1/* $NetBSD: getgrent.c,v 1.12 2005/09/14 15:54:53 drochner Exp $ */ 2 3/* 4 * Copyright (c) 1989, 1991, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32/* 33 * Portions Copyright (c) 1994, Jason Downs. All Rights Reserved. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS 45 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 46 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 47 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, 48 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 49 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 50 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 51 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 54 * SUCH DAMAGE. 55 */ 56 57/* 58 * Copied from: lib/libc/gen/getgrent.c 59 * NetBSD: getgrent.c,v 1.46 2003/02/17 00:11:54 simonb Exp 60 * and then gutted, leaving only /etc/group support. 61 */ 62 63#include <sys/cdefs.h> 64 65#ifdef __weak_alias 66#define endgrent _endgrent 67#define getgrent _getgrent 68#define getgrgid _getgrgid 69#define getgrnam _getgrnam 70#define getgrnam_r _getgrnam_r 71#define setgrent _setgrent 72#define setgroupent _setgroupent 73#define getgrouplist _getgrouplist 74 75__weak_alias(endgrent,_endgrent) 76__weak_alias(getgrent,_getgrent) 77__weak_alias(getgrgid,_getgrgid) 78__weak_alias(getgrnam,_getgrnam) 79__weak_alias(getgrnam_r,_getgrnam_r) 80__weak_alias(setgrent,_setgrent) 81__weak_alias(setgroupent,_setgroupent) 82__weak_alias(getgrouplist,_getgrouplist) 83#endif 84 85#include <sys/param.h> 86 87#include <grp.h> 88#include <limits.h> 89#include <stdio.h> 90#include <stdlib.h> 91#include <string.h> 92#include <unistd.h> 93#include <errno.h> 94 95static FILE *_gr_fp; 96static struct group _gr_group; 97static int _gr_stayopen; 98static int _gr_filesdone; 99 100static int grscan(int, gid_t, const char *, const char *); 101static int grstart(void); 102static int grmatchline(int, gid_t, const char *, const char *); 103 104#define MAXGRP 200 105#define MAXLINELENGTH 1024 106 107static __aconst char *members[MAXGRP]; 108static char grline[MAXLINELENGTH]; 109 110struct group * 111getgrent(void) 112{ 113 114 if ((!_gr_fp && !grstart()) || !grscan(0, 0, NULL, NULL)) 115 return (NULL); 116 return &_gr_group; 117} 118 119int 120getgrnam_r(const char *name, struct group *grp, char *buffer, 121 size_t buflen, struct group **result) 122{ 123 struct group *gp, *bgp; 124 125 /* 126 * We blatantly cheat (don't provide reentrancy) 127 * and hope to get away with it 128 */ 129 130 *result = NULL; 131 bgp = (struct group*)buffer; 132 if (buflen < sizeof(struct group)) 133 return ENOMEM; 134 135 gp = getgrnam(name); 136 if (gp) { 137 *bgp = *gp; 138 *result = bgp; 139 } 140 141 return (gp) ? ENOENT : 0; 142} 143 144struct group * 145getgrnam(const char *name) 146{ 147 int rval; 148 149 if (!grstart()) 150 return NULL; 151 rval = grscan(1, 0, name, NULL); 152 if (!_gr_stayopen) 153 endgrent(); 154 return (rval) ? &_gr_group : NULL; 155} 156 157struct group * 158getgrgid(gid_t gid) 159{ 160 int rval; 161 162 if (!grstart()) 163 return NULL; 164 rval = grscan(1, gid, NULL, NULL); 165 if (!_gr_stayopen) 166 endgrent(); 167 return (rval) ? &_gr_group : NULL; 168} 169 170static int 171grstart(void) 172{ 173 174 _gr_filesdone = 0; 175 if (_gr_fp) { 176 rewind(_gr_fp); 177 return 1; 178 } 179 return (_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0; 180} 181 182void 183setgrent(void) 184{ 185 186 (void) setgroupent(0); 187} 188 189int 190setgroupent(int stayopen) 191{ 192 193 if (!grstart()) 194 return 0; 195 _gr_stayopen = stayopen; 196 return 1; 197} 198 199void 200endgrent(void) 201{ 202 203 _gr_filesdone = 0; 204 if (_gr_fp) { 205 (void)fclose(_gr_fp); 206 _gr_fp = NULL; 207 } 208} 209 210int 211getgrouplist(const char *uname, gid_t agroup, 212 gid_t *groups, int *grpcnt) 213{ 214 struct group *grp; 215 int maxgroups, i, ngroups, ret; 216 217 maxgroups = *grpcnt; 218 ret = 0; 219 ngroups = 0; 220 221 /* 222 * install primary group 223 */ 224 if (ngroups < maxgroups) 225 groups[ngroups] = agroup; 226 else 227 ret = -1; 228 ngroups++; 229 230 /* 231 * Scan the group file to find additional groups. 232 */ 233 setgrent(); 234 nextgroup: 235 while ((grp = getgrent()) != NULL) { 236 if (grp->gr_gid == agroup) 237 continue; 238 for (i = 0; grp->gr_mem[i]; i++) { 239 if (strcmp(grp->gr_mem[i], uname) != 0) 240 continue; 241 for (i = 0; i < MIN(ngroups, maxgroups); i++) { 242 if (grp->gr_gid == groups[i]) 243 goto nextgroup; 244 } 245 if (ngroups < maxgroups) 246 groups[ngroups] = grp->gr_gid; 247 else 248 ret = -1; 249 ngroups++; 250 break; 251 } 252 } 253 endgrent(); 254 *grpcnt = ngroups; 255 return ret; 256} 257 258static int 259grscan(int search, gid_t gid, const char *name, const char *user) 260{ 261 262 if (_gr_filesdone) 263 return 0; 264 for (;;) { 265 if (!fgets(grline, sizeof(grline), _gr_fp)) { 266 if (!search) 267 _gr_filesdone = 1; 268 return 0; 269 } 270 /* skip lines that are too big */ 271 if (!strchr(grline, '\n')) { 272 int ch; 273 274 while ((ch = getc(_gr_fp)) != '\n' && ch != EOF) 275 ; 276 continue; 277 } 278 if (grmatchline(search, gid, name, user)) 279 return 1; 280 } 281 /* NOTREACHED */ 282} 283 284static int 285grmatchline(int search, gid_t gid, const char *name, const char *user) 286{ 287 unsigned long id; 288 __aconst char **m; 289 char *cp, *bp, *ep; 290 291 /* name may be NULL if search is nonzero */ 292 293 bp = grline; 294 _gr_group.gr_name = strsep(&bp, ":\n"); 295 if (search && name && strcmp(_gr_group.gr_name, name)) 296 return 0; 297 _gr_group.gr_passwd = strsep(&bp, ":\n"); 298 if (!(cp = strsep(&bp, ":\n"))) 299 return 0; 300 id = strtoul(cp, &ep, 10); 301 if (id > GID_MAX || *ep != '\0') 302 return 0; 303 _gr_group.gr_gid = (gid_t)id; 304 if (search && name == NULL && _gr_group.gr_gid != gid) 305 return 0; 306 cp = NULL; 307 if (bp == NULL) 308 return 0; 309 for (_gr_group.gr_mem = m = members;; bp++) { 310 if (m == &members[MAXGRP - 1]) 311 break; 312 if (*bp == ',') { 313 if (cp) { 314 *bp = '\0'; 315 *m++ = cp; 316 cp = NULL; 317 } 318 } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') { 319 if (cp) { 320 *bp = '\0'; 321 *m++ = cp; 322 } 323 break; 324 } else if (cp == NULL) 325 cp = bp; 326 } 327 *m = NULL; 328 if (user) { 329 for (m = members; *m; m++) 330 if (!strcmp(user, *m)) 331 return 1; 332 return 0; 333 } 334 return 1; 335} 336