Home | History | Annotate | Line # | Download | only in amd
      1 /*	$NetBSD: info_nis.c,v 1.1.1.3 2015/01/17 16:34:15 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997-2014 Erez Zadok
      5  * Copyright (c) 1989 Jan-Simon Pendry
      6  * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
      7  * Copyright (c) 1989 The Regents of the University of California.
      8  * All rights reserved.
      9  *
     10  * This code is derived from software contributed to Berkeley by
     11  * Jan-Simon Pendry at Imperial College, London.
     12  *
     13  * Redistribution and use in source and binary forms, with or without
     14  * modification, are permitted provided that the following conditions
     15  * are met:
     16  * 1. Redistributions of source code must retain the above copyright
     17  *    notice, this list of conditions and the following disclaimer.
     18  * 2. Redistributions in binary form must reproduce the above copyright
     19  *    notice, this list of conditions and the following disclaimer in the
     20  *    documentation and/or other materials provided with the distribution.
     21  * 3. Neither the name of the University nor the names of its contributors
     22  *    may be used to endorse or promote products derived from this software
     23  *    without specific prior written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     35  * SUCH DAMAGE.
     36  *
     37  *
     38  * File: am-utils/amd/info_nis.c
     39  *
     40  */
     41 
     42 /*
     43  * Get info from NIS map
     44  */
     45 
     46 #ifdef HAVE_CONFIG_H
     47 # include <config.h>
     48 #endif /* HAVE_CONFIG_H */
     49 #include <am_defs.h>
     50 #include <amd.h>
     51 #include <sun_map.h>
     52 
     53 
     54 /*
     55  * NIS+ servers in NIS compat mode don't have yp_order()
     56  *
     57  *	has_yp_order = 1	NIS server
     58  *		     = 0	NIS+ server
     59  *		     = -1	server is down
     60  */
     61 static int has_yp_order = -1;
     62 
     63 /* forward declarations */
     64 int nis_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *));
     65 int nis_search(mnt_map *m, char *map, char *key, char **val, time_t *tp);
     66 int nis_init(mnt_map *m, char *map, time_t *tp);
     67 int nis_isup(mnt_map *m, char *map);
     68 int nis_mtime(mnt_map *m, char *map, time_t *tp);
     69 
     70 /* typedefs */
     71 typedef void (*nis_callback_fxn_t)(mnt_map *, char *, char *);
     72 #ifndef DEFINED_YPALL_CALLBACK_FXN_T
     73 typedef int (*ypall_callback_fxn_t)();
     74 #endif /* DEFINED_YPALL_CALLBACK_FXN_T */
     75 
     76 struct nis_callback_data {
     77   mnt_map *ncd_m;
     78   char *ncd_map;
     79   nis_callback_fxn_t ncd_fn;
     80 };
     81 
     82 /* Map to the right version of yp_all */
     83 #ifdef HAVE_BAD_YP_ALL
     84 # define yp_all am_yp_all
     85 static int am_yp_all(char *indomain, char *inmap, struct ypall_callback *incallback);
     86 #endif /* HAVE_BAD_YP_ALL */
     87 
     88 
     89 /*
     90  * Figure out the nis domain name
     91  */
     92 static int
     93 determine_nis_domain(void)
     94 {
     95   static int nis_not_running = 0;
     96   char default_domain[YPMAXDOMAIN];
     97 
     98   if (nis_not_running)
     99     return ENOENT;
    100 
    101   if (getdomainname(default_domain, sizeof(default_domain)) < 0) {
    102     nis_not_running = 1;
    103     plog(XLOG_ERROR, "getdomainname: %m");
    104     return EIO;
    105   }
    106   if (!*default_domain) {
    107     nis_not_running = 1;
    108     plog(XLOG_WARNING, "NIS domain name is not set.  NIS ignored.");
    109     return ENOENT;
    110   }
    111   gopt.nis_domain = xstrdup(default_domain);
    112 
    113   return 0;
    114 }
    115 
    116 
    117 /*
    118  * Callback from yp_all
    119  */
    120 static int
    121 callback(int status, char *key, int kl, char *val, int vl, char *data)
    122 {
    123   struct nis_callback_data *ncdp = (struct nis_callback_data *) data;
    124 
    125   if (status == YP_TRUE) {
    126 
    127     /* add to list of maps */
    128     char *kp = strnsave(key, kl);
    129     char *vp = strnsave(val, vl);
    130 
    131     (*ncdp->ncd_fn) (ncdp->ncd_m, kp, vp);
    132 
    133     /* we want more ... */
    134     return FALSE;
    135 
    136   } else {
    137 
    138     /* NOMORE means end of map - otherwise log error */
    139     if (status != YP_NOMORE) {
    140       /* check what went wrong */
    141       int e = ypprot_err(status);
    142 
    143       plog(XLOG_ERROR, "yp enumeration of %s: %s, status=%d, e=%d",
    144 	   ncdp->ncd_map, yperr_string(e), status, e);
    145     }
    146     return TRUE;
    147   }
    148 }
    149 
    150 
    151 int
    152 nis_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *))
    153 {
    154   int error;
    155   struct nis_callback_data data;
    156   struct ypall_callback cbinfo;
    157 
    158   if (!gopt.nis_domain) {
    159     error = determine_nis_domain();
    160     if (error)
    161       return error;
    162   }
    163   data.ncd_m = m;
    164   data.ncd_map = map;
    165   data.ncd_fn = fn;
    166   cbinfo.data = (voidp) &data;
    167   cbinfo.foreach = (ypall_callback_fxn_t) callback;
    168 
    169   plog(XLOG_INFO, "NIS map %s reloading using yp_all", map);
    170   /*
    171    * If you are using NIS and your yp_all function is "broken", you have to
    172    * get it fixed.  The bug in yp_all() is that it does not close a TCP
    173    * connection to ypserv, and this ypserv runs out of open file descriptors,
    174    * getting into an infinite loop, thus all YP clients eventually unbind
    175    * and hang too.
    176    */
    177   error = yp_all(gopt.nis_domain, map, &cbinfo);
    178 
    179   if (error)
    180     plog(XLOG_ERROR, "error grabbing nis map of %s: %s", map, yperr_string(ypprot_err(error)));
    181   return error;
    182 }
    183 
    184 
    185 /*
    186  * Check if NIS is up, so we can determine if to clear the map or not.
    187  * Test it by checking the yp order.
    188  * Returns: 0 if NIS is down, 1 if it is up.
    189  */
    190 int
    191 nis_isup(mnt_map *m, char *map)
    192 {
    193   YP_ORDER_OUTORDER_TYPE order;
    194   int error;
    195   char *master;
    196   static int last_status = 1;	/* assume up by default */
    197 
    198   switch (has_yp_order) {
    199   case 1:
    200     /*
    201      * NIS server with yp_order
    202      */
    203     error = yp_order(gopt.nis_domain, map, &order);
    204     if (error != 0) {
    205       plog(XLOG_ERROR,
    206 	   "nis_isup: error getting the order of map %s: %s",
    207 	   map, yperr_string(ypprot_err(error)));
    208       last_status = 0;
    209       return 0;			/* NIS is down */
    210     }
    211     break;
    212 
    213   case 0:
    214     /*
    215      * NIS+ server without yp_order
    216      */
    217     error = yp_master(gopt.nis_domain, map, &master);
    218     if (error != 0) {
    219       plog(XLOG_ERROR,
    220 	   "nis_isup: error getting the master of map %s: %s",
    221 	   map, yperr_string(ypprot_err(error)));
    222       last_status = 0;
    223       return 0;			/* NIS+ is down */
    224     }
    225     break;
    226 
    227   default:
    228     /*
    229      * server was down
    230      */
    231     last_status = 0;
    232   }
    233 
    234   if (last_status == 0) {	/* reinitialize if was down before */
    235     time_t dummy;
    236     error = nis_init(m, map, &dummy);
    237     if (error)
    238       return 0;			/* still down */
    239     plog(XLOG_INFO, "nis_isup: NIS came back up for map %s", map);
    240     last_status = 1;
    241   }
    242   return 1;			/* NIS is up */
    243 }
    244 
    245 
    246 /*
    247  * Try to locate a key using NIS.
    248  */
    249 int
    250 nis_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
    251 {
    252   int outlen;
    253   int res;
    254   YP_ORDER_OUTORDER_TYPE order;
    255 
    256   /*
    257    * Make sure domain initialized
    258    */
    259   if (!gopt.nis_domain) {
    260     int error = determine_nis_domain();
    261     if (error)
    262       return error;
    263   }
    264 
    265 
    266   switch (has_yp_order) {
    267   case 1:
    268     /*
    269      * NIS server with yp_order
    270      * Check if map has changed
    271      */
    272     if (yp_order(gopt.nis_domain, map, &order))
    273       return EIO;
    274     if ((time_t) order > *tp) {
    275       *tp = (time_t) order;
    276       return -1;
    277     }
    278     break;
    279 
    280   case 0:
    281     /*
    282      * NIS+ server without yp_order
    283      * Check if timeout has expired to invalidate the cache
    284      */
    285     order = time(NULL);
    286     if ((time_t)order - *tp > gopt.am_timeo) {
    287       *tp = (time_t)order;
    288       return(-1);
    289     }
    290     break;
    291 
    292   default:
    293     /*
    294      * server was down
    295      */
    296      if (nis_isup(m, map))
    297        return -1;
    298      return EIO;
    299   }
    300 
    301   /*
    302    * Lookup key
    303    */
    304   res = yp_match(gopt.nis_domain, map, key, strlen(key), pval, &outlen);
    305   if (m->cfm && (m->cfm->cfm_flags & CFM_SUN_MAP_SYNTAX) && res == 0) {
    306     char *oldval = *pval;
    307     *pval = sun_entry2amd(key, oldval);
    308     /* We always need to free the output of the yp_match call. */
    309     XFREE(oldval);
    310     if (*pval == NULL)
    311       return -1;		/* sun2amd parser error */
    312   }
    313 
    314   /*
    315    * Do something interesting with the return code
    316    */
    317   switch (res) {
    318   case 0:
    319     return 0;
    320 
    321   case YPERR_KEY:
    322     return ENOENT;
    323 
    324   default:
    325     plog(XLOG_ERROR, "nis_search: %s: %s", map, yperr_string(res));
    326     return EIO;
    327   }
    328 }
    329 
    330 
    331 int
    332 nis_init(mnt_map *m, char *map, time_t *tp)
    333 {
    334   YP_ORDER_OUTORDER_TYPE order;
    335   int yp_order_result;
    336   char *master;
    337 
    338   if (!gopt.nis_domain) {
    339     int error = determine_nis_domain();
    340     if (error)
    341       return error;
    342   }
    343 
    344   /*
    345    * To see if the map exists, try to find
    346    * a master for it.
    347    */
    348   yp_order_result = yp_order(gopt.nis_domain, map, &order);
    349   switch (yp_order_result) {
    350   case 0:
    351     /* NIS server found */
    352     has_yp_order = 1;
    353     *tp = (time_t) order;
    354     dlog("NIS master for %s@%s has order %lu", map, gopt.nis_domain, (unsigned long) order);
    355     break;
    356   case YPERR_YPERR:
    357     /* NIS+ server found ! */
    358     has_yp_order = 0;
    359     /* try yp_master() instead */
    360     if (yp_master(gopt.nis_domain, map, &master)) {
    361       return ENOENT;
    362     } else {
    363       dlog("NIS master for %s@%s is a NIS+ server", map, gopt.nis_domain);
    364       /* Use fake timestamps */
    365       *tp = time(NULL);
    366     }
    367     break;
    368   default:
    369     /* server is down */
    370     has_yp_order = -1;
    371     return ENOENT;
    372   }
    373   return 0;
    374 }
    375 
    376 
    377 int
    378 nis_mtime(mnt_map *m, char *map, time_t *tp)
    379 {
    380   return nis_init(m, map, tp);
    381 }
    382 
    383 
    384 #ifdef HAVE_BAD_YP_ALL
    385 /*
    386  * If you are using NIS and your yp_all function is "broken", use an
    387  * alternate code which avoids a bug in yp_all().  The bug in yp_all() is
    388  * that it does not close a TCP connection to ypserv, and this ypserv runs
    389  * out of open filedescriptors, getting into an infinite loop, thus all YP
    390  * clients eventually unbind and hang too.
    391  *
    392  * Systems known to be plagued with this bug:
    393  *	earlier SunOS 4.x
    394  *	all irix systems (at this time, up to 6.4 was checked)
    395  *
    396  * -Erez Zadok <ezk (at) cs.columbia.edu>
    397  * -James Tanis <jtt (at) cs.columbia.edu> */
    398 static int
    399 am_yp_all(char *indomain, char *inmap, struct ypall_callback *incallback)
    400 {
    401   int i, j;
    402   char *outkey, *outval;
    403   int outkeylen, outvallen;
    404   char *outkey_old;
    405   int outkeylen_old;
    406 
    407   plog(XLOG_INFO, "NIS map %s reloading using am_yp_all", inmap);
    408 
    409   i = yp_first(indomain, inmap, &outkey, &outkeylen, &outval, &outvallen);
    410   if (i) {
    411     plog(XLOG_ERROR, "yp_first() returned error: %s\n", yperr_string(i));
    412   }
    413   do {
    414     j = (incallback->foreach)(YP_TRUE,
    415 			      outkey,
    416 			      outkeylen,
    417 			      outval,
    418 			      outvallen,
    419 			      incallback->data);
    420     if (j != FALSE)		/* terminate loop */
    421       break;
    422 
    423     /*
    424      * We have to manually free all char ** arguments to yp_first/yp_next
    425      * outval must be freed *before* calling yp_next again, outkey can be
    426      * freed as outkey_old *after* the call (this saves one call to
    427      * strnsave).
    428      */
    429     XFREE(outval);
    430     outkey_old = outkey;
    431     outkeylen_old = outkeylen;
    432     i = yp_next(indomain,
    433 		inmap,
    434 		outkey_old,
    435 		outkeylen_old,
    436 		&outkey,
    437 		&outkeylen,
    438 		&outval,
    439 		&outvallen);
    440     XFREE(outkey_old);
    441   } while (!i);
    442   if (i) {
    443     dlog("yp_next() returned error: %s\n", yperr_string(i));
    444   }
    445   if (i == YPERR_NOMORE)
    446     return 0;
    447   return i;
    448 }
    449 #endif /* HAVE_BAD_YP_ALL */
    450