xref: /illumos-gate/usr/src/cmd/keyserv/setkey.c (revision 028c45646327b08802a29b76d1abea8907a57f17)
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 /*
28  * University Copyright- Copyright (c) 1982, 1986, 1988
29  * The Regents of the University of California
30  * All Rights Reserved
31  *
32  * University Acknowledgment- Portions of this document are derived from
33  * software developed by the University of California, Berkeley, and its
34  * contributors.
35  */
36 
37 /*
38  * Do the real work of the keyserver.
39  * Store secret keys. Compute common keys,
40  * and use them to decrypt and encrypt DES keys.
41  * Cache the common keys, so the expensive computation is avoided.
42  */
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <mp.h>
46 #include <rpc/rpc.h>
47 #include <rpc/key_prot.h>
48 #include <rpc/des_crypt.h>
49 #include <rpcsvc/nis_dhext.h>
50 #include <sys/errno.h>
51 #include <string.h>
52 #include <thread.h>
53 #include <syslog.h>
54 
55 #include "debug.h"
56 #include "keyserv_cache.h"
57 
58 extern char ROOTKEY[];
59 extern mechanism_t **mechs;
60 extern char **cache_options;
61 extern int *cache_size;
62 extern int disk_caching;
63 
64 static MINT *MODULUS;
65 static int hash_keys();
66 static keystatus pk_crypt();
67 static keystatus pk_crypt3();
68 static int nodefaultkeys = 0;
69 
70 #define	DES		"des"
71 #define	DESALIAS	"dh192-0"
72 #define	DHMECHSTR	"diffie_hellman"
73 #define	CLASSIC_PK_DH(k, a)	(((k) == 192) && ((a) == 0))
74 
75 /*
76  * Exponential caching management
77  */
78 struct cachekey_list {
79 	keybuf secret;
80 	keybuf public;
81 	des_block deskey;
82 	struct cachekey_list *next;
83 };
84 #define	KEY_HASH_SIZE	256
85 static struct cachekey_list *g_cachedkeys[KEY_HASH_SIZE];
86 static rwlock_t g_cachedkeys_lock = DEFAULTRWLOCK;
87 
88 #ifdef DEBUG
89 int
90 test_debug(debug_level level, char *file, int line)
91 {
92 	if (level < debugging)
93 		return (0);
94 	fprintf(stderr, "file %s,\tline %d :\t", file, line);
95 	return (1);
96 }
97 
98 int
99 real_debug(char *fmt, ...)
100 {
101 	va_list args;
102 
103 	va_start(args, fmt);
104 	(void) vfprintf(stderr, fmt, args);
105 	va_end(args);
106 	fprintf(stderr, "\n");
107 	fflush(stderr);
108 	return (1);
109 }
110 #endif /* DEBUG */
111 
112 struct cacheuid_list {
113 	uid_t uid;
114 	int refcnt;
115 	keybuf3 *secretkey;
116 	keybuf3 *publickey;
117 	netnamestr netname;
118 	des_block key;
119 	struct cacheuid_list *next;
120 };
121 
122 #define	NUMHASHBUCKETS	256
123 #define	HASH_UID(x) (x & 0xff)
124 
125 struct mechdata {
126 	struct cacheuid_list *bucket[NUMHASHBUCKETS];
127 };
128 
129 struct psdata {
130 	struct cachekey3_list *common[NUMHASHBUCKETS];
131 };
132 
133 struct mechentry {
134 	mutex_t mech_lock;
135 	struct mechdata *mechdata;
136 	mutex_t ps_lock;
137 	struct psdata *psdata;
138 };
139 
140 /*
141  * we don't need to worry about locking for the keylen + algtype
142  * sparse array because it is created once and for all during
143  * initialization when there are no threads. The mechentry field
144  * and everything underneath it needs protection and this is what
145  * the *_lock fields are for.
146  */
147 struct algtypelist {
148 	algtype_t algtype;
149 	struct algtypelist *next;
150 	struct mechentry mech;
151 };
152 
153 struct keylenlist {
154 	keylen_t keylen;
155 	struct algtypelist *ap;
156 	struct keylenlist *next;
157 };
158 
159 #define	KEYSERV_VERSION	"1.0"
160 
161 static struct mechtable {
162 	char *version;
163 	struct keylenlist *kp;
164 } mechtable = {KEYSERV_VERSION, NULL};
165 
166 static struct keylenlist **
167 getkeylen(keylen_t k)
168 {
169 	struct keylenlist **kpp;
170 
171 	debug(KEYSERV_DEBUG1, ("getkeylen key: %d", k));
172 	for (kpp = &mechtable.kp;
173 		*kpp != NULL && (*kpp)->keylen != k;
174 		kpp = &(*kpp)->next)
175 		debug(KEYSERV_DEBUG0, ("getkeylen failed %x", kpp));
176 	debug(KEYSERV_DEBUG0, ("getkeylen return: %x", kpp));
177 	return (kpp);
178 }
179 
180 static void
181 appendkeylist(struct keylenlist **kpp, keylen_t k)
182 {
183 	struct keylenlist *kp;
184 
185 	if (*kpp == NULL) {
186 		kp = (struct keylenlist *)malloc(sizeof (*kp));
187 		if (kp == NULL) {
188 			debug(KEYSERV_INFO, ("appendkeylist : malloc failed"));
189 			return;
190 		}
191 		debug(KEYSERV_DEBUG, ("appendkeylist : %x %x %d", kpp, kp, k));
192 		kp->keylen = k;
193 		kp->ap = NULL;
194 		kp->next = NULL;
195 		*kpp = kp;
196 	} else {
197 		/*EMPTY*/
198 		/* do nothing; only happens for multiple algtypes */
199 		debug(KEYSERV_DEBUG0,
200 			("appendkeylist called for non tail element"));
201 	}
202 }
203 
204 static struct algtypelist **
205 getalgtype(struct keylenlist **kpp, algtype_t a)
206 {
207 	struct algtypelist **app;
208 
209 	debug(KEYSERV_DEBUG1, ("getalgtype key: %d", a));
210 	for (app = &(*kpp)->ap;
211 		*app != NULL && (*app)->algtype != a;
212 		app = &(*app)->next)
213 		debug(KEYSERV_DEBUG0, ("getalgtype key: %x", app));
214 	debug(KEYSERV_DEBUG0, ("getalgtype return: %x", app));
215 	return (app);
216 }
217 
218 static void
219 appendalgtype(struct algtypelist **app, algtype_t a)
220 {
221 	struct algtypelist *ap;
222 
223 	if (*app == NULL) {
224 		ap = (struct algtypelist *)malloc(sizeof (*ap));
225 		if (ap == NULL) {
226 			debug(KEYSERV_INFO, ("appendalgtype : malloc failed"));
227 			return;
228 		}
229 		debug(KEYSERV_DEBUG, ("appendalgtype : %x %x %d", app, ap, a));
230 		ap->algtype = a;
231 		mutex_init(&ap->mech.mech_lock, USYNC_THREAD, NULL);
232 		mutex_init(&ap->mech.ps_lock, USYNC_THREAD, NULL);
233 		ap->mech.mechdata = NULL;
234 		ap->mech.psdata = NULL;
235 		ap->next = NULL;
236 		*app = ap;
237 	} else {
238 		/*EMPTY*/
239 		/* don't mind duplicate (keylen,algtype) paris for now. */
240 		debug(KEYSERV_DEBUG0,
241 			("appendalgtype called for non tail element"));
242 	}
243 }
244 
245 static struct mechentry *
246 getmechtype(keylen_t k, algtype_t a)
247 {
248 	struct keylenlist **kpp;
249 	struct algtypelist **app;
250 
251 	debug(KEYSERV_DEBUG1, ("getmechtype %d %d", k, a));
252 	kpp = getkeylen(k);
253 	if (*kpp == NULL) {
254 		debug(KEYSERV_DEBUG0, ("getmechtype %d not found in keys", k));
255 		return (0);
256 	}
257 	app = getalgtype(kpp, a);
258 	if (*app == NULL) {
259 		debug(KEYSERV_DEBUG0, ("getmechtype %d not found in algs", a));
260 		return (0);
261 	}
262 	debug(KEYSERV_DEBUG0, ("getmechtype found %x", app));
263 	debug(KEYSERV_DEBUG0, ("getmechtype return %x", &(*app)->mech));
264 	return (&(*app)->mech);
265 }
266 
267 static keybuf3 *
268 getkeybuf3(int k)
269 {
270 	keybuf3 *buf;
271 
272 	debug(KEYSERV_DEBUG, ("getkeybuf3 malloc %d", k));
273 	buf = (keybuf3 *) malloc(sizeof (*buf));
274 	if (buf == NULL) {
275 		debug(KEYSERV_DEBUG, ("getkeybuf3 malloc failed"));
276 		syslog(LOG_ERR, "file %s line %d: malloc failed",
277 			__FILE__, __LINE__);
278 		return (NULL);
279 	}
280 	buf->keybuf3_len = k;
281 	/* XXX special case k==0 */
282 	if (k == 0) {
283 		buf->keybuf3_val = NULL;
284 	} else {
285 		buf->keybuf3_val = (char *)malloc(k);
286 		if (buf->keybuf3_val == NULL) {
287 			debug(KEYSERV_DEBUG, ("getkeybuf3 malloc failed"));
288 			free(buf);
289 			syslog(LOG_ERR, "file %s line %d: malloc failed",
290 				__FILE__, __LINE__);
291 			return (NULL);
292 		}
293 	}
294 	debug(KEYSERV_DEBUG1, ("getkeybuf3 ret %x", buf));
295 	return (buf);
296 }
297 
298 static void
299 freekeybuf3(keybuf3 *kp)
300 {
301 	debug(KEYSERV_DEBUG1, ("freekeybuf3 %x", kp));
302 	if (kp == NULL)
303 		return;
304 	if (kp->keybuf3_val) {
305 		/* XXX kp->keybuf3_len != 0? */
306 		free(kp->keybuf3_val);
307 	}
308 	free(kp);
309 }
310 
311 static keybuf3 *
312 cpykeybuf3(keybuf3 *src)
313 {
314 	keybuf3 *dst;
315 
316 	if (src == NULL) {
317 		return (NULL);
318 	}
319 	if ((dst = getkeybuf3(src->keybuf3_len)) == NULL) {
320 		return (NULL);
321 	}
322 	memcpy(dst->keybuf3_val, src->keybuf3_val, src->keybuf3_len);
323 	debug(KEYSERV_DEBUG0, ("cpykeybuf3 ret %x", dst));
324 	return (dst);
325 }
326 
327 static keybuf3 *
328 setkeybuf3(char *src, int len)
329 {
330 	keybuf3 *dst;
331 
332 	if ((dst = getkeybuf3(++len)) == NULL) {
333 		return (NULL);
334 	}
335 	memcpy(dst->keybuf3_val, src, len);
336 	return (dst);
337 }
338 
339 static int
340 cmpkeybuf3(keybuf3 *k1, keybuf3 *k2)
341 {
342 	if ((k1 == NULL) || (k2 == NULL)) {
343 		syslog(LOG_ERR, "cmpkeybuf3: invalid parameter: %x, %x",
344 			k1, k2);
345 		return (0);
346 	}
347 	if (k1->keybuf3_len != k2->keybuf3_len) {
348 		return (0);
349 	}
350 	return (!memcmp(k1->keybuf3_val, k2->keybuf3_val, k1->keybuf3_len));
351 }
352 
353 static int
354 storekeybuf3(keybuf3 *dst, keybuf3 *src)
355 {
356 	keybuf3 *tmp;
357 
358 	if ((tmp = cpykeybuf3(src)) == NULL) {
359 		return (0);
360 	}
361 	*dst = *tmp;
362 	free(tmp); /* but not the contents */
363 	debug(KEYSERV_DEBUG0, ("storekeybuf3 ret %d %x",
364 		dst->keybuf3_len, dst->keybuf3_val));
365 	return (1);
366 }
367 
368 static deskeyarray *
369 getdeskeyarray(int k)
370 {
371 	deskeyarray *buf;
372 
373 	debug(KEYSERV_DEBUG, ("getdeskeyarray malloc %d", k));
374 	buf = (deskeyarray *) malloc(sizeof (*buf));
375 	if (buf == NULL) {
376 		debug(KEYSERV_DEBUG, ("getdeskeyarray malloc failed"));
377 		syslog(LOG_ERR, "file %s line %d: malloc failed",
378 			__FILE__, __LINE__);
379 		return (NULL);
380 	}
381 	buf->deskeyarray_len = k;
382 	/* XXX special case k==0 */
383 	if (k == 0) {
384 		buf->deskeyarray_val = NULL;
385 	} else {
386 		buf->deskeyarray_val = (des_block *)
387 			malloc(k * sizeof (des_block));
388 		if (buf->deskeyarray_val == NULL) {
389 			debug(KEYSERV_DEBUG, ("getdeskeyarray malloc failed"));
390 			free(buf);
391 			syslog(LOG_ERR, "file %s line %d: malloc failed",
392 				__FILE__, __LINE__);
393 			return (NULL);
394 		}
395 	}
396 	debug(KEYSERV_DEBUG1, ("getdeskeyarray ret %x", buf));
397 	return (buf);
398 }
399 
400 static deskeyarray *
401 cpydeskeyarray(deskeyarray *src)
402 {
403 	deskeyarray *dst;
404 
405 	if (src == NULL) {
406 		return (NULL);
407 	}
408 	if ((dst = getdeskeyarray(src->deskeyarray_len)) == NULL) {
409 		return (NULL);
410 	}
411 	memcpy(dst->deskeyarray_val, src->deskeyarray_val,
412 		src->deskeyarray_len * sizeof (des_block));
413 	debug(KEYSERV_DEBUG0, ("cpydeskeyarray ret %x", dst));
414 	return (dst);
415 }
416 
417 static int
418 storedeskeyarray(deskeyarray *dst, deskeyarray *src)
419 {
420 	deskeyarray *tmp;
421 
422 	if ((tmp = cpydeskeyarray(src)) == NULL) {
423 		return (0);
424 	}
425 	*dst = *tmp;
426 	free(tmp); /* but not the contents */
427 	debug(KEYSERV_DEBUG0, ("storedeskeyarray ret %d %x",
428 		dst->deskeyarray_len, dst->deskeyarray_val));
429 	return (1);
430 }
431 
432 int
433 setdeskeyarray(deskeyarray *dst, int k)
434 {
435 	deskeyarray *tmp;
436 
437 	if ((tmp = getdeskeyarray(k)) == NULL) {
438 		return (0);
439 	}
440 	*dst = *tmp;
441 	free(tmp); /* but not the contents */
442 	debug(KEYSERV_DEBUG0, ("setdeskeyarray ret %d %x",
443 		dst->deskeyarray_len, dst->deskeyarray_val));
444 	return (1);
445 }
446 
447 static int
448 cachehit3(keybuf3 *public, keybuf3 *secret, struct cachekey3_list *cp)
449 {
450 	return (cmpkeybuf3(public, cp->public) &&
451 		cmpkeybuf3(secret, cp->secret));
452 }
453 
454 static struct cacheuid_list **
455 mapuid2cache(uid_t uid, struct mechdata *mdp)
456 {
457 	struct cacheuid_list **cpp;
458 	int hash = HASH_UID(uid);
459 
460 	debug(KEYSERV_DEBUG, ("mapuid2cache %d %d %x", uid, hash, mdp));
461 	for (cpp = &mdp->bucket[hash];
462 		*cpp != NULL && (*cpp)->uid != uid;
463 		cpp = &(*cpp)->next) {
464 		debug(KEYSERV_DEBUG0, ("mapuid2cache %x", cpp));
465 	}
466 	debug(KEYSERV_DEBUG, ("mapuid2cache ret %x", cpp));
467 	return (cpp);
468 }
469 
470 static int
471 appendsecretkey3(struct mechentry *mp, uid_t uid, setkeyarg3 *skey)
472 {
473 	struct mechdata *mdp;
474 	struct cacheuid_list **cpp, *cp;
475 	keybuf3 nullkey = {0, NULL};
476 
477 	debug(KEYSERV_DEBUG, ("appendsecretkey3 %x", mp));
478 	if ((skey == NULL) || (mp == NULL)) {
479 		return (0);
480 	}
481 	if (skey->key.keybuf3_len == 0) {
482 		return (0);
483 	}
484 	mutex_lock(&mp->mech_lock);
485 	if ((mdp = mp->mechdata) == NULL) {
486 		mdp = (struct mechdata *)calloc(1, sizeof (*mdp));
487 		if (mdp == NULL) {
488 			mutex_unlock(&mp->mech_lock);
489 			debug(KEYSERV_INFO,
490 				("appendsecretkey3 : calloc failed"));
491 			return (0);
492 		}
493 		mp->mechdata = mdp;
494 	}
495 	cpp = mapuid2cache(uid, mdp);
496 	if (*cpp == NULL) {
497 		cp = (struct cacheuid_list *)malloc(sizeof (*cp));
498 		if (cp == NULL) {
499 			mutex_unlock(&mp->mech_lock);
500 			debug(KEYSERV_INFO,
501 				("appendsecretkey3 : malloc failed"));
502 			syslog(LOG_ERR, "file %s line %d: malloc failed",
503 				__FILE__, __LINE__);
504 			return (0);
505 		}
506 		memset(cp, 0, sizeof (*cp));
507 		cp->uid = uid;
508 		*cpp = cp;
509 	} else {
510 		cp = *cpp;
511 	}
512 	freekeybuf3(cp->secretkey);
513 	if ((cp->secretkey = cpykeybuf3(&skey->key)) == NULL) {
514 		mutex_unlock(&mp->mech_lock);
515 		return (0);
516 	}
517 	freekeybuf3(cp->publickey);
518 	if ((cp->publickey = cpykeybuf3(&nullkey)) == NULL) {
519 		mutex_unlock(&mp->mech_lock);
520 		return (0);
521 	}
522 	mutex_unlock(&mp->mech_lock);
523 	return (1);
524 }
525 
526 /*
527  * Store the vers 3 secretkey for this uid
528  */
529 static int
530 storesecretkey3(uid_t uid, setkeyarg3 *skey)
531 {
532 	struct mechentry *mp;
533 
534 	if (skey == NULL) {
535 		return (0);
536 	}
537 	if ((mp = getmechtype(skey->keylen, skey->algtype)) == NULL) {
538 		return (0);
539 	}
540 	return (appendsecretkey3(mp, uid, skey));
541 }
542 
543 /*
544  * Set the vers 3 secretkey key for this uid
545  */
546 keystatus
547 pk_setkey3(uid_t uid, setkeyarg3 *skey)
548 {
549 	if (!storesecretkey3(uid, skey)) {
550 		return (KEY_SYSTEMERR);
551 	}
552 	return (KEY_SUCCESS);
553 }
554 
555 /*
556  * Set the secretkey key for this uid
557  */
558 keystatus
559 pk_setkey(uid, skey)
560 	uid_t uid;
561 	keybuf skey;
562 {
563 	int storesecretkey(uid_t, keybuf);
564 
565 	if (!storesecretkey(uid, skey)) {
566 		return (KEY_SYSTEMERR);
567 	}
568 	return (KEY_SUCCESS);
569 }
570 
571 int
572 storeotherrootkeys(FILE *fp, char *netname, char *passwd, char *osecret)
573 {
574 	des_block master;
575 	struct keylenlist *kp;
576 	struct algtypelist *ap;
577 	keybuf3 *secret;
578 	setkeyarg3 skey;
579 
580 	debug(KEYSERV_DEBUG, ("storeotherrootkeys %s %s",
581 		netname, passwd));
582 	passwd2des_g(passwd, netname, strlen(netname), &master, FALSE);
583 	for (kp = mechtable.kp; kp != NULL; kp = kp->next) {
584 		debug(KEYSERV_DEBUG0,
585 			("storeotherrootkeys key %d", kp->keylen));
586 		for (ap = kp->ap; ap != NULL; ap = ap->next) {
587 			debug(KEYSERV_DEBUG,
588 				("storeotherrootkeys alg: %d", ap->algtype));
589 			if ((secret = getkeybuf3(kp->keylen/4+1)) == NULL) {
590 				return (0);
591 			}
592 			debug(KEYSERV_DEBUG,
593 				("storeotherrootkeys calling getsecretkey_g"));
594 			if (!getsecretkey_g(netname,
595 				kp->keylen, ap->algtype,
596 				secret->keybuf3_val, secret->keybuf3_len,
597 				passwd)) {
598 				debug(KEYSERV_INFO,
599 				("Can't find %s's secret key", netname));
600 				return (0);
601 			}
602 			if (*secret->keybuf3_val == 0) { /* XXX */
603 				debug(KEYSERV_INFO,
604 				("Password does not decrypt secret key for %s",
605 					netname));
606 				return (0);
607 			}
608 			skey.key = *secret;
609 			free(secret); /* but not the buffer it points to */
610 			skey.userkey = master;
611 			skey.keylen = kp->keylen;
612 			skey.algtype = ap->algtype;
613 			if (CLASSIC_PK_DH(kp->keylen, ap->algtype)) {
614 				pk_setkey((uid_t)0, osecret);
615 				fprintf(fp, "%s\n", osecret);
616 			}
617 			if (pk_setkey3(0, &skey) != KEY_SUCCESS) {
618 				return (0);
619 			}
620 			if (!CLASSIC_PK_DH(kp->keylen, ap->algtype)) {
621 				fprintf(fp, "%s %d\n", skey.key.keybuf3_val,
622 					ap->algtype);
623 			}
624 		}
625 	}
626 	return (1);
627 }
628 
629 /*
630  * prohibit the nobody key on this machine k (the -d flag)
631  */
632 int
633 pk_nodefaultkeys()
634 {
635 	nodefaultkeys = 1;
636 	return (0);
637 }
638 
639 static void
640 freedisklist(struct cacheuid_list *cp)
641 {
642 	if (cp == NULL) {
643 		return;
644 	}
645 	free(cp->netname); /* ok even if this is NULL */
646 	freekeybuf3(cp->secretkey);
647 	freekeybuf3(cp->publickey);
648 }
649 
650 keystatus
651 pk_clear3(uid_t uid)
652 {
653 	struct keylenlist *kp;
654 	struct algtypelist *ap;
655 	struct mechdata *mdp;
656 	struct cacheuid_list **cpp, *cp;
657 
658 	debug(KEYSERV_DEBUG, ("pk_clear3 %d", uid));
659 	for (kp = mechtable.kp; kp != NULL; kp = kp->next) {
660 		debug(KEYSERV_DEBUG0, ("pk_clear3 key %d", kp->keylen));
661 		for (ap = kp->ap; ap != NULL; ap = ap->next) {
662 			debug(KEYSERV_DEBUG0,
663 				("pk_clear3 alg: %d", ap->algtype));
664 			mutex_lock(&ap->mech.mech_lock);
665 			if ((mdp = ap->mech.mechdata) == NULL) {
666 				mutex_unlock(&ap->mech.mech_lock);
667 				continue;
668 			}
669 			cpp = mapuid2cache(uid, mdp);
670 			if (*cpp == NULL) {
671 				mutex_unlock(&ap->mech.mech_lock);
672 				continue;
673 			}
674 			cp = (*cpp)->next;
675 			freedisklist(*cpp);
676 			*cpp = cp;
677 			mutex_unlock(&ap->mech.mech_lock);
678 		}
679 	}
680 	/* XXX clear stuff out of the common key cache as well? */
681 	/* XXX return success only if something was removed? */
682 	return (KEY_SUCCESS);
683 }
684 
685 /*
686  * Set the modulus for all our Diffie-Hellman operations
687  */
688 int
689 setmodulus(modx)
690 	char *modx;
691 {
692 	MODULUS = mp_xtom(modx);
693 	return (0);
694 }
695 
696 /*
697  * Encrypt the key using the public key associated with remote_name and the
698  * secret key associated with uid.
699  */
700 keystatus
701 pk_encrypt(uid, remote_name, remote_key, key)
702 	uid_t uid;
703 	char *remote_name;
704 	netobj	*remote_key;
705 	des_block *key;
706 {
707 	return (pk_crypt(uid, remote_name, remote_key, key, DES_ENCRYPT));
708 }
709 
710 /*
711  * Encrypt the key using the public key associated with remote_name and the
712  * secret key associated with uid using vers 3
713  */
714 keystatus
715 pk_encrypt3(
716 	uid_t uid,
717 	cryptkeyarg3 *arg,
718 	deskeyarray *key
719 )
720 {
721 	return (pk_crypt3(uid, arg, key, DES_ENCRYPT));
722 }
723 
724 /*
725  * Decrypt the key using the public key associated with remote_name and the
726  * secret key associated with uid.
727  */
728 keystatus
729 pk_decrypt(uid, remote_name, remote_key, key)
730 	uid_t uid;
731 	char *remote_name;
732 	netobj *remote_key;
733 	des_block *key;
734 {
735 	return (pk_crypt(uid, remote_name, remote_key, key, DES_DECRYPT));
736 }
737 
738 /*
739  * Decrypt the key using the public key associated with remote_name and the
740  * secret key associated with uid using vers 3
741  */
742 keystatus
743 pk_decrypt3(
744 	uid_t uid,
745 	cryptkeyarg3 *arg,
746 	deskeyarray *key
747 )
748 {
749 	return (pk_crypt3(uid, arg, key, DES_DECRYPT));
750 }
751 
752 /*
753  * Key storage management
754  */
755 
756 #define	KEY_ONLY 0
757 #define	KEY_NAME 1
758 struct secretkey_netname_list {
759 	uid_t uid;
760 	key_netstarg keynetdata;
761 	uchar_t sc_flag;
762 	struct secretkey_netname_list *next;
763 };
764 
765 #define	HASH_UID(x)	(x & 0xff)
766 static struct secretkey_netname_list *g_secretkey_netname[KEY_HASH_SIZE];
767 static rwlock_t g_secretkey_netname_lock = DEFAULTRWLOCK;
768 
769 /*
770  * Store the keys and netname for this uid
771  */
772 static int
773 store_netname(uid, netstore)
774 	uid_t uid;
775 	key_netstarg *netstore;
776 {
777 	struct secretkey_netname_list *new;
778 	struct secretkey_netname_list **l;
779 	int hash = HASH_UID(uid);
780 
781 	(void) rw_wrlock(&g_secretkey_netname_lock);
782 	for (l = &g_secretkey_netname[hash]; *l != NULL && (*l)->uid != uid;
783 			l = &(*l)->next) {
784 	}
785 	if (*l == NULL) {
786 /* LINTED pointer alignment */
787 		new = (struct secretkey_netname_list *)malloc(sizeof (*new));
788 		if (new == NULL) {
789 			(void) rw_unlock(&g_secretkey_netname_lock);
790 			return (0);
791 		}
792 		new->uid = uid;
793 		new->next = NULL;
794 		*l = new;
795 	} else {
796 		new = *l;
797 		if (new->keynetdata.st_netname)
798 			(void) free(new->keynetdata.st_netname);
799 	}
800 	memcpy(new->keynetdata.st_priv_key, netstore->st_priv_key,
801 		HEXKEYBYTES);
802 	memcpy(new->keynetdata.st_pub_key, netstore->st_pub_key, HEXKEYBYTES);
803 
804 	if (netstore->st_netname)
805 		new->keynetdata.st_netname = strdup(netstore->st_netname);
806 	else
807 		new->keynetdata.st_netname = (char *)NULL;
808 	new->sc_flag = KEY_NAME;
809 	(void) rw_unlock(&g_secretkey_netname_lock);
810 	return (1);
811 
812 }
813 
814 static int
815 appendnetname3(struct mechentry *mp, uid_t uid, key_netstarg3 *net)
816 {
817 	struct mechdata *mdp;
818 	struct cacheuid_list **cpp, *cp;
819 
820 	debug(KEYSERV_DEBUG, ("appendnetname3 %x", mp));
821 	if ((mp == NULL) || (net == NULL)) {
822 		return (0);
823 	}
824 	mutex_lock(&mp->mech_lock);
825 	if ((mdp = mp->mechdata) == NULL) {
826 		mdp = (struct mechdata *)calloc(1, sizeof (*mdp));
827 		if (mdp == NULL) {
828 			mutex_unlock(&mp->mech_lock);
829 			debug(KEYSERV_INFO, ("appendnetname3 : calloc failed"));
830 			return (0);
831 		}
832 		mp->mechdata = mdp;
833 	}
834 	cpp = mapuid2cache(uid, mdp);
835 	if (*cpp == NULL) {
836 		cp = (struct cacheuid_list *)malloc(sizeof (*cp));
837 		if (cp == NULL) {
838 			mutex_unlock(&mp->mech_lock);
839 			debug(KEYSERV_INFO, ("appendnetname3 : malloc failed"));
840 			syslog(LOG_ERR, "file %s line %d: malloc failed",
841 				__FILE__, __LINE__);
842 			return (0);
843 		}
844 		memset(cp, 0, sizeof (*cp));
845 		cp->uid = uid;
846 		*cpp = cp;
847 	} else {
848 		cp = *cpp;
849 	}
850 	freekeybuf3(cp->secretkey);
851 	if ((cp->secretkey = cpykeybuf3(&net->st_priv_key)) == NULL) {
852 		mutex_unlock(&mp->mech_lock);
853 		return (0);
854 	}
855 	freekeybuf3(cp->publickey);
856 	if ((cp->publickey = cpykeybuf3(&net->st_pub_key)) == NULL) {
857 		mutex_unlock(&mp->mech_lock);
858 		return (0);
859 	}
860 	free(cp->netname);
861 	if (net->st_netname) {
862 		cp->netname = strdup(net->st_netname);
863 	} else {
864 		cp->netname = (char *)NULL;
865 	}
866 	mutex_unlock(&mp->mech_lock);
867 	return (1);
868 }
869 
870 keystatus
871 pk_netput(uid, netstore)
872 	uid_t uid;
873 	key_netstarg *netstore;
874 {
875 
876 	if (!store_netname(uid, netstore)) {
877 		return (KEY_SYSTEMERR);
878 	}
879 	return (KEY_SUCCESS);
880 }
881 
882 /*
883  * Store the keys and netname for this uid vers 3
884  */
885 static int
886 store_netname3(uid_t uid, key_netstarg3 *net)
887 {
888 	struct mechentry *mp;
889 	key_netstarg netstore;
890 
891 	if (net == NULL) {
892 		return (0);
893 	}
894 	if ((mp = getmechtype(net->keylen, net->algtype)) == NULL) {
895 		return (0);
896 	}
897 	if (uid == 0 && CLASSIC_PK_DH(net->keylen, net->algtype)) {
898 		memcpy(netstore.st_priv_key, net->st_priv_key.keybuf3_val,
899 			HEXKEYBYTES);
900 		memset(netstore.st_pub_key, 0, HEXKEYBYTES);
901 		netstore.st_netname = net->st_netname;
902 		if (pk_netput(uid, &netstore) != KEY_SUCCESS) {
903 			(void) fprintf(stderr,
904 			"keyserv: could not set root's key and netname.\n");
905 			return (0);
906 		}
907 	}
908 	return (appendnetname3(mp, uid, net));
909 }
910 
911 keystatus
912 pk_netput3(uid_t uid, key_netstarg3 *netstore)
913 {
914 
915 	if (!store_netname3(uid, netstore)) {
916 		return (KEY_SYSTEMERR);
917 	}
918 	return (KEY_SUCCESS);
919 }
920 
921 int
922 addmasterkey(char *master, char *netname, algtype_t algtype)
923 {
924 	keybuf3 *secret, *public;
925 	int bytelen = strlen(master);
926 	keylen_t keylen = bytelen*4;
927 	key_netstarg3 tmp;
928 
929 	if ((secret = setkeybuf3(master, bytelen)) == NULL) {
930 		return (0);
931 	}
932 	if ((public = getkeybuf3(bytelen+1)) == NULL) {
933 		/* the +1 is mandated by getpublickey_g() */
934 		return (0);
935 	}
936 	/*
937 	 * getpublickey_g(netname, keylen, algtype,
938 	 *  public->keybuf3_val, public->keybuf3_len);
939 	 * cannot be called since rpc.nisd is not up yet
940 	 * so we continue to return a zero filled public key
941 	 * as in the earlier version
942 	 */
943 	memset(public->keybuf3_val, 0, bytelen+1);
944 	tmp.st_priv_key = *secret;
945 	free(secret);
946 	tmp.st_pub_key = *public;
947 	free(public);
948 	tmp.st_netname = strdup(netname);
949 	tmp.keylen = keylen;
950 	tmp.algtype = algtype;
951 	return (store_netname3(0, &tmp));
952 }
953 
954 /*
955  * Fetch the keys and netname for this uid
956  */
957 static int
958 fetch_netname(uid, key_netst)
959 	uid_t uid;
960 	struct key_netstarg *key_netst;
961 {
962 	struct secretkey_netname_list *l;
963 	int hash = HASH_UID(uid);
964 
965 	(void) rw_rdlock(&g_secretkey_netname_lock);
966 	for (l = g_secretkey_netname[hash]; l != NULL; l = l->next) {
967 		if ((l->uid == uid) && (l->sc_flag == KEY_NAME)) {
968 
969 			memcpy(key_netst->st_priv_key,
970 				l->keynetdata.st_priv_key, HEXKEYBYTES);
971 
972 			memcpy(key_netst->st_pub_key,
973 				l->keynetdata.st_pub_key, HEXKEYBYTES);
974 
975 			if (l->keynetdata.st_netname)
976 				strcpy(key_netst->st_netname,
977 						l->keynetdata.st_netname);
978 			else
979 				key_netst->st_netname = NULL;
980 			(void) rw_unlock(&g_secretkey_netname_lock);
981 			return (1);
982 		}
983 	}
984 	(void) rw_unlock(&g_secretkey_netname_lock);
985 	return (0);
986 }
987 
988 static void
989 remove_ref(struct cacheuid_list *cp)
990 {
991 	debug(KEYSERV_DEBUG0, ("remove_ref %x", cp));
992 	/*
993 	 * XXX
994 	 * if we are going to do this along the lines of vn_rele,
995 	 * more stuff needs to be done here and the access to refcnt
996 	 * needs to be mutex locked. Keep it simple for now.
997 	 */
998 	cp->refcnt--;
999 }
1000 
1001 static void
1002 add_ref(struct cacheuid_list **cpp)
1003 {
1004 	struct cacheuid_list *cp;
1005 
1006 	if (cpp == NULL) {
1007 		return;
1008 	}
1009 	/*LINTED assignment operator "=" found where "==" was expected*/
1010 	if (cp = *cpp) {
1011 		debug(KEYSERV_DEBUG0, ("add_ref %x", cp));
1012 		cp->refcnt++;
1013 	}
1014 }
1015 
1016 static struct cacheuid_list *
1017 getcachekey3(uid_t uid, struct mechentry *mp)
1018 {
1019 	struct cacheuid_list **cpp, *cp;
1020 	struct mechdata *mdp;
1021 
1022 	debug(KEYSERV_DEBUG1, ("getcachekey3 %d %x", uid, mp));
1023 	if (mp == NULL) {
1024 		return (0);
1025 	}
1026 	mutex_lock(&mp->mech_lock);
1027 	if ((mdp = mp->mechdata) == NULL) {
1028 		mutex_unlock(&mp->mech_lock);
1029 		debug(KEYSERV_DEBUG0, ("getcachekey3 ret 0"));
1030 		return (0);
1031 	}
1032 	cpp = mapuid2cache(uid, mdp);
1033 	cp = *cpp;
1034 	add_ref(cpp);
1035 	mutex_unlock(&mp->mech_lock);
1036 	debug(KEYSERV_DEBUG0, ("getcachekey3 ret %x", *cpp));
1037 	return (cp);
1038 }
1039 
1040 /*
1041  * Fetch any available cache for this uid (vers 3)
1042  */
1043 static struct cacheuid_list *
1044 getanycache3(uid_t uid)
1045 {
1046 	struct keylenlist *kp;
1047 	struct algtypelist *ap;
1048 	struct mechdata *mdp;
1049 	struct cacheuid_list **cpp, *cp;
1050 
1051 	debug(KEYSERV_DEBUG, ("getanycache3 %d", uid));
1052 	for (kp = mechtable.kp; kp != NULL; kp = kp->next) {
1053 		debug(KEYSERV_DEBUG0, ("getanycache3 key %d", kp->keylen));
1054 		for (ap = kp->ap; ap != NULL; ap = ap->next) {
1055 			debug(KEYSERV_DEBUG0,
1056 				("getanycache3 alg: %d", ap->algtype));
1057 			mutex_lock(&ap->mech.mech_lock);
1058 			if ((mdp = ap->mech.mechdata) == NULL) {
1059 				mutex_unlock(&ap->mech.mech_lock);
1060 				continue;
1061 			}
1062 			cpp = mapuid2cache(uid, mdp);
1063 			if (*cpp == NULL) {
1064 				mutex_unlock(&ap->mech.mech_lock);
1065 				continue;
1066 			}
1067 			cp = *cpp;
1068 			cp->refcnt++;
1069 			mutex_unlock(&ap->mech.mech_lock);
1070 			return (cp);
1071 		}
1072 	}
1073 	return (NULL);
1074 }
1075 
1076 static struct cacheuid_list *
1077 fetchcache3(uid_t uid, keylen_t k, algtype_t a)
1078 {
1079 	struct mechentry *mp;
1080 	struct cacheuid_list *cp;
1081 
1082 	debug(KEYSERV_DEBUG, ("fetchcache3 %d %d %d", uid, k, a));
1083 	if ((mp = getmechtype(k, a)) == NULL) {
1084 		return (NULL);
1085 	}
1086 	if ((cp = getcachekey3(uid, mp)) == NULL) {
1087 		return (NULL);
1088 	}
1089 	debug(KEYSERV_DEBUG, ("fetchcache3 ret %x", cp));
1090 	return (cp);
1091 }
1092 
1093 /*
1094  * Fetch the keys and netname for this uid vers 3
1095  */
1096 static int
1097 fetch_netname3(uid_t uid, mechtype *net, key_netstarg3 *ret)
1098 {
1099 	struct cacheuid_list *cp;
1100 
1101 	if ((net == NULL) || (ret == NULL)) {
1102 		return (0);
1103 	}
1104 	debug(KEYSERV_DEBUG, ("fetch_netname3 %d %d %d",
1105 		uid, net->keylen, net->algtype));
1106 	if (net->keylen == 0) {
1107 		cp = getanycache3(uid);
1108 	} else {
1109 		cp = fetchcache3(uid, net->keylen, net->algtype);
1110 	}
1111 	debug(KEYSERV_DEBUG, ("fetch_netname3 cp %x", cp));
1112 	if (cp == NULL) {
1113 		return (0);
1114 	}
1115 	debug(KEYSERV_DEBUG, ("fetch_netname3 sec %x", cp->secretkey));
1116 	if (!storekeybuf3(&ret->st_priv_key, cp->secretkey)) {
1117 		return (0);
1118 	}
1119 	debug(KEYSERV_DEBUG, ("fetch_netname3 pub %x", cp->publickey));
1120 	if (!storekeybuf3(&ret->st_pub_key, cp->publickey)) {
1121 		return (0);
1122 	}
1123 	if (cp->netname) {
1124 		debug(KEYSERV_DEBUG, ("fetch_netname3 net %s", cp->netname));
1125 		ret->st_netname = strdup(cp->netname);
1126 	} else {
1127 		ret->st_netname = NULL;
1128 	}
1129 	remove_ref(cp);
1130 	return (1);
1131 }
1132 
1133 keystatus
1134 pk_netget(uid, netstore)
1135 	uid_t uid;
1136 	key_netstarg *netstore;
1137 {
1138 	if (!fetch_netname(uid, netstore)) {
1139 		return (KEY_SYSTEMERR);
1140 	}
1141 	return (KEY_SUCCESS);
1142 }
1143 
1144 keystatus
1145 pk_netget3(uid_t uid, mechtype *net, key_netstarg3 *ret)
1146 {
1147 	if (!fetch_netname3(uid, net, ret)) {
1148 		return (KEY_SYSTEMERR);
1149 	}
1150 	return (KEY_SUCCESS);
1151 }
1152 
1153 #define	cachehit(pub, sec, list)	\
1154 		(memcmp(pub, (list)->public, sizeof (keybuf)) == 0 && \
1155 		memcmp(sec, (list)->secret, sizeof (keybuf)) == 0)
1156 
1157 /*
1158  * Try to find the common key in the cache
1159  */
1160 static int
1161 readcache(pub, sec, deskey, hash)
1162 	char *pub;
1163 	char *sec;
1164 	des_block *deskey;
1165 	int hash;
1166 {
1167 	register struct cachekey_list **l;
1168 
1169 	for (l = &g_cachedkeys[hash]; (*l) != NULL && !cachehit(pub, sec, *l);
1170 		l = &(*l)->next)
1171 		;
1172 	if ((*l) == NULL)
1173 		return (0);
1174 	*deskey = (*l)->deskey;
1175 	return (1);
1176 }
1177 
1178 /*
1179  * cache result of expensive multiple precision exponential operation
1180  */
1181 static int
1182 writecache(pub, sec, deskey, hash)
1183 	char *pub;
1184 	char *sec;
1185 	des_block *deskey;
1186 	int hash;
1187 {
1188 	struct cachekey_list *new;
1189 
1190 	new = (struct cachekey_list *)malloc(sizeof (struct cachekey_list));
1191 	if (new == NULL) {
1192 		return (0);
1193 	}
1194 	memcpy(new->public, pub, sizeof (keybuf));
1195 	memcpy(new->secret, sec, sizeof (keybuf));
1196 	new->deskey = *deskey;
1197 
1198 	new->next = g_cachedkeys[hash];
1199 	g_cachedkeys[hash] = new;
1200 	return (1);
1201 }
1202 
1203 /*
1204  * Choose middle 64 bits of the common key to use as our des key, possibly
1205  * overwriting the lower order bits by setting parity.
1206  */
1207 static int
1208 extractdeskey(ck, deskey)
1209 	MINT *ck;
1210 	des_block *deskey;
1211 {
1212 	void _mp_move(MINT *, MINT *);
1213 	MINT *a;
1214 	short r;
1215 	int i;
1216 	short base = (1 << 8);
1217 	char *k;
1218 
1219 	a = mp_itom(0);
1220 	_mp_move(ck, a);
1221 	for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) {
1222 		mp_sdiv(a, base, a, &r);
1223 	}
1224 	k = deskey->c;
1225 	for (i = 0; i < 8; i++) {
1226 		mp_sdiv(a, base, a, &r);
1227 		*k++ = r;
1228 	}
1229 	mp_mfree(a);
1230 	des_setparity((char *)deskey);
1231 	return (0);
1232 }
1233 
1234 static bool_t
1235 fetchsecretkey(uid, buf)
1236 	uid_t uid;
1237 	char *buf;
1238 {
1239 	struct secretkey_netname_list *l;
1240 	int hash = HASH_UID(uid);
1241 
1242 	(void) rw_rdlock(&g_secretkey_netname_lock);
1243 	for (l = g_secretkey_netname[hash]; l != NULL; l = l->next) {
1244 		if (l->uid == uid) {
1245 			memcpy(buf, l->keynetdata.st_priv_key,
1246 				sizeof (keybuf));
1247 			(void) rw_unlock(&g_secretkey_netname_lock);
1248 			return (TRUE);
1249 		}
1250 	}
1251 	(void) rw_unlock(&g_secretkey_netname_lock);
1252 	return (FALSE);
1253 }
1254 
1255 static keybuf3 *
1256 fetchsecretkey3(uid_t uid, keylen_t k, algtype_t a)
1257 {
1258 	struct cacheuid_list *cp;
1259 
1260 	debug(KEYSERV_DEBUG, ("fetchsecretkey3 %d %d %d", uid, k, a));
1261 	if ((cp = fetchcache3(uid, k, a)) == NULL) {
1262 		return (NULL);
1263 	}
1264 	debug(KEYSERV_DEBUG, ("fetchsecretkey3 ret %x", cp->secretkey));
1265 	return (cp->secretkey);
1266 }
1267 
1268 /*
1269  * Do the work of pk_encrypt && pk_decrypt
1270  */
1271 static keystatus
1272 pk_crypt(uid, remote_name, remote_key, key, mode)
1273 	uid_t uid;
1274 	char *remote_name;
1275 	netobj *remote_key;
1276 	des_block *key;
1277 	int mode;
1278 {
1279 	char xsecret[1024];
1280 	char xpublic[1024];
1281 	des_block deskey;
1282 	int err;
1283 	MINT *public;
1284 	MINT *secret;
1285 	MINT *common;
1286 	char zero[8];
1287 	int hash;
1288 
1289 	if (!fetchsecretkey(uid, xsecret) || xsecret[0] == 0) {
1290 		memset(zero, 0, sizeof (zero));
1291 		if (nodefaultkeys)
1292 			return (KEY_NOSECRET);
1293 
1294 		if (!getsecretkey("nobody", xsecret, zero) || xsecret[0] == 0) {
1295 			return (KEY_NOSECRET);
1296 		}
1297 	}
1298 	if (remote_key) {
1299 		memcpy(xpublic, remote_key->n_bytes, remote_key->n_len);
1300 	} else {
1301 		if (!getpublickey(remote_name, xpublic)) {
1302 			if (nodefaultkeys || !getpublickey("nobody", xpublic))
1303 				return (KEY_UNKNOWN);
1304 		}
1305 	}
1306 
1307 	xsecret[HEXKEYBYTES] = '\0';
1308 	xpublic[HEXKEYBYTES] = '\0';
1309 
1310 	hash = hash_keys(xpublic, xsecret);
1311 	(void) rw_rdlock(&g_cachedkeys_lock);
1312 	if (!readcache(xpublic, xsecret, &deskey, hash)) {
1313 		(void) rw_unlock(&g_cachedkeys_lock);
1314 		(void) rw_wrlock(&g_cachedkeys_lock);
1315 		if (!readcache(xpublic, xsecret, &deskey, hash)) {
1316 			public = mp_xtom(xpublic);
1317 			secret = mp_xtom(xsecret);
1318 			/* Sanity Check on public and private keys */
1319 			if (public == NULL || secret == NULL) {
1320 				(void) rw_unlock(&g_cachedkeys_lock);
1321 				return (KEY_SYSTEMERR);
1322 			}
1323 			common = mp_itom(0);
1324 			mp_pow(public, secret, MODULUS, common);
1325 			extractdeskey(common, &deskey);
1326 			writecache(xpublic, xsecret, &deskey, hash);
1327 			mp_mfree(secret);
1328 			mp_mfree(public);
1329 			mp_mfree(common);
1330 		}
1331 	}
1332 	(void) rw_unlock(&g_cachedkeys_lock);
1333 
1334 	err = ecb_crypt((char *)&deskey, (char *)key, sizeof (des_block),
1335 		DES_HW | mode);
1336 	if (DES_FAILED(err)) {
1337 		return (KEY_SYSTEMERR);
1338 	}
1339 	return (KEY_SUCCESS);
1340 }
1341 
1342 static int
1343 hash_keys3(keybuf3 *p, keybuf3 *s)
1344 {
1345 	int i;
1346 	int hash = 0;
1347 	char *pub = p->keybuf3_val;
1348 	char *sec = s->keybuf3_val;
1349 
1350 	debug(KEYSERV_DEBUG, ("hash_keys3 public %d %s",
1351 		p->keybuf3_len, pub));
1352 	debug(KEYSERV_DEBUG, ("hash_keys3 secret %d %s",
1353 		s->keybuf3_len, sec));
1354 	for (i = 0; i < s->keybuf3_len; i += 6, pub += 6, sec += 6) {
1355 		hash ^= *pub;
1356 		hash ^= *sec;
1357 	}
1358 	debug(KEYSERV_DEBUG, ("hash_keys3 ret %d", hash & 0xff));
1359 	return (hash & 0xff);
1360 }
1361 
1362 static struct cachekey3_list **
1363 map_ps2cache(keybuf3 *public, keybuf3 *secret, struct psdata *pdp)
1364 {
1365 	struct cachekey3_list **cpp;
1366 	int hash = hash_keys3(public, secret);
1367 
1368 	debug(KEYSERV_DEBUG, ("map_ps2cache %x %d", pdp, hash));
1369 	for (cpp = &pdp->common[hash];
1370 		*cpp != NULL && !(cachehit3(public, secret, *cpp));
1371 		cpp = &(*cpp)->next) {
1372 		debug(KEYSERV_DEBUG0, ("map_ps2cache %x", cpp));
1373 	}
1374 	debug(KEYSERV_DEBUG, ("map_ps2cache ret %x", cpp));
1375 	return (cpp);
1376 }
1377 
1378 static struct cachekey3_list *
1379 getdeskey3(
1380 	keylen_t keylen,
1381 	algtype_t algtype,
1382 	int desarylen,
1383 	keybuf3 *public,
1384 	keybuf3 *secret,
1385 	uid_t uid
1386 )
1387 {
1388 	struct mechentry *mp;
1389 	struct psdata *pdp;
1390 	struct cachekey3_list **cpp, *cp, *cachep;
1391 	struct cacheuid_list *cu;
1392 	int i;
1393 	int cached = 0;
1394 
1395 	debug(KEYSERV_DEBUG, ("getdeskey3 %d %d %d %x %x",
1396 		keylen, algtype, desarylen, public, secret));
1397 	if ((mp = getmechtype(keylen, algtype)) == NULL) {
1398 		return (0);
1399 	}
1400 	(void) mutex_lock(&mp->ps_lock);
1401 	if ((pdp = mp->psdata) == NULL) {
1402 		if ((pdp = (struct psdata *)calloc(1, sizeof (*pdp))) ==
1403 			NULL) {
1404 			mutex_unlock(&mp->ps_lock);
1405 			debug(KEYSERV_INFO, ("getdeskey3 : calloc failed"));
1406 			return (0);
1407 		}
1408 		mp->psdata = pdp;
1409 	}
1410 	debug(KEYSERV_DEBUG, ("getdeskey3 %x", pdp));
1411 	cpp = map_ps2cache(public, secret, pdp);
1412 	if (*cpp == NULL) {
1413 		debug(KEYSERV_DEBUG, ("getdeskey3 calling fetchcache3"));
1414 		if (disk_caching &&
1415 			(cu = fetchcache3(uid, keylen, algtype)) != NULL) {
1416 			debug(KEYSERV_DEBUG,
1417 				("getdeskey3 calling cache_retrieve"));
1418 			if ((cachep = cache_retrieve(keylen, algtype, uid,
1419 				public, cu->key)) != NULL) {
1420 				if (cmpkeybuf3(cachep->secret, cu->secretkey)) {
1421 					cached = 1;
1422 				} else {
1423 					debug(KEYSERV_DEBUG,
1424 					("getdeskey3 calling cache_remove"));
1425 					cache_remove(keylen, algtype,
1426 						uid, NULL);
1427 				}
1428 			}
1429 		}
1430 		if (cached) {
1431 			cp = cachep;
1432 		} else {
1433 			if ((cp = (struct cachekey3_list *)
1434 				malloc(sizeof (*cp))) == NULL) {
1435 				mutex_unlock(&mp->ps_lock);
1436 				debug(KEYSERV_INFO,
1437 					("getdeskey3 : malloc failed"));
1438 				syslog(LOG_ERR,
1439 					"file %s line %d: malloc failed",
1440 					__FILE__, __LINE__);
1441 				return (0);
1442 			}
1443 			cp->refcnt = 0;
1444 			cp->next = NULL;
1445 			if ((cp->public = cpykeybuf3(public)) == NULL) {
1446 				mutex_unlock(&mp->ps_lock);
1447 				return (0);
1448 			}
1449 			if ((cp->secret = cpykeybuf3(secret)) == NULL) {
1450 				mutex_unlock(&mp->ps_lock);
1451 				return (0);
1452 			}
1453 			if (!setdeskeyarray(&cp->deskey, desarylen)) {
1454 				mutex_unlock(&mp->ps_lock);
1455 				return (0);
1456 			}
1457 			debug(KEYSERV_DEBUG, ("getdeskey3 %x %x %x",
1458 				cp->public, cp->secret,
1459 				cp->deskey.deskeyarray_val));
1460 			debug(KEYSERV_DEBUG,
1461 				("getdeskey3 calling __gen_common_dhkeys_g"));
1462 			if (!__gen_common_dhkeys_g(public->keybuf3_val,
1463 				secret->keybuf3_val,
1464 				keylen, algtype,
1465 				cp->deskey.deskeyarray_val, desarylen)) {
1466 				mutex_unlock(&mp->ps_lock);
1467 				return (0);
1468 			}
1469 			for (i = 0; i < desarylen; i++) {
1470 				debug(KEYSERV_DEBUG0,
1471 					("getdeskey3 gendh key : (%x,%x)",
1472 					cp->deskey.deskeyarray_val[i].key.high,
1473 					cp->deskey.deskeyarray_val[i].key.low));
1474 			}
1475 			if (disk_caching && cu != NULL) {
1476 				debug(KEYSERV_DEBUG,
1477 					("getdeskey3 calling cache_insert"));
1478 				cache_insert(keylen, algtype, uid, cp->deskey,
1479 					cu->key, public, secret);
1480 			}
1481 		}
1482 		*cpp = cp;
1483 	} else {
1484 		cp = *cpp;
1485 	}
1486 	cp->refcnt++;
1487 	mutex_unlock(&mp->ps_lock);
1488 	debug(KEYSERV_DEBUG, ("getdeskey3 ret %x", cp));
1489 	return (cp);
1490 }
1491 
1492 keystatus
1493 pk_get_conv_key3(uid_t uid, deskeyarg3 *arg, cryptkeyres3 *res)
1494 {
1495 	keybuf3 *xsecret, *xpublic;
1496 	char zero[8];
1497 	struct cachekey3_list *cp;
1498 
1499 	debug(KEYSERV_DEBUG, ("pk_get_conv_key3 %d %x %x",
1500 		uid, arg, res));
1501 	if ((xsecret = fetchsecretkey3(uid,
1502 		arg->keylen, arg->algtype)) == NULL) {
1503 		if (nodefaultkeys)
1504 			return (KEY_NOSECRET);
1505 		memset(zero, 0, sizeof (zero));
1506 		if ((xsecret = getkeybuf3(arg->keylen/4+1)) == NULL) {
1507 			return (KEY_SYSTEMERR);
1508 		}
1509 		debug(KEYSERV_DEBUG,
1510 			("pk_get_conv_key3 calling getsecretkey_g"));
1511 		if (!getsecretkey_g("nobody",
1512 			arg->keylen, arg->algtype,
1513 			xsecret->keybuf3_val, xsecret->keybuf3_len,
1514 			zero) || *xsecret->keybuf3_val == 0) { /* XXX */
1515 			debug(KEYSERV_DEBUG,
1516 			("pk_get_conv_key3 calling getsecretkey_g failed"));
1517 			return (KEY_NOSECRET);
1518 		}
1519 		debug(KEYSERV_DEBUG,
1520 			("pk_get_conv_key3 calling getsecretkey_g succeeded"));
1521 	}
1522 	xpublic = &arg->pub_key;
1523 	if ((cp = getdeskey3(arg->keylen, arg->algtype, arg->nkeys,
1524 		xpublic, xsecret, uid)) == NULL) {
1525 		return (KEY_SYSTEMERR);
1526 	}
1527 	storedeskeyarray(&res->cryptkeyres3_u.deskey, &cp->deskey);
1528 	return (KEY_SUCCESS);
1529 }
1530 
1531 /*
1532  * Do the work of pk_encrypt3 && pk_decrypt3
1533  */
1534 static keystatus
1535 pk_crypt3(
1536 	uid_t uid,
1537 	cryptkeyarg3 *arg,
1538 	deskeyarray *key,
1539 	int mode
1540 )
1541 {
1542 	keybuf3 *xsecret = NULL, *xpublic = NULL;
1543 	char zero[8];
1544 	struct cachekey3_list *cp;
1545 	int err;
1546 	int xsecret_alloc = 0;
1547 	char ivec[8];
1548 
1549 	memset(ivec, 0, 8);
1550 	debug(KEYSERV_DEBUG1, ("pk_crypt3 %d %x %x %d",
1551 		uid, arg, key, mode));
1552 	if ((xsecret = fetchsecretkey3(uid,
1553 		arg->keylen, arg->algtype)) == NULL) {
1554 		if (nodefaultkeys)
1555 			return (KEY_NOSECRET);
1556 		memset(zero, 0, sizeof (zero));
1557 		if ((xsecret = getkeybuf3(arg->keylen/4+1)) == NULL) {
1558 			return (KEY_SYSTEMERR);
1559 		}
1560 		xsecret_alloc = 1;
1561 		debug(KEYSERV_DEBUG1, ("pk_crypt3 calling getsecretkey_g"));
1562 		if (!getsecretkey_g("nobody",
1563 			arg->keylen, arg->algtype,
1564 			xsecret->keybuf3_val, xsecret->keybuf3_len,
1565 			zero) || *xsecret->keybuf3_val == 0) { /* XXX */
1566 			debug(KEYSERV_DEBUG,
1567 				("pk_crypt3 calling getsecretkey_g failed"));
1568 			freekeybuf3(xsecret);
1569 			return (KEY_NOSECRET);
1570 		}
1571 		/* XXX optimize to cache nobody's secret key? */
1572 		debug(KEYSERV_DEBUG0,
1573 			("pk_crypt3 calling getsecretkey_g succeeded"));
1574 	}
1575 	if (arg->remotekey.keybuf3_len) {
1576 		if ((xpublic = cpykeybuf3(&arg->remotekey)) == NULL) {
1577 			if (xsecret_alloc) freekeybuf3(xsecret);
1578 			return (KEY_SYSTEMERR);
1579 		}
1580 	} else {
1581 		if ((xpublic = getkeybuf3(arg->keylen/4+1)) == NULL) {
1582 			if (xsecret_alloc) freekeybuf3(xsecret);
1583 			return (KEY_SYSTEMERR);
1584 		}
1585 		debug(KEYSERV_DEBUG1, ("pk_crypt3 calling getpublickey_g"));
1586 		if (!getpublickey_g(arg->remotename,
1587 			arg->keylen, arg->algtype,
1588 			xpublic->keybuf3_val, xpublic->keybuf3_len)) {
1589 			debug(KEYSERV_DEBUG0,
1590 				("pk_crypt3 calling getpublickey_g nobody"));
1591 			if (nodefaultkeys || !getpublickey_g("nobody",
1592 				arg->keylen, arg->algtype,
1593 				xpublic->keybuf3_val, xpublic->keybuf3_len)) {
1594 				debug(KEYSERV_DEBUG,
1595 			("pk_crypt3 calling getpublickey_g nobody failed"));
1596 				if (xsecret_alloc) freekeybuf3(xsecret);
1597 				freekeybuf3(xpublic);
1598 				return (KEY_UNKNOWN);
1599 			}
1600 		}
1601 		debug(KEYSERV_DEBUG0,
1602 			("pk_crypt3 calling getpublickey_g succeeded"));
1603 	}
1604 
1605 	if ((cp = getdeskey3(arg->keylen, arg->algtype,
1606 		arg->deskey.deskeyarray_len, xpublic, xsecret, uid)) == NULL) {
1607 		if (xsecret_alloc) freekeybuf3(xsecret);
1608 		freekeybuf3(xpublic);
1609 		return (KEY_SYSTEMERR);
1610 	}
1611 	storedeskeyarray(key, &arg->deskey);
1612 	if (CLASSIC_PK_DH(arg->keylen, arg->algtype)) {
1613 		/*EMPTY*/
1614 		debug(KEYSERV_DEBUG1,
1615 			("pk_crypt3 WARNING received 192-bit key"));
1616 	} else {
1617 		debug(KEYSERV_DEBUG,
1618 			("pk_crypt3 calling __cbc_triple_crypt"));
1619 		err = __cbc_triple_crypt(cp->deskey.deskeyarray_val,
1620 			(char *)key->deskeyarray_val,
1621 			cp->deskey.deskeyarray_len*sizeof (des_block),
1622 			DES_HW | mode, ivec);
1623 		if (DES_FAILED(err)) {
1624 			debug(KEYSERV_DEBUG,
1625 		("pk_crypt3 calling ecb_crypt/__cbc_triple_crypt failed"));
1626 			if (xsecret_alloc) freekeybuf3(xsecret);
1627 			freekeybuf3(xpublic);
1628 			return (KEY_SYSTEMERR);
1629 		}
1630 		debug(KEYSERV_DEBUG,
1631 			("pk_crypt3 calling __cbc_triple_crypt succeeded"));
1632 	}
1633 	if (xsecret_alloc) freekeybuf3(xsecret);
1634 	freekeybuf3(xpublic);
1635 	return (KEY_SUCCESS);
1636 }
1637 
1638 keystatus
1639 pk_get_conv_key(uid, pubkey, result)
1640 	uid_t uid;
1641 	keybuf pubkey;
1642 	cryptkeyres *result;
1643 {
1644 	char xsecret[1024];
1645 	char xpublic[1024];
1646 	MINT *public;
1647 	MINT *secret;
1648 	MINT *common;
1649 	char zero[8];
1650 	int hash;
1651 
1652 	if (!fetchsecretkey(uid, xsecret) || xsecret[0] == 0) {
1653 		memset(zero, 0, sizeof (zero));
1654 		if (nodefaultkeys)
1655 			return (KEY_NOSECRET);
1656 
1657 		if (!getsecretkey("nobody", xsecret, zero) ||
1658 			xsecret[0] == 0)
1659 			return (KEY_NOSECRET);
1660 	}
1661 
1662 	memcpy(xpublic, pubkey, sizeof (keybuf));
1663 	xsecret[HEXKEYBYTES] = '\0';
1664 	xpublic[HEXKEYBYTES] = '\0';
1665 
1666 	hash = hash_keys(xpublic, xsecret);
1667 	(void) rw_rdlock(&g_cachedkeys_lock);
1668 	if (!readcache(xpublic, xsecret, &result->cryptkeyres_u.deskey, hash)) {
1669 		(void) rw_unlock(&g_cachedkeys_lock);
1670 		(void) rw_wrlock(&g_cachedkeys_lock);
1671 		if (!readcache(xpublic, xsecret, &result->cryptkeyres_u.deskey,
1672 									hash)) {
1673 			public = mp_xtom(xpublic);
1674 			secret = mp_xtom(xsecret);
1675 			/* Sanity Check on public and private keys */
1676 			if (public == NULL || secret == NULL) {
1677 				(void) rw_unlock(&g_cachedkeys_lock);
1678 				return (KEY_SYSTEMERR);
1679 			}
1680 			common = mp_itom(0);
1681 			mp_pow(public, secret, MODULUS, common);
1682 			extractdeskey(common, &result->cryptkeyres_u.deskey);
1683 			writecache(xpublic, xsecret,
1684 					&result->cryptkeyres_u.deskey, hash);
1685 			mp_mfree(secret);
1686 			mp_mfree(public);
1687 			mp_mfree(common);
1688 		}
1689 	}
1690 	(void) rw_unlock(&g_cachedkeys_lock);
1691 
1692 	return (KEY_SUCCESS);
1693 }
1694 
1695 #define	findsec(sec, list)	\
1696 		(memcmp(sec, (list)->secret, sizeof (keybuf)) == 0)
1697 
1698 /*
1699  * Remove common keys from the cache.
1700  */
1701 static int
1702 removecache(sec)
1703 	char *sec;
1704 {
1705 	struct cachekey_list *found;
1706 	register struct cachekey_list **l;
1707 	int i;
1708 
1709 	(void) rw_wrlock(&g_cachedkeys_lock);
1710 	for (i = 0; i < KEY_HASH_SIZE; i++) {
1711 		for (l = &g_cachedkeys[i]; (*l) != NULL; ) {
1712 			if (findsec(sec, *l)) {
1713 				found = *l;
1714 				*l = (*l)->next;
1715 				memset((char *)found, 0,
1716 					sizeof (struct cachekey_list));
1717 				free(found);
1718 			} else {
1719 				l = &(*l)->next;
1720 			}
1721 		}
1722 	}
1723 	(void) rw_unlock(&g_cachedkeys_lock);
1724 	return (1);
1725 }
1726 
1727 /*
1728  * Store the secretkey for this uid
1729  */
1730 int
1731 storesecretkey(uid, key)
1732 	uid_t uid;
1733 	keybuf key;
1734 {
1735 	struct secretkey_netname_list *new;
1736 	struct secretkey_netname_list **l;
1737 	int hash = HASH_UID(uid);
1738 
1739 	(void) rw_wrlock(&g_secretkey_netname_lock);
1740 	for (l = &g_secretkey_netname[hash]; *l != NULL && (*l)->uid != uid;
1741 			l = &(*l)->next) {
1742 	}
1743 	if (*l == NULL) {
1744 		if (key[0] == '\0') {
1745 			(void) rw_unlock(&g_secretkey_netname_lock);
1746 			return (0);
1747 		}
1748 		new = (struct secretkey_netname_list *)malloc(sizeof (*new));
1749 		if (new == NULL) {
1750 			(void) rw_unlock(&g_secretkey_netname_lock);
1751 			return (0);
1752 		}
1753 		new->uid = uid;
1754 		new->sc_flag = KEY_ONLY;
1755 		memset(new->keynetdata.st_pub_key, 0, HEXKEYBYTES);
1756 		new->keynetdata.st_netname = NULL;
1757 		new->next = NULL;
1758 		*l = new;
1759 	} else {
1760 		new = *l;
1761 		if (key[0] == '\0')
1762 			removecache(new->keynetdata.st_priv_key);
1763 	}
1764 
1765 	memcpy(new->keynetdata.st_priv_key, key,
1766 		HEXKEYBYTES);
1767 	(void) rw_unlock(&g_secretkey_netname_lock);
1768 	return (1);
1769 }
1770 
1771 static int
1772 hexdigit(val)
1773 	int val;
1774 {
1775 	return ("0123456789abcdef"[val]);
1776 }
1777 
1778 int
1779 bin2hex(bin, hex, size)
1780 	unsigned char *bin;
1781 	unsigned char *hex;
1782 	int size;
1783 {
1784 	int i;
1785 
1786 	for (i = 0; i < size; i++) {
1787 		*hex++ = hexdigit(*bin >> 4);
1788 		*hex++ = hexdigit(*bin++ & 0xf);
1789 	}
1790 	return (0);
1791 }
1792 
1793 static int
1794 hexval(dig)
1795 	char dig;
1796 {
1797 	if ('0' <= dig && dig <= '9') {
1798 		return (dig - '0');
1799 	} else if ('a' <= dig && dig <= 'f') {
1800 		return (dig - 'a' + 10);
1801 	} else if ('A' <= dig && dig <= 'F') {
1802 		return (dig - 'A' + 10);
1803 	} else {
1804 		return (-1);
1805 	}
1806 }
1807 
1808 int
1809 hex2bin(hex, bin, size)
1810 	unsigned char *hex;
1811 	unsigned char *bin;
1812 	int size;
1813 {
1814 	int i;
1815 
1816 	for (i = 0; i < size; i++) {
1817 		*bin = hexval(*hex++) << 4;
1818 		*bin++ |= hexval(*hex++);
1819 	}
1820 	return (0);
1821 }
1822 
1823 static int
1824 hash_keys(pub, sec)
1825 	char *pub;
1826 	char *sec;
1827 {
1828 	int i;
1829 	int hash = 0;
1830 
1831 	for (i = 0; i < HEXKEYBYTES; i += 6, pub += 6, sec += 6) {
1832 		hash ^= *pub;
1833 		hash ^= *sec;
1834 	}
1835 	return (hash & 0xff);
1836 }
1837 
1838 /*
1839  * problem:  keyserv loads keys from /etc/.rootkey based on nisauthconf(8)
1840  *           which is too nis+-centric (see secure_rpc(3NSL)).
1841  *
1842  * So we want to make sure there is always a AUTH_DES compat entry
1843  * in the "list" of nis+ mechs so that the 192bit key always gets loaded so
1844  * non-nis+ services that use AUTH_DES (e.g. nfs) won't get hosed.  The real
1845  * hacky part of it is we muck with the array returned from
1846  * __nis_get_mechanisms which we really don't have any business
1847  * doing cause we should not know/care how that is implemented.  A better
1848  * way would be to change the __nis_get_mechanisms interface or add another
1849  * one similiar to it that forces the "des" compat entry into the list.
1850  *
1851  * Return ptr to mechs array on success, else NULL on memory errs.
1852  */
1853 mechanism_t **
1854 getmechwrap()
1855 {
1856 	mechanism_t	**mechs = __nis_get_mechanisms(FALSE);
1857 	mechanism_t	**mechsbak = NULL;
1858 	mechanism_t	*desmech = NULL;
1859 	int		i = 0;
1860 
1861 	if (mechs) {
1862 		/* got some valid mechs and possibly the AUTH_DES compat one */
1863 		for (i = 0; mechs[i]; i++) {
1864 			if (AUTH_DES_COMPAT_CHK(mechs[i]))
1865 				return (mechs);
1866 		}
1867 		/* i == number of ptrs not counting terminating NULL */
1868 	}
1869 
1870 	/* AUTH_DES compat entry not found, let's add it */
1871 	if ((desmech = malloc(sizeof (mechanism_t))) == NULL) {
1872 		if (mechs)
1873 			__nis_release_mechanisms(mechs);
1874 		return (NULL);
1875 	}
1876 	desmech->mechname = NULL;
1877 	desmech->alias = NIS_SEC_CF_DES_ALIAS;
1878 	desmech->keylen = AUTH_DES_KEYLEN;
1879 	desmech->algtype = AUTH_DES_ALGTYPE;
1880 	desmech->qop = NULL;
1881 	desmech->secserv = rpc_gss_svc_default;
1882 
1883 	mechsbak = mechs;
1884 	/* mechs == NULL and i == 0 is valid "no mechs configed" case */
1885 	if ((mechs = (mechanism_t **)realloc(mechs,
1886 			sizeof (mechanism_t *) * (i + 2))) == NULL) {
1887 		if (mechsbak)
1888 			__nis_release_mechanisms(mechsbak);
1889 		free(desmech);
1890 		return (NULL);
1891 	}
1892 	mechs[i] = desmech;
1893 	mechs[i+1] = NULL;
1894 
1895 	return (mechs);
1896 }
1897 
1898 int
1899 init_mechs()
1900 {
1901 	int nmechs, oldmechseen;
1902 	mechanism_t **mechpp;
1903 	char **cpp;
1904 
1905 	if (!(mechs = getmechwrap()))
1906 		return (-1);
1907 
1908 	/*
1909 	 * find how many mechanisms were specified and also
1910 	 * setup the mechanism table for unique keylen/algtype pair
1911 	 */
1912 	nmechs = 0;
1913 	for (mechpp = mechs; *mechpp != NULL; mechpp++) {
1914 		struct keylenlist **kpp;
1915 		struct algtypelist **app;
1916 
1917 		nmechs++;
1918 		if (((*mechpp)->keylen < 0) || ((*mechpp)->algtype < 0)) {
1919 			continue;
1920 		}
1921 		kpp = getkeylen((*mechpp)->keylen);
1922 		appendkeylist(kpp, (*mechpp)->keylen);
1923 		app = getalgtype(kpp, (*mechpp)->algtype);
1924 		appendalgtype(app, (*mechpp)->algtype);
1925 	}
1926 
1927 	/*
1928 	 * set of mechs for getsubopt()
1929 	 */
1930 	cache_options = (char **)calloc((size_t)nmechs + 1,
1931 	    sizeof (*cache_options));
1932 	if (cache_options == NULL) {
1933 		(void) fprintf(stderr, "unable to allocate option array");
1934 		return (-1);
1935 	}
1936 	/*
1937 	 * cache sizes
1938 	 */
1939 	cache_size = (int *)calloc((size_t)nmechs, sizeof (int));
1940 	if (cache_size == NULL) {
1941 		(void) fprintf(stderr, "unable to allocate cache array");
1942 		return (-1);
1943 	}
1944 
1945 	oldmechseen = 0;
1946 	cpp = cache_options;
1947 	for (mechpp = mechs; *mechpp != NULL; mechpp++) {
1948 		/*
1949 		 * usual case: a DH-style mechanism type, with an alias
1950 		 */
1951 		if ((*mechpp)->mechname != NULL &&
1952 		    strncmp((*mechpp)->mechname, DHMECHSTR,
1953 		    strlen(DHMECHSTR)) == 0 &&
1954 		    (*mechpp)->alias != NULL) {
1955 			/*
1956 			 * Is this trad 192-DH? already added?
1957 			 */
1958 			if (strcmp((*mechpp)->alias, DESALIAS) == 0) {
1959 				if (oldmechseen) {
1960 					continue;
1961 				}
1962 				oldmechseen++;
1963 			}
1964 
1965 			*cpp++ = (*mechpp)->alias;
1966 			continue;
1967 		}
1968 
1969 		/*
1970 		 * HACK: we recognise a special alias for traditional
1971 		 * 192-bit DH, unless the latter has already been mentioned
1972 		 * in it's full form
1973 		 */
1974 		if ((*mechpp)->mechname == NULL && (*mechpp)->alias != NULL &&
1975 		    strcmp((*mechpp)->alias, DES) == 0 && !oldmechseen) {
1976 			*cpp++ = DESALIAS;
1977 			oldmechseen++;
1978 			continue;
1979 		}
1980 
1981 		/*
1982 		 * Ignore anything else
1983 		 */
1984 	}
1985 
1986 	/* Terminate the options list */
1987 	*cpp = NULL;
1988 
1989 	return (0);
1990 }
1991