Handle hostnames with upper-case letters
[webmin.git] / dhcpd / save_shared.cgi
1 #!/usr/local/bin/perl
2 # save_shared.cgi
3 # Update, create or delete a shared network
4
5 require './dhcpd-lib.pl';
6 require './params-lib.pl';
7 &ReadParse();
8 &lock_file($config{'dhcpd_conf'});
9 ($par, $sha, $indent) = &get_branch('sha', $in{'new'});
10 $parconf = $par->{'members'};
11
12 # check acls
13 %access = &get_module_acl();
14 &error_setup($text{'eacl_aviol'});
15 if ($in{'delete'}) {
16         &error("$text{'eacl_np'} $text{'eacl_pdn'}")
17                 if !&can('rw', \%access, $sha, 1);
18         }
19 elsif ($in{'options'}) {
20         &error("$text{'eacl_np'} $text{'eacl_psn'}")
21                 if !&can('r', \%access, $sha);
22         }
23 elsif ($in{'new'}) {
24         &error("$text{'eacl_np'} $text{'eacl_pin'}") 
25                 unless &can('c', \%access, $sha) && &can('rw', \%access, $par);
26         # restrict duplicates
27         if($access{'uniq_sha'}) {
28                 foreach $s (&find("shared-network", &get_config())) {
29                         &error("$text{'eacl_np'} $text{'eacl_uniq'}")
30                                 if lc $s->{'values'}->[0] eq lc $in{'name'};
31                         }
32                 }
33         }
34 else {
35         &error("$text{'eacl_np'} $text{'eacl_pun'}")
36                 if !&can('rw', \%access, $sha);
37         }
38
39 # save
40 if ($in{'options'}) {
41         # Redirect to client options
42         &redirect("edit_options.cgi?idx=$in{'idx'}");
43         exit;
44         }
45 else {
46         if ($in{'delete'}) {
47                 &error_setup($text{'sshared_faildel'});
48                 }
49         else {
50                 &error_setup($text{'sshared_failsave'});
51                 $in{'name'} =~ /^\S+$/ ||
52                         &error($text{'sshared_invalidsname'});
53                 $sha->{'values'} = [ $in{'name'} ];
54                 $sha->{'comment'} = $in{'desc'};
55         }
56
57         # Move hosts, groups and subnets into or out of this shared network
58         @wasin = &find("host", $sha->{'members'});
59         foreach $hn (split(/\0/, $in{'hosts'})) {
60                 if ($hn =~ /(\d+),(\d+)/) {
61                         push(@nowin, $parconf->[$2]->{'members'}->[$1]);
62                         $nowpr{$parconf->[$2]->{'members'}->[$1]} =
63                                 $parconf->[$2];
64                         }
65                 elsif ($hn =~ /(\d+),/) {
66                         push(@nowin, $parconf->[$1]);
67                         $nowpr{$parconf->[$1]} = $par;
68                         }
69                 if ($nowin[$#nowin]->{'name'} ne "host") {
70                         &error($text{'sgroup_echanged'});
71                         }
72                 }
73         @wasgin = &find("group", $sha->{'members'});
74         foreach $gn (split(/\0/, $in{'groups'})) {
75                 if ($gn =~ /(\d+),(\d+)/) {
76                         push(@nowgin, $parconf->[$2]->{'members'}->[$1]);
77                         $nowgpr{$parconf->[$2]->{'members'}->[$1]} =
78                                 $parconf->[$2];
79                         }
80                 elsif ($gn =~ /(\d+),/) {
81                         push(@nowgin, $parconf->[$1]);
82                         $nowgpr{$parconf->[$1]} = $par;
83                         }
84                 if ($nowgin[$#nowgin]->{'name'} ne "group") {
85                         &error($text{'sgroup_echanged'});
86                         }
87                 }
88         @wasuin = &find("subnet", $sha->{'members'});
89         foreach $un (split(/\0/, $in{'subnets'})) {
90                 if ($un =~ /(\d+),(\d+)/) {
91                         push(@nowuin, $parconf->[$2]->{'members'}->[$1]);
92                         $nowupr{$parconf->[$2]->{'members'}->[$1]} =
93                                 $parconf->[$2];
94                         }
95                 elsif ($un =~ /(\d+),/) {
96                         push(@nowuin, $parconf->[$1]);
97                         $nowupr{$parconf->[$1]} = $par;
98                         }
99                 if ($nowuin[$#nowuin]->{'name'} ne "subnet") {
100                         &error($text{'sgroup_echanged'});
101                         }
102                 }
103
104         &error_setup($text{'eacl_aviol'});
105         foreach $h (&unique(@wasin, @nowin)) {
106                 $was = &indexof($h, @wasin) != -1;
107                 $now = &indexof($h, @nowin) != -1;
108
109                 # per-host ACLs for new or updated hosts
110                 if ($was != $now && !&can('rw', \%access, $h)) {
111                         &error("$text{'eacl_np'} $text{'eacl_pun'}");
112                         }
113                 if ($was && !$now) {
114                         # Move out of the shared network
115                         &save_directive($sha, [ $h ], [ ], 0);
116                         &save_directive($par, [ ], [ $h ], 0);
117                         }
118                 elsif ($now && !$was) {
119                         # Move into the shared network (maybe from another)
120                         &save_directive($nowpr{$h}, [ $h ], [ ], 0);
121                         &save_directive($sha, [ ], [ $h ], 1);
122                         }
123                 }
124         foreach $g (&unique(@wasgin, @nowgin)) {
125                 $was = &indexof($g, @wasgin) != -1;
126                 $now = &indexof($g, @nowgin) != -1;
127
128                 # per-group ACLs for new or updated groups
129                 if ($was != $now && !&can('rw', \%access, $g)) {
130                         &error("$text{'eacl_np'} $text{'eacl_pun'}");
131                         }       
132                 if ($was && !$now) {
133                         # Move out of the shared network
134                         &save_directive($sha, [ $g ], [ ], 0);
135                         &save_directive($par, [ ], [ $g ], 0);
136                         }
137                 elsif ($now && !$was) {
138                         # Move into the shared network (maybe from another)
139                         &save_directive($nowgpr{$g}, [ $g ], [ ], 0);
140                         &save_directive($sha, [ ], [ $g ], 1);
141                         }
142                 }
143         foreach $u (&unique(@wasuin, @nowuin)) {
144                 $was = &indexof($u, @wasuin) != -1;
145                 $now = &indexof($u, @nowuin) != -1;
146
147                 # per-subnet ACLs for new or updated subnetss
148                 if ($was != $now && !&can('rw', \%access, $u)) {
149                         &error("$text{'eacl_np'} $text{'eacl_pun'}");
150                         }                
151                 if ($was && !$now) {
152                         # Move out of the shared network
153                         &save_directive($sha, [ $u ], [ ], 0);
154                         &save_directive($par, [ ], [ $u ], 0);
155                         if ($par->{'name'} eq "shared-network") {
156                                 &fix_sequence($par);
157                                 }
158                         }
159                 elsif ($now && !$was) {
160                         # Move into the shared network (maybe from another)
161                         &save_directive($nowupr{$u}, [ $u ], [ ], 0);
162                         &save_directive($sha, [ ], [ $u ], 1);
163                         if ($nowupr{$u}->{'name'} eq "shared-network") {
164                                 &check_subnets($nowupr{$u});
165                                 }
166                         }
167                 }
168         &check_subnets($sha);
169         &fix_sequence($sha);
170
171         if (!$in{'delete'}) {
172                 &parse_params($sha);
173
174                 if ($in{'new'}) {
175                         # Add this shared net
176                         &save_directive($par, [ ], [ $sha ], 0);
177                         }
178                 else {
179                         # Update shared net
180                         &save_directive($par, [ $sha ], [ $sha ], 0);
181                         }
182                 }
183         }
184 &flush_file_lines();
185 if ($in{'delete'}) {
186         # Delete this net
187         if ($in{'hosts'} eq "" && $in{'groups'} eq "" && $in{'subnets'} eq "") {
188                 &save_directive($par, [ $sha ], [ ], 0);
189                 &flush_file_lines();
190                 }
191         else {
192                 &unlock_file($config{'dhcpd_conf'});
193                 &redirect("confirm_delete.cgi?idx=$in{'idx'}\&type=0");
194                 exit;
195                 }
196         }
197 &unlock_file($config{'dhcpd_conf'});
198 &webmin_log($in{'delete'} ? 'delete' : $in{'new'} ? 'create' : 'modify',
199             'shared', $sha->{'values'}->[0], \%in);
200 &redirect("");
201
202 # check whether thist shared network contains any subnet
203 sub check_subnets
204 {
205 local(@subnets);
206 @subnets = &find("subnet", $_[0]->{'members'});
207 if (@subnets == 0) {
208         &error_setup($text{'sshared_failsave'});
209         &error(&text('sshared_nosubnet', $_[0]->{'values'}->[0]));
210         }
211 }
212
213 # force hosts and groups to follow subnets
214 sub fix_sequence
215 {
216 local(@subnets, $max, $u, $i);
217 @subnets = &find("subnet", $_[0]->{'members'});
218 $max = -1;
219 foreach $u (@subnets) {
220         $max = $u->{'index'} > $max ? $u->{'index'} : $max;
221         }
222 for ($i = 0; $i < $max; $i++) {
223         $u = $_[0]->{'members'}->[$i];
224         if ($u->{'name'} eq "host" || $u->{'name'} eq "group") {
225                 # move to the end of list
226                 &save_directive($_[0], [ $u ], [ ], 0);
227                 &save_directive($_[0], [ ], [ $u ], 0);
228                 }
229         }
230 }
231