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.
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
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
42 * File: am-utils/amd/info_nis.c
47 * Get info from NIS map
52 #endif /* HAVE_CONFIG_H */
59 * NIS+ servers in NIS compat mode don't have yp_order()
61 * has_yp_order = 1 NIS server
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
);
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
{
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
97 determine_nis_domain(void)
99 static int nis_not_running
= 0;
100 char default_domain
[YPMAXDOMAIN
];
105 if (getdomainname(default_domain
, sizeof(default_domain
)) < 0) {
107 plog(XLOG_ERROR
, "getdomainname: %m");
110 if (!*default_domain
) {
112 plog(XLOG_WARNING
, "NIS domain name is not set. NIS ignored.");
115 gopt
.nis_domain
= strdup(default_domain
);
122 * Callback from yp_all
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 ... */
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
);
156 nis_reload(mnt_map
*m
, char *map
, void (*fn
) (mnt_map
*, char *, char *))
159 struct nis_callback_data data
;
160 struct ypall_callback cbinfo
;
162 if (!gopt
.nis_domain
) {
163 error
= determine_nis_domain();
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
180 error
= yp_all(gopt
.nis_domain
, map
, &cbinfo
);
183 plog(XLOG_ERROR
, "error grabbing nis map of %s: %s", map
, yperr_string(ypprot_err(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
;
199 static int last_status
= 1; /* assume up by default */
201 switch (has_yp_order
) {
204 * NIS server with yp_order
206 error
= yp_order(gopt
.nis_domain
, map
, &order
);
209 "nis_isup: error getting the order of map %s: %s",
210 map
, yperr_string(ypprot_err(error
)));
212 return 0; /* NIS is down */
218 * NIS+ server without yp_order
220 error
= yp_master(gopt
.nis_domain
, map
, &master
);
223 "nis_isup: error getting the master of map %s: %s",
224 map
, yperr_string(ypprot_err(error
)));
226 return 0; /* NIS+ is down */
237 if (last_status
== 0) { /* reinitialize if was down before */
239 error
= nis_init(m
, map
, &dummy
);
241 return 0; /* still down */
242 plog(XLOG_INFO
, "nis_isup: NIS came back up for map %s", map
);
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
)
257 YP_ORDER_OUTORDER_TYPE order
;
260 * Make sure domain initialized
262 if (!gopt
.nis_domain
) {
263 int error
= determine_nis_domain();
269 switch (has_yp_order
) {
272 * NIS server with yp_order
273 * Check if map has changed
275 if (yp_order(gopt
.nis_domain
, map
, &order
))
277 if ((time_t) order
> *tp
) {
278 *tp
= (time_t) order
;
285 * NIS+ server without yp_order
286 * Check if timeout has expired to invalidate the cache
289 if ((time_t)order
- *tp
> gopt
.am_timeo
) {
299 if (nis_isup(m
, map
))
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. */
314 return -1; /* sun2amd parser error */
318 * Do something interesting with the return code
328 plog(XLOG_ERROR
, "nis_search: %s: %s", map
, yperr_string(res
));
335 nis_init(mnt_map
*m
, char *map
, time_t *tp
)
337 YP_ORDER_OUTORDER_TYPE order
;
341 if (!gopt
.nis_domain
) {
342 int error
= determine_nis_domain();
348 * To see if the map exists, try to find
351 yp_order_result
= yp_order(gopt
.nis_domain
, map
, &order
);
352 switch (yp_order_result
) {
354 /* NIS server found */
356 *tp
= (time_t) order
;
357 dlog("NIS master for %s@%s has order %lu", map
, gopt
.nis_domain
, (unsigned long) order
);
360 /* NIS+ server found ! */
362 /* try yp_master() instead */
363 if (yp_master(gopt
.nis_domain
, map
, &master
)) {
366 dlog("NIS master for %s@%s is a NIS+ server", map
, gopt
.nis_domain
);
367 /* Use fake timestamps */
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:
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> */
402 am_yp_all(char *indomain
, char *inmap
, struct ypall_callback
*incallback
)
405 char *outkey
, *outval
;
406 int outkeylen
, outvallen
;
410 plog(XLOG_INFO
, "NIS map %s reloading using am_yp_all", inmap
);
412 i
= yp_first(indomain
, inmap
, &outkey
, &outkeylen
, &outval
, &outvallen
);
414 plog(XLOG_ERROR
, "yp_first() returned error: %s\n", yperr_string(i
));
417 j
= (incallback
->foreach
)(YP_TRUE
,
423 if (j
!= FALSE
) /* terminate loop */
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
434 outkeylen_old
= outkeylen
;
435 i
= yp_next(indomain
,
446 dlog("yp_next() returned error: %s\n", yperr_string(i
));
448 if (i
== YPERR_NOMORE
)
452 #endif /* HAVE_BAD_YP_ALL */