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