1 /* $NetBSD: getid.c,v 1.10 2014/10/27 21:46:45 christos Exp $ */ 2 /* from: NetBSD: getpwent.c,v 1.48 2000/10/03 03:22:26 enami Exp */ 3 /* from: NetBSD: getgrent.c,v 1.41 2002/01/12 23:51:30 lukem Exp */ 4 5 /* 6 * Copyright (c) 1987, 1988, 1989, 1993, 1994, 1995 7 * The Regents of the University of California. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 /*- 35 * Copyright (c) 2002 The NetBSD Foundation, Inc. 36 * All rights reserved. 37 * 38 * This code is derived from software contributed to The NetBSD Foundation 39 * by Luke Mewburn of Wasabi Systems. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 50 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 51 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 52 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 53 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 54 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 55 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 56 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 57 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 58 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 59 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 60 * POSSIBILITY OF SUCH DAMAGE. 61 */ 62 63 #if HAVE_NBTOOL_CONFIG_H 64 #include "nbtool_config.h" 65 #endif 66 67 #include <sys/cdefs.h> 68 __RCSID("$NetBSD: getid.c,v 1.10 2014/10/27 21:46:45 christos Exp $"); 69 70 #include <sys/param.h> 71 72 #include <grp.h> 73 #include <limits.h> 74 #include <pwd.h> 75 #include <stdlib.h> 76 #include <stdio.h> 77 #include <string.h> 78 #include <time.h> 79 #include <unistd.h> 80 81 #include "extern.h" 82 83 static struct group * gi_getgrnam(const char *); 84 static struct group * gi_getgrgid(gid_t); 85 static int gi_setgroupent(int); 86 static void gi_endgrent(void); 87 static int grstart(void); 88 static int grscan(int, gid_t, const char *); 89 static int grmatchline(int, gid_t, const char *); 90 91 static struct passwd * gi_getpwnam(const char *); 92 static struct passwd * gi_getpwuid(uid_t); 93 static int gi_setpassent(int); 94 static void gi_endpwent(void); 95 static int pwstart(void); 96 static int pwscan(int, uid_t, const char *); 97 static int pwmatchline(int, uid_t, const char *); 98 99 #define MAXGRP 200 100 #define MAXLINELENGTH 1024 101 102 static FILE *_gr_fp; 103 static struct group _gr_group; 104 static int _gr_stayopen; 105 static int _gr_filesdone; 106 static FILE *_pw_fp; 107 static struct passwd _pw_passwd; /* password structure */ 108 static int _pw_stayopen; /* keep fd's open */ 109 static int _pw_filesdone; 110 111 static char grfile[MAXPATHLEN]; 112 static char pwfile[MAXPATHLEN]; 113 114 static char *members[MAXGRP]; 115 static char grline[MAXLINELENGTH]; 116 static char pwline[MAXLINELENGTH]; 117 118 int 119 setup_getid(const char *dir) 120 { 121 if (dir == NULL) 122 return (0); 123 124 /* close existing databases */ 125 gi_endgrent(); 126 gi_endpwent(); 127 128 /* build paths to new databases */ 129 snprintf(grfile, sizeof(grfile), "%s/group", dir); 130 snprintf(pwfile, sizeof(pwfile), "%s/master.passwd", dir); 131 132 /* try to open new databases */ 133 if (!grstart() || !pwstart()) 134 return (0); 135 136 /* switch pwcache(3) lookup functions */ 137 if (pwcache_groupdb(gi_setgroupent, gi_endgrent, 138 gi_getgrnam, gi_getgrgid) == -1 139 || pwcache_userdb(gi_setpassent, gi_endpwent, 140 gi_getpwnam, gi_getpwuid) == -1) 141 return (0); 142 143 return (1); 144 } 145 146 147 /* 148 * group lookup functions 149 */ 150 151 static struct group * 152 gi_getgrnam(const char *name) 153 { 154 int rval; 155 156 if (!grstart()) 157 return NULL; 158 rval = grscan(1, 0, name); 159 if (!_gr_stayopen) 160 endgrent(); 161 return (rval) ? &_gr_group : NULL; 162 } 163 164 static struct group * 165 gi_getgrgid(gid_t gid) 166 { 167 int rval; 168 169 if (!grstart()) 170 return NULL; 171 rval = grscan(1, gid, NULL); 172 if (!_gr_stayopen) 173 endgrent(); 174 return (rval) ? &_gr_group : NULL; 175 } 176 177 static int 178 gi_setgroupent(int stayopen) 179 { 180 181 if (!grstart()) 182 return 0; 183 _gr_stayopen = stayopen; 184 return 1; 185 } 186 187 static void 188 gi_endgrent(void) 189 { 190 191 _gr_filesdone = 0; 192 if (_gr_fp) { 193 (void)fclose(_gr_fp); 194 _gr_fp = NULL; 195 } 196 } 197 198 static int 199 grstart(void) 200 { 201 202 _gr_filesdone = 0; 203 if (_gr_fp) { 204 rewind(_gr_fp); 205 return 1; 206 } 207 if (grfile[0] == '\0') /* sanity check */ 208 return 0; 209 210 _gr_fp = fopen(grfile, "r"); 211 if (_gr_fp != NULL) 212 return 1; 213 warn("Can't open `%s'", grfile); 214 return 0; 215 } 216 217 218 static int 219 grscan(int search, gid_t gid, const char *name) 220 { 221 222 if (_gr_filesdone) 223 return 0; 224 for (;;) { 225 if (!fgets(grline, sizeof(grline), _gr_fp)) { 226 if (!search) 227 _gr_filesdone = 1; 228 return 0; 229 } 230 /* skip lines that are too big */ 231 if (!strchr(grline, '\n')) { 232 int ch; 233 234 while ((ch = getc(_gr_fp)) != '\n' && ch != EOF) 235 ; 236 continue; 237 } 238 /* skip comments */ 239 if (grline[0] == '#') 240 continue; 241 if (grmatchline(search, gid, name)) 242 return 1; 243 } 244 /* NOTREACHED */ 245 } 246 247 static int 248 grmatchline(int search, gid_t gid, const char *name) 249 { 250 unsigned long id; 251 char **m; 252 char *cp, *bp, *ep; 253 254 /* name may be NULL if search is nonzero */ 255 256 bp = grline; 257 memset(&_gr_group, 0, sizeof(_gr_group)); 258 _gr_group.gr_name = strsep(&bp, ":\n"); 259 if (search && name && strcmp(_gr_group.gr_name, name)) 260 return 0; 261 _gr_group.gr_passwd = strsep(&bp, ":\n"); 262 if (!(cp = strsep(&bp, ":\n"))) 263 return 0; 264 id = strtoul(cp, &ep, 10); 265 if (id > GID_MAX || *ep != '\0') 266 return 0; 267 _gr_group.gr_gid = (gid_t)id; 268 if (search && name == NULL && _gr_group.gr_gid != gid) 269 return 0; 270 cp = NULL; 271 if (bp == NULL) 272 return 0; 273 for (_gr_group.gr_mem = m = members;; bp++) { 274 if (m == &members[MAXGRP - 1]) 275 break; 276 if (*bp == ',') { 277 if (cp) { 278 *bp = '\0'; 279 *m++ = cp; 280 cp = NULL; 281 } 282 } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') { 283 if (cp) { 284 *bp = '\0'; 285 *m++ = cp; 286 } 287 break; 288 } else if (cp == NULL) 289 cp = bp; 290 } 291 *m = NULL; 292 return 1; 293 } 294 295 296 /* 297 * user lookup functions 298 */ 299 300 static struct passwd * 301 gi_getpwnam(const char *name) 302 { 303 int rval; 304 305 if (!pwstart()) 306 return NULL; 307 rval = pwscan(1, 0, name); 308 if (!_pw_stayopen) 309 endpwent(); 310 return (rval) ? &_pw_passwd : NULL; 311 } 312 313 static struct passwd * 314 gi_getpwuid(uid_t uid) 315 { 316 int rval; 317 318 if (!pwstart()) 319 return NULL; 320 rval = pwscan(1, uid, NULL); 321 if (!_pw_stayopen) 322 endpwent(); 323 return (rval) ? &_pw_passwd : NULL; 324 } 325 326 static int 327 gi_setpassent(int stayopen) 328 { 329 330 if (!pwstart()) 331 return 0; 332 _pw_stayopen = stayopen; 333 return 1; 334 } 335 336 static void 337 gi_endpwent(void) 338 { 339 340 _pw_filesdone = 0; 341 if (_pw_fp) { 342 (void)fclose(_pw_fp); 343 _pw_fp = NULL; 344 } 345 } 346 347 static int 348 pwstart(void) 349 { 350 351 _pw_filesdone = 0; 352 if (_pw_fp) { 353 rewind(_pw_fp); 354 return 1; 355 } 356 if (pwfile[0] == '\0') /* sanity check */ 357 return 0; 358 _pw_fp = fopen(pwfile, "r"); 359 if (_pw_fp != NULL) 360 return 1; 361 warn("Can't open `%s'", pwfile); 362 return 0; 363 } 364 365 366 static int 367 pwscan(int search, uid_t uid, const char *name) 368 { 369 370 if (_pw_filesdone) 371 return 0; 372 for (;;) { 373 if (!fgets(pwline, sizeof(pwline), _pw_fp)) { 374 if (!search) 375 _pw_filesdone = 1; 376 return 0; 377 } 378 /* skip lines that are too big */ 379 if (!strchr(pwline, '\n')) { 380 int ch; 381 382 while ((ch = getc(_pw_fp)) != '\n' && ch != EOF) 383 ; 384 continue; 385 } 386 /* skip comments */ 387 if (pwline[0] == '#') 388 continue; 389 if (pwmatchline(search, uid, name)) 390 return 1; 391 } 392 /* NOTREACHED */ 393 } 394 395 static int 396 pwmatchline(int search, uid_t uid, const char *name) 397 { 398 unsigned long id; 399 char *cp, *bp, *ep; 400 401 /* name may be NULL if search is nonzero */ 402 403 bp = pwline; 404 memset(&_pw_passwd, 0, sizeof(_pw_passwd)); 405 _pw_passwd.pw_name = strsep(&bp, ":\n"); /* name */ 406 if (search && name && strcmp(_pw_passwd.pw_name, name)) 407 return 0; 408 409 _pw_passwd.pw_passwd = strsep(&bp, ":\n"); /* passwd */ 410 411 if (!(cp = strsep(&bp, ":\n"))) /* uid */ 412 return 0; 413 id = strtoul(cp, &ep, 10); 414 if (id > UID_MAX || *ep != '\0') 415 return 0; 416 _pw_passwd.pw_uid = (uid_t)id; 417 if (search && name == NULL && _pw_passwd.pw_uid != uid) 418 return 0; 419 420 if (!(cp = strsep(&bp, ":\n"))) /* gid */ 421 return 0; 422 id = strtoul(cp, &ep, 10); 423 if (id > GID_MAX || *ep != '\0') 424 return 0; 425 _pw_passwd.pw_gid = (gid_t)id; 426 427 if (!(ep = strsep(&bp, ":"))) /* class */ 428 return 0; 429 if (!(ep = strsep(&bp, ":"))) /* change */ 430 return 0; 431 if (!(ep = strsep(&bp, ":"))) /* expire */ 432 return 0; 433 434 if (!(_pw_passwd.pw_gecos = strsep(&bp, ":\n"))) /* gecos */ 435 return 0; 436 if (!(_pw_passwd.pw_dir = strsep(&bp, ":\n"))) /* directory */ 437 return 0; 438 if (!(_pw_passwd.pw_shell = strsep(&bp, ":\n"))) /* shell */ 439 return 0; 440 441 if (strchr(bp, ':') != NULL) 442 return 0; 443 444 return 1; 445 } 446 447