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