C!Mjx7 ddlZddlZddlZddlZddlZddlZddlZddlZddlZddlm Z ddl m Z m Z m Z ddlmZddlmZmZmZddlmZddlmZddlmZdd lmZdd lmZmZmZmZdd l m!Z!dd l"m#Z$ej%e&Z'd Z(de)de e*fdZ+de)de e*fdZ,de)de)de e*fdZ-de de*fdZ.de de)fdZ/de fdZ0de*de1fdZ2de*de e1e1e3ffdZ4dZ5d e)d!e e*de*fd"Z6 d+d e)d!e e*de e*fd#Z7 d,de)d%e e*d&e)de e e*e3ffd'Z8de e e*e*ffd(Z9d)ej:de e e*e*ffd*Z;dS)-N)Logger)ListOptionalTuple)drop_privileges) run_commandExternalProgramFailedis_user_present)cpusers)get_main_username_by_uid)REDIS_SERVER_BIN_FILE) WposError) USER_WPOS_DIRis_run_under_userdrop_permissions_if_neededrun_in_cagefs_if_needed) NoPackage)gettextz/opt/alt/redis/bin/redis-cli file_pathreturncd}tj|sd} t||gd}|d}|ddd}g}|d D]G} |t|8#t$rYDwxYw|S#ttf$rYnwxYwgS) z Retrieves list of PID list processes, which uses file (using fuser utility) This can find any process (for example php), not only redis service process :param file_path: Filename to check :return: PID list z/usr/bin/fuserz /sbin/fuserFreturn_full_output r: ) ospathexistsrsplitstripappendint ValueErrorr IndexError)r fuser_binarystd_out lines_list s_pid_listpid_lists_pids N/opt/cloudlinux/venv/lib64/python3.11/site-packages/clwpos/daemon_redis_lib.py_get_pids_for_filer.2s$L 7>>, ' '%$  |Y7ERRR]]4(( ]((--a06688 %%c**  E EKKMM 2 23333     !: .     Is6A4C!4CC! CC!CC!!C54C5usernamec tdddd|gd}n#t$rgcYSwxYw|d}t|dkrgSg}|d d }|D]^}|}|rF |t |N#t$rYZwxYw_|S) zz Update PID list in cache for user using /bin/ps utility :param: username: Username to scan :return: None z/bin/psz-opidz-uFrrrN)rr r!lenr"r#r$r%)r/r(r) user_pid_listlines r-_get_user_pidsr6Rsy$tXF[`aaa  t$$J : MABBJzz||   $$S%6%67777      s ((<4B11 B>=B>home_dirctj|td}t |}t |}g}|D]}||vr|||S)z Get redis PID list for user :param username: user name :param home_dir: User's homedir :return: PID list or [] if user has no redis redis.sock)rrjoinrr.r6r#)r/r7redis_socket_file pid_list_sock user_pidsr+r1s r-_get_user_redis_pidsr>rsn X}lKK&'899Mx((IH!! )   OOC O_loggerr1ctstd tj|tjt jd tj|tjn#t$rYnwxYwn;#t$r.}| d|t|Yd}~nd}~wwxYw| dt|dS)zj Kill process by pid :param _logger: Logger to log errors :param pid: Process pid to kill z;Internal error! Trying to kill process with root privilegesz+Can't kill redis process, pid %s; error: %sNzKilled process with pid=%s) rrrkillsignalSIGTERMtimesleepSIGKILLOSErrorwarningstrinfo)r@r1es r-kill_process_by_pidrNs   WUVVVT V^$$$ 1   GC ( ( ( (    D  TTTEsCPQFFSSSSSSSST LL-s3xx88888s;3BA32B3 B=B?BB B<$B77B<loggercHt|sdStj|}t|j|j}|dt||t|5|D]}t|| ddddS#1swxYwYdS)zq Kill all user's redice processes :param logger: Logger to log errors :param username: User name Nz%Killing redis with pid=%s for user=%s) r pwdgetpwnamr>pw_namepw_dirrLrKrrN)rOr/user_pwdredis_pid_list redis_pids r-_kill_all_redises_for_userrXs 8 $ $|H%%H)(*:HOLLN KK7^9L9LhWWW  " "33' 3 3I  2 2 2 2 3333333333333333333s3BBBc t}nN#ttttf$r.}|dt |Yd}~dSd}~wwxYw|D]}t||dS)z[ Find and kill lost redices for all panel users :param logger: Daemon's logger z"Can't get user list from panel: %sN)r rIIOErrorr&rrJrKrX)rOusersrMr/s r-kill_all_users_redisesr\s   Wj) 4;SVVDDD55"68444455sA#AAuidc T t|}tj|}n9#t$r,tdt |YdSwxYwtj |j td}td|dg}t|5t|}td|t |jt |jt |jdddn #1swxYwY|jdkS) a$ /opt/alt/redis/bin/redis-cli -s /home/cltest1/.clwpos/redis.sock ping Could not connect to Redis at /home/cltest1/.clwpos/redis.sock: No such file or directory echo $? 1 /opt/alt/redis/bin/redis-cli -s /home/cltest1/.clwpos/redis.sock ping PONG echo $? 0 4Redis check error for user %s. No user with such uidFr9z-spingzDRedis health check for user=%s, return code=%s, stdout=%s, stderr=%sNr)r rQrRKeyErrorrOrJrKrrr:rTr_REDIS_CLI_BIN_FILErrrL returncodestdoutstderr)r]r/rUredis_socket_pathredis_ping_cmdoutputs r-redis_socket_health_checkrisR+C00<)) MsSVxxXXXuu X_m\RR)41BFKN #H - -(((88 Z)** && &&  ( ( ((((((((((((((((   !!s"#&2AA$A$DDDuser_idc" tj|}|j}n\#t$rOtdt |ddtddt |idfcYSwxYw t|}ne#t$rX}td|t |ddtdt ||d dfcYd }~Sd }~wwxYw|sddtd d |d dfSddd difS)a Check user's redis is alive :param user_id: uid to check sockets return True/False - redis alive/not alive :return: Tuple: (redis is working/not working, is user present, errors dict) error - (False, False {"result": "error", "context": "..."}) r_Fz9Redis check error for user with uid %(uid)s. No such userr]resultcontextz+Redis check error for user %s. Error is: %sTz1Redis CLI start error %(error)s for user %(user)s)erroruserNz1Redis CLI check error %(error)s for user %(user)sz=Redis is not pingable for user, most likely it is not startedrmsuccess) rQgetpwuidrSrarOrJrK_ri Exception)rjrUr/is_redis_aliverMs r-is_user_redis_alivervs@<((# @@@MsSZ||\\\e*e(f(f*/W)>@@@ @ @ @@ Q27;; QQQDhPSTUPVPVWWWd*](^(^47FFH)N)NQQQ Q Q Q Q Q QQ <dq)\']']2q19););<<< < ), ,,s/AA76A7;B C-A C("C-(C- redis_pid_filename expected_uidc tj|tjtjztjz} tj|}t j|jstd||j |krtdtj |t}tj |n#tj |wxYwt|ddS)a Read and parse the redis pid from the pid file in a hostile-input-safe way. The pid path lives under the user-owned /.clwpos/, so when the root daemon reads it the file is attacker-controlled. Open with O_NOFOLLOW so a symlink planted at the path is not followed (raises OSError/ELOOP), fstat to require a regular file owned by the expected user (rejects FIFO/device/cross -owner targets that could block or mislead root), and read a bounded length. :param redis_pid_filename: Redis PID filename :param expected_uid: UID the pid file must be owned by, or None to skip the owner check (caller already runs as the target user) :return: parsed pid :raises OSError, ValueError: on any guard failure or parse error z$redis pid file is not a regular fileNzredis pid file owner mismatchasciistrict)ropenO_RDONLY O_NOFOLLOW O_CLOEXECfstatstatS_ISREGst_moderIst_uidread_REDIS_PID_FILE_MAX_BYTEScloser$decoder")rxryfdstraws r-_read_pid_from_pid_filers #R[2=%@2<%O P PB Xb\\|BJ'' B@AA A  # \(A(A9:: :gb344   szz'8,,2244 5 55s A2CCctdD]b} t||}tj|d|cS#tt t tf$rtj dY_wxYwdS)ai Get redis process PID from redis pid file. Wait up to 10 seconds :param redis_pid_filename: Redis PID filename :param expected_uid: UID the pid file must be owned by when read in root context (None skips the owner check for already-dropped callers) :return: Redis PID or None on error (pid file absent/invalid or redis not started) drg?N) rangerrrCrIrZr%UnicodeDecodeErrorrFrG)rxryir1s r-&_get_redis_pid_from_pid_file_with_waitrs3ZZ )*rNrXr\boolridictrvrrrrrProcessrr?r-rs   ((((((((((****** #"""""333333222222////// 544444  8 $ $4#$s)@ST#Y@3#$s)"99c9999,3v33333$ 56 5 5 5 5"3"4"""":--tT4/?)@----B668C=6UX6666:JNs9A#RZ[^R_.6:.,.,3.,08 .,/2.,>CHSMSWDW>X.,.,.,.,b #tE#s(O, # # # #FNxc3h/Hr?