Fix "make xcheck" in sunrpc.
[platform/upstream/glibc.git] / sunrpc / svc_unix.c
1 /*
2  * svc_unix.c, Server side for TCP/IP based RPC.
3  *
4  * Copyright (c) 2010, Oracle America, Inc.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above
13  *       copyright notice, this list of conditions and the following
14  *       disclaimer in the documentation and/or other materials
15  *       provided with the distribution.
16  *     * Neither the name of the "Oracle America, Inc." nor the names of its
17  *       contributors may be used to endorse or promote products derived
18  *       from this software without specific prior written permission.
19  *
20  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Actually implements two flavors of transporter -
34  * a unix rendezvouser (a listener and connection establisher)
35  * and a record/unix stream.
36  */
37
38 #include <stdio.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <rpc/rpc.h>
42 #include <rpc/svc.h>
43 #include <sys/socket.h>
44 #include <sys/uio.h>
45 #include <sys/poll.h>
46 #include <errno.h>
47 #include <stdlib.h>
48 #include <libintl.h>
49
50 #ifdef USE_IN_LIBIO
51 # include <wchar.h>
52 #endif
53
54 /*
55  * Ops vector for AF_UNIX based rpc service handle
56  */
57 static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
58 static enum xprt_stat svcunix_stat (SVCXPRT *);
59 static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
60 static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
61 static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
62 static void svcunix_destroy (SVCXPRT *);
63
64 static const struct xp_ops svcunix_op =
65 {
66   svcunix_recv,
67   svcunix_stat,
68   svcunix_getargs,
69   svcunix_reply,
70   svcunix_freeargs,
71   svcunix_destroy
72 };
73
74 /*
75  * Ops vector for AF_UNIX rendezvous handler
76  */
77 static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
78 static enum xprt_stat rendezvous_stat (SVCXPRT *);
79 static void svcunix_rendezvous_abort (void) __attribute__ ((__noreturn__));
80
81 /* This function makes sure abort() relocation goes through PLT
82    and thus can be lazy bound.  */
83 static void
84 svcunix_rendezvous_abort (void)
85 {
86   abort ();
87 };
88
89 static const struct xp_ops svcunix_rendezvous_op =
90 {
91   rendezvous_request,
92   rendezvous_stat,
93   (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
94   (bool_t (*) (SVCXPRT *, struct rpc_msg *)) svcunix_rendezvous_abort,
95   (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
96   svcunix_destroy
97 };
98
99 static int readunix (char*, char *, int);
100 static int writeunix (char *, char *, int);
101 static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
102
103 struct unix_rendezvous {        /* kept in xprt->xp_p1 */
104   u_int sendsize;
105   u_int recvsize;
106 };
107
108 struct unix_conn {              /* kept in xprt->xp_p1 */
109   enum xprt_stat strm_stat;
110   u_long x_id;
111   XDR xdrs;
112   char verf_body[MAX_AUTH_BYTES];
113 };
114
115 /*
116  * Usage:
117  *      xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
118  *
119  * Creates, registers, and returns a (rpc) unix based transporter.
120  * Once *xprt is initialized, it is registered as a transporter
121  * see (svc.h, xprt_register).  This routine returns
122  * a NULL if a problem occurred.
123  *
124  * If sock<0 then a socket is created, else sock is used.
125  * If the socket, sock is not bound to a port then svcunix_create
126  * binds it to an arbitrary port.  The routine then starts a unix
127  * listener on the socket's associated port.  In any (successful) case,
128  * xprt->xp_sock is the registered socket number and xprt->xp_port is the
129  * associated port number.
130  *
131  * Since unix streams do buffered io similar to stdio, the caller can specify
132  * how big the send and receive buffers are via the second and third parms;
133  * 0 => use the system default.
134  */
135 SVCXPRT *
136 svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
137 {
138   bool_t madesock = FALSE;
139   SVCXPRT *xprt;
140   struct unix_rendezvous *r;
141   struct sockaddr_un addr;
142   socklen_t len = sizeof (struct sockaddr_in);
143
144   if (sock == RPC_ANYSOCK)
145     {
146       if ((sock = __socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
147         {
148           perror (_("svc_unix.c - AF_UNIX socket creation problem"));
149           return (SVCXPRT *) NULL;
150         }
151       madesock = TRUE;
152     }
153   memset (&addr, '\0', sizeof (addr));
154   addr.sun_family = AF_UNIX;
155   len = strlen (path) + 1;
156   memcpy (addr.sun_path, path, len);
157   len += sizeof (addr.sun_family);
158
159   __bind (sock, (struct sockaddr *) &addr, len);
160
161   if (__getsockname (sock, (struct sockaddr *) &addr, &len) != 0
162       || __listen (sock, SOMAXCONN) != 0)
163     {
164       perror (_("svc_unix.c - cannot getsockname or listen"));
165       if (madesock)
166         __close (sock);
167       return (SVCXPRT *) NULL;
168     }
169
170   r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
171   xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
172   if (r == NULL || xprt == NULL)
173     {
174       __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
175       mem_free (r, sizeof (*r));
176       mem_free (xprt, sizeof (SVCXPRT));
177       return NULL;
178     }
179   r->sendsize = sendsize;
180   r->recvsize = recvsize;
181   xprt->xp_p2 = NULL;
182   xprt->xp_p1 = (caddr_t) r;
183   xprt->xp_verf = _null_auth;
184   xprt->xp_ops = &svcunix_rendezvous_op;
185   xprt->xp_port = -1;
186   xprt->xp_sock = sock;
187   xprt_register (xprt);
188   return xprt;
189 }
190 libc_hidden_nolink (svcunix_create, GLIBC_2_1)
191
192 /*
193  * Like svunix_create(), except the routine takes any *open* UNIX file
194  * descriptor as its first input.
195  */
196 SVCXPRT *
197 svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
198 {
199   return makefd_xprt (fd, sendsize, recvsize);
200 }
201 libc_hidden_nolink (svcunixfd_create, GLIBC_2_1)
202
203 static SVCXPRT *
204 internal_function
205 makefd_xprt (int fd, u_int sendsize, u_int recvsize)
206 {
207   SVCXPRT *xprt;
208   struct unix_conn *cd;
209
210   xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
211   cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
212   if (xprt == (SVCXPRT *) NULL || cd == (struct unix_conn *) NULL)
213     {
214       (void) __fxprintf (NULL, "%s: %s", "svc_unix: makefd_xprt",
215                          _("out of memory\n"));
216       mem_free (xprt, sizeof (SVCXPRT));
217       mem_free (cd, sizeof (struct unix_conn));
218       return NULL;
219     }
220   cd->strm_stat = XPRT_IDLE;
221   xdrrec_create (&(cd->xdrs), sendsize, recvsize,
222                  (caddr_t) xprt, readunix, writeunix);
223   xprt->xp_p2 = NULL;
224   xprt->xp_p1 = (caddr_t) cd;
225   xprt->xp_verf.oa_base = cd->verf_body;
226   xprt->xp_addrlen = 0;
227   xprt->xp_ops = &svcunix_op;   /* truly deals with calls */
228   xprt->xp_port = 0;            /* this is a connection, not a rendezvouser */
229   xprt->xp_sock = fd;
230   xprt_register (xprt);
231   return xprt;
232 }
233
234 static bool_t
235 rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg)
236 {
237   int sock;
238   struct unix_rendezvous *r;
239   struct sockaddr_un addr;
240   struct sockaddr_in in_addr;
241   socklen_t len;
242
243   r = (struct unix_rendezvous *) xprt->xp_p1;
244 again:
245   len = sizeof (struct sockaddr_un);
246   if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
247     {
248       if (errno == EINTR)
249         goto again;
250       return FALSE;
251     }
252   /*
253    * make a new transporter (re-uses xprt)
254    */
255   memset (&in_addr, '\0', sizeof (in_addr));
256   in_addr.sin_family = AF_UNIX;
257   xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
258   memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr));
259   xprt->xp_addrlen = len;
260   return FALSE;         /* there is never an rpc msg to be processed */
261 }
262
263 static enum xprt_stat
264 rendezvous_stat (SVCXPRT *xprt)
265 {
266   return XPRT_IDLE;
267 }
268
269 static void
270 svcunix_destroy (SVCXPRT *xprt)
271 {
272   struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
273
274   xprt_unregister (xprt);
275   __close (xprt->xp_sock);
276   if (xprt->xp_port != 0)
277     {
278       /* a rendezvouser socket */
279       xprt->xp_port = 0;
280     }
281   else
282     {
283       /* an actual connection socket */
284       XDR_DESTROY (&(cd->xdrs));
285     }
286   mem_free ((caddr_t) cd, sizeof (struct unix_conn));
287   mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
288 }
289
290 #ifdef SCM_CREDENTIALS
291 struct cmessage {
292   struct cmsghdr cmsg;
293   struct ucred cmcred;
294   /* hack to make sure we have enough memory */
295   char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
296 };
297
298 /* XXX This is not thread safe, but since the main functions in svc.c
299    and the rpcgen generated *_svc functions for the daemon are also not
300    thread safe and uses static global variables, it doesn't matter. */
301 static struct cmessage cm;
302 #endif
303
304 static int
305 __msgread (int sock, void *data, size_t cnt)
306 {
307   struct iovec iov;
308   struct msghdr msg;
309   int len;
310
311   iov.iov_base = data;
312   iov.iov_len = cnt;
313
314   msg.msg_iov = &iov;
315   msg.msg_iovlen = 1;
316   msg.msg_name = NULL;
317   msg.msg_namelen = 0;
318 #ifdef SCM_CREDENTIALS
319   msg.msg_control = (caddr_t) &cm;
320   msg.msg_controllen = sizeof (struct cmessage);
321 #endif
322   msg.msg_flags = 0;
323
324 #ifdef SO_PASSCRED
325   {
326     int on = 1;
327     if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
328       return -1;
329   }
330 #endif
331
332  restart:
333   len = __recvmsg (sock, &msg, 0);
334   if (len >= 0)
335     {
336       if (msg.msg_flags & MSG_CTRUNC || len == 0)
337         return 0;
338       else
339         return len;
340     }
341   if (errno == EINTR)
342     goto restart;
343   return -1;
344 }
345
346 static int
347 __msgwrite (int sock, void *data, size_t cnt)
348 {
349 #ifndef SCM_CREDENTIALS
350   /* We cannot implement this reliably.  */
351   __set_errno (ENOSYS);
352   return -1;
353 #else
354   struct iovec iov;
355   struct msghdr msg;
356   struct cmsghdr *cmsg = &cm.cmsg;
357   struct ucred cred;
358   int len;
359
360   /* XXX I'm not sure, if gete?id() is always correct, or if we should use
361      get?id(). But since keyserv needs geteuid(), we have no other chance.
362      It would be much better, if the kernel could pass both to the server. */
363   cred.pid = __getpid ();
364   cred.uid = __geteuid ();
365   cred.gid = __getegid ();
366
367   memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
368   cmsg->cmsg_level = SOL_SOCKET;
369   cmsg->cmsg_type = SCM_CREDENTIALS;
370   cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
371
372   iov.iov_base = data;
373   iov.iov_len = cnt;
374
375   msg.msg_iov = &iov;
376   msg.msg_iovlen = 1;
377   msg.msg_name = NULL;
378   msg.msg_namelen = 0;
379   msg.msg_control = cmsg;
380   msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
381   msg.msg_flags = 0;
382
383  restart:
384   len = __sendmsg (sock, &msg, 0);
385   if (len >= 0)
386     return len;
387   if (errno == EINTR)
388     goto restart;
389   return -1;
390
391 #endif
392 }
393
394 /*
395  * reads data from the unix connection.
396  * any error is fatal and the connection is closed.
397  * (And a read of zero bytes is a half closed stream => error.)
398  */
399 static int
400 readunix (char *xprtptr, char *buf, int len)
401 {
402   SVCXPRT *xprt = (SVCXPRT *) xprtptr;
403   int sock = xprt->xp_sock;
404   int milliseconds = 35 * 1000;
405   struct pollfd pollfd;
406
407   do
408     {
409       pollfd.fd = sock;
410       pollfd.events = POLLIN;
411       switch (__poll (&pollfd, 1, milliseconds))
412         {
413         case -1:
414           if (errno == EINTR)
415             continue;
416           /*FALLTHROUGH*/
417         case 0:
418           goto fatal_err;
419         default:
420           if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
421               || (pollfd.revents & POLLNVAL))
422             goto fatal_err;
423           break;
424         }
425     }
426   while ((pollfd.revents & POLLIN) == 0);
427
428   if ((len = __msgread (sock, buf, len)) > 0)
429     return len;
430
431  fatal_err:
432   ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
433   return -1;
434 }
435
436 /*
437  * writes data to the unix connection.
438  * Any error is fatal and the connection is closed.
439  */
440 static int
441 writeunix (char *xprtptr, char * buf, int len)
442 {
443   SVCXPRT *xprt = (SVCXPRT *) xprtptr;
444   int i, cnt;
445
446   for (cnt = len; cnt > 0; cnt -= i, buf += i)
447     {
448       if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
449         {
450           ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
451           return -1;
452         }
453     }
454   return len;
455 }
456
457 static enum xprt_stat
458 svcunix_stat (SVCXPRT *xprt)
459 {
460   struct unix_conn *cd =
461   (struct unix_conn *) (xprt->xp_p1);
462
463   if (cd->strm_stat == XPRT_DIED)
464     return XPRT_DIED;
465   if (!xdrrec_eof (&(cd->xdrs)))
466     return XPRT_MOREREQS;
467   return XPRT_IDLE;
468 }
469
470 static bool_t
471 svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
472 {
473   struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
474   XDR *xdrs = &(cd->xdrs);
475
476   xdrs->x_op = XDR_DECODE;
477   xdrrec_skiprecord (xdrs);
478   if (xdr_callmsg (xdrs, msg))
479     {
480       cd->x_id = msg->rm_xid;
481       /* set up verifiers */
482 #ifdef SCM_CREDENTIALS
483       msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
484       msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
485       msg->rm_call.cb_verf.oa_length = sizeof (cm);
486 #endif
487       return TRUE;
488     }
489   cd->strm_stat = XPRT_DIED;    /* XXXX */
490   return FALSE;
491 }
492
493 static bool_t
494 svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
495 {
496   return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
497                       args_ptr);
498 }
499
500 static bool_t
501 svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
502 {
503   XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
504
505   xdrs->x_op = XDR_FREE;
506   return (*xdr_args) (xdrs, args_ptr);
507 }
508
509 static bool_t
510 svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
511 {
512   struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
513   XDR *xdrs = &(cd->xdrs);
514   bool_t stat;
515
516   xdrs->x_op = XDR_ENCODE;
517   msg->rm_xid = cd->x_id;
518   stat = xdr_replymsg (xdrs, msg);
519   (void) xdrrec_endofrecord (xdrs, TRUE);
520   return stat;
521 }