--- Makefile.in.orig 2025-10-02 12:00:00.000000000 +++ Makefile.in 2025-10-02 12:00:00.000000000 @@ -208,6 +208,8 @@ FIXPATHSCMD = $(SED) $(PATHSUBS) FIXALGORITHMSCMD= $(SHELL) $(srcdir)/fixalgorithms $(SED) \ @UNSUPPORTED_ALGORITHMS@ + +LIBSSH_OBJS+= blacklist.o all: $(CONFIGFILES) $(MANPAGES) $(TARGETS) --- auth-pam.c.orig 2025-10-02 12:00:00.000000000 +++ auth-pam.c 2025-10-02 12:00:00.000000000 @@ -101,6 +101,7 @@ #endif #include "monitor_wrap.h" #include "srclimit.h" +#include "blacklist_client.h" extern ServerOptions options; extern struct sshbuf *loginmsg; @@ -936,6 +937,8 @@ sshbuf_free(buffer); return (0); } + BLACKLIST_NOTIFY(NULL, BLACKLIST_AUTH_FAIL, + "PAM illegal user"); error("PAM: %s for %s%.100s from %.100s", msg, sshpam_authctxt->valid ? "" : "illegal user ", sshpam_authctxt->user, sshpam_rhost); --- auth.c.orig 2025-10-02 12:00:00.000000000 +++ auth.c 2025-10-02 12:00:00.000000000 @@ -73,6 +73,7 @@ #include "monitor_wrap.h" #include "ssherr.h" #include "channels.h" +#include "blacklist_client.h" /* import */ extern ServerOptions options; @@ -283,8 +284,12 @@ authmsg = "Postponed"; else if (partial) authmsg = "Partial"; - else + else { authmsg = authenticated ? "Accepted" : "Failed"; + if (authenticated) + BLACKLIST_NOTIFY(ssh, BLACKLIST_AUTH_OK, + "Authenticated"); + } if ((extra = format_method_key(authctxt)) == NULL) { if (authctxt->auth_method_info != NULL) @@ -332,6 +337,7 @@ { Authctxt *authctxt = (Authctxt *)ssh->authctxt; + BLACKLIST_NOTIFY(ssh, BLACKLIST_AUTH_FAIL, "Maximum attempts exceeded"); error("maximum authentication attempts exceeded for " "%s%.100s from %.200s port %d ssh2", authctxt->valid ? "" : "invalid user ", @@ -492,6 +498,8 @@ aix_restoreauthdb(); #endif if (pw == NULL) { + BLACKLIST_NOTIFY(ssh, BLACKLIST_AUTH_FAIL, + "Invalid user"); logit("Invalid user %.100s from %.100s port %d", user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh)); #ifdef CUSTOM_FAILED_LOGIN --- blacklist.c.orig 2025-10-02 12:00:00.000000000 +++ blacklist.c 2025-10-02 12:00:00.000000000 @@ -0,0 +1,97 @@ +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * Copyright (c) 2016 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Kurt Lidl + * under sponsorship from the FreeBSD Foundation. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 FOUNDATION OR CONTRIBUTORS + * 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 "includes.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "ssh.h" +#include "packet.h" +#include "log.h" +#include "misc.h" +#include "servconf.h" +#include +#include "blacklist_client.h" + +static struct blacklist *blstate = NULL; + +/* import */ +extern ServerOptions options; + +/* internal definition from bl.h */ +struct blacklist *bl_create(bool, char *, void (*)(int, const char *, va_list)); + +/* impedence match vsyslog() to sshd's internal logging levels */ +void +im_log(int priority, const char *message, va_list args) +{ + LogLevel imlevel; + + switch (priority) { + case LOG_ERR: + imlevel = SYSLOG_LEVEL_ERROR; + break; + case LOG_DEBUG: + imlevel = SYSLOG_LEVEL_DEBUG1; + break; + case LOG_INFO: + imlevel = SYSLOG_LEVEL_INFO; + break; + default: + imlevel = SYSLOG_LEVEL_DEBUG2; + } + do_log2(imlevel, message, args); +} + +void +blacklist_init(void) +{ + + if (options.use_blacklist) + blstate = bl_create(false, NULL, im_log); +} + +void +blacklist_notify(struct ssh *ssh, int action, const char *msg) +{ + + if (blstate != NULL && ssh_packet_connection_is_on_socket(ssh)) + (void)blacklist_r(blstate, action, + ssh_packet_get_connection_in(ssh), msg); +} --- blacklist_client.h.orig 2025-10-02 12:00:00.000000000 +++ blacklist_client.h 2025-10-02 12:00:00.000000000 @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * Copyright (c) 2016 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Kurt Lidl + * under sponsorship from the FreeBSD Foundation. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 FOUNDATION OR CONTRIBUTORS + * 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 BLACKLIST_CLIENT_H +#define BLACKLIST_CLIENT_H + +#ifndef BLACKLIST_API_ENUM +enum { + BLACKLIST_AUTH_OK = 0, + BLACKLIST_AUTH_FAIL, + BLACKLIST_ABUSIVE_BEHAVIOR, + BLACKLIST_BAD_USER +}; +#endif + +#ifdef USE_BLACKLIST +void blacklist_init(void); +void blacklist_notify(struct ssh *, int, const char *); + +#define BLACKLIST_INIT() blacklist_init() +#define BLACKLIST_NOTIFY(ssh,x,msg) blacklist_notify(ssh,x,msg) + +#else + +#define BLACKLIST_INIT() +#define BLACKLIST_NOTIFY(ssh,x,msg) + +#endif + + +#endif /* BLACKLIST_CLIENT_H */ --- monitor.c.orig 2025-10-02 12:00:00.000000000 +++ monitor.c 2025-10-02 12:00:00.000000000 @@ -75,6 +75,8 @@ #include "misc.h" #include "servconf.h" #include "monitor.h" +#include "blacklist_client.h" + #ifdef GSSAPI #include "ssh-gss.h" #endif @@ -343,16 +345,24 @@ } } if (authctxt->failures > options.max_authtries) { + BLACKLIST_NOTIFY(ssh, BLACKLIST_AUTH_FAIL, + "Too many authentication attempts"); /* Shouldn't happen */ fatal_f("privsep child made too many authentication " "attempts"); } } - if (!authctxt->valid) - fatal_f("authenticated invalid user"); - if (strcmp(auth_method, "unknown") == 0) + if (!authctxt->valid) { + BLACKLIST_NOTIFY(ssh, BLACKLIST_AUTH_FAIL, + "Authenticated invalid user"); + fatal_f("authenticated invalid user"); + } + if (strcmp(auth_method, "unknown") == 0) { + BLACKLIST_NOTIFY(ssh, BLACKLIST_AUTH_FAIL, + "Authentication method name unknown"); fatal_f("authentication method name unknown"); + } debug_f("user %s authenticated by privileged process", authctxt->user); auth_attempted = 0; --- servconf.c.orig 2025-10-02 12:00:00.000000000 +++ servconf.c 2025-10-02 12:00:00.000000000 @@ -184,6 +184,7 @@ options->max_sessions = -1; options->banner = NULL; options->use_dns = -1; + options->use_blacklist = -1; options->client_alive_interval = -1; options->client_alive_count_max = -1; options->num_authkeys_files = 0; @@ -449,6 +458,8 @@ options->max_sessions = DEFAULT_SESSIONS_MAX; if (options->use_dns == -1) options->use_dns = 0; + if (options->use_blacklist == -1) + options->use_blacklist = 0; if (options->client_alive_interval == -1) options->client_alive_interval = 0; if (options->client_alive_count_max == -1) @@ -567,6 +568,7 @@ sGatewayPorts, sPubkeyAuthentication, sPubkeyAcceptedAlgorithms, sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions, sBanner, sUseDNS, sHostbasedAuthentication, + sUseBlacklist, sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms, sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize, sPerSourcePenalties, sPerSourcePenaltyExemptList, @@ -700,6 +712,8 @@ { "maxsessions", sMaxSessions, SSHCFG_ALL }, { "banner", sBanner, SSHCFG_ALL }, { "usedns", sUseDNS, SSHCFG_GLOBAL }, + { "useblacklist", sUseBlacklist, SSHCFG_GLOBAL }, + { "useblocklist", sUseBlacklist, SSHCFG_GLOBAL } /* alias */, { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL }, { "reversemappingcheck", sDeprecated, SSHCFG_GLOBAL }, { "clientaliveinterval", sClientAliveInterval, SSHCFG_ALL }, @@ -1782,6 +1796,10 @@ intptr = &options->use_dns; goto parse_flag; + case sUseBlacklist: + intptr = &options->use_blacklist; + goto parse_flag; + case sLogFacility: log_facility_ptr = &options->log_facility; arg = argv_next(&ac, &av); @@ -3279,6 +3297,7 @@ dump_cfg_fmtint(sCompression, o->compression); dump_cfg_fmtint(sGatewayPorts, o->fwd_opts.gateway_ports); dump_cfg_fmtint(sUseDNS, o->use_dns); + dump_cfg_fmtint(sUseBlacklist, o->use_blacklist); dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding); dump_cfg_fmtint(sAllowAgentForwarding, o->allow_agent_forwarding); dump_cfg_fmtint(sDisableForwarding, o->disable_forwarding); --- servconf.h.orig 2025-10-02 12:00:00.000000000 +++ servconf.h 2025-10-02 12:00:00.000000000 @@ -195,6 +195,7 @@ int max_sessions; char *banner; /* SSH-2 banner message */ int use_dns; + int use_blacklist; int client_alive_interval; /* * poke the client this often to * see if it's still there --- sshd-session.c.orig 2025-10-02 12:00:00.000000000 +++ sshd-session.c 2025-10-02 12:00:00.000000000 @@ -102,6 +102,7 @@ #include "sk-api.h" #include "srclimit.h" #include "dh.h" +#include "blacklist_client.h" #ifdef LIBWRAP #include @@ -1175,6 +1176,8 @@ ssh_signal(SIGQUIT, SIG_DFL); ssh_signal(SIGCHLD, SIG_DFL); ssh_signal(SIGINT, SIG_DFL); + + BLACKLIST_INIT(); /* * Register our connection. This turns encryption off because we do @@ -1249,8 +1271,10 @@ } if ((r = kex_exchange_identification(ssh, -1, - options.version_addendum)) != 0) + options.version_addendum)) != 0) { + BLACKLIST_NOTIFY(ssh, BLACKLIST_AUTH_FAIL, "Banner exchange"); sshpkt_fatal(ssh, r, "banner exchange"); + } ssh_packet_set_nonblocking(ssh); @@ -1395,7 +1419,10 @@ 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 && auth_attempted) { + BLACKLIST_NOTIFY(the_active_state, BLACKLIST_AUTH_FAIL, + "Fatal exit"); _exit(EXIT_AUTH_ATTEMPTED); + } _exit(i); } --- sshd_config.5.orig 2025-10-02 12:00:00.000000000 +++ sshd_config.5 2025-10-02 12:00:00.000000000 @@ -2009,6 +2009,20 @@ is to never expire connections for having no open channels. This option may be useful in conjunction with .Cm ChannelTimeout . +.It Cm UseBlacklist +Specifies whether +.Xr sshd 8 +attempts to send authentication success and failure messages +to the +.Xr blacklistd 8 +daemon. +The default is +.Cm no . +For forward compatibility with an upcoming +.Xr blacklistd +rename, the +.Cm UseBlocklist +alias can be used instead. .It Cm UseDNS Specifies whether .Xr sshd 8 --- sshd_config.orig 2025-10-02 12:00:00.000000000 +++ sshd_config 2025-10-02 12:00:00.000000000 @@ -102,6 +102,7 @@ #MaxStartups 10:30:100 #PermitTunnel no #ChrootDirectory none +#UseBlacklist no #VersionAddendum none # no default banner path