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