105f98035SJacques Vidrine /*- 205f98035SJacques Vidrine * Copyright (c) 2003 Networks Associates Technology, Inc. 305f98035SJacques Vidrine * All rights reserved. 405f98035SJacques Vidrine * 505f98035SJacques Vidrine * This software was developed for the FreeBSD Project by 605f98035SJacques Vidrine * Jacques A. Vidrine, Safeport Network Services, and Network 705f98035SJacques Vidrine * Associates Laboratories, the Security Research Division of Network 805f98035SJacques Vidrine * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 905f98035SJacques Vidrine * ("CBOSS"), as part of the DARPA CHATS research program. 1058f0484fSRodney W. Grimes * 1158f0484fSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 1258f0484fSRodney W. Grimes * modification, are permitted provided that the following conditions 1358f0484fSRodney W. Grimes * are met: 1458f0484fSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 1558f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 1658f0484fSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 1758f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 1858f0484fSRodney W. Grimes * documentation and/or other materials provided with the distribution. 1958f0484fSRodney W. Grimes * 2005f98035SJacques Vidrine * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2158f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2258f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2305f98035SJacques Vidrine * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2458f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2558f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2658f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2758f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2858f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2958f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3058f0484fSRodney W. Grimes * SUCH DAMAGE. 3105f98035SJacques Vidrine * 3258f0484fSRodney W. Grimes */ 3356bcbf00SBruce Evans #include <sys/cdefs.h> 34135b57f9SDavid E. O'Brien __FBSDID("$FreeBSD$"); 3558f0484fSRodney W. Grimes 3605f98035SJacques Vidrine #include "namespace.h" 3758f0484fSRodney W. Grimes #include <sys/param.h> 38248aee62SJacques Vidrine #ifdef YP 39248aee62SJacques Vidrine #include <rpc/rpc.h> 40248aee62SJacques Vidrine #include <rpcsvc/yp_prot.h> 41248aee62SJacques Vidrine #include <rpcsvc/ypclnt.h> 42248aee62SJacques Vidrine #endif 4305f98035SJacques Vidrine #include <arpa/inet.h> 4405f98035SJacques Vidrine #include <errno.h> 4505f98035SJacques Vidrine #include <fcntl.h> 4605f98035SJacques Vidrine #ifdef HESIOD 4705f98035SJacques Vidrine #include <hesiod.h> 4805f98035SJacques Vidrine #endif 4905f98035SJacques Vidrine #include <netdb.h> 5005f98035SJacques Vidrine #include <nsswitch.h> 5105f98035SJacques Vidrine #include <pthread.h> 5205f98035SJacques Vidrine #include <pthread_np.h> 5305f98035SJacques Vidrine #include <pwd.h> 5405f98035SJacques Vidrine #include <stdlib.h> 5505f98035SJacques Vidrine #include <stdio.h> 5605f98035SJacques Vidrine #include <string.h> 5705f98035SJacques Vidrine #include <syslog.h> 5805f98035SJacques Vidrine #include <unistd.h> 59d201fe46SDaniel Eischen #include "un-namespace.h" 6005f98035SJacques Vidrine #include <db.h> 612bbd7cf8SJacques Vidrine #include "libc_private.h" 62248aee62SJacques Vidrine #include "pw_scan.h" 6305f98035SJacques Vidrine #include "nss_tls.h" 64248aee62SJacques Vidrine 6505f98035SJacques Vidrine #ifndef CTASSERT 6605f98035SJacques Vidrine #define CTASSERT(x) _CTASSERT(x, __LINE__) 6705f98035SJacques Vidrine #define _CTASSERT(x, y) __CTASSERT(x, y) 6805f98035SJacques Vidrine #define __CTASSERT(x, y) typedef char __assert_ ## y [(x) ? 1 : -1] 69248aee62SJacques Vidrine #endif 70248aee62SJacques Vidrine 7105f98035SJacques Vidrine /* Counter as stored in /etc/pwd.db */ 7205f98035SJacques Vidrine typedef int pwkeynum; 73adf6ad9eSPeter Wemm 7405f98035SJacques Vidrine CTASSERT(MAXLOGNAME > sizeof(uid_t)); 7505f98035SJacques Vidrine CTASSERT(MAXLOGNAME > sizeof(pwkeynum)); 7694c53e1fSBill Paul 7705f98035SJacques Vidrine enum constants { 7805f98035SJacques Vidrine PWD_STORAGE_INITIAL = 1 << 10, /* 1 KByte */ 7905f98035SJacques Vidrine PWD_STORAGE_MAX = 1 << 20, /* 1 MByte */ 8005f98035SJacques Vidrine SETPWENT = 1, 8105f98035SJacques Vidrine ENDPWENT = 2, 8205f98035SJacques Vidrine HESIOD_NAME_MAX = 256 83248aee62SJacques Vidrine }; 84248aee62SJacques Vidrine 8505f98035SJacques Vidrine static const ns_src defaultsrc[] = { 861b467db2SJacques Vidrine { NSSRC_COMPAT, NS_SUCCESS }, 8705f98035SJacques Vidrine { NULL, 0 } 8805f98035SJacques Vidrine }; 8905f98035SJacques Vidrine 9005f98035SJacques Vidrine int __pw_match_entry(const char *, size_t, enum nss_lookup_type, 9105f98035SJacques Vidrine const char *, uid_t); 9205f98035SJacques Vidrine int __pw_parse_entry(char *, size_t, struct passwd *, int, int *errnop); 9305f98035SJacques Vidrine 94171614bfSJacques Vidrine static void pwd_init(struct passwd *); 954c3c0fecSJacques Vidrine 9605f98035SJacques Vidrine union key { 9705f98035SJacques Vidrine const char *name; 9805f98035SJacques Vidrine uid_t uid; 9905f98035SJacques Vidrine }; 10005f98035SJacques Vidrine 10105f98035SJacques Vidrine static struct passwd *getpw(int (*fn)(union key, struct passwd *, char *, 10205f98035SJacques Vidrine size_t, struct passwd **), union key); 10305f98035SJacques Vidrine static int wrap_getpwnam_r(union key, struct passwd *, char *, 10405f98035SJacques Vidrine size_t, struct passwd **); 10505f98035SJacques Vidrine static int wrap_getpwuid_r(union key, struct passwd *, char *, size_t, 10605f98035SJacques Vidrine struct passwd **); 10705f98035SJacques Vidrine static int wrap_getpwent_r(union key, struct passwd *, char *, size_t, 10805f98035SJacques Vidrine struct passwd **); 10905f98035SJacques Vidrine 11005f98035SJacques Vidrine static int pwdb_match_entry_v3(char *, size_t, enum nss_lookup_type, 11105f98035SJacques Vidrine const char *, uid_t); 11205f98035SJacques Vidrine static int pwdb_parse_entry_v3(char *, size_t, struct passwd *, int *); 11305f98035SJacques Vidrine static int pwdb_match_entry_v4(char *, size_t, enum nss_lookup_type, 11405f98035SJacques Vidrine const char *, uid_t); 11505f98035SJacques Vidrine static int pwdb_parse_entry_v4(char *, size_t, struct passwd *, int *); 11605f98035SJacques Vidrine 11705f98035SJacques Vidrine 11805f98035SJacques Vidrine struct { 11905f98035SJacques Vidrine int (*match)(char *, size_t, enum nss_lookup_type, const char *, 12005f98035SJacques Vidrine uid_t); 12105f98035SJacques Vidrine int (*parse)(char *, size_t, struct passwd *, int *); 12205f98035SJacques Vidrine } pwdb_versions[] = { 12305f98035SJacques Vidrine { NULL, NULL }, /* version 0 */ 12405f98035SJacques Vidrine { NULL, NULL }, /* version 1 */ 12505f98035SJacques Vidrine { NULL, NULL }, /* version 2 */ 12605f98035SJacques Vidrine { pwdb_match_entry_v3, pwdb_parse_entry_v3 }, /* version 3 */ 12705f98035SJacques Vidrine { pwdb_match_entry_v4, pwdb_parse_entry_v4 }, /* version 4 */ 12805f98035SJacques Vidrine }; 12905f98035SJacques Vidrine 13005f98035SJacques Vidrine 13105f98035SJacques Vidrine struct files_state { 13205f98035SJacques Vidrine DB *db; 13305f98035SJacques Vidrine pwkeynum keynum; 13405f98035SJacques Vidrine int stayopen; 13505f98035SJacques Vidrine int version; 13605f98035SJacques Vidrine }; 13705f98035SJacques Vidrine static void files_endstate(void *); 13805f98035SJacques Vidrine NSS_TLS_HANDLING(files); 13905f98035SJacques Vidrine static DB *pwdbopen(int *); 14005f98035SJacques Vidrine static void files_endstate(void *); 14105f98035SJacques Vidrine static int files_setpwent(void *, void *, va_list); 14205f98035SJacques Vidrine static int files_passwd(void *, void *, va_list); 14305f98035SJacques Vidrine 144248aee62SJacques Vidrine 145248aee62SJacques Vidrine #ifdef HESIOD 14605f98035SJacques Vidrine struct dns_state { 14705f98035SJacques Vidrine long counter; 14805f98035SJacques Vidrine }; 14905f98035SJacques Vidrine static void dns_endstate(void *); 15005f98035SJacques Vidrine NSS_TLS_HANDLING(dns); 15105f98035SJacques Vidrine static int dns_setpwent(void *, void *, va_list); 15205f98035SJacques Vidrine static int dns_passwd(void *, void *, va_list); 153248aee62SJacques Vidrine #endif 154248aee62SJacques Vidrine 155248aee62SJacques Vidrine 156248aee62SJacques Vidrine #ifdef YP 15705f98035SJacques Vidrine struct nis_state { 15805f98035SJacques Vidrine char domain[MAXHOSTNAMELEN]; 15905f98035SJacques Vidrine int done; 16005f98035SJacques Vidrine char *key; 16105f98035SJacques Vidrine int keylen; 16205f98035SJacques Vidrine }; 16305f98035SJacques Vidrine static void nis_endstate(void *); 16405f98035SJacques Vidrine NSS_TLS_HANDLING(nis); 16505f98035SJacques Vidrine static int nis_setpwent(void *, void *, va_list); 16605f98035SJacques Vidrine static int nis_passwd(void *, void *, va_list); 16705f98035SJacques Vidrine static int nis_map(char *, enum nss_lookup_type, char *, size_t, int *); 16805f98035SJacques Vidrine static int nis_adjunct(char *, const char *, char *, size_t); 169248aee62SJacques Vidrine #endif 170248aee62SJacques Vidrine 171248aee62SJacques Vidrine 17205f98035SJacques Vidrine struct compat_state { 17305f98035SJacques Vidrine DB *db; 17405f98035SJacques Vidrine pwkeynum keynum; 17505f98035SJacques Vidrine int stayopen; 17605f98035SJacques Vidrine int version; 17705f98035SJacques Vidrine DB *exclude; 17805f98035SJacques Vidrine struct passwd template; 17905f98035SJacques Vidrine char *name; 18005f98035SJacques Vidrine enum _compat { 18105f98035SJacques Vidrine COMPAT_MODE_OFF = 0, 18205f98035SJacques Vidrine COMPAT_MODE_ALL, 18305f98035SJacques Vidrine COMPAT_MODE_NAME, 18405f98035SJacques Vidrine COMPAT_MODE_NETGROUP 18505f98035SJacques Vidrine } compat; 18605f98035SJacques Vidrine }; 18705f98035SJacques Vidrine static void compat_endstate(void *); 18805f98035SJacques Vidrine NSS_TLS_HANDLING(compat); 18905f98035SJacques Vidrine static int compat_setpwent(void *, void *, va_list); 19005f98035SJacques Vidrine static int compat_passwd(void *, void *, va_list); 19105f98035SJacques Vidrine static void compat_clear_template(struct passwd *); 19205f98035SJacques Vidrine static int compat_set_template(struct passwd *, struct passwd *); 19305f98035SJacques Vidrine static int compat_use_template(struct passwd *, struct passwd *, char *, 19405f98035SJacques Vidrine size_t); 19505f98035SJacques Vidrine static int compat_redispatch(struct compat_state *, enum nss_lookup_type, 19605f98035SJacques Vidrine enum nss_lookup_type, const char *, const char *, uid_t, 19705f98035SJacques Vidrine struct passwd *, char *, size_t, int *); 19805f98035SJacques Vidrine void 19905f98035SJacques Vidrine setpwent(void) 200248aee62SJacques Vidrine { 201248aee62SJacques Vidrine static const ns_dtab dtab[] = { 20205f98035SJacques Vidrine { NSSRC_FILES, files_setpwent, (void *)SETPWENT }, 20305f98035SJacques Vidrine #ifdef HESIOD 20405f98035SJacques Vidrine { NSSRC_DNS, dns_setpwent, (void *)SETPWENT }, 20505f98035SJacques Vidrine #endif 20605f98035SJacques Vidrine #ifdef YP 20705f98035SJacques Vidrine { NSSRC_NIS, nis_setpwent, (void *)SETPWENT }, 20805f98035SJacques Vidrine #endif 20905f98035SJacques Vidrine { NSSRC_COMPAT, compat_setpwent, (void *)SETPWENT }, 21005f98035SJacques Vidrine { NULL, NULL, NULL } 211248aee62SJacques Vidrine }; 21205f98035SJacques Vidrine (void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", defaultsrc, 0); 213248aee62SJacques Vidrine } 214248aee62SJacques Vidrine 21558f0484fSRodney W. Grimes 21658f0484fSRodney W. Grimes int 21705f98035SJacques Vidrine setpassent(int stayopen) 21858f0484fSRodney W. Grimes { 21905f98035SJacques Vidrine static const ns_dtab dtab[] = { 22005f98035SJacques Vidrine { NSSRC_FILES, files_setpwent, (void *)SETPWENT }, 221248aee62SJacques Vidrine #ifdef HESIOD 22205f98035SJacques Vidrine { NSSRC_DNS, dns_setpwent, (void *)SETPWENT }, 223248aee62SJacques Vidrine #endif 22494c53e1fSBill Paul #ifdef YP 22505f98035SJacques Vidrine { NSSRC_NIS, nis_setpwent, (void *)SETPWENT }, 226248aee62SJacques Vidrine #endif 22705f98035SJacques Vidrine { NSSRC_COMPAT, compat_setpwent, (void *)SETPWENT }, 22805f98035SJacques Vidrine { NULL, NULL, NULL } 22905f98035SJacques Vidrine }; 23005f98035SJacques Vidrine (void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", defaultsrc, 23105f98035SJacques Vidrine stayopen); 2323948edc2SBill Paul return (1); 233248aee62SJacques Vidrine } 23405f98035SJacques Vidrine 23505f98035SJacques Vidrine 23605f98035SJacques Vidrine void 23705f98035SJacques Vidrine endpwent(void) 23805f98035SJacques Vidrine { 23905f98035SJacques Vidrine static const ns_dtab dtab[] = { 24005f98035SJacques Vidrine { NSSRC_FILES, files_setpwent, (void *)ENDPWENT }, 24105f98035SJacques Vidrine #ifdef HESIOD 24205f98035SJacques Vidrine { NSSRC_DNS, dns_setpwent, (void *)ENDPWENT }, 24305f98035SJacques Vidrine #endif 24405f98035SJacques Vidrine #ifdef YP 24505f98035SJacques Vidrine { NSSRC_NIS, nis_setpwent, (void *)ENDPWENT }, 24605f98035SJacques Vidrine #endif 24705f98035SJacques Vidrine { NSSRC_COMPAT, compat_setpwent, (void *)ENDPWENT }, 24805f98035SJacques Vidrine { NULL, NULL, NULL } 24905f98035SJacques Vidrine }; 25005f98035SJacques Vidrine (void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent", defaultsrc); 25105f98035SJacques Vidrine } 25205f98035SJacques Vidrine 25305f98035SJacques Vidrine 25405f98035SJacques Vidrine int 25505f98035SJacques Vidrine getpwent_r(struct passwd *pwd, char *buffer, size_t bufsize, 25605f98035SJacques Vidrine struct passwd **result) 25705f98035SJacques Vidrine { 25805f98035SJacques Vidrine static const ns_dtab dtab[] = { 25905f98035SJacques Vidrine { NSSRC_FILES, files_passwd, (void *)nss_lt_all }, 26005f98035SJacques Vidrine #ifdef HESIOD 26105f98035SJacques Vidrine { NSSRC_DNS, dns_passwd, (void *)nss_lt_all }, 26205f98035SJacques Vidrine #endif 26305f98035SJacques Vidrine #ifdef YP 26405f98035SJacques Vidrine { NSSRC_NIS, nis_passwd, (void *)nss_lt_all }, 26505f98035SJacques Vidrine #endif 26605f98035SJacques Vidrine { NSSRC_COMPAT, compat_passwd, (void *)nss_lt_all }, 26705f98035SJacques Vidrine { NULL, NULL, NULL } 26805f98035SJacques Vidrine }; 26905f98035SJacques Vidrine int rv, ret_errno; 27005f98035SJacques Vidrine 271171614bfSJacques Vidrine pwd_init(pwd); 272171614bfSJacques Vidrine ret_errno = 0; 27305f98035SJacques Vidrine *result = NULL; 27405f98035SJacques Vidrine rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwent_r", defaultsrc, 27505f98035SJacques Vidrine pwd, buffer, bufsize, &ret_errno); 27605f98035SJacques Vidrine if (rv == NS_SUCCESS) 27705f98035SJacques Vidrine return (0); 27805f98035SJacques Vidrine else 27905f98035SJacques Vidrine return (ret_errno); 28005f98035SJacques Vidrine } 28105f98035SJacques Vidrine 28205f98035SJacques Vidrine 28305f98035SJacques Vidrine int 28405f98035SJacques Vidrine getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t bufsize, 28505f98035SJacques Vidrine struct passwd **result) 28605f98035SJacques Vidrine { 28705f98035SJacques Vidrine static const ns_dtab dtab[] = { 28805f98035SJacques Vidrine { NSSRC_FILES, files_passwd, (void *)nss_lt_name }, 28905f98035SJacques Vidrine #ifdef HESIOD 29005f98035SJacques Vidrine { NSSRC_DNS, dns_passwd, (void *)nss_lt_name }, 29105f98035SJacques Vidrine #endif 29205f98035SJacques Vidrine #ifdef YP 29305f98035SJacques Vidrine { NSSRC_NIS, nis_passwd, (void *)nss_lt_name }, 29405f98035SJacques Vidrine #endif 29505f98035SJacques Vidrine { NSSRC_COMPAT, compat_passwd, (void *)nss_lt_name }, 29605f98035SJacques Vidrine { NULL, NULL, NULL } 29705f98035SJacques Vidrine }; 29805f98035SJacques Vidrine int rv, ret_errno; 29905f98035SJacques Vidrine 300171614bfSJacques Vidrine pwd_init(pwd); 301171614bfSJacques Vidrine ret_errno = 0; 30205f98035SJacques Vidrine *result = NULL; 30305f98035SJacques Vidrine rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwnam_r", defaultsrc, 30405f98035SJacques Vidrine name, pwd, buffer, bufsize, &ret_errno); 30505f98035SJacques Vidrine if (rv == NS_SUCCESS) 30605f98035SJacques Vidrine return (0); 30705f98035SJacques Vidrine else 30805f98035SJacques Vidrine return (ret_errno); 30905f98035SJacques Vidrine } 31005f98035SJacques Vidrine 31105f98035SJacques Vidrine 31205f98035SJacques Vidrine int 31305f98035SJacques Vidrine getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, 31405f98035SJacques Vidrine struct passwd **result) 31505f98035SJacques Vidrine { 31605f98035SJacques Vidrine static const ns_dtab dtab[] = { 31705f98035SJacques Vidrine { NSSRC_FILES, files_passwd, (void *)nss_lt_id }, 31805f98035SJacques Vidrine #ifdef HESIOD 31905f98035SJacques Vidrine { NSSRC_DNS, dns_passwd, (void *)nss_lt_id }, 32005f98035SJacques Vidrine #endif 32105f98035SJacques Vidrine #ifdef YP 32205f98035SJacques Vidrine { NSSRC_NIS, nis_passwd, (void *)nss_lt_id }, 32305f98035SJacques Vidrine #endif 32405f98035SJacques Vidrine { NSSRC_COMPAT, compat_passwd, (void *)nss_lt_id }, 32505f98035SJacques Vidrine { NULL, NULL, NULL } 32605f98035SJacques Vidrine }; 32705f98035SJacques Vidrine int rv, ret_errno; 32805f98035SJacques Vidrine 329171614bfSJacques Vidrine pwd_init(pwd); 330171614bfSJacques Vidrine ret_errno = 0; 33105f98035SJacques Vidrine *result = NULL; 33205f98035SJacques Vidrine rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwuid_r", defaultsrc, 33305f98035SJacques Vidrine uid, pwd, buffer, bufsize, &ret_errno); 33405f98035SJacques Vidrine if (rv == NS_SUCCESS) 33505f98035SJacques Vidrine return (0); 33605f98035SJacques Vidrine else 33705f98035SJacques Vidrine return (ret_errno); 33805f98035SJacques Vidrine } 33905f98035SJacques Vidrine 34005f98035SJacques Vidrine 341171614bfSJacques Vidrine static void 342171614bfSJacques Vidrine pwd_init(struct passwd *pwd) 3434c3c0fecSJacques Vidrine { 344171614bfSJacques Vidrine static char nul[] = ""; 3454c3c0fecSJacques Vidrine 3464c3c0fecSJacques Vidrine memset(pwd, 0, sizeof(*pwd)); 3474c3c0fecSJacques Vidrine pwd->pw_uid = (uid_t)-1; /* Considered least likely to lead to */ 3484c3c0fecSJacques Vidrine pwd->pw_gid = (gid_t)-1; /* a security issue. */ 349171614bfSJacques Vidrine pwd->pw_name = nul; 350171614bfSJacques Vidrine pwd->pw_passwd = nul; 351171614bfSJacques Vidrine pwd->pw_class = nul; 352171614bfSJacques Vidrine pwd->pw_gecos = nul; 353171614bfSJacques Vidrine pwd->pw_dir = nul; 354171614bfSJacques Vidrine pwd->pw_shell = nul; 3554c3c0fecSJacques Vidrine } 3564c3c0fecSJacques Vidrine 3574c3c0fecSJacques Vidrine 35805f98035SJacques Vidrine static struct passwd pwd; 35905f98035SJacques Vidrine static char *pwd_storage; 36005f98035SJacques Vidrine static size_t pwd_storage_size; 36105f98035SJacques Vidrine 36205f98035SJacques Vidrine 36305f98035SJacques Vidrine static struct passwd * 36405f98035SJacques Vidrine getpw(int (*fn)(union key, struct passwd *, char *, size_t, struct passwd **), 36505f98035SJacques Vidrine union key key) 36605f98035SJacques Vidrine { 36705f98035SJacques Vidrine int rv; 36805f98035SJacques Vidrine struct passwd *res; 36905f98035SJacques Vidrine 37005f98035SJacques Vidrine if (pwd_storage == NULL) { 37105f98035SJacques Vidrine pwd_storage = malloc(PWD_STORAGE_INITIAL); 37205f98035SJacques Vidrine if (pwd_storage == NULL) 37305f98035SJacques Vidrine return (NULL); 37405f98035SJacques Vidrine pwd_storage_size = PWD_STORAGE_INITIAL; 37505f98035SJacques Vidrine } 37605f98035SJacques Vidrine do { 37705f98035SJacques Vidrine rv = fn(key, &pwd, pwd_storage, pwd_storage_size, &res); 37805f98035SJacques Vidrine if (res == NULL && rv == ERANGE) { 37905f98035SJacques Vidrine free(pwd_storage); 38005f98035SJacques Vidrine if ((pwd_storage_size << 1) > PWD_STORAGE_MAX) { 38105f98035SJacques Vidrine pwd_storage = NULL; 382b4cc8687STim Kientzle errno = ERANGE; 38305f98035SJacques Vidrine return (NULL); 38405f98035SJacques Vidrine } 38505f98035SJacques Vidrine pwd_storage_size <<= 1; 38605f98035SJacques Vidrine pwd_storage = malloc(pwd_storage_size); 38705f98035SJacques Vidrine if (pwd_storage == NULL) 38805f98035SJacques Vidrine return (NULL); 38905f98035SJacques Vidrine } 39005f98035SJacques Vidrine } while (res == NULL && rv == ERANGE); 391b4cc8687STim Kientzle if (res == NULL) 392b4cc8687STim Kientzle errno = rv; 39305f98035SJacques Vidrine return (res); 39405f98035SJacques Vidrine } 39505f98035SJacques Vidrine 39605f98035SJacques Vidrine 39705f98035SJacques Vidrine static int 39805f98035SJacques Vidrine wrap_getpwnam_r(union key key, struct passwd *pwd, char *buffer, 39905f98035SJacques Vidrine size_t bufsize, struct passwd **res) 40005f98035SJacques Vidrine { 40105f98035SJacques Vidrine return (getpwnam_r(key.name, pwd, buffer, bufsize, res)); 40205f98035SJacques Vidrine } 40305f98035SJacques Vidrine 40405f98035SJacques Vidrine 40505f98035SJacques Vidrine static int 40605f98035SJacques Vidrine wrap_getpwuid_r(union key key, struct passwd *pwd, char *buffer, 40705f98035SJacques Vidrine size_t bufsize, struct passwd **res) 40805f98035SJacques Vidrine { 40905f98035SJacques Vidrine return (getpwuid_r(key.uid, pwd, buffer, bufsize, res)); 41005f98035SJacques Vidrine } 41105f98035SJacques Vidrine 41205f98035SJacques Vidrine 41305f98035SJacques Vidrine static int 41405f98035SJacques Vidrine wrap_getpwent_r(union key key __unused, struct passwd *pwd, char *buffer, 41505f98035SJacques Vidrine size_t bufsize, struct passwd **res) 41605f98035SJacques Vidrine { 41705f98035SJacques Vidrine return (getpwent_r(pwd, buffer, bufsize, res)); 41805f98035SJacques Vidrine } 41905f98035SJacques Vidrine 42005f98035SJacques Vidrine 42105f98035SJacques Vidrine struct passwd * 42205f98035SJacques Vidrine getpwnam(const char *name) 42305f98035SJacques Vidrine { 42405f98035SJacques Vidrine union key key; 42505f98035SJacques Vidrine 42605f98035SJacques Vidrine key.name = name; 42705f98035SJacques Vidrine return (getpw(wrap_getpwnam_r, key)); 42805f98035SJacques Vidrine } 42905f98035SJacques Vidrine 43005f98035SJacques Vidrine 43105f98035SJacques Vidrine struct passwd * 43205f98035SJacques Vidrine getpwuid(uid_t uid) 43305f98035SJacques Vidrine { 43405f98035SJacques Vidrine union key key; 43505f98035SJacques Vidrine 43605f98035SJacques Vidrine key.uid = uid; 43705f98035SJacques Vidrine return (getpw(wrap_getpwuid_r, key)); 43805f98035SJacques Vidrine } 43905f98035SJacques Vidrine 44005f98035SJacques Vidrine 44105f98035SJacques Vidrine struct passwd * 44205f98035SJacques Vidrine getpwent(void) 44305f98035SJacques Vidrine { 44405f98035SJacques Vidrine union key key; 44505f98035SJacques Vidrine 44605f98035SJacques Vidrine key.uid = 0; /* not used */ 44705f98035SJacques Vidrine return (getpw(wrap_getpwent_r, key)); 44805f98035SJacques Vidrine } 44905f98035SJacques Vidrine 45005f98035SJacques Vidrine 45105f98035SJacques Vidrine /* 45205f98035SJacques Vidrine * files backend 45305f98035SJacques Vidrine */ 45405f98035SJacques Vidrine static DB * 45505f98035SJacques Vidrine pwdbopen(int *version) 45605f98035SJacques Vidrine { 45705f98035SJacques Vidrine DB *res; 45805f98035SJacques Vidrine DBT key, entry; 45905f98035SJacques Vidrine int rv; 46005f98035SJacques Vidrine 46105f98035SJacques Vidrine if (geteuid() != 0 || 46205f98035SJacques Vidrine (res = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL)) == NULL) 46305f98035SJacques Vidrine res = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL); 46405f98035SJacques Vidrine if (res == NULL) 46505f98035SJacques Vidrine return (NULL); 46605f98035SJacques Vidrine key.data = _PWD_VERSION_KEY; 46705f98035SJacques Vidrine key.size = strlen(_PWD_VERSION_KEY); 46805f98035SJacques Vidrine rv = res->get(res, &key, &entry, 0); 46905f98035SJacques Vidrine if (rv == 0) 47005f98035SJacques Vidrine *version = *(unsigned char *)entry.data; 47105f98035SJacques Vidrine else 47205f98035SJacques Vidrine *version = 3; 47305f98035SJacques Vidrine if (*version < 3 || 47405f98035SJacques Vidrine *version >= sizeof(pwdb_versions)/sizeof(pwdb_versions[0])) { 47505f98035SJacques Vidrine syslog(LOG_CRIT, "Unsupported password database version %d", 47605f98035SJacques Vidrine *version); 47705f98035SJacques Vidrine res->close(res); 47805f98035SJacques Vidrine res = NULL; 47905f98035SJacques Vidrine } 48005f98035SJacques Vidrine return (res); 48105f98035SJacques Vidrine } 48205f98035SJacques Vidrine 48305f98035SJacques Vidrine 48405f98035SJacques Vidrine static void 48505f98035SJacques Vidrine files_endstate(void *p) 48605f98035SJacques Vidrine { 48705f98035SJacques Vidrine DB *db; 48805f98035SJacques Vidrine 48905f98035SJacques Vidrine if (p == NULL) 49005f98035SJacques Vidrine return; 49105f98035SJacques Vidrine db = ((struct files_state *)p)->db; 49205f98035SJacques Vidrine if (db != NULL) 49305f98035SJacques Vidrine db->close(db); 49405f98035SJacques Vidrine free(p); 49505f98035SJacques Vidrine } 49605f98035SJacques Vidrine 49705f98035SJacques Vidrine 49805f98035SJacques Vidrine static int 49905f98035SJacques Vidrine files_setpwent(void *retval, void *mdata, va_list ap) 50005f98035SJacques Vidrine { 50105f98035SJacques Vidrine struct files_state *st; 50205f98035SJacques Vidrine int rv, stayopen; 50305f98035SJacques Vidrine 50405f98035SJacques Vidrine rv = files_getstate(&st); 50505f98035SJacques Vidrine if (rv != 0) 50605f98035SJacques Vidrine return (NS_UNAVAIL); 50705f98035SJacques Vidrine switch ((enum constants)mdata) { 50805f98035SJacques Vidrine case SETPWENT: 50905f98035SJacques Vidrine stayopen = va_arg(ap, int); 51005f98035SJacques Vidrine st->keynum = 0; 51105f98035SJacques Vidrine if (stayopen) 51205f98035SJacques Vidrine st->db = pwdbopen(&st->version); 51305f98035SJacques Vidrine st->stayopen = stayopen; 51405f98035SJacques Vidrine break; 51505f98035SJacques Vidrine case ENDPWENT: 51605f98035SJacques Vidrine if (st->db != NULL) { 51705f98035SJacques Vidrine (void)st->db->close(st->db); 51805f98035SJacques Vidrine st->db = NULL; 51905f98035SJacques Vidrine } 52005f98035SJacques Vidrine break; 52105f98035SJacques Vidrine default: 52205f98035SJacques Vidrine break; 52305f98035SJacques Vidrine } 52405f98035SJacques Vidrine return (NS_UNAVAIL); 52505f98035SJacques Vidrine } 52605f98035SJacques Vidrine 52705f98035SJacques Vidrine 52805f98035SJacques Vidrine static int 52905f98035SJacques Vidrine files_passwd(void *retval, void *mdata, va_list ap) 53005f98035SJacques Vidrine { 53105f98035SJacques Vidrine char keybuf[MAXLOGNAME + 1]; 53205f98035SJacques Vidrine DBT key, entry; 53305f98035SJacques Vidrine struct files_state *st; 53405f98035SJacques Vidrine enum nss_lookup_type how; 53505f98035SJacques Vidrine const char *name; 53605f98035SJacques Vidrine struct passwd *pwd; 53705f98035SJacques Vidrine char *buffer; 53805f98035SJacques Vidrine size_t bufsize, namesize; 53905f98035SJacques Vidrine uid_t uid; 54005f98035SJacques Vidrine uint32_t store; 54105f98035SJacques Vidrine int rv, stayopen, *errnop; 54205f98035SJacques Vidrine 54305f98035SJacques Vidrine name = NULL; 54405f98035SJacques Vidrine uid = (uid_t)-1; 54505f98035SJacques Vidrine how = (enum nss_lookup_type)mdata; 54605f98035SJacques Vidrine switch (how) { 54705f98035SJacques Vidrine case nss_lt_name: 54805f98035SJacques Vidrine name = va_arg(ap, const char *); 54905f98035SJacques Vidrine keybuf[0] = _PW_KEYBYNAME; 55005f98035SJacques Vidrine break; 55105f98035SJacques Vidrine case nss_lt_id: 55205f98035SJacques Vidrine uid = va_arg(ap, uid_t); 55305f98035SJacques Vidrine keybuf[0] = _PW_KEYBYUID; 55405f98035SJacques Vidrine break; 55505f98035SJacques Vidrine case nss_lt_all: 55605f98035SJacques Vidrine keybuf[0] = _PW_KEYBYNUM; 55705f98035SJacques Vidrine break; 55805f98035SJacques Vidrine default: 55905f98035SJacques Vidrine rv = NS_NOTFOUND; 56005f98035SJacques Vidrine goto fin; 56105f98035SJacques Vidrine } 56205f98035SJacques Vidrine pwd = va_arg(ap, struct passwd *); 56305f98035SJacques Vidrine buffer = va_arg(ap, char *); 56405f98035SJacques Vidrine bufsize = va_arg(ap, size_t); 56505f98035SJacques Vidrine errnop = va_arg(ap, int *); 56605f98035SJacques Vidrine *errnop = files_getstate(&st); 56705f98035SJacques Vidrine if (*errnop != 0) 56805f98035SJacques Vidrine return (NS_UNAVAIL); 56905f98035SJacques Vidrine if (how == nss_lt_all && st->keynum < 0) { 57005f98035SJacques Vidrine rv = NS_NOTFOUND; 57105f98035SJacques Vidrine goto fin; 57205f98035SJacques Vidrine } 57305f98035SJacques Vidrine if (st->db == NULL && 57405f98035SJacques Vidrine (st->db = pwdbopen(&st->version)) == NULL) { 57505f98035SJacques Vidrine *errnop = errno; 57605f98035SJacques Vidrine rv = NS_UNAVAIL; 57705f98035SJacques Vidrine goto fin; 57805f98035SJacques Vidrine } 57905f98035SJacques Vidrine if (how == nss_lt_all) 58005f98035SJacques Vidrine stayopen = 1; 58105f98035SJacques Vidrine else 58205f98035SJacques Vidrine stayopen = st->stayopen; 58305f98035SJacques Vidrine key.data = keybuf; 58405f98035SJacques Vidrine do { 58505f98035SJacques Vidrine switch (how) { 58605f98035SJacques Vidrine case nss_lt_name: 58705f98035SJacques Vidrine /* MAXLOGNAME includes NUL byte, but we do not 58805f98035SJacques Vidrine * include the NUL byte in the key. 58905f98035SJacques Vidrine */ 590d0509082SJacques Vidrine namesize = strlcpy(&keybuf[1], name, sizeof(keybuf)-1); 59105f98035SJacques Vidrine if (namesize >= sizeof(keybuf)-1) { 59205f98035SJacques Vidrine *errnop = EINVAL; 59305f98035SJacques Vidrine rv = NS_NOTFOUND; 59405f98035SJacques Vidrine goto fin; 59505f98035SJacques Vidrine } 59605f98035SJacques Vidrine key.size = namesize + 1; 59705f98035SJacques Vidrine break; 59805f98035SJacques Vidrine case nss_lt_id: 59905f98035SJacques Vidrine if (st->version < _PWD_CURRENT_VERSION) { 60005f98035SJacques Vidrine memcpy(&keybuf[1], &uid, sizeof(uid)); 60105f98035SJacques Vidrine key.size = sizeof(uid) + 1; 60205f98035SJacques Vidrine } else { 60305f98035SJacques Vidrine store = htonl(uid); 60405f98035SJacques Vidrine memcpy(&keybuf[1], &store, sizeof(store)); 60505f98035SJacques Vidrine key.size = sizeof(store) + 1; 60605f98035SJacques Vidrine } 60705f98035SJacques Vidrine break; 60805f98035SJacques Vidrine case nss_lt_all: 60905f98035SJacques Vidrine st->keynum++; 61005f98035SJacques Vidrine if (st->version < _PWD_CURRENT_VERSION) { 61105f98035SJacques Vidrine memcpy(&keybuf[1], &st->keynum, 61205f98035SJacques Vidrine sizeof(st->keynum)); 61305f98035SJacques Vidrine key.size = sizeof(st->keynum) + 1; 61405f98035SJacques Vidrine } else { 61505f98035SJacques Vidrine store = htonl(st->keynum); 61605f98035SJacques Vidrine memcpy(&keybuf[1], &store, sizeof(store)); 61705f98035SJacques Vidrine key.size = sizeof(store) + 1; 61805f98035SJacques Vidrine } 61905f98035SJacques Vidrine break; 62005f98035SJacques Vidrine } 621b4603f3dSJacques Vidrine keybuf[0] = _PW_VERSIONED(keybuf[0], st->version); 62205f98035SJacques Vidrine rv = st->db->get(st->db, &key, &entry, 0); 62305f98035SJacques Vidrine if (rv < 0 || rv > 1) { /* should never return > 1 */ 62405f98035SJacques Vidrine *errnop = errno; 62505f98035SJacques Vidrine rv = NS_UNAVAIL; 62605f98035SJacques Vidrine goto fin; 62705f98035SJacques Vidrine } else if (rv == 1) { 62805f98035SJacques Vidrine if (how == nss_lt_all) 62905f98035SJacques Vidrine st->keynum = -1; 63005f98035SJacques Vidrine rv = NS_NOTFOUND; 63105f98035SJacques Vidrine goto fin; 63205f98035SJacques Vidrine } 63305f98035SJacques Vidrine rv = pwdb_versions[st->version].match(entry.data, entry.size, 63405f98035SJacques Vidrine how, name, uid); 63505f98035SJacques Vidrine if (rv != NS_SUCCESS) 63605f98035SJacques Vidrine continue; 63705f98035SJacques Vidrine if (entry.size > bufsize) { 63805f98035SJacques Vidrine *errnop = ERANGE; 63905f98035SJacques Vidrine rv = NS_RETURN; 64005f98035SJacques Vidrine break; 64105f98035SJacques Vidrine } 64205f98035SJacques Vidrine memcpy(buffer, entry.data, entry.size); 64305f98035SJacques Vidrine rv = pwdb_versions[st->version].parse(buffer, entry.size, pwd, 64405f98035SJacques Vidrine errnop); 64505f98035SJacques Vidrine } while (how == nss_lt_all && !(rv & NS_TERMINATE)); 64605f98035SJacques Vidrine fin: 64705f98035SJacques Vidrine if (!stayopen && st->db != NULL) { 64805f98035SJacques Vidrine (void)st->db->close(st->db); 64905f98035SJacques Vidrine st->db = NULL; 65005f98035SJacques Vidrine } 65171cc8f07SJacques Vidrine if (rv == NS_SUCCESS) { 65271cc8f07SJacques Vidrine pwd->pw_fields &= ~_PWF_SOURCE; 65371cc8f07SJacques Vidrine pwd->pw_fields |= _PWF_FILES; 65471cc8f07SJacques Vidrine if (retval != NULL) 65505f98035SJacques Vidrine *(struct passwd **)retval = pwd; 65671cc8f07SJacques Vidrine } 65705f98035SJacques Vidrine return (rv); 65805f98035SJacques Vidrine } 65905f98035SJacques Vidrine 66005f98035SJacques Vidrine 66105f98035SJacques Vidrine static int 66205f98035SJacques Vidrine pwdb_match_entry_v3(char *entry, size_t entrysize, enum nss_lookup_type how, 66305f98035SJacques Vidrine const char *name, uid_t uid) 66405f98035SJacques Vidrine { 66505f98035SJacques Vidrine const char *p, *eom; 66605f98035SJacques Vidrine uid_t uid2; 66705f98035SJacques Vidrine 66805f98035SJacques Vidrine eom = &entry[entrysize]; 66905f98035SJacques Vidrine for (p = entry; p < eom; p++) 67005f98035SJacques Vidrine if (*p == '\0') 67105f98035SJacques Vidrine break; 67205f98035SJacques Vidrine if (*p != '\0') 67305f98035SJacques Vidrine return (NS_NOTFOUND); 67405f98035SJacques Vidrine if (how == nss_lt_all) 67505f98035SJacques Vidrine return (NS_SUCCESS); 67605f98035SJacques Vidrine if (how == nss_lt_name) 67705f98035SJacques Vidrine return (strcmp(name, entry) == 0 ? NS_SUCCESS : NS_NOTFOUND); 67805f98035SJacques Vidrine for (p++; p < eom; p++) 67905f98035SJacques Vidrine if (*p == '\0') 68005f98035SJacques Vidrine break; 68105f98035SJacques Vidrine if (*p != '\0' || (++p) + sizeof(uid) >= eom) 68205f98035SJacques Vidrine return (NS_NOTFOUND); 68305f98035SJacques Vidrine memcpy(&uid2, p, sizeof(uid2)); 68405f98035SJacques Vidrine return (uid == uid2 ? NS_SUCCESS : NS_NOTFOUND); 68505f98035SJacques Vidrine } 68605f98035SJacques Vidrine 68705f98035SJacques Vidrine 68805f98035SJacques Vidrine static int 68905f98035SJacques Vidrine pwdb_parse_entry_v3(char *buffer, size_t bufsize, struct passwd *pwd, 69005f98035SJacques Vidrine int *errnop) 69105f98035SJacques Vidrine { 69205f98035SJacques Vidrine char *p, *eom; 69305f98035SJacques Vidrine int32_t pw_change, pw_expire; 69405f98035SJacques Vidrine 69505f98035SJacques Vidrine /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */ 69605f98035SJacques Vidrine p = buffer; 69705f98035SJacques Vidrine eom = &buffer[bufsize]; 69805f98035SJacques Vidrine #define STRING(field) do { \ 69905f98035SJacques Vidrine (field) = p; \ 70005f98035SJacques Vidrine while (p < eom && *p != '\0') \ 70105f98035SJacques Vidrine p++; \ 70205f98035SJacques Vidrine if (p >= eom) \ 70305f98035SJacques Vidrine return (NS_NOTFOUND); \ 70405f98035SJacques Vidrine p++; \ 70505f98035SJacques Vidrine } while (0) 70605f98035SJacques Vidrine #define SCALAR(field) do { \ 70705f98035SJacques Vidrine if (p + sizeof(field) > eom) \ 70805f98035SJacques Vidrine return (NS_NOTFOUND); \ 70905f98035SJacques Vidrine memcpy(&(field), p, sizeof(field)); \ 71005f98035SJacques Vidrine p += sizeof(field); \ 71105f98035SJacques Vidrine } while (0) 71205f98035SJacques Vidrine STRING(pwd->pw_name); 71305f98035SJacques Vidrine STRING(pwd->pw_passwd); 71405f98035SJacques Vidrine SCALAR(pwd->pw_uid); 71505f98035SJacques Vidrine SCALAR(pwd->pw_gid); 71605f98035SJacques Vidrine SCALAR(pw_change); 71705f98035SJacques Vidrine STRING(pwd->pw_class); 71805f98035SJacques Vidrine STRING(pwd->pw_gecos); 71905f98035SJacques Vidrine STRING(pwd->pw_dir); 72005f98035SJacques Vidrine STRING(pwd->pw_shell); 72105f98035SJacques Vidrine SCALAR(pw_expire); 72205f98035SJacques Vidrine SCALAR(pwd->pw_fields); 72305f98035SJacques Vidrine #undef STRING 72405f98035SJacques Vidrine #undef SCALAR 72505f98035SJacques Vidrine pwd->pw_change = pw_change; 72605f98035SJacques Vidrine pwd->pw_expire = pw_expire; 72705f98035SJacques Vidrine return (NS_SUCCESS); 72805f98035SJacques Vidrine } 72905f98035SJacques Vidrine 73005f98035SJacques Vidrine 73105f98035SJacques Vidrine static int 73205f98035SJacques Vidrine pwdb_match_entry_v4(char *entry, size_t entrysize, enum nss_lookup_type how, 73305f98035SJacques Vidrine const char *name, uid_t uid) 73405f98035SJacques Vidrine { 73505f98035SJacques Vidrine const char *p, *eom; 73605f98035SJacques Vidrine uint32_t uid2; 73705f98035SJacques Vidrine 73805f98035SJacques Vidrine eom = &entry[entrysize]; 73905f98035SJacques Vidrine for (p = entry; p < eom; p++) 74005f98035SJacques Vidrine if (*p == '\0') 74105f98035SJacques Vidrine break; 74205f98035SJacques Vidrine if (*p != '\0') 74305f98035SJacques Vidrine return (NS_NOTFOUND); 74405f98035SJacques Vidrine if (how == nss_lt_all) 74505f98035SJacques Vidrine return (NS_SUCCESS); 74605f98035SJacques Vidrine if (how == nss_lt_name) 74705f98035SJacques Vidrine return (strcmp(name, entry) == 0 ? NS_SUCCESS : NS_NOTFOUND); 74805f98035SJacques Vidrine for (p++; p < eom; p++) 74905f98035SJacques Vidrine if (*p == '\0') 75005f98035SJacques Vidrine break; 75105f98035SJacques Vidrine if (*p != '\0' || (++p) + sizeof(uid) >= eom) 75205f98035SJacques Vidrine return (NS_NOTFOUND); 75305f98035SJacques Vidrine memcpy(&uid2, p, sizeof(uid2)); 75405f98035SJacques Vidrine uid2 = ntohl(uid2); 75505f98035SJacques Vidrine return (uid == (uid_t)uid2 ? NS_SUCCESS : NS_NOTFOUND); 75605f98035SJacques Vidrine } 75705f98035SJacques Vidrine 75805f98035SJacques Vidrine 75905f98035SJacques Vidrine static int 76005f98035SJacques Vidrine pwdb_parse_entry_v4(char *buffer, size_t bufsize, struct passwd *pwd, 76105f98035SJacques Vidrine int *errnop) 76205f98035SJacques Vidrine { 76305f98035SJacques Vidrine char *p, *eom; 76405f98035SJacques Vidrine uint32_t n; 76505f98035SJacques Vidrine 76605f98035SJacques Vidrine /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */ 76705f98035SJacques Vidrine p = buffer; 76805f98035SJacques Vidrine eom = &buffer[bufsize]; 76905f98035SJacques Vidrine #define STRING(field) do { \ 77005f98035SJacques Vidrine (field) = p; \ 77105f98035SJacques Vidrine while (p < eom && *p != '\0') \ 77205f98035SJacques Vidrine p++; \ 77305f98035SJacques Vidrine if (p >= eom) \ 77405f98035SJacques Vidrine return (NS_NOTFOUND); \ 77505f98035SJacques Vidrine p++; \ 77605f98035SJacques Vidrine } while (0) 77705f98035SJacques Vidrine #define SCALAR(field) do { \ 77805f98035SJacques Vidrine if (p + sizeof(n) > eom) \ 77905f98035SJacques Vidrine return (NS_NOTFOUND); \ 78005f98035SJacques Vidrine memcpy(&n, p, sizeof(n)); \ 78105f98035SJacques Vidrine (field) = ntohl(n); \ 78205f98035SJacques Vidrine p += sizeof(n); \ 78305f98035SJacques Vidrine } while (0) 78405f98035SJacques Vidrine STRING(pwd->pw_name); 78505f98035SJacques Vidrine STRING(pwd->pw_passwd); 78605f98035SJacques Vidrine SCALAR(pwd->pw_uid); 78705f98035SJacques Vidrine SCALAR(pwd->pw_gid); 78805f98035SJacques Vidrine SCALAR(pwd->pw_change); 78905f98035SJacques Vidrine STRING(pwd->pw_class); 79005f98035SJacques Vidrine STRING(pwd->pw_gecos); 79105f98035SJacques Vidrine STRING(pwd->pw_dir); 79205f98035SJacques Vidrine STRING(pwd->pw_shell); 79305f98035SJacques Vidrine SCALAR(pwd->pw_expire); 79405f98035SJacques Vidrine SCALAR(pwd->pw_fields); 79505f98035SJacques Vidrine #undef STRING 79605f98035SJacques Vidrine #undef SCALAR 79705f98035SJacques Vidrine return (NS_SUCCESS); 79805f98035SJacques Vidrine } 79905f98035SJacques Vidrine 80005f98035SJacques Vidrine 80105f98035SJacques Vidrine #ifdef HESIOD 80205f98035SJacques Vidrine /* 80305f98035SJacques Vidrine * dns backend 80405f98035SJacques Vidrine */ 80505f98035SJacques Vidrine static void 80605f98035SJacques Vidrine dns_endstate(void *p) 80705f98035SJacques Vidrine { 80805f98035SJacques Vidrine free(p); 80905f98035SJacques Vidrine } 81005f98035SJacques Vidrine 81105f98035SJacques Vidrine 81205f98035SJacques Vidrine static int 81305f98035SJacques Vidrine dns_setpwent(void *retval, void *mdata, va_list ap) 81405f98035SJacques Vidrine { 81505f98035SJacques Vidrine struct dns_state *st; 81605f98035SJacques Vidrine int rv; 81705f98035SJacques Vidrine 81805f98035SJacques Vidrine rv = dns_getstate(&st); 81905f98035SJacques Vidrine if (rv != 0) 82005f98035SJacques Vidrine return (NS_UNAVAIL); 82105f98035SJacques Vidrine st->counter = 0; 82205f98035SJacques Vidrine return (NS_UNAVAIL); 82305f98035SJacques Vidrine } 82405f98035SJacques Vidrine 82505f98035SJacques Vidrine 82605f98035SJacques Vidrine static int 82705f98035SJacques Vidrine dns_passwd(void *retval, void *mdata, va_list ap) 82805f98035SJacques Vidrine { 82905f98035SJacques Vidrine char buf[HESIOD_NAME_MAX]; 83005f98035SJacques Vidrine struct dns_state *st; 83105f98035SJacques Vidrine struct passwd *pwd; 83205f98035SJacques Vidrine const char *name, *label; 83305f98035SJacques Vidrine void *ctx; 83405f98035SJacques Vidrine char *buffer, **hes; 83505f98035SJacques Vidrine size_t bufsize, linesize; 83605f98035SJacques Vidrine uid_t uid; 83705f98035SJacques Vidrine enum nss_lookup_type how; 83805f98035SJacques Vidrine int rv, *errnop; 83905f98035SJacques Vidrine 84005f98035SJacques Vidrine ctx = NULL; 84105f98035SJacques Vidrine hes = NULL; 84205f98035SJacques Vidrine name = NULL; 84305f98035SJacques Vidrine uid = (uid_t)-1; 84405f98035SJacques Vidrine how = (enum nss_lookup_type)mdata; 84505f98035SJacques Vidrine switch (how) { 84605f98035SJacques Vidrine case nss_lt_name: 84705f98035SJacques Vidrine name = va_arg(ap, const char *); 84805f98035SJacques Vidrine break; 84905f98035SJacques Vidrine case nss_lt_id: 85005f98035SJacques Vidrine uid = va_arg(ap, uid_t); 85105f98035SJacques Vidrine break; 85205f98035SJacques Vidrine case nss_lt_all: 85305f98035SJacques Vidrine break; 85405f98035SJacques Vidrine } 85505f98035SJacques Vidrine pwd = va_arg(ap, struct passwd *); 85605f98035SJacques Vidrine buffer = va_arg(ap, char *); 85705f98035SJacques Vidrine bufsize = va_arg(ap, size_t); 85805f98035SJacques Vidrine errnop = va_arg(ap, int *); 85905f98035SJacques Vidrine *errnop = dns_getstate(&st); 86005f98035SJacques Vidrine if (*errnop != 0) 86105f98035SJacques Vidrine return (NS_UNAVAIL); 86205f98035SJacques Vidrine if (hesiod_init(&ctx) != 0) { 86305f98035SJacques Vidrine *errnop = errno; 86405f98035SJacques Vidrine rv = NS_UNAVAIL; 86505f98035SJacques Vidrine goto fin; 86605f98035SJacques Vidrine } 86705f98035SJacques Vidrine do { 86805f98035SJacques Vidrine rv = NS_NOTFOUND; 86905f98035SJacques Vidrine switch (how) { 87005f98035SJacques Vidrine case nss_lt_name: 87105f98035SJacques Vidrine label = name; 87205f98035SJacques Vidrine break; 87305f98035SJacques Vidrine case nss_lt_id: 87405f98035SJacques Vidrine if (snprintf(buf, sizeof(buf), "%lu", 87505f98035SJacques Vidrine (unsigned long)uid) >= sizeof(buf)) 87605f98035SJacques Vidrine goto fin; 87705f98035SJacques Vidrine label = buf; 87805f98035SJacques Vidrine break; 87905f98035SJacques Vidrine case nss_lt_all: 88005f98035SJacques Vidrine if (st->counter < 0) 88105f98035SJacques Vidrine goto fin; 88205f98035SJacques Vidrine if (snprintf(buf, sizeof(buf), "passwd-%ld", 88305f98035SJacques Vidrine st->counter++) >= sizeof(buf)) 88405f98035SJacques Vidrine goto fin; 88505f98035SJacques Vidrine label = buf; 88605f98035SJacques Vidrine break; 88705f98035SJacques Vidrine } 88805f98035SJacques Vidrine hes = hesiod_resolve(ctx, label, 88905f98035SJacques Vidrine how == nss_lt_id ? "uid" : "passwd"); 89005f98035SJacques Vidrine if (hes == NULL) { 89105f98035SJacques Vidrine if (how == nss_lt_all) 89205f98035SJacques Vidrine st->counter = -1; 89305f98035SJacques Vidrine if (errno != ENOENT) 89405f98035SJacques Vidrine *errnop = errno; 89505f98035SJacques Vidrine goto fin; 89605f98035SJacques Vidrine } 89705f98035SJacques Vidrine rv = __pw_match_entry(hes[0], strlen(hes[0]), how, name, uid); 89805f98035SJacques Vidrine if (rv != NS_SUCCESS) { 89905f98035SJacques Vidrine hesiod_free_list(ctx, hes); 90005f98035SJacques Vidrine hes = NULL; 90105f98035SJacques Vidrine continue; 90205f98035SJacques Vidrine } 903d0509082SJacques Vidrine linesize = strlcpy(buffer, hes[0], bufsize); 90405f98035SJacques Vidrine if (linesize >= bufsize) { 90505f98035SJacques Vidrine *errnop = ERANGE; 90605f98035SJacques Vidrine rv = NS_RETURN; 90705f98035SJacques Vidrine continue; 90805f98035SJacques Vidrine } 90905f98035SJacques Vidrine hesiod_free_list(ctx, hes); 91005f98035SJacques Vidrine hes = NULL; 91105f98035SJacques Vidrine rv = __pw_parse_entry(buffer, bufsize, pwd, 0, errnop); 91205f98035SJacques Vidrine } while (how == nss_lt_all && !(rv & NS_TERMINATE)); 91305f98035SJacques Vidrine fin: 91405f98035SJacques Vidrine if (hes != NULL) 91505f98035SJacques Vidrine hesiod_free_list(ctx, hes); 91605f98035SJacques Vidrine if (ctx != NULL) 91705f98035SJacques Vidrine hesiod_end(ctx); 91805f98035SJacques Vidrine if (rv == NS_SUCCESS) { 91905f98035SJacques Vidrine pwd->pw_fields &= ~_PWF_SOURCE; 92005f98035SJacques Vidrine pwd->pw_fields |= _PWF_HESIOD; 92105f98035SJacques Vidrine if (retval != NULL) 92205f98035SJacques Vidrine *(struct passwd **)retval = pwd; 92305f98035SJacques Vidrine } 92405f98035SJacques Vidrine return (rv); 92505f98035SJacques Vidrine } 92605f98035SJacques Vidrine #endif /* HESIOD */ 92705f98035SJacques Vidrine 92805f98035SJacques Vidrine 92905f98035SJacques Vidrine #ifdef YP 93005f98035SJacques Vidrine /* 93105f98035SJacques Vidrine * nis backend 93205f98035SJacques Vidrine */ 93305f98035SJacques Vidrine static void 93405f98035SJacques Vidrine nis_endstate(void *p) 93505f98035SJacques Vidrine { 93605f98035SJacques Vidrine free(((struct nis_state *)p)->key); 93705f98035SJacques Vidrine free(p); 93858f0484fSRodney W. Grimes } 93958f0484fSRodney W. Grimes 9400287aa1cSBill Paul /* 9410287aa1cSBill Paul * Test for the presence of special FreeBSD-specific master.passwd.by* 9420287aa1cSBill Paul * maps. We do this using yp_order(). If it fails, then either the server 9430287aa1cSBill Paul * doesn't have the map, or the YPPROC_ORDER procedure isn't supported by 9440287aa1cSBill Paul * the server (Sun NIS+ servers in YP compat mode behave this way). If 9450287aa1cSBill Paul * the master.passwd.by* maps don't exist, then let the lookup routine try 9460287aa1cSBill Paul * the regular passwd.by* maps instead. If the lookup routine fails, it 9470287aa1cSBill Paul * can return an error as needed. 9480287aa1cSBill Paul */ 94951295a4dSJordan K. Hubbard static int 95005f98035SJacques Vidrine nis_map(char *domain, enum nss_lookup_type how, char *buffer, size_t bufsize, 95105f98035SJacques Vidrine int *master) 95258f0484fSRodney W. Grimes { 9530287aa1cSBill Paul int rv, order; 95458f0484fSRodney W. Grimes 95505f98035SJacques Vidrine *master = 0; 956d3fc864fSJacques Vidrine if (geteuid() == 0) { 95705f98035SJacques Vidrine if (snprintf(buffer, bufsize, "master.passwd.by%s", 95805f98035SJacques Vidrine (how == nss_lt_id) ? "uid" : "name") >= bufsize) 95905f98035SJacques Vidrine return (NS_UNAVAIL); 9600287aa1cSBill Paul rv = yp_order(domain, buffer, &order); 96105f98035SJacques Vidrine if (rv == 0) { 96205f98035SJacques Vidrine *master = 1; 96305f98035SJacques Vidrine return (NS_SUCCESS); 96405f98035SJacques Vidrine } 965d3fc864fSJacques Vidrine } 9660287aa1cSBill Paul 96705f98035SJacques Vidrine if (snprintf(buffer, bufsize, "passwd.by%s", 96805f98035SJacques Vidrine (how == nss_lt_id) ? "uid" : "name") >= bufsize) 96905f98035SJacques Vidrine return (NS_UNAVAIL); 9700287aa1cSBill Paul 97105f98035SJacques Vidrine return (NS_SUCCESS); 9728be26e5dSWolfram Schneider } 97358f0484fSRodney W. Grimes 974248aee62SJacques Vidrine 97505f98035SJacques Vidrine static int 97605f98035SJacques Vidrine nis_adjunct(char *domain, const char *name, char *buffer, size_t bufsize) 97705f98035SJacques Vidrine { 97805f98035SJacques Vidrine int rv; 97905f98035SJacques Vidrine char *result, *p, *q, *eor; 98005f98035SJacques Vidrine int resultlen; 981248aee62SJacques Vidrine 98205f98035SJacques Vidrine result = NULL; 98305f98035SJacques Vidrine rv = yp_match(domain, "passwd.adjunct.byname", name, strlen(name), 98405f98035SJacques Vidrine &result, &resultlen); 98505f98035SJacques Vidrine if (rv != 0) 98605f98035SJacques Vidrine rv = 1; 98705f98035SJacques Vidrine else { 98805f98035SJacques Vidrine eor = &result[resultlen]; 98905f98035SJacques Vidrine p = memchr(result, ':', eor - result); 99005f98035SJacques Vidrine if (p != NULL && ++p < eor && 99105f98035SJacques Vidrine (q = memchr(p, ':', eor - p)) != NULL) { 99205f98035SJacques Vidrine if (q - p >= bufsize) 99305f98035SJacques Vidrine rv = -1; 99405f98035SJacques Vidrine else { 99505f98035SJacques Vidrine memcpy(buffer, p, q - p); 99605f98035SJacques Vidrine buffer[q - p] ='\0'; 99705f98035SJacques Vidrine } 99805f98035SJacques Vidrine } else 99905f98035SJacques Vidrine rv = 1; 100005f98035SJacques Vidrine } 100105f98035SJacques Vidrine free(result); 100205f98035SJacques Vidrine return (rv); 100305f98035SJacques Vidrine } 100405f98035SJacques Vidrine 100505f98035SJacques Vidrine 100605f98035SJacques Vidrine static int 100705f98035SJacques Vidrine nis_setpwent(void *retval, void *mdata, va_list ap) 100805f98035SJacques Vidrine { 100905f98035SJacques Vidrine struct nis_state *st; 101005f98035SJacques Vidrine int rv; 101105f98035SJacques Vidrine 101205f98035SJacques Vidrine rv = nis_getstate(&st); 101305f98035SJacques Vidrine if (rv != 0) 101405f98035SJacques Vidrine return (NS_UNAVAIL); 101505f98035SJacques Vidrine st->done = 0; 101605f98035SJacques Vidrine free(st->key); 101705f98035SJacques Vidrine st->key = NULL; 101805f98035SJacques Vidrine return (NS_UNAVAIL); 101905f98035SJacques Vidrine } 102005f98035SJacques Vidrine 102105f98035SJacques Vidrine 102205f98035SJacques Vidrine static int 102305f98035SJacques Vidrine nis_passwd(void *retval, void *mdata, va_list ap) 102405f98035SJacques Vidrine { 102505f98035SJacques Vidrine char map[YPMAXMAP]; 102605f98035SJacques Vidrine struct nis_state *st; 102705f98035SJacques Vidrine struct passwd *pwd; 102805f98035SJacques Vidrine const char *name; 102905f98035SJacques Vidrine char *buffer, *key, *result; 103005f98035SJacques Vidrine size_t bufsize; 103105f98035SJacques Vidrine uid_t uid; 103205f98035SJacques Vidrine enum nss_lookup_type how; 103305f98035SJacques Vidrine int *errnop, keylen, resultlen, rv, master; 103405f98035SJacques Vidrine 103505f98035SJacques Vidrine name = NULL; 103605f98035SJacques Vidrine uid = (uid_t)-1; 103705f98035SJacques Vidrine how = (enum nss_lookup_type)mdata; 103805f98035SJacques Vidrine switch (how) { 103905f98035SJacques Vidrine case nss_lt_name: 104005f98035SJacques Vidrine name = va_arg(ap, const char *); 104105f98035SJacques Vidrine break; 104205f98035SJacques Vidrine case nss_lt_id: 104305f98035SJacques Vidrine uid = va_arg(ap, uid_t); 104405f98035SJacques Vidrine break; 104505f98035SJacques Vidrine case nss_lt_all: 104605f98035SJacques Vidrine break; 104705f98035SJacques Vidrine } 104805f98035SJacques Vidrine pwd = va_arg(ap, struct passwd *); 104905f98035SJacques Vidrine buffer = va_arg(ap, char *); 105005f98035SJacques Vidrine bufsize = va_arg(ap, size_t); 105105f98035SJacques Vidrine errnop = va_arg(ap, int *); 105205f98035SJacques Vidrine *errnop = nis_getstate(&st); 105305f98035SJacques Vidrine if (*errnop != 0) 105405f98035SJacques Vidrine return (NS_UNAVAIL); 105505f98035SJacques Vidrine if (st->domain[0] == '\0') { 105605f98035SJacques Vidrine if (getdomainname(st->domain, sizeof(st->domain)) != 0) { 105705f98035SJacques Vidrine *errnop = errno; 105805f98035SJacques Vidrine return (NS_UNAVAIL); 105905f98035SJacques Vidrine } 106005f98035SJacques Vidrine } 106105f98035SJacques Vidrine rv = nis_map(st->domain, how, map, sizeof(map), &master); 106205f98035SJacques Vidrine if (rv != NS_SUCCESS) 106305f98035SJacques Vidrine return (rv); 106405f98035SJacques Vidrine result = NULL; 106505f98035SJacques Vidrine do { 106605f98035SJacques Vidrine rv = NS_NOTFOUND; 106705f98035SJacques Vidrine switch (how) { 106805f98035SJacques Vidrine case nss_lt_name: 1069d0509082SJacques Vidrine if (strlcpy(buffer, name, bufsize) >= bufsize) 107005f98035SJacques Vidrine goto erange; 107105f98035SJacques Vidrine break; 107205f98035SJacques Vidrine case nss_lt_id: 107305f98035SJacques Vidrine if (snprintf(buffer, bufsize, "%lu", 107405f98035SJacques Vidrine (unsigned long)uid) >= bufsize) 107505f98035SJacques Vidrine goto erange; 107605f98035SJacques Vidrine break; 107705f98035SJacques Vidrine case nss_lt_all: 107805f98035SJacques Vidrine if (st->done) 107905f98035SJacques Vidrine goto fin; 108005f98035SJacques Vidrine break; 108105f98035SJacques Vidrine } 108205f98035SJacques Vidrine result = NULL; 108305f98035SJacques Vidrine if (how == nss_lt_all) { 108405f98035SJacques Vidrine if (st->key == NULL) 108505f98035SJacques Vidrine rv = yp_first(st->domain, map, &st->key, 108605f98035SJacques Vidrine &st->keylen, &result, &resultlen); 108705f98035SJacques Vidrine else { 108805f98035SJacques Vidrine key = st->key; 108905f98035SJacques Vidrine keylen = st->keylen; 109005f98035SJacques Vidrine st->key = NULL; 109105f98035SJacques Vidrine rv = yp_next(st->domain, map, key, keylen, 109205f98035SJacques Vidrine &st->key, &st->keylen, &result, 109305f98035SJacques Vidrine &resultlen); 109405f98035SJacques Vidrine free(key); 109505f98035SJacques Vidrine } 109605f98035SJacques Vidrine if (rv != 0) { 109705f98035SJacques Vidrine free(result); 109805f98035SJacques Vidrine free(st->key); 109905f98035SJacques Vidrine st->key = NULL; 110005f98035SJacques Vidrine if (rv == YPERR_NOMORE) 110105f98035SJacques Vidrine st->done = 1; 110205f98035SJacques Vidrine else 110305f98035SJacques Vidrine rv = NS_UNAVAIL; 110405f98035SJacques Vidrine goto fin; 110505f98035SJacques Vidrine } 110605f98035SJacques Vidrine } else { 110705f98035SJacques Vidrine rv = yp_match(st->domain, map, buffer, strlen(buffer), 110805f98035SJacques Vidrine &result, &resultlen); 110905f98035SJacques Vidrine if (rv == YPERR_KEY) { 111005f98035SJacques Vidrine rv = NS_NOTFOUND; 111105f98035SJacques Vidrine continue; 111205f98035SJacques Vidrine } else if (rv != 0) { 111305f98035SJacques Vidrine free(result); 111405f98035SJacques Vidrine rv = NS_UNAVAIL; 111505f98035SJacques Vidrine continue; 111605f98035SJacques Vidrine } 111705f98035SJacques Vidrine } 111805f98035SJacques Vidrine if (resultlen >= bufsize) 111905f98035SJacques Vidrine goto erange; 112005f98035SJacques Vidrine memcpy(buffer, result, resultlen); 112105f98035SJacques Vidrine buffer[resultlen] = '\0'; 112205f98035SJacques Vidrine free(result); 112305f98035SJacques Vidrine rv = __pw_match_entry(buffer, resultlen, how, name, uid); 112405f98035SJacques Vidrine if (rv == NS_SUCCESS) 112505f98035SJacques Vidrine rv = __pw_parse_entry(buffer, resultlen, pwd, master, 112605f98035SJacques Vidrine errnop); 112705f98035SJacques Vidrine } while (how == nss_lt_all && !(rv & NS_TERMINATE)); 112805f98035SJacques Vidrine fin: 112905f98035SJacques Vidrine if (rv == NS_SUCCESS) { 113005f98035SJacques Vidrine if (strstr(pwd->pw_passwd, "##") != NULL) { 11312734a36fSJacques Vidrine rv = nis_adjunct(st->domain, pwd->pw_name, 113205f98035SJacques Vidrine &buffer[resultlen+1], bufsize-resultlen-1); 113305f98035SJacques Vidrine if (rv < 0) 113405f98035SJacques Vidrine goto erange; 113505f98035SJacques Vidrine else if (rv == 0) 113605f98035SJacques Vidrine pwd->pw_passwd = &buffer[resultlen+1]; 113705f98035SJacques Vidrine } 113805f98035SJacques Vidrine pwd->pw_fields &= ~_PWF_SOURCE; 113905f98035SJacques Vidrine pwd->pw_fields |= _PWF_NIS; 114005f98035SJacques Vidrine if (retval != NULL) 114105f98035SJacques Vidrine *(struct passwd **)retval = pwd; 1142dbb4b1c8SJonathan Chen rv = NS_SUCCESS; 114305f98035SJacques Vidrine } 114405f98035SJacques Vidrine return (rv); 114505f98035SJacques Vidrine erange: 114605f98035SJacques Vidrine *errnop = ERANGE; 114705f98035SJacques Vidrine return (NS_RETURN); 114805f98035SJacques Vidrine } 114905f98035SJacques Vidrine #endif /* YP */ 115005f98035SJacques Vidrine 115105f98035SJacques Vidrine 115205f98035SJacques Vidrine /* 115305f98035SJacques Vidrine * compat backend 115405f98035SJacques Vidrine */ 115505f98035SJacques Vidrine static void 115605f98035SJacques Vidrine compat_clear_template(struct passwd *template) 115705f98035SJacques Vidrine { 115805f98035SJacques Vidrine 115905f98035SJacques Vidrine free(template->pw_passwd); 116005f98035SJacques Vidrine free(template->pw_gecos); 116105f98035SJacques Vidrine free(template->pw_dir); 116205f98035SJacques Vidrine free(template->pw_shell); 116305f98035SJacques Vidrine memset(template, 0, sizeof(*template)); 116405f98035SJacques Vidrine } 116505f98035SJacques Vidrine 116605f98035SJacques Vidrine 116705f98035SJacques Vidrine static int 116805f98035SJacques Vidrine compat_set_template(struct passwd *src, struct passwd *template) 116905f98035SJacques Vidrine { 117005f98035SJacques Vidrine 117105f98035SJacques Vidrine compat_clear_template(template); 117205f98035SJacques Vidrine #ifdef PW_OVERRIDE_PASSWD 117305f98035SJacques Vidrine if ((src->pw_fields & _PWF_PASSWD) && 117405f98035SJacques Vidrine (template->pw_passwd = strdup(src->pw_passwd)) == NULL) 117505f98035SJacques Vidrine goto enomem; 117605f98035SJacques Vidrine #endif 117705f98035SJacques Vidrine if (src->pw_fields & _PWF_UID) 117805f98035SJacques Vidrine template->pw_uid = src->pw_uid; 117905f98035SJacques Vidrine if (src->pw_fields & _PWF_GID) 118005f98035SJacques Vidrine template->pw_gid = src->pw_gid; 118105f98035SJacques Vidrine if ((src->pw_fields & _PWF_GECOS) && 118205f98035SJacques Vidrine (template->pw_gecos = strdup(src->pw_gecos)) == NULL) 118305f98035SJacques Vidrine goto enomem; 118405f98035SJacques Vidrine if ((src->pw_fields & _PWF_DIR) && 118505f98035SJacques Vidrine (template->pw_dir = strdup(src->pw_dir)) == NULL) 118605f98035SJacques Vidrine goto enomem; 118705f98035SJacques Vidrine if ((src->pw_fields & _PWF_SHELL) && 118805f98035SJacques Vidrine (template->pw_shell = strdup(src->pw_shell)) == NULL) 118905f98035SJacques Vidrine goto enomem; 119005f98035SJacques Vidrine template->pw_fields = src->pw_fields; 119105f98035SJacques Vidrine return (0); 119205f98035SJacques Vidrine enomem: 119305f98035SJacques Vidrine syslog(LOG_ERR, "getpwent memory allocation failure"); 119405f98035SJacques Vidrine return (-1); 119505f98035SJacques Vidrine } 119605f98035SJacques Vidrine 119705f98035SJacques Vidrine 119805f98035SJacques Vidrine static int 119905f98035SJacques Vidrine compat_use_template(struct passwd *pwd, struct passwd *template, char *buffer, 120005f98035SJacques Vidrine size_t bufsize) 120105f98035SJacques Vidrine { 120205f98035SJacques Vidrine struct passwd hold; 120305f98035SJacques Vidrine char *copy, *p, *q, *eob; 120405f98035SJacques Vidrine size_t n; 120505f98035SJacques Vidrine 120605f98035SJacques Vidrine /* We cannot know the layout of the password fields in `buffer', 120705f98035SJacques Vidrine * so we have to copy everything. 120805f98035SJacques Vidrine */ 120905f98035SJacques Vidrine if (template->pw_fields == 0) /* nothing to fill-in */ 121005f98035SJacques Vidrine return (0); 121105f98035SJacques Vidrine n = 0; 121205f98035SJacques Vidrine n += pwd->pw_name != NULL ? strlen(pwd->pw_name) + 1 : 0; 121305f98035SJacques Vidrine n += pwd->pw_passwd != NULL ? strlen(pwd->pw_passwd) + 1 : 0; 121405f98035SJacques Vidrine n += pwd->pw_class != NULL ? strlen(pwd->pw_class) + 1 : 0; 121505f98035SJacques Vidrine n += pwd->pw_gecos != NULL ? strlen(pwd->pw_gecos) + 1 : 0; 121605f98035SJacques Vidrine n += pwd->pw_dir != NULL ? strlen(pwd->pw_dir) + 1 : 0; 121705f98035SJacques Vidrine n += pwd->pw_shell != NULL ? strlen(pwd->pw_shell) + 1 : 0; 121805f98035SJacques Vidrine copy = malloc(n); 121905f98035SJacques Vidrine if (copy == NULL) { 122005f98035SJacques Vidrine syslog(LOG_ERR, "getpwent memory allocation failure"); 122105f98035SJacques Vidrine return (ENOMEM); 122205f98035SJacques Vidrine } 122305f98035SJacques Vidrine p = copy; 122405f98035SJacques Vidrine eob = ©[n]; 122505f98035SJacques Vidrine #define COPY(field) do { \ 122605f98035SJacques Vidrine if (pwd->field == NULL) \ 122705f98035SJacques Vidrine hold.field = NULL; \ 122805f98035SJacques Vidrine else { \ 122905f98035SJacques Vidrine hold.field = p; \ 1230d0509082SJacques Vidrine p += strlcpy(p, pwd->field, eob-p) + 1; \ 123105f98035SJacques Vidrine } \ 123205f98035SJacques Vidrine } while (0) 123305f98035SJacques Vidrine COPY(pw_name); 123405f98035SJacques Vidrine COPY(pw_passwd); 123505f98035SJacques Vidrine COPY(pw_class); 123605f98035SJacques Vidrine COPY(pw_gecos); 123705f98035SJacques Vidrine COPY(pw_dir); 123805f98035SJacques Vidrine COPY(pw_shell); 123905f98035SJacques Vidrine #undef COPY 124005f98035SJacques Vidrine p = buffer; 124105f98035SJacques Vidrine eob = &buffer[bufsize]; 124205f98035SJacques Vidrine #define COPY(field, flag) do { \ 124305f98035SJacques Vidrine q = (template->pw_fields & flag) ? template->field : hold.field; \ 124405f98035SJacques Vidrine if (q == NULL) \ 124505f98035SJacques Vidrine pwd->field = NULL; \ 124605f98035SJacques Vidrine else { \ 124705f98035SJacques Vidrine pwd->field = p; \ 1248d0509082SJacques Vidrine if ((n = strlcpy(p, q, eob-p)) >= eob-p) { \ 124905f98035SJacques Vidrine free(copy); \ 125005f98035SJacques Vidrine return (ERANGE); \ 125105f98035SJacques Vidrine } \ 125205f98035SJacques Vidrine p += n + 1; \ 125305f98035SJacques Vidrine } \ 125405f98035SJacques Vidrine } while (0) 125505f98035SJacques Vidrine COPY(pw_name, 0); 125605f98035SJacques Vidrine #ifdef PW_OVERRIDE_PASSWD 125705f98035SJacques Vidrine COPY(pw_passwd, _PWF_PASSWD); 125805f98035SJacques Vidrine #else 125905f98035SJacques Vidrine COPY(pw_passwd, 0); 126005f98035SJacques Vidrine #endif 126105f98035SJacques Vidrine COPY(pw_class, 0); 126205f98035SJacques Vidrine COPY(pw_gecos, _PWF_GECOS); 126305f98035SJacques Vidrine COPY(pw_dir, _PWF_DIR); 126405f98035SJacques Vidrine COPY(pw_shell, _PWF_SHELL); 126505f98035SJacques Vidrine #undef COPY 126605f98035SJacques Vidrine #define COPY(field, flag) do { \ 126705f98035SJacques Vidrine if (template->pw_fields & flag) \ 126805f98035SJacques Vidrine pwd->field = template->field; \ 126905f98035SJacques Vidrine } while (0) 127005f98035SJacques Vidrine COPY(pw_uid, _PWF_UID); 127105f98035SJacques Vidrine COPY(pw_gid, _PWF_GID); 127205f98035SJacques Vidrine #undef COPY 127305f98035SJacques Vidrine free(copy); 127405f98035SJacques Vidrine return (0); 127505f98035SJacques Vidrine } 127605f98035SJacques Vidrine 127705f98035SJacques Vidrine 127805f98035SJacques Vidrine static int 127905f98035SJacques Vidrine compat_exclude(const char *name, DB **db) 128005f98035SJacques Vidrine { 128105f98035SJacques Vidrine DBT key, data; 128205f98035SJacques Vidrine 128305f98035SJacques Vidrine if (*db == NULL && 128405f98035SJacques Vidrine (*db = dbopen(NULL, O_RDWR, 600, DB_HASH, 0)) == NULL) 128505f98035SJacques Vidrine return (errno); 128605f98035SJacques Vidrine key.size = strlen(name); 128705f98035SJacques Vidrine key.data = (char *)name; 128805f98035SJacques Vidrine data.size = 0; 128905f98035SJacques Vidrine data.data = NULL; 129005f98035SJacques Vidrine 129105f98035SJacques Vidrine if ((*db)->put(*db, &key, &data, 0) == -1) 129205f98035SJacques Vidrine return (errno); 129305f98035SJacques Vidrine return (0); 129405f98035SJacques Vidrine } 129505f98035SJacques Vidrine 129605f98035SJacques Vidrine 129705f98035SJacques Vidrine static int 129805f98035SJacques Vidrine compat_is_excluded(const char *name, DB *db) 129905f98035SJacques Vidrine { 130005f98035SJacques Vidrine DBT key, data; 130105f98035SJacques Vidrine 130205f98035SJacques Vidrine if (db == NULL) 130305f98035SJacques Vidrine return (0); 130405f98035SJacques Vidrine key.size = strlen(name); 130505f98035SJacques Vidrine key.data = (char *)name; 130605f98035SJacques Vidrine return (db->get(db, &key, &data, 0) == 0); 130705f98035SJacques Vidrine } 130805f98035SJacques Vidrine 130905f98035SJacques Vidrine 131005f98035SJacques Vidrine static int 131105f98035SJacques Vidrine compat_redispatch(struct compat_state *st, enum nss_lookup_type how, 131205f98035SJacques Vidrine enum nss_lookup_type lookup_how, const char *name, const char *lookup_name, 131305f98035SJacques Vidrine uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, int *errnop) 131405f98035SJacques Vidrine { 131505f98035SJacques Vidrine static const ns_src compatsrc[] = { 131605f98035SJacques Vidrine #ifdef YP 131705f98035SJacques Vidrine { NSSRC_NIS, NS_SUCCESS }, 131805f98035SJacques Vidrine #endif 131905f98035SJacques Vidrine { NULL, 0 } 132005f98035SJacques Vidrine }; 132105f98035SJacques Vidrine ns_dtab dtab[] = { 132205f98035SJacques Vidrine #ifdef YP 132305f98035SJacques Vidrine { NSSRC_NIS, nis_passwd, NULL }, 132405f98035SJacques Vidrine #endif 132505f98035SJacques Vidrine #ifdef HESIOD 132605f98035SJacques Vidrine { NSSRC_DNS, dns_passwd, NULL }, 132705f98035SJacques Vidrine #endif 132805f98035SJacques Vidrine { NULL, NULL, NULL } 132905f98035SJacques Vidrine }; 133005f98035SJacques Vidrine void *discard; 133105f98035SJacques Vidrine int rv, e, i; 133205f98035SJacques Vidrine 133305f98035SJacques Vidrine for (i = 0; i < sizeof(dtab)/sizeof(dtab[0]) - 1; i++) 133405f98035SJacques Vidrine dtab[i].mdata = (void *)lookup_how; 133505f98035SJacques Vidrine more: 1336e2527dafSJacques Vidrine pwd_init(pwd); 133705f98035SJacques Vidrine switch (lookup_how) { 133805f98035SJacques Vidrine case nss_lt_all: 133905f98035SJacques Vidrine rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT, 134005f98035SJacques Vidrine "getpwent_r", compatsrc, pwd, buffer, bufsize, 134105f98035SJacques Vidrine errnop); 134205f98035SJacques Vidrine break; 134305f98035SJacques Vidrine case nss_lt_id: 134405f98035SJacques Vidrine rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT, 134505f98035SJacques Vidrine "getpwuid_r", compatsrc, uid, pwd, buffer, 134605f98035SJacques Vidrine bufsize, errnop); 134705f98035SJacques Vidrine break; 134805f98035SJacques Vidrine case nss_lt_name: 134905f98035SJacques Vidrine rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT, 135005f98035SJacques Vidrine "getpwnam_r", compatsrc, lookup_name, pwd, buffer, 135105f98035SJacques Vidrine bufsize, errnop); 135205f98035SJacques Vidrine break; 135305f98035SJacques Vidrine default: 135405f98035SJacques Vidrine return (NS_UNAVAIL); 135505f98035SJacques Vidrine } 135605f98035SJacques Vidrine if (rv != NS_SUCCESS) 135705f98035SJacques Vidrine return (rv); 135805f98035SJacques Vidrine if (compat_is_excluded(pwd->pw_name, st->exclude)) { 135905f98035SJacques Vidrine if (how == nss_lt_all) 136005f98035SJacques Vidrine goto more; 136105f98035SJacques Vidrine return (NS_NOTFOUND); 136205f98035SJacques Vidrine } 136305f98035SJacques Vidrine e = compat_use_template(pwd, &st->template, buffer, bufsize); 136405f98035SJacques Vidrine if (e != 0) { 136505f98035SJacques Vidrine *errnop = e; 136605f98035SJacques Vidrine if (e == ERANGE) 136705f98035SJacques Vidrine return (NS_RETURN); 136805f98035SJacques Vidrine else 136905f98035SJacques Vidrine return (NS_UNAVAIL); 137005f98035SJacques Vidrine } 137105f98035SJacques Vidrine switch (how) { 137205f98035SJacques Vidrine case nss_lt_name: 137305f98035SJacques Vidrine if (strcmp(name, pwd->pw_name) != 0) 137405f98035SJacques Vidrine return (NS_NOTFOUND); 137505f98035SJacques Vidrine break; 137605f98035SJacques Vidrine case nss_lt_id: 137705f98035SJacques Vidrine if (uid != pwd->pw_uid) 137805f98035SJacques Vidrine return (NS_NOTFOUND); 137905f98035SJacques Vidrine break; 138005f98035SJacques Vidrine default: 138105f98035SJacques Vidrine break; 138205f98035SJacques Vidrine } 138305f98035SJacques Vidrine return (NS_SUCCESS); 138405f98035SJacques Vidrine } 138505f98035SJacques Vidrine 138605f98035SJacques Vidrine 138705f98035SJacques Vidrine static void 138805f98035SJacques Vidrine compat_endstate(void *p) 138905f98035SJacques Vidrine { 139005f98035SJacques Vidrine struct compat_state *st; 139105f98035SJacques Vidrine 139205f98035SJacques Vidrine if (p == NULL) 139305f98035SJacques Vidrine return; 139405f98035SJacques Vidrine st = (struct compat_state *)p; 139505f98035SJacques Vidrine if (st->db != NULL) 139605f98035SJacques Vidrine st->db->close(st->db); 139705f98035SJacques Vidrine if (st->exclude != NULL) 139805f98035SJacques Vidrine st->exclude->close(st->exclude); 139905f98035SJacques Vidrine compat_clear_template(&st->template); 140005f98035SJacques Vidrine free(p); 140105f98035SJacques Vidrine } 140205f98035SJacques Vidrine 140305f98035SJacques Vidrine 140405f98035SJacques Vidrine static int 140505f98035SJacques Vidrine compat_setpwent(void *retval, void *mdata, va_list ap) 140605f98035SJacques Vidrine { 1407c14d379dSJacques Vidrine static const ns_src compatsrc[] = { 1408c14d379dSJacques Vidrine #ifdef YP 1409c14d379dSJacques Vidrine { NSSRC_NIS, NS_SUCCESS }, 1410c14d379dSJacques Vidrine #endif 1411c14d379dSJacques Vidrine { NULL, 0 } 1412c14d379dSJacques Vidrine }; 1413c14d379dSJacques Vidrine ns_dtab dtab[] = { 1414c14d379dSJacques Vidrine #ifdef YP 1415c14d379dSJacques Vidrine { NSSRC_NIS, nis_setpwent, NULL }, 1416c14d379dSJacques Vidrine #endif 1417c14d379dSJacques Vidrine #ifdef HESIOD 1418c14d379dSJacques Vidrine { NSSRC_DNS, dns_setpwent, NULL }, 1419c14d379dSJacques Vidrine #endif 1420c14d379dSJacques Vidrine { NULL, NULL, NULL } 1421c14d379dSJacques Vidrine }; 142205f98035SJacques Vidrine struct compat_state *st; 142305f98035SJacques Vidrine int rv, stayopen; 142405f98035SJacques Vidrine 1425c14d379dSJacques Vidrine #define set_setent(x, y) do { \ 1426c14d379dSJacques Vidrine int i; \ 1427c14d379dSJacques Vidrine \ 1428c14d379dSJacques Vidrine for (i = 0; i < (sizeof(x)/sizeof(x[0])) - 1; i++) \ 1429c14d379dSJacques Vidrine x[i].mdata = (void *)y; \ 1430c14d379dSJacques Vidrine } while (0) 1431c14d379dSJacques Vidrine 143205f98035SJacques Vidrine rv = compat_getstate(&st); 143305f98035SJacques Vidrine if (rv != 0) 143405f98035SJacques Vidrine return (NS_UNAVAIL); 143505f98035SJacques Vidrine switch ((enum constants)mdata) { 143605f98035SJacques Vidrine case SETPWENT: 143705f98035SJacques Vidrine stayopen = va_arg(ap, int); 143805f98035SJacques Vidrine st->keynum = 0; 143905f98035SJacques Vidrine if (stayopen) 144005f98035SJacques Vidrine st->db = pwdbopen(&st->version); 144105f98035SJacques Vidrine st->stayopen = stayopen; 1442c14d379dSJacques Vidrine set_setent(dtab, mdata); 1443c14d379dSJacques Vidrine (void)_nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "setpwent", 1444c14d379dSJacques Vidrine compatsrc, 0); 144505f98035SJacques Vidrine break; 144605f98035SJacques Vidrine case ENDPWENT: 144705f98035SJacques Vidrine if (st->db != NULL) { 144805f98035SJacques Vidrine (void)st->db->close(st->db); 144905f98035SJacques Vidrine st->db = NULL; 145005f98035SJacques Vidrine } 1451c14d379dSJacques Vidrine set_setent(dtab, mdata); 1452c14d379dSJacques Vidrine (void)_nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "endpwent", 1453c14d379dSJacques Vidrine compatsrc, 0); 145405f98035SJacques Vidrine break; 145505f98035SJacques Vidrine default: 145605f98035SJacques Vidrine break; 145705f98035SJacques Vidrine } 145805f98035SJacques Vidrine return (NS_UNAVAIL); 1459c14d379dSJacques Vidrine #undef set_setent 146005f98035SJacques Vidrine } 146105f98035SJacques Vidrine 146205f98035SJacques Vidrine 146305f98035SJacques Vidrine static int 146405f98035SJacques Vidrine compat_passwd(void *retval, void *mdata, va_list ap) 146505f98035SJacques Vidrine { 146605f98035SJacques Vidrine char keybuf[MAXLOGNAME + 1]; 146705f98035SJacques Vidrine DBT key, entry; 146805f98035SJacques Vidrine struct compat_state *st; 146905f98035SJacques Vidrine enum nss_lookup_type how; 147005f98035SJacques Vidrine const char *name; 147105f98035SJacques Vidrine struct passwd *pwd; 147205f98035SJacques Vidrine char *buffer, *pw_name; 147305f98035SJacques Vidrine char *host, *user, *domain; 147405f98035SJacques Vidrine size_t bufsize; 147505f98035SJacques Vidrine uid_t uid; 147605f98035SJacques Vidrine uint32_t store; 1477a9ceaa9dSJacques Vidrine int rv, from_compat, stayopen, *errnop; 147805f98035SJacques Vidrine 1479a9ceaa9dSJacques Vidrine from_compat = 0; 148005f98035SJacques Vidrine name = NULL; 148105f98035SJacques Vidrine uid = (uid_t)-1; 148205f98035SJacques Vidrine how = (enum nss_lookup_type)mdata; 148305f98035SJacques Vidrine switch (how) { 148405f98035SJacques Vidrine case nss_lt_name: 148505f98035SJacques Vidrine name = va_arg(ap, const char *); 148605f98035SJacques Vidrine break; 148705f98035SJacques Vidrine case nss_lt_id: 148805f98035SJacques Vidrine uid = va_arg(ap, uid_t); 148905f98035SJacques Vidrine break; 149005f98035SJacques Vidrine case nss_lt_all: 149105f98035SJacques Vidrine break; 149205f98035SJacques Vidrine default: 149305f98035SJacques Vidrine rv = NS_NOTFOUND; 149405f98035SJacques Vidrine goto fin; 149505f98035SJacques Vidrine } 149605f98035SJacques Vidrine pwd = va_arg(ap, struct passwd *); 149705f98035SJacques Vidrine buffer = va_arg(ap, char *); 149805f98035SJacques Vidrine bufsize = va_arg(ap, size_t); 149905f98035SJacques Vidrine errnop = va_arg(ap, int *); 150005f98035SJacques Vidrine *errnop = compat_getstate(&st); 150105f98035SJacques Vidrine if (*errnop != 0) 150205f98035SJacques Vidrine return (NS_UNAVAIL); 150305f98035SJacques Vidrine if (how == nss_lt_all && st->keynum < 0) { 150405f98035SJacques Vidrine rv = NS_NOTFOUND; 150505f98035SJacques Vidrine goto fin; 150605f98035SJacques Vidrine } 150705f98035SJacques Vidrine if (st->db == NULL && 150805f98035SJacques Vidrine (st->db = pwdbopen(&st->version)) == NULL) { 150905f98035SJacques Vidrine *errnop = errno; 151005f98035SJacques Vidrine rv = NS_UNAVAIL; 151105f98035SJacques Vidrine goto fin; 151205f98035SJacques Vidrine } 151305f98035SJacques Vidrine if (how == nss_lt_all) { 151405f98035SJacques Vidrine if (st->keynum < 0) { 151505f98035SJacques Vidrine rv = NS_NOTFOUND; 151605f98035SJacques Vidrine goto fin; 151705f98035SJacques Vidrine } 151805f98035SJacques Vidrine stayopen = 1; 151905f98035SJacques Vidrine } else { 152005f98035SJacques Vidrine st->keynum = 0; 152105f98035SJacques Vidrine stayopen = st->stayopen; 152205f98035SJacques Vidrine } 152305f98035SJacques Vidrine docompat: 152405f98035SJacques Vidrine rv = NS_NOTFOUND; 152505f98035SJacques Vidrine switch (st->compat) { 152605f98035SJacques Vidrine case COMPAT_MODE_ALL: 152705f98035SJacques Vidrine rv = compat_redispatch(st, how, how, name, name, uid, pwd, 152805f98035SJacques Vidrine buffer, bufsize, errnop); 152905f98035SJacques Vidrine if (rv != NS_SUCCESS) 153005f98035SJacques Vidrine st->compat = COMPAT_MODE_OFF; 153105f98035SJacques Vidrine break; 153205f98035SJacques Vidrine case COMPAT_MODE_NETGROUP: 153305f98035SJacques Vidrine /* XXX getnetgrent is not thread-safe. */ 153405f98035SJacques Vidrine do { 153505f98035SJacques Vidrine rv = getnetgrent(&host, &user, &domain); 153605f98035SJacques Vidrine if (rv == 0) { 153705f98035SJacques Vidrine endnetgrent(); 153805f98035SJacques Vidrine st->compat = COMPAT_MODE_OFF; 153905f98035SJacques Vidrine rv = NS_NOTFOUND; 154005f98035SJacques Vidrine continue; 154105f98035SJacques Vidrine } else if (user == NULL || user[0] == '\0') 154205f98035SJacques Vidrine continue; 154305f98035SJacques Vidrine rv = compat_redispatch(st, how, nss_lt_name, name, 154405f98035SJacques Vidrine user, uid, pwd, buffer, bufsize, errnop); 154505f98035SJacques Vidrine } while (st->compat == COMPAT_MODE_NETGROUP && 154605f98035SJacques Vidrine !(rv & NS_TERMINATE)); 154705f98035SJacques Vidrine break; 154805f98035SJacques Vidrine case COMPAT_MODE_NAME: 154905f98035SJacques Vidrine rv = compat_redispatch(st, how, nss_lt_name, name, st->name, 155005f98035SJacques Vidrine uid, pwd, buffer, bufsize, errnop); 155105f98035SJacques Vidrine free(st->name); 155205f98035SJacques Vidrine st->name = NULL; 155305f98035SJacques Vidrine st->compat = COMPAT_MODE_OFF; 155405f98035SJacques Vidrine break; 155505f98035SJacques Vidrine default: 155605f98035SJacques Vidrine break; 155705f98035SJacques Vidrine } 1558a9ceaa9dSJacques Vidrine if (rv & NS_TERMINATE) { 1559a9ceaa9dSJacques Vidrine from_compat = 1; 156005f98035SJacques Vidrine goto fin; 1561a9ceaa9dSJacques Vidrine } 156205f98035SJacques Vidrine key.data = keybuf; 156305f98035SJacques Vidrine rv = NS_NOTFOUND; 156405f98035SJacques Vidrine while (st->keynum >= 0) { 156505f98035SJacques Vidrine st->keynum++; 156605f98035SJacques Vidrine if (st->version < _PWD_CURRENT_VERSION) { 156705f98035SJacques Vidrine memcpy(&keybuf[1], &st->keynum, sizeof(st->keynum)); 156805f98035SJacques Vidrine key.size = sizeof(st->keynum) + 1; 156905f98035SJacques Vidrine } else { 157005f98035SJacques Vidrine store = htonl(st->keynum); 157105f98035SJacques Vidrine memcpy(&keybuf[1], &store, sizeof(store)); 157205f98035SJacques Vidrine key.size = sizeof(store) + 1; 157305f98035SJacques Vidrine } 1574b4603f3dSJacques Vidrine keybuf[0] = _PW_VERSIONED(_PW_KEYBYNUM, st->version); 157505f98035SJacques Vidrine rv = st->db->get(st->db, &key, &entry, 0); 157605f98035SJacques Vidrine if (rv < 0 || rv > 1) { /* should never return > 1 */ 157705f98035SJacques Vidrine *errnop = errno; 157805f98035SJacques Vidrine rv = NS_UNAVAIL; 157905f98035SJacques Vidrine goto fin; 158005f98035SJacques Vidrine } else if (rv == 1) { 158105f98035SJacques Vidrine st->keynum = -1; 158205f98035SJacques Vidrine rv = NS_NOTFOUND; 158305f98035SJacques Vidrine goto fin; 158405f98035SJacques Vidrine } 158505f98035SJacques Vidrine pw_name = (char *)entry.data; 158605f98035SJacques Vidrine switch (pw_name[0]) { 158705f98035SJacques Vidrine case '+': 158805f98035SJacques Vidrine switch (pw_name[1]) { 158905f98035SJacques Vidrine case '\0': 159005f98035SJacques Vidrine st->compat = COMPAT_MODE_ALL; 159105f98035SJacques Vidrine break; 159205f98035SJacques Vidrine case '@': 159305f98035SJacques Vidrine setnetgrent(&pw_name[2]); 159405f98035SJacques Vidrine st->compat = COMPAT_MODE_NETGROUP; 159505f98035SJacques Vidrine break; 159605f98035SJacques Vidrine default: 159705f98035SJacques Vidrine st->name = strdup(&pw_name[1]); 159805f98035SJacques Vidrine if (st->name == NULL) { 159905f98035SJacques Vidrine syslog(LOG_ERR, 160005f98035SJacques Vidrine "getpwent memory allocation failure"); 160105f98035SJacques Vidrine *errnop = ENOMEM; 160205f98035SJacques Vidrine rv = NS_UNAVAIL; 160305f98035SJacques Vidrine break; 160405f98035SJacques Vidrine } 160505f98035SJacques Vidrine st->compat = COMPAT_MODE_NAME; 160605f98035SJacques Vidrine } 160705f98035SJacques Vidrine if (entry.size > bufsize) { 160805f98035SJacques Vidrine *errnop = ERANGE; 160905f98035SJacques Vidrine rv = NS_RETURN; 161005f98035SJacques Vidrine goto fin; 161105f98035SJacques Vidrine } 161205f98035SJacques Vidrine memcpy(buffer, entry.data, entry.size); 161305f98035SJacques Vidrine rv = pwdb_versions[st->version].parse(buffer, 161405f98035SJacques Vidrine entry.size, pwd, errnop); 161505f98035SJacques Vidrine if (rv != NS_SUCCESS) 161605f98035SJacques Vidrine ; 161705f98035SJacques Vidrine else if (compat_set_template(pwd, &st->template) < 0) { 161805f98035SJacques Vidrine *errnop = ENOMEM; 161905f98035SJacques Vidrine rv = NS_UNAVAIL; 162005f98035SJacques Vidrine goto fin; 162105f98035SJacques Vidrine } 162205f98035SJacques Vidrine goto docompat; 162305f98035SJacques Vidrine case '-': 162405f98035SJacques Vidrine switch (pw_name[1]) { 162505f98035SJacques Vidrine case '\0': 162605f98035SJacques Vidrine /* XXX Maybe syslog warning */ 162705f98035SJacques Vidrine continue; 162805f98035SJacques Vidrine case '@': 162905f98035SJacques Vidrine setnetgrent(&pw_name[2]); 163005f98035SJacques Vidrine while (getnetgrent(&host, &user, &domain) != 163116fc3635SMark Murray 0) { 163205f98035SJacques Vidrine if (user != NULL && user[0] != '\0') 163305f98035SJacques Vidrine compat_exclude(user, 163405f98035SJacques Vidrine &st->exclude); 163505f98035SJacques Vidrine } 163605f98035SJacques Vidrine endnetgrent(); 163705f98035SJacques Vidrine continue; 163805f98035SJacques Vidrine default: 163905f98035SJacques Vidrine compat_exclude(&pw_name[1], &st->exclude); 164005f98035SJacques Vidrine continue; 164105f98035SJacques Vidrine } 164205f98035SJacques Vidrine break; 164305f98035SJacques Vidrine default: 164405f98035SJacques Vidrine break; 164505f98035SJacques Vidrine } 164605f98035SJacques Vidrine if (compat_is_excluded((char *)entry.data, st->exclude)) 164705f98035SJacques Vidrine continue; 164805f98035SJacques Vidrine rv = pwdb_versions[st->version].match(entry.data, entry.size, 164905f98035SJacques Vidrine how, name, uid); 165005f98035SJacques Vidrine if (rv == NS_RETURN) 165105f98035SJacques Vidrine break; 165205f98035SJacques Vidrine else if (rv != NS_SUCCESS) 165305f98035SJacques Vidrine continue; 165405f98035SJacques Vidrine if (entry.size > bufsize) { 165505f98035SJacques Vidrine *errnop = ERANGE; 165605f98035SJacques Vidrine rv = NS_RETURN; 165705f98035SJacques Vidrine break; 165805f98035SJacques Vidrine } 165905f98035SJacques Vidrine memcpy(buffer, entry.data, entry.size); 166005f98035SJacques Vidrine rv = pwdb_versions[st->version].parse(buffer, entry.size, pwd, 166105f98035SJacques Vidrine errnop); 166205f98035SJacques Vidrine if (rv & NS_TERMINATE) 166305f98035SJacques Vidrine break; 166405f98035SJacques Vidrine } 166505f98035SJacques Vidrine fin: 166605f98035SJacques Vidrine if (!stayopen && st->db != NULL) { 166705f98035SJacques Vidrine (void)st->db->close(st->db); 166805f98035SJacques Vidrine st->db = NULL; 166905f98035SJacques Vidrine } 1670a9ceaa9dSJacques Vidrine if (rv == NS_SUCCESS) { 1671a9ceaa9dSJacques Vidrine if (!from_compat) { 1672a9ceaa9dSJacques Vidrine pwd->pw_fields &= ~_PWF_SOURCE; 1673a9ceaa9dSJacques Vidrine pwd->pw_fields |= _PWF_FILES; 1674a9ceaa9dSJacques Vidrine } 1675a9ceaa9dSJacques Vidrine if (retval != NULL) 167605f98035SJacques Vidrine *(struct passwd **)retval = pwd; 1677a9ceaa9dSJacques Vidrine } 167805f98035SJacques Vidrine return (rv); 167905f98035SJacques Vidrine } 168005f98035SJacques Vidrine 168105f98035SJacques Vidrine 168205f98035SJacques Vidrine /* 168305f98035SJacques Vidrine * common passwd line matching and parsing 168405f98035SJacques Vidrine */ 168505f98035SJacques Vidrine int 168605f98035SJacques Vidrine __pw_match_entry(const char *entry, size_t entrysize, enum nss_lookup_type how, 168705f98035SJacques Vidrine const char *name, uid_t uid) 168805f98035SJacques Vidrine { 168905f98035SJacques Vidrine const char *p, *eom; 169005f98035SJacques Vidrine char *q; 169105f98035SJacques Vidrine size_t len; 169205f98035SJacques Vidrine unsigned long m; 169305f98035SJacques Vidrine 169405f98035SJacques Vidrine eom = entry + entrysize; 169505f98035SJacques Vidrine for (p = entry; p < eom; p++) 169605f98035SJacques Vidrine if (*p == ':') 169705f98035SJacques Vidrine break; 169805f98035SJacques Vidrine if (*p != ':') 169905f98035SJacques Vidrine return (NS_NOTFOUND); 170005f98035SJacques Vidrine if (how == nss_lt_all) 170105f98035SJacques Vidrine return (NS_SUCCESS); 170205f98035SJacques Vidrine if (how == nss_lt_name) { 170305f98035SJacques Vidrine len = strlen(name); 170405f98035SJacques Vidrine if (len == (p - entry) && memcmp(name, entry, len) == 0) 170505f98035SJacques Vidrine return (NS_SUCCESS); 170605f98035SJacques Vidrine else 170705f98035SJacques Vidrine return (NS_NOTFOUND); 170805f98035SJacques Vidrine } 170905f98035SJacques Vidrine for (p++; p < eom; p++) 171005f98035SJacques Vidrine if (*p == ':') 171105f98035SJacques Vidrine break; 171205f98035SJacques Vidrine if (*p != ':') 171305f98035SJacques Vidrine return (NS_NOTFOUND); 171405f98035SJacques Vidrine m = strtoul(++p, &q, 10); 171505f98035SJacques Vidrine if (q[0] != ':' || (uid_t)m != uid) 171605f98035SJacques Vidrine return (NS_NOTFOUND); 171705f98035SJacques Vidrine else 171805f98035SJacques Vidrine return (NS_SUCCESS); 171905f98035SJacques Vidrine } 172005f98035SJacques Vidrine 172105f98035SJacques Vidrine 172205f98035SJacques Vidrine /* XXX buffer must be NUL-terminated. errnop is not set correctly. */ 172305f98035SJacques Vidrine int 172405f98035SJacques Vidrine __pw_parse_entry(char *buffer, size_t bufsize __unused, struct passwd *pwd, 172505f98035SJacques Vidrine int master, int *errnop __unused) 172605f98035SJacques Vidrine { 172705f98035SJacques Vidrine 172805f98035SJacques Vidrine if (__pw_scan(buffer, pwd, master ? _PWSCAN_MASTER : 0) == 0) 172905f98035SJacques Vidrine return (NS_NOTFOUND); 173005f98035SJacques Vidrine else 173105f98035SJacques Vidrine return (NS_SUCCESS); 173258f0484fSRodney W. Grimes } 1733