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