1 /*
2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 #pragma ident "@(#)g_imp_name.c 1.27 04/09/08 SMI"
7
8 /*
9 * glue routine gss_import_name
10 *
11 */
12
13 #include <mechglueP.h>
14 #include <stdio.h>
15 #ifdef HAVE_STDLIB_H
16 #include <stdlib.h>
17 #endif
18 #include <string.h>
19 #include <errno.h>
20
21 extern int
22 get_der_length(unsigned char **, unsigned int, unsigned int *);
23
24 /* local function to import GSS_C_EXPORT_NAME names */
25 static OM_uint32 importExportName(OM_uint32 *, gss_union_name_t);
26
27
28 OM_uint32
29 gss_import_name(minor_status,
30 input_name_buffer,
31 input_name_type,
32 output_name)
33
34 OM_uint32 *minor_status;
35 const gss_buffer_t input_name_buffer;
36 const gss_OID input_name_type;
37 gss_name_t *output_name;
38 {
39 gss_union_name_t union_name;
40 OM_uint32 major_status = GSS_S_FAILURE, tmp;
41 gss_OID mech;
42
43 gss_initialize();
44
45 if (minor_status)
46 *minor_status = 0;
47
48 /* if output_name is NULL, simply return */
49
50 if (output_name == NULL)
51 return (GSS_S_COMPLETE);
52
53 *output_name = 0;
54
55 /*
56 * First create the union name struct that will hold the external
57 * name and the name type.
58 */
59
60 union_name = (gss_union_name_t)malloc(sizeof (gss_union_name_desc));
61 if (!union_name) {
62 *minor_status = ENOMEM;
63 goto allocation_failure;
64 }
65 union_name->mech_type = 0;
66 union_name->mech_name = 0;
67 union_name->name_type = 0;
68 union_name->external_name = 0;
69
70 /*
71 * All we do here is record the external name and name_type.
72 * When the name is actually used, the underlying gss_import_name()
73 * is called for the appropriate mechanism. Note that the name type
74 * is assumed to be constant, so only a pointer to it is stored in
75 * union_name
76 */
77 union_name->external_name =
78 (gss_buffer_t) malloc(sizeof(gss_buffer_desc));
79 if (!union_name->external_name) {
80 *minor_status = ENOMEM;
81 goto allocation_failure;
82 }
83
84 union_name->external_name->length = input_name_buffer->length;
85 /* we malloc length+1 to stick a NULL on the end, just in case */
86 /* Note that this NULL is not included in ->length for a reason! */
87 union_name->external_name->value =
88 (void *) malloc(input_name_buffer->length+1);
89 if (!union_name->external_name->value) {
90 *minor_status = ENOMEM;
91 goto allocation_failure;
92 }
93
94 memcpy(union_name->external_name->value, input_name_buffer->value,
95 input_name_buffer->length);
96
97 /* add NULL to end of external_name->value, just in case... */
98 ((char *)union_name->external_name->value)
99 [input_name_buffer->length] = '\0';
100
101 major_status = generic_gss_copy_oid(minor_status, input_name_type,
102 &union_name->name_type);
103 if (major_status != GSS_S_COMPLETE)
104 goto allocation_failure;
105
106 /*
107 * See if this is a mechanism-specific name. If so, let's import
108 * it now so we can get any error messages, and to avoid trouble
109 * later...
110 */
111 mech = gss_find_mechanism_from_name_type(input_name_type);
112 if (mech) {
113 major_status = generic_gss_copy_oid(minor_status, mech,
114 &union_name->mech_type);
115 if (major_status != GSS_S_COMPLETE)
116 goto allocation_failure;
117
118 major_status = __gss_import_internal_name(minor_status, mech,
119 union_name,
120 &union_name->mech_name);
121 if (major_status)
122 goto allocation_failure;
123 }
124
125 *output_name = (gss_name_t) union_name;
126
127 return(GSS_S_COMPLETE);
128
129 allocation_failure:
130 if (union_name) {
131 if (union_name->external_name) {
132 if (union_name->external_name->value)
133 free(union_name->external_name->value);
134 free(union_name->external_name);
135 }
136 if (union_name->name_type)
137 (void) generic_gss_release_oid(&tmp,
138 &union_name->name_type);
139 if (union_name->mech_name)
140 (void) __gss_release_internal_name(minor_status,
141 union_name->mech_type,
142 &union_name->mech_name);
143 if (union_name->mech_type)
144 (void) generic_gss_release_oid(&tmp,
145 &union_name->mech_type);
146 free(union_name);
147 }
148 return (major_status);
149 }
150
|
1 /*
2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 #pragma ident "@(#)g_imp_name.c 1.26 04/02/23 SMI"
7
8 /*
9 * glue routine gss_import_name
10 *
11 */
12
13 #include <mechglueP.h>
14 #include <stdio.h>
15 #ifdef HAVE_STDLIB_H
16 #include <stdlib.h>
17 #endif
18 #include <string.h>
19 #include <errno.h>
20
21 extern int
22 get_der_length(unsigned char **, unsigned int, unsigned int *);
23
24 /* local function to import GSS_C_EXPORT_NAME names */
25 static OM_uint32 importExportName(OM_uint32 *, gss_union_name_t);
26
27
28 OM_uint32
29 gss_import_name(minor_status,
30 input_name_buffer,
31 input_name_type,
32 output_name)
33
34 OM_uint32 *minor_status;
35 const gss_buffer_t input_name_buffer;
36 const gss_OID input_name_type;
37 gss_name_t *output_name;
38 {
39 gss_union_name_t union_name;
40 OM_uint32 major_status = GSS_S_FAILURE, tmp;
41
42 /* check output parameters */
43 if (!minor_status)
44 return (GSS_S_CALL_INACCESSIBLE_WRITE);
45
46 *minor_status = 0;
47
48 if (GSS_EMPTY_BUFFER(input_name_buffer))
49 return (GSS_S_CALL_INACCESSIBLE_READ);
50
51 if (output_name == NULL)
52 return (GSS_S_CALL_INACCESSIBLE_WRITE);
53
54 *output_name = 0;
55
56 /*
57 * First create the union name struct that will hold the external
58 * name and the name type.
59 */
60 union_name = (gss_union_name_t)malloc(sizeof (gss_union_name_desc));
61 if (!union_name)
62 return (GSS_S_FAILURE);
63
64 union_name->mech_type = 0;
65 union_name->mech_name = 0;
66 union_name->name_type = 0;
67 union_name->external_name = 0;
68
69 /*
70 * All we do here is record the external name and name_type.
71 * When the name is actually used, the underlying gss_import_name()
72 * is called for the appropriate mechanism. The exception to this
73 * rule is when the name of GSS_C_NT_EXPORT_NAME type. If that is
74 * the case, then we make it MN in this call.
75 */
76 major_status = __gss_create_copy_buffer(input_name_buffer,
77 &union_name->external_name, 0);
78 if (major_status != GSS_S_COMPLETE) {
79 free(union_name);
80 return (major_status);
81 }
82
83 if (input_name_type != GSS_C_NULL_OID) {
84 major_status = generic_gss_copy_oid(minor_status,
85 input_name_type,
86 &union_name->name_type);
87 if (major_status != GSS_S_COMPLETE)
88 goto allocation_failure;
89 }
90
91 /*
92 * In MIT Distribution the mechanism is determined from the nametype;
93 * This is not a good idea - first mechanism that supports a given
94 * name type is picked up; later on the caller can request a
95 * different mechanism. So we don't determine the mechanism here. Now
96 * the user level and kernel level import_name routine looks similar
97 * except the kernel routine makes a copy of the nametype structure. We
98 * do however make this an MN for names of GSS_C_NT_EXPORT_NAME type.
99 */
100 if (input_name_type != GSS_C_NULL_OID &&
101 g_OID_equal(input_name_type, GSS_C_NT_EXPORT_NAME)) {
102 major_status = importExportName(minor_status, union_name);
103 if (major_status != GSS_S_COMPLETE)
104 goto allocation_failure;
105 }
106
107 *output_name = (gss_name_t)union_name;
108 return (GSS_S_COMPLETE);
109
110 allocation_failure:
111 if (union_name) {
112 if (union_name->external_name) {
113 if (union_name->external_name->value)
114 free(union_name->external_name->value);
115 free(union_name->external_name);
116 }
117 if (union_name->name_type)
118 (void) generic_gss_release_oid(&tmp,
119 &union_name->name_type);
120 if (union_name->mech_name)
121 (void) __gss_release_internal_name(minor_status,
122 union_name->mech_type,
123 &union_name->mech_name);
124 if (union_name->mech_type)
125 (void) generic_gss_release_oid(&tmp,
126 &union_name->mech_type);
127 free(union_name);
128 }
129 return (major_status);
130 }
131
132
133 /*
134 * GSS export name constants
135 */
136 static const char *expNameTokId = "\x04\x01";
137 static const int expNameTokIdLen = 2;
138 static const int mechOidLenLen = 2;
139 static const int nameTypeLenLen = 2;
140
141 static OM_uint32
142 importExportName(minor, unionName)
143 OM_uint32 *minor;
144 gss_union_name_t unionName;
145 {
146 gss_OID_desc mechOid;
147 gss_buffer_desc expName;
148 unsigned char *buf;
149 gss_mechanism mech;
150 OM_uint32 major, mechOidLen, nameLen, curLength;
151 unsigned int bytes;
152
153 expName.value = unionName->external_name->value;
154 expName.length = unionName->external_name->length;
155
156 curLength = expNameTokIdLen + mechOidLenLen;
157 if (expName.length < curLength)
158 return (GSS_S_DEFECTIVE_TOKEN);
159
160 buf = (unsigned char *)expName.value;
161 if (memcmp(expNameTokId, buf, expNameTokIdLen) != 0)
162 return (GSS_S_DEFECTIVE_TOKEN);
163
164 buf += expNameTokIdLen;
165
166 /* extract the mechanism oid length */
167 mechOidLen = (*buf++ << 8);
168 mechOidLen |= (*buf++);
169 curLength += mechOidLen;
170 if (expName.length < curLength)
171 return (GSS_S_DEFECTIVE_TOKEN);
172 /*
173 * The mechOid itself is encoded in DER format, OID Tag (0x06)
174 * length and the value of mech_OID
175 */
176 if (*buf++ != 0x06)
177 return (GSS_S_DEFECTIVE_TOKEN);
178
179 /*
180 * mechoid Length is encoded twice; once in 2 bytes as
181 * explained in RFC2743 (under mechanism independent exported
182 * name object format) and once using DER encoding
183 *
184 * We verify both lengths.
185 */
186
187 mechOid.length = get_der_length(&buf,
188 (expName.length - curLength), &bytes);
189 mechOid.elements = (void *)buf;
190
191 /*
192 * 'bytes' is the length of the DER length, '1' is for the DER
193 * tag for OID
194 */
195 if ((bytes + mechOid.length + 1) != mechOidLen)
196 return (GSS_S_DEFECTIVE_TOKEN);
197
198 buf += mechOid.length;
199 if ((mech = __gss_get_mechanism(&mechOid)) == NULL)
200 return (GSS_S_BAD_MECH);
201
202 if (mech->gss_import_name == NULL)
203 return (GSS_S_UNAVAILABLE);
204
205 /*
206 * we must now determine if we should unwrap the name ourselves
207 * or make the mechanism do it - we should only unwrap it
208 * if we create it; so if mech->gss_export_name == NULL, we must
209 * have created it.
210 */
211 if (mech->gss_export_name) {
212 if ((major = mech->gss_import_name(mech->context, minor,
213 &expName, (gss_OID)GSS_C_NT_EXPORT_NAME,
214 &unionName->mech_name)) != GSS_S_COMPLETE ||
215 (major = generic_gss_copy_oid(minor, &mechOid,
216 &unionName->mech_type)) !=
217 GSS_S_COMPLETE) {
218 return (major);
219 }
220 return (major);
221 }
222 /*
223 * we must have exported the name - so we now need to reconstruct it
224 * and call the mechanism to create it
225 *
226 * WARNING: Older versions of __gss_export_internal_name() did
227 * not export names correctly, but now it does. In
228 * order to stay compatible with existing exported
229 * names we must support names exported the broken
230 * way.
231 *
232 * Specifically, __gss_export_internal_name() used to include
233 * the name type OID in the encoding of the exported MN.
234 * Additionally, the Kerberos V mech used to make display names
235 * that included a null terminator which was counted in the
236 * display name gss_buffer_desc.
237 */
238 curLength += 4; /* 4 bytes for name len */
239 if (expName.length < curLength)
240 return (GSS_S_DEFECTIVE_TOKEN);
241
242 /* next 4 bytes in the name are the name length */
243 nameLen = (*buf++) << 24;
244 nameLen |= (*buf++ << 16);
245 nameLen |= (*buf++ << 8);
246 nameLen |= (*buf++);
247
248 /*
249 * we use < here because bad code in rpcsec_gss rounds up exported
250 * name token lengths and pads with nulls, otherwise != would be
251 * appropriate
252 */
253 curLength += nameLen; /* this is the total length */
254 if (expName.length < curLength)
255 return (GSS_S_DEFECTIVE_TOKEN);
256
257 /*
258 * We detect broken exported names here: they always start with
259 * a two-octet network-byte order OID length, which is always
260 * less than 256 bytes, so the first octet of the length is
261 * always '\0', which is not allowed in GSS-API display names
262 * (or never occurs in them anyways). Of course, the OID
263 * shouldn't be there, but it is. After the OID (sans DER tag
264 * and length) there's the name itself, though null-terminated;
265 * this null terminator should also not be there, but it is.
266 */
267 if (nameLen > 0 && *buf == '\0') {
268 OM_uint32 nameTypeLen;
269 /* next two bytes are the name oid */
270 if (nameLen < nameTypeLenLen)
271 return (GSS_S_DEFECTIVE_TOKEN);
272
273 nameLen -= nameTypeLenLen;
274
275 nameTypeLen = (*buf++) << 8;
276 nameTypeLen |= (*buf++);
277
278 if (nameLen < nameTypeLen)
279 return (GSS_S_DEFECTIVE_TOKEN);
280
281 buf += nameTypeLen;
282 nameLen -= nameTypeLen;
283
284 /*
285 * adjust for expected null terminator that should
286 * really not be there
287 */
288 if (nameLen > 0 && *(buf + nameLen - 1) == '\0')
289 nameLen--;
290 }
291
292 /*
293 * Can a name be null? Let the mech decide.
294 *
295 * NOTE: We use GSS_C_NULL_OID as the name type when importing
296 * the unwrapped name. Presumably the exported name had,
297 * prior to being exported been obtained in such a way
298 * that it has been properly perpared ("canonicalized," in
299 * GSS-API terms) accroding to some name type; we cannot
300 * tell what that name type was now, but the name should
301 * need no further preparation other than the lowest
302 * common denominator afforded by the mech to names
303 * imported with GSS_C_NULL_OID. For the Kerberos V mech
304 * this means doing less busywork too (particularly once
305 * IDN is thrown in with Kerberos V extensions).
306 */
307 expName.length = nameLen;
308 expName.value = nameLen ? (void *)buf : NULL;
309 major = mech->gss_import_name(mech->context, minor, &expName,
310 GSS_C_NULL_OID, &unionName->mech_name);
311 if (major != GSS_S_COMPLETE)
312 return (major);
313
314 return (generic_gss_copy_oid(minor, &mechOid, &unionName->mech_type));
315 } /* importExportName */
|