1998-12-20 Roland McGrath <roland@baalperazim.frob.com>
[kopensolaris-gnu/glibc.git] / sunrpc / clnt_unix.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 /*
31  * clnt_unix.c, Implements a TCP/IP based, client side RPC.
32  *
33  * Copyright (C) 1984, Sun Microsystems, Inc.
34  *
35  * TCP based RPC supports 'batched calls'.
36  * A sequence of calls may be batched-up in a send buffer.  The rpc call
37  * return immediately to the client even though the call was not necessarily
38  * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
39  * the rpc timeout value is zero (see clnt.h, rpc).
40  *
41  * Clients should NOT casually batch calls that in fact return results; that is,
42  * the server side should be aware that a call is batched and not produce any
43  * return message.  Batched calls that produce many result messages can
44  * deadlock (netlock) the client and the server....
45  *
46  * Now go hang yourself.
47  */
48
49 #include <netdb.h>
50 #include <errno.h>
51 #include <stdio.h>
52 #include <unistd.h>
53 #include <rpc/rpc.h>
54 #include <sys/uio.h>
55 #include <sys/poll.h>
56 #include <sys/socket.h>
57 #include <rpc/pmap_clnt.h>
58
59 extern u_long _create_xid (void);
60
61 #define MCALL_MSG_SIZE 24
62
63 struct ct_data
64   {
65     int ct_sock;
66     bool_t ct_closeit;
67     struct timeval ct_wait;
68     bool_t ct_waitset;          /* wait set by clnt_control? */
69     struct sockaddr_un ct_addr;
70     struct rpc_err ct_error;
71     char ct_mcall[MCALL_MSG_SIZE];      /* marshalled callmsg */
72     u_int ct_mpos;              /* pos after marshal */
73     XDR ct_xdrs;
74   };
75
76 static int readunix (char *, char *, int);
77 static int writeunix (char *, char *, int);
78
79 static enum clnt_stat clntunix_call (CLIENT *, u_long, xdrproc_t, caddr_t,
80                                     xdrproc_t, caddr_t, struct timeval);
81 static void clntunix_abort (void);
82 static void clntunix_geterr (CLIENT *, struct rpc_err *);
83 static bool_t clntunix_freeres (CLIENT *, xdrproc_t, caddr_t);
84 static bool_t clntunix_control (CLIENT *, int, char *);
85 static void clntunix_destroy (CLIENT *);
86
87 static struct clnt_ops unix_ops =
88 {
89   clntunix_call,
90   clntunix_abort,
91   clntunix_geterr,
92   clntunix_freeres,
93   clntunix_destroy,
94   clntunix_control
95 };
96
97 /*
98  * Create a client handle for a tcp/ip connection.
99  * If *sockp<0, *sockp is set to a newly created TCP socket and it is
100  * connected to raddr.  If *sockp non-negative then
101  * raddr is ignored.  The rpc/tcp package does buffering
102  * similar to stdio, so the client must pick send and receive buffer sizes,];
103  * 0 => use the default.
104  * If raddr->sin_port is 0, then a binder on the remote machine is
105  * consulted for the right port number.
106  * NB: *sockp is copied into a private area.
107  * NB: It is the clients responsibility to close *sockp.
108  * NB: The rpch->cl_auth is set null authentication.  Caller may wish to set this
109  * something more useful.
110  */
111 CLIENT *
112 clntunix_create (struct sockaddr_un *raddr, u_long prog, u_long vers,
113                  int *sockp, u_int sendsz, u_int recvsz)
114 {
115   CLIENT *h;
116   struct ct_data *ct = (struct ct_data *) mem_alloc (sizeof (*ct));
117   struct rpc_msg call_msg;
118   int len;
119
120   h = (CLIENT *) mem_alloc (sizeof (*h));
121   if (h == NULL)
122     {
123       (void) fputs (_("clntunix_create: out of memory\n"), stderr);
124       rpc_createerr.cf_stat = RPC_SYSTEMERROR;
125       rpc_createerr.cf_error.re_errno = errno;
126       goto fooy;
127     }
128   /*  ct = (struct ct_data *) mem_alloc (sizeof (*ct)); */
129   if (ct == NULL)
130     {
131       (void) fputs (_("clntunix_create: out of memory\n"), stderr);
132       rpc_createerr.cf_stat = RPC_SYSTEMERROR;
133       rpc_createerr.cf_error.re_errno = errno;
134       goto fooy;
135     }
136
137   /*
138    * If no socket given, open one
139    */
140   if (*sockp < 0)
141     {
142       *sockp = __socket (AF_UNIX, SOCK_STREAM, 0);
143       len = strlen (raddr->sun_path) + sizeof (raddr->sun_family) + 1;
144       if (*sockp < 0
145           || __connect (*sockp, (struct sockaddr *) raddr, len) < 0)
146         {
147           rpc_createerr.cf_stat = RPC_SYSTEMERROR;
148           rpc_createerr.cf_error.re_errno = errno;
149           if (*sockp != -1)
150             __close (*sockp);
151           goto fooy;
152         }
153       ct->ct_closeit = TRUE;
154     }
155   else
156     {
157       ct->ct_closeit = FALSE;
158     }
159
160   /*
161    * Set up private data struct
162    */
163   ct->ct_sock = *sockp;
164   ct->ct_wait.tv_usec = 0;
165   ct->ct_waitset = FALSE;
166   ct->ct_addr = *raddr;
167
168   /*
169    * Initialize call message
170    */
171   call_msg.rm_xid = _create_xid ();
172   call_msg.rm_direction = CALL;
173   call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
174   call_msg.rm_call.cb_prog = prog;
175   call_msg.rm_call.cb_vers = vers;
176
177   /*
178    * pre-serialize the static part of the call msg and stash it away
179    */
180   xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, XDR_ENCODE);
181   if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg))
182     {
183       if (ct->ct_closeit)
184         __close (*sockp);
185       goto fooy;
186     }
187   ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs));
188   XDR_DESTROY (&(ct->ct_xdrs));
189
190   /*
191    * Create a client handle which uses xdrrec for serialization
192    * and authnone for authentication.
193    */
194   xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz,
195                  (caddr_t) ct, readunix, writeunix);
196   h->cl_ops = &unix_ops;
197   h->cl_private = (caddr_t) ct;
198   h->cl_auth = authnone_create ();
199   return h;
200
201 fooy:
202   /*
203    * Something goofed, free stuff and barf
204    */
205   mem_free ((caddr_t) ct, sizeof (struct ct_data));
206   mem_free ((caddr_t) h, sizeof (CLIENT));
207   return (CLIENT *) NULL;
208 }
209
210 static enum clnt_stat
211 clntunix_call (h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
212      CLIENT *h;
213      u_long proc;
214      xdrproc_t xdr_args;
215      caddr_t args_ptr;
216      xdrproc_t xdr_results;
217      caddr_t results_ptr;
218      struct timeval timeout;
219 {
220   struct ct_data *ct = (struct ct_data *) h->cl_private;
221   XDR *xdrs = &(ct->ct_xdrs);
222   struct rpc_msg reply_msg;
223   u_long x_id;
224   u_int32_t *msg_x_id = (u_int32_t *) (ct->ct_mcall);   /* yuk */
225   bool_t shipnow;
226   int refreshes = 2;
227
228   if (!ct->ct_waitset)
229     {
230       ct->ct_wait = timeout;
231     }
232
233   shipnow =
234     (xdr_results == (xdrproc_t) 0 && timeout.tv_sec == 0
235      && timeout.tv_usec == 0) ? FALSE : TRUE;
236
237 call_again:
238   xdrs->x_op = XDR_ENCODE;
239   ct->ct_error.re_status = RPC_SUCCESS;
240   x_id = ntohl (--(*msg_x_id));
241   if ((!XDR_PUTBYTES (xdrs, ct->ct_mcall, ct->ct_mpos)) ||
242       (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
243       (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
244       (!(*xdr_args) (xdrs, args_ptr)))
245     {
246       if (ct->ct_error.re_status == RPC_SUCCESS)
247         ct->ct_error.re_status = RPC_CANTENCODEARGS;
248       (void) xdrrec_endofrecord (xdrs, TRUE);
249       return ct->ct_error.re_status;
250     }
251   if (!xdrrec_endofrecord (xdrs, shipnow))
252     return ct->ct_error.re_status = RPC_CANTSEND;
253   if (!shipnow)
254     return RPC_SUCCESS;
255   /*
256    * Hack to provide rpc-based message passing
257    */
258   if (timeout.tv_sec == 0 && timeout.tv_usec == 0)
259     return ct->ct_error.re_status = RPC_TIMEDOUT;
260
261
262   /*
263    * Keep receiving until we get a valid transaction id
264    */
265   xdrs->x_op = XDR_DECODE;
266   while (TRUE)
267     {
268       reply_msg.acpted_rply.ar_verf = _null_auth;
269       reply_msg.acpted_rply.ar_results.where = NULL;
270       reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
271       if (!xdrrec_skiprecord (xdrs))
272         return ct->ct_error.re_status;
273       /* now decode and validate the response header */
274       if (!xdr_replymsg (xdrs, &reply_msg))
275         {
276           if (ct->ct_error.re_status == RPC_SUCCESS)
277             continue;
278           return ct->ct_error.re_status;
279         }
280       if (reply_msg.rm_xid == x_id)
281         break;
282     }
283
284   /*
285    * process header
286    */
287   _seterr_reply (&reply_msg, &(ct->ct_error));
288   if (ct->ct_error.re_status == RPC_SUCCESS)
289     {
290       if (!AUTH_VALIDATE (h->cl_auth, &reply_msg.acpted_rply.ar_verf))
291         {
292           ct->ct_error.re_status = RPC_AUTHERROR;
293           ct->ct_error.re_why = AUTH_INVALIDRESP;
294         }
295       else if (!(*xdr_results) (xdrs, results_ptr))
296         {
297           if (ct->ct_error.re_status == RPC_SUCCESS)
298             ct->ct_error.re_status = RPC_CANTDECODERES;
299         }
300       /* free verifier ... */
301       if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
302         {
303           xdrs->x_op = XDR_FREE;
304           (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf));
305         }
306     }                           /* end successful completion */
307   else
308     {
309       /* maybe our credentials need to be refreshed ... */
310       if (refreshes-- && AUTH_REFRESH (h->cl_auth))
311         goto call_again;
312     }                           /* end of unsuccessful completion */
313   return ct->ct_error.re_status;
314 }
315
316 static void
317 clntunix_geterr (CLIENT *h, struct rpc_err *errp)
318 {
319   struct ct_data *ct = (struct ct_data *) h->cl_private;
320
321   *errp = ct->ct_error;
322 }
323
324 static bool_t
325 clntunix_freeres (cl, xdr_res, res_ptr)
326      CLIENT *cl;
327      xdrproc_t xdr_res;
328      caddr_t res_ptr;
329 {
330   struct ct_data *ct = (struct ct_data *) cl->cl_private;
331   XDR *xdrs = &(ct->ct_xdrs);
332
333   xdrs->x_op = XDR_FREE;
334   return (*xdr_res) (xdrs, res_ptr);
335 }
336
337 static void
338 clntunix_abort ()
339 {
340 }
341
342 static bool_t
343 clntunix_control (CLIENT *cl, int request, char *info)
344 {
345   struct ct_data *ct = (struct ct_data *) cl->cl_private;
346
347
348   switch (request)
349     {
350     case CLSET_FD_CLOSE:
351       ct->ct_closeit = TRUE;
352       break;
353     case CLSET_FD_NCLOSE:
354       ct->ct_closeit = FALSE;
355       break;
356     case CLSET_TIMEOUT:
357       ct->ct_wait = *(struct timeval *) info;
358       break;
359     case CLGET_TIMEOUT:
360       *(struct timeval *) info = ct->ct_wait;
361       break;
362     case CLGET_SERVER_ADDR:
363       *(struct sockaddr_un *) info = ct->ct_addr;
364       break;
365     case CLGET_FD:
366       *(int *)info = ct->ct_sock;
367       break;
368     case CLGET_XID:
369       /*
370        * use the knowledge that xid is the
371        * first element in the call structure *.
372        * This will get the xid of the PREVIOUS call
373        */
374       *(u_long *) info = ntohl (*(u_long *)ct->ct_mcall);
375       break;
376     case CLSET_XID:
377       /* This will set the xid of the NEXT call */
378       *(u_long *) ct->ct_mcall =  htonl (*(u_long *)info - 1);
379       /* decrement by 1 as clntunix_call() increments once */
380     case CLGET_VERS:
381       /*
382        * This RELIES on the information that, in the call body,
383        * the version number field is the fifth field from the
384        * begining of the RPC header. MUST be changed if the
385        * call_struct is changed
386        */
387       *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
388                                              + 4 * BYTES_PER_XDR_UNIT));
389       break;
390     case CLSET_VERS:
391       *(u_long *) (ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT)
392         = htonl (*(u_long *) info);
393       break;
394     case CLGET_PROG:
395       /*
396        * This RELIES on the information that, in the call body,
397        * the program number field is the  field from the
398        * begining of the RPC header. MUST be changed if the
399        * call_struct is changed
400        */
401       *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
402                                              + 3 * BYTES_PER_XDR_UNIT));
403       break;
404     case CLSET_PROG:
405       *(u_long *) (ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT)
406         = htonl(*(u_long *) info);
407       break;
408     /* The following are only possible with TI-RPC */
409     case CLGET_RETRY_TIMEOUT:
410     case CLSET_RETRY_TIMEOUT:
411     case CLGET_SVC_ADDR:
412     case CLSET_SVC_ADDR:
413     case CLSET_PUSH_TIMOD:
414     case CLSET_POP_TIMOD:
415     default:
416       return FALSE;
417     }
418   return TRUE;
419 }
420
421
422 static void
423 clntunix_destroy (CLIENT *h)
424 {
425   struct ct_data *ct =
426   (struct ct_data *) h->cl_private;
427
428   if (ct->ct_closeit)
429     {
430       (void) __close (ct->ct_sock);
431     }
432   XDR_DESTROY (&(ct->ct_xdrs));
433   mem_free ((caddr_t) ct, sizeof (struct ct_data));
434   mem_free ((caddr_t) h, sizeof (CLIENT));
435 }
436
437 #ifdef SCM_CREDENTIALS
438 struct cmessage {
439   struct cmsghdr cmsg;
440   struct ucred cmcred;
441 };
442 #endif
443
444 static int
445 __msgread (int sock, void *buf, size_t cnt)
446 {
447   struct iovec iov[1];
448   struct msghdr msg;
449 #ifdef SCM_CREDENTIALS
450   struct cmessage cm;
451 #endif
452
453   iov[0].iov_base = buf;
454   iov[0].iov_len = cnt;
455
456   msg.msg_iov = iov;
457   msg.msg_iovlen = 1;
458   msg.msg_name = NULL;
459   msg.msg_namelen = 0;
460 #ifdef SCM_CREDENTIALS
461   msg.msg_control = (caddr_t)&cm;
462   msg.msg_controllen = sizeof(struct cmessage);
463 #endif
464   msg.msg_flags = 0;
465
466 #ifdef SO_PASSCRED
467   {
468     int on = 1;
469     if (setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
470       return -1;
471   }
472 #endif
473
474   return recvmsg (sock, &msg, 0);
475 }
476
477 static int
478 __msgwrite (int sock, void *buf, size_t cnt)
479 {
480 #ifndef SCM_CREDENTIALS
481   /* We cannot implement this reliably.  */
482   __set_errno (ENOSYS);
483   return -1;
484 #else
485   struct iovec iov[1];
486   struct msghdr msg;
487   struct cmessage cm;
488
489   iov[0].iov_base = buf;
490   iov[0].iov_len = cnt;
491
492   cm.cmsg.cmsg_type = SCM_CREDENTIALS;
493   cm.cmsg.cmsg_level = SOL_SOCKET;
494   cm.cmsg.cmsg_len = sizeof (struct cmessage);
495   /* XXX I'm not sure, if gete?id() is always correct, or if we should use
496      get?id(). But since keyserv needs geteuid(), we have no other chance.
497      It would be much better, if the kernel could pass both to the server. */
498   cm.cmcred.pid = __getpid ();
499   cm.cmcred.uid = __geteuid ();
500   cm.cmcred.gid = __getegid ();
501
502   msg.msg_iov = iov;
503   msg.msg_iovlen = 1;
504   msg.msg_name = NULL;
505   msg.msg_namelen = 0;
506   msg.msg_control = (caddr_t) &cm;
507   msg.msg_controllen = sizeof (struct cmessage);
508   msg.msg_flags = 0;
509
510   return sendmsg (sock, &msg, 0);
511 #endif
512 }
513
514
515 /*
516  * Interface between xdr serializer and unix connection.
517  * Behaves like the system calls, read & write, but keeps some error state
518  * around for the rpc level.
519  */
520 static int
521 readunix (char *ctptr, char *buf, int len)
522 {
523   struct ct_data *ct = (struct ct_data *) ctptr;
524   struct pollfd fd;
525   int milliseconds = ((ct->ct_wait.tv_sec * 1000)
526                       + (ct->ct_wait.tv_usec / 1000));
527
528   if (len == 0)
529     return 0;
530
531   fd.fd = ct->ct_sock;
532   fd.events = POLLIN;
533   while (TRUE)
534     {
535       switch (__poll (&fd, 1, milliseconds))
536         {
537         case 0:
538           ct->ct_error.re_status = RPC_TIMEDOUT;
539           return -1;
540
541         case -1:
542           if (errno == EINTR)
543             continue;
544           ct->ct_error.re_status = RPC_CANTRECV;
545           ct->ct_error.re_errno = errno;
546           return -1;
547         }
548       break;
549     }
550   switch (len = __msgread (ct->ct_sock, buf, len))
551     {
552
553     case 0:
554       /* premature eof */
555       ct->ct_error.re_errno = ECONNRESET;
556       ct->ct_error.re_status = RPC_CANTRECV;
557       len = -1;                 /* it's really an error */
558       break;
559
560     case -1:
561       ct->ct_error.re_errno = errno;
562       ct->ct_error.re_status = RPC_CANTRECV;
563       break;
564     }
565   return len;
566 }
567
568 static int
569 writeunix (char *ctptr, char *buf, int len)
570 {
571   int i, cnt;
572   struct ct_data *ct = (struct ct_data *) ctptr;
573
574   for (cnt = len; cnt > 0; cnt -= i, buf += i)
575     {
576       if ((i = __msgwrite (ct->ct_sock, buf, cnt)) == -1)
577         {
578           ct->ct_error.re_errno = errno;
579           ct->ct_error.re_status = RPC_CANTSEND;
580           return -1;
581         }
582     }
583   return len;
584 }