1c0b9f4feSDoug Rabson /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
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
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
parse_header(const gss_buffer_t input_token,gss_OID mech_oid)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 =
101b16d6675SBrooks Davis {9, __DECONST(void *, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")};
10233f12199SDoug Rabson static gss_OID_desc ntlm_mechanism =
103b16d6675SBrooks Davis {10, __DECONST(void *, "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a")};
10433f12199SDoug Rabson static gss_OID_desc spnego_mechanism =
105b16d6675SBrooks Davis {6, __DECONST(void *, "\x2b\x06\x01\x05\x05\x02")};
10633f12199SDoug Rabson
10733f12199SDoug Rabson static OM_uint32
choose_mech(const gss_buffer_t input,gss_OID mech_oid)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 /*
13875f46cf6SPedro 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
gss_accept_sec_context(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,const gss_cred_id_t acceptor_cred_handle,const gss_buffer_t input_token,const gss_channel_bindings_t input_chan_bindings,gss_name_t * src_name,gss_OID * mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec,gss_cred_id_t * delegated_cred_handle)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