jg?ddlmZddlmZddlmZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddl m Z ddl mZmZmZmZddlmZddlmZdd lmZdd lmZmZmZdd lmZdd lmZdd l m!Z!ddl"m#Z#ddl$m%Z%dZ&dZ'd7dZ(d8dZ)dZ*dZ+dZ,dZ-dZ.dZ/dZ0dZ1d9dZ2d7dZ3d:d!Z4d:d"Z5d#Z6d$Z7d%Z8d&Z9d'Z:d(Z;d)Zd.Z?d/Z@d7d0ZAd1eBd2eCfd3ZDd4eBfd5ZEd6ZFdS)<)print_function)absolute_import)divisionN)time)AnyStrListDictOptional)Path)resolve_username_and_doc_root)CP_NAME)NoDomain NotSupported IncorrectData) mod_makedirs)init_sentry_client)get_pkg_version)clprint)ClSelectExceptz/sbin/cagefs_enter_userzehttps://9713d1296f804031b058b8f2d789d7ac:8ddacae32d8246cf8b25cf826bf3fc0a@cl.sentry.cloudlinux.com/12c  tj|tdtjtjd|d}|\}}nA#t tf$r-}tj |dt|d}~wwxYw|j dkr/tj |pdd |d||S) z Runs external process and returns output :param cmd: command and arguments as a list :param env_data :return string /dev/nullT)stdinstdoutstderr close_fdsenvtextrNzoutput of the command:   ) subprocessPopenopenPIPESTDOUT communicateOSErrorIOErrorrFileProcessErrorstr returncodeExternalProgramFailedjoin)cmdenv_dataoutputstd_outstd_erres E/opt/cloudlinux/venv/lib64/python3.11/site-packages/clselect/utils.py run_commandr5&s >! {##?$"--// W >>>-c!fc!ff===> A274j4jadaiaijmananananahah?jkk k NsAAB'(BBc D tj|tdtjtj|d||}|\}}nA#t t f$r-}tj|dt|d}~wwxYw|j ||fS)a Runs external process and returns output. Differs from subprocess.check_output, run_command above, and check_output below in that it does not throw an exception if process's return code != 0 :param cmd: command and arguments as a list :param env_data :param preexec_fn: Pre-exec function. None if don't need :param cwd: Directory name to set as current :return Cortege: (ret_code, stdout, stderr) rT)rrr preexec_fnrcwdrrN) r!r"r#r$r&r'r(rr)r*r+)r.r/r7r8processr1r2r3s r4run_command_fullr:?s >" {##??!#..00 W >>>-c!fc!ff===>  w //sAAB((BBcd} t|}|}|n#ttf$rYnwxYw|S)z8 Reads file contents and returns it as a string )r#readcloser'r()filenamedefaults_contentsfs r4read_file_as_stringrBZsb NNFFHH  W      s7<AAct|i|dSN) check_output)argskwargss r4 check_callrHhs$!&!!!!!c|dd}|d}|dd}|dd}|r||z }|d= tjd |tjtjdd|}nA#t t f$r-}tj|dt|d}~wwxYw| \}} |r)| || || |jrtj|p| p||S) av check_output(val1, val2, val3, arg4=val4) equivalent check_output(args=(val1, val2, val3), arg4=val4) or equivalent check_output(val1, args=(val2, val3), arg4=val4) DON'T USE check_output((val1, val2, val3), arg4=val4) :param tuple *args: arguments for command line :param dict **kwargs: parameters for subprocess.Popen :return str: errorNrFr0waitT)rFrrrr)popgetr!r"r$r'r(rr)r*r&writer>rLr+r,) rFrGrKargs_from_kwargsr0rLpr3rrs r4rErEls] JJw % %Ezz&)) ZZ$ ' 'F ::fd # #D    6N?   J$z$.O$ J JBH J J W ???-d1gs1vv>>>?]]__NFF  V   |N253LF3LfMMM Ms#*BC (CC cDfdtjDS)Ncg|]A}tjtj|?|BSrM)ospathisdirr-).0drVs r4 zlist_dirs..sK 5 5 5!w}}RW\\$2233 5A 5 5 5rI)rUlistdirrVs`r4 list_dirsr]s7 5 5 5 5rz$'' 5 5 55rIc #K|V|D]M\}}|t|zV|D]1}|dtt||fzV2NdS)N.)r*r-map)rVversionsmajorminorsminors r4 versioningres JJJ!<< vSZZ < ":":;;; ; ; ; ; <<>G ! " "N&&8A 888 LNN N G rIc@tjdS)Nz /var/.cagefs)rUrVrWrMrIr4 in_cagefsr~s 7== ( ((rIrcd}t|||} |}|n#|wxYw|S)zg read file and close :param path: file path :param mode: reading mode :return str: N)modeerrors)r#r=r>)rVrrdatastreams r4 file_readrsU D $T& 1 1 1F{{}}   Ks ?Acg}t||} |}|n#|wxYw|S)zE read litle file and close :param path: :return str: r)r# readlinesr>)rVrrrs r4file_readlinesrsW D $v & & &F!!   Ks >Awct|||} |||dS#|wxYwzN write litle data to file and close :param path: :return str: rN)r#rPr>)rVlinerrrs r4 file_writersR $V , , ,F T   ?Act|||} |||dS#|wxYwr)r# writelinesr>)rVlinesrrrs r4file_writelinesrsT $V , , ,F%     rctjddkr+tjddkr||S||d}t |dkr|d||df}n |dddf}|S)z str.partition for all python versions :param s: string to parse :param sep: separator to split by :return: cortege - see str.partition function for python 2.5+ rrmrr<)sys version_info partitionsplitlen)srts_parts ret_corteges r4rrrrs aC$4Q$71$<$<{{3ggc1ooG 7||qqz3 3 qz2r* rIc t|d}n#t$rYdSwxYwd}tj|}|D]}||r|dz }||S)z" find regex count in file rNrr)r#r(recompilesearchr>)patternrVrAcounterregexrs r4grepr s sOO ttG Jw  E <<    qLGGGIII Ns  !!c$ddlm}||S)z Determines is user should be skipped in selectorctl work :param username: user name to check :return: True - user should be skipped, False - not r)is_admin)clcommon.cpapir)usernamers r4user_should_be_skippedrs& (''''' 8H  rIc tj|se t|ddS#tt f$r>}t d|dt|tj dYd}~dSd}~wwxYwdS)NizError: failed to create:r) rUrVrWrr(r'printr*rexit)dest_dirr3s r4make_dirr's 7== " "  5 ) ) ) ) )!    +XsCFF C C C HQKKKKKKKKK s3B3A==Bc tj|n#t$rYnwxYwtj|rt j|ddSdS)NT)rUunlinkr'rVrWshutilrmtreer\s r4remove_file_or_dirr0sn  $       w}}T" dD!!!!!""s  $$c  tj|rEtj||kr+tj|tj||dSdSt |tj||dS#t$r@}td|d|dt|tj dYd}~dSd}~wwxYw)NzError: failed to create symlinkz->rr) rUrVislinkreadlinkrsymlinkrr'rr*rr)srcdstr3s r4 make_symlinkr9s  7>>#   !{33&& # 3$$$$$'& s # # # JsC  /dCc!ffMMM  sA B &$B C5CCc2tj|dddS)N),z: T)indent separators sort_keys)jsondumps)rs r4 pretty_jsonrGs :d1 M M MMrIrFc |}d} t||\}}n#t$rCtj|dd||dt jdYnt$r:|rn4tj|ddtzdt jdYnAt$r5tj|dd|d |dt jdYnwxYw||fS) a Safely resolve username and doc_root by domain, or resolve document root by username, or resolve document root and username by effective uid :param pass_not_supported_panel: pass not supported panel for php selector :param msg_format: error messages' format (json or text) :param user: str -> name of unix user :param domain: str -> domain of panel user :return: tuple -> user, doc_root N)rwdomainERRORz(No domain found for user: {}, domain: {})statusmessagerz6NodeJs/Ruby/Python selector not supported for %s panelzDomain z is not owned by the user ) r rr print_diagformatrrrr r)rwr msg_formatpass_not_supported_panel result_userresult_doc_roots r4$safely_resolve_username_and_doc_rootrLs`KO"'D( ( ( $ __  !ELLTSYZZ           #    %WZaa    HQKKK  !'FLffddS         ''sA C''AC');C'&C'ct||d}|D](}t||d}||kr ||cS)td|)a Transform all directories to realpath, compare and return config value :param user: str -> unix user - owner of the config :param directory: str -> wanted directory key :param config: dict -> config to get value from, should have directories as keys r%Config does not contain directory: {})r|KeyErrorr)rwrxconfig abs_directoryconf_dir abs_conf_dirs r4get_using_realpath_keysrs i003M$$"42215 L ( ((# # # # ) /66yAA C CCrIc t||d}d}t|}|D]#}t||d}||kr||=d}$|s"td|dS)a Transform all directories to realpath, compare and remove directory key :param user: str -> unix user - owner of the config :param directory: str -> wanted directory key :param config: dict -> config to remove key from, should have directories as keys rFTrN)r|listkeysrr)rwrxrrremoved_at_least_one config_keysrrs r4delete_using_realpath_keysrs i003M v{{}}%%K(("42215 L ( (x #' G 3 : :9 E EGG GGGrIc^t||dt||dkS)a# Checks that two paths in user home directory are the same after stripping symlinks :param user: Unix user whose home directory contains both paths :type path1: str :type path2: str :return: True if paths are canonically the same otherwise False :rtype: bool r)r|)rwpath1path2s r4realpaths_are_equalrs- tU # #A &+dE*B*B1*E EErIcli}|si}t||g|z}tj||tjtjd}|\}}|j} |s,| dkr&d|dtd}n|}||d<| |d<| rdnd |d <|S) z= Run any process using the utility cagefs_enter_user T)rrrrzUser's process "{}" failed and didn't return anything. It could mean that user has too small limit of PMEM for running of cloudlinux-selector. Please, increase the limit to user and try run process againrK)detailsresult timestampr0r+Ffailed) CAGEFS_ENTER_USER_BINr!r"r$r&r+rrstrip) rwpath_to_utilityargs_for_utilityenv_varsrr.r9r_retcodes r4run_process_in_cagefsrs F  $ 8;K KCs&0o&0o$(***G##%%IFA G   gmmNNTfUdNeNe   F8"F<&1ttEF8 MrIversionreturnctdtdtd}d|dd}d}t d}|sdS t |5}|}d d d n #1swxYwY|d std |d ||vrd S||vr[t | d  }| }|t|vrd Sn#|YnxYwdS)ar Check if python version is used by imunify packages The algorithm is as follows: - Verify if imunify services are installed - Check if shebang contains the path to the specified Python version being checked - If shebang contains the path to the imunify virtual environment, determine the Python version it is based on by reading a symlink lvemanagerF)releasedsnhandlez/opt/alt/pythonr_r<z/opt/imunify360/venvz/usr/bin/imunify-serviceNz#!zERROR: "z" doesn't have a shebangT)rr LVEMANDSNreplacer is_filer#readline startswith Exceptionrsrrr*captureException) r sentry_clientalt_pathimunify_venv_pathimunify_servicerA first_linevenv_python_bin python_bins r4is_imunify_using_pythonrs' --  M<b!9!9;;H.566O  " " $ $u) / " " &aJ & & & & & & & & & & & & & & &$$T** SQQQQRR R z ! !4  * *":#4#4T#:#:#@#@#B#BCCO(1133J3z??**t)&&((((( 5s7'D06B D0BD0B/D0AD00Erwc>tjfd}|S)z Drops to user ctjjtjjtjd<jtjd<dS)NUSERHOME)rUsetgidpw_gidsetuidpw_uidenvironrq)rwuser_pwdsr4funczdemote..func sG (/""" (/"""! 6%_ 6rI)rorp)rwrrs` @r4demoters:|D!!H------ KrIcld}d}|D](} ||g|Ri|}|dz}#|$r } | }Yd} ~ !d} ~ wwxYw|s||S)NFTrM) rusersexception_typerFrGcaught_exception is_handled user_aliasrr3s r4apply_for_at_least_one_userrsJ  T*6t666v66F $ JJ ! ! !       !  Ms -(-rD)NNN)rN)rN)NNrF)G __future__rrrrhrUrorr!rrrrtypingrrr r pathlibr clcommon.clpwdr rr clcommon.cpapi.cpapiexceptionsrrrclcommon.utilsrclsentryrclsentry.utilsr clselectprintrclselectexceptrrrr5r:rBrHrEr]rerkr|r~rrrrrrrrrrrrrrrrrr*boolrrrrMrIr4r&s&%%%%%&&&&&&  ////////////888888""""""PPPPPPPPPP''''''''''''******""""""******2 s 200006   """   F555 <<<    )))                $&"""   NNN 2(2(2(2(jCCC$GGG* F F F####L)S)T))))X     rI