Handle hostnames with upper-case letters
[webmin.git] / nis / suse-linux-lib.pl
1 # suse-linux-lib.pl
2 # NIS functions for SuSE linux NIS client and server
3
4 $yp_makefile = "/var/yp/Makefile";
5 $ypserv_conf = "/etc/ypserv.conf";
6 $pid_file = "/var/run/ypserv.pid";
7 $rc_config = "/etc/rc.config";
8
9 # get_nis_support()
10 # Returns 0 for no support, 1 for client only, 2 for server and 3 for both
11 sub get_nis_support
12 {
13 local $rv;
14 $rv += 1 if (&has_command("ypbind"));
15 $rv += 2 if (&has_command("ypserv"));
16 return $rv;
17 }
18
19 # get_client_config()
20 # Returns a hash ref containg details of the client's NIS settings
21 sub get_client_config
22 {
23 local $nis;
24 local $rc = &parse_rc_config();
25 if ($rc->{'START_YPBIND'}->{'value'} eq 'yes') {
26         $nis->{'domain'} = $rc->{'YP_DOMAINNAME'}->{'value'};
27         local @s = split(/\s+/, $rc->{'YP_SERVER'}->{'value'});
28         if (@s) {
29                 $nis->{'servers'} = \@s;
30                 }
31         else {
32                 $nis->{'broadcast'} = 1;
33                 }
34         }
35 return $nis;
36 }
37
38 # save_client_config(&config)
39 # Saves and applies the NIS client configuration in the give hash.
40 # Returns an error message if any, or undef on success.
41 sub save_client_config
42 {
43 # Save the config file
44 &open_tempfile(CONF, ">$config{'client_conf'}");
45 if ($_[0]->{'domain'}) {
46         if ($_[0]->{'broadcast'}) {
47                 &print_tempfile(CONF, "domain $_[0]->{'domain'} broadcast\n");
48                 }
49         else {
50                 local @s = @{$_[0]->{'servers'}};
51                 &print_tempfile(CONF, "domain $_[0]->{'domain'} server ",shift(@s),"\n");
52                 foreach $s (@s) {
53                         &print_tempfile(CONF, "ypserver $s\n");
54                         }
55                 }
56         }
57 &close_tempfile(CONF);
58
59 # Stop the init script
60 local $init = &init_script("ypbind");
61 if (!-r $init) { $init = &init_script("ypclient"); }
62 &system_logged("$init stop >/dev/null 2>&1");
63
64 # Save rc.config
65 local $rc = &parse_rc_config();
66 if ($_[0]->{'domain'}) {
67         &save_rc_config($rc, "START_YPBIND", "yes");
68         &save_rc_config($rc, "YP_DOMAINNAME", $_[0]->{'domain'});
69         if ($_[0]->{'broadcast'}) {
70                 &save_rc_config($rc, "YP_SERVER", "");
71                 }
72         else {
73                 &save_rc_config($rc, "YP_SERVER",
74                                 join(" ", @{$_[0]->{'servers'}}));
75                 }
76         &init::enable_at_boot("ypbind");
77         }
78 else {
79         &save_rc_config($rc, "START_YPBIND", "no");
80         }
81
82 # Start the init script
83 if ($_[0]->{'domain'}) {
84         local $out = &backquote_logged("$init start 2>&1");
85         if ($?) { return "<pre>$out</pre>"; }
86         }
87 return undef;
88 }
89
90 @nis_files = ( "passwd", "shadow", "group", "gshadow", "adjunct",
91                "aliases", "ethers", "bootparams", "hosts", "networks",
92                "printcap", "protocols", "publickeys", "rpc", "services",
93                "netgroup", "netid", "auto_master", "auto_home",
94                "auto_local", "timezone", "locale", "netmasks" );
95
96 @nis_tables = ( "passwd", "group", "hosts", "rpc", "services", "netid",
97                 "protocols", "netgrp", "mail", "shadow", "publickey",
98                 "networks", "ethers", "bootparams", "printcap", "amd.home",
99                 "auto.master", "auto.home", "auto.local", "passwd.adjunct",
100                 "timezone", "locale", "netmasks" );
101
102 # show_server_config()
103 # Display a form for editing NIS server options
104 sub show_server_config
105 {
106 local ($var, $rule) = &parse_yp_makefile();
107 local $rc = &parse_rc_config();
108 if ($var->{'YPPWDDIR'}->{'value'} =~ /^\$\(shell.*\s(\S+)\)$/) {
109         # Value comes from some rc.config file!
110         local $yrc = &parse_rc_config($1);
111         $var->{'YPPWDDIR'}->{'value'} = $yrc->{'YPPWD_SRCDIR'}->{'value'};
112         }
113
114 local $boot = &init::action_status("ypserv") == 2 &&
115               $rc->{'START_YPSERV'}->{'value'} eq 'yes';
116 print "<tr> <td><b>$text{'server_boot'}</b></td>\n";
117 printf "<td><input type=radio name=boot value=1 %s> %s\n",
118         $boot ? 'checked' : '', $text{'yes'};
119 printf "<input type=radio name=boot value=0 %s> %s</td>\n",
120         $boot ? '' : 'checked', $text{'no'};
121
122 local $dom = $var->{'LOCALDOMAIN'}->{'value'};
123 print "<td><b>$text{'server_domain'}</b></td>\n";
124 printf "<td><input type=radio name=domain_auto value=1 %s> %s\n",
125         $dom =~ /`.*domainname`/ ? 'checked' : '', $text{'server_domain_auto'};
126 printf "<input type=radio name=domain_auto value=0 %s>\n",
127         $dom =~ /`.*domainname`/ ? '' : 'checked';
128 printf "<input name=domain size=20 value='%s'></td> </tr>\n",
129         $dom =~ /`.*domainname`/ ? '' : $dom;
130
131 print "<tr> <td><b>$text{'server_type'}</b></td>\n";
132 printf "<td colspan=3><input type=radio name=type value=1 %s> %s\n",
133         $config{'slave'} ? '' : 'checked', $text{'server_master'};
134 printf "<input type=radio name=type value=0 %s> %s\n",
135         $config{'slave'} ? 'checked' : '', $text{'server_slave'};
136 printf "<input name=slave size=30 value='%s'></td> </tr>\n", $config{'slave'};
137
138 print "</table></td></tr></table><p>\n";
139 print "<table border width=100%>\n";
140 print "<tr $tb> <td><b>$text{'server_mheader'}</b></td> </tr>\n";
141 print "<tr $cb> <td><table width=100%>\n";
142
143 print "<tr> <td><b>$text{'server_dns'}</b></td>\n";
144 printf "<td><input type=radio name=b value='-b' %s> %s\n",
145         $var->{'B'}->{'value'} eq '-b' ? 'checked' : '', $text{'yes'};
146 printf "<input type=radio name=b value='' %s> %s</td>\n",
147         $var->{'B'}->{'value'} eq '-b' ? '' : 'checked', $text{'no'};
148
149 print "<td><b>$text{'server_push'}</b></td>\n";
150 printf "<td><input type=radio name=nopush value=false %s> %s\n",
151         $var->{'NOPUSH'}->{'value'} eq 'true' ? '' : 'checked', $text{'yes'};
152 printf "<input type=radio name=nopush value=true %s> %s</td> </tr>\n",
153         $var->{'NOPUSH'}->{'value'} eq 'true' ? 'checked' : '', $text{'no'};
154
155 local %inall;
156 map { $inall{$_}++ } split(/\s+/, $rule->{'all'}->{'value'});
157 print "<tr> <td rowspan=2 valign=top><b>$text{'server_tables'}</b></td>\n";
158 print "<td rowspan=2><select multiple size=5 name=tables>\n";
159 foreach $t (grep { $rule->{$_} } @nis_tables) {
160         printf "<option value=%s %s>%s\n",
161                 $t, $inall{$t} ? 'selected' : '', $t;
162         }
163 print "</select></td>\n";
164
165 print "<td><b>$text{'server_minuid'}</b></td>\n";
166 printf "<td><input name=minuid size=10 value='%s'></td> </tr>\n",
167         $var->{'MINUID'}->{'value'};
168
169 print "<td><b>$text{'server_mingid'}</b></td>\n";
170 printf "<td><input name=mingid size=10 value='%s'></td> </tr>\n",
171         $var->{'MINGID'}->{'value'};
172
173 print "<tr> <td><b>$text{'server_slaves'}</b></td>\n";
174 open(SLAVES, "/var/yp/ypservers");
175 while(<SLAVES>) {
176         s/\s//g;
177         push(@slaves, $_) if ($_);
178         }
179 close(SLAVES);
180 printf "<td colspan=3><input name=slaves size=60 value='%s'></td> </tr>\n",
181         join(" ", @slaves);
182
183 print "</table></td></tr></table><p>\n";
184 print "<table border width=100%>\n";
185 print "<tr $tb> <td><b>$text{'server_fheader'}</b></td> </tr>\n";
186 print "<tr $cb> <td><table width=100%>\n";
187
188 local $i = 0;
189 foreach $t (@nis_files) {
190         local $f = &expand_vars($var->{uc($t)}->{'value'}, $var);
191         next if (!$f);
192         print "<tr>\n" if ($i%2 == 0);
193         print "<td><b>",&text('server_file', $text{"desc_$t"} ? $text{"desc_$t"}
194                                                               : $t),"</b></td>\n";
195         print "<td><input name=$t size=30 value='$f'></td>\n";
196         print "</tr>\n" if ($i++%2 == 1);
197         }
198 }
199
200 # parse_server_config()
201 # Parse and save the NIS server options
202 sub parse_server_config
203 {
204 local ($var, $rule) = &parse_yp_makefile();
205 local $rc = &parse_rc_config();
206 if ($var->{'YPPWDDIR'}->{'value'} =~ /^\$\(shell.*\s(\S+)\)$/) {
207         # Value comes from some rc.config file!
208         local $yrc = &parse_rc_config($1);
209         $var->{'YPPWDDIR'}->{'value'} = $yrc->{'YPPWD_SRCDIR'}->{'value'};
210         }
211
212 $in{'minuid'} =~ /^\d+$/ || &error($text{'server_eminuid'});
213 $in{'mingid'} =~ /^\d+$/ || &error($text{'server_emingid'});
214 $in{'domain_auto'} || $in{'domain'} =~ /^[A-Za-z0-9\.\-]+$/ ||
215         &error($text{'server_edomain'});
216 $in{'type'} || &to_ipaddress($in{'slave'}) ||
217         &to_ip6address($in{'slave'}) || &error($text{'server_eslave'});
218 &update_makefile($var->{'MINUID'}, $in{'minuid'});
219 &update_makefile($var->{'MINGID'}, $in{'mingid'});
220 &update_makefile($var->{'NOPUSH'}, $in{'nopush'});
221 &update_makefile($var->{'B'}, $in{'b'});
222 &update_makefile($var->{'LOCALDOMAIN'}, $in{'domain_auto'} ? "`domainname`"
223                                                            : $in{'domain'});
224 &update_makefile($rule->{'all'}, join(" ", split(/\0/, $in{'tables'})), "");
225
226 foreach $t (@nis_files) {
227         local $old = &expand_vars($var->{uc($t)}->{'value'}, $var);
228         next if (!$old);
229         if ($old ne $in{$t}) {
230                 $in{$t} =~ /\S/ || &error(&text('server_efile', $text{"desc_$t"}));
231                 &update_makefile($var->{uc($t)}, $in{$t});
232                 }
233         }
234 &flush_file_lines();
235
236 &open_tempfile(SLAVES, ">/var/yp/ypservers");
237 foreach $s (split(/\s+/, $in{'slaves'})) {
238         &print_tempfile(SLAVES, "$s\n");
239         }
240 &close_tempfile(SLAVES);
241
242 local $init1 = &init_script("ypserv");
243 local $init2 = &init_script("yppasswdd");
244 &system_logged("$init1 stop >/dev/null 2>&1");
245 &system_logged("$init2 stop >/dev/null 2>&1");
246 if ($in{'boot'}) {
247         &init::enable_at_boot("ypserv");
248         &init::enable_at_boot("yppasswdd");
249         &save_rc_config($rc, "START_YPSERV", "yes");
250         &save_rc_config($rc, "START_YPPASSWDD", "yes");
251         }
252 else {
253         &save_rc_config($rc, "START_YPSERV", "no");
254         &save_rc_config($rc, "START_YPPASSWDD", "no");
255         }
256 if ($in{'boot'}) {
257         &system_logged("$init1 start >/dev/null 2>&1");
258         &system_logged("$init2 start >/dev/null 2>&1");
259         }
260 if ($in{'type'}) {
261         # Master server
262         delete($config{'slave'});
263         &apply_table_changes() if ($in{'boot'});
264         }
265 else {
266         $out = &backquote_logged("/usr/lib/yp/ypinit -s $in{'slave'} 2>&1");
267         if ($?) { &error("<tt>$out</tt>"); }
268         $config{'slave'} = $in{'slave'};
269         }
270 &write_file("$module_config_directory/config", \%config);
271 }
272
273 # get_server_mode()
274 # Returns 0 if the NIS server is inactive, 1 if active as a master, or 2 if
275 # active as a slave.
276 sub get_server_mode
277 {
278 if (&init::action_status("ypserv") != 2) {
279         return 0;
280         }
281 elsif ($config{'slave'}) {
282         return 2;
283         }
284 else {
285         return 1;
286         }
287 }
288
289 # list_nis_tables()
290 # Returns a list of structures of all NIS tables
291 sub list_nis_tables
292 {
293 local ($var, $rule) = &parse_yp_makefile();
294 if ($var->{'YPPWDDIR'}->{'value'} =~ /^\$\(shell.*\s(\S+)\)$/) {
295         # Value comes from some rc.config file!
296         local $yrc = &parse_rc_config($1);
297         $var->{'YPPWDDIR'}->{'value'} = $yrc->{'YPPWD_SRCDIR'}->{'value'};
298         }
299 local @rv;
300 local $dom = $var->{'LOCALDOMAIN'}->{'value'};
301 chop($dom = `domainname`) if ($dom =~ /`.*domainname`/);
302 local %file;
303 map { $file{uc($_)} = &expand_vars($var->{uc($_)}->{'value'}, $var) } @nis_files;
304 local @all = split(/\s+/, $rule->{'all'}->{'value'});
305 foreach $t (@all) {
306         local $table = { 'table' => $t,
307                          'index' => scalar(@rv),
308                          'domain' => $dom };
309         if ($t eq "passwd") {
310                 if ($var->{'MERGE_PASSWD'}->{'value'} eq 'true') {
311                         $table->{'type'} = 'passwd_shadow';
312                         $table->{'files'} = [ $file{'PASSWD'}, $file{'SHADOW'} ];
313                         }
314                 elsif (&indexof('shadow', @all) >= 0) {
315                         # Show separate shadow and passwd tables as one table
316                         $table->{'type'} = 'passwd_shadow_full';
317                         $table->{'files'} = [ $file{'PASSWD'}, $file{'SHADOW'} ];
318                         @all = grep { $_ ne 'shadow' } @all;
319                         }
320                 else {
321                         $table->{'type'} = 'passwd';
322                         $table->{'files'} = [ $file{'PASSWD'} ];
323                         }
324                 }
325         elsif ($t eq "group") {
326                 if ($var->{'MERGE_GROUP'}->{'value'} eq 'true') {
327                         $table->{'type'} = 'group_shadow';
328                         $table->{'files'} = [ $file{'GROUP'}, $file{'GSHADOW'} ];
329                         }
330                 else {
331                         $table->{'type'} = 'group';
332                         $table->{'files'} = [ $file{'GROUP'} ];
333                         }
334                 }
335         elsif ($t eq "netgrp") {
336                 $table->{'type'} = "netgroup";
337                 $table->{'files'} = [ $file{'NETGROUP'} ];
338                 }
339         elsif ($t eq "mail") {
340                 $table->{'type'} = "aliases";
341                 $table->{'files'} = [ $file{'ALIASES'} ];
342                 }
343         else {
344                 $table->{'type'} = $t;
345                 $table->{'files'} = [ $file{uc($t)} ];
346                 }
347         push(@rv, $table);
348         }
349 return @rv;
350 }
351
352 # apply_table_changes()
353 # Do whatever is necessary for the table text files to be loaded into
354 # the NIS server
355 sub apply_table_changes
356 {
357 &system_logged("(cd /var/yp ; make) >/dev/null 2>&1 </dev/null");
358 }
359
360 # parse_rc_config([filename])
361 sub parse_rc_config
362 {
363 local $rc;
364 local $lnum = 0;
365 local $f = $_[0] ? $_[0] : $rc_config;
366 open(CONF, $f);
367 while(<CONF>) {
368         s/\r|\n//g;
369         s/#.*$//g;
370         if (/([^=\s]+)="(.*)"/) {
371                 $rc->{$1} = { 'value' => $2,
372                               'line' => $lnum };
373                 }
374         elsif (/([^=\s]+)=(\S+)/) {
375                 $rc->{$1} = { 'value' => $2,
376                               'line' => $lnum };
377                 }
378         $lnum++;
379         }
380 close(CONF);
381 return $rc;
382 }
383
384 # save_rc_config(&config, directive, value)
385 sub save_rc_config
386 {
387 local $old = $_[0]->{$_[1]};
388 local $line = "$_[1]=\"$_[2]\"\n";
389 if ($old) {
390         &replace_file_line($rc_config, $old->{'line'}, $line);
391         }
392 else {
393         &open_tempfile(RC, ">>$rc_config");
394         &print_tempfile(RC, $line);
395         &close_tempfile(RC);
396         }
397 }
398
399 sub extra_config_files
400 {
401 return ( $rc_config, "/var/yp/ypservers" );
402 }
403
404 1;
405