1c0b9f4feSDoug Rabson /*- 2c0b9f4feSDoug Rabson * Copyright (c) 2005 Doug Rabson 3c0b9f4feSDoug Rabson * All rights reserved. 4c0b9f4feSDoug Rabson * 5c0b9f4feSDoug Rabson * Redistribution and use in source and binary forms, with or without 6c0b9f4feSDoug Rabson * modification, are permitted provided that the following conditions 7c0b9f4feSDoug Rabson * are met: 8c0b9f4feSDoug Rabson * 1. Redistributions of source code must retain the above copyright 9c0b9f4feSDoug Rabson * notice, this list of conditions and the following disclaimer. 10c0b9f4feSDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 11c0b9f4feSDoug Rabson * notice, this list of conditions and the following disclaimer in the 12c0b9f4feSDoug Rabson * documentation and/or other materials provided with the distribution. 13c0b9f4feSDoug Rabson * 14c0b9f4feSDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15c0b9f4feSDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16c0b9f4feSDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17c0b9f4feSDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18c0b9f4feSDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19c0b9f4feSDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20c0b9f4feSDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21c0b9f4feSDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22c0b9f4feSDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23c0b9f4feSDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24c0b9f4feSDoug Rabson * SUCH DAMAGE. 25c0b9f4feSDoug Rabson * 26c0b9f4feSDoug Rabson * $FreeBSD$ 27c0b9f4feSDoug Rabson */ 28c0b9f4feSDoug Rabson 29c0b9f4feSDoug Rabson #include <gssapi/gssapi.h> 30c0b9f4feSDoug Rabson #include <stdlib.h> 313aebdb89SAlexander Kabaev #include <string.h> 32c0b9f4feSDoug Rabson #include <errno.h> 33c0b9f4feSDoug Rabson 34c0b9f4feSDoug Rabson #include "mech_switch.h" 35c0b9f4feSDoug Rabson #include "context.h" 36c0b9f4feSDoug Rabson #include "cred.h" 37c0b9f4feSDoug Rabson #include "name.h" 3833f12199SDoug Rabson #include "utils.h" 39c0b9f4feSDoug Rabson 4033f12199SDoug Rabson static OM_uint32 4133f12199SDoug Rabson parse_header(const gss_buffer_t input_token, gss_OID mech_oid) 42c0b9f4feSDoug Rabson { 43c0b9f4feSDoug Rabson unsigned char *p = input_token->value; 44c0b9f4feSDoug Rabson size_t len = input_token->length; 45c0b9f4feSDoug Rabson size_t a, b; 46c0b9f4feSDoug Rabson 47c0b9f4feSDoug Rabson /* 48c0b9f4feSDoug Rabson * Token must start with [APPLICATION 0] SEQUENCE. 4933f12199SDoug Rabson * But if it doesn't assume it is DCE-STYLE Kerberos! 50c0b9f4feSDoug Rabson */ 5133f12199SDoug Rabson if (len == 0) 52c0b9f4feSDoug Rabson return (GSS_S_DEFECTIVE_TOKEN); 5333f12199SDoug Rabson 54c0b9f4feSDoug Rabson p++; 55c0b9f4feSDoug Rabson len--; 56c0b9f4feSDoug Rabson 57c0b9f4feSDoug Rabson /* 58c0b9f4feSDoug Rabson * Decode the length and make sure it agrees with the 59c0b9f4feSDoug Rabson * token length. 60c0b9f4feSDoug Rabson */ 61c0b9f4feSDoug Rabson if (len == 0) 62c0b9f4feSDoug Rabson return (GSS_S_DEFECTIVE_TOKEN); 63c0b9f4feSDoug Rabson if ((*p & 0x80) == 0) { 64c0b9f4feSDoug Rabson a = *p; 65c0b9f4feSDoug Rabson p++; 66c0b9f4feSDoug Rabson len--; 67c0b9f4feSDoug Rabson } else { 68c0b9f4feSDoug Rabson b = *p & 0x7f; 69c0b9f4feSDoug Rabson p++; 70c0b9f4feSDoug Rabson len--; 71c0b9f4feSDoug Rabson if (len < b) 72c0b9f4feSDoug Rabson return (GSS_S_DEFECTIVE_TOKEN); 73c0b9f4feSDoug Rabson a = 0; 74c0b9f4feSDoug Rabson while (b) { 75c0b9f4feSDoug Rabson a = (a << 8) | *p; 76c0b9f4feSDoug Rabson p++; 77c0b9f4feSDoug Rabson len--; 78c0b9f4feSDoug Rabson b--; 79c0b9f4feSDoug Rabson } 80c0b9f4feSDoug Rabson } 81c0b9f4feSDoug Rabson if (a != len) 82c0b9f4feSDoug Rabson return (GSS_S_DEFECTIVE_TOKEN); 83c0b9f4feSDoug Rabson 84c0b9f4feSDoug Rabson /* 85c0b9f4feSDoug Rabson * Decode the OID for the mechanism. Simplify life by 86c0b9f4feSDoug Rabson * assuming that the OID length is less than 128 bytes. 87c0b9f4feSDoug Rabson */ 88c0b9f4feSDoug Rabson if (len < 2 || *p != 0x06) 89c0b9f4feSDoug Rabson return (GSS_S_DEFECTIVE_TOKEN); 90c0b9f4feSDoug Rabson if ((p[1] & 0x80) || p[1] > (len - 2)) 91c0b9f4feSDoug Rabson return (GSS_S_DEFECTIVE_TOKEN); 9233f12199SDoug Rabson mech_oid->length = p[1]; 93c0b9f4feSDoug Rabson p += 2; 94c0b9f4feSDoug Rabson len -= 2; 9533f12199SDoug Rabson mech_oid->elements = p; 9633f12199SDoug Rabson 9733f12199SDoug Rabson return (GSS_S_COMPLETE); 9833f12199SDoug Rabson } 9933f12199SDoug Rabson 10033f12199SDoug Rabson static gss_OID_desc krb5_mechanism = 10133f12199SDoug Rabson {9, (void *)(uintptr_t) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"}; 10233f12199SDoug Rabson static gss_OID_desc ntlm_mechanism = 10333f12199SDoug Rabson {10, (void *)(uintptr_t) "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"}; 10433f12199SDoug Rabson static gss_OID_desc spnego_mechanism = 10533f12199SDoug Rabson {6, (void *)(uintptr_t) "\x2b\x06\x01\x05\x05\x02"}; 10633f12199SDoug Rabson 10733f12199SDoug Rabson static OM_uint32 10833f12199SDoug Rabson choose_mech(const gss_buffer_t input, gss_OID mech_oid) 10933f12199SDoug Rabson { 11033f12199SDoug Rabson OM_uint32 status; 11133f12199SDoug Rabson 11233f12199SDoug Rabson /* 11333f12199SDoug Rabson * First try to parse the gssapi token header and see if it's a 11433f12199SDoug Rabson * correct header, use that in the first hand. 11533f12199SDoug Rabson */ 11633f12199SDoug Rabson 11733f12199SDoug Rabson status = parse_header(input, mech_oid); 11833f12199SDoug Rabson if (status == GSS_S_COMPLETE) 11933f12199SDoug Rabson return (GSS_S_COMPLETE); 12033f12199SDoug Rabson 12133f12199SDoug Rabson /* 12233f12199SDoug Rabson * Lets guess what mech is really is, callback function to mech ?? 12333f12199SDoug Rabson */ 12433f12199SDoug Rabson 12533f12199SDoug Rabson if (input->length > 8 && 12633f12199SDoug Rabson memcmp((const char *)input->value, "NTLMSSP\x00", 8) == 0) 12733f12199SDoug Rabson { 12833f12199SDoug Rabson *mech_oid = ntlm_mechanism; 12933f12199SDoug Rabson return (GSS_S_COMPLETE); 13033f12199SDoug Rabson } else if (input->length != 0 && 13133f12199SDoug Rabson ((const char *)input->value)[0] == 0x6E) 13233f12199SDoug Rabson { 13333f12199SDoug Rabson /* Could be a raw AP-REQ (check for APPLICATION tag) */ 13433f12199SDoug Rabson *mech_oid = krb5_mechanism; 13533f12199SDoug Rabson return (GSS_S_COMPLETE); 13633f12199SDoug Rabson } else if (input->length == 0) { 13733f12199SDoug Rabson /* 138*75f46cf6SPedro F. Giffuni * There is the a weird mode of SPNEGO (in CIFS and 13933f12199SDoug Rabson * SASL GSS-SPENGO where the first token is zero 14033f12199SDoug Rabson * length and the acceptor returns a mech_list, lets 14133f12199SDoug Rabson * hope that is what is happening now. 14233f12199SDoug Rabson */ 14333f12199SDoug Rabson *mech_oid = spnego_mechanism; 14433f12199SDoug Rabson return (GSS_S_COMPLETE); 14533f12199SDoug Rabson } 14633f12199SDoug Rabson return (status); 14733f12199SDoug Rabson } 14833f12199SDoug Rabson 14933f12199SDoug Rabson OM_uint32 gss_accept_sec_context(OM_uint32 *minor_status, 15033f12199SDoug Rabson gss_ctx_id_t *context_handle, 15133f12199SDoug Rabson const gss_cred_id_t acceptor_cred_handle, 15233f12199SDoug Rabson const gss_buffer_t input_token, 15333f12199SDoug Rabson const gss_channel_bindings_t input_chan_bindings, 15433f12199SDoug Rabson gss_name_t *src_name, 15533f12199SDoug Rabson gss_OID *mech_type, 15633f12199SDoug Rabson gss_buffer_t output_token, 15733f12199SDoug Rabson OM_uint32 *ret_flags, 15833f12199SDoug Rabson OM_uint32 *time_rec, 15933f12199SDoug Rabson gss_cred_id_t *delegated_cred_handle) 16033f12199SDoug Rabson { 16133f12199SDoug Rabson OM_uint32 major_status, mech_ret_flags; 16233f12199SDoug Rabson struct _gss_mech_switch *m; 16333f12199SDoug Rabson struct _gss_context *ctx = (struct _gss_context *) *context_handle; 16433f12199SDoug Rabson struct _gss_cred *cred = (struct _gss_cred *) acceptor_cred_handle; 16533f12199SDoug Rabson struct _gss_mechanism_cred *mc; 16633f12199SDoug Rabson gss_cred_id_t acceptor_mc, delegated_mc; 16733f12199SDoug Rabson gss_name_t src_mn; 16833f12199SDoug Rabson 16933f12199SDoug Rabson *minor_status = 0; 17033f12199SDoug Rabson if (src_name) 17133f12199SDoug Rabson *src_name = GSS_C_NO_NAME; 17233f12199SDoug Rabson if (mech_type) 17333f12199SDoug Rabson *mech_type = GSS_C_NO_OID; 17433f12199SDoug Rabson if (ret_flags) 17533f12199SDoug Rabson *ret_flags = 0; 17633f12199SDoug Rabson if (time_rec) 17733f12199SDoug Rabson *time_rec = 0; 17833f12199SDoug Rabson if (delegated_cred_handle) 17933f12199SDoug Rabson *delegated_cred_handle = GSS_C_NO_CREDENTIAL; 18033f12199SDoug Rabson _gss_buffer_zero(output_token); 18133f12199SDoug Rabson 18233f12199SDoug Rabson /* 18333f12199SDoug Rabson * If this is the first call (*context_handle is NULL), we must 18433f12199SDoug Rabson * parse the input token to figure out the mechanism to use. 18533f12199SDoug Rabson */ 18633f12199SDoug Rabson if (*context_handle == GSS_C_NO_CONTEXT) { 18733f12199SDoug Rabson gss_OID_desc mech_oid; 18833f12199SDoug Rabson 18933f12199SDoug Rabson major_status = choose_mech(input_token, &mech_oid); 19033f12199SDoug Rabson if (major_status != GSS_S_COMPLETE) 19133f12199SDoug Rabson return (major_status); 192c0b9f4feSDoug Rabson 193c0b9f4feSDoug Rabson /* 194c0b9f4feSDoug Rabson * Now that we have a mechanism, we can find the 195c0b9f4feSDoug Rabson * implementation. 196c0b9f4feSDoug Rabson */ 197c0b9f4feSDoug Rabson ctx = malloc(sizeof(struct _gss_context)); 198c0b9f4feSDoug Rabson if (!ctx) { 199c0b9f4feSDoug Rabson *minor_status = ENOMEM; 200c0b9f4feSDoug Rabson return (GSS_S_DEFECTIVE_TOKEN); 201c0b9f4feSDoug Rabson } 202c0b9f4feSDoug Rabson memset(ctx, 0, sizeof(struct _gss_context)); 203c0b9f4feSDoug Rabson m = ctx->gc_mech = _gss_find_mech_switch(&mech_oid); 204c0b9f4feSDoug Rabson if (!m) { 205c0b9f4feSDoug Rabson free(ctx); 206c0b9f4feSDoug Rabson return (GSS_S_BAD_MECH); 207c0b9f4feSDoug Rabson } 208f2155136SMarcelo Araujo } else 209c0b9f4feSDoug Rabson m = ctx->gc_mech; 210c0b9f4feSDoug Rabson 211c0b9f4feSDoug Rabson if (cred) { 212c0b9f4feSDoug Rabson SLIST_FOREACH(mc, &cred->gc_mc, gmc_link) 213c0b9f4feSDoug Rabson if (mc->gmc_mech == m) 214c0b9f4feSDoug Rabson break; 215c0b9f4feSDoug Rabson if (!mc) 216c0b9f4feSDoug Rabson return (GSS_S_BAD_MECH); 217c0b9f4feSDoug Rabson acceptor_mc = mc->gmc_cred; 218c0b9f4feSDoug Rabson } else { 219c0b9f4feSDoug Rabson acceptor_mc = GSS_C_NO_CREDENTIAL; 220c0b9f4feSDoug Rabson } 221c0b9f4feSDoug Rabson delegated_mc = GSS_C_NO_CREDENTIAL; 222c0b9f4feSDoug Rabson 22333f12199SDoug Rabson mech_ret_flags = 0; 224c0b9f4feSDoug Rabson major_status = m->gm_accept_sec_context(minor_status, 225c0b9f4feSDoug Rabson &ctx->gc_ctx, 226c0b9f4feSDoug Rabson acceptor_mc, 227c0b9f4feSDoug Rabson input_token, 228c0b9f4feSDoug Rabson input_chan_bindings, 229c0b9f4feSDoug Rabson &src_mn, 230c0b9f4feSDoug Rabson mech_type, 231c0b9f4feSDoug Rabson output_token, 23222a25490SDoug Rabson &mech_ret_flags, 233c0b9f4feSDoug Rabson time_rec, 234c0b9f4feSDoug Rabson &delegated_mc); 235c0b9f4feSDoug Rabson if (major_status != GSS_S_COMPLETE && 23633f12199SDoug Rabson major_status != GSS_S_CONTINUE_NEEDED) { 23733f12199SDoug Rabson _gss_mg_error(m, major_status, *minor_status); 238c0b9f4feSDoug Rabson return (major_status); 23933f12199SDoug Rabson } 240c0b9f4feSDoug Rabson 24133f12199SDoug Rabson if (src_name && src_mn) { 242c0b9f4feSDoug Rabson /* 243c0b9f4feSDoug Rabson * Make a new name and mark it as an MN. 244c0b9f4feSDoug Rabson */ 245c0b9f4feSDoug Rabson struct _gss_name *name = _gss_make_name(m, src_mn); 246c0b9f4feSDoug Rabson 247c0b9f4feSDoug Rabson if (!name) { 248c0b9f4feSDoug Rabson m->gm_release_name(minor_status, &src_mn); 249c0b9f4feSDoug Rabson return (GSS_S_FAILURE); 250c0b9f4feSDoug Rabson } 251c0b9f4feSDoug Rabson *src_name = (gss_name_t) name; 25233f12199SDoug Rabson } else if (src_mn) { 25333f12199SDoug Rabson m->gm_release_name(minor_status, &src_mn); 254c0b9f4feSDoug Rabson } 255c0b9f4feSDoug Rabson 256e1a0d9efSDoug Rabson if (delegated_mc == GSS_C_NO_CREDENTIAL) 257e1a0d9efSDoug Rabson mech_ret_flags &= ~GSS_C_DELEG_FLAG; 258e1a0d9efSDoug Rabson 25922a25490SDoug Rabson if (mech_ret_flags & GSS_C_DELEG_FLAG) { 260c0b9f4feSDoug Rabson if (!delegated_cred_handle) { 261c0b9f4feSDoug Rabson m->gm_release_cred(minor_status, &delegated_mc); 262e1a0d9efSDoug Rabson mech_ret_flags &= ~GSS_C_DELEG_FLAG; 263c0b9f4feSDoug Rabson } else { 26433f12199SDoug Rabson struct _gss_cred *dcred; 26533f12199SDoug Rabson struct _gss_mechanism_cred *dmc; 266c0b9f4feSDoug Rabson 26733f12199SDoug Rabson dcred = malloc(sizeof(struct _gss_cred)); 26833f12199SDoug Rabson if (!dcred) { 269c0b9f4feSDoug Rabson *minor_status = ENOMEM; 270c0b9f4feSDoug Rabson return (GSS_S_FAILURE); 271c0b9f4feSDoug Rabson } 27233f12199SDoug Rabson SLIST_INIT(&dcred->gc_mc); 27333f12199SDoug Rabson dmc = malloc(sizeof(struct _gss_mechanism_cred)); 27433f12199SDoug Rabson if (!dmc) { 27533f12199SDoug Rabson free(dcred); 276c0b9f4feSDoug Rabson *minor_status = ENOMEM; 277c0b9f4feSDoug Rabson return (GSS_S_FAILURE); 278c0b9f4feSDoug Rabson } 27933f12199SDoug Rabson dmc->gmc_mech = m; 28033f12199SDoug Rabson dmc->gmc_mech_oid = &m->gm_mech_oid; 28133f12199SDoug Rabson dmc->gmc_cred = delegated_mc; 28233f12199SDoug Rabson SLIST_INSERT_HEAD(&dcred->gc_mc, dmc, gmc_link); 283c0b9f4feSDoug Rabson 28433f12199SDoug Rabson *delegated_cred_handle = (gss_cred_id_t) dcred; 285c0b9f4feSDoug Rabson } 286c0b9f4feSDoug Rabson } 287c0b9f4feSDoug Rabson 28822a25490SDoug Rabson if (ret_flags) 28922a25490SDoug Rabson *ret_flags = mech_ret_flags; 290c0b9f4feSDoug Rabson *context_handle = (gss_ctx_id_t) ctx; 291c0b9f4feSDoug Rabson return (major_status); 292c0b9f4feSDoug Rabson } 293