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