3 # Save client options for some subnet, shared net, group, host or global
5 require './dhcpd-lib.pl';
6 require './params-lib.pl';
8 &lock_file($config{'dhcpd_conf'});
9 $client = &get_parent_config();
10 push(@parents, $client);
11 foreach $i ($in{'sidx'}, $in{'uidx'}, $in{'gidx'}, $in{'idx'}) {
13 $client = $client->{'members'}->[$i];
14 push(@parents, $client);
20 %access = &get_module_acl();
21 &error_setup($text{'eacl_aviol'});
22 if ($client->{'name'} eq 'subnet') {
23 &error("$text{'eacl_np'} $text{'eacl_pus'}")
24 if !&can('rw', \%access, $client);
26 elsif ($client->{'name'} eq 'shared-network') {
27 &error("$text{'eacl_np'} $text{'eacl_pun'}")
28 if !&can('rw', \%access, $client);
30 elsif ($client->{'name'} eq 'host') {
31 &error("$text{'eacl_np'} $text{'eacl_puh'}")
32 if !&can('rw', \%access, $client);
34 elsif ($client->{'name'} eq 'group') {
35 &error("$text{'eacl_np'} $text{'eacl_pug'}")
36 if !&can('rw', \%access, $client);
39 &error("$text{'eacl_np'} $text{'eacl_pglob'}")
40 if !$access{'global'};
44 &error_setup($text{'sopt_failsave'});
46 &save_option("host-name", 3, $client, $indent);
47 &save_option("routers", 2, $client, $indent);
48 &save_option("subnet-mask", 0, $client, $indent);
49 &save_option("broadcast-address", 0, $client, $indent);
50 &save_option("domain-name", 3, $client, $indent);
51 &save_option("domain-name-servers", 2, $client, $indent);
52 &save_option("domain-search", 6, $client, $indent);
53 &save_option("time-servers", 2, $client, $indent);
54 &save_option("log-servers", 2, $client, $indent);
55 &save_option("swap-server", 2, $client, $indent);
56 &save_option("root-path", 3, $client, $indent);
57 &save_option("nis-domain", 3, $client, $indent);
58 &save_option("nis-servers", 2, $client, $indent);
59 &save_option("font-servers", 2, $client, $indent);
60 &save_option("x-display-manager", 2, $client, $indent);
61 &save_option("static-routes", 5, $client, $indent);
62 &save_option("ntp-servers", 2, $client, $indent);
63 &save_option("netbios-name-servers", 2, $client, $indent);
64 &save_option("netbios-scope", 3, $client, $indent);
65 &save_option("netbios-node-type", 1, $client, $indent);
66 &save_option("time-offset", 1, $client, $indent);
67 &save_option("dhcp-server-identifier", 2, $client, $indent);
68 &save_option("slp-directory-agent", 2, $client, $indent, 1);
69 &save_option("slp-service-scope", 3, $client, $indent, 1);
70 if ($in{'level'} eq "global") {
72 &save_choice("use-host-decl-names", $client, 0);
73 &parse_params($client, 0);
75 elsif ($in{'level'} eq "host") {
76 $ret="edit_host.cgi?sidx=$in{'sidx'}&uidx=$in{'uidx'}&gidx=$in{'gidx'}&idx=$in{'idx'}";
78 elsif ($in{'level'} eq "group") {
79 $ret="edit_group.cgi?sidx=$in{'sidx'}&uidx=$in{'uidx'}&idx=$in{'idx'}";
81 elsif ($in{'level'} eq "subnet") {
82 $ret="edit_subnet.cgi?sidx=$in{'sidx'}&idx=$in{'idx'}";
84 elsif ($in{'level'} eq "shared-network") {
85 $ret="edit_shared.cgi?idx=$in{'idx'}";
88 if ($config{'dhcpd_version'} >= 3) {
89 # Save option definitions, new DHCPd
90 @defs = grep { $_->{'name'} eq 'option' &&
91 $_->{'values'}->[1] eq 'code' &&
92 $_->{'values'}->[3] eq '=' }
93 @{$client->{'members'}};
94 %optdef = map { $_->{'values'}->[0], $_ } @defs;
95 for($i=0; defined($in{"dname_$i"}); $i++) {
96 next if (!$in{"dname_$i"} || !$in{"dnum_$i"} ||
98 $in{"dname_$i"} =~ /^[a-z0-9\.\-\_]+$/i ||
99 &error(&text('sopt_edname', $in{"dname_$i"}));
100 $in{"dnum_$i"} =~ /^\d+$/ ||
101 &error(&text('sopt_ednum', $in{"dnum_$i"}));
102 if ($in{"dtype_$i"} =~ /^[a-z0-9\s\.\-\_]+$/i) {
103 @dtypes = ( $in{"dtype_$i"} );
105 elsif ($in{"dtype_$i"} =~ /^\{.*\}$/) {
106 @dtypes = split(/\s+/, $in{"dtype_$i"});
109 &error(&text('sopt_edtype', $in{"dtype_$i"}));
111 push(@newdefs, { 'name' => 'option',
112 'values' => [ $in{"dname_$i"}, "code",
117 &save_directive($client, \@defs, \@newdefs, $indent, 1);
119 # Find option definitions at higher levels
120 foreach $p (@parents) {
121 @popts = &find("option", $p->{'members'});
122 @pdefs = grep { $_->{'values'}->[1] eq 'code' &&
123 $_->{'values'}->[3] eq '=' } @popts;
124 foreach $o (@pdefs) {
125 $optdef{$o->{'values'}->[0]} = $o
126 if ($o->{'values'}->[0]);
130 # Find the last definition
132 foreach $d (@newdefs) {
133 $maxdef = $d if (!$maxdef || $d->{'line'} > $maxdef->{'line'});
136 # Save custom options
137 @custom = grep { $_->{'name'} eq 'option' &&
138 $optdef{$_->{'values'}->[0]} &&
139 $_->{'values'}->[1] ne 'code' }
140 @{$client->{'members'}};
141 for($i=0; defined($in{"cname_$i"}); $i++) {
142 next if ($in{"cname_$i"} eq "");
143 local $o = $optdef{$in{"cname_$i"}};
144 local $cv = $in{"cval_$i"};
145 $cv =~ /\S/ || &error(&text('sopt_ecval', $in{"cname_$i"}));
146 if ($o && $o->{'values'}->[4] eq 'ip-address') {
147 &check_ipaddress($cv) ||
148 &check_ip6address($cv) ||
149 &error(&text('sopt_ecip', $in{"cname_$i"}));
151 if ($o && $o->{'values'}->[4] eq 'string' ||
152 $cv !~ /^([0-9a-fA-F]{1,2}:)*[0-9a-fA-F]{1,2}$/ &&
153 !&check_ipaddress($cv)) {
154 # Quote if type is a string, or unknown and not an IP
157 push(@newcustom, { 'name' => 'option',
158 'values' => [ $in{"cname_$i"}, $cv ] } );
160 &save_directive($client, \@custom, \@newcustom, $indent,
161 $maxdef ? 0 : 1, $maxdef);
164 # Save custom options, old DHCPd
165 @custom = grep { $_->{'name'} eq 'option' &&
166 $_->{'values'}->[0] =~ /^option-(\S+)$/ &&
167 $_->{'values'}->[1] ne 'code' }
168 @{$client->{'members'}};
169 for($i=0; defined($in{"cnum_$i"}); $i++) {
170 next if (!$in{"cnum_$i"} || !$in{"cval_$i"});
171 $in{"cnum_$i"} =~ /^\d+$/ ||
172 ($config{'dhcpd_version'} >= 3 &&
173 $in{"cnum_$i"} =~ /^\S+$/) ||
174 &error(&text('sopt_ednum', $in{"cnum_$i"}));
175 local $cv = $in{"cval_$i"};
177 if ($cv !~ /^([0-9a-fA-F]{1,2}:)*[0-9a-fA-F]{1,2}$/ &&
178 !&check_ipaddress($cv));
179 push(@newcustom, { 'name' => 'option',
180 'values' => [ 'option-'.$in{"cnum_$i"},
183 &save_directive($client, \@custom, \@newcustom, $indent, 1);
187 &unlock_file($config{'dhcpd_conf'});
188 if ($client->{'name'} eq 'subnet') {
189 &webmin_log("options", 'subnet',
190 "$client->{'values'}->[0]/$client->{'values'}->[2]", \%in);
192 elsif ($client->{'name'} eq 'shared-network') {
193 &webmin_log("options", 'subnet', $client->{'values'}->[0], \%in);
195 elsif ($client->{'name'} eq 'host') {
196 &webmin_log("options", 'host', $client->{'values'}->[0], \%in);
198 elsif ($client->{'name'} eq 'group') {
199 @count = &find("host", $client->{'members'});
200 &webmin_log("options", 'group',
201 join(",", map { $_->{'values'}->[0] } @count), \%in);
205 # save_option(name, type, &config, indent, [has-boolean])
209 local $m = $_[2]->{'members'};
210 for($i=0; $i<@$m; $i++) {
211 if ($m->[$i]->{'name'} eq 'option' &&
212 $m->[$i]->{'values'}->[0] eq $_[0]) {
217 if ($in{"$_[0]_def"}) {
218 &save_directive($_[2], [ $v ], [ ], 0, 1) if ($v);
221 local $nv = $in{$_[0]};
222 local @nv = split(/\s+/, $nv);
224 &to_ipaddress($nv) ||
225 &error("$_[0] '$nv' $text{'sopt_invalidip'}");
228 $nv =~ /^-?\d+$/ || &error("'$nv' $text{'sopt_invalidint'}");
231 foreach my $ip (@nv) {
232 &to_ipaddress($ip) ||
233 &error("'$ip' $text{'sopt_invalidip'}");
235 $nv = join(", ", @nv);
243 $ipp =~ /^(\S+)\s*,\s*(\S+)$/ ||
244 &error("'$ipp' $text{'sopt_invalidipp'}");
245 &check_ipaddress($1) ||
246 &error("'$1' $text{'sopt_invalidip'}");
247 &check_ipaddress($2) ||
248 &error("'$2' $text{'sopt_invalidip'}");
251 $nv = join(", ", @nnv);
254 $nv = join(", ", map { "\"$_\"" } @nv);
256 local @bool = !$_[4] ? ( ) :
257 $in{$_[0]."_bool"} ? ( "true" ) : ( "false" );
258 local $dir = { 'name' => 'option',
259 'values' => [ $_[0], @bool, $nv ] };
260 &save_directive($_[2], $v ? [ $v ] : [ ], [ $dir ], $_[3], 1);