3 # Creates a new user on multiple machines
5 require './cluster-useradmin-lib.pl';
6 require 'timelocal.pl';
7 &foreign_require("useradmin", "user-lib.pl");
8 &error_setup($text{'usave_err'});
10 @hosts = &list_useradmin_hosts();
11 @servers = &list_servers();
13 # Strip out \n characters in inputs
14 $in{'real'} =~ s/\r|\n//g;
15 $in{'user'} =~ s/\r|\n//g;
16 $in{'pass'} =~ s/\r|\n//g;
17 $in{'encpass'} =~ s/\r|\n//g;
18 $in{'home'} =~ s/\r|\n//g;
19 $in{'gid'} =~ s/\r|\n//g;
20 $in{'uid'} =~ s/\r|\n//g;
21 $in{'othersh'} =~ s/\r|\n//g;
24 $user{'user'} = $in{'user'};
25 $in{'user'} =~ /^[^:\t]+$/ ||
26 &error(&text('usave_ebadname', $in{'user'}));
27 $err = &useradmin::check_username_restrictions($in{'user'});
28 &error($err) if ($err);
31 &ui_print_header(undef, $text{'uedit_title2'}, "");
33 # Work out which hosts to create on
34 @already = grep { local ($alr) = grep { $_->{'user'} eq $in{'user'} }
37 @hosts = &create_on_parse("usave_header", \@already, $in{'user'});
39 # Check for username clash
41 ($s) = grep { $_->{'id'} == $h->{'id'} } @servers;
42 foreach $u (@{$h->{'users'}}) {
43 if ($u->{'user'} eq $in{'user'}) {
44 &error(&text('usave_einuse', $s->{'host'}));
49 # Validate and store basic inputs
50 $in{'uid'} =~ /^[0-9]+$/ || &error(&text('usave_euid', $in{'uid'}));
51 $in{'real'} =~ /^[^:]*$/ || &error(&text('usave_ereal', $in{'real'}));
52 if ($in{'shell'} eq "*") { $in{'shell'} = $in{'othersh'}; }
53 $user{'uid'} = $in{'uid'};
54 ($group) = grep { $_->{'group'} eq $in{'gid'} } @{$hosts[0]->{'groups'}};
56 $user{'gid'} = $group->{'gid'};
59 $user{'gid'} = getgrnam($in{'gid'});
61 if ($user{'gid'} eq "") { &error(&text('usave_egid', $in{'gid'})); }
62 if ($uconfig{'extra_real'}) {
63 $in{'office'} =~ /^[^:]*$/ || &error($text{'usave_eoffice'});
64 $in{'workph'} =~ /^[^:]*$/ || &error($text{'usave_eworkph'});
65 $in{'homeph'} =~ /^[^:]*$/ || &error($text{'usave_ehomeph'});
66 $user{'real'} = join(",", $in{'real'}, $in{'office'}, $in{'workph'},
68 $user{'real'} .= ",$in{'extra'}" if ($in{'extra'});
69 $user{'real'} =~ s/,+$//;
72 $user{'real'} = $in{'real'};
74 if ($uconfig{'home_base'} && $in{'home_base'}) {
75 $user{'home'} = &auto_home_dir($uconfig{'home_base'}, $in{'user'});
78 $user{'home'} = $in{'home'};
80 $user{'shell'} = $in{'shell'};
81 foreach $gid (split(/\0/, $in{'sgid'})) {
85 # Store password input
86 $crypted = &foreign_call("useradmin", "encrypt_password", $in{'pass'});
87 if ($in{'passmode'} == 0) {
88 if (!$uconfig{'empty_mode'}) {
89 local $err = &useradmin::check_password_restrictions(
91 &error($err) if ($err);
95 elsif ($in{'passmode'} == 1) { $user{'pass'} = $uconfig{'lock_string'}; }
96 elsif ($in{'passmode'} == 2) { $user{'pass'} = $in{'encpass'}; }
97 elsif ($in{'passmode'} == 3) {
98 local $err = &useradmin::check_password_restrictions(
99 $in{'pass'}, $user{'user'});
100 &error($err) if ($err);
101 $user{'pass'} = $crypted;
104 $pft = &foreign_call("useradmin", "passfiles_type");
106 # Validate shadow-password inputs
107 if ($in{'expired'} ne "" && $in{'expirem'} ne ""
108 && $in{'expirey'} ne "") {
109 eval { $expire = timelocal(0, 0, 12, $in{'expired'},
111 $in{'expirey'}-1900); };
112 if ($@) { &error("invalid expiry date"); }
113 $expire = int($expire / (60*60*24));
115 else { $expire = ""; }
116 $in{'min'} =~ /^[0-9]*$/ ||
117 &error(&text('usave_emin', $in{'min'}));
118 $in{'max'} =~ /^[0-9]*$/ ||
119 &error(&text('usave_emax', $in{'max'}));
120 $in{'warn'} =~ /^[0-9]*$/ ||
121 &error(&text('usave_ewarn', $in{'warn'}));
122 $in{'inactive'} =~ /^[0-9]*$/ ||
123 &error(&text('usave_einactive', $in{'inactive'}));
124 $user{'expire'} = $expire;
125 $user{'min'} = $in{'min'};
126 $user{'max'} = $in{'max'};
127 $user{'warn'} = $in{'warn'};
128 $user{'inactive'} = $in{'inactive'};
129 $user{'change'} = int(time() / (60*60*24));
131 elsif ($pft == 1 || $pft == 6) {
132 # Validate BSD-password inputs
133 if ($in{'expired'} ne "" && $in{'expirem'} ne ""
134 && $in{'expirey'} ne "") {
135 eval { $expire = timelocal(59, $in{'expiremi'},
139 $in{'expirey'}-1900); };
140 if ($@) { &error($text{'usave_eexpire'}); }
142 else { $expire = ""; }
143 if ($in{'changed'} ne "" && $in{'changem'} ne ""
144 && $in{'changey'} ne "") {
145 eval { $change = timelocal(59, $in{'changemi'},
149 $in{'changey'}-1900); };
150 if ($@) { &error($text{'usave_echange'}); }
152 else { $change = ""; }
153 $in{'class'} =~ /^([^: ]*)$/ ||
154 &error(&text('usave_eclass', $in{'class'}));
155 $user{'expire'} = $expire;
156 $user{'change'} = $change;
157 $user{'class'} = $in{'class'};
160 # Validate AIX-style password inputs
161 if ($in{'expired'} ne "" && $in{'expirem'} ne ""
162 && $in{'expirey'} ne "" ) {
163 # Add a leading zero if only 1 digit long
164 $in{'expirem'} =~ s/^(\d)$/0$1/;
165 $in{'expired'} =~ s/^(\d)$/0$1/;
166 $in{'expireh'} =~ s/^(\d)$/0$1/;
167 $in{'expiremi'} =~ s/^(\d)$/0$1/;
169 # Only use the last two digits of the year
170 $in{'expirey'} =~ s/^\d\d(\d\d)$/$1/;
172 # If the user didn't choose the hour and min make them 01
173 $in{'expireh'} = "01" if $in{'expireh'} eq "";
174 $in{'expiremi'} = "01" if $in{'expiremi'} eq "";
175 $expire="$in{'expirem'}$in{'expired'}$in{'expireh'}$in{'expiremi'}$in{'expirey'}";
177 else { $expire = ""; }
178 $user{'admin'} = $in{'flags'} =~ /admin/;
179 $user{'admchg'} = $in{'flags'} =~ /admchg/;
180 $user{'nocheck'} = $in{'flags'} =~ /nocheck/;
181 $user{'expire'} = $expire;
182 $user{'min'} = $in{'min'};
183 $user{'max'} = $in{'max'};
184 $user{'warn'} = $in{'warn'};
185 $user{'change'} = time();
188 # Setup error handler for down hosts
191 $add_error_msg = join("", @_);
193 &remote_error_setup(\&add_error);
195 # Loop through selected hosts to create user
196 foreach $host (@hosts) {
197 $add_error_msg = undef;
198 local ($serv) = grep { $_->{'id'} == $host->{'id'} } @servers;
199 &remote_foreign_require($serv->{'host'}, "useradmin", "user-lib.pl");
200 print "<b>",&text('usave_con', &server_name($serv)),"</b><p>\n";
202 if ($add_error_msg) {
204 print &text('usave_failed', $add_error_msg),"<p>\n";
209 if ($in{'sgid'} ne '') {
210 @glist = &remote_foreign_call($serv->{'host'}, "useradmin",
214 # Run the pre-change command
215 $envsgids = join(",", split(/\0/, $in{'sgid'}));
216 $envpass = $in{'passmode'} == 3 ? $in{'pass'} : undef;
217 &remote_eval($serv->{'host'}, "useradmin", <<EOF
218 \$ENV{'USERADMIN_USER'} = '$user{'user'}';
219 \$ENV{'USERADMIN_UID'} = '$user{'uid'}';
220 \$ENV{'USERADMIN_REAL'} = '$user{'real'}';
221 \$ENV{'USERADMIN_SHELL'} = '$user{'shell'}';
222 \$ENV{'USERADMIN_HOME'} = '$user{'home'}';
223 \$ENV{'USERADMIN_GID'} = '$user{'gid'}';
224 \$ENV{'USERADMIN_SECONDARY'} = '$envsgids';
225 \$ENV{'USERADMIN_PASS'} = '$envpass';
226 \$ENV{'USERADMIN_ACTION'} = 'CREATE_USER';
229 $merr = &remote_foreign_call($serv->{'host'}, "useradmin",
231 if (defined($merr)) {
232 print &text('usave_emaking', "<tt>$merr</tt>"),"<p>\n";
237 # Create the home directory
239 if ($in{'servs'} || $host eq $hosts[0]) {
240 if ($in{'makehome'}) {
241 local $exists = &remote_eval($serv->{'host'},
242 "useradmin", "-e '$user{'home'}'");
244 print "$text{'usave_mkhome'}<br>\n";
245 local $rv = &remote_eval($serv->{'host'}, "useradmin",
246 "mkdir('$user{'home'}', oct('$uconfig{'homedir_perms'}')) && chmod(oct('$uconfig{'homedir_perms'}'), '$user{'home'}') ? undef : \$!");
247 $rv && &error(&text('usave_emkdir', $rv));
248 $rv = &remote_eval($serv->{'host'}, "useradmin",
249 "chown($user{'uid'}, $user{'gid'}, '$user{'home'}')");
250 $rv || &error(&text('usave_echown', $rv));
252 print "$text{'udel_done'}<p>\n";
258 print "$text{'usave_create'}<br>\n";
259 &remote_foreign_call($serv->{'host'}, "useradmin",
260 "create_user", \%user);
261 print "$text{'udel_done'}<p>\n";
263 # Copy files into user's directory
264 if ($in{'servs'} || $host eq $hosts[0]) {
265 local $fconfig = &remote_foreign_config($serv->{'host'},
267 if ($in{'copy_files'} && $made_home) {
268 print "$text{'usave_copy'}<br>\n";
269 local $uf = $fconfig->{'user_files'};
270 $uf =~ s/\$group/$in{'gid'}/g;
271 $uf =~ s/\$gid/$user{'gid'}/g;
272 &remote_foreign_call($serv->{'host'}, "useradmin",
273 "copy_skel_files", $uf, $user{'home'},
274 $user{'uid'}, $user{'gid'});
275 print "$text{'udel_done'}<p>\n";
280 local @sgids = split(/\0/, $in{'sgid'});
281 print "$text{'usave_groups'}<br>\n" if (@sgids);
282 foreach $gid (@sgids) {
283 foreach $group (@glist) {
284 if ($group->{'gid'} == $gid) {
286 local %ogroup = %$group;
287 $group->{'members'} = join(",", $user{'user'},
288 split(/,/, $group->{'members'}));
289 &remote_foreign_call($serv->{'host'},
290 "useradmin", "modify_group",
295 print "$text{'udel_done'}<p>\n" if (@sgids);
297 # Run the post-change command
298 &remote_foreign_call($serv->{'host'}, "useradmin", "made_changes");
301 # Create in other modules on the server
302 print "$text{'usave_others'}<br>\n";
303 $user{'passmode'} = $in{'passmode'};
304 $user{'plainpass'} = $in{'pass'} if ($in{'passmode'} == 3);
305 &remote_foreign_call($serv->{'host'}, "useradmin",
306 "other_modules", "useradmin_create_user",
308 print "$text{'udel_done'}<p>\n";
312 push(@{$host->{'users'}}, \%user);
314 $host->{'groups'} = \@glist;
316 &save_useradmin_host($host);
319 &webmin_log("create", "user", $user{'user'}, \%user);
321 &ui_print_footer("", $text{'index_return'});