(pmap_set): Do CLNT_DESTROY even if CLNT_CALL failed.
[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, 2) != 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 #ifdef USE_IN_LIBIO
177       if (_IO_fwide (stderr, 0) > 0)
178         __fwprintf (stderr, L"%s", _("svcunix_create: out of memory\n"));
179       else
180 #endif
181         fputs (_("svcunix_create: out of memory\n"), stderr);
182       mem_free (r, sizeof (*r));
183       mem_free (xprt, sizeof (SVCXPRT));
184       return NULL;
185     }
186   r->sendsize = sendsize;
187   r->recvsize = recvsize;
188   xprt->xp_p2 = NULL;
189   xprt->xp_p1 = (caddr_t) r;
190   xprt->xp_verf = _null_auth;
191   xprt->xp_ops = &svcunix_rendezvous_op;
192   xprt->xp_port = -1;
193   xprt->xp_sock = sock;
194   xprt_register (xprt);
195   return xprt;
196 }
197
198 /*
199  * Like svunix_create(), except the routine takes any *open* UNIX file
200  * descriptor as its first input.
201  */
202 SVCXPRT *
203 svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
204 {
205   return makefd_xprt (fd, sendsize, recvsize);
206 }
207
208 static SVCXPRT *
209 internal_function
210 makefd_xprt (int fd, u_int sendsize, u_int recvsize)
211 {
212   SVCXPRT *xprt;
213   struct unix_conn *cd;
214
215   xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
216   cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
217   if (xprt == (SVCXPRT *) NULL || cd == (struct unix_conn *) NULL)
218     {
219 #ifdef USE_IN_LIBIO
220       if (_IO_fwide (stderr, 0) > 0)
221         (void) __fwprintf (stderr, L"%s",
222                            _("svc_unix: makefd_xprt: out of memory\n"));
223       else
224 #endif
225         (void) fputs (_("svc_unix: makefd_xprt: out of memory\n"), stderr);
226       mem_free (xprt, sizeof (SVCXPRT));
227       mem_free (cd, sizeof (struct unix_conn));
228       return NULL;
229     }
230   cd->strm_stat = XPRT_IDLE;
231   INTUSE(xdrrec_create) (&(cd->xdrs), sendsize, recvsize,
232                          (caddr_t) xprt, readunix, writeunix);
233   xprt->xp_p2 = NULL;
234   xprt->xp_p1 = (caddr_t) cd;
235   xprt->xp_verf.oa_base = cd->verf_body;
236   xprt->xp_addrlen = 0;
237   xprt->xp_ops = &svcunix_op;   /* truly deals with calls */
238   xprt->xp_port = 0;            /* this is a connection, not a rendezvouser */
239   xprt->xp_sock = fd;
240   xprt_register (xprt);
241   return xprt;
242 }
243
244 static bool_t
245 rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg)
246 {
247   int sock;
248   struct unix_rendezvous *r;
249   struct sockaddr_un addr;
250   struct sockaddr_in in_addr;
251   socklen_t len;
252
253   r = (struct unix_rendezvous *) xprt->xp_p1;
254 again:
255   len = sizeof (struct sockaddr_un);
256   if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
257     {
258       if (errno == EINTR)
259         goto again;
260       return FALSE;
261     }
262   /*
263    * make a new transporter (re-uses xprt)
264    */
265   memset (&in_addr, '\0', sizeof (in_addr));
266   in_addr.sin_family = AF_UNIX;
267   xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
268   memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr));
269   xprt->xp_addrlen = len;
270   return FALSE;         /* there is never an rpc msg to be processed */
271 }
272
273 static enum xprt_stat
274 rendezvous_stat (SVCXPRT *xprt)
275 {
276   return XPRT_IDLE;
277 }
278
279 static void
280 svcunix_destroy (SVCXPRT *xprt)
281 {
282   struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
283
284   xprt_unregister (xprt);
285   __close (xprt->xp_sock);
286   if (xprt->xp_port != 0)
287     {
288       /* a rendezvouser socket */
289       xprt->xp_port = 0;
290     }
291   else
292     {
293       /* an actual connection socket */
294       XDR_DESTROY (&(cd->xdrs));
295     }
296   mem_free ((caddr_t) cd, sizeof (struct unix_conn));
297   mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
298 }
299
300 #ifdef SCM_CREDENTIALS
301 struct cmessage {
302   struct cmsghdr cmsg;
303   struct ucred cmcred;
304   /* hack to make sure we have enough memory */
305   char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
306 };
307
308 /* XXX This is not thread safe, but since the main functions in svc.c
309    and the rpcgen generated *_svc functions for the daemon are also not
310    thread safe and uses static global variables, it doesn't matter. */
311 static struct cmessage cm;
312 #endif
313
314 static int
315 __msgread (int sock, void *data, size_t cnt)
316 {
317   struct iovec iov;
318   struct msghdr msg;
319   int len;
320
321   iov.iov_base = data;
322   iov.iov_len = cnt;
323
324   msg.msg_iov = &iov;
325   msg.msg_iovlen = 1;
326   msg.msg_name = NULL;
327   msg.msg_namelen = 0;
328 #ifdef SCM_CREDENTIALS
329   msg.msg_control = (caddr_t) &cm;
330   msg.msg_controllen = sizeof (struct cmessage);
331 #endif
332   msg.msg_flags = 0;
333
334 #ifdef SO_PASSCRED
335   {
336     int on = 1;
337     if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
338       return -1;
339   }
340 #endif
341
342  restart:
343   len = __recvmsg (sock, &msg, 0);
344   if (len >= 0)
345     {
346       if (msg.msg_flags & MSG_CTRUNC || len == 0)
347         return 0;
348       else
349         return len;
350     }
351   if (errno == EINTR)
352     goto restart;
353   return -1;
354 }
355
356 static int
357 __msgwrite (int sock, void *data, size_t cnt)
358 {
359 #ifndef SCM_CREDENTIALS
360   /* We cannot implement this reliably.  */
361   __set_errno (ENOSYS);
362   return -1;
363 #else
364   struct iovec iov;
365   struct msghdr msg;
366   struct cmsghdr *cmsg = &cm.cmsg;
367   struct ucred cred;
368   int len;
369
370   /* XXX I'm not sure, if gete?id() is always correct, or if we should use
371      get?id(). But since keyserv needs geteuid(), we have no other chance.
372      It would be much better, if the kernel could pass both to the server. */
373   cred.pid = __getpid ();
374   cred.uid = __geteuid ();
375   cred.gid = __getegid ();
376
377   memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
378   cmsg->cmsg_level = SOL_SOCKET;
379   cmsg->cmsg_type = SCM_CREDENTIALS;
380   cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
381
382   iov.iov_base = data;
383   iov.iov_len = cnt;
384
385   msg.msg_iov = &iov;
386   msg.msg_iovlen = 1;
387   msg.msg_name = NULL;
388   msg.msg_namelen = 0;
389   msg.msg_control = cmsg;
390   msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
391   msg.msg_flags = 0;
392
393  restart:
394   len = __sendmsg (sock, &msg, 0);
395   if (len >= 0)
396     return len;
397   if (errno == EINTR)
398     goto restart;
399   return -1;
400
401 #endif
402 }
403
404 /*
405  * reads data from the unix connection.
406  * any error is fatal and the connection is closed.
407  * (And a read of zero bytes is a half closed stream => error.)
408  */
409 static int
410 readunix (char *xprtptr, char *buf, int len)
411 {
412   SVCXPRT *xprt = (SVCXPRT *) xprtptr;
413   int sock = xprt->xp_sock;
414   int milliseconds = 35 * 1000;
415   struct pollfd pollfd;
416
417   do
418     {
419       pollfd.fd = sock;
420       pollfd.events = POLLIN;
421       switch (__poll (&pollfd, 1, milliseconds))
422         {
423         case -1:
424           if (errno == EINTR)
425             continue;
426           /*FALLTHROUGH*/
427         case 0:
428           goto fatal_err;
429         default:
430           if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
431               || (pollfd.revents & POLLNVAL))
432             goto fatal_err;
433           break;
434         }
435     }
436   while ((pollfd.revents & POLLIN) == 0);
437
438   if ((len = __msgread (sock, buf, len)) > 0)
439     return len;
440
441  fatal_err:
442   ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
443   return -1;
444 }
445
446 /*
447  * writes data to the unix connection.
448  * Any error is fatal and the connection is closed.
449  */
450 static int
451 writeunix (char *xprtptr, char * buf, int len)
452 {
453   SVCXPRT *xprt = (SVCXPRT *) xprtptr;
454   int i, cnt;
455
456   for (cnt = len; cnt > 0; cnt -= i, buf += i)
457     {
458       if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
459         {
460           ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
461           return -1;
462         }
463     }
464   return len;
465 }
466
467 static enum xprt_stat
468 svcunix_stat (SVCXPRT *xprt)
469 {
470   struct unix_conn *cd =
471   (struct unix_conn *) (xprt->xp_p1);
472
473   if (cd->strm_stat == XPRT_DIED)
474     return XPRT_DIED;
475   if (!INTUSE(xdrrec_eof) (&(cd->xdrs)))
476     return XPRT_MOREREQS;
477   return XPRT_IDLE;
478 }
479
480 static bool_t
481 svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
482 {
483   struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
484   XDR *xdrs = &(cd->xdrs);
485
486   xdrs->x_op = XDR_DECODE;
487   INTUSE(xdrrec_skiprecord) (xdrs);
488   if (INTUSE(xdr_callmsg) (xdrs, msg))
489     {
490       cd->x_id = msg->rm_xid;
491       /* set up verifiers */
492 #ifdef SCM_CREDENTIALS
493       msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
494       msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
495       msg->rm_call.cb_verf.oa_length = sizeof (cm);
496 #endif
497       return TRUE;
498     }
499   cd->strm_stat = XPRT_DIED;    /* XXXX */
500   return FALSE;
501 }
502
503 static bool_t
504 svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
505 {
506   return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
507                       args_ptr);
508 }
509
510 static bool_t
511 svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
512 {
513   XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
514
515   xdrs->x_op = XDR_FREE;
516   return (*xdr_args) (xdrs, args_ptr);
517 }
518
519 static bool_t
520 svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
521 {
522   struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
523   XDR *xdrs = &(cd->xdrs);
524   bool_t stat;
525
526   xdrs->x_op = XDR_ENCODE;
527   msg->rm_xid = cd->x_id;
528   stat = INTUSE(xdr_replymsg) (xdrs, msg);
529   (void) INTUSE(xdrrec_endofrecord) (xdrs, TRUE);
530   return stat;
531 }