10Sstevel@tonic-gate /* 212360SMark.Phalan@Sun.COM * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. 30Sstevel@tonic-gate */ 40Sstevel@tonic-gate 510598SGlenn.Barry@Sun.COM #include "mglueP.h" 6*13132SGlenn.Barry@oracle.com #include "gssapiP_generic.h" 70Sstevel@tonic-gate #include <stdio.h> 810598SGlenn.Barry@Sun.COM #ifdef HAVE_STDLIB_H 90Sstevel@tonic-gate #include <stdlib.h> 1010598SGlenn.Barry@Sun.COM #endif 1110598SGlenn.Barry@Sun.COM #include <string.h> 120Sstevel@tonic-gate #include <errno.h> 130Sstevel@tonic-gate 1410598SGlenn.Barry@Sun.COM #include "k5-platform-store_32.h" 1510598SGlenn.Barry@Sun.COM #include "k5-platform-store_16.h" 1610598SGlenn.Barry@Sun.COM /* 1710598SGlenn.Barry@Sun.COM * SUNW17PACresync 1810598SGlenn.Barry@Sun.COM * MIT has diff names for these GSS utilities. Solaris needs to change 1910598SGlenn.Barry@Sun.COM * them globally to get in sync w/MIT. 2010598SGlenn.Barry@Sun.COM * Revisit for full 1.7 resync. 2110598SGlenn.Barry@Sun.COM */ 2210598SGlenn.Barry@Sun.COM #define gssint_get_modOptions __gss_get_modOptions 2310598SGlenn.Barry@Sun.COM #define gssint_der_length_size der_length_size 2410598SGlenn.Barry@Sun.COM #define gssint_get_der_length get_der_length 2510598SGlenn.Barry@Sun.COM #define gssint_put_der_length put_der_length 2610598SGlenn.Barry@Sun.COM #define gssint_get_mechanism __gss_get_mechanism 2710598SGlenn.Barry@Sun.COM #define gssint_get_mechanism_cred __gss_get_mechanism_cred 2810598SGlenn.Barry@Sun.COM #define gssint_copy_oid_set gss_copy_oid_set 2910598SGlenn.Barry@Sun.COM #define gssint_get_mech_type __gss_get_mech_type 3010598SGlenn.Barry@Sun.COM #define gssint_export_internal_name __gss_export_internal_name 3110598SGlenn.Barry@Sun.COM #define gssint_release_internal_name __gss_release_internal_name 3210598SGlenn.Barry@Sun.COM #define gssint_convert_name_to_union_name __gss_convert_name_to_union_name 3310598SGlenn.Barry@Sun.COM #define gssint_import_internal_name __gss_import_internal_name 3410598SGlenn.Barry@Sun.COM #define gssint_display_internal_name __gss_display_internal_name 3510598SGlenn.Barry@Sun.COM 3610598SGlenn.Barry@Sun.COM 370Sstevel@tonic-gate #define MSO_BIT (8*(sizeof (int) - 1)) /* Most significant octet bit */ 380Sstevel@tonic-gate 3910598SGlenn.Barry@Sun.COM extern gss_mechanism *gssint_mechs_array; 4010598SGlenn.Barry@Sun.COM 410Sstevel@tonic-gate /* 420Sstevel@tonic-gate * This file contains the support routines for the glue layer. 430Sstevel@tonic-gate */ 440Sstevel@tonic-gate 450Sstevel@tonic-gate /* 460Sstevel@tonic-gate * get_der_length: Givin a pointer to a buffer that contains a DER encoded 470Sstevel@tonic-gate * length, decode the length updating the buffer to point to the character 480Sstevel@tonic-gate * after the DER encoding. The parameter bytes will point to the number of 490Sstevel@tonic-gate * bytes that made up the DER encoding of the length originally pointed to 500Sstevel@tonic-gate * by the buffer. Note we return -1 on error. 510Sstevel@tonic-gate */ 520Sstevel@tonic-gate int 5310598SGlenn.Barry@Sun.COM gssint_get_der_length(unsigned char **buf, unsigned int buf_len, unsigned int *bytes) 540Sstevel@tonic-gate { 5510598SGlenn.Barry@Sun.COM /* p points to the beginning of the buffer */ 5610598SGlenn.Barry@Sun.COM unsigned char *p = *buf; 5710598SGlenn.Barry@Sun.COM int length, new_length; 5810598SGlenn.Barry@Sun.COM unsigned int octets; 590Sstevel@tonic-gate 6010598SGlenn.Barry@Sun.COM if (buf_len < 1) 6110598SGlenn.Barry@Sun.COM return (-1); 620Sstevel@tonic-gate 6310598SGlenn.Barry@Sun.COM /* We should have at least one byte */ 6410598SGlenn.Barry@Sun.COM *bytes = 1; 650Sstevel@tonic-gate 6610598SGlenn.Barry@Sun.COM /* 6710598SGlenn.Barry@Sun.COM * If the High order bit is not set then the length is just the value 6810598SGlenn.Barry@Sun.COM * of *p. 6910598SGlenn.Barry@Sun.COM */ 7010598SGlenn.Barry@Sun.COM if (*p < 128) { 7110598SGlenn.Barry@Sun.COM *buf = p+1; /* Advance the buffer */ 720Sstevel@tonic-gate return (*p); /* return the length */ 7310598SGlenn.Barry@Sun.COM } 740Sstevel@tonic-gate 7510598SGlenn.Barry@Sun.COM /* 7610598SGlenn.Barry@Sun.COM * if the High order bit is set, then the low order bits represent 7710598SGlenn.Barry@Sun.COM * the number of bytes that contain the DER encoding of the length. 7810598SGlenn.Barry@Sun.COM */ 790Sstevel@tonic-gate 8010598SGlenn.Barry@Sun.COM octets = *p++ & 0x7f; 8110598SGlenn.Barry@Sun.COM *bytes += octets; 820Sstevel@tonic-gate 8310598SGlenn.Barry@Sun.COM /* See if the supplied buffer contains enough bytes for the length. */ 8410598SGlenn.Barry@Sun.COM if (octets > buf_len - 1) 8510598SGlenn.Barry@Sun.COM return (-1); 860Sstevel@tonic-gate 8710598SGlenn.Barry@Sun.COM /* 8810598SGlenn.Barry@Sun.COM * Calculate a multibyte length. The length is encoded as an 8910598SGlenn.Barry@Sun.COM * unsigned integer base 256. 9010598SGlenn.Barry@Sun.COM */ 9110598SGlenn.Barry@Sun.COM for (length = 0; octets; octets--) { 9210598SGlenn.Barry@Sun.COM new_length = (length << 8) + *p++; 9310598SGlenn.Barry@Sun.COM if (new_length < length) /* overflow */ 9410598SGlenn.Barry@Sun.COM return (-1); 9510598SGlenn.Barry@Sun.COM length = new_length; 9610598SGlenn.Barry@Sun.COM } 970Sstevel@tonic-gate 9810598SGlenn.Barry@Sun.COM *buf = p; /* Advance the buffer */ 990Sstevel@tonic-gate 10010598SGlenn.Barry@Sun.COM return (length); 1010Sstevel@tonic-gate } 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate /* 1040Sstevel@tonic-gate * der_length_size: Return the number of bytes to encode a given length. 1050Sstevel@tonic-gate */ 1060Sstevel@tonic-gate unsigned int 10710598SGlenn.Barry@Sun.COM gssint_der_length_size(unsigned int len) 1080Sstevel@tonic-gate { 10910598SGlenn.Barry@Sun.COM int i; 1100Sstevel@tonic-gate 11110598SGlenn.Barry@Sun.COM if (len < 128) 11210598SGlenn.Barry@Sun.COM return (1); 1130Sstevel@tonic-gate 11410598SGlenn.Barry@Sun.COM for (i = 0; len; i++) { 11510598SGlenn.Barry@Sun.COM len >>= 8; 11610598SGlenn.Barry@Sun.COM } 1170Sstevel@tonic-gate 11810598SGlenn.Barry@Sun.COM return (i+1); 1190Sstevel@tonic-gate } 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate /* 1220Sstevel@tonic-gate * put_der_length: Encode the supplied length into the buffer pointed to 1230Sstevel@tonic-gate * by buf. max_length represents the maximum length of the buffer pointed 1240Sstevel@tonic-gate * to by buff. We will advance buf to point to the character after the newly 1250Sstevel@tonic-gate * DER encoded length. We return 0 on success or -l it the length cannot 1260Sstevel@tonic-gate * be encoded in max_len characters. 1270Sstevel@tonic-gate */ 1280Sstevel@tonic-gate int 12910598SGlenn.Barry@Sun.COM gssint_put_der_length(unsigned int length, unsigned char **buf, unsigned int max_len) 1300Sstevel@tonic-gate { 13110598SGlenn.Barry@Sun.COM unsigned char *s, *p; 13210598SGlenn.Barry@Sun.COM unsigned int buf_len = 0; 13310598SGlenn.Barry@Sun.COM int i, first; 1340Sstevel@tonic-gate 13510598SGlenn.Barry@Sun.COM /* Oops */ 13610598SGlenn.Barry@Sun.COM if (buf == 0 || max_len < 1) 13710598SGlenn.Barry@Sun.COM return (-1); 13810598SGlenn.Barry@Sun.COM 13910598SGlenn.Barry@Sun.COM s = *buf; 1400Sstevel@tonic-gate 14110598SGlenn.Barry@Sun.COM /* Single byte is the length */ 14210598SGlenn.Barry@Sun.COM if (length < 128) { 14310598SGlenn.Barry@Sun.COM *s++ = length; 14410598SGlenn.Barry@Sun.COM *buf = s; 14510598SGlenn.Barry@Sun.COM return (0); 14610598SGlenn.Barry@Sun.COM } 1470Sstevel@tonic-gate 14810598SGlenn.Barry@Sun.COM /* First byte contains the number of octets */ 14910598SGlenn.Barry@Sun.COM p = s + 1; 1500Sstevel@tonic-gate 15110598SGlenn.Barry@Sun.COM /* Running total of the DER encoding length */ 15210598SGlenn.Barry@Sun.COM buf_len = 0; 1530Sstevel@tonic-gate 15410598SGlenn.Barry@Sun.COM /* 15510598SGlenn.Barry@Sun.COM * Encode MSB first. We do the encoding by setting a shift 15610598SGlenn.Barry@Sun.COM * factor to MSO_BIT (24 for 32 bit words) and then shifting the length 15710598SGlenn.Barry@Sun.COM * by the factor. We then encode the resulting low order byte. 15810598SGlenn.Barry@Sun.COM * We subtract 8 from the shift factor and repeat to ecnode the next 15910598SGlenn.Barry@Sun.COM * byte. We stop when the shift factor is zero or we've run out of 16010598SGlenn.Barry@Sun.COM * buffer to encode into. 16110598SGlenn.Barry@Sun.COM */ 16210598SGlenn.Barry@Sun.COM first = 0; 16310598SGlenn.Barry@Sun.COM for (i = MSO_BIT; i >= 0 && buf_len <= max_len; i -= 8) { 16410598SGlenn.Barry@Sun.COM unsigned int v; 16510598SGlenn.Barry@Sun.COM v = (length >> i) & 0xff; 16610598SGlenn.Barry@Sun.COM if ((v) || first) { 16710598SGlenn.Barry@Sun.COM buf_len += 1; 16810598SGlenn.Barry@Sun.COM *p++ = v; 16910598SGlenn.Barry@Sun.COM first = 1; 1700Sstevel@tonic-gate } 17110598SGlenn.Barry@Sun.COM } 17210598SGlenn.Barry@Sun.COM if (i >= 0) /* buffer overflow */ 17310598SGlenn.Barry@Sun.COM return (-1); 1740Sstevel@tonic-gate 17510598SGlenn.Barry@Sun.COM /* 17610598SGlenn.Barry@Sun.COM * We go back now and set the first byte to be the length with 17710598SGlenn.Barry@Sun.COM * the high order bit set. 17810598SGlenn.Barry@Sun.COM */ 17910598SGlenn.Barry@Sun.COM *s = buf_len | 0x80; 18010598SGlenn.Barry@Sun.COM *buf = p; 1810Sstevel@tonic-gate 18210598SGlenn.Barry@Sun.COM return (0); 1830Sstevel@tonic-gate } 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate /* 1870Sstevel@tonic-gate * glue routine for get_mech_type 1880Sstevel@tonic-gate * 1890Sstevel@tonic-gate */ 19010598SGlenn.Barry@Sun.COM 19110598SGlenn.Barry@Sun.COM OM_uint32 gssint_get_mech_type_oid(OID, token) 19210598SGlenn.Barry@Sun.COM gss_OID OID; 19310598SGlenn.Barry@Sun.COM gss_buffer_t token; 1940Sstevel@tonic-gate { 19510598SGlenn.Barry@Sun.COM unsigned char * buffer_ptr; 19610598SGlenn.Barry@Sun.COM int length; 19710598SGlenn.Barry@Sun.COM 19810598SGlenn.Barry@Sun.COM /* 19910598SGlenn.Barry@Sun.COM * This routine reads the prefix of "token" in order to determine 20010598SGlenn.Barry@Sun.COM * its mechanism type. It assumes the encoding suggested in 20110598SGlenn.Barry@Sun.COM * Appendix B of RFC 1508. This format starts out as follows : 20210598SGlenn.Barry@Sun.COM * 20310598SGlenn.Barry@Sun.COM * tag for APPLICATION 0, Sequence[constructed, definite length] 20410598SGlenn.Barry@Sun.COM * length of remainder of token 20510598SGlenn.Barry@Sun.COM * tag of OBJECT IDENTIFIER 20610598SGlenn.Barry@Sun.COM * length of mechanism OID 20710598SGlenn.Barry@Sun.COM * encoding of mechanism OID 20810598SGlenn.Barry@Sun.COM * <the rest of the token> 20910598SGlenn.Barry@Sun.COM * 21010598SGlenn.Barry@Sun.COM * Numerically, this looks like : 21110598SGlenn.Barry@Sun.COM * 21210598SGlenn.Barry@Sun.COM * 0x60 21310598SGlenn.Barry@Sun.COM * <length> - could be multiple bytes 21410598SGlenn.Barry@Sun.COM * 0x06 21510598SGlenn.Barry@Sun.COM * <length> - assume only one byte, hence OID length < 127 21610598SGlenn.Barry@Sun.COM * <mech OID bytes> 21710598SGlenn.Barry@Sun.COM * 21810598SGlenn.Barry@Sun.COM * The routine fills in the OID value and returns an error as necessary. 21910598SGlenn.Barry@Sun.COM */ 22010598SGlenn.Barry@Sun.COM 2210Sstevel@tonic-gate if (OID == NULL) 2220Sstevel@tonic-gate return (GSS_S_CALL_INACCESSIBLE_WRITE); 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate if ((token == NULL) || (token->value == NULL)) 22510598SGlenn.Barry@Sun.COM return (GSS_S_DEFECTIVE_TOKEN); 22610598SGlenn.Barry@Sun.COM 22710598SGlenn.Barry@Sun.COM /* Skip past the APP/Sequnce byte and the token length */ 22810598SGlenn.Barry@Sun.COM 22910598SGlenn.Barry@Sun.COM buffer_ptr = (unsigned char *) token->value; 2300Sstevel@tonic-gate 23110598SGlenn.Barry@Sun.COM if (*(buffer_ptr++) != 0x60) 23210598SGlenn.Barry@Sun.COM return (GSS_S_DEFECTIVE_TOKEN); 23310598SGlenn.Barry@Sun.COM length = *buffer_ptr++; 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate /* check if token length is null */ 2360Sstevel@tonic-gate if (length == 0) 2370Sstevel@tonic-gate return (GSS_S_DEFECTIVE_TOKEN); 2380Sstevel@tonic-gate 23910598SGlenn.Barry@Sun.COM if (length & 0x80) { 24010598SGlenn.Barry@Sun.COM if ((length & 0x7f) > 4) 24110598SGlenn.Barry@Sun.COM return (GSS_S_DEFECTIVE_TOKEN); 24210598SGlenn.Barry@Sun.COM buffer_ptr += length & 0x7f; 24310598SGlenn.Barry@Sun.COM } 24410598SGlenn.Barry@Sun.COM 24510598SGlenn.Barry@Sun.COM if (*(buffer_ptr++) != 0x06) 24610598SGlenn.Barry@Sun.COM return (GSS_S_DEFECTIVE_TOKEN); 24710598SGlenn.Barry@Sun.COM 24810598SGlenn.Barry@Sun.COM OID->length = (OM_uint32) *(buffer_ptr++); 24910598SGlenn.Barry@Sun.COM OID->elements = (void *) buffer_ptr; 25010598SGlenn.Barry@Sun.COM return (GSS_S_COMPLETE); 25110598SGlenn.Barry@Sun.COM } 2520Sstevel@tonic-gate 25310598SGlenn.Barry@Sun.COM /* 25410598SGlenn.Barry@Sun.COM * The following mechanisms do not always identify themselves 25510598SGlenn.Barry@Sun.COM * per the GSS-API specification, when interoperating with MS 25610598SGlenn.Barry@Sun.COM * peers. We include the OIDs here so we do not have to link 25710598SGlenn.Barry@Sun.COM * with the mechanism. 25810598SGlenn.Barry@Sun.COM */ 25910598SGlenn.Barry@Sun.COM static gss_OID_desc gss_ntlm_mechanism_oid_desc = 26010598SGlenn.Barry@Sun.COM {10, (void *)"\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"}; 26110598SGlenn.Barry@Sun.COM static gss_OID_desc gss_spnego_mechanism_oid_desc = 26210598SGlenn.Barry@Sun.COM {6, (void *)"\x2b\x06\x01\x05\x05\x02"}; 26310598SGlenn.Barry@Sun.COM static gss_OID_desc gss_krb5_mechanism_oid_desc = 26410598SGlenn.Barry@Sun.COM {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"}; 26510598SGlenn.Barry@Sun.COM 26610598SGlenn.Barry@Sun.COM #define NTLMSSP_SIGNATURE "NTLMSSP" 2670Sstevel@tonic-gate 26810598SGlenn.Barry@Sun.COM OM_uint32 gssint_get_mech_type(OID, token) 26910598SGlenn.Barry@Sun.COM gss_OID OID; 27010598SGlenn.Barry@Sun.COM gss_buffer_t token; 27110598SGlenn.Barry@Sun.COM { 27210598SGlenn.Barry@Sun.COM /* Check for interoperability exceptions */ 27310598SGlenn.Barry@Sun.COM if (token->length >= sizeof(NTLMSSP_SIGNATURE) && 27410598SGlenn.Barry@Sun.COM memcmp(token->value, NTLMSSP_SIGNATURE, 27510598SGlenn.Barry@Sun.COM sizeof(NTLMSSP_SIGNATURE)) == 0) { 27610598SGlenn.Barry@Sun.COM *OID = gss_ntlm_mechanism_oid_desc; 27710598SGlenn.Barry@Sun.COM } else if (token->length != 0 && 27810598SGlenn.Barry@Sun.COM ((char *)token->value)[0] == 0x6E) { 27910598SGlenn.Barry@Sun.COM /* Could be a raw AP-REQ (check for APPLICATION tag) */ 28010598SGlenn.Barry@Sun.COM *OID = gss_krb5_mechanism_oid_desc; 28110598SGlenn.Barry@Sun.COM } else if (token->length == 0) { 28210598SGlenn.Barry@Sun.COM *OID = gss_spnego_mechanism_oid_desc; 28310598SGlenn.Barry@Sun.COM } else { 28410598SGlenn.Barry@Sun.COM return gssint_get_mech_type_oid(OID, token); 28510598SGlenn.Barry@Sun.COM } 28610598SGlenn.Barry@Sun.COM 28710598SGlenn.Barry@Sun.COM return (GSS_S_COMPLETE); 2880Sstevel@tonic-gate } 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate /* 2920Sstevel@tonic-gate * Internal routines to get and release an internal mechanism name 2930Sstevel@tonic-gate */ 29410598SGlenn.Barry@Sun.COM 29510598SGlenn.Barry@Sun.COM #if 0 /* SUNW17PACresync */ 29610598SGlenn.Barry@Sun.COM #include "mglueP.h" 29710598SGlenn.Barry@Sun.COM #endif 29810598SGlenn.Barry@Sun.COM 29910598SGlenn.Barry@Sun.COM OM_uint32 gssint_import_internal_name (minor_status, mech_type, union_name, 30010598SGlenn.Barry@Sun.COM internal_name) 3010Sstevel@tonic-gate OM_uint32 *minor_status; 30210598SGlenn.Barry@Sun.COM gss_OID mech_type; 3030Sstevel@tonic-gate gss_union_name_t union_name; 3040Sstevel@tonic-gate gss_name_t *internal_name; 3050Sstevel@tonic-gate { 30610598SGlenn.Barry@Sun.COM OM_uint32 status; 30710598SGlenn.Barry@Sun.COM gss_mechanism mech; 3080Sstevel@tonic-gate 30910598SGlenn.Barry@Sun.COM mech = gssint_get_mechanism (mech_type); 31010598SGlenn.Barry@Sun.COM if (mech) { 31110598SGlenn.Barry@Sun.COM if (mech->gss_import_name) { 31210598SGlenn.Barry@Sun.COM status = mech->gss_import_name ( 31310598SGlenn.Barry@Sun.COM mech->context, /* SUNW17PACresync */ 31410598SGlenn.Barry@Sun.COM minor_status, 31510598SGlenn.Barry@Sun.COM union_name->external_name, 31610598SGlenn.Barry@Sun.COM union_name->name_type, 31710598SGlenn.Barry@Sun.COM internal_name); 31810598SGlenn.Barry@Sun.COM if (status != GSS_S_COMPLETE) 31910598SGlenn.Barry@Sun.COM map_error(minor_status, mech); 32010598SGlenn.Barry@Sun.COM } else 32110598SGlenn.Barry@Sun.COM status = GSS_S_UNAVAILABLE; 3220Sstevel@tonic-gate 32310598SGlenn.Barry@Sun.COM return (status); 32410598SGlenn.Barry@Sun.COM } 3250Sstevel@tonic-gate 32610598SGlenn.Barry@Sun.COM return (GSS_S_BAD_MECH); 3270Sstevel@tonic-gate } 3280Sstevel@tonic-gate 32910598SGlenn.Barry@Sun.COM OM_uint32 gssint_export_internal_name(minor_status, mech_type, 33010598SGlenn.Barry@Sun.COM internal_name, name_buf) 33110598SGlenn.Barry@Sun.COM OM_uint32 *minor_status; 33210598SGlenn.Barry@Sun.COM const gss_OID mech_type; 33310598SGlenn.Barry@Sun.COM const gss_name_t internal_name; 33410598SGlenn.Barry@Sun.COM gss_buffer_t name_buf; 3350Sstevel@tonic-gate { 33610598SGlenn.Barry@Sun.COM OM_uint32 status; 33710598SGlenn.Barry@Sun.COM gss_mechanism mech; 33810598SGlenn.Barry@Sun.COM gss_buffer_desc dispName; 33910598SGlenn.Barry@Sun.COM gss_OID nameOid; 34010598SGlenn.Barry@Sun.COM unsigned char *buf = NULL; 34110598SGlenn.Barry@Sun.COM const unsigned char tokId[] = "\x04\x01"; 34210598SGlenn.Barry@Sun.COM const unsigned int tokIdLen = 2; 34310598SGlenn.Barry@Sun.COM const int mechOidLenLen = 2, mechOidTagLen = 1, nameLenLen = 4; 34410598SGlenn.Barry@Sun.COM int mechOidDERLen = 0; 34510598SGlenn.Barry@Sun.COM int mechOidLen = 0; 3460Sstevel@tonic-gate 34710598SGlenn.Barry@Sun.COM mech = gssint_get_mechanism(mech_type); 34810598SGlenn.Barry@Sun.COM if (!mech) 34910598SGlenn.Barry@Sun.COM return (GSS_S_BAD_MECH); 3500Sstevel@tonic-gate 35110598SGlenn.Barry@Sun.COM if (mech->gss_export_name) { 35210598SGlenn.Barry@Sun.COM status = mech->gss_export_name( 35310598SGlenn.Barry@Sun.COM mech->context, /* SUNW17PACresync */ 35410598SGlenn.Barry@Sun.COM minor_status, 35510598SGlenn.Barry@Sun.COM internal_name, 35610598SGlenn.Barry@Sun.COM name_buf); 35710598SGlenn.Barry@Sun.COM if (status != GSS_S_COMPLETE) 35810598SGlenn.Barry@Sun.COM map_error(minor_status, mech); 35910598SGlenn.Barry@Sun.COM return status; 36010598SGlenn.Barry@Sun.COM } 3610Sstevel@tonic-gate 36210598SGlenn.Barry@Sun.COM /* 36310598SGlenn.Barry@Sun.COM * if we are here it is because the mechanism does not provide 36410598SGlenn.Barry@Sun.COM * a gss_export_name so we will use our implementation. We 36510598SGlenn.Barry@Sun.COM * do required that the mechanism define a gss_display_name. 36610598SGlenn.Barry@Sun.COM */ 36710598SGlenn.Barry@Sun.COM if (!mech->gss_display_name) 36810598SGlenn.Barry@Sun.COM return (GSS_S_UNAVAILABLE); 3690Sstevel@tonic-gate 37010598SGlenn.Barry@Sun.COM /* 37110598SGlenn.Barry@Sun.COM * NOTE: RFC2743 (section 3.2) governs the format of the outer 37210598SGlenn.Barry@Sun.COM * wrapper of exported names; the mechanisms' specs govern 37310598SGlenn.Barry@Sun.COM * the format of the inner portion of the exported name 37410598SGlenn.Barry@Sun.COM * and, for some (e.g., RFC1964, the Kerberos V mech), a 37510598SGlenn.Barry@Sun.COM * generic default as implemented here will do. 37610598SGlenn.Barry@Sun.COM * 37710598SGlenn.Barry@Sun.COM * The outer wrapper of an exported MN is: 2-octet tok Id 37810598SGlenn.Barry@Sun.COM * (0x0401) + 2-octet network-byte order mech OID length + mech 37910598SGlenn.Barry@Sun.COM * oid (in DER format, including DER tag and DER length) + 38010598SGlenn.Barry@Sun.COM * 4-octet network-byte order length of inner portion + inner 38110598SGlenn.Barry@Sun.COM * portion. 38210598SGlenn.Barry@Sun.COM * 38310598SGlenn.Barry@Sun.COM * For the Kerberos V mechanism the inner portion of an exported 38410598SGlenn.Barry@Sun.COM * MN is the display name string and ignores the name type OID 38510598SGlenn.Barry@Sun.COM * altogether. And we hope this will be so for any future 38610598SGlenn.Barry@Sun.COM * mechanisms also, so that factoring name export/import out of 38710598SGlenn.Barry@Sun.COM * the mech and into libgss pays off. 38810598SGlenn.Barry@Sun.COM */ 38910598SGlenn.Barry@Sun.COM if ((status = mech->gss_display_name( 39010598SGlenn.Barry@Sun.COM mech->context, 39110598SGlenn.Barry@Sun.COM minor_status, 39210598SGlenn.Barry@Sun.COM internal_name, 39310598SGlenn.Barry@Sun.COM &dispName, 39410598SGlenn.Barry@Sun.COM &nameOid)) 39510598SGlenn.Barry@Sun.COM != GSS_S_COMPLETE) { 39610598SGlenn.Barry@Sun.COM map_error(minor_status, mech); 39710598SGlenn.Barry@Sun.COM return (status); 39810598SGlenn.Barry@Sun.COM } 3990Sstevel@tonic-gate 40010598SGlenn.Barry@Sun.COM /* determine the size of the buffer needed */ 40110598SGlenn.Barry@Sun.COM mechOidDERLen = gssint_der_length_size(mech_type->length); 40210598SGlenn.Barry@Sun.COM name_buf->length = tokIdLen + mechOidLenLen + 40310598SGlenn.Barry@Sun.COM mechOidTagLen + mechOidDERLen + 40410598SGlenn.Barry@Sun.COM mech_type->length + 40510598SGlenn.Barry@Sun.COM nameLenLen + dispName.length; 40610598SGlenn.Barry@Sun.COM if ((name_buf->value = (void*)malloc(name_buf->length)) == 40710598SGlenn.Barry@Sun.COM (void*)NULL) { 40810598SGlenn.Barry@Sun.COM name_buf->length = 0; 40910598SGlenn.Barry@Sun.COM (void) gss_release_buffer(&status, &dispName); 41010598SGlenn.Barry@Sun.COM return (GSS_S_FAILURE); 41110598SGlenn.Barry@Sun.COM } 4120Sstevel@tonic-gate 41310598SGlenn.Barry@Sun.COM /* now create the name ..... */ 41410598SGlenn.Barry@Sun.COM buf = (unsigned char *)name_buf->value; 41510598SGlenn.Barry@Sun.COM (void) memset(name_buf->value, 0, name_buf->length); 41610598SGlenn.Barry@Sun.COM (void) memcpy(buf, tokId, tokIdLen); 41710598SGlenn.Barry@Sun.COM buf += tokIdLen; 4180Sstevel@tonic-gate 41910598SGlenn.Barry@Sun.COM /* spec allows only 2 bytes for the mech oid length */ 42010598SGlenn.Barry@Sun.COM mechOidLen = mechOidDERLen + mechOidTagLen + mech_type->length; 42110598SGlenn.Barry@Sun.COM store_16_be(mechOidLen, buf); 42210598SGlenn.Barry@Sun.COM buf += 2; 4230Sstevel@tonic-gate 42410598SGlenn.Barry@Sun.COM /* 42510598SGlenn.Barry@Sun.COM * DER Encoding of mech OID contains OID Tag (0x06), length and 42610598SGlenn.Barry@Sun.COM * mech OID value 42710598SGlenn.Barry@Sun.COM */ 42810598SGlenn.Barry@Sun.COM *buf++ = 0x06; 42910598SGlenn.Barry@Sun.COM if (gssint_put_der_length(mech_type->length, &buf, 43010598SGlenn.Barry@Sun.COM (name_buf->length - tokIdLen -2)) != 0) { 43110598SGlenn.Barry@Sun.COM name_buf->length = 0; 43210598SGlenn.Barry@Sun.COM free(name_buf->value); 43310598SGlenn.Barry@Sun.COM (void) gss_release_buffer(&status, &dispName); 43410598SGlenn.Barry@Sun.COM return (GSS_S_FAILURE); 43510598SGlenn.Barry@Sun.COM } 4360Sstevel@tonic-gate 43710598SGlenn.Barry@Sun.COM (void) memcpy(buf, mech_type->elements, mech_type->length); 43810598SGlenn.Barry@Sun.COM buf += mech_type->length; 4390Sstevel@tonic-gate 44010598SGlenn.Barry@Sun.COM /* spec designates the next 4 bytes for the name length */ 44110598SGlenn.Barry@Sun.COM store_32_be(dispName.length, buf); 44210598SGlenn.Barry@Sun.COM buf += 4; 4430Sstevel@tonic-gate 44410598SGlenn.Barry@Sun.COM /* for the final ingredient - add the name from gss_display_name */ 44510598SGlenn.Barry@Sun.COM (void) memcpy(buf, dispName.value, dispName.length); 4460Sstevel@tonic-gate 44710598SGlenn.Barry@Sun.COM /* release the buffer obtained from gss_display_name */ 44810598SGlenn.Barry@Sun.COM (void) gss_release_buffer(minor_status, &dispName); 44910598SGlenn.Barry@Sun.COM return (GSS_S_COMPLETE); 45010598SGlenn.Barry@Sun.COM } /* gssint_export_internal_name */ 4510Sstevel@tonic-gate 45210598SGlenn.Barry@Sun.COM OM_uint32 gssint_display_internal_name (minor_status, mech_type, internal_name, 45310598SGlenn.Barry@Sun.COM external_name, name_type) 45410598SGlenn.Barry@Sun.COM OM_uint32 *minor_status; 45510598SGlenn.Barry@Sun.COM gss_OID mech_type; 45610598SGlenn.Barry@Sun.COM gss_name_t internal_name; 45710598SGlenn.Barry@Sun.COM gss_buffer_t external_name; 45810598SGlenn.Barry@Sun.COM gss_OID *name_type; 4590Sstevel@tonic-gate { 46010598SGlenn.Barry@Sun.COM OM_uint32 status; 46110598SGlenn.Barry@Sun.COM gss_mechanism mech; 4620Sstevel@tonic-gate 46310598SGlenn.Barry@Sun.COM mech = gssint_get_mechanism (mech_type); 46410598SGlenn.Barry@Sun.COM if (mech) { 46510598SGlenn.Barry@Sun.COM if (mech->gss_display_name) { 46610598SGlenn.Barry@Sun.COM status = mech->gss_display_name ( 46710598SGlenn.Barry@Sun.COM mech->context, 46810598SGlenn.Barry@Sun.COM minor_status, 46910598SGlenn.Barry@Sun.COM internal_name, 47010598SGlenn.Barry@Sun.COM external_name, 47110598SGlenn.Barry@Sun.COM name_type); 47210598SGlenn.Barry@Sun.COM if (status != GSS_S_COMPLETE) 47310598SGlenn.Barry@Sun.COM map_error(minor_status, mech); 47410598SGlenn.Barry@Sun.COM } else 47510598SGlenn.Barry@Sun.COM status = GSS_S_UNAVAILABLE; 4760Sstevel@tonic-gate 47710598SGlenn.Barry@Sun.COM return (status); 47810598SGlenn.Barry@Sun.COM } 4790Sstevel@tonic-gate 48010598SGlenn.Barry@Sun.COM return (GSS_S_BAD_MECH); 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate 48310598SGlenn.Barry@Sun.COM OM_uint32 gssint_release_internal_name (minor_status, mech_type, internal_name) 48410598SGlenn.Barry@Sun.COM OM_uint32 *minor_status; 48510598SGlenn.Barry@Sun.COM gss_OID mech_type; 48610598SGlenn.Barry@Sun.COM gss_name_t *internal_name; 4870Sstevel@tonic-gate { 48810598SGlenn.Barry@Sun.COM OM_uint32 status; 48910598SGlenn.Barry@Sun.COM gss_mechanism mech; 4900Sstevel@tonic-gate 49110598SGlenn.Barry@Sun.COM mech = gssint_get_mechanism (mech_type); 49210598SGlenn.Barry@Sun.COM if (mech) { 49310598SGlenn.Barry@Sun.COM if (mech->gss_release_name) { 49410598SGlenn.Barry@Sun.COM status = mech->gss_release_name ( 49510598SGlenn.Barry@Sun.COM mech->context, 49610598SGlenn.Barry@Sun.COM minor_status, 49710598SGlenn.Barry@Sun.COM internal_name); 49810598SGlenn.Barry@Sun.COM if (status != GSS_S_COMPLETE) 49910598SGlenn.Barry@Sun.COM map_error(minor_status, mech); 50010598SGlenn.Barry@Sun.COM } else 50110598SGlenn.Barry@Sun.COM status = GSS_S_UNAVAILABLE; 5020Sstevel@tonic-gate 50310598SGlenn.Barry@Sun.COM return (status); 50410598SGlenn.Barry@Sun.COM } 5050Sstevel@tonic-gate 50610598SGlenn.Barry@Sun.COM return (GSS_S_BAD_MECH); 5070Sstevel@tonic-gate } 5080Sstevel@tonic-gate 50910598SGlenn.Barry@Sun.COM OM_uint32 gssint_delete_internal_sec_context (minor_status, 51010598SGlenn.Barry@Sun.COM mech_type, 51110598SGlenn.Barry@Sun.COM internal_ctx, 51210598SGlenn.Barry@Sun.COM output_token) 51310598SGlenn.Barry@Sun.COM OM_uint32 *minor_status; 51410598SGlenn.Barry@Sun.COM gss_OID mech_type; 51510598SGlenn.Barry@Sun.COM gss_ctx_id_t *internal_ctx; 51610598SGlenn.Barry@Sun.COM gss_buffer_t output_token; 51710598SGlenn.Barry@Sun.COM { 51810598SGlenn.Barry@Sun.COM OM_uint32 status; 51910598SGlenn.Barry@Sun.COM gss_mechanism mech; 52010598SGlenn.Barry@Sun.COM 52110598SGlenn.Barry@Sun.COM mech = gssint_get_mechanism (mech_type); 52210598SGlenn.Barry@Sun.COM if (mech) { 52310598SGlenn.Barry@Sun.COM if (mech->gss_delete_sec_context) 52410598SGlenn.Barry@Sun.COM status = mech->gss_delete_sec_context ( 52510598SGlenn.Barry@Sun.COM mech->context, /* SUNW17PACresync */ 52610598SGlenn.Barry@Sun.COM minor_status, 52710598SGlenn.Barry@Sun.COM internal_ctx, 52810598SGlenn.Barry@Sun.COM output_token); 52910598SGlenn.Barry@Sun.COM else 53010598SGlenn.Barry@Sun.COM /* SUNW17PACresync - map error here? */ 53110598SGlenn.Barry@Sun.COM status = GSS_S_UNAVAILABLE; 53210598SGlenn.Barry@Sun.COM 53310598SGlenn.Barry@Sun.COM return (status); 53410598SGlenn.Barry@Sun.COM } 53510598SGlenn.Barry@Sun.COM 53610598SGlenn.Barry@Sun.COM return (GSS_S_BAD_MECH); 53710598SGlenn.Barry@Sun.COM } 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate /* 5400Sstevel@tonic-gate * This function converts an internal gssapi name to a union gssapi 5410Sstevel@tonic-gate * name. Note that internal_name should be considered "consumed" by 5420Sstevel@tonic-gate * this call, whether or not we return an error. 5430Sstevel@tonic-gate */ 54410598SGlenn.Barry@Sun.COM OM_uint32 gssint_convert_name_to_union_name(minor_status, mech, 54510598SGlenn.Barry@Sun.COM internal_name, external_name) 54610598SGlenn.Barry@Sun.COM OM_uint32 *minor_status; 54710598SGlenn.Barry@Sun.COM gss_mechanism mech; 54810598SGlenn.Barry@Sun.COM gss_name_t internal_name; 54910598SGlenn.Barry@Sun.COM gss_name_t *external_name; 5500Sstevel@tonic-gate { 55110598SGlenn.Barry@Sun.COM OM_uint32 major_status,tmp; 55210598SGlenn.Barry@Sun.COM gss_union_name_t union_name; 5530Sstevel@tonic-gate 55410598SGlenn.Barry@Sun.COM union_name = (gss_union_name_t) malloc (sizeof(gss_union_name_desc)); 55510598SGlenn.Barry@Sun.COM if (!union_name) { 55610598SGlenn.Barry@Sun.COM major_status = GSS_S_FAILURE; 55710598SGlenn.Barry@Sun.COM *minor_status = ENOMEM; 55810598SGlenn.Barry@Sun.COM map_errcode(minor_status); 55910598SGlenn.Barry@Sun.COM goto allocation_failure; 56010598SGlenn.Barry@Sun.COM } 56110598SGlenn.Barry@Sun.COM union_name->mech_type = 0; 56210598SGlenn.Barry@Sun.COM union_name->mech_name = internal_name; 56310598SGlenn.Barry@Sun.COM union_name->name_type = 0; 56410598SGlenn.Barry@Sun.COM union_name->external_name = 0; 5650Sstevel@tonic-gate 56610598SGlenn.Barry@Sun.COM major_status = generic_gss_copy_oid(minor_status, &mech->mech_type, 56710598SGlenn.Barry@Sun.COM &union_name->mech_type); 56810598SGlenn.Barry@Sun.COM if (major_status != GSS_S_COMPLETE) { 56910598SGlenn.Barry@Sun.COM map_errcode(minor_status); 57010598SGlenn.Barry@Sun.COM goto allocation_failure; 57110598SGlenn.Barry@Sun.COM } 5720Sstevel@tonic-gate 57310598SGlenn.Barry@Sun.COM union_name->external_name = 57410598SGlenn.Barry@Sun.COM (gss_buffer_t) malloc(sizeof(gss_buffer_desc)); 57510598SGlenn.Barry@Sun.COM if (!union_name->external_name) { 57610598SGlenn.Barry@Sun.COM major_status = GSS_S_FAILURE; 57710598SGlenn.Barry@Sun.COM *minor_status = ENOMEM; 57810598SGlenn.Barry@Sun.COM goto allocation_failure; 57910598SGlenn.Barry@Sun.COM } 58010598SGlenn.Barry@Sun.COM 58112360SMark.Phalan@Sun.COM union_name->external_name->length = 0; 58212360SMark.Phalan@Sun.COM union_name->external_name->value = 0; 58312360SMark.Phalan@Sun.COM 58410598SGlenn.Barry@Sun.COM major_status = mech->gss_display_name( 58510598SGlenn.Barry@Sun.COM mech->context, /* SUNW17PACresync */ 58610598SGlenn.Barry@Sun.COM minor_status, 58710598SGlenn.Barry@Sun.COM internal_name, 58810598SGlenn.Barry@Sun.COM union_name->external_name, 58910598SGlenn.Barry@Sun.COM &union_name->name_type); 59010598SGlenn.Barry@Sun.COM if (major_status != GSS_S_COMPLETE) { 59110598SGlenn.Barry@Sun.COM map_error(minor_status, mech); 59210598SGlenn.Barry@Sun.COM goto allocation_failure; 59310598SGlenn.Barry@Sun.COM } 5940Sstevel@tonic-gate 59510598SGlenn.Barry@Sun.COM union_name->loopback = union_name; 59610598SGlenn.Barry@Sun.COM *external_name = (gss_name_t) union_name; 59710598SGlenn.Barry@Sun.COM return (GSS_S_COMPLETE); 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate allocation_failure: 60010598SGlenn.Barry@Sun.COM if (union_name) { 60110598SGlenn.Barry@Sun.COM if (union_name->external_name) { 60210598SGlenn.Barry@Sun.COM if (union_name->external_name->value) 60310598SGlenn.Barry@Sun.COM free(union_name->external_name->value); 60410598SGlenn.Barry@Sun.COM free(union_name->external_name); 6050Sstevel@tonic-gate } 60610598SGlenn.Barry@Sun.COM if (union_name->name_type) 60710598SGlenn.Barry@Sun.COM (void) gss_release_oid(&tmp, &union_name->name_type); 60810598SGlenn.Barry@Sun.COM if (union_name->mech_type) 60910598SGlenn.Barry@Sun.COM (void) gss_release_oid(&tmp, &union_name->mech_type); 61010598SGlenn.Barry@Sun.COM free(union_name); 61110598SGlenn.Barry@Sun.COM } 61210598SGlenn.Barry@Sun.COM /* 61310598SGlenn.Barry@Sun.COM * do as the top comment says - since we are now owners of 61410598SGlenn.Barry@Sun.COM * internal_name, we must clean it up 61510598SGlenn.Barry@Sun.COM */ 61610598SGlenn.Barry@Sun.COM if (internal_name) 61710598SGlenn.Barry@Sun.COM (void) gssint_release_internal_name(&tmp, &mech->mech_type, 61810598SGlenn.Barry@Sun.COM &internal_name); 61910598SGlenn.Barry@Sun.COM return (major_status); 6200Sstevel@tonic-gate } 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate /* 6230Sstevel@tonic-gate * Glue routine for returning the mechanism-specific credential from a 6240Sstevel@tonic-gate * external union credential. 6250Sstevel@tonic-gate */ 6260Sstevel@tonic-gate gss_cred_id_t 62710598SGlenn.Barry@Sun.COM gssint_get_mechanism_cred(union_cred, mech_type) 62810598SGlenn.Barry@Sun.COM gss_union_cred_t union_cred; 62910598SGlenn.Barry@Sun.COM gss_OID mech_type; 6300Sstevel@tonic-gate { 63110598SGlenn.Barry@Sun.COM int i; 63210598SGlenn.Barry@Sun.COM 63310598SGlenn.Barry@Sun.COM if (union_cred == (gss_union_cred_t) GSS_C_NO_CREDENTIAL) 63410598SGlenn.Barry@Sun.COM return GSS_C_NO_CREDENTIAL; 63510598SGlenn.Barry@Sun.COM 63610598SGlenn.Barry@Sun.COM /* 63710598SGlenn.Barry@Sun.COM * SUNW17PACresync 63810598SGlenn.Barry@Sun.COM * Disable this block as it causes problems for gss_add_cred 63910598SGlenn.Barry@Sun.COM * for HTTP SSO (and also probably causes STC gss.13 to fail too). 64010598SGlenn.Barry@Sun.COM */ 64110598SGlenn.Barry@Sun.COM #if 0 64210598SGlenn.Barry@Sun.COM /* SPNEGO mechanism will again call into GSSAPI */ 64310598SGlenn.Barry@Sun.COM if (g_OID_equal(&gss_spnego_mechanism_oid_desc, mech_type)) 64410598SGlenn.Barry@Sun.COM return (gss_cred_id_t)union_cred; 64510598SGlenn.Barry@Sun.COM #endif 6460Sstevel@tonic-gate 64710598SGlenn.Barry@Sun.COM for (i=0; i < union_cred->count; i++) { 64810598SGlenn.Barry@Sun.COM if (g_OID_equal(mech_type, &union_cred->mechs_array[i])) 64910598SGlenn.Barry@Sun.COM return union_cred->cred_array[i]; 65010598SGlenn.Barry@Sun.COM 65110598SGlenn.Barry@Sun.COM /* for SPNEGO, check the next-lower set of creds */ 65210598SGlenn.Barry@Sun.COM if (g_OID_equal(&gss_spnego_mechanism_oid_desc, &union_cred->mechs_array[i])) { 65310598SGlenn.Barry@Sun.COM gss_union_cred_t candidate_cred; 65410598SGlenn.Barry@Sun.COM gss_cred_id_t sub_cred; 6550Sstevel@tonic-gate 65610598SGlenn.Barry@Sun.COM candidate_cred = (gss_union_cred_t)union_cred->cred_array[i]; 65710598SGlenn.Barry@Sun.COM sub_cred = gssint_get_mechanism_cred(candidate_cred, mech_type); 65810598SGlenn.Barry@Sun.COM 65910598SGlenn.Barry@Sun.COM if(sub_cred != GSS_C_NO_CREDENTIAL) 66010598SGlenn.Barry@Sun.COM return sub_cred; 6610Sstevel@tonic-gate } 66210598SGlenn.Barry@Sun.COM } 66310598SGlenn.Barry@Sun.COM 66410598SGlenn.Barry@Sun.COM return GSS_C_NO_CREDENTIAL; 6650Sstevel@tonic-gate } 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate /* 6680Sstevel@tonic-gate * Routine to create and copy the gss_buffer_desc structure. 6690Sstevel@tonic-gate * Both space for the structure and the data is allocated. 6700Sstevel@tonic-gate */ 6710Sstevel@tonic-gate OM_uint32 6725053Sgtb gssint_create_copy_buffer(srcBuf, destBuf, addNullChar) 67310598SGlenn.Barry@Sun.COM const gss_buffer_t srcBuf; 67410598SGlenn.Barry@Sun.COM gss_buffer_t *destBuf; 67510598SGlenn.Barry@Sun.COM int addNullChar; 6760Sstevel@tonic-gate { 67710598SGlenn.Barry@Sun.COM gss_buffer_t aBuf; 67810598SGlenn.Barry@Sun.COM unsigned int len; 6790Sstevel@tonic-gate 68010598SGlenn.Barry@Sun.COM if (destBuf == NULL) 68110598SGlenn.Barry@Sun.COM return (GSS_S_CALL_INACCESSIBLE_WRITE); 6820Sstevel@tonic-gate 68310598SGlenn.Barry@Sun.COM *destBuf = 0; 6840Sstevel@tonic-gate 68510598SGlenn.Barry@Sun.COM aBuf = (gss_buffer_t)malloc(sizeof (gss_buffer_desc)); 68610598SGlenn.Barry@Sun.COM if (!aBuf) 68710598SGlenn.Barry@Sun.COM return (GSS_S_FAILURE); 6880Sstevel@tonic-gate 68910598SGlenn.Barry@Sun.COM if (addNullChar) 69010598SGlenn.Barry@Sun.COM len = srcBuf->length + 1; 69110598SGlenn.Barry@Sun.COM else 69210598SGlenn.Barry@Sun.COM len = srcBuf->length; 6930Sstevel@tonic-gate 69410598SGlenn.Barry@Sun.COM if (!(aBuf->value = (void*)malloc(len))) { 69510598SGlenn.Barry@Sun.COM free(aBuf); 69610598SGlenn.Barry@Sun.COM return (GSS_S_FAILURE); 69710598SGlenn.Barry@Sun.COM } 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate 70010598SGlenn.Barry@Sun.COM (void) memcpy(aBuf->value, srcBuf->value, srcBuf->length); 70110598SGlenn.Barry@Sun.COM aBuf->length = srcBuf->length; 70210598SGlenn.Barry@Sun.COM *destBuf = aBuf; 7030Sstevel@tonic-gate 70410598SGlenn.Barry@Sun.COM /* optionally add a NULL character */ 70510598SGlenn.Barry@Sun.COM if (addNullChar) 70610598SGlenn.Barry@Sun.COM ((char *)aBuf->value)[aBuf->length] = '\0'; 7070Sstevel@tonic-gate 70810598SGlenn.Barry@Sun.COM return (GSS_S_COMPLETE); 70910598SGlenn.Barry@Sun.COM } /* ****** gssint_create_copy_buffer ****** */ 71010598SGlenn.Barry@Sun.COM 711