Update.
[glibc.git] / sunrpc / svc_unix.c
blob9ee64d030310c1674570ce76f56abb4c15cd2716
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 <sys/socket.h>
45 #include <sys/uio.h>
46 #include <errno.h>
47 #include <stdlib.h>
50 * Ops vector for AF_UNIX based rpc service handle
52 static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
53 static enum xprt_stat svcunix_stat (SVCXPRT *);
54 static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
55 static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
56 static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
57 static void svcunix_destroy (SVCXPRT *);
59 static const struct xp_ops svcunix_op =
61 svcunix_recv,
62 svcunix_stat,
63 svcunix_getargs,
64 svcunix_reply,
65 svcunix_freeargs,
66 svcunix_destroy
70 * Ops vector for AF_UNIX rendezvous handler
72 static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
73 static enum xprt_stat rendezvous_stat (SVCXPRT *);
75 static const struct xp_ops svcunix_rendezvous_op =
77 rendezvous_request,
78 rendezvous_stat,
79 (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) abort,
80 (bool_t (*) (SVCXPRT *, struct rpc_msg *)) abort,
81 (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) abort,
82 svcunix_destroy
85 static int readunix (char*, char *, int);
86 static int writeunix (char *, char *, int);
87 static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
89 struct unix_rendezvous { /* kept in xprt->xp_p1 */
90 u_int sendsize;
91 u_int recvsize;
94 struct unix_conn { /* kept in xprt->xp_p1 */
95 enum xprt_stat strm_stat;
96 u_long x_id;
97 XDR xdrs;
98 char verf_body[MAX_AUTH_BYTES];
102 * Usage:
103 * xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
105 * Creates, registers, and returns a (rpc) unix based transporter.
106 * Once *xprt is initialized, it is registered as a transporter
107 * see (svc.h, xprt_register). This routine returns
108 * a NULL if a problem occurred.
110 * If sock<0 then a socket is created, else sock is used.
111 * If the socket, sock is not bound to a port then svcunix_create
112 * binds it to an arbitrary port. The routine then starts a unix
113 * listener on the socket's associated port. In any (successful) case,
114 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
115 * associated port number.
117 * Since unix streams do buffered io similar to stdio, the caller can specify
118 * how big the send and receive buffers are via the second and third parms;
119 * 0 => use the system default.
121 SVCXPRT *
122 svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
124 bool_t madesock = FALSE;
125 SVCXPRT *xprt;
126 struct unix_rendezvous *r;
127 struct sockaddr_un addr;
128 socklen_t len = sizeof (struct sockaddr_in);
130 if (sock == RPC_ANYSOCK)
132 if ((sock = __socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
134 perror (_("svc_unix.c - AF_UNIX socket creation problem"));
135 return (SVCXPRT *) NULL;
137 madesock = TRUE;
139 memset (&addr, '\0', sizeof (addr));
140 addr.sun_family = AF_UNIX;
141 len = strlen (path) + 1;
142 memcpy (addr.sun_path, path, len);
143 len += sizeof (addr.sun_family);
145 bind (sock, (struct sockaddr *) &addr, len);
147 if (getsockname (sock, (struct sockaddr *) &addr, &len) != 0
148 || listen (sock, 2) != 0)
150 perror (_("svc_unix.c - cannot getsockname or listen"));
151 if (madesock)
152 __close (sock);
153 return (SVCXPRT *) NULL;
156 r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
157 if (r == NULL)
159 fputs (_("svcunix_create: out of memory\n"), stderr);
160 return NULL;
162 r->sendsize = sendsize;
163 r->recvsize = recvsize;
164 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
165 if (xprt == NULL)
167 fputs (_("svcunix_create: out of memory\n"), stderr);
168 return NULL;
170 xprt->xp_p2 = NULL;
171 xprt->xp_p1 = (caddr_t) r;
172 xprt->xp_verf = _null_auth;
173 xprt->xp_ops = &svcunix_rendezvous_op;
174 xprt->xp_port = -1;
175 xprt->xp_sock = sock;
176 xprt_register (xprt);
177 return xprt;
181 * Like svunix_create(), except the routine takes any *open* UNIX file
182 * descriptor as its first input.
184 SVCXPRT *
185 svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
187 return makefd_xprt (fd, sendsize, recvsize);
190 static SVCXPRT *
191 internal_function
192 makefd_xprt (int fd, u_int sendsize, u_int recvsize)
194 SVCXPRT *xprt;
195 struct unix_conn *cd;
197 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
198 if (xprt == (SVCXPRT *) NULL)
200 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
201 goto done;
203 cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
204 if (cd == (struct unix_conn *) NULL)
206 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
207 mem_free ((char *) xprt, sizeof (SVCXPRT));
208 xprt = (SVCXPRT *) NULL;
209 goto done;
211 cd->strm_stat = XPRT_IDLE;
212 xdrrec_create (&(cd->xdrs), sendsize, recvsize,
213 (caddr_t) xprt, readunix, writeunix);
214 xprt->xp_p2 = NULL;
215 xprt->xp_p1 = (caddr_t) cd;
216 xprt->xp_verf.oa_base = cd->verf_body;
217 xprt->xp_addrlen = 0;
218 xprt->xp_ops = &svcunix_op; /* truly deals with calls */
219 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */
220 xprt->xp_sock = fd;
221 xprt_register (xprt);
222 done:
223 return xprt;
226 static bool_t
227 rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg)
229 int sock;
230 struct unix_rendezvous *r;
231 struct sockaddr_un addr;
232 struct sockaddr_in in_addr;
233 socklen_t len;
235 r = (struct unix_rendezvous *) xprt->xp_p1;
236 again:
237 len = sizeof (struct sockaddr_un);
238 if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
240 if (errno == EINTR)
241 goto again;
242 return FALSE;
245 * make a new transporter (re-uses xprt)
247 memset (&in_addr, '\0', sizeof (in_addr));
248 in_addr.sin_family = AF_UNIX;
249 xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
250 xprt->xp_raddr = in_addr;
251 xprt->xp_addrlen = len;
252 return FALSE; /* there is never an rpc msg to be processed */
255 static enum xprt_stat
256 rendezvous_stat (SVCXPRT *xprt)
258 return XPRT_IDLE;
261 static void
262 svcunix_destroy (SVCXPRT *xprt)
264 struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
266 xprt_unregister (xprt);
267 __close (xprt->xp_sock);
268 if (xprt->xp_port != 0)
270 /* a rendezvouser socket */
271 xprt->xp_port = 0;
273 else
275 /* an actual connection socket */
276 XDR_DESTROY (&(cd->xdrs));
278 mem_free ((caddr_t) cd, sizeof (struct unix_conn));
279 mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
282 struct cmessage {
283 struct cmsghdr cmsg;
284 struct ucred cmcred;
287 /* XXX This is not thread safe, but since the main functions in svc.c
288 and the rpcgen generated *_svc functions for the daemon are also not
289 thread safe and uses static global variables, it doesn't matter. */
290 static struct cmessage cm;
292 static int
293 __msgread (int sock, void *buf, size_t cnt)
295 struct iovec iov[1];
296 struct msghdr msg;
297 int on = 1;
299 iov[0].iov_base = buf;
300 iov[0].iov_len = cnt;
302 msg.msg_iov = iov;
303 msg.msg_iovlen = 1;
304 msg.msg_name = NULL;
305 msg.msg_namelen = 0;
306 msg.msg_control = (caddr_t) &cm;
307 msg.msg_controllen = sizeof (struct cmessage);
308 msg.msg_flags = 0;
310 #ifdef SO_PASSCRED
311 if (setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
312 return -1;
313 #endif
315 return recvmsg (sock, &msg, 0);
318 static int
319 __msgwrite (int sock, void *buf, size_t cnt)
321 #ifndef SCM_CREDENTIALS
322 /* We cannot implement this reliably. */
323 __set_errno (ENOSYS);
324 return -1;
325 #else
326 struct iovec iov[1];
327 struct msghdr msg;
329 iov[0].iov_base = buf;
330 iov[0].iov_len = cnt;
332 cm.cmsg.cmsg_type = SCM_CREDENTIALS;
333 cm.cmsg.cmsg_level = SOL_SOCKET;
334 cm.cmsg.cmsg_len = sizeof (struct cmessage);
335 /* XXX I'm not sure, if we really should use gete?id(), or get?id().
336 It would be much better, if the kernel could pass both to the
337 client. */
338 cm.cmcred.pid = __getpid ();
339 cm.cmcred.uid = __geteuid ();
340 cm.cmcred.gid = __getegid ();
342 msg.msg_iov = iov;
343 msg.msg_iovlen = 1;
344 msg.msg_name = NULL;
345 msg.msg_namelen = 0;
346 msg.msg_control = (caddr_t) &cm;
347 msg.msg_controllen = sizeof (struct cmessage);
348 msg.msg_flags = 0;
350 return sendmsg (sock, &msg, 0);
351 #endif
355 * All read operations timeout after 35 seconds.
356 * A timeout is fatal for the connection.
358 static struct timeval wait_per_try = {35, 0};
361 * reads data from the unix connection.
362 * any error is fatal and the connection is closed.
363 * (And a read of zero bytes is a half closed stream => error.)
365 static int
366 readunix (char *xprtptr, char *buf, int len)
368 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
369 int sock = xprt->xp_sock;
370 #ifdef FD_SETSIZE
371 fd_set readfds;
372 #else
373 int mask = 1 << sock;
374 int readfds;
375 #endif /* def FD_SETSIZE */
376 while (1)
378 struct timeval timeout = wait_per_try;
379 readfds = svc_fdset;
380 #ifdef FD_SETSIZE
381 FD_SET (sock, &readfds);
382 #else
383 readfds |= (1 << sock);
384 #endif /* def FD_SETSIZE */
385 if (__select (_rpc_dtablesize (), &readfds, (fd_set *) NULL,
386 (fd_set *) NULL, &timeout) <= 0)
388 if (errno == EINTR)
389 continue;
390 goto fatal_err;
393 #ifdef FD_SETSIZE
394 if (FD_ISSET (sock, &readfds))
395 #else
396 if (readfds == mask)
397 #endif /* def FD_SETSIZE */
398 break;
400 svc_getreqset (&readfds);
403 if ((len = __msgread (sock, buf, len)) > 0)
404 return len;
406 fatal_err:
407 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
408 return -1;
412 * writes data to the unix connection.
413 * Any error is fatal and the connection is closed.
415 static int
416 writeunix (char *xprtptr, char * buf, int len)
418 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
419 int i, cnt;
421 for (cnt = len; cnt > 0; cnt -= i, buf += i)
423 if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
425 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
426 return -1;
429 return len;
432 static enum xprt_stat
433 svcunix_stat (SVCXPRT *xprt)
435 struct unix_conn *cd =
436 (struct unix_conn *) (xprt->xp_p1);
438 if (cd->strm_stat == XPRT_DIED)
439 return XPRT_DIED;
440 if (!xdrrec_eof (&(cd->xdrs)))
441 return XPRT_MOREREQS;
442 return XPRT_IDLE;
445 static bool_t
446 svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
448 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
449 XDR *xdrs = &(cd->xdrs);
451 xdrs->x_op = XDR_DECODE;
452 xdrrec_skiprecord (xdrs);
453 if (xdr_callmsg (xdrs, msg))
455 cd->x_id = msg->rm_xid;
456 /* set up verifiers */
457 msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
458 msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
459 msg->rm_call.cb_verf.oa_length = sizeof (cm);
460 return TRUE;
462 cd->strm_stat = XPRT_DIED; /* XXXX */
463 return FALSE;
466 static bool_t
467 svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
469 return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
470 args_ptr);
473 static bool_t
474 svcunix_freeargs (xprt, xdr_args, args_ptr)
475 SVCXPRT *xprt;
476 xdrproc_t xdr_args;
477 caddr_t args_ptr;
479 XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
481 xdrs->x_op = XDR_FREE;
482 return (*xdr_args) (xdrs, args_ptr);
485 static bool_t
486 svcunix_reply (xprt, msg)
487 SVCXPRT *xprt;
488 struct rpc_msg *msg;
490 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
491 XDR *xdrs = &(cd->xdrs);
492 bool_t stat;
494 xdrs->x_op = XDR_ENCODE;
495 msg->rm_xid = cd->x_id;
496 stat = xdr_replymsg (xdrs, msg);
497 (void) xdrrec_endofrecord (xdrs, TRUE);
498 return stat;