1226031Sstas/*- 2226031Sstas * Copyright (c) 2005 Doug Rabson 3226031Sstas * All rights reserved. 4226031Sstas * 5226031Sstas * Redistribution and use in source and binary forms, with or without 6226031Sstas * modification, are permitted provided that the following conditions 7226031Sstas * are met: 8226031Sstas * 1. Redistributions of source code must retain the above copyright 9226031Sstas * notice, this list of conditions and the following disclaimer. 10226031Sstas * 2. Redistributions in binary form must reproduce the above copyright 11226031Sstas * notice, this list of conditions and the following disclaimer in the 12226031Sstas * documentation and/or other materials provided with the distribution. 13226031Sstas * 14226031Sstas * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15226031Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16226031Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17226031Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18226031Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19226031Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20226031Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21226031Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22226031Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23226031Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24226031Sstas * SUCH DAMAGE. 25226031Sstas * 26226031Sstas * $FreeBSD: src/lib/libgssapi/gss_accept_sec_context.c,v 1.1 2005/12/29 14:40:20 dfr Exp $ 27226031Sstas */ 28226031Sstas 29226031Sstas#include "mech_locl.h" 30226031Sstas 31226031Sstasstatic OM_uint32 32226031Sstasparse_header(const gss_buffer_t input_token, gss_OID mech_oid) 33226031Sstas{ 34226031Sstas unsigned char *p = input_token->value; 35226031Sstas size_t len = input_token->length; 36226031Sstas size_t a, b; 37226031Sstas 38226031Sstas /* 39226031Sstas * Token must start with [APPLICATION 0] SEQUENCE. 40226031Sstas * But if it doesn't assume it is DCE-STYLE Kerberos! 41226031Sstas */ 42226031Sstas if (len == 0) 43226031Sstas return (GSS_S_DEFECTIVE_TOKEN); 44226031Sstas 45226031Sstas p++; 46226031Sstas len--; 47226031Sstas 48226031Sstas /* 49226031Sstas * Decode the length and make sure it agrees with the 50226031Sstas * token length. 51226031Sstas */ 52226031Sstas if (len == 0) 53226031Sstas return (GSS_S_DEFECTIVE_TOKEN); 54226031Sstas if ((*p & 0x80) == 0) { 55226031Sstas a = *p; 56226031Sstas p++; 57226031Sstas len--; 58226031Sstas } else { 59226031Sstas b = *p & 0x7f; 60226031Sstas p++; 61226031Sstas len--; 62226031Sstas if (len < b) 63226031Sstas return (GSS_S_DEFECTIVE_TOKEN); 64226031Sstas a = 0; 65226031Sstas while (b) { 66226031Sstas a = (a << 8) | *p; 67226031Sstas p++; 68226031Sstas len--; 69226031Sstas b--; 70226031Sstas } 71226031Sstas } 72226031Sstas if (a != len) 73226031Sstas return (GSS_S_DEFECTIVE_TOKEN); 74226031Sstas 75226031Sstas /* 76226031Sstas * Decode the OID for the mechanism. Simplify life by 77226031Sstas * assuming that the OID length is less than 128 bytes. 78226031Sstas */ 79226031Sstas if (len < 2 || *p != 0x06) 80226031Sstas return (GSS_S_DEFECTIVE_TOKEN); 81226031Sstas if ((p[1] & 0x80) || p[1] > (len - 2)) 82226031Sstas return (GSS_S_DEFECTIVE_TOKEN); 83226031Sstas mech_oid->length = p[1]; 84226031Sstas p += 2; 85226031Sstas len -= 2; 86226031Sstas mech_oid->elements = p; 87226031Sstas 88226031Sstas return GSS_S_COMPLETE; 89226031Sstas} 90226031Sstas 91226031Sstasstatic gss_OID_desc krb5_mechanism = 92226031Sstas {9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")}; 93226031Sstasstatic gss_OID_desc ntlm_mechanism = 94226031Sstas {10, rk_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a")}; 95226031Sstasstatic gss_OID_desc spnego_mechanism = 96226031Sstas {6, rk_UNCONST("\x2b\x06\x01\x05\x05\x02")}; 97226031Sstas 98226031Sstasstatic OM_uint32 99226031Sstaschoose_mech(const gss_buffer_t input, gss_OID mech_oid) 100226031Sstas{ 101226031Sstas OM_uint32 status; 102226031Sstas 103226031Sstas /* 104226031Sstas * First try to parse the gssapi token header and see if it's a 105226031Sstas * correct header, use that in the first hand. 106226031Sstas */ 107226031Sstas 108226031Sstas status = parse_header(input, mech_oid); 109226031Sstas if (status == GSS_S_COMPLETE) 110226031Sstas return GSS_S_COMPLETE; 111226031Sstas 112226031Sstas /* 113226031Sstas * Lets guess what mech is really is, callback function to mech ?? 114226031Sstas */ 115226031Sstas 116226031Sstas if (input->length > 8 && 117226031Sstas memcmp((const char *)input->value, "NTLMSSP\x00", 8) == 0) 118226031Sstas { 119226031Sstas *mech_oid = ntlm_mechanism; 120226031Sstas return GSS_S_COMPLETE; 121226031Sstas } else if (input->length != 0 && 122226031Sstas ((const char *)input->value)[0] == 0x6E) 123226031Sstas { 124226031Sstas /* Could be a raw AP-REQ (check for APPLICATION tag) */ 125226031Sstas *mech_oid = krb5_mechanism; 126226031Sstas return GSS_S_COMPLETE; 127226031Sstas } else if (input->length == 0) { 128226031Sstas /* 129226031Sstas * There is the a wierd mode of SPNEGO (in CIFS and 130226031Sstas * SASL GSS-SPENGO where the first token is zero 131226031Sstas * length and the acceptor returns a mech_list, lets 132226031Sstas * hope that is what is happening now. 133226031Sstas * 134226031Sstas * http://msdn.microsoft.com/en-us/library/cc213114.aspx 135226031Sstas * "NegTokenInit2 Variation for Server-Initiation" 136226031Sstas */ 137226031Sstas *mech_oid = spnego_mechanism; 138226031Sstas return GSS_S_COMPLETE; 139226031Sstas } 140226031Sstas return status; 141226031Sstas} 142226031Sstas 143226031Sstas 144226031SstasGSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 145226031Sstasgss_accept_sec_context(OM_uint32 *minor_status, 146226031Sstas gss_ctx_id_t *context_handle, 147226031Sstas const gss_cred_id_t acceptor_cred_handle, 148226031Sstas const gss_buffer_t input_token, 149226031Sstas const gss_channel_bindings_t input_chan_bindings, 150226031Sstas gss_name_t *src_name, 151226031Sstas gss_OID *mech_type, 152226031Sstas gss_buffer_t output_token, 153226031Sstas OM_uint32 *ret_flags, 154226031Sstas OM_uint32 *time_rec, 155226031Sstas gss_cred_id_t *delegated_cred_handle) 156226031Sstas{ 157226031Sstas OM_uint32 major_status, mech_ret_flags, junk; 158226031Sstas gssapi_mech_interface m; 159226031Sstas struct _gss_context *ctx = (struct _gss_context *) *context_handle; 160226031Sstas struct _gss_cred *cred = (struct _gss_cred *) acceptor_cred_handle; 161226031Sstas struct _gss_mechanism_cred *mc; 162226031Sstas gss_cred_id_t acceptor_mc, delegated_mc; 163226031Sstas gss_name_t src_mn; 164226031Sstas gss_OID mech_ret_type = NULL; 165226031Sstas 166226031Sstas *minor_status = 0; 167226031Sstas if (src_name) 168226031Sstas *src_name = GSS_C_NO_NAME; 169226031Sstas if (mech_type) 170226031Sstas *mech_type = GSS_C_NO_OID; 171226031Sstas if (ret_flags) 172226031Sstas *ret_flags = 0; 173226031Sstas if (time_rec) 174226031Sstas *time_rec = 0; 175226031Sstas if (delegated_cred_handle) 176226031Sstas *delegated_cred_handle = GSS_C_NO_CREDENTIAL; 177226031Sstas _mg_buffer_zero(output_token); 178226031Sstas 179226031Sstas 180226031Sstas /* 181226031Sstas * If this is the first call (*context_handle is NULL), we must 182226031Sstas * parse the input token to figure out the mechanism to use. 183226031Sstas */ 184226031Sstas if (*context_handle == GSS_C_NO_CONTEXT) { 185226031Sstas gss_OID_desc mech_oid; 186226031Sstas 187226031Sstas major_status = choose_mech(input_token, &mech_oid); 188226031Sstas if (major_status != GSS_S_COMPLETE) 189226031Sstas return major_status; 190226031Sstas 191226031Sstas /* 192226031Sstas * Now that we have a mechanism, we can find the 193226031Sstas * implementation. 194226031Sstas */ 195226031Sstas ctx = malloc(sizeof(struct _gss_context)); 196226031Sstas if (!ctx) { 197226031Sstas *minor_status = ENOMEM; 198226031Sstas return (GSS_S_DEFECTIVE_TOKEN); 199226031Sstas } 200226031Sstas memset(ctx, 0, sizeof(struct _gss_context)); 201226031Sstas m = ctx->gc_mech = __gss_get_mechanism(&mech_oid); 202226031Sstas if (!m) { 203226031Sstas free(ctx); 204226031Sstas return (GSS_S_BAD_MECH); 205226031Sstas } 206226031Sstas *context_handle = (gss_ctx_id_t) ctx; 207226031Sstas } else { 208226031Sstas m = ctx->gc_mech; 209226031Sstas } 210226031Sstas 211226031Sstas if (cred) { 212226031Sstas HEIM_SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) 213226031Sstas if (mc->gmc_mech == m) 214226031Sstas break; 215226031Sstas if (!mc) { 216226031Sstas gss_delete_sec_context(&junk, context_handle, NULL); 217226031Sstas return (GSS_S_BAD_MECH); 218226031Sstas } 219226031Sstas acceptor_mc = mc->gmc_cred; 220226031Sstas } else { 221226031Sstas acceptor_mc = GSS_C_NO_CREDENTIAL; 222226031Sstas } 223226031Sstas delegated_mc = GSS_C_NO_CREDENTIAL; 224226031Sstas 225226031Sstas mech_ret_flags = 0; 226226031Sstas major_status = m->gm_accept_sec_context(minor_status, 227226031Sstas &ctx->gc_ctx, 228226031Sstas acceptor_mc, 229226031Sstas input_token, 230226031Sstas input_chan_bindings, 231226031Sstas &src_mn, 232226031Sstas &mech_ret_type, 233226031Sstas output_token, 234226031Sstas &mech_ret_flags, 235226031Sstas time_rec, 236226031Sstas &delegated_mc); 237226031Sstas if (major_status != GSS_S_COMPLETE && 238226031Sstas major_status != GSS_S_CONTINUE_NEEDED) 239226031Sstas { 240226031Sstas _gss_mg_error(m, major_status, *minor_status); 241226031Sstas gss_delete_sec_context(&junk, context_handle, NULL); 242226031Sstas return (major_status); 243226031Sstas } 244226031Sstas 245226031Sstas if (mech_type) 246226031Sstas *mech_type = mech_ret_type; 247226031Sstas 248226031Sstas if (src_name && src_mn) { 249226031Sstas /* 250226031Sstas * Make a new name and mark it as an MN. 251226031Sstas */ 252226031Sstas struct _gss_name *name = _gss_make_name(m, src_mn); 253226031Sstas 254226031Sstas if (!name) { 255226031Sstas m->gm_release_name(minor_status, &src_mn); 256226031Sstas gss_delete_sec_context(&junk, context_handle, NULL); 257226031Sstas return (GSS_S_FAILURE); 258226031Sstas } 259226031Sstas *src_name = (gss_name_t) name; 260226031Sstas } else if (src_mn) { 261226031Sstas m->gm_release_name(minor_status, &src_mn); 262226031Sstas } 263226031Sstas 264226031Sstas if (mech_ret_flags & GSS_C_DELEG_FLAG) { 265226031Sstas if (!delegated_cred_handle) { 266226031Sstas m->gm_release_cred(minor_status, &delegated_mc); 267226031Sstas mech_ret_flags &= 268226031Sstas ~(GSS_C_DELEG_FLAG|GSS_C_DELEG_POLICY_FLAG); 269226031Sstas } else if (gss_oid_equal(mech_ret_type, &m->gm_mech_oid) == 0) { 270226031Sstas /* 271226031Sstas * If the returned mech_type is not the same 272226031Sstas * as the mech, assume its pseudo mech type 273226031Sstas * and the returned type is already a 274226031Sstas * mech-glue object 275226031Sstas */ 276226031Sstas *delegated_cred_handle = delegated_mc; 277226031Sstas 278226031Sstas } else if (delegated_mc) { 279226031Sstas struct _gss_cred *dcred; 280226031Sstas struct _gss_mechanism_cred *dmc; 281226031Sstas 282226031Sstas dcred = malloc(sizeof(struct _gss_cred)); 283226031Sstas if (!dcred) { 284226031Sstas *minor_status = ENOMEM; 285226031Sstas gss_delete_sec_context(&junk, context_handle, NULL); 286226031Sstas return (GSS_S_FAILURE); 287226031Sstas } 288226031Sstas HEIM_SLIST_INIT(&dcred->gc_mc); 289226031Sstas dmc = malloc(sizeof(struct _gss_mechanism_cred)); 290226031Sstas if (!dmc) { 291226031Sstas free(dcred); 292226031Sstas *minor_status = ENOMEM; 293226031Sstas gss_delete_sec_context(&junk, context_handle, NULL); 294226031Sstas return (GSS_S_FAILURE); 295226031Sstas } 296226031Sstas dmc->gmc_mech = m; 297226031Sstas dmc->gmc_mech_oid = &m->gm_mech_oid; 298226031Sstas dmc->gmc_cred = delegated_mc; 299226031Sstas HEIM_SLIST_INSERT_HEAD(&dcred->gc_mc, dmc, gmc_link); 300226031Sstas 301226031Sstas *delegated_cred_handle = (gss_cred_id_t) dcred; 302226031Sstas } 303226031Sstas } 304226031Sstas 305226031Sstas if (ret_flags) 306226031Sstas *ret_flags = mech_ret_flags; 307226031Sstas return (major_status); 308226031Sstas} 309