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