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