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