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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29 /*
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.
33 */
34
35 #pragma ident "%Z%%M% %I% %E% SMI"
36
37 /*
38 * Interface to keyserver
39 *
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
44 */
45
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>
58
59 #define CLASSIC_PK_DH(k, a) (((k) == 192) && ((a) == 0))
60
61 #ifdef DEBUG
62 #define debug(msg) (void) fprintf(stderr, "%s\n", msg);
63 #else
64 #define debug(msg)
65 #endif /* DEBUG */
66
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 *);
70
71 /*
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.
75 *
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().
78 */
79
80 bool_t (*__key_encryptsession_pk_LOCAL)() = NULL;
81 bool_t (*__key_decryptsession_pk_LOCAL)() = NULL;
82 bool_t (*__key_gendes_LOCAL)() = NULL;
83
84
85 int
key_setsecret(const char * secretkey)86 key_setsecret(const char *secretkey)
87 {
88 char netName[MAXNETNAMELEN+1];
89 struct key_netstarg netst;
90 int ret;
91
92 if (getnetname(netName) == 0) {
93 debug("getnetname failed");
94 return (-1);
95 }
96
97 (void) memcpy(netst.st_priv_key, secretkey, HEXKEYBYTES);
98 netst.st_pub_key[0] = 0;
99 netst.st_netname = netName;
100
101 /*
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.
107 */
108 ret = key_setnet(&netst);
109
110 /* erase our copy of the secret key */
111 (void) memset(netst.st_priv_key, '\0', HEXKEYBYTES);
112
113 if (ret == 1)
114 return (0);
115
116 return (-1);
117 }
118
119 int
key_setsecret_g(char * secretkey,keylen_t keylen,algtype_t algtype,des_block userkey)120 key_setsecret_g(
121 char *secretkey,
122 keylen_t keylen,
123 algtype_t algtype,
124 des_block userkey)
125 {
126 setkeyarg3 arg;
127 keystatus status;
128
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);
142 }
143 return (0);
144 }
145
146 int
key_removesecret_g_ext(int use_uid)147 key_removesecret_g_ext(int use_uid)
148 {
149 keystatus status;
150
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);
155 }
156 if (status != KEY_SUCCESS) {
157 debug("remove secret status is nonzero");
158 return (-1);
159 }
160 return (0);
161 }
162
163 /*
164 * Use effective uid.
165 */
166 int
key_removesecret_g(void)167 key_removesecret_g(void)
168 {
169 return (key_removesecret_g_ext(0));
170 }
171
172 /*
173 * Use real uid.
174 */
175 int
key_removesecret_g_ruid(void)176 key_removesecret_g_ruid(void)
177 {
178 return (key_removesecret_g_ext(1));
179 }
180
181 /*
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.
186 *
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.
189 *
190 */
191 int
key_secretkey_is_set_ext(int use_ruid)192 key_secretkey_is_set_ext(int use_ruid)
193 {
194 struct key_netstres kres;
195
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);
206 }
207 return (0);
208 }
209
210 /*
211 * Use effective uid.
212 */
213 int
key_secretkey_is_set(void)214 key_secretkey_is_set(void)
215 {
216 return (key_secretkey_is_set_ext(0));
217 }
218
219 /*
220 * Use real uid.
221 */
222 int
key_secretkey_is_set_ruid(void)223 key_secretkey_is_set_ruid(void)
224 {
225 return (key_secretkey_is_set_ext(1));
226 }
227
228 /*
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.
233 *
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.
236 */
237 int
key_secretkey_is_set_g_ext(keylen_t keylen,algtype_t algtype,int use_ruid)238 key_secretkey_is_set_g_ext(keylen_t keylen, algtype_t algtype, int use_ruid)
239 {
240 mechtype arg;
241 key_netstres3 kres;
242
243 /*
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
248 */
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);
265 }
266 return (0);
267 }
268
269 /*
270 * Use effective uid.
271 */
272 int
key_secretkey_is_set_g(keylen_t keylen,algtype_t algtype)273 key_secretkey_is_set_g(keylen_t keylen, algtype_t algtype)
274 {
275 return (key_secretkey_is_set_g_ext(keylen, algtype, 0));
276 }
277
278 /*
279 * Use real uid.
280 */
281 int
key_secretkey_is_set_g_ruid(keylen_t keylen,algtype_t algtype)282 key_secretkey_is_set_g_ruid(keylen_t keylen, algtype_t algtype)
283 {
284 return (key_secretkey_is_set_g_ext(keylen, algtype, 1));
285 }
286
287
288 int
key_encryptsession_pk(const char * remotename,netobj * remotekey,des_block * deskey)289 key_encryptsession_pk(const char *remotename, netobj *remotekey,
290 des_block *deskey)
291 {
292 cryptkeyarg2 arg;
293 cryptkeyres res;
294
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);
304 }
305 *deskey = res.cryptkeyres_u.deskey;
306 return (0);
307 }
308
309 int
key_encryptsession_pk_g(const char * remotename,const char * remotekey,keylen_t remotekeylen,algtype_t algtype,des_block deskey[],keynum_t keynum)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
317 )
318 {
319 cryptkeyarg3 arg;
320 cryptkeyres3 res;
321
322 if (CLASSIC_PK_DH(remotekeylen, algtype)) {
323 int i;
324 netobj npk;
325
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);
331 }
332 return (0);
333 }
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);
350 }
351 if (res.cryptkeyres3_u.deskey.deskeyarray_len != keynum) {
352 debug("number of keys don't match");
353 return (-1);
354 }
355 return (0);
356 }
357
358 int
key_decryptsession_pk(const char * remotename,netobj * remotekey,des_block * deskey)359 key_decryptsession_pk(const char *remotename, netobj *remotekey,
360 des_block *deskey)
361 {
362 cryptkeyarg2 arg;
363 cryptkeyres res;
364
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);
374 }
375 *deskey = res.cryptkeyres_u.deskey;
376 return (0);
377 }
378
379 int
key_decryptsession_pk_g(const char * remotename,const char * remotekey,keylen_t remotekeylen,algtype_t algtype,des_block deskey[],keynum_t keynum)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
387 )
388 {
389 cryptkeyarg3 arg;
390 cryptkeyres3 res;
391
392 if (CLASSIC_PK_DH(remotekeylen, algtype)) {
393 int i;
394 netobj npk;
395
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);
402 }
403 return (0);
404 }
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);
421 }
422 if (res.cryptkeyres3_u.deskey.deskeyarray_len != keynum) {
423 debug("number of keys don't match");
424 return (-1);
425 }
426 return (0);
427 }
428
429 int
key_encryptsession(const char * remotename,des_block * deskey)430 key_encryptsession(const char *remotename, des_block *deskey)
431 {
432 cryptkeyarg arg;
433 cryptkeyres res;
434
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);
443 }
444 *deskey = res.cryptkeyres_u.deskey;
445 return (0);
446 }
447
448 int
key_encryptsession_g(const char * remotename,keylen_t keylen,algtype_t algtype,des_block deskey[],keynum_t keynum)449 key_encryptsession_g(
450 const char *remotename,
451 keylen_t keylen,
452 algtype_t algtype,
453 des_block deskey[],
454 keynum_t keynum
455 )
456 {
457 cryptkeyarg3 arg;
458 cryptkeyres3 res;
459
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);
476 }
477 if (res.cryptkeyres3_u.deskey.deskeyarray_len != keynum) {
478 debug("encrypt3 didn't return same number of keys");
479 return (-1);
480 }
481 return (0);
482 }
483
484
485 int
key_decryptsession(const char * remotename,des_block * deskey)486 key_decryptsession(const char *remotename, des_block *deskey)
487 {
488 cryptkeyarg arg;
489 cryptkeyres res;
490
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);
499 }
500 *deskey = res.cryptkeyres_u.deskey;
501 return (0);
502 }
503
504 int
key_decryptsession_g(const char * remotename,keylen_t keylen,algtype_t algtype,des_block deskey[],keynum_t keynum)505 key_decryptsession_g(
506 const char *remotename,
507 keylen_t keylen,
508 algtype_t algtype,
509 des_block deskey[],
510 keynum_t keynum
511 )
512 {
513 cryptkeyarg3 arg;
514 cryptkeyres3 res;
515
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);
532 }
533 if (res.cryptkeyres3_u.deskey.deskeyarray_len != keynum) {
534 debug("decrypt3 didn't return same number of keys");
535 return (-1);
536 }
537 return (0);
538 }
539
540 int
key_gendes(des_block * key)541 key_gendes(des_block *key)
542 {
543 if (!key_call((rpcproc_t)KEY_GEN, xdr_void, NULL,
544 xdr_des_block, (char *)key))
545 return (-1);
546 return (0);
547 }
548
549 int
key_gendes_g(des_block deskey[],keynum_t keynum)550 key_gendes_g(
551 des_block deskey[],
552 keynum_t keynum
553 )
554 {
555 deskeyarray res;
556
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);
564 }
565 return (0);
566 }
567
568 /*
569 * Call KEY_NET_PUT Operation to the keyserv.
570 *
571 * If use_ruid == 0, use effective uid.
572 * If use_ruid == 1, use real uid.
573 */
574 int
key_setnet_ext(struct key_netstarg * arg,int use_ruid)575 key_setnet_ext(struct key_netstarg *arg, int use_ruid)
576 {
577 keystatus status;
578
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);
582
583 if (status != KEY_SUCCESS) {
584 debug("key_setnet status is nonzero");
585 return (-1);
586 }
587 return (1);
588 }
589
590 /*
591 * Use effective uid.
592 */
593 int
key_setnet(struct key_netstarg * arg)594 key_setnet(struct key_netstarg *arg)
595 {
596 return (key_setnet_ext(arg, 0));
597 }
598
599 /*
600 * Use real uid.
601 */
602 int
key_setnet_ruid(struct key_netstarg * arg)603 key_setnet_ruid(struct key_netstarg *arg)
604 {
605 return (key_setnet_ext(arg, 1));
606 }
607
608 /*
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.
613 *
614 * Call KEY_NET_PUT_3 Operation to the keyserv.
615 * Stores the specified netname/pkey/skey triplet in the keyserv.
616 *
617 * If (use_ruid == 1), use real uid.
618 * If (use_ruid == 0), use effective uid.
619 */
620 int
key_setnet_g_ext(const char * netname,const char * skey,keylen_t skeylen,const char * pkey,keylen_t pkeylen,algtype_t algtype,int use_ruid)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)
629 {
630 key_netstarg3 arg;
631 keystatus status;
632
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;
639 }
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;
645 }
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);
651 }
652 arg.keylen = pkeylen;
653 } else {
654 if ((pkeylen != 0) && (skeylen != pkeylen)) {
655 debug("keylens don't match");
656 return (-1);
657 }
658 arg.keylen = skeylen;
659 }
660 if (CLASSIC_PK_DH(arg.keylen, arg.algtype)) {
661 key_netstarg tmp;
662
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));
669 }
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));
676 }
677 tmp.st_netname = (char *)netname;
678 return (key_setnet(&tmp));
679 }
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);
684 }
685
686 if (status != KEY_SUCCESS) {
687 debug("key_setnet3 status is nonzero");
688 return (-1);
689 }
690 return (0);
691 }
692
693 /*
694 * Use effective uid.
695 */
696 int
key_setnet_g(const char * netname,const char * skey,keylen_t skeylen,const char * pkey,keylen_t pkeylen,algtype_t algtype)697 key_setnet_g(const char *netname, const char *skey, keylen_t skeylen,
698 const char *pkey, keylen_t pkeylen, algtype_t algtype)
699 {
700 return (key_setnet_g_ext(netname, skey, skeylen, pkey, pkeylen,
701 algtype, 0));
702 }
703
704 /*
705 * Use real uid.
706 */
707 int
key_setnet_g_ruid(const char * netname,const char * skey,keylen_t skeylen,const char * pkey,keylen_t pkeylen,algtype_t algtype)708 key_setnet_g_ruid(const char *netname, const char *skey, keylen_t skeylen,
709 const char *pkey, keylen_t pkeylen, algtype_t algtype)
710 {
711 return (key_setnet_g_ext(netname, skey, skeylen, pkey, pkeylen,
712 algtype, 1));
713 }
714
715 int
key_get_conv(char * pkey,des_block * deskey)716 key_get_conv(char *pkey, des_block *deskey)
717 {
718 cryptkeyres res;
719
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);
726 }
727 *deskey = res.cryptkeyres_u.deskey;
728 return (0);
729 }
730
731 int
key_get_conv_g(const char * pkey,keylen_t pkeylen,algtype_t algtype,des_block deskey[],keynum_t keynum)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
738 )
739 {
740 deskeyarg3 arg;
741 cryptkeyres3 res;
742
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);
758 }
759 if (res.cryptkeyres3_u.deskey.deskeyarray_len != keynum) {
760 debug("get_conv3 number of keys dont match");
761 return (-1);
762 }
763 return (0);
764 }
765
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 */
771 };
772
773 static void set_rdev(struct key_call_private *);
774 static int check_rdev(struct key_call_private *);
775
776 static void
key_call_destroy(void * vp)777 key_call_destroy(void *vp)
778 {
779 struct key_call_private *kcp = (struct key_call_private *)vp;
780
781 if (kcp != NULL && kcp->client != NULL) {
782 (void) check_rdev(kcp);
783 clnt_destroy(kcp->client);
784 free(kcp);
785 }
786 }
787
788 static pthread_key_t key_call_key = PTHREAD_ONCE_KEY_NP;
789
790 void
_key_call_fini(void)791 _key_call_fini(void)
792 {
793 struct key_call_private *kcp;
794
795 if ((kcp = pthread_getspecific(key_call_key)) != NULL) {
796 key_call_destroy(kcp);
797 (void) pthread_setspecific(key_call_key, NULL);
798 }
799 }
800
801 /*
802 * Keep the handle cached. This call may be made quite often.
803 */
804 static CLIENT *
getkeyserv_handle(int vers,int stale)805 getkeyserv_handle(int vers, int stale)
806 {
807 struct key_call_private *kcp = NULL;
808 int _update_did();
809
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);
814 }
815
816 /*
817 * if pid has changed, destroy client and rebuild
818 * or if stale is '1' then destroy client and rebuild
819 */
820 if (kcp->client &&
821 (!check_rdev(kcp) || kcp->pid != getpid() || stale)) {
822 clnt_destroy(kcp->client);
823 kcp->client = NULL;
824 }
825 if (kcp->client) {
826 int fd;
827 /*
828 * Change the version number to the new one.
829 */
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);
836 }
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);
843 }
844
845 if ((kcp->client = clnt_door_create(KEY_PROG, vers, 0)) == NULL)
846 return (NULL);
847
848 kcp->pid = getpid();
849 set_rdev(kcp);
850 (void) fcntl(kcp->fd, F_SETFD, FD_CLOEXEC); /* close on exec */
851
852 return (kcp->client);
853 }
854
855 /*
856 * RPC calls to the keyserv.
857 *
858 * If (use_ruid == 1), use real uid.
859 * If (use_ruid == 0), use effective uid.
860 * Returns 0 on failure, 1 on success
861 */
862 int
key_call_ext(rpcproc_t proc,xdrproc_t xdr_arg,char * arg,xdrproc_t xdr_rslt,char * rslt,int use_ruid)863 key_call_ext(rpcproc_t proc, xdrproc_t xdr_arg, char *arg, xdrproc_t xdr_rslt,
864 char *rslt, int use_ruid)
865 {
866 CLIENT *clnt;
867 struct timeval wait_time = {0, 0};
868 enum clnt_stat status;
869 int vers;
870
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);
879 }
880 return (0);
881 }
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);
890 }
891 return (0);
892 }
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);
901 }
902 return (0);
903 }
904
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 */
911
912 clnt = getkeyserv_handle(vers, 0);
913 if (clnt == NULL)
914 return (0);
915
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();
921
922 status = CLNT_CALL(clnt, proc, xdr_arg, arg, xdr_rslt,
923 rslt, wait_time);
924
925 switch (status) {
926 case RPC_SUCCESS:
927 return (1);
928
929 case RPC_CANTRECV:
930 /*
931 * keyserv was probably restarted, so we'll try once more
932 */
933 if ((clnt = getkeyserv_handle(vers, 1)) == NULL)
934 return (0);
935
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();
941
942
943 if (CLNT_CALL(clnt, proc, xdr_arg, arg, xdr_rslt, rslt,
944 wait_time) == RPC_SUCCESS)
945 return (1);
946 return (0);
947
948 default:
949 return (0);
950 }
951 }
952
953 /*
954 * Use effective uid.
955 */
956 int
key_call(rpcproc_t proc,xdrproc_t xdr_arg,char * arg,xdrproc_t xdr_rslt,char * rslt)957 key_call(rpcproc_t proc, xdrproc_t xdr_arg, char *arg, xdrproc_t xdr_rslt,
958 char *rslt)
959 {
960 return (key_call_ext(proc, xdr_arg, arg, xdr_rslt, rslt, 0));
961 }
962
963 /*
964 * Use real uid.
965 */
966 int
key_call_ruid(rpcproc_t proc,xdrproc_t xdr_arg,char * arg,xdrproc_t xdr_rslt,char * rslt)967 key_call_ruid(rpcproc_t proc, xdrproc_t xdr_arg, char *arg,
968 xdrproc_t xdr_rslt, char *rslt)
969 {
970 return (key_call_ext(proc, xdr_arg, arg, xdr_rslt, rslt, 1));
971 }
972
973 static void
set_rdev(struct key_call_private * kcp)974 set_rdev(struct key_call_private *kcp)
975 {
976 int fd;
977 struct stat stbuf;
978
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;
984 }
985 kcp->fd = fd;
986 kcp->rdev = stbuf.st_rdev;
987 }
988
989 static int
check_rdev(struct key_call_private * kcp)990 check_rdev(struct key_call_private *kcp)
991 {
992 struct stat stbuf;
993
994 if (kcp->fd == -1)
995 return (1); /* can't check it, assume it is okay */
996
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);
1002
1003 return (0);
1004 }
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);
1012 }
1013 return (1); /* fd is okay */
1014 }
1015