9Mj3*ddlZddlZddlZddlZddlZddlZddlZddlmZddl m Z ddl m Z m Z mZmZddlmZddlmZmZddlmZdd lmZmZdd lmZmZmZdd lm Z dd l!m"Z"ej#d Z$dZ%dede&fdZ'de&defdZ(de&de&fdZ)dejde&fdZ*dejdeeeeffdZ+d(de,de-fdZ.de e/fdZ0de/de/fdZ1de e-fdZ2d)dZ3de de fd Z4d!e/d"e/ddfd#Z5de de fd$Z6de de fd%Z7de de fd&Z8de de fd'Z9dS)*Nwraps) HTTPStatus)CallableOptionalTupleAny)get_main_username_by_uid)is_cl_solo_editionis_cl_shared_pro_edition)gettext)user_tasks_countfpm_reload_timeout) XRayAPIError XRayErrorXRayMissingDomain)FPMReloadController)NginxUserCacheuser_plugin_utilsz>I_inputreturnctj|}tjt t ||zS)z; Pack input for sending with length-prefix framing )jsondumpsencodestructpack_formatlen)rdatas V/opt/cloudlinux/venv/lib64/python3.11/site-packages/xray/internal/user_plugin_utils.py pack_requestr#%s< :f   $ $ & &D ;wD * *T 11 byte_commandctj|}td|d|S)z! Unpack incoming command zCommand requested => %scommand)rloadsdecodeloggerinfoget)r%parseds r"unpack_requestr.-sEZ ++-- . .F KK)6::i+@+@AAA Mr$msgctdt|tjt t||zS)z- Prefix message with a 4-byte length zPacking message of %i length)r*debugr rrrr/s r" pack_responser36s< LL/S::: ;wC ) )C //r$ sock_objectcd}d}t}|d}|s||Stjt|d}||krt d|zt ||kr>||}|st d||z }t ||k>|S)z9 Read length-prefixed amount of data from socket iirz$Response message too large: %d bytesz.Connection closed before full message received)bytesrecvrunpackrConnectionErrorr )r4chunk max_msglenr/ raw_msglenmsglenparts r"unpack_responser@>s E!J ''C!!!$$J '&&& ]7J / / 2F DvMNNN c((V  && T!"RSS S t  c((V   Jr$cd}|tjtjt j|}t j||\}}} tj|j tj |j }}td|||||n-#t$r td|||YnwxYw|||fS)z6 Retrieve credentials from SO_PEERCRED option 3iz%Connected by proc %i of %i:%i (%s:%s)zConnected by proc %i of %i:%i) getsockoptsocket SOL_SOCKET SO_PEERCREDrcalcsizer9pwdgetpwuidpw_namegrpgetgrgidgr_namer*r+KeyError)r4rcreds_pid_uid_gidusergroups r" extract_credsrUVsG  " "6#4f6H&/ZaJbJb c cE}We44D$\l4((0#,t2D2D2Le  ;T4tUZ[[[[ GGG 3T4FFFFFG t s2B,,'CCrQc8|tj}|dkS)z9 Check for execution as root | command from root Nr)osgeteuid)rQs r"check_for_rootrYfs |z|| 19r$ctjd}|:tt|}td|||SdS)zK Retrieve the value of XRAYEXEC_UID env and resolve it to username XRAYEXEC_UIDNz/Got XRAYEXEC_UID: %s (%s), working in USER_MODE)rWgetenvr intr*r+)proxyuid _proxyusers r"get_xray_exec_userr`osRy((H-c(mm<<  ExQ[\\\r$c2tjd|idS)zF Construct an appropriate formatted response in case of error resultF) ensure_ascii)rrr2s r"error_responserdzs :xoE : : ::r$cNt}|t|jSdS)z3 Check nginx cache status for current user N)r`r is_enabled) proxyusers r"nginx_user_cacherhs.#$$Ii((33r$ctts)tttddS)zL Check if utility is executed as root and throw error in case if no z,Only root is allowed to execute this utilityN)rY SystemExitrd_r$r"root_execution_only_checkrms>   \*X(Y(YZZ[[[\\r$funcc<tfd}|S)zq Decorator aimed to verify domain owner in X-Ray Manager user mode Applies to get_domain_info method cxt}||i|S |i|}nC#t$r6}ttdd|jz}d|_|dd}~wwxYw|j|krHtd||ttdt|z|S) Wraps func N%s cannot be foundDomain Tz%s does not belong to user %s) r`rrrk domain_name_internal_missing_domainrSr*warningstr)argskwargsrgr+eerrrns r"wrapperz'user_mode_verification..wrappers '((  4((( ( 4(((DD    "A2336O 6O6OOPPC+/C (4 ' ( 9 ! ! NN:D) L L LA233c$ii?@@ @ s$ A$1AA$r)rnr|s` r"user_mode_verificationr}s6  4[[""""["H Nr$rt domain_ownerct}|D||kr@td||tt dd|zdSdS)uZ Enforce caller-owns-domain BEFORE the phpinfo probe's side effects (the temp PHP file-write into the target docroot + HTTP fetch) run. It is called from phpinfo_utils.get_php_configuration — the single sink every panel manager funnels into — so one guard covers Plesk, cPanel, DirectAdmin and custom panels. user_mode_verification only compares ownership AFTER the decorated get_domain_info body has returned, so without this pre-check a user-mode tenant can drive a cross-tenant side effect against another user's domain. Uses the SAME ownership primitive as user_mode_verification (get_xray_exec_user) and raises the SAME uniform error so a foreign domain is indistinguishable from a missing one. For root / non-user-mode callers (proxyuser is None) this is a no-op, preserving existing behaviour. Nz$Domain %s does not belong to user %srrrs)r`r*rvrrk)rtr~rgs r"verify_user_owns_domainrsi #$$I!:!:={IVVV.//2IK2I2IIJJJ!:!:r$cFdtfd}|S)z Decorator aimed to check if user is not hitting limit of running tasks, set in X-Ray Manager user mode. Applies to start and continue methods. Limiting of user's running tasks is applied to Shared PRO only. c tdsdSt}||dj}|}|d}|zt d|D}|t krXttd tt tt dSdSdS)zf If XRAYEXEC_UID exists, check if user does not exceed limit of running tasks Tskip_jwt_checkNrrbcDg|]}|ddk|S)statusrunning)r,).0items r" z7user_mode_restricted..check..s0$g$g$gdtxxPXGYGY]fGfGfTGfGfGfr$z>Limit of running tasks is {}. You already have {} running task) r r` ui_api_client get_task_listr,r rrrkformatrw)rxrgui_api_cli_instanseresp list_of_tasks running_counts r"checkz#user_mode_restricted..checks(t<<<  F&((  "&q'"7 &4466D HHX..M( #$g$gm$g$g$g h h  $444#\cc #$4 5 5s;K7L7L ! )(44r$c||i|S)rqrl)rxryrrns r"r|z%user_mode_restricted..wrappers% t tT$V$$$r$rrnr|rs` @r"user_mode_restrictedrsJ4 4[[%%%%%[% Nr$cFdtfd}|S)a Decorator aimed to restrict frequent reloads of FPM service Applies to get_domain_info method. Decorator ordering invariant: this decorator MUST sit OUTSIDE user_mode_verification (i.e. ``@with_fpm_reload_restricted`` above ``@user_mode_verification``) on every get_domain_info implementation. The wrapper below runs ``check`` only AFTER ``func`` returns, so any ownership-failure XRayError raised by the inner user_mode_verification wrapper short-circuits the throttle probe. Reversing the order would let the throttle check inspect another user's FPM service name and raise a distinguishable XRayError(flag='warning') before the outer ownership check could uniformise the response, leaking a side channel on whether the queried domain exists and whose service is currently throttled (see XRAY-244 / CLPRO-3079 information-oracle defense). c>tdrdSt}|v|jrq|d|}t |r7t tdttzddSdSdS) TrNrzhThe X-Ray User service is currently busy. Operation is temporarily not permitted. Try again in %s minuterv)flag) r r` panel_fpmfpm_service_namerrestrictrrkrwr)r!rxrg _fpm_services r"rz)with_fpm_reload_restricted..checks T 2 2 2  F&((  T^ 733D99L"<0099;; 1,-- . #  !   r$c(|i|}|d|i|S)rqr!rl)rxryr+rrns r"r|z+with_fpm_reload_restricted..wrapper,s3 tT$V$$ t$ r$rrs` @r"with_fpm_reload_restrictedrsJ$( 4[[[ Nr$cVdtfdtfd}|S)Nusernamecnt}|"||krttddSdS)zI If exists, check XRAYEXEC_UID against user passed param NzIncorrect user for request)r`rrk)rrgs r"validatez'username_verification..validate9sD'((  X%:%:A:;;<< < ! %:%:r$c:|d}||i|S)Nrrl)rxryrrnrs r"r|z&username_verification..wrapperAs2*%tT$V$$$r$)rwr)rnr|rs` @r"username_verificationr8sV=3==== 4[[%%%%%[% Nr$cZdtddfdtfd}|S)z Decorator aimed to verify user in X-Ray Smart Advice user mode Applies to get_detailed_advice method, which takes part in advice_details and advice_apply methods r!rNct} |dd}n*#t$rttdwxYw|"||krttddSdS)zU If exists, check XRAYEXEC_UID against user in metadata of an advice metadatarz#Requested advice cannot be verifiedNRequested advice does not exist)r`rNrrk)r!rgrs r"verifyz-user_mode_advice_verification..verifyQs'((  FJ' 3HH F F FACDDEE E F  X%:%:A?@@AA A ! %:%:s 'Ac |i|\}}nS#t$rF}t2|jtjkrt t ddd}~wwxYw|||fS)rqNr)rr`errnor NOT_FOUNDrrk)rxry advice_info advice_objrzrnrs r"r|z.user_mode_advice_verification..wrapper]s &*dD&;F&;&; #K   "##/AGz?S4S4S"C D DEE4O   {J&&s  AAAA)dictr)rnr|rs` @r"user_mode_advice_verificationrJsc BT Bd B B B B 4[['''''['& Nr$)N)rN):rKrloggingrWrHrDr functoolsrhttprtypingrrrr clcommon.cpapir clcommon.lib.cleditionr r xrayr rk constantsrr exceptionsrrr fpm_utilsr nginx_utilsr getLoggerr*rr7r#r.r3r@rUr]boolrYrwr`rdrhrmr}rrrrrrlr$r"rs}  111111111111333333OOOOOOOO;;;;;;;;BBBBBBBBBB******''''''  . / /  22222230u0000050 v} sC}1E     HSM;;;;;;4(4.4444\\\\++h++++\KKCKDKKKK,*x*H****Z/X/(////dX$''X''''''r$