3 # Updates an existing user across multiple servers
5 require './cluster-useradmin-lib.pl';
6 require 'timelocal.pl';
7 &error_setup($text{'usave_err'});
9 &foreign_require("useradmin", "user-lib.pl");
11 # Strip out \n characters in inputs
12 $in{'real'} =~ s/\r|\n//g;
13 $in{'user'} =~ s/\r|\n//g;
14 $in{'pass'} =~ s/\r|\n//g;
15 $in{'encpass'} =~ s/\r|\n//g;
16 $in{'home'} =~ s/\r|\n//g;
17 $in{'gid'} =~ s/\r|\n//g;
18 $in{'uid'} =~ s/\r|\n//g;
19 $in{'othersh'} =~ s/\r|\n//g;
22 $user{'user'} = $in{'user'};
23 $in{'user'} =~ /^[^:\t]+$/ ||
24 &error(&text('usave_ebadname', $in{'user'}));
25 $err = &useradmin::check_username_restrictions($in{'user'});
26 &error($err) if ($err);
28 # Get host and old user
29 @hosts = &list_useradmin_hosts();
30 @servers = &list_servers();
31 ($host) = grep { $_->{'id'} == $in{'id'} } @hosts;
32 if ($in{'user'} ne $in{'olduser'}) {
33 # Renaming .. check for clash
35 local $ou = grep { $_->{'user'} eq $in{'olduser'} }
37 local $nu = grep { $_->{'user'} eq $in{'user'} }
39 local ($serv) = grep { $_->{'id'} == $h->{'id'} } @servers;
40 &error(&text('usave_einuse', $serv->{'host'})) if ($ou && $nu)
44 # Validate basic inputs
45 $in{'uid_def'} || $in{'uid'} =~ /^[0-9]+$/ ||
46 &error(&text('usave_euid', $in{'uid'}));
47 $in{'real_def'} || $in{'real'} =~ /^[^:]*$/ ||
48 &error(&text('usave_ereal', $in{'real'}));
49 $in{'gid_def'} || defined(getgrnam($in{'gid'})) ||
50 &error(&text('usave_egid', $in{'gid'}));
51 if ($uconfig{'extra_real'}) {
52 $in{'office_def'} || $in{'office'} =~ /^[^:]*$/ ||
53 &error($text{'usave_eoffice'});
54 $in{'workph_def'} || $in{'workph'} =~ /^[^:]*$/ ||
55 &error($text{'usave_eworkph'});
56 $in{'homeph_def'} || $in{'homeph'} =~ /^[^:]*$/ ||
57 &error($text{'usave_ehomeph'});
59 $in{'home_def'} || $in{'home'} =~ /^\// ||
60 &error(&text('usave_ehome', $in{'home'}));
63 if ($in{'passmode'} == 3) {
64 local $err = &useradmin::check_password_restrictions(
65 $in{'pass'}, $user{'user'});
66 &error($err) if ($err);
69 $pft = &foreign_call("useradmin", "passfiles_type");
71 # Validate shadow-password inputs
72 if (!$in{'expire_def'} && $in{'expired'} ne "" &&
73 $in{'expirem'} ne "" && $in{'expirey'} ne "") {
74 eval { $expire = timelocal(0, 0, 12, $in{'expired'},
76 $in{'expirey'}-1900); };
77 if ($@) { &error($text{'usave_eexpire'}); }
78 $expire = int($expire / (60*60*24));
80 else { $expire = ""; }
81 $in{'min_def'} || $in{'min'} =~ /^[0-9]*$/ ||
82 &error(&text('usave_emin', $in{'min'}));
83 $in{'max_def'} || $in{'max'} =~ /^[0-9]*$/ ||
84 &error(&text('usave_emax', $in{'max'}));
85 $in{'warn_def'} || $in{'warn'} =~ /^[0-9]*$/ ||
86 &error(&text('usave_ewarn', $in{'warn'}));
87 $in{'inactive_def'} || $in{'inactive'} =~ /^[0-9]*$/ ||
88 &error(&text('usave_einactive', $in{'inactive'}));
90 elsif ($pft == 1 || $pft == 6) {
91 # Validate BSD password inputs
92 if (!$in{'expire_def'} && $in{'expired'} ne "" &&
93 $in{'expirem'} ne "" && $in{'expirey'} ne "") {
94 eval { $expire = timelocal(59, $in{'expiremi'},
98 $in{'expirey'}-1900); };
99 if ($@) { &error($text{'usave_eexpire'}); }
101 else { $expire = ""; }
102 if (!$in{'change_def'} && $in{'changed'} ne "" &&
103 $in{'changem'} ne "" && $in{'changey'} ne "") {
104 eval { $change = timelocal(59, $in{'changemi'},
108 $in{'changey'}-1900); };
109 if ($@) { &error($text{'usave_echange'}); }
111 else { $change = ""; }
112 $in{'class_def'} || $in{'class'} =~ /^([^: ]*)$/ ||
113 &error(&text('usave_eclass', $in{'class'}));
116 # Validate AIX password inputs
117 if (!$in{'expire_def'} && $in{'expired'} ne "" && $in{'expirem'} ne ""
118 && $in{'expirey'} ne "" ) {
119 # Add a leading zero if only 1 digit long
120 $in{'expirem'} =~ s/^(\d)$/0$1/;
121 $in{'expired'} =~ s/^(\d)$/0$1/;
122 $in{'expireh'} =~ s/^(\d)$/0$1/;
123 $in{'expiremi'} =~ s/^(\d)$/0$1/;
125 # Only use the last two digits of the year
126 $in{'expirey'} =~ s/^\d\d(\d\d)$/$1/;
128 # If the user didn't choose the hour and min make them 01
129 $in{'expireh'} = "01" if $in{'expireh'} eq "";
130 $in{'expiremi'} = "01" if $in{'expiremi'} eq "";
131 $expire="$in{'expirem'}$in{'expired'}$in{'expireh'}$in{'expiremi'}$in{'expirey'}";
133 else { $expire = ""; }
137 foreach $h (@hosts) {
138 map { $hasgroup{$_->{'group'}}++ } @{$h->{'groups'}};
140 @check = $in{'sgid_def'} == 1 ? split(/\s+/, $in{'sgidadd'}) :
141 $in{'sgid_def'} == 2 ? split(/\s+/, $in{'sgiddel'}) : ( );
142 foreach $c (@check) {
143 $hasgroup{$c} || &error(&text('usave_esecgid', $c));
146 # Setup error handler for down hosts
149 $mod_error_msg = join("", @_);
151 &remote_error_setup(\&mod_error);
153 # Do the changes across all hosts
154 &ui_print_header(undef, $text{'uedit_title'}, "");
155 $crypted = &foreign_call("useradmin", "encrypt_password", $in{'pass'});
156 foreach $host (@hosts) {
157 $mod_error_msg = undef;
158 ($user) = grep { $_->{'user'} eq $in{'olduser'} } @{$host->{'users'}};
160 local ($serv) = grep { $_->{'id'} == $host->{'id'} } @servers;
161 print "<b>",&text('usave_uon', $serv->{'desc'} ? $serv->{'desc'} :
162 $serv->{'host'}),"</b><p>\n";
164 &remote_foreign_require($serv->{'host'}, "useradmin", "user-lib.pl");
165 if ($mod_error_msg) {
167 print &text('usave_failed', $mod_error_msg),"<p>\n";
171 local @ulist = &remote_foreign_call($serv->{'host'}, "useradmin",
173 ($user) = grep { $_->{'user'} eq $in{'olduser'} } @ulist;
176 print "$text{'usave_gone'}<p>\n";
180 local %ouser = %$user;
182 # Update changed fields
183 $user->{'user'} = $in{'user'};
184 $user->{'olduser'} = $ouser{'user'};
185 $user->{'uid'} = $in{'uid'} if (!$in{'uid_def'});
186 if ($uconfig{'extra_real'}) {
187 local @real = split(/,/, $user->{'real'});
188 $real[0] = $in{'real'} if (!$in{'real_def'});
189 $real[1] = $in{'office'} if (!$in{'office_def'});
190 $real[2] = $in{'workph'} if (!$in{'workph_def'});
191 $real[3] = $in{'homeph'} if (!$in{'homeph_def'});
192 $real[4] = $in{'extra'} if (!$in{'extra_def'});
193 $user->{'real'} = join(",", @real);
196 $user->{'real'} = $in{'real'} if (!$in{'real_def'});
198 if ($in{'home_def'} == 2) {
199 $user->{'home'} = &auto_home_dir($uconfig{'home_base'},
202 elsif ($in{'home_def'} == 0) {
203 $user->{'home'} = $in{'home'};
205 $user->{'shell'} = $in{'shell'} if (!$in{'shell_def'});
206 if ($in{'passmode'} == 0) {
207 $user->{'pass'} = "";
209 elsif ($in{'passmode'} == 1) {
210 $user->{'pass'} = $uconfig{'lock_string'};
212 elsif ($in{'passmode'} == 2) {
213 $user->{'pass'} = $in{'encpass'};
215 elsif ($in{'passmode'} == 3) {
216 $user->{'pass'} = $crypted;
218 $user->{'passmode'} = $in{'passmode'} < 0 ? 2 : $in{'passmode'};
219 $user->{'gid'} = getgrnam($in{'gid'}) if (!$in{'gid_def'});
221 if ($pft == 1 || $pft == 6) {
222 # Save BSD password inputs
223 $user->{'expire'} = $expire if (!$in{'expire_def'});
224 $user->{'change'} = $change if (!$in{'change_def'});
225 $user->{'class'} = $in{'class'} if (!$in{'class_def'});
228 # Save shadow password inputs
229 $user->{'min'} = $in{'min'} if (!$in{'min_def'});
230 $user->{'max'} = $in{'max'} if (!$in{'max_def'});
231 $user->{'warn'} = $in{'warn'} if (!$in{'warn_def'});
232 $user->{'inactive'} = $in{'inactive'} if (!$in{'inactive_def'});
233 $user->{'expire'} = $expire if (!$in{'expire_def'});
234 $user->{'change'} = 0 if ($in{'forcechange'});
237 # Save AIX password inputs
238 if (!$in{'flags_def'}) {
239 $user->{'admin'} = $in{'flags'} =~ /admin/;
240 $user->{'admchg'} = $in{'flags'} =~ /admchg/;
241 $user->{'nocheck'} = $in{'flags'} =~ /nocheck/;
243 $user->{'expire'} = $expire if (!$in{'expire_def'});
244 $user->{'min'} = $in{'min'} if (!$in{'min_def'});
245 $user->{'max'} = $in{'max'} if (!$in{'max_def'});
246 $user->{'warn'} = $in{'warn'} if (!$in{'warn_def'});
249 # Run the pre-change command
250 $envpass = $in{'passmode'} == 3 ? $in{'pass'} : undef;
251 &remote_eval($serv->{'host'}, "useradmin", <<EOF
252 \$ENV{'USERADMIN_USER'} = '$user->{'user'}';
253 \$ENV{'USERADMIN_UID'} = '$user->{'uid'}';
254 \$ENV{'USERADMIN_REAL'} = '$user->{'real'}';
255 \$ENV{'USERADMIN_SHELL'} = '$user->{'shell'}';
256 \$ENV{'USERADMIN_HOME'} = '$user->{'home'}';
257 \$ENV{'USERADMIN_GID'} = '$user->{'gid'}';
258 \$ENV{'USERADMIN_PASS'} = '$envpass';
259 \$ENV{'USERADMIN_ACTION'} = 'MODIFY_USER';
262 $merr = &remote_foreign_call($serv->{'host'}, "useradmin",
264 if (defined($merr)) {
265 print &text('usave_emaking', "<tt>$merr</tt>"),"<p>\n";
270 # Update the user on the server
271 print "$text{'usave_update'}<br>\n";
272 &remote_foreign_call($serv->{'host'}, "useradmin", "modify_user",
274 print "$text{'udel_done'}<p>\n";
277 if ($in{'servs'} || $host eq $hosts[0]) {
278 if ($ouser{'home'} ne $user->{'home'} && $in{'movehome'}) {
279 print "$text{'usave_move'}<br>\n";
280 &remote_eval($serv->{'host'}, "useradmin",
281 "-d '$ouser{'home'}' && !-e '$user->{'home'}' && system(\"mv -f '$ouser{'home'}' '$user->{'home'}'\")");
282 print "$text{'udel_done'}<p>\n";
284 if ($ouser{'gid'} ne $user->{'gid'}) {
285 if ($in{'chgid'} == 1) {
286 print "$text{'usave_gid'}<br>\n";
287 &remote_foreign_call(
288 $serv->{'host'}, "useradmin",
289 "recursive_change", $user->{'home'},
290 $ouser{'uid'}, $ouser{'gid'}, -1,
292 print "$text{'udel_done'}<p>\n";
295 print "$text{'usave_gid'}<br>\n";
296 &remote_foreign_call(
297 $serv->{'host'}, "useradmin",
298 "recursive_change", "/",
299 $ouser{'uid'}, $ouser{'gid'}, -1,
301 print "$text{'udel_done'}<p>\n";
304 if ($ouser{'uid'} ne $user->{'uid'}) {
305 if ($in{'chuid'} == 1) {
306 print "$text{'usave_uid'}<br>\n";
307 &remote_foreign_call(
308 $serv->{'host'}, "useradmin",
309 "recursive_change", $user->{'home'},
312 print "$text{'udel_done'}<p>\n";
315 print "$text{'usave_uid'}<br>\n";
316 &remote_foreign_call(
317 $serv->{'host'}, "useradmin",
318 "recursive_change", "/",
321 print "$text{'udel_done'}<p>\n";
326 # Rename user in secondary groups
328 if ($in{'sgid_def'} || $user->{'user'} ne $ouser{'user'}) {
329 @glist = &remote_foreign_call($serv->{'host'}, "useradmin",
332 if ($user->{'user'} ne $ouser{'user'}) {
333 print "$text{'usave_rgroups'}<br>\n";
334 foreach $group (@glist) {
335 local @mems = split(/,/, $group->{'members'});
336 local $idx = &indexof($ouser{'user'}, @mems);
338 local %ogroup = %$group;
339 $mems[$idx] = $user->{'user'};
340 $group->{'members'} = join(",", @mems);
341 &remote_foreign_call($serv->{'host'},
342 "useradmin", "modify_group",
346 print "$text{'udel_done'}<p>\n";
349 # Save secondary group information
350 if ($in{'sgid_def'} == 1) {
352 print "$text{'usave_groups'}<br>\n";
353 foreach $g (split(/\s+/, $in{'sgidadd'})) {
354 local ($group) = grep { $_->{'group'} eq $g } @glist;
356 local %ogroup = %$group;
357 local @m = &unique(split(/,/,
358 $group->{'members'}), $user->{'user'});
359 $group->{'members'} = join(",", @m);
360 &remote_foreign_call($serv->{'host'},
361 "useradmin", "modify_group",
365 print "$text{'udel_done'}<p>\n";
367 elsif ($in{'sgid_def'} == 2) {
368 # Remove from some groups
369 print "$text{'udel_groups'}<br>\n";
370 foreach $g (split(/\s+/, $in{'sgiddel'})) {
371 local ($group) = grep { $_->{'group'} eq $g } @glist;
373 local %ogroup = %$group;
374 local @m = grep { $_ ne $user->{'user'} }
375 split(/,/, $group->{'members'});
376 $group->{'members'} = join(",", @m);
377 &remote_foreign_call($serv->{'host'},
378 "useradmin", "modify_group",
382 print "$text{'udel_done'}<p>\n";
385 # Run post-change command
386 &remote_foreign_call($serv->{'host'}, "useradmin", "made_changes");
389 # Update the user in other modules
390 print "$text{'usave_mothers'}<br>\n";
391 $user->{'passmode'} = $in{'passmode'};
392 if ($in{'passmode'} == 2 && $user->{'pass'} eq $ouser{'pass'}) {
393 $user{'passmode'} = 4;
395 $user->{'plainpass'} = $in{'pass'} if ($in{'passmode'} == 3);
396 &remote_foreign_call($serv->{'host'}, "useradmin",
397 "other_modules", "useradmin_modify_user",
399 print "$text{'udel_done'}<p>\n";
402 # Update in local list
403 $host->{'users'} = \@ulist;
405 $host->{'groups'} = \@glist;
407 &save_useradmin_host($host);
410 &webmin_log("modify", "user", $user->{'user'}, $user);
412 &ui_print_footer("", $text{'index_return'});