summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarren Tucker <dtucker@zip.com.au>2005-02-02 23:30:24 +1100
committerDarren Tucker <dtucker@zip.com.au>2005-02-02 23:30:24 +1100
commit2fba993080eba14e339d6a6666ee79580ee20f97 (patch)
tree0b7bc9ce53758047f3a844b0f9d5679ace5e94eb
parent9dc6c7dbec0716157e561036c480bca1bc3c7e47 (diff)
- (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@
-rw-r--r--ChangeLog7
-rw-r--r--auth.c5
-rw-r--r--canohost.c3
-rw-r--r--canohost.h2
-rw-r--r--configure.ac5
-rw-r--r--defines.h11
-rw-r--r--loginrec.c104
7 files changed, 130 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index d9670f36..07ae663d 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
@@ -2063,4 +2068,4 @@
- (djm) Trim deprecated options from INSTALL. Mention UsePAM
- (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu
-$Id: ChangeLog,v 1.3631 2005/02/02 07:30:33 dtucker Exp $
+$Id: ChangeLog,v 1.3632 2005/02/02 12:30:24 dtucker Exp $
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 94d6b1e7..86b26daf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-# $Id: configure.ac,v 1.236 2005/02/01 23:44:00 dtucker Exp $
+# $Id: configure.ac,v 1.237 2005/02/02 12:30:25 dtucker Exp $
#
# Copyright (c) 1999-2004 Damien Miller
#
@@ -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 8c1d9c40..4d59408a 100644
--- a/defines.h
+++ b/defines.h
@@ -25,7 +25,7 @@
#ifndef _DEFINES_H
#define _DEFINES_H
-/* $Id: defines.h,v 1.117 2004/06/22 03:27:16 dtucker Exp $ */
+/* $Id: defines.h,v 1.118 2005/02/02 12:30:25 dtucker Exp $ */
/* Constants */
@@ -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 25aa29f2..e77318ba 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 <util.h>
@@ -140,7 +163,7 @@
# include <libutil.h>
#endif
-RCSID("$Id: loginrec.c,v 1.62 2004/09/12 05:26:01 djm Exp $");
+RCSID("$Id: loginrec.c,v 1.63 2005/02/02 12:30:25 dtucker Exp $");
/**
** prototypes for helper functions in this file
@@ -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 */