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