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