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

Reply via email to