1/*-
2 * Copyright (c) 2005 Doug Rabson
3 * All rights reserved.
4 *
5 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 *	$FreeBSD: src/lib/libgssapi/gss_names.c,v 1.1 2005/12/29 14:40:20 dfr Exp $
29 */
30
31#include "mech_locl.h"
32
33
34OM_uint32
35_gss_find_mn(OM_uint32 *minor_status, struct _gss_name *name, gss_const_OID mech,
36	     struct _gss_mechanism_name **output_mn)
37{
38	OM_uint32 major_status;
39	gssapi_mech_interface m;
40	struct _gss_mechanism_name *mn;
41
42	*output_mn = NULL;
43
44	/* null names are ok, some mechs might not have names */
45	if (name == NULL)
46	    return GSS_S_COMPLETE;
47
48	HEIM_SLIST_FOREACH(mn, &name->gn_mn, gmn_link) {
49		if (gss_oid_equal(mech, mn->gmn_mech_oid))
50			break;
51	}
52
53	if (!mn) {
54		/*
55		 * If this name is canonical (i.e. there is only an
56		 * MN but it is from a different mech), give up now.
57		 */
58		if (!name->gn_value.value)
59			return GSS_S_BAD_NAME;
60
61		m = __gss_get_mechanism(mech);
62		if (!m)
63			return (GSS_S_BAD_MECH);
64
65		mn = malloc(sizeof(struct _gss_mechanism_name));
66		if (!mn)
67			return GSS_S_FAILURE;
68
69		major_status = m->gm_import_name(minor_status,
70		    &name->gn_value,
71		    (name->gn_type.elements
72			? &name->gn_type : GSS_C_NO_OID),
73		    &mn->gmn_name);
74		if (major_status != GSS_S_COMPLETE) {
75			_gss_mg_error(m, *minor_status);
76			free(mn);
77			return major_status;
78		}
79
80		mn->gmn_mech = m;
81		mn->gmn_mech_oid = &m->gm_mech_oid;
82		HEIM_SLIST_INSERT_HEAD(&name->gn_mn, mn, gmn_link);
83	}
84	*output_mn = mn;
85	return 0;
86}
87
88
89/*
90 * Make a name from an MN.
91 */
92struct _gss_name *
93_gss_create_name(gss_name_t new_mn, struct gssapi_mech_interface_desc *m)
94{
95	struct _gss_name *name;
96	struct _gss_mechanism_name *mn;
97
98	name = calloc(1, sizeof(struct _gss_name));
99	if (!name)
100		return (0);
101
102	HEIM_SLIST_INIT(&name->gn_mn);
103
104	if (new_mn) {
105		mn = malloc(sizeof(struct _gss_mechanism_name));
106		if (!mn) {
107			free(name);
108			return (0);
109		}
110
111		mn->gmn_mech = m;
112		mn->gmn_mech_oid = &m->gm_mech_oid;
113		mn->gmn_name = new_mn;
114		HEIM_SLIST_INSERT_HEAD(&name->gn_mn, mn, gmn_link);
115	}
116
117	return (name);
118}
119
120/*
121 *
122 */
123
124void
125_gss_mg_release_name(struct _gss_name *name)
126{
127	OM_uint32 junk;
128
129	_gss_free_oid(&junk, &name->gn_type);
130
131	while (HEIM_SLIST_FIRST(&name->gn_mn)) {
132		struct _gss_mechanism_name *mn;
133		mn = HEIM_SLIST_FIRST(&name->gn_mn);
134		HEIM_SLIST_REMOVE_HEAD(&name->gn_mn, gmn_link);
135		mn->gmn_mech->gm_release_name(&junk, &mn->gmn_name);
136		free(mn);
137	}
138	gss_release_buffer(&junk, &name->gn_value);
139	free(name);
140}
141
142void
143_gss_mg_check_name(gss_name_t name)
144{
145	if (name == NULL) return;
146}
147
148/*
149 *
150 */
151
152OM_uint32
153_gss_mech_import_name(OM_uint32 * minor_status,
154		      gss_const_OID mech,
155		      struct _gss_name_type *names,
156		      const gss_buffer_t input_name_buffer,
157		      gss_const_OID input_name_type,
158		      gss_name_t * output_name)
159{
160    struct _gss_name_type *name;
161    gss_buffer_t name_buffer = input_name_buffer;
162    gss_buffer_desc export_name;
163
164    *minor_status = 0;
165
166    if (output_name == NULL)
167	return GSS_S_CALL_INACCESSIBLE_WRITE;
168
169    *output_name = GSS_C_NO_NAME;
170
171    /*
172     * If its a exported name, strip of the mech glue.
173     */
174
175    if (gss_oid_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) {
176	unsigned char *p;
177	uint32_t length;
178
179	if (name_buffer->length < 10 + mech->length)
180	    return GSS_S_BAD_NAME;
181
182	/* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */
183
184	p = name_buffer->value;
185
186	if (memcmp(&p[0], "\x04\x01\x00", 3) != 0 ||
187	    p[3] != mech->length + 2 ||
188	    p[4] != 0x06 ||
189	    p[5] != mech->length ||
190	    memcmp(&p[6], mech->elements, mech->length) != 0)
191	    return GSS_S_BAD_NAME;
192
193	p += 6 + mech->length;
194
195	length = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
196	p += 4;
197
198	if (length > name_buffer->length - 10 - mech->length)
199	    return GSS_S_BAD_NAME;
200
201	/*
202	 * Point this to the mech specific name part, don't modifity
203	 * orignal input_name_buffer.
204	 */
205
206	export_name.length = length;
207	export_name.value = p;
208
209	name_buffer = &export_name;
210    }
211
212    for (name = names; name->gnt_parse != NULL; name++) {
213	if (gss_oid_equal(input_name_type, name->gnt_name_type)
214	    || (name->gnt_name_type == GSS_C_NO_OID && input_name_type == GSS_C_NO_OID))
215	    return name->gnt_parse(minor_status, mech, name_buffer,
216				   input_name_type, output_name);
217    }
218
219    return GSS_S_BAD_NAMETYPE;
220}
221
222OM_uint32
223_gss_mech_inquire_names_for_mech(OM_uint32 * minor_status,
224				 struct _gss_name_type *names,
225				 gss_OID_set * name_types)
226{
227    struct _gss_name_type *name;
228    OM_uint32 ret;
229
230    ret = gss_create_empty_oid_set(minor_status, name_types);
231    if (ret != GSS_S_COMPLETE)
232	return ret;
233
234    for (name = names; name->gnt_parse != NULL; name++) {
235	if (name->gnt_name_type == GSS_C_NO_OID)
236	    continue;
237	ret = gss_add_oid_set_member(minor_status,
238				     name->gnt_name_type,
239				     name_types);
240	if (ret != GSS_S_COMPLETE)
241	    break;
242    }
243
244    if (ret != GSS_S_COMPLETE)
245	gss_release_oid_set(NULL, name_types);
246
247    return GSS_S_COMPLETE;
248}
249