Update.
[platform/upstream/glibc.git] / sunrpc / key_call.c
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.
11  *
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.
15  *
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.
19  *
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.
23  *
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.
27  *
28  * Sun Microsystems, Inc.
29  * 2550 Garcia Avenue
30  * Mountain View, California  94043
31  */
32
33 /*
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>
37  */
38
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>
50
51 #define KEY_TIMEOUT     5       /* per-try timeout in seconds */
52 #define KEY_NRETRY      12      /* number of retries */
53
54 #define debug(msg)              /* turn off debugging */
55
56 extern int _openchild (char *command, FILE **fto, FILE **ffrom);
57
58
59 static int key_call (u_long, xdrproc_t xdr_arg, char *,
60                      xdrproc_t xdr_rslt, char *);
61
62 static struct timeval trytimeout = {KEY_TIMEOUT, 0};
63 static struct timeval tottimeout = {KEY_TIMEOUT *KEY_NRETRY, 0};
64
65 int
66 key_setsecret (char *secretkey)
67 {
68   keystatus status;
69
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)
74     {
75       debug ("set status is nonzero");
76       return -1;
77     }
78   return 0;
79 }
80
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
83  *
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.
86  */
87 int
88 key_secretkey_is_set (void)
89 {
90   struct key_netstres kres;
91
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))
97     {
98       /* avoid leaving secret key in memory */
99       memset (kres.key_netstres_u.knet.st_priv_key, 0, HEXKEYBYTES);
100       return 1;
101     }
102   return 0;
103 }
104
105 int
106 key_encryptsession (char *remotename, des_block *deskey)
107 {
108   cryptkeyarg arg;
109   cryptkeyres res;
110
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;
116
117   if (res.status != KEY_SUCCESS)
118     {
119       debug ("encrypt status is nonzero");
120       return -1;
121     }
122   *deskey = res.cryptkeyres_u.deskey;
123   return 0;
124 }
125
126 int
127 key_decryptsession (char *remotename, des_block *deskey)
128 {
129   cryptkeyarg arg;
130   cryptkeyres res;
131
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)
138     {
139       debug ("decrypt status is nonzero");
140       return -1;
141     }
142   *deskey = res.cryptkeyres_u.deskey;
143   return 0;
144 }
145
146 int
147 key_encryptsession_pk (char *remotename, netobj *remotekey,
148                        des_block *deskey)
149 {
150   cryptkeyarg2 arg;
151   cryptkeyres res;
152
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;
159
160   if (res.status != KEY_SUCCESS)
161     {
162       debug ("encrypt status is nonzero");
163       return -1;
164     }
165   *deskey = res.cryptkeyres_u.deskey;
166   return 0;
167 }
168
169 int
170 key_decryptsession_pk (char *remotename, netobj *remotekey,
171                        des_block *deskey)
172 {
173   cryptkeyarg2 arg;
174   cryptkeyres res;
175
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;
182
183   if (res.status != KEY_SUCCESS)
184     {
185       debug ("decrypt status is nonzero");
186       return -1;
187     }
188   *deskey = res.cryptkeyres_u.deskey;
189   return 0;
190 }
191
192 int
193 key_gendes (des_block *key)
194 {
195   struct sockaddr_in sin;
196   CLIENT *client;
197   int socket;
198   enum clnt_stat stat;
199
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;
210
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;
217
218   return 0;
219 }
220
221 int
222 key_setnet (struct key_netstarg *arg)
223 {
224   keystatus status;
225
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;
229
230   if (status != KEY_SUCCESS)
231     {
232       debug ("key_setnet status is nonzero");
233       return -1;
234     }
235   return 1;
236 }
237
238 int
239 key_get_conv (char *pkey, des_block *deskey)
240 {
241   cryptkeyres res;
242
243   if (!key_call ((u_long) KEY_GET_CONV, (xdrproc_t) xdr_keybuf, pkey,
244                  (xdrproc_t) xdr_cryptkeyres, (char *) &res))
245     return -1;
246
247   if (res.status != KEY_SUCCESS)
248     {
249       debug ("get_conv status is nonzero");
250       return -1;
251     }
252   *deskey = res.cryptkeyres_u.deskey;
253   return 0;
254 }
255
256 /*
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.
260  *
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().
263  */
264
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;
268
269 static int
270 key_call (u_long proc, xdrproc_t xdr_arg, char *arg,
271           xdrproc_t xdr_rslt, char *rslt)
272 {
273   XDR xdrargs;
274   XDR xdrrslt;
275   FILE *fargs;
276   FILE *frslt;
277   sigset_t oldmask, mask;
278   union wait status;
279   int pid;
280   int success;
281   uid_t ruid;
282   uid_t euid;
283   static char MESSENGER[] = "/usr/etc/keyenvoy";
284
285   if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL)
286     {
287       cryptkeyres *res;
288       res = (*__key_encryptsession_pk_LOCAL) (geteuid (), arg);
289       *(cryptkeyres *) rslt = *res;
290       return 1;
291     }
292   else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL)
293     {
294       cryptkeyres *res;
295       res = (*__key_decryptsession_pk_LOCAL) (geteuid (), arg);
296       *(cryptkeyres *) rslt = *res;
297       return 1;
298     }
299   else if (proc == KEY_GEN && __key_gendes_LOCAL)
300     {
301       des_block *res;
302       res = (*__key_gendes_LOCAL) (geteuid (), 0);
303       *(des_block *) rslt = *res;
304       return 1;
305     }
306
307   success = 1;
308   sigemptyset (&mask);
309   sigaddset (&mask, SIGCHLD);
310   sigprocmask (SIG_BLOCK, &mask, &oldmask);
311
312   /*
313    * We are going to exec a set-uid program which makes our effective uid
314    * zero, and authenticates us with our real uid. We need to make the
315    * effective uid be the real uid for the setuid program, and
316    * the real uid be the effective uid so that we can change things back.
317    */
318   euid = geteuid ();
319   ruid = getuid ();
320   setreuid (euid, ruid);
321   pid = _openchild (MESSENGER, &fargs, &frslt);
322   setreuid (ruid, euid);
323   if (pid < 0)
324     {
325       debug ("open_streams");
326       sigprocmask(SIG_SETMASK, &oldmask, NULL);
327       return (0);
328     }
329   xdrstdio_create (&xdrargs, fargs, XDR_ENCODE);
330   xdrstdio_create (&xdrrslt, frslt, XDR_DECODE);
331
332   if (!xdr_u_long (&xdrargs, &proc) || !(*xdr_arg) (&xdrargs, arg))
333     {
334       debug ("xdr args");
335       success = 0;
336     }
337   fclose (fargs);
338
339   if (success && !(*xdr_rslt) (&xdrrslt, rslt))
340     {
341       debug ("xdr rslt");
342       success = 0;
343     }
344   fclose(frslt);
345
346  wait_again:
347   if (wait4(pid, &status, 0, NULL) < 0)
348     {
349       if (errno == EINTR)
350         goto wait_again;
351       debug("wait4");
352       if (errno == ECHILD || errno == ESRCH)
353         perror("wait");
354       else
355         success = 0;
356     }
357   else
358     if (status.w_retcode)
359       {
360         debug("wait4 1");
361         success = 0;
362       }
363   sigprocmask(SIG_SETMASK, &oldmask, NULL);
364
365   return (success);
366 }