diff options
author | Matt Johnston <matt@ucc.asn.au> | 2022-11-09 17:33:48 +0800 |
---|---|---|
committer | Matt Johnston <matt@ucc.asn.au> | 2022-11-09 17:33:48 +0800 |
commit | 71d78653c7c4e9e42377ed96d3d7817d41ecf5b5 (patch) | |
tree | 51895d0b4336ea87118231e53097ae9b3ddcdf15 | |
parent | b4c30b5e7e7df9f70d8e90f2e3e8a6948c5080f2 (diff) | |
parent | 9f55ff216b6593c53c9fa72bf93b147b5a0d9c15 (diff) | |
download | dropbear-71d78653c7c4e9e42377ed96d3d7817d41ecf5b5.tar.gz |
Merge pull request #160 from Jackkal/two-factor-authentication
Two-factor authentication support (pubkey and password)
-rw-r--r-- | dropbear.8 | 4 | ||||
-rw-r--r-- | runopts.h | 1 | ||||
-rw-r--r-- | svr-authpam.c | 23 | ||||
-rw-r--r-- | svr-authpasswd.c | 22 | ||||
-rw-r--r-- | svr-authpubkey.c | 25 | ||||
-rw-r--r-- | svr-runopts.c | 9 |
6 files changed, 66 insertions, 18 deletions
@@ -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 @@ -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); |