fix musl compatibility
[project/librpc-uclibc.git] / svc_unix.c
1 /*
2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3 * unrestricted use provided that this legend is included on all tape
4 * media and as a part of the software program in whole or part. Users
5 * may copy or modify Sun RPC without charge, but are not authorized
6 * to license or distribute it to anyone else except as part of a product or
7 * program developed by the user.
8 *
9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12 *
13 * Sun RPC is provided with no support and without any obligation on the
14 * part of Sun Microsystems, Inc. to assist in its use, correction,
15 * modification or enhancement.
16 *
17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19 * OR ANY PART THEREOF.
20 *
21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22 * or profits or other special, indirect and consequential damages, even if
23 * Sun has been advised of the possibility of such damages.
24 *
25 * Sun Microsystems, Inc.
26 * 2550 Garcia Avenue
27 * Mountain View, California 94043
28 */
29
30 /*
31 * svc_unix.c, Server side for TCP/IP based RPC.
32 *
33 * Copyright (C) 1984, Sun Microsystems, Inc.
34 *
35 * Actually implements two flavors of transporter -
36 * a unix rendezvouser (a listener and connection establisher)
37 * and a record/unix stream.
38 */
39
40 #define __FORCE_GLIBC
41 #include <features.h>
42
43 #include <stdio.h>
44 #include <unistd.h>
45 #include <string.h>
46 #include <rpc/rpc.h>
47 #include <rpc/svc.h>
48 #include <sys/socket.h>
49 #include <sys/uio.h>
50 #include <poll.h>
51 #include <errno.h>
52 #include <stdlib.h>
53
54 #ifdef USE_IN_LIBIO
55 # include <wchar.h>
56 #endif
57
58
59 /*
60 * Ops vector for AF_UNIX based rpc service handle
61 */
62 static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
63 static enum xprt_stat svcunix_stat (SVCXPRT *);
64 static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
65 static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
66 static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
67 static void svcunix_destroy (SVCXPRT *);
68
69 static const struct xp_ops svcunix_op =
70 {
71 svcunix_recv,
72 svcunix_stat,
73 svcunix_getargs,
74 svcunix_reply,
75 svcunix_freeargs,
76 svcunix_destroy
77 };
78
79 /*
80 * Ops vector for AF_UNIX rendezvous handler
81 */
82 static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
83 static enum xprt_stat rendezvous_stat (SVCXPRT *);
84 static void svcunix_rendezvous_abort (void) attribute_noreturn;
85
86 /* This function makes sure abort() relocation goes through PLT
87 and thus can be lazy bound. */
88 static void
89 svcunix_rendezvous_abort (void)
90 {
91 abort ();
92 };
93
94 static const struct xp_ops svcunix_rendezvous_op =
95 {
96 rendezvous_request,
97 rendezvous_stat,
98 (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
99 (bool_t (*) (SVCXPRT *, struct rpc_msg *)) svcunix_rendezvous_abort,
100 (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
101 svcunix_destroy
102 };
103
104 static int readunix (char*, char *, int);
105 static int writeunix (char *, char *, int);
106 static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
107
108 struct unix_rendezvous { /* kept in xprt->xp_p1 */
109 u_int sendsize;
110 u_int recvsize;
111 };
112
113 struct unix_conn { /* kept in xprt->xp_p1 */
114 enum xprt_stat strm_stat;
115 u_long x_id;
116 XDR xdrs;
117 char verf_body[MAX_AUTH_BYTES];
118 };
119
120 /*
121 * Usage:
122 * xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
123 *
124 * Creates, registers, and returns a (rpc) unix based transporter.
125 * Once *xprt is initialized, it is registered as a transporter
126 * see (svc.h, xprt_register). This routine returns
127 * a NULL if a problem occurred.
128 *
129 * If sock<0 then a socket is created, else sock is used.
130 * If the socket, sock is not bound to a port then svcunix_create
131 * binds it to an arbitrary port. The routine then starts a unix
132 * listener on the socket's associated port. In any (successful) case,
133 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
134 * associated port number.
135 *
136 * Since unix streams do buffered io similar to stdio, the caller can specify
137 * how big the send and receive buffers are via the second and third parms;
138 * 0 => use the system default.
139 */
140 SVCXPRT *
141 svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
142 {
143 bool_t madesock = FALSE;
144 SVCXPRT *xprt;
145 struct unix_rendezvous *r;
146 struct sockaddr_un addr;
147 socklen_t len = sizeof (struct sockaddr_in);
148
149 if (sock == RPC_ANYSOCK)
150 {
151 if ((sock = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
152 {
153 perror (_("svc_unix.c - AF_UNIX socket creation problem"));
154 return (SVCXPRT *) NULL;
155 }
156 madesock = TRUE;
157 }
158 memset (&addr, '\0', sizeof (addr));
159 addr.sun_family = AF_UNIX;
160 len = strlen (path) + 1;
161 memcpy (addr.sun_path, path, len);
162 len += sizeof (addr.sun_family);
163
164 bind (sock, (struct sockaddr *) &addr, len);
165
166 if (getsockname (sock, (struct sockaddr *) &addr, &len) != 0
167 || listen (sock, 2) != 0)
168 {
169 perror (_("svc_unix.c - cannot getsockname or listen"));
170 if (madesock)
171 close (sock);
172 return (SVCXPRT *) NULL;
173 }
174
175 r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
176 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
177 if (r == NULL || xprt == NULL)
178 {
179 #ifdef USE_IN_LIBIO
180 if (_IO_fwide (stderr, 0) > 0)
181 __fwprintf (stderr, L"%s", _("svcunix_create: out of memory\n"));
182 else
183 #endif
184 fputs (_("svcunix_create: out of memory\n"), stderr);
185 mem_free (r, sizeof (*r));
186 mem_free (xprt, sizeof (SVCXPRT));
187 return NULL;
188 }
189 r->sendsize = sendsize;
190 r->recvsize = recvsize;
191 xprt->xp_p2 = NULL;
192 xprt->xp_p1 = (caddr_t) r;
193 xprt->xp_verf = _null_auth;
194 xprt->xp_ops = &svcunix_rendezvous_op;
195 xprt->xp_port = -1;
196 xprt->xp_sock = sock;
197 xprt_register (xprt);
198 return xprt;
199 }
200
201 /*
202 * Like svunix_create(), except the routine takes any *open* UNIX file
203 * descriptor as its first input.
204 */
205 SVCXPRT *
206 svcunixfd_create (int fd, u_int sendsize, u_int recvsize);
207 SVCXPRT *
208 svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
209 {
210 return makefd_xprt (fd, sendsize, recvsize);
211 }
212
213 static SVCXPRT *
214 internal_function
215 makefd_xprt (int fd, u_int sendsize, u_int recvsize)
216 {
217 SVCXPRT *xprt;
218 struct unix_conn *cd;
219
220 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
221 cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
222 if (xprt == (SVCXPRT *) NULL || cd == (struct unix_conn *) NULL)
223 {
224 #ifdef USE_IN_LIBIO
225 if (_IO_fwide (stderr, 0) > 0)
226 (void) __fwprintf (stderr, L"%s",
227 _("svc_unix: makefd_xprt: out of memory\n"));
228 else
229 #endif
230 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
231 mem_free (xprt, sizeof (SVCXPRT));
232 mem_free (cd, sizeof (struct unix_conn));
233 return NULL;
234 }
235 cd->strm_stat = XPRT_IDLE;
236 xdrrec_create (&(cd->xdrs), sendsize, recvsize,
237 (caddr_t) xprt, readunix, writeunix);
238 xprt->xp_p2 = NULL;
239 xprt->xp_p1 = (caddr_t) cd;
240 xprt->xp_verf.oa_base = cd->verf_body;
241 xprt->xp_addrlen = 0;
242 xprt->xp_ops = &svcunix_op; /* truly deals with calls */
243 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */
244 xprt->xp_sock = fd;
245 xprt_register (xprt);
246 return xprt;
247 }
248
249 static bool_t
250 rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg attribute_unused)
251 {
252 int sock;
253 struct unix_rendezvous *r;
254 struct sockaddr_un addr;
255 struct sockaddr_in in_addr;
256 socklen_t len;
257
258 r = (struct unix_rendezvous *) xprt->xp_p1;
259 again:
260 len = sizeof (struct sockaddr_un);
261 if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
262 {
263 if (errno == EINTR)
264 goto again;
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);
273 memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr));
274 xprt->xp_addrlen = len;
275 return FALSE; /* there is never an rpc msg to be processed */
276 }
277
278 static enum xprt_stat
279 rendezvous_stat (SVCXPRT *xprt attribute_unused)
280 {
281 return XPRT_IDLE;
282 }
283
284 static void
285 svcunix_destroy (SVCXPRT *xprt)
286 {
287 struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
288
289 xprt_unregister (xprt);
290 close (xprt->xp_sock);
291 if (xprt->xp_port != 0)
292 {
293 /* a rendezvouser socket */
294 xprt->xp_port = 0;
295 }
296 else
297 {
298 /* an actual connection socket */
299 XDR_DESTROY (&(cd->xdrs));
300 }
301 mem_free ((caddr_t) cd, sizeof (struct unix_conn));
302 mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
303 }
304
305 #ifdef SCM_CREDENTIALS
306 struct cmessage {
307 struct cmsghdr cmsg;
308 struct ucred cmcred;
309 /* hack to make sure we have enough memory */
310 char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
311 };
312
313 /* XXX This is not thread safe, but since the main functions in svc.c
314 and the rpcgen generated *_svc functions for the daemon are also not
315 thread safe and uses static global variables, it doesn't matter. */
316 static struct cmessage cm;
317 #endif
318
319 static int
320 __msgread (int sock, void *data, size_t cnt)
321 {
322 struct iovec iov;
323 struct msghdr msg;
324 int len;
325
326 iov.iov_base = data;
327 iov.iov_len = cnt;
328
329 msg.msg_iov = &iov;
330 msg.msg_iovlen = 1;
331 msg.msg_name = NULL;
332 msg.msg_namelen = 0;
333 #ifdef SCM_CREDENTIALS
334 msg.msg_control = (caddr_t) &cm;
335 msg.msg_controllen = sizeof (struct cmessage);
336 #endif
337 msg.msg_flags = 0;
338
339 #ifdef SO_PASSCRED
340 {
341 int on = 1;
342 if (setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
343 return -1;
344 }
345 #endif
346
347 restart:
348 len = recvmsg (sock, &msg, 0);
349 if (len >= 0)
350 {
351 if (msg.msg_flags & MSG_CTRUNC || len == 0)
352 return 0;
353 else
354 return len;
355 }
356 if (errno == EINTR)
357 goto restart;
358 return -1;
359 }
360
361 static int
362 __msgwrite (int sock, void *data, size_t cnt)
363 {
364 #ifndef SCM_CREDENTIALS
365 /* We cannot implement this reliably. */
366 __set_errno (ENOSYS);
367 return -1;
368 #else
369 struct iovec iov;
370 struct msghdr msg;
371 struct cmsghdr *cmsg = &cm.cmsg;
372 struct ucred cred;
373 int len;
374
375 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
376 get?id(). But since keyserv needs geteuid(), we have no other chance.
377 It would be much better, if the kernel could pass both to the server. */
378 cred.pid = getpid ();
379 cred.uid = geteuid ();
380 cred.gid = getegid ();
381
382 memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
383 cmsg->cmsg_level = SOL_SOCKET;
384 cmsg->cmsg_type = SCM_CREDENTIALS;
385 cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
386
387 iov.iov_base = data;
388 iov.iov_len = cnt;
389
390 msg.msg_iov = &iov;
391 msg.msg_iovlen = 1;
392 msg.msg_name = NULL;
393 msg.msg_namelen = 0;
394 msg.msg_control = cmsg;
395 msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
396 msg.msg_flags = 0;
397
398 restart:
399 len = sendmsg (sock, &msg, 0);
400 if (len >= 0)
401 return len;
402 if (errno == EINTR)
403 goto restart;
404 return -1;
405
406 #endif
407 }
408
409 /*
410 * reads data from the unix connection.
411 * any error is fatal and the connection is closed.
412 * (And a read of zero bytes is a half closed stream => error.)
413 */
414 static int
415 readunix (char *xprtptr, char *buf, int len)
416 {
417 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
418 int sock = xprt->xp_sock;
419 int milliseconds = 35 * 1000;
420 struct pollfd pollfd;
421
422 do
423 {
424 pollfd.fd = sock;
425 pollfd.events = POLLIN;
426 switch (poll (&pollfd, 1, milliseconds))
427 {
428 case -1:
429 if (errno == EINTR)
430 continue;
431 /*FALLTHROUGH*/
432 case 0:
433 goto fatal_err;
434 default:
435 if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
436 || (pollfd.revents & POLLNVAL))
437 goto fatal_err;
438 break;
439 }
440 }
441 while ((pollfd.revents & POLLIN) == 0);
442
443 if ((len = __msgread (sock, buf, len)) > 0)
444 return len;
445
446 fatal_err:
447 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
448 return -1;
449 }
450
451 /*
452 * writes data to the unix connection.
453 * Any error is fatal and the connection is closed.
454 */
455 static int
456 writeunix (char *xprtptr, char * buf, int len)
457 {
458 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
459 int i, cnt;
460
461 for (cnt = len; cnt > 0; cnt -= i, buf += i)
462 {
463 if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
464 {
465 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
466 return -1;
467 }
468 }
469 return len;
470 }
471
472 static enum xprt_stat
473 svcunix_stat (SVCXPRT *xprt)
474 {
475 struct unix_conn *cd =
476 (struct unix_conn *) (xprt->xp_p1);
477
478 if (cd->strm_stat == XPRT_DIED)
479 return XPRT_DIED;
480 if (!xdrrec_eof (&(cd->xdrs)))
481 return XPRT_MOREREQS;
482 return XPRT_IDLE;
483 }
484
485 static bool_t
486 svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
487 {
488 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
489 XDR *xdrs = &(cd->xdrs);
490
491 xdrs->x_op = XDR_DECODE;
492 xdrrec_skiprecord (xdrs);
493 if (xdr_callmsg (xdrs, msg))
494 {
495 cd->x_id = msg->rm_xid;
496 /* set up verifiers */
497 #ifdef SCM_CREDENTIALS
498 msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
499 msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
500 msg->rm_call.cb_verf.oa_length = sizeof (cm);
501 #endif
502 return TRUE;
503 }
504 cd->strm_stat = XPRT_DIED; /* XXXX */
505 return FALSE;
506 }
507
508 static bool_t
509 svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
510 {
511 return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
512 args_ptr);
513 }
514
515 static bool_t
516 svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
517 {
518 XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
519
520 xdrs->x_op = XDR_FREE;
521 return (*xdr_args) (xdrs, args_ptr);
522 }
523
524 static bool_t
525 svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
526 {
527 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
528 XDR *xdrs = &(cd->xdrs);
529 bool_t stat;
530
531 xdrs->x_op = XDR_ENCODE;
532 msg->rm_xid = cd->x_id;
533 stat = xdr_replymsg (xdrs, msg);
534 (void) xdrrec_endofrecord (xdrs, TRUE);
535 return stat;
536 }