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