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) 35 static 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 44 static FILE *_gr_fp; 45 static struct group _gr_group; 46 static int _gr_stayopen; 47 static int grscan(), start_gr(); 48 #ifdef YP 49 #include <rpc/rpc.h> 50 #include <rpcsvc/yp_prot.h> 51 #include <rpcsvc/ypclnt.h> 52 static int _gr_stepping_yp; 53 static int _gr_yp_enabled; 54 static int _getypgroup(struct group *, const char *, char *); 55 static int _nextypgroup(struct group *); 56 #endif 57 58 #define MAXGRP 200 59 static char *members[MAXGRP]; 60 #define MAXLINELENGTH 1024 61 static char line[MAXLINELENGTH]; 62 63 struct group * 64 getgrent() 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 } 75 tryagain: 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 94 struct group * 95 getgrnam(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 118 struct group * 119 #ifdef __STDC__ 120 getgrgid(gid_t gid) 121 #else 122 getgrgid(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 147 static int 148 start_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 182 int 183 setgrent() 184 { 185 return(setgroupent(0)); 186 } 187 188 int 189 setgroupent(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 201 void 202 endgrent() 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 213 static int 214 grscan(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 if (_ypfound) 294 return(1); 295 else 296 continue; 297 #ifdef YP 298 /* 299 * Hurm. Should we be doing this? We allow UIDs to 300 * be overridden -- what about GIDs? 301 */ 302 if (!_ypfound) 303 #endif 304 _gr_group.gr_gid = atoi(cp); 305 if (search && name == NULL && _gr_group.gr_gid != gid) 306 continue; 307 cp = NULL; 308 if (bp == NULL) /* !!! Must check for this! */ 309 break; 310 #ifdef YP 311 if ((cp = strsep(&bp, ":\n")) == NULL) 312 break; 313 314 if (!strlen(cp) && _ypfound) 315 return(1); 316 else 317 members[0] = NULL; 318 bp = cp; 319 cp = NULL; 320 #endif 321 for (m = _gr_group.gr_mem = members;; bp++) { 322 if (m == &members[MAXGRP - 1]) 323 break; 324 if (*bp == ',') { 325 if (cp) { 326 *bp = '\0'; 327 *m++ = cp; 328 cp = NULL; 329 } 330 } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') { 331 if (cp) { 332 *bp = '\0'; 333 *m++ = cp; 334 } 335 break; 336 } else if (cp == NULL) 337 cp = bp; 338 } 339 *m = NULL; 340 return(1); 341 } 342 /* NOTREACHED */ 343 return (0); 344 } 345 346 #ifdef YP 347 348 static int 349 _gr_breakout_yp(struct group *gr, char *result) 350 { 351 char *s, *cp; 352 char **m; 353 354 /* 355 * XXX If 's' ends up being a NULL pointer, punt on this group. 356 * It means the NIS group entry is badly formatted and should 357 * be skipped. 358 */ 359 if ((s = strsep(&result, ":")) == NULL) return 0; /* name */ 360 gr->gr_name = s; 361 362 if ((s = strsep(&result, ":")) == NULL) return 0; /* password */ 363 gr->gr_passwd = s; 364 365 if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */ 366 gr->gr_gid = atoi(s); 367 368 if ((s = result) == NULL) return 0; 369 cp = 0; 370 371 for (m = _gr_group.gr_mem = members; /**/; s++) { 372 if (m == &members[MAXGRP - 1]) { 373 break; 374 } 375 if (*s == ',') { 376 if (cp) { 377 *s = '\0'; 378 *m++ = cp; 379 cp = NULL; 380 } 381 } else if (*s == '\0' || *s == '\n' || *s == ' ') { 382 if (cp) { 383 *s = '\0'; 384 *m++ = cp; 385 } 386 break; 387 } else if (cp == NULL) { 388 cp = s; 389 } 390 } 391 *m = NULL; 392 393 return 1; 394 } 395 396 static char *_gr_yp_domain; 397 398 static int 399 _getypgroup(struct group *gr, const char *name, char *map) 400 { 401 char *result, *s; 402 static char resultbuf[1024]; 403 int resultlen; 404 405 if(!_gr_yp_domain) { 406 if(yp_get_default_domain(&_gr_yp_domain)) 407 return 0; 408 } 409 410 if(yp_match(_gr_yp_domain, map, name, strlen(name), 411 &result, &resultlen)) 412 return 0; 413 414 s = strchr(result, '\n'); 415 if(s) *s = '\0'; 416 417 if(resultlen >= sizeof resultbuf) return 0; 418 strncpy(resultbuf, result, resultlen); 419 free(result); 420 return(_gr_breakout_yp(gr, resultbuf)); 421 422 } 423 424 425 static int 426 _nextypgroup(struct group *gr) 427 { 428 static char *key; 429 static int keylen; 430 char *lastkey, *result; 431 static char resultbuf[1024]; 432 int resultlen; 433 int rv; 434 435 if(!_gr_yp_domain) { 436 if(yp_get_default_domain(&_gr_yp_domain)) 437 return 0; 438 } 439 440 if(!_gr_stepping_yp) { 441 if(key) free(key); 442 rv = yp_first(_gr_yp_domain, "group.byname", 443 &key, &keylen, &result, &resultlen); 444 if(rv) { 445 return 0; 446 } 447 _gr_stepping_yp = 1; 448 goto unpack; 449 } else { 450 tryagain: 451 lastkey = key; 452 rv = yp_next(_gr_yp_domain, "group.byname", key, keylen, 453 &key, &keylen, &result, &resultlen); 454 free(lastkey); 455 unpack: 456 if(rv) { 457 _gr_stepping_yp = 0; 458 return 0; 459 } 460 461 if(resultlen > sizeof(resultbuf)) { 462 free(result); 463 goto tryagain; 464 } 465 466 strcpy(resultbuf, result); 467 free(result); 468 if((result = strchr(resultbuf, '\n')) != NULL) 469 *result = '\0'; 470 if (_gr_breakout_yp(gr, resultbuf)) 471 return(1); 472 else 473 goto tryagain; 474 } 475 } 476 477 #endif /* YP */ 478