[openssh-commits] [openssh] 01/02: upstream: Add 'invaliduser' penalty to PerSourcePenalties, which is
git+noreply at mindrot.org
git+noreply at mindrot.org
Tue Dec 16 20:41:45 AEDT 2025
This is an automated email from the git hooks/post-receive script.
dtucker pushed a commit to branch master
in repository openssh.
commit 49480f1934f8cf994afa646d4bcbd22ac08bb6af
Author: dtucker at openbsd.org <dtucker at openbsd.org>
AuthorDate: Tue Dec 16 08:32:50 2025 +0000
upstream: Add 'invaliduser' penalty to PerSourcePenalties, which is
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 | 18 ++++++++++++++++--
monitor.h | 5 ++++-
servconf.c | 9 ++++++++-
servconf.h | 3 ++-
srclimit.c | 6 +++++-
srclimit.h | 2 ++
sshd-session.c | 8 ++++----
sshd.c | 8 +++++++-
sshd_config.5 | 7 +++++--
9 files changed, 53 insertions(+), 13 deletions(-)
diff --git a/monitor.c b/monitor.c
index a9e854bec..3867b438b 100644
--- 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 at citi.umich.edu>
* Copyright 2002 Markus Friedl <markus at 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)
diff --git a/monitor.h b/monitor.h
index 3f8a9bea3..dc7cd5c7e 100644
--- 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 at 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 *);
diff --git a/servconf.c b/servconf.c
index e74e3ecfb..1b8cfa4b6 100644
--- a/servconf.c
+++ b/servconf.c
@@ -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 at 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,
diff --git a/servconf.h b/servconf.h
index 1005b0070..73d952f09 100644
--- a/servconf.h
+++ b/servconf.h
@@ -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 at 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;
diff --git a/srclimit.c b/srclimit.c
index c6a553beb..dacc570aa 100644
--- a/srclimit.c
+++ b/srclimit.c
@@ -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)
diff --git a/srclimit.h b/srclimit.h
index 77d951ba6..3e083df44 100644
--- a/srclimit.h
+++ b/srclimit.h
@@ -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 **);
diff --git a/sshd-session.c b/sshd-session.c
index 70a876683..5d384fa2f 100644
--- a/sshd-session.c
+++ b/sshd-session.c
@@ -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 8a84ff69b..03c40f66c 100644
--- 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"
diff --git a/sshd_config.5 b/sshd_config.5
index 4b6955a3b..8108dc2da 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -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
--
To stop receiving notification emails like this one, please contact
djm at mindrot.org.
More information about the openssh-commits
mailing list