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