]> granicus.if.org Git - ejabberd/commitdiff
Relax digest-uri handling (thanks to Daniel Willmann)(EJAB-1529)
authorBadlop <badlop@process-one.net>
Fri, 16 Mar 2012 13:16:17 +0000 (14:16 +0100)
committerBadlop <badlop@process-one.net>
Fri, 16 Mar 2012 13:16:17 +0000 (14:16 +0100)
This patch introduces a new config option - fqdn - to set the fully
qualified domain name of the host:
  {fqdn, "foo.example.com"}.
This fixes a problem with Pidgin not being able to log in on a server
that used SRV records.

doc/guide.tex
src/cyrsasl_digest.erl
src/ejabberd.cfg.example
src/ejabberd_config.erl

index 1b151ee7c189508a8b9a62ddebea574b5375424e..f0af763ddee970f48b7b5be201b523c5f586a10f 100644 (file)
@@ -1231,6 +1231,12 @@ The default value is \term{closeold}.
 If the client uses old Jabber Non-SASL authentication (\xepref{0078}),
 then this option is not respected, and the action performed is \term{closeold}.
 
+The option \option{fqdn} allows you to define the Fully Qualified Domain Name
+of the machine, in case it isn't detected automatically.
+The FQDN is used to authenticate some clients that use the DIGEST-MD5 SASL mechanism.
+The option syntax is:
+\esyntax{\{fqdn, undefined|FqdnString\}.}
+
 \makesubsubsection{internalauth}{Internal}
 \ind{internal authentication}\ind{Mnesia}
 
index 99c8e2a0e6aab2732b39f82a4d644ff355e71b47..134a86dafa7b7426e8c0833bee5d81379ef99b76 100644 (file)
 -behaviour(cyrsasl).
 
 -record(state, {step, nonce, username, authzid, get_password, check_password, auth_module,
-               host}).
+               host, hostfqdn}).
 
 start(_Opts) ->
+    Fqdn = get_local_fqdn(),
+    ?INFO_MSG("FQDN used to check DIGEST-MD5 SASL authentication: ~p", [Fqdn]),
     cyrsasl:register_mechanism("DIGEST-MD5", ?MODULE, digest).
 
 stop() ->
@@ -49,6 +51,7 @@ mech_new(Host, GetPassword, _CheckPassword, CheckPasswordDigest) ->
     {ok, #state{step = 1,
                nonce = randoms:get_string(),
                host = Host,
+               hostfqdn = get_local_fqdn(),
                get_password = GetPassword,
                check_password = CheckPasswordDigest}}.
 
@@ -64,10 +67,11 @@ mech_step(#state{step = 3, nonce = Nonce} = State, ClientIn) ->
        KeyVals ->
            DigestURI = xml:get_attr_s("digest-uri", KeyVals),
            UserName = xml:get_attr_s("username", KeyVals),
-           case is_digesturi_valid(DigestURI, State#state.host) of
+           case is_digesturi_valid(DigestURI, State#state.host, State#state.hostfqdn) of
                false ->
                    ?DEBUG("User login not authorized because digest-uri "
-                          "seems invalid: ~p", [DigestURI]),
+                          "seems invalid: ~p (checking for Host ~p, FQDN ~p)", [DigestURI,
+                          State#state.host, State#state.hostfqdn]),
                    {error, "not-authorized", UserName};
                true ->
                    AuthzId = xml:get_attr_s("authzid", KeyVals),
@@ -154,21 +158,35 @@ parse4([], Key, Val, Ts) ->
 %% however ejabberd doesn't allow that.
 %% If the service (for example jabber.example.org)
 %% is provided by several hosts (being one of them server3.example.org),
-%% then digest-uri can be like xmpp/server3.example.org/jabber.example.org
-%% In that case, ejabberd only checks the service name, not the host.
-is_digesturi_valid(DigestURICase, JabberHost) ->
+%% then acceptable digest-uris would be:
+%% xmpp/server3.example.org/jabber.example.org, xmpp/server3.example.org and
+%% xmpp/jabber.example.org
+%% The last version is not actually allowed by the RFC, but implemented by popular clients
+is_digesturi_valid(DigestURICase, JabberDomain, JabberFQDN) ->
     DigestURI = stringprep:tolower(DigestURICase),
     case catch string:tokens(DigestURI, "/") of
-       ["xmpp", Host] when Host == JabberHost ->
+       ["xmpp", Host] when (Host == JabberDomain) or (Host == JabberFQDN) ->
            true;
-       ["xmpp", _Host, ServName] when ServName == JabberHost ->
+       ["xmpp", Host, ServName] when (ServName == JabberDomain) and (Host == JabberFQDN) ->
            true;
        _ ->
            false
     end.
 
-
-
+get_local_fqdn() ->
+    case (catch get_local_fqdn2()) of
+       Str when is_list(Str) -> Str;
+       _ -> "unknown-fqdn, please configure fqdn option in ejabberd.cfg!"
+    end.
+get_local_fqdn2() ->
+    case ejabberd_config:get_local_option(fqdn) of
+       ConfiguredFqdn when is_list(ConfiguredFqdn) ->
+           ConfiguredFqdn;
+       _undefined ->
+           {ok, Hostname} = inet:gethostname(),
+           {ok, {hostent, Fqdn, _, _, _, _}} = inet:gethostbyname(Hostname),
+           Fqdn
+    end.
 
 digit_to_xchar(D) when (D >= 0) and (D < 10) ->
     D + 48;
index 57eab41bd5dbdae4f508284ee31cc89a406ad7ac..a4068ad96877ecac17b9b74f42a09ca332ea6d62 100644 (file)
 %% Store the plain passwords or hashed for SCRAM:
 %%{auth_password_format, plain}.
 %%{auth_password_format, scram}.
+%%
+%% Define the FQDN if ejabberd doesn't detect it:
+%%{fqdn, "server3.example.com"}.
 
 %%
 %% Authentication using external script
index b1b67fee77b1c56e63d4624979d831ce6ff7dca5..503537e76fe094f5895976396f74ee3dd8875b31 100644 (file)
@@ -374,6 +374,9 @@ process_term(Term, State) ->
            State;
        {hosts, _Hosts} ->
            State;
+       {fqdn, HostFQDN} ->
+           ?DEBUG("FQDN set to: ~p", [HostFQDN]),
+           add_option(fqdn, HostFQDN, State);
        {host_config, Host, Terms} ->
            lists:foldl(fun(T, S) -> process_host_term(T, Host, S) end,
                        State, Terms);