1 1.84 christos /* $NetBSD: getpwent.c,v 1.84 2024/01/20 14:52:47 christos Exp $ */ 2 1.57 lukem 3 1.57 lukem /*- 4 1.66 lukem * Copyright (c) 1997-2000, 2004-2005 The NetBSD Foundation, Inc. 5 1.57 lukem * All rights reserved. 6 1.57 lukem * 7 1.57 lukem * This code is derived from software contributed to The NetBSD Foundation 8 1.57 lukem * by Luke Mewburn. 9 1.57 lukem * 10 1.57 lukem * Redistribution and use in source and binary forms, with or without 11 1.57 lukem * modification, are permitted provided that the following conditions 12 1.57 lukem * are met: 13 1.57 lukem * 1. Redistributions of source code must retain the above copyright 14 1.57 lukem * notice, this list of conditions and the following disclaimer. 15 1.57 lukem * 2. Redistributions in binary form must reproduce the above copyright 16 1.57 lukem * notice, this list of conditions and the following disclaimer in the 17 1.57 lukem * documentation and/or other materials provided with the distribution. 18 1.57 lukem * 19 1.57 lukem * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.57 lukem * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.57 lukem * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.57 lukem * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.57 lukem * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.57 lukem * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.57 lukem * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.57 lukem * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.57 lukem * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.57 lukem * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.57 lukem * POSSIBILITY OF SUCH DAMAGE. 30 1.57 lukem */ 31 1.12 cgd 32 1.1 cgd /* 33 1.12 cgd * Copyright (c) 1988, 1993 34 1.12 cgd * The Regents of the University of California. All rights reserved. 35 1.54 agc * 36 1.54 agc * Redistribution and use in source and binary forms, with or without 37 1.54 agc * modification, are permitted provided that the following conditions 38 1.54 agc * are met: 39 1.54 agc * 1. Redistributions of source code must retain the above copyright 40 1.54 agc * notice, this list of conditions and the following disclaimer. 41 1.54 agc * 2. Redistributions in binary form must reproduce the above copyright 42 1.54 agc * notice, this list of conditions and the following disclaimer in the 43 1.54 agc * documentation and/or other materials provided with the distribution. 44 1.54 agc * 3. Neither the name of the University nor the names of its contributors 45 1.54 agc * may be used to endorse or promote products derived from this software 46 1.54 agc * without specific prior written permission. 47 1.54 agc * 48 1.54 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 1.54 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 1.54 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 1.54 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 1.54 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 1.54 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 1.54 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 1.54 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 1.54 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 1.54 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 1.54 agc * SUCH DAMAGE. 59 1.54 agc */ 60 1.54 agc 61 1.54 agc /* 62 1.14 phil * Portions Copyright (c) 1994, 1995, Jason Downs. All rights reserved. 63 1.1 cgd * 64 1.1 cgd * Redistribution and use in source and binary forms, with or without 65 1.1 cgd * modification, are permitted provided that the following conditions 66 1.1 cgd * are met: 67 1.1 cgd * 1. Redistributions of source code must retain the above copyright 68 1.1 cgd * notice, this list of conditions and the following disclaimer. 69 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 70 1.1 cgd * notice, this list of conditions and the following disclaimer in the 71 1.1 cgd * documentation and/or other materials provided with the distribution. 72 1.1 cgd * 73 1.55 agc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS 74 1.55 agc * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 75 1.55 agc * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 76 1.55 agc * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, 77 1.55 agc * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 78 1.55 agc * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 79 1.55 agc * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 80 1.55 agc * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 81 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 82 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 83 1.1 cgd * SUCH DAMAGE. 84 1.1 cgd */ 85 1.1 cgd 86 1.22 christos #include <sys/cdefs.h> 87 1.1 cgd #if defined(LIBC_SCCS) && !defined(lint) 88 1.12 cgd #if 0 89 1.24 perry static char sccsid[] = "@(#)getpwent.c 8.2 (Berkeley) 4/27/95"; 90 1.12 cgd #else 91 1.84 christos __RCSID("$NetBSD: getpwent.c,v 1.84 2024/01/20 14:52:47 christos Exp $"); 92 1.12 cgd #endif 93 1.1 cgd #endif /* LIBC_SCCS and not lint */ 94 1.1 cgd 95 1.23 jtc #include "namespace.h" 96 1.62 lukem #include "reentrant.h" 97 1.62 lukem 98 1.1 cgd #include <sys/param.h> 99 1.45 lukem 100 1.45 lukem #include <assert.h> 101 1.1 cgd #include <db.h> 102 1.1 cgd #include <errno.h> 103 1.45 lukem #include <fcntl.h> 104 1.1 cgd #include <limits.h> 105 1.14 phil #include <netgroup.h> 106 1.32 lukem #include <nsswitch.h> 107 1.45 lukem #include <pwd.h> 108 1.51 wiz #include <stdarg.h> 109 1.56 lukem #include <stdio.h> 110 1.45 lukem #include <stdlib.h> 111 1.45 lukem #include <string.h> 112 1.45 lukem #include <syslog.h> 113 1.45 lukem #include <unistd.h> 114 1.84 christos #include "pw_private.h" 115 1.45 lukem 116 1.32 lukem #ifdef HESIOD 117 1.32 lukem #include <hesiod.h> 118 1.32 lukem #endif 119 1.57 lukem 120 1.4 deraadt #ifdef YP 121 1.4 deraadt #include <rpc/rpc.h> 122 1.4 deraadt #include <rpcsvc/yp_prot.h> 123 1.4 deraadt #include <rpcsvc/ypclnt.h> 124 1.23 jtc #endif 125 1.23 jtc 126 1.27 thorpej #include "pw_private.h" 127 1.27 thorpej 128 1.57 lukem #define _PASSWD_COMPAT /* "passwd" defaults to compat, so always provide it */ 129 1.57 lukem 130 1.23 jtc #ifdef __weak_alias 131 1.46 mycroft __weak_alias(endpwent,_endpwent) 132 1.46 mycroft __weak_alias(setpassent,_setpassent) 133 1.46 mycroft __weak_alias(setpwent,_setpwent) 134 1.4 deraadt #endif 135 1.1 cgd 136 1.61 lukem #ifdef _REENTRANT 137 1.61 lukem static mutex_t _pwmutex = MUTEX_INITIALIZER; 138 1.61 lukem #endif 139 1.61 lukem 140 1.57 lukem const char __yp_token[] = "__YP!"; /* Let pwd_mkdb pull this in. */ 141 1.24 perry 142 1.32 lukem 143 1.57 lukem /* 144 1.57 lukem * The pwd.db lookup techniques and data extraction code here must be kept 145 1.57 lukem * in sync with that in `pwd_mkdb'. 146 1.57 lukem */ 147 1.26 lukem 148 1.60 lukem #if defined(YP) || defined(HESIOD) 149 1.32 lukem /* 150 1.57 lukem * _pw_parse 151 1.57 lukem * Parses entry using pw_scan(3) (without the trailing \n) 152 1.57 lukem * after copying to buf, and fills in pw with corresponding values. 153 1.57 lukem * If old is non-zero, entry is in _PASSWORD_OLDFMT. 154 1.57 lukem * Returns 1 if parsed successfully, 0 on parse failure. 155 1.32 lukem */ 156 1.14 phil static int 157 1.57 lukem _pw_parse(const char *entry, struct passwd *pw, char *buf, size_t buflen, 158 1.57 lukem int old) 159 1.14 phil { 160 1.57 lukem int flags; 161 1.14 phil 162 1.57 lukem _DIAGASSERT(entry != NULL); 163 1.57 lukem _DIAGASSERT(pw != NULL); 164 1.57 lukem _DIAGASSERT(buf != NULL); 165 1.45 lukem 166 1.57 lukem if (strlcpy(buf, entry, buflen) >= buflen) 167 1.57 lukem return 0; 168 1.59 lukem flags = _PASSWORD_NOWARN; 169 1.57 lukem if (old) 170 1.57 lukem flags |= _PASSWORD_OLDFMT; 171 1.57 lukem return __pw_scan(buf, pw, &flags); 172 1.14 phil } 173 1.60 lukem #endif /* YP || HESIOD */ 174 1.14 phil 175 1.32 lukem /* 176 1.57 lukem * _pw_opendb 177 1.57 lukem * if *db is NULL, dbopen(3) /etc/spwd.db or /etc/pwd.db (depending 178 1.57 lukem * upon permissions, etc) 179 1.32 lukem */ 180 1.14 phil static int 181 1.76 christos _pw_opendb(DB **db, int *version) 182 1.14 phil { 183 1.57 lukem static int warned; 184 1.76 christos DBT key; 185 1.76 christos DBT value; 186 1.14 phil 187 1.70 lukem const char *dbfile = NULL; 188 1.45 lukem 189 1.57 lukem _DIAGASSERT(db != NULL); 190 1.76 christos _DIAGASSERT(version != NULL); 191 1.57 lukem if (*db != NULL) /* open *db */ 192 1.57 lukem return NS_SUCCESS; 193 1.14 phil 194 1.57 lukem if (geteuid() == 0) { 195 1.57 lukem dbfile = _PATH_SMP_DB; 196 1.57 lukem *db = dbopen(dbfile, O_RDONLY, 0, DB_HASH, NULL); 197 1.57 lukem } 198 1.57 lukem if (*db == NULL) { 199 1.57 lukem dbfile = _PATH_MP_DB; 200 1.57 lukem *db = dbopen(dbfile, O_RDONLY, 0, DB_HASH, NULL); 201 1.57 lukem } 202 1.57 lukem if (*db == NULL) { 203 1.57 lukem if (!warned) { 204 1.57 lukem int serrno = errno; 205 1.57 lukem syslog(LOG_ERR, "%s: %m", dbfile); 206 1.57 lukem errno = serrno; 207 1.57 lukem } 208 1.57 lukem warned = 1; 209 1.57 lukem return NS_UNAVAIL; 210 1.57 lukem } 211 1.76 christos key.data = __UNCONST("VERSION"); 212 1.76 christos key.size = strlen((char *)key.data) + 1; 213 1.76 christos switch ((*(*db)->get)(*db, &key, &value, 0)) { 214 1.76 christos case 0: 215 1.76 christos if (sizeof(*version) != value.size) 216 1.76 christos return NS_UNAVAIL; 217 1.76 christos (void)memcpy(version, value.data, value.size); 218 1.76 christos break; /* found */ 219 1.76 christos case 1: 220 1.76 christos *version = 0; /* not found */ 221 1.76 christos break; 222 1.76 christos case -1: 223 1.76 christos return NS_UNAVAIL; /* error in db routines */ 224 1.76 christos default: 225 1.76 christos abort(); 226 1.76 christos } 227 1.57 lukem return NS_SUCCESS; 228 1.14 phil } 229 1.14 phil 230 1.32 lukem /* 231 1.57 lukem * _pw_getkey 232 1.57 lukem * Lookup key in *db, filling in pw 233 1.57 lukem * with the result, allocating memory from buffer (size buflen). 234 1.57 lukem * (The caller may point key.data to buffer on entry; the contents 235 1.57 lukem * of key.data will be invalid on exit.) 236 1.32 lukem */ 237 1.57 lukem static int 238 1.57 lukem _pw_getkey(DB *db, DBT *key, 239 1.76 christos struct passwd *pw, char *buffer, size_t buflen, int *pwflags, 240 1.76 christos int version) 241 1.14 phil { 242 1.57 lukem char *p, *t; 243 1.57 lukem DBT data; 244 1.14 phil 245 1.57 lukem _DIAGASSERT(db != NULL); 246 1.57 lukem _DIAGASSERT(key != NULL); 247 1.57 lukem _DIAGASSERT(pw != NULL); 248 1.57 lukem _DIAGASSERT(buffer != NULL); 249 1.57 lukem /* pwflags may be NULL (if we don't care about them */ 250 1.14 phil 251 1.57 lukem if (db == NULL) /* this shouldn't happen */ 252 1.57 lukem return NS_UNAVAIL; 253 1.14 phil 254 1.57 lukem switch ((db->get)(db, key, &data, 0)) { 255 1.57 lukem case 0: 256 1.57 lukem break; /* found */ 257 1.57 lukem case 1: 258 1.68 lukem return NS_NOTFOUND; /* not found */ 259 1.57 lukem case -1: 260 1.57 lukem return NS_UNAVAIL; /* error in db routines */ 261 1.57 lukem default: 262 1.57 lukem abort(); 263 1.57 lukem } 264 1.14 phil 265 1.57 lukem p = (char *)data.data; 266 1.57 lukem if (data.size > buflen) { 267 1.57 lukem errno = ERANGE; 268 1.57 lukem return NS_UNAVAIL; 269 1.57 lukem } 270 1.14 phil 271 1.57 lukem /* 272 1.57 lukem * THE DECODING BELOW MUST MATCH THAT IN pwd_mkdb. 273 1.57 lukem */ 274 1.57 lukem t = buffer; 275 1.83 rillig #define MACRO(a) do { a } while (0) 276 1.76 christos #define EXPAND(e) MACRO(e = t; while ((*t++ = *p++));) 277 1.76 christos #define SCALAR(v) MACRO(memmove(&(v), p, sizeof v); p += sizeof v;) 278 1.57 lukem EXPAND(pw->pw_name); 279 1.57 lukem EXPAND(pw->pw_passwd); 280 1.57 lukem SCALAR(pw->pw_uid); 281 1.57 lukem SCALAR(pw->pw_gid); 282 1.76 christos if (version == 0) { 283 1.76 christos int32_t tmp; 284 1.76 christos SCALAR(tmp); 285 1.76 christos pw->pw_change = tmp; 286 1.76 christos } else 287 1.76 christos SCALAR(pw->pw_change); 288 1.57 lukem EXPAND(pw->pw_class); 289 1.57 lukem EXPAND(pw->pw_gecos); 290 1.57 lukem EXPAND(pw->pw_dir); 291 1.57 lukem EXPAND(pw->pw_shell); 292 1.76 christos if (version == 0) { 293 1.76 christos int32_t tmp; 294 1.76 christos SCALAR(tmp); 295 1.76 christos pw->pw_expire = tmp; 296 1.76 christos } else 297 1.76 christos SCALAR(pw->pw_expire); 298 1.57 lukem if (pwflags) { 299 1.57 lukem /* See if there's any data left. If so, read in flags. */ 300 1.57 lukem if (data.size > (size_t) (p - (char *)data.data)) { 301 1.57 lukem SCALAR(*pwflags); 302 1.57 lukem } else { /* default */ 303 1.57 lukem *pwflags = _PASSWORD_NOUID|_PASSWORD_NOGID; 304 1.57 lukem } 305 1.57 lukem } 306 1.14 phil 307 1.57 lukem return NS_SUCCESS; 308 1.14 phil } 309 1.4 deraadt 310 1.57 lukem /* 311 1.57 lukem * _pw_memfrombuf 312 1.57 lukem * Obtain want bytes from buffer (of size buflen) and return a pointer 313 1.57 lukem * to the available memory after adjusting buffer/buflen. 314 1.57 lukem * Returns NULL if there is insufficient space. 315 1.57 lukem */ 316 1.57 lukem static char * 317 1.57 lukem _pw_memfrombuf(size_t want, char **buffer, size_t *buflen) 318 1.26 lukem { 319 1.57 lukem char *rv; 320 1.26 lukem 321 1.57 lukem if (want > *buflen) { 322 1.57 lukem errno = ERANGE; 323 1.57 lukem return NULL; 324 1.57 lukem } 325 1.57 lukem rv = *buffer; 326 1.57 lukem *buffer += want; 327 1.57 lukem *buflen -= want; 328 1.57 lukem return rv; 329 1.26 lukem } 330 1.26 lukem 331 1.32 lukem /* 332 1.57 lukem * _pw_copy 333 1.57 lukem * Copy the contents of frompw to pw; memory for strings 334 1.57 lukem * and arrays will be allocated from buf (of size buflen). 335 1.57 lukem * If proto != NULL, use various fields in proto in preference to frompw. 336 1.57 lukem * Returns 1 if copied successfully, 0 on copy failure. 337 1.57 lukem * NOTE: frompw must not use buf for its own pointers. 338 1.32 lukem */ 339 1.26 lukem static int 340 1.57 lukem _pw_copy(const struct passwd *frompw, struct passwd *pw, 341 1.57 lukem char *buf, size_t buflen, const struct passwd *protopw, int protoflags) 342 1.4 deraadt { 343 1.57 lukem size_t count; 344 1.57 lukem int useproto; 345 1.4 deraadt 346 1.57 lukem _DIAGASSERT(frompw != NULL); 347 1.45 lukem _DIAGASSERT(pw != NULL); 348 1.57 lukem _DIAGASSERT(buf != NULL); 349 1.57 lukem /* protopw may be NULL */ 350 1.45 lukem 351 1.57 lukem useproto = protopw && protopw->pw_name; 352 1.57 lukem 353 1.57 lukem #define COPYSTR(to, from) \ 354 1.57 lukem do { \ 355 1.57 lukem count = strlen((from)); \ 356 1.57 lukem (to) = _pw_memfrombuf(count+1, &buf, &buflen); \ 357 1.57 lukem if ((to) == NULL) \ 358 1.57 lukem return 0; \ 359 1.57 lukem memmove((to), (from), count); \ 360 1.57 lukem to[count] = '\0'; \ 361 1.57 lukem } while (0) /* LINTED */ 362 1.57 lukem 363 1.57 lukem #define COPYFIELD(field) COPYSTR(pw->field, frompw->field) 364 1.57 lukem 365 1.57 lukem #define COPYPROTOFIELD(field) COPYSTR(pw->field, \ 366 1.57 lukem (useproto && *protopw->field ? protopw->field : frompw->field)) 367 1.57 lukem 368 1.57 lukem COPYFIELD(pw_name); 369 1.14 phil 370 1.32 lukem #ifdef PW_OVERRIDE_PASSWD 371 1.57 lukem COPYPROTOFIELD(pw_passwd); 372 1.57 lukem #else 373 1.57 lukem COPYFIELD(pw_passwd); 374 1.14 phil #endif 375 1.26 lukem 376 1.57 lukem if (useproto && !(protoflags & _PASSWORD_NOUID)) 377 1.57 lukem pw->pw_uid = protopw->pw_uid; 378 1.57 lukem else 379 1.57 lukem pw->pw_uid = frompw->pw_uid; 380 1.57 lukem 381 1.57 lukem if (useproto && !(protoflags & _PASSWORD_NOGID)) 382 1.57 lukem pw->pw_gid = protopw->pw_gid; 383 1.57 lukem else 384 1.57 lukem pw->pw_gid = frompw->pw_gid; 385 1.57 lukem 386 1.57 lukem pw->pw_change = frompw->pw_change; 387 1.57 lukem COPYFIELD(pw_class); 388 1.57 lukem COPYPROTOFIELD(pw_gecos); 389 1.57 lukem COPYPROTOFIELD(pw_dir); 390 1.57 lukem COPYPROTOFIELD(pw_shell); 391 1.57 lukem 392 1.57 lukem #undef COPYSTR 393 1.57 lukem #undef COPYFIELD 394 1.57 lukem #undef COPYPROTOFIELD 395 1.57 lukem 396 1.57 lukem return 1; 397 1.4 deraadt } 398 1.32 lukem 399 1.4 deraadt 400 1.57 lukem /* 401 1.57 lukem * files methods 402 1.57 lukem */ 403 1.57 lukem 404 1.57 lukem /* state shared between files methods */ 405 1.57 lukem struct files_state { 406 1.57 lukem int stayopen; /* see getpassent(3) */ 407 1.57 lukem DB *db; /* passwd file handle */ 408 1.57 lukem int keynum; /* key counter, -1 if no more */ 409 1.76 christos int version; 410 1.57 lukem }; 411 1.57 lukem 412 1.57 lukem static struct files_state _files_state; 413 1.57 lukem /* storage for non _r functions */ 414 1.57 lukem static struct passwd _files_passwd; 415 1.64 lukem static char _files_passwdbuf[_GETPW_R_SIZE_MAX]; 416 1.57 lukem 417 1.32 lukem static int 418 1.57 lukem _files_start(struct files_state *state) 419 1.1 cgd { 420 1.57 lukem int rv; 421 1.57 lukem 422 1.57 lukem _DIAGASSERT(state != NULL); 423 1.57 lukem 424 1.57 lukem state->keynum = 0; 425 1.76 christos rv = _pw_opendb(&state->db, &state->version); 426 1.57 lukem if (rv != NS_SUCCESS) 427 1.57 lukem return rv; 428 1.57 lukem return NS_SUCCESS; 429 1.57 lukem } 430 1.1 cgd 431 1.57 lukem static int 432 1.57 lukem _files_end(struct files_state *state) 433 1.57 lukem { 434 1.32 lukem 435 1.57 lukem _DIAGASSERT(state != NULL); 436 1.32 lukem 437 1.57 lukem state->keynum = 0; 438 1.57 lukem if (state->db) { 439 1.57 lukem (void)(state->db->close)(state->db); 440 1.57 lukem state->db = NULL; 441 1.32 lukem } 442 1.57 lukem return NS_SUCCESS; 443 1.32 lukem } 444 1.32 lukem 445 1.32 lukem /* 446 1.57 lukem * _files_pwscan 447 1.57 lukem * Search state->db for the next desired entry. 448 1.57 lukem * If search is _PW_KEYBYNUM, look for state->keynum. 449 1.57 lukem * If search is _PW_KEYBYNAME, look for name. 450 1.57 lukem * If search is _PW_KEYBYUID, look for uid. 451 1.68 lukem * Sets *retval to the errno if the result is not NS_SUCCESS 452 1.68 lukem * or NS_NOTFOUND. 453 1.32 lukem */ 454 1.32 lukem static int 455 1.57 lukem _files_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen, 456 1.57 lukem struct files_state *state, int search, const char *name, uid_t uid) 457 1.32 lukem { 458 1.57 lukem const void *from; 459 1.57 lukem size_t fromlen; 460 1.57 lukem DBT key; 461 1.57 lukem int rv; 462 1.39 lukem 463 1.57 lukem _DIAGASSERT(retval != NULL); 464 1.57 lukem _DIAGASSERT(pw != NULL); 465 1.57 lukem _DIAGASSERT(buffer != NULL); 466 1.57 lukem _DIAGASSERT(state != NULL); 467 1.57 lukem /* name is NULL to indicate searching for uid */ 468 1.57 lukem 469 1.57 lukem *retval = 0; 470 1.57 lukem 471 1.57 lukem if (state->db == NULL) { /* only start if file not open yet */ 472 1.57 lukem rv = _files_start(state); 473 1.57 lukem if (rv != NS_SUCCESS) 474 1.57 lukem goto filespwscan_out; 475 1.57 lukem } 476 1.57 lukem 477 1.57 lukem for (;;) { /* search for a match */ 478 1.57 lukem switch (search) { 479 1.57 lukem case _PW_KEYBYNUM: 480 1.57 lukem if (state->keynum == -1) 481 1.57 lukem return NS_NOTFOUND; /* no more records */ 482 1.57 lukem state->keynum++; 483 1.57 lukem from = &state->keynum; 484 1.57 lukem fromlen = sizeof(state->keynum); 485 1.57 lukem break; 486 1.57 lukem case _PW_KEYBYNAME: 487 1.57 lukem from = name; 488 1.57 lukem fromlen = strlen(name); 489 1.57 lukem break; 490 1.57 lukem case _PW_KEYBYUID: 491 1.57 lukem from = &uid; 492 1.57 lukem fromlen = sizeof(uid); 493 1.57 lukem break; 494 1.57 lukem default: 495 1.57 lukem abort(); 496 1.57 lukem } 497 1.32 lukem 498 1.57 lukem if (buflen <= fromlen) { /* buffer too small */ 499 1.57 lukem *retval = ERANGE; 500 1.57 lukem return NS_UNAVAIL; 501 1.57 lukem } 502 1.57 lukem buffer[0] = search; /* setup key */ 503 1.57 lukem memmove(buffer + 1, from, fromlen); 504 1.57 lukem key.size = fromlen + 1; 505 1.57 lukem key.data = (u_char *)buffer; 506 1.57 lukem 507 1.57 lukem /* search for key */ 508 1.76 christos rv = _pw_getkey(state->db, &key, pw, buffer, buflen, NULL, 509 1.76 christos state->version); 510 1.57 lukem if (rv != NS_SUCCESS) /* no match */ 511 1.57 lukem break; 512 1.57 lukem if (pw->pw_name[0] == '+' || pw->pw_name[0] == '-') { 513 1.57 lukem /* if a compat line */ 514 1.57 lukem if (search == _PW_KEYBYNUM) 515 1.57 lukem continue; /* read next if pwent */ 516 1.57 lukem rv = NS_NOTFOUND; /* don't match if pw{nam,uid} */ 517 1.57 lukem break; 518 1.57 lukem } 519 1.32 lukem break; 520 1.32 lukem } 521 1.32 lukem 522 1.57 lukem if (rv == NS_NOTFOUND && search == _PW_KEYBYNUM) 523 1.57 lukem state->keynum = -1; /* flag `no more records' */ 524 1.39 lukem 525 1.57 lukem if (rv == NS_SUCCESS) { 526 1.57 lukem if ((search == _PW_KEYBYUID && pw->pw_uid != uid) || 527 1.57 lukem (search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) != 0)) 528 1.57 lukem rv = NS_NOTFOUND; 529 1.32 lukem } 530 1.32 lukem 531 1.57 lukem filespwscan_out: 532 1.68 lukem if (rv != NS_SUCCESS && rv != NS_NOTFOUND) 533 1.57 lukem *retval = errno; 534 1.57 lukem return rv; 535 1.32 lukem } 536 1.1 cgd 537 1.57 lukem /*ARGSUSED*/ 538 1.57 lukem static int 539 1.57 lukem _files_setpwent(void *nsrv, void *nscb, va_list ap) 540 1.57 lukem { 541 1.57 lukem 542 1.57 lukem _files_state.stayopen = 0; 543 1.57 lukem return _files_start(&_files_state); 544 1.57 lukem } 545 1.14 phil 546 1.37 christos /*ARGSUSED*/ 547 1.32 lukem static int 548 1.57 lukem _files_setpassent(void *nsrv, void *nscb, va_list ap) 549 1.32 lukem { 550 1.57 lukem int *retval = va_arg(ap, int *); 551 1.57 lukem int stayopen = va_arg(ap, int); 552 1.32 lukem 553 1.57 lukem int rv; 554 1.32 lukem 555 1.57 lukem _files_state.stayopen = stayopen; 556 1.57 lukem rv = _files_start(&_files_state); 557 1.57 lukem *retval = (rv == NS_SUCCESS); 558 1.57 lukem return rv; 559 1.57 lukem } 560 1.32 lukem 561 1.57 lukem /*ARGSUSED*/ 562 1.57 lukem static int 563 1.57 lukem _files_endpwent(void *nsrv, void *nscb, va_list ap) 564 1.57 lukem { 565 1.32 lukem 566 1.57 lukem _files_state.stayopen = 0; 567 1.57 lukem return _files_end(&_files_state); 568 1.57 lukem } 569 1.32 lukem 570 1.57 lukem /*ARGSUSED*/ 571 1.32 lukem static int 572 1.57 lukem _files_getpwent(void *nsrv, void *nscb, va_list ap) 573 1.32 lukem { 574 1.57 lukem struct passwd **retval = va_arg(ap, struct passwd **); 575 1.32 lukem 576 1.57 lukem int rv, rerror; 577 1.32 lukem 578 1.57 lukem _DIAGASSERT(retval != NULL); 579 1.32 lukem 580 1.57 lukem *retval = NULL; 581 1.57 lukem rv = _files_pwscan(&rerror, &_files_passwd, 582 1.57 lukem _files_passwdbuf, sizeof(_files_passwdbuf), 583 1.57 lukem &_files_state, _PW_KEYBYNUM, NULL, 0); 584 1.57 lukem if (rv == NS_SUCCESS) 585 1.57 lukem *retval = &_files_passwd; 586 1.57 lukem return rv; 587 1.32 lukem } 588 1.32 lukem 589 1.37 christos /*ARGSUSED*/ 590 1.32 lukem static int 591 1.67 christos _files_getpwent_r(void *nsrv, void *nscb, va_list ap) 592 1.67 christos { 593 1.67 christos int *retval = va_arg(ap, int *); 594 1.67 christos struct passwd *pw = va_arg(ap, struct passwd *); 595 1.67 christos char *buffer = va_arg(ap, char *); 596 1.67 christos size_t buflen = va_arg(ap, size_t); 597 1.67 christos struct passwd **result = va_arg(ap, struct passwd **); 598 1.67 christos 599 1.67 christos int rv; 600 1.67 christos 601 1.67 christos _DIAGASSERT(retval != NULL); 602 1.67 christos _DIAGASSERT(pw != NULL); 603 1.67 christos _DIAGASSERT(buffer != NULL); 604 1.67 christos _DIAGASSERT(result != NULL); 605 1.67 christos 606 1.67 christos rv = _files_pwscan(retval, pw, buffer, buflen, &_files_state, 607 1.67 christos _PW_KEYBYNUM, NULL, 0); 608 1.67 christos if (rv == NS_SUCCESS) 609 1.67 christos *result = pw; 610 1.67 christos else 611 1.67 christos *result = NULL; 612 1.67 christos return rv; 613 1.67 christos } 614 1.67 christos 615 1.67 christos /*ARGSUSED*/ 616 1.67 christos static int 617 1.57 lukem _files_getpwnam(void *nsrv, void *nscb, va_list ap) 618 1.32 lukem { 619 1.57 lukem struct passwd **retval = va_arg(ap, struct passwd **); 620 1.57 lukem const char *name = va_arg(ap, const char *); 621 1.57 lukem 622 1.57 lukem int rv, rerror; 623 1.45 lukem 624 1.57 lukem _DIAGASSERT(retval != NULL); 625 1.45 lukem 626 1.57 lukem *retval = NULL; 627 1.57 lukem rv = _files_start(&_files_state); 628 1.57 lukem if (rv != NS_SUCCESS) 629 1.57 lukem return rv; 630 1.57 lukem rv = _files_pwscan(&rerror, &_files_passwd, 631 1.57 lukem _files_passwdbuf, sizeof(_files_passwdbuf), 632 1.57 lukem &_files_state, _PW_KEYBYNAME, name, 0); 633 1.57 lukem if (!_files_state.stayopen) 634 1.57 lukem _files_end(&_files_state); 635 1.57 lukem if (rv == NS_SUCCESS) 636 1.57 lukem *retval = &_files_passwd; 637 1.57 lukem return rv; 638 1.32 lukem } 639 1.32 lukem 640 1.57 lukem /*ARGSUSED*/ 641 1.32 lukem static int 642 1.57 lukem _files_getpwnam_r(void *nsrv, void *nscb, va_list ap) 643 1.32 lukem { 644 1.57 lukem int *retval = va_arg(ap, int *); 645 1.57 lukem const char *name = va_arg(ap, const char *); 646 1.57 lukem struct passwd *pw = va_arg(ap, struct passwd *); 647 1.57 lukem char *buffer = va_arg(ap, char *); 648 1.57 lukem size_t buflen = va_arg(ap, size_t); 649 1.57 lukem struct passwd **result = va_arg(ap, struct passwd **); 650 1.57 lukem 651 1.57 lukem struct files_state state; 652 1.57 lukem int rv; 653 1.57 lukem 654 1.57 lukem _DIAGASSERT(retval != NULL); 655 1.57 lukem _DIAGASSERT(pw != NULL); 656 1.57 lukem _DIAGASSERT(buffer != NULL); 657 1.57 lukem _DIAGASSERT(result != NULL); 658 1.32 lukem 659 1.57 lukem *result = NULL; 660 1.57 lukem memset(&state, 0, sizeof(state)); 661 1.57 lukem rv = _files_pwscan(retval, pw, buffer, buflen, &state, 662 1.57 lukem _PW_KEYBYNAME, name, 0); 663 1.57 lukem _files_end(&state); 664 1.57 lukem if (rv == NS_SUCCESS) 665 1.57 lukem *result = pw; 666 1.57 lukem return rv; 667 1.32 lukem } 668 1.32 lukem 669 1.37 christos /*ARGSUSED*/ 670 1.32 lukem static int 671 1.57 lukem _files_getpwuid(void *nsrv, void *nscb, va_list ap) 672 1.32 lukem { 673 1.57 lukem struct passwd **retval = va_arg(ap, struct passwd **); 674 1.57 lukem uid_t uid = va_arg(ap, uid_t); 675 1.32 lukem 676 1.57 lukem int rv, rerror; 677 1.32 lukem 678 1.57 lukem _DIAGASSERT(retval != NULL); 679 1.32 lukem 680 1.57 lukem *retval = NULL; 681 1.57 lukem rv = _files_start(&_files_state); 682 1.57 lukem if (rv != NS_SUCCESS) 683 1.57 lukem return rv; 684 1.57 lukem rv = _files_pwscan(&rerror, &_files_passwd, 685 1.57 lukem _files_passwdbuf, sizeof(_files_passwdbuf), 686 1.57 lukem &_files_state, _PW_KEYBYUID, NULL, uid); 687 1.57 lukem if (!_files_state.stayopen) 688 1.57 lukem _files_end(&_files_state); 689 1.57 lukem if (rv == NS_SUCCESS) 690 1.57 lukem *retval = &_files_passwd; 691 1.57 lukem return rv; 692 1.57 lukem } 693 1.57 lukem 694 1.57 lukem /*ARGSUSED*/ 695 1.57 lukem static int 696 1.57 lukem _files_getpwuid_r(void *nsrv, void *nscb, va_list ap) 697 1.57 lukem { 698 1.57 lukem int *retval = va_arg(ap, int *); 699 1.57 lukem uid_t uid = va_arg(ap, uid_t); 700 1.57 lukem struct passwd *pw = va_arg(ap, struct passwd *); 701 1.57 lukem char *buffer = va_arg(ap, char *); 702 1.57 lukem size_t buflen = va_arg(ap, size_t); 703 1.57 lukem struct passwd **result = va_arg(ap, struct passwd **); 704 1.57 lukem 705 1.57 lukem struct files_state state; 706 1.57 lukem int rv; 707 1.57 lukem 708 1.57 lukem _DIAGASSERT(retval != NULL); 709 1.57 lukem _DIAGASSERT(pw != NULL); 710 1.57 lukem _DIAGASSERT(buffer != NULL); 711 1.57 lukem _DIAGASSERT(result != NULL); 712 1.57 lukem 713 1.57 lukem *result = NULL; 714 1.57 lukem memset(&state, 0, sizeof(state)); 715 1.57 lukem rv = _files_pwscan(retval, pw, buffer, buflen, &state, 716 1.57 lukem _PW_KEYBYUID, NULL, uid); 717 1.57 lukem _files_end(&state); 718 1.57 lukem if (rv == NS_SUCCESS) 719 1.57 lukem *result = pw; 720 1.57 lukem return rv; 721 1.57 lukem } 722 1.57 lukem 723 1.57 lukem 724 1.57 lukem #ifdef HESIOD 725 1.57 lukem /* 726 1.57 lukem * dns methods 727 1.57 lukem */ 728 1.57 lukem 729 1.57 lukem /* state shared between dns methods */ 730 1.57 lukem struct dns_state { 731 1.57 lukem int stayopen; /* see getpassent(3) */ 732 1.57 lukem void *context; /* Hesiod context */ 733 1.57 lukem int num; /* passwd index, -1 if no more */ 734 1.57 lukem }; 735 1.57 lukem 736 1.57 lukem static struct dns_state _dns_state; 737 1.57 lukem /* storage for non _r functions */ 738 1.57 lukem static struct passwd _dns_passwd; 739 1.64 lukem static char _dns_passwdbuf[_GETPW_R_SIZE_MAX]; 740 1.57 lukem 741 1.57 lukem static int 742 1.57 lukem _dns_start(struct dns_state *state) 743 1.57 lukem { 744 1.57 lukem 745 1.57 lukem _DIAGASSERT(state != NULL); 746 1.57 lukem 747 1.57 lukem state->num = 0; 748 1.57 lukem if (state->context == NULL) { /* setup Hesiod */ 749 1.57 lukem if (hesiod_init(&state->context) == -1) 750 1.57 lukem return NS_UNAVAIL; 751 1.57 lukem } 752 1.57 lukem 753 1.57 lukem return NS_SUCCESS; 754 1.57 lukem } 755 1.57 lukem 756 1.57 lukem static int 757 1.57 lukem _dns_end(struct dns_state *state) 758 1.57 lukem { 759 1.57 lukem 760 1.57 lukem _DIAGASSERT(state != NULL); 761 1.57 lukem 762 1.57 lukem state->num = 0; 763 1.57 lukem if (state->context) { 764 1.57 lukem hesiod_end(state->context); 765 1.57 lukem state->context = NULL; 766 1.57 lukem } 767 1.57 lukem return NS_SUCCESS; 768 1.57 lukem } 769 1.57 lukem 770 1.57 lukem /* 771 1.57 lukem * _dns_pwscan 772 1.57 lukem * Look for the Hesiod name provided in buffer in the NULL-terminated 773 1.57 lukem * list of zones, 774 1.57 lukem * and decode into pw/buffer/buflen. 775 1.57 lukem */ 776 1.57 lukem static int 777 1.57 lukem _dns_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen, 778 1.57 lukem struct dns_state *state, const char **zones) 779 1.57 lukem { 780 1.57 lukem const char **curzone; 781 1.57 lukem char **hp, *ep; 782 1.57 lukem int rv; 783 1.57 lukem 784 1.57 lukem _DIAGASSERT(retval != NULL); 785 1.57 lukem _DIAGASSERT(pw != NULL); 786 1.57 lukem _DIAGASSERT(buffer != NULL); 787 1.57 lukem _DIAGASSERT(state != NULL); 788 1.57 lukem _DIAGASSERT(zones != NULL); 789 1.57 lukem 790 1.57 lukem *retval = 0; 791 1.57 lukem 792 1.57 lukem if (state->context == NULL) { /* only start if Hesiod not setup */ 793 1.57 lukem rv = _dns_start(state); 794 1.57 lukem if (rv != NS_SUCCESS) 795 1.57 lukem return rv; 796 1.57 lukem } 797 1.57 lukem 798 1.57 lukem hp = NULL; 799 1.57 lukem rv = NS_NOTFOUND; 800 1.57 lukem 801 1.57 lukem for (curzone = zones; *curzone; curzone++) { /* search zones */ 802 1.57 lukem hp = hesiod_resolve(state->context, buffer, *curzone); 803 1.57 lukem if (hp != NULL) 804 1.14 phil break; 805 1.57 lukem if (errno != ENOENT) { 806 1.57 lukem rv = NS_UNAVAIL; 807 1.57 lukem goto dnspwscan_out; 808 1.57 lukem } 809 1.57 lukem } 810 1.57 lukem if (*curzone == NULL) 811 1.57 lukem goto dnspwscan_out; 812 1.57 lukem 813 1.57 lukem if ((ep = strchr(hp[0], '\n')) != NULL) 814 1.57 lukem *ep = '\0'; /* clear trailing \n */ 815 1.57 lukem if (_pw_parse(hp[0], pw, buffer, buflen, 1)) /* validate line */ 816 1.57 lukem rv = NS_SUCCESS; 817 1.57 lukem else 818 1.57 lukem rv = NS_UNAVAIL; 819 1.57 lukem 820 1.57 lukem dnspwscan_out: 821 1.68 lukem if (rv != NS_SUCCESS && rv != NS_NOTFOUND) 822 1.57 lukem *retval = errno; 823 1.57 lukem if (hp) 824 1.57 lukem hesiod_free_list(state->context, hp); 825 1.57 lukem return rv; 826 1.57 lukem } 827 1.57 lukem 828 1.57 lukem /*ARGSUSED*/ 829 1.57 lukem static int 830 1.57 lukem _dns_setpwent(void *nsrv, void *nscb, va_list ap) 831 1.57 lukem { 832 1.57 lukem 833 1.57 lukem _dns_state.stayopen = 0; 834 1.57 lukem return _dns_start(&_dns_state); 835 1.57 lukem } 836 1.57 lukem 837 1.57 lukem /*ARGSUSED*/ 838 1.57 lukem static int 839 1.57 lukem _dns_setpassent(void *nsrv, void *nscb, va_list ap) 840 1.57 lukem { 841 1.57 lukem int *retval = va_arg(ap, int *); 842 1.57 lukem int stayopen = va_arg(ap, int); 843 1.57 lukem 844 1.57 lukem int rv; 845 1.57 lukem 846 1.57 lukem _dns_state.stayopen = stayopen; 847 1.57 lukem rv = _dns_start(&_dns_state); 848 1.57 lukem *retval = (rv == NS_SUCCESS); 849 1.57 lukem return rv; 850 1.57 lukem } 851 1.57 lukem 852 1.57 lukem /*ARGSUSED*/ 853 1.57 lukem static int 854 1.57 lukem _dns_endpwent(void *nsrv, void *nscb, va_list ap) 855 1.57 lukem { 856 1.57 lukem 857 1.57 lukem _dns_state.stayopen = 0; 858 1.57 lukem return _dns_end(&_dns_state); 859 1.57 lukem } 860 1.57 lukem 861 1.57 lukem /*ARGSUSED*/ 862 1.57 lukem static int 863 1.57 lukem _dns_getpwent(void *nsrv, void *nscb, va_list ap) 864 1.57 lukem { 865 1.57 lukem struct passwd **retval = va_arg(ap, struct passwd **); 866 1.57 lukem 867 1.57 lukem char **hp, *ep; 868 1.57 lukem int rv; 869 1.57 lukem 870 1.57 lukem _DIAGASSERT(retval != NULL); 871 1.57 lukem 872 1.57 lukem *retval = NULL; 873 1.57 lukem 874 1.57 lukem if (_dns_state.num == -1) /* exhausted search */ 875 1.57 lukem return NS_NOTFOUND; 876 1.57 lukem 877 1.57 lukem if (_dns_state.context == NULL) { 878 1.57 lukem /* only start if Hesiod not setup */ 879 1.57 lukem rv = _dns_start(&_dns_state); 880 1.57 lukem if (rv != NS_SUCCESS) 881 1.57 lukem return rv; 882 1.57 lukem } 883 1.57 lukem 884 1.66 lukem next_dns_entry: 885 1.57 lukem hp = NULL; 886 1.57 lukem rv = NS_NOTFOUND; 887 1.57 lukem 888 1.57 lukem /* find passwd-NNN */ 889 1.57 lukem snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf), 890 1.57 lukem "passwd-%u", _dns_state.num); 891 1.57 lukem _dns_state.num++; 892 1.57 lukem 893 1.57 lukem hp = hesiod_resolve(_dns_state.context, _dns_passwdbuf, "passwd"); 894 1.57 lukem if (hp == NULL) { 895 1.57 lukem if (errno == ENOENT) 896 1.57 lukem _dns_state.num = -1; 897 1.57 lukem else 898 1.57 lukem rv = NS_UNAVAIL; 899 1.57 lukem } else { 900 1.57 lukem if ((ep = strchr(hp[0], '\n')) != NULL) 901 1.57 lukem *ep = '\0'; /* clear trailing \n */ 902 1.57 lukem /* validate line */ 903 1.57 lukem if (_pw_parse(hp[0], &_dns_passwd, 904 1.57 lukem _dns_passwdbuf, sizeof(_dns_passwdbuf), 1)) 905 1.57 lukem rv = NS_SUCCESS; 906 1.66 lukem else { /* dodgy entry, try again */ 907 1.66 lukem hesiod_free_list(_dns_state.context, hp); 908 1.66 lukem goto next_dns_entry; 909 1.66 lukem } 910 1.57 lukem } 911 1.57 lukem 912 1.57 lukem if (hp) 913 1.57 lukem hesiod_free_list(_dns_state.context, hp); 914 1.57 lukem if (rv == NS_SUCCESS) 915 1.57 lukem *retval = &_dns_passwd; 916 1.57 lukem return rv; 917 1.57 lukem } 918 1.57 lukem 919 1.67 christos /*ARGSUSED*/ 920 1.67 christos static int 921 1.67 christos _dns_getpwent_r(void *nsrv, void *nscb, va_list ap) 922 1.67 christos { 923 1.67 christos int *retval = va_arg(ap, int *); 924 1.67 christos struct passwd *pw = va_arg(ap, struct passwd *); 925 1.67 christos char *buffer = va_arg(ap, char *); 926 1.67 christos size_t buflen = va_arg(ap, size_t); 927 1.67 christos struct passwd **result = va_arg(ap, struct passwd **); 928 1.67 christos 929 1.67 christos char **hp, *ep; 930 1.67 christos int rv; 931 1.67 christos 932 1.67 christos _DIAGASSERT(retval != NULL); 933 1.67 christos _DIAGASSERT(pw != NULL); 934 1.67 christos _DIAGASSERT(buffer != NULL); 935 1.67 christos _DIAGASSERT(result != NULL); 936 1.67 christos 937 1.67 christos *retval = 0; 938 1.67 christos 939 1.67 christos if (_dns_state.num == -1) /* exhausted search */ 940 1.67 christos return NS_NOTFOUND; 941 1.67 christos 942 1.67 christos if (_dns_state.context == NULL) { 943 1.67 christos /* only start if Hesiod not setup */ 944 1.67 christos rv = _dns_start(&_dns_state); 945 1.67 christos if (rv != NS_SUCCESS) 946 1.67 christos return rv; 947 1.67 christos } 948 1.67 christos 949 1.67 christos next_dns_entry: 950 1.67 christos hp = NULL; 951 1.67 christos rv = NS_NOTFOUND; 952 1.67 christos 953 1.67 christos /* find passwd-NNN */ 954 1.67 christos snprintf(buffer, buflen, "passwd-%u", _dns_state.num); 955 1.67 christos _dns_state.num++; 956 1.67 christos 957 1.67 christos hp = hesiod_resolve(_dns_state.context, buffer, "passwd"); 958 1.67 christos if (hp == NULL) { 959 1.67 christos if (errno == ENOENT) 960 1.67 christos _dns_state.num = -1; 961 1.67 christos else 962 1.67 christos rv = NS_UNAVAIL; 963 1.67 christos } else { 964 1.67 christos if ((ep = strchr(hp[0], '\n')) != NULL) 965 1.67 christos *ep = '\0'; /* clear trailing \n */ 966 1.67 christos /* validate line */ 967 1.67 christos if (_pw_parse(hp[0], pw, buffer, buflen, 1)) 968 1.67 christos rv = NS_SUCCESS; 969 1.67 christos else { /* dodgy entry, try again */ 970 1.67 christos hesiod_free_list(_dns_state.context, hp); 971 1.67 christos goto next_dns_entry; 972 1.67 christos } 973 1.67 christos } 974 1.67 christos 975 1.67 christos if (hp) 976 1.67 christos hesiod_free_list(_dns_state.context, hp); 977 1.67 christos if (rv == NS_SUCCESS) 978 1.67 christos *result = pw; 979 1.67 christos else 980 1.67 christos *result = NULL; 981 1.67 christos return rv; 982 1.67 christos } 983 1.67 christos 984 1.57 lukem static const char *_dns_uid_zones[] = { 985 1.57 lukem "uid", 986 1.57 lukem "passwd", 987 1.57 lukem NULL 988 1.57 lukem }; 989 1.57 lukem 990 1.57 lukem /*ARGSUSED*/ 991 1.57 lukem static int 992 1.57 lukem _dns_getpwuid(void *nsrv, void *nscb, va_list ap) 993 1.57 lukem { 994 1.57 lukem struct passwd **retval = va_arg(ap, struct passwd **); 995 1.57 lukem uid_t uid = va_arg(ap, uid_t); 996 1.57 lukem 997 1.57 lukem int rv, rerror; 998 1.57 lukem 999 1.57 lukem _DIAGASSERT(retval != NULL); 1000 1.32 lukem 1001 1.57 lukem *retval = NULL; 1002 1.57 lukem rv = _dns_start(&_dns_state); 1003 1.57 lukem if (rv != NS_SUCCESS) 1004 1.57 lukem return rv; 1005 1.57 lukem snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf), 1006 1.57 lukem "%u", (unsigned int)uid); 1007 1.57 lukem rv = _dns_pwscan(&rerror, &_dns_passwd, 1008 1.57 lukem _dns_passwdbuf, sizeof(_dns_passwdbuf), 1009 1.57 lukem &_dns_state, _dns_uid_zones); 1010 1.57 lukem if (!_dns_state.stayopen) 1011 1.57 lukem _dns_end(&_dns_state); 1012 1.57 lukem if (rv == NS_SUCCESS && uid == _dns_passwd.pw_uid) 1013 1.57 lukem *retval = &_dns_passwd; 1014 1.57 lukem return rv; 1015 1.57 lukem } 1016 1.57 lukem 1017 1.57 lukem /*ARGSUSED*/ 1018 1.57 lukem static int 1019 1.57 lukem _dns_getpwuid_r(void *nsrv, void *nscb, va_list ap) 1020 1.57 lukem { 1021 1.57 lukem int *retval = va_arg(ap, int *); 1022 1.57 lukem uid_t uid = va_arg(ap, uid_t); 1023 1.57 lukem struct passwd *pw = va_arg(ap, struct passwd *); 1024 1.57 lukem char *buffer = va_arg(ap, char *); 1025 1.57 lukem size_t buflen = va_arg(ap, size_t); 1026 1.57 lukem struct passwd **result = va_arg(ap, struct passwd **); 1027 1.57 lukem 1028 1.57 lukem struct dns_state state; 1029 1.57 lukem int rv; 1030 1.57 lukem 1031 1.57 lukem _DIAGASSERT(retval != NULL); 1032 1.57 lukem _DIAGASSERT(pw != NULL); 1033 1.57 lukem _DIAGASSERT(buffer != NULL); 1034 1.57 lukem _DIAGASSERT(result != NULL); 1035 1.57 lukem 1036 1.57 lukem *result = NULL; 1037 1.57 lukem memset(&state, 0, sizeof(state)); 1038 1.57 lukem snprintf(buffer, buflen, "%u", (unsigned int)uid); 1039 1.57 lukem rv = _dns_pwscan(retval, pw, buffer, buflen, &state, _dns_uid_zones); 1040 1.57 lukem _dns_end(&state); 1041 1.57 lukem if (rv != NS_SUCCESS) 1042 1.57 lukem return rv; 1043 1.57 lukem if (uid == pw->pw_uid) { 1044 1.57 lukem *result = pw; 1045 1.57 lukem return NS_SUCCESS; 1046 1.57 lukem } else 1047 1.57 lukem return NS_NOTFOUND; 1048 1.57 lukem } 1049 1.57 lukem 1050 1.57 lukem static const char *_dns_nam_zones[] = { 1051 1.57 lukem "passwd", 1052 1.57 lukem NULL 1053 1.57 lukem }; 1054 1.57 lukem 1055 1.57 lukem /*ARGSUSED*/ 1056 1.57 lukem static int 1057 1.57 lukem _dns_getpwnam(void *nsrv, void *nscb, va_list ap) 1058 1.57 lukem { 1059 1.57 lukem struct passwd **retval = va_arg(ap, struct passwd **); 1060 1.57 lukem const char *name = va_arg(ap, const char *); 1061 1.57 lukem 1062 1.57 lukem int rv, rerror; 1063 1.57 lukem 1064 1.57 lukem _DIAGASSERT(retval != NULL); 1065 1.57 lukem 1066 1.57 lukem *retval = NULL; 1067 1.57 lukem rv = _dns_start(&_dns_state); 1068 1.57 lukem if (rv != NS_SUCCESS) 1069 1.57 lukem return rv; 1070 1.57 lukem snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf), "%s", name); 1071 1.57 lukem rv = _dns_pwscan(&rerror, &_dns_passwd, 1072 1.57 lukem _dns_passwdbuf, sizeof(_dns_passwdbuf), 1073 1.57 lukem &_dns_state, _dns_nam_zones); 1074 1.57 lukem if (!_dns_state.stayopen) 1075 1.57 lukem _dns_end(&_dns_state); 1076 1.57 lukem if (rv == NS_SUCCESS && strcmp(name, _dns_passwd.pw_name) == 0) 1077 1.57 lukem *retval = &_dns_passwd; 1078 1.57 lukem return rv; 1079 1.57 lukem } 1080 1.57 lukem 1081 1.57 lukem /*ARGSUSED*/ 1082 1.57 lukem static int 1083 1.57 lukem _dns_getpwnam_r(void *nsrv, void *nscb, va_list ap) 1084 1.57 lukem { 1085 1.57 lukem int *retval = va_arg(ap, int *); 1086 1.57 lukem const char *name = va_arg(ap, const char *); 1087 1.57 lukem struct passwd *pw = va_arg(ap, struct passwd *); 1088 1.57 lukem char *buffer = va_arg(ap, char *); 1089 1.57 lukem size_t buflen = va_arg(ap, size_t); 1090 1.57 lukem struct passwd **result = va_arg(ap, struct passwd **); 1091 1.57 lukem 1092 1.57 lukem struct dns_state state; 1093 1.57 lukem int rv; 1094 1.57 lukem 1095 1.57 lukem _DIAGASSERT(retval != NULL); 1096 1.57 lukem _DIAGASSERT(pw != NULL); 1097 1.57 lukem _DIAGASSERT(buffer != NULL); 1098 1.57 lukem _DIAGASSERT(result != NULL); 1099 1.57 lukem 1100 1.57 lukem *result = NULL; 1101 1.57 lukem memset(&state, 0, sizeof(state)); 1102 1.57 lukem snprintf(buffer, buflen, "%s", name); 1103 1.57 lukem rv = _dns_pwscan(retval, pw, buffer, buflen, &state, _dns_nam_zones); 1104 1.57 lukem _dns_end(&state); 1105 1.57 lukem if (rv != NS_SUCCESS) 1106 1.57 lukem return rv; 1107 1.57 lukem if (strcmp(name, pw->pw_name) == 0) { 1108 1.57 lukem *result = pw; 1109 1.57 lukem return NS_SUCCESS; 1110 1.57 lukem } else 1111 1.57 lukem return NS_NOTFOUND; 1112 1.57 lukem } 1113 1.57 lukem 1114 1.57 lukem #endif /* HESIOD */ 1115 1.57 lukem 1116 1.57 lukem 1117 1.57 lukem #ifdef YP 1118 1.57 lukem /* 1119 1.57 lukem * nis methods 1120 1.57 lukem */ 1121 1.57 lukem /* state shared between nis methods */ 1122 1.57 lukem struct nis_state { 1123 1.57 lukem int stayopen; /* see getpassent(3) */ 1124 1.57 lukem char *domain; /* NIS domain */ 1125 1.57 lukem int done; /* non-zero if search exhausted */ 1126 1.57 lukem char *current; /* current first/next match */ 1127 1.57 lukem int currentlen; /* length of _nis_current */ 1128 1.57 lukem enum { /* shadow map type */ 1129 1.78 christos NISMAP_UNKNOWN = 0, /* unknown ... */ 1130 1.57 lukem NISMAP_NONE, /* none: use "passwd.by*" */ 1131 1.57 lukem NISMAP_ADJUNCT, /* pw_passwd from "passwd.adjunct.*" */ 1132 1.57 lukem NISMAP_MASTER /* all from "master.passwd.by*" */ 1133 1.57 lukem } maptype; 1134 1.57 lukem }; 1135 1.57 lukem 1136 1.57 lukem static struct nis_state _nis_state; 1137 1.57 lukem /* storage for non _r functions */ 1138 1.57 lukem static struct passwd _nis_passwd; 1139 1.64 lukem static char _nis_passwdbuf[_GETPW_R_SIZE_MAX]; 1140 1.57 lukem 1141 1.78 christos static const char __nis_pw_n_1[] = "master.passwd.byname"; 1142 1.78 christos static const char __nis_pw_n_2[] = "passwd.byname"; 1143 1.78 christos static const char __nis_pw_u_1[] = "master.passwd.byuid"; 1144 1.78 christos static const char __nis_pw_u_2[] = "passwd.byuid"; 1145 1.78 christos 1146 1.78 christos static const char * const __nis_pw_n_map[4] = { __nis_pw_n_2, __nis_pw_n_2, __nis_pw_n_2, __nis_pw_n_1 }; 1147 1.78 christos static const char * const __nis_pw_u_map[4] = { __nis_pw_u_2, __nis_pw_u_2, __nis_pw_u_2, __nis_pw_u_1 }; 1148 1.78 christos 1149 1.57 lukem /* macros for deciding which NIS maps to use. */ 1150 1.78 christos #define PASSWD_BYNAME(x) ((x)->maptype == NISMAP_MASTER ? __nis_pw_n_1 : __nis_pw_n_2) 1151 1.78 christos #define PASSWD_BYUID(x) ((x)->maptype == NISMAP_MASTER ? __nis_pw_u_1 : __nis_pw_u_2) 1152 1.57 lukem 1153 1.57 lukem static int 1154 1.57 lukem _nis_start(struct nis_state *state) 1155 1.57 lukem { 1156 1.57 lukem 1157 1.57 lukem _DIAGASSERT(state != NULL); 1158 1.57 lukem 1159 1.57 lukem state->done = 0; 1160 1.57 lukem if (state->current) { 1161 1.57 lukem free(state->current); 1162 1.57 lukem state->current = NULL; 1163 1.57 lukem } 1164 1.57 lukem if (state->domain == NULL) { /* setup NIS */ 1165 1.57 lukem switch (yp_get_default_domain(&state->domain)) { 1166 1.57 lukem case 0: 1167 1.14 phil break; 1168 1.57 lukem case YPERR_RESRC: 1169 1.57 lukem return NS_TRYAGAIN; 1170 1.57 lukem default: 1171 1.57 lukem return NS_UNAVAIL; 1172 1.57 lukem } 1173 1.57 lukem } 1174 1.57 lukem 1175 1.57 lukem /* determine where to get pw_passwd from */ 1176 1.57 lukem if (state->maptype == NISMAP_UNKNOWN) { 1177 1.57 lukem int r, order; 1178 1.32 lukem 1179 1.57 lukem state->maptype = NISMAP_NONE; /* default to no adjunct */ 1180 1.57 lukem if (geteuid() != 0) /* non-root can't use adjunct */ 1181 1.57 lukem return NS_SUCCESS; 1182 1.57 lukem 1183 1.57 lukem /* look for "master.passwd.*" */ 1184 1.57 lukem r = yp_order(state->domain, "master.passwd.byname", &order); 1185 1.57 lukem if (r == 0) { 1186 1.57 lukem state->maptype = NISMAP_MASTER; 1187 1.57 lukem return NS_SUCCESS; 1188 1.57 lukem } 1189 1.57 lukem 1190 1.57 lukem /* master.passwd doesn't exist, try passwd.adjunct */ 1191 1.57 lukem if (r == YPERR_MAP) { 1192 1.57 lukem r = yp_order(state->domain, "passwd.adjunct.byname", 1193 1.57 lukem &order); 1194 1.57 lukem if (r == 0) 1195 1.57 lukem state->maptype = NISMAP_ADJUNCT; 1196 1.57 lukem } 1197 1.57 lukem } 1198 1.57 lukem return NS_SUCCESS; 1199 1.57 lukem } 1200 1.57 lukem 1201 1.57 lukem static int 1202 1.57 lukem _nis_end(struct nis_state *state) 1203 1.57 lukem { 1204 1.57 lukem 1205 1.57 lukem _DIAGASSERT(state != NULL); 1206 1.57 lukem 1207 1.57 lukem if (state->domain) 1208 1.57 lukem state->domain = NULL; 1209 1.57 lukem state->done = 0; 1210 1.57 lukem if (state->current) 1211 1.57 lukem free(state->current); 1212 1.57 lukem state->current = NULL; 1213 1.57 lukem state->maptype = NISMAP_UNKNOWN; 1214 1.57 lukem return NS_SUCCESS; 1215 1.57 lukem } 1216 1.57 lukem 1217 1.57 lukem /* 1218 1.57 lukem * nis_parse 1219 1.57 lukem * wrapper to _pw_parse that obtains the real password from the 1220 1.57 lukem * "passwd.adjunct.byname" NIS map if the maptype is NISMAP_ADJUNCT. 1221 1.57 lukem */ 1222 1.57 lukem static int 1223 1.57 lukem _nis_parse(const char *entry, struct passwd *pw, char *buf, size_t buflen, 1224 1.57 lukem struct nis_state *state) 1225 1.57 lukem { 1226 1.57 lukem size_t elen; 1227 1.57 lukem 1228 1.57 lukem _DIAGASSERT(entry != NULL); 1229 1.57 lukem _DIAGASSERT(pw != NULL); 1230 1.57 lukem _DIAGASSERT(buf != NULL); 1231 1.57 lukem _DIAGASSERT(state != NULL); 1232 1.57 lukem 1233 1.79 christos elen = strlen(entry) + 1; 1234 1.57 lukem if (elen >= buflen) 1235 1.57 lukem return 0; 1236 1.57 lukem if (! _pw_parse(entry, pw, buf, buflen, 1237 1.57 lukem !(state->maptype == NISMAP_MASTER))) 1238 1.57 lukem return 0; 1239 1.57 lukem 1240 1.57 lukem if ((state->maptype == NISMAP_ADJUNCT) && 1241 1.57 lukem (strstr(pw->pw_passwd, "##") != NULL)) { 1242 1.57 lukem char *data; 1243 1.57 lukem int datalen; 1244 1.57 lukem 1245 1.57 lukem if (yp_match(state->domain, "passwd.adjunct.byname", 1246 1.57 lukem pw->pw_name, (int)strlen(pw->pw_name), 1247 1.57 lukem &data, &datalen) == 0) { 1248 1.57 lukem char *bp, *ep; 1249 1.57 lukem /* skip name to get password */ 1250 1.57 lukem ep = data; 1251 1.79 christos if (strsep(&ep, ":") != NULL && 1252 1.57 lukem (bp = strsep(&ep, ":")) != NULL) { 1253 1.57 lukem /* store new pw_passwd after entry */ 1254 1.79 christos if (strlcpy(buf + elen, bp, buflen - elen) >= 1255 1.79 christos buflen - elen) { 1256 1.79 christos free(data); 1257 1.79 christos return 0; 1258 1.79 christos } 1259 1.57 lukem pw->pw_passwd = &buf[elen]; 1260 1.4 deraadt } 1261 1.57 lukem free(data); 1262 1.57 lukem } 1263 1.57 lukem } 1264 1.57 lukem 1265 1.57 lukem return 1; 1266 1.57 lukem } 1267 1.57 lukem 1268 1.57 lukem 1269 1.57 lukem /* 1270 1.57 lukem * _nis_pwscan 1271 1.57 lukem * Look for the yp key provided in buffer from map, 1272 1.57 lukem * and decode into pw/buffer/buflen. 1273 1.57 lukem */ 1274 1.57 lukem static int 1275 1.57 lukem _nis_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen, 1276 1.81 dholland struct nis_state *state, const char * const *map_arr, size_t nmaps) 1277 1.57 lukem { 1278 1.57 lukem char *data; 1279 1.57 lukem int nisr, rv, datalen; 1280 1.57 lukem 1281 1.57 lukem _DIAGASSERT(retval != NULL); 1282 1.57 lukem _DIAGASSERT(pw != NULL); 1283 1.57 lukem _DIAGASSERT(buffer != NULL); 1284 1.57 lukem _DIAGASSERT(state != NULL); 1285 1.78 christos _DIAGASSERT(map_arr != NULL); 1286 1.57 lukem 1287 1.57 lukem *retval = 0; 1288 1.57 lukem 1289 1.57 lukem if (state->domain == NULL) { /* only start if NIS not setup */ 1290 1.57 lukem rv = _nis_start(state); 1291 1.57 lukem if (rv != NS_SUCCESS) 1292 1.57 lukem return rv; 1293 1.57 lukem } 1294 1.57 lukem 1295 1.57 lukem data = NULL; 1296 1.57 lukem rv = NS_NOTFOUND; 1297 1.81 dholland _DIAGASSERT(state->maptype != NISMAP_UNKNOWN && 1298 1.81 dholland (unsigned)state->maptype < nmaps); 1299 1.57 lukem 1300 1.57 lukem /* search map */ 1301 1.78 christos nisr = yp_match(state->domain, map_arr[state->maptype], buffer, (int)strlen(buffer), 1302 1.57 lukem &data, &datalen); 1303 1.57 lukem switch (nisr) { 1304 1.57 lukem case 0: 1305 1.57 lukem data[datalen] = '\0'; /* clear trailing \n */ 1306 1.57 lukem if (_nis_parse(data, pw, buffer, buflen, state)) 1307 1.57 lukem rv = NS_SUCCESS; /* validate line */ 1308 1.57 lukem else 1309 1.57 lukem rv = NS_UNAVAIL; 1310 1.57 lukem break; 1311 1.57 lukem case YPERR_KEY: 1312 1.57 lukem break; 1313 1.57 lukem default: 1314 1.57 lukem rv = NS_UNAVAIL; 1315 1.57 lukem break; 1316 1.57 lukem } 1317 1.57 lukem 1318 1.68 lukem if (rv != NS_SUCCESS && rv != NS_NOTFOUND) 1319 1.57 lukem *retval = errno; 1320 1.57 lukem if (data) 1321 1.57 lukem free(data); 1322 1.57 lukem return rv; 1323 1.57 lukem } 1324 1.57 lukem 1325 1.57 lukem /*ARGSUSED*/ 1326 1.57 lukem static int 1327 1.57 lukem _nis_setpwent(void *nsrv, void *nscb, va_list ap) 1328 1.57 lukem { 1329 1.57 lukem 1330 1.57 lukem _nis_state.stayopen = 0; 1331 1.57 lukem return _nis_start(&_nis_state); 1332 1.57 lukem } 1333 1.57 lukem 1334 1.57 lukem /*ARGSUSED*/ 1335 1.57 lukem static int 1336 1.57 lukem _nis_setpassent(void *nsrv, void *nscb, va_list ap) 1337 1.57 lukem { 1338 1.57 lukem int *retval = va_arg(ap, int *); 1339 1.57 lukem int stayopen = va_arg(ap, int); 1340 1.57 lukem 1341 1.57 lukem int rv; 1342 1.57 lukem 1343 1.57 lukem _nis_state.stayopen = stayopen; 1344 1.57 lukem rv = _nis_start(&_nis_state); 1345 1.57 lukem *retval = (rv == NS_SUCCESS); 1346 1.57 lukem return rv; 1347 1.57 lukem } 1348 1.57 lukem 1349 1.57 lukem /*ARGSUSED*/ 1350 1.57 lukem static int 1351 1.57 lukem _nis_endpwent(void *nsrv, void *nscb, va_list ap) 1352 1.57 lukem { 1353 1.57 lukem 1354 1.57 lukem return _nis_end(&_nis_state); 1355 1.57 lukem } 1356 1.57 lukem 1357 1.57 lukem 1358 1.57 lukem /*ARGSUSED*/ 1359 1.57 lukem static int 1360 1.57 lukem _nis_getpwent(void *nsrv, void *nscb, va_list ap) 1361 1.57 lukem { 1362 1.57 lukem struct passwd **retval = va_arg(ap, struct passwd **); 1363 1.57 lukem 1364 1.57 lukem char *key, *data; 1365 1.57 lukem int keylen, datalen, rv, nisr; 1366 1.57 lukem 1367 1.57 lukem _DIAGASSERT(retval != NULL); 1368 1.57 lukem 1369 1.57 lukem *retval = NULL; 1370 1.57 lukem 1371 1.57 lukem if (_nis_state.done) /* exhausted search */ 1372 1.57 lukem return NS_NOTFOUND; 1373 1.57 lukem if (_nis_state.domain == NULL) { 1374 1.57 lukem /* only start if NIS not setup */ 1375 1.57 lukem rv = _nis_start(&_nis_state); 1376 1.57 lukem if (rv != NS_SUCCESS) 1377 1.57 lukem return rv; 1378 1.57 lukem } 1379 1.57 lukem 1380 1.66 lukem next_nis_entry: 1381 1.57 lukem key = NULL; 1382 1.57 lukem data = NULL; 1383 1.57 lukem rv = NS_NOTFOUND; 1384 1.57 lukem 1385 1.57 lukem if (_nis_state.current) { /* already searching */ 1386 1.58 lukem nisr = yp_next(_nis_state.domain, PASSWD_BYNAME(&_nis_state), 1387 1.57 lukem _nis_state.current, _nis_state.currentlen, 1388 1.57 lukem &key, &keylen, &data, &datalen); 1389 1.57 lukem free(_nis_state.current); 1390 1.57 lukem _nis_state.current = NULL; 1391 1.57 lukem switch (nisr) { 1392 1.57 lukem case 0: 1393 1.57 lukem _nis_state.current = key; 1394 1.57 lukem _nis_state.currentlen = keylen; 1395 1.57 lukem key = NULL; 1396 1.14 phil break; 1397 1.57 lukem case YPERR_NOMORE: 1398 1.57 lukem _nis_state.done = 1; 1399 1.57 lukem goto nisent_out; 1400 1.57 lukem default: 1401 1.57 lukem rv = NS_UNAVAIL; 1402 1.57 lukem goto nisent_out; 1403 1.57 lukem } 1404 1.57 lukem } else { /* new search */ 1405 1.58 lukem if (yp_first(_nis_state.domain, PASSWD_BYNAME(&_nis_state), 1406 1.57 lukem &_nis_state.current, &_nis_state.currentlen, 1407 1.57 lukem &data, &datalen)) { 1408 1.57 lukem rv = NS_UNAVAIL; 1409 1.57 lukem goto nisent_out; 1410 1.4 deraadt } 1411 1.4 deraadt } 1412 1.4 deraadt 1413 1.57 lukem data[datalen] = '\0'; /* clear trailing \n */ 1414 1.57 lukem /* validate line */ 1415 1.57 lukem if (_nis_parse(data, &_nis_passwd, 1416 1.57 lukem _nis_passwdbuf, sizeof(_nis_passwdbuf), &_nis_state)) 1417 1.57 lukem rv = NS_SUCCESS; 1418 1.66 lukem else { /* dodgy entry, try again */ 1419 1.66 lukem free(data); 1420 1.66 lukem goto next_nis_entry; 1421 1.66 lukem } 1422 1.57 lukem 1423 1.57 lukem nisent_out: 1424 1.57 lukem if (key) 1425 1.57 lukem free(key); 1426 1.57 lukem if (data) 1427 1.57 lukem free(data); 1428 1.57 lukem if (rv == NS_SUCCESS) 1429 1.57 lukem *retval = &_nis_passwd; 1430 1.57 lukem return rv; 1431 1.57 lukem } 1432 1.57 lukem 1433 1.57 lukem /*ARGSUSED*/ 1434 1.57 lukem static int 1435 1.67 christos _nis_getpwent_r(void *nsrv, void *nscb, va_list ap) 1436 1.67 christos { 1437 1.67 christos int *retval = va_arg(ap, int *); 1438 1.67 christos struct passwd *pw = va_arg(ap, struct passwd *); 1439 1.67 christos char *buffer = va_arg(ap, char *); 1440 1.67 christos size_t buflen = va_arg(ap, size_t); 1441 1.67 christos struct passwd **result = va_arg(ap, struct passwd **); 1442 1.67 christos 1443 1.67 christos char *key, *data; 1444 1.67 christos int keylen, datalen, rv, nisr; 1445 1.67 christos 1446 1.67 christos _DIAGASSERT(retval != NULL); 1447 1.67 christos _DIAGASSERT(pw != NULL); 1448 1.67 christos _DIAGASSERT(buffer != NULL); 1449 1.67 christos _DIAGASSERT(result != NULL); 1450 1.67 christos 1451 1.67 christos *retval = 0; 1452 1.67 christos 1453 1.67 christos if (_nis_state.done) /* exhausted search */ 1454 1.67 christos return NS_NOTFOUND; 1455 1.67 christos if (_nis_state.domain == NULL) { 1456 1.67 christos /* only start if NIS not setup */ 1457 1.67 christos rv = _nis_start(&_nis_state); 1458 1.67 christos if (rv != NS_SUCCESS) 1459 1.67 christos return rv; 1460 1.67 christos } 1461 1.67 christos 1462 1.67 christos next_nis_entry: 1463 1.67 christos key = NULL; 1464 1.67 christos data = NULL; 1465 1.67 christos rv = NS_NOTFOUND; 1466 1.67 christos 1467 1.67 christos if (_nis_state.current) { /* already searching */ 1468 1.67 christos nisr = yp_next(_nis_state.domain, PASSWD_BYNAME(&_nis_state), 1469 1.67 christos _nis_state.current, _nis_state.currentlen, 1470 1.67 christos &key, &keylen, &data, &datalen); 1471 1.67 christos free(_nis_state.current); 1472 1.67 christos _nis_state.current = NULL; 1473 1.67 christos switch (nisr) { 1474 1.67 christos case 0: 1475 1.67 christos _nis_state.current = key; 1476 1.67 christos _nis_state.currentlen = keylen; 1477 1.67 christos key = NULL; 1478 1.67 christos break; 1479 1.67 christos case YPERR_NOMORE: 1480 1.67 christos _nis_state.done = 1; 1481 1.67 christos goto nisent_out; 1482 1.67 christos default: 1483 1.67 christos rv = NS_UNAVAIL; 1484 1.67 christos goto nisent_out; 1485 1.67 christos } 1486 1.67 christos } else { /* new search */ 1487 1.67 christos if (yp_first(_nis_state.domain, PASSWD_BYNAME(&_nis_state), 1488 1.67 christos &_nis_state.current, &_nis_state.currentlen, 1489 1.67 christos &data, &datalen)) { 1490 1.67 christos rv = NS_UNAVAIL; 1491 1.67 christos goto nisent_out; 1492 1.67 christos } 1493 1.67 christos } 1494 1.67 christos 1495 1.67 christos data[datalen] = '\0'; /* clear trailing \n */ 1496 1.67 christos /* validate line */ 1497 1.67 christos if (_nis_parse(data, pw, buffer, buflen, &_nis_state)) 1498 1.67 christos rv = NS_SUCCESS; 1499 1.67 christos else { /* dodgy entry, try again */ 1500 1.67 christos if (key) 1501 1.67 christos free(key); 1502 1.67 christos free(data); 1503 1.67 christos goto next_nis_entry; 1504 1.67 christos } 1505 1.67 christos 1506 1.67 christos nisent_out: 1507 1.67 christos if (key) 1508 1.67 christos free(key); 1509 1.67 christos if (data) 1510 1.67 christos free(data); 1511 1.67 christos if (rv == NS_SUCCESS) 1512 1.67 christos *result = pw; 1513 1.67 christos else 1514 1.67 christos *result = NULL; 1515 1.67 christos return rv; 1516 1.67 christos } 1517 1.67 christos 1518 1.67 christos /*ARGSUSED*/ 1519 1.67 christos static int 1520 1.57 lukem _nis_getpwuid(void *nsrv, void *nscb, va_list ap) 1521 1.57 lukem { 1522 1.57 lukem struct passwd **retval = va_arg(ap, struct passwd **); 1523 1.57 lukem uid_t uid = va_arg(ap, uid_t); 1524 1.57 lukem 1525 1.57 lukem int rv, rerror; 1526 1.57 lukem 1527 1.57 lukem _DIAGASSERT(retval != NULL); 1528 1.57 lukem 1529 1.57 lukem *retval = NULL; 1530 1.57 lukem rv = _nis_start(&_nis_state); 1531 1.57 lukem if (rv != NS_SUCCESS) 1532 1.57 lukem return rv; 1533 1.57 lukem snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%u", (unsigned int)uid); 1534 1.57 lukem rv = _nis_pwscan(&rerror, &_nis_passwd, 1535 1.58 lukem _nis_passwdbuf, sizeof(_nis_passwdbuf), 1536 1.81 dholland &_nis_state, __nis_pw_u_map, __arraycount(__nis_pw_u_map)); 1537 1.57 lukem if (!_nis_state.stayopen) 1538 1.57 lukem _nis_end(&_nis_state); 1539 1.57 lukem if (rv == NS_SUCCESS && uid == _nis_passwd.pw_uid) 1540 1.57 lukem *retval = &_nis_passwd; 1541 1.57 lukem return rv; 1542 1.57 lukem } 1543 1.57 lukem 1544 1.57 lukem /*ARGSUSED*/ 1545 1.57 lukem static int 1546 1.57 lukem _nis_getpwuid_r(void *nsrv, void *nscb, va_list ap) 1547 1.57 lukem { 1548 1.57 lukem int *retval = va_arg(ap, int *); 1549 1.57 lukem uid_t uid = va_arg(ap, uid_t); 1550 1.57 lukem struct passwd *pw = va_arg(ap, struct passwd *); 1551 1.57 lukem char *buffer = va_arg(ap, char *); 1552 1.57 lukem size_t buflen = va_arg(ap, size_t); 1553 1.57 lukem struct passwd **result = va_arg(ap, struct passwd **); 1554 1.57 lukem 1555 1.57 lukem struct nis_state state; 1556 1.57 lukem int rv; 1557 1.57 lukem 1558 1.57 lukem _DIAGASSERT(retval != NULL); 1559 1.57 lukem _DIAGASSERT(pw != NULL); 1560 1.57 lukem _DIAGASSERT(buffer != NULL); 1561 1.57 lukem _DIAGASSERT(result != NULL); 1562 1.57 lukem 1563 1.57 lukem *result = NULL; 1564 1.57 lukem snprintf(buffer, buflen, "%u", (unsigned int)uid); 1565 1.78 christos /* remark: we run under a global mutex inside of this module ... */ 1566 1.78 christos if (_nis_state.stayopen) 1567 1.78 christos { /* use global state only if stayopen is set - otherwise we would blow up getpwent_r() ... */ 1568 1.78 christos rv = _nis_pwscan(retval, pw, buffer, buflen, 1569 1.81 dholland &_nis_state, __nis_pw_u_map, __arraycount(__nis_pw_u_map)); 1570 1.78 christos } 1571 1.78 christos else 1572 1.78 christos { /* keep old semantic if no stayopen set - no need to call _nis_start() here - _nis_pwscan() will do it for us ... */ 1573 1.78 christos /* use same way as in getgrent.c ... */ 1574 1.78 christos memset(&state, 0, sizeof(state)); 1575 1.78 christos rv = _nis_pwscan(retval, pw, buffer, buflen, 1576 1.81 dholland &state, __nis_pw_u_map, __arraycount(__nis_pw_u_map)); 1577 1.78 christos _nis_end(&state); 1578 1.78 christos } 1579 1.57 lukem if (rv != NS_SUCCESS) 1580 1.57 lukem return rv; 1581 1.57 lukem if (uid == pw->pw_uid) { 1582 1.57 lukem *result = pw; 1583 1.57 lukem return NS_SUCCESS; 1584 1.57 lukem } else 1585 1.57 lukem return NS_NOTFOUND; 1586 1.57 lukem } 1587 1.57 lukem 1588 1.57 lukem /*ARGSUSED*/ 1589 1.57 lukem static int 1590 1.57 lukem _nis_getpwnam(void *nsrv, void *nscb, va_list ap) 1591 1.57 lukem { 1592 1.57 lukem struct passwd **retval = va_arg(ap, struct passwd **); 1593 1.57 lukem const char *name = va_arg(ap, const char *); 1594 1.57 lukem 1595 1.57 lukem int rv, rerror; 1596 1.57 lukem 1597 1.57 lukem _DIAGASSERT(retval != NULL); 1598 1.57 lukem 1599 1.57 lukem *retval = NULL; 1600 1.57 lukem rv = _nis_start(&_nis_state); 1601 1.57 lukem if (rv != NS_SUCCESS) 1602 1.57 lukem return rv; 1603 1.57 lukem snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%s", name); 1604 1.57 lukem rv = _nis_pwscan(&rerror, &_nis_passwd, 1605 1.58 lukem _nis_passwdbuf, sizeof(_nis_passwdbuf), 1606 1.81 dholland &_nis_state, __nis_pw_n_map, __arraycount(__nis_pw_n_map)); 1607 1.57 lukem if (!_nis_state.stayopen) 1608 1.57 lukem _nis_end(&_nis_state); 1609 1.57 lukem if (rv == NS_SUCCESS && strcmp(name, _nis_passwd.pw_name) == 0) 1610 1.57 lukem *retval = &_nis_passwd; 1611 1.57 lukem return rv; 1612 1.57 lukem } 1613 1.57 lukem 1614 1.57 lukem /*ARGSUSED*/ 1615 1.57 lukem static int 1616 1.57 lukem _nis_getpwnam_r(void *nsrv, void *nscb, va_list ap) 1617 1.57 lukem { 1618 1.57 lukem int *retval = va_arg(ap, int *); 1619 1.57 lukem const char *name = va_arg(ap, const char *); 1620 1.57 lukem struct passwd *pw = va_arg(ap, struct passwd *); 1621 1.57 lukem char *buffer = va_arg(ap, char *); 1622 1.57 lukem size_t buflen = va_arg(ap, size_t); 1623 1.57 lukem struct passwd **result = va_arg(ap, struct passwd **); 1624 1.57 lukem 1625 1.57 lukem struct nis_state state; 1626 1.57 lukem int rv; 1627 1.57 lukem 1628 1.57 lukem _DIAGASSERT(retval != NULL); 1629 1.57 lukem _DIAGASSERT(pw != NULL); 1630 1.57 lukem _DIAGASSERT(buffer != NULL); 1631 1.57 lukem _DIAGASSERT(result != NULL); 1632 1.57 lukem 1633 1.57 lukem *result = NULL; 1634 1.57 lukem snprintf(buffer, buflen, "%s", name); 1635 1.78 christos /* remark: we run under a global mutex inside of this module ... */ 1636 1.78 christos if (_nis_state.stayopen) 1637 1.78 christos { /* use global state only if stayopen is set - otherwise we would blow up getpwent_r() ... */ 1638 1.78 christos rv = _nis_pwscan(retval, pw, buffer, buflen, 1639 1.81 dholland &_nis_state, __nis_pw_n_map, __arraycount(__nis_pw_n_map)); 1640 1.78 christos } 1641 1.78 christos else 1642 1.78 christos { /* keep old semantic if no stayopen set - no need to call _nis_start() here - _nis_pwscan() will do it for us ... */ 1643 1.78 christos /* use same way as in getgrent.c ... */ 1644 1.78 christos memset(&state, 0, sizeof(state)); 1645 1.78 christos rv = _nis_pwscan(retval, pw, buffer, buflen, 1646 1.81 dholland &state, __nis_pw_n_map, __arraycount(__nis_pw_n_map)); 1647 1.78 christos _nis_end(&state); 1648 1.78 christos } 1649 1.57 lukem if (rv != NS_SUCCESS) 1650 1.57 lukem return rv; 1651 1.57 lukem if (strcmp(name, pw->pw_name) == 0) { 1652 1.57 lukem *result = pw; 1653 1.57 lukem return NS_SUCCESS; 1654 1.57 lukem } else 1655 1.57 lukem return NS_NOTFOUND; 1656 1.57 lukem } 1657 1.57 lukem 1658 1.57 lukem #endif /* YP */ 1659 1.57 lukem 1660 1.57 lukem 1661 1.40 lukem #ifdef _PASSWD_COMPAT 1662 1.57 lukem /* 1663 1.57 lukem * compat methods 1664 1.57 lukem */ 1665 1.57 lukem 1666 1.57 lukem /* state shared between compat methods */ 1667 1.57 lukem 1668 1.57 lukem struct compat_state { 1669 1.57 lukem int stayopen; /* see getpassent(3) */ 1670 1.57 lukem DB *db; /* passwd DB */ 1671 1.57 lukem int keynum; /* key counter, -1 if no more */ 1672 1.57 lukem enum { /* current compat mode */ 1673 1.57 lukem COMPAT_NOTOKEN = 0, /* no compat token present */ 1674 1.57 lukem COMPAT_NONE, /* parsing normal pwd.db line */ 1675 1.57 lukem COMPAT_FULL, /* parsing `+' entries */ 1676 1.57 lukem COMPAT_USER, /* parsing `+name' entries */ 1677 1.57 lukem COMPAT_NETGROUP /* parsing `+@netgroup' entries */ 1678 1.57 lukem } mode; 1679 1.57 lukem char *user; /* COMPAT_USER "+name" */ 1680 1.57 lukem DB *exclude; /* compat exclude DB */ 1681 1.57 lukem struct passwd proto; /* proto passwd entry */ 1682 1.64 lukem char protobuf[_GETPW_R_SIZE_MAX]; 1683 1.64 lukem /* buffer for proto ptrs */ 1684 1.57 lukem int protoflags; /* proto passwd flags */ 1685 1.76 christos int version; 1686 1.57 lukem }; 1687 1.57 lukem 1688 1.57 lukem static struct compat_state _compat_state; 1689 1.57 lukem /* storage for non _r functions */ 1690 1.57 lukem static struct passwd _compat_passwd; 1691 1.64 lukem static char _compat_passwdbuf[_GETPW_R_SIZE_MAX]; 1692 1.57 lukem 1693 1.57 lukem static int 1694 1.57 lukem _compat_start(struct compat_state *state) 1695 1.57 lukem { 1696 1.57 lukem int rv; 1697 1.57 lukem 1698 1.57 lukem _DIAGASSERT(state != NULL); 1699 1.57 lukem 1700 1.57 lukem state->keynum = 0; 1701 1.57 lukem if (state->db == NULL) { /* not open yet */ 1702 1.57 lukem DBT key, data; 1703 1.57 lukem DBT pkey, pdata; 1704 1.57 lukem char bf[MAXLOGNAME]; 1705 1.57 lukem 1706 1.76 christos rv = _pw_opendb(&state->db, &state->version); 1707 1.57 lukem if (rv != NS_SUCCESS) 1708 1.57 lukem return rv; 1709 1.57 lukem 1710 1.57 lukem state->mode = COMPAT_NOTOKEN; 1711 1.57 lukem 1712 1.57 lukem /* 1713 1.57 lukem * Determine if the "compat" token is present in pwd.db; 1714 1.57 lukem * either "__YP!" or PW_KEYBYNAME+"+". 1715 1.57 lukem * Only works if pwd_mkdb installs the token. 1716 1.57 lukem */ 1717 1.57 lukem key.data = (u_char *)__UNCONST(__yp_token); 1718 1.57 lukem key.size = strlen(__yp_token); 1719 1.57 lukem 1720 1.57 lukem bf[0] = _PW_KEYBYNAME; /* Pre-token database support. */ 1721 1.57 lukem bf[1] = '+'; 1722 1.57 lukem pkey.data = (u_char *)bf; 1723 1.57 lukem pkey.size = 2; 1724 1.57 lukem 1725 1.57 lukem if ((state->db->get)(state->db, &key, &data, 0) == 0 1726 1.57 lukem || (state->db->get)(state->db, &pkey, &pdata, 0) == 0) 1727 1.57 lukem state->mode = COMPAT_NONE; 1728 1.57 lukem } 1729 1.57 lukem return NS_SUCCESS; 1730 1.57 lukem } 1731 1.57 lukem 1732 1.57 lukem static int 1733 1.57 lukem _compat_end(struct compat_state *state) 1734 1.57 lukem { 1735 1.57 lukem 1736 1.57 lukem _DIAGASSERT(state != NULL); 1737 1.57 lukem 1738 1.57 lukem state->keynum = 0; 1739 1.57 lukem if (state->db) { 1740 1.57 lukem (void)(state->db->close)(state->db); 1741 1.57 lukem state->db = NULL; 1742 1.57 lukem } 1743 1.57 lukem state->mode = COMPAT_NOTOKEN; 1744 1.57 lukem if (state->user) 1745 1.57 lukem free(state->user); 1746 1.57 lukem state->user = NULL; 1747 1.57 lukem if (state->exclude != NULL) 1748 1.57 lukem (void)(state->exclude->close)(state->exclude); 1749 1.57 lukem state->exclude = NULL; 1750 1.57 lukem state->proto.pw_name = NULL; 1751 1.57 lukem state->protoflags = 0; 1752 1.57 lukem return NS_SUCCESS; 1753 1.57 lukem } 1754 1.57 lukem 1755 1.57 lukem /* 1756 1.57 lukem * _compat_add_exclude 1757 1.57 lukem * add the name to the exclude list in state->exclude. 1758 1.57 lukem */ 1759 1.57 lukem static int 1760 1.57 lukem _compat_add_exclude(struct compat_state *state, const char *name) 1761 1.57 lukem { 1762 1.57 lukem DBT key, data; 1763 1.57 lukem 1764 1.57 lukem _DIAGASSERT(state != NULL); 1765 1.57 lukem _DIAGASSERT(name != NULL); 1766 1.57 lukem 1767 1.57 lukem /* initialize the exclusion table if needed */ 1768 1.57 lukem if (state->exclude == NULL) { 1769 1.57 lukem state->exclude = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL); 1770 1.57 lukem if (state->exclude == NULL) 1771 1.57 lukem return 0; 1772 1.57 lukem } 1773 1.57 lukem 1774 1.57 lukem key.size = strlen(name); /* set up the key */ 1775 1.57 lukem key.data = (u_char *)__UNCONST(name); 1776 1.57 lukem 1777 1.57 lukem data.data = NULL; /* data is nothing */ 1778 1.57 lukem data.size = 0; 1779 1.57 lukem 1780 1.57 lukem /* store it */ 1781 1.57 lukem if ((state->exclude->put)(state->exclude, &key, &data, 0) == -1) 1782 1.57 lukem return 0; 1783 1.57 lukem 1784 1.57 lukem return 1; 1785 1.57 lukem } 1786 1.57 lukem 1787 1.57 lukem /* 1788 1.57 lukem * _compat_is_excluded 1789 1.57 lukem * test if a name is on the compat mode exclude list 1790 1.57 lukem */ 1791 1.57 lukem static int 1792 1.57 lukem _compat_is_excluded(struct compat_state *state, const char *name) 1793 1.57 lukem { 1794 1.57 lukem DBT key, data; 1795 1.57 lukem 1796 1.57 lukem _DIAGASSERT(state != NULL); 1797 1.57 lukem _DIAGASSERT(name != NULL); 1798 1.57 lukem 1799 1.57 lukem if (state->exclude == NULL) 1800 1.57 lukem return 0; /* nothing excluded */ 1801 1.57 lukem 1802 1.57 lukem key.size = strlen(name); /* set up the key */ 1803 1.57 lukem key.data = (u_char *)__UNCONST(name); 1804 1.57 lukem 1805 1.57 lukem if ((state->exclude->get)(state->exclude, &key, &data, 0) == 0) 1806 1.57 lukem return 1; /* is excluded */ 1807 1.57 lukem 1808 1.57 lukem return 0; 1809 1.57 lukem } 1810 1.57 lukem 1811 1.57 lukem 1812 1.57 lukem /* 1813 1.57 lukem * _passwdcompat_bad 1814 1.57 lukem * log an error if "files" or "compat" is specified in 1815 1.57 lukem * passwd_compat database 1816 1.57 lukem */ 1817 1.57 lukem /*ARGSUSED*/ 1818 1.57 lukem static int 1819 1.57 lukem _passwdcompat_bad(void *nsrv, void *nscb, va_list ap) 1820 1.57 lukem { 1821 1.57 lukem static int warned; 1822 1.57 lukem 1823 1.74 christos _DIAGASSERT(nsrv != NULL); 1824 1.74 christos _DIAGASSERT(nscb != NULL); 1825 1.14 phil 1826 1.57 lukem if (!warned) { 1827 1.57 lukem syslog(LOG_ERR, 1828 1.57 lukem "nsswitch.conf passwd_compat database can't use '%s'", 1829 1.57 lukem (char *)nscb); 1830 1.4 deraadt } 1831 1.57 lukem warned = 1; 1832 1.57 lukem return NS_UNAVAIL; 1833 1.1 cgd } 1834 1.1 cgd 1835 1.14 phil /* 1836 1.57 lukem * _passwdcompat_setpassent 1837 1.57 lukem * Call setpassent for all passwd_compat sources. 1838 1.14 phil */ 1839 1.57 lukem static int 1840 1.57 lukem _passwdcompat_setpassent(int stayopen) 1841 1.57 lukem { 1842 1.57 lukem static const ns_dtab dtab[] = { 1843 1.57 lukem NS_FILES_CB(_passwdcompat_bad, "files") 1844 1.57 lukem NS_DNS_CB(_dns_setpassent, NULL) 1845 1.57 lukem NS_NIS_CB(_nis_setpassent, NULL) 1846 1.57 lukem NS_COMPAT_CB(_passwdcompat_bad, "compat") 1847 1.73 christos NS_NULL_CB 1848 1.57 lukem }; 1849 1.32 lukem 1850 1.57 lukem int rv, result; 1851 1.57 lukem 1852 1.57 lukem rv = nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "setpassent", 1853 1.65 lukem __nsdefaultnis_forceall, &result, stayopen); 1854 1.57 lukem return rv; 1855 1.57 lukem } 1856 1.57 lukem 1857 1.57 lukem /* 1858 1.57 lukem * _passwdcompat_endpwent 1859 1.57 lukem * Call endpwent for all passwd_compat sources. 1860 1.57 lukem */ 1861 1.14 phil static int 1862 1.57 lukem _passwdcompat_endpwent(void) 1863 1.14 phil { 1864 1.57 lukem static const ns_dtab dtab[] = { 1865 1.57 lukem NS_FILES_CB(_passwdcompat_bad, "files") 1866 1.57 lukem NS_DNS_CB(_dns_endpwent, NULL) 1867 1.57 lukem NS_NIS_CB(_nis_endpwent, NULL) 1868 1.57 lukem NS_COMPAT_CB(_passwdcompat_bad, "compat") 1869 1.73 christos NS_NULL_CB 1870 1.57 lukem }; 1871 1.57 lukem 1872 1.57 lukem return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "endpwent", 1873 1.65 lukem __nsdefaultnis_forceall); 1874 1.57 lukem } 1875 1.34 lukem 1876 1.57 lukem /* 1877 1.60 lukem * _passwdcompat_pwscan 1878 1.57 lukem * When a name lookup in compat mode is required (e.g., `+name', or a 1879 1.57 lukem * name in `+@netgroup'), look it up in the 'passwd_compat' nsswitch 1880 1.57 lukem * database. 1881 1.57 lukem * Fail if passwd_compat contains files or compat. 1882 1.57 lukem */ 1883 1.57 lukem static int 1884 1.60 lukem _passwdcompat_pwscan(struct passwd *pw, char *buffer, size_t buflen, 1885 1.57 lukem int search, const char *name, uid_t uid) 1886 1.57 lukem { 1887 1.57 lukem static const ns_dtab compatentdtab[] = { 1888 1.57 lukem NS_FILES_CB(_passwdcompat_bad, "files") 1889 1.67 christos NS_DNS_CB(_dns_getpwent_r, NULL) 1890 1.67 christos NS_NIS_CB(_nis_getpwent_r, NULL) 1891 1.57 lukem NS_COMPAT_CB(_passwdcompat_bad, "compat") 1892 1.73 christos NS_NULL_CB 1893 1.57 lukem }; 1894 1.57 lukem static const ns_dtab compatuiddtab[] = { 1895 1.57 lukem NS_FILES_CB(_passwdcompat_bad, "files") 1896 1.57 lukem NS_DNS_CB(_dns_getpwuid_r, NULL) 1897 1.57 lukem NS_NIS_CB(_nis_getpwuid_r, NULL) 1898 1.57 lukem NS_COMPAT_CB(_passwdcompat_bad, "compat") 1899 1.73 christos NS_NULL_CB 1900 1.57 lukem }; 1901 1.57 lukem static const ns_dtab compatnamdtab[] = { 1902 1.57 lukem NS_FILES_CB(_passwdcompat_bad, "files") 1903 1.57 lukem NS_DNS_CB(_dns_getpwnam_r, NULL) 1904 1.57 lukem NS_NIS_CB(_nis_getpwnam_r, NULL) 1905 1.57 lukem NS_COMPAT_CB(_passwdcompat_bad, "compat") 1906 1.73 christos NS_NULL_CB 1907 1.57 lukem }; 1908 1.34 lukem 1909 1.57 lukem int rv, crv; 1910 1.57 lukem struct passwd *cpw; 1911 1.32 lukem 1912 1.32 lukem switch (search) { 1913 1.57 lukem case _PW_KEYBYNUM: 1914 1.57 lukem rv = nsdispatch(NULL, compatentdtab, 1915 1.67 christos NSDB_PASSWD_COMPAT, "getpwent_r", __nsdefaultnis, 1916 1.67 christos &crv, pw, buffer, buflen, &cpw); 1917 1.57 lukem break; 1918 1.32 lukem case _PW_KEYBYNAME: 1919 1.57 lukem _DIAGASSERT(name != NULL); 1920 1.57 lukem rv = nsdispatch(NULL, compatnamdtab, 1921 1.65 lukem NSDB_PASSWD_COMPAT, "getpwnam_r", __nsdefaultnis, 1922 1.57 lukem &crv, name, pw, buffer, buflen, &cpw); 1923 1.32 lukem break; 1924 1.32 lukem case _PW_KEYBYUID: 1925 1.57 lukem rv = nsdispatch(NULL, compatuiddtab, 1926 1.65 lukem NSDB_PASSWD_COMPAT, "getpwuid_r", __nsdefaultnis, 1927 1.57 lukem &crv, uid, pw, buffer, buflen, &cpw); 1928 1.32 lukem break; 1929 1.32 lukem default: 1930 1.32 lukem abort(); 1931 1.57 lukem /*NOTREACHED*/ 1932 1.57 lukem } 1933 1.57 lukem return rv; 1934 1.57 lukem } 1935 1.57 lukem 1936 1.57 lukem /* 1937 1.57 lukem * _compat_pwscan 1938 1.57 lukem * Search state->db for the next desired entry. 1939 1.57 lukem * If search is _PW_KEYBYNUM, look for state->keynum. 1940 1.57 lukem * If search is _PW_KEYBYNAME, look for name. 1941 1.57 lukem * If search is _PW_KEYBYUID, look for uid. 1942 1.68 lukem * Sets *retval to the errno if the result is not NS_SUCCESS 1943 1.68 lukem * or NS_NOTFOUND. 1944 1.57 lukem */ 1945 1.57 lukem static int 1946 1.57 lukem _compat_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen, 1947 1.57 lukem struct compat_state *state, int search, const char *name, uid_t uid) 1948 1.57 lukem { 1949 1.57 lukem DBT key; 1950 1.57 lukem int rv, r, pwflags; 1951 1.57 lukem const char *user, *host, *dom; 1952 1.57 lukem const void *from; 1953 1.57 lukem size_t fromlen; 1954 1.57 lukem 1955 1.57 lukem _DIAGASSERT(retval != NULL); 1956 1.57 lukem _DIAGASSERT(pw != NULL); 1957 1.57 lukem _DIAGASSERT(buffer != NULL); 1958 1.57 lukem _DIAGASSERT(state != NULL); 1959 1.57 lukem /* name may be NULL */ 1960 1.57 lukem 1961 1.57 lukem *retval = 0; 1962 1.57 lukem 1963 1.57 lukem if (state->db == NULL) { 1964 1.57 lukem rv = _compat_start(state); 1965 1.57 lukem if (rv != NS_SUCCESS) 1966 1.57 lukem return rv; 1967 1.57 lukem } 1968 1.57 lukem if (buflen <= 1) { /* buffer too small */ 1969 1.57 lukem *retval = ERANGE; 1970 1.57 lukem return NS_UNAVAIL; 1971 1.32 lukem } 1972 1.14 phil 1973 1.57 lukem for (;;) { /* loop over pwd.db */ 1974 1.57 lukem rv = NS_NOTFOUND; 1975 1.57 lukem if (state->mode != COMPAT_NOTOKEN && 1976 1.57 lukem state->mode != COMPAT_NONE) { 1977 1.57 lukem /* doing a compat lookup */ 1978 1.57 lukem struct passwd cpw; 1979 1.64 lukem char cbuf[_GETPW_R_SIZE_MAX]; 1980 1.57 lukem 1981 1.57 lukem switch (state->mode) { 1982 1.57 lukem 1983 1.57 lukem case COMPAT_FULL: 1984 1.72 ginsbach /* get next user or lookup by key */ 1985 1.60 lukem rv = _passwdcompat_pwscan(&cpw, 1986 1.72 ginsbach cbuf, sizeof(cbuf), search, name, uid); 1987 1.57 lukem if (rv != NS_SUCCESS) 1988 1.57 lukem state->mode = COMPAT_NONE; 1989 1.10 deraadt break; 1990 1.57 lukem 1991 1.57 lukem case COMPAT_NETGROUP: 1992 1.57 lukem /* XXXREENTRANT: getnetgrent is not thread safe */ 1993 1.57 lukem /* get next user from netgroup */ 1994 1.57 lukem r = getnetgrent(&host, &user, &dom); 1995 1.57 lukem if (r == 0) { /* end of group */ 1996 1.34 lukem endnetgrent(); 1997 1.57 lukem state->mode = COMPAT_NONE; 1998 1.57 lukem break; 1999 1.34 lukem } 2000 1.34 lukem if (!user || !*user) 2001 1.57 lukem break; 2002 1.60 lukem rv = _passwdcompat_pwscan(&cpw, 2003 1.57 lukem cbuf, sizeof(cbuf), 2004 1.57 lukem _PW_KEYBYNAME, user, 0); 2005 1.57 lukem break; 2006 1.57 lukem 2007 1.57 lukem case COMPAT_USER: 2008 1.57 lukem /* get specific user */ 2009 1.57 lukem if (state->user == NULL) { 2010 1.57 lukem state->mode = COMPAT_NONE; 2011 1.57 lukem break; 2012 1.57 lukem } 2013 1.60 lukem rv = _passwdcompat_pwscan(&cpw, 2014 1.57 lukem cbuf, sizeof(cbuf), 2015 1.57 lukem _PW_KEYBYNAME, state->user, 0); 2016 1.57 lukem free(state->user); 2017 1.57 lukem state->user = NULL; 2018 1.57 lukem state->mode = COMPAT_NONE; 2019 1.57 lukem break; 2020 1.57 lukem 2021 1.57 lukem case COMPAT_NOTOKEN: 2022 1.57 lukem case COMPAT_NONE: 2023 1.57 lukem abort(); 2024 1.57 lukem 2025 1.57 lukem } 2026 1.57 lukem if (rv != NS_SUCCESS) /* if not matched, next loop */ 2027 1.57 lukem continue; 2028 1.57 lukem 2029 1.57 lukem /* copy cpw to pw, applying prototype */ 2030 1.57 lukem if (! _pw_copy(&cpw, pw, buffer, buflen, 2031 1.57 lukem &state->proto, state->protoflags)) { 2032 1.57 lukem rv = NS_UNAVAIL; 2033 1.57 lukem break; 2034 1.57 lukem } 2035 1.32 lukem 2036 1.57 lukem if (_compat_is_excluded(state, pw->pw_name)) 2037 1.57 lukem continue; /* excluded; next loop */ 2038 1.32 lukem 2039 1.57 lukem if ((search == _PW_KEYBYNAME 2040 1.57 lukem && strcmp(pw->pw_name, name) != 0) 2041 1.57 lukem || (search == _PW_KEYBYUID && pw->pw_uid != uid)) { 2042 1.57 lukem continue; /* not specific; next loop */ 2043 1.57 lukem } 2044 1.57 lukem 2045 1.57 lukem break; /* exit loop if found */ 2046 1.57 lukem } else { /* not a compat line */ 2047 1.57 lukem state->proto.pw_name = NULL; 2048 1.57 lukem /* clear prototype */ 2049 1.57 lukem } 2050 1.57 lukem 2051 1.57 lukem if (state->mode == COMPAT_NOTOKEN) { 2052 1.57 lukem /* no compat token; do direct lookup */ 2053 1.57 lukem switch (search) { 2054 1.57 lukem case _PW_KEYBYNUM: 2055 1.57 lukem if (state->keynum == -1) /* no more records */ 2056 1.57 lukem return NS_NOTFOUND; 2057 1.57 lukem state->keynum++; 2058 1.57 lukem from = &state->keynum; 2059 1.57 lukem fromlen = sizeof(state->keynum); 2060 1.57 lukem break; 2061 1.57 lukem case _PW_KEYBYNAME: 2062 1.57 lukem from = name; 2063 1.57 lukem fromlen = strlen(name); 2064 1.57 lukem break; 2065 1.57 lukem case _PW_KEYBYUID: 2066 1.57 lukem from = &uid; 2067 1.57 lukem fromlen = sizeof(uid); 2068 1.34 lukem break; 2069 1.34 lukem default: 2070 1.57 lukem abort(); 2071 1.57 lukem } 2072 1.57 lukem buffer[0] = search; 2073 1.57 lukem } else { 2074 1.57 lukem /* compat token; do line by line */ 2075 1.57 lukem if (state->keynum == -1) /* no more records */ 2076 1.57 lukem return NS_NOTFOUND; 2077 1.57 lukem state->keynum++; 2078 1.57 lukem from = &state->keynum; 2079 1.57 lukem fromlen = sizeof(state->keynum); 2080 1.57 lukem buffer[0] = _PW_KEYBYNUM; 2081 1.57 lukem } 2082 1.57 lukem 2083 1.57 lukem if (buflen <= fromlen) { /* buffer too small */ 2084 1.57 lukem *retval = ERANGE; 2085 1.57 lukem return NS_UNAVAIL; 2086 1.57 lukem } 2087 1.57 lukem memmove(buffer + 1, from, fromlen); /* setup key */ 2088 1.57 lukem key.size = fromlen + 1; 2089 1.57 lukem key.data = (u_char *)buffer; 2090 1.57 lukem 2091 1.76 christos rv = _pw_getkey(state->db, &key, pw, buffer, buflen, &pwflags, 2092 1.76 christos state->version); 2093 1.57 lukem if (rv != NS_SUCCESS) /* stop on error */ 2094 1.57 lukem break; 2095 1.57 lukem 2096 1.57 lukem if (state->mode == COMPAT_NOTOKEN) 2097 1.57 lukem break; /* stop if no compat token */ 2098 1.34 lukem 2099 1.57 lukem if (pw->pw_name[0] == '+') { 2100 1.57 lukem /* compat inclusion */ 2101 1.57 lukem switch(pw->pw_name[1]) { 2102 1.57 lukem case '\0': /* `+' */ 2103 1.57 lukem state->mode = COMPAT_FULL; 2104 1.57 lukem /* reset passwd_compat search */ 2105 1.57 lukem /* XXXREENTRANT: setpassent is not thread safe ? */ 2106 1.78 christos (void) _passwdcompat_setpassent(_compat_state.stayopen); 2107 1.57 lukem break; 2108 1.57 lukem case '@': /* `+@netgroup' */ 2109 1.57 lukem state->mode = COMPAT_NETGROUP; 2110 1.57 lukem /* reset netgroup search */ 2111 1.57 lukem /* XXXREENTRANT: setnetgrent is not thread safe */ 2112 1.57 lukem setnetgrent(pw->pw_name + 2); 2113 1.57 lukem break; 2114 1.57 lukem default: /* `+name' */ 2115 1.57 lukem state->mode = COMPAT_USER; 2116 1.57 lukem if (state->user) 2117 1.57 lukem free(state->user); 2118 1.57 lukem state->user = strdup(pw->pw_name + 1); 2119 1.14 phil break; 2120 1.34 lukem } 2121 1.57 lukem /* save the prototype */ 2122 1.57 lukem state->protoflags = pwflags; 2123 1.57 lukem if (! _pw_copy(pw, &state->proto, state->protobuf, 2124 1.57 lukem sizeof(state->protobuf), NULL, 0)) { 2125 1.57 lukem rv = NS_UNAVAIL; 2126 1.57 lukem break; 2127 1.34 lukem } 2128 1.57 lukem continue; /* loop again after inclusion */ 2129 1.57 lukem } else if (pw->pw_name[0] == '-') { 2130 1.57 lukem /* compat exclusion */ 2131 1.57 lukem rv = NS_SUCCESS; 2132 1.57 lukem switch(pw->pw_name[1]) { 2133 1.57 lukem case '\0': /* `-' */ 2134 1.34 lukem break; 2135 1.57 lukem case '@': /* `-@netgroup' */ 2136 1.57 lukem /* XXXREENTRANT: {set,get,end}netgrent is not thread safe */ 2137 1.57 lukem setnetgrent(pw->pw_name + 2); 2138 1.57 lukem while (getnetgrent(&host, &user, &dom)) { 2139 1.57 lukem if (!user || !*user) 2140 1.57 lukem continue; 2141 1.57 lukem if (! _compat_add_exclude(state,user)) { 2142 1.57 lukem rv = NS_UNAVAIL; 2143 1.57 lukem break; 2144 1.57 lukem } 2145 1.14 phil } 2146 1.34 lukem endnetgrent(); 2147 1.14 phil break; 2148 1.57 lukem default: /* `-name' */ 2149 1.57 lukem if (! _compat_add_exclude(state, 2150 1.57 lukem pw->pw_name + 1)) { 2151 1.57 lukem rv = NS_UNAVAIL; 2152 1.57 lukem } 2153 1.32 lukem break; 2154 1.4 deraadt } 2155 1.57 lukem if (rv != NS_SUCCESS) /* exclusion failure */ 2156 1.57 lukem break; 2157 1.57 lukem continue; /* loop again after exclusion */ 2158 1.4 deraadt } 2159 1.57 lukem if (search == _PW_KEYBYNUM || 2160 1.57 lukem (search == _PW_KEYBYUID && pw->pw_uid == uid) || 2161 1.57 lukem (search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) == 0)) 2162 1.57 lukem break; /* token mode match found */ 2163 1.4 deraadt } 2164 1.1 cgd 2165 1.57 lukem if (rv == NS_NOTFOUND && 2166 1.57 lukem (search == _PW_KEYBYNUM || state->mode != COMPAT_NOTOKEN)) 2167 1.57 lukem state->keynum = -1; /* flag `no more records' */ 2168 1.57 lukem 2169 1.57 lukem if (rv == NS_SUCCESS) { 2170 1.57 lukem if ((search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) != 0) 2171 1.57 lukem || (search == _PW_KEYBYUID && pw->pw_uid != uid)) 2172 1.57 lukem rv = NS_NOTFOUND; 2173 1.1 cgd } 2174 1.57 lukem 2175 1.68 lukem if (rv != NS_SUCCESS && rv != NS_NOTFOUND) 2176 1.57 lukem *retval = errno; 2177 1.57 lukem return rv; 2178 1.57 lukem } 2179 1.57 lukem 2180 1.57 lukem /*ARGSUSED*/ 2181 1.57 lukem static int 2182 1.57 lukem _compat_setpwent(void *nsrv, void *nscb, va_list ap) 2183 1.57 lukem { 2184 1.57 lukem 2185 1.57 lukem /* force passwd_compat setpwent() */ 2186 1.57 lukem (void) _passwdcompat_setpassent(0); 2187 1.57 lukem 2188 1.57 lukem /* reset state, keep db open */ 2189 1.57 lukem _compat_state.stayopen = 0; 2190 1.57 lukem return _compat_start(&_compat_state); 2191 1.57 lukem } 2192 1.57 lukem 2193 1.57 lukem /*ARGSUSED*/ 2194 1.57 lukem static int 2195 1.57 lukem _compat_setpassent(void *nsrv, void *nscb, va_list ap) 2196 1.57 lukem { 2197 1.57 lukem int *retval = va_arg(ap, int *); 2198 1.57 lukem int stayopen = va_arg(ap, int); 2199 1.57 lukem 2200 1.57 lukem int rv; 2201 1.57 lukem 2202 1.57 lukem /* force passwd_compat setpassent() */ 2203 1.57 lukem (void) _passwdcompat_setpassent(stayopen); 2204 1.57 lukem 2205 1.57 lukem _compat_state.stayopen = stayopen; 2206 1.57 lukem rv = _compat_start(&_compat_state); 2207 1.57 lukem *retval = (rv == NS_SUCCESS); 2208 1.57 lukem return rv; 2209 1.57 lukem } 2210 1.57 lukem 2211 1.57 lukem /*ARGSUSED*/ 2212 1.57 lukem static int 2213 1.57 lukem _compat_endpwent(void *nsrv, void *nscb, va_list ap) 2214 1.57 lukem { 2215 1.57 lukem 2216 1.57 lukem /* force passwd_compat endpwent() */ 2217 1.57 lukem (void) _passwdcompat_endpwent(); 2218 1.57 lukem 2219 1.57 lukem /* reset state, close db */ 2220 1.57 lukem _compat_state.stayopen = 0; 2221 1.57 lukem return _compat_end(&_compat_state); 2222 1.57 lukem } 2223 1.57 lukem 2224 1.57 lukem 2225 1.57 lukem /*ARGSUSED*/ 2226 1.57 lukem static int 2227 1.57 lukem _compat_getpwent(void *nsrv, void *nscb, va_list ap) 2228 1.57 lukem { 2229 1.57 lukem struct passwd **retval = va_arg(ap, struct passwd **); 2230 1.57 lukem 2231 1.57 lukem int rv, rerror; 2232 1.57 lukem 2233 1.57 lukem _DIAGASSERT(retval != NULL); 2234 1.57 lukem 2235 1.57 lukem *retval = NULL; 2236 1.57 lukem rv = _compat_pwscan(&rerror, &_compat_passwd, 2237 1.57 lukem _compat_passwdbuf, sizeof(_compat_passwdbuf), 2238 1.57 lukem &_compat_state, _PW_KEYBYNUM, NULL, 0); 2239 1.57 lukem if (rv == NS_SUCCESS) 2240 1.57 lukem *retval = &_compat_passwd; 2241 1.57 lukem return rv; 2242 1.57 lukem } 2243 1.57 lukem 2244 1.57 lukem /*ARGSUSED*/ 2245 1.57 lukem static int 2246 1.67 christos _compat_getpwent_r(void *nsrv, void *nscb, va_list ap) 2247 1.67 christos { 2248 1.67 christos int *retval = va_arg(ap, int *); 2249 1.67 christos struct passwd *pw = va_arg(ap, struct passwd *); 2250 1.67 christos char *buffer = va_arg(ap, char *); 2251 1.67 christos size_t buflen = va_arg(ap, size_t); 2252 1.67 christos struct passwd **result = va_arg(ap, struct passwd **); 2253 1.67 christos 2254 1.67 christos int rv; 2255 1.67 christos 2256 1.67 christos _DIAGASSERT(retval != NULL); 2257 1.67 christos _DIAGASSERT(pw != NULL); 2258 1.67 christos _DIAGASSERT(buffer != NULL); 2259 1.67 christos _DIAGASSERT(result != NULL); 2260 1.67 christos 2261 1.67 christos rv = _compat_pwscan(retval, pw, buffer, buflen, &_compat_state, 2262 1.67 christos _PW_KEYBYNUM, NULL, 0); 2263 1.67 christos if (rv == NS_SUCCESS) 2264 1.67 christos *result = pw; 2265 1.67 christos else 2266 1.67 christos *result = NULL; 2267 1.67 christos return rv; 2268 1.67 christos } 2269 1.67 christos 2270 1.67 christos 2271 1.67 christos /*ARGSUSED*/ 2272 1.67 christos static int 2273 1.57 lukem _compat_getpwnam(void *nsrv, void *nscb, va_list ap) 2274 1.57 lukem { 2275 1.57 lukem struct passwd **retval = va_arg(ap, struct passwd **); 2276 1.57 lukem const char *name = va_arg(ap, const char *); 2277 1.57 lukem 2278 1.57 lukem int rv, rerror; 2279 1.57 lukem 2280 1.57 lukem _DIAGASSERT(retval != NULL); 2281 1.57 lukem 2282 1.57 lukem *retval = NULL; 2283 1.57 lukem rv = _compat_start(&_compat_state); 2284 1.57 lukem if (rv != NS_SUCCESS) 2285 1.57 lukem return rv; 2286 1.57 lukem rv = _compat_pwscan(&rerror, &_compat_passwd, 2287 1.57 lukem _compat_passwdbuf, sizeof(_compat_passwdbuf), 2288 1.57 lukem &_compat_state, _PW_KEYBYNAME, name, 0); 2289 1.57 lukem if (!_compat_state.stayopen) 2290 1.57 lukem _compat_end(&_compat_state); 2291 1.57 lukem if (rv == NS_SUCCESS) 2292 1.57 lukem *retval = &_compat_passwd; 2293 1.57 lukem return rv; 2294 1.57 lukem } 2295 1.57 lukem 2296 1.57 lukem /*ARGSUSED*/ 2297 1.57 lukem static int 2298 1.57 lukem _compat_getpwnam_r(void *nsrv, void *nscb, va_list ap) 2299 1.57 lukem { 2300 1.57 lukem int *retval = va_arg(ap, int *); 2301 1.57 lukem const char *name = va_arg(ap, const char *); 2302 1.57 lukem struct passwd *pw = va_arg(ap, struct passwd *); 2303 1.57 lukem char *buffer = va_arg(ap, char *); 2304 1.57 lukem size_t buflen = va_arg(ap, size_t); 2305 1.57 lukem struct passwd **result = va_arg(ap, struct passwd **); 2306 1.57 lukem 2307 1.57 lukem struct compat_state state; 2308 1.57 lukem int rv; 2309 1.57 lukem 2310 1.57 lukem _DIAGASSERT(retval != NULL); 2311 1.57 lukem _DIAGASSERT(pw != NULL); 2312 1.57 lukem _DIAGASSERT(buffer != NULL); 2313 1.57 lukem _DIAGASSERT(result != NULL); 2314 1.57 lukem 2315 1.57 lukem *result = NULL; 2316 1.57 lukem memset(&state, 0, sizeof(state)); 2317 1.57 lukem rv = _compat_pwscan(retval, pw, buffer, buflen, &state, 2318 1.57 lukem _PW_KEYBYNAME, name, 0); 2319 1.57 lukem _compat_end(&state); 2320 1.57 lukem if (rv == NS_SUCCESS) 2321 1.57 lukem *result = pw; 2322 1.57 lukem return rv; 2323 1.57 lukem } 2324 1.57 lukem 2325 1.57 lukem /*ARGSUSED*/ 2326 1.57 lukem static int 2327 1.57 lukem _compat_getpwuid(void *nsrv, void *nscb, va_list ap) 2328 1.57 lukem { 2329 1.57 lukem struct passwd **retval = va_arg(ap, struct passwd **); 2330 1.57 lukem uid_t uid = va_arg(ap, uid_t); 2331 1.57 lukem 2332 1.57 lukem int rv, rerror; 2333 1.57 lukem 2334 1.57 lukem _DIAGASSERT(retval != NULL); 2335 1.57 lukem 2336 1.57 lukem *retval = NULL; 2337 1.57 lukem rv = _compat_start(&_compat_state); 2338 1.57 lukem if (rv != NS_SUCCESS) 2339 1.57 lukem return rv; 2340 1.57 lukem rv = _compat_pwscan(&rerror, &_compat_passwd, 2341 1.57 lukem _compat_passwdbuf, sizeof(_compat_passwdbuf), 2342 1.57 lukem &_compat_state, _PW_KEYBYUID, NULL, uid); 2343 1.57 lukem if (!_compat_state.stayopen) 2344 1.57 lukem _compat_end(&_compat_state); 2345 1.57 lukem if (rv == NS_SUCCESS) 2346 1.57 lukem *retval = &_compat_passwd; 2347 1.57 lukem return rv; 2348 1.57 lukem } 2349 1.57 lukem 2350 1.57 lukem /*ARGSUSED*/ 2351 1.57 lukem static int 2352 1.57 lukem _compat_getpwuid_r(void *nsrv, void *nscb, va_list ap) 2353 1.57 lukem { 2354 1.57 lukem int *retval = va_arg(ap, int *); 2355 1.57 lukem uid_t uid = va_arg(ap, uid_t); 2356 1.57 lukem struct passwd *pw = va_arg(ap, struct passwd *); 2357 1.57 lukem char *buffer = va_arg(ap, char *); 2358 1.57 lukem size_t buflen = va_arg(ap, size_t); 2359 1.57 lukem struct passwd **result = va_arg(ap, struct passwd **); 2360 1.57 lukem 2361 1.57 lukem struct compat_state state; 2362 1.57 lukem int rv; 2363 1.57 lukem 2364 1.57 lukem _DIAGASSERT(retval != NULL); 2365 1.57 lukem _DIAGASSERT(pw != NULL); 2366 1.57 lukem _DIAGASSERT(buffer != NULL); 2367 1.57 lukem _DIAGASSERT(result != NULL); 2368 1.57 lukem 2369 1.57 lukem *result = NULL; 2370 1.57 lukem memset(&state, 0, sizeof(state)); 2371 1.57 lukem rv = _compat_pwscan(retval, pw, buffer, buflen, &state, 2372 1.57 lukem _PW_KEYBYUID, NULL, uid); 2373 1.57 lukem _compat_end(&state); 2374 1.57 lukem if (rv == NS_SUCCESS) 2375 1.57 lukem *result = pw; 2376 1.57 lukem return rv; 2377 1.57 lukem } 2378 1.57 lukem 2379 1.40 lukem #endif /* _PASSWD_COMPAT */ 2380 1.57 lukem 2381 1.57 lukem 2382 1.57 lukem /* 2383 1.57 lukem * public functions 2384 1.57 lukem */ 2385 1.1 cgd 2386 1.1 cgd struct passwd * 2387 1.57 lukem getpwent(void) 2388 1.1 cgd { 2389 1.32 lukem int r; 2390 1.57 lukem struct passwd *retval; 2391 1.57 lukem 2392 1.36 lukem static const ns_dtab dtab[] = { 2393 1.57 lukem NS_FILES_CB(_files_getpwent, NULL) 2394 1.57 lukem NS_DNS_CB(_dns_getpwent, NULL) 2395 1.57 lukem NS_NIS_CB(_nis_getpwent, NULL) 2396 1.35 lukem NS_COMPAT_CB(_compat_getpwent, NULL) 2397 1.73 christos NS_NULL_CB 2398 1.32 lukem }; 2399 1.32 lukem 2400 1.61 lukem mutex_lock(&_pwmutex); 2401 1.65 lukem r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent", __nsdefaultcompat, 2402 1.57 lukem &retval); 2403 1.61 lukem mutex_unlock(&_pwmutex); 2404 1.57 lukem return (r == NS_SUCCESS) ? retval : NULL; 2405 1.32 lukem } 2406 1.10 deraadt 2407 1.67 christos int 2408 1.67 christos getpwent_r(struct passwd *pwd, char *buffer, size_t buflen, 2409 1.67 christos struct passwd **result) 2410 1.67 christos { 2411 1.67 christos int r, retval; 2412 1.67 christos 2413 1.67 christos static const ns_dtab dtab[] = { 2414 1.67 christos NS_FILES_CB(_files_getpwent_r, NULL) 2415 1.67 christos NS_DNS_CB(_dns_getpwent_r, NULL) 2416 1.67 christos NS_NIS_CB(_nis_getpwent_r, NULL) 2417 1.67 christos NS_COMPAT_CB(_compat_getpwent_r, NULL) 2418 1.73 christos NS_NULL_CB 2419 1.67 christos }; 2420 1.67 christos 2421 1.67 christos _DIAGASSERT(pwd != NULL); 2422 1.67 christos _DIAGASSERT(buffer != NULL); 2423 1.67 christos _DIAGASSERT(result != NULL); 2424 1.67 christos 2425 1.67 christos *result = NULL; 2426 1.67 christos retval = 0; 2427 1.67 christos mutex_lock(&_pwmutex); 2428 1.67 christos r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent_r", __nsdefaultcompat, 2429 1.67 christos &retval, pwd, buffer, buflen, result); 2430 1.67 christos mutex_unlock(&_pwmutex); 2431 1.68 lukem switch (r) { 2432 1.68 lukem case NS_SUCCESS: 2433 1.68 lukem case NS_NOTFOUND: 2434 1.68 lukem return 0; 2435 1.68 lukem default: 2436 1.68 lukem return retval; 2437 1.68 lukem } 2438 1.67 christos } 2439 1.67 christos 2440 1.67 christos 2441 1.32 lukem struct passwd * 2442 1.57 lukem getpwnam(const char *name) 2443 1.32 lukem { 2444 1.57 lukem int rv; 2445 1.57 lukem struct passwd *retval; 2446 1.57 lukem 2447 1.36 lukem static const ns_dtab dtab[] = { 2448 1.57 lukem NS_FILES_CB(_files_getpwnam, NULL) 2449 1.57 lukem NS_DNS_CB(_dns_getpwnam, NULL) 2450 1.57 lukem NS_NIS_CB(_nis_getpwnam, NULL) 2451 1.57 lukem NS_COMPAT_CB(_compat_getpwnam, NULL) 2452 1.73 christos NS_NULL_CB 2453 1.32 lukem }; 2454 1.4 deraadt 2455 1.61 lukem mutex_lock(&_pwmutex); 2456 1.65 lukem rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam", __nsdefaultcompat, 2457 1.57 lukem &retval, name); 2458 1.61 lukem mutex_unlock(&_pwmutex); 2459 1.57 lukem return (rv == NS_SUCCESS) ? retval : NULL; 2460 1.57 lukem } 2461 1.57 lukem 2462 1.57 lukem int 2463 1.57 lukem getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t buflen, 2464 1.57 lukem struct passwd **result) 2465 1.57 lukem { 2466 1.57 lukem int r, retval; 2467 1.57 lukem 2468 1.57 lukem static const ns_dtab dtab[] = { 2469 1.57 lukem NS_FILES_CB(_files_getpwnam_r, NULL) 2470 1.57 lukem NS_DNS_CB(_dns_getpwnam_r, NULL) 2471 1.57 lukem NS_NIS_CB(_nis_getpwnam_r, NULL) 2472 1.57 lukem NS_COMPAT_CB(_compat_getpwnam_r, NULL) 2473 1.73 christos NS_NULL_CB 2474 1.57 lukem }; 2475 1.4 deraadt 2476 1.57 lukem _DIAGASSERT(name != NULL); 2477 1.57 lukem _DIAGASSERT(pwd != NULL); 2478 1.57 lukem _DIAGASSERT(buffer != NULL); 2479 1.57 lukem _DIAGASSERT(result != NULL); 2480 1.57 lukem 2481 1.57 lukem *result = NULL; 2482 1.57 lukem retval = 0; 2483 1.61 lukem mutex_lock(&_pwmutex); 2484 1.65 lukem r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam_r", __nsdefaultcompat, 2485 1.57 lukem &retval, name, pwd, buffer, buflen, result); 2486 1.61 lukem mutex_unlock(&_pwmutex); 2487 1.68 lukem switch (r) { 2488 1.68 lukem case NS_SUCCESS: 2489 1.68 lukem case NS_NOTFOUND: 2490 1.68 lukem return 0; 2491 1.68 lukem default: 2492 1.68 lukem return retval; 2493 1.68 lukem } 2494 1.32 lukem } 2495 1.14 phil 2496 1.32 lukem struct passwd * 2497 1.57 lukem getpwuid(uid_t uid) 2498 1.32 lukem { 2499 1.57 lukem int rv; 2500 1.57 lukem struct passwd *retval; 2501 1.57 lukem 2502 1.36 lukem static const ns_dtab dtab[] = { 2503 1.57 lukem NS_FILES_CB(_files_getpwuid, NULL) 2504 1.57 lukem NS_DNS_CB(_dns_getpwuid, NULL) 2505 1.57 lukem NS_NIS_CB(_nis_getpwuid, NULL) 2506 1.57 lukem NS_COMPAT_CB(_compat_getpwuid, NULL) 2507 1.73 christos NS_NULL_CB 2508 1.32 lukem }; 2509 1.1 cgd 2510 1.61 lukem mutex_lock(&_pwmutex); 2511 1.65 lukem rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid", __nsdefaultcompat, 2512 1.57 lukem &retval, uid); 2513 1.61 lukem mutex_unlock(&_pwmutex); 2514 1.57 lukem return (rv == NS_SUCCESS) ? retval : NULL; 2515 1.1 cgd } 2516 1.1 cgd 2517 1.1 cgd int 2518 1.57 lukem getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t buflen, 2519 1.57 lukem struct passwd **result) 2520 1.1 cgd { 2521 1.57 lukem int r, retval; 2522 1.57 lukem 2523 1.57 lukem static const ns_dtab dtab[] = { 2524 1.57 lukem NS_FILES_CB(_files_getpwuid_r, NULL) 2525 1.57 lukem NS_DNS_CB(_dns_getpwuid_r, NULL) 2526 1.57 lukem NS_NIS_CB(_nis_getpwuid_r, NULL) 2527 1.57 lukem NS_COMPAT_CB(_compat_getpwuid_r, NULL) 2528 1.73 christos NS_NULL_CB 2529 1.57 lukem }; 2530 1.57 lukem 2531 1.57 lukem _DIAGASSERT(pwd != NULL); 2532 1.57 lukem _DIAGASSERT(buffer != NULL); 2533 1.57 lukem _DIAGASSERT(result != NULL); 2534 1.57 lukem 2535 1.57 lukem *result = NULL; 2536 1.57 lukem retval = 0; 2537 1.61 lukem mutex_lock(&_pwmutex); 2538 1.65 lukem r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid_r", __nsdefaultcompat, 2539 1.57 lukem &retval, uid, pwd, buffer, buflen, result); 2540 1.61 lukem mutex_unlock(&_pwmutex); 2541 1.68 lukem switch (r) { 2542 1.68 lukem case NS_SUCCESS: 2543 1.68 lukem case NS_NOTFOUND: 2544 1.68 lukem return 0; 2545 1.68 lukem default: 2546 1.68 lukem return retval; 2547 1.68 lukem } 2548 1.1 cgd } 2549 1.1 cgd 2550 1.8 jtc void 2551 1.57 lukem endpwent(void) 2552 1.1 cgd { 2553 1.57 lukem static const ns_dtab dtab[] = { 2554 1.57 lukem NS_FILES_CB(_files_endpwent, NULL) 2555 1.57 lukem NS_DNS_CB(_dns_endpwent, NULL) 2556 1.57 lukem NS_NIS_CB(_nis_endpwent, NULL) 2557 1.57 lukem NS_COMPAT_CB(_compat_endpwent, NULL) 2558 1.73 christos NS_NULL_CB 2559 1.57 lukem }; 2560 1.1 cgd 2561 1.61 lukem mutex_lock(&_pwmutex); 2562 1.57 lukem /* force all endpwent() methods */ 2563 1.57 lukem (void) nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent", 2564 1.65 lukem __nsdefaultcompat_forceall); 2565 1.61 lukem mutex_unlock(&_pwmutex); 2566 1.1 cgd } 2567 1.1 cgd 2568 1.57 lukem /*ARGSUSED*/ 2569 1.57 lukem int 2570 1.57 lukem setpassent(int stayopen) 2571 1.1 cgd { 2572 1.57 lukem static const ns_dtab dtab[] = { 2573 1.57 lukem NS_FILES_CB(_files_setpassent, NULL) 2574 1.57 lukem NS_DNS_CB(_dns_setpassent, NULL) 2575 1.57 lukem NS_NIS_CB(_nis_setpassent, NULL) 2576 1.57 lukem NS_COMPAT_CB(_compat_setpassent, NULL) 2577 1.73 christos NS_NULL_CB 2578 1.57 lukem }; 2579 1.57 lukem int rv, retval; 2580 1.1 cgd 2581 1.61 lukem mutex_lock(&_pwmutex); 2582 1.57 lukem /* force all setpassent() methods */ 2583 1.57 lukem rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "setpassent", 2584 1.65 lukem __nsdefaultcompat_forceall, &retval, stayopen); 2585 1.61 lukem mutex_unlock(&_pwmutex); 2586 1.57 lukem return (rv == NS_SUCCESS) ? retval : 0; 2587 1.1 cgd } 2588 1.1 cgd 2589 1.57 lukem void 2590 1.57 lukem setpwent(void) 2591 1.1 cgd { 2592 1.57 lukem static const ns_dtab dtab[] = { 2593 1.57 lukem NS_FILES_CB(_files_setpwent, NULL) 2594 1.57 lukem NS_DNS_CB(_dns_setpwent, NULL) 2595 1.57 lukem NS_NIS_CB(_nis_setpwent, NULL) 2596 1.57 lukem NS_COMPAT_CB(_compat_setpwent, NULL) 2597 1.73 christos NS_NULL_CB 2598 1.57 lukem }; 2599 1.14 phil 2600 1.61 lukem mutex_lock(&_pwmutex); 2601 1.57 lukem /* force all setpwent() methods */ 2602 1.57 lukem (void) nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", 2603 1.65 lukem __nsdefaultcompat_forceall); 2604 1.61 lukem mutex_unlock(&_pwmutex); 2605 1.1 cgd } 2606