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