o 6­aêsã @s”dZddlmZddlZddlZddlZddlZddlmZzddl Z ddl Z ddl Z ddl Z ddl Z ddlZddlZWn eyGdZYnwdZGdd„dƒZeƒZd ed ed dfd d „Zded efdd„Zdeded ededed df dd„Z dRdedededed df dd„Zd ed ed efdd„Zd ed efdd„Zd ed ed efdd„ZdSd ed ed ed efd!d"„ZdSd ed ed dfd#d$„ZdSd ed ed dfd%d&„Z deded dfd'd(„Z!d ed efd)d*„Z"d+ed efd,d-„Z#d.ed efd/d0„Z$d.ed efd1d2„Z%d3ed4ed efd5d6„Z&d7ed8ed efd9d:„Z'd.ed;ed efdd?„Z)d@dA„Z*dTdBdC„Z+dDdE„Z,dFdG„Z-dHdI„Z.dJdK„Z/dLdM„Z0dNdO„Z1dPdQ„Z2dS)Uz;Compat module to handle files security on Windows and Linuxé)Úabsolute_importN)ÚListTFc@seZdZdZdd„ZdS)Ú _WindowsUmaskz+Store the current umask to apply on WindowscCs d|_dS)Né)Úmask)Úself©rú;/usr/lib/python3/dist-packages/certbot/compat/filesystem.pyÚ__init__s z_WindowsUmask.__init__N)Ú__name__Ú __module__Ú __qualname__Ú__doc__r rrrr rs rÚ file_pathÚmodeÚreturncCs"tr t ||¡dSt||ƒdS)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_MODEÚosÚchmodÚ_apply_win_mode©rrrrr r&srrcCstrt |¡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. )rrÚumaskÚ_WINDOWS_UMASKr)rÚprevious_umaskrrr r;s  rÚsrcÚdstÚ copy_userÚ copy_groupcCsVtrt |¡}|r |jnd}|r|jnd}t |||¡n|r$t||ƒt||ƒdS)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)rrÚstatÚst_uidÚst_gidÚchownÚ_copy_win_ownershipr)rrrrrÚstatsÚuser_idÚgroup_idrrr Úcopy_ownership_and_apply_modeUs  r'cCsdtr$t |¡}|r |jnd}|r|jnd}t |||¡t||jƒdS|r+t||ƒt ||ƒdS)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) rN) rrrr r!r"rÚst_moder#Ú_copy_win_mode)rrrrr$r%r&rrr Úcopy_ownership_and_modevs  r*cCs$tr t t |¡j¡|kSt||ƒ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_IMODErr(Ú_check_win_moderrrr Ú check_modes  r-cCs8tr t |¡jt ¡kSt |tj¡}| ¡}t ƒ|kS)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. ) rrrr ÚgetuidÚ win32securityÚGetFileSecurityÚOWNER_SECURITY_INFORMATIONÚGetSecurityDescriptorOwnerÚ_get_current_user)rÚsecurityÚuserrrr Ú check_owner s  r6cCst|ƒot||ƒ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. )r6r-rrrr Úcheck_permissions³s r7éÿÚflagsc Cs>tr t |||¡S|tj@r’|tj@rtjntj}t  ¡}|j }t ƒ}t ||t jƒ}| |d¡| d|d¡d}zDzt |tjtjtj@||dd¡}Wn)tjyu} z| jtjkrbttj| jƒ‚| jtjkrottj| jƒ‚| ‚d} ~ wwW|r}|  ¡n|r…|  ¡wwt ||tjAtjA¡St ||¡}t!||ƒ|S)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. réN)"rrÚopenÚO_CREATÚO_EXCLÚwin32conÚ CREATE_NEWÚ CREATE_ALWAYSr/ÚSECURITY_ATTRIBUTESÚSECURITY_DESCRIPTORr3Ú_generate_daclrrÚSetSecurityDescriptorOwnerÚSetSecurityDescriptorDaclÚ win32fileÚ CreateFileÚ GENERIC_READÚFILE_SHARE_READÚFILE_SHARE_WRITEÚ pywintypesÚerrorÚwinerrorÚERROR_FILE_EXISTSÚOSErrorÚerrnoÚEEXISTÚstrerrorÚERROR_SHARING_VIOLATIONÚEACCESÚCloser) rr9rÚ dispositionÚ attributesr4r5ÚdaclÚhandleÚerrrrr r;¿sF    þ  €ùý €ÿ ÿ  r;cCsrtdƒ}z/t|d|ABƒtrt ||¡Wt|ƒStj}ztt_t ||¡W|t_Wt|ƒS|t_wt|ƒw)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`` rr8)rrrÚmakedirsÚmkdir)rrÚ current_umaskÚ orig_mkdir_fnrrr r[s   ÷  þ r[c Csžtrt ||¡St ¡}|j}tƒ}t||tj ƒ}|  |d¡|  d|d¡z t   ||¡WdStjyN}z|jtjkrHttj|j||jƒ‚|‚d}~ww)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`` Fr:rN)rrr\r/rArBr3rCrrrDrErFÚCreateDirectoryrKrLrMÚERROR_ALREADY_EXISTSrOrPrQrR)rrrWr4r5rXrZrrr r\$s"  ù €ûr\cCs.ttdƒrttdƒ||ƒdSt ||¡dS)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)ÚhasattrrÚgetattrÚrename)rrrrr raCs racCs´|}ts tjdkrtj |¡}tj |¡rtd |¡ƒ‚|Sg}tj |¡rT|}t  |¡}tj  |¡s>tj  tj  |¡|¡}||vrItd |¡ƒ‚|  |¡tj |¡s&tj |¡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!)rÚsysÚ version_inforÚpathÚrealpathÚislinkÚ RuntimeErrorÚformatÚreadlinkÚisabsÚjoinÚdirnameÚappendÚabspath)rÚ original_pathriÚinspected_pathsÚ link_pathrrr rjTs"        ù rjrvcCs<t |¡}ts | d¡s|St|ƒdkr|dd…Stdƒ‚)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\\?\iéNz3Long paths are not supported by Certbot on Windows.)rrnrÚ startswithÚlenÚ ValueError)rvrirrr rnvs  rnricCs&trtj |¡ot |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 )rrriÚisfileÚaccessÚX_OKÚ_win_is_executable)rirrr Ú is_executable˜srcCsVtrtt t |¡j¡tj@ƒSt |tj ¡}|  ¡}t|  tj tj t d¡dœ¡ƒS)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)rÚboolrr+rr(ÚS_IRWXOr/r0ÚDACL_SECURITY_INFORMATIONÚGetSecurityDescriptorDaclÚGetEffectiveRightsFromAclÚTRUSTEE_IS_SIDÚTRUSTEE_IS_USERÚConvertStringSidToSid)rir4rXrrr Úhas_world_permissions¦s ýrÚold_keyÚ base_modecCs:trt t |¡j¡tjtjBtjBtjB@}||BS|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 ) rrr+rr(ÚS_IRGRPÚS_IWGRPÚS_IXGRPÚS_IROTH)rŽrÚold_moderrr Úcompute_private_key_mode»s  ÿr•Úpath1Úpath2cCsdtrt |¡}t |¡}|j|jf|j|jfkSt |tj¡}| ¡}t |tj¡}| ¡}||kS)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 ) rrrr r!r/r0r1r2)r–r—Ústats1Ústats2Ú security1Úuser1Ú security2Úuser2rrr Úhas_same_ownershipÐs  ržÚmin_modec Csªtrt |¡j}|||BkSt|ƒ}t |tjtjB¡}|  ¡}|  ¡}t ||ƒ}t |  ¡ƒD]#}| |¡}|d} |d}| tjtj|dœ¡} | | | BkrRdSq/dS)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 r:érFT)rrrr(rjr/r0r1r‡r2rˆrCÚrangeÚ GetAceCountÚGetAcer‰rŠr‹) rirŸr(r4r5rXÚmin_daclÚindexÚmin_acerÚeffective_maskrrr Úhas_min_permissionsés.   ÿ  ý ÿr¨cCsNtj |¡sdSt |tj¡}| ¡}| tjtj t ƒdœ¡}|t j @t j kS)NFr) rrir{r/r0r‡rˆr‰rŠr‹r3Ú ntsecurityconÚFILE_GENERIC_EXECUTE)rir4rXrrrr r~s ýr~cCsJt|ƒ}t |tj¡}| ¡}t||ƒ}| d|d¡t |tj|¡dS)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. r:rN) rjr/r0r1r2rCrEÚSetFileSecurityr‡)rrr4r5rXrrr r&s  rc Cs¾|r|d|@}t|ƒ}t d¡}t d¡}t d¡}t ¡}|||fvr5t|dƒ}|r5| tj||¡t|dƒ} | rE| tj| |¡tddddœƒ} | tj| |¡| tj| |¡|S) Nr8zS-1-5-18z S-1-5-32-544r€r5ÚallT©ÚreadÚwriteÚexecute)Ú _analyze_moder/rŒÚACLÚ_generate_windows_flagsÚAddAccessAllowedAceÚ ACL_REVISION) Úuser_sidrrÚanalysisÚsystemÚadminsÚeveryonerXÚ user_flagsÚeverybody_flagsÚfull_permissionsrrr rC9s$       rCcCs>|tj@|tj@|tj@dœ|tj@|tj@|tj@dœdœS)Nr­)r5r¬)rÚS_IRUSRÚS_IWUSRÚS_IXUSRr“ÚS_IWOTHÚS_IXOTH)rrrr r±]sýýúr±cCsLt|ƒ}t |tj¡}| ¡}t |tj¡}| |d¡t |tj|¡dS©NF)rjr/r0r1r2rDr«)rrÚ security_srcÚuser_srcÚ security_dstrrr r#ls  r#cCsNt|ƒ}t |tj¡}| ¡}t |tj¡}| d|d¡t |tj|¡dS)Nr:r)rjr/r0r‡rˆrEr«)rrrÄrXrÆrrr r){s r)cCsJd}|dr |tjB}|dr|tjtjAtjAB}|dr#|tjB}|S)Nrr®r¯r°)r©ÚFILE_GENERIC_READÚFILE_ALL_ACCESSrª)Ú rights_descÚflagrrr r³ˆs ÿþ r³cCsHt|ƒ}t |tjtjB¡}| ¡}| ¡}|sdSt||ƒ}t||ƒSrÃ) rjr/r0r1r‡rˆr2rCÚ_compare_dacls)rrr4rXr5Úref_daclrrr r,§s ÿ  r,cs4‡fdd„tˆ ¡ƒDƒ‡fdd„tˆ ¡ƒDƒkS)z¥ This method compare the two given DACLs to check if they are identical. Identical means here that they contains the same set of ACEs in the same order. cóg|]}ˆ |¡‘qSr©r£©Ú.0r¥)Údacl1rr Ú Âóz"_compare_dacls..crÍrrÎrÏ)Údacl2rr rÒÃrÓ)r¡r¢©rÑrÔrrÕr r˽sÿrËcCs$d t ¡t ¡¡}t d|¡dS)z= Return the pySID corresponding to the current user. z{0}\{1}Nr)rmÚwin32apiÚ GetDomainNameÚ GetUserNamer/ÚLookupAccountName)Ú account_namerrr r3Æsr3)TT)r8)N)3rÚ __future__rrPrrrgÚtypingrr©r/r>rÖrFrKrMÚ ImportErrorrrrÚstrÚintrrr…r'r*r-r6r7r;r[r\rarjrnrrr•ržr¨r~rrCr±r#r)r³r,rËr3rrrr Ús|    ÿÿÿ ÿ" ÿÿÿ ÿ E ""- $