Use INTUSE to reference functions and variables inside libc itself.
[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 = 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
215 static enum clnt_stat
216 clntunix_call (h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
217      CLIENT *h;
218      u_long proc;
219      xdrproc_t xdr_args;
220      caddr_t args_ptr;
221      xdrproc_t xdr_results;
222      caddr_t results_ptr;
223      struct timeval timeout;
224 {
225   struct ct_data *ct = (struct ct_data *) h->cl_private;
226   XDR *xdrs = &(ct->ct_xdrs);
227   struct rpc_msg reply_msg;
228   u_long x_id;
229   u_int32_t *msg_x_id = (u_int32_t *) (ct->ct_mcall);   /* yuk */
230   bool_t shipnow;
231   int refreshes = 2;
232
233   if (!ct->ct_waitset)
234     {
235       ct->ct_wait = timeout;
236     }
237
238   shipnow =
239     (xdr_results == (xdrproc_t) 0 && ct->ct_wait.tv_sec == 0
240      && ct->ct_wait.tv_usec == 0) ? FALSE : TRUE;
241
242 call_again:
243   xdrs->x_op = XDR_ENCODE;
244   ct->ct_error.re_status = RPC_SUCCESS;
245   x_id = ntohl (--(*msg_x_id));
246   if ((!XDR_PUTBYTES (xdrs, ct->ct_mcall, ct->ct_mpos)) ||
247       (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
248       (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
249       (!(*xdr_args) (xdrs, args_ptr)))
250     {
251       if (ct->ct_error.re_status == RPC_SUCCESS)
252         ct->ct_error.re_status = RPC_CANTENCODEARGS;
253       (void) INTUSE(xdrrec_endofrecord) (xdrs, TRUE);
254       return ct->ct_error.re_status;
255     }
256   if (!INTUSE(xdrrec_endofrecord) (xdrs, shipnow))
257     return ct->ct_error.re_status = RPC_CANTSEND;
258   if (!shipnow)
259     return RPC_SUCCESS;
260   /*
261    * Hack to provide rpc-based message passing
262    */
263   if (ct->ct_wait.tv_sec == 0 && ct->ct_wait.tv_usec == 0)
264     return ct->ct_error.re_status = RPC_TIMEDOUT;
265
266
267   /*
268    * Keep receiving until we get a valid transaction id
269    */
270   xdrs->x_op = XDR_DECODE;
271   while (TRUE)
272     {
273       reply_msg.acpted_rply.ar_verf = _null_auth;
274       reply_msg.acpted_rply.ar_results.where = NULL;
275       reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)INTUSE(xdr_void);
276       if (!INTUSE(xdrrec_skiprecord) (xdrs))
277         return ct->ct_error.re_status;
278       /* now decode and validate the response header */
279       if (!INTUSE(xdr_replymsg) (xdrs, &reply_msg))
280         {
281           if (ct->ct_error.re_status == RPC_SUCCESS)
282             continue;
283           return ct->ct_error.re_status;
284         }
285       if (reply_msg.rm_xid == x_id)
286         break;
287     }
288
289   /*
290    * process header
291    */
292   _seterr_reply (&reply_msg, &(ct->ct_error));
293   if (ct->ct_error.re_status == RPC_SUCCESS)
294     {
295       if (!AUTH_VALIDATE (h->cl_auth, &reply_msg.acpted_rply.ar_verf))
296         {
297           ct->ct_error.re_status = RPC_AUTHERROR;
298           ct->ct_error.re_why = AUTH_INVALIDRESP;
299         }
300       else if (!(*xdr_results) (xdrs, results_ptr))
301         {
302           if (ct->ct_error.re_status == RPC_SUCCESS)
303             ct->ct_error.re_status = RPC_CANTDECODERES;
304         }
305       /* free verifier ... */
306       if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
307         {
308           xdrs->x_op = XDR_FREE;
309           (void) INTUSE(xdr_opaque_auth) (xdrs,
310                                           &(reply_msg.acpted_rply.ar_verf));
311         }
312     }                           /* end successful completion */
313   else
314     {
315       /* maybe our credentials need to be refreshed ... */
316       if (refreshes-- && AUTH_REFRESH (h->cl_auth))
317         goto call_again;
318     }                           /* end of unsuccessful completion */
319   return ct->ct_error.re_status;
320 }
321
322 static void
323 clntunix_geterr (CLIENT *h, struct rpc_err *errp)
324 {
325   struct ct_data *ct = (struct ct_data *) h->cl_private;
326
327   *errp = ct->ct_error;
328 }
329
330 static bool_t
331 clntunix_freeres (cl, xdr_res, res_ptr)
332      CLIENT *cl;
333      xdrproc_t xdr_res;
334      caddr_t res_ptr;
335 {
336   struct ct_data *ct = (struct ct_data *) cl->cl_private;
337   XDR *xdrs = &(ct->ct_xdrs);
338
339   xdrs->x_op = XDR_FREE;
340   return (*xdr_res) (xdrs, res_ptr);
341 }
342
343 static void
344 clntunix_abort ()
345 {
346 }
347
348 static bool_t
349 clntunix_control (CLIENT *cl, int request, char *info)
350 {
351   struct ct_data *ct = (struct ct_data *) cl->cl_private;
352
353
354   switch (request)
355     {
356     case CLSET_FD_CLOSE:
357       ct->ct_closeit = TRUE;
358       break;
359     case CLSET_FD_NCLOSE:
360       ct->ct_closeit = FALSE;
361       break;
362     case CLSET_TIMEOUT:
363       ct->ct_wait = *(struct timeval *) info;
364       break;
365     case CLGET_TIMEOUT:
366       *(struct timeval *) info = ct->ct_wait;
367       break;
368     case CLGET_SERVER_ADDR:
369       *(struct sockaddr_un *) info = ct->ct_addr;
370       break;
371     case CLGET_FD:
372       *(int *)info = ct->ct_sock;
373       break;
374     case CLGET_XID:
375       /*
376        * use the knowledge that xid is the
377        * first element in the call structure *.
378        * This will get the xid of the PREVIOUS call
379        */
380       *(u_long *) info = ntohl (*(u_long *)ct->ct_mcall);
381       break;
382     case CLSET_XID:
383       /* This will set the xid of the NEXT call */
384       *(u_long *) ct->ct_mcall =  htonl (*(u_long *)info - 1);
385       /* decrement by 1 as clntunix_call() increments once */
386     case CLGET_VERS:
387       /*
388        * This RELIES on the information that, in the call body,
389        * the version number field is the fifth field from the
390        * begining of the RPC header. MUST be changed if the
391        * call_struct is changed
392        */
393       *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
394                                              + 4 * BYTES_PER_XDR_UNIT));
395       break;
396     case CLSET_VERS:
397       *(u_long *) (ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT)
398         = htonl (*(u_long *) info);
399       break;
400     case CLGET_PROG:
401       /*
402        * This RELIES on the information that, in the call body,
403        * the program number field is the  field from the
404        * begining of the RPC header. MUST be changed if the
405        * call_struct is changed
406        */
407       *(u_long *) info = ntohl (*(u_long *) (ct->ct_mcall
408                                              + 3 * BYTES_PER_XDR_UNIT));
409       break;
410     case CLSET_PROG:
411       *(u_long *) (ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT)
412         = htonl(*(u_long *) info);
413       break;
414     /* The following are only possible with TI-RPC */
415     case CLGET_RETRY_TIMEOUT:
416     case CLSET_RETRY_TIMEOUT:
417     case CLGET_SVC_ADDR:
418     case CLSET_SVC_ADDR:
419     case CLSET_PUSH_TIMOD:
420     case CLSET_POP_TIMOD:
421     default:
422       return FALSE;
423     }
424   return TRUE;
425 }
426
427
428 static void
429 clntunix_destroy (CLIENT *h)
430 {
431   struct ct_data *ct =
432   (struct ct_data *) h->cl_private;
433
434   if (ct->ct_closeit)
435     {
436       (void) __close (ct->ct_sock);
437     }
438   XDR_DESTROY (&(ct->ct_xdrs));
439   mem_free ((caddr_t) ct, sizeof (struct ct_data));
440   mem_free ((caddr_t) h, sizeof (CLIENT));
441 }
442
443 static int
444 __msgread (int sock, void *data, size_t cnt)
445 {
446   struct iovec iov;
447   struct msghdr msg;
448 #ifdef SCM_CREDENTIALS
449   static char cm[CMSG_SPACE(sizeof (struct ucred))];
450 #endif
451   int len;
452
453   iov.iov_base = data;
454   iov.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 = CMSG_SPACE(sizeof (struct ucred));
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  restart:
475   len = recvmsg (sock, &msg, 0);
476   if (len >= 0)
477     {
478       if (msg.msg_flags & MSG_CTRUNC || len == 0)
479         return 0;
480       else
481         return len;
482     }
483   if (errno == EINTR)
484     goto restart;
485   return -1;
486 }
487
488 static int
489 __msgwrite (int sock, void *data, size_t cnt)
490 {
491 #ifndef SCM_CREDENTIALS
492   /* We cannot implement this reliably.  */
493   __set_errno (ENOSYS);
494   return -1;
495 #else
496   struct iovec iov;
497   struct msghdr msg;
498   struct cmsghdr *cmsg = alloca (CMSG_SPACE(sizeof (struct ucred)));
499   struct ucred cred;
500   int len;
501
502   /* XXX I'm not sure, if gete?id() is always correct, or if we should use
503      get?id(). But since keyserv needs geteuid(), we have no other chance.
504      It would be much better, if the kernel could pass both to the server. */
505   cred.pid = __getpid ();
506   cred.uid = __geteuid ();
507   cred.gid = __getegid ();
508
509   memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
510   cmsg->cmsg_level = SOL_SOCKET;
511   cmsg->cmsg_type = SCM_CREDENTIALS;
512   cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
513
514   iov.iov_base = data;
515   iov.iov_len = cnt;
516
517   msg.msg_iov = &iov;
518   msg.msg_iovlen = 1;
519   msg.msg_name = NULL;
520   msg.msg_namelen = 0;
521   msg.msg_control = cmsg;
522   msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
523   msg.msg_flags = 0;
524
525  restart:
526   len = sendmsg (sock, &msg, 0);
527   if (len >= 0)
528     return len;
529   if (errno == EINTR)
530     goto restart;
531   return -1;
532
533 #endif
534 }
535
536
537 /*
538  * Interface between xdr serializer and unix connection.
539  * Behaves like the system calls, read & write, but keeps some error state
540  * around for the rpc level.
541  */
542 static int
543 readunix (char *ctptr, char *buf, int len)
544 {
545   struct ct_data *ct = (struct ct_data *) ctptr;
546   struct pollfd fd;
547   int milliseconds = ((ct->ct_wait.tv_sec * 1000)
548                       + (ct->ct_wait.tv_usec / 1000));
549
550   if (len == 0)
551     return 0;
552
553   fd.fd = ct->ct_sock;
554   fd.events = POLLIN;
555   while (TRUE)
556     {
557       switch (__poll (&fd, 1, milliseconds))
558         {
559         case 0:
560           ct->ct_error.re_status = RPC_TIMEDOUT;
561           return -1;
562
563         case -1:
564           if (errno == EINTR)
565             continue;
566           ct->ct_error.re_status = RPC_CANTRECV;
567           ct->ct_error.re_errno = errno;
568           return -1;
569         }
570       break;
571     }
572   switch (len = __msgread (ct->ct_sock, buf, len))
573     {
574
575     case 0:
576       /* premature eof */
577       ct->ct_error.re_errno = ECONNRESET;
578       ct->ct_error.re_status = RPC_CANTRECV;
579       len = -1;                 /* it's really an error */
580       break;
581
582     case -1:
583       ct->ct_error.re_errno = errno;
584       ct->ct_error.re_status = RPC_CANTRECV;
585       break;
586     }
587   return len;
588 }
589
590 static int
591 writeunix (char *ctptr, char *buf, int len)
592 {
593   int i, cnt;
594   struct ct_data *ct = (struct ct_data *) ctptr;
595
596   for (cnt = len; cnt > 0; cnt -= i, buf += i)
597     {
598       if ((i = __msgwrite (ct->ct_sock, buf, cnt)) == -1)
599         {
600           ct->ct_error.re_errno = errno;
601           ct->ct_error.re_status = RPC_CANTSEND;
602           return -1;
603         }
604     }
605   return len;
606 }