fdwalk should return 0 on an empty directory
[kopensolaris-gnu/glibc.git] / sunrpc / svc_unix.c
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.
8  *
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.
12  *
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.
16  *
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.
20  *
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.
24  *
25  * Sun Microsystems, Inc.
26  * 2550 Garcia Avenue
27  * Mountain View, California  94043
28  */
29
30 /*
31  * svc_unix.c, Server side for TCP/IP based RPC.
32  *
33  * Copyright (C) 1984, Sun Microsystems, Inc.
34  *
35  * Actually implements two flavors of transporter -
36  * a unix rendezvouser (a listener and connection establisher)
37  * and a record/unix stream.
38  */
39
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>
51
52 #ifdef USE_IN_LIBIO
53 # include <wchar.h>
54 #endif
55
56 /*
57  * Ops vector for AF_UNIX based rpc service handle
58  */
59 static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
60 static enum xprt_stat svcunix_stat (SVCXPRT *);
61 static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
62 static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
63 static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
64 static void svcunix_destroy (SVCXPRT *);
65
66 static const struct xp_ops svcunix_op =
67 {
68   svcunix_recv,
69   svcunix_stat,
70   svcunix_getargs,
71   svcunix_reply,
72   svcunix_freeargs,
73   svcunix_destroy
74 };
75
76 /*
77  * Ops vector for AF_UNIX rendezvous handler
78  */
79 static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
80 static enum xprt_stat rendezvous_stat (SVCXPRT *);
81 static void svcunix_rendezvous_abort (void) __attribute__ ((__noreturn__));
82
83 /* This function makes sure abort() relocation goes through PLT
84    and thus can be lazy bound.  */
85 static void
86 svcunix_rendezvous_abort (void)
87 {
88   abort ();
89 };
90
91 static const struct xp_ops svcunix_rendezvous_op =
92 {
93   rendezvous_request,
94   rendezvous_stat,
95   (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
96   (bool_t (*) (SVCXPRT *, struct rpc_msg *)) svcunix_rendezvous_abort,
97   (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
98   svcunix_destroy
99 };
100
101 static int readunix (char*, char *, int);
102 static int writeunix (char *, char *, int);
103 static SVCXPRT *makefd_xprt (int, u_int, u_int) internal_function;
104
105 struct unix_rendezvous {        /* kept in xprt->xp_p1 */
106   u_int sendsize;
107   u_int recvsize;
108 };
109
110 struct unix_conn {              /* kept in xprt->xp_p1 */
111   enum xprt_stat strm_stat;
112   u_long x_id;
113   XDR xdrs;
114   char verf_body[MAX_AUTH_BYTES];
115 };
116
117 /*
118  * Usage:
119  *      xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
120  *
121  * Creates, registers, and returns a (rpc) unix based transporter.
122  * Once *xprt is initialized, it is registered as a transporter
123  * see (svc.h, xprt_register).  This routine returns
124  * a NULL if a problem occurred.
125  *
126  * If sock<0 then a socket is created, else sock is used.
127  * If the socket, sock is not bound to a port then svcunix_create
128  * binds it to an arbitrary port.  The routine then starts a unix
129  * listener on the socket's associated port.  In any (successful) case,
130  * xprt->xp_sock is the registered socket number and xprt->xp_port is the
131  * associated port number.
132  *
133  * Since unix streams do buffered io similar to stdio, the caller can specify
134  * how big the send and receive buffers are via the second and third parms;
135  * 0 => use the system default.
136  */
137 SVCXPRT *
138 svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
139 {
140   bool_t madesock = FALSE;
141   SVCXPRT *xprt;
142   struct unix_rendezvous *r;
143   struct sockaddr_un addr;
144   socklen_t len = sizeof (struct sockaddr_in);
145
146   if (sock == RPC_ANYSOCK)
147     {
148       if ((sock = __socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
149         {
150           perror (_("svc_unix.c - AF_UNIX socket creation problem"));
151           return (SVCXPRT *) NULL;
152         }
153       madesock = TRUE;
154     }
155   memset (&addr, '\0', sizeof (addr));
156   addr.sun_family = AF_UNIX;
157   len = strlen (path) + 1;
158   memcpy (addr.sun_path, path, len);
159   len += sizeof (addr.sun_family);
160
161   __bind (sock, (struct sockaddr *) &addr, len);
162
163   if (__getsockname (sock, (struct sockaddr *) &addr, &len) != 0
164       || __listen (sock, SOMAXCONN) != 0)
165     {
166       perror (_("svc_unix.c - cannot getsockname or listen"));
167       if (madesock)
168         __close (sock);
169       return (SVCXPRT *) NULL;
170     }
171
172   r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
173   xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
174   if (r == NULL || xprt == NULL)
175     {
176       __fxprintf (NULL, "%s", _("svcunix_create: out of memory\n"));
177       mem_free (r, sizeof (*r));
178       mem_free (xprt, sizeof (SVCXPRT));
179       return NULL;
180     }
181   r->sendsize = sendsize;
182   r->recvsize = recvsize;
183   xprt->xp_p2 = NULL;
184   xprt->xp_p1 = (caddr_t) r;
185   xprt->xp_verf = _null_auth;
186   xprt->xp_ops = &svcunix_rendezvous_op;
187   xprt->xp_port = -1;
188   xprt->xp_sock = sock;
189   xprt_register (xprt);
190   return xprt;
191 }
192
193 /*
194  * Like svunix_create(), except the routine takes any *open* UNIX file
195  * descriptor as its first input.
196  */
197 SVCXPRT *
198 svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
199 {
200   return makefd_xprt (fd, sendsize, recvsize);
201 }
202
203 static SVCXPRT *
204 internal_function
205 makefd_xprt (int fd, u_int sendsize, u_int recvsize)
206 {
207   SVCXPRT *xprt;
208   struct unix_conn *cd;
209
210   xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
211   cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
212   if (xprt == (SVCXPRT *) NULL || cd == (struct unix_conn *) NULL)
213     {
214       (void) __fxprintf (NULL, "%s",
215                          _("svc_unix: makefd_xprt: out of memory\n"));
216       mem_free (xprt, sizeof (SVCXPRT));
217       mem_free (cd, sizeof (struct unix_conn));
218       return NULL;
219     }
220   cd->strm_stat = XPRT_IDLE;
221   INTUSE(xdrrec_create) (&(cd->xdrs), sendsize, recvsize,
222                          (caddr_t) xprt, readunix, writeunix);
223   xprt->xp_p2 = NULL;
224   xprt->xp_p1 = (caddr_t) cd;
225   xprt->xp_verf.oa_base = cd->verf_body;
226   xprt->xp_addrlen = 0;
227   xprt->xp_ops = &svcunix_op;   /* truly deals with calls */
228   xprt->xp_port = 0;            /* this is a connection, not a rendezvouser */
229   xprt->xp_sock = fd;
230   xprt_register (xprt);
231   return xprt;
232 }
233
234 static bool_t
235 rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg)
236 {
237   int sock;
238   struct unix_rendezvous *r;
239   struct sockaddr_un addr;
240   struct sockaddr_in in_addr;
241   socklen_t len;
242
243   r = (struct unix_rendezvous *) xprt->xp_p1;
244 again:
245   len = sizeof (struct sockaddr_un);
246   if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
247     {
248       if (errno == EINTR)
249         goto again;
250       return FALSE;
251     }
252   /*
253    * make a new transporter (re-uses xprt)
254    */
255   memset (&in_addr, '\0', sizeof (in_addr));
256   in_addr.sin_family = AF_UNIX;
257   xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
258   memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr));
259   xprt->xp_addrlen = len;
260   return FALSE;         /* there is never an rpc msg to be processed */
261 }
262
263 static enum xprt_stat
264 rendezvous_stat (SVCXPRT *xprt)
265 {
266   return XPRT_IDLE;
267 }
268
269 static void
270 svcunix_destroy (SVCXPRT *xprt)
271 {
272   struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
273
274   xprt_unregister (xprt);
275   __close (xprt->xp_sock);
276   if (xprt->xp_port != 0)
277     {
278       /* a rendezvouser socket */
279       xprt->xp_port = 0;
280     }
281   else
282     {
283       /* an actual connection socket */
284       XDR_DESTROY (&(cd->xdrs));
285     }
286   mem_free ((caddr_t) cd, sizeof (struct unix_conn));
287   mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
288 }
289
290 #ifdef SCM_CREDENTIALS
291 struct cmessage {
292   struct cmsghdr cmsg;
293   struct ucred cmcred;
294   /* hack to make sure we have enough memory */
295   char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
296 };
297
298 /* XXX This is not thread safe, but since the main functions in svc.c
299    and the rpcgen generated *_svc functions for the daemon are also not
300    thread safe and uses static global variables, it doesn't matter. */
301 static struct cmessage cm;
302 #endif
303
304 static int
305 __msgread (int sock, void *data, size_t cnt)
306 {
307   struct iovec iov;
308   struct msghdr msg;
309   int len;
310
311   iov.iov_base = data;
312   iov.iov_len = cnt;
313
314   msg.msg_iov = &iov;
315   msg.msg_iovlen = 1;
316   msg.msg_name = NULL;
317   msg.msg_namelen = 0;
318 #ifdef SCM_CREDENTIALS
319   msg.msg_control = (caddr_t) &cm;
320   msg.msg_controllen = sizeof (struct cmessage);
321 #endif
322   msg.msg_flags = 0;
323
324 #ifdef SO_PASSCRED
325   {
326     int on = 1;
327     if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
328       return -1;
329   }
330 #endif
331
332  restart:
333   len = __recvmsg (sock, &msg, 0);
334   if (len >= 0)
335     {
336       if (msg.msg_flags & MSG_CTRUNC || len == 0)
337         return 0;
338       else
339         return len;
340     }
341   if (errno == EINTR)
342     goto restart;
343   return -1;
344 }
345
346 static int
347 __msgwrite (int sock, void *data, size_t cnt)
348 {
349 #ifndef SCM_CREDENTIALS
350   /* We cannot implement this reliably.  */
351   __set_errno (ENOSYS);
352   return -1;
353 #else
354   struct iovec iov;
355   struct msghdr msg;
356   struct cmsghdr *cmsg = &cm.cmsg;
357   struct ucred cred;
358   int len;
359
360   /* XXX I'm not sure, if gete?id() is always correct, or if we should use
361      get?id(). But since keyserv needs geteuid(), we have no other chance.
362      It would be much better, if the kernel could pass both to the server. */
363   cred.pid = __getpid ();
364   cred.uid = __geteuid ();
365   cred.gid = __getegid ();
366
367   memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
368   cmsg->cmsg_level = SOL_SOCKET;
369   cmsg->cmsg_type = SCM_CREDENTIALS;
370   cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
371
372   iov.iov_base = data;
373   iov.iov_len = cnt;
374
375   msg.msg_iov = &iov;
376   msg.msg_iovlen = 1;
377   msg.msg_name = NULL;
378   msg.msg_namelen = 0;
379   msg.msg_control = cmsg;
380   msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
381   msg.msg_flags = 0;
382
383  restart:
384   len = __sendmsg (sock, &msg, 0);
385   if (len >= 0)
386     return len;
387   if (errno == EINTR)
388     goto restart;
389   return -1;
390
391 #endif
392 }
393
394 /*
395  * reads data from the unix connection.
396  * any error is fatal and the connection is closed.
397  * (And a read of zero bytes is a half closed stream => error.)
398  */
399 static int
400 readunix (char *xprtptr, char *buf, int len)
401 {
402   SVCXPRT *xprt = (SVCXPRT *) xprtptr;
403   int sock = xprt->xp_sock;
404   int milliseconds = 35 * 1000;
405   struct pollfd pollfd;
406
407   do
408     {
409       pollfd.fd = sock;
410       pollfd.events = POLLIN;
411       switch (__poll (&pollfd, 1, milliseconds))
412         {
413         case -1:
414           if (errno == EINTR)
415             continue;
416           /*FALLTHROUGH*/
417         case 0:
418           goto fatal_err;
419         default:
420           if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
421               || (pollfd.revents & POLLNVAL))
422             goto fatal_err;
423           break;
424         }
425     }
426   while ((pollfd.revents & POLLIN) == 0);
427
428   if ((len = __msgread (sock, buf, len)) > 0)
429     return len;
430
431  fatal_err:
432   ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
433   return -1;
434 }
435
436 /*
437  * writes data to the unix connection.
438  * Any error is fatal and the connection is closed.
439  */
440 static int
441 writeunix (char *xprtptr, char * buf, int len)
442 {
443   SVCXPRT *xprt = (SVCXPRT *) xprtptr;
444   int i, cnt;
445
446   for (cnt = len; cnt > 0; cnt -= i, buf += i)
447     {
448       if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
449         {
450           ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
451           return -1;
452         }
453     }
454   return len;
455 }
456
457 static enum xprt_stat
458 svcunix_stat (SVCXPRT *xprt)
459 {
460   struct unix_conn *cd =
461   (struct unix_conn *) (xprt->xp_p1);
462
463   if (cd->strm_stat == XPRT_DIED)
464     return XPRT_DIED;
465   if (!INTUSE(xdrrec_eof) (&(cd->xdrs)))
466     return XPRT_MOREREQS;
467   return XPRT_IDLE;
468 }
469
470 static bool_t
471 svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
472 {
473   struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
474   XDR *xdrs = &(cd->xdrs);
475
476   xdrs->x_op = XDR_DECODE;
477   INTUSE(xdrrec_skiprecord) (xdrs);
478   if (INTUSE(xdr_callmsg) (xdrs, msg))
479     {
480       cd->x_id = msg->rm_xid;
481       /* set up verifiers */
482 #ifdef SCM_CREDENTIALS
483       msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
484       msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
485       msg->rm_call.cb_verf.oa_length = sizeof (cm);
486 #endif
487       return TRUE;
488     }
489   cd->strm_stat = XPRT_DIED;    /* XXXX */
490   return FALSE;
491 }
492
493 static bool_t
494 svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
495 {
496   return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
497                       args_ptr);
498 }
499
500 static bool_t
501 svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
502 {
503   XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
504
505   xdrs->x_op = XDR_FREE;
506   return (*xdr_args) (xdrs, args_ptr);
507 }
508
509 static bool_t
510 svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
511 {
512   struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
513   XDR *xdrs = &(cd->xdrs);
514   bool_t stat;
515
516   xdrs->x_op = XDR_ENCODE;
517   msg->rm_xid = cd->x_id;
518   stat = INTUSE(xdr_replymsg) (xdrs, msg);
519   (void) INTUSE(xdrrec_endofrecord) (xdrs, TRUE);
520   return stat;
521 }