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