Update.
[glibc.git] / sunrpc / svc_unix.c
blobf47650afe56a5981b9869fae30d28b579f7147b4
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>
49 #include <libintl.h>
52 * Ops vector for AF_UNIX based rpc service handle
54 static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
55 static enum xprt_stat svcunix_stat (SVCXPRT *);
56 static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
57 static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
58 static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
59 static void svcunix_destroy (SVCXPRT *);
61 static const struct xp_ops svcunix_op =
63 svcunix_recv,
64 svcunix_stat,
65 svcunix_getargs,
66 svcunix_reply,
67 svcunix_freeargs,
68 svcunix_destroy
72 * Ops vector for AF_UNIX rendezvous handler
74 static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
75 static enum xprt_stat rendezvous_stat (SVCXPRT *);
77 static const struct xp_ops svcunix_rendezvous_op =
79 rendezvous_request,
80 rendezvous_stat,
81 (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) abort,
82 (bool_t (*) (SVCXPRT *, struct rpc_msg *)) abort,
83 (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) abort,
84 svcunix_destroy
87 static int readunix (char*, char *, int);
88 static int writeunix (char *, char *, int);
89 static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
91 struct unix_rendezvous { /* kept in xprt->xp_p1 */
92 u_int sendsize;
93 u_int recvsize;
96 struct unix_conn { /* kept in xprt->xp_p1 */
97 enum xprt_stat strm_stat;
98 u_long x_id;
99 XDR xdrs;
100 char verf_body[MAX_AUTH_BYTES];
104 * Usage:
105 * xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
107 * Creates, registers, and returns a (rpc) unix based transporter.
108 * Once *xprt is initialized, it is registered as a transporter
109 * see (svc.h, xprt_register). This routine returns
110 * a NULL if a problem occurred.
112 * If sock<0 then a socket is created, else sock is used.
113 * If the socket, sock is not bound to a port then svcunix_create
114 * binds it to an arbitrary port. The routine then starts a unix
115 * listener on the socket's associated port. In any (successful) case,
116 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
117 * associated port number.
119 * Since unix streams do buffered io similar to stdio, the caller can specify
120 * how big the send and receive buffers are via the second and third parms;
121 * 0 => use the system default.
123 SVCXPRT *
124 svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
126 bool_t madesock = FALSE;
127 SVCXPRT *xprt;
128 struct unix_rendezvous *r;
129 struct sockaddr_un addr;
130 socklen_t len = sizeof (struct sockaddr_in);
132 if (sock == RPC_ANYSOCK)
134 if ((sock = __socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
136 perror (_("svc_unix.c - AF_UNIX socket creation problem"));
137 return (SVCXPRT *) NULL;
139 madesock = TRUE;
141 memset (&addr, '\0', sizeof (addr));
142 addr.sun_family = AF_UNIX;
143 len = strlen (path) + 1;
144 memcpy (addr.sun_path, path, len);
145 len += sizeof (addr.sun_family);
147 bind (sock, (struct sockaddr *) &addr, len);
149 if (getsockname (sock, (struct sockaddr *) &addr, &len) != 0
150 || listen (sock, 2) != 0)
152 perror (_("svc_unix.c - cannot getsockname or listen"));
153 if (madesock)
154 __close (sock);
155 return (SVCXPRT *) NULL;
158 r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
159 if (r == NULL)
161 fputs (_("svcunix_create: out of memory\n"), stderr);
162 return NULL;
164 r->sendsize = sendsize;
165 r->recvsize = recvsize;
166 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
167 if (xprt == NULL)
169 fputs (_("svcunix_create: out of memory\n"), stderr);
170 return NULL;
172 xprt->xp_p2 = NULL;
173 xprt->xp_p1 = (caddr_t) r;
174 xprt->xp_verf = _null_auth;
175 xprt->xp_ops = &svcunix_rendezvous_op;
176 xprt->xp_port = -1;
177 xprt->xp_sock = sock;
178 xprt_register (xprt);
179 return xprt;
183 * Like svunix_create(), except the routine takes any *open* UNIX file
184 * descriptor as its first input.
186 SVCXPRT *
187 svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
189 return makefd_xprt (fd, sendsize, recvsize);
192 static SVCXPRT *
193 internal_function
194 makefd_xprt (int fd, u_int sendsize, u_int recvsize)
196 SVCXPRT *xprt;
197 struct unix_conn *cd;
199 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
200 if (xprt == (SVCXPRT *) NULL)
202 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
203 goto done;
205 cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
206 if (cd == (struct unix_conn *) NULL)
208 (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
209 mem_free ((char *) xprt, sizeof (SVCXPRT));
210 xprt = (SVCXPRT *) NULL;
211 goto done;
213 cd->strm_stat = XPRT_IDLE;
214 xdrrec_create (&(cd->xdrs), sendsize, recvsize,
215 (caddr_t) xprt, readunix, writeunix);
216 xprt->xp_p2 = NULL;
217 xprt->xp_p1 = (caddr_t) cd;
218 xprt->xp_verf.oa_base = cd->verf_body;
219 xprt->xp_addrlen = 0;
220 xprt->xp_ops = &svcunix_op; /* truly deals with calls */
221 xprt->xp_port = 0; /* this is a connection, not a rendezvouser */
222 xprt->xp_sock = fd;
223 xprt_register (xprt);
224 done:
225 return xprt;
228 static bool_t
229 rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg)
231 int sock;
232 struct unix_rendezvous *r;
233 struct sockaddr_un addr;
234 struct sockaddr_in in_addr;
235 socklen_t len;
237 r = (struct unix_rendezvous *) xprt->xp_p1;
238 again:
239 len = sizeof (struct sockaddr_un);
240 if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
242 if (errno == EINTR)
243 goto again;
244 return FALSE;
247 * make a new transporter (re-uses xprt)
249 memset (&in_addr, '\0', sizeof (in_addr));
250 in_addr.sin_family = AF_UNIX;
251 xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
252 memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr));
253 xprt->xp_addrlen = len;
254 return FALSE; /* there is never an rpc msg to be processed */
257 static enum xprt_stat
258 rendezvous_stat (SVCXPRT *xprt)
260 return XPRT_IDLE;
263 static void
264 svcunix_destroy (SVCXPRT *xprt)
266 struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
268 xprt_unregister (xprt);
269 __close (xprt->xp_sock);
270 if (xprt->xp_port != 0)
272 /* a rendezvouser socket */
273 xprt->xp_port = 0;
275 else
277 /* an actual connection socket */
278 XDR_DESTROY (&(cd->xdrs));
280 mem_free ((caddr_t) cd, sizeof (struct unix_conn));
281 mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
284 #ifdef SCM_CREDENTIALS
285 struct cmessage {
286 struct cmsghdr cmsg;
287 struct ucred cmcred;
288 /* hack to make sure we have enough memory */
289 char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
292 /* XXX This is not thread safe, but since the main functions in svc.c
293 and the rpcgen generated *_svc functions for the daemon are also not
294 thread safe and uses static global variables, it doesn't matter. */
295 static struct cmessage cm;
296 #endif
298 static int
299 __msgread (int sock, void *data, size_t cnt)
301 struct iovec iov;
302 struct msghdr msg;
303 int len;
305 iov.iov_base = data;
306 iov.iov_len = cnt;
308 msg.msg_iov = &iov;
309 msg.msg_iovlen = 1;
310 msg.msg_name = NULL;
311 msg.msg_namelen = 0;
312 #ifdef SCM_CREDENTIALS
313 msg.msg_control = (caddr_t) &cm;
314 msg.msg_controllen = sizeof (struct cmessage);
315 #endif
316 msg.msg_flags = 0;
318 #ifdef SO_PASSCRED
320 int on = 1;
321 if (setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
322 return -1;
324 #endif
326 restart:
327 len = recvmsg (sock, &msg, 0);
328 if (len >= 0)
330 if (msg.msg_flags & MSG_CTRUNC || len == 0)
331 return 0;
332 else
333 return len;
335 if (errno == EINTR)
336 goto restart;
337 return -1;
340 static int
341 __msgwrite (int sock, void *data, size_t cnt)
343 #ifndef SCM_CREDENTIALS
344 /* We cannot implement this reliably. */
345 __set_errno (ENOSYS);
346 return -1;
347 #else
348 struct iovec iov;
349 struct msghdr msg;
350 struct cmsghdr *cmsg = &cm.cmsg;
351 struct ucred cred;
352 int len;
354 /* XXX I'm not sure, if gete?id() is always correct, or if we should use
355 get?id(). But since keyserv needs geteuid(), we have no other chance.
356 It would be much better, if the kernel could pass both to the server. */
357 cred.pid = __getpid ();
358 cred.uid = __geteuid ();
359 cred.gid = __getegid ();
361 memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
362 cmsg->cmsg_level = SOL_SOCKET;
363 cmsg->cmsg_type = SCM_CREDENTIALS;
364 cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
366 iov.iov_base = data;
367 iov.iov_len = cnt;
369 msg.msg_iov = &iov;
370 msg.msg_iovlen = 1;
371 msg.msg_name = NULL;
372 msg.msg_namelen = 0;
373 msg.msg_control = cmsg;
374 msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
375 msg.msg_flags = 0;
377 restart:
378 len = sendmsg (sock, &msg, 0);
379 if (len >= 0)
380 return len;
381 if (errno == EINTR)
382 goto restart;
383 return -1;
385 #endif
389 * reads data from the unix connection.
390 * any error is fatal and the connection is closed.
391 * (And a read of zero bytes is a half closed stream => error.)
393 static int
394 readunix (char *xprtptr, char *buf, int len)
396 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
397 int sock = xprt->xp_sock;
398 int milliseconds = 35 * 1000;
399 struct pollfd pollfd;
403 pollfd.fd = sock;
404 pollfd.events = POLLIN;
405 switch (__poll (&pollfd, 1, milliseconds))
407 case -1:
408 if (errno == EINTR)
409 continue;
410 /*FALLTHROUGH*/
411 case 0:
412 goto fatal_err;
413 default:
414 if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
415 || (pollfd.revents & POLLNVAL))
416 goto fatal_err;
417 break;
420 while ((pollfd.revents & POLLIN) == 0);
422 if ((len = __msgread (sock, buf, len)) > 0)
423 return len;
425 fatal_err:
426 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
427 return -1;
431 * writes data to the unix connection.
432 * Any error is fatal and the connection is closed.
434 static int
435 writeunix (char *xprtptr, char * buf, int len)
437 SVCXPRT *xprt = (SVCXPRT *) xprtptr;
438 int i, cnt;
440 for (cnt = len; cnt > 0; cnt -= i, buf += i)
442 if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
444 ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
445 return -1;
448 return len;
451 static enum xprt_stat
452 svcunix_stat (SVCXPRT *xprt)
454 struct unix_conn *cd =
455 (struct unix_conn *) (xprt->xp_p1);
457 if (cd->strm_stat == XPRT_DIED)
458 return XPRT_DIED;
459 if (!xdrrec_eof (&(cd->xdrs)))
460 return XPRT_MOREREQS;
461 return XPRT_IDLE;
464 static bool_t
465 svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
467 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
468 XDR *xdrs = &(cd->xdrs);
470 xdrs->x_op = XDR_DECODE;
471 xdrrec_skiprecord (xdrs);
472 if (xdr_callmsg (xdrs, msg))
474 cd->x_id = msg->rm_xid;
475 /* set up verifiers */
476 #ifdef SCM_CREDENTIALS
477 msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
478 msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
479 msg->rm_call.cb_verf.oa_length = sizeof (cm);
480 #endif
481 return TRUE;
483 cd->strm_stat = XPRT_DIED; /* XXXX */
484 return FALSE;
487 static bool_t
488 svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
490 return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
491 args_ptr);
494 static bool_t
495 svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
497 XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
499 xdrs->x_op = XDR_FREE;
500 return (*xdr_args) (xdrs, args_ptr);
503 static bool_t
504 svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
506 struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
507 XDR *xdrs = &(cd->xdrs);
508 bool_t stat;
510 xdrs->x_op = XDR_ENCODE;
511 msg->rm_xid = cd->x_id;
512 stat = xdr_replymsg (xdrs, msg);
513 (void) xdrrec_endofrecord (xdrs, TRUE);
514 return stat;