Parcourir la source

Make auth variables available in env and fix further sudo issues.

 - It is now possible to set passwords and tokens in auth and to
   use them later in tasks as a variable so that they're not in
   cleartext.

 - sudo still failed in some cases (due to the variable nature of
   ssh interactions) and the closing of the root shell was bugged.
Aurelien il y a 5 ans
Parent
commit
ba4bd68a53
2 fichiers modifiés avec 24 ajouts et 8 suppressions
  1. 1 0
      byrd/cli.py
  2. 23 8
      byrd/main.py

+ 1 - 0
byrd/cli.py

@@ -118,6 +118,7 @@ def run():
         base_env = Env(
             cli.env,  # Highest-priority
             cli.cfg.get('env'),
+            {key: val for key, val in cli.cfg.get('auth').items() if key != 'ssh_private_key'},
             os.environ,  # Lowest
         )
         for task in cli.tasks:

+ 23 - 8
byrd/main.py

@@ -8,8 +8,10 @@ import io
 import os
 import posixpath
 import pwd
+import socket
 import subprocess
 import threading
+import time
 
 from .config import Task, yaml_load
 from .utils import (ByrdException, LocalException, ObjectDict, RemoteException,
@@ -53,6 +55,8 @@ def get_sudo_passwd():
 
 CONNECTION_CACHE = {}
 
+SUDO_PW_CACHE = {}
+
 
 def connect(host, auth):
     if host in CONNECTION_CACHE:
@@ -181,6 +185,15 @@ def log_stream(stream, buff):
     t.start()
     return t
 
+def read_channel(channel, wait_time):
+    t = time.time()
+    received = b''
+    channel.settimeout(wait_time)
+    while (time.time() - t) < wait_time:
+        try:
+            received += channel.recv(1024)
+        except socket.timeout:
+            return received
 
 def run_helper(client, cmd, env=None, in_buff=None, sudo=False):
     '''
@@ -198,20 +211,19 @@ def run_helper(client, cmd, env=None, in_buff=None, sudo=False):
         else:
             sudo_cmd = 'sudo -s'
         chan.exec_command(sudo_cmd)
-        msg = chan.recv(1024)
+        msg = read_channel(chan, 0.1)
         while msg and b'[sudo] password for' in msg:
-            pw = getpass(msg.decode())
+            pw = SUDO_PW_CACHE[client] if client in SUDO_PW_CACHE else getpass(msg.decode())
             chan.send(pw + '\n')
-            msg = chan.recv(1024)
-            msg += chan.recv(1024)
+            msg = read_channel(chan, 0.1)
             if b'root@' in msg:
+                SUDO_PW_CACHE[client] = pw
                 break
             else:
+                msg += read_channel(chan, 2)
                 if b'sudo: 3 incorrect password attempts' in msg:
                     raise RemoteException(msg)
-                if b'Sorry' in msg:  # Failure message in in two parts in bash on Debian anyway.
-                    msg += chan.recv(1024)
-
+        chan.settimeout(None)
         in_buff = cmd
 
     stdin = chan.makefile('wb')
@@ -227,8 +239,11 @@ def run_helper(client, cmd, env=None, in_buff=None, sudo=False):
 
     if in_buff:
         # XXX use a real buff (not a simple str) ?
-        stdin.write(in_buff.replace('\n', '') + ' && exit $?\n')
+        stdin.write(in_buff if in_buff[-1] == '\n' else in_buff + '\n')
         stdin.flush()
+        if sudo:
+            stdin.write('exit $?\n')
+            stdin.flush()
         stdin.close()
         chan.shutdown_write()