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