1 /*- 2 * Copyright (c) 2003 Networks Associates Technology, Inc. 3 * All rights reserved. 4 * 5 * This software was developed for the FreeBSD Project by 6 * Jacques A. Vidrine, Safeport Network Services, and Network 7 * Associates Laboratories, the Security Research Division of Network 8 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 9 * ("CBOSS"), as part of the DARPA CHATS research program. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 */ 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include "namespace.h" 37 #include <sys/param.h> 38 #ifdef YP 39 #include <rpc/rpc.h> 40 #include <rpcsvc/yp_prot.h> 41 #include <rpcsvc/ypclnt.h> 42 #endif 43 #include <assert.h> 44 #include <ctype.h> 45 #include <errno.h> 46 #ifdef HESIOD 47 #include <hesiod.h> 48 #endif 49 #include <grp.h> 50 #include <nsswitch.h> 51 #include <pthread.h> 52 #include <pthread_np.h> 53 #include <stdio.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #include <syslog.h> 57 #include <unistd.h> 58 #include "un-namespace.h" 59 #include "libc_private.h" 60 #include "nss_tls.h" 61 #ifdef NS_CACHING 62 #include "nscache.h" 63 #endif 64 65 enum constants { 66 GRP_STORAGE_INITIAL = 1 << 10, /* 1 KByte */ 67 GRP_STORAGE_MAX = 1 << 20, /* 1 MByte */ 68 SETGRENT = 1, 69 ENDGRENT = 2, 70 HESIOD_NAME_MAX = 256, 71 }; 72 73 static const ns_src defaultsrc[] = { 74 { NSSRC_COMPAT, NS_SUCCESS }, 75 { NULL, 0 } 76 }; 77 78 int __getgroupmembership(const char *, gid_t, gid_t *, int, int *); 79 int __gr_match_entry(const char *, size_t, enum nss_lookup_type, 80 const char *, gid_t); 81 int __gr_parse_entry(char *, size_t, struct group *, char *, size_t, 82 int *); 83 84 static int is_comment_line(const char *, size_t); 85 86 union key { 87 const char *name; 88 gid_t gid; 89 }; 90 static struct group *getgr(int (*)(union key, struct group *, char *, size_t, 91 struct group **), union key); 92 static int wrap_getgrnam_r(union key, struct group *, char *, size_t, 93 struct group **); 94 static int wrap_getgrgid_r(union key, struct group *, char *, size_t, 95 struct group **); 96 static int wrap_getgrent_r(union key, struct group *, char *, size_t, 97 struct group **); 98 99 struct files_state { 100 FILE *fp; 101 int stayopen; 102 }; 103 static void files_endstate(void *); 104 NSS_TLS_HANDLING(files); 105 static int files_setgrent(void *, void *, va_list); 106 static int files_group(void *, void *, va_list); 107 108 109 #ifdef HESIOD 110 struct dns_state { 111 long counter; 112 }; 113 static void dns_endstate(void *); 114 NSS_TLS_HANDLING(dns); 115 static int dns_setgrent(void *, void *, va_list); 116 static int dns_group(void *, void *, va_list); 117 #endif 118 119 120 #ifdef YP 121 struct nis_state { 122 char domain[MAXHOSTNAMELEN]; 123 int done; 124 char *key; 125 int keylen; 126 }; 127 static void nis_endstate(void *); 128 NSS_TLS_HANDLING(nis); 129 static int nis_setgrent(void *, void *, va_list); 130 static int nis_group(void *, void *, va_list); 131 #endif 132 133 struct compat_state { 134 FILE *fp; 135 int stayopen; 136 char *name; 137 enum _compat { 138 COMPAT_MODE_OFF = 0, 139 COMPAT_MODE_ALL, 140 COMPAT_MODE_NAME 141 } compat; 142 }; 143 static void compat_endstate(void *); 144 NSS_TLS_HANDLING(compat); 145 static int compat_setgrent(void *, void *, va_list); 146 static int compat_group(void *, void *, va_list); 147 148 static int gr_addgid(gid_t, gid_t *, int, int *); 149 static int getgroupmembership_fallback(void *, void *, va_list); 150 151 #ifdef NS_CACHING 152 static int grp_id_func(char *, size_t *, va_list, void *); 153 static int grp_marshal_func(char *, size_t *, void *, va_list, void *); 154 static int grp_unmarshal_func(char *, size_t, void *, va_list, void *); 155 156 static int 157 grp_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata) 158 { 159 char *name; 160 gid_t gid; 161 162 size_t desired_size, size; 163 int res = NS_UNAVAIL; 164 enum nss_lookup_type lookup_type; 165 166 167 lookup_type = (enum nss_lookup_type)cache_mdata; 168 switch (lookup_type) { 169 case nss_lt_name: 170 name = va_arg(ap, char *); 171 size = strlen(name); 172 desired_size = sizeof(enum nss_lookup_type) + size + 1; 173 if (desired_size > *buffer_size) { 174 res = NS_RETURN; 175 goto fin; 176 } 177 178 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 179 memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1); 180 181 res = NS_SUCCESS; 182 break; 183 case nss_lt_id: 184 gid = va_arg(ap, gid_t); 185 desired_size = sizeof(enum nss_lookup_type) + sizeof(gid_t); 186 if (desired_size > *buffer_size) { 187 res = NS_RETURN; 188 goto fin; 189 } 190 191 memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 192 memcpy(buffer + sizeof(enum nss_lookup_type), &gid, 193 sizeof(gid_t)); 194 195 res = NS_SUCCESS; 196 break; 197 default: 198 /* should be unreachable */ 199 return (NS_UNAVAIL); 200 } 201 202 fin: 203 *buffer_size = desired_size; 204 return (res); 205 } 206 207 static int 208 grp_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap, 209 void *cache_mdata) 210 { 211 char *name; 212 gid_t gid; 213 struct group *grp; 214 char *orig_buf; 215 size_t orig_buf_size; 216 217 struct group new_grp; 218 size_t desired_size, size, mem_size; 219 char *p, **mem; 220 221 switch ((enum nss_lookup_type)cache_mdata) { 222 case nss_lt_name: 223 name = va_arg(ap, char *); 224 break; 225 case nss_lt_id: 226 gid = va_arg(ap, gid_t); 227 break; 228 case nss_lt_all: 229 break; 230 default: 231 /* should be unreachable */ 232 return (NS_UNAVAIL); 233 } 234 235 grp = va_arg(ap, struct group *); 236 orig_buf = va_arg(ap, char *); 237 orig_buf_size = va_arg(ap, size_t); 238 239 desired_size = _ALIGNBYTES + sizeof(struct group) + sizeof(char *); 240 241 if (grp->gr_name != NULL) 242 desired_size += strlen(grp->gr_name) + 1; 243 if (grp->gr_passwd != NULL) 244 desired_size += strlen(grp->gr_passwd) + 1; 245 246 if (grp->gr_mem != NULL) { 247 mem_size = 0; 248 for (mem = grp->gr_mem; *mem; ++mem) { 249 desired_size += strlen(*mem) + 1; 250 ++mem_size; 251 } 252 253 desired_size += _ALIGNBYTES + (mem_size + 1) * sizeof(char *); 254 } 255 256 if (desired_size > *buffer_size) { 257 /* this assignment is here for future use */ 258 *buffer_size = desired_size; 259 return (NS_RETURN); 260 } 261 262 memcpy(&new_grp, grp, sizeof(struct group)); 263 memset(buffer, 0, desired_size); 264 265 *buffer_size = desired_size; 266 p = buffer + sizeof(struct group) + sizeof(char *); 267 memcpy(buffer + sizeof(struct group), &p, sizeof(char *)); 268 p = (char *)_ALIGN(p); 269 270 if (new_grp.gr_name != NULL) { 271 size = strlen(new_grp.gr_name); 272 memcpy(p, new_grp.gr_name, size); 273 new_grp.gr_name = p; 274 p += size + 1; 275 } 276 277 if (new_grp.gr_passwd != NULL) { 278 size = strlen(new_grp.gr_passwd); 279 memcpy(p, new_grp.gr_passwd, size); 280 new_grp.gr_passwd = p; 281 p += size + 1; 282 } 283 284 if (new_grp.gr_mem != NULL) { 285 p = (char *)_ALIGN(p); 286 memcpy(p, new_grp.gr_mem, sizeof(char *) * mem_size); 287 new_grp.gr_mem = (char **)p; 288 p += sizeof(char *) * (mem_size + 1); 289 290 for (mem = new_grp.gr_mem; *mem; ++mem) { 291 size = strlen(*mem); 292 memcpy(p, *mem, size); 293 *mem = p; 294 p += size + 1; 295 } 296 } 297 298 memcpy(buffer, &new_grp, sizeof(struct group)); 299 return (NS_SUCCESS); 300 } 301 302 static int 303 grp_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap, 304 void *cache_mdata) 305 { 306 char *name; 307 gid_t gid; 308 struct group *grp; 309 char *orig_buf; 310 size_t orig_buf_size; 311 int *ret_errno; 312 313 char *p; 314 char **mem; 315 316 switch ((enum nss_lookup_type)cache_mdata) { 317 case nss_lt_name: 318 name = va_arg(ap, char *); 319 break; 320 case nss_lt_id: 321 gid = va_arg(ap, gid_t); 322 break; 323 case nss_lt_all: 324 break; 325 default: 326 /* should be unreachable */ 327 return (NS_UNAVAIL); 328 } 329 330 grp = va_arg(ap, struct group *); 331 orig_buf = va_arg(ap, char *); 332 orig_buf_size = va_arg(ap, size_t); 333 ret_errno = va_arg(ap, int *); 334 335 if (orig_buf_size < 336 buffer_size - sizeof(struct group) - sizeof(char *)) { 337 *ret_errno = ERANGE; 338 return (NS_RETURN); 339 } 340 341 memcpy(grp, buffer, sizeof(struct group)); 342 memcpy(&p, buffer + sizeof(struct group), sizeof(char *)); 343 344 orig_buf = (char *)_ALIGN(orig_buf); 345 memcpy(orig_buf, buffer + sizeof(struct group) + sizeof(char *) + 346 _ALIGN(p) - (size_t)p, 347 buffer_size - sizeof(struct group) - sizeof(char *) - 348 _ALIGN(p) + (size_t)p); 349 p = (char *)_ALIGN(p); 350 351 NS_APPLY_OFFSET(grp->gr_name, orig_buf, p, char *); 352 NS_APPLY_OFFSET(grp->gr_passwd, orig_buf, p, char *); 353 if (grp->gr_mem != NULL) { 354 NS_APPLY_OFFSET(grp->gr_mem, orig_buf, p, char **); 355 356 for (mem = grp->gr_mem; *mem; ++mem) 357 NS_APPLY_OFFSET(*mem, orig_buf, p, char *); 358 } 359 360 if (retval != NULL) 361 *((struct group **)retval) = grp; 362 363 return (NS_SUCCESS); 364 } 365 366 NSS_MP_CACHE_HANDLING(group); 367 #endif /* NS_CACHING */ 368 369 #ifdef NS_CACHING 370 static const nss_cache_info setgrent_cache_info = NS_MP_CACHE_INFO_INITIALIZER( 371 group, (void *)nss_lt_all, 372 NULL, NULL); 373 #endif 374 375 static const ns_dtab setgrent_dtab[] = { 376 { NSSRC_FILES, files_setgrent, (void *)SETGRENT }, 377 #ifdef HESIOD 378 { NSSRC_DNS, dns_setgrent, (void *)SETGRENT }, 379 #endif 380 #ifdef YP 381 { NSSRC_NIS, nis_setgrent, (void *)SETGRENT }, 382 #endif 383 { NSSRC_COMPAT, compat_setgrent, (void *)SETGRENT }, 384 #ifdef NS_CACHING 385 NS_CACHE_CB(&setgrent_cache_info) 386 #endif 387 { NULL, NULL, NULL } 388 }; 389 390 #ifdef NS_CACHING 391 static const nss_cache_info endgrent_cache_info = NS_MP_CACHE_INFO_INITIALIZER( 392 group, (void *)nss_lt_all, 393 NULL, NULL); 394 #endif 395 396 static const ns_dtab endgrent_dtab[] = { 397 { NSSRC_FILES, files_setgrent, (void *)ENDGRENT }, 398 #ifdef HESIOD 399 { NSSRC_DNS, dns_setgrent, (void *)ENDGRENT }, 400 #endif 401 #ifdef YP 402 { NSSRC_NIS, nis_setgrent, (void *)ENDGRENT }, 403 #endif 404 { NSSRC_COMPAT, compat_setgrent, (void *)ENDGRENT }, 405 #ifdef NS_CACHING 406 NS_CACHE_CB(&endgrent_cache_info) 407 #endif 408 { NULL, NULL, NULL } 409 }; 410 411 #ifdef NS_CACHING 412 static const nss_cache_info getgrent_r_cache_info = NS_MP_CACHE_INFO_INITIALIZER( 413 group, (void *)nss_lt_all, 414 grp_marshal_func, grp_unmarshal_func); 415 #endif 416 417 static const ns_dtab getgrent_r_dtab[] = { 418 { NSSRC_FILES, files_group, (void *)nss_lt_all }, 419 #ifdef HESIOD 420 { NSSRC_DNS, dns_group, (void *)nss_lt_all }, 421 #endif 422 #ifdef YP 423 { NSSRC_NIS, nis_group, (void *)nss_lt_all }, 424 #endif 425 { NSSRC_COMPAT, compat_group, (void *)nss_lt_all }, 426 #ifdef NS_CACHING 427 NS_CACHE_CB(&getgrent_r_cache_info) 428 #endif 429 { NULL, NULL, NULL } 430 }; 431 432 static int 433 gr_addgid(gid_t gid, gid_t *groups, int maxgrp, int *grpcnt) 434 { 435 int ret, dupc; 436 437 for (dupc = 0; dupc < MIN(maxgrp, *grpcnt); dupc++) { 438 if (groups[dupc] == gid) 439 return 1; 440 } 441 442 ret = 1; 443 if (*grpcnt < maxgrp) 444 groups[*grpcnt] = gid; 445 else 446 ret = 0; 447 448 (*grpcnt)++; 449 450 return ret; 451 } 452 453 static int 454 getgroupmembership_fallback(void *retval, void *mdata, va_list ap) 455 { 456 const ns_src src[] = { 457 { mdata, NS_SUCCESS }, 458 { NULL, 0} 459 }; 460 struct group grp; 461 struct group *grp_p; 462 char *buf; 463 size_t bufsize; 464 const char *uname; 465 gid_t *groups; 466 gid_t agroup; 467 int maxgrp, *grpcnt; 468 int i, rv, ret_errno; 469 470 /* 471 * As this is a fallback method, only provided src 472 * list will be respected during methods search. 473 */ 474 assert(src[0].name != NULL); 475 476 uname = va_arg(ap, const char *); 477 agroup = va_arg(ap, gid_t); 478 groups = va_arg(ap, gid_t *); 479 maxgrp = va_arg(ap, int); 480 grpcnt = va_arg(ap, int *); 481 482 rv = NS_UNAVAIL; 483 484 buf = malloc(GRP_STORAGE_INITIAL); 485 if (buf == NULL) 486 goto out; 487 488 bufsize = GRP_STORAGE_INITIAL; 489 490 gr_addgid(agroup, groups, maxgrp, grpcnt); 491 492 _nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", src, 0); 493 for (;;) { 494 do { 495 ret_errno = 0; 496 grp_p = NULL; 497 rv = _nsdispatch(&grp_p, getgrent_r_dtab, NSDB_GROUP, 498 "getgrent_r", src, &grp, buf, bufsize, &ret_errno); 499 500 if (grp_p == NULL && ret_errno == ERANGE) { 501 free(buf); 502 if ((bufsize << 1) > GRP_STORAGE_MAX) { 503 buf = NULL; 504 errno = ERANGE; 505 goto out; 506 } 507 508 bufsize <<= 1; 509 buf = malloc(bufsize); 510 if (buf == NULL) { 511 goto out; 512 } 513 } 514 } while (grp_p == NULL && ret_errno == ERANGE); 515 516 if (ret_errno != 0) { 517 errno = ret_errno; 518 goto out; 519 } 520 521 if (grp_p == NULL) 522 break; 523 524 for (i = 0; grp.gr_mem[i]; i++) { 525 if (strcmp(grp.gr_mem[i], uname) == 0) 526 gr_addgid(grp.gr_gid, groups, maxgrp, grpcnt); 527 } 528 } 529 530 _nsdispatch(NULL, endgrent_dtab, NSDB_GROUP, "endgrent", src); 531 out: 532 free(buf); 533 return (rv); 534 } 535 536 /* XXX IEEE Std 1003.1, 2003 specifies `void setgrent(void)' */ 537 int 538 setgrent(void) 539 { 540 (void)_nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", defaultsrc, 0); 541 return (1); 542 } 543 544 545 int 546 setgroupent(int stayopen) 547 { 548 (void)_nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", defaultsrc, 549 stayopen); 550 return (1); 551 } 552 553 554 void 555 endgrent(void) 556 { 557 (void)_nsdispatch(NULL, endgrent_dtab, NSDB_GROUP, "endgrent", defaultsrc); 558 } 559 560 561 int 562 getgrent_r(struct group *grp, char *buffer, size_t bufsize, 563 struct group **result) 564 { 565 int rv, ret_errno; 566 567 ret_errno = 0; 568 *result = NULL; 569 rv = _nsdispatch(result, getgrent_r_dtab, NSDB_GROUP, "getgrent_r", defaultsrc, 570 grp, buffer, bufsize, &ret_errno); 571 if (rv == NS_SUCCESS) 572 return (0); 573 else 574 return (ret_errno); 575 } 576 577 578 int 579 getgrnam_r(const char *name, struct group *grp, char *buffer, size_t bufsize, 580 struct group **result) 581 { 582 #ifdef NS_CACHING 583 static const nss_cache_info cache_info = 584 NS_COMMON_CACHE_INFO_INITIALIZER( 585 group, (void *)nss_lt_name, 586 grp_id_func, grp_marshal_func, grp_unmarshal_func); 587 #endif 588 589 static const ns_dtab dtab[] = { 590 { NSSRC_FILES, files_group, (void *)nss_lt_name }, 591 #ifdef HESIOD 592 { NSSRC_DNS, dns_group, (void *)nss_lt_name }, 593 #endif 594 #ifdef YP 595 { NSSRC_NIS, nis_group, (void *)nss_lt_name }, 596 #endif 597 { NSSRC_COMPAT, compat_group, (void *)nss_lt_name }, 598 #ifdef NS_CACHING 599 NS_CACHE_CB(&cache_info) 600 #endif 601 { NULL, NULL, NULL } 602 }; 603 int rv, ret_errno; 604 605 ret_errno = 0; 606 *result = NULL; 607 rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrnam_r", defaultsrc, 608 name, grp, buffer, bufsize, &ret_errno); 609 if (rv == NS_SUCCESS) 610 return (0); 611 else 612 return (ret_errno); 613 } 614 615 616 int 617 getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize, 618 struct group **result) 619 { 620 #ifdef NS_CACHING 621 static const nss_cache_info cache_info = 622 NS_COMMON_CACHE_INFO_INITIALIZER( 623 group, (void *)nss_lt_id, 624 grp_id_func, grp_marshal_func, grp_unmarshal_func); 625 #endif 626 627 static const ns_dtab dtab[] = { 628 { NSSRC_FILES, files_group, (void *)nss_lt_id }, 629 #ifdef HESIOD 630 { NSSRC_DNS, dns_group, (void *)nss_lt_id }, 631 #endif 632 #ifdef YP 633 { NSSRC_NIS, nis_group, (void *)nss_lt_id }, 634 #endif 635 { NSSRC_COMPAT, compat_group, (void *)nss_lt_id }, 636 #ifdef NS_CACHING 637 NS_CACHE_CB(&cache_info) 638 #endif 639 { NULL, NULL, NULL } 640 }; 641 int rv, ret_errno; 642 643 ret_errno = 0; 644 *result = NULL; 645 rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrgid_r", defaultsrc, 646 gid, grp, buffer, bufsize, &ret_errno); 647 if (rv == NS_SUCCESS) 648 return (0); 649 else 650 return (ret_errno); 651 } 652 653 654 655 int 656 __getgroupmembership(const char *uname, gid_t agroup, gid_t *groups, 657 int maxgrp, int *grpcnt) 658 { 659 static const ns_dtab dtab[] = { 660 NS_FALLBACK_CB(getgroupmembership_fallback) 661 { NULL, NULL, NULL } 662 }; 663 int rv; 664 665 assert(uname != NULL); 666 /* groups may be NULL if just sizing when invoked with maxgrp = 0 */ 667 assert(grpcnt != NULL); 668 669 *grpcnt = 0; 670 rv = _nsdispatch(NULL, dtab, NSDB_GROUP, "getgroupmembership", 671 defaultsrc, uname, agroup, groups, maxgrp, grpcnt); 672 673 /* too many groups found? */ 674 return (*grpcnt > maxgrp ? -1 : 0); 675 } 676 677 678 static struct group grp; 679 static char *grp_storage; 680 static size_t grp_storage_size; 681 682 static struct group * 683 getgr(int (*fn)(union key, struct group *, char *, size_t, struct group **), 684 union key key) 685 { 686 int rv; 687 struct group *res; 688 689 if (grp_storage == NULL) { 690 grp_storage = malloc(GRP_STORAGE_INITIAL); 691 if (grp_storage == NULL) 692 return (NULL); 693 grp_storage_size = GRP_STORAGE_INITIAL; 694 } 695 do { 696 rv = fn(key, &grp, grp_storage, grp_storage_size, &res); 697 if (res == NULL && rv == ERANGE) { 698 free(grp_storage); 699 if ((grp_storage_size << 1) > GRP_STORAGE_MAX) { 700 grp_storage = NULL; 701 errno = ERANGE; 702 return (NULL); 703 } 704 grp_storage_size <<= 1; 705 grp_storage = malloc(grp_storage_size); 706 if (grp_storage == NULL) 707 return (NULL); 708 } 709 } while (res == NULL && rv == ERANGE); 710 if (rv != 0) 711 errno = rv; 712 return (res); 713 } 714 715 716 static int 717 wrap_getgrnam_r(union key key, struct group *grp, char *buffer, size_t bufsize, 718 struct group **res) 719 { 720 return (getgrnam_r(key.name, grp, buffer, bufsize, res)); 721 } 722 723 724 static int 725 wrap_getgrgid_r(union key key, struct group *grp, char *buffer, size_t bufsize, 726 struct group **res) 727 { 728 return (getgrgid_r(key.gid, grp, buffer, bufsize, res)); 729 } 730 731 732 static int 733 wrap_getgrent_r(union key key __unused, struct group *grp, char *buffer, 734 size_t bufsize, struct group **res) 735 { 736 return (getgrent_r(grp, buffer, bufsize, res)); 737 } 738 739 740 struct group * 741 getgrnam(const char *name) 742 { 743 union key key; 744 745 key.name = name; 746 return (getgr(wrap_getgrnam_r, key)); 747 } 748 749 750 struct group * 751 getgrgid(gid_t gid) 752 { 753 union key key; 754 755 key.gid = gid; 756 return (getgr(wrap_getgrgid_r, key)); 757 } 758 759 760 struct group * 761 getgrent(void) 762 { 763 union key key; 764 765 key.gid = 0; /* not used */ 766 return (getgr(wrap_getgrent_r, key)); 767 } 768 769 770 static int 771 is_comment_line(const char *s, size_t n) 772 { 773 const char *eom; 774 775 eom = &s[n]; 776 777 for (; s < eom; s++) 778 if (*s == '#' || !isspace((unsigned char)*s)) 779 break; 780 return (*s == '#' || s == eom); 781 } 782 783 784 /* 785 * files backend 786 */ 787 static void 788 files_endstate(void *p) 789 { 790 791 if (p == NULL) 792 return; 793 if (((struct files_state *)p)->fp != NULL) 794 fclose(((struct files_state *)p)->fp); 795 free(p); 796 } 797 798 799 static int 800 files_setgrent(void *retval, void *mdata, va_list ap) 801 { 802 struct files_state *st; 803 int rv, stayopen; 804 805 rv = files_getstate(&st); 806 if (rv != 0) 807 return (NS_UNAVAIL); 808 switch ((enum constants)mdata) { 809 case SETGRENT: 810 stayopen = va_arg(ap, int); 811 if (st->fp != NULL) 812 rewind(st->fp); 813 else if (stayopen) 814 st->fp = fopen(_PATH_GROUP, "re"); 815 break; 816 case ENDGRENT: 817 if (st->fp != NULL) { 818 fclose(st->fp); 819 st->fp = NULL; 820 } 821 break; 822 default: 823 break; 824 } 825 return (NS_UNAVAIL); 826 } 827 828 829 static int 830 files_group(void *retval, void *mdata, va_list ap) 831 { 832 struct files_state *st; 833 enum nss_lookup_type how; 834 const char *name, *line; 835 struct group *grp; 836 gid_t gid; 837 char *buffer; 838 size_t bufsize, linesize; 839 off_t pos; 840 int rv, stayopen, *errnop; 841 842 name = NULL; 843 gid = (gid_t)-1; 844 how = (enum nss_lookup_type)mdata; 845 switch (how) { 846 case nss_lt_name: 847 name = va_arg(ap, const char *); 848 break; 849 case nss_lt_id: 850 gid = va_arg(ap, gid_t); 851 break; 852 case nss_lt_all: 853 break; 854 default: 855 return (NS_NOTFOUND); 856 } 857 grp = va_arg(ap, struct group *); 858 buffer = va_arg(ap, char *); 859 bufsize = va_arg(ap, size_t); 860 errnop = va_arg(ap, int *); 861 *errnop = files_getstate(&st); 862 if (*errnop != 0) 863 return (NS_UNAVAIL); 864 if (st->fp == NULL && 865 ((st->fp = fopen(_PATH_GROUP, "re")) == NULL)) { 866 *errnop = errno; 867 return (NS_UNAVAIL); 868 } 869 if (how == nss_lt_all) 870 stayopen = 1; 871 else { 872 rewind(st->fp); 873 stayopen = st->stayopen; 874 } 875 rv = NS_NOTFOUND; 876 pos = ftello(st->fp); 877 while ((line = fgetln(st->fp, &linesize)) != NULL) { 878 if (line[linesize-1] == '\n') 879 linesize--; 880 rv = __gr_match_entry(line, linesize, how, name, gid); 881 if (rv != NS_SUCCESS) 882 continue; 883 /* We need room at least for the line, a string NUL 884 * terminator, alignment padding, and one (char *) 885 * pointer for the member list terminator. 886 */ 887 if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) { 888 *errnop = ERANGE; 889 rv = NS_RETURN; 890 break; 891 } 892 memcpy(buffer, line, linesize); 893 buffer[linesize] = '\0'; 894 rv = __gr_parse_entry(buffer, linesize, grp, 895 &buffer[linesize + 1], bufsize - linesize - 1, errnop); 896 if (rv & NS_TERMINATE) 897 break; 898 pos = ftello(st->fp); 899 } 900 if (st->fp != NULL && !stayopen) { 901 fclose(st->fp); 902 st->fp = NULL; 903 } 904 if (rv == NS_SUCCESS && retval != NULL) 905 *(struct group **)retval = grp; 906 else if (rv == NS_RETURN && *errnop == ERANGE && st->fp != NULL) 907 fseeko(st->fp, pos, SEEK_SET); 908 return (rv); 909 } 910 911 912 #ifdef HESIOD 913 /* 914 * dns backend 915 */ 916 static void 917 dns_endstate(void *p) 918 { 919 920 free(p); 921 } 922 923 924 static int 925 dns_setgrent(void *retval, void *cb_data, va_list ap) 926 { 927 struct dns_state *st; 928 int rv; 929 930 rv = dns_getstate(&st); 931 if (rv != 0) 932 return (NS_UNAVAIL); 933 st->counter = 0; 934 return (NS_UNAVAIL); 935 } 936 937 938 static int 939 dns_group(void *retval, void *mdata, va_list ap) 940 { 941 char buf[HESIOD_NAME_MAX]; 942 struct dns_state *st; 943 struct group *grp; 944 const char *name, *label; 945 void *ctx; 946 char *buffer, **hes; 947 size_t bufsize, adjsize, linesize; 948 gid_t gid; 949 enum nss_lookup_type how; 950 int rv, *errnop; 951 952 ctx = NULL; 953 hes = NULL; 954 name = NULL; 955 gid = (gid_t)-1; 956 how = (enum nss_lookup_type)mdata; 957 switch (how) { 958 case nss_lt_name: 959 name = va_arg(ap, const char *); 960 break; 961 case nss_lt_id: 962 gid = va_arg(ap, gid_t); 963 break; 964 case nss_lt_all: 965 break; 966 } 967 grp = va_arg(ap, struct group *); 968 buffer = va_arg(ap, char *); 969 bufsize = va_arg(ap, size_t); 970 errnop = va_arg(ap, int *); 971 *errnop = dns_getstate(&st); 972 if (*errnop != 0) 973 return (NS_UNAVAIL); 974 if (hesiod_init(&ctx) != 0) { 975 *errnop = errno; 976 rv = NS_UNAVAIL; 977 goto fin; 978 } 979 do { 980 rv = NS_NOTFOUND; 981 switch (how) { 982 case nss_lt_name: 983 label = name; 984 break; 985 case nss_lt_id: 986 if (snprintf(buf, sizeof(buf), "%lu", 987 (unsigned long)gid) >= sizeof(buf)) 988 goto fin; 989 label = buf; 990 break; 991 case nss_lt_all: 992 if (st->counter < 0) 993 goto fin; 994 if (snprintf(buf, sizeof(buf), "group-%ld", 995 st->counter++) >= sizeof(buf)) 996 goto fin; 997 label = buf; 998 break; 999 } 1000 hes = hesiod_resolve(ctx, label, 1001 how == nss_lt_id ? "gid" : "group"); 1002 if ((how == nss_lt_id && hes == NULL && 1003 (hes = hesiod_resolve(ctx, buf, "group")) == NULL) || 1004 hes == NULL) { 1005 if (how == nss_lt_all) 1006 st->counter = -1; 1007 if (errno != ENOENT) 1008 *errnop = errno; 1009 goto fin; 1010 } 1011 rv = __gr_match_entry(hes[0], strlen(hes[0]), how, name, gid); 1012 if (rv != NS_SUCCESS) { 1013 hesiod_free_list(ctx, hes); 1014 hes = NULL; 1015 continue; 1016 } 1017 /* We need room at least for the line, a string NUL 1018 * terminator, alignment padding, and one (char *) 1019 * pointer for the member list terminator. 1020 */ 1021 adjsize = bufsize - _ALIGNBYTES - sizeof(char *); 1022 linesize = strlcpy(buffer, hes[0], adjsize); 1023 if (linesize >= adjsize) { 1024 *errnop = ERANGE; 1025 rv = NS_RETURN; 1026 goto fin; 1027 } 1028 hesiod_free_list(ctx, hes); 1029 hes = NULL; 1030 rv = __gr_parse_entry(buffer, linesize, grp, 1031 &buffer[linesize + 1], bufsize - linesize - 1, errnop); 1032 } while (how == nss_lt_all && !(rv & NS_TERMINATE)); 1033 fin: 1034 if (hes != NULL) 1035 hesiod_free_list(ctx, hes); 1036 if (ctx != NULL) 1037 hesiod_end(ctx); 1038 if (rv == NS_SUCCESS && retval != NULL) 1039 *(struct group **)retval = grp; 1040 return (rv); 1041 } 1042 #endif /* HESIOD */ 1043 1044 1045 #ifdef YP 1046 /* 1047 * nis backend 1048 */ 1049 static void 1050 nis_endstate(void *p) 1051 { 1052 1053 if (p == NULL) 1054 return; 1055 free(((struct nis_state *)p)->key); 1056 free(p); 1057 } 1058 1059 1060 static int 1061 nis_setgrent(void *retval, void *cb_data, va_list ap) 1062 { 1063 struct nis_state *st; 1064 int rv; 1065 1066 rv = nis_getstate(&st); 1067 if (rv != 0) 1068 return (NS_UNAVAIL); 1069 st->done = 0; 1070 free(st->key); 1071 st->key = NULL; 1072 return (NS_UNAVAIL); 1073 } 1074 1075 1076 static int 1077 nis_group(void *retval, void *mdata, va_list ap) 1078 { 1079 char *map; 1080 struct nis_state *st; 1081 struct group *grp; 1082 const char *name; 1083 char *buffer, *key, *result; 1084 size_t bufsize; 1085 gid_t gid; 1086 enum nss_lookup_type how; 1087 int *errnop, keylen, resultlen, rv; 1088 1089 name = NULL; 1090 gid = (gid_t)-1; 1091 how = (enum nss_lookup_type)mdata; 1092 switch (how) { 1093 case nss_lt_name: 1094 name = va_arg(ap, const char *); 1095 map = "group.byname"; 1096 break; 1097 case nss_lt_id: 1098 gid = va_arg(ap, gid_t); 1099 map = "group.bygid"; 1100 break; 1101 case nss_lt_all: 1102 map = "group.byname"; 1103 break; 1104 } 1105 grp = va_arg(ap, struct group *); 1106 buffer = va_arg(ap, char *); 1107 bufsize = va_arg(ap, size_t); 1108 errnop = va_arg(ap, int *); 1109 *errnop = nis_getstate(&st); 1110 if (*errnop != 0) 1111 return (NS_UNAVAIL); 1112 if (st->domain[0] == '\0') { 1113 if (getdomainname(st->domain, sizeof(st->domain)) != 0) { 1114 *errnop = errno; 1115 return (NS_UNAVAIL); 1116 } 1117 } 1118 result = NULL; 1119 do { 1120 rv = NS_NOTFOUND; 1121 switch (how) { 1122 case nss_lt_name: 1123 if (strlcpy(buffer, name, bufsize) >= bufsize) 1124 goto erange; 1125 break; 1126 case nss_lt_id: 1127 if (snprintf(buffer, bufsize, "%lu", 1128 (unsigned long)gid) >= bufsize) 1129 goto erange; 1130 break; 1131 case nss_lt_all: 1132 if (st->done) 1133 goto fin; 1134 break; 1135 } 1136 result = NULL; 1137 if (how == nss_lt_all) { 1138 if (st->key == NULL) 1139 rv = yp_first(st->domain, map, &st->key, 1140 &st->keylen, &result, &resultlen); 1141 else { 1142 key = st->key; 1143 keylen = st->keylen; 1144 st->key = NULL; 1145 rv = yp_next(st->domain, map, key, keylen, 1146 &st->key, &st->keylen, &result, 1147 &resultlen); 1148 free(key); 1149 } 1150 if (rv != 0) { 1151 free(result); 1152 free(st->key); 1153 st->key = NULL; 1154 if (rv == YPERR_NOMORE) { 1155 st->done = 1; 1156 rv = NS_NOTFOUND; 1157 } else 1158 rv = NS_UNAVAIL; 1159 goto fin; 1160 } 1161 } else { 1162 rv = yp_match(st->domain, map, buffer, strlen(buffer), 1163 &result, &resultlen); 1164 if (rv == YPERR_KEY) { 1165 rv = NS_NOTFOUND; 1166 continue; 1167 } else if (rv != 0) { 1168 free(result); 1169 rv = NS_UNAVAIL; 1170 continue; 1171 } 1172 } 1173 /* We need room at least for the line, a string NUL 1174 * terminator, alignment padding, and one (char *) 1175 * pointer for the member list terminator. 1176 */ 1177 if (resultlen >= bufsize - _ALIGNBYTES - sizeof(char *)) { 1178 free(result); 1179 goto erange; 1180 } 1181 memcpy(buffer, result, resultlen); 1182 buffer[resultlen] = '\0'; 1183 free(result); 1184 rv = __gr_match_entry(buffer, resultlen, how, name, gid); 1185 if (rv == NS_SUCCESS) 1186 rv = __gr_parse_entry(buffer, resultlen, grp, 1187 &buffer[resultlen+1], bufsize - resultlen - 1, 1188 errnop); 1189 } while (how == nss_lt_all && !(rv & NS_TERMINATE)); 1190 fin: 1191 if (rv == NS_SUCCESS && retval != NULL) 1192 *(struct group **)retval = grp; 1193 return (rv); 1194 erange: 1195 *errnop = ERANGE; 1196 return (NS_RETURN); 1197 } 1198 #endif /* YP */ 1199 1200 1201 1202 /* 1203 * compat backend 1204 */ 1205 static void 1206 compat_endstate(void *p) 1207 { 1208 struct compat_state *st; 1209 1210 if (p == NULL) 1211 return; 1212 st = (struct compat_state *)p; 1213 free(st->name); 1214 if (st->fp != NULL) 1215 fclose(st->fp); 1216 free(p); 1217 } 1218 1219 1220 static int 1221 compat_setgrent(void *retval, void *mdata, va_list ap) 1222 { 1223 static const ns_src compatsrc[] = { 1224 #ifdef YP 1225 { NSSRC_NIS, NS_SUCCESS }, 1226 #endif 1227 { NULL, 0 } 1228 }; 1229 ns_dtab dtab[] = { 1230 #ifdef HESIOD 1231 { NSSRC_DNS, dns_setgrent, NULL }, 1232 #endif 1233 #ifdef YP 1234 { NSSRC_NIS, nis_setgrent, NULL }, 1235 #endif 1236 { NULL, NULL, NULL } 1237 }; 1238 struct compat_state *st; 1239 int rv, stayopen; 1240 1241 #define set_setent(x, y) do { \ 1242 unsigned int i; \ 1243 \ 1244 for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \ 1245 x[i].mdata = (void *)y; \ 1246 } while (0) 1247 1248 rv = compat_getstate(&st); 1249 if (rv != 0) 1250 return (NS_UNAVAIL); 1251 switch ((enum constants)mdata) { 1252 case SETGRENT: 1253 stayopen = va_arg(ap, int); 1254 if (st->fp != NULL) 1255 rewind(st->fp); 1256 else if (stayopen) 1257 st->fp = fopen(_PATH_GROUP, "re"); 1258 set_setent(dtab, mdata); 1259 (void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgrent", 1260 compatsrc, 0); 1261 break; 1262 case ENDGRENT: 1263 if (st->fp != NULL) { 1264 fclose(st->fp); 1265 st->fp = NULL; 1266 } 1267 set_setent(dtab, mdata); 1268 (void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "endgrent", 1269 compatsrc, 0); 1270 break; 1271 default: 1272 break; 1273 } 1274 st->compat = COMPAT_MODE_OFF; 1275 free(st->name); 1276 st->name = NULL; 1277 return (NS_UNAVAIL); 1278 #undef set_setent 1279 } 1280 1281 1282 static int 1283 compat_group(void *retval, void *mdata, va_list ap) 1284 { 1285 static const ns_src compatsrc[] = { 1286 #ifdef YP 1287 { NSSRC_NIS, NS_SUCCESS }, 1288 #endif 1289 { NULL, 0 } 1290 }; 1291 ns_dtab dtab[] = { 1292 #ifdef YP 1293 { NSSRC_NIS, nis_group, NULL }, 1294 #endif 1295 #ifdef HESIOD 1296 { NSSRC_DNS, dns_group, NULL }, 1297 #endif 1298 { NULL, NULL, NULL } 1299 }; 1300 struct compat_state *st; 1301 enum nss_lookup_type how; 1302 const char *name, *line; 1303 struct group *grp; 1304 gid_t gid; 1305 char *buffer, *p; 1306 void *discard; 1307 size_t bufsize, linesize; 1308 off_t pos; 1309 int rv, stayopen, *errnop; 1310 1311 #define set_lookup_type(x, y) do { \ 1312 unsigned int i; \ 1313 \ 1314 for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \ 1315 x[i].mdata = (void *)y; \ 1316 } while (0) 1317 1318 name = NULL; 1319 gid = (gid_t)-1; 1320 how = (enum nss_lookup_type)mdata; 1321 switch (how) { 1322 case nss_lt_name: 1323 name = va_arg(ap, const char *); 1324 break; 1325 case nss_lt_id: 1326 gid = va_arg(ap, gid_t); 1327 break; 1328 case nss_lt_all: 1329 break; 1330 default: 1331 return (NS_NOTFOUND); 1332 } 1333 grp = va_arg(ap, struct group *); 1334 buffer = va_arg(ap, char *); 1335 bufsize = va_arg(ap, size_t); 1336 errnop = va_arg(ap, int *); 1337 *errnop = compat_getstate(&st); 1338 if (*errnop != 0) 1339 return (NS_UNAVAIL); 1340 if (st->fp == NULL && 1341 ((st->fp = fopen(_PATH_GROUP, "re")) == NULL)) { 1342 *errnop = errno; 1343 rv = NS_UNAVAIL; 1344 goto fin; 1345 } 1346 if (how == nss_lt_all) 1347 stayopen = 1; 1348 else { 1349 rewind(st->fp); 1350 stayopen = st->stayopen; 1351 } 1352 docompat: 1353 switch (st->compat) { 1354 case COMPAT_MODE_ALL: 1355 set_lookup_type(dtab, how); 1356 switch (how) { 1357 case nss_lt_all: 1358 rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT, 1359 "getgrent_r", compatsrc, grp, buffer, bufsize, 1360 errnop); 1361 break; 1362 case nss_lt_id: 1363 rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT, 1364 "getgrgid_r", compatsrc, gid, grp, buffer, bufsize, 1365 errnop); 1366 break; 1367 case nss_lt_name: 1368 rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT, 1369 "getgrnam_r", compatsrc, name, grp, buffer, 1370 bufsize, errnop); 1371 break; 1372 } 1373 if (rv & NS_TERMINATE) 1374 goto fin; 1375 st->compat = COMPAT_MODE_OFF; 1376 break; 1377 case COMPAT_MODE_NAME: 1378 set_lookup_type(dtab, nss_lt_name); 1379 rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT, 1380 "getgrnam_r", compatsrc, st->name, grp, buffer, bufsize, 1381 errnop); 1382 switch (rv) { 1383 case NS_SUCCESS: 1384 switch (how) { 1385 case nss_lt_name: 1386 if (strcmp(name, grp->gr_name) != 0) 1387 rv = NS_NOTFOUND; 1388 break; 1389 case nss_lt_id: 1390 if (gid != grp->gr_gid) 1391 rv = NS_NOTFOUND; 1392 break; 1393 default: 1394 break; 1395 } 1396 break; 1397 case NS_RETURN: 1398 goto fin; 1399 default: 1400 break; 1401 } 1402 free(st->name); 1403 st->name = NULL; 1404 st->compat = COMPAT_MODE_OFF; 1405 if (rv == NS_SUCCESS) 1406 goto fin; 1407 break; 1408 default: 1409 break; 1410 } 1411 rv = NS_NOTFOUND; 1412 pos = ftello(st->fp); 1413 while ((line = fgetln(st->fp, &linesize)) != NULL) { 1414 if (line[linesize-1] == '\n') 1415 linesize--; 1416 if (linesize > 2 && line[0] == '+') { 1417 p = memchr(&line[1], ':', linesize); 1418 if (p == NULL || p == &line[1]) 1419 st->compat = COMPAT_MODE_ALL; 1420 else { 1421 st->name = malloc(p - line); 1422 if (st->name == NULL) { 1423 syslog(LOG_ERR, 1424 "getgrent memory allocation failure"); 1425 *errnop = ENOMEM; 1426 rv = NS_UNAVAIL; 1427 break; 1428 } 1429 memcpy(st->name, &line[1], p - line - 1); 1430 st->name[p - line - 1] = '\0'; 1431 st->compat = COMPAT_MODE_NAME; 1432 } 1433 goto docompat; 1434 } 1435 rv = __gr_match_entry(line, linesize, how, name, gid); 1436 if (rv != NS_SUCCESS) 1437 continue; 1438 /* We need room at least for the line, a string NUL 1439 * terminator, alignment padding, and one (char *) 1440 * pointer for the member list terminator. 1441 */ 1442 if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) { 1443 *errnop = ERANGE; 1444 rv = NS_RETURN; 1445 break; 1446 } 1447 memcpy(buffer, line, linesize); 1448 buffer[linesize] = '\0'; 1449 rv = __gr_parse_entry(buffer, linesize, grp, 1450 &buffer[linesize + 1], bufsize - linesize - 1, errnop); 1451 if (rv & NS_TERMINATE) 1452 break; 1453 pos = ftello(st->fp); 1454 } 1455 fin: 1456 if (st->fp != NULL && !stayopen) { 1457 fclose(st->fp); 1458 st->fp = NULL; 1459 } 1460 if (rv == NS_SUCCESS && retval != NULL) 1461 *(struct group **)retval = grp; 1462 else if (rv == NS_RETURN && *errnop == ERANGE && st->fp != NULL) 1463 fseeko(st->fp, pos, SEEK_SET); 1464 return (rv); 1465 #undef set_lookup_type 1466 } 1467 1468 1469 /* 1470 * common group line matching and parsing 1471 */ 1472 int 1473 __gr_match_entry(const char *line, size_t linesize, enum nss_lookup_type how, 1474 const char *name, gid_t gid) 1475 { 1476 size_t namesize; 1477 const char *p, *eol; 1478 char *q; 1479 unsigned long n; 1480 int i, needed; 1481 1482 if (linesize == 0 || is_comment_line(line, linesize)) 1483 return (NS_NOTFOUND); 1484 switch (how) { 1485 case nss_lt_name: needed = 1; break; 1486 case nss_lt_id: needed = 2; break; 1487 default: needed = 2; break; 1488 } 1489 eol = &line[linesize]; 1490 for (p = line, i = 0; i < needed && p < eol; p++) 1491 if (*p == ':') 1492 i++; 1493 if (i < needed) 1494 return (NS_NOTFOUND); 1495 switch (how) { 1496 case nss_lt_name: 1497 namesize = strlen(name); 1498 if (namesize + 1 == (size_t)(p - line) && 1499 memcmp(line, name, namesize) == 0) 1500 return (NS_SUCCESS); 1501 break; 1502 case nss_lt_id: 1503 n = strtoul(p, &q, 10); 1504 if (q < eol && *q == ':' && gid == (gid_t)n) 1505 return (NS_SUCCESS); 1506 break; 1507 case nss_lt_all: 1508 return (NS_SUCCESS); 1509 default: 1510 break; 1511 } 1512 return (NS_NOTFOUND); 1513 } 1514 1515 1516 int 1517 __gr_parse_entry(char *line, size_t linesize, struct group *grp, char *membuf, 1518 size_t membufsize, int *errnop) 1519 { 1520 char *s_gid, *s_mem, *p, **members; 1521 unsigned long n; 1522 int maxmembers; 1523 1524 memset(grp, 0, sizeof(*grp)); 1525 members = (char **)_ALIGN(membuf); 1526 membufsize -= (char *)members - membuf; 1527 maxmembers = membufsize / sizeof(*members); 1528 if (maxmembers <= 0 || 1529 (grp->gr_name = strsep(&line, ":")) == NULL || 1530 grp->gr_name[0] == '\0' || 1531 (grp->gr_passwd = strsep(&line, ":")) == NULL || 1532 (s_gid = strsep(&line, ":")) == NULL || 1533 s_gid[0] == '\0') 1534 return (NS_NOTFOUND); 1535 s_mem = line; 1536 n = strtoul(s_gid, &s_gid, 10); 1537 if (s_gid[0] != '\0') 1538 return (NS_NOTFOUND); 1539 grp->gr_gid = (gid_t)n; 1540 grp->gr_mem = members; 1541 while (maxmembers > 1 && s_mem != NULL) { 1542 p = strsep(&s_mem, ","); 1543 if (p != NULL && *p != '\0') { 1544 *members++ = p; 1545 maxmembers--; 1546 } 1547 } 1548 *members = NULL; 1549 if (s_mem == NULL) 1550 return (NS_SUCCESS); 1551 else { 1552 *errnop = ERANGE; 1553 return (NS_RETURN); 1554 } 1555 } 1556 1557 1558