summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2022-11-09 17:33:48 +0800
committerMatt Johnston <matt@ucc.asn.au>2022-11-09 17:33:48 +0800
commit71d78653c7c4e9e42377ed96d3d7817d41ecf5b5 (patch)
tree51895d0b4336ea87118231e53097ae9b3ddcdf15
parentb4c30b5e7e7df9f70d8e90f2e3e8a6948c5080f2 (diff)
parent9f55ff216b6593c53c9fa72bf93b147b5a0d9c15 (diff)
downloaddropbear-71d78653c7c4e9e42377ed96d3d7817d41ecf5b5.tar.gz
Merge pull request #160 from Jackkal/two-factor-authentication
Two-factor authentication support (pubkey and password)
-rw-r--r--dropbear.84
-rw-r--r--runopts.h1
-rw-r--r--svr-authpam.c23
-rw-r--r--svr-authpasswd.c22
-rw-r--r--svr-authpubkey.c25
-rw-r--r--svr-runopts.c9
6 files changed, 66 insertions, 18 deletions
diff --git a/dropbear.8 b/dropbear.8
index 30df631..298c220 100644
--- a/dropbear.8
+++ b/dropbear.8
@@ -53,6 +53,10 @@ Disable password logins.
.B \-g
Disable password logins for root.
.TP
+.B \-t
+Enable two-factor authentication. Both password login and public key authentication are
+required. Should not be used with the '-s' option.
+.TP
.B \-j
Disable local port forwarding.
.TP
diff --git a/runopts.h b/runopts.h
index 90b809c..48a768c 100644
--- a/runopts.h
+++ b/runopts.h
@@ -106,6 +106,7 @@ typedef struct svr_runopts {
int noauthpass;
int norootpass;
int allowblankpass;
+ int multiauthmethod;
unsigned int maxauthtries;
#if DROPBEAR_SVR_REMOTETCPFWD
diff --git a/svr-authpam.c b/svr-authpam.c
index e236db4..ec14632 100644
--- a/svr-authpam.c
+++ b/svr-authpam.c
@@ -30,6 +30,7 @@
#include "buffer.h"
#include "dbutil.h"
#include "auth.h"
+#include "runopts.h"
#if DROPBEAR_SVR_PAM_AUTH
@@ -278,12 +279,22 @@ void svr_auth_pam(int valid_user) {
goto cleanup;
}
- /* successful authentication */
- dropbear_log(LOG_NOTICE, "PAM password auth succeeded for '%s' from %s",
- ses.authstate.pw_name,
- svr_ses.addrstring);
- send_msg_userauth_success();
-
+ if (svr_opts.multiauthmethod && (ses.authstate.authtypes & ~AUTH_TYPE_PASSWORD)) {
+ /* successful PAM password authentication, but extra auth required */
+ dropbear_log(LOG_NOTICE,
+ "PAM password auth succeeded for '%s' from %s, extra auth required",
+ ses.authstate.pw_name,
+ svr_ses.addrstring);
+ ses.authstate.authtypes &= ~AUTH_TYPE_PASSWORD; /* PAM password auth ok, delete the method flag */
+ send_msg_userauth_failure(1, 0); /* Send partial success */
+ } else {
+ /* successful authentication */
+ dropbear_log(LOG_NOTICE, "PAM password auth succeeded for '%s' from %s",
+ ses.authstate.pw_name,
+ svr_ses.addrstring);
+ send_msg_userauth_success();
+ }
+
cleanup:
if (password != NULL) {
m_burn(password, passwordlen);
diff --git a/svr-authpasswd.c b/svr-authpasswd.c
index a4f3202..899a8ab 100644
--- a/svr-authpasswd.c
+++ b/svr-authpasswd.c
@@ -106,12 +106,22 @@ void svr_auth_password(int valid_user) {
}
if (constant_time_strcmp(testcrypt, passwdcrypt) == 0) {
- /* successful authentication */
- dropbear_log(LOG_NOTICE,
- "Password auth succeeded for '%s' from %s",
- ses.authstate.pw_name,
- svr_ses.addrstring);
- send_msg_userauth_success();
+ if (svr_opts.multiauthmethod && (ses.authstate.authtypes & ~AUTH_TYPE_PASSWORD)) {
+ /* successful password authentication, but extra auth required */
+ dropbear_log(LOG_NOTICE,
+ "Password auth succeeded for '%s' from %s, extra auth required",
+ ses.authstate.pw_name,
+ svr_ses.addrstring);
+ ses.authstate.authtypes &= ~AUTH_TYPE_PASSWORD; /* password auth ok, delete the method flag */
+ send_msg_userauth_failure(1, 0); /* Send partial success */
+ } else {
+ /* successful authentication */
+ dropbear_log(LOG_NOTICE,
+ "Password auth succeeded for '%s' from %s",
+ ses.authstate.pw_name,
+ svr_ses.addrstring);
+ send_msg_userauth_success();
+ }
} else {
dropbear_log(LOG_WARNING,
"Bad password attempt for '%s' from %s",
diff --git a/svr-authpubkey.c b/svr-authpubkey.c
index 529280c..5d298cb 100644
--- a/svr-authpubkey.c
+++ b/svr-authpubkey.c
@@ -64,6 +64,7 @@
#include "ssh.h"
#include "packet.h"
#include "algo.h"
+#include "runopts.h"
#if DROPBEAR_SVR_PUBKEY_AUTH
@@ -211,12 +212,24 @@ void svr_auth_pubkey(int valid_user) {
/* ... and finally verify the signature */
fp = sign_key_fingerprint(keyblob, keybloblen);
if (buf_verify(ses.payload, key, sigtype, signbuf) == DROPBEAR_SUCCESS) {
- dropbear_log(LOG_NOTICE,
- "Pubkey auth succeeded for '%s' with %s key %s from %s",
- ses.authstate.pw_name,
- signkey_name_from_type(keytype, NULL), fp,
- svr_ses.addrstring);
- send_msg_userauth_success();
+ if (svr_opts.multiauthmethod && (ses.authstate.authtypes & ~AUTH_TYPE_PUBKEY)) {
+ /* successful pubkey authentication, but extra auth required */
+ dropbear_log(LOG_NOTICE,
+ "Pubkey auth succeeded for '%s' with %s key %s from %s, extra auth required",
+ ses.authstate.pw_name,
+ signkey_name_from_type(keytype, NULL), fp,
+ svr_ses.addrstring);
+ ses.authstate.authtypes &= ~AUTH_TYPE_PUBKEY; /* pubkey auth ok, delete the method flag */
+ send_msg_userauth_failure(1, 0); /* Send partial success */
+ } else {
+ /* successful authentication */
+ dropbear_log(LOG_NOTICE,
+ "Pubkey auth succeeded for '%s' with %s key %s from %s",
+ ses.authstate.pw_name,
+ signkey_name_from_type(keytype, NULL), fp,
+ svr_ses.addrstring);
+ send_msg_userauth_success();
+ }
#if DROPBEAR_PLUGIN
if ((ses.plugin_session != NULL) && (svr_ses.plugin_instance->auth_success != NULL)) {
/* Was authenticated through the external plugin. tell plugin that signature verification was ok */
diff --git a/svr-runopts.c b/svr-runopts.c
index f2e8b89..7b76dca 100644
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -81,6 +81,7 @@ static void printhelp(const char * progname) {
"-s Disable password logins\n"
"-g Disable password logins for root\n"
"-B Allow blank password logins\n"
+ "-t Enable two-factor authentication (both password and public key required)\n"
#endif
"-T Maximum authentication tries (default %d)\n"
#if DROPBEAR_SVR_LOCALTCPFWD
@@ -159,6 +160,7 @@ void svr_getopts(int argc, char ** argv) {
svr_opts.noauthpass = 0;
svr_opts.norootpass = 0;
svr_opts.allowblankpass = 0;
+ svr_opts.multiauthmethod = 0;
svr_opts.maxauthtries = MAX_AUTH_TRIES;
svr_opts.inetdmode = 0;
svr_opts.portcount = 0;
@@ -297,6 +299,9 @@ void svr_getopts(int argc, char ** argv) {
case 'B':
svr_opts.allowblankpass = 1;
break;
+ case 't':
+ svr_opts.multiauthmethod = 1;
+ break;
#endif
case 'h':
printhelp(argv[0]);
@@ -447,6 +452,10 @@ void svr_getopts(int argc, char ** argv) {
}
#endif
+ if (svr_opts.multiauthmethod && svr_opts.noauthpass) {
+ dropbear_exit("-t and -s are incompatible");
+ }
+
#if DROPBEAR_PLUGIN
if (pubkey_plugin) {
svr_opts.pubkey_plugin = m_strdup(pubkey_plugin);