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.
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 #define xdrrec_create __xdrrec_create
41 #define xdrrec_endofrecord __xdrrec_endofrecord
42 #define xdrrec_skiprecord __xdrrec_skiprecord
43 #define xdrrec_eof __xdrrec_eof
44 #define xdr_callmsg __xdr_callmsg
45 #define xdr_replymsg __xdr_replymsg
46 #define xprt_register __xprt_register
47 #define getegid __getegid
48 #define geteuid __geteuid
58 #include <sys/socket.h>
69 * Ops vector for AF_UNIX based rpc service handle
71 static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
72 static enum xprt_stat svcunix_stat (SVCXPRT *);
73 static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
74 static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
75 static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
76 static void svcunix_destroy (SVCXPRT *);
78 static const struct xp_ops svcunix_op =
89 * Ops vector for AF_UNIX rendezvous handler
91 static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
92 static enum xprt_stat rendezvous_stat (SVCXPRT *);
93 static void svcunix_rendezvous_abort (void);
95 /* This function makes sure abort() relocation goes through PLT
96 and thus can be lazy bound. */
98 svcunix_rendezvous_abort (void)
103 static const struct xp_ops svcunix_rendezvous_op =
107 (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
108 (bool_t (*) (SVCXPRT *, struct rpc_msg *)) svcunix_rendezvous_abort,
109 (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
113 static int readunix (char*, char *, int);
114 static int writeunix (char *, char *, int);
115 static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
117 struct unix_rendezvous { /* kept in xprt->xp_p1 */
122 struct unix_conn { /* kept in xprt->xp_p1 */
123 enum xprt_stat strm_stat;
126 char verf_body[MAX_AUTH_BYTES];
131 * xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
133 * Creates, registers, and returns a (rpc) unix based transporter.
134 * Once *xprt is initialized, it is registered as a transporter
135 * see (svc.h, xprt_register). This routine returns
136 * a NULL if a problem occurred.
138 * If sock<0 then a socket is created, else sock is used.
139 * If the socket, sock is not bound to a port then svcunix_create
140 * binds it to an arbitrary port. The routine then starts a unix
141 * listener on the socket's associated port. In any (successful) case,
142 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
143 * associated port number.
145 * Since unix streams do buffered io similar to stdio, the caller can specify
146 * how big the send and receive buffers are via the second and third parms;
147 * 0 => use the system default.
150 svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
152 bool_t madesock = FALSE;
154 struct unix_rendezvous *r;
155 struct sockaddr_un addr;
156 socklen_t len = sizeof (struct sockaddr_in);
158 if (sock == RPC_ANYSOCK)
160 if ((sock = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
162 __perror (_("svc_unix.c - AF_UNIX socket creation problem"));
163 return (SVCXPRT *) NULL;
167 __memset (&addr, '\0', sizeof (addr));
168 addr.sun_family = AF_UNIX;
169 len = __strlen (path) + 1;
170 __memcpy (addr.sun_path, path, len);
171 len += sizeof (addr.sun_family);
173 bind (sock, (struct sockaddr *) &addr, len);
175 if (getsockname (sock, (struct sockaddr *) &addr, &len) != 0
176 || listen (sock, 2) != 0)
178 __perror (_("svc_unix.c - cannot getsockname or listen"));
181 return (SVCXPRT *) NULL;
184 r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
185 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
186 if (r == NULL || xprt == NULL)
189 if (_IO_fwide (stderr, 0) > 0)
190 __fwprintf (stderr, L"%s", _("svcunix_create: out of memory\n"));
193 fputs (_("svcunix_create: out of memory\n"), stderr);
194 mem_free (r, sizeof (*r));
195 mem_free (xprt, sizeof (SVCXPRT));
198 r->sendsize = sendsize;
199 r->recvsize = recvsize;
201 xprt->xp_p1 = (caddr_t) r;
202 xprt->xp_verf = _null_auth;
203 xprt->xp_ops = &svcunix_rendezvous_op;
205 xprt->xp_sock = sock;
206 xprt_register (xprt);
211 * Like svunix_create(), except the routine takes any *open* UNIX file
212 * descriptor as its first input.
215 svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
217 return makefd_xprt (fd, sendsize, recvsize);
222 makefd_xprt (int fd, u_int sendsize, u_int recvsize)
225 struct unix_conn *cd;
227 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
228 cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
229 if (xprt == (SVCXPRT *) NULL || cd == (struct unix_conn *) NULL)
232 if (_IO_fwide (stderr, 0) > 0)
233 (void) __fwprintf (stderr, L"%s",
234 _("svc_unix: makefd_xprt: out of memory\n"));
237 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
238 mem_free (xprt, sizeof (SVCXPRT));
239 mem_free (cd, sizeof (struct unix_conn));
242 cd->strm_stat = XPRT_IDLE;
243 xdrrec_create (&(cd->xdrs), sendsize, recvsize,
244 (caddr_t) xprt, readunix, writeunix);
246 xprt->xp_p1 = (caddr_t) cd;
247 xprt->xp_verf.oa_base = cd->verf_body;
248 xprt->xp_addrlen = 0;
249 xprt->xp_ops = &svcunix_op; /* truly deals with calls */
250 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */
252 xprt_register (xprt);
257 rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg)
260 struct unix_rendezvous *r;
261 struct sockaddr_un addr;
262 struct sockaddr_in in_addr;
265 r = (struct unix_rendezvous *) xprt->xp_p1;
267 len = sizeof (struct sockaddr_un);
268 if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
275 * make a new transporter (re-uses xprt)
277 __memset (&in_addr, '\0', sizeof (in_addr));
278 in_addr.sin_family = AF_UNIX;
279 xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
280 __memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr));
281 xprt->xp_addrlen = len;
282 return FALSE; /* there is never an rpc msg to be processed */
285 static enum xprt_stat
286 rendezvous_stat (SVCXPRT *xprt)
292 svcunix_destroy (SVCXPRT *xprt)
294 struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
296 xprt_unregister (xprt);
297 __close (xprt->xp_sock);
298 if (xprt->xp_port != 0)
300 /* a rendezvouser socket */
305 /* an actual connection socket */
306 XDR_DESTROY (&(cd->xdrs));
308 mem_free ((caddr_t) cd, sizeof (struct unix_conn));
309 mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
312 #ifdef SCM_CREDENTIALS
316 /* hack to make sure we have enough memory */
317 char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
320 /* XXX This is not thread safe, but since the main functions in svc.c
321 and the rpcgen generated *_svc functions for the daemon are also not
322 thread safe and uses static global variables, it doesn't matter. */
323 static struct cmessage cm;
327 __msgread (int sock, void *data, size_t cnt)
340 #ifdef SCM_CREDENTIALS
341 msg.msg_control = (caddr_t) &cm;
342 msg.msg_controllen = sizeof (struct cmessage);
349 if (setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
355 len = recvmsg (sock, &msg, 0);
358 if (msg.msg_flags & MSG_CTRUNC || len == 0)
369 __msgwrite (int sock, void *data, size_t cnt)
371 #ifndef SCM_CREDENTIALS
372 /* We cannot implement this reliably. */
373 __set_errno (ENOSYS);
378 struct cmsghdr *cmsg = &cm.cmsg;
382 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
383 get?id(). But since keyserv needs geteuid(), we have no other chance.
384 It would be much better, if the kernel could pass both to the server. */
385 cred.pid = __getpid ();
386 cred.uid = geteuid ();
387 cred.gid = getegid ();
389 __memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
390 cmsg->cmsg_level = SOL_SOCKET;
391 cmsg->cmsg_type = SCM_CREDENTIALS;
392 cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
401 msg.msg_control = cmsg;
402 msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
406 len = sendmsg (sock, &msg, 0);
417 * reads data from the unix connection.
418 * any error is fatal and the connection is closed.
419 * (And a read of zero bytes is a half closed stream => error.)
422 readunix (char *xprtptr, char *buf, int len)
424 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
425 int sock = xprt->xp_sock;
426 int milliseconds = 35 * 1000;
427 struct pollfd pollfd;
432 pollfd.events = POLLIN;
433 switch (poll (&pollfd, 1, milliseconds))
442 if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
443 || (pollfd.revents & POLLNVAL))
448 while ((pollfd.revents & POLLIN) == 0);
450 if ((len = __msgread (sock, buf, len)) > 0)
454 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
459 * writes data to the unix connection.
460 * Any error is fatal and the connection is closed.
463 writeunix (char *xprtptr, char * buf, int len)
465 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
468 for (cnt = len; cnt > 0; cnt -= i, buf += i)
470 if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
472 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
479 static enum xprt_stat
480 svcunix_stat (SVCXPRT *xprt)
482 struct unix_conn *cd =
483 (struct unix_conn *) (xprt->xp_p1);
485 if (cd->strm_stat == XPRT_DIED)
487 if (!xdrrec_eof (&(cd->xdrs)))
488 return XPRT_MOREREQS;
493 svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
495 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
496 XDR *xdrs = &(cd->xdrs);
498 xdrs->x_op = XDR_DECODE;
499 xdrrec_skiprecord (xdrs);
500 if (xdr_callmsg (xdrs, msg))
502 cd->x_id = msg->rm_xid;
503 /* set up verifiers */
504 #ifdef SCM_CREDENTIALS
505 msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
506 msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
507 msg->rm_call.cb_verf.oa_length = sizeof (cm);
511 cd->strm_stat = XPRT_DIED; /* XXXX */
516 svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
518 return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
523 svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
525 XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
527 xdrs->x_op = XDR_FREE;
528 return (*xdr_args) (xdrs, args_ptr);
532 svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
534 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
535 XDR *xdrs = &(cd->xdrs);
538 xdrs->x_op = XDR_ENCODE;
539 msg->rm_xid = cd->x_id;
540 stat = xdr_replymsg (xdrs, msg);
541 (void) xdrrec_endofrecord (xdrs, TRUE);