diff options
Diffstat (limited to 'modules/pam_access/pam_access.c')
-rw-r--r-- | modules/pam_access/pam_access.c | 195 |
1 files changed, 146 insertions, 49 deletions
diff --git a/modules/pam_access/pam_access.c b/modules/pam_access/pam_access.c index f70b7e49..48e7c7e9 100644 --- a/modules/pam_access/pam_access.c +++ b/modules/pam_access/pam_access.c @@ -56,11 +56,11 @@ #include "pam_cc_compat.h" #include "pam_inline.h" -#define PAM_ACCESS_CONFIG (SCONFIGDIR "/access.conf") -#define ACCESS_CONF_GLOB (SCONFIGDIR "/access.d/*.conf") -#ifdef VENDOR_SCONFIGDIR -#define VENDOR_PAM_ACCESS_CONFIG (VENDOR_SCONFIGDIR "/access.conf") -#define VENDOR_ACCESS_CONF_GLOB (VENDOR_SCONFIGDIR "/access.d/*.conf") +#define PAM_ACCESS_CONFIG (SCONFIG_DIR "/access.conf") +#define ACCESS_CONF_GLOB (SCONFIG_DIR "/access.d/*.conf") +#ifdef VENDOR_SCONFIG_DIR +#define VENDOR_PAM_ACCESS_CONFIG (VENDOR_SCONFIG_DIR "/access.conf") +#define VENDOR_ACCESS_CONF_GLOB (VENDOR_SCONFIG_DIR "/access.d/*.conf") #endif /* login_access.c from logdaemon-5.6 with several changes by A.Nogin: */ @@ -85,7 +85,7 @@ #define ALL 2 #define YES 1 #define NO 0 -#define NOMATCH -1 +#define NOMATCH (-1) /* * A structure to bundle up all login-related information to keep the @@ -99,6 +99,7 @@ struct login_info { int debug; /* Print debugging messages. */ int only_new_group_syntax; /* Only allow group entries of the form "(xyz)" */ int noaudit; /* Do not audit denials */ + int quiet_log; /* Do not log denials */ const char *fs; /* field separator */ const char *sep; /* list-element separator */ int from_remote_host; /* If PAM_RHOST was used for from */ @@ -115,6 +116,7 @@ parse_args(pam_handle_t *pamh, struct login_info *loginfo, int i; loginfo->noaudit = NO; + loginfo->quiet_log = NO; loginfo->debug = NO; loginfo->only_new_group_syntax = NO; loginfo->fs = ":"; @@ -150,6 +152,8 @@ parse_args(pam_handle_t *pamh, struct login_info *loginfo, loginfo->only_new_group_syntax = YES; } else if (strcmp (argv[i], "noaudit") == 0) { loginfo->noaudit = YES; + } else if (strcmp (argv[i], "quiet_log") == 0) { + loginfo->quiet_log = YES; } else { pam_syslog(pamh, LOG_ERR, "unrecognized option [%s]", argv[i]); } @@ -158,7 +162,7 @@ parse_args(pam_handle_t *pamh, struct login_info *loginfo, return 1; /* OK */ } -/* --- evaluting all files in VENDORDIR/security/access.d and /etc/security/access.d --- */ +/* --- evaluating all files in VENDORDIR/security/access.d and /etc/security/access.d --- */ static const char *base_name(const char *path) { const char *base = strrchr(path, '/'); @@ -254,7 +258,7 @@ typedef int match_func (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 *, int); +static int group_match (pam_handle_t *, char *, const char *, int); static int from_match (pam_handle_t *, char *, struct login_info *); static int remote_match (pam_handle_t *, char *, struct login_info *); static int string_match (pam_handle_t *, const char *, const char *, int); @@ -302,6 +306,23 @@ isipaddr (const char *string, int *addr_type, return is_ip; } +/* is_local_addr - checks if the IP address is local */ +static int +is_local_addr (const char *string, int addr_type) +{ + if (addr_type == AF_INET) { + if (strcmp(string, "127.0.0.1") == 0) { + return YES; + } + } else if (addr_type == AF_INET6) { + if (strcmp(string, "::1") == 0) { + return YES; + } + } + + return NO; +} + /* are_addresses_equal - translate IP address strings to real IP * addresses and compare them to find out if they are equal. @@ -323,9 +344,18 @@ are_addresses_equal (const char *ipaddr0, const char *ipaddr1, if (isipaddr (ipaddr1, &addr_type1, &addr1) == NO) return NO; - if (addr_type0 != addr_type1) - /* different address types */ + if (addr_type0 != addr_type1) { + /* different address types, but there is still a possibility that they are + * both local addresses + */ + int local1 = is_local_addr(ipaddr0, addr_type0); + int local2 = is_local_addr(ipaddr1, addr_type1); + + if (local1 == YES && local2 == YES) + return YES; + return NO; + } if (netmask != NULL) { /* Got a netmask, so normalize addresses? */ @@ -419,7 +449,7 @@ static int login_access (pam_handle_t *pamh, struct login_info *item) { FILE *fp; - char line[BUFSIZ]; + char *line = NULL; char *perm; /* becomes permission field */ char *users; /* becomes list of login names */ char *froms; /* becomes list of terminals or hosts */ @@ -427,8 +457,10 @@ login_access (pam_handle_t *pamh, struct login_info *item) #ifdef HAVE_LIBAUDIT int nonall_match = NO; #endif - int end; - int lineno = 0; /* for diagnostics */ + int result; + size_t end; + size_t lineno = 0; /* for diagnostics */ + size_t n = 0; char *sptr; if (item->debug) @@ -446,17 +478,19 @@ login_access (pam_handle_t *pamh, struct login_info *item) */ if ((fp = fopen(item->config_file, "r"))!=NULL) { - while (!match && fgets(line, sizeof(line), fp)) { + while (!match && getline(&line, &n, fp) != -1) { lineno++; + if (line[0] == 0) + continue; if (line[end = strlen(line) - 1] != '\n') { pam_syslog(pamh, LOG_ERR, - "%s: line %d: missing newline or line too long", + "%s: line %zu: missing newline or line too long", item->config_file, lineno); continue; } if (line[0] == '#') continue; /* comment line */ - while (end > 0 && isspace(line[end - 1])) + while (end > 0 && isspace((unsigned char)line[end - 1])) end--; line[end] = 0; /* strip trailing whitespace */ if (line[0] == 0) /* skip blank lines */ @@ -466,18 +500,18 @@ login_access (pam_handle_t *pamh, struct login_info *item) 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", + pam_syslog(pamh, LOG_ERR, "%s: line %zu: bad field count", item->config_file, lineno); continue; } if (perm[0] != '+' && perm[0] != '-') { - pam_syslog(pamh, LOG_ERR, "%s: line %d: bad first field", + pam_syslog(pamh, LOG_ERR, "%s: line %zu: bad first field", item->config_file, lineno); continue; } if (item->debug) pam_syslog (pamh, LOG_DEBUG, - "line %d: %s : %s : %s", lineno, perm, users, froms); + "line %zu: %s : %s : %s", lineno, perm, users, froms); match = list_match(pamh, users, NULL, item, user_match); if (item->debug) pam_syslog (pamh, LOG_DEBUG, "user_match=%d, \"%s\"", @@ -505,16 +539,19 @@ login_access (pam_handle_t *pamh, struct login_info *item) } #ifdef HAVE_LIBAUDIT if (!item->noaudit && (match == YES || (match == ALL && - nonall_match == YES)) && line[0] == '-') { + nonall_match == YES)) && line != NULL && line[0] == '-') { pam_modutil_audit_write(pamh, AUDIT_ANOM_LOGIN_LOCATION, "pam_access", 0); } #endif if (match == NO) - return NOMATCH; - if (line[0] == '+') - return YES; - return NO; + result = NOMATCH; + else if (line != NULL && line[0] == '+') + result = YES; + else + result = NO; + free(line); + return result; } @@ -594,7 +631,30 @@ netgroup_match (pam_handle_t *pamh, const char *netgroup, return retval; } -/* user_match - match a username against one token */ +/* user_name_or_uid_match - match a username or user uid against one token */ +static int +user_name_or_uid_match(pam_handle_t *pamh, const char *tok, + const struct login_info *item) +{ + /* ALL or exact match of username */ + int rv = string_match(pamh, tok, item->user->pw_name, item->debug); + if (rv != NO) + return rv; + + if (tok[strspn(tok, "0123456789")] != '\0') + return NO; + + char buf[sizeof(long long) * 3 + 1]; + snprintf(buf, sizeof(buf), "%llu", + zero_extend_signed_to_ull(item->user->pw_uid)); + if (item->debug) + pam_syslog(pamh, LOG_DEBUG, "user_match: tok=%s, uid=%s", tok, buf); + + /* check for exact match of uid */ + return string_match (pamh, tok, buf, item->debug); +} + +/* user_match - match a user against one token */ static int user_match (pam_handle_t *pamh, char *tok, struct login_info *item) @@ -645,7 +705,7 @@ user_match (pam_handle_t *pamh, char *tok, struct login_info *item) hostname = item->hostname; } return (netgroup_match (pamh, tok + 1, hostname, string, item->debug)); - } else if ((rv=string_match (pamh, tok, string, item->debug)) != NO) /* ALL or exact match */ + } else if ((rv=user_name_or_uid_match(pamh, tok, item)) != NO) /* ALL or exact match */ return rv; else if (item->only_new_group_syntax == NO && pam_modutil_user_in_group_nam_nam (pamh, @@ -657,14 +717,41 @@ user_match (pam_handle_t *pamh, char *tok, struct login_info *item) } +/* group_name_or_gid_match - match a group name or group gid against one token */ +static int +group_name_or_gid_match(pam_handle_t *pamh, const char *tok, + const char *usr, int debug) +{ + /* check for exact match of group name */ + if (pam_modutil_user_in_group_nam_nam(pamh, usr, tok) != NO) + return YES; + + if (tok[strspn(tok, "0123456789")] != '\0') + return NO; + + char *endptr = NULL; + errno = 0; + unsigned long int ul = strtoul(tok, &endptr, 10); + gid_t gid = (gid_t) ul; + if (errno != 0 + || tok == endptr + || *endptr != '\0' + || (unsigned long) zero_extend_signed_to_ull(gid) != ul) { + return NO; + } + + if (debug) + pam_syslog(pamh, LOG_DEBUG, "group_match: user=%s, gid=%s", usr, tok); + + /* check for exact match of gid */ + return pam_modutil_user_in_group_nam_gid(pamh, usr, gid); +} + /* group_match - match a username against token named group */ static int -group_match (pam_handle_t *pamh, const char *tok, const char* usr, - int debug) +group_match (pam_handle_t *pamh, char *tok, const char* usr, int debug) { - char grptok[BUFSIZ] = {}; - if (debug) pam_syslog (pamh, LOG_DEBUG, "group_match: grp=%s, user=%s", tok, usr); @@ -673,12 +760,13 @@ group_match (pam_handle_t *pamh, const char *tok, const char* usr, return NO; /* token is received under the format '(...)' */ - strncpy(grptok, tok + 1, strlen(tok) - 2); + tok++; + tok[strlen(tok) - 1] = '\0'; - if (pam_modutil_user_in_group_nam_nam(pamh, usr, grptok)) + if (group_name_or_gid_match (pamh, usr, tok, debug)) return YES; - return NO; + return NO; } @@ -757,7 +845,7 @@ remote_match (pam_handle_t *pamh, char *tok, struct login_info *item) DIAG_PUSH_IGNORE_CAST_ALIGN; inet_ntop (runp->ai_family, &((struct sockaddr_in *) runp->ai_addr)->sin_addr, - buf, sizeof (buf)); + buf, sizeof (buf) - 1); DIAG_POP_IGNORE_CAST_ALIGN; strcat (buf, "."); @@ -876,7 +964,8 @@ network_netmask_match (pam_handle_t *pamh, */ if (getaddrinfo (tok, NULL, NULL, &ai) != 0) { - pam_syslog(pamh, LOG_ERR, "cannot resolve hostname \"%s\"", tok); + if (item->debug) + pam_syslog(pamh, LOG_DEBUG, "cannot resolve hostname \"%s\"", tok); return NO; } @@ -967,9 +1056,8 @@ network_netmask_match (pam_handle_t *pamh, /* --- public PAM management functions --- */ -int -pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED, - int argc, const char **argv) +static int +pam_access(pam_handle_t *pamh, int argc, const char **argv) { struct login_info loginfo; const char *user=NULL; @@ -1099,8 +1187,10 @@ pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED, if (rv) { return (PAM_SUCCESS); } else { - pam_syslog(pamh, LOG_ERR, - "access denied for user `%s' from `%s'",user,from); + if (!loginfo.quiet_log) { + pam_syslog(pamh, LOG_ERR, + "access denied for user `%s' from `%s'",user,from); + } return (PAM_PERM_DENIED); } } @@ -1113,31 +1203,38 @@ pam_sm_setcred (pam_handle_t *pamh UNUSED, int flags UNUSED, } int -pam_sm_acct_mgmt (pam_handle_t *pamh, int flags, - int argc, const char **argv) +pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED, + int argc, const char **argv) +{ + return pam_access(pamh, argc, argv); +} + +int +pam_sm_acct_mgmt(pam_handle_t *pamh, int flags UNUSED, + int argc, const char **argv) { - return pam_sm_authenticate (pamh, flags, argc, argv); + return pam_access(pamh, argc, argv); } int -pam_sm_open_session(pam_handle_t *pamh, int flags, +pam_sm_open_session(pam_handle_t *pamh, int flags UNUSED, int argc, const char **argv) { - return pam_sm_authenticate(pamh, flags, argc, argv); + return pam_access(pamh, argc, argv); } int -pam_sm_close_session(pam_handle_t *pamh, int flags, +pam_sm_close_session(pam_handle_t *pamh, int flags UNUSED, int argc, const char **argv) { - return pam_sm_authenticate(pamh, flags, argc, argv); + return pam_access(pamh, argc, argv); } int -pam_sm_chauthtok(pam_handle_t *pamh, int flags, +pam_sm_chauthtok(pam_handle_t *pamh, int flags UNUSED, int argc, const char **argv) { - return pam_sm_authenticate(pamh, flags, argc, argv); + return pam_access(pamh, argc, argv); } /* end of module definition */ |