📄 digest.c
字号:
} r.u.error.code = EINVAL; } kdc_log(context, config, 0, "Digest %s request successful %s", ireq.u.digestRequest.type, ireq.u.digestRequest.username); break; } case choice_DigestReqInner_ntlmInit: if ((config->digests_allowed & (NTLM_V1|NTLM_V1_SESSION|NTLM_V2)) == 0) { kdc_log(context, config, 0, "NTLM not allowed"); goto failed; } r.element = choice_DigestRepInner_ntlmInitReply; r.u.ntlmInitReply.flags = NTLM_NEG_UNICODE; if ((ireq.u.ntlmInit.flags & NTLM_NEG_UNICODE) == 0) { kdc_log(context, config, 0, "NTLM client have no unicode"); goto failed; } if (ireq.u.ntlmInit.flags & NTLM_NEG_NTLM) r.u.ntlmInitReply.flags |= NTLM_NEG_NTLM; else { kdc_log(context, config, 0, "NTLM client doesn't support NTLM"); goto failed; } r.u.ntlmInitReply.flags |= NTLM_NEG_TARGET | NTLM_TARGET_DOMAIN | NTLM_ENC_128;#define ALL \ NTLM_NEG_SIGN| \ NTLM_NEG_SEAL| \ NTLM_NEG_ALWAYS_SIGN| \ NTLM_NEG_NTLM2_SESSION| \ NTLM_NEG_KEYEX r.u.ntlmInitReply.flags |= (ireq.u.ntlmInit.flags & (ALL));#undef ALL r.u.ntlmInitReply.targetname = get_ntlm_targetname(context, client); if (r.u.ntlmInitReply.targetname == NULL) { krb5_set_error_string(context, "out of memory"); ret = ENOMEM; goto out; } r.u.ntlmInitReply.challange.data = malloc(8); if (r.u.ntlmInitReply.challange.data == NULL) { krb5_set_error_string(context, "out of memory"); ret = ENOMEM; goto out; } r.u.ntlmInitReply.challange.length = 8; if (RAND_bytes(r.u.ntlmInitReply.challange.data, r.u.ntlmInitReply.challange.length) != 1) { krb5_set_error_string(context, "out of random error"); ret = ENOMEM; goto out; } /* XXX fix targetinfo */ ALLOC(r.u.ntlmInitReply.targetinfo); if (r.u.ntlmInitReply.targetinfo == NULL) { krb5_set_error_string(context, "out of memory"); ret = ENOMEM; goto out; } ret = fill_targetinfo(context, r.u.ntlmInitReply.targetname, client, r.u.ntlmInitReply.targetinfo); if (ret) { krb5_set_error_string(context, "out of memory"); ret = ENOMEM; goto out; } /* * Save data encryted in opaque for the second part of the * ntlm authentication */ sp = krb5_storage_emem(); if (sp == NULL) { ret = ENOMEM; krb5_set_error_string(context, "out of memory"); goto out; } ret = krb5_storage_write(sp, r.u.ntlmInitReply.challange.data, 8); if (ret != 8) { ret = ENOMEM; krb5_set_error_string(context, "storage write challange"); goto out; } ret = krb5_store_uint32(sp, r.u.ntlmInitReply.flags); if (ret) { krb5_clear_error_string(context); goto out; } ret = krb5_storage_to_data(sp, &buf); if (ret) { krb5_clear_error_string(context); goto out; } ret = get_digest_key(context, config, server, &crypto); if (ret) goto out; ret = krb5_encrypt(context, crypto, KRB5_KU_DIGEST_OPAQUE, buf.data, buf.length, &r.u.ntlmInitReply.opaque); krb5_data_free(&buf); krb5_crypto_destroy(context, crypto); crypto = NULL; if (ret) goto out; kdc_log(context, config, 0, "NTLM init from %s", from); break; case choice_DigestReqInner_ntlmRequest: { krb5_principal clientprincipal; unsigned char sessionkey[16]; unsigned char challange[8]; uint32_t flags; Key *key = NULL; int version; r.element = choice_DigestRepInner_ntlmResponse; r.u.ntlmResponse.success = 0; r.u.ntlmResponse.flags = 0; r.u.ntlmResponse.sessionkey = NULL; r.u.ntlmResponse.tickets = NULL; /* get username */ ret = krb5_parse_name(context, ireq.u.ntlmRequest.username, &clientprincipal); if (ret) goto failed; ret = _kdc_db_fetch(context, config, clientprincipal, HDB_F_GET_CLIENT, NULL, &user); krb5_free_principal(context, clientprincipal); if (ret) { krb5_set_error_string(context, "NTLM user %s not in database", ireq.u.ntlmRequest.username); goto failed; } ret = get_digest_key(context, config, server, &crypto); if (ret) goto failed; ret = krb5_decrypt(context, crypto, KRB5_KU_DIGEST_OPAQUE, ireq.u.ntlmRequest.opaque.data, ireq.u.ntlmRequest.opaque.length, &buf); krb5_crypto_destroy(context, crypto); crypto = NULL; if (ret) { kdc_log(context, config, 0, "Failed to decrypt nonce from %s", from); goto failed; } sp = krb5_storage_from_data(&buf); if (sp == NULL) { ret = ENOMEM; krb5_set_error_string(context, "out of memory"); goto out; } ret = krb5_storage_read(sp, challange, sizeof(challange)); if (ret != sizeof(challange)) { krb5_set_error_string(context, "NTLM storage read challange"); ret = ENOMEM; goto out; } ret = krb5_ret_uint32(sp, &flags); if (ret) { krb5_set_error_string(context, "NTLM storage read flags"); goto out; } krb5_data_free(&buf); if ((flags & NTLM_NEG_NTLM) == 0) { ret = EINVAL; krb5_set_error_string(context, "NTLM not negotiated"); goto out; } ret = hdb_enctype2key(context, &user->entry, ETYPE_ARCFOUR_HMAC_MD5, &key); if (ret) { krb5_set_error_string(context, "NTLM missing arcfour key"); goto out; } /* check if this is NTLMv2 */ if (ireq.u.ntlmRequest.ntlm.length != 24) { struct ntlm_buf infotarget, answer; char *targetname; if ((config->digests_allowed & NTLM_V2) == 0) { kdc_log(context, config, 0, "NTLM v2 not allowed"); goto out; } version = 2; targetname = get_ntlm_targetname(context, client); if (targetname == NULL) { krb5_set_error_string(context, "out of memory"); ret = ENOMEM; goto out; } answer.length = ireq.u.ntlmRequest.ntlm.length; answer.data = ireq.u.ntlmRequest.ntlm.data; ret = heim_ntlm_verify_ntlm2(key->key.keyvalue.data, key->key.keyvalue.length, ireq.u.ntlmRequest.username, targetname, 0, challange, &answer, &infotarget, sessionkey); free(targetname); if (ret) { krb5_set_error_string(context, "NTLM v2 verify failed"); goto failed; } /* XXX verify infotarget matches client (checksum ?) */ free(infotarget.data); /* */ } else { struct ntlm_buf answer; version = 1; if (flags & NTLM_NEG_NTLM2_SESSION) { unsigned char sessionhash[MD5_DIGEST_LENGTH]; MD5_CTX md5ctx; if ((config->digests_allowed & NTLM_V1_SESSION) == 0) { kdc_log(context, config, 0, "NTLM v1-session not allowed"); ret = EINVAL; goto failed; } if (ireq.u.ntlmRequest.lm.length != 24) { krb5_set_error_string(context, "LM hash have wrong length " "for NTLM session key"); ret = EINVAL; goto failed; } MD5_Init(&md5ctx); MD5_Update(&md5ctx, challange, sizeof(challange)); MD5_Update(&md5ctx, ireq.u.ntlmRequest.lm.data, 8); MD5_Final(sessionhash, &md5ctx); memcpy(challange, sessionhash, sizeof(challange)); } else { if ((config->digests_allowed & NTLM_V1) == 0) { kdc_log(context, config, 0, "NTLM v1 not allowed"); goto failed; } } ret = heim_ntlm_calculate_ntlm1(key->key.keyvalue.data, key->key.keyvalue.length, challange, &answer); if (ret) { krb5_set_error_string(context, "NTLM missing arcfour key"); goto failed; } if (ireq.u.ntlmRequest.ntlm.length != answer.length || memcmp(ireq.u.ntlmRequest.ntlm.data, answer.data, answer.length) != 0) { free(answer.data); ret = EINVAL; krb5_set_error_string(context, "NTLM hash mismatch"); goto failed; } free(answer.data); { MD4_CTX ctx; MD4_Init(&ctx); MD4_Update(&ctx, key->key.keyvalue.data, key->key.keyvalue.length); MD4_Final(sessionkey, &ctx); } } if (ireq.u.ntlmRequest.sessionkey) { unsigned char masterkey[MD4_DIGEST_LENGTH]; RC4_KEY rc4; size_t len; if ((flags & NTLM_NEG_KEYEX) == 0) { krb5_set_error_string(context, "NTLM client failed to neg key " "exchange but still sent key"); ret = EINVAL; goto failed; } len = ireq.u.ntlmRequest.sessionkey->length; if (len != sizeof(masterkey)){ krb5_set_error_string(context, "NTLM master key wrong length: %lu", (unsigned long)len); goto failed; } RC4_set_key(&rc4, sizeof(sessionkey), sessionkey); RC4(&rc4, sizeof(masterkey), ireq.u.ntlmRequest.sessionkey->data, masterkey); memset(&rc4, 0, sizeof(rc4)); r.u.ntlmResponse.sessionkey = malloc(sizeof(*r.u.ntlmResponse.sessionkey)); if (r.u.ntlmResponse.sessionkey == NULL) { krb5_set_error_string(context, "out of memory"); goto out; } ret = krb5_data_copy(r.u.ntlmResponse.sessionkey, masterkey, sizeof(masterkey)); if (ret) { krb5_set_error_string(context, "out of memory"); goto out; } } r.u.ntlmResponse.success = 1; kdc_log(context, config, 0, "NTLM version %d successful for %s", version, ireq.u.ntlmRequest.username); break; } case choice_DigestReqInner_supportedMechs: kdc_log(context, config, 0, "digest supportedMechs from %s", from); r.element = choice_DigestRepInner_supportedMechs; memset(&r.u.supportedMechs, 0, sizeof(r.u.supportedMechs)); if (config->digests_allowed & NTLM_V1) r.u.supportedMechs.ntlm_v1 = 1; if (config->digests_allowed & NTLM_V1_SESSION) r.u.supportedMechs.ntlm_v1_session = 1; if (config->digests_allowed & NTLM_V2) r.u.supportedMechs.ntlm_v2 = 1; if (config->digests_allowed & DIGEST_MD5) r.u.supportedMechs.digest_md5 = 1; if (config->digests_allowed & CHAP_MD5) r.u.supportedMechs.chap_md5 = 1; if (config->digests_allowed & MS_CHAP_V2) r.u.supportedMechs.ms_chap_v2 = 1; break; default: { char *s; krb5_set_error_string(context, "unknown operation to digest"); ret = EINVAL; failed: s = krb5_get_error_message(context, ret); if (s == NULL) { krb5_clear_error_string(context); goto out; } kdc_log(context, config, 0, "Digest failed with: %s", s); r.element = choice_DigestRepInner_error; r.u.error.reason = strdup("unknown error"); krb5_free_error_string(context, s); if (r.u.error.reason == NULL) { krb5_set_error_string(context, "out of memory"); ret = ENOMEM; goto out; } r.u.error.code = EINVAL; break; } } ASN1_MALLOC_ENCODE(DigestRepInner, buf.data, buf.length, &r, &size, ret); if (ret) { krb5_set_error_string(context, "Failed to encode inner digest reply"); goto out; } if (size != buf.length) krb5_abortx(context, "ASN1 internal error"); krb5_auth_con_addflags(context, ac, KRB5_AUTH_CONTEXT_USE_SUBKEY, NULL); ret = krb5_mk_rep (context, ac, &rep.apRep); if (ret) goto out; { krb5_keyblock *key; ret = krb5_auth_con_getlocalsubkey(context, ac, &key); if (ret) goto out; ret = krb5_crypto_init(context, key, 0, &crypto); krb5_free_keyblock (context, key); if (ret) goto out; } ret = krb5_encrypt_EncryptedData(context, crypto, KRB5_KU_DIGEST_ENCRYPT, buf.data, buf.length, 0, &rep.innerRep); ASN1_MALLOC_ENCODE(DigestREP, reply->data, reply->length, &rep, &size, ret); if (ret) { krb5_set_error_string(context, "Failed to encode digest reply"); goto out; } if (size != reply->length) krb5_abortx(context, "ASN1 internal error"); out: if (ac) krb5_auth_con_free(context, ac); if (ret) krb5_warn(context, ret, "Digest request from %s failed", from); if (ticket) krb5_free_ticket(context, ticket); if (id) krb5_kt_close(context, id); if (crypto) krb5_crypto_destroy(context, crypto); if (sp) krb5_storage_free(sp); if (user) _kdc_free_ent (context, user); if (server) _kdc_free_ent (context, server); if (client) _kdc_free_ent (context, client); if (password) { memset(password, 0, strlen(password)); free (password); } if (client_name) free (client_name); krb5_data_free(&buf); krb5_data_free(&serverNonce); free_DigestREP(&rep); free_DigestRepInner(&r); free_DigestReqInner(&ireq); return ret;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -