./ct_report/coverage/ejabberd_auth_rdbms.COVER.html

1 %%%----------------------------------------------------------------------
2 %%% File : ejabberd_auth_rdbms.erl
3 %%% Author : Alexey Shchepin <alexey@process-one.net>
4 %%% Purpose : Authentification via RDBMS
5 %%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@process-one.net>
6 %%%
7 %%%
8 %%% ejabberd, Copyright (C) 2002-2011 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(ejabberd_auth_rdbms).
27 -author('alexey@process-one.net').
28
29 %% External exports
30 -behaviour(mongoose_gen_auth).
31
32 -export([start/1,
33 stop/1,
34 config_spec/0,
35 authorize/1,
36 set_password/4,
37 try_register/4,
38 get_registered_users/3,
39 get_registered_users_number/3,
40 get_password/3,
41 get_password_s/3,
42 does_user_exist/3,
43 remove_user/3,
44 remove_domain/2,
45 supports_sasl_module/2,
46 supported_features/0
47 ]).
48
49 %% Internal
50 -export([check_password/4,
51 check_password/6]).
52
53 -export([scram_passwords/2, scram_passwords/4]).
54
55 -ignore_xref([scram_passwords/2, scram_passwords/4]).
56
57 -import(mongoose_rdbms, [prepare/4, execute_successfully/3]).
58
59 -include("mongoose.hrl").
60 -include("mongoose_config_spec.hrl").
61
62 -define(DEFAULT_SCRAMMIFY_COUNT, 10000).
63 -define(DEFAULT_SCRAMMIFY_INTERVAL, 1000).
64
65
66 %%%----------------------------------------------------------------------
67 %%% Types
68 %%%----------------------------------------------------------------------
69
70 -type prepared_password() ::
71 #{password := binary(),
72 details => binary()}.
73
74 %%%----------------------------------------------------------------------
75 %%% API
76 %%%----------------------------------------------------------------------
77
78 -spec start(moongooseim:host_type()) -> ok.
79 start(HostType) ->
80
:-(
prepare_queries(HostType),
81
:-(
ok.
82
83 -spec stop(moongooseim:host_type()) -> ok.
84 stop(_HostType) ->
85
:-(
ok.
86
87 -spec config_spec() -> mongoose_config_spec:config_section().
88 config_spec() ->
89 164 #section{
90 items = #{<<"users_number_estimate">> => #option{type = boolean}},
91 defaults = #{<<"users_number_estimate">> => false},
92 format_items = map
93 }.
94
95 -spec supports_sasl_module(mongooseim:host_type(), cyrsasl:sasl_module()) -> boolean().
96
:-(
supports_sasl_module(_HostType, cyrsasl_plain) -> true;
97
:-(
supports_sasl_module(HostType, cyrsasl_digest) -> not mongoose_scram:enabled(HostType);
98
:-(
supports_sasl_module(HostType, Mechanism) -> mongoose_scram:enabled(HostType, Mechanism).
99
100 -spec authorize(mongoose_credentials:t()) -> {ok, mongoose_credentials:t()}
101 | {error, any()}.
102 authorize(Creds) ->
103
:-(
ejabberd_auth:authorize_with_check_password(?MODULE, Creds).
104
105 -spec check_password(HostType :: mongooseim:host_type(),
106 LUser :: jid:luser(),
107 LServer :: jid:lserver(),
108 Password :: binary()) -> boolean().
109 check_password(HostType, LUser, LServer, Password) ->
110
:-(
try execute_get_password(HostType, LServer, LUser) of
111 {selected, [{Password, null}]} ->
112
:-(
Password /= <<"">>; %% Password is correct, and not empty
113 {selected, [{_Password2, null}]} ->
114
:-(
false;
115 {selected, [{_Password2, PassDetails}]} ->
116
:-(
case mongoose_scram:deserialize(PassDetails) of
117 {ok, Scram} ->
118
:-(
mongoose_scram:check_password(Password, Scram);
119 {error, Reason} ->
120
:-(
?LOG_WARNING(#{what => scram_serialisation_incorrect, reason => Reason,
121
:-(
user => LUser, server => LServer}),
122
:-(
false %% Password is not correct
123 end;
124 {selected, []} ->
125
:-(
false %% Account does not exist
126 catch
127 error:Reason:StackTrace ->
128
:-(
?LOG_ERROR(#{what => check_password_failed,
129 user => LUser, server => LServer,
130
:-(
class => error, reason => Reason, stacktrace => StackTrace}),
131
:-(
false %% Database error
132 end.
133
134 -spec check_password(HostType :: mongooseim:host_type(),
135 LUser :: jid:luser(),
136 LServer :: jid:lserver(),
137 Password :: binary(),
138 Digest :: binary(),
139 DigestGen :: fun()) -> boolean().
140
141 check_password(HostType, LUser, LServer, Password, Digest, DigestGen) ->
142
:-(
try execute_get_password(HostType, LServer, LUser) of
143 {selected, [{Passwd, null}]} ->
144
:-(
ejabberd_auth:check_digest(Digest, DigestGen, Password, Passwd);
145 {selected, [{_Passwd, PassDetails}]} ->
146
:-(
case mongoose_scram:deserialize(PassDetails) of
147 {ok, Scram} ->
148
:-(
mongoose_scram:check_digest(Scram, Digest, DigestGen, Password);
149 {error, Reason} ->
150
:-(
?LOG_WARNING(#{what => scram_serialisation_incorrect, reason => Reason,
151
:-(
user => LUser, server => LServer}),
152
:-(
false
153 end;
154 {selected, []} ->
155
:-(
false %% Account does not exist
156 catch
157 error:Reason:StackTrace ->
158
:-(
?LOG_ERROR(#{what => check_password_failed,
159 user => LUser, server => LServer,
160
:-(
class => error, reason => Reason, stacktrace => StackTrace}),
161
:-(
false %% Database error
162 end.
163
164 -spec set_password(HostType :: mongooseim:host_type(),
165 LUser :: jid:luser(),
166 LServer :: jid:lserver(),
167 Password :: binary()
168 ) -> ok | {error, not_allowed}.
169 set_password(HostType, LUser, LServer, Password) ->
170
:-(
PreparedPass = prepare_password(HostType, Password),
171
:-(
try
172
:-(
execute_set_password(HostType, LServer, LUser, PreparedPass),
173
:-(
ok
174 catch
175 error:Reason:StackTrace ->
176
:-(
?LOG_ERROR(#{what => set_password_failed,
177 user => LUser, server => LServer,
178
:-(
class => error, reason => Reason, stacktrace => StackTrace}),
179
:-(
{error, not_allowed}
180 end.
181
182 -spec try_register(HostType :: mongooseim:host_type(),
183 LUser :: jid:luser(),
184 LServer :: jid:lserver(),
185 Password :: binary()
186 ) -> ok | {error, exists}.
187 try_register(HostType, LUser, LServer, Password) ->
188
:-(
PreparedPass = prepare_password(HostType, Password),
189
:-(
try execute_add_user(HostType, LServer, LUser, PreparedPass) of
190 {updated, 1} ->
191
:-(
ok;
192 {updated, 0} ->
193
:-(
{error, exists}
194 catch
195 error:Reason:StackTrace ->
196
:-(
?LOG_ERROR(#{what => registration_failed,
197 user => LUser, server => LServer,
198
:-(
class => error, reason => Reason, stacktrace => StackTrace}),
199
:-(
{error, exists} %% XXX wrong error type - fix type in a separate PR
200 end.
201
202 -spec get_registered_users(mongooseim:host_type(), jid:lserver(), Opts :: list()) ->
203 [jid:simple_bare_jid()].
204 get_registered_users(HostType, LServer, Opts) ->
205
:-(
try
206
:-(
{selected, Res} = execute_list_users(HostType, LServer, maps:from_list(Opts)),
207
:-(
[{U, LServer} || {U} <- Res]
208 catch error:Reason:StackTrace ->
209
:-(
?LOG_ERROR(#{what => get_vh_registered_users_failed, server => LServer,
210
:-(
class => error, reason => Reason, stacktrace => StackTrace}),
211
:-(
[]
212 end.
213
214 -spec get_registered_users_number(mongooseim:host_type(), jid:lserver(), Opts :: list()) ->
215 non_neg_integer().
216 get_registered_users_number(HostType, LServer, Opts) ->
217
:-(
try
218
:-(
Selected = execute_count_users(HostType, LServer, maps:from_list(Opts)),
219
:-(
mongoose_rdbms:selected_to_integer(Selected)
220 catch error:Reason:StackTrace ->
221
:-(
?LOG_ERROR(#{what => get_vh_registered_users_numbers_failed, server => LServer,
222
:-(
class => error, reason => Reason, stacktrace => StackTrace}),
223
:-(
0
224 end.
225
226 -spec get_password(mongooseim:host_type(), jid:luser(), jid:lserver()) ->
227 ejabberd_auth:passterm() | false.
228 get_password(HostType, LUser, LServer) ->
229
:-(
try execute_get_password(HostType, LServer, LUser) of
230 {selected, [{Password, null}]} ->
231
:-(
Password; %% Plain password
232 {selected, [{_Password, PassDetails}]} ->
233
:-(
case mongoose_scram:deserialize(PassDetails) of
234 {ok, Scram} ->
235
:-(
Scram;
236 {error, Reason} ->
237
:-(
?LOG_WARNING(#{what => scram_serialisation_incorrect, reason => Reason,
238
:-(
user => LUser, server => LServer}),
239
:-(
false
240 end;
241 {selected, []} ->
242
:-(
false
243 catch
244 error:Reason:StackTrace ->
245
:-(
?LOG_ERROR(#{what => get_password_failed,
246 user => LUser, server => LServer,
247
:-(
class => error, reason => Reason, stacktrace => StackTrace}),
248
:-(
false
249 end.
250
251
252 -spec get_password_s(mongooseim:host_type(), jid:luser(), jid:lserver()) -> binary().
253 get_password_s(HostType, LUser, LServer) ->
254
:-(
try execute_get_password(HostType, LServer, LUser) of
255 {selected, [{Password, _}]} ->
256
:-(
Password;
257 {selected, []} ->
258
:-(
<<>>
259 catch
260 error:Reason:StackTrace ->
261
:-(
?LOG_ERROR(#{what => get_password_s_failed,
262 user => LUser, server => LServer,
263
:-(
class => error, reason => Reason, stacktrace => StackTrace}),
264
:-(
<<>>
265 end.
266
267
268 -spec does_user_exist(mongooseim:host_type(), jid:luser(), jid:lserver()) ->
269 boolean() | {error, atom()}.
270 does_user_exist(HostType, LUser, LServer) ->
271
:-(
try execute_get_password(HostType, LServer, LUser) of
272 {selected, [{_Password, _}]} ->
273
:-(
true; %% Account exists
274 {selected, []} ->
275
:-(
false %% Account does not exist
276 catch
277 error:Reason:StackTrace ->
278
:-(
?LOG_ERROR(#{what => does_user_exist_failed,
279 user => LUser, server => LServer,
280
:-(
class => error, reason => Reason, stacktrace => StackTrace}),
281
:-(
{error, Reason} %% Database error
282
283 end.
284
285
286 %% @doc Remove user.
287 %% Note: it may return ok even if there was some problem removing the user.
288 -spec remove_user(mongooseim:host_type(), jid:luser(), jid:lserver()) -> ok.
289 remove_user(HostType, LUser, LServer) ->
290
:-(
try
291
:-(
execute_delete_user(HostType, LServer, LUser)
292 catch
293 error:Reason:StackTrace ->
294
:-(
?LOG_ERROR(#{what => remove_user_failed,
295 user => LUser, server => LServer,
296
:-(
class => error, reason => Reason, stacktrace => StackTrace})
297 end,
298
:-(
ok.
299
300 -spec remove_domain(mongooseim:host_type(), jid:lserver()) -> ok.
301 remove_domain(HostType, Domain) ->
302
:-(
execute_successfully(HostType, auth_remove_domain, [Domain]),
303
:-(
ok.
304
305 -spec supported_features() -> [atom()].
306
:-(
supported_features() -> [dynamic_domains].
307
308 %%%------------------------------------------------------------------
309 %%% Scram
310 %%%------------------------------------------------------------------
311
312 -spec prepare_scrammed_password(HostType, Iterations, Password) -> prepared_password() when
313 HostType :: mongooseim:host_type(),
314 Iterations :: pos_integer(),
315 Password :: binary().
316 prepare_scrammed_password(HostType, Iterations, Password) when is_integer(Iterations) ->
317
:-(
Scram = mongoose_scram:password_to_scram(HostType, Password, Iterations),
318
:-(
#{password => <<>>,
319 details => mongoose_scram:serialize(Scram)}.
320
321 -spec prepare_password(HostType :: mongooseim:host_type(), Password :: binary()) ->
322 prepared_password().
323 prepare_password(HostType, Password) ->
324
:-(
case mongoose_scram:enabled(HostType) of
325 true ->
326
:-(
prepare_scrammed_password(HostType, mongoose_scram:iterations(HostType), Password);
327 false ->
328
:-(
#{password => Password}
329 end.
330
331 -spec scram_passwords(Server, ScramIterationCount) -> ok | {error, atom()} when
332 Server :: jid:lserver(),
333 ScramIterationCount :: pos_integer().
334 scram_passwords(Server, ScramIterationCount) ->
335
:-(
scram_passwords(Server, ?DEFAULT_SCRAMMIFY_COUNT,
336 ?DEFAULT_SCRAMMIFY_INTERVAL, ScramIterationCount).
337
338 -spec scram_passwords(Server, Count, Interval, ScramIterationCount) ->
339 ok | {error, atom()} when
340 Server :: jid:lserver(),
341 Count :: pos_integer(),
342 Interval :: pos_integer(),
343 ScramIterationCount :: pos_integer().
344 scram_passwords(Server, Count, Interval, ScramIterationCount) ->
345
:-(
LServer = jid:nameprep(Server),
346
:-(
{ok, HostType} = mongoose_domain_api:get_domain_host_type(LServer),
347
:-(
?LOG_INFO(#{what => scram_passwords, server => Server,
348
:-(
text => <<"Converting the stored passwords into SCRAM bits">>}),
349
:-(
Selected = execute_count_users_without_scram(HostType, LServer),
350
:-(
ToConvertCount = mongoose_rdbms:selected_to_integer(Selected),
351
352
:-(
?LOG_INFO(#{what => scram_passwords, server => Server,
353 convert_count => ToConvertCount,
354
:-(
text => <<"Users to scrammify">>}),
355
:-(
scram_passwords1(HostType, LServer, Count, Interval, ScramIterationCount).
356
357 -spec scram_passwords1(HostType, LServer, Count, Interval, ScramIterationCount) ->
358 ok | {error, interrupted} when
359 HostType :: mongooseim:host_type(),
360 LServer :: jid:lserver(),
361 Count :: pos_integer(),
362 Interval :: pos_integer(),
363 ScramIterationCount :: pos_integer().
364 scram_passwords1(HostType, LServer, Count, Interval, ScramIterationCount) ->
365
:-(
case execute_list_users_without_scram(HostType, LServer, Count) of
366 {selected, []} ->
367
:-(
?LOG_INFO(#{what => scram_passwords_completed,
368
:-(
text => <<"All users scrammed">>}),
369
:-(
ok;
370 {selected, Results} ->
371
:-(
?LOG_INFO(#{what => scram_passwords_progress,
372 user_count => length(Results),
373
:-(
text => <<"Scramming users in progress...">>}),
374
:-(
lists:foreach(
375 fun({Username, Password}) ->
376
:-(
ScrammedPassword = prepare_scrammed_password(HostType,
377 ScramIterationCount,
378 Password),
379
:-(
execute_set_password(HostType, LServer, Username, ScrammedPassword)
380 end, Results),
381
:-(
?LOG_INFO(#{what => scram_passwords_progress,
382 user_count => length(Results), interval => Interval,
383
:-(
text => io_lib:format("Scrammed. Waiting for ~pms", [Interval])}),
384
:-(
timer:sleep(Interval),
385
:-(
scram_passwords1(HostType, LServer, Count, Interval, ScramIterationCount)
386 end.
387
388 %%%------------------------------------------------------------------
389 %%% DB Queries
390 %%%------------------------------------------------------------------
391
392 -spec prepare_queries(mongooseim:host_type()) -> any().
393 prepare_queries(HostType) ->
394
:-(
prepare(auth_get_password, users,
395 [server, username],
396 <<"SELECT password, pass_details FROM users "
397 "WHERE server = ? AND username = ?">>),
398
:-(
prepare(auth_set_password_scram, users,
399 [password, pass_details, server, username],
400 <<"UPDATE users SET password = ?, pass_details = ? "
401 "WHERE server = ? AND username = ?">>),
402
:-(
prepare(auth_set_password, users,
403 [password, server, username],
404 <<"UPDATE users SET password = ? WHERE server = ? AND username = ?">>),
405
:-(
prepare(auth_add_user_scram, users,
406 [server, username, password, pass_details],
407 <<"INSERT INTO users(server, username, password, pass_details) VALUES (?, ?, ?, ?)">>),
408
:-(
prepare(auth_add_user, users,
409 [server, username, password],
410 <<"INSERT INTO users(server, username, password) VALUES (?, ?, ?)">>),
411
:-(
prepare(auth_delete_user, users,
412 [server, username],
413 <<"DELETE FROM users WHERE server = ? AND username = ?">>),
414
:-(
prepare(auth_list_users, users, [server],
415 <<"SELECT username FROM users WHERE server = ?">>),
416
:-(
LimitOffset = rdbms_queries:limit_offset_sql(),
417
:-(
prepare(auth_list_users_range, users,
418 [server, limit, offset],
419 <<"SELECT username FROM users WHERE server = ? ORDER BY username ",
420 LimitOffset/binary>>),
421
:-(
prepare(auth_list_users_prefix, users,
422 [server, username],
423 <<"SELECT username FROM users "
424 "WHERE server = ? AND username LIKE ? ESCAPE '$' ORDER BY username">>),
425
:-(
prepare(auth_list_users_prefix_range, users,
426 [server, username, limit, offset],
427 <<"SELECT username FROM users "
428 "WHERE server = ? AND username LIKE ? ESCAPE '$' ORDER BY username ",
429 LimitOffset/binary>>),
430
:-(
{LimitSQL, LimitMSSQL} = rdbms_queries:get_db_specific_limits_binaries(),
431
:-(
prepare(auth_list_users_without_scram, users,
432 [server, limit],
433 <<"SELECT ", LimitMSSQL/binary, " username, password FROM users "
434 "WHERE server = ? AND pass_details is NULL ", LimitSQL/binary>>),
435
:-(
prepare(auth_count_users_prefix, users,
436 [server, username],
437 <<"SELECT COUNT(*) FROM users WHERE server = ? AND username LIKE ? ESCAPE '$'">>),
438
:-(
prepare_count_users(HostType),
439
:-(
prepare(auth_count_users_without_scram, users, [server],
440 <<"SELECT COUNT(*) FROM users WHERE server = ? AND pass_details is NULL">>),
441
:-(
prepare(auth_remove_domain, users, [server],
442 <<"DELETE FROM users WHERE server = ?">>).
443
444 prepare_count_users(HostType) ->
445
:-(
case {mongoose_config:get_opt([{auth, HostType}, rdbms, users_number_estimate]),
446 mongoose_rdbms:db_engine(HostType)} of
447 {true, mysql} ->
448
:-(
prepare(auth_count_users_estimate, 'information_schema.tables', [],
449 <<"SELECT table_rows FROM information_schema.tables "
450 "WHERE table_name = 'users'">>);
451 {true, pgsql} ->
452
:-(
prepare_count_users(),
453
:-(
prepare(auth_count_users_estimate, pg_class, [],
454 <<"SELECT reltuples::numeric FROM pg_class "
455 "WHERE oid = 'users'::regclass::oid">>);
456 _ ->
457
:-(
prepare_count_users()
458 end.
459
460 prepare_count_users() ->
461
:-(
prepare(auth_count_users, users, [server], <<"SELECT COUNT(*) FROM users WHERE server = ?">>).
462
463 -spec execute_get_password(mongooseim:host_type(), jid:lserver(), jid:luser()) ->
464 mongoose_rdbms:query_result().
465 execute_get_password(HostType, LServer, LUser) ->
466
:-(
execute_successfully(HostType, auth_get_password, [LServer, LUser]).
467
468 -spec execute_set_password(mongooseim:host_type(), jid:lserver(), jid:luser(),
469 prepared_password()) ->
470 mongoose_rdbms:query_result().
471 execute_set_password(HostType, LServer, LUser, #{password := Pass, details := PassDetails}) ->
472
:-(
execute_successfully(HostType, auth_set_password_scram, [Pass, PassDetails, LServer, LUser]);
473 execute_set_password(HostType, LServer, LUser, #{password := Pass}) ->
474
:-(
execute_successfully(HostType, auth_set_password, [Pass, LServer, LUser]).
475
476 -spec execute_add_user(mongooseim:host_type(), jid:lserver(), jid:luser(), prepared_password()) ->
477 mongoose_rdbms:query_result().
478 execute_add_user(HostType, LServer, LUser, #{password := Pass, details := PassDetails}) ->
479
:-(
execute_successfully(HostType, auth_add_user_scram, [LServer, LUser, Pass, PassDetails]);
480 execute_add_user(HostType, LServer, LUser, #{password := Pass}) ->
481
:-(
execute_successfully(HostType, auth_add_user, [LServer, LUser, Pass]).
482
483 -spec execute_delete_user(mongooseim:host_type(), jid:lserver(), jid:luser()) ->
484 mongoose_rdbms:query_result().
485 execute_delete_user(HostType, LServer, LUser) ->
486
:-(
execute_successfully(HostType, auth_delete_user, [LServer, LUser]).
487
488 -spec execute_list_users(mongooseim:host_type(), jid:lserver(), map()) ->
489 mongoose_rdbms:query_result().
490 execute_list_users(HostType, LServer, #{from := Start, to := End} = OptMap) ->
491
:-(
Map = maps:without([from, to], OptMap),
492
:-(
execute_list_users(HostType, LServer, Map#{limit => End - Start + 1, offset => Start - 1});
493 execute_list_users(HostType, LServer, #{prefix := Prefix, limit := Limit, offset := Offset}) ->
494
:-(
Args = [LServer, prefix_to_like(Prefix)] ++ rdbms_queries:limit_offset_args(Limit, Offset),
495
:-(
execute_successfully(HostType, auth_list_users_prefix_range, Args);
496 execute_list_users(HostType, LServer, #{prefix := Prefix}) ->
497
:-(
Args = [LServer, prefix_to_like(Prefix)],
498
:-(
execute_successfully(HostType, auth_list_users_prefix, Args);
499 execute_list_users(HostType, LServer, #{limit := Limit, offset := Offset}) ->
500
:-(
Args = [LServer] ++ rdbms_queries:limit_offset_args(Limit, Offset),
501
:-(
execute_successfully(HostType, auth_list_users_range, Args);
502 execute_list_users(HostType, LServer, #{}) ->
503
:-(
execute_successfully(HostType, auth_list_users, [LServer]).
504
505 -spec execute_list_users_without_scram(mongooseim:host_type(), jid:lserver(), non_neg_integer()) ->
506 mongoose_rdbms:query_result().
507 execute_list_users_without_scram(HostType, LServer, Limit) ->
508
:-(
execute_successfully(HostType, auth_list_users_without_scram, [LServer, Limit]).
509
510 -spec execute_count_users(mongooseim:host_type(), jid:lserver(), map()) ->
511 mongoose_rdbms:query_result().
512 execute_count_users(HostType, LServer, #{prefix := Prefix}) ->
513
:-(
Args = [LServer, prefix_to_like(Prefix)],
514
:-(
execute_successfully(HostType, auth_count_users_prefix, Args);
515 execute_count_users(HostType, LServer, #{}) ->
516
:-(
case {mongoose_config:get_opt([{auth, HostType}, rdbms, users_number_estimate]),
517 mongoose_rdbms:db_engine(LServer)} of
518 {true, mysql} ->
519
:-(
execute_successfully(HostType, auth_count_users_estimate, []);
520 {true, pgsql} ->
521
:-(
case execute_successfully(HostType, auth_count_users_estimate, []) of
522 {selected,[{<<"-1">>}]} ->
523
:-(
execute_successfully(HostType, auth_count_users, [LServer]);
524 Otherwise ->
525
:-(
Otherwise
526 end;
527 _ ->
528
:-(
execute_successfully(HostType, auth_count_users, [LServer])
529 end.
530
531 -spec execute_count_users_without_scram(mongooseim:host_type(), jid:lserver()) ->
532 mongoose_rdbms:query_result().
533 execute_count_users_without_scram(HostType, LServer) ->
534
:-(
execute_successfully(HostType, auth_count_users_without_scram, [LServer]).
535
536 -spec prefix_to_like(binary()) -> binary().
537 prefix_to_like(Prefix) ->
538
:-(
EscapedPrefix = mongoose_rdbms:escape_prepared_like(Prefix),
539
:-(
<<EscapedPrefix/binary, $%>>.
Line Hits Source