Handle hostnames with upper-case letters
[webmin.git] / nis / solaris-lib.pl
1 # solaris-lib.pl
2 # NIS functions for solaris
3
4 $binding_dir = "/var/yp/binding";
5 $yp_makefile = "/var/yp/Makefile";
6
7 # get_nis_support()
8 # Returns 0 for no support, 1 for client only, 2 for server and 3 for both
9 sub get_nis_support
10 {
11 local $rv;
12 $rv += 1 if (-x "/usr/lib/netsvc/yp/ypbind");
13 $rv += 2 if (-x "/usr/lib/netsvc/yp/ypserv");
14 return $rv;
15 }
16
17 # get_client_config()
18 # Returns a hash ref containg details of the client's NIS settings
19 sub get_client_config
20 {
21 local $nis;
22 open(DOM, "/etc/defaultdomain");
23 chop($nis->{'domain'} = <DOM>);
24 close(DOM);
25 if ($nis->{'domain'}) {
26         if (open(SRV, "$binding_dir/$nis->{'domain'}/ypservers")) {
27                 while(<SRV>) {
28                         s/\r|\n//g;
29                         push(@{$nis->{'servers'}}, $_);
30                         }
31                 close(SRV);
32                 }
33         else {
34                 $nis->{'broadcast'} = 1;
35                 }
36         }
37 return $nis;
38 }
39
40 # save_client_config(&config)
41 # Saves and applies the NIS client configuration in the give hash.
42 # Returns an error message if any, or undef on success.
43 sub save_client_config
44 {
45 if ($_[0]->{'domain'}) {
46         # Check if the servers are in /etc/hosts
47         local @s = @{$_[0]->{'servers'}};
48         &foreign_require("net", "net-lib.pl");
49         foreach $s (@s) {
50                 local $found = 0;
51                 foreach $h (&foreign_call("net", "list_hosts")) {
52                         $found++ if (&indexof($s, @{$h->{'hosts'}}) >= 0);
53                         }
54                 return &text("client_ehosts", $s) if (!$found);
55                 }
56
57         # Write the files
58         &open_tempfile(DOM, ">/etc/defaultdomain");
59         &print_tempfile(DOM, $_[0]->{'domain'},"\n");
60         &close_tempfile(DOM);
61         mkdir("$binding_dir/$_[0]->{'domain'}", 0755);
62         if (@s) {
63                 &open_tempfile(SRV,">$binding_dir/$_[0]->{'domain'}/ypservers");
64                 foreach $s (@s) {
65                         &print_tempfile(SRV, "$s\n");
66                         }
67                 &close_tempfile(SRV);
68                 }
69         else {
70                 unlink("$binding_dir/$_[0]->{'domain'}/ypservers");
71                 }
72         }
73 else {
74         unlink("/etc/defaultdomain");
75         }
76
77 # Apply by running ypstop and ypstart
78 &system_logged("(/usr/lib/netsvc/yp/ypstop || /etc/init.d/yp stop) >/dev/null 2>&1");
79 &system_logged("domainname \"$_[0]->{'domain'}\" >/dev/null 2>&1");
80 &system_logged("(/usr/lib/netsvc/yp/ypstart || /etc/init.d/yp start) >/dev/null 2>&1");
81 sleep(2);
82 if ($_[0]->{'domain'}) {
83         local $out = `ypwhich 2>&1`;
84         if ($? || $out =~ /not\s+bound/i || $out =~ /can't\s+communicate/i) {
85                 system("(/usr/lib/netsvc/yp/ypstop || /etc/init.d/yp stop) >/dev/null 2>&1");
86                 return $text{'client_eypwhich'};
87                 }
88         }
89 }
90
91 @nis_tables = ( "passwd", "group", "hosts", "ethers", "networks", "rpc",
92                 "services", "protocols", "netgroup", "bootparams", "aliases",
93                 "publickey", "netid", "netmasks", "c2secure", "timezone",
94                 "auto.master", "auto.home" );
95
96 # show_server_config()
97 # Display a form for editing NIS server options
98 sub show_server_config
99 {
100 local ($var, $rule) = &parse_yp_makefile();
101 local $dom = `domainname`; chop($dom);
102
103 print "<tr> <td><b>$text{'server_boot'}</b></td> <td>\n";
104 if ($dom && -d "/var/yp/$dom") {
105         print "<i>$text{'server_already'}</i>\n";
106         }
107 else {
108         print "<input type=radio name=boot value=1 > $text{'yes'}\n";
109         print "<input type=radio name=boot value=0 checked > $text{'no'}\n";
110         }
111 print "</td>\n";
112
113 print "<td><b>$text{'server_domain'}</b></td>\n";
114 printf "<td><input type=radio name=domain_def value=1 %s> %s\n",
115         $dom ? '' : 'checked', $text{'server_none'};
116 printf "<input type=radio name=domain_def value=0 %s>\n",
117         $dom ? 'checked' : '';
118 printf "<input name=domain size=35 value='%s'></td> </tr>\n", $dom;
119
120 print "<tr> <td><b>$text{'server_type'}</b></td>\n";
121 printf "<td colspan=3><input type=radio name=type value=1 %s> %s\n",
122         $config{'slave'} ? '' : 'checked', $text{'server_master'};
123 printf "<input type=radio name=type value=0 %s> %s\n",
124         $config{'slave'} ? 'checked' : '', $text{'server_slave'};
125 printf "<input name=slave size=30 value='%s'></td> </tr>\n", $config{'slave'};
126
127 print "<tr> <td colspan=4><i>$text{'server_solaris'}</i></td> </tr>\n";
128
129 print "</table></td></tr></table><p>\n";
130 print "<table border width=100%>\n";
131 print "<tr $tb> <td><b>$text{'server_mheader'}</b></td> </tr>\n";
132 print "<tr $cb> <td><table width=100%>\n";
133
134 local %inall;
135 local @all = split(/\s+/, $rule->{'all'}->{'value'});
136 map { $inall{$_}++ } @all;
137 print "<tr> <td rowspan=4 valign=top><b>$text{'server_tables'}</b></td>\n";
138 print "<td rowspan=4><select multiple size=6 name=tables>\n";
139 foreach $t (&unique(@nis_tables, @all)) {
140         printf "<option value=%s %s>%s\n",
141                 $t, $inall{$t} ? 'selected' : '', $t;
142         }
143 print "</select></td>\n";
144
145 print "<td><b>$text{'server_dns'}</b></td>\n";
146 printf "<td><input type=radio name=b value='-b' %s> %s\n",
147         $var->{'B'}->{'value'} eq '-b' ? 'checked' : '', $text{'yes'};
148 printf "<input type=radio name=b value='' %s> %s</td> </tr>\n",
149         $var->{'B'}->{'value'} eq '-b' ? '' : 'checked', $text{'no'};
150
151 print "<tr> <td><b>$text{'server_push'}</b></td>\n";
152 printf "<td><input type=radio name=nopush value='\"\"' %s> %s\n",
153         $var->{'NOPUSH'}->{'value'} eq 'true' ? '' : 'checked', $text{'yes'};
154 printf "<input type=radio name=nopush value=true %s> %s</td> </tr>\n",
155         $var->{'NOPUSH'}->{'value'} eq 'true' ? 'checked' : '', $text{'no'};
156
157 print "<tr> <td><b>$text{'server_dir'}</b></td>\n";
158 printf "<td><input name=dir size=30 value='%s'> %s</td> </tr>\n",
159         $var->{'DIR'}->{'value'}, &file_chooser_button("dir", 0);
160
161 print "<tr> <td><b>$text{'server_pwdir'}</b></td>\n";
162 printf "<td><input name=pwdir size=30 value='%s'> %s</td> </tr>\n",
163         $var->{'PWDIR'}->{'value'}, &file_chooser_button("pwdir", 0);
164 }
165
166 # parse_server_config()
167 # Parse and save the NIS server options
168 sub parse_server_config
169 {
170 local ($var, $rule) = &parse_yp_makefile();
171 $in{'domain_def'} || $in{'domain'} =~ /^[A-Za-z0-9\.\-\_]+$/ ||
172         &error(&text('server_edomain', $in{'domain'}));
173 if ($in{'boot'} && $in{'domain_def'}) {
174         &error($text{'server_ebootdom'});
175         }
176 $in{'type'} || &to_ipaddress($in{'slave'}) ||
177         &to_ip6address($in{'slave'}) || &error($text{'server_eslave'});
178 -d $in{'dir'} || &error($text{'server_edir'});
179 -d $in{'pwdir'} || &error($text{'server_epwdir'});
180 &update_makefile($var->{'NOPUSH'}, $in{'nopush'});
181 &update_makefile($var->{'B'}, $in{'b'});
182 &update_makefile($rule->{'all'}, join(" ", split(/\0/, $in{'tables'})), "");
183 &update_makefile($var->{'DIR'}, $in{'dir'});
184 &update_makefile($var->{'PWDIR'}, $in{'pwdir'});
185 &flush_file_lines();
186
187 if ($in{'domain_def'}) {
188         unlink("/etc/defaultdomain");
189         &system_logged("domainname \"\" >/dev/null 2>&1");
190         }
191 else {
192         local $old = `domainname`; chop($old);
193         &open_tempfile(DOM, ">/etc/defaultdomain");
194         &print_tempfile(DOM, "$in{'domain'}\n");
195         &close_tempfile(DOM);
196         &system_logged("domainname \"$in{'domain'}\" >/dev/null 2>&1");
197         if ($in{'boot'}) {
198                 # Create the domain directory
199                 mkdir("/var/yp/$in{'domain'}", 0755);
200                 &system_logged("rm -f /var/yp/*.time"); # force a remake
201                 }
202         }
203
204 if ($in{'type'}) {
205         # Master server
206         delete($config{'slave'});
207         &apply_table_changes()
208                 if (!$in{'domain_def'} && -d "/var/yp/$in{'domain'}");
209         }
210 else {
211         local $temp = &transname();
212         open(TEMP, ">$temp");
213         print TEMP "n\ny\n";
214         close(TEMP);
215         $out = &backquote_logged("/usr/sbin/ypinit -s $in{'slave'} <$temp 2>&1");
216         unlink($temp);
217         if ($?) { &error("<tt>$out</tt>"); }
218         $config{'slave'} = $in{'slave'};
219         }
220 &write_file("$module_config_directory/config", \%config);
221 &system_logged("(/usr/lib/netsvc/yp/ypstop || /etc/init.d/yp stop) >/dev/null 2>&1");
222 &system_logged("(/usr/lib/netsvc/yp/ypstart || /etc/init.d/yp start) >/dev/null 2>&1");
223 }
224
225 # get_server_mode()
226 # Returns 0 if the NIS server is inactive, 1 if active as a master, or 2 if
227 # active as a slave.
228 sub get_server_mode
229 {
230 local $dom = `domainname`; chop($dom);
231 return !$dom ? 0 : $config{'slave'} ? 2 : 1;
232 }
233
234 # parse_yp_makefile()
235 # Returns hashes of makefile variables and rules
236 sub parse_yp_makefile
237 {
238 # First parse joined lines
239 local $lnum = 0;
240 local (@lines, $llast);
241 open(MAKE, $yp_makefile);
242 while(<MAKE>) {
243         s/\r|\n//g;
244         local $slash = (s/\\$//);
245         s/#.*$//;
246         if ($llast) {
247                 $llast->{'value'} .= " $_";
248                 $llast->{'eline'} = $lnum;
249                 }
250         else {
251                 push(@lines, { 'value' => $_,
252                                'line' => $lnum,
253                                'eline' => $lnum });
254                 }
255         $llast = $slash ? $lines[$#lines] : undef;
256         $lnum++;
257         }
258 close(MAKE);
259
260 # Then look for variables and rules
261 local ($i, %var, %rule);
262 for($i=0; $i<@lines; $i++) {
263         if ($lines[$i]->{'value'} =~ /^\s*(\S+)\s*=\s*(.*)/) {
264                 # Found a variable
265                 $var{$1} = { 'name' => $1,
266                              'value' => $2,
267                              'type' => 0,
268                              'line' => $lines[$i]->{'line'},
269                              'eline' => $lines[$i]->{'eline'} };
270                 }
271         elsif ($lines[$i]->{'value'} =~ /^\s*(\S+):\s*(.*)/) {
272                 # Found a makefile rule
273                 $rule{$1} = { 'name' => $1,
274                               'value' => $2,
275                               'type' => 1,
276                               'code' => $lines[$i+1]->{'value'},
277                               'line' => $lines[$i]->{'line'},
278                               'eline' => $lines[$i+1]->{'eline'} };
279                 $i++;
280                 }
281         }
282 return ( \%var, \%rule );
283 }
284
285 # expand_vars(string, &vars)
286 sub expand_vars
287 {
288 local $rv = $_[0];
289 while($rv =~ /^(.*)\$\(([A-Za-z0-9_]+)\)(.*)$/) {
290         $rv = $1.$_[1]->{$2}->{'value'}.$3;
291         }
292 return $rv;
293 }
294
295 # update_makefile(&old, value, [value]);
296 sub update_makefile
297 {
298 local $lref = &read_file_lines($yp_makefile);
299 local @n;
300 if ($_[0]->{'type'} == 0) {
301         @n = ( "$_[0]->{'name'} = $_[1]" );
302         }
303 else {
304         @n = ( "$_[0]->{'name'}: $_[1]", $_[2] );
305         }
306 splice(@$lref, $_[0]->{'line'}, $_[0]->{'eline'} - $_[0]->{'line'} + 1, @n);
307 }
308
309 # apply_table_changes()
310 # Do whatever is necessary for the table text files to be loaded into
311 # the NIS server
312 sub apply_table_changes
313 {
314 if ($0 =~ /save_(\S+).cgi/) {
315         # Try to make just one table
316         local $table = $1;
317         local $ex = &system_logged("(cd /var/yp ; /usr/ccs/bin/make $table) >/dev/null 2>&1 </dev/null");
318         return if (!$ex);
319         }
320 &system_logged("(cd /var/yp ; /usr/ccs/bin/make) >/dev/null 2>&1 </dev/null");
321 }
322
323 # list_nis_tables()
324 # Returns a list of structures of all NIS tables
325 sub list_nis_tables
326 {
327 local @rv;
328 local ($var, $rule) = &parse_yp_makefile();
329 local $dom = `domainname`; chop($dom);
330 local @all = split(/\s+/, $rule->{'all'}->{'value'});
331 foreach $t (@all) {
332         local $table = { 'table' => $t,
333                          'index' => scalar(@rv),
334                          'domain' => $dom };
335         local $rt = $rule->{"$t.time"};
336         local @files = split(/\s+/, $rt->{'value'});
337         @files = map { &expand_vars($_, $var) } @files;
338         $table->{'files'} = \@files;
339         $table->{'type'} = $t eq 'passwd' && @files > 1 ? 'passwd_shadow' :
340                            $t;
341         push(@rv, $table);
342         }
343 return @rv;
344 }
345
346 sub show_server_security
347 {
348 }
349
350 sub parse_server_security
351 {
352 &system_logged("(/usr/lib/netsvc/yp/ypstop || /etc/init.d/yp stop) >/dev/null 2>&1");
353 &system_logged("(/usr/lib/netsvc/yp/ypstart || /etc/init.d/yp start) >/dev/null 2>&1");
354 }
355
356 sub extra_config_files
357 {
358 local @rv = ( "/etc/defaultdomain" );
359 local $conf = &get_client_config();
360 if ($conf->{'domain'}) {
361         push(@rv, "$binding_dir/$conf->{'domain'}/ypservers");
362         }
363 return @rv;
364 }
365
366 1;
367