xref: /titanic_50/usr/src/cmd/keyserv/keyserv.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /*	All Rights Reserved   */
29 
30 /*
31  * University Copyright- Copyright (c) 1982, 1986, 1988
32  * The Regents of the University of California
33  * All Rights Reserved
34  *
35  * University Acknowledgment- Portions of this document are derived from
36  * software developed by the University of California, Berkeley, and its
37  * contributors.
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 /*
43  * keyserv - server for storing private encryption keys
44  *   keyserv(1M) performs multiple functions:  it stores secret keys per uid; it
45  *   performs public key encryption and decryption operations; and it generates
46  *   "random" keys.  keyserv(1M) will talk to no one but a local root process on
47  *   the local transport only.
48  */
49 
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <sys/uio.h>
55 #include <unistd.h>
56 #include <string.h>
57 #include <deflt.h>
58 #include <rpc/rpc.h>
59 #include <sys/param.h>
60 #include <sys/file.h>
61 #include <sys/resource.h>
62 #include <pwd.h>
63 #include <rpc/des_crypt.h>
64 #include <rpc/key_prot.h>
65 #include <thread.h>
66 #include "rpc/svc_mt.h"
67 #include <rpcsvc/nis_dhext.h>
68 #include <syslog.h>
69 #include <libscf.h>
70 
71 #include "debug.h"
72 #include "keyserv_cache.h"
73 
74 #ifdef KEYSERV_RANDOM
75 extern long random();
76 #endif
77 
78 extern keystatus pk_setkey();
79 extern keystatus pk_encrypt();
80 extern keystatus pk_decrypt();
81 extern keystatus pk_netput();
82 extern keystatus pk_netget();
83 extern keystatus pk_get_conv_key();
84 extern bool_t svc_get_local_cred();
85 
86 extern keystatus pk_setkey3();
87 extern keystatus pk_encrypt3();
88 extern keystatus pk_decrypt3();
89 extern keystatus pk_netput3();
90 extern keystatus pk_netget3();
91 extern keystatus pk_get_conv_key3();
92 extern keystatus pk_clear3();
93 
94 extern int init_mechs();
95 extern int addmasterkey();
96 extern int storeotherrootkeys();
97 extern int setdeskeyarray();
98 
99 extern int getdomainname();
100 
101 static void randomize();
102 static void usage();
103 static void defaults();
104 static int getrootkey();
105 static int get_cache_size(char *);
106 static bool_t get_auth();
107 
108 #ifdef DEBUG
109 extern int test_debug();
110 extern int real_debug();
111 int debugging = 1;
112 #else
113 int debugging = 0;
114 #endif
115 
116 static void keyprogram();
117 static des_block masterkey;
118 char *getenv();
119 static char ROOTKEY[] = "/etc/.rootkey";
120 
121 static char *defaults_file = "/etc/default/keyserv";
122 static int use_nobody_keys = TRUE;
123 
124 /*
125  * Hack to allow the keyserver to use AUTH_DES (for authenticated
126  * NIS+ calls, for example).  The only functions that get called
127  * are key_encryptsession_pk, key_decryptsession_pk, and key_gendes.
128  *
129  * The approach is to have the keyserver fill in pointers to local
130  * implementations of these functions, and to call those in key_call().
131  */
132 
133 bool_t __key_encrypt_pk_2_svc();
134 bool_t __key_decrypt_pk_2_svc();
135 bool_t __key_gen_1_svc();
136 
137 extern bool_t (*__key_encryptsession_pk_LOCAL)();
138 extern bool_t (*__key_decryptsession_pk_LOCAL)();
139 extern bool_t (*__key_gendes_LOCAL)();
140 
141 static int nthreads = 32;
142 
143 /* Disk caching of common keys on by default */
144 int disk_caching = 1;
145 
146 mechanism_t **mechs;
147 
148 /*
149  * The default size for all types of mech.
150  * positive integers denote multiples of 1MB
151  * negative integers denote number of entries
152  * same goes for non-null entries in cache_size
153  */
154 static int default_cache = 1;
155 
156 int *cache_size;
157 char **cache_options;
158 
159 main(argc, argv)
160 	int argc;
161 	char *argv[];
162 {
163 	int sflag = 0, s1flag = 0, s2flag = 0, nflag = 0, dflag = 0, eflag = 0;
164 	char *options, *value;
165 	extern char *optarg;
166 	extern int optind;
167 	int c, d;
168 	struct rlimit rl;
169 	int mode = RPC_SVC_MT_AUTO;
170 	int maxrecsz = RPC_MAXDATASIZE;
171 
172 	int detachfromtty();
173 	int setmodulus();
174 	int pk_nodefaultkeys();
175 	int svc_create_local_service();
176 
177 	char domainname[MAXNETNAMELEN + 1];
178 
179 	/*
180 	 * Set our allowed number of file descriptors to the max
181 	 * of what the system will allow, limited by FD_SETSIZE.
182 	 */
183 	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
184 		rlim_t limit;
185 
186 		if ((limit = rl.rlim_max) > FD_SETSIZE)
187 			limit = FD_SETSIZE;
188 		rl.rlim_cur = limit;
189 		(void) setrlimit(RLIMIT_NOFILE, &rl);
190 	}
191 
192 	__key_encryptsession_pk_LOCAL = &__key_encrypt_pk_2_svc;
193 	__key_decryptsession_pk_LOCAL = &__key_decrypt_pk_2_svc;
194 	__key_gendes_LOCAL = &__key_gen_1_svc;
195 
196 	/*
197 	 * Pre-option initialisation
198 	 */
199 	(void) umask(066);	/* paranoia */
200 	if (geteuid() != 0) {
201 		(void) fprintf(stderr, "%s must be run as root\n", argv[0]);
202 		exit(1);
203 	}
204 	setmodulus(HEXMODULUS);
205 	openlog("keyserv", LOG_PID, LOG_DAEMON);
206 
207 	/*
208 	 * keyserv will not work with a null domainname.
209 	 */
210 	if (getdomainname(domainname, MAXNETNAMELEN+1) ||
211 	    (domainname[0] == '\0')) {
212 	    syslog(LOG_ERR, "could not get a valid domainname.\n");
213 	    exit(SMF_EXIT_ERR_CONFIG);
214 	}
215 
216 	/*
217 	 * Initialise security mechanisms
218 	 */
219 	cache_size = NULL;
220 	cache_options = NULL;
221 	if (init_mechs() == -1) {
222 		disk_caching = 0;
223 	}
224 
225 	defaults();
226 
227 	while ((c = getopt(argc, argv, "ndDet:cs:")) != -1)
228 		switch (c) {
229 		case 'n':
230 			nflag++;
231 			break;
232 		case 'd':
233 			dflag++;
234 			use_nobody_keys = FALSE;
235 			break;
236 		case 'e':
237 			eflag++;
238 			use_nobody_keys = TRUE;
239 			break;
240 		case 'D':
241 			debugging = 1;
242 			break;
243 		case 't':
244 			nthreads = atoi(optarg);
245 			break;
246 		case 'c':
247 			disk_caching = 0;
248 			break;
249 		case 's':
250 			if (!disk_caching) {
251 				fprintf(stderr, "missing configuration file");
252 				fprintf(stderr, " or -c option specified\n");
253 				usage();
254 			}
255 			sflag++;
256 			/*
257 			 * Which version of [-s] do we have...?
258 			 */
259 			if (strchr((const char *) optarg, '=') == NULL) {
260 				/*
261 				 * -s <size>
262 				 */
263 				if (s1flag) {
264 				    fprintf(stderr, "duplicate [-s <size>]\n");
265 					usage();
266 				}
267 				s1flag++;
268 				default_cache = get_cache_size(optarg);
269 				break;
270 			}
271 			/*
272 			 * -s <mechtype>=<size>[,...]
273 			 */
274 			s2flag++;
275 			options = optarg;
276 			while (*options != '\0') {
277 				d = getsubopt(&options, cache_options, &value);
278 				if (d == -1) {
279 					/* Ignore unknown mechtype */
280 					continue;
281 				}
282 				if (value == NULL) {
283 					fprintf(stderr,
284 					"missing cache size for mechtype %s\n",
285 					cache_options[d]);
286 					usage();
287 				}
288 				cache_size[d] = get_cache_size(value);
289 			}
290 			break;
291 		default:
292 			usage();
293 			break;
294 		}
295 
296 
297 	if (dflag && eflag) {
298 		(void) fprintf(stderr, "specify only one of -d and -e\n");
299 		usage();
300 	}
301 
302 	if (use_nobody_keys == FALSE) {
303 		pk_nodefaultkeys();
304 	}
305 
306 	if (optind != argc) {
307 		usage();
308 	}
309 
310 	if (!disk_caching && sflag) {
311 		fprintf(stderr, "missing configuration file");
312 		fprintf(stderr, " or -c option specified\n");
313 		usage();
314 	}
315 
316 	if (debugging) {
317 		if (disk_caching) {
318 			char **cpp = cache_options;
319 			int *ip = cache_size;
320 			(void) fprintf(stderr, "default disk cache size: ");
321 			if (default_cache < 0) {
322 				(void) fprintf(stderr, "%d entries\n",
323 					abs(default_cache));
324 			} else {
325 				(void) fprintf(stderr, "%dMB\n", default_cache);
326 			}
327 
328 			(void) fprintf(stderr, "supported mechanisms:\n");
329 			(void) fprintf(stderr, "\talias\t\tdisk cache size\n");
330 			(void) fprintf(stderr, "\t=====\t\t===============\n");
331 			while (*cpp != NULL) {
332 				(void) fprintf(stderr, "\t%s\t\t", *cpp++);
333 				if (*ip < 0) {
334 					(void) fprintf(stderr, "%d entries\n",
335 						abs(*ip));
336 				} else {
337 					(void) fprintf(stderr, "%dMB\n", *ip);
338 				}
339 				ip++;
340 			}
341 		} else {
342 			(void) fprintf(stderr,
343 				"common key disk caching disabled\n");
344 		}
345 	}
346 	/*
347 	 * Post-option initialisation
348 	 */
349 	if (disk_caching) {
350 		int i;
351 		for (i = 0; mechs[i]; i++) {
352 			if ((AUTH_DES_COMPAT_CHK(mechs[i])) ||
353 			    (mechs[i]->keylen < 0) || (mechs[i]->algtype < 0))
354 				continue;
355 			create_cache_file(mechs[i]->keylen, mechs[i]->algtype,
356 				cache_size[i] ? cache_size[i] : default_cache);
357 		}
358 	}
359 	getrootkey(&masterkey, nflag);
360 
361 	/*
362 	 * Set MT mode
363 	 */
364 	if (nthreads > 0) {
365 		(void) rpc_control(RPC_SVC_MTMODE_SET, &mode);
366 		(void) rpc_control(RPC_SVC_THRMAX_SET, &nthreads);
367 	}
368 
369 	/*
370 	 * Enable non-blocking mode and maximum record size checks for
371 	 * connection oriented transports.
372 	 */
373 	if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
374 		syslog(LOG_INFO, "unable to set max RPC record size");
375 	}
376 
377 	if (svc_create_local_service(keyprogram, KEY_PROG, KEY_VERS,
378 		"netpath", "keyserv") == 0) {
379 		syslog(LOG_ERR,
380 			"%s: unable to create service for version %d\n",
381 			argv[0], KEY_VERS);
382 		exit(1);
383 	}
384 
385 	if (svc_create_local_service(keyprogram, KEY_PROG, KEY_VERS2,
386 		"netpath", "keyserv") == 0) {
387 		syslog(LOG_ERR,
388 			"%s: unable to create service for version %d\n",
389 			argv[0], KEY_VERS2);
390 		exit(1);
391 	}
392 
393 	if (svc_create_local_service(keyprogram, KEY_PROG, KEY_VERS3,
394 		"netpath", "keyserv") == 0) {
395 		syslog(LOG_ERR,
396 			"%s: unable to create service for version %d\n",
397 			argv[0], KEY_VERS3);
398 		exit(1);
399 	}
400 
401 	if (!debugging) {
402 		detachfromtty();
403 	}
404 
405 	if (svc_create(keyprogram, KEY_PROG, KEY_VERS, "door") == 0) {
406 		syslog(LOG_ERR,
407 		"%s: unable to create service over doors for version %d\n",
408 			argv[0], KEY_VERS);
409 		exit(1);
410 	}
411 
412 	if (svc_create(keyprogram, KEY_PROG, KEY_VERS2, "door") == 0) {
413 		syslog(LOG_ERR,
414 		"%s: unable to create service over doors for version %d\n",
415 			argv[0], KEY_VERS2);
416 		exit(1);
417 	}
418 
419 	if (svc_create(keyprogram, KEY_PROG, KEY_VERS3, "door") == 0) {
420 		syslog(LOG_ERR,
421 		"%s: unable to create service over doors for version %d\n",
422 			argv[0], KEY_VERS3);
423 		exit(1);
424 	}
425 
426 	svc_run();
427 	abort();
428 	/* NOTREACHED */
429 	return (0);
430 }
431 
432 
433 /*
434  * In the event that we don't get a root password, we try to
435  * randomize the master key the best we can
436  */
437 static void
438 randomize(master)
439 	des_block *master;
440 {
441 	int i;
442 	int seed;
443 	struct timeval tv;
444 	int shift;
445 
446 	seed = 0;
447 	for (i = 0; i < 1024; i++) {
448 		(void) gettimeofday(&tv, (struct timezone *)NULL);
449 		shift = i % 8 * sizeof (int);
450 		seed ^= (tv.tv_usec << shift) | (tv.tv_usec >> (32 - shift));
451 	}
452 #ifdef KEYSERV_RANDOM
453 	srandom(seed);
454 	master->key.low = random();
455 	master->key.high = random();
456 	srandom(seed);
457 #else
458 	/* use stupid dangerous bad rand() */
459 	srand(seed);
460 	master->key.low = rand();
461 	master->key.high = rand();
462 	srand(seed);
463 #endif
464 }
465 
466 static char *
467 fgets_ignorenul(char *s, int n, FILE *stream)
468 {
469 	int fildes = fileno(stream);
470 	int i = 0;
471 	int rs = 0;
472 	char c;
473 
474 	if (fildes < 0)
475 		return (NULL);
476 
477 	while (i < n - 1) {
478 		rs = read(fildes, &c, 1);
479 		switch (rs) {
480 		case 1:
481 			break;
482 		case 0:
483 			/* EOF */
484 			if (i > 0)
485 				s[i] = '\0';
486 			return (NULL);
487 			break;
488 		default:
489 			return (NULL);
490 		}
491 		switch (c) {
492 		case '\0':
493 			break;
494 		case '\n':
495 			s[i] = c;
496 			s[++i] = '\0';
497 			return (s);
498 		default:
499 		if (c != '\0')
500 			s[i++] = c;
501 		}
502 	}
503 	s[i] = '\0';
504 	return (s);
505 }
506 
507 /* Should last until 16384-bit DH keys */
508 #define	MAXROOTKEY_LINE_LEN	4224
509 #define	MAXROOTKEY_LEN		4096
510 #define	ROOTKEY_FILE		"/etc/.rootkey"
511 
512 static int
513 getotherrootkeys(char *name)
514 {
515 	FILE		*rootkey;
516 	char		line[MAXROOTKEY_LINE_LEN];
517 	char		key[MAXROOTKEY_LEN];
518 	algtype_t	algtype;
519 	int		count = 0;
520 
521 	if (!(rootkey = fopen(ROOTKEY, "r")))
522 		return (0);
523 
524 	while (fgets_ignorenul(line, MAXROOTKEY_LINE_LEN, rootkey)) {
525 		debug(KEYSERV_DEBUG0, ("ROOTKEY %d: %s\n", count, line));
526 		count++;
527 		sscanf(line, "%s %d", key, &algtype);
528 
529 		if (!strlen(key))
530 			continue;
531 		addmasterkey(key, name, algtype);
532 	}
533 	fclose(rootkey);
534 	return (1);
535 }
536 
537 /*
538  * Try to get root's secret key, by prompting if terminal is a tty, else trying
539  * from standard input.
540  * Returns 1 on success.
541  */
542 static
543 getrootkey(master, prompt)
544 	des_block *master;
545 	int prompt;
546 {
547 	char *passwd;
548 	char name[MAXNETNAMELEN + 1];
549 	char secret[HEXKEYBYTES + 1];
550 	FILE *fp;
551 	int passwd2des();
552 	int retval;
553 
554 	randomize(master);
555 	if (!getnetname(name)) {
556 	    (void) fprintf(stderr, "keyserv: \
557 failed to generate host's netname when establishing root's key.\n");
558 	    return (0);
559 	}
560 	if (!prompt) {
561 		return (getotherrootkeys(name));
562 	}
563 	/*
564 	 * Decrypt yellow pages publickey entry to get secret key
565 	 */
566 	passwd = getpass("root password:");
567 	passwd2des(passwd, master);
568 	if (!getsecretkey(name, secret, passwd)) {
569 		(void) fprintf(stderr,
570 		"Can't find %s's secret key\n", name);
571 		return (0);
572 	}
573 	if (secret[0] == 0) {
574 		(void) fprintf(stderr,
575 	"Password does not decrypt secret key for %s\n", name);
576 		return (0);
577 	}
578 	if ((fp = fopen(ROOTKEY, "w")) == NULL) {
579 		(void) fprintf(stderr,
580 			"Cannot open %s for write\n", ROOTKEY);
581 		return (0);
582 	}
583 	retval = storeotherrootkeys(fp, name, passwd, secret);
584 	fclose(fp);
585 	return (retval);
586 }
587 
588 /*
589  * Procedures to implement RPC service.  These procedures are named
590  * differently from the definitions in key_prot.h (generated by rpcgen)
591  * because they take different arguments.
592  */
593 char *
594 strstatus(status)
595 	keystatus status;
596 {
597 	switch (status) {
598 	case KEY_SUCCESS:
599 		return ("KEY_SUCCESS");
600 	case KEY_NOSECRET:
601 		return ("KEY_NOSECRET");
602 	case KEY_UNKNOWN:
603 		return ("KEY_UNKNOWN");
604 	case KEY_SYSTEMERR:
605 		return ("KEY_SYSTEMERR");
606 	case KEY_BADALG:
607 		return ("KEY_BADALG");
608 	case KEY_BADLEN:
609 		return ("KEY_BADLEN");
610 	default:
611 		return ("(bad result code)");
612 	}
613 }
614 
615 bool_t
616 __key_set_1_svc(uid, key, status)
617 	uid_t uid;
618 	keybuf key;
619 	keystatus *status;
620 {
621 	if (debugging) {
622 		(void) fprintf(stderr, "set(%d, %.*s) = ", uid,
623 				sizeof (keybuf), key);
624 	}
625 	*status = pk_setkey(uid, key);
626 	if (debugging) {
627 		(void) fprintf(stderr, "%s\n", strstatus(*status));
628 		(void) fflush(stderr);
629 	}
630 	return (TRUE);
631 }
632 
633 bool_t
634 __key_encrypt_pk_2_svc(uid, arg, res)
635 	uid_t uid;
636 	cryptkeyarg2 *arg;
637 	cryptkeyres *res;
638 {
639 
640 	if (debugging) {
641 		(void) fprintf(stderr, "encrypt(%d, %s, %08x%08x) = ", uid,
642 				arg->remotename, arg->deskey.key.high,
643 				arg->deskey.key.low);
644 	}
645 	res->cryptkeyres_u.deskey = arg->deskey;
646 	res->status = pk_encrypt(uid, arg->remotename, &(arg->remotekey),
647 				&res->cryptkeyres_u.deskey);
648 	if (debugging) {
649 		if (res->status == KEY_SUCCESS) {
650 			(void) fprintf(stderr, "%08x%08x\n",
651 					res->cryptkeyres_u.deskey.key.high,
652 					res->cryptkeyres_u.deskey.key.low);
653 		} else {
654 			(void) fprintf(stderr, "%s\n", strstatus(res->status));
655 		}
656 		(void) fflush(stderr);
657 	}
658 	return (TRUE);
659 }
660 
661 bool_t
662 __key_decrypt_pk_2_svc(uid, arg, res)
663 	uid_t uid;
664 	cryptkeyarg2 *arg;
665 	cryptkeyres *res;
666 {
667 
668 	if (debugging) {
669 		(void) fprintf(stderr, "decrypt(%d, %s, %08x%08x) = ", uid,
670 				arg->remotename, arg->deskey.key.high,
671 				arg->deskey.key.low);
672 	}
673 	res->cryptkeyres_u.deskey = arg->deskey;
674 	res->status = pk_decrypt(uid, arg->remotename, &(arg->remotekey),
675 				&res->cryptkeyres_u.deskey);
676 	if (debugging) {
677 		if (res->status == KEY_SUCCESS) {
678 			(void) fprintf(stderr, "%08x%08x\n",
679 					res->cryptkeyres_u.deskey.key.high,
680 					res->cryptkeyres_u.deskey.key.low);
681 		} else {
682 			(void) fprintf(stderr, "%s\n", strstatus(res->status));
683 		}
684 		(void) fflush(stderr);
685 	}
686 	return (TRUE);
687 }
688 
689 bool_t
690 __key_net_put_2_svc(uid, arg, status)
691 	uid_t uid;
692 	key_netstarg *arg;
693 	keystatus *status;
694 {
695 
696 	if (debugging) {
697 		(void) fprintf(stderr, "net_put(%s, %.*s, %.*s) = ",
698 			arg->st_netname, sizeof (arg->st_pub_key),
699 			arg->st_pub_key, sizeof (arg->st_priv_key),
700 			arg->st_priv_key);
701 	};
702 
703 	*status = pk_netput(uid, arg);
704 
705 	if (debugging) {
706 		(void) fprintf(stderr, "%s\n", strstatus(*status));
707 		(void) fflush(stderr);
708 	}
709 
710 	return (TRUE);
711 }
712 
713 /* ARGSUSED */
714 bool_t
715 __key_net_get_2_svc(uid, arg, keynetname)
716 	uid_t uid;
717 	void *arg;
718 	key_netstres *keynetname;
719 {
720 
721 	if (debugging)
722 		(void) fprintf(stderr, "net_get(%d) = ", uid);
723 
724 	keynetname->status = pk_netget(uid, &keynetname->key_netstres_u.knet);
725 	if (debugging) {
726 		if (keynetname->status == KEY_SUCCESS) {
727 			fprintf(stderr, "<%s, %.*s, %.*s>\n",
728 			keynetname->key_netstres_u.knet.st_netname,
729 			sizeof (keynetname->key_netstres_u.knet.st_pub_key),
730 			keynetname->key_netstres_u.knet.st_pub_key,
731 			sizeof (keynetname->key_netstres_u.knet.st_priv_key),
732 			keynetname->key_netstres_u.knet.st_priv_key);
733 		} else {
734 			(void) fprintf(stderr, "NOT FOUND\n");
735 		}
736 		(void) fflush(stderr);
737 	}
738 
739 	return (TRUE);
740 
741 }
742 
743 bool_t
744 __key_get_conv_2_svc(uid, arg, res)
745 	uid_t uid;
746 	keybuf arg;
747 	cryptkeyres *res;
748 {
749 
750 	if (debugging)
751 		(void) fprintf(stderr, "get_conv(%d, %.*s) = ", uid,
752 			sizeof (arg), arg);
753 
754 
755 	res->status = pk_get_conv_key(uid, arg, res);
756 
757 	if (debugging) {
758 		if (res->status == KEY_SUCCESS) {
759 			(void) fprintf(stderr, "%08x%08x\n",
760 				res->cryptkeyres_u.deskey.key.high,
761 				res->cryptkeyres_u.deskey.key.low);
762 		} else {
763 			(void) fprintf(stderr, "%s\n", strstatus(res->status));
764 		}
765 		(void) fflush(stderr);
766 	}
767 	return (TRUE);
768 }
769 
770 
771 bool_t
772 __key_encrypt_1_svc(uid, arg, res)
773 	uid_t uid;
774 	cryptkeyarg *arg;
775 	cryptkeyres *res;
776 {
777 
778 	if (debugging) {
779 		(void) fprintf(stderr, "encrypt(%d, %s, %08x%08x) = ", uid,
780 				arg->remotename, arg->deskey.key.high,
781 				arg->deskey.key.low);
782 	}
783 	res->cryptkeyres_u.deskey = arg->deskey;
784 	res->status = pk_encrypt(uid, arg->remotename, NULL,
785 				&res->cryptkeyres_u.deskey);
786 	if (debugging) {
787 		if (res->status == KEY_SUCCESS) {
788 			(void) fprintf(stderr, "%08x%08x\n",
789 					res->cryptkeyres_u.deskey.key.high,
790 					res->cryptkeyres_u.deskey.key.low);
791 		} else {
792 			(void) fprintf(stderr, "%s\n", strstatus(res->status));
793 		}
794 		(void) fflush(stderr);
795 	}
796 	return (TRUE);
797 }
798 
799 bool_t
800 __key_decrypt_1_svc(uid, arg, res)
801 	uid_t uid;
802 	cryptkeyarg *arg;
803 	cryptkeyres *res;
804 {
805 	if (debugging) {
806 		(void) fprintf(stderr, "decrypt(%d, %s, %08x%08x) = ", uid,
807 				arg->remotename, arg->deskey.key.high,
808 				arg->deskey.key.low);
809 	}
810 	res->cryptkeyres_u.deskey = arg->deskey;
811 	res->status = pk_decrypt(uid, arg->remotename, NULL,
812 				&res->cryptkeyres_u.deskey);
813 	if (debugging) {
814 		if (res->status == KEY_SUCCESS) {
815 			(void) fprintf(stderr, "%08x%08x\n",
816 					res->cryptkeyres_u.deskey.key.high,
817 					res->cryptkeyres_u.deskey.key.low);
818 		} else {
819 			(void) fprintf(stderr, "%s\n", strstatus(res->status));
820 		}
821 		(void) fflush(stderr);
822 	}
823 	return (TRUE);
824 }
825 
826 /* ARGSUSED */
827 bool_t
828 __key_gen_1_svc(v, s, key)
829 	void *v;
830 	struct svc_req *s;
831 	des_block *key;
832 {
833 	struct timeval time;
834 	static des_block keygen;
835 	static mutex_t keygen_mutex = DEFAULTMUTEX;
836 	int r;
837 
838 	(void) gettimeofday(&time, (struct timezone *)NULL);
839 	(void) mutex_lock(&keygen_mutex);
840 	keygen.key.high += (time.tv_sec ^ time.tv_usec);
841 	keygen.key.low += (time.tv_sec ^ time.tv_usec);
842 	r = ecb_crypt((char *)&masterkey, (char *)&keygen, sizeof (keygen),
843 		DES_ENCRYPT | DES_HW);
844 	if (r != DESERR_NONE && r != DESERR_NOHWDEVICE) {
845 		mutex_unlock(&keygen_mutex);
846 		return (FALSE);
847 	}
848 	*key = keygen;
849 	mutex_unlock(&keygen_mutex);
850 
851 	des_setparity_g(key);
852 	if (debugging) {
853 		(void) fprintf(stderr, "gen() = %08x%08x\n", key->key.high,
854 					key->key.low);
855 		(void) fflush(stderr);
856 	}
857 	return (TRUE);
858 }
859 
860 /* ARGSUSED */
861 bool_t
862 __key_getcred_1_svc(uid, name, res)
863 	uid_t uid;
864 	netnamestr *name;
865 	getcredres *res;
866 {
867 	struct unixcred *cred;
868 
869 	cred = &res->getcredres_u.cred;
870 	if (!netname2user(*name, (uid_t *)&cred->uid, (gid_t *)&cred->gid,
871 			(int *)&cred->gids.gids_len,
872 					(gid_t *)cred->gids.gids_val)) {
873 		res->status = KEY_UNKNOWN;
874 	} else {
875 		res->status = KEY_SUCCESS;
876 	}
877 	if (debugging) {
878 		(void) fprintf(stderr, "getcred(%s) = ", *name);
879 		if (res->status == KEY_SUCCESS) {
880 			(void) fprintf(stderr, "uid=%d, gid=%d, grouplen=%d\n",
881 				cred->uid, cred->gid, cred->gids.gids_len);
882 		} else {
883 			(void) fprintf(stderr, "%s\n", strstatus(res->status));
884 		}
885 		(void) fflush(stderr);
886 	}
887 	return (TRUE);
888 }
889 
890 /*
891  * Version 3 procedures follow...
892  */
893 
894 static bool_t
895 __key_set_3_svc(uid_t uid, setkeyarg3 *arg, keystatus *status)
896 {
897 	debug(KEYSERV_DEBUG, ("__key_set_3_svc(%d, %d, %d)",
898 		uid, arg->algtype, arg->keylen));
899 	*status = pk_setkey3(uid, arg);
900 	debug(KEYSERV_DEBUG, ("__key_set_3_svc %s", strstatus(*status)));
901 	return (TRUE);
902 }
903 
904 static bool_t
905 __key_encrypt_3_svc(uid_t uid, cryptkeyarg3 *arg, cryptkeyres3 *res)
906 {
907 	int len, i;
908 	des_block *dp;
909 
910 	debug(KEYSERV_DEBUG, ("encrypt_3(%d %d %s)", uid,
911 		arg->deskey.deskeyarray_len, arg->remotename));
912 	res->status = pk_encrypt3(uid, arg, &res->cryptkeyres3_u.deskey);
913 	len = res->cryptkeyres3_u.deskey.deskeyarray_len;
914 	dp = res->cryptkeyres3_u.deskey.deskeyarray_val;
915 	for (i = 0; i < len; i++) {
916 		debug(KEYSERV_DEBUG0, ("encrypt_3 retval[%d] == (%x,%x)",
917 			i, dp->key.high, dp->key.low));
918 		dp++;
919 	}
920 	debug(KEYSERV_DEBUG, ("encrypt_3 returned %s", strstatus(res->status)));
921 	return (TRUE);
922 }
923 
924 static bool_t
925 __key_decrypt_3_svc(uid_t uid, cryptkeyarg3 *arg, cryptkeyres3 *res)
926 {
927 	int len, i;
928 	des_block *dp;
929 
930 	debug(KEYSERV_DEBUG, ("decrypt_3(%d, %d, %s)", uid,
931 		arg->deskey.deskeyarray_len, arg->remotename));
932 	res->status = pk_decrypt3(uid, arg, &res->cryptkeyres3_u.deskey);
933 	len = res->cryptkeyres3_u.deskey.deskeyarray_len;
934 	dp = res->cryptkeyres3_u.deskey.deskeyarray_val;
935 	for (i = 0; i < len; i++) {
936 		debug(KEYSERV_DEBUG0, ("decrypt_3 retval[%d] == (%x,%x)",
937 			i, dp->key.high, dp->key.low));
938 		dp++;
939 	}
940 	debug(KEYSERV_DEBUG, ("decrypt_3 returned %s", strstatus(res->status)));
941 	return (TRUE);
942 }
943 
944 /* ARGSUSED */
945 static bool_t
946 __key_gen_3_svc(void *v, keynum_t *kp, deskeyarray *res)
947 {
948 	int i;
949 	keynum_t keynum = *kp;
950 
951 	debug(KEYSERV_DEBUG, ("gen_3(%d %x)", keynum, res));
952 	res->deskeyarray_val = 0;
953 	if (!setdeskeyarray(res, keynum)) {
954 		return (FALSE);
955 	}
956 	for (i = 0; i < keynum; i++) {
957 		debug(KEYSERV_DEBUG, ("gen_3 calling gen_1 %x",
958 			res->deskeyarray_val+i));
959 		__key_gen_1_svc((void *) NULL, (struct svc_req *)NULL,
960 			res->deskeyarray_val+i);
961 		debug(KEYSERV_DEBUG, ("gen_3 val %d %x",
962 			i, *(int *)(res->deskeyarray_val+i)));
963 	}
964 	return (TRUE);
965 }
966 
967 static void
968 __key_gen_3_svc_free(deskeyarray *dp)
969 {
970 	free(dp->deskeyarray_val);
971 }
972 
973 static bool_t
974 __key_getcred_3_svc(uid_t uid, netnamestr *name, getcredres3 *res)
975 {
976 	return (__key_getcred_1_svc(uid, name, (getcredres *)res));
977 }
978 
979 static bool_t
980 __key_encrypt_pk_3_svc(uid_t uid, cryptkeyarg3 *arg, cryptkeyres3 *res)
981 {
982 	debug(KEYSERV_DEBUG, ("encrypt_pk_3(%d, %s)", uid, arg->remotename));
983 	res->status = pk_encrypt3(uid, arg, &res->cryptkeyres3_u.deskey);
984 	debug(KEYSERV_DEBUG, ("encrypt returned %s", strstatus(res->status)));
985 	return (TRUE);
986 }
987 
988 static void
989 __key_encrypt_pk_3_svc_free(cryptkeyres3 *res)
990 {
991 	if (res->status == KEY_SUCCESS) {
992 		free(res->cryptkeyres3_u.deskey.deskeyarray_val);
993 	}
994 }
995 
996 static bool_t
997 __key_decrypt_pk_3(uid_t uid, cryptkeyarg3 *arg, cryptkeyres3 *res)
998 {
999 	debug(KEYSERV_DEBUG, ("decrypt_pk_3(%d, %s)", uid, arg->remotename));
1000 	res->status = pk_decrypt3(uid, arg, &res->cryptkeyres3_u.deskey);
1001 	debug(KEYSERV_DEBUG, ("encrypt returned %s", strstatus(res->status)));
1002 	return (TRUE);
1003 }
1004 
1005 static void
1006 __key_decrypt_pk_3_free(cryptkeyres3 *res)
1007 {
1008 	if (res->status == KEY_SUCCESS) {
1009 		free(res->cryptkeyres3_u.deskey.deskeyarray_val);
1010 	}
1011 }
1012 
1013 static bool_t
1014 __key_net_put_3_svc(uid_t uid, key_netstarg3 *arg, keystatus *status)
1015 {
1016 	debug(KEYSERV_DEBUG, ("net_put_3 (%d, %x)", uid, arg));
1017 	*status = pk_netput3(uid, arg);
1018 	debug(KEYSERV_DEBUG, ("net_put_3 ret %s", strstatus(*status)));
1019 	return (TRUE);
1020 }
1021 
1022 static bool_t
1023 __key_net_get_3_svc(uid_t uid, mechtype *arg, key_netstres3 *keynetname)
1024 {
1025 	debug(KEYSERV_DEBUG, ("net_get_3 (%d, %x)", uid, arg));
1026 	keynetname->status = pk_netget3(uid,
1027 		arg, &keynetname->key_netstres3_u.knet);
1028 	debug(KEYSERV_DEBUG,
1029 		("net_get_3 ret %s", strstatus(keynetname->status)));
1030 	return (TRUE);
1031 }
1032 
1033 static void
1034 __key_net_get_3_svc_free(key_netstres3 *keynetname)
1035 {
1036 	if (keynetname->status == KEY_SUCCESS) {
1037 		free(keynetname->key_netstres3_u.knet.st_priv_key.keybuf3_val);
1038 		free(keynetname->key_netstres3_u.knet.st_pub_key.keybuf3_val);
1039 		free(keynetname->key_netstres3_u.knet.st_netname);
1040 	}
1041 }
1042 
1043 static bool_t
1044 __key_get_conv_3_svc(uid_t uid, deskeyarg3 *arg, cryptkeyres3 *res)
1045 {
1046 	debug(KEYSERV_DEBUG, ("get_conv_3(%d %x %x)", uid, arg, res));
1047 	res->status = pk_get_conv_key3(uid, arg, res);
1048 	debug(KEYSERV_DEBUG,
1049 		("get_conv_3 ret %s", strstatus(res->status)));
1050 	return (TRUE);
1051 }
1052 
1053 /* ARGSUSED */
1054 static bool_t
1055 __key_clear_3_svc(uid_t uid, void *arg, keystatus *status)
1056 {
1057 	debug(KEYSERV_DEBUG, ("clear_3(%d)", uid));
1058 	*status = pk_clear3(uid);
1059 	debug(KEYSERV_DEBUG, ("clear_3 ret %s", strstatus(*status)));
1060 	return (TRUE);
1061 }
1062 
1063 /*
1064  * RPC boilerplate
1065  */
1066 static void
1067 keyprogram(rqstp, transp)
1068 	struct svc_req *rqstp;
1069 	SVCXPRT *transp;
1070 {
1071 	union {
1072 		keybuf key_set_1_arg;
1073 		cryptkeyarg key_encrypt_1_arg;
1074 		cryptkeyarg key_decrypt_1_arg;
1075 		netnamestr key_getcred_1_arg;
1076 		cryptkeyarg key_encrypt_2_arg;
1077 		cryptkeyarg key_decrypt_2_arg;
1078 		netnamestr key_getcred_2_arg;
1079 		cryptkeyarg2 key_encrypt_pk_2_arg;
1080 		cryptkeyarg2 key_decrypt_pk_2_arg;
1081 		key_netstarg key_net_put_2_arg;
1082 		netobj  key_get_conv_2_arg;
1083 		keybuf3 key_set_3_arg;
1084 		cryptkeyarg3 key_encrypt_3_arg;
1085 		cryptkeyarg3 key_decrypt_3_arg;
1086 		cryptkeyarg3 key_encrypt_pk_3_arg;
1087 		cryptkeyarg3 key_decrypt_pk_3_arg;
1088 		keynum_t key_gen_3_arg;
1089 		netnamestr key_getcred_3_arg;
1090 		key_netstarg3 key_net_put_3_arg;
1091 		key_netstarg3 key_net_get_3_arg;
1092 		deskeyarg3 key_get_conv_3_arg;
1093 	} argument;
1094 	union {
1095 		keystatus status;
1096 		cryptkeyres cres;
1097 		des_block key;
1098 		getcredres gres;
1099 		key_netstres keynetname;
1100 		cryptkeyres3 cres3;
1101 		deskeyarray keyarray;
1102 		getcredres3 gres3;
1103 		key_netstres3 keynetname3;
1104 	} result;
1105 	uint_t gids[MAXGIDS];
1106 	char netname_str[MAXNETNAMELEN + 1];
1107 	bool_t (*xdr_argument)(), (*xdr_result)();
1108 	bool_t (*local)();
1109 	void (*local_free)() = NULL;
1110 	bool_t retval;
1111 	uid_t uid;
1112 	int check_auth;
1113 
1114 	switch (rqstp->rq_proc) {
1115 	case NULLPROC:
1116 		svc_sendreply(transp, xdr_void, (char *)NULL);
1117 		return;
1118 
1119 	case KEY_SET:
1120 		xdr_argument = xdr_keybuf;
1121 		xdr_result = xdr_int;
1122 		local = __key_set_1_svc;
1123 		check_auth = 1;
1124 		break;
1125 
1126 	case KEY_ENCRYPT:
1127 		xdr_argument = xdr_cryptkeyarg;
1128 		xdr_result = xdr_cryptkeyres;
1129 		local = __key_encrypt_1_svc;
1130 		check_auth = 1;
1131 		break;
1132 
1133 	case KEY_DECRYPT:
1134 		xdr_argument = xdr_cryptkeyarg;
1135 		xdr_result = xdr_cryptkeyres;
1136 		local = __key_decrypt_1_svc;
1137 		check_auth = 1;
1138 		break;
1139 
1140 	case KEY_GEN:
1141 		xdr_argument = xdr_void;
1142 		xdr_result = xdr_des_block;
1143 		local = __key_gen_1_svc;
1144 		check_auth = 0;
1145 		break;
1146 
1147 	case KEY_GETCRED:
1148 		xdr_argument = xdr_netnamestr;
1149 		xdr_result = xdr_getcredres;
1150 		local = __key_getcred_1_svc;
1151 		result.gres.getcredres_u.cred.gids.gids_val = gids;
1152 		check_auth = 0;
1153 		break;
1154 
1155 	case KEY_ENCRYPT_PK:
1156 		xdr_argument = xdr_cryptkeyarg2;
1157 		xdr_result = xdr_cryptkeyres;
1158 		local = __key_encrypt_pk_2_svc;
1159 		check_auth = 1;
1160 		break;
1161 
1162 	case KEY_DECRYPT_PK:
1163 		xdr_argument = xdr_cryptkeyarg2;
1164 		xdr_result = xdr_cryptkeyres;
1165 		local = __key_decrypt_pk_2_svc;
1166 		check_auth = 1;
1167 		break;
1168 
1169 
1170 	case KEY_NET_PUT:
1171 		xdr_argument = xdr_key_netstarg;
1172 		xdr_result = xdr_keystatus;
1173 		local = __key_net_put_2_svc;
1174 		check_auth = 1;
1175 		break;
1176 
1177 	case KEY_NET_GET:
1178 		xdr_argument = (xdrproc_t)xdr_void;
1179 		xdr_result = xdr_key_netstres;
1180 		local = __key_net_get_2_svc;
1181 		result.keynetname.key_netstres_u.knet.st_netname = netname_str;
1182 		check_auth = 1;
1183 		break;
1184 
1185 	case KEY_GET_CONV:
1186 		xdr_argument = (xdrproc_t)xdr_keybuf;
1187 		xdr_result = xdr_cryptkeyres;
1188 		local = __key_get_conv_2_svc;
1189 		check_auth = 1;
1190 		break;
1191 
1192 	/*
1193 	 * Version 3 procedures follow...
1194 	 */
1195 
1196 	case KEY_SET_3:
1197 		xdr_argument = (xdrproc_t)xdr_setkeyarg3;
1198 		xdr_result = xdr_keystatus;
1199 		local = __key_set_3_svc;
1200 		check_auth = 1;
1201 		break;
1202 
1203 	case KEY_ENCRYPT_3:
1204 		xdr_argument = (xdrproc_t)xdr_cryptkeyarg3;
1205 		xdr_result = xdr_cryptkeyres3;
1206 		local = __key_encrypt_3_svc;
1207 		check_auth = 1;
1208 		break;
1209 
1210 	case KEY_DECRYPT_3:
1211 		xdr_argument = (xdrproc_t)xdr_cryptkeyarg3;
1212 		xdr_result = xdr_cryptkeyres3;
1213 		local = __key_decrypt_3_svc;
1214 		check_auth = 1;
1215 		break;
1216 
1217 	case KEY_GEN_3:
1218 		xdr_argument = (xdrproc_t)xdr_keynum_t;
1219 		xdr_result = xdr_deskeyarray;
1220 		local = __key_gen_3_svc;
1221 		local_free = __key_gen_3_svc_free;
1222 		check_auth = 0;
1223 		break;
1224 
1225 	case KEY_GETCRED_3:
1226 		xdr_argument = (xdrproc_t)xdr_netnamestr;
1227 		xdr_result = xdr_getcredres3;
1228 		local = __key_getcred_3_svc;
1229 		check_auth = 0;
1230 		break;
1231 
1232 	case KEY_ENCRYPT_PK_3:
1233 		xdr_argument = (xdrproc_t)xdr_cryptkeyarg3;
1234 		xdr_result = xdr_cryptkeyres3;
1235 		local = __key_encrypt_pk_3_svc;
1236 		local_free = __key_encrypt_pk_3_svc_free;
1237 		check_auth = 1;
1238 		break;
1239 
1240 	case KEY_DECRYPT_PK_3:
1241 		xdr_argument = (xdrproc_t)xdr_cryptkeyarg3;
1242 		xdr_result = xdr_cryptkeyres3;
1243 		local = __key_decrypt_pk_3;
1244 		local_free = __key_decrypt_pk_3_free;
1245 		check_auth = 1;
1246 		break;
1247 
1248 	case KEY_NET_PUT_3:
1249 		xdr_argument = (xdrproc_t)xdr_key_netstarg3;
1250 		xdr_result = xdr_keystatus;
1251 		local = __key_net_put_3_svc;
1252 		check_auth = 1;
1253 		break;
1254 
1255 	case KEY_NET_GET_3:
1256 		xdr_argument = (xdrproc_t)xdr_mechtype;
1257 		xdr_result = xdr_key_netstres3;
1258 		local = __key_net_get_3_svc;
1259 		local_free = __key_net_get_3_svc_free;
1260 		check_auth = 1;
1261 		break;
1262 
1263 	case KEY_GET_CONV_3:
1264 		xdr_argument = (xdrproc_t)xdr_deskeyarg3;
1265 		xdr_result = xdr_cryptkeyres3;
1266 		local = __key_get_conv_3_svc;
1267 		check_auth = 1;
1268 		break;
1269 
1270 	case KEY_CLEAR_3:
1271 		xdr_argument = (xdrproc_t)xdr_void;
1272 		xdr_result = xdr_keystatus;
1273 		local = __key_clear_3_svc;
1274 		check_auth = 1;
1275 		break;
1276 
1277 	default:
1278 		svcerr_noproc(transp);
1279 		return;
1280 	}
1281 	if (check_auth) {
1282 		if (!get_auth(transp, rqstp, &uid)) {
1283 			if (debugging) {
1284 				(void) fprintf(stderr,
1285 					"not local privileged process\n");
1286 			}
1287 			svcerr_weakauth(transp);
1288 			return;
1289 		}
1290 	}
1291 
1292 	memset((char *)&argument, 0, sizeof (argument));
1293 	if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
1294 		svcerr_decode(transp);
1295 		return;
1296 	}
1297 	retval = (*local)(uid, &argument, &result);
1298 	if (retval && !svc_sendreply(transp, xdr_result, (char *)&result)) {
1299 		if (debugging)
1300 			(void) fprintf(stderr, "unable to reply\n");
1301 		svcerr_systemerr(transp);
1302 	}
1303 	if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
1304 		if (debugging)
1305 			(void) fprintf(stderr,
1306 			"unable to free arguments\n");
1307 		exit(1);
1308 	}
1309 	if (local_free) {
1310 		(*local_free)(&result);
1311 	}
1312 }
1313 
1314 static bool_t
1315 get_auth(trans, rqstp, uid)
1316 	SVCXPRT *trans;
1317 	struct svc_req *rqstp;
1318 	uid_t *uid;
1319 {
1320 	svc_local_cred_t cred;
1321 
1322 	if (!svc_get_local_cred(trans, &cred)) {
1323 		if (debugging)
1324 			fprintf(stderr, "svc_get_local_cred failed %s %s\n",
1325 				trans->xp_netid, trans->xp_tp);
1326 		return (FALSE);
1327 	}
1328 	if (debugging)
1329 		fprintf(stderr, "local_uid  %d\n", cred.euid);
1330 	if (rqstp->rq_cred.oa_flavor == AUTH_SYS ||
1331 	    rqstp->rq_cred.oa_flavor == AUTH_LOOPBACK) {
1332 /* LINTED pointer alignment */
1333 		*uid = ((struct authunix_parms *)rqstp->rq_clntcred)->aup_uid;
1334 		return (*uid == cred.euid || cred.euid == 0);
1335 	} else {
1336 		*uid = cred.euid;
1337 		return (TRUE);
1338 	}
1339 }
1340 
1341 static int
1342 get_cache_size(size)
1343 char *size;
1344 {
1345 	int csize, len;
1346 
1347 	len = (int)strlen(size);
1348 	if (len == 0) {
1349 		usage();
1350 	}
1351 
1352 	if (size[len-1] == 'M' || size[len-1] == 'm') {
1353 		/*
1354 		 * cache size in MB
1355 		 */
1356 		size[len-1] = '\0';
1357 		csize = atoi(size);
1358 	} else {
1359 		csize = atoi(size);
1360 		/*
1361 		 * negative size indicates number of entries in cache
1362 		 */
1363 		csize = 0 - csize;
1364 	}
1365 
1366 	if (csize == 0) {
1367 		(void) fprintf(stderr, "invalid cache size: %s\n", size);
1368 		usage();
1369 	}
1370 
1371 	return (csize);
1372 }
1373 
1374 static void
1375 usage()
1376 {
1377 	(void) fprintf(stderr, "usage: \n");
1378 	(void) fprintf(stderr, "keyserv [-c]|[-s ");
1379 	(void) fprintf(stderr, "<size>|<mechtype>=<size>[,...]] [-n] [-D] ");
1380 	(void) fprintf(stderr, "[-d | -e] ");
1381 	(void) fprintf(stderr, "[-t threads]\n");
1382 	(void) fprintf(stderr, "-d disables the use of default keys\n");
1383 	(void) fprintf(stderr, "-e enables the use of default keys\n");
1384 	exit(1);
1385 }
1386 
1387 static void
1388 defaults(void)
1389 {
1390 	register int  flags;
1391 	register char *ptr;
1392 
1393 	if (defopen(defaults_file) == 0) {
1394 		/*
1395 		 * ignore case
1396 		 */
1397 		flags = defcntl(DC_GETFLAGS, 0);
1398 		TURNOFF(flags, DC_CASE);
1399 		defcntl(DC_SETFLAGS, flags);
1400 
1401 		if ((ptr = defread("ENABLE_NOBODY_KEYS=")) != NULL) {
1402 			if (strcasecmp(ptr, "NO") == 0) {
1403 				use_nobody_keys = FALSE;
1404 			}
1405 		}
1406 
1407 		(void) defopen((char *)NULL);
1408 	}
1409 }
1410