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