j&XdZddlZddlZddlZddlZddlZddlmZddlm Z ddl m Z ddl m Z ddlmZmZdd lmZdd lmZdd lmZdd lmZdd lmZddlmZmZmZddlm Z m!Z!m"Z#GddZ$ddZ%dS)zA This module contains classes implementing SSA Manager behaviour N)contextmanager)iglob) disable_quota)Tuple)load_validated_parserload_configuration) flag_file)SSAManagerError) ssa_version) AutoTracer) DecisionMaker) INI_FILE_NAMEINI_USER_LOCATIONS_BASEis_excluded_path)$copy_inis_to_website_isolation_paths(remove_inis_from_website_isolation_pathsregenerate_inis_for_userc"eZdZdZdZdZedefdZe de fdZ e de fdZ e de fdZd ede fd Z d.d edejfd ZdedefdZdefdZdefdZdefdZdefdZdefdZdede fdZdededefdZdedefdZdeeeefeffdZ e!dZ"dedededd fd!Z#d/d"Z$deeeefeffd#Z%d/d$Z&d/d%Z'd/d&Z(defd'Z)d/d(Z*d/d)Z+defd*Z,d/d+Z-d,edd fd-Z.d S)0Managerz SSA Manager class. ctjd|_t|_ddg|_ddg|_d|_d|_t|_ tttjf|_dS)Nmanagerz!usr/lib64/php/modules/clos_ssa.soz0usr/lib/x86_64-linux-gnu/php/modules/clos_ssa.sozlib64/php/modules/clos_ssa.soz,lib/x86_64-linux-gnu/php/modules/clos_ssa.soz lib/php/extensions/*/clos_ssa.so)z /opt/alt/php[0-9][0-9]/link/confz+/opt/cpanel/ea-php[0-9][0-9]/root/etc/php.dz$/opt/plesk/php/[0-9].[0-9]/etc/php.dz'/usr/local/php[0-9][0-9]/lib/php.conf.dzM/usr/share/cagefs/.cpanel.multiphp/opt/cpanel/ea-php[0-9][0-9]/root/etc/php.dzA/usr/share/cagefs-skeleton/usr/local/php[0-9][0-9]/lib/php.conf.d)logging getLoggerloggerr ini_file_namemodule_patterns_with_usrmodule_patterns_no_usrmodule_glob_pattern_directadminwildcard_ini_locationsrwildcard_ini_user_locationsOSError ValueError subprocessSubprocessErrorsubprocess_errorsselfs B/opt/cloudlinux/venv/lib64/python3.11/site-packages/ssa/manager.py__init__zManager.__init__-sz' 22 * 0 >) % , :' #0R,' #,C( Z!;" c J tj} tj|j}n#t $rd}YnwxYwdd|D}|j d|||||dS#t $rYdSwxYw)Nz  c3*K|]\}}|d|VdS)=N.0kvs r) z!Manager._audit..PsB$>$>%)Q111aa $>$>$>$>$>$>r+z0[audit] operation=%s status=%s uid=%d user=%s %s) osgetuidpwdgetpwuidpw_name Exceptionjoinitemsrinfo)r( operationstatusdetailsuidusername detail_partss r)_auditzManager._auditIs )++C '<,,4 ' ' '& '88$>$>-4]]__$>$>$>>>L K  B63, @ @ @ @ @    DD s-B0B ?B?AB B"!B"returncddi}|d|Dtj|S)z@ Form a success json response with given kwargs resultsuccessci|]\}}|| Sr0r0r1s r) z$Manager.response..^s===daQ===r+)updater=jsondumps)argskwargs raw_responses r)responsezManager.responseXsI !), ==fllnn===>>>z,'''r+cJtjtS)z Is SSA enabled )r6pathisfiler r's r)_enabledzManager._enabledas w~~i(((r+c ddhS)zK Configuration settings required Request Processor restart requests_duration ignore_listr0r's r)_restart_required_settingsz"Manager._restart_required_settingshs $]33r+c hdS)N>time correlationdomains_numberrequest_numbercorrelation_coefficientr0r's r)solo_filtered_settingszManager.solo_filtered_settingsos*** *r+settingsc6|j|S)z SSA Agent requires restart in case of changing these configuration: - requests_duration - ignore_list )rZ intersection)r(rbs r)_restart_requiredzManager._restart_requiredts .;;HEEEr+Fcommandc  tjdd|gdd|}|jd|dn#tj$r}|jdt |jt |jt |j |j|j|j |j d td |jd |jd |j p|j d }~w|j $rS}|jdt |dt |i td|d|d }~wwxYw|S)z Run /sbin/service utility to make given operation with SSA Agent service :command: command to invoke :check_retcode: whether to run with check or not :return: subprocess info about completed process z /sbin/servicez ssa-agentT)capture_outputtextcheckz ssa-agent z succeededz$SSA Agent %s failed with code %s: %s)cmdretcodestdoutstderrextraz SSA Agent z failed with code z: Nz&Failed to run %s command for SSA AgenterrzFailed to run z for SSA Agent: ) r$runrr>CalledProcessErrorerrorstrrk returncodermrnr r&)r(rf check_retcoderHes r)run_service_utilityzManager.run_service_utility|s ?^_%0%,%.48d*7 999F K  ='=== > > > >, ^ ^ ^ K  6AE AL!!AH e !"QX??  @ @ @"\QU\\al\\ahFZRSRZ\\^^ ^% ? ? ? K  FG %*CFFO  5 5 5!===!==?? ? ?  s#9=E BC(( E5AEErOc t}fdt|D}| |nv#t $ri}|jddt|i| dd|t|td|d }~wwxYw| dd | | r| d d | S)z Change SSA config and restart it. :args: dict to override current option values :return: JSON encoded result of the action c$i|] \}}|v || Sr0r0)r2r3r4rOs r)rKz&Manager.set_config..s/(((DAq$YYa&YYr+z Failed to update SSA config filerqro set_configfailure)previous requestedrtz"Failed to update SSA config file: NrI)r~newrestartTrw)rdictr=overridewrite_ssa_confr"rrtrurEr reryrR)r(rOconfigprevious_valuesrxs ` r)r|zManager.set_configs| '((((((D,@,@,F,F,H,H((( L  ! ! # # # # L L L K  @%*CFFO  5 5 5 KK i!0D!!ff  & & &""Jq"J"JKK K  L L),$  8 8 8  ! !$ ' ' D  $ $Yd $ C C C}}s%A:: C-A$C((C-cJt}||S)zV Get current SSA config. :return: JSON encoded current config )r)r rR)r( full_configs r) get_configzManager.get_configs# )** }}K}000r+cD|jrdnd}||S)zY Get current status of SSA. :return: JSON encoded current status enableddisabled) ssa_status)rVrR)r(r@s r)get_ssa_statuszManager.get_ssa_statuss( #m;}}}///r+c b|j}|sw |||n9#t$r,}|dddt |d}~wwxYw|dd|rdnd|S) a Enable SSA: - add clos_ssa extension for each PHP version on server - add clos_ssa extension into cagefs for each user and each ver - start SSA Agent (if it is not already started) - restart Apache (etc.) and FPM, reset CRIU images - create flag_file indicating that SSA is enabled successfully :return: JSON encoded current status enable_ssar}rprevious_statertNrIrr)rV generate_inisstart_ssa_agent create_flagr;rErurr( was_enabledrxs r)rzManager.enable_ssasm   ""$$$$$&&&  """"    L)+5SVVEEE  L)0;#K99  M M M""$$$'A99A>c b|j}|rw |||n9#t$r,}|dddt |d}~wwxYw|dd|rdnd|S) a{ Disable SSA: - remove clos_ssa extension for each PHP version on server - remove clos_ssa extension from cagefs for each user and each ver - stop SSA Agent - restart Apache (etc.) and FPM, reset CRIU images - remove flag_file indicating that SSA is enabled :return: JSON encoded current status disable_ssar}rrNrIrr)rVremove_clos_inisstop_ssa_agent remove_flagr;rErurrs r)rzManager.disable_ssasm   %%'''##%%%  """"    M9+4CFFDDD  M90;#K99  M M M""$$$rcdtD}||t|jrdnd|t S)z Get SSA statistics. Includes: - config values - version - SSA status (enabled|disabled) - SSA Agent status (active|inactive) :return: JSON encoded current statistics cXi|]'\}}|t|(Sr0)rulower)r2keyvalues r)rKz%Manager.get_stats..s<111zsE3E ((**111r+rr)rversionr@ agent_status autotracing)r r=rRr rVstatus_ssa_agentr get_stats)r(_configs r)rzManager.get_statss11%''--//111}}MM $ =99:..00" ..00    r+dir_pathc t|S)z= Check if directory path should be excluded. )r)r(rs r)unused_dir_pathzManager.unused_dir_path s )))r+php_rootpatternsc|D]E}tj||}tj|r|cSF|r&tj||dndS)z Search for clos_ssa.so module in php_root using a list of patterns. Returns the first found module path, or the first pattern as expected path if none exist. r)r6rTr<exists)r(rrpattern module_paths r)_find_module_in_rootzManager._find_module_in_rootsu   # #G',,x99Kw~~k** #"""" #7?Frw||Hhqk222BFr+ini_pathc|dr:d|vr6|dd}|||jS|drPd|vrL|dd}|dd}|||jS|d r:d|vr6|dd}|||jS|d r:d|vr6|dd}|||jS|d rjd |vrf|d d}t ttj ||j }|r|dSd S|drjd |vrf|d d}t ttj ||j }|r|dSd S|drXd|vrT|dddd}d|}|||jSd S)z Determine the path to clos_ssa.so module based on ini_path. Returns the expected module path, or empty string if not found. z /opt/alt/phpz /link/confrz4/usr/share/cagefs/.cpanel.multiphp/opt/cpanel/ea-phpz/root/etc/php.dz"/usr/share/cagefs/.cpanel.multiphpz/usr/share/cagefs-skeletonz /etc/php.dz/opt/cpanel/ea-phpz/opt/plesk/php/z(/usr/share/cagefs-skeleton/usr/local/phpz/lib/php.conf.drz/usr/local/phpz /var/cagefs/z/etc/cl.php.d/alt-phpr/z&/usr/share/cagefs-skeleton/opt/alt/php) startswithsplitrrreplacerlistrr6rTr<r)r(rr skeleton_pathpossible_pathsphp_ver skeleton_roots r)get_module_pathzManager.get_module_paths   ~ . . V<83K3K~~l33A6H,,Xt7TUU U   U V V V[lpx[x[x$,,-QSoppM$**<88;H,,Xt7TUU U   3 4 4 V9Jh9V9V~~l33A6H,,Xt7TUU U   0 1 1 Tlh6N6N~~l33A6H,,Xt7RSS S   I J J O`dlOlOl~~&788;H!% Xt?c(d(d"e"effN )%a((2   / 0 0 5F(5R5R~~&788;H!% Xt?c(d(d"e"effN )%a((2   ~ . . [3Jh3V3Vnn%<==a@FFsKKANGNWNNM,,]D)r(locationr pw_records r)existing_pathszManager.existing_paths`s0 3 ' 'H!(OO ' '''11h&&&&& ' 8 I IH!(6"233 I I''11I 0 0 : :I%+Y-=>HHHHH K$$&56>@@@H I I Is 2BB5c#K tj|tj|dVtjdtjddS#tjdtjdwxYw)z Dive into user context by dropping permissions to avoid most of the security issues. Does not cover cagefs case because it also requires nsenter, which is only available with execve() call in our system Nr)r6setegidseteuid)r(rBgids r) _user_contextzManager._user_contextzsn  JsOOO JsOOO EEE JqMMM JqMMMMM JqMMM JqMMMMs ,A*BrBrNcT||}|s|jd|dStj|s|jd||tj||j}tj|r | ||5tj ||jd|dddn #1swxYwYn@#t$r3}|jd|t|Yd}~nd}~wwxYwdStj||j}| ||5t5t|d5}|jd||ddddn #1swxYwYdddn #1swxYwYddddS#1swxYwYdS) zB Enable SSA extension for single ini_path (given) zr<rrunlinkr;ruropenwrite) r(rBrrr ini_file_pathrxrTinis r)generate_single_inizManager.generate_single_inis) **844   K   ^`h i i i Fw~~k**  K  WYdfn o o oGLL43EFFMw~~m,, cc++C55bb -000 (()QS`aaabbbbbbbbbbbbbbb!cccK''(JM[^_`[a[abbbbbbbbc Fw||Hd&899   S ) ) 1 1 1 1T3 1#& K  4d ; ; ; II/ 0 0 0  1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1s6D 0D< DD  DD D E)E  EH H11G." H.G2 2H5G2 6H9 HH H H HH!$H!c |jd|D]\\}}} ||||!#t$r|jd|YHt $r3}|jd|t|Yd}~d}~wwxYwt|j |jddS)z Place clos_ssa.ini into each existing Additional ini path, including cagefs ones and per-website directories z Generating clos_ssa.ini files...z>Unable to update file %s, possible permission misconfigurationz7Exception on generating clos_ssa.ini: "%s", error: "%s"N Finished!) rr>rrPermissionErrorr;rtrurr)r(rBrrrxs r)rzManager.generate_iniss ;<<<$($7$7$9$9   JS# ((c8<<<<"      "HIQSSS    !!"[]egjklgmgmnnn  -T-?@@@ %%%%%sA%B37 B3)B..B3c#K|D]O\\}}}tj|D]2}|j|vr ||ftj||fV3PdS)z Generator function searching for clos_ssa.ini files in all existing Additional ini paths Returns tuple of (uid, gid) and path. N)rr6listdirrrTr<)r(rBrrnames r)find_clos_iniszManager.find_clos_iniss %)$7$7$9$9 ? ? JS# 8,, ? ?%T11Cj"',,x">">>>>>> ? ? ?r+c |jd|D]\\}}} |||5t j|dddn #1swxYwYL#t $r3}|jd|t|Yd}~d}~wwxYwt|j|jddS)z[ Remove all gathered clos_ssa.ini files, including per-website directories zRemoving clos_ssa.ini files...Nz5Exception on removing clos_ssa.ini: "%s", error: "%s"r) rr>rrr6rr; exceptionrur)r(rBrclos_inirxs r)rzManager.remove_clos_iniss? 9:::$($7$7$9$9   JS# ''S11((Ih'''(((((((((((((((    %%&]_gilmnioioppp  11CDDD %%%%%s;A;A/# A;/A3 3A;6A3 7A;; B8)B33B8c|d}|jr|dddS|dddS)ze Start SSA Agent service or restart it if it is accidentally already running r@startTrrNryrvr(rs r)rzManager.start_ssa_agentsa //99  " D  $ $WD $ A A A A A  $ $Yd $ C C C C Cr+cp|d}|js|dddSdS)z` Stop SSA Agent service or do nothing if it is accidentally not running r@stopTrNrrs r)rzManager.stop_ssa_agentsN //99 & A  $ $V4 $ @ @ @ @ @ A Ar+cZ |ddn#t$rYdSwxYwdS)z: Get SSA Agent status: active or inactive r@Trinactiveactive)ryr r's r)rzManager.status_ssa_agentsJ   $ $XT $ B B B B   :: xs  ((cttd5 dddn #1swxYwY|jdtddS)zE Create a flag file indicating successful enablement rN Flag file z created)rr rr>r's r)rzManager.create_flags)S ! !                   9i999:::::s $((c  tjt|jdtddS#t $r=}|jdtdt|Yd}~dSd}~wwxYw)z: Remove a flag file indicating enablement rz removedz removal failed: N)r6rr rr>r"rru)r(rxs r)rzManager.remove_flags C Ii K  =)=== > > > > > C C C K  AYAAQAA C C C C C C C C C Cs4O@t41C111100000%C%%%%2%S%%%%2 3    (****** GS GD GS G G G G@@@@@@DIeCHos&: ;IIII4^"1s1111111<&&&&, ?eCHos&: ; ? ? ? ?&&&&& D D D DAAAA#;;;; C C C C'C''''!!!! FS FT F F F F F Fr+rrFManager instancectS)zk Factory function for appropriate manager initialization :return: appropriate manager instance )rr0r+r)initialize_managerr-s 99r+)rFr)&rrMrr6r8r$ contextlibrglobrsecureiortypingr configurationrr internal.constantsr internal.exceptionsr internal.utilsr modules.autotracerr modules.decision_makerr clos_ssa_inirrrwebsite_isolationrrrrrrr0r+r)rs  %%%%%%""""""DDDDDDDD))))))000000''''''******111111 BFBFBFBFBFBFBFBFJr+