OSDN Git Service

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