1 | /* |
---|
2 | * Sun RPC is a product of Sun Microsystems, Inc. and is provided for |
---|
3 | * unrestricted use provided that this legend is included on all tape |
---|
4 | * media and as a part of the software program in whole or part. Users |
---|
5 | * may copy or modify Sun RPC without charge, but are not authorized |
---|
6 | * to license or distribute it to anyone else except as part of a product or |
---|
7 | * program developed by the user. |
---|
8 | * |
---|
9 | * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE |
---|
10 | * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR |
---|
11 | * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. |
---|
12 | * |
---|
13 | * Sun RPC is provided with no support and without any obligation on the |
---|
14 | * part of Sun Microsystems, Inc. to assist in its use, correction, |
---|
15 | * modification or enhancement. |
---|
16 | * |
---|
17 | * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE |
---|
18 | * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC |
---|
19 | * OR ANY PART THEREOF. |
---|
20 | * |
---|
21 | * In no event will Sun Microsystems, Inc. be liable for any lost revenue |
---|
22 | * or profits or other special, indirect and consequential damages, even if |
---|
23 | * Sun has been advised of the possibility of such damages. |
---|
24 | * |
---|
25 | * Sun Microsystems, Inc. |
---|
26 | * 2550 Garcia Avenue |
---|
27 | * Mountain View, California 94043 |
---|
28 | */ |
---|
29 | /* |
---|
30 | * Copyright (c) 1986-1991 by Sun Microsystems Inc. |
---|
31 | * |
---|
32 | * $FreeBSD: src/lib/libc/rpc/key_call.c,v 1.3 2000/01/27 23:06:39 jasone Exp $ |
---|
33 | */ |
---|
34 | |
---|
35 | #ident "@(#)key_call.c 1.25 94/04/24 SMI" |
---|
36 | |
---|
37 | /* |
---|
38 | * key_call.c, 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 <stdio.h> |
---|
47 | #include <stdlib.h> |
---|
48 | #include <unistd.h> |
---|
49 | #include <errno.h> |
---|
50 | #include <rpc/rpc.h> |
---|
51 | #include <rpc/auth.h> |
---|
52 | #include <rpc/auth_unix.h> |
---|
53 | #include <rpc/key_prot.h> |
---|
54 | #include <string.h> |
---|
55 | #include <sys/utsname.h> |
---|
56 | #include <stdlib.h> |
---|
57 | #include <signal.h> |
---|
58 | #include <sys/wait.h> |
---|
59 | #include <sys/fcntl.h> |
---|
60 | |
---|
61 | |
---|
62 | #define KEY_TIMEOUT 5 /* per-try timeout in seconds */ |
---|
63 | #define KEY_NRETRY 12 /* number of retries */ |
---|
64 | |
---|
65 | #ifdef DEBUG |
---|
66 | #define debug(msg) (void) fprintf(stderr, "%s\n", msg); |
---|
67 | #else |
---|
68 | #define debug(msg) |
---|
69 | #endif /* DEBUG */ |
---|
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 | cryptkeyres *(*__key_encryptsession_pk_LOCAL)() = 0; |
---|
81 | cryptkeyres *(*__key_decryptsession_pk_LOCAL)() = 0; |
---|
82 | des_block *(*__key_gendes_LOCAL)() = 0; |
---|
83 | |
---|
84 | static int key_call __P(( u_long, xdrproc_t, char *, xdrproc_t, char * )); |
---|
85 | |
---|
86 | int |
---|
87 | key_setsecret(secretkey) |
---|
88 | const char *secretkey; |
---|
89 | { |
---|
90 | keystatus status; |
---|
91 | |
---|
92 | if (!key_call((u_long) KEY_SET, xdr_keybuf, (char *) secretkey, |
---|
93 | xdr_keystatus, (char *)&status)) { |
---|
94 | return (-1); |
---|
95 | } |
---|
96 | if (status != KEY_SUCCESS) { |
---|
97 | debug("set status is nonzero"); |
---|
98 | return (-1); |
---|
99 | } |
---|
100 | return (0); |
---|
101 | } |
---|
102 | |
---|
103 | |
---|
104 | /* key_secretkey_is_set() returns 1 if the keyserver has a secret key |
---|
105 | * stored for the caller's effective uid; it returns 0 otherwise |
---|
106 | * |
---|
107 | * N.B.: The KEY_NET_GET key call is undocumented. Applications shouldn't |
---|
108 | * be using it, because it allows them to get the user's secret key. |
---|
109 | */ |
---|
110 | |
---|
111 | int |
---|
112 | key_secretkey_is_set(void) |
---|
113 | { |
---|
114 | struct key_netstres kres; |
---|
115 | |
---|
116 | memset((void*)&kres, 0, sizeof (kres)); |
---|
117 | if (key_call((u_long) KEY_NET_GET, xdr_void, (char *)NULL, |
---|
118 | xdr_key_netstres, (char *) &kres) && |
---|
119 | (kres.status == KEY_SUCCESS) && |
---|
120 | (kres.key_netstres_u.knet.st_priv_key[0] != 0)) { |
---|
121 | /* avoid leaving secret key in memory */ |
---|
122 | memset(kres.key_netstres_u.knet.st_priv_key, 0, HEXKEYBYTES); |
---|
123 | return (1); |
---|
124 | } |
---|
125 | return (0); |
---|
126 | } |
---|
127 | |
---|
128 | int |
---|
129 | key_encryptsession_pk(remotename, remotekey, deskey) |
---|
130 | char *remotename; |
---|
131 | netobj *remotekey; |
---|
132 | des_block *deskey; |
---|
133 | { |
---|
134 | cryptkeyarg2 arg; |
---|
135 | cryptkeyres res; |
---|
136 | |
---|
137 | arg.remotename = remotename; |
---|
138 | arg.remotekey = *remotekey; |
---|
139 | arg.deskey = *deskey; |
---|
140 | if (!key_call((u_long)KEY_ENCRYPT_PK, xdr_cryptkeyarg2, (char *)&arg, |
---|
141 | xdr_cryptkeyres, (char *)&res)) { |
---|
142 | return (-1); |
---|
143 | } |
---|
144 | if (res.status != KEY_SUCCESS) { |
---|
145 | debug("encrypt status is nonzero"); |
---|
146 | return (-1); |
---|
147 | } |
---|
148 | *deskey = res.cryptkeyres_u.deskey; |
---|
149 | return (0); |
---|
150 | } |
---|
151 | |
---|
152 | int |
---|
153 | key_decryptsession_pk(remotename, remotekey, deskey) |
---|
154 | char *remotename; |
---|
155 | netobj *remotekey; |
---|
156 | 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, xdr_cryptkeyarg2, (char *)&arg, |
---|
165 | xdr_cryptkeyres, (char *)&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 |
---|
177 | key_encryptsession(remotename, deskey) |
---|
178 | const char *remotename; |
---|
179 | des_block *deskey; |
---|
180 | { |
---|
181 | cryptkeyarg arg; |
---|
182 | cryptkeyres res; |
---|
183 | |
---|
184 | arg.remotename = (char *) remotename; |
---|
185 | arg.deskey = *deskey; |
---|
186 | if (!key_call((u_long)KEY_ENCRYPT, xdr_cryptkeyarg, (char *)&arg, |
---|
187 | xdr_cryptkeyres, (char *)&res)) { |
---|
188 | return (-1); |
---|
189 | } |
---|
190 | if (res.status != KEY_SUCCESS) { |
---|
191 | debug("encrypt status is nonzero"); |
---|
192 | return (-1); |
---|
193 | } |
---|
194 | *deskey = res.cryptkeyres_u.deskey; |
---|
195 | return (0); |
---|
196 | } |
---|
197 | |
---|
198 | int |
---|
199 | key_decryptsession(remotename, deskey) |
---|
200 | const char *remotename; |
---|
201 | des_block *deskey; |
---|
202 | { |
---|
203 | cryptkeyarg arg; |
---|
204 | cryptkeyres res; |
---|
205 | |
---|
206 | arg.remotename = (char *) remotename; |
---|
207 | arg.deskey = *deskey; |
---|
208 | if (!key_call((u_long)KEY_DECRYPT, xdr_cryptkeyarg, (char *)&arg, |
---|
209 | xdr_cryptkeyres, (char *)&res)) { |
---|
210 | return (-1); |
---|
211 | } |
---|
212 | if (res.status != KEY_SUCCESS) { |
---|
213 | debug("decrypt status is nonzero"); |
---|
214 | return (-1); |
---|
215 | } |
---|
216 | *deskey = res.cryptkeyres_u.deskey; |
---|
217 | return (0); |
---|
218 | } |
---|
219 | |
---|
220 | int |
---|
221 | key_gendes(key) |
---|
222 | des_block *key; |
---|
223 | { |
---|
224 | if (!key_call((u_long)KEY_GEN, xdr_void, (char *)NULL, |
---|
225 | xdr_des_block, (char *)key)) { |
---|
226 | return (-1); |
---|
227 | } |
---|
228 | return (0); |
---|
229 | } |
---|
230 | |
---|
231 | int |
---|
232 | key_setnet(arg) |
---|
233 | struct netstarg *arg; |
---|
234 | { |
---|
235 | keystatus status; |
---|
236 | |
---|
237 | |
---|
238 | if (!key_call((u_long) KEY_NET_PUT, xdr_key_netstarg, (char *) arg, |
---|
239 | xdr_keystatus, (char *) &status)){ |
---|
240 | return (-1); |
---|
241 | } |
---|
242 | |
---|
243 | if (status != KEY_SUCCESS) { |
---|
244 | debug("key_setnet status is nonzero"); |
---|
245 | return (-1); |
---|
246 | } |
---|
247 | return (1); |
---|
248 | } |
---|
249 | |
---|
250 | |
---|
251 | int |
---|
252 | key_get_conv(pkey, deskey) |
---|
253 | char *pkey; |
---|
254 | des_block *deskey; |
---|
255 | { |
---|
256 | cryptkeyres res; |
---|
257 | |
---|
258 | if (!key_call((u_long) KEY_GET_CONV, xdr_keybuf, pkey, |
---|
259 | xdr_cryptkeyres, (char *)&res)) { |
---|
260 | return (-1); |
---|
261 | } |
---|
262 | if (res.status != KEY_SUCCESS) { |
---|
263 | debug("get_conv status is nonzero"); |
---|
264 | return (-1); |
---|
265 | } |
---|
266 | *deskey = res.cryptkeyres_u.deskey; |
---|
267 | return (0); |
---|
268 | } |
---|
269 | |
---|
270 | struct key_call_private { |
---|
271 | CLIENT *client; /* Client handle */ |
---|
272 | pid_t pid; /* process-id at moment of creation */ |
---|
273 | uid_t uid; /* user-id at last authorization */ |
---|
274 | }; |
---|
275 | static struct key_call_private *key_call_private_main = NULL; |
---|
276 | |
---|
277 | #ifdef foo |
---|
278 | static void |
---|
279 | key_call_destroy(void *vp) |
---|
280 | { |
---|
281 | register struct key_call_private *kcp = (struct key_call_private *)vp; |
---|
282 | |
---|
283 | if (kcp) { |
---|
284 | if (kcp->client) |
---|
285 | clnt_destroy(kcp->client); |
---|
286 | free(kcp); |
---|
287 | } |
---|
288 | } |
---|
289 | #endif |
---|
290 | |
---|
291 | /* |
---|
292 | * Keep the handle cached. This call may be made quite often. |
---|
293 | */ |
---|
294 | static CLIENT * |
---|
295 | getkeyserv_handle(vers) |
---|
296 | int vers; |
---|
297 | { |
---|
298 | struct key_call_private *kcp = key_call_private_main; |
---|
299 | struct timeval wait_time; |
---|
300 | int fd; |
---|
301 | struct sockaddr_un name; |
---|
302 | int namelen = sizeof(struct sockaddr_un); |
---|
303 | |
---|
304 | #define TOTAL_TIMEOUT 30 /* total timeout talking to keyserver */ |
---|
305 | #define TOTAL_TRIES 5 /* Number of tries */ |
---|
306 | |
---|
307 | if (kcp == (struct key_call_private *)NULL) { |
---|
308 | kcp = (struct key_call_private *)malloc(sizeof (*kcp)); |
---|
309 | if (kcp == (struct key_call_private *)NULL) { |
---|
310 | return ((CLIENT *) NULL); |
---|
311 | } |
---|
312 | key_call_private_main = kcp; |
---|
313 | kcp->client = NULL; |
---|
314 | } |
---|
315 | |
---|
316 | /* if pid has changed, destroy client and rebuild */ |
---|
317 | if (kcp->client != NULL && kcp->pid != getpid()) { |
---|
318 | clnt_destroy(kcp->client); |
---|
319 | kcp->client = NULL; |
---|
320 | } |
---|
321 | |
---|
322 | if (kcp->client != NULL) { |
---|
323 | /* if other side closed socket, build handle again */ |
---|
324 | clnt_control(kcp->client, CLGET_FD, (char *)&fd); |
---|
325 | if (getpeername(fd,(struct sockaddr *)&name,&namelen) == -1) { |
---|
326 | auth_destroy(kcp->client->cl_auth); |
---|
327 | clnt_destroy(kcp->client); |
---|
328 | kcp->client = NULL; |
---|
329 | } |
---|
330 | } |
---|
331 | |
---|
332 | if (kcp->client != NULL) { |
---|
333 | /* if uid has changed, build client handle again */ |
---|
334 | if (kcp->uid != geteuid()) { |
---|
335 | kcp->uid = geteuid(); |
---|
336 | auth_destroy(kcp->client->cl_auth); |
---|
337 | kcp->client->cl_auth = |
---|
338 | authsys_create("", kcp->uid, 0, 0, NULL); |
---|
339 | if (kcp->client->cl_auth == NULL) { |
---|
340 | clnt_destroy(kcp->client); |
---|
341 | kcp->client = NULL; |
---|
342 | return ((CLIENT *) NULL); |
---|
343 | } |
---|
344 | } |
---|
345 | /* Change the version number to the new one */ |
---|
346 | clnt_control(kcp->client, CLSET_VERS, (void *)&vers); |
---|
347 | return (kcp->client); |
---|
348 | } |
---|
349 | |
---|
350 | if ((kcp->client == (CLIENT *) NULL)) |
---|
351 | /* Use the AF_UNIX transport */ |
---|
352 | kcp->client = clnt_create("/var/run/keyservsock", KEY_PROG, |
---|
353 | vers, "unix"); |
---|
354 | |
---|
355 | if (kcp->client == (CLIENT *) NULL) { |
---|
356 | return ((CLIENT *) NULL); |
---|
357 | } |
---|
358 | kcp->uid = geteuid(); |
---|
359 | kcp->pid = getpid(); |
---|
360 | kcp->client->cl_auth = authsys_create("", kcp->uid, 0, 0, NULL); |
---|
361 | if (kcp->client->cl_auth == NULL) { |
---|
362 | clnt_destroy(kcp->client); |
---|
363 | kcp->client = NULL; |
---|
364 | return ((CLIENT *) NULL); |
---|
365 | } |
---|
366 | |
---|
367 | wait_time.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES; |
---|
368 | wait_time.tv_usec = 0; |
---|
369 | (void) clnt_control(kcp->client, CLSET_RETRY_TIMEOUT, |
---|
370 | (char *)&wait_time); |
---|
371 | if (clnt_control(kcp->client, CLGET_FD, (char *)&fd)) |
---|
372 | _fcntl(fd, F_SETFD, 1); /* make it "close on exec" */ |
---|
373 | |
---|
374 | return (kcp->client); |
---|
375 | } |
---|
376 | |
---|
377 | /* returns 0 on failure, 1 on success */ |
---|
378 | |
---|
379 | static int |
---|
380 | key_call(proc, xdr_arg, arg, xdr_rslt, rslt) |
---|
381 | u_long proc; |
---|
382 | xdrproc_t xdr_arg; |
---|
383 | char *arg; |
---|
384 | xdrproc_t xdr_rslt; |
---|
385 | char *rslt; |
---|
386 | { |
---|
387 | CLIENT *clnt; |
---|
388 | struct timeval wait_time; |
---|
389 | |
---|
390 | if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) { |
---|
391 | cryptkeyres *res; |
---|
392 | res = (*__key_encryptsession_pk_LOCAL)(geteuid(), arg); |
---|
393 | *(cryptkeyres*)rslt = *res; |
---|
394 | return (1); |
---|
395 | } else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) { |
---|
396 | cryptkeyres *res; |
---|
397 | res = (*__key_decryptsession_pk_LOCAL)(geteuid(), arg); |
---|
398 | *(cryptkeyres*)rslt = *res; |
---|
399 | return (1); |
---|
400 | } else if (proc == KEY_GEN && __key_gendes_LOCAL) { |
---|
401 | des_block *res; |
---|
402 | res = (*__key_gendes_LOCAL)(geteuid(), 0); |
---|
403 | *(des_block*)rslt = *res; |
---|
404 | return (1); |
---|
405 | } |
---|
406 | |
---|
407 | if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) || |
---|
408 | (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) || |
---|
409 | (proc == KEY_GET_CONV)) |
---|
410 | clnt = getkeyserv_handle(2); /* talk to version 2 */ |
---|
411 | else |
---|
412 | clnt = getkeyserv_handle(1); /* talk to version 1 */ |
---|
413 | |
---|
414 | if (clnt == NULL) { |
---|
415 | return (0); |
---|
416 | } |
---|
417 | |
---|
418 | wait_time.tv_sec = TOTAL_TIMEOUT; |
---|
419 | wait_time.tv_usec = 0; |
---|
420 | |
---|
421 | if (clnt_call(clnt, proc, xdr_arg, arg, xdr_rslt, rslt, |
---|
422 | wait_time) == RPC_SUCCESS) { |
---|
423 | return (1); |
---|
424 | } else { |
---|
425 | return (0); |
---|
426 | } |
---|
427 | } |
---|