File manager - Edit - /usr/local/cpanel/lib/python3/cPanel.py
Back
#!/usr/bin/python3 # Copyright 2024 WebPros International, LLC # All rights reserved. # copyright@cpanel.net http://cpanel.net # This code is subject to the cPanel license. Unauthorized copying is prohibited. import os import pwd try: import json except ImportError: import simplejson as json import copy import codecs import logging import pickle import pprint import tempfile import sys # isort:skip import paths # isort:skip # Import this /after/ paths so that the sys.path is properly hacked # Add it after `/usr/local/cpanel/lib/python3` which is in position 0 sys.path.insert(1, '/usr/local/cpanel/3rdparty/mailman') from Mailman.i18n import _ # isort:skip import Mailman.Bouncer # isort:skip import Mailman.MailList # isort:skip from Mailman.MailList import MailList # isort:skip from Mailman import mm_cfg # isort:skip def drop_privileges_to(username): pw = pwd.getpwnam(username) (uid, gid) = (pw[2], pw[3]) drop_privileges_to_uid_gid(uid, gid) def drop_privileges_to_uid_gid(uid, gid): try: os.setgroups([gid]) except: pass os.setgid(gid) os.setegid(gid) os.setuid(uid) os.seteuid(uid) def update_mailman(list, func): drop_privileges_to('mailman') mlist = MailList(list, lock=0) dict_copy = copy.copy(mlist.__dict__) # Only the owner is deep copied because # deepcopy was causing a loop of # Exception RuntimeError: 'maximum recursion depth exceeded while calling a Python object' dict_copy['owner'] = copy.deepcopy(mlist.__dict__['owner']) func(dict_copy) if dict_copy != mlist.__dict__: mlist.Lock() func(mlist.__dict__) try: mlist.Save() finally: mlist.Unlock() def export_cpanel_pickle_keys_as_json(filenames, sysuser, max_pickle_file_size): cpanelkeys = { 'advertised': 1, 'archive_private': 1, 'private_roster': 1, 'subscribe_policy': 1, 'owner': 1, } all_config_files = filenames.split(',') results = '' for filename in all_config_files: try: results += export_pickle_as_json(filename, sysuser, max_pickle_file_size, cpanelkeys) + '\n' except Exception as e: results += '\n' logging.exception('Failed to load ' + filename + ' and output JSON') results = results.rstrip('\n') return results def export_pickle_as_json( filename, sysuser, max_pickle_file_size, wantkeys={}, ): fh = open(filename, 'rb') fhstat = os.fstat(fh.fileno()) if fhstat.st_size > max_pickle_file_size: raise Exception('export_pickle_as_json attempted to load a file larger than %d' % max_pickle_file_size) tmpdir = tempfile.mkdtemp('', '') (pipein, pipeout) = os.pipe() newpid = os.fork() if newpid == 0: os.close(pipein) bytes_encoding = export_pickle_as_json_child(tmpdir, fh, sysuser, wantkeys).encode(encoding="utf-8") os.write(pipeout, bytes_encoding) os.close(pipeout) os._exit(0) else: fh.close() os.close(pipeout) json = bytearray(b'') while True: buff = os.read(pipein, 32768) json += buff if not len(buff): break os.close(pipein) os.waitpid(newpid, 0) os.rmdir(tmpdir) if len(json) == 0: raise Exception('export_pickle_as_json_child failed to produce JSON output') json_text = json.decode() return json_text class MailmanImportsOnlyUnpickler(pickle.Unpickler): def __init__(self, fh): super().__init__(fh, fix_imports=True, encoding='latin1') # https://docs.python.org/3/library/pickle.html#pickle-restrict def find_class(self, mod_name, kls_name): if mod_name == 'Mailman.UserDesc': mod_obj = __import__(mod_name, {}, {}, ['Mailman']) return getattr(mod_obj, kls_name) elif mod_name == 'Mailman.Bouncer': mod_obj = __import__(mod_name, {}, {}, ['Mailman']) return getattr(mod_obj, kls_name) elif mod_name == 'copy_reg': mod_obj = __import__('copyreg') return getattr(mod_obj, kls_name) elif mod_name == '_codecs': mod_obj = __import__('_codecs') return getattr(mod_obj, kls_name) elif mod_name == '__builtin__': mod_obj = __import__('builtins') return getattr(mod_obj, kls_name) else: raise pickle.UnpicklingError("Cannot import unsupported module.class '%s.%s'" % (mod_name, kls_name)) def export_pickle_as_json_child( tmpdir, fh, sysuser, wantkeys, ): # **STOP!** Before we drop into a chroot, we need to ensure that the latin1 # encoding is loaded. If we do not, then dump_cpanel_mailmancfg_as_json may # fail, because the encoding is (obviously in hindsight) not available to # be loaded from disk while in the jail. codecs.lookup('latin1') pw = pwd.getpwnam(sysuser) (uid, gid) = (pw[2], pw[3]) os.chroot(tmpdir) drop_privileges_to_uid_gid(uid, gid) unpickler = MailmanImportsOnlyUnpickler(fh) dict = {} dict = unpickler.load() # Reset the Bouncer object if 'bounce_info' in dict: dict['bounce_info'] = {} if 'evictions' in dict: evictions = dict['evictions'] for cookie in list(evictions.keys()): del dict[cookie] del evictions[cookie] # If they only want specific keys # create a new dictionary with just # the keys we need. # # Currently only used by # dump_cpanel_mailmancfg_as_json to just # export the keys in def export_cpanel_pickle_keys_as_json if wantkeys.items(): limited_dict = {} for (k, v) in wantkeys.items(): limited_dict[k] = dict[k] dict = limited_dict dict = convert_tuples(dict) fh.close() try: return json.dumps(dict, ensure_ascii=False) except: print('Failed to export to json') pp = pprint.PrettyPrinter(indent=4) pp.pprint(dict) raise def json_to_pickle(jsonstr): dict = json.loads(jsonstr, object_hook=json_convert_stringified_int_keys_to_ints) dict = restore_tuples(dict) # We're using protocol 4, which is the highest supported by Python3.6 # https://docs.python.org/3/library/pickle.html#data-stream-format # (Alma 8) return pickle.dumps(dict, 4) def is_int(input): try: num = int(input) except ValueError: return False return True def json_convert_stringified_int_keys_to_ints(the_dict): if isinstance(the_dict, dict): return dict([((int(key) if is_int(key) else key), value) for (key, value) in the_dict.items()]) return the_dict def restore_tuples(value): if isinstance(value, dict): try: if len(value['__items__']) == value['__tuple__'] and len(value.keys()) == 2: return restore_tuples(tuple(value['__items__'])) except: pass try: if value['__bytestring__'] is True and len(value.keys()) == 2: return value['__string__'].encode('iso-8859-1') except: pass return dict([(restore_tuples(k), restore_tuples(v)) for (k, v) in value.items()]) elif isinstance(value, list): return [restore_tuples(element) for element in value] elif isinstance(value, tuple): return tuple([restore_tuples(element) for element in value]) else: return value def convert_tuples(value): if isinstance(value, dict): return dict([(convert_tuples(k), convert_tuples(v)) for (k, v) in value.items()]) elif isinstance(value, list): return [convert_tuples(element) for element in value] elif isinstance(value, tuple): value = [convert_tuples(element) for element in value] return {'__tuple__': len(value), '__items__': value} else: return value def get_mailman_pickle(list): return '/usr/local/cpanel/3rdparty/mailman/lists/%s/config.pck' % list def mailman_url_for_domain(domain): if hasattr(mm_cfg, 'DEFAULT_URL_PATTERN') and len(mm_cfg.DEFAULT_URL_PATTERN) > 0: return mm_cfg.DEFAULT_URL_PATTERN % domain else: return 'http://' + domain + '/mailman'
| ver. 1.4 |
Github
|
.
| PHP 8.1.34 | Generation time: 0.02 |
proxy
|
phpinfo
|
Settings