aboutsummaryrefslogtreecommitdiff
path: root/src/backend/libpq/hba.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/libpq/hba.c')
-rw-r--r--src/backend/libpq/hba.c98
1 files changed, 67 insertions, 31 deletions
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 029b8e44838..adedbd31280 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -73,8 +73,10 @@ typedef struct
} tokenize_error_callback_arg;
#define token_has_regexp(t) (t->regex != NULL)
+#define token_is_member_check(t) (!t->quoted && t->string[0] == '+')
#define token_is_keyword(t, k) (!t->quoted && strcmp(t->string, k) == 0)
#define token_matches(t, k) (strcmp(t->string, k) == 0)
+#define token_matches_insensitive(t,k) (pg_strcasecmp(t->string, k) == 0)
/*
* Memory context holding the list of TokenizedAuthLines when parsing
@@ -995,10 +997,11 @@ is_member(Oid userid, const char *role)
*
* Each AuthToken listed is checked one-by-one. Keywords are processed
* first (these cannot have regular expressions), followed by regular
- * expressions (if any) and the exact match.
+ * expressions (if any), the case-insensitive match (if requested) and
+ * the exact match.
*/
static bool
-check_role(const char *role, Oid roleid, List *tokens)
+check_role(const char *role, Oid roleid, List *tokens, bool case_insensitive)
{
ListCell *cell;
AuthToken *tok;
@@ -1006,7 +1009,7 @@ check_role(const char *role, Oid roleid, List *tokens)
foreach(cell, tokens)
{
tok = lfirst(cell);
- if (!tok->quoted && tok->string[0] == '+')
+ if (token_is_member_check(tok))
{
if (is_member(roleid, tok->string + 1))
return true;
@@ -1018,6 +1021,11 @@ check_role(const char *role, Oid roleid, List *tokens)
if (regexec_auth_token(role, tok, 0, NULL) == REG_OKAY)
return true;
}
+ else if (case_insensitive)
+ {
+ if (token_matches_insensitive(tok, role))
+ return true;
+ }
else if (token_matches(tok, role))
return true;
}
@@ -2614,7 +2622,7 @@ check_hba(hbaPort *port)
hba->databases))
continue;
- if (!check_role(port->user_name, roleid, hba->roles))
+ if (!check_role(port->user_name, roleid, hba->roles, false))
continue;
/* Found a record that matched! */
@@ -2804,7 +2812,7 @@ parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
/*
* Now that the field validation is done, compile a regex from the user
- * token, if necessary.
+ * tokens, if necessary.
*/
if (regcomp_auth_token(parsedline->system_user, file_name, line_num,
err_msg, elevel))
@@ -2813,6 +2821,13 @@ parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
return NULL;
}
+ if (regcomp_auth_token(parsedline->pg_user, file_name, line_num,
+ err_msg, elevel))
+ {
+ /* err_msg includes the error to report */
+ return NULL;
+ }
+
return parsedline;
}
@@ -2827,6 +2842,8 @@ check_ident_usermap(IdentLine *identLine, const char *usermap_name,
const char *pg_user, const char *system_user,
bool case_insensitive, bool *found_p, bool *error_p)
{
+ Oid roleid;
+
*found_p = false;
*error_p = false;
@@ -2834,6 +2851,9 @@ check_ident_usermap(IdentLine *identLine, const char *usermap_name,
/* Line does not match the map name we're looking for, so just abort */
return;
+ /* Get the target role's OID. Note we do not error out for bad role. */
+ roleid = get_role_oid(pg_user, true);
+
/* Match? */
if (token_has_regexp(identLine->system_user))
{
@@ -2845,7 +2865,8 @@ check_ident_usermap(IdentLine *identLine, const char *usermap_name,
int r;
regmatch_t matches[2];
char *ofs;
- char *expanded_pg_user;
+ AuthToken *expanded_pg_user_token;
+ bool created_temporary_token = false;
r = regexec_auth_token(system_user, identLine->system_user, 2, matches);
if (r)
@@ -2865,8 +2886,16 @@ check_ident_usermap(IdentLine *identLine, const char *usermap_name,
return;
}
- if ((ofs = strstr(identLine->pg_user->string, "\\1")) != NULL)
+ /*
+ * Replace \1 with the first captured group unless the field already
+ * has some special meaning, like a group membership or a regexp-based
+ * check.
+ */
+ if (!token_is_member_check(identLine->pg_user) &&
+ !token_has_regexp(identLine->pg_user) &&
+ (ofs = strstr(identLine->pg_user->string, "\\1")) != NULL)
{
+ char *expanded_pg_user;
int offset;
/* substitution of the first argument requested */
@@ -2891,46 +2920,53 @@ check_ident_usermap(IdentLine *identLine, const char *usermap_name,
system_user + matches[1].rm_so,
matches[1].rm_eo - matches[1].rm_so);
strcat(expanded_pg_user, ofs + 2);
- }
- else
- {
- /* no substitution, so copy the match */
- expanded_pg_user = pstrdup(identLine->pg_user->string);
- }
- /*
- * now check if the username actually matched what the user is trying
- * to connect as
- */
- if (case_insensitive)
- {
- if (pg_strcasecmp(expanded_pg_user, pg_user) == 0)
- *found_p = true;
+ /*
+ * Mark the token as quoted, so it will only be compared literally
+ * and not for some special meaning, such as "all" or a group
+ * membership check.
+ */
+ expanded_pg_user_token = make_auth_token(expanded_pg_user, true);
+ created_temporary_token = true;
+ pfree(expanded_pg_user);
}
else
{
- if (strcmp(expanded_pg_user, pg_user) == 0)
- *found_p = true;
+ expanded_pg_user_token = identLine->pg_user;
}
- pfree(expanded_pg_user);
+
+ /* check the Postgres user */
+ *found_p = check_role(pg_user, roleid,
+ list_make1(expanded_pg_user_token),
+ case_insensitive);
+
+ if (created_temporary_token)
+ free_auth_token(expanded_pg_user_token);
return;
}
else
{
- /* Not regular expression, so make complete match */
+ /*
+ * Not a regular expression, so make a complete match. If the system
+ * user does not match, just leave.
+ */
if (case_insensitive)
{
- if (pg_strcasecmp(identLine->pg_user->string, pg_user) == 0 &&
- pg_strcasecmp(identLine->system_user->string, system_user) == 0)
- *found_p = true;
+ if (!token_matches_insensitive(identLine->system_user,
+ system_user))
+ return;
}
else
{
- if (strcmp(identLine->pg_user->string, pg_user) == 0 &&
- strcmp(identLine->system_user->string, system_user) == 0)
- *found_p = true;
+ if (!token_matches(identLine->system_user, system_user))
+ return;
}
+
+ /* check the Postgres user */
+ *found_p = check_role(pg_user, roleid,
+ list_make1(identLine->pg_user),
+ case_insensitive);
}
}