[BZ #5979]
[glibc.git] / sunrpc / svc_unix.c
blobf103ed96f31e0ab2a1258081266fd4b6d4896f3c
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.
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.
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.
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.
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.
25 * Sun Microsystems, Inc.
26 * 2550 Garcia Avenue
27 * Mountain View, California 94043
31 * svc_unix.c, Server side for TCP/IP based RPC.
33 * Copyright (C) 1984, Sun Microsystems, Inc.
35 * Actually implements two flavors of transporter -
36 * a unix rendezvouser (a listener and connection establisher)
37 * and a record/unix stream.
40 #include <stdio.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <rpc/rpc.h>
44 #include <rpc/svc.h>
45 #include <sys/socket.h>
46 #include <sys/uio.h>
47 #include <sys/poll.h>
48 #include <errno.h>
49 #include <stdlib.h>
50 #include <libintl.h>
52 #ifdef USE_IN_LIBIO
53 # include <wchar.h>
54 #endif
57 * Ops vector for AF_UNIX based rpc service handle
59 static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
60 static enum xprt_stat svcunix_stat (SVCXPRT *);
61 static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
62 static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
63 static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
64 static void svcunix_destroy (SVCXPRT *);
66 static const struct xp_ops svcunix_op =
68 svcunix_recv,
69 svcunix_stat,
70 svcunix_getargs,
71 svcunix_reply,
72 svcunix_freeargs,
73 svcunix_destroy
77 * Ops vector for AF_UNIX rendezvous handler
79 static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
80 static enum xprt_stat rendezvous_stat (SVCXPRT *);
81 static void svcunix_rendezvous_abort (void) __attribute__ ((__noreturn__));
83 /* This function makes sure abort() relocation goes through PLT
84 and thus can be lazy bound. */
85 static void
86 svcunix_rendezvous_abort (void)
88 abort ();
91 static const struct xp_ops svcunix_rendezvous_op =
93 rendezvous_request,
94 rendezvous_stat,
95 (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
96 (bool_t (*) (SVCXPRT *, struct rpc_msg *)) svcunix_rendezvous_abort,
97 (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
98 svcunix_destroy
101 static int readunix (char*, char *, int);
102 static int writeunix (char *, char *, int);
103 static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
105 struct unix_rendezvous { /* kept in xprt->xp_p1 */
106 u_int sendsize;
107 u_int recvsize;
110 struct unix_conn { /* kept in xprt->xp_p1 */
111 enum xprt_stat strm_stat;
112 u_long x_id;
113 XDR xdrs;
114 char verf_body[MAX_AUTH_BYTES];
118 * Usage:
119 * xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
121 * Creates, registers, and returns a (rpc) unix based transporter.
122 * Once *xprt is initialized, it is registered as a transporter
123 * see (svc.h, xprt_register). This routine returns
124 * a NULL if a problem occurred.
126 * If sock<0 then a socket is created, else sock is used.
127 * If the socket, sock is not bound to a port then svcunix_create
128 * binds it to an arbitrary port. The routine then starts a unix
129 * listener on the socket's associated port. In any (successful) case,
130 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
131 * associated port number.
133 * Since unix streams do buffered io similar to stdio, the caller can specify
134 * how big the send and receive buffers are via the second and third parms;
135 * 0 => use the system default.
137 SVCXPRT *
138 svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
140 bool_t madesock = FALSE;
141 SVCXPRT *xprt;
142 struct unix_rendezvous *r;
143 struct sockaddr_un addr;
144 socklen_t len = sizeof (struct sockaddr_in);
146 if (sock == RPC_ANYSOCK)
148 if ((sock = __socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
150 perror (_("svc_unix.c - AF_UNIX socket creation problem"));
151 return (SVCXPRT *) NULL;
153 madesock = TRUE;
155 memset (&addr, '\0', sizeof (addr));
156 addr.sun_family = AF_UNIX;
157 len = strlen (path) + 1;
158 memcpy (addr.sun_path, path, len);
159 len += sizeof (addr.sun_family);
161 __bind (sock, (struct sockaddr *) &addr, len);
163 if (__getsockname (sock, (struct sockaddr *) &addr, &len) != 0
164 || __listen (sock, SOMAXCONN) != 0)
166 perror (_("svc_unix.c - cannot getsockname or listen"));
167 if (madesock)
168 __close (sock);
169 return (SVCXPRT *) NULL;
172 r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
173 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
174 if (r == NULL || xprt == NULL)
176 __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
177 mem_free (r, sizeof (*r));
178 mem_free (xprt, sizeof (SVCXPRT));
179 return NULL;
181 r->sendsize = sendsize;
182 r->recvsize = recvsize;
183 xprt->xp_p2 = NULL;
184 xprt->xp_p1 = (caddr_t) r;
185 xprt->xp_verf = _null_auth;
186 xprt->xp_ops = &svcunix_rendezvous_op;
187 xprt->xp_port = -1;
188 xprt->xp_sock = sock;
189 xprt_register (xprt);
190 return xprt;
194 * Like svunix_create(), except the routine takes any *open* UNIX file
195 * descriptor as its first input.
197 SVCXPRT *
198 svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
200 return makefd_xprt (fd, sendsize, recvsize);
203 static SVCXPRT *
204 internal_function
205 makefd_xprt (int fd, u_int sendsize, u_int recvsize)
207 SVCXPRT *xprt;
208 struct unix_conn *cd;
210 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
211 cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
212 if (xprt == (SVCXPRT *) NULL || cd == (struct unix_conn *) NULL)
214 (void) __fxprintf (NULL, "%s: %s", "svc_unix: makefd_xprt",
215 _("out of memory\n"));
216 mem_free (xprt, sizeof (SVCXPRT));
217 mem_free (cd, sizeof (struct unix_conn));
218 return NULL;
220 cd->strm_stat = XPRT_IDLE;
221 INTUSE(xdrrec_create) (&(cd->xdrs), sendsize, recvsize,
222 (caddr_t) xprt, readunix, writeunix);
223 xprt->xp_p2 = NULL;
224 xprt->xp_p1 = (caddr_t) cd;
225 xprt->xp_verf.oa_base = cd->verf_body;
226 xprt->xp_addrlen = 0;
227 xprt->xp_ops = &svcunix_op; /* truly deals with calls */
228 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */
229 xprt->xp_sock = fd;
230 xprt_register (xprt);
231 return xprt;
234 static bool_t
235 rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg)
237 int sock;
238 struct unix_rendezvous *r;
239 struct sockaddr_un addr;
240 struct sockaddr_in in_addr;
241 socklen_t len;
243 r = (struct unix_rendezvous *) xprt->xp_p1;
244 again:
245 len = sizeof (struct sockaddr_un);
246 if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
248 if (errno == EINTR)
249 goto again;
250 return FALSE;
253 * make a new transporter (re-uses xprt)
255 memset (&in_addr, '\0', sizeof (in_addr));
256 in_addr.sin_family = AF_UNIX;
257 xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
258 memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr));
259 xprt->xp_addrlen = len;
260 return FALSE; /* there is never an rpc msg to be processed */
263 static enum xprt_stat
264 rendezvous_stat (SVCXPRT *xprt)
266 return XPRT_IDLE;
269 static void
270 svcunix_destroy (SVCXPRT *xprt)
272 struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
274 xprt_unregister (xprt);
275 __close (xprt->xp_sock);
276 if (xprt->xp_port != 0)
278 /* a rendezvouser socket */
279 xprt->xp_port = 0;
281 else
283 /* an actual connection socket */
284 XDR_DESTROY (&(cd->xdrs));
286 mem_free ((caddr_t) cd, sizeof (struct unix_conn));
287 mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
290 #ifdef SCM_CREDENTIALS
291 struct cmessage {
292 struct cmsghdr cmsg;
293 struct ucred cmcred;
294 /* hack to make sure we have enough memory */
295 char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
298 /* XXX This is not thread safe, but since the main functions in svc.c
299 and the rpcgen generated *_svc functions for the daemon are also not
300 thread safe and uses static global variables, it doesn't matter. */
301 static struct cmessage cm;
302 #endif
304 static int
305 __msgread (int sock, void *data, size_t cnt)
307 struct iovec iov;
308 struct msghdr msg;
309 int len;
311 iov.iov_base = data;
312 iov.iov_len = cnt;
314 msg.msg_iov = &iov;
315 msg.msg_iovlen = 1;
316 msg.msg_name = NULL;
317 msg.msg_namelen = 0;
318 #ifdef SCM_CREDENTIALS
319 msg.msg_control = (caddr_t) &cm;
320 msg.msg_controllen = sizeof (struct cmessage);
321 #endif
322 msg.msg_flags = 0;
324 #ifdef SO_PASSCRED
326 int on = 1;
327 if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
328 return -1;
330 #endif
332 restart:
333 len = __recvmsg (sock, &msg, 0);
334 if (len >= 0)
336 if (msg.msg_flags & MSG_CTRUNC || len == 0)
337 return 0;
338 else
339 return len;
341 if (errno == EINTR)
342 goto restart;
343 return -1;
346 static int
347 __msgwrite (int sock, void *data, size_t cnt)
349 #ifndef SCM_CREDENTIALS
350 /* We cannot implement this reliably. */
351 __set_errno (ENOSYS);
352 return -1;
353 #else
354 struct iovec iov;
355 struct msghdr msg;
356 struct cmsghdr *cmsg = &cm.cmsg;
357 struct ucred cred;
358 int len;
360 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
361 get?id(). But since keyserv needs geteuid(), we have no other chance.
362 It would be much better, if the kernel could pass both to the server. */
363 cred.pid = __getpid ();
364 cred.uid = __geteuid ();
365 cred.gid = __getegid ();
367 memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
368 cmsg->cmsg_level = SOL_SOCKET;
369 cmsg->cmsg_type = SCM_CREDENTIALS;
370 cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
372 iov.iov_base = data;
373 iov.iov_len = cnt;
375 msg.msg_iov = &iov;
376 msg.msg_iovlen = 1;
377 msg.msg_name = NULL;
378 msg.msg_namelen = 0;
379 msg.msg_control = cmsg;
380 msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
381 msg.msg_flags = 0;
383 restart:
384 len = __sendmsg (sock, &msg, 0);
385 if (len >= 0)
386 return len;
387 if (errno == EINTR)
388 goto restart;
389 return -1;
391 #endif
395 * reads data from the unix connection.
396 * any error is fatal and the connection is closed.
397 * (And a read of zero bytes is a half closed stream => error.)
399 static int
400 readunix (char *xprtptr, char *buf, int len)
402 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
403 int sock = xprt->xp_sock;
404 int milliseconds = 35 * 1000;
405 struct pollfd pollfd;
409 pollfd.fd = sock;
410 pollfd.events = POLLIN;
411 switch (__poll (&pollfd, 1, milliseconds))
413 case -1:
414 if (errno == EINTR)
415 continue;
416 /*FALLTHROUGH*/
417 case 0:
418 goto fatal_err;
419 default:
420 if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
421 || (pollfd.revents & POLLNVAL))
422 goto fatal_err;
423 break;
426 while ((pollfd.revents & POLLIN) == 0);
428 if ((len = __msgread (sock, buf, len)) > 0)
429 return len;
431 fatal_err:
432 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
433 return -1;
437 * writes data to the unix connection.
438 * Any error is fatal and the connection is closed.
440 static int
441 writeunix (char *xprtptr, char * buf, int len)
443 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
444 int i, cnt;
446 for (cnt = len; cnt > 0; cnt -= i, buf += i)
448 if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
450 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
451 return -1;
454 return len;
457 static enum xprt_stat
458 svcunix_stat (SVCXPRT *xprt)
460 struct unix_conn *cd =
461 (struct unix_conn *) (xprt->xp_p1);
463 if (cd->strm_stat == XPRT_DIED)
464 return XPRT_DIED;
465 if (!INTUSE(xdrrec_eof) (&(cd->xdrs)))
466 return XPRT_MOREREQS;
467 return XPRT_IDLE;
470 static bool_t
471 svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
473 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
474 XDR *xdrs = &(cd->xdrs);
476 xdrs->x_op = XDR_DECODE;
477 INTUSE(xdrrec_skiprecord) (xdrs);
478 if (INTUSE(xdr_callmsg) (xdrs, msg))
480 cd->x_id = msg->rm_xid;
481 /* set up verifiers */
482 #ifdef SCM_CREDENTIALS
483 msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
484 msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
485 msg->rm_call.cb_verf.oa_length = sizeof (cm);
486 #endif
487 return TRUE;
489 cd->strm_stat = XPRT_DIED; /* XXXX */
490 return FALSE;
493 static bool_t
494 svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
496 return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
497 args_ptr);
500 static bool_t
501 svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
503 XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
505 xdrs->x_op = XDR_FREE;
506 return (*xdr_args) (xdrs, args_ptr);
509 static bool_t
510 svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
512 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
513 XDR *xdrs = &(cd->xdrs);
514 bool_t stat;
516 xdrs->x_op = XDR_ENCODE;
517 msg->rm_xid = cd->x_id;
518 stat = INTUSE(xdr_replymsg) (xdrs, msg);
519 (void) INTUSE(xdrrec_endofrecord) (xdrs, TRUE);
520 return stat;