1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Rick Macklem at The University of Guelph. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include "namespace.h" 36 37 #include <ctype.h> 38 #include <errno.h> 39 #include <netdb.h> 40 #include <nsswitch.h> 41 #include <pthread.h> 42 #include <pthread_np.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 48 #include "nss_tls.h" 49 50 #ifdef YP 51 /* 52 * Notes: 53 * We want to be able to use NIS netgroups properly while retaining 54 * the ability to use a local /etc/netgroup file. Unfortunately, you 55 * can't really do both at the same time - at least, not efficiently. 56 * NetBSD deals with this problem by creating a netgroup database 57 * using Berkeley DB (just like the password database) that allows 58 * for lookups using netgroup, netgroup.byuser or netgroup.byhost 59 * searches. This is a neat idea, but I don't have time to implement 60 * something like that now. (I think ultimately it would be nice 61 * if we DB-fied the group and netgroup stuff all in one shot, but 62 * for now I'm satisfied just to have something that works well 63 * without requiring massive code changes.) 64 * 65 * Therefore, to still permit the use of the local file and maintain 66 * optimum NIS performance, we allow for the following conditions: 67 * 68 * - If /etc/netgroup does not exist and NIS is turned on, we use 69 * NIS netgroups only. 70 * 71 * - If /etc/netgroup exists but is empty, we use NIS netgroups 72 * only. 73 * 74 * - If /etc/netgroup exists and contains _only_ a '+', we use 75 * NIS netgroups only. 76 * 77 * - If /etc/netgroup exists, contains locally defined netgroups 78 * and a '+', we use a mixture of NIS and the local entries. 79 * This method should return the same NIS data as just using 80 * NIS alone, but it will be slower if the NIS netgroup database 81 * is large (innetgr() in particular will suffer since extra 82 * processing has to be done in order to determine memberships 83 * using just the raw netgroup data). 84 * 85 * - If /etc/netgroup exists and contains only locally defined 86 * netgroup entries, we use just those local entries and ignore 87 * NIS (this is the original, pre-NIS behavior). 88 */ 89 90 #include <rpc/rpc.h> 91 #include <rpcsvc/yp_prot.h> 92 #include <rpcsvc/ypclnt.h> 93 #include <sys/param.h> 94 #include <sys/stat.h> 95 #include <sys/errno.h> 96 static char *_netgr_yp_domain; 97 int _use_only_yp; 98 static int _netgr_yp_enabled; 99 static int _yp_innetgr; 100 #endif 101 102 #ifndef _PATH_NETGROUP 103 #define _PATH_NETGROUP "/etc/netgroup" 104 #endif 105 106 enum constants { 107 NGRP_STORAGE_INITIAL = 1 << 10, /* 1 KByte */ 108 NGRP_STORAGE_MAX = 1 << 20, /* 1 MByte */ 109 }; 110 111 static const ns_src defaultsrc[] = { 112 { NSSRC_COMPAT, NS_SUCCESS }, 113 { NULL, 0 }, 114 }; 115 116 /* 117 * Static Variables and functions used by setnetgrent(), getnetgrent() and 118 * endnetgrent(). 119 * There are two linked lists: 120 * - linelist is just used by setnetgrent() to parse the net group file via. 121 * parse_netgrp() 122 * - netgrp is the list of entries for the current netgroup 123 */ 124 struct linelist { 125 struct linelist *l_next; /* Chain ptr. */ 126 int l_parsed; /* Flag for cycles */ 127 char *l_groupname; /* Name of netgroup */ 128 char *l_line; /* Netgroup entrie(s) to be parsed */ 129 }; 130 131 struct netgrp { 132 struct netgrp *ng_next; /* Chain ptr */ 133 char *ng_str[3]; /* Field pointers, see below */ 134 }; 135 136 struct netgr_state { 137 FILE *st_netf; 138 struct linelist *st_linehead; 139 struct netgrp *st_nextgrp; 140 struct netgrp *st_gr; 141 char *st_grname; 142 }; 143 144 #define NG_HOST 0 /* Host name */ 145 #define NG_USER 1 /* User name */ 146 #define NG_DOM 2 /* and Domain name */ 147 148 static void netgr_endstate(void *); 149 NSS_TLS_HANDLING(netgr); 150 151 static int files_endnetgrent(void *, void *, va_list); 152 static int files_getnetgrent_r(void *, void *, va_list); 153 static int files_setnetgrent(void *, void *, va_list); 154 155 static int compat_endnetgrent(void *, void *, va_list); 156 static int compat_innetgr(void *, void *, va_list); 157 static int compat_getnetgrent_r(void *, void *, va_list); 158 static int compat_setnetgrent(void *, void *, va_list); 159 160 static void _compat_clearstate(void); 161 static int _getnetgrent_r(char **, char **, char **, char *, size_t, int *, 162 struct netgr_state *); 163 static int _innetgr_fallback(void *, void *, const char *, const char *, 164 const char *, const char *); 165 static int innetgr_fallback(void *, void *, va_list); 166 static int parse_netgrp(const char *, struct netgr_state *, int); 167 static struct linelist *read_for_group(const char *, struct netgr_state *, int); 168 169 #define LINSIZ 1024 /* Length of netgroup file line */ 170 171 static const ns_dtab getnetgrent_dtab[] = { 172 NS_FILES_CB(files_getnetgrent_r, NULL) 173 NS_COMPAT_CB(compat_getnetgrent_r, NULL) 174 { NULL, NULL, NULL }, 175 }; 176 177 static const ns_dtab setnetgrent_dtab[] = { 178 NS_FILES_CB(files_setnetgrent, NULL) 179 NS_COMPAT_CB(compat_setnetgrent, NULL) 180 { NULL, NULL, NULL }, 181 }; 182 183 static const ns_dtab endnetgrent_dtab[] = { 184 NS_FILES_CB(files_endnetgrent, NULL) 185 NS_COMPAT_CB(compat_endnetgrent, NULL) 186 { NULL, NULL, NULL }, 187 }; 188 189 static struct netgr_state compat_state; 190 191 static void 192 netgr_endstate(void *arg) 193 { 194 struct linelist *lp, *olp; 195 struct netgrp *gp, *ogp; 196 struct netgr_state *st; 197 198 st = (struct netgr_state *)arg; 199 lp = st->st_linehead; 200 while (lp != NULL) { 201 olp = lp; 202 lp = lp->l_next; 203 free(olp->l_groupname); 204 free(olp->l_line); 205 free(olp); 206 } 207 st->st_linehead = NULL; 208 if (st->st_grname != NULL) { 209 free(st->st_grname); 210 st->st_grname = NULL; 211 } 212 gp = st->st_gr; 213 while (gp != NULL) { 214 ogp = gp; 215 gp = gp->ng_next; 216 free(ogp->ng_str[NG_HOST]); 217 free(ogp->ng_str[NG_USER]); 218 free(ogp->ng_str[NG_DOM]); 219 free(ogp); 220 } 221 st->st_gr = NULL; 222 st->st_nextgrp = NULL; 223 } 224 225 static int 226 files_getnetgrent_r(void *retval, void *mdata, va_list ap) 227 { 228 struct netgr_state *st; 229 char **hostp, **userp, **domp, *buf; 230 size_t bufsize; 231 int *errnop; 232 233 hostp = va_arg(ap, char **); 234 userp = va_arg(ap, char **); 235 domp = va_arg(ap, char **); 236 buf = va_arg(ap, char *); 237 bufsize = va_arg(ap, size_t); 238 errnop = va_arg(ap, int *); 239 240 if (netgr_getstate(&st) != 0) 241 return (NS_UNAVAIL); 242 243 return (_getnetgrent_r(hostp, userp, domp, buf, bufsize, errnop, st)); 244 } 245 246 static int 247 files_setnetgrent(void *retval, void *mdata, va_list ap) 248 { 249 const ns_src src[] = { 250 { NSSRC_FILES, NS_SUCCESS }, 251 { NULL, 0 }, 252 }; 253 struct netgr_state *st; 254 const char *group; 255 int rv; 256 257 group = va_arg(ap, const char *); 258 259 if (group == NULL || group[0] == '\0') 260 return (NS_RETURN); 261 262 rv = netgr_getstate(&st); 263 if (rv != 0) 264 return (NS_UNAVAIL); 265 266 if (st->st_gr == NULL || strcmp(group, st->st_grname) != 0) { 267 (void)_nsdispatch(NULL, endnetgrent_dtab, NSDB_NETGROUP, 268 "endnetgrent", src); 269 if ((st->st_netf = fopen(_PATH_NETGROUP, "re")) != NULL) { 270 if (parse_netgrp(group, st, 0) != 0) 271 (void)_nsdispatch(NULL, endnetgrent_dtab, 272 NSDB_NETGROUP, "endnetgrent", src); 273 else 274 st->st_grname = strdup(group); 275 (void)fclose(st->st_netf); 276 st->st_netf = NULL; 277 } 278 } 279 st->st_nextgrp = st->st_gr; 280 return (st->st_grname != NULL ? NS_SUCCESS : NS_NOTFOUND); 281 } 282 283 static int 284 files_endnetgrent(void *retval, void *mdata, va_list ap) 285 { 286 struct netgr_state *st; 287 288 if (netgr_getstate(&st) != 0) 289 return (NS_UNAVAIL); 290 netgr_endstate(st); 291 return (NS_SUCCESS); 292 } 293 294 static int 295 compat_getnetgrent_r(void *retval, void *mdata, va_list ap) 296 { 297 char **hostp, **userp, **domp, *buf; 298 size_t bufsize; 299 int *errnop; 300 #ifdef YP 301 _yp_innetgr = 0; 302 #endif 303 304 hostp = va_arg(ap, char **); 305 userp = va_arg(ap, char **); 306 domp = va_arg(ap, char **); 307 buf = va_arg(ap, char *); 308 bufsize = va_arg(ap, size_t); 309 errnop = va_arg(ap, int *); 310 311 return (_getnetgrent_r(hostp, userp, domp, buf, bufsize, errnop, 312 &compat_state)); 313 } 314 315 /* 316 * compat_setnetgrent() 317 * Parse the netgroup file looking for the netgroup and build the list 318 * of netgrp structures. Let parse_netgrp() and read_for_group() do 319 * most of the work. 320 */ 321 static int 322 compat_setnetgrent(void *retval, void *mdata, va_list ap) 323 { 324 FILE *netf; 325 const char *group; 326 #ifdef YP 327 struct stat _yp_statp; 328 char _yp_plus; 329 #endif 330 331 group = va_arg(ap, const char *); 332 333 /* Sanity check */ 334 if (group == NULL || !strlen(group)) 335 return (NS_RETURN); 336 337 if (compat_state.st_gr == NULL || 338 strcmp(group, compat_state.st_grname) != 0) { 339 _compat_clearstate(); 340 341 #ifdef YP 342 /* Presumed guilty until proven innocent. */ 343 _use_only_yp = 0; 344 /* 345 * If /etc/netgroup doesn't exist or is empty, 346 * use NIS exclusively. 347 */ 348 if (((stat(_PATH_NETGROUP, &_yp_statp) < 0) && 349 errno == ENOENT) || _yp_statp.st_size == 0) 350 _use_only_yp = _netgr_yp_enabled = 1; 351 if ((netf = fopen(_PATH_NETGROUP,"re")) != NULL ||_use_only_yp){ 352 compat_state.st_netf = netf; 353 /* 354 * Icky: grab the first character of the netgroup file 355 * and turn on NIS if it's a '+'. rewind the stream 356 * afterwards so we don't goof up read_for_group() later. 357 */ 358 if (netf) { 359 fscanf(netf, "%c", &_yp_plus); 360 rewind(netf); 361 if (_yp_plus == '+') 362 _use_only_yp = _netgr_yp_enabled = 1; 363 } 364 /* 365 * If we were called specifically for an innetgr() 366 * lookup and we're in NIS-only mode, short-circuit 367 * parse_netgroup() and cut directly to the chase. 368 */ 369 if (_use_only_yp && _yp_innetgr) { 370 /* dohw! */ 371 if (netf != NULL) 372 fclose(netf); 373 return (NS_RETURN); 374 } 375 #else 376 if ((netf = fopen(_PATH_NETGROUP, "re"))) { 377 compat_state.st_netf = netf; 378 #endif 379 if (parse_netgrp(group, &compat_state, 1)) { 380 _compat_clearstate(); 381 } else { 382 compat_state.st_grname = strdup(group); 383 } 384 if (netf) 385 fclose(netf); 386 } 387 } 388 compat_state.st_nextgrp = compat_state.st_gr; 389 return (NS_SUCCESS); 390 } 391 392 static void 393 _compat_clearstate(void) 394 { 395 396 #ifdef YP 397 _netgr_yp_enabled = 0; 398 #endif 399 netgr_endstate(&compat_state); 400 } 401 402 /* 403 * compat_endnetgrent() - cleanup 404 */ 405 static int 406 compat_endnetgrent(void *retval, void *mdata, va_list ap) 407 { 408 409 _compat_clearstate(); 410 return (NS_SUCCESS); 411 } 412 413 int 414 _getnetgrent_r(char **hostp, char **userp, char **domp, char *buf, 415 size_t bufsize, int *errnop, struct netgr_state *st) 416 { 417 char *p, *src; 418 size_t len; 419 int rv; 420 421 #define COPY_NG_ELEM(dstp, i) do { \ 422 src = st->st_nextgrp->ng_str[(i)]; \ 423 if (src == NULL) \ 424 src = ""; \ 425 len = strlcpy(p, src, bufsize); \ 426 if (len >= bufsize) { \ 427 *errnop = ERANGE; \ 428 return (NS_RETURN); \ 429 } \ 430 *(dstp) = p; \ 431 p += len + 1; \ 432 bufsize -= len + 1; \ 433 } while (0) 434 435 p = buf; 436 if (st->st_nextgrp != NULL) { 437 COPY_NG_ELEM(hostp, NG_HOST); 438 COPY_NG_ELEM(userp, NG_USER); 439 COPY_NG_ELEM(domp, NG_DOM); 440 st->st_nextgrp = st->st_nextgrp->ng_next; 441 rv = NS_SUCCESS; 442 } else { 443 rv = NS_NOTFOUND; 444 } 445 #undef COPY_NG_ELEM 446 447 return (rv); 448 } 449 450 #ifdef YP 451 static int 452 _listmatch(const char *list, const char *group, int len) 453 { 454 const char *ptr = list; 455 const char *cptr; 456 int glen = strlen(group); 457 458 /* skip possible leading whitespace */ 459 while (isspace((unsigned char)*ptr)) 460 ptr++; 461 462 while (ptr < list + len) { 463 cptr = ptr; 464 while(*ptr != ',' && *ptr != '\0' && !isspace((unsigned char)*ptr)) 465 ptr++; 466 if (strncmp(cptr, group, glen) == 0 && glen == (ptr - cptr)) 467 return (1); 468 while (*ptr == ',' || isspace((unsigned char)*ptr)) 469 ptr++; 470 } 471 472 return (0); 473 } 474 475 static int 476 _revnetgr_lookup(char* lookupdom, char* map, const char* str, 477 const char* dom, const char* group) 478 { 479 int y, rv, rot; 480 char key[MAXHOSTNAMELEN]; 481 char *result; 482 int resultlen; 483 484 for (rot = 0; ; rot++) { 485 switch (rot) { 486 case 0: 487 snprintf(key, MAXHOSTNAMELEN, "%s.%s", str, 488 dom ? dom : lookupdom); 489 break; 490 case 1: 491 snprintf(key, MAXHOSTNAMELEN, "%s.*", str); 492 break; 493 case 2: 494 snprintf(key, MAXHOSTNAMELEN, "*.%s", 495 dom ? dom : lookupdom); 496 break; 497 case 3: 498 snprintf(key, MAXHOSTNAMELEN, "*.*"); 499 break; 500 default: 501 return (0); 502 } 503 y = yp_match(lookupdom, map, key, strlen(key), &result, 504 &resultlen); 505 if (y == 0) { 506 rv = _listmatch(result, group, resultlen); 507 free(result); 508 if (rv) 509 return (1); 510 } else if (y != YPERR_KEY) { 511 /* 512 * If we get an error other than 'no 513 * such key in map' then something is 514 * wrong and we should stop the search. 515 */ 516 return (-1); 517 } 518 } 519 } 520 #endif 521 522 /* 523 * Search for a match in a netgroup. 524 */ 525 static int 526 compat_innetgr(void *retval, void *mdata, va_list ap) 527 { 528 #ifdef YP 529 const ns_src src[] = { 530 { mdata, NS_SUCCESS }, 531 { NULL, 0 }, 532 }; 533 #endif 534 const char *group, *host, *user, *dom; 535 536 group = va_arg(ap, const char *); 537 host = va_arg(ap, const char *); 538 user = va_arg(ap, const char *); 539 dom = va_arg(ap, const char *); 540 541 if (group == NULL || !strlen(group)) 542 return (NS_RETURN); 543 544 #ifdef YP 545 _yp_innetgr = 1; 546 (void)_nsdispatch(NULL, setnetgrent_dtab, NSDB_NETGROUP, "setnetgrent", 547 src, group); 548 _yp_innetgr = 0; 549 /* 550 * If we're in NIS-only mode, do the search using 551 * NIS 'reverse netgroup' lookups. 552 * 553 * What happens with 'reverse netgroup' lookups: 554 * 555 * 1) try 'reverse netgroup' lookup 556 * 1.a) if host is specified and user is null: 557 * look in netgroup.byhost 558 * (try host.domain, host.*, *.domain or *.*) 559 * if found, return yes 560 * 1.b) if user is specified and host is null: 561 * look in netgroup.byuser 562 * (try host.domain, host.*, *.domain or *.*) 563 * if found, return yes 564 * 1.c) if both host and user are specified, 565 * don't do 'reverse netgroup' lookup. It won't work. 566 * 1.d) if neither host ane user are specified (why?!?) 567 * don't do 'reverse netgroup' lookup either. 568 * 2) if domain is specified and 'reverse lookup' is done: 569 * 'reverse lookup' was authoritative. bye bye. 570 * 3) otherwise, too bad, try it the slow way. 571 */ 572 if (_use_only_yp && (host == NULL) != (user == NULL)) { 573 int ret; 574 if(yp_get_default_domain(&_netgr_yp_domain)) 575 return (NS_NOTFOUND); 576 ret = _revnetgr_lookup(_netgr_yp_domain, 577 host?"netgroup.byhost":"netgroup.byuser", 578 host?host:user, dom, group); 579 if (ret == 1) { 580 *(int *)retval = 1; 581 return (NS_SUCCESS); 582 } else if (ret == 0 && dom != NULL) { 583 *(int *)retval = 0; 584 return (NS_SUCCESS); 585 } 586 } 587 #endif /* YP */ 588 589 return (_innetgr_fallback(retval, mdata, group, host, user, dom)); 590 } 591 592 static int 593 _innetgr_fallback(void *retval, void *mdata, const char *group, const char *host, 594 const char *user, const char *dom) 595 { 596 const ns_src src[] = { 597 { mdata, NS_SUCCESS }, 598 { NULL, 0 }, 599 }; 600 char *h, *u, *d; 601 char *buf; 602 size_t bufsize; 603 int rv, ret_errno; 604 605 if (group == NULL || group[0] == '\0') 606 return (NS_RETURN); 607 608 bufsize = NGRP_STORAGE_INITIAL; 609 buf = malloc(bufsize); 610 if (buf == NULL) 611 return (NS_UNAVAIL); 612 613 *(int *)retval = 0; 614 615 (void)_nsdispatch(NULL, setnetgrent_dtab, NSDB_NETGROUP, "setnetgrent", 616 src, group); 617 618 for (;;) { 619 do { 620 ret_errno = 0; 621 rv = _nsdispatch(NULL, getnetgrent_dtab, NSDB_NETGROUP, 622 "getnetgrent_r", src, &h, &u, &d, buf, bufsize, 623 &ret_errno); 624 if (rv != NS_SUCCESS && ret_errno == ERANGE) { 625 bufsize *= 2; 626 if (bufsize > NGRP_STORAGE_MAX || 627 (buf = reallocf(buf, bufsize)) == NULL) 628 goto out; 629 } 630 } while (rv != NS_SUCCESS && ret_errno == ERANGE); 631 632 if (rv != NS_SUCCESS) { 633 if (rv == NS_NOTFOUND && ret_errno == 0) 634 rv = NS_SUCCESS; 635 break; 636 } 637 638 if ((host == NULL || h == NULL || strcmp(host, h) == 0) && 639 (user == NULL || u == NULL || strcmp(user, u) == 0) && 640 (dom == NULL || d == NULL || strcmp(dom, d) == 0)) { 641 *(int *)retval = 1; 642 break; 643 } 644 } 645 646 out: 647 free(buf); 648 (void)_nsdispatch(NULL, endnetgrent_dtab, NSDB_NETGROUP, "endnetgrent", 649 src); 650 return (rv); 651 } 652 653 static int 654 innetgr_fallback(void *retval, void *mdata, va_list ap) 655 { 656 const char *group, *host, *user, *dom; 657 658 group = va_arg(ap, const char *); 659 host = va_arg(ap, const char *); 660 user = va_arg(ap, const char *); 661 dom = va_arg(ap, const char *); 662 663 return (_innetgr_fallback(retval, mdata, group, host, user, dom)); 664 } 665 666 /* 667 * Parse the netgroup file setting up the linked lists. 668 */ 669 static int 670 parse_netgrp(const char *group, struct netgr_state *st, int niscompat) 671 { 672 struct netgrp *grp; 673 struct linelist *lp = st->st_linehead; 674 char **ng; 675 char *epos, *gpos, *pos, *spos; 676 int freepos, len, strpos; 677 #ifdef DEBUG 678 int fields; 679 #endif 680 681 /* 682 * First, see if the line has already been read in. 683 */ 684 while (lp) { 685 if (!strcmp(group, lp->l_groupname)) 686 break; 687 lp = lp->l_next; 688 } 689 if (lp == NULL && (lp = read_for_group(group, st, niscompat)) == NULL) 690 return (1); 691 if (lp->l_parsed) { 692 #ifdef DEBUG 693 /* 694 * This error message is largely superflous since the 695 * code handles the error condition sucessfully, and 696 * spewing it out from inside libc can actually hose 697 * certain programs. 698 */ 699 fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname); 700 #endif 701 return (1); 702 } else 703 lp->l_parsed = 1; 704 pos = lp->l_line; 705 /* Watch for null pointer dereferences, dammit! */ 706 while (pos != NULL && *pos != '\0') { 707 if (*pos == '(') { 708 grp = malloc(sizeof(*grp)); 709 if (grp == NULL) 710 return (1); 711 ng = grp->ng_str; 712 bzero(grp, sizeof(*grp)); 713 pos++; 714 gpos = strsep(&pos, ")"); 715 #ifdef DEBUG 716 fields = 0; 717 #endif 718 for (strpos = 0; strpos < 3; strpos++) { 719 if ((spos = strsep(&gpos, ",")) == NULL) { 720 /* 721 * All other systems I've tested 722 * return NULL for empty netgroup 723 * fields. It's up to user programs 724 * to handle the NULLs appropriately. 725 */ 726 ng[strpos] = NULL; 727 continue; 728 } 729 #ifdef DEBUG 730 fields++; 731 #endif 732 while (*spos == ' ' || *spos == '\t') 733 spos++; 734 if ((epos = strpbrk(spos, " \t"))) { 735 *epos = '\0'; 736 len = epos - spos; 737 } else 738 len = strlen(spos); 739 if (len <= 0) 740 continue; 741 ng[strpos] = malloc(len + 1); 742 if (ng[strpos] == NULL) { 743 for (freepos = 0; freepos < strpos; 744 freepos++) 745 free(ng[freepos]); 746 free(grp); 747 return (1); 748 } 749 bcopy(spos, ng[strpos], len + 1); 750 } 751 grp->ng_next = st->st_gr; 752 st->st_gr = grp; 753 #ifdef DEBUG 754 /* 755 * Note: on other platforms, malformed netgroup 756 * entries are not normally flagged. While we 757 * can catch bad entries and report them, we should 758 * stay silent by default for compatibility's sake. 759 */ 760 if (fields < 3) { 761 fprintf(stderr, 762 "Bad entry (%s%s%s%s%s) in netgroup \"%s\"\n", 763 ng[NG_HOST] == NULL ? "" : ng[NG_HOST], 764 ng[NG_USER] == NULL ? "" : ",", 765 ng[NG_USER] == NULL ? "" : ng[NG_USER], 766 ng[NG_DOM] == NULL ? "" : ",", 767 ng[NG_DOM] == NULL ? "" : ng[NG_DOM], 768 lp->l_groupname); 769 } 770 #endif 771 } else { 772 spos = strsep(&pos, ", \t"); 773 if (parse_netgrp(spos, st, niscompat)) 774 continue; 775 } 776 if (pos == NULL) 777 break; 778 while (*pos == ' ' || *pos == ',' || *pos == '\t') 779 pos++; 780 } 781 return (0); 782 } 783 784 /* 785 * Read the netgroup file and save lines until the line for the netgroup 786 * is found. Return 1 if eof is encountered. 787 */ 788 static struct linelist * 789 read_for_group(const char *group, struct netgr_state *st, int niscompat) 790 { 791 char *linep, *olinep, *pos, *spos; 792 int len, olen; 793 int cont; 794 struct linelist *lp; 795 char line[LINSIZ + 2]; 796 FILE *netf; 797 #ifdef YP 798 char *result; 799 int resultlen; 800 linep = NULL; 801 802 netf = st->st_netf; 803 while ((_netgr_yp_enabled && niscompat) || 804 fgets(line, LINSIZ, netf) != NULL) { 805 if (_netgr_yp_enabled) { 806 if(!_netgr_yp_domain) 807 if(yp_get_default_domain(&_netgr_yp_domain)) 808 continue; 809 if (yp_match(_netgr_yp_domain, "netgroup", group, 810 strlen(group), &result, &resultlen)) { 811 free(result); 812 if (_use_only_yp) 813 return ((struct linelist *)0); 814 else { 815 _netgr_yp_enabled = 0; 816 continue; 817 } 818 } 819 if (strlen(result) == 0) { 820 free(result); 821 return (NULL); 822 } 823 snprintf(line, LINSIZ, "%s %s", group, result); 824 free(result); 825 } 826 #else 827 linep = NULL; 828 while (fgets(line, LINSIZ, netf) != NULL) { 829 #endif 830 pos = (char *)&line; 831 #ifdef YP 832 if (niscompat && *pos == '+') { 833 _netgr_yp_enabled = 1; 834 continue; 835 } 836 #endif 837 if (*pos == '#') 838 continue; 839 while (*pos == ' ' || *pos == '\t') 840 pos++; 841 spos = pos; 842 while (*pos != ' ' && *pos != '\t' && *pos != '\n' && 843 *pos != '\0') 844 pos++; 845 len = pos - spos; 846 while (*pos == ' ' || *pos == '\t') 847 pos++; 848 if (*pos != '\n' && *pos != '\0') { 849 lp = malloc(sizeof (*lp)); 850 if (lp == NULL) 851 return (NULL); 852 lp->l_parsed = 0; 853 lp->l_groupname = malloc(len + 1); 854 if (lp->l_groupname == NULL) { 855 free(lp); 856 return (NULL); 857 } 858 bcopy(spos, lp->l_groupname, len); 859 *(lp->l_groupname + len) = '\0'; 860 len = strlen(pos); 861 olen = 0; 862 863 /* 864 * Loop around handling line continuations. 865 */ 866 do { 867 if (*(pos + len - 1) == '\n') 868 len--; 869 if (*(pos + len - 1) == '\\') { 870 len--; 871 cont = 1; 872 } else 873 cont = 0; 874 if (len > 0) { 875 linep = malloc(olen + len + 1); 876 if (linep == NULL) { 877 free(lp->l_groupname); 878 free(lp); 879 if (olen > 0) 880 free(olinep); 881 return (NULL); 882 } 883 if (olen > 0) { 884 bcopy(olinep, linep, olen); 885 free(olinep); 886 } 887 bcopy(pos, linep + olen, len); 888 olen += len; 889 *(linep + olen) = '\0'; 890 olinep = linep; 891 } 892 if (cont) { 893 if (fgets(line, LINSIZ, netf)) { 894 pos = line; 895 len = strlen(pos); 896 } else 897 cont = 0; 898 } 899 } while (cont); 900 lp->l_line = linep; 901 lp->l_next = st->st_linehead; 902 st->st_linehead = lp; 903 904 /* 905 * If this is the one we wanted, we are done. 906 */ 907 if (!strcmp(lp->l_groupname, group)) 908 return (lp); 909 } 910 } 911 #ifdef YP 912 /* 913 * Yucky. The recursive nature of this whole mess might require 914 * us to make more than one pass through the netgroup file. 915 * This might be best left outside the #ifdef YP, but YP is 916 * defined by default anyway, so I'll leave it like this 917 * until I know better. 918 */ 919 rewind(netf); 920 #endif 921 return (NULL); 922 } 923 924 int 925 getnetgrent_r(char **hostp, char **userp, char **domp, char *buf, size_t bufsize) 926 { 927 int rv, ret_errno; 928 929 ret_errno = 0; 930 rv = _nsdispatch(NULL, getnetgrent_dtab, NSDB_NETGROUP, "getnetgrent_r", 931 defaultsrc, hostp, userp, domp, buf, bufsize, &ret_errno); 932 if (rv == NS_SUCCESS) { 933 return (1); 934 } else { 935 errno = ret_errno; 936 return (0); 937 } 938 } 939 940 int 941 getnetgrent(char **hostp, char **userp, char **domp) 942 { 943 static char *ngrp_storage; 944 static size_t ngrp_storage_size; 945 int ret_errno, rv; 946 947 if (ngrp_storage == NULL) { 948 ngrp_storage_size = NGRP_STORAGE_INITIAL; 949 ngrp_storage = malloc(ngrp_storage_size); 950 if (ngrp_storage == NULL) 951 return (0); 952 } 953 954 do { 955 ret_errno = 0; 956 rv = _nsdispatch(NULL, getnetgrent_dtab, NSDB_NETGROUP, 957 "getnetgrent_r", defaultsrc, hostp, userp, domp, 958 ngrp_storage, ngrp_storage_size, &ret_errno); 959 if (rv != NS_SUCCESS && ret_errno == ERANGE) { 960 ngrp_storage_size *= 2; 961 if (ngrp_storage_size > NGRP_STORAGE_MAX) { 962 free(ngrp_storage); 963 ngrp_storage = NULL; 964 errno = ERANGE; 965 return (0); 966 } 967 ngrp_storage = reallocf(ngrp_storage, 968 ngrp_storage_size); 969 if (ngrp_storage == NULL) 970 return (0); 971 } 972 } while (rv != NS_SUCCESS && ret_errno == ERANGE); 973 974 if (rv == NS_SUCCESS) { 975 return (1); 976 } else { 977 errno = ret_errno; 978 return (0); 979 } 980 } 981 982 void 983 setnetgrent(const char *netgroup) 984 { 985 986 (void)_nsdispatch(NULL, setnetgrent_dtab, NSDB_NETGROUP, "setnetgrent", 987 defaultsrc, netgroup); 988 } 989 990 void 991 endnetgrent(void) 992 { 993 994 (void)_nsdispatch(NULL, endnetgrent_dtab, NSDB_NETGROUP, "endnetgrent", 995 defaultsrc); 996 } 997 998 int 999 innetgr(const char *netgroup, const char *host, const char *user, 1000 const char *domain) 1001 { 1002 static const ns_dtab dtab[] = { 1003 NS_COMPAT_CB(compat_innetgr, NULL) 1004 NS_FALLBACK_CB(innetgr_fallback) 1005 { NULL, NULL, NULL }, 1006 }; 1007 int result, rv; 1008 1009 rv = _nsdispatch(&result, dtab, NSDB_NETGROUP, "innetgr", defaultsrc, 1010 netgroup, host, user, domain); 1011 return (rv == NS_SUCCESS ? result : 0); 1012 } 1013