xref: /freebsd/lib/libgssapi/gss_accept_sec_context.c (revision 3aebdb89adb23512b231f192471ced462a35aaa9)
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"
38c0b9f4feSDoug Rabson 
39c0b9f4feSDoug Rabson OM_uint32 gss_accept_sec_context(OM_uint32 *minor_status,
40c0b9f4feSDoug Rabson     gss_ctx_id_t *context_handle,
41c0b9f4feSDoug Rabson     const gss_cred_id_t acceptor_cred_handle,
42c0b9f4feSDoug Rabson     const gss_buffer_t input_token,
43c0b9f4feSDoug Rabson     const gss_channel_bindings_t input_chan_bindings,
44c0b9f4feSDoug Rabson     gss_name_t *src_name,
45c0b9f4feSDoug Rabson     gss_OID *mech_type,
46c0b9f4feSDoug Rabson     gss_buffer_t output_token,
47c0b9f4feSDoug Rabson     OM_uint32 *ret_flags,
48c0b9f4feSDoug Rabson     OM_uint32 *time_rec,
49c0b9f4feSDoug Rabson     gss_cred_id_t *delegated_cred_handle)
50c0b9f4feSDoug Rabson {
51c0b9f4feSDoug Rabson 	OM_uint32 major_status;
52c0b9f4feSDoug Rabson 	struct _gss_mech_switch *m;
53c0b9f4feSDoug Rabson 	struct _gss_context *ctx = (struct _gss_context *) *context_handle;
54c0b9f4feSDoug Rabson 	struct _gss_cred *cred = (struct _gss_cred *) acceptor_cred_handle;
55c0b9f4feSDoug Rabson 	struct _gss_mechanism_cred *mc;
56c0b9f4feSDoug Rabson 	gss_cred_id_t acceptor_mc, delegated_mc;
57c0b9f4feSDoug Rabson 	gss_name_t src_mn;
58c0b9f4feSDoug Rabson 	int allocated_ctx;
59c0b9f4feSDoug Rabson 
60c0b9f4feSDoug Rabson 	*minor_status = 0;
61c0b9f4feSDoug Rabson 	if (src_name) *src_name = 0;
62c0b9f4feSDoug Rabson 	if (mech_type) *mech_type = 0;
63c0b9f4feSDoug Rabson 	if (ret_flags) *ret_flags = 0;
64c0b9f4feSDoug Rabson 	if (time_rec) *time_rec = 0;
65c0b9f4feSDoug Rabson 	if (delegated_cred_handle) *delegated_cred_handle = 0;
66c0b9f4feSDoug Rabson 	output_token->length = 0;
67c0b9f4feSDoug Rabson 	output_token->value = 0;
68c0b9f4feSDoug Rabson 
69c0b9f4feSDoug Rabson 	/*
70c0b9f4feSDoug Rabson 	 * If this is the first call (*context_handle is NULL), we must
71c0b9f4feSDoug Rabson 	 * parse the input token to figure out the mechanism to use.
72c0b9f4feSDoug Rabson 	 */
73c0b9f4feSDoug Rabson 	if (*context_handle == GSS_C_NO_CONTEXT) {
74c0b9f4feSDoug Rabson 		unsigned char *p = input_token->value;
75c0b9f4feSDoug Rabson 		size_t len = input_token->length;
76c0b9f4feSDoug Rabson 		size_t a, b;
77c0b9f4feSDoug Rabson 		gss_OID_desc mech_oid;
78c0b9f4feSDoug Rabson 
79c0b9f4feSDoug Rabson 		/*
80c0b9f4feSDoug Rabson 		 * Token must start with [APPLICATION 0] SEQUENCE.
81c0b9f4feSDoug Rabson 		 */
82c0b9f4feSDoug Rabson 		if (len == 0 || *p != 0x60)
83c0b9f4feSDoug Rabson 			return (GSS_S_DEFECTIVE_TOKEN);
84c0b9f4feSDoug Rabson 		p++;
85c0b9f4feSDoug Rabson 		len--;
86c0b9f4feSDoug Rabson 
87c0b9f4feSDoug Rabson 		/*
88c0b9f4feSDoug Rabson 		 * Decode the length and make sure it agrees with the
89c0b9f4feSDoug Rabson 		 * token length.
90c0b9f4feSDoug Rabson 		 */
91c0b9f4feSDoug Rabson 		if (len == 0)
92c0b9f4feSDoug Rabson 			return (GSS_S_DEFECTIVE_TOKEN);
93c0b9f4feSDoug Rabson 		if ((*p & 0x80) == 0) {
94c0b9f4feSDoug Rabson 			a = *p;
95c0b9f4feSDoug Rabson 			p++;
96c0b9f4feSDoug Rabson 			len--;
97c0b9f4feSDoug Rabson 		} else {
98c0b9f4feSDoug Rabson 			b = *p & 0x7f;
99c0b9f4feSDoug Rabson 			p++;
100c0b9f4feSDoug Rabson 			len--;
101c0b9f4feSDoug Rabson 			if (len < b)
102c0b9f4feSDoug Rabson 				return (GSS_S_DEFECTIVE_TOKEN);
103c0b9f4feSDoug Rabson 			a = 0;
104c0b9f4feSDoug Rabson 			while (b) {
105c0b9f4feSDoug Rabson 				a = (a << 8) | *p;
106c0b9f4feSDoug Rabson 				p++;
107c0b9f4feSDoug Rabson 				len--;
108c0b9f4feSDoug Rabson 				b--;
109c0b9f4feSDoug Rabson 			}
110c0b9f4feSDoug Rabson 		}
111c0b9f4feSDoug Rabson 		if (a != len)
112c0b9f4feSDoug Rabson 			return (GSS_S_DEFECTIVE_TOKEN);
113c0b9f4feSDoug Rabson 
114c0b9f4feSDoug Rabson 		/*
115c0b9f4feSDoug Rabson 		 * Decode the OID for the mechanism. Simplify life by
116c0b9f4feSDoug Rabson 		 * assuming that the OID length is less than 128 bytes.
117c0b9f4feSDoug Rabson 		 */
118c0b9f4feSDoug Rabson 		if (len < 2 || *p != 0x06)
119c0b9f4feSDoug Rabson 			return (GSS_S_DEFECTIVE_TOKEN);
120c0b9f4feSDoug Rabson 		if ((p[1] & 0x80) || p[1] > (len - 2))
121c0b9f4feSDoug Rabson 			return (GSS_S_DEFECTIVE_TOKEN);
122c0b9f4feSDoug Rabson 		mech_oid.length = p[1];
123c0b9f4feSDoug Rabson 		p += 2;
124c0b9f4feSDoug Rabson 		len -= 2;
125c0b9f4feSDoug Rabson 		mech_oid.elements = p;
126c0b9f4feSDoug Rabson 
127c0b9f4feSDoug Rabson 		/*
128c0b9f4feSDoug Rabson 		 * Now that we have a mechanism, we can find the
129c0b9f4feSDoug Rabson 		 * implementation.
130c0b9f4feSDoug Rabson 		 */
131c0b9f4feSDoug Rabson 		ctx = malloc(sizeof(struct _gss_context));
132c0b9f4feSDoug Rabson 		if (!ctx) {
133c0b9f4feSDoug Rabson 			*minor_status = ENOMEM;
134c0b9f4feSDoug Rabson 			return (GSS_S_DEFECTIVE_TOKEN);
135c0b9f4feSDoug Rabson 		}
136c0b9f4feSDoug Rabson 		memset(ctx, 0, sizeof(struct _gss_context));
137c0b9f4feSDoug Rabson 		m = ctx->gc_mech = _gss_find_mech_switch(&mech_oid);
138c0b9f4feSDoug Rabson 		if (!m) {
139c0b9f4feSDoug Rabson 			free(ctx);
140c0b9f4feSDoug Rabson 			return (GSS_S_BAD_MECH);
141c0b9f4feSDoug Rabson 		}
142c0b9f4feSDoug Rabson 		allocated_ctx = 1;
143c0b9f4feSDoug Rabson 	} else {
144c0b9f4feSDoug Rabson 		m = ctx->gc_mech;
145c0b9f4feSDoug Rabson 		allocated_ctx = 0;
146c0b9f4feSDoug Rabson 	}
147c0b9f4feSDoug Rabson 
148c0b9f4feSDoug Rabson 	if (cred) {
149c0b9f4feSDoug Rabson 		SLIST_FOREACH(mc, &cred->gc_mc, gmc_link)
150c0b9f4feSDoug Rabson 			if (mc->gmc_mech == m)
151c0b9f4feSDoug Rabson 				break;
152c0b9f4feSDoug Rabson 		if (!mc)
153c0b9f4feSDoug Rabson 			return (GSS_S_BAD_MECH);
154c0b9f4feSDoug Rabson 		acceptor_mc = mc->gmc_cred;
155c0b9f4feSDoug Rabson 	} else {
156c0b9f4feSDoug Rabson 		acceptor_mc = GSS_C_NO_CREDENTIAL;
157c0b9f4feSDoug Rabson 	}
158c0b9f4feSDoug Rabson 	delegated_mc = GSS_C_NO_CREDENTIAL;
159c0b9f4feSDoug Rabson 
160c0b9f4feSDoug Rabson 	major_status = m->gm_accept_sec_context(minor_status,
161c0b9f4feSDoug Rabson 	    &ctx->gc_ctx,
162c0b9f4feSDoug Rabson 	    acceptor_mc,
163c0b9f4feSDoug Rabson 	    input_token,
164c0b9f4feSDoug Rabson 	    input_chan_bindings,
165c0b9f4feSDoug Rabson 	    &src_mn,
166c0b9f4feSDoug Rabson 	    mech_type,
167c0b9f4feSDoug Rabson 	    output_token,
168c0b9f4feSDoug Rabson 	    ret_flags,
169c0b9f4feSDoug Rabson 	    time_rec,
170c0b9f4feSDoug Rabson 	    &delegated_mc);
171c0b9f4feSDoug Rabson 	if (major_status != GSS_S_COMPLETE &&
172c0b9f4feSDoug Rabson 	    major_status != GSS_S_CONTINUE_NEEDED)
173c0b9f4feSDoug Rabson 		return (major_status);
174c0b9f4feSDoug Rabson 
175c0b9f4feSDoug Rabson 	if (!src_name) {
176c0b9f4feSDoug Rabson 		m->gm_release_name(minor_status, &src_mn);
177c0b9f4feSDoug Rabson 	} else {
178c0b9f4feSDoug Rabson 		/*
179c0b9f4feSDoug Rabson 		 * Make a new name and mark it as an MN.
180c0b9f4feSDoug Rabson 		 */
181c0b9f4feSDoug Rabson 		struct _gss_name *name = _gss_make_name(m, src_mn);
182c0b9f4feSDoug Rabson 
183c0b9f4feSDoug Rabson 		if (!name) {
184c0b9f4feSDoug Rabson 			m->gm_release_name(minor_status, &src_mn);
185c0b9f4feSDoug Rabson 			return (GSS_S_FAILURE);
186c0b9f4feSDoug Rabson 		}
187c0b9f4feSDoug Rabson 		*src_name = (gss_name_t) name;
188c0b9f4feSDoug Rabson 	}
189c0b9f4feSDoug Rabson 
190c0b9f4feSDoug Rabson 	if (*ret_flags & GSS_C_DELEG_FLAG) {
191c0b9f4feSDoug Rabson 		if (!delegated_cred_handle) {
192c0b9f4feSDoug Rabson 			m->gm_release_cred(minor_status, &delegated_mc);
193c0b9f4feSDoug Rabson 			*ret_flags &= ~GSS_C_DELEG_FLAG;
194c0b9f4feSDoug Rabson 		} else {
195c0b9f4feSDoug Rabson 			struct _gss_cred *cred;
196c0b9f4feSDoug Rabson 			struct _gss_mechanism_cred *mc;
197c0b9f4feSDoug Rabson 
198c0b9f4feSDoug Rabson 			cred = malloc(sizeof(struct _gss_cred));
199c0b9f4feSDoug Rabson 			if (!cred) {
200c0b9f4feSDoug Rabson 				*minor_status = ENOMEM;
201c0b9f4feSDoug Rabson 				return (GSS_S_FAILURE);
202c0b9f4feSDoug Rabson 			}
203c0b9f4feSDoug Rabson 			mc = malloc(sizeof(struct _gss_mechanism_cred));
204c0b9f4feSDoug Rabson 			if (!mc) {
205c0b9f4feSDoug Rabson 				free(cred);
206c0b9f4feSDoug Rabson 				*minor_status = ENOMEM;
207c0b9f4feSDoug Rabson 				return (GSS_S_FAILURE);
208c0b9f4feSDoug Rabson 			}
209c0b9f4feSDoug Rabson 			m->gm_inquire_cred(minor_status, delegated_mc,
210c0b9f4feSDoug Rabson 			    0, 0, &cred->gc_usage, 0);
211c0b9f4feSDoug Rabson 			mc->gmc_mech = m;
212c0b9f4feSDoug Rabson 			mc->gmc_mech_oid = &m->gm_mech_oid;
213c0b9f4feSDoug Rabson 			mc->gmc_cred = delegated_mc;
214c0b9f4feSDoug Rabson 			SLIST_INSERT_HEAD(&cred->gc_mc, mc, gmc_link);
215c0b9f4feSDoug Rabson 
216c0b9f4feSDoug Rabson 			*delegated_cred_handle = (gss_cred_id_t) cred;
217c0b9f4feSDoug Rabson 		}
218c0b9f4feSDoug Rabson 	}
219c0b9f4feSDoug Rabson 
220c0b9f4feSDoug Rabson 	*context_handle = (gss_ctx_id_t) ctx;
221c0b9f4feSDoug Rabson 	return (major_status);
222c0b9f4feSDoug Rabson }
223