Update.
[glibc.git] / sunrpc / svc_unix.c
bloba34e54dd71dfba7d5a27f8ff4a3954a2f4a0d360
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 <sys/poll.h>
47 #include <errno.h>
48 #include <stdlib.h>
51 * Ops vector for AF_UNIX based rpc service handle
53 static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
54 static enum xprt_stat svcunix_stat (SVCXPRT *);
55 static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
56 static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
57 static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
58 static void svcunix_destroy (SVCXPRT *);
60 static const struct xp_ops svcunix_op =
62 svcunix_recv,
63 svcunix_stat,
64 svcunix_getargs,
65 svcunix_reply,
66 svcunix_freeargs,
67 svcunix_destroy
71 * Ops vector for AF_UNIX rendezvous handler
73 static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
74 static enum xprt_stat rendezvous_stat (SVCXPRT *);
76 static const struct xp_ops svcunix_rendezvous_op =
78 rendezvous_request,
79 rendezvous_stat,
80 (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) abort,
81 (bool_t (*) (SVCXPRT *, struct rpc_msg *)) abort,
82 (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) abort,
83 svcunix_destroy
86 static int readunix (char*, char *, int);
87 static int writeunix (char *, char *, int);
88 static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
90 struct unix_rendezvous { /* kept in xprt->xp_p1 */
91 u_int sendsize;
92 u_int recvsize;
95 struct unix_conn { /* kept in xprt->xp_p1 */
96 enum xprt_stat strm_stat;
97 u_long x_id;
98 XDR xdrs;
99 char verf_body[MAX_AUTH_BYTES];
103 * Usage:
104 * xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
106 * Creates, registers, and returns a (rpc) unix based transporter.
107 * Once *xprt is initialized, it is registered as a transporter
108 * see (svc.h, xprt_register). This routine returns
109 * a NULL if a problem occurred.
111 * If sock<0 then a socket is created, else sock is used.
112 * If the socket, sock is not bound to a port then svcunix_create
113 * binds it to an arbitrary port. The routine then starts a unix
114 * listener on the socket's associated port. In any (successful) case,
115 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
116 * associated port number.
118 * Since unix streams do buffered io similar to stdio, the caller can specify
119 * how big the send and receive buffers are via the second and third parms;
120 * 0 => use the system default.
122 SVCXPRT *
123 svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
125 bool_t madesock = FALSE;
126 SVCXPRT *xprt;
127 struct unix_rendezvous *r;
128 struct sockaddr_un addr;
129 socklen_t len = sizeof (struct sockaddr_in);
131 if (sock == RPC_ANYSOCK)
133 if ((sock = __socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
135 perror (_("svc_unix.c - AF_UNIX socket creation problem"));
136 return (SVCXPRT *) NULL;
138 madesock = TRUE;
140 memset (&addr, '\0', sizeof (addr));
141 addr.sun_family = AF_UNIX;
142 len = strlen (path) + 1;
143 memcpy (addr.sun_path, path, len);
144 len += sizeof (addr.sun_family);
146 bind (sock, (struct sockaddr *) &addr, len);
148 if (getsockname (sock, (struct sockaddr *) &addr, &len) != 0
149 || listen (sock, 2) != 0)
151 perror (_("svc_unix.c - cannot getsockname or listen"));
152 if (madesock)
153 __close (sock);
154 return (SVCXPRT *) NULL;
157 r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
158 if (r == NULL)
160 fputs (_("svcunix_create: out of memory\n"), stderr);
161 return NULL;
163 r->sendsize = sendsize;
164 r->recvsize = recvsize;
165 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
166 if (xprt == NULL)
168 fputs (_("svcunix_create: out of memory\n"), stderr);
169 return NULL;
171 xprt->xp_p2 = NULL;
172 xprt->xp_p1 = (caddr_t) r;
173 xprt->xp_verf = _null_auth;
174 xprt->xp_ops = &svcunix_rendezvous_op;
175 xprt->xp_port = -1;
176 xprt->xp_sock = sock;
177 xprt_register (xprt);
178 return xprt;
182 * Like svunix_create(), except the routine takes any *open* UNIX file
183 * descriptor as its first input.
185 SVCXPRT *
186 svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
188 return makefd_xprt (fd, sendsize, recvsize);
191 static SVCXPRT *
192 internal_function
193 makefd_xprt (int fd, u_int sendsize, u_int recvsize)
195 SVCXPRT *xprt;
196 struct unix_conn *cd;
198 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
199 if (xprt == (SVCXPRT *) NULL)
201 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
202 goto done;
204 cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
205 if (cd == (struct unix_conn *) NULL)
207 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
208 mem_free ((char *) xprt, sizeof (SVCXPRT));
209 xprt = (SVCXPRT *) NULL;
210 goto done;
212 cd->strm_stat = XPRT_IDLE;
213 xdrrec_create (&(cd->xdrs), sendsize, recvsize,
214 (caddr_t) xprt, readunix, writeunix);
215 xprt->xp_p2 = NULL;
216 xprt->xp_p1 = (caddr_t) cd;
217 xprt->xp_verf.oa_base = cd->verf_body;
218 xprt->xp_addrlen = 0;
219 xprt->xp_ops = &svcunix_op; /* truly deals with calls */
220 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */
221 xprt->xp_sock = fd;
222 xprt_register (xprt);
223 done:
224 return xprt;
227 static bool_t
228 rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg)
230 int sock;
231 struct unix_rendezvous *r;
232 struct sockaddr_un addr;
233 struct sockaddr_in in_addr;
234 socklen_t len;
236 r = (struct unix_rendezvous *) xprt->xp_p1;
237 again:
238 len = sizeof (struct sockaddr_un);
239 if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
241 if (errno == EINTR)
242 goto again;
243 return FALSE;
246 * make a new transporter (re-uses xprt)
248 memset (&in_addr, '\0', sizeof (in_addr));
249 in_addr.sin_family = AF_UNIX;
250 xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
251 xprt->xp_raddr = in_addr;
252 xprt->xp_addrlen = len;
253 return FALSE; /* there is never an rpc msg to be processed */
256 static enum xprt_stat
257 rendezvous_stat (SVCXPRT *xprt)
259 return XPRT_IDLE;
262 static void
263 svcunix_destroy (SVCXPRT *xprt)
265 struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
267 xprt_unregister (xprt);
268 __close (xprt->xp_sock);
269 if (xprt->xp_port != 0)
271 /* a rendezvouser socket */
272 xprt->xp_port = 0;
274 else
276 /* an actual connection socket */
277 XDR_DESTROY (&(cd->xdrs));
279 mem_free ((caddr_t) cd, sizeof (struct unix_conn));
280 mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
283 #ifdef SCM_CREDENTIALS
284 struct cmessage {
285 struct cmsghdr cmsg;
286 struct ucred cmcred;
287 /* hack to make sure we have enough memory */
288 char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
291 /* XXX This is not thread safe, but since the main functions in svc.c
292 and the rpcgen generated *_svc functions for the daemon are also not
293 thread safe and uses static global variables, it doesn't matter. */
294 static struct cmessage cm;
295 #endif
297 static int
298 __msgread (int sock, void *data, size_t cnt)
300 struct iovec iov;
301 struct msghdr msg;
302 int len;
304 iov.iov_base = data;
305 iov.iov_len = cnt;
307 msg.msg_iov = &iov;
308 msg.msg_iovlen = 1;
309 msg.msg_name = NULL;
310 msg.msg_namelen = 0;
311 #ifdef SCM_CREDENTIALS
312 msg.msg_control = (caddr_t) &cm;
313 msg.msg_controllen = sizeof (struct cmessage);
314 #endif
315 msg.msg_flags = 0;
317 #ifdef SO_PASSCRED
319 int on = 1;
320 if (setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
321 return -1;
323 #endif
325 restart:
326 len = recvmsg (sock, &msg, 0);
327 if (len >= 0)
329 if (msg.msg_flags & MSG_CTRUNC || len == 0)
330 return 0;
331 else
332 return len;
334 if (errno == EINTR)
335 goto restart;
336 return -1;
339 static int
340 __msgwrite (int sock, void *data, size_t cnt)
342 #ifndef SCM_CREDENTIALS
343 /* We cannot implement this reliably. */
344 __set_errno (ENOSYS);
345 return -1;
346 #else
347 struct iovec iov;
348 struct msghdr msg;
349 struct cmsghdr *cmsg = &cm.cmsg;
350 struct ucred cred;
351 int len;
353 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
354 get?id(). But since keyserv needs geteuid(), we have no other chance.
355 It would be much better, if the kernel could pass both to the server. */
356 cred.pid = __getpid ();
357 cred.uid = __geteuid ();
358 cred.gid = __getegid ();
360 memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
361 cmsg->cmsg_level = SOL_SOCKET;
362 cmsg->cmsg_type = SCM_CREDENTIALS;
363 cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
365 iov.iov_base = data;
366 iov.iov_len = cnt;
368 msg.msg_iov = &iov;
369 msg.msg_iovlen = 1;
370 msg.msg_name = NULL;
371 msg.msg_namelen = 0;
372 msg.msg_control = cmsg;
373 msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
374 msg.msg_flags = 0;
376 restart:
377 len = sendmsg (sock, &msg, 0);
378 if (len >= 0)
379 return len;
380 if (errno == EINTR)
381 goto restart;
382 return -1;
384 #endif
388 * reads data from the unix connection.
389 * any error is fatal and the connection is closed.
390 * (And a read of zero bytes is a half closed stream => error.)
392 static int
393 readunix (char *xprtptr, char *buf, int len)
395 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
396 int sock = xprt->xp_sock;
397 int milliseconds = 35 * 1000;
398 struct pollfd pollfd;
402 pollfd.fd = sock;
403 pollfd.events = POLLIN;
404 switch (__poll (&pollfd, 1, milliseconds))
406 case -1:
407 if (errno == EINTR)
408 continue;
409 /*FALLTHROUGH*/
410 case 0:
411 goto fatal_err;
412 default:
413 if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
414 || (pollfd.revents & POLLNVAL))
415 goto fatal_err;
416 break;
419 while ((pollfd.revents & POLLIN) == 0);
421 if ((len = __msgread (sock, buf, len)) > 0)
422 return len;
424 fatal_err:
425 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
426 return -1;
430 * writes data to the unix connection.
431 * Any error is fatal and the connection is closed.
433 static int
434 writeunix (char *xprtptr, char * buf, int len)
436 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
437 int i, cnt;
439 for (cnt = len; cnt > 0; cnt -= i, buf += i)
441 if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
443 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
444 return -1;
447 return len;
450 static enum xprt_stat
451 svcunix_stat (SVCXPRT *xprt)
453 struct unix_conn *cd =
454 (struct unix_conn *) (xprt->xp_p1);
456 if (cd->strm_stat == XPRT_DIED)
457 return XPRT_DIED;
458 if (!xdrrec_eof (&(cd->xdrs)))
459 return XPRT_MOREREQS;
460 return XPRT_IDLE;
463 static bool_t
464 svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
466 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
467 XDR *xdrs = &(cd->xdrs);
469 xdrs->x_op = XDR_DECODE;
470 xdrrec_skiprecord (xdrs);
471 if (xdr_callmsg (xdrs, msg))
473 cd->x_id = msg->rm_xid;
474 /* set up verifiers */
475 #ifdef SCM_CREDENTIALS
476 msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
477 msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
478 msg->rm_call.cb_verf.oa_length = sizeof (cm);
479 #endif
480 return TRUE;
482 cd->strm_stat = XPRT_DIED; /* XXXX */
483 return FALSE;
486 static bool_t
487 svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
489 return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
490 args_ptr);
493 static bool_t
494 svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
496 XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
498 xdrs->x_op = XDR_FREE;
499 return (*xdr_args) (xdrs, args_ptr);
502 static bool_t
503 svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
505 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
506 XDR *xdrs = &(cd->xdrs);
507 bool_t stat;
509 xdrs->x_op = XDR_ENCODE;
510 msg->rm_xid = cd->x_id;
511 stat = xdr_replymsg (xdrs, msg);
512 (void) xdrrec_endofrecord (xdrs, TRUE);
513 return stat;