Path: blob/main/crypto/heimdal/lib/gssapi/ntlm/kdc.c
34914 views
/*1* Copyright (c) 2006 - 2007 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"3435#ifdef DIGEST3637/*38*39*/4041struct ntlmkrb5 {42krb5_context context;43krb5_ntlm ntlm;44krb5_realm kerberos_realm;45krb5_ccache id;46krb5_data opaque;47int destroy;48OM_uint32 flags;49struct ntlm_buf key;50krb5_data sessionkey;51};5253static OM_uint32 kdc_destroy(OM_uint32 *, void *);5455/*56* Get credential cache that the ntlm code can use to talk to the KDC57* using the digest API.58*/5960static krb5_error_code61get_ccache(krb5_context context, int *destroy, krb5_ccache *id)62{63krb5_principal principal = NULL;64krb5_error_code ret;65krb5_keytab kt = NULL;6667*id = NULL;6869if (!issuid()) {70const char *cache;7172cache = getenv("NTLM_ACCEPTOR_CCACHE");73if (cache) {74ret = krb5_cc_resolve(context, cache, id);75if (ret)76goto out;77return 0;78}79}8081ret = krb5_sname_to_principal(context, NULL, "host",82KRB5_NT_SRV_HST, &principal);83if (ret)84goto out;8586ret = krb5_cc_cache_match(context, principal, id);87if (ret == 0)88return 0;8990/* did not find in default credcache, lets try default keytab */91ret = krb5_kt_default(context, &kt);92if (ret)93goto out;9495/* XXX check in keytab */96{97krb5_get_init_creds_opt *opt;98krb5_creds cred;99100memset(&cred, 0, sizeof(cred));101102ret = krb5_cc_new_unique(context, "MEMORY", NULL, id);103if (ret)104goto out;105*destroy = 1;106ret = krb5_get_init_creds_opt_alloc(context, &opt);107if (ret)108goto out;109ret = krb5_get_init_creds_keytab (context,110&cred,111principal,112kt,1130,114NULL,115opt);116krb5_get_init_creds_opt_free(context, opt);117if (ret)118goto out;119ret = krb5_cc_initialize (context, *id, cred.client);120if (ret) {121krb5_free_cred_contents (context, &cred);122goto out;123}124ret = krb5_cc_store_cred (context, *id, &cred);125krb5_free_cred_contents (context, &cred);126if (ret)127goto out;128}129130krb5_kt_close(context, kt);131132return 0;133134out:135if (*id) {136if (*destroy)137krb5_cc_destroy(context, *id);138else139krb5_cc_close(context, *id);140*id = NULL;141}142143if (kt)144krb5_kt_close(context, kt);145146if (principal)147krb5_free_principal(context, principal);148return ret;149}150151/*152*153*/154155static OM_uint32156kdc_alloc(OM_uint32 *minor, void **ctx)157{158krb5_error_code ret;159struct ntlmkrb5 *c;160OM_uint32 junk;161162c = calloc(1, sizeof(*c));163if (c == NULL) {164*minor = ENOMEM;165return GSS_S_FAILURE;166}167168ret = krb5_init_context(&c->context);169if (ret) {170kdc_destroy(&junk, c);171*minor = ret;172return GSS_S_FAILURE;173}174175ret = get_ccache(c->context, &c->destroy, &c->id);176if (ret) {177kdc_destroy(&junk, c);178*minor = ret;179return GSS_S_FAILURE;180}181182ret = krb5_ntlm_alloc(c->context, &c->ntlm);183if (ret) {184kdc_destroy(&junk, c);185*minor = ret;186return GSS_S_FAILURE;187}188189*ctx = c;190191return GSS_S_COMPLETE;192}193194static int195kdc_probe(OM_uint32 *minor, void *ctx, const char *realm)196{197struct ntlmkrb5 *c = ctx;198krb5_error_code ret;199unsigned flags;200201ret = krb5_digest_probe(c->context, rk_UNCONST(realm), c->id, &flags);202if (ret)203return ret;204205if ((flags & (1|2|4)) == 0)206return EINVAL;207208return 0;209}210211/*212*213*/214215static OM_uint32216kdc_destroy(OM_uint32 *minor, void *ctx)217{218struct ntlmkrb5 *c = ctx;219krb5_data_free(&c->opaque);220krb5_data_free(&c->sessionkey);221if (c->ntlm)222krb5_ntlm_free(c->context, c->ntlm);223if (c->id) {224if (c->destroy)225krb5_cc_destroy(c->context, c->id);226else227krb5_cc_close(c->context, c->id);228}229if (c->context)230krb5_free_context(c->context);231memset(c, 0, sizeof(*c));232free(c);233234return GSS_S_COMPLETE;235}236237/*238*239*/240241static OM_uint32242kdc_type2(OM_uint32 *minor_status,243void *ctx,244uint32_t flags,245const char *hostname,246const char *domain,247uint32_t *ret_flags,248struct ntlm_buf *out)249{250struct ntlmkrb5 *c = ctx;251krb5_error_code ret;252struct ntlm_type2 type2;253krb5_data challange;254struct ntlm_buf data;255krb5_data ti;256257memset(&type2, 0, sizeof(type2));258259/*260* Request data for type 2 packet from the KDC.261*/262ret = krb5_ntlm_init_request(c->context,263c->ntlm,264NULL,265c->id,266flags,267hostname,268domain);269if (ret) {270*minor_status = ret;271return GSS_S_FAILURE;272}273274/*275*276*/277278ret = krb5_ntlm_init_get_opaque(c->context, c->ntlm, &c->opaque);279if (ret) {280*minor_status = ret;281return GSS_S_FAILURE;282}283284/*285*286*/287288ret = krb5_ntlm_init_get_flags(c->context, c->ntlm, &type2.flags);289if (ret) {290*minor_status = ret;291return GSS_S_FAILURE;292}293*ret_flags = type2.flags;294295ret = krb5_ntlm_init_get_challange(c->context, c->ntlm, &challange);296if (ret) {297*minor_status = ret;298return GSS_S_FAILURE;299}300301if (challange.length != sizeof(type2.challenge)) {302*minor_status = EINVAL;303return GSS_S_FAILURE;304}305memcpy(type2.challenge, challange.data, sizeof(type2.challenge));306krb5_data_free(&challange);307308ret = krb5_ntlm_init_get_targetname(c->context, c->ntlm,309&type2.targetname);310if (ret) {311*minor_status = ret;312return GSS_S_FAILURE;313}314315ret = krb5_ntlm_init_get_targetinfo(c->context, c->ntlm, &ti);316if (ret) {317free(type2.targetname);318*minor_status = ret;319return GSS_S_FAILURE;320}321322type2.targetinfo.data = ti.data;323type2.targetinfo.length = ti.length;324325ret = heim_ntlm_encode_type2(&type2, &data);326free(type2.targetname);327krb5_data_free(&ti);328if (ret) {329*minor_status = ret;330return GSS_S_FAILURE;331}332333out->data = data.data;334out->length = data.length;335336return GSS_S_COMPLETE;337}338339/*340*341*/342343static OM_uint32344kdc_type3(OM_uint32 *minor_status,345void *ctx,346const struct ntlm_type3 *type3,347struct ntlm_buf *sessionkey)348{349struct ntlmkrb5 *c = ctx;350krb5_error_code ret;351352sessionkey->data = NULL;353sessionkey->length = 0;354355ret = krb5_ntlm_req_set_flags(c->context, c->ntlm, type3->flags);356if (ret) goto out;357ret = krb5_ntlm_req_set_username(c->context, c->ntlm, type3->username);358if (ret) goto out;359ret = krb5_ntlm_req_set_targetname(c->context, c->ntlm,360type3->targetname);361if (ret) goto out;362ret = krb5_ntlm_req_set_lm(c->context, c->ntlm,363type3->lm.data, type3->lm.length);364if (ret) goto out;365ret = krb5_ntlm_req_set_ntlm(c->context, c->ntlm,366type3->ntlm.data, type3->ntlm.length);367if (ret) goto out;368ret = krb5_ntlm_req_set_opaque(c->context, c->ntlm, &c->opaque);369if (ret) goto out;370371if (type3->sessionkey.length) {372ret = krb5_ntlm_req_set_session(c->context, c->ntlm,373type3->sessionkey.data,374type3->sessionkey.length);375if (ret) goto out;376}377378/*379* Verify with the KDC the type3 packet is ok380*/381ret = krb5_ntlm_request(c->context,382c->ntlm,383NULL,384c->id);385if (ret)386goto out;387388if (krb5_ntlm_rep_get_status(c->context, c->ntlm) != TRUE) {389ret = EINVAL;390goto out;391}392393if (type3->sessionkey.length) {394ret = krb5_ntlm_rep_get_sessionkey(c->context,395c->ntlm,396&c->sessionkey);397if (ret)398goto out;399400sessionkey->data = c->sessionkey.data;401sessionkey->length = c->sessionkey.length;402}403404return 0;405406out:407*minor_status = ret;408return GSS_S_FAILURE;409}410411/*412*413*/414415static void416kdc_free_buffer(struct ntlm_buf *sessionkey)417{418if (sessionkey->data)419free(sessionkey->data);420sessionkey->data = NULL;421sessionkey->length = 0;422}423424/*425*426*/427428struct ntlm_server_interface ntlmsspi_kdc_digest = {429kdc_alloc,430kdc_destroy,431kdc_probe,432kdc_type2,433kdc_type3,434kdc_free_buffer435};436437#endif /* DIGEST */438439440