OSDN Git Service

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