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