Update.
[glibc.git] / sunrpc / key_call.c
bloba497bc7cad34609d607323e1fcb9f4abd2990f9a
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 <errno.h>
41 #include <signal.h>
42 #include <unistd.h>
43 #include <string.h>
44 #include <rpc/rpc.h>
45 #include <rpc/auth.h>
46 #include <sys/wait.h>
47 #include <sys/param.h>
48 #include <sys/socket.h>
49 #include <rpc/key_prot.h>
51 #define KEY_TIMEOUT 5 /* per-try timeout in seconds */
52 #define KEY_NRETRY 12 /* number of retries */
54 #define debug(msg) /* turn off debugging */
56 extern int _openchild (char *command, FILE **fto, FILE **ffrom);
59 static int key_call (u_long, xdrproc_t xdr_arg, char *,
60 xdrproc_t xdr_rslt, char *) internal_function;
62 static struct timeval trytimeout = {KEY_TIMEOUT, 0};
63 static struct timeval tottimeout = {KEY_TIMEOUT *KEY_NRETRY, 0};
65 int
66 key_setsecret (char *secretkey)
68 keystatus status;
70 if (!key_call ((u_long) KEY_SET, (xdrproc_t) xdr_keybuf, secretkey,
71 (xdrproc_t) xdr_keystatus, (char *) &status))
72 return -1;
73 if (status != KEY_SUCCESS)
75 debug ("set status is nonzero");
76 return -1;
78 return 0;
81 /* key_secretkey_is_set() returns 1 if the keyserver has a secret key
82 * stored for the caller's effective uid; it returns 0 otherwise
84 * N.B.: The KEY_NET_GET key call is undocumented. Applications shouldn't
85 * be using it, because it allows them to get the user's secret key.
87 int
88 key_secretkey_is_set (void)
90 struct key_netstres kres;
92 memset (&kres, 0, sizeof (kres));
93 if (key_call ((u_long) KEY_NET_GET, (xdrproc_t) xdr_void, (char *) NULL,
94 (xdrproc_t) xdr_key_netstres, (char *) &kres) &&
95 (kres.status == KEY_SUCCESS) &&
96 (kres.key_netstres_u.knet.st_priv_key[0] != 0))
98 /* avoid leaving secret key in memory */
99 memset (kres.key_netstres_u.knet.st_priv_key, 0, HEXKEYBYTES);
100 return 1;
102 return 0;
106 key_encryptsession (char *remotename, des_block *deskey)
108 cryptkeyarg arg;
109 cryptkeyres res;
111 arg.remotename = remotename;
112 arg.deskey = *deskey;
113 if (!key_call ((u_long) KEY_ENCRYPT, (xdrproc_t) xdr_cryptkeyarg,
114 (char *) &arg, (xdrproc_t) xdr_cryptkeyres, (char *) &res))
115 return -1;
117 if (res.status != KEY_SUCCESS)
119 debug ("encrypt status is nonzero");
120 return -1;
122 *deskey = res.cryptkeyres_u.deskey;
123 return 0;
127 key_decryptsession (char *remotename, des_block *deskey)
129 cryptkeyarg arg;
130 cryptkeyres res;
132 arg.remotename = remotename;
133 arg.deskey = *deskey;
134 if (!key_call ((u_long) KEY_DECRYPT, (xdrproc_t) xdr_cryptkeyarg,
135 (char *) &arg, (xdrproc_t) xdr_cryptkeyres, (char *) &res))
136 return -1;
137 if (res.status != KEY_SUCCESS)
139 debug ("decrypt status is nonzero");
140 return -1;
142 *deskey = res.cryptkeyres_u.deskey;
143 return 0;
147 key_encryptsession_pk (char *remotename, netobj *remotekey,
148 des_block *deskey)
150 cryptkeyarg2 arg;
151 cryptkeyres res;
153 arg.remotename = remotename;
154 arg.remotekey = *remotekey;
155 arg.deskey = *deskey;
156 if (!key_call ((u_long) KEY_ENCRYPT_PK, (xdrproc_t) xdr_cryptkeyarg2,
157 (char *) &arg, (xdrproc_t) xdr_cryptkeyres, (char *) &res))
158 return -1;
160 if (res.status != KEY_SUCCESS)
162 debug ("encrypt status is nonzero");
163 return -1;
165 *deskey = res.cryptkeyres_u.deskey;
166 return 0;
170 key_decryptsession_pk (char *remotename, netobj *remotekey,
171 des_block *deskey)
173 cryptkeyarg2 arg;
174 cryptkeyres res;
176 arg.remotename = remotename;
177 arg.remotekey = *remotekey;
178 arg.deskey = *deskey;
179 if (!key_call ((u_long) KEY_DECRYPT_PK, (xdrproc_t) xdr_cryptkeyarg2,
180 (char *) &arg, (xdrproc_t) xdr_cryptkeyres, (char *) &res))
181 return -1;
183 if (res.status != KEY_SUCCESS)
185 debug ("decrypt status is nonzero");
186 return -1;
188 *deskey = res.cryptkeyres_u.deskey;
189 return 0;
193 key_gendes (des_block *key)
195 struct sockaddr_in sin;
196 CLIENT *client;
197 int socket;
198 enum clnt_stat stat;
200 sin.sin_family = AF_INET;
201 sin.sin_port = 0;
202 sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
203 bzero (sin.sin_zero, sizeof (sin.sin_zero));
204 socket = RPC_ANYSOCK;
205 client = clntudp_bufcreate (&sin, (u_long) KEY_PROG, (u_long) KEY_VERS,
206 trytimeout, &socket, RPCSMALLMSGSIZE,
207 RPCSMALLMSGSIZE);
208 if (client == NULL)
209 return -1;
211 stat = clnt_call (client, KEY_GEN, (xdrproc_t) xdr_void, NULL,
212 (xdrproc_t) xdr_des_block, (caddr_t) key, tottimeout);
213 clnt_destroy (client);
214 close (socket);
215 if (stat != RPC_SUCCESS)
216 return -1;
218 return 0;
222 key_setnet (struct key_netstarg *arg)
224 keystatus status;
226 if (!key_call ((u_long) KEY_NET_PUT, (xdrproc_t) xdr_key_netstarg,
227 (char *) arg,(xdrproc_t) xdr_keystatus, (char *) &status))
228 return -1;
230 if (status != KEY_SUCCESS)
232 debug ("key_setnet status is nonzero");
233 return -1;
235 return 1;
239 key_get_conv (char *pkey, des_block *deskey)
241 cryptkeyres res;
243 if (!key_call ((u_long) KEY_GET_CONV, (xdrproc_t) xdr_keybuf, pkey,
244 (xdrproc_t) xdr_cryptkeyres, (char *) &res))
245 return -1;
247 if (res.status != KEY_SUCCESS)
249 debug ("get_conv status is nonzero");
250 return -1;
252 *deskey = res.cryptkeyres_u.deskey;
253 return 0;
257 * Hack to allow the keyserver to use AUTH_DES (for authenticated
258 * NIS+ calls, for example). The only functions that get called
259 * are key_encryptsession_pk, key_decryptsession_pk, and key_gendes.
261 * The approach is to have the keyserver fill in pointers to local
262 * implementations of these functions, and to call those in key_call().
265 cryptkeyres *(*__key_encryptsession_pk_LOCAL) (uid_t, char *) = 0;
266 cryptkeyres *(*__key_decryptsession_pk_LOCAL) (uid_t, char *) = 0;
267 des_block *(*__key_gendes_LOCAL) (uid_t, char *) = 0;
269 static int
270 internal_function
271 key_call (u_long proc, xdrproc_t xdr_arg, char *arg,
272 xdrproc_t xdr_rslt, char *rslt)
274 XDR xdrargs;
275 XDR xdrrslt;
276 FILE *fargs;
277 FILE *frslt;
278 sigset_t oldmask, mask;
279 union wait status;
280 int pid;
281 int success;
282 uid_t ruid;
283 uid_t euid;
284 static char MESSENGER[] = "/usr/etc/keyenvoy";
286 if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL)
288 cryptkeyres *res;
289 res = (*__key_encryptsession_pk_LOCAL) (geteuid (), arg);
290 *(cryptkeyres *) rslt = *res;
291 return 1;
293 else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL)
295 cryptkeyres *res;
296 res = (*__key_decryptsession_pk_LOCAL) (geteuid (), arg);
297 *(cryptkeyres *) rslt = *res;
298 return 1;
300 else if (proc == KEY_GEN && __key_gendes_LOCAL)
302 des_block *res;
303 res = (*__key_gendes_LOCAL) (geteuid (), 0);
304 *(des_block *) rslt = *res;
305 return 1;
308 success = 1;
309 sigemptyset (&mask);
310 sigaddset (&mask, SIGCHLD);
311 sigprocmask (SIG_BLOCK, &mask, &oldmask);
314 * We are going to exec a set-uid program which makes our effective uid
315 * zero, and authenticates us with our real uid. We need to make the
316 * effective uid be the real uid for the setuid program, and
317 * the real uid be the effective uid so that we can change things back.
319 euid = geteuid ();
320 ruid = getuid ();
321 setreuid (euid, ruid);
322 pid = _openchild (MESSENGER, &fargs, &frslt);
323 setreuid (ruid, euid);
324 if (pid < 0)
326 debug ("open_streams");
327 sigprocmask(SIG_SETMASK, &oldmask, NULL);
328 return (0);
330 xdrstdio_create (&xdrargs, fargs, XDR_ENCODE);
331 xdrstdio_create (&xdrrslt, frslt, XDR_DECODE);
333 if (!xdr_u_long (&xdrargs, &proc) || !(*xdr_arg) (&xdrargs, arg))
335 debug ("xdr args");
336 success = 0;
338 fclose (fargs);
340 if (success && !(*xdr_rslt) (&xdrrslt, rslt))
342 debug ("xdr rslt");
343 success = 0;
345 fclose(frslt);
347 wait_again:
348 if (wait4(pid, &status, 0, NULL) < 0)
350 if (errno == EINTR)
351 goto wait_again;
352 debug("wait4");
353 if (errno == ECHILD || errno == ESRCH)
354 perror("wait");
355 else
356 success = 0;
358 else
359 if (status.w_retcode)
361 debug("wait4 1");
362 success = 0;
364 sigprocmask(SIG_SETMASK, &oldmask, NULL);
366 return (success);