1 |
|
|
/* $OpenBSD: failedlogin.c,v 1.17 2015/01/16 06:40:09 deraadt Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 1996 Todd C. Miller <Todd.Miller@courtesan.com> |
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 |
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, S_IRUSR|S_IWUSR)) >= 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 |
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)) >= 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 |
|
|
} |