diff --git a/WebminCore.pm b/WebminCore.pm index 00a373a91..560659706 100644 --- a/WebminCore.pm +++ b/WebminCore.pm @@ -20,7 +20,7 @@ require Exporter; # Add functions in web-lib-funcs.pl # Generated with : # grep -h "^sub " web-lib-funcs.pl ui-lib.pl | sed -e 's/sub //' | xargs echo -@EXPORT = qw(read_file read_file_cached read_file_cached_with_stat write_file html_escape html_strip quote_escape quote_javascript tempname_dir tempname transname transname_timestamped trunc indexof indexoflc sysprint check_ipaddress check_ip6address generate_icon urlize un_urlize include copydata ReadParseMime ReadParse read_fully read_parse_mime_callback read_parse_mime_javascript PrintHeader header get_html_title get_html_framed_title get_html_status_line popup_header footer popup_footer load_module_preferences load_theme_library redirect kill_byname kill_byname_logged find_byname error popup_error register_error_handler call_error_handlers error_setup wait_for fast_wait_for has_command make_date file_chooser_button popup_window_button popup_window_link read_acl acl_filename acl_check get_miniserv_config_file get_miniserv_config put_miniserv_config restart_miniserv reload_miniserv check_os_support http_download complete_http_download http_post ftp_download ftp_upload no_proxy open_socket download_timeout ftp_command to_ipaddress to_ip6address to_hostname icons_table replace_meta replace_file_line read_file_lines flush_file_lines unflush_file_lines unix_user_input unix_group_input hlink user_chooser_button group_chooser_button foreign_check foreign_exists foreign_func_exists foreign_available foreign_require foreign_call foreign_config foreign_installed foreign_defined get_system_hostname get_webmin_version get_webmin_version_release get_module_acl get_group_module_acl save_module_acl save_group_module_acl init_config load_language_auto load_language text_subs text encode_base64 decode_base64 encode_base32 decode_base32 get_module_info get_all_module_infos list_themes get_theme_info list_languages safe_language read_env_file write_env_file lock_file unlock_file test_lock unlock_all_files can_lock_file webmin_log additional_log var_dump webmin_debug_log system_logged backquote_logged backquote_with_timeout backquote_command kill_logged rename_logged rename_file symlink_logged symlink_file link_file make_dir set_ownership_permissions unlink_logged unlink_file copy_source_dest move_source_dest remote_session_name remote_foreign_require remote_foreign_call remote_foreign_check remote_foreign_config remote_eval remote_write remote_read remote_finished remote_error_setup remote_rpc_call remote_multi_callback remote_multi_callback_error serialise_variable unserialise_variable other_groups date_chooser_button help_file seed_random disk_usage_kb recursive_disk_usage help_search_link make_http_connection validate_ssl_connection read_http_connection write_http_connection close_http_connection clean_environment reset_environment clean_language progress_callback switch_to_remote_user switch_to_unix_user eval_as_unix_user create_user_config_dirs create_missing_homedir filter_javascript resolve_links simplify_path same_file flush_webmin_caches list_usermods available_usermods get_available_module_infos get_visible_module_infos get_visible_modules_categories is_under_directory parse_http_url check_clicks_function load_entities_map entities_to_ascii get_product_name get_charset get_display_hostname save_module_config save_user_module_config nice_size get_perl_path get_goto_module select_all_link select_invert_link select_rows_link check_pid_file get_mod_lib module_root_directory list_mime_types guess_mime_type open_tempfile close_tempfile print_tempfile is_selinux_enabled get_clear_file_attributes reset_file_attributes cleanup_tempnames open_lock_tempfile END month_to_number number_to_month get_rbac_module_acl supports_rbac supports_ipv6 use_rbac_module_acl execute_command open_readfile open_execute_command translate_filename translate_command register_filename_callback register_command_callback capture_function_output capture_function_output_tempfile modules_chooser_button substitute_template substitute_pattern running_in_zone running_in_vserver running_in_xen running_in_openvz list_categories is_readonly_mode command_as_user list_osdn_mirrors convert_osdn_url get_current_dir supports_users supports_symlinks quote_path get_windows_root read_file_contents write_file_contents read_file_contents_limit unix_crypt split_quoted_string write_to_http_cache check_in_http_cache supports_javascript get_module_name get_module_variable clear_time_locale reset_time_locale callers_package web_libs_package get_userdb_string connect_userdb disconnect_userdb split_userdb_string uniquelc list_combined_webmin_menu list_modules_webmin_menu module_to_menu_item list_combined_system_info shell_is_bash compare_version_numbers convert_to_json convert_from_json print_json get_referer_relative get_webmin_email_url get_webmin_browser_url trim ui_link ui_help ui_img ui_link_button ui_table_start ui_table_end ui_table_row ui_table_hr ui_table_span ui_columns_start ui_columns_row ui_columns_header ui_checked_columns_row ui_radio_columns_row ui_columns_end ui_columns_table ui_form_columns_table ui_form_start ui_form_end ui_textbox ui_filebox ui_bytesbox ui_upload ui_password ui_hidden ui_select ui_multi_select ui_multi_select_javascript ui_radio ui_yesno_radio ui_checkbox ui_oneradio ui_textarea ui_user_textbox ui_users_textbox ui_group_textbox ui_groups_textbox ui_opt_textbox ui_submit ui_reset ui_button ui_date_input ui_buttons_start ui_buttons_end ui_buttons_row ui_buttons_hr ui_post_header ui_pre_footer ui_print_header ui_print_unbuffered_header ui_print_footer ui_config_link ui_print_endpage ui_subheading ui_links_row ui_hidden_javascript ui_hidden_start ui_hidden_end ui_hidden_table_row_start ui_hidden_table_row_end ui_hidden_table_start ui_hidden_table_end ui_tabs_start ui_tabs_end ui_tabs_start_tab ui_tabs_start_tabletab ui_tabs_end_tab ui_tabs_end_tabletab ui_max_text_width ui_radio_selector ui_radio_selector_javascript ui_grid_table ui_radio_table ui_up_down_arrows ui_hr ui_nav_link ui_confirmation_form ui_text_color ui_alert_box js_disable_inputs ui_page_flipper js_checkbox_disable js_redirect ui_webmin_link ui_line_break_double ui_details ui_read_file_contents_limit get_python_cmd get_buffer_size get_webprefix get_sub_ref_name setvar getvar delvar print_call_stack webmin_user_can_rpc webmin_user_login_mode webmin_user_is_admin webmin_user_is get_current_theme_info_cached); +@EXPORT = qw(read_file read_file_cached read_file_cached_with_stat write_file html_escape html_strip quote_escape quote_javascript tempname_dir tempname transname transname_timestamped trunc indexof indexoflc sysprint check_ipaddress check_ip6address generate_icon urlize un_urlize include copydata ReadParseMime ReadParse read_fully read_parse_mime_callback read_parse_mime_javascript PrintHeader header get_html_title get_html_framed_title get_html_status_line popup_header footer popup_footer load_module_preferences load_theme_library redirect kill_byname kill_byname_logged find_byname error popup_error register_error_handler call_error_handlers error_setup wait_for fast_wait_for has_command make_date file_chooser_button popup_window_button popup_window_link read_acl acl_filename acl_check get_miniserv_config_file get_miniserv_config put_miniserv_config restart_miniserv reload_miniserv miniserv_systemd_sig check_os_support http_download complete_http_download http_post ftp_download ftp_upload no_proxy open_socket download_timeout ftp_command to_ipaddress to_ip6address to_hostname icons_table replace_meta replace_file_line read_file_lines flush_file_lines unflush_file_lines unix_user_input unix_group_input hlink user_chooser_button group_chooser_button foreign_check foreign_exists foreign_func_exists foreign_available foreign_require foreign_call foreign_config foreign_installed foreign_defined get_system_hostname get_webmin_version get_webmin_version_release get_module_acl get_group_module_acl save_module_acl save_group_module_acl init_config load_language_auto load_language text_subs text encode_base64 decode_base64 encode_base32 decode_base32 get_module_info get_all_module_infos list_themes get_theme_info list_languages safe_language read_env_file write_env_file lock_file unlock_file test_lock unlock_all_files can_lock_file webmin_log additional_log var_dump webmin_debug_log system_logged backquote_logged backquote_with_timeout backquote_command kill_logged rename_logged rename_file symlink_logged symlink_file link_file make_dir set_ownership_permissions unlink_logged unlink_file copy_source_dest move_source_dest remote_session_name remote_foreign_require remote_foreign_call remote_foreign_check remote_foreign_config remote_eval remote_write remote_read remote_finished remote_error_setup remote_rpc_call remote_multi_callback remote_multi_callback_error serialise_variable unserialise_variable other_groups date_chooser_button help_file seed_random disk_usage_kb recursive_disk_usage help_search_link make_http_connection validate_ssl_connection read_http_connection write_http_connection close_http_connection clean_environment reset_environment clean_language progress_callback switch_to_remote_user switch_to_unix_user eval_as_unix_user create_user_config_dirs create_missing_homedir filter_javascript resolve_links simplify_path same_file flush_webmin_caches list_usermods available_usermods get_available_module_infos get_visible_module_infos get_visible_modules_categories is_under_directory parse_http_url check_clicks_function load_entities_map entities_to_ascii get_product_name get_charset get_display_hostname save_module_config save_user_module_config nice_size get_perl_path get_goto_module select_all_link select_invert_link select_rows_link check_pid_file get_mod_lib module_root_directory list_mime_types guess_mime_type open_tempfile close_tempfile print_tempfile is_selinux_enabled get_clear_file_attributes reset_file_attributes cleanup_tempnames open_lock_tempfile END month_to_number number_to_month get_rbac_module_acl supports_rbac supports_ipv6 use_rbac_module_acl execute_command open_readfile open_execute_command translate_filename translate_command register_filename_callback register_command_callback capture_function_output capture_function_output_tempfile modules_chooser_button substitute_template substitute_pattern running_in_zone running_in_vserver running_in_xen running_in_openvz list_categories is_readonly_mode command_as_user list_osdn_mirrors convert_osdn_url get_current_dir supports_users supports_symlinks quote_path get_windows_root read_file_contents write_file_contents read_file_contents_limit unix_crypt split_quoted_string write_to_http_cache check_in_http_cache supports_javascript get_module_name get_module_variable clear_time_locale reset_time_locale callers_package web_libs_package get_userdb_string connect_userdb disconnect_userdb split_userdb_string uniquelc list_combined_webmin_menu list_modules_webmin_menu module_to_menu_item list_combined_system_info shell_is_bash compare_version_numbers convert_to_json convert_from_json print_json get_referer_relative get_webmin_email_url get_webmin_browser_url trim ui_link ui_help ui_img ui_link_button ui_table_start ui_table_end ui_table_row ui_table_hr ui_table_span ui_columns_start ui_columns_row ui_columns_header ui_checked_columns_row ui_radio_columns_row ui_columns_end ui_columns_table ui_form_columns_table ui_form_start ui_form_end ui_textbox ui_filebox ui_bytesbox ui_upload ui_password ui_hidden ui_select ui_multi_select ui_multi_select_javascript ui_radio ui_yesno_radio ui_checkbox ui_oneradio ui_textarea ui_user_textbox ui_users_textbox ui_group_textbox ui_groups_textbox ui_opt_textbox ui_submit ui_reset ui_button ui_date_input ui_buttons_start ui_buttons_end ui_buttons_row ui_buttons_hr ui_post_header ui_pre_footer ui_print_header ui_print_unbuffered_header ui_print_footer ui_config_link ui_print_endpage ui_subheading ui_links_row ui_hidden_javascript ui_hidden_start ui_hidden_end ui_hidden_table_row_start ui_hidden_table_row_end ui_hidden_table_start ui_hidden_table_end ui_tabs_start ui_tabs_end ui_tabs_start_tab ui_tabs_start_tabletab ui_tabs_end_tab ui_tabs_end_tabletab ui_max_text_width ui_radio_selector ui_radio_selector_javascript ui_grid_table ui_radio_table ui_up_down_arrows ui_hr ui_nav_link ui_confirmation_form ui_text_color ui_alert_box js_disable_inputs ui_page_flipper js_checkbox_disable js_redirect ui_webmin_link ui_line_break_double ui_details ui_read_file_contents_limit get_python_cmd get_buffer_size get_webprefix get_sub_ref_name setvar getvar delvar print_call_stack webmin_user_can_rpc webmin_user_login_mode webmin_user_is_admin webmin_user_is get_current_theme_info_cached); # Add global variables in web-lib.pl push(@EXPORT, qw(&unique)); diff --git a/bin/disable-proxy b/bin/disable-proxy index e5ec41c51..694733404 100755 --- a/bin/disable-proxy +++ b/bin/disable-proxy @@ -129,7 +129,7 @@ Disable proxy-related features in Webmin. =head1 SYNOPSIS -disable-proxy [options] +webmin disable-proxy [options] =head1 OPTIONS @@ -146,14 +146,8 @@ C =back -=head1 EXIT CODES - -0 on success - -non-0 on error - =head1 LICENSE AND COPYRIGHT -Copyright 2018 Jamie Cameron , Joe Cooper -. + Copyright 2022 Jamie Cameron + Joe Cooper diff --git a/bin/disable-twofactor b/bin/disable-twofactor index 36c74203f..ba2d52aa3 100755 --- a/bin/disable-twofactor +++ b/bin/disable-twofactor @@ -87,7 +87,7 @@ second factor (e.g. phone or USB key) has been lost. =head1 SYNOPSIS -disable-twofactor --user username +webmin disable-twofactor --user username =head1 OPTIONS @@ -106,16 +106,13 @@ C Name of the user to disable two-factor authentication for. + + =back -=head1 EXIT CODES - -0 on successfully replacing configuration options - -non-0 on error - =head1 LICENSE AND COPYRIGHT -Copyright 2018 Jamie Cameron , Joe Cooper -. + Copyright 2022 Jamie Cameron + Joe Cooper + Ilia Rostovtsev diff --git a/bin/enable-proxy b/bin/enable-proxy index 15eb5856c..97bf86730 100755 --- a/bin/enable-proxy +++ b/bin/enable-proxy @@ -134,7 +134,7 @@ Configure the Webmin web server to be proxied through another web server, like A =head1 SYNOPSIS -enable-proxy [options] +webmin enable-proxy [options] =head1 OPTIONS @@ -161,14 +161,7 @@ domain.tld) =back -=head1 EXIT CODES - -0 on success - -non-0 on error - =head1 LICENSE AND COPYRIGHT -Copyright 2018 Jamie Cameron , Joe Cooper -. - + Copyright 2022 Jamie Cameron + Joe Cooper diff --git a/bin/language-manager b/bin/language-manager index edcfba14d..889e3550d 100755 --- a/bin/language-manager +++ b/bin/language-manager @@ -1784,7 +1784,7 @@ Manage Webmin/Usermin module language files (lang|ulang|help|config|uconfig|modu =head1 SYNOPSIS -language-manager [options] +webmin language-manager [options] =head1 OPTIONS @@ -1798,35 +1798,35 @@ Examples of usage: Synchronize all language keys for Apache module, based on template language. Newly added entries to Apache template language file (def. en), will be translated and inserted into all other machine translated language files, while deleted entries will also be removed on all targets (translations), including human translated files. The value for "defines_desc" will be force re-translated and translation will be done in HTML format. - - language-manager -m=apache -kft=defines_desc -kfh=defines_desc + - webmin language-manager -m=apache -kft=defines_desc -kfh=defines_desc Synchronize all modules' "help/" language files. Newly added files will be translated and already translated, both human and machine translations, will be kept intact. - - language-manager -w=help + - webmin language-manager -w=help Check for Software Packages module, all matching escaped HTML "<" and ">" entities in template file (def. en), and if found, make sure that translations (including machine translations) for the same key, contain exact escaped HTML entities, as on template string, rather than "<" or ">". Technically, it's possible to check and replace anything on language files using this command. - - language-manager -vf="<:<,>:>" -m=software + - webmin language-manager -vf="<:<,>:>" -m=software Translate all available languages, using old-time encoding map, for BIND module, using as type "lang" directory, discarding human translations for Hebrew, keeping original value (not translating) for key "mass_desc", and printing verbose output. - - language-manager -x=full -e=map -m=bind8 -w=lang -se=he -ke=mass_desc + - webmin language-manager -x=full -e=map -m=bind8 -w=lang -se=he -ke=mass_desc Transcode only and rename all modules' "help/" old-time format files. Old files, such as "ja_JP.euc.html", "ko_KR.euc.html", "zh_TW.Big5.html" and "ru_RU.html" will be automatically renamed and/or deleted. - - language-manager -w=help -e=map -ot + - webmin language-manager -w=help -e=map -ot Only transcode language files, using old-time encoding map, from files being in different encodings, to new style, where all language files are in "utf-8" encoding, for Apache module. No translations will be made, and no ".auto" files will be created. - - language-manager -x=full -e=map -m=apache -ot + - webmin language-manager -x=full -e=map -m=apache -ot Repare human translated language files, which stored in "utf-8" encoding already but still have HTML entities. - - language-manager -m=virtual-server -t=no,es -x=transcode + - webmin language-manager -m=virtual-server -t=no,es -x=transcode Test translations for "index_stopmsg,trusted_warning" keys, in Russian and German languages, in BIND module, print on-screen results and exit. - - language-manager -m=bind8 -t=ru,de -kt=index_stopmsg,trusted_warning + - webmin language-manager -m=bind8 -t=ru,de -kt=index_stopmsg,trusted_warning =item --mode, -x diff --git a/bin/list-config b/bin/list-config index 2ea53e27a..30bb57976 100755 --- a/bin/list-config +++ b/bin/list-config @@ -165,7 +165,7 @@ List one or all configuration directives for C or a module C file, instead of it's current value. This option is only available for modules, as miniserv.conf does not have a config.info. + + =back -=head1 EXIT CODES - -0 on success - -non-0 on error - =head1 LICENSE AND COPYRIGHT -Copyright 2018 Jamie Cameron , Joe Cooper -. - + Copyright 2022 Jamie Cameron + Joe Cooper diff --git a/bin/passwd b/bin/passwd index 0987af922..cc966e916 100755 --- a/bin/passwd +++ b/bin/passwd @@ -18,7 +18,8 @@ sub main GetOptions('help|h' => \$opt{'help'}, 'config|c=s' => \$opt{'config'}, 'user|u=s' => \$opt{'user'}, - 'password|p=s' => \$opt{'password'}); + 'password|p=s' => \$opt{'password'}, + 'stdout|o!' => \$opt{'stdout'}); # If username passed as regular param my $user = scalar(@ARGV) == 1 && $ARGV[0]; @@ -71,8 +72,9 @@ sub change_password my $root = root($confdif, \&$conf_check); # Use pre-defined encryption (forced by Webmin config) - if ($gconfig->{'md5pass'} == 1 || - $gconfig->{'md5pass'} == 2) + if (!$optref->{'stdout'} && + ($gconfig->{'md5pass'} == 1 || + $gconfig->{'md5pass'} == 2)) { do "$root/acl/md5-lib.pl"; @@ -160,6 +162,12 @@ sub change_password # Update with new password and store timestamp $uinfos{$user}->[0] = &$encrypt_password($pass, \%gconfig, \%config); + + # Print the hash and exit + if ($optref->{'stdout'}) { + say $uinfos{$user}->[0]; + exit 0; + } $uinfos{$user}->[5] = time() if ($uinfos{$user}->[5]); map {$ulines{$_} = join(":", @{ $uinfos{$_} })} keys %uinfos; @@ -209,15 +217,15 @@ sub root =head1 NAME -passwd + passwd =head1 DESCRIPTION -This program allows you to change the password of a user in the Webmin password file + This program allows you to change the password of a user in the Webmin password file =head1 SYNOPSIS -passwd [options] + webmin passwd [options] =head1 OPTIONS @@ -225,37 +233,32 @@ passwd [options] =item --help, -h -Print this usage summary and exit. + Print this usage summary and exit. -Examples of usage: - - - passwd root - - - passwd --user root - - - passwd --user root --password ycwyMQRVAZY - - - passwd --config /usr/local/etc/webmin --user root --password ycwyMQRVAZY + Examples of usage: + - webmin passwd root + - webmin passwd --user root + - webmin passwd --user root --password ycwyMQRVAZY + - webmin passwd --config /usr/local/etc/webmin --user root --password ycwyMQRVAZY + - webmin passwd --config /usr/local/etc/webmin --user root --password ycwyMQRVAZY --stdout =item --config, -c -Specify the full path to the Webmin configuration directory. Defaults to C + Specify the full path to the Webmin configuration directory. Defaults to C =item --user, -u -Existing Webmin user to change password for + Existing Webmin user to change password for =item --password, -p Set new user password. Using this option may be unsecure. - - =back =head1 LICENSE AND COPYRIGHT -Copyright 2021 Jamie Cameron - Joe Cooper - Ilia Rostovtsev + Copyright 2022 Jamie Cameron + Joe Cooper + Ilia Rostovtsev diff --git a/bin/server b/bin/server new file mode 100755 index 000000000..89d7ea55b --- /dev/null +++ b/bin/server @@ -0,0 +1,183 @@ +#!/usr/bin/env perl +# server - control Webmin web-server + +use strict; +use warnings; +use 5.010; + +use File::Basename; +use Getopt::Long; +use Pod::Usage; +use Term::ANSIColor qw(:constants); +use lib (dirname(dirname($0))); +use WebminCore; + +sub main +{ + my %opt; + GetOptions('help|h' => \$opt{'help'}, + 'command|x=s' => \$opt{'command'}, + 'config|c=s' => \$opt{'config'}); + + # If username passed as regular param + my $cmd = scalar(@ARGV) == 1 && $ARGV[0]; + $cmd = $opt{'command'} if ($opt{'command'}); + if ($cmd !~ /^(status|start|stop|restart|reload|force-restart|force-reload|kill)$/) { + $cmd = undef; + } + + # Show usage + pod2usage(0) if ($opt{'help'} || !$cmd); + + # Assign defaults + $opt{'config'} ||= "/etc/webmin"; + $opt{'cmd'} = $cmd; + + # Catch kill signal + my $sigkill = sub { + system("stty echo"); + print "\n^C"; + print "\n"; + exit 1; + }; + $SIG{INT} = \&$sigkill; + + # Run change password command + run(\%opt); + + return 0; +} +exit main(\@ARGV) if !caller(0); + +sub run +{ + my ($o) = @_; + my $conf_check = sub { + my ($configs) = @_; + foreach my $config (@{$configs}) { + if (!-r $config) { + say BRIGHT_RED, "Error: ", RESET, "Failed to read Webmin essential config file: ", BRIGHT_YELLOW, $config, + RESET, " doesn't exist"; + exit 1; + } + } + }; + root($o->{'config'}, \&$conf_check); + my $service = ($o->{'config'} =~ /usermin/ ? 'usermin' : 'webmin'); + my $systemctlcmd = `which systemctl`; + $systemctlcmd =~ s/\s+$//; + if ($o->{'cmd'} =~ /^(start|stop|restart|reload)$/) { + my $rs = system("$o->{'config'}/$o->{'cmd'} $service"); + exit $rs; + } + if ($o->{'cmd'} =~ /^(kill|force-kill)$/) { + my $rs; + if (-x $systemctlcmd) { + $rs = system("$systemctlcmd stop $service"); + $rs = system("$systemctlcmd kill -s SIGTERM $service"); + } + $rs = system("$o->{'config'}/.stop-init --kill >/dev/null 2>&1 $service"); + exit $rs; + } + if ($o->{'cmd'} =~ /^(force-reload|force-restart)$/) { + my $rs = system("$o->{'config'}/restart-by-force-kill $service"); + exit $rs; + } + if ($o->{'cmd'} =~ /^(status)$/) { + my $rs; + if (-x $systemctlcmd) { + $rs = system("$systemctlcmd status $service"); + } else { + $rs = system("service $service status"); + } + exit $rs; + } + exit 0; +} + +sub root +{ + my ($config, $conf_check) = @_; + my $mconf = "$config/miniserv.conf"; + $conf_check->([$mconf]); + open(my $CONF, "<", $mconf); + my $root; + while (<$CONF>) { + if (/^root=(.*)/) { + $root = $1; + } + } + close($CONF); + + # Does the Webmin root exist? + if ($root) { + die BRIGHT_RED, "Error: ", BRIGHT_YELLOW, $root, RESET, " is not a directory\n" unless (-d $root); + } else { + + # Try to guess where Webmin lives, since config file didn't know. + die BRIGHT_RED, "Error: ", RESET, "Unable to determine Webmin installation directory\n"; + } + + return $root; +} + +1; + +=pod + +=head1 NAME + + server + +=head1 DESCRIPTION + + This program allows you to control Webmin web-server + +=head1 SYNOPSIS + + webmin server [command] + webmin [command] + +=head1 OPTIONS + +=over + +=item --help, -h + + Print this usage summary and exit. + + Examples of usage: + - webmin server status + - webmin server restart + - webmin server --config /usr/local/etc/webmin --command start + - webmin status + - webmin restart + +=item --config, -c + + Specify the full path to the Webmin configuration directory. Defaults to C + +=item --command, -x + + Available commands: + - status + - start + - stop + - restart + - reload + - force-restart + - force-reload + - kill + + Alias commands: + - force-restart | force-reload + - kill | force-kill + +=back + +=head1 LICENSE AND COPYRIGHT + + Copyright 2022 Jamie Cameron + Joe Cooper + Ilia Rostovtsev + diff --git a/bin/set-config b/bin/set-config index 83bd2fe23..1106a2902 100755 --- a/bin/set-config +++ b/bin/set-config @@ -136,7 +136,7 @@ Set a configuration directive in either C (the core Webmin config =head1 SYNOPSIS -set-config [options] [--module] --option --value +webmin set-config [options] [--module] --option --value =head1 OPTIONS @@ -180,6 +180,5 @@ already exist in the file, and was added) =head1 LICENSE AND COPYRIGHT -Copyright 2018 Jamie Cameron , Joe Cooper -. - + Copyright 2022 Jamie Cameron + Joe Cooper diff --git a/bin/webmin b/bin/webmin index 9ccb797f8..99d86c26d 100755 --- a/bin/webmin +++ b/bin/webmin @@ -12,6 +12,8 @@ use Term::ANSIColor qw(:constants); use File::Spec; use File::Basename; +my $a0 = $ARGV[0]; + sub main { my ( %opt, $subcmd ); GetOptions( @@ -37,6 +39,7 @@ sub main { ); $opt{'config'} ||= "/etc/webmin"; + $opt{'commands'} = $a0; my @remain = @ARGV; # List commands? @@ -203,7 +206,7 @@ sub run_command { exit 1; } - my $command_path = get_command_path($root, $subcmd); + my $command_path = get_command_path($root, $subcmd, $optref); # Merge the options # Only handling config, right now... @@ -223,7 +226,7 @@ sub run_command { } sub get_command_path { - my ($root, $subcmd) = @_; + my ($root, $subcmd, $optref) = @_; # Check for a root-level command (in "$root/bin") my $command_path; if ($subcmd) { @@ -256,11 +259,13 @@ sub get_command_path { } } } - - if ($command) { + if ($optref->{'commands'} && + $optref->{'commands'} =~ /^(status|start|stop|restart|reload|force-restart|force-reload|kill)$/) { + exit system("$0 server $optref->{'commands'}"); + } elsif ($command) { return $command; } else { - die RED, "Unrecognized subcommand: $subcmd", RESET; + die RED, "Unrecognized subcommand: $subcmd", RESET , "\n"; } } @@ -325,7 +330,7 @@ sub man_command { my ($optref, $subcmd) = @_; my $root = root($optref->{'config'}); - my $command_path = get_command_path($root, $subcmd); + my $command_path = get_command_path($root, $subcmd, $optref); $ENV{'PAGER'} ||= "more"; open(my $PAGER, "|-", "$ENV{'PAGER'}"); @@ -341,7 +346,7 @@ sub man_command { sub root { my ($config) = @_; open(my $CONF, "<", "$config/miniserv.conf") || die RED, - "Failed to open $config/miniserv.conf", RESET; + "Failed to open $config/miniserv.conf", RESET , "\n"; my $root; while (<$CONF>) { if (/^root=(.*)/) { @@ -351,9 +356,9 @@ sub root { close($CONF); # Does the Webmin root exist? if ( $root ) { - die "$root is not a directory. Is --config correct?" unless (-d $root); + die "$root is not a directory. Is --config correct?\n" unless (-d $root); } else { - die "Unable to determine Webmin installation directory from $ENV{'WEBMIN_CONFIG'}"; + die "Unable to determine Webmin installation directory from $ENV{'WEBMIN_CONFIG'}\n"; } return $root; @@ -412,14 +417,11 @@ Returns Webmin and other modules and themes versions installed (only those for w =head1 EXIT CODES -0 on success - -non-0 on error +0 on success ; non-0 on error =head1 LICENSE AND COPYRIGHT -Copyright 2022 - Jamie Cameron , - Joe Cooper , - Ilia Rostovtsev . + Copyright 2022 Jamie Cameron + Joe Cooper + Ilia Rostovtsev diff --git a/dovecot/config-AlmaLinux-7.0-ALL b/dovecot/config-AlmaLinux-7.0-ALL new file mode 100644 index 000000000..bab7a35ec --- /dev/null +++ b/dovecot/config-AlmaLinux-7.0-ALL @@ -0,0 +1,4 @@ +dovecot=/usr/sbin/dovecot +dovecot_config=/etc/dovecot/dovecot.conf +init_script=dovecot.service +pid_file=/run/dovecot/master.pid diff --git a/dovecot/config-Rocky-Linux-7.0-ALL b/dovecot/config-Rocky-Linux-7.0-ALL new file mode 100644 index 000000000..bab7a35ec --- /dev/null +++ b/dovecot/config-Rocky-Linux-7.0-ALL @@ -0,0 +1,4 @@ +dovecot=/usr/sbin/dovecot +dovecot_config=/etc/dovecot/dovecot.conf +init_script=dovecot.service +pid_file=/run/dovecot/master.pid diff --git a/fail2ban/list_status.cgi b/fail2ban/list_status.cgi index fe79f66f7..9300ef125 100755 --- a/fail2ban/list_status.cgi +++ b/fail2ban/list_status.cgi @@ -13,7 +13,8 @@ my ($jail_list) = $out =~ /jail\s+list:\s*(.*)/im; my @jails = split(/,\s*/, $jail_list); if (@jails) { my $tdc = 'style="text-align: center;"'; - my $tal = 'style="text-align: left;"'; + my $tal = 'style="text-align: right; font-size: 96%;"'; + my $lwf = 'style="width: 100%; padding-right: 4px;"'; my @links = ( &select_all_link("jail"), &select_invert_link("jail") ); my $head; @@ -43,7 +44,7 @@ if (@jails) { my $jips; &open_execute_command($fh, $jcmd, 1); while(<$fh>) { - if (/-\s+(.*):\s*(.*)/) { + if (/-\s+(.*?):\s*(.*)/) { my $col = $1; my $val = $2; $col = lc($col); @@ -53,9 +54,9 @@ if (@jails) { if ($col =~ /banned_ip_list/) { $jips = $val; my @ips = split(/\s+/, $val); - @ips = map { "" } @ips; $val = "
" if ($val); $val .= join('
', @ips); $val = &$ipslimit($val); diff --git a/init/atboot.pl b/init/atboot.pl index 9fe2a0c53..97d091dc6 100755 --- a/init/atboot.pl +++ b/init/atboot.pl @@ -124,13 +124,18 @@ elsif ($init_mode eq "systemd") { &enable_at_boot( $product, "$ucproduct server daemon", - "$config_directory/.start-init", - "$config_directory/.stop-init", + "$root_directory/miniserv.pl $config_directory/miniserv.conf", + '/usr/bin/kill $MAINPID', undef, - { 'pidfile' => $var_directory."/miniserv.pid", - 'opts' => { - 'type' => 'forking', - 'killmode' => 'none' + { 'pidfile' => "$var_directory/miniserv.pid", + 'opts' => { + 'env' => '"PERLLIB=' . $root_directory . '"', + 'stop' => '/usr/bin/kill $MAINPID', + 'reload' => '/bin/bash -c \'/usr/bin/kill -HUP $MAINPID && while /usr/bin/kill -0 $MAINPID >/dev/null 2>&1 ; do /bin/sleep 0.5 ; done\'', + 'type' => 'forking', + 'restart' => 'always', + 'restartsec' => '2s', + 'timeout' => '15s', }}, ); } diff --git a/init/init-lib.pl b/init/init-lib.pl index 5f1fc34fb..f83243668 100755 --- a/init/init-lib.pl +++ b/init/init-lib.pl @@ -2343,6 +2343,8 @@ if (ref($opts)) { &print_tempfile(CFILE, "Group=$opts->{'group'}\n") if ($opts->{'group'}); &print_tempfile(CFILE, "KillMode=$opts->{'killmode'}\n") if ($opts->{'killmode'}); &print_tempfile(CFILE, "WorkingDirectory=$opts->{'workdir'}\n") if ($opts->{'workdir'}); + &print_tempfile(CFILE, "Restart=$opts->{'restart'}\n") if ($opts->{'restart'}); + &print_tempfile(CFILE, "RestartSec=$opts->{'restartsec'}\n") if ($opts->{'restartsec'}); &print_tempfile(CFILE, "TimeoutSec=$opts->{'timeout'}\n") if ($opts->{'timeout'}); &print_tempfile(CFILE, "StandardOutput=file:$opts->{'logstd'}\n") if ($opts->{'logstd'}); &print_tempfile(CFILE, "StandardError=file:$opts->{'logerr'}\n") if ($opts->{'logerr'}); @@ -2425,6 +2427,23 @@ if (-d $systemd_unit_dir1) { return $systemd_unit_dir2; } + +=head2 get_systemd_unit_pid([name]) + +Returns pid of running systemd unit +Returns 0 if unit stopped or missing + +=cut +sub get_systemd_unit_pid +{ +my ($unit) = @_; +my $pid = + &backquote_command("systemctl show --property MainPID @{[quotemeta($unit)]}"); +$pid =~ s/MainPID=(\d+)/$1/; +$pid = int($pid); +return $pid; +} + =head2 restart_systemd() Tell the systemd daemon to re-read its config diff --git a/init/updateboot.pl b/init/updateboot.pl index 41c699482..f5b50de56 100755 --- a/init/updateboot.pl +++ b/init/updateboot.pl @@ -24,7 +24,7 @@ if ($product) { ©_source_dest("$root_directory/webmin-systemd", "$temp"); my $lref = &read_file_lines($temp); foreach my $l (@{$lref}) { - $l =~ s/(WEBMIN_[A-Z]+)/$ENV{$1}/; + $l =~ s/(WEBMIN_[A-Z]+)/$ENV{$1}/g; } &flush_file_lines($temp); copy_source_dest($temp, "$systemd_root/$product.service"); diff --git a/mailboxes/folders-lib.pl b/mailboxes/folders-lib.pl index 115e41031..998099d79 100755 --- a/mailboxes/folders-lib.pl +++ b/mailboxes/folders-lib.pl @@ -2533,7 +2533,7 @@ foreach my $f (@$folders) { } } push(@opts, [ $byid ? &folder_name($f) : $f->{'index'}, - $f->{'name'}.$umsg ]); + &html_escape($f->{'name'}).$umsg ]); } return &ui_select($name, $byid ? &folder_name($folder) : $folder->{'index'}, \@opts, 1, 0, 0, 0, $auto ? "onChange='form.submit()'" : ""); diff --git a/setup.pl b/setup.pl index 7beb774da..240bdcc25 100755 --- a/setup.pl +++ b/setup.pl @@ -57,6 +57,7 @@ else { # Work out perl library path $ENV{'PERLLIB'} = $wadir; +$ENV{'WEBMIN_LIBDIR'} = $wadir; if ($ENV{'perllib'}) { $ENV{'PERLLIB'} .= ":".$ENV{'perllib'}; } @@ -649,7 +650,7 @@ else { # Reload systemd open(RELOADD, ">$config_directory/reload"); - print RELOADD "$config_directory/.reload-init >/dev/null 2>&1\n"; + print RELOADD "$systemctlcmd reload webmin\n"; close(RELOADD); chmod(0755, "$config_directory/start"); diff --git a/setup.sh b/setup.sh index ae6028729..fa0cadf90 100755 --- a/setup.sh +++ b/setup.sh @@ -72,10 +72,12 @@ cd "$wadir" # Work out perl library path PERLLIB=$wadir +WEBMIN_LIBDIR=$wadir if [ "$perllib" != "" ]; then PERLLIB="$PERLLIB:$perllib" fi export PERLLIB +export WEBMIN_LIBDIR # Validate source directory allmods=`cd "$srcdir"; echo */module.info | sed -e 's/\/module.info//g'` @@ -699,7 +701,7 @@ if [ -x "$systemctlcmd" ]; then echo "$systemctlcmd start webmin" >>$config_dir/restart-by-force-kill # Reload systemd echo "#!/bin/sh" >>$config_dir/reload - echo "$config_dir/.reload-init >/dev/null 2>&1" >>$config_dir/reload + echo "$systemctlcmd reload webmin" >>$config_dir/reload # Fix existing systemd webmin.service file to update start and stop commands (cd "$wadir/init" ; WEBMIN_CONFIG=$config_dir WEBMIN_VAR=$var_dir "$wadir/init/updateboot.pl" "webmin") diff --git a/usermin/change_bind.cgi b/usermin/change_bind.cgi index b02a745ba..3a5dc0f4b 100755 --- a/usermin/change_bind.cgi +++ b/usermin/change_bind.cgi @@ -81,20 +81,13 @@ else { &unlock_file($usermin_miniserv_config); # Attempt to re-start miniserv -$SIG{'TERM'} = 'ignore'; -&system_logged("$config{'usermin_dir'}/stop >/dev/null 2>&1 $temp 2>&1 /dev/null 2>&1 /dev/null 2>&1 /dev/null 2>&1 /dev/null 2>&1 ; do /bin/sleep 0.5 ; done' PIDFile=WEBMIN_VAR/miniserv.pid Type=forking Restart=always RestartSec=2s -OOMPolicy=kill -OOMScoreAdjust=-100 +TimeoutSec=15s [Install] WantedBy=multi-user.target diff --git a/webmin/webmin-lib.pl b/webmin/webmin-lib.pl index 47a8c66bd..0f4335bc4 100755 --- a/webmin/webmin-lib.pl +++ b/webmin/webmin-lib.pl @@ -1788,6 +1788,10 @@ Output a page with header and footer about Webmin needing to restart. =cut sub show_restart_page { +if (&miniserv_systemd_sig('HUP')) { + &redirect(""); + return; + } my ($title, $msg) = @_; $title ||= $text{'restart_title'}; $msg ||= $text{'restart_done'};