Fix crash when user mapping has no user name

When a user mapping is created without a user name in the options a
crash will occur when querying a distributed hypertable.

This change fixes the crash by using the "current user" when no user
option exists (i.e., no user mapping is done). This makes it possible
to create user mappings that only provide the password option.
This commit is contained in:
Erik Nordström 2020-12-17 00:37:09 +01:00 committed by Erik Nordström
parent 0f48f1b29d
commit 15e1edb76f
3 changed files with 43 additions and 10 deletions

View File

@ -455,7 +455,6 @@ extract_connection_options(List *defelems, const char **keywords, const char **v
}
}
Assert(*user != NULL);
return option_pos;
}
@ -992,6 +991,10 @@ remote_connection_set_peer_dist_id(TSConnection *conn)
/* sslmode, sslrootcert, sslcert, sslkey */
#define REMOTE_CONNECTION_SSL_OPTIONS_N 4
#define REMOTE_CONNECTION_OPTIONS_TOTAL_N \
(REMOTE_CONNECTION_SESSION_OPTIONS_N + REMOTE_CONNECTION_PASSWORD_OPTIONS_N + \
REMOTE_CONNECTION_SSL_OPTIONS_N)
/* default password file basename */
#define DEFAULT_PASSFILE_NAME "passfile"
@ -1154,13 +1157,15 @@ remote_connection_open_with_options_nothrow(const char *node_name, List *connect
* for fallback_application_name, client_encoding, end marker.
* One additional slot to set passfile and 4 slots for ssl options.
*/
option_count = list_length(connection_options) + REMOTE_CONNECTION_SESSION_OPTIONS_N +
REMOTE_CONNECTION_PASSWORD_OPTIONS_N + REMOTE_CONNECTION_SSL_OPTIONS_N;
option_count = list_length(connection_options) + REMOTE_CONNECTION_OPTIONS_TOTAL_N;
keywords = (const char **) palloc(option_count * sizeof(char *));
values = (const char **) palloc(option_count * sizeof(char *));
option_pos = extract_connection_options(connection_options, keywords, values, &user_name);
if (NULL == user_name)
user_name = GetUserNameFromId(GetUserId(), false);
/* Use the extension name as fallback_application_name. */
keywords[option_pos] = "fallback_application_name";
values[option_pos] = EXTENSION_NAME;
@ -1392,6 +1397,22 @@ get_user_mapping(Oid userid, Oid serverid)
return um;
}
static bool
options_contain(List *options, const char *key)
{
ListCell *lc;
foreach (lc, options)
{
DefElem *d = (DefElem *) lfirst(lc);
if (strcmp(d->defname, key) == 0)
return true;
}
return false;
}
/*
* Add user info (username and optionally password) to the connection
* options).
@ -1399,19 +1420,23 @@ get_user_mapping(Oid userid, Oid serverid)
static List *
add_userinfo_to_server_options(ForeignServer *server, Oid user_id)
{
const char *user_name = GetUserNameFromId(user_id, false);
List *server_options = list_copy(server->options);
const UserMapping *um = get_user_mapping(user_id, server->serverid);
List *options = list_copy(server->options);
/* If a user mapping exists, then use the "user" and "password" options
* from the user mapping (we assume that these options exist, or the
* connection will later fail). Otherwise, just add the "user" and rely on
* other authentication mechanisms. */
if (NULL != um)
return list_concat(server_options, um->options);
options = list_concat(options, um->options);
return lappend(server_options,
makeDefElem("user", (Node *) makeString(pstrdup(user_name)), -1));
if (!options_contain(options, "user"))
{
char *user_name = GetUserNameFromId(user_id, false);
options = lappend(options, makeDefElem("user", (Node *) makeString(user_name), -1));
}
return options;
}
TSConnection *

View File

@ -752,7 +752,9 @@ NOTICE: adding not-null constraint to column "time"
ERROR: could not connect to "data2"
\set ON_ERROR_STOP 1
RESET ROLE;
CREATE USER MAPPING FOR :ROLE_3 SERVER data2 OPTIONS (user :'ROLE_3', password :'ROLE_3_PASS');
-- Create user mapping for ROLE_3, but don't specify user in
-- options. The "current user" will instead be used when connecting.
CREATE USER MAPPING FOR :ROLE_3 SERVER data2 OPTIONS (password :'ROLE_3_PASS');
SET ROLE :ROLE_3;
-- User should be able to connect and create the distributed
-- hypertable at this point.
@ -771,3 +773,5 @@ SELECT * FROM disttable_role_3;
Tue Jan 01 00:00:00 2019 PST | 1 | 23.4
(1 row)
DROP USER MAPPING FOR :ROLE_3 SERVER data1;
DROP USER MAPPING FOR :ROLE_3 SERVER data2;

View File

@ -262,7 +262,9 @@ SELECT * FROM create_distributed_hypertable('disttable_role_3', 'time', data_nod
\set ON_ERROR_STOP 1
RESET ROLE;
CREATE USER MAPPING FOR :ROLE_3 SERVER data2 OPTIONS (user :'ROLE_3', password :'ROLE_3_PASS');
-- Create user mapping for ROLE_3, but don't specify user in
-- options. The "current user" will instead be used when connecting.
CREATE USER MAPPING FOR :ROLE_3 SERVER data2 OPTIONS (password :'ROLE_3_PASS');
SET ROLE :ROLE_3;
-- User should be able to connect and create the distributed
@ -273,3 +275,5 @@ SELECT * FROM create_distributed_hypertable('disttable_role_3', 'time', data_nod
INSERT INTO disttable_role_3 VALUES ('2019-01-01 00:00:00', 1, 23.4);
SELECT * FROM disttable_role_3;
DROP USER MAPPING FOR :ROLE_3 SERVER data1;
DROP USER MAPPING FOR :ROLE_3 SERVER data2;