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