#define OPT_AUDIT 0100
#define OPT_NOLOGNOTICE 0400
#define OPT_SERIALIZE 01000
+#define OPT_DEBUG 02000
#define MAX_LOCK_WAITING_TIME 10
log_phase_no_auth(pam_handle_t *pamh, int phase, const char *argv)
{
if ( phase != PHASE_AUTH ) {
- pam_syslog(pamh, LOG_ERR,
+ pam_syslog(pamh, LOG_ERR,
"option %s allowed in auth phase only", argv);
}
}
else if ( ! strcmp( *argv, "serialize" ) ) {
opts->ctrl |= OPT_SERIALIZE;
}
+ else if ( ! strcmp( *argv, "debug" ) ) {
+ opts->ctrl |= OPT_DEBUG;
+ }
else if ( ! strcmp( *argv, "even_deny_root_account" ) ||
! strcmp( *argv, "even_deny_root" ) ) {
log_phase_no_auth(pamh, phase, *argv);
}
}
else if ( ! strncmp( *argv, "root_unlock_time=", 17 ) ) {
- log_phase_no_auth(pamh, phase, *argv);
+ log_phase_no_auth(pamh, phase, *argv);
if ( sscanf((*argv)+17,"%ld",&opts->root_unlock_time) != 1 ) {
pam_syslog(pamh, LOG_ERR, "bad number supplied: %s", *argv);
return PAM_AUTH_ERR;
lstat_ret = lstat(filename, &fileinfo);
if (lstat_ret) {
- *tfile=open(filename, O_APPEND|O_CREAT, 0700);
+ *tfile=open(filename, O_APPEND|O_CREAT, S_IRUSR|S_IWUSR);
/* Create file, or append-open in pathological case. */
if (*tfile == -1) {
#ifndef MAIN
if ((*tfile = open(filename, O_RDWR)) == -1) {
#ifndef MAIN
if (errno == EACCES) /* called with insufficient access rights */
- return PAM_IGNORE;
-#endif
+ return PAM_IGNORE;
+#endif
pam_syslog(pamh, LOG_ALERT, "Error opening %s for update: %m", filename);
return PAM_AUTH_ERR;
if (lseek(*tfile, (off_t)uid*(off_t)sizeof(*tally), SEEK_SET) == (off_t)-1) {
pam_syslog(pamh, LOG_ALERT, "lseek failed for %s: %m", filename);
if (!preopened) {
- close(*tfile);
+ close(*tfile);
*tfile = -1;
}
return PAM_AUTH_ERR;
rv = lockf(*tfile, F_LOCK, sizeof(*tally));
/* lock failure is not fatal, we attempt to read the tally anyway */
-
+
/* reinstate the eventual old alarm handler */
if (rv == -1 && errno == EINTR) {
if (oldalarm > MAX_LOCK_WAITING_TIME) {
alarm(oldalarm);
}
- if (fileinfo.st_size < (off_t)(uid+1)*(off_t)sizeof(*tally)) {
- memset(tally, 0, sizeof(*tally));
- } else if (pam_modutil_read(*tfile, void_tally, sizeof(*tally)) != sizeof(*tally)) {
+ if (pam_modutil_read(*tfile, void_tally, sizeof(*tally)) != sizeof(*tally)) {
memset(tally, 0, sizeof(*tally));
- /* Shouldn't happen */
}
tally->fail_line[sizeof(tally->fail_line)-1] = '\0';
-
+
return PAM_SUCCESS;
}
struct tallylog *tally)
{
int rv = PAM_SUCCESS;
+ int loglevel = LOG_DEBUG;
#ifdef HAVE_LIBAUDIT
char buf[64];
int audit_fd = -1;
+ const void *rhost = NULL, *tty = NULL;
#endif
-
+
if ((opts->ctrl & OPT_MAGIC_ROOT) && getuid() == 0) {
return PAM_SUCCESS;
}
if ((audit_fd < 0) && !(errno == EINVAL || errno == EPROTONOSUPPORT ||
errno == EAFNOSUPPORT))
return PAM_SYSTEM_ERR;
+ (void)pam_get_item(pamh, PAM_TTY, &tty);
+ (void)pam_get_item(pamh, PAM_RHOST, &rhost);
#endif
if (opts->deny != 0 && /* deny==0 means no deny */
tally->fail_cnt > opts->deny && /* tally>deny means exceeded */
/* First say that max number was hit. */
snprintf(buf, sizeof(buf), "pam_tally2 uid=%u ", uid);
audit_log_user_message(audit_fd, AUDIT_ANOM_LOGIN_FAILURES, buf,
- NULL, NULL, NULL, 1);
+ rhost, NULL, tty, 1);
}
#endif
- if (uid) {
+ if (uid) {
/* Unlock time check */
if (opts->unlock_time && oldtime) {
- if (opts->unlock_time + oldtime <= time(NULL)) {
+ if (opts->unlock_time + oldtime <= time(NULL)) {
/* ignore deny check after unlock_time elapsed */
#ifdef HAVE_LIBAUDIT
snprintf(buf, sizeof(buf), "pam_tally2 uid=%u ", uid);
audit_log_user_message(audit_fd, AUDIT_RESP_ACCT_UNLOCK_TIMED, buf,
- NULL, NULL, NULL, 1);
+ rhost, NULL, tty, 1);
#endif
- rv = PAM_SUCCESS;
- goto cleanup;
- }
+ rv = PAM_SUCCESS;
+ goto cleanup;
+ }
}
} else {
/* Root unlock time check */
if (opts->root_unlock_time && oldtime) {
if (opts->root_unlock_time + oldtime <= time(NULL)) {
- /* ignore deny check after unlock_time elapsed */
+ /* ignore deny check after unlock_time elapsed */
#ifdef HAVE_LIBAUDIT
snprintf(buf, sizeof(buf), "pam_tally2 uid=%u ", uid);
audit_log_user_message(audit_fd, AUDIT_RESP_ACCT_UNLOCK_TIMED, buf,
- NULL, NULL, NULL, 1);
+ rhost, NULL, tty, 1);
#endif
- rv = PAM_SUCCESS;
- goto cleanup;
- }
+ rv = PAM_SUCCESS;
+ goto cleanup;
+ }
}
}
if (tally->fail_cnt == opts->deny+1) {
/* First say that max number was hit. */
audit_log_user_message(audit_fd, AUDIT_RESP_ACCT_LOCK, buf,
- NULL, NULL, NULL, 1);
+ rhost, NULL, tty, 1);
}
#endif
pam_info(pamh, _("Account locked due to %u failed logins"),
(unsigned int)tally->fail_cnt);
}
- if (!(opts->ctrl & OPT_NOLOGNOTICE)) {
- pam_syslog(pamh, LOG_NOTICE,
- "user %s (%lu) tally %hu, deny %hu",
- user, (unsigned long)uid, tally->fail_cnt, opts->deny);
- }
+ loglevel = LOG_NOTICE;
rv = PAM_AUTH_ERR; /* Only unconditional failure */
goto cleanup;
}
oldtime+opts->lock_time-time(NULL));
}
if (!(opts->ctrl & OPT_NOLOGNOTICE)) {
- pam_syslog(pamh, LOG_NOTICE,
+ pam_syslog(pamh, LOG_NOTICE,
"user %s (%lu) has time limit [%lds left]"
" since last failure.",
user, (unsigned long)uid,
}
rv = PAM_AUTH_ERR;
goto cleanup;
- }
+ }
}
cleanup:
+ if (!(opts->ctrl & OPT_NOLOGNOTICE) && (loglevel != LOG_DEBUG || opts->ctrl & OPT_DEBUG)) {
+ pam_syslog(pamh, loglevel,
+ "user %s (%lu) tally %hu, deny %hu",
+ user, (unsigned long)uid, tally->fail_cnt, opts->deny);
+ }
#ifdef HAVE_LIBAUDIT
if (audit_fd != -1) {
close(audit_fd);
static int
tally_bump (int inc, time_t *oldtime, pam_handle_t *pamh,
- uid_t uid, const char *user, struct tally_options *opts, int *tfile)
+ uid_t uid, const char *user, struct tally_options *opts, int *tfile)
{
struct tallylog tally;
tally_t oldcnt;
int i, rv;
tally.fail_cnt = 0; /* !TALLY_HI --> Log opened for update */
-
+
i = get_tally(pamh, uid, opts->filename, tfile, &tally, opts->ctrl);
if (i != PAM_SUCCESS) {
if (*tfile != -1) {
if (oldtime) {
*oldtime = (time_t)tally.fail_time;
}
-
+
tally.fail_time = time(NULL);
(void) pam_get_item(pamh, PAM_RHOST, &remote_host);
if (!remote_host) {
- (void) pam_get_item(pamh, PAM_TTY, &remote_host);
+ (void) pam_get_item(pamh, PAM_TTY, &remote_host);
if (!remote_host) {
- remote_host = "unknown";
- }
+ remote_host = "unknown";
+ }
}
-
+
strncpy(tally.fail_line, remote_host,
sizeof(tally.fail_line)-1);
tally.fail_line[sizeof(tally.fail_line)-1] = 0;
oldcnt = tally.fail_cnt;
-
+
if (!(opts->ctrl & OPT_MAGIC_ROOT) || getuid()) {
/* magic_root doesn't change tally */
tally.fail_cnt += inc;
static int
tally_reset (pam_handle_t *pamh, uid_t uid, struct tally_options *opts, int old_tfile)
{
- struct tallylog tally;
+ struct tallylog tally;
int tfile = old_tfile;
int i;
-
+
/* resets only if not magic root */
if ((opts->ctrl & OPT_MAGIC_ROOT) && getuid() == 0) {
- return PAM_SUCCESS;
+ return PAM_SUCCESS;
}
tally.fail_cnt = 0; /* !TALLY_HI --> Log opened for update */
close(tfile);
RETURN_ERROR(i);
}
-
+
memset(&tally, 0, sizeof(tally));
-
+
i=set_tally(pamh, uid, opts->filename, &tfile, &tally);
if (i != PAM_SUCCESS) {
if (tfile != old_tfile) /* the descriptor is not owned by pam data */
/* static module data */
-struct pam_module _pam_tally_modstruct = {
+struct pam_module _pam_tally2_modstruct = {
MODULE_NAME,
#ifdef PAM_SM_AUTH
pam_sm_authenticate,
*/
static const char *
-pam_errors( int i )
+pam_errors( int i )
{
switch (i) {
case PAM_AUTH_ERR: return _("Authentication error");
}
static int
-getopts( char **argv )
+getopts( char **argv )
{
const char *pname = *argv;
for ( ; *argv ; (void)(*argv && ++argv) ) {
putchar ('\n');
}
-int
+int
main( int argc UNUSED, char **argv )
{
struct tallylog tally;
int audit_fd = audit_open();
snprintf(buf, sizeof(buf), "pam_tally2 uid=%u reset=%hu", uid, cline_reset);
audit_log_user_message(audit_fd, AUDIT_USER_ACCT,
- buf, NULL, NULL, NULL, 1);
+ buf, NULL, NULL, ttyname(STDIN_FILENO), 1);
if (audit_fd >=0)
close(audit_fd);
#endif
FILE *tfile=fopen(cline_filename, "r");
uid_t uid=0;
if (!tfile && cline_reset != 0) {
- perror(*argv);
- exit(1);
+ perror(*argv);
+ exit(1);
}
for ( ; tfile && !feof(tfile); uid++ ) {
if ( !fread(&tally, sizeof(tally), 1, tfile)
|| !tally.fail_cnt ) {
- continue;
+ continue;
}
print_one(&tally, uid);
}
int audit_fd = audit_open();
snprintf(buf, sizeof(buf), "pam_tally2 uid=all reset=0");
audit_log_user_message(audit_fd, AUDIT_USER_ACCT,
- buf, NULL, NULL, NULL, 1);
+ buf, NULL, NULL, ttyname(STDIN_FILENO), 1);
if (audit_fd >=0)
close(audit_fd);
#endif