1153838Sdfr/*- 2153838Sdfr * Copyright (c) 2005 Doug Rabson 3153838Sdfr * All rights reserved. 4153838Sdfr * 5153838Sdfr * Redistribution and use in source and binary forms, with or without 6153838Sdfr * modification, are permitted provided that the following conditions 7153838Sdfr * are met: 8153838Sdfr * 1. Redistributions of source code must retain the above copyright 9153838Sdfr * notice, this list of conditions and the following disclaimer. 10153838Sdfr * 2. Redistributions in binary form must reproduce the above copyright 11153838Sdfr * notice, this list of conditions and the following disclaimer in the 12153838Sdfr * documentation and/or other materials provided with the distribution. 13153838Sdfr * 14153838Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15153838Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16153838Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17153838Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18153838Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19153838Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20153838Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21153838Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22153838Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23153838Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24153838Sdfr * SUCH DAMAGE. 25153838Sdfr * 26153838Sdfr * $FreeBSD$ 27153838Sdfr */ 28153838Sdfr 29153838Sdfr#include <gssapi/gssapi.h> 30153838Sdfr#include <stdlib.h> 31168340Skan#include <string.h> 32153838Sdfr#include <errno.h> 33153838Sdfr 34153838Sdfr#include "mech_switch.h" 35153838Sdfr#include "context.h" 36153838Sdfr#include "cred.h" 37153838Sdfr#include "name.h" 38178828Sdfr#include "utils.h" 39153838Sdfr 40178828Sdfrstatic OM_uint32 41178828Sdfrparse_header(const gss_buffer_t input_token, gss_OID mech_oid) 42178828Sdfr{ 43178828Sdfr unsigned char *p = input_token->value; 44178828Sdfr size_t len = input_token->length; 45178828Sdfr size_t a, b; 46178828Sdfr 47178828Sdfr /* 48178828Sdfr * Token must start with [APPLICATION 0] SEQUENCE. 49178828Sdfr * But if it doesn't assume it is DCE-STYLE Kerberos! 50178828Sdfr */ 51178828Sdfr if (len == 0) 52178828Sdfr return (GSS_S_DEFECTIVE_TOKEN); 53178828Sdfr 54178828Sdfr p++; 55178828Sdfr len--; 56178828Sdfr 57178828Sdfr /* 58178828Sdfr * Decode the length and make sure it agrees with the 59178828Sdfr * token length. 60178828Sdfr */ 61178828Sdfr if (len == 0) 62178828Sdfr return (GSS_S_DEFECTIVE_TOKEN); 63178828Sdfr if ((*p & 0x80) == 0) { 64178828Sdfr a = *p; 65178828Sdfr p++; 66178828Sdfr len--; 67178828Sdfr } else { 68178828Sdfr b = *p & 0x7f; 69178828Sdfr p++; 70178828Sdfr len--; 71178828Sdfr if (len < b) 72178828Sdfr return (GSS_S_DEFECTIVE_TOKEN); 73178828Sdfr a = 0; 74178828Sdfr while (b) { 75178828Sdfr a = (a << 8) | *p; 76178828Sdfr p++; 77178828Sdfr len--; 78178828Sdfr b--; 79178828Sdfr } 80178828Sdfr } 81178828Sdfr if (a != len) 82178828Sdfr return (GSS_S_DEFECTIVE_TOKEN); 83178828Sdfr 84178828Sdfr /* 85178828Sdfr * Decode the OID for the mechanism. Simplify life by 86178828Sdfr * assuming that the OID length is less than 128 bytes. 87178828Sdfr */ 88178828Sdfr if (len < 2 || *p != 0x06) 89178828Sdfr return (GSS_S_DEFECTIVE_TOKEN); 90178828Sdfr if ((p[1] & 0x80) || p[1] > (len - 2)) 91178828Sdfr return (GSS_S_DEFECTIVE_TOKEN); 92178828Sdfr mech_oid->length = p[1]; 93178828Sdfr p += 2; 94178828Sdfr len -= 2; 95178828Sdfr mech_oid->elements = p; 96178828Sdfr 97178828Sdfr return (GSS_S_COMPLETE); 98178828Sdfr} 99178828Sdfr 100178828Sdfrstatic gss_OID_desc krb5_mechanism = 101178828Sdfr{9, (void *)(uintptr_t) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"}; 102178828Sdfrstatic gss_OID_desc ntlm_mechanism = 103178828Sdfr{10, (void *)(uintptr_t) "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"}; 104178828Sdfrstatic gss_OID_desc spnego_mechanism = 105178828Sdfr{6, (void *)(uintptr_t) "\x2b\x06\x01\x05\x05\x02"}; 106178828Sdfr 107178828Sdfrstatic OM_uint32 108178828Sdfrchoose_mech(const gss_buffer_t input, gss_OID mech_oid) 109178828Sdfr{ 110178828Sdfr OM_uint32 status; 111178828Sdfr 112178828Sdfr /* 113178828Sdfr * First try to parse the gssapi token header and see if it's a 114178828Sdfr * correct header, use that in the first hand. 115178828Sdfr */ 116178828Sdfr 117178828Sdfr status = parse_header(input, mech_oid); 118178828Sdfr if (status == GSS_S_COMPLETE) 119178828Sdfr return (GSS_S_COMPLETE); 120178828Sdfr 121178828Sdfr /* 122178828Sdfr * Lets guess what mech is really is, callback function to mech ?? 123178828Sdfr */ 124178828Sdfr 125178828Sdfr if (input->length > 8 && 126178828Sdfr memcmp((const char *)input->value, "NTLMSSP\x00", 8) == 0) 127178828Sdfr { 128178828Sdfr *mech_oid = ntlm_mechanism; 129178828Sdfr return (GSS_S_COMPLETE); 130178828Sdfr } else if (input->length != 0 && 131178828Sdfr ((const char *)input->value)[0] == 0x6E) 132178828Sdfr { 133178828Sdfr /* Could be a raw AP-REQ (check for APPLICATION tag) */ 134178828Sdfr *mech_oid = krb5_mechanism; 135178828Sdfr return (GSS_S_COMPLETE); 136178828Sdfr } else if (input->length == 0) { 137178828Sdfr /* 138178828Sdfr * There is the a wierd mode of SPNEGO (in CIFS and 139178828Sdfr * SASL GSS-SPENGO where the first token is zero 140178828Sdfr * length and the acceptor returns a mech_list, lets 141178828Sdfr * hope that is what is happening now. 142178828Sdfr */ 143178828Sdfr *mech_oid = spnego_mechanism; 144178828Sdfr return (GSS_S_COMPLETE); 145178828Sdfr } 146178828Sdfr return (status); 147178828Sdfr} 148178828Sdfr 149153838SdfrOM_uint32 gss_accept_sec_context(OM_uint32 *minor_status, 150153838Sdfr gss_ctx_id_t *context_handle, 151153838Sdfr const gss_cred_id_t acceptor_cred_handle, 152153838Sdfr const gss_buffer_t input_token, 153153838Sdfr const gss_channel_bindings_t input_chan_bindings, 154153838Sdfr gss_name_t *src_name, 155153838Sdfr gss_OID *mech_type, 156153838Sdfr gss_buffer_t output_token, 157153838Sdfr OM_uint32 *ret_flags, 158153838Sdfr OM_uint32 *time_rec, 159153838Sdfr gss_cred_id_t *delegated_cred_handle) 160153838Sdfr{ 161171112Sdfr OM_uint32 major_status, mech_ret_flags; 162153838Sdfr struct _gss_mech_switch *m; 163153838Sdfr struct _gss_context *ctx = (struct _gss_context *) *context_handle; 164153838Sdfr struct _gss_cred *cred = (struct _gss_cred *) acceptor_cred_handle; 165153838Sdfr struct _gss_mechanism_cred *mc; 166153838Sdfr gss_cred_id_t acceptor_mc, delegated_mc; 167153838Sdfr gss_name_t src_mn; 168153838Sdfr int allocated_ctx; 169153838Sdfr 170153838Sdfr *minor_status = 0; 171178828Sdfr if (src_name) 172178828Sdfr *src_name = GSS_C_NO_NAME; 173178828Sdfr if (mech_type) 174178828Sdfr *mech_type = GSS_C_NO_OID; 175178828Sdfr if (ret_flags) 176178828Sdfr *ret_flags = 0; 177178828Sdfr if (time_rec) 178178828Sdfr *time_rec = 0; 179178828Sdfr if (delegated_cred_handle) 180178828Sdfr *delegated_cred_handle = GSS_C_NO_CREDENTIAL; 181178828Sdfr _gss_buffer_zero(output_token); 182153838Sdfr 183153838Sdfr /* 184153838Sdfr * If this is the first call (*context_handle is NULL), we must 185153838Sdfr * parse the input token to figure out the mechanism to use. 186153838Sdfr */ 187153838Sdfr if (*context_handle == GSS_C_NO_CONTEXT) { 188153838Sdfr gss_OID_desc mech_oid; 189153838Sdfr 190178828Sdfr major_status = choose_mech(input_token, &mech_oid); 191178828Sdfr if (major_status != GSS_S_COMPLETE) 192178828Sdfr return (major_status); 193153838Sdfr 194153838Sdfr /* 195153838Sdfr * Now that we have a mechanism, we can find the 196153838Sdfr * implementation. 197153838Sdfr */ 198153838Sdfr ctx = malloc(sizeof(struct _gss_context)); 199153838Sdfr if (!ctx) { 200153838Sdfr *minor_status = ENOMEM; 201153838Sdfr return (GSS_S_DEFECTIVE_TOKEN); 202153838Sdfr } 203153838Sdfr memset(ctx, 0, sizeof(struct _gss_context)); 204153838Sdfr m = ctx->gc_mech = _gss_find_mech_switch(&mech_oid); 205153838Sdfr if (!m) { 206153838Sdfr free(ctx); 207153838Sdfr return (GSS_S_BAD_MECH); 208153838Sdfr } 209153838Sdfr allocated_ctx = 1; 210153838Sdfr } else { 211153838Sdfr m = ctx->gc_mech; 212153838Sdfr allocated_ctx = 0; 213153838Sdfr } 214153838Sdfr 215153838Sdfr if (cred) { 216153838Sdfr SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) 217153838Sdfr if (mc->gmc_mech == m) 218153838Sdfr break; 219153838Sdfr if (!mc) 220153838Sdfr return (GSS_S_BAD_MECH); 221153838Sdfr acceptor_mc = mc->gmc_cred; 222153838Sdfr } else { 223153838Sdfr acceptor_mc = GSS_C_NO_CREDENTIAL; 224153838Sdfr } 225153838Sdfr delegated_mc = GSS_C_NO_CREDENTIAL; 226153838Sdfr 227178828Sdfr mech_ret_flags = 0; 228153838Sdfr major_status = m->gm_accept_sec_context(minor_status, 229153838Sdfr &ctx->gc_ctx, 230153838Sdfr acceptor_mc, 231153838Sdfr input_token, 232153838Sdfr input_chan_bindings, 233153838Sdfr &src_mn, 234153838Sdfr mech_type, 235153838Sdfr output_token, 236171112Sdfr &mech_ret_flags, 237153838Sdfr time_rec, 238153838Sdfr &delegated_mc); 239153838Sdfr if (major_status != GSS_S_COMPLETE && 240178828Sdfr major_status != GSS_S_CONTINUE_NEEDED) { 241178828Sdfr _gss_mg_error(m, major_status, *minor_status); 242153838Sdfr return (major_status); 243178828Sdfr } 244153838Sdfr 245178828Sdfr if (src_name && src_mn) { 246153838Sdfr /* 247153838Sdfr * Make a new name and mark it as an MN. 248153838Sdfr */ 249153838Sdfr struct _gss_name *name = _gss_make_name(m, src_mn); 250153838Sdfr 251153838Sdfr if (!name) { 252153838Sdfr m->gm_release_name(minor_status, &src_mn); 253153838Sdfr return (GSS_S_FAILURE); 254153838Sdfr } 255153838Sdfr *src_name = (gss_name_t) name; 256178828Sdfr } else if (src_mn) { 257178828Sdfr m->gm_release_name(minor_status, &src_mn); 258153838Sdfr } 259153838Sdfr 260178692Sdfr if (delegated_mc == GSS_C_NO_CREDENTIAL) 261178692Sdfr mech_ret_flags &= ~GSS_C_DELEG_FLAG; 262178692Sdfr 263171112Sdfr if (mech_ret_flags & GSS_C_DELEG_FLAG) { 264153838Sdfr if (!delegated_cred_handle) { 265153838Sdfr m->gm_release_cred(minor_status, &delegated_mc); 266178692Sdfr mech_ret_flags &= ~GSS_C_DELEG_FLAG; 267153838Sdfr } else { 268178828Sdfr struct _gss_cred *dcred; 269178828Sdfr struct _gss_mechanism_cred *dmc; 270153838Sdfr 271178828Sdfr dcred = malloc(sizeof(struct _gss_cred)); 272178828Sdfr if (!dcred) { 273153838Sdfr *minor_status = ENOMEM; 274153838Sdfr return (GSS_S_FAILURE); 275153838Sdfr } 276178828Sdfr SLIST_INIT(&dcred->gc_mc); 277178828Sdfr dmc = malloc(sizeof(struct _gss_mechanism_cred)); 278178828Sdfr if (!dmc) { 279178828Sdfr free(dcred); 280153838Sdfr *minor_status = ENOMEM; 281153838Sdfr return (GSS_S_FAILURE); 282153838Sdfr } 283178828Sdfr dmc->gmc_mech = m; 284178828Sdfr dmc->gmc_mech_oid = &m->gm_mech_oid; 285178828Sdfr dmc->gmc_cred = delegated_mc; 286178828Sdfr SLIST_INSERT_HEAD(&dcred->gc_mc, dmc, gmc_link); 287153838Sdfr 288178828Sdfr *delegated_cred_handle = (gss_cred_id_t) dcred; 289153838Sdfr } 290153838Sdfr } 291153838Sdfr 292171112Sdfr if (ret_flags) 293171112Sdfr *ret_flags = mech_ret_flags; 294153838Sdfr *context_handle = (gss_ctx_id_t) ctx; 295153838Sdfr return (major_status); 296153838Sdfr} 297