]> granicus.if.org Git - ejabberd/commitdiff
Add SSL support for SQL connections
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>
Tue, 10 Jan 2017 14:40:38 +0000 (17:40 +0300)
committerEvgeniy Khramtsov <ekhramtsov@process-one.net>
Tue, 10 Jan 2017 14:40:38 +0000 (17:40 +0300)
Currently only PostgreSQL is supported.
This requires p1_pgsql-1.1.2 and higher.

rebar.config
src/ejabberd_sql.erl

index c91b162518ea3e32c1848bdfdd5c217785789150..69dbba775ab647fead870121ba0cf47c05ba694e 100644 (file)
@@ -34,7 +34,7 @@
         {if_var_true, mysql, {p1_mysql, ".*", {git, "https://github.com/processone/p1_mysql",
                                                {tag, "1.0.2"}}}},
         {if_var_true, pgsql, {p1_pgsql, ".*", {git, "https://github.com/processone/p1_pgsql",
-                                               {tag, "1.1.1"}}}},
+                                               {tag, "1.1.2"}}}},
         {if_var_true, sqlite, {sqlite3, ".*", {git, "https://github.com/processone/erlang-sqlite3",
                                                {tag, "1.1.5"}}}},
         {if_var_true, pam, {p1_pam, ".*", {git, "https://github.com/processone/epam",
index 53e812063c61caeb5e3bfdf9b7610337cce5a1be..46dd682979c0addce4828af2419538859c100b5a 100644 (file)
@@ -279,8 +279,8 @@ init([Host, StartInterval]) ->
 
 connecting(connect, #state{host = Host} = State) ->
     ConnectRes = case db_opts(Host) of
-                  [mysql | Args] -> apply(fun mysql_connect/5, Args);
-           [pgsql | Args] -> apply(fun pgsql_connect/5, Args);
+                  [mysql | Args] -> apply(fun mysql_connect/7, Args);
+           [pgsql | Args] -> apply(fun pgsql_connect/7, Args);
            [sqlite | Args] -> apply(fun sqlite_connect/1, Args);
                   [mssql | Args] -> apply(fun odbc_connect/1, Args);
                   [odbc | Args] -> apply(fun odbc_connect/1, Args)
@@ -782,13 +782,14 @@ sqlite_to_odbc(_Host, _) ->
 
 %% part of init/1
 %% Open a database connection to PostgreSQL
-pgsql_connect(Server, Port, DB, Username, Password) ->
+pgsql_connect(Server, Port, DB, Username, Password, Transport, SSLOpts) ->
     case pgsql:connect([{host, Server},
                         {database, DB},
                         {user, Username},
                         {password, Password},
                         {port, Port},
-                        {as_binary, true}]) of
+                       {transport, Transport},
+                        {as_binary, true}|SSLOpts]) of
         {ok, Ref} ->
             pgsql:squery(Ref, [<<"alter database \"">>, DB, <<"\" set ">>,
                                <<"standard_conforming_strings='off';">>]),
@@ -837,7 +838,7 @@ pgsql_execute_to_odbc(_) -> {updated, undefined}.
 
 %% part of init/1
 %% Open a database connection to MySQL
-mysql_connect(Server, Port, DB, Username, Password) ->
+mysql_connect(Server, Port, DB, Username, Password, _, _) ->
     case p1_mysql_conn:start(binary_to_list(Server), Port,
                             binary_to_list(Username),
                             binary_to_list(Password),
@@ -921,6 +922,14 @@ db_opts(Host) ->
     Server = ejabberd_config:get_option({sql_server, Host},
                                         fun iolist_to_binary/1,
                                         <<"localhost">>),
+    Transport = case ejabberd_config:get_option(
+                      {sql_ssl, Host},
+                      fun(B) when is_boolean(B) -> B end,
+                      false) of
+                   false -> tcp;
+                   true -> ssl
+               end,
+    warn_if_ssl_unsupported(Transport, Type),
     case Type of
         odbc ->
             [odbc, Server];
@@ -944,15 +953,54 @@ db_opts(Host) ->
             Pass = ejabberd_config:get_option({sql_password, Host},
                                               fun iolist_to_binary/1,
                                               <<"">>),
+           SSLOpts = get_ssl_opts(Transport, Host),
            case Type of
                mssql ->
                    [mssql, <<"DSN=", Host/binary, ";UID=", User/binary,
                              ";PWD=", Pass/binary>>];
                _ ->
-                   [Type, Server, Port, DB, User, Pass]
+                   [Type, Server, Port, DB, User, Pass, Transport, SSLOpts]
            end
     end.
 
+warn_if_ssl_unsupported(tcp, _) ->
+    ok;
+warn_if_ssl_unsupported(ssl, pgsql) ->
+    ok;
+warn_if_ssl_unsupported(ssl, Type) ->
+    ?WARNING_MSG("SSL connection is not supported for ~s", [Type]).
+
+get_ssl_opts(ssl, Host) ->
+    Opts1 = case ejabberd_config:get_option({sql_ssl_certfile, Host},
+                                           fun iolist_to_binary/1) of
+               undefined -> [];
+               CertFile -> [{certfile, CertFile}]
+           end,
+    Opts2 = case ejabberd_config:get_option({sql_ssl_cafile, Host},
+                                           fun iolist_to_binary/1) of
+               undefined -> Opts1;
+               CAFile -> [{cacertfile, CAFile}|Opts1]
+           end,
+    case ejabberd_config:get_option({sql_ssl_verify, Host},
+                                   fun(B) when is_boolean(B) -> B end,
+                                   false) of
+       true ->
+           case lists:keymember(cacertfile, 1, Opts2) of
+               true ->
+                   [{verify, verify_peer}|Opts2];
+               false ->
+                   ?WARNING_MSG("SSL verification is enabled for "
+                                "SQL connection, but option "
+                                "'sql_ssl_cafile' is not set; "
+                                "verification will be disabled", []),
+                   Opts2
+           end;
+       false ->
+           Opts2
+    end;
+get_ssl_opts(tcp, _) ->
+    [].
+
 init_mssql(Host) ->
     Server = ejabberd_config:get_option({sql_server, Host},
                                         fun iolist_to_binary/1,
@@ -1061,7 +1109,12 @@ opt_type(sql_type) ->
        (odbc) -> odbc
     end;
 opt_type(sql_username) -> fun iolist_to_binary/1;
+opt_type(sql_ssl) -> fun(B) when is_boolean(B) -> B end;
+opt_type(sql_ssl_verify) -> fun(B) when is_boolean(B) -> B end;
+opt_type(sql_ssl_certfile) -> fun iolist_to_binary/1;
+opt_type(sql_ssl_cafile) -> fun iolist_to_binary/1;
 opt_type(_) ->
     [max_fsm_queue, sql_database, sql_keepalive_interval,
      sql_password, sql_port, sql_server, sql_type,
-     sql_username].
+     sql_username, sql_ssl, sql_ssl_verify, sql_ssl_cerfile,
+     sql_ssl_cafile].