1 /* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Portions Copyright (c) 1994, Jason Downs. All Rights Reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by the University of 17 * California, Berkeley and its contributors. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #if defined(LIBC_SCCS) && !defined(lint) 36 static char rcsid[] = "$OpenBSD: getgrent.c,v 1.13 2000/09/24 14:35:10 d Exp $"; 37 #endif /* LIBC_SCCS and not lint */ 38 39 #include <sys/types.h> 40 #include <sys/param.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <grp.h> 45 #ifdef YP 46 #include <rpc/rpc.h> 47 #include <rpcsvc/yp.h> 48 #include <rpcsvc/ypclnt.h> 49 #include "ypinternal.h" 50 #endif 51 #include "thread_private.h" 52 53 _THREAD_PRIVATE_KEY(gr); 54 _THREAD_PRIVATE_MUTEX(gr); 55 static FILE *_gr_fp; 56 static struct group _gr_group; 57 static int _gr_stayopen; 58 static int grscan __P((int, gid_t, const char *, struct group *)); 59 static int start_gr __P((void)); 60 static void endgrent_basic __P((void)); 61 62 _THREAD_PRIVATE_KEY(gr_storage); 63 static struct group_storage { 64 #define MAXGRP 200 65 char *members[MAXGRP]; 66 #define MAXLINELENGTH 1024 67 char line[MAXLINELENGTH]; 68 } gr_storage; 69 70 #ifdef YP 71 enum _ypmode { YPMODE_NONE, YPMODE_FULL, YPMODE_NAME }; 72 static enum _ypmode __ypmode; 73 static char *__ypcurrent, *__ypdomain; 74 static int __ypcurrentlen; 75 #endif 76 77 struct group * 78 getgrent_r(p_gr) 79 struct group *p_gr; 80 { 81 _THREAD_PRIVATE_MUTEX_LOCK(gr); 82 if ((!_gr_fp && !start_gr()) || !grscan(0, 0, NULL, p_gr)) 83 p_gr = NULL; 84 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 85 return (p_gr); 86 } 87 88 struct group * 89 getgrent() 90 { 91 struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr,_gr_group,NULL); 92 93 return getgrent_r(p_gr); 94 } 95 96 struct group * 97 getgrnam_r(name, p_gr) 98 const char *name; 99 struct group *p_gr; 100 { 101 int rval; 102 103 _THREAD_PRIVATE_MUTEX_LOCK(gr); 104 if (!start_gr()) 105 rval = 0; 106 else { 107 rval = grscan(1, 0, name, p_gr); 108 if (!_gr_stayopen) 109 endgrent_basic(); 110 } 111 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 112 return(rval ? p_gr : NULL); 113 } 114 115 struct group * 116 getgrnam(name) 117 const char *name; 118 { 119 struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr,_gr_group,NULL); 120 121 return getgrnam_r(name, p_gr); 122 } 123 124 struct group * 125 getgrgid_r(gid, p_gr) 126 gid_t gid; 127 struct group *p_gr; 128 { 129 int rval; 130 131 _THREAD_PRIVATE_MUTEX_LOCK(gr); 132 if (!start_gr()) 133 rval = 0; 134 else { 135 rval = grscan(1, gid, NULL, p_gr); 136 if (!_gr_stayopen) 137 endgrent_basic(); 138 } 139 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 140 return(rval ? p_gr : NULL); 141 } 142 143 struct group * 144 getgrgid(gid) 145 gid_t gid; 146 { 147 struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr,_gr_group,NULL); 148 149 return getgrgid_r(gid, p_gr); 150 } 151 152 static int 153 start_gr() 154 { 155 if (_gr_fp) { 156 rewind(_gr_fp); 157 #ifdef YP 158 __ypmode = YPMODE_NONE; 159 if(__ypcurrent) 160 free(__ypcurrent); 161 __ypcurrent = NULL; 162 #endif 163 return(1); 164 } 165 return((_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0); 166 } 167 168 void 169 setgrent() 170 { 171 (void) setgroupent(0); 172 } 173 174 int 175 setgroupent(stayopen) 176 int stayopen; 177 { 178 int retval; 179 180 _THREAD_PRIVATE_MUTEX_LOCK(gr); 181 if (!start_gr()) 182 retval = 0; 183 else { 184 _gr_stayopen = stayopen; 185 retval = 1; 186 } 187 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 188 return (retval); 189 } 190 191 static 192 void 193 endgrent_basic() 194 { 195 if (_gr_fp) { 196 (void)fclose(_gr_fp); 197 _gr_fp = NULL; 198 #ifdef YP 199 __ypmode = YPMODE_NONE; 200 if(__ypcurrent) 201 free(__ypcurrent); 202 __ypcurrent = NULL; 203 #endif 204 } 205 } 206 207 void 208 endgrent() 209 { 210 _THREAD_PRIVATE_MUTEX_LOCK(gr); 211 endgrent_basic(); 212 _THREAD_PRIVATE_MUTEX_UNLOCK(gr); 213 } 214 215 static int 216 grscan(search, gid, name, p_gr) 217 register int search; 218 register gid_t gid; 219 register const char *name; 220 struct group *p_gr; 221 { 222 register char *cp, **m; 223 char *bp, *endp; 224 u_long ul; 225 #ifdef YP 226 char *key, *data; 227 int keylen, datalen; 228 int r; 229 char *grname = (char *)NULL; 230 #endif 231 char **members; 232 char *line; 233 struct group_storage *gs; 234 235 /* Always use thread-specific storage for member data. */ 236 gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage,gr_storage,NULL); 237 if (gs == NULL) 238 return 0; 239 members = gs->members; 240 line = gs->line; 241 242 for (;;) { 243 #ifdef YP 244 if(__ypmode != YPMODE_NONE) { 245 246 if(!__ypdomain) { 247 if(yp_get_default_domain(&__ypdomain)) { 248 __ypmode = YPMODE_NONE; 249 if(grname != (char *)NULL) { 250 free(grname); 251 grname = (char *)NULL; 252 } 253 continue; 254 } 255 } 256 switch(__ypmode) { 257 case YPMODE_FULL: 258 if(__ypcurrent) { 259 r = yp_next(__ypdomain, "group.byname", 260 __ypcurrent, __ypcurrentlen, 261 &key, &keylen, &data, &datalen); 262 free(__ypcurrent); 263 if(r != 0) { 264 __ypcurrent = NULL; 265 __ypmode = YPMODE_NONE; 266 free(data); 267 continue; 268 } 269 __ypcurrent = key; 270 __ypcurrentlen = keylen; 271 bcopy(data, line, datalen); 272 free(data); 273 } else { 274 r = yp_first(__ypdomain, "group.byname", 275 &__ypcurrent, &__ypcurrentlen, 276 &data, &datalen); 277 if(r != 0) { 278 __ypmode = YPMODE_NONE; 279 free(data); 280 continue; 281 } 282 bcopy(data, line, datalen); 283 free(data); 284 } 285 break; 286 case YPMODE_NAME: 287 if(grname != (char *)NULL) { 288 r = yp_match(__ypdomain, "group.byname", 289 grname, strlen(grname), 290 &data, &datalen); 291 __ypmode = YPMODE_NONE; 292 free(grname); 293 grname = (char *)NULL; 294 if(r != 0) { 295 free(data); 296 continue; 297 } 298 bcopy(data, line, datalen); 299 free(data); 300 } else { 301 __ypmode = YPMODE_NONE; /* ??? */ 302 continue; 303 } 304 break; 305 } 306 line[datalen] = '\0'; 307 bp = line; 308 goto parse; 309 } 310 #endif 311 if (!fgets(line, sizeof(gs->line), _gr_fp)) 312 return(0); 313 bp = line; 314 /* skip lines that are too big */ 315 if (!strchr(line, '\n')) { 316 int ch; 317 318 while ((ch = getc(_gr_fp)) != '\n' && ch != EOF) 319 ; 320 continue; 321 } 322 #ifdef YP 323 if (line[0] == '+') { 324 switch(line[1]) { 325 case ':': 326 case '\0': 327 case '\n': 328 if(_yp_check(NULL)) { 329 if (!search) { 330 __ypmode = YPMODE_FULL; 331 continue; 332 } 333 if(!__ypdomain && 334 yp_get_default_domain(&__ypdomain)) 335 continue; 336 if (name) { 337 r = yp_match(__ypdomain, 338 "group.byname", 339 name, strlen(name), 340 &data, &datalen); 341 } else { 342 char buf[20]; 343 sprintf(buf, "%u", gid); 344 r = yp_match(__ypdomain, 345 "group.bygid", 346 buf, strlen(buf), 347 &data, &datalen); 348 } 349 if (r != 0) 350 continue; 351 bcopy(data, line, datalen); 352 free(data); 353 line[datalen] = '\0'; 354 bp = line; 355 p_gr->gr_name = strsep(&bp, ":\n"); 356 p_gr->gr_passwd = 357 strsep(&bp, ":\n"); 358 if (!(cp = strsep(&bp, ":\n"))) 359 continue; 360 if (name) { 361 ul = strtoul(cp, &endp, 10); 362 if (*endp != '\0' || 363 endp == cp || ul >= GID_MAX) 364 continue; 365 p_gr->gr_gid = ul; 366 } else 367 p_gr->gr_gid = gid; 368 goto found_it; 369 } 370 break; 371 default: 372 if(_yp_check(NULL)) { 373 register char *tptr; 374 375 tptr = strsep(&bp, ":\n"); 376 if (search && name && strcmp(tptr, name)) 377 continue; 378 __ypmode = YPMODE_NAME; 379 grname = strdup(tptr + 1); 380 continue; 381 } 382 break; 383 } 384 } 385 parse: 386 #endif 387 p_gr->gr_name = strsep(&bp, ":\n"); 388 if (search && name && strcmp(p_gr->gr_name, name)) 389 continue; 390 p_gr->gr_passwd = strsep(&bp, ":\n"); 391 if (!(cp = strsep(&bp, ":\n"))) 392 continue; 393 ul = strtoul(cp, &endp, 10); 394 if (endp == cp || *endp != '\0' || ul >= GID_MAX) 395 continue; 396 p_gr->gr_gid = ul; 397 if (search && name == NULL && p_gr->gr_gid != gid) 398 continue; 399 found_it: 400 cp = NULL; 401 if (bp == NULL) 402 continue; 403 for (m = p_gr->gr_mem = members;; bp++) { 404 if (m == &members[MAXGRP - 1]) 405 break; 406 if (*bp == ',') { 407 if (cp) { 408 *bp = '\0'; 409 *m++ = cp; 410 cp = NULL; 411 } 412 } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') { 413 if (cp) { 414 *bp = '\0'; 415 *m++ = cp; 416 } 417 break; 418 } else if (cp == NULL) 419 cp = bp; 420 } 421 *m = NULL; 422 return(1); 423 } 424 /* NOTREACHED */ 425 } 426