
    iT                        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d dlZd dl	Z	d dl
Z
d dlmZ d dlmZmZmZ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mZ d d	lmZ d d
lm Z  d dl!m"Z"m#Z# d dl$m%Z% d dl&m'Z'm(Z(m)Z) d dl*m+Z+ d dl,m-Z-m.Z. d dl/m0Z0m1Z1 d dl2m3Z3  ejh                  d      Z5defdZ6 G d de(      Z7ddddejp                  Z8 G d de1      Z9 G d dejt                        Z;de<de=ee<   ee<   f   fd Z>d!ee<   d"e<d#ed$e<de=ee<   ee<   f   f
d%Z?d!ee<   d&ee<   de=ee<   ee<   f   fd'Z@ G d( d)e+      ZA G d* d+e0      ZBd/d,ZCd/d-ZDeEd.k(  r eD        yy)0    N)Path)DictLiteralOptionalSequence)	polyfills)ferny)
bootloader)BridgeBeibootHelper)parse_os_releasesetup_logging)ChannelRoutingRule)PackagesChannel)
JsonObjectget_str)supported_oses)PackagesPackagesLoaderpatch_libexecdir)Peer)CockpitProblemCockpitProtocolError)RouterRoutingRule)StdioTransportzcockpit.beibootreturnc                     t         j                  j                  t        j                        dz  } | j                         }t        j                  j                  d      }|t        j                  j                  d      }t        j                  |d       t        |d      }t        j                  d|       	 |j                         |k7  rt        j                  d       t        |j!                         j"                  d	z  st        j                  d
       t        	 |S # t$        t        f$ r; t        j                  d       |j'                  |       |j)                  d       Y |S w xY w)zCreate askpass executable

    We need this for the flatpak: ssh and thus the askpass program run on the host (via flatpak-spawn),
    not the flatpak. Thus we cannot use the shipped cockpit-askpass program.
    zinteraction_client.pyXDG_CACHE_HOMEz~/.cacheT)exist_okzcockpit-client-askpasszChecking if %s exists...z.  ... it exists but is not the same version...@   z;  ... it has the correct contents, but is not executable...z  ... writing contents.i  )	importlib	resourcesfilesr	   __name__
read_bytesosenvirongetpath
expandusermakedirsr   loggerdebug
ValueErrorstatst_modeFileNotFoundErrorwrite_byteschmod)src_pathsrc_dataxdg_cache_home	dest_paths       1/usr/lib/python3/dist-packages/cockpit/beiboot.pyensure_ferny_askpassr9   %   s,    ""((8;RRH""$H ZZ^^$45N++J7KK.^%=>I
LL+Y7
!X-LLIJ~~''%/LLVW 0  z* ./h's   ;A&D$ $AE.-E.c                   H    e Zd ZU eeef   ed<   deeef   fdZdedefdZy)ProxyPackagesLoaderfile_statusc                     || _         y N)r<   )selfr<   s     r8   __init__zProxyPackagesLoader.__init__J   s
    &    r)   r   c                 :    | j                   j                  |d      S )NF)r<   r(   )r?   r)   s     r8   path_existszProxyPackagesLoader.path_existsM   s    ##D%00rA   N)	r$   
__module____qualname__r   strbool__annotations__r@   rC    rA   r8   r;   r;   G   s7    c4i 'DdO '1 1 1rA   r;   z
    import os
    def report_exists(files):
        command('cockpit.report-exists', {name: os.path.exists(name) for name in files})
    z
    import os
    def check_os_release(_argv):
        try:
            with open('/etc/os-release') as f:
                command('cockpit.check-os-release', f.read())
        except OSError:
                command('cockpit.check-os-release', "")
    z
    import os
    def force_exec(argv):
        try:
            os.execvp(argv[0], argv)
        except OSError as e:
            command('cockpit.fail-no-cockpit', str(e))
    )report_existscheck_os_release
force_execc                   H     e Zd ZU ded<   def fdZdeddfdZd	dZ xZ	S )
DefaultRoutingRulezPeer | Nonepeerrouterc                 $    t         |   |       y r>   )superr@   )r?   rP   	__class__s     r8   r@   zDefaultRoutingRule.__init__o   s     rA   optionsr   c                     | j                   S r>   )rO   )r?   rT   s     r8   
apply_rulezDefaultRoutingRule.apply_ruler   s    yyrA   c                 R    | j                   | j                   j                          y y r>   )rO   closer?   s    r8   shutdownzDefaultRoutingRule.shutdownu   s    99 IIOO !rA   r   N)
r$   rD   rE   rH   r   r@   r   rV   rZ   __classcell__rS   s   @r8   rN   rN   l   s-    
!v !*  rA   rN   c            
       r    e Zd ZU dZeed<   dedee   fdZdedededee   fd	Z	d
ede
dee   deddf
dZy)AuthorizeResponder)zferny.askpasscockpit.report-existscockpit.fail-no-cockpitcockpit.check-os-releaserP   basic_passwordc                 2    || _         || _        |d u| _        y r>   )rP   rc   have_basic_password)r?   rP   rc   s      r8   r@   zAuthorizeResponder.__init__~   s    ,#1#= rA   messagesprompthintr   c           	      X  K   t         j                  d|||       | j                  rId|j                         v r7| j                  +t         j                  d|       | j                  }d | _        |S |dk(  ry t        j                  d|      }t        j                  d|      }i }|r]|r[|j                  d      }|dk(  rt         j                  d	|       y
| d|j                  d       d|d<   |j                  d      |d<   t        j                          dt        j                          }	d|	 }
|
dz   t        j                  |j                               j                         z   } | j                  j                   |fd |||dd| d {   }|j#                  |
      st%        d| d|
       |j'                  |
      j)                         }t        j*                  |j                               j                         }t         j                  dt-        |             |S 7 w)Nz3AuthorizeResponder: prompt %r, messages %r, hint %rz	password:z=AuthorizeResponder: sending Basic auth password for prompt %rnonez&\n(\w+) key fingerprint is:? ([^.\n]+)zauthenticity of host '([^ ]+)    z	127.0.0.1z,auto-accepting fingerprint for 127.0.0.1: %syes z login-datazhost-key   default-zX-Conversation F)timeoutrf   rg   rh   echozAuthorizeResponder: response z does not match challenge zReturning a %d chars response)r,   r-   re   lowerrc   researchgroupr&   getpidtimebase64	b64encodeencodedecoderP   request_authorization
startswithr   removeprefixstrip	b64decodelen)r?   rf   rg   rh   replyfp_match
host_matchargshostnamechallenge_idchallenge_prefix	challengeresponseb64s                 r8   
do_askpasszAuthorizeResponder.do_askpass   s    JFT\^bc##v||~(E "".\^de++&*#6>  99FOYY@&I

!''*H;&KZX
 #+1X^^A->,?{KD&nnQ/DO))+a		}5,\N;$s*V-=-=fmmo-N-U-U-WW	:::9 CCGDLBH@D@EC >BC C ""#34&/z9STdSefh h##$45;;=##CJJL188:4c(mDCs   FH*H(BH*commandr   fdsstderrNc                   K   t         j                  d|||       |dk(  rg|\  }t        t        |            | j                  _        | j                  j                  j                  dt        | j                  t        g             |dk(  rt        d|d         |dk(  rht        |d         t         j                  d	       t         j                  d
t               t        D ]<  }t        fd|j                         D              s&t         j                  d|        y  t         j                  d       	 t        d      5 }t        |j!                               }d d d        j'                  d      j'                  d      k(  r:j'                  d      |j'                  d      k(  rt         j                  d|       y j'                  dj'                  dd             dj'                  dd       }
t        d|
      y # 1 sw Y   xY w# t"        $ r }	t         j%                  d|	       Y d }	~	y d }	~	ww xY ww)NzGot ferny command %s %s %sr`   )loaderr   ra   z
no-cockpit)messagerb   z'cockpit.check-os-release: remote OS: %rz,cockpit.check-os-release: supported OSes: %rc              3   L   K   | ]  \  }}j                  |      |k(    y wr>   )r(   ).0kv	remote_oss      r8   	<genexpr>z7AuthorizeResponder.do_custom_command.<locals>.<genexpr>   s#     HAy}}Q'1,Hs   !$z8cockpit.check-os-release: remote matches supported OS %rz$cockpit.check-os-release: remote: %rz/etc/os-releasezIfailed to read local /etc/os-release, skipping OS compatibility check: %sID
VERSION_IDz7cockpit.check-os-release: remote OS matches local OS %rNAME?rm    )unsupported)r,   r-   r   r;   rP   packagesrouting_rulesinsertr   r   r   r   r   allitemsopenreadOSErrorwarningr(   )r?   r   r   r   r   r<   osinfofthis_oser   r   s              @r8   do_custom_commandz$AuthorizeResponder.do_custom_command   s    17D&I--LK#+3F{3S#TDKK KK%%,,Q0B4;;Q`Pa0bc// tAw??00(a1ILLBINLLGX( HHHLL![]cd	 LL?K+, 9.qvvx8G9 }}T"gkk$&77IMM,<W[b[f[fgs[t<tVX_`&]]69==s3KLMQy}}]ikmOnNopK ;GG3 19 9 jlmnsO   D	I/I=H H"H *B"IHH 	I!H<7I<II)r$   rD   rE   commandsr   rH   r   rF   r@   r   tuplelistintr   rI   rA   r8   r_   r_   z   s    pHN>v >x} >
E Ec E ERU EN%Hs %H% %Hd3i %HY\ %Hae %HrA   r_   commentc                     ddd|  fdfS )Npython3z-icz# rI   rI   )r   s    r8   python_interpreterr      s    u7)n-r11rA   cmddestssh_askpassssh_optsc                    |j                  d      \  }}}|j                         r?|j                  d      s.|j                  d      r|j                  d      r|dd }d|d|g}nd|g}dg||t	        j
                  |       d	|d
dffS )N:[]rk   z-pz--sshzSSH_ASKPASS=z	DISPLAY=xzSSH_ASKPASS_REQUIRE=force)
rpartitionisdigitendswithr~   shlexjoin)r   r   r   r   host_portdestinations           r8   via_sshr      s    OOC(MD!T||~dmmC0??3DMM#$6":DT4.Tl 	&(-

3 {o& 	# rA   envc                 &    ddgd |D        | dfS )Nzflatpak-spawnz--hostc              3   &   K   | ]	  }d |   yw)z--env=NrI   )r   kvs     r8   r   z flatpak_spawn.<locals>.<genexpr>  s     	&BF2$-	&s   rI   rI   )r   r   s     r8   flatpak_spawnr     s2    	&#	& 
	 rA   c                        e Zd ZU ded<   dededej                  f fdZdd	Z	dd
Z
ddZdee   dee   ddfdZddZdeddfdZ xZS )SshPeerzMLiteral["always"] | Literal["never"] | Literal["supported"] | Literal["auto"]moderP   r   r   c                     || _         |j                  | _        t        j                         | _        t        | j                  j                        dz  | _        d | _        t        | )  |       y )Nzuser-known-hosts)r   remote_bridgetempfileTemporaryDirectorytmpdirr   nameknown_hosts_filerc   rR   r@   )r?   rP   r   r   rS   s       r8   r@   zSshPeer.__init__  s[    &!//113 $T[[%5%5 69K K,0 rA   r   Nc                    K   t         j                  j                  d      r| j                          d {    y | j	                          d {    y 7 7 w)Nz/.flatpak-info)r&   r)   existsconnect_from_flatpakconnect_from_bastion_hostrY   s    r8   do_connect_transportzSshPeer.do_connect_transport   sD     77>>*+++---00222 .2s!   3AAAAAAc                    K   t        d      \  }}| j                  dk7  r"t        || j                  t                     \  }}t	        ||      \  }}| j                  ||       d {    y 7 w)Ncockpit-bridge	localhost)r   r   r   r9   r   boot)r?   r   r   s      r8   r   zSshPeer.connect_from_flatpak'  se     %&67S {*sD$4$46J6LMHC c*SiiS!!!s   A$A.&A,'A.c                 v  K   d }ddg}| j                   j                  d       d {   }t        |d      }|j                  d      rtt	        j
                  |dd        j                         }|j                  d      \  }}}|j                  d      \  }}| _        |rt        j                  d	|       |d
|gz  }| j                  |ddgz  }t        d      \  }	}
t        d      }t        |t              sJ t        |      }|j!                         st        j#                  d|       t%        j&                  d      }|
|dd| gz  }|/| j(                  j+                  |       |dd| j(                  gz  }t-        |	| j.                  |g| \  }	}
| j1                  |	|
       d {    y 7 7 w)Nz-ozNumberOfPasswordPrompts=1*r   zBasic     r   z,got username %s and password from Basic authz-lzPasswordAuthentication=nor   z${libexecdir}/cockpit-askpassz+Could not find cockpit-askpass helper at %rCOCKPIT_SSH_KNOWN_HOSTS_FILEzGlobalKnownHostsFile=zUserKnownHostsfile=)rP   request_authorization_objectr   r~   ry   r   r|   	partitionrc   r,   r-   r   r   
isinstancerF   r   r   errorr&   getenvr   
write_textr   r   r   )r?   known_hostsr   authr   decodeduser_passwordr   userr   r   askpassr   env_known_hostss                 r8   r   z!SshPeer.connect_from_bastion_host4  s    12 [[==cBB4,x(&&x|4;;=G,3,=,=d,C)M1k+8+B+B3+G(D!T(KTRt$&T677D &&67S ##BC'3'''7m!!#LLFP))$BC&T2?2CDEED"!!,,[9T01F1F0IJKKD3 0 0+EESiiS!!!C CB 	"s"   %F9F4FF9.F7/F97F9r   r   c                   K   t        |       }t        j                  t        | j                  | j
                        |g      }t        j                  d||       | j                  |||d       d {   }| j                  dk(  rddgffg}nE| j                  dk(  rddgffg}n.| j                  d	k(  rddgffd
g ffg}n| j                  dk(  sJ g }t        j                  g |dt        t        j                               gf|j                  t               }|j#                  |j%                                |j'                          d {    y 7 7 w)Nz Launching command: cmd=%s env=%sT)r   start_new_sessionautotry_execr   alwaysrL   	supportedrK   neverrJ   )gadgets)r   r	   InteractionAgentr_   rP   rc   r,   r-   spawnr   r
   make_bootloaderr   r   get_condition_filesstepsBEIBOOT_GADGETSwriter{   communicate)r?   r   r   beiboot_helperagent	transportexec_cockpit_bridge_stepsstage1s           r8   r   zSshPeer.boot]  sw    ,T2&&(:4;;H[H[(\^l'mn7cB**S#et*TT	'*48H7I6K)L(M%8+*6:J9K8M)N(O%;.*48H7I6K)LOadfchNi(j%%%000(*% ++ -
&-
tN$F$F$HIJK-
 !!-
 #	$
 	( !!!- U, 	"s%   A0E2E3CEEEEc                     d | _         y r>   )rc   rY   s    r8   do_superuser_init_donezSshPeer.do_superuser_init_donez  s
    "rA   r   c                 x   t         j                  d|| j                  d u       t        |d      j	                  d      rSt        |d      }| j                  ;t         j                  d       | j                  d|| j                         d | _        y t         j                  d       | j                  dd	
       y )Nz*SshPeer.do_authorize: %r; have password %sr   zplain1:cookiez-SshPeer.do_authorize: responded with password	authorize)r   r  r   z0SshPeer.do_authorize: authentication-unavailablezauthentication-unavailable)r   r  problem)r,   r-   rc   r   r~   write_control)r?   r   r  s      r8   do_authorizezSshPeer.do_authorize}  s    A7DL_L_gkLkl7K(33I>Wh/F"".LM"";vPTPcPc"d&*#GH;vGcdrA   r[   )r$   rD   rE   rH   r   rF   argparse	Namespacer@   r   r   r   r   r   r
  r   r  r\   r]   s   @r8   r   r     sv    
YY!v !C !x?Q?Q !3"'"R"hsm "(3- "D ":#eJ e4 erA   r   c                   n     e Zd ZU dZee   ed<   eed<   dej                  f fdZ
d	dZd Zd	dZ xZS )
	SshBridgeNr   ssh_peerr   c                     t        |       }t        | 	  |g       t        | |j                  |      | _        | j
                  |_        y r>   )rN   rR   r@   r   r   r  rO   )r?   r   rulerS   s      r8   r@   zSshBridge.__init__  sA     "$'$   d&6&6=MM	rA   c                      y r>   rI   rY   s    r8   do_send_initzSshBridge.do_send_init  s    rA   c                 f    t         j                  d|       | j                  j                  |       y )NzSshBridge.do_init: %r)r,   r-   r  r  )r?   r   s     r8   do_initzSshBridge.do_init  s%     	,g6##G,rA   c                 N    | j                   j                  | j                         y r>   )r  add_done_callbackrX   rY   s    r8   setup_sessionzSshBridge.setup_session  s    ''

3rA   r[   )r$   rD   rE   r   r   r   rH   r   r  r  r@   r  r  r  r\   r]   s   @r8   r  r    s9    #'Hhx '	"X// 	"-4rA   r  c                 R  K   t         j                  d       t        |       }t        t	        j
                         |       	 t        |j                  j                          d {         }|j                  j                  j                         r9|j                  dddd|j                  j                  j                         i       |j                  di       }t        |t              s|j                  dd	d
       y t        |t              sJ d|d<   |j                  r,t        j!                  |j                  j                        |d<   |j                  |       |j                  j#                          t         j                  d       |j?                          	 |jA                          d {    y 7 V# t$        j&                  $ rT}t$        j(                  j+                  t-        |            }t         j                  d||       t        |t$        j.                        rd}nlt        |t$        j0                        rd}nOt        |t$        j2                        rd}n2t        |t4              rd}nt        |t$        j6                        rd}nd}|j                  j                  j                         rA|j                  d|t-        |      |j                  j                  j                                n|j                  d|t-        |             Y d }~y d }~wt8        $ r=}t         j                  d|       |j                  |j:                  d       Y d }~y d }~wt        j<                  $ r t         j                  d       Y y w xY w7 # tB        $ r Y y w xY ww)NzHi. How are you today?r  zx-login-datarp   zknown-hosts)r   r   r  
login_datacapabilitiesinitzprotocol-errorzcapabilities must be a dict)r   r  r   Tzexplicit-superuserr   z.ferny.InteractionError: %s, interpreted as: %rzauthentication-failedzinvalid-hostkeyzunknown-hostkeyzunknown-hostzinternal-error)r   r  r   r   zCockpitProblem: %s)r   z"Peer bridge got cancelled, exitingz/Startup done.  Looping until connection closes.)"r,   r-   r  r   asyncioget_running_loopdictr  startr   r   r  	read_text
setdefaultr   r   fromkeysthaw_endpointr	   InteractionError
ssh_errorsget_exception_for_ssh_stderrrF   SshAuthenticationErrorSshChangedHostKeyErrorSshHostKeyErrorr   SshErrorr   attrsCancelledErrorr  r  BrokenPipeError)r   bridger   r!  excr   r  s          r8   runr7    s    
LL)*t_F7++-v66V__22445??++224  #~c!6??#C#C#M#M#OW !  ))."=,-  9ISp q,----1)* ??"&--0H0H"IGJW%%%'@ LLBC
  """u 50 !!   ==c#hGEsEReU99:-Gu;;<'Gu445'Gw'$Gu~~.-G&G??++224  #e*-3__-M-M-W-W-Y ! [   #e* U )3/SYY7!! 9: 	# s   ?N'"F= $F:%BF=  N'A:F= ;%N'!N 4N5N 9N':F= =NE
L N' N,3M$N'$+NN'NN'N 	N$!N'#N$$N'c                  r   t        j                          t        j                  d      } | j	                  dg ddd       | j	                  dd	
       | j	                  dd       | j                         }t        |j                         t        j                  t        |      |j                         y )Nz@cockpit-bridge is run automatically inside of a Cockpit session.)descriptionz--remote-bridge)r   r   r   r   r   zHow to run cockpit-bridge from the remote host: auto: if installed (default), never: always copy the local one; supported: if not installed, copy local one for compatible OSes, fail otherwise; always: fail if not installed)choicesro   helpz--debug
store_true)actionr   z5Name of the remote host to connect to, or 'localhost')r;  )r-   )
r   installr  ArgumentParseradd_argument
parse_argsr   r-   r#  r7  )parserr   s     r8   mainrC    s    $$1stF
)3[ek8  9
 	,7
,cdD

#KKD	,rA   __main__r[   )Fr  r#  ry   importlib.resourcesr!   loggingr&   rt   r   r   rx   pathlibr   typingr   r   r   r   cockpitr   cockpit._vendorr	   cockpit._vendor.beir
   cockpit.beipackr   cockpit.bridger   r   cockpit.channelr   cockpit.channels.packagesr   cockpit.jsonutilr   r   cockpit.osinfor   cockpit.packagesr   r   r   cockpit.peerr   cockpit.protocolr   r   cockpit.routerr   r   cockpit.transportsr   	getLoggerr,   r9   r;   r  rN   AskpassHandlerr_   rF   r   r   r   r   r   r  r7  rC  r$   rI   rA   r8   <module>rY     s        	 	     4 4  ! * / : . 5 0 ) G G  A . -			,	-d D1. 1
. /6 uH-- uHp2 2hsmXc].J(K 2# c   QVW_`cWdfnorfsWsQt ,x} 8C= U8C=RZ[^R_C_=` sed sel4 4:DN-$ zF rA   