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