2022-03-19 20:41:35 -03:00
#!/usr/bin/env python3
2022-03-17 19:05:23 -03:00
#Imports
import yaml
import os
import re
import pexpect
from Crypto . PublicKey import RSA
from Crypto . Cipher import PKCS1_OAEP
import ast
from time import sleep
import datetime
import sys
2022-03-19 20:41:35 -03:00
#functions and classes
2022-03-17 19:05:23 -03:00
class node :
2022-03-18 15:32:48 -03:00
def __init__ ( self , unique , host , options = ' ' , logs = ' ' , password = ' ' , port = ' ' , protocol = ' ' , type = ' ' , user = ' ' , config = ' ' ) :
if config == ' ' :
2022-03-17 19:05:23 -03:00
self . idletime = 0
2022-03-18 15:32:48 -03:00
self . key = None
else :
self . idletime = config . config [ " idletime " ]
self . key = config . key
2022-03-17 19:05:23 -03:00
self . unique = unique
self . id = self . unique . split ( " @ " ) [ 0 ]
attr = { " host " : host , " logs " : logs , " options " : options , " port " : port , " protocol " : protocol , " user " : user }
for key in attr :
profile = re . search ( " ^@(.*) " , attr [ key ] )
2022-03-18 15:32:48 -03:00
if profile and config != ' ' :
2022-03-17 19:05:23 -03:00
setattr ( self , key , config . profiles [ profile . group ( 1 ) ] [ key ] )
elif attr [ key ] == ' ' and key == " protocol " :
try :
setattr ( self , key , config . profiles [ " default " ] [ key ] )
except :
setattr ( self , key , " ssh " )
else :
setattr ( self , key , attr [ key ] )
if isinstance ( password , list ) :
self . password = [ ]
for i , s in enumerate ( password ) :
profile = re . search ( " ^@(.*) " , password [ i ] )
2022-03-18 15:32:48 -03:00
if profile and config != ' ' :
2022-03-17 19:05:23 -03:00
self . password . append ( config . profiles [ profile . group ( 1 ) ] [ " password " ] )
else :
2022-03-18 15:32:48 -03:00
self . password = [ password ]
2022-03-17 19:05:23 -03:00
def __passtx ( self , passwords , * , keyfile = None ) :
dpass = [ ]
2022-03-18 15:32:48 -03:00
if keyfile is None :
keyfile = self . key
2022-03-25 12:25:59 -03:00
if keyfile is not None :
2022-03-18 15:32:48 -03:00
key = RSA . import_key ( open ( keyfile ) . read ( ) )
decryptor = PKCS1_OAEP . new ( key )
2022-03-17 19:05:23 -03:00
for passwd in passwords :
2022-03-18 15:32:48 -03:00
if isinstance ( passwd , str ) :
dpass . append ( passwd )
else :
try :
decrypted = decryptor . decrypt ( ast . literal_eval ( str ( passwd ) ) ) . decode ( " utf-8 " )
dpass . append ( decrypted )
except :
2022-03-25 12:25:59 -03:00
raise ValueError ( " Missing or corrupted key " )
2022-03-17 19:05:23 -03:00
return dpass
def _logfile ( self , logfile = None ) :
if logfile == None :
logfile = self . logs
logfile = logfile . replace ( " $ {id} " , self . id )
logfile = logfile . replace ( " $ {unique} " , self . unique )
logfile = logfile . replace ( " $ {host} " , self . host )
logfile = logfile . replace ( " $ {port} " , self . port )
logfile = logfile . replace ( " $ {user} " , self . user )
logfile = logfile . replace ( " $ {protocol} " , self . protocol )
now = datetime . datetime . now ( )
dateconf = re . search ( r ' \ $ \ { date \' (.*) \' } ' , logfile )
if dateconf :
logfile = re . sub ( r ' \ $ \ { date (.*)} ' , now . strftime ( dateconf . group ( 1 ) ) , logfile )
return logfile
2022-03-18 16:16:31 -03:00
def _logclean ( self , logfile , var = False ) :
if var == False :
t = open ( logfile , " r " ) . read ( )
else :
t = logfile
t = t . replace ( " \n " , " " , 1 ) . replace ( " \a " , " " )
2022-03-17 19:05:23 -03:00
t = t . replace ( ' \n \n ' , ' \n ' )
t = re . sub ( ' . \ [K ' , ' ' , t )
while True :
tb = re . sub ( ' . \b ' , ' ' , t , count = 1 )
if len ( t ) == len ( tb ) :
break
t = tb
2022-03-18 15:32:48 -03:00
ansi_escape = re . compile ( r ' \ x1B(?:[@-Z \\ -_]| \ [[0-?]*[ -/ ]*[@-~]) ' )
t = ansi_escape . sub ( ' ' , t )
2022-03-18 16:16:31 -03:00
if var == False :
d = open ( logfile , " w " )
d . write ( t )
d . close ( )
return
else :
return t
2022-03-17 19:05:23 -03:00
2022-03-22 19:54:05 -03:00
def interact ( self , debug = False ) :
connect = self . _connect ( debug = debug )
2022-03-18 15:32:48 -03:00
if connect == True :
print ( " Connected to " + self . unique + " at " + self . host + ( " : " if self . port != ' ' else ' ' ) + self . port + " via: " + self . protocol )
2022-03-25 12:25:59 -03:00
if ' logfile ' in dir ( self ) :
2022-03-18 15:32:48 -03:00
self . child . logfile_read = open ( self . logfile , " wb " )
2022-03-25 12:25:59 -03:00
elif debug :
self . child . logfile_read = None
2022-03-18 15:32:48 -03:00
if ' missingtext ' in dir ( self ) :
2022-03-19 20:41:35 -03:00
print ( self . child . after . decode ( ) , end = ' ' )
2022-03-18 15:32:48 -03:00
self . child . interact ( )
2022-03-22 19:54:05 -03:00
if " logfile " in dir ( self ) and not debug :
2022-03-18 15:32:48 -03:00
self . _logclean ( self . logfile )
2022-03-25 12:25:59 -03:00
else :
print ( connect )
exit ( 7 )
2022-03-18 15:32:48 -03:00
2022-03-18 16:16:31 -03:00
def run ( self , commands , * , folder = ' ' , prompt = ' >$|#$| \ $.$ ' , stdout = False ) :
2022-03-18 15:32:48 -03:00
connect = self . _connect ( )
if connect == True :
2022-03-19 20:41:35 -03:00
winsize = self . child . getwinsize ( )
self . child . setwinsize ( 65535 , winsize [ 1 ] )
2022-03-18 15:32:48 -03:00
output = ' '
if isinstance ( commands , list ) :
for c in commands :
self . child . expect ( prompt )
self . child . sendline ( c )
output = output + self . child . before . decode ( ) + self . child . after . decode ( )
else :
self . child . expect ( prompt )
2022-03-18 16:16:31 -03:00
self . child . sendline ( commands )
2022-03-18 15:32:48 -03:00
output = output + self . child . before . decode ( ) + self . child . after . decode ( )
self . child . expect ( prompt )
output = output + self . child . before . decode ( ) + self . child . after . decode ( )
2022-03-25 12:25:59 -03:00
if stdout == True :
print ( output )
if folder != ' ' :
2022-03-18 15:32:48 -03:00
with open ( folder + " / " + self . unique , " w " ) as f :
f . write ( output )
f . close ( )
self . _logclean ( folder + " / " + self . unique )
2022-03-18 16:16:31 -03:00
self . output = output
return output
2022-03-18 15:32:48 -03:00
2022-03-22 19:54:05 -03:00
def _connect ( self , debug = False ) :
2022-03-17 19:05:23 -03:00
if self . protocol == " ssh " :
cmd = " ssh "
if self . idletime > 0 :
cmd = cmd + " -o ServerAliveInterval= " + str ( self . idletime )
if self . user == ' ' :
cmd = cmd + " -t {} " . format ( self . host )
else :
cmd = cmd + " -t {} " . format ( " @ " . join ( [ self . user , self . host ] ) )
if self . port != ' ' :
cmd = cmd + " -p " + self . port
if self . options != ' ' :
cmd = cmd + " " + self . options
if self . logs != ' ' :
2022-03-18 15:32:48 -03:00
self . logfile = self . _logfile ( )
2022-03-17 19:05:23 -03:00
if self . password [ 0 ] != ' ' :
passwords = self . __passtx ( self . password )
else :
passwords = [ ]
2022-03-22 19:54:05 -03:00
expects = [ ' yes/no ' , ' refused ' , ' supported ' , ' cipher ' , ' sage ' , ' timeout ' , ' unavailable ' , ' closed ' , ' [p|P]assword:|[u|U]sername: ' , ' >$|#$| \ $.$ ' , ' suspend ' , pexpect . EOF , " No route to host " ]
2022-03-17 19:05:23 -03:00
elif self . protocol == " telnet " :
cmd = " telnet " + self . host
if self . port != ' ' :
cmd = cmd + " " + self . port
if self . options != ' ' :
cmd = cmd + " " + self . options
if self . logs != ' ' :
2022-03-18 15:32:48 -03:00
self . logfile = self . _logfile ( )
2022-03-17 19:05:23 -03:00
if self . password [ 0 ] != ' ' :
passwords = self . __passtx ( self . password )
else :
passwords = [ ]
2022-03-22 19:54:05 -03:00
expects = [ ' [u|U]sername: ' , ' refused ' , ' supported ' , ' cipher ' , ' sage ' , ' timeout ' , ' unavailable ' , ' closed ' , ' [p|P]assword: ' , ' >$|#$| \ $.$ ' , ' suspend ' , pexpect . EOF , " No route to host " ]
2022-03-17 19:05:23 -03:00
else :
2022-03-25 12:25:59 -03:00
raise ValueError ( " Invalid protocol: " + self . protocol )
2022-03-17 19:05:23 -03:00
child = pexpect . spawn ( cmd )
2022-03-22 19:54:05 -03:00
if debug :
child . logfile_read = sys . stdout . buffer
2022-03-17 19:05:23 -03:00
if len ( passwords ) > 0 :
loops = len ( passwords )
else :
loops = 1
endloop = False
for i in range ( 0 , loops ) :
while True :
results = child . expect ( expects )
match results :
case 0 :
if self . protocol == " ssh " :
child . sendline ( ' yes ' )
elif self . protocol == " telnet " :
if self . user != ' ' :
child . sendline ( self . user )
else :
2022-03-18 15:32:48 -03:00
self . missingtext = True
2022-03-17 19:05:23 -03:00
break
2022-03-22 19:54:05 -03:00
case 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 :
2022-03-17 19:05:23 -03:00
child . close ( )
2022-03-25 12:25:59 -03:00
return " Connection failed code: " + str ( results )
2022-03-17 19:05:23 -03:00
case 8 :
if len ( passwords ) > 0 :
child . sendline ( passwords [ i ] )
else :
2022-03-18 15:32:48 -03:00
self . missingtext = True
2022-03-17 19:05:23 -03:00
break
2022-03-18 15:32:48 -03:00
case 9 | 11 :
2022-03-17 19:05:23 -03:00
endloop = True
child . sendline ( )
break
case 10 :
child . sendline ( " \r " )
sleep ( 2 )
if endloop :
break
child . readline ( 0 )
2022-03-18 15:32:48 -03:00
self . child = child
return True
2022-03-17 19:05:23 -03:00
# script