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