./ct_report/coverage/eldap_utils.COVER.html

1 %%%----------------------------------------------------------------------
2 %%% File : eldap_utils.erl
3 %%% Author : Mickael Remond <mremond@process-one.net>
4 %%% Purpose : ejabberd LDAP helper functions
5 %%% Created : 12 Oct 2006 by Mickael Remond <mremond@process-one.net>
6 %%%
7 %%%
8 %%% ejabberd, Copyright (C) 2002-2013 ProcessOne
9 %%%
10 %%% This program is free software; you can redistribute it and/or
11 %%% modify it under the terms of the GNU General Public License as
12 %%% published by the Free Software Foundation; either version 2 of the
13 %%% License, or (at your option) any later version.
14 %%%
15 %%% This program is distributed in the hope that it will be useful,
16 %%% but WITHOUT ANY WARRANTY; without even the implied warranty of
17 %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 %%% General Public License for more details.
19 %%%
20 %%% You should have received a copy of the GNU General Public License
21 %%% along with this program; if not, write to the Free Software
22 %%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 %%%
24 %%%----------------------------------------------------------------------
25
26 -module(eldap_utils).
27 -author('mremond@process-one.net').
28
29 -export([generate_subfilter/1,
30 find_ldap_attrs/2,
31 get_ldap_attr/2,
32 get_user_part/2,
33 make_filter/2,
34 make_filter/3,
35 get_state/2,
36 case_insensitive_match/2,
37 deref_aliases/1,
38 process_user_filter/2,
39 get_search_filter/1,
40 decode_octet_string/3,
41 uids_domain_subst/2,
42 singleton_value/1,
43 maybe_list2b/1,
44 maybe_b2list/1]).
45
46 -ignore_xref([decode_octet_string/3, generate_subfilter/1, make_filter/2, uids_domain_subst/2]).
47
48 %% Used to be eldap:filter()
49 -type filter() :: term().
50
51 %% Used to be eldap:eldap_entry()
52 -type eldap_entry() :: term().
53
54 %% Used to be eldap:handle()
55 -type handle() :: term().
56
57 -export_type([handle/0,
58 filter/0,
59 eldap_entry/0]).
60
61 -type dn() :: binary().
62 -type deref() :: neverDerefAliases | derefInSearching
63 | derefFindingBaseObj | derefAlways.
64 %% Used to access mongoose_wpool
65 -type eldap_id() :: {HostType :: mongooseim:host_type(), Tag :: mongoose_wpool:tag()}.
66
67 -export_type([dn/0,
68 deref/0,
69 eldap_id/0]).
70
71 %% @doc Generate an 'or' LDAP query on one or several attributes
72 %% If there is only one attribute
73 -spec generate_subfilter([{binary()} | {binary(), binary()}]) -> binary().
74 generate_subfilter([UID]) ->
75 262 subfilter(UID);
76 %% If there is several attributes
77 generate_subfilter(UIDs) ->
78
:-(
iolist_to_binary(["(|", [subfilter(UID) || UID <- UIDs], ")"]).
79
80
81 %% @doc Subfilter for a single attribute
82 -spec subfilter({binary()} | {binary(), binary()}) -> binary().
83 subfilter({UIDAttr, UIDAttrFormat}) ->
84 %% The default UiDAttrFormat is %u
85 262 <<$(, UIDAttr/binary, $=, UIDAttrFormat/binary, $)>>;
86 subfilter({UIDAttr}) ->
87 %% The default UiDAttrFormat is <<"%u">>
88
:-(
<<$(, UIDAttr/binary, $=, "%u)">>.
89
90
91 %% @doc Not tail-recursive, but it is not very terribly.
92 %% It stops finding on the first not empty value.
93 -spec find_ldap_attrs([{binary()} | {binary(), binary()}],
94 [{binary(), [binary()]}]) -> <<>> | {binary(), binary()}.
95 find_ldap_attrs([{Attr} | Rest], Attributes) ->
96
:-(
find_ldap_attrs([{Attr, <<"%u">>} | Rest], Attributes);
97 find_ldap_attrs([{Attr, Format} | Rest], Attributes) ->
98 170711 case get_ldap_attr(Attr, Attributes) of
99 Value when Value /= <<>>, Value /= [] ->
100 170711 {Value, Format};
101 _ ->
102
:-(
find_ldap_attrs(Rest, Attributes)
103 end;
104 find_ldap_attrs([], _) ->
105
:-(
<<>>.
106
107
108 -spec get_ldap_attr(binary(), [{binary(), [binary()]}]) -> binary().
109 get_ldap_attr(LDAPAttr, Attributes) ->
110 171828 Res = lists:filter(
111 fun({Name, _}) ->
112 174342 case_insensitive_match(Name, LDAPAttr)
113 end, Attributes),
114 171828 case singleton_value(Res) of
115 170889 {_, Value} -> eldap_utils:maybe_list2b(Value);
116 939 _ -> <<>>
117 end.
118
119
120 -spec get_user_part(binary(), binary()) -> {ok, binary()} | {error, badmatch}.
121 get_user_part(String, Pattern) ->
122 170716 F = fun(S, P) ->
123 170716 {First, _} = binary:match(P, <<"%u">>),
124 170716 TailLength = byte_size(P) - (First+1),
125 170716 binary:part(S, First, byte_size(S)-TailLength-First+1)
126 end,
127 170716 case catch F(String, Pattern) of
128 {'EXIT', _} ->
129
:-(
{error, badmatch};
130 Result ->
131 170716 case catch re:replace(Pattern, <<"%u">>, Result, [global, {return, binary}]) of
132 {'EXIT', _} ->
133
:-(
{error, badmatch};
134 StringRes ->
135 170716 case case_insensitive_match(StringRes, String) of
136 true ->
137 170716 {ok, Result};
138 false ->
139
:-(
{error, badmatch}
140 end
141 end
142 end.
143
144
145 -spec generate_substring_list(binary())
146 -> [{'any', binary()} | {'final', binary()} | {'initial', binary()}].
147 generate_substring_list(Value)->
148 11 Splits = binary:split(Value, <<"*">>, [global]),
149 11 {Acc, S}=case Splits of
150 1 [<<"">>|T]->{[], maybe_b2list(T)};
151 10 [H|T]-> {[{initial, maybe_b2list(H)}], T}
152 end,
153 11 lists:reverse(generate_substring_list(S, Acc)).
154 generate_substring_list([<<"">>], Acc)->
155 10 Acc;
156 generate_substring_list([Last], Acc)->
157 1 [{final, Last}|Acc];
158 generate_substring_list([H|T], Acc)->
159 1 generate_substring_list(T, [{any, H}|Acc]).
160
161
162 -spec make_filter([{binary(), [binary()]}], [{binary(), binary()}]) -> any().
163 make_filter(Data, UIDs) ->
164
:-(
make_filter(Data, UIDs, 'and').
165
166 -spec make_filter([{binary(), [binary()]}], [{binary(), binary()}],
167 'or' | 'and') -> any().
168 make_filter(Data, UIDs, Op) ->
169 19 NewUIDs = [{U, eldap_filter:do_sub(
170 19 UF, [{<<"%u">>, <<"*%u*">>, 1}])} || {U, UF} <- UIDs],
171 19 Filter = lists:flatmap(
172 traverse_filter_fun(NewUIDs), Data),
173 19 case Filter of
174 [F] ->
175 17 F;
176 _ ->
177 2 eldap:Op(Filter)
178 end.
179
180 traverse_filter_fun(NewUIDs) ->
181 19 fun(Entry) ->
182 21 match_filter_name(Entry, NewUIDs)
183 end.
184
185 match_filter_name({<<"%u">>, [Value | _]}, NewUIDs) when Value /= <<"">> ->
186
:-(
case eldap_filter:parse(
187 generate_subfilter(NewUIDs),
188 [{<<"%u">>, Value}]) of
189
:-(
{ok, F} -> [F];
190
:-(
_ -> []
191 end;
192 match_filter_name({Name, [Value | _]}, _NewUIDs) when Value /= <<"">> ->
193 21 case binary:match(Value, <<"*">>) of
194 10 nomatch -> [eldap:equalityMatch(Name, Value)];
195 11 _ -> [eldap:substrings(maybe_b2list(Name),
196 generate_substring_list(Value))]
197 end;
198 match_filter_name(_, _) ->
199
:-(
[].
200
201 -spec case_insensitive_match(binary(), binary()) -> boolean().
202 case_insensitive_match(X, Y) ->
203 370103 X1 = string:to_lower(maybe_b2list(X)),
204 370103 Y1 = string:to_lower(maybe_b2list(Y)),
205 370103 case X1 == Y1 of
206 342750 true -> true;
207 27353 _-> false
208 end.
209
210
211 -spec get_state(mongooseim:host_type(), atom()) -> any().
212 get_state(HostType, Module) ->
213 19684 Proc = gen_mod:get_module_proc(HostType, Module),
214 19684 gen_server:call(Proc, get_state).
215
216
217 %% @doc From the list of uids attribute: we look from alias domain (%d) and make
218 %% the substitution with the actual host domain. This helps when you need to
219 %% configure many virtual domains.
220 -spec uids_domain_subst(binary(), [{binary(), binary()}]) ->
221 [{binary(), binary()}].
222 uids_domain_subst(Host, UIDs) ->
223 262 lists:map(fun({U, V}) ->
224 262 {U, eldap_filter:do_sub(V, [{<<"%d">>, Host}])};
225
:-(
(A) -> A
226 end,
227 UIDs).
228
229 263 deref_aliases(never) -> neverDerefAliases;
230
:-(
deref_aliases(searching) -> derefInSearching;
231
:-(
deref_aliases(finding) -> derefFindingBaseObj;
232
:-(
deref_aliases(always) -> derefAlways.
233
234 process_user_filter(UIDs, RawUserFilter) ->
235 262 SubFilter = generate_subfilter(UIDs),
236 262 case RawUserFilter of
237 <<>> ->
238
:-(
SubFilter;
239 F ->
240 262 <<"(&", SubFilter/binary, F/binary, ")">>
241 end.
242
243 get_search_filter(UserFilter) ->
244 262 eldap_filter:do_sub(UserFilter, [{<<"%u">>, <<"*">>}]).
245
246 -spec singleton_value(list()) -> {binary(), binary()} | false.
247 singleton_value([{K, [V]}]) ->
248 170903 {K, V};
249 singleton_value([{_K, _V} = I]) ->
250
:-(
I;
251 singleton_value(_) ->
252 939 false.
253 %%----------------------------------------
254 %% Borrowed from asn1rt_ber_bin_v2.erl
255 %%----------------------------------------
256
257 %%% The tag-number for universal types
258 -define(N_BOOLEAN, 1).
259 -define(N_INTEGER, 2).
260 -define(N_BIT_STRING, 3).
261 -define(N_OCTET_STRING, 4).
262 -define(N_NULL, 5).
263 -define(N_OBJECT_IDENTIFIER, 6).
264 -define(N_OBJECT_DESCRIPTOR, 7).
265 -define(N_EXTERNAL, 8).
266 -define(N_REAL, 9).
267 -define(N_ENUMERATED, 10).
268 -define(N_EMBEDDED_PDV, 11).
269 -define(N_SEQUENCE, 16).
270 -define(N_SET, 17).
271 -define(N_NumericString, 18).
272 -define(N_PrintableString, 19).
273 -define(N_TeletexString, 20).
274 -define(N_VideotexString, 21).
275 -define(N_IA5String, 22).
276 -define(N_UTCTime, 23).
277 -define(N_GeneralizedTime, 24).
278 -define(N_GraphicString, 25).
279 -define(N_VisibleString, 26).
280 -define(N_GeneralString, 27).
281 -define(N_UniversalString, 28).
282 -define(N_BMPString, 30).
283
284
285 -spec decode_octet_string(_, _, list()) -> binary().
286 decode_octet_string(Buffer, Range, Tags) ->
287 % NewTags = new_tags(HasTag, #tag{class=?UNIVERSAL, number=?N_OCTET_STRING}),
288
:-(
decode_restricted_string(Buffer, Range, Tags).
289
290
291 -spec decode_restricted_string(_, _, list()) -> binary().
292 decode_restricted_string(Tlv, Range, TagsIn) ->
293
:-(
Val = match_tags(Tlv, TagsIn),
294
:-(
Val2 =
295 case Val of
296 PartList = [_H|_T] -> % constructed val
297
:-(
collect_parts(PartList);
298 Bin ->
299
:-(
Bin
300 end,
301
:-(
check_and_convert_restricted_string(Val2, Range).
302
303
304 -spec check_and_convert_restricted_string(iolist(), _) -> binary().
305 check_and_convert_restricted_string(Val, Range) ->
306
:-(
{StrLen, NewVal} = if is_binary(Val) ->
307
:-(
{size(Val), Val};
308 true ->
309
:-(
{length(Val), list_to_binary(Val)}
310 end,
311
:-(
case Range of
312 [] -> % No length constraint
313
:-(
NewVal;
314 {Lb, Ub} when StrLen >= Lb, Ub >= StrLen -> % variable length constraint
315
:-(
NewVal;
316 {{Lb, _Ub}, []} when StrLen >= Lb ->
317
:-(
NewVal;
318 {{Lb, _Ub}, _Ext=[Min|_]} when StrLen >= Lb; StrLen >= Min ->
319
:-(
NewVal;
320 {{Lb1, Ub1}, {Lb2, Ub2}} when StrLen >= Lb1, StrLen =< Ub1;
321 StrLen =< Ub2, StrLen >= Lb2 ->
322
:-(
NewVal;
323 StrLen -> % fixed length constraint
324
:-(
NewVal;
325 {_, _} ->
326
:-(
exit({error, {asn1, {length, Range, Val}}});
327 _Len when is_integer(_Len) ->
328
:-(
exit({error, {asn1, {length, Range, Val}}});
329 _ -> % some strange constraint that we don't support yet
330
:-(
NewVal
331 end.
332
333 %%----------------------------------------
334 %% Decode the in buffer to bits
335 %%----------------------------------------
336 match_tags({T, V}, [T]) ->
337
:-(
V;
338 match_tags({T, V}, [T|Tt]) ->
339
:-(
match_tags(V, Tt);
340 match_tags([{T, V}], [T|Tt]) ->
341
:-(
match_tags(V, Tt);
342 match_tags(Vlist = [{T, _V}|_], [T]) ->
343
:-(
Vlist;
344 match_tags(Tlv, []) ->
345
:-(
Tlv;
346 match_tags({Tag, _V}, [T|_Tt]) ->
347
:-(
{error, {asn1, {wrong_tag, {Tag, T}}}}.
348
349
350 -spec collect_parts([{_, _}]) -> binary().
351 collect_parts(TlvList) ->
352
:-(
collect_parts(TlvList, []).
353
354
355 -spec collect_parts([{_, _}], [any()]) -> binary().
356 collect_parts([{_, L}|Rest], Acc) when is_list(L) ->
357
:-(
collect_parts(Rest, [collect_parts(L)|Acc]);
358 collect_parts([{?N_BIT_STRING, <<Unused, Bits/binary>>}|Rest], _Acc) ->
359
:-(
collect_parts_bit(Rest, [Bits], Unused);
360 collect_parts([{_T, V}|Rest], Acc) ->
361
:-(
collect_parts(Rest, [V|Acc]);
362 collect_parts([], Acc) ->
363
:-(
list_to_binary(lists:reverse(Acc)).
364
365
366 -spec collect_parts_bit([{3, binary()}], [binary(), ...], non_neg_integer()) -> binary().
367 collect_parts_bit([{?N_BIT_STRING, <<Unused, Bits/binary>>}|Rest], Acc, Uacc) ->
368
:-(
collect_parts_bit(Rest, [Bits|Acc], Unused+Uacc);
369 collect_parts_bit([], Acc, Uacc) ->
370
:-(
maybe_list2b([Uacc|lists:reverse(Acc)]).
371
372 maybe_b2list(B) when is_binary(B) ->
373 877092 binary_to_list(B);
374 maybe_b2list(L) when is_list(L) ->
375 48027 L;
376 maybe_b2list(O) ->
377
:-(
{error, {unknown_type, O}}.
378
379 maybe_list2b(L) when is_list(L) ->
380
:-(
list_to_binary(L);
381 maybe_list2b(B) when is_binary(B) ->
382 170908 B;
383 maybe_list2b(O) ->
384
:-(
{error, {unknown_type, O}}.
Line Hits Source