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