U
    ÓZj9_  ã                   @   s`  d Z ddlmZ ddlZddlZddlZz<ddlZddlZddlZddl	Z	ddl
Z
ddlZddlZW n ek
r|   dZY nX dZddlmZmZmZ dd„ Zd	d
„ Zdd„ Zdd„ Zdd„ Zd8dd„Zd9dd„Zd:dd„Zdd„ Zdd„ Zdd„ Zdd„ Zd d!„ Zd"d#„ Z d$d%„ Z!d&d'„ Z"d(d)„ Z#d*d+„ Z$d,d-„ Z%d.d/„ Z&d0d1„ Z'd2d3„ Z(d4d5„ Z)d6d7„ Z*dS );z;Compat module to handle files security on Windows and Linuxé    )Úabsolute_importNTF)ÚListÚUnionÚTuplec                 C   s    t rt | |¡ n
t| |ƒ dS )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©Ú	file_pathÚmode© r   ú\/var/www/html/TRUCKING_PROJECT/venv/lib/python3.8/site-packages/certbot/compat/filesystem.pyr      s    r   c                 C   sV   t r:t | ¡}|r|jnd}|r&|jnd}t |||¡ n|rHt| |ƒ t||ƒ dS )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)r   r   ÚstatÚst_uidÚst_gidÚchownÚ_copy_win_ownershipr   )ÚsrcÚdstr   Z	copy_userZ
copy_groupÚstatsZuser_idZgroup_idr   r   r   Úcopy_ownership_and_apply_mode8   s    

r   c                 C   s$   t rt t | ¡j¡|kS t| |ƒS )a`  
    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
    )r   r   ÚS_IMODEr   Úst_modeÚ_check_win_moder
   r   r   r   Ú
check_modeP   s    r   c                 C   s8   t rt | ¡jt ¡ kS t | t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.
    )
r   r   r   r   ÚgetuidÚwin32securityÚGetFileSecurityÚOWNER_SECURITY_INFORMATIONÚGetSecurityDescriptorOwnerÚ_get_current_user)r   ÚsecurityÚuserr   r   r   Úcheck_ownera   s
    r%   c                 C   s   t | ƒo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.
    )r%   r   r
   r   r   r   Úcheck_permissionst   s    	r&   éÿ  c           
   
   C   s:  t rt | ||¡S |tj@ �r |tj@ r.tjntj}t 	¡ }|j
}tƒ }t||ƒ}| |d¡ | d|d¡ d}z†z$t | tjtjtj@ ||dd¡}W n\ tjk
rò }	 z<|	jtjkrÄttj|	jƒ‚|	jtjkrÞttj|	jƒ‚|	‚W 5 d}	~	X Y nX W 5 |�r| ¡  X t | |tjA tjA ¡S t | |¡}t| |ƒ |S )az  
    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) r   r   ÚopenÚO_CREATÚO_EXCLÚwin32conZ
CREATE_NEWZCREATE_ALWAYSr   ÚSECURITY_ATTRIBUTESÚSECURITY_DESCRIPTORr"   Ú_generate_daclÚSetSecurityDescriptorOwnerÚSetSecurityDescriptorDaclÚCloseÚ	win32fileZ
CreateFileZGENERIC_READZFILE_SHARE_READZFILE_SHARE_WRITEÚ
pywintypesÚerrorÚwinerrorZERROR_FILE_EXISTSÚOSErrorÚerrnoÚEEXISTÚstrerrorZERROR_SHARING_VIOLATIONÚEACCESr   )
r   Úflagsr   ZdispositionÚ
attributesr#   r$   ÚdaclÚhandleÚerrr   r   r   r)   €   s>    


   þ

r)   c                 C   s:   t rt | |¡S tj}ztt_t | |¡W ¢S |t_X dS )a3  
    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``
    N)r   r   ÚmakedirsÚmkdir)r   r   Zorig_mkdir_fnr   r   r   rA   Å   s    	rA   c              
   C   s¦   t rt | |¡S t ¡ }|j}tƒ }t||ƒ}| |d¡ | 	d|d¡ zt
 | |¡ W nH tjk
r  } z(|jtjkrŒttj|j| |jƒ‚|‚W 5 d}~X Y nX dS )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(   r   N)r   r   rB   r   r-   r.   r"   r/   r0   r1   r3   ZCreateDirectoryr4   r5   r6   ZERROR_ALREADY_EXISTSr7   r8   r9   r:   )r   r   r=   r#   r$   r>   r@   r   r   r   rB   Û   s    	
rB   c                 C   s,   t tdƒrttdƒ| |ƒ nt | |¡ dS )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)r   r   r   r   r   rC   ú   s    
rC   c                 C   s    | }t r2tj | ¡}tj |¡r.td |¡ƒ‚|S g }tj | ¡r”| }t | ¡} tj | ¡srtj 	tj 
|¡| ¡} | |krˆtd |¡ƒ‚| | ¡ q6tj | ¡S )z²
    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.
    zError, link {0} is a loop!)r   r   ÚpathÚrealpathÚislinkÚRuntimeErrorÚformatÚreadlinkÚisabsÚjoinÚdirnameÚappendÚabspath)r   Zoriginal_pathrG   Zinspected_pathsÚ	link_pathr   r   r   rH   
  s     
rH   c                 C   s&   t rtj | ¡ot | tj¡S t| ƒS )zˆ
    Is path an executable file?
    :param str path: path to test
    :return: True if path is an executable file
    :rtype: bool
    )r   r   rG   ÚisfileÚaccessÚX_OKÚ_win_is_executable)rG   r   r   r   Úis_executable/  s    rW   c                 C   sV   t r tt t | ¡j¡tj@ ƒS t | tj	¡}| 
¡ }t| tjtj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©ZTrusteeFormZTrusteeTypeZ
Identifier)r   Úboolr   r   r   r   ÚS_IRWXOr   r   ÚDACL_SECURITY_INFORMATIONÚGetSecurityDescriptorDaclÚGetEffectiveRightsFromAclÚTRUSTEE_IS_SIDÚTRUSTEE_IS_USERÚConvertStringSidToSid)rG   r#   r>   r   r   r   Úhas_world_permissions=  s    ýrb   c                 C   s:   t r6t t | ¡j¡tjtjB tjB tjB @ }||B S |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
    )	r   r   r   r   r   ÚS_IRGRPÚS_IWGRPÚS_IXGRPÚS_IROTH)Úold_keyZ	base_modeZold_moder   r   r   Úcompute_private_key_modeR  s    	ÿrh   c                 C   sd   t r0t | ¡}t |¡}|j|jf|j|jfkS t | tj¡}| ¡ }t |tj¡}| ¡ }||kS )ar  
    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

    )	r   r   r   r   r   r   r   r    r!   )Zpath1Zpath2Zstats1Zstats2Z	security1Zuser1Z	security2Zuser2r   r   r   Úhas_same_ownershipg  s    

ri   c                 C   sª   t rt | ¡j}|||B kS t| ƒ} t | tjtjB ¡}| 	¡ }| 
¡ }t||ƒ}t| ¡ ƒD ]F}| |¡}|d }	|d }| tjtj|dœ¡}
|
|
|	B kr^ dS q^dS )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(   é   rY   FT)r   r   r   r   rH   r   r   r    r\   r!   r]   r/   ÚrangeÚGetAceCountÚGetAcer^   r_   r`   )rG   Zmin_moder   r#   r$   r>   Zmin_daclÚindexZmin_aceÚmaskZeffective_maskr   r   r   Úhas_min_permissions€  s.    
 
ÿ

ýrp   c                 C   sN   t j | ¡sdS t | tj¡}| ¡ }| tjtj	t
ƒ dœ¡}|tj@ tjkS )NFrY   )r   rG   rS   r   r   r\   r]   r^   r_   r`   r"   ÚntsecurityconÚFILE_GENERIC_EXECUTE)rG   r#   r>   r   r   r   r   rV   ­  s    ýrV   c                 C   sJ   t | ƒ} t | tj¡}| ¡ }t||ƒ}| d|d¡ t | tj|¡ dS )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(   r   N)	rH   r   r   r    r!   r/   r1   ÚSetFileSecurityr\   )r   r   r#   r$   r>   r   r   r   r	   ½  s    
r	   c           
      C   s®   t |ƒ}t d¡}t d¡}t d¡}t ¡ }| ||fkrZt|d ƒ}|rZ| tj|| ¡ t|d ƒ}|rz| tj||¡ tddddœƒ}	| tj|	|¡ | tj|	|¡ |S )NzS-1-5-18zS-1-5-32-544rX   r$   ÚallT©ÚreadÚwriteÚexecute)Ú_analyze_moder   ra   ZACLÚ_generate_windows_flagsZAddAccessAllowedAceZACL_REVISION)
Zuser_sidr   ZanalysisÚsystemZadminsZeveryoner>   Z
user_flagsZeverybody_flagsZfull_permissionsr   r   r   r/   Ð  s     


r/   c                 C   s>   | t j@ | t j@ | t j@ dœ| t j@ | t j@ | t j@ dœdœS )Nru   )r$   rt   )r   ÚS_IRUSRÚS_IWUSRÚS_IXUSRrf   ÚS_IWOTHÚS_IXOTH)r   r   r   r   ry   ò  s    ýýúry   c                 C   sD   t  | t j¡}| ¡ }t  |t j¡}| |d¡ t  |t j|¡ d S ©NF)r   r   r    r!   r0   rs   )r   r   Zsecurity_srcZuser_srcZsecurity_dstr   r   r   r     s
    r   c                 C   sJ   d}| d r|t jB }| d r4|t jt jA t jA B }| d rF|t jB }|S )Nr   rv   rw   rx   )rq   ZFILE_GENERIC_READZFILE_ALL_ACCESSrr   )Zrights_descÚflagr   r   r   rz     s    
ÿþ
rz   c                 C   sH   t | ƒ} t | tjtjB ¡}| ¡ }| ¡ }|s4dS t||ƒ}t||ƒS r�   )	rH   r   r   r    r\   r]   r!   r/   Ú_compare_dacls)r   r   r#   r>   r$   Zref_daclr   r   r   r   ,  s    
ÿ
r   c                    s4   ‡ fdd„t ˆ  ¡ ƒD ƒ‡fdd„t ˆ ¡ ƒD ƒkS )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                    s   g | ]}ˆ   |¡‘qS r   ©rm   ©Ú.0rn   )Údacl1r   r   Ú
<listcomp>G  s     z"_compare_dacls.<locals>.<listcomp>c                    s   g | ]}ˆ   |¡‘qS r   r„   r…   )Údacl2r   r   rˆ   H  s     )rk   rl   ©r‡   r‰   r   rŠ   r   rƒ   B  s    ÿrƒ   c                  C   s   t  t j¡} t d| ¡d S )z=
    Return the pySID corresponding to the current user.
    Nr   )Úwin32apiZGetUserNameExZNameSamCompatibler   ZLookupAccountName)Zaccount_namer   r   r   r"   K  s    r"   )r'   )r'   )r'   )+Ú__doc__Ú
__future__r   r8   r   r   rq   r   r,   r‹   r3   r4   r6   ÚImportErrorr   Zacme.magic_typingr   r   r   r   r   r   r%   r&   r)   rA   rB   rC   rH   rW   rb   rh   ri   rp   rV   r	   r/   ry   r   rz   r   rƒ   r"   r   r   r   r   Ú<module>   sP   

E

%-"	