linuxOS_AP05/debian/test/usr/share/system-tools-backends-2.0/scripts/Users/Users.pm

912 lines
25 KiB
Perl
Raw Normal View History

2025-09-26 01:40:02 +00:00
#-*- Mode: perl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
# Users account manager. Designed to be architecture and distribution independent.
#
# Copyright (C) 2000-2001 Ximian, Inc.
#
# Authors: Hans Petter Jansson <hpj@ximian.com>,
# Arturo Espinosa <arturo@ximian.com>,
# Tambet Ingo <tambet@ximian.com>.
# Grzegorz Golawski <grzegol@pld-linux.org> (PLD Support),
# Milan Bouchet-Valat <nalimilan@club.fr>.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Library General Public License as published
# by the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
# Best viewed with 100 columns of width.
# Configuration files affected:
#
# /etc/passwd
# /etc/group
# /etc/shadow
# /etc/login.defs
# /etc/shells
# /etc/skel/
# NIS support will come later.
# Running programs affected/used:
#
# adduser: creating users.
# usermod: modifying user data.
# passwd: assigning or changing passwords. (Un)locking users.
# chfn: modifying finger information - Name, Office, Office phone, Home phone.
# pw: modifying users/groups and user/group data on FreeBSD.
package Users::Users;
use Utils::Util;
use Utils::Report;
use Utils::File;
use Utils::Backend;
use Utils::Replace;
# --- System config file locations --- #
# We list each config file type with as many alternate locations as possible.
# They are tried in array order. First found = used.
@passwd_names = ( "/etc/passwd" );
@shadow_names = ( "/etc/shadow", "/etc/master.passwd" );
@login_defs_names = ( "/etc/login.defs", "/etc/adduser.conf" );
@shell_names = ( "/etc/shells" );
@skel_dir = ( "/usr/share/skel", "/etc/skel" );
# Where are the tools?
$cmd_usermod = &Utils::File::locate_tool ("usermod");
$cmd_userdel = &Utils::File::locate_tool ("userdel");
$cmd_useradd = &Utils::File::locate_tool ("useradd");
$cmd_adduser = &Utils::File::locate_tool ("adduser");
$cmd_deluser = &Utils::File::locate_tool ("deluser");
$cmd_chfn = &Utils::File::locate_tool ("chfn");
$cmd_pw = &Utils::File::locate_tool ("pw");
$cmd_passwd = &Utils::File::locate_tool ("passwd");
$cmd_chpasswd = &Utils::File::locate_tool ("chpasswd");
# enum like for verbose group array positions
my $i = 0;
my $LOGIN = $i++;
my $PASSWD = $i++;
my $UID = $i++;
my $GID = $i++;
my $COMMENT = $i++;
my $HOME = $i++;
my $SHELL = $i++;
my $PASSWD_STATUS = $i++;
my $ENC_HOME = $i++;
my $HOME_FLAGS = $i++;
my $LOCALE = $i++;
my $LOCATION = $i++;
my $FACE = $i++;
%login_defs_prop_map = ();
%profiles_prop_map = ();
sub get_login_defs_prop_array
{
my @prop_array;
my @login_defs_prop_array_default =
(
"QMAIL_DIR", "qmail_dir",
"MAIL_DIR", "mailbox_dir",
"MAIL_FILE", "mailbox_file",
"PASS_MAX_DAYS", "pwd_maxdays",
"PASS_MIN_DAYS", "pwd_mindays",
"PASS_MIN_LEN", "pwd_min_length",
"PASS_WARN_AGE", "pwd_warndays",
"UID_MIN", "umin",
"UID_MAX", "umax",
"GID_MIN", "gmin",
"GID_MAX", "gmax",
"USERDEL_CMD", "del_user_additional_command",
"CREATE_HOME", "create_home",
"", "");
my @login_defs_prop_array_suse =
(
"QMAIL_DIR", "qmail_dir",
"MAIL_DIR", "mailbox_dir",
"MAIL_FILE", "mailbox_file",
"PASS_MAX_DAYS", "pwd_maxdays",
"PASS_MIN_DAYS", "pwd_mindays",
"PASS_MIN_LEN", "pwd_min_length",
"PASS_WARN_AGE", "pwd_warndays",
"UID_MIN", "umin",
"UID_MAX", "umax",
"SYSTEM_GID_MIN", "gmin",
"GID_MAX", "gmax",
"USERDEL_CMD", "del_user_additional_command",
"CREATE_HOME", "create_home",
"", "");
if ($Utils::Backend::tool{"platform"} =~ /^suse/)
{
@prop_array = @login_defs_prop_array_suse;
}
else
{
@prop_array = @login_defs_prop_array_default;
}
for ($i = 0; $prop_array [$i] ne ""; $i += 2)
{
$login_defs_prop_map {$prop_array [$i]} = $prop_array [$i + 1];
$login_defs_prop_map {$prop_array [$i + 1]} = $prop_array [$i];
}
}
sub get_profiles_prop_array
{
my @prop_array;
my @profiles_prop_array_default =
(
"NAME" , "name",
"COMMENT", "comment",
"LOGINDEFS", "login_defs",
"HOME_PREFFIX", "home_prefix",
"SHELL", "shell",
"GROUP", "group",
"SKEL_DIR", "skel_dir",
"QMAIL_DIR" , "qmail_dir",
"MAIL_DIR" , "mailbox_dir",
"MAIL_FILE" , "mailbox_file",
"PASS_RANDOM", "pwd_random",
"PASS_MAX_DAYS" , "pwd_maxdays",
"PASS_MIN_DAYS" , "pwd_mindays",
"PASS_MIN_LEN" , "pwd_min_length",
"PASS_WARN_AGE" , "pwd_warndays",
"UID_MIN" , "umin",
"UID_MAX" , "umax",
"GID_MIN" , "gmin",
"GID_MAX" , "gmax",
"USERDEL_CMD" , "del_user_additional_command",
"CREATE_HOME" , "create_home",
"", "");
my @profiles_prop_array_suse =
(
"NAME" , "name",
"COMMENT", "comment",
"LOGINDEFS", "login_defs",
"HOME_PREFFIX", "home_prefix",
"SHELL", "shell",
"GROUP", "group",
"SKEL_DIR", "skel_dir",
"QMAIL_DIR" , "qmail_dir",
"MAIL_DIR" , "mailbox_dir",
"MAIL_FILE" , "mailbox_file",
"PASS_RANDOM", "pwd_random",
"PASS_MAX_DAYS" , "pwd_maxdays",
"PASS_MIN_DAYS" , "pwd_mindays",
"PASS_MIN_LEN" , "pwd_min_length",
"PASS_WARN_AGE" , "pwd_warndays",
"UID_MIN" , "umin",
"UID_MAX" , "umax",
"GID_MIN" , "gmin",
"GID_MAX" , "gmax",
"USERDEL_CMD" , "del_user_additional_command",
"CREATE_HOME" , "create_home",
"", "");
if ($Utils::Backend::tool{"platform"} =~ /suse/)
{
@prop_array = @profiles_prop_array_suse;
}
else
{
@prop_array = @profiles_prop_array_default;
}
for ($i = 0; $prop_array[$i] ne ""; $i += 2)
{
$profiles_prop_map {$prop_array [$i]} = $prop_array [$i + 1];
$profiles_prop_map {$prop_array [$i + 1]} = $prop_array [$i];
}
}
#FIXME: do not hardcode GIDs like that
my $rh_logindefs_defaults = {
'shell' => '/bin/bash',
'group' => -1,
'skel_dir' => '/etc/skel/',
};
my $gentoo_logindefs_defaults = {
'shell' => '/bin/bash',
'group' => 100,
'skel_dir' => '/etc/skel/',
};
my $freebsd_logindefs_defaults = {
'shell' => '/bin/sh',
'group' => -1,
'skel_dir' => '/etc/skel/',
};
my $logindefs_dist_map = {
'redhat-6.2' => $rh_logindefs_defaults,
'redhat-7.0' => $rh_logindefs_defaults,
'redhat-7.1' => $rh_logindefs_defaults,
'redhat-7.2' => $rh_logindefs_defaults,
'redhat-7.3' => $rh_logindefs_defaults,
'redhat-8.0' => $rh_logindefs_defaults,
'mandrake-9.0' => $rh_logindefs_defaults,
'pld-1.0' => $rh_logindefs_defaults,
'fedora-1' => $rh_logindefs_defaults,
'debian' => $rh_logindefs_defaults,
'vine-3.0' => $rh_logindefs_defaults,
'gentoo' => $gentoo_logindefs_defaults,
'archlinux' => $gentoo_logindefs_defaults,
'slackware-9.1.0' => $gentoo_logindefs_defaults,
'freebsd-5' => $freebsd_logindefs_defaults,
'suse-9.0' => $gentoo_logindefs_defaults,
'solaris-2.11' => $gentoo_logindefs_defaults,
};
# Add reporting table.
&Utils::Report::add ({
'users_read_profiledb_success' => ['info', 'Profiles read successfully.'],
'users_read_profiledb_fail' => ['warn', 'Profiles read failed.'],
'users_read_users_success' => ['info', 'Users read successfully.'],
'users_read_users_fail' => ['warn', 'Users read failed.'],
'users_read_users_invalid' => ['warn', 'Invalid user found while reading (missing fields).'],
'users_read_groups_success' => ['info', 'Groups read successfully.'],
'users_read_groups_fail' => ['warn', 'Groups read failed.'],
'users_read_shells_success' => ['info', 'Shells read successfully.'],
'users_read_shells_fail' => ['warn', 'Reading shells failed.'],
'users_write_profiledb_success' => ['info', 'Profiles written successfully.'],
'users_write_profiledb_fail' => ['warn', 'Writing profiles failed.'],
'users_write_users_success' => ['info', 'Users written successfully.'],
'users_write_users_fail' => ['warn', 'Writing users failed.'],
'users_write_groups_success' => ['info', 'Groups written successfully.'],
'users_write_groups_fail' => ['warn', 'Writing groups failed.'],
});
sub logindefs_add_defaults
{
# Common for all distros
my $logindefs = {
'home_prefix' => '/home/',
};
&get_profiles_prop_array ();
# Distro specific
my $dist_specific = $logindefs_dist_map->{$Utils::Backend::tool{"platform"}};
# Just to be 100% sure SOMETHING gets filled:
unless ($dist_specific)
{
$dist_specific = $rh_logindefs_defaults;
}
foreach my $key (keys %$dist_specific)
{
# Make sure there's no crappy entries
if (exists ($profiles_prop_map{$key}) || $key eq "groups")
{
$logindefs->{$key} = $dist_specific->{$key};
}
}
return $logindefs;
}
sub get_logindefs
{
my $logindefs;
&get_login_defs_prop_array ();
$logindefs = &logindefs_add_defaults ();
# Get new data in case someone has changed login_defs manually.
my $fh = &Utils::File::open_read_from_names (@login_defs_names);
if ($fh)
{
while (<$fh>)
{
next if &Utils::Util::ignore_line ($_);
chomp;
my @line = split /[ \t]+/;
if (exists $login_defs_prop_map{$line[0]})
{
$logindefs->{$login_defs_prop_map{$line[0]}} = $line[1];
}
}
close $fh;
}
else
{
# Put safe defaults for distros/OS that don't have any defaults file
$logindefs->{"umin"} = '1000';
$logindefs->{"umax"} = '60000';
$logindefs->{"gmin"} = '1000';
$logindefs->{"gmax"} = '60000';
}
return $logindefs;
}
sub get
{
my ($ifh, @users, %users_hash, $fd, @passwd_status);
my (@line, @users);
# Find the passwd file.
$ifh = &Utils::File::open_read_from_names(@passwd_names);
return unless ($ifh);
while (<$ifh>)
{
chomp;
# FreeBSD allows comments in the passwd file.
next if &Utils::Util::ignore_line ($_);
@line = split ':', $_, -1;
$login = $line[$LOGIN];
# skip invalid users, else they will create troubles
if (($line[$LOGIN] eq "") || ($line[$UID] eq ""))
{
&Utils::Report::do_report ("users_read_users_invalid");
next;
}
@comment = split ',', $line[$COMMENT], 5;
# we need to make sure that there are 5 elements
push @comment, "" while (scalar (@comment) < 5);
$line[$COMMENT] = [@comment];
# always return empty string - anyway, passwd should be in /etc/shadow
$line[$PASSWD] = "";
$users_hash{$login} = [@line];
# Detect lock status of password
# We run 'passwd' instead of reading /etc/shadow directly
# to avoid leaving sensitive data in memory (hard to clear in perl)
$fd = &Utils::File::run_pipe_read ("passwd -S $login");
@passwd_status = split ' ', <$fd>;
&Utils::File::close_file ($fd);
if ($passwd_status[1] eq "P")
{
$users_hash{$login}[$PASSWD_STATUS] = 0;
}
elsif ($passwd_status[1] eq "NP")
{
$users_hash{$login}[$PASSWD_STATUS] = 1;
}
else # "L", means locked password
{
$users_hash{$login}[$PASSWD_STATUS] = 1 << 1;
}
# max value for an unsigned 32 bits integer means no main group
$users_hash{$login}[$GID] = 0xFFFFFFFF if (!$users_hash{$login}[$GID]);
# TODO: read actual values
$users_hash{$login}[$ENC_HOME] = 0;
$users_hash{$login}[$HOME_FLAGS] = 0;
$users_hash{$login}[$LOCALE] = "";
$users_hash{$login}[$LOCATION] = "";
$users_hash{$login}[$FACE] = "";
}
&Utils::File::close_file ($ifh);
# transform the hash into an array
foreach $login (keys %users_hash)
{
push @users, $users_hash{$login};
}
return \@users;
}
sub del_user
{
my ($user) = @_;
my (@command, $remove_home);
$remove_home = $$user[$HOME_FLAGS] & 1;
if ($Utils::Backend::tool{"system"} eq "FreeBSD")
{
if ($remove_home)
{
@command = ($cmd_pw, "userdel", "-r", "-n", $$user[$LOGIN]);
}
else
{
@command = ($cmd_pw, "userdel", "-n", $$user[$LOGIN]);
}
}
elsif ($cmd_deluser) # use deluser (preferred method)
{
if ($remove_home)
{
@command = ($cmd_deluser, "--remove-home", $$user[$LOGIN]);
}
else
{
@command = ($cmd_deluser, $$user[$LOGIN]);
}
}
else # use userdel
{
if ($remove_home)
{
@command = ($cmd_userdel, "--remove", $$user[$LOGIN]);
}
else
{
@command = ($cmd_userdel, $$user[$LOGIN]);
}
}
&Utils::File::run (@command);
}
sub change_user_chfn
{
my ($login, $old_comment, $comment) = @_;
my ($fname, $office, $office_phone, $home_phone);
my (@command, $str);
return if !$login;
# Compare old and new data
return if (Utils::Util::struct_eq ($old_comment, $comment));
$str = join (",", @$comment);
if ($Utils::Backend::tool{"system"} eq "FreeBSD")
{
@command = ($cmd_pw, "usermod", "-n", $login,
"-c", $str);
}
else
{
@command = ($cmd_usermod, "-c", $str, $login);
}
&Utils::File::run (@command);
}
sub set_passwd
{
my ($login, $password, $passwd_status) = @_;
my ($pwdpipe);
# handle empty password via passwd, as all tools don't support it
if ($passwd_status & 1)
{
&Utils::File::run ("passwd", "-d", $login);
return;
}
if ($Utils::Backend::tool{"system"} eq "FreeBSD")
{
my ($command);
$command = "$cmd_pw usermod \'$login\' -h 0";
$pwdpipe = &Utils::File::run_pipe_write ($command);
print $pwdpipe $password;
&Utils::File::close_file ($pwdpipe);
}
elsif ($Utils::Backend::tool{"system"} eq "SunOS")
{
my ($command);
$command = "$cmd_passwd --stdin \'$login\'";
$pwdpipe = &Utils::File::run_pipe_write ($command);
print $pwdpipe $password;
&Utils::File::close_file ($pwdpipe);
}
else
{
$pwdpipe = &Utils::File::run_pipe_write ($cmd_chpasswd);
print $pwdpipe "$login:$password";
&Utils::File::close_file ($pwdpipe);
}
}
# Enable/disable password, only call if value has changed
sub set_lock
{
my ($login, $passwd_status) = @_;
my ($pwdpipe);
if ($passwd_status & (1 << 1))
{
&Utils::File::run ("passwd", "-l", $login);
}
else
{
&Utils::File::run ("passwd", "-u", $login);
}
}
# This function allows empty values to be passed, in which cas
# the platform's tools will choose the default.
sub add_user
{
my ($user) = @_;
my ($tool_mkdir, $chown_home, $real_uid, $real_gid);
$tool_mkdir = &Utils::File::locate_tool ("mkdir");
# If directory is specified, ensure its parents exist.
# When using default prefix, we assume the directory exists.
if ($$user[$HOME])
{
my $home_parents, $erase_home;
$home_parents = $$user[$HOME];
$home_parents =~ s/\/+[^\/]+\/*$//;
&Utils::File::run ($tool_mkdir, "-p", $home_parents);
$erase_home = $$user[$HOME_FLAGS] & (1 << 3);
# Remove home if asked, it will be created from scratch by platform tools
if ($erase_home && -e $$user[$HOME] && $$user[$HOME] ne "/")
{
# Remove trailing slash(es) to avoid issues with rm on symlinks
$$user[$HOME] =~ s|/*$||;
@command = ("rm", "-Rf", $$user[$HOME]);
&Utils::File::run (@command);
}
}
# max value means default UID or GID here
$real_uid = ($$user[$UID] != 0xFFFFFFFF);
$real_gid = ($$user[$GID] != 0xFFFFFFFF);
if ($Utils::Backend::tool{"system"} eq "FreeBSD")
{
my $logindefs;
# FreeBSD doesn't create the home directory
if (!$$user[$HOME])
{
$logindefs = &get_logindefs ();
$$user[$HOME] = "$$logindefs{'home_prefix'}/$$user[$LOGIN]";
}
&Utils::File::run ($tool_mkdir, "-p", $$user[$HOME]);
@command = ($cmd_pw, "useradd", "-n", $$user[$LOGIN],
"-h", "-"); # disable login until password is set
push (@command, ("-s", $$user[$HOME])) if ($$user[$HOME]);
push (@command, ("-s", $$user[$SHELL])) if ($$user[$SHELL]);
push (@command, ("-u", $$user[$UID])) if ($real_uid);
push (@command, ("-g", $$user[$GID])) if ($real_gid);
&Utils::File::run (@command);
}
elsif ($Utils::Backend::tool{"system"} eq "SunOS")
{
@command = ($cmd_useradd);
push (@command, ("-d", $$user[$HOME])) if ($$user[$HOME]);
push (@command, ("-s", $$user[$SHELL])) if ($$user[$SHELL]);
push (@command, ("-u", $$user[$UID])) if ($real_uid);
push (@command, ("-g", $$user[$GID])) if ($real_gid);
push (@command, $$user[$LOGIN]);
&Utils::File::run (@command);
}
else
{
if ($cmd_adduser &&
$Utils::Backend::tool{"platform"} !~ /^slackware/ &&
$Utils::Backend::tool{"platform"} !~ /^archlinux/ &&
$Utils::Backend::tool{"platform"} !~ /^redhat/ &&
$Utils::Backend::tool{"platform"} !~ /^gentoo/)
{
# use adduser if available and valid (slackware one is b0rk)
# set empty gecos fields and password, they will be filled out later
@command = ($cmd_adduser, "--gecos", "",
"--disabled-password");
push (@command, ("--home", $$user[$HOME])) if ($$user[$HOME]);
push (@command, ("--shell", $$user[$SHELL])) if ($$user[$SHELL]);
push (@command, ("--uid", $$user[$UID])) if ($real_uid);
push (@command, ("--gid", $$user[$GID])) if ($real_gid);
# Allow encrypted home if the tool is present
if ($$user[$ENC_HOME] && &Utils::File::locate_tool ("mount.ecryptfs"))
{
push (@command, "--encrypt-home");
}
push (@command, $$user[$LOGIN]);
&Utils::File::run (@command);
}
else
{
# fallback to useradd
@command = ($cmd_useradd, "-m");
push (@command, ("-d", $$user[$HOME])) if ($$user[$HOME]);
push (@command, ("-s", $$user[$SHELL])) if ($$user[$SHELL]);
push (@command, ("-u", $$user[$UID])) if ($real_uid);
push (@command, ("-g", $$user[$GID])) if ($real_gid);
push (@command, $$user[$LOGIN]);
&Utils::File::run (@command);
}
}
&change_user_chfn ($$user[$LOGIN], undef, $$user[$COMMENT]);
&set_passwd ($$user[$LOGIN], $$user[$PASSWD], $$user[$PASSWD_STATUS]);
&set_lock ($$user[$LOGIN], $$user[$PASSWD_STATUS]);
$chown_home = $$user[$HOME_FLAGS] & (1 << 1);
# update user to get values that were filled
$user = &get_user ($$user[$LOGIN]);
# ensure user owns its home dir if asked
if ($chown_home && $$user[$HOME] ne "/")
{
@command = ("chown", "-R", "$$user[$LOGIN]:$$user[$GID]", $$user[$HOME]);
&Utils::File::run (@command);
}
# Return the new user with default values filled.
# Returns NULL if user doesn't exist, which means failure.
return $user;
}
sub change_user
{
my ($old_user, $new_user) = @_;
my $chown_home, $move_home, $copy_home, $erase_home;
if ($Utils::Backend::tool{"system"} eq "FreeBSD")
{
@command = ($cmd_pw, "usermod", $$old_user[$LOGIN],
"-l", $$new_user[$LOGIN],
"-u", $$new_user[$UID],
"-d", $$new_user[$HOME],
"-g", $$new_user[$GID],
"-s", $$new_user[$SHELL]);
&Utils::File::run (@command);
}
else
{
@command = ($cmd_usermod, "-d", $$new_user[$HOME],
"-g", $$new_user[$GID],
"-l", $$new_user[$LOGIN],
"-s", $$new_user[$SHELL],
"-u", $$new_user[$UID],
$$old_user[$LOGIN]);
&Utils::File::run (@command);
}
&change_user_chfn ($$new_user[$LOGIN], $$old_user[$COMMENT], $$new_user[$COMMENT]);
&set_passwd ($$new_user[$LOGIN], $$new_user[$PASSWD], $$user[$PASSWD_STATUS]);
# Only change lock status if status has changed
if (($$new_user[$PASSWD_STATUS] & (1 << 1)) != ($$old_user[$PASSWD_STATUS] & (1 << 1)))
{
&set_lock ($$new_user[$LOGIN], $$new_user[$PASSWD_STATUS]);
}
# Home directory handling
if ($$new_user[$HOME] ne $$old_user[$HOME])
{
# remove old home dir
$remove_home = $$new_user[$HOME_FLAGS] & (1 << 0);
# ensure user owns home dir
$chown_home = $$new_user[$HOME_FLAGS] & (1 << 1);
# copy old home files to new dir
$copy_home = $$new_user[$HOME_FLAGS] & (1 << 2);
# remove files present in path to new home
$erase_home = $$new_user[$HOME_FLAGS] & (1 << 3);
# Remove trailing slash(es) to avoid issues with rm on symlinks
# '/' becomes empty, which is easier to check for security below
$$new_user[$HOME] =~ s|/*$||;
$$old_user[$HOME] =~ s|/*$||;
if ($erase_home && $$new_user[$HOME] && -e $$new_user[$HOME])
{
@command = ("rm", "-Rf", $$new_user[$HOME]);
&Utils::File::run (@command);
}
if ($copy_home && $$new_user[$HOME] && $$old_user[$HOME])
{
# Remove new directory if present, to avoid troubles when merging.
# GUIs should ask the user before passing this flag anyway!
if (-e $$new_user[$HOME])
{
@command = ("rm", "-Rf", $$new_user[$HOME]);
&Utils::File::run (@command);
}
if (-e $$old_user[$HOME])
{
if ($remove_home)
{
@command = ("mv", "-f", $$old_user[$HOME], $$new_user[$HOME]);
}
else
{
if ($Utils::Backend::tool{"system"} eq "SunOS")
{
@command = ("cp", "-RPpf", $$old_user[$HOME], $$new_user[$HOME]);
}
else
{
@command = ("cp", "-af", $$old_user[$HOME], $$new_user[$HOME]);
}
}
&Utils::File::run (@command);
}
}
elsif ($remove_home && $$old_user[$HOME] && -e $$old_user[$HOME] )
{
@command = ("rm", "-Rf", $$old_user[$HOME]);
&Utils::File::run (@command);
}
# Create home directory owned by user if not present
# If a file with this name exists, skip
if (!-e $$new_user[$HOME] && $$new_user[$HOME])
{
@command = ("mkdir", "-p", $$new_user[$HOME]);
&Utils::File::run (@command) if (!-d $$new_user[$HOME]);
@command = ("chown", "-f", "$$new_user[$LOGIN]:$$new_user[$GID]", $$new_user[$HOME]);
&Utils::File::run (@command);
}
elsif ($chown_home && $$new_user[$HOME])
{
@command = ("chown", "-Rf", "$$new_user[$LOGIN]:$$new_user[$GID]", $$new_user[$HOME]);
&Utils::File::run (@command);
}
}
# Erase password string to avoid it from staying in memory
$$new_user[$PASSWD] = '0' x length ($$new_user[$PASSWD]);
}
sub set_logindefs
{
my ($config) = @_;
my ($logindefs, $key, $file);
return unless $config;
&get_login_defs_prop_array ();
foreach $key (@login_defs_names)
{
if (-f $key)
{
$file = $key;
last;
}
}
unless ($file)
{
&Utils::Report::do_report ("file_open_read_failed", join (", ", @login_defs_names));
return;
}
foreach $key (keys (%$config))
{
# Write ONLY login.defs values.
if (exists ($login_defs_prop_map{$key}))
{
&Utils::Replace::split ($file, $login_defs_prop_map{$key}, "[ \t]+", $$config{$key});
}
}
}
sub get_self
{
my ($uid) = @_;
my ($users) = &get ();
foreach $user (@$users)
{
next if ($uid != $$user[$UID]);
return ($$user[$COMMENT], $$user[$LOCALE], $$user[$LOCATION]);
}
return ([""], "");
}
sub get_user
{
my ($login) = @_;
my ($users) = &get ();
foreach $user (@$users)
{
next if ($login ne $$user[$LOGIN]);
return $user;
}
return NULL;
}
sub set_user
{
my ($new_user) = @_;
my ($users) = &get ();
# Make backups manually, otherwise they don't get backed up.
&Utils::File::do_backup ($_) foreach (@passwd_names);
&Utils::File::do_backup ($_) foreach (@shadow_names);
foreach $user (@$users)
{
if ($$new_user[$LOGIN] eq $$user[$LOGIN])
{
&change_user ($user, $new_user);
return;
}
}
}
sub set_self
{
my ($uid, @comments, $locale, $location) = @_;
my ($users) = &get ();
# Make backups manually, otherwise they don't get backed up.
&Utils::File::do_backup ($_) foreach (@passwd_names);
&Utils::File::do_backup ($_) foreach (@shadow_names);
foreach $user (@$users)
{
if ($uid == $$user[$UID])
{
&change_user_chfn ($$user[$LOGIN], $$user[$COMMENT], @comments);
return;
}
}
# TODO: change locale and location
}
sub get_files
{
my ($arr);
push @$arr, @passwd_names;
push @$arr, @shadow_names;
return $arr;
}
1;