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