1113596Snectar/*- 2113596Snectar * Copyright (c) 2003 Networks Associates Technology, Inc. 3113596Snectar * All rights reserved. 41573Srgrimes * 5113596Snectar * This software was developed for the FreeBSD Project by 6113596Snectar * Jacques A. Vidrine, Safeport Network Services, and Network 7113596Snectar * Associates Laboratories, the Security Research Division of Network 8113596Snectar * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 9113596Snectar * ("CBOSS"), as part of the DARPA CHATS research program. 10113596Snectar * 111573Srgrimes * Redistribution and use in source and binary forms, with or without 121573Srgrimes * modification, are permitted provided that the following conditions 131573Srgrimes * are met: 141573Srgrimes * 1. Redistributions of source code must retain the above copyright 151573Srgrimes * notice, this list of conditions and the following disclaimer. 161573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171573Srgrimes * notice, this list of conditions and the following disclaimer in the 181573Srgrimes * documentation and/or other materials provided with the distribution. 191573Srgrimes * 20113596Snectar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23113596Snectar * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301573Srgrimes * SUCH DAMAGE. 31113596Snectar * 321573Srgrimes */ 3390016Sbde#include <sys/cdefs.h> 3489999Sobrien__FBSDID("$FreeBSD$"); 351573Srgrimes 36113596Snectar#include "namespace.h" 371573Srgrimes#include <sys/param.h> 38113596Snectar#ifdef YP 39113596Snectar#include <rpc/rpc.h> 40113596Snectar#include <rpcsvc/yp_prot.h> 41113596Snectar#include <rpcsvc/ypclnt.h> 42113596Snectar#endif 43113596Snectar#include <arpa/inet.h> 44113596Snectar#include <errno.h> 451573Srgrimes#include <fcntl.h> 4665532Snectar#ifdef HESIOD 4765532Snectar#include <hesiod.h> 4865532Snectar#endif 49113596Snectar#include <netdb.h> 50113596Snectar#include <nsswitch.h> 51113596Snectar#include <pthread.h> 52113596Snectar#include <pthread_np.h> 53113596Snectar#include <pwd.h> 54113596Snectar#include <stdlib.h> 5565532Snectar#include <stdio.h> 56113596Snectar#include <string.h> 57113596Snectar#include <syslog.h> 58113596Snectar#include <unistd.h> 5971579Sdeischen#include "un-namespace.h" 60113596Snectar#include <db.h> 61111618Snectar#include "libc_private.h" 6265532Snectar#include "pw_scan.h" 63113596Snectar#include "nss_tls.h" 64158115Sume#ifdef NS_CACHING 65158115Sume#include "nscache.h" 66158115Sume#endif 6765532Snectar 68113596Snectar#ifndef CTASSERT 69113596Snectar#define CTASSERT(x) _CTASSERT(x, __LINE__) 70113596Snectar#define _CTASSERT(x, y) __CTASSERT(x, y) 71113596Snectar#define __CTASSERT(x, y) typedef char __assert_ ## y [(x) ? 1 : -1] 7265532Snectar#endif 7365532Snectar 74113596Snectar/* Counter as stored in /etc/pwd.db */ 75113596Snectartypedef int pwkeynum; 7623668Speter 77113596SnectarCTASSERT(MAXLOGNAME > sizeof(uid_t)); 78113596SnectarCTASSERT(MAXLOGNAME > sizeof(pwkeynum)); 7965532Snectar 80113596Snectarenum constants { 81113596Snectar PWD_STORAGE_INITIAL = 1 << 10, /* 1 KByte */ 82113596Snectar PWD_STORAGE_MAX = 1 << 20, /* 1 MByte */ 83113596Snectar SETPWENT = 1, 84113596Snectar ENDPWENT = 2, 85113596Snectar HESIOD_NAME_MAX = 256 86113596Snectar}; 8765532Snectar 88113596Snectarstatic const ns_src defaultsrc[] = { 89113643Snectar { NSSRC_COMPAT, NS_SUCCESS }, 90113596Snectar { NULL, 0 } 9165532Snectar}; 9265532Snectar 93113596Snectarint __pw_match_entry(const char *, size_t, enum nss_lookup_type, 94113596Snectar const char *, uid_t); 95113596Snectarint __pw_parse_entry(char *, size_t, struct passwd *, int, int *errnop); 9615267Swpaul 97113694Snectarstatic void pwd_init(struct passwd *); 98113672Snectar 99113596Snectarunion key { 100113596Snectar const char *name; 101113596Snectar uid_t uid; 102113596Snectar}; 103113596Snectar 104113596Snectarstatic struct passwd *getpw(int (*fn)(union key, struct passwd *, char *, 105113596Snectar size_t, struct passwd **), union key); 106113596Snectarstatic int wrap_getpwnam_r(union key, struct passwd *, char *, 107113596Snectar size_t, struct passwd **); 108113596Snectarstatic int wrap_getpwuid_r(union key, struct passwd *, char *, size_t, 109113596Snectar struct passwd **); 110113596Snectarstatic int wrap_getpwent_r(union key, struct passwd *, char *, size_t, 111113596Snectar struct passwd **); 112113596Snectar 113113596Snectarstatic int pwdb_match_entry_v3(char *, size_t, enum nss_lookup_type, 114113596Snectar const char *, uid_t); 115113596Snectarstatic int pwdb_parse_entry_v3(char *, size_t, struct passwd *, int *); 116113596Snectarstatic int pwdb_match_entry_v4(char *, size_t, enum nss_lookup_type, 117113596Snectar const char *, uid_t); 118113596Snectarstatic int pwdb_parse_entry_v4(char *, size_t, struct passwd *, int *); 119113596Snectar 120113596Snectar 121113596Snectarstruct { 122113596Snectar int (*match)(char *, size_t, enum nss_lookup_type, const char *, 123113596Snectar uid_t); 124113596Snectar int (*parse)(char *, size_t, struct passwd *, int *); 125113596Snectar} pwdb_versions[] = { 126113596Snectar { NULL, NULL }, /* version 0 */ 127113596Snectar { NULL, NULL }, /* version 1 */ 128113596Snectar { NULL, NULL }, /* version 2 */ 129113596Snectar { pwdb_match_entry_v3, pwdb_parse_entry_v3 }, /* version 3 */ 130113596Snectar { pwdb_match_entry_v4, pwdb_parse_entry_v4 }, /* version 4 */ 131113596Snectar}; 132113596Snectar 133113596Snectar 134113596Snectarstruct files_state { 135113596Snectar DB *db; 136113596Snectar pwkeynum keynum; 137113596Snectar int stayopen; 138113596Snectar int version; 139113596Snectar}; 140113596Snectarstatic void files_endstate(void *); 141113596SnectarNSS_TLS_HANDLING(files); 142113596Snectarstatic DB *pwdbopen(int *); 143113596Snectarstatic void files_endstate(void *); 144113596Snectarstatic int files_setpwent(void *, void *, va_list); 145113596Snectarstatic int files_passwd(void *, void *, va_list); 146113596Snectar 147113596Snectar 14865532Snectar#ifdef HESIOD 149113596Snectarstruct dns_state { 150113596Snectar long counter; 151113596Snectar}; 152113596Snectarstatic void dns_endstate(void *); 153113596SnectarNSS_TLS_HANDLING(dns); 154113596Snectarstatic int dns_setpwent(void *, void *, va_list); 155113596Snectarstatic int dns_passwd(void *, void *, va_list); 15611436Swpaul#endif 1572917Swollman 15865532Snectar 159113596Snectar#ifdef YP 160113596Snectarstruct nis_state { 161113596Snectar char domain[MAXHOSTNAMELEN]; 162113596Snectar int done; 163113596Snectar char *key; 164113596Snectar int keylen; 165113596Snectar}; 166113596Snectarstatic void nis_endstate(void *); 167113596SnectarNSS_TLS_HANDLING(nis); 168113596Snectarstatic int nis_setpwent(void *, void *, va_list); 169113596Snectarstatic int nis_passwd(void *, void *, va_list); 170113596Snectarstatic int nis_map(char *, enum nss_lookup_type, char *, size_t, int *); 171113596Snectarstatic int nis_adjunct(char *, const char *, char *, size_t); 172113596Snectar#endif 17365532Snectar 17465532Snectar 175113596Snectarstruct compat_state { 176113596Snectar DB *db; 177113596Snectar pwkeynum keynum; 178113596Snectar int stayopen; 179113596Snectar int version; 180113596Snectar DB *exclude; 181113596Snectar struct passwd template; 182113596Snectar char *name; 183113596Snectar enum _compat { 184113596Snectar COMPAT_MODE_OFF = 0, 185113596Snectar COMPAT_MODE_ALL, 186113596Snectar COMPAT_MODE_NAME, 187113596Snectar COMPAT_MODE_NETGROUP 188113596Snectar } compat; 189113596Snectar}; 190113596Snectarstatic void compat_endstate(void *); 191113596SnectarNSS_TLS_HANDLING(compat); 192113596Snectarstatic int compat_setpwent(void *, void *, va_list); 193113596Snectarstatic int compat_passwd(void *, void *, va_list); 194113596Snectarstatic void compat_clear_template(struct passwd *); 195113596Snectarstatic int compat_set_template(struct passwd *, struct passwd *); 196113596Snectarstatic int compat_use_template(struct passwd *, struct passwd *, char *, 197113596Snectar size_t); 198113596Snectarstatic int compat_redispatch(struct compat_state *, enum nss_lookup_type, 199113596Snectar enum nss_lookup_type, const char *, const char *, uid_t, 200113596Snectar struct passwd *, char *, size_t, int *); 201158115Sume 202158115Sume#ifdef NS_CACHING 203158115Sumestatic int pwd_id_func(char *, size_t *, va_list ap, void *); 204158115Sumestatic int pwd_marshal_func(char *, size_t *, void *, va_list, void *); 205158115Sumestatic int pwd_unmarshal_func(char *, size_t, void *, va_list, void *); 206158115Sume 207158115Sumestatic int 208158115Sumepwd_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata) 209158115Sume{ 210158115Sume char *name; 211158115Sume uid_t uid; 212158115Sume size_t size, desired_size; 213158115Sume int res = NS_UNAVAIL; 214158115Sume enum nss_lookup_type lookup_type; 215158115Sume 216158115Sume lookup_type = (enum nss_lookup_type)cache_mdata; 217158115Sume switch (lookup_type) { 218158115Sume case nss_lt_name: 219158115Sume name = va_arg(ap, char *); 220158115Sume size = strlen(name); 221158115Sume desired_size = sizeof(enum nss_lookup_type) + size + 1; 222158115Sume if (desired_size > *buffer_size) { 223158115Sume res = NS_RETURN; 224158115Sume goto fin; 225158115Sume } 226158115Sume 227158115Sume memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 228158115Sume memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1); 229158115Sume 230158115Sume res = NS_SUCCESS; 231158115Sume break; 232158115Sume case nss_lt_id: 233158115Sume uid = va_arg(ap, uid_t); 234158115Sume desired_size = sizeof(enum nss_lookup_type) + sizeof(uid_t); 235158115Sume if (desired_size > *buffer_size) { 236158115Sume res = NS_RETURN; 237158115Sume goto fin; 238158115Sume } 239158115Sume 240158115Sume memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); 241158115Sume memcpy(buffer + sizeof(enum nss_lookup_type), &uid, 242158115Sume sizeof(uid_t)); 243158115Sume 244158115Sume res = NS_SUCCESS; 245158115Sume break; 246158115Sume default: 247158115Sume /* should be unreachable */ 248158115Sume return (NS_UNAVAIL); 249158115Sume } 250158115Sume 251158115Sumefin: 252158115Sume *buffer_size = desired_size; 253158115Sume return (res); 254158115Sume} 255158115Sume 256158115Sumestatic int 257158115Sumepwd_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap, 258158115Sume void *cache_mdata) 259158115Sume{ 260158115Sume char *name; 261158115Sume uid_t uid; 262158115Sume struct passwd *pwd; 263158115Sume char *orig_buf; 264158115Sume size_t orig_buf_size; 265158115Sume 266158115Sume struct passwd new_pwd; 267158115Sume size_t desired_size, size; 268158115Sume char *p; 269158115Sume 270158115Sume switch ((enum nss_lookup_type)cache_mdata) { 271158115Sume case nss_lt_name: 272158115Sume name = va_arg(ap, char *); 273158115Sume break; 274158115Sume case nss_lt_id: 275158115Sume uid = va_arg(ap, uid_t); 276158115Sume break; 277158115Sume case nss_lt_all: 278158115Sume break; 279158115Sume default: 280158115Sume /* should be unreachable */ 281158115Sume return (NS_UNAVAIL); 282158115Sume } 283158115Sume 284158115Sume pwd = va_arg(ap, struct passwd *); 285158115Sume orig_buf = va_arg(ap, char *); 286158115Sume orig_buf_size = va_arg(ap, size_t); 287158115Sume 288158115Sume desired_size = sizeof(struct passwd) + sizeof(char *) + 289158115Sume strlen(pwd->pw_name) + 1; 290158115Sume if (pwd->pw_passwd != NULL) 291158115Sume desired_size += strlen(pwd->pw_passwd) + 1; 292158115Sume if (pwd->pw_class != NULL) 293158115Sume desired_size += strlen(pwd->pw_class) + 1; 294158115Sume if (pwd->pw_gecos != NULL) 295158115Sume desired_size += strlen(pwd->pw_gecos) + 1; 296158115Sume if (pwd->pw_dir != NULL) 297158115Sume desired_size += strlen(pwd->pw_dir) + 1; 298158115Sume if (pwd->pw_shell != NULL) 299158115Sume desired_size += strlen(pwd->pw_shell) + 1; 300158115Sume 301158115Sume if (*buffer_size < desired_size) { 302158115Sume /* this assignment is here for future use */ 303158115Sume *buffer_size = desired_size; 304158115Sume return (NS_RETURN); 305158115Sume } 306158115Sume 307158115Sume memcpy(&new_pwd, pwd, sizeof(struct passwd)); 308158115Sume memset(buffer, 0, desired_size); 309158115Sume 310158115Sume *buffer_size = desired_size; 311158115Sume p = buffer + sizeof(struct passwd) + sizeof(char *); 312158115Sume memcpy(buffer + sizeof(struct passwd), &p, sizeof(char *)); 313158115Sume 314158115Sume if (new_pwd.pw_name != NULL) { 315158115Sume size = strlen(new_pwd.pw_name); 316158115Sume memcpy(p, new_pwd.pw_name, size); 317158115Sume new_pwd.pw_name = p; 318158115Sume p += size + 1; 319158115Sume } 320158115Sume 321158115Sume if (new_pwd.pw_passwd != NULL) { 322158115Sume size = strlen(new_pwd.pw_passwd); 323158115Sume memcpy(p, new_pwd.pw_passwd, size); 324158115Sume new_pwd.pw_passwd = p; 325158115Sume p += size + 1; 326158115Sume } 327158115Sume 328158115Sume if (new_pwd.pw_class != NULL) { 329158115Sume size = strlen(new_pwd.pw_class); 330158115Sume memcpy(p, new_pwd.pw_class, size); 331158115Sume new_pwd.pw_class = p; 332158115Sume p += size + 1; 333158115Sume } 334158115Sume 335158115Sume if (new_pwd.pw_gecos != NULL) { 336158115Sume size = strlen(new_pwd.pw_gecos); 337158115Sume memcpy(p, new_pwd.pw_gecos, size); 338158115Sume new_pwd.pw_gecos = p; 339158115Sume p += size + 1; 340158115Sume } 341158115Sume 342158115Sume if (new_pwd.pw_dir != NULL) { 343158115Sume size = strlen(new_pwd.pw_dir); 344158115Sume memcpy(p, new_pwd.pw_dir, size); 345158115Sume new_pwd.pw_dir = p; 346158115Sume p += size + 1; 347158115Sume } 348158115Sume 349158115Sume if (new_pwd.pw_shell != NULL) { 350158115Sume size = strlen(new_pwd.pw_shell); 351158115Sume memcpy(p, new_pwd.pw_shell, size); 352158115Sume new_pwd.pw_shell = p; 353158115Sume p += size + 1; 354158115Sume } 355158115Sume 356158115Sume memcpy(buffer, &new_pwd, sizeof(struct passwd)); 357158115Sume return (NS_SUCCESS); 358158115Sume} 359158115Sume 360158115Sumestatic int 361158115Sumepwd_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap, 362158115Sume void *cache_mdata) 363158115Sume{ 364158115Sume char *name; 365158115Sume uid_t uid; 366158115Sume struct passwd *pwd; 367158115Sume char *orig_buf; 368158115Sume size_t orig_buf_size; 369158115Sume int *ret_errno; 370158115Sume 371158115Sume char *p; 372158115Sume 373158115Sume switch ((enum nss_lookup_type)cache_mdata) { 374158115Sume case nss_lt_name: 375158115Sume name = va_arg(ap, char *); 376158115Sume break; 377158115Sume case nss_lt_id: 378158115Sume uid = va_arg(ap, uid_t); 379158115Sume break; 380158115Sume case nss_lt_all: 381158115Sume break; 382158115Sume default: 383158115Sume /* should be unreachable */ 384158115Sume return (NS_UNAVAIL); 385158115Sume } 386158115Sume 387158115Sume pwd = va_arg(ap, struct passwd *); 388158115Sume orig_buf = va_arg(ap, char *); 389158115Sume orig_buf_size = va_arg(ap, size_t); 390158115Sume ret_errno = va_arg(ap, int *); 391158115Sume 392158115Sume if (orig_buf_size < 393158115Sume buffer_size - sizeof(struct passwd) - sizeof(char *)) { 394158115Sume *ret_errno = ERANGE; 395158115Sume return (NS_RETURN); 396158115Sume } 397158115Sume 398158115Sume memcpy(pwd, buffer, sizeof(struct passwd)); 399158115Sume memcpy(&p, buffer + sizeof(struct passwd), sizeof(char *)); 400158115Sume memcpy(orig_buf, buffer + sizeof(struct passwd) + sizeof(char *), 401158115Sume buffer_size - sizeof(struct passwd) - sizeof(char *)); 402158115Sume 403158115Sume NS_APPLY_OFFSET(pwd->pw_name, orig_buf, p, char *); 404158115Sume NS_APPLY_OFFSET(pwd->pw_passwd, orig_buf, p, char *); 405158115Sume NS_APPLY_OFFSET(pwd->pw_class, orig_buf, p, char *); 406158115Sume NS_APPLY_OFFSET(pwd->pw_gecos, orig_buf, p, char *); 407158115Sume NS_APPLY_OFFSET(pwd->pw_dir, orig_buf, p, char *); 408158115Sume NS_APPLY_OFFSET(pwd->pw_shell, orig_buf, p, char *); 409158115Sume 410158115Sume if (retval != NULL) 411158115Sume *((struct passwd **)retval) = pwd; 412158115Sume 413158115Sume return (NS_SUCCESS); 414158115Sume} 415158115Sume 416158115SumeNSS_MP_CACHE_HANDLING(passwd); 417158115Sume#endif /* NS_CACHING */ 418158115Sume 419113596Snectarvoid 420113596Snectarsetpwent(void) 4211573Srgrimes{ 422158115Sume#ifdef NS_CACHING 423158115Sume static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 424158115Sume passwd, (void *)nss_lt_all, 425158115Sume NULL, NULL); 426158115Sume#endif 427158115Sume 428113596Snectar static const ns_dtab dtab[] = { 429113596Snectar { NSSRC_FILES, files_setpwent, (void *)SETPWENT }, 430113596Snectar#ifdef HESIOD 431113596Snectar { NSSRC_DNS, dns_setpwent, (void *)SETPWENT }, 432113596Snectar#endif 433113596Snectar#ifdef YP 434113596Snectar { NSSRC_NIS, nis_setpwent, (void *)SETPWENT }, 435113596Snectar#endif 436113596Snectar { NSSRC_COMPAT, compat_setpwent, (void *)SETPWENT }, 437158115Sume#ifdef NS_CACHING 438158115Sume NS_CACHE_CB(&cache_info) 439158115Sume#endif 440113596Snectar { NULL, NULL, NULL } 441113596Snectar }; 442113596Snectar (void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", defaultsrc, 0); 443113596Snectar} 4441573Srgrimes 44510521Swpaul 446113596Snectarint 447113596Snectarsetpassent(int stayopen) 448113596Snectar{ 449158115Sume#ifdef NS_CACHING 450158115Sume static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 451158115Sume passwd, (void *)nss_lt_all, 452158115Sume NULL, NULL); 453158115Sume#endif 454158115Sume 455113596Snectar static const ns_dtab dtab[] = { 456113596Snectar { NSSRC_FILES, files_setpwent, (void *)SETPWENT }, 457113596Snectar#ifdef HESIOD 458113596Snectar { NSSRC_DNS, dns_setpwent, (void *)SETPWENT }, 459113596Snectar#endif 460113596Snectar#ifdef YP 461113596Snectar { NSSRC_NIS, nis_setpwent, (void *)SETPWENT }, 462113596Snectar#endif 463113596Snectar { NSSRC_COMPAT, compat_setpwent, (void *)SETPWENT }, 464158115Sume#ifdef NS_CACHING 465158115Sume NS_CACHE_CB(&cache_info) 466158115Sume#endif 467113596Snectar { NULL, NULL, NULL } 468113596Snectar }; 469113596Snectar (void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", defaultsrc, 470113596Snectar stayopen); 471113596Snectar return (1); 472113596Snectar} 47365532Snectar 47465532Snectar 475113596Snectarvoid 476113596Snectarendpwent(void) 477113596Snectar{ 478158115Sume#ifdef NS_CACHING 479158115Sume static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 480158115Sume passwd, (void *)nss_lt_all, 481158115Sume NULL, NULL); 482158115Sume#endif 483158115Sume 484113596Snectar static const ns_dtab dtab[] = { 485113596Snectar { NSSRC_FILES, files_setpwent, (void *)ENDPWENT }, 486113596Snectar#ifdef HESIOD 487113596Snectar { NSSRC_DNS, dns_setpwent, (void *)ENDPWENT }, 488113596Snectar#endif 489113596Snectar#ifdef YP 490113596Snectar { NSSRC_NIS, nis_setpwent, (void *)ENDPWENT }, 491113596Snectar#endif 492113596Snectar { NSSRC_COMPAT, compat_setpwent, (void *)ENDPWENT }, 493158115Sume#ifdef NS_CACHING 494158115Sume NS_CACHE_CB(&cache_info) 495158115Sume#endif 496113596Snectar { NULL, NULL, NULL } 497113596Snectar }; 498113596Snectar (void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent", defaultsrc); 4991573Srgrimes} 5001573Srgrimes 501113596Snectar 502113596Snectarint 503113596Snectargetpwent_r(struct passwd *pwd, char *buffer, size_t bufsize, 504113596Snectar struct passwd **result) 5051573Srgrimes{ 506158115Sume#ifdef NS_CACHING 507158115Sume static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( 508158115Sume passwd, (void *)nss_lt_all, 509158115Sume pwd_marshal_func, pwd_unmarshal_func); 510158115Sume#endif 511158115Sume 512113596Snectar static const ns_dtab dtab[] = { 513113596Snectar { NSSRC_FILES, files_passwd, (void *)nss_lt_all }, 514113596Snectar#ifdef HESIOD 515113596Snectar { NSSRC_DNS, dns_passwd, (void *)nss_lt_all }, 516113596Snectar#endif 517113596Snectar#ifdef YP 518113596Snectar { NSSRC_NIS, nis_passwd, (void *)nss_lt_all }, 519113596Snectar#endif 520113596Snectar { NSSRC_COMPAT, compat_passwd, (void *)nss_lt_all }, 521158115Sume#ifdef NS_CACHING 522158115Sume NS_CACHE_CB(&cache_info) 523158115Sume#endif 524113596Snectar { NULL, NULL, NULL } 525113596Snectar }; 526113596Snectar int rv, ret_errno; 5271573Srgrimes 528113694Snectar pwd_init(pwd); 529113694Snectar ret_errno = 0; 530113596Snectar *result = NULL; 531113596Snectar rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwent_r", defaultsrc, 532113596Snectar pwd, buffer, bufsize, &ret_errno); 533113596Snectar if (rv == NS_SUCCESS) 534113596Snectar return (0); 535113596Snectar else 536113596Snectar return (ret_errno); 537113596Snectar} 5381573Srgrimes 5391573Srgrimes 540113596Snectarint 541113596Snectargetpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t bufsize, 542113596Snectar struct passwd **result) 543113596Snectar{ 544158115Sume#ifdef NS_CACHING 545158115Sume static const nss_cache_info cache_info = 546158115Sume NS_COMMON_CACHE_INFO_INITIALIZER( 547158115Sume passwd, (void *)nss_lt_name, 548158115Sume pwd_id_func, pwd_marshal_func, pwd_unmarshal_func); 549158115Sume#endif 550158115Sume 551113596Snectar static const ns_dtab dtab[] = { 552113596Snectar { NSSRC_FILES, files_passwd, (void *)nss_lt_name }, 553113596Snectar#ifdef HESIOD 554113596Snectar { NSSRC_DNS, dns_passwd, (void *)nss_lt_name }, 555113596Snectar#endif 556113596Snectar#ifdef YP 557113596Snectar { NSSRC_NIS, nis_passwd, (void *)nss_lt_name }, 558113596Snectar#endif 559113596Snectar { NSSRC_COMPAT, compat_passwd, (void *)nss_lt_name }, 560158115Sume#ifdef NS_CACHING 561158115Sume NS_CACHE_CB(&cache_info) 562158115Sume#endif 563113596Snectar { NULL, NULL, NULL } 564113596Snectar }; 565113596Snectar int rv, ret_errno; 566113596Snectar 567113694Snectar pwd_init(pwd); 568113694Snectar ret_errno = 0; 569113596Snectar *result = NULL; 570113596Snectar rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwnam_r", defaultsrc, 571113596Snectar name, pwd, buffer, bufsize, &ret_errno); 572113596Snectar if (rv == NS_SUCCESS) 573113596Snectar return (0); 574113596Snectar else 575113596Snectar return (ret_errno); 57665532Snectar} 5775714Swollman 578113596Snectar 579113596Snectarint 580113596Snectargetpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, 581113596Snectar struct passwd **result) 58265532Snectar{ 583158115Sume#ifdef NS_CACHING 584158115Sume static const nss_cache_info cache_info = 585158115Sume NS_COMMON_CACHE_INFO_INITIALIZER( 586158115Sume passwd, (void *)nss_lt_id, 587158115Sume pwd_id_func, pwd_marshal_func, pwd_unmarshal_func); 588158115Sume#endif 589158115Sume 590113596Snectar static const ns_dtab dtab[] = { 591113596Snectar { NSSRC_FILES, files_passwd, (void *)nss_lt_id }, 592113596Snectar#ifdef HESIOD 593113596Snectar { NSSRC_DNS, dns_passwd, (void *)nss_lt_id }, 594113596Snectar#endif 595113596Snectar#ifdef YP 596113596Snectar { NSSRC_NIS, nis_passwd, (void *)nss_lt_id }, 597113596Snectar#endif 598113596Snectar { NSSRC_COMPAT, compat_passwd, (void *)nss_lt_id }, 599158115Sume#ifdef NS_CACHING 600158115Sume NS_CACHE_CB(&cache_info) 601158115Sume#endif 602113596Snectar { NULL, NULL, NULL } 603113596Snectar }; 604113596Snectar int rv, ret_errno; 60565532Snectar 606113694Snectar pwd_init(pwd); 607113694Snectar ret_errno = 0; 608113596Snectar *result = NULL; 609113596Snectar rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwuid_r", defaultsrc, 610113596Snectar uid, pwd, buffer, bufsize, &ret_errno); 611113596Snectar if (rv == NS_SUCCESS) 612113596Snectar return (0); 613113596Snectar else 614113596Snectar return (ret_errno); 615113596Snectar} 61665532Snectar 61765532Snectar 618113694Snectarstatic void 619113694Snectarpwd_init(struct passwd *pwd) 620113672Snectar{ 621113694Snectar static char nul[] = ""; 622113672Snectar 623113672Snectar memset(pwd, 0, sizeof(*pwd)); 624113672Snectar pwd->pw_uid = (uid_t)-1; /* Considered least likely to lead to */ 625113672Snectar pwd->pw_gid = (gid_t)-1; /* a security issue. */ 626113694Snectar pwd->pw_name = nul; 627113694Snectar pwd->pw_passwd = nul; 628113694Snectar pwd->pw_class = nul; 629113694Snectar pwd->pw_gecos = nul; 630113694Snectar pwd->pw_dir = nul; 631113694Snectar pwd->pw_shell = nul; 632113672Snectar} 633113672Snectar 634113672Snectar 635113596Snectarstatic struct passwd pwd; 636113596Snectarstatic char *pwd_storage; 637113596Snectarstatic size_t pwd_storage_size; 63868577Snectar 63965532Snectar 640113596Snectarstatic struct passwd * 641113596Snectargetpw(int (*fn)(union key, struct passwd *, char *, size_t, struct passwd **), 642113596Snectar union key key) 643113596Snectar{ 644113596Snectar int rv; 645113596Snectar struct passwd *res; 64665532Snectar 647113596Snectar if (pwd_storage == NULL) { 648113596Snectar pwd_storage = malloc(PWD_STORAGE_INITIAL); 649113596Snectar if (pwd_storage == NULL) 650113596Snectar return (NULL); 651113596Snectar pwd_storage_size = PWD_STORAGE_INITIAL; 65268577Snectar } 653113596Snectar do { 654113596Snectar rv = fn(key, &pwd, pwd_storage, pwd_storage_size, &res); 655113596Snectar if (res == NULL && rv == ERANGE) { 656113596Snectar free(pwd_storage); 657113596Snectar if ((pwd_storage_size << 1) > PWD_STORAGE_MAX) { 658113596Snectar pwd_storage = NULL; 659129319Skientzle errno = ERANGE; 660113596Snectar return (NULL); 661113596Snectar } 662113596Snectar pwd_storage_size <<= 1; 663113596Snectar pwd_storage = malloc(pwd_storage_size); 664113596Snectar if (pwd_storage == NULL) 665113596Snectar return (NULL); 666113596Snectar } 667113596Snectar } while (res == NULL && rv == ERANGE); 668129349Skientzle if (rv != 0) 669129319Skientzle errno = rv; 670113596Snectar return (res); 671113596Snectar} 67265532Snectar 673113596Snectar 674113596Snectarstatic int 675113596Snectarwrap_getpwnam_r(union key key, struct passwd *pwd, char *buffer, 676113596Snectar size_t bufsize, struct passwd **res) 677113596Snectar{ 678113596Snectar return (getpwnam_r(key.name, pwd, buffer, bufsize, res)); 6791573Srgrimes} 6801573Srgrimes 681113596Snectar 68265532Snectarstatic int 683113596Snectarwrap_getpwuid_r(union key key, struct passwd *pwd, char *buffer, 684113596Snectar size_t bufsize, struct passwd **res) 6851573Srgrimes{ 686113596Snectar return (getpwuid_r(key.uid, pwd, buffer, bufsize, res)); 687113596Snectar} 6881573Srgrimes 6891573Srgrimes 690113596Snectarstatic int 691113596Snectarwrap_getpwent_r(union key key __unused, struct passwd *pwd, char *buffer, 692113596Snectar size_t bufsize, struct passwd **res) 693113596Snectar{ 694113596Snectar return (getpwent_r(pwd, buffer, bufsize, res)); 695113596Snectar} 6961573Srgrimes 69765532Snectar 698113596Snectarstruct passwd * 699113596Snectargetpwnam(const char *name) 700113596Snectar{ 701113596Snectar union key key; 70265532Snectar 703113596Snectar key.name = name; 704113596Snectar return (getpw(wrap_getpwnam_r, key)); 705113596Snectar} 7067258Swpaul 7071573Srgrimes 708113596Snectarstruct passwd * 709113596Snectargetpwuid(uid_t uid) 710113596Snectar{ 711113596Snectar union key key; 712113596Snectar 713113596Snectar key.uid = uid; 714113596Snectar return (getpw(wrap_getpwuid_r, key)); 7151573Srgrimes} 7161573Srgrimes 717113596Snectar 718113596Snectarstruct passwd * 719113596Snectargetpwent(void) 720113596Snectar{ 721113596Snectar union key key; 722113596Snectar 723113596Snectar key.uid = 0; /* not used */ 724113596Snectar return (getpw(wrap_getpwent_r, key)); 725113596Snectar} 726113596Snectar 727113596Snectar 72865532Snectar/* 729113596Snectar * files backend 73065532Snectar */ 731113596Snectarstatic DB * 732113596Snectarpwdbopen(int *version) 7331573Srgrimes{ 734113596Snectar DB *res; 735113596Snectar DBT key, entry; 736113596Snectar int rv; 7371573Srgrimes 738113596Snectar if (geteuid() != 0 || 739113596Snectar (res = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL)) == NULL) 740113596Snectar res = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL); 741113596Snectar if (res == NULL) 742113596Snectar return (NULL); 743113596Snectar key.data = _PWD_VERSION_KEY; 744113596Snectar key.size = strlen(_PWD_VERSION_KEY); 745113596Snectar rv = res->get(res, &key, &entry, 0); 746113596Snectar if (rv == 0) 747113596Snectar *version = *(unsigned char *)entry.data; 748113596Snectar else 749113596Snectar *version = 3; 750113596Snectar if (*version < 3 || 751113596Snectar *version >= sizeof(pwdb_versions)/sizeof(pwdb_versions[0])) { 752113596Snectar syslog(LOG_CRIT, "Unsupported password database version %d", 753113596Snectar *version); 754113596Snectar res->close(res); 755113596Snectar res = NULL; 75615267Swpaul } 757113596Snectar return (res); 758113596Snectar} 75965532Snectar 76065532Snectar 761113596Snectarstatic void 762113596Snectarfiles_endstate(void *p) 763113596Snectar{ 764113596Snectar DB *db; 765113596Snectar 766113596Snectar if (p == NULL) 767113596Snectar return; 768113596Snectar db = ((struct files_state *)p)->db; 769113596Snectar if (db != NULL) 770113596Snectar db->close(db); 771113596Snectar free(p); 772113596Snectar} 773113596Snectar 774113596Snectar 775113596Snectarstatic int 776113596Snectarfiles_setpwent(void *retval, void *mdata, va_list ap) 777113596Snectar{ 778113596Snectar struct files_state *st; 779113596Snectar int rv, stayopen; 780113596Snectar 781113596Snectar rv = files_getstate(&st); 782113596Snectar if (rv != 0) 783113596Snectar return (NS_UNAVAIL); 784113596Snectar switch ((enum constants)mdata) { 785113596Snectar case SETPWENT: 786113596Snectar stayopen = va_arg(ap, int); 787113596Snectar st->keynum = 0; 788113596Snectar if (stayopen) 789113596Snectar st->db = pwdbopen(&st->version); 790113596Snectar st->stayopen = stayopen; 791113596Snectar break; 792113596Snectar case ENDPWENT: 793113596Snectar if (st->db != NULL) { 794113596Snectar (void)st->db->close(st->db); 795113596Snectar st->db = NULL; 79665532Snectar } 797113596Snectar break; 798113596Snectar default: 799113596Snectar break; 80015267Swpaul } 801113596Snectar return (NS_UNAVAIL); 8021573Srgrimes} 8031573Srgrimes 80465532Snectar 80517141Sjkhstatic int 806113596Snectarfiles_passwd(void *retval, void *mdata, va_list ap) 8071573Srgrimes{ 808113596Snectar char keybuf[MAXLOGNAME + 1]; 809113596Snectar DBT key, entry; 810113596Snectar struct files_state *st; 811113596Snectar enum nss_lookup_type how; 812113596Snectar const char *name; 813113596Snectar struct passwd *pwd; 814113596Snectar char *buffer; 815113596Snectar size_t bufsize, namesize; 816113596Snectar uid_t uid; 817113596Snectar uint32_t store; 818113596Snectar int rv, stayopen, *errnop; 8191573Srgrimes 820113596Snectar name = NULL; 821113596Snectar uid = (uid_t)-1; 822113596Snectar how = (enum nss_lookup_type)mdata; 823113596Snectar switch (how) { 824113596Snectar case nss_lt_name: 82565532Snectar name = va_arg(ap, const char *); 826113596Snectar keybuf[0] = _PW_KEYBYNAME; 82765532Snectar break; 828113596Snectar case nss_lt_id: 82965532Snectar uid = va_arg(ap, uid_t); 830113596Snectar keybuf[0] = _PW_KEYBYUID; 83165532Snectar break; 832113596Snectar case nss_lt_all: 833113596Snectar keybuf[0] = _PW_KEYBYNUM; 834113596Snectar break; 83565532Snectar default: 836113596Snectar rv = NS_NOTFOUND; 837113596Snectar goto fin; 83865532Snectar } 839113596Snectar pwd = va_arg(ap, struct passwd *); 840113596Snectar buffer = va_arg(ap, char *); 841113596Snectar bufsize = va_arg(ap, size_t); 842113596Snectar errnop = va_arg(ap, int *); 843113596Snectar *errnop = files_getstate(&st); 844113596Snectar if (*errnop != 0) 845113596Snectar return (NS_UNAVAIL); 846113596Snectar if (how == nss_lt_all && st->keynum < 0) { 847113596Snectar rv = NS_NOTFOUND; 848113596Snectar goto fin; 84965532Snectar } 850113596Snectar if (st->db == NULL && 851113596Snectar (st->db = pwdbopen(&st->version)) == NULL) { 852113596Snectar *errnop = errno; 853113596Snectar rv = NS_UNAVAIL; 854113596Snectar goto fin; 85594688Sdes } 856113596Snectar if (how == nss_lt_all) 857113596Snectar stayopen = 1; 858113596Snectar else 859113596Snectar stayopen = st->stayopen; 860113596Snectar key.data = keybuf; 861113596Snectar do { 862113596Snectar switch (how) { 863113596Snectar case nss_lt_name: 864113596Snectar /* MAXLOGNAME includes NUL byte, but we do not 865113596Snectar * include the NUL byte in the key. 866113596Snectar */ 867114443Snectar namesize = strlcpy(&keybuf[1], name, sizeof(keybuf)-1); 868113596Snectar if (namesize >= sizeof(keybuf)-1) { 869113596Snectar *errnop = EINVAL; 870113596Snectar rv = NS_NOTFOUND; 871113596Snectar goto fin; 872113596Snectar } 873113596Snectar key.size = namesize + 1; 874113596Snectar break; 875113596Snectar case nss_lt_id: 876113596Snectar if (st->version < _PWD_CURRENT_VERSION) { 877113596Snectar memcpy(&keybuf[1], &uid, sizeof(uid)); 878113596Snectar key.size = sizeof(uid) + 1; 879113596Snectar } else { 880113596Snectar store = htonl(uid); 881113596Snectar memcpy(&keybuf[1], &store, sizeof(store)); 882113596Snectar key.size = sizeof(store) + 1; 883113596Snectar } 884113596Snectar break; 885113596Snectar case nss_lt_all: 886113596Snectar st->keynum++; 887113596Snectar if (st->version < _PWD_CURRENT_VERSION) { 888113596Snectar memcpy(&keybuf[1], &st->keynum, 889113596Snectar sizeof(st->keynum)); 890113596Snectar key.size = sizeof(st->keynum) + 1; 891113596Snectar } else { 892113596Snectar store = htonl(st->keynum); 893113596Snectar memcpy(&keybuf[1], &store, sizeof(store)); 894113596Snectar key.size = sizeof(store) + 1; 895113596Snectar } 896113596Snectar break; 897113596Snectar } 898113666Snectar keybuf[0] = _PW_VERSIONED(keybuf[0], st->version); 899113596Snectar rv = st->db->get(st->db, &key, &entry, 0); 900113596Snectar if (rv < 0 || rv > 1) { /* should never return > 1 */ 901113596Snectar *errnop = errno; 902113596Snectar rv = NS_UNAVAIL; 903113596Snectar goto fin; 904113596Snectar } else if (rv == 1) { 905113596Snectar if (how == nss_lt_all) 906113596Snectar st->keynum = -1; 907113596Snectar rv = NS_NOTFOUND; 908113596Snectar goto fin; 909113596Snectar } 910113596Snectar rv = pwdb_versions[st->version].match(entry.data, entry.size, 911113596Snectar how, name, uid); 912113596Snectar if (rv != NS_SUCCESS) 913113596Snectar continue; 914113596Snectar if (entry.size > bufsize) { 915113596Snectar *errnop = ERANGE; 916113596Snectar rv = NS_RETURN; 917113596Snectar break; 918113596Snectar } 919113596Snectar memcpy(buffer, entry.data, entry.size); 920113596Snectar rv = pwdb_versions[st->version].parse(buffer, entry.size, pwd, 921113596Snectar errnop); 922113596Snectar } while (how == nss_lt_all && !(rv & NS_TERMINATE)); 923113596Snectarfin: 924113596Snectar if (!stayopen && st->db != NULL) { 925113596Snectar (void)st->db->close(st->db); 926113596Snectar st->db = NULL; 927113596Snectar } 928113670Snectar if (rv == NS_SUCCESS) { 929113670Snectar pwd->pw_fields &= ~_PWF_SOURCE; 930113670Snectar pwd->pw_fields |= _PWF_FILES; 931113670Snectar if (retval != NULL) 932113670Snectar *(struct passwd **)retval = pwd; 933113670Snectar } 934113596Snectar return (rv); 9351573Srgrimes} 9361573Srgrimes 937113596Snectar 938113596Snectarstatic int 939124432Snectarpwdb_match_entry_v3(char *entry, size_t entrysize, enum nss_lookup_type how, 940113596Snectar const char *name, uid_t uid) 941113596Snectar{ 942113596Snectar const char *p, *eom; 943113596Snectar uid_t uid2; 944113596Snectar 945113596Snectar eom = &entry[entrysize]; 946113596Snectar for (p = entry; p < eom; p++) 947113596Snectar if (*p == '\0') 948113596Snectar break; 949113596Snectar if (*p != '\0') 950113596Snectar return (NS_NOTFOUND); 951113596Snectar if (how == nss_lt_all) 952113596Snectar return (NS_SUCCESS); 953124432Snectar if (how == nss_lt_name) 954113596Snectar return (strcmp(name, entry) == 0 ? NS_SUCCESS : NS_NOTFOUND); 955113596Snectar for (p++; p < eom; p++) 956113596Snectar if (*p == '\0') 957113596Snectar break; 958113596Snectar if (*p != '\0' || (++p) + sizeof(uid) >= eom) 959113596Snectar return (NS_NOTFOUND); 960113596Snectar memcpy(&uid2, p, sizeof(uid2)); 961113596Snectar return (uid == uid2 ? NS_SUCCESS : NS_NOTFOUND); 962113596Snectar} 963113596Snectar 964113596Snectar 965113596Snectarstatic int 966113596Snectarpwdb_parse_entry_v3(char *buffer, size_t bufsize, struct passwd *pwd, 967113596Snectar int *errnop) 968113596Snectar{ 969113596Snectar char *p, *eom; 970113596Snectar int32_t pw_change, pw_expire; 971113596Snectar 972113596Snectar /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */ 973113596Snectar p = buffer; 974113596Snectar eom = &buffer[bufsize]; 975113596Snectar#define STRING(field) do { \ 976113596Snectar (field) = p; \ 977113596Snectar while (p < eom && *p != '\0') \ 978113596Snectar p++; \ 979113596Snectar if (p >= eom) \ 980113596Snectar return (NS_NOTFOUND); \ 981113596Snectar p++; \ 982113596Snectar } while (0) 983113596Snectar#define SCALAR(field) do { \ 984113596Snectar if (p + sizeof(field) > eom) \ 985113596Snectar return (NS_NOTFOUND); \ 986113596Snectar memcpy(&(field), p, sizeof(field)); \ 987113596Snectar p += sizeof(field); \ 988113596Snectar } while (0) 989113596Snectar STRING(pwd->pw_name); 990113596Snectar STRING(pwd->pw_passwd); 991113596Snectar SCALAR(pwd->pw_uid); 992113596Snectar SCALAR(pwd->pw_gid); 993113596Snectar SCALAR(pw_change); 994113596Snectar STRING(pwd->pw_class); 995113596Snectar STRING(pwd->pw_gecos); 996113596Snectar STRING(pwd->pw_dir); 997113596Snectar STRING(pwd->pw_shell); 998113596Snectar SCALAR(pw_expire); 999113596Snectar SCALAR(pwd->pw_fields); 1000113596Snectar#undef STRING 1001113596Snectar#undef SCALAR 1002113596Snectar pwd->pw_change = pw_change; 1003113596Snectar pwd->pw_expire = pw_expire; 1004113596Snectar return (NS_SUCCESS); 1005113596Snectar} 1006113596Snectar 1007113596Snectar 1008113596Snectarstatic int 1009124432Snectarpwdb_match_entry_v4(char *entry, size_t entrysize, enum nss_lookup_type how, 1010113596Snectar const char *name, uid_t uid) 1011113596Snectar{ 1012113596Snectar const char *p, *eom; 1013113596Snectar uint32_t uid2; 1014113596Snectar 1015113596Snectar eom = &entry[entrysize]; 1016113596Snectar for (p = entry; p < eom; p++) 1017113596Snectar if (*p == '\0') 1018113596Snectar break; 1019113596Snectar if (*p != '\0') 1020113596Snectar return (NS_NOTFOUND); 1021113596Snectar if (how == nss_lt_all) 1022113596Snectar return (NS_SUCCESS); 1023124432Snectar if (how == nss_lt_name) 1024113596Snectar return (strcmp(name, entry) == 0 ? NS_SUCCESS : NS_NOTFOUND); 1025113596Snectar for (p++; p < eom; p++) 1026113596Snectar if (*p == '\0') 1027113596Snectar break; 1028113596Snectar if (*p != '\0' || (++p) + sizeof(uid) >= eom) 1029113596Snectar return (NS_NOTFOUND); 1030113596Snectar memcpy(&uid2, p, sizeof(uid2)); 1031113596Snectar uid2 = ntohl(uid2); 1032113596Snectar return (uid == (uid_t)uid2 ? NS_SUCCESS : NS_NOTFOUND); 1033113596Snectar} 1034113596Snectar 1035113596Snectar 1036113596Snectarstatic int 1037113596Snectarpwdb_parse_entry_v4(char *buffer, size_t bufsize, struct passwd *pwd, 1038113596Snectar int *errnop) 1039113596Snectar{ 1040113596Snectar char *p, *eom; 1041113596Snectar uint32_t n; 1042113596Snectar 1043113596Snectar /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */ 1044113596Snectar p = buffer; 1045113596Snectar eom = &buffer[bufsize]; 1046113596Snectar#define STRING(field) do { \ 1047113596Snectar (field) = p; \ 1048113596Snectar while (p < eom && *p != '\0') \ 1049113596Snectar p++; \ 1050113596Snectar if (p >= eom) \ 1051113596Snectar return (NS_NOTFOUND); \ 1052113596Snectar p++; \ 1053113596Snectar } while (0) 1054113596Snectar#define SCALAR(field) do { \ 1055113596Snectar if (p + sizeof(n) > eom) \ 1056113596Snectar return (NS_NOTFOUND); \ 1057113596Snectar memcpy(&n, p, sizeof(n)); \ 1058113596Snectar (field) = ntohl(n); \ 1059113596Snectar p += sizeof(n); \ 1060113596Snectar } while (0) 1061113596Snectar STRING(pwd->pw_name); 1062113596Snectar STRING(pwd->pw_passwd); 1063113596Snectar SCALAR(pwd->pw_uid); 1064113596Snectar SCALAR(pwd->pw_gid); 1065113596Snectar SCALAR(pwd->pw_change); 1066113596Snectar STRING(pwd->pw_class); 1067113596Snectar STRING(pwd->pw_gecos); 1068113596Snectar STRING(pwd->pw_dir); 1069113596Snectar STRING(pwd->pw_shell); 1070113596Snectar SCALAR(pwd->pw_expire); 1071113596Snectar SCALAR(pwd->pw_fields); 1072113596Snectar#undef STRING 1073113596Snectar#undef SCALAR 1074113596Snectar return (NS_SUCCESS); 1075113596Snectar} 1076113596Snectar 1077113596Snectar 107865532Snectar#ifdef HESIOD 107965532Snectar/* 1080113596Snectar * dns backend 108165532Snectar */ 1082113596Snectarstatic void 1083113596Snectardns_endstate(void *p) 1084113596Snectar{ 1085113596Snectar free(p); 1086113596Snectar} 108765532Snectar 1088113596Snectar 108917141Sjkhstatic int 1090113596Snectardns_setpwent(void *retval, void *mdata, va_list ap) 10911573Srgrimes{ 1092113596Snectar struct dns_state *st; 1093113596Snectar int rv; 10941573Srgrimes 1095113596Snectar rv = dns_getstate(&st); 1096113596Snectar if (rv != 0) 1097113596Snectar return (NS_UNAVAIL); 1098113596Snectar st->counter = 0; 1099113596Snectar return (NS_UNAVAIL); 1100113596Snectar} 11011573Srgrimes 1102113596Snectar 1103113596Snectarstatic int 1104113596Snectardns_passwd(void *retval, void *mdata, va_list ap) 1105113596Snectar{ 1106113596Snectar char buf[HESIOD_NAME_MAX]; 1107113596Snectar struct dns_state *st; 1108113596Snectar struct passwd *pwd; 1109113596Snectar const char *name, *label; 1110113596Snectar void *ctx; 1111113596Snectar char *buffer, **hes; 1112113596Snectar size_t bufsize, linesize; 1113113596Snectar uid_t uid; 1114113596Snectar enum nss_lookup_type how; 1115113596Snectar int rv, *errnop; 1116113596Snectar 1117113596Snectar ctx = NULL; 1118113596Snectar hes = NULL; 1119113596Snectar name = NULL; 1120113596Snectar uid = (uid_t)-1; 1121113596Snectar how = (enum nss_lookup_type)mdata; 1122113596Snectar switch (how) { 1123113596Snectar case nss_lt_name: 112465532Snectar name = va_arg(ap, const char *); 112565532Snectar break; 1126113596Snectar case nss_lt_id: 112765532Snectar uid = va_arg(ap, uid_t); 112865532Snectar break; 1129113596Snectar case nss_lt_all: 1130113596Snectar break; 113129479Swosch } 1132113596Snectar pwd = va_arg(ap, struct passwd *); 1133113596Snectar buffer = va_arg(ap, char *); 1134113596Snectar bufsize = va_arg(ap, size_t); 1135113596Snectar errnop = va_arg(ap, int *); 1136113596Snectar *errnop = dns_getstate(&st); 1137113596Snectar if (*errnop != 0) 1138113596Snectar return (NS_UNAVAIL); 1139113596Snectar if (hesiod_init(&ctx) != 0) { 1140113596Snectar *errnop = errno; 1141113596Snectar rv = NS_UNAVAIL; 1142113596Snectar goto fin; 1143113596Snectar } 1144113596Snectar do { 1145113596Snectar rv = NS_NOTFOUND; 1146113596Snectar switch (how) { 1147113596Snectar case nss_lt_name: 1148113596Snectar label = name; 1149113596Snectar break; 1150113596Snectar case nss_lt_id: 1151113596Snectar if (snprintf(buf, sizeof(buf), "%lu", 1152113596Snectar (unsigned long)uid) >= sizeof(buf)) 1153113596Snectar goto fin; 1154113596Snectar label = buf; 1155113596Snectar break; 1156113596Snectar case nss_lt_all: 1157113596Snectar if (st->counter < 0) 1158113596Snectar goto fin; 1159113596Snectar if (snprintf(buf, sizeof(buf), "passwd-%ld", 1160113596Snectar st->counter++) >= sizeof(buf)) 1161113596Snectar goto fin; 1162113596Snectar label = buf; 1163113596Snectar break; 116465532Snectar } 1165113596Snectar hes = hesiod_resolve(ctx, label, 1166113596Snectar how == nss_lt_id ? "uid" : "passwd"); 1167113596Snectar if (hes == NULL) { 1168113596Snectar if (how == nss_lt_all) 1169113596Snectar st->counter = -1; 1170113596Snectar if (errno != ENOENT) 1171113596Snectar *errnop = errno; 1172113596Snectar goto fin; 1173113596Snectar } 1174113596Snectar rv = __pw_match_entry(hes[0], strlen(hes[0]), how, name, uid); 1175113596Snectar if (rv != NS_SUCCESS) { 1176113596Snectar hesiod_free_list(ctx, hes); 1177113596Snectar hes = NULL; 1178113596Snectar continue; 1179113596Snectar } 1180114443Snectar linesize = strlcpy(buffer, hes[0], bufsize); 1181113596Snectar if (linesize >= bufsize) { 1182113596Snectar *errnop = ERANGE; 1183113596Snectar rv = NS_RETURN; 1184113596Snectar continue; 1185113596Snectar } 1186113596Snectar hesiod_free_list(ctx, hes); 1187113596Snectar hes = NULL; 1188113596Snectar rv = __pw_parse_entry(buffer, bufsize, pwd, 0, errnop); 1189113596Snectar } while (how == nss_lt_all && !(rv & NS_TERMINATE)); 1190113596Snectarfin: 1191113596Snectar if (hes != NULL) 1192113596Snectar hesiod_free_list(ctx, hes); 1193113596Snectar if (ctx != NULL) 1194113596Snectar hesiod_end(ctx); 1195113596Snectar if (rv == NS_SUCCESS) { 1196113596Snectar pwd->pw_fields &= ~_PWF_SOURCE; 1197113596Snectar pwd->pw_fields |= _PWF_HESIOD; 1198113596Snectar if (retval != NULL) 1199113596Snectar *(struct passwd **)retval = pwd; 120065532Snectar } 1201113596Snectar return (rv); 120215267Swpaul} 1203113596Snectar#endif /* HESIOD */ 12047258Swpaul 1205113596Snectar 120665532Snectar#ifdef YP 120715267Swpaul/* 1208113596Snectar * nis backend 120915267Swpaul */ 1210113596Snectarstatic void 1211113596Snectarnis_endstate(void *p) 1212113596Snectar{ 1213113596Snectar free(((struct nis_state *)p)->key); 1214113596Snectar free(p); 1215113596Snectar} 121665532Snectar 1217117750Swpaul/* 1218117750Swpaul * Test for the presence of special FreeBSD-specific master.passwd.by* 1219117750Swpaul * maps. We do this using yp_order(). If it fails, then either the server 1220117750Swpaul * doesn't have the map, or the YPPROC_ORDER procedure isn't supported by 1221117750Swpaul * the server (Sun NIS+ servers in YP compat mode behave this way). If 1222117750Swpaul * the master.passwd.by* maps don't exist, then let the lookup routine try 1223117750Swpaul * the regular passwd.by* maps instead. If the lookup routine fails, it 1224117750Swpaul * can return an error as needed. 1225117750Swpaul */ 122665532Snectarstatic int 1227113596Snectarnis_map(char *domain, enum nss_lookup_type how, char *buffer, size_t bufsize, 1228113596Snectar int *master) 122915267Swpaul{ 1230117750Swpaul int rv, order; 12317258Swpaul 1232113596Snectar *master = 0; 1233113794Snectar if (geteuid() == 0) { 1234113794Snectar if (snprintf(buffer, bufsize, "master.passwd.by%s", 1235113794Snectar (how == nss_lt_id) ? "uid" : "name") >= bufsize) 1236113794Snectar return (NS_UNAVAIL); 1237117750Swpaul rv = yp_order(domain, buffer, &order); 1238113794Snectar if (rv == 0) { 1239113794Snectar *master = 1; 1240113794Snectar return (NS_SUCCESS); 1241113794Snectar } 124265532Snectar } 1243117750Swpaul 1244113596Snectar if (snprintf(buffer, bufsize, "passwd.by%s", 1245113596Snectar (how == nss_lt_id) ? "uid" : "name") >= bufsize) 1246113596Snectar return (NS_UNAVAIL); 1247117750Swpaul 1248117750Swpaul return (NS_SUCCESS); 1249113596Snectar} 125015267Swpaul 1251113596Snectar 1252113596Snectarstatic int 1253113596Snectarnis_adjunct(char *domain, const char *name, char *buffer, size_t bufsize) 1254113596Snectar{ 1255113596Snectar int rv; 1256113596Snectar char *result, *p, *q, *eor; 1257113596Snectar int resultlen; 1258113596Snectar 1259113596Snectar result = NULL; 1260113596Snectar rv = yp_match(domain, "passwd.adjunct.byname", name, strlen(name), 1261113596Snectar &result, &resultlen); 1262113596Snectar if (rv != 0) 1263113596Snectar rv = 1; 1264113596Snectar else { 1265113596Snectar eor = &result[resultlen]; 1266113596Snectar p = memchr(result, ':', eor - result); 1267113596Snectar if (p != NULL && ++p < eor && 1268113596Snectar (q = memchr(p, ':', eor - p)) != NULL) { 1269113596Snectar if (q - p >= bufsize) 1270113596Snectar rv = -1; 1271113596Snectar else { 1272113596Snectar memcpy(buffer, p, q - p); 1273113596Snectar buffer[q - p] ='\0'; 1274113596Snectar } 1275113596Snectar } else 1276113596Snectar rv = 1; 1277124432Snectar } 1278113596Snectar free(result); 1279113596Snectar return (rv); 1280113596Snectar} 1281113596Snectar 1282113596Snectar 1283113596Snectarstatic int 1284113596Snectarnis_setpwent(void *retval, void *mdata, va_list ap) 1285113596Snectar{ 1286113596Snectar struct nis_state *st; 1287113596Snectar int rv; 1288113596Snectar 1289113596Snectar rv = nis_getstate(&st); 1290113596Snectar if (rv != 0) 1291113596Snectar return (NS_UNAVAIL); 1292113596Snectar st->done = 0; 1293113596Snectar free(st->key); 1294113596Snectar st->key = NULL; 1295113596Snectar return (NS_UNAVAIL); 1296113596Snectar} 1297113596Snectar 1298113596Snectar 1299113596Snectarstatic int 1300113596Snectarnis_passwd(void *retval, void *mdata, va_list ap) 1301113596Snectar{ 1302113596Snectar char map[YPMAXMAP]; 1303113596Snectar struct nis_state *st; 1304113596Snectar struct passwd *pwd; 1305113596Snectar const char *name; 1306113596Snectar char *buffer, *key, *result; 1307113596Snectar size_t bufsize; 1308113596Snectar uid_t uid; 1309113596Snectar enum nss_lookup_type how; 1310113596Snectar int *errnop, keylen, resultlen, rv, master; 1311124432Snectar 1312113596Snectar name = NULL; 1313113596Snectar uid = (uid_t)-1; 1314113596Snectar how = (enum nss_lookup_type)mdata; 1315113596Snectar switch (how) { 1316113596Snectar case nss_lt_name: 131765532Snectar name = va_arg(ap, const char *); 131865532Snectar break; 1319113596Snectar case nss_lt_id: 132065532Snectar uid = va_arg(ap, uid_t); 132165532Snectar break; 1322113596Snectar case nss_lt_all: 1323113596Snectar break; 132465532Snectar } 1325113596Snectar pwd = va_arg(ap, struct passwd *); 1326113596Snectar buffer = va_arg(ap, char *); 1327113596Snectar bufsize = va_arg(ap, size_t); 1328113596Snectar errnop = va_arg(ap, int *); 1329113596Snectar *errnop = nis_getstate(&st); 1330113596Snectar if (*errnop != 0) 1331113596Snectar return (NS_UNAVAIL); 1332113596Snectar if (st->domain[0] == '\0') { 1333113596Snectar if (getdomainname(st->domain, sizeof(st->domain)) != 0) { 1334113596Snectar *errnop = errno; 1335113596Snectar return (NS_UNAVAIL); 133665532Snectar } 133765532Snectar } 1338113596Snectar rv = nis_map(st->domain, how, map, sizeof(map), &master); 1339113596Snectar if (rv != NS_SUCCESS) 1340113596Snectar return (rv); 1341113596Snectar result = NULL; 1342113596Snectar do { 1343113596Snectar rv = NS_NOTFOUND; 1344113596Snectar switch (how) { 1345113596Snectar case nss_lt_name: 1346114443Snectar if (strlcpy(buffer, name, bufsize) >= bufsize) 1347113596Snectar goto erange; 1348113596Snectar break; 1349113596Snectar case nss_lt_id: 1350113596Snectar if (snprintf(buffer, bufsize, "%lu", 1351113596Snectar (unsigned long)uid) >= bufsize) 1352113596Snectar goto erange; 1353113596Snectar break; 1354113596Snectar case nss_lt_all: 1355113596Snectar if (st->done) 1356113596Snectar goto fin; 1357113596Snectar break; 1358113596Snectar } 1359113596Snectar result = NULL; 1360113596Snectar if (how == nss_lt_all) { 1361113596Snectar if (st->key == NULL) 1362113596Snectar rv = yp_first(st->domain, map, &st->key, 1363113596Snectar &st->keylen, &result, &resultlen); 1364113596Snectar else { 1365113596Snectar key = st->key; 1366113596Snectar keylen = st->keylen; 1367113596Snectar st->key = NULL; 1368113596Snectar rv = yp_next(st->domain, map, key, keylen, 1369113596Snectar &st->key, &st->keylen, &result, 1370113596Snectar &resultlen); 1371113596Snectar free(key); 137265532Snectar } 1373113596Snectar if (rv != 0) { 1374113596Snectar free(result); 1375113596Snectar free(st->key); 1376113596Snectar st->key = NULL; 1377113596Snectar if (rv == YPERR_NOMORE) 1378113596Snectar st->done = 1; 1379113596Snectar else 1380113596Snectar rv = NS_UNAVAIL; 1381113596Snectar goto fin; 1382113596Snectar } 138365532Snectar } else { 1384113596Snectar rv = yp_match(st->domain, map, buffer, strlen(buffer), 1385113596Snectar &result, &resultlen); 1386113596Snectar if (rv == YPERR_KEY) { 1387113596Snectar rv = NS_NOTFOUND; 1388113596Snectar continue; 1389113596Snectar } else if (rv != 0) { 1390113596Snectar free(result); 1391113596Snectar rv = NS_UNAVAIL; 1392113596Snectar continue; 1393113596Snectar } 139465532Snectar } 1395113596Snectar if (resultlen >= bufsize) 1396113596Snectar goto erange; 1397113596Snectar memcpy(buffer, result, resultlen); 1398113596Snectar buffer[resultlen] = '\0'; 1399113596Snectar free(result); 1400113596Snectar rv = __pw_match_entry(buffer, resultlen, how, name, uid); 1401113596Snectar if (rv == NS_SUCCESS) 1402113596Snectar rv = __pw_parse_entry(buffer, resultlen, pwd, master, 1403113596Snectar errnop); 1404113596Snectar } while (how == nss_lt_all && !(rv & NS_TERMINATE)); 1405124432Snectarfin: 1406113596Snectar if (rv == NS_SUCCESS) { 1407113596Snectar if (strstr(pwd->pw_passwd, "##") != NULL) { 1408124431Snectar rv = nis_adjunct(st->domain, pwd->pw_name, 1409113596Snectar &buffer[resultlen+1], bufsize-resultlen-1); 1410113596Snectar if (rv < 0) 1411113596Snectar goto erange; 1412113596Snectar else if (rv == 0) 1413113596Snectar pwd->pw_passwd = &buffer[resultlen+1]; 141465532Snectar } 1415113596Snectar pwd->pw_fields &= ~_PWF_SOURCE; 1416113596Snectar pwd->pw_fields |= _PWF_NIS; 1417113596Snectar if (retval != NULL) 1418113596Snectar *(struct passwd **)retval = pwd; 1419128537Sjon rv = NS_SUCCESS; 142015267Swpaul } 1421124432Snectar return (rv); 1422113596Snectarerange: 1423113596Snectar *errnop = ERANGE; 1424113596Snectar return (NS_RETURN); 1425113596Snectar} 1426113596Snectar#endif /* YP */ 142715267Swpaul 1428113596Snectar 142915267Swpaul/* 1430113596Snectar * compat backend 143115267Swpaul */ 1432113596Snectarstatic void 1433113596Snectarcompat_clear_template(struct passwd *template) 1434113596Snectar{ 143565532Snectar 1436113596Snectar free(template->pw_passwd); 1437113596Snectar free(template->pw_gecos); 1438113596Snectar free(template->pw_dir); 1439113596Snectar free(template->pw_shell); 1440113596Snectar memset(template, 0, sizeof(*template)); 1441113596Snectar} 1442113596Snectar 1443113596Snectar 144465532Snectarstatic int 1445113596Snectarcompat_set_template(struct passwd *src, struct passwd *template) 144615267Swpaul{ 144715267Swpaul 1448113596Snectar compat_clear_template(template); 1449113596Snectar#ifdef PW_OVERRIDE_PASSWD 1450113596Snectar if ((src->pw_fields & _PWF_PASSWD) && 1451113596Snectar (template->pw_passwd = strdup(src->pw_passwd)) == NULL) 1452113596Snectar goto enomem; 1453113596Snectar#endif 1454113596Snectar if (src->pw_fields & _PWF_UID) 1455113596Snectar template->pw_uid = src->pw_uid; 1456113596Snectar if (src->pw_fields & _PWF_GID) 1457113596Snectar template->pw_gid = src->pw_gid; 1458113596Snectar if ((src->pw_fields & _PWF_GECOS) && 1459113596Snectar (template->pw_gecos = strdup(src->pw_gecos)) == NULL) 1460113596Snectar goto enomem; 1461113596Snectar if ((src->pw_fields & _PWF_DIR) && 1462113596Snectar (template->pw_dir = strdup(src->pw_dir)) == NULL) 1463113596Snectar goto enomem; 1464113596Snectar if ((src->pw_fields & _PWF_SHELL) && 1465113596Snectar (template->pw_shell = strdup(src->pw_shell)) == NULL) 1466113596Snectar goto enomem; 1467113596Snectar template->pw_fields = src->pw_fields; 1468113596Snectar return (0); 1469113596Snectarenomem: 1470113596Snectar syslog(LOG_ERR, "getpwent memory allocation failure"); 1471113596Snectar return (-1); 1472113596Snectar} 147315267Swpaul 147415267Swpaul 1475113596Snectarstatic int 1476113596Snectarcompat_use_template(struct passwd *pwd, struct passwd *template, char *buffer, 1477113596Snectar size_t bufsize) 1478113596Snectar{ 1479113596Snectar struct passwd hold; 1480113596Snectar char *copy, *p, *q, *eob; 1481113596Snectar size_t n; 1482113596Snectar 1483113596Snectar /* We cannot know the layout of the password fields in `buffer', 1484113596Snectar * so we have to copy everything. 1485113596Snectar */ 1486113596Snectar if (template->pw_fields == 0) /* nothing to fill-in */ 1487113596Snectar return (0); 1488113596Snectar n = 0; 1489113596Snectar n += pwd->pw_name != NULL ? strlen(pwd->pw_name) + 1 : 0; 1490113596Snectar n += pwd->pw_passwd != NULL ? strlen(pwd->pw_passwd) + 1 : 0; 1491113596Snectar n += pwd->pw_class != NULL ? strlen(pwd->pw_class) + 1 : 0; 1492113596Snectar n += pwd->pw_gecos != NULL ? strlen(pwd->pw_gecos) + 1 : 0; 1493113596Snectar n += pwd->pw_dir != NULL ? strlen(pwd->pw_dir) + 1 : 0; 1494113596Snectar n += pwd->pw_shell != NULL ? strlen(pwd->pw_shell) + 1 : 0; 1495113596Snectar copy = malloc(n); 1496113596Snectar if (copy == NULL) { 1497113596Snectar syslog(LOG_ERR, "getpwent memory allocation failure"); 1498113596Snectar return (ENOMEM); 1499113596Snectar } 1500113596Snectar p = copy; 1501113596Snectar eob = ©[n]; 1502113596Snectar#define COPY(field) do { \ 1503113596Snectar if (pwd->field == NULL) \ 1504113596Snectar hold.field = NULL; \ 1505113596Snectar else { \ 1506113596Snectar hold.field = p; \ 1507114443Snectar p += strlcpy(p, pwd->field, eob-p) + 1; \ 1508113596Snectar } \ 1509113596Snectar} while (0) 1510113596Snectar COPY(pw_name); 1511113596Snectar COPY(pw_passwd); 1512113596Snectar COPY(pw_class); 1513113596Snectar COPY(pw_gecos); 1514113596Snectar COPY(pw_dir); 1515113596Snectar COPY(pw_shell); 1516113596Snectar#undef COPY 1517113596Snectar p = buffer; 1518113596Snectar eob = &buffer[bufsize]; 1519113596Snectar#define COPY(field, flag) do { \ 1520113596Snectar q = (template->pw_fields & flag) ? template->field : hold.field; \ 1521113596Snectar if (q == NULL) \ 1522113596Snectar pwd->field = NULL; \ 1523113596Snectar else { \ 1524113596Snectar pwd->field = p; \ 1525114443Snectar if ((n = strlcpy(p, q, eob-p)) >= eob-p) { \ 1526113596Snectar free(copy); \ 1527113596Snectar return (ERANGE); \ 1528113596Snectar } \ 1529113596Snectar p += n + 1; \ 1530113596Snectar } \ 1531113596Snectar} while (0) 1532113596Snectar COPY(pw_name, 0); 1533113596Snectar#ifdef PW_OVERRIDE_PASSWD 1534113596Snectar COPY(pw_passwd, _PWF_PASSWD); 1535113596Snectar#else 1536113596Snectar COPY(pw_passwd, 0); 1537113596Snectar#endif 1538113596Snectar COPY(pw_class, 0); 1539113596Snectar COPY(pw_gecos, _PWF_GECOS); 1540113596Snectar COPY(pw_dir, _PWF_DIR); 1541113596Snectar COPY(pw_shell, _PWF_SHELL); 1542113596Snectar#undef COPY 1543113596Snectar#define COPY(field, flag) do { \ 1544113596Snectar if (template->pw_fields & flag) \ 1545113596Snectar pwd->field = template->field; \ 1546113596Snectar} while (0) 1547113596Snectar COPY(pw_uid, _PWF_UID); 1548113596Snectar COPY(pw_gid, _PWF_GID); 1549113596Snectar#undef COPY 1550113596Snectar free(copy); 1551113596Snectar return (0); 155215267Swpaul} 155315267Swpaul 155465532Snectar 155565532Snectarstatic int 1556113596Snectarcompat_exclude(const char *name, DB **db) 155715267Swpaul{ 1558113596Snectar DBT key, data; 1559113596Snectar 1560113596Snectar if (*db == NULL && 1561113596Snectar (*db = dbopen(NULL, O_RDWR, 600, DB_HASH, 0)) == NULL) 1562113596Snectar return (errno); 1563113596Snectar key.size = strlen(name); 1564113596Snectar key.data = (char *)name; 1565113596Snectar data.size = 0; 1566113596Snectar data.data = NULL; 1567113596Snectar 1568113596Snectar if ((*db)->put(*db, &key, &data, 0) == -1) 1569113596Snectar return (errno); 1570113596Snectar return (0); 15717258Swpaul} 15727258Swpaul 157365532Snectar 157465532Snectarstatic int 1575113596Snectarcompat_is_excluded(const char *name, DB *db) 15767258Swpaul{ 1577113596Snectar DBT key, data; 15787258Swpaul 1579113596Snectar if (db == NULL) 1580113596Snectar return (0); 1581113596Snectar key.size = strlen(name); 1582113596Snectar key.data = (char *)name; 1583113596Snectar return (db->get(db, &key, &data, 0) == 0); 15847258Swpaul} 15857258Swpaul 158665532Snectar 158765532Snectarstatic int 1588113596Snectarcompat_redispatch(struct compat_state *st, enum nss_lookup_type how, 1589113596Snectar enum nss_lookup_type lookup_how, const char *name, const char *lookup_name, 1590113596Snectar uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, int *errnop) 159110521Swpaul{ 1592113596Snectar static const ns_src compatsrc[] = { 1593113596Snectar#ifdef YP 1594113596Snectar { NSSRC_NIS, NS_SUCCESS }, 159565532Snectar#endif 1596113596Snectar { NULL, 0 } 1597113596Snectar }; 1598113596Snectar ns_dtab dtab[] = { 1599113596Snectar#ifdef YP 1600113596Snectar { NSSRC_NIS, nis_passwd, NULL }, 1601113596Snectar#endif 1602113596Snectar#ifdef HESIOD 1603113596Snectar { NSSRC_DNS, dns_passwd, NULL }, 1604113596Snectar#endif 1605113596Snectar { NULL, NULL, NULL } 1606113596Snectar }; 1607113596Snectar void *discard; 1608113596Snectar int rv, e, i; 160910521Swpaul 1610113596Snectar for (i = 0; i < sizeof(dtab)/sizeof(dtab[0]) - 1; i++) 1611113596Snectar dtab[i].mdata = (void *)lookup_how; 1612113596Snectarmore: 1613113992Snectar pwd_init(pwd); 1614113596Snectar switch (lookup_how) { 1615113596Snectar case nss_lt_all: 1616113596Snectar rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT, 1617113596Snectar "getpwent_r", compatsrc, pwd, buffer, bufsize, 1618113596Snectar errnop); 1619113596Snectar break; 1620113596Snectar case nss_lt_id: 1621113596Snectar rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT, 1622113596Snectar "getpwuid_r", compatsrc, uid, pwd, buffer, 1623113596Snectar bufsize, errnop); 1624113596Snectar break; 1625113596Snectar case nss_lt_name: 1626113596Snectar rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT, 1627113596Snectar "getpwnam_r", compatsrc, lookup_name, pwd, buffer, 1628113596Snectar bufsize, errnop); 1629113596Snectar break; 1630113596Snectar default: 1631113596Snectar return (NS_UNAVAIL); 1632113596Snectar } 1633113596Snectar if (rv != NS_SUCCESS) 1634113596Snectar return (rv); 1635113596Snectar if (compat_is_excluded(pwd->pw_name, st->exclude)) { 1636113596Snectar if (how == nss_lt_all) 1637113596Snectar goto more; 1638113596Snectar return (NS_NOTFOUND); 1639113596Snectar } 1640113596Snectar e = compat_use_template(pwd, &st->template, buffer, bufsize); 1641113596Snectar if (e != 0) { 1642113596Snectar *errnop = e; 1643113596Snectar if (e == ERANGE) 1644113596Snectar return (NS_RETURN); 1645113596Snectar else 1646113596Snectar return (NS_UNAVAIL); 1647113596Snectar } 1648113596Snectar switch (how) { 1649113596Snectar case nss_lt_name: 1650113596Snectar if (strcmp(name, pwd->pw_name) != 0) 1651113596Snectar return (NS_NOTFOUND); 1652113596Snectar break; 1653113596Snectar case nss_lt_id: 1654113596Snectar if (uid != pwd->pw_uid) 1655113596Snectar return (NS_NOTFOUND); 1656113596Snectar break; 1657113596Snectar default: 1658113596Snectar break; 1659113596Snectar } 1660113596Snectar return (NS_SUCCESS); 1661113596Snectar} 166265532Snectar 166365532Snectar 1664113596Snectarstatic void 1665113596Snectarcompat_endstate(void *p) 1666113596Snectar{ 1667113596Snectar struct compat_state *st; 166865532Snectar 1669113596Snectar if (p == NULL) 1670113596Snectar return; 1671113596Snectar st = (struct compat_state *)p; 1672113596Snectar if (st->db != NULL) 1673113596Snectar st->db->close(st->db); 1674113596Snectar if (st->exclude != NULL) 1675113596Snectar st->exclude->close(st->exclude); 1676113596Snectar compat_clear_template(&st->template); 1677113596Snectar free(p); 1678113596Snectar} 167965532Snectar 168065532Snectar 1681113596Snectarstatic int 1682113596Snectarcompat_setpwent(void *retval, void *mdata, va_list ap) 1683113596Snectar{ 1684114021Snectar static const ns_src compatsrc[] = { 1685114021Snectar#ifdef YP 1686114021Snectar { NSSRC_NIS, NS_SUCCESS }, 1687114021Snectar#endif 1688114021Snectar { NULL, 0 } 1689114021Snectar }; 1690114021Snectar ns_dtab dtab[] = { 1691114021Snectar#ifdef YP 1692114021Snectar { NSSRC_NIS, nis_setpwent, NULL }, 1693114021Snectar#endif 1694114021Snectar#ifdef HESIOD 1695114021Snectar { NSSRC_DNS, dns_setpwent, NULL }, 1696114021Snectar#endif 1697114021Snectar { NULL, NULL, NULL } 1698114021Snectar }; 1699113596Snectar struct compat_state *st; 1700113596Snectar int rv, stayopen; 170165532Snectar 1702114021Snectar#define set_setent(x, y) do { \ 1703114021Snectar int i; \ 1704114021Snectar \ 1705114021Snectar for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \ 1706114021Snectar x[i].mdata = (void *)y; \ 1707114021Snectar} while (0) 1708114021Snectar 1709113596Snectar rv = compat_getstate(&st); 1710113596Snectar if (rv != 0) 1711113596Snectar return (NS_UNAVAIL); 1712113596Snectar switch ((enum constants)mdata) { 1713113596Snectar case SETPWENT: 1714113596Snectar stayopen = va_arg(ap, int); 1715113596Snectar st->keynum = 0; 1716113596Snectar if (stayopen) 1717113596Snectar st->db = pwdbopen(&st->version); 1718113596Snectar st->stayopen = stayopen; 1719114021Snectar set_setent(dtab, mdata); 1720114021Snectar (void)_nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "setpwent", 1721114021Snectar compatsrc, 0); 1722113596Snectar break; 1723113596Snectar case ENDPWENT: 1724113596Snectar if (st->db != NULL) { 1725113596Snectar (void)st->db->close(st->db); 1726113596Snectar st->db = NULL; 172765532Snectar } 1728114021Snectar set_setent(dtab, mdata); 1729114021Snectar (void)_nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "endpwent", 1730114021Snectar compatsrc, 0); 1731113596Snectar break; 1732113596Snectar default: 1733113596Snectar break; 173410521Swpaul } 1735113596Snectar return (NS_UNAVAIL); 1736114021Snectar#undef set_setent 173710521Swpaul} 173820119Swpaul 173920119Swpaul 17409332Swpaulstatic int 1741113596Snectarcompat_passwd(void *retval, void *mdata, va_list ap) 17422917Swollman{ 1743113596Snectar char keybuf[MAXLOGNAME + 1]; 1744113596Snectar DBT key, entry; 1745113596Snectar struct compat_state *st; 1746113596Snectar enum nss_lookup_type how; 1747113596Snectar const char *name; 1748113596Snectar struct passwd *pwd; 1749113596Snectar char *buffer, *pw_name; 1750113596Snectar char *host, *user, *domain; 1751113596Snectar size_t bufsize; 1752113596Snectar uid_t uid; 1753113596Snectar uint32_t store; 1754113691Snectar int rv, from_compat, stayopen, *errnop; 17552917Swollman 1756113691Snectar from_compat = 0; 175765532Snectar name = NULL; 1758113596Snectar uid = (uid_t)-1; 1759113596Snectar how = (enum nss_lookup_type)mdata; 1760113596Snectar switch (how) { 1761113596Snectar case nss_lt_name: 1762113596Snectar name = va_arg(ap, const char *); 176365532Snectar break; 1764113596Snectar case nss_lt_id: 176565532Snectar uid = va_arg(ap, uid_t); 176665532Snectar break; 1767113596Snectar case nss_lt_all: 1768113596Snectar break; 176965532Snectar default: 1770113596Snectar rv = NS_NOTFOUND; 1771113596Snectar goto fin; 17722917Swollman } 1773113596Snectar pwd = va_arg(ap, struct passwd *); 1774113596Snectar buffer = va_arg(ap, char *); 1775113596Snectar bufsize = va_arg(ap, size_t); 1776113596Snectar errnop = va_arg(ap, int *); 1777113596Snectar *errnop = compat_getstate(&st); 1778113596Snectar if (*errnop != 0) 1779113596Snectar return (NS_UNAVAIL); 1780113596Snectar if (how == nss_lt_all && st->keynum < 0) { 1781113596Snectar rv = NS_NOTFOUND; 1782113596Snectar goto fin; 1783113596Snectar } 1784113596Snectar if (st->db == NULL && 1785113596Snectar (st->db = pwdbopen(&st->version)) == NULL) { 1786113596Snectar *errnop = errno; 1787113596Snectar rv = NS_UNAVAIL; 1788113596Snectar goto fin; 1789113596Snectar } 1790113596Snectar if (how == nss_lt_all) { 1791113596Snectar if (st->keynum < 0) { 1792113596Snectar rv = NS_NOTFOUND; 1793113596Snectar goto fin; 1794113596Snectar } 1795113596Snectar stayopen = 1; 1796113596Snectar } else { 1797113596Snectar st->keynum = 0; 1798113596Snectar stayopen = st->stayopen; 1799113596Snectar } 1800113596Snectardocompat: 1801113596Snectar rv = NS_NOTFOUND; 1802113596Snectar switch (st->compat) { 1803113596Snectar case COMPAT_MODE_ALL: 1804113596Snectar rv = compat_redispatch(st, how, how, name, name, uid, pwd, 1805113596Snectar buffer, bufsize, errnop); 1806113596Snectar if (rv != NS_SUCCESS) 1807113596Snectar st->compat = COMPAT_MODE_OFF; 1808113596Snectar break; 1809113596Snectar case COMPAT_MODE_NETGROUP: 1810113596Snectar /* XXX getnetgrent is not thread-safe. */ 1811113596Snectar do { 1812113596Snectar rv = getnetgrent(&host, &user, &domain); 1813113596Snectar if (rv == 0) { 1814113596Snectar endnetgrent(); 1815113596Snectar st->compat = COMPAT_MODE_OFF; 1816113596Snectar rv = NS_NOTFOUND; 1817113596Snectar continue; 1818113596Snectar } else if (user == NULL || user[0] == '\0') 1819113596Snectar continue; 1820113596Snectar rv = compat_redispatch(st, how, nss_lt_name, name, 1821113596Snectar user, uid, pwd, buffer, bufsize, errnop); 1822113596Snectar } while (st->compat == COMPAT_MODE_NETGROUP && 1823113596Snectar !(rv & NS_TERMINATE)); 1824113596Snectar break; 1825113596Snectar case COMPAT_MODE_NAME: 1826113596Snectar rv = compat_redispatch(st, how, nss_lt_name, name, st->name, 1827113596Snectar uid, pwd, buffer, bufsize, errnop); 1828113596Snectar free(st->name); 1829113596Snectar st->name = NULL; 1830113596Snectar st->compat = COMPAT_MODE_OFF; 1831113596Snectar break; 1832113596Snectar default: 1833113596Snectar break; 1834113596Snectar } 1835113691Snectar if (rv & NS_TERMINATE) { 1836113691Snectar from_compat = 1; 1837113596Snectar goto fin; 1838113691Snectar } 1839113596Snectar key.data = keybuf; 1840113596Snectar rv = NS_NOTFOUND; 1841113596Snectar while (st->keynum >= 0) { 1842113596Snectar st->keynum++; 1843113596Snectar if (st->version < _PWD_CURRENT_VERSION) { 1844113596Snectar memcpy(&keybuf[1], &st->keynum, sizeof(st->keynum)); 1845113596Snectar key.size = sizeof(st->keynum) + 1; 1846113596Snectar } else { 1847113596Snectar store = htonl(st->keynum); 1848113596Snectar memcpy(&keybuf[1], &store, sizeof(store)); 1849113596Snectar key.size = sizeof(store) + 1; 1850113596Snectar } 1851113666Snectar keybuf[0] = _PW_VERSIONED(_PW_KEYBYNUM, st->version); 1852113596Snectar rv = st->db->get(st->db, &key, &entry, 0); 1853113596Snectar if (rv < 0 || rv > 1) { /* should never return > 1 */ 1854113596Snectar *errnop = errno; 1855113596Snectar rv = NS_UNAVAIL; 1856113596Snectar goto fin; 1857113596Snectar } else if (rv == 1) { 1858113596Snectar st->keynum = -1; 1859113596Snectar rv = NS_NOTFOUND; 1860113596Snectar goto fin; 1861113596Snectar } 1862113596Snectar pw_name = (char *)entry.data; 1863113596Snectar switch (pw_name[0]) { 186465532Snectar case '+': 1865113596Snectar switch (pw_name[1]) { 186665532Snectar case '\0': 1867113596Snectar st->compat = COMPAT_MODE_ALL; 186865532Snectar break; 186965532Snectar case '@': 1870113596Snectar setnetgrent(&pw_name[2]); 1871113596Snectar st->compat = COMPAT_MODE_NETGROUP; 187265532Snectar break; 187365532Snectar default: 1874113596Snectar st->name = strdup(&pw_name[1]); 1875113596Snectar if (st->name == NULL) { 1876113596Snectar syslog(LOG_ERR, 1877113596Snectar "getpwent memory allocation failure"); 1878113596Snectar *errnop = ENOMEM; 1879113596Snectar rv = NS_UNAVAIL; 1880113596Snectar break; 1881113596Snectar } 1882113596Snectar st->compat = COMPAT_MODE_NAME; 188365532Snectar } 1884113596Snectar if (entry.size > bufsize) { 1885113596Snectar *errnop = ERANGE; 1886113596Snectar rv = NS_RETURN; 1887113596Snectar goto fin; 188865532Snectar } 1889113596Snectar memcpy(buffer, entry.data, entry.size); 1890113596Snectar rv = pwdb_versions[st->version].parse(buffer, 1891113596Snectar entry.size, pwd, errnop); 1892113596Snectar if (rv != NS_SUCCESS) 1893113596Snectar ; 1894113596Snectar else if (compat_set_template(pwd, &st->template) < 0) { 1895113596Snectar *errnop = ENOMEM; 1896113596Snectar rv = NS_UNAVAIL; 1897113596Snectar goto fin; 1898113596Snectar } 1899113596Snectar goto docompat; 190065532Snectar case '-': 1901113596Snectar switch (pw_name[1]) { 190265532Snectar case '\0': 1903113596Snectar /* XXX Maybe syslog warning */ 1904113596Snectar continue; 190565532Snectar case '@': 1906113596Snectar setnetgrent(&pw_name[2]); 1907113596Snectar while (getnetgrent(&host, &user, &domain) != 1908126643Smarkm 0) { 1909113596Snectar if (user != NULL && user[0] != '\0') 1910113596Snectar compat_exclude(user, 1911113596Snectar &st->exclude); 191265532Snectar } 191365532Snectar endnetgrent(); 1914113596Snectar continue; 191565532Snectar default: 1916113596Snectar compat_exclude(&pw_name[1], &st->exclude); 1917113596Snectar continue; 191865532Snectar } 191965532Snectar break; 192096186Sdes default: 1921113596Snectar break; 19226190Swpaul } 1923113596Snectar if (compat_is_excluded((char *)entry.data, st->exclude)) 1924113596Snectar continue; 1925113596Snectar rv = pwdb_versions[st->version].match(entry.data, entry.size, 1926113596Snectar how, name, uid); 1927113596Snectar if (rv == NS_RETURN) 192865532Snectar break; 1929113596Snectar else if (rv != NS_SUCCESS) 1930113596Snectar continue; 1931113596Snectar if (entry.size > bufsize) { 1932113596Snectar *errnop = ERANGE; 1933113596Snectar rv = NS_RETURN; 1934113596Snectar break; 193565532Snectar } 1936113596Snectar memcpy(buffer, entry.data, entry.size); 1937113596Snectar rv = pwdb_versions[st->version].parse(buffer, entry.size, pwd, 1938113596Snectar errnop); 1939113596Snectar if (rv & NS_TERMINATE) 1940113596Snectar break; 19412917Swollman } 1942113596Snectarfin: 1943113596Snectar if (!stayopen && st->db != NULL) { 1944113596Snectar (void)st->db->close(st->db); 1945113596Snectar st->db = NULL; 19466076Swpaul } 1947124432Snectar if (rv == NS_SUCCESS) { 1948113691Snectar if (!from_compat) { 1949113691Snectar pwd->pw_fields &= ~_PWF_SOURCE; 1950113691Snectar pwd->pw_fields |= _PWF_FILES; 1951113691Snectar } 1952113691Snectar if (retval != NULL) 1953113691Snectar *(struct passwd **)retval = pwd; 1954113691Snectar } 1955113596Snectar return (rv); 195665532Snectar} 19576076Swpaul 19589332Swpaul 1959113596Snectar/* 1960113596Snectar * common passwd line matching and parsing 1961113596Snectar */ 196265532Snectarint 1963113596Snectar__pw_match_entry(const char *entry, size_t entrysize, enum nss_lookup_type how, 1964113596Snectar const char *name, uid_t uid) 19652917Swollman{ 1966113596Snectar const char *p, *eom; 1967113596Snectar char *q; 1968113596Snectar size_t len; 1969113596Snectar unsigned long m; 19702917Swollman 1971113596Snectar eom = entry + entrysize; 1972113596Snectar for (p = entry; p < eom; p++) 1973113596Snectar if (*p == ':') 1974113596Snectar break; 1975113596Snectar if (*p != ':') 1976113596Snectar return (NS_NOTFOUND); 1977113596Snectar if (how == nss_lt_all) 1978113596Snectar return (NS_SUCCESS); 1979113596Snectar if (how == nss_lt_name) { 1980113596Snectar len = strlen(name); 1981113596Snectar if (len == (p - entry) && memcmp(name, entry, len) == 0) 1982113596Snectar return (NS_SUCCESS); 1983113596Snectar else 1984113596Snectar return (NS_NOTFOUND); 198545066Sdes } 1986113596Snectar for (p++; p < eom; p++) 1987113596Snectar if (*p == ':') 1988113596Snectar break; 1989113596Snectar if (*p != ':') 1990113596Snectar return (NS_NOTFOUND); 1991113596Snectar m = strtoul(++p, &q, 10); 1992113596Snectar if (q[0] != ':' || (uid_t)m != uid) 1993113596Snectar return (NS_NOTFOUND); 1994113596Snectar else 1995113596Snectar return (NS_SUCCESS); 199665532Snectar} 19972917Swollman 199815267Swpaul 1999113596Snectar/* XXX buffer must be NUL-terminated. errnop is not set correctly. */ 2000113596Snectarint 2001113596Snectar__pw_parse_entry(char *buffer, size_t bufsize __unused, struct passwd *pwd, 2002113596Snectar int master, int *errnop __unused) 20032917Swollman{ 20042917Swollman 2005113596Snectar if (__pw_scan(buffer, pwd, master ? _PWSCAN_MASTER : 0) == 0) 2006113596Snectar return (NS_NOTFOUND); 2007113596Snectar else 2008113596Snectar return (NS_SUCCESS); 20092917Swollman} 2010