Update.
[platform/upstream/glibc.git] / sunrpc / key_call.c
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) 1988 by Sun Microsystems, Inc.
31  */
32 /*
33  * The original source is from the RPCSRC 4.0 package from Sun Microsystems.
34  * The Interface to keyserver protocoll 2, RPC over AF_UNIX and Linux/doors
35  * was added by Thorsten Kukuk <kukuk@suse.de>
36  * Since the Linux/doors project was stopped, I doubt that this code will
37  * ever be useful <kukuk@suse.de>.
38  */
39
40 #include <stdio.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <signal.h>
44 #include <unistd.h>
45 #include <string.h>
46 #include <rpc/rpc.h>
47 #include <rpc/auth.h>
48 #include <sys/wait.h>
49 #include <sys/param.h>
50 #include <sys/socket.h>
51 #include <rpc/key_prot.h>
52 #include <bits/libc-lock.h>
53
54 #ifdef HAVE_DOORS
55 # include "door/door.h"
56 #endif
57
58 #define KEY_TIMEOUT     5       /* per-try timeout in seconds */
59 #define KEY_NRETRY      12      /* number of retries */
60
61 #define debug(msg)              /* turn off debugging */
62
63 #ifndef SO_PASSCRED
64 extern int _openchild (const char *command, FILE **fto, FILE **ffrom);
65 #endif
66
67 static int key_call (u_long, xdrproc_t xdr_arg, char *,
68                      xdrproc_t xdr_rslt, char *) internal_function;
69
70 static const struct timeval trytimeout = {KEY_TIMEOUT, 0};
71 static const struct timeval tottimeout = {KEY_TIMEOUT *KEY_NRETRY, 0};
72
73 int
74 key_setsecret (char *secretkey)
75 {
76   keystatus status;
77
78   if (!key_call ((u_long) KEY_SET, (xdrproc_t) INTUSE(xdr_keybuf), secretkey,
79                  (xdrproc_t) INTUSE(xdr_keystatus), (char *) &status))
80     return -1;
81   if (status != KEY_SUCCESS)
82     {
83       debug ("set status is nonzero");
84       return -1;
85     }
86   return 0;
87 }
88
89 /* key_secretkey_is_set() returns 1 if the keyserver has a secret key
90  * stored for the caller's effective uid; it returns 0 otherwise
91  *
92  * N.B.:  The KEY_NET_GET key call is undocumented.  Applications shouldn't
93  * be using it, because it allows them to get the user's secret key.
94  */
95 int
96 key_secretkey_is_set (void)
97 {
98   struct key_netstres kres;
99
100   memset (&kres, 0, sizeof (kres));
101   if (key_call ((u_long) KEY_NET_GET, (xdrproc_t) INTUSE(xdr_void),
102                 (char *) NULL, (xdrproc_t) INTUSE(xdr_key_netstres),
103                 (char *) &kres) &&
104       (kres.status == KEY_SUCCESS) &&
105       (kres.key_netstres_u.knet.st_priv_key[0] != 0))
106     {
107       /* avoid leaving secret key in memory */
108       memset (kres.key_netstres_u.knet.st_priv_key, 0, HEXKEYBYTES);
109       return 1;
110     }
111   return 0;
112 }
113
114 int
115 key_encryptsession (char *remotename, des_block *deskey)
116 {
117   cryptkeyarg arg;
118   cryptkeyres res;
119
120   arg.remotename = remotename;
121   arg.deskey = *deskey;
122   if (!key_call ((u_long) KEY_ENCRYPT, (xdrproc_t) INTUSE(xdr_cryptkeyarg),
123                  (char *) &arg, (xdrproc_t) INTUSE(xdr_cryptkeyres),
124                  (char *) &res))
125     return -1;
126
127   if (res.status != KEY_SUCCESS)
128     {
129       debug ("encrypt status is nonzero");
130       return -1;
131     }
132   *deskey = res.cryptkeyres_u.deskey;
133   return 0;
134 }
135
136 int
137 key_decryptsession (char *remotename, des_block *deskey)
138 {
139   cryptkeyarg arg;
140   cryptkeyres res;
141
142   arg.remotename = remotename;
143   arg.deskey = *deskey;
144   if (!key_call ((u_long) KEY_DECRYPT, (xdrproc_t) INTUSE(xdr_cryptkeyarg),
145                  (char *) &arg, (xdrproc_t) INTUSE(xdr_cryptkeyres),
146                  (char *) &res))
147     return -1;
148   if (res.status != KEY_SUCCESS)
149     {
150       debug ("decrypt status is nonzero");
151       return -1;
152     }
153   *deskey = res.cryptkeyres_u.deskey;
154   return 0;
155 }
156
157 int
158 key_encryptsession_pk (char *remotename, netobj *remotekey,
159                        des_block *deskey)
160 {
161   cryptkeyarg2 arg;
162   cryptkeyres res;
163
164   arg.remotename = remotename;
165   arg.remotekey = *remotekey;
166   arg.deskey = *deskey;
167   if (!key_call ((u_long) KEY_ENCRYPT_PK, (xdrproc_t) INTUSE(xdr_cryptkeyarg2),
168                  (char *) &arg, (xdrproc_t) INTUSE(xdr_cryptkeyres),
169                  (char *) &res))
170     return -1;
171
172   if (res.status != KEY_SUCCESS)
173     {
174       debug ("encrypt status is nonzero");
175       return -1;
176     }
177   *deskey = res.cryptkeyres_u.deskey;
178   return 0;
179 }
180
181 int
182 key_decryptsession_pk (char *remotename, netobj *remotekey,
183                        des_block *deskey)
184 {
185   cryptkeyarg2 arg;
186   cryptkeyres res;
187
188   arg.remotename = remotename;
189   arg.remotekey = *remotekey;
190   arg.deskey = *deskey;
191   if (!key_call ((u_long) KEY_DECRYPT_PK, (xdrproc_t) INTUSE(xdr_cryptkeyarg2),
192                  (char *) &arg, (xdrproc_t) INTUSE(xdr_cryptkeyres),
193                  (char *) &res))
194     return -1;
195
196   if (res.status != KEY_SUCCESS)
197     {
198       debug ("decrypt status is nonzero");
199       return -1;
200     }
201   *deskey = res.cryptkeyres_u.deskey;
202   return 0;
203 }
204
205 int
206 key_gendes (des_block *key)
207 {
208   struct sockaddr_in sin;
209   CLIENT *client;
210   int socket;
211   enum clnt_stat stat;
212
213   sin.sin_family = AF_INET;
214   sin.sin_port = 0;
215   sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
216   __bzero (sin.sin_zero, sizeof (sin.sin_zero));
217   socket = RPC_ANYSOCK;
218   client = INTUSE(clntudp_bufcreate) (&sin, (u_long) KEY_PROG,
219                                       (u_long) KEY_VERS, trytimeout, &socket,
220                                       RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
221   if (client == NULL)
222     return -1;
223
224   stat = clnt_call (client, KEY_GEN, (xdrproc_t) INTUSE(xdr_void), NULL,
225                     (xdrproc_t) INTUSE(xdr_des_block), (caddr_t) key,
226                     tottimeout);
227   clnt_destroy (client);
228   __close (socket);
229   if (stat != RPC_SUCCESS)
230     return -1;
231
232   return 0;
233 }
234
235 int
236 key_setnet (struct key_netstarg *arg)
237 {
238   keystatus status;
239
240   if (!key_call ((u_long) KEY_NET_PUT, (xdrproc_t) INTUSE(xdr_key_netstarg),
241                  (char *) arg,(xdrproc_t) INTUSE(xdr_keystatus),
242                  (char *) &status))
243     return -1;
244
245   if (status != KEY_SUCCESS)
246     {
247       debug ("key_setnet status is nonzero");
248       return -1;
249     }
250   return 1;
251 }
252
253 int
254 key_get_conv (char *pkey, des_block *deskey)
255 {
256   cryptkeyres res;
257
258   if (!key_call ((u_long) KEY_GET_CONV, (xdrproc_t) INTUSE(xdr_keybuf), pkey,
259                  (xdrproc_t) INTUSE(xdr_cryptkeyres), (char *) &res))
260     return -1;
261
262   if (res.status != KEY_SUCCESS)
263     {
264       debug ("get_conv status is nonzero");
265       return -1;
266     }
267   *deskey = res.cryptkeyres_u.deskey;
268   return 0;
269 }
270
271 /*
272  * Hack to allow the keyserver to use AUTH_DES (for authenticated
273  * NIS+ calls, for example).  The only functions that get called
274  * are key_encryptsession_pk, key_decryptsession_pk, and key_gendes.
275  *
276  * The approach is to have the keyserver fill in pointers to local
277  * implementations of these functions, and to call those in key_call().
278  */
279
280 cryptkeyres *(*__key_encryptsession_pk_LOCAL) (uid_t, char *);
281 cryptkeyres *(*__key_decryptsession_pk_LOCAL) (uid_t, char *);
282 des_block *(*__key_gendes_LOCAL) (uid_t, char *);
283
284 #ifndef SO_PASSCRED
285 static int
286 internal_function
287 key_call_keyenvoy (u_long proc, xdrproc_t xdr_arg, char *arg,
288                    xdrproc_t xdr_rslt, char *rslt)
289 {
290   XDR xdrargs;
291   XDR xdrrslt;
292   FILE *fargs;
293   FILE *frslt;
294   sigset_t oldmask, mask;
295   union wait status;
296   int pid;
297   int success;
298   uid_t ruid;
299   uid_t euid;
300   static const char MESSENGER[] = "/usr/etc/keyenvoy";
301
302   success = 1;
303   sigemptyset (&mask);
304   sigaddset (&mask, SIGCHLD);
305   __sigprocmask (SIG_BLOCK, &mask, &oldmask);
306
307   /*
308    * We are going to exec a set-uid program which makes our effective uid
309    * zero, and authenticates us with our real uid. We need to make the
310    * effective uid be the real uid for the setuid program, and
311    * the real uid be the effective uid so that we can change things back.
312    */
313   euid = __geteuid ();
314   ruid = __getuid ();
315   __setreuid (euid, ruid);
316   pid = _openchild (MESSENGER, &fargs, &frslt);
317   __setreuid (ruid, euid);
318   if (pid < 0)
319     {
320       debug ("open_streams");
321       __sigprocmask (SIG_SETMASK, &oldmask, NULL);
322       return (0);
323     }
324   xdrstdio_create (&xdrargs, fargs, XDR_ENCODE);
325   xdrstdio_create (&xdrrslt, frslt, XDR_DECODE);
326
327   if (!INTUSE(xdr_u_long) (&xdrargs, &proc) || !(*xdr_arg) (&xdrargs, arg))
328     {
329       debug ("xdr args");
330       success = 0;
331     }
332   fclose (fargs);
333
334   if (success && !(*xdr_rslt) (&xdrrslt, rslt))
335     {
336       debug ("xdr rslt");
337       success = 0;
338     }
339   fclose(frslt);
340
341  wait_again:
342   if (__wait4 (pid, &status, 0, NULL) < 0)
343     {
344       if (errno == EINTR)
345         goto wait_again;
346       debug ("wait4");
347       if (errno == ECHILD || errno == ESRCH)
348         perror ("wait");
349       else
350         success = 0;
351     }
352   else
353     if (status.w_retcode)
354       {
355         debug ("wait4 1");
356         success = 0;
357       }
358   __sigprocmask (SIG_SETMASK, &oldmask, NULL);
359
360   return success;
361 }
362 #endif
363
364 struct  key_call_private {
365   CLIENT  *client;        /* Client handle */
366   pid_t   pid;            /* process-id at moment of creation */
367   uid_t   uid;            /* user-id at last authorization */
368 };
369 #ifdef _RPC_THREAD_SAFE_
370 #define key_call_private_main ((struct  key_call_private *)RPC_THREAD_VARIABLE(key_call_private_s))
371 #else
372 static struct key_call_private *key_call_private_main;
373 #endif
374 __libc_lock_define_initialized (static, keycall_lock)
375
376 /*
377  * Keep the handle cached.  This call may be made quite often.
378  */
379 static CLIENT *
380 getkeyserv_handle (int vers)
381 {
382   struct key_call_private *kcp = key_call_private_main;
383   struct timeval wait_time;
384   int fd;
385   struct sockaddr_un name;
386   int namelen = sizeof(struct sockaddr_un);
387
388 #define TOTAL_TIMEOUT   30      /* total timeout talking to keyserver */
389 #define TOTAL_TRIES     5       /* Number of tries */
390
391   if (kcp == (struct key_call_private *)NULL)
392     {
393       kcp = (struct key_call_private *)malloc (sizeof (*kcp));
394       if (kcp == (struct key_call_private *)NULL)
395         return (CLIENT *) NULL;
396
397       key_call_private_main = kcp;
398       kcp->client = NULL;
399     }
400
401   /* if pid has changed, destroy client and rebuild */
402   if (kcp->client != NULL && kcp->pid != __getpid ())
403     {
404       clnt_destroy (kcp->client);
405       kcp->client = NULL;
406     }
407
408   if (kcp->client != NULL)
409     {
410       /* if other side closed socket, build handle again */
411       clnt_control (kcp->client, CLGET_FD, (char *)&fd);
412       if (__getpeername (fd,(struct sockaddr *)&name,&namelen) == -1)
413         {
414           auth_destroy (kcp->client->cl_auth);
415           clnt_destroy (kcp->client);
416           kcp->client = NULL;
417         }
418     }
419
420   if (kcp->client != NULL)
421     {
422       /* if uid has changed, build client handle again */
423       if (kcp->uid != __geteuid ())
424         {
425         kcp->uid = __geteuid ();
426         auth_destroy (kcp->client->cl_auth);
427         kcp->client->cl_auth =
428           INTUSE(authunix_create) ((char *)"", kcp->uid, 0, 0, NULL);
429         if (kcp->client->cl_auth == NULL)
430           {
431             clnt_destroy (kcp->client);
432             kcp->client = NULL;
433             return ((CLIENT *) NULL);
434           }
435         }
436       /* Change the version number to the new one */
437       clnt_control (kcp->client, CLSET_VERS, (void *)&vers);
438       return kcp->client;
439     }
440
441   if ((kcp->client == (CLIENT *) NULL))
442     /* Use the AF_UNIX transport */
443     kcp->client = INTUSE(clnt_create) ("/var/run/keyservsock", KEY_PROG, vers,
444                                        "unix");
445
446   if (kcp->client == (CLIENT *) NULL)
447     return (CLIENT *) NULL;
448
449   kcp->uid = __geteuid ();
450   kcp->pid = __getpid ();
451   kcp->client->cl_auth = INTUSE(authunix_create) ((char *)"", kcp->uid, 0, 0,
452                                                   NULL);
453   if (kcp->client->cl_auth == NULL)
454     {
455       clnt_destroy (kcp->client);
456       kcp->client = NULL;
457       return (CLIENT *) NULL;
458     }
459
460   wait_time.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES;
461   wait_time.tv_usec = 0;
462   clnt_control (kcp->client, CLSET_RETRY_TIMEOUT,
463                 (char *)&wait_time);
464   if (clnt_control (kcp->client, CLGET_FD, (char *)&fd))
465     __fcntl (fd, F_SETFD, 1);  /* make it "close on exec" */
466
467   return kcp->client;
468 }
469
470 /* returns  0 on failure, 1 on success */
471 static int
472 internal_function
473 key_call_socket (u_long proc, xdrproc_t xdr_arg, char *arg,
474                xdrproc_t xdr_rslt, char *rslt)
475 {
476   CLIENT *clnt;
477   struct timeval wait_time;
478   int result = 0;
479
480   __libc_lock_lock (keycall_lock);
481   if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) ||
482       (proc == KEY_NET_GET) || (proc == KEY_NET_PUT) ||
483       (proc == KEY_GET_CONV))
484     clnt = getkeyserv_handle(2); /* talk to version 2 */
485   else
486     clnt = getkeyserv_handle(1); /* talk to version 1 */
487
488   if (clnt != NULL)
489     {
490       wait_time.tv_sec = TOTAL_TIMEOUT;
491       wait_time.tv_usec = 0;
492
493       if (clnt_call (clnt, proc, xdr_arg, arg, xdr_rslt, rslt,
494                      wait_time) == RPC_SUCCESS)
495         result = 1;
496     }
497
498   __libc_lock_unlock (keycall_lock);
499
500   return result;
501 }
502
503 #ifdef HAVE_DOORS
504 /* returns 0 on failure, 1 on success */
505 static int
506 internal_function
507 key_call_door (u_long proc, xdrproc_t xdr_arg, char *arg,
508                xdrproc_t xdr_rslt, char *rslt)
509 {
510   XDR xdrs;
511   int fd, ret;
512   door_arg_t args;
513   char *data_ptr;
514   u_long data_len = 0;
515   char res[255];
516
517   if ((fd = open("/var/run/keyservdoor", O_RDONLY)) < 0)
518     return 0;
519   res[0] = 0;
520
521   data_len = xdr_sizeof (xdr_arg, arg);
522   data_ptr = calloc (1, data_len + 2 * sizeof (u_long));
523   if (data_ptr == NULL)
524     return 0;
525
526   INTUSE(xdrmem_create) (&xdrs, &data_ptr[2 * sizeof (u_long)], data_len,
527                          XDR_ENCODE);
528   if (!xdr_arg (&xdrs, arg))
529     {
530       xdr_destroy (&xdrs);
531       free (data_ptr);
532       return 0;
533     }
534   xdr_destroy (&xdrs);
535
536   memcpy (data_ptr, &proc, sizeof (u_long));
537   memcpy (&data_ptr[sizeof (proc)], &data_len, sizeof (u_long));
538
539   args.data_ptr = data_ptr;
540   args.data_size = data_len + 2 * sizeof (u_long);
541   args.desc_ptr = NULL;
542   args.desc_num = 0;
543   args.rbuf = res;
544   args.rsize = sizeof (res);
545
546   ret = __door_call (fd, &args);
547   free (data_ptr);
548   close (fd);
549
550   if (ret < 0)
551     return 0;
552
553   memcpy (&data_len, args.data_ptr, sizeof (u_long));
554   if (data_len != 0)
555     return 0;
556
557   memcpy (&data_len, &args.data_ptr[sizeof (u_long)], sizeof (u_long));
558   INTUSE(xdrmem_create) (&xdrs, &args.data_ptr[2 * sizeof (u_long)],
559                          data_len, XDR_DECODE);
560   if (!xdr_rslt (&xdrs, rslt))
561     {
562       xdr_destroy (&xdrs);
563       return 0;
564     }
565   xdr_destroy (&xdrs);
566
567   return 1;
568 }
569 #endif
570
571 /* returns 0 on failure, 1 on success */
572 static int
573 internal_function
574 key_call (u_long proc, xdrproc_t xdr_arg, char *arg,
575           xdrproc_t xdr_rslt, char *rslt)
576 {
577 #ifndef SO_PASSCRED
578   static int use_keyenvoy;
579 #endif
580 #ifdef HAVE_DOORS
581   static int not_use_doors;
582 #endif
583
584   if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL)
585     {
586       cryptkeyres *res;
587       res = (*__key_encryptsession_pk_LOCAL) (__geteuid (), arg);
588       *(cryptkeyres *) rslt = *res;
589       return 1;
590     }
591   else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL)
592     {
593       cryptkeyres *res;
594       res = (*__key_decryptsession_pk_LOCAL) (__geteuid (), arg);
595       *(cryptkeyres *) rslt = *res;
596       return 1;
597     }
598   else if (proc == KEY_GEN && __key_gendes_LOCAL)
599     {
600       des_block *res;
601       res = (*__key_gendes_LOCAL) (__geteuid (), 0);
602       *(des_block *) rslt = *res;
603       return 1;
604     }
605
606 #ifdef HAVE_DOORS
607   if (!not_use_doors)
608     {
609       if (key_call_door (proc, xdr_arg, arg, xdr_rslt, rslt))
610         return 1;
611       not_use_doors = 1;
612     }
613 #endif
614
615 #ifdef SO_PASSCRED
616   return key_call_socket (proc, xdr_arg, arg, xdr_rslt, rslt);
617 #else
618   if (!use_keyenvoy)
619     {
620       if (key_call_socket (proc, xdr_arg, arg, xdr_rslt, rslt))
621         return 1;
622       use_keyenvoy = 1;
623     }
624   return key_call_keyenvoy (proc, xdr_arg, arg, xdr_rslt, rslt);
625 #endif
626 }
627
628 #ifdef _RPC_THREAD_SAFE_
629 void
630 __rpc_thread_key_cleanup (void)
631 {
632         struct key_call_private *kcp = RPC_THREAD_VARIABLE(key_call_private_s);
633
634         if (kcp) {
635                 if (kcp->client)
636                         clnt_destroy(kcp->client);
637                 free (kcp);
638         }
639 }
640 #endif /* _RPC_THREAD_SAFE_ */