1113596Snectar/*- 2113596Snectar * Copyright (c) 2003 Networks Associates Technology, Inc. 3113596Snectar * All rights reserved. 41573Srgrimes * 5113596Snectar * This software was developed for the FreeBSD Project by 6113596Snectar * Jacques A. Vidrine, Safeport Network Services, and Network 7113596Snectar * Associates Laboratories, the Security Research Division of Network 8113596Snectar * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 9113596Snectar * ("CBOSS"), as part of the DARPA CHATS research program. 10113596Snectar * 111573Srgrimes * Redistribution and use in source and binary forms, with or without 121573Srgrimes * modification, are permitted provided that the following conditions 131573Srgrimes * are met: 141573Srgrimes * 1. Redistributions of source code must retain the above copyright 151573Srgrimes * notice, this list of conditions and the following disclaimer. 161573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171573Srgrimes * notice, this list of conditions and the following disclaimer in the 181573Srgrimes * documentation and/or other materials provided with the distribution. 191573Srgrimes * 20113596Snectar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23113596Snectar * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301573Srgrimes * SUCH DAMAGE. 31113596Snectar * 321573Srgrimes */ 3390016Sbde#include <sys/cdefs.h> 3489999Sobrien__FBSDID("$FreeBSD: releng/10.3/lib/libc/gen/getgrent.c 290582 2015-11-09 07:34:30Z ngie $"); 351573Srgrimes 36113596Snectar#include "namespace.h" 37113596Snectar#include <sys/param.h> 38113596Snectar#ifdef YP 39113596Snectar#include <rpc/rpc.h> 40113596Snectar#include <rpcsvc/yp_prot.h> 41113596Snectar#include <rpcsvc/ypclnt.h> 42113596Snectar#endif 43174547Sbushman#include <assert.h> 44113596Snectar#include <ctype.h> 4565532Snectar#include <errno.h> 46113596Snectar#ifdef HESIOD 47113596Snectar#include <hesiod.h> 48113596Snectar#endif 4965532Snectar#include <grp.h> 5065532Snectar#include <nsswitch.h> 51113596Snectar#include <pthread.h> 52113596Snectar#include <pthread_np.h> 531573Srgrimes#include <stdio.h> 541573Srgrimes#include <stdlib.h> 552936Swollman#include <string.h> 5665532Snectar#include <syslog.h> 57113596Snectar#include <unistd.h> 58113596Snectar#include "un-namespace.h" 59113596Snectar#include "libc_private.h" 60113596Snectar#include "nss_tls.h" 61158115Sume#ifdef NS_CACHING 62158115Sume#include "nscache.h" 63158115Sume#endif 641573Srgrimes 65113596Snectarenum constants { 66113596Snectar GRP_STORAGE_INITIAL = 1 << 10, /* 1 KByte */ 67113596Snectar GRP_STORAGE_MAX = 1 << 20, /* 1 MByte */ 68113596Snectar SETGRENT = 1, 69113596Snectar ENDGRENT = 2, 70113596Snectar HESIOD_NAME_MAX = 256, 71113596Snectar}; 7265532Snectar 73113596Snectarstatic const ns_src defaultsrc[] = { 74113643Snectar { NSSRC_COMPAT, NS_SUCCESS }, 75113596Snectar { NULL, 0 } 76113596Snectar}; 7765532Snectar 78113596Snectarint __gr_match_entry(const char *, size_t, enum nss_lookup_type, 79113596Snectar const char *, gid_t); 80113596Snectarint __gr_parse_entry(char *, size_t, struct group *, char *, size_t, 81113596Snectar int *); 8265532Snectar 83113596Snectarstatic int is_comment_line(const char *, size_t); 8465532Snectar 85113596Snectarunion key { 86113596Snectar const char *name; 87113596Snectar gid_t gid; 88113596Snectar}; 89113596Snectarstatic struct group *getgr(int (*)(union key, struct group *, char *, size_t, 90113596Snectar struct group **), union key); 91113596Snectarstatic int wrap_getgrnam_r(union key, struct group *, char *, size_t, 92113596Snectar struct group **); 93113596Snectarstatic int wrap_getgrgid_r(union key, struct group *, char *, size_t, 94113596Snectar struct group **); 95113596Snectarstatic int wrap_getgrent_r(union key, struct group *, char *, size_t, 96113596Snectar struct group **); 9765532Snectar 98113596Snectarstruct files_state { 99113596Snectar FILE *fp; 100113596Snectar int stayopen; 101113596Snectar}; 102113596Snectarstatic void files_endstate(void *); 103113596SnectarNSS_TLS_HANDLING(files); 104113596Snectarstatic int files_setgrent(void *, void *, va_list); 105113596Snectarstatic int files_group(void *, void *, va_list); 10665532Snectar 1071573Srgrimes 10865532Snectar#ifdef HESIOD 109113596Snectarstruct dns_state { 110113596Snectar long counter; 111113596Snectar}; 112113596Snectarstatic void dns_endstate(void *); 113113596SnectarNSS_TLS_HANDLING(dns); 114113596Snectarstatic int dns_setgrent(void *, void *, va_list); 115113596Snectarstatic int dns_group(void *, void *, va_list); 11665532Snectar#endif 117113596Snectar 118113596Snectar 119113596Snectar#ifdef YP 120113596Snectarstruct nis_state { 121113596Snectar char domain[MAXHOSTNAMELEN]; 122113596Snectar int done; 123113596Snectar char *key; 124113596Snectar int keylen; 125113596Snectar}; 126113596Snectarstatic void nis_endstate(void *); 127113596SnectarNSS_TLS_HANDLING(nis); 128113596Snectarstatic int nis_setgrent(void *, void *, va_list); 129113596Snectarstatic int nis_group(void *, void *, va_list); 13065532Snectar#endif 13120911Swosch 132113596Snectarstruct compat_state { 133113596Snectar FILE *fp; 134113596Snectar int stayopen; 135113596Snectar char *name; 136113596Snectar enum _compat { 137113596Snectar COMPAT_MODE_OFF = 0, 138113596Snectar COMPAT_MODE_ALL, 139113596Snectar COMPAT_MODE_NAME 140113596Snectar } compat; 141113596Snectar}; 142113596Snectarstatic void compat_endstate(void *); 143113596SnectarNSS_TLS_HANDLING(compat); 144113596Snectarstatic int compat_setgrent(void *, void *, va_list); 145113596Snectarstatic int compat_group(void *, void *, va_list); 14665532Snectar 147174547Sbushmanstatic int gr_addgid(gid_t, gid_t *, int, int *); 148174547Sbushmanstatic int getgroupmembership_fallback(void *, void *, va_list); 149174547Sbushman 150158115Sume#ifdef NS_CACHING 151158115Sumestatic int grp_id_func(char *, size_t *, va_list, void *); 152158115Sumestatic int grp_marshal_func(char *, size_t *, void *, va_list, void *); 153158115Sumestatic int grp_unmarshal_func(char *, size_t, void *, va_list, void *); 15420911Swosch 155158115Sumestatic int 156158115Sumegrp_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata) 157158115Sume{ 158158115Sume char *name; 159158115Sume gid_t gid; 160158115Sume 161158115Sume size_t desired_size, size; 162158115Sume int res = NS_UNAVAIL; 163158115Sume enum nss_lookup_type lookup_type; 164158115Sume 165158115Sume 166158115Sume lookup_type = (enum nss_lookup_type)cache_mdata; 167158115Sume switch (lookup_type) { 168158115Sume case nss_lt_name: 169158115Sume name = va_arg(ap, char *); 170158115Sume size = strlen(name); 171158115Sume desired_size = sizeof(enum nss_lookup_type) + size + 1; 172158115Sume if (desired_size > *buffer_size) { 173158115Sume res = NS_RETURN; 174158115Sume goto fin; 175158115Sume } 176158115Sume 177158115Sume memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 178158115Sume memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1); 179158115Sume 180158115Sume res = NS_SUCCESS; 181158115Sume break; 182158115Sume case nss_lt_id: 183158115Sume gid = va_arg(ap, gid_t); 184158115Sume desired_size = sizeof(enum nss_lookup_type) + sizeof(gid_t); 185158115Sume if (desired_size > *buffer_size) { 186158115Sume res = NS_RETURN; 187158115Sume goto fin; 188158115Sume } 189158115Sume 190158115Sume memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 191158115Sume memcpy(buffer + sizeof(enum nss_lookup_type), &gid, 192158115Sume sizeof(gid_t)); 193158115Sume 194158115Sume res = NS_SUCCESS; 195158115Sume break; 196158115Sume default: 197158115Sume /* should be unreachable */ 198158115Sume return (NS_UNAVAIL); 199158115Sume } 200158115Sume 201158115Sumefin: 202158115Sume *buffer_size = desired_size; 203158115Sume return (res); 204158115Sume} 205158115Sume 206158115Sumestatic int 207158115Sumegrp_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap, 208158115Sume void *cache_mdata) 209158115Sume{ 210158115Sume char *name; 211158115Sume gid_t gid; 212158115Sume struct group *grp; 213158115Sume char *orig_buf; 214158115Sume size_t orig_buf_size; 215158115Sume 216158115Sume struct group new_grp; 217158115Sume size_t desired_size, size, mem_size; 218158115Sume char *p, **mem; 219158115Sume 220158115Sume switch ((enum nss_lookup_type)cache_mdata) { 221158115Sume case nss_lt_name: 222158115Sume name = va_arg(ap, char *); 223158115Sume break; 224158115Sume case nss_lt_id: 225158115Sume gid = va_arg(ap, gid_t); 226158115Sume break; 227158115Sume case nss_lt_all: 228158115Sume break; 229158115Sume default: 230158115Sume /* should be unreachable */ 231158115Sume return (NS_UNAVAIL); 232158115Sume } 233158115Sume 234158115Sume grp = va_arg(ap, struct group *); 235158115Sume orig_buf = va_arg(ap, char *); 236158115Sume orig_buf_size = va_arg(ap, size_t); 237158115Sume 238158115Sume desired_size = _ALIGNBYTES + sizeof(struct group) + sizeof(char *); 239158115Sume 240158115Sume if (grp->gr_name != NULL) 241158115Sume desired_size += strlen(grp->gr_name) + 1; 242158115Sume if (grp->gr_passwd != NULL) 243158115Sume desired_size += strlen(grp->gr_passwd) + 1; 244158115Sume 245158115Sume if (grp->gr_mem != NULL) { 246158115Sume mem_size = 0; 247158115Sume for (mem = grp->gr_mem; *mem; ++mem) { 248158115Sume desired_size += strlen(*mem) + 1; 249158115Sume ++mem_size; 250158115Sume } 251158115Sume 252158115Sume desired_size += _ALIGNBYTES + (mem_size + 1) * sizeof(char *); 253158115Sume } 254158115Sume 255158115Sume if (desired_size > *buffer_size) { 256158115Sume /* this assignment is here for future use */ 257158115Sume *buffer_size = desired_size; 258158115Sume return (NS_RETURN); 259158115Sume } 260158115Sume 261158115Sume memcpy(&new_grp, grp, sizeof(struct group)); 262158115Sume memset(buffer, 0, desired_size); 263158115Sume 264158115Sume *buffer_size = desired_size; 265158115Sume p = buffer + sizeof(struct group) + sizeof(char *); 266158115Sume memcpy(buffer + sizeof(struct group), &p, sizeof(char *)); 267158115Sume p = (char *)_ALIGN(p); 268158115Sume 269158115Sume if (new_grp.gr_name != NULL) { 270158115Sume size = strlen(new_grp.gr_name); 271158115Sume memcpy(p, new_grp.gr_name, size); 272158115Sume new_grp.gr_name = p; 273158115Sume p += size + 1; 274158115Sume } 275158115Sume 276158115Sume if (new_grp.gr_passwd != NULL) { 277158115Sume size = strlen(new_grp.gr_passwd); 278158115Sume memcpy(p, new_grp.gr_passwd, size); 279158115Sume new_grp.gr_passwd = p; 280158115Sume p += size + 1; 281158115Sume } 282158115Sume 283158115Sume if (new_grp.gr_mem != NULL) { 284158115Sume p = (char *)_ALIGN(p); 285158115Sume memcpy(p, new_grp.gr_mem, sizeof(char *) * mem_size); 286158115Sume new_grp.gr_mem = (char **)p; 287158115Sume p += sizeof(char *) * (mem_size + 1); 288158115Sume 289158115Sume for (mem = new_grp.gr_mem; *mem; ++mem) { 290158115Sume size = strlen(*mem); 291158115Sume memcpy(p, *mem, size); 292158115Sume *mem = p; 293158115Sume p += size + 1; 294158115Sume } 295158115Sume } 296158115Sume 297158115Sume memcpy(buffer, &new_grp, sizeof(struct group)); 298158115Sume return (NS_SUCCESS); 299158115Sume} 300158115Sume 301158115Sumestatic int 302158115Sumegrp_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap, 303158115Sume void *cache_mdata) 304158115Sume{ 305158115Sume char *name; 306158115Sume gid_t gid; 307158115Sume struct group *grp; 308158115Sume char *orig_buf; 309158115Sume size_t orig_buf_size; 310158115Sume int *ret_errno; 311158115Sume 312158115Sume char *p; 313158115Sume char **mem; 314158115Sume 315158115Sume switch ((enum nss_lookup_type)cache_mdata) { 316158115Sume case nss_lt_name: 317158115Sume name = va_arg(ap, char *); 318158115Sume break; 319158115Sume case nss_lt_id: 320158115Sume gid = va_arg(ap, gid_t); 321158115Sume break; 322158115Sume case nss_lt_all: 323158115Sume break; 324158115Sume default: 325158115Sume /* should be unreachable */ 326158115Sume return (NS_UNAVAIL); 327158115Sume } 328158115Sume 329158115Sume grp = va_arg(ap, struct group *); 330158115Sume orig_buf = va_arg(ap, char *); 331158115Sume orig_buf_size = va_arg(ap, size_t); 332158115Sume ret_errno = va_arg(ap, int *); 333158115Sume 334158115Sume if (orig_buf_size < 335158115Sume buffer_size - sizeof(struct group) - sizeof(char *)) { 336158115Sume *ret_errno = ERANGE; 337158115Sume return (NS_RETURN); 338158115Sume } 339158115Sume 340158115Sume memcpy(grp, buffer, sizeof(struct group)); 341158115Sume memcpy(&p, buffer + sizeof(struct group), sizeof(char *)); 342158115Sume 343158115Sume orig_buf = (char *)_ALIGN(orig_buf); 344158115Sume memcpy(orig_buf, buffer + sizeof(struct group) + sizeof(char *) + 345158115Sume _ALIGN(p) - (size_t)p, 346158115Sume buffer_size - sizeof(struct group) - sizeof(char *) - 347158115Sume _ALIGN(p) + (size_t)p); 348158115Sume p = (char *)_ALIGN(p); 349158115Sume 350158115Sume NS_APPLY_OFFSET(grp->gr_name, orig_buf, p, char *); 351158115Sume NS_APPLY_OFFSET(grp->gr_passwd, orig_buf, p, char *); 352158115Sume if (grp->gr_mem != NULL) { 353158115Sume NS_APPLY_OFFSET(grp->gr_mem, orig_buf, p, char **); 354158115Sume 355158115Sume for (mem = grp->gr_mem; *mem; ++mem) 356158115Sume NS_APPLY_OFFSET(*mem, orig_buf, p, char *); 357158115Sume } 358158115Sume 359158115Sume if (retval != NULL) 360158115Sume *((struct group **)retval) = grp; 361158115Sume 362158115Sume return (NS_SUCCESS); 363158115Sume} 364158115Sume 365158115SumeNSS_MP_CACHE_HANDLING(group); 366158115Sume#endif /* NS_CACHING */ 367158115Sume 368158115Sume#ifdef NS_CACHING 369174547Sbushmanstatic const nss_cache_info setgrent_cache_info = NS_MP_CACHE_INFO_INITIALIZER( 370174547Sbushman group, (void *)nss_lt_all, 371174547Sbushman NULL, NULL); 372158115Sume#endif 373158115Sume 374174547Sbushmanstatic const ns_dtab setgrent_dtab[] = { 375174547Sbushman { NSSRC_FILES, files_setgrent, (void *)SETGRENT }, 376113596Snectar#ifdef HESIOD 377174547Sbushman { NSSRC_DNS, dns_setgrent, (void *)SETGRENT }, 378113596Snectar#endif 3792936Swollman#ifdef YP 380174547Sbushman { NSSRC_NIS, nis_setgrent, (void *)SETGRENT }, 3812936Swollman#endif 382174547Sbushman { NSSRC_COMPAT, compat_setgrent, (void *)SETGRENT }, 383158115Sume#ifdef NS_CACHING 384174547Sbushman NS_CACHE_CB(&setgrent_cache_info) 385158115Sume#endif 386174547Sbushman { NULL, NULL, NULL } 387174547Sbushman}; 3882936Swollman 389158115Sume#ifdef NS_CACHING 390174547Sbushmanstatic const nss_cache_info endgrent_cache_info = NS_MP_CACHE_INFO_INITIALIZER( 391174547Sbushman group, (void *)nss_lt_all, 392174547Sbushman NULL, NULL); 393158115Sume#endif 394158115Sume 395174547Sbushmanstatic const ns_dtab endgrent_dtab[] = { 396174547Sbushman { NSSRC_FILES, files_setgrent, (void *)ENDGRENT }, 39765532Snectar#ifdef HESIOD 398174547Sbushman { NSSRC_DNS, dns_setgrent, (void *)ENDGRENT }, 3992936Swollman#endif 400113596Snectar#ifdef YP 401174547Sbushman { NSSRC_NIS, nis_setgrent, (void *)ENDGRENT }, 40265532Snectar#endif 403174547Sbushman { NSSRC_COMPAT, compat_setgrent, (void *)ENDGRENT }, 404158115Sume#ifdef NS_CACHING 405174547Sbushman NS_CACHE_CB(&endgrent_cache_info) 406158115Sume#endif 407174547Sbushman { NULL, NULL, NULL } 408174547Sbushman}; 40965532Snectar 410158115Sume#ifdef NS_CACHING 411174547Sbushmanstatic const nss_cache_info getgrent_r_cache_info = NS_MP_CACHE_INFO_INITIALIZER( 412174547Sbushman group, (void *)nss_lt_all, 413174547Sbushman grp_marshal_func, grp_unmarshal_func); 414158115Sume#endif 415158115Sume 416174547Sbushmanstatic const ns_dtab getgrent_r_dtab[] = { 417174547Sbushman { NSSRC_FILES, files_group, (void *)nss_lt_all }, 418113596Snectar#ifdef HESIOD 419174547Sbushman { NSSRC_DNS, dns_group, (void *)nss_lt_all }, 420113596Snectar#endif 421113596Snectar#ifdef YP 422174547Sbushman { NSSRC_NIS, nis_group, (void *)nss_lt_all }, 423113596Snectar#endif 424174547Sbushman { NSSRC_COMPAT, compat_group, (void *)nss_lt_all }, 425158115Sume#ifdef NS_CACHING 426174547Sbushman NS_CACHE_CB(&getgrent_r_cache_info) 427158115Sume#endif 428174547Sbushman { NULL, NULL, NULL } 429174547Sbushman}; 430174547Sbushman 431174547Sbushmanstatic int 432174547Sbushmangr_addgid(gid_t gid, gid_t *groups, int maxgrp, int *grpcnt) 433174547Sbushman{ 434174547Sbushman int ret, dupc; 435174547Sbushman 436174547Sbushman for (dupc = 0; dupc < MIN(maxgrp, *grpcnt); dupc++) { 437174547Sbushman if (groups[dupc] == gid) 438174547Sbushman return 1; 439174547Sbushman } 440174547Sbushman 441174547Sbushman ret = 1; 442174547Sbushman if (*grpcnt < maxgrp) 443174547Sbushman groups[*grpcnt] = gid; 444174547Sbushman else 445174547Sbushman ret = 0; 446174547Sbushman 447174547Sbushman (*grpcnt)++; 448174547Sbushman 449174547Sbushman return ret; 450174547Sbushman} 451174547Sbushman 452174547Sbushmanstatic int 453174547Sbushmangetgroupmembership_fallback(void *retval, void *mdata, va_list ap) 454174547Sbushman{ 455174547Sbushman const ns_src src[] = { 456174547Sbushman { mdata, NS_SUCCESS }, 457174547Sbushman { NULL, 0} 458113596Snectar }; 459174547Sbushman struct group grp; 460174547Sbushman struct group *grp_p; 461174547Sbushman char *buf; 462174547Sbushman size_t bufsize; 463174547Sbushman const char *uname; 464174547Sbushman gid_t *groups; 465174547Sbushman gid_t agroup; 466174547Sbushman int maxgrp, *grpcnt; 467174547Sbushman int i, rv, ret_errno; 468174547Sbushman 469174547Sbushman /* 470174547Sbushman * As this is a fallback method, only provided src 471174547Sbushman * list will be respected during methods search. 472174547Sbushman */ 473174547Sbushman assert(src[0].name != NULL); 474174547Sbushman 475174547Sbushman uname = va_arg(ap, const char *); 476174547Sbushman agroup = va_arg(ap, gid_t); 477174547Sbushman groups = va_arg(ap, gid_t *); 478174547Sbushman maxgrp = va_arg(ap, int); 479174547Sbushman grpcnt = va_arg(ap, int *); 480174547Sbushman 481174547Sbushman rv = NS_UNAVAIL; 482174547Sbushman 483174547Sbushman buf = malloc(GRP_STORAGE_INITIAL); 484174547Sbushman if (buf == NULL) 485174547Sbushman goto out; 486174547Sbushman 487174547Sbushman bufsize = GRP_STORAGE_INITIAL; 488174547Sbushman 489174547Sbushman gr_addgid(agroup, groups, maxgrp, grpcnt); 490174547Sbushman 491174547Sbushman _nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", src, 0); 492174547Sbushman for (;;) { 493174547Sbushman do { 494174547Sbushman ret_errno = 0; 495174547Sbushman grp_p = NULL; 496174547Sbushman rv = _nsdispatch(&grp_p, getgrent_r_dtab, NSDB_GROUP, 497174547Sbushman "getgrent_r", src, &grp, buf, bufsize, &ret_errno); 498174547Sbushman 499174547Sbushman if (grp_p == NULL && ret_errno == ERANGE) { 500174547Sbushman free(buf); 501174547Sbushman if ((bufsize << 1) > GRP_STORAGE_MAX) { 502174547Sbushman buf = NULL; 503174547Sbushman errno = ERANGE; 504174547Sbushman goto out; 505174547Sbushman } 506174547Sbushman 507174547Sbushman bufsize <<= 1; 508174547Sbushman buf = malloc(bufsize); 509174547Sbushman if (buf == NULL) { 510174547Sbushman goto out; 511174547Sbushman } 512174547Sbushman } 513174547Sbushman } while (grp_p == NULL && ret_errno == ERANGE); 514174547Sbushman 515174547Sbushman if (ret_errno != 0) { 516174547Sbushman errno = ret_errno; 517174547Sbushman goto out; 518174547Sbushman } 519174547Sbushman 520174547Sbushman if (grp_p == NULL) 521174547Sbushman break; 522174547Sbushman 523174547Sbushman for (i = 0; grp.gr_mem[i]; i++) { 524174547Sbushman if (strcmp(grp.gr_mem[i], uname) == 0) 525174547Sbushman gr_addgid(grp.gr_gid, groups, maxgrp, grpcnt); 526174547Sbushman } 527174547Sbushman } 528174547Sbushman 529174547Sbushman _nsdispatch(NULL, endgrent_dtab, NSDB_GROUP, "endgrent", src); 530174547Sbushmanout: 531174547Sbushman free(buf); 532174547Sbushman return (rv); 5331573Srgrimes} 5341573Srgrimes 535174547Sbushman/* XXX IEEE Std 1003.1, 2003 specifies `void setgrent(void)' */ 536174547Sbushmanint 537174547Sbushmansetgrent(void) 538174547Sbushman{ 539174547Sbushman (void)_nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", defaultsrc, 0); 540174547Sbushman return (1); 541174547Sbushman} 542113596Snectar 543174547Sbushman 544113596Snectarint 545174547Sbushmansetgroupent(int stayopen) 546174547Sbushman{ 547174547Sbushman (void)_nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", defaultsrc, 548174547Sbushman stayopen); 549174547Sbushman return (1); 550174547Sbushman} 551174547Sbushman 552174547Sbushman 553174547Sbushmanvoid 554174547Sbushmanendgrent(void) 555174547Sbushman{ 556174547Sbushman (void)_nsdispatch(NULL, endgrent_dtab, NSDB_GROUP, "endgrent", defaultsrc); 557174547Sbushman} 558174547Sbushman 559174547Sbushman 560174547Sbushmanint 561113596Snectargetgrent_r(struct group *grp, char *buffer, size_t bufsize, 562113596Snectar struct group **result) 5631573Srgrimes{ 564113596Snectar int rv, ret_errno; 5651573Srgrimes 566113596Snectar ret_errno = 0; 567113596Snectar *result = NULL; 568174547Sbushman rv = _nsdispatch(result, getgrent_r_dtab, NSDB_GROUP, "getgrent_r", defaultsrc, 569113596Snectar grp, buffer, bufsize, &ret_errno); 570113596Snectar if (rv == NS_SUCCESS) 571113596Snectar return (0); 572113596Snectar else 573113596Snectar return (ret_errno); 5741573Srgrimes} 5751573Srgrimes 576113596Snectar 577113596Snectarint 578113596Snectargetgrnam_r(const char *name, struct group *grp, char *buffer, size_t bufsize, 579113596Snectar struct group **result) 5801573Srgrimes{ 581158115Sume#ifdef NS_CACHING 582158115Sume static const nss_cache_info cache_info = 583158115Sume NS_COMMON_CACHE_INFO_INITIALIZER( 584158115Sume group, (void *)nss_lt_name, 585158115Sume grp_id_func, grp_marshal_func, grp_unmarshal_func); 586158115Sume#endif 587158115Sume 588113596Snectar static const ns_dtab dtab[] = { 589113596Snectar { NSSRC_FILES, files_group, (void *)nss_lt_name }, 590113596Snectar#ifdef HESIOD 591113596Snectar { NSSRC_DNS, dns_group, (void *)nss_lt_name }, 592113596Snectar#endif 593113596Snectar#ifdef YP 594113596Snectar { NSSRC_NIS, nis_group, (void *)nss_lt_name }, 595113596Snectar#endif 596113596Snectar { NSSRC_COMPAT, compat_group, (void *)nss_lt_name }, 597158115Sume#ifdef NS_CACHING 598158115Sume NS_CACHE_CB(&cache_info) 599158115Sume#endif 600113596Snectar { NULL, NULL, NULL } 601113596Snectar }; 602113596Snectar int rv, ret_errno; 6031573Srgrimes 604113596Snectar ret_errno = 0; 605113596Snectar *result = NULL; 606113596Snectar rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrnam_r", defaultsrc, 607113596Snectar name, grp, buffer, bufsize, &ret_errno); 608113596Snectar if (rv == NS_SUCCESS) 609113596Snectar return (0); 610113596Snectar else 611113596Snectar return (ret_errno); 6121573Srgrimes} 6131573Srgrimes 614113596Snectar 615113596Snectarint 616113596Snectargetgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize, 617113596Snectar struct group **result) 6181573Srgrimes{ 619158115Sume#ifdef NS_CACHING 620158115Sume static const nss_cache_info cache_info = 621158115Sume NS_COMMON_CACHE_INFO_INITIALIZER( 622158115Sume group, (void *)nss_lt_id, 623158115Sume grp_id_func, grp_marshal_func, grp_unmarshal_func); 624158115Sume#endif 625158115Sume 626113596Snectar static const ns_dtab dtab[] = { 627113596Snectar { NSSRC_FILES, files_group, (void *)nss_lt_id }, 62865532Snectar#ifdef HESIOD 629113596Snectar { NSSRC_DNS, dns_group, (void *)nss_lt_id }, 63065532Snectar#endif 631113596Snectar#ifdef YP 632113596Snectar { NSSRC_NIS, nis_group, (void *)nss_lt_id }, 63365532Snectar#endif 634113596Snectar { NSSRC_COMPAT, compat_group, (void *)nss_lt_id }, 635158115Sume#ifdef NS_CACHING 636158115Sume NS_CACHE_CB(&cache_info) 637158115Sume#endif 638113596Snectar { NULL, NULL, NULL } 639113596Snectar }; 640113596Snectar int rv, ret_errno; 641113596Snectar 642113596Snectar ret_errno = 0; 643113596Snectar *result = NULL; 644113596Snectar rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrgid_r", defaultsrc, 645113596Snectar gid, grp, buffer, bufsize, &ret_errno); 646113596Snectar if (rv == NS_SUCCESS) 647113596Snectar return (0); 648113596Snectar else 649113596Snectar return (ret_errno); 65065532Snectar} 65120911Swosch 652113596Snectar 653174547Sbushman 654174547Sbushmanint 655174547Sbushman__getgroupmembership(const char *uname, gid_t agroup, gid_t *groups, 656174547Sbushman int maxgrp, int *grpcnt) 657174547Sbushman{ 658174547Sbushman static const ns_dtab dtab[] = { 659174547Sbushman NS_FALLBACK_CB(getgroupmembership_fallback) 660174547Sbushman { NULL, NULL, NULL } 661174547Sbushman }; 662174547Sbushman 663174547Sbushman assert(uname != NULL); 664174547Sbushman /* groups may be NULL if just sizing when invoked with maxgrp = 0 */ 665174547Sbushman assert(grpcnt != NULL); 666174547Sbushman 667174547Sbushman *grpcnt = 0; 668290582Sngie (void)_nsdispatch(NULL, dtab, NSDB_GROUP, "getgroupmembership", 669174547Sbushman defaultsrc, uname, agroup, groups, maxgrp, grpcnt); 670174547Sbushman 671174547Sbushman /* too many groups found? */ 672174547Sbushman return (*grpcnt > maxgrp ? -1 : 0); 673174547Sbushman} 674174547Sbushman 675174547Sbushman 676113596Snectarstatic struct group grp; 677113596Snectarstatic char *grp_storage; 678113596Snectarstatic size_t grp_storage_size; 679113596Snectar 680113596Snectarstatic struct group * 681113596Snectargetgr(int (*fn)(union key, struct group *, char *, size_t, struct group **), 682113596Snectar union key key) 68365532Snectar{ 684113596Snectar int rv; 685113596Snectar struct group *res; 686113596Snectar 687113596Snectar if (grp_storage == NULL) { 688113596Snectar grp_storage = malloc(GRP_STORAGE_INITIAL); 689113596Snectar if (grp_storage == NULL) 690113596Snectar return (NULL); 691113596Snectar grp_storage_size = GRP_STORAGE_INITIAL; 69220911Swosch } 693113596Snectar do { 694113596Snectar rv = fn(key, &grp, grp_storage, grp_storage_size, &res); 695113596Snectar if (res == NULL && rv == ERANGE) { 696113596Snectar free(grp_storage); 697113596Snectar if ((grp_storage_size << 1) > GRP_STORAGE_MAX) { 698113596Snectar grp_storage = NULL; 699129367Skientzle errno = ERANGE; 700113596Snectar return (NULL); 701113596Snectar } 702113596Snectar grp_storage_size <<= 1; 703113596Snectar grp_storage = malloc(grp_storage_size); 704113596Snectar if (grp_storage == NULL) 705113596Snectar return (NULL); 706113596Snectar } 707113596Snectar } while (res == NULL && rv == ERANGE); 708129367Skientzle if (rv != 0) 709129367Skientzle errno = rv; 710113596Snectar return (res); 7111573Srgrimes} 7121573Srgrimes 713113596Snectar 714113596Snectarstatic int 715113596Snectarwrap_getgrnam_r(union key key, struct group *grp, char *buffer, size_t bufsize, 716113596Snectar struct group **res) 7171573Srgrimes{ 718113596Snectar return (getgrnam_r(key.name, grp, buffer, bufsize, res)); 7191573Srgrimes} 7201573Srgrimes 721113596Snectar 722113596Snectarstatic int 723113596Snectarwrap_getgrgid_r(union key key, struct group *grp, char *buffer, size_t bufsize, 724113596Snectar struct group **res) 7251573Srgrimes{ 726113596Snectar return (getgrgid_r(key.gid, grp, buffer, bufsize, res)); 7271573Srgrimes} 7281573Srgrimes 729113596Snectar 730113596Snectarstatic int 731113596Snectarwrap_getgrent_r(union key key __unused, struct group *grp, char *buffer, 732113596Snectar size_t bufsize, struct group **res) 7331573Srgrimes{ 734113596Snectar return (getgrent_r(grp, buffer, bufsize, res)); 7351573Srgrimes} 7361573Srgrimes 73765532Snectar 738113596Snectarstruct group * 739113596Snectargetgrnam(const char *name) 740113596Snectar{ 741113596Snectar union key key; 74265532Snectar 743113596Snectar key.name = name; 744113596Snectar return (getgr(wrap_getgrnam_r, key)); 745113596Snectar} 746113596Snectar 747113596Snectar 748113596Snectarstruct group * 749113596Snectargetgrgid(gid_t gid) 7501573Srgrimes{ 751113596Snectar union key key; 75220911Swosch 753113596Snectar key.gid = gid; 754113596Snectar return (getgr(wrap_getgrgid_r, key)); 75565532Snectar} 75620911Swosch 7571573Srgrimes 758113596Snectarstruct group * 759113596Snectargetgrent(void) 76065532Snectar{ 761113596Snectar union key key; 76220911Swosch 763113596Snectar key.gid = 0; /* not used */ 764113596Snectar return (getgr(wrap_getgrent_r, key)); 765113596Snectar} 76665532Snectar 76765532Snectar 768113596Snectarstatic int 769113596Snectaris_comment_line(const char *s, size_t n) 770113596Snectar{ 771113596Snectar const char *eom; 77220911Swosch 773113596Snectar eom = &s[n]; 774113596Snectar 775113596Snectar for (; s < eom; s++) 776113596Snectar if (*s == '#' || !isspace((unsigned char)*s)) 77765532Snectar break; 778113596Snectar return (*s == '#' || s == eom); 779113596Snectar} 78065532Snectar 781113596Snectar 782113596Snectar/* 783113596Snectar * files backend 784113596Snectar */ 785113596Snectarstatic void 786113596Snectarfiles_endstate(void *p) 787113596Snectar{ 788113596Snectar 789113596Snectar if (p == NULL) 790113596Snectar return; 791113596Snectar if (((struct files_state *)p)->fp != NULL) 792113596Snectar fclose(((struct files_state *)p)->fp); 793113596Snectar free(p); 794113596Snectar} 795113596Snectar 796113596Snectar 797113596Snectarstatic int 798113596Snectarfiles_setgrent(void *retval, void *mdata, va_list ap) 799113596Snectar{ 800113596Snectar struct files_state *st; 801113596Snectar int rv, stayopen; 802113596Snectar 803113596Snectar rv = files_getstate(&st); 804113596Snectar if (rv != 0) 805113596Snectar return (NS_UNAVAIL); 806113596Snectar switch ((enum constants)mdata) { 807113596Snectar case SETGRENT: 808113596Snectar stayopen = va_arg(ap, int); 809113596Snectar if (st->fp != NULL) 810113596Snectar rewind(st->fp); 811113596Snectar else if (stayopen) 812244092Sjilles st->fp = fopen(_PATH_GROUP, "re"); 813113596Snectar break; 814113596Snectar case ENDGRENT: 815113596Snectar if (st->fp != NULL) { 816113596Snectar fclose(st->fp); 817113596Snectar st->fp = NULL; 818112404Srobert } 819113596Snectar break; 820113596Snectar default: 821113596Snectar break; 82265532Snectar } 823113596Snectar return (NS_UNAVAIL); 82465532Snectar} 82520911Swosch 82620911Swosch 82765532Snectarstatic int 828113596Snectarfiles_group(void *retval, void *mdata, va_list ap) 82965532Snectar{ 830113596Snectar struct files_state *st; 831113596Snectar enum nss_lookup_type how; 832113596Snectar const char *name, *line; 833113596Snectar struct group *grp; 834113596Snectar gid_t gid; 835113596Snectar char *buffer; 836113596Snectar size_t bufsize, linesize; 837159144Smaxim off_t pos; 838113596Snectar int rv, stayopen, *errnop; 83965532Snectar 840113596Snectar name = NULL; 841113596Snectar gid = (gid_t)-1; 842113596Snectar how = (enum nss_lookup_type)mdata; 843113596Snectar switch (how) { 844113596Snectar case nss_lt_name: 845113596Snectar name = va_arg(ap, const char *); 846113596Snectar break; 847113596Snectar case nss_lt_id: 848113596Snectar gid = va_arg(ap, gid_t); 849113596Snectar break; 850113596Snectar case nss_lt_all: 851113596Snectar break; 852113596Snectar default: 853113596Snectar return (NS_NOTFOUND); 854113596Snectar } 855113596Snectar grp = va_arg(ap, struct group *); 856113596Snectar buffer = va_arg(ap, char *); 857113596Snectar bufsize = va_arg(ap, size_t); 858113596Snectar errnop = va_arg(ap, int *); 859113596Snectar *errnop = files_getstate(&st); 860113596Snectar if (*errnop != 0) 861113596Snectar return (NS_UNAVAIL); 862113596Snectar if (st->fp == NULL && 863244092Sjilles ((st->fp = fopen(_PATH_GROUP, "re")) == NULL)) { 864113596Snectar *errnop = errno; 865113596Snectar return (NS_UNAVAIL); 866113596Snectar } 867113596Snectar if (how == nss_lt_all) 868113596Snectar stayopen = 1; 869113596Snectar else { 870113596Snectar rewind(st->fp); 871113596Snectar stayopen = st->stayopen; 872113596Snectar } 873113596Snectar rv = NS_NOTFOUND; 874159144Smaxim pos = ftello(st->fp); 875113596Snectar while ((line = fgetln(st->fp, &linesize)) != NULL) { 876113596Snectar if (line[linesize-1] == '\n') 877113596Snectar linesize--; 878113596Snectar rv = __gr_match_entry(line, linesize, how, name, gid); 879113596Snectar if (rv != NS_SUCCESS) 880113596Snectar continue; 881113596Snectar /* We need room at least for the line, a string NUL 882113596Snectar * terminator, alignment padding, and one (char *) 883113596Snectar * pointer for the member list terminator. 884113596Snectar */ 885113596Snectar if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) { 886113596Snectar *errnop = ERANGE; 887113596Snectar rv = NS_RETURN; 88811286Swpaul break; 8898172Swpaul } 890113596Snectar memcpy(buffer, line, linesize); 891113596Snectar buffer[linesize] = '\0'; 892113596Snectar rv = __gr_parse_entry(buffer, linesize, grp, 893113596Snectar &buffer[linesize + 1], bufsize - linesize - 1, errnop); 894113596Snectar if (rv & NS_TERMINATE) 89565532Snectar break; 896160355Smaxim pos = ftello(st->fp); 89765532Snectar } 898113596Snectar if (!stayopen && st->fp != NULL) { 899113596Snectar fclose(st->fp); 900113596Snectar st->fp = NULL; 90165532Snectar } 902113596Snectar if (rv == NS_SUCCESS && retval != NULL) 903113596Snectar *(struct group **)retval = grp; 904162391Smaxim else if (rv == NS_RETURN && *errnop == ERANGE && st->fp != NULL) 905160355Smaxim fseeko(st->fp, pos, SEEK_SET); 906113596Snectar return (rv); 90765532Snectar} 90865532Snectar 909113596Snectar 910113596Snectar#ifdef HESIOD 91165532Snectar/* 912113596Snectar * dns backend 91365532Snectar */ 914113596Snectarstatic void 915113596Snectardns_endstate(void *p) 916113596Snectar{ 91765532Snectar 918113596Snectar free(p); 919113596Snectar} 920113596Snectar 921113596Snectar 92265532Snectarstatic int 923113596Snectardns_setgrent(void *retval, void *cb_data, va_list ap) 92465532Snectar{ 925113596Snectar struct dns_state *st; 926113596Snectar int rv; 92765532Snectar 928113596Snectar rv = dns_getstate(&st); 929113596Snectar if (rv != 0) 930113596Snectar return (NS_UNAVAIL); 931113596Snectar st->counter = 0; 932113596Snectar return (NS_UNAVAIL); 933113596Snectar} 934113596Snectar 935113596Snectar 936113596Snectarstatic int 937113596Snectardns_group(void *retval, void *mdata, va_list ap) 938113596Snectar{ 939113596Snectar char buf[HESIOD_NAME_MAX]; 940113596Snectar struct dns_state *st; 941113596Snectar struct group *grp; 942113596Snectar const char *name, *label; 943113596Snectar void *ctx; 944113596Snectar char *buffer, **hes; 945113596Snectar size_t bufsize, adjsize, linesize; 946113596Snectar gid_t gid; 947113596Snectar enum nss_lookup_type how; 948113596Snectar int rv, *errnop; 949113596Snectar 950113596Snectar ctx = NULL; 951113596Snectar hes = NULL; 952113596Snectar name = NULL; 953113596Snectar gid = (gid_t)-1; 954113596Snectar how = (enum nss_lookup_type)mdata; 955113596Snectar switch (how) { 956113596Snectar case nss_lt_name: 957113596Snectar name = va_arg(ap, const char *); 958113596Snectar break; 959113596Snectar case nss_lt_id: 960113596Snectar gid = va_arg(ap, gid_t); 961113596Snectar break; 962113596Snectar case nss_lt_all: 963113596Snectar break; 96465532Snectar } 965113596Snectar grp = va_arg(ap, struct group *); 966113596Snectar buffer = va_arg(ap, char *); 967113596Snectar bufsize = va_arg(ap, size_t); 968113596Snectar errnop = va_arg(ap, int *); 969113596Snectar *errnop = dns_getstate(&st); 970113596Snectar if (*errnop != 0) 971113596Snectar return (NS_UNAVAIL); 972113596Snectar if (hesiod_init(&ctx) != 0) { 973113596Snectar *errnop = errno; 974113596Snectar rv = NS_UNAVAIL; 975113596Snectar goto fin; 976113596Snectar } 977113596Snectar do { 978113596Snectar rv = NS_NOTFOUND; 979113596Snectar switch (how) { 980113596Snectar case nss_lt_name: 981113596Snectar label = name; 982113596Snectar break; 983113596Snectar case nss_lt_id: 984113596Snectar if (snprintf(buf, sizeof(buf), "%lu", 985113596Snectar (unsigned long)gid) >= sizeof(buf)) 986113596Snectar goto fin; 987113596Snectar label = buf; 988113596Snectar break; 989113596Snectar case nss_lt_all: 990113596Snectar if (st->counter < 0) 991113596Snectar goto fin; 992113596Snectar if (snprintf(buf, sizeof(buf), "group-%ld", 993113596Snectar st->counter++) >= sizeof(buf)) 994113596Snectar goto fin; 995113596Snectar label = buf; 996113596Snectar break; 997113596Snectar } 998113596Snectar hes = hesiod_resolve(ctx, label, 999113596Snectar how == nss_lt_id ? "gid" : "group"); 1000113596Snectar if ((how == nss_lt_id && hes == NULL && 1001113596Snectar (hes = hesiod_resolve(ctx, buf, "group")) == NULL) || 1002113596Snectar hes == NULL) { 1003113596Snectar if (how == nss_lt_all) 1004113596Snectar st->counter = -1; 1005113596Snectar if (errno != ENOENT) 1006113596Snectar *errnop = errno; 1007113596Snectar goto fin; 1008113596Snectar } 1009113596Snectar rv = __gr_match_entry(hes[0], strlen(hes[0]), how, name, gid); 1010113596Snectar if (rv != NS_SUCCESS) { 1011113596Snectar hesiod_free_list(ctx, hes); 1012113596Snectar hes = NULL; 1013113596Snectar continue; 1014113596Snectar } 1015113596Snectar /* We need room at least for the line, a string NUL 1016113596Snectar * terminator, alignment padding, and one (char *) 1017113596Snectar * pointer for the member list terminator. 1018113596Snectar */ 1019113596Snectar adjsize = bufsize - _ALIGNBYTES - sizeof(char *); 1020114443Snectar linesize = strlcpy(buffer, hes[0], adjsize); 1021113596Snectar if (linesize >= adjsize) { 1022113596Snectar *errnop = ERANGE; 1023113596Snectar rv = NS_RETURN; 1024113596Snectar goto fin; 1025113596Snectar } 1026113596Snectar hesiod_free_list(ctx, hes); 1027113596Snectar hes = NULL; 1028113596Snectar rv = __gr_parse_entry(buffer, linesize, grp, 1029113596Snectar &buffer[linesize + 1], bufsize - linesize - 1, errnop); 1030113596Snectar } while (how == nss_lt_all && !(rv & NS_TERMINATE)); 1031113596Snectarfin: 1032113596Snectar if (hes != NULL) 1033113596Snectar hesiod_free_list(ctx, hes); 1034113596Snectar if (ctx != NULL) 1035113596Snectar hesiod_end(ctx); 1036113596Snectar if (rv == NS_SUCCESS && retval != NULL) 1037113596Snectar *(struct group **)retval = grp; 1038113596Snectar return (rv); 103965532Snectar} 1040113596Snectar#endif /* HESIOD */ 104165532Snectar 1042113596Snectar 1043113596Snectar#ifdef YP 104465532Snectar/* 1045113596Snectar * nis backend 104665532Snectar */ 1047113596Snectarstatic void 1048113596Snectarnis_endstate(void *p) 1049113596Snectar{ 105065532Snectar 1051113596Snectar if (p == NULL) 1052113596Snectar return; 1053113596Snectar free(((struct nis_state *)p)->key); 1054113596Snectar free(p); 1055113596Snectar} 105665532Snectar 1057113596Snectar 105865532Snectarstatic int 1059113596Snectarnis_setgrent(void *retval, void *cb_data, va_list ap) 106065532Snectar{ 1061113596Snectar struct nis_state *st; 1062113596Snectar int rv; 106365532Snectar 1064113596Snectar rv = nis_getstate(&st); 1065113596Snectar if (rv != 0) 1066113596Snectar return (NS_UNAVAIL); 1067113596Snectar st->done = 0; 1068113596Snectar free(st->key); 1069113596Snectar st->key = NULL; 1070113596Snectar return (NS_UNAVAIL); 107165532Snectar} 107265532Snectar 107365532Snectar 107465532Snectarstatic int 1075113596Snectarnis_group(void *retval, void *mdata, va_list ap) 107665532Snectar{ 1077113596Snectar char *map; 1078113596Snectar struct nis_state *st; 1079113596Snectar struct group *grp; 1080113596Snectar const char *name; 1081113596Snectar char *buffer, *key, *result; 1082113596Snectar size_t bufsize; 1083113596Snectar gid_t gid; 1084113596Snectar enum nss_lookup_type how; 1085113596Snectar int *errnop, keylen, resultlen, rv; 1086113596Snectar 1087113596Snectar name = NULL; 1088113596Snectar gid = (gid_t)-1; 1089113596Snectar how = (enum nss_lookup_type)mdata; 1090113596Snectar switch (how) { 1091113596Snectar case nss_lt_name: 1092113596Snectar name = va_arg(ap, const char *); 1093113596Snectar map = "group.byname"; 1094113596Snectar break; 1095113596Snectar case nss_lt_id: 1096113596Snectar gid = va_arg(ap, gid_t); 1097113596Snectar map = "group.bygid"; 1098113596Snectar break; 1099113596Snectar case nss_lt_all: 1100113596Snectar map = "group.byname"; 1101113596Snectar break; 1102113596Snectar } 1103113596Snectar grp = va_arg(ap, struct group *); 1104113596Snectar buffer = va_arg(ap, char *); 1105113596Snectar bufsize = va_arg(ap, size_t); 1106113596Snectar errnop = va_arg(ap, int *); 1107113596Snectar *errnop = nis_getstate(&st); 1108113596Snectar if (*errnop != 0) 1109113596Snectar return (NS_UNAVAIL); 1110113596Snectar if (st->domain[0] == '\0') { 1111113596Snectar if (getdomainname(st->domain, sizeof(st->domain)) != 0) { 1112113596Snectar *errnop = errno; 1113113596Snectar return (NS_UNAVAIL); 1114113596Snectar } 1115113596Snectar } 1116113596Snectar result = NULL; 1117113596Snectar do { 1118113596Snectar rv = NS_NOTFOUND; 1119113596Snectar switch (how) { 1120113596Snectar case nss_lt_name: 1121114443Snectar if (strlcpy(buffer, name, bufsize) >= bufsize) 1122113596Snectar goto erange; 1123113596Snectar break; 1124113596Snectar case nss_lt_id: 1125113596Snectar if (snprintf(buffer, bufsize, "%lu", 1126113596Snectar (unsigned long)gid) >= bufsize) 1127113596Snectar goto erange; 1128113596Snectar break; 1129113596Snectar case nss_lt_all: 1130113596Snectar if (st->done) 1131113596Snectar goto fin; 1132113596Snectar break; 1133113596Snectar } 1134113596Snectar result = NULL; 1135113596Snectar if (how == nss_lt_all) { 1136113596Snectar if (st->key == NULL) 1137113596Snectar rv = yp_first(st->domain, map, &st->key, 1138113596Snectar &st->keylen, &result, &resultlen); 1139113596Snectar else { 1140113596Snectar key = st->key; 1141113596Snectar keylen = st->keylen; 1142113596Snectar st->key = NULL; 1143113596Snectar rv = yp_next(st->domain, map, key, keylen, 1144113596Snectar &st->key, &st->keylen, &result, 1145113596Snectar &resultlen); 1146113596Snectar free(key); 1147113596Snectar } 1148113596Snectar if (rv != 0) { 1149113596Snectar free(result); 1150113596Snectar free(st->key); 1151113596Snectar st->key = NULL; 1152113596Snectar if (rv == YPERR_NOMORE) { 1153113596Snectar st->done = 1; 1154113596Snectar rv = NS_NOTFOUND; 1155113596Snectar } else 1156113596Snectar rv = NS_UNAVAIL; 1157113596Snectar goto fin; 1158113596Snectar } 1159113596Snectar } else { 1160113596Snectar rv = yp_match(st->domain, map, buffer, strlen(buffer), 1161113596Snectar &result, &resultlen); 1162113596Snectar if (rv == YPERR_KEY) { 1163113596Snectar rv = NS_NOTFOUND; 1164113596Snectar continue; 1165113596Snectar } else if (rv != 0) { 1166113596Snectar free(result); 1167113596Snectar rv = NS_UNAVAIL; 1168113596Snectar continue; 1169113596Snectar } 1170113596Snectar } 1171113596Snectar /* We need room at least for the line, a string NUL 1172113596Snectar * terminator, alignment padding, and one (char *) 1173113596Snectar * pointer for the member list terminator. 1174113596Snectar */ 1175113596Snectar if (resultlen >= bufsize - _ALIGNBYTES - sizeof(char *)) 1176113596Snectar goto erange; 1177113596Snectar memcpy(buffer, result, resultlen); 1178113596Snectar buffer[resultlen] = '\0'; 1179113596Snectar free(result); 1180113596Snectar rv = __gr_match_entry(buffer, resultlen, how, name, gid); 1181113596Snectar if (rv == NS_SUCCESS) 1182113596Snectar rv = __gr_parse_entry(buffer, resultlen, grp, 1183113596Snectar &buffer[resultlen+1], bufsize - resultlen - 1, 1184113596Snectar errnop); 1185113596Snectar } while (how == nss_lt_all && !(rv & NS_TERMINATE)); 1186113596Snectarfin: 1187113596Snectar if (rv == NS_SUCCESS && retval != NULL) 1188113596Snectar *(struct group **)retval = grp; 1189113596Snectar return (rv); 1190113596Snectarerange: 1191113596Snectar *errnop = ERANGE; 1192113596Snectar return (NS_RETURN); 1193113596Snectar} 1194113596Snectar#endif /* YP */ 119565532Snectar 119618046Swpaul 119765532Snectar 1198113596Snectar/* 1199113596Snectar * compat backend 1200113596Snectar */ 1201113596Snectarstatic void 1202113596Snectarcompat_endstate(void *p) 1203113596Snectar{ 1204113596Snectar struct compat_state *st; 120565532Snectar 1206113596Snectar if (p == NULL) 1207113596Snectar return; 1208113596Snectar st = (struct compat_state *)p; 1209113596Snectar free(st->name); 1210113596Snectar if (st->fp != NULL) 1211113596Snectar fclose(st->fp); 1212113596Snectar free(p); 1213113596Snectar} 121465532Snectar 121565532Snectar 1216113596Snectarstatic int 1217113596Snectarcompat_setgrent(void *retval, void *mdata, va_list ap) 1218113596Snectar{ 1219114021Snectar static const ns_src compatsrc[] = { 1220114021Snectar#ifdef YP 1221114021Snectar { NSSRC_NIS, NS_SUCCESS }, 1222114021Snectar#endif 1223114021Snectar { NULL, 0 } 1224114021Snectar }; 1225114021Snectar ns_dtab dtab[] = { 1226114021Snectar#ifdef HESIOD 1227114021Snectar { NSSRC_DNS, dns_setgrent, NULL }, 1228114021Snectar#endif 1229114021Snectar#ifdef YP 1230114021Snectar { NSSRC_NIS, nis_setgrent, NULL }, 1231114021Snectar#endif 1232114021Snectar { NULL, NULL, NULL } 1233114021Snectar }; 1234113596Snectar struct compat_state *st; 1235113596Snectar int rv, stayopen; 1236113596Snectar 1237114021Snectar#define set_setent(x, y) do { \ 1238114021Snectar int i; \ 1239114021Snectar \ 1240114021Snectar for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \ 1241114021Snectar x[i].mdata = (void *)y; \ 1242114021Snectar} while (0) 1243114021Snectar 1244113596Snectar rv = compat_getstate(&st); 1245113596Snectar if (rv != 0) 1246113596Snectar return (NS_UNAVAIL); 1247113596Snectar switch ((enum constants)mdata) { 1248113596Snectar case SETGRENT: 1249113596Snectar stayopen = va_arg(ap, int); 1250113596Snectar if (st->fp != NULL) 1251113596Snectar rewind(st->fp); 1252113596Snectar else if (stayopen) 1253244092Sjilles st->fp = fopen(_PATH_GROUP, "re"); 1254114021Snectar set_setent(dtab, mdata); 1255114021Snectar (void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgrent", 1256114021Snectar compatsrc, 0); 1257113596Snectar break; 1258113596Snectar case ENDGRENT: 1259113596Snectar if (st->fp != NULL) { 1260113596Snectar fclose(st->fp); 1261113596Snectar st->fp = NULL; 126265532Snectar } 1263114021Snectar set_setent(dtab, mdata); 1264114021Snectar (void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "endgrent", 1265114021Snectar compatsrc, 0); 1266113596Snectar break; 1267113596Snectar default: 1268113596Snectar break; 12691573Srgrimes } 1270113596Snectar st->compat = COMPAT_MODE_OFF; 1271113596Snectar free(st->name); 1272113596Snectar st->name = NULL; 1273113596Snectar return (NS_UNAVAIL); 1274114021Snectar#undef set_setent 12751573Srgrimes} 12762936Swollman 1277113596Snectar 12789331Swpaulstatic int 1279113596Snectarcompat_group(void *retval, void *mdata, va_list ap) 12802936Swollman{ 128165532Snectar static const ns_src compatsrc[] = { 1282113596Snectar#ifdef YP 1283113596Snectar { NSSRC_NIS, NS_SUCCESS }, 1284113596Snectar#endif 1285113596Snectar { NULL, 0 } 128665532Snectar }; 1287113596Snectar ns_dtab dtab[] = { 1288113596Snectar#ifdef YP 1289113596Snectar { NSSRC_NIS, nis_group, NULL }, 1290113596Snectar#endif 1291113596Snectar#ifdef HESIOD 1292113596Snectar { NSSRC_DNS, dns_group, NULL }, 1293113596Snectar#endif 1294113596Snectar { NULL, NULL, NULL } 1295113596Snectar }; 1296113596Snectar struct compat_state *st; 1297113596Snectar enum nss_lookup_type how; 1298113596Snectar const char *name, *line; 1299113596Snectar struct group *grp; 1300113596Snectar gid_t gid; 1301113596Snectar char *buffer, *p; 1302113596Snectar void *discard; 1303113596Snectar size_t bufsize, linesize; 1304159144Smaxim off_t pos; 1305113596Snectar int rv, stayopen, *errnop; 13062936Swollman 1307113596Snectar#define set_lookup_type(x, y) do { \ 1308113596Snectar int i; \ 1309113596Snectar \ 1310113596Snectar for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \ 1311113596Snectar x[i].mdata = (void *)y; \ 1312113596Snectar} while (0) 13132936Swollman 1314113596Snectar name = NULL; 1315113596Snectar gid = (gid_t)-1; 1316113596Snectar how = (enum nss_lookup_type)mdata; 1317113596Snectar switch (how) { 1318113596Snectar case nss_lt_name: 1319113596Snectar name = va_arg(ap, const char *); 1320113596Snectar break; 1321113596Snectar case nss_lt_id: 1322113596Snectar gid = va_arg(ap, gid_t); 1323113596Snectar break; 1324113596Snectar case nss_lt_all: 1325113596Snectar break; 1326113596Snectar default: 1327113596Snectar return (NS_NOTFOUND); 1328113596Snectar } 1329113596Snectar grp = va_arg(ap, struct group *); 1330113596Snectar buffer = va_arg(ap, char *); 1331113596Snectar bufsize = va_arg(ap, size_t); 1332113596Snectar errnop = va_arg(ap, int *); 1333113596Snectar *errnop = compat_getstate(&st); 1334113596Snectar if (*errnop != 0) 1335113596Snectar return (NS_UNAVAIL); 1336113596Snectar if (st->fp == NULL && 1337244092Sjilles ((st->fp = fopen(_PATH_GROUP, "re")) == NULL)) { 1338113596Snectar *errnop = errno; 1339113596Snectar rv = NS_UNAVAIL; 1340113596Snectar goto fin; 1341113596Snectar } 1342113596Snectar if (how == nss_lt_all) 1343113596Snectar stayopen = 1; 1344113596Snectar else { 1345113596Snectar rewind(st->fp); 1346113596Snectar stayopen = st->stayopen; 1347113596Snectar } 1348113596Snectardocompat: 1349113596Snectar switch (st->compat) { 1350113596Snectar case COMPAT_MODE_ALL: 1351113596Snectar set_lookup_type(dtab, how); 1352113596Snectar switch (how) { 1353113596Snectar case nss_lt_all: 1354113596Snectar rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT, 1355113596Snectar "getgrent_r", compatsrc, grp, buffer, bufsize, 1356113596Snectar errnop); 1357113596Snectar break; 1358113596Snectar case nss_lt_id: 1359113882Snectar rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT, 1360113596Snectar "getgrgid_r", compatsrc, gid, grp, buffer, bufsize, 1361113596Snectar errnop); 1362113596Snectar break; 1363113596Snectar case nss_lt_name: 1364113882Snectar rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT, 1365113596Snectar "getgrnam_r", compatsrc, name, grp, buffer, 1366113596Snectar bufsize, errnop); 1367113596Snectar break; 13682936Swollman } 1369113596Snectar if (rv & NS_TERMINATE) 1370113596Snectar goto fin; 1371113596Snectar st->compat = COMPAT_MODE_OFF; 1372113596Snectar break; 1373113596Snectar case COMPAT_MODE_NAME: 1374113596Snectar set_lookup_type(dtab, nss_lt_name); 1375113882Snectar rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT, 1376113596Snectar "getgrnam_r", compatsrc, st->name, grp, buffer, bufsize, 1377113596Snectar errnop); 1378113596Snectar switch (rv) { 1379113596Snectar case NS_SUCCESS: 1380113596Snectar switch (how) { 1381113596Snectar case nss_lt_name: 1382113596Snectar if (strcmp(name, grp->gr_name) != 0) 1383113596Snectar rv = NS_NOTFOUND; 1384113596Snectar break; 1385113596Snectar case nss_lt_id: 1386113596Snectar if (gid != grp->gr_gid) 1387113596Snectar rv = NS_NOTFOUND; 1388113596Snectar break; 1389113596Snectar default: 1390113596Snectar break; 13912936Swollman } 1392113596Snectar break; 1393113596Snectar case NS_RETURN: 1394113596Snectar goto fin; 1395113596Snectar default: 1396113596Snectar break; 1397113596Snectar } 1398113596Snectar free(st->name); 1399113596Snectar st->name = NULL; 1400113596Snectar st->compat = COMPAT_MODE_OFF; 1401113596Snectar if (rv == NS_SUCCESS) 1402113596Snectar goto fin; 1403113596Snectar break; 1404113596Snectar default: 1405113596Snectar break; 1406113596Snectar } 1407113596Snectar rv = NS_NOTFOUND; 1408159144Smaxim pos = ftello(st->fp); 1409113596Snectar while ((line = fgetln(st->fp, &linesize)) != NULL) { 1410113596Snectar if (line[linesize-1] == '\n') 1411113596Snectar linesize--; 1412113596Snectar if (linesize > 2 && line[0] == '+') { 1413113596Snectar p = memchr(&line[1], ':', linesize); 1414113596Snectar if (p == NULL || p == &line[1]) 1415113596Snectar st->compat = COMPAT_MODE_ALL; 1416113596Snectar else { 1417113596Snectar st->name = malloc(p - line); 1418113596Snectar if (st->name == NULL) { 1419113596Snectar syslog(LOG_ERR, 1420113596Snectar "getgrent memory allocation failure"); 1421113596Snectar *errnop = ENOMEM; 1422113596Snectar rv = NS_UNAVAIL; 1423113596Snectar break; 1424113596Snectar } 1425113596Snectar memcpy(st->name, &line[1], p - line - 1); 1426113596Snectar st->name[p - line - 1] = '\0'; 1427113596Snectar st->compat = COMPAT_MODE_NAME; 14282936Swollman } 1429113596Snectar goto docompat; 1430113596Snectar } 1431113596Snectar rv = __gr_match_entry(line, linesize, how, name, gid); 1432113596Snectar if (rv != NS_SUCCESS) 1433113596Snectar continue; 1434113596Snectar /* We need room at least for the line, a string NUL 1435113596Snectar * terminator, alignment padding, and one (char *) 1436113596Snectar * pointer for the member list terminator. 1437113596Snectar */ 1438113596Snectar if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) { 1439113596Snectar *errnop = ERANGE; 1440113596Snectar rv = NS_RETURN; 14412936Swollman break; 1442113596Snectar } 1443113596Snectar memcpy(buffer, line, linesize); 1444113596Snectar buffer[linesize] = '\0'; 1445113596Snectar rv = __gr_parse_entry(buffer, linesize, grp, 1446113596Snectar &buffer[linesize + 1], bufsize - linesize - 1, errnop); 1447113596Snectar if (rv & NS_TERMINATE) 1448113596Snectar break; 1449160355Smaxim pos = ftello(st->fp); 1450113596Snectar } 1451113596Snectarfin: 1452113596Snectar if (!stayopen && st->fp != NULL) { 1453113596Snectar fclose(st->fp); 1454113596Snectar st->fp = NULL; 1455113596Snectar } 1456113596Snectar if (rv == NS_SUCCESS && retval != NULL) 1457113596Snectar *(struct group **)retval = grp; 1458162391Smaxim else if (rv == NS_RETURN && *errnop == ERANGE && st->fp != NULL) 1459160355Smaxim fseeko(st->fp, pos, SEEK_SET); 1460113596Snectar return (rv); 1461113596Snectar#undef set_lookup_type 14622936Swollman} 14632936Swollman 1464113596Snectar 1465113596Snectar/* 1466113596Snectar * common group line matching and parsing 1467113596Snectar */ 1468113596Snectarint 1469113596Snectar__gr_match_entry(const char *line, size_t linesize, enum nss_lookup_type how, 1470113596Snectar const char *name, gid_t gid) 14712936Swollman{ 1472113596Snectar size_t namesize; 1473113596Snectar const char *p, *eol; 1474113596Snectar char *q; 1475113596Snectar unsigned long n; 1476113596Snectar int i, needed; 14772936Swollman 1478113596Snectar if (linesize == 0 || is_comment_line(line, linesize)) 1479113596Snectar return (NS_NOTFOUND); 1480113596Snectar switch (how) { 1481113596Snectar case nss_lt_name: needed = 1; break; 1482113596Snectar case nss_lt_id: needed = 2; break; 1483113596Snectar default: needed = 2; break; 14842936Swollman } 1485113596Snectar eol = &line[linesize]; 1486113596Snectar for (p = line, i = 0; i < needed && p < eol; p++) 1487113596Snectar if (*p == ':') 1488113596Snectar i++; 1489113596Snectar if (i < needed) 1490113596Snectar return (NS_NOTFOUND); 1491113596Snectar switch (how) { 1492113596Snectar case nss_lt_name: 1493113596Snectar namesize = strlen(name); 1494113596Snectar if (namesize + 1 == (size_t)(p - line) && 1495113596Snectar memcmp(line, name, namesize) == 0) 1496113596Snectar return (NS_SUCCESS); 1497113596Snectar break; 1498113596Snectar case nss_lt_id: 1499113596Snectar n = strtoul(p, &q, 10); 1500113596Snectar if (q < eol && *q == ':' && gid == (gid_t)n) 1501113596Snectar return (NS_SUCCESS); 1502113596Snectar break; 1503113596Snectar case nss_lt_all: 1504113596Snectar return (NS_SUCCESS); 1505113596Snectar default: 1506113596Snectar break; 1507113596Snectar } 1508113596Snectar return (NS_NOTFOUND); 1509113596Snectar} 15102936Swollman 15112936Swollman 1512113596Snectarint 1513113596Snectar__gr_parse_entry(char *line, size_t linesize, struct group *grp, char *membuf, 1514113596Snectar size_t membufsize, int *errnop) 15152936Swollman{ 1516113727Snectar char *s_gid, *s_mem, *p, **members; 1517113596Snectar unsigned long n; 1518113596Snectar int maxmembers; 15192936Swollman 1520113596Snectar memset(grp, 0, sizeof(*grp)); 1521113596Snectar members = (char **)_ALIGN(membuf); 1522113596Snectar membufsize -= (char *)members - membuf; 1523113596Snectar maxmembers = membufsize / sizeof(*members); 1524113596Snectar if (maxmembers <= 0 || 1525113596Snectar (grp->gr_name = strsep(&line, ":")) == NULL || 1526113596Snectar grp->gr_name[0] == '\0' || 1527113596Snectar (grp->gr_passwd = strsep(&line, ":")) == NULL || 1528113596Snectar (s_gid = strsep(&line, ":")) == NULL || 1529113596Snectar s_gid[0] == '\0') 1530113596Snectar return (NS_NOTFOUND); 1531113596Snectar s_mem = line; 1532113596Snectar n = strtoul(s_gid, &s_gid, 10); 1533113596Snectar if (s_gid[0] != '\0') 1534113596Snectar return (NS_NOTFOUND); 1535113596Snectar grp->gr_gid = (gid_t)n; 1536113596Snectar grp->gr_mem = members; 1537113596Snectar while (maxmembers > 1 && s_mem != NULL) { 1538113727Snectar p = strsep(&s_mem, ","); 1539113727Snectar if (p != NULL && *p != '\0') { 1540113727Snectar *members++ = p; 1541113727Snectar maxmembers--; 1542113727Snectar } 1543113596Snectar } 1544113596Snectar *members = NULL; 1545113596Snectar if (s_mem == NULL) 1546113596Snectar return (NS_SUCCESS); 1547113596Snectar else { 1548113596Snectar *errnop = ERANGE; 1549113596Snectar return (NS_RETURN); 1550113596Snectar } 15512936Swollman} 1552174547Sbushman 1553174547Sbushman 1554