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