Make sunrpc code usable again
[glibc.git] / sunrpc / svc_unix.c
blob94507b240348fe0aac4480feeb58d444baf5d331
1 /*
2 * svc_unix.c, Server side for TCP/IP based RPC.
4 * Copyright (c) 2010, Oracle America, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
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.
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.
33 * Actually implements two flavors of transporter -
34 * a unix rendezvouser (a listener and connection establisher)
35 * and a record/unix stream.
38 #include <stdio.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <rpc/rpc.h>
42 #include <rpc/svc.h>
43 #include <sys/socket.h>
44 #include <sys/uio.h>
45 #include <sys/poll.h>
46 #include <errno.h>
47 #include <stdlib.h>
48 #include <libintl.h>
49 #include <wchar.h>
52 * Ops vector for AF_UNIX based rpc service handle
54 static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
55 static enum xprt_stat svcunix_stat (SVCXPRT *);
56 static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
57 static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
58 static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
59 static void svcunix_destroy (SVCXPRT *);
61 static const struct xp_ops svcunix_op =
63 svcunix_recv,
64 svcunix_stat,
65 svcunix_getargs,
66 svcunix_reply,
67 svcunix_freeargs,
68 svcunix_destroy
72 * Ops vector for AF_UNIX rendezvous handler
74 static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
75 static enum xprt_stat rendezvous_stat (SVCXPRT *);
76 static void svcunix_rendezvous_abort (void) __attribute__ ((__noreturn__));
78 /* This function makes sure abort() relocation goes through PLT
79 and thus can be lazy bound. */
80 static void
81 svcunix_rendezvous_abort (void)
83 abort ();
86 static const struct xp_ops svcunix_rendezvous_op =
88 rendezvous_request,
89 rendezvous_stat,
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,
93 svcunix_destroy
96 static int readunix (char*, char *, int);
97 static int writeunix (char *, char *, int);
98 static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
100 struct unix_rendezvous { /* kept in xprt->xp_p1 */
101 u_int sendsize;
102 u_int recvsize;
105 struct 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];
113 * Usage:
114 * xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
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.
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.
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.
132 SVCXPRT *
133 svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
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);
141 if (sock == RPC_ANYSOCK)
143 if ((sock = __socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
145 perror (_("svc_unix.c - AF_UNIX socket creation problem"));
146 return (SVCXPRT *) NULL;
148 madesock = TRUE;
150 memset (&addr, '\0', sizeof (addr));
151 addr.sun_family = AF_UNIX;
152 len = strlen (path) + 1;
153 memcpy (addr.sun_path, path, len);
154 len += sizeof (addr.sun_family);
156 __bind (sock, (struct sockaddr *) &addr, len);
158 if (__getsockname (sock, (struct sockaddr *) &addr, &len) != 0
159 || __listen (sock, SOMAXCONN) != 0)
161 perror (_("svc_unix.c - cannot getsockname or listen"));
162 if (madesock)
163 __close (sock);
164 return (SVCXPRT *) NULL;
167 r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
168 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
169 if (r == NULL || xprt == NULL)
171 __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
172 mem_free (r, sizeof (*r));
173 mem_free (xprt, sizeof (SVCXPRT));
174 return NULL;
176 r->sendsize = sendsize;
177 r->recvsize = recvsize;
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;
187 libc_hidden_nolink_sunrpc (svcunix_create, GLIBC_2_1)
190 * Like svunix_create(), except the routine takes any *open* UNIX file
191 * descriptor as its first input.
193 SVCXPRT *
194 svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
196 return makefd_xprt (fd, sendsize, recvsize);
198 libc_hidden_nolink_sunrpc (svcunixfd_create, GLIBC_2_1)
200 static SVCXPRT *
201 internal_function
202 makefd_xprt (int fd, u_int sendsize, u_int recvsize)
204 SVCXPRT *xprt;
205 struct unix_conn *cd;
207 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
208 cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
209 if (xprt == (SVCXPRT *) NULL || cd == (struct unix_conn *) NULL)
211 (void) __fxprintf (NULL, "%s: %s", "svc_unix: makefd_xprt",
212 _("out of memory\n"));
213 mem_free (xprt, sizeof (SVCXPRT));
214 mem_free (cd, sizeof (struct unix_conn));
215 return NULL;
217 cd->strm_stat = XPRT_IDLE;
218 xdrrec_create (&(cd->xdrs), sendsize, recvsize,
219 (caddr_t) xprt, readunix, writeunix);
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);
228 return xprt;
231 static bool_t
232 rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg)
234 int sock;
235 struct unix_rendezvous *r;
236 struct sockaddr_un addr;
237 struct sockaddr_in in_addr;
238 socklen_t len;
240 r = (struct unix_rendezvous *) xprt->xp_p1;
241 again:
242 len = sizeof (struct sockaddr_un);
243 if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
245 if (errno == EINTR)
246 goto again;
247 return FALSE;
250 * make a new transporter (re-uses xprt)
252 memset (&in_addr, '\0', sizeof (in_addr));
253 in_addr.sin_family = AF_UNIX;
254 xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
255 memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr));
256 xprt->xp_addrlen = len;
257 return FALSE; /* there is never an rpc msg to be processed */
260 static enum xprt_stat
261 rendezvous_stat (SVCXPRT *xprt)
263 return XPRT_IDLE;
266 static void
267 svcunix_destroy (SVCXPRT *xprt)
269 struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
271 xprt_unregister (xprt);
272 __close (xprt->xp_sock);
273 if (xprt->xp_port != 0)
275 /* a rendezvouser socket */
276 xprt->xp_port = 0;
278 else
280 /* an actual connection socket */
281 XDR_DESTROY (&(cd->xdrs));
283 mem_free ((caddr_t) cd, sizeof (struct unix_conn));
284 mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
287 #ifdef SCM_CREDENTIALS
288 struct cmessage {
289 struct cmsghdr cmsg;
290 struct ucred cmcred;
291 /* hack to make sure we have enough memory */
292 char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
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. */
298 static struct cmessage cm;
299 #endif
301 static int
302 __msgread (int sock, void *data, size_t cnt)
304 struct iovec iov;
305 struct msghdr msg;
306 int len;
308 iov.iov_base = data;
309 iov.iov_len = cnt;
311 msg.msg_iov = &iov;
312 msg.msg_iovlen = 1;
313 msg.msg_name = NULL;
314 msg.msg_namelen = 0;
315 #ifdef SCM_CREDENTIALS
316 msg.msg_control = (caddr_t) &cm;
317 msg.msg_controllen = sizeof (struct cmessage);
318 #endif
319 msg.msg_flags = 0;
321 #ifdef SO_PASSCRED
323 int on = 1;
324 if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
325 return -1;
327 #endif
329 restart:
330 len = __recvmsg (sock, &msg, 0);
331 if (len >= 0)
333 if (msg.msg_flags & MSG_CTRUNC || len == 0)
334 return 0;
335 else
336 return len;
338 if (errno == EINTR)
339 goto restart;
340 return -1;
343 static int
344 __msgwrite (int sock, void *data, size_t cnt)
346 #ifndef SCM_CREDENTIALS
347 /* We cannot implement this reliably. */
348 __set_errno (ENOSYS);
349 return -1;
350 #else
351 struct iovec iov;
352 struct msghdr msg;
353 struct cmsghdr *cmsg = &cm.cmsg;
354 struct ucred cred;
355 int len;
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 ();
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);
369 iov.iov_base = data;
370 iov.iov_len = cnt;
372 msg.msg_iov = &iov;
373 msg.msg_iovlen = 1;
374 msg.msg_name = NULL;
375 msg.msg_namelen = 0;
376 msg.msg_control = cmsg;
377 msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
378 msg.msg_flags = 0;
380 restart:
381 len = __sendmsg (sock, &msg, 0);
382 if (len >= 0)
383 return len;
384 if (errno == EINTR)
385 goto restart;
386 return -1;
388 #endif
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.)
396 static int
397 readunix (char *xprtptr, char *buf, int len)
399 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
400 int sock = xprt->xp_sock;
401 int milliseconds = 35 * 1000;
402 struct pollfd pollfd;
406 pollfd.fd = sock;
407 pollfd.events = POLLIN;
408 switch (__poll (&pollfd, 1, milliseconds))
410 case -1:
411 if (errno == EINTR)
412 continue;
413 /*FALLTHROUGH*/
414 case 0:
415 goto fatal_err;
416 default:
417 if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
418 || (pollfd.revents & POLLNVAL))
419 goto fatal_err;
420 break;
423 while ((pollfd.revents & POLLIN) == 0);
425 if ((len = __msgread (sock, buf, len)) > 0)
426 return len;
428 fatal_err:
429 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
430 return -1;
434 * writes data to the unix connection.
435 * Any error is fatal and the connection is closed.
437 static int
438 writeunix (char *xprtptr, char * buf, int len)
440 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
441 int i, cnt;
443 for (cnt = len; cnt > 0; cnt -= i, buf += i)
445 if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
447 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
448 return -1;
451 return len;
454 static enum xprt_stat
455 svcunix_stat (SVCXPRT *xprt)
457 struct unix_conn *cd =
458 (struct unix_conn *) (xprt->xp_p1);
460 if (cd->strm_stat == XPRT_DIED)
461 return XPRT_DIED;
462 if (!xdrrec_eof (&(cd->xdrs)))
463 return XPRT_MOREREQS;
464 return XPRT_IDLE;
467 static bool_t
468 svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
470 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
471 XDR *xdrs = &(cd->xdrs);
473 xdrs->x_op = XDR_DECODE;
474 xdrrec_skiprecord (xdrs);
475 if (xdr_callmsg (xdrs, msg))
477 cd->x_id = msg->rm_xid;
478 /* set up verifiers */
479 #ifdef SCM_CREDENTIALS
480 msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
481 msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
482 msg->rm_call.cb_verf.oa_length = sizeof (cm);
483 #endif
484 return TRUE;
486 cd->strm_stat = XPRT_DIED; /* XXXX */
487 return FALSE;
490 static bool_t
491 svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
493 return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
494 args_ptr);
497 static bool_t
498 svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
500 XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
502 xdrs->x_op = XDR_FREE;
503 return (*xdr_args) (xdrs, args_ptr);
506 static bool_t
507 svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
509 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
510 XDR *xdrs = &(cd->xdrs);
511 bool_t stat;
513 xdrs->x_op = XDR_ENCODE;
514 msg->rm_xid = cd->x_id;
515 stat = xdr_replymsg (xdrs, msg);
516 (void) xdrrec_endofrecord (xdrs, TRUE);
517 return stat;