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