Update.
[glibc.git] / sunrpc / svc_unix.c
blob20bc0aaf388578e20deb052f1206de42b68f20f6
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 *);
77 static void svcunix_rendezvous_abort (void);
79 /* This function makes sure abort() relocation goes through PLT
80 and thus can be lazy bound. */
81 static void
82 svcunix_rendezvous_abort (void)
84 abort ();
87 static const struct xp_ops svcunix_rendezvous_op =
89 rendezvous_request,
90 rendezvous_stat,
91 (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
92 (bool_t (*) (SVCXPRT *, struct rpc_msg *)) svcunix_rendezvous_abort,
93 (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
94 svcunix_destroy
97 static int readunix (char*, char *, int);
98 static int writeunix (char *, char *, int);
99 static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
101 struct unix_rendezvous { /* kept in xprt->xp_p1 */
102 u_int sendsize;
103 u_int recvsize;
106 struct unix_conn { /* kept in xprt->xp_p1 */
107 enum xprt_stat strm_stat;
108 u_long x_id;
109 XDR xdrs;
110 char verf_body[MAX_AUTH_BYTES];
114 * Usage:
115 * xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
117 * Creates, registers, and returns a (rpc) unix based transporter.
118 * Once *xprt is initialized, it is registered as a transporter
119 * see (svc.h, xprt_register). This routine returns
120 * a NULL if a problem occurred.
122 * If sock<0 then a socket is created, else sock is used.
123 * If the socket, sock is not bound to a port then svcunix_create
124 * binds it to an arbitrary port. The routine then starts a unix
125 * listener on the socket's associated port. In any (successful) case,
126 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
127 * associated port number.
129 * Since unix streams do buffered io similar to stdio, the caller can specify
130 * how big the send and receive buffers are via the second and third parms;
131 * 0 => use the system default.
133 SVCXPRT *
134 svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
136 bool_t madesock = FALSE;
137 SVCXPRT *xprt;
138 struct unix_rendezvous *r;
139 struct sockaddr_un addr;
140 socklen_t len = sizeof (struct sockaddr_in);
142 if (sock == RPC_ANYSOCK)
144 if ((sock = __socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
146 perror (_("svc_unix.c - AF_UNIX socket creation problem"));
147 return (SVCXPRT *) NULL;
149 madesock = TRUE;
151 memset (&addr, '\0', sizeof (addr));
152 addr.sun_family = AF_UNIX;
153 len = strlen (path) + 1;
154 memcpy (addr.sun_path, path, len);
155 len += sizeof (addr.sun_family);
157 bind (sock, (struct sockaddr *) &addr, len);
159 if (getsockname (sock, (struct sockaddr *) &addr, &len) != 0
160 || listen (sock, 2) != 0)
162 perror (_("svc_unix.c - cannot getsockname or listen"));
163 if (madesock)
164 __close (sock);
165 return (SVCXPRT *) NULL;
168 r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
169 if (r == NULL)
171 fputs (_("svcunix_create: out of memory\n"), stderr);
172 return NULL;
174 r->sendsize = sendsize;
175 r->recvsize = recvsize;
176 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
177 if (xprt == NULL)
179 fputs (_("svcunix_create: out of memory\n"), stderr);
180 return NULL;
182 xprt->xp_p2 = NULL;
183 xprt->xp_p1 = (caddr_t) r;
184 xprt->xp_verf = _null_auth;
185 xprt->xp_ops = &svcunix_rendezvous_op;
186 xprt->xp_port = -1;
187 xprt->xp_sock = sock;
188 xprt_register (xprt);
189 return xprt;
193 * Like svunix_create(), except the routine takes any *open* UNIX file
194 * descriptor as its first input.
196 SVCXPRT *
197 svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
199 return makefd_xprt (fd, sendsize, recvsize);
202 static SVCXPRT *
203 internal_function
204 makefd_xprt (int fd, u_int sendsize, u_int recvsize)
206 SVCXPRT *xprt;
207 struct unix_conn *cd;
209 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
210 if (xprt == (SVCXPRT *) NULL)
212 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
213 goto done;
215 cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
216 if (cd == (struct unix_conn *) NULL)
218 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
219 mem_free ((char *) xprt, sizeof (SVCXPRT));
220 xprt = (SVCXPRT *) NULL;
221 goto done;
223 cd->strm_stat = XPRT_IDLE;
224 xdrrec_create (&(cd->xdrs), sendsize, recvsize,
225 (caddr_t) xprt, readunix, writeunix);
226 xprt->xp_p2 = NULL;
227 xprt->xp_p1 = (caddr_t) cd;
228 xprt->xp_verf.oa_base = cd->verf_body;
229 xprt->xp_addrlen = 0;
230 xprt->xp_ops = &svcunix_op; /* truly deals with calls */
231 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */
232 xprt->xp_sock = fd;
233 xprt_register (xprt);
234 done:
235 return xprt;
238 static bool_t
239 rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg)
241 int sock;
242 struct unix_rendezvous *r;
243 struct sockaddr_un addr;
244 struct sockaddr_in in_addr;
245 socklen_t len;
247 r = (struct unix_rendezvous *) xprt->xp_p1;
248 again:
249 len = sizeof (struct sockaddr_un);
250 if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
252 if (errno == EINTR)
253 goto again;
254 return FALSE;
257 * make a new transporter (re-uses xprt)
259 memset (&in_addr, '\0', sizeof (in_addr));
260 in_addr.sin_family = AF_UNIX;
261 xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
262 memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr));
263 xprt->xp_addrlen = len;
264 return FALSE; /* there is never an rpc msg to be processed */
267 static enum xprt_stat
268 rendezvous_stat (SVCXPRT *xprt)
270 return XPRT_IDLE;
273 static void
274 svcunix_destroy (SVCXPRT *xprt)
276 struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
278 xprt_unregister (xprt);
279 __close (xprt->xp_sock);
280 if (xprt->xp_port != 0)
282 /* a rendezvouser socket */
283 xprt->xp_port = 0;
285 else
287 /* an actual connection socket */
288 XDR_DESTROY (&(cd->xdrs));
290 mem_free ((caddr_t) cd, sizeof (struct unix_conn));
291 mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
294 #ifdef SCM_CREDENTIALS
295 struct cmessage {
296 struct cmsghdr cmsg;
297 struct ucred cmcred;
298 /* hack to make sure we have enough memory */
299 char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
302 /* XXX This is not thread safe, but since the main functions in svc.c
303 and the rpcgen generated *_svc functions for the daemon are also not
304 thread safe and uses static global variables, it doesn't matter. */
305 static struct cmessage cm;
306 #endif
308 static int
309 __msgread (int sock, void *data, size_t cnt)
311 struct iovec iov;
312 struct msghdr msg;
313 int len;
315 iov.iov_base = data;
316 iov.iov_len = cnt;
318 msg.msg_iov = &iov;
319 msg.msg_iovlen = 1;
320 msg.msg_name = NULL;
321 msg.msg_namelen = 0;
322 #ifdef SCM_CREDENTIALS
323 msg.msg_control = (caddr_t) &cm;
324 msg.msg_controllen = sizeof (struct cmessage);
325 #endif
326 msg.msg_flags = 0;
328 #ifdef SO_PASSCRED
330 int on = 1;
331 if (setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
332 return -1;
334 #endif
336 restart:
337 len = recvmsg (sock, &msg, 0);
338 if (len >= 0)
340 if (msg.msg_flags & MSG_CTRUNC || len == 0)
341 return 0;
342 else
343 return len;
345 if (errno == EINTR)
346 goto restart;
347 return -1;
350 static int
351 __msgwrite (int sock, void *data, size_t cnt)
353 #ifndef SCM_CREDENTIALS
354 /* We cannot implement this reliably. */
355 __set_errno (ENOSYS);
356 return -1;
357 #else
358 struct iovec iov;
359 struct msghdr msg;
360 struct cmsghdr *cmsg = &cm.cmsg;
361 struct ucred cred;
362 int len;
364 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
365 get?id(). But since keyserv needs geteuid(), we have no other chance.
366 It would be much better, if the kernel could pass both to the server. */
367 cred.pid = __getpid ();
368 cred.uid = __geteuid ();
369 cred.gid = __getegid ();
371 memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
372 cmsg->cmsg_level = SOL_SOCKET;
373 cmsg->cmsg_type = SCM_CREDENTIALS;
374 cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
376 iov.iov_base = data;
377 iov.iov_len = cnt;
379 msg.msg_iov = &iov;
380 msg.msg_iovlen = 1;
381 msg.msg_name = NULL;
382 msg.msg_namelen = 0;
383 msg.msg_control = cmsg;
384 msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
385 msg.msg_flags = 0;
387 restart:
388 len = sendmsg (sock, &msg, 0);
389 if (len >= 0)
390 return len;
391 if (errno == EINTR)
392 goto restart;
393 return -1;
395 #endif
399 * reads data from the unix connection.
400 * any error is fatal and the connection is closed.
401 * (And a read of zero bytes is a half closed stream => error.)
403 static int
404 readunix (char *xprtptr, char *buf, int len)
406 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
407 int sock = xprt->xp_sock;
408 int milliseconds = 35 * 1000;
409 struct pollfd pollfd;
413 pollfd.fd = sock;
414 pollfd.events = POLLIN;
415 switch (__poll (&pollfd, 1, milliseconds))
417 case -1:
418 if (errno == EINTR)
419 continue;
420 /*FALLTHROUGH*/
421 case 0:
422 goto fatal_err;
423 default:
424 if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
425 || (pollfd.revents & POLLNVAL))
426 goto fatal_err;
427 break;
430 while ((pollfd.revents & POLLIN) == 0);
432 if ((len = __msgread (sock, buf, len)) > 0)
433 return len;
435 fatal_err:
436 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
437 return -1;
441 * writes data to the unix connection.
442 * Any error is fatal and the connection is closed.
444 static int
445 writeunix (char *xprtptr, char * buf, int len)
447 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
448 int i, cnt;
450 for (cnt = len; cnt > 0; cnt -= i, buf += i)
452 if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
454 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
455 return -1;
458 return len;
461 static enum xprt_stat
462 svcunix_stat (SVCXPRT *xprt)
464 struct unix_conn *cd =
465 (struct unix_conn *) (xprt->xp_p1);
467 if (cd->strm_stat == XPRT_DIED)
468 return XPRT_DIED;
469 if (!xdrrec_eof (&(cd->xdrs)))
470 return XPRT_MOREREQS;
471 return XPRT_IDLE;
474 static bool_t
475 svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
477 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
478 XDR *xdrs = &(cd->xdrs);
480 xdrs->x_op = XDR_DECODE;
481 xdrrec_skiprecord (xdrs);
482 if (xdr_callmsg (xdrs, msg))
484 cd->x_id = msg->rm_xid;
485 /* set up verifiers */
486 #ifdef SCM_CREDENTIALS
487 msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
488 msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
489 msg->rm_call.cb_verf.oa_length = sizeof (cm);
490 #endif
491 return TRUE;
493 cd->strm_stat = XPRT_DIED; /* XXXX */
494 return FALSE;
497 static bool_t
498 svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
500 return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
501 args_ptr);
504 static bool_t
505 svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
507 XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
509 xdrs->x_op = XDR_FREE;
510 return (*xdr_args) (xdrs, args_ptr);
513 static bool_t
514 svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
516 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
517 XDR *xdrs = &(cd->xdrs);
518 bool_t stat;
520 xdrs->x_op = XDR_ENCODE;
521 msg->rm_xid = cd->x_id;
522 stat = xdr_replymsg (xdrs, msg);
523 (void) xdrrec_endofrecord (xdrs, TRUE);
524 return stat;