Handle hostnames with upper-case letters
[webmin.git] / cluster-webmin / save_user.cgi
1 #!/usr/local/bin/perl
2 # save_user.cgi
3 # Update a webmin user on all servers
4
5 require './cluster-webmin-lib.pl';
6 &ReadParse();
7 &ui_print_header(undef, $text{'user_title2'}, "");
8 print "<b>",&text('user_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('user_ename', $in{'name'}));
20 $in{'name'} ne $in{'old'} && $taken{$in{'name'}} &&
21         &error(&text('user_etaken', $in{'name'}));
22 $in{'pass_def'} == 0 && $in{'pass'} =~ /:/ && &error($text{'user_ecolon'});
23 if ($in{'ipmode'} > 0) {
24         @ips = split(/\s+/, $in{'ips'});
25         }
26
27 # Setup error handler for down hosts
28 sub user_error
29 {
30 $user_error_msg = join("", @_);
31 }
32 &remote_error_setup(\&user_error);
33
34 # Update the user on all servers that have him
35 foreach $h (@allhosts) {
36         foreach $u (@{$h->{'users'}}) {
37                 if ($u->{'name'} eq $in{'old'}) {
38                         push(@hosts, $h);
39                         last;
40                         }
41                 }
42         }
43 @servers = &list_servers();
44 $p = 0;
45 foreach $h (@hosts) {
46         local ($s) = grep { $_->{'id'} == $h->{'id'} } @servers;
47         local ($rh = "READ$p", $wh = "WRITE$p");
48         pipe($rh, $wh);
49         if (!fork()) {
50                 close($rh);
51                 &remote_foreign_require($s->{'host'}, "acl", "acl-lib.pl");
52                 if ($user_error_msg) {
53                         # Host is down
54                         print $wh &serialise_variable([ 0, $user_error_msg ]);
55                         exit;
56                         }
57
58                 # Update the user
59                 ($user) = grep { $_->{'name'} eq $in{'old'} } @{$h->{'users'}};
60                 $user->{'name'} = $in{'name'};
61                 if (!$in{'lang_def'}) {
62                         $user->{'lang'} = $in{'lang'} ? $in{'lang'} : undef;
63                         }
64                 if (!$in{'theme_def'}) {
65                         if ($in{'theme'} eq 'webmin') {
66                                 delete($user->{'theme'});
67                                 }
68                         else {
69                                 $user->{'theme'} = $in{'theme'};
70                                 }
71                         }
72                 if ($in{'ipmode'} == 0) {
73                         delete($user->{'allow'});
74                         delete($user->{'deny'});
75                         }
76                 elsif ($in{'ipmode'} == 1) {
77                         $user->{'allow'} = join(" ", @ips);
78                         delete($user->{'deny'});
79                         }
80                 elsif ($in{'ipmode'} == 2) {
81                         delete($user->{'allow'});
82                         $user->{'deny'} = join(" ", @ips);
83                         }
84                 if ($in{'pass_def'} == 0) {
85                         $salt = chr(int(rand(26))+65).chr(int(rand(26))+65);
86                         $user->{'pass'} = &unix_crypt($in{'pass'}, $salt);
87                         $user->{'sync'} = 0;
88                         }
89                 elsif ($in{'pass_def'} == 3) {
90                         $user->{'pass'} = 'x';
91                         $user->{'sync'} = 0;
92                         }
93                 elsif ($in{'pass_def'} == 4) {
94                         $user->{'pass'} = '*LK*';
95                         $user->{'sync'} = 0;
96                         }
97                 elsif ($in{'pass_def'} == 5) {
98                         $user->{'pass'} = 'e';
99                         $user->{'sync'} = 0;
100                         }
101
102                 # Save module categorization setting
103                 $user->{'notabs'} = $in{'notabs'};
104
105                 # Work out which modules the user has
106                 local @selmods = ( split(/\0/, $in{'mods1'}),
107                                    split(/\0/, $in{'mods2'}),
108                                    split(/\0/, $in{'mods3'}) );
109                 local @mods = @{$user->{'modules'}};
110                 if ($in{'mods_def'} == 2) {
111                         @mods = @selmods;
112                         }
113                 elsif ($in{'mods_def'} == 3) {
114                         @mods = &unique(@mods, @selmods);
115                         }
116                 elsif ($in{'mods_def'} == 0) {
117                         @mods = grep { &indexof($_, @selmods) < 0 } @mods;
118                         }
119
120                 # Update old and new groups
121                 foreach $g (@{$h->{'groups'}}) {
122                         if (&indexof($in{'old'}, @{$g->{'members'}}) >= 0) {
123                                 $oldgroup = $g;
124                                 }
125                         }
126                 if ($in{'group_def'}) {
127                         $group = $oldgroup;
128                         }
129                 else {
130                         ($group) = grep { $_->{'name'} eq $in{'group'} }
131                                         @{$h->{'groups'}};
132                         if (!$group && $in{'group'}) {
133                                 print $wh &serialise_variable(
134                                         [ 0, $text{'user_egroup'} ]);
135                                 exit;
136                                 }
137                         }
138                 if (($group ? $group->{'name'} : '') ne
139                     ($oldgroup ? $oldgroup->{'name'} : '')) {
140                         # Group has changed - update the member lists
141                         if ($oldgroup) {
142                                 $oldgroup->{'members'} =
143                                         [ grep { $_ ne $in{'old'} }
144                                                @{$oldgroup->{'members'}} ];
145                                 &remote_foreign_call($s->{'host'}, "acl",
146                                     "modify_group", $oldgroup->{'name'}, $oldgroup);
147                                 }
148                         if ($group) {
149                                 push(@{$group->{'members'}}, $in{'name'});
150                                 &remote_foreign_call($s->{'host'}, "acl",
151                                     "modify_group", $group->{'name'}, $group);
152                                 }
153                         }
154
155                 if ($oldgroup) {
156                         # Remove modules from the old group
157                         @mods = grep { &indexof($_, @{$oldgroup->{'modules'}}) < 0 }
158                                      @mods;
159                         }
160
161                 @ownmods = ( );
162                 if ($group) {
163                         # Add modules from new group
164                         foreach $m (@mods) {
165                                 push(@ownmods, $m)
166                                     if (&indexof($m, @{$group->{'modules'}}) < 0);
167                                 }
168                         @mods = &unique(@mods, @{$group->{'modules'}});
169                         &remote_foreign_call($s->{'host'}, "acl",
170                                 "copy_acl_files", $group->{'name'}, $in{'old'},
171                                 [ @{$group->{'modules'}}, "" ]);
172                         }
173
174                 $user->{'modules'} = \@mods;
175                 $user->{'ownmods'} = \@ownmods;
176                 &remote_foreign_call($s->{'host'}, "acl", "modify_user",
177                                      $in{'old'}, $user);
178                 &save_webmin_host($h);
179
180                 # Restart the remote webmin
181                 print $wh &serialise_variable([ 1 ]);
182                 &remote_foreign_call($s->{'host'}, "acl", "restart_miniserv");
183                 exit;
184                 }
185         close($wh);
186         $p++;
187         }
188
189 # Read back the results
190 $p = 0;
191 foreach $h (@hosts) {
192         local ($s) = grep { $_->{'id'} == $h->{'id'} } @servers;
193         local $d = &server_name($s);
194         local $rh = "READ$p";
195         local $line = <$rh>;
196         local $rv = &unserialise_variable($line);
197         close($rh);
198
199         if ($rv && $rv->[0] == 1) {
200                 # It worked
201                 print &text('user_success2', $d),"<br>\n";
202                 }
203         else {
204                 # Something went wrong
205                 print &text('user_failed2', $d, $rv->[1]),"<br>\n";
206                 }
207         $p++;
208         }
209
210 print "<p><b>$text{'user_done'}</b><p>\n";
211
212 &remote_finished();
213 &ui_print_footer("", $text{'index_return'});
214