From 2badd4f116d18d84ac2e8de09bba9be6ba29c66b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Mr=C3=A1z?= Date: Tue, 22 Jan 2008 21:52:13 +0000 Subject: [PATCH] - add auditing to pam_access, pam_limits, and pam_time - moved sanity testing code to check script --- pam-0.99.8.1-audit-failed.patch | 838 ++++++++++++++++++++++++++++++++ pam.spec | 68 +-- 2 files changed, 876 insertions(+), 30 deletions(-) create mode 100644 pam-0.99.8.1-audit-failed.patch 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; 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. ++ ++ ++ + + + 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)