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 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 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 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 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 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 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 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 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