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

source code of glibc/sunrpc/svc_unix.c