1   /*
   2    * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
   3    * Use is subject to license terms.
   4    */
   5   
   6 | #pragma ident        "@(#)g_glue.c        1.26        04/09/08 SMI"
   6 | #pragma ident        "@(#)g_glue.c        1.25        04/02/23 SMI"
   7   
   8   #include <mechglueP.h>
   9   #include <stdio.h>
  10   #include <stdlib.h>
  11   #include <strings.h>
  12   #include <errno.h>
  13   
  14   #define        MSO_BIT (8*(sizeof (int) - 1))  /* Most significant octet bit */
  15   
  16   /*
  17    * This file contains the support routines for the glue layer.
  18    */
  19   
  20   /*
  21 +  * get_der_length: Givin a pointer to a buffer that contains a DER encoded
  22 +  * length, decode the length updating the buffer to point to the character
  23 +  * after the DER encoding. The parameter bytes will point to the number of
  24 +  * bytes that made up the DER encoding of the length originally pointed to
  25 +  * by the buffer. Note we return -1 on error.
  26 +  */
  27 + int
  28 + get_der_length(unsigned char **buf, unsigned int buf_len, unsigned int *bytes)
  29 + {
  30 +         /* p points to the beginning of the buffer */
  31 +         unsigned char *p = *buf;
  32 +         int length, new_length;
  33 +         int octets;
  34 + 
  35 +         if (buf_len < 1)
  36 +                 return (-1);
  37 + 
  38 +         /* We should have at least one byte */
  39 +         *bytes = 1;
  40 + 
  41 +         /*
  42 +          * If the High order bit is not set then the length is just the value
  43 +          * of *p.
  44 +          */
  45 +         if (*p < 128) {
  46 +                 *buf = p+1;        /* Advance the buffer */
  47 +         return (*p);                /* return the length */
  48 +         }
  49 + 
  50 +         /*
  51 +          * if the High order bit is set, then the low order bits represent
  52 +          * the number of bytes that contain the DER encoding of the length.
  53 +          */
  54 + 
  55 +         octets = *p++ & 0x7f;
  56 +         *bytes += octets;
  57 + 
  58 +         /* See if the supplied buffer contains enough bytes for the length. */
  59 +         if (octets > buf_len - 1)
  60 +                 return (-1);
  61 + 
  62 +         /*
  63 +          * Calculate a multibyte length. The length is encoded as an
  64 +          * unsigned integer base 256.
  65 +          */
  66 +         for (length = 0; octets; octets--) {
  67 +                 new_length = (length << 8) + *p++;
  68 +                 if (new_length < length)  /* overflow */
  69 +                         return (-1);
  70 +                 length = new_length;
  71 +         }
  72 + 
  73 +         *buf = p; /* Advance the buffer */
  74 + 
  75 +         return (length);
  76 + }
  77 + 
  78 + /*
  79    * der_length_size: Return the number of bytes to encode a given length.
  80    */
  81   unsigned int
  82   der_length_size(unsigned int len)
  83   {
  26 |    if (length < (1<<7))
  84 |         int i;
  85 + 
  86 +         if (len < 128)
  87                   return (1);
  28 |    else if (length < (1<<8))
  29 |       return(2);
  30 | #if (SIZEOF_INT == 2)
  88 | 
  89 |         for (i = 0; len; i++) {
  90 |                 len >>= 8;
  31 -    else 
  32 -        return(3);
  33 - #else   
  34 -    else if (length < (1<<16))
  35 -       return(3);
  36 -    else if (length < (1<<24))
  37 -       return(4);
  38 -    else 
  39 -       return(5);
  40 - #endif  
  91           }
  92   
  93 +         return (i+1);
  94 + }
  95 + 
  96   /*
  97 +  * put_der_length: Encode the supplied length into the buffer pointed to
  98 +  * by buf. max_length represents the maximum length of the buffer pointed
  99 +  * to by buff. We will advance buf to point to the character after the newly
 100 +  * DER encoded length. We return 0 on success or -l it the length cannot
 101 +  * be encoded in max_len characters.
 102 +  */
 103 + int
 104 + put_der_length(unsigned length, unsigned char **buf, unsigned int max_len)
 105 + {
 106 +         unsigned char *s = *buf, *p;
 107 +         unsigned int buf_len = 0;
 108 +         int i, first;
 109 + 
 110 +         /* Oops */
 111 +         if (buf == 0 || max_len < 1)
 112 +                 return (-1);
 113 + 
 114 +         /* Single byte is the length */
 115 +         if (length < 128) {
 116 +                 *s++ = length;
 117 +                 *buf = s;
 118 +                 return (0);
 119 +         }
 120 + 
 121 +         /* First byte contains the number of octets */
 122 +         p = s + 1;
 123 + 
 124 +         /* Running total of the DER encoding length */
 125 +         buf_len = 0;
 126 + 
 127 +         /*
 128 +          * Encode MSB first. We do the encoding by setting a shift
 129 +          * factor to MSO_BIT (24 for 32 bit words) and then shifting the length
 130 +          * by the factor. We then encode the resulting low order byte.
 131 +          * We subtract 8 from the shift factor and repeat to ecnode the next
 132 +          * byte. We stop when the shift factor is zero or we've run out of
 133 +          * buffer to encode into.
 134 +          */
 135 +         first = 0;
 136 +         for (i = MSO_BIT; i >= 0 && buf_len <= max_len; i -= 8) {
 137 +                 unsigned int v;
 138 +                 v = (length >> i) & 0xff;
 139 +                 if ((v) || first) {
 140 +                         buf_len += 1;
 141 +                         *p++ = v;
 142 +                         first = 1;
 143 +                 }
 144 +         }
 145 +         if (i >= 0)                        /* buffer overflow */
 146 +                 return (-1);
 147 + 
 148 +         /*
 149 +          * We go back now and set the first byte to be the length with
 150 +          * the high order bit set.
 151 +          */
 152 +         *s = buf_len | 0x80;
 153 +         *buf = p;
 154 + 
 155 +         return (0);
 156 + }
 157 + 
 158 + 
 159 + /*
 160    *  glue routine for get_mech_type
 161    *
 162    */
 163   OM_uint32
 164   __gss_get_mech_type(OID, token)
 165           gss_OID                        OID;
 166           const gss_buffer_t        token;
 167   {
 168           unsigned char *buffer_ptr;
 169           int length;
 170   
 171           /*
 172            * This routine reads the prefix of "token" in order to determine
 173            * its mechanism type. It assumes the encoding suggested in
 174            * Appendix B of RFC 1508. This format starts out as follows :
 175            *
 176            * tag for APPLICATION 0, Sequence[constructed, definite length]
 177            * length of remainder of token
 178            * tag of OBJECT IDENTIFIER
 179            * length of mechanism OID
 180            * encoding of mechanism OID
 181            * <the rest of the token>
 182            *
 183            * Numerically, this looks like :
 184            *
 185            * 0x60
 186            * <length> - could be multiple bytes
 187            * 0x06
 188            * <length> - assume only one byte, hence OID length < 127
 189            * <mech OID bytes>
 190            *
 191            * The routine fills in the OID value and returns an error as necessary.
 192            */
 193   
  78 |         if (token == NULL)
 194 |         if (OID == NULL)
 195 +                 return (GSS_S_CALL_INACCESSIBLE_WRITE);
 196 + 
 197 +         if ((token == NULL) || (token->value == NULL))
 198                   return (GSS_S_DEFECTIVE_TOKEN);
 199   
 200           /* Skip past the APP/Sequnce byte and the token length */
 201   
 202           buffer_ptr = (unsigned char *) token->value;
 203   
 204           if (*(buffer_ptr++) != 0x60)
 205                   return (GSS_S_DEFECTIVE_TOKEN);
 206           length = *buffer_ptr++;
 207 + 
 208 +         /* check if token length is null */
 209 +         if (length == 0)
 210 +             return (GSS_S_DEFECTIVE_TOKEN);
 211 + 
 212           if (length & 0x80) {
 213                   if ((length & 0x7f) > 4)
 214                           return (GSS_S_DEFECTIVE_TOKEN);
 215                   buffer_ptr += length & 0x7f;
 216           }
 217   
 218           if (*(buffer_ptr++) != 0x06)
 219                   return (GSS_S_DEFECTIVE_TOKEN);
 220   
 221           OID->length = (OM_uint32) *(buffer_ptr++);
 222           OID->elements = (void *) buffer_ptr;
 223           return (GSS_S_COMPLETE);
 224   }
 225   
 226   
 227   /*
 228    *  Internal routines to get and release an internal mechanism name
 229    */
 230   OM_uint32 __gss_import_internal_name(minor_status, mech_type, union_name,
 231                                           internal_name)
 232   OM_uint32                *minor_status;
 233   const gss_OID                mech_type;
 234   gss_union_name_t        union_name;
 235   gss_name_t                *internal_name;
 236   {
 237           OM_uint32                        status;
 238           gss_mechanism                mech;
 239   
 240           mech = __gss_get_mechanism(mech_type);
 241           if (mech) {
 242                   if (mech->gss_import_name)
 243                           status = mech->gss_import_name(
 244                                                   mech->context,
 245                                                   minor_status,
 246                                                   union_name->external_name,
 247                                                   union_name->name_type,
 248                                                   internal_name);
 249                   else
 126 |                         status = GSS_S_BAD_BINDINGS;
 250 |                         status = GSS_S_UNAVAILABLE;
 251   
 252                   return (status);
 253           }
 254   
 255           return (GSS_S_BAD_MECH);
 256   }
 257   
 258 + 
 259 + OM_uint32 __gss_export_internal_name(minor_status, mech_type,
 260 +                 internal_name, name_buf)
 261 + OM_uint32                *minor_status;
 262 + const gss_OID                mech_type;
 263 + const gss_name_t        internal_name;
 264 + gss_buffer_t                name_buf;
 265 + {
 266 +         OM_uint32 status;
 267 +         gss_mechanism mech;
 268 +         gss_buffer_desc dispName;
 269 +         gss_OID nameOid;
 270 +         unsigned char *buf = NULL;
 271 +         const unsigned char tokId[] = "\x04\x01";
 272 +         const int tokIdLen = 2;
 273 +         const int mechOidLenLen = 2, mechOidTagLen = 1, nameLenLen = 4;
 274 +         int mechOidDERLen = 0;
 275 +         int mechOidLen = 0;
 276 + 
 277 +         mech = __gss_get_mechanism(mech_type);
 278 +         if (!mech)
 279 +                 return (GSS_S_BAD_MECH);
 280 + 
 281 +         if (mech->gss_export_name)
 282 +                 return (mech->gss_export_name(mech->context,
 283 +                                                 minor_status,
 284 +                                                 internal_name,
 285 +                                                 name_buf));
 286 + 
 287 +         /*
 288 +          * if we are here it is because the mechanism does not provide
 289 +          * a gss_export_name so we will use our implementation.  We
 290 +          * do required that the mechanism define a gss_display_name.
 291 +          */
 292 +         if (!mech->gss_display_name)
 293 +                 return (GSS_S_UNAVAILABLE);
 294 + 
 295 +         /*
 296 +          * NOTE: RFC2743 (section 3.2) governs the format of the outer
 297 +          *         wrapper of exported names; the mechanisms' specs govern
 298 +          *         the format of the inner portion of the exported name
 299 +          *         and, for some (e.g., RFC1964, the Kerberos V mech), a
 300 +          *         generic default as implemented here will do.
 301 +          *
 302 +          * The outer wrapper of an exported MN is: 2-octet tok Id
 303 +          * (0x0401) + 2-octet network-byte order mech OID length + mech
 304 +          * oid (in DER format, including DER tag and DER length) +
 305 +          * 4-octet network-byte order length of inner portion + inner
 306 +          * portion.
 307 +          *
 308 +          * For the Kerberos V mechanism the inner portion of an exported
 309 +          * MN is the display name string and ignores the name type OID
 310 +          * altogether.  And we hope this will be so for any future
 311 +          * mechanisms also, so that factoring name export/import out of
 312 +          * the mech and into libgss pays off.
 313 +          */
 314 +         if ((status = mech->gss_display_name(mech->context,
 315 +                                                 minor_status,
 316 +                                                 internal_name,
 317 +                                                 &dispName,
 318 +                                                 &nameOid))
 319 +                                                 != GSS_S_COMPLETE)
 320 +                 return (status);
 321 + 
 322 +         /* determine the size of the buffer needed */
 323 +         mechOidDERLen = der_length_size(mech_type->length);
 324 +         name_buf->length = tokIdLen + mechOidLenLen +
 325 +                                 mechOidTagLen + mechOidDERLen +
 326 +                                 mech_type->length +
 327 +                                 nameLenLen + dispName.length;
 328 +         if ((name_buf->value = (void*)malloc(name_buf->length)) ==
 329 +                 (void*)NULL) {
 330 +                         name_buf->length = 0;
 331 +                         (void) gss_release_buffer(&status, &dispName);
 332 +                         return (GSS_S_FAILURE);
 333 +         }
 334 + 
 335 +         /* now create the name ..... */
 336 +         buf = (unsigned char *)name_buf->value;
 337 +         (void) memset(name_buf->value, 0, name_buf->length);
 338 +         (void) memcpy(buf, tokId, tokIdLen);
 339 +         buf += tokIdLen;
 340 + 
 341 +         /* spec allows only 2 bytes for the mech oid length */
 342 +         mechOidLen = mechOidDERLen + mechOidTagLen + mech_type->length;
 343 +         *buf++ = (mechOidLen & 0xFF00) >> 8;
 344 +         *buf++ = (mechOidLen & 0x00FF);
 345 + 
 346 +         /*
 347 +          * DER Encoding of mech OID contains OID Tag (0x06), length and
 348 +          * mech OID value
 349 +         */
 350 +         *buf++ = 0x06;
 351 +         if (put_der_length(mech_type->length, &buf,
 352 +                 (name_buf->length - tokIdLen -2)) != 0) {
 353 +                 name_buf->length = 0;
 354 +                 free(name_buf->value);
 355 +                 (void) gss_release_buffer(&status, &dispName);
 356 +                 return (GSS_S_FAILURE);
 357 +         }
 358 + 
 359 +         (void) memcpy(buf, mech_type->elements, mech_type->length);
 360 +         buf += mech_type->length;
 361 + 
 362 +         /* spec designates the next 4 bytes for the name length */
 363 +         *buf++ = (dispName.length & 0xFF000000) >> 24;
 364 +         *buf++ = (dispName.length & 0x00FF0000) >> 16;
 365 +         *buf++ = (dispName.length & 0x0000FF00) >> 8;
 366 +         *buf++ = (dispName.length & 0X000000FF);
 367 + 
 368 +         /* for the final ingredient - add the name from gss_display_name */
 369 +         (void) memcpy(buf, dispName.value, dispName.length);
 370 + 
 371 +         /* release the buffer obtained from gss_display_name */
 372 +         (void) gss_release_buffer(minor_status, &dispName);
 373 +         return (GSS_S_COMPLETE);
 374 + } /*  __gss_export_internal_name */
 375 + 
 376 + 
 377   OM_uint32 __gss_display_internal_name(minor_status, mech_type, internal_name,
 378                                                   external_name, name_type)
 379   OM_uint32                *minor_status;
 380   const gss_OID                mech_type;
 381   const gss_name_t        internal_name;
 382   gss_buffer_t                external_name;
 383   gss_OID                        *name_type;
 384   {
 385           OM_uint32                        status;
 386           gss_mechanism                mech;
 387   
 388           mech = __gss_get_mechanism(mech_type);
 389           if (mech) {
 390                   if (mech->gss_display_name)
 391                           status = mech->gss_display_name(
 392                                                           mech->context,
 393                                                           minor_status,
 394                                                           internal_name,
 395                                                           external_name,
 396                                                           name_type);
 397                   else
 155 |                         status = GSS_S_BAD_BINDINGS;
 398 |                         status = GSS_S_UNAVAILABLE;
 399   
 400                   return (status);
 401           }
 402   
 403           return (GSS_S_BAD_MECH);
 404   }
 405   
 406   OM_uint32
 407   __gss_release_internal_name(minor_status, mech_type, internal_name)
 408   OM_uint32                *minor_status;
 409   const gss_OID                mech_type;
 410   gss_name_t                *internal_name;
 411   {
 412           OM_uint32                        status;
 413           gss_mechanism                mech;
 414   
 415           mech = __gss_get_mechanism(mech_type);
 416           if (mech) {
 417                   if (mech->gss_release_name)
 418                           status = mech->gss_release_name(
 419                                                           mech->context,
 420                                                           minor_status,
 421                                                           internal_name);
 422                   else
 180 |                         status = GSS_S_BAD_BINDINGS;
 423 |                         status = GSS_S_UNAVAILABLE;
 424   
 425                   return (status);
 426           }
 427   
 428           return (GSS_S_BAD_MECH);
 429   }
 430   
 431   
 432   /*
 433    * This function converts an internal gssapi name to a union gssapi
 434    * name.  Note that internal_name should be considered "consumed" by
 435    * this call, whether or not we return an error.
 436    */
 437   OM_uint32 __gss_convert_name_to_union_name(minor_status, mech,
 438                                                   internal_name, external_name)
 439           OM_uint32 *minor_status;
 440           gss_mechanism                mech;
 441           gss_name_t                internal_name;
 442           gss_name_t                *external_name;
 443   {
 444           OM_uint32 major_status, tmp;
 445           gss_union_name_t union_name;
 446   
 447           union_name = (gss_union_name_t)malloc(sizeof (gss_union_name_desc));
 206 -                         *minor_status = ENOMEM;
 448           if (!union_name) {
 449                           goto allocation_failure;
 450           }
 451           union_name->mech_type = 0;
 452           union_name->mech_name = internal_name;
 453           union_name->name_type = 0;
 454           union_name->external_name = 0;
 455   
 456           major_status = generic_gss_copy_oid(minor_status, &mech->mech_type,
 457                                                   &union_name->mech_type);
 458           if (major_status != GSS_S_COMPLETE)
 459                   goto allocation_failure;
 460   
 461           union_name->external_name =
 462                   (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
 222 -                         *minor_status = ENOMEM;
 463           if (!union_name->external_name) {
 464                           goto allocation_failure;
 465           }
 466   
 467           major_status = mech->gss_display_name(mech->context, minor_status,
 468                                                   internal_name,
 469                                                   union_name->external_name,
 470                                                   &union_name->name_type);
 471           if (major_status != GSS_S_COMPLETE)
 472                   goto allocation_failure;
 473   
 474           *external_name =  (gss_name_t)union_name;
 475           return (GSS_S_COMPLETE);
 476   
 477   allocation_failure:
 478           if (union_name) {
 479                   if (union_name->external_name) {
 480                           if (union_name->external_name->value)
 481                                   free(union_name->external_name->value);
 482                           free(union_name->external_name);
 483                   }
 484                   if (union_name->name_type)
 245 -                 if (union_name->mech_name)
 246 -                 (void) __gss_release_internal_name(minor_status,
 247 -                         union_name->mech_type, &union_name->mech_name);
 485                           (void) gss_release_oid(&tmp, &union_name->name_type);
 486                   if (union_name->mech_type)
 487                           (void) gss_release_oid(&tmp, &union_name->mech_type);
 488                   free(union_name);
 489           }
 490 +         /*
 491 +          * do as the top comment says - since we are now owners of
 492 +          * internal_name, we must clean it up
 493 +          */
 494 +         if (internal_name)
 495 +                 (void) __gss_release_internal_name(&tmp, &mech->mech_type,
 496 +                                                 &internal_name);
 497   
 498           return (major_status);
 499   }

 ----Unchanged portion omitted----

 521   
 522 + 
 523 + /*
 524 +  * Routine to create and copy the gss_buffer_desc structure.
 525 +  * Both space for the structure and the data is allocated.
 526 +  */
 527 + OM_uint32
 528 + __gss_create_copy_buffer(srcBuf, destBuf, addNullChar)
 529 +         const gss_buffer_t        srcBuf;
 530 +         gss_buffer_t                 *destBuf;
 531 +         int                        addNullChar;
 532 + {
 533 +         gss_buffer_t aBuf;
 534 +         int len;
 535 + 
 536 +         if (destBuf == NULL)
 537 +                 return (GSS_S_CALL_INACCESSIBLE_WRITE);
 538 + 
 539 +         *destBuf = 0;
 540 + 
 541 +         aBuf = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
 542 +         if (!aBuf)
 543 +                 return (GSS_S_FAILURE);
 544 + 
 545 +         if (addNullChar)
 546 +                 len = srcBuf->length + 1;
 547 +         else
 548 +                 len = srcBuf->length;
 549 + 
 550 +         if (!(aBuf->value = (void*)malloc(len))) {
 551 +                 free(aBuf);
 552 +                 return (GSS_S_FAILURE);
 553 +         }
 554 + 
 555 + 
 556 +         (void) memcpy(aBuf->value, srcBuf->value, srcBuf->length);
 557 +         aBuf->length = srcBuf->length;
 558 +         *destBuf = aBuf;
 559 + 
 560 +         /* optionally add a NULL character */
 561 +         if (addNullChar)
 562 +                 ((char *)aBuf->value)[aBuf->length] = '\0';
 563 + 
 564 +         return (GSS_S_COMPLETE);
 565 + } /* ****** __gss_create_copy_buffer  ****** */