diff options
Diffstat (limited to 'source3/libads/sasl.c')
-rw-r--r-- | source3/libads/sasl.c | 254 |
1 files changed, 28 insertions, 226 deletions
diff --git a/source3/libads/sasl.c b/source3/libads/sasl.c index f7dd01084a..81dedb0a81 100644 --- a/source3/libads/sasl.c +++ b/source3/libads/sasl.c @@ -22,198 +22,37 @@ #ifdef HAVE_ADS -/* - perform a LDAP/SASL/SPNEGO/NTLMSSP bind (just how many layers can - we fit on one socket??) +#if USE_CYRUS_SASL +/* + this is a minimal interact function, just enough for SASL to talk + GSSAPI/kerberos to W2K + Error handling is a bit of a problem. I can't see how to get Cyrus-sasl + to give sensible errors */ -static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads) +static int sasl_interact(LDAP *ld,unsigned flags,void *defaults,void *in) { - const char *mechs[] = {OID_NTLMSSP, NULL}; - DATA_BLOB msg1; - DATA_BLOB blob, chal1, chal2, auth; - uint8 challenge[8]; - uint8 nthash[24], lmhash[24], sess_key[16]; - uint32 neg_flags; - struct berval cred, *scred; - ADS_STATUS status; - extern pstring global_myname; - int rc; + sasl_interact_t *interact = in; - if (!ads->auth.password) { - /* No password, don't segfault below... */ - return ADS_ERROR_NT(NT_STATUS_LOGON_FAILURE); + while (interact->id != SASL_CB_LIST_END) { + interact->result = strdup(""); + interact->len = strlen(interact->result); + interact++; } - - neg_flags = NTLMSSP_NEGOTIATE_UNICODE | - NTLMSSP_NEGOTIATE_128 | - NTLMSSP_NEGOTIATE_NTLM; - - memset(sess_key, 0, 16); - - /* generate the ntlmssp negotiate packet */ - msrpc_gen(&blob, "CddB", - "NTLMSSP", - NTLMSSP_NEGOTIATE, - neg_flags, - sess_key, 16); - - /* and wrap it in a SPNEGO wrapper */ - msg1 = gen_negTokenTarg(mechs, blob); - data_blob_free(&blob); - - cred.bv_val = msg1.data; - cred.bv_len = msg1.length; - - rc = ldap_sasl_bind_s(ads->ld, NULL, "GSS-SPNEGO", &cred, 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); - - /* the server gives us back two challenges */ - if (!spnego_parse_challenge(blob, &chal1, &chal2)) { - DEBUG(3,("Failed to parse challenges\n")); - status = ADS_ERROR(LDAP_OPERATIONS_ERROR); - goto failed; - } - - data_blob_free(&blob); - - /* encrypt the password with the challenge */ - memcpy(challenge, chal1.data + 24, 8); - SMBencrypt(ads->auth.password, challenge,lmhash); - SMBNTencrypt(ads->auth.password, challenge,nthash); - - data_blob_free(&chal1); - data_blob_free(&chal2); - - /* this generates the actual auth packet */ - msrpc_gen(&blob, "CdBBUUUBd", - "NTLMSSP", - NTLMSSP_AUTH, - lmhash, 24, - nthash, 24, - lp_workgroup(), - ads->auth.user_name, - global_myname, - sess_key, 16, - neg_flags); - - /* wrap it in SPNEGO */ - auth = spnego_gen_auth(blob); - - data_blob_free(&blob); - - /* now send the auth packet and we should be done */ - cred.bv_val = auth.data; - cred.bv_len = auth.length; - - rc = ldap_sasl_bind_s(ads->ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred); - - return ADS_ERROR(rc); - -failed: - return status; + + return LDAP_SUCCESS; } - -/* - perform a LDAP/SASL/SPNEGO/KRB5 bind -*/ -static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads, const char *principal) -{ - DATA_BLOB blob; - struct berval cred, *scred; - int rc; - - blob = spnego_gen_negTokenTarg(principal, ads->auth.time_offset); - - if (!blob.data) { - return ADS_ERROR(LDAP_OPERATIONS_ERROR); - } - - /* now send the auth packet and we should be done */ - cred.bv_val = blob.data; - cred.bv_len = blob.length; - - rc = ldap_sasl_bind_s(ads->ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred); - - data_blob_free(&blob); - - return ADS_ERROR(rc); -} - -/* - 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 *principal; - char *OIDs[ASN1_MAX_OIDS]; - BOOL got_kerberos_mechanism = False; - - rc = ldap_sasl_bind_s(ads->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); - -#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, &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,("got OID=%s\n", OIDs[i])); - if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 || - strcmp(OIDs[i], OID_KERBEROS5) == 0) { - got_kerberos_mechanism = True; - } - free(OIDs[i]); - } - DEBUG(3,("got principal=%s\n", principal)); - if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) && - got_kerberos_mechanism && ads_kinit_password(ads) == 0) { - return ads_sasl_spnego_krb5_bind(ads, 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; -} - -#ifdef HAVE_GSSAPI #define MAX_GSS_PASSES 3 /* this performs a SASL/gssapi bind we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl is very dependent on correctly configured DNS whereas this routine is much less fragile - see RFC2078 and RFC2222 for details + see RFC2078 for details */ -static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) +ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) { int minor_status; gss_name_t serv_name; @@ -229,7 +68,6 @@ static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) uint8 *p; uint32 max_msg_size; char *sname; - unsigned sec_layer; ADS_STATUS status; krb5_principal principal; krb5_context ctx; @@ -321,25 +159,22 @@ static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) p = (uint8 *)output_token.value; - file_save("sasl_gssapi.dat", output_token.value, output_token.length); - max_msg_size = (p[1]<<16) | (p[2]<<8) | p[3]; - sec_layer = *p; gss_release_buffer(&minor_status, &output_token); output_token.value = malloc(strlen(ads->config.bind_path) + 8); p = output_token.value; - *p++ = 1; /* no sign & seal selection */ + *p++ = 1; /* no sign or seal */ /* choose the same size as the server gave us */ *p++ = max_msg_size>>16; *p++ = max_msg_size>>8; *p++ = max_msg_size; snprintf(p, strlen(ads->config.bind_path)+4, "dn:%s", ads->config.bind_path); - p += strlen(p); + p += strlen(ads->config.bind_path); - output_token.length = PTR_DIFF(p, output_token.value); + output_token.length = strlen(ads->config.bind_path) + 8; gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT, &output_token, &conf_state, @@ -363,51 +198,18 @@ static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) failed: return status; } -#endif - -/* mapping between SASL mechanisms and functions */ -static struct { - const char *name; - ADS_STATUS (*fn)(ADS_STRUCT *); -} sasl_mechanisms[] = { - {"GSS-SPNEGO", ads_sasl_spnego_bind}, -#ifdef HAVE_GSSAPI - {"GSSAPI", ads_sasl_gssapi_bind}, /* doesn't work with .NET RC1. No idea why */ -#endif - {NULL, NULL} -}; ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads) { - const char *attrs[] = {"supportedSASLMechanisms", NULL}; - char **values; - ADS_STATUS status; - int i, j; - void *res; - - /* get a list of supported SASL mechanisms */ - status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res); - if (!ADS_ERR_OK(status)) return status; - - values = ldap_get_values(ads->ld, res, "supportedSASLMechanisms"); - - /* try our supported mechanisms in order */ - for (i=0;sasl_mechanisms[i].name;i++) { - /* see if the server supports it */ - for (j=0;values && values[j];j++) { - if (strcmp(values[j], sasl_mechanisms[i].name) == 0) { - DEBUG(4,("Found SASL mechanism %s\n", values[j])); - status = sasl_mechanisms[i].fn(ads); - ldap_value_free(values); - ldap_msgfree(res); - return status; - } - } - } - - ldap_value_free(values); - ldap_msgfree(res); - return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED); +#if USE_CYRUS_SASL + int rc; + rc = ldap_sasl_interactive_bind_s(ads->ld, NULL, NULL, NULL, NULL, + LDAP_SASL_QUIET, + sasl_interact, NULL); + return ADS_ERROR(rc); +#else + return ads_sasl_gssapi_bind(ads); +#endif } #endif |