1#!/usr/local/bin/perl
2# change_bind.cgi
3# Update the binding IP address and port for miniserv
4
5require './usermin-lib.pl';
6$access{'bind'} || &error($text{'acl_ecannot'});
7use Socket;
8&ReadParse();
9&get_usermin_miniserv_config(\%miniserv);
10%oldminiserv = %miniserv;
11&error_setup($text{'bind_err'});
12
13# Validate inputs
14for($i=0; defined($in{"ip_def_$i"}); $i++) {
15	next if (!$in{"ip_def_$i"});
16	if ($in{"ip_def_$i"} == 1) {
17		$ip = "*";
18		}
19	else {
20		$ip = $in{"ip_$i"};
21		&check_ipaddress($ip) ||
22		    $in{'ipv6'} && &check_ip6address($ip) ||
23			&error(&text('bind_eip2', $ip));
24		}
25	if ($in{"port_def_$i"} == 1) {
26		$port = $in{"port_$i"};
27		$port =~ /^\d+$/ && $port < 65536 ||
28			&error(&text('bind_eport2', $port));
29		}
30	else {
31		$port = "*";
32		}
33	push(@sockets, [ $ip, $port ]);
34	push(@ports, $port) if ($port && $port ne "*");
35	}
36@sockets || &error($text{'bind_enone'});
37$in{'hostname_def'} || $in{'hostname'} =~ /^[a-z0-9\.\-]+$/i ||
38	&error($text{'bind_ehostname'});
39if ($in{'ipv6'}) {
40	eval "use Socket6";
41	$@ && &error(&text('bind_eipv6', "<tt>Socket6</tt>"));
42	}
43
44# For any new ports, check if they are already in use
45@oldports = split(/\s+/, $in{'oldports'});
46@newports = &unique(grep { &indexof($_, @oldports) < 0 } @ports);
47if (&has_command("lsof")) {
48        foreach my $p (@newports) {
49                $out = &backquote_command("lsof -t -i tcp:$p 2>/dev/null");
50                if ($out =~ /\d+/) {
51                        &error(&text('bind_elsof', $p));
52                        }
53                }
54        }
55
56# Update config file
57&lock_file($usermin_miniserv_config);
58$first = shift(@sockets);
59$miniserv{'port'} = $first->[1];
60if ($first->[0] eq "*") {
61	delete($miniserv{'bind'});
62	}
63else {
64	$miniserv{'bind'} = $first->[0];
65	}
66$miniserv{'sockets'} = join(" ", map { "$_->[0]:$_->[1]" } @sockets);
67$miniserv{'ipv6'} = $in{'ipv6'};
68if ($in{'listen_def'}) {
69	delete($miniserv{'listen'});
70	}
71else {
72	$miniserv{'listen'} = $in{'listen'};
73	}
74if ($in{'hostname_def'}) {
75	delete($miniserv{'host'});
76	}
77else {
78	$miniserv{'host'} = $in{'hostname'};
79	}
80&put_usermin_miniserv_config(\%miniserv);
81&unlock_file($usermin_miniserv_config);
82
83# Attempt to re-start miniserv
84$SIG{'TERM'} = 'ignore';
85&system_logged("$config{'usermin_dir'}/stop >/dev/null 2>&1 </dev/null");
86$temp = &transname();
87$rv = &system_logged("$config{'usermin_dir'}/start >$temp 2>&1 </dev/null");
88$out = &read_file_contents($temp);
89$out =~ s/^Starting Usermin server in.*\n//;
90$out =~ s/at.*line.*//;
91unlink($temp);
92if ($rv) {
93	# Failed! Roll back config and start again
94	&lock_file($usermin_miniserv_config);
95	&put_usermin_miniserv_config(\%oldminiserv);
96	&unlock_file($usermin_miniserv_config);
97	&system_logged("$config{'usermin_dir'}/start >/dev/null 2>&1 </dev/null");
98	&error(&text('bind_erestart', $out));
99	}
100
101# If possible, open the new ports
102foreach my $mod ("firewall", "firewalld") {
103	if (&foreign_check($mod) && $in{'firewall'}) {
104		if (@newports) {
105			&clean_environment();
106			$ENV{'WEBMIN_CONFIG'} = $config_directory;
107			&system_logged(
108				&module_root_directory($mod)."/open-ports.pl ".
109			        join(" ", map { $_.":".($_+10) } @newports).
110			        " >/dev/null 2>&1");
111			&reset_environment();
112			}
113		}
114	}
115
116&webmin_log("bind", undef, undef, \%in);
117
118&redirect("");
119
120