関数 | |
const krb5_data * | krb5_princ_component (krb5_context, krb5_principal, int) |
static BOOL | ads_keytab_verify_ticket (krb5_context context, krb5_auth_context auth_context, const DATA_BLOB *ticket, krb5_ticket **pp_tkt, krb5_keyblock **keyblock, krb5_error_code *perr) |
static krb5_error_code | ads_secrets_verify_ticket (krb5_context context, krb5_auth_context auth_context, krb5_principal host_princ, const DATA_BLOB *ticket, krb5_ticket **pp_tkt, krb5_keyblock **keyblock, krb5_error_code *perr) |
NTSTATUS | ads_verify_ticket (TALLOC_CTX *mem_ctx, const char *realm, time_t time_offset, const DATA_BLOB *ticket, char **principal, PAC_DATA **pac_data, DATA_BLOB *ap_rep, DATA_BLOB *session_key) |
const krb5_data * krb5_princ_component | ( | krb5_context | , | |
krb5_principal | , | |||
int | ||||
) |
参照元 ads_verify_ticket()・smb_krb5_principal_compare_any_realm().
00754 { 00755 static krb5_data kdata; 00756 00757 kdata.data = (char *)krb5_principal_get_comp_string(context, principal, i); 00758 kdata.length = strlen((const char *)kdata.data); 00759 return &kdata; 00760 }
static BOOL ads_keytab_verify_ticket | ( | krb5_context | context, | |
krb5_auth_context | auth_context, | |||
const DATA_BLOB * | ticket, | |||
krb5_ticket ** | pp_tkt, | |||
krb5_keyblock ** | keyblock, | |||
krb5_error_code * | perr | |||
) | [static] |
kerberos_verify.c の 41 行で定義されています。
参照先 asprintf()・data_blob_::data・global_myname・krb5_rd_req_return_keyblock_from_keytab()・data_blob_::length・name_to_fqdn()・packet・smb_krb5_kt_free_entry()・smb_krb5_unparse_name()・strequal().
参照元 ads_verify_ticket().
00047 { 00048 krb5_error_code ret = 0; 00049 BOOL auth_ok = False; 00050 krb5_keytab keytab = NULL; 00051 krb5_kt_cursor kt_cursor; 00052 krb5_keytab_entry kt_entry; 00053 char *valid_princ_formats[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; 00054 char *entry_princ_s = NULL; 00055 fstring my_name, my_fqdn; 00056 int i; 00057 int number_matched_principals = 0; 00058 krb5_data packet; 00059 00060 *pp_tkt = NULL; 00061 *keyblock = NULL; 00062 *perr = 0; 00063 00064 /* Generate the list of principal names which we expect 00065 * clients might want to use for authenticating to the file 00066 * service. We allow name$,{host,cifs}/{name,fqdn,name.REALM}. */ 00067 00068 fstrcpy(my_name, global_myname()); 00069 00070 my_fqdn[0] = '\0'; 00071 name_to_fqdn(my_fqdn, global_myname()); 00072 00073 asprintf(&valid_princ_formats[0], "%s$@%s", my_name, lp_realm()); 00074 asprintf(&valid_princ_formats[1], "host/%s@%s", my_name, lp_realm()); 00075 asprintf(&valid_princ_formats[2], "host/%s@%s", my_fqdn, lp_realm()); 00076 asprintf(&valid_princ_formats[3], "host/%s.%s@%s", my_name, lp_realm(), lp_realm()); 00077 asprintf(&valid_princ_formats[4], "cifs/%s@%s", my_name, lp_realm()); 00078 asprintf(&valid_princ_formats[5], "cifs/%s@%s", my_fqdn, lp_realm()); 00079 asprintf(&valid_princ_formats[6], "cifs/%s.%s@%s", my_name, lp_realm(), lp_realm()); 00080 00081 ZERO_STRUCT(kt_entry); 00082 ZERO_STRUCT(kt_cursor); 00083 00084 ret = krb5_kt_default(context, &keytab); 00085 if (ret) { 00086 DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_default failed (%s)\n", error_message(ret))); 00087 goto out; 00088 } 00089 00090 /* Iterate through the keytab. For each key, if the principal 00091 * name case-insensitively matches one of the allowed formats, 00092 * try verifying the ticket using that principal. */ 00093 00094 ret = krb5_kt_start_seq_get(context, keytab, &kt_cursor); 00095 if (ret) { 00096 DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_start_seq_get failed (%s)\n", error_message(ret))); 00097 goto out; 00098 } 00099 00100 while (!auth_ok && (krb5_kt_next_entry(context, keytab, &kt_entry, &kt_cursor) == 0)) { 00101 ret = smb_krb5_unparse_name(context, kt_entry.principal, &entry_princ_s); 00102 if (ret) { 00103 DEBUG(1, ("ads_keytab_verify_ticket: smb_krb5_unparse_name failed (%s)\n", 00104 error_message(ret))); 00105 goto out; 00106 } 00107 00108 for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) { 00109 00110 if (!strequal(entry_princ_s, valid_princ_formats[i])) { 00111 continue; 00112 } 00113 00114 number_matched_principals++; 00115 packet.length = ticket->length; 00116 packet.data = (char *)ticket->data; 00117 *pp_tkt = NULL; 00118 00119 ret = krb5_rd_req_return_keyblock_from_keytab(context, &auth_context, &packet, 00120 kt_entry.principal, keytab, 00121 NULL, pp_tkt, keyblock); 00122 00123 if (ret) { 00124 DEBUG(10,("ads_keytab_verify_ticket: " 00125 "krb5_rd_req_return_keyblock_from_keytab(%s) failed: %s\n", 00126 entry_princ_s, error_message(ret))); 00127 00128 /* workaround for MIT: 00129 * as krb5_ktfile_get_entry will explicitly 00130 * close the krb5_keytab as soon as krb5_rd_req 00131 * has successfully decrypted the ticket but the 00132 * ticket is not valid yet (due to clockskew) 00133 * there is no point in querying more keytab 00134 * entries - Guenther */ 00135 00136 if (ret == KRB5KRB_AP_ERR_TKT_NYV || 00137 ret == KRB5KRB_AP_ERR_TKT_EXPIRED || 00138 ret == KRB5KRB_AP_ERR_SKEW) { 00139 break; 00140 } 00141 } else { 00142 DEBUG(3,("ads_keytab_verify_ticket: " 00143 "krb5_rd_req_return_keyblock_from_keytab succeeded for principal %s\n", 00144 entry_princ_s)); 00145 auth_ok = True; 00146 break; 00147 } 00148 } 00149 00150 /* Free the name we parsed. */ 00151 SAFE_FREE(entry_princ_s); 00152 00153 /* Free the entry we just read. */ 00154 smb_krb5_kt_free_entry(context, &kt_entry); 00155 ZERO_STRUCT(kt_entry); 00156 } 00157 krb5_kt_end_seq_get(context, keytab, &kt_cursor); 00158 00159 ZERO_STRUCT(kt_cursor); 00160 00161 out: 00162 00163 for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) { 00164 SAFE_FREE(valid_princ_formats[i]); 00165 } 00166 00167 if (!auth_ok) { 00168 if (!number_matched_principals) { 00169 DEBUG(3, ("ads_keytab_verify_ticket: no keytab principals matched expected file service name.\n")); 00170 } else { 00171 DEBUG(3, ("ads_keytab_verify_ticket: krb5_rd_req failed for all %d matched keytab principals\n", 00172 number_matched_principals)); 00173 } 00174 } 00175 00176 SAFE_FREE(entry_princ_s); 00177 00178 { 00179 krb5_keytab_entry zero_kt_entry; 00180 ZERO_STRUCT(zero_kt_entry); 00181 if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) { 00182 smb_krb5_kt_free_entry(context, &kt_entry); 00183 } 00184 } 00185 00186 { 00187 krb5_kt_cursor zero_csr; 00188 ZERO_STRUCT(zero_csr); 00189 if ((memcmp(&kt_cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) { 00190 krb5_kt_end_seq_get(context, keytab, &kt_cursor); 00191 } 00192 } 00193 00194 if (keytab) { 00195 krb5_kt_close(context, keytab); 00196 } 00197 *perr = ret; 00198 return auth_ok; 00199 }
static krb5_error_code ads_secrets_verify_ticket | ( | krb5_context | context, | |
krb5_auth_context | auth_context, | |||
krb5_principal | host_princ, | |||
const DATA_BLOB * | ticket, | |||
krb5_ticket ** | pp_tkt, | |||
krb5_keyblock ** | keyblock, | |||
krb5_error_code * | perr | |||
) | [static] |
kerberos_verify.c の 205 行で定義されています。
参照先 create_kerberos_key_from_string()・data_blob_::data・krb5_auth_con_setuseruserkey()・data_blob_::length・lp_workgroup()・packet・password・secrets_fetch_machine_password()・secrets_init().
参照元 ads_verify_ticket().
00212 { 00213 krb5_error_code ret = 0; 00214 BOOL auth_ok = False; 00215 char *password_s = NULL; 00216 krb5_data password; 00217 krb5_enctype enctypes[4] = { ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_MD5, 0, 0 }; 00218 krb5_data packet; 00219 int i; 00220 00221 *pp_tkt = NULL; 00222 *keyblock = NULL; 00223 *perr = 0; 00224 00225 #if defined(ENCTYPE_ARCFOUR_HMAC) 00226 enctypes[2] = ENCTYPE_ARCFOUR_HMAC; 00227 #endif 00228 00229 if (!secrets_init()) { 00230 DEBUG(1,("ads_secrets_verify_ticket: secrets_init failed\n")); 00231 *perr = KRB5_CONFIG_CANTOPEN; 00232 return False; 00233 } 00234 00235 password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); 00236 if (!password_s) { 00237 DEBUG(1,("ads_secrets_verify_ticket: failed to fetch machine password\n")); 00238 *perr = KRB5_LIBOS_CANTREADPWD; 00239 return False; 00240 } 00241 00242 password.data = password_s; 00243 password.length = strlen(password_s); 00244 00245 /* CIFS doesn't use addresses in tickets. This would break NAT. JRA */ 00246 00247 packet.length = ticket->length; 00248 packet.data = (char *)ticket->data; 00249 00250 /* We need to setup a auth context with each possible encoding type in turn. */ 00251 for (i=0;enctypes[i];i++) { 00252 krb5_keyblock *key = NULL; 00253 00254 if (!(key = SMB_MALLOC_P(krb5_keyblock))) { 00255 ret = ENOMEM; 00256 goto out; 00257 } 00258 00259 if (create_kerberos_key_from_string(context, host_princ, &password, key, enctypes[i])) { 00260 SAFE_FREE(key); 00261 continue; 00262 } 00263 00264 krb5_auth_con_setuseruserkey(context, auth_context, key); 00265 00266 if (!(ret = krb5_rd_req(context, &auth_context, &packet, 00267 NULL, 00268 NULL, NULL, pp_tkt))) { 00269 DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n", 00270 (unsigned int)enctypes[i] )); 00271 auth_ok = True; 00272 krb5_copy_keyblock(context, key, keyblock); 00273 krb5_free_keyblock(context, key); 00274 break; 00275 } 00276 00277 DEBUG((ret != KRB5_BAD_ENCTYPE) ? 3 : 10, 00278 ("ads_secrets_verify_ticket: enc type [%u] failed to decrypt with error %s\n", 00279 (unsigned int)enctypes[i], error_message(ret))); 00280 00281 /* successfully decrypted but ticket is just not valid at the moment */ 00282 if (ret == KRB5KRB_AP_ERR_TKT_NYV || 00283 ret == KRB5KRB_AP_ERR_TKT_EXPIRED || 00284 ret == KRB5KRB_AP_ERR_SKEW) { 00285 break; 00286 } 00287 00288 krb5_free_keyblock(context, key); 00289 00290 } 00291 00292 out: 00293 SAFE_FREE(password_s); 00294 *perr = ret; 00295 return auth_ok; 00296 }
NTSTATUS ads_verify_ticket | ( | TALLOC_CTX * | mem_ctx, | |
const char * | realm, | |||
time_t | time_offset, | |||
const DATA_BLOB * | ticket, | |||
char ** | principal, | |||
PAC_DATA ** | pac_data, | |||
DATA_BLOB * | ap_rep, | |||
DATA_BLOB * | session_key | |||
) |
kerberos_verify.c の 303 行で定義されています。
参照先 ads_keytab_verify_ticket()・ads_secrets_verify_ticket()・asprintf()・data_blob_::data・data_blob()・data_blob_free()・decode_pac_data()・dump_data_pw()・file_save()・get_auth_data_from_tkt()・get_authtime_from_tkt()・get_krb5_smb_session_key()・get_principal_from_tkt()・global_myname・grab_server_mutex()・kerberos_free_data_contents()・krb5_princ_component()・krb5_set_real_time()・krb5_to_nt_status()・data_blob_::length・nt_errstr()・packet・release_server_mutex()・smb_krb5_parse_name()・smb_krb5_unparse_name()・strlower_m().
参照元 manage_gss_spnego_request()・reply_spnego_kerberos()・winbindd_raw_kerberos_login().
00311 { 00312 NTSTATUS sret = NT_STATUS_LOGON_FAILURE; 00313 NTSTATUS pac_ret; 00314 DATA_BLOB auth_data; 00315 krb5_context context = NULL; 00316 krb5_auth_context auth_context = NULL; 00317 krb5_data packet; 00318 krb5_ticket *tkt = NULL; 00319 krb5_rcache rcache = NULL; 00320 krb5_keyblock *keyblock = NULL; 00321 time_t authtime; 00322 krb5_error_code ret = 0; 00323 00324 krb5_principal host_princ = NULL; 00325 krb5_const_principal client_principal = NULL; 00326 char *host_princ_s = NULL; 00327 BOOL auth_ok = False; 00328 BOOL got_replay_mutex = False; 00329 BOOL got_auth_data = False; 00330 00331 ZERO_STRUCT(packet); 00332 ZERO_STRUCT(auth_data); 00333 00334 *principal = NULL; 00335 *pac_data = NULL; 00336 *ap_rep = data_blob(NULL,0); 00337 *session_key = data_blob(NULL,0); 00338 00339 initialize_krb5_error_table(); 00340 ret = krb5_init_context(&context); 00341 if (ret) { 00342 DEBUG(1,("ads_verify_ticket: krb5_init_context failed (%s)\n", error_message(ret))); 00343 return NT_STATUS_LOGON_FAILURE; 00344 } 00345 00346 if (time_offset != 0) { 00347 krb5_set_real_time(context, time(NULL) + time_offset, 0); 00348 } 00349 00350 ret = krb5_set_default_realm(context, realm); 00351 if (ret) { 00352 DEBUG(1,("ads_verify_ticket: krb5_set_default_realm failed (%s)\n", error_message(ret))); 00353 goto out; 00354 } 00355 00356 /* This whole process is far more complex than I would 00357 like. We have to go through all this to allow us to store 00358 the secret internally, instead of using /etc/krb5.keytab */ 00359 00360 ret = krb5_auth_con_init(context, &auth_context); 00361 if (ret) { 00362 DEBUG(1,("ads_verify_ticket: krb5_auth_con_init failed (%s)\n", error_message(ret))); 00363 goto out; 00364 } 00365 00366 asprintf(&host_princ_s, "%s$", global_myname()); 00367 if (!host_princ_s) { 00368 goto out; 00369 } 00370 00371 strlower_m(host_princ_s); 00372 ret = smb_krb5_parse_name(context, host_princ_s, &host_princ); 00373 if (ret) { 00374 DEBUG(1,("ads_verify_ticket: smb_krb5_parse_name(%s) failed (%s)\n", 00375 host_princ_s, error_message(ret))); 00376 goto out; 00377 } 00378 00379 00380 /* Lock a mutex surrounding the replay as there is no locking in the MIT krb5 00381 * code surrounding the replay cache... */ 00382 00383 if (!grab_server_mutex("replay cache mutex")) { 00384 DEBUG(1,("ads_verify_ticket: unable to protect replay cache with mutex.\n")); 00385 ret = KRB5_CC_IO; 00386 goto out; 00387 } 00388 00389 got_replay_mutex = True; 00390 00391 /* 00392 * JRA. We must set the rcache here. This will prevent replay attacks. 00393 */ 00394 00395 ret = krb5_get_server_rcache(context, krb5_princ_component(context, host_princ, 0), &rcache); 00396 if (ret) { 00397 DEBUG(1,("ads_verify_ticket: krb5_get_server_rcache failed (%s)\n", error_message(ret))); 00398 goto out; 00399 } 00400 00401 ret = krb5_auth_con_setrcache(context, auth_context, rcache); 00402 if (ret) { 00403 DEBUG(1,("ads_verify_ticket: krb5_auth_con_setrcache failed (%s)\n", error_message(ret))); 00404 goto out; 00405 } 00406 00407 if (lp_use_kerberos_keytab()) { 00408 auth_ok = ads_keytab_verify_ticket(context, auth_context, ticket, &tkt, &keyblock, &ret); 00409 } 00410 if (!auth_ok) { 00411 auth_ok = ads_secrets_verify_ticket(context, auth_context, host_princ, 00412 ticket, &tkt, &keyblock, &ret); 00413 } 00414 00415 release_server_mutex(); 00416 got_replay_mutex = False; 00417 00418 #if 0 00419 /* Heimdal leaks here, if we fix the leak, MIT crashes */ 00420 if (rcache) { 00421 krb5_rc_close(context, rcache); 00422 } 00423 #endif 00424 00425 if (!auth_ok) { 00426 DEBUG(3,("ads_verify_ticket: krb5_rd_req with auth failed (%s)\n", 00427 error_message(ret))); 00428 /* Try map the error return in case it's something like 00429 * a clock skew error. 00430 */ 00431 sret = krb5_to_nt_status(ret); 00432 if (NT_STATUS_IS_OK(sret) || NT_STATUS_EQUAL(sret,NT_STATUS_UNSUCCESSFUL)) { 00433 sret = NT_STATUS_LOGON_FAILURE; 00434 } 00435 DEBUG(10,("ads_verify_ticket: returning error %s\n", 00436 nt_errstr(sret) )); 00437 goto out; 00438 } 00439 00440 authtime = get_authtime_from_tkt(tkt); 00441 client_principal = get_principal_from_tkt(tkt); 00442 00443 ret = krb5_mk_rep(context, auth_context, &packet); 00444 if (ret) { 00445 DEBUG(3,("ads_verify_ticket: Failed to generate mutual authentication reply (%s)\n", 00446 error_message(ret))); 00447 goto out; 00448 } 00449 00450 *ap_rep = data_blob(packet.data, packet.length); 00451 if (packet.data) { 00452 kerberos_free_data_contents(context, &packet); 00453 ZERO_STRUCT(packet); 00454 } 00455 00456 get_krb5_smb_session_key(context, auth_context, session_key, True); 00457 dump_data_pw("SMB session key (from ticket)\n", session_key->data, session_key->length); 00458 00459 #if 0 00460 file_save("/tmp/ticket.dat", ticket->data, ticket->length); 00461 #endif 00462 00463 /* continue when no PAC is retrieved or we couldn't decode the PAC 00464 (like accounts that have the UF_NO_AUTH_DATA_REQUIRED flag set, or 00465 Kerberos tickets encrypted using a DES key) - Guenther */ 00466 00467 got_auth_data = get_auth_data_from_tkt(mem_ctx, &auth_data, tkt); 00468 if (!got_auth_data) { 00469 DEBUG(3,("ads_verify_ticket: did not retrieve auth data. continuing without PAC\n")); 00470 } 00471 00472 if (got_auth_data && pac_data != NULL) { 00473 00474 pac_ret = decode_pac_data(mem_ctx, &auth_data, context, keyblock, client_principal, authtime, pac_data); 00475 if (!NT_STATUS_IS_OK(pac_ret)) { 00476 DEBUG(3,("ads_verify_ticket: failed to decode PAC_DATA: %s\n", nt_errstr(pac_ret))); 00477 *pac_data = NULL; 00478 } 00479 data_blob_free(&auth_data); 00480 } 00481 00482 #if 0 00483 #if defined(HAVE_KRB5_TKT_ENC_PART2) 00484 /* MIT */ 00485 if (tkt->enc_part2) { 00486 file_save("/tmp/authdata.dat", 00487 tkt->enc_part2->authorization_data[0]->contents, 00488 tkt->enc_part2->authorization_data[0]->length); 00489 } 00490 #else 00491 /* Heimdal */ 00492 if (tkt->ticket.authorization_data) { 00493 file_save("/tmp/authdata.dat", 00494 tkt->ticket.authorization_data->val->ad_data.data, 00495 tkt->ticket.authorization_data->val->ad_data.length); 00496 } 00497 #endif 00498 #endif 00499 00500 if ((ret = smb_krb5_unparse_name(context, client_principal, principal))) { 00501 DEBUG(3,("ads_verify_ticket: smb_krb5_unparse_name failed (%s)\n", 00502 error_message(ret))); 00503 sret = NT_STATUS_LOGON_FAILURE; 00504 goto out; 00505 } 00506 00507 sret = NT_STATUS_OK; 00508 00509 out: 00510 00511 if (got_replay_mutex) { 00512 release_server_mutex(); 00513 } 00514 00515 if (!NT_STATUS_IS_OK(sret)) { 00516 data_blob_free(&auth_data); 00517 } 00518 00519 if (!NT_STATUS_IS_OK(sret)) { 00520 data_blob_free(ap_rep); 00521 } 00522 00523 if (host_princ) { 00524 krb5_free_principal(context, host_princ); 00525 } 00526 00527 if (keyblock) { 00528 krb5_free_keyblock(context, keyblock); 00529 } 00530 00531 if (tkt != NULL) { 00532 krb5_free_ticket(context, tkt); 00533 } 00534 00535 SAFE_FREE(host_princ_s); 00536 00537 if (auth_context) { 00538 krb5_auth_con_free(context, auth_context); 00539 } 00540 00541 if (context) { 00542 krb5_free_context(context); 00543 } 00544 00545 return sret; 00546 }