xref: /illumos-gate/usr/src/cmd/gss/gssd/gssdtest.c (revision 13b136d3061155363c62c9f6568d25b8b27da8f6)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2017 Gary Mills
24  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 /*
29  * Test client for gssd.  This program is not shipped on the binary
30  * release.
31  */
32 
33 #include <stdio.h>
34 #include <strings.h>
35 #include <ctype.h>
36 #include <stdlib.h>
37 #include <gssapi/gssapi.h>
38 #include <gssapi/gssapi_ext.h>
39 #include "gssd.h"
40 #include <rpc/rpc.h>
41 
42 #define	_KERNEL
43 #include <gssapi/gssapi.h>
44 #undef	_KERNEL
45 
46 int gss_major_code;
47 int gss_minor_code;
48 
49 int init_sec_context_phase = 0;
50 int accept_sec_context_phase = 0;
51 
52 gss_ctx_id_t    initiator_context_handle;
53 gss_ctx_id_t    acceptor_context_handle;
54 gss_cred_id_t   acceptor_credentials;
55 gss_buffer_desc init_token_buffer;
56 gss_buffer_desc accept_token_buffer;
57 gss_buffer_desc delete_token_buffer;
58 gss_buffer_desc message_buffer;
59 gss_buffer_desc msg_token;
60 
61 #define	LOOP_COUNTER  100
62 #define	GSS_KRB5_MECH_OID "1.2.840.113554.1.2.2"
63 #define	GSS_DUMMY_MECH_OID "1.3.6.1.4.1.42.2.26.1.2"
64 #ifdef _KERNEL
65 #define	OCTAL_MACRO "%03o."
66 #define	MALLOC(n) kmem_alloc((n), KM_SLEEP)
67 #define	CALLOC(n, s) kmem_zalloc((n)*(s), KM_SLEEP)
68 #define	FREE(x, n) kmem_free((x), (n))
69 #define	memcpy(dst, src, n) bcopy((src), (dst), (n))
70 #define	fprintf(s, m) printf(m)
71 #define	isspace(s) ((s) == ' ' || (s) == '\t' || (s) == '\n' || \
72 		(s) == '\r' || (s) == '\v' || (s) == '\f')
73 
74 static char *strdup(const char *s)
75 {
76 	int len = strlen(s);
77 	char *new = MALLOC(len+1);
78 	strcpy(new, s);
79 	return (new);
80 }
81 
82 #else /* !_KERNEL */
83 #define	OCTAL_MACRO "%03.3o."
84 #define	MALLOC(n) malloc(n)
85 #define	CALLOC(n, s) calloc((n), (s))
86 #define	FREE(x, n) free(x)
87 #endif /* _KERNEL */
88 
89 static gss_OID gss_str2oid(char *);
90 static char * gss_oid2str(gss_OID);
91 static void instructs();
92 static void usage();
93 static int parse_input_line(char *, int *, char ***);
94 extern uid_t getuid();
95 
96 static void _gss_init_sec_context(int, char **);
97 static void _gss_acquire_cred(int, char **);
98 static void _gss_add_cred(int, char **);
99 static void _gss_sign(int, char **);
100 static void _gss_release_cred(int, char **);
101 static void _gss_accept_sec_context(int, char **);
102 static void _gss_process_context_token(int, char **);
103 static void _gss_delete_sec_context(int, char **);
104 static void _gss_context_time(int, char **);
105 static void _gss_verify(int, char **);
106 static void _gss_seal(int, char **);
107 static void _gss_unseal(int, char **);
108 static void _gss_display_status(int, char **);
109 static void _gss_indicate_mechs(int, char **);
110 static void _gss_inquire_cred(int, char **);
111 static void _gssd_expname_to_unix_cred(int, char **);
112 static void _gssd_name_to_unix_cred(int, char **);
113 static void _gssd_get_group_info(int, char **);
114 
115 static int do_gssdtest(char *buf);
116 
117 
118 #ifndef _KERNEL
119 static int read_line(char *buf, int size)
120 {
121 	int len;
122 
123 	/* read the next line. If cntl-d, return with zero char count */
124 	printf(gettext("\n> "));
125 
126 	if (fgets(buf, size, stdin) == NULL)
127 		return (0);
128 
129 	len = strlen(buf);
130 	buf[--len] = '\0';
131 	return (len);
132 }
133 
134 int
135 main()
136 {
137 	char buf[512];
138 	int len, ret;
139 
140 	/* Print out usage and instructions to start off the session */
141 
142 	instructs();
143 	usage();
144 
145 	/*
146 	 * Loop, repeatedly calling parse_input_line() to get the
147 	 * next line and parse it into argc and argv. Act on the
148 	 * arguements found on the line.
149 	 */
150 
151 	do {
152 		len = read_line(buf, 512);
153 		if (len)
154 			ret = do_gssdtest(buf);
155 	} while (len && !ret);
156 
157 	return (0);
158 }
159 #endif /* !_KERNEL */
160 
161 static int
162 do_gssdtest(char *buf)
163 {
164 	int argc, seal_argc;
165 	int i;
166 	char **argv, **argv_array;
167 
168 	char *cmd;
169 	char *seal_ini_array [] = { "initiator", " Hello"};
170 	char *seal_acc_array [] = { "acceptor", " Hello"};
171 	char *unseal_acc_array [] = {"acceptor"};
172 	char *unseal_ini_array [] = {"initiator"};
173 	char *delet_acc_array [] = {"acceptor"};
174 	char *delet_ini_array [] = {"initiator"};
175 
176 	argv = 0;
177 
178 	if (parse_input_line(buf, &argc, &argv) == 0) {
179 		printf(gettext("\n"));
180 		return (1);
181 	}
182 
183 	if (argc == 0) {
184 		usage();
185 		/*LINTED*/
186 		FREE(argv_array, (argc+1)*sizeof (char *));
187 		return (0);
188 	}
189 
190 	/*
191 	 * remember argv_array address, which is memory calloc'd by
192 	 * parse_input_line, so it can be free'd at the end of the loop.
193 	 */
194 
195 	argv_array = argv;
196 
197 	cmd = argv[0];
198 
199 	argc--;
200 	argv++;
201 
202 	if (strcmp(cmd, "gss_loop") == 0 ||
203 	    strcmp(cmd, "loop") == 0) {
204 
205 		if (argc < 1) {
206 			usage();
207 			FREE(argv_array, (argc+2) * sizeof (char *));
208 			return (0);
209 		}
210 		for (i = 0; i < LOOP_COUNTER; i++) {
211 			printf(gettext("Loop Count is %d \n"), i);
212 			/*
213 			 * if (i > 53)
214 			 *	printf ("Loop counter is greater than 55\n");
215 			 */
216 			_gss_acquire_cred(argc, argv);
217 			_gss_init_sec_context(argc, argv);
218 			_gss_accept_sec_context(0, argv);
219 			_gss_init_sec_context(argc, argv);
220 
221 			seal_argc = 2;
222 			_gss_seal(seal_argc, seal_ini_array);
223 			seal_argc = 1;
224 			_gss_unseal(seal_argc, unseal_acc_array);
225 			seal_argc = 2;
226 			_gss_seal(seal_argc, seal_acc_array);
227 			seal_argc = 1;
228 			_gss_unseal(seal_argc, unseal_ini_array);
229 			seal_argc = 2;
230 			_gss_sign(seal_argc, seal_ini_array);
231 			seal_argc = 1;
232 			_gss_verify(seal_argc, unseal_acc_array);
233 			seal_argc = 2;
234 			_gss_sign(seal_argc, seal_acc_array);
235 			seal_argc = 1;
236 			_gss_verify(seal_argc, unseal_ini_array);
237 			_gss_delete_sec_context(argc, delet_acc_array);
238 			_gss_delete_sec_context(argc, delet_ini_array);
239 		}
240 	}
241 	if (strcmp(cmd, "gss_all") == 0 ||
242 	    strcmp(cmd, "all") == 0) {
243 		_gss_acquire_cred(argc, argv);
244 		_gss_init_sec_context(argc, argv);
245 		_gss_accept_sec_context(0, argv);
246 		_gss_init_sec_context(argc, argv);
247 
248 		seal_argc = 2;
249 		_gss_seal(seal_argc, seal_acc_array);
250 		seal_argc = 1;
251 		_gss_unseal(seal_argc, unseal_ini_array);
252 		seal_argc = 2;
253 		_gss_seal(seal_argc, seal_ini_array);
254 		seal_argc = 1;
255 		_gss_unseal(seal_argc, unseal_acc_array);
256 		seal_argc = 2;
257 		_gss_sign(seal_argc, seal_ini_array);
258 		seal_argc = 1;
259 		_gss_verify(seal_argc, unseal_acc_array);
260 		seal_argc = 2;
261 		_gss_sign(seal_argc, seal_acc_array);
262 		seal_argc = 1;
263 		_gss_verify(seal_argc, unseal_ini_array);
264 
265 	}
266 	if (strcmp(cmd, "gss_acquire_cred") == 0 ||
267 	    strcmp(cmd, "acquire") == 0) {
268 		_gss_acquire_cred(argc, argv);
269 		if (argc == 1)
270 			_gss_add_cred(argc, argv);
271 	}
272 
273 	else if (strcmp(cmd, "gss_release_cred") == 0 ||
274 		strcmp(cmd, "release") == 0)
275 		_gss_release_cred(argc, argv);
276 	else if (strcmp(cmd, "gss_init_sec_context") == 0 ||
277 		strcmp(cmd, "init") == 0)
278 		_gss_init_sec_context(argc, argv);
279 	else if (strcmp(cmd, "gss_accept_sec_context") == 0 ||
280 		strcmp(cmd, "accept") == 0)
281 		_gss_accept_sec_context(argc, argv);
282 	else if (strcmp(cmd, "gss_process_context_token") == 0 ||
283 		strcmp(cmd, "process") == 0)
284 		_gss_process_context_token(argc, argv);
285 	else if (strcmp(cmd, "gss_delete_sec_context") == 0 ||
286 		strcmp(cmd, "delete") == 0)
287 		_gss_delete_sec_context(argc, argv);
288 	else if (strcmp(cmd, "gss_context_time") == 0 ||
289 		strcmp(cmd, "time") == 0)
290 		_gss_context_time(argc, argv);
291 	else if (strcmp(cmd, "gss_sign") == 0 ||
292 		strcmp(cmd, "sign") == 0)
293 		_gss_sign(argc, argv);
294 	else if (strcmp(cmd, "gss_verify") == 0 ||
295 		strcmp(cmd, "verify") == 0)
296 		_gss_verify(argc, argv);
297 	else if (strcmp(cmd, "gss_seal") == 0 ||
298 		strcmp(cmd, "seal") == 0)
299 		_gss_seal(argc, argv);
300 	else if (strcmp(cmd, "gss_unseal") == 0 ||
301 		strcmp(cmd, "unseal") == 0)
302 		_gss_unseal(argc, argv);
303 	else if (strcmp(cmd, "gss_display_status") == 0||
304 		strcmp(cmd, "status") == 0)
305 		_gss_display_status(argc, argv);
306 	else if (strcmp(cmd, "gss_indicate_mechs") == 0 ||
307 		strcmp(cmd, "indicate") == 0)
308 		_gss_indicate_mechs(argc, argv);
309 	else if (strcmp(cmd, "gss_inquire_cred") == 0 ||
310 		strcmp(cmd, "inquire") == 0)
311 		_gss_inquire_cred(argc, argv);
312 	else if (strcmp(cmd, "expname2unixcred") == 0 ||
313 		strcmp(cmd, "gsscred_expname_to_unix_cred") == 0)
314 		_gssd_expname_to_unix_cred(argc, argv);
315 	else if (strcmp(cmd, "name2unixcred") == 0 ||
316 		strcmp(cmd, "gsscred_name_to_unix_cred") == 0)
317 		_gssd_name_to_unix_cred(argc, argv);
318 	else if (strcmp(cmd, "grpinfo") == 0 ||
319 		strcmp(cmd, "gss_get_group_info") == 0)
320 		_gssd_get_group_info(argc, argv);
321 	else if (strcmp(cmd, "exit") == 0) {
322 		printf(gettext("\n"));
323 		FREE(argv_array, (argc+2) * sizeof (char *));
324 		return (1);
325 	} else
326 		usage();
327 
328 	/* free argv array */
329 
330 	FREE(argv_array, (argc+2) * sizeof (char *));
331 	return (0);
332 }
333 
334 static void
335 _gss_acquire_cred(argc, argv)
336 int argc;
337 char **argv;
338 {
339 
340 	OM_UINT32 status, minor_status;
341 	gss_buffer_desc name;
342 	gss_name_t desired_name = (gss_name_t) 0;
343 	OM_uint32 time_req;
344 	gss_OID_set_desc desired_mechs_desc;
345 	gss_OID_set desired_mechs = &desired_mechs_desc;
346 	int cred_usage;
347 	gss_OID_set actual_mechs = GSS_C_NULL_OID_SET;
348 	gss_OID_set inquire_mechs = GSS_C_NULL_OID_SET;
349 	OM_UINT32 time_rec;
350 	char * string;
351 	char * inq_string;
352 	uid_t uid;
353 	gss_OID mech_type;
354 
355 	/*
356 	 * First set up the command line independent input arguments.
357 	 */
358 
359 	time_req = (OM_uint32) 0;
360 	cred_usage = GSS_C_ACCEPT;
361 	uid = getuid();
362 
363 	/* Parse the command line for the variable input arguments */
364 
365 	if (argc == 0) {
366 		usage();
367 		return;
368 	}
369 
370 	/*
371 	 * Get the name of the principal.
372 	 */
373 
374 	name.length = strlen(argv[0])+1;
375 	name.value = argv[0];
376 
377 	/*
378 	 * Now convert the string given by the first argument into internal
379 	 * form suitable for input to gss_acquire_cred()
380 	 */
381 
382 	if ((status = gss_import_name(&minor_status, &name,
383 		(gss_OID)GSS_C_NT_HOSTBASED_SERVICE, &desired_name))
384 		!= GSS_S_COMPLETE) {
385 		printf(gettext(
386 			"could not parse desired name: err (octal) %o (%s)\n"),
387 			status, gettext("gss_acquire_cred error"));
388 		return;
389 	}
390 
391 	argc--;
392 	argv++;
393 
394 	/*
395 	 * The next argument is an OID in dotted decimal form.
396 	 */
397 
398 	if (argc == 0) {
399 		printf(gettext("Assuming Kerberos V5 as the mechanism\n"));
400 		printf(gettext(
401 			"The mech OID 1.2.840.113554.1.2.2 will be used\n"));
402 		mech_type = gss_str2oid((char *)GSS_KRB5_MECH_OID);
403 	} else
404 		mech_type = gss_str2oid(argv[0]);
405 
406 	if (mech_type == 0 || mech_type->length == 0) {
407 		printf(gettext("improperly formated mechanism OID\n"));
408 		return;
409 	}
410 
411 	/*
412 	 * set up desired_mechs so it points to mech_type.
413 	 */
414 
415 	desired_mechs = (gss_OID_set) MALLOC(sizeof (gss_OID_desc));
416 
417 	desired_mechs->count = 1;
418 	desired_mechs->elements = mech_type;
419 
420 	status = kgss_acquire_cred(
421 				&minor_status,
422 				desired_name,
423 				time_req,
424 				desired_mechs,
425 				cred_usage,
426 				&acceptor_credentials,
427 				&actual_mechs,
428 				&time_rec,
429 				uid);
430 
431 	/* store major and minor status for gss_display_status() call */
432 
433 	gss_major_code = status;
434 	gss_minor_code = minor_status;
435 
436 	if (status == GSS_S_COMPLETE) {
437 		/* process returned values */
438 
439 		printf(gettext("\nacquire succeeded\n\n"));
440 
441 		/*
442 		 * print out the actual mechs returned  NB: Since only one
443 		 * mechanism is specified in desired_mechs, only one
444 		 * can be returned in actual_mechs. Consequently,
445 		 * actual_mechs->elements points to an array of only one
446 		 * element.
447 		 */
448 
449 		if ((string = gss_oid2str(actual_mechs->elements)) == 0) {
450 			printf(gettext("actual mechs == NULL\n\n"));
451 		} else {
452 			printf(gettext("actual mechs  = %s\n\n"), string);
453 			FREE(string, (actual_mechs->elements->length+1)*4+1);
454 		}
455 
456 		if (cred_usage == GSS_C_BOTH)
457 			printf(gettext("GSS_C_BOTH\n\n"));
458 
459 		if (cred_usage == GSS_C_INITIATE)
460 			printf(gettext("GSS_C_INITIATE\n\n"));
461 
462 		if (cred_usage == GSS_C_ACCEPT)
463 			printf(gettext("GSS_C_ACCEPT\n\n"));
464 		status = kgss_inquire_cred(
465 				&minor_status,
466 				acceptor_credentials,
467 				NULL,
468 				&time_req,
469 				&cred_usage,
470 				&inquire_mechs,
471 				uid);
472 
473 		if (status != GSS_S_COMPLETE)
474 			printf(gettext("server ret err (octal) %o (%s)\n"),
475 			status, gettext("gss_inquire_cred error"));
476 		else {
477 			if ((inq_string =
478 				gss_oid2str(inquire_mechs->elements)) == 0) {
479 				printf(gettext
480 					("mechs from inquire == NULL\n\n"));
481 			} else {
482 				printf(gettext
483 					("mechs from inquiry  = %s\n\n"),
484 					inq_string);
485 				FREE(inq_string,
486 				(inquire_mechs->elements->length+1)*4+1);
487 			}
488 			printf(gettext("inquire_cred successful \n\n"));
489 		}
490 
491 	} else {
492 		printf(gettext("server ret err (octal) %o (%s)\n"),
493 			status, gettext("gss_acquire_cred error"));
494 	}
495 
496 	/* free allocated memory */
497 
498 	/* actual mechs is allocated by clnt_stubs. Release it here */
499 	if (actual_mechs != GSS_C_NULL_OID_SET)
500 		gss_release_oid_set_and_oids(&minor_status, &actual_mechs);
501 	if (inquire_mechs != GSS_C_NULL_OID_SET)
502 		gss_release_oid_set_and_oids(&minor_status, &inquire_mechs);
503 
504 	gss_release_name(&minor_status, &desired_name);
505 
506 	/* mech_type and desired_mechs are allocated above. Release it here */
507 
508 	FREE(mech_type->elements, mech_type->length);
509 	FREE(mech_type, sizeof (gss_OID_desc));
510 	FREE(desired_mechs, sizeof (gss_OID_desc));
511 }
512 
513 static void
514 _gss_add_cred(argc, argv)
515 int argc;
516 char **argv;
517 {
518 
519 	OM_UINT32 status, minor_status;
520 	gss_buffer_desc name;
521 	gss_name_t desired_name = (gss_name_t) 0;
522 	OM_uint32 time_req;
523 	OM_uint32 initiator_time_req;
524 	OM_uint32 acceptor_time_req;
525 	int cred_usage;
526 	gss_OID_set actual_mechs = GSS_C_NULL_OID_SET;
527 	gss_OID_set inquire_mechs = GSS_C_NULL_OID_SET;
528 	char * string;
529 	uid_t uid;
530 	gss_OID mech_type;
531 	int i;
532 
533 	/*
534 	 * First set up the command line independent input arguments.
535 	 */
536 
537 	initiator_time_req = (OM_uint32) 0;
538 	acceptor_time_req = (OM_uint32) 0;
539 	cred_usage = GSS_C_ACCEPT;
540 	uid = getuid();
541 
542 	/* Parse the command line for the variable input arguments */
543 
544 	if (argc == 0) {
545 		usage();
546 		return;
547 	}
548 
549 	/*
550 	 * Get the name of the principal.
551 	 */
552 
553 	name.length = strlen(argv[0])+1;
554 	name.value = argv[0];
555 
556 	/*
557 	 * Now convert the string given by the first argument into internal
558 	 * form suitable for input to gss_acquire_cred()
559 	 */
560 
561 	if ((status = gss_import_name(&minor_status, &name,
562 		(gss_OID)GSS_C_NT_HOSTBASED_SERVICE, &desired_name))
563 		!= GSS_S_COMPLETE) {
564 		printf(gettext(
565 			"could not parse desired name: err (octal) %o (%s)\n"),
566 			status, gettext("gss_acquire_cred error"));
567 		return;
568 	}
569 
570 	argc--;
571 	argv++;
572 
573 	/*
574 	 * The next argument is an OID in dotted decimal form.
575 	 */
576 
577 	if (argc == 0) {
578 		printf(gettext("Assuming dummy  as the mechanism\n"));
579 		printf(gettext(
580 			"The mech OID 1.3.6.1.4.1.42.2.26.1.2 will be used\n"));
581 		mech_type = gss_str2oid((char *)GSS_DUMMY_MECH_OID);
582 	} else
583 		mech_type = gss_str2oid(argv[0]);
584 
585 	if (mech_type == 0 || mech_type->length == 0) {
586 		printf(gettext("improperly formated mechanism OID\n"));
587 		return;
588 	}
589 
590 	/*
591 	 * set up desired_mechs so it points to mech_type.
592 	 */
593 
594 	status = kgss_add_cred(
595 				&minor_status,
596 				acceptor_credentials,
597 				desired_name,
598 				mech_type,
599 				cred_usage,
600 				initiator_time_req,
601 				acceptor_time_req,
602 				&actual_mechs,
603 				NULL,
604 				NULL,
605 				uid);
606 
607 	/* store major and minor status for gss_display_status() call */
608 
609 	gss_major_code = status;
610 	gss_minor_code = minor_status;
611 	if (status == GSS_S_COMPLETE) {
612 		/* process returned values */
613 
614 		printf(gettext("\nadd  succeeded\n\n"));
615 		if (actual_mechs) {
616 			for (i = 0; i < actual_mechs->count; i++) {
617 				if ((string =
618 					gss_oid2str
619 					(&actual_mechs->elements[i])) == 0) {
620 					printf(gettext
621 					("actual mechs == NULL\n\n"));
622 				} else {
623 					printf(gettext
624 					("actual mechs  = %s\n\n"), string);
625 					FREE(string,
626 					(actual_mechs->elements->length+1)*4+1);
627 				}
628 			}
629 		}
630 		/*
631 		 * Try adding the cred again for the same mech
632 		 * We should get GSS_S_DUPLICATE_ELEMENT
633 		 * if not return an error
634 		 */
635 		status = kgss_add_cred(
636 				&minor_status,
637 				acceptor_credentials,
638 				desired_name,
639 				mech_type,
640 				cred_usage,
641 				initiator_time_req,
642 				acceptor_time_req,
643 				NULL, /*  &actual_mechs, */
644 				NULL,
645 				NULL,
646 				uid);
647 		if (status != GSS_S_DUPLICATE_ELEMENT) {
648 			printf(gettext("Expected duplicate element, Got "
649 			" (octal) %o (%s)\n"),
650 			status, gettext("gss_add_cred error"));
651 		}
652 		status = kgss_inquire_cred(
653 				&minor_status,
654 				acceptor_credentials,
655 				NULL,
656 				&time_req,
657 				&cred_usage,
658 				&inquire_mechs,
659 				uid);
660 
661 		if (status != GSS_S_COMPLETE)
662 			printf(gettext("server ret err (octal) %o (%s)\n"),
663 			status, gettext("gss_inquire_cred error"));
664 		else {
665 			for (i = 0; i < inquire_mechs->count; i++) {
666 				if ((string =
667 					gss_oid2str
668 					(&inquire_mechs->elements[i])) == 0) {
669 					printf(gettext
670 					("inquire_mechs mechs == NULL\n\n"));
671 				} else {
672 					printf(gettext
673 					("inquire_cred mechs  = %s\n\n"),
674 						string);
675 					FREE(string,
676 					(inquire_mechs->elements->length+1)*4
677 					+1);
678 				}
679 			}
680 			printf(gettext("inquire_cred successful \n\n"));
681 		}
682 
683 	} else {
684 		printf(gettext("server ret err (octal) %o (%s)\n"),
685 			status, gettext("gss_acquire_cred error"));
686 	}
687 
688 	/* Let us do inquire_cred_by_mech for both mechanisms */
689 	status = kgss_inquire_cred_by_mech(
690 			&minor_status,
691 			acceptor_credentials,
692 			mech_type,
693 			uid);
694 	if (status != GSS_S_COMPLETE)
695 		printf(gettext("server ret err (octal) %o (%s)\n"),
696 		status, gettext("gss_inquire_cred_by_mech"));
697 	else
698 		printf(gettext("gss_inquire_cred_by_mech successful"));
699 
700 
701 	FREE(mech_type->elements, mech_type->length);
702 	FREE(mech_type, sizeof (gss_OID_desc));
703 	mech_type = gss_str2oid((char *)GSS_KRB5_MECH_OID);
704 	status = kgss_inquire_cred_by_mech(
705 			&minor_status,
706 			acceptor_credentials,
707 			mech_type,
708 			uid);
709 	if (status != GSS_S_COMPLETE)
710 		printf(gettext("server ret err (octal) %o (%s)\n"),
711 			status, gettext
712 			("gss_inquire_cred_by_mech for dummy mech error"));
713 
714 	/* free allocated memory */
715 
716 	/* actual mechs is allocated by clnt_stubs. Release it here */
717 	if (actual_mechs != GSS_C_NULL_OID_SET)
718 		gss_release_oid_set_and_oids(&minor_status, &actual_mechs);
719 	if (inquire_mechs != GSS_C_NULL_OID_SET)
720 		gss_release_oid_set_and_oids(&minor_status, &inquire_mechs);
721 
722 	gss_release_name(&minor_status, &desired_name);
723 
724 	/* mech_type and desired_mechs are allocated above. Release it here */
725 
726 	FREE(mech_type->elements, mech_type->length);
727 	FREE(mech_type, sizeof (gss_OID_desc));
728 }
729 
730 /*ARGSUSED*/
731 static void
732 _gss_release_cred(argc, argv)
733 int argc;
734 char **argv;
735 {
736 	OM_UINT32 status;
737 	OM_UINT32 minor_status;
738 	uid_t uid;
739 
740 	/* set up input arguments here */
741 
742 	if (argc != 0) {
743 		usage();
744 		return;
745 	}
746 
747 	uid = getuid();
748 
749 	status = kgss_release_cred(
750 				&minor_status,
751 				&acceptor_credentials,
752 				uid);
753 
754 	/* store major and minor status for gss_display_status() call */
755 
756 	gss_major_code = status;
757 	gss_minor_code = minor_status;
758 
759 	if (status == GSS_S_COMPLETE) {
760 		printf(gettext("\nrelease succeeded\n\n"));
761 	} else {
762 		printf(gettext("server ret err (octal) %o (%s)\n"),
763 			status, gettext("gss_release_cred error"));
764 	}
765 }
766 
767 static void
768 _gss_init_sec_context(argc, argv)
769 int argc;
770 char **argv;
771 {
772 
773 	OM_uint32 status;
774 
775 	OM_uint32 minor_status;
776 	gss_cred_id_t claimant_cred_handle;
777 	gss_name_t target_name = (gss_name_t) 0;
778 	gss_OID mech_type = (gss_OID) 0;
779 	int req_flags;
780 	OM_uint32 time_req;
781 	gss_channel_bindings_t input_chan_bindings;
782 	gss_buffer_t input_token;
783 	gss_buffer_desc context_token;
784 	gss_OID actual_mech_type;
785 	int ret_flags;
786 	OM_uint32 time_rec;
787 	uid_t uid;
788 	char * string;
789 	gss_buffer_desc name;
790 
791 	/*
792 	 * If this is the first phase of the context establishment,
793 	 * clear initiator_context_handle and indicate next phase.
794 	 */
795 
796 	if (init_sec_context_phase == 0) {
797 		initiator_context_handle = GSS_C_NO_CONTEXT;
798 		input_token = GSS_C_NO_BUFFER;
799 		init_sec_context_phase = 1;
800 	} else
801 		input_token = &init_token_buffer;
802 
803 	/*
804 	 * First set up the non-variable command line independent input
805 	 * arguments
806 	 */
807 
808 	claimant_cred_handle = GSS_C_NO_CREDENTIAL;
809 
810 	req_flags = GSS_C_MUTUAL_FLAG;
811 	time_req = (OM_uint32) 0;
812 	input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
813 	uid = getuid();
814 
815 	/* Now parse the command line for the remaining input arguments */
816 
817 	if (argc == 0) {
818 		usage();
819 		return;
820 	}
821 
822 	/*
823 	 * Get the name of the target.
824 	 */
825 
826 	name.length = strlen(argv[0])+1;
827 	name.value = argv[0];
828 
829 	/*
830 	 * Now convert the string given by the first argument into a target
831 	 * name suitable for input to gss_init_sec_context()
832 	 */
833 
834 	if ((status = gss_import_name(&minor_status, &name,
835 		/* GSS_C_NULL_OID, &target_name)) */
836 		(gss_OID)GSS_C_NT_HOSTBASED_SERVICE, &target_name))
837 		!= GSS_S_COMPLETE) {
838 		printf(gettext(
839 			"could not parse target name: err (octal) %o (%s)\n"),
840 			status,
841 			gettext("gss_init_sec_context error"));
842 		if (input_token != GSS_C_NO_BUFFER)
843 			gss_release_buffer(&minor_status, &init_token_buffer);
844 		init_sec_context_phase = 0;
845 		return;
846 	}
847 
848 	argc--;
849 	argv++;
850 
851 	if (argc == 0) {
852 		printf(gettext("Assuming Kerberos V5 as the mechanism\n"));
853 		printf(gettext(
854 			"The mech OID 1.2.840.113554.1.2.2 will be used\n"));
855 		mech_type = gss_str2oid((char *)GSS_KRB5_MECH_OID);
856 	} else {
857 		mech_type = gss_str2oid(argv[0]);
858 	}
859 
860 	if (mech_type == 0 || mech_type->length == 0) {
861 		printf(gettext("improperly formated mechanism OID\n"));
862 		if (input_token != GSS_C_NO_BUFFER)
863 			gss_release_buffer(&minor_status, &init_token_buffer);
864 		init_sec_context_phase = 0;
865 		return;
866 	}
867 
868 	/* call kgss_init_sec_context */
869 
870 	status = kgss_init_sec_context(&minor_status,
871 				claimant_cred_handle,
872 				&initiator_context_handle,
873 				target_name,
874 				mech_type,
875 				req_flags,
876 				time_req,
877 				input_chan_bindings,
878 				input_token,
879 				&actual_mech_type,
880 				&accept_token_buffer,
881 				&ret_flags,
882 				&time_rec,
883 				uid);
884 
885 	/* store major and minor status for gss_display_status() call */
886 	gss_major_code = status;
887 	gss_minor_code = minor_status;
888 
889 	if (status != GSS_S_COMPLETE &&
890 	    status != GSS_S_CONTINUE_NEEDED) {
891 
892 		printf(gettext("server ret err (octal) %o (%s)\n"),
893 			status, "gss_init_sec_context error");
894 		init_sec_context_phase = 0;
895 		if (status == GSS_S_NO_CRED)
896 			printf(gettext(" : no credentials"));
897 		if (input_token != GSS_C_NO_BUFFER)
898 			gss_release_buffer(&minor_status, &init_token_buffer);
899 		if (status != GSS_S_FAILURE && minor_status != 0xffffffff)
900 			status = kgss_delete_sec_context(&minor_status,
901 					&initiator_context_handle,
902 					&msg_token);
903 		return;
904 
905 	} else if (status == GSS_S_COMPLETE) {
906 
907 		/* process returned values */
908 
909 		printf(gettext("\ninit succeeded\n\n"));
910 
911 		/* print out the actual mechanism type */
912 
913 		if ((string = gss_oid2str(actual_mech_type)) == 0) {
914 
915 			printf(gettext(
916 				"gssapi internal err : actual "
917 				"mech type null\n"));
918 			init_sec_context_phase = 0;
919 			if (input_token != GSS_C_NO_BUFFER)
920 				gss_release_buffer(&minor_status,
921 						&init_token_buffer);
922 			gss_release_buffer(&minor_status, &accept_token_buffer);
923 			status = kgss_delete_sec_context(&minor_status,
924 					&initiator_context_handle,
925 					&msg_token);
926 			return;
927 		} else {
928 			printf(gettext("actual mech type = %s\n\n"), string);
929 			FREE(string, (actual_mech_type->length+1)*4+1);
930 		}
931 
932 		/* print out value of ret_flags and time_req */
933 
934 		if (ret_flags & GSS_C_DELEG_FLAG)
935 			printf(gettext("GSS_C_DELEG_FLAG = True\n"));
936 		else
937 			printf(gettext("GSS_C_DELEG_FLAG = False\n"));
938 
939 		if (ret_flags & GSS_C_MUTUAL_FLAG)
940 			printf(gettext("GSS_C_MUTUAL_FLAG = True\n"));
941 		else
942 			printf(gettext("GSS_C_MUTUAL_FLAG = False\n"));
943 
944 		if (ret_flags & GSS_C_REPLAY_FLAG)
945 			printf(gettext("GSS_C_REPLAY_FLAG = True\n"));
946 		else
947 			printf(gettext("GSS_C_REPLAY_FLAG = False\n"));
948 
949 		if (ret_flags & GSS_C_SEQUENCE_FLAG)
950 			printf(gettext("GSS_C_SEQUENCE_FLAG = True\n"));
951 		else
952 			printf(gettext("GSS_C_SEQUENCE_FLAG = False\n"));
953 
954 		if (ret_flags & GSS_C_CONF_FLAG)
955 			printf(gettext("GSS_C_CONF_FLAG = True\n"));
956 		else
957 			printf(gettext("GSS_C_CONF_FLAG = False\n"));
958 
959 		if (ret_flags & GSS_C_INTEG_FLAG)
960 			printf(gettext("GSS_C_INTEG_FLAG = True\n\n"));
961 		else
962 			printf(gettext("GSS_C_INTEG_FLAG = False\n\n"));
963 
964 		printf(gettext("time_req = %u seconds\n\n"), time_rec);
965 
966 		/* free allocated memory */
967 
968 		FREE(mech_type->elements, mech_type->length);
969 		FREE(mech_type, sizeof (gss_OID_desc));
970 
971 		/* these two were malloc'd by kgss_init_sec_context() */
972 
973 		FREE(actual_mech_type->elements, actual_mech_type->length);
974 		FREE(actual_mech_type, sizeof (gss_OID_desc));
975 
976 		gss_release_name(&minor_status, &target_name);
977 
978 		if (input_token != GSS_C_NO_BUFFER)
979 			gss_release_buffer(&minor_status, &init_token_buffer);
980 
981 		/*
982 		 * if status == GSS_S_COMPLETE, reset the phase to 0 and
983 		 * release token in accept_token_buffer
984 		 */
985 
986 		init_sec_context_phase = 0;
987 	/* Save and restore the context */
988 	status = kgss_export_sec_context(&minor_status,
989 					&initiator_context_handle,
990 					&context_token);
991 	if (status != GSS_S_COMPLETE) {
992 		printf(gettext("server ret err (octal) %o (%s)\n"),
993 			status, gettext("gss_export_sec_context_error"));
994 		return;
995 	}
996 	status = kgss_import_sec_context(&minor_status,
997 					&context_token,
998 					&initiator_context_handle);
999 	if (status != GSS_S_COMPLETE) {
1000 		printf(gettext("server ret err (octal) %o (%s)\n"),
1001 			status, gettext("gss_import_sec_context_error"));
1002 		return;
1003 	}
1004 	(void) gss_release_buffer(&minor_status, &context_token);
1005 
1006 	/* gss_export & gss_import secxc_context worked, return */
1007 	printf(gettext("\nexport and import of contexts succeeded\n"));
1008 	printf(gettext("\ninit completed"));
1009 
1010 	} else {
1011 		printf(gettext("\nfirst phase of init succeeded"));
1012 		printf(gettext("\ninit must be called again\n\n"));
1013 	}
1014 
1015 }
1016 
1017 /*ARGSUSED*/
1018 static void
1019 _gss_accept_sec_context(argc, argv)
1020 int argc;
1021 char **argv;
1022 {
1023 	OM_UINT32 status;
1024 
1025 	OM_uint32 minor_status;
1026 	gss_channel_bindings_t input_chan_bindings;
1027 	gss_OID mech_type;
1028 	int ret_flags;
1029 	OM_uint32 time_rec;
1030 	gss_cred_id_t delegated_cred_handle;
1031 	uid_t uid;
1032 	char *string;
1033 	gss_buffer_desc src_name, src_name_string;
1034 	gss_buffer_desc output_token;
1035 	gss_name_t gss_name;
1036 	gss_buffer_desc context_token;
1037 
1038 	/*
1039 	 * If this is the first phase of the context establishment,
1040 	 * clear acceptor_context_handle and indicate next phase.
1041 	 */
1042 
1043 	if (accept_sec_context_phase == 0) {
1044 		acceptor_context_handle = GSS_C_NO_CONTEXT;
1045 		accept_sec_context_phase = 1;
1046 	}
1047 
1048 	/* Now set up the other command line independent input arguments */
1049 
1050 	input_chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
1051 
1052 	uid = (uid_t) getuid();
1053 
1054 	if (argc != 0) {
1055 		usage();
1056 		return;
1057 	}
1058 
1059 	status = kgss_accept_sec_context(&minor_status,
1060 					&acceptor_context_handle,
1061 					acceptor_credentials,
1062 					&accept_token_buffer,
1063 					input_chan_bindings,
1064 					&src_name,
1065 					&mech_type,
1066 					&init_token_buffer,
1067 					&ret_flags,
1068 					&time_rec,
1069 					&delegated_cred_handle,
1070 					uid);
1071 
1072 	/* store major and minor status for gss_display_status() call */
1073 
1074 	gss_major_code = status;
1075 	gss_minor_code = minor_status;
1076 
1077 	if (status != GSS_S_COMPLETE && status != GSS_S_CONTINUE_NEEDED) {
1078 		printf(gettext("server ret err (octal) %o (%s)\n"),
1079 			status, gettext("gss_accept_sec_context error"));
1080 		gss_release_buffer(&minor_status, &accept_token_buffer);
1081 		return;
1082 	} else if (status == GSS_S_COMPLETE) {
1083 
1084 		/* process returned values */
1085 
1086 		printf(gettext("\naccept succeeded\n\n"));
1087 
1088 		/*
1089 		 * convert the exported name returned in src_name into
1090 		 * a string and print it.
1091 		 */
1092 		if ((status = gss_import_name(&minor_status, &src_name,
1093 			(gss_OID) GSS_C_NT_EXPORT_NAME, &gss_name))
1094 			!= GSS_S_COMPLETE) {
1095 			printf(gettext(
1096 				"could not import src name 0x%x\n"), status);
1097 			accept_sec_context_phase = 0;
1098 			status = kgss_delete_sec_context(&minor_status,
1099 					&acceptor_context_handle,
1100 					&output_token);
1101 			gss_release_buffer(&minor_status, &accept_token_buffer);
1102 			if (status == GSS_S_CONTINUE_NEEDED)
1103 				gss_release_buffer(&minor_status,
1104 						&init_token_buffer);
1105 			gss_release_buffer(&minor_status, &src_name);
1106 			return;
1107 		}
1108 
1109 		memset(&src_name_string, 0, sizeof (src_name_string));
1110 		if ((status = gss_display_name(&minor_status, gss_name,
1111 			&src_name_string, NULL)) != GSS_S_COMPLETE) {
1112 			printf(gettext("could not display src name: "
1113 				"err (octal) %o (%s)\n"), status,
1114 				"gss_init_sec_context error");
1115 			accept_sec_context_phase = 0;
1116 			status = kgss_delete_sec_context(&minor_status,
1117 					&acceptor_context_handle,
1118 					&output_token);
1119 			gss_release_buffer(&minor_status, &accept_token_buffer);
1120 			if (status == GSS_S_CONTINUE_NEEDED)
1121 				gss_release_buffer(&minor_status,
1122 						&init_token_buffer);
1123 			gss_release_buffer(&minor_status, &src_name);
1124 			return;
1125 		}
1126 		printf(gettext("src name = %s\n"), src_name_string.value);
1127 		gss_release_name(&minor_status, &gss_name);
1128 		gss_release_buffer(&minor_status, &src_name_string);
1129 		gss_release_buffer(&minor_status, &src_name);
1130 
1131 		/* print out the mechanism type */
1132 
1133 		if ((string = gss_oid2str(mech_type)) == 0) {
1134 
1135 			printf(gettext(
1136 				"gssapi internal err :"
1137 				" actual mech type null\n"));
1138 			accept_sec_context_phase = 0;
1139 			status = kgss_delete_sec_context(&minor_status,
1140 					&acceptor_context_handle,
1141 					&output_token);
1142 			gss_release_buffer(&minor_status, &accept_token_buffer);
1143 			if (status == GSS_S_CONTINUE_NEEDED)
1144 				gss_release_buffer(&minor_status,
1145 						&init_token_buffer);
1146 			return;
1147 		} else {
1148 
1149 			printf(gettext("actual mech type = %s\n\n"), string);
1150 			FREE(string, (mech_type->length+1)*4+1);
1151 		}
1152 
1153 	/* Save and restore the context */
1154 	status = kgss_export_sec_context(&minor_status,
1155 					&initiator_context_handle,
1156 					&context_token);
1157 	if (status != GSS_S_COMPLETE) {
1158 		printf(gettext("server ret err (octal) %o (%s)\n"),
1159 			status, gettext("gss_export_sec_context_error"));
1160 		return;
1161 	}
1162 	status = kgss_import_sec_context(&minor_status,
1163 					&context_token,
1164 					&initiator_context_handle);
1165 	if (status != GSS_S_COMPLETE) {
1166 		printf(gettext("server ret err (octal) %o (%s)\n"),
1167 			status, gettext("gss_import_sec_context_error"));
1168 		return;
1169 	}
1170 	(void) gss_release_buffer(&minor_status, &context_token);
1171 
1172 	/* gss_export & gss_import secxc_context worked, return */
1173 
1174 	/* print out value of ret_flags and time_req */
1175 
1176 		if (ret_flags & GSS_C_DELEG_FLAG)
1177 			printf(gettext("GSS_C_DELEG_FLAG = True\n"));
1178 		else
1179 			printf(gettext("GSS_C_DELEG_FLAG = False\n"));
1180 
1181 		if (ret_flags & GSS_C_MUTUAL_FLAG)
1182 			printf(gettext("GSS_C_MUTUAL_FLAG = True\n"));
1183 		else
1184 			printf(gettext("GSS_C_MUTUAL_FLAG = False\n"));
1185 
1186 		if (ret_flags & GSS_C_REPLAY_FLAG)
1187 			printf(gettext("GSS_C_REPLAY_FLAG = True\n"));
1188 		else
1189 			printf(gettext("GSS_C_REPLAY_FLAG = False\n"));
1190 
1191 		if (ret_flags & GSS_C_SEQUENCE_FLAG)
1192 			printf(gettext("GSS_C_SEQUENCE_FLAG = True\n"));
1193 		else
1194 			printf(gettext("GSS_C_SEQUENCE_FLAG = False\n"));
1195 
1196 		if (ret_flags & GSS_C_CONF_FLAG)
1197 			printf(gettext("GSS_C_CONF_FLAG = True\n"));
1198 		else
1199 			printf(gettext("GSS_C_CONF_FLAG = False\n"));
1200 
1201 		if (ret_flags & GSS_C_INTEG_FLAG)
1202 			printf(gettext("GSS_C_INTEG_FLAG = True\n\n"));
1203 		else
1204 			printf(gettext("GSS_C_INTEG_FLAG = False\n\n"));
1205 
1206 		printf(gettext("time_rec = %d seconds\n\n"), time_rec);
1207 
1208 		/* free allocated memory */
1209 
1210 		printf(gettext("\nexport and import of contexts succeeded\n"));
1211 
1212 		FREE(mech_type->elements, mech_type->length);
1213 		FREE(mech_type, sizeof (gss_OID_desc));
1214 	} else {
1215 		printf(gettext("\nfirst phase of accept succeeded"));
1216 		printf(gettext("\naccept must be called again\n\n"));
1217 	}
1218 
1219 
1220 	/* free the input token in accept_token_buffer */
1221 	gss_release_buffer(&minor_status, &accept_token_buffer);
1222 
1223 	/* if status == GSS_S_COMPLETE, reset the phase to 0 */
1224 
1225 	if (status == GSS_S_COMPLETE)
1226 		accept_sec_context_phase = 0;
1227 
1228 	/* gss_accept_sec_context worked, return */
1229 }
1230 
1231 void
1232 _gss_process_context_token(argc, argv)
1233 int argc;
1234 char **argv;
1235 {
1236 	OM_UINT32 status;
1237 
1238 	gss_ctx_id_t context_handle;
1239 	OM_uint32 minor_status;
1240 	uid_t uid;
1241 
1242 	uid = (uid_t) getuid();
1243 
1244 	/* parse the command line to determine the variable input argument */
1245 
1246 	if (argc == 0) {
1247 		usage();
1248 		return;
1249 	}
1250 
1251 	if (strcmp(argv[0], "initiator") == 0)
1252 		context_handle = initiator_context_handle;
1253 	else if (strcmp(argv[0], "acceptor") == 0)
1254 		context_handle = acceptor_context_handle;
1255 	else {
1256 		printf(gettext(
1257 			"must specify either \"initiator\" or \"acceptor\"\n"));
1258 		return;
1259 	}
1260 
1261 	argc--;
1262 	argv++;
1263 
1264 	if (argc != 0) {
1265 		usage();
1266 		return;
1267 	}
1268 
1269 	status = kgss_process_context_token(&minor_status,
1270 					    context_handle,
1271 					    delete_token_buffer,
1272 					    uid);
1273 
1274 	/* store major and minor status for gss_display_status() call */
1275 
1276 	gss_major_code = status;
1277 	gss_minor_code = minor_status;
1278 
1279 	if (status != GSS_S_COMPLETE) {
1280 		printf(gettext("server ret err (octal) %o (%s)\n"),
1281 			status, gettext("gss_process_context_token error"));
1282 		return;
1283 
1284 	} else {
1285 		printf(gettext("\nprocess succeeded\n\n"));
1286 		return;
1287 	}
1288 }
1289 
1290 static void
1291 _gss_delete_sec_context(argc, argv)
1292 int argc;
1293 char **argv;
1294 {
1295 	OM_UINT32 status;
1296 	gss_ctx_id_t *context_handle;
1297 	OM_uint32 minor_status;
1298 
1299 
1300 	/* parse the command line to determine the variable input argument */
1301 
1302 	if (argc == 0) {
1303 		usage();
1304 		return;
1305 	}
1306 
1307 	if (strcmp(argv[0], "initiator") == 0) {
1308 		context_handle = &initiator_context_handle;
1309 	} else if (strcmp(argv[0], "acceptor") == 0) {
1310 		context_handle = &acceptor_context_handle;
1311 	} else {
1312 		printf(gettext(
1313 			"must specify either \"initiator\" or \"acceptor\"\n"));
1314 		return;
1315 	}
1316 
1317 	argc--;
1318 	argv++;
1319 
1320 	if (argc != 0) {
1321 		usage();
1322 		return;
1323 	}
1324 
1325 
1326 	status = kgss_delete_sec_context(&minor_status,
1327 					context_handle,
1328 					&delete_token_buffer);
1329 
1330 
1331 	/* store major and minor status for gss_display_status() call */
1332 
1333 	gss_major_code = status;
1334 	gss_minor_code = minor_status;
1335 
1336 	if (status != GSS_S_COMPLETE) {
1337 
1338 		printf(gettext("server ret err (octal) %o (%s)\n"),
1339 			status, gettext("gss_delete_sec_context error"));
1340 		return;
1341 
1342 	} else {
1343 		printf(gettext("\ndelete succeeded\n\n"));
1344 		return;
1345 	}
1346 }
1347 
1348 /*ARGSUSED*/
1349 static void
1350 _gss_context_time(argc, argv)
1351 int argc;
1352 char **argv;
1353 {
1354 	/*
1355 	 * set up input arguments here
1356 	 * this function is unimplemented. Call usage() and return
1357 	 */
1358 
1359 	printf(gettext("\nunimplemented function"));
1360 }
1361 
1362 static void
1363 _gss_sign(argc, argv)
1364 int argc;
1365 char **argv;
1366 {
1367 	OM_UINT32 status;
1368 	OM_uint32 minor_status;
1369 	gss_ctx_id_t context_handle;
1370 	int qop_req;
1371 	uid_t uid;
1372 
1373 	uid = (uid_t) getuid();
1374 
1375 	/* specify the default quality of protection */
1376 
1377 	qop_req = GSS_C_QOP_DEFAULT;
1378 
1379 	/* set up the arguments specified in the input parameters */
1380 
1381 	if (argc == 0) {
1382 		usage();
1383 		return;
1384 	}
1385 
1386 
1387 	if (strcmp(argv[0], "initiator") == 0)
1388 		context_handle = initiator_context_handle;
1389 	else if (strcmp(argv[0], "acceptor") == 0)
1390 		context_handle = acceptor_context_handle;
1391 	else {
1392 		printf(gettext(
1393 			"must specify either \"initiator\" or \"acceptor\"\n"));
1394 		return;
1395 	}
1396 
1397 	argc--;
1398 	argv++;
1399 
1400 	if (argc == 0) {
1401 		usage();
1402 		return;
1403 	}
1404 
1405 	message_buffer.length = strlen(argv[0])+1;
1406 	message_buffer.value = (void *) MALLOC(message_buffer.length);
1407 	strcpy(message_buffer.value, argv[0]);
1408 
1409 	argc--;
1410 	argv++;
1411 
1412 	if (argc != 0) {
1413 		usage();
1414 		return;
1415 	}
1416 
1417 	status = kgss_sign(&minor_status,
1418 			context_handle,
1419 			qop_req,
1420 			&message_buffer,
1421 			&msg_token,
1422 			uid);
1423 
1424 	/* store major and minor status for gss_display_status() call */
1425 
1426 	gss_major_code = status;
1427 	gss_minor_code = minor_status;
1428 
1429 	if (status != GSS_S_COMPLETE) {
1430 		printf(gettext("server ret err (octal) %o (%s)\n"),
1431 			status, gettext("gss_sign error"));
1432 		return;
1433 
1434 	} else {
1435 		printf(gettext("\nsign succeeded\n\n"));
1436 		return;
1437 	}
1438 }
1439 
1440 static void
1441 _gss_verify(argc, argv)
1442 int argc;
1443 char **argv;
1444 {
1445 	OM_UINT32 status, minor_status;
1446 	gss_ctx_id_t context_handle;
1447 	int qop_state;
1448 	uid_t uid;
1449 
1450 	uid = (uid_t) getuid();
1451 
1452 	/* set up the arguments specified in the input parameters */
1453 
1454 	if (argc == 0) {
1455 		usage();
1456 		return;
1457 	}
1458 
1459 
1460 	if (strcmp(argv[0], "initiator") == 0)
1461 		context_handle = initiator_context_handle;
1462 	else if (strcmp(argv[0], "acceptor") == 0)
1463 		context_handle = acceptor_context_handle;
1464 	else {
1465 		printf(gettext(
1466 			"must specify either \"initiator\" or \"acceptor\"\n"));
1467 		return;
1468 	}
1469 
1470 	argc--;
1471 	argv++;
1472 
1473 	if (argc != 0) {
1474 		usage();
1475 		return;
1476 	}
1477 
1478 	status = kgss_verify(&minor_status,
1479 			context_handle,
1480 			&message_buffer,
1481 			&msg_token,
1482 			&qop_state,
1483 			uid);
1484 
1485 	/* store major and minor status for gss_display_status() call */
1486 
1487 	gss_major_code = status;
1488 	gss_minor_code = minor_status;
1489 
1490 	if (status != GSS_S_COMPLETE) {
1491 		printf(gettext("server ret err (octal) %o (%s)\n"),
1492 			status, gettext("gss_verify error"));
1493 		return;
1494 	} else {
1495 
1496 		/* print out the verified message */
1497 
1498 		printf(gettext(
1499 			"verified message = \"%s\"\n\n"), message_buffer.value);
1500 
1501 		/* print out the quality of protection returned */
1502 
1503 		printf(gettext("quality of protection = %d \n\n"), qop_state);
1504 
1505 		/* free the message buffer and message token and return */
1506 
1507 		gss_release_buffer(&minor_status, &message_buffer);
1508 		gss_release_buffer(&minor_status, &msg_token);
1509 
1510 		return;
1511 	}
1512 }
1513 
1514 static void
1515 _gss_seal(argc, argv)
1516 int argc;
1517 char **argv;
1518 {
1519 	OM_UINT32 status;
1520 
1521 	OM_uint32 minor_status;
1522 	gss_ctx_id_t context_handle;
1523 	int conf_req_flag;
1524 	int qop_req;
1525 	gss_buffer_desc input_message_buffer;
1526 	int conf_state;
1527 	uid_t uid;
1528 
1529 	uid = (uid_t) getuid();
1530 
1531 	/*
1532 	 * specify the default confidentiality requested (both integrity
1533 	 * and confidentiality) and quality of protection
1534 	 */
1535 
1536 	conf_req_flag = 1;
1537 	qop_req = GSS_C_QOP_DEFAULT;
1538 
1539 	/* set up the arguments specified in the input parameters */
1540 
1541 	if (argc == 0) {
1542 		usage();
1543 		return;
1544 	}
1545 
1546 
1547 	if (strcmp(argv[0], "initiator") == 0)
1548 		context_handle = initiator_context_handle;
1549 	else if (strcmp(argv[0], "acceptor") == 0)
1550 		context_handle = acceptor_context_handle;
1551 	else {
1552 		printf(gettext(
1553 			"must specify either \"initiator\" or \"acceptor\"\n"));
1554 		return;
1555 	}
1556 
1557 	argc--;
1558 	argv++;
1559 
1560 	if (argc == 0) {
1561 		usage();
1562 		return;
1563 	}
1564 
1565 
1566 	input_message_buffer.length = strlen(argv[0])+1;
1567 	input_message_buffer.value =
1568 		(void *) MALLOC(input_message_buffer.length);
1569 	strcpy(input_message_buffer.value, argv[0]);
1570 
1571 	argc--;
1572 	argv++;
1573 
1574 	if (argc != 0) {
1575 		usage();
1576 		return;
1577 	}
1578 
1579 	status = kgss_seal(&minor_status,
1580 			context_handle,
1581 			conf_req_flag,
1582 			qop_req,
1583 			&input_message_buffer,
1584 			&conf_state,
1585 			&message_buffer,
1586 			uid);
1587 
1588 	/* store major and minor status for gss_display_status() call */
1589 
1590 	gss_major_code = status;
1591 	gss_minor_code = minor_status;
1592 
1593 	/* free the inputmessage buffer */
1594 
1595 	gss_release_buffer(&minor_status, &input_message_buffer);
1596 
1597 	if (status != GSS_S_COMPLETE) {
1598 		printf(gettext("server ret err (octal) %o (%s)\n"),
1599 			status, gettext("gss_seal error"));
1600 		return;
1601 	} else {
1602 		printf(gettext("\nseal succeeded\n\n"));
1603 		return;
1604 	}
1605 }
1606 
1607 static void
1608 _gss_unseal(argc, argv)
1609 int argc;
1610 char **argv;
1611 {
1612 	OM_UINT32 status;
1613 
1614 	OM_uint32 minor_status;
1615 	gss_ctx_id_t context_handle;
1616 	gss_buffer_desc output_message_buffer;
1617 	int conf_state;
1618 	int qop_state;
1619 	uid_t uid;
1620 
1621 	uid = (uid_t) getuid();
1622 
1623 	/* set up the arguments specified in the input parameters */
1624 
1625 	if (argc == 0) {
1626 		usage();
1627 		return;
1628 	}
1629 
1630 
1631 	if (strcmp(argv[0], "initiator") == 0)
1632 		context_handle = initiator_context_handle;
1633 	else if (strcmp(argv[0], "acceptor") == 0)
1634 		context_handle = acceptor_context_handle;
1635 	else {
1636 		printf(gettext(
1637 			"must specify either \"initiator\" or \"acceptor\"\n"));
1638 		return;
1639 	}
1640 
1641 	argc--;
1642 	argv++;
1643 
1644 	if (argc != 0) {
1645 		usage();
1646 		return;
1647 	}
1648 
1649 	status = kgss_unseal(&minor_status,
1650 			context_handle,
1651 			&message_buffer,
1652 			&output_message_buffer,
1653 			&conf_state,
1654 			&qop_state,
1655 			uid);
1656 
1657 	/* store major and minor status for gss_display_status() call */
1658 
1659 	gss_major_code = status;
1660 	gss_minor_code = minor_status;
1661 
1662 	if (status == GSS_S_COMPLETE) {
1663 		printf(gettext("\nunseal succeeded\n\n"));
1664 		printf(gettext("unsealed message = \"%s\"\n\n"),
1665 			output_message_buffer.value);
1666 		if (conf_state)
1667 			printf(gettext("confidentiality and integrity used\n"));
1668 		else
1669 			printf(gettext("only integrity used\n"));
1670 		printf(gettext("quality of protection = %d\n\n"), qop_state);
1671 		gss_release_buffer(&minor_status, &output_message_buffer);
1672 	} else {
1673 		printf(gettext("server ret err (octal) %o (%s)\n"),
1674 			status, gettext("gss_unseal error"));
1675 	}
1676 
1677 	/* free the message buffer and return */
1678 
1679 	gss_release_buffer(&minor_status, &message_buffer);
1680 }
1681 
1682 static void
1683 _gss_display_status(argc, argv)
1684 int argc;
1685 char **argv;
1686 {
1687 	OM_UINT32 status;
1688 	OM_uint32 minor_status;
1689 	int status_type;
1690 	int status_value;
1691 	gss_OID mech_type = (gss_OID) 0;
1692 	int message_context;
1693 	gss_buffer_desc status_string;
1694 	uid_t uid;
1695 
1696 	uid = (uid_t) getuid();
1697 
1698 	/* initialize message context to zero */
1699 
1700 	message_context = 0;
1701 
1702 	if (argc == 0) {
1703 		printf(gettext("Assuming Kerberos V5 as the mechanism\n"));
1704 		printf(gettext(
1705 			"The mech OID 1.2.840.113554.1.2.2 will be used\n"));
1706 		mech_type = gss_str2oid((char *)GSS_KRB5_MECH_OID);
1707 	} else
1708 		mech_type = gss_str2oid(argv[0]);
1709 
1710 	if (mech_type == 0 || mech_type->length == 0) {
1711 		printf(gettext("improperly formated mechanism OID\n"));
1712 		return;
1713 	}
1714 
1715 	/* Is this call for the major or minor status? */
1716 
1717 	if (strcmp(argv[0], "major") == 0) {
1718 		status_type = GSS_C_GSS_CODE;
1719 		status_value = gss_major_code;
1720 	} else if (strcmp(argv[0], "minor") == 0) {
1721 		status_type = GSS_C_MECH_CODE;
1722 		status_value = gss_minor_code;
1723 	} else {
1724 		printf(gettext("must specify either \"major\" or \"minor\"\n"));
1725 		return;
1726 	}
1727 
1728 	argc--;
1729 	argv++;
1730 
1731 	if (argc != 0) {
1732 		usage();
1733 		return;
1734 	}
1735 
1736 	status = kgss_display_status(&minor_status,
1737 				status_value,
1738 				status_type,
1739 				mech_type,
1740 				&message_context,
1741 				&status_string,
1742 				uid);
1743 
1744 	if (status == GSS_S_COMPLETE) {
1745 		printf(gettext("status =\n  %s\n\n"), status_string.value);
1746 	} else if (status == GSS_S_BAD_MECH) {
1747 		printf(gettext("invalide mechanism OID\n\n"));
1748 	} else {
1749 		printf(gettext("server ret err (octal) %o (%s)\n"),
1750 			status, gettext("gss_display_status error"));
1751 	}
1752 }
1753 
1754 /*ARGSUSED*/
1755 static void
1756 _gss_indicate_mechs(argc, argv)
1757 int argc;
1758 char **argv;
1759 {
1760 	OM_UINT32 status;
1761 	OM_UINT32 minor_status;
1762 	gss_OID_set oid_set = GSS_C_NULL_OID_SET;
1763 	uid_t uid;
1764 
1765 	uid = (uid_t) getuid();
1766 
1767 	/* set up input arguments here */
1768 
1769 	if (argc != 0) {
1770 		usage();
1771 		return;
1772 	}
1773 
1774 	status = kgss_indicate_mechs(&minor_status, &oid_set, uid);
1775 
1776 	if (status == GSS_S_COMPLETE) {
1777 		int i;
1778 		char *string;
1779 
1780 		printf(gettext("%d supported mechanism%s%s\n"), oid_set->count,
1781 			(oid_set->count == 1) ? "" : "s",
1782 			(oid_set->count > 0) ? ":" : "");
1783 
1784 		for (i = 0; i < oid_set->count; i++) {
1785 			string = gss_oid2str(&oid_set->elements[i]);
1786 			printf(gettext("\t%s\n"), string);
1787 			FREE(string, ((oid_set->elements[i].length+1)*4)+1);
1788 		}
1789 		printf("\n");
1790 
1791 	} else {
1792 		printf(gettext("server ret err (octal) %o (%s)\n"),
1793 			status, gettext("gss_indicate_mechs error"));
1794 	}
1795 
1796 	if (oid_set)
1797 		gss_release_oid_set_and_oids(&minor_status, &oid_set);
1798 }
1799 
1800 /*ARGSUSED*/
1801 static void
1802 _gss_inquire_cred(argc, argv)
1803 int argc;
1804 char **argv;
1805 {
1806 	/* set up input arguments here */
1807 
1808 	if (argc != 0) {
1809 		usage();
1810 		return;
1811 	}
1812 
1813 
1814 	/* this function is unimplemented. Call usage() and return */
1815 
1816 	printf(gettext("\nUnsupported function"));
1817 }
1818 
1819 static char hexChars[] = "0123456789ABCDEF";
1820 
1821 static void
1822 _gssd_expname_to_unix_cred(argc, argv)
1823 int argc;
1824 char **argv;
1825 {
1826 	OM_uint32 major;
1827 	gss_buffer_desc expName;
1828 	char krb5_root_name[] = "040100092A864886F712010202000000"
1829 		"25000A2A864886F71201020101726F6F744053554E534F46"
1830 		"542E454E472E53554E2E434F4D00";
1831 	unsigned char *byteStr, *hexStr;
1832 	uid_t uidOut, uidIn;
1833 	gid_t *gids, gidOut;
1834 	int gidsLen, i, newLen;
1835 
1836 	/* set up the arguments */
1837 	uidIn = (uid_t) getuid();
1838 
1839 	if (argc < 1) {
1840 		printf(gettext(
1841 			"Using principal name of root for krberos_v5\n"));
1842 		expName.value = (void*)krb5_root_name;
1843 		expName.length = strlen(krb5_root_name);
1844 	} else {
1845 		expName.value = (void*)argv[0];
1846 		expName.length = strlen(argv[0]);
1847 	}
1848 
1849 	/* convert the name from hex to byte... */
1850 	hexStr = (unsigned char *)expName.value;
1851 	newLen = expName.length/2;
1852 	byteStr = (unsigned char *)MALLOC(newLen+1);
1853 	expName.value = (char *)byteStr;
1854 	for (i = 0; i < expName.length; i += 2) {
1855 		*byteStr = (strchr(hexChars, *hexStr++) - hexChars) << 4;
1856 		*byteStr += (strchr(hexChars, *hexStr++) - hexChars);
1857 		byteStr++;
1858 	}
1859 	expName.length = newLen;
1860 
1861 	major = kgsscred_expname_to_unix_cred(&expName, &uidOut, &gidOut,
1862 					&gids, &gidsLen, uidIn);
1863 
1864 	FREE(expName.value, newLen);
1865 
1866 	if (major == GSS_S_COMPLETE) {
1867 		printf(gettext("uid = <%d>\tgid = <%d>\t"), uidOut, gidOut);
1868 		if (gidsLen > 0)
1869 			printf(gettext(" %d gids <"), gidsLen);
1870 		else
1871 			printf(gettext(
1872 				" no supplementary group information\n"));
1873 		for (i = 0; i < gidsLen; i++)
1874 			printf(" %d ", gids[i]);
1875 		if (gidsLen > 0) {
1876 			printf(">\n");
1877 			FREE(gids, gidsLen * sizeof (gid_t));
1878 		}
1879 	} else {
1880 		printf(gettext("server ret err (octal) %o (%s)\n"),
1881 			major, gettext("gsscred_expname_to_unix_cred"));
1882 	}
1883 }
1884 
1885 static void
1886 _gssd_name_to_unix_cred(argc, argv)
1887 int argc;
1888 char **argv;
1889 {
1890 	OM_uint32 major, minor;
1891 	gss_name_t gssName;
1892 	gss_buffer_desc gssBuf = GSS_C_EMPTY_BUFFER;
1893 	int gidsLen, i;
1894 	gid_t *gids, gidOut;
1895 	uid_t uidOut, uid;
1896 	char defaultPrincipal[] = "root";
1897 	gss_OID mechType, nameType;
1898 
1899 	uid = getuid();
1900 
1901 	/* optional argument 1 - contains principal name */
1902 	if (argc > 0) {
1903 		gssBuf.value = (void *)argv[0];
1904 		gssBuf.length = strlen((char *)argv[0]);
1905 	} else {
1906 		gssBuf.value = (void *)defaultPrincipal;
1907 		gssBuf.length = strlen(defaultPrincipal);
1908 	}
1909 	printf(gettext(
1910 		"Using <%s> as the principal name.\n"), (char *)gssBuf.value);
1911 
1912 
1913 	/* optional argument 2 - contains name oid */
1914 	if (argc > 1)
1915 		nameType = gss_str2oid((char *) argv[1]);
1916 	else
1917 		nameType = (gss_OID)GSS_C_NT_USER_NAME;
1918 
1919 	if (nameType == NULL || nameType->length == 0) {
1920 		printf(gettext("improperly formated name OID\n"));
1921 		return;
1922 	}
1923 	printf(gettext("Principal name of type: <%s>.\n"),
1924 		(argc > 1) ? argv[1] : "GSS_C_NT_USER_NAME");
1925 
1926 
1927 	/* optional argument 3 - contains mech oid */
1928 	if (argc > 2)
1929 		mechType = gss_str2oid(argv[2]);
1930 	else
1931 		mechType = gss_str2oid((char *)GSS_KRB5_MECH_OID);
1932 
1933 	if (mechType == NULL || mechType->length == 0) {
1934 		FREE(nameType->elements, nameType->length);
1935 		FREE(nameType, sizeof (gss_OID_desc));
1936 		printf(gettext("improperly formated mech OID\n"));
1937 		return;
1938 	}
1939 	printf(gettext("Mechanism oid: <%s>.\n"),
1940 		(argc > 2) ? argv[2] :
1941 		(char *)GSS_KRB5_MECH_OID "(Kerberos v5)");
1942 
1943 
1944 	/* convert the name to internal format */
1945 	if ((major = gss_import_name(&minor, &gssBuf,
1946 				nameType, &gssName)) != GSS_S_COMPLETE) {
1947 		printf(gettext("could not parse name: err (octal) %o (%s)\n"),
1948 			major, "gss_import_name");
1949 
1950 		FREE(nameType->elements, nameType->length);
1951 		FREE(nameType, sizeof (gss_OID_desc));
1952 		return;
1953 	}
1954 
1955 	major = kgsscred_name_to_unix_cred(gssName, mechType, &uidOut,
1956 					&gidOut, &gids, &gidsLen, uid);
1957 
1958 	gss_release_name(&minor, &gssName);
1959 	FREE(mechType->elements, mechType->length);
1960 	FREE(mechType, sizeof (gss_OID_desc));
1961 	if (argc > 1) {
1962 		FREE(nameType->elements, nameType->length);
1963 		FREE(nameType, sizeof (gss_OID_desc));
1964 	}
1965 
1966 	if (major == GSS_S_COMPLETE) {
1967 		printf("uid = <%d>\tgid = <%d>\t", uidOut, gidOut);
1968 		if (gidsLen > 0)
1969 			printf(gettext(" %d gids <"), gidsLen);
1970 		else
1971 			printf(gettext(
1972 				" no supplementary group information\n"));
1973 		for (i = 0; i < gidsLen; i++)
1974 			printf(" %d ", gids[i]);
1975 		if (gidsLen > 0) {
1976 			printf(">\n");
1977 			FREE(gids, gidsLen * sizeof (gid_t));
1978 		}
1979 	} else {
1980 		printf(gettext("server ret err (octal) %o (%s)\n"),
1981 			major, gettext("gsscred_name_to_unix_cred"));
1982 	}
1983 }
1984 
1985 static void
1986 _gssd_get_group_info(argc, argv)
1987 int argc;
1988 char **argv;
1989 {
1990 	OM_uint32 major;
1991 	uid_t puid, uidIn;
1992 	gid_t *gids, gidOut;
1993 	int gidsLen, i;
1994 
1995 	/* set up the arguments */
1996 	uidIn = (uid_t) getuid();
1997 
1998 	if (argc < 1)
1999 		puid = 0;
2000 	else
2001 		puid = atol(argv[0]);
2002 
2003 	printf(gettext("Retrieving group info for uid of <%d>\n"), puid);
2004 
2005 	major = kgss_get_group_info(puid, &gidOut, &gids, &gidsLen, uidIn);
2006 
2007 	if (major == GSS_S_COMPLETE) {
2008 		printf(gettext("group id = <%d>\t"), gidOut);
2009 		if (gidsLen > 0)
2010 			printf(gettext(" %d gids <"), gidsLen);
2011 		else
2012 			printf(gettext(
2013 				" no supplementary group information\n"));
2014 		for (i = 0; i < gidsLen; i++)
2015 			printf(" %d ", gids[i]);
2016 		if (gidsLen > 0) {
2017 			printf(">\n");
2018 			FREE(gids, gidsLen * sizeof (gid_t));
2019 		}
2020 	} else {
2021 		printf(gettext("server ret err (octal) %o (%s)\n"),
2022 			major, "gss_get_group_info");
2023 	}
2024 }
2025 
2026 static gss_OID
2027 gss_str2oid(string)
2028 char * string;
2029 {
2030 	/*
2031 	 * a convenient wrapper routine for gss_str_to_oid
2032 	 * this can handle all valid oid strings.
2033 	 */
2034 	OM_uint32 minor;
2035 	gss_buffer_desc abuf;
2036 	gss_OID oidOut;
2037 
2038 	abuf.value = (void*)string;
2039 	abuf.length = strlen(string);
2040 
2041 	if (gss_str_to_oid(&minor, &abuf, &oidOut) != GSS_S_COMPLETE)
2042 		return (NULL);
2043 
2044 	return (oidOut);
2045 }
2046 
2047 static char *
2048 gss_oid2str(oid)
2049 gss_OID oid;
2050 {
2051 	/*
2052 	 * a convenient wrapper for gss_oid_to_str
2053 	 * this calls the GSS-API routine which should
2054 	 * be able to handle all types of oids.
2055 	 */
2056 	OM_uint32 minor;
2057 	gss_buffer_desc oidStr;
2058 
2059 	if (gss_oid_to_str(&minor, oid, &oidStr) != GSS_S_COMPLETE)
2060 		return (NULL);
2061 
2062 	return ((char *)oidStr.value);
2063 } /* gss_oid2str */
2064 
2065 static void
2066 instructs()
2067 {
2068 	fprintf(stderr,
2069 		gettext(
2070 "\nThis program must be run as root. Root must be installed on the KDC\n"
2071 "and exist in srvtab as root/<hostname>, where <hostname> is the machine on\n"
2072 "which the test runs. Before running gssdtest for Kerberos mechanism, the\n"
2073 "operator running as root must kinit as some other principal, e.g., test.\n"
2074 "There are two mechanisms avaialble: dummy and Kerberos(default).\n"
2075 "The OID for dummy mechanism is 1.3.6.1.4.1.42.2.26.1.2.\n"
2076 "The OID for Kerberos mechanism is 1.2.840.113554.1.2.2.\n"
2077 "The order of context establishment calls is important. First, acquire must"
2078 "\nbe called. This obtains the credentials used by accept. Acquire need\n"
2079 "only be called once, since the credentials it returns are used each time\n"
2080 "accept is called. Then init is called, followed by accept. Calling init\n"
2081 "twice without calling accept or calling these in a different order gives\n"
2082 "erroneous results and will cause memory leaks in the gssapi daemon. \n"
2083 "Finally, after calling init and accept, init must be called again to\n"
2084 "finish context establishment. So an example sequence (with data valid for\n"
2085 "the Kerberos mechanism and running on the machine \"elrond\" in the realm\n"
2086 "FOO.BAR.SUN.COM is :\n"));
2087 	fprintf(stderr,
2088 		gettext("\nacquire service@host 1.2.840.113554.1.2.2\n"
2089 		"init service@host 1.2.840.113554.1.2.2\n"
2090 		"accept\ninit service@host 1.2.840.113554.1.2.2\n"
2091 		"\nAfter a context is established, sign, seal,\n"
2092 		"verify and unseal may be called. Here are some examples\n"
2093 		"for these routines : \n\n"
2094 		"sign initiator ThisTestMessageIsForSigning\n"
2095 		"verify acceptor\nseal initiator ThisTestMessageIsForSealing\n"
2096 		"unseal acceptor\n\nEach input line is terminated by <cr>.\n"
2097 		"The program is terminated by cntl-d\nor the command \"exit\""
2098 		"\nfrom the prompt\n\n"));
2099 }
2100 
2101 static void
2102 usage()
2103 {
2104 	fprintf(stderr,
2105 		gettext(
2106 		"\nusage:\t[acquire | gss_acquire_cred]"
2107 		"desired_name mech_type\n"
2108 		"\t[release | gss_release_cred]\n"
2109 		"\t[init | gss_init_sec_context] target_name mech_type\n"
2110 		"\t[accept | gss_accept_sec_context]\n"
2111 		"\t[process | gss_process_context_token] initiator | acceptor\n"
2112 		"\t[delete | gss_delete_sec_context] initiator | acceptor\n"
2113 		"\t[time | gss_context_time] {not yet implemented}\n"
2114 		"\t[sign | gss_sign] initiator | acceptor message-to-sign\n"
2115 		"\t[verify | gss_verify] initiator | acceptor\n"
2116 		"\t[seal | gss_seal] initiator | acceptor message-to-seal\n"
2117 		"\t[unseal | gss_unseal] initiator | acceptor\n"
2118 		"\t[status | gss_display_status] mech_type  [major | minor] \n"
2119 		"\t[indicate | gss_indicate_mechs]\n"
2120 		"\t[inquire | gss_inquire_cred] {not yet implemented}\n"
2121 		"\t[expname2unixcred | gsscred_expname_to_unix_cred]"
2122 		" export-name\n"
2123 		"\t[name2unixcred | gsscred_name_to_unix_cred] "
2124 		"pname [name_type mech_type]\n"
2125 		"\t[grpinfo | gss_get_group_info] uid\n"
2126 		"\t[gss_all | all] desired_name\n"
2127 		"\t[gss_loop | loop] desired_name\n"
2128 		"\texit\n\n"));
2129 }
2130 
2131 /* Copied from parse_argv(), then modified */
2132 
2133 static int
2134 parse_input_line(input_line, argc, argv)
2135 char *input_line;
2136 int * argc;
2137 char ***argv;
2138 {
2139 	const char nil = '\0';
2140 	char * chptr;
2141 	int chr_cnt;
2142 	int arg_cnt = 0;
2143 	int ch_was_space = 1;
2144 	int ch_is_space;
2145 
2146 	chr_cnt = strlen(input_line);
2147 
2148 	/* Count the arguments in the input_line string */
2149 
2150 	*argc = 1;
2151 
2152 	for (chptr = &input_line[0]; *chptr != nil; chptr++) {
2153 		ch_is_space = isspace(*chptr);
2154 		if (ch_is_space && !ch_was_space) {
2155 			(*argc)++;
2156 		}
2157 		ch_was_space = ch_is_space;
2158 	}
2159 
2160 	if (ch_was_space) {
2161 		(*argc)--;
2162 	}	/* minus trailing spaces */
2163 
2164 	/* Now that we know how many args calloc the argv array */
2165 
2166 	*argv = (char **) CALLOC((*argc)+1, sizeof (char *));
2167 	chptr = (char *) (&input_line[0]);
2168 
2169 	for (ch_was_space = 1; *chptr != nil; chptr++) {
2170 		ch_is_space = isspace(*chptr);
2171 		if (ch_is_space) {
2172 			*chptr = nil;	/* replace each space with nil	*/
2173 		} else if (ch_was_space) {	/* begining of word? */
2174 			(*argv)[arg_cnt++] = chptr;	/* new argument ? */
2175 		}
2176 
2177 		ch_was_space = ch_is_space;
2178 	}
2179 
2180 	return (chr_cnt);
2181 }
2182