7 /* By Tim Baverstock <warwick@mmm.co.uk>, Multi Media Machine Ltd.
10 * Stuff stolen from pam_rootok and pam_listfile
12 * Changes by Tomas Mraz <tmraz@redhat.com> 5 January 2005, 26 January 2006
13 * Audit option added for Tomas patch by Sebastien Tricaud <toady@gscore.org> 13 January 2005
14 * Portions Copyright 2006, Red Hat, Inc.
15 * Portions Copyright 1989 - 1993, Julianne Frances Haugh
16 * All rights reserved.
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution.
26 * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
27 * may be used to endorse or promote products derived from this software
28 * without specific prior written permission.
30 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 #if defined(MAIN) && defined(MEMORY_DEBUG)
47 #endif /* defined(MAIN) && defined(MEMORY_DEBUG) */
63 #include <sys/types.h>
65 #include <sys/param.h>
78 * here, we make a definition for the externally accessible function
79 * in this file (this definition is required for static a module
80 * but strongly encouraged generally) it is used to instruct the
81 * modules include file to define the function prototypes.
86 #define PAM_SM_ACCOUNT
87 /* #define PAM_SM_SESSION */
88 /* #define PAM_SM_PASSWORD */
90 #include <security/pam_modutil.h>
91 #include <security/pam_ext.h>
93 #include <security/pam_modules.h>
95 /*---------------------------------------------------------------------*/
97 #define DEFAULT_LOGFILE "/var/log/tallylog"
98 #define MODULE_NAME "pam_tally2"
100 #define tally_t uint16_t
101 #define TALLY_HI ((tally_t)~0L)
103 struct tally_options {
104 const char *filename;
108 long root_unlock_time;
112 #define PHASE_UNKNOWN 0
114 #define PHASE_ACCOUNT 2
115 #define PHASE_SESSION 3
117 #define OPT_MAGIC_ROOT 01
118 #define OPT_FAIL_ON_ERROR 02
119 #define OPT_DENY_ROOT 04
120 #define OPT_QUIET 040
121 #define OPT_AUDIT 0100
122 #define OPT_NOLOGNOTICE 0400
125 /*---------------------------------------------------------------------*/
127 /* some syslogging */
130 #define pam_syslog tally_log
132 tally_log (const pam_handle_t *pamh UNUSED, int priority UNUSED,
133 const char *fmt, ...)
138 fprintf(stderr, "%s: ", MODULE_NAME);
139 vfprintf(stderr, fmt, args);
140 fprintf(stderr,"\n");
144 #define pam_modutil_getpwnam(pamh, user) getpwnam(user)
147 /*---------------------------------------------------------------------*/
149 /* --- Support function: parse arguments --- */
154 log_phase_no_auth(pam_handle_t *pamh, int phase, const char *argv)
156 if ( phase != PHASE_AUTH ) {
157 pam_syslog(pamh, LOG_ERR,
158 "option %s allowed in auth phase only", argv);
163 tally_parse_args(pam_handle_t *pamh, struct tally_options *opts,
164 int phase, int argc, const char **argv)
166 memset(opts, 0, sizeof(*opts));
167 opts->filename = DEFAULT_LOGFILE;
168 opts->ctrl = OPT_FAIL_ON_ERROR;
169 opts->root_unlock_time = -1;
171 for ( ; argc-- > 0; ++argv ) {
173 if ( ! strncmp( *argv, "file=", 5 ) ) {
174 const char *from = *argv + 5;
176 pam_syslog(pamh, LOG_ERR,
177 "filename not /rooted; %s", *argv);
180 opts->filename = from;
182 else if ( ! strcmp( *argv, "onerr=fail" ) ) {
183 opts->ctrl |= OPT_FAIL_ON_ERROR;
185 else if ( ! strcmp( *argv, "onerr=succeed" ) ) {
186 opts->ctrl &= ~OPT_FAIL_ON_ERROR;
188 else if ( ! strcmp( *argv, "magic_root" ) ) {
189 opts->ctrl |= OPT_MAGIC_ROOT;
191 else if ( ! strcmp( *argv, "even_deny_root_account" ) ||
192 ! strcmp( *argv, "even_deny_root" ) ) {
193 log_phase_no_auth(pamh, phase, *argv);
194 opts->ctrl |= OPT_DENY_ROOT;
196 else if ( ! strncmp( *argv, "deny=", 5 ) ) {
197 log_phase_no_auth(pamh, phase, *argv);
198 if ( sscanf((*argv)+5,"%hu",&opts->deny) != 1 ) {
199 pam_syslog(pamh, LOG_ERR, "bad number supplied: %s", *argv);
203 else if ( ! strncmp( *argv, "lock_time=", 10 ) ) {
204 log_phase_no_auth(pamh, phase, *argv);
205 if ( sscanf((*argv)+10,"%ld",&opts->lock_time) != 1 ) {
206 pam_syslog(pamh, LOG_ERR, "bad number supplied: %s", *argv);
210 else if ( ! strncmp( *argv, "unlock_time=", 12 ) ) {
211 log_phase_no_auth(pamh, phase, *argv);
212 if ( sscanf((*argv)+12,"%ld",&opts->unlock_time) != 1 ) {
213 pam_syslog(pamh, LOG_ERR, "bad number supplied: %s", *argv);
217 else if ( ! strncmp( *argv, "root_unlock_time=", 17 ) ) {
218 log_phase_no_auth(pamh, phase, *argv);
219 if ( sscanf((*argv)+17,"%ld",&opts->root_unlock_time) != 1 ) {
220 pam_syslog(pamh, LOG_ERR, "bad number supplied: %s", *argv);
223 opts->ctrl |= OPT_DENY_ROOT; /* even_deny_root implied */
225 else if ( ! strcmp( *argv, "quiet" ) ||
226 ! strcmp ( *argv, "silent")) {
227 opts->ctrl |= OPT_QUIET;
229 else if ( ! strcmp ( *argv, "no_log_info") ) {
230 opts->ctrl |= OPT_NOLOGNOTICE;
232 else if ( ! strcmp ( *argv, "audit") ) {
233 opts->ctrl |= OPT_AUDIT;
236 pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
240 if (opts->root_unlock_time == -1)
241 opts->root_unlock_time = opts->unlock_time;
246 #endif /* #ifndef MAIN */
248 /*---------------------------------------------------------------------*/
250 /* --- Support function: get uid (and optionally username) from PAM or
254 static char *cline_user=0; /* cline_user is used in the administration prog */
258 pam_get_uid(pam_handle_t *pamh, uid_t *uid, const char **userp, struct tally_options *opts)
260 const char *user = NULL;
266 if ((pam_get_user( pamh, &user, NULL )) != PAM_SUCCESS) {
271 if ( !user || !*user ) {
272 pam_syslog(pamh, LOG_ERR, "pam_get_uid; user?");
276 if ( ! ( pw = pam_modutil_getpwnam( pamh, user ) ) ) {
277 opts->ctrl & OPT_AUDIT ?
278 pam_syslog(pamh, LOG_ERR, "pam_get_uid; no such user %s", user) :
279 pam_syslog(pamh, LOG_ERR, "pam_get_uid; no such user");
280 return PAM_USER_UNKNOWN;
283 if ( uid ) *uid = pw->pw_uid;
284 if ( userp ) *userp = user;
288 /*---------------------------------------------------------------------*/
290 /* --- Support functions: set/get tally data --- */
295 _cleanup(pam_handle_t *pamh UNUSED, void *data, int error_status UNUSED)
302 tally_set_data( pam_handle_t *pamh, time_t oldtime )
306 if ( (data=malloc(sizeof(time_t))) != NULL ) {
308 pam_set_data(pamh, MODULE_NAME, (void *)data, _cleanup);
313 tally_get_data( pam_handle_t *pamh, time_t *oldtime )
318 rv = pam_get_data(pamh, MODULE_NAME, &data);
319 if ( rv == PAM_SUCCESS && data != NULL && oldtime != NULL ) {
320 *oldtime = *(const time_t *)data;
321 pam_set_data(pamh, MODULE_NAME, NULL, NULL);
329 #endif /* #ifndef MAIN */
331 /*---------------------------------------------------------------------*/
333 /* --- Support function: open/create tallyfile and return tally for uid --- */
335 /* If on entry tallyfile doesn't exist, creation is attempted. */
338 get_tally(pam_handle_t *pamh, uid_t uid, const char *filename,
339 FILE **tfile, struct tallylog *tally)
341 struct stat fileinfo;
344 lstat_ret = lstat(filename, &fileinfo);
347 int oldmask = umask(077);
348 *tfile=fopen(filename, "a");
350 /* Create file, or append-open in pathological case. */
354 if (save_errno == EACCES) {
355 return PAM_IGNORE; /* called with insufficient access rights */
359 pam_syslog(pamh, LOG_ALERT, "Couldn't create %s: %m", filename);
362 lstat_ret = fstat(fileno(*tfile),&fileinfo);
368 pam_syslog(pamh, LOG_ALERT, "Couldn't stat %s", filename);
372 if ((fileinfo.st_mode & S_IWOTH) || !S_ISREG(fileinfo.st_mode)) {
373 /* If the file is world writable or is not a
374 normal file, return error */
375 pam_syslog(pamh, LOG_ALERT,
376 "%s is either world writable or not a normal file",
381 if (!(*tfile = fopen(filename, "r+"))) {
383 if (errno == EACCES) /* called with insufficient access rights */
386 pam_syslog(pamh, LOG_ALERT, "Error opening %s for update: %m", filename);
391 if (fseeko(*tfile, (off_t)uid*(off_t)sizeof(*tally), SEEK_SET)) {
392 pam_syslog(pamh, LOG_ALERT, "fseek failed for %s: %m", filename);
398 if (fileinfo.st_size < (off_t)(uid+1)*(off_t)sizeof(*tally)) {
399 memset(tally, 0, sizeof(*tally));
400 } else if (fread(tally, sizeof(*tally), 1, *tfile) == 0) {
401 memset(tally, 0, sizeof(*tally));
402 /* Shouldn't happen */
405 tally->fail_line[sizeof(tally->fail_line)-1] = '\0';
410 /*---------------------------------------------------------------------*/
412 /* --- Support function: update and close tallyfile with tally!=TALLY_HI --- */
415 set_tally(pam_handle_t *pamh, uid_t uid,
416 const char *filename, FILE **tfile, struct tallylog *tally)
418 if (tally->fail_cnt != TALLY_HI) {
419 if (fseeko(*tfile, (off_t)uid * sizeof(*tally), SEEK_SET)) {
420 pam_syslog(pamh, LOG_ALERT, "fseek failed for %s: %m", filename);
423 if (fwrite(tally, sizeof(*tally), 1, *tfile) == 0) {
424 pam_syslog(pamh, LOG_ALERT, "update (fwrite) failed for %s: %m", filename);
429 if (fclose(*tfile)) {
431 pam_syslog(pamh, LOG_ALERT, "update (fclose) failed for %s: %m", filename);
438 /*---------------------------------------------------------------------*/
440 /* --- PAM bits --- */
444 #define RETURN_ERROR(i) return ((opts->ctrl & OPT_FAIL_ON_ERROR)?(i):(PAM_SUCCESS))
446 /*---------------------------------------------------------------------*/
449 tally_check (tally_t oldcnt, time_t oldtime, pam_handle_t *pamh, uid_t uid,
450 const char *user, struct tally_options *opts,
451 struct tallylog *tally)
453 int rv = PAM_SUCCESS;
459 if ((opts->ctrl & OPT_MAGIC_ROOT) && getuid() == 0) {
462 /* magic_root skips tally check */
464 audit_fd = audit_open();
465 /* If there is an error & audit support is in the kernel report error */
466 if ((audit_fd < 0) && !(errno == EINVAL || errno == EPROTONOSUPPORT ||
467 errno == EAFNOSUPPORT))
468 return PAM_SYSTEM_ERR;
470 if (opts->deny != 0 && /* deny==0 means no deny */
471 tally->fail_cnt > opts->deny && /* tally>deny means exceeded */
472 ((opts->ctrl & OPT_DENY_ROOT) || uid)) { /* even_deny stops uid check */
474 if (tally->fail_cnt == opts->deny+1) {
475 /* First say that max number was hit. */
476 snprintf(buf, sizeof(buf), "pam_tally2 uid=%u ", uid);
477 audit_log_user_message(audit_fd, AUDIT_ANOM_LOGIN_FAILURES, buf,
478 NULL, NULL, NULL, 1);
482 /* Unlock time check */
483 if (opts->unlock_time && oldtime) {
484 if (opts->unlock_time + oldtime <= time(NULL)) {
485 /* ignore deny check after unlock_time elapsed */
487 snprintf(buf, sizeof(buf), "pam_tally2 uid=%u ", uid);
488 audit_log_user_message(audit_fd, AUDIT_RESP_ACCT_UNLOCK_TIMED, buf,
489 NULL, NULL, NULL, 1);
496 /* Root unlock time check */
497 if (opts->root_unlock_time && oldtime) {
498 if (opts->root_unlock_time + oldtime <= time(NULL)) {
499 /* ignore deny check after unlock_time elapsed */
501 snprintf(buf, sizeof(buf), "pam_tally2 uid=%u ", uid);
502 audit_log_user_message(audit_fd, AUDIT_RESP_ACCT_UNLOCK_TIMED, buf,
503 NULL, NULL, NULL, 1);
512 if (tally->fail_cnt == opts->deny+1) {
513 /* First say that max number was hit. */
514 audit_log_user_message(audit_fd, AUDIT_RESP_ACCT_LOCK, buf,
515 NULL, NULL, NULL, 1);
519 if (!(opts->ctrl & OPT_QUIET)) {
520 pam_info(pamh, _("Account locked due to %u failed logins"),
521 (unsigned int)tally->fail_cnt);
523 if (!(opts->ctrl & OPT_NOLOGNOTICE)) {
524 pam_syslog(pamh, LOG_NOTICE,
525 "user %s (%lu) tally %hu, deny %hu",
526 user, (unsigned long)uid, tally->fail_cnt, opts->deny);
528 rv = PAM_AUTH_ERR; /* Only unconditional failure */
532 /* Lock time check */
533 if (opts->lock_time && oldtime) {
534 if (opts->lock_time + oldtime > time(NULL)) {
535 /* don't increase fail_cnt or update fail_time when
537 tally->fail_cnt = oldcnt;
538 tally->fail_time = oldtime;
540 if (!(opts->ctrl & OPT_QUIET)) {
541 pam_info(pamh, _("Account temporary locked (%ld seconds left)"),
542 oldtime+opts->lock_time-time(NULL));
544 if (!(opts->ctrl & OPT_NOLOGNOTICE)) {
545 pam_syslog(pamh, LOG_NOTICE,
546 "user %s (%lu) has time limit [%lds left]"
547 " since last failure.",
548 user, (unsigned long)uid,
549 oldtime+opts->lock_time-time(NULL));
558 if (audit_fd != -1) {
565 /* --- tally bump function: bump tally for uid by (signed) inc --- */
568 tally_bump (int inc, time_t *oldtime, pam_handle_t *pamh,
569 uid_t uid, const char *user, struct tally_options *opts)
571 struct tallylog tally;
574 const void *remote_host = NULL;
577 tally.fail_cnt = 0; /* !TALLY_HI --> Log opened for update */
579 i = get_tally(pamh, uid, opts->filename, &tfile, &tally);
580 if (i != PAM_SUCCESS) {
586 /* to remember old fail time (for locktime) */
588 *oldtime = (time_t)tally.fail_time;
591 tally.fail_time = time(NULL);
593 (void) pam_get_item(pamh, PAM_RHOST, &remote_host);
595 (void) pam_get_item(pamh, PAM_TTY, &remote_host);
597 remote_host = "unknown";
601 strncpy(tally.fail_line, remote_host,
602 sizeof(tally.fail_line)-1);
603 tally.fail_line[sizeof(tally.fail_line)-1] = 0;
605 oldcnt = tally.fail_cnt;
607 if (!(opts->ctrl & OPT_MAGIC_ROOT) || getuid()) {
608 /* magic_root doesn't change tally */
609 tally.fail_cnt += inc;
611 if (tally.fail_cnt == TALLY_HI) { /* Overflow *and* underflow. :) */
612 tally.fail_cnt -= inc;
613 pam_syslog(pamh, LOG_ALERT, "Tally %sflowed for user %s",
614 (inc<0)?"under":"over",user);
618 rv = tally_check(oldcnt, *oldtime, pamh, uid, user, opts, &tally);
620 i = set_tally(pamh, uid, opts->filename, &tfile, &tally);
621 if (i != PAM_SUCCESS) {
624 if (rv == PAM_SUCCESS)
633 tally_reset (pam_handle_t *pamh, uid_t uid, struct tally_options *opts)
635 struct tallylog tally;
639 /* resets only if not magic root */
641 if ((opts->ctrl & OPT_MAGIC_ROOT) && getuid() == 0) {
645 tally.fail_cnt = 0; /* !TALLY_HI --> Log opened for update */
647 i=get_tally(pamh, uid, opts->filename, &tfile, &tally);
648 if (i != PAM_SUCCESS) {
654 memset(&tally, 0, sizeof(tally));
656 i=set_tally(pamh, uid, opts->filename, &tfile, &tally);
657 if (i != PAM_SUCCESS) {
666 /*---------------------------------------------------------------------*/
668 /* --- authentication management functions (only) --- */
671 pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED,
672 int argc, const char **argv)
679 options, *opts = &options;
685 rv = tally_parse_args(pamh, opts, PHASE_AUTH, argc, argv);
686 if (rv != PAM_SUCCESS)
689 if (flags & PAM_SILENT)
690 opts->ctrl |= OPT_QUIET;
692 rv = pam_get_uid(pamh, &uid, &user, opts);
693 if (rv != PAM_SUCCESS)
696 rv = tally_bump(1, &oldtime, pamh, uid, user, opts);
698 tally_set_data(pamh, oldtime);
704 pam_sm_setcred(pam_handle_t *pamh, int flags UNUSED,
705 int argc, const char **argv)
712 options, *opts = &options;
718 rv = tally_parse_args(pamh, opts, PHASE_AUTH, argc, argv);
719 if ( rv != PAM_SUCCESS )
722 rv = pam_get_uid(pamh, &uid, &user, opts);
723 if ( rv != PAM_SUCCESS )
726 if ( tally_get_data(pamh, &oldtime) != 0 )
730 return tally_reset(pamh, uid, opts);
733 /*---------------------------------------------------------------------*/
735 /* --- authentication management functions (only) --- */
737 /* To reset failcount of user on successfull login */
740 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags UNUSED,
741 int argc, const char **argv)
748 options, *opts = &options;
754 rv = tally_parse_args(pamh, opts, PHASE_ACCOUNT, argc, argv);
755 if ( rv != PAM_SUCCESS )
758 rv = pam_get_uid(pamh, &uid, &user, opts);
759 if ( rv != PAM_SUCCESS )
762 if ( tally_get_data(pamh, &oldtime) != 0 )
766 return tally_reset(pamh, uid, opts);
769 /*-----------------------------------------------------------------------*/
773 /* static module data */
775 struct pam_module _pam_tally_modstruct = {
784 #ifdef PAM_SM_ACCOUNT
794 #endif /* #ifdef PAM_STATIC */
796 /*-----------------------------------------------------------------------*/
798 #else /* #ifndef MAIN */
800 static const char *cline_filename = DEFAULT_LOGFILE;
801 static tally_t cline_reset = TALLY_HI; /* Default is `interrogate only' */
802 static int cline_quiet = 0;
805 * Not going to link with pamlib just for these.. :)
812 case PAM_AUTH_ERR: return _("Authentication error");
813 case PAM_SERVICE_ERR: return _("Service error");
814 case PAM_USER_UNKNOWN: return _("Unknown user");
815 default: return _("Unknown error");
820 getopts( char **argv )
822 const char *pname = *argv;
823 for ( ; *argv ; (void)(*argv && ++argv) ) {
824 if ( !strcmp (*argv,"--file") ) cline_filename=*++argv;
825 else if ( !strcmp(*argv,"-f") ) cline_filename=*++argv;
826 else if ( !strncmp(*argv,"--file=",7) ) cline_filename=*argv+7;
827 else if ( !strcmp (*argv,"--user") ) cline_user=*++argv;
828 else if ( !strcmp (*argv,"-u") ) cline_user=*++argv;
829 else if ( !strncmp(*argv,"--user=",7) ) cline_user=*argv+7;
830 else if ( !strcmp (*argv,"--reset") ) cline_reset=0;
831 else if ( !strcmp (*argv,"-r") ) cline_reset=0;
832 else if ( !strncmp(*argv,"--reset=",8)) {
833 if ( sscanf(*argv+8,"%hu",&cline_reset) != 1 )
834 fprintf(stderr,_("%s: Bad number given to --reset=\n"),pname), exit(0);
836 else if ( !strcmp (*argv,"--quiet") ) cline_quiet=1;
838 fprintf(stderr,_("%s: Unrecognised option %s\n"),pname,*argv);
846 print_one(const struct tallylog *tally, uid_t uid)
852 struct passwd *pwent;
853 const char *username = "[NONAME]";
856 pwent = getpwuid(uid);
857 fail_time = tally->fail_time;
858 tm = localtime(&fail_time);
859 strftime (ptime, sizeof (ptime), "%D %H:%M:%S", tm);
862 username = pwent->pw_name;
865 printf (_("Login Failures Latest failure From\n"));
868 printf ("%-15.15s %5hu ", username, tally->fail_cnt);
869 if (tally->fail_time) {
870 printf ("%-17.17s %s", cp, tally->fail_line);
876 main( int argc UNUSED, char **argv )
878 struct tallylog tally;
880 if ( ! getopts( argv+1 ) ) {
881 printf(_("%s: [-f rooted-filename] [--file rooted-filename]\n"
882 " [-u username] [--user username]\n"
883 " [-r] [--reset[=n]] [--quiet]\n"),
891 * Major difference between individual user and all users:
892 * --user just handles one user, just like PAM.
893 * without --user it handles all users, sniffing cline_filename for nonzeros
899 struct tally_options opts;
902 memset(&opts, 0, sizeof(opts));
903 opts.ctrl = OPT_AUDIT;
904 i=pam_get_uid(NULL, &uid, NULL, &opts);
905 if ( i != PAM_SUCCESS ) {
906 fprintf(stderr,"%s: %s\n",*argv,pam_errors(i));
910 i=get_tally(NULL, uid, cline_filename, &tfile, &tally);
911 if ( i != PAM_SUCCESS ) {
914 fprintf(stderr, "%s: %s\n", *argv, pam_errors(i));
919 print_one(&tally, uid);
921 if (cline_reset != TALLY_HI) {
924 int audit_fd = audit_open();
925 snprintf(buf, sizeof(buf), "pam_tally2 uid=%u reset=%hu", uid, cline_reset);
926 audit_log_user_message(audit_fd, AUDIT_USER_ACCT,
927 buf, NULL, NULL, NULL, 1);
931 if (cline_reset == 0) {
932 memset(&tally, 0, sizeof(tally));
934 tally.fail_cnt = cline_reset;
936 i=set_tally(NULL, uid, cline_filename, &tfile, &tally);
937 if (i != PAM_SUCCESS) {
938 if (tfile) fclose(tfile);
939 fprintf(stderr,"%s: %s\n",*argv,pam_errors(i));
946 else /* !cline_user (ie, operate on all users) */ {
947 FILE *tfile=fopen(cline_filename, "r");
949 if (!tfile && cline_reset != 0) {
954 for ( ; tfile && !feof(tfile); uid++ ) {
955 if ( !fread(&tally, sizeof(tally), 1, tfile)
956 || !tally.fail_cnt ) {
959 print_one(&tally, uid);
963 if ( cline_reset!=0 && cline_reset!=TALLY_HI ) {
964 fprintf(stderr,_("%s: Can't reset all users to non-zero\n"),*argv);
966 else if ( !cline_reset ) {
969 int audit_fd = audit_open();
970 snprintf(buf, sizeof(buf), "pam_tally2 uid=all reset=0");
971 audit_log_user_message(audit_fd, AUDIT_USER_ACCT,
972 buf, NULL, NULL, NULL, 1);
976 tfile=fopen(cline_filename, "w");
977 if ( !tfile ) perror(*argv), exit(0);
985 #endif /* #ifndef MAIN */