a ‡e&@sdZddlZddlmZddlmZddlmZddlm Z m Z m Z m Z ddl Z ddlmZddlmZGd d d ZGd d d ZGd ddZdS)zCommon fixperms classesN)quote)Path)Union)S_IMODES_ISREGS_ISDIRS_ISLNK)Args)IDCachec@s$eZdZdZeeeeeee eefdddZ ee e edfe edffe eefddddZ ee jeed d d Zee je edfd d dZd(eedddZd)eedddZddddZddddZe je defdddZe jeddd Zed!d"d#d$Zed%d&d'ZdS)*PermMapzBase class for fixperms)idsargsuser all_docroots docroot_chmod docroot_chownc Cs||_|jj|_||_|j|_t||_||_||_ |j |}|j |_ |j |_| |dj }||dj} tdd|f|| f|_tj|j|_td|jst|d|jt|j|_g|_dS)Nrz \/home\d*\/z: unexpected homedir: )r skipcopyrZloggerlogHardLinkTracker hard_linksr rgetpwnamZpw_uiduidZpw_gidgidZgetgrnamZgr_gidRule docroot_permsospathrealpathpw_dirhomedirrematch ValueErrorescapehome_reperm_map) selfr r rrrrZpwuserZdoc_uidZdoc_gidr*#./usr/lib/fixperms/fixperms_base.py__init__s$   zPermMap.__init__N)regexmodeschownreturncCs"|jt|j|||dS)z9Add a fixperms path rule. ^HOMEDIR is automatically addedN)r(appendrr'r)r-r.r/r*r*r+add_rule+szPermMap.add_rule)rstatrrc Cs||krdkrnndS|dkr*|jn|}|dkr<|jn|}|j|jf||fkrXdS|jjszt|||Wn2ty}z|j|WYd}~dSd}~00|j |j}|j |j} |j |} |j |} |j dt ||| | | dS)zRuns os.lchownNz+Changed ownership of %s from %s:%s to %s:%s)st_uidst_gidr nooprlchownOSErrorrerrorr Z uid_labelZ gid_labeldebugr) r)rr4rrZtgt_uidZtgt_gidexcZold_userZ old_groupZnew_userZ new_groupr*r*r+r95s0   zPermMap.lchown)rr4modec Cs|dur dSt|j}||kr"dSt|jr0dS|jjs|zt||Wn2tyz}z|j |WYd}~dSd}~00|j dt |t |ddt |dddS)z*Runs os.chmod if the path is not a symlinkNz Changed mode of %s from %s to %s) rst_moderr r8rchmodr:rr;r<roct)r)rr4r>Zorigr=r*r*r+lchmodPs&   zPermMap.lchmodF)r ignore_skipsc csl|||D]Z}zt|}Wn<tyZ}z$|j|WYd}~q WYd}~n d}~00||fVq dS)z8os.walk/os.lstat to yield a path and all of its contentsN)_walkrlstatr:rr;)r)rrDentryr4r=r*r*r+walkks "z PermMap.walk)top_dirrDc #s|s||rdS|Vtj|s(dSt|D]\}}}|D]&}tj||}|s`||s@|Vq@g|D]2}tj||}|s||r|qp|Vqpr2fdd|D|dd<q2dS)Ncsg|]}|vr|qSr*r*).0xZ skip_dirsr*r+ z!PermMap._walk..) should_skiprrisdirrHjoinr1) r)rIrDdirpathZdirnames filenamesfilenamerdirnamer*rLr+rEus$  z PermMap._walk)r0cCs||jdS)z8To be called from fixperms_main.py - processes this userN)fixpermsrhandle)r)r*r*r+runsz PermMap.runc Cs\||jD]J\}}z|||Wq tyT}z|j|WYd}~q d}~00q dS)z5Iterate over a user's files and chown/chmod as neededN)rHr" check_pathr:rr;)r)r4rr=r*r*r+rVs zPermMap.fixperms)r4new_modecCs*|dur dS|jjr&|jd@}||BS|S)z2Get a new file mode including old mode's exec bitsNI)r Z preserve_execr@)r)r4rZZ exec_bitsr*r*r+with_exec_bitss  zPermMap.with_exec_bits)r4rcCs|t|}|j\}}t|jrR|||}|jdkr|j|||j |dSn2t |jrb|}n"t |jrrd}n|j d|dS|dur|||||j||g|j RdS)z"Chown and chmod files as necessaryrNz#Skipping unexpected path type at %s) find_rulestrr.rr@r\st_nlinkraddr/rrrZwarningrCr9)r)r4rruleZ file_modeZdir_moderZr*r*r+rYs       zPermMap.check_pathr)rr0cCsPt|tsJ||jvr|jS|jD]}|j|r$|Sq$td|dS)z+Find the matching ``Rule`` for a given pathzNo matching rule for N) isinstancer^rrr(r-r$r%)r)rrar*r*r+r]s    zPermMap.find_rule)rcCs2|jD]&}||krdSt||rdSqdS)z:Determine if a path should be skipped based on --skip argsTF)rris_relative_to)r)rrr*r*r+rOs  zPermMap.should_skip)F)F)__name__ __module__ __qualname____doc__r r r^listinttupler,rr3r stat_resultr9rCboolrHrErXrVr\rYr]rOr*r*r*r+r s4       r c@sLeZdZdZedddZeeje e e fe e dfdddZ d d Z dS) rzQTracks and handles hard links discovered while walking through a user's files)r(cCs"||_i|_i|_i|_i|_dS)N)r(chownsstatsr.paths)r)r(r*r*r+r,s zHardLinkTracker.__init__N)rr4r/r>c Cs|j}||j|<||jvr,|j||n |g|j|<||jvr|\}}|j|\}} |dkrd|}|dkrp| }||g|j|<n ||j|<|dur||j|<dS)zaUsed to add a hard link found during the fixperms run which might be unsafe to operate onr5N)st_inornror1rmr.) r)rr4r/r>inumrrZprev_uidZprev_gidr*r*r+r`s      zHardLinkTracker.addc Cs|jD]\}}|jt|j|krl|j|d}|jj||g|j|R|j|||j |dq |j|D]}|jj dt |qvq dS)zjIf self.hard_links was populated with any items, handle any that are safe, or log any that are notrNz*%s is hardlinked and not owned by the user)rnitemsr_lenror(r9rmrCr.getrr;r)r)rqr4rr*r*r+rWszHardLinkTracker.handle)rdrerfrgr r,r^rrkrjrirr`rWr*r*r*r+rs   rc@sBeZdZdZeeeedfeedffeeefdddZdS)rzFixperms path ruleN)r-r.r/cCs8t||_t|tsJt|ts(J||_||_dS)a,Fixperms path rule Args: regex (str): regular expression file tuple[(int | None), (int | None)]: (file, dir) modes if matched chown tuple[int, int]: if a matching file/dir is found, chown to this UID/GID. Use -1 to make no change. N)r#compiler-rbrjr.r/r2r*r*r+r,s  z Rule.__init__) rdrerfrgr^rjrrir,r*r*r*r+rs  r)rgrZshlexrpathlibrtypingrr4rrrrr#Z fixperms_clir Z fixperms_idsr r rrr*r*r*r+s     ><