1 /* $OpenBSD: getgrent.c,v 1.47 2018/09/13 12:31:15 millert 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); 51 static 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); 61 static FILE *_gr_fp; 62 static struct group _gr_group; 63 static int _gr_stayopen; 64 static int grscan(int, gid_t, const char *, struct group *, struct group_storage *, 65 int *); 66 static int start_gr(void); 67 static void endgrent_basic(void); 68 69 static struct group *getgrnam_gs(const char *, struct group *, 70 struct group_storage *); 71 static struct group *getgrgid_gs(gid_t, struct group *, 72 struct group_storage *); 73 74 #ifdef YP 75 static struct _ypexclude *__ypexhead = NULL; 76 static int __ypmode = 0; 77 static char *__ypcurrent, *__ypdomain; 78 static int __ypcurrentlen; 79 #endif 80 81 struct 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 95 struct group * 96 getgrent(void) 97 { 98 return (_getgrent_yp(NULL)); 99 } 100 101 static struct group * 102 getgrnam_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 118 struct group * 119 getgrnam(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 128 int 129 getgrnam_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 } 147 DEF_WEAK(getgrnam_r); 148 149 static struct group * 150 getgrgid_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 166 struct group * 167 getgrgid(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 176 int 177 getgrgid_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 } 195 DEF_WEAK(getgrgid_r); 196 197 static int 198 start_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 #ifdef YP 214 /* 215 * Hint to the kernel that a passwd database operation is happening. 216 */ 217 (void)access("/var/run/ypbind.lock", R_OK); 218 #endif 219 220 return((_gr_fp = fopen(_PATH_GROUP, "re")) ? 1 : 0); 221 } 222 223 void 224 setgrent(void) 225 { 226 int saved_errno; 227 228 saved_errno = errno; 229 setgroupent(0); 230 errno = saved_errno; 231 } 232 DEF_WEAK(setgrent); 233 234 int 235 setgroupent(int stayopen) 236 { 237 int retval; 238 239 _THREAD_PRIVATE_MUTEX_LOCK(gr); 240 if (!start_gr()) 241 retval = 0; 242 else { 243 _gr_stayopen = stayopen; 244 retval = 1; 245 } 246 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 247 return (retval); 248 } 249 DEF_WEAK(setgroupent); 250 251 static 252 void 253 endgrent_basic(void) 254 { 255 int saved_errno; 256 257 if (_gr_fp) { 258 saved_errno = errno; 259 fclose(_gr_fp); 260 _gr_fp = NULL; 261 #ifdef YP 262 __ypmode = 0; 263 free(__ypcurrent); 264 __ypcurrent = NULL; 265 if (__ypexhead) 266 __ypexclude_free(&__ypexhead); 267 __ypexhead = NULL; 268 #endif 269 errno = saved_errno; 270 } 271 } 272 273 void 274 endgrent(void) 275 { 276 _THREAD_PRIVATE_MUTEX_LOCK(gr); 277 endgrent_basic(); 278 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 279 } 280 DEF_WEAK(endgrent); 281 282 static int 283 grscan(int search, gid_t gid, const char *name, struct group *p_gr, 284 struct group_storage *gs, int *foundyp) 285 { 286 char *cp, **m; 287 char *bp, *endp; 288 u_long ul; 289 #ifdef YP 290 char *key, *data; 291 int keylen, datalen; 292 int r; 293 #endif 294 char **members; 295 char *line; 296 int saved_errno; 297 298 if (gs == NULL) 299 return 0; 300 members = gs->members; 301 line = gs->line; 302 saved_errno = errno; 303 304 for (;;) { 305 #ifdef YP 306 if (__ypmode) { 307 if (__ypcurrent) { 308 r = yp_next(__ypdomain, "group.byname", 309 __ypcurrent, __ypcurrentlen, 310 &key, &keylen, &data, &datalen); 311 free(__ypcurrent); 312 __ypcurrent = key; 313 __ypcurrentlen = keylen; 314 } else { 315 r = yp_first(__ypdomain, "group.byname", 316 &__ypcurrent, &__ypcurrentlen, 317 &data, &datalen); 318 } 319 if (r) { 320 __ypmode = 0; 321 __ypcurrent = NULL; 322 if (r == YPERR_NOMORE) 323 continue; 324 else 325 return 0; 326 } 327 bcopy(data, line, datalen); 328 free(data); 329 line[datalen] = '\0'; 330 bp = line; 331 goto parse; 332 } 333 #endif 334 if (!fgets(line, sizeof(gs->line), _gr_fp)) { 335 if (feof(_gr_fp) && !ferror(_gr_fp)) 336 errno = saved_errno; 337 return 0; 338 } 339 bp = line; 340 /* skip lines that are too big */ 341 if (!strchr(line, '\n')) { 342 int ch; 343 344 while ((ch = getc_unlocked(_gr_fp)) != '\n' && 345 ch != EOF) 346 ; 347 continue; 348 } 349 #ifdef YP 350 if (line[0] == '+' || line[0] == '-') { 351 if (__ypdomain == NULL && 352 yp_get_default_domain(&__ypdomain)) 353 goto parse; 354 switch (yp_bind(__ypdomain)) { 355 case 0: 356 break; 357 case YPERR_BADARGS: 358 case YPERR_YPBIND: 359 goto parse; 360 default: 361 return 0; 362 } 363 } 364 if (line[0] == '+') { 365 switch (line[1]) { 366 case ':': 367 case '\0': 368 case '\n': 369 if (foundyp) { 370 *foundyp = 1; 371 errno = saved_errno; 372 return 0; 373 } 374 if (!search) { 375 __ypmode = 1; 376 continue; 377 } 378 if (name) { 379 r = yp_match(__ypdomain, 380 "group.byname", name, strlen(name), 381 &data, &datalen); 382 } else { 383 char buf[20]; 384 snprintf(buf, sizeof buf, "%u", gid); 385 r = yp_match(__ypdomain, "group.bygid", 386 buf, strlen(buf), &data, &datalen); 387 } 388 switch (r) { 389 case 0: 390 break; 391 case YPERR_KEY: 392 continue; 393 default: 394 return 0; 395 } 396 bcopy(data, line, datalen); 397 free(data); 398 line[datalen] = '\0'; 399 bp = line; 400 p_gr->gr_name = strsep(&bp, ":\n"); 401 if (__ypexclude_is(&__ypexhead, p_gr->gr_name)) 402 continue; 403 p_gr->gr_passwd = strsep(&bp, ":\n"); 404 if (!(cp = strsep(&bp, ":\n"))) 405 continue; 406 if (name) { 407 ul = strtoul(cp, &endp, 10); 408 if (*endp != '\0' || endp == cp || 409 ul >= GID_MAX) 410 continue; 411 p_gr->gr_gid = ul; 412 } else 413 p_gr->gr_gid = gid; 414 goto found_it; 415 default: 416 bp = strsep(&bp, ":\n") + 1; 417 if ((search && name && strcmp(bp, name)) || 418 __ypexclude_is(&__ypexhead, bp)) 419 continue; 420 r = yp_match(__ypdomain, "group.byname", 421 bp, strlen(bp), &data, &datalen); 422 switch (r) { 423 case 0: 424 break; 425 case YPERR_KEY: 426 continue; 427 default: 428 return 0; 429 } 430 bcopy(data, line, datalen); 431 free(data); 432 line[datalen] = '\0'; 433 bp = line; 434 } 435 } else if (line[0] == '-') { 436 if (__ypexclude_add(&__ypexhead, 437 strsep(&line, ":\n") + 1)) 438 return 0; 439 if (foundyp) { 440 *foundyp = -1; 441 errno = saved_errno; 442 return 0; 443 } 444 continue; 445 } 446 parse: 447 #endif 448 p_gr->gr_name = strsep(&bp, ":\n"); 449 if (search && name && strcmp(p_gr->gr_name, name)) 450 continue; 451 #ifdef YP 452 if (__ypmode && __ypexclude_is(&__ypexhead, p_gr->gr_name)) 453 continue; 454 #endif 455 p_gr->gr_passwd = strsep(&bp, ":\n"); 456 if (!(cp = strsep(&bp, ":\n"))) 457 continue; 458 ul = strtoul(cp, &endp, 10); 459 if (endp == cp || *endp != '\0' || ul >= GID_MAX) 460 continue; 461 p_gr->gr_gid = ul; 462 if (search && name == NULL && p_gr->gr_gid != gid) 463 continue; 464 #ifdef YP 465 found_it: 466 #endif 467 cp = NULL; 468 if (bp == NULL) 469 continue; 470 for (m = p_gr->gr_mem = members;; bp++) { 471 if (m == &members[MAXGRP - 1]) 472 break; 473 if (*bp == ',') { 474 if (cp) { 475 *bp = '\0'; 476 *m++ = cp; 477 cp = NULL; 478 } 479 } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') { 480 if (cp) { 481 *bp = '\0'; 482 *m++ = cp; 483 } 484 break; 485 } else if (cp == NULL) 486 cp = bp; 487 } 488 *m = NULL; 489 errno = saved_errno; 490 return 1; 491 } 492 /* NOTREACHED */ 493 } 494