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 2006 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #pragma ident "%Z%%M% %I% %E% SMI" 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <syslog.h> 34 #include <string.h> 35 #include <ctype.h> 36 #include <nsswitch.h> 37 #include <sys/param.h> 38 #include <sys/types.h> 39 #include <sys/systeminfo.h> 40 #include <rpc/rpc.h> 41 #include <rpcsvc/nfs_prot.h> 42 #include <rpcsvc/ypclnt.h> 43 #include <rpcsvc/yp_prot.h> 44 #include <sys/errno.h> 45 #include "automount.h" 46 47 #define KEY 0 48 #define CONTENTS 1 49 50 static int replace_undscr_by_dot(char *); 51 static int nis_err(int); 52 53 static char nis_mydomain[YPMAXDOMAIN]; 54 55 struct dir_cbdata { 56 struct dir_entry **list; 57 struct dir_entry *last; 58 int error; 59 }; 60 61 static int readdir_callback(int, char *, int, const char *, 62 int, struct dir_cbdata *); 63 64 void 65 init_nis(char **stack, char ***stkptr) 66 { 67 #ifdef lint 68 stack = stack; 69 stkptr = stkptr; 70 #endif /* lint */ 71 72 (void) sysinfo(SI_SRPC_DOMAIN, nis_mydomain, sizeof (nis_mydomain)); 73 (void) __nis_reset_state(); /* XXX temporary hack for csh bug */ 74 } 75 76 /*ARGSUSED*/ 77 int 78 getmapent_nis(key, map, ml, stack, stkptr, iswildcard, isrestricted) 79 char *key, *map; 80 struct mapline *ml; 81 char **stack; 82 char ***stkptr; 83 bool_t *iswildcard; 84 bool_t isrestricted; 85 { 86 char *nisline = NULL; 87 char *my_map = NULL; 88 char *lp, *lq; 89 int nislen, len; 90 int nserr; 91 92 if (iswildcard) 93 *iswildcard = FALSE; 94 nserr = yp_match(nis_mydomain, map, key, strlen(key), 95 &nisline, &nislen); 96 if (nserr == YPERR_MAP) { 97 my_map = strdup(map); 98 if (my_map == NULL) { 99 syslog(LOG_ERR, 100 "getmapent_nis: memory alloc failed: %m"); 101 return (__NSW_UNAVAIL); 102 } 103 if (replace_undscr_by_dot(my_map)) 104 nserr = yp_match(nis_mydomain, my_map, key, 105 strlen(key), &nisline, &nislen); 106 } 107 108 if (nserr) { 109 if (nserr == YPERR_KEY) { 110 /* 111 * Try the default entry "*" 112 */ 113 if (my_map == NULL) 114 nserr = yp_match(nis_mydomain, map, "*", 1, 115 &nisline, &nislen); 116 else 117 nserr = yp_match(nis_mydomain, my_map, "*", 1, 118 &nisline, &nislen); 119 if (!nserr && iswildcard) 120 *iswildcard = TRUE; 121 } else { 122 if (verbose) 123 syslog(LOG_ERR, "%s: %s", 124 map, yperr_string(nserr)); 125 nserr = 1; 126 } 127 } 128 if (my_map != NULL) 129 free(my_map); 130 131 nserr = nis_err(nserr); 132 if (nserr) 133 goto done; 134 135 /* 136 * at this point we are sure that yp_match succeeded 137 * so massage the entry by 138 * 1. ignoring # and beyond 139 * 2. trim the trailing whitespace 140 */ 141 if (lp = strchr(nisline, '#')) 142 *lp = '\0'; 143 len = strlen(nisline); 144 if (len == 0) { 145 nserr = __NSW_NOTFOUND; 146 goto done; 147 } 148 lp = &nisline[len - 1]; 149 while (lp > nisline && isspace(*lp)) 150 *lp-- = '\0'; 151 if (lp == nisline) { 152 nserr = __NSW_NOTFOUND; 153 goto done; 154 } 155 (void) strcpy(ml->linebuf, nisline); 156 lp = ml->linebuf; 157 lq = ml->lineqbuf; 158 unquote(lp, lq); 159 /* now we have the correct line */ 160 161 nserr = __NSW_SUCCESS; 162 done: 163 if (nisline) 164 free((char *)nisline); 165 return (nserr); 166 167 } 168 169 int 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 int 312 loaddirect_nis(nismap, localmap, opts, stack, stkptr) 313 char *nismap, *localmap, *opts; 314 char **stack; 315 char ***stkptr; 316 { 317 int first, err, count; 318 char *key, *nkey, *val, *my_nismap; 319 int kl, nkl, vl; 320 char dir[100]; 321 322 first = 1; 323 key = NULL; kl = 0; 324 nkey = NULL; nkl = 0; 325 val = NULL; vl = 0; 326 count = 0; 327 my_nismap = NULL; 328 329 my_nismap = strdup(nismap); 330 if (my_nismap == NULL) { 331 syslog(LOG_ERR, "loadmaster_yp: memory alloc failed: %m"); 332 return (__NSW_UNAVAIL); 333 } 334 for (;;) { 335 if (first) { 336 first = 0; 337 err = yp_first(nis_mydomain, my_nismap, &nkey, &nkl, 338 &val, &vl); 339 340 if ((err == YPERR_MAP) && 341 (replace_undscr_by_dot(my_nismap))) 342 err = yp_first(nis_mydomain, my_nismap, 343 &nkey, &nkl, &val, &vl); 344 345 if ((err == YPERR_DOMAIN) || (err == YPERR_YPBIND)) { 346 syslog(LOG_ERR, 347 "can't read nis map %s: %s - retrying", 348 my_nismap, yperr_string(err)); 349 while ((err == YPERR_DOMAIN) || 350 (err == YPERR_YPBIND)) { 351 (void) sleep(20); 352 err = yp_first(nis_mydomain, my_nismap, 353 &nkey, &nkl, &val, &vl); 354 } 355 syslog(LOG_ERR, 356 "nis map %s: read OK.", my_nismap); 357 } 358 } else { 359 err = yp_next(nis_mydomain, my_nismap, key, kl, 360 &nkey, &nkl, &val, &vl); 361 } 362 if (err) { 363 if (err != YPERR_NOMORE && err != YPERR_MAP) 364 syslog(LOG_ERR, "%s: %s", 365 my_nismap, yperr_string(err)); 366 break; 367 } 368 if (key) 369 free(key); 370 key = nkey; 371 kl = nkl; 372 373 if (kl < 2 || kl >= 100) 374 continue; 375 if (isspace(*key) || *key == '#') 376 continue; 377 (void) strncpy(dir, key, kl); 378 dir[kl] = '\0'; 379 380 dirinit(dir, localmap, opts, 1, stack, stkptr); 381 count++; 382 free(val); 383 } 384 385 if (my_nismap) 386 free(my_nismap); 387 388 if (count > 0 && err == YPERR_NOMORE) 389 return (__NSW_SUCCESS); 390 else 391 return (nis_err(err)); 392 393 } 394 395 static int 396 replace_undscr_by_dot(map) 397 char *map; 398 { 399 int ret_val = 0; 400 401 while (*map) { 402 if (*map == '_') { 403 ret_val = 1; 404 *map = '.'; 405 } 406 map++; 407 } 408 return (ret_val); 409 } 410 411 static int 412 nis_err(err) 413 int err; 414 { 415 switch (err) { 416 case 0: 417 return (__NSW_SUCCESS); 418 case YPERR_KEY: 419 return (__NSW_NOTFOUND); 420 case YPERR_MAP: 421 return (__NSW_UNAVAIL); 422 default: 423 return (__NSW_UNAVAIL); 424 } 425 } 426 427 int 428 getmapkeys_nis(nsmap, list, error, cache_time, stack, stkptr) 429 char *nsmap; 430 struct dir_entry **list; 431 int *error; 432 int *cache_time; 433 char **stack; 434 char ***stkptr; 435 { 436 int nserr; 437 struct dir_cbdata readdir_cbdata; 438 struct ypall_callback cback; 439 char *my_map = NULL; 440 441 char *key = NULL, *val = NULL; 442 int nkl, vl; 443 444 #ifdef lint 445 stack = stack; 446 stkptr = stkptr; 447 #endif /* lint */ 448 449 *cache_time = RDDIR_CACHE_TIME; 450 451 /* 452 * XXX Hack to determine if we need to replace '_' with '.' 453 * Have to use yp_first() since yp_all() simply fails if 454 * the map is not present 455 */ 456 my_map = strdup(nsmap); 457 if (my_map == NULL) { 458 syslog(LOG_ERR, 459 "getmapkeys_nis: memory alloc failed: %m"); 460 *error = ENOMEM; 461 return (__NSW_UNAVAIL); 462 } 463 nserr = yp_first(nis_mydomain, my_map, &key, &nkl, &val, &vl); 464 if (nserr == YPERR_MAP) { 465 if (replace_undscr_by_dot(my_map)) { 466 nserr = yp_first(nis_mydomain, my_map, 467 &key, &nkl, &val, &vl); 468 } 469 if (nserr == YPERR_MAP) { 470 /* 471 * map not found 472 */ 473 *error = 0; /* return an empty list */ 474 if (verbose) { 475 syslog(LOG_ERR, "%s: %s", 476 nsmap, yperr_string(nserr)); 477 } 478 free(my_map); 479 return (nis_err(nserr)); 480 } 481 } 482 if (key) 483 free(key); 484 if (val) 485 free(val); 486 487 readdir_cbdata.list = list; 488 readdir_cbdata.last = NULL; 489 readdir_cbdata.error = 0; 490 491 cback.foreach = readdir_callback; 492 cback.data = (char *)&readdir_cbdata; 493 494 /* 495 * after all this song and dance we finally 496 * ask for the list of entries 497 */ 498 nserr = yp_all(nis_mydomain, my_map, &cback); 499 500 free(my_map); 501 *error = readdir_cbdata.error; 502 if (nserr) { 503 if (verbose) 504 syslog(LOG_ERR, "%s: %s", nsmap, yperr_string(nserr)); 505 nserr = 1; 506 if (*error == 0) 507 *error = ENOENT; 508 509 return (nis_err(nserr)); 510 } 511 512 return (__NSW_SUCCESS); 513 } 514 515 static int 516 readdir_callback(instatus, inkey, inkeylen, inval, invallen, indata) 517 int instatus; 518 char *inkey; 519 int inkeylen; 520 const char *inval; 521 int invallen; 522 struct dir_cbdata *indata; 523 { 524 struct dir_entry **list = indata->list; 525 struct dir_entry *last = indata->last; 526 char key[MAXPATHLEN]; 527 528 #ifdef lint 529 inval = inval; 530 invallen = invallen; 531 #endif 532 533 if (instatus != YP_TRUE) 534 return (0); /* next entry. yp_all may decide otherwise... */ 535 536 if (inkeylen == 0 || isspace(*inkey) || *inkey == '#') 537 return (0); 538 539 /* 540 * yp_all allocates inkey with two extra bytes which contain 541 * NEWLINE and null but these two bytes are not reflected in 542 * inkeylen. 543 */ 544 strncpy(key, inkey, inkeylen); 545 key[inkeylen] = '\0'; 546 547 /* 548 * Wildcard entry should be ignored - following entries should continue 549 * to be read to corroborate with the way we search for entries in yp, 550 * i.e., first for an exact key match and then a wildcard, if there's 551 * no exact key match. 552 */ 553 if (key[0] == '*' && key[1] == '\0') 554 return (0); 555 556 if (add_dir_entry(key, list, &last)) { 557 indata->error = ENOMEM; 558 return (1); /* get no more entries */ 559 } 560 561 indata->last = last; 562 indata->error = 0; 563 564 return (0); 565 } 566