126234Swpaul/*
226234Swpaul * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
326234Swpaul * unrestricted use provided that this legend is included on all tape
426234Swpaul * media and as a part of the software program in whole or part.  Users
526234Swpaul * may copy or modify Sun RPC without charge, but are not authorized
626234Swpaul * to license or distribute it to anyone else except as part of a product or
726234Swpaul * program developed by the user.
826234Swpaul *
926234Swpaul * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
1026234Swpaul * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
1126234Swpaul * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
1226234Swpaul *
1326234Swpaul * Sun RPC is provided with no support and without any obligation on the
1426234Swpaul * part of Sun Microsystems, Inc. to assist in its use, correction,
1526234Swpaul * modification or enhancement.
1626234Swpaul *
1726234Swpaul * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
1826234Swpaul * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
1926234Swpaul * OR ANY PART THEREOF.
2026234Swpaul *
2126234Swpaul * In no event will Sun Microsystems, Inc. be liable for any lost revenue
2226234Swpaul * or profits or other special, indirect and consequential damages, even if
2326234Swpaul * Sun has been advised of the possibility of such damages.
2426234Swpaul *
2526234Swpaul * Sun Microsystems, Inc.
2626234Swpaul * 2550 Garcia Avenue
2726234Swpaul * Mountain View, California  94043
2826234Swpaul */
2926234Swpaul
3029735Scharnier#ifndef lint
3129735Scharnier#if 0
3229735Scharnierstatic char sccsid[] = "@(#)setkey.c	1.11	94/04/25 SMI";
3329735Scharnier#endif
3429735Scharnierstatic const char rcsid[] =
3550479Speter  "$FreeBSD$";
3629735Scharnier#endif /* not lint */
3726234Swpaul
3826234Swpaul/*
3926234Swpaul * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
4026234Swpaul */
4126234Swpaul
4226234Swpaul/*
4326234Swpaul * Do the real work of the keyserver.
4426234Swpaul * Store secret keys. Compute common keys,
4526234Swpaul * and use them to decrypt and encrypt DES keys.
4626234Swpaul * Cache the common keys, so the expensive computation is avoided.
4726234Swpaul */
4829735Scharnier#include <mp.h>
4926234Swpaul#include <stdio.h>
5026234Swpaul#include <stdlib.h>
5129735Scharnier#include <string.h>
5226234Swpaul#include <unistd.h>
5326234Swpaul#include <sys/types.h>
5426234Swpaul#include <rpc/rpc.h>
5526234Swpaul#include <rpc/key_prot.h>
5626234Swpaul#include <rpc/des_crypt.h>
5726234Swpaul#include <rpc/des.h>
5826234Swpaul#include <sys/errno.h>
5926234Swpaul#include "keyserv.h"
6026234Swpaul
6126234Swpaulstatic MINT *MODULUS;
62173412Skevlostatic char *fetchsecretkey( uid_t );
63173412Skevlostatic void writecache( char *, char *, des_block * );
64173412Skevlostatic int readcache( char *, char *, des_block * );
65173412Skevlostatic void extractdeskey( MINT *, des_block * );
66173412Skevlostatic int storesecretkey( uid_t, keybuf );
67173412Skevlostatic keystatus pk_crypt( uid_t, char *, netobj *, des_block *, int);
6826234Swpaulstatic int nodefaultkeys = 0;
6926234Swpaul
7026234Swpaul
7126234Swpaul/*
7226234Swpaul * prohibit the nobody key on this machine k (the -d flag)
7326234Swpaul */
7426234Swpaulvoid
7526234Swpaulpk_nodefaultkeys()
7626234Swpaul{
7726234Swpaul	nodefaultkeys = 1;
7826234Swpaul}
7926234Swpaul
8026234Swpaul/*
8126234Swpaul * Set the modulus for all our Diffie-Hellman operations
8226234Swpaul */
8326234Swpaulvoid
8426234Swpaulsetmodulus(modx)
8526234Swpaul	char *modx;
8626234Swpaul{
87189092Sed	MODULUS = mp_xtom(modx);
8826234Swpaul}
8926234Swpaul
9026234Swpaul/*
9126234Swpaul * Set the secretkey key for this uid
9226234Swpaul */
9326234Swpaulkeystatus
9426234Swpaulpk_setkey(uid, skey)
9526234Swpaul	uid_t uid;
9626234Swpaul	keybuf skey;
9726234Swpaul{
9826234Swpaul	if (!storesecretkey(uid, skey)) {
9926234Swpaul		return (KEY_SYSTEMERR);
10026234Swpaul	}
10126234Swpaul	return (KEY_SUCCESS);
10226234Swpaul}
10326234Swpaul
10426234Swpaul/*
10526234Swpaul * Encrypt the key using the public key associated with remote_name and the
10626234Swpaul * secret key associated with uid.
10726234Swpaul */
10826234Swpaulkeystatus
10926234Swpaulpk_encrypt(uid, remote_name, remote_key, key)
11026234Swpaul	uid_t uid;
11126234Swpaul	char *remote_name;
11226234Swpaul	netobj	*remote_key;
11326234Swpaul	des_block *key;
11426234Swpaul{
11526234Swpaul	return (pk_crypt(uid, remote_name, remote_key, key, DES_ENCRYPT));
11626234Swpaul}
11726234Swpaul
11826234Swpaul/*
11926234Swpaul * Decrypt the key using the public key associated with remote_name and the
12026234Swpaul * secret key associated with uid.
12126234Swpaul */
12226234Swpaulkeystatus
12326234Swpaulpk_decrypt(uid, remote_name, remote_key, key)
12426234Swpaul	uid_t uid;
12526234Swpaul	char *remote_name;
12626234Swpaul	netobj *remote_key;
12726234Swpaul	des_block *key;
12826234Swpaul{
12926234Swpaul	return (pk_crypt(uid, remote_name, remote_key, key, DES_DECRYPT));
13026234Swpaul}
13126234Swpaul
132173412Skevlostatic int store_netname( uid_t, key_netstarg * );
133173412Skevlostatic int fetch_netname( uid_t, key_netstarg * );
13426234Swpaul
13526234Swpaulkeystatus
13626234Swpaulpk_netput(uid, netstore)
13726234Swpaul	uid_t uid;
13826234Swpaul	key_netstarg *netstore;
13926234Swpaul{
14026234Swpaul	if (!store_netname(uid, netstore)) {
14126234Swpaul		return (KEY_SYSTEMERR);
14226234Swpaul	}
14326234Swpaul	return (KEY_SUCCESS);
14426234Swpaul}
14526234Swpaul
14626234Swpaulkeystatus
14726234Swpaulpk_netget(uid, netstore)
14826234Swpaul	uid_t uid;
14926234Swpaul	key_netstarg *netstore;
15026234Swpaul{
15126234Swpaul	if (!fetch_netname(uid, netstore)) {
15226234Swpaul		return (KEY_SYSTEMERR);
15326234Swpaul	}
15426234Swpaul	return (KEY_SUCCESS);
15526234Swpaul}
15626234Swpaul
15726234Swpaul
15826234Swpaul/*
15926234Swpaul * Do the work of pk_encrypt && pk_decrypt
16026234Swpaul */
16126234Swpaulstatic keystatus
16226234Swpaulpk_crypt(uid, remote_name, remote_key, key, mode)
16326234Swpaul	uid_t uid;
16426234Swpaul	char *remote_name;
16526234Swpaul	netobj *remote_key;
16626234Swpaul	des_block *key;
16726234Swpaul	int mode;
16826234Swpaul{
16926234Swpaul	char *xsecret;
17026234Swpaul	char xpublic[1024];
17126234Swpaul	char xsecret_hold[1024];
17226234Swpaul	des_block deskey;
17326234Swpaul	int err;
17426234Swpaul	MINT *public;
17526234Swpaul	MINT *secret;
17626234Swpaul	MINT *common;
17726234Swpaul	char zero[8];
17826234Swpaul
17926234Swpaul	xsecret = fetchsecretkey(uid);
18026234Swpaul	if (xsecret == NULL || xsecret[0] == 0) {
18126234Swpaul		memset(zero, 0, sizeof (zero));
18226234Swpaul		xsecret = xsecret_hold;
18326234Swpaul		if (nodefaultkeys)
18426234Swpaul			return (KEY_NOSECRET);
18526234Swpaul
18626234Swpaul		if (!getsecretkey("nobody", xsecret, zero) || xsecret[0] == 0) {
18726234Swpaul			return (KEY_NOSECRET);
18826234Swpaul		}
18926234Swpaul	}
19026234Swpaul	if (remote_key) {
19126234Swpaul		memcpy(xpublic, remote_key->n_bytes, remote_key->n_len);
19226234Swpaul	} else {
19326234Swpaul		bzero((char *)&xpublic, sizeof(xpublic));
19426234Swpaul		if (!getpublickey(remote_name, xpublic)) {
19526234Swpaul			if (nodefaultkeys || !getpublickey("nobody", xpublic))
19626234Swpaul				return (KEY_UNKNOWN);
19726234Swpaul		}
19826234Swpaul	}
19926234Swpaul
20026234Swpaul	if (!readcache(xpublic, xsecret, &deskey)) {
201189092Sed		public = mp_xtom(xpublic);
202189092Sed		secret = mp_xtom(xsecret);
20326234Swpaul		/* Sanity Check on public and private keys */
20426234Swpaul		if ((public == NULL) || (secret == NULL))
20526234Swpaul			return (KEY_SYSTEMERR);
20626234Swpaul
207189092Sed		common = mp_itom(0);
208189092Sed		mp_pow(public, secret, MODULUS, common);
20926234Swpaul		extractdeskey(common, &deskey);
21026234Swpaul		writecache(xpublic, xsecret, &deskey);
211189092Sed		mp_mfree(secret);
212189092Sed		mp_mfree(public);
213189092Sed		mp_mfree(common);
21426234Swpaul	}
21526234Swpaul	err = ecb_crypt((char *)&deskey, (char *)key, sizeof (des_block),
21626234Swpaul		DES_HW | mode);
21726234Swpaul	if (DES_FAILED(err)) {
21826234Swpaul		return (KEY_SYSTEMERR);
21926234Swpaul	}
22026234Swpaul	return (KEY_SUCCESS);
22126234Swpaul}
22226234Swpaul
22326234Swpaulkeystatus
22426234Swpaulpk_get_conv_key(uid, xpublic, result)
22526234Swpaul	uid_t uid;
22626234Swpaul	keybuf xpublic;
22726234Swpaul	cryptkeyres *result;
22826234Swpaul{
22926234Swpaul	char *xsecret;
23026234Swpaul	char xsecret_hold[1024];
23126234Swpaul	MINT *public;
23226234Swpaul	MINT *secret;
23326234Swpaul	MINT *common;
23426234Swpaul	char zero[8];
23526234Swpaul
23626234Swpaul
23726234Swpaul	xsecret = fetchsecretkey(uid);
23826234Swpaul
23926234Swpaul	if (xsecret == NULL || xsecret[0] == 0) {
24026234Swpaul		memset(zero, 0, sizeof (zero));
24126234Swpaul		xsecret = xsecret_hold;
24226234Swpaul		if (nodefaultkeys)
24326234Swpaul			return (KEY_NOSECRET);
24426234Swpaul
24526234Swpaul		if (!getsecretkey("nobody", xsecret, zero) ||
24626234Swpaul			xsecret[0] == 0)
24726234Swpaul			return (KEY_NOSECRET);
24826234Swpaul	}
24926234Swpaul
25026234Swpaul	if (!readcache(xpublic, xsecret, &result->cryptkeyres_u.deskey)) {
251189092Sed		public = mp_xtom(xpublic);
252189092Sed		secret = mp_xtom(xsecret);
25326234Swpaul		/* Sanity Check on public and private keys */
25426234Swpaul		if ((public == NULL) || (secret == NULL))
25526234Swpaul			return (KEY_SYSTEMERR);
25626234Swpaul
257189092Sed		common = mp_itom(0);
258189092Sed		mp_pow(public, secret, MODULUS, common);
25926234Swpaul		extractdeskey(common, &result->cryptkeyres_u.deskey);
26026234Swpaul		writecache(xpublic, xsecret, &result->cryptkeyres_u.deskey);
261189092Sed		mp_mfree(secret);
262189092Sed		mp_mfree(public);
263189092Sed		mp_mfree(common);
26426234Swpaul	}
26526234Swpaul
26626234Swpaul	return (KEY_SUCCESS);
26726234Swpaul}
26826234Swpaul
26926234Swpaul/*
27026234Swpaul * Choose middle 64 bits of the common key to use as our des key, possibly
27126234Swpaul * overwriting the lower order bits by setting parity.
27226234Swpaul */
27326234Swpaulstatic void
27426234Swpaulextractdeskey(ck, deskey)
27526234Swpaul	MINT *ck;
27626234Swpaul	des_block *deskey;
27726234Swpaul{
27826234Swpaul	MINT *a;
27926234Swpaul	short r;
28026234Swpaul	int i;
28126234Swpaul	short base = (1 << 8);
28226234Swpaul	char *k;
28326234Swpaul
284189092Sed	a = mp_itom(0);
28526234Swpaul#ifdef SOLARIS_MP
28626234Swpaul	_mp_move(ck, a);
28726234Swpaul#else
288189092Sed	mp_move(ck, a);
28926234Swpaul#endif
29026234Swpaul	for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) {
291189092Sed		mp_sdiv(a, base, a, &r);
29226234Swpaul	}
29326234Swpaul	k = deskey->c;
29426234Swpaul	for (i = 0; i < 8; i++) {
295189092Sed		mp_sdiv(a, base, a, &r);
29626234Swpaul		*k++ = r;
29726234Swpaul	}
298189092Sed	mp_mfree(a);
29926234Swpaul	des_setparity((char *)deskey);
30026234Swpaul}
30126234Swpaul
30226234Swpaul/*
30326234Swpaul * Key storage management
30426234Swpaul */
30526234Swpaul
30626234Swpaul#define	KEY_ONLY 0
30726234Swpaul#define	KEY_NAME 1
30826234Swpaulstruct secretkey_netname_list {
30926234Swpaul	uid_t uid;
31026234Swpaul	key_netstarg keynetdata;
31126234Swpaul	u_char sc_flag;
31226234Swpaul	struct secretkey_netname_list *next;
31326234Swpaul};
31426234Swpaul
31526234Swpaul
31626234Swpaul
31726234Swpaulstatic struct secretkey_netname_list *g_secretkey_netname;
31826234Swpaul
31926234Swpaul/*
32026234Swpaul * Store the keys and netname for this uid
32126234Swpaul */
32226234Swpaulstatic int
32326234Swpaulstore_netname(uid, netstore)
32426234Swpaul	uid_t uid;
32526234Swpaul	key_netstarg *netstore;
32626234Swpaul{
32726234Swpaul	struct secretkey_netname_list *new;
32826234Swpaul	struct secretkey_netname_list **l;
32926234Swpaul
33026234Swpaul	for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid;
33126234Swpaul			l = &(*l)->next) {
33226234Swpaul	}
33326234Swpaul	if (*l == NULL) {
33426234Swpaul		new = (struct secretkey_netname_list *)malloc(sizeof (*new));
33526234Swpaul		if (new == NULL) {
33626234Swpaul			return (0);
33726234Swpaul		}
33826234Swpaul		new->uid = uid;
33926234Swpaul		new->next = NULL;
34026234Swpaul		*l = new;
34126234Swpaul	} else {
34226234Swpaul		new = *l;
34326234Swpaul		if (new->keynetdata.st_netname)
34426234Swpaul			(void) free (new->keynetdata.st_netname);
34526234Swpaul	}
34626234Swpaul	memcpy(new->keynetdata.st_priv_key, netstore->st_priv_key,
34726234Swpaul		HEXKEYBYTES);
34826234Swpaul	memcpy(new->keynetdata.st_pub_key, netstore->st_pub_key, HEXKEYBYTES);
34926234Swpaul
35026234Swpaul	if (netstore->st_netname)
35126234Swpaul		new->keynetdata.st_netname = strdup(netstore->st_netname);
35226234Swpaul	else
35326234Swpaul		new->keynetdata.st_netname = (char *)NULL;
35426234Swpaul	new->sc_flag = KEY_NAME;
35526234Swpaul	return (1);
35626234Swpaul
35726234Swpaul}
35826234Swpaul
35926234Swpaul/*
36026234Swpaul * Fetch the keys and netname for this uid
36126234Swpaul */
36226234Swpaul
36326234Swpaulstatic int
36426234Swpaulfetch_netname(uid, key_netst)
36526234Swpaul	uid_t uid;
36626234Swpaul	struct key_netstarg *key_netst;
36726234Swpaul{
36826234Swpaul	struct secretkey_netname_list *l;
36926234Swpaul
37026234Swpaul	for (l = g_secretkey_netname; l != NULL; l = l->next) {
37126234Swpaul		if ((l->uid == uid) && (l->sc_flag == KEY_NAME)){
37226234Swpaul
37326234Swpaul			memcpy(key_netst->st_priv_key,
37426234Swpaul				l->keynetdata.st_priv_key, HEXKEYBYTES);
37526234Swpaul
37626234Swpaul			memcpy(key_netst->st_pub_key,
37726234Swpaul				l->keynetdata.st_pub_key, HEXKEYBYTES);
37826234Swpaul
37926234Swpaul			if (l->keynetdata.st_netname)
38026234Swpaul				key_netst->st_netname =
38126234Swpaul					strdup(l->keynetdata.st_netname);
38226234Swpaul			else
38326234Swpaul				key_netst->st_netname = NULL;
38426234Swpaul		return (1);
38526234Swpaul		}
38626234Swpaul	}
38726234Swpaul
38826234Swpaul	return (0);
38926234Swpaul}
39026234Swpaul
39126234Swpaulstatic char *
39226234Swpaulfetchsecretkey(uid)
39326234Swpaul	uid_t uid;
39426234Swpaul{
39526234Swpaul	struct secretkey_netname_list *l;
39626234Swpaul
39726234Swpaul	for (l = g_secretkey_netname; l != NULL; l = l->next) {
39826234Swpaul		if (l->uid == uid) {
39926234Swpaul			return (l->keynetdata.st_priv_key);
40026234Swpaul		}
40126234Swpaul	}
40226234Swpaul	return (NULL);
40326234Swpaul}
40426234Swpaul
40526234Swpaul/*
40626234Swpaul * Store the secretkey for this uid
40726234Swpaul */
40826234Swpaulstatic int
40926234Swpaulstoresecretkey(uid, key)
41026234Swpaul	uid_t uid;
41126234Swpaul	keybuf key;
41226234Swpaul{
41326234Swpaul	struct secretkey_netname_list *new;
41426234Swpaul	struct secretkey_netname_list **l;
41526234Swpaul
41626234Swpaul	for (l = &g_secretkey_netname; *l != NULL && (*l)->uid != uid;
41726234Swpaul			l = &(*l)->next) {
41826234Swpaul	}
41926234Swpaul	if (*l == NULL) {
42026234Swpaul		new = (struct secretkey_netname_list *) malloc(sizeof (*new));
42126234Swpaul		if (new == NULL) {
42226234Swpaul			return (0);
42326234Swpaul		}
42426234Swpaul		new->uid = uid;
42526234Swpaul		new->sc_flag = KEY_ONLY;
42626234Swpaul		memset(new->keynetdata.st_pub_key, 0, HEXKEYBYTES);
42726234Swpaul		new->keynetdata.st_netname = NULL;
42826234Swpaul		new->next = NULL;
42926234Swpaul		*l = new;
43026234Swpaul	} else {
43126234Swpaul		new = *l;
43226234Swpaul	}
43326234Swpaul
43426234Swpaul	memcpy(new->keynetdata.st_priv_key, key,
43526234Swpaul		HEXKEYBYTES);
43626234Swpaul	return (1);
43726234Swpaul}
43826234Swpaul
43926234Swpaulstatic int
44026234Swpaulhexdigit(val)
44126234Swpaul	int val;
44226234Swpaul{
44326234Swpaul	return ("0123456789abcdef"[val]);
44426234Swpaul}
44526234Swpaul
44626234Swpaulvoid
44726234Swpaulbin2hex(bin, hex, size)
44826234Swpaul	unsigned char *bin;
44926234Swpaul	unsigned char *hex;
45026234Swpaul	int size;
45126234Swpaul{
45226234Swpaul	int i;
45326234Swpaul
45426234Swpaul	for (i = 0; i < size; i++) {
45526234Swpaul		*hex++ = hexdigit(*bin >> 4);
45626234Swpaul		*hex++ = hexdigit(*bin++ & 0xf);
45726234Swpaul	}
45826234Swpaul}
45926234Swpaul
46026234Swpaulstatic int
46126234Swpaulhexval(dig)
46226234Swpaul	char dig;
46326234Swpaul{
46426234Swpaul	if ('0' <= dig && dig <= '9') {
46526234Swpaul		return (dig - '0');
46626234Swpaul	} else if ('a' <= dig && dig <= 'f') {
46726234Swpaul		return (dig - 'a' + 10);
46826234Swpaul	} else if ('A' <= dig && dig <= 'F') {
46926234Swpaul		return (dig - 'A' + 10);
47026234Swpaul	} else {
47126234Swpaul		return (-1);
47226234Swpaul	}
47326234Swpaul}
47426234Swpaul
47526234Swpaulvoid
47626234Swpaulhex2bin(hex, bin, size)
47726234Swpaul	unsigned char *hex;
47826234Swpaul	unsigned char *bin;
47926234Swpaul	int size;
48026234Swpaul{
48126234Swpaul	int i;
48226234Swpaul
48326234Swpaul	for (i = 0; i < size; i++) {
48426234Swpaul		*bin = hexval(*hex++) << 4;
48526234Swpaul		*bin++ |= hexval(*hex++);
48626234Swpaul	}
48726234Swpaul}
48826234Swpaul
48926234Swpaul/*
49026234Swpaul * Exponential caching management
49126234Swpaul */
49226234Swpaulstruct cachekey_list {
49326234Swpaul	keybuf secret;
49426234Swpaul	keybuf public;
49526234Swpaul	des_block deskey;
49626234Swpaul	struct cachekey_list *next;
49726234Swpaul};
49826234Swpaulstatic struct cachekey_list *g_cachedkeys;
49926234Swpaul
50026234Swpaul/*
50126234Swpaul * cache result of expensive multiple precision exponential operation
50226234Swpaul */
50326234Swpaulstatic void
50426234Swpaulwritecache(pub, sec, deskey)
50526234Swpaul	char *pub;
50626234Swpaul	char *sec;
50726234Swpaul	des_block *deskey;
50826234Swpaul{
50926234Swpaul	struct cachekey_list *new;
51026234Swpaul
51126234Swpaul	new = (struct cachekey_list *) malloc(sizeof (struct cachekey_list));
51226234Swpaul	if (new == NULL) {
51326234Swpaul		return;
51426234Swpaul	}
51526234Swpaul	memcpy(new->public, pub, sizeof (keybuf));
51626234Swpaul	memcpy(new->secret, sec, sizeof (keybuf));
51726234Swpaul	new->deskey = *deskey;
51826234Swpaul	new->next = g_cachedkeys;
51926234Swpaul	g_cachedkeys = new;
52026234Swpaul}
52126234Swpaul
52226234Swpaul/*
52326234Swpaul * Try to find the common key in the cache
52426234Swpaul */
52526234Swpaulstatic int
52626234Swpaulreadcache(pub, sec, deskey)
52726234Swpaul	char *pub;
52826234Swpaul	char *sec;
52926234Swpaul	des_block *deskey;
53026234Swpaul{
53126234Swpaul	struct cachekey_list *found;
53226234Swpaul	register struct cachekey_list **l;
53326234Swpaul
53426234Swpaul#define	cachehit(pub, sec, list)	\
53526234Swpaul		(memcmp(pub, (list)->public, sizeof (keybuf)) == 0 && \
53626234Swpaul		memcmp(sec, (list)->secret, sizeof (keybuf)) == 0)
53726234Swpaul
53826234Swpaul	for (l = &g_cachedkeys; (*l) != NULL && !cachehit(pub, sec, *l);
53926234Swpaul		l = &(*l)->next)
54026234Swpaul		;
54126234Swpaul	if ((*l) == NULL) {
54226234Swpaul		return (0);
54326234Swpaul	}
54426234Swpaul	found = *l;
54526234Swpaul	(*l) = (*l)->next;
54626234Swpaul	found->next = g_cachedkeys;
54726234Swpaul	g_cachedkeys = found;
54826234Swpaul	*deskey = found->deskey;
54926234Swpaul	return (1);
55026234Swpaul}
551