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