1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 2009, Sun Microsystems, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * - Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * - Neither the name of Sun Microsystems, Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30 /*
31 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
32 */
33
34 #ident "@(#)key_call.c 1.25 94/04/24 SMI"
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 /*
39 * key_call.c, 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 "namespace.h"
48 #include "reentrant.h"
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <unistd.h>
52 #include <errno.h>
53 #include <rpc/rpc.h>
54 #include <rpc/auth.h>
55 #include <rpc/auth_unix.h>
56 #include <rpc/key_prot.h>
57 #include <string.h>
58 #include <netconfig.h>
59 #include <sys/utsname.h>
60 #include <stdlib.h>
61 #include <signal.h>
62 #include <sys/wait.h>
63 #include <sys/fcntl.h>
64 #include "un-namespace.h"
65 #include "mt_misc.h"
66
67
68 #define KEY_TIMEOUT 5 /* per-try timeout in seconds */
69 #define KEY_NRETRY 12 /* number of retries */
70
71 #ifdef DEBUG
72 #define debug(msg) (void) fprintf(stderr, "%s\n", msg);
73 #else
74 #define debug(msg)
75 #endif /* DEBUG */
76
77 /*
78 * Hack to allow the keyserver to use AUTH_DES (for authenticated
79 * NIS+ calls, for example). The only functions that get called
80 * are key_encryptsession_pk, key_decryptsession_pk, and key_gendes.
81 *
82 * The approach is to have the keyserver fill in pointers to local
83 * implementations of these functions, and to call those in key_call().
84 */
85
86 cryptkeyres *(*__key_encryptsession_pk_LOCAL)(uid_t, void *arg) = 0;
87 cryptkeyres *(*__key_decryptsession_pk_LOCAL)(uid_t, void *arg) = 0;
88 des_block *(*__key_gendes_LOCAL)(uid_t, void *) = 0;
89
90 static int key_call( u_long, xdrproc_t, void *, xdrproc_t, void *);
91
92 int
key_setsecret(const char * secretkey)93 key_setsecret(const char *secretkey)
94 {
95 keystatus status;
96
97 if (!key_call((u_long) KEY_SET, (xdrproc_t)xdr_keybuf,
98 (void *)secretkey,
99 (xdrproc_t)xdr_keystatus, &status)) {
100 return (-1);
101 }
102 if (status != KEY_SUCCESS) {
103 debug("set status is nonzero");
104 return (-1);
105 }
106 return (0);
107 }
108
109
110 /* key_secretkey_is_set() returns 1 if the keyserver has a secret key
111 * stored for the caller's effective uid; it returns 0 otherwise
112 *
113 * N.B.: The KEY_NET_GET key call is undocumented. Applications shouldn't
114 * be using it, because it allows them to get the user's secret key.
115 */
116
117 int
key_secretkey_is_set(void)118 key_secretkey_is_set(void)
119 {
120 struct key_netstres kres;
121
122 memset((void*)&kres, 0, sizeof (kres));
123 if (key_call((u_long) KEY_NET_GET, (xdrproc_t)xdr_void, NULL,
124 (xdrproc_t)xdr_key_netstres, &kres) &&
125 (kres.status == KEY_SUCCESS) &&
126 (kres.key_netstres_u.knet.st_priv_key[0] != 0)) {
127 /* avoid leaving secret key in memory */
128 memset(kres.key_netstres_u.knet.st_priv_key, 0, HEXKEYBYTES);
129 return (1);
130 }
131 return (0);
132 }
133
134 int
key_encryptsession_pk(char * remotename,netobj * remotekey,des_block * deskey)135 key_encryptsession_pk(char *remotename, netobj *remotekey, des_block *deskey)
136 {
137 cryptkeyarg2 arg;
138 cryptkeyres res;
139
140 arg.remotename = remotename;
141 arg.remotekey = *remotekey;
142 arg.deskey = *deskey;
143 if (!key_call((u_long)KEY_ENCRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg,
144 (xdrproc_t)xdr_cryptkeyres, &res)) {
145 return (-1);
146 }
147 if (res.status != KEY_SUCCESS) {
148 debug("encrypt status is nonzero");
149 return (-1);
150 }
151 *deskey = res.cryptkeyres_u.deskey;
152 return (0);
153 }
154
155 int
key_decryptsession_pk(char * remotename,netobj * remotekey,des_block * deskey)156 key_decryptsession_pk(char *remotename, netobj *remotekey, des_block *deskey)
157 {
158 cryptkeyarg2 arg;
159 cryptkeyres res;
160
161 arg.remotename = remotename;
162 arg.remotekey = *remotekey;
163 arg.deskey = *deskey;
164 if (!key_call((u_long)KEY_DECRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg,
165 (xdrproc_t)xdr_cryptkeyres, &res)) {
166 return (-1);
167 }
168 if (res.status != KEY_SUCCESS) {
169 debug("decrypt status is nonzero");
170 return (-1);
171 }
172 *deskey = res.cryptkeyres_u.deskey;
173 return (0);
174 }
175
176 int
key_encryptsession(const char * remotename,des_block * deskey)177 key_encryptsession(const char *remotename, des_block *deskey)
178 {
179 cryptkeyarg arg;
180 cryptkeyres res;
181
182 arg.remotename = (char *) remotename;
183 arg.deskey = *deskey;
184 if (!key_call((u_long)KEY_ENCRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg,
185 (xdrproc_t)xdr_cryptkeyres, &res)) {
186 return (-1);
187 }
188 if (res.status != KEY_SUCCESS) {
189 debug("encrypt status is nonzero");
190 return (-1);
191 }
192 *deskey = res.cryptkeyres_u.deskey;
193 return (0);
194 }
195
196 int
key_decryptsession(const char * remotename,des_block * deskey)197 key_decryptsession(const char *remotename, des_block *deskey)
198 {
199 cryptkeyarg arg;
200 cryptkeyres res;
201
202 arg.remotename = (char *) remotename;
203 arg.deskey = *deskey;
204 if (!key_call((u_long)KEY_DECRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg,
205 (xdrproc_t)xdr_cryptkeyres, &res)) {
206 return (-1);
207 }
208 if (res.status != KEY_SUCCESS) {
209 debug("decrypt status is nonzero");
210 return (-1);
211 }
212 *deskey = res.cryptkeyres_u.deskey;
213 return (0);
214 }
215
216 int
key_gendes(des_block * key)217 key_gendes(des_block *key)
218 {
219 if (!key_call((u_long)KEY_GEN, (xdrproc_t)xdr_void, NULL,
220 (xdrproc_t)xdr_des_block, key)) {
221 return (-1);
222 }
223 return (0);
224 }
225
226 int
key_setnet(struct key_netstarg * arg)227 key_setnet(struct key_netstarg *arg)
228 {
229 keystatus status;
230
231
232 if (!key_call((u_long) KEY_NET_PUT, (xdrproc_t)xdr_key_netstarg, arg,
233 (xdrproc_t)xdr_keystatus, &status)){
234 return (-1);
235 }
236
237 if (status != KEY_SUCCESS) {
238 debug("key_setnet status is nonzero");
239 return (-1);
240 }
241 return (1);
242 }
243
244
245 int
key_get_conv(char * pkey,des_block * deskey)246 key_get_conv(char *pkey, des_block *deskey)
247 {
248 cryptkeyres res;
249
250 if (!key_call((u_long) KEY_GET_CONV, (xdrproc_t)xdr_keybuf, pkey,
251 (xdrproc_t)xdr_cryptkeyres, &res)) {
252 return (-1);
253 }
254 if (res.status != KEY_SUCCESS) {
255 debug("get_conv status is nonzero");
256 return (-1);
257 }
258 *deskey = res.cryptkeyres_u.deskey;
259 return (0);
260 }
261
262 struct key_call_private {
263 CLIENT *client; /* Client handle */
264 pid_t pid; /* process-id at moment of creation */
265 uid_t uid; /* user-id at last authorization */
266 };
267 static struct key_call_private *key_call_private_main = NULL;
268 static thread_key_t key_call_key;
269 static once_t key_call_once = ONCE_INITIALIZER;
270 static int key_call_key_error;
271
272 static void
key_call_destroy(void * vp)273 key_call_destroy(void *vp)
274 {
275 struct key_call_private *kcp = (struct key_call_private *)vp;
276
277 if (kcp) {
278 if (kcp->client)
279 clnt_destroy(kcp->client);
280 free(kcp);
281 }
282 }
283
284 static void
key_call_init(void)285 key_call_init(void)
286 {
287
288 key_call_key_error = thr_keycreate(&key_call_key, key_call_destroy);
289 }
290
291 /*
292 * Keep the handle cached. This call may be made quite often.
293 */
294 static CLIENT *
getkeyserv_handle(int vers)295 getkeyserv_handle(int vers)
296 {
297 void *localhandle;
298 struct netconfig *nconf;
299 struct netconfig *tpconf;
300 struct key_call_private *kcp;
301 struct timeval wait_time;
302 struct utsname u;
303 int main_thread;
304 int fd;
305
306 #define TOTAL_TIMEOUT 30 /* total timeout talking to keyserver */
307 #define TOTAL_TRIES 5 /* Number of tries */
308
309 if ((main_thread = thr_main())) {
310 kcp = key_call_private_main;
311 } else {
312 if (thr_once(&key_call_once, key_call_init) != 0 ||
313 key_call_key_error != 0)
314 return ((CLIENT *) NULL);
315 kcp = (struct key_call_private *)thr_getspecific(key_call_key);
316 }
317 if (kcp == (struct key_call_private *)NULL) {
318 kcp = (struct key_call_private *)malloc(sizeof (*kcp));
319 if (kcp == (struct key_call_private *)NULL) {
320 return ((CLIENT *) NULL);
321 }
322 if (main_thread)
323 key_call_private_main = kcp;
324 else
325 thr_setspecific(key_call_key, (void *) kcp);
326 kcp->client = NULL;
327 }
328
329 /* if pid has changed, destroy client and rebuild */
330 if (kcp->client != NULL && kcp->pid != getpid()) {
331 clnt_destroy(kcp->client);
332 kcp->client = NULL;
333 }
334
335 if (kcp->client != NULL) {
336 /* if uid has changed, build client handle again */
337 if (kcp->uid != geteuid()) {
338 kcp->uid = geteuid();
339 auth_destroy(kcp->client->cl_auth);
340 kcp->client->cl_auth =
341 authsys_create("", kcp->uid, 0, 0, NULL);
342 if (kcp->client->cl_auth == NULL) {
343 clnt_destroy(kcp->client);
344 kcp->client = NULL;
345 return ((CLIENT *) NULL);
346 }
347 }
348 /* Change the version number to the new one */
349 clnt_control(kcp->client, CLSET_VERS, (void *)&vers);
350 return (kcp->client);
351 }
352 if (!(localhandle = setnetconfig())) {
353 return ((CLIENT *) NULL);
354 }
355 tpconf = NULL;
356 #if defined(__FreeBSD__)
357 if (uname(&u) == -1)
358 #else
359 #if defined(i386)
360 if (_nuname(&u) == -1)
361 #elif defined(sparc)
362 if (_uname(&u) == -1)
363 #else
364 #error Unknown architecture!
365 #endif
366 #endif
367 {
368 endnetconfig(localhandle);
369 return ((CLIENT *) NULL);
370 }
371 while ((nconf = getnetconfig(localhandle)) != NULL) {
372 if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
373 /*
374 * We use COTS_ORD here so that the caller can
375 * find out immediately if the server is dead.
376 */
377 if (nconf->nc_semantics == NC_TPI_COTS_ORD) {
378 kcp->client = clnt_tp_create(u.nodename,
379 KEY_PROG, vers, nconf);
380 if (kcp->client)
381 break;
382 } else {
383 tpconf = nconf;
384 }
385 }
386 }
387 if ((kcp->client == (CLIENT *) NULL) && (tpconf))
388 /* Now, try the CLTS or COTS loopback transport */
389 kcp->client = clnt_tp_create(u.nodename,
390 KEY_PROG, vers, tpconf);
391 endnetconfig(localhandle);
392
393 if (kcp->client == (CLIENT *) NULL) {
394 return ((CLIENT *) NULL);
395 }
396 kcp->uid = geteuid();
397 kcp->pid = getpid();
398 kcp->client->cl_auth = authsys_create("", kcp->uid, 0, 0, NULL);
399 if (kcp->client->cl_auth == NULL) {
400 clnt_destroy(kcp->client);
401 kcp->client = NULL;
402 return ((CLIENT *) NULL);
403 }
404
405 wait_time.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES;
406 wait_time.tv_usec = 0;
407 (void) clnt_control(kcp->client, CLSET_RETRY_TIMEOUT,
408 (char *)&wait_time);
409 if (clnt_control(kcp->client, CLGET_FD, (char *)&fd))
410 _fcntl(fd, F_SETFD, 1); /* make it "close on exec" */
411
412 return (kcp->client);
413 }
414
415 /* returns 0 on failure, 1 on success */
416
417 static int
key_call(u_long proc,xdrproc_t xdr_arg,void * arg,xdrproc_t xdr_rslt,void * rslt)418 key_call(u_long proc, xdrproc_t xdr_arg, void *arg, xdrproc_t xdr_rslt,
419 void *rslt)
420 {
421 CLIENT *clnt;
422 struct timeval wait_time;
423
424 if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) {
425 cryptkeyres *res;
426 res = (*__key_encryptsession_pk_LOCAL)(geteuid(), arg);
427 *(cryptkeyres*)rslt = *res;
428 return (1);
429 } else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) {
430 cryptkeyres *res;
431 res = (*__key_decryptsession_pk_LOCAL)(geteuid(), arg);
432 *(cryptkeyres*)rslt = *res;
433 return (1);
434 } else if (proc == KEY_GEN && __key_gendes_LOCAL) {
435 des_block *res;
436 res = (*__key_gendes_LOCAL)(geteuid(), 0);
437 *(des_block*)rslt = *res;
438 return (1);
439 }
440
441 if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) ||
442 (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) ||
443 (proc == KEY_GET_CONV))
444 clnt = getkeyserv_handle(2); /* talk to version 2 */
445 else
446 clnt = getkeyserv_handle(1); /* talk to version 1 */
447
448 if (clnt == NULL) {
449 return (0);
450 }
451
452 wait_time.tv_sec = TOTAL_TIMEOUT;
453 wait_time.tv_usec = 0;
454
455 if (clnt_call(clnt, proc, xdr_arg, arg, xdr_rslt, rslt,
456 wait_time) == RPC_SUCCESS) {
457 return (1);
458 } else {
459 return (0);
460 }
461 }
462