OSDN Git Service

3f10117e515c9538706e019eac89cfd99f091cf4
[uclinux-h8/uClibc.git] / libc / inet / rpc / svc_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  * svc_unix.c, Server side for TCP/IP based RPC.
32  *
33  * Copyright (C) 1984, Sun Microsystems, Inc.
34  *
35  * Actually implements two flavors of transporter -
36  * a unix rendezvouser (a listener and connection establisher)
37  * and a record/unix stream.
38  */
39
40 #define xdrrec_create __xdrrec_create
41 #define xdrrec_endofrecord __xdrrec_endofrecord
42 #define xdrrec_skiprecord __xdrrec_skiprecord
43 #define xdrrec_eof __xdrrec_eof
44 #define xdr_callmsg __xdr_callmsg
45 #define xdr_replymsg __xdr_replymsg
46 #define xprt_register __xprt_register
47 #define getegid __getegid
48 #define geteuid __geteuid
49
50 #define __FORCE_GLIBC
51 #include <features.h>
52
53 #include <stdio.h>
54 #include <unistd.h>
55 #include <string.h>
56 #include <rpc/rpc.h>
57 #include <rpc/svc.h>
58 #include <sys/socket.h>
59 #include <sys/uio.h>
60 #include <sys/poll.h>
61 #include <errno.h>
62 #include <stdlib.h>
63
64 #ifdef USE_IN_LIBIO
65 # include <wchar.h>
66 #endif
67
68 /*
69  * Ops vector for AF_UNIX based rpc service handle
70  */
71 static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
72 static enum xprt_stat svcunix_stat (SVCXPRT *);
73 static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
74 static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
75 static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
76 static void svcunix_destroy (SVCXPRT *);
77
78 static const struct xp_ops svcunix_op =
79 {
80   svcunix_recv,
81   svcunix_stat,
82   svcunix_getargs,
83   svcunix_reply,
84   svcunix_freeargs,
85   svcunix_destroy
86 };
87
88 /*
89  * Ops vector for AF_UNIX rendezvous handler
90  */
91 static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
92 static enum xprt_stat rendezvous_stat (SVCXPRT *);
93 static void svcunix_rendezvous_abort (void);
94
95 /* This function makes sure abort() relocation goes through PLT
96    and thus can be lazy bound.  */
97 static void
98 svcunix_rendezvous_abort (void)
99 {
100   abort ();
101 };
102
103 static const struct xp_ops svcunix_rendezvous_op =
104 {
105   rendezvous_request,
106   rendezvous_stat,
107   (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
108   (bool_t (*) (SVCXPRT *, struct rpc_msg *)) svcunix_rendezvous_abort,
109   (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
110   svcunix_destroy
111 };
112
113 static int readunix (char*, char *, int);
114 static int writeunix (char *, char *, int);
115 static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
116
117 struct unix_rendezvous {        /* kept in xprt->xp_p1 */
118   u_int sendsize;
119   u_int recvsize;
120 };
121
122 struct unix_conn {              /* kept in xprt->xp_p1 */
123   enum xprt_stat strm_stat;
124   u_long x_id;
125   XDR xdrs;
126   char verf_body[MAX_AUTH_BYTES];
127 };
128
129 /*
130  * Usage:
131  *      xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
132  *
133  * Creates, registers, and returns a (rpc) unix based transporter.
134  * Once *xprt is initialized, it is registered as a transporter
135  * see (svc.h, xprt_register).  This routine returns
136  * a NULL if a problem occurred.
137  *
138  * If sock<0 then a socket is created, else sock is used.
139  * If the socket, sock is not bound to a port then svcunix_create
140  * binds it to an arbitrary port.  The routine then starts a unix
141  * listener on the socket's associated port.  In any (successful) case,
142  * xprt->xp_sock is the registered socket number and xprt->xp_port is the
143  * associated port number.
144  *
145  * Since unix streams do buffered io similar to stdio, the caller can specify
146  * how big the send and receive buffers are via the second and third parms;
147  * 0 => use the system default.
148  */
149 SVCXPRT *
150 svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
151 {
152   bool_t madesock = FALSE;
153   SVCXPRT *xprt;
154   struct unix_rendezvous *r;
155   struct sockaddr_un addr;
156   socklen_t len = sizeof (struct sockaddr_in);
157
158   if (sock == RPC_ANYSOCK)
159     {
160       if ((sock = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
161         {
162           __perror (_("svc_unix.c - AF_UNIX socket creation problem"));
163           return (SVCXPRT *) NULL;
164         }
165       madesock = TRUE;
166     }
167   __memset (&addr, '\0', sizeof (addr));
168   addr.sun_family = AF_UNIX;
169   len = __strlen (path) + 1;
170   __memcpy (addr.sun_path, path, len);
171   len += sizeof (addr.sun_family);
172
173   bind (sock, (struct sockaddr *) &addr, len);
174
175   if (getsockname (sock, (struct sockaddr *) &addr, &len) != 0
176       || listen (sock, 2) != 0)
177     {
178       __perror (_("svc_unix.c - cannot getsockname or listen"));
179       if (madesock)
180         __close (sock);
181       return (SVCXPRT *) NULL;
182     }
183
184   r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
185   xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
186   if (r == NULL || xprt == NULL)
187     {
188 #ifdef USE_IN_LIBIO
189       if (_IO_fwide (stderr, 0) > 0)
190         __fwprintf (stderr, L"%s", _("svcunix_create: out of memory\n"));
191       else
192 #endif
193         fputs (_("svcunix_create: out of memory\n"), stderr);
194       mem_free (r, sizeof (*r));
195       mem_free (xprt, sizeof (SVCXPRT));
196       return NULL;
197     }
198   r->sendsize = sendsize;
199   r->recvsize = recvsize;
200   xprt->xp_p2 = NULL;
201   xprt->xp_p1 = (caddr_t) r;
202   xprt->xp_verf = _null_auth;
203   xprt->xp_ops = &svcunix_rendezvous_op;
204   xprt->xp_port = -1;
205   xprt->xp_sock = sock;
206   xprt_register (xprt);
207   return xprt;
208 }
209
210 /*
211  * Like svunix_create(), except the routine takes any *open* UNIX file
212  * descriptor as its first input.
213  */
214 SVCXPRT *
215 svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
216 {
217   return makefd_xprt (fd, sendsize, recvsize);
218 }
219
220 static SVCXPRT *
221 internal_function
222 makefd_xprt (int fd, u_int sendsize, u_int recvsize)
223 {
224   SVCXPRT *xprt;
225   struct unix_conn *cd;
226
227   xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
228   cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
229   if (xprt == (SVCXPRT *) NULL || cd == (struct unix_conn *) NULL)
230     {
231 #ifdef USE_IN_LIBIO
232       if (_IO_fwide (stderr, 0) > 0)
233         (void) __fwprintf (stderr, L"%s",
234                            _("svc_unix: makefd_xprt: out of memory\n"));
235       else
236 #endif
237         (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
238       mem_free (xprt, sizeof (SVCXPRT));
239       mem_free (cd, sizeof (struct unix_conn));
240       return NULL;
241     }
242   cd->strm_stat = XPRT_IDLE;
243   xdrrec_create (&(cd->xdrs), sendsize, recvsize,
244                  (caddr_t) xprt, readunix, writeunix);
245   xprt->xp_p2 = NULL;
246   xprt->xp_p1 = (caddr_t) cd;
247   xprt->xp_verf.oa_base = cd->verf_body;
248   xprt->xp_addrlen = 0;
249   xprt->xp_ops = &svcunix_op;   /* truly deals with calls */
250   xprt->xp_port = 0;            /* this is a connection, not a rendezvouser */
251   xprt->xp_sock = fd;
252   xprt_register (xprt);
253   return xprt;
254 }
255
256 static bool_t
257 rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg)
258 {
259   int sock;
260   struct unix_rendezvous *r;
261   struct sockaddr_un addr;
262   struct sockaddr_in in_addr;
263   socklen_t len;
264
265   r = (struct unix_rendezvous *) xprt->xp_p1;
266 again:
267   len = sizeof (struct sockaddr_un);
268   if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
269     {
270       if (errno == EINTR)
271         goto again;
272       return FALSE;
273     }
274   /*
275    * make a new transporter (re-uses xprt)
276    */
277   __memset (&in_addr, '\0', sizeof (in_addr));
278   in_addr.sin_family = AF_UNIX;
279   xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
280   __memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr));
281   xprt->xp_addrlen = len;
282   return FALSE;         /* there is never an rpc msg to be processed */
283 }
284
285 static enum xprt_stat
286 rendezvous_stat (SVCXPRT *xprt)
287 {
288   return XPRT_IDLE;
289 }
290
291 static void
292 svcunix_destroy (SVCXPRT *xprt)
293 {
294   struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
295
296   xprt_unregister (xprt);
297   __close (xprt->xp_sock);
298   if (xprt->xp_port != 0)
299     {
300       /* a rendezvouser socket */
301       xprt->xp_port = 0;
302     }
303   else
304     {
305       /* an actual connection socket */
306       XDR_DESTROY (&(cd->xdrs));
307     }
308   mem_free ((caddr_t) cd, sizeof (struct unix_conn));
309   mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
310 }
311
312 #ifdef SCM_CREDENTIALS
313 struct cmessage {
314   struct cmsghdr cmsg;
315   struct ucred cmcred;
316   /* hack to make sure we have enough memory */
317   char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
318 };
319
320 /* XXX This is not thread safe, but since the main functions in svc.c
321    and the rpcgen generated *_svc functions for the daemon are also not
322    thread safe and uses static global variables, it doesn't matter. */
323 static struct cmessage cm;
324 #endif
325
326 static int
327 __msgread (int sock, void *data, size_t cnt)
328 {
329   struct iovec iov;
330   struct msghdr msg;
331   int len;
332
333   iov.iov_base = data;
334   iov.iov_len = cnt;
335
336   msg.msg_iov = &iov;
337   msg.msg_iovlen = 1;
338   msg.msg_name = NULL;
339   msg.msg_namelen = 0;
340 #ifdef SCM_CREDENTIALS
341   msg.msg_control = (caddr_t) &cm;
342   msg.msg_controllen = sizeof (struct cmessage);
343 #endif
344   msg.msg_flags = 0;
345
346 #ifdef SO_PASSCRED
347   {
348     int on = 1;
349     if (setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
350       return -1;
351   }
352 #endif
353
354  restart:
355   len = recvmsg (sock, &msg, 0);
356   if (len >= 0)
357     {
358       if (msg.msg_flags & MSG_CTRUNC || len == 0)
359         return 0;
360       else
361         return len;
362     }
363   if (errno == EINTR)
364     goto restart;
365   return -1;
366 }
367
368 static int
369 __msgwrite (int sock, void *data, size_t cnt)
370 {
371 #ifndef SCM_CREDENTIALS
372   /* We cannot implement this reliably.  */
373   __set_errno (ENOSYS);
374   return -1;
375 #else
376   struct iovec iov;
377   struct msghdr msg;
378   struct cmsghdr *cmsg = &cm.cmsg;
379   struct ucred cred;
380   int len;
381
382   /* XXX I'm not sure, if gete?id() is always correct, or if we should use
383      get?id(). But since keyserv needs geteuid(), we have no other chance.
384      It would be much better, if the kernel could pass both to the server. */
385   cred.pid = __getpid ();
386   cred.uid = geteuid ();
387   cred.gid = getegid ();
388
389   __memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
390   cmsg->cmsg_level = SOL_SOCKET;
391   cmsg->cmsg_type = SCM_CREDENTIALS;
392   cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
393
394   iov.iov_base = data;
395   iov.iov_len = cnt;
396
397   msg.msg_iov = &iov;
398   msg.msg_iovlen = 1;
399   msg.msg_name = NULL;
400   msg.msg_namelen = 0;
401   msg.msg_control = cmsg;
402   msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
403   msg.msg_flags = 0;
404
405  restart:
406   len = sendmsg (sock, &msg, 0);
407   if (len >= 0)
408     return len;
409   if (errno == EINTR)
410     goto restart;
411   return -1;
412
413 #endif
414 }
415
416 /*
417  * reads data from the unix connection.
418  * any error is fatal and the connection is closed.
419  * (And a read of zero bytes is a half closed stream => error.)
420  */
421 static int
422 readunix (char *xprtptr, char *buf, int len)
423 {
424   SVCXPRT *xprt = (SVCXPRT *) xprtptr;
425   int sock = xprt->xp_sock;
426   int milliseconds = 35 * 1000;
427   struct pollfd pollfd;
428
429   do
430     {
431       pollfd.fd = sock;
432       pollfd.events = POLLIN;
433       switch (poll (&pollfd, 1, milliseconds))
434         {
435         case -1:
436           if (errno == EINTR)
437             continue;
438           /*FALLTHROUGH*/
439         case 0:
440           goto fatal_err;
441         default:
442           if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
443               || (pollfd.revents & POLLNVAL))
444             goto fatal_err;
445           break;
446         }
447     }
448   while ((pollfd.revents & POLLIN) == 0);
449
450   if ((len = __msgread (sock, buf, len)) > 0)
451     return len;
452
453  fatal_err:
454   ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
455   return -1;
456 }
457
458 /*
459  * writes data to the unix connection.
460  * Any error is fatal and the connection is closed.
461  */
462 static int
463 writeunix (char *xprtptr, char * buf, int len)
464 {
465   SVCXPRT *xprt = (SVCXPRT *) xprtptr;
466   int i, cnt;
467
468   for (cnt = len; cnt > 0; cnt -= i, buf += i)
469     {
470       if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
471         {
472           ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
473           return -1;
474         }
475     }
476   return len;
477 }
478
479 static enum xprt_stat
480 svcunix_stat (SVCXPRT *xprt)
481 {
482   struct unix_conn *cd =
483   (struct unix_conn *) (xprt->xp_p1);
484
485   if (cd->strm_stat == XPRT_DIED)
486     return XPRT_DIED;
487   if (!xdrrec_eof (&(cd->xdrs)))
488     return XPRT_MOREREQS;
489   return XPRT_IDLE;
490 }
491
492 static bool_t
493 svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
494 {
495   struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
496   XDR *xdrs = &(cd->xdrs);
497
498   xdrs->x_op = XDR_DECODE;
499   xdrrec_skiprecord (xdrs);
500   if (xdr_callmsg (xdrs, msg))
501     {
502       cd->x_id = msg->rm_xid;
503       /* set up verifiers */
504 #ifdef SCM_CREDENTIALS
505       msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
506       msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
507       msg->rm_call.cb_verf.oa_length = sizeof (cm);
508 #endif
509       return TRUE;
510     }
511   cd->strm_stat = XPRT_DIED;    /* XXXX */
512   return FALSE;
513 }
514
515 static bool_t
516 svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
517 {
518   return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
519                       args_ptr);
520 }
521
522 static bool_t
523 svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
524 {
525   XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
526
527   xdrs->x_op = XDR_FREE;
528   return (*xdr_args) (xdrs, args_ptr);
529 }
530
531 static bool_t
532 svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
533 {
534   struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
535   XDR *xdrs = &(cd->xdrs);
536   bool_t stat;
537
538   xdrs->x_op = XDR_ENCODE;
539   msg->rm_xid = cd->x_id;
540   stat = xdr_replymsg (xdrs, msg);
541   (void) xdrrec_endofrecord (xdrs, TRUE);
542   return stat;
543 }