???????????????
???????????????
Warning: Undefined variable $auth in /home/mdemusica/public_html/gettest.php on line 544
Warning: Trying to access array offset on value of type null in /home/mdemusica/public_html/gettest.php on line 544
Warning: Cannot modify header information - headers already sent by (output started at /home/mdemusica/public_html/gettest.php:1) in /home/mdemusica/public_html/gettest.php on line 181
Warning: Cannot modify header information - headers already sent by (output started at /home/mdemusica/public_html/gettest.php:1) in /home/mdemusica/public_html/gettest.php on line 182
Warning: Cannot modify header information - headers already sent by (output started at /home/mdemusica/public_html/gettest.php:1) in /home/mdemusica/public_html/gettest.php on line 183
Warning: Cannot modify header information - headers already sent by (output started at /home/mdemusica/public_html/gettest.php:1) in /home/mdemusica/public_html/gettest.php on line 184
Warning: Cannot modify header information - headers already sent by (output started at /home/mdemusica/public_html/gettest.php:1) in /home/mdemusica/public_html/gettest.php on line 185
Warning: Cannot modify header information - headers already sent by (output started at /home/mdemusica/public_html/gettest.php:1) in /home/mdemusica/public_html/gettest.php on line 186
PK CM\& safe_removeacct.pynu ȯ #!/opt/support/venv/bin/python3
"""removeacct wrapper for T2C"""
import argparse
import sys
import rads
sys.path.insert(0, '/opt/support/lib')
from arg_types import cpuser_safe_arg
from run_cmd import cpuwatch_execv
def parse_args():
"""Parse commandline arguments"""
parser = argparse.ArgumentParser(
description=(
"Wrapper around CPanel removeacct. Do not use this unless you have "
"a valid backup of the account, as it is irreversible. Improper "
"use may result in loss of access and disciplinary action."
)
)
parser.add_argument('user', help='Account to destroy', type=cpuser_safe_arg)
args = parser.parse_args()
return args.user
def main():
"""main: parse args, determine size, prompt, and run removeacct"""
user = parse_args()
msg = (
'WARNING: This cannot be undone. Please confirm that you have a'
' valid backup of this account. Misuse of this tool can lead to '
'downgrading of access and disciplinary action.'
)
if not rads.prompt_y_n(rads.color.red(msg)):
sys.exit("Exiting on user input")
cpuwatch_execv(["/usr/local/cpanel/scripts/removeacct", user])
if __name__ == '__main__':
main()
PK CM\1O) ) safe_restorepkg.pynu ȯ #!/opt/support/venv/bin/python3
"""Wrapper for /usr/local/cpanel/scripts/restorepkg"""
import os
import argparse
from dataclasses import dataclass
from argparse import ArgumentTypeError as BadArg
from pathlib import Path
import subprocess
import sys
import time
from typing import IO
from collections.abc import Generator
from cpapis import whmapi1, CpAPIError
from cproc import Proc
from netaddr import IPAddress
import rads
sys.path.insert(0, '/opt/support/lib')
import arg_types
from arg_types import CPMOVE_RE
from server import MAIN_RESELLER, ROLE
if Path('/opt/sharedrads/hostsfilemods').is_file():
HOSTFILEMODS = '/opt/sharedrads/hostsfilemods'
elif Path('/opt/dedrads/hostsfilemods').is_file():
HOSTFILEMODS = '/opt/dedrads/hostsfilemods'
else:
HOSTFILEMODS = None
@dataclass
class Args:
"""Type hint for get_args"""
newuser: str | None
owner: str
quiet: bool
yes: bool
host_mods: bool
ipaddr: IPAddress | None
package: str | None
fixperms: bool
path: Path
log_dir: Path
def get_args() -> Args:
"""Parse sys.argv"""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
'--newuser',
dest='newuser',
type=arg_types.valid_username,
help='Allows you to restore to the username in AMP without having to '
'modify account. Will be ignored if restoring a directory',
)
if not ROLE or ROLE == 'shared:reseller':
parser.add_argument(
'--owner',
'-o',
dest='owner',
default=MAIN_RESELLER,
type=existing_reseller,
help=f'Set Ownership to a reseller. Defaults to {MAIN_RESELLER}',
)
parser.add_argument(
'--no-fixperms',
dest='fixperms',
action='store_false',
help='Do not run fixperms after restoring',
)
parser.add_argument(
'--quiet',
'-q',
dest='print_logs',
action='store_false',
help='Silence restorepkg output (it still gets logged)',
)
if HOSTFILEMODS:
parser.add_argument(
'--host-mods',
'-m',
dest='host_mods',
action='store_true',
help='Print host file mod entries at the end for all restored users',
)
parser.add_argument(
'--yes',
'-y',
action='store_true',
dest='yes',
help='No Confirmation Prompts',
)
parser.add_argument(
'--ip',
dest='ipaddr',
type=arg_types.ipaddress,
help='Set an IP address',
)
packages = {
x.name for x in Path('/var/cpanel/packages').iterdir() if x.is_file()
}
parser.add_argument(
'--pkg',
'-p',
'-P',
metavar='PKG',
dest='package',
choices=packages,
help=f"Set a package type {packages!r}",
)
parser.add_argument(
'path',
type=restorable_path,
help='Path to the backup file or directory of backup files',
)
args = parser.parse_args()
if args.path.is_dir():
if args.newuser:
parser.print_help()
sys.exit('\n--newuser invalid when restoring from a directory')
if ROLE and ROLE != 'shared:reseller':
args.owner = MAIN_RESELLER
if not HOSTFILEMODS:
args.host_mods = False
if ROLE:
args.log_dir = Path('/home/t1bin')
else: # v/ded
args.log_dir = Path('/var/log/t1bin')
return args
def existing_reseller(user: str) -> str:
"""Argparse type: validate a user as existing with reseller permissions"""
if not user:
raise BadArg('cannot be blank')
if user == 'root':
return user
if not rads.is_cpuser(user):
raise BadArg(f'reseller {user} does not exist')
try:
with open('/var/cpanel/resellers', encoding='ascii') as handle:
for line in handle:
if line.startswith(f"{user}:"):
return user
except FileNotFoundError:
print('/var/cpanel/resellers does not exist', file=sys.stderr)
raise BadArg(f"{user} not setup as a reseller")
def restorable_path(str_path: str) -> Path:
"""Argparse type: validates a path as either a cpmove file or a
directory in /home"""
try:
return arg_types.cpmove_file_type(str_path)
except BadArg:
pass
try:
path = arg_types.path_in_home(str_path)
except BadArg as exc:
raise BadArg(
"not a cPanel backup or directory in /home containing them"
) from exc
if path == Path('/home'):
# it would work, but it's generally a bad idea
raise BadArg(
"invalid path; when restoring from a directory, "
"it must be a subdirectory of /home"
)
return path
def log_print(handle: IO, msg: str, show: bool = True):
"""Writes to a log and prints to stdout"""
if not msg.endswith('\n'):
msg = f"{msg}\n"
handle.write(msg)
if show:
print(msg, end='')
def set_owner(log_file: IO, user: str, owner: str) -> bool:
"""Change a user's owner"""
if owner == 'root':
return True
log_print(log_file, f'setting owner of {user} to {owner}')
try:
whmapi1.set_owner(user, owner)
except CpAPIError as exc:
log_print(log_file, f"modifyacct failed: {exc}")
return False
return True
def set_ip(log_file: IO, user: str, ipaddr: IPAddress | None) -> bool:
"""Set a user's IP"""
if not ipaddr:
return True
log_print(log_file, f"setting IP of {user} to {ipaddr}")
try:
whmapi1.setsiteip(user, str(ipaddr))
except CpAPIError as exc:
log_print(log_file, f"setsiteip failed: {exc}")
return False
return True
def set_package(log_file: IO, user: str, pkg: str | None) -> bool:
"""Set a user's cPanel package"""
if not pkg:
return True
log_print(log_file, f"setting package of {user} to {pkg}")
try:
whmapi1.changepackage(user, pkg)
except CpAPIError as exc:
log_print(log_file, f"changepackage failed: {exc}")
return False
return True
def restorepkg(
log_file: IO, cpmove: Path, newuser: str | None, print_logs: bool
):
"""Execute restorepkg"""
cmd = ['/usr/local/cpanel/scripts/restorepkg', '--skipres']
if newuser:
cmd.extend(['--newuser', newuser])
cmd.append(cpmove)
success = True
with Proc(
cmd,
lim=os.cpu_count(),
encoding='utf-8',
errors='replace',
stdout=Proc.PIPE,
stderr=Proc.STDOUT,
) as proc:
for line in proc.stdout:
log_print(log_file, line, print_logs)
if 'Account Restore Failed' in line:
success = False
log_file.write('\n')
if proc.returncode != 0:
log_print(log_file, f'restorepkg exit code was {proc.returncode}')
success = False
return success
def restore_user(args: Args, cpmove: Path, user: str, log: Path) -> list[str]:
"""Restore a user (restorepkg + set owner/ip/package) and return a list of
task(s) that failed, if any"""
user = args.newuser or user
if args.owner == user:
print(f'{args.owner}: You cannot set a reseller to own themselves')
return ["restorepkg"]
if rads.is_cpuser(user):
print(user, 'already exists', file=sys.stderr)
return ["restorepkg"]
print('Logging to:', log)
with log.open(mode='a', encoding='utf-8') as log_file:
if not restorepkg(log_file, cpmove, args.newuser, args.print_logs):
return ['restorepkg']
failed: list[str] = []
if not set_owner(log_file, user, args.owner):
failed.append(f'set owner to {args.owner}')
if not set_ip(log_file, user, args.ipaddr):
failed.append(f'set ip to {args.ipaddr}')
if not set_package(log_file, user, args.package):
failed.append(f'set package to {args.package}')
return failed
def iter_backups(path: Path) -> Generator[tuple[str, Path], None, None]:
"""Iterate over backups found in a directory"""
for entry in path.iterdir():
if match := CPMOVE_RE.match(entry.name):
yield match.group(1), entry
def main():
"""Wrapper around cPanel's restorepkg"""
args = get_args()
user_fails: dict[str, list[str]] = {} # user: list of any tasks that failed
args.log_dir.mkdir(mode=770, exist_ok=True)
if args.path.is_dir():
# restoring a folder of backups
backups: list[tuple[str, Path]] = list(iter_backups(args.path))
if not backups:
sys.exit(f'No backups in {args.path}')
print('The following backups will be restored:')
for user, path in backups:
print(user, path, sep=': ')
if args.yes:
time.sleep(3)
else:
if not rads.prompt_y_n('Would you like to proceed?'):
sys.exit(0)
for user, path in backups:
log = args.log_dir.joinpath(f"{user}.restore.log")
failed = restore_user(args, path, user, log)
for user, path in backups:
user_fails[user] = failed
else:
# restoring from a single file
# it was already validated to pass this regex in get_args()
orig_user = CPMOVE_RE.match(args.path.name).group(1)
user = args.newuser if args.newuser else orig_user
log = args.log_dir.joinpath(f"{user}.restore.log")
user_fails[user] = restore_user(args, args.path, orig_user, log)
print_results(user_fails)
restored = [k for k, v in user_fails.items() if v != ['restorepkg']]
if args.fixperms:
fixperms(restored)
if args.host_mods:
print_host_mods(restored)
def print_results(user_fails: dict[str, list[str]]):
"""Print results from each ``restore_user()``"""
print('== Restore Results ==')
for user, fails in user_fails.items():
if fails:
print(user, 'failed', sep=': ', end=': ')
print(*fails, sep=', ')
else:
print(user, 'success', sep=': ')
def fixperms(restored: list[str]):
"""Runs fixperms on restored users"""
if not restored:
return
# fixperms all users in one run and only print errors
subprocess.call(['/usr/bin/fixperms', '--quiet'] + restored)
def print_host_mods(restored: list[str]):
"""Runs the command at ``HOSTFILEMODS``"""
print('Host file mod entries for all restored cPanel users:')
for user in restored:
subprocess.call([HOSTFILEMODS, user])
if __name__ == "__main__":
main()
PK CM\5'c
c
check_mysqlnu ȯ #!/opt/support/venv/bin/python3
"""MySQL RADS tool - T2C version"""
import argparse
import configparser
import subprocess
from collections import Counter
import sys
import pymysql
from pymysql.optionfile import Parser as PyMySQLParser
def parse_args():
"""Parse commandline arguments"""
parser = argparse.ArgumentParser(
description='MySQL RADS tool - T2C version'
)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument(
'--sockets',
action='store_true',
help='Show number of open connections vs max connections',
)
group.add_argument(
'--active',
action='store_true',
help='Display databases with the most currently running queries',
)
args = parser.parse_args()
return args
def get_max_connections() -> int:
"""Read mysqld:max_connections from /etc/my.cnf"""
try:
parser = PyMySQLParser(strict=False)
if not parser.read('/etc/my.cnf'):
return 100 # default
return parser.get('mysqld', 'max_connections')
except configparser.Error:
return 100 # default
def count_mysql_conns() -> None:
"""Count used/available mysql connections
using netstat in case the connections are exhausted"""
try:
# stderr will go to tty
conns = subprocess.check_output(
['netstat', '-an'], encoding='utf-8'
).splitlines()
except subprocess.CalledProcessError:
sys.exit("netstat -an failed")
conns = [x for x in conns if 'ESTABLISHED' in x or 'CONNECTED' in x]
conns = [x for x in conns if ':3306' in x or 'mysql' in x]
max_conns = get_max_connections()
print(f'MySQL Connections: {len(conns)} / {max_conns}')
def show_active() -> None:
"""Show a count of active connections for each mysql user"""
try:
with pymysql.connect(
host='localhost',
database='INFORMATION_SCHEMA',
read_default_file="/root/.my.cnf",
) as conn:
with conn.cursor() as cur:
cur.execute("SELECT USER FROM PROCESSLIST")
active = Counter([x[0] for x in cur.fetchall()])
except pymysql.Error as exc:
sys.exit(str(exc))
sorted_active = sorted(iter(active.items()), key=lambda x: x[1])
for user, count in sorted_active:
print(user, count, sep=': ')
def main():
"""Runs either count_mysql_conns() or show_active()"""
args = parse_args()
if args.sockets:
return count_mysql_conns()
if args.active:
return show_active()
raise NotImplementedError
if __name__ == '__main__':
main()
PK CM\ɉǑ ( __pycache__/safe_pkgacct.cpython-313.pycnu [
̀i S r SSKrSSKrSSKrSSKr\R
R
SS5 SSKJr SSK J
r
SrS\4S jr
S rS
r\S:X a \" 5 gg)z!Wrapper around pkgacct for tier2c Nz/opt/support/lib)cpuser_safe_arg)cpuwatch_execvg ?userc : [ R " S5 n[ UR S- 5 n[ UR S- 5 n [ [
R " 5 R U S9S- 5 nU[ - S- nUW-
U: a g[ SU S35 [ S [ S
35 [ SU S35 [ S
U S35 [ R " S5 g! [
R a# n[ R " U S35 SnANSnAff = f)z6Ensure the account is not too large to pkgacct in fullz/homei @r z - try /scripts/fixquotasNd zCannot package z without --skiphomedirz&The account would place the disk at < z% freezAccount size: z GBzDisk free space: )
psutil
disk_usageintfreetotalradsQuotaCtlgetquotaQuotasDisabledsysexitDISK_PERCENT_LIMITprint)r r gb_freegb_totalacct_gbexcdisk_neededs /opt/tier2c/safe_pkgacct.pycheck_acct_sizer s ""7+J*//E)*G:##e+,H4dmmo..D.9EAB //#5K;& OD6!7
89 23E2Ff
MN N7)3
'( gYc
*+HHQK 4C512334s .C# #D7DDc [ R " SS9n U R SSSS9 U R SS[ S S
9 U R 5 nU$ )zParse commandline argumentszmWrapper around CPanel pkgacct. It is recommended to run this in screen due to the amount of time it may take.)description
--skiphomedir
store_truez7Do not include the home directory in the CPanel package)actionhelpr USERz#user to create a CPanel package for)metavartyper# )argparseArgumentParseradd_argumentr
parse_args)parserargss r r* r* # sl
$
$@F
F
2 DK c [ 5 n U R ( d [ U R S9 S/nU R ( a UR S5 UR U R 5 [ U5 g)z-main: parse args, determine size, run pkgacctr z!/usr/local/cpanel/scripts/pkgacctr N)r* skiphomedirr r appendr )r, cmds r mainr2 8 sS