static void ntlm_service(void *ctx, const heim_idata *req, const heim_icred cred, heim_ipc_complete complete, heim_sipc_call cctx) { NTLMRequest2 ntq; unsigned char sessionkey[16]; heim_idata rep = { 0, NULL }; krb5_context context = ctx; hdb_entry_ex *user = NULL; Key *key = NULL; NTLMReply ntp; size_t size; int ret; char *domain; kdc_log(context, config, 1, "digest-request: uid=%d", (int)heim_ipc_cred_get_uid(cred)); if (heim_ipc_cred_get_uid(cred) != 0) { (*complete)(cctx, EPERM, NULL); return; } ntp.success = 0; ntp.flags = 0; ntp.sessionkey = NULL; ret = decode_NTLMRequest2(req->data, req->length, &ntq, NULL); if (ret) goto failed; /* XXX forward to NetrLogonSamLogonEx() if not a local domain */ if (strcmp(ntq.loginDomainName, "BUILTIN") == 0) { domain = ntq.loginDomainName; } else if (strcmp(ntq.loginDomainName, "") == 0) { domain = "BUILTIN"; } else { ret = EINVAL; goto failed; } kdc_log(context, config, 1, "digest-request: user=%s/%s", ntq.loginUserName, domain); if (ntq.lmchallenge.length != 8) goto failed; if (ntq.ntChallengeResponce.length == 0) goto failed; { krb5_principal client; ret = krb5_make_principal(context, &client, domain, ntq.loginUserName, NULL); if (ret) goto failed; krb5_principal_set_type(context, client, KRB5_NT_NTLM); ret = _kdc_db_fetch(context, config, client, HDB_F_GET_CLIENT, NULL, NULL, &user); krb5_free_principal(context, client); if (ret) goto failed; ret = hdb_enctype2key(context, &user->entry, ETYPE_ARCFOUR_HMAC_MD5, &key); if (ret) { krb5_set_error_message(context, ret, "NTLM missing arcfour key"); goto failed; } } kdc_log(context, config, 2, "digest-request: found user, processing ntlm request", ret); if (ntq.ntChallengeResponce.length != 24) { struct ntlm_buf infotarget, answer; answer.length = ntq.ntChallengeResponce.length; answer.data = ntq.ntChallengeResponce.data; ret = heim_ntlm_verify_ntlm2(key->key.keyvalue.data, key->key.keyvalue.length, ntq.loginUserName, ntq.loginDomainName, 0, ntq.lmchallenge.data, &answer, &infotarget, sessionkey); if (ret) { goto failed; } free(infotarget.data); /* XXX verify info target */ } else { struct ntlm_buf answer; if (ntq.flags & NTLM_NEG_NTLM2_SESSION) { unsigned char sessionhash[MD5_DIGEST_LENGTH]; EVP_MD_CTX *md5ctx; /* the first first 8 bytes is the challenge, what is the other 16 bytes ? */ if (ntq.lmChallengeResponce.length != 24) goto failed; md5ctx = EVP_MD_CTX_create(); EVP_DigestInit_ex(md5ctx, EVP_md5(), NULL); EVP_DigestUpdate(md5ctx, ntq.lmchallenge.data, 8); EVP_DigestUpdate(md5ctx, ntq.lmChallengeResponce.data, 8); EVP_DigestFinal_ex(md5ctx, sessionhash, NULL); EVP_MD_CTX_destroy(md5ctx); memcpy(ntq.lmchallenge.data, sessionhash, ntq.lmchallenge.length); } ret = heim_ntlm_calculate_ntlm1(key->key.keyvalue.data, key->key.keyvalue.length, ntq.lmchallenge.data, &answer); if (ret) goto failed; if (ntq.ntChallengeResponce.length != answer.length || memcmp(ntq.ntChallengeResponce.data, answer.data, answer.length) != 0) { free(answer.data); ret = EINVAL; goto failed; } free(answer.data); { EVP_MD_CTX *ctx; ctx = EVP_MD_CTX_create(); EVP_DigestInit_ex(ctx, EVP_md4(), NULL); EVP_DigestUpdate(ctx, key->key.keyvalue.data, key->key.keyvalue.length); EVP_DigestFinal_ex(ctx, sessionkey, NULL); EVP_MD_CTX_destroy(ctx); } } ntp.success = 1; ASN1_MALLOC_ENCODE(NTLMReply, rep.data, rep.length, &ntp, &size, ret); if (ret) goto failed; if (rep.length != size) abort(); failed: kdc_log(context, config, 1, "digest-request: %d", ret); (*complete)(cctx, ret, &rep); free(rep.data); free_NTLMRequest2(&ntq); if (user) _kdc_free_ent (context, user); }
static int test_keys(void) { const char *username = "******", *password = "******", *target = "TESTNT"; const unsigned char serverchallenge[8] = "\x67\x7f\x1c\x55\x7a\x5e\xe9\x6c"; struct ntlm_buf infotarget, infotarget2, answer, key; unsigned char ntlmv2[16], ntlmv2_1[16]; int ret; infotarget.length = 70; infotarget.data = "\x02\x00\x0c\x00\x54\x00\x45\x00\x53\x00\x54\x00\x4e\x00\x54\x00" "\x01\x00\x0c\x00\x4d\x00\x45\x00\x4d\x00\x42\x00\x45\x00\x52\x00" "\x03\x00\x1e\x00\x6d\x00\x65\x00\x6d\x00\x62\x00\x65\x00\x72\x00" "\x2e\x00\x74\x00\x65\x00\x73\x00\x74\x00\x2e\x00\x63\x00\x6f" "\x00\x6d\x00" "\x00\x00\x00\x00"; answer.length = 0; answer.data = NULL; heim_ntlm_nt_key(password, &key); ret = heim_ntlm_calculate_ntlm2(key.data, key.length, username, target, serverchallenge, &infotarget, ntlmv2, &answer); if (ret) errx(1, "heim_ntlm_calculate_ntlm2"); ret = heim_ntlm_verify_ntlm2(key.data, key.length, username, target, 0, serverchallenge, &answer, &infotarget2, ntlmv2_1); if (ret) errx(1, "heim_ntlm_verify_ntlm2"); if (memcmp(ntlmv2, ntlmv2_1, sizeof(ntlmv2)) != 0) errx(1, "ntlm master key not same"); if (infotarget.length > infotarget2.length) errx(1, "infotarget length"); if (memcmp(infotarget.data, infotarget2.data, infotarget.length) != 0) errx(1, "infotarget not the same"); free(key.data); free(answer.data); free(infotarget2.data); return 0; }