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