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