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_glue.c
39586 views
1
/* #pragma ident "@(#)g_glue.c 1.25 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
#include "mglueP.h"
26
#include "k5-der.h"
27
#include <stdio.h>
28
#ifdef HAVE_STDLIB_H
29
#include <stdlib.h>
30
#endif
31
#include <string.h>
32
#include <errno.h>
33
34
#define MSO_BIT (8*(sizeof (int) - 1)) /* Most significant octet bit */
35
36
extern gss_mechanism *gssint_mechs_array;
37
38
/*
39
* This file contains the support routines for the glue layer.
40
*/
41
42
/*
43
* The following mechanisms do not always identify themselves
44
* per the GSS-API specification, when interoperating with MS
45
* peers. We include the OIDs here so we do not have to ilnk
46
* with the mechanism.
47
*/
48
static gss_OID_desc gss_ntlm_mechanism_oid_desc =
49
{10, (void *)"\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"};
50
static gss_OID_desc gss_spnego_mechanism_oid_desc =
51
{6, (void *)"\x2b\x06\x01\x05\x05\x02"};
52
static gss_OID_desc gss_krb5_mechanism_oid_desc =
53
{9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
54
55
#define NTLMSSP_SIGNATURE "NTLMSSP"
56
57
OM_uint32
58
gssint_get_mech_type(gss_OID OID, gss_buffer_t token)
59
{
60
struct k5input in;
61
size_t tlen;
62
63
/* Check for interoperability exceptions */
64
if (token->length >= sizeof(NTLMSSP_SIGNATURE) &&
65
memcmp(token->value, NTLMSSP_SIGNATURE,
66
sizeof(NTLMSSP_SIGNATURE)) == 0) {
67
*OID = gss_ntlm_mechanism_oid_desc;
68
} else if (token->length != 0 &&
69
((char *)token->value)[0] == 0x6E) {
70
/* Could be a raw AP-REQ (check for APPLICATION tag) */
71
*OID = gss_krb5_mechanism_oid_desc;
72
} else if (token->length == 0) {
73
*OID = gss_spnego_mechanism_oid_desc;
74
} else {
75
k5_input_init(&in, token->value, token->length);
76
return (g_get_token_header(&in, OID, &tlen) ? GSS_S_COMPLETE :
77
GSS_S_DEFECTIVE_TOKEN);
78
}
79
80
return (GSS_S_COMPLETE);
81
}
82
83
static OM_uint32
84
import_internal_attributes(OM_uint32 *minor,
85
gss_mechanism dmech,
86
gss_union_name_t sname,
87
gss_name_t dname)
88
{
89
OM_uint32 major, tmpMinor;
90
gss_mechanism smech;
91
gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET;
92
size_t i;
93
94
if (sname->mech_name == GSS_C_NO_NAME)
95
return (GSS_S_UNAVAILABLE);
96
97
smech = gssint_get_mechanism (sname->mech_type);
98
if (smech == NULL)
99
return (GSS_S_BAD_MECH);
100
101
if (smech->gss_inquire_name == NULL ||
102
smech->gss_get_name_attribute == NULL)
103
return (GSS_S_UNAVAILABLE);
104
105
if (dmech->gss_set_name_attribute == NULL)
106
return (GSS_S_UNAVAILABLE);
107
108
major = smech->gss_inquire_name(minor, sname->mech_name,
109
NULL, NULL, &attrs);
110
if (GSS_ERROR(major) || attrs == GSS_C_NO_BUFFER_SET) {
111
gss_release_buffer_set(&tmpMinor, &attrs);
112
return (major);
113
}
114
115
for (i = 0; i < attrs->count; i++) {
116
int more = -1;
117
118
while (more != 0) {
119
gss_buffer_desc value, display_value;
120
int authenticated, complete;
121
122
major = smech->gss_get_name_attribute(minor, sname->mech_name,
123
&attrs->elements[i],
124
&authenticated, &complete,
125
&value, &display_value,
126
&more);
127
if (GSS_ERROR(major))
128
continue;
129
130
if (authenticated) {
131
dmech->gss_set_name_attribute(minor, dname, complete,
132
&attrs->elements[i], &value);
133
}
134
135
gss_release_buffer(&tmpMinor, &value);
136
gss_release_buffer(&tmpMinor, &display_value);
137
}
138
}
139
140
gss_release_buffer_set(&tmpMinor, &attrs);
141
142
return (GSS_S_COMPLETE);
143
}
144
145
/*
146
* Internal routines to get and release an internal mechanism name
147
*/
148
149
OM_uint32
150
gssint_import_internal_name(OM_uint32 *minor_status, gss_OID mech_type,
151
gss_union_name_t union_name,
152
gss_name_t *internal_name)
153
{
154
OM_uint32 status, tmpMinor;
155
gss_mechanism mech;
156
gss_OID public_mech;
157
158
mech = gssint_get_mechanism (mech_type);
159
if (mech == NULL)
160
return (GSS_S_BAD_MECH);
161
162
/*
163
* If we are importing a name for the same mechanism, and the
164
* mechanism implements gss_duplicate_name, then use that.
165
*/
166
if (union_name->mech_type != GSS_C_NO_OID &&
167
union_name->mech_name != GSS_C_NO_NAME &&
168
g_OID_equal(union_name->mech_type, mech_type) &&
169
mech->gss_duplicate_name != NULL) {
170
status = mech->gss_duplicate_name(minor_status,
171
union_name->mech_name,
172
internal_name);
173
if (status != GSS_S_UNAVAILABLE) {
174
if (status != GSS_S_COMPLETE)
175
map_error(minor_status, mech);
176
return (status);
177
}
178
}
179
180
if (mech->gssspi_import_name_by_mech) {
181
public_mech = gssint_get_public_oid(mech_type);
182
status = mech->gssspi_import_name_by_mech(minor_status, public_mech,
183
union_name->external_name,
184
union_name->name_type,
185
internal_name);
186
} else if (mech->gss_import_name) {
187
status = mech->gss_import_name(minor_status, union_name->external_name,
188
union_name->name_type, internal_name);
189
} else {
190
return (GSS_S_UNAVAILABLE);
191
}
192
193
if (status == GSS_S_COMPLETE) {
194
/* Attempt to round-trip attributes */
195
(void) import_internal_attributes(&tmpMinor, mech,
196
union_name, *internal_name);
197
} else {
198
map_error(minor_status, mech);
199
}
200
201
return (status);
202
}
203
204
OM_uint32
205
gssint_export_internal_name(OM_uint32 *minor_status, const gss_OID mech_type,
206
const gss_name_t internal_name,
207
gss_buffer_t name_buf)
208
{
209
OM_uint32 status;
210
gss_mechanism mech;
211
gss_buffer_desc dispName;
212
gss_OID nameOid;
213
int mech_der_len = 0;
214
struct k5buf buf;
215
216
mech = gssint_get_mechanism(mech_type);
217
if (!mech)
218
return (GSS_S_BAD_MECH);
219
220
if (mech->gss_export_name) {
221
status = mech->gss_export_name(minor_status,
222
internal_name,
223
name_buf);
224
if (status != GSS_S_COMPLETE)
225
map_error(minor_status, mech);
226
return status;
227
}
228
229
/*
230
* if we are here it is because the mechanism does not provide
231
* a gss_export_name so we will use our implementation. We
232
* do required that the mechanism define a gss_display_name.
233
*/
234
if (!mech->gss_display_name)
235
return (GSS_S_UNAVAILABLE);
236
237
/*
238
* NOTE: RFC2743 (section 3.2) governs the format of the outer
239
* wrapper of exported names; the mechanisms' specs govern
240
* the format of the inner portion of the exported name
241
* and, for some (e.g., RFC1964, the Kerberos V mech), a
242
* generic default as implemented here will do.
243
*
244
* The outer wrapper of an exported MN is: 2-octet tok Id
245
* (0x0401) + 2-octet network-byte order mech OID length + mech
246
* oid (in DER format, including DER tag and DER length) +
247
* 4-octet network-byte order length of inner portion + inner
248
* portion.
249
*
250
* For the Kerberos V mechanism the inner portion of an exported
251
* MN is the display name string and ignores the name type OID
252
* altogether. And we hope this will be so for any future
253
* mechanisms also, so that factoring name export/import out of
254
* the mech and into libgss pays off.
255
*/
256
if ((status = mech->gss_display_name(minor_status,
257
internal_name,
258
&dispName,
259
&nameOid))
260
!= GSS_S_COMPLETE) {
261
map_error(minor_status, mech);
262
return (status);
263
}
264
265
/* Allocate space and prepare a buffer. */
266
mech_der_len = k5_der_value_len(mech_type->length);
267
name_buf->length = 2 + 2 + mech_der_len + 4 + dispName.length;
268
name_buf->value = gssalloc_malloc(name_buf->length);
269
if (name_buf->value == NULL) {
270
name_buf->length = 0;
271
(void) gss_release_buffer(&status, &dispName);
272
return (GSS_S_FAILURE);
273
}
274
k5_buf_init_fixed(&buf, name_buf->value, name_buf->length);
275
276
/* Assemble the name. */
277
k5_buf_add_len(&buf, "\x04\x01", 2);
278
k5_buf_add_uint16_be(&buf, mech_der_len);
279
k5_der_add_value(&buf, 0x06, mech_type->elements, mech_type->length);
280
k5_buf_add_uint32_be(&buf, dispName.length);
281
k5_buf_add_len(&buf, dispName.value, dispName.length);
282
assert(buf.len == name_buf->length);
283
284
/* release the buffer obtained from gss_display_name */
285
(void) gss_release_buffer(minor_status, &dispName);
286
return (GSS_S_COMPLETE);
287
} /* gssint_export_internal_name */
288
289
OM_uint32
290
gssint_display_internal_name(OM_uint32 *minor_status, gss_OID mech_type,
291
gss_name_t internal_name,
292
gss_buffer_t external_name, gss_OID *name_type)
293
{
294
OM_uint32 status;
295
gss_mechanism mech;
296
297
mech = gssint_get_mechanism (mech_type);
298
if (mech) {
299
if (mech->gss_display_name) {
300
status = mech->gss_display_name (
301
minor_status,
302
internal_name,
303
external_name,
304
name_type);
305
if (status != GSS_S_COMPLETE)
306
map_error(minor_status, mech);
307
} else
308
status = GSS_S_UNAVAILABLE;
309
310
return (status);
311
}
312
313
return (GSS_S_BAD_MECH);
314
}
315
316
OM_uint32
317
gssint_release_internal_name(OM_uint32 *minor_status, gss_OID mech_type,
318
gss_name_t *internal_name)
319
{
320
OM_uint32 status;
321
gss_mechanism mech;
322
323
mech = gssint_get_mechanism (mech_type);
324
if (mech) {
325
if (mech->gss_release_name) {
326
status = mech->gss_release_name (
327
minor_status,
328
internal_name);
329
if (status != GSS_S_COMPLETE)
330
map_error(minor_status, mech);
331
} else
332
status = GSS_S_UNAVAILABLE;
333
334
return (status);
335
}
336
337
return (GSS_S_BAD_MECH);
338
}
339
340
OM_uint32
341
gssint_delete_internal_sec_context(OM_uint32 *minor_status, gss_OID mech_type,
342
gss_ctx_id_t *internal_ctx,
343
gss_buffer_t output_token)
344
{
345
OM_uint32 status;
346
gss_mechanism mech;
347
348
mech = gssint_get_mechanism (mech_type);
349
if (mech) {
350
if (mech->gss_delete_sec_context)
351
status = mech->gss_delete_sec_context (minor_status,
352
internal_ctx,
353
output_token);
354
else
355
status = GSS_S_UNAVAILABLE;
356
357
return (status);
358
}
359
360
return (GSS_S_BAD_MECH);
361
}
362
363
/*
364
* This function converts an internal gssapi name to a union gssapi
365
* name. Note that internal_name should be considered "consumed" by
366
* this call, whether or not we return an error.
367
*/
368
OM_uint32
369
gssint_convert_name_to_union_name(OM_uint32 *minor_status, gss_mechanism mech,
370
gss_name_t internal_name,
371
gss_name_t *external_name)
372
{
373
OM_uint32 major_status,tmp;
374
gss_union_name_t union_name;
375
376
union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc));
377
if (!union_name) {
378
major_status = GSS_S_FAILURE;
379
*minor_status = ENOMEM;
380
map_errcode(minor_status);
381
goto allocation_failure;
382
}
383
union_name->mech_type = 0;
384
union_name->mech_name = internal_name;
385
union_name->name_type = 0;
386
union_name->external_name = 0;
387
388
major_status = generic_gss_copy_oid(minor_status, &mech->mech_type,
389
&union_name->mech_type);
390
if (major_status != GSS_S_COMPLETE) {
391
map_errcode(minor_status);
392
goto allocation_failure;
393
}
394
395
union_name->external_name =
396
(gss_buffer_t) malloc(sizeof(gss_buffer_desc));
397
if (!union_name->external_name) {
398
major_status = GSS_S_FAILURE;
399
goto allocation_failure;
400
}
401
union_name->external_name->length = 0;
402
union_name->external_name->value = NULL;
403
404
major_status = mech->gss_display_name(minor_status,
405
internal_name,
406
union_name->external_name,
407
&union_name->name_type);
408
if (major_status != GSS_S_COMPLETE) {
409
map_error(minor_status, mech);
410
goto allocation_failure;
411
}
412
413
union_name->loopback = union_name;
414
*external_name = /*(gss_name_t) CHECK */union_name;
415
return (GSS_S_COMPLETE);
416
417
allocation_failure:
418
if (union_name) {
419
if (union_name->external_name) {
420
if (union_name->external_name->value)
421
free(union_name->external_name->value);
422
free(union_name->external_name);
423
}
424
if (union_name->name_type)
425
gss_release_oid(&tmp, &union_name->name_type);
426
if (union_name->mech_type)
427
gss_release_oid(&tmp, &union_name->mech_type);
428
free(union_name);
429
}
430
/*
431
* do as the top comment says - since we are now owners of
432
* internal_name, we must clean it up
433
*/
434
if (internal_name)
435
(void) gssint_release_internal_name(&tmp, &mech->mech_type,
436
&internal_name);
437
return (major_status);
438
}
439
440
/*
441
* Glue routine for returning the mechanism-specific credential from a
442
* external union credential.
443
*/
444
gss_cred_id_t
445
gssint_get_mechanism_cred(gss_union_cred_t union_cred, gss_OID mech_type)
446
{
447
int i;
448
449
if (union_cred == GSS_C_NO_CREDENTIAL)
450
return GSS_C_NO_CREDENTIAL;
451
452
for (i=0; i < union_cred->count; i++) {
453
if (g_OID_equal(mech_type, &union_cred->mechs_array[i]))
454
return union_cred->cred_array[i];
455
}
456
return GSS_C_NO_CREDENTIAL;
457
}
458
459
/*
460
* Routine to create and copy the gss_buffer_desc structure.
461
* Both space for the structure and the data is allocated.
462
*/
463
OM_uint32
464
gssint_create_copy_buffer(const gss_buffer_t srcBuf, gss_buffer_t *destBuf,
465
int addNullChar)
466
{
467
gss_buffer_t aBuf;
468
unsigned int len;
469
470
if (destBuf == NULL)
471
return (GSS_S_CALL_INACCESSIBLE_WRITE);
472
473
*destBuf = 0;
474
475
aBuf = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
476
if (!aBuf)
477
return (GSS_S_FAILURE);
478
479
if (addNullChar)
480
len = srcBuf->length + 1;
481
else
482
len = srcBuf->length;
483
484
if (!(aBuf->value = (void*)gssalloc_malloc(len))) {
485
free(aBuf);
486
return (GSS_S_FAILURE);
487
}
488
489
490
(void) memcpy(aBuf->value, srcBuf->value, srcBuf->length);
491
aBuf->length = srcBuf->length;
492
*destBuf = aBuf;
493
494
/* optionally add a NULL character */
495
if (addNullChar)
496
((char *)aBuf->value)[aBuf->length] = '\0';
497
498
return (GSS_S_COMPLETE);
499
} /* ****** gssint_create_copy_buffer ****** */
500
501
OM_uint32
502
gssint_create_union_context(OM_uint32 *minor, gss_const_OID mech_oid,
503
gss_union_ctx_id_t *ctx_out)
504
{
505
OM_uint32 status;
506
gss_union_ctx_id_t ctx;
507
508
*ctx_out = NULL;
509
510
ctx = calloc(1, sizeof(*ctx));
511
if (ctx == NULL) {
512
*minor = ENOMEM;
513
return GSS_S_FAILURE;
514
}
515
516
status = generic_gss_copy_oid(minor, mech_oid, &ctx->mech_type);
517
if (status != GSS_S_COMPLETE) {
518
free(ctx);
519
return status;
520
}
521
522
ctx->loopback = ctx;
523
ctx->internal_ctx_id = GSS_C_NO_CONTEXT;
524
525
*ctx_out = ctx;
526
return GSS_S_COMPLETE;
527
}
528
529