Saturday, January 17, 2026

Re: Binary to read file /var/log/failedlogin

On Sat, Jan 17, 2026 at 03:58:28PM -0700, Todd C. Miller wrote:
> On Sun, 18 Jan 2026 11:38:06 +1300, Avon Robertson wrote:
>
> > Is there a base binary that can read file /var/log/failedlogin?
> >
> > If not, is there a ports package that can read it?
> >
> > TIA for your replies.
>
> That file is used by login(1) to report the last failed login but
> there isn't a separate program that uses it. One thing to be aware
> of is that it the info gets cleared after a successful login occurs.
>
> I hacked up the failedlogin.c code from login(1) so that a user's
> entry can be queried. It will only display something if the user
> has had bad login. Maybe this will help.
>
> For example:
>
> % sudo ./failedlogin millert
> Last unsuccessful login: Sat Jan 17 15:57:38 on tty00
>
> - todd
>
> /* $OpenBSD: failedlogin.c,v 1.19 2021/10/24 21:24:16 deraadt Exp $ */
>
> /*
> * Copyright (c) 1996 Todd C. Miller <millert@openbsd.org>
> *
> * Permission to use, copy, modify, and distribute this software for any
> * purpose with or without fee is hereby granted, provided that the above
> * copyright notice and this permission notice appear in all copies.
> *
> * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> */
>
> /*
> * failedlogin.c
> * Log to failedlogin file and read from it, reporting the number of
> * failed logins since the last good login and when/from where
> * the last failed login was.
> */
>
> #include <sys/stat.h>
> #include <sys/time.h>
>
> #include <err.h>
> #include <fcntl.h>
> #include <pwd.h>
> #include <stdio.h>
> #include <string.h>
> #include <unistd.h>
> #include <utmp.h>
>
> #define _PATH_FAILEDLOGIN "/var/log/failedlogin"
>
> struct badlogin {
> char bl_line[UT_LINESIZE]; /* tty used */
> char bl_name[UT_NAMESIZE]; /* remote username */
> char bl_host[UT_HOSTSIZE]; /* remote host */
> time_t bl_time; /* time of the login attempt */
> size_t count; /* number of bad logins */
> };
>
> /*
> * Check the failedlogin file and report about the number of unsuccessful
> * logins and info about the last one in lastlogin style.
> */
> static int
> check_failedlogin(const char *name, uid_t uid)
> {
> struct badlogin failedlogin;
> int fd, was_bad = 0;
>
> (void)memset(&failedlogin, 0, sizeof(failedlogin));
>
> if ((fd = open(_PATH_FAILEDLOGIN, O_RDONLY)) == -1)
> err(1, _PATH_FAILEDLOGIN);
> (void)lseek(fd, (off_t)uid * sizeof(failedlogin), SEEK_SET);
> if (read(fd, &failedlogin, sizeof(failedlogin)) == -1)
> err(1, _PATH_FAILEDLOGIN);
> if (failedlogin.count > 0 ) {
> /* There was a bad login */
> was_bad = 1;
> if (failedlogin.count > 1)
> (void)printf("There have been %lu unsuccessful "
> "login attempts for user %s.\n",
> (u_long)failedlogin.count, name);
> (void)printf("Last unsuccessful login: %.*s", 24-5,
> ctime(&failedlogin.bl_time));
> (void)printf(" on %.*s",
> (int)sizeof(failedlogin.bl_line),
> failedlogin.bl_line);
> if (*failedlogin.bl_host != '\0') {
> if (*failedlogin.bl_name != '\0')
> (void)printf(" from %.*s@%.*s",
> (int)sizeof(failedlogin.bl_name),
> failedlogin.bl_name,
> (int)sizeof(failedlogin.bl_host),
> failedlogin.bl_host);
> else
> (void)printf(" from %.*s",
> (int)sizeof(failedlogin.bl_host),
> failedlogin.bl_host);
> }
> (void)putchar('\n');
> }
> (void)close(fd);
>
> return(was_bad);
> }
>
> int
> main(int argc, char *argv[])
> {
> int i, ret = 0;
>
> for (i = 1; i < argc; i++) {
> uid_t uid;
> const char *name = argv[i];
> int status = uid_from_user(name, &uid);
> if (status != 0) {
> warnx("unknown user %s", name);
> ret = 1;
> continue;
> }
> check_failedlogin(name, uid);
> }
>
> return ret;
> }

Thank you very much Todd!

Initially, I will use your code to check for attempted logins on my
home router.

--
aer

No comments:

Post a Comment