o
    iZW                     @   sx  U d dl Z d dlmZ d dlmZ d dlZd dlZd dlZd dlmZ d dlm	Z	 d dlm
Z
 d dlmZ d dlmZ d d	lmZ d d
lmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlm Z  ee!Z"e#de$ej%ddd&dd de'fddZ(de$e'e'f fddZ)i Z*e$e'e	e'gdf f e+d< i Z,e$e'e	ee-e' e'f gdf f e+d< de'd e	e'gdf fd!d"Z.de'fd#d$Z/de'd e	ee-e' e'f gdf fd%d&Z0de'fd'd(Z1d)d* Z2de-e' fd+d,Z3ed-d.G d/d0 d0Z4G d1d2 d2Z5d?d3d4Z6ej7d5d6 Z8ej7d7d8 Z9ej7d9d: Z:ej7d;d< Z;ej7d=d> Z<dS )@    N)	dataclass)fnmatch)join)Callable)Optional)Union)cast)Pin)trace_utils)COMMANDS)	SpanTypes)core)
get_logger)config)RLock)tracer
subprocess!DD_SUBPROCESS_SENSITIVE_WILDCARDS )default,)sensitive_wildcardsreturnc                   C   s   dS )z6Get the version string for the subprocess integration.r    r   r   r   ]/home/ubuntu/.local/lib/python3.10/site-packages/ddtrace/contrib/internal/subprocess/patch.pyget_version!   s   r   c                   C   s   ddiS )Nr   *r   r   r   r   r   _supported_versions&   s   r   _STR_CALLBACKS_LST_CALLBACKSnamecallbackc                 C      |t | < dS )zAdd a callback function for string commands.

    Args:
        name: Unique identifier for the callback
        callback: Function that will be called with string command arguments
    N)r   r    r!   r   r   r   add_str_callback.      r$   c                 C      t | d dS )zdRemove a string command callback.

    Args:
        name: Identifier of the callback to remove
    N)r   popr    r   r   r   del_str_callback8      r)   c                 C   r"   )zAdd a callback function for list commands.

    Args:
        name: Unique identifier for the callback
        callback: Function that will be called with list/tuple command arguments
    N)r   r#   r   r   r   add_lst_callbackA   r%   r+   c                 C   r&   )zbRemove a list command callback.

    Args:
        name: Identifier of the callback to remove
    N)r   r'   r(   r   r   r   del_lst_callbackK   r*   r,   c                   C   s   t j ot jS )N)
asm_config_bypass_instrumentation_for_waf_asm_enabledr   r   r   r   should_trace_subprocessT   s   r0   c            	      C   s:  g } t js| S ddl}ddl}t|j }t|dr"t|j nd}t	|dd}|duo3t| }|s:|s:|rft
 | |rKt|dt| |rVt|dt| |rat|dt| | d t|jj }t|jj }|sz|rt
 | |rt|dt| |rt|d	t| | d
 | S )at  Patch subprocess and os functions to enable security monitoring.

    This function instruments various subprocess and os functions to provide
    security monitoring capabilities for AAP (Application Attack Protection).

    Note:
        Patching always occurs because AAP can be enabled dynamically via remote config.
        Already patched functions are skipped.
    r   NforkF	_spawnvefsystemoszPopen.__init__z
Popen.waitr   )r-   _load_modulesr4   r   r
   	iswrappedr3   hasattrr1   getattrr	   ontowrap_traced_ossystem_traced_fork_traced_osspawnappendPopen__init__wait_traced_subprocess_init_traced_subprocess_wait)	patchedr4   r   should_patch_systemshould_patch_forkspawnvefshould_patch_spawnvefshould_patch_Popen_initshould_patch_Popen_waitr   r   r   patchX   s8   


rK   F)eqc                   @   sn   e Zd ZU dZdZee ed< dZee	 ed< dZ
eed< dZee	 ed< dZee	 ed< dZee ed	< dS )
SubprocessCmdLineCacheEntryzCache entry for storing parsed subprocess command line data.

    This class stores the parsed and processed command line arguments,
    environment variables, and metadata to avoid recomputing the same
    command line parsing multiple times.
    Nbinary	argumentsF	truncatedenv_varsas_list	as_string)__name__
__module____qualname____doc__rN   r   str__annotations__rO   listrP   boolrQ   rR   rS   r   r   r   r   rM      s   
 rM   c                   @   s   e Zd ZU dZi Zeeef ed< e	
 Ze	j
e ed< dZe Zedd Zedd Zd	Zh d
ZdhZg dZedZd"deeee f deddfddZdd Zdd ZdedefddZde ee ef fddZ!dd Z"d d! Z#dS )#SubprocessCmdLinea  Parser and scrubber for subprocess command lines.

    This class handles parsing, scrubbing, and caching of subprocess command lines
    for security monitoring. It supports both shell and non-shell commands,
    scrubs sensitive information, and provides caching for performance.
    _CACHE_CACHE_DEQUE    c                 C   s   || j v rdS t }||_||_||_||_| j* t| j| j	kr0| jd }| j |= | j
  || j |< | j| W d   |S 1 sFw   Y  |S )z*Add a new entry to the command line cache.N)r]   rM   rN   rO   rP   rQ   _CACHE_LOCKlenr^   _CACHE_MAXSIZEr'   
appendleft)clskeyrQ   rN   rO   rP   cache_entrylast_cache_keyr   r   r   _add_new_cache_entry   s$   






z&SubprocessCmdLine._add_new_cache_entryc                 C   s@   | j  | j  | j  W d   dS 1 sw   Y  dS )z|Clear all entries from the command line cache.

        Thread-safe method to completely clear the cache and deque.
        N)ra   r^   clearr]   )re   r   r   r   _clear_cache   s   
"zSubprocessCmdLine._clear_cachei   >   PATH
LD_PRELOADLD_LIBRARY_PATHmd5)
z
*password*z*passwd*z*mysql_pwd*z*access_token*z*auth_token*z	*api_key*z*apikey*z*secret*z*credentials*stripetokenz\b[A-Z_]+=\w+F
shell_argsshellr   Nc                 C   s   t |t | }tj|| _| jr(| jj| _| jj| _| jj| _| jj| _dS g | _d| _g | _d| _t	|t r?t
|}nttt  |}|rN| | n|d | _|dd | _t	| jtret| jn| j| _|   t|| j| j| j| j| _dS )z
        For shell=True, the shell_args is parsed to extract environment variables,
        binary, and arguments. For shell=False, the first element is the binary
        and the rest are arguments.
        r   Fr      N)rX   r\   r]   get_cache_entryrQ   rN   rO   rP   
isinstanceshlexsplitr   rZ   scrub_env_varstuplescrub_argumentsri   )selfrq   rr   	cache_keytokensr   r   r   r@      s.   





zSubprocessCmdLine.__init__c              	   C   s   t |D ]D\}}t| j|r+|d\}}|| jv r"| j| q| jd|  qz|| | _||d d | _	W  dS  t
yH   Y  dS w dS )aD  Extract and scrub environment variables from shell command tokens.

        Args:
            tokens: list of command tokens to process

        Side effects:
            Updates self.env_vars, self.binary, and self.arguments
            Environment variables not in allowlist are scrubbed (value replaced with '?')
        =z%s=?rs   N)	enumeraterematch_COMPILED_ENV_VAR_REGEXPrx   ENV_VARS_ALLOWLISTrQ   r>   rN   rO   
IndexError)r|   r~   idxtokenvarvaluer   r   r   ry   	  s   


z SubprocessCmdLine.scrub_env_varsc                 C   sF  | j r| j  | jv rdd | jD | _dS d}g }t| j}|r|d }| jtjj	 D ]}t
||r8d} nq-d}|sG|| |  q |d |vrW|d |  q d	|v re|d |  q z$|d
 d |v ry|d |  W q ||dg |  |  W q  ty   |d |  Y nw |s"|| _dS )a  Scrub sensitive information from command arguments.

        This method processes command arguments to remove or obscure sensitive
        information like passwords, API keys, tokens, etc. It handles both
        standalone sensitive arguments and argument-value pairs.

        Side effects:
            Updates self.arguments with scrubbed values (sensitive data replaced with '?')

        Scrubbing rules:
        1. If binary is in denylist, scrub all arguments
        2. For each argument matching sensitive patterns:
           - If it contains '=', scrub the entire argument
           - If it's followed by another option, scrub only this argument
           - If it's followed by a value, scrub the value instead
        c                 S   s   g | ]}d qS )?r   ).0_r   r   r   
<listcomp>7  s    z5SubprocessCmdLine.scrub_arguments.<locals>.<listcomp>N)-/r   TFr   r   rs   )rN   lowerBINARIES_DENYLISTrO   collectionsdequeSENSITIVE_WORDS_WILDCARDSr   r   r   r   r>   popleftextendr   )r|   param_prefixesnew_args
deque_argscurrent	sensitiveis_sensitiver   r   r   r{   $  sR   






-z!SubprocessCmdLine.scrub_argumentsstr_c                 C   sH   t || j }|dkrd| _|S d| _d| }|d|t |   | S )a1  Truncate a string if it exceeds the size limit.

        Args:
            str_: String to potentially truncate

        Returns:
            str: Original string if under limit, or truncated string with message

        Side effects:
            Sets self.truncated = True if truncation occurred
        r   FTz* "4kB argument truncated by %d characters")rb   TRUNCATE_LIMITrP   )r|   r   oversizemsgr   r   r   truncate_stringm  s   z!SubprocessCmdLine.truncate_stringc                 C   s4   | j | jg | j }| t|}t|}||fS )aK  Generate both list and string representations of the command.

        Returns:
            tuple[list[str], str]: (command_as_list, command_as_string)

        Note:
            The string representation may be truncated if it exceeds size limits.
            The list representation is derived from the truncated string.
        )rQ   rN   rO   r   r   rw   rx   )r|   
total_listtruncated_strtruncated_listr   r   r   _as_list_and_string  s   

z%SubprocessCmdLine._as_list_and_stringc                 C   s@   | j r| j jdur| j jS |  \}}| j r|| j _|| j _|S )a  Get the command as a list of strings.

        Returns:
            list[str]: Command represented as list of arguments

        Note:
            Result is cached for performance. Includes environment variables,
            binary, and arguments in that order.
        N)ru   rR   r   rS   r|   list_resstr_resr   r   r   rR        
zSubprocessCmdLine.as_listc                 C   s@   | j r| j jdur| j jS |  \}}| j r|| j _|| j _|S )a  Get the command as a shell-quoted string.

        Returns:
            str: Command represented as a shell-quoted string

        Note:
            Result is cached for performance. String may be truncated if
            it exceeds the size limit.
        N)ru   rS   r   rR   r   r   r   r   rS     r   zSubprocessCmdLine.as_string)F)$rT   rU   rV   rW   r]   dictrX   rM   rY   r   r   r^   rc   r   ra   classmethodri   rk   r   r   r   r   r   compiler   r   rZ   r[   r@   ry   r{   r   rz   r   rR   rS   r   r   r   r   r\      s.   
 

	
$)Ir\   c               	   C   s   ddl } ddl}t |  t | | df| df| df|jdf|jdffD ]\}}zt|| W q' ty<   Y q'w t	  dS )aA  Remove instrumentation from subprocess and os functions.

    This function removes all patches applied by the patch() function,
    restoring the original behavior of subprocess and os functions.
    Also clears the command line cache.

    Note:
        Safe to call multiple times. Missing attributes are ignored.
    r   Nr3   r1   r2   r@   rA   )
r4   r   r	   remove_fromr?   r
   unwrapAttributeErrorr\   rk   )r4   r   objattrr   r   r   unpatch  s    
r   c           
      C   s  t  rzt|d trt D ]}||d  qt|d dd}W n ty8   tjddd ||i | Y S w t	j
tj|jtjd4}|tj|  |jrX|tjd |tjd ||i |}	|tjt|	 |	W  d	   S 1 s{w   Y  d	S ||i |S )
zTraced wrapper for os.system function.

    Note:
        Only instruments when AAP is enabled and WAF bypass is not active.
        Creates spans with shell command details, exit codes, and component tags.
    r   Trr   z2Could not trace subprocess execution for os.systemexc_inforesource	span_typeyesr4   N)r0   rv   rX   r   valuesr\   	Exceptionlogdebugr   tracer   	SPAN_NAMErN   r   SYSTEM_set_tag_strSHELLrS   rP   	TRUNCATED	COMPONENT	EXIT_CODE)
modulepinwrappedinstanceargskwargsr!   shellcmdspanretr   r   r   r;     s(   $	r;   c                 C   sx   t js
||i |S tjtjdtjd}|tj	dg |
tjd ||i |W  d   S 1 s5w   Y  dS )zTraced wrapper for os.fork function.

    Note:
        Only instruments when AAP is enabled.
        Creates spans with fork operation details.
    r1   r   zos.forkr4   N)r-   r/   r   r   r   r   r   r   set_tagEXECr   r   )r   r   r   r   r   r   r   r   r   r   r<     s   	$r<   c                 C   s2  t js
||i |S z)|\}}}}	}	t|tttfr,|gt| }
t D ]}||
 q%t|dd}W n t	yJ   t
jddd ||i | Y S w tjtj|jtjd9}|tj|  |jrj|tjd |tjd ||i |}|tjkr|tjt| |W  d	   S 1 sw   Y  d	S )
zTraced wrapper for os._spawnvef function (used by all os.spawn* variants).

    Note:
        Only instruments when AAP is enabled.
        Creates spans with spawn operation details and exit codes for P_WAIT mode.
    Fr   z1Could not trace subprocess execution for os.spawnTr   r   truer4   N)r-   r/   rv   rZ   rz   rX   r   r   r\   r   r   r   r   r   r   r   rN   r   r   r   r   rR   rP   r   r   r   r4   P_WAITr   )r   r   r   r   r   r   modefile	func_argsr   commandsr!   r   r   r   r   r   r   r=     s.   

$r=   c                 C   s~  t  rzKt|r|d n|d }t|tttfr5|ddr*t D ]}|| q"nt	 D ]}|| q.t|tr?t
|n|}|dd}	t||	d}
W n tye   tjddd ||i | Y S w tjtj|
jtjd	= ttj|	 |
jrttjd
 |	rttj|
  n	ttj|
  ttj|
j ||i |W  d   S 1 sw   Y  dS ||i |S )a'  Traced wrapper for subprocess.Popen.__init__ method.

    Note:
        Only instruments when AAP is enabled and WAF bypass is not active.
        Stores command details in context for later use by _traced_subprocess_wait.
        Creates a span that will be completed by the wait() method.
    r   r   rr   Fr   z$Could not trace subprocess executionTr   r   r   N) r0   rb   rv   rZ   rz   rX   rt   r   r   r   rw   rx   r\   r   r   r   r   r   r   r   rN   r   r   r   set_itemCTX_SUBP_IS_SHELLrP   CTX_SUBP_TRUNCATEDCTX_SUBP_LINErS   rR   CTX_SUBP_BINARY)r   r   r   r   r   r   cmd_argsr!   cmd_args_listis_shellr   r   r   r   rB   -  s8   	

$rB   c           
      C   s   t  ritd}tjtj|tjdM}ttj	r%|
tjttj n|tjttj ttj}|r?|
tjd |
tjd ||i |}	|
tjt|	 |	W  d   S 1 sbw   Y  dS ||i |S )a  Traced wrapper for subprocess.Popen.wait method.

    Note:
        Only instruments when AAP is enabled and WAF bypass is not active.
        Retrieves command details stored by _traced_subprocess_init and completes
        the span with execution results and exit code.
    subprocess_popen_binaryr   r   r   N)r0   r   	find_itemr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rX   )
r   r   r   r   r   r   rN   r   rP   r   r   r   r   rC   W  s   	
$rC   )r   N)=r   dataclassesr   r   r4   r   rw   r   typingr   r   r   r   ddtrace._trace.pinr	   ddtrace.contribr
   -ddtrace.contrib.internal.subprocess.constantsr   ddtrace.extr   ddtrace.internalr   ddtrace.internal.loggerr   !ddtrace.internal.settings._configr   ddtrace.internal.settings.asmr-   ddtrace.internal.threadsr   ddtrace.tracer   rT   r   _addr   getenvrx   rX   r   r   r   rY   r   rZ   r$   r)   r+   r,   r0   rK   rM   r\   r   with_traced_moduler;   r<   r=   rB   rC   r   r   r   r   <module>   sh   
 *
(	
	1  
"!


!
)