getgrent.c revision 1.10
1/* $NetBSD: getgrent.c,v 1.10 2005/04/01 13:11:12 he 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 setgrent _setgrent 71#define setgroupent _setgroupent 72#define getgroupmembership _getgroupmembership 73 74__weak_alias(endgrent,_endgrent) 75__weak_alias(getgrent,_getgrent) 76__weak_alias(getgrgid,_getgrgid) 77__weak_alias(getgrnam,_getgrnam) 78__weak_alias(setgrent,_setgrent) 79__weak_alias(setgroupent,_setgroupent) 80__weak_alias(getgroupmembership,_getgroupmembership) 81#endif 82 83#include <sys/param.h> 84 85#include <grp.h> 86#include <limits.h> 87#include <stdio.h> 88#include <stdlib.h> 89#include <string.h> 90#include <unistd.h> 91 92static FILE *_gr_fp; 93static struct group _gr_group; 94static int _gr_stayopen; 95static int _gr_filesdone; 96 97static int grscan(int, gid_t, const char *, const char *); 98static int grstart(void); 99static int grmatchline(int, gid_t, const char *, const char *); 100 101#define MAXGRP 200 102#define MAXLINELENGTH 1024 103 104static __aconst char *members[MAXGRP]; 105static char grline[MAXLINELENGTH]; 106 107struct group * 108getgrent(void) 109{ 110 111 if ((!_gr_fp && !grstart()) || !grscan(0, 0, NULL, NULL)) 112 return (NULL); 113 return &_gr_group; 114} 115 116struct group * 117getgrnam(const char *name) 118{ 119 int rval; 120 121 if (!grstart()) 122 return NULL; 123 rval = grscan(1, 0, name, NULL); 124 if (!_gr_stayopen) 125 endgrent(); 126 return (rval) ? &_gr_group : NULL; 127} 128 129struct group * 130getgrgid(gid_t gid) 131{ 132 int rval; 133 134 if (!grstart()) 135 return NULL; 136 rval = grscan(1, gid, NULL, NULL); 137 if (!_gr_stayopen) 138 endgrent(); 139 return (rval) ? &_gr_group : NULL; 140} 141 142static int 143grstart(void) 144{ 145 146 _gr_filesdone = 0; 147 if (_gr_fp) { 148 rewind(_gr_fp); 149 return 1; 150 } 151 return (_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0; 152} 153 154void 155setgrent(void) 156{ 157 158 (void) setgroupent(0); 159} 160 161int 162setgroupent(int stayopen) 163{ 164 165 if (!grstart()) 166 return 0; 167 _gr_stayopen = stayopen; 168 return 1; 169} 170 171void 172endgrent(void) 173{ 174 175 _gr_filesdone = 0; 176 if (_gr_fp) { 177 (void)fclose(_gr_fp); 178 _gr_fp = NULL; 179 } 180} 181 182int 183getgroupmembership(const char *uname, gid_t agroup, 184 gid_t *groups, int maxgroups, int *grpcnt) 185{ 186 struct group *grp; 187 int i, ngroups, ret; 188 189 ret = 0; 190 ngroups = 0; 191 192 /* 193 * install primary group 194 */ 195 if (ngroups < maxgroups) 196 groups[ngroups] = agroup; 197 else 198 ret = -1; 199 ngroups++; 200 201 /* 202 * Scan the group file to find additional groups. 203 */ 204 setgrent(); 205 nextgroup: 206 while ((grp = getgrent()) != NULL) { 207 if (grp->gr_gid == agroup) 208 continue; 209 for (i = 0; grp->gr_mem[i]; i++) { 210 if (strcmp(grp->gr_mem[i], uname) != 0) 211 continue; 212 for (i = 0; i < MIN(ngroups, maxgroups); i++) { 213 if (grp->gr_gid == groups[i]) 214 goto nextgroup; 215 } 216 if (ngroups < maxgroups) 217 groups[ngroups] = grp->gr_gid; 218 else 219 ret = -1; 220 ngroups++; 221 break; 222 } 223 } 224 endgrent(); 225 *grpcnt = ngroups; 226 return ret; 227} 228 229static int 230grscan(int search, gid_t gid, const char *name, const char *user) 231{ 232 233 if (_gr_filesdone) 234 return 0; 235 for (;;) { 236 if (!fgets(grline, sizeof(grline), _gr_fp)) { 237 if (!search) 238 _gr_filesdone = 1; 239 return 0; 240 } 241 /* skip lines that are too big */ 242 if (!strchr(grline, '\n')) { 243 int ch; 244 245 while ((ch = getc(_gr_fp)) != '\n' && ch != EOF) 246 ; 247 continue; 248 } 249 if (grmatchline(search, gid, name, user)) 250 return 1; 251 } 252 /* NOTREACHED */ 253} 254 255static int 256grmatchline(int search, gid_t gid, const char *name, const char *user) 257{ 258 unsigned long id; 259 __aconst char **m; 260 char *cp, *bp, *ep; 261 262 /* name may be NULL if search is nonzero */ 263 264 bp = grline; 265 _gr_group.gr_name = strsep(&bp, ":\n"); 266 if (search && name && strcmp(_gr_group.gr_name, name)) 267 return 0; 268 _gr_group.gr_passwd = strsep(&bp, ":\n"); 269 if (!(cp = strsep(&bp, ":\n"))) 270 return 0; 271 id = strtoul(cp, &ep, 10); 272 if (id > GID_MAX || *ep != '\0') 273 return 0; 274 _gr_group.gr_gid = (gid_t)id; 275 if (search && name == NULL && _gr_group.gr_gid != gid) 276 return 0; 277 cp = NULL; 278 if (bp == NULL) 279 return 0; 280 for (_gr_group.gr_mem = m = members;; bp++) { 281 if (m == &members[MAXGRP - 1]) 282 break; 283 if (*bp == ',') { 284 if (cp) { 285 *bp = '\0'; 286 *m++ = cp; 287 cp = NULL; 288 } 289 } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') { 290 if (cp) { 291 *bp = '\0'; 292 *m++ = cp; 293 } 294 break; 295 } else if (cp == NULL) 296 cp = bp; 297 } 298 *m = NULL; 299 if (user) { 300 for (m = members; *m; m++) 301 if (!strcmp(user, *m)) 302 return 1; 303 return 0; 304 } 305 return 1; 306} 307