Update.
[glibc.git] / sunrpc / key_call.c
blobba1c2638fb320015f076c5c0769e82c2dceae0ca
1 /*
2 * Copyright (c) 1988 by Sun Microsystems, Inc.
3 */
4 /*
5 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
6 * unrestricted use provided that this legend is included on all tape
7 * media and as a part of the software program in whole or part. Users
8 * may copy or modify Sun RPC without charge, but are not authorized
9 * to license or distribute it to anyone else except as part of a product or
10 * program developed by the user.
12 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
13 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
14 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
16 * Sun RPC is provided with no support and without any obligation on the
17 * part of Sun Microsystems, Inc. to assist in its use, correction,
18 * modification or enhancement.
20 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
21 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
22 * OR ANY PART THEREOF.
24 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
25 * or profits or other special, indirect and consequential damages, even if
26 * Sun has been advised of the possibility of such damages.
28 * Sun Microsystems, Inc.
29 * 2550 Garcia Avenue
30 * Mountain View, California 94043
34 * The original source is from the RPCSRC 4.0 package from Sun Microsystems.
35 * The Interface to keyserver protocoll 2 was added by
36 * Thorsten Kukuk <kukuk@vt.uni-paderborn.de>
39 #include <stdio.h>
40 #include <signal.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <rpc/rpc.h>
44 #include <rpc/auth.h>
45 #include <sys/wait.h>
46 #include <sys/param.h>
47 #include <sys/socket.h>
48 #include <rpc/key_prot.h>
50 #define KEY_TIMEOUT 5 /* per-try timeout in seconds */
51 #define KEY_NRETRY 12 /* number of retries */
53 #define debug(msg) /* turn off debugging */
55 extern int _openchild (char *command, FILE ** fto, FILE ** ffrom);
58 static int key_call (u_long, xdrproc_t xdr_arg, char *,
59 xdrproc_t xdr_rslt, char *);
61 static struct timeval trytimeout = {KEY_TIMEOUT, 0};
62 static struct timeval tottimeout = {KEY_TIMEOUT * KEY_NRETRY, 0};
64 int
65 key_setsecret (char *secretkey)
67 keystatus status;
69 if (!key_call ((u_long) KEY_SET, (xdrproc_t) xdr_keybuf, secretkey,
70 (xdrproc_t) xdr_keystatus, (char *) &status))
71 return -1;
72 if (status != KEY_SUCCESS)
74 debug ("set status is nonzero");
75 return -1;
77 return 0;
80 /* key_secretkey_is_set() returns 1 if the keyserver has a secret key
81 * stored for the caller's effective uid; it returns 0 otherwise
83 * N.B.: The KEY_NET_GET key call is undocumented. Applications shouldn't
84 * be using it, because it allows them to get the user's secret key.
86 int
87 key_secretkey_is_set (void)
89 struct key_netstres kres;
91 memset (&kres, 0, sizeof (kres));
92 if (key_call ((u_long) KEY_NET_GET, (xdrproc_t) xdr_void, (char *) NULL,
93 (xdrproc_t) xdr_key_netstres, (char *) &kres) &&
94 (kres.status == KEY_SUCCESS) &&
95 (kres.key_netstres_u.knet.st_priv_key[0] != 0))
97 /* avoid leaving secret key in memory */
98 memset (kres.key_netstres_u.knet.st_priv_key, 0, HEXKEYBYTES);
99 return 1;
101 return 0;
105 key_encryptsession (char *remotename, des_block * deskey)
107 cryptkeyarg arg;
108 cryptkeyres res;
110 arg.remotename = remotename;
111 arg.deskey = *deskey;
112 if (!key_call ((u_long) KEY_ENCRYPT, (xdrproc_t) xdr_cryptkeyarg,
113 (char *) &arg, (xdrproc_t) xdr_cryptkeyres, (char *) &res))
114 return -1;
116 if (res.status != KEY_SUCCESS)
118 debug ("encrypt status is nonzero");
119 return -1;
121 *deskey = res.cryptkeyres_u.deskey;
122 return 0;
126 key_decryptsession (char *remotename, des_block * deskey)
128 cryptkeyarg arg;
129 cryptkeyres res;
131 arg.remotename = remotename;
132 arg.deskey = *deskey;
133 if (!key_call ((u_long) KEY_DECRYPT, (xdrproc_t) xdr_cryptkeyarg,
134 (char *) &arg, (xdrproc_t) xdr_cryptkeyres, (char *) &res))
135 return -1;
136 if (res.status != KEY_SUCCESS)
138 debug ("decrypt status is nonzero");
139 return -1;
141 *deskey = res.cryptkeyres_u.deskey;
142 return 0;
146 key_encryptsession_pk (char *remotename, netobj * remotekey,
147 des_block * deskey)
149 cryptkeyarg2 arg;
150 cryptkeyres res;
152 arg.remotename = remotename;
153 arg.remotekey = *remotekey;
154 arg.deskey = *deskey;
155 if (!key_call ((u_long) KEY_ENCRYPT_PK, (xdrproc_t) xdr_cryptkeyarg2,
156 (char *) &arg, (xdrproc_t) xdr_cryptkeyres, (char *) &res))
157 return -1;
159 if (res.status != KEY_SUCCESS)
161 debug ("encrypt status is nonzero");
162 return -1;
164 *deskey = res.cryptkeyres_u.deskey;
165 return 0;
169 key_decryptsession_pk (char *remotename, netobj * remotekey,
170 des_block * deskey)
172 cryptkeyarg2 arg;
173 cryptkeyres res;
175 arg.remotename = remotename;
176 arg.remotekey = *remotekey;
177 arg.deskey = *deskey;
178 if (!key_call ((u_long) KEY_DECRYPT_PK, (xdrproc_t) xdr_cryptkeyarg2,
179 (char *) &arg, (xdrproc_t) xdr_cryptkeyres, (char *) &res))
180 return -1;
182 if (res.status != KEY_SUCCESS)
184 debug ("decrypt status is nonzero");
185 return -1;
187 *deskey = res.cryptkeyres_u.deskey;
188 return 0;
192 key_gendes (des_block * key)
194 struct sockaddr_in sin;
195 CLIENT *client;
196 int socket;
197 enum clnt_stat stat;
199 sin.sin_family = AF_INET;
200 sin.sin_port = 0;
201 sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
202 bzero (sin.sin_zero, sizeof (sin.sin_zero));
203 socket = RPC_ANYSOCK;
204 client = clntudp_bufcreate (&sin, (u_long) KEY_PROG, (u_long) KEY_VERS,
205 trytimeout, &socket, RPCSMALLMSGSIZE,
206 RPCSMALLMSGSIZE);
207 if (client == NULL)
208 return -1;
210 stat = clnt_call (client, KEY_GEN, (xdrproc_t) xdr_void, NULL,
211 (xdrproc_t) xdr_des_block, (caddr_t) key, tottimeout);
212 clnt_destroy (client);
213 close (socket);
214 if (stat != RPC_SUCCESS)
215 return -1;
217 return 0;
221 key_setnet (struct key_netstarg *arg)
223 keystatus status;
225 if (!key_call ((u_long) KEY_NET_PUT, (xdrproc_t) xdr_key_netstarg,
226 (char *) arg,(xdrproc_t) xdr_keystatus, (char *) &status))
227 return -1;
229 if (status != KEY_SUCCESS)
231 debug ("key_setnet status is nonzero");
232 return -1;
234 return 1;
238 key_get_conv (char *pkey, des_block * deskey)
240 cryptkeyres res;
242 if (!key_call ((u_long) KEY_GET_CONV, (xdrproc_t) xdr_keybuf, pkey,
243 (xdrproc_t) xdr_cryptkeyres, (char *) &res))
244 return -1;
246 if (res.status != KEY_SUCCESS)
248 debug ("get_conv status is nonzero");
249 return -1;
251 *deskey = res.cryptkeyres_u.deskey;
252 return 0;
256 * Hack to allow the keyserver to use AUTH_DES (for authenticated
257 * NIS+ calls, for example). The only functions that get called
258 * are key_encryptsession_pk, key_decryptsession_pk, and key_gendes.
260 * The approach is to have the keyserver fill in pointers to local
261 * implementations of these functions, and to call those in key_call().
264 cryptkeyres *(*__key_encryptsession_pk_LOCAL) (uid_t, char *) = 0;
265 cryptkeyres *(*__key_decryptsession_pk_LOCAL) (uid_t, char *) = 0;
266 des_block *(*__key_gendes_LOCAL) (uid_t, char *) = 0;
268 static int
269 key_call (u_long proc, xdrproc_t xdr_arg, char *arg,
270 xdrproc_t xdr_rslt, char *rslt)
272 XDR xdrargs;
273 XDR xdrrslt;
274 FILE *fargs;
275 FILE *frslt;
276 void (*osigchild) (int);
277 union wait status;
278 int pid;
279 int success;
280 uid_t ruid;
281 uid_t euid;
282 static char MESSENGER[] = "/usr/etc/keyenvoy";
284 success = 1;
285 osigchild = signal (SIGCHLD, SIG_IGN);
287 if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL)
289 cryptkeyres *res;
290 res = (*__key_encryptsession_pk_LOCAL) (geteuid (), arg);
291 *(cryptkeyres *) rslt = *res;
292 return 1;
294 else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL)
296 cryptkeyres *res;
297 res = (*__key_decryptsession_pk_LOCAL) (geteuid (), arg);
298 *(cryptkeyres *) rslt = *res;
299 return 1;
301 else if (proc == KEY_GEN && __key_gendes_LOCAL)
303 des_block *res;
304 res = (*__key_gendes_LOCAL) (geteuid (), 0);
305 *(des_block *) rslt = *res;
306 return 1;
310 * We are going to exec a set-uid program which makes our effective uid
311 * zero, and authenticates us with our real uid. We need to make the
312 * effective uid be the real uid for the setuid program, and
313 * the real uid be the effective uid so that we can change things back.
315 euid = geteuid ();
316 ruid = getuid ();
317 setreuid (euid, ruid);
318 pid = _openchild (MESSENGER, &fargs, &frslt);
319 setreuid (ruid, euid);
320 if (pid < 0)
322 debug ("open_streams");
323 return (0);
325 xdrstdio_create (&xdrargs, fargs, XDR_ENCODE);
326 xdrstdio_create (&xdrrslt, frslt, XDR_DECODE);
328 if (!xdr_u_long (&xdrargs, &proc) || !(*xdr_arg) (&xdrargs, arg))
330 debug ("xdr args");
331 success = 0;
333 fclose (fargs);
335 if (success && !(*xdr_rslt) (&xdrrslt, rslt))
337 debug ("xdr rslt");
338 success = 0;
341 #ifdef NOTDEF
343 * WARNING! XXX
344 * The original code appears first. wait4 returns only after the process
345 * with the requested pid terminates. The effect of using wait() instead
346 * has not been determined.
348 fclose (frslt);
349 if (wait4 (pid, &status, 0, NULL) < 0 || status.w_retcode != 0)
351 debug ("wait4");
352 success = 0;
354 #endif /* def NOTDEF */
355 if (wait (&status) < 0 || status.w_retcode != 0)
357 debug ("wait");
358 success = 0;
360 signal (SIGCHLD, osigchild);
362 return (success);