Author: metze
Date: 2007-07-31 09:33:27 +0000 (Tue, 31 Jul 2007)
New Revision: 24094

WebSVN: 
http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=24094

Log:
merge from SAMBA_3_2:
move gssapi/krb5 principal handling into a function

metze
Modified:
   branches/SAMBA_3_2_0/source/libads/sasl.c


Changeset:
Modified: branches/SAMBA_3_2_0/source/libads/sasl.c
===================================================================
--- branches/SAMBA_3_2_0/source/libads/sasl.c   2007-07-31 09:31:47 UTC (rev 
24093)
+++ branches/SAMBA_3_2_0/source/libads/sasl.c   2007-07-31 09:33:27 UTC (rev 
24094)
@@ -360,7 +360,7 @@
 /* 
    perform a LDAP/SASL/SPNEGO/GSSKRB5 bind
 */
-static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const char 
*sname)
+static ADS_STATUS ads_sasl_spnego_gsskrb5_bind(ADS_STRUCT *ads, const 
gss_name_t serv_name)
 {
        ADS_STATUS status;
        BOOL ok;
@@ -371,7 +371,6 @@
        gss_OID mech_type = &krb5_mech_type;
        gss_OID actual_mech_type = GSS_C_NULL_OID;
        const char *spnego_mechs[] = {OID_KERBEROS5_OLD, OID_KERBEROS5, 
OID_NTLMSSP, NULL};
-       gss_name_t serv_name;
        gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
        gss_buffer_desc input_token, output_token;
        uint32 req_flags, ret_flags;
@@ -379,51 +378,7 @@
        DATA_BLOB unwrapped;
        DATA_BLOB wrapped;
        struct berval cred, *scred = NULL;
-       krb5_principal principal = NULL;
-       gss_buffer_desc input_name;
-       krb5_context ctx = NULL;
-       krb5_enctype enc_types[] = {
-#ifdef ENCTYPE_ARCFOUR_HMAC
-                       ENCTYPE_ARCFOUR_HMAC,
-#endif
-                       ENCTYPE_DES_CBC_MD5,
-                       ENCTYPE_NULL};
-       gss_OID_desc nt_principal = 
-       {10, CONST_DISCARD(char *, "\052\206\110\206\367\022\001\002\002\002")};
 
-       initialize_krb5_error_table();
-       status = ADS_ERROR_KRB5(krb5_init_context(&ctx));
-       if (!ADS_ERR_OK(status)) {
-               return status;
-       }
-       status = ADS_ERROR_KRB5(krb5_set_default_tgs_ktypes(ctx, enc_types));
-       if (!ADS_ERR_OK(status)) {
-               krb5_free_context(ctx); 
-               return status;
-       }
-       status = ADS_ERROR_KRB5(smb_krb5_parse_name(ctx, sname, &principal));
-       if (!ADS_ERR_OK(status)) {
-               krb5_free_context(ctx); 
-               return status;
-       }
-
-       /*
-        * The MIT libraries have a *HORRIBLE* bug - input_value.value needs
-        * to point to the *address* of the krb5_principal, and the gss 
libraries
-        * to a shallow copy of the krb5_principal pointer - so we need to keep
-        * the krb5_principal around until we do the gss_release_name. MIT 
*SUCKS* !
-        * Just one more way in which MIT engineers screwed me over.... JRA.
-        */
-       input_name.value = &principal;
-       input_name.length = sizeof(principal);
-
-       gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, 
&serv_name);
-       if (gss_rc) {
-               krb5_free_principal(ctx, principal);
-               krb5_free_context(ctx); 
-               return ADS_ERROR_GSS(gss_rc, minor_status);
-       }
-
        input_token.value = NULL;
        input_token.length = 0;
 
@@ -633,17 +588,136 @@
        }
 
 failed:
-       gss_release_name(&minor_status, &serv_name);
        if (context_handle != GSS_C_NO_CONTEXT)
                gss_delete_sec_context(&minor_status, &context_handle, 
GSS_C_NO_BUFFER);
-       krb5_free_principal(ctx, principal);
-       krb5_free_context(ctx); 
        return status;
 }
 
 #endif
 
 #ifdef HAVE_KRB5
+struct ads_service_principal {
+        krb5_context ctx;
+        char *string;
+        krb5_principal principal;
+#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
+       if (p->principal) {
+               krb5_free_principal(p->ctx, p->principal);
+       }
+
+       if (p->ctx) {
+               krb5_free_context(p->ctx);
+       }
+
+       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;
+       krb5_enctype enc_types[] = {
+#ifdef ENCTYPE_ARCFOUR_HMAC
+                       ENCTYPE_ARCFOUR_HMAC,
+#endif
+                       ENCTYPE_DES_CBC_MD5,
+                       ENCTYPE_NULL};
+#ifdef HAVE_GSSAPI
+       gss_buffer_desc input_name;
+       gss_OID_desc nt_principal = 
+       {10, CONST_DISCARD(char *, "\052\206\110\206\367\022\001\002\002\002")};
+       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  */
+       if (given_principal) {
+               p->string = SMB_STRDUP(given_principal);
+               if (!p->string) {
+                       return ADS_ERROR(LDAP_NO_MEMORY);
+               }
+       } else 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(&p->string, "ldap/[EMAIL PROTECTED]", server, 
server_realm);
+
+               SAFE_FREE(server);
+               SAFE_FREE(server_realm);
+
+               if (!p->string) {
+                       return ADS_ERROR(LDAP_NO_MEMORY);
+               }
+       }
+
+       initialize_krb5_error_table();
+       status = ADS_ERROR_KRB5(krb5_init_context(&p->ctx));
+       if (!ADS_ERR_OK(status)) {
+               ads_free_service_principal(p);
+               return status;
+       }
+       status = ADS_ERROR_KRB5(krb5_set_default_tgs_ktypes(p->ctx, enc_types));
+       if (!ADS_ERR_OK(status)) {
+               ads_free_service_principal(p);
+               return status;
+       }
+       status = ADS_ERROR_KRB5(smb_krb5_parse_name(p->ctx, p->string, 
&p->principal));
+       if (!ADS_ERR_OK(status)) {
+               ads_free_service_principal(p);
+               return status;
+       }
+
+#ifdef HAVE_GSSAPI
+       /*
+        * The MIT libraries have a *HORRIBLE* bug - input_value.value needs
+        * to point to the *address* of the krb5_principal, and the gss 
libraries
+        * to a shallow copy of the krb5_principal pointer - so we need to keep
+        * the krb5_principal around until we do the gss_release_name. MIT 
*SUCKS* !
+        * Just one more way in which MIT engineers screwed me over.... JRA.
+        *
+        * That's the reason for principal not beeing a local var in this 
function
+        */
+       input_name.value = &p->principal;
+       input_name.length = sizeof(p->principal);
+
+       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 status;
+}
+
 /* 
    perform a LDAP/SASL/SPNEGO/KRB5 bind
 */
@@ -679,7 +753,8 @@
        return ADS_ERROR(rc);
 }
 
-static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, const char 
*principal)
+static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
+                                           struct ads_service_principal *p)
 {
 #ifdef HAVE_GSSAPI
        /*
@@ -693,10 +768,10 @@
         *   against clock skew errors
         */
        if (ads->ldap.wrap_type > ADS_SASLWRAP_TYPE_PLAIN) {
-               return ads_sasl_spnego_gsskrb5_bind(ads, principal);
+               return ads_sasl_spnego_gsskrb5_bind(ads, p->name);
        }
 #endif
-       return ads_sasl_spnego_rawkrb5_bind(ads, principal);
+       return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
 }
 #endif
 
@@ -709,7 +784,7 @@
        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;
@@ -732,7 +807,7 @@
 
        /* 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;
@@ -750,42 +825,23 @@
 #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);
+               struct ads_service_principal p;
 
-                               strlower_m( server );
-                               strupper_m( server_realm );                     
        
-                               asprintf( &principal, "ldap/[EMAIL PROTECTED]", 
server, server_realm );
+               status = ads_generate_service_principal(ads, given_principal, 
&p);
+               SAFE_FREE(given_principal);
+               if (!ADS_ERR_OK(status)) {
+                       return status;
+               }
 
-                               SAFE_FREE( server );
-                               SAFE_FREE( server_realm );
-
-                               if ( !principal )
-                                       return ADS_ERROR(LDAP_NO_MEMORY);       
                        
-                       }
-                       
-               }
-               
-               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;
                }
 
@@ -795,20 +851,22 @@
                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);
                }
 
+               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(given_principal);
        }
-#endif
 
-       SAFE_FREE(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 
           library for HMAC_MD4 encryption */

Reply via email to