1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * ns_nis.c
23 *
24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <syslog.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <nsswitch.h>
35 #include <sys/param.h>
36 #include <sys/types.h>
37 #include <sys/systeminfo.h>
38 #include <rpc/rpc.h>
39 #include <rpcsvc/nfs_prot.h>
40 #include <rpcsvc/ypclnt.h>
41 #include <rpcsvc/yp_prot.h>
42 #include <sys/errno.h>
43 #include "automount.h"
44
45 #define KEY 0
46 #define CONTENTS 1
47
48 static int replace_undscr_by_dot(char *);
49 static int nis_err(int);
50
51 static char nis_mydomain[YPMAXDOMAIN];
52
53 struct dir_cbdata {
54 struct dir_entry **list;
55 struct dir_entry *last;
56 int error;
57 };
58
59 static int readdir_callback(int, char *, int, const char *,
60 int, struct dir_cbdata *);
61
62 void
init_nis(char ** stack,char *** stkptr)63 init_nis(char **stack, char ***stkptr)
64 {
65 #ifdef lint
66 stack = stack;
67 stkptr = stkptr;
68 #endif /* lint */
69
70 (void) sysinfo(SI_SRPC_DOMAIN, nis_mydomain, sizeof (nis_mydomain));
71 }
72
73 /*ARGSUSED*/
74 int
getmapent_nis(key,map,ml,stack,stkptr,iswildcard,isrestricted)75 getmapent_nis(key, map, ml, stack, stkptr, iswildcard, isrestricted)
76 char *key, *map;
77 struct mapline *ml;
78 char **stack;
79 char ***stkptr;
80 bool_t *iswildcard;
81 bool_t isrestricted;
82 {
83 char *nisline = NULL;
84 char *my_map = NULL;
85 char *lp, *lq;
86 int nislen, len;
87 int nserr;
88
89 if (iswildcard)
90 *iswildcard = FALSE;
91 nserr = yp_match(nis_mydomain, map, key, strlen(key),
92 &nisline, &nislen);
93 if (nserr == YPERR_MAP) {
94 my_map = strdup(map);
95 if (my_map == NULL) {
96 syslog(LOG_ERR,
97 "getmapent_nis: memory alloc failed: %m");
98 return (__NSW_UNAVAIL);
99 }
100 if (replace_undscr_by_dot(my_map))
101 nserr = yp_match(nis_mydomain, my_map, key,
102 strlen(key), &nisline, &nislen);
103 }
104
105 if (nserr) {
106 if (nserr == YPERR_KEY) {
107 /*
108 * Try the default entry "*"
109 */
110 if (my_map == NULL)
111 nserr = yp_match(nis_mydomain, map, "*", 1,
112 &nisline, &nislen);
113 else
114 nserr = yp_match(nis_mydomain, my_map, "*", 1,
115 &nisline, &nislen);
116 if (!nserr && iswildcard)
117 *iswildcard = TRUE;
118 } else {
119 if (verbose)
120 syslog(LOG_ERR, "%s: %s",
121 map, yperr_string(nserr));
122 nserr = 1;
123 }
124 }
125 if (my_map != NULL)
126 free(my_map);
127
128 nserr = nis_err(nserr);
129 if (nserr)
130 goto done;
131
132 /*
133 * at this point we are sure that yp_match succeeded
134 * so massage the entry by
135 * 1. ignoring # and beyond
136 * 2. trim the trailing whitespace
137 */
138 if (lp = strchr(nisline, '#'))
139 *lp = '\0';
140 len = strlen(nisline);
141 if (len == 0) {
142 nserr = __NSW_NOTFOUND;
143 goto done;
144 }
145 lp = &nisline[len - 1];
146 while (lp > nisline && isspace(*lp))
147 *lp-- = '\0';
148 if (lp == nisline) {
149 nserr = __NSW_NOTFOUND;
150 goto done;
151 }
152 (void) strcpy(ml->linebuf, nisline);
153 lp = ml->linebuf;
154 lq = ml->lineqbuf;
155 unquote(lp, lq);
156 /* now we have the correct line */
157
158 nserr = __NSW_SUCCESS;
159 done:
160 if (nisline)
161 free((char *)nisline);
162 return (nserr);
163
164 }
165
166 int
loadmaster_nis(mapname,defopts,stack,stkptr)167 loadmaster_nis(mapname, defopts, stack, stkptr)
168 char *mapname, *defopts;
169 char **stack;
170 char ***stkptr;
171 {
172 int first, err;
173 char *key, *nkey, *val;
174 int kl, nkl, vl;
175 char dir[256], map[256], qbuff[256];
176 char *pmap, *opts, *my_mapname;
177 int count = 0;
178
179 first = 1;
180 key = NULL; kl = 0;
181 nkey = NULL; nkl = 0;
182 val = NULL; vl = 0;
183
184 /*
185 * need a private copy of mapname, because we may change
186 * the underscores by dots. We however do not want the
187 * orignal to be changed, as we may want to use the
188 * original name in some other name service
189 */
190 my_mapname = strdup(mapname);
191 if (my_mapname == NULL) {
192 syslog(LOG_ERR, "loadmaster_yp: memory alloc failed: %m");
193 /* not the name svc's fault but ... */
194 return (__NSW_UNAVAIL);
195 }
196 for (;;) {
197 if (first) {
198 first = 0;
199 err = yp_first(nis_mydomain, my_mapname,
200 &nkey, &nkl, &val, &vl);
201
202 if ((err == YPERR_MAP) &&
203 (replace_undscr_by_dot(my_mapname)))
204 err = yp_first(nis_mydomain, my_mapname,
205 &nkey, &nkl, &val, &vl);
206
207 if ((err == YPERR_DOMAIN) || (err == YPERR_YPBIND)) {
208 syslog(LOG_ERR,
209 "can't read nis map %s: %s - retrying",
210 my_mapname, yperr_string(err));
211 while ((err == YPERR_DOMAIN) ||
212 (err == YPERR_YPBIND)) {
213 (void) sleep(20);
214 err = yp_first(nis_mydomain, my_mapname,
215 &nkey, &nkl, &val, &vl);
216 }
217 syslog(LOG_ERR,
218 "nis map %s: read OK.", my_mapname);
219 }
220 } else {
221 err = yp_next(nis_mydomain, my_mapname, key, kl,
222 &nkey, &nkl, &val, &vl);
223 }
224 if (err) {
225 if (err != YPERR_NOMORE && err != YPERR_MAP)
226 if (verbose)
227 syslog(LOG_ERR, "%s: %s",
228 my_mapname, yperr_string(err));
229 break;
230 }
231 if (key)
232 free(key);
233 key = nkey;
234 kl = nkl;
235
236
237 if (kl >= 256 || vl >= 256)
238 break;
239 if (kl < 2 || vl < 1)
240 break;
241 if (isspace(*key) || *key == '#')
242 break;
243 (void) strncpy(dir, key, kl);
244 dir[kl] = '\0';
245 if (macro_expand("", dir, qbuff, sizeof (dir))) {
246 syslog(LOG_ERR,
247 "%s in NIS map %s: entry too long (max %d chars)",
248 dir, my_mapname, sizeof (dir) - 1);
249 break;
250 }
251 (void) strncpy(map, val, vl);
252 map[vl] = '\0';
253 if (macro_expand(dir, map, qbuff, sizeof (map))) {
254 syslog(LOG_ERR,
255 "%s in NIS map %s: entry too long (max %d chars)",
256 map, my_mapname, sizeof (map) - 1);
257 break;
258 }
259 pmap = map;
260 while (*pmap && isspace(*pmap))
261 pmap++; /* skip blanks in front of map */
262 opts = pmap;
263 while (*opts && !isspace(*opts))
264 opts++;
265 if (*opts) {
266 *opts++ = '\0';
267 while (*opts && isspace(*opts))
268 opts++;
269 if (*opts == '-')
270 opts++;
271 else
272 opts = defopts;
273 }
274 free(val);
275
276 /*
277 * Check for no embedded blanks.
278 */
279 if (strcspn(opts, " ") == strlen(opts)) {
280 dirinit(dir, pmap, opts, 0, stack, stkptr);
281 count++;
282 } else {
283 pr_msg("Warning: invalid entry for %s in NIS map %s ignored.\n", dir, mapname);
284 }
285
286 }
287 if (my_mapname)
288 free(my_mapname);
289
290 /*
291 * In the context of a master map, if no entry is
292 * found, it is like NOTFOUND
293 */
294 if (count > 0 && err == YPERR_NOMORE)
295 return (__NSW_SUCCESS);
296 else {
297 if (err)
298 return (nis_err(err));
299 else
300 /*
301 * This case will happen if map is empty
302 * or none of the entries is valid
303 */
304 return (__NSW_NOTFOUND);
305 }
306 }
307
308 int
loaddirect_nis(nismap,localmap,opts,stack,stkptr)309 loaddirect_nis(nismap, localmap, opts, stack, stkptr)
310 char *nismap, *localmap, *opts;
311 char **stack;
312 char ***stkptr;
313 {
314 int first, err, count;
315 char *key, *nkey, *val, *my_nismap;
316 int kl, nkl, vl;
317 char dir[100];
318
319 first = 1;
320 key = NULL; kl = 0;
321 nkey = NULL; nkl = 0;
322 val = NULL; vl = 0;
323 count = 0;
324 my_nismap = NULL;
325
326 my_nismap = strdup(nismap);
327 if (my_nismap == NULL) {
328 syslog(LOG_ERR, "loadmaster_yp: memory alloc failed: %m");
329 return (__NSW_UNAVAIL);
330 }
331 for (;;) {
332 if (first) {
333 first = 0;
334 err = yp_first(nis_mydomain, my_nismap, &nkey, &nkl,
335 &val, &vl);
336
337 if ((err == YPERR_MAP) &&
338 (replace_undscr_by_dot(my_nismap)))
339 err = yp_first(nis_mydomain, my_nismap,
340 &nkey, &nkl, &val, &vl);
341
342 if ((err == YPERR_DOMAIN) || (err == YPERR_YPBIND)) {
343 syslog(LOG_ERR,
344 "can't read nis map %s: %s - retrying",
345 my_nismap, yperr_string(err));
346 while ((err == YPERR_DOMAIN) ||
347 (err == YPERR_YPBIND)) {
348 (void) sleep(20);
349 err = yp_first(nis_mydomain, my_nismap,
350 &nkey, &nkl, &val, &vl);
351 }
352 syslog(LOG_ERR,
353 "nis map %s: read OK.", my_nismap);
354 }
355 } else {
356 err = yp_next(nis_mydomain, my_nismap, key, kl,
357 &nkey, &nkl, &val, &vl);
358 }
359 if (err) {
360 if (err != YPERR_NOMORE && err != YPERR_MAP)
361 syslog(LOG_ERR, "%s: %s",
362 my_nismap, yperr_string(err));
363 break;
364 }
365 if (key)
366 free(key);
367 key = nkey;
368 kl = nkl;
369
370 if (kl < 2 || kl >= 100)
371 continue;
372 if (isspace(*key) || *key == '#')
373 continue;
374 (void) strncpy(dir, key, kl);
375 dir[kl] = '\0';
376
377 dirinit(dir, localmap, opts, 1, stack, stkptr);
378 count++;
379 free(val);
380 }
381
382 if (my_nismap)
383 free(my_nismap);
384
385 if (count > 0 && err == YPERR_NOMORE)
386 return (__NSW_SUCCESS);
387 else
388 return (nis_err(err));
389
390 }
391
392 static int
replace_undscr_by_dot(map)393 replace_undscr_by_dot(map)
394 char *map;
395 {
396 int ret_val = 0;
397
398 while (*map) {
399 if (*map == '_') {
400 ret_val = 1;
401 *map = '.';
402 }
403 map++;
404 }
405 return (ret_val);
406 }
407
408 static int
nis_err(err)409 nis_err(err)
410 int err;
411 {
412 switch (err) {
413 case 0:
414 return (__NSW_SUCCESS);
415 case YPERR_KEY:
416 return (__NSW_NOTFOUND);
417 case YPERR_MAP:
418 return (__NSW_UNAVAIL);
419 default:
420 return (__NSW_UNAVAIL);
421 }
422 }
423
424 int
getmapkeys_nis(nsmap,list,error,cache_time,stack,stkptr)425 getmapkeys_nis(nsmap, list, error, cache_time, stack, stkptr)
426 char *nsmap;
427 struct dir_entry **list;
428 int *error;
429 int *cache_time;
430 char **stack;
431 char ***stkptr;
432 {
433 int nserr;
434 struct dir_cbdata readdir_cbdata;
435 struct ypall_callback cback;
436 char *my_map = NULL;
437
438 char *key = NULL, *val = NULL;
439 int nkl, vl;
440
441 #ifdef lint
442 stack = stack;
443 stkptr = stkptr;
444 #endif /* lint */
445
446 *cache_time = RDDIR_CACHE_TIME;
447
448 /*
449 * XXX Hack to determine if we need to replace '_' with '.'
450 * Have to use yp_first() since yp_all() simply fails if
451 * the map is not present
452 */
453 my_map = strdup(nsmap);
454 if (my_map == NULL) {
455 syslog(LOG_ERR,
456 "getmapkeys_nis: memory alloc failed: %m");
457 *error = ENOMEM;
458 return (__NSW_UNAVAIL);
459 }
460 nserr = yp_first(nis_mydomain, my_map, &key, &nkl, &val, &vl);
461 if (nserr == YPERR_MAP) {
462 if (replace_undscr_by_dot(my_map)) {
463 nserr = yp_first(nis_mydomain, my_map,
464 &key, &nkl, &val, &vl);
465 }
466 if (nserr == YPERR_MAP) {
467 /*
468 * map not found
469 */
470 *error = 0; /* return an empty list */
471 if (verbose) {
472 syslog(LOG_ERR, "%s: %s",
473 nsmap, yperr_string(nserr));
474 }
475 free(my_map);
476 return (nis_err(nserr));
477 }
478 }
479 if (key)
480 free(key);
481 if (val)
482 free(val);
483
484 readdir_cbdata.list = list;
485 readdir_cbdata.last = NULL;
486 readdir_cbdata.error = 0;
487
488 cback.foreach = readdir_callback;
489 cback.data = (char *)&readdir_cbdata;
490
491 /*
492 * after all this song and dance we finally
493 * ask for the list of entries
494 */
495 nserr = yp_all(nis_mydomain, my_map, &cback);
496
497 free(my_map);
498 *error = readdir_cbdata.error;
499 if (nserr) {
500 if (verbose)
501 syslog(LOG_ERR, "%s: %s", nsmap, yperr_string(nserr));
502 nserr = 1;
503 if (*error == 0)
504 *error = ENOENT;
505
506 return (nis_err(nserr));
507 }
508
509 return (__NSW_SUCCESS);
510 }
511
512 static int
readdir_callback(instatus,inkey,inkeylen,inval,invallen,indata)513 readdir_callback(instatus, inkey, inkeylen, inval, invallen, indata)
514 int instatus;
515 char *inkey;
516 int inkeylen;
517 const char *inval;
518 int invallen;
519 struct dir_cbdata *indata;
520 {
521 struct dir_entry **list = indata->list;
522 struct dir_entry *last = indata->last;
523 char key[MAXPATHLEN];
524
525 #ifdef lint
526 inval = inval;
527 invallen = invallen;
528 #endif
529
530 if (instatus != YP_TRUE)
531 return (0); /* next entry. yp_all may decide otherwise... */
532
533 if (inkeylen == 0 || isspace(*inkey) || *inkey == '#')
534 return (0);
535
536 /*
537 * yp_all allocates inkey with two extra bytes which contain
538 * NEWLINE and null but these two bytes are not reflected in
539 * inkeylen.
540 */
541 strncpy(key, inkey, inkeylen);
542 key[inkeylen] = '\0';
543
544 /*
545 * Wildcard entry should be ignored - following entries should continue
546 * to be read to corroborate with the way we search for entries in yp,
547 * i.e., first for an exact key match and then a wildcard, if there's
548 * no exact key match.
549 */
550 if (key[0] == '*' && key[1] == '\0')
551 return (0);
552
553 if (add_dir_entry(key, list, &last)) {
554 indata->error = ENOMEM;
555 return (1); /* get no more entries */
556 }
557
558 indata->last = last;
559 indata->error = 0;
560
561 return (0);
562 }
563