1 /* $NetBSD: getgrent.c,v 1.47 2003/08/07 16:42:49 agc Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 /* 33 * Portions Copyright (c) 1994, Jason Downs. All Rights Reserved. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 3. All advertising materials mentioning features or use of this software 44 * must display the following acknowledgement: 45 * This product includes software developed by the University of 46 * California, Berkeley and its contributors. 47 * 4. Neither the name of the University nor the names of its contributors 48 * may be used to endorse or promote products derived from this software 49 * without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 */ 63 64 #include <sys/cdefs.h> 65 #if defined(LIBC_SCCS) && !defined(lint) 66 #if 0 67 static char sccsid[] = "@(#)getgrent.c 8.2 (Berkeley) 3/21/94"; 68 #else 69 __RCSID("$NetBSD: getgrent.c,v 1.47 2003/08/07 16:42:49 agc Exp $"); 70 #endif 71 #endif /* LIBC_SCCS and not lint */ 72 73 #include "namespace.h" 74 75 #include <sys/types.h> 76 77 #include <assert.h> 78 #include <errno.h> 79 #include <grp.h> 80 #include <limits.h> 81 #include <nsswitch.h> 82 #include <stdio.h> 83 #include <stdlib.h> 84 #include <string.h> 85 #include <syslog.h> 86 87 #include <stdarg.h> 88 89 #ifdef HESIOD 90 #include <hesiod.h> 91 #endif 92 #ifdef YP 93 #include <rpc/rpc.h> 94 #include <rpcsvc/yp_prot.h> 95 #include <rpcsvc/ypclnt.h> 96 #endif 97 98 #if defined(YP) || defined(HESIOD) 99 #define _GROUP_COMPAT 100 #endif 101 102 struct group *_getgrent_user(const char *); 103 104 #ifdef __weak_alias 105 __weak_alias(endgrent,_endgrent) 106 __weak_alias(getgrent,_getgrent) 107 __weak_alias(getgrgid,_getgrgid) 108 __weak_alias(getgrnam,_getgrnam) 109 __weak_alias(setgrent,_setgrent) 110 __weak_alias(setgroupent,_setgroupent) 111 #endif 112 113 static FILE *_gr_fp; 114 static struct group _gr_group; 115 static int _gr_stayopen; 116 static int _gr_filesdone; 117 118 static void grcleanup(void); 119 static int grscan(int, gid_t, const char *, const char *); 120 static int grstart(void); 121 static int grmatchline(int, gid_t, const char *, const char *); 122 123 #define MAXGRP 200 124 #define MAXLINELENGTH 1024 125 126 static __aconst char *members[MAXGRP]; 127 static char line[MAXLINELENGTH]; 128 129 #ifdef YP 130 static char *__ypcurrent, *__ypdomain; 131 static int __ypcurrentlen; 132 static int _gr_ypdone; 133 #endif 134 135 #ifdef HESIOD 136 static int _gr_hesnum; 137 static struct group *_gr_hesgrplist = NULL; 138 static int _gr_hesgrplistnum; 139 static int _gr_hesgrplistmax; 140 #endif 141 142 #ifdef _GROUP_COMPAT 143 enum _grmode { GRMODE_NONE, GRMODE_FULL, GRMODE_NAME }; 144 static enum _grmode __grmode; 145 #endif 146 147 struct group * 148 getgrent(void) 149 { 150 151 if ((!_gr_fp && !grstart()) || !grscan(0, 0, NULL, NULL)) 152 return (NULL); 153 return &_gr_group; 154 } 155 156 /* 157 * _getgrent_user() is designed only to be called by getgrouplist(3) and 158 * hence makes no guarantees about filling the entire structure that it 159 * returns. It may only fill in the group name and gid fields. 160 */ 161 162 struct group * 163 _getgrent_user(const char *user) 164 { 165 166 if ((!_gr_fp && !grstart()) || !grscan(0, 0, NULL, user)) 167 return (NULL); 168 return &_gr_group; 169 } 170 171 struct group * 172 getgrnam(const char *name) 173 { 174 int rval; 175 176 _DIAGASSERT(name != NULL); 177 178 if (!grstart()) 179 return NULL; 180 rval = grscan(1, 0, name, NULL); 181 if (!_gr_stayopen) 182 endgrent(); 183 return (rval) ? &_gr_group : NULL; 184 } 185 186 struct group * 187 getgrgid(gid_t gid) 188 { 189 int rval; 190 191 if (!grstart()) 192 return NULL; 193 rval = grscan(1, gid, NULL, NULL); 194 if (!_gr_stayopen) 195 endgrent(); 196 return (rval) ? &_gr_group : NULL; 197 } 198 199 void 200 grcleanup(void) 201 { 202 203 _gr_filesdone = 0; 204 #ifdef YP 205 if (__ypcurrent) 206 free(__ypcurrent); 207 __ypcurrent = NULL; 208 _gr_ypdone = 0; 209 #endif 210 #ifdef HESIOD 211 _gr_hesnum = 0; 212 if (!_gr_hesgrplist) 213 free(_gr_hesgrplist); 214 _gr_hesgrplist = NULL; 215 _gr_hesgrplistnum = -1; 216 _gr_hesgrplistmax = 0; 217 #endif 218 #ifdef _GROUP_COMPAT 219 __grmode = GRMODE_NONE; 220 #endif 221 } 222 223 static int 224 grstart(void) 225 { 226 227 grcleanup(); 228 if (_gr_fp) { 229 rewind(_gr_fp); 230 return 1; 231 } 232 return (_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0; 233 } 234 235 void 236 setgrent(void) 237 { 238 239 (void) setgroupent(0); 240 } 241 242 int 243 setgroupent(int stayopen) 244 { 245 246 if (!grstart()) 247 return 0; 248 _gr_stayopen = stayopen; 249 return 1; 250 } 251 252 void 253 endgrent(void) 254 { 255 256 grcleanup(); 257 if (_gr_fp) { 258 (void)fclose(_gr_fp); 259 _gr_fp = NULL; 260 } 261 } 262 263 264 static int _local_grscan(void *, void *, va_list); 265 266 /*ARGSUSED*/ 267 static int 268 _local_grscan(void *rv, void *cb_data, va_list ap) 269 { 270 int search = va_arg(ap, int); 271 gid_t gid = va_arg(ap, gid_t); 272 const char *name = va_arg(ap, const char *); 273 const char *user = va_arg(ap, const char *); 274 275 if (_gr_filesdone) 276 return NS_NOTFOUND; 277 for (;;) { 278 if (!fgets(line, sizeof(line), _gr_fp)) { 279 if (!search) 280 _gr_filesdone = 1; 281 return NS_NOTFOUND; 282 } 283 /* skip lines that are too big */ 284 if (!strchr(line, '\n')) { 285 int ch; 286 287 while ((ch = getc(_gr_fp)) != '\n' && ch != EOF) 288 ; 289 continue; 290 } 291 if (grmatchline(search, gid, name, user)) 292 return NS_SUCCESS; 293 } 294 /* NOTREACHED */ 295 } 296 297 #ifdef HESIOD 298 static int _dns_grscan(void *, void *, va_list); 299 static int _dns_grplist(const char *); 300 301 /*ARGSUSED*/ 302 static int 303 _dns_grscan(void *rv, void *cb_data, va_list ap) 304 { 305 int search = va_arg(ap, int); 306 gid_t gid = va_arg(ap, gid_t); 307 const char *name = va_arg(ap, const char *); 308 const char *user = va_arg(ap, const char *); 309 310 char **hp; 311 void *context; 312 int r; 313 314 r = NS_UNAVAIL; 315 if (!search && user && _gr_hesgrplistmax != -1) { 316 r = _dns_grplist(user); 317 /* if we did not find user.grplist, just iterate */ 318 if (!_gr_hesgrplist) { 319 _gr_hesgrplistmax = -1; 320 if (r != NS_NOTFOUND) 321 return r; 322 } else 323 return r; 324 } 325 if (!search && _gr_hesnum == -1) 326 return NS_NOTFOUND; 327 if (hesiod_init(&context) == -1) 328 return (r); 329 330 for (;;) { 331 if (search) { 332 if (name) 333 strlcpy(line, name, sizeof(line)); 334 else 335 snprintf(line, sizeof(line), "%u", 336 (unsigned int)gid); 337 } else { 338 snprintf(line, sizeof(line), "group-%u", _gr_hesnum); 339 _gr_hesnum++; 340 } 341 342 hp = NULL; 343 if (search && !name) { 344 hp = hesiod_resolve(context, line, "gid"); 345 if (hp == NULL && errno != ENOENT) 346 break; 347 } 348 if (hp == NULL) 349 hp = hesiod_resolve(context, line, "group"); 350 if (hp == NULL) { 351 if (errno == ENOENT) { 352 if (!search) 353 _gr_hesnum = -1; 354 r = NS_NOTFOUND; 355 } 356 break; 357 } 358 359 /* only check first elem */ 360 strlcpy(line, hp[0], sizeof(line)); 361 hesiod_free_list(context, hp); 362 if (grmatchline(search, gid, name, user)) { 363 r = NS_SUCCESS; 364 break; 365 } else if (search) { 366 r = NS_NOTFOUND; 367 break; 368 } 369 } 370 hesiod_end(context); 371 return (r); 372 } 373 374 static int 375 _dns_grplist(const char *user) 376 { 377 void *context; 378 int r; 379 char **hp; 380 char *cp; 381 382 r = NS_UNAVAIL; 383 if (!_gr_hesgrplist) { 384 if (hesiod_init(&context) == -1) 385 return r; 386 387 _gr_hesgrplistnum = -1; 388 hp = hesiod_resolve(context, user, "grplist"); 389 if (!hp) { 390 if (errno == ENOENT) 391 r = NS_NOTFOUND; 392 hesiod_end(context); 393 return r; 394 } 395 396 strlcpy(line, hp[0], sizeof(line)); 397 hesiod_free_list(context, hp); 398 399 _gr_hesgrplistmax = 0; 400 for (cp=line; *cp; cp++) 401 if (*cp == ':') 402 _gr_hesgrplistmax++; 403 _gr_hesgrplistmax /= 2; 404 _gr_hesgrplistmax++; 405 406 _gr_hesgrplist = malloc(_gr_hesgrplistmax * 407 sizeof(*_gr_hesgrplist)); 408 if (!_gr_hesgrplist) { 409 hesiod_end(context); 410 return NS_UNAVAIL; 411 } 412 413 cp = line; 414 _gr_hesgrplistmax = 0; 415 for (;;) { 416 char *name; 417 char *num; 418 gid_t gid; 419 char *ep; 420 421 /* XXXrcd: error handling */ 422 if (!(name = strsep(&cp, ":"))) 423 break; 424 if (!(num = strsep(&cp, ":"))) 425 break; 426 gid = (gid_t) strtoul(num, &ep, 10); 427 if (gid > GID_MAX || *ep != '\0') 428 break; 429 430 _gr_hesgrplist[_gr_hesgrplistmax].gr_name = name; 431 _gr_hesgrplist[_gr_hesgrplistmax].gr_gid = gid; 432 _gr_hesgrplistmax++; 433 } 434 435 hesiod_end(context); 436 } 437 438 /* we assume that _gr_hesgrplist is now defined */ 439 if (++_gr_hesgrplistnum >= _gr_hesgrplistmax) 440 return NS_NOTFOUND; 441 442 /* 443 * Now we copy the relevant information into _gr_group, so that 444 * it can be returned. Note that we only fill in the bare necessities 445 * as this will be used exclusively by getgrouplist(3) and we do 446 * not want to have to look up all of the information. 447 */ 448 _gr_group.gr_name = _gr_hesgrplist[_gr_hesgrplistnum].gr_name; 449 _gr_group.gr_passwd = NULL; 450 _gr_group.gr_gid = _gr_hesgrplist[_gr_hesgrplistnum].gr_gid; 451 _gr_group.gr_mem = NULL; 452 453 return NS_SUCCESS; 454 } 455 #endif /* HESIOD */ 456 457 #ifdef YP 458 static int _nis_grscan(void *, void *, va_list); 459 460 /*ARGSUSED*/ 461 static int 462 _nis_grscan(void *rv, void *cb_data, va_list ap) 463 { 464 int search = va_arg(ap, int); 465 gid_t gid = va_arg(ap, gid_t); 466 const char *name = va_arg(ap, const char *); 467 const char *user = va_arg(ap, const char *); 468 469 char *key, *data; 470 int keylen, datalen; 471 int r; 472 473 if(__ypdomain == NULL) { 474 switch (yp_get_default_domain(&__ypdomain)) { 475 case 0: 476 break; 477 case YPERR_RESRC: 478 return NS_TRYAGAIN; 479 default: 480 return NS_UNAVAIL; 481 } 482 } 483 484 if (search) { /* specific group or gid */ 485 if (name) 486 strlcpy(line, name, sizeof(line)); 487 else 488 snprintf(line, sizeof(line), "%u", (unsigned int)gid); 489 data = NULL; 490 r = yp_match(__ypdomain, 491 (name) ? "group.byname" : "group.bygid", 492 line, (int)strlen(line), &data, &datalen); 493 switch (r) { 494 case 0: 495 break; 496 case YPERR_KEY: 497 if (data) 498 free(data); 499 return NS_NOTFOUND; 500 default: 501 if (data) 502 free(data); 503 return NS_UNAVAIL; 504 } 505 data[datalen] = '\0'; /* clear trailing \n */ 506 strlcpy(line, data, sizeof(line)); 507 free(data); 508 if (grmatchline(search, gid, name, user)) 509 return NS_SUCCESS; 510 else 511 return NS_NOTFOUND; 512 } 513 514 /* ! search */ 515 if (_gr_ypdone) 516 return NS_NOTFOUND; 517 for (;;) { 518 data = NULL; 519 if(__ypcurrent) { 520 key = NULL; 521 r = yp_next(__ypdomain, "group.byname", 522 __ypcurrent, __ypcurrentlen, 523 &key, &keylen, &data, &datalen); 524 free(__ypcurrent); 525 switch (r) { 526 case 0: 527 break; 528 case YPERR_NOMORE: 529 __ypcurrent = NULL; 530 if (key) 531 free(key); 532 if (data) 533 free(data); 534 _gr_ypdone = 1; 535 return NS_NOTFOUND; 536 default: 537 if (key) 538 free(key); 539 if (data) 540 free(data); 541 return NS_UNAVAIL; 542 } 543 __ypcurrent = key; 544 __ypcurrentlen = keylen; 545 } else { 546 if (yp_first(__ypdomain, "group.byname", 547 &__ypcurrent, &__ypcurrentlen, 548 &data, &datalen)) { 549 if (data) 550 free(data); 551 return NS_UNAVAIL; 552 } 553 } 554 data[datalen] = '\0'; /* clear trailing \n */ 555 strlcpy(line, data, sizeof(line)); 556 free(data); 557 if (grmatchline(search, gid, name, user)) 558 return NS_SUCCESS; 559 } 560 /* NOTREACHED */ 561 } 562 #endif /* YP */ 563 564 #ifdef _GROUP_COMPAT 565 /* 566 * log an error if "files" or "compat" is specified in group_compat database 567 */ 568 static int _bad_grscan(void *, void *, va_list); 569 570 /*ARGSUSED*/ 571 static int 572 _bad_grscan(void *rv, void *cb_data, va_list ap) 573 { 574 static int warned; 575 576 _DIAGASSERT(cb_data != NULL); 577 578 if (!warned) { 579 syslog(LOG_ERR, 580 "nsswitch.conf group_compat database can't use '%s'", 581 (char *)cb_data); 582 } 583 warned = 1; 584 return NS_UNAVAIL; 585 } 586 587 /* 588 * when a name lookup in compat mode is required, look it up in group_compat 589 * nsswitch database. only Hesiod and NIS is supported - it doesn't make 590 * sense to lookup compat names from 'files' or 'compat' 591 */ 592 593 static int __grscancompat(int, gid_t, const char *, const char *); 594 595 static int 596 __grscancompat(int search, gid_t gid, const char *name, const char *user) 597 { 598 static const ns_dtab dtab[] = { 599 NS_FILES_CB(_bad_grscan, "files") 600 NS_DNS_CB(_dns_grscan, NULL) 601 NS_NIS_CB(_nis_grscan, NULL) 602 NS_COMPAT_CB(_bad_grscan, "compat") 603 { 0 } 604 }; 605 static const ns_src defaultnis[] = { 606 { NSSRC_NIS, NS_SUCCESS }, 607 { 0 } 608 }; 609 610 _DIAGASSERT(name != NULL); 611 612 return (nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "grscancompat", 613 defaultnis, search, gid, name, user)); 614 } 615 #endif /* GROUP_COMPAT */ 616 617 618 static int _compat_grscan(void *, void *, va_list); 619 620 /*ARGSUSED*/ 621 static int 622 _compat_grscan(void *rv, void *cb_data, va_list ap) 623 { 624 int search = va_arg(ap, int); 625 gid_t gid = va_arg(ap, gid_t); 626 const char *name = va_arg(ap, const char *); 627 const char *user = va_arg(ap, const char *); 628 629 #ifdef _GROUP_COMPAT 630 static char *grname = NULL; 631 #endif 632 633 for (;;) { 634 #ifdef _GROUP_COMPAT 635 if(__grmode != GRMODE_NONE) { 636 int r; 637 638 switch(__grmode) { 639 case GRMODE_FULL: 640 r = __grscancompat(search, gid, name, user); 641 if (r == NS_SUCCESS) 642 return r; 643 __grmode = GRMODE_NONE; 644 break; 645 case GRMODE_NAME: 646 if(grname == (char *)NULL) { 647 __grmode = GRMODE_NONE; 648 break; 649 } 650 r = __grscancompat(1, 0, grname, user); 651 free(grname); 652 grname = (char *)NULL; 653 if (r != NS_SUCCESS) 654 break; 655 if (!search) 656 return NS_SUCCESS; 657 if (name) { 658 if (! strcmp(_gr_group.gr_name, name)) 659 return NS_SUCCESS; 660 } else { 661 if (_gr_group.gr_gid == gid) 662 return NS_SUCCESS; 663 } 664 break; 665 case GRMODE_NONE: 666 abort(); 667 } 668 continue; 669 } 670 #endif /* _GROUP_COMPAT */ 671 672 if (!fgets(line, sizeof(line), _gr_fp)) 673 return NS_NOTFOUND; 674 /* skip lines that are too big */ 675 if (!strchr(line, '\n')) { 676 int ch; 677 678 while ((ch = getc(_gr_fp)) != '\n' && ch != EOF) 679 ; 680 continue; 681 } 682 683 #ifdef _GROUP_COMPAT 684 if (line[0] == '+') { 685 char *tptr, *bp; 686 687 switch(line[1]) { 688 case ':': 689 case '\0': 690 case '\n': 691 __grmode = GRMODE_FULL; 692 break; 693 default: 694 __grmode = GRMODE_NAME; 695 bp = line; 696 tptr = strsep(&bp, ":\n"); 697 grname = strdup(tptr + 1); 698 break; 699 } 700 continue; 701 } 702 #endif /* _GROUP_COMPAT */ 703 if (grmatchline(search, gid, name, user)) 704 return NS_SUCCESS; 705 } 706 /* NOTREACHED */ 707 } 708 709 static int 710 grscan(int search, gid_t gid, const char *name, const char *user) 711 { 712 int r; 713 static const ns_dtab dtab[] = { 714 NS_FILES_CB(_local_grscan, NULL) 715 NS_DNS_CB(_dns_grscan, NULL) 716 NS_NIS_CB(_nis_grscan, NULL) 717 NS_COMPAT_CB(_compat_grscan, NULL) 718 { 0 } 719 }; 720 static const ns_src compatsrc[] = { 721 { NSSRC_COMPAT, NS_SUCCESS }, 722 { 0 } 723 }; 724 725 /* name may be NULL if search is nonzero */ 726 727 r = nsdispatch(NULL, dtab, NSDB_GROUP, "grscan", compatsrc, 728 search, gid, name, user); 729 return (r == NS_SUCCESS) ? 1 : 0; 730 } 731 732 static int 733 grmatchline(int search, gid_t gid, const char *name, const char *user) 734 { 735 unsigned long id; 736 __aconst char **m; 737 char *cp, *bp, *ep; 738 739 /* name may be NULL if search is nonzero */ 740 741 if (line[0] == '+') 742 return 0; /* sanity check to prevent recursion */ 743 bp = line; 744 _gr_group.gr_name = strsep(&bp, ":\n"); 745 if (search && name && strcmp(_gr_group.gr_name, name)) 746 return 0; 747 _gr_group.gr_passwd = strsep(&bp, ":\n"); 748 if (!(cp = strsep(&bp, ":\n"))) 749 return 0; 750 id = strtoul(cp, &ep, 10); 751 if (id > GID_MAX || *ep != '\0') 752 return 0; 753 _gr_group.gr_gid = (gid_t)id; 754 if (search && name == NULL && _gr_group.gr_gid != gid) 755 return 0; 756 cp = NULL; 757 if (bp == NULL) 758 return 0; 759 for (_gr_group.gr_mem = m = members;; bp++) { 760 if (m == &members[MAXGRP - 1]) 761 break; 762 if (*bp == ',') { 763 if (cp) { 764 *bp = '\0'; 765 *m++ = cp; 766 cp = NULL; 767 } 768 } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') { 769 if (cp) { 770 *bp = '\0'; 771 *m++ = cp; 772 } 773 break; 774 } else if (cp == NULL) 775 cp = bp; 776 } 777 *m = NULL; 778 if (user) { 779 for (m = members; *m; m++) 780 if (!strcmp(user, *m)) 781 return 1; 782 return 0; 783 } 784 return 1; 785 } 786