(root)/
glibc-2.38/
sunrpc/
svc.c
       1  /*
       2   * svc.c, Server-side remote procedure call interface.
       3   *
       4   * There are two sets of procedures here.  The xprt routines are
       5   * for handling transport handles.  The svc routines handle the
       6   * list of service routines.
       7   *  Copyright (C) 2002-2023 Free Software Foundation, Inc.
       8   *  This file is part of the GNU C Library.
       9   *
      10   *  The GNU C Library is free software; you can redistribute it and/or
      11   *  modify it under the terms of the GNU Lesser General Public
      12   *  License as published by the Free Software Foundation; either
      13   *  version 2.1 of the License, or (at your option) any later version.
      14   *
      15   *  The GNU C Library is distributed in the hope that it will be useful,
      16   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      18   *  Lesser General Public License for more details.
      19   *
      20   *  You should have received a copy of the GNU Lesser General Public
      21   *  License along with the GNU C Library; if not, see
      22   *  <https://www.gnu.org/licenses/>.
      23   *
      24   * Copyright (c) 2010, Oracle America, Inc.
      25   *
      26   * Redistribution and use in source and binary forms, with or without
      27   * modification, are permitted provided that the following conditions are
      28   * met:
      29   *
      30   *     * Redistributions of source code must retain the above copyright
      31   *       notice, this list of conditions and the following disclaimer.
      32   *     * Redistributions in binary form must reproduce the above
      33   *       copyright notice, this list of conditions and the following
      34   *       disclaimer in the documentation and/or other materials
      35   *       provided with the distribution.
      36   *     * Neither the name of the "Oracle America, Inc." nor the names of its
      37   *       contributors may be used to endorse or promote products derived
      38   *       from this software without specific prior written permission.
      39   *
      40   *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      41   *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      42   *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
      43   *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
      44   *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
      45   *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      46   *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
      47   *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      48   *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      49   *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
      50   *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      51   *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      52   */
      53  
      54  #include <errno.h>
      55  #include <unistd.h>
      56  #include <rpc/rpc.h>
      57  #include <rpc/svc.h>
      58  #include <rpc/pmap_clnt.h>
      59  #include <sys/poll.h>
      60  #include <time.h>
      61  #include <shlib-compat.h>
      62  
      63  #define xports RPC_THREAD_VARIABLE(svc_xports_s)
      64  
      65  #define NULL_SVC ((struct svc_callout *)0)
      66  #define	RQCRED_SIZE	400	/* this size is excessive */
      67  
      68  /* The services list
      69     Each entry represents a set of procedures (an rpc program).
      70     The dispatch routine takes request structs and runs the
      71     appropriate procedure. */
      72  struct svc_callout {
      73    struct svc_callout *sc_next;
      74    rpcprog_t sc_prog;
      75    rpcvers_t sc_vers;
      76    void (*sc_dispatch) (struct svc_req *, SVCXPRT *);
      77    bool_t sc_mapped;
      78  };
      79  #define svc_head RPC_THREAD_VARIABLE(svc_head_s)
      80  
      81  /* ***************  SVCXPRT related stuff **************** */
      82  
      83  /* Activate a transport handle. */
      84  void
      85  xprt_register (SVCXPRT *xprt)
      86  {
      87    register int sock = xprt->xp_sock;
      88    register int i;
      89  
      90    if (xports == NULL)
      91      {
      92        xports = (SVCXPRT **) calloc (_rpc_dtablesize (), sizeof (SVCXPRT *));
      93        if (xports == NULL) /* Don't add handle */
      94  	return;
      95      }
      96  
      97    if (sock < _rpc_dtablesize ())
      98      {
      99        struct pollfd *new_svc_pollfd;
     100  
     101        xports[sock] = xprt;
     102        if (sock < FD_SETSIZE)
     103  	FD_SET (sock, &svc_fdset);
     104  
     105        /* Check if we have an empty slot */
     106        for (i = 0; i < svc_max_pollfd; ++i)
     107  	if (svc_pollfd[i].fd == -1)
     108  	  {
     109  	    svc_pollfd[i].fd = sock;
     110  	    svc_pollfd[i].events = (POLLIN | POLLPRI |
     111  				    POLLRDNORM | POLLRDBAND);
     112  	    return;
     113  	  }
     114  
     115        new_svc_pollfd = (struct pollfd *) realloc (svc_pollfd,
     116  						  sizeof (struct pollfd)
     117  						  * (svc_max_pollfd + 1));
     118        if (new_svc_pollfd == NULL) /* Out of memory */
     119  	return;
     120        svc_pollfd = new_svc_pollfd;
     121        ++svc_max_pollfd;
     122  
     123        svc_pollfd[svc_max_pollfd - 1].fd = sock;
     124        svc_pollfd[svc_max_pollfd - 1].events = (POLLIN | POLLPRI |
     125  					       POLLRDNORM | POLLRDBAND);
     126      }
     127  }
     128  libc_hidden_nolink_sunrpc (xprt_register, GLIBC_2_0)
     129  
     130  /* De-activate a transport handle. */
     131  void
     132  xprt_unregister (SVCXPRT *xprt)
     133  {
     134    register int sock = xprt->xp_sock;
     135    register int i;
     136  
     137    if ((sock < _rpc_dtablesize ()) && (xports[sock] == xprt))
     138      {
     139        xports[sock] = (SVCXPRT *) 0;
     140  
     141        if (sock < FD_SETSIZE)
     142  	FD_CLR (sock, &svc_fdset);
     143  
     144        for (i = 0; i < svc_max_pollfd; ++i)
     145  	if (svc_pollfd[i].fd == sock)
     146  	  svc_pollfd[i].fd = -1;
     147      }
     148  }
     149  #ifdef EXPORT_RPC_SYMBOLS
     150  libc_hidden_def (xprt_unregister)
     151  #else
     152  libc_hidden_nolink_sunrpc (xprt_unregister, GLIBC_2_0)
     153  #endif
     154  
     155  
     156  /* ********************** CALLOUT list related stuff ************* */
     157  
     158  /* Search the callout list for a program number, return the callout
     159     struct. */
     160  static struct svc_callout *
     161  svc_find (rpcprog_t prog, rpcvers_t vers, struct svc_callout **prev)
     162  {
     163    register struct svc_callout *s, *p;
     164  
     165    p = NULL_SVC;
     166    for (s = svc_head; s != NULL_SVC; s = s->sc_next)
     167      {
     168        if ((s->sc_prog == prog) && (s->sc_vers == vers))
     169  	goto done;
     170        p = s;
     171      }
     172  done:
     173    *prev = p;
     174    return s;
     175  }
     176  
     177  /* Add a service program to the callout list.
     178     The dispatch routine will be called when a rpc request for this
     179     program number comes in. */
     180  bool_t
     181  svc_register (SVCXPRT * xprt, rpcprog_t prog, rpcvers_t vers,
     182  	      void (*dispatch) (struct svc_req *, SVCXPRT *),
     183  	      rpcproc_t protocol)
     184  {
     185    struct svc_callout *prev;
     186    register struct svc_callout *s;
     187  
     188    if ((s = svc_find (prog, vers, &prev)) != NULL_SVC)
     189      {
     190        if (s->sc_dispatch == dispatch)
     191  	goto pmap_it;		/* he is registering another xptr */
     192        return FALSE;
     193      }
     194    s = (struct svc_callout *) mem_alloc (sizeof (struct svc_callout));
     195    if (s == (struct svc_callout *) 0)
     196      return FALSE;
     197  
     198    s->sc_prog = prog;
     199    s->sc_vers = vers;
     200    s->sc_dispatch = dispatch;
     201    s->sc_next = svc_head;
     202    s->sc_mapped = FALSE;
     203    svc_head = s;
     204  
     205  pmap_it:
     206    /* now register the information with the local binder service */
     207    if (protocol)
     208      {
     209        if (! pmap_set (prog, vers, protocol, xprt->xp_port))
     210  	return FALSE;
     211  
     212        s->sc_mapped = TRUE;
     213      }
     214  
     215    return TRUE;
     216  }
     217  #ifdef EXPORT_RPC_SYMBOLS
     218  libc_hidden_def (svc_register)
     219  #else
     220  libc_hidden_nolink_sunrpc (svc_register, GLIBC_2_0)
     221  #endif
     222  
     223  /* Remove a service program from the callout list. */
     224  void
     225  svc_unregister (rpcprog_t prog, rpcvers_t vers)
     226  {
     227    struct svc_callout *prev;
     228    register struct svc_callout *s;
     229  
     230    if ((s = svc_find (prog, vers, &prev)) == NULL_SVC)
     231      return;
     232    bool is_mapped = s->sc_mapped;
     233  
     234    if (prev == NULL_SVC)
     235      svc_head = s->sc_next;
     236    else
     237      prev->sc_next = s->sc_next;
     238  
     239    s->sc_next = NULL_SVC;
     240    mem_free ((char *) s, (u_int) sizeof (struct svc_callout));
     241    /* now unregister the information with the local binder service */
     242    if (is_mapped)
     243      pmap_unset (prog, vers);
     244  }
     245  libc_hidden_nolink_sunrpc (svc_unregister, GLIBC_2_0)
     246  
     247  /* ******************* REPLY GENERATION ROUTINES  ************ */
     248  
     249  /* Send a reply to an rpc request */
     250  bool_t
     251  svc_sendreply (register SVCXPRT *xprt, xdrproc_t xdr_results,
     252  	       caddr_t xdr_location)
     253  {
     254    struct rpc_msg rply;
     255  
     256    rply.rm_direction = REPLY;
     257    rply.rm_reply.rp_stat = MSG_ACCEPTED;
     258    rply.acpted_rply.ar_verf = xprt->xp_verf;
     259    rply.acpted_rply.ar_stat = SUCCESS;
     260    rply.acpted_rply.ar_results.where = xdr_location;
     261    rply.acpted_rply.ar_results.proc = xdr_results;
     262    return SVC_REPLY (xprt, &rply);
     263  }
     264  #ifdef EXPORT_RPC_SYMBOLS
     265  libc_hidden_def (svc_sendreply)
     266  #else
     267  libc_hidden_nolink_sunrpc (svc_sendreply, GLIBC_2_0)
     268  #endif
     269  
     270  /* No procedure error reply */
     271  void
     272  svcerr_noproc (register SVCXPRT *xprt)
     273  {
     274    struct rpc_msg rply;
     275  
     276    rply.rm_direction = REPLY;
     277    rply.rm_reply.rp_stat = MSG_ACCEPTED;
     278    rply.acpted_rply.ar_verf = xprt->xp_verf;
     279    rply.acpted_rply.ar_stat = PROC_UNAVAIL;
     280    SVC_REPLY (xprt, &rply);
     281  }
     282  #ifdef EXPORT_RPC_SYMBOLS
     283  libc_hidden_def (svcerr_noproc)
     284  #else
     285  libc_hidden_nolink_sunrpc (svcerr_noproc, GLIBC_2_0)
     286  #endif
     287  
     288  /* Can't decode args error reply */
     289  void
     290  svcerr_decode (register SVCXPRT *xprt)
     291  {
     292    struct rpc_msg rply;
     293  
     294    rply.rm_direction = REPLY;
     295    rply.rm_reply.rp_stat = MSG_ACCEPTED;
     296    rply.acpted_rply.ar_verf = xprt->xp_verf;
     297    rply.acpted_rply.ar_stat = GARBAGE_ARGS;
     298    SVC_REPLY (xprt, &rply);
     299  }
     300  #ifdef EXPORT_RPC_SYMBOLS
     301  libc_hidden_def (svcerr_decode)
     302  #else
     303  libc_hidden_nolink_sunrpc (svcerr_decode, GLIBC_2_0)
     304  #endif
     305  
     306  /* Some system error */
     307  void
     308  svcerr_systemerr (register SVCXPRT *xprt)
     309  {
     310    struct rpc_msg rply;
     311  
     312    rply.rm_direction = REPLY;
     313    rply.rm_reply.rp_stat = MSG_ACCEPTED;
     314    rply.acpted_rply.ar_verf = xprt->xp_verf;
     315    rply.acpted_rply.ar_stat = SYSTEM_ERR;
     316    SVC_REPLY (xprt, &rply);
     317  }
     318  #ifdef EXPORT_RPC_SYMBOLS
     319  libc_hidden_def (svcerr_systemerr)
     320  #else
     321  libc_hidden_nolink_sunrpc (svcerr_systemerr, GLIBC_2_0)
     322  #endif
     323  
     324  /* Authentication error reply */
     325  void
     326  svcerr_auth (SVCXPRT *xprt, enum auth_stat why)
     327  {
     328    struct rpc_msg rply;
     329  
     330    rply.rm_direction = REPLY;
     331    rply.rm_reply.rp_stat = MSG_DENIED;
     332    rply.rjcted_rply.rj_stat = AUTH_ERROR;
     333    rply.rjcted_rply.rj_why = why;
     334    SVC_REPLY (xprt, &rply);
     335  }
     336  libc_hidden_nolink_sunrpc (svcerr_auth, GLIBC_2_0)
     337  
     338  /* Auth too weak error reply */
     339  void
     340  svcerr_weakauth (SVCXPRT *xprt)
     341  {
     342    svcerr_auth (xprt, AUTH_TOOWEAK);
     343  }
     344  libc_hidden_nolink_sunrpc (svcerr_weakauth, GLIBC_2_0)
     345  
     346  /* Program unavailable error reply */
     347  void
     348  svcerr_noprog (register SVCXPRT *xprt)
     349  {
     350    struct rpc_msg rply;
     351  
     352    rply.rm_direction = REPLY;
     353    rply.rm_reply.rp_stat = MSG_ACCEPTED;
     354    rply.acpted_rply.ar_verf = xprt->xp_verf;
     355    rply.acpted_rply.ar_stat = PROG_UNAVAIL;
     356    SVC_REPLY (xprt, &rply);
     357  }
     358  libc_hidden_nolink_sunrpc (svcerr_noprog, GLIBC_2_0)
     359  
     360  /* Program version mismatch error reply */
     361  void
     362  svcerr_progvers (register SVCXPRT *xprt, rpcvers_t low_vers,
     363  		 rpcvers_t high_vers)
     364  {
     365    struct rpc_msg rply;
     366  
     367    rply.rm_direction = REPLY;
     368    rply.rm_reply.rp_stat = MSG_ACCEPTED;
     369    rply.acpted_rply.ar_verf = xprt->xp_verf;
     370    rply.acpted_rply.ar_stat = PROG_MISMATCH;
     371    rply.acpted_rply.ar_vers.low = low_vers;
     372    rply.acpted_rply.ar_vers.high = high_vers;
     373    SVC_REPLY (xprt, &rply);
     374  }
     375  libc_hidden_nolink_sunrpc (svcerr_progvers, GLIBC_2_0)
     376  
     377  /* ******************* SERVER INPUT STUFF ******************* */
     378  
     379  /*
     380   * Get server side input from some transport.
     381   *
     382   * Statement of authentication parameters management:
     383   * This function owns and manages all authentication parameters, specifically
     384   * the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
     385   * the "cooked" credentials (rqst->rq_clntcred).
     386   * However, this function does not know the structure of the cooked
     387   * credentials, so it make the following assumptions:
     388   *   a) the structure is contiguous (no pointers), and
     389   *   b) the cred structure size does not exceed RQCRED_SIZE bytes.
     390   * In all events, all three parameters are freed upon exit from this routine.
     391   * The storage is trivially management on the call stack in user land, but
     392   * is mallocated in kernel land.
     393   */
     394  
     395  void
     396  svc_getreq (int rdfds)
     397  {
     398    fd_set readfds;
     399  
     400    FD_ZERO (&readfds);
     401    readfds.fds_bits[0] = rdfds;
     402    svc_getreqset (&readfds);
     403  }
     404  libc_hidden_nolink_sunrpc (svc_getreq, GLIBC_2_0)
     405  
     406  void
     407  svc_getreqset (fd_set *readfds)
     408  {
     409    register fd_mask mask;
     410    register fd_mask *maskp;
     411    register int setsize;
     412    register int sock;
     413    register int bit;
     414  
     415    setsize = _rpc_dtablesize ();
     416    if (setsize > FD_SETSIZE)
     417      setsize = FD_SETSIZE;
     418    maskp = readfds->fds_bits;
     419    for (sock = 0; sock < setsize; sock += NFDBITS)
     420      for (mask = *maskp++; (bit = ffsl (mask)); mask ^= (1L << (bit - 1)))
     421        svc_getreq_common (sock + bit - 1);
     422  }
     423  libc_hidden_nolink_sunrpc (svc_getreqset, GLIBC_2_0)
     424  
     425  void
     426  svc_getreq_poll (struct pollfd *pfdp, int pollretval)
     427  {
     428    if (pollretval == 0)
     429      return;
     430  
     431    register int fds_found;
     432    for (int i = fds_found = 0; i < svc_max_pollfd; ++i)
     433      {
     434        register struct pollfd *p = &pfdp[i];
     435  
     436        if (p->fd != -1 && p->revents)
     437  	{
     438  	  /* fd has input waiting */
     439  	  if (p->revents & POLLNVAL)
     440  	    xprt_unregister (xports[p->fd]);
     441  	  else
     442  	    svc_getreq_common (p->fd);
     443  
     444  	  if (++fds_found >= pollretval)
     445  	    break;
     446  	}
     447      }
     448  }
     449  #ifdef EXPORT_RPC_SYMBOLS
     450  libc_hidden_def (svc_getreq_poll)
     451  #else
     452  libc_hidden_nolink_sunrpc (svc_getreq_poll, GLIBC_2_2)
     453  #endif
     454  
     455  
     456  void
     457  svc_getreq_common (const int fd)
     458  {
     459    enum xprt_stat stat;
     460    struct rpc_msg msg;
     461    register SVCXPRT *xprt;
     462    char cred_area[2 * MAX_AUTH_BYTES + RQCRED_SIZE];
     463    msg.rm_call.cb_cred.oa_base = cred_area;
     464    msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
     465  
     466    xprt = xports[fd];
     467    /* Do we control fd? */
     468    if (xprt == NULL)
     469       return;
     470  
     471    /* now receive msgs from xprtprt (support batch calls) */
     472    do
     473      {
     474        if (SVC_RECV (xprt, &msg))
     475  	{
     476  	  /* now find the exported program and call it */
     477  	  struct svc_callout *s;
     478  	  struct svc_req r;
     479  	  enum auth_stat why;
     480  	  rpcvers_t low_vers;
     481  	  rpcvers_t high_vers;
     482  	  int prog_found;
     483  
     484  	  r.rq_clntcred = &(cred_area[2 * MAX_AUTH_BYTES]);
     485  	  r.rq_xprt = xprt;
     486  	  r.rq_prog = msg.rm_call.cb_prog;
     487  	  r.rq_vers = msg.rm_call.cb_vers;
     488  	  r.rq_proc = msg.rm_call.cb_proc;
     489  	  r.rq_cred = msg.rm_call.cb_cred;
     490  
     491  	  /* first authenticate the message */
     492  	  /* Check for null flavor and bypass these calls if possible */
     493  
     494  	  if (msg.rm_call.cb_cred.oa_flavor == AUTH_NULL)
     495  	    {
     496  	      r.rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor;
     497  	      r.rq_xprt->xp_verf.oa_length = 0;
     498  	    }
     499  	  else if ((why = _authenticate (&r, &msg)) != AUTH_OK)
     500  	    {
     501  	      svcerr_auth (xprt, why);
     502  	      goto call_done;
     503  	    }
     504  
     505  	  /* now match message with a registered service */
     506  	  prog_found = FALSE;
     507  	  low_vers = 0 - 1;
     508  	  high_vers = 0;
     509  
     510  	  for (s = svc_head; s != NULL_SVC; s = s->sc_next)
     511  	    {
     512  	      if (s->sc_prog == r.rq_prog)
     513  		{
     514  		  if (s->sc_vers == r.rq_vers)
     515  		    {
     516  		      (*s->sc_dispatch) (&r, xprt);
     517  		      goto call_done;
     518  		    }
     519  		  /* found correct version */
     520  		  prog_found = TRUE;
     521  		  if (s->sc_vers < low_vers)
     522  		    low_vers = s->sc_vers;
     523  		  if (s->sc_vers > high_vers)
     524  		    high_vers = s->sc_vers;
     525  		}
     526  	      /* found correct program */
     527  	    }
     528  	  /* if we got here, the program or version
     529  	     is not served ... */
     530  	  if (prog_found)
     531  	    svcerr_progvers (xprt, low_vers, high_vers);
     532  	  else
     533  	    svcerr_noprog (xprt);
     534  	  /* Fall through to ... */
     535  	}
     536      call_done:
     537        if ((stat = SVC_STAT (xprt)) == XPRT_DIED)
     538  	{
     539  	  SVC_DESTROY (xprt);
     540  	  break;
     541  	}
     542      }
     543    while (stat == XPRT_MOREREQS);
     544  }
     545  libc_hidden_nolink_sunrpc (svc_getreq_common, GLIBC_2_2)
     546  
     547  void
     548  __svc_wait_on_error (void)
     549  {
     550    struct timespec ts = { .tv_sec = 0, .tv_nsec = 50000000 };
     551    __nanosleep (&ts, NULL);
     552  }
     553  
     554  /* If there are no file descriptors available, then accept will fail.
     555     We want to delay here so the connection request can be dequeued;
     556     otherwise we can bounce between polling and accepting, never giving the
     557     request a chance to dequeue and eating an enormous amount of cpu time
     558     in svc_run if we're polling on many file descriptors.  */
     559  void
     560  __svc_accept_failed (void)
     561  {
     562    if (errno == EMFILE)
     563      {
     564        __svc_wait_on_error ();
     565      }
     566  }
     567  
     568  
     569  void
     570  __rpc_thread_svc_cleanup (void)
     571  {
     572    struct svc_callout *svcp;
     573  
     574    while ((svcp = svc_head) != NULL)
     575      svc_unregister (svcp->sc_prog, svcp->sc_vers);
     576  }