From b7bbc7504d14e2d1c18f5e9392f644d94bf91f08 Mon Sep 17 00:00:00 2001
From: Kurt Zeilenga <kurt@openldap.org>
Date: Fri, 2 Jul 1999 19:48:07 +0000
Subject: [PATCH] More bind changes to support SASL/DIGEST. Added configuration
 support for "digest-realm <realm>" configure directive. Added connection
 state and bind_in_progress fields to cn=monitor connection attribute.

---
 servers/slapd/backend.c    |   3 +
 servers/slapd/bind.c       | 111 ++++++++++++++++++++++++-------------
 servers/slapd/config.c     |  24 +++++++-
 servers/slapd/connection.c |  28 +++++++++-
 servers/slapd/monitor.c    |   4 +-
 servers/slapd/proto-slap.h |   2 +
 servers/slapd/slap.h       |   5 +-
 7 files changed, 133 insertions(+), 44 deletions(-)

diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c
index 5b5a1f5db8..74cc285665 100644
--- a/servers/slapd/backend.c
+++ b/servers/slapd/backend.c
@@ -385,6 +385,9 @@ backend_db_init(
 	be->be_sizelimit = defsize;
 	be->be_timelimit = deftime;
 
+	be->be_realm = global_realm != NULL
+		? ch_strdup( global_realm ) : NULL;
+
 	if(bi->bi_db_init) {
 		rc = bi->bi_db_init( be );
 	}
diff --git a/servers/slapd/bind.c b/servers/slapd/bind.c
index bb9ccd3e16..8a11db02b0 100644
--- a/servers/slapd/bind.c
+++ b/servers/slapd/bind.c
@@ -39,7 +39,7 @@ do_bind(
 	char		*mech;
 	char		*cdn, *ndn;
 	ber_tag_t	tag;
-	int			rc;
+	int			rc = LDAP_SUCCESS;
 	struct berval	cred;
 	Backend		*be;
 
@@ -50,6 +50,25 @@ do_bind(
 	mech = NULL;
 	cred.bv_val = NULL;
 
+	ldap_pvt_thread_mutex_lock( &conn->c_mutex );
+
+	/* Force to connection to "anonymous" until bind succeeds.
+	 * This may need to be relocated or done on a case by case basis
+	 * to handle certain SASL mechanisms.
+	 */
+
+	if ( conn->c_cdn != NULL ) {
+		free( conn->c_cdn );
+		conn->c_cdn = NULL;
+	}
+
+	if ( conn->c_dn != NULL ) {
+		free( conn->c_dn );
+		conn->c_dn = NULL;
+	}
+
+	ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
+
 	/*
 	 * Parse the bind request.  It looks like this:
 	 *
@@ -59,8 +78,14 @@ do_bind(
 	 *		authentication	CHOICE {
 	 *			simple		[0] OCTET STRING -- passwd
 	 *			krbv42ldap	[1] OCTET STRING
-	 *			krbv42dsa	[1] OCTET STRING
+	 *			krbv42dsa	[2] OCTET STRING
+	 *			SASL		[3] SaslCredentials
 	 *		}
+	 *	}
+	 *
+	 *	SaslCredentials ::= SEQUENCE {
+     *		mechanism           LDAPString,
+     *		credentials         OCTET STRING OPTIONAL
 	 *	}
 	 */
 
@@ -152,26 +177,58 @@ do_bind(
 				NULL, "sasl mechanism not supported" );
 			goto cleanup;
 		}
-	}
 
-	/* accept null binds */
-	if ( ndn == NULL || *ndn == '\0' ) {
 		ldap_pvt_thread_mutex_lock( &conn->c_mutex );
 
-		conn->c_protocol = version;
+		if ( conn->c_authmech != NULL ) {
+			assert( conn->c_bind_in_progress );
+
+			if((strcmp(conn->c_authmech, mech) != 0)) {
+				/* mechanism changed, cancel in progress bind */
+				conn->c_bind_in_progress = 0;
+				if( conn->c_authstate != NULL ) {
+					free(conn->c_authstate);
+					conn->c_authstate = NULL;
+				}
+				free(conn->c_authmech);
+				conn->c_authmech = NULL;
+			}
 
-		if ( conn->c_cdn != NULL ) {
-			free( conn->c_cdn );
-			conn->c_cdn = NULL;
+#ifdef LDAP_DEBUG
+		} else {
+			assert( !conn->c_bind_in_progress );
+			assert( conn->c_authmech == NULL );
+			assert( conn->c_authstate == NULL );
+#endif
 		}
 
-		if ( conn->c_dn != NULL ) {
-			free( conn->c_dn );
-			conn->c_dn = NULL;
+	} else {
+		ldap_pvt_thread_mutex_lock( &conn->c_mutex );
+
+		if ( conn->c_authmech != NULL ) {
+			assert( conn->c_bind_in_progress );
+
+			/* cancel in progress bind */
+			conn->c_bind_in_progress = 0;
+
+			if( conn->c_authstate != NULL ) {
+				free(conn->c_authstate);
+				conn->c_authstate = NULL;
+			}
+			free(conn->c_authmech);
+			conn->c_authmech = NULL;
 		}
+	}
 
-		ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
+	conn->c_protocol = version;
+	ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
 
+	/* accept null binds */
+	if ( ndn == NULL || *ndn == '\0' ) {
+		/*
+		 * we already forced connection to "anonymous", we just
+		 * need to send success
+		 */
 		send_ldap_result( conn, op, LDAP_SUCCESS, NULL, NULL );
 		goto cleanup;
 	}
@@ -184,27 +241,13 @@ do_bind(
 
 	if ( (be = select_backend( ndn )) == NULL ) {
 		if ( cred.bv_len == 0 ) {
-			ldap_pvt_thread_mutex_lock( &conn->c_mutex );
-
-			conn->c_protocol = version;
-
-			if ( conn->c_cdn != NULL ) {
-				free( conn->c_cdn );
-				conn->c_cdn = NULL;
-			}
-
-			if ( conn->c_dn != NULL ) {
-				free( conn->c_dn );
-				conn->c_dn = NULL;
-			}
-
-			ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
-
 			send_ldap_result( conn, op, LDAP_SUCCESS,
 				NULL, NULL );
+
 		} else if ( default_referral && *default_referral ) {
 			send_ldap_result( conn, op, rc = LDAP_PARTIAL_RESULTS,
 				NULL, default_referral );
+
 		} else {
 			send_ldap_result( conn, op, rc = LDAP_INVALID_CREDENTIALS,
 				NULL, default_referral );
@@ -222,19 +265,9 @@ do_bind(
 		if ( (*be->be_bind)( be, conn, op, ndn, method, mech, &cred, &edn ) == 0 ) {
 			ldap_pvt_thread_mutex_lock( &conn->c_mutex );
 
-			conn->c_protocol = version;
-
-			if ( conn->c_cdn != NULL ) {
-				free( conn->c_cdn );
-			}
-
 			conn->c_cdn = cdn;
 			cdn = NULL;
 
-			if ( conn->c_dn != NULL ) {
-				free( conn->c_dn );
-			}
-
 			if(edn != NULL) {
 				conn->c_dn = edn;
 			} else {
diff --git a/servers/slapd/config.c b/servers/slapd/config.c
index 45b25b9d40..f2f0cd79a0 100644
--- a/servers/slapd/config.c
+++ b/servers/slapd/config.c
@@ -26,6 +26,7 @@ int		global_default_access = ACL_READ;
 char		*replogfile;
 int		global_lastmod;
 int		global_idletimeout = 0;
+char	*global_realm = NULL;
 char		*ldap_srvtab = "";
 
 char   *slapd_pid_file  = NULL;
@@ -144,7 +145,28 @@ read_config( char *fname )
 
 			slapd_args_file = ch_strdup( cargv[1] );
 
-		/* set size limit */
+		/* set DIGEST realm */
+		} else if ( strcasecmp( cargv[0], "digest-realm" ) == 0 ) {
+			if ( cargc < 2 ) {
+				Debug( LDAP_DEBUG_ANY,
+	    "%s: line %d: missing realm in \"digest-realm <realm>\" line\n",
+				    fname, lineno, 0 );
+				return( 1 );
+			}
+			if ( be != NULL ) {
+				be->be_realm = ch_strdup( cargv[1] );
+
+			} else if ( global_realm != NULL ) {
+				Debug( LDAP_DEBUG_ANY,
+					"%s: line %d: already set global realm!\n",
+					fname, lineno, 0 );
+				return 1;
+
+			} else {
+				global_realm = ch_strdup( cargv[1] );
+			}
+
+		/* set time limit */
 		} else if ( strcasecmp( cargv[0], "sizelimit" ) == 0 ) {
 			if ( cargc < 2 ) {
 				Debug( LDAP_DEBUG_ANY,
diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c
index 1df8b52800..a8c6e26fb8 100644
--- a/servers/slapd/connection.c
+++ b/servers/slapd/connection.c
@@ -30,6 +30,18 @@ static unsigned long conn_nextid = 0;
 #define SLAP_C_BINDING			0x03	/* binding */
 #define SLAP_C_CLOSING			0x04	/* closing */
 
+char* connection_state2str( int state ) {
+	switch( state ) {
+	case SLAP_C_INVALID:	return "!";		
+	case SLAP_C_INACTIVE:	return "|";		
+	case SLAP_C_ACTIVE:		return "";			
+	case SLAP_C_BINDING:	return "B";
+	case SLAP_C_CLOSING:	return "C";			
+	}
+
+	return "?";
+}
+
 static Connection* connection_get( ber_socket_t s );
 
 static int connection_input( Connection *c );
@@ -326,6 +338,8 @@ long connection_init(
         c->c_client_addr = NULL;
         c->c_ops = NULL;
         c->c_pending_ops = NULL;
+		c->c_authmech = NULL;
+		c->c_authstate = NULL;
 
         c->c_sb = ber_sockbuf_alloc( );
 
@@ -346,6 +360,8 @@ long connection_init(
     assert( c->c_client_addr == NULL );
     assert( c->c_ops == NULL );
     assert( c->c_pending_ops == NULL );
+	assert( c->c_authmech == NULL );
+	assert( c->c_authstate == NULL );
 
     c->c_client_name = ch_strdup( name == NULL ? "" : name );
     c->c_client_addr = ch_strdup( addr );
@@ -416,6 +432,14 @@ connection_destroy( Connection *c )
 		free(c->c_client_addr);
 		c->c_client_addr = NULL;
 	}
+	if(c->c_authmech != NULL ) {
+		free(c->c_authmech);
+		c->c_authmech = NULL;
+	}
+	if(c->c_authstate != NULL ) {
+		free(c->c_authstate);
+		c->c_authstate = NULL;
+	}
 
 	if ( ber_pvt_sb_in_use(c->c_sb) ) {
 		int sd = ber_pvt_sb_get_desc(c->c_sb);
@@ -916,10 +940,10 @@ static int connection_op_activate( Connection *conn, Operation *op )
 
 	arg->co_op->o_protocol = conn->c_protocol;
 
+	arg->co_op->o_authtype = conn->c_authtype;
 	arg->co_op->o_authmech = conn->c_authmech != NULL
 		?  ch_strdup( conn->c_authmech ) : NULL;
-	arg->co_op->o_authtype = conn->c_authtype;
-
+	
 	slap_op_add( &conn->c_ops, arg->co_op );
 
 	if(tag == LDAP_REQ_BIND) {
diff --git a/servers/slapd/monitor.c b/servers/slapd/monitor.c
index a9aef36cf7..a37ab8b2a5 100644
--- a/servers/slapd/monitor.c
+++ b/servers/slapd/monitor.c
@@ -110,7 +110,7 @@ monitor_info( Connection *conn, Operation *op )
 			"%ld : %ld "
 			": %ld/%ld/%ld/%ld "
 			": %ld/%ld/%ld "
-			": %s%s%s%s "
+			": %s%s%s%s%s%s "
 			": %s : %s : %s "
 			": %s : %s",
 
@@ -127,6 +127,8 @@ monitor_info( Connection *conn, Operation *op )
 		    c->c_writewaiter ? "w" : "",
 		    c->c_ops != NULL ? "x" : "",
 		    c->c_pending_ops != NULL ? "p" : "",
+			connection_state2str( c->c_conn_state ),
+			c->c_bind_in_progress ? "S" : "",
 
 		    c->c_cdn ? c->c_cdn : "<anonymous>",
 		    c->c_client_addr ? c->c_client_addr : "unknown",
diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h
index 0407ea158d..d8c33673a6 100644
--- a/servers/slapd/proto-slap.h
+++ b/servers/slapd/proto-slap.h
@@ -148,6 +148,7 @@ long connection_init LDAP_P((
 
 void connection_closing LDAP_P(( Connection *c ));
 int connection_state_closing LDAP_P(( Connection *c ));
+char *connection_state2str LDAP_P(( int state ));
 
 int connection_write LDAP_P((ber_socket_t s));
 int connection_read LDAP_P((ber_socket_t s));
@@ -331,6 +332,7 @@ extern int		global_default_access;
 extern int		global_lastmod;
 extern int		global_idletimeout;
 extern int		global_schemacheck;
+extern char		*global_realm;
 extern int		lber_debug;
 extern int		ldap_syslog;
 
diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h
index 4edb275b89..d52b63f8bc 100644
--- a/servers/slapd/slap.h
+++ b/servers/slapd/slap.h
@@ -363,6 +363,8 @@ struct backend_db {
 	char	*be_update_ndn;	/* allowed to make changes (in replicas)   */
 	int	be_lastmod;	/* keep track of lastmodified{by,time}	   */
 
+	char	*be_realm;
+
 	void	*be_private;	/* anything the backend database needs 	   */
 };
 
@@ -542,8 +544,9 @@ typedef struct slap_conn {
 	char	*c_cdn;		/* DN provided by the client */
 	char	*c_dn;		/* DN bound to this conn  */
 	ber_int_t	c_protocol;	/* version of the LDAP protocol used by client */
-	ber_tag_t	c_authtype;	/* auth method used to bind c_dn  */
+	ber_tag_t	c_authtype;/* auth method used to bind c_dn  */
 	char	*c_authmech;	/* SASL mechanism used to bind c_dn */
+	void	*c_authstate;	/* SASL state data */
 
 	Operation	*c_ops;			/* list of operations being processed */
 	Operation	*c_pending_ops;	/* list of pending operations */
-- 
GitLab