aboutsummaryrefslogtreecommitdiff
path: root/modules/pam_access/pam_access.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/pam_access/pam_access.c')
-rw-r--r--modules/pam_access/pam_access.c195
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 */