1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 #pragma ident   "%Z%%M% %I%     %E% SMI"
  22 
  23 /*
  24  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  25  * Use is subject to license terms.
  26  *
  27  * A module that implements a dummy security mechanism.
  28  * It's mainly used to test GSS-API application. Multiple tokens
  29  * exchanged during security context establishment can be
  30  * specified through dummy_mech.conf located in /etc.
  31  *
  32  */
  33 #ifndef lint
  34 #define dummy_gss_accept_sec_context \
  35                 dummy_867227349
  36 #define dummy_gss_acquire_cred \
  37                 dummy_352458907
  38 #define dummy_gss_add_cred \
  39                 dummy_911432290
  40 #define dummy_gss_compare_name \
  41                 dummy_396663848
  42 #define dummy_gss_context_time \
  43                 dummy_955669998
  44 #define dummy_gss_delete_sec_context \
  45                 dummy_440868788
  46 #define dummy_gss_display_name \
  47                 dummy_999874939
  48 #define dummy_gss_display_status \
  49                 dummy_485073729
  50 #define dummy_gss_export_sec_context \
  51                 dummy_1044079879
  52 #define dummy_gss_import_name \
  53                 dummy_529311438
  54 #define dummy_gss_import_sec_context \
  55                 dummy_14542996
  56 #define dummy_gss_indicate_mechs \
  57                 dummy_573516378
  58 #define dummy_gss_init_sec_context \
  59                 dummy_58780705
  60 #define dummy_gss_inquire_context \
  61                 dummy_617721319
  62 #define dummy_gss_inquire_cred \
  63                 dummy_102985645
  64 #define dummy_gss_inquire_cred_by_mech \
  65                 dummy_661926260
  66 #define dummy_gss_inquire_names_for_mech \
  67                 dummy_147190586
  68 #define dummy_gss_internal_release_oid \
  69                 dummy_706163968
  70 #define dummy_gss_process_context_token \
  71                 dummy_191395526
  72 #define dummy_gss_release_cred \
  73                 dummy_750368909
  74 #define dummy_gss_release_name \
  75                 dummy_235600467
  76 #define dummy_gss_seal \
  77                 dummy_794573849
  78 #define dummy_gss_sign \
  79                 dummy_279838176
  80 #define dummy_gss_unseal \
  81                 dummy_838778790
  82 #define dummy_gss_verify \
  83                 dummy_324010348
  84 #define dummy_gss_wrap_size_limit \
  85                 dummy_882983731
  86 #define dummy_pname_to_uid \
  87                 dummy_345475423
  88 #endif
  89 
  90 #include <stdio.h>
  91 #include <stdlib.h>
  92 #include <gssapiP_dummy.h>
  93 #include <mechglueP.h>
  94 #include <gssapi_err_generic.h>
  95 
  96 #define dummy_context_name_len  19
  97 /* private routines for dummy_mechanism */
  98 static dummy_token_t make_dummy_token(char *name);
  99 static void free_dummy_token(dummy_token_t *token);
 100 static gss_buffer_desc make_dummy_token_buffer(char *name);
 101 static gss_buffer_desc make_dummy_token_msg(void *data, int datalen);
 102 static int der_length_size(int length);
 103 static void der_write_length(unsigned char ** buf, int length);
 104 static int der_read_length(unsigned char **buf, int *bufsize);
 105 static int g_token_size(gss_OID mech, unsigned int body_size);
 106 static void g_make_token_header(gss_OID mech, int body_size,
 107                                 unsigned char **buf, int tok_type);
 108 static int g_verify_token_header(gss_OID mech, int *body_size,
 109                                 unsigned char **buf_in, int tok_type,
 110                                 int toksize);
 111 
 112 
 113 /* private global variables */
 114 static char dummy_srcname[] = "dummy source";
 115 static OM_uint32 dummy_flags;
 116 static int token_nums;
 117 
 118 /*
 119  * The Mech OID:
 120  * { iso(1) org(3) internet(6) dod(1) private(4) enterprises(1) sun(42)
 121  *  products(2) gssapi(26) mechtypes(1) dummy(2) }
 122  */
 123 static struct gss_config dummy_mechanism =
 124         {{10, "\053\006\001\004\001\052\002\032\001\002"},
 125         NULL,
 126         dummy_gss_acquire_cred,
 127         dummy_gss_release_cred,
 128         dummy_gss_init_sec_context,
 129         dummy_gss_accept_sec_context,
 130         dummy_gss_unseal,
 131         dummy_gss_process_context_token,
 132         dummy_gss_delete_sec_context,
 133         dummy_gss_context_time,
 134         dummy_gss_display_status,
 135         dummy_gss_indicate_mechs,
 136         dummy_gss_compare_name,
 137         dummy_gss_display_name,
 138         dummy_gss_import_name,
 139         dummy_gss_release_name,
 140         dummy_gss_inquire_cred,
 141         dummy_gss_add_cred,
 142         dummy_gss_seal,
 143         dummy_gss_export_sec_context,
 144         dummy_gss_import_sec_context,
 145         dummy_gss_inquire_cred_by_mech,
 146         dummy_gss_inquire_names_for_mech,
 147         dummy_gss_inquire_context,
 148         dummy_gss_internal_release_oid,
 149         dummy_gss_wrap_size_limit,
 150         dummy_pname_to_uid,
 151         NULL,   /* __gss_userok */
 152         NULL,   /* _export name */
 153         dummy_gss_sign,
 154         dummy_gss_verify,
 155         NULL,   /* _store_cred */
 156 };
 157 
 158 gss_mechanism
 159 gss_mech_initialize(oid)
 160 const gss_OID oid;
 161 {
 162         FILE *fp;
 163 
 164         dprintf("Entering gss_mech_initialize\n");
 165 
 166         if (oid == NULL ||
 167                 !g_OID_equal(oid, &dummy_mechanism.mech_type)) {
 168                 fprintf(stderr, "invalid dummy mechanism oid.\n");
 169                 return (NULL);
 170         }
 171 
 172         fp = fopen("/etc/dummy_mech_token.conf", "rF");
 173         if (fp == NULL) {
 174                 fprintf(stderr, "dummy_mech.conf is not found.\n");
 175                 fprintf(stderr, "Setting number tokens exchanged to 1\n");
 176                 token_nums = 1;
 177         } else {
 178                 fscanf(fp, "%d", &token_nums);
 179                 fclose(fp);
 180                 dprintf("dummy_mech.conf is found.\n");
 181                 dprintf1("Setting number tokens exchanged to %d\n", token_nums);
 182         }
 183 
 184         if (token_nums == 1)
 185                 dummy_flags = GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
 186         else
 187                 dummy_flags = GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG
 188                                 | GSS_C_MUTUAL_FLAG;
 189 
 190         dprintf("Leaving gss_mech_initialize\n");
 191         return (&dummy_mechanism);
 192 }
 193 
 194 /*ARGSUSED*/
 195 OM_uint32
 196 dummy_gss_acquire_cred(ctx, minor_status, desired_name, time_req, desired_mechs,
 197                         cred_usage, output_cred_handle,
 198                         actual_mechs, time_rec)
 199         void *ctx;
 200         OM_uint32 *minor_status;
 201         gss_name_t desired_name;
 202         OM_uint32 time_req;
 203         gss_OID_set desired_mechs;
 204         gss_cred_usage_t cred_usage;
 205         gss_cred_id_t *output_cred_handle;
 206         gss_OID_set *actual_mechs;
 207         OM_uint32 *time_rec;
 208 {
 209         dprintf("Entering dummy_gss_acquire_cred\n");
 210 
 211         if (actual_mechs)
 212                 *actual_mechs = NULL;
 213         if (time_rec)
 214                 *time_rec = 0;
 215 
 216         *output_cred_handle = (gss_cred_id_t)
 217                                 make_dummy_token("dummy_gss_acquire_cred");
 218         if (time_rec)  /* user may pass a null pointer */
 219                 *time_rec = GSS_C_INDEFINITE;
 220         if (actual_mechs) {
 221                 if (gss_copy_oid_set(minor_status, gss_mech_set_dummy,
 222                                 actual_mechs) == GSS_S_FAILURE) {
 223                         return (GSS_S_FAILURE);
 224                 }
 225         }
 226 
 227         dprintf("Leaving dummy_gss_acquire_cred\n");
 228         return (GSS_S_COMPLETE);
 229 }
 230 
 231 /*ARGSUSED*/
 232 OM_uint32
 233 dummy_gss_release_cred(ctx, minor_status, cred_handle)
 234         void *ctx;
 235         OM_uint32 *minor_status;
 236         gss_cred_id_t *cred_handle;
 237 {
 238         dprintf("Entering dummy_gss_release_cred\n");
 239 
 240         free_dummy_token((dummy_token_t *)(cred_handle));
 241         *cred_handle = NULL;
 242 
 243         dprintf("Leaving dummy_gss_release_cred\n");
 244         return (GSS_S_COMPLETE);
 245 }
 246 
 247 /*ARGSUSED*/
 248 OM_uint32
 249 dummy_gss_init_sec_context(ct, minor_status, claimant_cred_handle,
 250                                 context_handle, target_name, mech_type,
 251                                 req_flags, time_req, input_chan_bindings,
 252                                 input_token, actual_mech_type, output_token,
 253                                 ret_flags, time_rec)
 254         void *ct;
 255         OM_uint32 *minor_status;
 256         gss_cred_id_t claimant_cred_handle;
 257         gss_ctx_id_t *context_handle;
 258         gss_name_t target_name;
 259         gss_OID mech_type;
 260         OM_uint32 req_flags;
 261         OM_uint32 time_req;
 262         gss_channel_bindings_t input_chan_bindings;
 263         gss_buffer_t input_token;
 264         gss_OID *actual_mech_type;
 265         gss_buffer_t output_token;
 266         OM_uint32 *ret_flags;
 267         OM_uint32 *time_rec;
 268 {
 269         dummy_gss_ctx_id_t ctx;
 270         char token_string[64];
 271         OM_uint32 ret;
 272         OM_uint32 aret;
 273         int send_token = 0;
 274 
 275         dprintf("Entering init_sec_context\n");
 276 
 277         output_token->length = 0;
 278         output_token->value = NULL;
 279         if (actual_mech_type)
 280                 *actual_mech_type = NULL;
 281 
 282         if (*context_handle == GSS_C_NO_CONTEXT) {
 283 
 284                 if (input_token != NULL && input_token->value != NULL)
 285                         return (GSS_S_FAILURE);
 286 
 287                 ctx = (dummy_gss_ctx_id_t)malloc(sizeof (dummy_gss_ctx_id_rec));
 288                 ctx->established = 0;
 289                 ctx->last_stat = 0xffffffff;
 290                 *context_handle = (gss_ctx_id_t)ctx;
 291                 /*
 292                  * Initiator interpretation of config file. If 2 or more
 293                  * the client returns CONTINUE_NNED on the first call.
 294                  */
 295                 if (token_nums >= 2) {
 296                         ret = GSS_S_CONTINUE_NEEDED;
 297                 } else {
 298                         ret = GSS_S_COMPLETE;
 299                 }
 300                 send_token = 1;
 301         } else {
 302                 unsigned char *ptr;
 303                 int bodysize;
 304                 int err;
 305 
 306                 if (input_token == NULL || input_token->value == NULL) {
 307                         ctx->last_stat = GSS_S_FAILURE;
 308                         return (GSS_S_FAILURE);
 309                 }
 310 
 311                 ctx = (dummy_gss_ctx_id_t)(*context_handle);
 312 
 313 
 314                 ptr = (unsigned char *) input_token->value;
 315                 if (err = g_verify_token_header((gss_OID)gss_mech_dummy,
 316                     &bodysize, &ptr, 0, input_token->length)) {
 317 
 318                         *minor_status = err;
 319                         ctx->last_stat = GSS_S_DEFECTIVE_TOKEN;
 320                         return (GSS_S_DEFECTIVE_TOKEN);
 321                 }
 322 
 323                 if (sscanf((char *)ptr, "%d", &aret) < 1) {
 324                         *minor_status = 1;
 325                         ctx->last_stat = GSS_S_DEFECTIVE_TOKEN;
 326                         return (GSS_S_DEFECTIVE_TOKEN);
 327                 }
 328 
 329                 if (aret == GSS_S_CONTINUE_NEEDED) {
 330                         if (ctx->last_stat == GSS_S_COMPLETE) {
 331                                 /*
 332                                  * RFC 2078, page 36, under GSS_S_COMPLETE
 333                                  * says that acceptor (target) has sufficient
 334                                  * information to perform per-message
 335                                  * processing. So if initiator previously
 336                                  * returned GSS_S_COMPLETE, and acceptor
 337                                  * says he needs more, then we have
 338                                  * a problem.
 339                                  */
 340                                 ctx->last_stat = GSS_S_FAILURE;
 341                                 return (GSS_S_FAILURE);
 342                         }
 343                         ret = GSS_S_CONTINUE_NEEDED;
 344                         send_token = 1;
 345                 } else {
 346                         ret = GSS_S_COMPLETE;
 347                         send_token = 0;
 348                 }
 349         }
 350         if (ret_flags)  /* user may pass a null pointer */
 351                 *ret_flags = dummy_flags;
 352         if (time_rec)  /* user may pass a null pointer */
 353                 *time_rec = GSS_C_INDEFINITE;
 354         if (actual_mech_type)
 355                 *actual_mech_type = (gss_OID) gss_mech_dummy;
 356 
 357         if (send_token == 1) {
 358                 sprintf(token_string, "%d", ret);
 359 
 360                 *output_token = make_dummy_token_msg(
 361                                 token_string, strlen(token_string) + 1);
 362         } else {
 363                 *output_token = make_dummy_token_msg(NULL, 0);
 364         }
 365 
 366         if (ret == GSS_S_COMPLETE)
 367                 ctx->established = 1;
 368 
 369         ctx->last_stat = ret;
 370         return (ret);
 371 }
 372 
 373 /*ARGSUSED*/
 374 OM_uint32
 375 dummy_gss_accept_sec_context(ct, minor_status, context_handle,
 376                                 verifier_cred_handle, input_token,
 377                                 input_chan_bindings, src_name, mech_type,
 378                                 output_token, ret_flags, time_rec,
 379                                 delegated_cred_handle)
 380         void *ct;
 381         OM_uint32 *minor_status;
 382         gss_ctx_id_t *context_handle;
 383         gss_cred_id_t verifier_cred_handle;
 384         gss_buffer_t input_token;
 385         gss_channel_bindings_t input_chan_bindings;
 386         gss_name_t *src_name;
 387         gss_OID *mech_type;
 388         gss_buffer_t output_token;
 389         OM_uint32 *ret_flags;
 390         OM_uint32 *time_rec;
 391         gss_cred_id_t *delegated_cred_handle;
 392 {
 393         dummy_gss_ctx_id_t ctx;
 394         char token_string[64];
 395         gss_buffer_desc name;
 396         OM_uint32 status;
 397         gss_name_t temp;
 398         unsigned char *ptr;
 399         int bodysize;
 400         int err;
 401         OM_uint32 iret;
 402         int return_token = 0;
 403 
 404         dprintf("Entering accept_sec_context\n");
 405 
 406         if (src_name)
 407                 *src_name = (gss_name_t)NULL;
 408         output_token->length = 0;
 409         output_token->value = NULL;
 410         if (mech_type)
 411                 *mech_type = GSS_C_NULL_OID;
 412         /* return a bogus cred handle */
 413         if (delegated_cred_handle)
 414                 *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
 415 
 416         /* Check for defective input token. */
 417         ptr = (unsigned char *) input_token->value;
 418         if (err = g_verify_token_header((gss_OID)gss_mech_dummy, &bodysize,
 419                                         &ptr, 0,
 420                                         input_token->length)) {
 421                 *minor_status = err;
 422                 return (GSS_S_DEFECTIVE_TOKEN);
 423         }
 424 
 425         if (sscanf((char *)ptr, "%d", &iret) < 1) {
 426                 *minor_status = 1;
 427                 return (GSS_S_DEFECTIVE_TOKEN);
 428         }
 429 
 430         if (*context_handle == GSS_C_NO_CONTEXT) {
 431                 ctx = (dummy_gss_ctx_id_t)malloc(sizeof (dummy_gss_ctx_id_rec));
 432                 ctx->token_number = token_nums;
 433                 ctx->established = 0;
 434                 *context_handle = (gss_ctx_id_t)ctx;
 435         } else {
 436                 ctx = (dummy_gss_ctx_id_t)(*context_handle);
 437         }
 438 
 439         if (ret_flags)  /* user may pass a null pointer */
 440                 *ret_flags = dummy_flags;
 441         if (time_rec)  /* user may pass a null pointer */
 442                 *time_rec = GSS_C_INDEFINITE;
 443         if (mech_type)
 444                 *mech_type = (gss_OID)gss_mech_dummy;
 445 
 446         /*
 447          * RFC 2078, page 36, under GSS_S_COMPLETE, GSS_S_CONTINUE_NEEDED
 448          * tells us whether to return a token or not.
 449          */
 450 
 451         if (iret == GSS_S_CONTINUE_NEEDED)
 452                 return_token = 1;
 453         else
 454                 return_token = 0;
 455 
 456 
 457         if (ctx->token_number > 1) {
 458                 /*
 459                  * RFC 2078, page 36, under GSS_S_COMPLETE, says that if
 460                  * initiator is done, the target (us) has what it needs, so
 461                  * it must return GSS_S_COMPLETE;
 462                  */
 463                 if (iret == GSS_S_CONTINUE_NEEDED)
 464                         status = GSS_S_CONTINUE_NEEDED;
 465                 else
 466                         status = GSS_S_COMPLETE;
 467 
 468         } else
 469                 status = GSS_S_COMPLETE;
 470 
 471         /* source name is ready at GSS_S_COMPLELE */
 472         if ((status == GSS_S_COMPLETE) && src_name) {
 473                 name.length = strlen(dummy_srcname);
 474                 name.value = dummy_srcname;
 475                 status = dummy_gss_import_name(ct, minor_status, &name,
 476                                 (gss_OID)GSS_C_NT_USER_NAME, &temp);
 477                 if (status != GSS_S_COMPLETE) {
 478                         free(*context_handle);
 479                         *context_handle = GSS_C_NO_CONTEXT;
 480                         return (status);
 481                 }
 482                 *src_name = temp;
 483         }
 484 
 485         if (status == GSS_S_COMPLETE) {
 486                 ctx->established = 1;
 487         }
 488 
 489         if (return_token == 1) {
 490                 sprintf(token_string, "%d", status);
 491 
 492                 *output_token = make_dummy_token_msg(
 493                                 token_string, strlen(token_string) + 1);
 494         } else {
 495                 *output_token = make_dummy_token_msg(NULL, 0);
 496         }
 497 
 498         if (ctx->token_number > 0)
 499                 ctx->token_number--;
 500 
 501         return (status);
 502 }
 503 
 504 
 505 /*ARGSUSED*/
 506 OM_uint32
 507 dummy_gss_process_context_token(ct, minor_status, context_handle, token_buffer)
 508         void *ct;
 509         OM_uint32 *minor_status;
 510         gss_ctx_id_t context_handle;
 511         gss_buffer_t token_buffer;
 512 {
 513         dprintf("In process_sec_context\n");
 514         return (GSS_S_COMPLETE);
 515 }
 516 
 517 /*ARGSUSED*/
 518 OM_uint32
 519 dummy_gss_delete_sec_context(ct, minor_status, context_handle, output_token)
 520         void *ct;
 521         OM_uint32 *minor_status;
 522         gss_ctx_id_t *context_handle;
 523         gss_buffer_t output_token;
 524 {
 525         dummy_gss_ctx_id_t ctx;
 526 
 527         dprintf("Entering delete_sec_context\n");
 528 
 529         /* Make the length to 0, so the output token is not sent to peer */
 530         if (output_token) {
 531                 output_token->length = 0;
 532                 output_token->value = NULL;
 533         }
 534 
 535         if (*context_handle == GSS_C_NO_CONTEXT) {
 536                 *minor_status = 0;
 537                 return (GSS_S_COMPLETE);
 538         }
 539 
 540         ctx = (dummy_gss_ctx_id_t)*context_handle;
 541         free(ctx);
 542         *context_handle = GSS_C_NO_CONTEXT;
 543 
 544         dprintf("Leaving delete_sec_context\n");
 545         return (GSS_S_COMPLETE);
 546 }
 547 
 548 
 549 /*ARGSUSED*/
 550 OM_uint32
 551 dummy_gss_context_time(ct, minor_status, context_handle, time_rec)
 552         void *ct;
 553         OM_uint32 *minor_status;
 554         gss_ctx_id_t context_handle;
 555         OM_uint32 *time_rec;
 556 {
 557         dprintf("In context_time\n");
 558         if (time_rec)  /* user may pass a null pointer */
 559                 return (GSS_S_FAILURE);
 560         else
 561                 *time_rec = GSS_C_INDEFINITE;
 562         return (GSS_S_COMPLETE);
 563 }
 564 
 565 /*ARGSUSED*/
 566 OM_uint32
 567 dummy_gss_sign(ctx, minor_status, context_handle,
 568                 qop_req, message_buffer, message_token)
 569         void *ctx;
 570         OM_uint32 *minor_status;
 571         gss_ctx_id_t context_handle;
 572         int qop_req;
 573         gss_buffer_t message_buffer;
 574         gss_buffer_t message_token;
 575 {
 576         char token_string[] = "dummy_gss_sign";
 577         dummy_gss_ctx_id_t context;
 578 
 579         dprintf("Entering gss_sign\n");
 580 
 581         context = (dummy_gss_ctx_id_t)(context_handle);
 582         if (context_handle == GSS_C_NO_CONTEXT)
 583                 return (GSS_S_NO_CONTEXT);
 584         if (!context->established)
 585                 return (GSS_S_NO_CONTEXT);
 586 
 587         *message_token = make_dummy_token_msg(
 588                         token_string, strlen(token_string));
 589 
 590         dprintf("Leaving gss_sign\n");
 591         return (GSS_S_COMPLETE);
 592 }
 593 
 594 /*ARGSUSED*/
 595 OM_uint32
 596 dummy_gss_verify(ctx, minor_status, context_handle,
 597                 message_buffer, token_buffer, qop_state)
 598         void *ctx;
 599         OM_uint32 *minor_status;
 600         gss_ctx_id_t context_handle;
 601         gss_buffer_t message_buffer;
 602         gss_buffer_t token_buffer;
 603         int *qop_state;
 604 {
 605         unsigned char *ptr;
 606         int bodysize;
 607         int err;
 608         dummy_gss_ctx_id_t context;
 609 
 610         dprintf("Entering gss_verify\n");
 611 
 612         context = (dummy_gss_ctx_id_t)(context_handle);
 613         if (context_handle == GSS_C_NO_CONTEXT)
 614                 return (GSS_S_NO_CONTEXT);
 615         if (!context->established)
 616                 return (GSS_S_NO_CONTEXT);
 617 
 618         /* Check for defective input token. */
 619         ptr = (unsigned char *) token_buffer->value;
 620         if (err = g_verify_token_header((gss_OID)gss_mech_dummy, &bodysize,
 621                                         &ptr, 0,
 622                                         token_buffer->length)) {
 623                 *minor_status = err;
 624                 return (GSS_S_DEFECTIVE_TOKEN);
 625         }
 626 
 627         if (qop_state)
 628                 *qop_state = GSS_C_QOP_DEFAULT;
 629 
 630         dprintf("Leaving gss_verify\n");
 631         return (GSS_S_COMPLETE);
 632 }
 633 
 634 /*ARGSUSED*/
 635 OM_uint32
 636 dummy_gss_seal(ctx, minor_status, context_handle, conf_req_flag,
 637                 qop_req, input_message_buffer, conf_state,
 638                 output_message_buffer)
 639         void *ctx;
 640         OM_uint32 *minor_status;
 641         gss_ctx_id_t context_handle;
 642         int conf_req_flag;
 643         int qop_req;
 644         gss_buffer_t input_message_buffer;
 645         int *conf_state;
 646         gss_buffer_t output_message_buffer;
 647 {
 648         gss_buffer_desc output;
 649         dummy_gss_ctx_id_t context;
 650 
 651         dprintf("Entering gss_seal\n");
 652 
 653         context = (dummy_gss_ctx_id_t)(context_handle);
 654         if (context_handle == GSS_C_NO_CONTEXT)
 655                 return (GSS_S_NO_CONTEXT);
 656         if (!context->established)
 657                 return (GSS_S_NO_CONTEXT);
 658 
 659         /* Copy the input message to output message */
 660         output = make_dummy_token_msg(
 661                 input_message_buffer->value, input_message_buffer->length);
 662 
 663         if (conf_state)
 664                 *conf_state = 1;
 665 
 666         *output_message_buffer = output;
 667 
 668         dprintf("Leaving gss_seal\n");
 669         return (GSS_S_COMPLETE);
 670 }
 671 
 672 
 673 
 674 
 675 /*ARGSUSED*/
 676 OM_uint32
 677 dummy_gss_unseal(ctx, minor_status, context_handle,
 678                 input_message_buffer, output_message_buffer,
 679                 conf_state, qop_state)
 680         void *ctx;
 681         OM_uint32 *minor_status;
 682         gss_ctx_id_t context_handle;
 683         gss_buffer_t input_message_buffer;
 684         gss_buffer_t output_message_buffer;
 685         int *conf_state;
 686         int *qop_state;
 687 {
 688         gss_buffer_desc output;
 689         unsigned char *ptr;
 690         int bodysize;
 691         int err;
 692         dummy_gss_ctx_id_t context;
 693 
 694         dprintf("Entering gss_unseal\n");
 695 
 696         context = (dummy_gss_ctx_id_t)(context_handle);
 697         if (context_handle == GSS_C_NO_CONTEXT)
 698                 return (GSS_S_NO_CONTEXT);
 699         if (!context->established)
 700                 return (GSS_S_NO_CONTEXT);
 701 
 702         ptr = (unsigned char *) input_message_buffer->value;
 703         if (err = g_verify_token_header((gss_OID)gss_mech_dummy, &bodysize,
 704                                         &ptr, 0,
 705                                         input_message_buffer->length)) {
 706                 *minor_status = err;
 707                 return (GSS_S_DEFECTIVE_TOKEN);
 708         }
 709         output.length = bodysize;
 710         output.value = (void *)malloc(output.length);
 711         memcpy(output.value, ptr, output.length);
 712 
 713         *output_message_buffer = output;
 714         if (qop_state)
 715                 *qop_state = GSS_C_QOP_DEFAULT;
 716         if (conf_state)
 717                 *conf_state = 1;
 718 
 719         dprintf("Leaving gss_unseal\n");
 720         return (GSS_S_COMPLETE);
 721 }
 722 
 723 /*ARGSUSED*/
 724 OM_uint32
 725 dummy_gss_display_status(ctx, minor_status, status_value, status_type,
 726                         mech_type, message_context, status_string)
 727         void *ctx;
 728         OM_uint32 *minor_status;
 729         OM_uint32 status_value;
 730         int status_type;
 731         gss_OID mech_type;
 732         OM_uint32 *message_context;
 733         gss_buffer_t status_string;
 734 {
 735         dprintf("Entering display_status\n");
 736 
 737         *message_context = 0;
 738         *status_string = make_dummy_token_buffer("dummy_gss_display_status");
 739 
 740         dprintf("Leaving display_status\n");
 741         return (GSS_S_COMPLETE);
 742 }
 743 
 744 /*ARGSUSED*/
 745 OM_uint32
 746 dummy_gss_indicate_mechs(ctx, minor_status, mech_set)
 747         void *ctx;
 748         OM_uint32 *minor_status;
 749         gss_OID_set *mech_set;
 750 {
 751         dprintf("Entering indicate_mechs\n");
 752 
 753         *minor_status = 0;
 754         if (mech_set) {
 755                 if (gss_copy_oid_set(minor_status, gss_mech_set_dummy,
 756                                 mech_set) == GSS_S_FAILURE) {
 757                         return (GSS_S_FAILURE);
 758                 }
 759         }
 760 
 761         dprintf("Leaving indicate_mechs\n");
 762         return (GSS_S_COMPLETE);
 763 }
 764 
 765 /*ARGSUSED*/
 766 OM_uint32
 767 dummy_gss_compare_name(ctx, minor_status, name1, name2, name_equal)
 768         void *ctx;
 769         OM_uint32 *minor_status;
 770         gss_name_t name1;
 771         gss_name_t name2;
 772         int *name_equal;
 773 {
 774         dummy_name_t name_1 = (dummy_name_t)name1;
 775         dummy_name_t name_2 = (dummy_name_t)name2;
 776 
 777         dprintf("Entering compare_name\n");
 778 
 779         if (g_OID_equal(name_1->type, name_2->type) &&
 780         (name_1->buffer->length == name_2->buffer->length) &&
 781         !memcmp(name_1->buffer->value, name_2->buffer->value,
 782         name_1->buffer->length))
 783                 *name_equal = 1;
 784         else
 785                 *name_equal = 0;
 786 
 787         dprintf("Leaving compare_name\n");
 788         return (GSS_S_COMPLETE);
 789 }
 790 
 791 /*ARGSUSED*/
 792 OM_uint32
 793 dummy_gss_display_name(ctx, minor_status, input_name, output_name_buffer,
 794                         output_name_type)
 795         void *ctx;
 796         OM_uint32 *minor_status;
 797         gss_name_t input_name;
 798         gss_buffer_t output_name_buffer;
 799         gss_OID *output_name_type;
 800 {
 801         OM_uint32 status = GSS_S_COMPLETE;
 802         dummy_name_t name = (dummy_name_t)input_name;
 803 
 804         dprintf("Entering display_name\n");
 805 
 806         if (g_OID_equal(name->type, GSS_C_NT_USER_NAME) ||
 807         g_OID_equal(name->type, GSS_C_NT_MACHINE_UID_NAME) ||
 808         g_OID_equal(name->type, GSS_C_NT_STRING_UID_NAME) ||
 809         g_OID_equal(name->type, GSS_C_NT_HOSTBASED_SERVICE)) {
 810 /*
 811  *              output_name_buffer = (gss_buffer_t)
 812  *                                      malloc(sizeof (gss_buffer_desc));
 813  */
 814                 if (output_name_buffer == NULL)
 815                         return (GSS_S_FAILURE);
 816 
 817                 output_name_buffer->length = name->buffer->length;
 818                 output_name_buffer->value = (void *)
 819                                                 malloc(name->buffer->length);
 820                 if (output_name_buffer->value == NULL)
 821                         return (GSS_S_FAILURE);
 822 
 823                 memcpy(output_name_buffer->value, name->buffer->value,
 824                         name->buffer->length);
 825                 if (output_name_type)
 826                         *output_name_type = name->type;
 827 
 828                 dprintf("Leaving display_name\n");
 829                 return (status);
 830         }
 831 
 832         dprintf("Leaving display_name\n");
 833         return (GSS_S_BAD_NAMETYPE);
 834 }
 835 
 836 /*ARGSUSED*/
 837 OM_uint32
 838 dummy_gss_import_name(ctx, minor_status, input_name_buffer,
 839                         input_name_type, output_name)
 840         void *ctx;
 841         OM_uint32 *minor_status;
 842         gss_buffer_t input_name_buffer;
 843         gss_OID input_name_type;
 844         gss_name_t *output_name;
 845 {
 846         OM_uint32 status;
 847 
 848         dprintf("Entering import_name\n");
 849 
 850         *output_name = NULL;
 851         *minor_status = 0;
 852 
 853         if (input_name_type == GSS_C_NULL_OID)
 854                 return (GSS_S_BAD_NAMETYPE);
 855 
 856         if (g_OID_equal(input_name_type, GSS_C_NT_USER_NAME) ||
 857         g_OID_equal(input_name_type, GSS_C_NT_MACHINE_UID_NAME) ||
 858         g_OID_equal(input_name_type, GSS_C_NT_STRING_UID_NAME) ||
 859         g_OID_equal(input_name_type, GSS_C_NT_HOSTBASED_SERVICE)) {
 860                 dummy_name_t name = (dummy_name_t)
 861                                         malloc(sizeof (dummy_name_desc));
 862                 name->buffer = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
 863                 name->buffer->length = input_name_buffer->length;
 864                 name->buffer->value = (void *)malloc(input_name_buffer->length);
 865                 if (name->buffer->value == NULL)
 866                         return (GSS_S_FAILURE);
 867 
 868                 memcpy(name->buffer->value, input_name_buffer->value,
 869                                 input_name_buffer->length);
 870 
 871                 status = generic_gss_copy_oid(minor_status,
 872                 input_name_type, &(name->type));
 873                 *output_name = (gss_name_t)name;
 874                 dprintf("Leaving import_name\n");
 875                 return (status);
 876         }
 877         dprintf("Leaving import_name\n");
 878         return (GSS_S_BAD_NAMETYPE);
 879 }
 880 
 881 /*ARGSUSED*/
 882 OM_uint32
 883 dummy_gss_release_name(ctx, minor_status, input_name)
 884         void *ctx;
 885         OM_uint32 *minor_status;
 886         gss_name_t *input_name;
 887 {
 888         dummy_name_t name = (dummy_name_t)*input_name;
 889 
 890         dprintf("Entering release_name\n");
 891         free(name->buffer->value);
 892         generic_gss_release_oid(minor_status, &(name->type));
 893         free(name->buffer);
 894         free(name);
 895         dprintf("Leaving release_name\n");
 896         return (GSS_S_COMPLETE);
 897 }
 898 
 899 /*ARGSUSED*/
 900 OM_uint32
 901 dummy_gss_inquire_cred(ctx, minor_status, cred_handle, name, lifetime_ret,
 902                         cred_usage, mechanisms)
 903         void *ctx;
 904         OM_uint32 *minor_status;
 905         gss_cred_id_t cred_handle;
 906         gss_name_t *name;
 907         OM_uint32 *lifetime_ret;
 908         gss_cred_usage_t *cred_usage;
 909         gss_OID_set *mechanisms;
 910 {
 911         dprintf("Entering inquire_cred\n");
 912         if (name)
 913                 *name = (gss_name_t)make_dummy_token
 914                                 ("dummy gss credential");
 915         if (lifetime_ret)
 916                 *lifetime_ret = GSS_C_INDEFINITE;
 917         if (cred_usage)
 918                 *cred_usage = GSS_C_BOTH;
 919         if (mechanisms) {
 920                 if (gss_copy_oid_set(minor_status, gss_mech_set_dummy,
 921                                 mechanisms) == GSS_S_FAILURE)
 922                         return (GSS_S_FAILURE);
 923         }
 924 
 925         dprintf("Leaving inquire_cred\n");
 926         return (GSS_S_COMPLETE);
 927 }
 928 
 929 /*ARGSUSED*/
 930 OM_uint32
 931 dummy_gss_add_cred(ctx, minor_status, input_cred_handle,
 932                         desired_name, desired_mech, cred_usage,
 933                         initiator_time_req, acceptor_time_req,
 934                         output_cred_handle, actual_mechs,
 935                         initiator_time_rec, acceptor_time_rec)
 936         void *ctx;
 937         OM_uint32 *minor_status;
 938         gss_cred_id_t input_cred_handle;
 939         gss_name_t desired_name;
 940         gss_OID desired_mech;
 941         gss_cred_usage_t cred_usage;
 942         OM_uint32 initiator_time_req;
 943         OM_uint32 acceptor_time_req;
 944         gss_cred_id_t *output_cred_handle;
 945         gss_OID_set *actual_mechs;
 946         OM_uint32 *initiator_time_rec;
 947         OM_uint32 *acceptor_time_rec;
 948 {
 949         dprintf("Entering add_cred\n");
 950 
 951         if ((desired_mech != GSS_C_NULL_OID) &&
 952         (g_OID_equal(desired_mech, gss_mech_dummy)))
 953                 return (GSS_S_BAD_MECH);
 954         *minor_status = 0;
 955 
 956         dprintf("Leaving add_cred\n");
 957 
 958         /* This routine likes in kerberos V5 is never be used / called by */
 959         /* the GSS_API. It simply returns GSS_S_DUPLICATE_ELEMENT to indicate */
 960         /* this error */
 961 
 962         return (GSS_S_DUPLICATE_ELEMENT);
 963 }
 964 
 965 /* Should I add the token structure to deal with import/export */
 966 /* of sec_context. For now, I just create dummy interprocess token, and when */
 967 /* the peer accept it, it calls the import_sec_context.The import_sec_context */
 968 /* creates new sec_context with status established. (rather than get it */
 969 /* from interprocess token. it can be done because the sec context in dummy */
 970 /* mechanism is very simple (contains only status if it's established). */
 971 /*ARGSUSED*/
 972 OM_uint32
 973 dummy_gss_export_sec_context(ct, minor_status, context_handle,
 974                                 interprocess_token)
 975         void *ct;
 976         OM_uint32 *minor_status;
 977         gss_ctx_id_t *context_handle;
 978         gss_buffer_t interprocess_token;
 979 {
 980         char str[] = "dummy_gss_export_sec_context";
 981 
 982         dprintf("Entering export_sec_context\n");
 983 
 984         *interprocess_token = make_dummy_token_msg(str, strlen(str));
 985         free(*context_handle);
 986         *context_handle = GSS_C_NO_CONTEXT;
 987 
 988         dprintf("Leaving export_sec_context\n");
 989         return (GSS_S_COMPLETE);
 990 }
 991 
 992 /*ARGSUSED*/
 993 OM_uint32
 994 dummy_gss_import_sec_context(ct, minor_status, interprocess_token,
 995                                 context_handle)
 996 void *ct;
 997 OM_uint32 *minor_status;
 998 gss_buffer_t interprocess_token;
 999 gss_ctx_id_t *context_handle;
1000 {
1001         /* Assume that we got ctx from the interprocess token. */
1002         dummy_gss_ctx_id_t ctx;
1003 
1004         dprintf("Entering import_sec_context\n");
1005 
1006         ctx = (dummy_gss_ctx_id_t)malloc(sizeof (dummy_gss_ctx_id_rec));
1007         ctx->token_number = 0;
1008         ctx->established = 1;
1009 
1010         *context_handle = (gss_ctx_id_t)ctx;
1011 
1012         dprintf("Leaving import_sec_context\n");
1013         return (GSS_S_COMPLETE);
1014 }
1015 
1016 /*ARGSUSED*/
1017 OM_uint32
1018 dummy_gss_inquire_cred_by_mech(ctx, minor_status, cred_handle,
1019                                 mech_type, name, initiator_lifetime,
1020                                 acceptor_lifetime, cred_usage)
1021         void *ctx;
1022         OM_uint32 *minor_status;
1023         gss_cred_id_t cred_handle;
1024         gss_OID mech_type;
1025         gss_name_t *name;
1026         OM_uint32 *initiator_lifetime;
1027         OM_uint32 *acceptor_lifetime;
1028         gss_cred_usage_t *cred_usage;
1029 {
1030         dprintf("Entering inquire_cred_by_mech\n");
1031         if (name)
1032                 *name = (gss_name_t)make_dummy_token("dummy credential name");
1033         if (initiator_lifetime)
1034                 *initiator_lifetime = GSS_C_INDEFINITE;
1035         if (acceptor_lifetime)
1036                 *acceptor_lifetime = GSS_C_INDEFINITE;
1037         if (cred_usage)
1038                 *cred_usage = GSS_C_BOTH;
1039 
1040         dprintf("Leaving inquire_cred_by_mech\n");
1041         return (GSS_S_COMPLETE);
1042 }
1043 
1044 /*ARGSUSED*/
1045 OM_uint32
1046 dummy_gss_inquire_names_for_mech(ctx, minor_status, mechanism, name_types)
1047         void            *ctx;
1048         OM_uint32       *minor_status;
1049         gss_OID         mechanism;
1050         gss_OID_set     *name_types;
1051 {
1052         OM_uint32   major, minor;
1053 
1054         dprintf("Entering inquire_names_for_mech\n");
1055         /*
1056          * We only know how to handle our own mechanism.
1057          */
1058         if ((mechanism != GSS_C_NULL_OID) &&
1059         !g_OID_equal(gss_mech_dummy, mechanism)) {
1060                 *minor_status = 0;
1061                 return (GSS_S_FAILURE);
1062         }
1063 
1064         major = gss_create_empty_oid_set(minor_status, name_types);
1065         if (major == GSS_S_COMPLETE) {
1066                 /* Now add our members. */
1067                 if (((major = gss_add_oid_set_member(minor_status,
1068                         (gss_OID) GSS_C_NT_USER_NAME, name_types))
1069                 == GSS_S_COMPLETE) &&
1070                 ((major = gss_add_oid_set_member(minor_status,
1071                         (gss_OID) GSS_C_NT_MACHINE_UID_NAME, name_types))
1072                 == GSS_S_COMPLETE) &&
1073                 ((major = gss_add_oid_set_member(minor_status,
1074                         (gss_OID) GSS_C_NT_STRING_UID_NAME, name_types))
1075                 == GSS_S_COMPLETE)) {
1076                         major = gss_add_oid_set_member(minor_status,
1077                         (gss_OID) GSS_C_NT_HOSTBASED_SERVICE, name_types);
1078                 }
1079 
1080                 if (major != GSS_S_COMPLETE)
1081                         (void) gss_release_oid_set(&minor, name_types);
1082         }
1083 
1084         dprintf("Leaving inquire_names_for_mech\n");
1085         return (major);
1086 }
1087 
1088 /*ARGSUSED*/
1089 OM_uint32
1090 dummy_gss_inquire_context(ct, minor_status, context_handle, initiator_name,
1091                         acceptor_name, lifetime_rec, mech_type, ret_flags,
1092                         locally_initiated, open)
1093         void *ct;
1094         OM_uint32 *minor_status;
1095         gss_ctx_id_t context_handle;
1096         gss_name_t *initiator_name;
1097         gss_name_t *acceptor_name;
1098         OM_uint32 *lifetime_rec;
1099         gss_OID *mech_type;
1100         OM_uint32 *ret_flags;
1101         int *locally_initiated;
1102         int *open;
1103 {
1104         dummy_gss_ctx_id_t ctx;
1105         dummy_name_t name1, name2;
1106         OM_uint32 status;
1107 
1108         dprintf("Entering inquire_context\n");
1109 
1110         ctx = (dummy_gss_ctx_id_t)(context_handle);
1111         name1 = (dummy_name_t)
1112                                 malloc(sizeof (dummy_name_desc));
1113         name1->buffer = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
1114         name1->buffer->length = dummy_context_name_len;
1115         name1->buffer->value = make_dummy_token("dummy context name");
1116         status = generic_gss_copy_oid(minor_status,
1117                 (gss_OID) GSS_C_NT_USER_NAME, &(name1->type));
1118         if (status != GSS_S_COMPLETE)
1119                 return (status);
1120         if (initiator_name)
1121                 *initiator_name = (gss_name_t)name1;
1122 
1123         name2 = (dummy_name_t)
1124                                 malloc(sizeof (dummy_name_desc));
1125         name2->buffer = (gss_buffer_t)malloc(sizeof (gss_buffer_desc));
1126         name2->buffer->length = dummy_context_name_len;
1127         name2->buffer->value = make_dummy_token("dummy context name");
1128         status = generic_gss_copy_oid(minor_status,
1129                 (gss_OID) GSS_C_NT_USER_NAME, &(name2->type));
1130         if (status != GSS_S_COMPLETE)
1131                 return (status);
1132         if (acceptor_name)
1133                 *acceptor_name = (gss_name_t)name2;
1134 
1135         if (lifetime_rec)  /* user may pass a null pointer */
1136                 *lifetime_rec = GSS_C_INDEFINITE;
1137         if (mech_type)
1138                 *mech_type = (gss_OID)gss_mech_dummy;
1139         if (ret_flags)
1140                 *ret_flags = dummy_flags;
1141         if (open)
1142         *open = ctx->established;
1143 
1144         dprintf("Leaving inquire_context\n");
1145         return (GSS_S_COMPLETE);
1146 }
1147 
1148 /*ARGSUSED*/
1149 OM_uint32
1150 dummy_gss_internal_release_oid(ct, minor_status, oid)
1151         void            *ct;
1152         OM_uint32       *minor_status;
1153         gss_OID         *oid;
1154 {
1155         dprintf("Entering internal_release_oid\n");
1156 
1157         /* Similar to krb5_gss_internal_release_oid */
1158 
1159         if (*oid != gss_mech_dummy)
1160                 return (GSS_S_CONTINUE_NEEDED); /* We don't know this oid */
1161 
1162         *minor_status = 0;
1163         *oid = GSS_C_NO_OID;
1164 
1165         dprintf("Leaving internal_release_oid\n");
1166         return (GSS_S_COMPLETE);
1167 }
1168 
1169 /*ARGSUSED*/
1170 OM_uint32
1171 dummy_gss_wrap_size_limit(ct, minor_status, context_handle, conf_req_flag,
1172                                 qop_req, req_output_size, max_input_size)
1173         void            *ct;
1174         OM_uint32       *minor_status;
1175         gss_ctx_id_t    context_handle;
1176         int             conf_req_flag;
1177         gss_qop_t       qop_req;
1178         OM_uint32       req_output_size;
1179         OM_uint32       *max_input_size;
1180 {
1181         dprintf("Entering wrap_size_limit\n");
1182         *max_input_size = req_output_size;
1183         dprintf("Leaving wrap_size_limit\n");
1184         return (GSS_S_COMPLETE);
1185 }
1186 
1187 /* ARGSUSED */
1188 OM_uint32
1189 dummy_pname_to_uid(ct, minor_status, name, uidOut)
1190         void *ct;
1191         OM_uint32 *minor_status;
1192         const gss_name_t name;
1193         uid_t *uidOut;
1194 {
1195         dprintf("Entering pname_to_uid\n");
1196         *minor_status = 0;
1197         *uidOut = 60001;
1198         dprintf("Leaving pname_to_uid\n");
1199         return (GSS_S_COMPLETE);
1200 }
1201 
1202 static dummy_token_t
1203 make_dummy_token(char *name)
1204 {
1205         dummy_token_t token;
1206 
1207         token = (dummy_token_t)malloc(strlen(name)+1);
1208         strcpy(token, name);
1209         return (token);
1210 }
1211 
1212 static void
1213 free_dummy_token(dummy_token_t *token)
1214 {
1215         free(*token);
1216         *token = NULL;
1217 }
1218 
1219 static gss_buffer_desc
1220 make_dummy_token_buffer(char *name)
1221 {
1222         gss_buffer_desc buffer;
1223 
1224         if (name == NULL) {
1225                 buffer.length = 0;
1226                 buffer.value = NULL;
1227         } else {
1228                 buffer.length = strlen(name)+1;
1229                 buffer.value = make_dummy_token(name);
1230         }
1231         return (buffer);
1232 }
1233 
1234 static gss_buffer_desc
1235 make_dummy_token_msg(void *data, int dataLen)
1236 {
1237         gss_buffer_desc buffer;
1238         int tlen;
1239         unsigned char *t;
1240         unsigned char *ptr;
1241 
1242         if (data == NULL) {
1243                 buffer.length = 0;
1244                 buffer.value = NULL;
1245                 return (buffer);
1246         }
1247 
1248         tlen = g_token_size((gss_OID)gss_mech_dummy, dataLen);
1249         t = (unsigned char *) malloc(tlen);
1250         ptr = t;
1251 
1252         g_make_token_header((gss_OID)gss_mech_dummy, dataLen, &ptr, 0);
1253         memcpy(ptr, data, dataLen);
1254 
1255         buffer.length = tlen;
1256         buffer.value = (void *) t;
1257         return (buffer);
1258 }
1259 
1260 static int
1261 der_length_size(length)
1262         int length;
1263 {
1264         if (length < (1<<7))
1265                 return (1);
1266         else if (length < (1<<8))
1267                 return (2);
1268         else if (length < (1<<16))
1269                 return (3);
1270         else if (length < (1<<24))
1271                 return (4);
1272         else
1273                 return (5);
1274 }
1275 
1276 static void
1277 der_write_length(buf, length)
1278         unsigned char **buf;
1279         int length;
1280 {
1281         if (length < (1<<7)) {
1282                 *(*buf)++ = (unsigned char) length;
1283         } else {
1284                 *(*buf)++ = (unsigned char) (der_length_size(length)+127);
1285                 if (length >= (1<<24))
1286                         *(*buf)++ = (unsigned char) (length>>24);
1287                 if (length >= (1<<16))
1288                         *(*buf)++ = (unsigned char) ((length>>16)&0xff);
1289                 if (length >= (1<<8))
1290                         *(*buf)++ = (unsigned char) ((length>>8)&0xff);
1291                 *(*buf)++ = (unsigned char) (length&0xff);
1292         }
1293 }
1294 
1295 static int
1296 der_read_length(buf, bufsize)
1297 unsigned char **buf;
1298 int *bufsize;
1299 {
1300         unsigned char sf;
1301         int ret;
1302 
1303         if (*bufsize < 1)
1304                 return (-1);
1305 
1306         sf = *(*buf)++;
1307         (*bufsize)--;
1308         if (sf & 0x80) {
1309                 if ((sf &= 0x7f) > ((*bufsize)-1))
1310                         return (-1);
1311 
1312                 if (sf > DUMMY_SIZE_OF_INT)
1313                         return (-1);
1314                 ret = 0;
1315                 for (; sf; sf--) {
1316                 ret = (ret<<8) + (*(*buf)++);
1317                 (*bufsize)--;
1318         }
1319         } else {
1320                 ret = sf;
1321         }
1322 
1323         return (ret);
1324 }
1325 
1326 static int
1327 g_token_size(mech, body_size)
1328         gss_OID mech;
1329         unsigned int body_size;
1330 {
1331         /* set body_size to sequence contents size */
1332         body_size += 4 + (int)mech->length;  /* NEED overflow check */
1333         return (1 + der_length_size(body_size) + body_size);
1334 }
1335 
1336 static void
1337 g_make_token_header(mech, body_size, buf, tok_type)
1338         gss_OID mech;
1339         int body_size;
1340         unsigned char **buf;
1341         int tok_type;
1342 {
1343         *(*buf)++ = 0x60;
1344         der_write_length(buf, 4 + mech->length + body_size);
1345         *(*buf)++ = 0x06;
1346         *(*buf)++ = (unsigned char) mech->length;
1347         TWRITE_STR(*buf, mech->elements, ((int)mech->length));
1348         *(*buf)++ = (unsigned char) ((tok_type>>8)&0xff);
1349         *(*buf)++ = (unsigned char) (tok_type&0xff);
1350 }
1351 
1352 static int
1353 g_verify_token_header(mech, body_size, buf_in, tok_type, toksize)
1354 gss_OID mech;
1355 int *body_size;
1356 unsigned char **buf_in;
1357 int tok_type;
1358 int toksize;
1359 {
1360         unsigned char *buf = *buf_in;
1361         int seqsize;
1362         gss_OID_desc toid;
1363         int ret = 0;
1364 
1365         if ((toksize -= 1) < 0)
1366                 return (G_BAD_TOK_HEADER);
1367         if (*buf++ != 0x60)
1368                 return (G_BAD_TOK_HEADER);
1369 
1370         if ((seqsize = der_read_length(&buf, &toksize)) < 0)
1371                 return (G_BAD_TOK_HEADER);
1372 
1373         if (seqsize != toksize)
1374                 return (G_BAD_TOK_HEADER);
1375 
1376         if ((toksize -= 1) < 0)
1377                 return (G_BAD_TOK_HEADER);
1378         if (*buf++ != 0x06)
1379                 return (G_BAD_TOK_HEADER);
1380 
1381         if ((toksize -= 1) < 0)
1382                 return (G_BAD_TOK_HEADER);
1383         toid.length = *buf++;
1384 
1385         if ((toksize -= toid.length) < 0)
1386                 return (G_BAD_TOK_HEADER);
1387         toid.elements = buf;
1388         buf += toid.length;
1389 
1390         if (!g_OID_equal(&toid, mech))
1391                 ret = G_WRONG_MECH;
1392 
1393         /*
1394          * G_WRONG_MECH is not returned immediately because it's more important
1395          * to return G_BAD_TOK_HEADER if the token header is in fact bad
1396          */
1397 
1398         if ((toksize -= 2) < 0)
1399                 return (G_BAD_TOK_HEADER);
1400 
1401         if ((*buf++ != ((tok_type>>8)&0xff)) ||
1402             (*buf++ != (tok_type&0xff)))
1403                 return (G_BAD_TOK_HEADER);
1404 
1405         if (!ret) {
1406                 *buf_in = buf;
1407                 *body_size = toksize;
1408         }
1409 
1410         return (ret);
1411 }