[PATCH 1/1] sshd: Added authentication failure hook

Thomas Koeller thomas at koeller.dyndns.org
Wed Mar 11 07:42:51 AEDT 2020


Added a configuration option named AuthFailHook. This option holds
the path of a program to run in the event that sshd exits without
successfully authenticating a network client. The program receives
the client's ip address in its environment.

This is meant as a means of blacklisting nodes that attempt to break
into our system by trying long lists of common passwords, one by one.
Delegating this task to an external program provides for maximum
flexibility.
---
 servconf.c    |  6 ++++++
 servconf.h    |  1 +
 sshd.c        | 19 +++++++++++++++++++
 sshd_config   |  3 +++
 sshd_config.5 | 11 +++++++++++
 5 files changed, 40 insertions(+)

diff --git a/servconf.c b/servconf.c
index 70f5f73f..d455e465 100644
--- a/servconf.c
+++ b/servconf.c
@@ -543,6 +543,7 @@ typedef enum {
 	sStreamLocalBindMask, sStreamLocalBindUnlink,
 	sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
 	sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
+	sAuthFailHook,
 	sDeprecated, sIgnore, sUnsupported
 } ServerOpCodes;
 
@@ -695,6 +696,7 @@ static struct {
 	{ "rdomain", sRDomain, SSHCFG_ALL },
 	{ "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL },
 	{ "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL },
+	{ "authfailhook", sAuthFailHook, SSHCFG_ALL },
 	{ NULL, sBadOption, 0 }
 };
 
@@ -2338,6 +2340,10 @@ process_server_config_line_depth(ServerOptions *options, char *line,
 			*charptr = xstrdup(arg);
 		break;
 
+	case sAuthFailHook:
+		charptr = &options->auth_fail_hook;
+		goto parse_filename;
+
 	case sDeprecated:
 	case sIgnore:
 	case sUnsupported:
diff --git a/servconf.h b/servconf.h
index 4202a2d0..2946d169 100644
--- a/servconf.h
+++ b/servconf.h
@@ -218,6 +218,7 @@ typedef struct {
 	int	expose_userauth_info;
 	u_int64_t timing_secret;
 	char   *sk_provider;
+	char   *auth_fail_hook;
 }       ServerOptions;
 
 /* Information about the incoming connection as used by Match */
diff --git a/sshd.c b/sshd.c
index 60b2aaf7..446d7ce9 100644
--- a/sshd.c
+++ b/sshd.c
@@ -2385,12 +2385,30 @@ do_ssh2_kex(struct ssh *ssh)
 	debug("KEX done");
 }
 
+/* Run an external program if client authentication was unsuccessful */
+static void
+run_auth_fail_hook(const char * h, const char * ip)
+{
+	if ((use_privsep && !mm_is_monitor()) || !strcmp(ip, "UNKNOWN"))
+		return;
+
+	debug3("%s: Running %s for ip %s", __func__, h, ip);
+
+	if (setenv("SSH_NOAUTH_ADDRESS", ip, 1) != 0 || system(h) != 0)
+		error("%s: Failed to run authentification failure hook",
+		    __func__);
+}
+
 /* server specific fatal cleanup */
 void
 cleanup_exit(int i)
 {
 	if (the_active_state != NULL && the_authctxt != NULL) {
 		do_cleanup(the_active_state, the_authctxt);
+		if (options.auth_fail_hook != NULL &&
+		    !the_authctxt->authenticated)
+			run_auth_fail_hook(options.auth_fail_hook,
+			    ssh_remote_ipaddr(the_active_state));
 		if (use_privsep && privsep_is_preauth &&
 		    pmonitor != NULL && pmonitor->m_pid > 1) {
 			debug("Killing privsep child %d", pmonitor->m_pid);
@@ -2405,5 +2423,6 @@ cleanup_exit(int i)
 	if (the_active_state != NULL && (!use_privsep || mm_is_monitor()))
 		audit_event(the_active_state, SSH_CONNECTION_ABANDON);
 #endif
+
 	_exit(i);
 }
diff --git a/sshd_config b/sshd_config
index 19b7c91a..108c07cd 100644
--- a/sshd_config
+++ b/sshd_config
@@ -105,6 +105,9 @@ AuthorizedKeysFile	.ssh/authorized_keys
 # no default banner path
 #Banner none
 
+# Program to run if client not authenticated
+#AuthFailHook /bin/true
+
 # override default of no subsystems
 Subsystem	sftp	/usr/libexec/sftp-server
 
diff --git a/sshd_config.5 b/sshd_config.5
index 70ccea44..94e48084 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -231,6 +231,17 @@ is enabled),
 .Qq password
 and
 .Qq publickey .
+.It Cm AuthFailHook
+Specifies a program to be run if sshd exits whithout sucessfully
+authenticating a client. The program is run via the
+.Xr system 3
+function. It is only executed if the login attempt arrived via a
+network connection. The address of the originating node will be passed
+to it in the
+.Ev SSH_NOAUTH_ADDRESS
+environment variable. This is meant to provide a means of blacklisting
+hosts that attempt to break into the system by trying long lists of
+common passwords.
 .It Cm AuthorizedKeysCommand
 Specifies a program to be used to look up the user's public keys.
 The program must be owned by root, not writable by group or others and
-- 
2.24.1


More information about the openssh-unix-dev mailing list