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 <[email protected]>
*
* 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;
}