krb5KeyblockObject *keyblock_new(PyObject *unused, PyObject *args) { krb5_error_code ret; krb5ContextObject *context; krb5EnctypeObject *enctype; char *password; PyObject *arg; krb5KeyblockObject *self = (krb5KeyblockObject *) PyObject_New(krb5KeyblockObject, &krb5KeyblockType); int error = 0; if (!PyArg_ParseTuple(args, "OOsO", &context, &enctype, &password, &arg)) return NULL; if (self == NULL) return NULL; self->context = context->context; #if PY_MAJOR_VERSION >= 2 && PY_MINOR_VERSION >= 2 if (PyObject_TypeCheck(arg, &krb5SaltType)) { krb5SaltObject *salt = (krb5SaltObject*)arg; ret = krb5_string_to_key_salt(context->context, enctype->enctype, password, salt->salt, &self->keyblock); } else if (PyObject_TypeCheck(arg, &krb5PrincipalType)) { #else if (1) { #endif krb5PrincipalObject *principal = (krb5PrincipalObject*)arg; ret = krb5_string_to_key(context->context, enctype->enctype, password, principal->principal, &self->keyblock); } else { PyErr_SetString(PyExc_TypeError, "either principal or salt needs to be passed"); error = 1; goto out; } if (ret) { error = 1; krb5_exception(NULL, ret); goto out; } out: if (error) return NULL; else return self; } krb5KeyblockObject *keyblock_raw_new(PyObject *unused, PyObject *args) { krb5_error_code ret; krb5ContextObject *py_context; PyObject *py_enctype; PyObject *py_key; uint8_t *key_buf; size_t key_len; krb5_enctype enctype; int error = 0; krb5KeyblockObject *self = (krb5KeyblockObject *) PyObject_NEW(krb5KeyblockObject, &krb5KeyblockType); if (!PyArg_ParseTuple(args, "O!OS", &krb5ContextType, &py_context, &py_enctype, &py_key)) return NULL; if (self == NULL) return NULL; self->context = py_context->context; if (PyObject_TypeCheck(py_enctype, &krb5EnctypeType)) { krb5EnctypeObject *enctype_obj = (krb5EnctypeObject*)py_enctype; enctype = enctype_obj>enctype; } else if (PyInt_Check(py_enctype)) { enctype = PyInt_AsLong(py_enctype); } else { PyErr_SetString(PyExc_TypeError, "enctype must be of type integer or krb5EnctypeObject"); error = 1; goto out; } key_buf = (uint8_t *) PyString_AsString(py_key); key_len = PyString_Size(py_key); ret = krb5_keyblock_init(py_context->context, enctype, key_buf, key_len, &self->keyblock); if (ret) { error = 1; krb5_exception(NULL, ret); goto out; } out: if (error) return NULL; else return self; }
krb5_error_code KRB5_LIB_FUNCTION _krb5_krb_decomp_ticket(krb5_context context, const krb5_data *enc_ticket, const krb5_keyblock *key, const char *local_realm, char **sname, char **sinstance, struct _krb5_krb_auth_data *ad) { krb5_error_code ret; krb5_ssize_t size; krb5_storage *sp = NULL; krb5_data ticket; unsigned char des_key[8]; memset(ad, 0, sizeof(*ad)); krb5_data_zero(&ticket); *sname = NULL; *sinstance = NULL; RCHECK(ret, decrypt_etext(context, key, enc_ticket, &ticket), error); sp = krb5_storage_from_data(&ticket); if (sp == NULL) { krb5_data_free(&ticket); krb5_set_error_string(context, "alloc: out of memory"); return ENOMEM; } krb5_storage_set_eof_code(sp, EINVAL); /* XXX */ RCHECK(ret, krb5_ret_int8(sp, &ad->k_flags), error); RCHECK(ret, get_v4_stringz(sp, &ad->pname, ANAME_SZ), error); RCHECK(ret, get_v4_stringz(sp, &ad->pinst, INST_SZ), error); RCHECK(ret, get_v4_stringz(sp, &ad->prealm, REALM_SZ), error); RCHECK(ret, krb5_ret_uint32(sp, &ad->address), error); size = krb5_storage_read(sp, des_key, sizeof(des_key)); if (size != sizeof(des_key)) { ret = EINVAL; /* XXX */ goto error; } RCHECK(ret, krb5_ret_uint8(sp, &ad->life), error); if (ad->k_flags & 1) krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_LE); else krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_BE); RCHECK(ret, krb5_ret_uint32(sp, &ad->time_sec), error); RCHECK(ret, get_v4_stringz(sp, sname, ANAME_SZ), error); RCHECK(ret, get_v4_stringz(sp, sinstance, INST_SZ), error); ret = krb5_keyblock_init(context, ETYPE_DES_PCBC_NONE, des_key, sizeof(des_key), &ad->session); if (ret) goto error; if (strlen(ad->prealm) == 0) { free(ad->prealm); ad->prealm = strdup(local_realm); if (ad->prealm == NULL) { ret = ENOMEM; goto error; } } error: memset(des_key, 0, sizeof(des_key)); if (sp) krb5_storage_free(sp); krb5_data_free(&ticket); if (ret) { if (*sname) { free(*sname); *sname = NULL; } if (*sinstance) { free(*sinstance); *sinstance = NULL; } _krb5_krb_free_auth_data(context, ad); krb5_set_error_string(context, "Failed to decode v4 ticket"); } return ret; }
static bool torture_pac_self_check(struct torture_context *tctx) { NTSTATUS nt_status; DATA_BLOB tmp_blob; struct PAC_DATA *pac_data; struct PAC_LOGON_INFO *logon_info; union netr_Validation validation; /* Generate a nice, arbitary keyblock */ uint8_t server_bytes[16]; uint8_t krbtgt_bytes[16]; krb5_keyblock server_keyblock; krb5_keyblock krbtgt_keyblock; krb5_error_code ret; struct smb_krb5_context *smb_krb5_context; struct auth_serversupplied_info *server_info; struct auth_serversupplied_info *server_info_out; krb5_principal client_principal; time_t logon_time = time(NULL); TALLOC_CTX *mem_ctx = tctx; torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx, NULL, tctx->lp_ctx, &smb_krb5_context), "smb_krb5_init_context"); generate_random_buffer(server_bytes, 16); generate_random_buffer(krbtgt_bytes, 16); ret = krb5_keyblock_init(smb_krb5_context->krb5_context, ENCTYPE_ARCFOUR_HMAC, server_bytes, sizeof(server_bytes), &server_keyblock); torture_assert(tctx, !ret, talloc_asprintf(tctx, "(self test) Server Keyblock encoding failed: %s", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); ret = krb5_keyblock_init(smb_krb5_context->krb5_context, ENCTYPE_ARCFOUR_HMAC, krbtgt_bytes, sizeof(krbtgt_bytes), &krbtgt_keyblock); if (ret) { char *err = smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); torture_fail(tctx, talloc_asprintf(tctx, "(self test) KRBTGT Keyblock encoding failed: %s", err)); } /* We need an input, and this one requires no underlying database */ nt_status = auth_anonymous_server_info(mem_ctx, lp_netbios_name(tctx->lp_ctx), &server_info); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); torture_fail(tctx, "auth_anonymous_server_info"); } ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, server_info->account_name, KRB5_PRINCIPAL_PARSE_NO_REALM, &client_principal); if (ret) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); torture_fail(tctx, "krb5_parse_name_flags(norealm)"); } /* OK, go ahead and make a PAC */ ret = kerberos_create_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), server_info, smb_krb5_context->krb5_context, &krbtgt_keyblock, &server_keyblock, client_principal, logon_time, &tmp_blob); if (ret) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC encoding failed: %s", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); } dump_data(10,tmp_blob.data,tmp_blob.length); /* Now check that we can read it back (using full decode and validate) */ nt_status = kerberos_decode_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data, tmp_blob, smb_krb5_context->krb5_context, &krbtgt_keyblock, &server_keyblock, client_principal, logon_time, NULL); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC decoding failed: %s", nt_errstr(nt_status))); } /* Now check we can read it back (using Heimdal's pac parsing) */ nt_status = kerberos_pac_blob_to_server_info(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), tmp_blob, smb_krb5_context->krb5_context, &server_info_out); if (!dom_sid_equal(server_info->account_sid, server_info_out->account_sid)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC Decode resulted in *different* domain SID: %s != %s", dom_sid_string(mem_ctx, server_info->account_sid), dom_sid_string(mem_ctx, server_info_out->account_sid))); } talloc_free(server_info_out); /* Now check that we can read it back (yet again) */ nt_status = kerberos_pac_logon_info(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &logon_info, tmp_blob, smb_krb5_context->krb5_context, &krbtgt_keyblock, &server_keyblock, client_principal, logon_time, NULL); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC decoding (for logon info) failed: %s", nt_errstr(nt_status))); } krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &krbtgt_keyblock); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); /* And make a server info from the samba-parsed PAC */ validation.sam3 = &logon_info->info3; nt_status = make_server_info_netlogon_validation(mem_ctx, "", 3, &validation, &server_info_out); if (!NT_STATUS_IS_OK(nt_status)) { torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC decoding (make server info) failed: %s", nt_errstr(nt_status))); } if (!dom_sid_equal(server_info->account_sid, server_info_out->account_sid)) { torture_fail(tctx, talloc_asprintf(tctx, "(self test) PAC Decode resulted in *different* domain SID: %s != %s", dom_sid_string(mem_ctx, server_info->account_sid), dom_sid_string(mem_ctx, server_info_out->account_sid))); } return true; }
/* Check with a known 'well formed' PAC, from my test server */ static bool torture_pac_saved_check(struct torture_context *tctx) { NTSTATUS nt_status; enum ndr_err_code ndr_err; DATA_BLOB tmp_blob, validate_blob; struct PAC_DATA *pac_data, pac_data2; struct PAC_LOGON_INFO *logon_info; union netr_Validation validation; const char *pac_file, *pac_kdc_key, *pac_member_key; struct auth_serversupplied_info *server_info_out; krb5_keyblock server_keyblock; krb5_keyblock krbtgt_keyblock, *krbtgt_keyblock_p; struct samr_Password *krbtgt_bytes, *krbsrv_bytes; krb5_error_code ret; struct smb_krb5_context *smb_krb5_context; const char *principal_string; char *broken_principal_string; krb5_principal client_principal; const char *authtime_string; time_t authtime; TALLOC_CTX *mem_ctx = tctx; torture_assert(tctx, 0 == smb_krb5_init_context(mem_ctx, NULL, tctx->lp_ctx, &smb_krb5_context), "smb_krb5_init_context"); pac_kdc_key = torture_setting_string(tctx, "pac_kdc_key", "B286757148AF7FD252C53603A150B7E7"); pac_member_key = torture_setting_string(tctx, "pac_member_key", "D217FAEAE5E6B5F95CCC94077AB8A5FC"); torture_comment(tctx, "Using pac_kdc_key '%s'\n", pac_kdc_key); torture_comment(tctx, "Using pac_member_key '%s'\n", pac_member_key); /* The krbtgt key in use when the above PAC was generated. * This is an arcfour-hmac-md5 key, extracted with our 'net * samdump' tool. */ if (*pac_kdc_key == 0) { krbtgt_bytes = NULL; } else { krbtgt_bytes = smbpasswd_gethexpwd(mem_ctx, pac_kdc_key); if (!krbtgt_bytes) { torture_fail(tctx, "(saved test) Could not interpret krbtgt key"); } } krbsrv_bytes = smbpasswd_gethexpwd(mem_ctx, pac_member_key); if (!krbsrv_bytes) { torture_fail(tctx, "(saved test) Could not interpret krbsrv key"); } ret = krb5_keyblock_init(smb_krb5_context->krb5_context, ENCTYPE_ARCFOUR_HMAC, krbsrv_bytes->hash, sizeof(krbsrv_bytes->hash), &server_keyblock); torture_assert(tctx, !ret, talloc_asprintf(tctx, "(saved test) Server Keyblock encoding failed: %s", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); if (krbtgt_bytes) { ret = krb5_keyblock_init(smb_krb5_context->krb5_context, ENCTYPE_ARCFOUR_HMAC, krbtgt_bytes->hash, sizeof(krbtgt_bytes->hash), &krbtgt_keyblock); if (ret) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) Server Keyblock encoding failed: %s", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); } krbtgt_keyblock_p = &krbtgt_keyblock; } else { krbtgt_keyblock_p = NULL; } pac_file = torture_setting_string(tctx, "pac_file", NULL); if (pac_file) { tmp_blob.data = (uint8_t *)file_load(pac_file, &tmp_blob.length, 0, mem_ctx); torture_comment(tctx, "(saved test) Loaded pac of size %ld from %s\n", (long)tmp_blob.length, pac_file); } else { tmp_blob = data_blob_talloc(mem_ctx, saved_pac, sizeof(saved_pac)); } dump_data(10,tmp_blob.data,tmp_blob.length); principal_string = torture_setting_string(tctx, "pac_client_principal", "[email protected]"); authtime_string = torture_setting_string(tctx, "pac_authtime", "1120440609"); authtime = strtoull(authtime_string, NULL, 0); ret = krb5_parse_name(smb_krb5_context->krb5_context, principal_string, &client_principal); if (ret) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) parsing of client principal [%s] failed: %s", principal_string, smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); } /* Decode and verify the signaure on the PAC */ nt_status = kerberos_decode_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, NULL); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC decoding failed: %s", nt_errstr(nt_status))); } /* Now check we can read it back (using Heimdal's pac parsing) */ nt_status = kerberos_pac_blob_to_server_info(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), tmp_blob, smb_krb5_context->krb5_context, &server_info_out); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) Heimdal PAC decoding failed: %s", nt_errstr(nt_status))); } if (!pac_file && !dom_sid_equal(dom_sid_parse_talloc(mem_ctx, "S-1-5-21-3048156945-3961193616-3706469200-1005"), server_info_out->account_sid)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) Heimdal PAC Decode resulted in *different* domain SID: %s != %s", "S-1-5-21-3048156945-3961193616-3706469200-1005", dom_sid_string(mem_ctx, server_info_out->account_sid))); } talloc_free(server_info_out); /* Parse the PAC again, for the logon info this time (using Samba4's parsing) */ nt_status = kerberos_pac_logon_info(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &logon_info, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, NULL); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC decoding (for logon info) failed: %s", nt_errstr(nt_status))); } validation.sam3 = &logon_info->info3; nt_status = make_server_info_netlogon_validation(mem_ctx, "", 3, &validation, &server_info_out); if (!NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC decoding (make server info) failed: %s", nt_errstr(nt_status))); } if (!pac_file && !dom_sid_equal(dom_sid_parse_talloc(mem_ctx, "S-1-5-21-3048156945-3961193616-3706469200-1005"), server_info_out->account_sid)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC Decode resulted in *different* domain SID: %s != %s", "S-1-5-21-3048156945-3961193616-3706469200-1005", dom_sid_string(mem_ctx, server_info_out->account_sid))); } if (krbtgt_bytes == NULL) { torture_comment(tctx, "skipping PAC encoding tests as non kdc key\n"); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); return true; } ret = kerberos_encode_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), pac_data, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, &validate_blob); if (ret != 0) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, "(saved test) PAC push failed"); } dump_data(10, validate_blob.data, validate_blob.length); /* compare both the length and the data bytes after a * pull/push cycle. This ensures we use the exact same * pointer, padding etc algorithms as win2k3. */ if (tmp_blob.length != validate_blob.length) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC push failed: original buffer length[%u] != created buffer length[%u]", (unsigned)tmp_blob.length, (unsigned)validate_blob.length)); } if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); DEBUG(0, ("tmp_data:\n")); dump_data(0, tmp_blob.data, tmp_blob.length); DEBUG(0, ("validate_blob:\n")); dump_data(0, validate_blob.data, validate_blob.length); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC push failed: length[%u] matches, but data does not", (unsigned)tmp_blob.length)); } ret = kerberos_create_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), server_info_out, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, &validate_blob); if (ret != 0) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, "(saved test) regnerated PAC create failed"); } dump_data(10,validate_blob.data,validate_blob.length); /* compare both the length and the data bytes after a * pull/push cycle. This ensures we use the exact same * pointer, padding etc algorithms as win2k3. */ if (tmp_blob.length != validate_blob.length) { ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data2, (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); nt_status = ndr_map_error2ntstatus(ndr_err); torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC"); NDR_PRINT_DEBUG(PAC_DATA, pac_data); NDR_PRINT_DEBUG(PAC_DATA, &pac_data2); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC regenerate failed: original buffer length[%u] != created buffer length[%u]", (unsigned)tmp_blob.length, (unsigned)validate_blob.length)); } if (memcmp(tmp_blob.data, validate_blob.data, tmp_blob.length) != 0) { ndr_err = ndr_pull_struct_blob(&validate_blob, mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data2, (ndr_pull_flags_fn_t)ndr_pull_PAC_DATA); nt_status = ndr_map_error2ntstatus(ndr_err); torture_assert_ntstatus_ok(tctx, nt_status, "can't parse the PAC"); NDR_PRINT_DEBUG(PAC_DATA, pac_data); NDR_PRINT_DEBUG(PAC_DATA, &pac_data2); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); DEBUG(0, ("tmp_data:\n")); dump_data(0, tmp_blob.data, tmp_blob.length); DEBUG(0, ("validate_blob:\n")); dump_data(0, validate_blob.data, validate_blob.length); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) PAC regenerate failed: length[%u] matches, but data does not", (unsigned)tmp_blob.length)); } /* Break the auth time, to ensure we check this vital detail (not setting this caused all the pain in the first place... */ nt_status = kerberos_decode_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime + 1, NULL); if (NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); krb5_free_principal(smb_krb5_context->krb5_context, client_principal); torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken auth time (time + 1)"); } /* Break the client principal */ krb5_free_principal(smb_krb5_context->krb5_context, client_principal); broken_principal_string = talloc_strdup(mem_ctx, principal_string); broken_principal_string[0]++; ret = krb5_parse_name(smb_krb5_context->krb5_context, broken_principal_string, &client_principal); if (ret) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); torture_fail(tctx, talloc_asprintf(tctx, "(saved test) parsing of broken client principal failed: %s", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); } nt_status = kerberos_decode_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, NULL); if (NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on modified principal"); } /* Finally... Bugger up the signature, and check we fail the checksum */ tmp_blob.data[tmp_blob.length - 2]++; nt_status = kerberos_decode_pac(mem_ctx, lp_iconv_convenience(tctx->lp_ctx), &pac_data, tmp_blob, smb_krb5_context->krb5_context, krbtgt_keyblock_p, &server_keyblock, client_principal, authtime, NULL); if (NT_STATUS_IS_OK(nt_status)) { krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); torture_fail(tctx, "(saved test) PAC decoding DID NOT fail on broken checksum"); } krb5_free_keyblock_contents(smb_krb5_context->krb5_context, krbtgt_keyblock_p); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &server_keyblock); return true; }
krb5_error_code kinit_to_ccache(TALLOC_CTX *parent_ctx, struct cli_credentials *credentials, struct smb_krb5_context *smb_krb5_context, krb5_ccache ccache) { krb5_error_code ret; const char *password; time_t kdc_time = 0; krb5_principal princ; int tries; TALLOC_CTX *mem_ctx = talloc_new(parent_ctx); if (!mem_ctx) { return ENOMEM; } ret = principal_from_credentials(mem_ctx, credentials, smb_krb5_context, &princ); if (ret) { talloc_free(mem_ctx); return ret; } password = cli_credentials_get_password(credentials); tries = 2; while (tries--) { if (password) { ret = kerberos_kinit_password_cc(smb_krb5_context->krb5_context, ccache, princ, password, NULL, &kdc_time); } else { /* No password available, try to use a keyblock instead */ krb5_keyblock keyblock; const struct samr_Password *mach_pwd; mach_pwd = cli_credentials_get_nt_hash(credentials, mem_ctx); if (!mach_pwd) { talloc_free(mem_ctx); DEBUG(1, ("kinit_to_ccache: No password available for kinit\n")); return EINVAL; } ret = krb5_keyblock_init(smb_krb5_context->krb5_context, ENCTYPE_ARCFOUR_HMAC, mach_pwd->hash, sizeof(mach_pwd->hash), &keyblock); if (ret == 0) { ret = kerberos_kinit_keyblock_cc(smb_krb5_context->krb5_context, ccache, princ, &keyblock, NULL, &kdc_time); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &keyblock); } } if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) { /* Perhaps we have been given an invalid skew, so try again without it */ time_t t = time(NULL); krb5_set_real_time(smb_krb5_context->krb5_context, t, 0); } else { /* not a skew problem */ break; } } if (ret == KRB5KRB_AP_ERR_SKEW || ret == KRB5_KDCREP_SKEW) { DEBUG(1,("kinit for %s failed (%s)\n", cli_credentials_get_principal(credentials, mem_ctx), smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } /* cope with ticket being in the future due to clock skew */ if ((unsigned)kdc_time > time(NULL)) { time_t t = time(NULL); int time_offset =(unsigned)kdc_time-t; DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset)); krb5_set_real_time(smb_krb5_context->krb5_context, t + time_offset + 1, 0); } if (ret == KRB5KDC_ERR_PREAUTH_FAILED && cli_credentials_wrong_password(credentials)) { ret = kinit_to_ccache(parent_ctx, credentials, smb_krb5_context, ccache); } if (ret) { DEBUG(1,("kinit for %s failed (%s)\n", cli_credentials_get_principal(credentials, mem_ctx), smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } talloc_free(mem_ctx); return 0; }
int kt_add(struct add_options *opt, int argc, char **argv) { krb5_error_code ret; krb5_keytab keytab; krb5_keytab_entry entry; char buf[1024]; krb5_enctype enctype; if((keytab = ktutil_open_keytab()) == NULL) return 1; memset(&entry, 0, sizeof(entry)); if(opt->principal_string == NULL) { if(readstring("Principal: ", buf, sizeof(buf)) == NULL) return 1; opt->principal_string = buf; } ret = krb5_parse_name(context, opt->principal_string, &entry.principal); if(ret) { krb5_warn(context, ret, "%s", opt->principal_string); goto out; } if(opt->enctype_string == NULL) { if(readstring("Encryption type: ", buf, sizeof(buf)) == NULL) { ret = 1; goto out; } opt->enctype_string = buf; } ret = krb5_string_to_enctype(context, opt->enctype_string, &enctype); if(ret) { int t; if(sscanf(opt->enctype_string, "%d", &t) == 1) enctype = t; else { krb5_warn(context, ret, "%s", opt->enctype_string); goto out; } } if(opt->kvno_integer == -1) { if(readstring("Key version: ", buf, sizeof(buf)) == NULL) { ret = 1; goto out; } if(sscanf(buf, "%u", &opt->kvno_integer) != 1) goto out; } if(opt->password_string == NULL && opt->random_flag == 0) { if(UI_UTIL_read_pw_string(buf, sizeof(buf), "Password: "******"malloc"); goto out; } if ((size_t)hex_decode(opt->password_string, data, len) != len) { free(data); krb5_warn(context, ENOMEM, "hex decode failed"); goto out; } ret = krb5_keyblock_init(context, enctype, data, len, &entry.keyblock); free(data); } else if (!opt->salt_flag) { krb5_salt salt; krb5_data pw; salt.salttype = KRB5_PW_SALT; salt.saltvalue.data = NULL; salt.saltvalue.length = 0; pw.data = (void*)opt->password_string; pw.length = strlen(opt->password_string); ret = krb5_string_to_key_data_salt(context, enctype, pw, salt, &entry.keyblock); } else { ret = krb5_string_to_key(context, enctype, opt->password_string, entry.principal, &entry.keyblock); } memset (opt->password_string, 0, strlen(opt->password_string)); } else { ret = krb5_generate_random_keyblock(context, enctype, &entry.keyblock); } if(ret) { krb5_warn(context, ret, "add"); goto out; } entry.vno = opt->kvno_integer; entry.timestamp = time (NULL); ret = krb5_kt_add_entry(context, keytab, &entry); if(ret) krb5_warn(context, ret, "add"); out: krb5_kt_free_entry(context, &entry); krb5_kt_close(context, keytab); return ret != 0; }
static int create_keytab(TALLOC_CTX *parent_ctx, struct cli_credentials *machine_account, struct smb_krb5_context *smb_krb5_context, const char **enctype_strings, krb5_keytab keytab, BOOL add_old) { krb5_error_code ret; const char *password_s; const char *old_secret; int kvno; krb5_principal salt_princ; krb5_principal princ; const char *princ_string; TALLOC_CTX *mem_ctx = talloc_new(parent_ctx); if (!mem_ctx) { return ENOMEM; } princ_string = cli_credentials_get_principal(machine_account, mem_ctx); /* Get the principal we will store the new keytab entries under */ ret = principal_from_credentials(mem_ctx, machine_account, smb_krb5_context, &princ); if (ret) { DEBUG(1,("create_keytab: makeing krb5 principal failed (%s)\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } /* The salt used to generate these entries may be different however, fetch that */ ret = salt_principal_from_credentials(mem_ctx, machine_account, smb_krb5_context, &salt_princ); if (ret) { DEBUG(1,("create_keytab: makeing salt principal failed (%s)\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } /* Finally, do the dance to get the password to put in the entry */ password_s = cli_credentials_get_password(machine_account); if (!password_s) { krb5_keytab_entry entry; const struct samr_Password *mach_pwd; if (!str_list_check(enctype_strings, "arcfour-hmac-md5")) { DEBUG(1, ("Asked to create keytab, but with only an NT hash supplied, " "but not listing arcfour-hmac-md5 as an enc type to include in the keytab!\n")); talloc_free(mem_ctx); return EINVAL; } /* If we don't have the plaintext password, try for * the MD4 password hash */ mach_pwd = cli_credentials_get_nt_hash(machine_account, mem_ctx); if (!mach_pwd) { /* OK, nothing to do here */ talloc_free(mem_ctx); return 0; } ret = krb5_keyblock_init(smb_krb5_context->krb5_context, ETYPE_ARCFOUR_HMAC_MD5, mach_pwd->hash, sizeof(mach_pwd->hash), &entry.keyblock); if (ret) { DEBUG(1, ("create_keytab: krb5_keyblock_init failed: %s\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } entry.principal = princ; entry.vno = cli_credentials_get_kvno(machine_account); ret = krb5_kt_add_entry(smb_krb5_context->krb5_context, keytab, &entry); if (ret) { DEBUG(1, ("Failed to add ARCFOUR_HMAC (only) entry for %s to keytab: %s", cli_credentials_get_principal(machine_account, mem_ctx), smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock); return ret; } DEBUG(5, ("Added %s(kvno %d) to keytab (arcfour-hmac-md5)\n", cli_credentials_get_principal(machine_account, mem_ctx), cli_credentials_get_kvno(machine_account))); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock); /* Can't go any further, we only have this one key */ talloc_free(mem_ctx); return 0; } kvno = cli_credentials_get_kvno(machine_account); /* good, we actually have the real plaintext */ ret = keytab_add_keys(mem_ctx, princ_string, princ, salt_princ, kvno, password_s, smb_krb5_context, enctype_strings, keytab); if (!ret) { talloc_free(mem_ctx); return ret; } if (!add_old || kvno == 0) { talloc_free(mem_ctx); return 0; } old_secret = cli_credentials_get_old_password(machine_account); if (!old_secret) { talloc_free(mem_ctx); return 0; } ret = keytab_add_keys(mem_ctx, princ_string, princ, salt_princ, kvno - 1, old_secret, smb_krb5_context, enctype_strings, keytab); if (!ret) { talloc_free(mem_ctx); return ret; } talloc_free(mem_ctx); return 0; }