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