]> granicus.if.org Git - shadow/blob - src/faillog.c
[svn-upgrade] Integrating new upstream version, shadow (4.0.10)
[shadow] / src / faillog.c
1 /*
2  * Copyright 1989 - 1993, Julianne Frances Haugh
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <config.h>
31
32 #include "rcsid.h"
33 RCSID (PKG_VER "$Id: faillog.c,v 1.23 2005/05/25 19:31:51 kloczek Exp $")
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <stdio.h>
37 #include <pwd.h>
38 #include <time.h>
39 #include <getopt.h>
40 #include "prototypes.h"
41 #include "defines.h"
42 #include "faillog.h"
43 static FILE *fail;              /* failure file stream */
44 static uid_t user;              /* one single user, specified on command line */
45 static int days;                /* number of days to consider for print command */
46 static time_t seconds;          /* that number of days in seconds */
47
48 static int
49  aflg = 0,                      /* set if all users are to be printed always */
50     uflg = 0,                   /* set if user is a valid user id */
51     tflg = 0;                   /* print is restricted to most recent days */
52
53 static struct stat statbuf;     /* fstat buffer for file size */
54
55 #define NOW     (time((time_t *) 0))
56
57 static void usage (void)
58 {
59         fprintf (stderr, _("Usage: faillog [options]\n"
60                            "\n"
61                            "Options:\n"
62                            "  -a, --all                 display faillog records for all users\n"
63                            "  -h, --help                        display this help message and exit\n"
64                            "  -l, --lock-time SEC               after failed login lock accout to SEC seconds\n"
65                            "  -m, --maximum MAX         set maximum failed login counters to MAX\n"
66                            "  -r, --reset                       reset the counters of login failures\n"
67                            "  -t, --time DAYS           display faillog records more recent than DAYS\n"
68                            "  -u, --user LOGIN          display faillog record or maintains failure counters\n"
69                            "                            and limits (if used with -r, -m or -l options) only\n"
70                            "                            for user with LOGIN\n"));
71         exit (1);
72 }
73
74 static void print_one (const struct faillog *fl, uid_t uid)
75 {
76         static int once;
77         char *cp;
78         struct tm *tm;
79         time_t now;
80         struct passwd *pwent;
81
82 #ifdef HAVE_STRFTIME
83         char ptime[80];
84 #endif
85
86         if (!once) {
87                 printf (_
88                         ("Login       Failures Maximum Latest                   On\n"));
89                 once++;
90         }
91         pwent = getpwuid (uid);
92         time (&now);
93         tm = localtime (&fl->fail_time);
94 #ifdef HAVE_STRFTIME
95         strftime (ptime, sizeof (ptime), "%D %H:%M:%S %z", tm);
96         cp = ptime;
97 #endif
98         if (pwent) {
99                 printf ("%-9s   %5d    %5d   ",
100                         pwent->pw_name, fl->fail_cnt, fl->fail_max);
101                 if (fl->fail_time) {
102                         printf ("%s  %s", cp, fl->fail_line);
103                         if (fl->fail_locktime) {
104                                 if (fl->fail_time + fl->fail_locktime > now
105                                     && fl->fail_cnt)
106                                         printf (_(" [%lds left]"),
107                                                 fl->fail_time +
108                                                 fl->fail_locktime - now);
109                                 else
110                                         printf (_(" [%lds lock]"),
111                                                 fl->fail_locktime);
112                         }
113                 }
114                 putchar ('\n');
115         }
116 }
117
118 static int reset_one (uid_t uid)
119 {
120         off_t offset;
121         struct faillog faillog;
122
123         offset = uid * sizeof faillog;
124         if (fstat (fileno (fail), &statbuf)) {
125                 perror (FAILLOG_FILE);
126                 return 0;
127         }
128         if (offset >= statbuf.st_size)
129                 return 0;
130
131         if (fseeko (fail, offset, SEEK_SET) != 0) {
132                 perror (FAILLOG_FILE);
133                 return 0;
134         }
135         if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) {
136                 if (!feof (fail))
137                         perror (FAILLOG_FILE);
138
139                 return 0;
140         }
141         if (faillog.fail_cnt == 0)
142                 return 1;       /* don't fill in no holes ... */
143
144         faillog.fail_cnt = 0;
145
146         if (fseeko (fail, offset, SEEK_SET) == 0
147             && fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1) {
148                 fflush (fail);
149                 return 1;
150         } else {
151                 perror (FAILLOG_FILE);
152         }
153         return 0;
154 }
155
156 static void reset (void)
157 {
158         uid_t uid;
159
160         if (uflg)
161                 reset_one (user);
162         else
163                 for (uid = 0; reset_one (uid); uid++);
164 }
165
166 static void print (void)
167 {
168         uid_t uid;
169         off_t offset;
170         struct faillog faillog;
171
172         if (uflg) {
173                 offset = user * sizeof faillog;
174                 if (fstat (fileno (fail), &statbuf)) {
175                         perror (FAILLOG_FILE);
176                         return;
177                 }
178                 if (offset >= statbuf.st_size)
179                         return;
180
181                 fseeko (fail, (off_t) user * sizeof faillog, SEEK_SET);
182                 if (fread ((char *) &faillog, sizeof faillog, 1, fail) == 1)
183                         print_one (&faillog, user);
184                 else
185                         perror (FAILLOG_FILE);
186         } else {
187                 for (uid = 0;
188                      fread ((char *) &faillog, sizeof faillog, 1,
189                             fail) == 1; uid++) {
190
191                         if (aflg == 0 && faillog.fail_cnt == 0)
192                                 continue;
193
194                         if (aflg == 0 && tflg &&
195                             NOW - faillog.fail_time > seconds)
196                                 continue;
197
198                         if (aflg && faillog.fail_time == 0)
199                                 continue;
200
201                         print_one (&faillog, uid);
202                 }
203         }
204 }
205
206 static void setmax_one (uid_t uid, int max)
207 {
208         off_t offset;
209         struct faillog faillog;
210
211         offset = uid * sizeof faillog;
212
213         if (fseeko (fail, offset, SEEK_SET) != 0) {
214                 perror (FAILLOG_FILE);
215                 return;
216         }
217         if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) {
218                 if (!feof (fail))
219                         perror (FAILLOG_FILE);
220                 memzero (&faillog, sizeof faillog);
221         }
222         faillog.fail_max = max;
223
224         if (fseeko (fail, offset, SEEK_SET) == 0
225             && fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1)
226                 fflush (fail);
227         else
228                 perror (FAILLOG_FILE);
229 }
230
231 static void setmax (int max)
232 {
233         struct passwd *pwent;
234
235         if (uflg) {
236                 setmax_one (user, max);
237         } else {
238                 setpwent ();
239                 while ((pwent = getpwent ()))
240                         setmax_one (pwent->pw_uid, max);
241         }
242 }
243
244 static void set_locktime_one (uid_t uid, long locktime)
245 {
246         off_t offset;
247         struct faillog faillog;
248
249         offset = uid * sizeof faillog;
250
251         if (fseeko (fail, offset, SEEK_SET) != 0) {
252                 perror (FAILLOG_FILE);
253                 return;
254         }
255         if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) {
256                 if (!feof (fail))
257                         perror (FAILLOG_FILE);
258                 memzero (&faillog, sizeof faillog);
259         }
260         faillog.fail_locktime = locktime;
261
262         if (fseeko (fail, offset, SEEK_SET) == 0
263             && fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1)
264                 fflush (fail);
265         else
266                 perror (FAILLOG_FILE);
267 }
268
269 /*
270  * XXX - this needs to be written properly some day, right now it is
271  * a quick cut-and-paste hack from the above two functions.  --marekm
272  */
273 static void set_locktime (long locktime)
274 {
275         struct passwd *pwent;
276
277         if (uflg) {
278                 set_locktime_one (user, locktime);
279         } else {
280                 setpwent ();
281                 while ((pwent = getpwent ()))
282                         set_locktime_one (pwent->pw_uid, locktime);
283         }
284 }
285
286 int main (int argc, char **argv)
287 {
288         int anyflag = 0;
289         struct passwd *pwent;
290
291         setlocale (LC_ALL, "");
292         bindtextdomain (PACKAGE, LOCALEDIR);
293         textdomain (PACKAGE);
294
295         /* try to open for read/write, if that fails - read only */
296         fail = fopen (FAILLOG_FILE, "r+");
297         if (!fail)
298                 fail = fopen (FAILLOG_FILE, "r");
299         if (!fail) {
300                 perror (FAILLOG_FILE);
301                 exit (1);
302         }
303
304         {
305                 int option_index = 0;
306                 int c;
307                 static struct option long_options[] = {
308                         {"all", no_argument, NULL, 'a'},
309                         {"help", no_argument, NULL, 'h'},
310                         {"lock-secs", no_argument, NULL, 'l'},
311                         {"maximum", no_argument, NULL, 'm'},
312                         {"reset", no_argument, NULL, 'r'},
313                         {"time", no_argument, NULL, 't'},
314                         {"user", no_argument, NULL, 'u'},
315                         {NULL, 0, NULL, '\0'}
316                 };
317
318                 while ((c =
319                         getopt_long (argc, argv, "ahl:m:rt:u:",
320                                      long_options, &option_index)) != -1) {
321                         switch (c) {
322                         case 'a':
323                                 aflg++;
324                                 if (uflg)
325                                         usage ();
326                                 break;
327                         case 'h':
328                                 usage ();
329                                 break;
330                         case 'l':
331                                 set_locktime ((long) atoi (optarg));
332                                 anyflag++;
333                                 break;
334                         case 'm':
335                                 setmax (atoi (optarg));
336                                 anyflag++;
337                                 break;
338                         case 'r':
339                                 reset ();
340                                 anyflag++;
341                                 break;
342                         case 't':
343                                 days = atoi (optarg);
344                                 seconds = days * DAY;
345                                 tflg++;
346                                 break;
347                         case 'u':
348                                 if (aflg)
349                                         usage ();
350
351                                 pwent = getpwnam (optarg);
352                                 if (!pwent) {
353                                         fprintf (stderr,
354                                                  _("Unknown User: %s\n"),
355                                                  optarg);
356                                         exit (1);
357                                 }
358                                 uflg++;
359                                 user = pwent->pw_uid;
360                                 break;
361                         default:
362                                 usage ();
363                         }
364                 }
365         }
366
367         /* no flags implies -a -p (= print information for all users)  */
368         if (!(anyflag || aflg || tflg || uflg))
369                 aflg++;
370         /* (-a or -t days or -u user) and no other flags implies -p
371            (= print information for selected users) */
372         if (!anyflag && (aflg || tflg || uflg))
373                 print ();
374         fclose (fail);
375         return 0;
376 }