1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Portions Copyright (c) 1994, Jason Downs. All Rights Reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by the University of 17 * California, Berkeley and its contributors. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #if defined(LIBC_SCCS) && !defined(lint) 36 static char rcsid[] = "$OpenBSD: getgrent.c,v 1.14 2001/09/11 04:52:50 pvalchev Exp $"; 37 #endif /* LIBC_SCCS and not lint */ 38 39 #include <sys/types.h> 40 #include <sys/param.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <grp.h> 45 #include <errno.h> 46 #ifdef YP 47 #include <rpc/rpc.h> 48 #include <rpcsvc/yp.h> 49 #include <rpcsvc/ypclnt.h> 50 #include "ypinternal.h" 51 #endif 52 #include "thread_private.h" 53 54 /* This global storage is locked for the non-rentrant functions */ 55 _THREAD_PRIVATE_KEY(gr_storage); 56 static struct group_storage { 57 #define MAXGRP 200 58 char *members[MAXGRP]; 59 #define MAXLINELENGTH 1024 60 char line[MAXLINELENGTH]; 61 } gr_storage; 62 #define GETGR_R_SIZE_MAX (1024+200*sizeof(char*)) 63 64 /* File pointers are locked with the 'gr' mutex */ 65 _THREAD_PRIVATE_KEY(gr); 66 _THREAD_PRIVATE_MUTEX(gr); 67 static FILE *_gr_fp; 68 static struct group _gr_group; 69 static int _gr_stayopen; 70 static int grscan __P((int, gid_t, const char *, struct group *, struct group_storage *)); 71 static int start_gr __P((void)); 72 static void endgrent_basic __P((void)); 73 74 static struct group *getgrnam_gs(const char *, struct group *, 75 struct group_storage *); 76 static struct group *getgrgid_gs(gid_t, struct group *, 77 struct group_storage *); 78 79 #ifdef YP 80 enum _ypmode { YPMODE_NONE, YPMODE_FULL, YPMODE_NAME }; 81 static enum _ypmode __ypmode; 82 static char *__ypcurrent, *__ypdomain; 83 static int __ypcurrentlen; 84 #endif 85 86 struct group * 87 getgrent() 88 { 89 struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr,_gr_group,NULL); 90 struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage,gr_storage,NULL); 91 92 _THREAD_PRIVATE_MUTEX_LOCK(gr); 93 if ((!_gr_fp && !start_gr()) || !grscan(0, 0, NULL, p_gr, gs)) 94 p_gr = NULL; 95 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 96 return (p_gr); 97 } 98 99 static struct group * 100 getgrnam_gs(name, p_gr, gs) 101 const char *name; 102 struct group *p_gr; 103 struct group_storage *gs; 104 { 105 int rval; 106 107 _THREAD_PRIVATE_MUTEX_LOCK(gr); 108 if (!start_gr()) 109 rval = 0; 110 else { 111 rval = grscan(1, 0, name, p_gr, gs); 112 if (!_gr_stayopen) 113 endgrent_basic(); 114 } 115 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 116 return(rval ? p_gr : NULL); 117 } 118 119 struct group * 120 getgrnam(name) 121 const char *name; 122 { 123 struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr,_gr_group,NULL); 124 struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage,gr_storage,NULL); 125 126 return getgrnam_gs(name, p_gr, gs); 127 } 128 129 int 130 getgrnam_r(name, grp, buffer, bufsize, result) 131 const char *name; 132 struct group *grp; 133 char *buffer; 134 size_t bufsize; 135 struct group **result; 136 { 137 int errnosave; 138 int ret; 139 140 if (bufsize < GETGR_R_SIZE_MAX) 141 return ERANGE; 142 errnosave = errno; 143 *result = getgrnam_gs(name, grp, (struct group_storage *)buffer); 144 if (*result == NULL) 145 ret = errno; 146 else 147 ret = 0; 148 errno = errnosave; 149 return ret; 150 } 151 152 static struct group * 153 getgrgid_gs(gid, p_gr, gs) 154 gid_t gid; 155 struct group *p_gr; 156 struct group_storage *gs; 157 { 158 int rval; 159 160 _THREAD_PRIVATE_MUTEX_LOCK(gr); 161 if (!start_gr()) 162 rval = 0; 163 else { 164 rval = grscan(1, gid, NULL, p_gr, gs); 165 if (!_gr_stayopen) 166 endgrent_basic(); 167 } 168 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 169 return(rval ? p_gr : NULL); 170 } 171 172 struct group * 173 getgrgid(gid) 174 gid_t gid; 175 { 176 struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr,_gr_group,NULL); 177 struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage,gr_storage,NULL); 178 179 return getgrgid_gs(gid, p_gr, gs); 180 } 181 182 int 183 getgrgid_r(gid, grp, buffer, bufsize, result) 184 gid_t gid; 185 struct group *grp; 186 char *buffer; 187 size_t bufsize; 188 struct group **result; 189 { 190 int errnosave; 191 int ret; 192 193 if (bufsize < GETGR_R_SIZE_MAX) 194 return ERANGE; 195 errnosave = errno; 196 *result = getgrgid_gs(gid, grp, (struct group_storage *)buffer); 197 if (*result == NULL) 198 ret = errno; 199 else 200 ret = 0; 201 errno = errnosave; 202 return ret; 203 } 204 205 static int 206 start_gr() 207 { 208 if (_gr_fp) { 209 rewind(_gr_fp); 210 #ifdef YP 211 __ypmode = YPMODE_NONE; 212 if(__ypcurrent) 213 free(__ypcurrent); 214 __ypcurrent = NULL; 215 #endif 216 return(1); 217 } 218 return((_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0); 219 } 220 221 void 222 setgrent() 223 { 224 (void) setgroupent(0); 225 } 226 227 int 228 setgroupent(stayopen) 229 int stayopen; 230 { 231 int retval; 232 233 _THREAD_PRIVATE_MUTEX_LOCK(gr); 234 if (!start_gr()) 235 retval = 0; 236 else { 237 _gr_stayopen = stayopen; 238 retval = 1; 239 } 240 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 241 return (retval); 242 } 243 244 static 245 void 246 endgrent_basic() 247 { 248 if (_gr_fp) { 249 (void)fclose(_gr_fp); 250 _gr_fp = NULL; 251 #ifdef YP 252 __ypmode = YPMODE_NONE; 253 if(__ypcurrent) 254 free(__ypcurrent); 255 __ypcurrent = NULL; 256 #endif 257 } 258 } 259 260 void 261 endgrent() 262 { 263 _THREAD_PRIVATE_MUTEX_LOCK(gr); 264 endgrent_basic(); 265 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 266 } 267 268 static int 269 grscan(search, gid, name, p_gr, gs) 270 register int search; 271 register gid_t gid; 272 register const char *name; 273 struct group *p_gr; 274 struct group_storage *gs; 275 { 276 register char *cp, **m; 277 char *bp, *endp; 278 u_long ul; 279 #ifdef YP 280 char *key, *data; 281 int keylen, datalen; 282 int r; 283 char *grname = (char *)NULL; 284 #endif 285 char **members; 286 char *line; 287 288 if (gs == NULL) 289 return 0; 290 members = gs->members; 291 line = gs->line; 292 293 for (;;) { 294 #ifdef YP 295 if(__ypmode != YPMODE_NONE) { 296 297 if(!__ypdomain) { 298 if(yp_get_default_domain(&__ypdomain)) { 299 __ypmode = YPMODE_NONE; 300 if(grname != (char *)NULL) { 301 free(grname); 302 grname = (char *)NULL; 303 } 304 continue; 305 } 306 } 307 switch(__ypmode) { 308 case YPMODE_FULL: 309 if(__ypcurrent) { 310 r = yp_next(__ypdomain, "group.byname", 311 __ypcurrent, __ypcurrentlen, 312 &key, &keylen, &data, &datalen); 313 free(__ypcurrent); 314 if(r != 0) { 315 __ypcurrent = NULL; 316 __ypmode = YPMODE_NONE; 317 free(data); 318 continue; 319 } 320 __ypcurrent = key; 321 __ypcurrentlen = keylen; 322 bcopy(data, line, datalen); 323 free(data); 324 } else { 325 r = yp_first(__ypdomain, "group.byname", 326 &__ypcurrent, &__ypcurrentlen, 327 &data, &datalen); 328 if(r != 0) { 329 __ypmode = YPMODE_NONE; 330 free(data); 331 continue; 332 } 333 bcopy(data, line, datalen); 334 free(data); 335 } 336 break; 337 case YPMODE_NAME: 338 if(grname != (char *)NULL) { 339 r = yp_match(__ypdomain, "group.byname", 340 grname, strlen(grname), 341 &data, &datalen); 342 __ypmode = YPMODE_NONE; 343 free(grname); 344 grname = (char *)NULL; 345 if(r != 0) { 346 free(data); 347 continue; 348 } 349 bcopy(data, line, datalen); 350 free(data); 351 } else { 352 __ypmode = YPMODE_NONE; /* ??? */ 353 continue; 354 } 355 break; 356 } 357 line[datalen] = '\0'; 358 bp = line; 359 goto parse; 360 } 361 #endif 362 if (!fgets(line, sizeof(gs->line), _gr_fp)) 363 return(0); 364 bp = line; 365 /* skip lines that are too big */ 366 if (!strchr(line, '\n')) { 367 int ch; 368 369 while ((ch = getc(_gr_fp)) != '\n' && ch != EOF) 370 ; 371 continue; 372 } 373 #ifdef YP 374 if (line[0] == '+') { 375 switch(line[1]) { 376 case ':': 377 case '\0': 378 case '\n': 379 if(_yp_check(NULL)) { 380 if (!search) { 381 __ypmode = YPMODE_FULL; 382 continue; 383 } 384 if(!__ypdomain && 385 yp_get_default_domain(&__ypdomain)) 386 continue; 387 if (name) { 388 r = yp_match(__ypdomain, 389 "group.byname", 390 name, strlen(name), 391 &data, &datalen); 392 } else { 393 char buf[20]; 394 sprintf(buf, "%u", gid); 395 r = yp_match(__ypdomain, 396 "group.bygid", 397 buf, strlen(buf), 398 &data, &datalen); 399 } 400 if (r != 0) 401 continue; 402 bcopy(data, line, datalen); 403 free(data); 404 line[datalen] = '\0'; 405 bp = line; 406 p_gr->gr_name = strsep(&bp, ":\n"); 407 p_gr->gr_passwd = 408 strsep(&bp, ":\n"); 409 if (!(cp = strsep(&bp, ":\n"))) 410 continue; 411 if (name) { 412 ul = strtoul(cp, &endp, 10); 413 if (*endp != '\0' || 414 endp == cp || ul >= GID_MAX) 415 continue; 416 p_gr->gr_gid = ul; 417 } else 418 p_gr->gr_gid = gid; 419 goto found_it; 420 } 421 break; 422 default: 423 if(_yp_check(NULL)) { 424 register char *tptr; 425 426 tptr = strsep(&bp, ":\n"); 427 if (search && name && strcmp(tptr, name)) 428 continue; 429 __ypmode = YPMODE_NAME; 430 grname = strdup(tptr + 1); 431 continue; 432 } 433 break; 434 } 435 } 436 parse: 437 #endif 438 p_gr->gr_name = strsep(&bp, ":\n"); 439 if (search && name && strcmp(p_gr->gr_name, name)) 440 continue; 441 p_gr->gr_passwd = strsep(&bp, ":\n"); 442 if (!(cp = strsep(&bp, ":\n"))) 443 continue; 444 ul = strtoul(cp, &endp, 10); 445 if (endp == cp || *endp != '\0' || ul >= GID_MAX) 446 continue; 447 p_gr->gr_gid = ul; 448 if (search && name == NULL && p_gr->gr_gid != gid) 449 continue; 450 found_it: 451 cp = NULL; 452 if (bp == NULL) 453 continue; 454 for (m = p_gr->gr_mem = members;; bp++) { 455 if (m == &members[MAXGRP - 1]) 456 break; 457 if (*bp == ',') { 458 if (cp) { 459 *bp = '\0'; 460 *m++ = cp; 461 cp = NULL; 462 } 463 } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') { 464 if (cp) { 465 *bp = '\0'; 466 *m++ = cp; 467 } 468 break; 469 } else if (cp == NULL) 470 cp = bp; 471 } 472 *m = NULL; 473 return(1); 474 } 475 /* NOTREACHED */ 476 } 477