Handle hostnames with upper-case letters
[webmin.git] / dhcpd / save_host.cgi
1 #!/usr/local/bin/perl
2 # save_host.cgi
3 # Update, create or delete a host
4
5 require './dhcpd-lib.pl';
6 require './params-lib.pl';
7 &ReadParse();
8 &lock_file($config{'dhcpd_conf'});
9 ($par, $host, $indent, $npar, $nindent) = get_branch('hst', $in{'new'});
10
11 # check acls
12 %access = &get_module_acl();
13 &error_setup($text{'eacl_aviol'});
14 if ($in{'delete'}) {
15         &error("$text{'eacl_np'} $text{'eacl_pdh'}")
16                 if !&can('rw', \%access, $host, 1);
17         }
18 elsif ($in{'options'}) {
19         &error("$text{'eacl_np'} $text{'eacl_psh'}")
20                 if !&can('r', \%access, $host);
21         }
22 elsif ($in{'new'}) {
23         &error("$text{'eacl_np'} $text{'eacl_pih'}")
24                 unless &can('c', \%access, $host) && 
25                                 &can('rw', \%access, $par) &&
26                                 (!$npar || &can('rw', \%access, $npar));
27         }
28 else {
29         &error("$text{'eacl_np'} $text{'eacl_puh'}")
30                 unless &can('rw', \%access, $host) &&
31                         (!$npar || &can('rw', \%access, $npar));
32         $oldname = $host->{'values'}->[0];
33         }
34
35 # save
36 if ($in{'delete'}) {
37         # Delete this host
38         &error_setup($text{'shost_faildel'});
39         &save_directive($par, [ $host ], [ ], 0);
40         &drop_dhcpd_acl('hst', \%access, $host->{'values'}->[0]);
41         }
42 elsif ($in{'options'}) {
43         # Redirect to client options
44         &redirect("edit_options.cgi?sidx=$in{'sidx'}&uidx=$in{'uidx'}&gidx=$in{'gidx'}&idx=$in{'idx'}");
45         exit;
46         }
47 else {
48         &error_setup($text{'shost_failsave'});
49
50         # Validate and save inputs
51         $in{'name'} =~ /^[a-z0-9\.\-]+$/i ||
52                 &error("'$in{'name'}' $text{'shost_invalidhn'}");
53         $host->{'comment'} = $in{'desc'};
54
55         # Check for a hostname clash
56         if (($in{'new'} || $in{'name'} ne $host->{'values'}->[0]) &&
57             $access{'uniq_hst'}) {
58                 foreach $h (&get_my_shared_network_hosts($npar)) {
59                         &error("$text{'eacl_np'} $text{'eacl_uniq'}")
60                                 if (lc($h->{'values'}->[0]) eq lc($in{'name'}));
61                         }
62                 }
63         $host->{'values'} = [ $in{'name'} ];
64
65         if ($in{'hardware'}) {
66                 # Check for hardware clash
67                 $oldhard = $in{'new'} ? undef
68                                       : &find("hardware", $host->{'members'});
69                 if ((!$oldhard || $in{'hardware'} ne $oldhard->{'values'}->[1])
70                     && $access{'uniq_hst'}) {
71                         foreach $h (&get_my_shared_network_hosts($npar)) {
72                                 $chard = &find("hardware", $h->{'members'});
73                                 &error("$text{'eacl_np'} $text{'eacl_uniqh'}")
74                                         if ($chard && lc($chard->{'values'}->[1]) eq lc($in{'hardware'}));
75                                 }
76                         }
77
78                 # Convert from Windows / Cisco formats
79                 $in{'hardware'} =~ s/-/:/g;
80                 if ($in{'hardware'} =~ /^([0-9a-f]{2})([0-9a-f]{2}).([0-9a-f]{2})([0-9a-f]{2}).([0-9a-f]{2})([0-9a-f]{2}).([0-9a-f]{2})([0-9a-f]{2})$/) {
81                         $in{'hardware'} = "$1:$2:$3:$4:$5:$6";
82                         }
83                 $in{'hardware'} =~ /^([0-9a-f]{1,2}:)*[0-9a-f]{1,2}$/i ||
84                         &error(&text('shost_invalidhwa', $in{'hardware'},
85                                      $in{'hardware_type'}) );
86                 @hard = ( { 'name' => 'hardware',
87                             'values' => [ $in{'hardware_type'},
88                                           $in{'hardware'} ] } );
89                 }
90         &save_directive($host, 'hardware', \@hard);
91
92         if ($in{'fixed-address'}) {
93                 # Check for IP clash
94                 $oldfixed = $in{'new'} ? undef
95                               : &find("fixed-address", $host->{'members'});
96                 if ((!$oldfixed ||
97                     $in{'fixed-address'} ne $oldfixed->{'values'}->[0])
98                     && $access{'uniq_hst'}) {
99                         foreach $h (&get_my_shared_network_hosts($npar)) {
100                                 $cfixed = &find("fixed-address",
101                                                 $h->{'members'});
102                                 &error("$text{'eacl_np'} $text{'eacl_uniqi'}")
103                                         if ($cfixed && lc($cfixed->{'values'}->[0]) eq lc($in{'fixed-address'}));
104                                 }
105                         }
106
107                 # Save IP address
108                 if ($in{'fixed-address'} !~ /^[\w\s\.\-,]+$/ ||
109                     $in{'fixed-address'} =~ /(^|[\s,])[-_]/ ||
110                     $in{'fixed-address'} =~ /\.([\s,\.]|$)/ ||
111                     $in{'fixed-address'} =~ /(^|[\s,])\d+\.[\d\.]*[a-z_]/i) {
112                         &error(&text('shost_invalidaddr', $in{'fixed-address'}));       
113                         }
114                 @fixedip = split(/[,\s]+/, $in{'fixed-address'});
115                 @fixed = ( { 'name' => 'fixed-address',
116                              'values' => [ join(" , ", @fixedip) ] } );
117                 }
118         &save_directive($host, 'fixed-address', \@fixed);
119
120         &parse_params($host);
121
122         @partypes = ( "", "shared-network", "subnet", "group" );
123         if (!$npar || $in{'assign'} > 0 && $npar->{'name'} ne $partypes[$in{'assign'}]) {
124                 if ($in{'jsquirk'}) {
125                         &error($text{'shost_invassign'});
126                         }
127                 else {
128                         &redirect("edit_host.cgi?assign=".$in{'assign'}.
129                                 "&idx=".$in{'idx'}."&gidx=".$in{'gidx'}.
130                                 "&uidx=".$in{'uidx'}."&sidx=".$in{'sidx'});
131                         exit;
132                         }
133                 }
134         if ($in{'new'}) {
135                 # save acl for new host
136                 &save_dhcpd_acl('rw', 'hst', \%access, $in{'name'});
137                 # Add to the end of the parent structure
138                 &save_directive($npar, [ ], [ $host ], $nindent);
139                 }
140         elsif ($par eq $npar) {
141                 # Update host
142                 &save_directive($par, [ $host ], [ $host ], $indent);
143                 if ($oldname ne $in{'name'}) {
144                         &drop_dhcpd_acl('hst', \%access, $oldname);
145                         &save_dhcpd_acl('rw', 'hst', \%access, $in{'name'});
146                         }
147                 }
148         else {
149                 # Move this host
150                 &save_directive($par, [ $host ], [ ], 0);
151                 &save_directive($npar, [ ], [ $host ], $nindent);
152                 }
153         }
154 &flush_file_lines();
155 &unlock_file($config{'dhcpd_conf'});
156 &webmin_log($in{'delete'} ? 'delete' : $in{'new'} ? 'create' : 'modify',
157             'host', $host->{'values'}->[0], \%in);
158 if ($in{'ret'} eq "group") {
159         $retparms = "sidx=$in{'sidx'}&uidx=$in{'uidx'}&idx=$in{'gidx'}";
160         }
161 elsif ($in{'ret'} eq "subnet") {
162         $retparms = "sidx=$in{'sidx'}&idx=$in{'uidx'}";
163         }
164 elsif ($in{'ret'} eq "shared") {
165         $retparms = "idx=$in{'sidx'}";
166         }
167
168 &redirect($in{'ret'} ? "edit_$in{'ret'}.cgi?$retparms" : "");