xref: /titanic_50/usr/src/cmd/keyserv/keyserv.c (revision 6e1ae2a33c618c4c2b14aec7d2f21743ddea5837)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 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 /*
41  * keyserv - server for storing private encryption keys
42  *   keyserv(1M) performs multiple functions:  it stores secret keys per uid; it
43  *   performs public key encryption and decryption operations; and it generates
44  *   "random" keys.  keyserv(1M) will talk to no one but a local root process on
45  *   the local transport only.
46  */
47 
48 #include <stdio.h>
49 #include <stdio_ext.h>
50 #include <stdlib.h>
51 #include <sys/types.h>
52 #include <sys/stat.h>
53 #include <sys/uio.h>
54 #include <unistd.h>
55 #include <string.h>
56 #include <deflt.h>
57 #include <rpc/rpc.h>
58 #include <sys/param.h>
59 #include <sys/file.h>
60 #include <sys/resource.h>
61 #include <pwd.h>
62 #include <rpc/des_crypt.h>
63 #include <rpc/key_prot.h>
64 #include <thread.h>
65 #include "rpc/svc_mt.h"
66 #include <rpcsvc/nis_dhext.h>
67 #include <syslog.h>
68 #include <libscf.h>
69 
70 #include "debug.h"
71 #include "keyserv_cache.h"
72 
73 #ifdef KEYSERV_RANDOM
74 extern long random();
75 #endif
76 
77 extern keystatus pk_setkey();
78 extern keystatus pk_encrypt();
79 extern keystatus pk_decrypt();
80 extern keystatus pk_netput();
81 extern keystatus pk_netget();
82 extern keystatus pk_get_conv_key();
83 extern bool_t svc_get_local_cred();
84 
85 extern keystatus pk_setkey3();
86 extern keystatus pk_encrypt3();
87 extern keystatus pk_decrypt3();
88 extern keystatus pk_netput3();
89 extern keystatus pk_netget3();
90 extern keystatus pk_get_conv_key3();
91 extern keystatus pk_clear3();
92 
93 extern int init_mechs();
94 extern int addmasterkey();
95 extern int storeotherrootkeys();
96 extern int setdeskeyarray();
97 
98 extern int getdomainname();
99 
100 static void randomize();
101 static void usage();
102 static void defaults();
103 static int getrootkey();
104 static int get_cache_size(char *);
105 static bool_t get_auth();
106 
107 #ifdef DEBUG
108 extern int test_debug();
109 extern int real_debug();
110 int debugging = 1;
111 #else
112 int debugging = 0;
113 #endif
114 
115 static void keyprogram();
116 static des_block masterkey;
117 char *getenv();
118 static char ROOTKEY[] = "/etc/.rootkey";
119 
120 static char *defaults_file = "/etc/default/keyserv";
121 static int use_nobody_keys = TRUE;
122 
123 /*
124  * Hack to allow the keyserver to use AUTH_DES. The only functions
125  * that get called are key_encryptsession_pk, key_decryptsession_pk,
126  * and key_gendes.
127  *
128  * The approach is to have the keyserver fill in pointers to local
129  * implementations of these functions, and to call those in key_call().
130  */
131 
132 bool_t __key_encrypt_pk_2_svc();
133 bool_t __key_decrypt_pk_2_svc();
134 bool_t __key_gen_1_svc();
135 
136 extern bool_t (*__key_encryptsession_pk_LOCAL)();
137 extern bool_t (*__key_decryptsession_pk_LOCAL)();
138 extern bool_t (*__key_gendes_LOCAL)();
139 
140 static int nthreads = 32;
141 
142 /* Disk caching of common keys on by default */
143 int disk_caching = 1;
144 
145 mechanism_t **mechs;
146 
147 /*
148  * The default size for all types of mech.
149  * positive integers denote multiples of 1MB
150  * negative integers denote number of entries
151  * same goes for non-null entries in cache_size
152  */
153 static int default_cache = 1;
154 
155 int *cache_size;
156 char **cache_options;
157 
158 int
159 main(int argc, char *argv[])
160 {
161 	int sflag = 0, s1flag = 0, s2flag = 0, nflag = 0, dflag = 0, eflag = 0;
162 	char *options, *value;
163 	extern char *optarg;
164 	extern int optind;
165 	int c, d;
166 	struct rlimit rl;
167 	int mode = RPC_SVC_MT_AUTO;
168 	int maxrecsz = RPC_MAXDATASIZE;
169 
170 	void detachfromtty(void);
171 	int setmodulus();
172 	int pk_nodefaultkeys();
173 	int svc_create_local_service();
174 
175 	char domainname[MAXNETNAMELEN + 1];
176 
177 	/*
178 	 * Set our allowed number of file descriptors to the max
179 	 * of what the system will allow, limited by FD_SETSIZE.
180 	 */
181 	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
182 		rlim_t limit;
183 
184 		if ((limit = rl.rlim_max) > FD_SETSIZE)
185 			limit = FD_SETSIZE;
186 		rl.rlim_cur = limit;
187 		(void) setrlimit(RLIMIT_NOFILE, &rl);
188 		(void) enable_extended_FILE_stdio(-1, -1);
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"
264 					    " [-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 "
285 					    "mechtype %s\n", 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 		if (sscanf(line, "%s %d", key, &algtype) < 2) {
528 			/*
529 			 * No encryption algorithm found in the file
530 			 * (algtype) so default to DES.
531 			 */
532 			algtype = AUTH_DES_ALGTYPE;
533 		}
534 		if (!strlen(key))
535 			continue;
536 		addmasterkey(key, name, algtype);
537 	}
538 	fclose(rootkey);
539 	return (1);
540 }
541 
542 /*
543  * Try to get root's secret key, by prompting if terminal is a tty, else trying
544  * from standard input.
545  * Returns 1 on success.
546  */
547 static int
548 getrootkey(master, prompt)
549 	des_block *master;
550 	int prompt;
551 {
552 	char *passwd;
553 	char name[MAXNETNAMELEN + 1];
554 	char secret[HEXKEYBYTES + 1];
555 	FILE *fp;
556 	int passwd2des();
557 	int retval;
558 
559 	randomize(master);
560 	if (!getnetname(name)) {
561 	    (void) fprintf(stderr, "keyserv: \
562 failed to generate host's netname when establishing root's key.\n");
563 	    return (0);
564 	}
565 	if (!prompt) {
566 		return (getotherrootkeys(name));
567 	}
568 	/*
569 	 * Decrypt yellow pages publickey entry to get secret key
570 	 */
571 	passwd = getpass("root password:");
572 	passwd2des(passwd, master);
573 	if (!getsecretkey(name, secret, passwd)) {
574 		(void) fprintf(stderr,
575 		"Can't find %s's secret key\n", name);
576 		return (0);
577 	}
578 	if (secret[0] == 0) {
579 		(void) fprintf(stderr,
580 	"Password does not decrypt secret key for %s\n", name);
581 		return (0);
582 	}
583 	if ((fp = fopen(ROOTKEY, "w")) == NULL) {
584 		(void) fprintf(stderr,
585 			"Cannot open %s for write\n", ROOTKEY);
586 		return (0);
587 	}
588 	retval = storeotherrootkeys(fp, name, passwd, secret);
589 	fclose(fp);
590 	return (retval);
591 }
592 
593 /*
594  * Procedures to implement RPC service.  These procedures are named
595  * differently from the definitions in key_prot.h (generated by rpcgen)
596  * because they take different arguments.
597  */
598 char *
599 strstatus(status)
600 	keystatus status;
601 {
602 	switch (status) {
603 	case KEY_SUCCESS:
604 		return ("KEY_SUCCESS");
605 	case KEY_NOSECRET:
606 		return ("KEY_NOSECRET");
607 	case KEY_UNKNOWN:
608 		return ("KEY_UNKNOWN");
609 	case KEY_SYSTEMERR:
610 		return ("KEY_SYSTEMERR");
611 	case KEY_BADALG:
612 		return ("KEY_BADALG");
613 	case KEY_BADLEN:
614 		return ("KEY_BADLEN");
615 	default:
616 		return ("(bad result code)");
617 	}
618 }
619 
620 bool_t
621 __key_set_1_svc(uid, key, status)
622 	uid_t uid;
623 	keybuf key;
624 	keystatus *status;
625 {
626 	if (debugging) {
627 		(void) fprintf(stderr, "set(%d, %.*s) = ", uid,
628 				sizeof (keybuf), key);
629 	}
630 	*status = pk_setkey(uid, key);
631 	if (debugging) {
632 		(void) fprintf(stderr, "%s\n", strstatus(*status));
633 		(void) fflush(stderr);
634 	}
635 	return (TRUE);
636 }
637 
638 bool_t
639 __key_encrypt_pk_2_svc(uid, arg, res)
640 	uid_t uid;
641 	cryptkeyarg2 *arg;
642 	cryptkeyres *res;
643 {
644 
645 	if (debugging) {
646 		(void) fprintf(stderr, "encrypt(%d, %s, %08x%08x) = ", uid,
647 				arg->remotename, arg->deskey.key.high,
648 				arg->deskey.key.low);
649 	}
650 	res->cryptkeyres_u.deskey = arg->deskey;
651 	res->status = pk_encrypt(uid, arg->remotename, &(arg->remotekey),
652 				&res->cryptkeyres_u.deskey);
653 	if (debugging) {
654 		if (res->status == KEY_SUCCESS) {
655 			(void) fprintf(stderr, "%08x%08x\n",
656 					res->cryptkeyres_u.deskey.key.high,
657 					res->cryptkeyres_u.deskey.key.low);
658 		} else {
659 			(void) fprintf(stderr, "%s\n", strstatus(res->status));
660 		}
661 		(void) fflush(stderr);
662 	}
663 	return (TRUE);
664 }
665 
666 bool_t
667 __key_decrypt_pk_2_svc(uid, arg, res)
668 	uid_t uid;
669 	cryptkeyarg2 *arg;
670 	cryptkeyres *res;
671 {
672 
673 	if (debugging) {
674 		(void) fprintf(stderr, "decrypt(%d, %s, %08x%08x) = ", uid,
675 				arg->remotename, arg->deskey.key.high,
676 				arg->deskey.key.low);
677 	}
678 	res->cryptkeyres_u.deskey = arg->deskey;
679 	res->status = pk_decrypt(uid, arg->remotename, &(arg->remotekey),
680 				&res->cryptkeyres_u.deskey);
681 	if (debugging) {
682 		if (res->status == KEY_SUCCESS) {
683 			(void) fprintf(stderr, "%08x%08x\n",
684 					res->cryptkeyres_u.deskey.key.high,
685 					res->cryptkeyres_u.deskey.key.low);
686 		} else {
687 			(void) fprintf(stderr, "%s\n", strstatus(res->status));
688 		}
689 		(void) fflush(stderr);
690 	}
691 	return (TRUE);
692 }
693 
694 bool_t
695 __key_net_put_2_svc(uid, arg, status)
696 	uid_t uid;
697 	key_netstarg *arg;
698 	keystatus *status;
699 {
700 
701 	if (debugging) {
702 		(void) fprintf(stderr, "net_put(%s, %.*s, %.*s) = ",
703 			arg->st_netname, sizeof (arg->st_pub_key),
704 			arg->st_pub_key, sizeof (arg->st_priv_key),
705 			arg->st_priv_key);
706 	};
707 
708 	*status = pk_netput(uid, arg);
709 
710 	if (debugging) {
711 		(void) fprintf(stderr, "%s\n", strstatus(*status));
712 		(void) fflush(stderr);
713 	}
714 
715 	return (TRUE);
716 }
717 
718 /* ARGSUSED */
719 bool_t
720 __key_net_get_2_svc(uid, arg, keynetname)
721 	uid_t uid;
722 	void *arg;
723 	key_netstres *keynetname;
724 {
725 
726 	if (debugging)
727 		(void) fprintf(stderr, "net_get(%d) = ", uid);
728 
729 	keynetname->status = pk_netget(uid, &keynetname->key_netstres_u.knet);
730 	if (debugging) {
731 		if (keynetname->status == KEY_SUCCESS) {
732 			fprintf(stderr, "<%s, %.*s, %.*s>\n",
733 			keynetname->key_netstres_u.knet.st_netname,
734 			sizeof (keynetname->key_netstres_u.knet.st_pub_key),
735 			keynetname->key_netstres_u.knet.st_pub_key,
736 			sizeof (keynetname->key_netstres_u.knet.st_priv_key),
737 			keynetname->key_netstres_u.knet.st_priv_key);
738 		} else {
739 			(void) fprintf(stderr, "NOT FOUND\n");
740 		}
741 		(void) fflush(stderr);
742 	}
743 
744 	return (TRUE);
745 
746 }
747 
748 bool_t
749 __key_get_conv_2_svc(uid, arg, res)
750 	uid_t uid;
751 	keybuf arg;
752 	cryptkeyres *res;
753 {
754 
755 	if (debugging)
756 		(void) fprintf(stderr, "get_conv(%d, %.*s) = ", uid,
757 			sizeof (arg), arg);
758 
759 
760 	res->status = pk_get_conv_key(uid, arg, res);
761 
762 	if (debugging) {
763 		if (res->status == KEY_SUCCESS) {
764 			(void) fprintf(stderr, "%08x%08x\n",
765 				res->cryptkeyres_u.deskey.key.high,
766 				res->cryptkeyres_u.deskey.key.low);
767 		} else {
768 			(void) fprintf(stderr, "%s\n", strstatus(res->status));
769 		}
770 		(void) fflush(stderr);
771 	}
772 	return (TRUE);
773 }
774 
775 
776 bool_t
777 __key_encrypt_1_svc(uid, arg, res)
778 	uid_t uid;
779 	cryptkeyarg *arg;
780 	cryptkeyres *res;
781 {
782 
783 	if (debugging) {
784 		(void) fprintf(stderr, "encrypt(%d, %s, %08x%08x) = ", uid,
785 				arg->remotename, arg->deskey.key.high,
786 				arg->deskey.key.low);
787 	}
788 	res->cryptkeyres_u.deskey = arg->deskey;
789 	res->status = pk_encrypt(uid, arg->remotename, NULL,
790 				&res->cryptkeyres_u.deskey);
791 	if (debugging) {
792 		if (res->status == KEY_SUCCESS) {
793 			(void) fprintf(stderr, "%08x%08x\n",
794 					res->cryptkeyres_u.deskey.key.high,
795 					res->cryptkeyres_u.deskey.key.low);
796 		} else {
797 			(void) fprintf(stderr, "%s\n", strstatus(res->status));
798 		}
799 		(void) fflush(stderr);
800 	}
801 	return (TRUE);
802 }
803 
804 bool_t
805 __key_decrypt_1_svc(uid, arg, res)
806 	uid_t uid;
807 	cryptkeyarg *arg;
808 	cryptkeyres *res;
809 {
810 	if (debugging) {
811 		(void) fprintf(stderr, "decrypt(%d, %s, %08x%08x) = ", uid,
812 				arg->remotename, arg->deskey.key.high,
813 				arg->deskey.key.low);
814 	}
815 	res->cryptkeyres_u.deskey = arg->deskey;
816 	res->status = pk_decrypt(uid, arg->remotename, NULL,
817 				&res->cryptkeyres_u.deskey);
818 	if (debugging) {
819 		if (res->status == KEY_SUCCESS) {
820 			(void) fprintf(stderr, "%08x%08x\n",
821 					res->cryptkeyres_u.deskey.key.high,
822 					res->cryptkeyres_u.deskey.key.low);
823 		} else {
824 			(void) fprintf(stderr, "%s\n", strstatus(res->status));
825 		}
826 		(void) fflush(stderr);
827 	}
828 	return (TRUE);
829 }
830 
831 /* ARGSUSED */
832 bool_t
833 __key_gen_1_svc(v, s, key)
834 	void *v;
835 	struct svc_req *s;
836 	des_block *key;
837 {
838 	struct timeval time;
839 	static des_block keygen;
840 	static mutex_t keygen_mutex = DEFAULTMUTEX;
841 	int r;
842 
843 	(void) gettimeofday(&time, (struct timezone *)NULL);
844 	(void) mutex_lock(&keygen_mutex);
845 	keygen.key.high += (time.tv_sec ^ time.tv_usec);
846 	keygen.key.low += (time.tv_sec ^ time.tv_usec);
847 	r = ecb_crypt((char *)&masterkey, (char *)&keygen, sizeof (keygen),
848 		DES_ENCRYPT | DES_HW);
849 	if (r != DESERR_NONE && r != DESERR_NOHWDEVICE) {
850 		mutex_unlock(&keygen_mutex);
851 		return (FALSE);
852 	}
853 	*key = keygen;
854 	mutex_unlock(&keygen_mutex);
855 
856 	des_setparity_g(key);
857 	if (debugging) {
858 		(void) fprintf(stderr, "gen() = %08x%08x\n", key->key.high,
859 					key->key.low);
860 		(void) fflush(stderr);
861 	}
862 	return (TRUE);
863 }
864 
865 /* ARGSUSED */
866 bool_t
867 __key_getcred_1_svc(uid, name, res)
868 	uid_t uid;
869 	netnamestr *name;
870 	getcredres *res;
871 {
872 	struct unixcred *cred;
873 
874 	cred = &res->getcredres_u.cred;
875 	if (!netname2user(*name, (uid_t *)&cred->uid, (gid_t *)&cred->gid,
876 			(int *)&cred->gids.gids_len,
877 					(gid_t *)cred->gids.gids_val)) {
878 		res->status = KEY_UNKNOWN;
879 	} else {
880 		res->status = KEY_SUCCESS;
881 	}
882 	if (debugging) {
883 		(void) fprintf(stderr, "getcred(%s) = ", *name);
884 		if (res->status == KEY_SUCCESS) {
885 			(void) fprintf(stderr, "uid=%d, gid=%d, grouplen=%d\n",
886 				cred->uid, cred->gid, cred->gids.gids_len);
887 		} else {
888 			(void) fprintf(stderr, "%s\n", strstatus(res->status));
889 		}
890 		(void) fflush(stderr);
891 	}
892 	return (TRUE);
893 }
894 
895 /*
896  * Version 3 procedures follow...
897  */
898 
899 static bool_t
900 __key_set_3_svc(uid_t uid, setkeyarg3 *arg, keystatus *status)
901 {
902 	debug(KEYSERV_DEBUG, ("__key_set_3_svc(%d, %d, %d)",
903 	    uid, arg->algtype, arg->keylen));
904 	*status = pk_setkey3(uid, arg);
905 	debug(KEYSERV_DEBUG, ("__key_set_3_svc %s", strstatus(*status)));
906 	return (TRUE);
907 }
908 
909 static bool_t
910 __key_encrypt_3_svc(uid_t uid, cryptkeyarg3 *arg, cryptkeyres3 *res)
911 {
912 	int len, i;
913 	des_block *dp;
914 
915 	debug(KEYSERV_DEBUG, ("encrypt_3(%d %d %s)", uid,
916 	    arg->deskey.deskeyarray_len, arg->remotename));
917 	res->status = pk_encrypt3(uid, arg, &res->cryptkeyres3_u.deskey);
918 	len = res->cryptkeyres3_u.deskey.deskeyarray_len;
919 	dp = res->cryptkeyres3_u.deskey.deskeyarray_val;
920 	for (i = 0; i < len; i++) {
921 		debug(KEYSERV_DEBUG0, ("encrypt_3 retval[%d] == (%x,%x)",
922 		    i, dp->key.high, dp->key.low));
923 		dp++;
924 	}
925 	debug(KEYSERV_DEBUG, ("encrypt_3 returned %s", strstatus(res->status)));
926 	return (TRUE);
927 }
928 
929 static bool_t
930 __key_decrypt_3_svc(uid_t uid, cryptkeyarg3 *arg, cryptkeyres3 *res)
931 {
932 	int len, i;
933 	des_block *dp;
934 
935 	debug(KEYSERV_DEBUG, ("decrypt_3(%d, %d, %s)", uid,
936 	    arg->deskey.deskeyarray_len, arg->remotename));
937 	res->status = pk_decrypt3(uid, arg, &res->cryptkeyres3_u.deskey);
938 	len = res->cryptkeyres3_u.deskey.deskeyarray_len;
939 	dp = res->cryptkeyres3_u.deskey.deskeyarray_val;
940 	for (i = 0; i < len; i++) {
941 		debug(KEYSERV_DEBUG0, ("decrypt_3 retval[%d] == (%x,%x)",
942 		    i, dp->key.high, dp->key.low));
943 		dp++;
944 	}
945 	debug(KEYSERV_DEBUG, ("decrypt_3 returned %s", strstatus(res->status)));
946 	return (TRUE);
947 }
948 
949 /* ARGSUSED */
950 static bool_t
951 __key_gen_3_svc(void *v, keynum_t *kp, deskeyarray *res)
952 {
953 	int i;
954 	keynum_t keynum = *kp;
955 
956 	debug(KEYSERV_DEBUG, ("gen_3(%d %x)", keynum, res));
957 	res->deskeyarray_val = 0;
958 	if (!setdeskeyarray(res, keynum)) {
959 		return (FALSE);
960 	}
961 	for (i = 0; i < keynum; i++) {
962 		debug(KEYSERV_DEBUG, ("gen_3 calling gen_1 %x",
963 		    res->deskeyarray_val+i));
964 		__key_gen_1_svc((void *) NULL, (struct svc_req *)NULL,
965 		    res->deskeyarray_val+i);
966 		debug(KEYSERV_DEBUG, ("gen_3 val %d %x",
967 		    i, *(int *)(res->deskeyarray_val+i)));
968 	}
969 	return (TRUE);
970 }
971 
972 static void
973 __key_gen_3_svc_free(deskeyarray *dp)
974 {
975 	free(dp->deskeyarray_val);
976 }
977 
978 static bool_t
979 __key_getcred_3_svc(uid_t uid, netnamestr *name, getcredres3 *res)
980 {
981 	return (__key_getcred_1_svc(uid, name, (getcredres *)res));
982 }
983 
984 static bool_t
985 __key_encrypt_pk_3_svc(uid_t uid, cryptkeyarg3 *arg, cryptkeyres3 *res)
986 {
987 	debug(KEYSERV_DEBUG, ("encrypt_pk_3(%d, %s)", uid, arg->remotename));
988 	res->status = pk_encrypt3(uid, arg, &res->cryptkeyres3_u.deskey);
989 	debug(KEYSERV_DEBUG, ("encrypt returned %s", strstatus(res->status)));
990 	return (TRUE);
991 }
992 
993 static void
994 __key_encrypt_pk_3_svc_free(cryptkeyres3 *res)
995 {
996 	if (res->status == KEY_SUCCESS) {
997 		free(res->cryptkeyres3_u.deskey.deskeyarray_val);
998 	}
999 }
1000 
1001 static bool_t
1002 __key_decrypt_pk_3(uid_t uid, cryptkeyarg3 *arg, cryptkeyres3 *res)
1003 {
1004 	debug(KEYSERV_DEBUG, ("decrypt_pk_3(%d, %s)", uid, arg->remotename));
1005 	res->status = pk_decrypt3(uid, arg, &res->cryptkeyres3_u.deskey);
1006 	debug(KEYSERV_DEBUG, ("encrypt returned %s", strstatus(res->status)));
1007 	return (TRUE);
1008 }
1009 
1010 static void
1011 __key_decrypt_pk_3_free(cryptkeyres3 *res)
1012 {
1013 	if (res->status == KEY_SUCCESS) {
1014 		free(res->cryptkeyres3_u.deskey.deskeyarray_val);
1015 	}
1016 }
1017 
1018 static bool_t
1019 __key_net_put_3_svc(uid_t uid, key_netstarg3 *arg, keystatus *status)
1020 {
1021 	debug(KEYSERV_DEBUG, ("net_put_3 (%d, %x)", uid, arg));
1022 	*status = pk_netput3(uid, arg);
1023 	debug(KEYSERV_DEBUG, ("net_put_3 ret %s", strstatus(*status)));
1024 	return (TRUE);
1025 }
1026 
1027 static bool_t
1028 __key_net_get_3_svc(uid_t uid, mechtype *arg, key_netstres3 *keynetname)
1029 {
1030 	debug(KEYSERV_DEBUG, ("net_get_3 (%d, %x)", uid, arg));
1031 	keynetname->status = pk_netget3(uid,
1032 	    arg, &keynetname->key_netstres3_u.knet);
1033 	debug(KEYSERV_DEBUG,
1034 	    ("net_get_3 ret %s", strstatus(keynetname->status)));
1035 	return (TRUE);
1036 }
1037 
1038 static void
1039 __key_net_get_3_svc_free(key_netstres3 *keynetname)
1040 {
1041 	if (keynetname->status == KEY_SUCCESS) {
1042 		free(keynetname->key_netstres3_u.knet.st_priv_key.keybuf3_val);
1043 		free(keynetname->key_netstres3_u.knet.st_pub_key.keybuf3_val);
1044 		free(keynetname->key_netstres3_u.knet.st_netname);
1045 	}
1046 }
1047 
1048 static bool_t
1049 __key_get_conv_3_svc(uid_t uid, deskeyarg3 *arg, cryptkeyres3 *res)
1050 {
1051 	debug(KEYSERV_DEBUG, ("get_conv_3(%d %x %x)", uid, arg, res));
1052 	res->status = pk_get_conv_key3(uid, arg, res);
1053 	debug(KEYSERV_DEBUG,
1054 	    ("get_conv_3 ret %s", strstatus(res->status)));
1055 	return (TRUE);
1056 }
1057 
1058 /* ARGSUSED */
1059 static bool_t
1060 __key_clear_3_svc(uid_t uid, void *arg, keystatus *status)
1061 {
1062 	debug(KEYSERV_DEBUG, ("clear_3(%d)", uid));
1063 	*status = pk_clear3(uid);
1064 	debug(KEYSERV_DEBUG, ("clear_3 ret %s", strstatus(*status)));
1065 	return (TRUE);
1066 }
1067 
1068 /*
1069  * RPC boilerplate
1070  */
1071 static void
1072 keyprogram(rqstp, transp)
1073 	struct svc_req *rqstp;
1074 	SVCXPRT *transp;
1075 {
1076 	union {
1077 		keybuf key_set_1_arg;
1078 		cryptkeyarg key_encrypt_1_arg;
1079 		cryptkeyarg key_decrypt_1_arg;
1080 		netnamestr key_getcred_1_arg;
1081 		cryptkeyarg key_encrypt_2_arg;
1082 		cryptkeyarg key_decrypt_2_arg;
1083 		netnamestr key_getcred_2_arg;
1084 		cryptkeyarg2 key_encrypt_pk_2_arg;
1085 		cryptkeyarg2 key_decrypt_pk_2_arg;
1086 		key_netstarg key_net_put_2_arg;
1087 		netobj  key_get_conv_2_arg;
1088 		keybuf3 key_set_3_arg;
1089 		cryptkeyarg3 key_encrypt_3_arg;
1090 		cryptkeyarg3 key_decrypt_3_arg;
1091 		cryptkeyarg3 key_encrypt_pk_3_arg;
1092 		cryptkeyarg3 key_decrypt_pk_3_arg;
1093 		keynum_t key_gen_3_arg;
1094 		netnamestr key_getcred_3_arg;
1095 		key_netstarg3 key_net_put_3_arg;
1096 		key_netstarg3 key_net_get_3_arg;
1097 		deskeyarg3 key_get_conv_3_arg;
1098 	} argument;
1099 	union {
1100 		keystatus status;
1101 		cryptkeyres cres;
1102 		des_block key;
1103 		getcredres gres;
1104 		key_netstres keynetname;
1105 		cryptkeyres3 cres3;
1106 		deskeyarray keyarray;
1107 		getcredres3 gres3;
1108 		key_netstres3 keynetname3;
1109 	} result;
1110 	uint_t gids[MAXGIDS];
1111 	char netname_str[MAXNETNAMELEN + 1];
1112 	bool_t (*xdr_argument)(), (*xdr_result)();
1113 	bool_t (*local)();
1114 	void (*local_free)() = NULL;
1115 	bool_t retval;
1116 	uid_t uid;
1117 	int check_auth;
1118 
1119 	switch (rqstp->rq_proc) {
1120 	case NULLPROC:
1121 		svc_sendreply(transp, xdr_void, (char *)NULL);
1122 		return;
1123 
1124 	case KEY_SET:
1125 		xdr_argument = xdr_keybuf;
1126 		xdr_result = xdr_int;
1127 		local = __key_set_1_svc;
1128 		check_auth = 1;
1129 		break;
1130 
1131 	case KEY_ENCRYPT:
1132 		xdr_argument = xdr_cryptkeyarg;
1133 		xdr_result = xdr_cryptkeyres;
1134 		local = __key_encrypt_1_svc;
1135 		check_auth = 1;
1136 		break;
1137 
1138 	case KEY_DECRYPT:
1139 		xdr_argument = xdr_cryptkeyarg;
1140 		xdr_result = xdr_cryptkeyres;
1141 		local = __key_decrypt_1_svc;
1142 		check_auth = 1;
1143 		break;
1144 
1145 	case KEY_GEN:
1146 		xdr_argument = xdr_void;
1147 		xdr_result = xdr_des_block;
1148 		local = __key_gen_1_svc;
1149 		check_auth = 0;
1150 		break;
1151 
1152 	case KEY_GETCRED:
1153 		xdr_argument = xdr_netnamestr;
1154 		xdr_result = xdr_getcredres;
1155 		local = __key_getcred_1_svc;
1156 		result.gres.getcredres_u.cred.gids.gids_val = gids;
1157 		check_auth = 0;
1158 		break;
1159 
1160 	case KEY_ENCRYPT_PK:
1161 		xdr_argument = xdr_cryptkeyarg2;
1162 		xdr_result = xdr_cryptkeyres;
1163 		local = __key_encrypt_pk_2_svc;
1164 		check_auth = 1;
1165 		break;
1166 
1167 	case KEY_DECRYPT_PK:
1168 		xdr_argument = xdr_cryptkeyarg2;
1169 		xdr_result = xdr_cryptkeyres;
1170 		local = __key_decrypt_pk_2_svc;
1171 		check_auth = 1;
1172 		break;
1173 
1174 
1175 	case KEY_NET_PUT:
1176 		xdr_argument = xdr_key_netstarg;
1177 		xdr_result = xdr_keystatus;
1178 		local = __key_net_put_2_svc;
1179 		check_auth = 1;
1180 		break;
1181 
1182 	case KEY_NET_GET:
1183 		xdr_argument = (xdrproc_t)xdr_void;
1184 		xdr_result = xdr_key_netstres;
1185 		local = __key_net_get_2_svc;
1186 		result.keynetname.key_netstres_u.knet.st_netname = netname_str;
1187 		check_auth = 1;
1188 		break;
1189 
1190 	case KEY_GET_CONV:
1191 		xdr_argument = (xdrproc_t)xdr_keybuf;
1192 		xdr_result = xdr_cryptkeyres;
1193 		local = __key_get_conv_2_svc;
1194 		check_auth = 1;
1195 		break;
1196 
1197 	/*
1198 	 * Version 3 procedures follow...
1199 	 */
1200 
1201 	case KEY_SET_3:
1202 		xdr_argument = (xdrproc_t)xdr_setkeyarg3;
1203 		xdr_result = xdr_keystatus;
1204 		local = __key_set_3_svc;
1205 		check_auth = 1;
1206 		break;
1207 
1208 	case KEY_ENCRYPT_3:
1209 		xdr_argument = (xdrproc_t)xdr_cryptkeyarg3;
1210 		xdr_result = xdr_cryptkeyres3;
1211 		local = __key_encrypt_3_svc;
1212 		check_auth = 1;
1213 		break;
1214 
1215 	case KEY_DECRYPT_3:
1216 		xdr_argument = (xdrproc_t)xdr_cryptkeyarg3;
1217 		xdr_result = xdr_cryptkeyres3;
1218 		local = __key_decrypt_3_svc;
1219 		check_auth = 1;
1220 		break;
1221 
1222 	case KEY_GEN_3:
1223 		xdr_argument = (xdrproc_t)xdr_keynum_t;
1224 		xdr_result = xdr_deskeyarray;
1225 		local = __key_gen_3_svc;
1226 		local_free = __key_gen_3_svc_free;
1227 		check_auth = 0;
1228 		break;
1229 
1230 	case KEY_GETCRED_3:
1231 		xdr_argument = (xdrproc_t)xdr_netnamestr;
1232 		xdr_result = xdr_getcredres3;
1233 		local = __key_getcred_3_svc;
1234 		check_auth = 0;
1235 		break;
1236 
1237 	case KEY_ENCRYPT_PK_3:
1238 		xdr_argument = (xdrproc_t)xdr_cryptkeyarg3;
1239 		xdr_result = xdr_cryptkeyres3;
1240 		local = __key_encrypt_pk_3_svc;
1241 		local_free = __key_encrypt_pk_3_svc_free;
1242 		check_auth = 1;
1243 		break;
1244 
1245 	case KEY_DECRYPT_PK_3:
1246 		xdr_argument = (xdrproc_t)xdr_cryptkeyarg3;
1247 		xdr_result = xdr_cryptkeyres3;
1248 		local = __key_decrypt_pk_3;
1249 		local_free = __key_decrypt_pk_3_free;
1250 		check_auth = 1;
1251 		break;
1252 
1253 	case KEY_NET_PUT_3:
1254 		xdr_argument = (xdrproc_t)xdr_key_netstarg3;
1255 		xdr_result = xdr_keystatus;
1256 		local = __key_net_put_3_svc;
1257 		check_auth = 1;
1258 		break;
1259 
1260 	case KEY_NET_GET_3:
1261 		xdr_argument = (xdrproc_t)xdr_mechtype;
1262 		xdr_result = xdr_key_netstres3;
1263 		local = __key_net_get_3_svc;
1264 		local_free = __key_net_get_3_svc_free;
1265 		check_auth = 1;
1266 		break;
1267 
1268 	case KEY_GET_CONV_3:
1269 		xdr_argument = (xdrproc_t)xdr_deskeyarg3;
1270 		xdr_result = xdr_cryptkeyres3;
1271 		local = __key_get_conv_3_svc;
1272 		check_auth = 1;
1273 		break;
1274 
1275 	case KEY_CLEAR_3:
1276 		xdr_argument = (xdrproc_t)xdr_void;
1277 		xdr_result = xdr_keystatus;
1278 		local = __key_clear_3_svc;
1279 		check_auth = 1;
1280 		break;
1281 
1282 	default:
1283 		svcerr_noproc(transp);
1284 		return;
1285 	}
1286 	if (check_auth) {
1287 		if (!get_auth(transp, rqstp, &uid)) {
1288 			if (debugging) {
1289 				(void) fprintf(stderr,
1290 					"not local privileged process\n");
1291 			}
1292 			svcerr_weakauth(transp);
1293 			return;
1294 		}
1295 	}
1296 
1297 	memset((char *)&argument, 0, sizeof (argument));
1298 	if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
1299 		svcerr_decode(transp);
1300 		return;
1301 	}
1302 	retval = (*local)(uid, &argument, &result);
1303 	if (retval && !svc_sendreply(transp, xdr_result, (char *)&result)) {
1304 		if (debugging)
1305 			(void) fprintf(stderr, "unable to reply\n");
1306 		svcerr_systemerr(transp);
1307 	}
1308 	if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
1309 		if (debugging)
1310 			(void) fprintf(stderr,
1311 			"unable to free arguments\n");
1312 		exit(1);
1313 	}
1314 	if (local_free) {
1315 		(*local_free)(&result);
1316 	}
1317 }
1318 
1319 static bool_t
1320 get_auth(trans, rqstp, uid)
1321 	SVCXPRT *trans;
1322 	struct svc_req *rqstp;
1323 	uid_t *uid;
1324 {
1325 	svc_local_cred_t cred;
1326 
1327 	if (!svc_get_local_cred(trans, &cred)) {
1328 		if (debugging)
1329 			fprintf(stderr, "svc_get_local_cred failed %s %s\n",
1330 				trans->xp_netid, trans->xp_tp);
1331 		return (FALSE);
1332 	}
1333 	if (debugging)
1334 		fprintf(stderr, "local_uid  %d\n", cred.euid);
1335 	if (rqstp->rq_cred.oa_flavor == AUTH_SYS ||
1336 	    rqstp->rq_cred.oa_flavor == AUTH_LOOPBACK) {
1337 /* LINTED pointer alignment */
1338 		*uid = ((struct authunix_parms *)rqstp->rq_clntcred)->aup_uid;
1339 		return (*uid == cred.euid || cred.euid == 0);
1340 	} else {
1341 		*uid = cred.euid;
1342 		return (TRUE);
1343 	}
1344 }
1345 
1346 static int
1347 get_cache_size(size)
1348 char *size;
1349 {
1350 	int csize, len;
1351 
1352 	len = (int)strlen(size);
1353 	if (len == 0) {
1354 		usage();
1355 	}
1356 
1357 	if (size[len-1] == 'M' || size[len-1] == 'm') {
1358 		/*
1359 		 * cache size in MB
1360 		 */
1361 		size[len-1] = '\0';
1362 		csize = atoi(size);
1363 	} else {
1364 		csize = atoi(size);
1365 		/*
1366 		 * negative size indicates number of entries in cache
1367 		 */
1368 		csize = 0 - csize;
1369 	}
1370 
1371 	if (csize == 0) {
1372 		(void) fprintf(stderr, "invalid cache size: %s\n", size);
1373 		usage();
1374 	}
1375 
1376 	return (csize);
1377 }
1378 
1379 static void
1380 usage()
1381 {
1382 	(void) fprintf(stderr, "usage: \n");
1383 	(void) fprintf(stderr, "keyserv [-c]|[-s ");
1384 	(void) fprintf(stderr, "<size>|<mechtype>=<size>[,...]] [-n] [-D] ");
1385 	(void) fprintf(stderr, "[-d | -e] ");
1386 	(void) fprintf(stderr, "[-t threads]\n");
1387 	(void) fprintf(stderr, "-d disables the use of default keys\n");
1388 	(void) fprintf(stderr, "-e enables the use of default keys\n");
1389 	exit(1);
1390 }
1391 
1392 static void
1393 defaults(void)
1394 {
1395 	register int  flags;
1396 	register char *ptr;
1397 
1398 	if (defopen(defaults_file) == 0) {
1399 		/*
1400 		 * ignore case
1401 		 */
1402 		flags = defcntl(DC_GETFLAGS, 0);
1403 		TURNOFF(flags, DC_CASE);
1404 		(void) defcntl(DC_SETFLAGS, flags);
1405 
1406 		if ((ptr = defread("ENABLE_NOBODY_KEYS=")) != NULL) {
1407 			if (strcasecmp(ptr, "NO") == 0) {
1408 				use_nobody_keys = FALSE;
1409 			}
1410 		}
1411 
1412 		(void) defopen((char *)NULL);
1413 	}
1414 }
1415