Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / bsd / am-utils / dist / amd / info_nis.c
blobd12809569979cc5efc9b4521de274e638818ffa5
1 /* $NetBSD$ */
3 /*
4 * Copyright (c) 1997-2009 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.
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
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. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgment:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
42 * File: am-utils/amd/info_nis.c
47 * Get info from NIS map
50 #ifdef HAVE_CONFIG_H
51 # include <config.h>
52 #endif /* HAVE_CONFIG_H */
53 #include <am_defs.h>
54 #include <amd.h>
55 #include <sun_map.h>
59 * NIS+ servers in NIS compat mode don't have yp_order()
61 * has_yp_order = 1 NIS server
62 * = 0 NIS+ server
63 * = -1 server is down
65 static int has_yp_order = -1;
67 /* forward declarations */
68 int nis_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *));
69 int nis_search(mnt_map *m, char *map, char *key, char **val, time_t *tp);
70 int nis_init(mnt_map *m, char *map, time_t *tp);
71 int nis_isup(mnt_map *m, char *map);
72 int nis_mtime(mnt_map *m, char *map, time_t *tp);
74 /* typedefs */
75 typedef void (*nis_callback_fxn_t)(mnt_map *, char *, char *);
76 #ifndef DEFINED_YPALL_CALLBACK_FXN_T
77 typedef int (*ypall_callback_fxn_t)();
78 #endif /* DEFINED_YPALL_CALLBACK_FXN_T */
80 struct nis_callback_data {
81 mnt_map *ncd_m;
82 char *ncd_map;
83 nis_callback_fxn_t ncd_fn;
86 /* Map to the right version of yp_all */
87 #ifdef HAVE_BAD_YP_ALL
88 # define yp_all am_yp_all
89 static int am_yp_all(char *indomain, char *inmap, struct ypall_callback *incallback);
90 #endif /* HAVE_BAD_YP_ALL */
94 * Figure out the nis domain name
96 static int
97 determine_nis_domain(void)
99 static int nis_not_running = 0;
100 char default_domain[YPMAXDOMAIN];
102 if (nis_not_running)
103 return ENOENT;
105 if (getdomainname(default_domain, sizeof(default_domain)) < 0) {
106 nis_not_running = 1;
107 plog(XLOG_ERROR, "getdomainname: %m");
108 return EIO;
110 if (!*default_domain) {
111 nis_not_running = 1;
112 plog(XLOG_WARNING, "NIS domain name is not set. NIS ignored.");
113 return ENOENT;
115 gopt.nis_domain = strdup(default_domain);
117 return 0;
122 * Callback from yp_all
124 static int
125 callback(int status, char *key, int kl, char *val, int vl, char *data)
127 struct nis_callback_data *ncdp = (struct nis_callback_data *) data;
129 if (status == YP_TRUE) {
131 /* add to list of maps */
132 char *kp = strnsave(key, kl);
133 char *vp = strnsave(val, vl);
135 (*ncdp->ncd_fn) (ncdp->ncd_m, kp, vp);
137 /* we want more ... */
138 return FALSE;
140 } else {
142 /* NOMORE means end of map - otherwise log error */
143 if (status != YP_NOMORE) {
144 /* check what went wrong */
145 int e = ypprot_err(status);
147 plog(XLOG_ERROR, "yp enumeration of %s: %s, status=%d, e=%d",
148 ncdp->ncd_map, yperr_string(e), status, e);
150 return TRUE;
156 nis_reload(mnt_map *m, char *map, void (*fn) (mnt_map *, char *, char *))
158 int error;
159 struct nis_callback_data data;
160 struct ypall_callback cbinfo;
162 if (!gopt.nis_domain) {
163 error = determine_nis_domain();
164 if (error)
165 return error;
167 data.ncd_m = m;
168 data.ncd_map = map;
169 data.ncd_fn = fn;
170 cbinfo.data = (voidp) &data;
171 cbinfo.foreach = (ypall_callback_fxn_t) callback;
174 * If you are using NIS and your yp_all function is "broken", you have to
175 * get it fixed. The bug in yp_all() is that it does not close a TCP
176 * connection to ypserv, and this ypserv runs out of open file descriptors,
177 * getting into an infinite loop, thus all YP clients eventually unbind
178 * and hang too.
180 error = yp_all(gopt.nis_domain, map, &cbinfo);
182 if (error)
183 plog(XLOG_ERROR, "error grabbing nis map of %s: %s", map, yperr_string(ypprot_err(error)));
184 return error;
189 * Check if NIS is up, so we can determine if to clear the map or not.
190 * Test it by checking the yp order.
191 * Returns: 0 if NIS is down, 1 if it is up.
194 nis_isup(mnt_map *m, char *map)
196 YP_ORDER_OUTORDER_TYPE order;
197 int error;
198 char *master;
199 static int last_status = 1; /* assume up by default */
201 switch (has_yp_order) {
202 case 1:
204 * NIS server with yp_order
206 error = yp_order(gopt.nis_domain, map, &order);
207 if (error != 0) {
208 plog(XLOG_ERROR,
209 "nis_isup: error getting the order of map %s: %s",
210 map, yperr_string(ypprot_err(error)));
211 last_status = 0;
212 return 0; /* NIS is down */
214 break;
216 case 0:
218 * NIS+ server without yp_order
220 error = yp_master(gopt.nis_domain, map, &master);
221 if (error != 0) {
222 plog(XLOG_ERROR,
223 "nis_isup: error getting the master of map %s: %s",
224 map, yperr_string(ypprot_err(error)));
225 last_status = 0;
226 return 0; /* NIS+ is down */
228 break;
230 default:
232 * server was down
234 last_status = 0;
237 if (last_status == 0) { /* reinitialize if was down before */
238 time_t dummy;
239 error = nis_init(m, map, &dummy);
240 if (error)
241 return 0; /* still down */
242 plog(XLOG_INFO, "nis_isup: NIS came back up for map %s", map);
243 last_status = 1;
245 return 1; /* NIS is up */
250 * Try to locate a key using NIS.
253 nis_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
255 int outlen;
256 int res;
257 YP_ORDER_OUTORDER_TYPE order;
260 * Make sure domain initialized
262 if (!gopt.nis_domain) {
263 int error = determine_nis_domain();
264 if (error)
265 return error;
269 switch (has_yp_order) {
270 case 1:
272 * NIS server with yp_order
273 * Check if map has changed
275 if (yp_order(gopt.nis_domain, map, &order))
276 return EIO;
277 if ((time_t) order > *tp) {
278 *tp = (time_t) order;
279 return -1;
281 break;
283 case 0:
285 * NIS+ server without yp_order
286 * Check if timeout has expired to invalidate the cache
288 order = time(NULL);
289 if ((time_t)order - *tp > gopt.am_timeo) {
290 *tp = (time_t)order;
291 return(-1);
293 break;
295 default:
297 * server was down
299 if (nis_isup(m, map))
300 return -1;
301 return EIO;
305 * Lookup key
307 res = yp_match(gopt.nis_domain, map, key, strlen(key), pval, &outlen);
308 if (m->cfm && (m->cfm->cfm_flags & CFM_SUN_MAP_SYNTAX) && res == 0) {
309 char *oldval = *pval;
310 *pval = sun_entry2amd(key, oldval);
311 /* We always need to free the output of the yp_match call. */
312 XFREE(oldval);
313 if (*pval == NULL)
314 return -1; /* sun2amd parser error */
318 * Do something interesting with the return code
320 switch (res) {
321 case 0:
322 return 0;
324 case YPERR_KEY:
325 return ENOENT;
327 default:
328 plog(XLOG_ERROR, "nis_search: %s: %s", map, yperr_string(res));
329 return EIO;
335 nis_init(mnt_map *m, char *map, time_t *tp)
337 YP_ORDER_OUTORDER_TYPE order;
338 int yp_order_result;
339 char *master;
341 if (!gopt.nis_domain) {
342 int error = determine_nis_domain();
343 if (error)
344 return error;
348 * To see if the map exists, try to find
349 * a master for it.
351 yp_order_result = yp_order(gopt.nis_domain, map, &order);
352 switch (yp_order_result) {
353 case 0:
354 /* NIS server found */
355 has_yp_order = 1;
356 *tp = (time_t) order;
357 dlog("NIS master for %s@%s has order %lu", map, gopt.nis_domain, (unsigned long) order);
358 break;
359 case YPERR_YPERR:
360 /* NIS+ server found ! */
361 has_yp_order = 0;
362 /* try yp_master() instead */
363 if (yp_master(gopt.nis_domain, map, &master)) {
364 return ENOENT;
365 } else {
366 dlog("NIS master for %s@%s is a NIS+ server", map, gopt.nis_domain);
367 /* Use fake timestamps */
368 *tp = time(NULL);
370 break;
371 default:
372 /* server is down */
373 has_yp_order = -1;
374 return ENOENT;
376 return 0;
381 nis_mtime(mnt_map *m, char *map, time_t *tp)
383 return nis_init(m, map, tp);
387 #ifdef HAVE_BAD_YP_ALL
389 * If you are using NIS and your yp_all function is "broken", use an
390 * alternate code which avoids a bug in yp_all(). The bug in yp_all() is
391 * that it does not close a TCP connection to ypserv, and this ypserv runs
392 * out of open filedescriptors, getting into an infinite loop, thus all YP
393 * clients eventually unbind and hang too.
395 * Systems known to be plagued with this bug:
396 * earlier SunOS 4.x
397 * all irix systems (at this time, up to 6.4 was checked)
399 * -Erez Zadok <ezk@cs.columbia.edu>
400 * -James Tanis <jtt@cs.columbia.edu> */
401 static int
402 am_yp_all(char *indomain, char *inmap, struct ypall_callback *incallback)
404 int i, j;
405 char *outkey, *outval;
406 int outkeylen, outvallen;
407 char *outkey_old;
408 int outkeylen_old;
410 plog(XLOG_INFO, "NIS map %s reloading using am_yp_all", inmap);
412 i = yp_first(indomain, inmap, &outkey, &outkeylen, &outval, &outvallen);
413 if (i) {
414 plog(XLOG_ERROR, "yp_first() returned error: %s\n", yperr_string(i));
416 do {
417 j = (incallback->foreach)(YP_TRUE,
418 outkey,
419 outkeylen,
420 outval,
421 outvallen,
422 incallback->data);
423 if (j != FALSE) /* terminate loop */
424 break;
427 * We have to manually free all char ** arguments to yp_first/yp_next
428 * outval must be freed *before* calling yp_next again, outkey can be
429 * freed as outkey_old *after* the call (this saves one call to
430 * strnsave).
432 XFREE(outval);
433 outkey_old = outkey;
434 outkeylen_old = outkeylen;
435 i = yp_next(indomain,
436 inmap,
437 outkey_old,
438 outkeylen_old,
439 &outkey,
440 &outkeylen,
441 &outval,
442 &outvallen);
443 XFREE(outkey_old);
444 } while (!i);
445 if (i) {
446 dlog("yp_next() returned error: %s\n", yperr_string(i));
448 if (i == YPERR_NOMORE)
449 return 0;
450 return i;
452 #endif /* HAVE_BAD_YP_ALL */