Home | History | Annotate | Download | only in libgss
      1      0  stevel /*
      2  10598   Glenn  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
      3      0  stevel  * Use is subject to license terms.
      4      0  stevel  */
      5      0  stevel 
      6  10598   Glenn #include "mglueP.h"
      7      0  stevel 
      8      0  stevel #include <stdio.h>
      9  10598   Glenn #ifdef HAVE_STDLIB_H
     10      0  stevel #include <stdlib.h>
     11  10598   Glenn #endif
     12  10598   Glenn #include <string.h>
     13      0  stevel #include <errno.h>
     14      0  stevel 
     15  10598   Glenn #include "k5-platform-store_32.h"
     16  10598   Glenn #include "k5-platform-store_16.h"
     17  10598   Glenn /*
     18  10598   Glenn  * SUNW17PACresync
     19  10598   Glenn  * MIT has diff names for these GSS utilities.  Solaris needs to change
     20  10598   Glenn  * them globally to get in sync w/MIT.
     21  10598   Glenn  * Revisit for full 1.7 resync.
     22  10598   Glenn  */
     23  10598   Glenn #define gssint_get_modOptions __gss_get_modOptions
     24  10598   Glenn #define gssint_der_length_size der_length_size
     25  10598   Glenn #define gssint_get_der_length get_der_length
     26  10598   Glenn #define gssint_put_der_length put_der_length
     27  10598   Glenn #define gssint_get_mechanism __gss_get_mechanism
     28  10598   Glenn #define gssint_get_mechanism_cred __gss_get_mechanism_cred
     29  10598   Glenn #define gssint_copy_oid_set gss_copy_oid_set
     30  10598   Glenn #define gssint_get_mech_type __gss_get_mech_type
     31  10598   Glenn #define gssint_export_internal_name __gss_export_internal_name
     32  10598   Glenn #define gssint_release_internal_name __gss_release_internal_name
     33  10598   Glenn #define gssint_convert_name_to_union_name __gss_convert_name_to_union_name
     34  10598   Glenn #define gssint_import_internal_name __gss_import_internal_name
     35  10598   Glenn #define gssint_display_internal_name __gss_display_internal_name
     36  10598   Glenn 
     37  10598   Glenn 
     38      0  stevel #define	MSO_BIT (8*(sizeof (int) - 1))  /* Most significant octet bit */
     39  10598   Glenn 
     40  10598   Glenn extern gss_mechanism *gssint_mechs_array;
     41      0  stevel 
     42      0  stevel /*
     43      0  stevel  * This file contains the support routines for the glue layer.
     44      0  stevel  */
     45      0  stevel 
     46      0  stevel /*
     47      0  stevel  * get_der_length: Givin a pointer to a buffer that contains a DER encoded
     48      0  stevel  * length, decode the length updating the buffer to point to the character
     49      0  stevel  * after the DER encoding. The parameter bytes will point to the number of
     50      0  stevel  * bytes that made up the DER encoding of the length originally pointed to
     51      0  stevel  * by the buffer. Note we return -1 on error.
     52      0  stevel  */
     53      0  stevel int
     54  10598   Glenn gssint_get_der_length(unsigned char **buf, unsigned int buf_len, unsigned int *bytes)
     55      0  stevel {
     56  10598   Glenn     /* p points to the beginning of the buffer */
     57  10598   Glenn     unsigned char *p = *buf;
     58  10598   Glenn     int length, new_length;
     59  10598   Glenn     unsigned int octets;
     60      0  stevel 
     61  10598   Glenn     if (buf_len < 1)
     62  10598   Glenn 	return (-1);
     63      0  stevel 
     64  10598   Glenn     /* We should have at least one byte */
     65  10598   Glenn     *bytes = 1;
     66      0  stevel 
     67  10598   Glenn     /*
     68  10598   Glenn      * If the High order bit is not set then the length is just the value
     69  10598   Glenn      * of *p.
     70  10598   Glenn      */
     71  10598   Glenn     if (*p < 128) {
     72  10598   Glenn 	*buf = p+1;	/* Advance the buffer */
     73      0  stevel 	return (*p);		/* return the length */
     74  10598   Glenn     }
     75      0  stevel 
     76  10598   Glenn     /*
     77  10598   Glenn      * if the High order bit is set, then the low order bits represent
     78  10598   Glenn      * the number of bytes that contain the DER encoding of the length.
     79  10598   Glenn      */
     80      0  stevel 
     81  10598   Glenn     octets = *p++ & 0x7f;
     82  10598   Glenn     *bytes += octets;
     83      0  stevel 
     84  10598   Glenn     /* See if the supplied buffer contains enough bytes for the length. */
     85  10598   Glenn     if (octets > buf_len - 1)
     86  10598   Glenn 	return (-1);
     87      0  stevel 
     88  10598   Glenn     /*
     89  10598   Glenn      * Calculate a multibyte length. The length is encoded as an
     90  10598   Glenn      * unsigned integer base 256.
     91  10598   Glenn      */
     92  10598   Glenn     for (length = 0; octets; octets--) {
     93  10598   Glenn 	new_length = (length << 8) + *p++;
     94  10598   Glenn 	if (new_length < length)  /* overflow */
     95  10598   Glenn 	    return (-1);
     96  10598   Glenn 	length = new_length;
     97  10598   Glenn     }
     98      0  stevel 
     99  10598   Glenn     *buf = p; /* Advance the buffer */
    100      0  stevel 
    101  10598   Glenn     return (length);
    102      0  stevel }
    103      0  stevel 
    104      0  stevel /*
    105      0  stevel  * der_length_size: Return the number of bytes to encode a given length.
    106      0  stevel  */
    107      0  stevel unsigned int
    108  10598   Glenn gssint_der_length_size(unsigned int len)
    109      0  stevel {
    110  10598   Glenn     int i;
    111      0  stevel 
    112  10598   Glenn     if (len < 128)
    113  10598   Glenn 	return (1);
    114      0  stevel 
    115  10598   Glenn     for (i = 0; len; i++) {
    116  10598   Glenn 	len >>= 8;
    117  10598   Glenn     }
    118      0  stevel 
    119  10598   Glenn     return (i+1);
    120      0  stevel }
    121      0  stevel 
    122      0  stevel /*
    123      0  stevel  * put_der_length: Encode the supplied length into the buffer pointed to
    124      0  stevel  * by buf. max_length represents the maximum length of the buffer pointed
    125      0  stevel  * to by buff. We will advance buf to point to the character after the newly
    126      0  stevel  * DER encoded length. We return 0 on success or -l it the length cannot
    127      0  stevel  * be encoded in max_len characters.
    128      0  stevel  */
    129      0  stevel int
    130  10598   Glenn gssint_put_der_length(unsigned int length, unsigned char **buf, unsigned int max_len)
    131      0  stevel {
    132  10598   Glenn     unsigned char *s, *p;
    133  10598   Glenn     unsigned int buf_len = 0;
    134  10598   Glenn     int i, first;
    135      0  stevel 
    136  10598   Glenn     /* Oops */
    137  10598   Glenn     if (buf == 0 || max_len < 1)
    138  10598   Glenn 	return (-1);
    139      0  stevel 
    140  10598   Glenn     s = *buf;
    141  10598   Glenn 
    142  10598   Glenn     /* Single byte is the length */
    143  10598   Glenn     if (length < 128) {
    144  10598   Glenn 	*s++ = length;
    145  10598   Glenn 	*buf = s;
    146  10598   Glenn 	return (0);
    147  10598   Glenn     }
    148  10598   Glenn 
    149  10598   Glenn     /* First byte contains the number of octets */
    150  10598   Glenn     p = s + 1;
    151  10598   Glenn 
    152  10598   Glenn     /* Running total of the DER encoding length */
    153  10598   Glenn     buf_len = 0;
    154  10598   Glenn 
    155  10598   Glenn     /*
    156  10598   Glenn      * Encode MSB first. We do the encoding by setting a shift
    157  10598   Glenn      * factor to MSO_BIT (24 for 32 bit words) and then shifting the length
    158  10598   Glenn      * by the factor. We then encode the resulting low order byte.
    159  10598   Glenn      * We subtract 8 from the shift factor and repeat to ecnode the next
    160  10598   Glenn      * byte. We stop when the shift factor is zero or we've run out of
    161  10598   Glenn      * buffer to encode into.
    162  10598   Glenn      */
    163  10598   Glenn     first = 0;
    164  10598   Glenn     for (i = MSO_BIT; i >= 0 && buf_len <= max_len; i -= 8) {
    165  10598   Glenn 	unsigned int v;
    166  10598   Glenn 	v = (length >> i) & 0xff;
    167  10598   Glenn 	if ((v) || first) {
    168  10598   Glenn 	    buf_len += 1;
    169  10598   Glenn 	    *p++ = v;
    170  10598   Glenn 	    first = 1;
    171      0  stevel 	}
    172  10598   Glenn     }
    173  10598   Glenn     if (i >= 0)			/* buffer overflow */
    174  10598   Glenn 	return (-1);
    175      0  stevel 
    176  10598   Glenn     /*
    177  10598   Glenn      * We go back now and set the first byte to be the length with
    178  10598   Glenn      * the high order bit set.
    179  10598   Glenn      */
    180  10598   Glenn     *s = buf_len | 0x80;
    181  10598   Glenn     *buf = p;
    182      0  stevel 
    183  10598   Glenn     return (0);
    184      0  stevel }
    185      0  stevel 
    186      0  stevel 
    187      0  stevel /*
    188      0  stevel  *  glue routine for get_mech_type
    189      0  stevel  *
    190      0  stevel  */
    191  10598   Glenn 
    192  10598   Glenn OM_uint32 gssint_get_mech_type_oid(OID, token)
    193  10598   Glenn     gss_OID		OID;
    194  10598   Glenn     gss_buffer_t	token;
    195      0  stevel {
    196  10598   Glenn     unsigned char * buffer_ptr;
    197  10598   Glenn     int length;
    198  10598   Glenn 
    199  10598   Glenn     /*
    200  10598   Glenn      * This routine reads the prefix of "token" in order to determine
    201  10598   Glenn      * its mechanism type. It assumes the encoding suggested in
    202  10598   Glenn      * Appendix B of RFC 1508. This format starts out as follows :
    203  10598   Glenn      *
    204  10598   Glenn      * tag for APPLICATION 0, Sequence[constructed, definite length]
    205  10598   Glenn      * length of remainder of token
    206  10598   Glenn      * tag of OBJECT IDENTIFIER
    207  10598   Glenn      * length of mechanism OID
    208  10598   Glenn      * encoding of mechanism OID
    209  10598   Glenn      * <the rest of the token>
    210  10598   Glenn      *
    211  10598   Glenn      * Numerically, this looks like :
    212  10598   Glenn      *
    213  10598   Glenn      * 0x60
    214  10598   Glenn      * <length> - could be multiple bytes
    215  10598   Glenn      * 0x06
    216  10598   Glenn      * <length> - assume only one byte, hence OID length < 127
    217  10598   Glenn      * <mech OID bytes>
    218  10598   Glenn      *
    219  10598   Glenn      * The routine fills in the OID value and returns an error as necessary.
    220  10598   Glenn      */
    221  10598   Glenn 
    222      0  stevel 	if (OID == NULL)
    223      0  stevel 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
    224      0  stevel 
    225      0  stevel 	if ((token == NULL) || (token->value == NULL))
    226  10598   Glenn 	return (GSS_S_DEFECTIVE_TOKEN);
    227  10598   Glenn 
    228  10598   Glenn     /* Skip past the APP/Sequnce byte and the token length */
    229  10598   Glenn 
    230  10598   Glenn     buffer_ptr = (unsigned char *) token->value;
    231      0  stevel 
    232  10598   Glenn     if (*(buffer_ptr++) != 0x60)
    233  10598   Glenn 	return (GSS_S_DEFECTIVE_TOKEN);
    234  10598   Glenn     length = *buffer_ptr++;
    235      0  stevel 
    236      0  stevel 	/* check if token length is null */
    237      0  stevel 	if (length == 0)
    238      0  stevel 	    return (GSS_S_DEFECTIVE_TOKEN);
    239      0  stevel 
    240  10598   Glenn     if (length & 0x80) {
    241  10598   Glenn 	if ((length & 0x7f) > 4)
    242  10598   Glenn 	    return (GSS_S_DEFECTIVE_TOKEN);
    243  10598   Glenn 	buffer_ptr += length & 0x7f;
    244  10598   Glenn     }
    245  10598   Glenn 
    246  10598   Glenn     if (*(buffer_ptr++) != 0x06)
    247  10598   Glenn 	return (GSS_S_DEFECTIVE_TOKEN);
    248  10598   Glenn 
    249  10598   Glenn     OID->length = (OM_uint32) *(buffer_ptr++);
    250  10598   Glenn     OID->elements = (void *) buffer_ptr;
    251  10598   Glenn     return (GSS_S_COMPLETE);
    252  10598   Glenn }
    253      0  stevel 
    254  10598   Glenn /*
    255  10598   Glenn  * The following mechanisms do not always identify themselves
    256  10598   Glenn  * per the GSS-API specification, when interoperating with MS
    257  10598   Glenn  * peers. We include the OIDs here so we do not have to link
    258  10598   Glenn  * with the mechanism.
    259  10598   Glenn  */
    260  10598   Glenn static gss_OID_desc gss_ntlm_mechanism_oid_desc =
    261  10598   Glenn 	{10, (void *)"\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"};
    262  10598   Glenn static gss_OID_desc gss_spnego_mechanism_oid_desc =
    263  10598   Glenn 	{6, (void *)"\x2b\x06\x01\x05\x05\x02"};
    264  10598   Glenn static gss_OID_desc gss_krb5_mechanism_oid_desc =
    265  10598   Glenn 	{9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"};
    266      0  stevel 
    267  10598   Glenn #define NTLMSSP_SIGNATURE "NTLMSSP"
    268  10598   Glenn 
    269  10598   Glenn OM_uint32 gssint_get_mech_type(OID, token)
    270  10598   Glenn     gss_OID		OID;
    271  10598   Glenn     gss_buffer_t	token;
    272  10598   Glenn {
    273  10598   Glenn     /* Check for interoperability exceptions */
    274  10598   Glenn     if (token->length >= sizeof(NTLMSSP_SIGNATURE) &&
    275  10598   Glenn 	memcmp(token->value, NTLMSSP_SIGNATURE,
    276  10598   Glenn 	       sizeof(NTLMSSP_SIGNATURE)) == 0) {
    277  10598   Glenn 	*OID = gss_ntlm_mechanism_oid_desc;
    278  10598   Glenn     } else if (token->length != 0 &&
    279  10598   Glenn 	       ((char *)token->value)[0] == 0x6E) {
    280  10598   Glenn  	/* Could be a raw AP-REQ (check for APPLICATION tag) */
    281  10598   Glenn 	*OID = gss_krb5_mechanism_oid_desc;
    282  10598   Glenn     } else if (token->length == 0) {
    283  10598   Glenn 	*OID = gss_spnego_mechanism_oid_desc;
    284  10598   Glenn     } else {
    285  10598   Glenn 	return gssint_get_mech_type_oid(OID, token);
    286  10598   Glenn     }
    287  10598   Glenn 
    288  10598   Glenn     return (GSS_S_COMPLETE);
    289      0  stevel }
    290      0  stevel 
    291      0  stevel 
    292      0  stevel /*
    293      0  stevel  *  Internal routines to get and release an internal mechanism name
    294      0  stevel  */
    295  10598   Glenn 
    296  10598   Glenn #if 0 /* SUNW17PACresync */
    297  10598   Glenn #include "mglueP.h"
    298  10598   Glenn #endif
    299  10598   Glenn 
    300  10598   Glenn OM_uint32 gssint_import_internal_name (minor_status, mech_type, union_name,
    301  10598   Glenn 				internal_name)
    302      0  stevel OM_uint32		*minor_status;
    303  10598   Glenn gss_OID			mech_type;
    304      0  stevel gss_union_name_t	union_name;
    305      0  stevel gss_name_t		*internal_name;
    306      0  stevel {
    307  10598   Glenn     OM_uint32		status;
    308  10598   Glenn     gss_mechanism	mech;
    309      0  stevel 
    310  10598   Glenn     mech = gssint_get_mechanism (mech_type);
    311  10598   Glenn     if (mech) {
    312  10598   Glenn 	if (mech->gss_import_name) {
    313  10598   Glenn 	    status = mech->gss_import_name (
    314  10598   Glenn 		    mech->context, /* SUNW17PACresync */
    315  10598   Glenn 					    minor_status,
    316  10598   Glenn 					    union_name->external_name,
    317  10598   Glenn 					    union_name->name_type,
    318  10598   Glenn 					    internal_name);
    319  10598   Glenn 	    if (status != GSS_S_COMPLETE)
    320  10598   Glenn 		map_error(minor_status, mech);
    321  10598   Glenn 	} else
    322  10598   Glenn 	    status = GSS_S_UNAVAILABLE;
    323      0  stevel 
    324  10598   Glenn 	return (status);
    325  10598   Glenn     }
    326      0  stevel 
    327  10598   Glenn     return (GSS_S_BAD_MECH);
    328      0  stevel }
    329      0  stevel 
    330  10598   Glenn OM_uint32 gssint_export_internal_name(minor_status, mech_type,
    331  10598   Glenn 				     internal_name, name_buf)
    332  10598   Glenn     OM_uint32		*minor_status;
    333  10598   Glenn     const gss_OID		mech_type;
    334  10598   Glenn     const gss_name_t	internal_name;
    335  10598   Glenn     gss_buffer_t		name_buf;
    336  10598   Glenn {
    337  10598   Glenn     OM_uint32 status;
    338  10598   Glenn     gss_mechanism mech;
    339  10598   Glenn     gss_buffer_desc dispName;
    340  10598   Glenn     gss_OID nameOid;
    341  10598   Glenn     unsigned char *buf = NULL;
    342  10598   Glenn     const unsigned char tokId[] = "\x04\x01";
    343  10598   Glenn     const unsigned int tokIdLen = 2;
    344  10598   Glenn     const int mechOidLenLen = 2, mechOidTagLen = 1, nameLenLen = 4;
    345  10598   Glenn     int mechOidDERLen = 0;
    346  10598   Glenn     int mechOidLen = 0;
    347      0  stevel 
    348  10598   Glenn     mech = gssint_get_mechanism(mech_type);
    349  10598   Glenn     if (!mech)
    350  10598   Glenn 	return (GSS_S_BAD_MECH);
    351  10598   Glenn 
    352  10598   Glenn     if (mech->gss_export_name) {
    353  10598   Glenn 	status = mech->gss_export_name(
    354  10598   Glenn 		mech->context,  /* SUNW17PACresync */
    355  10598   Glenn 		minor_status,
    356  10598   Glenn 		internal_name,
    357  10598   Glenn 		name_buf);
    358  10598   Glenn 	if (status != GSS_S_COMPLETE)
    359  10598   Glenn 	    map_error(minor_status, mech);
    360  10598   Glenn 	return status;
    361  10598   Glenn     }
    362  10598   Glenn 
    363  10598   Glenn     /*
    364  10598   Glenn      * if we are here it is because the mechanism does not provide
    365  10598   Glenn      * a gss_export_name so we will use our implementation.  We
    366  10598   Glenn      * do required that the mechanism define a gss_display_name.
    367  10598   Glenn      */
    368  10598   Glenn     if (!mech->gss_display_name)
    369  10598   Glenn 	return (GSS_S_UNAVAILABLE);
    370  10598   Glenn 
    371  10598   Glenn     /*
    372  10598   Glenn      * NOTE: RFC2743 (section 3.2) governs the format of the outer
    373  10598   Glenn      *	 wrapper of exported names; the mechanisms' specs govern
    374  10598   Glenn      *	 the format of the inner portion of the exported name
    375  10598   Glenn      *	 and, for some (e.g., RFC1964, the Kerberos V mech), a
    376  10598   Glenn      *	 generic default as implemented here will do.
    377  10598   Glenn      *
    378  10598   Glenn      * The outer wrapper of an exported MN is: 2-octet tok Id
    379  10598   Glenn      * (0x0401) + 2-octet network-byte order mech OID length + mech
    380  10598   Glenn      * oid (in DER format, including DER tag and DER length) +
    381  10598   Glenn      * 4-octet network-byte order length of inner portion + inner
    382  10598   Glenn      * portion.
    383  10598   Glenn      *
    384  10598   Glenn      * For the Kerberos V mechanism the inner portion of an exported
    385  10598   Glenn      * MN is the display name string and ignores the name type OID
    386  10598   Glenn      * altogether.  And we hope this will be so for any future
    387  10598   Glenn      * mechanisms also, so that factoring name export/import out of
    388  10598   Glenn      * the mech and into libgss pays off.
    389  10598   Glenn      */
    390  10598   Glenn     if ((status = mech->gss_display_name(
    391  10598   Glenn 		mech->context,
    392  10598   Glenn 		minor_status,
    393  10598   Glenn 					 internal_name,
    394  10598   Glenn 					 &dispName,
    395  10598   Glenn 					 &nameOid))
    396  10598   Glenn 	!= GSS_S_COMPLETE) {
    397  10598   Glenn 	map_error(minor_status, mech);
    398  10598   Glenn 	return (status);
    399  10598   Glenn     }
    400  10598   Glenn 
    401  10598   Glenn     /* determine the size of the buffer needed */
    402  10598   Glenn     mechOidDERLen = gssint_der_length_size(mech_type->length);
    403  10598   Glenn     name_buf->length = tokIdLen + mechOidLenLen +
    404  10598   Glenn 	mechOidTagLen + mechOidDERLen +
    405  10598   Glenn 	mech_type->length +
    406  10598   Glenn 	nameLenLen + dispName.length;
    407  10598   Glenn     if ((name_buf->value = (void*)malloc(name_buf->length)) ==
    408  10598   Glenn 	(void*)NULL) {
    409  10598   Glenn 	name_buf->length = 0;
    410  10598   Glenn 	(void) gss_release_buffer(&status, &dispName);
    411  10598   Glenn 	return (GSS_S_FAILURE);
    412  10598   Glenn     }
    413  10598   Glenn 
    414  10598   Glenn     /* now create the name ..... */
    415  10598   Glenn     buf = (unsigned char *)name_buf->value;
    416  10598   Glenn     (void) memset(name_buf->value, 0, name_buf->length);
    417  10598   Glenn     (void) memcpy(buf, tokId, tokIdLen);
    418  10598   Glenn     buf += tokIdLen;
    419  10598   Glenn 
    420  10598   Glenn     /* spec allows only 2 bytes for the mech oid length */
    421  10598   Glenn     mechOidLen = mechOidDERLen + mechOidTagLen + mech_type->length;
    422  10598   Glenn     store_16_be(mechOidLen, buf);
    423  10598   Glenn     buf += 2;
    424  10598   Glenn 
    425  10598   Glenn     /*
    426  10598   Glenn      * DER Encoding of mech OID contains OID Tag (0x06), length and
    427  10598   Glenn      * mech OID value
    428  10598   Glenn      */
    429  10598   Glenn     *buf++ = 0x06;
    430  10598   Glenn     if (gssint_put_der_length(mech_type->length, &buf,
    431  10598   Glenn 		       (name_buf->length - tokIdLen -2)) != 0) {
    432  10598   Glenn 	name_buf->length = 0;
    433  10598   Glenn 	free(name_buf->value);
    434  10598   Glenn 	(void) gss_release_buffer(&status, &dispName);
    435  10598   Glenn 	return (GSS_S_FAILURE);
    436  10598   Glenn     }
    437  10598   Glenn 
    438  10598   Glenn     (void) memcpy(buf, mech_type->elements, mech_type->length);
    439  10598   Glenn     buf += mech_type->length;
    440  10598   Glenn 
    441  10598   Glenn     /* spec designates the next 4 bytes for the name length */
    442  10598   Glenn     store_32_be(dispName.length, buf);
    443  10598   Glenn     buf += 4;
    444  10598   Glenn 
    445  10598   Glenn     /* for the final ingredient - add the name from gss_display_name */
    446  10598   Glenn     (void) memcpy(buf, dispName.value, dispName.length);
    447  10598   Glenn 
    448  10598   Glenn     /* release the buffer obtained from gss_display_name */
    449  10598   Glenn     (void) gss_release_buffer(minor_status, &dispName);
    450  10598   Glenn     return (GSS_S_COMPLETE);
    451  10598   Glenn } /*  gssint_export_internal_name */
    452  10598   Glenn 
    453  10598   Glenn OM_uint32 gssint_display_internal_name (minor_status, mech_type, internal_name,
    454  10598   Glenn 				 external_name, name_type)
    455  10598   Glenn OM_uint32	*minor_status;
    456  10598   Glenn gss_OID		mech_type;
    457  10598   Glenn gss_name_t	internal_name;
    458  10598   Glenn gss_buffer_t	external_name;
    459  10598   Glenn gss_OID		*name_type;
    460      0  stevel {
    461  10598   Glenn     OM_uint32		status;
    462  10598   Glenn     gss_mechanism	mech;
    463      0  stevel 
    464  10598   Glenn     mech = gssint_get_mechanism (mech_type);
    465  10598   Glenn     if (mech) {
    466  10598   Glenn 	if (mech->gss_display_name) {
    467  10598   Glenn 	    status = mech->gss_display_name (
    468  10598   Glenn 		    mech->context,
    469  10598   Glenn 					     minor_status,
    470  10598   Glenn 					     internal_name,
    471  10598   Glenn 					     external_name,
    472  10598   Glenn 					     name_type);
    473  10598   Glenn 	    if (status != GSS_S_COMPLETE)
    474  10598   Glenn 		map_error(minor_status, mech);
    475  10598   Glenn 	} else
    476  10598   Glenn 	    status = GSS_S_UNAVAILABLE;
    477      0  stevel 
    478  10598   Glenn 	return (status);
    479  10598   Glenn     }
    480      0  stevel 
    481  10598   Glenn     return (GSS_S_BAD_MECH);
    482      0  stevel }
    483      0  stevel 
    484  10598   Glenn OM_uint32 gssint_release_internal_name (minor_status, mech_type, internal_name)
    485  10598   Glenn OM_uint32	*minor_status;
    486  10598   Glenn gss_OID		mech_type;
    487  10598   Glenn gss_name_t	*internal_name;
    488      0  stevel {
    489  10598   Glenn     OM_uint32		status;
    490  10598   Glenn     gss_mechanism	mech;
    491      0  stevel 
    492  10598   Glenn     mech = gssint_get_mechanism (mech_type);
    493  10598   Glenn     if (mech) {
    494  10598   Glenn 	if (mech->gss_release_name) {
    495  10598   Glenn 	    status = mech->gss_release_name (
    496  10598   Glenn 		    mech->context,
    497  10598   Glenn 					     minor_status,
    498  10598   Glenn 					     internal_name);
    499  10598   Glenn 	    if (status != GSS_S_COMPLETE)
    500  10598   Glenn 		map_error(minor_status, mech);
    501  10598   Glenn 	} else
    502  10598   Glenn 	    status = GSS_S_UNAVAILABLE;
    503      0  stevel 
    504  10598   Glenn 	return (status);
    505  10598   Glenn     }
    506      0  stevel 
    507  10598   Glenn     return (GSS_S_BAD_MECH);
    508      0  stevel }
    509      0  stevel 
    510  10598   Glenn OM_uint32 gssint_delete_internal_sec_context (minor_status,
    511  10598   Glenn 					      mech_type,
    512  10598   Glenn 					      internal_ctx,
    513  10598   Glenn 					      output_token)
    514  10598   Glenn OM_uint32	*minor_status;
    515  10598   Glenn gss_OID		mech_type;
    516  10598   Glenn gss_ctx_id_t	*internal_ctx;
    517  10598   Glenn gss_buffer_t	output_token;
    518  10598   Glenn {
    519  10598   Glenn     OM_uint32		status;
    520  10598   Glenn     gss_mechanism	mech;
    521  10598   Glenn 
    522  10598   Glenn     mech = gssint_get_mechanism (mech_type);
    523  10598   Glenn     if (mech) {
    524  10598   Glenn 	if (mech->gss_delete_sec_context)
    525  10598   Glenn 	    status = mech->gss_delete_sec_context (
    526  10598   Glenn 		    mech->context,  /* SUNW17PACresync */
    527  10598   Glenn 		    minor_status,
    528  10598   Glenn 		    internal_ctx,
    529  10598   Glenn 		    output_token);
    530  10598   Glenn 	else
    531  10598   Glenn 	    /* SUNW17PACresync - map error here? */
    532  10598   Glenn 	    status = GSS_S_UNAVAILABLE;
    533  10598   Glenn 
    534  10598   Glenn 	return (status);
    535  10598   Glenn     }
    536  10598   Glenn 
    537  10598   Glenn     return (GSS_S_BAD_MECH);
    538  10598   Glenn }
    539      0  stevel 
    540      0  stevel /*
    541      0  stevel  * This function converts an internal gssapi name to a union gssapi
    542      0  stevel  * name.  Note that internal_name should be considered "consumed" by
    543      0  stevel  * this call, whether or not we return an error.
    544      0  stevel  */
    545  10598   Glenn OM_uint32 gssint_convert_name_to_union_name(minor_status, mech,
    546  10598   Glenn 					   internal_name, external_name)
    547  10598   Glenn     OM_uint32 *minor_status;
    548  10598   Glenn     gss_mechanism	mech;
    549  10598   Glenn     gss_name_t	internal_name;
    550  10598   Glenn     gss_name_t	*external_name;
    551      0  stevel {
    552  10598   Glenn     OM_uint32 major_status,tmp;
    553  10598   Glenn     gss_union_name_t union_name;
    554      0  stevel 
    555  10598   Glenn     union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc));
    556  10598   Glenn     if (!union_name) {
    557  10598   Glenn 	major_status = GSS_S_FAILURE;
    558  10598   Glenn 	*minor_status = ENOMEM;
    559  10598   Glenn 	map_errcode(minor_status);
    560  10598   Glenn 	goto allocation_failure;
    561  10598   Glenn     }
    562  10598   Glenn     union_name->mech_type = 0;
    563  10598   Glenn     union_name->mech_name = internal_name;
    564  10598   Glenn     union_name->name_type = 0;
    565  10598   Glenn     union_name->external_name = 0;
    566      0  stevel 
    567  10598   Glenn     major_status = generic_gss_copy_oid(minor_status, &mech->mech_type,
    568  10598   Glenn 					&union_name->mech_type);
    569  10598   Glenn     if (major_status != GSS_S_COMPLETE) {
    570  10598   Glenn 	map_errcode(minor_status);
    571  10598   Glenn 	goto allocation_failure;
    572  10598   Glenn     }
    573      0  stevel 
    574  10598   Glenn     union_name->external_name =
    575  10598   Glenn 	(gss_buffer_t) malloc(sizeof(gss_buffer_desc));
    576  10598   Glenn     if (!union_name->external_name) {
    577  10598   Glenn 	    major_status = GSS_S_FAILURE;
    578  10598   Glenn 	    *minor_status = ENOMEM;
    579  10598   Glenn 	    goto allocation_failure;
    580  10598   Glenn     }
    581  10598   Glenn 
    582  10598   Glenn     major_status = mech->gss_display_name(
    583  10598   Glenn 	    mech->context,  /* SUNW17PACresync */
    584  10598   Glenn 	    minor_status,
    585  10598   Glenn 	    internal_name,
    586  10598   Glenn 	    union_name->external_name,
    587  10598   Glenn 	    &union_name->name_type);
    588  10598   Glenn     if (major_status != GSS_S_COMPLETE) {
    589  10598   Glenn 	map_error(minor_status, mech);
    590  10598   Glenn 	goto allocation_failure;
    591  10598   Glenn     }
    592      0  stevel 
    593  10598   Glenn     union_name->loopback = union_name;
    594  10598   Glenn     *external_name = (gss_name_t) union_name;
    595  10598   Glenn     return (GSS_S_COMPLETE);
    596      0  stevel 
    597      0  stevel allocation_failure:
    598  10598   Glenn     if (union_name) {
    599  10598   Glenn 	if (union_name->external_name) {
    600  10598   Glenn 	    if (union_name->external_name->value)
    601  10598   Glenn 		free(union_name->external_name->value);
    602  10598   Glenn 	    free(union_name->external_name);
    603      0  stevel 	}
    604  10598   Glenn 	if (union_name->name_type)
    605  10598   Glenn 		(void) gss_release_oid(&tmp, &union_name->name_type);
    606  10598   Glenn 	if (union_name->mech_type)
    607  10598   Glenn 		(void) gss_release_oid(&tmp, &union_name->mech_type);
    608  10598   Glenn 	free(union_name);
    609  10598   Glenn     }
    610  10598   Glenn     /*
    611  10598   Glenn      * do as the top comment says - since we are now owners of
    612  10598   Glenn      * internal_name, we must clean it up
    613  10598   Glenn      */
    614  10598   Glenn     if (internal_name)
    615  10598   Glenn 	(void) gssint_release_internal_name(&tmp, &mech->mech_type,
    616  10598   Glenn 					   &internal_name);
    617  10598   Glenn     return (major_status);
    618      0  stevel }
    619      0  stevel 
    620      0  stevel /*
    621      0  stevel  * Glue routine for returning the mechanism-specific credential from a
    622      0  stevel  * external union credential.
    623      0  stevel  */
    624      0  stevel gss_cred_id_t
    625  10598   Glenn gssint_get_mechanism_cred(union_cred, mech_type)
    626  10598   Glenn     gss_union_cred_t	union_cred;
    627  10598   Glenn     gss_OID		mech_type;
    628      0  stevel {
    629  10598   Glenn     int		i;
    630      0  stevel 
    631  10598   Glenn     if (union_cred == (gss_union_cred_t) GSS_C_NO_CREDENTIAL)
    632  10598   Glenn 	return GSS_C_NO_CREDENTIAL;
    633      0  stevel 
    634  10598   Glenn     /*
    635  10598   Glenn      * SUNW17PACresync
    636  10598   Glenn      * Disable this block as it causes problems for gss_add_cred
    637  10598   Glenn      * for HTTP SSO (and also probably causes STC gss.13 to fail too).
    638  10598   Glenn      */
    639  10598   Glenn #if 0
    640  10598   Glenn     /* SPNEGO mechanism will again call into GSSAPI */
    641  10598   Glenn     if (g_OID_equal(&gss_spnego_mechanism_oid_desc, mech_type))
    642  10598   Glenn 	return (gss_cred_id_t)union_cred;
    643  10598   Glenn #endif
    644  10598   Glenn 
    645  10598   Glenn     for (i=0; i < union_cred->count; i++) {
    646  10598   Glenn 	if (g_OID_equal(mech_type, &union_cred->mechs_array[i]))
    647  10598   Glenn 	    return union_cred->cred_array[i];
    648  10598   Glenn 
    649  10598   Glenn 	/* for SPNEGO, check the next-lower set of creds */
    650  10598   Glenn 	if (g_OID_equal(&gss_spnego_mechanism_oid_desc, &union_cred->mechs_array[i])) {
    651  10598   Glenn 	    gss_union_cred_t candidate_cred;
    652  10598   Glenn 	    gss_cred_id_t    sub_cred;
    653  10598   Glenn 
    654  10598   Glenn 	    candidate_cred = (gss_union_cred_t)union_cred->cred_array[i];
    655  10598   Glenn 	    sub_cred = gssint_get_mechanism_cred(candidate_cred, mech_type);
    656  10598   Glenn 
    657  10598   Glenn 	    if(sub_cred != GSS_C_NO_CREDENTIAL)
    658  10598   Glenn 		return sub_cred;
    659      0  stevel 	}
    660  10598   Glenn     }
    661  10598   Glenn 
    662  10598   Glenn     return GSS_C_NO_CREDENTIAL;
    663      0  stevel }
    664      0  stevel 
    665      0  stevel /*
    666      0  stevel  * Routine to create and copy the gss_buffer_desc structure.
    667      0  stevel  * Both space for the structure and the data is allocated.
    668      0  stevel  */
    669      0  stevel OM_uint32
    670   5053     gtb gssint_create_copy_buffer(srcBuf, destBuf, addNullChar)
    671  10598   Glenn     const gss_buffer_t	srcBuf;
    672  10598   Glenn     gss_buffer_t 		*destBuf;
    673  10598   Glenn     int			addNullChar;
    674      0  stevel {
    675  10598   Glenn     gss_buffer_t aBuf;
    676  10598   Glenn     unsigned int len;
    677      0  stevel 
    678  10598   Glenn     if (destBuf == NULL)
    679  10598   Glenn 	return (GSS_S_CALL_INACCESSIBLE_WRITE);
    680      0  stevel 
    681  10598   Glenn     *destBuf = 0;
    682      0  stevel 
    683  10598   Glenn     aBuf = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
    684  10598   Glenn     if (!aBuf)
    685  10598   Glenn 	return (GSS_S_FAILURE);
    686      0  stevel 
    687  10598   Glenn     if (addNullChar)
    688  10598   Glenn 	len = srcBuf->length + 1;
    689  10598   Glenn     else
    690  10598   Glenn 	len = srcBuf->length;
    691      0  stevel 
    692  10598   Glenn     if (!(aBuf->value = (void*)malloc(len))) {
    693  10598   Glenn 	free(aBuf);
    694  10598   Glenn 	return (GSS_S_FAILURE);
    695  10598   Glenn     }
    696      0  stevel 
    697      0  stevel 
    698  10598   Glenn     (void) memcpy(aBuf->value, srcBuf->value, srcBuf->length);
    699  10598   Glenn     aBuf->length = srcBuf->length;
    700  10598   Glenn     *destBuf = aBuf;
    701      0  stevel 
    702  10598   Glenn     /* optionally add a NULL character */
    703  10598   Glenn     if (addNullChar)
    704  10598   Glenn 	((char *)aBuf->value)[aBuf->length] = '\0';
    705      0  stevel 
    706  10598   Glenn     return (GSS_S_COMPLETE);
    707  10598   Glenn } /* ****** gssint_create_copy_buffer  ****** */
    708  10598   Glenn 
    709