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