libads/kerberos_verify.c

ソースコードを見る。

関数

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   
)

clikrb5.c753 行で定義されています。

参照元 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.c41 行で定義されています。

参照先 asprintf()data_blob_::dataglobal_mynamekrb5_rd_req_return_keyblock_from_keytab()data_blob_::lengthname_to_fqdn()packetsmb_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.c205 行で定義されています。

参照先 create_kerberos_key_from_string()data_blob_::datakrb5_auth_con_setuseruserkey()data_blob_::lengthlp_workgroup()packetpasswordsecrets_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.c303 行で定義されています。

参照先 ads_keytab_verify_ticket()ads_secrets_verify_ticket()asprintf()data_blob_::datadata_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_mynamegrab_server_mutex()kerberos_free_data_contents()krb5_princ_component()krb5_set_real_time()krb5_to_nt_status()data_blob_::lengthnt_errstr()packetrelease_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 }


Sambaに対してSat Aug 29 21:23:42 2009に生成されました。  doxygen 1.4.7