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