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