diff --git a/doc/guide.tex b/doc/guide.tex index fea9d55e639..bef001c3267 100644 --- a/doc/guide.tex +++ b/doc/guide.tex @@ -2187,6 +2187,11 @@ The value \term{tls} enables encryption by using LDAP over SSL. Note that STARTTLS encryption is not supported. The default value is: \term{none}. +\titem{\{ldap\_tls\_verify, false|soft|hard\}} \ind{options!ldap\_tls\_verify} +This option specifies whether to verify LDAP server certificate or not when TLS is enabled. +When \term{hard} is enabled \ejabberd{} doesn't proceed if a certificate is invalid. +When \term{soft} is enabled \ejabberd{} proceeds even if check fails. +The default is \term{false} which means no checks are performed. \titem{\{ldap\_port, Number\}} \ind{options!ldap\_port}Port to connect to your LDAP server. The default port is~389 if encryption is disabled; and 636 if encryption is enabled. If you configure a value, it is stored in \ejabberd{}'s database. diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl index 9c490bb9301..b96571366d7 100644 --- a/src/ejabberd_auth_ldap.erl +++ b/src/ejabberd_auth_ldap.erl @@ -66,7 +66,7 @@ servers, backups, port, - encrypt, + tls_options, dn, password, base, @@ -119,19 +119,19 @@ terminate(_Reason, _State) -> init(Host) -> State = parse_options(Host), eldap_pool:start_link(State#state.eldap_id, - State#state.servers, - State#state.backups, - State#state.port, - State#state.dn, - State#state.password, - State#state.encrypt), + State#state.servers, + State#state.backups, + State#state.port, + State#state.dn, + State#state.password, + State#state.tls_options), eldap_pool:start_link(State#state.bind_eldap_id, - State#state.servers, - State#state.backups, - State#state.port, - State#state.dn, - State#state.password, - State#state.encrypt), + State#state.servers, + State#state.backups, + State#state.port, + State#state.dn, + State#state.password, + State#state.tls_options), {ok, State}. plain_password_required() -> @@ -373,6 +373,7 @@ parse_options(Host) -> Backups -> Backups end, LDAPEncrypt = ejabberd_config:get_local_option({ldap_encrypt, Host}), + LDAPTLSVerify = ejabberd_config:get_local_option({ldap_tls_verify, Host}), LDAPPort = case ejabberd_config:get_local_option({ldap_port, Host}) of undefined -> case LDAPEncrypt of tls -> ?LDAPS_PORT; @@ -417,7 +418,8 @@ parse_options(Host) -> servers = LDAPServers, backups = LDAPBackups, port = LDAPPort, - encrypt = LDAPEncrypt, + tls_options = [{encrypt, LDAPEncrypt}, + {tls_verify, LDAPTLSVerify}], dn = RootDN, password = Password, base = LDAPBase, diff --git a/src/eldap/eldap.erl b/src/eldap/eldap.erl index 5bc0c425af9..82f0df47869 100644 --- a/src/eldap/eldap.erl +++ b/src/eldap/eldap.erl @@ -130,9 +130,10 @@ start_link(Name) -> Reg_name = list_to_atom("eldap_" ++ Name), gen_fsm:start_link({local, Reg_name}, ?MODULE, [], []). -start_link(Name, Hosts, Port, Rootdn, Passwd, Encrypt) -> +start_link(Name, Hosts, Port, Rootdn, Passwd, Opts) -> Reg_name = list_to_atom("eldap_" ++ Name), - gen_fsm:start_link({local, Reg_name}, ?MODULE, {Hosts, Port, Rootdn, Passwd, Encrypt}, []). + gen_fsm:start_link({local, Reg_name}, ?MODULE, + {Hosts, Port, Rootdn, Passwd, Opts}, []). %%% -------------------------------------------------------------------- %%% Get status of connection. @@ -423,15 +424,19 @@ get_handle(Name) when is_list(Name) -> list_to_atom("eldap_" ++ Name). %%---------------------------------------------------------------------- init([]) -> case get_config() of - {ok, Hosts, Rootdn, Passwd, Encrypt} -> - init({Hosts, Rootdn, Passwd, Encrypt}); + {ok, Hosts, Rootdn, Passwd, Opts} -> + init({Hosts, Rootdn, Passwd, Opts}); {error, Reason} -> {stop, Reason} end; -init({Hosts, Port, Rootdn, Passwd, Encrypt}) -> +init({Hosts, Port, Rootdn, Passwd, Opts}) -> catch ssl:start(), {X1,X2,X3} = erlang:now(), ssl:seed(integer_to_list(X1) ++ integer_to_list(X2) ++ integer_to_list(X3)), + Encrypt = case proplists:get_value(encrypt, Opts) of + tls -> tls; + _ -> none + end, PortTemp = case Port of undefined -> case Encrypt of @@ -444,7 +449,14 @@ init({Hosts, Port, Rootdn, Passwd, Encrypt}) -> end; PT -> PT end, - TLSOpts = [verify_none], + TLSOpts = case proplists:get_value(tls_verify, Opts) of + soft -> + [{verify, 1}]; + hard -> + [{verify, 2}]; + _ -> + [{verify, 0}] + end, {ok, connecting, #eldap{hosts = Hosts, port = PortTemp, rootdn = Rootdn, @@ -958,7 +970,7 @@ connect_bind(S) -> tls -> SockMod = ssl, SslOpts = [{packet, asn1}, {active, true}, {keepalive, true}, - binary], + binary | S#eldap.tls_options], ssl:connect(Host, S#eldap.port, SslOpts); %% starttls -> %% TODO: Implement STARTTLS; _ -> @@ -1074,8 +1086,8 @@ get_config() -> case file:consult(File) of {ok, Entries} -> case catch parse(Entries) of - {ok, Hosts, Port, Rootdn, Passwd, Encrypt} -> - {ok, Hosts, Port, Rootdn, Passwd, Encrypt}; + {ok, Hosts, Port, Rootdn, Passwd, Opts} -> + {ok, Hosts, Port, Rootdn, Passwd, Opts}; {error, Reason} -> {error, Reason}; {'EXIT', Reason} -> @@ -1091,7 +1103,7 @@ parse(Entries) -> get_integer(port, Entries), get_list(rootdn, Entries), get_list(passwd, Entries), - get_atom(encrypt, Entries)}. + get_list(options, Entries)}. get_integer(Key, List) -> case lists:keysearch(Key, 1, List) of @@ -1113,15 +1125,15 @@ get_list(Key, List) -> throw({error, "No Entry in Config for " ++ atom_to_list(Key)}) end. -get_atom(Key, List) -> - case lists:keysearch(Key, 1, List) of - {value, {Key, Value}} when is_atom(Value) -> - Value; - {value, {Key, _Value}} -> - throw({error, "Bad Value in Config for " ++ atom_to_list(Key)}); - false -> - throw({error, "No Entry in Config for " ++ atom_to_list(Key)}) - end. +%% get_atom(Key, List) -> +%% case lists:keysearch(Key, 1, List) of +%% {value, {Key, Value}} when is_atom(Value) -> +%% Value; +%% {value, {Key, _Value}} -> +%% throw({error, "Bad Value in Config for " ++ atom_to_list(Key)}); +%% false -> +%% throw({error, "No Entry in Config for " ++ atom_to_list(Key)}) +%% end. get_hosts(Key, List) -> lists:map(fun({Key1, {A,B,C,D}}) when is_integer(A), diff --git a/src/eldap/eldap_pool.erl b/src/eldap/eldap_pool.erl index 2331b2c05f2..ed03692e7e5 100644 --- a/src/eldap/eldap_pool.erl +++ b/src/eldap/eldap_pool.erl @@ -49,18 +49,20 @@ search(PoolName, Opts) -> modify_passwd(PoolName, DN, Passwd) -> do_request(PoolName, {modify_passwd, [DN, Passwd]}). -start_link(Name, Hosts, Backups, Port, Rootdn, Passwd, Encrypt) -> +start_link(Name, Hosts, Backups, Port, Rootdn, Passwd, Opts) -> PoolName = make_id(Name), pg2:create(PoolName), - lists:foreach(fun(Host) -> - ID = erlang:ref_to_list(make_ref()), - case catch eldap:start_link(ID, [Host|Backups], Port, Rootdn, Passwd, Encrypt) of - {ok, Pid} -> - pg2:join(PoolName, Pid); - _ -> - error - end - end, Hosts). + lists:foreach( + fun(Host) -> + ID = erlang:ref_to_list(make_ref()), + case catch eldap:start_link(ID, [Host|Backups], Port, + Rootdn, Passwd, Opts) of + {ok, Pid} -> + pg2:join(PoolName, Pid); + _ -> + error + end + end, Hosts). %%==================================================================== %% Internal functions diff --git a/src/mod_vcard_ldap.erl b/src/mod_vcard_ldap.erl index f4078dfc439..ed52a05939f 100644 --- a/src/mod_vcard_ldap.erl +++ b/src/mod_vcard_ldap.erl @@ -62,7 +62,7 @@ servers, backups, port, - encrypt, + tls_options, dn, base, password, @@ -181,7 +181,7 @@ init([Host, Opts]) -> State#state.port, State#state.dn, State#state.password, - State#state.encrypt), + State#state.tls_options), case State#state.search of true -> ejabberd_router:register_route(State#state.myhost); @@ -686,6 +686,11 @@ parse_options(Host, Opts) -> ejabberd_config:get_local_option({ldap_encrypt, Host}); E -> E end, + LDAPTLSVerify = case gen_mod:get_opt(ldap_tls_verify, Opts, undefined) of + undefined -> + ejabberd_config:get_local_option({ldap_tls_verify, Host}); + Verify -> Verify + end, LDAPPortTemp = case gen_mod:get_opt(ldap_port, Opts, undefined) of undefined -> ejabberd_config:get_local_option({ldap_port, Host}); @@ -766,7 +771,8 @@ parse_options(Host, Opts) -> servers = LDAPServers, backups = LDAPBackups, port = LDAPPort, - encrypt = LDAPEncrypt, + tls_options = [{encrypt, LDAPEncrypt}, + {tls_verify, LDAPTLSVerify}], dn = RootDN, base = LDAPBase, password = Password,