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