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