./ct_report/coverage/eldap_filter.COVER.html

1 %%%----------------------------------------------------------------------
2 %%% File: eldap_filter.erl
3 %%% Purpose: Converts String Representation of
4 %%% LDAP Search Filter (RFC 2254)
5 %%% to eldap's representation of filter
6 %%% Author: Evgeniy Khramtsov <ekhramtsov@process-one.net>
7 %%%
8 %%%
9 %%% ejabberd, Copyright (C) 2002-2013 ProcessOne
10 %%%
11 %%% This program is free software; you can redistribute it and/or
12 %%% modify it under the terms of the GNU General Public License as
13 %%% published by the Free Software Foundation; either version 2 of the
14 %%% License, or (at your option) any later version.
15 %%%
16 %%% This program is distributed in the hope that it will be useful,
17 %%% but WITHOUT ANY WARRANTY; without even the implied warranty of
18 %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 %%% General Public License for more details.
20 %%%
21 %%% You should have received a copy of the GNU General Public License
22 %%% along with this program; if not, write to the Free Software
23 %%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 %%%
25 %%%----------------------------------------------------------------------
26 -module(eldap_filter).
27
28 %% TODO: remove this when new regexp module will be used
29 -export([parse/1, parse/2, do_sub/2]).
30
31 %%====================================================================
32 %% API
33 %%====================================================================
34 %%%-------------------------------------------------------------------
35 %%% Arity: parse/1
36 %%% Function: parse(RFC2254_Filter) -> {ok, EldapFilter} |
37 %%% {error, bad_filter}
38 %%%
39 %%% RFC2254_Filter = string().
40 %%%
41 %%% Description: Converts String Representation of LDAP Search Filter (RFC 2254)
42 %%% to eldap's representation of filter.
43 %%%
44 %%% Example:
45 %%% > eldap_filter:parse("(&(!(uid<=100))(mail=*))").
46 %%%
47 %%% {ok, {'and', [{'not', {lessOrEqual, {'AttributeValueAssertion', "uid", "100"}}},
48 %%% {present, "mail"}]}}
49 %%%-------------------------------------------------------------------
50 -spec parse(binary()) -> {error, any()} | {ok, eldap_utils:filter()}.
51 parse(L) ->
52 3268 parse(L, []).
53
54 %%%-------------------------------------------------------------------
55 %%% Arity: parse/2
56 %%% Function: parse(RFC2254_Filter, [SubstValue |...]) ->
57 %%% {ok, EldapFilter} |
58 %%% {error, bad_filter} |
59 %%% {error, bad_regexp} |
60 %%% {error, max_substitute_recursion}
61 %%%
62 %%% SubstValue = {RegExp, Value} | {RegExp, Value, N},
63 %%% RFC2254_Filter = RegExp = Value = string(),
64 %%% N = integer().
65 %%%
66 %%% Description: The same as parse/1, but substitutes N or all occurences
67 %%% of RegExp with Value *after* parsing.
68 %%%
69 %%% Example:
70 %%% > eldap_filter:parse(
71 %%% "(|(mail=%u@%d)(jid=%u@%d))",
72 %%% [{"%u", "xramtsov"}, {"%d", "gmail.com"}]).
73 %%%
74 %%% {ok, {'or', [{equalityMatch, {'AttributeValueAssertion',
75 %%% "mail",
76 %%% "xramtsov@gmail.com"}},
77 %%% {equalityMatch, {'AttributeValueAssertion',
78 %%% "jid",
79 %%% "xramtsov@gmail.com"}}]}}
80 %%%-------------------------------------------------------------------
81 -spec parse(binary(), [{binary(), binary()} |
82 {binary(), binary(), pos_integer()}]) ->
83 {error, any()} | {ok, eldap_utils:filter()}.
84
85 parse(L, SList) ->
86 16897 case catch eldap_filter_yecc:parse(scan(binary_to_list(L), SList)) of
87 {'EXIT', _} = Err ->
88
:-(
{error, Err};
89 {error, {_, _, Msg}} ->
90
:-(
{error, Msg};
91 {ok, Result} ->
92 16897 {ok, Result};
93 {regexp, Err} ->
94
:-(
{error, Err}
95 end.
96
97 %%====================================================================
98 %% Internal functions
99 %%====================================================================
100 -define(do_scan(L), scan(Rest, <<>>, [{L, 1} | check(Buf, S) ++ Result], L, S)).
101
102
103 -spec scan([byte()], _) -> [{atom(), 1} | {'str', 1, [any()]}].
104 scan(L, SList) ->
105 16897 scan(L, <<"">>, [], undefined, SList).
106
107
108 -spec scan([byte()], Buf :: binary(), Result :: [{atom(), 1} | {'str', 1, [any()]}],
109 atom(), S :: any()) -> [{atom(), 1} | {'str', 1, [any()]}].
110 scan("=*)" ++ Rest, Buf, Result, '(', S) ->
111 3258 scan(Rest, <<>>, [{')', 1}, {'=*', 1} | check(Buf, S) ++ Result], ')', S);
112
:-(
scan(":dn" ++ Rest, Buf, Result, '(', S) -> ?do_scan(':dn');
113
:-(
scan(":=" ++ Rest, Buf, Result, '(', S) -> ?do_scan(':=');
114
:-(
scan(":=" ++ Rest, Buf, Result, ':dn', S) -> ?do_scan(':=');
115
:-(
scan(":=" ++ Rest, Buf, Result, ':', S) -> ?do_scan(':=');
116
:-(
scan("~=" ++ Rest, Buf, Result, '(', S) -> ?do_scan('~=');
117
:-(
scan(">=" ++ Rest, Buf, Result, '(', S) -> ?do_scan('>=');
118
:-(
scan("<=" ++ Rest, Buf, Result, '(', S) -> ?do_scan('<=');
119 30531 scan("=" ++ Rest, Buf, Result, '(', S) -> ?do_scan('=');
120
:-(
scan(":" ++ Rest, Buf, Result, '(', S) -> ?do_scan(':');
121
:-(
scan(":" ++ Rest, Buf, Result, ':dn', S) -> ?do_scan(':');
122 16892 scan("&" ++ Rest, Buf, Result, '(', S) when Buf==<<"">> -> ?do_scan('&');
123
:-(
scan("|" ++ Rest, Buf, Result, '(', S) when Buf==<<"">> -> ?do_scan('|');
124
:-(
scan("!" ++ Rest, Buf, Result, '(', S) when Buf==<<"">> -> ?do_scan('!');
125
:-(
scan("*" ++ Rest, Buf, Result, '*', S) -> ?do_scan('*');
126
:-(
scan("*" ++ Rest, Buf, Result, '=', S) -> ?do_scan('*');
127 50681 scan("(" ++ Rest, Buf, Result, _, S) -> ?do_scan('(');
128 47423 scan(")" ++ Rest, Buf, Result, _, S) -> ?do_scan(')');
129 scan([Letter | Rest], Buf, Result, PreviosAtom, S) ->
130 483494 scan(Rest, <<Buf/binary, Letter>>, Result, PreviosAtom, S);
131 scan([], Buf, Result, _, S) ->
132 16897 lists:reverse(check(Buf, S) ++ Result).
133
134
135 -spec check(binary(), _) -> [{'str', 1, [byte()]}].
136 check(<<>>, _) ->
137 101362 [];
138 check(Buf, S) ->
139 64320 [{str, 1, binary_to_list(do_sub(Buf, S))}].
140
141
142 -define(MAX_RECURSION, 100).
143
144
145 -spec do_sub(binary(), [{binary(), binary()} |
146 {binary(), binary(), pos_integer()}]) -> binary().
147 do_sub(S, []) ->
148 66023 S;
149 do_sub(<<>>, _) ->
150
:-(
<<>>;
151 do_sub(S, [{RegExp, New} | T]) ->
152 57345 Result = do_sub(S, {RegExp, replace_amps(New)}, 1),
153 57345 do_sub(Result, T);
154 do_sub(S, [{RegExp, New, Times} | T]) ->
155 1122 Result = do_sub(S, {RegExp, replace_amps(New), Times}, 1),
156 1122 do_sub(Result, T).
157
158
159 do_sub(S, {RegExp, New}, _Iter) ->
160 57345 re:replace(S, RegExp, New, [global, {return, binary}]);
161 do_sub(S, {_, _, N}, _) when N<1 ->
162
:-(
S;
163 do_sub(S, {RegExp, New, _Times}, _Iter) ->
164 1122 re:replace(S, RegExp, New, [global, {return, binary}]).
165
166
167 -spec replace_amps(binary()) -> binary().
168 replace_amps(Bin) ->
169 58467 list_to_binary(
170 lists:flatmap(
171
:-(
fun($&) -> "\\&";
172
:-(
($\\) -> "\\\\";
173 2040474 (Chr) -> [Chr]
174 end, eldap_utils:maybe_b2list(Bin))).
Line Hits Source