1 /* $NetBSD: getgrent.c,v 1.58 2005/04/19 05:27:58 lukem Exp $ */ 2 3 /*- 4 * Copyright (c) 1999-2000, 2004-2005 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Luke Mewburn. 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. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Copyright (c) 1989, 1993 41 * The Regents of the University of California. All rights reserved. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 3. Neither the name of the University nor the names of its contributors 52 * may be used to endorse or promote products derived from this software 53 * without specific prior written permission. 54 * 55 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 56 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 57 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 58 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 59 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 60 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 61 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 62 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 63 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 64 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 65 * SUCH DAMAGE. 66 */ 67 68 /* 69 * Portions Copyright (c) 1994, Jason Downs. All Rights Reserved. 70 * 71 * Redistribution and use in source and binary forms, with or without 72 * modification, are permitted provided that the following conditions 73 * are met: 74 * 1. Redistributions of source code must retain the above copyright 75 * notice, this list of conditions and the following disclaimer. 76 * 2. Redistributions in binary form must reproduce the above copyright 77 * notice, this list of conditions and the following disclaimer in the 78 * documentation and/or other materials provided with the distribution. 79 * 80 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS 81 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 82 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 83 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, 84 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 85 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 86 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 87 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 88 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 89 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 90 * SUCH DAMAGE. 91 */ 92 93 #include <sys/cdefs.h> 94 #if defined(LIBC_SCCS) && !defined(lint) 95 #if 0 96 static char sccsid[] = "@(#)getgrent.c 8.2 (Berkeley) 3/21/94"; 97 #else 98 __RCSID("$NetBSD: getgrent.c,v 1.58 2005/04/19 05:27:58 lukem Exp $"); 99 #endif 100 #endif /* LIBC_SCCS and not lint */ 101 102 #include "namespace.h" 103 #include "reentrant.h" 104 105 #include <sys/param.h> 106 107 #include <assert.h> 108 #include <errno.h> 109 #include <grp.h> 110 #include <limits.h> 111 #include <nsswitch.h> 112 #include <stdarg.h> 113 #include <stdio.h> 114 #include <stdlib.h> 115 #include <string.h> 116 #include <syslog.h> 117 118 #ifdef HESIOD 119 #include <hesiod.h> 120 #endif 121 122 #ifdef YP 123 #include <rpc/rpc.h> 124 #include <rpcsvc/yp_prot.h> 125 #include <rpcsvc/ypclnt.h> 126 #endif 127 128 #include "gr_private.h" 129 130 #ifdef __weak_alias 131 __weak_alias(endgrent,_endgrent) 132 __weak_alias(getgrent,_getgrent) 133 __weak_alias(getgrent_r,_getgrent_r) 134 __weak_alias(getgrgid,_getgrgid) 135 __weak_alias(getgrgid_r,_getgrgid_r) 136 __weak_alias(getgrnam,_getgrnam) 137 __weak_alias(getgrnam_r,_getgrnam_r) 138 __weak_alias(setgrent,_setgrent) 139 __weak_alias(setgroupent,_setgroupent) 140 #endif 141 142 #ifdef _REENTRANT 143 mutex_t __grmutex = MUTEX_INITIALIZER; 144 #endif 145 146 /* 147 * _gr_memfrombuf 148 * Obtain want bytes from buffer (of size buflen) and return a pointer 149 * to the available memory after adjusting buffer/buflen. 150 * Returns NULL if there is insufficient space. 151 */ 152 static char * 153 _gr_memfrombuf(size_t want, char **buffer, size_t *buflen) 154 { 155 char *rv; 156 157 if (want > *buflen) { 158 errno = ERANGE; 159 return NULL; 160 } 161 rv = *buffer; 162 *buffer += want; 163 *buflen -= want; 164 return rv; 165 } 166 167 /* 168 * _gr_parse 169 * Parses entry as a line per group(5) (without the trailing \n) 170 * and fills in grp with corresponding values; memory for strings 171 * and arrays will be allocated from buf (of size buflen). 172 * Returns 1 if parsed successfully, 0 on parse failure. 173 */ 174 static int 175 _gr_parse(const char *entry, struct group *grp, char *buf, size_t buflen) 176 { 177 unsigned long id; 178 const char *bp; 179 char *ep; 180 size_t count; 181 int memc; 182 183 _DIAGASSERT(entry != NULL); 184 _DIAGASSERT(grp != NULL); 185 _DIAGASSERT(buf != NULL); 186 187 #define COPYTOBUF(to) \ 188 do { \ 189 (to) = _gr_memfrombuf(count+1, &buf, &buflen); \ 190 if ((to) == NULL) \ 191 return 0; \ 192 memmove((to), entry, count); \ 193 to[count] = '\0'; \ 194 } while (0) /* LINTED */ 195 196 #if 0 197 if (*entry == '+') /* fail on compat `+' token */ 198 return 0; 199 #endif 200 201 count = strcspn(entry, ":"); /* parse gr_name */ 202 if (entry[count] == '\0') 203 return 0; 204 COPYTOBUF(grp->gr_name); 205 entry += count + 1; 206 207 count = strcspn(entry, ":"); /* parse gr_passwd */ 208 if (entry[count] == '\0') 209 return 0; 210 COPYTOBUF(grp->gr_passwd); 211 entry += count + 1; 212 213 count = strcspn(entry, ":"); /* parse gr_gid */ 214 if (entry[count] == '\0') 215 return 0; 216 id = strtoul(entry, &ep, 10); 217 if (id > GID_MAX || *ep != ':') 218 return 0; 219 grp->gr_gid = (gid_t)id; 220 entry += count + 1; 221 222 memc = 1; /* for final NULL */ 223 if (*entry != '\0') 224 memc++; /* for first item */ 225 for (bp = entry; *bp != '\0'; bp++) { 226 if (*bp == ',') 227 memc++; 228 } 229 /* grab ALIGNed char **gr_mem from buf */ 230 ep = _gr_memfrombuf(memc * sizeof(char *) + ALIGNBYTES, &buf, &buflen); 231 grp->gr_mem = (char **)ALIGN(ep); 232 if (grp->gr_mem == NULL) 233 return 0; 234 235 for (memc = 0; *entry != '\0'; memc++) { 236 count = strcspn(entry, ","); /* parse member */ 237 COPYTOBUF(grp->gr_mem[memc]); 238 entry += count; 239 if (*entry == ',') 240 entry++; 241 } 242 243 #undef COPYTOBUF 244 245 grp->gr_mem[memc] = NULL; 246 return 1; 247 } 248 249 /* 250 * _gr_copy 251 * Copy the contents of fromgrp to grp; memory for strings 252 * and arrays will be allocated from buf (of size buflen). 253 * Returns 1 if copied successfully, 0 on copy failure. 254 * NOTE: fromgrp must not use buf for its own pointers. 255 */ 256 static int 257 _gr_copy(struct group *fromgrp, struct group *grp, char *buf, size_t buflen) 258 { 259 char *ep; 260 int memc; 261 262 _DIAGASSERT(fromgrp != NULL); 263 _DIAGASSERT(grp != NULL); 264 _DIAGASSERT(buf != NULL); 265 266 #define COPYSTR(to, from) \ 267 do { \ 268 size_t count = strlen((from)); \ 269 (to) = _gr_memfrombuf(count+1, &buf, &buflen); \ 270 if ((to) == NULL) \ 271 return 0; \ 272 memmove((to), (from), count); \ 273 to[count] = '\0'; \ 274 } while (0) /* LINTED */ 275 276 COPYSTR(grp->gr_name, fromgrp->gr_name); 277 COPYSTR(grp->gr_passwd, fromgrp->gr_passwd); 278 grp->gr_gid = fromgrp->gr_gid; 279 280 for (memc = 0; fromgrp->gr_mem[memc]; memc++) 281 continue; 282 memc++; /* for final NULL */ 283 284 /* grab ALIGNed char **gr_mem from buf */ 285 ep = _gr_memfrombuf(memc * sizeof(char *) + ALIGNBYTES, &buf, &buflen); 286 grp->gr_mem = (char **)ALIGN(ep); 287 if (grp->gr_mem == NULL) 288 return 0; 289 290 for (memc = 0; fromgrp->gr_mem[memc]; memc++) { 291 COPYSTR(grp->gr_mem[memc], fromgrp->gr_mem[memc]); 292 } 293 294 #undef COPYSTR 295 296 grp->gr_mem[memc] = NULL; 297 return 1; 298 } 299 300 /* 301 * files methods 302 */ 303 304 int 305 __grstart_files(struct __grstate_files *state) 306 { 307 308 _DIAGASSERT(state != NULL); 309 310 if (state->fp == NULL) { 311 state->fp = fopen(_PATH_GROUP, "r"); 312 if (state->fp == NULL) 313 return NS_UNAVAIL; 314 } else { 315 rewind(state->fp); 316 } 317 return NS_SUCCESS; 318 } 319 320 int 321 __grend_files(struct __grstate_files *state) 322 { 323 324 _DIAGASSERT(state != NULL); 325 326 if (state->fp) { 327 (void) fclose(state->fp); 328 state->fp = NULL; 329 } 330 return NS_SUCCESS; 331 } 332 333 /* 334 * __grscan_files 335 * Scan state->fp for the next desired entry. 336 * If search is zero, return the next entry. 337 * If search is non-zero, look for a specific name (if name != NULL), 338 * or a specific gid (if name == NULL). 339 * Sets *retval to the errno if the result is not NS_SUCCESS 340 * or NS_NOTFOUND. 341 */ 342 int 343 __grscan_files(int *retval, struct group *grp, char *buffer, size_t buflen, 344 struct __grstate_files *state, int search, const char *name, gid_t gid) 345 { 346 int rv; 347 char filebuf[_GETGR_R_SIZE_MAX], *ep; 348 349 _DIAGASSERT(retval != NULL); 350 _DIAGASSERT(grp != NULL); 351 _DIAGASSERT(buffer != NULL); 352 _DIAGASSERT(state != NULL); 353 /* name is NULL to indicate searching for gid */ 354 355 *retval = 0; 356 357 if (state->fp == NULL) { /* only start if file not open yet */ 358 rv = __grstart_files(state); 359 if (rv != NS_SUCCESS) 360 goto filesgrscan_out; 361 } 362 363 rv = NS_NOTFOUND; 364 365 /* scan line by line */ 366 while (fgets(filebuf, sizeof(filebuf), state->fp) != NULL) { 367 ep = strchr(filebuf, '\n'); 368 if (ep == NULL) { /* skip lines that are too big */ 369 int ch; 370 371 while ((ch = getc(state->fp)) != '\n' && ch != EOF) 372 continue; 373 continue; 374 } 375 *ep = '\0'; /* clear trailing \n */ 376 377 if (filebuf[0] == '+') /* skip compat line */ 378 continue; 379 380 /* validate line */ 381 if (! _gr_parse(filebuf, grp, buffer, buflen)) { 382 continue; /* skip bad lines */ 383 } 384 if (! search) { /* just want this one */ 385 rv = NS_SUCCESS; 386 break; 387 } 388 /* want specific */ 389 if ((name && strcmp(name, grp->gr_name) == 0) || 390 (!name && gid == grp->gr_gid)) { 391 rv = NS_SUCCESS; 392 break; 393 } 394 } 395 396 filesgrscan_out: 397 if (rv != NS_SUCCESS && rv != NS_NOTFOUND) 398 *retval = errno; 399 return rv; 400 } 401 402 403 static struct __grstate_files _files_state; 404 /* storage for non _r functions */ 405 static struct group _files_group; 406 static char _files_groupbuf[_GETGR_R_SIZE_MAX]; 407 408 /*ARGSUSED*/ 409 static int 410 _files_setgrent(void *nsrv, void *nscb, va_list ap) 411 { 412 413 _files_state.stayopen = 0; 414 return __grstart_files(&_files_state); 415 } 416 417 /*ARGSUSED*/ 418 static int 419 _files_setgroupent(void *nsrv, void *nscb, va_list ap) 420 { 421 int *retval = va_arg(ap, int *); 422 int stayopen = va_arg(ap, int); 423 424 int rv; 425 426 _files_state.stayopen = stayopen; 427 rv = __grstart_files(&_files_state); 428 *retval = (rv == NS_SUCCESS); 429 return rv; 430 } 431 432 /*ARGSUSED*/ 433 static int 434 _files_endgrent(void *nsrv, void *nscb, va_list ap) 435 { 436 437 _files_state.stayopen = 0; 438 return __grend_files(&_files_state); 439 } 440 441 /*ARGSUSED*/ 442 static int 443 _files_getgrent(void *nsrv, void *nscb, va_list ap) 444 { 445 struct group **retval = va_arg(ap, struct group **); 446 447 int rv, rerror; 448 449 _DIAGASSERT(retval != NULL); 450 451 *retval = NULL; 452 rv = __grscan_files(&rerror, &_files_group, 453 _files_groupbuf, sizeof(_files_groupbuf), 454 &_files_state, 0, NULL, 0); 455 if (rv == NS_SUCCESS) 456 *retval = &_files_group; 457 return rv; 458 } 459 460 /*ARGSUSED*/ 461 static int 462 _files_getgrent_r(void *nsrv, void *nscb, va_list ap) 463 { 464 int *retval = va_arg(ap, int *); 465 struct group *grp = va_arg(ap, struct group *); 466 char *buffer = va_arg(ap, char *); 467 size_t buflen = va_arg(ap, size_t); 468 struct group **result = va_arg(ap, struct group **); 469 470 int rv; 471 472 _DIAGASSERT(retval != NULL); 473 _DIAGASSERT(grp != NULL); 474 _DIAGASSERT(buffer != NULL); 475 _DIAGASSERT(result != NULL); 476 477 rv = __grscan_files(retval, grp, buffer, buflen, 478 &_files_state, 0, NULL, 0); 479 if (rv == NS_SUCCESS) 480 *result = grp; 481 else 482 *result = NULL; 483 return rv; 484 } 485 486 /*ARGSUSED*/ 487 static int 488 _files_getgrgid(void *nsrv, void *nscb, va_list ap) 489 { 490 struct group **retval = va_arg(ap, struct group **); 491 gid_t gid = va_arg(ap, gid_t); 492 493 int rv, rerror; 494 495 _DIAGASSERT(retval != NULL); 496 497 *retval = NULL; 498 rv = __grstart_files(&_files_state); 499 if (rv != NS_SUCCESS) 500 return rv; 501 rv = __grscan_files(&rerror, &_files_group, 502 _files_groupbuf, sizeof(_files_groupbuf), 503 &_files_state, 1, NULL, gid); 504 if (!_files_state.stayopen) 505 __grend_files(&_files_state); 506 if (rv == NS_SUCCESS) 507 *retval = &_files_group; 508 return rv; 509 } 510 511 /*ARGSUSED*/ 512 static int 513 _files_getgrgid_r(void *nsrv, void *nscb, va_list ap) 514 { 515 int *retval = va_arg(ap, int *); 516 gid_t gid = va_arg(ap, gid_t); 517 struct group *grp = va_arg(ap, struct group *); 518 char *buffer = va_arg(ap, char *); 519 size_t buflen = va_arg(ap, size_t); 520 struct group **result = va_arg(ap, struct group **); 521 522 struct __grstate_files state; 523 int rv; 524 525 _DIAGASSERT(retval != NULL); 526 _DIAGASSERT(grp != NULL); 527 _DIAGASSERT(buffer != NULL); 528 _DIAGASSERT(result != NULL); 529 530 *result = NULL; 531 memset(&state, 0, sizeof(state)); 532 rv = __grscan_files(retval, grp, buffer, buflen, &state, 1, NULL, gid); 533 __grend_files(&state); 534 if (rv == NS_SUCCESS) 535 *result = grp; 536 return rv; 537 } 538 539 /*ARGSUSED*/ 540 static int 541 _files_getgrnam(void *nsrv, void *nscb, va_list ap) 542 { 543 struct group **retval = va_arg(ap, struct group **); 544 const char *name = va_arg(ap, const char *); 545 546 int rv, rerror; 547 548 _DIAGASSERT(retval != NULL); 549 550 *retval = NULL; 551 rv = __grstart_files(&_files_state); 552 if (rv != NS_SUCCESS) 553 return rv; 554 rv = __grscan_files(&rerror, &_files_group, 555 _files_groupbuf, sizeof(_files_groupbuf), 556 &_files_state, 1, name, 0); 557 if (!_files_state.stayopen) 558 __grend_files(&_files_state); 559 if (rv == NS_SUCCESS) 560 *retval = &_files_group; 561 return rv; 562 } 563 564 /*ARGSUSED*/ 565 static int 566 _files_getgrnam_r(void *nsrv, void *nscb, va_list ap) 567 { 568 int *retval = va_arg(ap, int *); 569 const char *name = va_arg(ap, const char *); 570 struct group *grp = va_arg(ap, struct group *); 571 char *buffer = va_arg(ap, char *); 572 size_t buflen = va_arg(ap, size_t); 573 struct group **result = va_arg(ap, struct group **); 574 575 struct __grstate_files state; 576 int rv; 577 578 _DIAGASSERT(retval != NULL); 579 _DIAGASSERT(grp != NULL); 580 _DIAGASSERT(buffer != NULL); 581 _DIAGASSERT(result != NULL); 582 583 *result = NULL; 584 memset(&state, 0, sizeof(state)); 585 rv = __grscan_files(retval, grp, buffer, buflen, &state, 1, name, 0); 586 __grend_files(&state); 587 if (rv == NS_SUCCESS) 588 *result = grp; 589 return rv; 590 } 591 592 593 #ifdef HESIOD 594 /* 595 * dns methods 596 */ 597 598 int 599 __grstart_dns(struct __grstate_dns *state) 600 { 601 602 _DIAGASSERT(state != NULL); 603 604 state->num = 0; 605 if (state->context == NULL) { /* setup Hesiod */ 606 if (hesiod_init(&state->context) == -1) 607 return NS_UNAVAIL; 608 } 609 610 return NS_SUCCESS; 611 } 612 613 int 614 __grend_dns(struct __grstate_dns *state) 615 { 616 617 _DIAGASSERT(state != NULL); 618 619 state->num = 0; 620 if (state->context) { 621 hesiod_end(state->context); 622 state->context = NULL; 623 } 624 return NS_SUCCESS; 625 } 626 627 /* 628 * __grscan_dns 629 * Search Hesiod for the next desired entry. 630 * If search is zero, return the next entry. 631 * If search is non-zero, look for a specific name (if name != NULL), 632 * or a specific gid (if name == NULL). 633 */ 634 int 635 __grscan_dns(int *retval, struct group *grp, char *buffer, size_t buflen, 636 struct __grstate_dns *state, int search, const char *name, gid_t gid) 637 { 638 const char **curzone; 639 char **hp, *ep; 640 int rv; 641 642 static const char *zones_gid_group[] = { 643 "gid", 644 "group", 645 NULL 646 }; 647 648 static const char *zones_group[] = { 649 "group", 650 NULL 651 }; 652 653 _DIAGASSERT(retval != NULL); 654 _DIAGASSERT(grp != NULL); 655 _DIAGASSERT(buffer != NULL); 656 _DIAGASSERT(state != NULL); 657 /* name is NULL to indicate searching for gid */ 658 659 *retval = 0; 660 661 if (state->context == NULL) { /* only start if Hesiod not setup */ 662 rv = __grstart_dns(state); 663 if (rv != NS_SUCCESS) 664 return rv; 665 } 666 667 next_dns_entry: 668 hp = NULL; 669 rv = NS_NOTFOUND; 670 671 if (! search) { /* find next entry */ 672 if (state->num == -1) /* exhausted search */ 673 return NS_NOTFOUND; 674 /* find group-NNN */ 675 snprintf(buffer, buflen, "group-%u", state->num); 676 state->num++; 677 curzone = zones_group; 678 } else if (name) { /* find group name */ 679 snprintf(buffer, buflen, "%s", name); 680 curzone = zones_group; 681 } else { /* find gid */ 682 snprintf(buffer, buflen, "%u", (unsigned int)gid); 683 curzone = zones_gid_group; 684 } 685 686 for (; *curzone; curzone++) { /* search zones */ 687 hp = hesiod_resolve(state->context, buffer, *curzone); 688 if (hp != NULL) 689 break; 690 if (errno != ENOENT) { 691 rv = NS_UNAVAIL; 692 goto dnsgrscan_out; 693 } 694 } 695 if (*curzone == NULL) { 696 if (! search) 697 state->num = -1; 698 goto dnsgrscan_out; 699 } 700 701 if ((ep = strchr(hp[0], '\n')) != NULL) 702 *ep = '\0'; /* clear trailing \n */ 703 if (_gr_parse(hp[0], grp, buffer, buflen)) { /* validate line */ 704 if (! search) { /* just want this one */ 705 rv = NS_SUCCESS; 706 } else if ((name && strcmp(name, grp->gr_name) == 0) || 707 (!name && gid == grp->gr_gid)) { /* want specific */ 708 rv = NS_SUCCESS; 709 } 710 } else { /* dodgy entry */ 711 if (!search) { /* try again if ! searching */ 712 hesiod_free_list(state->context, hp); 713 goto next_dns_entry; 714 } 715 } 716 717 dnsgrscan_out: 718 if (rv != NS_SUCCESS && rv != NS_NOTFOUND) 719 *retval = errno; 720 if (hp) 721 hesiod_free_list(state->context, hp); 722 return rv; 723 } 724 725 static struct __grstate_dns _dns_state; 726 /* storage for non _r functions */ 727 static struct group _dns_group; 728 static char _dns_groupbuf[_GETGR_R_SIZE_MAX]; 729 730 /*ARGSUSED*/ 731 static int 732 _dns_setgrent(void *nsrv, void *nscb, va_list ap) 733 { 734 735 _dns_state.stayopen = 0; 736 return __grstart_dns(&_dns_state); 737 } 738 739 /*ARGSUSED*/ 740 static int 741 _dns_setgroupent(void *nsrv, void *nscb, va_list ap) 742 { 743 int *retval = va_arg(ap, int *); 744 int stayopen = va_arg(ap, int); 745 746 int rv; 747 748 _dns_state.stayopen = stayopen; 749 rv = __grstart_dns(&_dns_state); 750 *retval = (rv == NS_SUCCESS); 751 return rv; 752 } 753 754 /*ARGSUSED*/ 755 static int 756 _dns_endgrent(void *nsrv, void *nscb, va_list ap) 757 { 758 759 _dns_state.stayopen = 0; 760 return __grend_dns(&_dns_state); 761 } 762 763 /*ARGSUSED*/ 764 static int 765 _dns_getgrent(void *nsrv, void *nscb, va_list ap) 766 { 767 struct group **retval = va_arg(ap, struct group **); 768 769 int rv, rerror; 770 771 _DIAGASSERT(retval != NULL); 772 773 *retval = NULL; 774 rv = __grscan_dns(&rerror, &_dns_group, 775 _dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, 0, NULL, 0); 776 if (rv == NS_SUCCESS) 777 *retval = &_dns_group; 778 return rv; 779 } 780 781 /*ARGSUSED*/ 782 static int 783 _dns_getgrent_r(void *nsrv, void *nscb, va_list ap) 784 { 785 int *retval = va_arg(ap, int *); 786 struct group *grp = va_arg(ap, struct group *); 787 char *buffer = va_arg(ap, char *); 788 size_t buflen = va_arg(ap, size_t); 789 struct group **result = va_arg(ap, struct group **); 790 791 int rv; 792 793 _DIAGASSERT(retval != NULL); 794 _DIAGASSERT(grp != NULL); 795 _DIAGASSERT(buffer != NULL); 796 _DIAGASSERT(result != NULL); 797 798 rv = __grscan_dns(retval, grp, buffer, buflen, 799 &_dns_state, 0, NULL, 0); 800 if (rv == NS_SUCCESS) 801 *result = grp; 802 else 803 *result = NULL; 804 return rv; 805 } 806 /*ARGSUSED*/ 807 static int 808 _dns_getgrgid(void *nsrv, void *nscb, va_list ap) 809 { 810 struct group **retval = va_arg(ap, struct group **); 811 gid_t gid = va_arg(ap, gid_t); 812 813 int rv, rerror; 814 815 _DIAGASSERT(retval != NULL); 816 817 *retval = NULL; 818 rv = __grstart_dns(&_dns_state); 819 if (rv != NS_SUCCESS) 820 return rv; 821 rv = __grscan_dns(&rerror, &_dns_group, 822 _dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, 1, NULL, gid); 823 if (!_dns_state.stayopen) 824 __grend_dns(&_dns_state); 825 if (rv == NS_SUCCESS) 826 *retval = &_dns_group; 827 return rv; 828 } 829 830 /*ARGSUSED*/ 831 static int 832 _dns_getgrgid_r(void *nsrv, void *nscb, va_list ap) 833 { 834 int *retval = va_arg(ap, int *); 835 gid_t gid = va_arg(ap, gid_t); 836 struct group *grp = va_arg(ap, struct group *); 837 char *buffer = va_arg(ap, char *); 838 size_t buflen = va_arg(ap, size_t); 839 struct group **result = va_arg(ap, struct group **); 840 841 struct __grstate_dns state; 842 int rv; 843 844 _DIAGASSERT(retval != NULL); 845 _DIAGASSERT(grp != NULL); 846 _DIAGASSERT(buffer != NULL); 847 _DIAGASSERT(result != NULL); 848 849 *result = NULL; 850 memset(&state, 0, sizeof(state)); 851 rv = __grscan_dns(retval, grp, buffer, buflen, &state, 1, NULL, gid); 852 __grend_dns(&state); 853 if (rv == NS_SUCCESS) 854 *result = grp; 855 return rv; 856 } 857 858 /*ARGSUSED*/ 859 static int 860 _dns_getgrnam(void *nsrv, void *nscb, va_list ap) 861 { 862 struct group **retval = va_arg(ap, struct group **); 863 const char *name = va_arg(ap, const char *); 864 865 int rv, rerror; 866 867 _DIAGASSERT(retval != NULL); 868 869 *retval = NULL; 870 rv = __grstart_dns(&_dns_state); 871 if (rv != NS_SUCCESS) 872 return rv; 873 rv = __grscan_dns(&rerror, &_dns_group, 874 _dns_groupbuf, sizeof(_dns_groupbuf), &_dns_state, 1, name, 0); 875 if (!_dns_state.stayopen) 876 __grend_dns(&_dns_state); 877 if (rv == NS_SUCCESS) 878 *retval = &_dns_group; 879 return rv; 880 } 881 882 /*ARGSUSED*/ 883 static int 884 _dns_getgrnam_r(void *nsrv, void *nscb, va_list ap) 885 { 886 int *retval = va_arg(ap, int *); 887 const char *name = va_arg(ap, const char *); 888 struct group *grp = va_arg(ap, struct group *); 889 char *buffer = va_arg(ap, char *); 890 size_t buflen = va_arg(ap, size_t); 891 struct group **result = va_arg(ap, struct group **); 892 893 struct __grstate_dns state; 894 int rv; 895 896 _DIAGASSERT(retval != NULL); 897 _DIAGASSERT(grp != NULL); 898 _DIAGASSERT(buffer != NULL); 899 _DIAGASSERT(result != NULL); 900 901 *result = NULL; 902 memset(&state, 0, sizeof(state)); 903 rv = __grscan_dns(retval, grp, buffer, buflen, &state, 1, name, 0); 904 __grend_dns(&state); 905 if (rv == NS_SUCCESS) 906 *result = grp; 907 return rv; 908 } 909 910 #endif /* HESIOD */ 911 912 913 #ifdef YP 914 /* 915 * nis methods 916 */ 917 918 int 919 __grstart_nis(struct __grstate_nis *state) 920 { 921 922 _DIAGASSERT(state != NULL); 923 924 state->done = 0; 925 if (state->current) { 926 free(state->current); 927 state->current = NULL; 928 } 929 if (state->domain == NULL) { /* setup NIS */ 930 switch (yp_get_default_domain(&state->domain)) { 931 case 0: 932 break; 933 case YPERR_RESRC: 934 return NS_TRYAGAIN; 935 default: 936 return NS_UNAVAIL; 937 } 938 } 939 return NS_SUCCESS; 940 } 941 942 int 943 __grend_nis(struct __grstate_nis *state) 944 { 945 946 _DIAGASSERT(state != NULL); 947 948 if (state->domain) { 949 state->domain = NULL; 950 } 951 state->done = 0; 952 if (state->current) { 953 free(state->current); 954 state->current = NULL; 955 } 956 return NS_SUCCESS; 957 } 958 959 /* 960 * __grscan_nis 961 * Search NIS for the next desired entry. 962 * If search is zero, return the next entry. 963 * If search is non-zero, look for a specific name (if name != NULL), 964 * or a specific gid (if name == NULL). 965 */ 966 int 967 __grscan_nis(int *retval, struct group *grp, char *buffer, size_t buflen, 968 struct __grstate_nis *state, int search, const char *name, gid_t gid) 969 { 970 const char *map; 971 char *key, *data; 972 int nisr, rv, keylen, datalen; 973 974 _DIAGASSERT(retval != NULL); 975 _DIAGASSERT(grp != NULL); 976 _DIAGASSERT(buffer != NULL); 977 _DIAGASSERT(state != NULL); 978 /* name is NULL to indicate searching for gid */ 979 980 *retval = 0; 981 982 if (state->domain == NULL) { /* only start if NIS not setup */ 983 rv = __grstart_nis(state); 984 if (rv != NS_SUCCESS) 985 return rv; 986 } 987 988 next_nis_entry: 989 key = NULL; 990 data = NULL; 991 rv = NS_SUCCESS; 992 993 if (! search) { /* find next entry */ 994 if (state->done) /* exhausted search */ 995 return NS_NOTFOUND; 996 map = "group.byname"; 997 if (state->current) { /* already searching */ 998 nisr = yp_next(state->domain, map, 999 state->current, state->currentlen, 1000 &key, &keylen, &data, &datalen); 1001 free(state->current); 1002 state->current = NULL; 1003 switch (nisr) { 1004 case 0: 1005 state->current = key; 1006 state->currentlen = keylen; 1007 key = NULL; 1008 break; 1009 case YPERR_NOMORE: 1010 rv = NS_NOTFOUND; 1011 state->done = 1; 1012 break; 1013 default: 1014 rv = NS_UNAVAIL; 1015 break; 1016 } 1017 } else { /* new search */ 1018 if (yp_first(state->domain, map, 1019 &state->current, &state->currentlen, 1020 &data, &datalen)) { 1021 rv = NS_UNAVAIL; 1022 } 1023 } 1024 } else { /* search for specific item */ 1025 if (name) { /* find group name */ 1026 snprintf(buffer, buflen, "%s", name); 1027 map = "group.byname"; 1028 } else { /* find gid */ 1029 snprintf(buffer, buflen, "%u", (unsigned int)gid); 1030 map = "group.bygid"; 1031 } 1032 nisr = yp_match(state->domain, map, buffer, (int)strlen(buffer), 1033 &data, &datalen); 1034 switch (nisr) { 1035 case 0: 1036 break; 1037 case YPERR_KEY: 1038 rv = NS_NOTFOUND; 1039 break; 1040 default: 1041 rv = NS_UNAVAIL; 1042 break; 1043 } 1044 } 1045 if (rv == NS_SUCCESS) { /* validate data */ 1046 data[datalen] = '\0'; /* clear trailing \n */ 1047 if (_gr_parse(data, grp, buffer, buflen)) { 1048 if (! search) { /* just want this one */ 1049 rv = NS_SUCCESS; 1050 } else if ((name && strcmp(name, grp->gr_name) == 0) || 1051 (!name && gid == grp->gr_gid)) { 1052 /* want specific */ 1053 rv = NS_SUCCESS; 1054 } 1055 } else { /* dodgy entry */ 1056 if (!search) { /* try again if ! searching */ 1057 if (key) 1058 free(key); 1059 free(data); 1060 goto next_nis_entry; 1061 } 1062 } 1063 } 1064 1065 if (rv != NS_SUCCESS && rv != NS_NOTFOUND) 1066 *retval = errno; 1067 if (key) 1068 free(key); 1069 if (data) 1070 free(data); 1071 return rv; 1072 } 1073 1074 static struct __grstate_nis _nis_state; 1075 /* storage for non _r functions */ 1076 static struct group _nis_group; 1077 static char _nis_groupbuf[_GETGR_R_SIZE_MAX]; 1078 1079 /*ARGSUSED*/ 1080 static int 1081 _nis_setgrent(void *nsrv, void *nscb, va_list ap) 1082 { 1083 1084 _nis_state.stayopen = 0; 1085 return __grstart_nis(&_nis_state); 1086 } 1087 1088 /*ARGSUSED*/ 1089 static int 1090 _nis_setgroupent(void *nsrv, void *nscb, va_list ap) 1091 { 1092 int *retval = va_arg(ap, int *); 1093 int stayopen = va_arg(ap, int); 1094 1095 int rv; 1096 1097 _nis_state.stayopen = stayopen; 1098 rv = __grstart_nis(&_nis_state); 1099 *retval = (rv == NS_SUCCESS); 1100 return rv; 1101 } 1102 1103 /*ARGSUSED*/ 1104 static int 1105 _nis_endgrent(void *nsrv, void *nscb, va_list ap) 1106 { 1107 1108 return __grend_nis(&_nis_state); 1109 } 1110 1111 /*ARGSUSED*/ 1112 static int 1113 _nis_getgrent(void *nsrv, void *nscb, va_list ap) 1114 { 1115 struct group **retval = va_arg(ap, struct group **); 1116 1117 int rv, rerror; 1118 1119 _DIAGASSERT(retval != NULL); 1120 1121 *retval = NULL; 1122 rv = __grscan_nis(&rerror, &_nis_group, 1123 _nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, 0, NULL, 0); 1124 if (rv == NS_SUCCESS) 1125 *retval = &_nis_group; 1126 return rv; 1127 } 1128 1129 /*ARGSUSED*/ 1130 static int 1131 _nis_getgrent_r(void *nsrv, void *nscb, va_list ap) 1132 { 1133 int *retval = va_arg(ap, int *); 1134 struct group *grp = va_arg(ap, struct group *); 1135 char *buffer = va_arg(ap, char *); 1136 size_t buflen = va_arg(ap, size_t); 1137 struct group **result = va_arg(ap, struct group **); 1138 1139 int rv; 1140 1141 _DIAGASSERT(retval != NULL); 1142 _DIAGASSERT(grp != NULL); 1143 _DIAGASSERT(buffer != NULL); 1144 _DIAGASSERT(result != NULL); 1145 1146 rv = __grscan_nis(retval, grp, buffer, buflen, 1147 &_nis_state, 0, NULL, 0); 1148 if (rv == NS_SUCCESS) 1149 *result = grp; 1150 else 1151 *result = NULL; 1152 return rv; 1153 } 1154 1155 /*ARGSUSED*/ 1156 static int 1157 _nis_getgrgid(void *nsrv, void *nscb, va_list ap) 1158 { 1159 struct group **retval = va_arg(ap, struct group **); 1160 gid_t gid = va_arg(ap, gid_t); 1161 1162 int rv, rerror; 1163 1164 _DIAGASSERT(retval != NULL); 1165 1166 *retval = NULL; 1167 rv = __grstart_nis(&_nis_state); 1168 if (rv != NS_SUCCESS) 1169 return rv; 1170 rv = __grscan_nis(&rerror, &_nis_group, 1171 _nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, 1, NULL, gid); 1172 if (!_nis_state.stayopen) 1173 __grend_nis(&_nis_state); 1174 if (rv == NS_SUCCESS) 1175 *retval = &_nis_group; 1176 return rv; 1177 } 1178 1179 /*ARGSUSED*/ 1180 static int 1181 _nis_getgrgid_r(void *nsrv, void *nscb, va_list ap) 1182 { 1183 int *retval = va_arg(ap, int *); 1184 gid_t gid = va_arg(ap, gid_t); 1185 struct group *grp = va_arg(ap, struct group *); 1186 char *buffer = va_arg(ap, char *); 1187 size_t buflen = va_arg(ap, size_t); 1188 struct group **result = va_arg(ap, struct group **); 1189 1190 struct __grstate_nis state; 1191 int rv; 1192 1193 _DIAGASSERT(retval != NULL); 1194 _DIAGASSERT(grp != NULL); 1195 _DIAGASSERT(buffer != NULL); 1196 _DIAGASSERT(result != NULL); 1197 1198 *result = NULL; 1199 memset(&state, 0, sizeof(state)); 1200 rv = __grscan_nis(retval, grp, buffer, buflen, &state, 1, NULL, gid); 1201 __grend_nis(&state); 1202 if (rv == NS_SUCCESS) 1203 *result = grp; 1204 return rv; 1205 } 1206 1207 /*ARGSUSED*/ 1208 static int 1209 _nis_getgrnam(void *nsrv, void *nscb, va_list ap) 1210 { 1211 struct group **retval = va_arg(ap, struct group **); 1212 const char *name = va_arg(ap, const char *); 1213 1214 int rv, rerror; 1215 1216 _DIAGASSERT(retval != NULL); 1217 1218 *retval = NULL; 1219 rv = __grstart_nis(&_nis_state); 1220 if (rv != NS_SUCCESS) 1221 return rv; 1222 rv = __grscan_nis(&rerror, &_nis_group, 1223 _nis_groupbuf, sizeof(_nis_groupbuf), &_nis_state, 1, name, 0); 1224 if (!_nis_state.stayopen) 1225 __grend_nis(&_nis_state); 1226 if (rv == NS_SUCCESS) 1227 *retval = &_nis_group; 1228 return rv; 1229 } 1230 1231 /*ARGSUSED*/ 1232 static int 1233 _nis_getgrnam_r(void *nsrv, void *nscb, va_list ap) 1234 { 1235 int *retval = va_arg(ap, int *); 1236 const char *name = va_arg(ap, const char *); 1237 struct group *grp = va_arg(ap, struct group *); 1238 char *buffer = va_arg(ap, char *); 1239 size_t buflen = va_arg(ap, size_t); 1240 struct group **result = va_arg(ap, struct group **); 1241 1242 struct __grstate_nis state; 1243 int rv; 1244 1245 _DIAGASSERT(retval != NULL); 1246 _DIAGASSERT(grp != NULL); 1247 _DIAGASSERT(buffer != NULL); 1248 _DIAGASSERT(result != NULL); 1249 1250 *result = NULL; 1251 memset(&state, 0, sizeof(state)); 1252 rv = __grscan_nis(retval, grp, buffer, buflen, &state, 1, name, 0); 1253 __grend_nis(&state); 1254 if (rv == NS_SUCCESS) 1255 *result = grp; 1256 return rv; 1257 } 1258 1259 #endif /* YP */ 1260 1261 1262 #ifdef _GROUP_COMPAT 1263 /* 1264 * compat methods 1265 */ 1266 1267 int 1268 __grstart_compat(struct __grstate_compat *state) 1269 { 1270 1271 _DIAGASSERT(state != NULL); 1272 1273 if (state->fp == NULL) { 1274 state->fp = fopen(_PATH_GROUP, "r"); 1275 if (state->fp == NULL) 1276 return NS_UNAVAIL; 1277 } else { 1278 rewind(state->fp); 1279 } 1280 return NS_SUCCESS; 1281 } 1282 1283 int 1284 __grend_compat(struct __grstate_compat *state) 1285 { 1286 1287 _DIAGASSERT(state != NULL); 1288 1289 if (state->name) { 1290 free(state->name); 1291 state->name = NULL; 1292 } 1293 if (state->fp) { 1294 (void) fclose(state->fp); 1295 state->fp = NULL; 1296 } 1297 return NS_SUCCESS; 1298 } 1299 1300 1301 /* 1302 * __grbad_compat 1303 * log an error if "files" or "compat" is specified in 1304 * group_compat database 1305 */ 1306 /*ARGSUSED*/ 1307 int 1308 __grbad_compat(void *nsrv, void *nscb, va_list ap) 1309 { 1310 static int warned; 1311 1312 _DIAGASSERT(cb_data != NULL); 1313 1314 if (!warned) { 1315 syslog(LOG_ERR, 1316 "nsswitch.conf group_compat database can't use '%s'", 1317 (const char *)nscb); 1318 } 1319 warned = 1; 1320 return NS_UNAVAIL; 1321 } 1322 1323 /* 1324 * __grscan_compat 1325 * Scan state->fp for the next desired entry. 1326 * If search is zero, return the next entry. 1327 * If search is non-zero, look for a specific name (if name != NULL), 1328 * or a specific gid (if name == NULL). 1329 * Sets *retval to the errno if the result is not NS_SUCCESS or 1330 * NS_NOTFOUND. 1331 * 1332 * searchfunc is invoked when a compat "+" lookup is required; 1333 * searchcookie is passed as the first argument to searchfunc, 1334 * the second argument is the group result. 1335 * This should return NS_NOTFOUND when "no more groups" from compat src. 1336 * If searchfunc is NULL then nsdispatch of getgrent is used. 1337 * This is primarily intended for getgroupmembership(3)'s compat backend. 1338 */ 1339 int 1340 __grscan_compat(int *retval, struct group *grp, char *buffer, size_t buflen, 1341 struct __grstate_compat *state, int search, const char *name, gid_t gid, 1342 int (*searchfunc)(void *, struct group **), void *searchcookie) 1343 { 1344 int rv; 1345 char filebuf[_GETGR_R_SIZE_MAX], *ep; 1346 1347 static const ns_dtab compatentdtab[] = { 1348 NS_FILES_CB(__grbad_compat, "files") 1349 NS_DNS_CB(_dns_getgrent_r, NULL) 1350 NS_NIS_CB(_nis_getgrent_r, NULL) 1351 NS_COMPAT_CB(__grbad_compat, "compat") 1352 { 0 } 1353 }; 1354 static const ns_dtab compatgiddtab[] = { 1355 NS_FILES_CB(__grbad_compat, "files") 1356 NS_DNS_CB(_dns_getgrgid_r, NULL) 1357 NS_NIS_CB(_nis_getgrgid_r, NULL) 1358 NS_COMPAT_CB(__grbad_compat, "compat") 1359 { 0 } 1360 }; 1361 static const ns_dtab compatnamdtab[] = { 1362 NS_FILES_CB(__grbad_compat, "files") 1363 NS_DNS_CB(_dns_getgrnam_r, NULL) 1364 NS_NIS_CB(_nis_getgrnam_r, NULL) 1365 NS_COMPAT_CB(__grbad_compat, "compat") 1366 { 0 } 1367 }; 1368 1369 _DIAGASSERT(retval != NULL); 1370 _DIAGASSERT(grp != NULL); 1371 _DIAGASSERT(buffer != NULL); 1372 _DIAGASSERT(state != NULL); 1373 /* name is NULL to indicate searching for gid */ 1374 1375 *retval = 0; 1376 1377 if (state->fp == NULL) { /* only start if file not open yet */ 1378 rv = __grstart_compat(state); 1379 if (rv != NS_SUCCESS) 1380 goto compatgrscan_out; 1381 } 1382 rv = NS_NOTFOUND; 1383 1384 for (;;) { /* loop through file */ 1385 if (state->name != NULL) { 1386 /* processing compat entry */ 1387 int crv, cretval; 1388 struct group cgrp, *cgrpres; 1389 1390 if (state->name[0]) { /* specific +group: */ 1391 crv = nsdispatch(NULL, compatnamdtab, 1392 NSDB_GROUP_COMPAT, "getgrnam_r", 1393 __nsdefaultnis, 1394 &cretval, state->name, 1395 &cgrp, filebuf, sizeof(filebuf), &cgrpres); 1396 free(state->name); /* (only check 1 grp) */ 1397 state->name = NULL; 1398 } else if (!search) { /* any group */ 1399 if (searchfunc) { 1400 crv = searchfunc(searchcookie, 1401 &cgrpres); 1402 } else { 1403 crv = nsdispatch(NULL, compatentdtab, 1404 NSDB_GROUP_COMPAT, "getgrent_r", 1405 __nsdefaultnis, 1406 &cretval, &cgrp, filebuf, 1407 sizeof(filebuf), &cgrpres); 1408 } 1409 } else if (name) { /* specific group */ 1410 crv = nsdispatch(NULL, compatnamdtab, 1411 NSDB_GROUP_COMPAT, "getgrnam_r", 1412 __nsdefaultnis, 1413 &cretval, name, 1414 &cgrp, filebuf, sizeof(filebuf), &cgrpres); 1415 } else { /* specific gid */ 1416 crv = nsdispatch(NULL, compatgiddtab, 1417 NSDB_GROUP_COMPAT, "getgrgid_r", 1418 __nsdefaultnis, 1419 &cretval, gid, 1420 &cgrp, filebuf, sizeof(filebuf), &cgrpres); 1421 } 1422 if (crv != NS_SUCCESS) { /* not found */ 1423 free(state->name); 1424 state->name = NULL; 1425 continue; /* try next line */ 1426 } 1427 if (!_gr_copy(cgrpres, grp, buffer, buflen)) { 1428 rv = NS_UNAVAIL; 1429 break; 1430 } 1431 goto compatgrscan_cmpgrp; /* skip to grp test */ 1432 } 1433 1434 /* get next file line */ 1435 if (fgets(filebuf, sizeof(filebuf), state->fp) == NULL) 1436 break; 1437 1438 ep = strchr(filebuf, '\n'); 1439 if (ep == NULL) { /* skip lines that are too big */ 1440 int ch; 1441 1442 while ((ch = getc(state->fp)) != '\n' && ch != EOF) 1443 continue; 1444 continue; 1445 } 1446 *ep = '\0'; /* clear trailing \n */ 1447 1448 if (filebuf[0] == '+') { /* parse compat line */ 1449 if (state->name) 1450 free(state->name); 1451 state->name = NULL; 1452 switch(filebuf[1]) { 1453 case ':': 1454 case '\0': 1455 state->name = strdup(""); 1456 break; 1457 default: 1458 ep = strchr(filebuf + 1, ':'); 1459 if (ep == NULL) 1460 break; 1461 *ep = '\0'; 1462 state->name = strdup(filebuf + 1); 1463 break; 1464 } 1465 if (state->name == NULL) { 1466 rv = NS_UNAVAIL; 1467 break; 1468 } 1469 continue; 1470 } 1471 1472 /* validate line */ 1473 if (! _gr_parse(filebuf, grp, buffer, buflen)) { 1474 continue; /* skip bad lines */ 1475 } 1476 1477 compatgrscan_cmpgrp: 1478 if (! search) { /* just want this one */ 1479 rv = NS_SUCCESS; 1480 break; 1481 } 1482 /* want specific */ 1483 if ((name && strcmp(name, grp->gr_name) == 0) || 1484 (!name && gid == grp->gr_gid)) { 1485 rv = NS_SUCCESS; 1486 break; 1487 } 1488 1489 } 1490 1491 compatgrscan_out: 1492 if (rv != NS_SUCCESS && rv != NS_NOTFOUND) 1493 *retval = errno; 1494 return rv; 1495 } 1496 1497 static struct __grstate_compat _compat_state; 1498 /* storage for non _r functions */ 1499 static struct group _compat_group; 1500 static char _compat_groupbuf[_GETGR_R_SIZE_MAX]; 1501 1502 /*ARGSUSED*/ 1503 static int 1504 _compat_setgrent(void *nsrv, void *nscb, va_list ap) 1505 { 1506 static const ns_dtab dtab[] = { 1507 NS_FILES_CB(__grbad_compat, "files") 1508 NS_DNS_CB(_dns_setgrent, NULL) 1509 NS_NIS_CB(_nis_setgrent, NULL) 1510 NS_COMPAT_CB(__grbad_compat, "compat") 1511 { 0 } 1512 }; 1513 1514 /* force group_compat setgrent() */ 1515 (void) nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgrent", 1516 __nsdefaultnis_forceall); 1517 1518 /* reset state, keep fp open */ 1519 _compat_state.stayopen = 0; 1520 return __grstart_compat(&_compat_state); 1521 } 1522 1523 /*ARGSUSED*/ 1524 static int 1525 _compat_setgroupent(void *nsrv, void *nscb, va_list ap) 1526 { 1527 int *retval = va_arg(ap, int *); 1528 int stayopen = va_arg(ap, int); 1529 1530 int rv; 1531 1532 static const ns_dtab dtab[] = { 1533 NS_FILES_CB(__grbad_compat, "files") 1534 NS_DNS_CB(_dns_setgroupent, NULL) 1535 NS_NIS_CB(_nis_setgroupent, NULL) 1536 NS_COMPAT_CB(__grbad_compat, "compat") 1537 { 0 } 1538 }; 1539 1540 /* force group_compat setgroupent() */ 1541 (void) nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgroupent", 1542 __nsdefaultnis_forceall, &rv, stayopen); 1543 1544 _compat_state.stayopen = stayopen; 1545 rv = __grstart_compat(&_compat_state); 1546 *retval = (rv == NS_SUCCESS); 1547 return rv; 1548 } 1549 1550 /*ARGSUSED*/ 1551 static int 1552 _compat_endgrent(void *nsrv, void *nscb, va_list ap) 1553 { 1554 static const ns_dtab dtab[] = { 1555 NS_FILES_CB(__grbad_compat, "files") 1556 NS_DNS_CB(_dns_endgrent, NULL) 1557 NS_NIS_CB(_nis_endgrent, NULL) 1558 NS_COMPAT_CB(__grbad_compat, "compat") 1559 { 0 } 1560 }; 1561 1562 /* force group_compat endgrent() */ 1563 (void) nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "endgrent", 1564 __nsdefaultnis_forceall); 1565 1566 /* reset state, close fp */ 1567 _compat_state.stayopen = 0; 1568 return __grend_compat(&_compat_state); 1569 } 1570 1571 /*ARGSUSED*/ 1572 static int 1573 _compat_getgrent(void *nsrv, void *nscb, va_list ap) 1574 { 1575 struct group **retval = va_arg(ap, struct group **); 1576 1577 int rv, rerror; 1578 1579 _DIAGASSERT(retval != NULL); 1580 1581 *retval = NULL; 1582 rv = __grscan_compat(&rerror, &_compat_group, 1583 _compat_groupbuf, sizeof(_compat_groupbuf), 1584 &_compat_state, 0, NULL, 0, NULL, NULL); 1585 if (rv == NS_SUCCESS) 1586 *retval = &_compat_group; 1587 return rv; 1588 } 1589 1590 /*ARGSUSED*/ 1591 static int 1592 _compat_getgrent_r(void *nsrv, void *nscb, va_list ap) 1593 { 1594 int *retval = va_arg(ap, int *); 1595 struct group *grp = va_arg(ap, struct group *); 1596 char *buffer = va_arg(ap, char *); 1597 size_t buflen = va_arg(ap, size_t); 1598 struct group **result = va_arg(ap, struct group **); 1599 1600 int rv; 1601 1602 _DIAGASSERT(retval != NULL); 1603 _DIAGASSERT(grp != NULL); 1604 _DIAGASSERT(buffer != NULL); 1605 _DIAGASSERT(result != NULL); 1606 1607 rv = __grscan_compat(retval, grp, buffer, buflen, 1608 &_compat_state, 0, NULL, 0, NULL, NULL); 1609 if (rv == NS_SUCCESS) 1610 *result = grp; 1611 else 1612 *result = NULL; 1613 return rv; 1614 } 1615 1616 /*ARGSUSED*/ 1617 static int 1618 _compat_getgrgid(void *nsrv, void *nscb, va_list ap) 1619 { 1620 struct group **retval = va_arg(ap, struct group **); 1621 gid_t gid = va_arg(ap, gid_t); 1622 1623 int rv, rerror; 1624 1625 _DIAGASSERT(retval != NULL); 1626 1627 *retval = NULL; 1628 rv = __grstart_compat(&_compat_state); 1629 if (rv != NS_SUCCESS) 1630 return rv; 1631 rv = __grscan_compat(&rerror, &_compat_group, 1632 _compat_groupbuf, sizeof(_compat_groupbuf), 1633 &_compat_state, 1, NULL, gid, NULL, NULL); 1634 if (!_compat_state.stayopen) 1635 __grend_compat(&_compat_state); 1636 if (rv == NS_SUCCESS) 1637 *retval = &_compat_group; 1638 return rv; 1639 } 1640 1641 /*ARGSUSED*/ 1642 static int 1643 _compat_getgrgid_r(void *nsrv, void *nscb, va_list ap) 1644 { 1645 int *retval = va_arg(ap, int *); 1646 gid_t gid = va_arg(ap, gid_t); 1647 struct group *grp = va_arg(ap, struct group *); 1648 char *buffer = va_arg(ap, char *); 1649 size_t buflen = va_arg(ap, size_t); 1650 struct group **result = va_arg(ap, struct group **); 1651 1652 struct __grstate_compat state; 1653 int rv; 1654 1655 _DIAGASSERT(retval != NULL); 1656 _DIAGASSERT(grp != NULL); 1657 _DIAGASSERT(buffer != NULL); 1658 _DIAGASSERT(result != NULL); 1659 1660 *result = NULL; 1661 memset(&state, 0, sizeof(state)); 1662 rv = __grscan_compat(retval, grp, buffer, buflen, &state, 1663 1, NULL, gid, NULL, NULL); 1664 __grend_compat(&state); 1665 if (rv == NS_SUCCESS) 1666 *result = grp; 1667 return rv; 1668 } 1669 1670 /*ARGSUSED*/ 1671 static int 1672 _compat_getgrnam(void *nsrv, void *nscb, va_list ap) 1673 { 1674 struct group **retval = va_arg(ap, struct group **); 1675 const char *name = va_arg(ap, const char *); 1676 1677 int rv, rerror; 1678 1679 _DIAGASSERT(retval != NULL); 1680 1681 *retval = NULL; 1682 rv = __grstart_compat(&_compat_state); 1683 if (rv != NS_SUCCESS) 1684 return rv; 1685 rv = __grscan_compat(&rerror, &_compat_group, 1686 _compat_groupbuf, sizeof(_compat_groupbuf), 1687 &_compat_state, 1, name, 0, NULL, NULL); 1688 if (!_compat_state.stayopen) 1689 __grend_compat(&_compat_state); 1690 if (rv == NS_SUCCESS) 1691 *retval = &_compat_group; 1692 return rv; 1693 } 1694 1695 /*ARGSUSED*/ 1696 static int 1697 _compat_getgrnam_r(void *nsrv, void *nscb, va_list ap) 1698 { 1699 int *retval = va_arg(ap, int *); 1700 const char *name = va_arg(ap, const char *); 1701 struct group *grp = va_arg(ap, struct group *); 1702 char *buffer = va_arg(ap, char *); 1703 size_t buflen = va_arg(ap, size_t); 1704 struct group **result = va_arg(ap, struct group **); 1705 1706 struct __grstate_compat state; 1707 int rv; 1708 1709 _DIAGASSERT(retval != NULL); 1710 _DIAGASSERT(grp != NULL); 1711 _DIAGASSERT(buffer != NULL); 1712 _DIAGASSERT(result != NULL); 1713 1714 *result = NULL; 1715 memset(&state, 0, sizeof(state)); 1716 rv = __grscan_compat(retval, grp, buffer, buflen, &state, 1717 1, name, 0, NULL, NULL); 1718 __grend_compat(&state); 1719 if (rv == NS_SUCCESS) 1720 *result = grp; 1721 return rv; 1722 } 1723 1724 #endif /* _GROUP_COMPAT */ 1725 1726 1727 /* 1728 * public functions 1729 */ 1730 1731 struct group * 1732 getgrent(void) 1733 { 1734 int rv; 1735 struct group *retval; 1736 1737 static const ns_dtab dtab[] = { 1738 NS_FILES_CB(_files_getgrent, NULL) 1739 NS_DNS_CB(_dns_getgrent, NULL) 1740 NS_NIS_CB(_nis_getgrent, NULL) 1741 NS_COMPAT_CB(_compat_getgrent, NULL) 1742 { 0 } 1743 }; 1744 1745 mutex_lock(&__grmutex); 1746 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrent", __nsdefaultcompat, 1747 &retval); 1748 mutex_unlock(&__grmutex); 1749 return (rv == NS_SUCCESS) ? retval : NULL; 1750 } 1751 1752 int 1753 getgrent_r(struct group *grp, char *buffer, size_t buflen, 1754 struct group **result) 1755 { 1756 int rv, retval; 1757 1758 static const ns_dtab dtab[] = { 1759 NS_FILES_CB(_files_getgrent_r, NULL) 1760 NS_DNS_CB(_dns_getgrent_r, NULL) 1761 NS_NIS_CB(_nis_getgrent_r, NULL) 1762 NS_COMPAT_CB(_compat_getgrent_r, NULL) 1763 { 0 } 1764 }; 1765 1766 mutex_lock(&__grmutex); 1767 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrent_r", __nsdefaultcompat, 1768 &retval, grp, buffer, buflen, result); 1769 mutex_unlock(&__grmutex); 1770 switch (rv) { 1771 case NS_SUCCESS: 1772 case NS_NOTFOUND: 1773 return 0; 1774 default: 1775 return retval; 1776 } 1777 } 1778 1779 1780 struct group * 1781 getgrgid(gid_t gid) 1782 { 1783 int rv; 1784 struct group *retval; 1785 1786 static const ns_dtab dtab[] = { 1787 NS_FILES_CB(_files_getgrgid, NULL) 1788 NS_DNS_CB(_dns_getgrgid, NULL) 1789 NS_NIS_CB(_nis_getgrgid, NULL) 1790 NS_COMPAT_CB(_compat_getgrgid, NULL) 1791 { 0 } 1792 }; 1793 1794 mutex_lock(&__grmutex); 1795 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrgid", __nsdefaultcompat, 1796 &retval, gid); 1797 mutex_unlock(&__grmutex); 1798 return (rv == NS_SUCCESS) ? retval : NULL; 1799 } 1800 1801 int 1802 getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t buflen, 1803 struct group **result) 1804 { 1805 int rv, retval; 1806 1807 static const ns_dtab dtab[] = { 1808 NS_FILES_CB(_files_getgrgid_r, NULL) 1809 NS_DNS_CB(_dns_getgrgid_r, NULL) 1810 NS_NIS_CB(_nis_getgrgid_r, NULL) 1811 NS_COMPAT_CB(_compat_getgrgid_r, NULL) 1812 { 0 } 1813 }; 1814 1815 _DIAGASSERT(grp != NULL); 1816 _DIAGASSERT(buffer != NULL); 1817 _DIAGASSERT(result != NULL); 1818 1819 *result = NULL; 1820 retval = 0; 1821 mutex_lock(&__grmutex); 1822 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrgid_r", __nsdefaultcompat, 1823 &retval, gid, grp, buffer, buflen, result); 1824 mutex_unlock(&__grmutex); 1825 switch (rv) { 1826 case NS_SUCCESS: 1827 case NS_NOTFOUND: 1828 return 0; 1829 default: 1830 return retval; 1831 } 1832 } 1833 1834 struct group * 1835 getgrnam(const char *name) 1836 { 1837 int rv; 1838 struct group *retval; 1839 1840 static const ns_dtab dtab[] = { 1841 NS_FILES_CB(_files_getgrnam, NULL) 1842 NS_DNS_CB(_dns_getgrnam, NULL) 1843 NS_NIS_CB(_nis_getgrnam, NULL) 1844 NS_COMPAT_CB(_compat_getgrnam, NULL) 1845 { 0 } 1846 }; 1847 1848 mutex_lock(&__grmutex); 1849 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrnam", __nsdefaultcompat, 1850 &retval, name); 1851 mutex_unlock(&__grmutex); 1852 return (rv == NS_SUCCESS) ? retval : NULL; 1853 } 1854 1855 int 1856 getgrnam_r(const char *name, struct group *grp, char *buffer, size_t buflen, 1857 struct group **result) 1858 { 1859 int rv, retval; 1860 1861 static const ns_dtab dtab[] = { 1862 NS_FILES_CB(_files_getgrnam_r, NULL) 1863 NS_DNS_CB(_dns_getgrnam_r, NULL) 1864 NS_NIS_CB(_nis_getgrnam_r, NULL) 1865 NS_COMPAT_CB(_compat_getgrnam_r, NULL) 1866 { 0 } 1867 }; 1868 1869 _DIAGASSERT(name != NULL); 1870 _DIAGASSERT(grp != NULL); 1871 _DIAGASSERT(buffer != NULL); 1872 _DIAGASSERT(result != NULL); 1873 1874 *result = NULL; 1875 retval = 0; 1876 mutex_lock(&__grmutex); 1877 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "getgrnam_r", __nsdefaultcompat, 1878 &retval, name, grp, buffer, buflen, result); 1879 mutex_unlock(&__grmutex); 1880 switch (rv) { 1881 case NS_SUCCESS: 1882 case NS_NOTFOUND: 1883 return 0; 1884 default: 1885 return retval; 1886 } 1887 } 1888 1889 void 1890 endgrent(void) 1891 { 1892 static const ns_dtab dtab[] = { 1893 NS_FILES_CB(_files_endgrent, NULL) 1894 NS_DNS_CB(_dns_endgrent, NULL) 1895 NS_NIS_CB(_nis_endgrent, NULL) 1896 NS_COMPAT_CB(_compat_endgrent, NULL) 1897 { 0 } 1898 }; 1899 1900 mutex_lock(&__grmutex); 1901 /* force all endgrent() methods */ 1902 (void) nsdispatch(NULL, dtab, NSDB_GROUP, "endgrent", 1903 __nsdefaultcompat_forceall); 1904 mutex_unlock(&__grmutex); 1905 } 1906 1907 int 1908 setgroupent(int stayopen) 1909 { 1910 static const ns_dtab dtab[] = { 1911 NS_FILES_CB(_files_setgroupent, NULL) 1912 NS_DNS_CB(_dns_setgroupent, NULL) 1913 NS_NIS_CB(_nis_setgroupent, NULL) 1914 NS_COMPAT_CB(_compat_setgroupent, NULL) 1915 { 0 } 1916 }; 1917 int rv, retval; 1918 1919 mutex_lock(&__grmutex); 1920 /* force all setgroupent() methods */ 1921 rv = nsdispatch(NULL, dtab, NSDB_GROUP, "setgroupent", 1922 __nsdefaultcompat_forceall, &retval, stayopen); 1923 mutex_unlock(&__grmutex); 1924 return (rv == NS_SUCCESS) ? retval : 0; 1925 } 1926 1927 void 1928 setgrent(void) 1929 { 1930 static const ns_dtab dtab[] = { 1931 NS_FILES_CB(_files_setgrent, NULL) 1932 NS_DNS_CB(_dns_setgrent, NULL) 1933 NS_NIS_CB(_nis_setgrent, NULL) 1934 NS_COMPAT_CB(_compat_setgrent, NULL) 1935 { 0 } 1936 }; 1937 1938 mutex_lock(&__grmutex); 1939 /* force all setgrent() methods */ 1940 (void) nsdispatch(NULL, dtab, NSDB_GROUP, "setgrent", 1941 __nsdefaultcompat_forceall); 1942 mutex_unlock(&__grmutex); 1943 } 1944