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