• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

processone / ejabberd / 1296

19 Jan 2026 11:25AM UTC coverage: 33.562% (+0.09%) from 33.468%
1296

push

github

badlop
mod_conversejs: Cosmetic change: sort paths alphabetically

0 of 4 new or added lines in 1 file covered. (0.0%)

11245 existing lines in 174 files now uncovered.

15580 of 46421 relevant lines covered (33.56%)

1074.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.0
/src/mod_legacy_auth.erl
1
%%%-------------------------------------------------------------------
2
%%% Created : 11 Dec 2016 by Evgeny Khramtsov <ekhramtsov@process-one.net>
3
%%%
4
%%%
5
%%% ejabberd, Copyright (C) 2002-2026   ProcessOne
6
%%%
7
%%% This program is free software; you can redistribute it and/or
8
%%% modify it under the terms of the GNU General Public License as
9
%%% published by the Free Software Foundation; either version 2 of the
10
%%% License, or (at your option) any later version.
11
%%%
12
%%% This program is distributed in the hope that it will be useful,
13
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
14
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
%%% General Public License for more details.
16
%%%
17
%%% You should have received a copy of the GNU General Public License along
18
%%% with this program; if not, write to the Free Software Foundation, Inc.,
19
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
%%%
21
%%%-------------------------------------------------------------------
22
-module(mod_legacy_auth).
23
-behaviour(gen_mod).
24

25
-protocol({xep, 78, '2.5', '17.03', "complete", ""}).
26

27
%% gen_mod API
28
-export([start/2, stop/1, reload/3, depends/2, mod_options/1, mod_doc/0]).
29
%% hooks
30
-export([c2s_unauthenticated_packet/2, c2s_stream_features/2]).
31

32
-include_lib("xmpp/include/xmpp.hrl").
33
-include("translate.hrl").
34

35
-type c2s_state() :: ejabberd_c2s:state().
36

37
%%%===================================================================
38
%%% API
39
%%%===================================================================
40
start(_Host, _Opts) ->
41
    {ok, [{hook, c2s_unauthenticated_packet, c2s_unauthenticated_packet, 50},
98✔
42
          {hook, c2s_pre_auth_features, c2s_stream_features, 50}]}.
43

44
stop(_Host) ->
45
    ok.
98✔
46

47
reload(_Host, _NewOpts, _OldOpts) ->
48
    ok.
×
49

50
depends(_Host, _Opts) ->
51
    [].
116✔
52

53
mod_options(_) ->
54
    [].
116✔
55

56
mod_doc() ->
57
    #{desc =>
×
58
          [?T("The module implements "
59
              "https://xmpp.org/extensions/xep-0078.html"
60
              "[XEP-0078: Non-SASL Authentication]."), "",
61
           ?T("NOTE: This type of authentication was obsoleted in "
62
              "2008 and you unlikely need this module unless "
63
              "you have something like outdated Jabber bots.")]}.
64

65
-spec c2s_unauthenticated_packet(c2s_state(), iq()) ->
66
      c2s_state() | {stop, c2s_state()}.
67
c2s_unauthenticated_packet(State, #iq{type = T, sub_els = [_]} = IQ)
68
  when T == get; T == set ->
UNCOV
69
    try xmpp:try_subtag(IQ, #legacy_auth{}) of
97✔
70
        #legacy_auth{} = Auth ->
UNCOV
71
            {stop, authenticate(State, xmpp:set_els(IQ, [Auth]))};
80✔
72
        false ->
UNCOV
73
            State
17✔
74
    catch _:{xmpp_codec, Why} ->
75
            Txt = xmpp:io_format_error(Why),
×
76
            Lang = maps:get(lang, State),
×
77
            Err = xmpp:make_error(IQ, xmpp:err_bad_request(Txt, Lang)),
×
78
            {stop, ejabberd_c2s:send(State, Err)}
×
79
    end;
80
c2s_unauthenticated_packet(State, _) ->
UNCOV
81
    State.
2✔
82

83
-spec c2s_stream_features([xmpp_element()], binary()) -> [xmpp_element()].
84
c2s_stream_features(Acc, LServer) ->
85
    case gen_mod:is_loaded(LServer, ?MODULE) of
2,053✔
86
        true ->
87
            [#legacy_auth_feature{}|Acc];
2,053✔
88
        false ->
89
            Acc
×
90
    end.
91

92
%%%===================================================================
93
%%% Internal functions
94
%%%===================================================================
95
-spec authenticate(c2s_state(), iq()) -> c2s_state().
96
authenticate(#{server := Server} = State,
97
             #iq{type = get, sub_els = [#legacy_auth{}]} = IQ) ->
UNCOV
98
    LServer = jid:nameprep(Server),
40✔
UNCOV
99
    Auth = #legacy_auth{username = <<>>, password = <<>>, resource = <<>>},
40✔
UNCOV
100
    Res = case ejabberd_auth:plain_password_required(LServer) of
40✔
101
              false ->
UNCOV
102
                  xmpp:make_iq_result(IQ, Auth#legacy_auth{digest = <<>>});
40✔
103
              true ->
104
                  xmpp:make_iq_result(IQ, Auth)
×
105
          end,
UNCOV
106
    ejabberd_c2s:send(State, Res);
40✔
107
authenticate(State,
108
             #iq{type = set, lang = Lang,
109
                 sub_els = [#legacy_auth{username = U,
110
                                         resource = R}]} = IQ)
111
  when U == undefined; R == undefined; U == <<"">>; R == <<"">> ->
UNCOV
112
    Txt = ?T("Both the username and the resource are required"),
8✔
UNCOV
113
    Err = xmpp:make_error(IQ, xmpp:err_not_acceptable(Txt, Lang)),
8✔
UNCOV
114
    ejabberd_c2s:send(State, Err);
8✔
115
authenticate(#{stream_id := StreamID, server := Server,
116
               access := Access, ip := IP} = State,
117
             #iq{type = set, lang = Lang,
118
                 sub_els = [#legacy_auth{username = U,
119
                                         password = P0,
120
                                         digest = D0,
121
                                         resource = R}]} = IQ) ->
UNCOV
122
    P = if is_binary(P0) -> P0; true -> <<>> end,
32✔
UNCOV
123
    D = if is_binary(D0) -> D0; true -> <<>> end,
32✔
UNCOV
124
    DGen = fun (PW) -> str:sha(<<StreamID/binary, PW/binary>>) end,
32✔
UNCOV
125
    JID = jid:make(U, Server, R),
32✔
UNCOV
126
    case JID /= error andalso
32✔
127
        acl:match_rule(JID#jid.lserver, Access,
UNCOV
128
                       #{usr => jid:split(JID), ip => IP}) == allow of
24✔
129
        true ->
UNCOV
130
            case ejabberd_auth:check_password_with_authmodule(
24✔
131
                   U, U, JID#jid.lserver, P, D, DGen) of
132
                {true, AuthModule} ->
UNCOV
133
                    State1 = State#{sasl_mech => <<"legacy">>},
16✔
UNCOV
134
                    State2 = ejabberd_c2s:handle_auth_success(
16✔
135
                               U, <<"legacy">>, AuthModule, State1),
UNCOV
136
                    State3 = State2#{user := U},
16✔
UNCOV
137
                    open_session(State3, IQ, R);
16✔
138
                _ ->
UNCOV
139
                    Err = xmpp:make_error(IQ, xmpp:err_not_authorized()),
8✔
UNCOV
140
                    process_auth_failure(State, U, Err, 'not-authorized')
8✔
141
            end;
142
        false when JID == error ->
UNCOV
143
            Err = xmpp:make_error(IQ, xmpp:err_jid_malformed()),
8✔
UNCOV
144
            process_auth_failure(State, U, Err, 'jid-malformed');
8✔
145
        false ->
146
            Txt = ?T("Access denied by service policy"),
×
147
            Err = xmpp:make_error(IQ, xmpp:err_forbidden(Txt, Lang)),
×
148
            process_auth_failure(State, U, Err, 'forbidden')
×
149
    end.
150

151
-spec open_session(c2s_state(), iq(), binary()) -> c2s_state().
152
open_session(State, IQ, R) ->
UNCOV
153
    case ejabberd_c2s:bind(R, State) of
16✔
154
        {ok, State1} ->
UNCOV
155
            Res = xmpp:make_iq_result(IQ),
16✔
UNCOV
156
            ejabberd_c2s:send(State1, Res);
16✔
157
        {error, Err, State1} ->
158
            Res = xmpp:make_error(IQ, Err),
×
159
            ejabberd_c2s:send(State1, Res)
×
160
    end.
161

162
-spec process_auth_failure(c2s_state(), binary(), iq(), atom()) -> c2s_state().
163
process_auth_failure(State, User, StanzaErr, Reason) ->
UNCOV
164
    State1 = ejabberd_c2s:send(State, StanzaErr),
16✔
UNCOV
165
    State2 = State1#{sasl_mech => <<"legacy">>},
16✔
UNCOV
166
    Text = format_reason(Reason),
16✔
UNCOV
167
    ejabberd_c2s:handle_auth_failure(User, <<"legacy">>, Text, State2).
16✔
168

169
-spec format_reason(atom()) -> binary().
170
format_reason('not-authorized') ->
UNCOV
171
    <<"Invalid username or password">>;
8✔
172
format_reason('forbidden') ->
173
    <<"Access denied by service policy">>;
×
174
format_reason('jid-malformed') ->
UNCOV
175
    <<"Malformed XMPP address">>.
8✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc