1cf2b5f3bSDag-Erling Smørgrav /*- 2cf2b5f3bSDag-Erling Smørgrav * Copyright (c) 2002 Networks Associates Technology, Inc. 3cf2b5f3bSDag-Erling Smørgrav * All rights reserved. 4cf2b5f3bSDag-Erling Smørgrav * 5cf2b5f3bSDag-Erling Smørgrav * This software was developed for the FreeBSD Project by ThinkSec AS and 6cf2b5f3bSDag-Erling Smørgrav * NAI Labs, the Security Research Division of Network Associates, Inc. 7cf2b5f3bSDag-Erling Smørgrav * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 8cf2b5f3bSDag-Erling Smørgrav * DARPA CHATS research program. 909958426SBrian Feldman * 1009958426SBrian Feldman * Redistribution and use in source and binary forms, with or without 1109958426SBrian Feldman * modification, are permitted provided that the following conditions 1209958426SBrian Feldman * are met: 1309958426SBrian Feldman * 1. Redistributions of source code must retain the above copyright 1409958426SBrian Feldman * notice, this list of conditions and the following disclaimer. 1509958426SBrian Feldman * 2. Redistributions in binary form must reproduce the above copyright 1609958426SBrian Feldman * notice, this list of conditions and the following disclaimer in the 1709958426SBrian Feldman * documentation and/or other materials provided with the distribution. 1809958426SBrian Feldman * 19cf2b5f3bSDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20cf2b5f3bSDag-Erling Smørgrav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21cf2b5f3bSDag-Erling Smørgrav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22cf2b5f3bSDag-Erling Smørgrav * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23cf2b5f3bSDag-Erling Smørgrav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24cf2b5f3bSDag-Erling Smørgrav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25cf2b5f3bSDag-Erling Smørgrav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26cf2b5f3bSDag-Erling Smørgrav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27cf2b5f3bSDag-Erling Smørgrav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28cf2b5f3bSDag-Erling Smørgrav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29cf2b5f3bSDag-Erling Smørgrav * SUCH DAMAGE. 3009958426SBrian Feldman */ 3121e764dfSDag-Erling Smørgrav /* 3221e764dfSDag-Erling Smørgrav * Copyright (c) 2003,2004 Damien Miller <djm@mindrot.org> 3321e764dfSDag-Erling Smørgrav * Copyright (c) 2003,2004 Darren Tucker <dtucker@zip.com.au> 3421e764dfSDag-Erling Smørgrav * 3521e764dfSDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any 3621e764dfSDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above 3721e764dfSDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies. 3821e764dfSDag-Erling Smørgrav * 3921e764dfSDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 4021e764dfSDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 4121e764dfSDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 4221e764dfSDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 4321e764dfSDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 4421e764dfSDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 4521e764dfSDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 4621e764dfSDag-Erling Smørgrav */ 4709958426SBrian Feldman 48acc1a9efSDag-Erling Smørgrav /* Based on FreeBSD: src/crypto/openssh/auth2-pam-freebsd.c,v 1.11 2003/03/31 13:48:18 des */ 49acc1a9efSDag-Erling Smørgrav 5009958426SBrian Feldman #include "includes.h" 51333ee039SDag-Erling Smørgrav 52333ee039SDag-Erling Smørgrav #include <sys/types.h> 53333ee039SDag-Erling Smørgrav #include <sys/stat.h> 54333ee039SDag-Erling Smørgrav #include <sys/wait.h> 55333ee039SDag-Erling Smørgrav 56333ee039SDag-Erling Smørgrav #include <errno.h> 57333ee039SDag-Erling Smørgrav #include <signal.h> 58333ee039SDag-Erling Smørgrav #include <stdarg.h> 59333ee039SDag-Erling Smørgrav #include <string.h> 60333ee039SDag-Erling Smørgrav #include <unistd.h> 6109958426SBrian Feldman 6209958426SBrian Feldman #ifdef USE_PAM 631ec0d754SDag-Erling Smørgrav #if defined(HAVE_SECURITY_PAM_APPL_H) 64cf2b5f3bSDag-Erling Smørgrav #include <security/pam_appl.h> 651ec0d754SDag-Erling Smørgrav #elif defined (HAVE_PAM_PAM_APPL_H) 661ec0d754SDag-Erling Smørgrav #include <pam/pam_appl.h> 671ec0d754SDag-Erling Smørgrav #endif 68cf2b5f3bSDag-Erling Smørgrav 69ca86bcf2SDag-Erling Smørgrav #if !defined(SSHD_PAM_SERVICE) 70ca86bcf2SDag-Erling Smørgrav extern char *__progname; 71ca86bcf2SDag-Erling Smørgrav # define SSHD_PAM_SERVICE __progname 72ca86bcf2SDag-Erling Smørgrav #endif 73ca86bcf2SDag-Erling Smørgrav 74d4ecd108SDag-Erling Smørgrav /* OpenGroup RFC86.0 and XSSO specify no "const" on arguments */ 75d4ecd108SDag-Erling Smørgrav #ifdef PAM_SUN_CODEBASE 76076ad2f8SDag-Erling Smørgrav # define sshpam_const /* Solaris, HP-UX, SunOS */ 77d4ecd108SDag-Erling Smørgrav #else 78076ad2f8SDag-Erling Smørgrav # define sshpam_const const /* LinuxPAM, OpenPAM, AIX */ 79d4ecd108SDag-Erling Smørgrav #endif 80d4ecd108SDag-Erling Smørgrav 81333ee039SDag-Erling Smørgrav /* Ambiguity in spec: is it an array of pointers or a pointer to an array? */ 82333ee039SDag-Erling Smørgrav #ifdef PAM_SUN_CODEBASE 83333ee039SDag-Erling Smørgrav # define PAM_MSG_MEMBER(msg, n, member) ((*(msg))[(n)].member) 84333ee039SDag-Erling Smørgrav #else 85333ee039SDag-Erling Smørgrav # define PAM_MSG_MEMBER(msg, n, member) ((msg)[(n)]->member) 86333ee039SDag-Erling Smørgrav #endif 87333ee039SDag-Erling Smørgrav 88333ee039SDag-Erling Smørgrav #include "xmalloc.h" 89333ee039SDag-Erling Smørgrav #include "buffer.h" 90333ee039SDag-Erling Smørgrav #include "key.h" 91333ee039SDag-Erling Smørgrav #include "hostfile.h" 92989dd127SDag-Erling Smørgrav #include "auth.h" 93989dd127SDag-Erling Smørgrav #include "auth-pam.h" 944c5de869SBrian Feldman #include "canohost.h" 95cf2b5f3bSDag-Erling Smørgrav #include "log.h" 96cf2b5f3bSDag-Erling Smørgrav #include "msg.h" 97cf2b5f3bSDag-Erling Smørgrav #include "packet.h" 9821e764dfSDag-Erling Smørgrav #include "misc.h" 99cf2b5f3bSDag-Erling Smørgrav #include "servconf.h" 100cf2b5f3bSDag-Erling Smørgrav #include "ssh2.h" 101cf2b5f3bSDag-Erling Smørgrav #include "auth-options.h" 102333ee039SDag-Erling Smørgrav #ifdef GSSAPI 103333ee039SDag-Erling Smørgrav #include "ssh-gss.h" 104333ee039SDag-Erling Smørgrav #endif 105333ee039SDag-Erling Smørgrav #include "monitor_wrap.h" 106b2af61ecSKurt Lidl #include "blacklist_client.h" 10709958426SBrian Feldman 108989dd127SDag-Erling Smørgrav extern ServerOptions options; 1091ec0d754SDag-Erling Smørgrav extern Buffer loginmsg; 1101ec0d754SDag-Erling Smørgrav extern int compat20; 1115962c0e9SDag-Erling Smørgrav extern u_int utmp_len; 1122c917d39SAlfred Perlstein 113aa49c926SDag-Erling Smørgrav /* so we don't silently change behaviour */ 114cf2b5f3bSDag-Erling Smørgrav #ifdef USE_POSIX_THREADS 115aa49c926SDag-Erling Smørgrav # error "USE_POSIX_THREADS replaced by UNSUPPORTED_POSIX_THREADS_HACK" 116aa49c926SDag-Erling Smørgrav #endif 117aa49c926SDag-Erling Smørgrav 118aa49c926SDag-Erling Smørgrav /* 119aa49c926SDag-Erling Smørgrav * Formerly known as USE_POSIX_THREADS, using this is completely unsupported 120aa49c926SDag-Erling Smørgrav * and generally a bad idea. Use at own risk and do not expect support if 121aa49c926SDag-Erling Smørgrav * this breaks. 122aa49c926SDag-Erling Smørgrav */ 123aa49c926SDag-Erling Smørgrav #ifdef UNSUPPORTED_POSIX_THREADS_HACK 124cf2b5f3bSDag-Erling Smørgrav #include <pthread.h> 125cf2b5f3bSDag-Erling Smørgrav /* 126cf2b5f3bSDag-Erling Smørgrav * Avoid namespace clash when *not* using pthreads for systems *with* 127cf2b5f3bSDag-Erling Smørgrav * pthreads, which unconditionally define pthread_t via sys/types.h 128cf2b5f3bSDag-Erling Smørgrav * (e.g. Linux) 129cf2b5f3bSDag-Erling Smørgrav */ 130cf2b5f3bSDag-Erling Smørgrav typedef pthread_t sp_pthread_t; 131cf2b5f3bSDag-Erling Smørgrav #else 1321ec0d754SDag-Erling Smørgrav typedef pid_t sp_pthread_t; 1331ec0d754SDag-Erling Smørgrav #endif 1341ec0d754SDag-Erling Smørgrav 1351ec0d754SDag-Erling Smørgrav struct pam_ctxt { 1361ec0d754SDag-Erling Smørgrav sp_pthread_t pam_thread; 1371ec0d754SDag-Erling Smørgrav int pam_psock; 1381ec0d754SDag-Erling Smørgrav int pam_csock; 1391ec0d754SDag-Erling Smørgrav int pam_done; 1401ec0d754SDag-Erling Smørgrav }; 1411ec0d754SDag-Erling Smørgrav 1421ec0d754SDag-Erling Smørgrav static void sshpam_free_ctx(void *); 1431ec0d754SDag-Erling Smørgrav static struct pam_ctxt *cleanup_ctxt; 1441ec0d754SDag-Erling Smørgrav 145aa49c926SDag-Erling Smørgrav #ifndef UNSUPPORTED_POSIX_THREADS_HACK 146cf2b5f3bSDag-Erling Smørgrav /* 147cf2b5f3bSDag-Erling Smørgrav * Simulate threads with processes. 148cf2b5f3bSDag-Erling Smørgrav */ 1491ec0d754SDag-Erling Smørgrav 1501ec0d754SDag-Erling Smørgrav static int sshpam_thread_status = -1; 1511ec0d754SDag-Erling Smørgrav static mysig_t sshpam_oldsig; 1521ec0d754SDag-Erling Smørgrav 1531ec0d754SDag-Erling Smørgrav static void 1541ec0d754SDag-Erling Smørgrav sshpam_sigchld_handler(int sig) 1551ec0d754SDag-Erling Smørgrav { 15621e764dfSDag-Erling Smørgrav signal(SIGCHLD, SIG_DFL); 1571ec0d754SDag-Erling Smørgrav if (cleanup_ctxt == NULL) 1581ec0d754SDag-Erling Smørgrav return; /* handler called after PAM cleanup, shouldn't happen */ 15921e764dfSDag-Erling Smørgrav if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, WNOHANG) 16021e764dfSDag-Erling Smørgrav <= 0) { 16121e764dfSDag-Erling Smørgrav /* PAM thread has not exitted, privsep slave must have */ 16221e764dfSDag-Erling Smørgrav kill(cleanup_ctxt->pam_thread, SIGTERM); 163076ad2f8SDag-Erling Smørgrav while (waitpid(cleanup_ctxt->pam_thread, 164076ad2f8SDag-Erling Smørgrav &sshpam_thread_status, 0) == -1) { 165076ad2f8SDag-Erling Smørgrav if (errno == EINTR) 166076ad2f8SDag-Erling Smørgrav continue; 167076ad2f8SDag-Erling Smørgrav return; 168076ad2f8SDag-Erling Smørgrav } 16921e764dfSDag-Erling Smørgrav } 1701ec0d754SDag-Erling Smørgrav if (WIFSIGNALED(sshpam_thread_status) && 1711ec0d754SDag-Erling Smørgrav WTERMSIG(sshpam_thread_status) == SIGTERM) 1721ec0d754SDag-Erling Smørgrav return; /* terminated by pthread_cancel */ 1731ec0d754SDag-Erling Smørgrav if (!WIFEXITED(sshpam_thread_status)) 174d4af9e69SDag-Erling Smørgrav sigdie("PAM: authentication thread exited unexpectedly"); 1751ec0d754SDag-Erling Smørgrav if (WEXITSTATUS(sshpam_thread_status) != 0) 176d4af9e69SDag-Erling Smørgrav sigdie("PAM: authentication thread exited uncleanly"); 1771ec0d754SDag-Erling Smørgrav } 17809958426SBrian Feldman 179333ee039SDag-Erling Smørgrav /* ARGSUSED */ 180cf2b5f3bSDag-Erling Smørgrav static void 181333ee039SDag-Erling Smørgrav pthread_exit(void *value) 18209958426SBrian Feldman { 183cf2b5f3bSDag-Erling Smørgrav _exit(0); 18409958426SBrian Feldman } 18509958426SBrian Feldman 186333ee039SDag-Erling Smørgrav /* ARGSUSED */ 187cf2b5f3bSDag-Erling Smørgrav static int 188333ee039SDag-Erling Smørgrav pthread_create(sp_pthread_t *thread, const void *attr, 189cf2b5f3bSDag-Erling Smørgrav void *(*thread_start)(void *), void *arg) 190cf2b5f3bSDag-Erling Smørgrav { 191cf2b5f3bSDag-Erling Smørgrav pid_t pid; 192d4ecd108SDag-Erling Smørgrav struct pam_ctxt *ctx = arg; 193cf2b5f3bSDag-Erling Smørgrav 1945962c0e9SDag-Erling Smørgrav sshpam_thread_status = -1; 195cf2b5f3bSDag-Erling Smørgrav switch ((pid = fork())) { 196cf2b5f3bSDag-Erling Smørgrav case -1: 197cf2b5f3bSDag-Erling Smørgrav error("fork(): %s", strerror(errno)); 198cf2b5f3bSDag-Erling Smørgrav return (-1); 199cf2b5f3bSDag-Erling Smørgrav case 0: 200d4ecd108SDag-Erling Smørgrav close(ctx->pam_psock); 201d4ecd108SDag-Erling Smørgrav ctx->pam_psock = -1; 202cf2b5f3bSDag-Erling Smørgrav thread_start(arg); 203cf2b5f3bSDag-Erling Smørgrav _exit(1); 204cf2b5f3bSDag-Erling Smørgrav default: 205cf2b5f3bSDag-Erling Smørgrav *thread = pid; 206d4ecd108SDag-Erling Smørgrav close(ctx->pam_csock); 207d4ecd108SDag-Erling Smørgrav ctx->pam_csock = -1; 2081ec0d754SDag-Erling Smørgrav sshpam_oldsig = signal(SIGCHLD, sshpam_sigchld_handler); 209cf2b5f3bSDag-Erling Smørgrav return (0); 210cf2b5f3bSDag-Erling Smørgrav } 211cf2b5f3bSDag-Erling Smørgrav } 212cf2b5f3bSDag-Erling Smørgrav 213cf2b5f3bSDag-Erling Smørgrav static int 214cf2b5f3bSDag-Erling Smørgrav pthread_cancel(sp_pthread_t thread) 215cf2b5f3bSDag-Erling Smørgrav { 2161ec0d754SDag-Erling Smørgrav signal(SIGCHLD, sshpam_oldsig); 217cf2b5f3bSDag-Erling Smørgrav return (kill(thread, SIGTERM)); 218cf2b5f3bSDag-Erling Smørgrav } 219cf2b5f3bSDag-Erling Smørgrav 220333ee039SDag-Erling Smørgrav /* ARGSUSED */ 221cf2b5f3bSDag-Erling Smørgrav static int 222333ee039SDag-Erling Smørgrav pthread_join(sp_pthread_t thread, void **value) 223cf2b5f3bSDag-Erling Smørgrav { 224cf2b5f3bSDag-Erling Smørgrav int status; 225cf2b5f3bSDag-Erling Smørgrav 2261ec0d754SDag-Erling Smørgrav if (sshpam_thread_status != -1) 2271ec0d754SDag-Erling Smørgrav return (sshpam_thread_status); 2281ec0d754SDag-Erling Smørgrav signal(SIGCHLD, sshpam_oldsig); 229076ad2f8SDag-Erling Smørgrav while (waitpid(thread, &status, 0) == -1) { 230076ad2f8SDag-Erling Smørgrav if (errno == EINTR) 231076ad2f8SDag-Erling Smørgrav continue; 232076ad2f8SDag-Erling Smørgrav fatal("%s: waitpid: %s", __func__, strerror(errno)); 233076ad2f8SDag-Erling Smørgrav } 234cf2b5f3bSDag-Erling Smørgrav return (status); 235cf2b5f3bSDag-Erling Smørgrav } 236cf2b5f3bSDag-Erling Smørgrav #endif 237cf2b5f3bSDag-Erling Smørgrav 238cf2b5f3bSDag-Erling Smørgrav 239cf2b5f3bSDag-Erling Smørgrav static pam_handle_t *sshpam_handle = NULL; 240cf2b5f3bSDag-Erling Smørgrav static int sshpam_err = 0; 241cf2b5f3bSDag-Erling Smørgrav static int sshpam_authenticated = 0; 242cf2b5f3bSDag-Erling Smørgrav static int sshpam_session_open = 0; 243cf2b5f3bSDag-Erling Smørgrav static int sshpam_cred_established = 0; 2441ec0d754SDag-Erling Smørgrav static int sshpam_account_status = -1; 245076ad2f8SDag-Erling Smørgrav static int sshpam_maxtries_reached = 0; 2461ec0d754SDag-Erling Smørgrav static char **sshpam_env = NULL; 2475962c0e9SDag-Erling Smørgrav static Authctxt *sshpam_authctxt = NULL; 24821e764dfSDag-Erling Smørgrav static const char *sshpam_password = NULL; 249cf2b5f3bSDag-Erling Smørgrav 2501ec0d754SDag-Erling Smørgrav /* Some PAM implementations don't implement this */ 2511ec0d754SDag-Erling Smørgrav #ifndef HAVE_PAM_GETENVLIST 2521ec0d754SDag-Erling Smørgrav static char ** 2531ec0d754SDag-Erling Smørgrav pam_getenvlist(pam_handle_t *pamh) 2541ec0d754SDag-Erling Smørgrav { 2551ec0d754SDag-Erling Smørgrav /* 2561ec0d754SDag-Erling Smørgrav * XXX - If necessary, we can still support envrionment passing 2571ec0d754SDag-Erling Smørgrav * for platforms without pam_getenvlist by searching for known 2581ec0d754SDag-Erling Smørgrav * env vars (e.g. KRB5CCNAME) from the PAM environment. 2591ec0d754SDag-Erling Smørgrav */ 2601ec0d754SDag-Erling Smørgrav return NULL; 2611ec0d754SDag-Erling Smørgrav } 2621ec0d754SDag-Erling Smørgrav #endif 263cf2b5f3bSDag-Erling Smørgrav 26421e764dfSDag-Erling Smørgrav /* 26521e764dfSDag-Erling Smørgrav * Some platforms, notably Solaris, do not enforce password complexity 26621e764dfSDag-Erling Smørgrav * rules during pam_chauthtok() if the real uid of the calling process 26721e764dfSDag-Erling Smørgrav * is 0, on the assumption that it's being called by "passwd" run by root. 26821e764dfSDag-Erling Smørgrav * This wraps pam_chauthtok and sets/restore the real uid so PAM will do 26921e764dfSDag-Erling Smørgrav * the right thing. 27021e764dfSDag-Erling Smørgrav */ 27121e764dfSDag-Erling Smørgrav #ifdef SSHPAM_CHAUTHTOK_NEEDS_RUID 27221e764dfSDag-Erling Smørgrav static int 27321e764dfSDag-Erling Smørgrav sshpam_chauthtok_ruid(pam_handle_t *pamh, int flags) 27421e764dfSDag-Erling Smørgrav { 27521e764dfSDag-Erling Smørgrav int result; 27621e764dfSDag-Erling Smørgrav 27721e764dfSDag-Erling Smørgrav if (sshpam_authctxt == NULL) 27821e764dfSDag-Erling Smørgrav fatal("PAM: sshpam_authctxt not initialized"); 27921e764dfSDag-Erling Smørgrav if (setreuid(sshpam_authctxt->pw->pw_uid, -1) == -1) 28021e764dfSDag-Erling Smørgrav fatal("%s: setreuid failed: %s", __func__, strerror(errno)); 28121e764dfSDag-Erling Smørgrav result = pam_chauthtok(pamh, flags); 28221e764dfSDag-Erling Smørgrav if (setreuid(0, -1) == -1) 28321e764dfSDag-Erling Smørgrav fatal("%s: setreuid failed: %s", __func__, strerror(errno)); 28421e764dfSDag-Erling Smørgrav return result; 28521e764dfSDag-Erling Smørgrav } 28621e764dfSDag-Erling Smørgrav # define pam_chauthtok(a,b) (sshpam_chauthtok_ruid((a), (b))) 28721e764dfSDag-Erling Smørgrav #endif 28821e764dfSDag-Erling Smørgrav 2891ec0d754SDag-Erling Smørgrav void 29021e764dfSDag-Erling Smørgrav sshpam_password_change_required(int reqd) 2911ec0d754SDag-Erling Smørgrav { 2921ec0d754SDag-Erling Smørgrav debug3("%s %d", __func__, reqd); 2935962c0e9SDag-Erling Smørgrav if (sshpam_authctxt == NULL) 2945962c0e9SDag-Erling Smørgrav fatal("%s: PAM authctxt not initialized", __func__); 2955962c0e9SDag-Erling Smørgrav sshpam_authctxt->force_pwchange = reqd; 2961ec0d754SDag-Erling Smørgrav if (reqd) { 2971ec0d754SDag-Erling Smørgrav no_port_forwarding_flag |= 2; 2981ec0d754SDag-Erling Smørgrav no_agent_forwarding_flag |= 2; 2991ec0d754SDag-Erling Smørgrav no_x11_forwarding_flag |= 2; 3001ec0d754SDag-Erling Smørgrav } else { 3011ec0d754SDag-Erling Smørgrav no_port_forwarding_flag &= ~2; 3021ec0d754SDag-Erling Smørgrav no_agent_forwarding_flag &= ~2; 3031ec0d754SDag-Erling Smørgrav no_x11_forwarding_flag &= ~2; 3041ec0d754SDag-Erling Smørgrav } 3051ec0d754SDag-Erling Smørgrav } 3061ec0d754SDag-Erling Smørgrav 3071ec0d754SDag-Erling Smørgrav /* Import regular and PAM environment from subprocess */ 3081ec0d754SDag-Erling Smørgrav static void 3091ec0d754SDag-Erling Smørgrav import_environments(Buffer *b) 3101ec0d754SDag-Erling Smørgrav { 3111ec0d754SDag-Erling Smørgrav char *env; 3121ec0d754SDag-Erling Smørgrav u_int i, num_env; 3131ec0d754SDag-Erling Smørgrav int err; 3141ec0d754SDag-Erling Smørgrav 3151ec0d754SDag-Erling Smørgrav debug3("PAM: %s entering", __func__); 3161ec0d754SDag-Erling Smørgrav 317aa49c926SDag-Erling Smørgrav #ifndef UNSUPPORTED_POSIX_THREADS_HACK 3181ec0d754SDag-Erling Smørgrav /* Import variables set by do_pam_account */ 3191ec0d754SDag-Erling Smørgrav sshpam_account_status = buffer_get_int(b); 32021e764dfSDag-Erling Smørgrav sshpam_password_change_required(buffer_get_int(b)); 3211ec0d754SDag-Erling Smørgrav 3221ec0d754SDag-Erling Smørgrav /* Import environment from subprocess */ 3231ec0d754SDag-Erling Smørgrav num_env = buffer_get_int(b); 324333ee039SDag-Erling Smørgrav if (num_env > 1024) 325333ee039SDag-Erling Smørgrav fatal("%s: received %u environment variables, expected <= 1024", 326333ee039SDag-Erling Smørgrav __func__, num_env); 327333ee039SDag-Erling Smørgrav sshpam_env = xcalloc(num_env + 1, sizeof(*sshpam_env)); 3281ec0d754SDag-Erling Smørgrav debug3("PAM: num env strings %d", num_env); 3291ec0d754SDag-Erling Smørgrav for(i = 0; i < num_env; i++) 3301ec0d754SDag-Erling Smørgrav sshpam_env[i] = buffer_get_string(b, NULL); 3311ec0d754SDag-Erling Smørgrav 3321ec0d754SDag-Erling Smørgrav sshpam_env[num_env] = NULL; 3331ec0d754SDag-Erling Smørgrav 3341ec0d754SDag-Erling Smørgrav /* Import PAM environment from subprocess */ 3351ec0d754SDag-Erling Smørgrav num_env = buffer_get_int(b); 3361ec0d754SDag-Erling Smørgrav debug("PAM: num PAM env strings %d", num_env); 3371ec0d754SDag-Erling Smørgrav for(i = 0; i < num_env; i++) { 3381ec0d754SDag-Erling Smørgrav env = buffer_get_string(b, NULL); 3391ec0d754SDag-Erling Smørgrav 3401ec0d754SDag-Erling Smørgrav #ifdef HAVE_PAM_PUTENV 3411ec0d754SDag-Erling Smørgrav /* Errors are not fatal here */ 3421ec0d754SDag-Erling Smørgrav if ((err = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) { 3431ec0d754SDag-Erling Smørgrav error("PAM: pam_putenv: %s", 3441ec0d754SDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 3451ec0d754SDag-Erling Smørgrav } 3461ec0d754SDag-Erling Smørgrav #endif 3471ec0d754SDag-Erling Smørgrav } 3485962c0e9SDag-Erling Smørgrav #endif 3491ec0d754SDag-Erling Smørgrav } 350cf2b5f3bSDag-Erling Smørgrav 351cf2b5f3bSDag-Erling Smørgrav /* 352cf2b5f3bSDag-Erling Smørgrav * Conversation function for authentication thread. 353cf2b5f3bSDag-Erling Smørgrav */ 354cf2b5f3bSDag-Erling Smørgrav static int 355d4ecd108SDag-Erling Smørgrav sshpam_thread_conv(int n, sshpam_const struct pam_message **msg, 356cf2b5f3bSDag-Erling Smørgrav struct pam_response **resp, void *data) 357cf2b5f3bSDag-Erling Smørgrav { 358cf2b5f3bSDag-Erling Smørgrav Buffer buffer; 359cf2b5f3bSDag-Erling Smørgrav struct pam_ctxt *ctxt; 360cf2b5f3bSDag-Erling Smørgrav struct pam_response *reply; 361cf2b5f3bSDag-Erling Smørgrav int i; 362cf2b5f3bSDag-Erling Smørgrav 3631ec0d754SDag-Erling Smørgrav debug3("PAM: %s entering, %d messages", __func__, n); 364cf2b5f3bSDag-Erling Smørgrav *resp = NULL; 365cf2b5f3bSDag-Erling Smørgrav 36621e764dfSDag-Erling Smørgrav if (data == NULL) { 36721e764dfSDag-Erling Smørgrav error("PAM: conversation function passed a null context"); 36821e764dfSDag-Erling Smørgrav return (PAM_CONV_ERR); 36921e764dfSDag-Erling Smørgrav } 370cf2b5f3bSDag-Erling Smørgrav ctxt = data; 371cf2b5f3bSDag-Erling Smørgrav if (n <= 0 || n > PAM_MAX_NUM_MSG) 372cf2b5f3bSDag-Erling Smørgrav return (PAM_CONV_ERR); 373cf2b5f3bSDag-Erling Smørgrav 374333ee039SDag-Erling Smørgrav if ((reply = calloc(n, sizeof(*reply))) == NULL) 375cf2b5f3bSDag-Erling Smørgrav return (PAM_CONV_ERR); 376cf2b5f3bSDag-Erling Smørgrav 377cf2b5f3bSDag-Erling Smørgrav buffer_init(&buffer); 378cf2b5f3bSDag-Erling Smørgrav for (i = 0; i < n; ++i) { 379cf2b5f3bSDag-Erling Smørgrav switch (PAM_MSG_MEMBER(msg, i, msg_style)) { 380cf2b5f3bSDag-Erling Smørgrav case PAM_PROMPT_ECHO_OFF: 381cf2b5f3bSDag-Erling Smørgrav case PAM_PROMPT_ECHO_ON: 382cf2b5f3bSDag-Erling Smørgrav buffer_put_cstring(&buffer, 383cf2b5f3bSDag-Erling Smørgrav PAM_MSG_MEMBER(msg, i, msg)); 3841ec0d754SDag-Erling Smørgrav if (ssh_msg_send(ctxt->pam_csock, 3851ec0d754SDag-Erling Smørgrav PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1) 3861ec0d754SDag-Erling Smørgrav goto fail; 3871ec0d754SDag-Erling Smørgrav if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1) 3881ec0d754SDag-Erling Smørgrav goto fail; 389cf2b5f3bSDag-Erling Smørgrav if (buffer_get_char(&buffer) != PAM_AUTHTOK) 390cf2b5f3bSDag-Erling Smørgrav goto fail; 391cf2b5f3bSDag-Erling Smørgrav reply[i].resp = buffer_get_string(&buffer, NULL); 392cf2b5f3bSDag-Erling Smørgrav break; 393cf2b5f3bSDag-Erling Smørgrav case PAM_ERROR_MSG: 394cf2b5f3bSDag-Erling Smørgrav case PAM_TEXT_INFO: 395cf2b5f3bSDag-Erling Smørgrav buffer_put_cstring(&buffer, 396cf2b5f3bSDag-Erling Smørgrav PAM_MSG_MEMBER(msg, i, msg)); 3971ec0d754SDag-Erling Smørgrav if (ssh_msg_send(ctxt->pam_csock, 3981ec0d754SDag-Erling Smørgrav PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1) 3991ec0d754SDag-Erling Smørgrav goto fail; 400cf2b5f3bSDag-Erling Smørgrav break; 401cf2b5f3bSDag-Erling Smørgrav default: 402cf2b5f3bSDag-Erling Smørgrav goto fail; 403cf2b5f3bSDag-Erling Smørgrav } 404cf2b5f3bSDag-Erling Smørgrav buffer_clear(&buffer); 405cf2b5f3bSDag-Erling Smørgrav } 406cf2b5f3bSDag-Erling Smørgrav buffer_free(&buffer); 407cf2b5f3bSDag-Erling Smørgrav *resp = reply; 408cf2b5f3bSDag-Erling Smørgrav return (PAM_SUCCESS); 409cf2b5f3bSDag-Erling Smørgrav 410cf2b5f3bSDag-Erling Smørgrav fail: 411cf2b5f3bSDag-Erling Smørgrav for(i = 0; i < n; i++) { 412e4a9863fSDag-Erling Smørgrav free(reply[i].resp); 413cf2b5f3bSDag-Erling Smørgrav } 414e4a9863fSDag-Erling Smørgrav free(reply); 415cf2b5f3bSDag-Erling Smørgrav buffer_free(&buffer); 416cf2b5f3bSDag-Erling Smørgrav return (PAM_CONV_ERR); 417cf2b5f3bSDag-Erling Smørgrav } 418cf2b5f3bSDag-Erling Smørgrav 419cf2b5f3bSDag-Erling Smørgrav /* 420cf2b5f3bSDag-Erling Smørgrav * Authentication thread. 421cf2b5f3bSDag-Erling Smørgrav */ 422cf2b5f3bSDag-Erling Smørgrav static void * 423cf2b5f3bSDag-Erling Smørgrav sshpam_thread(void *ctxtp) 424cf2b5f3bSDag-Erling Smørgrav { 425cf2b5f3bSDag-Erling Smørgrav struct pam_ctxt *ctxt = ctxtp; 426cf2b5f3bSDag-Erling Smørgrav Buffer buffer; 427cf2b5f3bSDag-Erling Smørgrav struct pam_conv sshpam_conv; 42821e764dfSDag-Erling Smørgrav int flags = (options.permit_empty_passwd == 0 ? 42921e764dfSDag-Erling Smørgrav PAM_DISALLOW_NULL_AUTHTOK : 0); 430aa49c926SDag-Erling Smørgrav #ifndef UNSUPPORTED_POSIX_THREADS_HACK 4311ec0d754SDag-Erling Smørgrav extern char **environ; 4321ec0d754SDag-Erling Smørgrav char **env_from_pam; 4331ec0d754SDag-Erling Smørgrav u_int i; 434cf2b5f3bSDag-Erling Smørgrav const char *pam_user; 435d4ecd108SDag-Erling Smørgrav const char **ptr_pam_user = &pam_user; 436333ee039SDag-Erling Smørgrav char *tz = getenv("TZ"); 437cf2b5f3bSDag-Erling Smørgrav 438f7167e0eSDag-Erling Smørgrav sshpam_err = pam_get_item(sshpam_handle, PAM_USER, 439d4ecd108SDag-Erling Smørgrav (sshpam_const void **)ptr_pam_user); 440f7167e0eSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) 441f7167e0eSDag-Erling Smørgrav goto auth_fail; 442333ee039SDag-Erling Smørgrav 4431ec0d754SDag-Erling Smørgrav environ[0] = NULL; 444333ee039SDag-Erling Smørgrav if (tz != NULL) 445333ee039SDag-Erling Smørgrav if (setenv("TZ", tz, 1) == -1) 446333ee039SDag-Erling Smørgrav error("PAM: could not set TZ environment: %s", 447333ee039SDag-Erling Smørgrav strerror(errno)); 44821e764dfSDag-Erling Smørgrav 44921e764dfSDag-Erling Smørgrav if (sshpam_authctxt != NULL) { 45021e764dfSDag-Erling Smørgrav setproctitle("%s [pam]", 45121e764dfSDag-Erling Smørgrav sshpam_authctxt->valid ? pam_user : "unknown"); 45221e764dfSDag-Erling Smørgrav } 453cf2b5f3bSDag-Erling Smørgrav #endif 454cf2b5f3bSDag-Erling Smørgrav 455cf2b5f3bSDag-Erling Smørgrav sshpam_conv.conv = sshpam_thread_conv; 456cf2b5f3bSDag-Erling Smørgrav sshpam_conv.appdata_ptr = ctxt; 457cf2b5f3bSDag-Erling Smørgrav 4585962c0e9SDag-Erling Smørgrav if (sshpam_authctxt == NULL) 4595962c0e9SDag-Erling Smørgrav fatal("%s: PAM authctxt not initialized", __func__); 4605962c0e9SDag-Erling Smørgrav 461cf2b5f3bSDag-Erling Smørgrav buffer_init(&buffer); 462cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, 463cf2b5f3bSDag-Erling Smørgrav (const void *)&sshpam_conv); 464cf2b5f3bSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) 465cf2b5f3bSDag-Erling Smørgrav goto auth_fail; 46621e764dfSDag-Erling Smørgrav sshpam_err = pam_authenticate(sshpam_handle, flags); 467076ad2f8SDag-Erling Smørgrav if (sshpam_err == PAM_MAXTRIES) 468076ad2f8SDag-Erling Smørgrav sshpam_set_maxtries_reached(1); 469cf2b5f3bSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) 470cf2b5f3bSDag-Erling Smørgrav goto auth_fail; 4711ec0d754SDag-Erling Smørgrav 4721ec0d754SDag-Erling Smørgrav if (compat20) { 473333ee039SDag-Erling Smørgrav if (!do_pam_account()) { 474333ee039SDag-Erling Smørgrav sshpam_err = PAM_ACCT_EXPIRED; 4751ec0d754SDag-Erling Smørgrav goto auth_fail; 476333ee039SDag-Erling Smørgrav } 4775962c0e9SDag-Erling Smørgrav if (sshpam_authctxt->force_pwchange) { 4781ec0d754SDag-Erling Smørgrav sshpam_err = pam_chauthtok(sshpam_handle, 4791ec0d754SDag-Erling Smørgrav PAM_CHANGE_EXPIRED_AUTHTOK); 4801ec0d754SDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) 4811ec0d754SDag-Erling Smørgrav goto auth_fail; 48221e764dfSDag-Erling Smørgrav sshpam_password_change_required(0); 4831ec0d754SDag-Erling Smørgrav } 4841ec0d754SDag-Erling Smørgrav } 4851ec0d754SDag-Erling Smørgrav 486cf2b5f3bSDag-Erling Smørgrav buffer_put_cstring(&buffer, "OK"); 4871ec0d754SDag-Erling Smørgrav 488aa49c926SDag-Erling Smørgrav #ifndef UNSUPPORTED_POSIX_THREADS_HACK 4891ec0d754SDag-Erling Smørgrav /* Export variables set by do_pam_account */ 4901ec0d754SDag-Erling Smørgrav buffer_put_int(&buffer, sshpam_account_status); 4915962c0e9SDag-Erling Smørgrav buffer_put_int(&buffer, sshpam_authctxt->force_pwchange); 4921ec0d754SDag-Erling Smørgrav 4931ec0d754SDag-Erling Smørgrav /* Export any environment strings set in child */ 4941ec0d754SDag-Erling Smørgrav for(i = 0; environ[i] != NULL; i++) 4951ec0d754SDag-Erling Smørgrav ; /* Count */ 4961ec0d754SDag-Erling Smørgrav buffer_put_int(&buffer, i); 4971ec0d754SDag-Erling Smørgrav for(i = 0; environ[i] != NULL; i++) 4981ec0d754SDag-Erling Smørgrav buffer_put_cstring(&buffer, environ[i]); 4991ec0d754SDag-Erling Smørgrav 5001ec0d754SDag-Erling Smørgrav /* Export any environment strings set by PAM in child */ 5011ec0d754SDag-Erling Smørgrav env_from_pam = pam_getenvlist(sshpam_handle); 5021ec0d754SDag-Erling Smørgrav for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++) 5031ec0d754SDag-Erling Smørgrav ; /* Count */ 5041ec0d754SDag-Erling Smørgrav buffer_put_int(&buffer, i); 5051ec0d754SDag-Erling Smørgrav for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++) 5061ec0d754SDag-Erling Smørgrav buffer_put_cstring(&buffer, env_from_pam[i]); 507aa49c926SDag-Erling Smørgrav #endif /* UNSUPPORTED_POSIX_THREADS_HACK */ 5081ec0d754SDag-Erling Smørgrav 5091ec0d754SDag-Erling Smørgrav /* XXX - can't do much about an error here */ 510cf2b5f3bSDag-Erling Smørgrav ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer); 511cf2b5f3bSDag-Erling Smørgrav buffer_free(&buffer); 512cf2b5f3bSDag-Erling Smørgrav pthread_exit(NULL); 513cf2b5f3bSDag-Erling Smørgrav 514cf2b5f3bSDag-Erling Smørgrav auth_fail: 515cf2b5f3bSDag-Erling Smørgrav buffer_put_cstring(&buffer, 516cf2b5f3bSDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 5171ec0d754SDag-Erling Smørgrav /* XXX - can't do much about an error here */ 518333ee039SDag-Erling Smørgrav if (sshpam_err == PAM_ACCT_EXPIRED) 519333ee039SDag-Erling Smørgrav ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, &buffer); 520076ad2f8SDag-Erling Smørgrav else if (sshpam_maxtries_reached) 521076ad2f8SDag-Erling Smørgrav ssh_msg_send(ctxt->pam_csock, PAM_MAXTRIES, &buffer); 522333ee039SDag-Erling Smørgrav else 523cf2b5f3bSDag-Erling Smørgrav ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer); 524cf2b5f3bSDag-Erling Smørgrav buffer_free(&buffer); 525cf2b5f3bSDag-Erling Smørgrav pthread_exit(NULL); 526cf2b5f3bSDag-Erling Smørgrav 527cf2b5f3bSDag-Erling Smørgrav return (NULL); /* Avoid warning for non-pthread case */ 528cf2b5f3bSDag-Erling Smørgrav } 529cf2b5f3bSDag-Erling Smørgrav 5301ec0d754SDag-Erling Smørgrav void 5311ec0d754SDag-Erling Smørgrav sshpam_thread_cleanup(void) 532cf2b5f3bSDag-Erling Smørgrav { 5331ec0d754SDag-Erling Smørgrav struct pam_ctxt *ctxt = cleanup_ctxt; 534cf2b5f3bSDag-Erling Smørgrav 5351ec0d754SDag-Erling Smørgrav debug3("PAM: %s entering", __func__); 5361ec0d754SDag-Erling Smørgrav if (ctxt != NULL && ctxt->pam_thread != 0) { 537cf2b5f3bSDag-Erling Smørgrav pthread_cancel(ctxt->pam_thread); 538cf2b5f3bSDag-Erling Smørgrav pthread_join(ctxt->pam_thread, NULL); 539cf2b5f3bSDag-Erling Smørgrav close(ctxt->pam_psock); 540cf2b5f3bSDag-Erling Smørgrav close(ctxt->pam_csock); 5411ec0d754SDag-Erling Smørgrav memset(ctxt, 0, sizeof(*ctxt)); 5421ec0d754SDag-Erling Smørgrav cleanup_ctxt = NULL; 5431ec0d754SDag-Erling Smørgrav } 544cf2b5f3bSDag-Erling Smørgrav } 545cf2b5f3bSDag-Erling Smørgrav 546cf2b5f3bSDag-Erling Smørgrav static int 547d4ecd108SDag-Erling Smørgrav sshpam_null_conv(int n, sshpam_const struct pam_message **msg, 548cf2b5f3bSDag-Erling Smørgrav struct pam_response **resp, void *data) 549cf2b5f3bSDag-Erling Smørgrav { 5501ec0d754SDag-Erling Smørgrav debug3("PAM: %s entering, %d messages", __func__, n); 551cf2b5f3bSDag-Erling Smørgrav return (PAM_CONV_ERR); 552cf2b5f3bSDag-Erling Smørgrav } 553cf2b5f3bSDag-Erling Smørgrav 554cf2b5f3bSDag-Erling Smørgrav static struct pam_conv null_conv = { sshpam_null_conv, NULL }; 555cf2b5f3bSDag-Erling Smørgrav 556aa49c926SDag-Erling Smørgrav static int 557d4ecd108SDag-Erling Smørgrav sshpam_store_conv(int n, sshpam_const struct pam_message **msg, 558aa49c926SDag-Erling Smørgrav struct pam_response **resp, void *data) 559aa49c926SDag-Erling Smørgrav { 560aa49c926SDag-Erling Smørgrav struct pam_response *reply; 561aa49c926SDag-Erling Smørgrav int i; 562aa49c926SDag-Erling Smørgrav size_t len; 563aa49c926SDag-Erling Smørgrav 564aa49c926SDag-Erling Smørgrav debug3("PAM: %s called with %d messages", __func__, n); 565aa49c926SDag-Erling Smørgrav *resp = NULL; 566aa49c926SDag-Erling Smørgrav 567aa49c926SDag-Erling Smørgrav if (n <= 0 || n > PAM_MAX_NUM_MSG) 568aa49c926SDag-Erling Smørgrav return (PAM_CONV_ERR); 569aa49c926SDag-Erling Smørgrav 570333ee039SDag-Erling Smørgrav if ((reply = calloc(n, sizeof(*reply))) == NULL) 571aa49c926SDag-Erling Smørgrav return (PAM_CONV_ERR); 572aa49c926SDag-Erling Smørgrav 573aa49c926SDag-Erling Smørgrav for (i = 0; i < n; ++i) { 574aa49c926SDag-Erling Smørgrav switch (PAM_MSG_MEMBER(msg, i, msg_style)) { 575aa49c926SDag-Erling Smørgrav case PAM_ERROR_MSG: 576aa49c926SDag-Erling Smørgrav case PAM_TEXT_INFO: 577aa49c926SDag-Erling Smørgrav len = strlen(PAM_MSG_MEMBER(msg, i, msg)); 578aa49c926SDag-Erling Smørgrav buffer_append(&loginmsg, PAM_MSG_MEMBER(msg, i, msg), len); 579aa49c926SDag-Erling Smørgrav buffer_append(&loginmsg, "\n", 1 ); 580aa49c926SDag-Erling Smørgrav reply[i].resp_retcode = PAM_SUCCESS; 581aa49c926SDag-Erling Smørgrav break; 582aa49c926SDag-Erling Smørgrav default: 583aa49c926SDag-Erling Smørgrav goto fail; 584aa49c926SDag-Erling Smørgrav } 585aa49c926SDag-Erling Smørgrav } 586aa49c926SDag-Erling Smørgrav *resp = reply; 587aa49c926SDag-Erling Smørgrav return (PAM_SUCCESS); 588aa49c926SDag-Erling Smørgrav 589aa49c926SDag-Erling Smørgrav fail: 590aa49c926SDag-Erling Smørgrav for(i = 0; i < n; i++) { 591e4a9863fSDag-Erling Smørgrav free(reply[i].resp); 592aa49c926SDag-Erling Smørgrav } 593e4a9863fSDag-Erling Smørgrav free(reply); 594aa49c926SDag-Erling Smørgrav return (PAM_CONV_ERR); 595aa49c926SDag-Erling Smørgrav } 596aa49c926SDag-Erling Smørgrav 597aa49c926SDag-Erling Smørgrav static struct pam_conv store_conv = { sshpam_store_conv, NULL }; 598aa49c926SDag-Erling Smørgrav 5991ec0d754SDag-Erling Smørgrav void 6001ec0d754SDag-Erling Smørgrav sshpam_cleanup(void) 601cf2b5f3bSDag-Erling Smørgrav { 602d4af9e69SDag-Erling Smørgrav if (sshpam_handle == NULL || (use_privsep && !mm_is_monitor())) 603cf2b5f3bSDag-Erling Smørgrav return; 604d4af9e69SDag-Erling Smørgrav debug("PAM: cleanup"); 605cf2b5f3bSDag-Erling Smørgrav pam_set_item(sshpam_handle, PAM_CONV, (const void *)&null_conv); 606cf2b5f3bSDag-Erling Smørgrav if (sshpam_session_open) { 607d4af9e69SDag-Erling Smørgrav debug("PAM: closing session"); 608cf2b5f3bSDag-Erling Smørgrav pam_close_session(sshpam_handle, PAM_SILENT); 609cf2b5f3bSDag-Erling Smørgrav sshpam_session_open = 0; 610cf2b5f3bSDag-Erling Smørgrav } 6117aee6ffeSDag-Erling Smørgrav if (sshpam_cred_established) { 6127aee6ffeSDag-Erling Smørgrav debug("PAM: deleting credentials"); 6137aee6ffeSDag-Erling Smørgrav pam_setcred(sshpam_handle, PAM_DELETE_CRED); 6147aee6ffeSDag-Erling Smørgrav sshpam_cred_established = 0; 6157aee6ffeSDag-Erling Smørgrav } 6161ec0d754SDag-Erling Smørgrav sshpam_authenticated = 0; 617cf2b5f3bSDag-Erling Smørgrav pam_end(sshpam_handle, sshpam_err); 618cf2b5f3bSDag-Erling Smørgrav sshpam_handle = NULL; 619cf2b5f3bSDag-Erling Smørgrav } 620cf2b5f3bSDag-Erling Smørgrav 621cf2b5f3bSDag-Erling Smørgrav static int 6225962c0e9SDag-Erling Smørgrav sshpam_init(Authctxt *authctxt) 623cf2b5f3bSDag-Erling Smørgrav { 6245962c0e9SDag-Erling Smørgrav const char *pam_rhost, *pam_user, *user = authctxt->user; 625d4ecd108SDag-Erling Smørgrav const char **ptr_pam_user = &pam_user; 626076ad2f8SDag-Erling Smørgrav struct ssh *ssh = active_state; /* XXX */ 627cf2b5f3bSDag-Erling Smørgrav 628cf2b5f3bSDag-Erling Smørgrav if (sshpam_handle != NULL) { 629cf2b5f3bSDag-Erling Smørgrav /* We already have a PAM context; check if the user matches */ 630cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_get_item(sshpam_handle, 631d4ecd108SDag-Erling Smørgrav PAM_USER, (sshpam_const void **)ptr_pam_user); 632cf2b5f3bSDag-Erling Smørgrav if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0) 633cf2b5f3bSDag-Erling Smørgrav return (0); 634cf2b5f3bSDag-Erling Smørgrav pam_end(sshpam_handle, sshpam_err); 635cf2b5f3bSDag-Erling Smørgrav sshpam_handle = NULL; 636cf2b5f3bSDag-Erling Smørgrav } 637cf2b5f3bSDag-Erling Smørgrav debug("PAM: initializing for \"%s\"", user); 638cf2b5f3bSDag-Erling Smørgrav sshpam_err = 639aa49c926SDag-Erling Smørgrav pam_start(SSHD_PAM_SERVICE, user, &store_conv, &sshpam_handle); 6405962c0e9SDag-Erling Smørgrav sshpam_authctxt = authctxt; 6415962c0e9SDag-Erling Smørgrav 642cf2b5f3bSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) { 643cf2b5f3bSDag-Erling Smørgrav pam_end(sshpam_handle, sshpam_err); 644cf2b5f3bSDag-Erling Smørgrav sshpam_handle = NULL; 645cf2b5f3bSDag-Erling Smørgrav return (-1); 646cf2b5f3bSDag-Erling Smørgrav } 647076ad2f8SDag-Erling Smørgrav pam_rhost = auth_get_canonical_hostname(ssh, options.use_dns); 648cf2b5f3bSDag-Erling Smørgrav debug("PAM: setting PAM_RHOST to \"%s\"", pam_rhost); 649cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST, pam_rhost); 650cf2b5f3bSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) { 651cf2b5f3bSDag-Erling Smørgrav pam_end(sshpam_handle, sshpam_err); 652cf2b5f3bSDag-Erling Smørgrav sshpam_handle = NULL; 653cf2b5f3bSDag-Erling Smørgrav return (-1); 654cf2b5f3bSDag-Erling Smørgrav } 655cf2b5f3bSDag-Erling Smørgrav #ifdef PAM_TTY_KLUDGE 656cf2b5f3bSDag-Erling Smørgrav /* 657cf2b5f3bSDag-Erling Smørgrav * Some silly PAM modules (e.g. pam_time) require a TTY to operate. 658cf2b5f3bSDag-Erling Smørgrav * sshd doesn't set the tty until too late in the auth process and 659cf2b5f3bSDag-Erling Smørgrav * may not even set one (for tty-less connections) 660cf2b5f3bSDag-Erling Smørgrav */ 661cf2b5f3bSDag-Erling Smørgrav debug("PAM: setting PAM_TTY to \"ssh\""); 662cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, "ssh"); 663cf2b5f3bSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) { 664cf2b5f3bSDag-Erling Smørgrav pam_end(sshpam_handle, sshpam_err); 665cf2b5f3bSDag-Erling Smørgrav sshpam_handle = NULL; 666cf2b5f3bSDag-Erling Smørgrav return (-1); 667cf2b5f3bSDag-Erling Smørgrav } 668cf2b5f3bSDag-Erling Smørgrav #endif 669cf2b5f3bSDag-Erling Smørgrav return (0); 670cf2b5f3bSDag-Erling Smørgrav } 671cf2b5f3bSDag-Erling Smørgrav 672cf2b5f3bSDag-Erling Smørgrav static void * 673cf2b5f3bSDag-Erling Smørgrav sshpam_init_ctx(Authctxt *authctxt) 674cf2b5f3bSDag-Erling Smørgrav { 675cf2b5f3bSDag-Erling Smørgrav struct pam_ctxt *ctxt; 676cf2b5f3bSDag-Erling Smørgrav int socks[2]; 677cf2b5f3bSDag-Erling Smørgrav 6781ec0d754SDag-Erling Smørgrav debug3("PAM: %s entering", __func__); 679333ee039SDag-Erling Smørgrav /* 680333ee039SDag-Erling Smørgrav * Refuse to start if we don't have PAM enabled or do_pam_account 681333ee039SDag-Erling Smørgrav * has previously failed. 682333ee039SDag-Erling Smørgrav */ 683333ee039SDag-Erling Smørgrav if (!options.use_pam || sshpam_account_status == 0) 684cf2b5f3bSDag-Erling Smørgrav return NULL; 685cf2b5f3bSDag-Erling Smørgrav 686cf2b5f3bSDag-Erling Smørgrav /* Initialize PAM */ 6875962c0e9SDag-Erling Smørgrav if (sshpam_init(authctxt) == -1) { 688cf2b5f3bSDag-Erling Smørgrav error("PAM: initialization failed"); 689cf2b5f3bSDag-Erling Smørgrav return (NULL); 690cf2b5f3bSDag-Erling Smørgrav } 691cf2b5f3bSDag-Erling Smørgrav 692d4af9e69SDag-Erling Smørgrav ctxt = xcalloc(1, sizeof *ctxt); 6931ec0d754SDag-Erling Smørgrav 694cf2b5f3bSDag-Erling Smørgrav /* Start the authentication thread */ 695cf2b5f3bSDag-Erling Smørgrav if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) { 696cf2b5f3bSDag-Erling Smørgrav error("PAM: failed create sockets: %s", strerror(errno)); 697e4a9863fSDag-Erling Smørgrav free(ctxt); 698cf2b5f3bSDag-Erling Smørgrav return (NULL); 699cf2b5f3bSDag-Erling Smørgrav } 700cf2b5f3bSDag-Erling Smørgrav ctxt->pam_psock = socks[0]; 701cf2b5f3bSDag-Erling Smørgrav ctxt->pam_csock = socks[1]; 702cf2b5f3bSDag-Erling Smørgrav if (pthread_create(&ctxt->pam_thread, NULL, sshpam_thread, ctxt) == -1) { 703cf2b5f3bSDag-Erling Smørgrav error("PAM: failed to start authentication thread: %s", 704cf2b5f3bSDag-Erling Smørgrav strerror(errno)); 705cf2b5f3bSDag-Erling Smørgrav close(socks[0]); 706cf2b5f3bSDag-Erling Smørgrav close(socks[1]); 707e4a9863fSDag-Erling Smørgrav free(ctxt); 708cf2b5f3bSDag-Erling Smørgrav return (NULL); 709cf2b5f3bSDag-Erling Smørgrav } 7101ec0d754SDag-Erling Smørgrav cleanup_ctxt = ctxt; 711cf2b5f3bSDag-Erling Smørgrav return (ctxt); 712cf2b5f3bSDag-Erling Smørgrav } 713cf2b5f3bSDag-Erling Smørgrav 714cf2b5f3bSDag-Erling Smørgrav static int 715cf2b5f3bSDag-Erling Smørgrav sshpam_query(void *ctx, char **name, char **info, 716cf2b5f3bSDag-Erling Smørgrav u_int *num, char ***prompts, u_int **echo_on) 717cf2b5f3bSDag-Erling Smørgrav { 718076ad2f8SDag-Erling Smørgrav struct ssh *ssh = active_state; /* XXX */ 719cf2b5f3bSDag-Erling Smørgrav Buffer buffer; 720cf2b5f3bSDag-Erling Smørgrav struct pam_ctxt *ctxt = ctx; 721cf2b5f3bSDag-Erling Smørgrav size_t plen; 722cf2b5f3bSDag-Erling Smørgrav u_char type; 723cf2b5f3bSDag-Erling Smørgrav char *msg; 724aa49c926SDag-Erling Smørgrav size_t len, mlen; 725cf2b5f3bSDag-Erling Smørgrav 7261ec0d754SDag-Erling Smørgrav debug3("PAM: %s entering", __func__); 727cf2b5f3bSDag-Erling Smørgrav buffer_init(&buffer); 728cf2b5f3bSDag-Erling Smørgrav *name = xstrdup(""); 729cf2b5f3bSDag-Erling Smørgrav *info = xstrdup(""); 730cf2b5f3bSDag-Erling Smørgrav *prompts = xmalloc(sizeof(char *)); 731cf2b5f3bSDag-Erling Smørgrav **prompts = NULL; 732cf2b5f3bSDag-Erling Smørgrav plen = 0; 733cf2b5f3bSDag-Erling Smørgrav *echo_on = xmalloc(sizeof(u_int)); 734cf2b5f3bSDag-Erling Smørgrav while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) { 735cf2b5f3bSDag-Erling Smørgrav type = buffer_get_char(&buffer); 736cf2b5f3bSDag-Erling Smørgrav msg = buffer_get_string(&buffer, NULL); 737aa49c926SDag-Erling Smørgrav mlen = strlen(msg); 738cf2b5f3bSDag-Erling Smørgrav switch (type) { 739cf2b5f3bSDag-Erling Smørgrav case PAM_PROMPT_ECHO_ON: 740cf2b5f3bSDag-Erling Smørgrav case PAM_PROMPT_ECHO_OFF: 741cf2b5f3bSDag-Erling Smørgrav *num = 1; 742aa49c926SDag-Erling Smørgrav len = plen + mlen + 1; 743557f75e5SDag-Erling Smørgrav **prompts = xreallocarray(**prompts, 1, len); 744aa49c926SDag-Erling Smørgrav strlcpy(**prompts + plen, msg, len - plen); 745aa49c926SDag-Erling Smørgrav plen += mlen; 746cf2b5f3bSDag-Erling Smørgrav **echo_on = (type == PAM_PROMPT_ECHO_ON); 747e4a9863fSDag-Erling Smørgrav free(msg); 748cf2b5f3bSDag-Erling Smørgrav return (0); 749cf2b5f3bSDag-Erling Smørgrav case PAM_ERROR_MSG: 750cf2b5f3bSDag-Erling Smørgrav case PAM_TEXT_INFO: 751cf2b5f3bSDag-Erling Smørgrav /* accumulate messages */ 752aa49c926SDag-Erling Smørgrav len = plen + mlen + 2; 753557f75e5SDag-Erling Smørgrav **prompts = xreallocarray(**prompts, 1, len); 754aa49c926SDag-Erling Smørgrav strlcpy(**prompts + plen, msg, len - plen); 755aa49c926SDag-Erling Smørgrav plen += mlen; 756aa49c926SDag-Erling Smørgrav strlcat(**prompts + plen, "\n", len - plen); 757aa49c926SDag-Erling Smørgrav plen++; 758e4a9863fSDag-Erling Smørgrav free(msg); 759cf2b5f3bSDag-Erling Smørgrav break; 760333ee039SDag-Erling Smørgrav case PAM_ACCT_EXPIRED: 761076ad2f8SDag-Erling Smørgrav case PAM_MAXTRIES: 762076ad2f8SDag-Erling Smørgrav if (type == PAM_ACCT_EXPIRED) 763333ee039SDag-Erling Smørgrav sshpam_account_status = 0; 764076ad2f8SDag-Erling Smørgrav if (type == PAM_MAXTRIES) 765076ad2f8SDag-Erling Smørgrav sshpam_set_maxtries_reached(1); 766333ee039SDag-Erling Smørgrav /* FALLTHROUGH */ 767cf2b5f3bSDag-Erling Smørgrav case PAM_AUTH_ERR: 768333ee039SDag-Erling Smørgrav debug3("PAM: %s", pam_strerror(sshpam_handle, type)); 769b74df5b2SDag-Erling Smørgrav if (**prompts != NULL && strlen(**prompts) != 0) { 770b74df5b2SDag-Erling Smørgrav *info = **prompts; 771b74df5b2SDag-Erling Smørgrav **prompts = NULL; 772b74df5b2SDag-Erling Smørgrav *num = 0; 773b74df5b2SDag-Erling Smørgrav **echo_on = 0; 774b74df5b2SDag-Erling Smørgrav ctxt->pam_done = -1; 775e4a9863fSDag-Erling Smørgrav free(msg); 776b74df5b2SDag-Erling Smørgrav return 0; 777b74df5b2SDag-Erling Smørgrav } 778b74df5b2SDag-Erling Smørgrav /* FALLTHROUGH */ 779b74df5b2SDag-Erling Smørgrav case PAM_SUCCESS: 780cf2b5f3bSDag-Erling Smørgrav if (**prompts != NULL) { 781cf2b5f3bSDag-Erling Smørgrav /* drain any accumulated messages */ 7821ec0d754SDag-Erling Smørgrav debug("PAM: %s", **prompts); 7831ec0d754SDag-Erling Smørgrav buffer_append(&loginmsg, **prompts, 7841ec0d754SDag-Erling Smørgrav strlen(**prompts)); 785e4a9863fSDag-Erling Smørgrav free(**prompts); 786cf2b5f3bSDag-Erling Smørgrav **prompts = NULL; 787cf2b5f3bSDag-Erling Smørgrav } 788cf2b5f3bSDag-Erling Smørgrav if (type == PAM_SUCCESS) { 789aa49c926SDag-Erling Smørgrav if (!sshpam_authctxt->valid || 790aa49c926SDag-Erling Smørgrav (sshpam_authctxt->pw->pw_uid == 0 && 791aa49c926SDag-Erling Smørgrav options.permit_root_login != PERMIT_YES)) 792aa49c926SDag-Erling Smørgrav fatal("Internal error: PAM auth " 793aa49c926SDag-Erling Smørgrav "succeeded when it should have " 794aa49c926SDag-Erling Smørgrav "failed"); 7951ec0d754SDag-Erling Smørgrav import_environments(&buffer); 796cf2b5f3bSDag-Erling Smørgrav *num = 0; 797cf2b5f3bSDag-Erling Smørgrav **echo_on = 0; 798cf2b5f3bSDag-Erling Smørgrav ctxt->pam_done = 1; 799e4a9863fSDag-Erling Smørgrav free(msg); 800cf2b5f3bSDag-Erling Smørgrav return (0); 801cf2b5f3bSDag-Erling Smørgrav } 802342b8b88SKurt Lidl BLACKLIST_NOTIFY(BLACKLIST_BAD_USER, 803342b8b88SKurt Lidl sshpam_authctxt->user); 8045962c0e9SDag-Erling Smørgrav error("PAM: %s for %s%.100s from %.100s", msg, 8055962c0e9SDag-Erling Smørgrav sshpam_authctxt->valid ? "" : "illegal user ", 8065962c0e9SDag-Erling Smørgrav sshpam_authctxt->user, 807076ad2f8SDag-Erling Smørgrav auth_get_canonical_hostname(ssh, options.use_dns)); 8081ec0d754SDag-Erling Smørgrav /* FALLTHROUGH */ 809cf2b5f3bSDag-Erling Smørgrav default: 810cf2b5f3bSDag-Erling Smørgrav *num = 0; 811cf2b5f3bSDag-Erling Smørgrav **echo_on = 0; 812e4a9863fSDag-Erling Smørgrav free(msg); 813cf2b5f3bSDag-Erling Smørgrav ctxt->pam_done = -1; 814cf2b5f3bSDag-Erling Smørgrav return (-1); 815cf2b5f3bSDag-Erling Smørgrav } 816cf2b5f3bSDag-Erling Smørgrav } 817cf2b5f3bSDag-Erling Smørgrav return (-1); 818cf2b5f3bSDag-Erling Smørgrav } 819cf2b5f3bSDag-Erling Smørgrav 820076ad2f8SDag-Erling Smørgrav /* 821076ad2f8SDag-Erling Smørgrav * Returns a junk password of identical length to that the user supplied. 822076ad2f8SDag-Erling Smørgrav * Used to mitigate timing attacks against crypt(3)/PAM stacks that 823076ad2f8SDag-Erling Smørgrav * vary processing time in proportion to password length. 824076ad2f8SDag-Erling Smørgrav */ 825076ad2f8SDag-Erling Smørgrav static char * 826076ad2f8SDag-Erling Smørgrav fake_password(const char *wire_password) 827076ad2f8SDag-Erling Smørgrav { 828076ad2f8SDag-Erling Smørgrav const char junk[] = "\b\n\r\177INCORRECT"; 829076ad2f8SDag-Erling Smørgrav char *ret = NULL; 830076ad2f8SDag-Erling Smørgrav size_t i, l = wire_password != NULL ? strlen(wire_password) : 0; 831076ad2f8SDag-Erling Smørgrav 832076ad2f8SDag-Erling Smørgrav if (l >= INT_MAX) 833076ad2f8SDag-Erling Smørgrav fatal("%s: password length too long: %zu", __func__, l); 834076ad2f8SDag-Erling Smørgrav 835076ad2f8SDag-Erling Smørgrav ret = malloc(l + 1); 836*d93a896eSDag-Erling Smørgrav if (ret == NULL) 837*d93a896eSDag-Erling Smørgrav return NULL; 838076ad2f8SDag-Erling Smørgrav for (i = 0; i < l; i++) 839076ad2f8SDag-Erling Smørgrav ret[i] = junk[i % (sizeof(junk) - 1)]; 840076ad2f8SDag-Erling Smørgrav ret[i] = '\0'; 841076ad2f8SDag-Erling Smørgrav return ret; 842076ad2f8SDag-Erling Smørgrav } 843076ad2f8SDag-Erling Smørgrav 844cf2b5f3bSDag-Erling Smørgrav /* XXX - see also comment in auth-chall.c:verify_response */ 845cf2b5f3bSDag-Erling Smørgrav static int 846cf2b5f3bSDag-Erling Smørgrav sshpam_respond(void *ctx, u_int num, char **resp) 847cf2b5f3bSDag-Erling Smørgrav { 848cf2b5f3bSDag-Erling Smørgrav Buffer buffer; 849cf2b5f3bSDag-Erling Smørgrav struct pam_ctxt *ctxt = ctx; 850076ad2f8SDag-Erling Smørgrav char *fake; 851cf2b5f3bSDag-Erling Smørgrav 852b74df5b2SDag-Erling Smørgrav debug2("PAM: %s entering, %u responses", __func__, num); 853cf2b5f3bSDag-Erling Smørgrav switch (ctxt->pam_done) { 854cf2b5f3bSDag-Erling Smørgrav case 1: 855cf2b5f3bSDag-Erling Smørgrav sshpam_authenticated = 1; 856cf2b5f3bSDag-Erling Smørgrav return (0); 857cf2b5f3bSDag-Erling Smørgrav case 0: 858cf2b5f3bSDag-Erling Smørgrav break; 859cf2b5f3bSDag-Erling Smørgrav default: 860cf2b5f3bSDag-Erling Smørgrav return (-1); 861cf2b5f3bSDag-Erling Smørgrav } 862cf2b5f3bSDag-Erling Smørgrav if (num != 1) { 863cf2b5f3bSDag-Erling Smørgrav error("PAM: expected one response, got %u", num); 864cf2b5f3bSDag-Erling Smørgrav return (-1); 865cf2b5f3bSDag-Erling Smørgrav } 866cf2b5f3bSDag-Erling Smørgrav buffer_init(&buffer); 867aa49c926SDag-Erling Smørgrav if (sshpam_authctxt->valid && 868aa49c926SDag-Erling Smørgrav (sshpam_authctxt->pw->pw_uid != 0 || 869aa49c926SDag-Erling Smørgrav options.permit_root_login == PERMIT_YES)) 870cf2b5f3bSDag-Erling Smørgrav buffer_put_cstring(&buffer, *resp); 871076ad2f8SDag-Erling Smørgrav else { 872076ad2f8SDag-Erling Smørgrav fake = fake_password(*resp); 873076ad2f8SDag-Erling Smørgrav buffer_put_cstring(&buffer, fake); 874076ad2f8SDag-Erling Smørgrav free(fake); 875076ad2f8SDag-Erling Smørgrav } 8761ec0d754SDag-Erling Smørgrav if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) { 8771ec0d754SDag-Erling Smørgrav buffer_free(&buffer); 8781ec0d754SDag-Erling Smørgrav return (-1); 8791ec0d754SDag-Erling Smørgrav } 880cf2b5f3bSDag-Erling Smørgrav buffer_free(&buffer); 881cf2b5f3bSDag-Erling Smørgrav return (1); 882cf2b5f3bSDag-Erling Smørgrav } 883cf2b5f3bSDag-Erling Smørgrav 884cf2b5f3bSDag-Erling Smørgrav static void 885cf2b5f3bSDag-Erling Smørgrav sshpam_free_ctx(void *ctxtp) 886cf2b5f3bSDag-Erling Smørgrav { 887cf2b5f3bSDag-Erling Smørgrav struct pam_ctxt *ctxt = ctxtp; 888cf2b5f3bSDag-Erling Smørgrav 8891ec0d754SDag-Erling Smørgrav debug3("PAM: %s entering", __func__); 8901ec0d754SDag-Erling Smørgrav sshpam_thread_cleanup(); 891e4a9863fSDag-Erling Smørgrav free(ctxt); 892cf2b5f3bSDag-Erling Smørgrav /* 893cf2b5f3bSDag-Erling Smørgrav * We don't call sshpam_cleanup() here because we may need the PAM 894cf2b5f3bSDag-Erling Smørgrav * handle at a later stage, e.g. when setting up a session. It's 895cf2b5f3bSDag-Erling Smørgrav * still on the cleanup list, so pam_end() *will* be called before 896cf2b5f3bSDag-Erling Smørgrav * the server process terminates. 897cf2b5f3bSDag-Erling Smørgrav */ 898cf2b5f3bSDag-Erling Smørgrav } 899cf2b5f3bSDag-Erling Smørgrav 900cf2b5f3bSDag-Erling Smørgrav KbdintDevice sshpam_device = { 901cf2b5f3bSDag-Erling Smørgrav "pam", 902cf2b5f3bSDag-Erling Smørgrav sshpam_init_ctx, 903cf2b5f3bSDag-Erling Smørgrav sshpam_query, 904cf2b5f3bSDag-Erling Smørgrav sshpam_respond, 905cf2b5f3bSDag-Erling Smørgrav sshpam_free_ctx 906cf2b5f3bSDag-Erling Smørgrav }; 907cf2b5f3bSDag-Erling Smørgrav 908cf2b5f3bSDag-Erling Smørgrav KbdintDevice mm_sshpam_device = { 909cf2b5f3bSDag-Erling Smørgrav "pam", 910cf2b5f3bSDag-Erling Smørgrav mm_sshpam_init_ctx, 911cf2b5f3bSDag-Erling Smørgrav mm_sshpam_query, 912cf2b5f3bSDag-Erling Smørgrav mm_sshpam_respond, 913cf2b5f3bSDag-Erling Smørgrav mm_sshpam_free_ctx 914cf2b5f3bSDag-Erling Smørgrav }; 915cf2b5f3bSDag-Erling Smørgrav 916cf2b5f3bSDag-Erling Smørgrav /* 917cf2b5f3bSDag-Erling Smørgrav * This replaces auth-pam.c 918cf2b5f3bSDag-Erling Smørgrav */ 919cf2b5f3bSDag-Erling Smørgrav void 9205962c0e9SDag-Erling Smørgrav start_pam(Authctxt *authctxt) 921cf2b5f3bSDag-Erling Smørgrav { 922cf2b5f3bSDag-Erling Smørgrav if (!options.use_pam) 923cf2b5f3bSDag-Erling Smørgrav fatal("PAM: initialisation requested when UsePAM=no"); 924cf2b5f3bSDag-Erling Smørgrav 9255962c0e9SDag-Erling Smørgrav if (sshpam_init(authctxt) == -1) 926cf2b5f3bSDag-Erling Smørgrav fatal("PAM: initialisation failed"); 927cf2b5f3bSDag-Erling Smørgrav } 928cf2b5f3bSDag-Erling Smørgrav 929cf2b5f3bSDag-Erling Smørgrav void 930cf2b5f3bSDag-Erling Smørgrav finish_pam(void) 931cf2b5f3bSDag-Erling Smørgrav { 9321ec0d754SDag-Erling Smørgrav sshpam_cleanup(); 933cf2b5f3bSDag-Erling Smørgrav } 934cf2b5f3bSDag-Erling Smørgrav 935cf2b5f3bSDag-Erling Smørgrav u_int 936cf2b5f3bSDag-Erling Smørgrav do_pam_account(void) 937cf2b5f3bSDag-Erling Smørgrav { 938aa49c926SDag-Erling Smørgrav debug("%s: called", __func__); 9391ec0d754SDag-Erling Smørgrav if (sshpam_account_status != -1) 9401ec0d754SDag-Erling Smørgrav return (sshpam_account_status); 9411ec0d754SDag-Erling Smørgrav 942cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_acct_mgmt(sshpam_handle, 0); 943aa49c926SDag-Erling Smørgrav debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err, 944aa49c926SDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 945cf2b5f3bSDag-Erling Smørgrav 9461ec0d754SDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) { 9471ec0d754SDag-Erling Smørgrav sshpam_account_status = 0; 9481ec0d754SDag-Erling Smørgrav return (sshpam_account_status); 94909958426SBrian Feldman } 95009958426SBrian Feldman 9511ec0d754SDag-Erling Smørgrav if (sshpam_err == PAM_NEW_AUTHTOK_REQD) 95221e764dfSDag-Erling Smørgrav sshpam_password_change_required(1); 95309958426SBrian Feldman 9541ec0d754SDag-Erling Smørgrav sshpam_account_status = 1; 9551ec0d754SDag-Erling Smørgrav return (sshpam_account_status); 95609958426SBrian Feldman } 95709958426SBrian Feldman 958cf2b5f3bSDag-Erling Smørgrav void 959cf2b5f3bSDag-Erling Smørgrav do_pam_setcred(int init) 96009958426SBrian Feldman { 961cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, 962aa49c926SDag-Erling Smørgrav (const void *)&store_conv); 963cf2b5f3bSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) 964cf2b5f3bSDag-Erling Smørgrav fatal("PAM: failed to set PAM_CONV: %s", 965cf2b5f3bSDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 966cf2b5f3bSDag-Erling Smørgrav if (init) { 967cf2b5f3bSDag-Erling Smørgrav debug("PAM: establishing credentials"); 968cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_setcred(sshpam_handle, PAM_ESTABLISH_CRED); 969cf2b5f3bSDag-Erling Smørgrav } else { 970cf2b5f3bSDag-Erling Smørgrav debug("PAM: reinitializing credentials"); 971cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_setcred(sshpam_handle, PAM_REINITIALIZE_CRED); 972cf2b5f3bSDag-Erling Smørgrav } 973cf2b5f3bSDag-Erling Smørgrav if (sshpam_err == PAM_SUCCESS) { 974cf2b5f3bSDag-Erling Smørgrav sshpam_cred_established = 1; 975989dd127SDag-Erling Smørgrav return; 976cf2b5f3bSDag-Erling Smørgrav } 977cf2b5f3bSDag-Erling Smørgrav if (sshpam_authenticated) 978cf2b5f3bSDag-Erling Smørgrav fatal("PAM: pam_setcred(): %s", 979cf2b5f3bSDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 9802c917d39SAlfred Perlstein else 981cf2b5f3bSDag-Erling Smørgrav debug("PAM: pam_setcred(): %s", 982cf2b5f3bSDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 98309958426SBrian Feldman } 98409958426SBrian Feldman 985cf2b5f3bSDag-Erling Smørgrav static int 986d4ecd108SDag-Erling Smørgrav sshpam_tty_conv(int n, sshpam_const struct pam_message **msg, 987cf2b5f3bSDag-Erling Smørgrav struct pam_response **resp, void *data) 98809958426SBrian Feldman { 989cf2b5f3bSDag-Erling Smørgrav char input[PAM_MAX_MSG_SIZE]; 990cf2b5f3bSDag-Erling Smørgrav struct pam_response *reply; 991f388f5efSDag-Erling Smørgrav int i; 992f388f5efSDag-Erling Smørgrav 9931ec0d754SDag-Erling Smørgrav debug3("PAM: %s called with %d messages", __func__, n); 9941ec0d754SDag-Erling Smørgrav 995cf2b5f3bSDag-Erling Smørgrav *resp = NULL; 996cf2b5f3bSDag-Erling Smørgrav 9971ec0d754SDag-Erling Smørgrav if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO)) 998cf2b5f3bSDag-Erling Smørgrav return (PAM_CONV_ERR); 999cf2b5f3bSDag-Erling Smørgrav 1000333ee039SDag-Erling Smørgrav if ((reply = calloc(n, sizeof(*reply))) == NULL) 1001cf2b5f3bSDag-Erling Smørgrav return (PAM_CONV_ERR); 1002cf2b5f3bSDag-Erling Smørgrav 1003cf2b5f3bSDag-Erling Smørgrav for (i = 0; i < n; ++i) { 1004cf2b5f3bSDag-Erling Smørgrav switch (PAM_MSG_MEMBER(msg, i, msg_style)) { 1005cf2b5f3bSDag-Erling Smørgrav case PAM_PROMPT_ECHO_OFF: 1006cf2b5f3bSDag-Erling Smørgrav reply[i].resp = 1007cf2b5f3bSDag-Erling Smørgrav read_passphrase(PAM_MSG_MEMBER(msg, i, msg), 1008cf2b5f3bSDag-Erling Smørgrav RP_ALLOW_STDIN); 1009cf2b5f3bSDag-Erling Smørgrav reply[i].resp_retcode = PAM_SUCCESS; 1010cf2b5f3bSDag-Erling Smørgrav break; 1011cf2b5f3bSDag-Erling Smørgrav case PAM_PROMPT_ECHO_ON: 10121ec0d754SDag-Erling Smørgrav fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg)); 1013d4af9e69SDag-Erling Smørgrav if (fgets(input, sizeof input, stdin) == NULL) 1014d4af9e69SDag-Erling Smørgrav input[0] = '\0'; 101521e764dfSDag-Erling Smørgrav if ((reply[i].resp = strdup(input)) == NULL) 101621e764dfSDag-Erling Smørgrav goto fail; 1017cf2b5f3bSDag-Erling Smørgrav reply[i].resp_retcode = PAM_SUCCESS; 1018cf2b5f3bSDag-Erling Smørgrav break; 1019cf2b5f3bSDag-Erling Smørgrav case PAM_ERROR_MSG: 1020cf2b5f3bSDag-Erling Smørgrav case PAM_TEXT_INFO: 10211ec0d754SDag-Erling Smørgrav fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg)); 1022cf2b5f3bSDag-Erling Smørgrav reply[i].resp_retcode = PAM_SUCCESS; 1023cf2b5f3bSDag-Erling Smørgrav break; 1024cf2b5f3bSDag-Erling Smørgrav default: 1025cf2b5f3bSDag-Erling Smørgrav goto fail; 1026f388f5efSDag-Erling Smørgrav } 1027f388f5efSDag-Erling Smørgrav } 1028cf2b5f3bSDag-Erling Smørgrav *resp = reply; 1029cf2b5f3bSDag-Erling Smørgrav return (PAM_SUCCESS); 1030cf2b5f3bSDag-Erling Smørgrav 1031cf2b5f3bSDag-Erling Smørgrav fail: 1032cf2b5f3bSDag-Erling Smørgrav for(i = 0; i < n; i++) { 1033e4a9863fSDag-Erling Smørgrav free(reply[i].resp); 1034cf2b5f3bSDag-Erling Smørgrav } 1035e4a9863fSDag-Erling Smørgrav free(reply); 1036cf2b5f3bSDag-Erling Smørgrav return (PAM_CONV_ERR); 1037cf2b5f3bSDag-Erling Smørgrav } 1038f388f5efSDag-Erling Smørgrav 103921e764dfSDag-Erling Smørgrav static struct pam_conv tty_conv = { sshpam_tty_conv, NULL }; 10401ec0d754SDag-Erling Smørgrav 1041cf2b5f3bSDag-Erling Smørgrav /* 1042cf2b5f3bSDag-Erling Smørgrav * XXX this should be done in the authentication phase, but ssh1 doesn't 1043cf2b5f3bSDag-Erling Smørgrav * support that 1044cf2b5f3bSDag-Erling Smørgrav */ 1045cf2b5f3bSDag-Erling Smørgrav void 1046cf2b5f3bSDag-Erling Smørgrav do_pam_chauthtok(void) 104709958426SBrian Feldman { 1048cf2b5f3bSDag-Erling Smørgrav if (use_privsep) 1049cf2b5f3bSDag-Erling Smørgrav fatal("Password expired (unable to change with privsep)"); 1050cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, 10511ec0d754SDag-Erling Smørgrav (const void *)&tty_conv); 1052cf2b5f3bSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) 1053cf2b5f3bSDag-Erling Smørgrav fatal("PAM: failed to set PAM_CONV: %s", 1054cf2b5f3bSDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 1055cf2b5f3bSDag-Erling Smørgrav debug("PAM: changing password"); 1056cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_chauthtok(sshpam_handle, PAM_CHANGE_EXPIRED_AUTHTOK); 1057cf2b5f3bSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) 1058cf2b5f3bSDag-Erling Smørgrav fatal("PAM: pam_chauthtok(): %s", 1059cf2b5f3bSDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 106009958426SBrian Feldman } 106109958426SBrian Feldman 10621ec0d754SDag-Erling Smørgrav void 10631ec0d754SDag-Erling Smørgrav do_pam_session(void) 10641ec0d754SDag-Erling Smørgrav { 10651ec0d754SDag-Erling Smørgrav debug3("PAM: opening session"); 10661ec0d754SDag-Erling Smørgrav sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, 10671ec0d754SDag-Erling Smørgrav (const void *)&store_conv); 10681ec0d754SDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) 10691ec0d754SDag-Erling Smørgrav fatal("PAM: failed to set PAM_CONV: %s", 10701ec0d754SDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 10711ec0d754SDag-Erling Smørgrav sshpam_err = pam_open_session(sshpam_handle, 0); 1072aa49c926SDag-Erling Smørgrav if (sshpam_err == PAM_SUCCESS) 10731ec0d754SDag-Erling Smørgrav sshpam_session_open = 1; 1074aa49c926SDag-Erling Smørgrav else { 1075aa49c926SDag-Erling Smørgrav sshpam_session_open = 0; 1076aa49c926SDag-Erling Smørgrav disable_forwarding(); 1077aa49c926SDag-Erling Smørgrav error("PAM: pam_open_session(): %s", 1078aa49c926SDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 1079aa49c926SDag-Erling Smørgrav } 1080aa49c926SDag-Erling Smørgrav 1081aa49c926SDag-Erling Smørgrav } 1082aa49c926SDag-Erling Smørgrav 1083aa49c926SDag-Erling Smørgrav int 1084aa49c926SDag-Erling Smørgrav is_pam_session_open(void) 1085aa49c926SDag-Erling Smørgrav { 1086aa49c926SDag-Erling Smørgrav return sshpam_session_open; 10871ec0d754SDag-Erling Smørgrav } 10881ec0d754SDag-Erling Smørgrav 1089cf2b5f3bSDag-Erling Smørgrav /* 1090cf2b5f3bSDag-Erling Smørgrav * Set a PAM environment string. We need to do this so that the session 1091cf2b5f3bSDag-Erling Smørgrav * modules can handle things like Kerberos/GSI credentials that appear 1092cf2b5f3bSDag-Erling Smørgrav * during the ssh authentication process. 1093cf2b5f3bSDag-Erling Smørgrav */ 1094cf2b5f3bSDag-Erling Smørgrav int 1095cf2b5f3bSDag-Erling Smørgrav do_pam_putenv(char *name, char *value) 109609958426SBrian Feldman { 1097cf2b5f3bSDag-Erling Smørgrav int ret = 1; 1098cf2b5f3bSDag-Erling Smørgrav #ifdef HAVE_PAM_PUTENV 1099cf2b5f3bSDag-Erling Smørgrav char *compound; 1100cf2b5f3bSDag-Erling Smørgrav size_t len; 110109958426SBrian Feldman 1102cf2b5f3bSDag-Erling Smørgrav len = strlen(name) + strlen(value) + 2; 1103cf2b5f3bSDag-Erling Smørgrav compound = xmalloc(len); 110409958426SBrian Feldman 1105cf2b5f3bSDag-Erling Smørgrav snprintf(compound, len, "%s=%s", name, value); 1106cf2b5f3bSDag-Erling Smørgrav ret = pam_putenv(sshpam_handle, compound); 1107e4a9863fSDag-Erling Smørgrav free(compound); 1108cf2b5f3bSDag-Erling Smørgrav #endif 110909958426SBrian Feldman 1110cf2b5f3bSDag-Erling Smørgrav return (ret); 1111cf2b5f3bSDag-Erling Smørgrav } 111209958426SBrian Feldman 11131ec0d754SDag-Erling Smørgrav char ** 11141ec0d754SDag-Erling Smørgrav fetch_pam_child_environment(void) 1115cf2b5f3bSDag-Erling Smørgrav { 11161ec0d754SDag-Erling Smørgrav return sshpam_env; 1117cf2b5f3bSDag-Erling Smørgrav } 1118cf2b5f3bSDag-Erling Smørgrav 1119cf2b5f3bSDag-Erling Smørgrav char ** 1120cf2b5f3bSDag-Erling Smørgrav fetch_pam_environment(void) 1121cf2b5f3bSDag-Erling Smørgrav { 1122cf2b5f3bSDag-Erling Smørgrav return (pam_getenvlist(sshpam_handle)); 1123cf2b5f3bSDag-Erling Smørgrav } 1124cf2b5f3bSDag-Erling Smørgrav 1125cf2b5f3bSDag-Erling Smørgrav void 1126cf2b5f3bSDag-Erling Smørgrav free_pam_environment(char **env) 1127cf2b5f3bSDag-Erling Smørgrav { 1128cf2b5f3bSDag-Erling Smørgrav char **envp; 1129cf2b5f3bSDag-Erling Smørgrav 1130cf2b5f3bSDag-Erling Smørgrav if (env == NULL) 1131cf2b5f3bSDag-Erling Smørgrav return; 1132cf2b5f3bSDag-Erling Smørgrav 1133cf2b5f3bSDag-Erling Smørgrav for (envp = env; *envp; envp++) 1134e4a9863fSDag-Erling Smørgrav free(*envp); 1135e4a9863fSDag-Erling Smørgrav free(env); 113609958426SBrian Feldman } 113709958426SBrian Feldman 113821e764dfSDag-Erling Smørgrav /* 113921e764dfSDag-Erling Smørgrav * "Blind" conversation function for password authentication. Assumes that 114021e764dfSDag-Erling Smørgrav * echo-off prompts are for the password and stores messages for later 114121e764dfSDag-Erling Smørgrav * display. 114221e764dfSDag-Erling Smørgrav */ 114321e764dfSDag-Erling Smørgrav static int 1144d4ecd108SDag-Erling Smørgrav sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg, 114521e764dfSDag-Erling Smørgrav struct pam_response **resp, void *data) 114621e764dfSDag-Erling Smørgrav { 114721e764dfSDag-Erling Smørgrav struct pam_response *reply; 114821e764dfSDag-Erling Smørgrav int i; 114921e764dfSDag-Erling Smørgrav size_t len; 115021e764dfSDag-Erling Smørgrav 115121e764dfSDag-Erling Smørgrav debug3("PAM: %s called with %d messages", __func__, n); 115221e764dfSDag-Erling Smørgrav 115321e764dfSDag-Erling Smørgrav *resp = NULL; 115421e764dfSDag-Erling Smørgrav 115521e764dfSDag-Erling Smørgrav if (n <= 0 || n > PAM_MAX_NUM_MSG) 115621e764dfSDag-Erling Smørgrav return (PAM_CONV_ERR); 115721e764dfSDag-Erling Smørgrav 1158d4af9e69SDag-Erling Smørgrav if ((reply = calloc(n, sizeof(*reply))) == NULL) 115921e764dfSDag-Erling Smørgrav return (PAM_CONV_ERR); 116021e764dfSDag-Erling Smørgrav 116121e764dfSDag-Erling Smørgrav for (i = 0; i < n; ++i) { 116221e764dfSDag-Erling Smørgrav switch (PAM_MSG_MEMBER(msg, i, msg_style)) { 116321e764dfSDag-Erling Smørgrav case PAM_PROMPT_ECHO_OFF: 116421e764dfSDag-Erling Smørgrav if (sshpam_password == NULL) 116521e764dfSDag-Erling Smørgrav goto fail; 116621e764dfSDag-Erling Smørgrav if ((reply[i].resp = strdup(sshpam_password)) == NULL) 116721e764dfSDag-Erling Smørgrav goto fail; 116821e764dfSDag-Erling Smørgrav reply[i].resp_retcode = PAM_SUCCESS; 116921e764dfSDag-Erling Smørgrav break; 117021e764dfSDag-Erling Smørgrav case PAM_ERROR_MSG: 117121e764dfSDag-Erling Smørgrav case PAM_TEXT_INFO: 117221e764dfSDag-Erling Smørgrav len = strlen(PAM_MSG_MEMBER(msg, i, msg)); 117321e764dfSDag-Erling Smørgrav if (len > 0) { 117421e764dfSDag-Erling Smørgrav buffer_append(&loginmsg, 117521e764dfSDag-Erling Smørgrav PAM_MSG_MEMBER(msg, i, msg), len); 117621e764dfSDag-Erling Smørgrav buffer_append(&loginmsg, "\n", 1); 117721e764dfSDag-Erling Smørgrav } 117821e764dfSDag-Erling Smørgrav if ((reply[i].resp = strdup("")) == NULL) 117921e764dfSDag-Erling Smørgrav goto fail; 118021e764dfSDag-Erling Smørgrav reply[i].resp_retcode = PAM_SUCCESS; 118121e764dfSDag-Erling Smørgrav break; 118221e764dfSDag-Erling Smørgrav default: 118321e764dfSDag-Erling Smørgrav goto fail; 118421e764dfSDag-Erling Smørgrav } 118521e764dfSDag-Erling Smørgrav } 118621e764dfSDag-Erling Smørgrav *resp = reply; 118721e764dfSDag-Erling Smørgrav return (PAM_SUCCESS); 118821e764dfSDag-Erling Smørgrav 118921e764dfSDag-Erling Smørgrav fail: 119021e764dfSDag-Erling Smørgrav for(i = 0; i < n; i++) { 1191e4a9863fSDag-Erling Smørgrav free(reply[i].resp); 119221e764dfSDag-Erling Smørgrav } 1193e4a9863fSDag-Erling Smørgrav free(reply); 119421e764dfSDag-Erling Smørgrav return (PAM_CONV_ERR); 119521e764dfSDag-Erling Smørgrav } 119621e764dfSDag-Erling Smørgrav 119721e764dfSDag-Erling Smørgrav static struct pam_conv passwd_conv = { sshpam_passwd_conv, NULL }; 119821e764dfSDag-Erling Smørgrav 119921e764dfSDag-Erling Smørgrav /* 120021e764dfSDag-Erling Smørgrav * Attempt password authentication via PAM 120121e764dfSDag-Erling Smørgrav */ 120221e764dfSDag-Erling Smørgrav int 120321e764dfSDag-Erling Smørgrav sshpam_auth_passwd(Authctxt *authctxt, const char *password) 120421e764dfSDag-Erling Smørgrav { 120521e764dfSDag-Erling Smørgrav int flags = (options.permit_empty_passwd == 0 ? 120621e764dfSDag-Erling Smørgrav PAM_DISALLOW_NULL_AUTHTOK : 0); 1207076ad2f8SDag-Erling Smørgrav char *fake = NULL; 120821e764dfSDag-Erling Smørgrav 120921e764dfSDag-Erling Smørgrav if (!options.use_pam || sshpam_handle == NULL) 121021e764dfSDag-Erling Smørgrav fatal("PAM: %s called when PAM disabled or failed to " 121121e764dfSDag-Erling Smørgrav "initialise.", __func__); 121221e764dfSDag-Erling Smørgrav 121321e764dfSDag-Erling Smørgrav sshpam_password = password; 121421e764dfSDag-Erling Smørgrav sshpam_authctxt = authctxt; 121521e764dfSDag-Erling Smørgrav 121621e764dfSDag-Erling Smørgrav /* 121721e764dfSDag-Erling Smørgrav * If the user logging in is invalid, or is root but is not permitted 121821e764dfSDag-Erling Smørgrav * by PermitRootLogin, use an invalid password to prevent leaking 121921e764dfSDag-Erling Smørgrav * information via timing (eg if the PAM config has a delay on fail). 122021e764dfSDag-Erling Smørgrav */ 122121e764dfSDag-Erling Smørgrav if (!authctxt->valid || (authctxt->pw->pw_uid == 0 && 122221e764dfSDag-Erling Smørgrav options.permit_root_login != PERMIT_YES)) 1223076ad2f8SDag-Erling Smørgrav sshpam_password = fake = fake_password(password); 122421e764dfSDag-Erling Smørgrav 122521e764dfSDag-Erling Smørgrav sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, 122621e764dfSDag-Erling Smørgrav (const void *)&passwd_conv); 122721e764dfSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) 122821e764dfSDag-Erling Smørgrav fatal("PAM: %s: failed to set PAM_CONV: %s", __func__, 122921e764dfSDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 123021e764dfSDag-Erling Smørgrav 123121e764dfSDag-Erling Smørgrav sshpam_err = pam_authenticate(sshpam_handle, flags); 123221e764dfSDag-Erling Smørgrav sshpam_password = NULL; 1233076ad2f8SDag-Erling Smørgrav free(fake); 1234076ad2f8SDag-Erling Smørgrav if (sshpam_err == PAM_MAXTRIES) 1235076ad2f8SDag-Erling Smørgrav sshpam_set_maxtries_reached(1); 123621e764dfSDag-Erling Smørgrav if (sshpam_err == PAM_SUCCESS && authctxt->valid) { 123721e764dfSDag-Erling Smørgrav debug("PAM: password authentication accepted for %.100s", 123821e764dfSDag-Erling Smørgrav authctxt->user); 123921e764dfSDag-Erling Smørgrav return 1; 124021e764dfSDag-Erling Smørgrav } else { 124121e764dfSDag-Erling Smørgrav debug("PAM: password authentication failed for %.100s: %s", 124221e764dfSDag-Erling Smørgrav authctxt->valid ? authctxt->user : "an illegal user", 124321e764dfSDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 124421e764dfSDag-Erling Smørgrav return 0; 124521e764dfSDag-Erling Smørgrav } 124621e764dfSDag-Erling Smørgrav } 1247076ad2f8SDag-Erling Smørgrav 1248076ad2f8SDag-Erling Smørgrav int 1249076ad2f8SDag-Erling Smørgrav sshpam_get_maxtries_reached(void) 1250076ad2f8SDag-Erling Smørgrav { 1251076ad2f8SDag-Erling Smørgrav return sshpam_maxtries_reached; 1252076ad2f8SDag-Erling Smørgrav } 1253076ad2f8SDag-Erling Smørgrav 1254076ad2f8SDag-Erling Smørgrav void 1255076ad2f8SDag-Erling Smørgrav sshpam_set_maxtries_reached(int reached) 1256076ad2f8SDag-Erling Smørgrav { 1257076ad2f8SDag-Erling Smørgrav if (reached == 0 || sshpam_maxtries_reached) 1258076ad2f8SDag-Erling Smørgrav return; 1259076ad2f8SDag-Erling Smørgrav sshpam_maxtries_reached = 1; 1260076ad2f8SDag-Erling Smørgrav options.password_authentication = 0; 1261076ad2f8SDag-Erling Smørgrav options.kbd_interactive_authentication = 0; 1262076ad2f8SDag-Erling Smørgrav options.challenge_response_authentication = 0; 1263076ad2f8SDag-Erling Smørgrav } 126409958426SBrian Feldman #endif /* USE_PAM */ 1265