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