]> git.ipfire.org Git - thirdparty/glibc.git/blame - sunrpc/svc_unix.c
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / sunrpc / svc_unix.c
CommitLineData
e852e889 1/*
a7ab6ec8 2 * svc_unix.c, Server side for TCP/IP based RPC.
e852e889 3 *
2b778ceb 4 * Copyright (C) 2012-2021 Free Software Foundation, Inc.
14bc93a9
JL
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
5a82c748 19 * <https://www.gnu.org/licenses/>.
14bc93a9 20 *
a7ab6ec8 21 * Copyright (c) 2010, Oracle America, Inc.
e852e889 22 *
a7ab6ec8
UD
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions are
25 * met:
e852e889 26 *
a7ab6ec8
UD
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.
cb636bb2 36 *
a7ab6ec8
UD
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.
e852e889
UD
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>
e4aced47 59#include <rpc/svc.h>
e852e889
UD
60#include <sys/socket.h>
61#include <sys/uio.h>
090ca000 62#include <sys/poll.h>
e852e889
UD
63#include <errno.h>
64#include <stdlib.h>
4360eafd 65#include <libintl.h>
3ce1f295 66#include <wchar.h>
82f43dd2 67#include <shlib-compat.h>
51028f34 68
e852e889
UD
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 *);
a49d0179 94static void svcunix_rendezvous_abort (void) __attribute__ ((__noreturn__));
4b9afc43
UD
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};
e852e889
UD
103
104static const struct xp_ops svcunix_rendezvous_op =
105{
106 rendezvous_request,
107 rendezvous_stat,
4b9afc43
UD
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,
e852e889
UD
111 svcunix_destroy
112};
113
114static int readunix (char*, char *, int);
115static int writeunix (char *, char *, int);
ca4ec803 116static SVCXPRT *makefd_xprt (int, u_int, u_int);
e852e889
UD
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;
c3966b88 170 len = strlen (path) + 1;
e852e889
UD
171 memcpy (addr.sun_path, path, len);
172 len += sizeof (addr.sun_family);
173
b2bffca2 174 __bind (sock, (struct sockaddr *) &addr, len);
e852e889 175
b2bffca2 176 if (__getsockname (sock, (struct sockaddr *) &addr, &len) != 0
a3a449c1 177 || __listen (sock, SOMAXCONN) != 0)
e852e889
UD
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));
51028f34
UD
186 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
187 if (r == NULL || xprt == NULL)
e852e889 188 {
1d20f7f8 189 __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
2e3e5db6
UD
190 mem_free (r, sizeof (*r));
191 mem_free (xprt, sizeof (SVCXPRT));
e852e889
UD
192 return NULL;
193 }
194 r->sendsize = sendsize;
195 r->recvsize = recvsize;
e852e889
UD
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}
021db4be 205libc_hidden_nolink_sunrpc (svcunix_create, GLIBC_2_1)
e852e889
UD
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}
021db4be 216libc_hidden_nolink_sunrpc (svcunixfd_create, GLIBC_2_1)
e852e889
UD
217
218static SVCXPRT *
e852e889
UD
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));
e852e889 225 cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
51028f34 226 if (xprt == (SVCXPRT *) NULL || cd == (struct unix_conn *) NULL)
e852e889 227 {
1d20f7f8
UD
228 (void) __fxprintf (NULL, "%s: %s", "svc_unix: makefd_xprt",
229 _("out of memory\n"));
2e3e5db6
UD
230 mem_free (xprt, sizeof (SVCXPRT));
231 mem_free (cd, sizeof (struct unix_conn));
51028f34 232 return NULL;
e852e889
UD
233 }
234 cd->strm_stat = XPRT_IDLE;
7b57bfe5
UD
235 xdrrec_create (&(cd->xdrs), sendsize, recvsize,
236 (caddr_t) xprt, readunix, writeunix);
e852e889
UD
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);
e852e889
UD
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;
14bc93a9 264 __svc_accept_failed ();
e852e889
UD
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);
4b2e40a9
SL
273
274 /* If we are out of memory, makefd_xprt has already dumped an error. */
275 if (xprt == NULL)
276 {
277 __svc_wait_on_error ();
278 return FALSE;
279 }
280
c1301d9a 281 memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr));
e852e889
UD
282 xprt->xp_addrlen = len;
283 return FALSE; /* there is never an rpc msg to be processed */
284}
285
286static enum xprt_stat
287rendezvous_stat (SVCXPRT *xprt)
288{
289 return XPRT_IDLE;
290}
291
292static void
293svcunix_destroy (SVCXPRT *xprt)
294{
295 struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
296
297 xprt_unregister (xprt);
298 __close (xprt->xp_sock);
299 if (xprt->xp_port != 0)
300 {
301 /* a rendezvouser socket */
302 xprt->xp_port = 0;
303 }
304 else
305 {
306 /* an actual connection socket */
307 XDR_DESTROY (&(cd->xdrs));
308 }
309 mem_free ((caddr_t) cd, sizeof (struct unix_conn));
310 mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
311}
312
c5720a93 313#ifdef SCM_CREDENTIALS
e852e889
UD
314struct cmessage {
315 struct cmsghdr cmsg;
7ce241a0 316 struct ucred cmcred;
d1275afe
AS
317 /* hack to make sure we have enough memory */
318 char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
e852e889
UD
319};
320
321/* XXX This is not thread safe, but since the main functions in svc.c
322 and the rpcgen generated *_svc functions for the daemon are also not
323 thread safe and uses static global variables, it doesn't matter. */
324static struct cmessage cm;
c5720a93 325#endif
e852e889
UD
326
327static int
d1275afe 328__msgread (int sock, void *data, size_t cnt)
e852e889 329{
d1275afe 330 struct iovec iov;
e852e889 331 struct msghdr msg;
d1275afe 332 int len;
e852e889 333
d1275afe
AS
334 iov.iov_base = data;
335 iov.iov_len = cnt;
e852e889 336
d1275afe 337 msg.msg_iov = &iov;
e852e889
UD
338 msg.msg_iovlen = 1;
339 msg.msg_name = NULL;
340 msg.msg_namelen = 0;
c5720a93 341#ifdef SCM_CREDENTIALS
e852e889
UD
342 msg.msg_control = (caddr_t) &cm;
343 msg.msg_controllen = sizeof (struct cmessage);
c5720a93 344#endif
e852e889
UD
345 msg.msg_flags = 0;
346
7cabd57c 347#ifdef SO_PASSCRED
d76240d7
RM
348 {
349 int on = 1;
b2bffca2 350 if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
d76240d7
RM
351 return -1;
352 }
7cabd57c 353#endif
e852e889 354
d1275afe 355 restart:
b2bffca2 356 len = __recvmsg (sock, &msg, 0);
d1275afe
AS
357 if (len >= 0)
358 {
359 if (msg.msg_flags & MSG_CTRUNC || len == 0)
7b57bfe5 360 return 0;
d1275afe 361 else
7b57bfe5 362 return len;
d1275afe
AS
363 }
364 if (errno == EINTR)
365 goto restart;
366 return -1;
e852e889
UD
367}
368
369static int
d1275afe 370__msgwrite (int sock, void *data, size_t cnt)
e852e889 371{
7ce241a0 372#ifndef SCM_CREDENTIALS
e852e889
UD
373 /* We cannot implement this reliably. */
374 __set_errno (ENOSYS);
786a5421 375 return -1;
e852e889 376#else
d1275afe 377 struct iovec iov;
e852e889 378 struct msghdr msg;
d1275afe
AS
379 struct cmsghdr *cmsg = &cm.cmsg;
380 struct ucred cred;
381 int len;
382
383 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
384 get?id(). But since keyserv needs geteuid(), we have no other chance.
385 It would be much better, if the kernel could pass both to the server. */
386 cred.pid = __getpid ();
387 cred.uid = __geteuid ();
388 cred.gid = __getegid ();
389
390 memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
391 cmsg->cmsg_level = SOL_SOCKET;
392 cmsg->cmsg_type = SCM_CREDENTIALS;
393 cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
394
395 iov.iov_base = data;
396 iov.iov_len = cnt;
397
398 msg.msg_iov = &iov;
e852e889
UD
399 msg.msg_iovlen = 1;
400 msg.msg_name = NULL;
401 msg.msg_namelen = 0;
d1275afe
AS
402 msg.msg_control = cmsg;
403 msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
e852e889
UD
404 msg.msg_flags = 0;
405
d1275afe 406 restart:
b2bffca2 407 len = __sendmsg (sock, &msg, 0);
d1275afe
AS
408 if (len >= 0)
409 return len;
410 if (errno == EINTR)
411 goto restart;
412 return -1;
413
e852e889
UD
414#endif
415}
416
e852e889
UD
417/*
418 * reads data from the unix connection.
419 * any error is fatal and the connection is closed.
420 * (And a read of zero bytes is a half closed stream => error.)
421 */
422static int
423readunix (char *xprtptr, char *buf, int len)
424{
425 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
426 int sock = xprt->xp_sock;
090ca000
UD
427 int milliseconds = 35 * 1000;
428 struct pollfd pollfd;
429
430 do
e852e889 431 {
090ca000
UD
432 pollfd.fd = sock;
433 pollfd.events = POLLIN;
434 switch (__poll (&pollfd, 1, milliseconds))
e852e889 435 {
090ca000 436 case -1:
e852e889
UD
437 if (errno == EINTR)
438 continue;
090ca000
UD
439 /*FALLTHROUGH*/
440 case 0:
e852e889 441 goto fatal_err;
090ca000 442 default:
f1317ef5
UD
443 if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
444 || (pollfd.revents & POLLNVAL))
445 goto fatal_err;
090ca000 446 break;
e852e889 447 }
e852e889 448 }
090ca000 449 while ((pollfd.revents & POLLIN) == 0);
e852e889
UD
450
451 if ((len = __msgread (sock, buf, len)) > 0)
452 return len;
453
454 fatal_err:
455 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
456 return -1;
457}
458
459/*
460 * writes data to the unix connection.
461 * Any error is fatal and the connection is closed.
462 */
463static int
464writeunix (char *xprtptr, char * buf, int len)
465{
466 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
467 int i, cnt;
468
469 for (cnt = len; cnt > 0; cnt -= i, buf += i)
470 {
471 if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
472 {
473 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
474 return -1;
475 }
476 }
477 return len;
478}
479
480static enum xprt_stat
481svcunix_stat (SVCXPRT *xprt)
482{
483 struct unix_conn *cd =
484 (struct unix_conn *) (xprt->xp_p1);
485
486 if (cd->strm_stat == XPRT_DIED)
487 return XPRT_DIED;
7b57bfe5 488 if (!xdrrec_eof (&(cd->xdrs)))
e852e889
UD
489 return XPRT_MOREREQS;
490 return XPRT_IDLE;
491}
492
493static bool_t
494svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
495{
496 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
497 XDR *xdrs = &(cd->xdrs);
498
499 xdrs->x_op = XDR_DECODE;
7b57bfe5
UD
500 xdrrec_skiprecord (xdrs);
501 if (xdr_callmsg (xdrs, msg))
e852e889
UD
502 {
503 cd->x_id = msg->rm_xid;
504 /* set up verifiers */
c5720a93 505#ifdef SCM_CREDENTIALS
d1275afe 506 msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
e852e889
UD
507 msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
508 msg->rm_call.cb_verf.oa_length = sizeof (cm);
c5720a93 509#endif
e852e889
UD
510 return TRUE;
511 }
512 cd->strm_stat = XPRT_DIED; /* XXXX */
513 return FALSE;
514}
515
516static bool_t
517svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
518{
519 return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
520 args_ptr);
521}
522
523static bool_t
090ca000 524svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
e852e889
UD
525{
526 XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
527
528 xdrs->x_op = XDR_FREE;
529 return (*xdr_args) (xdrs, args_ptr);
530}
531
532static bool_t
090ca000 533svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
e852e889
UD
534{
535 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
536 XDR *xdrs = &(cd->xdrs);
537 bool_t stat;
538
539 xdrs->x_op = XDR_ENCODE;
540 msg->rm_xid = cd->x_id;
7b57bfe5
UD
541 stat = xdr_replymsg (xdrs, msg);
542 (void) xdrrec_endofrecord (xdrs, TRUE);
e852e889
UD
543 return stat;
544}