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$"); 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 int rv; 663174547Sbushman 664174547Sbushman assert(uname != NULL); 665174547Sbushman /* groups may be NULL if just sizing when invoked with maxgrp = 0 */ 666174547Sbushman assert(grpcnt != NULL); 667174547Sbushman 668174547Sbushman *grpcnt = 0; 669174547Sbushman rv = _nsdispatch(NULL, dtab, NSDB_GROUP, "getgroupmembership", 670174547Sbushman defaultsrc, uname, agroup, groups, maxgrp, grpcnt); 671174547Sbushman 672174547Sbushman /* too many groups found? */ 673174547Sbushman return (*grpcnt > maxgrp ? -1 : 0); 674174547Sbushman} 675174547Sbushman 676174547Sbushman 677113596Snectarstatic struct group grp; 678113596Snectarstatic char *grp_storage; 679113596Snectarstatic size_t grp_storage_size; 680113596Snectar 681113596Snectarstatic struct group * 682113596Snectargetgr(int (*fn)(union key, struct group *, char *, size_t, struct group **), 683113596Snectar union key key) 68465532Snectar{ 685113596Snectar int rv; 686113596Snectar struct group *res; 687113596Snectar 688113596Snectar if (grp_storage == NULL) { 689113596Snectar grp_storage = malloc(GRP_STORAGE_INITIAL); 690113596Snectar if (grp_storage == NULL) 691113596Snectar return (NULL); 692113596Snectar grp_storage_size = GRP_STORAGE_INITIAL; 69320911Swosch } 694113596Snectar do { 695113596Snectar rv = fn(key, &grp, grp_storage, grp_storage_size, &res); 696113596Snectar if (res == NULL && rv == ERANGE) { 697113596Snectar free(grp_storage); 698113596Snectar if ((grp_storage_size << 1) > GRP_STORAGE_MAX) { 699113596Snectar grp_storage = NULL; 700129367Skientzle errno = ERANGE; 701113596Snectar return (NULL); 702113596Snectar } 703113596Snectar grp_storage_size <<= 1; 704113596Snectar grp_storage = malloc(grp_storage_size); 705113596Snectar if (grp_storage == NULL) 706113596Snectar return (NULL); 707113596Snectar } 708113596Snectar } while (res == NULL && rv == ERANGE); 709129367Skientzle if (rv != 0) 710129367Skientzle errno = rv; 711113596Snectar return (res); 7121573Srgrimes} 7131573Srgrimes 714113596Snectar 715113596Snectarstatic int 716113596Snectarwrap_getgrnam_r(union key key, struct group *grp, char *buffer, size_t bufsize, 717113596Snectar struct group **res) 7181573Srgrimes{ 719113596Snectar return (getgrnam_r(key.name, grp, buffer, bufsize, res)); 7201573Srgrimes} 7211573Srgrimes 722113596Snectar 723113596Snectarstatic int 724113596Snectarwrap_getgrgid_r(union key key, struct group *grp, char *buffer, size_t bufsize, 725113596Snectar struct group **res) 7261573Srgrimes{ 727113596Snectar return (getgrgid_r(key.gid, grp, buffer, bufsize, res)); 7281573Srgrimes} 7291573Srgrimes 730113596Snectar 731113596Snectarstatic int 732113596Snectarwrap_getgrent_r(union key key __unused, struct group *grp, char *buffer, 733113596Snectar size_t bufsize, struct group **res) 7341573Srgrimes{ 735113596Snectar return (getgrent_r(grp, buffer, bufsize, res)); 7361573Srgrimes} 7371573Srgrimes 73865532Snectar 739113596Snectarstruct group * 740113596Snectargetgrnam(const char *name) 741113596Snectar{ 742113596Snectar union key key; 74365532Snectar 744113596Snectar key.name = name; 745113596Snectar return (getgr(wrap_getgrnam_r, key)); 746113596Snectar} 747113596Snectar 748113596Snectar 749113596Snectarstruct group * 750113596Snectargetgrgid(gid_t gid) 7511573Srgrimes{ 752113596Snectar union key key; 75320911Swosch 754113596Snectar key.gid = gid; 755113596Snectar return (getgr(wrap_getgrgid_r, key)); 75665532Snectar} 75720911Swosch 7581573Srgrimes 759113596Snectarstruct group * 760113596Snectargetgrent(void) 76165532Snectar{ 762113596Snectar union key key; 76320911Swosch 764113596Snectar key.gid = 0; /* not used */ 765113596Snectar return (getgr(wrap_getgrent_r, key)); 766113596Snectar} 76765532Snectar 76865532Snectar 769113596Snectarstatic int 770113596Snectaris_comment_line(const char *s, size_t n) 771113596Snectar{ 772113596Snectar const char *eom; 77320911Swosch 774113596Snectar eom = &s[n]; 775113596Snectar 776113596Snectar for (; s < eom; s++) 777113596Snectar if (*s == '#' || !isspace((unsigned char)*s)) 77865532Snectar break; 779113596Snectar return (*s == '#' || s == eom); 780113596Snectar} 78165532Snectar 782113596Snectar 783113596Snectar/* 784113596Snectar * files backend 785113596Snectar */ 786113596Snectarstatic void 787113596Snectarfiles_endstate(void *p) 788113596Snectar{ 789113596Snectar 790113596Snectar if (p == NULL) 791113596Snectar return; 792113596Snectar if (((struct files_state *)p)->fp != NULL) 793113596Snectar fclose(((struct files_state *)p)->fp); 794113596Snectar free(p); 795113596Snectar} 796113596Snectar 797113596Snectar 798113596Snectarstatic int 799113596Snectarfiles_setgrent(void *retval, void *mdata, va_list ap) 800113596Snectar{ 801113596Snectar struct files_state *st; 802113596Snectar int rv, stayopen; 803113596Snectar 804113596Snectar rv = files_getstate(&st); 805113596Snectar if (rv != 0) 806113596Snectar return (NS_UNAVAIL); 807113596Snectar switch ((enum constants)mdata) { 808113596Snectar case SETGRENT: 809113596Snectar stayopen = va_arg(ap, int); 810113596Snectar if (st->fp != NULL) 811113596Snectar rewind(st->fp); 812113596Snectar else if (stayopen) 813244092Sjilles st->fp = fopen(_PATH_GROUP, "re"); 814113596Snectar break; 815113596Snectar case ENDGRENT: 816113596Snectar if (st->fp != NULL) { 817113596Snectar fclose(st->fp); 818113596Snectar st->fp = NULL; 819112404Srobert } 820113596Snectar break; 821113596Snectar default: 822113596Snectar break; 82365532Snectar } 824113596Snectar return (NS_UNAVAIL); 82565532Snectar} 82620911Swosch 82720911Swosch 82865532Snectarstatic int 829113596Snectarfiles_group(void *retval, void *mdata, va_list ap) 83065532Snectar{ 831113596Snectar struct files_state *st; 832113596Snectar enum nss_lookup_type how; 833113596Snectar const char *name, *line; 834113596Snectar struct group *grp; 835113596Snectar gid_t gid; 836113596Snectar char *buffer; 837113596Snectar size_t bufsize, linesize; 838159144Smaxim off_t pos; 839113596Snectar int rv, stayopen, *errnop; 84065532Snectar 841113596Snectar name = NULL; 842113596Snectar gid = (gid_t)-1; 843113596Snectar how = (enum nss_lookup_type)mdata; 844113596Snectar switch (how) { 845113596Snectar case nss_lt_name: 846113596Snectar name = va_arg(ap, const char *); 847113596Snectar break; 848113596Snectar case nss_lt_id: 849113596Snectar gid = va_arg(ap, gid_t); 850113596Snectar break; 851113596Snectar case nss_lt_all: 852113596Snectar break; 853113596Snectar default: 854113596Snectar return (NS_NOTFOUND); 855113596Snectar } 856113596Snectar grp = va_arg(ap, struct group *); 857113596Snectar buffer = va_arg(ap, char *); 858113596Snectar bufsize = va_arg(ap, size_t); 859113596Snectar errnop = va_arg(ap, int *); 860113596Snectar *errnop = files_getstate(&st); 861113596Snectar if (*errnop != 0) 862113596Snectar return (NS_UNAVAIL); 863113596Snectar if (st->fp == NULL && 864244092Sjilles ((st->fp = fopen(_PATH_GROUP, "re")) == NULL)) { 865113596Snectar *errnop = errno; 866113596Snectar return (NS_UNAVAIL); 867113596Snectar } 868113596Snectar if (how == nss_lt_all) 869113596Snectar stayopen = 1; 870113596Snectar else { 871113596Snectar rewind(st->fp); 872113596Snectar stayopen = st->stayopen; 873113596Snectar } 874113596Snectar rv = NS_NOTFOUND; 875159144Smaxim pos = ftello(st->fp); 876113596Snectar while ((line = fgetln(st->fp, &linesize)) != NULL) { 877113596Snectar if (line[linesize-1] == '\n') 878113596Snectar linesize--; 879113596Snectar rv = __gr_match_entry(line, linesize, how, name, gid); 880113596Snectar if (rv != NS_SUCCESS) 881113596Snectar continue; 882113596Snectar /* We need room at least for the line, a string NUL 883113596Snectar * terminator, alignment padding, and one (char *) 884113596Snectar * pointer for the member list terminator. 885113596Snectar */ 886113596Snectar if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) { 887113596Snectar *errnop = ERANGE; 888113596Snectar rv = NS_RETURN; 88911286Swpaul break; 8908172Swpaul } 891113596Snectar memcpy(buffer, line, linesize); 892113596Snectar buffer[linesize] = '\0'; 893113596Snectar rv = __gr_parse_entry(buffer, linesize, grp, 894113596Snectar &buffer[linesize + 1], bufsize - linesize - 1, errnop); 895113596Snectar if (rv & NS_TERMINATE) 89665532Snectar break; 897160355Smaxim pos = ftello(st->fp); 89865532Snectar } 899113596Snectar if (!stayopen && st->fp != NULL) { 900113596Snectar fclose(st->fp); 901113596Snectar st->fp = NULL; 90265532Snectar } 903113596Snectar if (rv == NS_SUCCESS && retval != NULL) 904113596Snectar *(struct group **)retval = grp; 905162391Smaxim else if (rv == NS_RETURN && *errnop == ERANGE && st->fp != NULL) 906160355Smaxim fseeko(st->fp, pos, SEEK_SET); 907113596Snectar return (rv); 90865532Snectar} 90965532Snectar 910113596Snectar 911113596Snectar#ifdef HESIOD 91265532Snectar/* 913113596Snectar * dns backend 91465532Snectar */ 915113596Snectarstatic void 916113596Snectardns_endstate(void *p) 917113596Snectar{ 91865532Snectar 919113596Snectar free(p); 920113596Snectar} 921113596Snectar 922113596Snectar 92365532Snectarstatic int 924113596Snectardns_setgrent(void *retval, void *cb_data, va_list ap) 92565532Snectar{ 926113596Snectar struct dns_state *st; 927113596Snectar int rv; 92865532Snectar 929113596Snectar rv = dns_getstate(&st); 930113596Snectar if (rv != 0) 931113596Snectar return (NS_UNAVAIL); 932113596Snectar st->counter = 0; 933113596Snectar return (NS_UNAVAIL); 934113596Snectar} 935113596Snectar 936113596Snectar 937113596Snectarstatic int 938113596Snectardns_group(void *retval, void *mdata, va_list ap) 939113596Snectar{ 940113596Snectar char buf[HESIOD_NAME_MAX]; 941113596Snectar struct dns_state *st; 942113596Snectar struct group *grp; 943113596Snectar const char *name, *label; 944113596Snectar void *ctx; 945113596Snectar char *buffer, **hes; 946113596Snectar size_t bufsize, adjsize, linesize; 947113596Snectar gid_t gid; 948113596Snectar enum nss_lookup_type how; 949113596Snectar int rv, *errnop; 950113596Snectar 951113596Snectar ctx = NULL; 952113596Snectar hes = NULL; 953113596Snectar name = NULL; 954113596Snectar gid = (gid_t)-1; 955113596Snectar how = (enum nss_lookup_type)mdata; 956113596Snectar switch (how) { 957113596Snectar case nss_lt_name: 958113596Snectar name = va_arg(ap, const char *); 959113596Snectar break; 960113596Snectar case nss_lt_id: 961113596Snectar gid = va_arg(ap, gid_t); 962113596Snectar break; 963113596Snectar case nss_lt_all: 964113596Snectar break; 96565532Snectar } 966113596Snectar grp = va_arg(ap, struct group *); 967113596Snectar buffer = va_arg(ap, char *); 968113596Snectar bufsize = va_arg(ap, size_t); 969113596Snectar errnop = va_arg(ap, int *); 970113596Snectar *errnop = dns_getstate(&st); 971113596Snectar if (*errnop != 0) 972113596Snectar return (NS_UNAVAIL); 973113596Snectar if (hesiod_init(&ctx) != 0) { 974113596Snectar *errnop = errno; 975113596Snectar rv = NS_UNAVAIL; 976113596Snectar goto fin; 977113596Snectar } 978113596Snectar do { 979113596Snectar rv = NS_NOTFOUND; 980113596Snectar switch (how) { 981113596Snectar case nss_lt_name: 982113596Snectar label = name; 983113596Snectar break; 984113596Snectar case nss_lt_id: 985113596Snectar if (snprintf(buf, sizeof(buf), "%lu", 986113596Snectar (unsigned long)gid) >= sizeof(buf)) 987113596Snectar goto fin; 988113596Snectar label = buf; 989113596Snectar break; 990113596Snectar case nss_lt_all: 991113596Snectar if (st->counter < 0) 992113596Snectar goto fin; 993113596Snectar if (snprintf(buf, sizeof(buf), "group-%ld", 994113596Snectar st->counter++) >= sizeof(buf)) 995113596Snectar goto fin; 996113596Snectar label = buf; 997113596Snectar break; 998113596Snectar } 999113596Snectar hes = hesiod_resolve(ctx, label, 1000113596Snectar how == nss_lt_id ? "gid" : "group"); 1001113596Snectar if ((how == nss_lt_id && hes == NULL && 1002113596Snectar (hes = hesiod_resolve(ctx, buf, "group")) == NULL) || 1003113596Snectar hes == NULL) { 1004113596Snectar if (how == nss_lt_all) 1005113596Snectar st->counter = -1; 1006113596Snectar if (errno != ENOENT) 1007113596Snectar *errnop = errno; 1008113596Snectar goto fin; 1009113596Snectar } 1010113596Snectar rv = __gr_match_entry(hes[0], strlen(hes[0]), how, name, gid); 1011113596Snectar if (rv != NS_SUCCESS) { 1012113596Snectar hesiod_free_list(ctx, hes); 1013113596Snectar hes = NULL; 1014113596Snectar continue; 1015113596Snectar } 1016113596Snectar /* We need room at least for the line, a string NUL 1017113596Snectar * terminator, alignment padding, and one (char *) 1018113596Snectar * pointer for the member list terminator. 1019113596Snectar */ 1020113596Snectar adjsize = bufsize - _ALIGNBYTES - sizeof(char *); 1021114443Snectar linesize = strlcpy(buffer, hes[0], adjsize); 1022113596Snectar if (linesize >= adjsize) { 1023113596Snectar *errnop = ERANGE; 1024113596Snectar rv = NS_RETURN; 1025113596Snectar goto fin; 1026113596Snectar } 1027113596Snectar hesiod_free_list(ctx, hes); 1028113596Snectar hes = NULL; 1029113596Snectar rv = __gr_parse_entry(buffer, linesize, grp, 1030113596Snectar &buffer[linesize + 1], bufsize - linesize - 1, errnop); 1031113596Snectar } while (how == nss_lt_all && !(rv & NS_TERMINATE)); 1032113596Snectarfin: 1033113596Snectar if (hes != NULL) 1034113596Snectar hesiod_free_list(ctx, hes); 1035113596Snectar if (ctx != NULL) 1036113596Snectar hesiod_end(ctx); 1037113596Snectar if (rv == NS_SUCCESS && retval != NULL) 1038113596Snectar *(struct group **)retval = grp; 1039113596Snectar return (rv); 104065532Snectar} 1041113596Snectar#endif /* HESIOD */ 104265532Snectar 1043113596Snectar 1044113596Snectar#ifdef YP 104565532Snectar/* 1046113596Snectar * nis backend 104765532Snectar */ 1048113596Snectarstatic void 1049113596Snectarnis_endstate(void *p) 1050113596Snectar{ 105165532Snectar 1052113596Snectar if (p == NULL) 1053113596Snectar return; 1054113596Snectar free(((struct nis_state *)p)->key); 1055113596Snectar free(p); 1056113596Snectar} 105765532Snectar 1058113596Snectar 105965532Snectarstatic int 1060113596Snectarnis_setgrent(void *retval, void *cb_data, va_list ap) 106165532Snectar{ 1062113596Snectar struct nis_state *st; 1063113596Snectar int rv; 106465532Snectar 1065113596Snectar rv = nis_getstate(&st); 1066113596Snectar if (rv != 0) 1067113596Snectar return (NS_UNAVAIL); 1068113596Snectar st->done = 0; 1069113596Snectar free(st->key); 1070113596Snectar st->key = NULL; 1071113596Snectar return (NS_UNAVAIL); 107265532Snectar} 107365532Snectar 107465532Snectar 107565532Snectarstatic int 1076113596Snectarnis_group(void *retval, void *mdata, va_list ap) 107765532Snectar{ 1078113596Snectar char *map; 1079113596Snectar struct nis_state *st; 1080113596Snectar struct group *grp; 1081113596Snectar const char *name; 1082113596Snectar char *buffer, *key, *result; 1083113596Snectar size_t bufsize; 1084113596Snectar gid_t gid; 1085113596Snectar enum nss_lookup_type how; 1086113596Snectar int *errnop, keylen, resultlen, rv; 1087113596Snectar 1088113596Snectar name = NULL; 1089113596Snectar gid = (gid_t)-1; 1090113596Snectar how = (enum nss_lookup_type)mdata; 1091113596Snectar switch (how) { 1092113596Snectar case nss_lt_name: 1093113596Snectar name = va_arg(ap, const char *); 1094113596Snectar map = "group.byname"; 1095113596Snectar break; 1096113596Snectar case nss_lt_id: 1097113596Snectar gid = va_arg(ap, gid_t); 1098113596Snectar map = "group.bygid"; 1099113596Snectar break; 1100113596Snectar case nss_lt_all: 1101113596Snectar map = "group.byname"; 1102113596Snectar break; 1103113596Snectar } 1104113596Snectar grp = va_arg(ap, struct group *); 1105113596Snectar buffer = va_arg(ap, char *); 1106113596Snectar bufsize = va_arg(ap, size_t); 1107113596Snectar errnop = va_arg(ap, int *); 1108113596Snectar *errnop = nis_getstate(&st); 1109113596Snectar if (*errnop != 0) 1110113596Snectar return (NS_UNAVAIL); 1111113596Snectar if (st->domain[0] == '\0') { 1112113596Snectar if (getdomainname(st->domain, sizeof(st->domain)) != 0) { 1113113596Snectar *errnop = errno; 1114113596Snectar return (NS_UNAVAIL); 1115113596Snectar } 1116113596Snectar } 1117113596Snectar result = NULL; 1118113596Snectar do { 1119113596Snectar rv = NS_NOTFOUND; 1120113596Snectar switch (how) { 1121113596Snectar case nss_lt_name: 1122114443Snectar if (strlcpy(buffer, name, bufsize) >= bufsize) 1123113596Snectar goto erange; 1124113596Snectar break; 1125113596Snectar case nss_lt_id: 1126113596Snectar if (snprintf(buffer, bufsize, "%lu", 1127113596Snectar (unsigned long)gid) >= bufsize) 1128113596Snectar goto erange; 1129113596Snectar break; 1130113596Snectar case nss_lt_all: 1131113596Snectar if (st->done) 1132113596Snectar goto fin; 1133113596Snectar break; 1134113596Snectar } 1135113596Snectar result = NULL; 1136113596Snectar if (how == nss_lt_all) { 1137113596Snectar if (st->key == NULL) 1138113596Snectar rv = yp_first(st->domain, map, &st->key, 1139113596Snectar &st->keylen, &result, &resultlen); 1140113596Snectar else { 1141113596Snectar key = st->key; 1142113596Snectar keylen = st->keylen; 1143113596Snectar st->key = NULL; 1144113596Snectar rv = yp_next(st->domain, map, key, keylen, 1145113596Snectar &st->key, &st->keylen, &result, 1146113596Snectar &resultlen); 1147113596Snectar free(key); 1148113596Snectar } 1149113596Snectar if (rv != 0) { 1150113596Snectar free(result); 1151113596Snectar free(st->key); 1152113596Snectar st->key = NULL; 1153113596Snectar if (rv == YPERR_NOMORE) { 1154113596Snectar st->done = 1; 1155113596Snectar rv = NS_NOTFOUND; 1156113596Snectar } else 1157113596Snectar rv = NS_UNAVAIL; 1158113596Snectar goto fin; 1159113596Snectar } 1160113596Snectar } else { 1161113596Snectar rv = yp_match(st->domain, map, buffer, strlen(buffer), 1162113596Snectar &result, &resultlen); 1163113596Snectar if (rv == YPERR_KEY) { 1164113596Snectar rv = NS_NOTFOUND; 1165113596Snectar continue; 1166113596Snectar } else if (rv != 0) { 1167113596Snectar free(result); 1168113596Snectar rv = NS_UNAVAIL; 1169113596Snectar continue; 1170113596Snectar } 1171113596Snectar } 1172113596Snectar /* We need room at least for the line, a string NUL 1173113596Snectar * terminator, alignment padding, and one (char *) 1174113596Snectar * pointer for the member list terminator. 1175113596Snectar */ 1176113596Snectar if (resultlen >= bufsize - _ALIGNBYTES - sizeof(char *)) 1177113596Snectar goto erange; 1178113596Snectar memcpy(buffer, result, resultlen); 1179113596Snectar buffer[resultlen] = '\0'; 1180113596Snectar free(result); 1181113596Snectar rv = __gr_match_entry(buffer, resultlen, how, name, gid); 1182113596Snectar if (rv == NS_SUCCESS) 1183113596Snectar rv = __gr_parse_entry(buffer, resultlen, grp, 1184113596Snectar &buffer[resultlen+1], bufsize - resultlen - 1, 1185113596Snectar errnop); 1186113596Snectar } while (how == nss_lt_all && !(rv & NS_TERMINATE)); 1187113596Snectarfin: 1188113596Snectar if (rv == NS_SUCCESS && retval != NULL) 1189113596Snectar *(struct group **)retval = grp; 1190113596Snectar return (rv); 1191113596Snectarerange: 1192113596Snectar *errnop = ERANGE; 1193113596Snectar return (NS_RETURN); 1194113596Snectar} 1195113596Snectar#endif /* YP */ 119665532Snectar 119718046Swpaul 119865532Snectar 1199113596Snectar/* 1200113596Snectar * compat backend 1201113596Snectar */ 1202113596Snectarstatic void 1203113596Snectarcompat_endstate(void *p) 1204113596Snectar{ 1205113596Snectar struct compat_state *st; 120665532Snectar 1207113596Snectar if (p == NULL) 1208113596Snectar return; 1209113596Snectar st = (struct compat_state *)p; 1210113596Snectar free(st->name); 1211113596Snectar if (st->fp != NULL) 1212113596Snectar fclose(st->fp); 1213113596Snectar free(p); 1214113596Snectar} 121565532Snectar 121665532Snectar 1217113596Snectarstatic int 1218113596Snectarcompat_setgrent(void *retval, void *mdata, va_list ap) 1219113596Snectar{ 1220114021Snectar static const ns_src compatsrc[] = { 1221114021Snectar#ifdef YP 1222114021Snectar { NSSRC_NIS, NS_SUCCESS }, 1223114021Snectar#endif 1224114021Snectar { NULL, 0 } 1225114021Snectar }; 1226114021Snectar ns_dtab dtab[] = { 1227114021Snectar#ifdef HESIOD 1228114021Snectar { NSSRC_DNS, dns_setgrent, NULL }, 1229114021Snectar#endif 1230114021Snectar#ifdef YP 1231114021Snectar { NSSRC_NIS, nis_setgrent, NULL }, 1232114021Snectar#endif 1233114021Snectar { NULL, NULL, NULL } 1234114021Snectar }; 1235113596Snectar struct compat_state *st; 1236113596Snectar int rv, stayopen; 1237113596Snectar 1238114021Snectar#define set_setent(x, y) do { \ 1239114021Snectar int i; \ 1240114021Snectar \ 1241114021Snectar for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \ 1242114021Snectar x[i].mdata = (void *)y; \ 1243114021Snectar} while (0) 1244114021Snectar 1245113596Snectar rv = compat_getstate(&st); 1246113596Snectar if (rv != 0) 1247113596Snectar return (NS_UNAVAIL); 1248113596Snectar switch ((enum constants)mdata) { 1249113596Snectar case SETGRENT: 1250113596Snectar stayopen = va_arg(ap, int); 1251113596Snectar if (st->fp != NULL) 1252113596Snectar rewind(st->fp); 1253113596Snectar else if (stayopen) 1254244092Sjilles st->fp = fopen(_PATH_GROUP, "re"); 1255114021Snectar set_setent(dtab, mdata); 1256114021Snectar (void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgrent", 1257114021Snectar compatsrc, 0); 1258113596Snectar break; 1259113596Snectar case ENDGRENT: 1260113596Snectar if (st->fp != NULL) { 1261113596Snectar fclose(st->fp); 1262113596Snectar st->fp = NULL; 126365532Snectar } 1264114021Snectar set_setent(dtab, mdata); 1265114021Snectar (void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "endgrent", 1266114021Snectar compatsrc, 0); 1267113596Snectar break; 1268113596Snectar default: 1269113596Snectar break; 12701573Srgrimes } 1271113596Snectar st->compat = COMPAT_MODE_OFF; 1272113596Snectar free(st->name); 1273113596Snectar st->name = NULL; 1274113596Snectar return (NS_UNAVAIL); 1275114021Snectar#undef set_setent 12761573Srgrimes} 12772936Swollman 1278113596Snectar 12799331Swpaulstatic int 1280113596Snectarcompat_group(void *retval, void *mdata, va_list ap) 12812936Swollman{ 128265532Snectar static const ns_src compatsrc[] = { 1283113596Snectar#ifdef YP 1284113596Snectar { NSSRC_NIS, NS_SUCCESS }, 1285113596Snectar#endif 1286113596Snectar { NULL, 0 } 128765532Snectar }; 1288113596Snectar ns_dtab dtab[] = { 1289113596Snectar#ifdef YP 1290113596Snectar { NSSRC_NIS, nis_group, NULL }, 1291113596Snectar#endif 1292113596Snectar#ifdef HESIOD 1293113596Snectar { NSSRC_DNS, dns_group, NULL }, 1294113596Snectar#endif 1295113596Snectar { NULL, NULL, NULL } 1296113596Snectar }; 1297113596Snectar struct compat_state *st; 1298113596Snectar enum nss_lookup_type how; 1299113596Snectar const char *name, *line; 1300113596Snectar struct group *grp; 1301113596Snectar gid_t gid; 1302113596Snectar char *buffer, *p; 1303113596Snectar void *discard; 1304113596Snectar size_t bufsize, linesize; 1305159144Smaxim off_t pos; 1306113596Snectar int rv, stayopen, *errnop; 13072936Swollman 1308113596Snectar#define set_lookup_type(x, y) do { \ 1309113596Snectar int i; \ 1310113596Snectar \ 1311113596Snectar for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \ 1312113596Snectar x[i].mdata = (void *)y; \ 1313113596Snectar} while (0) 13142936Swollman 1315113596Snectar name = NULL; 1316113596Snectar gid = (gid_t)-1; 1317113596Snectar how = (enum nss_lookup_type)mdata; 1318113596Snectar switch (how) { 1319113596Snectar case nss_lt_name: 1320113596Snectar name = va_arg(ap, const char *); 1321113596Snectar break; 1322113596Snectar case nss_lt_id: 1323113596Snectar gid = va_arg(ap, gid_t); 1324113596Snectar break; 1325113596Snectar case nss_lt_all: 1326113596Snectar break; 1327113596Snectar default: 1328113596Snectar return (NS_NOTFOUND); 1329113596Snectar } 1330113596Snectar grp = va_arg(ap, struct group *); 1331113596Snectar buffer = va_arg(ap, char *); 1332113596Snectar bufsize = va_arg(ap, size_t); 1333113596Snectar errnop = va_arg(ap, int *); 1334113596Snectar *errnop = compat_getstate(&st); 1335113596Snectar if (*errnop != 0) 1336113596Snectar return (NS_UNAVAIL); 1337113596Snectar if (st->fp == NULL && 1338244092Sjilles ((st->fp = fopen(_PATH_GROUP, "re")) == NULL)) { 1339113596Snectar *errnop = errno; 1340113596Snectar rv = NS_UNAVAIL; 1341113596Snectar goto fin; 1342113596Snectar } 1343113596Snectar if (how == nss_lt_all) 1344113596Snectar stayopen = 1; 1345113596Snectar else { 1346113596Snectar rewind(st->fp); 1347113596Snectar stayopen = st->stayopen; 1348113596Snectar } 1349113596Snectardocompat: 1350113596Snectar switch (st->compat) { 1351113596Snectar case COMPAT_MODE_ALL: 1352113596Snectar set_lookup_type(dtab, how); 1353113596Snectar switch (how) { 1354113596Snectar case nss_lt_all: 1355113596Snectar rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT, 1356113596Snectar "getgrent_r", compatsrc, grp, buffer, bufsize, 1357113596Snectar errnop); 1358113596Snectar break; 1359113596Snectar case nss_lt_id: 1360113882Snectar rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT, 1361113596Snectar "getgrgid_r", compatsrc, gid, grp, buffer, bufsize, 1362113596Snectar errnop); 1363113596Snectar break; 1364113596Snectar case nss_lt_name: 1365113882Snectar rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT, 1366113596Snectar "getgrnam_r", compatsrc, name, grp, buffer, 1367113596Snectar bufsize, errnop); 1368113596Snectar break; 13692936Swollman } 1370113596Snectar if (rv & NS_TERMINATE) 1371113596Snectar goto fin; 1372113596Snectar st->compat = COMPAT_MODE_OFF; 1373113596Snectar break; 1374113596Snectar case COMPAT_MODE_NAME: 1375113596Snectar set_lookup_type(dtab, nss_lt_name); 1376113882Snectar rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT, 1377113596Snectar "getgrnam_r", compatsrc, st->name, grp, buffer, bufsize, 1378113596Snectar errnop); 1379113596Snectar switch (rv) { 1380113596Snectar case NS_SUCCESS: 1381113596Snectar switch (how) { 1382113596Snectar case nss_lt_name: 1383113596Snectar if (strcmp(name, grp->gr_name) != 0) 1384113596Snectar rv = NS_NOTFOUND; 1385113596Snectar break; 1386113596Snectar case nss_lt_id: 1387113596Snectar if (gid != grp->gr_gid) 1388113596Snectar rv = NS_NOTFOUND; 1389113596Snectar break; 1390113596Snectar default: 1391113596Snectar break; 13922936Swollman } 1393113596Snectar break; 1394113596Snectar case NS_RETURN: 1395113596Snectar goto fin; 1396113596Snectar default: 1397113596Snectar break; 1398113596Snectar } 1399113596Snectar free(st->name); 1400113596Snectar st->name = NULL; 1401113596Snectar st->compat = COMPAT_MODE_OFF; 1402113596Snectar if (rv == NS_SUCCESS) 1403113596Snectar goto fin; 1404113596Snectar break; 1405113596Snectar default: 1406113596Snectar break; 1407113596Snectar } 1408113596Snectar rv = NS_NOTFOUND; 1409159144Smaxim pos = ftello(st->fp); 1410113596Snectar while ((line = fgetln(st->fp, &linesize)) != NULL) { 1411113596Snectar if (line[linesize-1] == '\n') 1412113596Snectar linesize--; 1413113596Snectar if (linesize > 2 && line[0] == '+') { 1414113596Snectar p = memchr(&line[1], ':', linesize); 1415113596Snectar if (p == NULL || p == &line[1]) 1416113596Snectar st->compat = COMPAT_MODE_ALL; 1417113596Snectar else { 1418113596Snectar st->name = malloc(p - line); 1419113596Snectar if (st->name == NULL) { 1420113596Snectar syslog(LOG_ERR, 1421113596Snectar "getgrent memory allocation failure"); 1422113596Snectar *errnop = ENOMEM; 1423113596Snectar rv = NS_UNAVAIL; 1424113596Snectar break; 1425113596Snectar } 1426113596Snectar memcpy(st->name, &line[1], p - line - 1); 1427113596Snectar st->name[p - line - 1] = '\0'; 1428113596Snectar st->compat = COMPAT_MODE_NAME; 14292936Swollman } 1430113596Snectar goto docompat; 1431113596Snectar } 1432113596Snectar rv = __gr_match_entry(line, linesize, how, name, gid); 1433113596Snectar if (rv != NS_SUCCESS) 1434113596Snectar continue; 1435113596Snectar /* We need room at least for the line, a string NUL 1436113596Snectar * terminator, alignment padding, and one (char *) 1437113596Snectar * pointer for the member list terminator. 1438113596Snectar */ 1439113596Snectar if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) { 1440113596Snectar *errnop = ERANGE; 1441113596Snectar rv = NS_RETURN; 14422936Swollman break; 1443113596Snectar } 1444113596Snectar memcpy(buffer, line, linesize); 1445113596Snectar buffer[linesize] = '\0'; 1446113596Snectar rv = __gr_parse_entry(buffer, linesize, grp, 1447113596Snectar &buffer[linesize + 1], bufsize - linesize - 1, errnop); 1448113596Snectar if (rv & NS_TERMINATE) 1449113596Snectar break; 1450160355Smaxim pos = ftello(st->fp); 1451113596Snectar } 1452113596Snectarfin: 1453113596Snectar if (!stayopen && st->fp != NULL) { 1454113596Snectar fclose(st->fp); 1455113596Snectar st->fp = NULL; 1456113596Snectar } 1457113596Snectar if (rv == NS_SUCCESS && retval != NULL) 1458113596Snectar *(struct group **)retval = grp; 1459162391Smaxim else if (rv == NS_RETURN && *errnop == ERANGE && st->fp != NULL) 1460160355Smaxim fseeko(st->fp, pos, SEEK_SET); 1461113596Snectar return (rv); 1462113596Snectar#undef set_lookup_type 14632936Swollman} 14642936Swollman 1465113596Snectar 1466113596Snectar/* 1467113596Snectar * common group line matching and parsing 1468113596Snectar */ 1469113596Snectarint 1470113596Snectar__gr_match_entry(const char *line, size_t linesize, enum nss_lookup_type how, 1471113596Snectar const char *name, gid_t gid) 14722936Swollman{ 1473113596Snectar size_t namesize; 1474113596Snectar const char *p, *eol; 1475113596Snectar char *q; 1476113596Snectar unsigned long n; 1477113596Snectar int i, needed; 14782936Swollman 1479113596Snectar if (linesize == 0 || is_comment_line(line, linesize)) 1480113596Snectar return (NS_NOTFOUND); 1481113596Snectar switch (how) { 1482113596Snectar case nss_lt_name: needed = 1; break; 1483113596Snectar case nss_lt_id: needed = 2; break; 1484113596Snectar default: needed = 2; break; 14852936Swollman } 1486113596Snectar eol = &line[linesize]; 1487113596Snectar for (p = line, i = 0; i < needed && p < eol; p++) 1488113596Snectar if (*p == ':') 1489113596Snectar i++; 1490113596Snectar if (i < needed) 1491113596Snectar return (NS_NOTFOUND); 1492113596Snectar switch (how) { 1493113596Snectar case nss_lt_name: 1494113596Snectar namesize = strlen(name); 1495113596Snectar if (namesize + 1 == (size_t)(p - line) && 1496113596Snectar memcmp(line, name, namesize) == 0) 1497113596Snectar return (NS_SUCCESS); 1498113596Snectar break; 1499113596Snectar case nss_lt_id: 1500113596Snectar n = strtoul(p, &q, 10); 1501113596Snectar if (q < eol && *q == ':' && gid == (gid_t)n) 1502113596Snectar return (NS_SUCCESS); 1503113596Snectar break; 1504113596Snectar case nss_lt_all: 1505113596Snectar return (NS_SUCCESS); 1506113596Snectar default: 1507113596Snectar break; 1508113596Snectar } 1509113596Snectar return (NS_NOTFOUND); 1510113596Snectar} 15112936Swollman 15122936Swollman 1513113596Snectarint 1514113596Snectar__gr_parse_entry(char *line, size_t linesize, struct group *grp, char *membuf, 1515113596Snectar size_t membufsize, int *errnop) 15162936Swollman{ 1517113727Snectar char *s_gid, *s_mem, *p, **members; 1518113596Snectar unsigned long n; 1519113596Snectar int maxmembers; 15202936Swollman 1521113596Snectar memset(grp, 0, sizeof(*grp)); 1522113596Snectar members = (char **)_ALIGN(membuf); 1523113596Snectar membufsize -= (char *)members - membuf; 1524113596Snectar maxmembers = membufsize / sizeof(*members); 1525113596Snectar if (maxmembers <= 0 || 1526113596Snectar (grp->gr_name = strsep(&line, ":")) == NULL || 1527113596Snectar grp->gr_name[0] == '\0' || 1528113596Snectar (grp->gr_passwd = strsep(&line, ":")) == NULL || 1529113596Snectar (s_gid = strsep(&line, ":")) == NULL || 1530113596Snectar s_gid[0] == '\0') 1531113596Snectar return (NS_NOTFOUND); 1532113596Snectar s_mem = line; 1533113596Snectar n = strtoul(s_gid, &s_gid, 10); 1534113596Snectar if (s_gid[0] != '\0') 1535113596Snectar return (NS_NOTFOUND); 1536113596Snectar grp->gr_gid = (gid_t)n; 1537113596Snectar grp->gr_mem = members; 1538113596Snectar while (maxmembers > 1 && s_mem != NULL) { 1539113727Snectar p = strsep(&s_mem, ","); 1540113727Snectar if (p != NULL && *p != '\0') { 1541113727Snectar *members++ = p; 1542113727Snectar maxmembers--; 1543113727Snectar } 1544113596Snectar } 1545113596Snectar *members = NULL; 1546113596Snectar if (s_mem == NULL) 1547113596Snectar return (NS_SUCCESS); 1548113596Snectar else { 1549113596Snectar *errnop = ERANGE; 1550113596Snectar return (NS_RETURN); 1551113596Snectar } 15522936Swollman} 1553174547Sbushman 1554174547Sbushman 1555