xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/gssapi/mech/gss_import_name.c (revision afab4e300d3a9fb07dd8c80daf53d0feb3345706)
1 /*	$NetBSD: gss_import_name.c,v 1.3 2023/06/19 21:41:43 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 2005 Doug Rabson
5  * 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_import_name.c,v 1.1 2005/12/29 14:40:20 dfr Exp $
29  */
30 
31 #include "mech_locl.h"
32 
33 static OM_uint32
_gss_import_export_name(OM_uint32 * minor_status,const gss_buffer_t input_name_buffer,gss_name_t * output_name)34 _gss_import_export_name(OM_uint32 *minor_status,
35     const gss_buffer_t input_name_buffer,
36     gss_name_t *output_name)
37 {
38 	OM_uint32 major_status;
39 	unsigned char *p = input_name_buffer->value;
40 	size_t len = input_name_buffer->length;
41 	size_t t;
42 	gss_OID_desc mech_oid;
43 	gssapi_mech_interface m;
44 	struct _gss_name *name;
45 	gss_name_t new_canonical_name;
46 	int composite = 0;
47 
48 	*minor_status = 0;
49 	*output_name = 0;
50 
51 	/*
52 	 * Make sure that TOK_ID is {4, 1}.
53 	 */
54 	if (len < 2)
55 		return (GSS_S_BAD_NAME);
56 	if (p[0] != 4)
57 		return (GSS_S_BAD_NAME);
58 	switch (p[1]) {
59 	case 1:	/* non-composite name */
60 		break;
61 	case 2:	/* composite name */
62 		composite = 1;
63 		break;
64 	default:
65 		return (GSS_S_BAD_NAME);
66 	}
67 	p += 2;
68 	len -= 2;
69 
70 	/*
71 	 * Get the mech length and the name length and sanity
72 	 * check the size of of the buffer.
73 	 */
74 	if (len < 2)
75 		return (GSS_S_BAD_NAME);
76 	t = (p[0] << 8) + p[1];
77 	p += 2;
78 	len -= 2;
79 
80 	/*
81 	 * Check the DER encoded OID to make sure it agrees with the
82 	 * length we just decoded.
83 	 */
84 	if (p[0] != 6)		/* 6=OID */
85 		return (GSS_S_BAD_NAME);
86 	p++;
87 	len--;
88 	t--;
89 	if (p[0] & 0x80) {
90 		int digits = p[0];
91 		p++;
92 		len--;
93 		t--;
94 		mech_oid.length = 0;
95 		while (digits--) {
96 			mech_oid.length = (mech_oid.length << 8) | p[0];
97 			p++;
98 			len--;
99 			t--;
100 		}
101 	} else {
102 		mech_oid.length = p[0];
103 		p++;
104 		len--;
105 		t--;
106 	}
107 	if (mech_oid.length != t)
108 		return (GSS_S_BAD_NAME);
109 
110 	mech_oid.elements = p;
111 
112 	if (len < t + 4)
113 		return (GSS_S_BAD_NAME);
114 	p += t;
115 	len -= t;
116 
117 	t = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
118 	/* p += 4; */
119 	len -= 4;
120 
121 	if (!composite && len != t)
122 		return (GSS_S_BAD_NAME);
123 
124 	m = __gss_get_mechanism(&mech_oid);
125 	if (!m)
126 		return (GSS_S_BAD_MECH);
127 
128 	/*
129 	 * Ask the mechanism to import the name.
130 	 */
131 	major_status = m->gm_import_name(minor_status,
132 	    input_name_buffer, GSS_C_NT_EXPORT_NAME, &new_canonical_name);
133 	if (major_status != GSS_S_COMPLETE) {
134 		_gss_mg_error(m, major_status, *minor_status);
135 		return major_status;
136 	}
137 
138 	/*
139 	 * Now we make a new name and mark it as an MN.
140 	 */
141 	name = _gss_make_name(m, new_canonical_name);
142 	if (!name) {
143 		m->gm_release_name(minor_status, &new_canonical_name);
144 		return (GSS_S_FAILURE);
145 	}
146 
147 	*output_name = (gss_name_t) name;
148 
149 	*minor_status = 0;
150 	return (GSS_S_COMPLETE);
151 }
152 
153 /**
154  * Convert a GGS-API name from contiguous string to internal form.
155  *
156  * Type of name and their format:
157  * - GSS_C_NO_OID
158  * - GSS_C_NT_USER_NAME
159  * - GSS_C_NT_HOSTBASED_SERVICE
160  * - GSS_C_NT_EXPORT_NAME
161  * - GSS_C_NT_ANONYMOUS
162  * - GSS_KRB5_NT_PRINCIPAL_NAME
163  *
164  * @sa gss_export_name(), @ref internalVSmechname.
165  *
166  * @param minor_status       minor status code
167  * @param input_name_buffer  import name buffer
168  * @param input_name_type    type of the import name buffer
169  * @param output_name        the resulting type, release with
170  *        gss_release_name(), independent of input_name
171  *
172  * @returns a gss_error code, see gss_display_status() about printing
173  *        the error code.
174  *
175  * @ingroup gssapi
176  */
177 
178 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gss_import_name(OM_uint32 * minor_status,const gss_buffer_t input_name_buffer,const gss_OID input_name_type,gss_name_t * output_name)179 gss_import_name(OM_uint32 *minor_status,
180     const gss_buffer_t input_name_buffer,
181     const gss_OID input_name_type,
182     gss_name_t *output_name)
183 {
184         struct _gss_mechanism_name *mn;
185 	gss_OID			name_type = input_name_type;
186 	OM_uint32		major_status, ms;
187 	struct _gss_name	*name;
188         struct _gss_mech_switch	*m;
189 	gss_name_t		rname;
190 
191 	*output_name = GSS_C_NO_NAME;
192 
193 	if (input_name_buffer->length == 0) {
194 		*minor_status = 0;
195 		return (GSS_S_BAD_NAME);
196 	}
197 
198 	_gss_load_mech();
199 
200 	/*
201 	 * Use GSS_NT_USER_NAME as default name type.
202 	 */
203 	if (name_type == GSS_C_NO_OID)
204 		name_type = GSS_C_NT_USER_NAME;
205 
206 	/*
207 	 * If this is an exported name, we need to parse it to find
208 	 * the mechanism and then import it as an MN. See RFC 2743
209 	 * section 3.2 for a description of the format.
210 	 */
211 	if (gss_oid_equal(name_type, GSS_C_NT_EXPORT_NAME)) {
212 		return _gss_import_export_name(minor_status,
213 		    input_name_buffer, output_name);
214 	}
215 
216 
217 	*minor_status = 0;
218 	name = calloc(1, sizeof(struct _gss_name));
219 	if (!name) {
220 		*minor_status = ENOMEM;
221 		return (GSS_S_FAILURE);
222 	}
223 
224 	HEIM_SLIST_INIT(&name->gn_mn);
225 
226 	major_status = _gss_copy_oid(minor_status,
227 	    name_type, &name->gn_type);
228 	if (major_status) {
229 		free(name);
230 		return (GSS_S_FAILURE);
231 	}
232 
233 	major_status = _gss_copy_buffer(minor_status,
234 	    input_name_buffer, &name->gn_value);
235 	if (major_status)
236 		goto out;
237 
238 	/*
239 	 * Walk over the mechs and import the name into a mech name
240 	 * for those supported this nametype.
241 	 */
242 
243 	HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) {
244 		int present = 0;
245 
246 		major_status = gss_test_oid_set_member(minor_status,
247 		    name_type, m->gm_name_types, &present);
248 
249 		if (major_status || present == 0)
250 			continue;
251 
252 		mn = malloc(sizeof(struct _gss_mechanism_name));
253 		if (!mn) {
254 			*minor_status = ENOMEM;
255 			major_status = GSS_S_FAILURE;
256 			goto out;
257 		}
258 
259 		major_status = (*m->gm_mech.gm_import_name)(minor_status,
260 		    &name->gn_value,
261 		    (name->gn_type.elements
262 			? &name->gn_type : GSS_C_NO_OID),
263 		    &mn->gmn_name);
264 		if (major_status != GSS_S_COMPLETE) {
265 			_gss_mg_error(&m->gm_mech, major_status, *minor_status);
266 			free(mn);
267 			goto out;
268 		}
269 
270 		mn->gmn_mech = &m->gm_mech;
271 		mn->gmn_mech_oid = &m->gm_mech_oid;
272 		HEIM_SLIST_INSERT_HEAD(&name->gn_mn, mn, gmn_link);
273 	}
274 
275 	/*
276 	 * If we can't find a mn for the name, bail out already here.
277 	 */
278 
279 	mn = HEIM_SLIST_FIRST(&name->gn_mn);
280 	if (!mn) {
281 		*minor_status = 0;
282 		major_status = GSS_S_NAME_NOT_MN;
283 		goto out;
284 	}
285 
286 	*output_name = (gss_name_t) name;
287 	return (GSS_S_COMPLETE);
288 
289  out:
290 	rname = (gss_name_t)name;
291 	gss_release_name(&ms, &rname);
292 	return major_status;
293 }
294