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.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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
36 * File: am-utils/amd/info_nis.c
41 * Get info from NIS map
46 #endif /* HAVE_CONFIG_H */
53 * NIS+ servers in NIS compat mode don't have yp_order()
55 * has_yp_order = 1 NIS server
59 static int has_yp_order = -1;
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);
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 */
74 struct nis_callback_data {
77 nis_callback_fxn_t ncd_fn;
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 */
88 * Figure out the nis domain name
91 determine_nis_domain(void)
93 static int nis_not_running = 0;
94 char default_domain[YPMAXDOMAIN];
99 if (getdomainname(default_domain, sizeof(default_domain)) < 0) {
101 plog(XLOG_ERROR, "getdomainname: %m");
104 if (!*default_domain) {
106 plog(XLOG_WARNING, "NIS domain name is not set. NIS ignored.");
109 gopt.nis_domain = xstrdup(default_domain);
116 * Callback from yp_all
119 callback(int status, char *key, int kl, char *val, int vl, char *data)
121 struct nis_callback_data *ncdp = (struct nis_callback_data *) data;
123 if (status == YP_TRUE) {
125 /* add to list of maps */
126 char *kp = strnsave(key, kl);
127 char *vp = strnsave(val, vl);
129 (*ncdp->ncd_fn) (ncdp->ncd_m, kp, vp);
131 /* we want more ... */
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);
141 plog(XLOG_ERROR, "yp enumeration of %s: %s, status=%d, e=%d",
142 ncdp->ncd_map, yperr_string(e), status, e);
150 nis_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *))
153 struct nis_callback_data data;
154 struct ypall_callback cbinfo;
156 if (!gopt.nis_domain) {
157 error = determine_nis_domain();
164 cbinfo.data = (voidp) &data;
165 cbinfo.foreach = (ypall_callback_fxn_t) callback;
167 plog(XLOG_INFO, "NIS map %s reloading using yp_all", map);
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
175 error = yp_all(gopt.nis_domain, map, &cbinfo);
178 plog(XLOG_ERROR, "error grabbing nis map of %s: %s", map, yperr_string(ypprot_err(error)));
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.
189 nis_isup(mnt_map *m, char *map)
191 YP_ORDER_OUTORDER_TYPE order;
194 static int last_status = 1; /* assume up by default */
196 switch (has_yp_order) {
199 * NIS server with yp_order
201 error = yp_order(gopt.nis_domain, map, &order);
204 "nis_isup: error getting the order of map %s: %s",
205 map, yperr_string(ypprot_err(error)));
207 return 0; /* NIS is down */
213 * NIS+ server without yp_order
215 error = yp_master(gopt.nis_domain, map, &master);
218 "nis_isup: error getting the master of map %s: %s",
219 map, yperr_string(ypprot_err(error)));
221 return 0; /* NIS+ is down */
232 if (last_status == 0) { /* reinitialize if was down before */
234 error = nis_init(m, map, &dummy);
236 return 0; /* still down */
237 plog(XLOG_INFO, "nis_isup: NIS came back up for map %s", map);
240 return 1; /* NIS is up */
245 * Try to locate a key using NIS.
248 nis_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
252 YP_ORDER_OUTORDER_TYPE order;
255 * Make sure domain initialized
257 if (!gopt.nis_domain) {
258 int error = determine_nis_domain();
264 switch (has_yp_order) {
267 * NIS server with yp_order
268 * Check if map has changed
270 if (yp_order(gopt.nis_domain, map, &order))
272 if ((time_t) order > *tp) {
273 *tp = (time_t) order;
280 * NIS+ server without yp_order
281 * Check if timeout has expired to invalidate the cache
284 if ((time_t)order - *tp > gopt.am_timeo) {
294 if (nis_isup(m, map))
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. */
309 return -1; /* sun2amd parser error */
313 * Do something interesting with the return code
323 plog(XLOG_ERROR, "nis_search: %s: %s", map, yperr_string(res));
330 nis_init(mnt_map *m, char *map, time_t *tp)
332 YP_ORDER_OUTORDER_TYPE order;
336 if (!gopt.nis_domain) {
337 int error = determine_nis_domain();
343 * To see if the map exists, try to find
346 yp_order_result = yp_order(gopt.nis_domain, map, &order);
347 switch (yp_order_result) {
349 /* NIS server found */
351 *tp = (time_t) order;
352 dlog("NIS master for %s@%s has order %lu", map, gopt.nis_domain, (unsigned long) order);
355 /* NIS+ server found ! */
357 /* try yp_master() instead */
358 if (yp_master(gopt.nis_domain, map, &master)) {
361 dlog("NIS master for %s@%s is a NIS+ server", map, gopt.nis_domain);
362 /* Use fake timestamps */
376 nis_mtime(mnt_map *m, char *map, time_t *tp)
378 return nis_init(m, map, tp);
382 #ifdef HAVE_BAD_YP_ALL
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.
390 * Systems known to be plagued with this bug:
392 * all irix systems (at this time, up to 6.4 was checked)
394 * -Erez Zadok <ezk@cs.columbia.edu>
395 * -James Tanis <jtt@cs.columbia.edu> */
397 am_yp_all(char *indomain, char *inmap, struct ypall_callback *incallback)
400 char *outkey, *outval;
401 int outkeylen, outvallen;
405 plog(XLOG_INFO, "NIS map %s reloading using am_yp_all", inmap);
407 i = yp_first(indomain, inmap, &outkey, &outkeylen, &outval, &outvallen);
409 plog(XLOG_ERROR, "yp_first() returned error: %s\n", yperr_string(i));
412 j = (incallback->foreach)(YP_TRUE,
418 if (j != FALSE) /* terminate loop */
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
429 outkeylen_old = outkeylen;
430 i = yp_next(indomain,
441 dlog("yp_next() returned error: %s\n", yperr_string(i));
443 if (i == YPERR_NOMORE)
447 #endif /* HAVE_BAD_YP_ALL */