xref: /titanic_51/usr/src/lib/libnsl/rpc/key_call.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28 /*
29  * Portions of this source code were derived from Berkeley
30  * 4.3 BSD under license from the Regents of the University of
31  * California.
32  */
33 
34 #pragma ident	"%Z%%M%	%I%	%E% SMI"
35 
36 /*
37  * key_call.c, Interface to keyserver
38  *
39  * setsecretkey(key) - set your secret key
40  * encryptsessionkey(agent, deskey) - encrypt a session key to talk to agent
41  * decryptsessionkey(agent, deskey) - decrypt ditto
42  * gendeskey(deskey) - generate a secure des key
43  */
44 
45 #include "mt.h"
46 #include "rpc_mt.h"
47 #include <errno.h>
48 #include <rpc/rpc.h>
49 #include <rpc/trace.h>
50 #include <rpc/key_prot.h>
51 #include <stdio.h>
52 #include <syslog.h>
53 #include <string.h>
54 #include <stdlib.h>
55 #include <unistd.h>
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 
59 #define	CLASSIC_PK_DH(k, a)	(((k) == 192) && ((a) == 0))
60 
61 #if defined(sparc)
62 #define	_FSTAT _fstat
63 #else  /* !sparc */
64 #define	_FSTAT fstat
65 #endif /* sparc */
66 
67 #ifdef DEBUG
68 #define	debug(msg)	(void) fprintf(stderr, "%s\n", msg);
69 #else
70 #define	debug(msg)
71 #endif /* DEBUG */
72 
73 int key_call(rpcproc_t, xdrproc_t, char *, xdrproc_t, char *);
74 int key_call_ext(rpcproc_t, xdrproc_t, char *, xdrproc_t, char *, int);
75 int key_setnet(struct key_netstarg *);
76 
77 /*
78  * Hack to allow the keyserver to use AUTH_DES (for authenticated
79  * NIS+ calls, for example).  The only functions that get called
80  * are key_encryptsession_pk, key_decryptsession_pk, and key_gendes.
81  *
82  * The approach is to have the keyserver fill in pointers to local
83  * implementations of these functions, and to call those in key_call().
84  */
85 
86 bool_t (*__key_encryptsession_pk_LOCAL)() = NULL;
87 bool_t (*__key_decryptsession_pk_LOCAL)() = NULL;
88 bool_t (*__key_gendes_LOCAL)() = NULL;
89 
90 
91 int
92 key_setsecret(secretkey)
93 	const char *secretkey;
94 {
95 	keystatus status;
96 	char netName[MAXNETNAMELEN+1];
97 	struct key_netstarg netst;
98 	int ret;
99 
100 	trace1(TR_key_setsecret, 0);
101 	if (getnetname(netName) == 0) {
102 		debug("getnetname failed");
103 		return (-1);
104 	}
105 
106 	memcpy(netst.st_priv_key, secretkey, HEXKEYBYTES);
107 	netst.st_pub_key[0] = 0;
108 	netst.st_netname = netName;
109 
110 	/*
111 	 * Actual key login
112 	 * We perform the KEY_NET_PUT instead of the SET_KEY
113 	 * rpc call because key_secretkey_is_set function uses
114 	 * the KEY_NET_GET call which expects the netname to be
115 	 * set along with the key. Keylogin also uses KEY_NET_PUT.
116 	 */
117 	ret = key_setnet(&netst);
118 	trace1(TR_key_setsecret, 1);
119 
120 	/* erase our copy of the secret key */
121 	memset(netst.st_priv_key, '\0', HEXKEYBYTES);
122 
123 	if (ret == 1)
124 		return (0);
125 
126 	return (-1);
127 }
128 
129 int
130 key_setsecret_g(
131 	char *secretkey,
132 	keylen_t keylen,
133 	algtype_t algtype,
134 	des_block userkey)
135 {
136 	setkeyarg3 arg;
137 	keystatus status;
138 
139 	trace1(TR_key_setsecret_g, 0);
140 	if (CLASSIC_PK_DH(keylen, algtype)) {
141 		trace1(TR_key_setsecret_g, 1);
142 		return (key_setsecret(secretkey));
143 	}
144 	arg.key.keybuf3_len = keylen/4 + 1;
145 	arg.key.keybuf3_val = secretkey;
146 	arg.algtype = algtype;
147 	arg.keylen = keylen;
148 	arg.userkey = userkey;
149 	if (!key_call((rpcproc_t)KEY_SET_3, xdr_setkeyarg3, (char *)&arg,
150 			xdr_keystatus, (char *)&status)) {
151 		trace1(TR_key_setsecret_g, 1);
152 		return (-1);
153 	}
154 	if (status != KEY_SUCCESS) {
155 		debug("set3 status is nonzero");
156 		trace1(TR_key_setsecret_g, 1);
157 		return (-1);
158 	}
159 	trace1(TR_key_setsecret_g, 1);
160 	return (0);
161 }
162 
163 int
164 key_removesecret_g_ext(int use_uid)
165 {
166 	keystatus status;
167 
168 	trace1(TR_key_removesecret_g_ext, 0);
169 	if (!key_call_ext((rpcproc_t)KEY_CLEAR_3, xdr_void, (char *)NULL,
170 			xdr_keystatus, (char *)&status, use_uid)) {
171 		debug("remove secret key call failed");
172 		trace1(TR_key_removesecret_g_ext, 1);
173 		return (-1);
174 	}
175 	if (status != KEY_SUCCESS) {
176 		debug("remove secret status is nonzero");
177 		trace1(TR_key_setsecret_g_ext, 1);
178 		return (-1);
179 	}
180 	trace1(TR_key_removesecret_g_ext, 1);
181 	return (0);
182 }
183 
184 /*
185  * Use effective uid.
186  */
187 int
188 key_removesecret_g()
189 {
190 	return (key_removesecret_g_ext(0));
191 }
192 
193 /*
194  * Use real uid.
195  */
196 int
197 key_removesecret_g_ruid()
198 {
199 	return (key_removesecret_g_ext(1));
200 }
201 
202 /*
203  * key_secretkey_is_set() returns 1 if the keyserver has a secret key
204  * stored for the caller's effective uid if use_ruid is 0 or
205  * stored for the caller's real uid if use_ruid is 1.
206  * it returns 0 otherwise.
207  *
208  * N.B.:  The KEY_NET_GET key call is undocumented.  Applications shouldn't
209  * be using it, because it allows them to get the user's secret key.
210  *
211  */
212 int
213 key_secretkey_is_set_ext(int use_ruid)
214 {
215 	struct key_netstres 	kres;
216 
217 	trace1(TR_key_secretkey_is_set_ext, 0);
218 	memset((void*)&kres, 0, sizeof (kres));
219 	if (key_call_ext((rpcproc_t)KEY_NET_GET, xdr_void, (char *)NULL,
220 			xdr_key_netstres, (char *)&kres, use_ruid) &&
221 	    (kres.status == KEY_SUCCESS) &&
222 	    (kres.key_netstres_u.knet.st_priv_key[0] != 0)) {
223 		/* avoid leaving secret key in memory */
224 		memset(kres.key_netstres_u.knet.st_priv_key, 0, HEXKEYBYTES);
225 		xdr_free(xdr_key_netstres, (char *)&kres);
226 		trace1(TR_key_secretkey_is_set_ext, 1);
227 		return (1);
228 	}
229 	trace1(TR_key_secretkey_is_set_ext, 1);
230 	return (0);
231 }
232 
233 /*
234  * Use effective uid.
235  */
236 int
237 key_secretkey_is_set(void)
238 {
239 	return (key_secretkey_is_set_ext(0));
240 }
241 
242 /*
243  * Use real uid.
244  */
245 int
246 key_secretkey_is_set_ruid(void)
247 {
248 	return (key_secretkey_is_set_ext(1));
249 }
250 
251 /*
252  * key_secretkey_is_set_g_ext() returns 1 if the keyserver has a secret key
253  * stored for the caller's uid, it returns 0 otherwise.
254  * If (use_ruid == 0), for the caller's effective uid.
255  * If (use_ruid == 1), for the caller's real uid.
256  *
257  * N.B.:  The KEY_NET_GET_3 key call is undocumented.  Applications shouldn't
258  * be using it, because it allows them to get the user's secret key.
259  */
260 int
261 key_secretkey_is_set_g_ext(keylen_t keylen, algtype_t algtype, int use_ruid)
262 {
263 	mechtype arg;
264 	key_netstres3 	kres;
265 
266 	trace1(TR_key_secretkey_is_set_g_ext, 0);
267 	/*
268 	 * key_secretkey_is_set_g_ext is tricky because keylen == 0
269 	 * means check if any key exists for the caller (old/new, 192/1024 ...)
270 	 * Rather than handle this on the server side, we call the old
271 	 * routine if keylen == 0 and try the newer stuff only if that fails
272 	 */
273 	if ((keylen == 0) && key_secretkey_is_set_ext(use_ruid)) {
274 		trace1(TR_key_secretkey_is_set_g_ext, 1);
275 		return (1);
276 	}
277 	if (CLASSIC_PK_DH(keylen, algtype)) {
278 		trace1(TR_key_secretkey_is_set_g_ext, 1);
279 		return (key_secretkey_is_set_ext(use_ruid));
280 	}
281 	arg.keylen = keylen;
282 	arg.algtype = algtype;
283 	memset((void*)&kres, 0, sizeof (kres));
284 	if (key_call_ext((rpcproc_t)KEY_NET_GET_3, xdr_mechtype, (char *)&arg,
285 			xdr_key_netstres3, (char *)&kres, use_ruid) &&
286 	    (kres.status == KEY_SUCCESS) &&
287 	    (kres.key_netstres3_u.knet.st_priv_key.keybuf3_len != 0)) {
288 		/* avoid leaving secret key in memory */
289 		memset(kres.key_netstres3_u.knet.st_priv_key.keybuf3_val, 0,
290 			kres.key_netstres3_u.knet.st_priv_key.keybuf3_len);
291 		xdr_free(xdr_key_netstres3, (char *)&kres);
292 		trace1(TR_key_secretkey_is_set_g_ext, 1);
293 		return (1);
294 	}
295 	trace1(TR_key_secretkey_is_set_g_ext, 1);
296 	return (0);
297 }
298 
299 /*
300  * Use effective uid.
301  */
302 int
303 key_secretkey_is_set_g(keylen_t keylen, algtype_t algtype)
304 {
305 	return (key_secretkey_is_set_g_ext(keylen, algtype, 0));
306 }
307 
308 /*
309  * Use real uid.
310  */
311 int
312 key_secretkey_is_set_g_ruid(keylen_t keylen, algtype_t algtype)
313 {
314 	return (key_secretkey_is_set_g_ext(keylen, algtype, 1));
315 }
316 
317 
318 int
319 key_encryptsession_pk(remotename, remotekey, deskey)
320 	char *remotename;
321 	netobj *remotekey;
322 	des_block *deskey;
323 {
324 	cryptkeyarg2 arg;
325 	cryptkeyres res;
326 
327 	trace1(TR_key_encryptsession_pk, 0);
328 	arg.remotename = remotename;
329 	arg.remotekey = *remotekey;
330 	arg.deskey = *deskey;
331 	if (!key_call((rpcproc_t)KEY_ENCRYPT_PK, xdr_cryptkeyarg2, (char *)&arg,
332 			xdr_cryptkeyres, (char *)&res)) {
333 		trace1(TR_key_encryptsession_pk, 1);
334 		return (-1);
335 	}
336 	if (res.status != KEY_SUCCESS) {
337 		debug("encrypt status is nonzero");
338 		trace1(TR_key_encryptsession_pk, 1);
339 		return (-1);
340 	}
341 	*deskey = res.cryptkeyres_u.deskey;
342 	trace1(TR_key_encryptsession_pk, 1);
343 	return (0);
344 }
345 
346 int
347 key_encryptsession_pk_g(
348 	const char *remotename,
349 	const char *remotekey,
350 	keylen_t remotekeylen,
351 	algtype_t algtype,
352 	des_block deskey[],
353 	keynum_t keynum
354 )
355 {
356 	cryptkeyarg3 arg;
357 	cryptkeyres3 res;
358 
359 	trace1(TR_key_encryptsession_pk_g, 0);
360 	if (CLASSIC_PK_DH(remotekeylen, algtype)) {
361 		int i;
362 		netobj npk;
363 
364 		npk.n_len = remotekeylen/4 + 1;
365 		npk.n_bytes = (char *)remotekey;
366 		for (i = 0; i < keynum; i++) {
367 			if (key_encryptsession_pk((char *)remotename,
368 					&npk, &deskey[i]))
369 				return (-1);
370 		}
371 		return (0);
372 	}
373 	arg.remotename = (char *)remotename;
374 	arg.remotekey.keybuf3_len = remotekeylen/4 + 1;
375 	arg.remotekey.keybuf3_val = (char *)remotekey;
376 	arg.keylen = remotekeylen;
377 	arg.algtype = algtype;
378 	arg.deskey.deskeyarray_len = keynum;
379 	arg.deskey.deskeyarray_val = deskey;
380 	memset(&res, 0, sizeof (res));
381 	res.cryptkeyres3_u.deskey.deskeyarray_val = deskey;
382 	if (!key_call((rpcproc_t)KEY_ENCRYPT_PK_3,
383 			xdr_cryptkeyarg3, (char *)&arg,
384 			xdr_cryptkeyres3, (char *)&res)) {
385 		trace1(TR_key_encryptsession_pk_g, 1);
386 		return (-1);
387 	}
388 	if (res.status != KEY_SUCCESS) {
389 		debug("encrypt3 status is nonzero");
390 		trace1(TR_key_encryptsession_pk_g, 1);
391 		return (-1);
392 	}
393 	if (res.cryptkeyres3_u.deskey.deskeyarray_len != keynum) {
394 		debug("number of keys don't match");
395 		trace1(TR_key_encryptsession_pk_g, 1);
396 		return (-1);
397 	}
398 	trace1(TR_key_encryptsession_pk_g, 1);
399 	return (0);
400 }
401 
402 int
403 key_decryptsession_pk(remotename, remotekey, deskey)
404 	char *remotename;
405 	netobj *remotekey;
406 	des_block *deskey;
407 {
408 	cryptkeyarg2 arg;
409 	cryptkeyres res;
410 
411 	trace1(TR_key_decryptsession_pk, 0);
412 	arg.remotename = remotename;
413 	arg.remotekey = *remotekey;
414 	arg.deskey = *deskey;
415 	if (!key_call((rpcproc_t)KEY_DECRYPT_PK, xdr_cryptkeyarg2, (char *)&arg,
416 			xdr_cryptkeyres, (char *)&res)) {
417 		trace1(TR_key_decryptsession_pk, 1);
418 		return (-1);
419 	}
420 	if (res.status != KEY_SUCCESS) {
421 		debug("decrypt status is nonzero");
422 		trace1(TR_key_decryptsession_pk, 1);
423 		return (-1);
424 	}
425 	*deskey = res.cryptkeyres_u.deskey;
426 	trace1(TR_key_decryptsession_pk, 1);
427 	return (0);
428 }
429 
430 int
431 key_decryptsession_pk_g(
432 	const char *remotename,
433 	const char *remotekey,
434 	keylen_t remotekeylen,
435 	algtype_t algtype,
436 	des_block deskey[],
437 	keynum_t keynum
438 )
439 {
440 	cryptkeyarg3 arg;
441 	cryptkeyres3 res;
442 
443 	trace1(TR_key_decryptsession_pk_g, 0);
444 	if (CLASSIC_PK_DH(remotekeylen, algtype)) {
445 		int i;
446 		netobj npk;
447 
448 		npk.n_len = remotekeylen/4 + 1;
449 		npk.n_bytes = (char *)remotekey;
450 		for (i = 0; i < keynum; i++) {
451 			if (key_decryptsession_pk((char *)remotename,
452 					&npk, &deskey[i]))
453 				return (-1);
454 		}
455 		return (0);
456 	}
457 	arg.remotename = (char *)remotename;
458 	arg.remotekey.keybuf3_len = remotekeylen/4 + 1;
459 	arg.remotekey.keybuf3_val = (char *)remotekey;
460 	arg.deskey.deskeyarray_len = keynum;
461 	arg.deskey.deskeyarray_val = deskey;
462 	arg.algtype = algtype;
463 	arg.keylen = remotekeylen;
464 	memset(&res, 0, sizeof (res));
465 	res.cryptkeyres3_u.deskey.deskeyarray_val = deskey;
466 	if (!key_call((rpcproc_t)KEY_DECRYPT_PK_3,
467 			xdr_cryptkeyarg3, (char *)&arg,
468 			xdr_cryptkeyres3, (char *)&res)) {
469 		trace1(TR_key_decryptsession_pk_g, 1);
470 		return (-1);
471 	}
472 	if (res.status != KEY_SUCCESS) {
473 		debug("decrypt3 status is nonzero");
474 		trace1(TR_key_decryptsession_pk_g, 1);
475 		return (-1);
476 	}
477 	if (res.cryptkeyres3_u.deskey.deskeyarray_len != keynum) {
478 		debug("number of keys don't match");
479 		trace1(TR_key_encryptsession_pk_g, 1);
480 		return (-1);
481 	}
482 	trace1(TR_key_decryptsession_pk_g, 1);
483 	return (0);
484 }
485 
486 int
487 key_encryptsession(remotename, deskey)
488 	const char *remotename;
489 	des_block *deskey;
490 {
491 	cryptkeyarg arg;
492 	cryptkeyres res;
493 
494 	trace1(TR_key_encryptsession, 0);
495 	arg.remotename = (char *)remotename;
496 	arg.deskey = *deskey;
497 	if (!key_call((rpcproc_t)KEY_ENCRYPT, xdr_cryptkeyarg, (char *)&arg,
498 			xdr_cryptkeyres, (char *)&res)) {
499 		trace1(TR_key_encryptsession, 1);
500 		return (-1);
501 	}
502 	if (res.status != KEY_SUCCESS) {
503 		debug("encrypt status is nonzero");
504 		trace1(TR_key_encryptsession, 1);
505 		return (-1);
506 	}
507 	*deskey = res.cryptkeyres_u.deskey;
508 	trace1(TR_key_encryptsession, 1);
509 	return (0);
510 }
511 
512 int
513 key_encryptsession_g(
514 	const char *remotename,
515 	keylen_t keylen,
516 	algtype_t algtype,
517 	des_block deskey[],
518 	keynum_t keynum
519 )
520 {
521 	cryptkeyarg3 arg;
522 	cryptkeyres3 res;
523 
524 	trace1(TR_key_encryptsession_g, 0);
525 	if (CLASSIC_PK_DH(keylen, algtype)) {
526 		trace1(TR_key_encryptsession, 1);
527 		return (key_encryptsession(remotename, deskey));
528 	}
529 	arg.remotename = (char *)remotename;
530 	arg.algtype = algtype;
531 	arg.keylen = keylen;
532 	arg.deskey.deskeyarray_len = keynum;
533 	arg.deskey.deskeyarray_val = deskey;
534 	arg.remotekey.keybuf3_len = 0;
535 	memset(&res, 0, sizeof (res));
536 	res.cryptkeyres3_u.deskey.deskeyarray_val = deskey;
537 	if (!key_call((rpcproc_t)KEY_ENCRYPT_3, xdr_cryptkeyarg3, (char *)&arg,
538 			xdr_cryptkeyres3, (char *)&res)) {
539 		trace1(TR_key_encryptsession_g, 1);
540 		return (-1);
541 	}
542 	if (res.status != KEY_SUCCESS) {
543 		debug("encrypt3 status is nonzero");
544 		trace1(TR_key_encryptsession_g, 1);
545 		return (-1);
546 	}
547 	if (res.cryptkeyres3_u.deskey.deskeyarray_len != keynum) {
548 		debug("encrypt3 didn't return same number of keys");
549 		trace1(TR_key_encryptsession_g, 1);
550 		return (-1);
551 	}
552 	trace1(TR_key_encryptsession_g, 1);
553 	return (0);
554 }
555 
556 
557 int
558 key_decryptsession(remotename, deskey)
559 	const char *remotename;
560 	des_block *deskey;
561 {
562 	cryptkeyarg arg;
563 	cryptkeyres res;
564 
565 	trace1(TR_key_decryptsession, 0);
566 	arg.remotename = (char *)remotename;
567 	arg.deskey = *deskey;
568 	if (!key_call((rpcproc_t)KEY_DECRYPT, xdr_cryptkeyarg, (char *)&arg,
569 			xdr_cryptkeyres, (char *)&res)) {
570 		trace1(TR_key_decryptsession, 1);
571 		return (-1);
572 	}
573 	if (res.status != KEY_SUCCESS) {
574 		debug("decrypt status is nonzero");
575 		trace1(TR_key_decryptsession, 1);
576 		return (-1);
577 	}
578 	*deskey = res.cryptkeyres_u.deskey;
579 	trace1(TR_key_decryptsession, 1);
580 	return (0);
581 }
582 
583 int
584 key_decryptsession_g(
585 	const char *remotename,
586 	keylen_t keylen,
587 	algtype_t algtype,
588 	des_block deskey[],
589 	keynum_t keynum
590 )
591 {
592 	cryptkeyarg3 arg;
593 	cryptkeyres3 res;
594 
595 	trace1(TR_key_decryptsession_g, 0);
596 	if (CLASSIC_PK_DH(keylen, algtype)) {
597 		trace1(TR_key_decryptsession, 1);
598 		return (key_decryptsession(remotename, deskey));
599 	}
600 	arg.remotename = (char *)remotename;
601 	arg.algtype = algtype;
602 	arg.keylen = keylen;
603 	arg.deskey.deskeyarray_len = keynum;
604 	arg.deskey.deskeyarray_val = deskey;
605 	arg.remotekey.keybuf3_len = 0;
606 	memset(&res, 0, sizeof (res));
607 	res.cryptkeyres3_u.deskey.deskeyarray_val = deskey;
608 	if (!key_call((rpcproc_t)KEY_DECRYPT_3, xdr_cryptkeyarg3, (char *)&arg,
609 			xdr_cryptkeyres3, (char *)&res)) {
610 		trace1(TR_key_decryptsession_g, 1);
611 		return (-1);
612 	}
613 	if (res.status != KEY_SUCCESS) {
614 		debug("decrypt3 status is nonzero");
615 		trace1(TR_key_decryptsession_g, 1);
616 		return (-1);
617 	}
618 	if (res.cryptkeyres3_u.deskey.deskeyarray_len != keynum) {
619 		debug("decrypt3 didn't return same number of keys");
620 		trace1(TR_key_encryptsession_g, 1);
621 		return (-1);
622 	}
623 	trace1(TR_key_decryptsession_g, 1);
624 	return (0);
625 }
626 
627 int
628 key_gendes(key)
629 	des_block *key;
630 {
631 	trace1(TR_key_gendes, 0);
632 	if (!key_call((rpcproc_t)KEY_GEN, xdr_void, (char *)NULL,
633 			xdr_des_block, (char *)key)) {
634 		trace1(TR_key_gendes, 1);
635 		return (-1);
636 	}
637 	trace1(TR_key_gendes, 1);
638 	return (0);
639 }
640 
641 int
642 key_gendes_g(
643 	des_block deskey[],
644 	keynum_t keynum
645 )
646 {
647 	deskeyarray res;
648 
649 	trace1(TR_key_gendes_g, 0);
650 	res.deskeyarray_val = deskey;
651 	if (!key_call((rpcproc_t)KEY_GEN_3, xdr_keynum_t, (char *)&keynum,
652 			xdr_deskeyarray, (char *)&res)) {
653 		trace1(TR_key_gendes_g, 1);
654 		return (-1);
655 	}
656 	if (res.deskeyarray_len != keynum) {
657 		debug("return length doesn't match\n");
658 		trace1(TR_key_gendes_g, 1);
659 		return (-1);
660 	}
661 	trace1(TR_key_gendes_g, 1);
662 	return (0);
663 }
664 
665 /*
666  * Call KEY_NET_PUT Operation to the keyserv.
667  *
668  * If use_ruid == 0, use effective uid.
669  * If use_ruid == 1, use real uid.
670  */
671 int
672 key_setnet_ext(struct key_netstarg *arg, int use_ruid)
673 {
674 	keystatus status;
675 
676 	trace1(TR_key_setnet_ext, 0);
677 	if (!key_call_ext((rpcproc_t)KEY_NET_PUT, xdr_key_netstarg,
678 		(char *)arg, xdr_keystatus, (char *)&status, use_ruid)) {
679 		trace1(TR_key_setnet, 1);
680 		return (-1);
681 	}
682 
683 	if (status != KEY_SUCCESS) {
684 		debug("key_setnet status is nonzero");
685 		trace1(TR_key_setnet_ext, 1);
686 		return (-1);
687 	}
688 	trace1(TR_key_setnet_ext, 1);
689 	return (1);
690 }
691 
692 /*
693  * Use effective uid.
694  */
695 int
696 key_setnet(struct key_netstarg *arg)
697 {
698 	return (key_setnet_ext(arg, 0));
699 }
700 
701 /*
702  * Use real uid.
703  */
704 int
705 key_setnet_ruid(struct key_netstarg *arg)
706 {
707 	return (key_setnet_ext(arg, 1));
708 }
709 
710 /*
711  * Input netname, secret and public keys (hex string representation)
712  * of length skeylen/pkeylen (bits), and algorithm type. One, but not
713  * both, of skey or pkey may have zero length. If both lengths are
714  * specified, they must be the same.
715  *
716  * Call KEY_NET_PUT_3 Operation to the keyserv.
717  * Stores the specified netname/pkey/skey triplet in the keyserv.
718  *
719  * If (use_ruid == 1), use real uid.
720  * If (use_ruid == 0), use effective uid.
721  */
722 int
723 key_setnet_g_ext(
724 	const char *netname,
725 	const char *skey,
726 	keylen_t skeylen,
727 	const char *pkey,
728 	keylen_t pkeylen,
729 	algtype_t algtype,
730 	int use_ruid)
731 {
732 	key_netstarg3 arg;
733 	keystatus status;
734 
735 	trace1(TR_key_setnet_g_ext, 0);
736 	arg.st_netname = (char *)netname;
737 	arg.algtype = algtype;
738 	if (skeylen == 0) {
739 		arg.st_priv_key.keybuf3_len = 0;
740 	} else {
741 		arg.st_priv_key.keybuf3_len = skeylen/4 + 1;
742 	}
743 	arg.st_priv_key.keybuf3_val = (char *)skey;
744 	if (pkeylen == 0) {
745 		arg.st_pub_key.keybuf3_len = 0;
746 	} else {
747 		arg.st_pub_key.keybuf3_len = pkeylen/4 + 1;
748 	}
749 	arg.st_pub_key.keybuf3_val = (char *)pkey;
750 	if (skeylen == 0) {
751 		if (pkeylen == 0) {
752 			debug("keylens are both 0");
753 			trace1(TR_key_setnet_g_ext, 1);
754 			return (-1);
755 		}
756 		arg.keylen = pkeylen;
757 	} else {
758 		if ((pkeylen != 0) && (skeylen != pkeylen)) {
759 			debug("keylens don't match");
760 			trace1(TR_key_setnet_g_ext, 1);
761 			return (-1);
762 		}
763 		arg.keylen = skeylen;
764 	}
765 	if (CLASSIC_PK_DH(arg.keylen, arg.algtype)) {
766 		key_netstarg tmp;
767 
768 		if (skeylen != 0) {
769 			memcpy(&tmp.st_priv_key, skey,
770 				sizeof (tmp.st_priv_key));
771 		} else {
772 			memset(&tmp.st_priv_key, 0, sizeof (tmp.st_priv_key));
773 		}
774 		if (pkeylen != 0) {
775 			memcpy(&tmp.st_pub_key, skey, sizeof (tmp.st_pub_key));
776 		} else {
777 			memset(&tmp.st_pub_key, 0, sizeof (tmp.st_pub_key));
778 		}
779 		tmp.st_netname = (char *)netname;
780 		trace1(TR_key_setnet_g_ext, 1);
781 		return (key_setnet(&tmp));
782 	}
783 	if (!key_call_ext((rpcproc_t)KEY_NET_PUT_3,
784 		xdr_key_netstarg3, (char *)&arg,
785 		xdr_keystatus, (char *)&status, use_ruid)) {
786 		trace1(TR_key_setnet_g_ext, 1);
787 		return (-1);
788 	}
789 
790 	if (status != KEY_SUCCESS) {
791 		debug("key_setnet3 status is nonzero");
792 		trace1(TR_key_setnet_g_ext, 1);
793 		return (-1);
794 	}
795 	trace1(TR_key_setnet_g_ext, 1);
796 	return (0);
797 }
798 
799 /*
800  * Use effective uid.
801  */
802 int
803 key_setnet_g(const char *netname, const char *skey, keylen_t skeylen,
804 	const char *pkey, keylen_t pkeylen, algtype_t algtype)
805 {
806 	return (key_setnet_g_ext(netname, skey, skeylen, pkey, pkeylen,
807 			algtype, 0));
808 }
809 
810 /*
811  * Use real uid.
812  */
813 int
814 key_setnet_g_ruid(const char *netname, const char *skey, keylen_t skeylen,
815 	const char *pkey, keylen_t pkeylen, algtype_t algtype)
816 {
817 	return (key_setnet_g_ext(netname, skey, skeylen, pkey, pkeylen,
818 			algtype, 1));
819 }
820 
821 int
822 key_get_conv(pkey, deskey)
823 	char *pkey;
824 	des_block *deskey;
825 {
826 	cryptkeyres res;
827 
828 	trace1(TR_key_get_conv, 0);
829 	if (!key_call((rpcproc_t)KEY_GET_CONV, xdr_keybuf, pkey,
830 		xdr_cryptkeyres, (char *)&res)) {
831 		trace1(TR_key_get_conv, 1);
832 		return (-1);
833 	}
834 	if (res.status != KEY_SUCCESS) {
835 		debug("get_conv status is nonzero");
836 		trace1(TR_key_get_conv, 1);
837 		return (-1);
838 	}
839 	*deskey = res.cryptkeyres_u.deskey;
840 	trace1(TR_key_get_conv, 1);
841 	return (0);
842 }
843 
844 int
845 key_get_conv_g(
846 	const char *pkey,
847 	keylen_t pkeylen,
848 	algtype_t algtype,
849 	des_block deskey[],
850 	keynum_t keynum
851 )
852 {
853 	deskeyarg3 arg;
854 	cryptkeyres3 res;
855 
856 	trace1(TR_key_get_conv_g, 0);
857 	if (CLASSIC_PK_DH(pkeylen, algtype)) {
858 		trace1(TR_key_get_conv_g, 1);
859 		return (key_get_conv((char *)pkey, deskey));
860 	}
861 	arg.pub_key.keybuf3_len = pkeylen/4 + 1;
862 	arg.pub_key.keybuf3_val = (char *)pkey;
863 	arg.nkeys = keynum;
864 	arg.algtype = algtype;
865 	arg.keylen = pkeylen;
866 	memset(&res, 0, sizeof (res));
867 	res.cryptkeyres3_u.deskey.deskeyarray_val = deskey;
868 	if (!key_call((rpcproc_t)KEY_GET_CONV_3, xdr_deskeyarg3, (char *)&arg,
869 		xdr_cryptkeyres3, (char *)&res)) {
870 		trace1(TR_key_get_conv_g, 1);
871 		return (-1);
872 	}
873 	if (res.status != KEY_SUCCESS) {
874 		debug("get_conv3 status is nonzero");
875 		trace1(TR_key_get_conv_g, 1);
876 		return (-1);
877 	}
878 	if (res.cryptkeyres3_u.deskey.deskeyarray_len != keynum) {
879 		debug("get_conv3 number of keys dont match");
880 		trace1(TR_key_get_conv_g, 1);
881 		return (-1);
882 	}
883 	trace1(TR_key_get_conv_g, 1);
884 	return (0);
885 }
886 
887 struct  key_call_private {
888 	CLIENT	*client;	/* Client handle */
889 	pid_t	pid;		/* process-id at moment of creation */
890 	int	fd;		/* client handle fd */
891 	dev_t	rdev;		/* device client handle is using */
892 };
893 
894 static void set_rdev(struct key_call_private *);
895 static int check_rdev(struct key_call_private *);
896 
897 static void
898 key_call_destroy(void *vp)
899 {
900 	struct key_call_private *kcp = (struct key_call_private *)vp;
901 
902 	if (kcp != NULL && kcp->client != NULL) {
903 		check_rdev(kcp);
904 		clnt_destroy(kcp->client);
905 		free(kcp);
906 	}
907 }
908 
909 static pthread_key_t key_call_key;
910 
911 void
912 _key_call_fini(void)
913 {
914 	struct key_call_private	*kcp = NULL;
915 
916 	if (key_call_key &&
917 	    (kcp = pthread_getspecific(key_call_key)) != NULL) {
918 		key_call_destroy(kcp);
919 		(void) pthread_setspecific(key_call_key, NULL);
920 	}
921 }
922 
923 /*
924  * Keep the handle cached.  This call may be made quite often.
925  */
926 static CLIENT *
927 getkeyserv_handle(int vers, int stale)
928 {
929 	struct key_call_private	*kcp = NULL;
930 	int _update_did();
931 
932 	kcp = thr_get_storage(&key_call_key, sizeof (*kcp), key_call_destroy);
933 	if (kcp == NULL) {
934 		syslog(LOG_CRIT, "getkeyserv_handle: out of memory");
935 		return (NULL);
936 	}
937 
938 	/*
939 	 * if pid has changed, destroy client and rebuild
940 	 * or if stale is '1' then destroy client and rebuild
941 	 */
942 	if (kcp->client &&
943 	    (!check_rdev(kcp) || kcp->pid != getpid() || stale)) {
944 		clnt_destroy(kcp->client);
945 		kcp->client = NULL;
946 	}
947 	if (kcp->client) {
948 		int	fd;
949 		/*
950 		 * Change the version number to the new one.
951 		 */
952 		clnt_control(kcp->client, CLSET_VERS, (void *)&vers);
953 		if (!_update_did(kcp->client, vers)) {
954 			if (rpc_createerr.cf_stat == RPC_SYSTEMERROR)
955 				syslog(LOG_DEBUG, "getkeyserv_handle: "
956 						"out of memory!");
957 			return (NULL);
958 		}
959 		/* Update fd in kcp because it was reopened in _update_did */
960 		if (clnt_control(kcp->client, CLGET_FD, (void *)&fd) &&
961 		    (fd >= 0))
962 			_fcntl(fd, F_SETFD, FD_CLOEXEC); /* "close on exec" */
963 		kcp->fd = fd;
964 		return (kcp->client);
965 	}
966 
967 	if ((kcp->client = clnt_door_create(KEY_PROG, vers, 0)) == NULL)
968 		return (NULL);
969 
970 	kcp->pid = getpid();
971 	set_rdev(kcp);
972 	_fcntl(kcp->fd, F_SETFD, FD_CLOEXEC);	/* make it "close on exec" */
973 
974 	return (kcp->client);
975 }
976 
977 /*
978  * RPC calls to the keyserv.
979  *
980  * If (use_ruid == 1), use real uid.
981  * If (use_ruid == 0), use effective uid.
982  * Returns  0 on failure, 1 on success
983  */
984 int
985 key_call_ext(proc, xdr_arg, arg, xdr_rslt, rslt, use_ruid)
986 	rpcproc_t proc;
987 	xdrproc_t xdr_arg;
988 	char *arg;
989 	xdrproc_t xdr_rslt;
990 	char *rslt;
991 	int use_ruid;
992 {
993 	CLIENT		*clnt;
994 	struct timeval	wait_time = {0, 0};
995 	enum clnt_stat	status;
996 	int		vers;
997 
998 	if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) {
999 		cryptkeyres res;
1000 		bool_t r;
1001 		r = (*__key_encryptsession_pk_LOCAL)(geteuid(), arg, &res);
1002 		if (r == TRUE) {
1003 /* LINTED pointer alignment */
1004 			*(cryptkeyres*)rslt = res;
1005 			return (1);
1006 		}
1007 		return (0);
1008 	}
1009 	if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) {
1010 		cryptkeyres res;
1011 		bool_t r;
1012 		r = (*__key_decryptsession_pk_LOCAL)(geteuid(), arg, &res);
1013 		if (r == TRUE) {
1014 /* LINTED pointer alignment */
1015 			*(cryptkeyres*)rslt = res;
1016 			return (1);
1017 		}
1018 		return (0);
1019 	}
1020 	if (proc == KEY_GEN && __key_gendes_LOCAL) {
1021 		des_block res;
1022 		bool_t r;
1023 		r = (*__key_gendes_LOCAL)(geteuid(), 0, &res);
1024 		if (r == TRUE) {
1025 /* LINTED pointer alignment */
1026 			*(des_block*)rslt = res;
1027 			return (1);
1028 		}
1029 		return (0);
1030 	}
1031 
1032 	if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) ||
1033 	    (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) ||
1034 	    (proc == KEY_GET_CONV))
1035 		vers = 2;	/* talk to version 2 */
1036 	else
1037 		vers = 1;	/* talk to version 1 */
1038 
1039 	clnt = getkeyserv_handle(vers, 0);
1040 	if (clnt == NULL)
1041 		return (0);
1042 
1043 	auth_destroy(clnt->cl_auth);
1044 	if (use_ruid)
1045 		clnt->cl_auth = authsys_create_ruid();
1046 	else
1047 		clnt->cl_auth = authnone_create();
1048 
1049 	status = CLNT_CALL(clnt, proc, xdr_arg, arg, xdr_rslt,
1050 			rslt, wait_time);
1051 
1052 	switch (status) {
1053 	case RPC_SUCCESS:
1054 		return (1);
1055 
1056 	case RPC_CANTRECV:
1057 		/*
1058 		 * keyserv was probably restarted, so we'll try once more
1059 		 */
1060 		if ((clnt = getkeyserv_handle(vers, 1)) == NULL)
1061 			return (0);
1062 
1063 		auth_destroy(clnt->cl_auth);
1064 		if (use_ruid)
1065 			clnt->cl_auth = authsys_create_ruid();
1066 		else
1067 			clnt->cl_auth = authnone_create();
1068 
1069 
1070 		if (CLNT_CALL(clnt, proc, xdr_arg, arg, xdr_rslt, rslt,
1071 						wait_time) == RPC_SUCCESS)
1072 			return (1);
1073 		return (0);
1074 
1075 	default:
1076 		return (0);
1077 	}
1078 }
1079 
1080 /*
1081  * Use effective uid.
1082  */
1083 int
1084 key_call(rpcproc_t proc, xdrproc_t xdr_arg, char *arg, xdrproc_t xdr_rslt,
1085 	char *rslt)
1086 {
1087 	return (key_call_ext(proc, xdr_arg, arg, xdr_rslt, rslt, 0));
1088 }
1089 
1090 /*
1091  * Use real uid.
1092  */
1093 int
1094 key_call_ruid(rpcproc_t proc, xdrproc_t xdr_arg, char *arg,
1095 	xdrproc_t xdr_rslt, char *rslt)
1096 {
1097 	return (key_call_ext(proc, xdr_arg, arg, xdr_rslt, rslt, 1));
1098 }
1099 
1100 static
1101 void
1102 set_rdev(kcp)
1103 	struct key_call_private *kcp;
1104 {
1105 	int fd;
1106 	struct stat stbuf;
1107 
1108 	if (clnt_control(kcp->client, CLGET_FD, (char *)&fd) != TRUE ||
1109 	    _FSTAT(fd, &stbuf) == -1) {
1110 		syslog(LOG_DEBUG, "keyserv_client:  can't get info");
1111 		kcp->fd = -1;
1112 		return;
1113 	}
1114 	kcp->fd = fd;
1115 	kcp->rdev = stbuf.st_rdev;
1116 }
1117 
1118 static
1119 int
1120 check_rdev(kcp)
1121 	struct key_call_private *kcp;
1122 {
1123 	struct stat stbuf;
1124 
1125 	if (kcp->fd == -1)
1126 		return (1);    /* can't check it, assume it is okay */
1127 
1128 	if (_FSTAT(kcp->fd, &stbuf) == -1) {
1129 		syslog(LOG_DEBUG, "keyserv_client:  can't stat %d", kcp->fd);
1130 		/* could be because file descriptor was closed */
1131 		/* it's not our file descriptor, so don't try to close it */
1132 		clnt_control(kcp->client, CLSET_FD_NCLOSE, (char *)NULL);
1133 
1134 		return (0);
1135 	}
1136 	if (kcp->rdev != stbuf.st_rdev) {
1137 		syslog(LOG_DEBUG,
1138 		    "keyserv_client:  fd %d changed, old=0x%x, new=0x%x",
1139 		    kcp->fd, kcp->rdev, stbuf.st_rdev);
1140 		/* it's not our file descriptor, so don't try to close it */
1141 		clnt_control(kcp->client, CLSET_FD_NCLOSE, (char *)NULL);
1142 		return (0);
1143 	}
1144 	return (1);    /* fd is okay */
1145 }
1146