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