1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 1997 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
28*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
29*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
30*7c478bd9Sstevel@tonic-gate #include <unistd.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/mman.h>
32*7c478bd9Sstevel@tonic-gate #include <thread.h>
33*7c478bd9Sstevel@tonic-gate #include <synch.h>
34*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
35*7c478bd9Sstevel@tonic-gate #include <syslog.h>
36*7c478bd9Sstevel@tonic-gate #include <rpc/des_crypt.h>
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate #include "keyserv_cache.h"
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate struct cachekey {
41*7c478bd9Sstevel@tonic-gate 	struct cachekey_header	*ch;
42*7c478bd9Sstevel@tonic-gate 	keylen_t		keylen;
43*7c478bd9Sstevel@tonic-gate 	algtype_t		algtype;
44*7c478bd9Sstevel@tonic-gate 	mutex_t			mp;
45*7c478bd9Sstevel@tonic-gate 	struct cachekey		*next;
46*7c478bd9Sstevel@tonic-gate };
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate static struct cachekey		*cache = 0;
49*7c478bd9Sstevel@tonic-gate static mutex_t			cache_lock = DEFAULTMUTEX;
50*7c478bd9Sstevel@tonic-gate static cond_t			cache_cv = DEFAULTCV;
51*7c478bd9Sstevel@tonic-gate static u_long			cache_refcnt = 0;
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate struct skck {
54*7c478bd9Sstevel@tonic-gate 	des_block	common[3];
55*7c478bd9Sstevel@tonic-gate 	des_block	verifier;	/* Checksum */
56*7c478bd9Sstevel@tonic-gate 	struct dhkey	secret;
57*7c478bd9Sstevel@tonic-gate };
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate struct cachekey_disklist {
60*7c478bd9Sstevel@tonic-gate 	uid_t				uid;
61*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist	*prev;		/* LRU order */
62*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist	*next;
63*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist	*prevhash;	/* Hash chain */
64*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist	*nexthash;
65*7c478bd9Sstevel@tonic-gate 	struct dhkey			public;
66*7c478bd9Sstevel@tonic-gate 	/*
67*7c478bd9Sstevel@tonic-gate 	 * Storage for encrypted skck structure here. The length will be
68*7c478bd9Sstevel@tonic-gate 	 * 8 * ( ( ( sizeof(struct skck) - 1 + secret.length ) - 1 ) / 8 + 1 )
69*7c478bd9Sstevel@tonic-gate 	 */
70*7c478bd9Sstevel@tonic-gate };
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate /* Length of skck structure for given key length (in bits) */
73*7c478bd9Sstevel@tonic-gate #define	SKCK_LEN(keylen)	ALIGN8(sizeof (struct skck) + KEYLEN(keylen))
74*7c478bd9Sstevel@tonic-gate /* Length of a cachekey_disklist record for given key length (in bits) */
75*7c478bd9Sstevel@tonic-gate #define	CACHEKEY_RECLEN(keylen)	ALIGN8(sizeof (struct cachekey_disklist) - 1 + \
76*7c478bd9Sstevel@tonic-gate 					KEYLEN(keylen) + SKCK_LEN(keylen))
77*7c478bd9Sstevel@tonic-gate #define	NUMHASHBUCKETS	253
78*7c478bd9Sstevel@tonic-gate #define	CHUNK_NUMREC	64
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate #define	CACHEKEY_HEADER_VERSION	0
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate struct cachekey_header {		/* First in each key cache file */
83*7c478bd9Sstevel@tonic-gate 	u_int		version;	/* version number of interface */
84*7c478bd9Sstevel@tonic-gate 	u_int		headerlength;	/* size of this header */
85*7c478bd9Sstevel@tonic-gate 	keylen_t	keylen;		/* in bits */
86*7c478bd9Sstevel@tonic-gate 	algtype_t	algtype;	/* algorithm type */
87*7c478bd9Sstevel@tonic-gate 	size_t		reclength;	/* cache file record size in bytes */
88*7c478bd9Sstevel@tonic-gate 	int		fd;		/* file descriptor */
89*7c478bd9Sstevel@tonic-gate 	caddr_t		address;	/* mmap()ed here */
90*7c478bd9Sstevel@tonic-gate 	size_t		length;		/* bytes mapped */
91*7c478bd9Sstevel@tonic-gate 	size_t		maxsize;	/* don't grow beyond this */
92*7c478bd9Sstevel@tonic-gate 	u_int		inuse_count;
93*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist	*inuse;	/* LRU order */
94*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist	*inuse_end;
95*7c478bd9Sstevel@tonic-gate 	u_int				free_count;
96*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist	*free;
97*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist	*bucket[NUMHASHBUCKETS];
98*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist	array[1];	/* Start of array */
99*7c478bd9Sstevel@tonic-gate };
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate static struct cachekey_header	*create_cache_file_ch(keylen_t keylen,
103*7c478bd9Sstevel@tonic-gate 							algtype_t algtype,
104*7c478bd9Sstevel@tonic-gate 							int sizespec);
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate static struct cachekey_header	*remap_cache_file_ch(struct cachekey_header *ch,
107*7c478bd9Sstevel@tonic-gate 						u_int newrecs);
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate static struct cachekey_header	*cache_insert_ch(struct cachekey_header *ch,
110*7c478bd9Sstevel@tonic-gate 						uid_t uid, deskeyarray common,
111*7c478bd9Sstevel@tonic-gate 						des_block key,
112*7c478bd9Sstevel@tonic-gate 						keybuf3 *public,
113*7c478bd9Sstevel@tonic-gate 						keybuf3 *secret);
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate static struct cachekey3_list	*cache_retrieve_ch(struct cachekey_header *ch,
116*7c478bd9Sstevel@tonic-gate 						uid_t uid,
117*7c478bd9Sstevel@tonic-gate 						keybuf3 *public,
118*7c478bd9Sstevel@tonic-gate 						des_block key);
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate static int			cache_remove_ch(struct cachekey_header *ch,
121*7c478bd9Sstevel@tonic-gate 						uid_t uid,
122*7c478bd9Sstevel@tonic-gate 						keybuf3 *public);
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate static struct cachekey		*get_cache_header(keylen_t keylen,
125*7c478bd9Sstevel@tonic-gate 							algtype_t algtype);
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate static void			release_cache_header(struct cachekey *);
128*7c478bd9Sstevel@tonic-gate 
129*7c478bd9Sstevel@tonic-gate static int			cache_remap_addresses_ch(
130*7c478bd9Sstevel@tonic-gate 					struct cachekey_header *);
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate static struct cachekey_disklist	*find_cache_item(struct cachekey_header **,
133*7c478bd9Sstevel@tonic-gate 						uid_t, struct dhkey *);
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate static struct dhkey		*keybuf3_2_dhkey(keybuf3 *);
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate static u_int			hashval(uid_t);
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate static void			list_remove(struct cachekey_disklist *,
140*7c478bd9Sstevel@tonic-gate 						struct cachekey_disklist **,
141*7c478bd9Sstevel@tonic-gate 						struct cachekey_disklist **,
142*7c478bd9Sstevel@tonic-gate 						u_int *);
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate static void			list_remove_hash(struct cachekey_disklist *,
145*7c478bd9Sstevel@tonic-gate 						struct cachekey_disklist **,
146*7c478bd9Sstevel@tonic-gate 						struct cachekey_disklist **,
147*7c478bd9Sstevel@tonic-gate 						u_int *);
148*7c478bd9Sstevel@tonic-gate 
149*7c478bd9Sstevel@tonic-gate static void			list_insert(struct cachekey_disklist *,
150*7c478bd9Sstevel@tonic-gate 						struct cachekey_disklist **,
151*7c478bd9Sstevel@tonic-gate 						struct cachekey_disklist **,
152*7c478bd9Sstevel@tonic-gate 						u_int *);
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate static void			list_insert_hash(struct cachekey_disklist *,
155*7c478bd9Sstevel@tonic-gate 						struct cachekey_disklist **,
156*7c478bd9Sstevel@tonic-gate 						struct cachekey_disklist **,
157*7c478bd9Sstevel@tonic-gate 						u_int *);
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate static struct cachekey3_list *	copy_cl_item(struct cachekey_header *ch,
160*7c478bd9Sstevel@tonic-gate 						struct cachekey_disklist *cd,
161*7c478bd9Sstevel@tonic-gate 						des_block key);
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate extern int			hex2bin(u_char *, u_char *, int);
164*7c478bd9Sstevel@tonic-gate extern int			bin2hex(u_char *, u_char *, int);
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate /*
167*7c478bd9Sstevel@tonic-gate  * The folowing set of macros implement address validity checking. A valid
168*7c478bd9Sstevel@tonic-gate  * address is defined to be either 0, or to fall on a record boundary. In
169*7c478bd9Sstevel@tonic-gate  * the latter case, the the difference between the address and the start of
170*7c478bd9Sstevel@tonic-gate  * the record array is divisible by the record length.
171*7c478bd9Sstevel@tonic-gate  */
172*7c478bd9Sstevel@tonic-gate #define	FILEOFFSET(ckh)			((u_long)(ckh) - \
173*7c478bd9Sstevel@tonic-gate 					(u_long)((ckh)->address))
174*7c478bd9Sstevel@tonic-gate #define	ADJUSTEDADDR(addr, ckh)		((u_long)(addr) + FILEOFFSET(ckh))
175*7c478bd9Sstevel@tonic-gate #define	ARRAYOFFSET(addr, ckh)		(ADJUSTEDADDR(addr, ckh) - \
176*7c478bd9Sstevel@tonic-gate 					(u_long)&((ckh)->array[0]))
177*7c478bd9Sstevel@tonic-gate #define	INVALID_ADDRESS(addr, ckh)	((addr == 0) ? 0 : \
178*7c478bd9Sstevel@tonic-gate 			(ARRAYOFFSET(addr, ckh) % (ckh)->reclength) != 0)
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate /* Add offset to old address */
181*7c478bd9Sstevel@tonic-gate #define	MOVE_ADDR(old, offset)	((old) == 0) ? 0 : \
182*7c478bd9Sstevel@tonic-gate 				(void *)((u_long)(old) + (offset))
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate /* Number of records in use or on free list */
185*7c478bd9Sstevel@tonic-gate #define	NUMRECS(ck_header)	((ck_header)->inuse_count + \
186*7c478bd9Sstevel@tonic-gate 				(ck_header)->free_count)
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate /* Max number of records the mapped file could hold */
189*7c478bd9Sstevel@tonic-gate #define	MAPRECS(ck_header)	(((ck_header)->length - \
190*7c478bd9Sstevel@tonic-gate 				sizeof (struct cachekey_header)) / \
191*7c478bd9Sstevel@tonic-gate 				(ck_header)->reclength)
192*7c478bd9Sstevel@tonic-gate /* Max number of records the file will hold if extended to the maxsize */
193*7c478bd9Sstevel@tonic-gate #define	MAXRECS(ck_header)	(((ck_header)->maxsize - \
194*7c478bd9Sstevel@tonic-gate 				sizeof (struct cachekey_header)) / \
195*7c478bd9Sstevel@tonic-gate 				(ck_header)->reclength)
196*7c478bd9Sstevel@tonic-gate 
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate struct cachekey_header *
create_cache_file_ch(keylen_t keylen,algtype_t algtype,int sizespec)199*7c478bd9Sstevel@tonic-gate create_cache_file_ch(keylen_t keylen, algtype_t algtype, int sizespec)
200*7c478bd9Sstevel@tonic-gate {
201*7c478bd9Sstevel@tonic-gate 	char				filename[MAXPATHLEN];
202*7c478bd9Sstevel@tonic-gate 	struct cachekey_header		*ch;
203*7c478bd9Sstevel@tonic-gate 	int				fd, newfile = 0, i, checkvalid = 1;
204*7c478bd9Sstevel@tonic-gate 	struct stat			statbuf;
205*7c478bd9Sstevel@tonic-gate 	size_t				reclength, length;
206*7c478bd9Sstevel@tonic-gate 	struct cachekey_header		*oldbase = 0;
207*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist	*cd;
208*7c478bd9Sstevel@tonic-gate 	size_t maxsize;
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 	/* Construct cache file name */
211*7c478bd9Sstevel@tonic-gate 	if (snprintf(filename, sizeof (filename), "/var/nis/.keyserv_%d-%d",
212*7c478bd9Sstevel@tonic-gate 			keylen, algtype) > sizeof (filename)) {
213*7c478bd9Sstevel@tonic-gate 		syslog(LOG_WARNING,
214*7c478bd9Sstevel@tonic-gate 		"error constructing file name for mech %d-%d", keylen, algtype);
215*7c478bd9Sstevel@tonic-gate 		return (0);
216*7c478bd9Sstevel@tonic-gate 	}
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate 	/* Open/create the file */
219*7c478bd9Sstevel@tonic-gate 	if ((fd = open(filename, O_RDWR|O_CREAT, 0600)) < 0) {
220*7c478bd9Sstevel@tonic-gate 		syslog(LOG_WARNING, "cache file open error for mech %d-%d: %m",
221*7c478bd9Sstevel@tonic-gate 			keylen, algtype);
222*7c478bd9Sstevel@tonic-gate 		return (0);
223*7c478bd9Sstevel@tonic-gate 	}
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 	/* We want exclusive use of the file */
226*7c478bd9Sstevel@tonic-gate 	if (lockf(fd, F_LOCK, 0) < 0) {
227*7c478bd9Sstevel@tonic-gate 		syslog(LOG_WARNING, "cache file lock error for mech %d-%d: %m",
228*7c478bd9Sstevel@tonic-gate 			keylen, algtype);
229*7c478bd9Sstevel@tonic-gate 		close(fd);
230*7c478bd9Sstevel@tonic-gate 		return (0);
231*7c478bd9Sstevel@tonic-gate 	}
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	/* Zero size means a new file */
234*7c478bd9Sstevel@tonic-gate 	if (fstat(fd, &statbuf) < 0) {
235*7c478bd9Sstevel@tonic-gate 		syslog(LOG_WARNING, "cache file fstat error for mech %d-%d: %m",
236*7c478bd9Sstevel@tonic-gate 			keylen, algtype);
237*7c478bd9Sstevel@tonic-gate 		close(fd);
238*7c478bd9Sstevel@tonic-gate 		return (0);
239*7c478bd9Sstevel@tonic-gate 	}
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 	reclength = CACHEKEY_RECLEN(keylen);
242*7c478bd9Sstevel@tonic-gate 	if (sizespec < 0) {
243*7c478bd9Sstevel@tonic-gate 		/* specifies the number of records in file */
244*7c478bd9Sstevel@tonic-gate 		maxsize = ALIGN8(sizeof (struct cachekey_header)) +
245*7c478bd9Sstevel@tonic-gate 			-sizespec*reclength;
246*7c478bd9Sstevel@tonic-gate 	} else {
247*7c478bd9Sstevel@tonic-gate 		/* specifies size of file in MB */
248*7c478bd9Sstevel@tonic-gate 		maxsize = sizespec*1024*1024;
249*7c478bd9Sstevel@tonic-gate 	}
250*7c478bd9Sstevel@tonic-gate 	length    = ALIGN8(sizeof (struct cachekey_header)) +
251*7c478bd9Sstevel@tonic-gate 			reclength*CHUNK_NUMREC;
252*7c478bd9Sstevel@tonic-gate 	if (length > maxsize) {
253*7c478bd9Sstevel@tonic-gate 		/*
254*7c478bd9Sstevel@tonic-gate 		 * First record resides partly in the header, so the length
255*7c478bd9Sstevel@tonic-gate 		 * cannot be allowed to be less than header plus one record.
256*7c478bd9Sstevel@tonic-gate 		 */
257*7c478bd9Sstevel@tonic-gate 		if (maxsize > ALIGN8(sizeof (struct cachekey_header)+reclength))
258*7c478bd9Sstevel@tonic-gate 			length = maxsize;
259*7c478bd9Sstevel@tonic-gate 		else {
260*7c478bd9Sstevel@tonic-gate 			length  = ALIGN8(sizeof (struct cachekey_header)+
261*7c478bd9Sstevel@tonic-gate 					reclength);
262*7c478bd9Sstevel@tonic-gate 			maxsize = length;
263*7c478bd9Sstevel@tonic-gate 		}
264*7c478bd9Sstevel@tonic-gate 	}
265*7c478bd9Sstevel@tonic-gate 
266*7c478bd9Sstevel@tonic-gate 	if (statbuf.st_size == 0) {
267*7c478bd9Sstevel@tonic-gate 		/* Extend the file if we just created it */
268*7c478bd9Sstevel@tonic-gate 		if (ftruncate(fd, length) < 0) {
269*7c478bd9Sstevel@tonic-gate 			syslog(LOG_WARNING,
270*7c478bd9Sstevel@tonic-gate 				"cache file ftruncate error for mech %d-%d: %m",
271*7c478bd9Sstevel@tonic-gate 				keylen, algtype);
272*7c478bd9Sstevel@tonic-gate 			close(fd);
273*7c478bd9Sstevel@tonic-gate 			return (0);
274*7c478bd9Sstevel@tonic-gate 		}
275*7c478bd9Sstevel@tonic-gate 		newfile = 1;
276*7c478bd9Sstevel@tonic-gate 	} else {
277*7c478bd9Sstevel@tonic-gate 		/*
278*7c478bd9Sstevel@tonic-gate 		 * Temporarily mmap the header, to sanity check and obtain
279*7c478bd9Sstevel@tonic-gate 		 * the address where it was mapped the last time.
280*7c478bd9Sstevel@tonic-gate 		 */
281*7c478bd9Sstevel@tonic-gate 		if ((ch = (void *)mmap(0, sizeof (struct cachekey_header),
282*7c478bd9Sstevel@tonic-gate 				PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) ==
283*7c478bd9Sstevel@tonic-gate 			MAP_FAILED) {
284*7c478bd9Sstevel@tonic-gate 			syslog(LOG_WARNING,
285*7c478bd9Sstevel@tonic-gate 				"cache file mmap1 error for mech %d-%d: %m",
286*7c478bd9Sstevel@tonic-gate 				keylen, algtype);
287*7c478bd9Sstevel@tonic-gate 			close(fd);
288*7c478bd9Sstevel@tonic-gate 			return (0);
289*7c478bd9Sstevel@tonic-gate 		}
290*7c478bd9Sstevel@tonic-gate 		if (ch->version != CACHEKEY_HEADER_VERSION ||
291*7c478bd9Sstevel@tonic-gate 			ch->headerlength != sizeof (struct cachekey_header) ||
292*7c478bd9Sstevel@tonic-gate 			ch->keylen != keylen ||
293*7c478bd9Sstevel@tonic-gate 			ch->algtype != algtype ||
294*7c478bd9Sstevel@tonic-gate 			ch->reclength != reclength ||
295*7c478bd9Sstevel@tonic-gate 			ch->length < sizeof (struct cachekey_header) ||
296*7c478bd9Sstevel@tonic-gate 			ch->maxsize < ch->length ||
297*7c478bd9Sstevel@tonic-gate 			INVALID_ADDRESS(ch->inuse, ch) ||
298*7c478bd9Sstevel@tonic-gate 			INVALID_ADDRESS(ch->free, ch)) {
299*7c478bd9Sstevel@tonic-gate 			syslog(LOG_WARNING,
300*7c478bd9Sstevel@tonic-gate 			"cache file consistency error for mech %d-%d",
301*7c478bd9Sstevel@tonic-gate 				keylen, algtype);
302*7c478bd9Sstevel@tonic-gate 			munmap((caddr_t)ch, sizeof (struct cachekey_header));
303*7c478bd9Sstevel@tonic-gate 			close(fd);
304*7c478bd9Sstevel@tonic-gate 			return (0);
305*7c478bd9Sstevel@tonic-gate 		}
306*7c478bd9Sstevel@tonic-gate 		oldbase = (void *)ch->address;
307*7c478bd9Sstevel@tonic-gate 		length  = ch->length;
308*7c478bd9Sstevel@tonic-gate 		if (munmap((caddr_t)ch, sizeof (struct cachekey_header)) < 0) {
309*7c478bd9Sstevel@tonic-gate 			syslog(LOG_WARNING,
310*7c478bd9Sstevel@tonic-gate 				"cache file munmap error for mech %d-%d: %m",
311*7c478bd9Sstevel@tonic-gate 				keylen, algtype);
312*7c478bd9Sstevel@tonic-gate 			close(fd);
313*7c478bd9Sstevel@tonic-gate 			return (0);
314*7c478bd9Sstevel@tonic-gate 		}
315*7c478bd9Sstevel@tonic-gate 	}
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate 	/* Map the file */
318*7c478bd9Sstevel@tonic-gate 	if ((ch = (void *)mmap((caddr_t)oldbase, length,
319*7c478bd9Sstevel@tonic-gate 		PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
320*7c478bd9Sstevel@tonic-gate 		syslog(LOG_WARNING,
321*7c478bd9Sstevel@tonic-gate 			"cache file mmap2 error for mech %d-%d: %m",
322*7c478bd9Sstevel@tonic-gate 				keylen, algtype);
323*7c478bd9Sstevel@tonic-gate 		close(fd);
324*7c478bd9Sstevel@tonic-gate 		return (0);
325*7c478bd9Sstevel@tonic-gate 	}
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 	ch->fd		= fd;
328*7c478bd9Sstevel@tonic-gate 	ch->maxsize	= maxsize;
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 	if (newfile) {
331*7c478bd9Sstevel@tonic-gate 		ch->version		= CACHEKEY_HEADER_VERSION;
332*7c478bd9Sstevel@tonic-gate 		ch->headerlength	= sizeof (struct cachekey_header);
333*7c478bd9Sstevel@tonic-gate 		ch->keylen		= keylen;
334*7c478bd9Sstevel@tonic-gate 		ch->algtype		= algtype;
335*7c478bd9Sstevel@tonic-gate 		ch->reclength		= reclength;
336*7c478bd9Sstevel@tonic-gate 		ch->length		= length;
337*7c478bd9Sstevel@tonic-gate 		ch->address		= (caddr_t)ch;
338*7c478bd9Sstevel@tonic-gate 		ch->inuse_count		= 0;
339*7c478bd9Sstevel@tonic-gate 		ch->inuse		= 0;
340*7c478bd9Sstevel@tonic-gate 		ch->inuse_end		= 0;
341*7c478bd9Sstevel@tonic-gate 		ch->free		= 0;
342*7c478bd9Sstevel@tonic-gate 		ch->free_count		= 0;
343*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < NUMHASHBUCKETS; i++) {
344*7c478bd9Sstevel@tonic-gate 			ch->bucket[i] = 0;
345*7c478bd9Sstevel@tonic-gate 		}
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 		cd = &(ch->array[0]);
348*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAPRECS(ch);
349*7c478bd9Sstevel@tonic-gate 			i++, cd = MOVE_ADDR(cd, ch->reclength)) {
350*7c478bd9Sstevel@tonic-gate 			cd->uid		= (uid_t)-1;
351*7c478bd9Sstevel@tonic-gate 			cd->prev	= MOVE_ADDR(cd, -(ch->reclength));
352*7c478bd9Sstevel@tonic-gate 			cd->next	= MOVE_ADDR(cd, +(ch->reclength));
353*7c478bd9Sstevel@tonic-gate 			cd->prevhash	= 0;
354*7c478bd9Sstevel@tonic-gate 			cd->nexthash	= 0;
355*7c478bd9Sstevel@tonic-gate 		}
356*7c478bd9Sstevel@tonic-gate 		/*
357*7c478bd9Sstevel@tonic-gate 		 * Last record next pointer, and first record prev pointer,
358*7c478bd9Sstevel@tonic-gate 		 * are both NULL.
359*7c478bd9Sstevel@tonic-gate 		 */
360*7c478bd9Sstevel@tonic-gate 		cd		= MOVE_ADDR(cd, -(ch->reclength));
361*7c478bd9Sstevel@tonic-gate 		cd->next	= 0;
362*7c478bd9Sstevel@tonic-gate 		cd		= &(ch->array[0]);
363*7c478bd9Sstevel@tonic-gate 		cd->prev	= 0;
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 		ch->free_count	= MAPRECS(ch);
366*7c478bd9Sstevel@tonic-gate 		ch->free	= &(ch->array[0]);
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 		(void) msync((caddr_t)ch, ch->length, MS_SYNC);
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate 	} else if (ch->length > maxsize) {
371*7c478bd9Sstevel@tonic-gate 		/* File should shrink */
372*7c478bd9Sstevel@tonic-gate 		if ((ch = remap_cache_file_ch(ch, MAXRECS(ch))) == 0) {
373*7c478bd9Sstevel@tonic-gate 			return (0);
374*7c478bd9Sstevel@tonic-gate 		}
375*7c478bd9Sstevel@tonic-gate 		checkvalid = 0;
376*7c478bd9Sstevel@tonic-gate 	}
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 	/*
379*7c478bd9Sstevel@tonic-gate 	 * cache_remap_addresses() also checks address consistency, so call
380*7c478bd9Sstevel@tonic-gate 	 * it even if the remap is a no-op. However, if we've called
381*7c478bd9Sstevel@tonic-gate 	 * remap_cache_file_ch(), it will have invoked cache_remap_addresses()
382*7c478bd9Sstevel@tonic-gate 	 * already, so we don't have to do that again.
383*7c478bd9Sstevel@tonic-gate 	 */
384*7c478bd9Sstevel@tonic-gate 	if (checkvalid &&
385*7c478bd9Sstevel@tonic-gate 		cache_remap_addresses_ch(ch) == 0) {
386*7c478bd9Sstevel@tonic-gate 		syslog(LOG_WARNING, "cache file invalid for mech %d-%d",
387*7c478bd9Sstevel@tonic-gate 			keylen, algtype);
388*7c478bd9Sstevel@tonic-gate 		(void) munmap((caddr_t)ch, ch->length);
389*7c478bd9Sstevel@tonic-gate 		close(fd);
390*7c478bd9Sstevel@tonic-gate 		return (0);
391*7c478bd9Sstevel@tonic-gate 	}
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 	(void) msync((caddr_t)ch, ch->length, MS_SYNC);
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 	return (ch);
396*7c478bd9Sstevel@tonic-gate }
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate static int
cache_remap_addresses_ch(struct cachekey_header * ch)400*7c478bd9Sstevel@tonic-gate cache_remap_addresses_ch(struct cachekey_header *ch)
401*7c478bd9Sstevel@tonic-gate {
402*7c478bd9Sstevel@tonic-gate 	int				i;
403*7c478bd9Sstevel@tonic-gate 	u_long				offset;
404*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist	*cd;
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 	offset = (u_long)ch - (u_long)ch->address;
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	if (INVALID_ADDRESS(ch->inuse, ch) ||
409*7c478bd9Sstevel@tonic-gate 		INVALID_ADDRESS(ch->inuse_end, ch) ||
410*7c478bd9Sstevel@tonic-gate 		INVALID_ADDRESS(ch->free, ch)) {
411*7c478bd9Sstevel@tonic-gate 		return (0);
412*7c478bd9Sstevel@tonic-gate 	}
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 	ch->inuse	= MOVE_ADDR(ch->inuse, offset);
415*7c478bd9Sstevel@tonic-gate 	ch->inuse_end	= MOVE_ADDR(ch->inuse_end, offset);
416*7c478bd9Sstevel@tonic-gate 	ch->free	= MOVE_ADDR(ch->free, offset);
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 	cd = &(ch->array[0]);
419*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < NUMRECS(ch); i++) {
420*7c478bd9Sstevel@tonic-gate 		if (INVALID_ADDRESS(cd->prev, ch) ||
421*7c478bd9Sstevel@tonic-gate 			INVALID_ADDRESS(cd->next, ch) ||
422*7c478bd9Sstevel@tonic-gate 			INVALID_ADDRESS(cd->prevhash, ch) ||
423*7c478bd9Sstevel@tonic-gate 			INVALID_ADDRESS(cd->nexthash, ch)) {
424*7c478bd9Sstevel@tonic-gate 			return (0);
425*7c478bd9Sstevel@tonic-gate 		}
426*7c478bd9Sstevel@tonic-gate 		cd->prev	= MOVE_ADDR(cd->prev, offset);
427*7c478bd9Sstevel@tonic-gate 		cd->next	= MOVE_ADDR(cd->next, offset);
428*7c478bd9Sstevel@tonic-gate 		cd->prevhash	= MOVE_ADDR(cd->prevhash, offset);
429*7c478bd9Sstevel@tonic-gate 		cd->nexthash	= MOVE_ADDR(cd->nexthash, offset);
430*7c478bd9Sstevel@tonic-gate 		cd = MOVE_ADDR(cd, ch->reclength);
431*7c478bd9Sstevel@tonic-gate 	}
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < NUMHASHBUCKETS; i++) {
434*7c478bd9Sstevel@tonic-gate 		if (INVALID_ADDRESS(ch->bucket[i], ch)) {
435*7c478bd9Sstevel@tonic-gate 			return (0);
436*7c478bd9Sstevel@tonic-gate 		}
437*7c478bd9Sstevel@tonic-gate 		ch->bucket[i] = MOVE_ADDR(ch->bucket[i], offset);
438*7c478bd9Sstevel@tonic-gate 	}
439*7c478bd9Sstevel@tonic-gate 
440*7c478bd9Sstevel@tonic-gate 	/*
441*7c478bd9Sstevel@tonic-gate 	 * To prevent disaster if this function is invoked again, we
442*7c478bd9Sstevel@tonic-gate 	 * update ch->address, so that offset will be zero if we do
443*7c478bd9Sstevel@tonic-gate 	 * get called once more, and the mapped file hasn't moved.
444*7c478bd9Sstevel@tonic-gate 	 */
445*7c478bd9Sstevel@tonic-gate 	ch->address = (caddr_t)ch;
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 	return (1);
448*7c478bd9Sstevel@tonic-gate }
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate /*
452*7c478bd9Sstevel@tonic-gate  * Remap cache file with space for 'newrecs' records. The mmap:ed address
453*7c478bd9Sstevel@tonic-gate  * may have to move; the new address is returned.
454*7c478bd9Sstevel@tonic-gate  */
455*7c478bd9Sstevel@tonic-gate static struct cachekey_header *
remap_cache_file_ch(struct cachekey_header * ch,u_int newrecs)456*7c478bd9Sstevel@tonic-gate remap_cache_file_ch(struct cachekey_header *ch, u_int newrecs)
457*7c478bd9Sstevel@tonic-gate {
458*7c478bd9Sstevel@tonic-gate 	size_t				newsize, oldsize;
459*7c478bd9Sstevel@tonic-gate 	u_int				currecs;
460*7c478bd9Sstevel@tonic-gate 	int				i, fd;
461*7c478bd9Sstevel@tonic-gate 	struct cachekey_header		*newch;
462*7c478bd9Sstevel@tonic-gate 	caddr_t				oldaddr;
463*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist	*cd = 0;
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	if (ch == 0)
466*7c478bd9Sstevel@tonic-gate 		return (0);
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 	/*
470*7c478bd9Sstevel@tonic-gate 	 * Since the first record partly resides in the cachekey_header,
471*7c478bd9Sstevel@tonic-gate 	 * newrecs cannot be less than 1.
472*7c478bd9Sstevel@tonic-gate 	 */
473*7c478bd9Sstevel@tonic-gate 	if (newrecs < 1)
474*7c478bd9Sstevel@tonic-gate 		newrecs = 1;
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 	newsize = ALIGN8(sizeof (struct cachekey_header)) +
477*7c478bd9Sstevel@tonic-gate 			(ch->reclength)*newrecs;
478*7c478bd9Sstevel@tonic-gate 	currecs = NUMRECS(ch);
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	if (newsize > ch->maxsize) {
481*7c478bd9Sstevel@tonic-gate 		/* Would exceed maximum allowed */
482*7c478bd9Sstevel@tonic-gate 		newsize = ch->maxsize;
483*7c478bd9Sstevel@tonic-gate 	}
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	/* Save stuff we need while the file is unmapped */
486*7c478bd9Sstevel@tonic-gate 	oldsize	= ch->length;
487*7c478bd9Sstevel@tonic-gate 	oldaddr	= (caddr_t)ch;
488*7c478bd9Sstevel@tonic-gate 	fd	= ch->fd;
489*7c478bd9Sstevel@tonic-gate 
490*7c478bd9Sstevel@tonic-gate 	if (newsize > ch->length) {
491*7c478bd9Sstevel@tonic-gate 		/* Extending the file */
492*7c478bd9Sstevel@tonic-gate 		cd = &(ch->array[0]);
493*7c478bd9Sstevel@tonic-gate 	} else if (newsize == ch->length) {
494*7c478bd9Sstevel@tonic-gate 		/* Already OK */
495*7c478bd9Sstevel@tonic-gate 		return (ch);
496*7c478bd9Sstevel@tonic-gate 	} else {
497*7c478bd9Sstevel@tonic-gate 		size_t				tmpsize;
498*7c478bd9Sstevel@tonic-gate 		struct cachekey_disklist	*fcd;
499*7c478bd9Sstevel@tonic-gate 		/*
500*7c478bd9Sstevel@tonic-gate 		 * Shrink the file by removing records from the end.
501*7c478bd9Sstevel@tonic-gate 		 * First, we have to make sure the file contains valid
502*7c478bd9Sstevel@tonic-gate 		 * addresses.
503*7c478bd9Sstevel@tonic-gate 		 */
504*7c478bd9Sstevel@tonic-gate 		if (cache_remap_addresses_ch(ch) == 0) {
505*7c478bd9Sstevel@tonic-gate 			syslog(LOG_WARNING, "cache file invalid for mech %d-%d",
506*7c478bd9Sstevel@tonic-gate 			ch->keylen, ch->algtype);
507*7c478bd9Sstevel@tonic-gate 			close(ch->fd);
508*7c478bd9Sstevel@tonic-gate 			munmap((caddr_t)ch, ch->length);
509*7c478bd9Sstevel@tonic-gate 			return (0);
510*7c478bd9Sstevel@tonic-gate 		}
511*7c478bd9Sstevel@tonic-gate 		fcd = MOVE_ADDR(&(ch->array[0]),
512*7c478bd9Sstevel@tonic-gate 				ch->reclength*(MAPRECS(ch)-1));
513*7c478bd9Sstevel@tonic-gate 		tmpsize = (u_long)fcd - (u_long)ch + ch->reclength;
514*7c478bd9Sstevel@tonic-gate 		while (tmpsize > newsize && fcd > &(ch->array[0])) {
515*7c478bd9Sstevel@tonic-gate 			if (fcd->uid == (uid_t)-1) {
516*7c478bd9Sstevel@tonic-gate 				list_remove(fcd, &(ch->free), 0,
517*7c478bd9Sstevel@tonic-gate 					&(ch->free_count));
518*7c478bd9Sstevel@tonic-gate 			} else {
519*7c478bd9Sstevel@tonic-gate 				list_remove_hash(fcd,
520*7c478bd9Sstevel@tonic-gate 					&(ch->bucket[hashval(fcd->uid)]), 0, 0);
521*7c478bd9Sstevel@tonic-gate 				list_remove(fcd, &(ch->inuse), &(ch->inuse_end),
522*7c478bd9Sstevel@tonic-gate 						&(ch->inuse_count));
523*7c478bd9Sstevel@tonic-gate 			}
524*7c478bd9Sstevel@tonic-gate 			tmpsize -= ch->reclength;
525*7c478bd9Sstevel@tonic-gate 			fcd = MOVE_ADDR(fcd, -(ch->reclength));
526*7c478bd9Sstevel@tonic-gate 		}
527*7c478bd9Sstevel@tonic-gate 		ch->length = newsize;
528*7c478bd9Sstevel@tonic-gate 		(void) msync((caddr_t)ch, ch->length, MS_SYNC);
529*7c478bd9Sstevel@tonic-gate 	}
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 	/* Unmap the file */
532*7c478bd9Sstevel@tonic-gate 	if (munmap((caddr_t)oldaddr, oldsize) < 0) {
533*7c478bd9Sstevel@tonic-gate 		return (0);
534*7c478bd9Sstevel@tonic-gate 	}
535*7c478bd9Sstevel@tonic-gate 	ch = 0;
536*7c478bd9Sstevel@tonic-gate 
537*7c478bd9Sstevel@tonic-gate 	/* Truncate/extend it */
538*7c478bd9Sstevel@tonic-gate 	if (ftruncate(fd, newsize) < 0) {
539*7c478bd9Sstevel@tonic-gate 		return (0);
540*7c478bd9Sstevel@tonic-gate 	}
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 	/* Map it again */
543*7c478bd9Sstevel@tonic-gate 	if ((newch = (void *)mmap(oldaddr, newsize,
544*7c478bd9Sstevel@tonic-gate 			PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) ==
545*7c478bd9Sstevel@tonic-gate 	MAP_FAILED) {
546*7c478bd9Sstevel@tonic-gate 		return (0);
547*7c478bd9Sstevel@tonic-gate 	}
548*7c478bd9Sstevel@tonic-gate 
549*7c478bd9Sstevel@tonic-gate 	/* Update with new values */
550*7c478bd9Sstevel@tonic-gate 	newch->length	= newsize;
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 	if (cache_remap_addresses_ch(newch) == 0) {
553*7c478bd9Sstevel@tonic-gate 		syslog(LOG_WARNING, "cache file invalid for mech %d-%d",
554*7c478bd9Sstevel@tonic-gate 			newch->keylen, newch->algtype);
555*7c478bd9Sstevel@tonic-gate 		newch->length = oldsize;
556*7c478bd9Sstevel@tonic-gate 		close(newch->fd);
557*7c478bd9Sstevel@tonic-gate 		munmap((caddr_t)newch, newsize);
558*7c478bd9Sstevel@tonic-gate 		return (0);
559*7c478bd9Sstevel@tonic-gate 	}
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 	/* If extending the file, add new records to the free list */
562*7c478bd9Sstevel@tonic-gate 	if (cd != 0) {
563*7c478bd9Sstevel@tonic-gate 		cd = MOVE_ADDR(&(newch->array[0]), currecs*newch->reclength);
564*7c478bd9Sstevel@tonic-gate 		for (i = currecs; i < MAPRECS(newch); i++) {
565*7c478bd9Sstevel@tonic-gate 			cd->uid		= (uid_t)-1;
566*7c478bd9Sstevel@tonic-gate 			list_insert(cd, &(newch->free), 0,
567*7c478bd9Sstevel@tonic-gate 					&(newch->free_count));
568*7c478bd9Sstevel@tonic-gate 			cd		= MOVE_ADDR(cd, newch->reclength);
569*7c478bd9Sstevel@tonic-gate 		}
570*7c478bd9Sstevel@tonic-gate 	}
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 	(void) msync(newch->address, newch->length, MS_SYNC);
573*7c478bd9Sstevel@tonic-gate 
574*7c478bd9Sstevel@tonic-gate 	return (newch);
575*7c478bd9Sstevel@tonic-gate }
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 
578*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
579*7c478bd9Sstevel@tonic-gate void
print_cache_ch(struct cachekey_header * ch)580*7c478bd9Sstevel@tonic-gate print_cache_ch(struct cachekey_header *ch)
581*7c478bd9Sstevel@tonic-gate {
582*7c478bd9Sstevel@tonic-gate 	int				i, inuse, inuse_err, free, free_err;
583*7c478bd9Sstevel@tonic-gate 	int				pb;
584*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist	*cd;
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate 	printf(
587*7c478bd9Sstevel@tonic-gate "\nkeylen = %d, algtype = %d, version = %d, headerlen = %d, reclen = %d\n",
588*7c478bd9Sstevel@tonic-gate 		ch->keylen, ch->algtype, ch->version, ch->headerlength,
589*7c478bd9Sstevel@tonic-gate 		ch->reclength);
590*7c478bd9Sstevel@tonic-gate 	printf("fd = %d, address = 0x%x, mapped length = %d, maxsize = %d\n",
591*7c478bd9Sstevel@tonic-gate 		ch->fd, ch->address, ch->length, ch->maxsize);
592*7c478bd9Sstevel@tonic-gate 	printf("inuse = %d, free = %d\n", ch->inuse_count, ch->free_count);
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 	printf("Active hash buckets:\n");
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate 	for (i = 0, inuse = 0, inuse_err = 0; i < NUMHASHBUCKETS; i++) {
597*7c478bd9Sstevel@tonic-gate 		cd = ch->bucket[i];
598*7c478bd9Sstevel@tonic-gate 		pb = -1;
599*7c478bd9Sstevel@tonic-gate 		if (cd != 0) {
600*7c478bd9Sstevel@tonic-gate 			pb = 0;
601*7c478bd9Sstevel@tonic-gate 			printf("\t%d: ", i);
602*7c478bd9Sstevel@tonic-gate 		}
603*7c478bd9Sstevel@tonic-gate 		while (cd != 0) {
604*7c478bd9Sstevel@tonic-gate 			pb++;
605*7c478bd9Sstevel@tonic-gate 			printf("%d ", cd->uid);
606*7c478bd9Sstevel@tonic-gate 			if (cd->uid != (uid_t)-1) {
607*7c478bd9Sstevel@tonic-gate 				inuse++;
608*7c478bd9Sstevel@tonic-gate 			} else {
609*7c478bd9Sstevel@tonic-gate 				inuse_err++;
610*7c478bd9Sstevel@tonic-gate 			}
611*7c478bd9Sstevel@tonic-gate 			cd = cd->nexthash;
612*7c478bd9Sstevel@tonic-gate 		}
613*7c478bd9Sstevel@tonic-gate 		if (pb >= 0)
614*7c478bd9Sstevel@tonic-gate 			printf(" (%d)\n", pb);
615*7c478bd9Sstevel@tonic-gate 	}
616*7c478bd9Sstevel@tonic-gate 
617*7c478bd9Sstevel@tonic-gate 	printf("\ncounted hash inuse = %d, errors = %d\n", inuse, inuse_err);
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate 	cd = ch->inuse;
620*7c478bd9Sstevel@tonic-gate 	inuse = inuse_err = 0;
621*7c478bd9Sstevel@tonic-gate 	while (cd != 0) {
622*7c478bd9Sstevel@tonic-gate 		if (cd->uid != (uid_t)-1) {
623*7c478bd9Sstevel@tonic-gate 			inuse++;
624*7c478bd9Sstevel@tonic-gate 		} else {
625*7c478bd9Sstevel@tonic-gate 			inuse_err++;
626*7c478bd9Sstevel@tonic-gate 		}
627*7c478bd9Sstevel@tonic-gate 		cd = cd->next;
628*7c478bd9Sstevel@tonic-gate 	}
629*7c478bd9Sstevel@tonic-gate 	printf("counted LRU  inuse = %d, errors = %d\n", inuse, inuse_err);
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate 	cd = ch->free;
632*7c478bd9Sstevel@tonic-gate 	free = free_err = 0;
633*7c478bd9Sstevel@tonic-gate 	while (cd != 0) {
634*7c478bd9Sstevel@tonic-gate 		if (cd->uid == (uid_t)-1) {
635*7c478bd9Sstevel@tonic-gate 			free++;
636*7c478bd9Sstevel@tonic-gate 		} else {
637*7c478bd9Sstevel@tonic-gate 			free_err++;
638*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, "free = %d, err = %d, cd->uid = %d\n",
639*7c478bd9Sstevel@tonic-gate 				free, free_err, cd->uid);
640*7c478bd9Sstevel@tonic-gate 		}
641*7c478bd9Sstevel@tonic-gate 		cd = cd->next;
642*7c478bd9Sstevel@tonic-gate 	}
643*7c478bd9Sstevel@tonic-gate 	printf("counted      free = %d, errors = %d\n", free, free_err);
644*7c478bd9Sstevel@tonic-gate }
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate void
print_cache(keylen_t keylen,algtype_t algtype)647*7c478bd9Sstevel@tonic-gate print_cache(keylen_t keylen, algtype_t algtype)
648*7c478bd9Sstevel@tonic-gate {
649*7c478bd9Sstevel@tonic-gate 	struct cachekey	*c;
650*7c478bd9Sstevel@tonic-gate 
651*7c478bd9Sstevel@tonic-gate 	if ((c = get_cache_header(keylen, algtype)) == 0)
652*7c478bd9Sstevel@tonic-gate 		return;
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate 	if (c->ch == 0) {
655*7c478bd9Sstevel@tonic-gate 		release_cache_header(c);
656*7c478bd9Sstevel@tonic-gate 		return;
657*7c478bd9Sstevel@tonic-gate 	}
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate 	print_cache_ch(c->ch);
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate 	release_cache_header(c);
662*7c478bd9Sstevel@tonic-gate }
663*7c478bd9Sstevel@tonic-gate #endif
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate static u_int
hashval(uid_t uid)668*7c478bd9Sstevel@tonic-gate hashval(uid_t uid)
669*7c478bd9Sstevel@tonic-gate {
670*7c478bd9Sstevel@tonic-gate 	return (uid % NUMHASHBUCKETS);
671*7c478bd9Sstevel@tonic-gate }
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate static void
list_remove(struct cachekey_disklist * item,struct cachekey_disklist ** head,struct cachekey_disklist ** tail,u_int * count)675*7c478bd9Sstevel@tonic-gate list_remove(
676*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist *item,
677*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist **head,
678*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist **tail,
679*7c478bd9Sstevel@tonic-gate 	u_int *count)
680*7c478bd9Sstevel@tonic-gate {
681*7c478bd9Sstevel@tonic-gate 	if (item == NULL) return;
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 	/* Handle previous item, if any */
684*7c478bd9Sstevel@tonic-gate 	if (item->prev == 0)
685*7c478bd9Sstevel@tonic-gate 		*head = item->next;
686*7c478bd9Sstevel@tonic-gate 	else
687*7c478bd9Sstevel@tonic-gate 		item->prev->next = item->next;
688*7c478bd9Sstevel@tonic-gate 
689*7c478bd9Sstevel@tonic-gate 	/* Take care of the next item, if any */
690*7c478bd9Sstevel@tonic-gate 	if (item->next != 0)
691*7c478bd9Sstevel@tonic-gate 		item->next->prev = item->prev;
692*7c478bd9Sstevel@tonic-gate 
693*7c478bd9Sstevel@tonic-gate 	/* Handle tail pointer, if supplied */
694*7c478bd9Sstevel@tonic-gate 	if (tail != 0 && *tail == item)
695*7c478bd9Sstevel@tonic-gate 		*tail = item->prev;
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate 	item->prev = item->next = 0;
698*7c478bd9Sstevel@tonic-gate 	if (count != 0)
699*7c478bd9Sstevel@tonic-gate 		(*count)--;
700*7c478bd9Sstevel@tonic-gate }
701*7c478bd9Sstevel@tonic-gate 
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate static void
list_remove_hash(struct cachekey_disklist * item,struct cachekey_disklist ** head,struct cachekey_disklist ** tail,u_int * count)704*7c478bd9Sstevel@tonic-gate list_remove_hash(
705*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist *item,
706*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist **head,
707*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist **tail,
708*7c478bd9Sstevel@tonic-gate 	u_int *count)
709*7c478bd9Sstevel@tonic-gate {
710*7c478bd9Sstevel@tonic-gate 	if (item == NULL) return;
711*7c478bd9Sstevel@tonic-gate 
712*7c478bd9Sstevel@tonic-gate 	/* Handle previous item, if any */
713*7c478bd9Sstevel@tonic-gate 	if (item->prevhash == 0)
714*7c478bd9Sstevel@tonic-gate 		*head = item->nexthash;
715*7c478bd9Sstevel@tonic-gate 	else
716*7c478bd9Sstevel@tonic-gate 		item->prevhash->nexthash = item->nexthash;
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 	/* Take care of the next item, if any */
719*7c478bd9Sstevel@tonic-gate 	if (item->nexthash != 0)
720*7c478bd9Sstevel@tonic-gate 		item->nexthash->prevhash = item->prevhash;
721*7c478bd9Sstevel@tonic-gate 
722*7c478bd9Sstevel@tonic-gate 	/* Handle tail pointer, if supplied */
723*7c478bd9Sstevel@tonic-gate 	if (tail != 0 && *tail == item)
724*7c478bd9Sstevel@tonic-gate 		*tail = item->prevhash;
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 	item->prevhash = item->nexthash = 0;
727*7c478bd9Sstevel@tonic-gate 	if (count != 0)
728*7c478bd9Sstevel@tonic-gate 		(*count)--;
729*7c478bd9Sstevel@tonic-gate }
730*7c478bd9Sstevel@tonic-gate 
731*7c478bd9Sstevel@tonic-gate 
732*7c478bd9Sstevel@tonic-gate static void
list_insert(struct cachekey_disklist * item,struct cachekey_disklist ** head,struct cachekey_disklist ** tail,u_int * count)733*7c478bd9Sstevel@tonic-gate list_insert(
734*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist *item,
735*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist **head,
736*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist **tail,
737*7c478bd9Sstevel@tonic-gate 	u_int *count)
738*7c478bd9Sstevel@tonic-gate {
739*7c478bd9Sstevel@tonic-gate 	if (item == NULL) return;
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 	/* Insert at tail, if supplied */
742*7c478bd9Sstevel@tonic-gate 	if (tail != 0) {
743*7c478bd9Sstevel@tonic-gate 		item->prev = *tail;
744*7c478bd9Sstevel@tonic-gate 		if (item->prev != 0)
745*7c478bd9Sstevel@tonic-gate 			item->prev->next = item;
746*7c478bd9Sstevel@tonic-gate 		item->next	= 0;
747*7c478bd9Sstevel@tonic-gate 		*tail		= item;
748*7c478bd9Sstevel@tonic-gate 		if (*head == 0)
749*7c478bd9Sstevel@tonic-gate 			*head	= item;
750*7c478bd9Sstevel@tonic-gate 	} else {
751*7c478bd9Sstevel@tonic-gate 		item->next = *head;
752*7c478bd9Sstevel@tonic-gate 		if (item->next != 0)
753*7c478bd9Sstevel@tonic-gate 			item->next->prev = item;
754*7c478bd9Sstevel@tonic-gate 		item->prev	= 0;
755*7c478bd9Sstevel@tonic-gate 		*head		= item;
756*7c478bd9Sstevel@tonic-gate 	}
757*7c478bd9Sstevel@tonic-gate 	if (count != 0)
758*7c478bd9Sstevel@tonic-gate 		(*count)++;
759*7c478bd9Sstevel@tonic-gate }
760*7c478bd9Sstevel@tonic-gate 
761*7c478bd9Sstevel@tonic-gate static void
list_insert_hash(struct cachekey_disklist * item,struct cachekey_disklist ** head,struct cachekey_disklist ** tail,u_int * count)762*7c478bd9Sstevel@tonic-gate list_insert_hash(
763*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist *item,
764*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist **head,
765*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist **tail,
766*7c478bd9Sstevel@tonic-gate 	u_int *count)
767*7c478bd9Sstevel@tonic-gate {
768*7c478bd9Sstevel@tonic-gate 	if (item == NULL) return;
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate 	/* Insert at tail, if supplied */
771*7c478bd9Sstevel@tonic-gate 	if (tail != 0) {
772*7c478bd9Sstevel@tonic-gate 		item->prevhash = *tail;
773*7c478bd9Sstevel@tonic-gate 		if (item->prevhash != 0)
774*7c478bd9Sstevel@tonic-gate 			item->prevhash->nexthash = item;
775*7c478bd9Sstevel@tonic-gate 		item->nexthash	= 0;
776*7c478bd9Sstevel@tonic-gate 		*tail		= item;
777*7c478bd9Sstevel@tonic-gate 		if (*head == 0)
778*7c478bd9Sstevel@tonic-gate 			*head	= item;
779*7c478bd9Sstevel@tonic-gate 	} else {
780*7c478bd9Sstevel@tonic-gate 		item->nexthash	= *head;
781*7c478bd9Sstevel@tonic-gate 		if (item->nexthash != 0)
782*7c478bd9Sstevel@tonic-gate 			item->nexthash->prevhash = item;
783*7c478bd9Sstevel@tonic-gate 		item->prevhash	= 0;
784*7c478bd9Sstevel@tonic-gate 		*head		= item;
785*7c478bd9Sstevel@tonic-gate 	}
786*7c478bd9Sstevel@tonic-gate 	if (count != 0)
787*7c478bd9Sstevel@tonic-gate 		(*count)++;
788*7c478bd9Sstevel@tonic-gate }
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 
791*7c478bd9Sstevel@tonic-gate /*
792*7c478bd9Sstevel@tonic-gate  * Find the cache item specified by the header, uid, and public key. If
793*7c478bd9Sstevel@tonic-gate  * no such uid/public item exists, return a pointer to an empty record.
794*7c478bd9Sstevel@tonic-gate  * In either case, the item returned has been removed from any and all
795*7c478bd9Sstevel@tonic-gate  * lists.
796*7c478bd9Sstevel@tonic-gate  */
797*7c478bd9Sstevel@tonic-gate static struct cachekey_disklist *
find_cache_item(struct cachekey_header ** ch,uid_t uid,struct dhkey * public)798*7c478bd9Sstevel@tonic-gate find_cache_item(struct cachekey_header **ch, uid_t uid, struct dhkey *public)
799*7c478bd9Sstevel@tonic-gate {
800*7c478bd9Sstevel@tonic-gate 	u_int				hash;
801*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist	*cd;
802*7c478bd9Sstevel@tonic-gate 
803*7c478bd9Sstevel@tonic-gate 	hash = hashval(uid);
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate 	if ((ch == NULL) || ((*ch) == NULL)) {
806*7c478bd9Sstevel@tonic-gate 		return (0);
807*7c478bd9Sstevel@tonic-gate 	}
808*7c478bd9Sstevel@tonic-gate 	for (cd = (*ch)->bucket[hash]; cd != 0; cd = cd->nexthash) {
809*7c478bd9Sstevel@tonic-gate 		if (uid == cd->uid &&
810*7c478bd9Sstevel@tonic-gate 			public->length == cd->public.length &&
811*7c478bd9Sstevel@tonic-gate 			memcmp(public->key, cd->public.key,
812*7c478bd9Sstevel@tonic-gate 				cd->public.length) == 0) {
813*7c478bd9Sstevel@tonic-gate 			list_remove_hash(cd, &((*ch)->bucket[hash]), 0, 0);
814*7c478bd9Sstevel@tonic-gate 			list_remove(cd, &((*ch)->inuse), &((*ch)->inuse_end),
815*7c478bd9Sstevel@tonic-gate 					&((*ch)->inuse_count));
816*7c478bd9Sstevel@tonic-gate 			return (cd);
817*7c478bd9Sstevel@tonic-gate 		}
818*7c478bd9Sstevel@tonic-gate 	}
819*7c478bd9Sstevel@tonic-gate 
820*7c478bd9Sstevel@tonic-gate 	if ((cd = (*ch)->free) != 0) {
821*7c478bd9Sstevel@tonic-gate 		list_remove(cd, &((*ch)->free), 0, &((*ch)->free_count));
822*7c478bd9Sstevel@tonic-gate 		return (cd);
823*7c478bd9Sstevel@tonic-gate 	}
824*7c478bd9Sstevel@tonic-gate 
825*7c478bd9Sstevel@tonic-gate 	/* Try to extend the file by CHUNK_NUMREC records */
826*7c478bd9Sstevel@tonic-gate 	if (((*ch) = remap_cache_file_ch(*ch, NUMRECS(*ch)+CHUNK_NUMREC)) == 0)
827*7c478bd9Sstevel@tonic-gate 		return (0);
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate 	/* If the extend worked, there should now be at least one free record */
830*7c478bd9Sstevel@tonic-gate 	if ((cd = (*ch)->free) != 0) {
831*7c478bd9Sstevel@tonic-gate 		list_remove(cd, &((*ch)->free), 0, &((*ch)->free_count));
832*7c478bd9Sstevel@tonic-gate 		return (cd);
833*7c478bd9Sstevel@tonic-gate 	}
834*7c478bd9Sstevel@tonic-gate 
835*7c478bd9Sstevel@tonic-gate 	/* Sacrifice the LRU item, if there is one */
836*7c478bd9Sstevel@tonic-gate 	if ((cd = (*ch)->inuse) == 0)
837*7c478bd9Sstevel@tonic-gate 		return (0);
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 	/* Extract from hash list */
840*7c478bd9Sstevel@tonic-gate 	list_remove_hash(cd, &((*ch)->bucket[hashval(cd->uid)]), 0, 0);
841*7c478bd9Sstevel@tonic-gate 	/* Extract from LRU list */
842*7c478bd9Sstevel@tonic-gate 	list_remove(cd, &((*ch)->inuse), &((*ch)->inuse_end),
843*7c478bd9Sstevel@tonic-gate 			&((*ch)->inuse_count));
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate 	return (cd);
846*7c478bd9Sstevel@tonic-gate }
847*7c478bd9Sstevel@tonic-gate 
848*7c478bd9Sstevel@tonic-gate 
849*7c478bd9Sstevel@tonic-gate static struct cachekey_header *
cache_insert_ch(struct cachekey_header * ch,uid_t uid,deskeyarray common,des_block key,keybuf3 * public,keybuf3 * secret)850*7c478bd9Sstevel@tonic-gate cache_insert_ch(
851*7c478bd9Sstevel@tonic-gate 	struct cachekey_header *ch,
852*7c478bd9Sstevel@tonic-gate 	uid_t uid,
853*7c478bd9Sstevel@tonic-gate 	deskeyarray common,
854*7c478bd9Sstevel@tonic-gate 	des_block key,
855*7c478bd9Sstevel@tonic-gate 	keybuf3 *public,
856*7c478bd9Sstevel@tonic-gate 	keybuf3 *secret)
857*7c478bd9Sstevel@tonic-gate {
858*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist	*cd;
859*7c478bd9Sstevel@tonic-gate 	struct cachekey_header		*newch;
860*7c478bd9Sstevel@tonic-gate 	int				i, err;
861*7c478bd9Sstevel@tonic-gate 	struct skck			*skck;
862*7c478bd9Sstevel@tonic-gate 	des_block			ivec;
863*7c478bd9Sstevel@tonic-gate 	struct dhkey			*pk;
864*7c478bd9Sstevel@tonic-gate 	struct dhkey			*sk;
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate 
867*7c478bd9Sstevel@tonic-gate 	if (ch == 0 || uid == (uid_t)-1) {
868*7c478bd9Sstevel@tonic-gate 		return (0);
869*7c478bd9Sstevel@tonic-gate 	}
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate 	if (common.deskeyarray_len > sizeof (skck->common)/sizeof (des_block) ||
872*7c478bd9Sstevel@tonic-gate 		(pk = keybuf3_2_dhkey(public)) == 0 ||
873*7c478bd9Sstevel@tonic-gate 		(sk = keybuf3_2_dhkey(secret)) == 0) {
874*7c478bd9Sstevel@tonic-gate 		return (0);
875*7c478bd9Sstevel@tonic-gate 	}
876*7c478bd9Sstevel@tonic-gate 
877*7c478bd9Sstevel@tonic-gate 	newch = ch;
878*7c478bd9Sstevel@tonic-gate 	if ((cd = find_cache_item(&newch, uid, pk)) == 0) {
879*7c478bd9Sstevel@tonic-gate 		free(pk);
880*7c478bd9Sstevel@tonic-gate 		free(sk);
881*7c478bd9Sstevel@tonic-gate 		return (newch);
882*7c478bd9Sstevel@tonic-gate 	}
883*7c478bd9Sstevel@tonic-gate 
884*7c478bd9Sstevel@tonic-gate 	/*
885*7c478bd9Sstevel@tonic-gate 	 * The item may have been free, or may have been the LRU sacrificial
886*7c478bd9Sstevel@tonic-gate 	 * lamb, so reset all fields.
887*7c478bd9Sstevel@tonic-gate 	 */
888*7c478bd9Sstevel@tonic-gate 	cd->uid = uid;
889*7c478bd9Sstevel@tonic-gate 	memcpy(&(cd->public), pk, DHKEYSIZE(pk));
890*7c478bd9Sstevel@tonic-gate 
891*7c478bd9Sstevel@tonic-gate 	skck = MOVE_ADDR(&(cd->public), DHKEYSIZE(pk));
892*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < common.deskeyarray_len; i++) {
893*7c478bd9Sstevel@tonic-gate 		skck->common[i] = common.deskeyarray_val[i];
894*7c478bd9Sstevel@tonic-gate 	}
895*7c478bd9Sstevel@tonic-gate 	skck->verifier = key;
896*7c478bd9Sstevel@tonic-gate 	memcpy(&(skck->secret), sk, DHKEYSIZE(sk));
897*7c478bd9Sstevel@tonic-gate 	free(pk);
898*7c478bd9Sstevel@tonic-gate 	free(sk);
899*7c478bd9Sstevel@tonic-gate 	memcpy(ivec.c, key.c, sizeof (key.c));
900*7c478bd9Sstevel@tonic-gate 	err = cbc_crypt(key.c, (char *)skck, SKCK_LEN(newch->keylen),
901*7c478bd9Sstevel@tonic-gate 			DES_ENCRYPT|DES_HW, ivec.c);
902*7c478bd9Sstevel@tonic-gate 	if (DES_FAILED(err)) {
903*7c478bd9Sstevel@tonic-gate 		/* Re-insert on free list */
904*7c478bd9Sstevel@tonic-gate 		list_insert(cd, &(newch->free), 0, &(newch->free_count));
905*7c478bd9Sstevel@tonic-gate 		return (newch);
906*7c478bd9Sstevel@tonic-gate 	}
907*7c478bd9Sstevel@tonic-gate 
908*7c478bd9Sstevel@tonic-gate 	/* Re-insert on hash list */
909*7c478bd9Sstevel@tonic-gate 	list_insert_hash(cd, &(newch->bucket[hashval(cd->uid)]), 0, 0);
910*7c478bd9Sstevel@tonic-gate 	/* Insert at end of LRU list */
911*7c478bd9Sstevel@tonic-gate 	list_insert(cd, &(newch->inuse), &(newch->inuse_end),
912*7c478bd9Sstevel@tonic-gate 			&(newch->inuse_count));
913*7c478bd9Sstevel@tonic-gate 
914*7c478bd9Sstevel@tonic-gate 	(void) msync((caddr_t)newch, newch->length, MS_SYNC);
915*7c478bd9Sstevel@tonic-gate 
916*7c478bd9Sstevel@tonic-gate 	return (newch);
917*7c478bd9Sstevel@tonic-gate }
918*7c478bd9Sstevel@tonic-gate 
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate static struct cachekey3_list *
copy_cl_item(struct cachekey_header * ch,struct cachekey_disklist * cd,des_block key)921*7c478bd9Sstevel@tonic-gate copy_cl_item(struct cachekey_header *ch, struct cachekey_disklist *cd,
922*7c478bd9Sstevel@tonic-gate 		des_block key) {
923*7c478bd9Sstevel@tonic-gate 
924*7c478bd9Sstevel@tonic-gate 	struct cachekey3_list		*cl;
925*7c478bd9Sstevel@tonic-gate 	struct skck			*skck, *skck_cd;
926*7c478bd9Sstevel@tonic-gate 	int				i, err;
927*7c478bd9Sstevel@tonic-gate 	des_block			ivec;
928*7c478bd9Sstevel@tonic-gate 
929*7c478bd9Sstevel@tonic-gate 	/* Allocate the cachekey3_list structure */
930*7c478bd9Sstevel@tonic-gate 	if ((cl = malloc(CACHEKEY3_LIST_SIZE(ch->keylen))) == 0) {
931*7c478bd9Sstevel@tonic-gate 		return (0);
932*7c478bd9Sstevel@tonic-gate 	}
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate 	/* Allocate skck structure for decryption */
935*7c478bd9Sstevel@tonic-gate 	if ((skck = malloc(SKCK_LEN(ch->keylen))) == 0) {
936*7c478bd9Sstevel@tonic-gate 		free(cl);
937*7c478bd9Sstevel@tonic-gate 		return (0);
938*7c478bd9Sstevel@tonic-gate 	}
939*7c478bd9Sstevel@tonic-gate 
940*7c478bd9Sstevel@tonic-gate 	/* Decrypt and check verifier */
941*7c478bd9Sstevel@tonic-gate 	skck_cd = MOVE_ADDR(&(cd->public), DHKEYSIZE(&(cd->public)));
942*7c478bd9Sstevel@tonic-gate 	memcpy(skck, skck_cd, SKCK_LEN(ch->keylen));
943*7c478bd9Sstevel@tonic-gate 	memcpy(ivec.c, key.c, sizeof (ivec.c));
944*7c478bd9Sstevel@tonic-gate 	err = cbc_crypt(key.c, (char *)skck, SKCK_LEN(ch->keylen),
945*7c478bd9Sstevel@tonic-gate 			DES_DECRYPT|DES_HW, ivec.c);
946*7c478bd9Sstevel@tonic-gate 	if (DES_FAILED(err)) {
947*7c478bd9Sstevel@tonic-gate 		free(cl);
948*7c478bd9Sstevel@tonic-gate 		free(skck);
949*7c478bd9Sstevel@tonic-gate 		return (0);
950*7c478bd9Sstevel@tonic-gate 	}
951*7c478bd9Sstevel@tonic-gate 	if (memcmp(key.c, skck->verifier.c, sizeof (skck->verifier.c)) != 0) {
952*7c478bd9Sstevel@tonic-gate 		free(cl);
953*7c478bd9Sstevel@tonic-gate 		free(skck);
954*7c478bd9Sstevel@tonic-gate 		return (0);
955*7c478bd9Sstevel@tonic-gate 	}
956*7c478bd9Sstevel@tonic-gate 
957*7c478bd9Sstevel@tonic-gate 	/* Everything OK; copy values */
958*7c478bd9Sstevel@tonic-gate 	cl->public		= MOVE_ADDR(cl, sizeof (struct cachekey3_list));
959*7c478bd9Sstevel@tonic-gate 	cl->public->keybuf3_val	= MOVE_ADDR(cl->public, sizeof (keybuf3));
960*7c478bd9Sstevel@tonic-gate 	cl->secret		= MOVE_ADDR(cl->public->keybuf3_val,
961*7c478bd9Sstevel@tonic-gate 					ALIGN4(2*KEYLEN(ch->keylen)+1));
962*7c478bd9Sstevel@tonic-gate 	cl->secret->keybuf3_val	= MOVE_ADDR(cl->secret, sizeof (keybuf3));
963*7c478bd9Sstevel@tonic-gate 	cl->deskey.deskeyarray_val =
964*7c478bd9Sstevel@tonic-gate 				MOVE_ADDR(cl->secret->keybuf3_val,
965*7c478bd9Sstevel@tonic-gate 					ALIGN4(2*KEYLEN(ch->keylen)+1));
966*7c478bd9Sstevel@tonic-gate 	bin2hex(cd->public.key, (u_char *)cl->public->keybuf3_val,
967*7c478bd9Sstevel@tonic-gate 		cd->public.length);
968*7c478bd9Sstevel@tonic-gate 	cl->public->keybuf3_len = cd->public.length*2+1;
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 	bin2hex(skck->secret.key, (u_char *)cl->secret->keybuf3_val,
971*7c478bd9Sstevel@tonic-gate 		skck->secret.length);
972*7c478bd9Sstevel@tonic-gate 	cl->secret->keybuf3_len = skck->secret.length*2+1;
973*7c478bd9Sstevel@tonic-gate 	cl->deskey.deskeyarray_len = sizeof (skck->common)/sizeof (des_block);
974*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < cl->deskey.deskeyarray_len; i++) {
975*7c478bd9Sstevel@tonic-gate 		cl->deskey.deskeyarray_val[i] = skck->common[i];
976*7c478bd9Sstevel@tonic-gate 	}
977*7c478bd9Sstevel@tonic-gate 
978*7c478bd9Sstevel@tonic-gate 	cl->refcnt = 0;
979*7c478bd9Sstevel@tonic-gate 	cl->next   = 0;
980*7c478bd9Sstevel@tonic-gate 
981*7c478bd9Sstevel@tonic-gate 	free(skck);
982*7c478bd9Sstevel@tonic-gate 
983*7c478bd9Sstevel@tonic-gate 	return (cl);
984*7c478bd9Sstevel@tonic-gate 
985*7c478bd9Sstevel@tonic-gate }
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate 
988*7c478bd9Sstevel@tonic-gate static struct cachekey3_list *
cache_retrieve_ch(struct cachekey_header * ch,uid_t uid,keybuf3 * public,des_block key)989*7c478bd9Sstevel@tonic-gate cache_retrieve_ch(struct cachekey_header *ch, uid_t uid, keybuf3 *public,
990*7c478bd9Sstevel@tonic-gate 		des_block key) {
991*7c478bd9Sstevel@tonic-gate 
992*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist	*cd;
993*7c478bd9Sstevel@tonic-gate 	struct cachekey3_list		*cl = 0, **cltmp = &cl;
994*7c478bd9Sstevel@tonic-gate 	u_int				hash;
995*7c478bd9Sstevel@tonic-gate 	struct dhkey			*pk = 0;
996*7c478bd9Sstevel@tonic-gate 
997*7c478bd9Sstevel@tonic-gate 	if (uid == (uid_t)-1 ||
998*7c478bd9Sstevel@tonic-gate 		(public != 0 && (pk = keybuf3_2_dhkey(public)) == 0)) {
999*7c478bd9Sstevel@tonic-gate 		return (0);
1000*7c478bd9Sstevel@tonic-gate 	}
1001*7c478bd9Sstevel@tonic-gate 
1002*7c478bd9Sstevel@tonic-gate 	hash = hashval(uid);
1003*7c478bd9Sstevel@tonic-gate 
1004*7c478bd9Sstevel@tonic-gate 	for (cd = ch->bucket[hash]; cd != 0; cd = cd->nexthash) {
1005*7c478bd9Sstevel@tonic-gate 		if (uid == cd->uid) {
1006*7c478bd9Sstevel@tonic-gate 			/* Match on public key as well ? */
1007*7c478bd9Sstevel@tonic-gate 			if (pk != 0) {
1008*7c478bd9Sstevel@tonic-gate 				if (memcmp(cd->public.key, pk->key,
1009*7c478bd9Sstevel@tonic-gate 						cd->public.length) != 0) {
1010*7c478bd9Sstevel@tonic-gate 					/* Keep looking... */
1011*7c478bd9Sstevel@tonic-gate 					continue;
1012*7c478bd9Sstevel@tonic-gate 				}
1013*7c478bd9Sstevel@tonic-gate 				cl = copy_cl_item(ch, cd, key);
1014*7c478bd9Sstevel@tonic-gate 				/* Match on public key => nothing more to do */
1015*7c478bd9Sstevel@tonic-gate 				break;
1016*7c478bd9Sstevel@tonic-gate 			}
1017*7c478bd9Sstevel@tonic-gate 			*cltmp = copy_cl_item(ch, cd, key);
1018*7c478bd9Sstevel@tonic-gate 			if (*cltmp == 0) {
1019*7c478bd9Sstevel@tonic-gate 				/* Return what we've got */
1020*7c478bd9Sstevel@tonic-gate 				break;
1021*7c478bd9Sstevel@tonic-gate 			}
1022*7c478bd9Sstevel@tonic-gate 			cltmp = &((*cltmp)->next);
1023*7c478bd9Sstevel@tonic-gate 			/* On to the next item */
1024*7c478bd9Sstevel@tonic-gate 		}
1025*7c478bd9Sstevel@tonic-gate 	}
1026*7c478bd9Sstevel@tonic-gate 
1027*7c478bd9Sstevel@tonic-gate 	if (pk != 0)
1028*7c478bd9Sstevel@tonic-gate 		free(pk);
1029*7c478bd9Sstevel@tonic-gate 
1030*7c478bd9Sstevel@tonic-gate 	return (cl);
1031*7c478bd9Sstevel@tonic-gate }
1032*7c478bd9Sstevel@tonic-gate 
1033*7c478bd9Sstevel@tonic-gate 
1034*7c478bd9Sstevel@tonic-gate /*
1035*7c478bd9Sstevel@tonic-gate  * Remove specified item. 'public' == 0 => remove all items for uid.
1036*7c478bd9Sstevel@tonic-gate  * Return number of items removed.
1037*7c478bd9Sstevel@tonic-gate  */
1038*7c478bd9Sstevel@tonic-gate static int
cache_remove_ch(struct cachekey_header * ch,uid_t uid,keybuf3 * public)1039*7c478bd9Sstevel@tonic-gate cache_remove_ch(struct cachekey_header *ch, uid_t uid, keybuf3 *public) {
1040*7c478bd9Sstevel@tonic-gate 
1041*7c478bd9Sstevel@tonic-gate 	struct cachekey_disklist	*cd, *cdtmp;
1042*7c478bd9Sstevel@tonic-gate 	u_int				hash;
1043*7c478bd9Sstevel@tonic-gate 	int				match = 0;
1044*7c478bd9Sstevel@tonic-gate 	struct dhkey			*pk = 0;
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate 	if (uid == (uid_t)-1 ||
1047*7c478bd9Sstevel@tonic-gate 		(public != 0 && (pk = keybuf3_2_dhkey(public)) == 0)) {
1048*7c478bd9Sstevel@tonic-gate 		return (0);
1049*7c478bd9Sstevel@tonic-gate 	}
1050*7c478bd9Sstevel@tonic-gate 
1051*7c478bd9Sstevel@tonic-gate 	hash = hashval(uid);
1052*7c478bd9Sstevel@tonic-gate 
1053*7c478bd9Sstevel@tonic-gate 	for (cd = ch->bucket[hash]; cd != 0; ) {
1054*7c478bd9Sstevel@tonic-gate 		if (uid == cd->uid) {
1055*7c478bd9Sstevel@tonic-gate 			/* Match on public key as well ? */
1056*7c478bd9Sstevel@tonic-gate 			if (pk != 0) {
1057*7c478bd9Sstevel@tonic-gate 				if (memcmp(cd->public.key, pk->key,
1058*7c478bd9Sstevel@tonic-gate 						cd->public.length) != 0) {
1059*7c478bd9Sstevel@tonic-gate 					/* Keep looking... */
1060*7c478bd9Sstevel@tonic-gate 					continue;
1061*7c478bd9Sstevel@tonic-gate 				}
1062*7c478bd9Sstevel@tonic-gate 				match++;
1063*7c478bd9Sstevel@tonic-gate 				list_remove_hash(cd, &(ch->bucket[hash]), 0, 0);
1064*7c478bd9Sstevel@tonic-gate 				list_remove(cd, &(ch->inuse), &(ch->inuse_end),
1065*7c478bd9Sstevel@tonic-gate 						&(ch->inuse_count));
1066*7c478bd9Sstevel@tonic-gate 				cd->uid = (uid_t)-1;
1067*7c478bd9Sstevel@tonic-gate 				list_insert(cd, &(ch->free), 0,
1068*7c478bd9Sstevel@tonic-gate 						&(ch->free_count));
1069*7c478bd9Sstevel@tonic-gate 				/* Match on public key => nothing more to do */
1070*7c478bd9Sstevel@tonic-gate 				break;
1071*7c478bd9Sstevel@tonic-gate 			}
1072*7c478bd9Sstevel@tonic-gate 			match++;
1073*7c478bd9Sstevel@tonic-gate 			/*
1074*7c478bd9Sstevel@tonic-gate 			 * XXX: Assume that the order of the hash list remains
1075*7c478bd9Sstevel@tonic-gate 			 * the same after removal of an item. If this isn't
1076*7c478bd9Sstevel@tonic-gate 			 * true, we really should start over from the start
1077*7c478bd9Sstevel@tonic-gate 			 * of the hash bucket.
1078*7c478bd9Sstevel@tonic-gate 			 */
1079*7c478bd9Sstevel@tonic-gate 			cdtmp = cd->nexthash;
1080*7c478bd9Sstevel@tonic-gate 			list_remove_hash(cd, &(ch->bucket[hash]), 0, 0);
1081*7c478bd9Sstevel@tonic-gate 			list_remove(cd, &(ch->inuse), &(ch->inuse_end),
1082*7c478bd9Sstevel@tonic-gate 					&(ch->inuse_count));
1083*7c478bd9Sstevel@tonic-gate 			cd->uid = (uid_t)-1;
1084*7c478bd9Sstevel@tonic-gate 			list_insert(cd, &(ch->free), 0,
1085*7c478bd9Sstevel@tonic-gate 					&(ch->free_count));
1086*7c478bd9Sstevel@tonic-gate 			/* On to the next item */
1087*7c478bd9Sstevel@tonic-gate 			cd = cdtmp;
1088*7c478bd9Sstevel@tonic-gate 		} else {
1089*7c478bd9Sstevel@tonic-gate 			cd = cd->nexthash;
1090*7c478bd9Sstevel@tonic-gate 		}
1091*7c478bd9Sstevel@tonic-gate 	}
1092*7c478bd9Sstevel@tonic-gate 
1093*7c478bd9Sstevel@tonic-gate 	free(pk);
1094*7c478bd9Sstevel@tonic-gate 	return (match);
1095*7c478bd9Sstevel@tonic-gate }
1096*7c478bd9Sstevel@tonic-gate 
1097*7c478bd9Sstevel@tonic-gate 
1098*7c478bd9Sstevel@tonic-gate #define	INCCACHEREFCNT	mutex_lock(&cache_lock); \
1099*7c478bd9Sstevel@tonic-gate 			cache_refcnt++; \
1100*7c478bd9Sstevel@tonic-gate 			mutex_unlock(&cache_lock)
1101*7c478bd9Sstevel@tonic-gate 
1102*7c478bd9Sstevel@tonic-gate #if !defined(lint) && !defined(__lint)
1103*7c478bd9Sstevel@tonic-gate #define	DECCACHEREFCNT	mutex_lock(&cache_lock); \
1104*7c478bd9Sstevel@tonic-gate 			if (cache_refcnt > 0) \
1105*7c478bd9Sstevel@tonic-gate 				if (cache_refcnt-- == 0) (void) cond_broadcast(&cache_cv); \
1106*7c478bd9Sstevel@tonic-gate 			mutex_unlock(&cache_lock)
1107*7c478bd9Sstevel@tonic-gate #else
1108*7c478bd9Sstevel@tonic-gate #define	DECCACHEREFCNT	mutex_lock(&cache_lock); \
1109*7c478bd9Sstevel@tonic-gate 			if (cache_refcnt-- == 0) (void) cond_broadcast(&cache_cv); \
1110*7c478bd9Sstevel@tonic-gate 			mutex_unlock(&cache_lock)
1111*7c478bd9Sstevel@tonic-gate #endif
1112*7c478bd9Sstevel@tonic-gate 
1113*7c478bd9Sstevel@tonic-gate /*
1114*7c478bd9Sstevel@tonic-gate  * Return the cachekey structure for the specified keylen and algtype.
1115*7c478bd9Sstevel@tonic-gate  * When returned, the lock in the structure has been activated. It's the
1116*7c478bd9Sstevel@tonic-gate  * responsibility of the caller to unlock it by calling release_cache_header().
1117*7c478bd9Sstevel@tonic-gate  */
1118*7c478bd9Sstevel@tonic-gate static struct cachekey *
get_cache_header(keylen_t keylen,algtype_t algtype)1119*7c478bd9Sstevel@tonic-gate get_cache_header(keylen_t keylen, algtype_t algtype) {
1120*7c478bd9Sstevel@tonic-gate 
1121*7c478bd9Sstevel@tonic-gate 	struct cachekey		*c;
1122*7c478bd9Sstevel@tonic-gate 
1123*7c478bd9Sstevel@tonic-gate 	INCCACHEREFCNT;
1124*7c478bd9Sstevel@tonic-gate 
1125*7c478bd9Sstevel@tonic-gate 	for (c = cache; c != 0; c = c->next) {
1126*7c478bd9Sstevel@tonic-gate 		if (c->keylen == keylen && c->algtype == algtype) {
1127*7c478bd9Sstevel@tonic-gate 			mutex_lock(&c->mp);
1128*7c478bd9Sstevel@tonic-gate 			return (c);
1129*7c478bd9Sstevel@tonic-gate 		}
1130*7c478bd9Sstevel@tonic-gate 	}
1131*7c478bd9Sstevel@tonic-gate 
1132*7c478bd9Sstevel@tonic-gate 	/* Spin until there are no cache readers */
1133*7c478bd9Sstevel@tonic-gate 	mutex_lock(&cache_lock);
1134*7c478bd9Sstevel@tonic-gate #if !defined(lint) && !defined(__lint)
1135*7c478bd9Sstevel@tonic-gate 	if (cache_refcnt > 0)
1136*7c478bd9Sstevel@tonic-gate #endif
1137*7c478bd9Sstevel@tonic-gate 		cache_refcnt--;
1138*7c478bd9Sstevel@tonic-gate 	while (cache_refcnt != 0) {
1139*7c478bd9Sstevel@tonic-gate 		(void) cond_wait(&cache_cv, &cache_lock);
1140*7c478bd9Sstevel@tonic-gate 	}
1141*7c478bd9Sstevel@tonic-gate 
1142*7c478bd9Sstevel@tonic-gate 	if ((c = malloc(sizeof (struct cachekey))) != 0) {
1143*7c478bd9Sstevel@tonic-gate 		c->ch		= 0;
1144*7c478bd9Sstevel@tonic-gate 		c->keylen	= keylen;
1145*7c478bd9Sstevel@tonic-gate 		c->algtype	= algtype;
1146*7c478bd9Sstevel@tonic-gate 		mutex_init(&c->mp, 0, 0);
1147*7c478bd9Sstevel@tonic-gate 		c->next		= cache;
1148*7c478bd9Sstevel@tonic-gate 		cache		= c;
1149*7c478bd9Sstevel@tonic-gate 		mutex_lock(&c->mp);
1150*7c478bd9Sstevel@tonic-gate 		cache_refcnt++;
1151*7c478bd9Sstevel@tonic-gate 		mutex_unlock(&cache_lock);
1152*7c478bd9Sstevel@tonic-gate 		return (c);
1153*7c478bd9Sstevel@tonic-gate 	}
1154*7c478bd9Sstevel@tonic-gate 
1155*7c478bd9Sstevel@tonic-gate 	mutex_unlock(&cache_lock);
1156*7c478bd9Sstevel@tonic-gate 	return (0);
1157*7c478bd9Sstevel@tonic-gate }
1158*7c478bd9Sstevel@tonic-gate 
1159*7c478bd9Sstevel@tonic-gate 
1160*7c478bd9Sstevel@tonic-gate static void
release_cache_header(struct cachekey * ck)1161*7c478bd9Sstevel@tonic-gate release_cache_header(struct cachekey *ck) {
1162*7c478bd9Sstevel@tonic-gate 
1163*7c478bd9Sstevel@tonic-gate 	struct cachekey	*c;
1164*7c478bd9Sstevel@tonic-gate 
1165*7c478bd9Sstevel@tonic-gate 	if (ck == 0)
1166*7c478bd9Sstevel@tonic-gate 		return;
1167*7c478bd9Sstevel@tonic-gate 
1168*7c478bd9Sstevel@tonic-gate 	for (c = cache; c != 0; c = c->next) {
1169*7c478bd9Sstevel@tonic-gate 		if (c == ck) {
1170*7c478bd9Sstevel@tonic-gate 			mutex_unlock(&c->mp);
1171*7c478bd9Sstevel@tonic-gate 			DECCACHEREFCNT;
1172*7c478bd9Sstevel@tonic-gate 			break;
1173*7c478bd9Sstevel@tonic-gate 		}
1174*7c478bd9Sstevel@tonic-gate 	}
1175*7c478bd9Sstevel@tonic-gate }
1176*7c478bd9Sstevel@tonic-gate 
1177*7c478bd9Sstevel@tonic-gate 
1178*7c478bd9Sstevel@tonic-gate int
create_cache_file(keylen_t keylen,algtype_t algtype,int sizespec)1179*7c478bd9Sstevel@tonic-gate create_cache_file(keylen_t keylen, algtype_t algtype, int sizespec)
1180*7c478bd9Sstevel@tonic-gate {
1181*7c478bd9Sstevel@tonic-gate 	struct cachekey	*c;
1182*7c478bd9Sstevel@tonic-gate 	int		ret;
1183*7c478bd9Sstevel@tonic-gate 
1184*7c478bd9Sstevel@tonic-gate 	if ((c = get_cache_header(keylen, algtype)) == 0)
1185*7c478bd9Sstevel@tonic-gate 		return (0);
1186*7c478bd9Sstevel@tonic-gate 
1187*7c478bd9Sstevel@tonic-gate 	if (c->ch != 0) {
1188*7c478bd9Sstevel@tonic-gate 		/* Already created and opened */
1189*7c478bd9Sstevel@tonic-gate 		release_cache_header(c);
1190*7c478bd9Sstevel@tonic-gate 		return (1);
1191*7c478bd9Sstevel@tonic-gate 	}
1192*7c478bd9Sstevel@tonic-gate 
1193*7c478bd9Sstevel@tonic-gate 	ret = (c->ch = create_cache_file_ch(keylen, algtype, sizespec)) != 0;
1194*7c478bd9Sstevel@tonic-gate 	release_cache_header(c);
1195*7c478bd9Sstevel@tonic-gate 
1196*7c478bd9Sstevel@tonic-gate 	return (ret);
1197*7c478bd9Sstevel@tonic-gate }
1198*7c478bd9Sstevel@tonic-gate 
1199*7c478bd9Sstevel@tonic-gate 
1200*7c478bd9Sstevel@tonic-gate int
cache_insert(keylen_t keylen,algtype_t algtype,uid_t uid,deskeyarray common,des_block key,keybuf3 * public,keybuf3 * secret)1201*7c478bd9Sstevel@tonic-gate cache_insert(
1202*7c478bd9Sstevel@tonic-gate 	keylen_t keylen,
1203*7c478bd9Sstevel@tonic-gate 	algtype_t algtype,
1204*7c478bd9Sstevel@tonic-gate 	uid_t uid,
1205*7c478bd9Sstevel@tonic-gate 	deskeyarray common,
1206*7c478bd9Sstevel@tonic-gate 	des_block key,
1207*7c478bd9Sstevel@tonic-gate 	keybuf3 *public,
1208*7c478bd9Sstevel@tonic-gate 	keybuf3 *secret)
1209*7c478bd9Sstevel@tonic-gate {
1210*7c478bd9Sstevel@tonic-gate 	struct cachekey	*c;
1211*7c478bd9Sstevel@tonic-gate 	int		ret;
1212*7c478bd9Sstevel@tonic-gate 
1213*7c478bd9Sstevel@tonic-gate 	if ((c = get_cache_header(keylen, algtype)) == 0)
1214*7c478bd9Sstevel@tonic-gate 		return (0);
1215*7c478bd9Sstevel@tonic-gate 
1216*7c478bd9Sstevel@tonic-gate 	if (c->ch == 0) {
1217*7c478bd9Sstevel@tonic-gate 		release_cache_header(c);
1218*7c478bd9Sstevel@tonic-gate 		return (0);
1219*7c478bd9Sstevel@tonic-gate 	}
1220*7c478bd9Sstevel@tonic-gate 
1221*7c478bd9Sstevel@tonic-gate 	ret = (c->ch =
1222*7c478bd9Sstevel@tonic-gate 		cache_insert_ch(c->ch, uid, common, key, public, secret)) != 0;
1223*7c478bd9Sstevel@tonic-gate 
1224*7c478bd9Sstevel@tonic-gate 	release_cache_header(c);
1225*7c478bd9Sstevel@tonic-gate 
1226*7c478bd9Sstevel@tonic-gate 	return (ret);
1227*7c478bd9Sstevel@tonic-gate }
1228*7c478bd9Sstevel@tonic-gate 
1229*7c478bd9Sstevel@tonic-gate 
1230*7c478bd9Sstevel@tonic-gate struct cachekey3_list *
cache_retrieve(keylen_t keylen,algtype_t algtype,uid_t uid,keybuf3 * public,des_block key)1231*7c478bd9Sstevel@tonic-gate cache_retrieve(
1232*7c478bd9Sstevel@tonic-gate 	keylen_t keylen,
1233*7c478bd9Sstevel@tonic-gate 	algtype_t algtype,
1234*7c478bd9Sstevel@tonic-gate 	uid_t uid,
1235*7c478bd9Sstevel@tonic-gate 	keybuf3 *public,
1236*7c478bd9Sstevel@tonic-gate 	des_block key)
1237*7c478bd9Sstevel@tonic-gate {
1238*7c478bd9Sstevel@tonic-gate 	struct cachekey		*c;
1239*7c478bd9Sstevel@tonic-gate 	struct cachekey3_list	*cl;
1240*7c478bd9Sstevel@tonic-gate 
1241*7c478bd9Sstevel@tonic-gate 	if ((c = get_cache_header(keylen, algtype)) == 0)
1242*7c478bd9Sstevel@tonic-gate 		return (0);
1243*7c478bd9Sstevel@tonic-gate 
1244*7c478bd9Sstevel@tonic-gate 	if (c->ch == 0) {
1245*7c478bd9Sstevel@tonic-gate 		release_cache_header(c);
1246*7c478bd9Sstevel@tonic-gate 		return (0);
1247*7c478bd9Sstevel@tonic-gate 	}
1248*7c478bd9Sstevel@tonic-gate 
1249*7c478bd9Sstevel@tonic-gate 	cl = cache_retrieve_ch(c->ch, uid, public, key);
1250*7c478bd9Sstevel@tonic-gate 
1251*7c478bd9Sstevel@tonic-gate 	release_cache_header(c);
1252*7c478bd9Sstevel@tonic-gate 
1253*7c478bd9Sstevel@tonic-gate 	return (cl);
1254*7c478bd9Sstevel@tonic-gate }
1255*7c478bd9Sstevel@tonic-gate 
1256*7c478bd9Sstevel@tonic-gate int
cache_remove(keylen_t keylen,algtype_t algtype,uid_t uid,keybuf3 * public)1257*7c478bd9Sstevel@tonic-gate cache_remove(keylen_t keylen, algtype_t algtype, uid_t uid, keybuf3 *public)
1258*7c478bd9Sstevel@tonic-gate {
1259*7c478bd9Sstevel@tonic-gate 	struct cachekey	*c;
1260*7c478bd9Sstevel@tonic-gate 	int		ret;
1261*7c478bd9Sstevel@tonic-gate 
1262*7c478bd9Sstevel@tonic-gate 	if ((c = get_cache_header(keylen, algtype)) == 0)
1263*7c478bd9Sstevel@tonic-gate 		return (0);
1264*7c478bd9Sstevel@tonic-gate 
1265*7c478bd9Sstevel@tonic-gate 	if (c->ch == 0) {
1266*7c478bd9Sstevel@tonic-gate 		release_cache_header(c);
1267*7c478bd9Sstevel@tonic-gate 		return (0);
1268*7c478bd9Sstevel@tonic-gate 	}
1269*7c478bd9Sstevel@tonic-gate 
1270*7c478bd9Sstevel@tonic-gate 	ret = cache_remove_ch(c->ch, uid, public);
1271*7c478bd9Sstevel@tonic-gate 
1272*7c478bd9Sstevel@tonic-gate 	release_cache_header(c);
1273*7c478bd9Sstevel@tonic-gate 
1274*7c478bd9Sstevel@tonic-gate 	return (ret);
1275*7c478bd9Sstevel@tonic-gate }
1276*7c478bd9Sstevel@tonic-gate 
1277*7c478bd9Sstevel@tonic-gate 
1278*7c478bd9Sstevel@tonic-gate static struct dhkey *
keybuf3_2_dhkey(keybuf3 * hexkey)1279*7c478bd9Sstevel@tonic-gate keybuf3_2_dhkey(keybuf3 *hexkey)
1280*7c478bd9Sstevel@tonic-gate {
1281*7c478bd9Sstevel@tonic-gate 	struct dhkey	*binkey;
1282*7c478bd9Sstevel@tonic-gate 
1283*7c478bd9Sstevel@tonic-gate 	/* hexkey->keybuf3_len*4 is the key length in bits */
1284*7c478bd9Sstevel@tonic-gate 	if ((binkey = malloc(DHKEYALLOC(hexkey->keybuf3_len*4))) == 0)
1285*7c478bd9Sstevel@tonic-gate 		return (0);
1286*7c478bd9Sstevel@tonic-gate 
1287*7c478bd9Sstevel@tonic-gate 	/* Set to zero to keep dbx and Purify access checking happy */
1288*7c478bd9Sstevel@tonic-gate 	memset(binkey, 0, DHKEYALLOC(hexkey->keybuf3_len*4));
1289*7c478bd9Sstevel@tonic-gate 
1290*7c478bd9Sstevel@tonic-gate 	binkey->length = hexkey->keybuf3_len/2;
1291*7c478bd9Sstevel@tonic-gate 	hex2bin((u_char *)hexkey->keybuf3_val, binkey->key,
1292*7c478bd9Sstevel@tonic-gate 		(int)binkey->length);
1293*7c478bd9Sstevel@tonic-gate 
1294*7c478bd9Sstevel@tonic-gate 	return (binkey);
1295*7c478bd9Sstevel@tonic-gate }
1296