1 /* $OpenBSD: getgrent.c,v 1.37 2011/04/25 20:10:10 sthen 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 #include "ypexclude.h" 45 #endif 46 #include "thread_private.h" 47 48 /* This global storage is locked for the non-rentrant functions */ 49 _THREAD_PRIVATE_KEY(gr_storage); 50 static struct group_storage { 51 #define MAXGRP 200 52 char *members[MAXGRP]; 53 #define MAXLINELENGTH 1024 54 char line[MAXLINELENGTH]; 55 } gr_storage; 56 #define GETGR_R_SIZE_MAX _GR_BUF_LEN 57 58 /* File pointers are locked with the 'gr' mutex */ 59 _THREAD_PRIVATE_KEY(gr); 60 static FILE *_gr_fp; 61 static struct group _gr_group; 62 static int _gr_stayopen; 63 static int grscan(int, gid_t, const char *, struct group *, struct group_storage *, 64 int *); 65 static int start_gr(void); 66 static void endgrent_basic(void); 67 68 static struct group *getgrnam_gs(const char *, struct group *, 69 struct group_storage *); 70 static struct group *getgrgid_gs(gid_t, struct group *, 71 struct group_storage *); 72 73 #ifdef YP 74 static struct _ypexclude *__ypexhead = NULL; 75 static int __ypmode = 0; 76 static char *__ypcurrent, *__ypdomain; 77 static int __ypcurrentlen; 78 #endif 79 80 struct group * 81 _getgrent_yp(int *foundyp) 82 { 83 struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr, _gr_group, NULL); 84 struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage, 85 gr_storage, NULL); 86 87 _THREAD_PRIVATE_MUTEX_LOCK(gr); 88 if ((!_gr_fp && !start_gr()) || !grscan(0, 0, NULL, p_gr, gs, foundyp)) 89 p_gr = NULL; 90 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 91 return (p_gr); 92 } 93 94 struct group * 95 getgrent(void) 96 { 97 return (_getgrent_yp(NULL)); 98 } 99 100 static struct group * 101 getgrnam_gs(const char *name, struct group *p_gr, struct group_storage *gs) 102 { 103 int rval; 104 105 _THREAD_PRIVATE_MUTEX_LOCK(gr); 106 if (!start_gr()) 107 rval = 0; 108 else { 109 rval = grscan(1, 0, name, p_gr, gs, NULL); 110 if (!_gr_stayopen) 111 endgrent_basic(); 112 } 113 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 114 return(rval ? p_gr : NULL); 115 } 116 117 struct group * 118 getgrnam(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(const char *name, struct group *grp, char *buffer, 129 size_t bufsize, struct group **result) 130 { 131 int errnosave; 132 int ret; 133 134 if (bufsize < GETGR_R_SIZE_MAX) 135 return ERANGE; 136 errnosave = errno; 137 *result = getgrnam_gs(name, grp, (struct group_storage *)buffer); 138 if (*result == NULL) 139 ret = errno; 140 else 141 ret = 0; 142 errno = errnosave; 143 return ret; 144 } 145 146 static struct group * 147 getgrgid_gs(gid_t gid, struct group *p_gr, struct group_storage *gs) 148 { 149 int rval; 150 151 _THREAD_PRIVATE_MUTEX_LOCK(gr); 152 if (!start_gr()) 153 rval = 0; 154 else { 155 rval = grscan(1, gid, NULL, p_gr, gs, NULL); 156 if (!_gr_stayopen) 157 endgrent_basic(); 158 } 159 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 160 return(rval ? p_gr : NULL); 161 } 162 163 struct group * 164 getgrgid(gid_t gid) 165 { 166 struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr, _gr_group, NULL); 167 struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage, 168 gr_storage, NULL); 169 170 return getgrgid_gs(gid, p_gr, gs); 171 } 172 173 int 174 getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize, 175 struct group **result) 176 { 177 int errnosave; 178 int ret; 179 180 if (bufsize < GETGR_R_SIZE_MAX) 181 return ERANGE; 182 errnosave = errno; 183 *result = getgrgid_gs(gid, grp, (struct group_storage *)buffer); 184 if (*result == NULL) 185 ret = errno; 186 else 187 ret = 0; 188 errno = errnosave; 189 return ret; 190 } 191 192 static int 193 start_gr(void) 194 { 195 if (_gr_fp) { 196 rewind(_gr_fp); 197 #ifdef YP 198 __ypmode = 0; 199 if (__ypcurrent) 200 free(__ypcurrent); 201 __ypcurrent = NULL; 202 if (__ypexhead) 203 __ypexclude_free(&__ypexhead); 204 __ypexhead = NULL; 205 #endif 206 return(1); 207 } 208 return((_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0); 209 } 210 211 void 212 setgrent(void) 213 { 214 (void) setgroupent(0); 215 } 216 217 int 218 setgroupent(int stayopen) 219 { 220 int retval; 221 222 _THREAD_PRIVATE_MUTEX_LOCK(gr); 223 if (!start_gr()) 224 retval = 0; 225 else { 226 _gr_stayopen = stayopen; 227 retval = 1; 228 } 229 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 230 return (retval); 231 } 232 233 static 234 void 235 endgrent_basic(void) 236 { 237 if (_gr_fp) { 238 (void)fclose(_gr_fp); 239 _gr_fp = NULL; 240 #ifdef YP 241 __ypmode = 0; 242 if (__ypcurrent) 243 free(__ypcurrent); 244 __ypcurrent = NULL; 245 if (__ypexhead) 246 __ypexclude_free(&__ypexhead); 247 __ypexhead = NULL; 248 #endif 249 } 250 } 251 252 void 253 endgrent(void) 254 { 255 _THREAD_PRIVATE_MUTEX_LOCK(gr); 256 endgrent_basic(); 257 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 258 } 259 260 static int 261 grscan(int search, gid_t gid, const char *name, struct group *p_gr, 262 struct group_storage *gs, int *foundyp) 263 { 264 char *cp, **m; 265 char *bp, *endp; 266 u_long ul; 267 #ifdef YP 268 char *key, *data; 269 int keylen, datalen; 270 int r; 271 #endif 272 char **members; 273 char *line; 274 int saved_errno; 275 276 if (gs == NULL) 277 return 0; 278 members = gs->members; 279 line = gs->line; 280 saved_errno = errno; 281 282 for (;;) { 283 #ifdef YP 284 if (__ypmode) { 285 if (__ypcurrent) { 286 r = yp_next(__ypdomain, "group.byname", 287 __ypcurrent, __ypcurrentlen, 288 &key, &keylen, &data, &datalen); 289 free(__ypcurrent); 290 __ypcurrent = key; 291 __ypcurrentlen = keylen; 292 } else { 293 r = yp_first(__ypdomain, "group.byname", 294 &__ypcurrent, &__ypcurrentlen, 295 &data, &datalen); 296 } 297 if (r) { 298 __ypmode = 0; 299 __ypcurrent = NULL; 300 if (r == YPERR_NOMORE) 301 continue; 302 else 303 return 0; 304 } 305 bcopy(data, line, datalen); 306 free(data); 307 line[datalen] = '\0'; 308 bp = line; 309 goto parse; 310 } 311 #endif 312 if (!fgets(line, sizeof(gs->line), _gr_fp)) { 313 if (feof(_gr_fp) && !ferror(_gr_fp)) 314 errno = saved_errno; 315 return 0; 316 } 317 bp = line; 318 /* skip lines that are too big */ 319 if (!strchr(line, '\n')) { 320 int ch; 321 322 while ((ch = getc_unlocked(_gr_fp)) != '\n' && 323 ch != EOF) 324 ; 325 continue; 326 } 327 #ifdef YP 328 if (line[0] == '+' || line[0] == '-') { 329 if (__ypdomain == NULL && 330 yp_get_default_domain(&__ypdomain)) 331 goto parse; 332 switch (yp_bind(__ypdomain)) { 333 case 0: 334 break; 335 case YPERR_BADARGS: 336 case YPERR_YPBIND: 337 goto parse; 338 default: 339 return 0; 340 } 341 } 342 if (line[0] == '+') { 343 switch (line[1]) { 344 case ':': 345 case '\0': 346 case '\n': 347 if (foundyp) { 348 *foundyp = 1; 349 errno = saved_errno; 350 return 0; 351 } 352 if (!search) { 353 __ypmode = 1; 354 continue; 355 } 356 if (name) { 357 r = yp_match(__ypdomain, 358 "group.byname", name, strlen(name), 359 &data, &datalen); 360 } else { 361 char buf[20]; 362 snprintf(buf, sizeof buf, "%u", gid); 363 r = yp_match(__ypdomain, "group.bygid", 364 buf, strlen(buf), &data, &datalen); 365 } 366 switch (r) { 367 case 0: 368 break; 369 case YPERR_KEY: 370 continue; 371 default: 372 return 0; 373 } 374 bcopy(data, line, datalen); 375 free(data); 376 line[datalen] = '\0'; 377 bp = line; 378 p_gr->gr_name = strsep(&bp, ":\n"); 379 if (__ypexclude_is(&__ypexhead, p_gr->gr_name)) 380 continue; 381 p_gr->gr_passwd = strsep(&bp, ":\n"); 382 if (!(cp = strsep(&bp, ":\n"))) 383 continue; 384 if (name) { 385 ul = strtoul(cp, &endp, 10); 386 if (*endp != '\0' || endp == cp || 387 ul >= GID_MAX) 388 continue; 389 p_gr->gr_gid = ul; 390 } else 391 p_gr->gr_gid = gid; 392 goto found_it; 393 default: 394 bp = strsep(&bp, ":\n") + 1; 395 if (search && name && strcmp(bp, name) || 396 __ypexclude_is(&__ypexhead, bp)) 397 continue; 398 r = yp_match(__ypdomain, "group.byname", 399 bp, strlen(bp), &data, &datalen); 400 switch (r) { 401 case 0: 402 break; 403 case YPERR_KEY: 404 continue; 405 default: 406 return 0; 407 } 408 bcopy(data, line, datalen); 409 free(data); 410 line[datalen] = '\0'; 411 bp = line; 412 } 413 } else if (line[0] == '-') { 414 if (__ypexclude_add(&__ypexhead, 415 strsep(&line, ":\n") + 1)) 416 return 0; 417 if (foundyp) { 418 *foundyp = -1; 419 errno = saved_errno; 420 return 0; 421 } 422 continue; 423 } 424 parse: 425 #endif 426 p_gr->gr_name = strsep(&bp, ":\n"); 427 if (search && name && strcmp(p_gr->gr_name, name)) 428 continue; 429 #ifdef YP 430 if (__ypmode && __ypexclude_is(&__ypexhead, p_gr->gr_name)) 431 continue; 432 #endif 433 p_gr->gr_passwd = strsep(&bp, ":\n"); 434 if (!(cp = strsep(&bp, ":\n"))) 435 continue; 436 ul = strtoul(cp, &endp, 10); 437 if (endp == cp || *endp != '\0' || ul >= GID_MAX) 438 continue; 439 p_gr->gr_gid = ul; 440 if (search && name == NULL && p_gr->gr_gid != gid) 441 continue; 442 #ifdef YP 443 found_it: 444 #endif 445 cp = NULL; 446 if (bp == NULL) 447 continue; 448 for (m = p_gr->gr_mem = members;; bp++) { 449 if (m == &members[MAXGRP - 1]) 450 break; 451 if (*bp == ',') { 452 if (cp) { 453 *bp = '\0'; 454 *m++ = cp; 455 cp = NULL; 456 } 457 } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') { 458 if (cp) { 459 *bp = '\0'; 460 *m++ = cp; 461 } 462 break; 463 } else if (cp == NULL) 464 cp = bp; 465 } 466 *m = NULL; 467 errno = saved_errno; 468 return 1; 469 } 470 /* NOTREACHED */ 471 } 472