Escaping group name.
[webmin.git] / useradmin / edit_user.cgi
1 #!/usr/local/bin/perl
2 # edit_user.cgi
3 # Display a form for editing a user, or creating a new user
4
5 require './user-lib.pl';
6 require 'timelocal.pl';
7 &ReadParse();
8
9 # Show header and get the user
10 $n = $in{'user'};
11 if ($n eq "") {
12         $access{'ucreate'} || &error($text{'uedit_ecreate'});
13         &ui_print_header(undef, $text{'uedit_title2'}, "", "create_user");
14         }
15 else {
16         @ulist = &list_users();
17         ($uinfo_hash) = grep { $_->{'user'} eq $n } @ulist;
18         $uinfo_hash || &error($text{'uedit_egone'});
19         %uinfo = %$uinfo_hash;
20         &can_edit_user(\%access, \%uinfo) || &error($text{'uedit_eedit'});
21         &ui_print_header(undef, $text{'uedit_title'}, "", "edit_user");
22         }
23 @tds = ( "width=30%" );
24
25 # build list of used shells
26 %shells = map { $_, 1 } split(/,/, $config{'shells'});
27 @shlist = ($config{'default_shell'} ? ( $config{'default_shell'} ) : ( ));
28 push(@shlist, "/bin/sh", "/bin/csh", "/bin/false") if ($shells{'fixed'});
29 &build_user_used(\%used, $shells{'passwd'} ? \@shlist : undef);
30 if ($shells{'shells'}) {
31         open(SHELLS, "/etc/shells");
32         while(<SHELLS>) {
33                 s/\r|\n//g;
34                 s/#.*$//;
35                 push(@shlist, $_) if (/\S/);
36                 }
37         close(SHELLS);
38         }
39
40 # Start of the form
41 print &ui_form_start("save_user.cgi", "post");
42 print &ui_hidden("old", $n) if ($n ne "");
43 print &ui_table_start($text{'uedit_details'}, "width=100%", 2, \@tds);
44
45 # Username
46 if ($n eq "" && $config{'new_user_group'} && $access{'gcreate'}) {
47         $onch = "newgid.value = user.value";
48         }
49 if ($access{'urename'} || $n eq "") {
50         print &ui_table_row(&hlink($text{'user'}, "user"),
51                 &ui_textbox("user", $uinfo{'user'}, 40, 0, undef,
52                             "onChange='$onch'"));
53         }
54 else {
55         print &ui_table_row(&hlink($text{'user'}, "user"),
56                 "<tt>".&html_escape($uinfo{'user'})."</tt>");
57         print &ui_hidden("user", $uinfo{'user'}),"\n";
58         }
59
60 # User ID
61 if ($n ne "") {
62         # Existing user, just show field to edit
63         $uidfield = &ui_textbox("uid", $uinfo{'uid'}, 10);
64         }
65 else {
66         # Work out which UID modes are available
67         @uidmodes = ( );
68         $defuid = &allocate_uid(\%used);
69         if ($access{'autouid'}) {
70                 push(@uidmodes, [ 1, $text{'uedit_uid_def'} ]);
71                 }
72         if ($access{'calcuid'}) {
73                 push(@uidmodes, [ 2, $text{'uedit_uid_calc'} ]);
74                 }
75         if ($access{'useruid'}) {
76                 push(@uidmodes, [ 0, &ui_textbox("uid", $defuid, 10) ]);
77                 }
78         if (@uidmodes == 1) {
79                 $uidfield = &ui_hidden("uid_def", $uidmodes[0]->[0]).
80                             $uidmodes[0]->[1];
81                 }
82         else {
83                 $uidfield = &ui_radio("uid_def", $config{'uid_mode'},
84                                       \@uidmodes);
85                 }
86         }
87 print &ui_table_row(&hlink($text{'uid'}, "uid"), $uidfield);
88
89 # Real name
90 if ($config{'extra_real'}) {
91         # Has separate name, office, work and home phone parts
92         local @real = split(/,/, $uinfo{'real'}, 5);
93         print &ui_table_row(&hlink($text{'real'}, "real"),
94                 &ui_textbox("real", $real[0], 40));
95
96         print &ui_table_row(&hlink($text{'office'}, "office"),
97                 &ui_textbox("office", $real[1], 20));
98
99         print &ui_table_row(&hlink($text{'workph'}, "workph"),
100                 &ui_textbox("workph", $real[2], 20));
101
102         print &ui_table_row(&hlink($text{'homeph'}, "homeph"),
103                 &ui_textbox("homeph", $real[3], 20));
104
105         print &ui_table_row(&hlink($text{'extra'}, "extra"),
106                 &ui_textbox("extra", $real[4], 20));
107         }
108 else {
109         # Just a name
110         $uinfo{'real'} =~ s/,*$//;      # Strip empty extra fields
111         print &ui_table_row(&hlink($text{'real'}, "real"),
112                 &ui_textbox("real", $uinfo{'real'}, 40));
113         }
114
115 # Show input for home directory
116 if ($access{'autohome'}) {
117         # Automatic, cannot be changed
118         $homefield = $text{'uedit_auto'}.
119                      ($n eq "" ? "" : " ( <tt>$uinfo{'home'}</tt> )" );
120         }
121 else {
122         if ($config{'home_base'}) {
123                 # Can be automatic
124                 local $grp = &my_getgrgid($uinfo{'gid'});
125                 local $hb = $n eq "" ||
126                             &auto_home_dir($config{'home_base'},
127                                     $uinfo{'user'}, $grp) eq $uinfo{'home'};
128                 $homefield = &ui_radio("home_base", $hb ? 1 : 0,
129                         [ [ 1, $text{'uedit_auto'}."<br>" ],
130                           [ 0, $text{'uedit_manual'}." ".
131                                &ui_filebox("home", $hb ? "" : $uinfo{'home'},
132                                            40, 0, undef, undef, 1) ] ]);
133                 }
134         else {
135                 # Allow any directory
136                 $homefield = &ui_filebox("home", $uinfo{'home'}, 25, 0,
137                                          undef, undef, 1);
138                 }
139         }
140 print &ui_table_row(&hlink($text{'home'}, "home"),
141         $homefield);
142
143 # Show shell drop-down
144 push(@shlist, $uinfo{'shell'}) if ($n ne "" && $uinfo{'shell'});
145 if ($access{'shells'} ne "*") {
146         # Limit to shells from ACL
147         @shlist = $n ne "" ? ($uinfo{'shell'}) : ();
148         push(@shlist, split(/\s+/, $access{'shells'}));
149         $shells = 1;
150         }
151 $shells = 1 if ($access{'noother'});
152 @shlist = &unique(@shlist);
153 if ($n ne "" && !$uinfo{'shell'}) {
154         # No shell!
155         push(@shlist, [ "", "&lt;None&gt;" ]);
156         }
157 push(@shlist, [ "*", $text{'uedit_other'} ]) if (!$shells);
158 $firstshell = ref($shlist[0]) ? $shlist[0]->[0] : $shlist[0];
159 print &ui_table_row(&hlink($text{'shell'}, "shell"),
160         &ui_select("shell", $n eq "" ? $config{'default_shell'} || $firstshell
161                                      : $uinfo{'shell'},
162            \@shlist, 1, 0, 0, 0,
163            "onChange='form.othersh.disabled = form.shell.value != \"*\"'").
164            ($shells ? "" : &ui_filebox("othersh", undef, 40, 1)));
165
166 # Get the password, generate random if needed
167 $pass = $n ne "" ? $uinfo{'pass'} : $config{'lock_string'};
168 if ($n eq "" && $config{'random_password'}) {
169         $random_password = &generate_random_password();
170         }
171
172 # Check if temporary locking is supported
173 if (&supports_temporary_disable()) {
174         if ($n ne "" && $pass ne $config{'lock_string'} && $pass ne "") {
175                 # Can disable if not already locked, or if a new account
176                 $can_disable = 1;
177                 if ($pass =~ /^\Q$disable_string\E/) {
178                         $disabled = 1;
179                         $pass =~ s/^\Q$disable_string\E//;
180                         }
181                 }
182         elsif ($n eq "") {
183                 $can_disable = 1;
184                 }
185         }
186
187 # Show password field
188 $passmode = $pass eq "" && $random_password eq "" ? 0 :
189             $pass eq $config{'lock_string'} && $random_password eq "" ? 1 :
190             $random_password ne "" ? 3 :
191             $pass && $pass ne $config{'lock_string'} &&
192                 $random_password eq "" ? 2 : -1;
193 $pffunc = $config{'passwd_stars'} ? \&ui_password : \&ui_textbox;
194 print &ui_table_row(&hlink($text{'pass'}, "pass"),
195         &ui_radio_table("passmode", $passmode,
196           [ [ 0, $config{'empty_mode'} ? $text{'none1'} : $text{'none2'} ],
197             [ 1, $text{'nologin'} ],
198             [ 3, $text{'clear'},
199               &$pffunc("pass", $config{'random_password'} && $n eq "" ?
200                                 $random_password : "", 15) ],
201             $access{'nocrypt'} ?
202                 ( [ 2, $text{'nochange'},
203                     &ui_hidden("encpass", $pass) ] ) :
204                 ( [ 2, $text{'encrypted'},
205                     &ui_textbox("encpass", $passmode == 2 ? $pass : "", 60) ] )
206           ]).
207           ($can_disable ? "&nbsp;&nbsp;".&ui_checkbox("disable", 1,
208                                 $text{'uedit_disabled'}, $disabled) : "")
209           );
210
211 print &ui_table_end();
212
213 $pft = &passfiles_type();
214 if (($pft == 1 || $pft == 6) && $access{'peopt'}) {
215         # Additional user fields for BSD users
216         print &ui_table_start($text{'uedit_passopts'}, "width=100%", 4, \@tds);
217
218         # Last change date
219         if ($uinfo{'change'}) {
220                 @tm = localtime($uinfo{'change'});
221                 $cday = $tm[3];
222                 $cmon = $tm[4]+1;
223                 $cyear = $tm[5]+1900;
224                 $chour = sprintf "%2.2d", $tm[2];
225                 $cmin = sprintf "%2.2d", $tm[1];
226                 }
227         print "<td>";
228         &date_input($cday, $cmon, $cyear, 'change');
229         print &ui_table_row(&hlink($text{'change2'}, "change2"),
230                 &date_input($cday, $cmon, $cyear, 'change').
231                 " ".&ui_textbox("changeh", $chour, 3).
232                 ":".&ui_textbox("changemi", $cmin, 3));
233
234         # Expiry date
235         if ($n eq "") {
236                 if ($config{'default_expire'} =~
237                     /^(\d+)\/(\d+)\/(\d+)$/) {
238                         $eday = $1;
239                         $emon = $2;
240                         $eyear = $3;
241                         $ehour = "00";
242                         $emin = "00";
243                         }
244                 }
245         elsif ($uinfo{'expire'}) {
246                 @tm = localtime($uinfo{'expire'});
247                 $eday = $tm[3];
248                 $emon = $tm[4]+1;
249                 $eyear = $tm[5]+1900;
250                 $ehour = sprintf "%2.2d", $tm[2];
251                 $emin = sprintf "%2.2d", $tm[1];
252                 }
253         print &ui_table_row(&hlink($text{'expire2'}, "expire2"),
254                 &date_input($eday, $emon, $eyear, 'expire').
255                 " ".&ui_textbox("expireh", $ehour, 3).
256                 ":".&ui_textbox("expiremi", $emin, 3));
257
258         # BSD login class
259         print &ui_table_row(&hlink($text{'class'}, "class"),
260                 &ui_textbox("class", $uinfo{'class'}, 10));
261
262         print &ui_table_end();
263         }
264 elsif (($pft == 2 || $pft == 5) && $access{'peopt'}) {
265         # System has a shadow password file as well.. which means it supports
266         # password expiry and so on
267         print &ui_table_start($text{'uedit_passopts'}, "width=100%", 4, \@tds);
268
269         # Last change date
270         local $max = $n eq "" ? $config{'default_max'} : $uinfo{'max'};
271         print &ui_table_row(&hlink($text{'change'}, "change"),
272                 ($uinfo{'change'} ? &make_date(timelocal(
273                                        gmtime($uinfo{'change'} * 60*60*24)),1) :
274                  $n eq "" ? $text{'uedit_never'} :
275                             $text{'uedit_unknown'}));
276
277         if ($pft == 2) {
278                 # Expiry date
279                 if ($n eq "") {
280                         if ($config{'default_expire'} =~
281                             /^(\d+)\/(\d+)\/(\d+)$/) {
282                                 $eday = $1;
283                                 $emon = $2;
284                                 $eyear = $3;
285                                 }
286                         }
287                 elsif ($uinfo{'expire'}) {
288                         @tm = localtime(timelocal(gmtime($uinfo{'expire'} *
289                                                          60*60*24)));
290                         $eday = $tm[3];
291                         $emon = $tm[4]+1;
292                         $eyear = $tm[5]+1900;
293                         }
294                 print &ui_table_row(&hlink($text{'expire'}, "expire"),
295                         &date_input($eday, $emon, $eyear, 'expire'));
296                 }
297         else {
298                 # Ask at first login?
299                 print &ui_table_row(&hlink($text{'ask'}, "ask"),
300                         &ui_yesno_radio("ask", $uinfo{'change'} eq '0'));
301                 }
302
303         # Minimum and maximum days for changing
304         print &ui_table_row(&hlink($text{'min'}, "min"),
305                 &ui_textbox("min", $n eq "" ? $config{'default_min'} :
306                                         $uinfo{'min'}, 5));
307
308         print &ui_table_row(&hlink($text{'max'}, "max"),
309                 &ui_textbox("max", $n eq "" ? $config{'default_max'} :
310                                         $uinfo{'max'}, 5));
311
312         if ($pft == 2) {
313                 # Warning and inactive days. Only available when full shadow
314                 # files are used
315                 print &ui_table_row(&hlink($text{'warn'}, "warn"),
316                         &ui_textbox("warn", $n eq "" ? $config{'default_warn'}
317                                                      : $uinfo{'warn'}, 5));
318
319                 print &ui_table_row(&hlink($text{'inactive'}, "inactive"),
320                         &ui_textbox("inactive", $n eq "" ?
321                                         $config{'default_inactive'} :
322                                         $uinfo{'inactive'}, 5));
323                 }
324
325         # Force change at next login
326         if (($max || $gconfig{'os_type'} =~ /-linux$/) && $pft == 2) {
327                 print &ui_table_row(
328                         &hlink($text{'uedit_forcechange'}, 'forcechange'),
329                         &ui_yesno_radio("forcechange", 0));
330                 }
331
332         print &ui_table_end();
333         }
334 elsif ($pft == 4 && $access{'peopt'}) {
335         # System has extra AIX password information
336         print &ui_table_start($text{'uedit_passopts'}, "width=100%", 4, \@tds);
337
338         # Last change date and time
339         print &ui_table_row(&hlink($text{'change'}, "change"),
340                 ($uinfo{'change'} ? &make_date($uinfo{'change'}) :
341                  $n eq "" ? $text{'uedit_never'} :
342                             $text{'uedit_unknown'}));
343
344         if ($uinfo{'expire'} =~ /^(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)/) {
345                 $emon = $1;
346                 $eday = $2;
347                 $ehour = $3;
348                 $emin = $4;
349                 $eyear = $5;
350                 if ($eyear > 38) {
351                         $eyear += 1900;
352                         }
353                 else {
354                         $eyear += 2000;
355                         }
356                 }
357         $emon =~ s/0(\d)/$1/;   # strip leading 0 
358         print &ui_table_row(&hlink($text{'expire'}, "expire"),
359                 &ui_radio("expire_def", $uinfo{'expire'} eq '' ? 1 :
360                                         $uinfo{'expire'} eq '0' ? 2 : 0,
361                           [ [ 1, $text{'uedit_sys'} ],
362                             [ 2, $text{'uedit_never'} ],
363                             [ 0, &date_input($eday, $emon, $eyear, 'expire').
364                                  " ".&ui_textbox("expireh", $ehour, 3).
365                                  "/".&ui_textbox("expiremi", $emin, 3) ] ]), 3);
366
367         # Minimum and maximum ages in weeks
368         print &ui_table_row(&hlink($text{'min_weeks'}, "min_weeks"),
369            &ui_opt_textbox("min", $uinfo{'min'}, 5, $text{'uedit_sys'}), 3);
370
371         print &ui_table_row(&hlink($text{'max_weeks'}, "max_weeks"),
372             &ui_opt_textbox("max", $uinfo{'max'}, 5, $text{'uedit_sys'}), 3);
373
374         # Warning days
375         print &ui_table_row(&hlink($text{'warn'}, "warn"),
376             &ui_opt_textbox("warn", $uinfo{'warn'}, 5, $text{'uedit_sys'}), 3);
377
378         # AIX-specific flags
379         print &ui_table_row(&hlink($text{'flags'}, "flags"),
380                 &ui_checkbox("flags", "admin", $text{'uedit_admin'},
381                              $uinfo{'admin'})."<br>".
382                 &ui_checkbox("flags", "admchg", $text{'uedit_admchg'},
383                              $uinfo{'admchg'})."<br>".
384                 &ui_checkbox("flags", "nocheck", $text{'uedit_nocheck'},
385                              $uinfo{'nocheck'}), 3);
386
387         print &ui_table_end();
388         }
389
390 # Group memberships section
391 print &ui_table_start($text{'uedit_gmem'}, "width=100%", 4, \@tds);
392
393 # Primary group
394 @groupopts = ( );
395 $gidmode = 0;
396 if ($n eq "" && $access{'gcreate'}) {
397         # Has option to create a group
398         push(@groupopts, [ 2, $text{'uedit_samg'} ]);
399         push(@groupopts, [ 1, $text{'uedit_newg'},
400                            &ui_textbox("newgid", undef, 20) ]);
401         $gidmode = $config{'new_user_group'} ? 2 : 0;
402         }
403 if ($access{'ugroups'} eq "*" || $access{'uedit_gmode'} >= 3) {
404         # Group can be chosen with popup window
405         local $w = 300;
406         local $h = 200;
407         if ($gconfig{'db_sizeuser'}) {
408                 ($w, $h) = split(/x/, $gconfig{'db_sizeuser'});
409                 }
410         push(@groupopts, [ 0, $text{'uedit_oldg'},
411                    &ui_textbox("gid", $n eq "" ? $config{'default_group'} :
412                                  scalar(&my_getgrgid($uinfo{'gid'})), 13)." ".
413                    &popup_window_button("my_group_chooser.cgi?multi=0", $w, $h,
414                                         1, [ [ "ifield", "gid", "group" ] ]) ]);
415         }
416 else {
417         # From fixed menu of groups
418         $cg = $uinfo{'gid'} ? &my_getgrgid($uinfo{'gid'}) : undef;
419         @gl = &unique($cg ? ($cg) : (),
420                       &split_quoted_string($access{'ugroups'}));
421         push(@groupopts, [ 0, $text{'uedit_oldg'},
422                            &ui_select("gid", $cg, \@gl) ]);
423         }
424 if (@groupopts == 1) {
425         $groupfield = $groupopts[0]->[2];
426         }
427 else {
428         $groupfield = &ui_radio_table("gidmode", $gidmode, \@groupopts);
429         }
430 print &ui_table_row(&hlink($text{'group'}, "group"), $groupfield, 3);
431
432 # Work out which secondary groups the user is in
433 if ($config{'secmode'} != 1) {
434         @defsecs = &split_quoted_string($config{'default_secs'});
435         @glist = &list_groups();
436         @glist = sort { $a->{'group'} cmp $b->{'group'} } @glist
437                 if ($config{'sort_mode'});
438         %ingroups = ( );
439         foreach $g (@glist) {
440                 @mems = split(/,/ , $g->{'members'});
441                 $ismem = &indexof($uinfo{'user'}, @mems) >= 0;
442                 if ($n eq "") {
443                         $ismem = 1 if (&indexof($g->{'group'}, @defsecs) >= 0);
444                         }
445                 $ingroups{$g->{'group'}} = $ismem;
446                 }
447         }
448
449 if ($config{'secmode'} == 0) {
450         # Show secondary groups with select menu
451         @canglist = ( );
452         foreach $g (@glist) {
453                 next if (!&can_use_group(\%access, $g->{'group'}) &&
454                          !$ingroups{$g->{'group'}});
455                 push(@canglist, [ $g->{'group'}, &html_escape($g->{'group'}) ]);
456                 }
457         @ingroups = map { [ $_, $_ ] } sort { $a cmp $b }
458                         grep { $ingroups{$_} } (keys %ingroups);
459         $secfield = &ui_multi_select("sgid", \@ingroups, \@canglist, 5, 1, 0,
460                                      $text{'uedit_allg'}, $text{'uedit_ing'});
461         }
462 elsif ($config{'secmode'} == 2) {
463         # Show a text box
464         @insecs = ( );
465         foreach $g (@glist) {
466                 if ($ingroups{$g->{'group'}}) {
467                         push(@insecs, $g->{'group'});
468                         }
469                 }
470         $secfield = &ui_textarea("sgid", join("\n", @insecs), 5, 20);
471         }
472 else {
473         # Don't show
474         $secfield = undef;
475         }
476 if ($secfield) {
477         print &ui_table_row(&hlink($text{'uedit_2nd'}, "2nd"), $secfield, 3);
478         }
479
480 print &ui_table_end();
481
482 if ($n ne "") {
483         # Editing a user - show options for moving home directory, changing IDs
484         # and updating in other modules
485         if ($access{'movehome'} == 1 || $access{'chuid'} == 1 ||
486             $access{'chgid'} == 1 || $access{'mothers'} == 1) {
487                 print &ui_table_start($text{'onsave'}, "width=100%", 2, \@tds);
488
489                 # Move home directory
490                 if ($access{'movehome'} == 1) {
491                         print &ui_table_row(
492                                 &hlink($text{'uedit_movehome'}, "movehome"),
493                                 &ui_yesno_radio("movehome", 1));
494                         }
495
496                 # Change UID on files
497                 if ($access{'chuid'} == 1) {
498                         print &ui_table_row(
499                                 &hlink($text{'uedit_chuid'},"chuid"),
500                                 &ui_radio("chuid", 1,
501                                           [ [ 0, $text{'no'} ],
502                                             [ 1, $text{'home'} ],
503                                             [ 2, $text{'uedit_allfiles'} ] ]));
504                         }
505
506                 # Change GID on files
507                 if ($access{'chgid'} == 1) {
508                         print &ui_table_row(
509                                 &hlink($text{'uedit_chgid'},"chgid"),
510                                 &ui_radio("chgid", 1,
511                                           [ [ 0, $text{'no'} ],
512                                             [ 1, $text{'home'} ],
513                                             [ 2, $text{'uedit_allfiles'} ] ]));
514                         }
515
516                 # Modify in other modules
517                 if ($access{'mothers'} == 1) {
518                         print &ui_table_row(
519                                 &hlink($text{'uedit_mothers'},"others"),
520                                 &ui_yesno_radio("others",
521                                         $config{'default_other'} ? 1 : 0));
522                         }
523
524                 # Rename group, if the same and if editable
525                 @ginfo = &my_getgrgid($uinfo{'gid'});
526                 if ($ginfo[0] eq $uinfo{'user'}) {
527                         ($group) = grep { $_->{'gid'} == $uinfo{'gid'} }
528                                         &list_groups();
529                         if (&can_edit_group(\%access, $group)) {
530                                 print &ui_table_row(
531                                         &hlink($text{'uedit_grename'},"grename"),
532                                         &ui_yesno_radio("grename", 1));
533                                 }
534                         }
535
536                 print &ui_table_end(),"<p>\n";
537                 }
538         }
539 else {
540         # Creating a user - show options for creating home directory, copying
541         # skel files and creating in other modules
542         if ($access{'makehome'} == 1 || $access{'copy'} == 1 ||
543             $access{'cothers'} == 1) {
544                 print &ui_table_start($text{'uedit_oncreate'}, "width=100%",
545                                       2, \@tds);
546
547                 # Create home dir
548                 if ($access{'makehome'} == 1) {
549                         print &ui_table_row(
550                                 &hlink($text{'uedit_makehome'}, "makehome"),
551                                 &ui_yesno_radio("makehome", 1));
552                         }
553
554                 # Copy skel files
555                 if ($config{'user_files'} =~ /\S/ && $access{'copy'} == 1) {
556                         print &ui_table_row(
557                                 &hlink($text{'uedit_copy'}, "copy_files"),
558                                 &ui_yesno_radio("copy_files", 1));
559                         }
560
561                 # Create in other modules
562                 if ($access{'cothers'} == 1) {
563                         print &ui_table_row(
564                                 &hlink($text{'uedit_cothers'},"others"),
565                                 &ui_yesno_radio("others",
566                                                 $config{'default_other'}));
567                         }
568
569                 print &ui_table_end();
570                 }
571         }
572
573 if ($n ne "") {
574         # Buttons for saving and other actions
575         @buts = ( [ undef, $text{'save'} ] );
576
577         # List logins by user
578         push(@buts, [ "list", $text{'uedit_logins'} ]);
579
580         # Link to the mailboxes module, if installed
581         if (&foreign_available("mailboxes") &&
582             &foreign_installed("mailboxes", 1)) {
583                 push(@buts, [ "mailboxes", $text{'uedit_mail'} ]);
584                 }
585
586         # Link to Usermin for switching user
587         if (&foreign_available("usermin") &&
588             &foreign_installed("usermin", 1) &&
589             (%uacl = &get_module_acl("usermin") &&
590             $uacl{'sessions'})) {
591                 # Link to Usermin module for switching to some user
592                 &foreign_require("usermin", "usermin-lib.pl");
593                 local %uminiserv;
594                 &usermin::get_usermin_miniserv_config(\%uminiserv);
595                 if ($uminiserv{'session'}) {
596                         push(@buts, [ "switch", $text{'uedit_swit'} ]);
597                         }
598                 }
599
600         # Delete user
601         if ($access{'udelete'}) {
602                 push(@buts, [ "delete", $text{'delete'} ]);
603                 }
604         print &ui_form_end(\@buts);
605         }
606 else {
607         # Create button
608         print &ui_form_end([ [ undef, $text{'create'} ] ]);
609         }
610
611 &ui_print_footer("index.cgi?mode=users", $text{'index_return'});
612
613