#!/usr/bin/perl

use strict;
use warnings;
use File::Slurp;
use Data::Dumper;

# chgacctip
# changes an account to specified IP
# https://gatorwiki.hostgator.com/Admin/ChgAcctIP
# http://git.toolbox.hostgator.com/chgacctip
# Please submit all bug reports at bugs.hostgator.com
#
# (C) 2012 - HostGator.com, LLC

if ( ( !defined( $ARGV[0] ) ) || ( !defined( $ARGV[1] ) ) ) {
    die "Usage: username IP [y|n to reload/rebuild/restart]\n";

    #Example: perl myfile.pl username IP
}

my $users   = $ARGV[0];
my $resips  = $ARGV[1];
my $rebuild = $ARGV[2];

### Safety check for OCI boxes. Only safe to run right now for the monitoring account
my $cp_nat = {};
if ( -s '/var/cpanel/cpnat' ) {
    open( my $NAT_FH, '<', '/var/cpanel/cpnat' )
      or die "Could not open file '/var/cpanel/cpnat': $!";
    while ( my $line = <$NAT_FH> ) {
        my @entry = split( ' ', $line );
        $cp_nat->{ $entry[0] } = $entry[1];
    }
}

chomp($resips);
if ( $resips !~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/ ) {
    die "Not a valid IP address. Exiting.\n";
}

if ( ( keys %{$cp_nat} ) && ( !$cp_nat->{$resips} ) ) {
    die "$resips is not bound to the server or is not a private IP.\n";
}

chomp( my $oldip = resuserip($users) );

if ( $oldip !~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/ ) {
    die "Cannot determine old IP address. Exiting.\n";
}
print "Changing IP in named. \n";
changeuseripnamed( $users, $cp_nat->{$resips} ? $cp_nat->{$resips} : $resips, $cp_nat->{$oldip} ? $cp_nat->{$oldip} : $oldip );
print "Changing IP in cPanel data file. \n";
changeuserfileip( $users, $resips, $oldip );
changeuserdatafileip( $users, $resips, $oldip );
if ($rebuild) { rebuild($users); }

sub resuserip {
    my $resuser = shift;
    open( USERIP, "/var/cpanel/users/$resuser" ) || die("Could not open file <br> $!");
    while ( my $line = <USERIP> ) {
        if ( $line =~ /^IP=/ ) {
            my @line = split( "=", $line );
            return $line[1];

        }
    }
    close(USERIP);
}

sub getuserdomains {    # Username -- @rh_domains|Errorcode

    #  undef $lasterror;
    my $rh_user = $_[0];
    my @rh_domains;
    open USERFILE, "/var/cpanel/users/$_[0]" or die "getuserdomains($rh_user): Couldn't open /var/cpanel/users/$_[0]: $!\n";
    while (<USERFILE>) {
        push @rh_domains, $1 if m,^X?DNS\d*=(\S+),;
    }
    close USERFILE;
    return @rh_domains;
}

sub changeuseripnamed {    # Username, newip, oldip -- Errorcode
    my $rh_user  = $_[0];
    my $rh_newip = $_[1];
    my $rh_oldip = $_[2];
    my $RH_VERBOSE;
    my $rh_prefix  = "changeuseripnamed($rh_user, $rh_newip, $rh_oldip)";
    my @rh_domains = getuserdomains($rh_user);
    my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime(time);
    my $rh_timestamp = $year + 1900 . substr( 0 . ( $mon + 1 ), -2, 2 ) . substr( 0 . $mday, -2, 2 ) . substr( 0 . $hour, -2, 2 );
    my $rh_count;
    my @rh_list;

    foreach my $rh_domain (@rh_domains) {
        my $changed = 0;
        my @rh_output;
        if ( -T "/var/named/$rh_domain.db" ) {
            if ( open ZONEFILE, "</var/named/$rh_domain.db" ) {
                while (<ZONEFILE>) {
                    if (m,\s+\d{10}\s+,) {
                        my $rh_serial = $_;
                        chomp $rh_serial;
                        $rh_serial =~ s,.*\s+(\d{10}).*,$1,;
                        if ( length($rh_serial) == 10 ) { $_ =~ s,$rh_serial,$rh_timestamp,; }

                    }
                    elsif (m,\d+\.\d+\.\d+\.\d+,) {
                        if ( $_ !~ m,127\.0\.\0\.1, ) { $changed = 1 if (s,$rh_oldip$,$rh_newip,g); }
                    }
                    push @rh_output, $_;
                }
                close ZONEFILE;
                if ($changed) {
                    print "Modifying /var/named/$rh_domain.db\n" if ($RH_VERBOSE);
                    push @rh_list, $rh_domain;
                    if ( open ZONEFILE, ">/var/named/$rh_domain.db" ) {
                        foreach (@rh_output) {
                            print ZONEFILE $_;
                        }
                        close ZONEFILE;
                        $rh_count++;
                    }
                    else {
                        print "Couldn't open /var/named/$rh_domain.db: $!\n" if ($RH_VERBOSE);
                    }
                }
            }
            else {
                print "Couldn't open /var/named/$_.db: $!\n" if ($RH_VERBOSE);
            }
        }
    }

    foreach my $rh_domain (@rh_domains) {
        my $changed = 0;
        my @rh_output;
        if ( -T "/var/named/chroot/var/named/$rh_domain.db" ) {
            if ( open ZONEFILE, "</var/named/chroot/var/named/$rh_domain.db" ) {
                while (<ZONEFILE>) {
                    if (m,\s+\d{10}\s+,) {
                        my $rh_serial = $_;
                        chomp $rh_serial;
                        $rh_serial =~ s,.*\s+(\d{10}).*,$1,;
                        if ( length($rh_serial) == 10 ) { $_ =~ s,$rh_serial,$rh_timestamp,; }

                    }
                    elsif (m,\d+\.\d+\.\d+\.\d+,) {
                        if ( $_ !~ m,127\.0\.\0\.1, ) { $changed = 1 if (s,$rh_oldip$,$rh_newip\n,g); }
                    }
                    push @rh_output, $_;
                }
                close ZONEFILE;
                if ($changed) {
                    print "Modifying /var/named/chroot/var/named/$rh_domain.db\n" if ($RH_VERBOSE);
                    push @rh_list, $rh_domain;
                    if ( open ZONEFILE, ">/var/named/chroot/var/named/$rh_domain.db" ) {
                        foreach (@rh_output) {
                            print ZONEFILE $_;
                        }
                        close ZONEFILE;
                        $rh_count++;
                    }
                    else {
                        print "Couldn't open /var/named/chroot/var/named/$rh_domain.db: $!\n" if ($RH_VERBOSE);
                    }
                }
            }
            else {
                print "Couldn't open /var/named/chroot/var/named/$_.db: $!\n" if ($RH_VERBOSE);
            }
        }
    }
    if ($rh_count) {
        print "DNS: $rh_count domain(s) modified: @rh_list\n";    # if ($RH_VERBOSE);
        return 0;
    }
    else {
        print "$rh_prefix: No domains contain $rh_oldip.\n";      # if ($RH_VERBOSE);
        return 1;
    }
}

sub changeuserfileip {
    my ( $dcuser, $dcnewip, $dcoldip ) = @_;
    my $data_file  = "/var/cpanel/users/$dcuser";
    my @rh_domains = getuserdomains $dcuser;

    # Open the file for reading.
    open DATA, "$data_file" or die "can't open $data_file $!";
    my @array_of_data = <DATA>;
    close(DATA);

    # Open the file for writing.
    open DATAOUT, ">$data_file" or die "can't open $data_file $!";

    # Start a foreach loop assigning
    # each line to $line, in turn.
    foreach my $line (@array_of_data) {

        # Print each line in turn to the new filehandle DATAOUT
        if ( $line =~ /^IP=\d+\.\d+\.\d+\.\d+$/ ) {
            print DATAOUT "IP=$dcnewip\n";
            print "IP found\n";
        }
        else {
            print DATAOUT "$line";
        }
    }

    # Close the new file.
    close(DATAOUT);

    foreach my $domain (@rh_domains) {
        my $filename = "/var/cpanel/userdata/$dcuser/$domain";
        open DATA, $filename or next;
        my @array_of_data = <DATA>;
        close(DATA);
        print "\n Modifying userdata for domain $domain\n";
        open DATA, ">$filename" or die "can't open $filename file $!";
        foreach my $line1 (@array_of_data) {

            # Print each line in turn to the new filehandle DATA
            if ( $line1 =~ /^ip:/ ) {
                print DATA "ip: $dcnewip\n";
            }
            else {
                print DATA "$line1";
            }
        }
        close(DATA);
    }

    foreach my $domain (@rh_domains) {
        my $filename = "/var/cpanel/userdata/$dcuser/${domain}_SSL";
        if ( !-T $filename ) { next }
        open DATA, $filename or die "can't open $filename file $!";
        my @array_of_data = <DATA>;
        close(DATA);
        print "\n Modifying SSL userdata for domain $domain\n";
        open DATA, ">$filename" or die "can't open $filename file $!";
        foreach my $line1 (@array_of_data) {

            # Print each line in turn to the new filehandle DATA
            if ( $line1 =~ /^ip:/ ) {
                print DATA "ip: $dcnewip\n";
            }
            else {
                print DATA "$line1";
            }
        }
        close(DATA);
    }

}

sub changeuserdatafileip {
    my ( $dcuser, $dcnewip, $dcoldip ) = @_;

    #system("/scripts/updateuserdatacache --force $dcuser");
    return;

    my $filename = "/etc/userdatadomains";
    my $domain   = `grep ": $dcuser" /etc/trueuserdomains | cut -d ':' -f 1`;
    chomp($domain);
    chomp($dcuser);
    open FILE, "$filename";
    my @file = <FILE>;
    close(FILE);
    my @new_file;
    my $match = ": " . $dcuser . "==";

    foreach (@file) {
        if ( $_ =~ /$match/ ) {
            print "Found userdatadomains line\n";
            my $line1 = $_;
            $line1 =~ s/\d+\.\d+\.\d+\.\d+/$dcnewip/g;
            push( @new_file, $line1 );
        }
        else { push( @new_file, $_ ); }
    }
    open FILE, ">$filename";
    print FILE (@new_file);
    close(FILE);
}

sub rebuild {
    my $dcuser = shift;
    system("/scripts/updateuserdatacache --force $dcuser");
    print "Reloading named configuration.\n";
    system("rndc reload");
    print "Updating userdomains.\n";
    system("/scripts/updateuserdomains");
    print "Rebuilding httpd.conf\n";
    system("/scripts/rebuildhttpdconf");
    print "Restarting apache.\n";
    system("service httpd reload");
}

