Back to index

glibc  2.9
nis_callback.c
Go to the documentation of this file.
00001 /* Copyright (C) 1997,1998,1999,2000,2005,2006 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Thorsten Kukuk <kukuk@suse.de>, 1997.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <errno.h>
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <unistd.h>
00024 #include <libintl.h>
00025 #include <rpc/rpc.h>
00026 #include <rpc/pmap_clnt.h>
00027 #include <string.h>
00028 #include <memory.h>
00029 #include <syslog.h>
00030 #include <sys/poll.h>
00031 #include <sys/socket.h>
00032 #include <netinet/in.h>
00033 #include <arpa/inet.h>
00034 #include <rpc/key_prot.h>
00035 #include <rpcsvc/nis.h>
00036 #include <rpcsvc/nis_callback.h>
00037 #include <bits/libc-lock.h>
00038 
00039 #include "nis_xdr.h"
00040 #include "nis_intern.h"
00041 
00042 /* Sorry, we are not able to make this threadsafe. Stupid. But some
00043    functions doesn't send us a nis_result obj, so we don't have a
00044    cookie. Maybe we could use keys for threads ? Have to learn more
00045    about pthreads -- kukuk@vt.uni-paderborn.de */
00046 
00047 static nis_cb *data;
00048 
00049 __libc_lock_define_initialized (static, callback)
00050 
00051 
00052 #if 0
00053 static char *
00054 __nis_getpkey(const char *sname)
00055 {
00056   char buf[(strlen (sname) + 1) * 2 + 40];
00057   char pkey[HEXKEYBYTES + 1];
00058   char *cp, *domain;
00059   nis_result *res;
00060   unsigned int len = 0;
00061 
00062   domain = strchr (sname, '.');
00063   if (domain == NULL)
00064     return NULL;
00065 
00066   /* Remove prefixing dot */
00067   ++domain;
00068 
00069   cp = stpcpy (buf, "[cname=");
00070   cp = stpcpy (cp, sname);
00071   cp = stpcpy (cp, ",auth_type=DES],cred.org_dir.");
00072   cp = stpcpy (cp, domain);
00073 
00074   res = nis_list (buf, USE_DGRAM|NO_AUTHINFO|FOLLOW_LINKS|FOLLOW_PATH,
00075                 NULL, NULL);
00076 
00077   if (res == NULL)
00078     return NULL;
00079 
00080   if (NIS_RES_STATUS (res) != NIS_SUCCESS)
00081     {
00082       nis_freeresult (res);
00083       return NULL;
00084     }
00085 
00086   len = ENTRY_LEN(NIS_RES_OBJECT(res), 3);
00087   strncpy (pkey, ENTRY_VAL(NIS_RES_OBJECT(res), 3), len);
00088   pkey[len] = '\0';
00089   cp = strchr (pkey, ':');
00090   if (cp != NULL)
00091     *cp = '\0';
00092 
00093   nis_freeresult (res);
00094 
00095   return strdup (pkey);
00096 }
00097 #endif
00098 
00099 static void
00100 cb_prog_1 (struct svc_req *rqstp, SVCXPRT *transp)
00101 {
00102   union
00103     {
00104       cback_data cbproc_receive_1_arg;
00105       nis_error cbproc_error_1_arg;
00106     }
00107   argument;
00108   char *result;
00109   xdrproc_t xdr_argument, xdr_result;
00110   bool_t bool_result;
00111 
00112   switch (rqstp->rq_proc)
00113     {
00114     case NULLPROC:
00115       svc_sendreply (transp, (xdrproc_t) xdr_void, (char *) NULL);
00116       return;
00117 
00118     case CBPROC_RECEIVE:
00119       {
00120        unsigned int i;
00121 
00122        xdr_argument = (xdrproc_t) xdr_cback_data;
00123        xdr_result = (xdrproc_t) xdr_bool;
00124        memset (&argument, 0, sizeof (argument));
00125        if (!svc_getargs (transp, xdr_argument, (caddr_t) & argument))
00126          {
00127            svcerr_decode (transp);
00128            return;
00129          }
00130        bool_result = FALSE;
00131        for (i = 0; i < argument.cbproc_receive_1_arg.entries.entries_len; ++i)
00132          {
00133 #define cbproc_entry(a) argument.cbproc_receive_1_arg.entries.entries_val[a]
00134            char name[strlen (cbproc_entry(i)->zo_name) +
00135                     strlen (cbproc_entry(i)->zo_domain) + 3];
00136            char *cp;
00137 
00138            cp = stpcpy (name, cbproc_entry(i)->zo_name);
00139            *cp++ = '.';
00140            cp = stpcpy (cp, cbproc_entry(i)->zo_domain);
00141 
00142            if ((data->callback) (name, cbproc_entry(i), data->userdata))
00143              {
00144               bool_result = TRUE;
00145               data->nomore = 1;
00146               data->result = NIS_SUCCESS;
00147               break;
00148              }
00149          }
00150        result = (char *) &bool_result;
00151       }
00152       break;
00153     case CBPROC_FINISH:
00154       xdr_argument = (xdrproc_t) xdr_void;
00155       xdr_result = (xdrproc_t) xdr_void;
00156       memset (&argument, 0, sizeof (argument));
00157       if (!svc_getargs (transp, xdr_argument, (caddr_t) & argument))
00158        {
00159          svcerr_decode (transp);
00160          return;
00161        }
00162       data->nomore = 1;
00163       data->result = NIS_SUCCESS;
00164       bool_result = TRUE;   /* to make gcc happy, not necessary */
00165       result = (char *) &bool_result;
00166       break;
00167     case CBPROC_ERROR:
00168       xdr_argument = (xdrproc_t) _xdr_nis_error;
00169       xdr_result = (xdrproc_t) xdr_void;
00170       memset (&argument, 0, sizeof (argument));
00171       if (!svc_getargs (transp, xdr_argument, (caddr_t) & argument))
00172        {
00173          svcerr_decode (transp);
00174          return;
00175        }
00176       data->nomore = 1;
00177       data->result = argument.cbproc_error_1_arg;
00178       bool_result = TRUE;   /* to make gcc happy, not necessary */
00179       result = (char *) &bool_result;
00180       break;
00181     default:
00182       svcerr_noproc (transp);
00183       return;
00184     }
00185   if (result != NULL && !svc_sendreply (transp, xdr_result, result))
00186     svcerr_systemerr (transp);
00187   if (!svc_freeargs (transp, xdr_argument, (caddr_t) & argument))
00188     {
00189       fputs (_ ("unable to free arguments"), stderr);
00190       exit (1);
00191     }
00192   return;
00193 }
00194 
00195 static nis_error
00196 internal_nis_do_callback (struct dir_binding *bptr, netobj *cookie,
00197                        struct nis_cb *cb)
00198 {
00199   struct timeval TIMEOUT = {25, 0};
00200   bool_t cb_is_running;
00201 
00202   data = cb;
00203 
00204   for (;;)
00205     {
00206       struct pollfd my_pollfd[svc_max_pollfd];
00207       int i;
00208 
00209       if (svc_max_pollfd == 0 && svc_pollfd == NULL)
00210         return NIS_CBERROR;
00211 
00212       for (i = 0; i < svc_max_pollfd; ++i)
00213         {
00214           my_pollfd[i].fd = svc_pollfd[i].fd;
00215           my_pollfd[i].events = svc_pollfd[i].events;
00216           my_pollfd[i].revents = 0;
00217         }
00218 
00219       switch (i = TEMP_FAILURE_RETRY (__poll (my_pollfd, svc_max_pollfd,
00220                                          25*1000)))
00221         {
00222        case -1:
00223          return NIS_CBERROR;
00224        case 0:
00225          /* See if callback 'thread' in the server is still alive. */
00226          cb_is_running = FALSE;
00227          if (clnt_call (bptr->clnt, NIS_CALLBACK, (xdrproc_t) xdr_netobj,
00228                       (caddr_t) cookie, (xdrproc_t) xdr_bool,
00229                       (caddr_t) &cb_is_running, TIMEOUT) != RPC_SUCCESS)
00230            cb_is_running = FALSE;
00231 
00232          if (cb_is_running == FALSE)
00233            {
00234              syslog (LOG_ERR, "NIS+: callback timed out");
00235              return NIS_CBERROR;
00236            }
00237          break;
00238        default:
00239          svc_getreq_poll (my_pollfd, i);
00240          if (data->nomore)
00241            return data->result;
00242        }
00243     }
00244 }
00245 
00246 nis_error
00247 __nis_do_callback (struct dir_binding *bptr, netobj *cookie,
00248                  struct nis_cb *cb)
00249 {
00250   nis_error result;
00251 
00252   __libc_lock_lock (callback);
00253 
00254   result = internal_nis_do_callback (bptr, cookie, cb);
00255 
00256   __libc_lock_unlock (callback);
00257 
00258   return result;
00259 }
00260 
00261 struct nis_cb *
00262 __nis_create_callback (int (*callback) (const_nis_name, const nis_object *,
00263                                    const void *),
00264                      const void *userdata, unsigned int flags)
00265 {
00266   struct nis_cb *cb;
00267   int sock = RPC_ANYSOCK;
00268   struct sockaddr_in sin;
00269   socklen_t len = sizeof (struct sockaddr_in);
00270   unsigned short port;
00271   int nomsg = 0;
00272 
00273   cb = (struct nis_cb *) calloc (1,
00274                              sizeof (struct nis_cb) + sizeof (nis_server));
00275   if (__builtin_expect (cb == NULL, 0))
00276     goto failed;
00277   cb->serv = (nis_server *) (cb + 1);
00278   cb->serv->name = strdup (nis_local_principal ());
00279   if (__builtin_expect (cb->serv->name == NULL, 0))
00280     goto failed;
00281   cb->serv->ep.ep_val = (endpoint *) calloc (2, sizeof (endpoint));
00282   if (__builtin_expect (cb->serv->ep.ep_val == NULL, 0))
00283     goto failed;
00284   cb->serv->ep.ep_len = 1;
00285   cb->serv->ep.ep_val[0].family = strdup ("inet");
00286   if (__builtin_expect (cb->serv->ep.ep_val[0].family == NULL, 0))
00287     goto failed;
00288   cb->callback = callback;
00289   cb->userdata = userdata;
00290 
00291   if ((flags & NO_AUTHINFO) || !key_secretkey_is_set ())
00292     {
00293       cb->serv->key_type = NIS_PK_NONE;
00294       cb->serv->pkey.n_bytes = NULL;
00295       cb->serv->pkey.n_len = 0;
00296     }
00297   else
00298     {
00299 #if 0
00300       if ((cb->serv->pkey.n_bytes = __nis_getpkey (cb->serv->name)) == NULL)
00301        {
00302          cb->serv->pkey.n_len = 0;
00303          cb->serv->key_type = NIS_PK_NONE;
00304        }
00305       else
00306        {
00307          cb->serv->key_type = NIS_PK_DH;
00308          cb->serv->pkey.n_len = strlen(cb->serv->pkey.n_bytes);
00309        }
00310 #else
00311       cb->serv->pkey.n_len =0;
00312       cb->serv->pkey.n_bytes = NULL;
00313       cb->serv->key_type = NIS_PK_NONE;
00314 #endif
00315     }
00316 
00317   cb->serv->ep.ep_val[0].proto = strdup ((flags & USE_DGRAM) ? "udp" : "tcp");
00318   if (__builtin_expect (cb->serv->ep.ep_val[0].proto == NULL, 0))
00319     goto failed;
00320   cb->xprt = ((flags & USE_DGRAM)
00321              ? svcudp_bufcreate (sock, 100, 8192)
00322              : svctcp_create (sock, 100, 8192));
00323   if (cb->xprt == NULL)
00324     {
00325       nomsg = 1;
00326       goto failed;
00327     }
00328   cb->sock = cb->xprt->xp_sock;
00329   if (!svc_register (cb->xprt, CB_PROG, CB_VERS, cb_prog_1, 0))
00330     {
00331       xprt_unregister (cb->xprt);
00332       svc_destroy (cb->xprt);
00333       xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
00334       free (cb);
00335       syslog (LOG_ERR, "NIS+: failed to register callback dispatcher");
00336       return NULL;
00337     }
00338 
00339   if (getsockname (cb->sock, (struct sockaddr *) &sin, &len) == -1)
00340     {
00341       xprt_unregister (cb->xprt);
00342       svc_destroy (cb->xprt);
00343       xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
00344       free (cb);
00345       syslog (LOG_ERR, "NIS+: failed to read local socket info");
00346       return NULL;
00347     }
00348   port = ntohs (sin.sin_port);
00349   get_myaddress (&sin);
00350 
00351   if (asprintf (&cb->serv->ep.ep_val[0].uaddr, "%s.%d.%d",
00352               inet_ntoa (sin.sin_addr), (port & 0xFF00) >> 8, port & 0x00FF)
00353       < 0)
00354     goto failed;
00355 
00356   return cb;
00357 
00358  failed:
00359   if (cb)
00360     {
00361       if (cb->xprt)
00362        svc_destroy (cb->xprt);
00363       xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
00364       free (cb);
00365     }
00366   if (!nomsg)
00367     syslog (LOG_ERR, "NIS+: out of memory allocating callback");
00368   return NULL;
00369 }
00370 
00371 nis_error
00372 __nis_destroy_callback (struct nis_cb *cb)
00373 {
00374   xprt_unregister (cb->xprt);
00375   svc_destroy (cb->xprt);
00376   close (cb->sock);
00377   xdr_free ((xdrproc_t) _xdr_nis_server, (char *) cb->serv);
00378   free (cb);
00379 
00380   return NIS_SUCCESS;
00381 }