diff --git a/pam-0.99.8.1-audit-failed.patch b/pam-0.99.8.1-audit-failed.patch
new file mode 100644
index 0000000..33580b1
--- /dev/null
+++ b/pam-0.99.8.1-audit-failed.patch
@@ -0,0 +1,838 @@
+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; ifs = argv[i]+9;
+
+ } else if (!strncmp("listsep=", argv[i], 8)) {
+
+ /* the admin wants to override the default list separators */
+- sep = argv[i]+8;
++ loginfo->sep = argv[i]+8;
+
+ } else if (!strncmp("accessfile=", argv[i], 11)) {
+ FILE *fp = fopen(11 + argv[i], "r");
+@@ -138,9 +142,11 @@ parse_args(pam_handle_t *pamh, struct lo
+ }
+
+ } else if (strcmp (argv[i], "debug") == 0) {
+- pam_access_debug = YES;
++ loginfo->debug = 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.
++
++
++
+
+
+
diff --git a/pam.spec b/pam.spec
index 2014923..5e64588 100644
--- a/pam.spec
+++ b/pam.spec
@@ -11,7 +11,7 @@
Summary: A security tool which provides authentication for applications
Name: pam
Version: 0.99.8.1
-Release: 15%{?dist}
+Release: 16%{?dist}
# The library is BSD licensed with option to relicense as GPLv2+ - this option is redundant
# as the BSD license allows that anyway. pam_timestamp and pam_console modules are GPLv2+,
# pam_rhosts_auth module is BSD with advertising
@@ -46,6 +46,7 @@ Patch47: pam-0.99.8.1-xauth-no-free.patch
Patch48: pam-0.99.8.1-substack.patch
Patch49: pam-0.99.8.1-tty-audit.patch
Patch50: pam-0.99.8.1-tty-audit2.patch
+Patch51: pam-0.99.8.1-audit-failed.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
Requires: cracklib, cracklib-dicts >= 2.8
@@ -117,6 +118,7 @@ popd
%patch48 -p0 -b .substack
%patch49 -p1 -b .tty-audit
%patch50 -p1 -b .tty-audit2
+%patch51 -p1 -b .audit-failed
autoreconf
@@ -158,6 +160,7 @@ LDFLAGS=-L${topdir}/%{_lib} ; export LDFLAGS
--enable-isadir=../../%{_lib}/security \
--with-db-uniquename=_pam
make
+# we do not use _smp_mflags because the build of sources in yacc/flex fails
%install
rm -rf $RPM_BUILD_ROOT
@@ -188,35 +191,6 @@ install -m 600 /dev/null $RPM_BUILD_ROOT/var/log/tallylog
# Install man pages.
install -m 644 %{SOURCE9} %{SOURCE10} $RPM_BUILD_ROOT%{_mandir}/man5/
-# Make sure every module subdirectory gave us a module. Yes, this is hackish.
-for dir in modules/pam_* ; do
-if [ -d ${dir} ] ; then
- if ! ls -1 $RPM_BUILD_ROOT/%{_lib}/security/`basename ${dir}`*.so ; then
- echo ERROR `basename ${dir}` did not build a module.
- exit 1
- fi
-fi
-done
-
-# Check for module problems. Specifically, check that every module we just
-# installed can actually be loaded by a minimal PAM-aware application.
-/sbin/ldconfig -n $RPM_BUILD_ROOT/%{_lib}
-for module in $RPM_BUILD_ROOT/%{_lib}/security/pam*.so ; do
- if ! env LD_LIBRARY_PATH=$RPM_BUILD_ROOT/%{_lib} \
- %{SOURCE8} -ldl -lpam -L$RPM_BUILD_ROOT/%{_lib} ${module} ; then
- echo ERROR module: ${module} cannot be loaded.
- exit 1
- fi
-# And for good measure, make sure that none of the modules pull in threading
-# libraries, which if loaded in a non-threaded application, can cause Very
-# Bad Things to happen.
- if env LD_LIBRARY_PATH=$RPM_BUILD_ROOT/%{_lib} \
- LD_PRELOAD=$RPM_BUILD_ROOT/%{_lib}/libpam.so ldd -r ${module} | fgrep -q libpthread ; then
- echo ERROR module: ${module} pulls threading libraries.
- exit 1
- fi
-done
-
for phase in auth acct passwd session ; do
ln -sf pam_unix.so $RPM_BUILD_ROOT/%{_lib}/security/pam_unix_${phase}.so
done
@@ -241,6 +215,36 @@ install -m755 -d $RPM_BUILD_ROOT/lib/security
%find_lang Linux-PAM
+%check
+# Make sure every module subdirectory gave us a module. Yes, this is hackish.
+for dir in modules/pam_* ; do
+if [ -d ${dir} ] ; then
+ if ! ls -1 $RPM_BUILD_ROOT/%{_lib}/security/`basename ${dir}`*.so ; then
+ echo ERROR `basename ${dir}` did not build a module.
+ exit 1
+ fi
+fi
+done
+
+# Check for module problems. Specifically, check that every module we just
+# installed can actually be loaded by a minimal PAM-aware application.
+/sbin/ldconfig -n $RPM_BUILD_ROOT/%{_lib}
+for module in $RPM_BUILD_ROOT/%{_lib}/security/pam*.so ; do
+ if ! env LD_LIBRARY_PATH=$RPM_BUILD_ROOT/%{_lib} \
+ %{SOURCE8} -ldl -lpam -L$RPM_BUILD_ROOT/%{_lib} ${module} ; then
+ echo ERROR module: ${module} cannot be loaded.
+ exit 1
+ fi
+# And for good measure, make sure that none of the modules pull in threading
+# libraries, which if loaded in a non-threaded application, can cause Very
+# Bad Things to happen.
+ if env LD_LIBRARY_PATH=$RPM_BUILD_ROOT/%{_lib} \
+ LD_PRELOAD=$RPM_BUILD_ROOT%{_libdir}/libpam.so ldd -r ${module} | fgrep -q libpthread ; then
+ echo ERROR module: ${module} pulls threading libraries.
+ exit 1
+ fi
+done
+
%clean
rm -rf $RPM_BUILD_ROOT
@@ -364,6 +368,10 @@ fi
%doc doc/adg/*.txt doc/adg/html
%changelog
+* Tue Jan 22 2008 Tomas Mraz 0.99.8.1-16
+- add auditing to pam_access, pam_limits, and pam_time
+- moved sanity testing code to check script
+
* Mon Jan 14 2008 Tomas Mraz 0.99.8.1-15
- merge review fixes (#226228)