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
determine_nis_domain(void)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
callback(int status,char * key,int kl,char * val,int vl,char * data)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
nis_reload(mnt_map * m,char * map,void (* fn)(mnt_map *,char *,char *))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
nis_isup(mnt_map * m,char * map)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
nis_search(mnt_map * m,char * map,char * key,char ** pval,time_t * tp)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
nis_init(mnt_map * m,char * map,time_t * tp)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
nis_mtime(mnt_map * m,char * map,time_t * tp)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@cs.columbia.edu>
397 * -James Tanis <jtt@cs.columbia.edu> */
398 static int
am_yp_all(char * indomain,char * inmap,struct ypall_callback * incallback)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