1 /* $OpenBSD: failedlogin.c,v 1.19 2021/10/24 21:24:16 deraadt Exp $ */
2
3 /*
4 * Copyright (c) 1996 Todd C. Miller <millert@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /*
20 * failedlogin.c
21 * Log to failedlogin file and read from it, reporting the number of
22 * failed logins since the last good login and when/from where
23 * the last failed login was.
24 */
25
26 #include <sys/stat.h>
27 #include <sys/time.h>
28
29 #include <fcntl.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <utmp.h>
34
35 #include "pathnames.h"
36
37 struct badlogin {
38 char bl_line[UT_LINESIZE]; /* tty used */
39 char bl_name[UT_NAMESIZE]; /* remote username */
40 char bl_host[UT_HOSTSIZE]; /* remote host */
41 time_t bl_time; /* time of the login attempt */
42 size_t count; /* number of bad logins */
43 };
44
45 void log_failedlogin(uid_t, char *, char *, char *);
46 int check_failedlogin(uid_t);
47
48 /*
49 * Log a bad login to the failedlogin file.
50 */
51 void
log_failedlogin(uid_t uid,char * host,char * name,char * tty)52 log_failedlogin(uid_t uid, char *host, char *name, char *tty)
53 {
54 struct badlogin failedlogin;
55 int fd;
56
57 /* Add O_CREAT if you want to create failedlogin if it doesn't exist */
58 if ((fd = open(_PATH_FAILEDLOGIN, O_RDWR)) >= 0) {
59 (void)lseek(fd, (off_t)uid * sizeof(failedlogin), SEEK_SET);
60
61 /* Read in last bad login so can get the count */
62 if (read(fd, (char *)&failedlogin, sizeof(failedlogin)) !=
63 sizeof(failedlogin) || failedlogin.bl_time == 0)
64 memset((void *)&failedlogin, 0, sizeof(failedlogin));
65
66 (void)lseek(fd, (off_t)uid * sizeof(failedlogin), SEEK_SET);
67 /* Increment count of bad logins */
68 ++failedlogin.count;
69 (void)time(&failedlogin.bl_time);
70 strncpy(failedlogin.bl_line, tty, sizeof(failedlogin.bl_line));
71 if (host)
72 strncpy(failedlogin.bl_host, host, sizeof(failedlogin.bl_host));
73 else
74 *failedlogin.bl_host = '\0'; /* NULL host field */
75 if (name)
76 strncpy(failedlogin.bl_name, name, sizeof(failedlogin.bl_name));
77 else
78 *failedlogin.bl_name = '\0'; /* NULL name field */
79 (void)write(fd, (char *)&failedlogin, sizeof(failedlogin));
80 (void)close(fd);
81 }
82 }
83
84 /*
85 * Check the failedlogin file and report about the number of unsuccessful
86 * logins and info about the last one in lastlogin style.
87 * NOTE: zeros the count field since this is assumed to be called after the
88 * user has been validated.
89 */
90 int
check_failedlogin(uid_t uid)91 check_failedlogin(uid_t uid)
92 {
93 struct badlogin failedlogin;
94 int fd, was_bad = 0;
95
96 (void)memset((void *)&failedlogin, 0, sizeof(failedlogin));
97
98 if ((fd = open(_PATH_FAILEDLOGIN, O_RDWR)) >= 0) {
99 (void)lseek(fd, (off_t)uid * sizeof(failedlogin), SEEK_SET);
100 if (read(fd, (char *)&failedlogin, sizeof(failedlogin)) ==
101 sizeof(failedlogin) && failedlogin.count > 0 ) {
102 /* There was a bad login */
103 was_bad = 1;
104 if (failedlogin.count > 1)
105 (void)printf("There have been %lu unsuccessful "
106 "login attempts to your account.\n",
107 (u_long)failedlogin.count);
108 (void)printf("Last unsuccessful login: %.*s", 24-5,
109 (char *)ctime(&failedlogin.bl_time));
110 (void)printf(" on %.*s",
111 (int)sizeof(failedlogin.bl_line),
112 failedlogin.bl_line);
113 if (*failedlogin.bl_host != '\0') {
114 if (*failedlogin.bl_name != '\0')
115 (void)printf(" from %.*s@%.*s",
116 (int)sizeof(failedlogin.bl_name),
117 failedlogin.bl_name,
118 (int)sizeof(failedlogin.bl_host),
119 failedlogin.bl_host);
120 else
121 (void)printf(" from %.*s",
122 (int)sizeof(failedlogin.bl_host),
123 failedlogin.bl_host);
124 }
125 (void)putchar('\n');
126
127 /* Reset since this is a good login and write record */
128 failedlogin.count = 0;
129 (void)lseek(fd, (off_t)uid * sizeof(failedlogin),
130 SEEK_SET);
131 (void)write(fd, (char *)&failedlogin,
132 sizeof(failedlogin));
133 }
134 (void)close(fd);
135 }
136 return(was_bad);
137 }
138