Bugzilla – Attachment 3569 Details for
Bug 3384
Feature proposal
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Feature implementation
0003-Added-authentication-result-reporting-to-sshd.patch (text/plain), 16.15 KB, created by
Thomas Koeller
on 2022-01-30 11:46:28 AEDT
(
hide
)
Description:
Feature implementation
Filename:
MIME Type:
Creator:
Thomas Koeller
Created:
2022-01-30 11:46:28 AEDT
Size:
16.15 KB
patch
obsolete
>From 1a01294e961e248170bb3d705b265db26b3cca92 Mon Sep 17 00:00:00 2001 >Message-Id: <1a01294e961e248170bb3d705b265db26b3cca92.1643473104.git.thomas@koeller.dyndns.org> >In-Reply-To: <cover.1643473104.git.thomas@koeller.dyndns.org> >References: <cover.1643473104.git.thomas@koeller.dyndns.org> >From: Thomas Koeller <thomas@koeller.dyndns.org> >Date: Tue, 10 Mar 2020 21:42:51 +0100 >Subject: [PATCH 3/3] Added authentication result reporting to sshd > >Whenever sshd tries to authenticate a user, a record containing the >result, along with the client's address and port number, is written >to a unix domain socket for external processing (e.g. managing a >blacklist or similar). > >Signed-off-by: Thomas Koeller <thomas@koeller.dyndns.org> >--- > Makefile.in | 4 +- > README.authreport | 38 +++++++++++++++ > auth.c | 9 +++- > auth2.c | 8 +++ > authreport.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++ > authreport.h | 37 ++++++++++++++ > configure.ac | 13 +++++ > servconf.c | 17 +++++++ > servconf.h | 3 ++ > sshd.c | 8 +++ > sshd_config | 1 + > sshd_config.5 | 8 +++ > 12 files changed, 264 insertions(+), 3 deletions(-) > create mode 100644 README.authreport > create mode 100644 authreport.c > create mode 100644 authreport.h > >diff --git a/Makefile.in b/Makefile.in >index 6d82c1b1..db54c7e2 100644 >--- a/Makefile.in >+++ b/Makefile.in >@@ -122,7 +122,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o \ > audit.o audit-bsm.o audit-linux.o platform.o \ > sshpty.o sshlogin.o servconf.o serverloop.o \ > auth.o auth2.o auth-options.o session.o \ >- auth2-chall.o groupaccess.o \ >+ auth2-chall.o groupaccess.o authreport.o \ > auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \ > auth2-none.o auth2-passwd.o auth2-pubkey.o \ > monitor.o monitor_wrap.o auth-krb5.o \ >@@ -307,7 +307,7 @@ distclean: regressclean > rm -f *.o *.a $(TARGETS) logintest config.cache config.log > rm -f *.out core opensshd.init openssh.xml > rm -f Makefile buildpkg.sh config.h config.status >- rm -f survey.sh openbsd-compat/regress/Makefile *~ >+ rm -f survey.sh openbsd-compat/regress/Makefile *~ > rm -rf autom4te.cache > rm -f regress/check-perm > rm -f regress/mkdtemp >diff --git a/README.authreport b/README.authreport >new file mode 100644 >index 00000000..7e27d04d >--- /dev/null >+++ b/README.authreport >@@ -0,0 +1,38 @@ >+The authentication report feature >+--------------------------------- >+There is an optional feature named 'authentication reporting', enabled >+by the --enable-authreport configuration switch. This causes sshd to >+report the outcome of every user authentication requested by a client to >+an external program for further processing. The intention is to allow >+for things like blacklisting clients that attempt to break into the system >+by trying large lists of common user names. Consult your log files if you >+don't know what I'm talking about. >+ >+Use of this feature requires the external authentication result processor >+to set up a unix domain socket which sshd will then send report records >+to. There is a configuration option named AuthReportSocket in sshd_config >+which has to be set to the file system path of that socket, (or 'none', >+the default). Unless this option is set to 'none', sshd will attempt to >+access the socket during startup. If this fails, startup is aborted, so >+the external processor has to be started before sshd. Communication style >+is connectionless, so the receiving socket has to be of the SOCK_DGRAM >+variety. >+ >+When sshd is up and running, every time a client connects and requests >+user authentication, a record containing the authentication result is >+sent. This record contains an ASCII string consisting of four parts >+separated by blanks, formatted like >+ >+ "RES=reject ADDR=::1 PORT=52592 USER=goofy" >+ >+RES is set to the authentication result, encoded as either "accept" or >+"reject". ADDR is the address of the requesting host, PORT is its source >+port number. Finally, USER contains the user name for which authentication >+was requested. The authreport-test folder contains a sample program >+illustrating the feature. >+ >+Care has been taken to design this feature in a way that it interferes >+with sshd's normal operation as little as possible. The socket used to >+communicate to the external processor is set to nonblocking mode, and >+any communiction failure will be ignored. >+ >diff --git a/auth.c b/auth.c >index 00b168b4..5bd95970 100644 >--- a/auth.c >+++ b/auth.c >@@ -76,7 +76,9 @@ > #include "ssherr.h" > #include "compat.h" > #include "channels.h" >- >+#ifdef ENABLE_AUTHREPORT >+#include "authreport.h" >+#endif > /* import */ > extern ServerOptions options; > extern struct include_list includes; >@@ -386,6 +388,11 @@ auth_maxtries_exceeded(struct ssh *ssh) > authctxt->user, > ssh_remote_ipaddr(ssh), > ssh_remote_port(ssh)); >+#ifdef ENABLE_AUTHREPORT >+ debug_f("Reporting authentication result: %s", >+ authctxt->success ? "success" : "failed"); >+ report_auth_result(ssh); >+#endif > ssh_packet_disconnect(ssh, "Too many authentication failures"); > /* NOTREACHED */ > } >diff --git a/auth2.c b/auth2.c >index 6ae27bd4..fdb27ccd 100644 >--- a/auth2.c >+++ b/auth2.c >@@ -58,6 +58,9 @@ > #endif > #include "monitor_wrap.h" > #include "digest.h" >+#ifdef ENABLE_AUTHREPORT >+#include "authreport.h" >+#endif > > /* import */ > extern ServerOptions options; >@@ -175,6 +178,11 @@ do_authentication2(struct ssh *ssh) > ssh_dispatch_init(ssh, &dispatch_protocol_error); > ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_REQUEST, &input_service_request); > ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt->success); >+#ifdef ENABLE_AUTHREPORT >+ debug_f("Reporting authentication result: %s", >+ authctxt->success ? "success" : "failed"); >+ report_auth_result(ssh); >+#endif > ssh->authctxt = NULL; > } > >diff --git a/authreport.c b/authreport.c >new file mode 100644 >index 00000000..13525cc6 >--- /dev/null >+++ b/authreport.c >@@ -0,0 +1,121 @@ >+/* >+ * Copyright (c) 2022 Thomas Koeller. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR >+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES >+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. >+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, >+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT >+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, >+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY >+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF >+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include <errno.h> >+#include <string.h> >+#include <stdio.h> >+#include <fcntl.h> >+#include <unistd.h> >+#include <stddef.h> >+#include <sys/socket.h> >+#include <sys/un.h> >+ >+#include "config.h" >+#include "packet.h" >+#include "log.h" >+#include "misc.h" >+#include "auth.h" >+#include "authreport.h" >+ >+static int sock_l = -1; >+ >+void >+init_auth_report(const char *skt_path) >+{ >+ static const size_t sbsize = 1024; >+ >+ struct sockaddr_un remaddr = { >+ .sun_family = AF_UNIX, >+ .sun_path = { 0 } >+ }; >+ >+ if (skt_path == NULL || *skt_path == 0 || >+ strcasecmp(skt_path, "none") == 0) { >+ verbose("Authresult processing disabled"); >+ return; >+ } >+ >+ strncpy(remaddr.sun_path, skt_path, sizeof remaddr.sun_path); >+ if (*(remaddr.sun_path + sizeof remaddr.sun_path - 1) != 0) { >+ /* Error: socket path truncated */ >+ fatal_f("Path '%s' too long", skt_path); >+ } >+ >+ sock_l = socket(PF_LOCAL, SOCK_DGRAM, 0); >+ >+ if (sock_l == -1) { >+ /* Error: failed to create local socket */ >+ fatal_f("Failed to create local socket %s: %s", >+ skt_path, strerror(errno)); >+ } >+ >+ if (setsockopt(sock_l, SOL_SOCKET, SO_SNDBUF, &sbsize, sizeof sbsize) < 0) { >+ fatal_f("Failed to set socket buffer size:%s", >+ strerror(errno)); >+ } >+ >+ if (set_nonblock(sock_l) < 0) { >+ fatal_f("Failed to set socket nonblocking mode"); >+ } >+ >+ if (connect(sock_l, (__CONST_SOCKADDR_ARG) &remaddr, SUN_LEN(&remaddr)) < 0) { >+ fatal_f("Failed to connect to socket %s: %s", >+ skt_path, strerror(errno)); >+ } >+} >+ >+void >+report_auth_result(struct ssh *ssh) >+{ >+ char rec[100]; >+ int n; >+ const Authctxt *authctxt = ssh->authctxt; >+ ssize_t nout; >+ >+ if (sock_l == -1) return; >+ >+ n = snprintf(rec, sizeof rec, AUTHRPT_REC_FMT, >+ authctxt->valid ? AUTHRPT_RES_ACCEPT : AUTHRPT_RES_REJECT, >+ ssh_remote_ipaddr(ssh), >+ ssh_remote_port(ssh), >+ authctxt->user >+ ); >+ >+ if (n >= sizeof rec) { >+ error_f("Record length %d exceeds buffer size %z", >+ n, sizeof rec); >+ return; >+ } >+ >+ nout = write(sock_l, rec, (size_t) n); >+ if (nout != n) { >+ if (nout < 0) >+ error_f("Communication failure:%s", strerror(errno)); >+ else >+ error_f("Message tuncated"); >+ /* Is there a better way to handle this condition? */ >+ close(sock_l); >+ sock_l = -1; >+ } >+} >diff --git a/authreport.h b/authreport.h >new file mode 100644 >index 00000000..3212360e >--- /dev/null >+++ b/authreport.h >@@ -0,0 +1,37 @@ >+/* >+ * Copyright (c) 2022 Thomas Koeller. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR >+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES >+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. >+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, >+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT >+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, >+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY >+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF >+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#ifndef _SSH_AUTHREPORT_H >+#define _SSH_AUTHREPORT_H >+ >+#define AUTHRPT_RES_ACCEPT "accept" >+#define AUTHRPT_RES_REJECT "reject" >+#define AUTHRPT_REC_FMT "RES=%s ADDR=%s PORT=%u USER=%s" >+ >+struct ssh; >+ >+void init_auth_report(const char *); >+void report_auth_result(struct ssh *); >+ >+#endif /* _SSH_AUTHREPORT_H */ >diff --git a/configure.ac b/configure.ac >index eb265143..b5dbbba2 100644 >--- a/configure.ac >+++ b/configure.ac >@@ -3477,6 +3477,18 @@ else > fi > AC_SUBST([SSH_PRIVSEP_USER]) > >+AUTHREPORT_MSG="no" >+AC_ARG_ENABLE([authreport], >+ [ --enable-authreport Enable authentication result reporting ], >+ [ >+ if test "x$enableval" = "xyes" ; then >+ AC_DEFINE([ENABLE_AUTHREPORT], [1], >+ [Enable authentication failure reporting]) >+ AUTHREPORT_MSG="yes" >+ fi >+ ] >+) >+ > if test "x$have_linux_no_new_privs" = "x1" ; then > AC_CHECK_DECL([SECCOMP_MODE_FILTER], [have_seccomp_filter=1], , [ > #include <sys/types.h> >@@ -5587,6 +5599,7 @@ echo " Random number source: $RAND_MSG" > echo " Privsep sandbox style: $SANDBOX_STYLE" > echo " PKCS#11 support: $enable_pkcs11" > echo " U2F/FIDO support: $enable_sk" >+echo " Authentication result reporting: $AUTHREPORT_MSG" > > echo "" > >diff --git a/servconf.c b/servconf.c >index b2fbf0b2..fd07dd8f 100644 >--- a/servconf.c >+++ b/servconf.c >@@ -195,6 +195,9 @@ initialize_server_options(ServerOptions *options) > options->fingerprint_hash = -1; > options->disable_forwarding = -1; > options->expose_userauth_info = -1; >+#ifdef ENABLE_AUTHREPORT >+ options->auth_report_socket = NULL; >+#endif > } > > /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ >@@ -470,6 +473,9 @@ fill_default_server_options(ServerOptions *options) > CLEAR_ON_NONE(options->host_key_files[i]); > for (i = 0; i < options->num_host_cert_files; i++) > CLEAR_ON_NONE(options->host_cert_files[i]); >+#ifdef ENABLE_AUTHREPORT >+ CLEAR_ON_NONE(options->auth_report_socket); >+#endif > #undef CLEAR_ON_NONE > > /* Similar handling for AuthenticationMethods=any */ >@@ -517,6 +523,7 @@ typedef enum { > sStreamLocalBindMask, sStreamLocalBindUnlink, > sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, > sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider, >+ sAuthReportSocket, > sDeprecated, sIgnore, sUnsupported > } ServerOpCodes; > >@@ -676,6 +683,7 @@ static struct { > { "rdomain", sRDomain, SSHCFG_ALL }, > { "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL }, > { "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL }, >+ { "authreportsocket", sAuthReportSocket, SSHCFG_ALL }, > { NULL, sBadOption, 0 } > }; > >@@ -2435,6 +2443,12 @@ process_server_config_line_depth(ServerOptions *options, char *line, > *charptr = xstrdup(arg); > break; > >+#ifdef ENABLE_AUTHREPORT >+ case sAuthReportSocket: >+ charptr = &options->auth_report_socket; >+ goto parse_filename; >+#endif >+ > case sDeprecated: > case sIgnore: > case sUnsupported: >@@ -2946,6 +2960,9 @@ dump_config(ServerOptions *o) > #if defined(__OpenBSD__) || defined(HAVE_SYS_SET_PROCESS_RDOMAIN) > dump_cfg_string(sRDomain, o->routing_domain); > #endif >+#ifdef ENABLE_AUTHREPORT >+ dump_cfg_string(sAuthReportSocket, o->auth_report_socket); >+#endif > > /* string arguments requiring a lookup */ > dump_cfg_string(sLogLevel, log_level_name(o->log_level)); >diff --git a/servconf.h b/servconf.h >index dd5cbc15..99b32474 100644 >--- a/servconf.h >+++ b/servconf.h >@@ -229,6 +229,9 @@ typedef struct { > int expose_userauth_info; > u_int64_t timing_secret; > char *sk_provider; >+#ifdef ENABLE_AUTHREPORT >+ char *auth_report_socket; >+#endif > } ServerOptions; > > /* Information about the incoming connection as used by Match */ >diff --git a/sshd.c b/sshd.c >index 296c6e86..4fd6b284 100644 >--- a/sshd.c >+++ b/sshd.c >@@ -128,6 +128,9 @@ > #include "sk-api.h" > #include "srclimit.h" > #include "dh.h" >+#ifdef ENABLE_AUTHREPORT >+#include "authreport.h" >+#endif > > /* Re-exec fds */ > #define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) >@@ -2020,6 +2023,11 @@ main(int ac, char **av) > for (i = 0; i < options.num_log_verbose; i++) > log_verbose_add(options.log_verbose[i]); > >+#ifdef ENABLE_AUTHREPORT >+ /* Initiallize user authorization result reporting */ >+ init_auth_report(options.auth_report_socket); >+#endif >+ > /* > * If not in debugging mode, not started from inetd and not already > * daemonized (eg re-exec via SIGHUP), disconnect from the controlling >diff --git a/sshd_config b/sshd_config >index c423eba1..fba3f1e5 100644 >--- a/sshd_config >+++ b/sshd_config >@@ -33,6 +33,7 @@ > #StrictModes yes > #MaxAuthTries 6 > #MaxSessions 10 >+#AuthReportSocket none > > #PubkeyAuthentication yes > >diff --git a/sshd_config.5 b/sshd_config.5 >index 985f1ba5..8c0c380f 100644 >--- a/sshd_config.5 >+++ b/sshd_config.5 >@@ -231,6 +231,14 @@ is enabled), > .Qq password > and > .Qq publickey . >+.It Cm AuthReportSocket >+Specifies the file system path of a unix domain socket. For every user >+authentication request, sshd will report thr result by sending a record >+containing the client's address to this socket. >+This is meant to provide a means of blacklisting hosts that attempt to >+break into the system by trying long lists of common passwords. A >+literal 'none' given for this parameter disables reporting of authorization >+failures. > .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.34.1 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 3384
:
3566
|
3567
|
3568
| 3569