The unified diff between revisions [12619953..] and [23e9cf6a..] is displayed below. It can also be downloaded as a raw diff.
#
#
# add_file "svr-authpam.c"
# content [6dbb7c0181129f6871c6fbb194b5cd92d0a9d337]
#
# patch "Makefile.in"
# from [cbca06faeb152aa4d8b47590e096d52f7fd7dfda]
# to [597afdd77f8936704ae8e3721dd800d7e0f722bf]
#
# patch "auth.h"
# from [42a641e0c3b3027858c3f8e8e717cca76b7eddd8]
# to [ff1ddd99ccdd09f16eabf2e22e5384dabf33543d]
#
# patch "configure.in"
# from [f3d9be07f83d1adafab1c522bb5459e028d6efc6]
# to [2dab0af5acf2a9845f1c249c5c10e0fc7b8c1e2e]
#
# patch "options.h"
# from [586757c4c005905a36d6900b1857a297c010d0e9]
# to [64a6ffbbed9f9bdf520a8b2b33f903ae63200cf3]
#
# patch "svr-auth.c"
# from [86f05f7a7df1de1108492ed86ba038e5a2d82eaa]
# to [aa0862ce0910cee5bfb9c0f57d1c482c9370c225]
#
# patch "svr-runopts.c"
# from [0dc09806e7b620e96f83e49a6c18af83ad1b887f]
# to [d4a122f8fbe9a29b5bf8c4fa05f0a938edbeba07]
#
============================================================
--- svr-authpam.c 6dbb7c0181129f6871c6fbb194b5cd92d0a9d337
+++ svr-authpam.c 6dbb7c0181129f6871c6fbb194b5cd92d0a9d337
@@ -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 <security/pam_appl.h>
+#elif defined (HAVE_PAM_PAM_APPL_H)
+#include <pam/pam_appl.h>
+#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 */);
+ }
+}
============================================================
--- Makefile.in cbca06faeb152aa4d8b47590e096d52f7fd7dfda
+++ Makefile.in 597afdd77f8936704ae8e3721dd800d7e0f722bf
@@ -24,7 +24,7 @@ SVROBJS=svr-kex.o svr-algo.o svr-auth.o
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 \
============================================================
--- auth.h 42a641e0c3b3027858c3f8e8e717cca76b7eddd8
+++ auth.h ff1ddd99ccdd09f16eabf2e22e5384dabf33543d
@@ -36,6 +36,7 @@ void svr_auth_pubkey();
void send_msg_userauth_success();
void svr_auth_password();
void svr_auth_pubkey();
+void svr_auth_pam();
/* Client functions */
void recv_msg_userauth_failure();
============================================================
--- configure.in f3d9be07f83d1adafab1c522bb5459e028d6efc6
+++ configure.in 2dab0af5acf2a9845f1c249c5c10e0fc7b8c1e2e
@@ -117,6 +117,43 @@ AC_ARG_ENABLE(zlib,
]
)
+# 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 @@ AC_HEADER_SYS_WAIT
# 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
============================================================
--- options.h 586757c4c005905a36d6900b1857a297c010d0e9
+++ options.h 64a6ffbbed9f9bdf520a8b2b33f903ae63200cf3
@@ -110,9 +110,19 @@ etc) slower (perhaps by 50%). Recommende
#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 @@ etc) slower (perhaps by 50%). Recommende
*******************************************************************/
#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 @@ etc) slower (perhaps by 50%). Recommende
#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)
============================================================
--- svr-auth.c 86f05f7a7df1de1108492ed86ba038e5a2d82eaa
+++ svr-auth.c aa0862ce0910cee5bfb9c0f57d1c482c9370c225
@@ -55,7 +55,7 @@ static void authclear() {
#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 @@ void recv_msg_userauth_request() {
}
#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 &&
============================================================
--- svr-runopts.c 0dc09806e7b620e96f83e49a6c18af83ad1b887f
+++ svr-runopts.c d4a122f8fbe9a29b5bf8c4fa05f0a938edbeba07
@@ -59,7 +59,7 @@ static void printhelp(const char * progn
"-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 @@ void svr_getopts(int argc, char ** argv)
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;