From c75c3ff9f2c3d221aabe89b8d0779f041e71e30c Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Fri, 7 Jan 2005 13:52:42 +0000 Subject: Relevant BUGIDs: Red Hat bz 60930 Purpose of commit: bugfix, new feature Commit summary: --------------- major rewrite of the pam_tally module --- modules/pam_tally/README | 86 ++++--- modules/pam_tally/pam_tally.c | 555 ++++++++++++++++++++++++------------------ 2 files changed, 374 insertions(+), 267 deletions(-) (limited to 'modules/pam_tally') diff --git a/modules/pam_tally/README b/modules/pam_tally/README index 4c421648..6c7d87f4 100644 --- a/modules/pam_tally/README +++ b/modules/pam_tally/README @@ -1,5 +1,5 @@ SUMMARY: - pam_tally: + pam_tally.so: Maintains a count of attempted accesses, can reset count on success, can deny access if too many attempts fail. @@ -11,41 +11,54 @@ SUMMARY: * file=/where/to/keep/counts (default /var/log/faillog) (auth) - Authentication phase increments attempted login counter. - * no_magic_root (root DOES increment counter. Use for - daemon-based stuff, like telnet/rsh/login) + Authentication phase first checks if user should be denied access + and if not it increments attempted login counter. Then on call to + pam_setcred it resets the attempts counter if the user is NOT + magic root. + * deny=n (deny access if tally for this user exceeds n) + + * lock_time=n (always deny for n seconds after failed attempt) + + * unlock_time=n (allow access after n seconds after the last + failed attempt with exceeded tally) - (account) - Account phase can deny access and/or reset attempts counter. - * deny=n (deny access if tally for this user exceeds n; - The presence of deny=n changes the default for - reset/no_reset to reset, unless the user trying to - gain access is root and the no_magic_root option - has NOT been specified.) - - * no_magic_root (access attempts by root DON'T ignore deny. - Use this for daemon-based stuff, like telnet/rsh/login) + * magic_root (access attempts by root as requesting user ignore + deny and don't change counter. + Use this for su and similar services.) + * even_deny_root_account (Root can become unavailable. BEWARE. Note that magic root trying to gain root bypasses this, but normal users can be locked out.) - * reset (reset count to 0 on successful entry, even for - magic root) - * no_reset (don't reset count on successful entry) - This is the default unless deny exists and the - user attempting access is NOT magic root. - * per_user (If /var/log/faillog contains a non-zero - .fail_max field for this user then use it - instead of deny=n parameter) + .fail_max/.fail_locktime field for this user then use it + instead of deny=n/lock_time=n parameter.) * no_lock_time (Don't use .fail_locktime filed in /var/log/faillog for this user) + * no_reset (don't reset count on successful entry, + only decrement) + + + (account) + Account phase resets attempts counter if the user is NOT magic root. + This phase can be used optionaly for services which don't call + pam_setcred correctly or if the reset should be done regardless + of the failure of the account phase of other modules. + + * magic_root (access attempts by root as requesting user + don't change counter. + Use this for su and similar services.) + + * no_reset (don't reset count on successful entry, + only decrement) + Also checks to make sure that the counts file is a plain file and not world writable. - Tim Baverstock , v0.1 5 March 1997 + - Tomas Mraz , v0.2 5 January 2005 LONGER: @@ -53,20 +66,20 @@ pam_tally comes in two parts: pam_tally.so and pam_tally. pam_tally.so sits in a pam config file, in the auth and account sections. -In the auth section, it increments a per-uid counter for each attempted -login, in the account section, it denies access if attempted logins -exceed some threashold and/or resets that counter to zero on successful -login. +In the auth section, it denies access if attempted logins exceed some +threshold and it increments a per-uid counter for each attempted login, +in the account section, it resets that counter to zero on successful +login. If the module isn't used in the account section it resets the counter +to zero on call to pam_setcred. Root is treated specially: -1. When a process already running as root tries to access some service, the -access is `magic', and bypasses pam_tally's checks: handy for `su'ing from -root into an account otherwise blocked. However, for services like telnet or -login which always effectively run from the root account, root (ie everyone) -shouldn't be granted this magic status, and the flag `no_magic_root' should -be set in this situation, as noted in the summary above. [This option may -be obsolete, with `sufficient root' processing.] +1. When a process already running as root tries to access some service and the +'magic_root' flag is set, the access is `magic', and bypasses pam_tally's +checks: handy for `su'ing from root into an account otherwise blocked. +NOTE: This was changed from the previous version of pam_tally where the default +was to treat root as magic and there were the 'no_magic_root' flag. However +for most of services the current default make sense. 2. Normally, failed attempts to access root will NOT cause the root account to become blocked, to prevent denial-of-service: if your users aren't @@ -93,3 +106,10 @@ The (4.0 Redhat) utilities seem to do funny things with uid, and I'm not wholly sure I understood what I should have been doing anyway so the `keep a count of current logins' bit has been #ifdef'd out and you can only reset the counter on successful authentication, for now. + +IMPORTANT NOTICE: +In the original version of pam_tally there was a bug where the information +if the password was correct or not was leaked by returning error from +different pam management phases. This was solved by moving the denying +functionality to the auth phase. However it's necessary to update the pam +configuration by moving the required options (as deny=N) to the auth phase. diff --git a/modules/pam_tally/pam_tally.c b/modules/pam_tally/pam_tally.c index 341f448e..134f7f32 100644 --- a/modules/pam_tally/pam_tally.c +++ b/modules/pam_tally/pam_tally.c @@ -9,6 +9,8 @@ * 5 March 1997 * * Stuff stolen from pam_rootok and pam_listfile + * + * Changes by Tomas Mraz 5 January 2005 */ #include @@ -56,12 +58,6 @@ #define DEFAULT_LOGFILE "/var/log/faillog" #define MODULE_NAME "pam_tally" -enum TALLY_RESET { - TALLY_RESET_DEFAULT, - TALLY_RESET_RESET, - TALLY_RESET_NO_RESET -}; - #define tally_t unsigned short int #define TALLY_FMT "%hu" #define TALLY_HI ((tally_t)~0L) @@ -79,6 +75,27 @@ struct fail_s { #endif /* ndef MAIN */ }; +struct tally_options { + const char *filename; + tally_t deny; + long lock_time; + long unlock_time; + unsigned int ctrl; +}; + +#define PHASE_UNKNOWN 0 +#define PHASE_AUTH 1 +#define PHASE_ACCOUNT 2 +#define PHASE_SESSION 3 + +#define OPT_MAGIC_ROOT 01 +#define OPT_FAIL_ON_ERROR 02 +#define OPT_DENY_ROOT 04 +#define OPT_PER_USER 010 +#define OPT_NO_LOCK_TIME 020 +#define OPT_NO_RESET 040 + + /*---------------------------------------------------------------------*/ /* some syslogging */ @@ -101,6 +118,91 @@ static void _pam_log(int err, const char *format, ...) /*---------------------------------------------------------------------*/ +/* --- Support function: parse arguments --- */ + +static void log_phase_no_auth( int phase, const char *argv ) +{ + if ( phase != PHASE_AUTH ) { + _pam_log(LOG_ERR, + MODULE_NAME ": option %s allowed in auth phase only", argv); + } +} + +static int tally_parse_args( struct tally_options *opts, int phase, + int argc, const char **argv ) +{ + memset(opts, 0, sizeof(*opts)); + opts->filename = DEFAULT_LOGFILE; + + for ( ; argc-- > 0; ++argv ) { + + if ( ! strncmp( *argv, "file=", 5 ) ) { + const char *from = *argv + 5; + if ( *from!='/' || strlen(from)>FILENAME_MAX-1 ) { + _pam_log(LOG_ERR, + MODULE_NAME ": filename not /rooted or too long; ", + *argv); + return PAM_AUTH_ERR; + } + opts->filename = from; + } + else if ( ! strcmp( *argv, "onerr=fail" ) ) { + opts->ctrl |= OPT_FAIL_ON_ERROR; + } + else if ( ! strcmp( *argv, "onerr=succeed" ) ) { + opts->ctrl &= ~OPT_FAIL_ON_ERROR; + } + else if ( ! strcmp( *argv, "magic_root" ) ) { + opts->ctrl |= OPT_MAGIC_ROOT; + } + else if ( ! strcmp( *argv, "even_deny_root_account" ) ) { + log_phase_no_auth(phase, *argv); + opts->ctrl |= OPT_DENY_ROOT; + } + else if ( ! strncmp( *argv, "deny=", 5 ) ) { + log_phase_no_auth(phase, *argv); + if ( sscanf((*argv)+5,TALLY_FMT,&opts->deny) != 1 ) { + _pam_log(LOG_ERR,"bad number supplied; %s",*argv); + return PAM_AUTH_ERR; + } + } + else if ( ! strncmp( *argv, "lock_time=", 10 ) ) { + log_phase_no_auth(phase, *argv); + if ( sscanf((*argv)+10,"%ld",&opts->lock_time) != 1 ) { + _pam_log(LOG_ERR,"bad number supplied; %s",*argv); + return PAM_AUTH_ERR; + } + } + else if ( ! strncmp( *argv, "unlock_time=", 12 ) ) { + log_phase_no_auth(phase, *argv); + if ( sscanf((*argv)+12,"%ld",&opts->unlock_time) != 1 ) { + _pam_log(LOG_ERR,"bad number supplied; %s",*argv); + return PAM_AUTH_ERR; + } + } + else if ( ! strcmp( *argv, "per_user" ) ) + { + log_phase_no_auth(phase, *argv); + opts->ctrl |= OPT_PER_USER; + } + else if ( ! strcmp( *argv, "no_lock_time") ) + { + log_phase_no_auth(phase, *argv); + opts->ctrl |= OPT_NO_LOCK_TIME; + } + else if ( ! strcmp( *argv, "no_reset" ) ) { + opts->ctrl |= OPT_NO_RESET; + } + else { + _pam_log(LOG_ERR, MODULE_NAME ": unknown option; %s",*argv); + } + } + + return PAM_SUCCESS; +} + +/*---------------------------------------------------------------------*/ + /* --- Support function: get uid (and optionally username) from PAM or cline_user --- */ @@ -136,6 +238,42 @@ static int pam_get_uid( pam_handle_t *pamh, uid_t *uid, const char **userp ) /*---------------------------------------------------------------------*/ +/* --- Support functions: set/get tally data --- */ + +static void _cleanup( pam_handle_t *pamh, void *data, int error_status ) + { + free(data); + } + +static void tally_set_data( pam_handle_t *pamh, time_t oldtime ) + { + time_t *data; + + if ( (data=malloc(sizeof(time_t))) != NULL ) { + *data = oldtime; + pam_set_data(pamh, MODULE_NAME, (void *)data, _cleanup); + } + } + +static int tally_get_data( pam_handle_t *pamh, time_t *oldtime ) + { + int rv; + const void *data; + + rv = pam_get_data(pamh, MODULE_NAME, &data); + if ( rv == PAM_SUCCESS && oldtime != NULL ) { + *oldtime = *(const time_t *)data; + pam_set_data(pamh, MODULE_NAME, NULL, NULL); + } + else { + rv = -1; + *oldtime = 0; + } + return rv; + } + +/*---------------------------------------------------------------------*/ + /* --- Support function: open/create tallyfile and return tally for uid --- */ /* If on entry *tally==TALLY_HI, tallyfile is opened READONLY */ @@ -255,82 +393,42 @@ static int set_tally( tally_t tally, #define PAM_FUNCTION(name) \ PAM_EXTERN int name (pam_handle_t *pamh,int flags,int argc,const char **argv) -#define RETURN_ERROR(i) return ((fail_on_error)?(i):(PAM_SUCCESS)) +#define RETURN_ERROR(i) return ((opts->ctrl & OPT_FAIL_ON_ERROR)?(i):(PAM_SUCCESS)) /*---------------------------------------------------------------------*/ /* --- tally bump function: bump tally for uid by (signed) inc --- */ -static int tally_bump (int inc, +static int tally_bump (int inc, time_t *oldtime, pam_handle_t *pamh, - int flags, - int argc, - const char **argv) { - uid_t uid; - - int - fail_on_error = FALSE; + uid_t uid, + const char *user, + struct tally_options *opts) { tally_t tally = 0; /* !TALLY_HI --> Log opened for update */ - char - no_magic_root = FALSE; - - char - filename[ FILENAME_MAX ] = DEFAULT_LOGFILE; - - /* Should probably decode the parameters before anything else. */ - - { - for ( ; argc-- > 0; ++argv ) { - - /* generic options.. um, ignored. :] */ - - if ( ! strcmp( *argv, "no_magic_root" ) ) { - no_magic_root = TRUE; - } - else if ( ! strncmp( *argv, "file=", 5 ) ) { - char const - *from = (*argv)+5; - char - *to = filename; - if ( *from!='/' || strlen(from)>FILENAME_MAX-1 ) { - _pam_log(LOG_ERR, - MODULE_NAME ": filename not /rooted or too long; ", - *argv); - RETURN_ERROR( PAM_AUTH_ERR ); - } - while ( ( *to++ = *from++ ) ); - } - else if ( ! strcmp( *argv, "onerr=fail" ) ) { - fail_on_error=TRUE; - } - else if ( ! strcmp( *argv, "onerr=succeed" ) ) { - fail_on_error=FALSE; - } - else { - _pam_log(LOG_ERR, MODULE_NAME ": unknown option; %s",*argv); - } - } /* for() */ - } - - { FILE *TALLY = NULL; const char - *user = NULL, *remote_host = NULL, *cur_tty = NULL; struct fail_s fs, *fsp = &fs; + int i; - int i=pam_get_uid(pamh, &uid, &user); - if ( i != PAM_SUCCESS ) RETURN_ERROR( i ); - - i=get_tally( &tally, uid, filename, &TALLY, fsp ); + i=get_tally( &tally, uid, opts->filename, &TALLY, fsp ); /* to remember old fail time (for locktime) */ fsp->fs_fail_time = fsp->fs_faillog.fail_time; - fsp->fs_faillog.fail_time = time(NULL); + if ( inc > 0 ) { + if ( oldtime ) { + *oldtime = fsp->fs_faillog.fail_time; + } + fsp->fs_faillog.fail_time = time(NULL); + } else { + if ( oldtime ) { + fsp->fs_faillog.fail_time = *oldtime; + } + } (void) pam_get_item(pamh, PAM_RHOST, (const void **)&remote_host); if (!remote_host) { @@ -352,7 +450,7 @@ static int tally_bump (int inc, } if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); } - if ( no_magic_root || getuid() ) { /* no_magic_root kills uid test */ + if ( !(opts->ctrl & OPT_MAGIC_ROOT) || getuid() ) { /* magic_root doesn't change tally */ tally+=inc; @@ -363,217 +461,215 @@ static int tally_bump (int inc, } } - i=set_tally( tally, uid, filename, &TALLY, fsp ); + i=set_tally( tally, uid, opts->filename, &TALLY, fsp ); if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); } - } - return PAM_SUCCESS; + return PAM_SUCCESS; } -/*---------------------------------------------------------------------*/ - -/* --- authentication management functions (only) --- */ - -#ifdef PAM_SM_AUTH - -PAM_FUNCTION( pam_sm_authenticate ) { - return tally_bump( 1, pamh, flags, argc, argv); -} - -/* --- Seems to need this function. Ho hum. --- */ - -PAM_FUNCTION( pam_sm_setcred ) { return PAM_SUCCESS; } - -#endif - -/*---------------------------------------------------------------------*/ - -/* --- session management functions (only) --- */ - -/* - * Unavailable until .so files can be suid - */ - -#ifdef PAM_SM_SESSION - -/* To maintain a balance-tally of successful login/outs */ - -PAM_FUNCTION( pam_sm_open_session ) { - return tally_bump( 1, pamh, flags, argc, argv); -} - -PAM_FUNCTION( pam_sm_close_session ) { - return tally_bump(-1, pamh, flags, argc, argv); -} - -#endif - -/*---------------------------------------------------------------------*/ - -/* --- authentication management functions (only) --- */ - -#ifdef PAM_SM_AUTH - -/* To lock out a user with an unacceptably high tally */ - -PAM_FUNCTION( pam_sm_acct_mgmt ) { - uid_t - uid; - - int - fail_on_error = FALSE; +static int tally_check (time_t oldtime, + pam_handle_t *pamh, + uid_t uid, + const char *user, + struct tally_options *opts) { tally_t - deny = 0; + deny = opts->deny; tally_t tally = 0; /* !TALLY_HI --> Log opened for update */ + long + lock_time = opts->lock_time; - char - no_magic_root = FALSE, - even_deny_root_account = FALSE; - char per_user = FALSE; /* if true then deny=.fail_max for user */ - char no_lock_time = FALSE; /* if true then don't use .fail_locktime */ - - const char - *user = NULL; - - enum TALLY_RESET - reset = TALLY_RESET_DEFAULT; - - char - filename[ FILENAME_MAX ] = DEFAULT_LOGFILE; - - /* Should probably decode the parameters before anything else. */ - - { - for ( ; argc-- > 0; ++argv ) { - - /* generic options.. um, ignored. :] */ - - if ( ! strcmp( *argv, "no_magic_root" ) ) { - no_magic_root = TRUE; - } - else if ( ! strcmp( *argv, "even_deny_root_account" ) ) { - even_deny_root_account = TRUE; - } - else if ( ! strcmp( *argv, "reset" ) ) { - reset = TALLY_RESET_RESET; - } - else if ( ! strcmp( *argv, "no_reset" ) ) { - reset = TALLY_RESET_NO_RESET; - } - else if ( ! strncmp( *argv, "file=", 5 ) ) { - char const - *from = (*argv)+5; - char - *to = filename; - if ( *from != '/' || strlen(from) > FILENAME_MAX-1 ) { - _pam_log(LOG_ERR, - MODULE_NAME ": filename not /rooted or too long; ", - *argv); - RETURN_ERROR( PAM_AUTH_ERR ); - } - while ( ( *to++ = *from++ ) ); - } - else if ( ! strncmp( *argv, "deny=", 5 ) ) { - if ( sscanf((*argv)+5,TALLY_FMT,&deny) != 1 ) { - _pam_log(LOG_ERR,"bad number supplied; %s",*argv); - RETURN_ERROR( PAM_AUTH_ERR ); - } - } - else if ( ! strcmp( *argv, "onerr=fail" ) ) { - fail_on_error=TRUE; - } - else if ( ! strcmp( *argv, "onerr=succeed" ) ) { - fail_on_error=FALSE; - } - else if ( ! strcmp( *argv, "per_user" ) ) - { - per_user = TRUE; - } - else if ( ! strcmp( *argv, "no_lock_time") ) - { - no_lock_time = TRUE; - } - else { - _pam_log(LOG_ERR, MODULE_NAME ": unknown option; %s",*argv); - } - } /* for() */ - } - - { struct fail_s fs, *fsp = &fs; FILE *TALLY=0; - int i=pam_get_uid(pamh, &uid, &user); - if ( i != PAM_SUCCESS ) RETURN_ERROR( i ); + int i; - i=get_tally( &tally, uid, filename, &TALLY, fsp ); - if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); } + i=get_tally( &tally, uid, opts->filename, &TALLY, fsp ); + if (TALLY) fclose(TALLY); + if ( i != PAM_SUCCESS ) { RETURN_ERROR( i ); } - if ( no_magic_root || getuid() ) { /* no_magic_root kills uid test */ + if ( !(opts->ctrl & OPT_MAGIC_ROOT) || getuid() ) { /* magic_root skips tally check */ /* To deny or not to deny; that is the question */ /* if there's .fail_max entry and per_user=TRUE then deny=.fail_max */ - if ( (fsp->fs_faillog.fail_max) && (per_user) ) { + if ( (fsp->fs_faillog.fail_max) && (opts->ctrl & OPT_PER_USER) ) { deny = fsp->fs_faillog.fail_max; } - if (fsp->fs_faillog.fail_locktime && fsp->fs_fail_time - && (!no_lock_time) ) + if ( (fsp->fs_faillog.fail_locktime) && (opts->ctrl & OPT_PER_USER) ) { + lock_time = fsp->fs_faillog.fail_locktime; + } + if (lock_time && oldtime + && !(opts->ctrl & OPT_NO_LOCK_TIME) ) { - if ( (fsp->fs_faillog.fail_locktime + fsp->fs_fail_time) > time(NULL) ) + if ( lock_time + oldtime > time(NULL) ) { _pam_log(LOG_NOTICE, "user %s ("UID_FMT") has time limit [%lds left]" " since last failure.", user,uid, - fsp->fs_fail_time+fsp->fs_faillog.fail_locktime + oldtime+lock_time -time(NULL)); - if (TALLY) - fclose(TALLY); return PAM_AUTH_ERR; } } + if (opts->unlock_time && oldtime) + { + if ( opts->unlock_time + oldtime <= time(NULL) ) + { /* ignore deny check after unlock_time elapsed */ + return PAM_SUCCESS; + } + } if ( ( deny != 0 ) && /* deny==0 means no deny */ ( tally > deny ) && /* tally>deny means exceeded */ - ( even_deny_root_account || uid ) /* even_deny stops uid check */ + ( ((opts->ctrl & OPT_DENY_ROOT) || uid) ) /* even_deny stops uid check */ ) { _pam_log(LOG_NOTICE,"user %s ("UID_FMT") tally "TALLY_FMT", deny "TALLY_FMT, user, uid, tally, deny); - if (TALLY) - fclose(TALLY); return PAM_AUTH_ERR; /* Only unconditional failure */ } - - /* resets for explicit reset - * or by default if deny exists and not magic-root - */ - - if ( ( reset == TALLY_RESET_RESET ) || - ( reset == TALLY_RESET_DEFAULT && deny ) ) { tally=0; } } - else /* is magic root */ { - /* Magic root skips deny test... */ + return PAM_SUCCESS; +} + +static int tally_reset (pam_handle_t *pamh, + uid_t uid, + const char *user, + struct tally_options *opts) { + tally_t + tally = 0; /* !TALLY_HI --> Log opened for update */ + + struct fail_s fs, *fsp = &fs; + FILE *TALLY=0; + int i; + + i=get_tally( &tally, uid, opts->filename, &TALLY, fsp ); + if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); } + + /* resets if not magic root + */ - /* Magic root only resets on explicit reset, regardless of deny */ + if ( (!(opts->ctrl & OPT_MAGIC_ROOT) || getuid()) + && !(opts->ctrl & OPT_NO_RESET) ) + { tally=0; } - if ( reset == TALLY_RESET_RESET ) { tally=0; } - } if (tally == 0) { fsp->fs_faillog.fail_time = (time_t) 0; strcpy(fsp->fs_faillog.fail_line, ""); } - i=set_tally( tally, uid, filename, &TALLY, fsp ); + + i=set_tally( tally, uid, opts->filename, &TALLY, fsp ); if ( i != PAM_SUCCESS ) { if (TALLY) fclose(TALLY); RETURN_ERROR( i ); } - } - return PAM_SUCCESS; + return PAM_SUCCESS; +} + +/*---------------------------------------------------------------------*/ + +/* --- authentication management functions (only) --- */ + +#ifdef PAM_SM_AUTH + +PAM_FUNCTION( pam_sm_authenticate ) { + int + rvcheck, rvbump; + time_t + oldtime = 0; + struct tally_options + options, *opts = &options; + uid_t + uid; + const char + *user; + + rvcheck = tally_parse_args(opts, PHASE_AUTH, argc, argv); + if ( rvcheck != PAM_SUCCESS ) + RETURN_ERROR( rvcheck ); + + rvcheck = pam_get_uid(pamh, &uid, &user); + if ( rvcheck != PAM_SUCCESS ) + RETURN_ERROR( rvcheck ); + + rvbump = tally_bump(1, &oldtime, pamh, uid, user, opts); + rvcheck = tally_check(oldtime, pamh, uid, user, opts); + + tally_set_data(pamh, oldtime); + + return rvcheck != PAM_SUCCESS ? rvcheck : rvbump; +} + +PAM_FUNCTION( pam_sm_setcred ) { + int + rv; + time_t + oldtime = 0; + struct tally_options + options, *opts = &options; + uid_t + uid; + const char + *user; + + rv = tally_parse_args(opts, PHASE_AUTH, argc, argv); + if ( rv != PAM_SUCCESS ) + RETURN_ERROR( rv ); + + rv = pam_get_uid(pamh, &uid, &user); + if ( rv != PAM_SUCCESS ) + RETURN_ERROR( rv ); + + if ( tally_get_data(pamh, &oldtime) != 0 ) + /* no data found */ + return PAM_SUCCESS; + + if ( (rv=tally_bump(-1, &oldtime, pamh, uid, user, opts)) != PAM_SUCCESS ) + return rv; + return tally_reset(pamh, uid, user, opts); +} + +#endif + +/*---------------------------------------------------------------------*/ + +/* --- authentication management functions (only) --- */ + +#ifdef PAM_SM_ACCOUNT + +/* To reset failcount of user on successfull login */ + +PAM_FUNCTION( pam_sm_acct_mgmt ) { + int + rv; + time_t + oldtime = 0; + struct tally_options + options, *opts = &options; + uid_t + uid; + const char + *user; + + rv = tally_parse_args(opts, PHASE_ACCOUNT, argc, argv); + if ( rv != PAM_SUCCESS ) + RETURN_ERROR( rv ); + + rv = pam_get_uid(pamh, &uid, &user); + if ( rv != PAM_SUCCESS ) + RETURN_ERROR( rv ); + + if ( tally_get_data(pamh, &oldtime) != 0 ) + /* no data found */ + return PAM_SUCCESS; + + if ( (rv=tally_bump(-1, &oldtime, pamh, uid, user, opts)) != PAM_SUCCESS ) + return rv; + return tally_reset(pamh, uid, user, opts); } -#endif /* #ifdef PAM_SM_AUTH */ +#endif /* #ifdef PAM_SM_ACCOUNT */ /*-----------------------------------------------------------------------*/ @@ -595,18 +691,9 @@ struct pam_module _pam_tally_modstruct = { #else NULL, #endif -#ifdef PAM_SM_SESSION - pam_sm_open_session, - pam_sm_close_session, -#else NULL, NULL, -#endif -#ifdef PAM_SM_PASSWORD - pam_sm_chauthtok, -#else NULL, -#endif }; #endif /* #ifdef PAM_STATIC */ -- cgit v1.2.3