Line data Source code
1 : /*-
2 : * Copyright (c) 2005 Doug Rabson
3 : * All rights reserved.
4 : *
5 : * Redistribution and use in source and binary forms, with or without
6 : * modification, are permitted provided that the following conditions
7 : * are met:
8 : * 1. Redistributions of source code must retain the above copyright
9 : * notice, this list of conditions and the following disclaimer.
10 : * 2. Redistributions in binary form must reproduce the above copyright
11 : * notice, this list of conditions and the following disclaimer in the
12 : * documentation and/or other materials provided with the distribution.
13 : *
14 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 : * SUCH DAMAGE.
25 : *
26 : * $FreeBSD: src/lib/libgssapi/gss_import_name.c,v 1.1 2005/12/29 14:40:20 dfr Exp $
27 : */
28 :
29 : #include "mech_locl.h"
30 :
31 : static OM_uint32
32 0 : _gss_import_export_name(OM_uint32 *minor_status,
33 : const gss_buffer_t input_name_buffer,
34 : const gss_OID name_type,
35 : gss_name_t *output_name)
36 : {
37 0 : OM_uint32 major_status;
38 0 : unsigned char *p = input_name_buffer->value;
39 0 : size_t len = input_name_buffer->length;
40 0 : size_t t;
41 0 : gss_OID_desc mech_oid;
42 0 : gssapi_mech_interface m;
43 0 : struct _gss_name *name;
44 0 : gss_name_t new_canonical_name;
45 0 : int composite = 0;
46 :
47 0 : *minor_status = 0;
48 0 : *output_name = 0;
49 :
50 : /*
51 : * Make sure that TOK_ID is {4, 1}.
52 : */
53 0 : if (len < 2)
54 0 : return (GSS_S_BAD_NAME);
55 0 : if (p[0] != 4)
56 0 : return (GSS_S_BAD_NAME);
57 0 : switch (p[1]) {
58 0 : case 1: /* non-composite name */
59 0 : break;
60 0 : case 2: /* composite name */
61 0 : composite = 1;
62 0 : break;
63 0 : default:
64 0 : return (GSS_S_BAD_NAME);
65 : }
66 0 : p += 2;
67 0 : len -= 2;
68 :
69 : /*
70 : * If the name token is a composite token (TOK_ID 0x04 0x02) then per
71 : * RFC6680 everything after that is implementation-specific. This
72 : * mech-glue is pluggable however, so we need the format of the rest of
73 : * the header to be stable, otherwise we couldn't reliably determine
74 : * what mechanism the token is for and we'd have to try all of them.
75 : *
76 : * So... we keep the same format for the exported composite name token
77 : * as for normal exported name tokens (see RFC2743, section 3.2), with
78 : * the TOK_ID 0x04 0x02, but only up to the mechanism OID. We don't
79 : * enforce that there be a NAME_LEN in the exported composite name
80 : * token, or that it match the length of the remainder of the token.
81 : *
82 : * FYI, at least one out-of-tree mechanism implements exported
83 : * composite name tokens as the same as exported name tokens with
84 : * attributes appended and the NAME_LEN not modified to match.
85 : */
86 :
87 : /*
88 : * Get the mech length and the name length and sanity
89 : * check the size of of the buffer.
90 : */
91 0 : if (len < 2)
92 0 : return (GSS_S_BAD_NAME);
93 0 : t = (p[0] << 8) + p[1];
94 0 : p += 2;
95 0 : len -= 2;
96 :
97 : /*
98 : * Check the DER encoded OID to make sure it agrees with the
99 : * length we just decoded.
100 : */
101 0 : if (p[0] != 6) /* 6=OID */
102 0 : return (GSS_S_BAD_NAME);
103 0 : p++;
104 0 : len--;
105 0 : t--;
106 0 : if (p[0] & 0x80) {
107 0 : int digits = p[0];
108 0 : p++;
109 0 : len--;
110 0 : t--;
111 0 : mech_oid.length = 0;
112 0 : while (digits--) {
113 0 : mech_oid.length = (mech_oid.length << 8) | p[0];
114 0 : p++;
115 0 : len--;
116 0 : t--;
117 : }
118 : } else {
119 0 : mech_oid.length = p[0];
120 0 : p++;
121 0 : len--;
122 0 : t--;
123 : }
124 0 : if (mech_oid.length != t)
125 0 : return (GSS_S_BAD_NAME);
126 :
127 0 : mech_oid.elements = p;
128 :
129 0 : if (!composite) {
130 0 : if (len < t + 4)
131 0 : return (GSS_S_BAD_NAME);
132 0 : p += t;
133 0 : len -= t;
134 :
135 0 : t = ((unsigned long)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
136 : /* p += 4; // we're done using `p' now */
137 0 : len -= 4;
138 :
139 0 : if (len != t)
140 0 : return (GSS_S_BAD_NAME);
141 : }
142 :
143 0 : m = __gss_get_mechanism(&mech_oid);
144 0 : if (!m || !m->gm_import_name)
145 0 : return (GSS_S_BAD_MECH);
146 :
147 : /*
148 : * Ask the mechanism to import the name.
149 : */
150 0 : major_status = m->gm_import_name(minor_status,
151 : input_name_buffer, name_type, &new_canonical_name);
152 0 : if (major_status != GSS_S_COMPLETE) {
153 0 : _gss_mg_error(m, *minor_status);
154 0 : return major_status;
155 : }
156 :
157 : /*
158 : * Now we make a new name and mark it as an MN.
159 : */
160 0 : name = _gss_create_name(new_canonical_name, m);
161 0 : if (!name) {
162 0 : m->gm_release_name(minor_status, &new_canonical_name);
163 0 : return (GSS_S_FAILURE);
164 : }
165 :
166 0 : *output_name = (gss_name_t) name;
167 :
168 0 : *minor_status = 0;
169 0 : return (GSS_S_COMPLETE);
170 : }
171 :
172 : /**
173 : * Convert a GGS-API name from contiguous string to internal form.
174 : *
175 : * Type of name and their format:
176 : * - GSS_C_NO_OID
177 : * - GSS_C_NT_USER_NAME
178 : * - GSS_C_NT_HOSTBASED_SERVICE
179 : * - GSS_C_NT_EXPORT_NAME
180 : * - GSS_C_NT_COMPOSITE_EXPORT
181 : * - GSS_C_NT_ANONYMOUS
182 : * - GSS_KRB5_NT_PRINCIPAL_NAME
183 : *
184 : * @sa gss_export_name(), @ref internalVSmechname.
185 : *
186 : * @param minor_status minor status code
187 : * @param input_name_buffer import name buffer
188 : * @param input_name_type type of the import name buffer
189 : * @param output_name the resulting type, release with
190 : * gss_release_name(), independent of input_name
191 : *
192 : * @returns a gss_error code, see gss_display_status() about printing
193 : * the error code.
194 : *
195 : * @ingroup gssapi
196 : */
197 :
198 : GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
199 24237 : gss_import_name(OM_uint32 *minor_status,
200 : const gss_buffer_t input_name_buffer,
201 : const gss_OID input_name_type,
202 : gss_name_t *output_name)
203 : {
204 1035 : struct _gss_mechanism_name *mn;
205 24237 : gss_OID name_type = input_name_type;
206 1035 : OM_uint32 major_status, ms;
207 1035 : struct _gss_name *name;
208 1035 : struct _gss_mech_switch *m;
209 1035 : gss_name_t rname;
210 :
211 24237 : if (input_name_buffer == GSS_C_NO_BUFFER)
212 0 : return GSS_S_CALL_INACCESSIBLE_READ;
213 24237 : if (output_name == NULL)
214 0 : return GSS_S_CALL_INACCESSIBLE_WRITE;
215 :
216 24237 : *output_name = GSS_C_NO_NAME;
217 :
218 : /* Allow empty names since that's valid (ANONYMOUS for example) */
219 :
220 24237 : _gss_load_mech();
221 :
222 : /*
223 : * If this is an exported name, we need to parse it to find
224 : * the mechanism and then import it as an MN. See RFC 2743
225 : * section 3.2 for a description of the format.
226 : */
227 48474 : if (gss_oid_equal(name_type, GSS_C_NT_EXPORT_NAME) ||
228 24237 : gss_oid_equal(name_type, GSS_C_NT_COMPOSITE_EXPORT)) {
229 0 : return _gss_import_export_name(minor_status, input_name_buffer,
230 : name_type, output_name);
231 : }
232 :
233 :
234 24237 : *minor_status = 0;
235 24237 : name = _gss_create_name(NULL, NULL);
236 24237 : if (!name) {
237 0 : *minor_status = ENOMEM;
238 0 : return (GSS_S_FAILURE);
239 : }
240 :
241 24237 : if (name_type != GSS_C_NO_OID) {
242 24116 : major_status = _gss_intern_oid(minor_status,
243 : name_type, &name->gn_type);
244 24116 : if (major_status) {
245 0 : rname = (gss_name_t)name;
246 0 : gss_release_name(&ms, (gss_name_t *)&rname);
247 0 : return (GSS_S_FAILURE);
248 : }
249 : } else
250 121 : name->gn_type = GSS_C_NO_OID;
251 :
252 25272 : major_status = _gss_copy_buffer(minor_status,
253 24237 : input_name_buffer, &name->gn_value);
254 24237 : if (major_status)
255 0 : goto out;
256 :
257 : /*
258 : * Walk over the mechs and import the name into a mech name
259 : * for those supported this nametype.
260 : */
261 :
262 72711 : HEIM_TAILQ_FOREACH(m, &_gss_mechs, gm_link) {
263 48474 : int present = 0;
264 :
265 48474 : if ((m->gm_mech.gm_flags & GM_USE_MG_NAME))
266 24237 : continue;
267 :
268 24237 : if (name_type != GSS_C_NO_OID) {
269 24116 : major_status = gss_test_oid_set_member(minor_status,
270 : name_type, m->gm_name_types, &present);
271 :
272 24116 : if (GSS_ERROR(major_status) || present == 0)
273 0 : continue;
274 : }
275 :
276 24237 : mn = malloc(sizeof(struct _gss_mechanism_name));
277 24237 : if (!mn) {
278 0 : *minor_status = ENOMEM;
279 0 : major_status = GSS_S_FAILURE;
280 0 : goto out;
281 : }
282 :
283 24237 : major_status = (*m->gm_mech.gm_import_name)(minor_status,
284 23202 : &name->gn_value,
285 : name->gn_type,
286 : &mn->gmn_name);
287 24237 : if (major_status != GSS_S_COMPLETE) {
288 0 : _gss_mg_error(&m->gm_mech, *minor_status);
289 0 : free(mn);
290 : /**
291 : * If we failed to import the name in a mechanism, it
292 : * will be ignored as long as its possible to import
293 : * name in some other mechanism. We will catch the
294 : * failure later though in gss_init_sec_context() or
295 : * another function.
296 : */
297 0 : continue;
298 : }
299 :
300 24237 : mn->gmn_mech = &m->gm_mech;
301 24237 : mn->gmn_mech_oid = m->gm_mech_oid;
302 24237 : HEIM_TAILQ_INSERT_TAIL(&name->gn_mn, mn, gmn_link);
303 : }
304 :
305 : /*
306 : * If we can't find a mn for the name, bail out already here.
307 : */
308 :
309 24237 : mn = HEIM_TAILQ_FIRST(&name->gn_mn);
310 24237 : if (!mn) {
311 0 : *minor_status = 0;
312 0 : major_status = GSS_S_NAME_NOT_MN;
313 0 : goto out;
314 : }
315 :
316 24237 : *output_name = (gss_name_t) name;
317 24237 : return (GSS_S_COMPLETE);
318 :
319 0 : out:
320 0 : rname = (gss_name_t)name;
321 0 : gss_release_name(&ms, &rname);
322 0 : return major_status;
323 : }
|