diff -up Linux-PAM-0.99.8.1/libpam/libpam.map.audit-failed Linux-PAM-0.99.8.1/libpam/libpam.map --- Linux-PAM-0.99.8.1/libpam/libpam.map.audit-failed 2006-06-14 17:28:44.000000000 +0200 +++ Linux-PAM-0.99.8.1/libpam/libpam.map 2008-01-22 22:24:05.000000000 +0100 @@ -45,3 +45,7 @@ LIBPAM_MODUTIL_1.0 { pam_modutil_read; pam_modutil_write; }; +LIBPAM_MODUTIL_1.1 { + global: + pam_modutil_audit_write; +} LIBPAM_MODUTIL_1.0; diff -up Linux-PAM-0.99.8.1/libpam/pam_audit.c.audit-failed Linux-PAM-0.99.8.1/libpam/pam_audit.c --- Linux-PAM-0.99.8.1/libpam/pam_audit.c.audit-failed 2008-01-22 22:24:05.000000000 +0100 +++ Linux-PAM-0.99.8.1/libpam/pam_audit.c 2008-01-22 22:24:05.000000000 +0100 @@ -42,39 +42,53 @@ _pam_audit_writelog(pam_handle_t *pamh, best to fix it. */ errno = -rc; + if (rc < 0 && errno != old_errno) + { + old_errno = errno; + pam_syslog (pamh, LOG_CRIT, "audit_log_acct_message() failed: %m"); + } + pamh->audit_state |= PAMAUDIT_LOGGED; - if (rc < 0) { - if (rc == -EPERM && getuid() != 0) - return 0; - if (errno != old_errno) { - old_errno = errno; - pam_syslog (pamh, LOG_CRIT, "audit_log_acct_message() failed: %m"); - } - } - return rc; + if (rc == -EPERM && getuid () != 0) + return 0; + else + return rc; } -int -_pam_auditlog(pam_handle_t *pamh, int action, int retval, int flags) +static int +_pam_audit_open(pam_handle_t *pamh) { - const char *message; - int type; int audit_fd; - audit_fd = audit_open(); if (audit_fd < 0) { /* You get these error codes only when the kernel doesn't have * audit compiled in. */ if (errno == EINVAL || errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) - return retval; + return -2; /* this should only fail in case of extreme resource shortage, * need to prevent login in that case for CAPP compliance. */ pam_syslog(pamh, LOG_CRIT, "audit_open() failed: %m"); + return -1; + } + + return audit_fd; +} + +int +_pam_auditlog(pam_handle_t *pamh, int action, int retval, int flags) +{ + const char *message; + int type; + int audit_fd; + + if ((audit_fd=_pam_audit_open(pamh)) == -1) { return PAM_SYSTEM_ERR; + } else if (audit_fd == -2) { + return retval; } switch (action) { @@ -141,4 +155,30 @@ _pam_audit_end(pam_handle_t *pamh, int s return 0; } +int +pam_modutil_audit_write(pam_handle_t *pamh, int type, + const char *message, int retval) +{ + int audit_fd; + int rc; + + if ((audit_fd=_pam_audit_open(pamh)) == -1) { + return PAM_SYSTEM_ERR; + } else if (audit_fd == -2) { + return retval; + } + + rc = _pam_audit_writelog(pamh, audit_fd, type, message, retval); + + audit_close(audit_fd); + + return rc < 0 ? PAM_SYSTEM_ERR : PAM_SUCCESS; +} + +#else +int pam_modutil_audit_write(pam_handle_t *pamh UNUSED, int type UNUSED, + const char *message UNUSED, int retval UNUSED) +{ + return PAM_SUCCESS; +} #endif /* HAVE_LIBAUDIT */ diff -up Linux-PAM-0.99.8.1/modules/pam_access/pam_access.8.xml.audit-failed Linux-PAM-0.99.8.1/modules/pam_access/pam_access.8.xml --- Linux-PAM-0.99.8.1/modules/pam_access/pam_access.8.xml.audit-failed 2007-06-22 10:03:29.000000000 +0200 +++ Linux-PAM-0.99.8.1/modules/pam_access/pam_access.8.xml 2008-01-22 22:24:05.000000000 +0100 @@ -29,6 +29,9 @@ nodefgroup + noaudit + + accessfile=file @@ -54,6 +57,10 @@ /etc/security/access.conf if you don't specify another file. + + If Linux PAM is compiled with audit support the module will report + when it denies access based on origin (host or tty). + @@ -87,6 +94,17 @@ + + + + + Do not report logins from disallowed hosts and ttys to the audit subsystem. + + + + + + diff -up Linux-PAM-0.99.8.1/modules/pam_access/pam_access.c.audit-failed Linux-PAM-0.99.8.1/modules/pam_access/pam_access.c --- Linux-PAM-0.99.8.1/modules/pam_access/pam_access.c.audit-failed 2007-06-25 11:59:11.000000000 +0200 +++ Linux-PAM-0.99.8.1/modules/pam_access/pam_access.c 2008-01-22 22:24:05.000000000 +0100 @@ -46,6 +46,10 @@ #include #include +#ifdef HAVE_LIBAUDIT +#include +#endif + /* * here, we make definitions for the externally accessible functions * in this file (these definitions are required for static modules @@ -81,17 +85,11 @@ /* Delimiters for fields and for lists of users, ttys or hosts. */ -static const char *fs = ":"; /* field separator */ -static const char *sep = ", \t"; /* list-element separator */ - - /* Constants to be used in assignments only, not in comparisons... */ +#define ALL 2 #define YES 1 #define NO 0 -/* Only allow group entries of the form "(xyz)" */ -static int only_new_group_syntax = NO; - /* * A structure to bundle up all login-related information to keep the * functional interfaces as generic as possible. @@ -100,12 +98,13 @@ struct login_info { const struct passwd *user; const char *from; const char *config_file; + int debug; /* Print debugging messages. */ + int only_new_group_syntax; /* Only allow group entries of the form "(xyz)" */ + int noaudit; /* Do not audit denials */ + const char *fs; /* field separator */ + const char *sep; /* list-element separator */ }; -/* Print debugging messages. - Default is NO which means don't print debugging messages. */ -static char pam_access_debug = NO; - /* Parse module config arguments */ static int @@ -113,17 +112,22 @@ parse_args(pam_handle_t *pamh, struct lo int argc, const char **argv) { int i; - + + loginfo->noaudit = NO; + loginfo->debug = NO; + loginfo->only_new_group_syntax = NO; + loginfo->fs = ":"; + loginfo->sep = ", \t"; for (i=0; idebug = YES; } else if (strcmp (argv[i], "nodefgroup") == 0) { - only_new_group_syntax = YES; + loginfo->only_new_group_syntax = YES; + } else if (strcmp (argv[i], "noaudit") == 0) { + loginfo->noaudit = YES; } else { pam_syslog(pamh, LOG_ERR, "unrecognized option [%s]", argv[i]); } @@ -153,13 +159,13 @@ parse_args(pam_handle_t *pamh, struct lo typedef int match_func (pam_handle_t *, char *, struct login_info *); -static int list_match (pam_handle_t *, char *, struct login_info *, +static int list_match (pam_handle_t *, char *, char *, struct login_info *, match_func *); static int user_match (pam_handle_t *, char *, struct login_info *); -static int group_match (pam_handle_t *, const char *, const char *); +static int group_match (pam_handle_t *, const char *, const char *, int); static int from_match (pam_handle_t *, char *, struct login_info *); -static int string_match (pam_handle_t *, const char *, const char *); -static int network_netmask_match (pam_handle_t *, const char *, const char *); +static int string_match (pam_handle_t *, const char *, const char *, int); +static int network_netmask_match (pam_handle_t *, const char *, const char *, int); /* isipaddr - find out if string provided is an IP address or not */ @@ -325,11 +331,12 @@ login_access (pam_handle_t *pamh, struct char *users; /* becomes list of login names */ char *froms; /* becomes list of terminals or hosts */ int match = NO; + int nonall_match = NO; int end; int lineno = 0; /* for diagnostics */ char *sptr; - if (pam_access_debug) + if (item->debug) pam_syslog (pamh, LOG_DEBUG, "login_access: user=%s, from=%s, file=%s", item->user->pw_name, @@ -361,8 +368,8 @@ login_access (pam_handle_t *pamh, struct continue; /* Allow field seperator in last field of froms */ - if (!(perm = strtok_r(line, fs, &sptr)) - || !(users = strtok_r(NULL, fs, &sptr)) + if (!(perm = strtok_r(line, item->fs, &sptr)) + || !(users = strtok_r(NULL, item->fs, &sptr)) || !(froms = strtok_r(NULL, "\n", &sptr))) { pam_syslog(pamh, LOG_ERR, "%s: line %d: bad field count", item->config_file, lineno); @@ -373,17 +380,22 @@ login_access (pam_handle_t *pamh, struct item->config_file, lineno); continue; } - if (pam_access_debug) + if (item->debug) pam_syslog (pamh, LOG_DEBUG, "line %d: %s : %s : %s", lineno, perm, users, froms); - match = list_match(pamh, froms, item, from_match); - if (pam_access_debug) - pam_syslog (pamh, LOG_DEBUG, - "from_match=%d, \"%s\"", match, item->from); - match = match && list_match (pamh, users, item, user_match); - if (pam_access_debug) + match = list_match(pamh, users, NULL, item, user_match); + if (item->debug) pam_syslog (pamh, LOG_DEBUG, "user_match=%d, \"%s\"", match, item->user->pw_name); + if (match) { + match = list_match(pamh, froms, NULL, item, from_match); + if (!match && perm[0] == '+') { + nonall_match = YES; + } + if (item->debug) + pam_syslog (pamh, LOG_DEBUG, + "from_match=%d, \"%s\"", match, item->from); + } } (void) fclose(fp); } else if (errno == ENOENT) { @@ -394,20 +406,27 @@ login_access (pam_handle_t *pamh, struct pam_syslog(pamh, LOG_ERR, "cannot open %s: %m", item->config_file); return NO; } +#ifdef HAVE_LIBAUDIT + if (!item->noaudit && line[0] == '-' && (match == YES || (match == ALL && + nonall_match == YES))) { + pam_modutil_audit_write(pamh, AUDIT_ANOM_LOGIN_LOCATION, + "pam_access", 0); + } +#endif return (match == NO || (line[0] == '+')); } /* list_match - match an item against a list of tokens with exceptions */ -static int list_match(pam_handle_t *pamh, - char *list, struct login_info *item, match_func *match_fn) +static int +list_match(pam_handle_t *pamh, char *list, char *sptr, + struct login_info *item, match_func *match_fn) { char *tok; int match = NO; - char *sptr; - if (pam_access_debug) + if (item->debug && list != NULL) pam_syslog (pamh, LOG_DEBUG, "list_match: list=%s, item=%s", list, item->user->pw_name); @@ -418,8 +437,8 @@ static int list_match(pam_handle_t *pamh * the match is affected by any exceptions. */ - for (tok = strtok_r(list, sep, &sptr); tok != 0; - tok = strtok_r(NULL, sep, &sptr)) { + for (tok = strtok_r(list, item->sep, &sptr); tok != 0; + tok = strtok_r(NULL, item->sep, &sptr)) { if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */ break; if ((match = (*match_fn) (pamh, tok, item))) /* YES */ @@ -428,10 +447,12 @@ static int list_match(pam_handle_t *pamh /* Process exceptions to matches. */ if (match != NO) { - while ((tok = strtok_r(NULL, sep, &sptr)) && strcasecmp(tok, "EXCEPT")) + while ((tok = strtok_r(NULL, item->sep, &sptr)) && strcasecmp(tok, "EXCEPT")) /* VOID */ ; - if (tok == 0 || list_match(pamh, sptr, item, match_fn) == NO) - return (match); + if (tok == 0) + return match; + if (list_match(pamh, NULL, sptr, item, match_fn) == NO) + return YES; /* drop special meaning of ALL */ } return (NO); } @@ -453,7 +474,7 @@ static char *myhostname(void) static int netgroup_match (pam_handle_t *pamh, const char *netgroup, - const char *machine, const char *user) + const char *machine, const char *user, int debug) { char *mydomain = NULL; int retval; @@ -462,7 +483,7 @@ netgroup_match (pam_handle_t *pamh, cons retval = innetgr (netgroup, machine, user, mydomain); - if (pam_access_debug == YES) + if (debug == YES) pam_syslog (pamh, LOG_DEBUG, "netgroup_match: %d (netgroup=%s, machine=%s, user=%s, domain=%s)", retval, netgroup ? netgroup : "NULL", @@ -480,8 +501,9 @@ user_match (pam_handle_t *pamh, char *to char *string = item->user->pw_name; struct login_info fake_item; char *at; + int rv; - if (pam_access_debug) + if (item->debug) pam_syslog (pamh, LOG_DEBUG, "user_match: tok=%s, item=%s", tok, string); @@ -500,12 +522,12 @@ user_match (pam_handle_t *pamh, char *to return (user_match (pamh, tok, item) && from_match (pamh, at + 1, &fake_item)); } else if (tok[0] == '@') /* netgroup */ - return (netgroup_match (pamh, tok + 1, (char *) 0, string)); + return (netgroup_match (pamh, tok + 1, (char *) 0, string, item->debug)); else if (tok[0] == '(' && tok[strlen(tok) - 1] == ')') - return (group_match (pamh, tok, string)); - else if (string_match (pamh, tok, string)) /* ALL or exact match */ - return YES; - else if (only_new_group_syntax == NO && + return (group_match (pamh, tok, string, item->debug)); + else if ((rv=string_match (pamh, tok, string, item->debug)) != NO) /* ALL or exact match */ + return rv; + else if (item->only_new_group_syntax == NO && pam_modutil_user_in_group_nam_nam (pamh, item->user->pw_name, tok)) /* try group membership */ @@ -518,11 +540,12 @@ user_match (pam_handle_t *pamh, char *to /* group_match - match a username against token named group */ static int -group_match (pam_handle_t *pamh, const char *tok, const char* usr) +group_match (pam_handle_t *pamh, const char *tok, const char* usr, + int debug) { char grptok[BUFSIZ]; - if (pam_access_debug) + if (debug) pam_syslog (pamh, LOG_DEBUG, "group_match: grp=%s, user=%s", grptok, usr); @@ -548,8 +571,9 @@ from_match (pam_handle_t *pamh UNUSED, c const char *string = item->from; int tok_len; int str_len; + int rv; - if (pam_access_debug) + if (item->debug) pam_syslog (pamh, LOG_DEBUG, "from_match: tok=%s, item=%s", tok, string); @@ -565,10 +589,10 @@ from_match (pam_handle_t *pamh UNUSED, c if (string == NULL) { return NO; } else if (tok[0] == '@') { /* netgroup */ - return (netgroup_match (pamh, tok + 1, string, (char *) 0)); - } else if (string_match(pamh, tok, string)) { + return (netgroup_match (pamh, tok + 1, string, (char *) 0, item->debug)); + } else if ((rv = string_match(pamh, tok, string, item->debug)) != NO) { /* ALL or exact match */ - return (YES); + return rv; } else if (tok[0] == '.') { /* domain: match last fields */ if ((str_len = strlen(string)) > (tok_len = strlen(tok)) && strcasecmp(tok, string + str_len - tok_len) == 0) @@ -614,7 +638,7 @@ from_match (pam_handle_t *pamh UNUSED, c } } else if (isipaddr(string, NULL, NULL) == YES) { /* Assume network/netmask with a IP of a host. */ - if (network_netmask_match(pamh, tok, string)) + if (network_netmask_match(pamh, tok, string, item->debug)) return YES; } else { /* Assume network/netmask with a name of a host. */ @@ -641,7 +665,7 @@ from_match (pam_handle_t *pamh UNUSED, c : (void *) &((struct sockaddr_in6 *) runp->ai_addr)->sin6_addr, buf, sizeof (buf)); - if (network_netmask_match(pamh, tok, buf)) + if (network_netmask_match(pamh, tok, buf, item->debug)) { freeaddrinfo (res); return YES; @@ -658,10 +682,11 @@ from_match (pam_handle_t *pamh UNUSED, c /* string_match - match a string against one token */ static int -string_match (pam_handle_t *pamh, const char *tok, const char *string) +string_match (pam_handle_t *pamh, const char *tok, const char *string, + int debug) { - if (pam_access_debug) + if (debug) pam_syslog (pamh, LOG_DEBUG, "string_match: tok=%s, item=%s", tok, string); @@ -672,7 +697,7 @@ string_match (pam_handle_t *pamh, const */ if (strcasecmp(tok, "ALL") == 0) { /* all: always matches */ - return (YES); + return (ALL); } else if (string != NULL) { if (strcasecmp(tok, string) == 0) { /* try exact match */ return (YES); @@ -690,9 +715,9 @@ string_match (pam_handle_t *pamh, const */ static int network_netmask_match (pam_handle_t *pamh, - const char *tok, const char *string) + const char *tok, const char *string, int debug) { - if (pam_access_debug) + if (debug) pam_syslog (pamh, LOG_DEBUG, "network_netmask_match: tok=%s, item=%s", tok, string); @@ -771,6 +796,22 @@ pam_sm_authenticate (pam_handle_t *pamh, return PAM_USER_UNKNOWN; } + if ((user_pw=pam_modutil_getpwnam(pamh, user))==NULL) + return (PAM_USER_UNKNOWN); + + /* + * Bundle up the arguments to avoid unnecessary clumsiness later on. + */ + loginfo.user = user_pw; + loginfo.config_file = PAM_ACCESS_CONFIG; + + /* parse the argument list */ + + if (!parse_args(pamh, &loginfo, argc, argv)) { + pam_syslog(pamh, LOG_ERR, "failed to parse the module arguments"); + return PAM_ABORT; + } + /* remote host name */ if (pam_get_item(pamh, PAM_RHOST, &void_from) @@ -799,7 +840,7 @@ pam_sm_authenticate (pam_handle_t *pamh, return PAM_ABORT; } from = void_from; - if (pam_access_debug) + if (loginfo.debug) pam_syslog (pamh, LOG_DEBUG, "cannot determine tty or remote hostname, using service %s", from); @@ -817,22 +858,7 @@ pam_sm_authenticate (pam_handle_t *pamh, } } - if ((user_pw=pam_modutil_getpwnam(pamh, user))==NULL) - return (PAM_USER_UNKNOWN); - - /* - * Bundle up the arguments to avoid unnecessary clumsiness later on. - */ - loginfo.user = user_pw; loginfo.from = from; - loginfo.config_file = PAM_ACCESS_CONFIG; - - /* parse the argument list */ - - if (!parse_args(pamh, &loginfo, argc, argv)) { - pam_syslog(pamh, LOG_ERR, "failed to parse the module arguments"); - return PAM_ABORT; - } if (login_access(pamh, &loginfo)) { return (PAM_SUCCESS); diff -up Linux-PAM-0.99.8.1/modules/pam_time/pam_time.c.audit-failed Linux-PAM-0.99.8.1/modules/pam_time/pam_time.c --- Linux-PAM-0.99.8.1/modules/pam_time/pam_time.c.audit-failed 2006-06-16 08:35:16.000000000 +0200 +++ Linux-PAM-0.99.8.1/modules/pam_time/pam_time.c 2008-01-22 22:24:05.000000000 +0100 @@ -22,9 +22,16 @@ #include #include +#ifdef HAVE_LIBAUDIT +#include +#endif + #define PAM_TIME_BUFLEN 1000 #define FIELD_SEPARATOR ';' /* this is new as of .02 */ +#define PAM_DEBUG_ARG 0x0001 +#define PAM_NO_AUDIT 0x0002 + #ifndef TRUE # define TRUE 1 #endif @@ -46,6 +53,29 @@ typedef enum { AND, OR } operator; #include #include #include +#include + +static int +_pam_parse (const pam_handle_t *pamh, int argc, const char **argv) +{ + int ctrl = 0; + + /* step through arguments */ + for (; argc-- > 0; ++argv) { + + /* generic options */ + + if (!strcmp(*argv, "debug")) { + ctrl |= PAM_DEBUG_ARG; + } else if (!strcmp(*argv, "noaudit")) { + ctrl |= PAM_NO_AUDIT; + } else { + pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv); + } + } + + return ctrl; +} /* --- static functions for checking whether the user should be let in --- */ @@ -59,7 +89,7 @@ shift_bytes(char *mem, int from, int by) } static int -read_field(pam_handle_t *pamh, int fd, char **buf, int *from, int *to) +read_field(const pam_handle_t *pamh, int fd, char **buf, int *from, int *to) { /* is buf set ? */ @@ -137,6 +167,7 @@ read_field(pam_handle_t *pamh, int fd, c switch ((*buf)[i]) { int j,c; case '#': + c = 0; for (j=i; j < *to && (c = (*buf)[j]) != '\n'; ++j); if (j >= *to) { (*buf)[*to = ++i] = '\0'; @@ -324,6 +355,13 @@ is_same(pam_handle_t *pamh UNUSED, const return FALSE; } } + + /* Ok, we know that b is a substring from A and does not contain + wildcards, but now the length of both strings must be the same, + too. */ + if (strlen (a) != strlen(b)) + return FALSE; + return ( !len ); } @@ -559,11 +597,15 @@ check_account(pam_handle_t *pamh, const PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags UNUSED, - int argc UNUSED, const char **argv UNUSED) + int argc, const char **argv) { const void *service=NULL, *void_tty=NULL; const char *tty; const char *user=NULL; + int ctrl; + int rv; + + ctrl = _pam_parse(pamh, argc, argv); /* set service name */ @@ -612,7 +654,19 @@ pam_sm_acct_mgmt(pam_handle_t *pamh, int D(("user=%s", user)); D(("tty=%s", tty)); - return check_account(pamh, service, tty, user); + rv = check_account(pamh, service, tty, user); + if (rv != PAM_SUCCESS) { +#ifdef HAVE_LIBAUDIT + if (!(ctrl & PAM_NO_AUDIT)) { + pam_modutil_audit_write(pamh, AUDIT_ANOM_LOGIN_TIME, + "pam_time", rv); /* ignore return value as we fail anyway */ + } +#endif + if (ctrl & PAM_DEBUG_ARG) { + pam_syslog(pamh, LOG_DEBUG, "user %s rejected", user); + } + } + return rv; } /* end of module definition */ diff -up Linux-PAM-0.99.8.1/modules/pam_time/pam_time.8.xml.audit-failed Linux-PAM-0.99.8.1/modules/pam_time/pam_time.8.xml --- Linux-PAM-0.99.8.1/modules/pam_time/pam_time.8.xml.audit-failed 2006-06-22 21:44:30.000000000 +0200 +++ Linux-PAM-0.99.8.1/modules/pam_time/pam_time.8.xml 2008-01-22 22:24:05.000000000 +0100 @@ -22,6 +22,12 @@ pam_time.so + + debug + + + noaudit + @@ -41,11 +47,40 @@ By default rules for time/port access are taken from config file /etc/security/time.conf. + + If Linux PAM is compiled with audit support the module will report + when it denies access. + OPTIONS - This module does not recognice any options. + + + + + + + + + Some debug informations are printed with + syslog3. + + + + + + + + + + + Do not report logins at disallowed time to the audit subsystem. + + + + + diff -up Linux-PAM-0.99.8.1/modules/pam_limits/pam_limits.c.audit-failed Linux-PAM-0.99.8.1/modules/pam_limits/pam_limits.c --- Linux-PAM-0.99.8.1/modules/pam_limits/pam_limits.c.audit-failed 2007-07-10 12:10:56.000000000 +0200 +++ Linux-PAM-0.99.8.1/modules/pam_limits/pam_limits.c 2008-01-22 22:41:40.000000000 +0100 @@ -41,6 +41,10 @@ #include #include +#ifdef HAVE_LIBAUDIT +#include +#endif + /* Module defines */ #define LINE_LENGTH 1024 @@ -101,6 +105,7 @@ struct pam_limit_s { #define PAM_DEBUG_ARG 0x0001 #define PAM_DO_SETREUID 0x0002 #define PAM_UTMP_EARLY 0x0004 +#define PAM_NO_AUDIT 0x0008 /* Limits from globbed files. */ #define LIMITS_CONF_GLOB LIMITS_FILE_DIR @@ -126,6 +131,8 @@ _pam_parse (const pam_handle_t *pamh, in ctrl |= PAM_DO_SETREUID; } else if (!strcmp(*argv,"utmp_early")) { ctrl |= PAM_UTMP_EARLY; + } else if (!strcmp(*argv,"noaudit")) { + ctrl |= PAM_NO_AUDIT; } else { pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv); } @@ -599,6 +606,13 @@ static int setup_limits(pam_handle_t *pa D(("skip login limit check for uid=0")); } else if (pl->login_limit > 0) { if (check_logins(pamh, uname, pl->login_limit, ctrl, pl) == LOGIN_ERR) { +#ifdef HAVE_LIBAUDIT + if (!(ctrl & PAM_NO_AUDIT)) { + pam_modutil_audit_write(pamh, AUDIT_ANOM_LOGIN_SESSIONS, + "pam_limits", PAM_PERM_DENIED); + /* ignore return value as we fail anyway */ + } +#endif retval |= LOGIN_ERR; } } else if (pl->login_limit == 0) { diff -up Linux-PAM-0.99.8.1/modules/pam_limits/pam_limits.8.xml.audit-failed Linux-PAM-0.99.8.1/modules/pam_limits/pam_limits.8.xml --- Linux-PAM-0.99.8.1/modules/pam_limits/pam_limits.8.xml.audit-failed 2007-04-30 12:47:26.000000000 +0200 +++ Linux-PAM-0.99.8.1/modules/pam_limits/pam_limits.8.xml 2008-01-22 22:24:05.000000000 +0100 @@ -34,6 +34,9 @@ utmp_early + + noaudit + @@ -57,6 +60,11 @@ The module must not be called by a multithreaded application. + + If Linux PAM is compiled with audit support the module will report + when it denies access based on limit of maximum number of concurrent + login sessions. + @@ -111,6 +119,16 @@ + + + + + + + Do not report exceeded maximum logins count to the audit subsystem. + + +