1 /*
2  * svc_unix.c, Server side for TCP/IP based RPC.
3  *
4  * Copyright (C) 2012-2022 Free Software Foundation, Inc.
5  * This file is part of the GNU C Library.
6  *
7  * The GNU C Library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * The GNU C Library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with the GNU C Library; if not, see
19  * <https://www.gnu.org/licenses/>.
20  *
21  * Copyright (c) 2010, Oracle America, Inc.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions are
25  * met:
26  *
27  *     * Redistributions of source code must retain the above copyright
28  *       notice, this list of conditions and the following disclaimer.
29  *     * Redistributions in binary form must reproduce the above
30  *       copyright notice, this list of conditions and the following
31  *       disclaimer in the documentation and/or other materials
32  *       provided with the distribution.
33  *     * Neither the name of the "Oracle America, Inc." nor the names of its
34  *       contributors may be used to endorse or promote products derived
35  *       from this software without specific prior written permission.
36  *
37  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
38  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
39  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
40  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
41  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
42  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
44  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
45  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
46  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
47  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
48  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49  *
50  * Actually implements two flavors of transporter -
51  * a unix rendezvouser (a listener and connection establisher)
52  * and a record/unix stream.
53  */
54 
55 #include <stdio.h>
56 #include <unistd.h>
57 #include <string.h>
58 #include <rpc/rpc.h>
59 #include <rpc/svc.h>
60 #include <sys/socket.h>
61 #include <sys/uio.h>
62 #include <sys/poll.h>
63 #include <errno.h>
64 #include <stdlib.h>
65 #include <libintl.h>
66 #include <wchar.h>
67 #include <shlib-compat.h>
68 
69 /*
70  * Ops vector for AF_UNIX based rpc service handle
71  */
72 static bool_t svcunix_recv (SVCXPRT *, struct rpc_msg *);
73 static enum xprt_stat svcunix_stat (SVCXPRT *);
74 static bool_t svcunix_getargs (SVCXPRT *, xdrproc_t, caddr_t);
75 static bool_t svcunix_reply (SVCXPRT *, struct rpc_msg *);
76 static bool_t svcunix_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
77 static void svcunix_destroy (SVCXPRT *);
78 
79 static const struct xp_ops svcunix_op =
80 {
81   svcunix_recv,
82   svcunix_stat,
83   svcunix_getargs,
84   svcunix_reply,
85   svcunix_freeargs,
86   svcunix_destroy
87 };
88 
89 /*
90  * Ops vector for AF_UNIX rendezvous handler
91  */
92 static bool_t rendezvous_request (SVCXPRT *, struct rpc_msg *);
93 static enum xprt_stat rendezvous_stat (SVCXPRT *);
94 static void svcunix_rendezvous_abort (void) __attribute__ ((__noreturn__));
95 
96 /* This function makes sure abort() relocation goes through PLT
97    and thus can be lazy bound.  */
98 static void
svcunix_rendezvous_abort(void)99 svcunix_rendezvous_abort (void)
100 {
101   abort ();
102 };
103 
104 static const struct xp_ops svcunix_rendezvous_op =
105 {
106   rendezvous_request,
107   rendezvous_stat,
108   (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
109   (bool_t (*) (SVCXPRT *, struct rpc_msg *)) svcunix_rendezvous_abort,
110   (bool_t (*) (SVCXPRT *, xdrproc_t, caddr_t)) svcunix_rendezvous_abort,
111   svcunix_destroy
112 };
113 
114 static int readunix (char*, char *, int);
115 static int writeunix (char *, char *, int);
116 static SVCXPRT *makefd_xprt (int, u_int, u_int);
117 
118 struct unix_rendezvous {        /* kept in xprt->xp_p1 */
119   u_int sendsize;
120   u_int recvsize;
121 };
122 
123 struct unix_conn {		/* kept in xprt->xp_p1 */
124   enum xprt_stat strm_stat;
125   u_long x_id;
126   XDR xdrs;
127   char verf_body[MAX_AUTH_BYTES];
128 };
129 
130 /*
131  * Usage:
132  *      xprt = svcunix_create(sock, send_buf_size, recv_buf_size);
133  *
134  * Creates, registers, and returns a (rpc) unix based transporter.
135  * Once *xprt is initialized, it is registered as a transporter
136  * see (svc.h, xprt_register).  This routine returns
137  * a NULL if a problem occurred.
138  *
139  * If sock<0 then a socket is created, else sock is used.
140  * If the socket, sock is not bound to a port then svcunix_create
141  * binds it to an arbitrary port.  The routine then starts a unix
142  * listener on the socket's associated port.  In any (successful) case,
143  * xprt->xp_sock is the registered socket number and xprt->xp_port is the
144  * associated port number.
145  *
146  * Since unix streams do buffered io similar to stdio, the caller can specify
147  * how big the send and receive buffers are via the second and third parms;
148  * 0 => use the system default.
149  */
150 SVCXPRT *
svcunix_create(int sock,u_int sendsize,u_int recvsize,char * path)151 svcunix_create (int sock, u_int sendsize, u_int recvsize, char *path)
152 {
153   bool_t madesock = FALSE;
154   SVCXPRT *xprt;
155   struct unix_rendezvous *r;
156   struct sockaddr_un addr;
157   socklen_t len = sizeof (addr);
158 
159   if (__sockaddr_un_set (&addr, path) < 0)
160     return NULL;
161 
162   if (sock == RPC_ANYSOCK)
163     {
164       if ((sock = __socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
165 	{
166 	  perror (_("svc_unix.c - AF_UNIX socket creation problem"));
167 	  return (SVCXPRT *) NULL;
168 	}
169       madesock = TRUE;
170     }
171   __bind (sock, (struct sockaddr *) &addr, len);
172 
173   if (__getsockname (sock, (struct sockaddr *) &addr, &len) != 0
174       || __listen (sock, SOMAXCONN) != 0)
175     {
176       perror (_("svc_unix.c - cannot getsockname or listen"));
177       if (madesock)
178 	__close (sock);
179       return (SVCXPRT *) NULL;
180     }
181 
182   r = (struct unix_rendezvous *) mem_alloc (sizeof (*r));
183   xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
184   if (r == NULL || xprt == NULL)
185     {
186       __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
187       mem_free (r, sizeof (*r));
188       mem_free (xprt, sizeof (SVCXPRT));
189       return NULL;
190     }
191   r->sendsize = sendsize;
192   r->recvsize = recvsize;
193   xprt->xp_p2 = NULL;
194   xprt->xp_p1 = (caddr_t) r;
195   xprt->xp_verf = _null_auth;
196   xprt->xp_ops = &svcunix_rendezvous_op;
197   xprt->xp_port = -1;
198   xprt->xp_sock = sock;
199   xprt_register (xprt);
200   return xprt;
201 }
libc_hidden_nolink_sunrpc(svcunix_create,GLIBC_2_1)202 libc_hidden_nolink_sunrpc (svcunix_create, GLIBC_2_1)
203 
204 /*
205  * Like svunix_create(), except the routine takes any *open* UNIX file
206  * descriptor as its first input.
207  */
208 SVCXPRT *
209 svcunixfd_create (int fd, u_int sendsize, u_int recvsize)
210 {
211   return makefd_xprt (fd, sendsize, recvsize);
212 }
libc_hidden_nolink_sunrpc(svcunixfd_create,GLIBC_2_1)213 libc_hidden_nolink_sunrpc (svcunixfd_create, GLIBC_2_1)
214 
215 static SVCXPRT *
216 makefd_xprt (int fd, u_int sendsize, u_int recvsize)
217 {
218   SVCXPRT *xprt;
219   struct unix_conn *cd;
220 
221   xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
222   cd = (struct unix_conn *) mem_alloc (sizeof (struct unix_conn));
223   if (xprt == (SVCXPRT *) NULL || cd == (struct unix_conn *) NULL)
224     {
225       (void) __fxprintf (NULL, "%s: %s", "svc_unix: makefd_xprt",
226 			 _("out of memory\n"));
227       mem_free (xprt, sizeof (SVCXPRT));
228       mem_free (cd, sizeof (struct unix_conn));
229       return NULL;
230     }
231   cd->strm_stat = XPRT_IDLE;
232   xdrrec_create (&(cd->xdrs), sendsize, recvsize,
233 		 (caddr_t) xprt, readunix, writeunix);
234   xprt->xp_p2 = NULL;
235   xprt->xp_p1 = (caddr_t) cd;
236   xprt->xp_verf.oa_base = cd->verf_body;
237   xprt->xp_addrlen = 0;
238   xprt->xp_ops = &svcunix_op;	/* truly deals with calls */
239   xprt->xp_port = 0;		/* this is a connection, not a rendezvouser */
240   xprt->xp_sock = fd;
241   xprt_register (xprt);
242   return xprt;
243 }
244 
245 static bool_t
rendezvous_request(SVCXPRT * xprt,struct rpc_msg * errmsg)246 rendezvous_request (SVCXPRT *xprt, struct rpc_msg *errmsg)
247 {
248   int sock;
249   struct unix_rendezvous *r;
250   struct sockaddr_un addr;
251   struct sockaddr_in in_addr;
252   socklen_t len;
253 
254   r = (struct unix_rendezvous *) xprt->xp_p1;
255 again:
256   len = sizeof (struct sockaddr_un);
257   if ((sock = accept (xprt->xp_sock, (struct sockaddr *) &addr, &len)) < 0)
258     {
259       if (errno == EINTR)
260 	goto again;
261       __svc_accept_failed ();
262       return FALSE;
263     }
264   /*
265    * make a new transporter (re-uses xprt)
266    */
267   memset (&in_addr, '\0', sizeof (in_addr));
268   in_addr.sin_family = AF_UNIX;
269   xprt = makefd_xprt (sock, r->sendsize, r->recvsize);
270 
271   /* If we are out of memory, makefd_xprt has already dumped an error.  */
272   if (xprt == NULL)
273     {
274       __svc_wait_on_error ();
275       return FALSE;
276     }
277 
278   memcpy (&xprt->xp_raddr, &in_addr, sizeof (in_addr));
279   xprt->xp_addrlen = len;
280   return FALSE;		/* there is never an rpc msg to be processed */
281 }
282 
283 static enum xprt_stat
rendezvous_stat(SVCXPRT * xprt)284 rendezvous_stat (SVCXPRT *xprt)
285 {
286   return XPRT_IDLE;
287 }
288 
289 static void
svcunix_destroy(SVCXPRT * xprt)290 svcunix_destroy (SVCXPRT *xprt)
291 {
292   struct unix_conn *cd = (struct unix_conn *) xprt->xp_p1;
293 
294   xprt_unregister (xprt);
295   __close (xprt->xp_sock);
296   if (xprt->xp_port != 0)
297     {
298       /* a rendezvouser socket */
299       xprt->xp_port = 0;
300     }
301   else
302     {
303       /* an actual connection socket */
304       XDR_DESTROY (&(cd->xdrs));
305     }
306   mem_free ((caddr_t) cd, sizeof (struct unix_conn));
307   mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
308 }
309 
310 #ifdef SCM_CREDENTIALS
311 struct cmessage {
312   struct cmsghdr cmsg;
313   struct ucred cmcred;
314   /* hack to make sure we have enough memory */
315   char dummy[(CMSG_ALIGN (sizeof (struct ucred)) - sizeof (struct ucred) + sizeof (long))];
316 };
317 
318 /* XXX This is not thread safe, but since the main functions in svc.c
319    and the rpcgen generated *_svc functions for the daemon are also not
320    thread safe and uses static global variables, it doesn't matter. */
321 static struct cmessage cm;
322 #endif
323 
324 static int
__msgread(int sock,void * data,size_t cnt)325 __msgread (int sock, void *data, size_t cnt)
326 {
327   struct iovec iov;
328   struct msghdr msg;
329   int len;
330 
331   iov.iov_base = data;
332   iov.iov_len = cnt;
333 
334   msg.msg_iov = &iov;
335   msg.msg_iovlen = 1;
336   msg.msg_name = NULL;
337   msg.msg_namelen = 0;
338 #ifdef SCM_CREDENTIALS
339   msg.msg_control = (caddr_t) &cm;
340   msg.msg_controllen = sizeof (struct cmessage);
341 #endif
342   msg.msg_flags = 0;
343 
344 #ifdef SO_PASSCRED
345   {
346     int on = 1;
347     if (__setsockopt (sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof (on)))
348       return -1;
349   }
350 #endif
351 
352  restart:
353   len = __recvmsg (sock, &msg, 0);
354   if (len >= 0)
355     {
356       if (msg.msg_flags & MSG_CTRUNC || len == 0)
357 	return 0;
358       else
359 	return len;
360     }
361   if (errno == EINTR)
362     goto restart;
363   return -1;
364 }
365 
366 static int
__msgwrite(int sock,void * data,size_t cnt)367 __msgwrite (int sock, void *data, size_t cnt)
368 {
369 #ifndef SCM_CREDENTIALS
370   /* We cannot implement this reliably.  */
371   __set_errno (ENOSYS);
372   return -1;
373 #else
374   struct iovec iov;
375   struct msghdr msg;
376   struct cmsghdr *cmsg = &cm.cmsg;
377   struct ucred cred;
378   int len;
379 
380   /* XXX I'm not sure, if gete?id() is always correct, or if we should use
381      get?id(). But since keyserv needs geteuid(), we have no other chance.
382      It would be much better, if the kernel could pass both to the server. */
383   cred.pid = __getpid ();
384   cred.uid = __geteuid ();
385   cred.gid = __getegid ();
386 
387   memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred));
388   cmsg->cmsg_level = SOL_SOCKET;
389   cmsg->cmsg_type = SCM_CREDENTIALS;
390   cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred);
391 
392   iov.iov_base = data;
393   iov.iov_len = cnt;
394 
395   msg.msg_iov = &iov;
396   msg.msg_iovlen = 1;
397   msg.msg_name = NULL;
398   msg.msg_namelen = 0;
399   msg.msg_control = cmsg;
400   msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len);
401   msg.msg_flags = 0;
402 
403  restart:
404   len = __sendmsg (sock, &msg, 0);
405   if (len >= 0)
406     return len;
407   if (errno == EINTR)
408     goto restart;
409   return -1;
410 
411 #endif
412 }
413 
414 /*
415  * reads data from the unix connection.
416  * any error is fatal and the connection is closed.
417  * (And a read of zero bytes is a half closed stream => error.)
418  */
419 static int
readunix(char * xprtptr,char * buf,int len)420 readunix (char *xprtptr, char *buf, int len)
421 {
422   SVCXPRT *xprt = (SVCXPRT *) xprtptr;
423   int sock = xprt->xp_sock;
424   int milliseconds = 35 * 1000;
425   struct pollfd pollfd;
426 
427   do
428     {
429       pollfd.fd = sock;
430       pollfd.events = POLLIN;
431       switch (__poll (&pollfd, 1, milliseconds))
432 	{
433 	case -1:
434 	  if (errno == EINTR)
435 	    continue;
436 	  /*FALLTHROUGH*/
437 	case 0:
438 	  goto fatal_err;
439 	default:
440 	  if ((pollfd.revents & POLLERR) || (pollfd.revents & POLLHUP)
441 	      || (pollfd.revents & POLLNVAL))
442 	    goto fatal_err;
443 	  break;
444 	}
445     }
446   while ((pollfd.revents & POLLIN) == 0);
447 
448   if ((len = __msgread (sock, buf, len)) > 0)
449     return len;
450 
451  fatal_err:
452   ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
453   return -1;
454 }
455 
456 /*
457  * writes data to the unix connection.
458  * Any error is fatal and the connection is closed.
459  */
460 static int
writeunix(char * xprtptr,char * buf,int len)461 writeunix (char *xprtptr, char * buf, int len)
462 {
463   SVCXPRT *xprt = (SVCXPRT *) xprtptr;
464   int i, cnt;
465 
466   for (cnt = len; cnt > 0; cnt -= i, buf += i)
467     {
468       if ((i = __msgwrite (xprt->xp_sock, buf, cnt)) < 0)
469 	{
470 	  ((struct unix_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
471 	  return -1;
472 	}
473     }
474   return len;
475 }
476 
477 static enum xprt_stat
svcunix_stat(SVCXPRT * xprt)478 svcunix_stat (SVCXPRT *xprt)
479 {
480   struct unix_conn *cd =
481   (struct unix_conn *) (xprt->xp_p1);
482 
483   if (cd->strm_stat == XPRT_DIED)
484     return XPRT_DIED;
485   if (!xdrrec_eof (&(cd->xdrs)))
486     return XPRT_MOREREQS;
487   return XPRT_IDLE;
488 }
489 
490 static bool_t
svcunix_recv(SVCXPRT * xprt,struct rpc_msg * msg)491 svcunix_recv (SVCXPRT *xprt, struct rpc_msg *msg)
492 {
493   struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
494   XDR *xdrs = &(cd->xdrs);
495 
496   xdrs->x_op = XDR_DECODE;
497   xdrrec_skiprecord (xdrs);
498   if (xdr_callmsg (xdrs, msg))
499     {
500       cd->x_id = msg->rm_xid;
501       /* set up verifiers */
502 #ifdef SCM_CREDENTIALS
503       msg->rm_call.cb_verf.oa_flavor = AUTH_UNIX;
504       msg->rm_call.cb_verf.oa_base = (caddr_t) &cm;
505       msg->rm_call.cb_verf.oa_length = sizeof (cm);
506 #endif
507       return TRUE;
508     }
509   cd->strm_stat = XPRT_DIED;	/* XXXX */
510   return FALSE;
511 }
512 
513 static bool_t
svcunix_getargs(SVCXPRT * xprt,xdrproc_t xdr_args,caddr_t args_ptr)514 svcunix_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
515 {
516   return (*xdr_args) (&(((struct unix_conn *) (xprt->xp_p1))->xdrs),
517 		      args_ptr);
518 }
519 
520 static bool_t
svcunix_freeargs(SVCXPRT * xprt,xdrproc_t xdr_args,caddr_t args_ptr)521 svcunix_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
522 {
523   XDR *xdrs = &(((struct unix_conn *) (xprt->xp_p1))->xdrs);
524 
525   xdrs->x_op = XDR_FREE;
526   return (*xdr_args) (xdrs, args_ptr);
527 }
528 
529 static bool_t
svcunix_reply(SVCXPRT * xprt,struct rpc_msg * msg)530 svcunix_reply (SVCXPRT *xprt, struct rpc_msg *msg)
531 {
532   struct unix_conn *cd = (struct unix_conn *) (xprt->xp_p1);
533   XDR *xdrs = &(cd->xdrs);
534   bool_t stat;
535 
536   xdrs->x_op = XDR_ENCODE;
537   msg->rm_xid = cd->x_id;
538   stat = xdr_replymsg (xdrs, msg);
539   (void) xdrrec_endofrecord (xdrs, TRUE);
540   return stat;
541 }
542