# HG changeset patch # User Matt Johnston # Date 1095167369 0 # Node ID cb7ef2f63bf05562eb3b7786d35da6e8e9cc08aa # Parent 18b261b1dea250dbc12b0905f009e63e47fa7a58# Parent 9337c9f9a607ed51a74b73c6ee678f6a8437c54e propagate of f51a272341ee12268fe7028bc2f2bad66c603069 and ab35ee4292ea910d4871c3609d6100fe34300720 from branch 'matt.dbclient.rez' to 'matt.dbclient.work' diff -r 18b261b1dea2 -r cb7ef2f63bf0 Makefile.in --- a/Makefile.in Sun Sep 12 05:53:48 2004 +0000 +++ b/Makefile.in Tue Sep 14 13:09:29 2004 +0000 @@ -24,7 +24,7 @@ SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \ svr-authpasswd.o svr-authpubkey.o svr-session.o svr-service.o \ svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\ - svr-tcpfwd.o + svr-tcpfwd.o svr-authpam.o CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \ cli-session.o cli-service.o cli-runopts.o cli-chansession.o \ diff -r 18b261b1dea2 -r cb7ef2f63bf0 auth.h --- a/auth.h Sun Sep 12 05:53:48 2004 +0000 +++ b/auth.h Tue Sep 14 13:09:29 2004 +0000 @@ -36,6 +36,7 @@ void send_msg_userauth_success(); void svr_auth_password(); void svr_auth_pubkey(); +void svr_auth_pam(); /* Client functions */ void recv_msg_userauth_failure(); diff -r 18b261b1dea2 -r cb7ef2f63bf0 configure.in --- a/configure.in Sun Sep 12 05:53:48 2004 +0000 +++ b/configure.in Tue Sep 14 13:09:29 2004 +0000 @@ -117,6 +117,43 @@ ] ) +# Check if pam is needed +AC_ARG_WITH(pam, + [ --with-pam=PATH Use pam in PATH], + [ + # option is given + if test -d "$withval/lib"; then + LDFLAGS="-L${withval}/lib ${LDFLAGS}" + else + LDFLAGS="-L${withval} ${LDFLAGS}" + fi + if test -d "$withval/include"; then + CPPFLAGS="-I${withval}/include ${CPPFLAGS}" + else + CPPFLAGS="-I${withval} ${CPPFLAGS}" + fi + ] +) + + +AC_ARG_ENABLE(pam, + [ --enable-pam Try to include PAM support], + [ + if test "x$enableval" = "xyes"; then + AC_CHECK_LIB(pam, pam_authenticate, , AC_MSG_ERROR([*** PAM missing - install first or check config.log ***])) + AC_MSG_RESULT(Enabling PAM) + else + AC_DEFINE(DISABLE_PAM,, Use PAM) + AC_MSG_RESULT(Disabling PAM) + fi + ], + [ + # disable it by default + AC_DEFINE(DISABLE_PAM,, Use PAM) + AC_MSG_RESULT(Disabling PAM) + ] +) + AC_ARG_ENABLE(openpty, [ --disable-openpty Don't use openpty, use alternative method], [ @@ -169,7 +206,7 @@ # Checks for header files. AC_HEADER_STDC AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h]) +AC_CHECK_HEADERS([fcntl.h limits.h netinet/in.h netinet/tcp.h stdlib.h string.h sys/socket.h sys/time.h termios.h unistd.h crypt.h pty.h ioctl.h libutil.h libgen.h inttypes.h stropts.h utmp.h utmpx.h lastlog.h paths.h util.h netdb.h security/pam_appl.h pam/pam_appl.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST diff -r 18b261b1dea2 -r cb7ef2f63bf0 options.h --- a/options.h Sun Sep 12 05:53:48 2004 +0000 +++ b/options.h Tue Sep 14 13:09:29 2004 +0000 @@ -110,9 +110,19 @@ #define MOTD_FILENAME "/etc/motd" #endif -/* Authentication types to enable, at least one required. +/* Authentication Types - at least one required. RFC Draft requires pubkey auth, and recommends password */ -#define ENABLE_SVR_PASSWORD_AUTH + +/* PAM auth is quite simple, and only works for PAM modules which just do a + * simple "Login: " "Password: " (or something like that - if your module is + * similar but not quite like that, edit the strings in svr-authpam.c). + * Basically, it's useful for systems like OS X where standard password crypts + * don't work, but there's and interface via a PAM module. You'll need to + * configure with --enable-pam as well, since it's off by default. And you + * should only enable either PASSWORD _or_ PAM auth, not both. */ + +/*#define ENABLE_SVR_PASSWORD_AUTH*/ +#define ENABLE_SVR_PAM_AUTH #define ENABLE_SVR_PUBKEY_AUTH #define ENABLE_CLI_PASSWORD_AUTH @@ -173,7 +183,7 @@ *******************************************************************/ #ifndef DROPBEAR_VERSION -#define DROPBEAR_VERSION "0.44test3" +#define DROPBEAR_VERSION "0.44rez1" #endif #define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION @@ -322,6 +332,10 @@ #define DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */ #endif +#if defined(ENABLE_SVR_PASSWORD_AUTH) && defined(ENABLE_SVR_PAM_AUTH) +#error "You can't turn on PASSWORD and PAM auth both at once. Fix it in options.h" +#endif + /* We use dropbear_client and dropbear_server as shortcuts to avoid redundant * code, if we're just compiling as client or server */ #if defined(DROPBEAR_SERVER) && defined(DROPBEAR_CLIENT) diff -r 18b261b1dea2 -r cb7ef2f63bf0 svr-auth.c --- a/svr-auth.c Sun Sep 12 05:53:48 2004 +0000 +++ b/svr-auth.c Tue Sep 14 13:09:29 2004 +0000 @@ -55,7 +55,7 @@ #ifdef ENABLE_SVR_PUBKEY_AUTH ses.authstate.authtypes |= AUTH_TYPE_PUBKEY; #endif -#ifdef ENABLE_SVR_PASSWORD_AUTH +#if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH) if (!svr_opts.noauthpass) { ses.authstate.authtypes |= AUTH_TYPE_PASSWORD; } @@ -154,6 +154,19 @@ } #endif +#ifdef ENABLE_SVR_PAM_AUTH + if (!svr_opts.noauthpass && + !(svr_opts.norootpass && ses.authstate.pw->pw_uid == 0) ) { + /* user wants to try password auth */ + if (methodlen == AUTH_METHOD_PASSWORD_LEN && + strncmp(methodname, AUTH_METHOD_PASSWORD, + AUTH_METHOD_PASSWORD_LEN) == 0) { + svr_auth_pam(); + goto out; + } + } +#endif + #ifdef ENABLE_SVR_PUBKEY_AUTH /* user wants to try pubkey auth */ if (methodlen == AUTH_METHOD_PUBKEY_LEN && diff -r 18b261b1dea2 -r cb7ef2f63bf0 svr-authpam.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/svr-authpam.c Tue Sep 14 13:09:29 2004 +0000 @@ -0,0 +1,219 @@ +/* + * Dropbear SSH + * + * Copyright (c) 2004 Martin Carlsson + * Portions (c) 2004 Matt Johnston + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ + +/* Validates a user password using PAM */ + +#include "includes.h" +#include "session.h" +#include "buffer.h" +#include "dbutil.h" +#include "auth.h" + +#if defined(HAVE_SECURITY_PAM_APPL_H) +#include +#elif defined (HAVE_PAM_PAM_APPL_H) +#include +#endif + +struct UserDataS { + char* user; + char* passwd; +}; + +/* PAM conversation function - for now we only handle one message */ +int +pamConvFunc(int num_msg, + const struct pam_message **msg, + struct pam_response **respp, + void *appdata_ptr) { + + int rc = PAM_SUCCESS; + struct pam_response* resp = NULL; + struct UserDataS* userDatap = (struct UserDataS*) appdata_ptr; + + const char* message = (*msg)->msg; + + TRACE(("enter pamConvFunc")); + + if (num_msg != 1) { + /* If you're getting here - Dropbear probably can't support your pam + * modules. This whole file is a bit of a hack around lack of + * asynchronocity in PAM anyway */ + dropbear_log(LOG_INFO, "pamConvFunc() called with >1 messages: not supported."); + return PAM_CONV_ERR; + } + + TRACE(("msg_style is %d", (*msg)->msg_style)); + if (message) { + TRACE(("message is '%s'", message)); + } else { + TRACE(("null message")); + } + + switch((*msg)->msg_style) { + + case PAM_PROMPT_ECHO_OFF: + + if (strcmp(message, "Password:") != 0) { + TRACE(("PAM_PROMPT_ECHO_OFF: unrecognized prompt")); + rc = PAM_CONV_ERR; + break; + } + + /* This looks leaky, but the PAM module-writer docs + * assure us that the caller will free it... */ + resp = (struct pam_response*) m_malloc(sizeof(struct pam_response)); + memset(resp, 0, sizeof(struct pam_response)); + + /* Safe to just use the direct pointer (no strdup) since + * it shouldn't be getting munged at all */ + resp->resp = userDatap->passwd; + (*respp) = resp; + break; + + + case PAM_PROMPT_ECHO_ON: + + if ((strcmp(message, "login: " ) != 0) + && (strcmp(message, "login:" ) != 0) + && (strcmp(message, "Please enter username: " ) != 0)) { + TRACE(("PAM_PROMPT_ECHO_ON: unrecognized prompt")); + rc = PAM_CONV_ERR; + break; + } + + /* This looks leaky, but the PAM module-writer docs + * assure us that the caller will free it... */ + resp = (struct pam_response*) m_malloc(sizeof(struct pam_response)); + memset(resp, 0, sizeof(struct pam_response)); + + /* Safe to just use the direct pointer (no strdup) since + * it shouldn't be getting munged at all */ + resp->resp = userDatap->user; + TRACE(("userDatap->user='%s'", userDatap->user)); + (*respp) = resp; + break; + + default: + TRACE(("Unknown message type")); + rc = PAM_CONV_ERR; + break; + } + + TRACE(("leave pamConvFunc, rc %d", rc)); + + return rc; +} + +/* Process a password auth request, sending success or failure messages as + * appropriate. To the client it looks like it's doing normal password auth (as + * opposed to keyboard-interactive or something), so the pam module has to be + * fairly standard (ie just "what's your username, what's your password, OK"). + * + * Keyboard interactive would be a lot nicer, but since PAM is synchronous, it + * gets very messy trying to send the interactive challenges, and read the + * interactive responses, over the network. */ +void svr_auth_pam() { + + struct UserDataS userData; + struct pam_conv pamConv = { + pamConvFunc, + &userData /* submitted to pamvConvFunc as appdata_ptr */ + }; + + pam_handle_t* pamHandlep = NULL; + + unsigned char * password = NULL; + unsigned int passwordlen; + + int rc = PAM_SUCCESS; + unsigned char changepw; + + /* check if client wants to change password */ + changepw = buf_getbyte(ses.payload); + if (changepw) { + /* not implemented by this server */ + send_msg_userauth_failure(0, 1); + goto cleanup; + } + + password = buf_getstring(ses.payload, &passwordlen); + + /* used to pass data to the PAM conversation function */ + userData.user = ses.authstate.printableuser; + userData.passwd = password; + + /* Init pam */ + if ((rc = pam_start("sshd", NULL, &pamConv, &pamHandlep)) != PAM_SUCCESS) { + dropbear_log(LOG_WARNING, "pam_start() failed, rc=%d, %s\n", + rc, pam_strerror(pamHandlep, rc)); + goto cleanup; + } + + /* just to set it to something */ + if ((rc = pam_set_item(pamHandlep, PAM_TTY, "ssh") != PAM_SUCCESS)) { + dropbear_log(LOG_WARNING, "pam_set_item() failed, rc=%d, %s\n", + rc, pam_strerror(pamHandlep, rc)); + goto cleanup; + } + + (void) pam_fail_delay(pamHandlep, 0 /* musec_delay */); + + /* (void) pam_set_item(pamHandlep, PAM_FAIL_DELAY, (void*) pamDelayFunc); */ + + if ((rc = pam_authenticate(pamHandlep, 0)) != PAM_SUCCESS) { + dropbear_log(LOG_WARNING, "pam_authenticate() failed, rc=%d, %s\n", + rc, pam_strerror(pamHandlep, rc)); + dropbear_log(LOG_WARNING, + "bad pam password attempt for '%s'", + ses.authstate.printableuser); + send_msg_userauth_failure(0, 1); + goto cleanup; + } + + if ((rc = pam_acct_mgmt(pamHandlep, 0)) != PAM_SUCCESS) { + dropbear_log(LOG_WARNING, "pam_acct_mgmt() failed, rc=%d, %s\n", + rc, pam_strerror(pamHandlep, rc)); + dropbear_log(LOG_WARNING, + "bad pam password attempt for '%s'", + ses.authstate.printableuser); + send_msg_userauth_failure(0, 1); + goto cleanup; + } + + /* successful authentication */ + dropbear_log(LOG_NOTICE, "pam password auth succeeded for '%s'", + ses.authstate.printableuser); + send_msg_userauth_success(); + +cleanup: + if (password != NULL) { + m_burn(password, passwordlen); + m_free(password); + } + if (pamHandlep != NULL) { + (void) pam_end(pamHandlep, 0 /* pam_status */); + } +} diff -r 18b261b1dea2 -r cb7ef2f63bf0 svr-runopts.c --- a/svr-runopts.c Sun Sep 12 05:53:48 2004 +0000 +++ b/svr-runopts.c Tue Sep 14 13:09:29 2004 +0000 @@ -59,7 +59,7 @@ "-m Don't display the motd on login\n" #endif "-w Disallow root logins\n" -#ifdef ENABLE_SVR_PASSWORD_AUTH +#if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH) "-s Disable password logins\n" "-g Disable password logins for root\n" #endif @@ -183,7 +183,7 @@ case 'w': svr_opts.norootlogin = 1; break; -#ifdef ENABLE_SVR_PASSWORD_AUTH +#if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH) case 's': svr_opts.noauthpass = 1; break;