summaryrefslogtreecommitdiff
path: root/src/rabbit.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/rabbit.erl')
-rw-r--r--src/rabbit.erl106
1 files changed, 105 insertions, 1 deletions
diff --git a/src/rabbit.erl b/src/rabbit.erl
index c9a008c446..f0d66f4110 100644
--- a/src/rabbit.erl
+++ b/src/rabbit.erl
@@ -24,7 +24,7 @@
start_fhc/0]).
-export([start/2, stop/1, prep_stop/1]).
-export([start_apps/1, stop_apps/1]).
--export([log_location/1, config_files/0]). %% for testing and mgmt-agent
+-export([log_location/1, config_files/0, decrypt_config/2]). %% for testing and mgmt-agent
%%---------------------------------------------------------------------------
%% Boot steps.
@@ -449,6 +449,38 @@ stop_and_halt() ->
start_apps(Apps) ->
app_utils:load_applications(Apps),
+
+ ConfigEntryDecoder = case application:get_env(rabbit, config_entry_decoder) of
+ undefined ->
+ [];
+ {ok, Val} ->
+ Val
+ end,
+ PassPhrase = case proplists:get_value(passphrase, ConfigEntryDecoder) of
+ prompt ->
+ IoDevice = get_input_iodevice(),
+ io:setopts(IoDevice, [{echo, false}]),
+ PP = lists:droplast(io:get_line(IoDevice,
+ "\nPlease enter the passphrase to unlock encrypted "
+ "configuration entries.\n\nPassphrase: ")),
+ io:setopts(IoDevice, [{echo, true}]),
+ io:format(IoDevice, "~n", []),
+ PP;
+ {file, Filename} ->
+ {ok, File} = file:read_file(Filename),
+ [PP|_] = binary:split(File, [<<"\r\n">>, <<"\n">>]),
+ PP;
+ PP ->
+ PP
+ end,
+ Algo = {
+ proplists:get_value(cipher, ConfigEntryDecoder, rabbit_pbe:default_cipher()),
+ proplists:get_value(hash, ConfigEntryDecoder, rabbit_pbe:default_hash()),
+ proplists:get_value(iterations, ConfigEntryDecoder, rabbit_pbe:default_iterations()),
+ PassPhrase
+ },
+ decrypt_config(Apps, Algo),
+
OrderedApps = app_utils:app_dependency_order(Apps, false),
case lists:member(rabbit, Apps) of
false -> rabbit_boot_steps:run_boot_steps(Apps); %% plugin activation
@@ -457,6 +489,78 @@ start_apps(Apps) ->
ok = app_utils:start_applications(OrderedApps,
handle_app_error(could_not_start)).
+%% This function retrieves the correct IoDevice for requesting
+%% input. The problem with using the default IoDevice is that
+%% the Erlang shell prevents us from getting the input.
+%%
+%% Instead we therefore look for the io process used by the
+%% shell and if it can't be found (because the shell is not
+%% started e.g with -noshell) we use the 'user' process.
+%%
+%% This function will not work when either -oldshell or -noinput
+%% options are passed to erl.
+get_input_iodevice() ->
+ case whereis(user) of
+ undefined -> user;
+ User ->
+ case group:interfaces(User) of
+ [] ->
+ user;
+ [{user_drv, Drv}] ->
+ case user_drv:interfaces(Drv) of
+ [] ->
+ user;
+ [{current_group, IoDevice}] ->
+ IoDevice
+ end
+ end
+ end.
+
+decrypt_config([], _) ->
+ ok;
+decrypt_config([App|Apps], Algo) ->
+ decrypt_app(App, application:get_all_env(App), Algo),
+ decrypt_config(Apps, Algo).
+
+decrypt_app(_, [], _) ->
+ ok;
+decrypt_app(App, [{Key, Value}|Tail], Algo) ->
+ try begin
+ case decrypt(Value, Algo) of
+ Value ->
+ ok;
+ NewValue ->
+ application:set_env(App, Key, NewValue)
+ end
+ end
+ catch
+ exit:{bad_configuration, config_entry_decoder} ->
+ exit({bad_configuration, config_entry_decoder});
+ _:Msg ->
+ rabbit_log:info("Error while decrypting key '~p'. Please check encrypted value, passphrase, and encryption configuration~n", [Key]),
+ exit({decryption_error, {key, Key}, Msg})
+ end,
+ decrypt_app(App, Tail, Algo).
+
+decrypt({encrypted, _}, {_, _, _, undefined}) ->
+ exit({bad_configuration, config_entry_decoder});
+decrypt({encrypted, EncValue}, {Cipher, Hash, Iterations, Password}) ->
+ rabbit_pbe:decrypt_term(Cipher, Hash, Iterations, Password, EncValue);
+decrypt(List, Algo) when is_list(List) ->
+ decrypt_list(List, Algo, []);
+decrypt(Value, _) ->
+ Value.
+
+%% We make no distinction between strings and other lists.
+%% When we receive a string, we loop through each element
+%% and ultimately return the string unmodified, as intended.
+decrypt_list([], _, Acc) ->
+ lists:reverse(Acc);
+decrypt_list([{Key, Value}|Tail], Algo, Acc) when Key =/= encrypted ->
+ decrypt_list(Tail, Algo, [{Key, decrypt(Value, Algo)}|Acc]);
+decrypt_list([Value|Tail], Algo, Acc) ->
+ decrypt_list(Tail, Algo, [decrypt(Value, Algo)|Acc]).
+
stop_apps(Apps) ->
ok = app_utils:stop_applications(
Apps, handle_app_error(error_during_shutdown)),