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 */ 3109958426SBrian Feldman 32cf2b5f3bSDag-Erling Smørgrav /* Based on $xFreeBSD: src/crypto/openssh/auth2-pam-freebsd.c,v 1.11 2003/03/31 13:48:18 des Exp $ */ 3309958426SBrian Feldman #include "includes.h" 345962c0e9SDag-Erling Smørgrav RCSID("$Id: auth-pam.c,v 1.100 2004/04/18 01:00:26 dtucker Exp $"); 35cf2b5f3bSDag-Erling Smørgrav RCSID("$FreeBSD$"); 3609958426SBrian Feldman 3709958426SBrian Feldman #ifdef USE_PAM 381ec0d754SDag-Erling Smørgrav #if defined(HAVE_SECURITY_PAM_APPL_H) 39cf2b5f3bSDag-Erling Smørgrav #include <security/pam_appl.h> 401ec0d754SDag-Erling Smørgrav #elif defined (HAVE_PAM_PAM_APPL_H) 411ec0d754SDag-Erling Smørgrav #include <pam/pam_appl.h> 421ec0d754SDag-Erling Smørgrav #endif 43cf2b5f3bSDag-Erling Smørgrav 44989dd127SDag-Erling Smørgrav #include "auth.h" 45989dd127SDag-Erling Smørgrav #include "auth-pam.h" 46cf2b5f3bSDag-Erling Smørgrav #include "buffer.h" 47cf2b5f3bSDag-Erling Smørgrav #include "bufaux.h" 484c5de869SBrian Feldman #include "canohost.h" 49cf2b5f3bSDag-Erling Smørgrav #include "log.h" 50cf2b5f3bSDag-Erling Smørgrav #include "monitor_wrap.h" 51cf2b5f3bSDag-Erling Smørgrav #include "msg.h" 52cf2b5f3bSDag-Erling Smørgrav #include "packet.h" 53989dd127SDag-Erling Smørgrav #include "readpass.h" 54cf2b5f3bSDag-Erling Smørgrav #include "servconf.h" 55cf2b5f3bSDag-Erling Smørgrav #include "ssh2.h" 56cf2b5f3bSDag-Erling Smørgrav #include "xmalloc.h" 57cf2b5f3bSDag-Erling Smørgrav #include "auth-options.h" 5809958426SBrian Feldman 59989dd127SDag-Erling Smørgrav extern ServerOptions options; 601ec0d754SDag-Erling Smørgrav extern Buffer loginmsg; 611ec0d754SDag-Erling Smørgrav extern int compat20; 625962c0e9SDag-Erling Smørgrav extern u_int utmp_len; 632c917d39SAlfred Perlstein 64cf2b5f3bSDag-Erling Smørgrav #ifdef USE_POSIX_THREADS 65cf2b5f3bSDag-Erling Smørgrav #include <pthread.h> 66cf2b5f3bSDag-Erling Smørgrav /* 67cf2b5f3bSDag-Erling Smørgrav * Avoid namespace clash when *not* using pthreads for systems *with* 68cf2b5f3bSDag-Erling Smørgrav * pthreads, which unconditionally define pthread_t via sys/types.h 69cf2b5f3bSDag-Erling Smørgrav * (e.g. Linux) 70cf2b5f3bSDag-Erling Smørgrav */ 71cf2b5f3bSDag-Erling Smørgrav typedef pthread_t sp_pthread_t; 72cf2b5f3bSDag-Erling Smørgrav #else 731ec0d754SDag-Erling Smørgrav typedef pid_t sp_pthread_t; 741ec0d754SDag-Erling Smørgrav #endif 751ec0d754SDag-Erling Smørgrav 761ec0d754SDag-Erling Smørgrav struct pam_ctxt { 771ec0d754SDag-Erling Smørgrav sp_pthread_t pam_thread; 781ec0d754SDag-Erling Smørgrav int pam_psock; 791ec0d754SDag-Erling Smørgrav int pam_csock; 801ec0d754SDag-Erling Smørgrav int pam_done; 811ec0d754SDag-Erling Smørgrav }; 821ec0d754SDag-Erling Smørgrav 831ec0d754SDag-Erling Smørgrav static void sshpam_free_ctx(void *); 841ec0d754SDag-Erling Smørgrav static struct pam_ctxt *cleanup_ctxt; 851ec0d754SDag-Erling Smørgrav 861ec0d754SDag-Erling Smørgrav #ifndef USE_POSIX_THREADS 87cf2b5f3bSDag-Erling Smørgrav /* 88cf2b5f3bSDag-Erling Smørgrav * Simulate threads with processes. 89cf2b5f3bSDag-Erling Smørgrav */ 901ec0d754SDag-Erling Smørgrav 911ec0d754SDag-Erling Smørgrav static int sshpam_thread_status = -1; 921ec0d754SDag-Erling Smørgrav static mysig_t sshpam_oldsig; 931ec0d754SDag-Erling Smørgrav 941ec0d754SDag-Erling Smørgrav static void 951ec0d754SDag-Erling Smørgrav sshpam_sigchld_handler(int sig) 961ec0d754SDag-Erling Smørgrav { 971ec0d754SDag-Erling Smørgrav if (cleanup_ctxt == NULL) 981ec0d754SDag-Erling Smørgrav return; /* handler called after PAM cleanup, shouldn't happen */ 991ec0d754SDag-Erling Smørgrav if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, 0) == -1) 1001ec0d754SDag-Erling Smørgrav return; /* couldn't wait for process */ 1011ec0d754SDag-Erling Smørgrav if (WIFSIGNALED(sshpam_thread_status) && 1021ec0d754SDag-Erling Smørgrav WTERMSIG(sshpam_thread_status) == SIGTERM) 1031ec0d754SDag-Erling Smørgrav return; /* terminated by pthread_cancel */ 1041ec0d754SDag-Erling Smørgrav if (!WIFEXITED(sshpam_thread_status)) 1051ec0d754SDag-Erling Smørgrav fatal("PAM: authentication thread exited unexpectedly"); 1061ec0d754SDag-Erling Smørgrav if (WEXITSTATUS(sshpam_thread_status) != 0) 1071ec0d754SDag-Erling Smørgrav fatal("PAM: authentication thread exited uncleanly"); 1081ec0d754SDag-Erling Smørgrav } 10909958426SBrian Feldman 110cf2b5f3bSDag-Erling Smørgrav static void 111cf2b5f3bSDag-Erling Smørgrav pthread_exit(void *value __unused) 11209958426SBrian Feldman { 113cf2b5f3bSDag-Erling Smørgrav _exit(0); 11409958426SBrian Feldman } 11509958426SBrian Feldman 116cf2b5f3bSDag-Erling Smørgrav static int 117cf2b5f3bSDag-Erling Smørgrav pthread_create(sp_pthread_t *thread, const void *attr __unused, 118cf2b5f3bSDag-Erling Smørgrav void *(*thread_start)(void *), void *arg) 119cf2b5f3bSDag-Erling Smørgrav { 120cf2b5f3bSDag-Erling Smørgrav pid_t pid; 121cf2b5f3bSDag-Erling Smørgrav 1225962c0e9SDag-Erling Smørgrav sshpam_thread_status = -1; 123cf2b5f3bSDag-Erling Smørgrav switch ((pid = fork())) { 124cf2b5f3bSDag-Erling Smørgrav case -1: 125cf2b5f3bSDag-Erling Smørgrav error("fork(): %s", strerror(errno)); 126cf2b5f3bSDag-Erling Smørgrav return (-1); 127cf2b5f3bSDag-Erling Smørgrav case 0: 128cf2b5f3bSDag-Erling Smørgrav thread_start(arg); 129cf2b5f3bSDag-Erling Smørgrav _exit(1); 130cf2b5f3bSDag-Erling Smørgrav default: 131cf2b5f3bSDag-Erling Smørgrav *thread = pid; 1321ec0d754SDag-Erling Smørgrav sshpam_oldsig = signal(SIGCHLD, sshpam_sigchld_handler); 133cf2b5f3bSDag-Erling Smørgrav return (0); 134cf2b5f3bSDag-Erling Smørgrav } 135cf2b5f3bSDag-Erling Smørgrav } 136cf2b5f3bSDag-Erling Smørgrav 137cf2b5f3bSDag-Erling Smørgrav static int 138cf2b5f3bSDag-Erling Smørgrav pthread_cancel(sp_pthread_t thread) 139cf2b5f3bSDag-Erling Smørgrav { 1401ec0d754SDag-Erling Smørgrav signal(SIGCHLD, sshpam_oldsig); 141cf2b5f3bSDag-Erling Smørgrav return (kill(thread, SIGTERM)); 142cf2b5f3bSDag-Erling Smørgrav } 143cf2b5f3bSDag-Erling Smørgrav 144cf2b5f3bSDag-Erling Smørgrav static int 145cf2b5f3bSDag-Erling Smørgrav pthread_join(sp_pthread_t thread, void **value __unused) 146cf2b5f3bSDag-Erling Smørgrav { 147cf2b5f3bSDag-Erling Smørgrav int status; 148cf2b5f3bSDag-Erling Smørgrav 1491ec0d754SDag-Erling Smørgrav if (sshpam_thread_status != -1) 1501ec0d754SDag-Erling Smørgrav return (sshpam_thread_status); 1511ec0d754SDag-Erling Smørgrav signal(SIGCHLD, sshpam_oldsig); 152cf2b5f3bSDag-Erling Smørgrav waitpid(thread, &status, 0); 153cf2b5f3bSDag-Erling Smørgrav return (status); 154cf2b5f3bSDag-Erling Smørgrav } 155cf2b5f3bSDag-Erling Smørgrav #endif 156cf2b5f3bSDag-Erling Smørgrav 157cf2b5f3bSDag-Erling Smørgrav 158cf2b5f3bSDag-Erling Smørgrav static pam_handle_t *sshpam_handle = NULL; 159cf2b5f3bSDag-Erling Smørgrav static int sshpam_err = 0; 160cf2b5f3bSDag-Erling Smørgrav static int sshpam_authenticated = 0; 161cf2b5f3bSDag-Erling Smørgrav static int sshpam_session_open = 0; 162cf2b5f3bSDag-Erling Smørgrav static int sshpam_cred_established = 0; 1631ec0d754SDag-Erling Smørgrav static int sshpam_account_status = -1; 1641ec0d754SDag-Erling Smørgrav static char **sshpam_env = NULL; 1655962c0e9SDag-Erling Smørgrav static Authctxt *sshpam_authctxt = NULL; 166cf2b5f3bSDag-Erling Smørgrav 1671ec0d754SDag-Erling Smørgrav /* Some PAM implementations don't implement this */ 1681ec0d754SDag-Erling Smørgrav #ifndef HAVE_PAM_GETENVLIST 1691ec0d754SDag-Erling Smørgrav static char ** 1701ec0d754SDag-Erling Smørgrav pam_getenvlist(pam_handle_t *pamh) 1711ec0d754SDag-Erling Smørgrav { 1721ec0d754SDag-Erling Smørgrav /* 1731ec0d754SDag-Erling Smørgrav * XXX - If necessary, we can still support envrionment passing 1741ec0d754SDag-Erling Smørgrav * for platforms without pam_getenvlist by searching for known 1751ec0d754SDag-Erling Smørgrav * env vars (e.g. KRB5CCNAME) from the PAM environment. 1761ec0d754SDag-Erling Smørgrav */ 1771ec0d754SDag-Erling Smørgrav return NULL; 1781ec0d754SDag-Erling Smørgrav } 1791ec0d754SDag-Erling Smørgrav #endif 180cf2b5f3bSDag-Erling Smørgrav 1811ec0d754SDag-Erling Smørgrav void 1821ec0d754SDag-Erling Smørgrav pam_password_change_required(int reqd) 1831ec0d754SDag-Erling Smørgrav { 1841ec0d754SDag-Erling Smørgrav debug3("%s %d", __func__, reqd); 1855962c0e9SDag-Erling Smørgrav if (sshpam_authctxt == NULL) 1865962c0e9SDag-Erling Smørgrav fatal("%s: PAM authctxt not initialized", __func__); 1875962c0e9SDag-Erling Smørgrav sshpam_authctxt->force_pwchange = reqd; 1881ec0d754SDag-Erling Smørgrav if (reqd) { 1891ec0d754SDag-Erling Smørgrav no_port_forwarding_flag |= 2; 1901ec0d754SDag-Erling Smørgrav no_agent_forwarding_flag |= 2; 1911ec0d754SDag-Erling Smørgrav no_x11_forwarding_flag |= 2; 1921ec0d754SDag-Erling Smørgrav } else { 1931ec0d754SDag-Erling Smørgrav no_port_forwarding_flag &= ~2; 1941ec0d754SDag-Erling Smørgrav no_agent_forwarding_flag &= ~2; 1951ec0d754SDag-Erling Smørgrav no_x11_forwarding_flag &= ~2; 1961ec0d754SDag-Erling Smørgrav } 1971ec0d754SDag-Erling Smørgrav } 1981ec0d754SDag-Erling Smørgrav 1991ec0d754SDag-Erling Smørgrav /* Import regular and PAM environment from subprocess */ 2001ec0d754SDag-Erling Smørgrav static void 2011ec0d754SDag-Erling Smørgrav import_environments(Buffer *b) 2021ec0d754SDag-Erling Smørgrav { 2031ec0d754SDag-Erling Smørgrav char *env; 2041ec0d754SDag-Erling Smørgrav u_int i, num_env; 2051ec0d754SDag-Erling Smørgrav int err; 2061ec0d754SDag-Erling Smørgrav 2071ec0d754SDag-Erling Smørgrav debug3("PAM: %s entering", __func__); 2081ec0d754SDag-Erling Smørgrav 2095962c0e9SDag-Erling Smørgrav #ifndef USE_POSIX_THREADS 2101ec0d754SDag-Erling Smørgrav /* Import variables set by do_pam_account */ 2111ec0d754SDag-Erling Smørgrav sshpam_account_status = buffer_get_int(b); 2121ec0d754SDag-Erling Smørgrav pam_password_change_required(buffer_get_int(b)); 2131ec0d754SDag-Erling Smørgrav 2141ec0d754SDag-Erling Smørgrav /* Import environment from subprocess */ 2151ec0d754SDag-Erling Smørgrav num_env = buffer_get_int(b); 2161ec0d754SDag-Erling Smørgrav sshpam_env = xmalloc((num_env + 1) * sizeof(*sshpam_env)); 2171ec0d754SDag-Erling Smørgrav debug3("PAM: num env strings %d", num_env); 2181ec0d754SDag-Erling Smørgrav for(i = 0; i < num_env; i++) 2191ec0d754SDag-Erling Smørgrav sshpam_env[i] = buffer_get_string(b, NULL); 2201ec0d754SDag-Erling Smørgrav 2211ec0d754SDag-Erling Smørgrav sshpam_env[num_env] = NULL; 2221ec0d754SDag-Erling Smørgrav 2231ec0d754SDag-Erling Smørgrav /* Import PAM environment from subprocess */ 2241ec0d754SDag-Erling Smørgrav num_env = buffer_get_int(b); 2251ec0d754SDag-Erling Smørgrav debug("PAM: num PAM env strings %d", num_env); 2261ec0d754SDag-Erling Smørgrav for(i = 0; i < num_env; i++) { 2271ec0d754SDag-Erling Smørgrav env = buffer_get_string(b, NULL); 2281ec0d754SDag-Erling Smørgrav 2291ec0d754SDag-Erling Smørgrav #ifdef HAVE_PAM_PUTENV 2301ec0d754SDag-Erling Smørgrav /* Errors are not fatal here */ 2311ec0d754SDag-Erling Smørgrav if ((err = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) { 2321ec0d754SDag-Erling Smørgrav error("PAM: pam_putenv: %s", 2331ec0d754SDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 2341ec0d754SDag-Erling Smørgrav } 2351ec0d754SDag-Erling Smørgrav #endif 2361ec0d754SDag-Erling Smørgrav } 2375962c0e9SDag-Erling Smørgrav #endif 2381ec0d754SDag-Erling Smørgrav } 239cf2b5f3bSDag-Erling Smørgrav 240cf2b5f3bSDag-Erling Smørgrav /* 241cf2b5f3bSDag-Erling Smørgrav * Conversation function for authentication thread. 242cf2b5f3bSDag-Erling Smørgrav */ 243cf2b5f3bSDag-Erling Smørgrav static int 244cf2b5f3bSDag-Erling Smørgrav sshpam_thread_conv(int n, const struct pam_message **msg, 245cf2b5f3bSDag-Erling Smørgrav struct pam_response **resp, void *data) 246cf2b5f3bSDag-Erling Smørgrav { 247cf2b5f3bSDag-Erling Smørgrav Buffer buffer; 248cf2b5f3bSDag-Erling Smørgrav struct pam_ctxt *ctxt; 249cf2b5f3bSDag-Erling Smørgrav struct pam_response *reply; 250cf2b5f3bSDag-Erling Smørgrav int i; 251cf2b5f3bSDag-Erling Smørgrav 2521ec0d754SDag-Erling Smørgrav debug3("PAM: %s entering, %d messages", __func__, n); 253cf2b5f3bSDag-Erling Smørgrav *resp = NULL; 254cf2b5f3bSDag-Erling Smørgrav 255cf2b5f3bSDag-Erling Smørgrav ctxt = data; 256cf2b5f3bSDag-Erling Smørgrav if (n <= 0 || n > PAM_MAX_NUM_MSG) 257cf2b5f3bSDag-Erling Smørgrav return (PAM_CONV_ERR); 258cf2b5f3bSDag-Erling Smørgrav 259cf2b5f3bSDag-Erling Smørgrav if ((reply = malloc(n * sizeof(*reply))) == NULL) 260cf2b5f3bSDag-Erling Smørgrav return (PAM_CONV_ERR); 261cf2b5f3bSDag-Erling Smørgrav memset(reply, 0, n * sizeof(*reply)); 262cf2b5f3bSDag-Erling Smørgrav 263cf2b5f3bSDag-Erling Smørgrav buffer_init(&buffer); 264cf2b5f3bSDag-Erling Smørgrav for (i = 0; i < n; ++i) { 265cf2b5f3bSDag-Erling Smørgrav switch (PAM_MSG_MEMBER(msg, i, msg_style)) { 266cf2b5f3bSDag-Erling Smørgrav case PAM_PROMPT_ECHO_OFF: 267cf2b5f3bSDag-Erling Smørgrav buffer_put_cstring(&buffer, 268cf2b5f3bSDag-Erling Smørgrav PAM_MSG_MEMBER(msg, i, msg)); 2691ec0d754SDag-Erling Smørgrav if (ssh_msg_send(ctxt->pam_csock, 2701ec0d754SDag-Erling Smørgrav PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1) 2711ec0d754SDag-Erling Smørgrav goto fail; 2721ec0d754SDag-Erling Smørgrav if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1) 2731ec0d754SDag-Erling Smørgrav goto fail; 274cf2b5f3bSDag-Erling Smørgrav if (buffer_get_char(&buffer) != PAM_AUTHTOK) 275cf2b5f3bSDag-Erling Smørgrav goto fail; 276cf2b5f3bSDag-Erling Smørgrav reply[i].resp = buffer_get_string(&buffer, NULL); 27709958426SBrian Feldman break; 278cf2b5f3bSDag-Erling Smørgrav case PAM_PROMPT_ECHO_ON: 279cf2b5f3bSDag-Erling Smørgrav buffer_put_cstring(&buffer, 280cf2b5f3bSDag-Erling Smørgrav PAM_MSG_MEMBER(msg, i, msg)); 2811ec0d754SDag-Erling Smørgrav if (ssh_msg_send(ctxt->pam_csock, 2821ec0d754SDag-Erling Smørgrav PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1) 2831ec0d754SDag-Erling Smørgrav goto fail; 2841ec0d754SDag-Erling Smørgrav if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1) 2851ec0d754SDag-Erling Smørgrav goto fail; 286cf2b5f3bSDag-Erling Smørgrav if (buffer_get_char(&buffer) != PAM_AUTHTOK) 287cf2b5f3bSDag-Erling Smørgrav goto fail; 288cf2b5f3bSDag-Erling Smørgrav reply[i].resp = buffer_get_string(&buffer, NULL); 289cf2b5f3bSDag-Erling Smørgrav break; 290cf2b5f3bSDag-Erling Smørgrav case PAM_ERROR_MSG: 291cf2b5f3bSDag-Erling Smørgrav buffer_put_cstring(&buffer, 292cf2b5f3bSDag-Erling Smørgrav PAM_MSG_MEMBER(msg, i, msg)); 2931ec0d754SDag-Erling Smørgrav if (ssh_msg_send(ctxt->pam_csock, 2941ec0d754SDag-Erling Smørgrav PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1) 2951ec0d754SDag-Erling Smørgrav goto fail; 296cf2b5f3bSDag-Erling Smørgrav break; 297cf2b5f3bSDag-Erling Smørgrav case PAM_TEXT_INFO: 298cf2b5f3bSDag-Erling Smørgrav buffer_put_cstring(&buffer, 299cf2b5f3bSDag-Erling Smørgrav PAM_MSG_MEMBER(msg, i, msg)); 3001ec0d754SDag-Erling Smørgrav if (ssh_msg_send(ctxt->pam_csock, 3011ec0d754SDag-Erling Smørgrav PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1) 3021ec0d754SDag-Erling Smørgrav goto fail; 303cf2b5f3bSDag-Erling Smørgrav break; 304cf2b5f3bSDag-Erling Smørgrav default: 305cf2b5f3bSDag-Erling Smørgrav goto fail; 306cf2b5f3bSDag-Erling Smørgrav } 307cf2b5f3bSDag-Erling Smørgrav buffer_clear(&buffer); 308cf2b5f3bSDag-Erling Smørgrav } 309cf2b5f3bSDag-Erling Smørgrav buffer_free(&buffer); 310cf2b5f3bSDag-Erling Smørgrav *resp = reply; 311cf2b5f3bSDag-Erling Smørgrav return (PAM_SUCCESS); 312cf2b5f3bSDag-Erling Smørgrav 313cf2b5f3bSDag-Erling Smørgrav fail: 314cf2b5f3bSDag-Erling Smørgrav for(i = 0; i < n; i++) { 315cf2b5f3bSDag-Erling Smørgrav if (reply[i].resp != NULL) 316cf2b5f3bSDag-Erling Smørgrav xfree(reply[i].resp); 317cf2b5f3bSDag-Erling Smørgrav } 318cf2b5f3bSDag-Erling Smørgrav xfree(reply); 319cf2b5f3bSDag-Erling Smørgrav buffer_free(&buffer); 320cf2b5f3bSDag-Erling Smørgrav return (PAM_CONV_ERR); 321cf2b5f3bSDag-Erling Smørgrav } 322cf2b5f3bSDag-Erling Smørgrav 323cf2b5f3bSDag-Erling Smørgrav /* 324cf2b5f3bSDag-Erling Smørgrav * Authentication thread. 325cf2b5f3bSDag-Erling Smørgrav */ 326cf2b5f3bSDag-Erling Smørgrav static void * 327cf2b5f3bSDag-Erling Smørgrav sshpam_thread(void *ctxtp) 328cf2b5f3bSDag-Erling Smørgrav { 329cf2b5f3bSDag-Erling Smørgrav struct pam_ctxt *ctxt = ctxtp; 330cf2b5f3bSDag-Erling Smørgrav Buffer buffer; 331cf2b5f3bSDag-Erling Smørgrav struct pam_conv sshpam_conv; 332cf2b5f3bSDag-Erling Smørgrav #ifndef USE_POSIX_THREADS 3331ec0d754SDag-Erling Smørgrav extern char **environ; 3341ec0d754SDag-Erling Smørgrav char **env_from_pam; 3351ec0d754SDag-Erling Smørgrav u_int i; 336cf2b5f3bSDag-Erling Smørgrav const char *pam_user; 337cf2b5f3bSDag-Erling Smørgrav 338cf2b5f3bSDag-Erling Smørgrav pam_get_item(sshpam_handle, PAM_USER, (const void **)&pam_user); 339cf2b5f3bSDag-Erling Smørgrav setproctitle("%s [pam]", pam_user); 3401ec0d754SDag-Erling Smørgrav environ[0] = NULL; 341cf2b5f3bSDag-Erling Smørgrav #endif 342cf2b5f3bSDag-Erling Smørgrav 343cf2b5f3bSDag-Erling Smørgrav sshpam_conv.conv = sshpam_thread_conv; 344cf2b5f3bSDag-Erling Smørgrav sshpam_conv.appdata_ptr = ctxt; 345cf2b5f3bSDag-Erling Smørgrav 3465962c0e9SDag-Erling Smørgrav if (sshpam_authctxt == NULL) 3475962c0e9SDag-Erling Smørgrav fatal("%s: PAM authctxt not initialized", __func__); 3485962c0e9SDag-Erling Smørgrav 349cf2b5f3bSDag-Erling Smørgrav buffer_init(&buffer); 350cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, 351cf2b5f3bSDag-Erling Smørgrav (const void *)&sshpam_conv); 352cf2b5f3bSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) 353cf2b5f3bSDag-Erling Smørgrav goto auth_fail; 354cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_authenticate(sshpam_handle, 0); 355cf2b5f3bSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) 356cf2b5f3bSDag-Erling Smørgrav goto auth_fail; 3571ec0d754SDag-Erling Smørgrav 3581ec0d754SDag-Erling Smørgrav if (compat20) { 3591ec0d754SDag-Erling Smørgrav if (!do_pam_account()) 3601ec0d754SDag-Erling Smørgrav goto auth_fail; 3615962c0e9SDag-Erling Smørgrav if (sshpam_authctxt->force_pwchange) { 3621ec0d754SDag-Erling Smørgrav sshpam_err = pam_chauthtok(sshpam_handle, 3631ec0d754SDag-Erling Smørgrav PAM_CHANGE_EXPIRED_AUTHTOK); 3641ec0d754SDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) 3651ec0d754SDag-Erling Smørgrav goto auth_fail; 3661ec0d754SDag-Erling Smørgrav pam_password_change_required(0); 3671ec0d754SDag-Erling Smørgrav } 3681ec0d754SDag-Erling Smørgrav } 3691ec0d754SDag-Erling Smørgrav 370cf2b5f3bSDag-Erling Smørgrav buffer_put_cstring(&buffer, "OK"); 3711ec0d754SDag-Erling Smørgrav 3721ec0d754SDag-Erling Smørgrav #ifndef USE_POSIX_THREADS 3731ec0d754SDag-Erling Smørgrav /* Export variables set by do_pam_account */ 3741ec0d754SDag-Erling Smørgrav buffer_put_int(&buffer, sshpam_account_status); 3755962c0e9SDag-Erling Smørgrav buffer_put_int(&buffer, sshpam_authctxt->force_pwchange); 3761ec0d754SDag-Erling Smørgrav 3771ec0d754SDag-Erling Smørgrav /* Export any environment strings set in child */ 3781ec0d754SDag-Erling Smørgrav for(i = 0; environ[i] != NULL; i++) 3791ec0d754SDag-Erling Smørgrav ; /* Count */ 3801ec0d754SDag-Erling Smørgrav buffer_put_int(&buffer, i); 3811ec0d754SDag-Erling Smørgrav for(i = 0; environ[i] != NULL; i++) 3821ec0d754SDag-Erling Smørgrav buffer_put_cstring(&buffer, environ[i]); 3831ec0d754SDag-Erling Smørgrav 3841ec0d754SDag-Erling Smørgrav /* Export any environment strings set by PAM in child */ 3851ec0d754SDag-Erling Smørgrav env_from_pam = pam_getenvlist(sshpam_handle); 3861ec0d754SDag-Erling Smørgrav for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++) 3871ec0d754SDag-Erling Smørgrav ; /* Count */ 3881ec0d754SDag-Erling Smørgrav buffer_put_int(&buffer, i); 3891ec0d754SDag-Erling Smørgrav for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++) 3901ec0d754SDag-Erling Smørgrav buffer_put_cstring(&buffer, env_from_pam[i]); 3911ec0d754SDag-Erling Smørgrav #endif /* USE_POSIX_THREADS */ 3921ec0d754SDag-Erling Smørgrav 3931ec0d754SDag-Erling Smørgrav /* XXX - can't do much about an error here */ 394cf2b5f3bSDag-Erling Smørgrav ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer); 395cf2b5f3bSDag-Erling Smørgrav buffer_free(&buffer); 396cf2b5f3bSDag-Erling Smørgrav pthread_exit(NULL); 397cf2b5f3bSDag-Erling Smørgrav 398cf2b5f3bSDag-Erling Smørgrav auth_fail: 399cf2b5f3bSDag-Erling Smørgrav buffer_put_cstring(&buffer, 400cf2b5f3bSDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 4011ec0d754SDag-Erling Smørgrav /* XXX - can't do much about an error here */ 402cf2b5f3bSDag-Erling Smørgrav ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer); 403cf2b5f3bSDag-Erling Smørgrav buffer_free(&buffer); 404cf2b5f3bSDag-Erling Smørgrav pthread_exit(NULL); 405cf2b5f3bSDag-Erling Smørgrav 406cf2b5f3bSDag-Erling Smørgrav return (NULL); /* Avoid warning for non-pthread case */ 407cf2b5f3bSDag-Erling Smørgrav } 408cf2b5f3bSDag-Erling Smørgrav 4091ec0d754SDag-Erling Smørgrav void 4101ec0d754SDag-Erling Smørgrav sshpam_thread_cleanup(void) 411cf2b5f3bSDag-Erling Smørgrav { 4121ec0d754SDag-Erling Smørgrav struct pam_ctxt *ctxt = cleanup_ctxt; 413cf2b5f3bSDag-Erling Smørgrav 4141ec0d754SDag-Erling Smørgrav debug3("PAM: %s entering", __func__); 4151ec0d754SDag-Erling Smørgrav if (ctxt != NULL && ctxt->pam_thread != 0) { 416cf2b5f3bSDag-Erling Smørgrav pthread_cancel(ctxt->pam_thread); 417cf2b5f3bSDag-Erling Smørgrav pthread_join(ctxt->pam_thread, NULL); 418cf2b5f3bSDag-Erling Smørgrav close(ctxt->pam_psock); 419cf2b5f3bSDag-Erling Smørgrav close(ctxt->pam_csock); 4201ec0d754SDag-Erling Smørgrav memset(ctxt, 0, sizeof(*ctxt)); 4211ec0d754SDag-Erling Smørgrav cleanup_ctxt = NULL; 4221ec0d754SDag-Erling Smørgrav } 423cf2b5f3bSDag-Erling Smørgrav } 424cf2b5f3bSDag-Erling Smørgrav 425cf2b5f3bSDag-Erling Smørgrav static int 426cf2b5f3bSDag-Erling Smørgrav sshpam_null_conv(int n, const struct pam_message **msg, 427cf2b5f3bSDag-Erling Smørgrav struct pam_response **resp, void *data) 428cf2b5f3bSDag-Erling Smørgrav { 4291ec0d754SDag-Erling Smørgrav debug3("PAM: %s entering, %d messages", __func__, n); 430cf2b5f3bSDag-Erling Smørgrav return (PAM_CONV_ERR); 431cf2b5f3bSDag-Erling Smørgrav } 432cf2b5f3bSDag-Erling Smørgrav 433cf2b5f3bSDag-Erling Smørgrav static struct pam_conv null_conv = { sshpam_null_conv, NULL }; 434cf2b5f3bSDag-Erling Smørgrav 4351ec0d754SDag-Erling Smørgrav void 4361ec0d754SDag-Erling Smørgrav sshpam_cleanup(void) 437cf2b5f3bSDag-Erling Smørgrav { 438cf2b5f3bSDag-Erling Smørgrav debug("PAM: cleanup"); 439cf2b5f3bSDag-Erling Smørgrav if (sshpam_handle == NULL) 440cf2b5f3bSDag-Erling Smørgrav return; 441cf2b5f3bSDag-Erling Smørgrav pam_set_item(sshpam_handle, PAM_CONV, (const void *)&null_conv); 442cf2b5f3bSDag-Erling Smørgrav if (sshpam_cred_established) { 443cf2b5f3bSDag-Erling Smørgrav pam_setcred(sshpam_handle, PAM_DELETE_CRED); 444cf2b5f3bSDag-Erling Smørgrav sshpam_cred_established = 0; 445cf2b5f3bSDag-Erling Smørgrav } 446cf2b5f3bSDag-Erling Smørgrav if (sshpam_session_open) { 447cf2b5f3bSDag-Erling Smørgrav pam_close_session(sshpam_handle, PAM_SILENT); 448cf2b5f3bSDag-Erling Smørgrav sshpam_session_open = 0; 449cf2b5f3bSDag-Erling Smørgrav } 4501ec0d754SDag-Erling Smørgrav sshpam_authenticated = 0; 451cf2b5f3bSDag-Erling Smørgrav pam_end(sshpam_handle, sshpam_err); 452cf2b5f3bSDag-Erling Smørgrav sshpam_handle = NULL; 453cf2b5f3bSDag-Erling Smørgrav } 454cf2b5f3bSDag-Erling Smørgrav 455cf2b5f3bSDag-Erling Smørgrav static int 4565962c0e9SDag-Erling Smørgrav sshpam_init(Authctxt *authctxt) 457cf2b5f3bSDag-Erling Smørgrav { 458cf2b5f3bSDag-Erling Smørgrav extern char *__progname; 4595962c0e9SDag-Erling Smørgrav const char *pam_rhost, *pam_user, *user = authctxt->user; 460cf2b5f3bSDag-Erling Smørgrav 461cf2b5f3bSDag-Erling Smørgrav if (sshpam_handle != NULL) { 462cf2b5f3bSDag-Erling Smørgrav /* We already have a PAM context; check if the user matches */ 463cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_get_item(sshpam_handle, 464cf2b5f3bSDag-Erling Smørgrav PAM_USER, (const void **)&pam_user); 465cf2b5f3bSDag-Erling Smørgrav if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0) 466cf2b5f3bSDag-Erling Smørgrav return (0); 467cf2b5f3bSDag-Erling Smørgrav pam_end(sshpam_handle, sshpam_err); 468cf2b5f3bSDag-Erling Smørgrav sshpam_handle = NULL; 469cf2b5f3bSDag-Erling Smørgrav } 470cf2b5f3bSDag-Erling Smørgrav debug("PAM: initializing for \"%s\"", user); 471cf2b5f3bSDag-Erling Smørgrav sshpam_err = 472cf2b5f3bSDag-Erling Smørgrav pam_start(SSHD_PAM_SERVICE, user, &null_conv, &sshpam_handle); 4735962c0e9SDag-Erling Smørgrav sshpam_authctxt = authctxt; 4745962c0e9SDag-Erling Smørgrav 475cf2b5f3bSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) { 476cf2b5f3bSDag-Erling Smørgrav pam_end(sshpam_handle, sshpam_err); 477cf2b5f3bSDag-Erling Smørgrav sshpam_handle = NULL; 478cf2b5f3bSDag-Erling Smørgrav return (-1); 479cf2b5f3bSDag-Erling Smørgrav } 480cf2b5f3bSDag-Erling Smørgrav pam_rhost = get_remote_name_or_ip(utmp_len, options.use_dns); 481cf2b5f3bSDag-Erling Smørgrav debug("PAM: setting PAM_RHOST to \"%s\"", pam_rhost); 482cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST, pam_rhost); 483cf2b5f3bSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) { 484cf2b5f3bSDag-Erling Smørgrav pam_end(sshpam_handle, sshpam_err); 485cf2b5f3bSDag-Erling Smørgrav sshpam_handle = NULL; 486cf2b5f3bSDag-Erling Smørgrav return (-1); 487cf2b5f3bSDag-Erling Smørgrav } 488cf2b5f3bSDag-Erling Smørgrav #ifdef PAM_TTY_KLUDGE 489cf2b5f3bSDag-Erling Smørgrav /* 490cf2b5f3bSDag-Erling Smørgrav * Some silly PAM modules (e.g. pam_time) require a TTY to operate. 491cf2b5f3bSDag-Erling Smørgrav * sshd doesn't set the tty until too late in the auth process and 492cf2b5f3bSDag-Erling Smørgrav * may not even set one (for tty-less connections) 493cf2b5f3bSDag-Erling Smørgrav */ 494cf2b5f3bSDag-Erling Smørgrav debug("PAM: setting PAM_TTY to \"ssh\""); 495cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, "ssh"); 496cf2b5f3bSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) { 497cf2b5f3bSDag-Erling Smørgrav pam_end(sshpam_handle, sshpam_err); 498cf2b5f3bSDag-Erling Smørgrav sshpam_handle = NULL; 499cf2b5f3bSDag-Erling Smørgrav return (-1); 500cf2b5f3bSDag-Erling Smørgrav } 501cf2b5f3bSDag-Erling Smørgrav #endif 502cf2b5f3bSDag-Erling Smørgrav return (0); 503cf2b5f3bSDag-Erling Smørgrav } 504cf2b5f3bSDag-Erling Smørgrav 505cf2b5f3bSDag-Erling Smørgrav static void * 506cf2b5f3bSDag-Erling Smørgrav sshpam_init_ctx(Authctxt *authctxt) 507cf2b5f3bSDag-Erling Smørgrav { 508cf2b5f3bSDag-Erling Smørgrav struct pam_ctxt *ctxt; 509cf2b5f3bSDag-Erling Smørgrav int socks[2]; 510cf2b5f3bSDag-Erling Smørgrav 5111ec0d754SDag-Erling Smørgrav debug3("PAM: %s entering", __func__); 512cf2b5f3bSDag-Erling Smørgrav /* Refuse to start if we don't have PAM enabled */ 513cf2b5f3bSDag-Erling Smørgrav if (!options.use_pam) 514cf2b5f3bSDag-Erling Smørgrav return NULL; 515cf2b5f3bSDag-Erling Smørgrav 516cf2b5f3bSDag-Erling Smørgrav /* Initialize PAM */ 5175962c0e9SDag-Erling Smørgrav if (sshpam_init(authctxt) == -1) { 518cf2b5f3bSDag-Erling Smørgrav error("PAM: initialization failed"); 519cf2b5f3bSDag-Erling Smørgrav return (NULL); 520cf2b5f3bSDag-Erling Smørgrav } 521cf2b5f3bSDag-Erling Smørgrav 522cf2b5f3bSDag-Erling Smørgrav ctxt = xmalloc(sizeof *ctxt); 5231ec0d754SDag-Erling Smørgrav memset(ctxt, 0, sizeof(*ctxt)); 5241ec0d754SDag-Erling Smørgrav 525cf2b5f3bSDag-Erling Smørgrav /* Start the authentication thread */ 526cf2b5f3bSDag-Erling Smørgrav if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) { 527cf2b5f3bSDag-Erling Smørgrav error("PAM: failed create sockets: %s", strerror(errno)); 528cf2b5f3bSDag-Erling Smørgrav xfree(ctxt); 529cf2b5f3bSDag-Erling Smørgrav return (NULL); 530cf2b5f3bSDag-Erling Smørgrav } 531cf2b5f3bSDag-Erling Smørgrav ctxt->pam_psock = socks[0]; 532cf2b5f3bSDag-Erling Smørgrav ctxt->pam_csock = socks[1]; 533cf2b5f3bSDag-Erling Smørgrav if (pthread_create(&ctxt->pam_thread, NULL, sshpam_thread, ctxt) == -1) { 534cf2b5f3bSDag-Erling Smørgrav error("PAM: failed to start authentication thread: %s", 535cf2b5f3bSDag-Erling Smørgrav strerror(errno)); 536cf2b5f3bSDag-Erling Smørgrav close(socks[0]); 537cf2b5f3bSDag-Erling Smørgrav close(socks[1]); 538cf2b5f3bSDag-Erling Smørgrav xfree(ctxt); 539cf2b5f3bSDag-Erling Smørgrav return (NULL); 540cf2b5f3bSDag-Erling Smørgrav } 5411ec0d754SDag-Erling Smørgrav cleanup_ctxt = ctxt; 542cf2b5f3bSDag-Erling Smørgrav return (ctxt); 543cf2b5f3bSDag-Erling Smørgrav } 544cf2b5f3bSDag-Erling Smørgrav 545cf2b5f3bSDag-Erling Smørgrav static int 546cf2b5f3bSDag-Erling Smørgrav sshpam_query(void *ctx, char **name, char **info, 547cf2b5f3bSDag-Erling Smørgrav u_int *num, char ***prompts, u_int **echo_on) 548cf2b5f3bSDag-Erling Smørgrav { 549cf2b5f3bSDag-Erling Smørgrav Buffer buffer; 550cf2b5f3bSDag-Erling Smørgrav struct pam_ctxt *ctxt = ctx; 551cf2b5f3bSDag-Erling Smørgrav size_t plen; 552cf2b5f3bSDag-Erling Smørgrav u_char type; 553cf2b5f3bSDag-Erling Smørgrav char *msg; 554cf2b5f3bSDag-Erling Smørgrav size_t len; 555cf2b5f3bSDag-Erling Smørgrav 5561ec0d754SDag-Erling Smørgrav debug3("PAM: %s entering", __func__); 557cf2b5f3bSDag-Erling Smørgrav buffer_init(&buffer); 558cf2b5f3bSDag-Erling Smørgrav *name = xstrdup(""); 559cf2b5f3bSDag-Erling Smørgrav *info = xstrdup(""); 560cf2b5f3bSDag-Erling Smørgrav *prompts = xmalloc(sizeof(char *)); 561cf2b5f3bSDag-Erling Smørgrav **prompts = NULL; 562cf2b5f3bSDag-Erling Smørgrav plen = 0; 563cf2b5f3bSDag-Erling Smørgrav *echo_on = xmalloc(sizeof(u_int)); 564cf2b5f3bSDag-Erling Smørgrav while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) { 565cf2b5f3bSDag-Erling Smørgrav type = buffer_get_char(&buffer); 566cf2b5f3bSDag-Erling Smørgrav msg = buffer_get_string(&buffer, NULL); 567cf2b5f3bSDag-Erling Smørgrav switch (type) { 568cf2b5f3bSDag-Erling Smørgrav case PAM_PROMPT_ECHO_ON: 569cf2b5f3bSDag-Erling Smørgrav case PAM_PROMPT_ECHO_OFF: 570cf2b5f3bSDag-Erling Smørgrav *num = 1; 571cf2b5f3bSDag-Erling Smørgrav len = plen + strlen(msg) + 1; 572cf2b5f3bSDag-Erling Smørgrav **prompts = xrealloc(**prompts, len); 573cf2b5f3bSDag-Erling Smørgrav plen += snprintf(**prompts + plen, len, "%s", msg); 574cf2b5f3bSDag-Erling Smørgrav **echo_on = (type == PAM_PROMPT_ECHO_ON); 575cf2b5f3bSDag-Erling Smørgrav xfree(msg); 576cf2b5f3bSDag-Erling Smørgrav return (0); 577cf2b5f3bSDag-Erling Smørgrav case PAM_ERROR_MSG: 578cf2b5f3bSDag-Erling Smørgrav case PAM_TEXT_INFO: 579cf2b5f3bSDag-Erling Smørgrav /* accumulate messages */ 5801ec0d754SDag-Erling Smørgrav len = plen + strlen(msg) + 2; 581cf2b5f3bSDag-Erling Smørgrav **prompts = xrealloc(**prompts, len); 5821ec0d754SDag-Erling Smørgrav plen += snprintf(**prompts + plen, len, "%s\n", msg); 583cf2b5f3bSDag-Erling Smørgrav xfree(msg); 584cf2b5f3bSDag-Erling Smørgrav break; 585cf2b5f3bSDag-Erling Smørgrav case PAM_SUCCESS: 586cf2b5f3bSDag-Erling Smørgrav case PAM_AUTH_ERR: 587cf2b5f3bSDag-Erling Smørgrav if (**prompts != NULL) { 588cf2b5f3bSDag-Erling Smørgrav /* drain any accumulated messages */ 5891ec0d754SDag-Erling Smørgrav debug("PAM: %s", **prompts); 5901ec0d754SDag-Erling Smørgrav buffer_append(&loginmsg, **prompts, 5911ec0d754SDag-Erling Smørgrav strlen(**prompts)); 592cf2b5f3bSDag-Erling Smørgrav xfree(**prompts); 593cf2b5f3bSDag-Erling Smørgrav **prompts = NULL; 594cf2b5f3bSDag-Erling Smørgrav } 595cf2b5f3bSDag-Erling Smørgrav if (type == PAM_SUCCESS) { 5961ec0d754SDag-Erling Smørgrav import_environments(&buffer); 597cf2b5f3bSDag-Erling Smørgrav *num = 0; 598cf2b5f3bSDag-Erling Smørgrav **echo_on = 0; 599cf2b5f3bSDag-Erling Smørgrav ctxt->pam_done = 1; 600cf2b5f3bSDag-Erling Smørgrav xfree(msg); 601cf2b5f3bSDag-Erling Smørgrav return (0); 602cf2b5f3bSDag-Erling Smørgrav } 6035962c0e9SDag-Erling Smørgrav error("PAM: %s for %s%.100s from %.100s", msg, 6045962c0e9SDag-Erling Smørgrav sshpam_authctxt->valid ? "" : "illegal user ", 6055962c0e9SDag-Erling Smørgrav sshpam_authctxt->user, 6065962c0e9SDag-Erling Smørgrav get_remote_name_or_ip(utmp_len, options.use_dns)); 6071ec0d754SDag-Erling Smørgrav /* FALLTHROUGH */ 608cf2b5f3bSDag-Erling Smørgrav default: 609cf2b5f3bSDag-Erling Smørgrav *num = 0; 610cf2b5f3bSDag-Erling Smørgrav **echo_on = 0; 611cf2b5f3bSDag-Erling Smørgrav xfree(msg); 612cf2b5f3bSDag-Erling Smørgrav ctxt->pam_done = -1; 613cf2b5f3bSDag-Erling Smørgrav return (-1); 614cf2b5f3bSDag-Erling Smørgrav } 615cf2b5f3bSDag-Erling Smørgrav } 616cf2b5f3bSDag-Erling Smørgrav return (-1); 617cf2b5f3bSDag-Erling Smørgrav } 618cf2b5f3bSDag-Erling Smørgrav 619cf2b5f3bSDag-Erling Smørgrav /* XXX - see also comment in auth-chall.c:verify_response */ 620cf2b5f3bSDag-Erling Smørgrav static int 621cf2b5f3bSDag-Erling Smørgrav sshpam_respond(void *ctx, u_int num, char **resp) 622cf2b5f3bSDag-Erling Smørgrav { 623cf2b5f3bSDag-Erling Smørgrav Buffer buffer; 624cf2b5f3bSDag-Erling Smørgrav struct pam_ctxt *ctxt = ctx; 625cf2b5f3bSDag-Erling Smørgrav 6261ec0d754SDag-Erling Smørgrav debug2("PAM: %s entering, %d responses", __func__, num); 627cf2b5f3bSDag-Erling Smørgrav switch (ctxt->pam_done) { 628cf2b5f3bSDag-Erling Smørgrav case 1: 629cf2b5f3bSDag-Erling Smørgrav sshpam_authenticated = 1; 630cf2b5f3bSDag-Erling Smørgrav return (0); 631cf2b5f3bSDag-Erling Smørgrav case 0: 632cf2b5f3bSDag-Erling Smørgrav break; 633cf2b5f3bSDag-Erling Smørgrav default: 634cf2b5f3bSDag-Erling Smørgrav return (-1); 635cf2b5f3bSDag-Erling Smørgrav } 636cf2b5f3bSDag-Erling Smørgrav if (num != 1) { 637cf2b5f3bSDag-Erling Smørgrav error("PAM: expected one response, got %u", num); 638cf2b5f3bSDag-Erling Smørgrav return (-1); 639cf2b5f3bSDag-Erling Smørgrav } 640cf2b5f3bSDag-Erling Smørgrav buffer_init(&buffer); 641cf2b5f3bSDag-Erling Smørgrav buffer_put_cstring(&buffer, *resp); 6421ec0d754SDag-Erling Smørgrav if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) { 6431ec0d754SDag-Erling Smørgrav buffer_free(&buffer); 6441ec0d754SDag-Erling Smørgrav return (-1); 6451ec0d754SDag-Erling Smørgrav } 646cf2b5f3bSDag-Erling Smørgrav buffer_free(&buffer); 647cf2b5f3bSDag-Erling Smørgrav return (1); 648cf2b5f3bSDag-Erling Smørgrav } 649cf2b5f3bSDag-Erling Smørgrav 650cf2b5f3bSDag-Erling Smørgrav static void 651cf2b5f3bSDag-Erling Smørgrav sshpam_free_ctx(void *ctxtp) 652cf2b5f3bSDag-Erling Smørgrav { 653cf2b5f3bSDag-Erling Smørgrav struct pam_ctxt *ctxt = ctxtp; 654cf2b5f3bSDag-Erling Smørgrav 6551ec0d754SDag-Erling Smørgrav debug3("PAM: %s entering", __func__); 6561ec0d754SDag-Erling Smørgrav sshpam_thread_cleanup(); 657cf2b5f3bSDag-Erling Smørgrav xfree(ctxt); 658cf2b5f3bSDag-Erling Smørgrav /* 659cf2b5f3bSDag-Erling Smørgrav * We don't call sshpam_cleanup() here because we may need the PAM 660cf2b5f3bSDag-Erling Smørgrav * handle at a later stage, e.g. when setting up a session. It's 661cf2b5f3bSDag-Erling Smørgrav * still on the cleanup list, so pam_end() *will* be called before 662cf2b5f3bSDag-Erling Smørgrav * the server process terminates. 663cf2b5f3bSDag-Erling Smørgrav */ 664cf2b5f3bSDag-Erling Smørgrav } 665cf2b5f3bSDag-Erling Smørgrav 666cf2b5f3bSDag-Erling Smørgrav KbdintDevice sshpam_device = { 667cf2b5f3bSDag-Erling Smørgrav "pam", 668cf2b5f3bSDag-Erling Smørgrav sshpam_init_ctx, 669cf2b5f3bSDag-Erling Smørgrav sshpam_query, 670cf2b5f3bSDag-Erling Smørgrav sshpam_respond, 671cf2b5f3bSDag-Erling Smørgrav sshpam_free_ctx 672cf2b5f3bSDag-Erling Smørgrav }; 673cf2b5f3bSDag-Erling Smørgrav 674cf2b5f3bSDag-Erling Smørgrav KbdintDevice mm_sshpam_device = { 675cf2b5f3bSDag-Erling Smørgrav "pam", 676cf2b5f3bSDag-Erling Smørgrav mm_sshpam_init_ctx, 677cf2b5f3bSDag-Erling Smørgrav mm_sshpam_query, 678cf2b5f3bSDag-Erling Smørgrav mm_sshpam_respond, 679cf2b5f3bSDag-Erling Smørgrav mm_sshpam_free_ctx 680cf2b5f3bSDag-Erling Smørgrav }; 681cf2b5f3bSDag-Erling Smørgrav 682cf2b5f3bSDag-Erling Smørgrav /* 683cf2b5f3bSDag-Erling Smørgrav * This replaces auth-pam.c 684cf2b5f3bSDag-Erling Smørgrav */ 685cf2b5f3bSDag-Erling Smørgrav void 6865962c0e9SDag-Erling Smørgrav start_pam(Authctxt *authctxt) 687cf2b5f3bSDag-Erling Smørgrav { 688cf2b5f3bSDag-Erling Smørgrav if (!options.use_pam) 689cf2b5f3bSDag-Erling Smørgrav fatal("PAM: initialisation requested when UsePAM=no"); 690cf2b5f3bSDag-Erling Smørgrav 6915962c0e9SDag-Erling Smørgrav if (sshpam_init(authctxt) == -1) 692cf2b5f3bSDag-Erling Smørgrav fatal("PAM: initialisation failed"); 693cf2b5f3bSDag-Erling Smørgrav } 694cf2b5f3bSDag-Erling Smørgrav 695cf2b5f3bSDag-Erling Smørgrav void 696cf2b5f3bSDag-Erling Smørgrav finish_pam(void) 697cf2b5f3bSDag-Erling Smørgrav { 6981ec0d754SDag-Erling Smørgrav sshpam_cleanup(); 699cf2b5f3bSDag-Erling Smørgrav } 700cf2b5f3bSDag-Erling Smørgrav 701cf2b5f3bSDag-Erling Smørgrav u_int 702cf2b5f3bSDag-Erling Smørgrav do_pam_account(void) 703cf2b5f3bSDag-Erling Smørgrav { 7041ec0d754SDag-Erling Smørgrav if (sshpam_account_status != -1) 7051ec0d754SDag-Erling Smørgrav return (sshpam_account_status); 7061ec0d754SDag-Erling Smørgrav 707cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_acct_mgmt(sshpam_handle, 0); 7081ec0d754SDag-Erling Smørgrav debug3("PAM: %s pam_acct_mgmt = %d", __func__, sshpam_err); 709cf2b5f3bSDag-Erling Smørgrav 7101ec0d754SDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) { 7111ec0d754SDag-Erling Smørgrav sshpam_account_status = 0; 7121ec0d754SDag-Erling Smørgrav return (sshpam_account_status); 71309958426SBrian Feldman } 71409958426SBrian Feldman 7151ec0d754SDag-Erling Smørgrav if (sshpam_err == PAM_NEW_AUTHTOK_REQD) 7161ec0d754SDag-Erling Smørgrav pam_password_change_required(1); 71709958426SBrian Feldman 7181ec0d754SDag-Erling Smørgrav sshpam_account_status = 1; 7191ec0d754SDag-Erling Smørgrav return (sshpam_account_status); 72009958426SBrian Feldman } 72109958426SBrian Feldman 722cf2b5f3bSDag-Erling Smørgrav void 723cf2b5f3bSDag-Erling Smørgrav do_pam_set_tty(const char *tty) 724cf2b5f3bSDag-Erling Smørgrav { 725cf2b5f3bSDag-Erling Smørgrav if (tty != NULL) { 726cf2b5f3bSDag-Erling Smørgrav debug("PAM: setting PAM_TTY to \"%s\"", tty); 727cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, tty); 728cf2b5f3bSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) 729cf2b5f3bSDag-Erling Smørgrav fatal("PAM: failed to set PAM_TTY: %s", 730cf2b5f3bSDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 731cf2b5f3bSDag-Erling Smørgrav } 73209958426SBrian Feldman } 73309958426SBrian Feldman 734cf2b5f3bSDag-Erling Smørgrav void 735cf2b5f3bSDag-Erling Smørgrav do_pam_setcred(int init) 73609958426SBrian Feldman { 737cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, 738cf2b5f3bSDag-Erling Smørgrav (const void *)&null_conv); 739cf2b5f3bSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) 740cf2b5f3bSDag-Erling Smørgrav fatal("PAM: failed to set PAM_CONV: %s", 741cf2b5f3bSDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 742cf2b5f3bSDag-Erling Smørgrav if (init) { 743cf2b5f3bSDag-Erling Smørgrav debug("PAM: establishing credentials"); 744cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_setcred(sshpam_handle, PAM_ESTABLISH_CRED); 745cf2b5f3bSDag-Erling Smørgrav } else { 746cf2b5f3bSDag-Erling Smørgrav debug("PAM: reinitializing credentials"); 747cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_setcred(sshpam_handle, PAM_REINITIALIZE_CRED); 748cf2b5f3bSDag-Erling Smørgrav } 749cf2b5f3bSDag-Erling Smørgrav if (sshpam_err == PAM_SUCCESS) { 750cf2b5f3bSDag-Erling Smørgrav sshpam_cred_established = 1; 751989dd127SDag-Erling Smørgrav return; 752cf2b5f3bSDag-Erling Smørgrav } 753cf2b5f3bSDag-Erling Smørgrav if (sshpam_authenticated) 754cf2b5f3bSDag-Erling Smørgrav fatal("PAM: pam_setcred(): %s", 755cf2b5f3bSDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 7562c917d39SAlfred Perlstein else 757cf2b5f3bSDag-Erling Smørgrav debug("PAM: pam_setcred(): %s", 758cf2b5f3bSDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 75909958426SBrian Feldman } 76009958426SBrian Feldman 761cf2b5f3bSDag-Erling Smørgrav static int 7621ec0d754SDag-Erling Smørgrav pam_tty_conv(int n, const struct pam_message **msg, 763cf2b5f3bSDag-Erling Smørgrav struct pam_response **resp, void *data) 76409958426SBrian Feldman { 765cf2b5f3bSDag-Erling Smørgrav char input[PAM_MAX_MSG_SIZE]; 766cf2b5f3bSDag-Erling Smørgrav struct pam_response *reply; 767f388f5efSDag-Erling Smørgrav int i; 768f388f5efSDag-Erling Smørgrav 7691ec0d754SDag-Erling Smørgrav debug3("PAM: %s called with %d messages", __func__, n); 7701ec0d754SDag-Erling Smørgrav 771cf2b5f3bSDag-Erling Smørgrav *resp = NULL; 772cf2b5f3bSDag-Erling Smørgrav 7731ec0d754SDag-Erling Smørgrav if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO)) 774cf2b5f3bSDag-Erling Smørgrav return (PAM_CONV_ERR); 775cf2b5f3bSDag-Erling Smørgrav 776cf2b5f3bSDag-Erling Smørgrav if ((reply = malloc(n * sizeof(*reply))) == NULL) 777cf2b5f3bSDag-Erling Smørgrav return (PAM_CONV_ERR); 778cf2b5f3bSDag-Erling Smørgrav memset(reply, 0, n * sizeof(*reply)); 779cf2b5f3bSDag-Erling Smørgrav 780cf2b5f3bSDag-Erling Smørgrav for (i = 0; i < n; ++i) { 781cf2b5f3bSDag-Erling Smørgrav switch (PAM_MSG_MEMBER(msg, i, msg_style)) { 782cf2b5f3bSDag-Erling Smørgrav case PAM_PROMPT_ECHO_OFF: 783cf2b5f3bSDag-Erling Smørgrav reply[i].resp = 784cf2b5f3bSDag-Erling Smørgrav read_passphrase(PAM_MSG_MEMBER(msg, i, msg), 785cf2b5f3bSDag-Erling Smørgrav RP_ALLOW_STDIN); 786cf2b5f3bSDag-Erling Smørgrav reply[i].resp_retcode = PAM_SUCCESS; 787cf2b5f3bSDag-Erling Smørgrav break; 788cf2b5f3bSDag-Erling Smørgrav case PAM_PROMPT_ECHO_ON: 7891ec0d754SDag-Erling Smørgrav fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg)); 790cf2b5f3bSDag-Erling Smørgrav fgets(input, sizeof input, stdin); 791cf2b5f3bSDag-Erling Smørgrav reply[i].resp = xstrdup(input); 792cf2b5f3bSDag-Erling Smørgrav reply[i].resp_retcode = PAM_SUCCESS; 793cf2b5f3bSDag-Erling Smørgrav break; 794cf2b5f3bSDag-Erling Smørgrav case PAM_ERROR_MSG: 795cf2b5f3bSDag-Erling Smørgrav case PAM_TEXT_INFO: 7961ec0d754SDag-Erling Smørgrav fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg)); 797cf2b5f3bSDag-Erling Smørgrav reply[i].resp_retcode = PAM_SUCCESS; 798cf2b5f3bSDag-Erling Smørgrav break; 799cf2b5f3bSDag-Erling Smørgrav default: 800cf2b5f3bSDag-Erling Smørgrav goto fail; 801f388f5efSDag-Erling Smørgrav } 802f388f5efSDag-Erling Smørgrav } 803cf2b5f3bSDag-Erling Smørgrav *resp = reply; 804cf2b5f3bSDag-Erling Smørgrav return (PAM_SUCCESS); 805cf2b5f3bSDag-Erling Smørgrav 806cf2b5f3bSDag-Erling Smørgrav fail: 807cf2b5f3bSDag-Erling Smørgrav for(i = 0; i < n; i++) { 808cf2b5f3bSDag-Erling Smørgrav if (reply[i].resp != NULL) 809cf2b5f3bSDag-Erling Smørgrav xfree(reply[i].resp); 810cf2b5f3bSDag-Erling Smørgrav } 811cf2b5f3bSDag-Erling Smørgrav xfree(reply); 812cf2b5f3bSDag-Erling Smørgrav return (PAM_CONV_ERR); 813cf2b5f3bSDag-Erling Smørgrav } 814f388f5efSDag-Erling Smørgrav 8151ec0d754SDag-Erling Smørgrav static struct pam_conv tty_conv = { pam_tty_conv, NULL }; 8161ec0d754SDag-Erling Smørgrav 817cf2b5f3bSDag-Erling Smørgrav /* 818cf2b5f3bSDag-Erling Smørgrav * XXX this should be done in the authentication phase, but ssh1 doesn't 819cf2b5f3bSDag-Erling Smørgrav * support that 820cf2b5f3bSDag-Erling Smørgrav */ 821cf2b5f3bSDag-Erling Smørgrav void 822cf2b5f3bSDag-Erling Smørgrav do_pam_chauthtok(void) 82309958426SBrian Feldman { 824cf2b5f3bSDag-Erling Smørgrav if (use_privsep) 825cf2b5f3bSDag-Erling Smørgrav fatal("Password expired (unable to change with privsep)"); 826cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, 8271ec0d754SDag-Erling Smørgrav (const void *)&tty_conv); 828cf2b5f3bSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) 829cf2b5f3bSDag-Erling Smørgrav fatal("PAM: failed to set PAM_CONV: %s", 830cf2b5f3bSDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 831cf2b5f3bSDag-Erling Smørgrav debug("PAM: changing password"); 832cf2b5f3bSDag-Erling Smørgrav sshpam_err = pam_chauthtok(sshpam_handle, PAM_CHANGE_EXPIRED_AUTHTOK); 833cf2b5f3bSDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) 834cf2b5f3bSDag-Erling Smørgrav fatal("PAM: pam_chauthtok(): %s", 835cf2b5f3bSDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 83609958426SBrian Feldman } 83709958426SBrian Feldman 8381ec0d754SDag-Erling Smørgrav static int 8391ec0d754SDag-Erling Smørgrav pam_store_conv(int n, const struct pam_message **msg, 8401ec0d754SDag-Erling Smørgrav struct pam_response **resp, void *data) 8411ec0d754SDag-Erling Smørgrav { 8421ec0d754SDag-Erling Smørgrav struct pam_response *reply; 8431ec0d754SDag-Erling Smørgrav int i; 8441ec0d754SDag-Erling Smørgrav size_t len; 8451ec0d754SDag-Erling Smørgrav 8461ec0d754SDag-Erling Smørgrav debug3("PAM: %s called with %d messages", __func__, n); 8471ec0d754SDag-Erling Smørgrav *resp = NULL; 8481ec0d754SDag-Erling Smørgrav 8491ec0d754SDag-Erling Smørgrav if (n <= 0 || n > PAM_MAX_NUM_MSG) 8501ec0d754SDag-Erling Smørgrav return (PAM_CONV_ERR); 8511ec0d754SDag-Erling Smørgrav 8521ec0d754SDag-Erling Smørgrav if ((reply = malloc(n * sizeof(*reply))) == NULL) 8531ec0d754SDag-Erling Smørgrav return (PAM_CONV_ERR); 8541ec0d754SDag-Erling Smørgrav memset(reply, 0, n * sizeof(*reply)); 8551ec0d754SDag-Erling Smørgrav 8561ec0d754SDag-Erling Smørgrav for (i = 0; i < n; ++i) { 8571ec0d754SDag-Erling Smørgrav switch (PAM_MSG_MEMBER(msg, i, msg_style)) { 8581ec0d754SDag-Erling Smørgrav case PAM_ERROR_MSG: 8591ec0d754SDag-Erling Smørgrav case PAM_TEXT_INFO: 8601ec0d754SDag-Erling Smørgrav len = strlen(PAM_MSG_MEMBER(msg, i, msg)); 8611ec0d754SDag-Erling Smørgrav buffer_append(&loginmsg, PAM_MSG_MEMBER(msg, i, msg), len); 8621ec0d754SDag-Erling Smørgrav buffer_append(&loginmsg, "\n", 1 ); 8631ec0d754SDag-Erling Smørgrav reply[i].resp_retcode = PAM_SUCCESS; 8641ec0d754SDag-Erling Smørgrav break; 8651ec0d754SDag-Erling Smørgrav default: 8661ec0d754SDag-Erling Smørgrav goto fail; 8671ec0d754SDag-Erling Smørgrav } 8681ec0d754SDag-Erling Smørgrav } 8691ec0d754SDag-Erling Smørgrav *resp = reply; 8701ec0d754SDag-Erling Smørgrav return (PAM_SUCCESS); 8711ec0d754SDag-Erling Smørgrav 8721ec0d754SDag-Erling Smørgrav fail: 8731ec0d754SDag-Erling Smørgrav for(i = 0; i < n; i++) { 8741ec0d754SDag-Erling Smørgrav if (reply[i].resp != NULL) 8751ec0d754SDag-Erling Smørgrav xfree(reply[i].resp); 8761ec0d754SDag-Erling Smørgrav } 8771ec0d754SDag-Erling Smørgrav xfree(reply); 8781ec0d754SDag-Erling Smørgrav return (PAM_CONV_ERR); 8791ec0d754SDag-Erling Smørgrav } 8801ec0d754SDag-Erling Smørgrav 8811ec0d754SDag-Erling Smørgrav static struct pam_conv store_conv = { pam_store_conv, NULL }; 8821ec0d754SDag-Erling Smørgrav 8831ec0d754SDag-Erling Smørgrav void 8841ec0d754SDag-Erling Smørgrav do_pam_session(void) 8851ec0d754SDag-Erling Smørgrav { 8861ec0d754SDag-Erling Smørgrav debug3("PAM: opening session"); 8871ec0d754SDag-Erling Smørgrav sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, 8881ec0d754SDag-Erling Smørgrav (const void *)&store_conv); 8891ec0d754SDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) 8901ec0d754SDag-Erling Smørgrav fatal("PAM: failed to set PAM_CONV: %s", 8911ec0d754SDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 8921ec0d754SDag-Erling Smørgrav sshpam_err = pam_open_session(sshpam_handle, 0); 8931ec0d754SDag-Erling Smørgrav if (sshpam_err != PAM_SUCCESS) 8941ec0d754SDag-Erling Smørgrav fatal("PAM: pam_open_session(): %s", 8951ec0d754SDag-Erling Smørgrav pam_strerror(sshpam_handle, sshpam_err)); 8961ec0d754SDag-Erling Smørgrav sshpam_session_open = 1; 8971ec0d754SDag-Erling Smørgrav } 8981ec0d754SDag-Erling Smørgrav 899cf2b5f3bSDag-Erling Smørgrav /* 900cf2b5f3bSDag-Erling Smørgrav * Set a PAM environment string. We need to do this so that the session 901cf2b5f3bSDag-Erling Smørgrav * modules can handle things like Kerberos/GSI credentials that appear 902cf2b5f3bSDag-Erling Smørgrav * during the ssh authentication process. 903cf2b5f3bSDag-Erling Smørgrav */ 904cf2b5f3bSDag-Erling Smørgrav int 905cf2b5f3bSDag-Erling Smørgrav do_pam_putenv(char *name, char *value) 90609958426SBrian Feldman { 907cf2b5f3bSDag-Erling Smørgrav int ret = 1; 908cf2b5f3bSDag-Erling Smørgrav #ifdef HAVE_PAM_PUTENV 909cf2b5f3bSDag-Erling Smørgrav char *compound; 910cf2b5f3bSDag-Erling Smørgrav size_t len; 91109958426SBrian Feldman 912cf2b5f3bSDag-Erling Smørgrav len = strlen(name) + strlen(value) + 2; 913cf2b5f3bSDag-Erling Smørgrav compound = xmalloc(len); 91409958426SBrian Feldman 915cf2b5f3bSDag-Erling Smørgrav snprintf(compound, len, "%s=%s", name, value); 916cf2b5f3bSDag-Erling Smørgrav ret = pam_putenv(sshpam_handle, compound); 917cf2b5f3bSDag-Erling Smørgrav xfree(compound); 918cf2b5f3bSDag-Erling Smørgrav #endif 91909958426SBrian Feldman 920cf2b5f3bSDag-Erling Smørgrav return (ret); 921cf2b5f3bSDag-Erling Smørgrav } 92209958426SBrian Feldman 9231ec0d754SDag-Erling Smørgrav char ** 9241ec0d754SDag-Erling Smørgrav fetch_pam_child_environment(void) 925cf2b5f3bSDag-Erling Smørgrav { 9261ec0d754SDag-Erling Smørgrav return sshpam_env; 927cf2b5f3bSDag-Erling Smørgrav } 928cf2b5f3bSDag-Erling Smørgrav 929cf2b5f3bSDag-Erling Smørgrav char ** 930cf2b5f3bSDag-Erling Smørgrav fetch_pam_environment(void) 931cf2b5f3bSDag-Erling Smørgrav { 932cf2b5f3bSDag-Erling Smørgrav return (pam_getenvlist(sshpam_handle)); 933cf2b5f3bSDag-Erling Smørgrav } 934cf2b5f3bSDag-Erling Smørgrav 935cf2b5f3bSDag-Erling Smørgrav void 936cf2b5f3bSDag-Erling Smørgrav free_pam_environment(char **env) 937cf2b5f3bSDag-Erling Smørgrav { 938cf2b5f3bSDag-Erling Smørgrav char **envp; 939cf2b5f3bSDag-Erling Smørgrav 940cf2b5f3bSDag-Erling Smørgrav if (env == NULL) 941cf2b5f3bSDag-Erling Smørgrav return; 942cf2b5f3bSDag-Erling Smørgrav 943cf2b5f3bSDag-Erling Smørgrav for (envp = env; *envp; envp++) 944cf2b5f3bSDag-Erling Smørgrav xfree(*envp); 945cf2b5f3bSDag-Erling Smørgrav xfree(env); 94609958426SBrian Feldman } 94709958426SBrian Feldman 94809958426SBrian Feldman #endif /* USE_PAM */ 949