Re: [webmin-devel] using modify_user to change user details
"Todd Kennedy" <[email protected]> Tue, 3 Jun 2008 09:28:50 -0400
| Newsgroups | gmane.comp.web.webmin.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi Jamie, Thanks for replying to my post. I still can't figure out whats going on. I've defined %user hash but to no avail I cannot seem to locate the issue. I've attached my recycle_users.cgi. If you could briefly review it that would be great. I also welcome any pointers and constructive criticism. Thanks -Todd On Mon, Jun 2, 2008 at 5:04 PM, Jamie Cameron <[email protected]> wrote: > Hi Todd, > > Make sure that in your code, you aren't calling modify_user with an > empty user hash. It looks like that is the case, as this would cause > an 'empty' line like that to be inserted into /etc/passwd. > > I'd have to see all your code to comment further though.. > > - Jamie > > On 02/Jun/2008 12:11 Todd Kennedy wrote .. >> Hello, >> >> I am new to webmin module development and am trying to extend the "Users >> & Groups" module for internal purposes. What I have done is create a >> "Recycle User" button on the selected users "Edit Users" page that >> basically mimics the functionality of the delete_user.cgi (without >> actually deleting the user) but also extends it by showing me a list of >> currently selected user processes running. Once I press the "Recycle >> user and home directory button" it goes off and first terminates those >> running processes then removes the users home directory then I need to >> reset the users password back to some default. I am about 90% of the way >> there but seem to be caught up on the saving of the modified password. I >> am using the modify_user function. Whats actually happening is that it's >> leaving an incomplete line in the /etc/password and shadow file looking >> something like this: >> >> svctag:*LK*:6445:::::: >> nobody:*LK*:6445:::::: >> noaccess:*LK*:6445:::::: >> nobody4:*LK*:6445:::::: >> :::::::: >> >> This last line should be the entry that I recycled but it's just a bunch >> of empty GECOS fields. So it seems to me that it's rewriting the line >> but is doing it with empty values. >> >> So I think I am missing something somewhere but am unsure what other >> functions possibly I need to call in order for it to write out the >> password file. I'm assuming the modify_user function takes care of that, no? >> >> >> This does seem like a strange thing to do but would fit nicely into >> managing test accounts for may lab machines. When the lab reservation >> expires the admin can recycle the user with a press of the button and >> set it back to some default settings. >> >> Here's the snippet of code that is suppose to be resetting the password >> and saving it. >> >> %recycleuser = %{$ulist[$in{'num'}]}; >> $pass = &encrypt_password($config{'recycle_passwd'}); >> $recycleuser{'pass'} = $pass; >> >> # Update user details >> &modify_user(\%recycleuser, \%user); >> >> # Run the pre-change command >> $merr = &making_changes(); >> &error(&text('usave_emaking', "<tt>$merr</tt>")) if (defined($merr)); >> &unlock_user_files(); >> &made_changes(); >> >> So as the code runs the following is displayed in the borwser, The has >> info is there for debugging purposes. >> >> Deleting from other modules .. >> .. done >> Killing user processes >> .. done >> >> Deleting home directory .. >> .. done >> >> Creating Home Directory >> .. done >> >> new encrypted passwd=TN4xb4vuWbxc6 >> >> Contents of recycleuser Hash prior to change >> >> num => 20 >> >> inactive => >> >> max => >> >> warn => >> >> user => testuser >> >> shell => /bin/sh >> >> home => /export/home/testuser >> >> real => >> >> line => 20 >> >> pass => NNwEdL/U3qYwU >> >> sline => 20 >> >> uid => 1000 >> >> change => 14032 >> >> min => >> >> expire => >> >> gid => 10 >> >> >> Contents of User hash after replacing $pass but before saving >> >> num => 20 >> >> inactive => >> >> max => >> >> warn => >> >> user => testuser >> >> shell => /bin/sh >> >> home => /export/home/testuser >> >> real => >> >> line => 20 >> >> pass => TN4xb4vuWbxc6 >> >> sline => 20 >> >> uid => 1000 >> >> change => 14032 >> >> min => >> >> expire => >> >> gid => 10 >> >> >> Reread the %ulist has for the user "Still has the old password" >> >> num => 20 >> >> inactive => >> >> max => >> >> warn => >> >> user => testuser >> >> shell => /bin/sh >> >> home => /export/home/testuser >> >> real => >> >> line => 20 >> >> pass => NNwEdL/U3qYwU >> >> sline => 20 >> >> uid => 1000 >> >> change => 14032 >> >> min => >> >> expire => >> >> gid => 10 >> >> >> Any help on this would be much appriciated. > > ------------------------------------------------------------------------- > This SF.net email is sponsored by: Microsoft > Defy all challenges. Microsoft(R) Visual Studio 2008. > http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ > - > Forwarded by the Webmin development list at [email protected] > To remove yourself from this list, go to > http://lists.sourceforge.net/lists/listinfo/webadmin-devel > ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ - Forwarded by the Webmin development list at [email protected] To remove yourself from this list, go to http://lists.sourceforge.net/lists/listinfo/webadmin-devel
recycle_user.cgi.txt
(text/plain, 6.5 KB)
#!/usr/local/bin/perl
# Recycle the current users login account
# Kill all users processes
# remove / recreate users home directory
# reset the users password to a common password
require './user-lib.pl';
&foreign_require("proc", "proc-lib.pl");
&ReadParse();
&lock_user_files();
@ulist = &list_users();
%recycleuser = %{$ulist[$in{'num'}]};
%user = %recycleuser;
$user = $ulist[$in{'num'}];
$user || &error($text{'recycle_enum'});
&error_setup($text{'recycle_err'});
%access = &get_module_acl();
&can_edit_user(\%access, $user) || &error($text{'recycle_euser'});
$access{'udelete'} || &error($text{'recycle_euser'});
@procs = sort { $b->{'cpu'} <=> $a->{'cpu'} } &proc::list_processes();
@procs = grep { &proc::can_view_process($_->{'user'}) } @procs;
$valid = 0;
$| = 1;
&ui_print_header(undef, $text{'recycle_title'}, "");
############# Start of User Del section ##############
if (!$config{'delete_root'} && $user->{'uid'} <= 10) {
print "<p> <b>$text{'recycle_eroot'}</b> <p>\n";
print "<hr>\n";
&footer("", $text{'index_return'});
exit;
}
# Check for repeat click
if ($user->{'user'} ne $in{'user'} || $in{'user'} eq '') {
print "<p> <b>$text{'recycle_ealready'}</b> <p>\n";
print "<hr>\n";
&footer("", $text{'index_return'});
exit;
}
if ($in{'confirmed'}) {
# Run the before command
local @secs;
foreach $g (&list_groups()) {
@mems = split(/,/, $g->{'members'});
if (&indexof($user->{'user'}, @mems) >= 0) {
push(@secs, $g->{'gid'});
}
}
&set_user_envs($user, 'MODIFY_USER', undef, \@secs);
$merr = &making_changes();
&error(&text('usave_emaking', "<tt>$merr</tt>")) if (defined($merr));
# Go ahead and do it!
$in{'others'} = !$access{'dothers'} if ($access{'dothers'} != 1);
if ($in{'others'}) {
print "$text{'recycle_other'}<br>\n";
local $error_must_die = 1;
eval { &other_modules("useradmin_delete_user", $user); };
if ($@) {
print &text('recycle_failed', $@),"<p>\n";
}
else {
print "$text{'recycle_done'}<p>\n";
$pass = &encrypt_password($config{'recycle_passwd'});
$recycleuser{'pass'} = $pass;
&modify_user(\%recycleuser, \%user);
}
}
# Kill Running Processes
print "$text{'recycle_procs'}<br>\n";
@pidlist = split(/\s+/, $in{pidlist});
@pinfo = &proc::list_processes(@pidlist);
for($i=0; $i<@pidlist; $i++) {
$in{"args$i"} = $pinfo[$i]->{'args'};
print "$text{'pid'} <tt>$pidlist[$i]</tt> ... \n";
if (&proc::can_edit_process($pinfo[$i]->{'user'})) {
if (&proc::kill_logged($in{signal}, $pidlist[$i])) {
print "SIG$in{signal} $text{'recycle_kill_sent'}<br>\n";
}
else {
print "$!<br>\n";
}
}
else {
print "$text{'recyle_kill_ecannot'}<br>\n";
}
}
print "$text{'recycle_done'}<p>\n";
&webmin_log("kill", undef, undef, \%in);
print "<p>\n";
&unlock_user_files();
if ($in{'delhome'} && $user->{'home'} !~ /^\/+$/ && $access{'delhome'} != 0) {
# Delete home directory
print "$text{'recycle_home'}<br>\n";
&lock_file($user->{'home'});
&delete_home_directory($user);
&unlock_file($user->{'home'});
print "$text{'recycle_done'}<p>\n";
# Now lets recreate the user directory
print "$text{'recycle_ucreate_home'}<br>\n";
&create_home_directory(\%user, $user->{'home'});
print "$text{'recycle_done'}<p>\n";
}
&made_changes();
%p = ( %in, %$user );
delete($p{'pass'});
&webmin_log("recycle", "user", $user->{'user'}, \%p);
done:
&ui_print_footer("", $text{'index_return'});
}
else {
# Check if something has changed
if ($user->{'user'} ne $in{'user'}) {
print "<p> <b>$text{'recycle_echanged'}</b> <p>\n";
&ui_print_footer("", $text{'index_return'});
exit;
}
############# List running user processes ###############
if (&supports_users()) {
@uinfo = getpwnam($user->{'user'});
$uinfo[6] =~ s/,.*$//;
}
print &ui_subheading("$user->{'user'} ".($uinfo[6] ? "($uinfo[6])" : "")),"\n";
print &ui_columns_start([
$text{'pid'},
$text{'cpu'},
$info_arg_map{'_stime'} ? ( $text{'stime'} ) : ( ),
$text{'command'} ], 100);
foreach $pr (grep { $_->{'user'} eq $user->{'user'} } @procs) {
local @cols;
push(@pidlist, $pr->{'pid'});
push(@cols, $pr->{'pid'});
push(@cols, $pr->{'cpu'});
if ($info_arg_map{'_stime'}) {
push(@cols, $pr->{'_stime'});
}
push(@cols, &html_escape(&proc::cut_string($pr->{'args'})));
print &ui_columns_row(\@cols);
$valid++;
}
print &ui_columns_end();
if ($valid eq 0) {
print "<br><center><b>",&text('recycle_no_procs', $user->{'user'}),
"</b><p><br>\n";
}
# warn if running processes
if (@pidlist) {
print "<br><center><b><font color=#ff0000>",
&text('recycle_kill_warn', "<tt>$user->{'user'}</tt>", scalar(@others)),
"</font></b><br>\n";
}
# Ask if the user is sure
print "<form action=recycle_user.cgi>\n";
print "<input type=hidden name=num value=\"$in{'num'}\">\n";
print "<input type=hidden name=user value=\"$user->{'user'}\">\n";
printf "<input type=hidden name=pidlist value=\"%s\">\n",
join(" ", @pidlist);
print "<input type=hidden name=signal value=\"KILL\">\n";
print "<input type=hidden name=confirmed value=1>\n";
if ($user->{'home'} ne "/" && -d $user->{'home'} && $access{'delhome'} != 0) {
# Has a home directory, so check for files owned by others
$size = &disk_usage_kb($user->{'home'});
print "<center><b>",&text('recycle_sure', $user->{'user'},
"<tt>$user->{'home'}</tt>", &nice_size($size*1024)),
"</b><p>\n";
if ($access{'delhome'} != 1) {
print "<input type=submit value=\"$text{'recycle_del1'}\">\n";
}
print "<input name=delhome type=submit ",
"value=\"$text{'recycle_del2'}\">\n";
# check for files owned by other users
@others = &backquote_command("find ".quotemeta($user->{'home'})." ! -user $user->{'uid'} 2>/dev/null", 1);
if (@others) {
print "<br><b><font color=#ff0000>",
&text('recycle_dir_warn', "<tt>$user->{'home'}</tt>", scalar(@others)),
"</font></b><br>\n";
}
}
# We Don't want two buttons, we only want to recycle the user and home dir
# else {
# # No home directory
# print "<center><b>",&text('recycle_sure2',
# $user->{'user'}),"</b><p>\n";
# print "<input type=submit value=\"$text{'recycle_del1'}\">\n";
# }
print "<br>\n";
if ($access{'dothers'} == 1) {
printf "<input type=checkbox name=others value=1 %s> %s<br>\n",
$config{'default_other'} ? "checked" : "",
$text{'recycle_dothers'};
}
if ($user->{'user'} eq 'root') {
print "<center><b><font color=#ff0000>$text{'recycle_root'}",
"</font></b><p></center>\n";
}
print "</form></center>\n";
&ui_print_footer("", $text{'index_return'});
}