[SCM] Samba Shared Repository - branch v3-0-test updated - release-3-0-28-115-g83b04c6

Günther Deschner gd at samba.org
Thu Jan 31 12:06:27 GMT 2008


The branch, v3-0-test has been updated
       via  83b04c60fac76ccd2d5aecb14f8896a07d488b1f (commit)
      from  945bbd14bb1c8ec11365d52a7897ca17e95c9053 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-0-test


- Log -----------------------------------------------------------------
commit 83b04c60fac76ccd2d5aecb14f8896a07d488b1f
Author: Günther Deschner <gd at samba.org>
Date:   Thu Jan 31 13:05:36 2008 +0100

    Enable v3-0-test to successfully join a windows 2008 domain controller.
    
    This is hand-merged from a couple of commits from 3-2-test, cherry-picking was
    hardly possible without importing all the ldap sign/seal work from metze.
    
    Guenther

-----------------------------------------------------------------------

Summary of changes:
 source/include/ads.h       |    3 +
 source/libads/sasl.c       |  140 ++++++++++++++++++++++++++++++++------------
 source/libads/util.c       |   57 ++++++++++++++++++
 source/libsmb/cliconnect.c |    3 +-
 4 files changed, 164 insertions(+), 39 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source/include/ads.h b/source/include/ads.h
index fcaeb20..24884f5 100644
--- a/source/include/ads.h
+++ b/source/include/ads.h
@@ -321,4 +321,7 @@ typedef struct {
 	int val;
 	int critical;
 } ads_control;
+
+#define ADS_IGNORE_PRINCIPAL "not_defined_in_RFC4178 at please_ignore"
+
 #endif	/* _INCLUDE_ADS_H_ */
diff --git a/source/libads/sasl.c b/source/libads/sasl.c
index 0067a19..40749be 100644
--- a/source/libads/sasl.c
+++ b/source/libads/sasl.c
@@ -137,10 +137,81 @@ static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
 }
 
 #ifdef HAVE_KRB5
+struct ads_service_principal {
+	 char *string;
+#ifdef HAVE_GSSAPI
+	 gss_name_t name;
+#endif
+};
+
+static void ads_free_service_principal(struct ads_service_principal *p)
+{
+	SAFE_FREE(p->string);
+
+#ifdef HAVE_GSSAPI
+	if (p->name) {
+		uint32 minor_status;
+		gss_release_name(&minor_status, &p->name);
+	}
+#endif
+	ZERO_STRUCTP(p);
+}
+
+static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
+						 const char *given_principal,
+						 struct ads_service_principal *p)
+{
+	ADS_STATUS status;
+#ifdef HAVE_GSSAPI
+	gss_buffer_desc input_name;
+	/* GSS_KRB5_NT_PRINCIPAL_NAME */
+	gss_OID_desc nt_principal =
+	{10, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
+	uint32 minor_status;
+	int gss_rc;
+#endif
+
+	ZERO_STRUCTP(p);
+
+	/* I've seen a child Windows 2000 domain not send
+	   the principal name back in the first round of
+	   the SASL bind reply.  So we guess based on server
+	   name and realm.  --jerry  */
+	/* Also try best guess when we get the w2k8 ignore
+	   principal back - gd */
+
+	if (!given_principal ||
+	    strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
+
+		status = ads_guess_service_principal(ads, &p->string);
+		if (!ADS_ERR_OK(status)) {
+			return status;
+		}
+	} else {
+		p->string = SMB_STRDUP(given_principal);
+		if (!p->string) {
+			return ADS_ERROR(LDAP_NO_MEMORY);
+		}
+	}
+
+#ifdef HAVE_GSSAPI
+	input_name.value = p->string;
+	input_name.length = strlen(p->string);
+
+	gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
+	if (gss_rc) {
+		ads_free_service_principal(p);
+		return ADS_ERROR_GSS(gss_rc, minor_status);
+	}
+#endif
+
+	return ADS_SUCCESS;
+}
+
 /* 
    perform a LDAP/SASL/SPNEGO/KRB5 bind
 */
-static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, const char *principal)
+static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
 {
 	DATA_BLOB blob = data_blob(NULL, 0);
 	struct berval cred, *scred = NULL;
@@ -167,6 +238,13 @@ static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, const char *princip
 
 	return ADS_ERROR(rc);
 }
+
+static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
+					    struct ads_service_principal *p)
+{
+	return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
+}
+
 #endif
 
 /* 
@@ -178,7 +256,7 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
 	int rc, i;
 	ADS_STATUS status;
 	DATA_BLOB blob;
-	char *principal = NULL;
+	char *given_principal = NULL;
 	char *OIDs[ASN1_MAX_OIDS];
 #ifdef HAVE_KRB5
 	BOOL got_kerberos_mechanism = False;
@@ -201,7 +279,7 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
 
 	/* the server sent us the first part of the SPNEGO exchange in the negprot 
 	   reply */
-	if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
+	if (!spnego_parse_negTokenInit(blob, OIDs, &given_principal)) {
 		data_blob_free(&blob);
 		status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
 		goto failed;
@@ -219,42 +297,23 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
 #endif
 		free(OIDs[i]);
 	}
-	DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", principal));
+	DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
 
 #ifdef HAVE_KRB5
 	if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
 	    got_kerberos_mechanism) 
 	{
-		/* I've seen a child Windows 2000 domain not send 
-		   the principal name back in the first round of 
-		   the SASL bind reply.  So we guess based on server
-		   name and realm.  --jerry  */
-		if ( !principal ) {
-			if ( ads->server.realm && ads->server.ldap_server ) {
-				char *server, *server_realm;
-				
-				server = SMB_STRDUP( ads->server.ldap_server );
-				server_realm = SMB_STRDUP( ads->server.realm );
-				
-				if ( !server || !server_realm )
-					return ADS_ERROR(LDAP_NO_MEMORY);
-
-				strlower_m( server );
-				strupper_m( server_realm );				
-				asprintf( &principal, "ldap/%s@%s", server, server_realm );
-
-				SAFE_FREE( server );
-				SAFE_FREE( server_realm );
-
-				if ( !principal )
-					return ADS_ERROR(LDAP_NO_MEMORY);				
-			}
-			
+		struct ads_service_principal p;
+
+		status = ads_generate_service_principal(ads, given_principal, &p);
+		SAFE_FREE(given_principal);
+		if (!ADS_ERR_OK(status)) {
+			return status;
 		}
-		
-		status = ads_sasl_spnego_krb5_bind(ads, principal);
+
+		status = ads_sasl_spnego_krb5_bind(ads, &p);
 		if (ADS_ERR_OK(status)) {
-			SAFE_FREE(principal);
+			ads_free_service_principal(&p);
 			return status;
 		}
 
@@ -264,19 +323,26 @@ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
 		status = ADS_ERROR_KRB5(ads_kinit_password(ads)); 
 
 		if (ADS_ERR_OK(status)) {
-			status = ads_sasl_spnego_krb5_bind(ads, principal);
+			status = ads_sasl_spnego_krb5_bind(ads, &p);
+			if (!ADS_ERR_OK(status)) {
+				DEBUG(0,("kinit succeeded but "
+					"ads_sasl_spnego_krb5_bind failed: %s\n",
+					ads_errstr(status)));
+			}
 		}
 
+		ads_free_service_principal(&p);
+
 		/* only fallback to NTLMSSP if allowed */
 		if (ADS_ERR_OK(status) || 
 		    !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
-			SAFE_FREE(principal);
 			return status;
 		}
-	}
+	} else
 #endif
-
-	SAFE_FREE(principal);
+	{
+		SAFE_FREE(given_principal);
+	}
 
 	/* lets do NTLMSSP ... this has the big advantage that we don't need
 	   to sync clocks, and we don't rely on special versions of the krb5 
diff --git a/source/libads/util.c b/source/libads/util.c
index eb6dccb..365f72e 100644
--- a/source/libads/util.c
+++ b/source/libads/util.c
@@ -52,4 +52,61 @@ failed:
 	SAFE_FREE(password);
 	return ret;
 }
+
+ADS_STATUS ads_guess_service_principal(ADS_STRUCT *ads,
+				       char **returned_principal)
+{
+	char *princ = NULL;
+
+	if (ads->server.realm && ads->server.ldap_server) {
+		char *server, *server_realm;
+
+		server = SMB_STRDUP(ads->server.ldap_server);
+		server_realm = SMB_STRDUP(ads->server.realm);
+
+		if (!server || !server_realm) {
+			return ADS_ERROR(LDAP_NO_MEMORY);
+		}
+
+		strlower_m(server);
+		strupper_m(server_realm);
+		asprintf(&princ, "ldap/%s@%s", server, server_realm);
+
+		SAFE_FREE(server);
+		SAFE_FREE(server_realm);
+
+		if (!princ) {
+			return ADS_ERROR(LDAP_NO_MEMORY);
+		}
+	} else if (ads->config.realm && ads->config.ldap_server_name) {
+		char *server, *server_realm;
+
+		server = SMB_STRDUP(ads->config.ldap_server_name);
+		server_realm = SMB_STRDUP(ads->config.realm);
+
+		if (!server || !server_realm) {
+			return ADS_ERROR(LDAP_NO_MEMORY);
+		}
+
+		strlower_m(server);
+		strupper_m(server_realm);
+		asprintf(&princ, "ldap/%s@%s", server, server_realm);
+
+		SAFE_FREE(server);
+		SAFE_FREE(server_realm);
+
+		if (!princ) {
+			return ADS_ERROR(LDAP_NO_MEMORY);
+		}
+	}
+
+	if (!princ) {
+		return ADS_ERROR(LDAP_PARAM_ERROR);
+	}
+
+	*returned_principal = princ;
+
+	return ADS_SUCCESS;
+}
+
 #endif
diff --git a/source/libsmb/cliconnect.c b/source/libsmb/cliconnect.c
index 3168dd1..2f6606f 100644
--- a/source/libsmb/cliconnect.c
+++ b/source/libsmb/cliconnect.c
@@ -866,8 +866,7 @@ ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user,
 		/* If we get a bad principal, try to guess it if
 		   we have a valid host NetBIOS name.
 		 */
-		if (strequal(principal,
-				"not_defined_in_RFC4178 at please_ignore")) {
+		if (strequal(principal, ADS_IGNORE_PRINCIPAL)) {
 			SAFE_FREE(principal);
 		}
 		if (principal == NULL &&


-- 
Samba Shared Repository


More information about the samba-cvs mailing list