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 2005 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 int 171 loadmaster_nis(mapname, defopts, stack, stkptr) 172 char *mapname, *defopts; 173 char **stack; 174 char ***stkptr; 175 { 176 int first, err; 177 char *key, *nkey, *val; 178 int kl, nkl, vl; 179 char dir[256], map[256], qbuff[256]; 180 char *pmap, *opts, *my_mapname; 181 int count = 0; 182 183 first = 1; 184 key = NULL; kl = 0; 185 nkey = NULL; nkl = 0; 186 val = NULL; vl = 0; 187 188 /* 189 * need a private copy of mapname, because we may change 190 * the underscores by dots. We however do not want the 191 * orignal to be changed, as we may want to use the 192 * original name in some other name service 193 */ 194 my_mapname = strdup(mapname); 195 if (my_mapname == NULL) { 196 syslog(LOG_ERR, "loadmaster_yp: memory alloc failed: %m"); 197 /* not the name svc's fault but ... */ 198 return (__NSW_UNAVAIL); 199 } 200 for (;;) { 201 if (first) { 202 first = 0; 203 err = yp_first(nis_mydomain, my_mapname, 204 &nkey, &nkl, &val, &vl); 205 206 if ((err == YPERR_MAP) && 207 (replace_undscr_by_dot(my_mapname))) 208 err = yp_first(nis_mydomain, my_mapname, 209 &nkey, &nkl, &val, &vl); 210 211 if ((err == YPERR_DOMAIN) || (err == YPERR_YPBIND)) { 212 syslog(LOG_ERR, 213 "can't read nis map %s: %s - retrying", 214 my_mapname, yperr_string(err)); 215 while ((err == YPERR_DOMAIN) || 216 (err == YPERR_YPBIND)) { 217 (void) sleep(20); 218 err = yp_first(nis_mydomain, my_mapname, 219 &nkey, &nkl, &val, &vl); 220 } 221 syslog(LOG_ERR, 222 "nis map %s: read OK.", my_mapname); 223 } 224 } else { 225 err = yp_next(nis_mydomain, my_mapname, key, kl, 226 &nkey, &nkl, &val, &vl); 227 } 228 if (err) { 229 if (err != YPERR_NOMORE && err != YPERR_MAP) 230 if (verbose) 231 syslog(LOG_ERR, "%s: %s", 232 my_mapname, yperr_string(err)); 233 break; 234 } 235 if (key) 236 free(key); 237 key = nkey; 238 kl = nkl; 239 240 241 if (kl >= 256 || vl >= 256) 242 break; 243 if (kl < 2 || vl < 1) 244 break; 245 if (isspace(*key) || *key == '#') 246 break; 247 (void) strncpy(dir, key, kl); 248 dir[kl] = '\0'; 249 if (macro_expand("", dir, qbuff, sizeof (dir))) { 250 syslog(LOG_ERR, 251 "%s in NIS map %s: entry too long (max %d chars)", 252 dir, my_mapname, sizeof (dir) - 1); 253 break; 254 } 255 (void) strncpy(map, val, vl); 256 map[vl] = '\0'; 257 if (macro_expand(dir, map, qbuff, sizeof (map))) { 258 syslog(LOG_ERR, 259 "%s in NIS map %s: entry too long (max %d chars)", 260 map, my_mapname, sizeof (map) - 1); 261 break; 262 } 263 pmap = map; 264 while (*pmap && isspace(*pmap)) 265 pmap++; /* skip blanks in front of map */ 266 opts = pmap; 267 while (*opts && !isspace(*opts)) 268 opts++; 269 if (*opts) { 270 *opts++ = '\0'; 271 while (*opts && isspace(*opts)) 272 opts++; 273 if (*opts == '-') 274 opts++; 275 else 276 opts = defopts; 277 } 278 free(val); 279 280 /* 281 * Check for no embedded blanks. 282 */ 283 if (strcspn(opts, " ") == strlen(opts)) { 284 dirinit(dir, pmap, opts, 0, stack, stkptr); 285 count++; 286 } else { 287 pr_msg("Warning: invalid entry for %s in NIS map %s ignored.\n", dir, mapname); 288 } 289 290 } 291 if (my_mapname) 292 free(my_mapname); 293 294 /* 295 * In the context of a master map, if no entry is 296 * found, it is like NOTFOUND 297 */ 298 if (count > 0 && err == YPERR_NOMORE) 299 return (__NSW_SUCCESS); 300 else { 301 if (err) 302 return (nis_err(err)); 303 else 304 /* 305 * This case will happen if map is empty 306 * or none of the entries is valid 307 */ 308 return (__NSW_NOTFOUND); 309 } 310 } 311 312 int 313 loaddirect_nis(nismap, localmap, opts, stack, stkptr) 314 char *nismap, *localmap, *opts; 315 char **stack; 316 char ***stkptr; 317 { 318 int first, err, count; 319 char *key, *nkey, *val, *my_nismap; 320 int kl, nkl, vl; 321 char dir[100]; 322 323 first = 1; 324 key = NULL; kl = 0; 325 nkey = NULL; nkl = 0; 326 val = NULL; vl = 0; 327 count = 0; 328 my_nismap = NULL; 329 330 my_nismap = strdup(nismap); 331 if (my_nismap == NULL) { 332 syslog(LOG_ERR, "loadmaster_yp: memory alloc failed: %m"); 333 return (__NSW_UNAVAIL); 334 } 335 for (;;) { 336 if (first) { 337 first = 0; 338 err = yp_first(nis_mydomain, my_nismap, &nkey, &nkl, 339 &val, &vl); 340 341 if ((err == YPERR_MAP) && 342 (replace_undscr_by_dot(my_nismap))) 343 err = yp_first(nis_mydomain, my_nismap, 344 &nkey, &nkl, &val, &vl); 345 346 if ((err == YPERR_DOMAIN) || (err == YPERR_YPBIND)) { 347 syslog(LOG_ERR, 348 "can't read nis map %s: %s - retrying", 349 my_nismap, yperr_string(err)); 350 while ((err == YPERR_DOMAIN) || 351 (err == YPERR_YPBIND)) { 352 (void) sleep(20); 353 err = yp_first(nis_mydomain, my_nismap, 354 &nkey, &nkl, &val, &vl); 355 } 356 syslog(LOG_ERR, 357 "nis map %s: read OK.", my_nismap); 358 } 359 } else { 360 err = yp_next(nis_mydomain, my_nismap, key, kl, 361 &nkey, &nkl, &val, &vl); 362 } 363 if (err) { 364 if (err != YPERR_NOMORE && err != YPERR_MAP) 365 syslog(LOG_ERR, "%s: %s", 366 my_nismap, yperr_string(err)); 367 break; 368 } 369 if (key) 370 free(key); 371 key = nkey; 372 kl = nkl; 373 374 if (kl < 2 || kl >= 100) 375 continue; 376 if (isspace(*key) || *key == '#') 377 continue; 378 (void) strncpy(dir, key, kl); 379 dir[kl] = '\0'; 380 381 dirinit(dir, localmap, opts, 1, stack, stkptr); 382 count++; 383 free(val); 384 } 385 386 if (my_nismap) 387 free(my_nismap); 388 389 if (count > 0 && err == YPERR_NOMORE) 390 return (__NSW_SUCCESS); 391 else 392 return (nis_err(err)); 393 394 } 395 396 static int 397 replace_undscr_by_dot(map) 398 char *map; 399 { 400 int ret_val = 0; 401 402 while (*map) { 403 if (*map == '_') { 404 ret_val = 1; 405 *map = '.'; 406 } 407 map++; 408 } 409 return (ret_val); 410 } 411 412 static int 413 nis_err(err) 414 int err; 415 { 416 switch (err) { 417 case 0: 418 return (__NSW_SUCCESS); 419 case YPERR_KEY: 420 return (__NSW_NOTFOUND); 421 case YPERR_MAP: 422 return (__NSW_UNAVAIL); 423 default: 424 return (__NSW_UNAVAIL); 425 } 426 } 427 428 int 429 getmapkeys_nis(nsmap, list, error, cache_time, stack, stkptr) 430 char *nsmap; 431 struct dir_entry **list; 432 int *error; 433 int *cache_time; 434 char **stack; 435 char ***stkptr; 436 { 437 int nserr; 438 struct dir_cbdata readdir_cbdata; 439 struct ypall_callback cback; 440 char *my_map = NULL; 441 442 char *key = NULL, *val = NULL; 443 int nkl, vl; 444 445 #ifdef lint 446 stack = stack; 447 stkptr = stkptr; 448 #endif /* lint */ 449 450 *cache_time = RDDIR_CACHE_TIME; 451 452 /* 453 * XXX Hack to determine if we need to replace '_' with '.' 454 * Have to use yp_first() since yp_all() simply fails if 455 * the map is not present 456 */ 457 my_map = strdup(nsmap); 458 if (my_map == NULL) { 459 syslog(LOG_ERR, 460 "getmapkeys_nis: memory alloc failed: %m"); 461 *error = ENOMEM; 462 return (__NSW_UNAVAIL); 463 } 464 nserr = yp_first(nis_mydomain, my_map, &key, &nkl, &val, &vl); 465 if (nserr == YPERR_MAP) { 466 if (replace_undscr_by_dot(my_map)) { 467 nserr = yp_first(nis_mydomain, my_map, 468 &key, &nkl, &val, &vl); 469 } 470 if (nserr == YPERR_MAP) { 471 /* 472 * map not found 473 */ 474 *error = 0; /* return an empty list */ 475 if (verbose) { 476 syslog(LOG_ERR, "%s: %s", 477 nsmap, yperr_string(nserr)); 478 } 479 free(my_map); 480 return (nis_err(nserr)); 481 } 482 if (key) 483 free(key); 484 if (val) 485 free(val); 486 } 487 488 readdir_cbdata.list = list; 489 readdir_cbdata.last = NULL; 490 readdir_cbdata.error = 0; 491 492 cback.foreach = readdir_callback; 493 cback.data = (char *)&readdir_cbdata; 494 495 /* 496 * after all this song and dance we finally 497 * ask for the list of entries 498 */ 499 nserr = yp_all(nis_mydomain, my_map, &cback); 500 501 free(my_map); 502 *error = readdir_cbdata.error; 503 if (nserr) { 504 if (verbose) 505 syslog(LOG_ERR, "%s: %s", nsmap, yperr_string(nserr)); 506 nserr = 1; 507 if (*error == 0) 508 *error = ENOENT; 509 510 return (nis_err(nserr)); 511 } 512 513 return (__NSW_SUCCESS); 514 } 515 516 static int 517 readdir_callback(instatus, inkey, inkeylen, inval, invallen, indata) 518 int instatus; 519 char *inkey; 520 int inkeylen; 521 const char *inval; 522 int invallen; 523 struct dir_cbdata *indata; 524 { 525 struct dir_entry **list = indata->list; 526 struct dir_entry *last = indata->last; 527 char key[MAXPATHLEN]; 528 529 #ifdef lint 530 inval = inval; 531 invallen = invallen; 532 #endif 533 534 if (instatus != YP_TRUE) 535 return (0); /* next entry. yp_all may decide otherwise... */ 536 537 if (inkeylen == 0 || isspace(*inkey) || *inkey == '#') 538 return (0); 539 540 /* 541 * yp_all allocates inkey with two extra bytes which contain 542 * NEWLINE and null but these two bytes are not reflected in 543 * inkeylen. 544 */ 545 strncpy(key, inkey, inkeylen); 546 key[inkeylen] = '\0'; 547 548 /* 549 * Wildcard entry should be ignored - following entries should continue 550 * to be read to corroborate with the way we search for entries in yp, 551 * i.e., first for an exact key match and then a wildcard, if there's 552 * no exact key match. 553 */ 554 if (key[0] == '*' && key[1] == '\0') 555 return (0); 556 557 if (add_dir_entry(key, list, &last)) { 558 indata->error = ENOMEM; 559 return (1); /* get no more entries */ 560 } 561 562 indata->last = last; 563 indata->error = 0; 564 565 return (0); 566 } 567