static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) { ADS_STATUS status; struct ads_service_principal p; status = ads_generate_service_principal(ads, &p); if (!ADS_ERR_OK(status)) { return status; } if (ads->auth.password == NULL || ads->auth.password[0] == '\0') { status = ads_sasl_gssapi_do_bind(ads, p.name); if (ADS_ERR_OK(status)) { ads_free_service_principal(&p); return status; } DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, " "calling kinit\n", ads_errstr(status))); } status = ADS_ERROR_KRB5(ads_kinit_password(ads)); if (ADS_ERR_OK(status)) { status = ads_sasl_gssapi_do_bind(ads, p.name); } ads_free_service_principal(&p); return status; }
/* this performs a SASL/SPNEGO bind */ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads) { TALLOC_CTX *frame = talloc_stackframe(); struct ads_service_principal p = {0}; struct berval *scred=NULL; int rc, i; ADS_STATUS status; DATA_BLOB blob = data_blob_null; char *given_principal = NULL; char *OIDs[ASN1_MAX_OIDS]; #ifdef HAVE_KRB5 bool got_kerberos_mechanism = False; #endif const char *mech = NULL; rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred); if (rc != LDAP_SASL_BIND_IN_PROGRESS) { status = ADS_ERROR(rc); goto done; } blob = data_blob(scred->bv_val, scred->bv_len); ber_bvfree(scred); #if 0 file_save("sasl_spnego.dat", blob.data, blob.length); #endif /* the server sent us the first part of the SPNEGO exchange in the negprot reply */ if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) || OIDs[0] == NULL) { status = ADS_ERROR(LDAP_OPERATIONS_ERROR); goto done; } TALLOC_FREE(given_principal); /* make sure the server understands kerberos */ for (i=0;OIDs[i];i++) { DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i])); #ifdef HAVE_KRB5 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 || strcmp(OIDs[i], OID_KERBEROS5) == 0) { got_kerberos_mechanism = True; } #endif talloc_free(OIDs[i]); } status = ads_generate_service_principal(ads, &p); if (!ADS_ERR_OK(status)) { goto done; } #ifdef HAVE_KRB5 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) && got_kerberos_mechanism) { mech = "KRB5"; if (ads->auth.password == NULL || ads->auth.password[0] == '\0') { status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO", CRED_MUST_USE_KERBEROS, p.service, p.hostname, blob); if (ADS_ERR_OK(status)) { ads_free_service_principal(&p); goto done; } DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, " "calling kinit\n", ads_errstr(status))); } status = ADS_ERROR_KRB5(ads_kinit_password(ads)); if (ADS_ERR_OK(status)) { status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO", CRED_MUST_USE_KERBEROS, p.service, p.hostname, blob); if (!ADS_ERR_OK(status)) { DEBUG(0,("kinit succeeded but " "ads_sasl_spnego_gensec_bind(KRB5) failed " "for %s/%s with user[%s] realm[%s]: %s\n", p.service, p.hostname, ads->auth.user_name, ads->auth.realm, ads_errstr(status))); } } /* only fallback to NTLMSSP if allowed */ if (ADS_ERR_OK(status) || !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) { goto done; } DEBUG(1,("ads_sasl_spnego_gensec_bind(KRB5) failed " "for %s/%s with user[%s] realm[%s]: %s, " "fallback to NTLMSSP\n", p.service, p.hostname, ads->auth.user_name, ads->auth.realm, ads_errstr(status))); } #endif /* 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 */ mech = "NTLMSSP"; status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO", CRED_DONT_USE_KERBEROS, p.service, p.hostname, data_blob_null); done: if (!ADS_ERR_OK(status)) { DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed " "for %s/%s with user[%s] realm=[%s]: %s\n", mech, p.service, p.hostname, ads->auth.user_name, ads->auth.realm, ads_errstr(status))); } ads_free_service_principal(&p); TALLOC_FREE(frame); if (blob.data != NULL) { data_blob_free(&blob); } return status; }
/* this performs a SASL/SPNEGO bind */ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads) { struct berval *scred=NULL; int rc, i; ADS_STATUS status; DATA_BLOB blob; char *given_principal = NULL; char *OIDs[ASN1_MAX_OIDS]; #ifdef HAVE_KRB5 bool got_kerberos_mechanism = False; #endif rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred); if (rc != LDAP_SASL_BIND_IN_PROGRESS) { status = ADS_ERROR(rc); goto failed; } blob = data_blob(scred->bv_val, scred->bv_len); ber_bvfree(scred); #if 0 file_save("sasl_spnego.dat", blob.data, blob.length); #endif /* the server sent us the first part of the SPNEGO exchange in the negprot reply */ if (!spnego_parse_negTokenInit(blob, OIDs, &given_principal)) { data_blob_free(&blob); status = ADS_ERROR(LDAP_OPERATIONS_ERROR); goto failed; } data_blob_free(&blob); /* make sure the server understands kerberos */ for (i=0;OIDs[i];i++) { DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i])); #ifdef HAVE_KRB5 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 || strcmp(OIDs[i], OID_KERBEROS5) == 0) { got_kerberos_mechanism = True; } #endif talloc_free(OIDs[i]); } 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) { struct ads_service_principal p; status = ads_generate_service_principal(ads, given_principal, &p); TALLOC_FREE(given_principal); if (!ADS_ERR_OK(status)) { return status; } status = ads_sasl_spnego_krb5_bind(ads, &p); if (ADS_ERR_OK(status)) { ads_free_service_principal(&p); return status; } DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, " "calling kinit\n", ads_errstr(status))); status = ADS_ERROR_KRB5(ads_kinit_password(ads)); if (ADS_ERR_OK(status)) { 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)) { return status; } } else #endif { TALLOC_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 library for HMAC_MD4 encryption */ return ads_sasl_spnego_ntlmssp_bind(ads); failed: return status; }