xref: /openbsd/usr.bin/login/failedlogin.c (revision 133306f0)
1 /*	$OpenBSD: failedlogin.c,v 1.9 2000/03/02 04:05:44 millert Exp $	*/
2 
3 /*
4  * Copyright (c) 1996 Todd C. Miller <Todd.Miller@courtesan.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
21  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #ifndef lint
31 static char rcsid[] = "$OpenBSD: failedlogin.c,v 1.9 2000/03/02 04:05:44 millert Exp $";
32 #endif /* not lint */
33 
34 /*
35  * failedlogin.c
36  *	Log to failedlogin file and read from it, reporting the number of
37  *	failed logins since the last good login and when/from where
38  *	the last failed login was.
39  */
40 
41 #include <sys/param.h>
42 #include <sys/stat.h>
43 #include <sys/time.h>
44 
45 #include <fcntl.h>
46 #include <stdio.h>
47 #include <string.h>
48 #include <unistd.h>
49 #include <utmp.h>
50 
51 #include "pathnames.h"
52 
53 struct badlogin {
54 	char	bl_line[UT_LINESIZE];	/* tty used */
55 	char	bl_name[UT_NAMESIZE];	/* remote username */
56 	char	bl_host[UT_HOSTSIZE];	/* remote host */
57 	time_t	bl_time;		/* time of the login attempt */
58 	size_t	count;			/* number of bad logins */
59 };
60 
61 /*
62  * Log a bad login to the failedlogin file.
63  */
64 void
65 log_failedlogin(uid, host, name, tty)
66 	uid_t uid;
67 	char *host, *name, *tty;
68 {
69 	struct badlogin failedlogin;
70 	int fd;
71 
72 	/* Add O_CREAT if you want to create failedlogin if it doesn't exist */
73 	if ((fd = open(_PATH_FAILEDLOGIN, O_RDWR, S_IREAD|S_IWRITE)) >= 0) {
74 		(void)lseek(fd, (off_t)uid * sizeof(failedlogin), SEEK_SET);
75 
76 		/* Read in last bad login so can get the count */
77 		if (read(fd, (char *)&failedlogin, sizeof(failedlogin)) !=
78 			sizeof(failedlogin) || failedlogin.bl_time == 0)
79 			memset((void *)&failedlogin, 0, sizeof(failedlogin));
80 
81 		(void)lseek(fd, (off_t)uid * sizeof(failedlogin), SEEK_SET);
82 		/* Increment count of bad logins */
83 		++failedlogin.count;
84 		(void)time(&failedlogin.bl_time);
85 		strncpy(failedlogin.bl_line, tty, sizeof(failedlogin.bl_line));
86 		if (host)
87 			strncpy(failedlogin.bl_host, host, sizeof(failedlogin.bl_host));
88 		else
89 			*failedlogin.bl_host = '\0';	/* NULL host field */
90 		if (name)
91 			strncpy(failedlogin.bl_name, name, sizeof(failedlogin.bl_name));
92 		else
93 			*failedlogin.bl_name = '\0';	/* NULL name field */
94 		(void)write(fd, (char *)&failedlogin, sizeof(failedlogin));
95 		(void)close(fd);
96 	}
97 }
98 
99 /*
100  * Check the failedlogin file and report about the number of unsuccessful
101  * logins and info about the last one in lastlogin style.
102  * NOTE: zeros the count field since this is assumed to be called after the
103  * user has been validated.
104  */
105 int
106 check_failedlogin(uid)
107 	uid_t uid;
108 {
109 	int fd;
110 	struct badlogin failedlogin;
111 	int was_bad = 0;
112 
113 	(void)memset((void *)&failedlogin, 0, sizeof(failedlogin));
114 
115 	if ((fd = open(_PATH_FAILEDLOGIN, O_RDWR, 0)) >= 0) {
116 		(void)lseek(fd, (off_t)uid * sizeof(failedlogin), SEEK_SET);
117 		if (read(fd, (char *)&failedlogin, sizeof(failedlogin)) ==
118 		    sizeof(failedlogin) && failedlogin.count > 0 ) {
119 			/* There was a bad login */
120 			was_bad = 1;
121 			if (failedlogin.count > 1)
122 				(void)printf("There have been %lu unsuccessful "
123 				    "login attempts to your account.\n",
124 				    (u_long)failedlogin.count);
125 			(void)printf("Last unsuccessful login: %.*s", 24-5,
126 				(char *)ctime(&failedlogin.bl_time));
127 			(void)printf(" on %.*s",
128 			    (int)sizeof(failedlogin.bl_line),
129 			    failedlogin.bl_line);
130 			if (*failedlogin.bl_host != '\0') {
131 				if (*failedlogin.bl_name != '\0')
132 					(void)printf(" from %.*s@%.*s",
133 					    (int)sizeof(failedlogin.bl_name),
134 					    failedlogin.bl_name,
135 					    (int)sizeof(failedlogin.bl_host),
136 					    failedlogin.bl_host);
137 				else
138 					(void)printf(" from %.*s",
139 					    (int)sizeof(failedlogin.bl_host),
140 					    failedlogin.bl_host);
141 			}
142 			(void)putchar('\n');
143 
144 			/* Reset since this is a good login and write record */
145 			failedlogin.count = 0;
146 			(void)lseek(fd, (off_t)uid * sizeof(failedlogin),
147 			    SEEK_SET);
148 			(void)write(fd, (char *)&failedlogin,
149 			    sizeof(failedlogin));
150 		}
151 		(void)close(fd);
152 	}
153 	return(was_bad);
154 }
155