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