import less(1)
[unleashed/tickless.git] / usr / src / lib / libc / port / nsl / key_call.c
blob27e2ac4165ab05d04c11a07dd685a42a8e6c5424
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 * Portions of this source code were derived from Berkeley
31 * 4.3 BSD under license from the Regents of the University of
32 * California.
35 #pragma ident "%Z%%M% %I% %E% SMI"
38 * Interface to keyserver
40 * setsecretkey(key) - set your secret key
41 * encryptsessionkey(agent, deskey) - encrypt a session key to talk to agent
42 * decryptsessionkey(agent, deskey) - decrypt ditto
43 * gendeskey(deskey) - generate a secure des key
46 #include "mt.h"
47 #include "rpc_mt.h"
48 #include <errno.h>
49 #include <rpc/rpc.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>
59 #define CLASSIC_PK_DH(k, a) (((k) == 192) && ((a) == 0))
61 #ifdef DEBUG
62 #define debug(msg) (void) fprintf(stderr, "%s\n", msg);
63 #else
64 #define debug(msg)
65 #endif /* DEBUG */
67 int key_call(rpcproc_t, xdrproc_t, char *, xdrproc_t, char *);
68 int key_call_ext(rpcproc_t, xdrproc_t, char *, xdrproc_t, char *, int);
69 int key_setnet(struct key_netstarg *);
72 * Hack to allow the keyserver to use AUTH_DES (for authenticated
73 * NIS+ calls, for example). The only functions that get called
74 * are key_encryptsession_pk, key_decryptsession_pk, and key_gendes.
76 * The approach is to have the keyserver fill in pointers to local
77 * implementations of these functions, and to call those in key_call().
80 bool_t (*__key_encryptsession_pk_LOCAL)() = NULL;
81 bool_t (*__key_decryptsession_pk_LOCAL)() = NULL;
82 bool_t (*__key_gendes_LOCAL)() = NULL;
85 int
86 key_setsecret(const char *secretkey)
88 char netName[MAXNETNAMELEN+1];
89 struct key_netstarg netst;
90 int ret;
92 if (getnetname(netName) == 0) {
93 debug("getnetname failed");
94 return (-1);
97 (void) memcpy(netst.st_priv_key, secretkey, HEXKEYBYTES);
98 netst.st_pub_key[0] = 0;
99 netst.st_netname = netName;
102 * Actual key login
103 * We perform the KEY_NET_PUT instead of the SET_KEY
104 * rpc call because key_secretkey_is_set function uses
105 * the KEY_NET_GET call which expects the netname to be
106 * set along with the key. Keylogin also uses KEY_NET_PUT.
108 ret = key_setnet(&netst);
110 /* erase our copy of the secret key */
111 (void) memset(netst.st_priv_key, '\0', HEXKEYBYTES);
113 if (ret == 1)
114 return (0);
116 return (-1);
120 key_setsecret_g(
121 char *secretkey,
122 keylen_t keylen,
123 algtype_t algtype,
124 des_block userkey)
126 setkeyarg3 arg;
127 keystatus status;
129 if (CLASSIC_PK_DH(keylen, algtype))
130 return (key_setsecret(secretkey));
131 arg.key.keybuf3_len = keylen/4 + 1;
132 arg.key.keybuf3_val = secretkey;
133 arg.algtype = algtype;
134 arg.keylen = keylen;
135 arg.userkey = userkey;
136 if (!key_call((rpcproc_t)KEY_SET_3, xdr_setkeyarg3, (char *)&arg,
137 xdr_keystatus, (char *)&status))
138 return (-1);
139 if (status != KEY_SUCCESS) {
140 debug("set3 status is nonzero");
141 return (-1);
143 return (0);
147 key_removesecret_g_ext(int use_uid)
149 keystatus status;
151 if (!key_call_ext((rpcproc_t)KEY_CLEAR_3, xdr_void, NULL,
152 xdr_keystatus, (char *)&status, use_uid)) {
153 debug("remove secret key call failed");
154 return (-1);
156 if (status != KEY_SUCCESS) {
157 debug("remove secret status is nonzero");
158 return (-1);
160 return (0);
164 * Use effective uid.
167 key_removesecret_g(void)
169 return (key_removesecret_g_ext(0));
173 * Use real uid.
176 key_removesecret_g_ruid(void)
178 return (key_removesecret_g_ext(1));
182 * key_secretkey_is_set() returns 1 if the keyserver has a secret key
183 * stored for the caller's effective uid if use_ruid is 0 or
184 * stored for the caller's real uid if use_ruid is 1.
185 * it returns 0 otherwise.
187 * N.B.: The KEY_NET_GET key call is undocumented. Applications shouldn't
188 * be using it, because it allows them to get the user's secret key.
192 key_secretkey_is_set_ext(int use_ruid)
194 struct key_netstres kres;
196 (void) memset(&kres, 0, sizeof (kres));
197 if (key_call_ext((rpcproc_t)KEY_NET_GET, xdr_void, NULL,
198 xdr_key_netstres, (char *)&kres, use_ruid) &&
199 (kres.status == KEY_SUCCESS) &&
200 (kres.key_netstres_u.knet.st_priv_key[0] != 0)) {
201 /* avoid leaving secret key in memory */
202 (void) memset(kres.key_netstres_u.knet.st_priv_key, 0,
203 HEXKEYBYTES);
204 xdr_free(xdr_key_netstres, (char *)&kres);
205 return (1);
207 return (0);
211 * Use effective uid.
214 key_secretkey_is_set(void)
216 return (key_secretkey_is_set_ext(0));
220 * Use real uid.
223 key_secretkey_is_set_ruid(void)
225 return (key_secretkey_is_set_ext(1));
229 * key_secretkey_is_set_g_ext() returns 1 if the keyserver has a secret key
230 * stored for the caller's uid, it returns 0 otherwise.
231 * If (use_ruid == 0), for the caller's effective uid.
232 * If (use_ruid == 1), for the caller's real uid.
234 * N.B.: The KEY_NET_GET_3 key call is undocumented. Applications shouldn't
235 * be using it, because it allows them to get the user's secret key.
238 key_secretkey_is_set_g_ext(keylen_t keylen, algtype_t algtype, int use_ruid)
240 mechtype arg;
241 key_netstres3 kres;
244 * key_secretkey_is_set_g_ext is tricky because keylen == 0
245 * means check if any key exists for the caller (old/new, 192/1024 ...)
246 * Rather than handle this on the server side, we call the old
247 * routine if keylen == 0 and try the newer stuff only if that fails
249 if ((keylen == 0) && key_secretkey_is_set_ext(use_ruid))
250 return (1);
251 if (CLASSIC_PK_DH(keylen, algtype))
252 return (key_secretkey_is_set_ext(use_ruid));
253 arg.keylen = keylen;
254 arg.algtype = algtype;
255 (void) memset(&kres, 0, sizeof (kres));
256 if (key_call_ext((rpcproc_t)KEY_NET_GET_3, xdr_mechtype, (char *)&arg,
257 xdr_key_netstres3, (char *)&kres, use_ruid) &&
258 (kres.status == KEY_SUCCESS) &&
259 (kres.key_netstres3_u.knet.st_priv_key.keybuf3_len != 0)) {
260 /* avoid leaving secret key in memory */
261 (void) memset(kres.key_netstres3_u.knet.st_priv_key.keybuf3_val,
262 0, kres.key_netstres3_u.knet.st_priv_key.keybuf3_len);
263 xdr_free(xdr_key_netstres3, (char *)&kres);
264 return (1);
266 return (0);
270 * Use effective uid.
273 key_secretkey_is_set_g(keylen_t keylen, algtype_t algtype)
275 return (key_secretkey_is_set_g_ext(keylen, algtype, 0));
279 * Use real uid.
282 key_secretkey_is_set_g_ruid(keylen_t keylen, algtype_t algtype)
284 return (key_secretkey_is_set_g_ext(keylen, algtype, 1));
289 key_encryptsession_pk(const char *remotename, netobj *remotekey,
290 des_block *deskey)
292 cryptkeyarg2 arg;
293 cryptkeyres res;
295 arg.remotename = (char *)remotename;
296 arg.remotekey = *remotekey;
297 arg.deskey = *deskey;
298 if (!key_call((rpcproc_t)KEY_ENCRYPT_PK, xdr_cryptkeyarg2, (char *)&arg,
299 xdr_cryptkeyres, (char *)&res))
300 return (-1);
301 if (res.status != KEY_SUCCESS) {
302 debug("encrypt status is nonzero");
303 return (-1);
305 *deskey = res.cryptkeyres_u.deskey;
306 return (0);
310 key_encryptsession_pk_g(
311 const char *remotename,
312 const char *remotekey,
313 keylen_t remotekeylen,
314 algtype_t algtype,
315 des_block deskey[],
316 keynum_t keynum
319 cryptkeyarg3 arg;
320 cryptkeyres3 res;
322 if (CLASSIC_PK_DH(remotekeylen, algtype)) {
323 int i;
324 netobj npk;
326 npk.n_len = remotekeylen/4 + 1;
327 npk.n_bytes = (char *)remotekey;
328 for (i = 0; i < keynum; i++) {
329 if (key_encryptsession_pk(remotename, &npk, &deskey[i]))
330 return (-1);
332 return (0);
334 arg.remotename = (char *)remotename;
335 arg.remotekey.keybuf3_len = remotekeylen/4 + 1;
336 arg.remotekey.keybuf3_val = (char *)remotekey;
337 arg.keylen = remotekeylen;
338 arg.algtype = algtype;
339 arg.deskey.deskeyarray_len = keynum;
340 arg.deskey.deskeyarray_val = deskey;
341 (void) memset(&res, 0, sizeof (res));
342 res.cryptkeyres3_u.deskey.deskeyarray_val = deskey;
343 if (!key_call((rpcproc_t)KEY_ENCRYPT_PK_3,
344 xdr_cryptkeyarg3, (char *)&arg,
345 xdr_cryptkeyres3, (char *)&res))
346 return (-1);
347 if (res.status != KEY_SUCCESS) {
348 debug("encrypt3 status is nonzero");
349 return (-1);
351 if (res.cryptkeyres3_u.deskey.deskeyarray_len != keynum) {
352 debug("number of keys don't match");
353 return (-1);
355 return (0);
359 key_decryptsession_pk(const char *remotename, netobj *remotekey,
360 des_block *deskey)
362 cryptkeyarg2 arg;
363 cryptkeyres res;
365 arg.remotename = (char *)remotename;
366 arg.remotekey = *remotekey;
367 arg.deskey = *deskey;
368 if (!key_call((rpcproc_t)KEY_DECRYPT_PK, xdr_cryptkeyarg2, (char *)&arg,
369 xdr_cryptkeyres, (char *)&res))
370 return (-1);
371 if (res.status != KEY_SUCCESS) {
372 debug("decrypt status is nonzero");
373 return (-1);
375 *deskey = res.cryptkeyres_u.deskey;
376 return (0);
380 key_decryptsession_pk_g(
381 const char *remotename,
382 const char *remotekey,
383 keylen_t remotekeylen,
384 algtype_t algtype,
385 des_block deskey[],
386 keynum_t keynum
389 cryptkeyarg3 arg;
390 cryptkeyres3 res;
392 if (CLASSIC_PK_DH(remotekeylen, algtype)) {
393 int i;
394 netobj npk;
396 npk.n_len = remotekeylen/4 + 1;
397 npk.n_bytes = (char *)remotekey;
398 for (i = 0; i < keynum; i++) {
399 if (key_decryptsession_pk(remotename,
400 &npk, &deskey[i]))
401 return (-1);
403 return (0);
405 arg.remotename = (char *)remotename;
406 arg.remotekey.keybuf3_len = remotekeylen/4 + 1;
407 arg.remotekey.keybuf3_val = (char *)remotekey;
408 arg.deskey.deskeyarray_len = keynum;
409 arg.deskey.deskeyarray_val = deskey;
410 arg.algtype = algtype;
411 arg.keylen = remotekeylen;
412 (void) memset(&res, 0, sizeof (res));
413 res.cryptkeyres3_u.deskey.deskeyarray_val = deskey;
414 if (!key_call((rpcproc_t)KEY_DECRYPT_PK_3,
415 xdr_cryptkeyarg3, (char *)&arg,
416 xdr_cryptkeyres3, (char *)&res))
417 return (-1);
418 if (res.status != KEY_SUCCESS) {
419 debug("decrypt3 status is nonzero");
420 return (-1);
422 if (res.cryptkeyres3_u.deskey.deskeyarray_len != keynum) {
423 debug("number of keys don't match");
424 return (-1);
426 return (0);
430 key_encryptsession(const char *remotename, des_block *deskey)
432 cryptkeyarg arg;
433 cryptkeyres res;
435 arg.remotename = (char *)remotename;
436 arg.deskey = *deskey;
437 if (!key_call((rpcproc_t)KEY_ENCRYPT, xdr_cryptkeyarg, (char *)&arg,
438 xdr_cryptkeyres, (char *)&res))
439 return (-1);
440 if (res.status != KEY_SUCCESS) {
441 debug("encrypt status is nonzero");
442 return (-1);
444 *deskey = res.cryptkeyres_u.deskey;
445 return (0);
449 key_encryptsession_g(
450 const char *remotename,
451 keylen_t keylen,
452 algtype_t algtype,
453 des_block deskey[],
454 keynum_t keynum
457 cryptkeyarg3 arg;
458 cryptkeyres3 res;
460 if (CLASSIC_PK_DH(keylen, algtype))
461 return (key_encryptsession(remotename, deskey));
462 arg.remotename = (char *)remotename;
463 arg.algtype = algtype;
464 arg.keylen = keylen;
465 arg.deskey.deskeyarray_len = keynum;
466 arg.deskey.deskeyarray_val = deskey;
467 arg.remotekey.keybuf3_len = 0;
468 (void) memset(&res, 0, sizeof (res));
469 res.cryptkeyres3_u.deskey.deskeyarray_val = deskey;
470 if (!key_call((rpcproc_t)KEY_ENCRYPT_3, xdr_cryptkeyarg3, (char *)&arg,
471 xdr_cryptkeyres3, (char *)&res))
472 return (-1);
473 if (res.status != KEY_SUCCESS) {
474 debug("encrypt3 status is nonzero");
475 return (-1);
477 if (res.cryptkeyres3_u.deskey.deskeyarray_len != keynum) {
478 debug("encrypt3 didn't return same number of keys");
479 return (-1);
481 return (0);
486 key_decryptsession(const char *remotename, des_block *deskey)
488 cryptkeyarg arg;
489 cryptkeyres res;
491 arg.remotename = (char *)remotename;
492 arg.deskey = *deskey;
493 if (!key_call((rpcproc_t)KEY_DECRYPT, xdr_cryptkeyarg, (char *)&arg,
494 xdr_cryptkeyres, (char *)&res))
495 return (-1);
496 if (res.status != KEY_SUCCESS) {
497 debug("decrypt status is nonzero");
498 return (-1);
500 *deskey = res.cryptkeyres_u.deskey;
501 return (0);
505 key_decryptsession_g(
506 const char *remotename,
507 keylen_t keylen,
508 algtype_t algtype,
509 des_block deskey[],
510 keynum_t keynum
513 cryptkeyarg3 arg;
514 cryptkeyres3 res;
516 if (CLASSIC_PK_DH(keylen, algtype))
517 return (key_decryptsession(remotename, deskey));
518 arg.remotename = (char *)remotename;
519 arg.algtype = algtype;
520 arg.keylen = keylen;
521 arg.deskey.deskeyarray_len = keynum;
522 arg.deskey.deskeyarray_val = deskey;
523 arg.remotekey.keybuf3_len = 0;
524 (void) memset(&res, 0, sizeof (res));
525 res.cryptkeyres3_u.deskey.deskeyarray_val = deskey;
526 if (!key_call((rpcproc_t)KEY_DECRYPT_3, xdr_cryptkeyarg3, (char *)&arg,
527 xdr_cryptkeyres3, (char *)&res))
528 return (-1);
529 if (res.status != KEY_SUCCESS) {
530 debug("decrypt3 status is nonzero");
531 return (-1);
533 if (res.cryptkeyres3_u.deskey.deskeyarray_len != keynum) {
534 debug("decrypt3 didn't return same number of keys");
535 return (-1);
537 return (0);
541 key_gendes(des_block *key)
543 if (!key_call((rpcproc_t)KEY_GEN, xdr_void, NULL,
544 xdr_des_block, (char *)key))
545 return (-1);
546 return (0);
550 key_gendes_g(
551 des_block deskey[],
552 keynum_t keynum
555 deskeyarray res;
557 res.deskeyarray_val = deskey;
558 if (!key_call((rpcproc_t)KEY_GEN_3, xdr_keynum_t, (char *)&keynum,
559 xdr_deskeyarray, (char *)&res))
560 return (-1);
561 if (res.deskeyarray_len != keynum) {
562 debug("return length doesn't match\n");
563 return (-1);
565 return (0);
569 * Call KEY_NET_PUT Operation to the keyserv.
571 * If use_ruid == 0, use effective uid.
572 * If use_ruid == 1, use real uid.
575 key_setnet_ext(struct key_netstarg *arg, int use_ruid)
577 keystatus status;
579 if (!key_call_ext((rpcproc_t)KEY_NET_PUT, xdr_key_netstarg,
580 (char *)arg, xdr_keystatus, (char *)&status, use_ruid))
581 return (-1);
583 if (status != KEY_SUCCESS) {
584 debug("key_setnet status is nonzero");
585 return (-1);
587 return (1);
591 * Use effective uid.
594 key_setnet(struct key_netstarg *arg)
596 return (key_setnet_ext(arg, 0));
600 * Use real uid.
603 key_setnet_ruid(struct key_netstarg *arg)
605 return (key_setnet_ext(arg, 1));
609 * Input netname, secret and public keys (hex string representation)
610 * of length skeylen/pkeylen (bits), and algorithm type. One, but not
611 * both, of skey or pkey may have zero length. If both lengths are
612 * specified, they must be the same.
614 * Call KEY_NET_PUT_3 Operation to the keyserv.
615 * Stores the specified netname/pkey/skey triplet in the keyserv.
617 * If (use_ruid == 1), use real uid.
618 * If (use_ruid == 0), use effective uid.
621 key_setnet_g_ext(
622 const char *netname,
623 const char *skey,
624 keylen_t skeylen,
625 const char *pkey,
626 keylen_t pkeylen,
627 algtype_t algtype,
628 int use_ruid)
630 key_netstarg3 arg;
631 keystatus status;
633 arg.st_netname = (char *)netname;
634 arg.algtype = algtype;
635 if (skeylen == 0) {
636 arg.st_priv_key.keybuf3_len = 0;
637 } else {
638 arg.st_priv_key.keybuf3_len = skeylen/4 + 1;
640 arg.st_priv_key.keybuf3_val = (char *)skey;
641 if (pkeylen == 0) {
642 arg.st_pub_key.keybuf3_len = 0;
643 } else {
644 arg.st_pub_key.keybuf3_len = pkeylen/4 + 1;
646 arg.st_pub_key.keybuf3_val = (char *)pkey;
647 if (skeylen == 0) {
648 if (pkeylen == 0) {
649 debug("keylens are both 0");
650 return (-1);
652 arg.keylen = pkeylen;
653 } else {
654 if ((pkeylen != 0) && (skeylen != pkeylen)) {
655 debug("keylens don't match");
656 return (-1);
658 arg.keylen = skeylen;
660 if (CLASSIC_PK_DH(arg.keylen, arg.algtype)) {
661 key_netstarg tmp;
663 if (skeylen != 0) {
664 (void) memcpy(&tmp.st_priv_key, skey,
665 sizeof (tmp.st_priv_key));
666 } else {
667 (void) memset(&tmp.st_priv_key, 0,
668 sizeof (tmp.st_priv_key));
670 if (pkeylen != 0) {
671 (void) memcpy(&tmp.st_pub_key, skey,
672 sizeof (tmp.st_pub_key));
673 } else {
674 (void) memset(&tmp.st_pub_key, 0,
675 sizeof (tmp.st_pub_key));
677 tmp.st_netname = (char *)netname;
678 return (key_setnet(&tmp));
680 if (!key_call_ext((rpcproc_t)KEY_NET_PUT_3,
681 xdr_key_netstarg3, (char *)&arg,
682 xdr_keystatus, (char *)&status, use_ruid)) {
683 return (-1);
686 if (status != KEY_SUCCESS) {
687 debug("key_setnet3 status is nonzero");
688 return (-1);
690 return (0);
694 * Use effective uid.
697 key_setnet_g(const char *netname, const char *skey, keylen_t skeylen,
698 const char *pkey, keylen_t pkeylen, algtype_t algtype)
700 return (key_setnet_g_ext(netname, skey, skeylen, pkey, pkeylen,
701 algtype, 0));
705 * Use real uid.
708 key_setnet_g_ruid(const char *netname, const char *skey, keylen_t skeylen,
709 const char *pkey, keylen_t pkeylen, algtype_t algtype)
711 return (key_setnet_g_ext(netname, skey, skeylen, pkey, pkeylen,
712 algtype, 1));
716 key_get_conv(char *pkey, des_block *deskey)
718 cryptkeyres res;
720 if (!key_call((rpcproc_t)KEY_GET_CONV, xdr_keybuf, pkey,
721 xdr_cryptkeyres, (char *)&res))
722 return (-1);
723 if (res.status != KEY_SUCCESS) {
724 debug("get_conv status is nonzero");
725 return (-1);
727 *deskey = res.cryptkeyres_u.deskey;
728 return (0);
732 key_get_conv_g(
733 const char *pkey,
734 keylen_t pkeylen,
735 algtype_t algtype,
736 des_block deskey[],
737 keynum_t keynum
740 deskeyarg3 arg;
741 cryptkeyres3 res;
743 if (CLASSIC_PK_DH(pkeylen, algtype))
744 return (key_get_conv((char *)pkey, deskey));
745 arg.pub_key.keybuf3_len = pkeylen/4 + 1;
746 arg.pub_key.keybuf3_val = (char *)pkey;
747 arg.nkeys = keynum;
748 arg.algtype = algtype;
749 arg.keylen = pkeylen;
750 (void) memset(&res, 0, sizeof (res));
751 res.cryptkeyres3_u.deskey.deskeyarray_val = deskey;
752 if (!key_call((rpcproc_t)KEY_GET_CONV_3, xdr_deskeyarg3, (char *)&arg,
753 xdr_cryptkeyres3, (char *)&res))
754 return (-1);
755 if (res.status != KEY_SUCCESS) {
756 debug("get_conv3 status is nonzero");
757 return (-1);
759 if (res.cryptkeyres3_u.deskey.deskeyarray_len != keynum) {
760 debug("get_conv3 number of keys dont match");
761 return (-1);
763 return (0);
766 struct key_call_private {
767 CLIENT *client; /* Client handle */
768 pid_t pid; /* process-id at moment of creation */
769 int fd; /* client handle fd */
770 dev_t rdev; /* device client handle is using */
773 static void set_rdev(struct key_call_private *);
774 static int check_rdev(struct key_call_private *);
776 static void
777 key_call_destroy(void *vp)
779 struct key_call_private *kcp = (struct key_call_private *)vp;
781 if (kcp != NULL && kcp->client != NULL) {
782 (void) check_rdev(kcp);
783 clnt_destroy(kcp->client);
784 free(kcp);
788 static pthread_key_t key_call_key = PTHREAD_ONCE_KEY_NP;
790 void
791 _key_call_fini(void)
793 struct key_call_private *kcp;
795 if ((kcp = pthread_getspecific(key_call_key)) != NULL) {
796 key_call_destroy(kcp);
797 (void) pthread_setspecific(key_call_key, NULL);
802 * Keep the handle cached. This call may be made quite often.
804 static CLIENT *
805 getkeyserv_handle(int vers, int stale)
807 struct key_call_private *kcp = NULL;
808 int _update_did();
810 kcp = thr_get_storage(&key_call_key, sizeof (*kcp), key_call_destroy);
811 if (kcp == NULL) {
812 syslog(LOG_CRIT, "getkeyserv_handle: out of memory");
813 return (NULL);
817 * if pid has changed, destroy client and rebuild
818 * or if stale is '1' then destroy client and rebuild
820 if (kcp->client &&
821 (!check_rdev(kcp) || kcp->pid != getpid() || stale)) {
822 clnt_destroy(kcp->client);
823 kcp->client = NULL;
825 if (kcp->client) {
826 int fd;
828 * Change the version number to the new one.
830 clnt_control(kcp->client, CLSET_VERS, (void *)&vers);
831 if (!_update_did(kcp->client, vers)) {
832 if (rpc_createerr.cf_stat == RPC_SYSTEMERROR)
833 syslog(LOG_DEBUG, "getkeyserv_handle: "
834 "out of memory!");
835 return (NULL);
837 /* Update fd in kcp because it was reopened in _update_did */
838 if (clnt_control(kcp->client, CLGET_FD, (void *)&fd) &&
839 (fd >= 0))
840 (void) fcntl(fd, F_SETFD, FD_CLOEXEC); /* close exec */
841 kcp->fd = fd;
842 return (kcp->client);
845 if ((kcp->client = clnt_door_create(KEY_PROG, vers, 0)) == NULL)
846 return (NULL);
848 kcp->pid = getpid();
849 set_rdev(kcp);
850 (void) fcntl(kcp->fd, F_SETFD, FD_CLOEXEC); /* close on exec */
852 return (kcp->client);
856 * RPC calls to the keyserv.
858 * If (use_ruid == 1), use real uid.
859 * If (use_ruid == 0), use effective uid.
860 * Returns 0 on failure, 1 on success
863 key_call_ext(rpcproc_t proc, xdrproc_t xdr_arg, char *arg, xdrproc_t xdr_rslt,
864 char *rslt, int use_ruid)
866 CLIENT *clnt;
867 struct timeval wait_time = {0, 0};
868 enum clnt_stat status;
869 int vers;
871 if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) {
872 cryptkeyres res;
873 bool_t r;
874 r = (*__key_encryptsession_pk_LOCAL)(geteuid(), arg, &res);
875 if (r == TRUE) {
876 /* LINTED pointer alignment */
877 *(cryptkeyres*)rslt = res;
878 return (1);
880 return (0);
882 if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) {
883 cryptkeyres res;
884 bool_t r;
885 r = (*__key_decryptsession_pk_LOCAL)(geteuid(), arg, &res);
886 if (r == TRUE) {
887 /* LINTED pointer alignment */
888 *(cryptkeyres*)rslt = res;
889 return (1);
891 return (0);
893 if (proc == KEY_GEN && __key_gendes_LOCAL) {
894 des_block res;
895 bool_t r;
896 r = (*__key_gendes_LOCAL)(geteuid(), 0, &res);
897 if (r == TRUE) {
898 /* LINTED pointer alignment */
899 *(des_block*)rslt = res;
900 return (1);
902 return (0);
905 if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) ||
906 (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) ||
907 (proc == KEY_GET_CONV))
908 vers = 2; /* talk to version 2 */
909 else
910 vers = 1; /* talk to version 1 */
912 clnt = getkeyserv_handle(vers, 0);
913 if (clnt == NULL)
914 return (0);
916 auth_destroy(clnt->cl_auth);
917 if (use_ruid)
918 clnt->cl_auth = authsys_create_ruid();
919 else
920 clnt->cl_auth = authnone_create();
922 status = CLNT_CALL(clnt, proc, xdr_arg, arg, xdr_rslt,
923 rslt, wait_time);
925 switch (status) {
926 case RPC_SUCCESS:
927 return (1);
929 case RPC_CANTRECV:
931 * keyserv was probably restarted, so we'll try once more
933 if ((clnt = getkeyserv_handle(vers, 1)) == NULL)
934 return (0);
936 auth_destroy(clnt->cl_auth);
937 if (use_ruid)
938 clnt->cl_auth = authsys_create_ruid();
939 else
940 clnt->cl_auth = authnone_create();
943 if (CLNT_CALL(clnt, proc, xdr_arg, arg, xdr_rslt, rslt,
944 wait_time) == RPC_SUCCESS)
945 return (1);
946 return (0);
948 default:
949 return (0);
954 * Use effective uid.
957 key_call(rpcproc_t proc, xdrproc_t xdr_arg, char *arg, xdrproc_t xdr_rslt,
958 char *rslt)
960 return (key_call_ext(proc, xdr_arg, arg, xdr_rslt, rslt, 0));
964 * Use real uid.
967 key_call_ruid(rpcproc_t proc, xdrproc_t xdr_arg, char *arg,
968 xdrproc_t xdr_rslt, char *rslt)
970 return (key_call_ext(proc, xdr_arg, arg, xdr_rslt, rslt, 1));
973 static void
974 set_rdev(struct key_call_private *kcp)
976 int fd;
977 struct stat stbuf;
979 if (clnt_control(kcp->client, CLGET_FD, (char *)&fd) != TRUE ||
980 fstat(fd, &stbuf) == -1) {
981 syslog(LOG_DEBUG, "keyserv_client: can't get info");
982 kcp->fd = -1;
983 return;
985 kcp->fd = fd;
986 kcp->rdev = stbuf.st_rdev;
989 static int
990 check_rdev(struct key_call_private *kcp)
992 struct stat stbuf;
994 if (kcp->fd == -1)
995 return (1); /* can't check it, assume it is okay */
997 if (fstat(kcp->fd, &stbuf) == -1) {
998 syslog(LOG_DEBUG, "keyserv_client: can't stat %d", kcp->fd);
999 /* could be because file descriptor was closed */
1000 /* it's not our file descriptor, so don't try to close it */
1001 clnt_control(kcp->client, CLSET_FD_NCLOSE, NULL);
1003 return (0);
1005 if (kcp->rdev != stbuf.st_rdev) {
1006 syslog(LOG_DEBUG,
1007 "keyserv_client: fd %d changed, old=0x%x, new=0x%x",
1008 kcp->fd, kcp->rdev, stbuf.st_rdev);
1009 /* it's not our file descriptor, so don't try to close it */
1010 clnt_control(kcp->client, CLSET_FD_NCLOSE, NULL);
1011 return (0);
1013 return (1); /* fd is okay */