(root)/
glibc-2.38/
sunrpc/
svc_unix.c
       1  /*
       2   * svc_unix.c, Server side for TCP/IP based RPC.
       3   *
       4   * Copyright (C) 2012-2023 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
      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 *
     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  }
     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  }
     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
     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
     284  rendezvous_stat (SVCXPRT *xprt)
     285  {
     286    return XPRT_IDLE;
     287  }
     288  
     289  static void
     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
     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
     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
     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
     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
     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
     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
     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
     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
     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  }