MOON
Server: Apache/2.2.31 (Unix) mod_ssl/2.2.31 OpenSSL/0.9.8e-fips-rhel5 mod_bwlimited/1.4
System: Linux csr818.wilogic.com 2.6.18-419.el5xen #1 SMP Fri Feb 24 22:50:37 UTC 2017 x86_64
User: digitals (531)
PHP: 5.4.45
Disabled: NONE
Upload Files
File: //scripts.20110531.215904.25158/mailperm
#!/usr/bin/perl
# cpanel - mailperm                               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 { unshift @INC, '/usr/local/cpanel'; }

use strict;
use Cpanel::Sys                     ();
use Cpanel::Usage                   ();
use Cpanel::SafeFind                ();
use Cpanel::Hostname                ();
use Cpanel::FileUtils::TouchFile    ();
use Cpanel::Rlimit                  ();
use Cpanel::AccessIds::SetUids      ();
use Cpanel::PwCache                 ();
use Cpanel::SafeFile                ();
use Cpanel::Config::LoadCpUserFile  ();
use Cpanel::Config::Users           ();
use Cpanel::Config::LoadUserDomains ();
use Cpanel::SafetyBits              ();
my $verbose   = 0;
my $skiplocal = 0;
my $skipperm  = 0;
my $checkuser;

# Argument processing
my %opts = (
    'verbose'          => \$verbose,
    'skiplocaldomains' => \$skiplocal,
    'skipserverperm'   => \$skipperm,
);

Cpanel::Usage::wrap_options( \@ARGV, \&usage, \%opts );

exit 0 if ( $ENV{'DONT_RUN_MAILPERM'} );

my $maxmem = ( 256 * ( 1024 * 1024 ) );
Cpanel::Rlimit::set_rlimit($maxmem);

@ARGV = ( grep( !/^--/, @ARGV ) );

if (@ARGV) {
    $checkuser = $ARGV[$#ARGV];
    if ( !( Cpanel::PwCache::getpwnam($checkuser) )[0] ) {
        warn "!! Specified user is not a valid system account !!\n\n";
        usage();
        exit 1;
    }
}

my %localdomains;
my %remotedomains;
my @ensure_dir_files = ( '/etc/valiases/', '/etc/vdomainaliases/', '/etc/vfilters/' );
my $mailgid          = ( getgrnam('mail') )[2];
my $hasmailnull      = Cpanel::PwCache::getpwnam('mailnull') ? 1 : 0;

# Script does the same check, but a stat here is better
# than a system call to another script
if ( -x '/etc/security/msec' ) {
    system '/scripts/mseclocal';
}

foreach my $dir (@ensure_dir_files) {
    if ( !-e $dir ) {
        mkdir $dir, 0711;
    }
}

if ( !$skipperm ) {
    require '/scripts/checkexim.pl';
    checkeximperms();

    foreach my $dir (@ensure_dir_files) {
        chmod 0711, $dir;
    }
}

chmod( 0666, '/dev/null' );

update_local_domains();

set_perms();

chmod( 0666, '/dev/null' );

sub update_local_domains {
    Cpanel::FileUtils::TouchFile::touchfile('/etc/remotedomains');
    Cpanel::FileUtils::TouchFile::touchfile('/etc/localdomains');

    # Remote domains
    my $rlock = Cpanel::SafeFile::safeopen( \*RD, '<', '/etc/remotedomains' );    #keep remotedomains and localdomains locked at the same time
    if ($rlock) {
        while ( my $line = readline( \*RD ) ) {
            chomp $line;
            $remotedomains{$line} = 1;
        }
    }

    # Local domains
    my $llock = Cpanel::SafeFile::safeopen( \*LD, '+<', '/etc/localdomains' );    #keep remotedomains and localdomains locked at the same time
    if ($llock) {
        while ( my $line = readline( \*LD ) ) {
            chomp $line;
            $localdomains{$line} = 1;
        }
    }

    if ( !$skiplocal ) {
        Cpanel::Config::LoadUserDomains::loaduserdomains( \%localdomains, 1 );
    }

    # Ensure hostname is always included
    my $hostname = Cpanel::Hostname::gethostname();
    $localdomains{$hostname} = 1;

    my $update_failed = 0;
    if ( $llock && $rlock ) {

        # Update /etc/localdomains
        seek( LD, 0, 0 );
        foreach my $domain ( sort keys %localdomains ) {
            next if $domain =~ m/^\*/;                              # drop wildcard domains
            next if ( !Cpanel::Sys::validdomainname($domain) );
            if ( !$remotedomains{$domain} ) {
                print LD "$domain\n";
            }
        }
        truncate( LD, tell(LD) );
    }
    else {
        $update_failed = 1;
    }

    if ($llock) {
        Cpanel::SafeFile::safeclose( \*LD, $llock );
    }
    if ($rlock) {
        Cpanel::SafeFile::safeclose( \*RD, $rlock );
    }

    if ($update_failed) {
        die "Unable to update /etc/localdomains because a lock could not be obtained on /etc/remotedomains and /etc/localdomains.";
    }
}

sub set_perms {
    my @USERS = Cpanel::Config::Users::getcpusers();

    if ( !$checkuser ) { Cpanel::PwCache::init_passwdless_pwcache(); }

    foreach my $cpuser (@USERS) {
        next if ( $checkuser && $cpuser ne $checkuser );
        my ( $useruid, $usergid, $homedir ) = ( Cpanel::PwCache::getpwnam($cpuser) )[ 2, 3, 7 ];
        if ( !$useruid || !$usergid || !$homedir ) {
            warn "Skipping invalid user $cpuser";
            next;
        }

        my $cpuser_ref = Cpanel::Config::LoadCpUserFile::loadcpuserfile($cpuser);
        next if ( !scalar keys %{$cpuser_ref} );

        my @DOMAINS;
        if ( $cpuser_ref->{'DOMAIN'} )      { push @DOMAINS, $cpuser_ref->{'DOMAIN'}; }
        if ( ref $cpuser_ref->{'DOMAINS'} ) { push @DOMAINS, @{ $cpuser_ref->{'DOMAINS'} }; }

        if ( -d "$homedir/mail" ) {
            Cpanel::SafetyBits::safe_chmod( 0770, $useruid, $homedir . '/mail' );
            if ( -e "$homedir/mail/inbox" ) {
                Cpanel::SafetyBits::safe_chmod( 0660, $useruid, $homedir . '/mail/inbox' );
            }
            if ( !-l "$homedir/mail" ) {

                # Fix perms on mbox style directories
                if ( my $chmodpid = fork() ) {
                    waitpid( $chmodpid, 0 );
                }
                else {
                    Cpanel::AccessIds::SetUids::setuids( $useruid, $usergid ) || die "Could not setuid to $cpuser ($useruid,$usergid).";
                    $0 = 'mailperm - processing ' . $cpuser;
                    Cpanel::SafeFind::find(
                        {
                            wanted => sub {
                                return if ( !$File::Find::name );
                                next   if ( -l $File::Find::name );
                                my ( $mode, $fuid, $fgid ) = ( stat(_) )[ 2, 4, 5 ];

                                $File::Find::name =~ /(.*)/;
                                my $safefile = $1;

                                if ( $fuid != $useruid || $fgid != $usergid ) {
                                    my $changed = chown( $useruid, $usergid, $safefile );
                                    if ($verbose) {
                                        if ($changed) {
                                            print "Fixed ownership of $File::Find::name : was ($fuid:$fgid), now ($useruid:$usergid)\n";
                                        }
                                        else {
                                            print "Unable to fix ownership of $File::Find::name : currently ($fuid:$fgid), should be ($useruid:$usergid)\n";
                                        }
                                    }
                                }
                                return
                                  if ( $File::Find::name =~
                                    m/\/(?:courierimapkeywords|courierpop3dsizelist|dovecot-uidvalidity|dovecot-keywords|dovecot.index.log.2|dovecot.index|dovecot-uidlist|subscriptions|dovecot.index.cache|dovecot.index.log|maildirsize|courierimapuiddb)$/
                                    || $File::Find::name =~ m/\.cppop\.cache(?:\.msgs)?$/ );
                                return if -d _;    # Reuse previous stat
                                $mode = sprintf '%04o', $mode & 07777;
                                if ( $mode ne '0660' ) {
                                    my $changed = chmod( 0660, $safefile );
                                    if ($verbose) {
                                        if ($changed) {
                                            print "Fixed permissions of $File::Find::name : was ($mode), now (0660)\n";
                                        }
                                        else {
                                            print "Unable to fix permissions of $File::Find::name : currently ($mode), should be (0660)\n";
                                        }
                                    }

                                }
                            },
                            'follow'   => 0,
                            'no_chdir' => 1
                        },
                        $homedir . '/mail'
                    );

                    exit 0;
                }
            }
            else {
                print "Skipping $homedir/mail. Directory is symlinked.\n";
            }
        }

        if ($hasmailnull) {
            if ( my $mailchownpid = fork() ) {
                waitpid( $mailchownpid, 0 );
            }
            else {
                my $targetuid = $useruid;
                my $targetgid = ( $hasmailnull ? $mailgid : $usergid );
                Cpanel::AccessIds::SetUids::setuids( $targetuid, $targetgid ) || die "Could not setuid to ($targetuid,$targetgid).";
                if ( -d "$homedir/etc" ) {
                    chmod( 0750, "$homedir/etc" );
                    chown( $targetuid, $targetgid, "$homedir/etc" );
                    foreach my $domain (@DOMAINS) {
                        next if !-d "$homedir/etc/$domain";
                        chmod( 0750, "$homedir/etc/$domain" );
                        chmod( 0640, "$homedir/etc/$domain/shadow" );
                        chmod( 0644, "$homedir/etc/$domain/passwd" );
                        chown( $targetuid, $targetgid, "$homedir/etc/$domain" );
                        chown( $targetuid, $targetgid, "$homedir/etc/$domain/shadow" );
                        chown( $targetuid, $targetgid, "$homedir/etc/$domain/passwd" );
                    }
                }
                exit(0);
            }
        }

        foreach my $domain (@DOMAINS) {
            next if ( !$domain || $domain =~ /^\./ || $domain =~ /\// );
            foreach my $dir (@ensure_dir_files) {
                if ( !-e $dir . $domain ) {
                    Cpanel::FileUtils::TouchFile::touchfile( $dir . $domain );
                }
                chown $useruid, $mailgid, $dir . $domain;    #safe root owns dir
                chmod 0644, $dir . $domain;                  #safe root owns dir
            }
        }

    }
}

sub usage {
    print <<'EOM';
Usage: mailperm <modifier> <user>

Arguments:
    <user> - Optional argument to specify the scope of
        the permissions checks. The specified user must
        be a valid system account.

Modifier Flags:
    --skiplocaldomains - This optional argument bypasses
        addition of missing domains to the /etc/localdomains
        file when specified. The localdomains file specifies
        to Exim that it should always accept delivery for 
        the listed domains. Remote domains are removed from
        /etc/localdomains regardless of this flag.

    --skipserverperm - This optional flag prevents modification
        of the mail system files used by Exim and limits the 
        scope of permission modifications to the mail account
        files.

    --verbose - This optional flag signals the utility to
        report detected permissions problems per user prior
        to modifying any permissions.
       
    --help - display this message and exit.

EOM
    exit;
}