Handle hostnames with upper-case letters
[webmin.git] / cluster-webmin / save_group.cgi
1 #!/usr/local/bin/perl
2 # save_group.cgi
3 # Update a webmin group on all servers
4
5 require './cluster-webmin-lib.pl';
6 &ReadParse();
7 &ui_print_header(undef, $text{'group_title2'}, "");
8 print "<b>",&text('group_doing2', $in{'old'}),"</b><p>\n";
9
10 @allhosts = &list_webmin_hosts();
11 foreach $h (@allhosts) {
12         foreach $ug (@{$h->{'users'}}, @{$h->{'groups'}}) {
13                 $taken{$ug->{'name'}}++;
14                 }
15         }
16
17 # Validate inputs
18 $in{'name'} =~ /^[A-z0-9\-\_\.\@]+$/ ||
19         &error(&text('group_ename', $in{'name'}));
20 $in{'name'} ne $in{'old'} && $taken{$in{'name'}} &&
21         &error(&text('group_etaken', $in{'name'}));
22
23 # Setup error handler for down hosts
24 sub group_error
25 {
26 $group_error_msg = join("", @_);
27 }
28 &remote_error_setup(\&group_error);
29
30 # Update the group on all servers that have it
31 foreach $h (@allhosts) {
32         foreach $g (@{$h->{'groups'}}) {
33                 if ($g->{'name'} eq $in{'old'}) {
34                         push(@hosts, $h);
35                         last;
36                         }
37                 }
38         }
39 @servers = &list_servers();
40 $p = 0;
41 foreach $h (@hosts) {
42         local ($s) = grep { $_->{'id'} == $h->{'id'} } @servers;
43         local ($rh = "READ$p", $wh = "WRITE$p");
44         pipe($rh, $wh);
45         if (!fork()) {
46                 close($rh);
47                 &remote_foreign_require($s->{'host'}, "acl", "acl-lib.pl");
48                 if ($group_error_msg) {
49                         # Host is down
50                         print $wh &serialise_variable([ 0, $group_error_msg ]);
51                         exit;
52                         }
53
54                 # Update the user
55                 ($edgrp) = grep { $_->{'name'} eq $in{'old'} } @{$h->{'groups'}};
56                 $edgrp->{'name'} = $in{'name'};
57
58                 # Work out which modules the group has
59                 local @selmods = ( split(/\0/, $in{'mods1'}),
60                                    split(/\0/, $in{'mods2'}),
61                                    split(/\0/, $in{'mods3'}) );
62                 local @mods = @{$edgrp->{'modules'}};
63                 if ($in{'mods_def'} == 2) {
64                         @mods = @selmods;
65                         }
66                 elsif ($in{'mods_def'} == 3) {
67                         @mods = &unique(@mods, @selmods);
68                         }
69                 elsif ($in{'mods_def'} == 0) {
70                         @mods = grep { &indexof($_, @selmods) < 0 } @mods;
71                         }
72
73                 # Update old and new parent groups
74                 foreach $g (@{$h->{'groups'}}) {
75                         if (&indexof($in{'old'}, @{$g->{'members'}}) >= 0) {
76                                 $oldgroup = $g;
77                                 }
78                         }
79                 if ($in{'group_def'}) {
80                         $group = $oldgroup;
81                         }
82                 else {
83                         ($group) = grep { $_->{'name'} eq $in{'group'} }
84                                         @{$h->{'groups'}};
85                         if (!$group && $in{'group'}) {
86                                 print $wh &serialise_variable(
87                                         [ 0, $text{'group_egroup'} ]);
88                                 exit;
89                                 }
90                         }
91                 if (($group ? $group->{'name'} : '') ne
92                     ($oldgroup ? $oldgroup->{'name'} : '')) {
93                         # Parent group has changed - update the member lists
94                         if ($oldgroup) {
95                                 $oldgroup->{'members'} =
96                                         [ grep { $_ ne $in{'old'} }
97                                                @{$oldgroup->{'members'}} ];
98                                 &remote_foreign_call($s->{'host'}, "acl",
99                                     "modify_group", $oldgroup->{'name'}, $oldgroup);
100                                 }
101                         if ($group) {
102                                 push(@{$group->{'members'}}, $in{'name'});
103                                 &remote_foreign_call($s->{'host'}, "acl",
104                                     "modify_group", $group->{'name'}, $group);
105                                 }
106                         }
107
108                 if ($oldgroup) {
109                         # Remove modules from the old group
110                         @mods = grep { &indexof($_, @{$oldgroup->{'modules'}}) < 0 }
111                                      @mods;
112                         }
113
114                 @ownmods = ( );
115                 if ($group) {
116                         # Add modules from new group
117                         foreach $m (@mods) {
118                                 push(@ownmods, $m)
119                                     if (&indexof($m, @{$group->{'modules'}}) < 0);
120                                 }
121                         @mods = &unique(@mods, @{$group->{'modules'}});
122                         &remote_foreign_call($s->{'host'}, "acl",
123                                 "copy_acl_files", $group->{'name'}, $in{'old'},
124                                 [ @{$group->{'modules'}}, "" ]);
125                         }
126
127                 $edgrp->{'modules'} = \@mods;
128                 $edgrp->{'ownmods'} = \@ownmods;
129                 &remote_foreign_call($s->{'host'}, "acl", "modify_group",
130                                      $in{'old'}, $edgrp);
131
132                 # Recursively update all member users and groups
133                 &remote_foreign_call($s->{'host'}, "acl", "update_members",
134                                      $h->{'users'}, $h->{'groups'},
135                                      $edgrp->{'modules'}, $edgrp->{'members'});
136                 @freshusers = &remote_foreign_call($s->{'host'}, "acl",
137                                                    "list_users");
138                 $h->{'users'} = \@freshusers;
139                 @freshgroups = &remote_foreign_call($s->{'host'}, "acl",
140                                                     "list_groups");
141                 $h->{'groups'} = \@freshgroups;
142                 &save_webmin_host($h);
143
144                 # Restart the remote webmin
145                 print $wh &serialise_variable([ 1 ]);
146                 &remote_foreign_call($s->{'host'}, "acl", "restart_miniserv");
147                 exit;
148                 }
149         close($wh);
150         $p++;
151         }
152
153 # Read back the results
154 $p = 0;
155 foreach $h (@hosts) {
156         local ($s) = grep { $_->{'id'} == $h->{'id'} } @servers;
157         local $d = &server_name($s);
158         local $rh = "READ$p";
159         local $line = <$rh>;
160         local $rv = &unserialise_variable($line);
161         close($rh);
162
163         if ($rv && $rv->[0] == 1) {
164                 # It worked
165                 print &text('group_success2', $d),"<br>\n";
166                 }
167         else {
168                 # Something went wrong
169                 print &text('group_failed2', $d, $rv->[1]),"<br>\n";
170                 }
171         $p++;
172         }
173
174 print "<p><b>$text{'group_done'}</b><p>\n";
175
176 &remote_finished();
177 &ui_print_footer("", $text{'index_return'});
178