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 <[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;
> }

Thank you very much Todd!

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

-- 
aer

Reply via email to