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