1/*
2 * svc_unix.c, Server side for TCP/IP based RPC.
3 *
4 * Copyright (C) 2012-2016 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 */
71static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
72static enum xprt_stat svcunix_stat (SVCXPRT *);
73static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
74static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
75static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
76static void svcunix_destroy (SVCXPRT *);
77
78static 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 */
91static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
92static enum xprt_stat rendezvous_stat (SVCXPRT *);
93static 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. */
97static void
98svcunix_rendezvous_abort (void)
99{
100 abort ();
101};
102
103static 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
113static int readunix (char*, char *, int);
114static int writeunix (char *, char *, int);
115static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
116
117struct unix_rendezvous { /* kept in xprt->xp_p1 */
118 u_int sendsize;
119 u_int recvsize;
120};
121
122struct 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 */
149SVCXPRT *
150svcunix_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}
204libc_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 */
210SVCXPRT *
211svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
212{
213 return makefd_xprt (fd, sendsize, recvsize);
214}
215libc_hidden_nolink_sunrpc (svcunixfd_create, GLIBC_2_1)
216
217static SVCXPRT *
218internal_function
219makefd_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
248static bool_t
249rendezvous_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;
258again:
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
278static enum xprt_stat
279rendezvous_stat (SVCXPRT *xprt)
280{
281 return XPRT_IDLE;
282}
283
284static void
285svcunix_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
306struct 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. */
316static struct cmessage cm;
317#endif
318
319static 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
361static 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 */
414static int
415readunix (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 */
455static int
456writeunix (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
472static enum xprt_stat
473svcunix_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
485static bool_t
486svcunix_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
508static bool_t
509svcunix_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
515static bool_t
516svcunix_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
524static bool_t
525svcunix_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}
537