xref: /illumos-gate/usr/src/lib/gss_mechs/mech_dummy/mech/dmech.c (revision 8119dad84d6416f13557b0ba8e2aaf9064cbcfd3)
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 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  * Copyright (c) 2016 by Delphix. All rights reserved.
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 it 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 }
1412