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