Coverage Report

Created: 2026-02-09 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/krb5/src/lib/gssapi/mechglue/g_glue.c
Line
Count
Source
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
5.92k
#define NTLMSSP_SIGNATURE "NTLMSSP"
56
57
OM_uint32
58
gssint_get_mech_type(gss_OID OID, gss_buffer_t token)
59
2.09k
{
60
2.09k
    struct k5input in;
61
2.09k
    size_t tlen;
62
63
    /* Check for interoperability exceptions */
64
2.09k
    if (token->length >= sizeof(NTLMSSP_SIGNATURE) &&
65
1.91k
  memcmp(token->value, NTLMSSP_SIGNATURE,
66
1.91k
         sizeof(NTLMSSP_SIGNATURE)) == 0) {
67
1
  *OID = gss_ntlm_mechanism_oid_desc;
68
2.09k
    } else if (token->length != 0 &&
69
2.09k
         ((char *)token->value)[0] == 0x6E) {
70
  /* Could be a raw AP-REQ (check for APPLICATION tag) */
71
5
  *OID = gss_krb5_mechanism_oid_desc;
72
2.09k
    } else if (token->length == 0) {
73
0
  *OID = gss_spnego_mechanism_oid_desc;
74
2.09k
    } else {
75
2.09k
  k5_input_init(&in, token->value, token->length);
76
2.09k
  return (g_get_token_header(&in, OID, &tlen) ? GSS_S_COMPLETE :
77
2.09k
    GSS_S_DEFECTIVE_TOKEN);
78
2.09k
    }
79
80
6
    return (GSS_S_COMPLETE);
81
2.09k
}
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
0
{
89
0
    OM_uint32 major, tmpMinor;
90
0
    gss_mechanism smech;
91
0
    gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET;
92
0
    size_t i;
93
94
0
    if (sname->mech_name == GSS_C_NO_NAME)
95
0
  return (GSS_S_UNAVAILABLE);
96
97
0
    smech = gssint_get_mechanism (sname->mech_type);
98
0
    if (smech == NULL)
99
0
  return (GSS_S_BAD_MECH);
100
101
0
    if (smech->gss_inquire_name == NULL ||
102
0
  smech->gss_get_name_attribute == NULL)
103
0
  return (GSS_S_UNAVAILABLE);
104
105
0
    if (dmech->gss_set_name_attribute == NULL)
106
0
  return (GSS_S_UNAVAILABLE);
107
108
0
    major = smech->gss_inquire_name(minor, sname->mech_name,
109
0
            NULL, NULL, &attrs);
110
0
    if (GSS_ERROR(major) || attrs == GSS_C_NO_BUFFER_SET) {
111
0
  gss_release_buffer_set(&tmpMinor, &attrs);
112
0
  return (major);
113
0
    }
114
115
0
    for (i = 0; i < attrs->count; i++) {
116
0
  int more = -1;
117
118
0
  while (more != 0) {
119
0
      gss_buffer_desc value, display_value;
120
0
      int authenticated, complete;
121
122
0
      major = smech->gss_get_name_attribute(minor, sname->mech_name,
123
0
              &attrs->elements[i],
124
0
              &authenticated, &complete,
125
0
              &value, &display_value,
126
0
              &more);
127
0
      if (GSS_ERROR(major))
128
0
    continue;
129
130
0
      if (authenticated) {
131
0
    dmech->gss_set_name_attribute(minor, dname, complete,
132
0
                &attrs->elements[i], &value);
133
0
      }
134
135
0
      gss_release_buffer(&tmpMinor, &value);
136
0
      gss_release_buffer(&tmpMinor, &display_value);
137
0
  }
138
0
    }
139
140
0
    gss_release_buffer_set(&tmpMinor, &attrs);
141
142
0
    return (GSS_S_COMPLETE);
143
0
}
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
0
{
154
0
    OM_uint32   status, tmpMinor;
155
0
    gss_mechanism mech;
156
0
    gss_OID   public_mech;
157
158
0
    mech = gssint_get_mechanism (mech_type);
159
0
    if (mech == NULL)
160
0
  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
0
    if (union_name->mech_type != GSS_C_NO_OID &&
167
0
  union_name->mech_name != GSS_C_NO_NAME &&
168
0
  g_OID_equal(union_name->mech_type, mech_type) &&
169
0
  mech->gss_duplicate_name != NULL) {
170
0
  status = mech->gss_duplicate_name(minor_status,
171
0
            union_name->mech_name,
172
0
            internal_name);
173
0
  if (status != GSS_S_UNAVAILABLE) {
174
0
      if (status != GSS_S_COMPLETE)
175
0
    map_error(minor_status, mech);
176
0
      return (status);
177
0
  }
178
0
    }
179
180
0
    if (mech->gssspi_import_name_by_mech) {
181
0
  public_mech = gssint_get_public_oid(mech_type);
182
0
  status = mech->gssspi_import_name_by_mech(minor_status, public_mech,
183
0
              union_name->external_name,
184
0
              union_name->name_type,
185
0
              internal_name);
186
0
    } else if (mech->gss_import_name) {
187
0
  status = mech->gss_import_name(minor_status, union_name->external_name,
188
0
               union_name->name_type, internal_name);
189
0
    } else {
190
0
  return (GSS_S_UNAVAILABLE);
191
0
    }
192
193
0
    if (status == GSS_S_COMPLETE) {
194
        /* Attempt to round-trip attributes */
195
0
  (void) import_internal_attributes(&tmpMinor, mech,
196
0
                  union_name, *internal_name);
197
0
    } else {
198
0
  map_error(minor_status, mech);
199
0
    }
200
201
0
    return (status);
202
0
}
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
0
{
209
0
    OM_uint32 status;
210
0
    gss_mechanism mech;
211
0
    gss_buffer_desc dispName;
212
0
    gss_OID nameOid;
213
0
    int mech_der_len = 0;
214
0
    struct k5buf buf;
215
216
0
    mech = gssint_get_mechanism(mech_type);
217
0
    if (!mech)
218
0
  return (GSS_S_BAD_MECH);
219
220
0
    if (mech->gss_export_name) {
221
0
  status = mech->gss_export_name(minor_status,
222
0
               internal_name,
223
0
               name_buf);
224
0
  if (status != GSS_S_COMPLETE)
225
0
      map_error(minor_status, mech);
226
0
  return status;
227
0
    }
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
0
    if (!mech->gss_display_name)
235
0
  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
0
    if ((status = mech->gss_display_name(minor_status,
257
0
           internal_name,
258
0
           &dispName,
259
0
           &nameOid))
260
0
  != GSS_S_COMPLETE) {
261
0
  map_error(minor_status, mech);
262
0
  return (status);
263
0
    }
264
265
    /* Allocate space and prepare a buffer. */
266
0
    mech_der_len = k5_der_value_len(mech_type->length);
267
0
    name_buf->length = 2 + 2 + mech_der_len + 4 + dispName.length;
268
0
    name_buf->value = gssalloc_malloc(name_buf->length);
269
0
    if (name_buf->value == NULL) {
270
0
  name_buf->length = 0;
271
0
  (void) gss_release_buffer(&status, &dispName);
272
0
  return (GSS_S_FAILURE);
273
0
    }
274
0
    k5_buf_init_fixed(&buf, name_buf->value, name_buf->length);
275
276
    /* Assemble the name. */
277
0
    k5_buf_add_len(&buf, "\x04\x01", 2);
278
0
    k5_buf_add_uint16_be(&buf, mech_der_len);
279
0
    k5_der_add_value(&buf, 0x06, mech_type->elements, mech_type->length);
280
0
    k5_buf_add_uint32_be(&buf, dispName.length);
281
0
    k5_buf_add_len(&buf, dispName.value, dispName.length);
282
0
    assert(buf.len == name_buf->length);
283
284
    /* release the buffer obtained from gss_display_name */
285
0
    (void) gss_release_buffer(minor_status, &dispName);
286
0
    return (GSS_S_COMPLETE);
287
0
} /*  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
0
{
294
0
    OM_uint32   status;
295
0
    gss_mechanism mech;
296
297
0
    mech = gssint_get_mechanism (mech_type);
298
0
    if (mech) {
299
0
  if (mech->gss_display_name) {
300
0
      status = mech->gss_display_name (
301
0
               minor_status,
302
0
               internal_name,
303
0
               external_name,
304
0
               name_type);
305
0
      if (status != GSS_S_COMPLETE)
306
0
    map_error(minor_status, mech);
307
0
  } else
308
0
      status = GSS_S_UNAVAILABLE;
309
310
0
  return (status);
311
0
    }
312
313
0
    return (GSS_S_BAD_MECH);
314
0
}
315
316
OM_uint32
317
gssint_release_internal_name(OM_uint32 *minor_status, gss_OID mech_type,
318
           gss_name_t *internal_name)
319
0
{
320
0
    OM_uint32   status;
321
0
    gss_mechanism mech;
322
323
0
    mech = gssint_get_mechanism (mech_type);
324
0
    if (mech) {
325
0
  if (mech->gss_release_name) {
326
0
      status = mech->gss_release_name (
327
0
               minor_status,
328
0
               internal_name);
329
0
      if (status != GSS_S_COMPLETE)
330
0
    map_error(minor_status, mech);
331
0
  } else
332
0
      status = GSS_S_UNAVAILABLE;
333
334
0
  return (status);
335
0
    }
336
337
0
    return (GSS_S_BAD_MECH);
338
0
}
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
0
{
345
0
    OM_uint32   status;
346
0
    gss_mechanism mech;
347
348
0
    mech = gssint_get_mechanism (mech_type);
349
0
    if (mech) {
350
0
  if (mech->gss_delete_sec_context)
351
0
      status = mech->gss_delete_sec_context (minor_status,
352
0
               internal_ctx,
353
0
               output_token);
354
0
  else
355
0
      status = GSS_S_UNAVAILABLE;
356
357
0
  return (status);
358
0
    }
359
360
0
    return (GSS_S_BAD_MECH);
361
0
}
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
0
{
373
0
    OM_uint32 major_status,tmp;
374
0
    gss_union_name_t union_name;
375
376
0
    union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc));
377
0
    if (!union_name) {
378
0
  major_status = GSS_S_FAILURE;
379
0
  *minor_status = ENOMEM;
380
0
  map_errcode(minor_status);
381
0
  goto allocation_failure;
382
0
    }
383
0
    union_name->mech_type = 0;
384
0
    union_name->mech_name = internal_name;
385
0
    union_name->name_type = 0;
386
0
    union_name->external_name = 0;
387
388
0
    major_status = generic_gss_copy_oid(minor_status, &mech->mech_type,
389
0
          &union_name->mech_type);
390
0
    if (major_status != GSS_S_COMPLETE) {
391
0
  map_errcode(minor_status);
392
0
  goto allocation_failure;
393
0
    }
394
395
0
    union_name->external_name =
396
0
  (gss_buffer_t) malloc(sizeof(gss_buffer_desc));
397
0
    if (!union_name->external_name) {
398
0
      major_status = GSS_S_FAILURE;
399
0
      goto allocation_failure;
400
0
    }
401
0
    union_name->external_name->length = 0;
402
0
    union_name->external_name->value = NULL;
403
404
0
    major_status = mech->gss_display_name(minor_status,
405
0
            internal_name,
406
0
            union_name->external_name,
407
0
            &union_name->name_type);
408
0
    if (major_status != GSS_S_COMPLETE) {
409
0
  map_error(minor_status, mech);
410
0
  goto allocation_failure;
411
0
    }
412
413
0
    union_name->loopback = union_name;
414
0
    *external_name = /*(gss_name_t) CHECK */union_name;
415
0
    return (GSS_S_COMPLETE);
416
417
0
allocation_failure:
418
0
    if (union_name) {
419
0
  if (union_name->external_name) {
420
0
      if (union_name->external_name->value)
421
0
    free(union_name->external_name->value);
422
0
      free(union_name->external_name);
423
0
  }
424
0
  if (union_name->name_type)
425
0
      gss_release_oid(&tmp, &union_name->name_type);
426
0
  if (union_name->mech_type)
427
0
      gss_release_oid(&tmp, &union_name->mech_type);
428
0
  free(union_name);
429
0
    }
430
    /*
431
     * do as the top comment says - since we are now owners of
432
     * internal_name, we must clean it up
433
     */
434
0
    if (internal_name)
435
0
  (void) gssint_release_internal_name(&tmp, &mech->mech_type,
436
0
             &internal_name);
437
0
    return (major_status);
438
0
}
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
42
{
447
42
    int   i;
448
449
42
    if (union_cred == GSS_C_NO_CREDENTIAL)
450
0
  return GSS_C_NO_CREDENTIAL;
451
452
42
    for (i=0; i < union_cred->count; i++) {
453
0
  if (g_OID_equal(mech_type, &union_cred->mechs_array[i]))
454
0
      return union_cred->cred_array[i];
455
0
    }
456
42
    return GSS_C_NO_CREDENTIAL;
457
42
}
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
0
{
467
0
    gss_buffer_t aBuf;
468
0
    unsigned int len;
469
470
0
    if (destBuf == NULL)
471
0
  return (GSS_S_CALL_INACCESSIBLE_WRITE);
472
473
0
    *destBuf = 0;
474
475
0
    aBuf = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
476
0
    if (!aBuf)
477
0
  return (GSS_S_FAILURE);
478
479
0
    if (addNullChar)
480
0
  len = srcBuf->length + 1;
481
0
    else
482
0
  len = srcBuf->length;
483
484
0
    if (!(aBuf->value = (void*)gssalloc_malloc(len))) {
485
0
  free(aBuf);
486
0
  return (GSS_S_FAILURE);
487
0
    }
488
489
490
0
    (void) memcpy(aBuf->value, srcBuf->value, srcBuf->length);
491
0
    aBuf->length = srcBuf->length;
492
0
    *destBuf = aBuf;
493
494
    /* optionally add a NULL character */
495
0
    if (addNullChar)
496
0
  ((char *)aBuf->value)[aBuf->length] = '\0';
497
498
0
    return (GSS_S_COMPLETE);
499
0
} /* ****** 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
1.66k
{
505
1.66k
    OM_uint32 status;
506
1.66k
    gss_union_ctx_id_t ctx;
507
508
1.66k
    *ctx_out = NULL;
509
510
1.66k
    ctx = calloc(1, sizeof(*ctx));
511
1.66k
    if (ctx == NULL) {
512
0
  *minor = ENOMEM;
513
0
  return GSS_S_FAILURE;
514
0
    }
515
516
1.66k
    status = generic_gss_copy_oid(minor, mech_oid, &ctx->mech_type);
517
1.66k
    if (status != GSS_S_COMPLETE) {
518
0
  free(ctx);
519
0
  return status;
520
0
    }
521
522
1.66k
    ctx->loopback = ctx;
523
1.66k
    ctx->internal_ctx_id = GSS_C_NO_CONTEXT;
524
525
1.66k
    *ctx_out = ctx;
526
1.66k
    return GSS_S_COMPLETE;
527
1.66k
}