00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "includes.h"
00028
00029 #ifdef HAVE_KRB5
00030
00031 #if !defined(HAVE_KRB5_PRINC_COMPONENT)
00032 const krb5_data *krb5_princ_component(krb5_context, krb5_principal, int );
00033 #endif
00034
00035
00036
00037
00038
00039
00040
00041 static BOOL ads_keytab_verify_ticket(krb5_context context,
00042 krb5_auth_context auth_context,
00043 const DATA_BLOB *ticket,
00044 krb5_ticket **pp_tkt,
00045 krb5_keyblock **keyblock,
00046 krb5_error_code *perr)
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
00065
00066
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
00091
00092
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
00129
00130
00131
00132
00133
00134
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
00151 SAFE_FREE(entry_princ_s);
00152
00153
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 }
00200
00201
00202
00203
00204
00205 static krb5_error_code ads_secrets_verify_ticket(krb5_context context,
00206 krb5_auth_context auth_context,
00207 krb5_principal host_princ,
00208 const DATA_BLOB *ticket,
00209 krb5_ticket **pp_tkt,
00210 krb5_keyblock **keyblock,
00211 krb5_error_code *perr)
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
00246
00247 packet.length = ticket->length;
00248 packet.data = (char *)ticket->data;
00249
00250
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
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 }
00297
00298
00299
00300
00301
00302
00303 NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
00304 const char *realm,
00305 time_t time_offset,
00306 const DATA_BLOB *ticket,
00307 char **principal,
00308 PAC_DATA **pac_data,
00309 DATA_BLOB *ap_rep,
00310 DATA_BLOB *session_key)
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
00357
00358
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
00381
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
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
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
00429
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
00464
00465
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
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
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 }
00547
00548 #endif