]> git.feebdaed.xyz Git - 0xmirror/openssh-portable.git/commitdiff
upstream: Add 'invaliduser' penalty to PerSourcePenalties, which is
authordtucker@openbsd.org <dtucker@openbsd.org>
Tue, 16 Dec 2025 08:32:50 +0000 (08:32 +0000)
committerDarren Tucker <dtucker@dtucker.net>
Tue, 16 Dec 2025 09:40:59 +0000 (20:40 +1100)
applied to login attempts for usernames that do not match real accounts.
Defaults to 5s to match 'authfail' but allows administrators to block such
sources for longer if desired.  with & ok djm@

OpenBSD-Commit-ID: bb62797bcf2adceb96f608ce86d0bb042aff5834

monitor.c
monitor.h
servconf.c
servconf.h
srclimit.c
srclimit.h
sshd-session.c
sshd.c
sshd_config.5

index a9e854bec8315b7a4cb153e2135cf3484c8a0584..3867b438b33030bd34e7e47061f2e3b12ea5f4e7 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor.c,v 1.249 2025/09/25 06:45:50 djm Exp $ */
+/* $OpenBSD: monitor.c,v 1.250 2025/12/16 08:32:50 dtucker Exp $ */
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
  * Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -155,7 +155,8 @@ static char *auth_submethod = NULL;
 static u_int session_id2_len = 0;
 static u_char *session_id2 = NULL;
 static pid_t monitor_child_pid;
-int auth_attempted = 0;
+static int auth_attempted = 0;
+static int invalid_user = 0;
 
 struct mon_table {
        enum monitor_reqtype type;
@@ -855,6 +856,7 @@ mm_answer_pwnamallow(struct ssh *ssh, int sock, struct sshbuf *m)
        sshbuf_reset(m);
 
        if (pwent == NULL) {
+               invalid_user = 1;
                if ((r = sshbuf_put_u8(m, 0)) != 0)
                        fatal_fr(r, "assemble fakepw");
                authctxt->pw = fakepw();
@@ -1944,6 +1946,18 @@ monitor_reinit(struct monitor *mon)
        monitor_openfds(mon, 0);
 }
 
+int
+monitor_auth_attempted(void)
+{
+       return auth_attempted;
+}
+
+int
+monitor_invalid_user(void)
+{
+       return invalid_user;
+}
+
 #ifdef GSSAPI
 int
 mm_answer_gss_setup_ctx(struct ssh *ssh, int sock, struct sshbuf *m)
index 3f8a9bea30c6106f117801fa4c75461180772701..dc7cd5c7eb03998c581b8e0544ef5192019699ed 100644 (file)
--- a/monitor.h
+++ b/monitor.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor.h,v 1.24 2024/05/17 00:30:24 djm Exp $ */
+/* $OpenBSD: monitor.h,v 1.26 2025/12/16 08:32:50 dtucker Exp $ */
 
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
@@ -88,6 +88,9 @@ void monitor_child_postauth(struct ssh *, struct monitor *);
 void monitor_clear_keystate(struct ssh *, struct monitor *);
 void monitor_apply_keystate(struct ssh *, struct monitor *);
 
+int  monitor_auth_attempted(void);
+int  monitor_invalid_user(void);
+
 /* Prototypes for request sending and receiving */
 void mm_request_send(int, enum monitor_reqtype, struct sshbuf *);
 void mm_request_receive(int, struct sshbuf *);
index e74e3ecfbb120acc6d5183a7e6a5299df5065e21..1b8cfa4b62ed56ff3515e5dfac492edcd287f9a4 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: servconf.c,v 1.439 2025/12/08 03:55:22 djm Exp $ */
+/* $OpenBSD: servconf.c,v 1.440 2025/12/16 08:32:50 dtucker Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -176,6 +176,7 @@ initialize_server_options(ServerOptions *options)
        options->per_source_penalty.overflow_mode6 = -1;
        options->per_source_penalty.penalty_crash = -1.0;
        options->per_source_penalty.penalty_authfail = -1.0;
+       options->per_source_penalty.penalty_invaliduser = -1.0;
        options->per_source_penalty.penalty_noauth = -1.0;
        options->per_source_penalty.penalty_grace = -1.0;
        options->per_source_penalty.penalty_refuseconnection = -1.0;
@@ -438,6 +439,8 @@ fill_default_server_options(ServerOptions *options)
                options->per_source_penalty.penalty_grace = 10.0;
        if (options->per_source_penalty.penalty_authfail < 0.0)
                options->per_source_penalty.penalty_authfail = 5.0;
+       if (options->per_source_penalty.penalty_invaliduser < 0.0)
+               options->per_source_penalty.penalty_invaliduser = 5.0;
        if (options->per_source_penalty.penalty_noauth < 0.0)
                options->per_source_penalty.penalty_noauth = 1.0;
        if (options->per_source_penalty.penalty_refuseconnection < 0.0)
@@ -2115,6 +2118,8 @@ process_server_config_line_depth(ServerOptions *options, char *line,
                                doubleptr = &options->per_source_penalty.penalty_crash;
                        } else if ((q = strprefix(arg, "authfail:", 0)) != NULL) {
                                doubleptr = &options->per_source_penalty.penalty_authfail;
+                       } else if ((q = strprefix(arg, "invaliduser:", 0)) != NULL) {
+                               doubleptr = &options->per_source_penalty.penalty_invaliduser;
                        } else if ((q = strprefix(arg, "noauth:", 0)) != NULL) {
                                doubleptr = &options->per_source_penalty.penalty_noauth;
                        } else if ((q = strprefix(arg, "grace-exceeded:", 0)) != NULL) {
@@ -3430,12 +3435,14 @@ dump_config(ServerOptions *o)
 
        if (o->per_source_penalty.enabled) {
                printf("persourcepenalties crash:%f authfail:%f noauth:%f "
+                   "invaliduser:%f "
                    "grace-exceeded:%f refuseconnection:%f max:%f min:%f "
                    "max-sources4:%d max-sources6:%d "
                    "overflow:%s overflow6:%s\n",
                    o->per_source_penalty.penalty_crash,
                    o->per_source_penalty.penalty_authfail,
                    o->per_source_penalty.penalty_noauth,
+                   o->per_source_penalty.penalty_invaliduser,
                    o->per_source_penalty.penalty_grace,
                    o->per_source_penalty.penalty_refuseconnection,
                    o->per_source_penalty.penalty_max,
index 1005b0070b982c6b8e9db175a0f320693b868f65..73d952f095c62e07a96ac6164c31be97c922a1a3 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: servconf.h,v 1.171 2025/12/08 03:55:22 djm Exp $ */
+/* $OpenBSD: servconf.h,v 1.172 2025/12/16 08:32:50 dtucker Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -76,6 +76,7 @@ struct per_source_penalty {
        double  penalty_crash;
        double  penalty_grace;
        double  penalty_authfail;
+       double  penalty_invaliduser;
        double  penalty_noauth;
        double  penalty_refuseconnection;
        double  penalty_max;
index c6a553beb56db448f69bc9d2675a1e9bd1797544..dacc570aa4061d1879119de2f5e073d163f22aa2 100644 (file)
@@ -382,6 +382,10 @@ srclimit_penalise(struct xaddr *addr, int penalty_type)
                penalty_secs = penalty_cfg.penalty_noauth;
                reason = "penalty: connections without attempting authentication";
                break;
+       case SRCLIMIT_PENALTY_INVALIDUSER:
+               penalty_secs = penalty_cfg.penalty_invaliduser;
+               reason = "penalty: attempted authentication by invalid user";
+               break;
        case SRCLIMIT_PENALTY_REFUSECONNECTION:
                penalty_secs = penalty_cfg.penalty_refuseconnection;
                reason = "penalty: connection prohibited by RefuseConnection";
@@ -434,7 +438,7 @@ srclimit_penalise(struct xaddr *addr, int penalty_type)
                        fatal_f("internal error: %s penalty tables corrupt", t);
                do_log2_f(penalty->active ?
                    SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_VERBOSE,
-                   "%s: new %s %s penalty of %f seconds for %s", t,
+                   "%s: new %s %s penalty of %.3f seconds for %s", t,
                    addrnetmask, penalty->active ? "active" : "deferred",
                    penalty_secs, reason);
                if (++(*npenaltiesp) > (size_t)max_sources)
index 77d951ba66ea1b335c5aea293ebb373d02ba87b4..3e083df4413e9b56f1d21bf80df2795a0c13b9c7 100644 (file)
@@ -28,12 +28,14 @@ void        srclimit_done(int);
 #define SRCLIMIT_PENALTY_GRACE_EXCEEDED                3
 #define SRCLIMIT_PENALTY_NOAUTH                        4
 #define SRCLIMIT_PENALTY_REFUSECONNECTION      5
+#define SRCLIMIT_PENALTY_INVALIDUSER           6
 
 /* meaningful exit values, used by sshd listener for penalties */
 #define EXIT_LOGIN_GRACE       3       /* login grace period exceeded */
 #define EXIT_CHILD_CRASH       4       /* preauth child crashed */
 #define EXIT_AUTH_ATTEMPTED    5       /* at least one auth attempt made */
 #define EXIT_CONFIG_REFUSED    6       /* sshd_config RefuseConnection */
+#define EXIT_INVALID_USER      7       /* invalid user supplied */
 
 void   srclimit_penalise(struct xaddr *, int);
 int    srclimit_penalty_check_allow(int, const char **);
index 70a8766831feb8a4f26d7e6334b5d3863a633195..5d384fa2f986c4a53d1d5aabb20b76b62351e7a7 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshd-session.c,v 1.17 2025/11/13 10:35:14 dtucker Exp $ */
+/* $OpenBSD: sshd-session.c,v 1.18 2025/12/16 08:32:50 dtucker Exp $ */
 /*
  * SSH2 implementation:
  * Privilege Separation:
@@ -1375,8 +1375,6 @@ sshd_hostkey_sign(struct ssh *ssh, struct sshkey *privkey,
 void
 cleanup_exit(int i)
 {
-       extern int auth_attempted; /* monitor.c */
-
        if (the_active_state != NULL && the_authctxt != NULL) {
                do_cleanup(the_active_state, the_authctxt);
                if (privsep_is_preauth &&
@@ -1395,7 +1393,9 @@ cleanup_exit(int i)
                audit_event(the_active_state, SSH_CONNECTION_ABANDON);
 #endif
        /* Override default fatal exit value when auth was attempted */
-       if (i == 255 && auth_attempted)
+       if (i == 255 && monitor_auth_attempted())
                _exit(EXIT_AUTH_ATTEMPTED);
+       if (i == 255 && monitor_invalid_user())
+               _exit(EXIT_INVALID_USER);
        _exit(i);
 }
diff --git a/sshd.c b/sshd.c
index 8a84ff69b78e9b20f59229edc5ab605b5907eab9..03c40f66ca8e39accd21eab4a1bac6aeadbc55b8 100644 (file)
--- a/sshd.c
+++ b/sshd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshd.c,v 1.623 2025/11/13 10:35:14 dtucker Exp $ */
+/* $OpenBSD: sshd.c,v 1.624 2025/12/16 08:32:50 dtucker Exp $ */
 /*
  * Copyright (c) 2000, 2001, 2002 Markus Friedl.  All rights reserved.
  * Copyright (c) 2002 Niels Provos.  All rights reserved.
@@ -399,6 +399,12 @@ child_reap(struct early_child *child)
                            "after unsuccessful auth attempt%s",
                            (long)child->pid, child->id, child_status);
                        break;
+               case EXIT_INVALID_USER:
+                       penalty_type = SRCLIMIT_PENALTY_INVALIDUSER;
+                       debug_f("preauth child %ld for %s exited "
+                           "after auth attempt by invalid user%s",
+                           (long)child->pid, child->id, child_status);
+                       break;
                case EXIT_CONFIG_REFUSED:
                        penalty_type = SRCLIMIT_PENALTY_REFUSECONNECTION;
                        debug_f("preauth child %ld for %s prohibited by"
index 4b6955a3b19edb435a8ad24c8af44bf166ae5ae5..8108dc2daff56d80d04c4580ba084910543a9f75 100644 (file)
@@ -33,8 +33,8 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $OpenBSD: sshd_config.5,v 1.389 2025/12/08 03:55:22 djm Exp $
-.Dd $Mdocdate: December 8 2025 $
+.\" $OpenBSD: sshd_config.5,v 1.390 2025/12/16 08:32:50 dtucker Exp $
+.Dd $Mdocdate: December 16 2025 $
 .Dt SSHD_CONFIG 5
 .Os
 .Sh NAME
@@ -1622,6 +1622,9 @@ Specifies how long to refuse clients that cause a crash of
 .It Cm authfail:duration
 Specifies how long to refuse clients that disconnect after making one or more
 unsuccessful authentication attempts (default: 5s).
+.It Cm invaliduser:duration
+Specifies how long to refuse clients that attempt to log in with an invalid
+user (default: 5s).
 .It Cm refuseconnection:duration
 Specifies how long to refuse clients that were administratively prohibited
 connection via the