getgrent.c revision 20756
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#ifdef YP 103 tryagain: 104#endif 105 rval = grscan(1, 0, name); 106#ifdef YP 107 if(rval == -1 && (_gr_yp_enabled < 0 || (_gr_yp_enabled && 108 _gr_group.gr_name[0] == '+'))) { 109 if (!(rval = _getypgroup(&_gr_group, name, "group.byname"))) 110 goto tryagain; 111 } 112#endif 113 if (!_gr_stayopen) 114 endgrent(); 115 return(rval ? &_gr_group : NULL); 116} 117 118struct group * 119#ifdef __STDC__ 120getgrgid(gid_t gid) 121#else 122getgrgid(gid) 123 gid_t gid; 124#endif 125{ 126 int rval; 127 128 if (!start_gr()) 129 return(NULL); 130#ifdef YP 131 tryagain: 132#endif 133 rval = grscan(1, gid, NULL); 134#ifdef YP 135 if(rval == -1 && _gr_yp_enabled) { 136 char buf[16]; 137 snprintf(buf, sizeof buf, "%d", (unsigned)gid); 138 if (!(rval = _getypgroup(&_gr_group, buf, "group.bygid"))) 139 goto tryagain; 140 } 141#endif 142 if (!_gr_stayopen) 143 endgrent(); 144 return(rval ? &_gr_group : NULL); 145} 146 147static int 148start_gr() 149{ 150 if (_gr_fp) { 151 rewind(_gr_fp); 152 return(1); 153 } 154 _gr_fp = fopen(_PATH_GROUP, "r"); 155 if(!_gr_fp) return 0; 156#ifdef YP 157 /* 158 * This is a disgusting hack, used to determine when YP is enabled. 159 * This would be easier if we had a group database to go along with 160 * the password database. 161 */ 162 { 163 char *line; 164 size_t linelen; 165 _gr_yp_enabled = 0; 166 while((line = fgetln(_gr_fp, &linelen)) != NULL) { 167 if(line[0] == '+') { 168 if(line[1] && line[1] != ':' && !_gr_yp_enabled) { 169 _gr_yp_enabled = 1; 170 } else { 171 _gr_yp_enabled = -1; 172 break; 173 } 174 } 175 } 176 rewind(_gr_fp); 177 } 178#endif 179 return 1; 180} 181 182int 183setgrent() 184{ 185 return(setgroupent(0)); 186} 187 188int 189setgroupent(stayopen) 190 int stayopen; 191{ 192 if (!start_gr()) 193 return(0); 194 _gr_stayopen = stayopen; 195#ifdef YP 196 _gr_stepping_yp = 0; 197#endif 198 return(1); 199} 200 201void 202endgrent() 203{ 204#ifdef YP 205 _gr_stepping_yp = 0; 206#endif 207 if (_gr_fp) { 208 (void)fclose(_gr_fp); 209 _gr_fp = NULL; 210 } 211} 212 213static int 214grscan(search, gid, name) 215 register int search, gid; 216 register char *name; 217{ 218 register char *cp, **m; 219 char *bp; 220#ifdef YP 221 int _ypfound; 222#endif; 223 for (;;) { 224#ifdef YP 225 _ypfound = 0; 226#endif 227 if (!fgets(line, sizeof(line), _gr_fp)) 228 return(0); 229 bp = line; 230 /* skip lines that are too big */ 231 if (!index(line, '\n')) { 232 int ch; 233 234 while ((ch = getc(_gr_fp)) != '\n' && ch != EOF) 235 ; 236 continue; 237 } 238 if ((_gr_group.gr_name = strsep(&bp, ":\n")) == NULL) 239 break; 240#ifdef YP 241 /* 242 * XXX We need to be careful to avoid proceeding 243 * past this point under certain circumstances or 244 * we risk dereferencing null pointers down below. 245 */ 246 if (_gr_group.gr_name[0] == '+') { 247 if (strlen(_gr_group.gr_name) == 1) { 248 switch(search) { 249 case 0: 250 return(1); 251 case 1: 252 return(-1); 253 default: 254 return(0); 255 } 256 } else { 257 cp = &_gr_group.gr_name[1]; 258 if (search && name != NULL) 259 if (strcmp(cp, name)) 260 continue; 261 if (!_getypgroup(&_gr_group, cp, 262 "group.byname")) 263 continue; 264 if (search && name == NULL) 265 if (gid != _gr_group.gr_gid) 266 continue; 267 /* We're going to override -- tell the world. */ 268 _ypfound++; 269 } 270 } 271#else 272 if (_gr_group.gr_name[0] == '+') 273 continue; 274#endif /* YP */ 275 if (search && name) { 276 if(strcmp(_gr_group.gr_name, name)) { 277 continue; 278 } 279 } 280#ifdef YP 281 if ((cp = strsep(&bp, ":\n")) == NULL) 282 if (_ypfound) 283 return(1); 284 else 285 break; 286 if (strlen(cp) || !_ypfound) 287 _gr_group.gr_passwd = cp; 288#else 289 if ((_gr_group.gr_passwd = strsep(&bp, ":\n")) == NULL) 290 break; 291#endif 292 if (!(cp = strsep(&bp, ":\n"))) 293#ifdef YP 294 if (_ypfound) 295 return(1); 296 else 297#endif 298 continue; 299#ifdef YP 300 /* 301 * Hurm. Should we be doing this? We allow UIDs to 302 * be overridden -- what about GIDs? 303 */ 304 if (!_ypfound) 305#endif 306 _gr_group.gr_gid = atoi(cp); 307 if (search && name == NULL && _gr_group.gr_gid != gid) 308 continue; 309 cp = NULL; 310 if (bp == NULL) /* !!! Must check for this! */ 311 break; 312#ifdef YP 313 if ((cp = strsep(&bp, ":\n")) == NULL) 314 break; 315 316 if (!strlen(cp) && _ypfound) 317 return(1); 318 else 319 members[0] = NULL; 320 bp = cp; 321 cp = NULL; 322#endif 323 for (m = _gr_group.gr_mem = members;; bp++) { 324 if (m == &members[MAXGRP - 1]) 325 break; 326 if (*bp == ',') { 327 if (cp) { 328 *bp = '\0'; 329 *m++ = cp; 330 cp = NULL; 331 } 332 } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') { 333 if (cp) { 334 *bp = '\0'; 335 *m++ = cp; 336 } 337 break; 338 } else if (cp == NULL) 339 cp = bp; 340 } 341 *m = NULL; 342 return(1); 343 } 344 /* NOTREACHED */ 345 return (0); 346} 347 348#ifdef YP 349 350static int 351_gr_breakout_yp(struct group *gr, char *result) 352{ 353 char *s, *cp; 354 char **m; 355 356 /* 357 * XXX If 's' ends up being a NULL pointer, punt on this group. 358 * It means the NIS group entry is badly formatted and should 359 * be skipped. 360 */ 361 if ((s = strsep(&result, ":")) == NULL) return 0; /* name */ 362 gr->gr_name = s; 363 364 if ((s = strsep(&result, ":")) == NULL) return 0; /* password */ 365 gr->gr_passwd = s; 366 367 if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */ 368 gr->gr_gid = atoi(s); 369 370 if ((s = result) == NULL) return 0; 371 cp = 0; 372 373 for (m = _gr_group.gr_mem = members; /**/; s++) { 374 if (m == &members[MAXGRP - 1]) { 375 break; 376 } 377 if (*s == ',') { 378 if (cp) { 379 *s = '\0'; 380 *m++ = cp; 381 cp = NULL; 382 } 383 } else if (*s == '\0' || *s == '\n' || *s == ' ') { 384 if (cp) { 385 *s = '\0'; 386 *m++ = cp; 387 } 388 break; 389 } else if (cp == NULL) { 390 cp = s; 391 } 392 } 393 *m = NULL; 394 395 return 1; 396} 397 398static char *_gr_yp_domain; 399 400static int 401_getypgroup(struct group *gr, const char *name, char *map) 402{ 403 char *result, *s; 404 static char resultbuf[1024]; 405 int resultlen; 406 407 if(!_gr_yp_domain) { 408 if(yp_get_default_domain(&_gr_yp_domain)) 409 return 0; 410 } 411 412 if(yp_match(_gr_yp_domain, map, name, strlen(name), 413 &result, &resultlen)) 414 return 0; 415 416 s = strchr(result, '\n'); 417 if(s) *s = '\0'; 418 419 if(resultlen >= sizeof resultbuf) return 0; 420 strncpy(resultbuf, result, resultlen); 421 free(result); 422 return(_gr_breakout_yp(gr, resultbuf)); 423 424} 425 426 427static int 428_nextypgroup(struct group *gr) 429{ 430 static char *key; 431 static int keylen; 432 char *lastkey, *result; 433 static char resultbuf[1024]; 434 int resultlen; 435 int rv; 436 437 if(!_gr_yp_domain) { 438 if(yp_get_default_domain(&_gr_yp_domain)) 439 return 0; 440 } 441 442 if(!_gr_stepping_yp) { 443 if(key) free(key); 444 rv = yp_first(_gr_yp_domain, "group.byname", 445 &key, &keylen, &result, &resultlen); 446 if(rv) { 447 return 0; 448 } 449 _gr_stepping_yp = 1; 450 goto unpack; 451 } else { 452tryagain: 453 lastkey = key; 454 rv = yp_next(_gr_yp_domain, "group.byname", key, keylen, 455 &key, &keylen, &result, &resultlen); 456 free(lastkey); 457unpack: 458 if(rv) { 459 _gr_stepping_yp = 0; 460 return 0; 461 } 462 463 if(resultlen > sizeof(resultbuf)) { 464 free(result); 465 goto tryagain; 466 } 467 468 strcpy(resultbuf, result); 469 free(result); 470 if((result = strchr(resultbuf, '\n')) != NULL) 471 *result = '\0'; 472 if (_gr_breakout_yp(gr, resultbuf)) 473 return(1); 474 else 475 goto tryagain; 476 } 477} 478 479#endif /* YP */ 480