Update.
[glibc.git] / sunrpc / svc_unix.c
blob4aa05a14758bbd99540e3b4a613d15e0e8838324
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>
53 * Ops vector for AF_UNIX based rpc service handle
55 static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
56 static enum xprt_stat svcunix_stat (SVCXPRT *);
57 static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
58 static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
59 static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
60 static void svcunix_destroy (SVCXPRT *);
62 static const struct xp_ops svcunix_op =
64 svcunix_recv,
65 svcunix_stat,
66 svcunix_getargs,
67 svcunix_reply,
68 svcunix_freeargs,
69 svcunix_destroy
73 * Ops vector for AF_UNIX rendezvous handler
75 static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
76 static enum xprt_stat rendezvous_stat (SVCXPRT *);
78 static const struct xp_ops svcunix_rendezvous_op =
80 rendezvous_request,
81 rendezvous_stat,
82 (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) abort,
83 (bool_t (*) (SVCXPRT *, struct rpc_msg *)) abort,
84 (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) abort,
85 svcunix_destroy
88 static int readunix (char*, char *, int);
89 static int writeunix (char *, char *, int);
90 static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
92 struct unix_rendezvous { /* kept in xprt->xp_p1 */
93 u_int sendsize;
94 u_int recvsize;
97 struct unix_conn { /* kept in xprt->xp_p1 */
98 enum xprt_stat strm_stat;
99 u_long x_id;
100 XDR xdrs;
101 char verf_body[MAX_AUTH_BYTES];
105 * Usage:
106 * xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
108 * Creates, registers, and returns a (rpc) unix based transporter.
109 * Once *xprt is initialized, it is registered as a transporter
110 * see (svc.h, xprt_register). This routine returns
111 * a NULL if a problem occurred.
113 * If sock<0 then a socket is created, else sock is used.
114 * If the socket, sock is not bound to a port then svcunix_create
115 * binds it to an arbitrary port. The routine then starts a unix
116 * listener on the socket's associated port. In any (successful) case,
117 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
118 * associated port number.
120 * Since unix streams do buffered io similar to stdio, the caller can specify
121 * how big the send and receive buffers are via the second and third parms;
122 * 0 => use the system default.
124 SVCXPRT *
125 svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
127 bool_t madesock = FALSE;
128 SVCXPRT *xprt;
129 struct unix_rendezvous *r;
130 struct sockaddr_un addr;
131 socklen_t len = sizeof (struct sockaddr_in);
133 if (sock == RPC_ANYSOCK)
135 if ((sock = __socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
137 perror (_("svc_unix.c - AF_UNIX socket creation problem"));
138 return (SVCXPRT *) NULL;
140 madesock = TRUE;
142 memset (&addr, '\0', sizeof (addr));
143 addr.sun_family = AF_UNIX;
144 len = strlen (path) + 1;
145 memcpy (addr.sun_path, path, len);
146 len += sizeof (addr.sun_family);
148 bind (sock, (struct sockaddr *) &addr, len);
150 if (getsockname (sock, (struct sockaddr *) &addr, &len) != 0
151 || listen (sock, 2) != 0)
153 perror (_("svc_unix.c - cannot getsockname or listen"));
154 if (madesock)
155 __close (sock);
156 return (SVCXPRT *) NULL;
159 r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
160 if (r == NULL)
162 fputs (_("svcunix_create: out of memory\n"), stderr);
163 return NULL;
165 r->sendsize = sendsize;
166 r->recvsize = recvsize;
167 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
168 if (xprt == NULL)
170 fputs (_("svcunix_create: out of memory\n"), stderr);
171 return NULL;
173 xprt->xp_p2 = NULL;
174 xprt->xp_p1 = (caddr_t) r;
175 xprt->xp_verf = _null_auth;
176 xprt->xp_ops = &svcunix_rendezvous_op;
177 xprt->xp_port = -1;
178 xprt->xp_sock = sock;
179 xprt_register (xprt);
180 return xprt;
184 * Like svunix_create(), except the routine takes any *open* UNIX file
185 * descriptor as its first input.
187 SVCXPRT *
188 svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
190 return makefd_xprt (fd, sendsize, recvsize);
193 static SVCXPRT *
194 internal_function
195 makefd_xprt (int fd, u_int sendsize, u_int recvsize)
197 SVCXPRT *xprt;
198 struct unix_conn *cd;
200 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
201 if (xprt == (SVCXPRT *) NULL)
203 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
204 goto done;
206 cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
207 if (cd == (struct unix_conn *) NULL)
209 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
210 mem_free ((char *) xprt, sizeof (SVCXPRT));
211 xprt = (SVCXPRT *) NULL;
212 goto done;
214 cd->strm_stat = XPRT_IDLE;
215 xdrrec_create (&(cd->xdrs), sendsize, recvsize,
216 (caddr_t) xprt, readunix, writeunix);
217 xprt->xp_p2 = NULL;
218 xprt->xp_p1 = (caddr_t) cd;
219 xprt->xp_verf.oa_base = cd->verf_body;
220 xprt->xp_addrlen = 0;
221 xprt->xp_ops = &svcunix_op; /* truly deals with calls */
222 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */
223 xprt->xp_sock = fd;
224 xprt_register (xprt);
225 done:
226 return xprt;
229 static bool_t
230 rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg)
232 int sock;
233 struct unix_rendezvous *r;
234 struct sockaddr_un addr;
235 struct sockaddr_in in_addr;
236 socklen_t len;
238 r = (struct unix_rendezvous *) xprt->xp_p1;
239 again:
240 len = sizeof (struct sockaddr_un);
241 if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
243 if (errno == EINTR)
244 goto again;
245 return FALSE;
248 * make a new transporter (re-uses xprt)
250 memset (&in_addr, '\0', sizeof (in_addr));
251 in_addr.sin_family = AF_UNIX;
252 xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
253 memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr));
254 xprt->xp_addrlen = len;
255 return FALSE; /* there is never an rpc msg to be processed */
258 static enum xprt_stat
259 rendezvous_stat (SVCXPRT *xprt)
261 return XPRT_IDLE;
264 static void
265 svcunix_destroy (SVCXPRT *xprt)
267 struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
269 xprt_unregister (xprt);
270 __close (xprt->xp_sock);
271 if (xprt->xp_port != 0)
273 /* a rendezvouser socket */
274 xprt->xp_port = 0;
276 else
278 /* an actual connection socket */
279 XDR_DESTROY (&(cd->xdrs));
281 mem_free ((caddr_t) cd, sizeof (struct unix_conn));
282 mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
285 #ifdef SCM_CREDENTIALS
286 struct cmessage {
287 struct cmsghdr cmsg;
288 struct ucred cmcred;
289 /* hack to make sure we have enough memory */
290 char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
293 /* XXX This is not thread safe, but since the main functions in svc.c
294 and the rpcgen generated *_svc functions for the daemon are also not
295 thread safe and uses static global variables, it doesn't matter. */
296 static struct cmessage cm;
297 #endif
299 static int
300 __msgread (int sock, void *data, size_t cnt)
302 struct iovec iov;
303 struct msghdr msg;
304 int len;
306 iov.iov_base = data;
307 iov.iov_len = cnt;
309 msg.msg_iov = &iov;
310 msg.msg_iovlen = 1;
311 msg.msg_name = NULL;
312 msg.msg_namelen = 0;
313 #ifdef SCM_CREDENTIALS
314 msg.msg_control = (caddr_t) &cm;
315 msg.msg_controllen = sizeof (struct cmessage);
316 #endif
317 msg.msg_flags = 0;
319 #ifdef SO_PASSCRED
321 int on = 1;
322 if (setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
323 return -1;
325 #endif
327 restart:
328 len = recvmsg (sock, &msg, 0);
329 if (len >= 0)
331 if (msg.msg_flags & MSG_CTRUNC || len == 0)
332 return 0;
333 else
334 return len;
336 if (errno == EINTR)
337 goto restart;
338 return -1;
341 static int
342 __msgwrite (int sock, void *data, size_t cnt)
344 #ifndef SCM_CREDENTIALS
345 /* We cannot implement this reliably. */
346 __set_errno (ENOSYS);
347 return -1;
348 #else
349 struct iovec iov;
350 struct msghdr msg;
351 struct cmsghdr *cmsg = &cm.cmsg;
352 struct ucred cred;
353 int len;
355 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
356 get?id(). But since keyserv needs geteuid(), we have no other chance.
357 It would be much better, if the kernel could pass both to the server. */
358 cred.pid = __getpid ();
359 cred.uid = __geteuid ();
360 cred.gid = __getegid ();
362 memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
363 cmsg->cmsg_level = SOL_SOCKET;
364 cmsg->cmsg_type = SCM_CREDENTIALS;
365 cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
367 iov.iov_base = data;
368 iov.iov_len = cnt;
370 msg.msg_iov = &iov;
371 msg.msg_iovlen = 1;
372 msg.msg_name = NULL;
373 msg.msg_namelen = 0;
374 msg.msg_control = cmsg;
375 msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
376 msg.msg_flags = 0;
378 restart:
379 len = sendmsg (sock, &msg, 0);
380 if (len >= 0)
381 return len;
382 if (errno == EINTR)
383 goto restart;
384 return -1;
386 #endif
390 * reads data from the unix connection.
391 * any error is fatal and the connection is closed.
392 * (And a read of zero bytes is a half closed stream => error.)
394 static int
395 readunix (char *xprtptr, char *buf, int len)
397 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
398 int sock = xprt->xp_sock;
399 int milliseconds = 35 * 1000;
400 struct pollfd pollfd;
404 pollfd.fd = sock;
405 pollfd.events = POLLIN;
406 switch (__poll (&pollfd, 1, milliseconds))
408 case -1:
409 if (errno == EINTR)
410 continue;
411 /*FALLTHROUGH*/
412 case 0:
413 goto fatal_err;
414 default:
415 if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
416 || (pollfd.revents & POLLNVAL))
417 goto fatal_err;
418 break;
421 while ((pollfd.revents & POLLIN) == 0);
423 if ((len = __msgread (sock, buf, len)) > 0)
424 return len;
426 fatal_err:
427 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
428 return -1;
432 * writes data to the unix connection.
433 * Any error is fatal and the connection is closed.
435 static int
436 writeunix (char *xprtptr, char * buf, int len)
438 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
439 int i, cnt;
441 for (cnt = len; cnt > 0; cnt -= i, buf += i)
443 if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
445 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
446 return -1;
449 return len;
452 static enum xprt_stat
453 svcunix_stat (SVCXPRT *xprt)
455 struct unix_conn *cd =
456 (struct unix_conn *) (xprt->xp_p1);
458 if (cd->strm_stat == XPRT_DIED)
459 return XPRT_DIED;
460 if (!xdrrec_eof (&(cd->xdrs)))
461 return XPRT_MOREREQS;
462 return XPRT_IDLE;
465 static bool_t
466 svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
468 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
469 XDR *xdrs = &(cd->xdrs);
471 xdrs->x_op = XDR_DECODE;
472 xdrrec_skiprecord (xdrs);
473 if (xdr_callmsg (xdrs, msg))
475 cd->x_id = msg->rm_xid;
476 /* set up verifiers */
477 #ifdef SCM_CREDENTIALS
478 msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
479 msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
480 msg->rm_call.cb_verf.oa_length = sizeof (cm);
481 #endif
482 return TRUE;
484 cd->strm_stat = XPRT_DIED; /* XXXX */
485 return FALSE;
488 static bool_t
489 svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
491 return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
492 args_ptr);
495 static bool_t
496 svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
498 XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
500 xdrs->x_op = XDR_FREE;
501 return (*xdr_args) (xdrs, args_ptr);
504 static bool_t
505 svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
507 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
508 XDR *xdrs = &(cd->xdrs);
509 bool_t stat;
511 xdrs->x_op = XDR_ENCODE;
512 msg->rm_xid = cd->x_id;
513 stat = xdr_replymsg (xdrs, msg);
514 (void) xdrrec_endofrecord (xdrs, TRUE);
515 return stat;