25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-12-20 17:27:00 +01:00

Update SQL escaping

This commit is contained in:
Alexey Shchepin 2016-05-12 18:32:13 +03:00
parent be2a9e35ae
commit 792f47b4bd
7 changed files with 85 additions and 28 deletions

View File

@ -43,6 +43,7 @@
escape/1,
escape_like/1,
escape_like_arg/1,
escape_like_arg_circumflex/1,
to_bool/1,
sqlite_db/1,
sqlite_file/1,
@ -200,6 +201,7 @@ escape_like(S) when is_binary(S) ->
<< <<(escape_like(C))/binary>> || <<C>> <= S >>;
escape_like($%) -> <<"\\%">>;
escape_like($_) -> <<"\\_">>;
escape_like($\\) -> <<"\\\\\\\\">>;
escape_like(C) when is_integer(C), C >= 0, C =< 255 -> sql_queries:escape(C).
escape_like_arg(S) when is_binary(S) ->
@ -209,6 +211,13 @@ escape_like_arg($_) -> <<"\\_">>;
escape_like_arg($\\) -> <<"\\\\">>;
escape_like_arg(C) when is_integer(C), C >= 0, C =< 255 -> <<C>>.
escape_like_arg_circumflex(S) when is_binary(S) ->
<< <<(escape_like_arg_circumflex(C))/binary>> || <<C>> <= S >>;
escape_like_arg_circumflex($%) -> <<"^%">>;
escape_like_arg_circumflex($_) -> <<"^_">>;
escape_like_arg_circumflex($^) -> <<"^^">>;
escape_like_arg_circumflex(C) when is_integer(C), C >= 0, C =< 255 -> <<C>>.
to_bool(<<"t">>) -> true;
to_bool(<<"true">>) -> true;
to_bool(<<"1">>) -> true;
@ -508,7 +517,7 @@ sql_query_internal(#sql_query{} = Query) ->
odbc ->
generic_sql_query(Query);
mssql ->
generic_sql_query(Query);
mssql_sql_query(Query);
pgsql ->
Key = {?PREPARE_KEY, Query#sql_query.hash},
case get(Key) of
@ -534,7 +543,7 @@ sql_query_internal(#sql_query{} = Query) ->
mysql ->
generic_sql_query(Query);
sqlite ->
generic_sql_query(Query)
sqlite_sql_query(Query)
end
catch
Class:Reason ->
@ -623,6 +632,32 @@ generic_escape() ->
end
}.
sqlite_sql_query(SQLQuery) ->
sql_query_format_res(
sql_query_internal(sqlite_sql_query_format(SQLQuery)),
SQLQuery).
sqlite_sql_query_format(SQLQuery) ->
Args = (SQLQuery#sql_query.args)(sqlite_escape()),
(SQLQuery#sql_query.format_query)(Args).
sqlite_escape() ->
#sql_escape{string = fun(X) -> <<"'", (standard_escape(X))/binary, "'">> end,
integer = fun(X) -> integer_to_binary(X) end,
boolean = fun(true) -> <<"1">>;
(false) -> <<"0">>
end
}.
standard_escape(S) ->
<< <<(case Char of
$' -> << "''" >>;
_ -> << Char >>
end)/binary>> || <<Char>> <= S >>.
mssql_sql_query(SQLQuery) ->
sqlite_sql_query(SQLQuery).
pgsql_prepare(SQLQuery, State) ->
Escape = #sql_escape{_ = fun(X) -> X end},
N = length((SQLQuery#sql_query.args)(Escape)),

View File

@ -227,9 +227,11 @@ make_val(Match, Field, Val) ->
Condition = case str:suffix(<<"*">>, Val) of
true ->
Val1 = str:substr(Val, 1, byte_size(Val) - 1),
SVal = <<(ejabberd_sql:escape_like(Val1))/binary,
SVal = <<(ejabberd_sql:escape(
ejabberd_sql:escape_like_arg_circumflex(
Val1)))/binary,
"%">>,
[Field, <<" LIKE '">>, SVal, <<"'">>];
[Field, <<" LIKE '">>, SVal, <<"' ESCAPE '^'">>];
_ ->
SVal = ejabberd_sql:escape(Val),
[Field, <<" = '">>, SVal, <<"'">>]

View File

@ -51,9 +51,11 @@
get_entity_subscriptions_for_send_last/2, get_last_items/3]).
-export([decode_jid/1, encode_jid/1,
encode_jid_like/1,
decode_affiliation/1, decode_subscriptions/1,
encode_affiliation/1, encode_subscriptions/1,
encode_host/1]).
encode_host/1,
encode_host_like/1]).
init(_Host, _ServerHost, _Opts) ->
%%pubsub_subscription_sql:init(),
@ -350,11 +352,13 @@ get_entity_subscriptions(Host, Owner) ->
H = encode_host(Host),
SJ = encode_jid(SubKey),
GJ = encode_jid(GenKey),
GJLike = encode_jid_like(GenKey),
Query = case SubKey of
GenKey ->
[<<"select node, type, i.nodeid, jid, subscriptions "
"from pubsub_state i, pubsub_node n "
"where i.nodeid = n.nodeid and jid like '">>, GJ, <<"%' and host='">>, H, <<"';">>];
"where i.nodeid = n.nodeid and jid like '">>, GJLike,
<<"%' escape '^' and host='">>, H, <<"';">>];
_ ->
[<<"select node, type, i.nodeid, jid, subscriptions "
"from pubsub_state i, pubsub_node n "
@ -399,12 +403,14 @@ get_entity_subscriptions_for_send_last(Host, Owner) ->
H = encode_host(Host),
SJ = encode_jid(SubKey),
GJ = encode_jid(GenKey),
GJLike = encode_jid_like(GenKey),
Query = case SubKey of
GenKey ->
[<<"select node, type, i.nodeid, jid, subscriptions "
"from pubsub_state i, pubsub_node n, pubsub_node_option o "
"where i.nodeid = n.nodeid and n.nodeid = o.nodeid and name='send_last_published_item' "
"and val='on_sub_and_presence' and jid like '">>, GJ, <<"%' and host='">>, H, <<"';">>];
"and val='on_sub_and_presence' and jid like '">>, GJLike,
<<"%' escape '^' and host='">>, H, <<"';">>];
_ ->
[<<"select node, type, i.nodeid, jid, subscriptions "
"from pubsub_state i, pubsub_node n, pubsub_node_option o "
@ -568,8 +574,9 @@ get_states(Nidx) ->
[<<"jid">>, <<"affiliation">>, <<"subscriptions">>], RItems} ->
{result,
lists:map(fun ([SJID, Aff, Subs]) ->
#pubsub_state{stateid = {decode_jid(SJID), Nidx},
items = itemids(Nidx, SJID),
JID = decode_jid(SJID),
#pubsub_state{stateid = {JID, Nidx},
items = itemids(Nidx, JID),
affiliation = decode_affiliation(Aff),
subscriptions = decode_subscriptions(Subs)}
end,
@ -899,13 +906,12 @@ first_in_list(Pred, [H | T]) ->
_ -> first_in_list(Pred, T)
end.
itemids(Nidx, {U, S, R}) ->
itemids(Nidx, encode_jid({U, S, R}));
itemids(Nidx, SJID) ->
itemids(Nidx, {_U, _S, _R} = JID) ->
SJID = encode_jid_like(JID),
case catch
ejabberd_sql:sql_query_t([<<"select itemid from pubsub_item where "
"nodeid='">>, Nidx, <<"' and publisher like '">>, SJID,
<<"%' order by modification desc;">>])
<<"%' escape '^' order by modification desc;">>])
of
{selected, [<<"itemid">>], RItems} ->
[ItemId || [ItemId] <- RItems];
@ -1011,6 +1017,10 @@ decode_subscriptions(Subscriptions) ->
encode_jid(JID) ->
ejabberd_sql:escape(jid:to_string(JID)).
-spec(encode_jid_like/1 :: (JID :: ljid()) -> binary()).
encode_jid_like(JID) ->
ejabberd_sql:escape(ejabberd_sql:escape_like_arg_circumflex(jid:to_string(JID))).
-spec(encode_host/1 ::
( Host :: host())
-> binary()
@ -1018,6 +1028,14 @@ encode_jid(JID) ->
encode_host({_U, _S, _R} = LJID) -> encode_jid(LJID);
encode_host(Host) -> ejabberd_sql:escape(Host).
-spec(encode_host_like/1 ::
( Host :: host())
-> binary()
).
encode_host_like({_U, _S, _R} = LJID) -> encode_jid_like(LJID);
encode_host_like(Host) ->
ejabberd_sql:escape(ejabberd_sql:escape_like_arg_circumflex(Host)).
-spec(encode_affiliation/1 ::
( Arg :: atom())
-> binary()

View File

@ -114,20 +114,21 @@ set_affiliation(Nidx, Owner, Affiliation) ->
get_entity_subscriptions(_Host, Owner) ->
SubKey = jid:tolower(Owner),
GenKey = jid:remove_resource(SubKey),
Host = node_flat_sql:encode_host(element(2, SubKey)),
HostLike = node_flat_sql:encode_host_like(element(2, SubKey)),
SJ = node_flat_sql:encode_jid(SubKey),
GJ = node_flat_sql:encode_jid(GenKey),
GJLike = node_flat_sql:encode_jid_like(GenKey),
Query = case SubKey of
GenKey ->
[<<"select host, node, type, i.nodeid, jid, "
"subscriptions from pubsub_state i, pubsub_node n "
"where i.nodeid = n.nodeid and jid "
"like '">>, GJ, <<"%' and host like '%@">>, Host, <<"';">>];
"like '">>, GJLike, <<"%' escape '^' and host like '%@">>, HostLike, <<"' escape '^';">>];
_ ->
[<<"select host, node, type, i.nodeid, jid, "
"subscriptions from pubsub_state i, pubsub_node n "
"where i.nodeid = n.nodeid and jid "
"in ('">>, SJ, <<"', '">>, GJ, <<"') and host like '%@">>, Host, <<"';">>]
"in ('">>, SJ, <<"', '">>, GJ, <<"') and host like '%@">>, HostLike, <<"' escape '^';">>]
end,
Reply = case catch ejabberd_sql:sql_query_t(Query) of
{selected,
@ -149,9 +150,10 @@ get_entity_subscriptions(_Host, Owner) ->
get_entity_subscriptions_for_send_last(_Host, Owner) ->
SubKey = jid:tolower(Owner),
GenKey = jid:remove_resource(SubKey),
Host = node_flat_sql:encode_host(element(2, SubKey)),
HostLike = node_flat_sql:encode_host_like(element(2, SubKey)),
SJ = node_flat_sql:encode_jid(SubKey),
GJ = node_flat_sql:encode_jid(GenKey),
GJLike = node_flat_sql:encode_jid_like(GenKey),
Query = case SubKey of
GenKey ->
[<<"select host, node, type, i.nodeid, jid, "
@ -159,14 +161,14 @@ get_entity_subscriptions_for_send_last(_Host, Owner) ->
"pubsub_node_option o where i.nodeid = n.nodeid "
"and n.nodeid = o.nodeid and name='send_last_published_item' and "
"val='on_sub_and_presence' and jid like '">>,
GJ, <<"%' and host like '%@">>, Host, <<"';">>];
GJLike, <<"%' escape '^' and host like '%@">>, HostLike, <<"' escape '^';">>];
_ ->
[<<"select host, node, type, i.nodeid, jid, "
"subscriptions from pubsub_state i, pubsub_node n, "
"pubsub_node_option o where i.nodeid = n.nodeid "
"and n.nodeid = o.nodeid and name='send_last_published_item' and "
"val='on_sub_and_presence' and jid in ",
"('">>, SJ, <<"', '">>, GJ, <<"') and host like '%@">>, Host, <<"';">>]
"('">>, SJ, <<"', '">>, GJ, <<"') and host like '%@">>, HostLike, <<"' escape '^';">>]
end,
Reply = case catch ejabberd_sql:sql_query_t(Query) of
{selected,

View File

@ -196,11 +196,11 @@ get_subnodes_tree(Host, Node, _From) ->
get_subnodes_tree(Host, Node) ->
H = node_flat_sql:encode_host(Host),
N = ejabberd_sql:escape(Node),
N = ejabberd_sql:escape(ejabberd_sql:escape_like_arg_circumflex(Node)),
case catch
ejabberd_sql:sql_query_t([<<"select node, parent, type, nodeid from "
"pubsub_node where host='">>,
H, <<"' and node like '">>, N, <<"%';">>])
H, <<"' and node like '">>, N, <<"%' escape '^';">>])
of
{selected,
[<<"node">>, <<"parent">>, <<"type">>, <<"nodeid">>], RItems} ->
@ -256,10 +256,10 @@ create_node(Host, Node, Type, Owner, Options, Parents) ->
delete_node(Host, Node) ->
H = node_flat_sql:encode_host(Host),
N = ejabberd_sql:escape(Node),
N = ejabberd_sql:escape(ejabberd_sql:escape_like_arg_circumflex(Node)),
Removed = get_subnodes_tree(Host, Node),
catch ejabberd_sql:sql_query_t([<<"delete from pubsub_node where host='">>,
H, <<"' and node like '">>, N, <<"%';">>]),
H, <<"' and node like '">>, N, <<"%' escape '^';">>]),
Removed.
%% helpers

View File

@ -231,12 +231,12 @@ list_users(LServer,
[{prefix, Prefix}, {limit, Limit}, {offset, Offset}])
when is_binary(Prefix) and is_integer(Limit) and
is_integer(Offset) ->
SPrefix = ejabberd_sql:escape_like_arg(Prefix),
SPrefix = ejabberd_sql:escape_like_arg_circumflex(Prefix),
SPrefix2 = <<SPrefix/binary, $%>>,
ejabberd_sql:sql_query(
LServer,
?SQL("select @(username)s from users "
"where username like %(SPrefix2)s "
"where username like %(SPrefix2)s escape '^' "
"order by username "
"limit %(Limit)d offset %(Offset)d")).
@ -264,12 +264,12 @@ users_number(LServer) ->
users_number(LServer, [{prefix, Prefix}])
when is_binary(Prefix) ->
SPrefix = ejabberd_sql:escape_like_arg(Prefix),
SPrefix = ejabberd_sql:escape_like_arg_circumflex(Prefix),
SPrefix2 = <<SPrefix/binary, $%>>,
ejabberd_sql:sql_query(
LServer,
?SQL("select @(count(*))d from users "
"where username like %(SPrefix2)s"));
"where username like %(SPrefix2)s escape '^'"));
users_number(LServer, []) ->
users_number(LServer).

View File

@ -66,7 +66,7 @@ init_config(Config) ->
{resource, <<"resource">>},
{master_resource, <<"master_resource">>},
{slave_resource, <<"slave_resource">>},
{password, <<"password">>},
{password, <<"password!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>}
{backends, get_config_backends()}
|Config].