1 /* $OpenBSD: getgrent.c,v 1.42 2015/01/16 16:48:51 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 <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <limits.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 errno = 0; 138 *result = getgrnam_gs(name, grp, (struct group_storage *)buffer); 139 if (*result == NULL) 140 ret = errno; 141 else 142 ret = 0; 143 errno = errnosave; 144 return ret; 145 } 146 147 static struct group * 148 getgrgid_gs(gid_t gid, struct group *p_gr, struct group_storage *gs) 149 { 150 int rval; 151 152 _THREAD_PRIVATE_MUTEX_LOCK(gr); 153 if (!start_gr()) 154 rval = 0; 155 else { 156 rval = grscan(1, gid, NULL, p_gr, gs, NULL); 157 if (!_gr_stayopen) 158 endgrent_basic(); 159 } 160 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 161 return(rval ? p_gr : NULL); 162 } 163 164 struct group * 165 getgrgid(gid_t gid) 166 { 167 struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr, _gr_group, NULL); 168 struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage, 169 gr_storage, NULL); 170 171 return getgrgid_gs(gid, p_gr, gs); 172 } 173 174 int 175 getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize, 176 struct group **result) 177 { 178 int errnosave; 179 int ret; 180 181 if (bufsize < GETGR_R_SIZE_MAX) 182 return ERANGE; 183 errnosave = errno; 184 errno = 0; 185 *result = getgrgid_gs(gid, grp, (struct group_storage *)buffer); 186 if (*result == NULL) 187 ret = errno; 188 else 189 ret = 0; 190 errno = errnosave; 191 return ret; 192 } 193 194 static int 195 start_gr(void) 196 { 197 if (_gr_fp) { 198 rewind(_gr_fp); 199 #ifdef YP 200 __ypmode = 0; 201 if (__ypcurrent) 202 free(__ypcurrent); 203 __ypcurrent = NULL; 204 if (__ypexhead) 205 __ypexclude_free(&__ypexhead); 206 __ypexhead = NULL; 207 #endif 208 return(1); 209 } 210 return((_gr_fp = fopen(_PATH_GROUP, "re")) ? 1 : 0); 211 } 212 213 void 214 setgrent(void) 215 { 216 int saved_errno; 217 218 saved_errno = errno; 219 setgroupent(0); 220 errno = saved_errno; 221 } 222 223 int 224 setgroupent(int stayopen) 225 { 226 int retval; 227 228 _THREAD_PRIVATE_MUTEX_LOCK(gr); 229 if (!start_gr()) 230 retval = 0; 231 else { 232 _gr_stayopen = stayopen; 233 retval = 1; 234 } 235 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 236 return (retval); 237 } 238 239 static 240 void 241 endgrent_basic(void) 242 { 243 int saved_errno; 244 245 if (_gr_fp) { 246 saved_errno = errno; 247 fclose(_gr_fp); 248 _gr_fp = NULL; 249 #ifdef YP 250 __ypmode = 0; 251 if (__ypcurrent) 252 free(__ypcurrent); 253 __ypcurrent = NULL; 254 if (__ypexhead) 255 __ypexclude_free(&__ypexhead); 256 __ypexhead = NULL; 257 #endif 258 errno = saved_errno; 259 } 260 } 261 262 void 263 endgrent(void) 264 { 265 _THREAD_PRIVATE_MUTEX_LOCK(gr); 266 endgrent_basic(); 267 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 268 } 269 270 static int 271 grscan(int search, gid_t gid, const char *name, struct group *p_gr, 272 struct group_storage *gs, int *foundyp) 273 { 274 char *cp, **m; 275 char *bp, *endp; 276 u_long ul; 277 #ifdef YP 278 char *key, *data; 279 int keylen, datalen; 280 int r; 281 #endif 282 char **members; 283 char *line; 284 int saved_errno; 285 286 if (gs == NULL) 287 return 0; 288 members = gs->members; 289 line = gs->line; 290 saved_errno = errno; 291 292 for (;;) { 293 #ifdef YP 294 if (__ypmode) { 295 if (__ypcurrent) { 296 r = yp_next(__ypdomain, "group.byname", 297 __ypcurrent, __ypcurrentlen, 298 &key, &keylen, &data, &datalen); 299 free(__ypcurrent); 300 __ypcurrent = key; 301 __ypcurrentlen = keylen; 302 } else { 303 r = yp_first(__ypdomain, "group.byname", 304 &__ypcurrent, &__ypcurrentlen, 305 &data, &datalen); 306 } 307 if (r) { 308 __ypmode = 0; 309 __ypcurrent = NULL; 310 if (r == YPERR_NOMORE) 311 continue; 312 else 313 return 0; 314 } 315 bcopy(data, line, datalen); 316 free(data); 317 line[datalen] = '\0'; 318 bp = line; 319 goto parse; 320 } 321 #endif 322 if (!fgets(line, sizeof(gs->line), _gr_fp)) { 323 if (feof(_gr_fp) && !ferror(_gr_fp)) 324 errno = saved_errno; 325 return 0; 326 } 327 bp = line; 328 /* skip lines that are too big */ 329 if (!strchr(line, '\n')) { 330 int ch; 331 332 while ((ch = getc_unlocked(_gr_fp)) != '\n' && 333 ch != EOF) 334 ; 335 continue; 336 } 337 #ifdef YP 338 if (line[0] == '+' || line[0] == '-') { 339 if (__ypdomain == NULL && 340 yp_get_default_domain(&__ypdomain)) 341 goto parse; 342 switch (yp_bind(__ypdomain)) { 343 case 0: 344 break; 345 case YPERR_BADARGS: 346 case YPERR_YPBIND: 347 goto parse; 348 default: 349 return 0; 350 } 351 } 352 if (line[0] == '+') { 353 switch (line[1]) { 354 case ':': 355 case '\0': 356 case '\n': 357 if (foundyp) { 358 *foundyp = 1; 359 errno = saved_errno; 360 return 0; 361 } 362 if (!search) { 363 __ypmode = 1; 364 continue; 365 } 366 if (name) { 367 r = yp_match(__ypdomain, 368 "group.byname", name, strlen(name), 369 &data, &datalen); 370 } else { 371 char buf[20]; 372 snprintf(buf, sizeof buf, "%u", gid); 373 r = yp_match(__ypdomain, "group.bygid", 374 buf, strlen(buf), &data, &datalen); 375 } 376 switch (r) { 377 case 0: 378 break; 379 case YPERR_KEY: 380 continue; 381 default: 382 return 0; 383 } 384 bcopy(data, line, datalen); 385 free(data); 386 line[datalen] = '\0'; 387 bp = line; 388 p_gr->gr_name = strsep(&bp, ":\n"); 389 if (__ypexclude_is(&__ypexhead, p_gr->gr_name)) 390 continue; 391 p_gr->gr_passwd = strsep(&bp, ":\n"); 392 if (!(cp = strsep(&bp, ":\n"))) 393 continue; 394 if (name) { 395 ul = strtoul(cp, &endp, 10); 396 if (*endp != '\0' || endp == cp || 397 ul >= GID_MAX) 398 continue; 399 p_gr->gr_gid = ul; 400 } else 401 p_gr->gr_gid = gid; 402 goto found_it; 403 default: 404 bp = strsep(&bp, ":\n") + 1; 405 if ((search && name && strcmp(bp, name)) || 406 __ypexclude_is(&__ypexhead, bp)) 407 continue; 408 r = yp_match(__ypdomain, "group.byname", 409 bp, strlen(bp), &data, &datalen); 410 switch (r) { 411 case 0: 412 break; 413 case YPERR_KEY: 414 continue; 415 default: 416 return 0; 417 } 418 bcopy(data, line, datalen); 419 free(data); 420 line[datalen] = '\0'; 421 bp = line; 422 } 423 } else if (line[0] == '-') { 424 if (__ypexclude_add(&__ypexhead, 425 strsep(&line, ":\n") + 1)) 426 return 0; 427 if (foundyp) { 428 *foundyp = -1; 429 errno = saved_errno; 430 return 0; 431 } 432 continue; 433 } 434 parse: 435 #endif 436 p_gr->gr_name = strsep(&bp, ":\n"); 437 if (search && name && strcmp(p_gr->gr_name, name)) 438 continue; 439 #ifdef YP 440 if (__ypmode && __ypexclude_is(&__ypexhead, p_gr->gr_name)) 441 continue; 442 #endif 443 p_gr->gr_passwd = strsep(&bp, ":\n"); 444 if (!(cp = strsep(&bp, ":\n"))) 445 continue; 446 ul = strtoul(cp, &endp, 10); 447 if (endp == cp || *endp != '\0' || ul >= GID_MAX) 448 continue; 449 p_gr->gr_gid = ul; 450 if (search && name == NULL && p_gr->gr_gid != gid) 451 continue; 452 #ifdef YP 453 found_it: 454 #endif 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 errno = saved_errno; 478 return 1; 479 } 480 /* NOTREACHED */ 481 } 482