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