Path: blob/main/crypto/heimdal/lib/gssapi/ntlm/init_sec_context.c
34914 views
/*1* Copyright (c) 2006 - 2008 Kungliga Tekniska Högskolan2* (Royal Institute of Technology, Stockholm, Sweden).3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8*9* 1. Redistributions of source code must retain the above copyright10* notice, this list of conditions and the following disclaimer.11*12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* 3. Neither the name of the Institute nor the names of its contributors17* may be used to endorse or promote products derived from this software18* without specific prior written permission.19*20* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND21* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE23* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE24* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL25* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS26* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)27* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT28* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY29* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF30* SUCH DAMAGE.31*/3233#include "ntlm.h"3435static int36from_file(const char *fn, const char *target_domain,37char **username, struct ntlm_buf *key)38{39char *str, buf[1024];40FILE *f;4142f = fopen(fn, "r");43if (f == NULL)44return ENOENT;45rk_cloexec_file(f);4647while (fgets(buf, sizeof(buf), f) != NULL) {48char *d, *u, *p;49buf[strcspn(buf, "\r\n")] = '\0';50if (buf[0] == '#')51continue;52str = NULL;53d = strtok_r(buf, ":", &str);54if (!d)55continue;56if (d && strcasecmp(target_domain, d) != 0)57continue;58u = strtok_r(NULL, ":", &str);59p = strtok_r(NULL, ":", &str);60if (u == NULL || p == NULL)61continue;6263*username = strdup(u);6465heim_ntlm_nt_key(p, key);6667memset(buf, 0, sizeof(buf));68fclose(f);69return 0;70}71memset(buf, 0, sizeof(buf));72fclose(f);73return ENOENT;74}7576static int77get_user_file(const ntlm_name target_name,78char **username, struct ntlm_buf *key)79{80const char *fn;8182if (issuid())83return ENOENT;8485fn = getenv("NTLM_USER_FILE");86if (fn == NULL)87return ENOENT;88if (from_file(fn, target_name->domain, username, key) == 0)89return 0;9091return ENOENT;92}9394/*95* Pick up the ntlm cred from the default krb5 credential cache.96*/9798static int99get_user_ccache(const ntlm_name name, char **username, struct ntlm_buf *key)100{101krb5_context context = NULL;102krb5_principal client;103krb5_ccache id = NULL;104krb5_error_code ret;105char *confname;106krb5_data data;107108*username = NULL;109krb5_data_zero(&data);110key->length = 0;111key->data = NULL;112113ret = krb5_init_context(&context);114if (ret)115return ret;116117ret = krb5_cc_default(context, &id);118if (ret)119goto out;120121ret = krb5_cc_get_principal(context, id, &client);122if (ret)123goto out;124125ret = krb5_unparse_name_flags(context, client,126KRB5_PRINCIPAL_UNPARSE_NO_REALM,127username);128krb5_free_principal(context, client);129if (ret)130goto out;131132asprintf(&confname, "ntlm-key-%s", name->domain);133if (confname == NULL) {134krb5_clear_error_message(context);135ret = ENOMEM;136goto out;137}138139ret = krb5_cc_get_config(context, id, NULL,140confname, &data);141if (ret)142goto out;143144key->data = malloc(data.length);145if (key->data == NULL) {146ret = ENOMEM;147goto out;148}149key->length = data.length;150memcpy(key->data, data.data, data.length);151152out:153krb5_data_free(&data);154if (id)155krb5_cc_close(context, id);156157krb5_free_context(context);158159return ret;160}161162int163_gss_ntlm_get_user_cred(const ntlm_name target_name,164ntlm_cred *rcred)165{166ntlm_cred cred;167int ret;168169cred = calloc(1, sizeof(*cred));170if (cred == NULL)171return ENOMEM;172173ret = get_user_file(target_name, &cred->username, &cred->key);174if (ret)175ret = get_user_ccache(target_name, &cred->username, &cred->key);176if (ret) {177free(cred);178return ret;179}180181cred->domain = strdup(target_name->domain);182*rcred = cred;183184return ret;185}186187static int188_gss_copy_cred(ntlm_cred from, ntlm_cred *to)189{190*to = calloc(1, sizeof(**to));191if (*to == NULL)192return ENOMEM;193(*to)->username = strdup(from->username);194if ((*to)->username == NULL) {195free(*to);196return ENOMEM;197}198(*to)->domain = strdup(from->domain);199if ((*to)->domain == NULL) {200free((*to)->username);201free(*to);202return ENOMEM;203}204(*to)->key.data = malloc(from->key.length);205if ((*to)->key.data == NULL) {206free((*to)->domain);207free((*to)->username);208free(*to);209return ENOMEM;210}211memcpy((*to)->key.data, from->key.data, from->key.length);212(*to)->key.length = from->key.length;213214return 0;215}216217OM_uint32 GSSAPI_CALLCONV218_gss_ntlm_init_sec_context219(OM_uint32 * minor_status,220const gss_cred_id_t initiator_cred_handle,221gss_ctx_id_t * context_handle,222const gss_name_t target_name,223const gss_OID mech_type,224OM_uint32 req_flags,225OM_uint32 time_req,226const gss_channel_bindings_t input_chan_bindings,227const gss_buffer_t input_token,228gss_OID * actual_mech_type,229gss_buffer_t output_token,230OM_uint32 * ret_flags,231OM_uint32 * time_rec232)233{234ntlm_ctx ctx;235ntlm_name name = (ntlm_name)target_name;236237*minor_status = 0;238239if (ret_flags)240*ret_flags = 0;241if (time_rec)242*time_rec = 0;243if (actual_mech_type)244*actual_mech_type = GSS_C_NO_OID;245246if (*context_handle == GSS_C_NO_CONTEXT) {247struct ntlm_type1 type1;248struct ntlm_buf data;249uint32_t flags = 0;250int ret;251252ctx = calloc(1, sizeof(*ctx));253if (ctx == NULL) {254*minor_status = EINVAL;255return GSS_S_FAILURE;256}257*context_handle = (gss_ctx_id_t)ctx;258259if (initiator_cred_handle != GSS_C_NO_CREDENTIAL) {260ntlm_cred cred = (ntlm_cred)initiator_cred_handle;261ret = _gss_copy_cred(cred, &ctx->client);262} else263ret = _gss_ntlm_get_user_cred(name, &ctx->client);264265if (ret) {266_gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);267*minor_status = ret;268return GSS_S_FAILURE;269}270271if (req_flags & GSS_C_CONF_FLAG)272flags |= NTLM_NEG_SEAL;273if (req_flags & GSS_C_INTEG_FLAG)274flags |= NTLM_NEG_SIGN;275else276flags |= NTLM_NEG_ALWAYS_SIGN;277278flags |= NTLM_NEG_UNICODE;279flags |= NTLM_NEG_NTLM;280flags |= NTLM_NEG_NTLM2_SESSION;281flags |= NTLM_NEG_KEYEX;282283memset(&type1, 0, sizeof(type1));284285type1.flags = flags;286type1.domain = name->domain;287type1.hostname = NULL;288type1.os[0] = 0;289type1.os[1] = 0;290291ret = heim_ntlm_encode_type1(&type1, &data);292if (ret) {293_gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);294*minor_status = ret;295return GSS_S_FAILURE;296}297298output_token->value = data.data;299output_token->length = data.length;300301return GSS_S_CONTINUE_NEEDED;302} else {303krb5_error_code ret;304struct ntlm_type2 type2;305struct ntlm_type3 type3;306struct ntlm_buf data;307308ctx = (ntlm_ctx)*context_handle;309310data.data = input_token->value;311data.length = input_token->length;312313ret = heim_ntlm_decode_type2(&data, &type2);314if (ret) {315_gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);316*minor_status = ret;317return GSS_S_FAILURE;318}319320ctx->flags = type2.flags;321322/* XXX check that type2.targetinfo matches `target_name´ */323/* XXX check verify targetinfo buffer */324325memset(&type3, 0, sizeof(type3));326327type3.username = ctx->client->username;328type3.flags = type2.flags;329type3.targetname = type2.targetname;330type3.ws = rk_UNCONST("workstation");331332/*333* NTLM Version 1 if no targetinfo buffer.334*/335336if (1 || type2.targetinfo.length == 0) {337struct ntlm_buf sessionkey;338339if (type2.flags & NTLM_NEG_NTLM2_SESSION) {340unsigned char nonce[8];341342if (RAND_bytes(nonce, sizeof(nonce)) != 1) {343_gss_ntlm_delete_sec_context(minor_status,344context_handle, NULL);345*minor_status = EINVAL;346return GSS_S_FAILURE;347}348349ret = heim_ntlm_calculate_ntlm2_sess(nonce,350type2.challenge,351ctx->client->key.data,352&type3.lm,353&type3.ntlm);354} else {355ret = heim_ntlm_calculate_ntlm1(ctx->client->key.data,356ctx->client->key.length,357type2.challenge,358&type3.ntlm);359360}361if (ret) {362_gss_ntlm_delete_sec_context(minor_status,context_handle,NULL);363*minor_status = ret;364return GSS_S_FAILURE;365}366367ret = heim_ntlm_build_ntlm1_master(ctx->client->key.data,368ctx->client->key.length,369&sessionkey,370&type3.sessionkey);371if (ret) {372if (type3.lm.data)373free(type3.lm.data);374if (type3.ntlm.data)375free(type3.ntlm.data);376_gss_ntlm_delete_sec_context(minor_status,context_handle,NULL);377*minor_status = ret;378return GSS_S_FAILURE;379}380381ret = krb5_data_copy(&ctx->sessionkey,382sessionkey.data, sessionkey.length);383free(sessionkey.data);384if (ret) {385if (type3.lm.data)386free(type3.lm.data);387if (type3.ntlm.data)388free(type3.ntlm.data);389_gss_ntlm_delete_sec_context(minor_status,context_handle,NULL);390*minor_status = ret;391return GSS_S_FAILURE;392}393ctx->status |= STATUS_SESSIONKEY;394395} else {396struct ntlm_buf sessionkey;397unsigned char ntlmv2[16];398struct ntlm_targetinfo ti;399400/* verify infotarget */401402ret = heim_ntlm_decode_targetinfo(&type2.targetinfo, 1, &ti);403if(ret) {404_gss_ntlm_delete_sec_context(minor_status,405context_handle, NULL);406*minor_status = ret;407return GSS_S_FAILURE;408}409410if (ti.domainname && strcmp(ti.domainname, name->domain) != 0) {411_gss_ntlm_delete_sec_context(minor_status,412context_handle, NULL);413*minor_status = EINVAL;414return GSS_S_FAILURE;415}416417ret = heim_ntlm_calculate_ntlm2(ctx->client->key.data,418ctx->client->key.length,419ctx->client->username,420name->domain,421type2.challenge,422&type2.targetinfo,423ntlmv2,424&type3.ntlm);425if (ret) {426_gss_ntlm_delete_sec_context(minor_status,427context_handle, NULL);428*minor_status = ret;429return GSS_S_FAILURE;430}431432ret = heim_ntlm_build_ntlm1_master(ntlmv2, sizeof(ntlmv2),433&sessionkey,434&type3.sessionkey);435memset(ntlmv2, 0, sizeof(ntlmv2));436if (ret) {437_gss_ntlm_delete_sec_context(minor_status,438context_handle, NULL);439*minor_status = ret;440return GSS_S_FAILURE;441}442443ctx->flags |= NTLM_NEG_NTLM2_SESSION;444445ret = krb5_data_copy(&ctx->sessionkey,446sessionkey.data, sessionkey.length);447free(sessionkey.data);448if (ret) {449_gss_ntlm_delete_sec_context(minor_status,450context_handle, NULL);451*minor_status = ret;452return GSS_S_FAILURE;453}454}455456if (ctx->flags & NTLM_NEG_NTLM2_SESSION) {457ctx->status |= STATUS_SESSIONKEY;458_gss_ntlm_set_key(&ctx->u.v2.send, 0, (ctx->flags & NTLM_NEG_KEYEX),459ctx->sessionkey.data,460ctx->sessionkey.length);461_gss_ntlm_set_key(&ctx->u.v2.recv, 1, (ctx->flags & NTLM_NEG_KEYEX),462ctx->sessionkey.data,463ctx->sessionkey.length);464} else {465ctx->status |= STATUS_SESSIONKEY;466RC4_set_key(&ctx->u.v1.crypto_recv.key,467ctx->sessionkey.length,468ctx->sessionkey.data);469RC4_set_key(&ctx->u.v1.crypto_send.key,470ctx->sessionkey.length,471ctx->sessionkey.data);472}473474475476ret = heim_ntlm_encode_type3(&type3, &data);477free(type3.sessionkey.data);478if (type3.lm.data)479free(type3.lm.data);480if (type3.ntlm.data)481free(type3.ntlm.data);482if (ret) {483_gss_ntlm_delete_sec_context(minor_status, context_handle, NULL);484*minor_status = ret;485return GSS_S_FAILURE;486}487488output_token->length = data.length;489output_token->value = data.data;490491if (actual_mech_type)492*actual_mech_type = GSS_NTLM_MECHANISM;493if (ret_flags)494*ret_flags = 0;495if (time_rec)496*time_rec = GSS_C_INDEFINITE;497498ctx->status |= STATUS_OPEN;499500return GSS_S_COMPLETE;501}502}503504505