File: //scripts.20110531.215904.25158/realadduser
#!/usr/bin/perl
# cpanel - realadduser Copyright(c) 2010 cPanel, Inc.
# All rights Reserved.
# copyright@cpanel.net http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited
BEGIN {
$ENV{'LANG'} = 'C';
unshift @INC, '/usr/local/cpanel';
}
use strict;
use Cpanel::OSSys;
use Fcntl ();
use Cpanel::RcsRecord ();
use Cpanel::SafeFile ();
use AcctLock ();
use Cpanel::Logger ();
use Cpanel::NSCD ();
use Cpanel::SafetyBits ();
use Cpanel::Logger ();
my $logger = Cpanel::Logger->new();
my $mailgid = ( getgrnam('mail') )[2];
my $hasmd5auth = 0;
if ( open my $sysauth_fh, '<', '/etc/pam.d/system-auth' ) {
while ( my $line = readline $sysauth_fh ) {
if ( $line =~ m/^password.*md5/ ) {
$hasmd5auth = 1;
last;
}
}
close $sysauth_fh;
}
my $system = ( Cpanel::OSSys::uname() )[0];
my $nochecks = 0;
my $shell = 0;
my $debug = 0;
if (@ARGV) {
while ( my $arg = shift @ARGV ) {
last if !$arg;
if ( $arg =~ m/^-+(\S+)/ ) {
my $flag = $1;
if ( $flag eq 'nochecks' ) {
$nochecks = 1;
}
elsif ( $flag =~ m/^(no)?shell$/ ) {
if ($1) {
$shell = 'noshell';
}
else {
$shell = shift @ARGV;
}
}
elsif ( $flag =~ m/debug/i ) {
$debug = 1;
}
}
else {
unshift @ARGV, $arg;
last;
}
}
}
my $pwd_mkdb = 'pwd_mkdb';
my $username = $ARGV[0];
my $homeroot = $ARGV[1];
my $pass = $ARGV[2];
my $myuid = $ARGV[3];
my $mygid = $ARGV[4];
if ( !$ARGV[0] ) {
my $up;
chomp( $up = <STDIN> );
my @UP = split( / /, $up );
$username = $UP[0];
$homeroot = $UP[1];
$pass = $UP[2];
}
if ( !$username ) {
Cpanel::Logger::logger(
{
'message' => "Syntax: adduser <username> <homeroot> <password>",
'level' => 'die',
'service' => 'realadduser',
'output' => 2,
'backtrace' => 0,
}
);
}
if ( !$homeroot ) {
Cpanel::Logger::logger(
{
'message' => "Syntax: adduser <username> <homeroot> <password>",
'level' => 'die',
'service' => 'realadduser',
'output' => 2,
'backtrace' => 0,
}
);
}
if ( !-e '/etc/allowstupidstuff' ) {
if ( $username =~ /^\d+/ ) {
Cpanel::Logger::logger(
{
'message' => "Invalid username $username. Usernames must not begin with a number.",
'level' => 'die',
'service' => 'realadduser',
'output' => 2,
'backtrace' => 0,
}
);
}
}
if ( !$shell ) {
if ( -x '/bin/rstsh' ) {
$shell = '/bin/rstsh';
}
elsif ( -x '/bin/bash' ) {
$shell = '/bin/bash';
}
elsif ( -x '/usr/local/bin/bash' ) {
$shell = '/usr/local/bin/bash';
}
elsif ( -x '/bin/sh' ) {
$shell = '/bin/sh';
}
else {
Cpanel::Logger::logger(
{
'message' => "No valid shell found. Using /bin/false",
'level' => 'warn',
'service' => 'realadduser',
'output' => 2,
'backtrace' => 0,
}
);
$shell = '/bin/false';
}
}
elsif ( $shell eq 'noshell' ) {
if ( -x '/usr/local/cpanel/bin/noshell' ) {
$shell = '/usr/local/cpanel/bin/noshell';
}
else {
$shell = '/bin/false';
}
}
if ($debug) {
Cpanel::Logger::logger(
{
'message' => "User: $username Home: $homeroot Shell: $shell Checks: $nochecks",
'level' => 'debug',
'service' => 'realadduser',
'output' => 1,
'backtrace' => 0,
}
);
exit;
}
my $home = $homeroot;
if ( !-e $home ) {
mkdir( $home, 0755 );
}
if ( $pass eq '' ) {
Cpanel::Logger::logger(
{
'message' => "No password specified for $username",
'level' => 'info',
'service' => 'realadduser',
'output' => 1,
'backtrace' => 0,
}
);
$pass = '*';
}
my $minuid = 500;
my $mingid = 500;
my $maxuid = 32000;
my $maxgid = 32000;
# Set minuid according to /etc/wwwacct.conf
if ( open my $wwwacct_fh, '<', '/etc/wwwacct.conf' ) {
while ( my $line = readline $wwwacct_fh ) {
chomp $line;
next if $line =~ m/^;/;
if ( $line =~ m/^\s*MINUID\s+(\d+)/ ) {
$minuid = $1;
}
}
close $wwwacct_fh;
if ( int($minuid) < 1 ) {
$minuid = 500;
}
if ( $minuid < 100 ) {
$minuid = 100;
}
}
my $username_nodash = $username;
if ( !$nochecks ) {
$username_nodash =~ s/-//g;
}
my @UIDS;
my @GIDS;
if ( -e '/etc/master.passwd' ) {
Cpanel::RcsRecord::rcsrecord( '/etc/master.passwd', "BEGIN realadduser user $username" );
}
else {
Cpanel::RcsRecord::rcsrecord( '/etc/shadow', "BEGIN realadduser user $username" );
}
Cpanel::RcsRecord::rcsrecord( '/etc/passwd', "BEGIN realadduser user $username" );
AcctLock::acctlock();
my $passwdlock = Cpanel::SafeFile::safeopen( \*PASSWD, '+<', '/etc/passwd' );
if( !$passwdlock ) {
$logger->die("Could not edit /etc/passwd");
}
while (<PASSWD>) {
my ( $user, undef, $uid, $gid, undef, undef ) = split( /:/, $_, 5 );
if ( $user eq $username ) {
Cpanel::SafeFile::safeclose( \*PASSWD, $passwdlock );
AcctLock::acctunlock();
Cpanel::Logger::logger(
{
'message' => "User $username already exists",
'level' => 'die',
'service' => 'realadduser',
'output' => 2,
'backtrace' => 0,
}
);
}
elsif ( !$nochecks ) {
my $user_nodash = $user;
$user_nodash =~ s/-//g;
if ( $user_nodash eq $username_nodash ) {
Cpanel::SafeFile::safeclose( \*PASSWD, $passwdlock );
AcctLock::acctunlock();
if ( $user =~ m/-/ ) {
Cpanel::Logger::logger(
{
'message' => "Username $username with a dash already exists",
'level' => 'die',
'service' => 'realadduser',
'output' => 2,
'backtrace' => 0,
}
);
}
elsif ( $username =~ m/-/ ) {
Cpanel::Logger::logger(
{
'message' => "Username $username without a dash already exists",
'level' => 'die',
'service' => 'realadduser',
'output' => 2,
'backtrace' => 0,
}
);
}
}
}
if ( $uid > $minuid ) {
push @UIDS, $uid;
}
if ( $gid > $mingid ) {
push @GIDS, $gid;
}
}
my $grouplock = Cpanel::SafeFile::safeopen( \*GROUP, '+<', '/etc/group' );
if( !$grouplock ) {
$logger->die("Could not edit /etc/group");
}
while (<GROUP>) {
my ( $user, undef, $gid, undef ) = split( /:/, $_, 4 );
if ( $gid > $mingid ) {
push @GIDS, $gid;
}
}
if (!$myuid) {
$myuid = $maxuid;
my $lastuid = $maxuid;
foreach my $uid ( sort { $a <=> $b } @UIDS ) {
if ( ( $uid - $lastuid ) > 1 ) {
$myuid = ( $lastuid + 1 );
last;
}
$lastuid = $uid;
}
if ( $myuid == $maxuid ) {
$myuid = ( $lastuid + 1 );
}
}
if (!$mygid) {
$mygid = $maxgid;
my $lastgid = $maxgid;
foreach my $gid ( sort { $a <=> $b } @GIDS ) {
if ( ( $gid - $lastgid ) > 1 ) {
$mygid = ( $lastgid + 1 );
last;
}
$lastgid = $gid;
}
if ( $mygid == $maxgid ) {
$mygid = ( $lastgid + 1 );
}
}
if ( -e '/vsrvmgrq' ) {
my $nextuid = `/usr/local/cpanel/bin/vsrvmgradmin 0 UID`;
$nextuid =~ s/\n//g;
if ( $nextuid < 1 ) {
Cpanel::SafeFile::safeclose( \*PASSWD, $passwdlock );
Cpanel::SafeFile::safeclose( \*GROUP, $grouplock );
AcctLock::acctunlock();
Cpanel::Logger::logger(
{
'message' => "Unable to get uid from vserver master",
'level' => 'die',
'service' => 'realadduser',
'output' => 2,
'backtrace' => 0,
}
);
}
if ( $nextuid !~ /^\d+$/ ) {
Cpanel::SafeFile::safeclose( \*PASSWD, $passwdlock );
Cpanel::SafeFile::safeclose( \*GROUP, $grouplock );
AcctLock::acctunlock();
Cpanel::Logger::logger(
{
'message' => "Invalid uid from vserver master!!!",
'level' => 'die',
'service' => 'realadduser',
'output' => 2,
'backtrace' => 0,
}
);
}
$myuid = $nextuid;
$mygid = $nextuid;
}
my $random = '';
open( RANDOM, '/dev/urandom' );
read RANDOM, $random, 4096;
close(RANDOM);
$random =~ s/\W//g;
my $cpass = '';
if ( $pass eq '*' ) {
$cpass = '*';
}
else {
$cpass = '';
if ( -e '/scripts/md5crypt' && $hasmd5auth ) {
my ( $fd0, $fd1 ) = Cpanel::OSSys::pipe();
Cpanel::OSSys::write( $fd1, $pass, length($pass) );
Cpanel::OSSys::write( $fd1, "\n", length("\n") );
$cpass = `/scripts/md5crypt $fd0`;
}
$cpass =~ s/\n//g;
if ( $cpass eq '' ) {
while ( $cpass eq undef or $cpass =~ /:/ ) {
$cpass = crypt( $pass, $random );
}
}
}
my $mytime = int( time / ( 60 * 60 * 24 ) );
my $passwd = "${username}:x:${myuid}:${mygid}::${home}/${username}:${shell}\n";
my $masterpasswd = "${username}:${cpass}:${myuid}:${mygid}::0:0::${home}/${username}:${shell}\n";
my $shadow = "${username}:${cpass}:${mytime}::::::\n";
my $group = "${username}:x:${mygid}:${username}\n";
if ( $system =~ m/freebsd/i ) {
system( $pwd_mkdb, '-C', '/etc/master.passwd' );
# Unlock /etc/passwd
Cpanel::SafeFile::safeclose( \*PASSWD, $passwdlock );
my $mpasswdlock = Cpanel::SafeFile::safeopen( \*MPASSWD, '>>', '/etc/master.passwd' );
if( !$mpasswdlock ) {
$logger->die("Could not write to /etc/master.passwd");
}
print MPASSWD $masterpasswd;
Cpanel::SafeFile::safeclose( \*MPASSWD, $mpasswdlock );
system( $pwd_mkdb, '-p', '/etc/master.passwd' );
if ($?) {
warn "``$pwd_mkdb'' failed\n";
Cpanel::SafeFile::safeclose( \*GROUP, $grouplock );
AcctLock::acctunlock();
exit( $? >> 8 );
}
}
else {
seek( PASSWD, 0, &Fcntl::SEEK_END );
print PASSWD $passwd;
my $shadowlock = Cpanel::SafeFile::safeopen( \*SHADOW, '>>', '/etc/shadow' );
if( !$shadowlock ) {
$logger->die("Could not write to /etc/shadow");
}
print SHADOW $shadow;
truncate( PASSWD, tell(PASSWD) );
Cpanel::SafeFile::safeclose( \*PASSWD, $passwdlock );
Cpanel::SafeFile::safeclose( \*SHADOW, $shadowlock );
}
seek( GROUP, 0, &Fcntl::SEEK_END );
print GROUP $group;
truncate( GROUP, tell(GROUP) );
Cpanel::SafeFile::safeclose( \*GROUP, $grouplock );
AcctLock::acctunlock();
mkdir( $home . '/' . $username, 0711 );
Cpanel::SafetyBits::safe_chown( $myuid, $mygid, $home . '/' . $username );
if ( my $pid = fork() ) {
waitpid( $pid, 0 );
}
else {
Cpanel::SafetyBits::setuids($username);
mkdir( $home . '/' . $username . '/mail', 0770 );
exit();
}
open( SPOOL, '>', '/var/spool/mail/' . $username );
close(SPOOL);
Cpanel::SafetyBits::safe_chown( $myuid, $mailgid, '/var/spool/mail/' . $username );
Cpanel::SafetyBits::safe_chmod( 0660, $myuid, '/var/spool/mail/' . $username );
if ( $system =~ m/linux/i && -e '/etc/chroothttpd' ) {
#update http env's passwd
system( '/usr/local/cpanel/bin/chroothttpd', '--updatefiles' );
}
Cpanel::Logger::logger(
{
'message' => "User $username added",
'level' => 'info',
'service' => 'realadduser',
'output' => 1,
'backtrace' => 0,
}
);
if ( -e '/etc/master.passwd' ) {
Cpanel::RcsRecord::rcsrecord( '/etc/master.passwd', "END realadduser user $username" );
}
else {
Cpanel::RcsRecord::rcsrecord( '/etc/shadow', "END realadduser user $username" );
}
Cpanel::RcsRecord::rcsrecord( '/etc/passwd', "END realadduser user $username" );
Cpanel::NSCD::clear_cache();