@ -73,8 +73,10 @@ typedef struct
} tokenize_error_callback_arg ;
} tokenize_error_callback_arg ;
# define token_has_regexp(t) (t->regex != NULL)
# 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_is_keyword(t, k) (!t->quoted && strcmp(t->string, k) == 0)
# define token_matches(t, k) (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
* 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
* Each AuthToken listed is checked one - by - one . Keywords are processed
* first ( these cannot have regular expressions ) , followed by regular
* 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
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 ;
ListCell * cell ;
AuthToken * tok ;
AuthToken * tok ;
@ -1006,7 +1009,7 @@ check_role(const char *role, Oid roleid, List *tokens)
foreach ( cell , tokens )
foreach ( cell , tokens )
{
{
tok = lfirst ( cell ) ;
tok = lfirst ( cell ) ;
if ( ! tok - > quoted & & tok - > string [ 0 ] = = ' + ' )
if ( token_is_member_check ( tok ) )
{
{
if ( is_member ( roleid , tok - > string + 1 ) )
if ( is_member ( roleid , tok - > string + 1 ) )
return true ;
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 )
if ( regexec_auth_token ( role , tok , 0 , NULL ) = = REG_OKAY )
return true ;
return true ;
}
}
else if ( case_insensitive )
{
if ( token_matches_insensitive ( tok , role ) )
return true ;
}
else if ( token_matches ( tok , role ) )
else if ( token_matches ( tok , role ) )
return true ;
return true ;
}
}
@ -2614,7 +2622,7 @@ check_hba(hbaPort *port)
hba - > databases ) )
hba - > databases ) )
continue ;
continue ;
if ( ! check_role ( port - > user_name , roleid , hba - > roles ) )
if ( ! check_role ( port - > user_name , roleid , hba - > roles , false ) )
continue ;
continue ;
/* Found a record that matched! */
/* 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
* 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 ,
if ( regcomp_auth_token ( parsedline - > system_user , file_name , line_num ,
err_msg , elevel ) )
err_msg , elevel ) )
@ -2813,6 +2821,13 @@ parse_ident_line(TokenizedAuthLine *tok_line, int elevel)
return NULL ;
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 ;
return parsedline ;
}
}
@ -2827,6 +2842,8 @@ check_ident_usermap(IdentLine *identLine, const char *usermap_name,
const char * pg_user , const char * system_user ,
const char * pg_user , const char * system_user ,
bool case_insensitive , bool * found_p , bool * error_p )
bool case_insensitive , bool * found_p , bool * error_p )
{
{
Oid roleid ;
* found_p = false ;
* found_p = false ;
* error_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 */
/* Line does not match the map name we're looking for, so just abort */
return ;
return ;
/* Get the target role's OID. Note we do not error out for bad role. */
roleid = get_role_oid ( pg_user , true ) ;
/* Match? */
/* Match? */
if ( token_has_regexp ( identLine - > system_user ) )
if ( token_has_regexp ( identLine - > system_user ) )
{
{
@ -2845,7 +2865,8 @@ check_ident_usermap(IdentLine *identLine, const char *usermap_name,
int r ;
int r ;
regmatch_t matches [ 2 ] ;
regmatch_t matches [ 2 ] ;
char * ofs ;
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 ) ;
r = regexec_auth_token ( system_user , identLine - > system_user , 2 , matches ) ;
if ( r )
if ( r )
@ -2865,8 +2886,16 @@ check_ident_usermap(IdentLine *identLine, const char *usermap_name,
return ;
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 ;
int offset ;
/* substitution of the first argument requested */
/* 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 ,
system_user + matches [ 1 ] . rm_so ,
matches [ 1 ] . rm_eo - matches [ 1 ] . rm_so ) ;
matches [ 1 ] . rm_eo - matches [ 1 ] . rm_so ) ;
strcat ( expanded_pg_user , ofs + 2 ) ;
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
* Mark the token as quoted , so it will only be compared literally
* to connect as
* and not for some special meaning , such as " all " or a group
* membership check .
*/
*/
if ( case_insensitive )
expanded_pg_user_token = make_auth_token ( expanded_pg_user , true ) ;
{
created_temporary_token = true ;
if ( pg_strcasecmp ( expanded_pg_user , pg_user ) = = 0 )
pfree ( expanded_pg_user ) ;
* found_p = true ;
}
}
else
else
{
{
if ( strcmp ( expanded_pg_user , pg_user ) = = 0 )
expanded_pg_user_token = identLine - > pg_user ;
* found_p = true ;
}
}
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 ;
return ;
}
}
else
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 ( case_insensitive )
{
{
if ( pg_strcasecmp ( identLine - > pg_user - > string , pg_user ) = = 0 & &
if ( ! token_matches_insensitive ( identLine - > system_user ,
pg_strcasecmp ( identLine - > system_user - > string , system_user ) = = 0 )
system_user ) )
* found_p = true ;
return ;
}
}
else
else
{
{
if ( strcmp ( identLine - > pg_user - > string , pg_user ) = = 0 & &
if ( ! token_matches ( identLine - > system_user , system_user ) )
strcmp ( identLine - > system_user - > string , system_user ) = = 0 )
return ;
* found_p = true ;
}
}
/* check the Postgres user */
* found_p = check_role ( pg_user , roleid ,
list_make1 ( identLine - > pg_user ) ,
case_insensitive ) ;
}
}
}
}