Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/lib/gssapi/mechglue/g_imp_name.c
39586 views
1
/* #pragma ident "@(#)g_imp_name.c 1.26 04/02/23 SMI" */
2
3
/*
4
* Copyright 1996 by Sun Microsystems, Inc.
5
*
6
* Permission to use, copy, modify, distribute, and sell this software
7
* and its documentation for any purpose is hereby granted without fee,
8
* provided that the above copyright notice appears in all copies and
9
* that both that copyright notice and this permission notice appear in
10
* supporting documentation, and that the name of Sun Microsystems not be used
11
* in advertising or publicity pertaining to distribution of the software
12
* without specific, written prior permission. Sun Microsystems makes no
13
* representations about the suitability of this software for any
14
* purpose. It is provided "as is" without express or implied warranty.
15
*
16
* SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18
* EVENT SHALL SUN MICROSYSTEMS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
20
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
21
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22
* PERFORMANCE OF THIS SOFTWARE.
23
*/
24
25
/*
26
* glue routine gss_import_name
27
*
28
*/
29
30
#include "mglueP.h"
31
#include "k5-der.h"
32
#include <stdio.h>
33
#ifdef HAVE_STDLIB_H
34
#include <stdlib.h>
35
#endif
36
#include <string.h>
37
#include <errno.h>
38
39
/* local function to import GSS_C_EXPORT_NAME names */
40
static OM_uint32 importExportName(OM_uint32 *, gss_union_name_t, gss_OID);
41
42
static OM_uint32
43
val_imp_name_args(
44
OM_uint32 *minor_status,
45
gss_buffer_t input_name_buffer,
46
gss_OID input_name_type,
47
gss_name_t *output_name)
48
{
49
50
/* Initialize outputs. */
51
52
if (minor_status != NULL)
53
*minor_status = 0;
54
55
if (output_name != NULL)
56
*output_name = GSS_C_NO_NAME;
57
58
/* Validate arguments. */
59
60
if (minor_status == NULL)
61
return (GSS_S_CALL_INACCESSIBLE_WRITE);
62
63
if (output_name == NULL)
64
return (GSS_S_CALL_INACCESSIBLE_WRITE);
65
66
if (input_name_buffer == GSS_C_NO_BUFFER)
67
return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
68
69
if (input_name_type == GSS_C_NO_OID ||
70
!g_OID_equal(input_name_type, GSS_C_NT_ANONYMOUS)) {
71
if (input_name_buffer->length == 0)
72
return (GSS_S_BAD_NAME);
73
74
if (input_name_buffer->value == NULL)
75
return (GSS_S_CALL_INACCESSIBLE_READ | GSS_S_BAD_NAME);
76
}
77
78
return (GSS_S_COMPLETE);
79
}
80
81
static gss_buffer_desc emptyNameBuffer;
82
83
OM_uint32 KRB5_CALLCONV
84
gss_import_name(OM_uint32 * minor_status, gss_buffer_t input_name_buffer,
85
gss_OID input_name_type, gss_name_t * output_name)
86
{
87
gss_union_name_t union_name;
88
OM_uint32 tmp, major_status = GSS_S_FAILURE;
89
90
if (input_name_buffer == GSS_C_NO_BUFFER)
91
input_name_buffer = &emptyNameBuffer;
92
93
major_status = val_imp_name_args(minor_status,
94
input_name_buffer, input_name_type,
95
output_name);
96
if (major_status != GSS_S_COMPLETE)
97
return (major_status);
98
99
/*
100
* First create the union name struct that will hold the external
101
* name and the name type.
102
*/
103
union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc));
104
if (!union_name)
105
return (GSS_S_FAILURE);
106
107
union_name->loopback = 0;
108
union_name->mech_type = 0;
109
union_name->mech_name = 0;
110
union_name->name_type = 0;
111
union_name->external_name = 0;
112
113
/*
114
* All we do here is record the external name and name_type.
115
* When the name is actually used, the underlying gss_import_name()
116
* is called for the appropriate mechanism. The exception to this
117
* rule is when the name of GSS_C_NT_EXPORT_NAME type. If that is
118
* the case, then we make it MN in this call.
119
*/
120
major_status = gssint_create_copy_buffer(input_name_buffer,
121
&union_name->external_name, 0);
122
if (major_status != GSS_S_COMPLETE) {
123
free(union_name);
124
return (major_status);
125
}
126
127
if (input_name_type != GSS_C_NULL_OID) {
128
major_status = generic_gss_copy_oid(minor_status,
129
input_name_type,
130
&union_name->name_type);
131
if (major_status != GSS_S_COMPLETE) {
132
map_errcode(minor_status);
133
goto allocation_failure;
134
}
135
}
136
137
/*
138
* In MIT Distribution the mechanism is determined from the nametype;
139
* This is not a good idea - first mechanism that supports a given
140
* name type is picked up; later on the caller can request a
141
* different mechanism. So we don't determine the mechanism here. Now
142
* the user level and kernel level import_name routine looks similar
143
* except the kernel routine makes a copy of the nametype structure. We
144
* do however make this an MN for names of GSS_C_NT_EXPORT_NAME type.
145
*/
146
if (input_name_type != GSS_C_NULL_OID &&
147
(g_OID_equal(input_name_type, GSS_C_NT_EXPORT_NAME) ||
148
g_OID_equal(input_name_type, GSS_C_NT_COMPOSITE_EXPORT))) {
149
major_status = importExportName(minor_status, union_name, input_name_type);
150
if (major_status != GSS_S_COMPLETE)
151
goto allocation_failure;
152
}
153
154
union_name->loopback = union_name;
155
*output_name = (gss_name_t)union_name;
156
return (GSS_S_COMPLETE);
157
158
allocation_failure:
159
if (union_name) {
160
if (union_name->external_name) {
161
if (union_name->external_name->value)
162
free(union_name->external_name->value);
163
free(union_name->external_name);
164
}
165
if (union_name->name_type)
166
generic_gss_release_oid(&tmp, &union_name->name_type);
167
if (union_name->mech_name)
168
gssint_release_internal_name(minor_status, union_name->mech_type,
169
&union_name->mech_name);
170
if (union_name->mech_type)
171
generic_gss_release_oid(&tmp, &union_name->mech_type);
172
free(union_name);
173
}
174
return (major_status);
175
}
176
177
static OM_uint32
178
importExportName(OM_uint32 *minor, gss_union_name_t unionName,
179
gss_OID inputNameType)
180
{
181
gss_OID_desc mechOid;
182
gss_buffer_desc expName;
183
gss_mechanism mech;
184
OM_uint32 major, mechOidLen, nameLen;
185
uint8_t b2;
186
const uint8_t *name;
187
struct k5input in, oid, old_format;
188
189
expName.value = unionName->external_name->value;
190
expName.length = unionName->external_name->length;
191
k5_input_init(&in, expName.value, expName.length);
192
193
if (k5_input_get_byte(&in) != 0x04)
194
return (GSS_S_DEFECTIVE_TOKEN);
195
b2 = k5_input_get_byte(&in);
196
if (b2 != 0x01 && b2 != 0x02) /* allow composite names */
197
return (GSS_S_DEFECTIVE_TOKEN);
198
199
mechOidLen = k5_input_get_uint16_be(&in);
200
201
if (!k5_der_get_value(&in, 0x06, &oid))
202
return (GSS_S_DEFECTIVE_TOKEN);
203
/* Verify that mechOidLen is consistent with the DER OID length. */
204
if (mechOidLen != k5_der_value_len(oid.len))
205
return (GSS_S_DEFECTIVE_TOKEN);
206
mechOid.length = oid.len;
207
mechOid.elements = (uint8_t *)oid.ptr;
208
if ((mech = gssint_get_mechanism(&mechOid)) == NULL)
209
return (GSS_S_BAD_MECH);
210
211
if (mech->gssspi_import_name_by_mech == NULL &&
212
mech->gss_import_name == NULL)
213
return (GSS_S_UNAVAILABLE);
214
215
/*
216
* we must now determine if we should unwrap the name ourselves
217
* or make the mechanism do it - we should only unwrap it
218
* if we create it; so if mech->gss_export_name == NULL, we must
219
* have created it.
220
*/
221
if (mech->gss_export_name) {
222
if (mech->gssspi_import_name_by_mech) {
223
major = mech->gssspi_import_name_by_mech(minor, &mechOid, &expName,
224
inputNameType,
225
&unionName->mech_name);
226
} else {
227
major = mech->gss_import_name(minor, &expName, inputNameType,
228
&unionName->mech_name);
229
}
230
if (major != GSS_S_COMPLETE)
231
map_error(minor, mech);
232
else {
233
major = generic_gss_copy_oid(minor, &mechOid,
234
&unionName->mech_type);
235
if (major != GSS_S_COMPLETE)
236
map_errcode(minor);
237
}
238
return (major);
239
}
240
/*
241
* we must have exported the name - so we now need to reconstruct it
242
* and call the mechanism to create it
243
*
244
* WARNING: Older versions of gssint_export_internal_name() did
245
* not export names correctly, but now it does. In
246
* order to stay compatible with existing exported
247
* names we must support names exported the broken
248
* way.
249
*
250
* Specifically, gssint_export_internal_name() used to include
251
* the name type OID in the encoding of the exported MN.
252
* Additionally, the Kerberos V mech used to make display names
253
* that included a null terminator which was counted in the
254
* display name gss_buffer_desc.
255
*/
256
257
/* next 4 bytes in the name are the name length */
258
nameLen = k5_input_get_uint32_be(&in);
259
name = k5_input_get_bytes(&in, nameLen);
260
if (name == NULL)
261
return (GSS_S_DEFECTIVE_TOKEN);
262
263
/*
264
* We detect broken exported names here: they always start with
265
* a two-octet network-byte order OID length, which is always
266
* less than 256 bytes, so the first octet of the length is
267
* always '\0', which is not allowed in GSS-API display names
268
* (or never occurs in them anyways). Of course, the OID
269
* shouldn't be there, but it is. After the OID (sans DER tag
270
* and length) there's the name itself, though null-terminated;
271
* this null terminator should also not be there, but it is.
272
*/
273
if (nameLen > 0 && *name == '\0') {
274
OM_uint32 nameTypeLen;
275
276
/* Skip the name type. */
277
k5_input_init(&old_format, name, nameLen);
278
nameTypeLen = k5_input_get_uint16_be(&old_format);
279
if (k5_input_get_bytes(&old_format, nameTypeLen) == NULL)
280
return (GSS_S_DEFECTIVE_TOKEN);
281
/* Remove a null terminator if one is present. */
282
if (old_format.len > 0 && old_format.ptr[old_format.len - 1] == 0)
283
old_format.len--;
284
name = old_format.ptr;
285
nameLen = old_format.len;
286
}
287
288
/*
289
* Can a name be null? Let the mech decide.
290
*
291
* NOTE: We use GSS_C_NULL_OID as the name type when importing
292
* the unwrapped name. Presumably the exported name had,
293
* prior to being exported been obtained in such a way
294
* that it has been properly perpared ("canonicalized," in
295
* GSS-API terms) according to some name type; we cannot
296
* tell what that name type was now, but the name should
297
* need no further preparation other than the lowest
298
* common denominator afforded by the mech to names
299
* imported with GSS_C_NULL_OID. For the Kerberos V mech
300
* this means doing less busywork too (particularly once
301
* IDN is thrown in with Kerberos V extensions).
302
*/
303
expName.length = nameLen;
304
expName.value = nameLen ? (uint8_t *)name : NULL;
305
if (mech->gssspi_import_name_by_mech) {
306
major = mech->gssspi_import_name_by_mech(minor, &mechOid, &expName,
307
GSS_C_NULL_OID,
308
&unionName->mech_name);
309
} else {
310
major = mech->gss_import_name(minor, &expName,
311
GSS_C_NULL_OID, &unionName->mech_name);
312
}
313
if (major != GSS_S_COMPLETE) {
314
map_error(minor, mech);
315
return (major);
316
}
317
318
major = generic_gss_copy_oid(minor, &mechOid, &unionName->mech_type);
319
if (major != GSS_S_COMPLETE) {
320
map_errcode(minor);
321
}
322
return major;
323
} /* importExportName */
324
325