2424 start_fhc /0 ]).
2525-export ([start /2 , stop /1 , prep_stop /1 ]).
2626-export ([start_apps /1 , stop_apps /1 ]).
27- -export ([log_location /1 , config_files /0 ]). % % for testing and mgmt-agent
27+ -export ([log_location /1 , config_files /0 , decrypt_config / 2 ]). % % for testing and mgmt-agent
2828
2929% %---------------------------------------------------------------------------
3030% % Boot steps.
@@ -442,6 +442,38 @@ stop_and_halt() ->
442442
443443start_apps (Apps ) ->
444444 app_utils :load_applications (Apps ),
445+
446+ DecoderConfig = case application :get_env (rabbit , decoder_config ) of
447+ undefined ->
448+ [];
449+ {ok , Val } ->
450+ Val
451+ end ,
452+ PassPhrase = case proplists :get_value (passphrase , DecoderConfig ) of
453+ prompt ->
454+ IoDevice = get_input_iodevice (),
455+ io :setopts (IoDevice , [{echo , false }]),
456+ PP = lists :droplast (io :get_line (IoDevice ,
457+ " \n Please enter the passphrase to unlock encrypted "
458+ " configuration entries.\n\n Passphrase: " )),
459+ io :setopts (IoDevice , [{echo , true }]),
460+ io :format (IoDevice , " ~n " , []),
461+ PP ;
462+ {file , Filename } ->
463+ {ok , File } = file :read_file (Filename ),
464+ [PP |_ ] = binary :split (File , [<<" \r\n " >>, <<" \n " >>]),
465+ PP ;
466+ PP ->
467+ PP
468+ end ,
469+ Algo = {
470+ proplists :get_value (cipher , DecoderConfig , rabbit_pbe :default_cipher ()),
471+ proplists :get_value (hash , DecoderConfig , rabbit_pbe :default_hash ()),
472+ proplists :get_value (iterations , DecoderConfig , rabbit_pbe :default_iterations ()),
473+ PassPhrase
474+ },
475+ decrypt_config (Apps , Algo ),
476+
445477 OrderedApps = app_utils :app_dependency_order (Apps , false ),
446478 case lists :member (rabbit , Apps ) of
447479 false -> rabbit_boot_steps :run_boot_steps (Apps ); % % plugin activation
@@ -450,6 +482,78 @@ start_apps(Apps) ->
450482 ok = app_utils :start_applications (OrderedApps ,
451483 handle_app_error (could_not_start )).
452484
485+ % % This function retrieves the correct IoDevice for requesting
486+ % % input. The problem with using the default IoDevice is that
487+ % % the Erlang shell prevents us from getting the input.
488+ % %
489+ % % Instead we therefore look for the io process used by the
490+ % % shell and if it can't be found (because the shell is not
491+ % % started e.g with -noshell) we use the 'user' process.
492+ % %
493+ % % This function will not work when either -oldshell or -noinput
494+ % % options are passed to erl.
495+ get_input_iodevice () ->
496+ case whereis (user ) of
497+ undefined -> user ;
498+ User ->
499+ case group :interfaces (User ) of
500+ [] ->
501+ user ;
502+ [{user_drv , Drv }] ->
503+ case user_drv :interfaces (Drv ) of
504+ [] ->
505+ user ;
506+ [{current_group , IoDevice }] ->
507+ IoDevice
508+ end
509+ end
510+ end .
511+
512+ decrypt_config ([], _ ) ->
513+ ok ;
514+ decrypt_config ([App |Apps ], Algo ) ->
515+ decrypt_app (App , application :get_all_env (App ), Algo ),
516+ decrypt_config (Apps , Algo ).
517+
518+ decrypt_app (_ , [], _ ) ->
519+ ok ;
520+ decrypt_app (App , [{Key , Value }|Tail ], Algo ) ->
521+ try begin
522+ case decrypt (Value , Algo ) of
523+ Value ->
524+ ok ;
525+ NewValue ->
526+ application :set_env (App , Key , NewValue )
527+ end
528+ end
529+ catch
530+ exit :{bad_configuration , decoder_config } ->
531+ exit ({bad_configuration , decoder_config });
532+ _ :Msg ->
533+ rabbit_log :info (" Error while decrypting key '~p '. Please check encrypted value, passphrase, and encryption configuration~n " , [Key ]),
534+ exit ({decryption_error , {key , Key }, Msg })
535+ end ,
536+ decrypt_app (App , Tail , Algo ).
537+
538+ decrypt ({encrypted , _ }, {_ , _ , _ , undefined }) ->
539+ exit ({bad_configuration , decoder_config });
540+ decrypt ({encrypted , EncValue }, {Cipher , Hash , Iterations , Password }) ->
541+ rabbit_pbe :decrypt_term (Cipher , Hash , Iterations , Password , EncValue );
542+ decrypt (List , Algo ) when is_list (List ) ->
543+ decrypt_list (List , Algo , []);
544+ decrypt (Value , _ ) ->
545+ Value .
546+
547+ % % We make no distinction between strings and other lists.
548+ % % When we receive a string, we loop through each element
549+ % % and ultimately return the string unmodified, as intended.
550+ decrypt_list ([], _ , Acc ) ->
551+ lists :reverse (Acc );
552+ decrypt_list ([{Key , Value }|Tail ], Algo , Acc ) when Key =/= encrypted ->
553+ decrypt_list (Tail , Algo , [{Key , decrypt (Value , Algo )}|Acc ]);
554+ decrypt_list ([Value |Tail ], Algo , Acc ) ->
555+ decrypt_list (Tail , Algo , [decrypt (Value , Algo )|Acc ]).
556+
453557stop_apps (Apps ) ->
454558 ok = app_utils :stop_applications (
455559 Apps , handle_app_error (error_during_shutdown )),
0 commit comments