Localize rpcgen
[platform/upstream/glibc.git] / sunrpc / svc_unix.c
1 /*
2  * svc_unix.c, Server side for TCP/IP based RPC.
3  *
4  * Copyright (C) 2012-2013 Free Software Foundation, Inc.
5  * This file is part of the GNU C Library.
6  *
7  * The GNU C Library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * The GNU C Library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with the GNU C Library; if not, see
19  * <http://www.gnu.org/licenses/>.
20  *
21  * Copyright (c) 2010, Oracle America, Inc.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions are
25  * met:
26  *
27  *     * Redistributions of source code must retain the above copyright
28  *       notice, this list of conditions and the following disclaimer.
29  *     * Redistributions in binary form must reproduce the above
30  *       copyright notice, this list of conditions and the following
31  *       disclaimer in the documentation and/or other materials
32  *       provided with the distribution.
33  *     * Neither the name of the "Oracle America, Inc." nor the names of its
34  *       contributors may be used to endorse or promote products derived
35  *       from this software without specific prior written permission.
36  *
37  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
38  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
39  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
40  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
41  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
42  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
44  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
45  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
46  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
47  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
48  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49  *
50  * Actually implements two flavors of transporter -
51  * a unix rendezvouser (a listener and connection establisher)
52  * and a record/unix stream.
53  */
54
55 #include <stdio.h>
56 #include <unistd.h>
57 #include <string.h>
58 #include <rpc/rpc.h>
59 #include <rpc/svc.h>
60 #include <sys/socket.h>
61 #include <sys/uio.h>
62 #include <sys/poll.h>
63 #include <errno.h>
64 #include <stdlib.h>
65 #include <libintl.h>
66 #include <wchar.h>
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) __attribute__ ((__noreturn__));
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, SOMAXCONN) != 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       __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
189       mem_free (r, sizeof (*r));
190       mem_free (xprt, sizeof (SVCXPRT));
191       return NULL;
192     }
193   r->sendsize = sendsize;
194   r->recvsize = recvsize;
195   xprt->xp_p2 = NULL;
196   xprt->xp_p1 = (caddr_t) r;
197   xprt->xp_verf = _null_auth;
198   xprt->xp_ops = &svcunix_rendezvous_op;
199   xprt->xp_port = -1;
200   xprt->xp_sock = sock;
201   xprt_register (xprt);
202   return xprt;
203 }
204 libc_hidden_nolink_sunrpc (svcunix_create, GLIBC_2_1)
205
206 /*
207  * Like svunix_create(), except the routine takes any *open* UNIX file
208  * descriptor as its first input.
209  */
210 SVCXPRT *
211 svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
212 {
213   return makefd_xprt (fd, sendsize, recvsize);
214 }
215 libc_hidden_nolink_sunrpc (svcunixfd_create, GLIBC_2_1)
216
217 static SVCXPRT *
218 internal_function
219 makefd_xprt (int fd, u_int sendsize, u_int recvsize)
220 {
221   SVCXPRT *xprt;
222   struct unix_conn *cd;
223
224   xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
225   cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
226   if (xprt == (SVCXPRT *) NULL || cd == (struct unix_conn *) NULL)
227     {
228       (void) __fxprintf (NULL, "%s: %s", "svc_unix: makefd_xprt",
229                          _("out of memory\n"));
230       mem_free (xprt, sizeof (SVCXPRT));
231       mem_free (cd, sizeof (struct unix_conn));
232       return NULL;
233     }
234   cd->strm_stat = XPRT_IDLE;
235   xdrrec_create (&(cd->xdrs), sendsize, recvsize,
236                  (caddr_t) xprt, readunix, writeunix);
237   xprt->xp_p2 = NULL;
238   xprt->xp_p1 = (caddr_t) cd;
239   xprt->xp_verf.oa_base = cd->verf_body;
240   xprt->xp_addrlen = 0;
241   xprt->xp_ops = &svcunix_op;   /* truly deals with calls */
242   xprt->xp_port = 0;            /* this is a connection, not a rendezvouser */
243   xprt->xp_sock = fd;
244   xprt_register (xprt);
245   return xprt;
246 }
247
248 static bool_t
249 rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg)
250 {
251   int sock;
252   struct unix_rendezvous *r;
253   struct sockaddr_un addr;
254   struct sockaddr_in in_addr;
255   socklen_t len;
256
257   r = (struct unix_rendezvous *) xprt->xp_p1;
258 again:
259   len = sizeof (struct sockaddr_un);
260   if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
261     {
262       if (errno == EINTR)
263         goto again;
264       __svc_accept_failed ();
265       return FALSE;
266     }
267   /*
268    * make a new transporter (re-uses xprt)
269    */
270   memset (&in_addr, '\0', sizeof (in_addr));
271   in_addr.sin_family = AF_UNIX;
272   xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
273   memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr));
274   xprt->xp_addrlen = len;
275   return FALSE;         /* there is never an rpc msg to be processed */
276 }
277
278 static enum xprt_stat
279 rendezvous_stat (SVCXPRT *xprt)
280 {
281   return XPRT_IDLE;
282 }
283
284 static void
285 svcunix_destroy (SVCXPRT *xprt)
286 {
287   struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
288
289   xprt_unregister (xprt);
290   __close (xprt->xp_sock);
291   if (xprt->xp_port != 0)
292     {
293       /* a rendezvouser socket */
294       xprt->xp_port = 0;
295     }
296   else
297     {
298       /* an actual connection socket */
299       XDR_DESTROY (&(cd->xdrs));
300     }
301   mem_free ((caddr_t) cd, sizeof (struct unix_conn));
302   mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
303 }
304
305 #ifdef SCM_CREDENTIALS
306 struct cmessage {
307   struct cmsghdr cmsg;
308   struct ucred cmcred;
309   /* hack to make sure we have enough memory */
310   char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
311 };
312
313 /* XXX This is not thread safe, but since the main functions in svc.c
314    and the rpcgen generated *_svc functions for the daemon are also not
315    thread safe and uses static global variables, it doesn't matter. */
316 static struct cmessage cm;
317 #endif
318
319 static int
320 __msgread (int sock, void *data, size_t cnt)
321 {
322   struct iovec iov;
323   struct msghdr msg;
324   int len;
325
326   iov.iov_base = data;
327   iov.iov_len = cnt;
328
329   msg.msg_iov = &iov;
330   msg.msg_iovlen = 1;
331   msg.msg_name = NULL;
332   msg.msg_namelen = 0;
333 #ifdef SCM_CREDENTIALS
334   msg.msg_control = (caddr_t) &cm;
335   msg.msg_controllen = sizeof (struct cmessage);
336 #endif
337   msg.msg_flags = 0;
338
339 #ifdef SO_PASSCRED
340   {
341     int on = 1;
342     if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
343       return -1;
344   }
345 #endif
346
347  restart:
348   len = __recvmsg (sock, &msg, 0);
349   if (len >= 0)
350     {
351       if (msg.msg_flags & MSG_CTRUNC || len == 0)
352         return 0;
353       else
354         return len;
355     }
356   if (errno == EINTR)
357     goto restart;
358   return -1;
359 }
360
361 static int
362 __msgwrite (int sock, void *data, size_t cnt)
363 {
364 #ifndef SCM_CREDENTIALS
365   /* We cannot implement this reliably.  */
366   __set_errno (ENOSYS);
367   return -1;
368 #else
369   struct iovec iov;
370   struct msghdr msg;
371   struct cmsghdr *cmsg = &cm.cmsg;
372   struct ucred cred;
373   int len;
374
375   /* XXX I'm not sure, if gete?id() is always correct, or if we should use
376      get?id(). But since keyserv needs geteuid(), we have no other chance.
377      It would be much better, if the kernel could pass both to the server. */
378   cred.pid = __getpid ();
379   cred.uid = __geteuid ();
380   cred.gid = __getegid ();
381
382   memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
383   cmsg->cmsg_level = SOL_SOCKET;
384   cmsg->cmsg_type = SCM_CREDENTIALS;
385   cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
386
387   iov.iov_base = data;
388   iov.iov_len = cnt;
389
390   msg.msg_iov = &iov;
391   msg.msg_iovlen = 1;
392   msg.msg_name = NULL;
393   msg.msg_namelen = 0;
394   msg.msg_control = cmsg;
395   msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
396   msg.msg_flags = 0;
397
398  restart:
399   len = __sendmsg (sock, &msg, 0);
400   if (len >= 0)
401     return len;
402   if (errno == EINTR)
403     goto restart;
404   return -1;
405
406 #endif
407 }
408
409 /*
410  * reads data from the unix connection.
411  * any error is fatal and the connection is closed.
412  * (And a read of zero bytes is a half closed stream => error.)
413  */
414 static int
415 readunix (char *xprtptr, char *buf, int len)
416 {
417   SVCXPRT *xprt = (SVCXPRT *) xprtptr;
418   int sock = xprt->xp_sock;
419   int milliseconds = 35 * 1000;
420   struct pollfd pollfd;
421
422   do
423     {
424       pollfd.fd = sock;
425       pollfd.events = POLLIN;
426       switch (__poll (&pollfd, 1, milliseconds))
427         {
428         case -1:
429           if (errno == EINTR)
430             continue;
431           /*FALLTHROUGH*/
432         case 0:
433           goto fatal_err;
434         default:
435           if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
436               || (pollfd.revents & POLLNVAL))
437             goto fatal_err;
438           break;
439         }
440     }
441   while ((pollfd.revents & POLLIN) == 0);
442
443   if ((len = __msgread (sock, buf, len)) > 0)
444     return len;
445
446  fatal_err:
447   ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
448   return -1;
449 }
450
451 /*
452  * writes data to the unix connection.
453  * Any error is fatal and the connection is closed.
454  */
455 static int
456 writeunix (char *xprtptr, char * buf, int len)
457 {
458   SVCXPRT *xprt = (SVCXPRT *) xprtptr;
459   int i, cnt;
460
461   for (cnt = len; cnt > 0; cnt -= i, buf += i)
462     {
463       if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
464         {
465           ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
466           return -1;
467         }
468     }
469   return len;
470 }
471
472 static enum xprt_stat
473 svcunix_stat (SVCXPRT *xprt)
474 {
475   struct unix_conn *cd =
476   (struct unix_conn *) (xprt->xp_p1);
477
478   if (cd->strm_stat == XPRT_DIED)
479     return XPRT_DIED;
480   if (!xdrrec_eof (&(cd->xdrs)))
481     return XPRT_MOREREQS;
482   return XPRT_IDLE;
483 }
484
485 static bool_t
486 svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
487 {
488   struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
489   XDR *xdrs = &(cd->xdrs);
490
491   xdrs->x_op = XDR_DECODE;
492   xdrrec_skiprecord (xdrs);
493   if (xdr_callmsg (xdrs, msg))
494     {
495       cd->x_id = msg->rm_xid;
496       /* set up verifiers */
497 #ifdef SCM_CREDENTIALS
498       msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
499       msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
500       msg->rm_call.cb_verf.oa_length = sizeof (cm);
501 #endif
502       return TRUE;
503     }
504   cd->strm_stat = XPRT_DIED;    /* XXXX */
505   return FALSE;
506 }
507
508 static bool_t
509 svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
510 {
511   return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
512                       args_ptr);
513 }
514
515 static bool_t
516 svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
517 {
518   XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
519
520   xdrs->x_op = XDR_FREE;
521   return (*xdr_args) (xdrs, args_ptr);
522 }
523
524 static bool_t
525 svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
526 {
527   struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
528   XDR *xdrs = &(cd->xdrs);
529   bool_t stat;
530
531   xdrs->x_op = XDR_ENCODE;
532   msg->rm_xid = cd->x_id;
533   stat = xdr_replymsg (xdrs, msg);
534   (void) xdrrec_endofrecord (xdrs, TRUE);
535   return stat;
536 }