M/ew hdZddlmZddlmZddlZddlZddlZddlZddl m Z ddl m Z ddl m Z ddl m Z dd l mZ ddlZddlZddlZddlZddlZddlZddlZd ZGd d ZeZdededdfdZdedefdZedede dfdZdedededededdf dZ d@dededededdf dZ!dededefdZ"dedefdZ#dededefdZ$dAdedededefd Z%dAdededdfd!Z&dAdededdfd"Z'dededdfd#Z(dedefd$Z)d%edefd&Z*d'edefd(Z+d'edefd)Z,d*ed+edefd,Z-d-ed.edefd/Z.d'ed0edefd1Z/d'edefd2Z0dededdfd3Z1dBd4e dedeede fd5Z2dede ee eefffd6Z3dededdfd7Z4dededdfd8Z5d9e eefdefd:Z6dededefd;Z7dZ8de fd?Z9y#e$rd ZYTwxYw)Cz;Compat module to handle files security on Windows and Linux)absolute_import)contextmanagerN)Any)Dict) Generator)List)OptionalFTceZdZdZddZy) _WindowsUmaskz+Store the current umask to apply on WindowsNcd|_y)N)mask)selfs ;/usr/lib/python3/dist-packages/certbot/compat/filesystem.py__init__z_WindowsUmask.__init__$s  )returnN)__name__ __module__ __qualname____doc__rrrr r "s 5rr file_pathmodercVtrtj||yt||y)a[ Apply a POSIX mode on given file_path: - for Linux, the POSIX mode will be directly applied using chmod, - for Windows, the POSIX mode will be translated into a Windows DACL that make sense for Certbot context, and applied to the file using kernel calls. The definition of the Windows DACL that correspond to a POSIX mode, in the context of Certbot, is explained at https://github.com/certbot/certbot/issues/6356 and is implemented by the method `_generate_windows_flags()`. :param str file_path: Path of the file :param int mode: POSIX mode to apply N) POSIX_MODEoschmod_apply_win_moderrs rrr+s D! 4(rrcrtrtj|Stj}|t_|S)a$ Set the current numeric umask and return the previous umask. On Linux, the built-in umask method is used. On Windows, our Certbot-side implementation is used. :param int mask: The user file-creation mode mask to apply. :rtype: int :return: The previous umask value. )rrumask_WINDOWS_UMASKr)rprevious_umasks rr"r"@s.xx~#((NN r)NNNc#rKd} t|}d| t|yy#| t|wwxYww)z Apply a umask temporarily, meant to be used in a `with` block. Uses the Certbot implementation of umask. :param int mask: The user file-creation mode mask to apply temporarily N)r")r old_umasks r temp_umaskr'QsF $I$K   )  !9 )  !s7$747srcdst copy_user copy_groupctrMtj|}|r |jnd}|r |jnd}tj |||n|r t ||t||y)a Copy ownership (user and optionally group on Linux) from the source to the destination, then apply given mode in compatible way for Linux and Windows. This replaces the os.chown command. :param str src: Path of the source file :param str dst: Path of the destination file :param int mode: Permission mode to apply on the destination file :param bool copy_user: Copy user if `True` :param bool copy_group: Copy group if `True` on Linux (has no effect on Windows) N)rrstatst_uidst_gidchown_copy_win_ownershipr)r(r)rr*r+statsuser_idgroup_ids rcopy_ownership_and_apply_moder6ksW "+%,,#-5<<2 gx( C% #trc trctj|}|r |jnd}|r |jnd}tj |||t ||jy|r t||t||y)aU Copy ownership (user and optionally group on Linux) and mode/DACL from the source to the destination. :param str src: Path of the source file :param str dst: Path of the destination file :param bool copy_user: Copy user if `True` :param bool copy_group: Copy group if `True` on Linux (has no effect on Windows) r-N) rrr.r/r0r1rst_moder2_copy_win_mode)r(r)r*r+r3r4r5s rcopy_ownership_and_moder:sc "+%,,#-5<<2 gx( c5==!  S )sC rctr5tjtj|j|k(St ||S)aa Check if the given mode matches the permissions of the given file. On Linux, will make a direct comparison, on Windows, mode will be compared against the security model. :param str file_path: Path of the file :param int mode: POSIX mode to test :rtype: bool :return: True if the POSIX mode matches the file permissions )rr.S_IMODErr8_check_win_moder s r check_moder>s7||BGGI.6674?? 9d ++rctr4tj|jtjk(St j |t j}|j}t|k(S)z Check if given file is owned by current user. :param str file_path: File path to check :rtype: bool :return: True if given file is owned by current user, False otherwise. ) rrr.r/getuid win32securityGetFileSecurityOWNER_SECURITY_INFORMATIONGetSecurityDescriptorOwner_get_current_user)rsecurityusers r check_ownerrHs_wwy!((BIIK77,,Y 8`8`aH  . . 0D  $ &&rc4t|xr t||S)z Check if given file has the given mode and is owned by current user. :param str file_path: File path to check :param int mode: POSIX mode to check :rtype: bool :return: True if file has correct mode and owner, False otherwise. )rHr>r s rcheck_permissionsrJs y ! AjD&AArflagsc trtj|||S|tjzr4|tjzrt j nt j}tj}|j}t}t||tj}|j|d|j!d|dd} t#j$|t"j&t"j(t"j*z||dd} |r|jA tj||tjz tjz Stj||} tC||| S#t,j.$r} | j0t0j2k(r$t5t6j8| j:| j0t0j<k(r$t5t6j>| j:| d} ~ wwxYw#|r|jAwwxYw)aw Wrapper of original os.open function, that will ensure on Windows that given mode is correctly applied. :param str file_path: The file path to open :param int flags: Flags to apply on file while opened :param int mode: POSIX mode to apply on file when opened, Python defaults will be applied if ``None`` :returns: the file descriptor to the opened file :rtype: int :raise: OSError(errno.EEXIST) if the file already exists and os.O_CREAT & os.O_EXCL are set, OSError(errno.EACCES) on Windows if the file already exists and is a directory, and os.O_CREAT is set. rN)"rropenO_CREATO_EXCLwin32con CREATE_NEW CREATE_ALWAYSrASECURITY_ATTRIBUTESSECURITY_DESCRIPTORrE_generate_daclr#rSetSecurityDescriptorOwnerSetSecurityDescriptorDacl win32file CreateFile GENERIC_READFILE_SHARE_READFILE_SHARE_WRITE pywintypeserrorwinerrorERROR_FILE_EXISTSOSErrorerrnoEEXISTstrerrorERROR_SHARING_VIOLATIONEACCESCloser) rrKr disposition attributesrFrGdaclhandleerrfds rrNrNswwy%.. rzz.3RYY->h))HDZDZ "668 11 "dD.*=*=> ++D!4 **1dA6 )))Y5K5K*3*C*CiF`F`*`*4k1dLF  wwy%"**"4ryy"@AA E "B )T I) ||x999ellCLL99||x???ellCLL99I  s&AF H&BH!!H&&H))H>cbtd} t|d|z ztr!tj||t|Stj} tt_tj|||t_t|S#|t_wxYw#t|wxYw)a4 Rewrite of original os.makedirs function, that will ensure on Windows that given mode is correctly applied. :param str file_path: The file path to open :param int mode: POSIX mode to apply on leaf directory when created, Python defaults will be applied if ``None`` r)r"rrmakedirsmkdir)rr current_umask orig_mkdir_fns rrqrqs!HM medl*+ ;;y$/ m  %BH;;y$/$BH m%BH ms),B!B!$B: B! BB!! B.ctrtj||Stj}|j }t }t||tj}|j|d|jd|d tj||y#tj$rT}|j t j"k(r0t%t&j(|j*||j |d}~wwxYw)a, Rewrite of original os.mkdir function, that will ensure on Windows that given mode is correctly applied. :param str file_path: The file path to open :param int mode: POSIX mode to apply on directory when created, Python defaults will be applied if ``None`` FrMrN)rrrrrArTrUrErVr#rrWrXrYCreateDirectoryr^r_r`ERROR_ALREADY_EXISTSrbrcrdre)rrrjrFrGrkrms rrrrr:sxx 4((224J--H  D $n&9&9 :D ''e4 &&q$2!!)Z8     <<888 8%,, iN N sBD2ADDcttdrttd||ytj||y)z Rename a file to a destination path and handles situations where the destination exists. :param str src: The current file path. :param str dst: The new file path. replaceN)hasattrrgetattrrename)r(r)s rryryYs3r9 IsC( #src|}tstjdk\rZtjj |}tjj |rtdj||Sg}tjj |r|}tj|}tjj|s=tjjtjj||}||vrtdj||j|tjj |rtjj|S)a  Find the real path for the given path. This method resolves symlinks, including recursive symlinks, and is protected against symlinks that creates an infinite loop. :param str file_path: The path to resolve :returns: The real path for the given path :rtype: str )zError, link {0} is a loop!)rsys version_inforpathrealpathislink RuntimeErrorformatreadlinkisabsjoindirnameappendabspath)r original_pathrinspected_paths link_paths rrrjs MS%%/ww * 77>>$ ;BB=QR R !#O ''.. # KK * ww}}Y' RWW__Y%?KI  ';BB=QR Ry) ''.. # 77??9 %%rrctj|}ts|jds|St |dkr|ddSt d)a Return a string representing the path to which the symbolic link points. :param str link_path: The symlink path to resolve :return: The path the symlink points to :returns: str :raise: ValueError if a long path (260> characters) is encountered on Windows z\\?\iNz3Long paths are not supported by Certbot on Windows.)rrr startswithlen ValueError)rrs rrrsI ;;y !D3  4y3ABx J KKrrctrEtjj|xr$tj|tj St |S)z Is path an executable file? :param str path: path to test :return: True if path is an executable file :rtype: bool )rrrisfileaccessX_OK_win_is_executable)rs r is_executablers9ww~~d#@ $(@@ d ##rc trLttjt j|j tj zStj|tj}|j}t|jtjtjtjddS)z Check if everybody/world has any right (read/write/execute) on a file given its path. :param str path: path to test :return: True if everybody/world has any right to the file :rtype: bool S-1-1-0 TrusteeForm TrusteeType Identifier)rboolr.r<rr8S_IRWXOrArBDACL_SECURITY_INFORMATIONGetSecurityDescriptorDaclGetEffectiveRightsFromAclTRUSTEE_IS_SIDTRUSTEE_IS_USERConvertStringSidToSid)rrFrks rhas_world_permissionsrsDLL!6!67$,,FGG,,T=3Z3Z[H  - - /D ..$33$44#99)D0 rold_key base_modectr{tjtj|jtj tj ztjztjzz}||zS|S)a Calculate the POSIX mode to apply to a private key given the previous private key. :param str old_key: path to the previous private key :param int base_mode: the minimum modes to apply to a private key :return: the POSIX mode to apply :rtype: int ) rr.r<rr8S_IRGRPS_IWGRPS_IXGRPS_IROTH)rrold_modes rcompute_private_key_modersaLL!1!9!9:\\DLL04<<?$,,NP8## rpath1path2ctr[tj|}tj|}|j|jf|j|jfk(St j |t j}|j}t j |t j}|j}||k(S)as Return True if the ownership of two files given their respective path is the same. On Windows, ownership is checked against owner only, since files do not have a group owner. :param str path1: path to the first file :param str path2: path to the second file :return: True if both files have the same ownership, False otherwise :rtype: bool ) rrr.r/r0rArBrCrD)rrstats1stats2 security1user1 security2user2s rhas_same_ownershiprs v}}-&--1OOO--e]5]5]^I  0 0 2E--e]5]5]^I  0 0 2E E>rmin_modectr'tj|j}|||zk(St |}t j |t jt jz}|j}|j}t||}t|jD]X}|j|}|d} |d}|jt j t j"|d} | | | zk7sXyy)a Check if a file given its path has at least the permissions defined by the given minimal mode. On Windows, group permissions are ignored since files do not have a group owner. :param str path: path to the file to check :param int min_mode: the minimal permissions expected :return: True if the file matches the minimal permissions expectations, False otherwise :rtype: bool rMrFT)rrr.r8rrArBrCrrDrrVrange GetAceCountGetAcerrr) rrr8rFrGrkmin_daclindexmin_acereffective_masks rhas_min_permissionsrs''$-'''H,,, D>D,, m669`9``bH  . . 0D  - - /DdH-Hx++-.//%(qzqz77(77(889   ^d2 2" rcdtjj|sytj|tj }|j }|jtjtjtd}|tjztjk(S)NFr) rrrrArBrrrrrrE ntsecurityconFILE_GENERIC_EXECUTE)rrFrkrs rrr,s 77>>$ ,,T=3Z3Z[H  - - /D  ) )$33$44')+ D -44 4 8Z8Z ZZrc t|}tj|tj}|j }t ||}|j d|dtj|tj|y)z This function converts the given POSIX mode into a Windows ACL list, and applies it to the file given its path. If the given path is a symbolic link, it will resolved to apply the mode on the targeted file. rMrN) rrArBrCrDrVrXSetFileSecurityr)rrrFrGrks rrr<so #I,,Y 8`8`aH  . . 0D $ %D &&q$2!!)]-T-TV^_ruser_sidcH|r|d|z z}t|}tjd}tjd}tjd}tj}|||fvr1t |d}|r!|j tj ||t |d} | r!|j tj | |t dddd} |j tj | ||j tj | ||S) NrpzS-1-5-18z S-1-5-32-544rrGallTreadwriteexecute) _analyze_moderArACL_generate_windows_flagsAddAccessAllowedAce ACL_REVISION) rrranalysissystemadminseveryonerk user_flagseverybody_flagsfull_permissionss rrVrVOs ut|$T"H  0 0   $ $]%?%?X V.huo>O   !;!;_hW/tX\/]^]779I6R]779I6R Krc|tjz|tjz|tjzd|tjz|tj z|tj zddS)Nr)rGr)r.S_IRUSRS_IWUSRS_IXUSRrS_IWOTHS_IXOTH)rs rrrssb4<<'DLL(dll* 4<<'DLL(dll*  rc8t|}tj|tj}|j }tj|tj}|j |dtj |tj|yNF)rrArBrCrDrWr)r(r) security_srcuser_src security_dsts rr2r2st 3-C 00m6^6^_L668H 00m6^6^_L++He<!!#}'O'OQ]^rc:t|}tj|tj}|j }tj|tj}|j d|dtj |tj|y)NrMr)rrArBrrrXr)r(r)rrkrs rr9r9sv 3-C!00m6]6]^L  1 1 3D 00m6]6]^L**1dA6!!#}'N'NP\]r rights_desccd}|dr|tjz}|dr5|tjtjz tjz z}|dr|tjz}|S)Nrrrr)rFILE_GENERIC_READFILE_ALL_ACCESSr)rflags rrrsv$ D6m5557}44&889&;;<=9m888 Krct|}tj|tjtjz}|j }|j }|syt||}t||Sr) rrArBrCrrrDrV_compare_dacls)rrrFrkrGref_dacls rr=r=sw#I,,Y 8`8`/q AAr)TT)rp)N):r __future__r contextlibrrcrr.rtypingrrrrr rr^rrQrYrAr`r ImportErrorr r#strintrr"r'rr6r:r>rHrJrNrqrrryrrrrrrrrrrVrr2r9rr=rrErrrrsA&%  J )S)))*" S Y'78  2sC-1?CHLDHL!!3!'+!@D!PT!2,#,S,T,"'3'4'& B BC BD BBCBB3B3BJ34@S>34"&&&DLLLD $ $ $*ccc*c#$2*c*S*T*Z [S [T [ `s`#`$`&!S!!8C=!C!H  S$sCx.%8 9  _S _s _t _ ^ ^# ^$ ^c3hC>*s*#*$*,K#KcKdKB3BKJsF&&F10F1