8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / keyserv / setkey.c
blob39ac5dfaef95568b26168f2520e0d393f3e946e6
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * University Copyright- Copyright (c) 1982, 1986, 1988
29 * The Regents of the University of California
30 * All Rights Reserved
32 * University Acknowledgment- Portions of this document are derived from
33 * software developed by the University of California, Berkeley, and its
34 * contributors.
37 #pragma ident "%Z%%M% %I% %E% SMI"
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.
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>
57 #include "debug.h"
58 #include "keyserv_cache.h"
60 extern char ROOTKEY[];
61 extern mechanism_t **mechs;
62 extern char **cache_options;
63 extern int *cache_size;
64 extern int disk_caching;
66 static MINT *MODULUS;
67 static int hash_keys();
68 static keystatus pk_crypt();
69 static keystatus pk_crypt3();
70 static int nodefaultkeys = 0;
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))
78 * Exponential caching management
80 struct cachekey_list {
81 keybuf secret;
82 keybuf public;
83 des_block deskey;
84 struct cachekey_list *next;
86 #define KEY_HASH_SIZE 256
87 static struct cachekey_list *g_cachedkeys[KEY_HASH_SIZE];
88 static rwlock_t g_cachedkeys_lock = DEFAULTRWLOCK;
90 #ifdef DEBUG
91 int
92 test_debug(debug_level level, char *file, int line)
94 if (level < debugging)
95 return (0);
96 fprintf(stderr, "file %s,\tline %d :\t", file, line);
97 return (1);
101 real_debug(char *fmt, ...)
103 va_list args;
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);
112 #endif /* DEBUG */
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;
124 #define NUMHASHBUCKETS 256
125 #define HASH_UID(x) (x & 0xff)
127 struct mechdata {
128 struct cacheuid_list *bucket[NUMHASHBUCKETS];
131 struct psdata {
132 struct cachekey3_list *common[NUMHASHBUCKETS];
135 struct mechentry {
136 mutex_t mech_lock;
137 struct mechdata *mechdata;
138 mutex_t ps_lock;
139 struct psdata *psdata;
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.
149 struct algtypelist {
150 algtype_t algtype;
151 struct algtypelist *next;
152 struct mechentry mech;
155 struct keylenlist {
156 keylen_t keylen;
157 struct algtypelist *ap;
158 struct keylenlist *next;
161 #define KEYSERV_VERSION "1.0"
163 static struct mechtable {
164 char *version;
165 struct keylenlist *kp;
166 } mechtable = {KEYSERV_VERSION, NULL};
168 static struct keylenlist **
169 getkeylen(keylen_t k)
171 struct keylenlist **kpp;
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);
182 static void
183 appendkeylist(struct keylenlist **kpp, keylen_t k)
185 struct keylenlist *kp;
187 if (*kpp == NULL) {
188 kp = (struct keylenlist *)malloc(sizeof (*kp));
189 if (kp == NULL) {
190 debug(KEYSERV_INFO, ("appendkeylist : malloc failed"));
191 return;
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"));
206 static struct algtypelist **
207 getalgtype(struct keylenlist **kpp, algtype_t a)
209 struct algtypelist **app;
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);
220 static void
221 appendalgtype(struct algtypelist **app, algtype_t a)
223 struct algtypelist *ap;
225 if (*app == NULL) {
226 ap = (struct algtypelist *)malloc(sizeof (*ap));
227 if (ap == NULL) {
228 debug(KEYSERV_INFO, ("appendalgtype : malloc failed"));
229 return;
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"));
247 static struct mechentry *
248 getmechtype(keylen_t k, algtype_t a)
250 struct keylenlist **kpp;
251 struct algtypelist **app;
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);
259 app = getalgtype(kpp, a);
260 if (*app == NULL) {
261 debug(KEYSERV_DEBUG0, ("getmechtype %d not found in algs", a));
262 return (0);
264 debug(KEYSERV_DEBUG0, ("getmechtype found %x", app));
265 debug(KEYSERV_DEBUG0, ("getmechtype return %x", &(*app)->mech));
266 return (&(*app)->mech);
269 static keybuf3 *
270 getkeybuf3(int k)
272 keybuf3 *buf;
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);
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);
296 debug(KEYSERV_DEBUG1, ("getkeybuf3 ret %x", buf));
297 return (buf);
300 static void
301 freekeybuf3(keybuf3 *kp)
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);
310 free(kp);
313 static keybuf3 *
314 cpykeybuf3(keybuf3 *src)
316 keybuf3 *dst;
318 if (src == NULL) {
319 return (NULL);
321 if ((dst = getkeybuf3(src->keybuf3_len)) == NULL) {
322 return (NULL);
324 memcpy(dst->keybuf3_val, src->keybuf3_val, src->keybuf3_len);
325 debug(KEYSERV_DEBUG0, ("cpykeybuf3 ret %x", dst));
326 return (dst);
329 static keybuf3 *
330 setkeybuf3(char *src, int len)
332 keybuf3 *dst;
334 if ((dst = getkeybuf3(++len)) == NULL) {
335 return (NULL);
337 memcpy(dst->keybuf3_val, src, len);
338 return (dst);
341 static int
342 cmpkeybuf3(keybuf3 *k1, keybuf3 *k2)
344 if ((k1 == NULL) || (k2 == NULL)) {
345 syslog(LOG_ERR, "cmpkeybuf3: invalid parameter: %x, %x",
346 k1, k2);
347 return (0);
349 if (k1->keybuf3_len != k2->keybuf3_len) {
350 return (0);
352 return (!memcmp(k1->keybuf3_val, k2->keybuf3_val, k1->keybuf3_len));
355 static int
356 storekeybuf3(keybuf3 *dst, keybuf3 *src)
358 keybuf3 *tmp;
360 if ((tmp = cpykeybuf3(src)) == NULL) {
361 return (0);
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);
370 static deskeyarray *
371 getdeskeyarray(int k)
373 deskeyarray *buf;
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);
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);
398 debug(KEYSERV_DEBUG1, ("getdeskeyarray ret %x", buf));
399 return (buf);
402 static deskeyarray *
403 cpydeskeyarray(deskeyarray *src)
405 deskeyarray *dst;
407 if (src == NULL) {
408 return (NULL);
410 if ((dst = getdeskeyarray(src->deskeyarray_len)) == NULL) {
411 return (NULL);
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);
419 static int
420 storedeskeyarray(deskeyarray *dst, deskeyarray *src)
422 deskeyarray *tmp;
424 if ((tmp = cpydeskeyarray(src)) == NULL) {
425 return (0);
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);
435 setdeskeyarray(deskeyarray *dst, int k)
437 deskeyarray *tmp;
439 if ((tmp = getdeskeyarray(k)) == NULL) {
440 return (0);
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);
449 static int
450 cachehit3(keybuf3 *public, keybuf3 *secret, struct cachekey3_list *cp)
452 return (cmpkeybuf3(public, cp->public) &&
453 cmpkeybuf3(secret, cp->secret));
456 static struct cacheuid_list **
457 mapuid2cache(uid_t uid, struct mechdata *mdp)
459 struct cacheuid_list **cpp;
460 int hash = HASH_UID(uid);
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));
468 debug(KEYSERV_DEBUG, ("mapuid2cache ret %x", cpp));
469 return (cpp);
472 static int
473 appendsecretkey3(struct mechentry *mp, uid_t uid, setkeyarg3 *skey)
475 struct mechdata *mdp;
476 struct cacheuid_list **cpp, *cp;
477 keybuf3 nullkey = {0, NULL};
479 debug(KEYSERV_DEBUG, ("appendsecretkey3 %x", mp));
480 if ((skey == NULL) || (mp == NULL)) {
481 return (0);
483 if (skey->key.keybuf3_len == 0) {
484 return (0);
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);
495 mp->mechdata = mdp;
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);
508 memset(cp, 0, sizeof (*cp));
509 cp->uid = uid;
510 *cpp = cp;
511 } else {
512 cp = *cpp;
514 freekeybuf3(cp->secretkey);
515 if ((cp->secretkey = cpykeybuf3(&skey->key)) == NULL) {
516 mutex_unlock(&mp->mech_lock);
517 return (0);
519 freekeybuf3(cp->publickey);
520 if ((cp->publickey = cpykeybuf3(&nullkey)) == NULL) {
521 mutex_unlock(&mp->mech_lock);
522 return (0);
524 mutex_unlock(&mp->mech_lock);
525 return (1);
529 * Store the vers 3 secretkey for this uid
531 static int
532 storesecretkey3(uid_t uid, setkeyarg3 *skey)
534 struct mechentry *mp;
536 if (skey == NULL) {
537 return (0);
539 if ((mp = getmechtype(skey->keylen, skey->algtype)) == NULL) {
540 return (0);
542 return (appendsecretkey3(mp, uid, skey));
546 * Set the vers 3 secretkey key for this uid
548 keystatus
549 pk_setkey3(uid_t uid, setkeyarg3 *skey)
551 if (!storesecretkey3(uid, skey)) {
552 return (KEY_SYSTEMERR);
554 return (KEY_SUCCESS);
558 * Set the secretkey key for this uid
560 keystatus
561 pk_setkey(uid, skey)
562 uid_t uid;
563 keybuf skey;
565 int storesecretkey(uid_t, keybuf);
567 if (!storesecretkey(uid, skey)) {
568 return (KEY_SYSTEMERR);
570 return (KEY_SUCCESS);
574 storeotherrootkeys(FILE *fp, char *netname, char *passwd, char *osecret)
576 des_block master;
577 struct keylenlist *kp;
578 struct algtypelist *ap;
579 keybuf3 *secret;
580 setkeyarg3 skey;
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);
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);
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);
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);
619 if (pk_setkey3(0, &skey) != KEY_SUCCESS) {
620 return (0);
622 if (!CLASSIC_PK_DH(kp->keylen, ap->algtype)) {
623 fprintf(fp, "%s %d\n", skey.key.keybuf3_val,
624 ap->algtype);
628 return (1);
632 * prohibit the nobody key on this machine k (the -d flag)
635 pk_nodefaultkeys()
637 nodefaultkeys = 1;
638 return (0);
641 static void
642 freedisklist(struct cacheuid_list *cp)
644 if (cp == NULL) {
645 return;
647 free(cp->netname); /* ok even if this is NULL */
648 freekeybuf3(cp->secretkey);
649 freekeybuf3(cp->publickey);
652 keystatus
653 pk_clear3(uid_t uid)
655 struct keylenlist *kp;
656 struct algtypelist *ap;
657 struct mechdata *mdp;
658 struct cacheuid_list **cpp, *cp;
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;
671 cpp = mapuid2cache(uid, mdp);
672 if (*cpp == NULL) {
673 mutex_unlock(&ap->mech.mech_lock);
674 continue;
676 cp = (*cpp)->next;
677 freedisklist(*cpp);
678 *cpp = cp;
679 mutex_unlock(&ap->mech.mech_lock);
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);
688 * Set the modulus for all our Diffie-Hellman operations
691 setmodulus(modx)
692 char *modx;
694 MODULUS = mp_xtom(modx);
695 return (0);
699 * Encrypt the key using the public key associated with remote_name and the
700 * secret key associated with uid.
702 keystatus
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;
709 return (pk_crypt(uid, remote_name, remote_key, key, DES_ENCRYPT));
713 * Encrypt the key using the public key associated with remote_name and the
714 * secret key associated with uid using vers 3
716 keystatus
717 pk_encrypt3(
718 uid_t uid,
719 cryptkeyarg3 *arg,
720 deskeyarray *key
723 return (pk_crypt3(uid, arg, key, DES_ENCRYPT));
727 * Decrypt the key using the public key associated with remote_name and the
728 * secret key associated with uid.
730 keystatus
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;
737 return (pk_crypt(uid, remote_name, remote_key, key, DES_DECRYPT));
741 * Decrypt the key using the public key associated with remote_name and the
742 * secret key associated with uid using vers 3
744 keystatus
745 pk_decrypt3(
746 uid_t uid,
747 cryptkeyarg3 *arg,
748 deskeyarray *key
751 return (pk_crypt3(uid, arg, key, DES_DECRYPT));
755 * Key storage management
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;
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;
772 * Store the keys and netname for this uid
774 static int
775 store_netname(uid, netstore)
776 uid_t uid;
777 key_netstarg *netstore;
779 struct secretkey_netname_list *new;
780 struct secretkey_netname_list **l;
781 int hash = HASH_UID(uid);
783 (void) rw_wrlock(&g_secretkey_netname_lock);
784 for (l = &g_secretkey_netname[hash]; *l != NULL && (*l)->uid != uid;
785 l = &(*l)->next) {
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);
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);
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);
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);
816 static int
817 appendnetname3(struct mechentry *mp, uid_t uid, key_netstarg3 *net)
819 struct mechdata *mdp;
820 struct cacheuid_list **cpp, *cp;
822 debug(KEYSERV_DEBUG, ("appendnetname3 %x", mp));
823 if ((mp == NULL) || (net == NULL)) {
824 return (0);
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);
834 mp->mechdata = mdp;
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);
846 memset(cp, 0, sizeof (*cp));
847 cp->uid = uid;
848 *cpp = cp;
849 } else {
850 cp = *cpp;
852 freekeybuf3(cp->secretkey);
853 if ((cp->secretkey = cpykeybuf3(&net->st_priv_key)) == NULL) {
854 mutex_unlock(&mp->mech_lock);
855 return (0);
857 freekeybuf3(cp->publickey);
858 if ((cp->publickey = cpykeybuf3(&net->st_pub_key)) == NULL) {
859 mutex_unlock(&mp->mech_lock);
860 return (0);
862 free(cp->netname);
863 if (net->st_netname) {
864 cp->netname = strdup(net->st_netname);
865 } else {
866 cp->netname = (char *)NULL;
868 mutex_unlock(&mp->mech_lock);
869 return (1);
872 keystatus
873 pk_netput(uid, netstore)
874 uid_t uid;
875 key_netstarg *netstore;
878 if (!store_netname(uid, netstore)) {
879 return (KEY_SYSTEMERR);
881 return (KEY_SUCCESS);
885 * Store the keys and netname for this uid vers 3
887 static int
888 store_netname3(uid_t uid, key_netstarg3 *net)
890 struct mechentry *mp;
891 key_netstarg netstore;
893 if (net == NULL) {
894 return (0);
896 if ((mp = getmechtype(net->keylen, net->algtype)) == NULL) {
897 return (0);
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);
910 return (appendnetname3(mp, uid, net));
913 keystatus
914 pk_netput3(uid_t uid, key_netstarg3 *netstore)
917 if (!store_netname3(uid, netstore)) {
918 return (KEY_SYSTEMERR);
920 return (KEY_SUCCESS);
924 addmasterkey(char *master, char *netname, algtype_t algtype)
926 keybuf3 *secret, *public;
927 int bytelen = strlen(master);
928 keylen_t keylen = bytelen*4;
929 key_netstarg3 tmp;
931 if ((secret = setkeybuf3(master, bytelen)) == NULL) {
932 return (0);
934 if ((public = getkeybuf3(bytelen+1)) == NULL) {
935 /* the +1 is mandated by getpublickey_g() */
936 return (0);
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
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));
957 * Fetch the keys and netname for this uid
959 static int
960 fetch_netname(uid, key_netst)
961 uid_t uid;
962 struct key_netstarg *key_netst;
964 struct secretkey_netname_list *l;
965 int hash = HASH_UID(uid);
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)) {
971 memcpy(key_netst->st_priv_key,
972 l->keynetdata.st_priv_key, HEXKEYBYTES);
974 memcpy(key_netst->st_pub_key,
975 l->keynetdata.st_pub_key, HEXKEYBYTES);
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);
986 (void) rw_unlock(&g_secretkey_netname_lock);
987 return (0);
990 static void
991 remove_ref(struct cacheuid_list *cp)
993 debug(KEYSERV_DEBUG0, ("remove_ref %x", cp));
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.
1000 cp->refcnt--;
1003 static void
1004 add_ref(struct cacheuid_list **cpp)
1006 struct cacheuid_list *cp;
1008 if (cpp == NULL) {
1009 return;
1011 /*LINTED assignment operator "=" found where "==" was expected*/
1012 if (cp = *cpp) {
1013 debug(KEYSERV_DEBUG0, ("add_ref %x", cp));
1014 cp->refcnt++;
1018 static struct cacheuid_list *
1019 getcachekey3(uid_t uid, struct mechentry *mp)
1021 struct cacheuid_list **cpp, *cp;
1022 struct mechdata *mdp;
1024 debug(KEYSERV_DEBUG1, ("getcachekey3 %d %x", uid, mp));
1025 if (mp == NULL) {
1026 return (0);
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);
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);
1043 * Fetch any available cache for this uid (vers 3)
1045 static struct cacheuid_list *
1046 getanycache3(uid_t uid)
1048 struct keylenlist *kp;
1049 struct algtypelist *ap;
1050 struct mechdata *mdp;
1051 struct cacheuid_list **cpp, *cp;
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;
1064 cpp = mapuid2cache(uid, mdp);
1065 if (*cpp == NULL) {
1066 mutex_unlock(&ap->mech.mech_lock);
1067 continue;
1069 cp = *cpp;
1070 cp->refcnt++;
1071 mutex_unlock(&ap->mech.mech_lock);
1072 return (cp);
1075 return (NULL);
1078 static struct cacheuid_list *
1079 fetchcache3(uid_t uid, keylen_t k, algtype_t a)
1081 struct mechentry *mp;
1082 struct cacheuid_list *cp;
1084 debug(KEYSERV_DEBUG, ("fetchcache3 %d %d %d", uid, k, a));
1085 if ((mp = getmechtype(k, a)) == NULL) {
1086 return (NULL);
1088 if ((cp = getcachekey3(uid, mp)) == NULL) {
1089 return (NULL);
1091 debug(KEYSERV_DEBUG, ("fetchcache3 ret %x", cp));
1092 return (cp);
1096 * Fetch the keys and netname for this uid vers 3
1098 static int
1099 fetch_netname3(uid_t uid, mechtype *net, key_netstarg3 *ret)
1101 struct cacheuid_list *cp;
1103 if ((net == NULL) || (ret == NULL)) {
1104 return (0);
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);
1113 debug(KEYSERV_DEBUG, ("fetch_netname3 cp %x", cp));
1114 if (cp == NULL) {
1115 return (0);
1117 debug(KEYSERV_DEBUG, ("fetch_netname3 sec %x", cp->secretkey));
1118 if (!storekeybuf3(&ret->st_priv_key, cp->secretkey)) {
1119 return (0);
1121 debug(KEYSERV_DEBUG, ("fetch_netname3 pub %x", cp->publickey));
1122 if (!storekeybuf3(&ret->st_pub_key, cp->publickey)) {
1123 return (0);
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;
1131 remove_ref(cp);
1132 return (1);
1135 keystatus
1136 pk_netget(uid, netstore)
1137 uid_t uid;
1138 key_netstarg *netstore;
1140 if (!fetch_netname(uid, netstore)) {
1141 return (KEY_SYSTEMERR);
1143 return (KEY_SUCCESS);
1146 keystatus
1147 pk_netget3(uid_t uid, mechtype *net, key_netstarg3 *ret)
1149 if (!fetch_netname3(uid, net, ret)) {
1150 return (KEY_SYSTEMERR);
1152 return (KEY_SUCCESS);
1155 #define cachehit(pub, sec, list) \
1156 (memcmp(pub, (list)->public, sizeof (keybuf)) == 0 && \
1157 memcmp(sec, (list)->secret, sizeof (keybuf)) == 0)
1160 * Try to find the common key in the cache
1162 static int
1163 readcache(pub, sec, deskey, hash)
1164 char *pub;
1165 char *sec;
1166 des_block *deskey;
1167 int hash;
1169 register struct cachekey_list **l;
1171 for (l = &g_cachedkeys[hash]; (*l) != NULL && !cachehit(pub, sec, *l);
1172 l = &(*l)->next)
1174 if ((*l) == NULL)
1175 return (0);
1176 *deskey = (*l)->deskey;
1177 return (1);
1181 * cache result of expensive multiple precision exponential operation
1183 static int
1184 writecache(pub, sec, deskey, hash)
1185 char *pub;
1186 char *sec;
1187 des_block *deskey;
1188 int hash;
1190 struct cachekey_list *new;
1192 new = (struct cachekey_list *)malloc(sizeof (struct cachekey_list));
1193 if (new == NULL) {
1194 return (0);
1196 memcpy(new->public, pub, sizeof (keybuf));
1197 memcpy(new->secret, sec, sizeof (keybuf));
1198 new->deskey = *deskey;
1200 new->next = g_cachedkeys[hash];
1201 g_cachedkeys[hash] = new;
1202 return (1);
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.
1209 static int
1210 extractdeskey(ck, deskey)
1211 MINT *ck;
1212 des_block *deskey;
1214 void _mp_move(MINT *, MINT *);
1215 MINT *a;
1216 short r;
1217 int i;
1218 short base = (1 << 8);
1219 char *k;
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);
1226 k = deskey->c;
1227 for (i = 0; i < 8; i++) {
1228 mp_sdiv(a, base, a, &r);
1229 *k++ = r;
1231 mp_mfree(a);
1232 des_setparity((char *)deskey);
1233 return (0);
1236 static bool_t
1237 fetchsecretkey(uid, buf)
1238 uid_t uid;
1239 char *buf;
1241 struct secretkey_netname_list *l;
1242 int hash = HASH_UID(uid);
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);
1253 (void) rw_unlock(&g_secretkey_netname_lock);
1254 return (FALSE);
1257 static keybuf3 *
1258 fetchsecretkey3(uid_t uid, keylen_t k, algtype_t a)
1260 struct cacheuid_list *cp;
1262 debug(KEYSERV_DEBUG, ("fetchsecretkey3 %d %d %d", uid, k, a));
1263 if ((cp = fetchcache3(uid, k, a)) == NULL) {
1264 return (NULL);
1266 debug(KEYSERV_DEBUG, ("fetchsecretkey3 ret %x", cp->secretkey));
1267 return (cp->secretkey);
1271 * Do the work of pk_encrypt && pk_decrypt
1273 static keystatus
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;
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;
1291 if (!fetchsecretkey(uid, xsecret) || xsecret[0] == 0) {
1292 memset(zero, 0, sizeof (zero));
1293 if (nodefaultkeys)
1294 return (KEY_NOSECRET);
1296 if (!getsecretkey("nobody", xsecret, zero) || xsecret[0] == 0) {
1297 return (KEY_NOSECRET);
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);
1309 xsecret[HEXKEYBYTES] = '\0';
1310 xpublic[HEXKEYBYTES] = '\0';
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);
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);
1334 (void) rw_unlock(&g_cachedkeys_lock);
1336 err = ecb_crypt((char *)&deskey, (char *)key, sizeof (des_block),
1337 DES_HW | mode);
1338 if (DES_FAILED(err)) {
1339 return (KEY_SYSTEMERR);
1341 return (KEY_SUCCESS);
1344 static int
1345 hash_keys3(keybuf3 *p, keybuf3 *s)
1347 int i;
1348 int hash = 0;
1349 char *pub = p->keybuf3_val;
1350 char *sec = s->keybuf3_val;
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;
1360 debug(KEYSERV_DEBUG, ("hash_keys3 ret %d", hash & 0xff));
1361 return (hash & 0xff);
1364 static struct cachekey3_list **
1365 map_ps2cache(keybuf3 *public, keybuf3 *secret, struct psdata *pdp)
1367 struct cachekey3_list **cpp;
1368 int hash = hash_keys3(public, secret);
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));
1376 debug(KEYSERV_DEBUG, ("map_ps2cache ret %x", cpp));
1377 return (cpp);
1380 static struct cachekey3_list *
1381 getdeskey3(
1382 keylen_t keylen,
1383 algtype_t algtype,
1384 int desarylen,
1385 keybuf3 *public,
1386 keybuf3 *secret,
1387 uid_t uid
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;
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);
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);
1410 mp->psdata = pdp;
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);
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);
1445 cp->refcnt = 0;
1446 cp->next = NULL;
1447 if ((cp->public = cpykeybuf3(public)) == NULL) {
1448 mutex_unlock(&mp->ps_lock);
1449 return (0);
1451 if ((cp->secret = cpykeybuf3(secret)) == NULL) {
1452 mutex_unlock(&mp->ps_lock);
1453 return (0);
1455 if (!setdeskeyarray(&cp->deskey, desarylen)) {
1456 mutex_unlock(&mp->ps_lock);
1457 return (0);
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);
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));
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);
1484 *cpp = cp;
1485 } else {
1486 cp = *cpp;
1488 cp->refcnt++;
1489 mutex_unlock(&mp->ps_lock);
1490 debug(KEYSERV_DEBUG, ("getdeskey3 ret %x", cp));
1491 return (cp);
1494 keystatus
1495 pk_get_conv_key3(uid_t uid, deskeyarg3 *arg, cryptkeyres3 *res)
1497 keybuf3 *xsecret, *xpublic;
1498 char zero[8];
1499 struct cachekey3_list *cp;
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);
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);
1521 debug(KEYSERV_DEBUG,
1522 ("pk_get_conv_key3 calling getsecretkey_g succeeded"));
1524 xpublic = &arg->pub_key;
1525 if ((cp = getdeskey3(arg->keylen, arg->algtype, arg->nkeys,
1526 xpublic, xsecret, uid)) == NULL) {
1527 return (KEY_SYSTEMERR);
1529 storedeskeyarray(&res->cryptkeyres3_u.deskey, &cp->deskey);
1530 return (KEY_SUCCESS);
1534 * Do the work of pk_encrypt3 && pk_decrypt3
1536 static keystatus
1537 pk_crypt3(
1538 uid_t uid,
1539 cryptkeyarg3 *arg,
1540 deskeyarray *key,
1541 int mode
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];
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);
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);
1573 /* XXX optimize to cache nobody's secret key? */
1574 debug(KEYSERV_DEBUG0,
1575 ("pk_crypt3 calling getsecretkey_g succeeded"));
1577 if (arg->remotekey.keybuf3_len) {
1578 if ((xpublic = cpykeybuf3(&arg->remotekey)) == NULL) {
1579 if (xsecret_alloc) freekeybuf3(xsecret);
1580 return (KEY_SYSTEMERR);
1582 } else {
1583 if ((xpublic = getkeybuf3(arg->keylen/4+1)) == NULL) {
1584 if (xsecret_alloc) freekeybuf3(xsecret);
1585 return (KEY_SYSTEMERR);
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);
1603 debug(KEYSERV_DEBUG0,
1604 ("pk_crypt3 calling getpublickey_g succeeded"));
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);
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);
1632 debug(KEYSERV_DEBUG,
1633 ("pk_crypt3 calling __cbc_triple_crypt succeeded"));
1635 if (xsecret_alloc) freekeybuf3(xsecret);
1636 freekeybuf3(xpublic);
1637 return (KEY_SUCCESS);
1640 keystatus
1641 pk_get_conv_key(uid, pubkey, result)
1642 uid_t uid;
1643 keybuf pubkey;
1644 cryptkeyres *result;
1646 char xsecret[1024];
1647 char xpublic[1024];
1648 MINT *public;
1649 MINT *secret;
1650 MINT *common;
1651 char zero[8];
1652 int hash;
1654 if (!fetchsecretkey(uid, xsecret) || xsecret[0] == 0) {
1655 memset(zero, 0, sizeof (zero));
1656 if (nodefaultkeys)
1657 return (KEY_NOSECRET);
1659 if (!getsecretkey("nobody", xsecret, zero) ||
1660 xsecret[0] == 0)
1661 return (KEY_NOSECRET);
1664 memcpy(xpublic, pubkey, sizeof (keybuf));
1665 xsecret[HEXKEYBYTES] = '\0';
1666 xpublic[HEXKEYBYTES] = '\0';
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);
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);
1692 (void) rw_unlock(&g_cachedkeys_lock);
1694 return (KEY_SUCCESS);
1697 #define findsec(sec, list) \
1698 (memcmp(sec, (list)->secret, sizeof (keybuf)) == 0)
1701 * Remove common keys from the cache.
1703 static int
1704 removecache(sec)
1705 char *sec;
1707 struct cachekey_list *found;
1708 register struct cachekey_list **l;
1709 int i;
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;
1725 (void) rw_unlock(&g_cachedkeys_lock);
1726 return (1);
1730 * Store the secretkey for this uid
1733 storesecretkey(uid, key)
1734 uid_t uid;
1735 keybuf key;
1737 struct secretkey_netname_list *new;
1738 struct secretkey_netname_list **l;
1739 int hash = HASH_UID(uid);
1741 (void) rw_wrlock(&g_secretkey_netname_lock);
1742 for (l = &g_secretkey_netname[hash]; *l != NULL && (*l)->uid != uid;
1743 l = &(*l)->next) {
1745 if (*l == NULL) {
1746 if (key[0] == '\0') {
1747 (void) rw_unlock(&g_secretkey_netname_lock);
1748 return (0);
1750 new = (struct secretkey_netname_list *)malloc(sizeof (*new));
1751 if (new == NULL) {
1752 (void) rw_unlock(&g_secretkey_netname_lock);
1753 return (0);
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);
1767 memcpy(new->keynetdata.st_priv_key, key,
1768 HEXKEYBYTES);
1769 (void) rw_unlock(&g_secretkey_netname_lock);
1770 return (1);
1773 static int
1774 hexdigit(val)
1775 int val;
1777 return ("0123456789abcdef"[val]);
1781 bin2hex(bin, hex, size)
1782 unsigned char *bin;
1783 unsigned char *hex;
1784 int size;
1786 int i;
1788 for (i = 0; i < size; i++) {
1789 *hex++ = hexdigit(*bin >> 4);
1790 *hex++ = hexdigit(*bin++ & 0xf);
1792 return (0);
1795 static int
1796 hexval(dig)
1797 char dig;
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);
1811 hex2bin(hex, bin, size)
1812 unsigned char *hex;
1813 unsigned char *bin;
1814 int size;
1816 int i;
1818 for (i = 0; i < size; i++) {
1819 *bin = hexval(*hex++) << 4;
1820 *bin++ |= hexval(*hex++);
1822 return (0);
1825 static int
1826 hash_keys(pub, sec)
1827 char *pub;
1828 char *sec;
1830 int i;
1831 int hash = 0;
1833 for (i = 0; i < HEXKEYBYTES; i += 6, pub += 6, sec += 6) {
1834 hash ^= *pub;
1835 hash ^= *sec;
1837 return (hash & 0xff);
1841 * problem: keyserv loads keys from /etc/.rootkey based on nisauthconf(1M)
1842 * which is too nis+-centric (see secure_rpc(3N)).
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.
1853 * Return ptr to mechs array on success, else NULL on memory errs.
1855 mechanism_t **
1856 getmechwrap()
1858 mechanism_t **mechs = __nis_get_mechanisms(FALSE);
1859 mechanism_t **mechsbak = NULL;
1860 mechanism_t *desmech = NULL;
1861 int i = 0;
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);
1869 /* i == number of ptrs not counting terminating NULL */
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);
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;
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);
1894 mechs[i] = desmech;
1895 mechs[i+1] = NULL;
1897 return (mechs);
1901 init_mechs()
1903 int nmechs, oldmechseen;
1904 mechanism_t **mechpp;
1905 char **cpp;
1907 if (!(mechs = getmechwrap()))
1908 return (-1);
1911 * find how many mechanisms were specified and also
1912 * setup the mechanism table for unique keylen/algtype pair
1914 nmechs = 0;
1915 for (mechpp = mechs; *mechpp != NULL; mechpp++) {
1916 struct keylenlist **kpp;
1917 struct algtypelist **app;
1919 nmechs++;
1920 if (((*mechpp)->keylen < 0) || ((*mechpp)->algtype < 0)) {
1921 continue;
1923 kpp = getkeylen((*mechpp)->keylen);
1924 appendkeylist(kpp, (*mechpp)->keylen);
1925 app = getalgtype(kpp, (*mechpp)->algtype);
1926 appendalgtype(app, (*mechpp)->algtype);
1930 * set of mechs for getsubopt()
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);
1939 * cache sizes
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);
1947 oldmechseen = 0;
1948 cpp = cache_options;
1949 for (mechpp = mechs; *mechpp != NULL; mechpp++) {
1951 * usual case: a DH-style mechanism type, with an alias
1953 if ((*mechpp)->mechname != NULL &&
1954 strncmp((*mechpp)->mechname, DHMECHSTR,
1955 strlen(DHMECHSTR)) == 0 &&
1956 (*mechpp)->alias != NULL) {
1958 * Is this trad 192-DH? already added?
1960 if (strcmp((*mechpp)->alias, DESALIAS) == 0) {
1961 if (oldmechseen) {
1962 continue;
1964 oldmechseen++;
1967 *cpp++ = (*mechpp)->alias;
1968 continue;
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
1976 if ((*mechpp)->mechname == NULL && (*mechpp)->alias != NULL &&
1977 strcmp((*mechpp)->alias, DES) == 0 && !oldmechseen) {
1978 *cpp++ = DESALIAS;
1979 oldmechseen++;
1980 continue;
1984 * Ignore anything else
1988 /* Terminate the options list */
1989 *cpp = NULL;
1991 return (0);