(root)/
glibc-2.38/
nis/
nis_callback.c
       1  /* Copyright (C) 1997-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <errno.h>
      19  #include <stdio.h>
      20  #include <stdlib.h>
      21  #include <unistd.h>
      22  #include <libintl.h>
      23  #include <rpc/rpc.h>
      24  #include <rpc/pmap_clnt.h>
      25  #include <string.h>
      26  #include <memory.h>
      27  #include <syslog.h>
      28  #include <sys/poll.h>
      29  #include <sys/socket.h>
      30  #include <netinet/in.h>
      31  #include <arpa/inet.h>
      32  #include <rpc/key_prot.h>
      33  #include <rpcsvc/nis.h>
      34  #include <rpcsvc/nis_callback.h>
      35  #include <libc-lock.h>
      36  
      37  #include "nis_xdr.h"
      38  #include "nis_intern.h"
      39  
      40  /* Sorry, we are not able to make this threadsafe. Stupid. But some
      41     functions doesn't send us a nis_result obj, so we don't have a
      42     cookie. Maybe we could use keys for threads ? Have to learn more
      43     about pthreads -- kukuk@vt.uni-paderborn.de */
      44  
      45  static nis_cb *data;
      46  
      47  __libc_lock_define_initialized (static, callback)
      48  
      49  
      50  #if 0
      51  static char *
      52  __nis_getpkey(const char *sname)
      53  {
      54    char buf[(strlen (sname) + 1) * 2 + 40];
      55    char pkey[HEXKEYBYTES + 1];
      56    char *cp, *domain;
      57    nis_result *res;
      58    unsigned int len = 0;
      59  
      60    domain = strchr (sname, '.');
      61    if (domain == NULL)
      62      return NULL;
      63  
      64    /* Remove prefixing dot */
      65    ++domain;
      66  
      67    cp = stpcpy (buf, "[cname=");
      68    cp = stpcpy (cp, sname);
      69    cp = stpcpy (cp, ",auth_type=DES],cred.org_dir.");
      70    cp = stpcpy (cp, domain);
      71  
      72    res = nis_list (buf, USE_DGRAM|NO_AUTHINFO|FOLLOW_LINKS|FOLLOW_PATH,
      73  		  NULL, NULL);
      74  
      75    if (res == NULL)
      76      return NULL;
      77  
      78    if (NIS_RES_STATUS (res) != NIS_SUCCESS)
      79      {
      80        nis_freeresult (res);
      81        return NULL;
      82      }
      83  
      84    len = ENTRY_LEN(NIS_RES_OBJECT(res), 3);
      85    strncpy (pkey, ENTRY_VAL(NIS_RES_OBJECT(res), 3), len);
      86    pkey[len] = '\0';
      87    cp = strchr (pkey, ':');
      88    if (cp != NULL)
      89      *cp = '\0';
      90  
      91    nis_freeresult (res);
      92  
      93    return strdup (pkey);
      94  }
      95  #endif
      96  
      97  static void
      98  cb_prog_1 (struct svc_req *rqstp, SVCXPRT *transp)
      99  {
     100    union
     101      {
     102        cback_data cbproc_receive_1_arg;
     103        nis_error cbproc_error_1_arg;
     104      }
     105    argument;
     106    char *result;
     107    xdrproc_t xdr_argument, xdr_result;
     108    bool_t bool_result;
     109  
     110    switch (rqstp->rq_proc)
     111      {
     112      case NULLPROC:
     113        svc_sendreply (transp, (xdrproc_t) xdr_void, (char *) NULL);
     114        return;
     115  
     116      case CBPROC_RECEIVE:
     117        {
     118  	unsigned int i;
     119  
     120  	xdr_argument = (xdrproc_t) xdr_cback_data;
     121  	xdr_result = (xdrproc_t) xdr_bool;
     122  	memset (&argument, 0, sizeof (argument));
     123  	if (!svc_getargs (transp, xdr_argument, (caddr_t) & argument))
     124  	  {
     125  	    svcerr_decode (transp);
     126  	    return;
     127  	  }
     128  	bool_result = FALSE;
     129  	for (i = 0; i < argument.cbproc_receive_1_arg.entries.entries_len; ++i)
     130  	  {
     131  #define cbproc_entry(a) argument.cbproc_receive_1_arg.entries.entries_val[a]
     132  	    char name[strlen (cbproc_entry(i)->zo_name)
     133  		      + strlen (cbproc_entry(i)->zo_domain) + 3];
     134  	    char *cp;
     135  
     136  	    cp = stpcpy (name, cbproc_entry(i)->zo_name);
     137  	    *cp++ = '.';
     138  	    cp = stpcpy (cp, cbproc_entry(i)->zo_domain);
     139  
     140  	    if ((data->callback) (name, cbproc_entry(i), data->userdata))
     141  	      {
     142  		bool_result = TRUE;
     143  		data->nomore = 1;
     144  		data->result = NIS_SUCCESS;
     145  		break;
     146  	      }
     147  	  }
     148  	result = (char *) &bool_result;
     149        }
     150        break;
     151      case CBPROC_FINISH:
     152        xdr_argument = (xdrproc_t) xdr_void;
     153        xdr_result = (xdrproc_t) xdr_void;
     154        memset (&argument, 0, sizeof (argument));
     155        if (!svc_getargs (transp, xdr_argument, (caddr_t) & argument))
     156  	{
     157  	  svcerr_decode (transp);
     158  	  return;
     159  	}
     160        data->nomore = 1;
     161        data->result = NIS_SUCCESS;
     162        bool_result = TRUE;	/* to make gcc happy, not necessary */
     163        result = (char *) &bool_result;
     164        break;
     165      case CBPROC_ERROR:
     166        xdr_argument = (xdrproc_t) _xdr_nis_error;
     167        xdr_result = (xdrproc_t) xdr_void;
     168        memset (&argument, 0, sizeof (argument));
     169        if (!svc_getargs (transp, xdr_argument, (caddr_t) & argument))
     170  	{
     171  	  svcerr_decode (transp);
     172  	  return;
     173  	}
     174        data->nomore = 1;
     175        data->result = argument.cbproc_error_1_arg;
     176        bool_result = TRUE;	/* to make gcc happy, not necessary */
     177        result = (char *) &bool_result;
     178        break;
     179      default:
     180        svcerr_noproc (transp);
     181        return;
     182      }
     183    if (result != NULL && !svc_sendreply (transp, xdr_result, result))
     184      svcerr_systemerr (transp);
     185    if (!svc_freeargs (transp, xdr_argument, (caddr_t) & argument))
     186      {
     187        fputs (_ ("unable to free arguments"), stderr);
     188        exit (1);
     189      }
     190    return;
     191  }
     192  
     193  static nis_error
     194  internal_nis_do_callback (struct dir_binding *bptr, netobj *cookie,
     195  			  struct nis_cb *cb)
     196  {
     197    struct timeval TIMEOUT = {25, 0};
     198    bool_t cb_is_running;
     199  
     200    data = cb;
     201  
     202    for (;;)
     203      {
     204        struct pollfd my_pollfd[svc_max_pollfd];
     205        int i;
     206  
     207        if (svc_max_pollfd == 0 && svc_pollfd == NULL)
     208          return NIS_CBERROR;
     209  
     210        for (i = 0; i < svc_max_pollfd; ++i)
     211          {
     212            my_pollfd[i].fd = svc_pollfd[i].fd;
     213            my_pollfd[i].events = svc_pollfd[i].events;
     214            my_pollfd[i].revents = 0;
     215          }
     216  
     217        switch (i = TEMP_FAILURE_RETRY (__poll (my_pollfd, svc_max_pollfd,
     218  					      25*1000)))
     219          {
     220  	case -1:
     221  	  return NIS_CBERROR;
     222  	case 0:
     223  	  /* See if callback 'thread' in the server is still alive. */
     224  	  cb_is_running = FALSE;
     225  	  if (clnt_call (bptr->clnt, NIS_CALLBACK, (xdrproc_t) xdr_netobj,
     226  			 (caddr_t) cookie, (xdrproc_t) xdr_bool,
     227  			 (caddr_t) &cb_is_running, TIMEOUT) != RPC_SUCCESS)
     228  	    cb_is_running = FALSE;
     229  
     230  	  if (cb_is_running == FALSE)
     231  	    {
     232  	      syslog (LOG_ERR, "NIS+: callback timed out");
     233  	      return NIS_CBERROR;
     234  	    }
     235  	  break;
     236  	default:
     237  	  svc_getreq_poll (my_pollfd, i);
     238  	  if (data->nomore)
     239  	    return data->result;
     240  	}
     241      }
     242  }
     243  
     244  nis_error
     245  __nis_do_callback (struct dir_binding *bptr, netobj *cookie,
     246  		   struct nis_cb *cb)
     247  {
     248    nis_error result;
     249  
     250    __libc_lock_lock (callback);
     251  
     252    result = internal_nis_do_callback (bptr, cookie, cb);
     253  
     254    __libc_lock_unlock (callback);
     255  
     256    return result;
     257  }
     258  
     259  struct nis_cb *
     260  __nis_create_callback (int (*callback) (const_nis_name, const nis_object *,
     261  					const void *),
     262  		       const void *userdata, unsigned int flags)
     263  {
     264    struct nis_cb *cb;
     265    int sock = RPC_ANYSOCK;
     266    struct sockaddr_in sin;
     267    socklen_t len = sizeof (struct sockaddr_in);
     268    unsigned short port;
     269    int nomsg = 0;
     270  
     271    cb = (struct nis_cb *) calloc (1,
     272  				 sizeof (struct nis_cb) + sizeof (nis_server));
     273    if (__glibc_unlikely (cb == NULL))
     274      goto failed;
     275    cb->serv = (nis_server *) (cb + 1);
     276    cb->serv->name = strdup (nis_local_principal ());
     277    if (__glibc_unlikely (cb->serv->name == NULL))
     278      goto failed;
     279    cb->serv->ep.ep_val = (endpoint *) calloc (2, sizeof (endpoint));
     280    if (__glibc_unlikely (cb->serv->ep.ep_val == NULL))
     281      goto failed;
     282    cb->serv->ep.ep_len = 1;
     283    cb->serv->ep.ep_val[0].family = strdup ("inet");
     284    if (__glibc_unlikely (cb->serv->ep.ep_val[0].family == NULL))
     285      goto failed;
     286    cb->callback = callback;
     287    cb->userdata = userdata;
     288  
     289    if ((flags & NO_AUTHINFO) || !key_secretkey_is_set ())
     290      {
     291        cb->serv->key_type = NIS_PK_NONE;
     292        cb->serv->pkey.n_bytes = NULL;
     293        cb->serv->pkey.n_len = 0;
     294      }
     295    else
     296      {
     297  #if 0
     298        if ((cb->serv->pkey.n_bytes = __nis_getpkey (cb->serv->name)) == NULL)
     299  	{
     300  	  cb->serv->pkey.n_len = 0;
     301  	  cb->serv->key_type = NIS_PK_NONE;
     302  	}
     303        else
     304  	{
     305  	  cb->serv->key_type = NIS_PK_DH;
     306  	  cb->serv->pkey.n_len = strlen(cb->serv->pkey.n_bytes);
     307  	}
     308  #else
     309        cb->serv->pkey.n_len =0;
     310        cb->serv->pkey.n_bytes = NULL;
     311        cb->serv->key_type = NIS_PK_NONE;
     312  #endif
     313      }
     314  
     315    cb->serv->ep.ep_val[0].proto = strdup ((flags & USE_DGRAM) ? "udp" : "tcp");
     316    if (__glibc_unlikely (cb->serv->ep.ep_val[0].proto == NULL))
     317      goto failed;
     318    cb->xprt = ((flags & USE_DGRAM)
     319  	      ? svcudp_bufcreate (sock, 100, 8192)
     320  	      : svctcp_create (sock, 100, 8192));
     321    if (cb->xprt == NULL)
     322      {
     323        nomsg = 1;
     324        goto failed;
     325      }
     326    cb->sock = cb->xprt->xp_sock;
     327    if (!svc_register (cb->xprt, CB_PROG, CB_VERS, cb_prog_1, 0))
     328      {
     329        xprt_unregister (cb->xprt);
     330        svc_destroy (cb->xprt);
     331        xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
     332        free (cb);
     333        syslog (LOG_ERR, "NIS+: failed to register callback dispatcher");
     334        return NULL;
     335      }
     336  
     337    if (getsockname (cb->sock, (struct sockaddr *) &sin, &len) == -1)
     338      {
     339        xprt_unregister (cb->xprt);
     340        svc_destroy (cb->xprt);
     341        xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
     342        free (cb);
     343        syslog (LOG_ERR, "NIS+: failed to read local socket info");
     344        return NULL;
     345      }
     346    port = ntohs (sin.sin_port);
     347    get_myaddress (&sin);
     348  
     349    if (asprintf (&cb->serv->ep.ep_val[0].uaddr, "%s.%d.%d",
     350  		inet_ntoa (sin.sin_addr), (port & 0xFF00) >> 8, port & 0x00FF)
     351        < 0)
     352      goto failed;
     353  
     354    return cb;
     355  
     356   failed:
     357    if (cb)
     358      {
     359        if (cb->xprt)
     360  	svc_destroy (cb->xprt);
     361        xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
     362        free (cb);
     363      }
     364    if (!nomsg)
     365      syslog (LOG_ERR, "NIS+: out of memory allocating callback");
     366    return NULL;
     367  }
     368  
     369  nis_error
     370  __nis_destroy_callback (struct nis_cb *cb)
     371  {
     372    xprt_unregister (cb->xprt);
     373    svc_destroy (cb->xprt);
     374    close (cb->sock);
     375    xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
     376    free (cb);
     377  
     378    return NIS_SUCCESS;
     379  }