1 /* 2 * Copyright (c) 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. 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 #if defined(LIBC_SCCS) && !defined(lint) 35 static char sccsid[] = "@(#)getpwent.c 8.1 (Berkeley) 6/4/93"; 36 #endif /* LIBC_SCCS and not lint */ 37 38 #include <sys/param.h> 39 #include <fcntl.h> 40 #include <db.h> 41 #include <syslog.h> 42 #include <pwd.h> 43 #include <utmp.h> 44 #include <errno.h> 45 #include <unistd.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <limits.h> 49 50 static struct passwd _pw_passwd; /* password structure */ 51 static DB *_pw_db; /* password database */ 52 static int _pw_keynum; /* key counter */ 53 static int _pw_stayopen; /* keep fd's open */ 54 #ifdef YP 55 static struct passwd _pw_copy; 56 static int _yp_enabled; /* set true when yp enabled */ 57 static int _pw_stepping_yp; /* set true when stepping thru map */ 58 #endif 59 static int __hashpw(), __initdb(); 60 61 static int _havemaster(const char *); 62 static int _getyppass(struct passwd *, const char *, const char *); 63 static int _nextyppass(struct passwd *); 64 65 struct passwd * 66 getpwent() 67 { 68 DBT key; 69 char bf[sizeof(_pw_keynum) + 1]; 70 int rv; 71 72 if (!_pw_db && !__initdb()) 73 return((struct passwd *)NULL); 74 75 #ifdef YP 76 if(_pw_stepping_yp) { 77 _pw_passwd = _pw_copy; 78 return (_nextyppass(&_pw_passwd) ? &_pw_passwd : 0); 79 } 80 #endif 81 82 tryagain: 83 ++_pw_keynum; 84 bf[0] = _PW_KEYBYNUM; 85 bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum)); 86 key.data = (u_char *)bf; 87 key.size = sizeof(_pw_keynum) + 1; 88 rv = __hashpw(&key); 89 if(!rv) return (struct passwd *)NULL; 90 #ifdef YP 91 if(_pw_passwd.pw_name[0] == '+' && _pw_passwd.pw_name[1]) { 92 _getyppass(&_pw_passwd, &_pw_passwd.pw_name[1], 93 "passwd.byname"); 94 } else if(_pw_passwd.pw_name[0] == '+') { 95 _pw_copy = _pw_passwd; 96 return (_nextyppass(&_pw_passwd) ? &_pw_passwd : 0); 97 } 98 #else 99 /* Ignore YP password file entries when YP is disabled. */ 100 if(_pw_passwd.pw_name[0] == '+') { 101 goto tryagain; 102 } 103 #endif 104 return(&_pw_passwd); 105 } 106 107 struct passwd * 108 getpwnam(name) 109 const char *name; 110 { 111 DBT key; 112 int len, rval; 113 char bf[UT_NAMESIZE + 2]; 114 115 if (!_pw_db && !__initdb()) 116 return((struct passwd *)NULL); 117 118 bf[0] = _PW_KEYBYNAME; 119 len = strlen(name); 120 bcopy(name, bf + 1, MIN(len, UT_NAMESIZE)); 121 key.data = (u_char *)bf; 122 key.size = len + 1; 123 rval = __hashpw(&key); 124 125 #ifdef YP 126 if (!rval && _yp_enabled) { 127 bf[1] = '+'; 128 bcopy(name, bf + 2, MIN(len, UT_NAMESIZE - 1)); 129 key.data = (u_char *)bf; 130 key.size = len + 2; 131 rval = __hashpw(&key); 132 if (!rval && _yp_enabled < 0) { 133 key.size = 2; 134 rval = __hashpw(&key); 135 } 136 if(rval) 137 rval = _getyppass(&_pw_passwd, name, "passwd.byname"); 138 } 139 #endif 140 /* 141 * Prevent login attempts when YP is not enabled but YP entries 142 * are in /etc/master.passwd. 143 */ 144 if (rval && _pw_passwd.pw_name[0] == '+') rval = 0; 145 146 if (!_pw_stayopen) { 147 (void)(_pw_db->close)(_pw_db); 148 _pw_db = (DB *)NULL; 149 } 150 return(rval ? &_pw_passwd : (struct passwd *)NULL); 151 } 152 153 struct passwd * 154 #ifdef __STDC__ 155 getpwuid(uid_t uid) 156 #else 157 getpwuid(uid) 158 int uid; 159 #endif 160 { 161 DBT key; 162 int keyuid, rval; 163 char bf[sizeof(keyuid) + 1]; 164 165 if (!_pw_db && !__initdb()) 166 return((struct passwd *)NULL); 167 168 bf[0] = _PW_KEYBYUID; 169 keyuid = uid; 170 bcopy(&keyuid, bf + 1, sizeof(keyuid)); 171 key.data = (u_char *)bf; 172 key.size = sizeof(keyuid) + 1; 173 rval = __hashpw(&key); 174 175 #ifdef YP 176 if (!rval && _yp_enabled) { 177 char ypbuf[16]; /* big enough for 32-bit uids and then some */ 178 snprintf(ypbuf, sizeof ypbuf, "%u", (unsigned)uid); 179 rval = _getyppass(&_pw_passwd, ypbuf, "passwd.byuid"); 180 } 181 #endif 182 if (!_pw_stayopen) { 183 (void)(_pw_db->close)(_pw_db); 184 _pw_db = (DB *)NULL; 185 } 186 return(rval ? &_pw_passwd : (struct passwd *)NULL); 187 } 188 189 int 190 setpassent(stayopen) 191 int stayopen; 192 { 193 _pw_keynum = 0; 194 #ifdef YP 195 _pw_stepping_yp = 0; 196 #endif 197 _pw_stayopen = stayopen; 198 return(1); 199 } 200 201 int 202 setpwent() 203 { 204 _pw_keynum = 0; 205 #ifdef YP 206 _pw_stepping_yp = 0; 207 #endif 208 _pw_stayopen = 0; 209 return(1); 210 } 211 212 void 213 endpwent() 214 { 215 _pw_keynum = 0; 216 #ifdef YP 217 _pw_stepping_yp = 0; 218 #endif 219 if (_pw_db) { 220 (void)(_pw_db->close)(_pw_db); 221 _pw_db = (DB *)NULL; 222 } 223 } 224 225 static 226 __initdb() 227 { 228 static int warned; 229 char *p; 230 231 p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB; 232 _pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL); 233 if (_pw_db) { 234 #ifdef YP 235 DBT key, data; 236 char buf[] = { _PW_KEYYPENABLED }; 237 key.data = buf; 238 key.size = 1; 239 if ((_pw_db->get)(_pw_db, &key, &data, 0)) { 240 _yp_enabled = 0; 241 } else { 242 /* Distinguish between old and new versions of 243 pwd_mkdb. */ 244 if(data.size != 1) { 245 _yp_enabled = -1; 246 } else { 247 _yp_enabled = (int)*((char *)data.data) - 2; 248 } 249 } 250 #endif 251 return(1); 252 } 253 if (!warned) 254 syslog(LOG_ERR, "%s: %m", p); 255 return(0); 256 } 257 258 static 259 __hashpw(key) 260 DBT *key; 261 { 262 register char *p, *t; 263 static u_int max; 264 static char *line; 265 DBT data; 266 267 /* 268 * XXX The pw_fields member of _pw_passwd needs to be cleared 269 * at some point since __hashpw() can be called several times in 270 * a single program. If we leave here after the second invokation 271 * with garbage data in pw_fields, it can totally screw up NIS 272 * lookups (the pw_breakout_yp function only populates the pw_passwd 273 * structure if the pw_fields bits are clear). 274 */ 275 if ((_pw_db->get)(_pw_db, key, &data, 0)) { 276 if (_pw_passwd.pw_fields) 277 _pw_passwd.pw_fields = 0; 278 return(0); 279 } 280 p = (char *)data.data; 281 if (data.size > max && !(line = realloc(line, max += 1024))) { 282 if (_pw_passwd.pw_fields) 283 _pw_passwd.pw_fields = 0; 284 return(0); 285 } 286 287 t = line; 288 #define EXPAND(e) e = t; while (*t++ = *p++); 289 EXPAND(_pw_passwd.pw_name); 290 EXPAND(_pw_passwd.pw_passwd); 291 bcopy(p, (char *)&_pw_passwd.pw_uid, sizeof(int)); 292 p += sizeof(int); 293 bcopy(p, (char *)&_pw_passwd.pw_gid, sizeof(int)); 294 p += sizeof(int); 295 bcopy(p, (char *)&_pw_passwd.pw_change, sizeof(time_t)); 296 p += sizeof(time_t); 297 EXPAND(_pw_passwd.pw_class); 298 EXPAND(_pw_passwd.pw_gecos); 299 EXPAND(_pw_passwd.pw_dir); 300 EXPAND(_pw_passwd.pw_shell); 301 bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t)); 302 p += sizeof(time_t); 303 bcopy(p, (char *)&_pw_passwd.pw_fields, sizeof _pw_passwd.pw_fields); 304 p += sizeof _pw_passwd.pw_fields; 305 return(1); 306 } 307 308 #ifdef YP 309 static void 310 _pw_breakout_yp(struct passwd *pw, char *result, int master) 311 { 312 char *s; 313 314 s = strsep(&result, ":"); /* name */ 315 if(!(pw->pw_fields & _PWF_NAME) || (pw->pw_name[0] == '+')) { 316 pw->pw_name = s; 317 pw->pw_fields |= _PWF_NAME; 318 } 319 320 s = strsep(&result, ":"); /* password */ 321 if(!(pw->pw_fields & _PWF_PASSWD)) { 322 pw->pw_passwd = s; 323 pw->pw_fields |= _PWF_PASSWD; 324 } 325 326 s = strsep(&result, ":"); /* uid */ 327 if(!(pw->pw_fields & _PWF_UID)) { 328 pw->pw_uid = atoi(s); 329 pw->pw_fields |= _PWF_UID; 330 } 331 332 s = strsep(&result, ":"); /* gid */ 333 if(!(pw->pw_fields & _PWF_GID)) { 334 pw->pw_gid = atoi(s); 335 pw->pw_fields |= _PWF_GID; 336 } 337 338 if (master) { 339 s = strsep(&result, ":"); /* class */ 340 if(!(pw->pw_fields & _PWF_CLASS)) { 341 pw->pw_class = s; 342 pw->pw_fields |= _PWF_CLASS; 343 } 344 345 s = strsep(&result, ":"); /* change */ 346 if(!(pw->pw_fields & _PWF_CHANGE)) { 347 pw->pw_change = atol(s); 348 pw->pw_fields |= _PWF_CHANGE; 349 } 350 351 s = strsep(&result, ":"); /* expire */ 352 if(!(pw->pw_fields & _PWF_EXPIRE)) { 353 pw->pw_expire = atol(s); 354 pw->pw_fields |= _PWF_EXPIRE; 355 } 356 } 357 358 s = strsep(&result, ":"); /* gecos */ 359 if(!(pw->pw_fields & _PWF_GECOS)) { 360 pw->pw_gecos = s; 361 pw->pw_fields |= _PWF_GECOS; 362 } 363 364 s = strsep(&result, ":"); /* dir */ 365 if(!(pw->pw_fields & _PWF_DIR)) { 366 pw->pw_dir = s; 367 pw->pw_fields |= _PWF_DIR; 368 } 369 370 s = strsep(&result, ":"); /* shell */ 371 if(!(pw->pw_fields & _PWF_SHELL)) { 372 pw->pw_shell = s; 373 pw->pw_fields |= _PWF_SHELL; 374 } 375 } 376 377 static char *_pw_yp_domain; 378 379 static int 380 _havemaster(const char *_pw_yp_domain) 381 { 382 char *result; 383 static char *key; 384 int resultlen; 385 static int keylen; 386 387 if (yp_first(_pw_yp_domain, "master.passwd.byname", 388 &key, &keylen, &result, &resultlen)) 389 return 0; 390 391 return 1; 392 } 393 394 static int 395 _getyppass(struct passwd *pw, const char *name, const char *map) 396 { 397 char *result, *s; 398 static char resultbuf[1024]; 399 int resultlen; 400 char mastermap[1024]; 401 int gotmaster = 0; 402 403 if(!_pw_yp_domain) { 404 if(yp_get_default_domain(&_pw_yp_domain)) 405 return 0; 406 } 407 408 sprintf(mastermap,"%s",map); 409 410 /* Don't even bother with this if we aren't root. */ 411 if (!geteuid()) 412 if (_havemaster(_pw_yp_domain)) { 413 sprintf(mastermap,"master.%s", map); 414 gotmaster++; 415 } 416 417 if(yp_match(_pw_yp_domain, &mastermap, name, strlen(name), 418 &result, &resultlen)) 419 return 0; 420 421 s = strchr(result, '\n'); 422 if(s) *s = '\0'; 423 424 if(resultlen >= sizeof resultbuf) return 0; 425 strcpy(resultbuf, result); 426 result = resultbuf; 427 _pw_breakout_yp(pw, resultbuf, gotmaster); 428 429 return 1; 430 } 431 432 static int 433 _nextyppass(struct passwd *pw) 434 { 435 static char *key; 436 static int keylen; 437 char *lastkey, *result; 438 static char resultbuf[1024]; 439 int resultlen; 440 int rv; 441 char *map = "passwd.byname"; 442 int gotmaster = 0; 443 444 if(!_pw_yp_domain) { 445 if(yp_get_default_domain(&_pw_yp_domain)) 446 return 0; 447 } 448 449 /* Don't even bother with this if we aren't root. */ 450 if (!geteuid()) 451 if(_havemaster(_pw_yp_domain)) { 452 map = "master.passwd.byname"; 453 gotmaster++; 454 } 455 456 if(!_pw_stepping_yp) { 457 if(key) free(key); 458 rv = yp_first(_pw_yp_domain, map, 459 &key, &keylen, &result, &resultlen); 460 if(rv) { 461 return 0; 462 } 463 _pw_stepping_yp = 1; 464 goto unpack; 465 } else { 466 tryagain: 467 lastkey = key; 468 rv = yp_next(_pw_yp_domain, map, key, keylen, 469 &key, &keylen, &result, &resultlen); 470 free(lastkey); 471 unpack: 472 if(rv) { 473 _pw_stepping_yp = 0; 474 return 0; 475 } 476 477 if(resultlen > sizeof(resultbuf)) { 478 free(result); 479 goto tryagain; 480 } 481 482 strcpy(resultbuf, result); 483 free(result); 484 if(result = strchr(resultbuf, '\n')) *result = '\0'; 485 _pw_breakout_yp(pw, resultbuf, gotmaster); 486 } 487 return 1; 488 } 489 490 #endif /* YP */ 491