00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "includes.h"
00022
00023 #ifdef HAVE_LDAP
00024
00025
00026
00027
00028
00029 static ADS_STATUS ads_sasl_spnego_ntlmssp_bind(ADS_STRUCT *ads)
00030 {
00031 DATA_BLOB msg1 = data_blob(NULL, 0);
00032 DATA_BLOB blob = data_blob(NULL, 0);
00033 DATA_BLOB blob_in = data_blob(NULL, 0);
00034 DATA_BLOB blob_out = data_blob(NULL, 0);
00035 struct berval cred, *scred = NULL;
00036 int rc;
00037 NTSTATUS nt_status;
00038 int turn = 1;
00039
00040 struct ntlmssp_state *ntlmssp_state;
00041
00042 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_client_start(&ntlmssp_state))) {
00043 return ADS_ERROR_NT(nt_status);
00044 }
00045 ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_SIGN;
00046
00047 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_username(ntlmssp_state, ads->auth.user_name))) {
00048 return ADS_ERROR_NT(nt_status);
00049 }
00050 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_domain(ntlmssp_state, ads->auth.realm))) {
00051 return ADS_ERROR_NT(nt_status);
00052 }
00053 if (!NT_STATUS_IS_OK(nt_status = ntlmssp_set_password(ntlmssp_state, ads->auth.password))) {
00054 return ADS_ERROR_NT(nt_status);
00055 }
00056
00057 blob_in = data_blob(NULL, 0);
00058
00059 do {
00060 nt_status = ntlmssp_update(ntlmssp_state,
00061 blob_in, &blob_out);
00062 data_blob_free(&blob_in);
00063 if ((NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)
00064 || NT_STATUS_IS_OK(nt_status))
00065 && blob_out.length) {
00066 if (turn == 1) {
00067
00068 msg1 = gen_negTokenInit(OID_NTLMSSP, blob_out);
00069 } else {
00070
00071 msg1 = spnego_gen_auth(blob_out);
00072 }
00073
00074 data_blob_free(&blob_out);
00075
00076 cred.bv_val = (char *)msg1.data;
00077 cred.bv_len = msg1.length;
00078 scred = NULL;
00079 rc = ldap_sasl_bind_s(ads->ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
00080 data_blob_free(&msg1);
00081 if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) {
00082 if (scred) {
00083 ber_bvfree(scred);
00084 }
00085
00086 ntlmssp_end(&ntlmssp_state);
00087 return ADS_ERROR(rc);
00088 }
00089 if (scred) {
00090 blob = data_blob(scred->bv_val, scred->bv_len);
00091 ber_bvfree(scred);
00092 } else {
00093 blob = data_blob(NULL, 0);
00094 }
00095
00096 } else {
00097
00098 ntlmssp_end(&ntlmssp_state);
00099 data_blob_free(&blob_out);
00100 return ADS_ERROR_NT(nt_status);
00101 }
00102
00103 if ((turn == 1) &&
00104 (rc == LDAP_SASL_BIND_IN_PROGRESS)) {
00105 DATA_BLOB tmp_blob = data_blob(NULL, 0);
00106
00107 if (!spnego_parse_challenge(blob, &blob_in,
00108 &tmp_blob)) {
00109
00110 ntlmssp_end(&ntlmssp_state);
00111 data_blob_free(&blob);
00112 DEBUG(3,("Failed to parse challenges\n"));
00113 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
00114 }
00115 data_blob_free(&tmp_blob);
00116 } else if (rc == LDAP_SASL_BIND_IN_PROGRESS) {
00117 if (!spnego_parse_auth_response(blob, nt_status,
00118 &blob_in)) {
00119
00120 ntlmssp_end(&ntlmssp_state);
00121 data_blob_free(&blob);
00122 DEBUG(3,("Failed to parse auth response\n"));
00123 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
00124 }
00125 }
00126 data_blob_free(&blob);
00127 data_blob_free(&blob_out);
00128 turn++;
00129 } while (rc == LDAP_SASL_BIND_IN_PROGRESS && !NT_STATUS_IS_OK(nt_status));
00130
00131
00132
00133
00134 ntlmssp_end(&ntlmssp_state);
00135
00136 return ADS_ERROR(rc);
00137 }
00138
00139 #ifdef HAVE_KRB5
00140 struct ads_service_principal {
00141 char *string;
00142 #ifdef HAVE_GSSAPI
00143 gss_name_t name;
00144 #endif
00145 };
00146
00147 static void ads_free_service_principal(struct ads_service_principal *p)
00148 {
00149 SAFE_FREE(p->string);
00150
00151 #ifdef HAVE_GSSAPI
00152 if (p->name) {
00153 uint32 minor_status;
00154 gss_release_name(&minor_status, &p->name);
00155 }
00156 #endif
00157 ZERO_STRUCTP(p);
00158 }
00159
00160 static ADS_STATUS ads_generate_service_principal(ADS_STRUCT *ads,
00161 const char *given_principal,
00162 struct ads_service_principal *p)
00163 {
00164 ADS_STATUS status;
00165 #ifdef HAVE_GSSAPI
00166 gss_buffer_desc input_name;
00167
00168 gss_OID_desc nt_principal =
00169 {10, CONST_DISCARD(char *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x01")};
00170 uint32 minor_status;
00171 int gss_rc;
00172 #endif
00173
00174 ZERO_STRUCTP(p);
00175
00176
00177
00178
00179
00180
00181
00182
00183 if (!given_principal ||
00184 strequal(given_principal, ADS_IGNORE_PRINCIPAL)) {
00185
00186 status = ads_guess_service_principal(ads, &p->string);
00187 if (!ADS_ERR_OK(status)) {
00188 return status;
00189 }
00190 } else {
00191 p->string = SMB_STRDUP(given_principal);
00192 if (!p->string) {
00193 return ADS_ERROR(LDAP_NO_MEMORY);
00194 }
00195 }
00196
00197 #ifdef HAVE_GSSAPI
00198 input_name.value = p->string;
00199 input_name.length = strlen(p->string);
00200
00201 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &p->name);
00202 if (gss_rc) {
00203 ads_free_service_principal(p);
00204 return ADS_ERROR_GSS(gss_rc, minor_status);
00205 }
00206 #endif
00207
00208 return ADS_SUCCESS;
00209 }
00210
00211
00212
00213
00214 static ADS_STATUS ads_sasl_spnego_rawkrb5_bind(ADS_STRUCT *ads, const char *principal)
00215 {
00216 DATA_BLOB blob = data_blob(NULL, 0);
00217 struct berval cred, *scred = NULL;
00218 DATA_BLOB session_key = data_blob(NULL, 0);
00219 int rc;
00220
00221 rc = spnego_gen_negTokenTarg(principal, ads->auth.time_offset, &blob, &session_key, 0,
00222 &ads->auth.tgs_expire);
00223
00224 if (rc) {
00225 return ADS_ERROR_KRB5(rc);
00226 }
00227
00228
00229 cred.bv_val = (char *)blob.data;
00230 cred.bv_len = blob.length;
00231
00232 rc = ldap_sasl_bind_s(ads->ld, NULL, "GSS-SPNEGO", &cred, NULL, NULL, &scred);
00233
00234 data_blob_free(&blob);
00235 data_blob_free(&session_key);
00236 if(scred)
00237 ber_bvfree(scred);
00238
00239 return ADS_ERROR(rc);
00240 }
00241
00242 static ADS_STATUS ads_sasl_spnego_krb5_bind(ADS_STRUCT *ads,
00243 struct ads_service_principal *p)
00244 {
00245 return ads_sasl_spnego_rawkrb5_bind(ads, p->string);
00246 }
00247
00248 #endif
00249
00250
00251
00252
00253 static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads)
00254 {
00255 struct berval *scred=NULL;
00256 int rc, i;
00257 ADS_STATUS status;
00258 DATA_BLOB blob;
00259 char *given_principal = NULL;
00260 char *OIDs[ASN1_MAX_OIDS];
00261 #ifdef HAVE_KRB5
00262 BOOL got_kerberos_mechanism = False;
00263 #endif
00264
00265 rc = ldap_sasl_bind_s(ads->ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred);
00266
00267 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
00268 status = ADS_ERROR(rc);
00269 goto failed;
00270 }
00271
00272 blob = data_blob(scred->bv_val, scred->bv_len);
00273
00274 ber_bvfree(scred);
00275
00276 #if 0
00277 file_save("sasl_spnego.dat", blob.data, blob.length);
00278 #endif
00279
00280
00281
00282 if (!spnego_parse_negTokenInit(blob, OIDs, &given_principal)) {
00283 data_blob_free(&blob);
00284 status = ADS_ERROR(LDAP_OPERATIONS_ERROR);
00285 goto failed;
00286 }
00287 data_blob_free(&blob);
00288
00289
00290 for (i=0;OIDs[i];i++) {
00291 DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i]));
00292 #ifdef HAVE_KRB5
00293 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
00294 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
00295 got_kerberos_mechanism = True;
00296 }
00297 #endif
00298 free(OIDs[i]);
00299 }
00300 DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal));
00301
00302 #ifdef HAVE_KRB5
00303 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) &&
00304 got_kerberos_mechanism)
00305 {
00306 struct ads_service_principal p;
00307
00308 status = ads_generate_service_principal(ads, given_principal, &p);
00309 SAFE_FREE(given_principal);
00310 if (!ADS_ERR_OK(status)) {
00311 return status;
00312 }
00313
00314 status = ads_sasl_spnego_krb5_bind(ads, &p);
00315 if (ADS_ERR_OK(status)) {
00316 ads_free_service_principal(&p);
00317 return status;
00318 }
00319
00320 DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, "
00321 "calling kinit\n", ads_errstr(status)));
00322
00323 status = ADS_ERROR_KRB5(ads_kinit_password(ads));
00324
00325 if (ADS_ERR_OK(status)) {
00326 status = ads_sasl_spnego_krb5_bind(ads, &p);
00327 if (!ADS_ERR_OK(status)) {
00328 DEBUG(0,("kinit succeeded but "
00329 "ads_sasl_spnego_krb5_bind failed: %s\n",
00330 ads_errstr(status)));
00331 }
00332 }
00333
00334 ads_free_service_principal(&p);
00335
00336
00337 if (ADS_ERR_OK(status) ||
00338 !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) {
00339 return status;
00340 }
00341 } else
00342 #endif
00343 {
00344 SAFE_FREE(given_principal);
00345 }
00346
00347
00348
00349
00350 return ads_sasl_spnego_ntlmssp_bind(ads);
00351
00352 failed:
00353 return status;
00354 }
00355
00356 #ifdef HAVE_GSSAPI
00357 #define MAX_GSS_PASSES 3
00358
00359
00360
00361
00362
00363
00364
00365 static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads)
00366 {
00367 uint32 minor_status;
00368 gss_name_t serv_name;
00369 gss_buffer_desc input_name;
00370 gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT;
00371 gss_OID mech_type = GSS_C_NULL_OID;
00372 gss_buffer_desc output_token, input_token;
00373 uint32 ret_flags, conf_state;
00374 struct berval cred;
00375 struct berval *scred = NULL;
00376 int i=0;
00377 int gss_rc, rc;
00378 uint8 *p;
00379 uint32 max_msg_size = 0;
00380 char *sname = NULL;
00381 ADS_STATUS status;
00382 krb5_principal principal = NULL;
00383 krb5_context ctx = NULL;
00384 krb5_enctype enc_types[] = {
00385 #ifdef ENCTYPE_ARCFOUR_HMAC
00386 ENCTYPE_ARCFOUR_HMAC,
00387 #endif
00388 ENCTYPE_DES_CBC_MD5,
00389 ENCTYPE_NULL};
00390 gss_OID_desc nt_principal =
00391 {10, CONST_DISCARD(char *, "\052\206\110\206\367\022\001\002\002\002")};
00392
00393
00394
00395 asprintf(&sname, "ldap/%s@%s", ads->config.ldap_server_name, ads->config.realm);
00396
00397 initialize_krb5_error_table();
00398 status = ADS_ERROR_KRB5(krb5_init_context(&ctx));
00399 if (!ADS_ERR_OK(status)) {
00400 SAFE_FREE(sname);
00401 return status;
00402 }
00403 status = ADS_ERROR_KRB5(krb5_set_default_tgs_ktypes(ctx, enc_types));
00404 if (!ADS_ERR_OK(status)) {
00405 SAFE_FREE(sname);
00406 krb5_free_context(ctx);
00407 return status;
00408 }
00409 status = ADS_ERROR_KRB5(smb_krb5_parse_name(ctx, sname, &principal));
00410 if (!ADS_ERR_OK(status)) {
00411 SAFE_FREE(sname);
00412 krb5_free_context(ctx);
00413 return status;
00414 }
00415
00416 input_name.value = &principal;
00417 input_name.length = sizeof(principal);
00418
00419 gss_rc = gss_import_name(&minor_status, &input_name, &nt_principal, &serv_name);
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429 SAFE_FREE(sname);
00430
00431 if (gss_rc) {
00432 krb5_free_principal(ctx, principal);
00433 krb5_free_context(ctx);
00434 return ADS_ERROR_GSS(gss_rc, minor_status);
00435 }
00436
00437 input_token.value = NULL;
00438 input_token.length = 0;
00439
00440 for (i=0; i < MAX_GSS_PASSES; i++) {
00441 gss_rc = gss_init_sec_context(&minor_status,
00442 GSS_C_NO_CREDENTIAL,
00443 &context_handle,
00444 serv_name,
00445 mech_type,
00446 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
00447 0,
00448 NULL,
00449 &input_token,
00450 NULL,
00451 &output_token,
00452 &ret_flags,
00453 NULL);
00454
00455 if (input_token.value) {
00456 gss_release_buffer(&minor_status, &input_token);
00457 }
00458
00459 if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) {
00460 status = ADS_ERROR_GSS(gss_rc, minor_status);
00461 goto failed;
00462 }
00463
00464 cred.bv_val = (char *)output_token.value;
00465 cred.bv_len = output_token.length;
00466
00467 rc = ldap_sasl_bind_s(ads->ld, NULL, "GSSAPI", &cred, NULL, NULL,
00468 &scred);
00469 if (rc != LDAP_SASL_BIND_IN_PROGRESS) {
00470 status = ADS_ERROR(rc);
00471 goto failed;
00472 }
00473
00474 if (output_token.value) {
00475 gss_release_buffer(&minor_status, &output_token);
00476 }
00477
00478 if (scred) {
00479 input_token.value = scred->bv_val;
00480 input_token.length = scred->bv_len;
00481 } else {
00482 input_token.value = NULL;
00483 input_token.length = 0;
00484 }
00485
00486 if (gss_rc == 0) break;
00487 }
00488
00489 gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token,
00490 (int *)&conf_state,NULL);
00491 if (gss_rc) {
00492 status = ADS_ERROR_GSS(gss_rc, minor_status);
00493 goto failed;
00494 }
00495
00496 gss_release_buffer(&minor_status, &input_token);
00497
00498 p = (uint8 *)output_token.value;
00499
00500 #if 0
00501 file_save("sasl_gssapi.dat", output_token.value, output_token.length);
00502 #endif
00503
00504 if (p) {
00505 max_msg_size = (p[1]<<16) | (p[2]<<8) | p[3];
00506 }
00507
00508 gss_release_buffer(&minor_status, &output_token);
00509
00510 output_token.value = SMB_MALLOC(strlen(ads->config.bind_path) + 8);
00511 p = (uint8 *)output_token.value;
00512
00513 *p++ = 1;
00514
00515 *p++ = max_msg_size>>16;
00516 *p++ = max_msg_size>>8;
00517 *p++ = max_msg_size;
00518 snprintf((char *)p, strlen(ads->config.bind_path)+4, "dn:%s", ads->config.bind_path);
00519 p += strlen((const char *)p);
00520
00521 output_token.length = PTR_DIFF(p, output_token.value);
00522
00523 gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT,
00524 &output_token, (int *)&conf_state,
00525 &input_token);
00526 if (gss_rc) {
00527 status = ADS_ERROR_GSS(gss_rc, minor_status);
00528 goto failed;
00529 }
00530
00531 free(output_token.value);
00532
00533 cred.bv_val = (char *)input_token.value;
00534 cred.bv_len = input_token.length;
00535
00536 rc = ldap_sasl_bind_s(ads->ld, NULL, "GSSAPI", &cred, NULL, NULL,
00537 &scred);
00538 status = ADS_ERROR(rc);
00539
00540 gss_release_buffer(&minor_status, &input_token);
00541
00542 failed:
00543
00544 gss_release_name(&minor_status, &serv_name);
00545 if (context_handle != GSS_C_NO_CONTEXT)
00546 gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER);
00547 krb5_free_principal(ctx, principal);
00548 krb5_free_context(ctx);
00549
00550 if(scred)
00551 ber_bvfree(scred);
00552 return status;
00553 }
00554 #endif
00555
00556
00557 static struct {
00558 const char *name;
00559 ADS_STATUS (*fn)(ADS_STRUCT *);
00560 } sasl_mechanisms[] = {
00561 {"GSS-SPNEGO", ads_sasl_spnego_bind},
00562 #ifdef HAVE_GSSAPI
00563 {"GSSAPI", ads_sasl_gssapi_bind},
00564 #endif
00565 {NULL, NULL}
00566 };
00567
00568 ADS_STATUS ads_sasl_bind(ADS_STRUCT *ads)
00569 {
00570 const char *attrs[] = {"supportedSASLMechanisms", NULL};
00571 char **values;
00572 ADS_STATUS status;
00573 int i, j;
00574 LDAPMessage *res;
00575
00576
00577 status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
00578 if (!ADS_ERR_OK(status)) return status;
00579
00580 values = ldap_get_values(ads->ld, res, "supportedSASLMechanisms");
00581
00582
00583 for (i=0;sasl_mechanisms[i].name;i++) {
00584
00585 for (j=0;values && values[j];j++) {
00586 if (strcmp(values[j], sasl_mechanisms[i].name) == 0) {
00587 DEBUG(4,("Found SASL mechanism %s\n", values[j]));
00588 status = sasl_mechanisms[i].fn(ads);
00589 ldap_value_free(values);
00590 ldap_msgfree(res);
00591 return status;
00592 }
00593 }
00594 }
00595
00596 ldap_value_free(values);
00597 ldap_msgfree(res);
00598 return ADS_ERROR(LDAP_AUTH_METHOD_NOT_SUPPORTED);
00599 }
00600
00601 #endif
00602