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