1 | #include <machine/rtems-bsd-user-space.h> |
---|
2 | |
---|
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)() = 0; |
---|
87 | cryptkeyres *(*__key_decryptsession_pk_LOCAL)() = 0; |
---|
88 | des_block *(*__key_gendes_LOCAL)() = 0; |
---|
89 | |
---|
90 | static int key_call( u_long, xdrproc_t, void *, xdrproc_t, void *); |
---|
91 | |
---|
92 | int |
---|
93 | key_setsecret(secretkey) |
---|
94 | const char *secretkey; |
---|
95 | { |
---|
96 | keystatus status; |
---|
97 | |
---|
98 | if (!key_call((u_long) KEY_SET, (xdrproc_t)xdr_keybuf, |
---|
99 | (void *)secretkey, |
---|
100 | (xdrproc_t)xdr_keystatus, &status)) { |
---|
101 | return (-1); |
---|
102 | } |
---|
103 | if (status != KEY_SUCCESS) { |
---|
104 | debug("set status is nonzero"); |
---|
105 | return (-1); |
---|
106 | } |
---|
107 | return (0); |
---|
108 | } |
---|
109 | |
---|
110 | |
---|
111 | /* key_secretkey_is_set() returns 1 if the keyserver has a secret key |
---|
112 | * stored for the caller's effective uid; it returns 0 otherwise |
---|
113 | * |
---|
114 | * N.B.: The KEY_NET_GET key call is undocumented. Applications shouldn't |
---|
115 | * be using it, because it allows them to get the user's secret key. |
---|
116 | */ |
---|
117 | |
---|
118 | int |
---|
119 | key_secretkey_is_set(void) |
---|
120 | { |
---|
121 | struct key_netstres kres; |
---|
122 | |
---|
123 | memset((void*)&kres, 0, sizeof (kres)); |
---|
124 | if (key_call((u_long) KEY_NET_GET, (xdrproc_t)xdr_void, NULL, |
---|
125 | (xdrproc_t)xdr_key_netstres, &kres) && |
---|
126 | (kres.status == KEY_SUCCESS) && |
---|
127 | (kres.key_netstres_u.knet.st_priv_key[0] != 0)) { |
---|
128 | /* avoid leaving secret key in memory */ |
---|
129 | memset(kres.key_netstres_u.knet.st_priv_key, 0, HEXKEYBYTES); |
---|
130 | return (1); |
---|
131 | } |
---|
132 | return (0); |
---|
133 | } |
---|
134 | |
---|
135 | int |
---|
136 | key_encryptsession_pk(remotename, remotekey, deskey) |
---|
137 | char *remotename; |
---|
138 | netobj *remotekey; |
---|
139 | des_block *deskey; |
---|
140 | { |
---|
141 | cryptkeyarg2 arg; |
---|
142 | cryptkeyres res; |
---|
143 | |
---|
144 | arg.remotename = remotename; |
---|
145 | arg.remotekey = *remotekey; |
---|
146 | arg.deskey = *deskey; |
---|
147 | if (!key_call((u_long)KEY_ENCRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg, |
---|
148 | (xdrproc_t)xdr_cryptkeyres, &res)) { |
---|
149 | return (-1); |
---|
150 | } |
---|
151 | if (res.status != KEY_SUCCESS) { |
---|
152 | debug("encrypt status is nonzero"); |
---|
153 | return (-1); |
---|
154 | } |
---|
155 | *deskey = res.cryptkeyres_u.deskey; |
---|
156 | return (0); |
---|
157 | } |
---|
158 | |
---|
159 | int |
---|
160 | key_decryptsession_pk(remotename, remotekey, deskey) |
---|
161 | char *remotename; |
---|
162 | netobj *remotekey; |
---|
163 | des_block *deskey; |
---|
164 | { |
---|
165 | cryptkeyarg2 arg; |
---|
166 | cryptkeyres res; |
---|
167 | |
---|
168 | arg.remotename = remotename; |
---|
169 | arg.remotekey = *remotekey; |
---|
170 | arg.deskey = *deskey; |
---|
171 | if (!key_call((u_long)KEY_DECRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg, |
---|
172 | (xdrproc_t)xdr_cryptkeyres, &res)) { |
---|
173 | return (-1); |
---|
174 | } |
---|
175 | if (res.status != KEY_SUCCESS) { |
---|
176 | debug("decrypt status is nonzero"); |
---|
177 | return (-1); |
---|
178 | } |
---|
179 | *deskey = res.cryptkeyres_u.deskey; |
---|
180 | return (0); |
---|
181 | } |
---|
182 | |
---|
183 | int |
---|
184 | key_encryptsession(remotename, deskey) |
---|
185 | const char *remotename; |
---|
186 | des_block *deskey; |
---|
187 | { |
---|
188 | cryptkeyarg arg; |
---|
189 | cryptkeyres res; |
---|
190 | |
---|
191 | arg.remotename = (char *) remotename; |
---|
192 | arg.deskey = *deskey; |
---|
193 | if (!key_call((u_long)KEY_ENCRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg, |
---|
194 | (xdrproc_t)xdr_cryptkeyres, &res)) { |
---|
195 | return (-1); |
---|
196 | } |
---|
197 | if (res.status != KEY_SUCCESS) { |
---|
198 | debug("encrypt status is nonzero"); |
---|
199 | return (-1); |
---|
200 | } |
---|
201 | *deskey = res.cryptkeyres_u.deskey; |
---|
202 | return (0); |
---|
203 | } |
---|
204 | |
---|
205 | int |
---|
206 | key_decryptsession(remotename, deskey) |
---|
207 | const char *remotename; |
---|
208 | des_block *deskey; |
---|
209 | { |
---|
210 | cryptkeyarg arg; |
---|
211 | cryptkeyres res; |
---|
212 | |
---|
213 | arg.remotename = (char *) remotename; |
---|
214 | arg.deskey = *deskey; |
---|
215 | if (!key_call((u_long)KEY_DECRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg, |
---|
216 | (xdrproc_t)xdr_cryptkeyres, &res)) { |
---|
217 | return (-1); |
---|
218 | } |
---|
219 | if (res.status != KEY_SUCCESS) { |
---|
220 | debug("decrypt status is nonzero"); |
---|
221 | return (-1); |
---|
222 | } |
---|
223 | *deskey = res.cryptkeyres_u.deskey; |
---|
224 | return (0); |
---|
225 | } |
---|
226 | |
---|
227 | int |
---|
228 | key_gendes(key) |
---|
229 | des_block *key; |
---|
230 | { |
---|
231 | if (!key_call((u_long)KEY_GEN, (xdrproc_t)xdr_void, NULL, |
---|
232 | (xdrproc_t)xdr_des_block, key)) { |
---|
233 | return (-1); |
---|
234 | } |
---|
235 | return (0); |
---|
236 | } |
---|
237 | |
---|
238 | int |
---|
239 | key_setnet(arg) |
---|
240 | struct key_netstarg *arg; |
---|
241 | { |
---|
242 | keystatus status; |
---|
243 | |
---|
244 | |
---|
245 | if (!key_call((u_long) KEY_NET_PUT, (xdrproc_t)xdr_key_netstarg, arg, |
---|
246 | (xdrproc_t)xdr_keystatus, &status)){ |
---|
247 | return (-1); |
---|
248 | } |
---|
249 | |
---|
250 | if (status != KEY_SUCCESS) { |
---|
251 | debug("key_setnet status is nonzero"); |
---|
252 | return (-1); |
---|
253 | } |
---|
254 | return (1); |
---|
255 | } |
---|
256 | |
---|
257 | |
---|
258 | int |
---|
259 | key_get_conv(pkey, deskey) |
---|
260 | char *pkey; |
---|
261 | des_block *deskey; |
---|
262 | { |
---|
263 | cryptkeyres res; |
---|
264 | |
---|
265 | if (!key_call((u_long) KEY_GET_CONV, (xdrproc_t)xdr_keybuf, pkey, |
---|
266 | (xdrproc_t)xdr_cryptkeyres, &res)) { |
---|
267 | return (-1); |
---|
268 | } |
---|
269 | if (res.status != KEY_SUCCESS) { |
---|
270 | debug("get_conv status is nonzero"); |
---|
271 | return (-1); |
---|
272 | } |
---|
273 | *deskey = res.cryptkeyres_u.deskey; |
---|
274 | return (0); |
---|
275 | } |
---|
276 | |
---|
277 | struct key_call_private { |
---|
278 | CLIENT *client; /* Client handle */ |
---|
279 | pid_t pid; /* process-id at moment of creation */ |
---|
280 | uid_t uid; /* user-id at last authorization */ |
---|
281 | }; |
---|
282 | static struct key_call_private *key_call_private_main = NULL; |
---|
283 | static thread_key_t key_call_key; |
---|
284 | static once_t key_call_once = ONCE_INITIALIZER; |
---|
285 | static int key_call_key_error; |
---|
286 | |
---|
287 | static void |
---|
288 | key_call_destroy(void *vp) |
---|
289 | { |
---|
290 | struct key_call_private *kcp = (struct key_call_private *)vp; |
---|
291 | |
---|
292 | if (kcp) { |
---|
293 | if (kcp->client) |
---|
294 | clnt_destroy(kcp->client); |
---|
295 | free(kcp); |
---|
296 | } |
---|
297 | } |
---|
298 | |
---|
299 | static void |
---|
300 | key_call_init(void) |
---|
301 | { |
---|
302 | |
---|
303 | key_call_key_error = thr_keycreate(&key_call_key, key_call_destroy); |
---|
304 | } |
---|
305 | |
---|
306 | /* |
---|
307 | * Keep the handle cached. This call may be made quite often. |
---|
308 | */ |
---|
309 | static CLIENT * |
---|
310 | getkeyserv_handle(vers) |
---|
311 | int vers; |
---|
312 | { |
---|
313 | void *localhandle; |
---|
314 | struct netconfig *nconf; |
---|
315 | struct netconfig *tpconf; |
---|
316 | struct key_call_private *kcp; |
---|
317 | struct timeval wait_time; |
---|
318 | struct utsname u; |
---|
319 | int main_thread; |
---|
320 | int fd; |
---|
321 | |
---|
322 | #define TOTAL_TIMEOUT 30 /* total timeout talking to keyserver */ |
---|
323 | #define TOTAL_TRIES 5 /* Number of tries */ |
---|
324 | |
---|
325 | if ((main_thread = thr_main())) { |
---|
326 | kcp = key_call_private_main; |
---|
327 | } else { |
---|
328 | if (thr_once(&key_call_once, key_call_init) != 0 || |
---|
329 | key_call_key_error != 0) |
---|
330 | return ((CLIENT *) NULL); |
---|
331 | kcp = (struct key_call_private *)thr_getspecific(key_call_key); |
---|
332 | } |
---|
333 | if (kcp == (struct key_call_private *)NULL) { |
---|
334 | kcp = (struct key_call_private *)malloc(sizeof (*kcp)); |
---|
335 | if (kcp == (struct key_call_private *)NULL) { |
---|
336 | return ((CLIENT *) NULL); |
---|
337 | } |
---|
338 | if (main_thread) |
---|
339 | key_call_private_main = kcp; |
---|
340 | else |
---|
341 | thr_setspecific(key_call_key, (void *) kcp); |
---|
342 | kcp->client = NULL; |
---|
343 | } |
---|
344 | |
---|
345 | /* if pid has changed, destroy client and rebuild */ |
---|
346 | if (kcp->client != NULL && kcp->pid != getpid()) { |
---|
347 | clnt_destroy(kcp->client); |
---|
348 | kcp->client = NULL; |
---|
349 | } |
---|
350 | |
---|
351 | if (kcp->client != NULL) { |
---|
352 | /* if uid has changed, build client handle again */ |
---|
353 | if (kcp->uid != geteuid()) { |
---|
354 | kcp->uid = geteuid(); |
---|
355 | auth_destroy(kcp->client->cl_auth); |
---|
356 | kcp->client->cl_auth = |
---|
357 | authsys_create("", kcp->uid, 0, 0, NULL); |
---|
358 | if (kcp->client->cl_auth == NULL) { |
---|
359 | clnt_destroy(kcp->client); |
---|
360 | kcp->client = NULL; |
---|
361 | return ((CLIENT *) NULL); |
---|
362 | } |
---|
363 | } |
---|
364 | /* Change the version number to the new one */ |
---|
365 | clnt_control(kcp->client, CLSET_VERS, (void *)&vers); |
---|
366 | return (kcp->client); |
---|
367 | } |
---|
368 | if (!(localhandle = setnetconfig())) { |
---|
369 | return ((CLIENT *) NULL); |
---|
370 | } |
---|
371 | tpconf = NULL; |
---|
372 | #if defined(__FreeBSD__) |
---|
373 | if (uname(&u) == -1) |
---|
374 | #else |
---|
375 | #if defined(i386) |
---|
376 | if (_nuname(&u) == -1) |
---|
377 | #elif defined(sparc) |
---|
378 | if (_uname(&u) == -1) |
---|
379 | #else |
---|
380 | #error Unknown architecture! |
---|
381 | #endif |
---|
382 | #endif |
---|
383 | { |
---|
384 | endnetconfig(localhandle); |
---|
385 | return ((CLIENT *) NULL); |
---|
386 | } |
---|
387 | while ((nconf = getnetconfig(localhandle)) != NULL) { |
---|
388 | if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { |
---|
389 | /* |
---|
390 | * We use COTS_ORD here so that the caller can |
---|
391 | * find out immediately if the server is dead. |
---|
392 | */ |
---|
393 | if (nconf->nc_semantics == NC_TPI_COTS_ORD) { |
---|
394 | kcp->client = clnt_tp_create(u.nodename, |
---|
395 | KEY_PROG, vers, nconf); |
---|
396 | if (kcp->client) |
---|
397 | break; |
---|
398 | } else { |
---|
399 | tpconf = nconf; |
---|
400 | } |
---|
401 | } |
---|
402 | } |
---|
403 | if ((kcp->client == (CLIENT *) NULL) && (tpconf)) |
---|
404 | /* Now, try the CLTS or COTS loopback transport */ |
---|
405 | kcp->client = clnt_tp_create(u.nodename, |
---|
406 | KEY_PROG, vers, tpconf); |
---|
407 | endnetconfig(localhandle); |
---|
408 | |
---|
409 | if (kcp->client == (CLIENT *) NULL) { |
---|
410 | return ((CLIENT *) NULL); |
---|
411 | } |
---|
412 | kcp->uid = geteuid(); |
---|
413 | kcp->pid = getpid(); |
---|
414 | kcp->client->cl_auth = authsys_create("", kcp->uid, 0, 0, NULL); |
---|
415 | if (kcp->client->cl_auth == NULL) { |
---|
416 | clnt_destroy(kcp->client); |
---|
417 | kcp->client = NULL; |
---|
418 | return ((CLIENT *) NULL); |
---|
419 | } |
---|
420 | |
---|
421 | wait_time.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES; |
---|
422 | wait_time.tv_usec = 0; |
---|
423 | (void) clnt_control(kcp->client, CLSET_RETRY_TIMEOUT, |
---|
424 | (char *)&wait_time); |
---|
425 | if (clnt_control(kcp->client, CLGET_FD, (char *)&fd)) |
---|
426 | _fcntl(fd, F_SETFD, 1); /* make it "close on exec" */ |
---|
427 | |
---|
428 | return (kcp->client); |
---|
429 | } |
---|
430 | |
---|
431 | /* returns 0 on failure, 1 on success */ |
---|
432 | |
---|
433 | static int |
---|
434 | key_call(proc, xdr_arg, arg, xdr_rslt, rslt) |
---|
435 | u_long proc; |
---|
436 | xdrproc_t xdr_arg; |
---|
437 | void *arg; |
---|
438 | xdrproc_t xdr_rslt; |
---|
439 | void *rslt; |
---|
440 | { |
---|
441 | CLIENT *clnt; |
---|
442 | struct timeval wait_time; |
---|
443 | |
---|
444 | if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) { |
---|
445 | cryptkeyres *res; |
---|
446 | res = (*__key_encryptsession_pk_LOCAL)(geteuid(), arg); |
---|
447 | *(cryptkeyres*)rslt = *res; |
---|
448 | return (1); |
---|
449 | } else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) { |
---|
450 | cryptkeyres *res; |
---|
451 | res = (*__key_decryptsession_pk_LOCAL)(geteuid(), arg); |
---|
452 | *(cryptkeyres*)rslt = *res; |
---|
453 | return (1); |
---|
454 | } else if (proc == KEY_GEN && __key_gendes_LOCAL) { |
---|
455 | des_block *res; |
---|
456 | res = (*__key_gendes_LOCAL)(geteuid(), 0); |
---|
457 | *(des_block*)rslt = *res; |
---|
458 | return (1); |
---|
459 | } |
---|
460 | |
---|
461 | if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) || |
---|
462 | (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) || |
---|
463 | (proc == KEY_GET_CONV)) |
---|
464 | clnt = getkeyserv_handle(2); /* talk to version 2 */ |
---|
465 | else |
---|
466 | clnt = getkeyserv_handle(1); /* talk to version 1 */ |
---|
467 | |
---|
468 | if (clnt == NULL) { |
---|
469 | return (0); |
---|
470 | } |
---|
471 | |
---|
472 | wait_time.tv_sec = TOTAL_TIMEOUT; |
---|
473 | wait_time.tv_usec = 0; |
---|
474 | |
---|
475 | if (clnt_call(clnt, proc, xdr_arg, arg, xdr_rslt, rslt, |
---|
476 | wait_time) == RPC_SUCCESS) { |
---|
477 | return (1); |
---|
478 | } else { |
---|
479 | return (0); |
---|
480 | } |
---|
481 | } |
---|