From b6610e8f234a934706d4d2d3db17fe12488534e8 Mon Sep 17 00:00:00 2001 From: dtucker Date: Wed, 2 Feb 2005 12:30:24 +0000 Subject: [PATCH] - (dtucker) [auth.c canohost.c canohost.h configure.ac defines.h loginrec.c] Bug #974: Teach sshd to write failed login records to btmp for failed auth attempts (currently only for password, kbdint and C/R, only on Linux and HP-UX), based on code from login.c from util-linux. With ashok_kovai at hotmail.com, ok djm@ --- ChangeLog | 5 +++ auth.c | 5 ++- canohost.c | 3 +- canohost.h | 2 + configure.ac | 3 ++ defines.h | 9 +++++ loginrec.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 126 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 42fd4c34..1f676b5c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,11 @@ the process. Since we also unset KRB5CCNAME at startup, if it's set after authentication it must have been set by the platform's native auth system. This was already done for AIX; this enables it for the general case. + - (dtucker) [auth.c canohost.c canohost.h configure.ac defines.h loginrec.c] + Bug #974: Teach sshd to write failed login records to btmp for failed auth + attempts (currently only for password, kbdint and C/R, only on Linux and + HP-UX), based on code from login.c from util-linux. With ashok_kovai at + hotmail.com, ok djm@ 20050201 - (dtucker) [log.c] Bug #973: force log_init() to open syslog, since on some diff --git a/auth.c b/auth.c index dfc1be37..b6c00c12 100644 --- a/auth.c +++ b/auth.c @@ -244,7 +244,10 @@ auth_log(Authctxt *authctxt, int authenticated, char *method, char *info) info); #ifdef CUSTOM_FAILED_LOGIN - if (authenticated == 0 && strcmp(method, "password") == 0) + if (authenticated == 0 && !authctxt->postponed && + (strcmp(method, "password") == 0 || + strncmp(method, "keyboard-interactive", 20) == 0) || + strcmp(method, "challenge-response") == 0) record_failed_login(authctxt->user, get_canonical_hostname(options.use_dns), "ssh"); #endif diff --git a/canohost.c b/canohost.c index 8ad684d6..e5a6b6be 100644 --- a/canohost.c +++ b/canohost.c @@ -20,7 +20,6 @@ RCSID("$OpenBSD: canohost.c,v 1.41 2004/07/21 11:51:29 djm Exp $"); #include "canohost.h" static void check_ip_options(int, char *); -static void ipv64_normalise_mapped(struct sockaddr_storage *, socklen_t *); /* * Return the canonical name of the host at the other end of the socket. The @@ -166,7 +165,7 @@ check_ip_options(int sock, char *ipaddr) #endif /* IP_OPTIONS */ } -static void +void ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len) { struct sockaddr_in6 *a6 = (struct sockaddr_in6 *)addr; diff --git a/canohost.h b/canohost.h index 4347b488..df1f125e 100644 --- a/canohost.h +++ b/canohost.h @@ -23,3 +23,5 @@ char *get_local_name(int); int get_remote_port(void); int get_local_port(void); + +void ipv64_normalise_mapped(struct sockaddr_storage *, socklen_t *); diff --git a/configure.ac b/configure.ac index 99bbdf0e..136e6aec 100644 --- a/configure.ac +++ b/configure.ac @@ -219,6 +219,7 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) AC_DEFINE(DISABLE_UTMP) AC_DEFINE(LOCKED_PASSWD_STRING, "*") AC_DEFINE(SPT_TYPE,SPT_PSTAT) + AC_DEFINE(USE_BTMP, 1, [Use btmp to log bad logins]) check_for_hpux_broken_getaddrinfo=1 check_for_conflicting_getspnam=1 LIBS="$LIBS -lsec" @@ -256,6 +257,8 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) AC_DEFINE(LOCKED_PASSWD_PREFIX, "!") AC_DEFINE(SPT_TYPE,SPT_REUSEARGV) AC_DEFINE(LINK_OPNOTSUPP_ERRNO, EPERM) + AC_DEFINE(_PATH_BTMP, "/var/log/btmp", [log for bad login attempts]) + AC_DEFINE(USE_BTMP, 1, [Use btmp to log bad logins]) inet6_default_4in6=yes case `uname -r` in 1.*|2.0.*) diff --git a/defines.h b/defines.h index b21235fd..d83be080 100644 --- a/defines.h +++ b/defines.h @@ -644,6 +644,15 @@ struct winsize { # define CUSTOM_SYS_AUTH_PASSWD 1 #endif +/* HP-UX 11.11 */ +#ifdef BTMP_FILE +# define _PATH_BTMP BTMP_FILE +#endif + +#if defined(USE_BTMP) && defined(_PATH_BTMP) +# define CUSTOM_FAILED_LOGIN +#endif + /** end of login recorder definitions */ #endif /* _DEFINES_H */ diff --git a/loginrec.c b/loginrec.c index b1c4d297..491b7afb 100644 --- a/loginrec.c +++ b/loginrec.c @@ -25,6 +25,27 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* + * The btmp logging code is derived from login.c from util-linux and is under + * the the following license: + * + * Copyright (c) 1980, 1987, 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + + /** ** loginrec.c: platform-independent login recording and lastlog retrieval **/ @@ -131,6 +152,8 @@ #include "loginrec.h" #include "log.h" #include "atomicio.h" +#include "packet.h" +#include "canohost.h" #ifdef HAVE_UTIL_H # include @@ -1563,3 +1586,82 @@ lastlog_get_entry(struct logininfo *li) return (0); } #endif /* USE_LASTLOG */ + +#ifdef USE_BTMP + /* + * Logs failed login attempts in _PATH_BTMP if that exists. + * The most common login failure is to give password instead of username. + * So the _PATH_BTMP file checked for the correct permission, so that + * only root can read it. + */ + +void +record_failed_login(const char *username, const char *hostname, + const char *ttyn) +{ + int fd; + struct utmp ut; + struct sockaddr_storage from; + size_t fromlen = sizeof(from); + struct sockaddr_in *a4; + struct sockaddr_in6 *a6; + time_t t; + struct stat fst; + + if (geteuid() != 0) + return; + if ((fd = open(_PATH_BTMP, O_WRONLY | O_APPEND)) < 0) { + debug("Unable to open the btmp file %s: %s", _PATH_BTMP, + strerror(errno)); + return; + } + if (fstat(fd, &fst) < 0) { + logit("%s: fstat of %s failed: %s", __func__, _PATH_BTMP, + strerror(errno)); + goto out; + } + if((fst.st_mode & (S_IRWXG | S_IRWXO)) || (fst.st_uid != 0)){ + logit("Excess permission or bad ownership on file %s", + _PATH_BTMP); + goto out; + } + + memset(&ut, 0, sizeof(ut)); + /* strncpy because we don't necessarily want nul termination */ + strncpy(ut.ut_user, username, sizeof(ut.ut_user)); + strlcpy(ut.ut_line, "ssh:notty", sizeof(ut.ut_line)); + + time(&t); + ut.ut_time = t; /* ut_time is not always a time_t */ + ut.ut_type = LOGIN_PROCESS; + ut.ut_pid = getpid(); + + /* strncpy because we don't necessarily want nul termination */ + strncpy(ut.ut_host, hostname, sizeof(ut.ut_host)); + + if (packet_connection_is_on_socket() && + getpeername(packet_get_connection_in(), + (struct sockaddr *)&from, &fromlen) == 0) { + ipv64_normalise_mapped(&from, &fromlen); + if (from.ss_family == AF_INET) { + a4 = (struct sockaddr_in *)&from; + memcpy(&ut.ut_addr, &(a4->sin_addr), + MIN_SIZEOF(ut.ut_addr, a4->sin_addr)); + } +#ifdef HAVE_ADDR_V6_IN_UTMP + if (from.ss_family == AF_INET6) { + a6 = (struct sockaddr_in6 *)&from; + memcpy(&ut.ut_addr_v6, &(a6->sin6_addr), + MIN_SIZEOF(ut.ut_addr_v6, a6->sin6_addr)); + } +#endif + } + + if (atomicio(vwrite, fd, &ut, sizeof(ut)) != sizeof(ut)) + error("Failed to write to %s: %s", _PATH_BTMP, + strerror(errno)); + +out: + close(fd); +} +#endif /* USE_BTMP */ -- 2.45.2