/
opt
/
dedrads
/
/opt/dedrads
mkdir
upload
Name
Size
Mode
Actions
account_review/
-
0555
rm
check_software_mods/
-
0555
rm
cms_tools/
-
0555
rm
etc/
-
0555
rm
extras/
-
0555
rm
mailparse/
-
0555
rm
mysql/
-
0555
rm
nlp_scripts/
-
0555
rm
oldrads/
-
0555
rm
perl/
-
0555
rm
provision/
-
0555
rm
python/
-
0555
rm
suspended/
-
0555
rm
__pycache__/
-
0555
rm
account-review
799
0555
edit
dl
rm
allfw
6259
0555
edit
dl
rm
alp.py
16553
0555
edit
dl
rm
autossl_sync
6267
0555
edit
dl
rm
check_apache
9205
0555
edit
dl
rm
check_bandwidth
4546
0555
edit
dl
rm
check_boxtrapper
1684
0555
edit
dl
rm
check_cpu
12212
0555
edit
dl
rm
check_crons
1827
0555
edit
dl
rm
check_dcpumon
1973
0555
edit
dl
rm
check_dns
1827
0555
edit
dl
rm
check_domlogs
61
0555
edit
dl
rm
check_exim
3731
0555
edit
dl
rm
check_hacks
22604
0555
edit
dl
rm
check_imap
5249
0555
edit
dl
rm
check_io
6635
0555
edit
dl
rm
check_max_children
16341
0555
edit
dl
rm
check_mem
1660
0555
edit
dl
rm
check_misc
1510
0555
edit
dl
rm
check_pacct
5201
0555
edit
dl
rm
check_php
4344
0555
edit
dl
rm
check_pop3
2295
0555
edit
dl
rm
check_prov.py
4714
0555
edit
dl
rm
check_server
696
0555
edit
dl
rm
check_size
490
0555
edit
dl
rm
check_software
9849
0555
edit
dl
rm
check_spamd
2426
0555
edit
dl
rm
check_traffic
1933
0555
edit
dl
rm
check_user
1887
0555
edit
dl
rm
clean_exim.py
6390
0555
edit
dl
rm
clusterfix
5343
0555
edit
dl
rm
cmspass.py
3970
0555
edit
dl
rm
cms_check.py
9825
0555
edit
dl
rm
cms_counter.py
36734
0555
edit
dl
rm
cms_creds
713
0555
edit
dl
rm
cms_dumpdb
4485
0555
edit
dl
rm
cms_pw
1416
0555
edit
dl
rm
cpanel-api
7040
0555
edit
dl
rm
cpanel_postgres_manager.py
29004
0555
edit
dl
rm
cpmerge
4631
0555
edit
dl
rm
cpumon
2195
0555
edit
dl
rm
dcpumon.pl
1239
0555
edit
dl
rm
dedcheck
18127
0555
edit
dl
rm
dns-sync
14386
0555
edit
dl
rm
docroot.py
4425
0555
edit
dl
rm
du-tree
7450
0555
edit
dl
rm
envinfo.py
6633
0555
edit
dl
rm
exclude_rbl.py
5249
0555
edit
dl
rm
extract-vhost
2691
0555
edit
dl
rm
filescan
3566
0555
edit
dl
rm
find_warez
1460
0555
edit
dl
rm
first_setup.py
19120
0555
edit
dl
rm
fixwpcron.py
4822
0555
edit
dl
rm
fix_dns_cluster
353
0555
edit
dl
rm
goaccess
1217720
0555
edit
dl
rm
hostsfilemods
4467
0555
edit
dl
rm
imap_io
2323
0555
edit
dl
rm
innodb_converter.py
9343
0555
edit
dl
rm
killall911
530
0555
edit
dl
rm
killdns
941
0555
edit
dl
rm
lastcommcache.sh
1374
0555
edit
dl
rm
legal_lock_down.sh
7450
0555
edit
dl
rm
lil-cpanel
52002
0555
edit
dl
rm
listacct
4575
0555
edit
dl
rm
mailscan
4544
0555
edit
dl
rm
mail_sources.py
7407
0555
edit
dl
rm
megaclisas-status
38664
0555
edit
dl
rm
migrate2central.sh
14418
0555
edit
dl
rm
modify-account
40631
0555
edit
dl
rm
modsec_disable.py
11461
0555
edit
dl
rm
monarxctl
8912
0555
edit
dl
rm
msp.pl
27714
0555
edit
dl
rm
mysql_dstat
474
0555
edit
dl
rm
mysql_selector.py
73102
0555
edit
dl
rm
nlp
4582
0555
edit
dl
rm
procscrape
1863
0555
edit
dl
rm
quarantine
11083
0555
edit
dl
rm
radsfunctions.sh
863
0555
edit
dl
rm
recent-cp
16148
0555
edit
dl
rm
remote_dump
18347
0555
edit
dl
rm
reset_cpanel
3205
0555
edit
dl
rm
server-load
2192
0555
edit
dl
rm
show-conns
20105
0555
edit
dl
rm
show-conns-adv.py
54667
0555
edit
dl
rm
sparta.py
382498
0555
edit
dl
rm
sqltop
27129
0555
edit
dl
rm
telcheck
2411
0555
edit
dl
rm
temprootreset
186
0555
edit
dl
rm
unsuspend_user
1307
0555
edit
dl
rm
unsusprunner.sh
1840
0555
edit
dl
rm
updatednsadmin
526
0555
edit
dl
rm
update_spf
14972
0555
edit
dl
rm
upgrade-check
9216
0555
edit
dl
rm
vhost_data.py
6221
0555
edit
dl
rm
wp-xray.sh
85816
0555
edit
dl
rm
Edit:
/opt/dedrads/remote_dump
(18347B)
#!/usr/lib/rads/venv/bin/python3 __author__ = 'chases' import os import shlex import socket import argparse import sys import base64 import subprocess import threading from typing import IO from time import sleep from urllib.parse import urlencode import requests from requests.adapters import TimeoutSauce from prettytable import PrettyTable from rads import prompt_y_n, is_cpuser, SECURE_USER, SYS_USERS, get_owner from rads.color import red, yellow, green from cpapis import whmapi1, CpAPIError def check_user(username): """Checks whether the user is valid for switching. Taken from /opt/tier1adv/bin/switch""" restricted_users = SYS_USERS sec_user = SECURE_USER if sec_user is not None: # will be None on VPS/Ded restricted_users.append(sec_user) if username in restricted_users: print(red(f"You may not remove {username}.")) return False if not is_cpuser(username): print(f"The user {username} is not a cpanel user.") return False return True def input_parse(): parser = argparse.ArgumentParser() # fmt: off parser.add_argument( '-u', '--user', action='store', dest='user', help='Define your remote cpanel user or reseller', ) parser.add_argument( '-d', '--domain', action='store', dest='domain', default=False, help='set domain if cannot be pulled from listaccount (no reseller)', ) parser.add_argument( '-p', '--pass', action='store', dest='res_pass', default=None, help='Set the password for the remote reseller or cpuser. Not ' 'recommended to pass as an argument, but an option nonetheless.', ) parser.add_argument( '--replace', action='store', dest='replace', default=False, help='Replace a cpanel user with the backup restored.', ) parser.add_argument( '-r', '--host', action='store', dest='remote_host', default=None, help='Remote Hostname.', ) parser.add_argument( '-n', '--nosize', action='store_true', default=False, dest='nosize', help='Ignore size limitations', ) parser.add_argument( '--norestore', action='store_true', default=False, dest='norestore', help='Will not restore the package', ) parser.add_argument( '--skip', action='store', default=False, nargs='+', dest='skip', help='Skip specific accounts. Useful with --all', ) parser.add_argument( '-i', '--ip', action='store', dest='IP', default=False, help='Set the IP address on Restore.', ) parser.add_argument( '-o', '--owner', action='store', dest='owner', default=False, help='Set the Owner on restore', ) parser.add_argument( '-P', '--package', action='store', dest='package', default=False, help='Set the package on restore', ) parser.add_argument( '--all', action='store_true', default=False, dest='all', help='Dump all backups for accounts within size specification', ) parser.add_argument('--version', action='version', version='%(prog)s 2.0') # fmt: on raw = parser.parse_known_args() parsed = raw[0] try: if not parsed.user: parsed.user = input( "Enter the reseller user from the remote host: " ) if not parsed.res_pass: parsed.res_pass = input( "Enter the reseller password for the remote host: " ) if not parsed.remote_host: parsed.remote_host = input("Enter remote hostname or IP address: ") if parsed.replace: if os.path.isfile(f'/var/cpanel/users/{parsed.replace}'): choice = prompt_y_n( f'Are you sure you would like to replace {parsed.replace} ' f'which is owned by: {get_owner(parsed.replace)}' ) if not choice: parsed.replace = False else: parsed.replace = False except KeyboardInterrupt: sys.exit('\nQuitting') return parsed class MyTimeout(TimeoutSauce): def __init__(self, *_args, **kwargs): connect = kwargs.get('connect', 5) read = kwargs.get('read', connect) super().__init__(connect=connect, read=read) def validate_whm_connection(parsed): print( 'Trying to make a socket connection to WHM. If you know this will ', 'not work you can Ctrl ^C to move on', ) sock = socket.socket() address = parsed.remote_host port = 2086 # port number is a number, not string try: sock.connect((address, port)) except KeyboardInterrupt: print('Moving on') return False except Exception as exc: print(exc, file=sys.stderr) print(red(f"Unable to connect to {address} on port {port}.")) return False return True def remote_whm_post(parsed, jsoncall, url_args, **kwargs): user = kwargs.get('user', parsed.user) port = kwargs.get('port', '2087') remote_host = parsed.remote_host if url_args: jsoncall += '?' + urlencode(url_args) url = 'https://' + remote_host + ':' + port + '/' + jsoncall passholder = parsed.res_pass encoded_pass = base64.b64encode(user + ':' + passholder) auth = "Basic " + encoded_pass header = {'Authorization': auth} requests.adapters.TimeoutSauce = MyTimeout try: response = requests.post(url, headers=header, verify=False, timeout=5) except requests.exceptions.ConnectTimeout: return False try: response = response.json() except ValueError: print('Unable to get valid response from', remote_host) print('Response received from ', remote_host, ':', response) return False return response def _write_stdin(stdin: IO, data: str): stdin.write(data) stdin.close() def get_cpanel_backup( parsed, restoreuser=False, restoredomain=False, attempt=0 ): if restoreuser: parsed.user = restoreuser if restoredomain: parsed.domain = restoredomain restorelog = f'/tmp/parsed.{parsed.user}.backuplog' print( "Backup will start in the background. You can monitor it by tail -f", restorelog, ) cmd = [ '/scripts/getremotecpmove', parsed.remote_host, parsed.user, parsed.domain, ] with open(restorelog, 'w', encoding='utf-8') as writelog: with subprocess.Popen( cmd, encoding='utf-8', stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, ) as proc: # write to stdin in a thread so this won't deadlock if the proc # writes > 1024 bytes to stdout/err before consuming stdin thread = threading.Thread( target=_write_stdin, args=(proc.stdin, parsed.res_pass), daemon=True, ) for line in proc.stdout: print(line.strip(), flush=True) writelog.write(line) thread.join() if proc.wait(): # non-zero exit code print(red('Failed to get backup from remote host.')) if attempt < 2: print( red('Waiting 10 minutes and attempting again.'), red('Press ctrl ^c to Manually Fail this user.'), flush=True, ) try: sleep(600) except KeyboardInterrupt: # This user Failed, but continuing on return False attempt += 1 get_cpanel_backup(parsed, attempt=attempt) else: print(red('Too many attempts failed. Moving on to next user.')) return False with open(restorelog, encoding='utf-8') as resultfile: for line in resultfile: if line.startswith('pkgacctfile is'): print('Backup Found: {}'.format(line.split(' ')[2].strip())) return line.split(' ')[2].strip() if 'Failed to fetch cpmove file via cPanel XML-API' in line: return False return False def set_backup_to_standard_naming(backup, user): if os.path.isfile(backup): os.rename(backup, f'/home/cpmove-{user}.tar.gz') return f'/home/cpmove-{user}.tar.gz' return False def restore_backup(backup, user, parsed): # TODO: this script is python. restorepkg is python. Import and inspect the # result directly rather than executing and reading its output str. # Do this after merging the rpms. cmd = ['/opt/tier2c/safe_restorepkg.py'] if parsed.IP: cmd.extend(['--ip', parsed.IP.strip()]) cmd.extend('--quiet', backup) status = 'Success' with subprocess.Popen( cmd, encoding='utf-8', stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) as proc: for line in proc.stdout: print(line.strip()) if 'Failed' in line: status = 'Failed' if line.startswith("{'%s'" % user): try: status = line.split("'")[3] except KeyError: pass if proc.wait(): status = 'Non-Zero Exit' if status == 'Success' and parsed.owner: try: whmapi1.set_owner(user, parsed.owner) except CpAPIError as exc: status = str(exc) return status def main(): parsed = input_parse() if parsed.domain or parsed.replace or not validate_whm_connection(parsed): if not parsed.domain: print('Additional Information Required') parsed.domain = input( "Enter the primary domain for the cPanel you are transferring: " ) print('Running:') cmd = [ '/scripts/getremotecpmove', parsed.remote_host, parsed.user, parsed.domain, ] print('echo', shlex.quote(parsed.res_pass), '|', shlex.join(cmd)) backup = get_cpanel_backup(parsed) if backup: backup = set_backup_to_standard_naming(backup, parsed.user) if ( parsed.replace and check_user(parsed.replace) and backup is not False ): print( yellow(f'Removing Account {parsed.replace} so it can '), yellow('be restored from the backup'), ) subprocess.check_call( ['/scripts/removeacct', '--force', parsed.user] ) if not parsed.norestore: restore_backup(backup, parsed.user, parsed) else: parsed.userinfo = remote_whm_post( parsed, 'json-api/listaccts', { 'api.version': 1, 'want': 'user,disklimit,diskused,domain,suspended', }, ) # Check to see if the WHM connection failed and if so switch # to single transfer mode if parsed.userinfo: try: print(parsed.userinfo['cpanelresult']['data']['reason']) # Check for a read-only filesystem, and exit if found if "Read-only" in parsed.userinfo['metadata']['reason']: sys.exit('Read-only file system found') if prompt_y_n( 'Connection to remote WHM Failed. Would you like to try ' 'connecting via cPanel? Select Yes if not a reseller.' ): if not parsed.domain: print('Additional Information Required') parsed.domain = input( "Enter the primary domain for the cPanel " "you are transferring: " ) backup = get_cpanel_backup(parsed) if backup: backup = set_backup_to_standard_naming( backup, parsed.user ) if not parsed.norestore: restore_backup(backup, parsed.user, parsed) except Exception as exc: print(exc, file=sys.stderr) # This handles the case of remote_whm_post returning False, and was # otherwise not a caught exception prior else: sys.exit( 'There was an issue connecting to the remote host. Exiting.' ) userdata = {} pickerlist = [] toobig = [] try: for userinfo in parsed.userinfo['data']['acct']: userdata[userinfo['user']] = {} userdata[userinfo['user']]['domain'] = userinfo['domain'] userdata[userinfo['user']]['diskused'] = userinfo['diskused'] userdata[userinfo['user']]['disklimit'] = userinfo['disklimit'] userdata[userinfo['user']]['disklimit'] = userinfo['suspended'] if ( str(userinfo['diskused'].split('M')).lower() == 'none' or parsed.nosize or int(userinfo['diskused'].split('M')[0]) <= 6000 ): pickerlist.append( '{} - {} - {}'.format( userinfo['user'], userinfo['domain'], userinfo['diskused'], )[:50] ) if ( not parsed.nosize and int(userinfo['diskused'].split('M')[0]) >= 6000 ): toobig.append(userinfo['user']) if userinfo['suspended'] == 1: try: print( red(f'Unable to transfer {userinfo["user"]}'), red('because it is suspended.'), ) pickerlist.remove( '{} - {} - {}'.format( userinfo['user'], userinfo['domain'], userinfo['diskused'], )[:50] ) except Exception: pass except KeyError: print(userdata) sys.exit('Unable to gather required information') if toobig: print( 'The Following Accounts are too big to move by default.', 'You can use --nosize if you need to transfer them', ) print(*toobig) if not prompt_y_n('Would you like to continue?'): sys.exit('Try again with --nosize to ignore 6GB limit') if parsed.all: opts = [i.split(' ')[0] for i in pickerlist] else: useroptions = [i.split(' ')[0] for i in opts] print("Select users to transfer") print(opts.join("\n")) print("send q to finish") opts = [] while True: user_input = input().lower() if user_input in useroptions and user_input not in opts: opts.append(user_input) elif user_input == "q": break split = user_input.split(" ") if len(split) > 1: for name in split: if name in useroptions and name not in opts: opts.append(name) os.system('clear') print(opts) sys.stdout.flush() status = {} for user in opts: status[user] = 'Pending' for user in opts: print_status_info(status) try: if ( userdata[user]['disklimit'].lower() != 'unlimited' and str(userdata[user]['diskused'].split('M')).lower() != 'none' ): if ( int(userdata[user]['diskused'].split('M')[0]) * 2 ) < userdata[user]['disklimit'].split('M')[0]: print( red(f'Warning: User {user}: Does not have double'), red('the quota of the disk space used which can '), red('cause problems'), ) print( green('Setting Quota to unlimited to ensure no '), green(f'problem with backup on {user}'), ) newquota = remote_whm_post( parsed, 'json-api/modifyacct', {'api.version': 1, 'user': user, 'QUOTA': 0}, ) if newquota['metadata']['result'] == 1: print(green('Result: Success')) except Exception as exc: print(exc) print(red(f'Failed to set new Quota on {user}')) backup = get_cpanel_backup( parsed, restoreuser=user, restoredomain=userdata[user]['domain'] ) if backup and not parsed.norestore: backup = set_backup_to_standard_naming(backup, user) status[user] = restore_backup(backup, user, parsed) elif parsed.norestore: status[user] = 'Restore Skipped' else: status[user] = 'Failed' print_status_info(status) print('Done') def print_status_info(status): tbl = PrettyTable() tbl.field_names = ["User", "Status", "Conflict Info"] for user, itemstatus in status.items(): if '-' in status: conflict = status.split('-')[1:] itemstatus = status.split('-')[0] else: conflict = None tbl.add_row([user, itemstatus, conflict]) print(tbl) if __name__ == "__main__": main()
Save
cmd:
run