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
60extern char ROOTKEY[];
61extern mechanism_t **mechs;
62extern char **cache_options;
63extern int *cache_size;
64extern int disk_caching;
65
66static MINT *MODULUS;
67static int hash_keys();
68static keystatus pk_crypt();
69static keystatus pk_crypt3();
70static 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 */
80struct cachekey_list {
81	keybuf secret;
82	keybuf public;
83	des_block deskey;
84	struct cachekey_list *next;
85};
86#define	KEY_HASH_SIZE	256
87static struct cachekey_list *g_cachedkeys[KEY_HASH_SIZE];
88static rwlock_t g_cachedkeys_lock = DEFAULTRWLOCK;
89
90#ifdef DEBUG
91int
92test_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
100int
101real_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
114struct 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
127struct mechdata {
128	struct cacheuid_list *bucket[NUMHASHBUCKETS];
129};
130
131struct psdata {
132	struct cachekey3_list *common[NUMHASHBUCKETS];
133};
134
135struct 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 */
149struct algtypelist {
150	algtype_t algtype;
151	struct algtypelist *next;
152	struct mechentry mech;
153};
154
155struct keylenlist {
156	keylen_t keylen;
157	struct algtypelist *ap;
158	struct keylenlist *next;
159};
160
161#define	KEYSERV_VERSION	"1.0"
162
163static struct mechtable {
164	char *version;
165	struct keylenlist *kp;
166} mechtable = {KEYSERV_VERSION, NULL};
167
168static struct keylenlist **
169getkeylen(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
182static void
183appendkeylist(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
206static struct algtypelist **
207getalgtype(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
220static void
221appendalgtype(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
247static struct mechentry *
248getmechtype(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
269static keybuf3 *
270getkeybuf3(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
300static void
301freekeybuf3(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
313static keybuf3 *
314cpykeybuf3(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
329static keybuf3 *
330setkeybuf3(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
341static int
342cmpkeybuf3(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
355static int
356storekeybuf3(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
370static deskeyarray *
371getdeskeyarray(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
402static deskeyarray *
403cpydeskeyarray(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
419static int
420storedeskeyarray(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
434int
435setdeskeyarray(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
449static int
450cachehit3(keybuf3 *public, keybuf3 *secret, struct cachekey3_list *cp)
451{
452	return (cmpkeybuf3(public, cp->public) &&
453		cmpkeybuf3(secret, cp->secret));
454}
455
456static struct cacheuid_list **
457mapuid2cache(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
472static int
473appendsecretkey3(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 */
531static int
532storesecretkey3(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 */
548keystatus
549pk_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 */
560keystatus
561pk_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
573int
574storeotherrootkeys(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 */
634int
635pk_nodefaultkeys()
636{
637	nodefaultkeys = 1;
638	return (0);
639}
640
641static void
642freedisklist(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
652keystatus
653pk_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 */
690int
691setmodulus(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 */
702keystatus
703pk_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 */
716keystatus
717pk_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 */
730keystatus
731pk_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 */
744keystatus
745pk_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
760struct 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)
768static struct secretkey_netname_list *g_secretkey_netname[KEY_HASH_SIZE];
769static rwlock_t g_secretkey_netname_lock = DEFAULTRWLOCK;
770
771/*
772 * Store the keys and netname for this uid
773 */
774static int
775store_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
816static int
817appendnetname3(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
872keystatus
873pk_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 */
887static int
888store_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
913keystatus
914pk_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
923int
924addmasterkey(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 */
959static int
960fetch_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
990static void
991remove_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
1003static void
1004add_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
1018static struct cacheuid_list *
1019getcachekey3(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 */
1045static struct cacheuid_list *
1046getanycache3(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
1078static struct cacheuid_list *
1079fetchcache3(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 */
1098static int
1099fetch_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
1135keystatus
1136pk_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
1146keystatus
1147pk_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 */
1162static int
1163readcache(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 */
1183static int
1184writecache(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 */
1209static int
1210extractdeskey(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
1236static bool_t
1237fetchsecretkey(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
1257static keybuf3 *
1258fetchsecretkey3(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 */
1273static keystatus
1274pk_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
1344static int
1345hash_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
1364static struct cachekey3_list **
1365map_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
1380static struct cachekey3_list *
1381getdeskey3(
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
1494keystatus
1495pk_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 */
1536static keystatus
1537pk_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
1640keystatus
1641pk_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 */
1703static int
1704removecache(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 */
1732int
1733storesecretkey(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
1773static int
1774hexdigit(val)
1775	int val;
1776{
1777	return ("0123456789abcdef"[val]);
1778}
1779
1780int
1781bin2hex(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
1795static int
1796hexval(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
1810int
1811hex2bin(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
1825static int
1826hash_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 */
1855mechanism_t **
1856getmechwrap()
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
1900int
1901init_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