getgrent.c revision 8172
1109998Smarkm/* 2109998Smarkm * Copyright (c) 1989, 1993 3109998Smarkm * The Regents of the University of California. All rights reserved. 4109998Smarkm * 5109998Smarkm * Redistribution and use in source and binary forms, with or without 6109998Smarkm * modification, are permitted provided that the following conditions 7109998Smarkm * are met: 8109998Smarkm * 1. Redistributions of source code must retain the above copyright 9109998Smarkm * notice, this list of conditions and the following disclaimer. 10109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright 11109998Smarkm * notice, this list of conditions and the following disclaimer in the 12109998Smarkm * documentation and/or other materials provided with the distribution. 13109998Smarkm * 3. All advertising materials mentioning features or use of this software 14109998Smarkm * must display the following acknowledgement: 15109998Smarkm * This product includes software developed by the University of 16109998Smarkm * California, Berkeley and its contributors. 17109998Smarkm * 4. Neither the name of the University nor the names of its contributors 18109998Smarkm * may be used to endorse or promote products derived from this software 19109998Smarkm * without specific prior written permission. 20109998Smarkm * 21109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22109998Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23205128Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24205128Ssimon * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25205128Ssimon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26205128Ssimon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27109998Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28205128Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29205128Ssimon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30205128Ssimon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31109998Smarkm * SUCH DAMAGE. 32205128Ssimon */ 33205128Ssimon 34205128Ssimon#if defined(LIBC_SCCS) && !defined(lint) 35205128Ssimonstatic char sccsid[] = "@(#)getgrent.c 8.2 (Berkeley) 3/21/94"; 36205128Ssimon#endif /* LIBC_SCCS and not lint */ 37205128Ssimon 38109998Smarkm#include <sys/types.h> 39109998Smarkm#include <stdio.h> 40205128Ssimon#include <stdlib.h> 41205128Ssimon#include <string.h> 42205128Ssimon#include <grp.h> 43109998Smarkm 44205128Ssimonstatic FILE *_gr_fp; 45205128Ssimonstatic struct group _gr_group; 46109998Smarkmstatic int _gr_stayopen; 47205128Ssimonstatic int grscan(), start_gr(); 48109998Smarkm#ifdef YP 49109998Smarkm#include <rpc/rpc.h> 50109998Smarkm#include <rpcsvc/yp_prot.h> 51109998Smarkm#include <rpcsvc/ypclnt.h> 52109998Smarkmstatic int _gr_stepping_yp; 53109998Smarkmstatic int _gr_yp_enabled; 54109998Smarkmstatic int _getypgroup(struct group *, const char *, char *); 55109998Smarkmstatic int _nextypgroup(struct group *); 56109998Smarkm#endif 57109998Smarkm 58#define MAXGRP 200 59static char *members[MAXGRP]; 60#define MAXLINELENGTH 1024 61static char line[MAXLINELENGTH]; 62 63struct group * 64getgrent() 65{ 66 if (!_gr_fp && !start_gr()) { 67 return NULL; 68 } 69 70#ifdef YP 71 if (_gr_stepping_yp) { 72 return (_nextypgroup(&_gr_group) ? &_gr_group : 0); 73 } 74#endif 75 76 if (!grscan(0, 0, NULL)) 77 return(NULL); 78#ifdef YP 79 if(_gr_group.gr_name[0] == '+' && _gr_group.gr_name[1]) { 80 _getypgroup(&_gr_group, &_gr_group.gr_name[1], 81 "group.byname"); 82 } else if(_gr_group.gr_name[0] == '+') { 83 return (_nextypgroup(&_gr_group) ? &_gr_group : 0); 84 } 85#endif 86 return(&_gr_group); 87} 88 89struct group * 90getgrnam(name) 91 const char *name; 92{ 93 int rval; 94 95 if (!start_gr()) 96 return(NULL); 97 rval = grscan(1, 0, name); 98#ifdef YP 99 if(!rval && (_gr_yp_enabled < 0 || (_gr_yp_enabled && 100 _gr_group.gr_name[0] == '+'))) { 101 rval = _getypgroup(&_gr_group, name, "group.byname"); 102 } 103#endif 104 if (!_gr_stayopen) 105 endgrent(); 106 return(rval ? &_gr_group : NULL); 107} 108 109struct group * 110#ifdef __STDC__ 111getgrgid(gid_t gid) 112#else 113getgrgid(gid) 114 gid_t gid; 115#endif 116{ 117 int rval; 118 119 if (!start_gr()) 120 return(NULL); 121 rval = grscan(1, gid, NULL); 122#ifdef YP 123 if(!rval && _gr_yp_enabled) { 124 char buf[16]; 125 snprintf(buf, sizeof buf, "%d", (unsigned)gid); 126 rval = _getypgroup(&_gr_group, buf, "group.bygid"); 127 } 128#endif 129 if (!_gr_stayopen) 130 endgrent(); 131 return(rval ? &_gr_group : NULL); 132} 133 134static int 135start_gr() 136{ 137 if (_gr_fp) { 138 rewind(_gr_fp); 139 return(1); 140 } 141 _gr_fp = fopen(_PATH_GROUP, "r"); 142 if(!_gr_fp) return 0; 143#ifdef YP 144 /* 145 * This is a disgusting hack, used to determine when YP is enabled. 146 * This would be easier if we had a group database to go along with 147 * the password database. 148 */ 149 { 150 char *line; 151 size_t linelen; 152 _gr_yp_enabled = 0; 153 while(line = fgetln(_gr_fp, &linelen)) { 154 if(line[0] == '+') { 155 if(line[1] && !_gr_yp_enabled) { 156 _gr_yp_enabled = 1; 157 } else { 158 _gr_yp_enabled = -1; 159 break; 160 } 161 } 162 } 163 rewind(_gr_fp); 164 } 165#endif 166 return 1; 167} 168 169int 170setgrent() 171{ 172 return(setgroupent(0)); 173} 174 175int 176setgroupent(stayopen) 177 int stayopen; 178{ 179 if (!start_gr()) 180 return(0); 181 _gr_stayopen = stayopen; 182#ifdef YP 183 _gr_stepping_yp = 0; 184#endif 185 return(1); 186} 187 188void 189endgrent() 190{ 191#ifdef YP 192 _gr_stepping_yp = 0; 193#endif 194 if (_gr_fp) { 195 (void)fclose(_gr_fp); 196 _gr_fp = NULL; 197 } 198} 199 200static int 201grscan(search, gid, name) 202 register int search, gid; 203 register char *name; 204{ 205 register char *cp, **m; 206 char *bp; 207 char *fgets(), *strsep(), *index(); 208 209 for (;;) { 210 if (!fgets(line, sizeof(line), _gr_fp)) 211 return(0); 212 bp = line; 213 /* skip lines that are too big */ 214 if (!index(line, '\n')) { 215 int ch; 216 217 while ((ch = getc(_gr_fp)) != '\n' && ch != EOF) 218 ; 219 continue; 220 } 221 _gr_group.gr_name = strsep(&bp, ":\n"); 222 if (search && name) { 223#ifdef YP 224 if(_gr_group.gr_name[0] == '+') { 225 if(strcmp(&_gr_group.gr_name[1], name)) { 226 continue; 227 } 228 return _getypgroup(&_gr_group, name, 229 "group.byname"); 230 } 231#endif /* YP */ 232 if(strcmp(_gr_group.gr_name, name)) { 233 continue; 234 } 235 } 236#ifdef YP 237 /* 238 * XXX We need to be careful to avoid proceeding 239 * past this point under certain circumstances or 240 * we risk dereferencing null pointers down below. 241 */ 242 if (_gr_group.gr_name[0] == '+') { 243 switch(search) { 244 case 0: 245 return(1); 246 case 1: 247 return(0); 248 default: 249 return(0); 250 } 251 } 252#endif /* YP */ 253 _gr_group.gr_passwd = strsep(&bp, ":\n"); 254 if (!(cp = strsep(&bp, ":\n"))) 255 continue; 256 _gr_group.gr_gid = atoi(cp); 257 if (search && name == NULL && _gr_group.gr_gid != gid) 258 continue; 259 cp = NULL; 260 for (m = _gr_group.gr_mem = members;; bp++) { 261 if (m == &members[MAXGRP - 1]) 262 break; 263 if (*bp == ',') { 264 if (cp) { 265 *bp = '\0'; 266 *m++ = cp; 267 cp = NULL; 268 } 269 } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') { 270 if (cp) { 271 *bp = '\0'; 272 *m++ = cp; 273 } 274 break; 275 } else if (cp == NULL) 276 cp = bp; 277 } 278 *m = NULL; 279 return(1); 280 } 281 /* NOTREACHED */ 282} 283 284#ifdef YP 285 286static void 287_gr_breakout_yp(struct group *gr, char *result) 288{ 289 char *s, *cp; 290 char **m; 291 292 s = strsep(&result, ":"); /* name */ 293 gr->gr_name = s; 294 295 s = strsep(&result, ":"); /* password */ 296 gr->gr_passwd = s; 297 298 s = strsep(&result, ":"); /* gid */ 299 gr->gr_gid = atoi(s); 300 301 s = result; 302 cp = 0; 303 304 for (m = _gr_group.gr_mem = members; /**/; s++) { 305 if (m == &members[MAXGRP - 1]) { 306 break; 307 } 308 if (*s == ',') { 309 if (cp) { 310 *s = '\0'; 311 *m++ = cp; 312 cp = NULL; 313 } 314 } else if (*s == '\0' || *s == '\n' || *s == ' ') { 315 if (cp) { 316 *s = '\0'; 317 *m++ = cp; 318 } 319 break; 320 } else if (cp == NULL) { 321 cp = s; 322 } 323 } 324 *m = NULL; 325} 326 327static char *_gr_yp_domain; 328 329static int 330_getypgroup(struct group *gr, const char *name, char *map) 331{ 332 char *result, *s; 333 static char resultbuf[1024]; 334 int resultlen; 335 336 if(!_gr_yp_domain) { 337 if(yp_get_default_domain(&_gr_yp_domain)) 338 return 0; 339 } 340 341 if(yp_match(_gr_yp_domain, map, name, strlen(name), 342 &result, &resultlen)) 343 return 0; 344 345 s = strchr(result, '\n'); 346 if(s) *s = '\0'; 347 348 if(resultlen >= sizeof resultbuf) return 0; 349 strcpy(resultbuf, result); 350 result = resultbuf; 351 _gr_breakout_yp(gr, resultbuf); 352 353 return 1; 354} 355 356 357static int 358_nextypgroup(struct group *gr) 359{ 360 static char *key; 361 static int keylen; 362 char *lastkey, *result; 363 static char resultbuf[1024]; 364 int resultlen; 365 int rv; 366 367 if(!_gr_yp_domain) { 368 if(yp_get_default_domain(&_gr_yp_domain)) 369 return 0; 370 } 371 372 if(!_gr_stepping_yp) { 373 if(key) free(key); 374 rv = yp_first(_gr_yp_domain, "group.byname", 375 &key, &keylen, &result, &resultlen); 376 if(rv) { 377 return 0; 378 } 379 _gr_stepping_yp = 1; 380 goto unpack; 381 } else { 382tryagain: 383 lastkey = key; 384 rv = yp_next(_gr_yp_domain, "group.byname", key, keylen, 385 &key, &keylen, &result, &resultlen); 386 free(lastkey); 387unpack: 388 if(rv) { 389 _gr_stepping_yp = 0; 390 return 0; 391 } 392 393 if(resultlen > sizeof(resultbuf)) { 394 free(result); 395 goto tryagain; 396 } 397 398 strcpy(resultbuf, result); 399 free(result); 400 if(result = strchr(resultbuf, '\n')) *result = '\0'; 401 _gr_breakout_yp(gr, resultbuf); 402 } 403 return 1; 404} 405 406#endif /* YP */ 407