diff options
Diffstat (limited to 'src/backend/libpq/hba.c')
-rw-r--r-- | src/backend/libpq/hba.c | 98 |
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); } } |