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