├── .gitignore ├── Exscript ├── Account.py ├── AccountManager.py ├── AccountPool.py ├── AccountProxy.py ├── FileLogger.py ├── Host.py ├── Log.py ├── Logfile.py ├── Logger.py ├── LoggerProxy.py ├── PrivateKey.py ├── Queue.py ├── __init__.py ├── emulators │ ├── CommandSet.py │ ├── IOSEmulator.py │ ├── VirtualDevice.py │ └── __init__.py ├── external │ ├── __init__.py │ └── otp │ │ ├── AppendixB.py │ │ ├── __init__.py │ │ ├── keywrangling.py │ │ └── otp.py ├── interpreter │ ├── Append.py │ ├── Assign.py │ ├── Code.py │ ├── Enter.py │ ├── Exception.py │ ├── Execute.py │ ├── Expression.py │ ├── ExpressionNode.py │ ├── Extract.py │ ├── Fail.py │ ├── FunctionCall.py │ ├── IfCondition.py │ ├── Loop.py │ ├── Number.py │ ├── Parser.py │ ├── Program.py │ ├── Regex.py │ ├── Scope.py │ ├── String.py │ ├── Template.py │ ├── Term.py │ ├── Try.py │ ├── Variable.py │ └── __init__.py ├── parselib │ ├── Exception.py │ ├── Lexer.py │ ├── Token.py │ └── __init__.py ├── protocols │ ├── Dummy.py │ ├── Exception.py │ ├── OsGuesser.py │ ├── Protocol.py │ ├── SSH2.py │ ├── Telnet.py │ ├── __init__.py │ ├── drivers │ │ ├── __init__.py │ │ ├── ace.py │ │ ├── aironet.py │ │ ├── aix.py │ │ ├── arbor_peakflow.py │ │ ├── aruba.py │ │ ├── bigip.py │ │ ├── brocade.py │ │ ├── driver.py │ │ ├── enterasys.py │ │ ├── enterasys_wc.py │ │ ├── ericsson_ban.py │ │ ├── fortios.py │ │ ├── generic.py │ │ ├── hp_pro_curve.py │ │ ├── ios.py │ │ ├── ios_xr.py │ │ ├── isam.py │ │ ├── junos.py │ │ ├── junos_erx.py │ │ ├── nxos.py │ │ ├── one_os.py │ │ ├── shell.py │ │ ├── smart_edge_os.py │ │ ├── sros.py │ │ ├── vrp.py │ │ ├── vxworks.py │ │ └── zte.py │ └── telnetlib.py ├── servers │ ├── HTTPd.py │ ├── SSHd.py │ ├── Server.py │ ├── Telnetd.py │ └── __init__.py ├── stdlib │ ├── __init__.py │ ├── connection.py │ ├── crypt.py │ ├── file.py │ ├── ipv4.py │ ├── list.py │ ├── mysys.py │ ├── string.py │ └── util.py ├── util │ ├── __init__.py │ ├── buffer.py │ ├── cast.py │ ├── crypt.py │ ├── daemonize.py │ ├── decorator.py │ ├── event.py │ ├── file.py │ ├── impl.py │ ├── interact.py │ ├── ip.py │ ├── ipv4.py │ ├── ipv6.py │ ├── log.py │ ├── mail.py │ ├── match.py │ ├── pidutil.py │ ├── report.py │ ├── sigint.py │ ├── sigintcatcher.py │ ├── start.py │ ├── syslog.py │ ├── template.py │ ├── tty.py │ ├── url.py │ └── weakmethod.py ├── version.py └── workqueue │ ├── DBPipeline.py │ ├── Job.py │ ├── MainLoop.py │ ├── Pipeline.py │ ├── Task.py │ ├── WorkQueue.py │ └── __init__.py ├── LICENSE ├── README.md ├── climber.py ├── html ├── css │ ├── github.css │ └── report.css ├── images │ ├── minus.png │ └── plus.png └── javascripts │ ├── highlight.pack.js │ ├── jquery.collapsible.js │ ├── jquery.collapsible.min.js │ ├── jquery.cookie.js │ └── jquery.min.js ├── plugins ├── exploit │ └── shellshock ├── file_systems │ ├── df │ ├── fstab │ ├── mount │ ├── sgid │ ├── sticky_bit │ ├── suid │ ├── writable_dirs │ └── writable_files ├── networking │ ├── arp │ ├── hostname │ ├── ifconfig │ ├── interfaces │ ├── iptables │ ├── lsof │ ├── netstat │ ├── networks │ ├── resolv.conf │ └── route ├── operating_system │ ├── crontab │ ├── dpkg │ ├── env │ ├── issue │ ├── lsb-release │ ├── motd │ ├── os-release │ ├── ps │ ├── rpm │ ├── top │ └── uname ├── ssh │ ├── authorized_keys │ ├── id_dsa │ ├── id_dsa.pub │ ├── id_rsa │ ├── id_rsa.pub │ ├── identity │ └── identity.pub ├── users │ ├── bash_history │ ├── group │ ├── home │ ├── id │ ├── last │ ├── mail │ ├── passwd │ ├── root │ ├── shadow │ ├── sudo │ ├── sudoers │ ├── w │ └── who └── website │ ├── htdocs │ ├── html │ └── www ├── requirements.txt └── templates └── report.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | 21 | # Installer logs 22 | pip-log.txt 23 | 24 | # Unit test / coverage reports 25 | .coverage 26 | .tox 27 | nosetests.xml 28 | 29 | # Translations 30 | *.mo 31 | 32 | # Mr Developer 33 | .mr.developer.cfg 34 | .project 35 | .pydevproject 36 | -------------------------------------------------------------------------------- /Exscript/FileLogger.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Logging to the file system. 17 | """ 18 | import os 19 | from Exscript.Logfile import Logfile 20 | from Exscript.Logger import Logger 21 | 22 | class FileLogger(Logger): 23 | """ 24 | A Logger that stores logs into files. 25 | """ 26 | 27 | def __init__(self, 28 | logdir, 29 | mode = 'a', 30 | delete = False, 31 | clearmem = True): 32 | """ 33 | The logdir argument specifies the location where the logs 34 | are stored. The mode specifies whether to append the existing logs 35 | (if any). If delete is True, the logs are deleted after they are 36 | completed, unless they have an error in them. 37 | If clearmem is True, the logger does not store a reference to 38 | the log in it. If you want to use the functions from 39 | L{Exscript.util.report} with the logger, clearmem must be False. 40 | """ 41 | Logger.__init__(self) 42 | self.logdir = logdir 43 | self.mode = mode 44 | self.delete = delete 45 | self.clearmem = clearmem 46 | if not os.path.exists(self.logdir): 47 | os.mkdir(self.logdir) 48 | 49 | def add_log(self, job_id, name, attempt): 50 | if attempt > 1: 51 | name += '_retry%d' % (attempt - 1) 52 | filename = os.path.join(self.logdir, name + '.log') 53 | log = Logfile(name, filename, self.mode, self.delete) 54 | log.started() 55 | self.logs[job_id].append(log) 56 | return log 57 | 58 | def log_aborted(self, job_id, exc_info): 59 | Logger.log_aborted(self, job_id, exc_info) 60 | if self.clearmem: 61 | self.logs.pop(job_id) 62 | 63 | def log_succeeded(self, job_id): 64 | Logger.log_succeeded(self, job_id) 65 | if self.clearmem: 66 | self.logs.pop(job_id) 67 | -------------------------------------------------------------------------------- /Exscript/Log.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | from StringIO import StringIO 16 | from Exscript.util.impl import format_exception 17 | 18 | class Log(object): 19 | def __init__(self, name): 20 | self.name = name 21 | self.data = StringIO('') 22 | self.exc_info = None 23 | self.did_end = False 24 | 25 | def __str__(self): 26 | return self.data.getvalue() 27 | 28 | def __len__(self): 29 | return len(str(self)) 30 | 31 | def get_name(self): 32 | return self.name 33 | 34 | def write(self, *data): 35 | self.data.write(' '.join(data)) 36 | 37 | def get_error(self, include_tb = True): 38 | if self.exc_info is None: 39 | return None 40 | if include_tb: 41 | return format_exception(*self.exc_info) 42 | if str(self.exc_info[1]): 43 | return str(self.exc_info[1]) 44 | return self.exc_info[0].__name__ 45 | 46 | def started(self): 47 | """ 48 | Called by a logger to inform us that logging may now begin. 49 | """ 50 | self.did_end = False 51 | 52 | def aborted(self, exc_info): 53 | """ 54 | Called by a logger to log an exception. 55 | """ 56 | self.exc_info = exc_info 57 | self.did_end = True 58 | self.write(format_exception(*self.exc_info)) 59 | 60 | def succeeded(self): 61 | """ 62 | Called by a logger to inform us that logging is complete. 63 | """ 64 | self.did_end = True 65 | 66 | def has_error(self): 67 | return self.exc_info is not None 68 | 69 | def has_ended(self): 70 | return self.did_end 71 | -------------------------------------------------------------------------------- /Exscript/Logfile.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Represents the logfiles for one specific action. 17 | """ 18 | import os 19 | import errno 20 | from Exscript.Log import Log 21 | from Exscript.util.impl import format_exception 22 | 23 | class Logfile(Log): 24 | """ 25 | This class logs to two files: The raw log, and sometimes a separate 26 | log containing the error message with a traceback. 27 | """ 28 | 29 | def __init__(self, name, filename, mode = 'a', delete = False): 30 | Log.__init__(self, name) 31 | self.filename = filename 32 | self.errorname = filename + '.error' 33 | self.mode = mode 34 | self.delete = delete 35 | self.do_log = True 36 | dirname = os.path.dirname(filename) 37 | if dirname: 38 | try: 39 | os.mkdir(dirname) 40 | except OSError, e: 41 | if e.errno != errno.EEXIST: 42 | raise 43 | 44 | def __str__(self): 45 | data = '' 46 | if os.path.isfile(self.filename): 47 | with open(self.filename, 'r') as thefile: 48 | data += thefile.read() 49 | if os.path.isfile(self.errorname): 50 | with open(self.errorname, 'r') as thefile: 51 | data += thefile.read() 52 | return data 53 | 54 | def _write_file(self, filename, *data): 55 | if not self.do_log: 56 | return 57 | try: 58 | with open(filename, self.mode) as thefile: 59 | thefile.write(' '.join(data)) 60 | except Exception, e: 61 | print 'Error writing to %s: %s' % (filename, e) 62 | self.do_log = False 63 | raise 64 | 65 | def write(self, *data): 66 | return self._write_file(self.filename, *data) 67 | 68 | def _write_error(self, *data): 69 | return self._write_file(self.errorname, *data) 70 | 71 | def started(self): 72 | self.write('') # Creates the file. 73 | 74 | def aborted(self, exc_info): 75 | self.exc_info = exc_info 76 | self.did_end = True 77 | self.write('ERROR:', str(exc_info[1]), '\n') 78 | self._write_error(format_exception(*self.exc_info)) 79 | 80 | def succeeded(self): 81 | if self.delete and not self.has_error(): 82 | os.remove(self.filename) 83 | return 84 | Log.succeeded(self) 85 | -------------------------------------------------------------------------------- /Exscript/Logger.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Logging to memory. 17 | """ 18 | import weakref 19 | from itertools import chain, ifilter 20 | from collections import defaultdict 21 | from Exscript.Log import Log 22 | 23 | logger_registry = weakref.WeakValueDictionary() # Map id(logger) to Logger. 24 | 25 | class Logger(object): 26 | """ 27 | A QueueListener that implements logging for the queue. 28 | Logs are kept in memory, and not written to the disk. 29 | """ 30 | 31 | def __init__(self): 32 | """ 33 | Creates a new logger instance. Use the L{Exscript.util.log.log_to} 34 | decorator to send messages to the logger. 35 | """ 36 | logger_registry[id(self)] = self 37 | self.logs = defaultdict(list) 38 | self.started = 0 39 | self.success = 0 40 | self.failed = 0 41 | 42 | def _reset(self): 43 | self.logs = defaultdict(list) 44 | 45 | def get_succeeded_actions(self): 46 | """ 47 | Returns the number of jobs that were completed successfully. 48 | """ 49 | return self.success 50 | 51 | def get_aborted_actions(self): 52 | """ 53 | Returns the number of jobs that were aborted. 54 | """ 55 | return self.failed 56 | 57 | def get_logs(self): 58 | return list(chain.from_iterable(self.logs.itervalues())) 59 | 60 | def get_succeeded_logs(self): 61 | func = lambda x: x.has_ended() and not x.has_error() 62 | return list(ifilter(func, self.get_logs())) 63 | 64 | def get_aborted_logs(self): 65 | func = lambda x: x.has_ended() and x.has_error() 66 | return list(ifilter(func, self.get_logs())) 67 | 68 | def _get_log(self, job_id): 69 | return self.logs[job_id][-1] 70 | 71 | def add_log(self, job_id, name, attempt): 72 | log = Log(name) 73 | log.started() 74 | self.logs[job_id].append(log) 75 | self.started += 1 76 | return log 77 | 78 | def log(self, job_id, message): 79 | # This method is called whenever a sub thread sends a log message 80 | # via a pipe. (See LoggerProxy and Queue.PipeHandler) 81 | log = self._get_log(job_id) 82 | log.write(message) 83 | 84 | def log_aborted(self, job_id, exc_info): 85 | log = self._get_log(job_id) 86 | log.aborted(exc_info) 87 | self.failed += 1 88 | 89 | def log_succeeded(self, job_id): 90 | log = self._get_log(job_id) 91 | log.succeeded() 92 | self.success += 1 93 | -------------------------------------------------------------------------------- /Exscript/LoggerProxy.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | 16 | class LoggerProxy(object): 17 | """ 18 | An object that has a 1:1 relation to a Logger object in another 19 | process. 20 | """ 21 | def __init__(self, parent, logger_id): 22 | """ 23 | Constructor. 24 | 25 | @type parent: multiprocessing.Connection 26 | @param parent: A pipe to the associated pipe handler. 27 | """ 28 | self.parent = parent 29 | self.logger_id = logger_id 30 | 31 | def add_log(self, job_id, name, attempt): 32 | self.parent.send(('log-add', (self.logger_id, job_id, name, attempt))) 33 | response = self.parent.recv() 34 | if isinstance(response, Exception): 35 | raise response 36 | return response 37 | 38 | def log(self, job_id, message): 39 | self.parent.send(('log-message', (self.logger_id, job_id, message))) 40 | 41 | def log_aborted(self, job_id, exc_info): 42 | self.parent.send(('log-aborted', (self.logger_id, job_id, exc_info))) 43 | 44 | def log_succeeded(self, job_id): 45 | self.parent.send(('log-succeeded', (self.logger_id, job_id))) 46 | -------------------------------------------------------------------------------- /Exscript/PrivateKey.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2011 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Represents a private key. 17 | """ 18 | from paramiko import RSAKey, DSSKey 19 | from paramiko.ssh_exception import SSHException 20 | 21 | class PrivateKey(object): 22 | """ 23 | Represents a cryptographic key, and may be used to authenticate 24 | useing L{Exscript.protocols}. 25 | """ 26 | keytypes = set() 27 | 28 | def __init__(self, keytype = 'rsa'): 29 | """ 30 | Constructor. Supported key types are provided by their respective 31 | protocol adapters and can be retrieved from the PrivateKey.keytypes 32 | class attribute. 33 | 34 | @type keytype: string 35 | @param keytype: The key type. 36 | """ 37 | if keytype not in self.keytypes: 38 | raise TypeError('unsupported key type: ' + repr(keytype)) 39 | self.keytype = keytype 40 | self.filename = None 41 | self.password = None 42 | 43 | @staticmethod 44 | def from_file(filename, password = '', keytype = None): 45 | """ 46 | Returns a new PrivateKey instance with the given attributes. 47 | If keytype is None, we attempt to automatically detect the type. 48 | 49 | @type filename: string 50 | @param filename: The key file name. 51 | @type password: string 52 | @param password: The key password. 53 | @type keytype: string 54 | @param keytype: The key type. 55 | @rtype: PrivateKey 56 | @return: The new key. 57 | """ 58 | if keytype is None: 59 | try: 60 | key = RSAKey.from_private_key_file(filename) 61 | keytype = 'rsa' 62 | except SSHException, e: 63 | try: 64 | key = DSSKey.from_private_key_file(filename) 65 | keytype = 'dss' 66 | except SSHException, e: 67 | msg = 'not a recognized private key: ' + repr(filename) 68 | raise ValueError(msg) 69 | key = PrivateKey(keytype) 70 | key.filename = filename 71 | key.password = password 72 | return key 73 | 74 | def get_type(self): 75 | """ 76 | Returns the type of the key, e.g. RSA or DSA. 77 | 78 | @rtype: string 79 | @return: The key type 80 | """ 81 | return self.keytype 82 | 83 | def set_filename(self, filename): 84 | """ 85 | Sets the name of the key file to use. 86 | 87 | @type filename: string 88 | @param filename: The key filename. 89 | """ 90 | self.filename = filename 91 | 92 | def get_filename(self): 93 | """ 94 | Returns the name of the key file. 95 | 96 | @rtype: string 97 | @return: The key password. 98 | """ 99 | return self.filename 100 | 101 | def set_password(self, password): 102 | """ 103 | Defines the password used for decrypting the key. 104 | 105 | @type password: string 106 | @param password: The key password. 107 | """ 108 | self.password = password 109 | 110 | def get_password(self): 111 | """ 112 | Returns the password for the key. 113 | 114 | @rtype: string 115 | @return: The key password. 116 | """ 117 | return self.password 118 | -------------------------------------------------------------------------------- /Exscript/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | The core module. 17 | """ 18 | import warnings 19 | with warnings.catch_warnings(): 20 | warnings.filterwarnings('ignore', category = DeprecationWarning) 21 | import paramiko 22 | from Exscript.version import __version__ 23 | from Exscript.Account import Account 24 | from Exscript.AccountPool import AccountPool 25 | from Exscript.PrivateKey import PrivateKey 26 | from Exscript.Queue import Queue 27 | from Exscript.Host import Host 28 | from Exscript.Logger import Logger 29 | from Exscript.FileLogger import FileLogger 30 | 31 | import inspect 32 | __all__ = [name for name, obj in locals().items() 33 | if not (name.startswith('_') or inspect.ismodule(obj))] 34 | -------------------------------------------------------------------------------- /Exscript/emulators/CommandSet.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Defines the behavior of commands by mapping commands to functions. 17 | """ 18 | import re 19 | 20 | class CommandSet(object): 21 | """ 22 | A set of commands to be used by the Dummy adapter. 23 | """ 24 | 25 | def __init__(self, strict = True): 26 | """ 27 | Constructor. 28 | """ 29 | self.strict = strict 30 | self.response_list = [] 31 | 32 | def add(self, command, response): 33 | """ 34 | Register a command/response pair. 35 | 36 | The command may be either a string (which is then automatically 37 | compiled into a regular expression), or a pre-compiled regular 38 | expression object. 39 | 40 | If the given response handler is a string, it is sent as the 41 | response to any command that matches the given regular expression. 42 | If the given response handler is a function, it is called 43 | with the command passed as an argument. 44 | 45 | @type command: str|regex 46 | @param command: A string or a compiled regular expression. 47 | @type response: function|str 48 | @param response: A reponse, or a response handler. 49 | """ 50 | if isinstance(command, str): 51 | command = re.compile(command) 52 | elif not hasattr(command, 'search'): 53 | raise TypeError('command argument must be str or a regex') 54 | self.response_list.append((command, response)) 55 | 56 | def add_from_file(self, filename, handler_decorator = None): 57 | """ 58 | Wrapper around add() that reads the handlers from the 59 | file with the given name. The file is a Python script containing 60 | a list named 'commands' of tuples that map command names to 61 | handlers. 62 | 63 | @type filename: str 64 | @param filename: The name of the file containing the tuples. 65 | @type handler_decorator: function 66 | @param handler_decorator: A function that is used to decorate 67 | each of the handlers in the file. 68 | """ 69 | args = {} 70 | execfile(filename, args) 71 | commands = args.get('commands') 72 | if commands is None: 73 | raise Exception(filename + ' has no variable named "commands"') 74 | elif not hasattr(commands, '__iter__'): 75 | raise Exception(filename + ': "commands" is not iterable') 76 | for key, handler in commands: 77 | if handler_decorator: 78 | handler = handler_decorator(handler) 79 | self.add(key, handler) 80 | 81 | def eval(self, command): 82 | """ 83 | Evaluate the given string against all registered commands and 84 | return the defined response. 85 | 86 | @type command: str 87 | @param command: The command that is evaluated. 88 | @rtype: str or None 89 | @return: The response, if one was defined. 90 | """ 91 | for cmd, response in self.response_list: 92 | if not cmd.match(command): 93 | continue 94 | if response is None: 95 | return None 96 | elif isinstance(response, str): 97 | return response 98 | else: 99 | return response(command) 100 | if self.strict: 101 | raise Exception('Undefined command: ' + repr(command)) 102 | return None 103 | -------------------------------------------------------------------------------- /Exscript/emulators/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Emulating a device for testing your scripts. 17 | """ 18 | from Exscript.emulators.CommandSet import CommandSet 19 | from Exscript.emulators.VirtualDevice import VirtualDevice 20 | from Exscript.emulators.IOSEmulator import IOSEmulator 21 | 22 | import inspect 23 | __all__ = [name for name, obj in locals().items() 24 | if not (name.startswith('_') or inspect.ismodule(obj))] 25 | -------------------------------------------------------------------------------- /Exscript/external/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Python modules that are maintained by third party developers. 3 | """ 4 | -------------------------------------------------------------------------------- /Exscript/external/otp/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ['otp'], 2 | 3 | from otp import generate 4 | -------------------------------------------------------------------------------- /Exscript/external/otp/keywrangling.py: -------------------------------------------------------------------------------- 1 | """ 2 | PyOTP, the Python One-Time Password module. 3 | 4 | keywrangling.py: key handling routines for the otp module. 5 | 6 | 7 | """ 8 | 9 | __version__ = '$Revision: 1.4 $' 10 | 11 | import types 12 | from AppendixB import DefaultDictionary, WordFromNumber, NumberFromWord 13 | 14 | def keyformat(key): 15 | """Return the type of a key or list of keys (all of which must 16 | be in the same format). 17 | 18 | Result: 'sixword', 'hex', 'long', 'raw', or None for an 19 | unrecognised key format. 20 | 21 | LIMITATIONS: This routine doesn't go to nearly enough effort 22 | to double- and triple-check key types. For example, any string 23 | of length 16 will be treated as a hex key. More checks should 24 | be added in the future.""" 25 | 26 | if type(key) == types.ListType: 27 | return keyformat(key[0]) 28 | if type(key) == types.LongType: 29 | return 'long' 30 | elif type(key) == types.StringType: 31 | if len(key) == 8: 32 | return 'raw' 33 | elif len(key) == 19 and len(key.split(' ')) == 4: 34 | return 'hex' 35 | elif len(key.split(' ')) == 6: 36 | return 'sixword' 37 | else: 38 | return None 39 | else: 40 | return None 41 | 42 | def long_from_raw(hash): 43 | """Fold to a long, a digest supplied as a string.""" 44 | 45 | hashnum = 0L 46 | for h in hash: 47 | hashnum <<= 8 48 | hashnum |= ord(h) 49 | 50 | return hashnum 51 | 52 | def sixword_from_raw(key, dictionary=DefaultDictionary): 53 | return sixword_from_long(long_from_raw(key), dictionary) 54 | 55 | def sixword_from_hex(key, dictionary=DefaultDictionary): 56 | return sixword_from_long(long_from_hex(key), dictionary) 57 | 58 | def hex_from_long(key): 59 | k = '%016x' % key 60 | return ' '.join( [ k[0:4], k[4:8], k[8:12], k[12:16] ] ).upper() 61 | 62 | def hex_from_raw(key): 63 | return hex_from_long(long_from_raw(key)) 64 | 65 | def hex_from_sixword(key): 66 | return hex_from_long(long_from_sixword(key)) 67 | 68 | def long_from_hex(key): 69 | return long(''.join(key.split(' ')).lower(), 16) 70 | 71 | def checksummed_long(key): 72 | sum, k = 0, key 73 | for i in range(0, 32): 74 | sum = sum + ( k % 4 ) 75 | k = k >> 2 76 | return ( key << 2 ) | ( sum % 4 ) 77 | 78 | def sixword_from_long(key, dictionary=DefaultDictionary): 79 | key = checksummed_long(key) 80 | 81 | words = [] 82 | for i in range(0,6): 83 | words = [dictionary[key % 2048]] + words 84 | key = key >> 11 85 | return ' '.join(words) 86 | 87 | def long_from_sixword(key): 88 | # no alternative dictionary format yet! 89 | words = key.split(' ') 90 | for w in words: 91 | wordIndex = NumberFromWord(w) 92 | try: 93 | wordCheck = WordFromNumber(wordIndex) 94 | except: 95 | wordCheck = None 96 | print wordIndex, wordCheck 97 | 98 | _KEYCONVERSIONTABLE = { 99 | 'sixword' : { 'raw' : sixword_from_raw , 100 | 'long' : sixword_from_long , 101 | 'hex' : sixword_from_hex }, 102 | 'long' : { 'raw' : long_from_raw , 103 | 'sixword' : long_from_sixword, 104 | 'hex' : long_from_hex }, 105 | 'hex' : { 'raw' : hex_from_raw , 106 | 'sixword' : hex_from_sixword, 107 | 'long' : hex_from_long } 108 | } 109 | 110 | def convertkey(format, key_or_keylist): 111 | """Convert a key or a list of keys from one format to another. 112 | 113 | format -- 'sixword', 'hex', or 'long' 114 | key_or_keylist -- either a key, or a list of keys ALL OF THE 115 | SAME FORMAT.""" 116 | 117 | originalformat = keyformat(key_or_keylist) 118 | if originalformat == format: # just in case! 119 | return key_or_keylist 120 | 121 | conversionfunction = _KEYCONVERSIONTABLE[format][originalformat] 122 | if type(key_or_keylist) == types.ListType: 123 | return map(conversionfunction, key_or_keylist) 124 | else: 125 | return conversionfunction(key_or_keylist) 126 | -------------------------------------------------------------------------------- /Exscript/interpreter/Append.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | from Exscript.parselib import Token 16 | from Exscript.interpreter.Term import Term 17 | 18 | class Append(Token): 19 | def __init__(self, lexer, parser, parent): 20 | Token.__init__(self, 'Append', lexer, parser, parent) 21 | 22 | # First expect an expression. 23 | lexer.expect(self, 'keyword', 'append') 24 | lexer.expect(self, 'whitespace') 25 | self.expr = Term(lexer, parser, parent) 26 | 27 | # Expect "to" keyword. 28 | lexer.expect(self, 'whitespace') 29 | lexer.expect(self, 'keyword', 'to') 30 | 31 | # Expect a variable name. 32 | lexer.expect(self, 'whitespace') 33 | _, self.varname = lexer.token() 34 | lexer.expect(self, 'varname') 35 | self.parent.define(**{self.varname: []}) 36 | 37 | self.mark_end() 38 | 39 | def value(self, context): 40 | existing = self.parent.get(self.varname) 41 | args = {self.varname: existing + self.expr.value(context)} 42 | self.parent.define(**args) 43 | return 1 44 | 45 | def dump(self, indent = 0): 46 | print (' ' * indent) + self.name, "to", self.varname 47 | self.expr.dump(indent + 1) 48 | -------------------------------------------------------------------------------- /Exscript/interpreter/Assign.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | import Expression 16 | from Exscript.parselib import Token 17 | 18 | class Assign(Token): 19 | def __init__(self, lexer, parser, parent): 20 | Token.__init__(self, 'Assign', lexer, parser, parent) 21 | 22 | # Extract the variable name. 23 | _, self.varname = lexer.token() 24 | lexer.expect(self, 'varname') 25 | lexer.expect(self, 'whitespace') 26 | lexer.expect(self, 'assign') 27 | lexer.expect(self, 'whitespace') 28 | 29 | if self.varname.startswith('__'): 30 | msg = 'Assignment to internal variable ' + self.varname 31 | lexer.syntax_error(msg, self) 32 | 33 | self.expression = Expression.Expression(lexer, parser, parent) 34 | self.parent.define(**{self.varname: None}) 35 | 36 | 37 | def dump(self, indent = 0): 38 | print (' ' * indent) + self.name, self.varname, 'start' 39 | self.expression.dump(indent + 1) 40 | print (' ' * indent) + self.name, self.varname, 'start' 41 | 42 | def value(self, context): 43 | result = self.expression.value(context) 44 | self.parent.define(**{self.varname: result}) 45 | return result 46 | -------------------------------------------------------------------------------- /Exscript/interpreter/Enter.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | from Exscript.parselib import Token 16 | from Exscript.interpreter.Execute import Execute 17 | 18 | class Enter(Token): 19 | def __init__(self, lexer, parser, parent): 20 | Token.__init__(self, 'Enter', lexer, parser, parent) 21 | 22 | lexer.expect(self, 'keyword', 'enter') 23 | lexer.skip(['whitespace', 'newline']) 24 | 25 | self.execute = Execute(lexer, parser, parent, '') 26 | 27 | def value(self, context): 28 | return self.execute.value(context) 29 | 30 | def dump(self, indent = 0): 31 | print (' ' * indent) + self.name 32 | self.execute.dump(indent + 1) 33 | -------------------------------------------------------------------------------- /Exscript/interpreter/Exception.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | class ExscriptException(Exception): 16 | pass 17 | 18 | class FailException(ExscriptException): 19 | """ 20 | This exception type is used if the "fail" command was used in a template. 21 | """ 22 | pass 23 | 24 | class PermissionError(ExscriptException): 25 | """ 26 | Raised if an insecure function was called when the parser is in secure 27 | mode. 28 | """ 29 | pass 30 | -------------------------------------------------------------------------------- /Exscript/interpreter/Execute.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | from Exscript.parselib import Token 16 | from Exscript.interpreter.String import String, string_re 17 | 18 | class Execute(String): 19 | def __init__(self, lexer, parser, parent, command): 20 | Token.__init__(self, 'Execute', lexer, parser, parent) 21 | self.string = command 22 | self.no_prompt = parser.no_prompt 23 | self.strip_command = parser.strip_command 24 | 25 | # The lexer has parsed the command, including a newline. 26 | # Make the debugger point to the beginning of the command. 27 | self.start -= len(command) + 1 28 | self.mark_end(self.start + len(command)) 29 | 30 | # Make sure that any variables specified in the command are declared. 31 | string_re.sub(self.variable_test_cb, command) 32 | self.parent.define(__response__ = []) 33 | 34 | def value(self, context): 35 | if not self.parent.is_defined('__connection__'): 36 | error = 'Undefined variable "__connection__"' 37 | self.lexer.runtime_error(error, self) 38 | conn = self.parent.get('__connection__') 39 | 40 | # Substitute variables in the command for values. 41 | command = string_re.sub(self.variable_sub_cb, self.string) 42 | command = command.lstrip() 43 | 44 | # Execute the command. 45 | if self.no_prompt: 46 | conn.send(command + '\r') 47 | response = '' 48 | else: 49 | conn.execute(command) 50 | response = conn.response.replace('\r\n', '\n') 51 | response = response.replace('\r', '\n').split('\n') 52 | 53 | if self.strip_command: 54 | response = response[1:] 55 | if len(response) == 0: 56 | response = [''] 57 | 58 | self.parent.define(__response__ = response) 59 | return 1 60 | 61 | 62 | def dump(self, indent = 0): 63 | print (' ' * indent) + self.name, self.string 64 | -------------------------------------------------------------------------------- /Exscript/interpreter/Expression.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | from Exscript.parselib import Token 16 | from Exscript.interpreter.ExpressionNode import ExpressionNode 17 | 18 | class Expression(Token): 19 | def __init__(self, lexer, parser, parent): 20 | Token.__init__(self, 'Expression', lexer, parser, parent) 21 | 22 | # Parse the expression. 23 | self.root = ExpressionNode(lexer, parser, parent) 24 | 25 | # Reorder the tree according to the operator priorities. 26 | self.prioritize(self.root) 27 | self.mark_end() 28 | 29 | 30 | def prioritize(self, start, prio = 1): 31 | #print "Prioritizing from", start.op, "with prio", prio, (start.lft, start.rgt) 32 | if prio == 6: 33 | return 34 | root = start 35 | while root is not None and root.priority() <= prio: 36 | root = root.rgt 37 | if root is None: 38 | self.prioritize(start, prio + 1) 39 | return 40 | 41 | # Find the next node that has the current priority. 42 | previous = root 43 | current = root.rgt 44 | while current is not None and current.priority() != prio: 45 | previous = current 46 | current = current.rgt 47 | if current is None: 48 | self.prioritize(start, prio + 1) 49 | return 50 | 51 | # Reparent the expressions. 52 | #print "Prio of", root.op, 'is higher than', current.op 53 | previous.rgt = current.lft 54 | current.lft = root 55 | 56 | # Change the pointer of the parent of the root node. 57 | # If this was the root of the entire tree we need to change that as 58 | # well. 59 | if root.parent_node is None: 60 | self.root = current 61 | elif root.parent_node.lft == root: 62 | root.parent_node.lft = current 63 | elif root.parent_node.rgt == root: 64 | root.parent_node.rgt = current 65 | 66 | root.parent_node = current 67 | 68 | # Go ahead prioritizing the children. 69 | self.prioritize(current.lft, prio + 1) 70 | self.prioritize(current.rgt, prio) 71 | 72 | def value(self, context): 73 | return self.root.value(context) 74 | 75 | def dump(self, indent = 0): 76 | print (' ' * indent) + self.name, 'start' 77 | self.root.dump(indent + 1) 78 | print (' ' * indent) + self.name, 'end.' 79 | -------------------------------------------------------------------------------- /Exscript/interpreter/Fail.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | from Exscript.parselib import Token 16 | from Exscript.interpreter.Expression import Expression 17 | from Exscript.interpreter.Exception import FailException 18 | 19 | class Fail(Token): 20 | def __init__(self, lexer, parser, parent): 21 | Token.__init__(self, 'Fail', lexer, parser, parent) 22 | self.expression = None 23 | 24 | # "fail" keyword. 25 | lexer.expect(self, 'keyword', 'fail') 26 | lexer.expect(self, 'whitespace') 27 | self.msg = Expression(lexer, parser, parent) 28 | 29 | # 'If' keyword with an expression. 30 | #token = lexer.token() 31 | if lexer.next_if('keyword', 'if'): 32 | lexer.expect(self, 'whitespace') 33 | self.expression = Expression(lexer, parser, parent) 34 | 35 | # End of expression. 36 | self.mark_end() 37 | lexer.skip(['whitespace', 'newline']) 38 | 39 | def value(self, context): 40 | if self.expression is None or self.expression.value(context)[0]: 41 | raise FailException(self.msg.value(context)[0]) 42 | return 1 43 | 44 | def dump(self, indent = 0): 45 | print (' ' * indent) + self.name, 'start' 46 | self.msg.dump(indent + 1) 47 | self.expression.dump(indent + 1) 48 | print (' ' * indent) + self.name, 'end.' 49 | -------------------------------------------------------------------------------- /Exscript/interpreter/FunctionCall.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | import Expression 16 | from Exscript.parselib import Token 17 | from Exscript.interpreter.Exception import PermissionError 18 | 19 | class FunctionCall(Token): 20 | def __init__(self, lexer, parser, parent): 21 | Token.__init__(self, 'FunctionCall', lexer, parser, parent) 22 | self.funcname = None 23 | self.arguments = [] 24 | 25 | # Extract the function name. 26 | _, token = lexer.token() 27 | lexer.expect(self, 'open_function_call') 28 | self.funcname = token[:-1] 29 | function = self.parent.get(self.funcname) 30 | if function is None: 31 | lexer.syntax_error('Undefined function %s' % self.funcname, self) 32 | 33 | # Parse the argument list. 34 | _, token = lexer.token() 35 | while 1: 36 | if lexer.next_if('close_bracket'): 37 | break 38 | self.arguments.append(Expression.Expression(lexer, parser, parent)) 39 | ttype, token = lexer.token() 40 | if not lexer.next_if('comma') and not lexer.current_is('close_bracket'): 41 | error = 'Expected separator or argument list end but got %s' 42 | lexer.syntax_error(error % ttype, self) 43 | 44 | if parser.secure_only and not hasattr(function, '_is_secure'): 45 | msg = 'Use of insecure function %s is not permitted' % self.funcname 46 | lexer.error(msg, self, PermissionError) 47 | 48 | self.mark_end() 49 | 50 | def dump(self, indent = 0): 51 | print (' ' * indent) + self.name, self.funcname, 'start' 52 | for argument in self.arguments: 53 | argument.dump(indent + 1) 54 | print (' ' * indent) + self.name, self.funcname, 'end.' 55 | 56 | def value(self, context): 57 | argument_values = [arg.value(context) for arg in self.arguments] 58 | function = self.parent.get(self.funcname) 59 | if function is None: 60 | self.lexer.runtime_error('Undefined function %s' % self.funcname, self) 61 | return function(self.parent, *argument_values) 62 | -------------------------------------------------------------------------------- /Exscript/interpreter/IfCondition.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | import Code 16 | from Exscript.parselib import Token 17 | from Exscript.interpreter.Expression import Expression 18 | 19 | class IfCondition(Token): 20 | def __init__(self, lexer, parser, parent): 21 | Token.__init__(self, 'If-condition', lexer, parser, parent) 22 | 23 | # Expect an expression. 24 | lexer.expect(self, 'keyword', 'if') 25 | lexer.expect(self, 'whitespace') 26 | self.expression = Expression(lexer, parser, parent) 27 | self.mark_end() 28 | 29 | # Body of the if block. 30 | self.if_block = Code.Code(lexer, parser, parent) 31 | self.elif_blocks = [] 32 | self.else_block = None 33 | 34 | # If there is no "else" statement, just return. 35 | lexer.skip(['whitespace', 'newline']) 36 | if not lexer.next_if('keyword', 'else'): 37 | return 38 | 39 | # If the "else" statement is followed by an "if" (=elif), 40 | # read the next if condition recursively and return. 41 | lexer.skip(['whitespace', 'newline']) 42 | if lexer.current_is('keyword', 'if'): 43 | self.else_block = IfCondition(lexer, parser, parent) 44 | return 45 | 46 | # There was no "elif", so we handle a normal "else" condition here. 47 | self.else_block = Code.Code(lexer, parser, parent) 48 | 49 | def value(self, context): 50 | if self.expression.value(context)[0]: 51 | self.if_block.value(context) 52 | elif self.else_block is not None: 53 | self.else_block.value(context) 54 | return 1 55 | 56 | 57 | def dump(self, indent = 0): 58 | print (' ' * indent) + self.name, 'start' 59 | self.expression.dump(indent + 1) 60 | self.if_block.dump(indent + 1) 61 | if self.else_block is not None: 62 | self.else_block.dump(indent + 1) 63 | print (' ' * indent) + self.name, 'end.' 64 | -------------------------------------------------------------------------------- /Exscript/interpreter/Number.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | class Number(object): 16 | def __init__(self, number): 17 | self.number = int(number) 18 | 19 | def value(self, context): 20 | return [self.number] 21 | 22 | def dump(self, indent = 0): 23 | print (' ' * indent) + 'Number', self.number 24 | -------------------------------------------------------------------------------- /Exscript/interpreter/Parser.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | import copy 16 | from Exscript.parselib import Lexer 17 | from Exscript.interpreter.Program import Program 18 | 19 | class Parser(object): 20 | def __init__(self, **kwargs): 21 | self.no_prompt = kwargs.get('no_prompt', False) 22 | self.strip_command = kwargs.get('strip_command', True) 23 | self.secure_only = kwargs.get('secure', False) 24 | self.debug = kwargs.get('debug', 0) 25 | self.variables = {} 26 | 27 | def define(self, **kwargs): 28 | for key, value in kwargs.iteritems(): 29 | if hasattr(value, '__iter__') or hasattr(value, '__call__'): 30 | self.variables[key] = value 31 | else: 32 | self.variables[key] = [value] 33 | 34 | def define_object(self, **kwargs): 35 | self.variables.update(kwargs) 36 | 37 | def _create_lexer(self): 38 | variables = copy.deepcopy(self.variables) 39 | return Lexer(Program, self, variables, debug = self.debug) 40 | 41 | def parse(self, string, filename = None): 42 | lexer = self._create_lexer() 43 | return lexer.parse(string, filename) 44 | 45 | def parse_file(self, filename): 46 | lexer = self._create_lexer() 47 | return lexer.parse_file(filename) 48 | 49 | if __name__ == "__main__": 50 | import sys 51 | if len(sys.argv) == 1: 52 | filename = 'test.exscript' 53 | elif len(sys.argv) == 2: 54 | filename = sys.argv[1] 55 | else: 56 | sys.exit(1) 57 | parser = Parser(debug = 5) 58 | compiled = parser.parse_file(filename) 59 | compiled.dump() 60 | -------------------------------------------------------------------------------- /Exscript/interpreter/Program.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | import copy 16 | from Exscript.interpreter.Template import Template 17 | from Exscript.interpreter.Scope import Scope 18 | 19 | class Program(Scope): 20 | def __init__(self, lexer, parser, variables, **kwargs): 21 | Scope.__init__(self, 'Program', lexer, parser, None, **kwargs) 22 | self.variables = variables 23 | self.init_variables = variables 24 | self.add(Template(lexer, parser, self)) 25 | 26 | def init(self, *args, **kwargs): 27 | for key in kwargs: 28 | if key.find('.') >= 0 or key.startswith('_'): 29 | continue 30 | if type(kwargs[key]) == type([]): 31 | self.init_variables[key] = kwargs[key] 32 | else: 33 | self.init_variables[key] = [kwargs[key]] 34 | 35 | def execute(self, *args, **kwargs): 36 | self.variables = copy.copy(self.init_variables) 37 | if 'variables' in kwargs: 38 | self.variables.update(kwargs.get('variables')) 39 | self.value(self) 40 | return self.variables 41 | -------------------------------------------------------------------------------- /Exscript/interpreter/Regex.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | import re 16 | from Exscript.interpreter.String import String 17 | 18 | # Matches any opening parenthesis that is neither preceeded by a backslash 19 | # nor has a "?:" or "?<" appended. 20 | bracket_re = re.compile(r'(?= 0 or key.startswith('_') \ 36 | or type(kwargs[key]) == type([]): 37 | self.variables[key] = kwargs[key] 38 | else: 39 | self.variables[key] = [kwargs[key]] 40 | 41 | def define_object(self, **kwargs): 42 | self.variables.update(kwargs) 43 | 44 | def is_defined(self, name): 45 | if name in self.variables: 46 | return 1 47 | if self.parent is not None: 48 | return self.parent.is_defined(name) 49 | return 0 50 | 51 | def get_vars(self): 52 | """ 53 | Returns a complete dict of all variables that are defined in this 54 | scope, including the variables of the parent. 55 | """ 56 | if self.parent is None: 57 | vars = {} 58 | vars.update(self.variables) 59 | return vars 60 | vars = self.parent.get_vars() 61 | vars.update(self.variables) 62 | return vars 63 | 64 | def copy_public_vars(self): 65 | """ 66 | Like get_vars(), but does not include any private variables and 67 | deep copies each variable. 68 | """ 69 | vars = self.get_vars() 70 | vars = dict([k for k in vars.iteritems() if not k[0].startswith('_')]) 71 | return deepcopy(vars) 72 | 73 | def get(self, name, default = None): 74 | if name in self.variables: 75 | return self.variables[name] 76 | if self.parent is None: 77 | return default 78 | return self.parent.get(name, default) 79 | 80 | def value(self, context): 81 | result = 1 82 | for child in self.children: 83 | result = child.value(context) 84 | return result 85 | 86 | def dump(self, indent = 0): 87 | print (' ' * indent) + self.name, 'start' 88 | for child in self.children: 89 | child.dump(indent + 1) 90 | print (' ' * indent) + self.name, 'end' 91 | 92 | def dump1(self): 93 | if self.parent is not None: 94 | self.parent.dump1() 95 | return 96 | print "Scope:", self.variables 97 | -------------------------------------------------------------------------------- /Exscript/interpreter/Template.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | import re 16 | from Exscript.interpreter.Scope import Scope 17 | from Exscript.interpreter.Code import Code 18 | from Exscript.interpreter.Execute import Execute 19 | 20 | grammar = ( 21 | ('escaped_data', r'\\.'), 22 | ('open_curly_bracket', '{'), 23 | ('close_curly_bracket', '}'), 24 | ('newline', r'[\r\n]'), 25 | ('raw_data', r'[^\r\n{}\\]+') 26 | ) 27 | 28 | grammar_c = [] 29 | for thetype, regex in grammar: 30 | grammar_c.append((thetype, re.compile(regex))) 31 | 32 | class Template(Scope): 33 | def __init__(self, lexer, parser, parent, *args, **kwargs): 34 | Scope.__init__(self, 'Template', lexer, parser, parent, **kwargs) 35 | lexer.set_grammar(grammar_c) 36 | #print "Opening Scope:", lexer.token() 37 | buffer = '' 38 | while 1: 39 | if self.exit_requested or lexer.current_is('EOF'): 40 | break 41 | elif lexer.next_if('open_curly_bracket'): 42 | if buffer.strip() != '': 43 | self.add(Execute(lexer, parser, self, buffer)) 44 | buffer = '' 45 | if isinstance(parent, Code): 46 | break 47 | self.add(Code(lexer, parser, self)) 48 | elif lexer.current_is('raw_data'): 49 | if lexer.token()[1].lstrip().startswith('#'): 50 | while not lexer.current_is('newline'): 51 | lexer.next() 52 | continue 53 | buffer += lexer.token()[1] 54 | lexer.next() 55 | elif lexer.current_is('escaped_data'): 56 | token = lexer.token()[1] 57 | if token[1] == '$': 58 | # An escaped $ is handeled by the Execute() token, so 59 | # we do not strip the \ here. 60 | buffer += token 61 | else: 62 | buffer += token[1] 63 | lexer.next() 64 | elif lexer.next_if('newline'): 65 | if buffer.strip() != '': 66 | self.add(Execute(lexer, parser, self, buffer)) 67 | buffer = '' 68 | else: 69 | ttype = lexer.token()[0] 70 | lexer.syntax_error('Unexpected %s' % ttype, self) 71 | lexer.restore_grammar() 72 | 73 | def execute(self): 74 | return self.value(self) 75 | -------------------------------------------------------------------------------- /Exscript/interpreter/Term.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | from Exscript.parselib import Token 16 | from Exscript.interpreter.Variable import Variable 17 | from Exscript.interpreter.Number import Number 18 | from Exscript.interpreter.FunctionCall import FunctionCall 19 | from Exscript.interpreter.String import String 20 | from Exscript.interpreter.Regex import Regex 21 | 22 | class Term(Token): 23 | def __init__(self, lexer, parser, parent): 24 | Token.__init__(self, 'Term', lexer, parser, parent) 25 | self.term = None 26 | self.lft = None 27 | self.rgt = None 28 | self.op = None 29 | 30 | # Expect a term. 31 | ttype, token = lexer.token() 32 | if lexer.current_is('varname'): 33 | if not parent.is_defined(token): 34 | lexer.error('Undeclared variable %s' % token, self, ValueError) 35 | self.term = Variable(lexer, parser, parent) 36 | elif lexer.current_is('open_function_call'): 37 | self.term = FunctionCall(lexer, parser, parent) 38 | elif lexer.current_is('string_delimiter'): 39 | self.term = String(lexer, parser, parent) 40 | elif lexer.next_if('number'): 41 | self.term = Number(token) 42 | elif lexer.next_if('keyword', 'false'): 43 | self.term = Number(0) 44 | elif lexer.next_if('keyword', 'true'): 45 | self.term = Number(1) 46 | elif lexer.next_if('octal_number'): 47 | self.term = Number(int(token[1:], 8)) 48 | elif lexer.next_if('hex_number'): 49 | self.term = Number(int(token[2:], 16)) 50 | elif lexer.current_is('regex_delimiter'): 51 | self.term = Regex(lexer, parser, parent) 52 | else: 53 | lexer.syntax_error('Expected term but got %s' % ttype, self) 54 | self.mark_end() 55 | 56 | def priority(self): 57 | return 6 58 | 59 | def value(self, context): 60 | return self.term.value(context) 61 | 62 | def dump(self, indent = 0): 63 | print (' ' * indent) + self.name 64 | self.term.dump(indent + 1) 65 | -------------------------------------------------------------------------------- /Exscript/interpreter/Try.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | import Code 16 | from Exscript.protocols.Exception import ProtocolException 17 | from Exscript.interpreter.Scope import Scope 18 | 19 | class Try(Scope): 20 | def __init__(self, lexer, parser, parent): 21 | Scope.__init__(self, 'Try', lexer, parser, parent) 22 | 23 | lexer.next_if('whitespace') 24 | lexer.expect(self, 'keyword', 'try') 25 | lexer.skip(['whitespace', 'newline']) 26 | self.block = Code.Code(lexer, parser, parent) 27 | 28 | def value(self, context): 29 | try: 30 | self.block.value(context) 31 | except ProtocolException, e: 32 | return 1 33 | return 1 34 | 35 | def dump(self, indent = 0): 36 | print (' ' * indent) + self.name, 'start' 37 | self.block.dump(indent + 1) 38 | print (' ' * indent) + self.name, 'end' 39 | -------------------------------------------------------------------------------- /Exscript/interpreter/Variable.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | from Exscript.parselib import Token 16 | 17 | class Variable(Token): 18 | def __init__(self, lexer, parser, parent): 19 | Token.__init__(self, 'Variable', lexer, parser, parent) 20 | self.varname = lexer.token()[1] 21 | lexer.expect(self, 'varname') 22 | self.mark_end() 23 | 24 | def value(self, context): 25 | val = self.parent.get(self.varname) 26 | if val is None: 27 | msg = 'Undefined variable %s' % self.varname 28 | self.lexer.runtime_error(msg, self) 29 | return val 30 | 31 | def dump(self, indent = 0): 32 | print (' ' * indent) + 'Variable', self.varname, '.' 33 | -------------------------------------------------------------------------------- /Exscript/interpreter/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | from Exscript.interpreter.Parser import Parser 16 | 17 | import inspect 18 | __all__ = [name for name, obj in locals().items() 19 | if not (name.startswith('_') or inspect.ismodule(obj))] 20 | -------------------------------------------------------------------------------- /Exscript/parselib/Exception.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | class LexerException(Exception): 16 | """ 17 | Fallback exception that is called when the error type is not known. 18 | """ 19 | pass 20 | 21 | class CompileError(LexerException): 22 | """ 23 | Raised during the compilation procedure if the template contained 24 | a syntax error. 25 | """ 26 | pass 27 | 28 | class ExecuteError(LexerException): 29 | """ 30 | Raised during the execution of the compiled template whenever any 31 | error occurs. 32 | """ 33 | pass 34 | -------------------------------------------------------------------------------- /Exscript/parselib/Token.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | 16 | class Token(object): 17 | """ 18 | Abstract base class for all tokens. 19 | """ 20 | 21 | class Iterator(object): 22 | """ 23 | A tree iterator that walks through all tokens. 24 | """ 25 | def __init__(self, current): 26 | """ 27 | Constructor. 28 | """ 29 | self.path = [current] 30 | 31 | def __iter__(self): 32 | return self 33 | 34 | def _next(self): 35 | # Make sure that the end is not yet reached. 36 | if len(self.path) == 0: 37 | raise StopIteration() 38 | 39 | # If the current token has children, the first child is the next item. 40 | current = self.path[-1] 41 | children = current.get_children() 42 | if len(children) > 0: 43 | self.path.append(children[0]) 44 | return current 45 | 46 | # Ending up here, this task has no children. Crop the path until we 47 | # reach a task that has unvisited children, or until we hit the end. 48 | while True: 49 | old_child = self.path.pop(-1) 50 | if len(self.path) == 0: 51 | break 52 | 53 | # If this task has a sibling, choose it. 54 | parent = self.path[-1] 55 | children = parent.get_children() 56 | pos = children.index(old_child) 57 | if len(children) > pos + 1: 58 | self.path.append(children[pos + 1]) 59 | break 60 | return current 61 | 62 | def next(self): 63 | # By using this loop we avoid an (expensive) recursive call. 64 | while True: 65 | next = self._next() 66 | if next is not None: 67 | return next 68 | 69 | def __init__(self, name, lexer, parser, parent = None): 70 | self.lexer = lexer 71 | self.parser = parser 72 | self.parent = parent 73 | self.name = name 74 | self.children = [] 75 | self.start = lexer.current_char 76 | self.end = lexer.current_char + 1 77 | 78 | def value(self, context): 79 | for child in self.get_children(): 80 | child.value(context) 81 | 82 | def mark_start(self): 83 | self.start = self.lexer.current_char 84 | if self.start >= self.end: 85 | self.end = self.start + 1 86 | 87 | def mark_end(self, char = None): 88 | self.end = char and char or self.lexer.current_char 89 | 90 | def __iter__(self): 91 | """ 92 | Returns an iterator that points to the first token. 93 | """ 94 | return Token.Iterator(self) 95 | 96 | def add(self, child): 97 | self.children.append(child) 98 | 99 | def get_children(self): 100 | return self.children 101 | 102 | def dump(self, indent = 0): 103 | print (' ' * indent) + self.name 104 | for child in self.get_children(): 105 | child.dump(indent + 1) 106 | -------------------------------------------------------------------------------- /Exscript/parselib/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | from Exscript.parselib.Lexer import Lexer 16 | from Exscript.parselib.Token import Token 17 | 18 | import inspect 19 | __all__ = [name for name, obj in locals().items() 20 | if not (name.startswith('_') or inspect.ismodule(obj))] 21 | -------------------------------------------------------------------------------- /Exscript/protocols/Exception.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Network related error types. 17 | """ 18 | 19 | class ProtocolException(Exception): 20 | """ 21 | Default exception that is thrown on most protocol related errors. 22 | """ 23 | pass 24 | 25 | class TimeoutException(ProtocolException): 26 | """ 27 | An exception that is thrown if the connected host did not 28 | respond for too long. 29 | """ 30 | pass 31 | 32 | class ExpectCancelledException(ProtocolException): 33 | """ 34 | An exception that is thrown if Protocol.cancel_expect() 35 | was called. 36 | """ 37 | pass 38 | 39 | class DriverReplacedException(ProtocolException): 40 | """ 41 | An exception that is thrown if the protocol driver 42 | was switched during a call to expect(). 43 | """ 44 | pass 45 | 46 | class LoginFailure(ProtocolException): 47 | """ 48 | An exception that is thrown if the response of a connected host looked 49 | like it was trying to signal a login error during the authentication 50 | procedure. 51 | """ 52 | pass 53 | 54 | class InvalidCommandException(ProtocolException): 55 | """ 56 | An exception that is thrown if the response of a connected host contained 57 | a string that looked like an error. 58 | """ 59 | pass 60 | -------------------------------------------------------------------------------- /Exscript/protocols/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | from Exscript import Account 16 | from Exscript.util.cast import to_host 17 | from Exscript.util.url import Url 18 | from Exscript.protocols.Protocol import Protocol 19 | from Exscript.protocols.Telnet import Telnet 20 | from Exscript.protocols.SSH2 import SSH2 21 | from Exscript.protocols.Dummy import Dummy 22 | 23 | protocol_map = {'dummy': Dummy, 24 | 'pseudo': Dummy, 25 | 'telnet': Telnet, 26 | 'ssh': SSH2, 27 | 'ssh2': SSH2} 28 | 29 | def get_protocol_from_name(name): 30 | """ 31 | Returns the protocol class for the protocol with the given name. 32 | 33 | @type name: str 34 | @param name: The name of the protocol. 35 | @rtype: Protocol 36 | @return: The protocol class. 37 | """ 38 | cls = protocol_map.get(name) 39 | if not cls: 40 | raise ValueError('Unsupported protocol "%s".' % name) 41 | return cls 42 | 43 | def create_protocol(name, **kwargs): 44 | """ 45 | Returns an instance of the protocol with the given name. 46 | 47 | @type name: str 48 | @param name: The name of the protocol. 49 | @rtype: Protocol 50 | @return: An instance of the protocol. 51 | """ 52 | cls = protocol_map.get(name) 53 | if not cls: 54 | raise ValueError('Unsupported protocol "%s".' % name) 55 | return cls(**kwargs) 56 | 57 | def prepare(host, default_protocol = 'telnet', **kwargs): 58 | """ 59 | Creates an instance of the protocol by either parsing the given 60 | URL-formatted hostname using L{Exscript.util.url}, or according to 61 | the options of the given L{Exscript.Host}. 62 | 63 | @type host: str or Host 64 | @param host: A URL-formatted hostname or a L{Exscript.Host} instance. 65 | @type default_protocol: str 66 | @param default_protocol: Protocol that is used if the URL specifies none. 67 | @type kwargs: dict 68 | @param kwargs: Passed to the protocol constructor. 69 | @rtype: Protocol 70 | @return: An instance of the protocol. 71 | """ 72 | host = to_host(host, default_protocol = default_protocol) 73 | protocol = host.get_protocol() 74 | conn = create_protocol(protocol, **kwargs) 75 | if protocol == 'pseudo': 76 | filename = host.get_address() 77 | conn.device.add_commands_from_file(filename) 78 | return conn 79 | 80 | def connect(host, default_protocol = 'telnet', **kwargs): 81 | """ 82 | Like L{prepare()}, but also connects to the host by calling 83 | L{Protocol.connect()}. If the URL or host contain any login info, this 84 | function also logs into the host using L{Protocol.login()}. 85 | 86 | @type host: str or Host 87 | @param host: A URL-formatted hostname or a L{Exscript.Host} object. 88 | @type default_protocol: str 89 | @param default_protocol: Protocol that is used if the URL specifies none. 90 | @type kwargs: dict 91 | @param kwargs: Passed to the protocol constructor. 92 | @rtype: Protocol 93 | @return: An instance of the protocol. 94 | """ 95 | host = to_host(host) 96 | conn = prepare(host, default_protocol, **kwargs) 97 | account = host.get_account() 98 | conn.connect(host.get_address(), host.get_tcp_port()) 99 | if account is not None: 100 | conn.login(account) 101 | return conn 102 | 103 | import inspect 104 | __all__ = [name for name, obj in locals().items() 105 | if not (name.startswith('_') or inspect.ismodule(obj))] 106 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/__init__.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | from Exscript.protocols.drivers.driver import Driver 3 | from Exscript.protocols.drivers.aironet import AironetDriver 4 | from Exscript.protocols.drivers.aix import AIXDriver 5 | from Exscript.protocols.drivers.arbor_peakflow import ArborPeakflowDriver 6 | from Exscript.protocols.drivers.brocade import BrocadeDriver 7 | from Exscript.protocols.drivers.enterasys import EnterasysDriver 8 | from Exscript.protocols.drivers.generic import GenericDriver 9 | from Exscript.protocols.drivers.hp_pro_curve import HPProCurveDriver 10 | from Exscript.protocols.drivers.ios import IOSDriver 11 | from Exscript.protocols.drivers.nxos import NXOSDriver 12 | from Exscript.protocols.drivers.ios_xr import IOSXRDriver 13 | from Exscript.protocols.drivers.ace import ACEDriver 14 | from Exscript.protocols.drivers.junos import JunOSDriver 15 | from Exscript.protocols.drivers.junos_erx import JunOSERXDriver 16 | from Exscript.protocols.drivers.one_os import OneOSDriver 17 | from Exscript.protocols.drivers.shell import ShellDriver 18 | from Exscript.protocols.drivers.smart_edge_os import SmartEdgeOSDriver 19 | from Exscript.protocols.drivers.vrp import VRPDriver 20 | from Exscript.protocols.drivers.sros import SROSDriver 21 | from Exscript.protocols.drivers.aruba import ArubaDriver 22 | from Exscript.protocols.drivers.enterasys_wc import EnterasysWCDriver 23 | from Exscript.protocols.drivers.fortios import FortiOSDriver 24 | from Exscript.protocols.drivers.bigip import BigIPDriver 25 | from Exscript.protocols.drivers.isam import IsamDriver 26 | from Exscript.protocols.drivers.zte import ZteDriver 27 | from Exscript.protocols.drivers.vxworks import VxworksDriver 28 | from Exscript.protocols.drivers.ericsson_ban import EricssonBanDriver 29 | 30 | driver_classes = [] 31 | drivers = [] 32 | driver_map = {} 33 | 34 | def isdriver(o): 35 | return inspect.isclass(o) and issubclass(o, Driver) and not o is Driver 36 | 37 | def add_driver(cls): 38 | driver = cls() 39 | driver_classes.append(cls) 40 | drivers.append(driver) 41 | driver_map[driver.name] = driver 42 | 43 | # Load built-in drivers. 44 | for name, obj in locals().items(): 45 | if isdriver(obj): 46 | add_driver(obj) 47 | driver_map['unknown'] = driver_map['generic'] 48 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/ace.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for Cisco Application Control Engine (ACE) 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _user_re = [re.compile(r'user ?name: ?$', re.I)] 22 | _password_re = [re.compile(r'(?:[\r\n]Password: ?|last resort password:)$')] 23 | _tacacs_re = re.compile(r'[\r\n]s\/key[\S ]+\r?%s' % _password_re[0].pattern) 24 | _prompt_re = [re.compile(r'[\r\n][\-\w+\.:/]+(?:\([^\)]+\))?[>#] ?$')] 25 | _error_re = [re.compile(r'%Error'), 26 | re.compile(r'invalid input', re.I), 27 | re.compile(r'(?:incomplete|ambiguous) command', re.I), 28 | re.compile(r'connection timed out', re.I), 29 | re.compile(r'[^\r\n]+ not found', re.I)] 30 | 31 | class ACEDriver(Driver): 32 | def __init__(self): 33 | Driver.__init__(self, 'ace') 34 | self.user_re = _user_re 35 | self.password_re = _password_re 36 | self.prompt_re = _prompt_re 37 | self.error_re = _error_re 38 | 39 | def check_head_for_os(self, string): 40 | if 'Cisco Application Control Software' in string: 41 | return 90 42 | 43 | def init_terminal(self, conn): 44 | conn.execute('term len 0') 45 | 46 | def auto_authorize(self, conn, account, flush, bailout): 47 | conn.send('enable\r') 48 | conn.app_authorize(account, flush, bailout) 49 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/aironet.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 Mike Pennington, Samuel Abels 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for Cisco Aironet Wireless Controllers 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _user_re = [re.compile(r'User:\s$', re.I)] 22 | _password_re = [re.compile(r'(?:[\r\n]Password: ?|last resort password:)$')] 23 | _prompt_re = [re.compile(r'[\r\n].(?:(?:Cisco\sController)|(?:WiSM\S+?)|(?:\(.+\))).\s>$')] 24 | _error_re = [re.compile(r'Incorrect\susage', re.I), 25 | re.compile(r'Incorrect\sinput', re.I), 26 | re.compile(r'connection timed out', re.I), 27 | re.compile(r'[^\r\n]+ not found', re.I)] 28 | 29 | class AironetDriver(Driver): 30 | def __init__(self): 31 | Driver.__init__(self, 'aironet') 32 | self.user_re = _user_re 33 | self.prompt_re = _prompt_re 34 | 35 | def check_head_for_os(self, string): 36 | if '(Cisco Controller)' in string: 37 | return 90 38 | elif '(WiSM-slot' in string: 39 | return 90 40 | elif ') >' in string: 41 | return 87 42 | return 0 43 | 44 | def init_terminal(self, conn): 45 | conn.execute('config paging disable') 46 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/aix.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for AIX. 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _user_re = [re.compile(r'[\r\n]Authorized Login: $')] 22 | _password_re = [re.compile(r'[\r\n]\w+\'s Password: $')] 23 | _aix_re = re.compile(r'\bAIX\b') 24 | 25 | class AIXDriver(Driver): 26 | def __init__(self): 27 | Driver.__init__(self, 'aix') 28 | self.user_re = _user_re 29 | self.password_re = _password_re 30 | 31 | def check_head_for_os(self, string): 32 | if _user_re[0].search(string): 33 | return 70 34 | if _aix_re.search(string): 35 | return 75 36 | return 0 37 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/arbor_peakflow.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for Peakflow SP by Arbor Networks. 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _user_re = [re.compile(r'(user|login): $', re.I)] 22 | _password_re = [re.compile(r'Password: $')] 23 | _prompt_re = [re.compile(r'[\r\n][\-\w+\._]+@[\-\w+\._~]+:(?:/\w*)+[#%] $'), 24 | re.compile(r'Exit anyway\? \[.\] $')] 25 | _os_re = re.compile(r'\b(peakflow\b.*\barbor|arbos)\b', re.I | re.S) 26 | 27 | class ArborPeakflowDriver(Driver): 28 | def __init__(self): 29 | Driver.__init__(self, 'arbor_peakflow') 30 | self.user_re = _user_re 31 | self.password_re = _password_re 32 | self.prompt_re = _prompt_re 33 | 34 | def check_head_for_os(self, string): 35 | if _os_re.search(string): 36 | return 97 37 | return 0 38 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/aruba.py: -------------------------------------------------------------------------------- 1 | """ 2 | A driver for Aruba controllers 3 | """ 4 | import re 5 | from Exscript.protocols.drivers.driver import Driver 6 | 7 | _user_re = [re.compile(r'user ?name: ?$', re.I)] 8 | _password_re = [re.compile(r'(?:[\r\n]Password: ?|last resort password:)$')] 9 | _tacacs_re = re.compile(r'[\r\n]s\/key[\S ]+\r?%s' % _password_re[0].pattern) 10 | _prompt_re = [re.compile(r'[\r\n]\(\w+\) [>#] ?$')] 11 | _error_re = [re.compile(r'%Error'), 12 | re.compile(r'invalid input', re.I), 13 | re.compile(r'(?:incomplete|ambiguous) command', re.I), 14 | re.compile(r'connection timed out', re.I), 15 | re.compile(r'[^\r\n]+ not found', re.I)] 16 | _aruba_prompt_re = [re.compile(r'\(Aruba\d?\d?\d?\d?\) >')] 17 | 18 | 19 | class ArubaDriver(Driver): 20 | def __init__(self): 21 | Driver.__init__(self, 'aruba') 22 | self.user_re = _user_re 23 | self.password_re = _password_re 24 | self.prompt_re = _prompt_re 25 | self.error_re = _error_re 26 | 27 | def check_head_for_os(self, string): 28 | if 'aruba' in string.lower(): 29 | return 88 30 | 31 | def init_terminal(self, conn): 32 | conn.execute('no paging') 33 | 34 | def auto_authorize(self, conn, account, flush, bailout): 35 | conn.send('enable\r') 36 | conn.app_authorize(account, flush, bailout) 37 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/bigip.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for F5 Big-IP system (TMSH SHELL) 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _user_re = [re.compile(r'user ?name: ?$', re.I)] 22 | _password_re = [re.compile(r'(?:[\r\n]Password: ?|last resort password:)$')] 23 | _prompt_re = [re.compile(r'\S+@(\(.*?\)){1,4}\(tmos.*?\)#\s?')] 24 | _error_re = [re.compile(r'Syntax Error', re.I), 25 | re.compile(r'connection timed out', re.I)] 26 | 27 | class BigIPDriver(Driver): 28 | def __init__(self): 29 | Driver.__init__(self, 'bigip') 30 | self.user_re = _user_re 31 | self.password_re = _password_re 32 | self.prompt_re = _prompt_re 33 | self.error_re = _error_re 34 | 35 | def check_head_for_os(self, string): 36 | if "(tmos)" in string: 37 | return 90 38 | 39 | def init_terminal(self, conn): 40 | conn.execute('modify cli preference pager disabled') 41 | 42 | def auto_authorize(self, conn, account, flush, bailout): 43 | pass -------------------------------------------------------------------------------- /Exscript/protocols/drivers/brocade.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 Job Snijders 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for Brocade XMR/MLX devices. 17 | """ 18 | 19 | import re 20 | from Exscript.protocols.drivers.driver import Driver 21 | 22 | _user_re = [re.compile(r'[\r\n](Please Enter Login Name: |User Name:)$')] 23 | _password_re = [re.compile(r'[\r\n](Please Enter Password: |Password:)$')] 24 | _warning = r'(?:Warning: \d+ user\(s\) already in config mode\.)' 25 | _prompt = r'[\r\n]?(telnet|SSH)@[\-\w+\.:]+(?:\([\-\/\w]+\))?[>#]$' 26 | _prompt_re = [re.compile(_warning + r'?' + _prompt)] 27 | _error_re = [re.compile(r'%Error'), 28 | re.compile(r'Invalid input', re.I), 29 | re.compile(r'(?:incomplete|ambiguous) command', re.I), 30 | re.compile(r'connection timed out', re.I), 31 | re.compile(r'[^\r\n]+ not found', re.I)] 32 | 33 | class BrocadeDriver(Driver): 34 | def __init__(self): 35 | Driver.__init__(self, 'brocade') 36 | self.user_re = _user_re 37 | self.password_re = _password_re 38 | self.prompt_re = _prompt_re 39 | self.error_re = _error_re 40 | 41 | def check_head_for_os(self, string): 42 | if 'User Access Verification\r\n\r\nPlease Enter Login Name' in string: 43 | return 95 44 | if _prompt_re[0].search(string): 45 | return 90 46 | return 0 47 | 48 | def init_terminal(self, conn): 49 | conn.execute('terminal length 0') 50 | 51 | def auto_authorize(self, conn, account, flush, bailout): 52 | conn.send('enable\r') 53 | conn.app_authorize(account, flush, bailout) 54 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/driver.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Base class for all drivers. 17 | """ 18 | import re, string 19 | 20 | _flags = re.I 21 | _printable = re.escape(string.printable) 22 | _unprintable = r'[^' + _printable + r']' 23 | _unprintable_re = re.compile(_unprintable) 24 | _ignore = r'[\x1b\x07\x00]' 25 | _nl = r'[\r\n]' 26 | _prompt_start = _nl + r'(?:' + _unprintable + r'*|' + _ignore + '*)' 27 | _prompt_chars = r'[\-\w\(\)@:~]' 28 | _filename = r'(?:[\w\+\-\._]+)' 29 | _path = r'(?:(?:' + _filename + r')?(?:/' + _filename + r')*/?)' 30 | _any_path = r'(?:' + _path + r'|~' + _path + r'?)' 31 | _host = r'(?:[\w+\-\.]+)' 32 | _user = r'(?:[\w+\-]+)' 33 | _user_host = r'(?:(?:' + _user + r'\@)?' + _host + r')' 34 | _prompt_re = [re.compile(_prompt_start \ 35 | + r'[\[\<]?' \ 36 | + r'\w+' \ 37 | + _user_host + r'?' \ 38 | + r':?' \ 39 | + _any_path + r'?' \ 40 | + r'[: ]?' \ 41 | + _any_path + r'?' \ 42 | + r'(?:\(' + _filename + '\))?' \ 43 | + r'[\]\-]?' \ 44 | + r'[#>%\$\]] ?' \ 45 | + _unprintable + r'*' \ 46 | + r'\Z', _flags)] 47 | 48 | _user_re = [re.compile(r'(user ?name|user|login): *$', _flags)] 49 | _pass_re = [re.compile(r'password:? *$', _flags)] 50 | _errors = [r'error', 51 | r'invalid', 52 | r'incomplete', 53 | r'unrecognized', 54 | r'unknown command', 55 | r'connection timed out', 56 | r'[^\r\n]+ not found'] 57 | _error_re = [re.compile(r'^%?\s*(?:' + '|'.join(_errors) + r')', _flags)] 58 | _login_fail = [r'bad secrets', 59 | r'denied', 60 | r'invalid', 61 | r'too short', 62 | r'incorrect', 63 | r'connection timed out', 64 | r'failed', 65 | r'failure'] 66 | _login_fail_re = [re.compile(_nl \ 67 | + r'[^\r\n]*' \ 68 | + r'(?:' + '|'.join(_login_fail) + r')', _flags)] 69 | 70 | class Driver(object): 71 | def __init__(self, name): 72 | self.name = name 73 | self.user_re = _user_re 74 | self.password_re = _pass_re 75 | self.prompt_re = _prompt_re 76 | self.error_re = _error_re 77 | self.login_error_re = _login_fail_re 78 | 79 | def check_head_for_os(self, string): 80 | return 0 81 | 82 | def _check_head(self, string): 83 | return self.name, self.check_head_for_os(string) 84 | 85 | def check_response_for_os(self, string): 86 | return 0 87 | 88 | def _check_response(self, string): 89 | return self.name, self.check_response_for_os(string) 90 | 91 | def clean_response_for_re_match(self, response): 92 | return response, '' 93 | 94 | def init_terminal(self, conn): 95 | pass 96 | 97 | def supports_auto_authorize(self): 98 | return self.__class__.auto_authorize != Driver.auto_authorize 99 | 100 | def auto_authorize(self, conn, account, flush, bailout): 101 | conn.app_authorize(account, flush, bailout) 102 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/enterasys.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for Enterasys devices. 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _user_re = [re.compile(r'[\r\n]Username: $')] 22 | _password_re = [re.compile(r'[\r\n]Password: $')] 23 | _prompt_re = [re.compile(r'[\r\n][\-\w+\.]+(?:\([^\)]+\))?-?[>#] ?$')] 24 | _enterasys_re = re.compile(r'\benterasys\b', re.I) 25 | 26 | class EnterasysDriver(Driver): 27 | def __init__(self): 28 | Driver.__init__(self, 'enterasys') 29 | self.user_re = _user_re 30 | self.password_re = _password_re 31 | self.prompt_re = _prompt_re 32 | 33 | def check_head_for_os(self, string): 34 | if _enterasys_re.search(string): 35 | return 80 36 | return 0 37 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/enterasys_wc.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 Enno Groeper 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for Enterasys/Extreme (HiPath) Wireless Controller devices. 17 | 18 | Created using a C5110 device. 19 | """ 20 | import re 21 | from Exscript.protocols.drivers.driver import Driver 22 | 23 | _user_re = [re.compile(r'[\r\n]Username: $')] 24 | _password_re = [re.compile(r'[\r\n]Password: $')] 25 | _prompt_re = [ 26 | re.compile(r'[\r\n][a-zA-Z0-9-_ .]+# $'), # base prompt 27 | re.compile(r'[\r\n][a-zA-Z0-9-_ .]+(?::[A-Za-z0-9_.-]+)*# $') 28 | ] 29 | _hwc_re = re.compile(r'Enterasys Wireless Convergence OS', re.I) 30 | 31 | 32 | class EnterasysWCDriver(Driver): 33 | def __init__(self): 34 | Driver.__init__(self, 'enterasys_wc') 35 | self.user_re = _user_re 36 | self.password_re = _password_re 37 | self.prompt_re = _prompt_re 38 | 39 | def check_head_for_os(self, string): 40 | if _hwc_re.search(string): 41 | return 85 42 | return 0 43 | 44 | def init_terminal(self, conn): 45 | pass 46 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/ericsson_ban.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for devices running Ericsson's Broadband Access Nodes (BAN) OS 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _user_re = [re.compile(r'user:', re.I)] 22 | _password_re = [re.compile(r'pass:', re.I)] 23 | _prompt_re = [re.compile(r'[\r\n][\-\w+\.]+(?:\([^\)]+\))?[%#] ?$|(?:\(y/n\)\[n\])')] 24 | _error_re = [re.compile(r'\(error\)')] 25 | 26 | _ban_re = re.compile(r"BLM\d+ - Broadband Loop Multiplexer", re.I) 27 | 28 | _banner_re = re.compile(r"Last login", re.I) 29 | 30 | _login_fail_re = [r'Login failed'] 31 | 32 | 33 | class EricssonBanDriver(Driver): 34 | def __init__(self): 35 | Driver.__init__(self, 'ericsson_ban') 36 | 37 | self.user_re = _user_re 38 | self.password_re = _password_re 39 | self.prompt_re = _prompt_re 40 | self.error_re = _error_re 41 | self.login_error_re = _login_fail_re 42 | 43 | # def auto_authorize(self, conn, account, flush, bailout): 44 | # conn.send('enable\r\n') 45 | # conn.app_authorize(account, flush, bailout) 46 | 47 | def check_head_for_os(self, string): 48 | if _ban_re.search(string): 49 | return 90 50 | return 0 51 | 52 | def check_response_for_os(self, string): 53 | if _banner_re.search(string): 54 | return 20 55 | return 0 -------------------------------------------------------------------------------- /Exscript/protocols/drivers/fortios.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2014 Enno Groeper 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for FortiOS devices. 17 | 18 | Created using a Fortigate device and FortiOS 5.0. 19 | """ 20 | import re 21 | from Exscript.protocols.drivers.driver import Driver 22 | 23 | _user_re = [re.compile(r'[\r\n]Username: $')] 24 | _password_re = [re.compile(r'[\r\n]Password: $')] 25 | _prompt_re = [ 26 | re.compile(r'^[a-zA-Z0-9-_ .]+ (?:\$|#) $'), # first prompt 27 | re.compile(r'[\r\n][a-zA-Z0-9-_ .]+ (?:\([A-Za-z0-9_/.-]+\) )?(?:\$|#) $') 28 | ] 29 | _fortios_re = [ 30 | _prompt_re[0], # first prompt 31 | re.compile(r'^[a-zA-Z0-9-_.]+@[a-zA-Z0-9-_.]+\'s password:') 32 | ] 33 | _error_re = [re.compile(r'^Command fail.'), 34 | re.compile(r'^object check operator error') 35 | ] 36 | 37 | # example errors: 38 | #invalid netmask. 39 | #object check operator error, -9, discard the setting 40 | #Command fail. Return code -9 41 | 42 | #entry not found in datasource 43 | #value parse error before 'imported' 44 | #Command fail. Return code -3 45 | 46 | 47 | class FortiOSDriver(Driver): 48 | def __init__(self): 49 | Driver.__init__(self, 'fortios') 50 | self.user_re = _user_re 51 | self.password_re = _password_re 52 | self.prompt_re = _prompt_re 53 | self.error_re = _error_re 54 | 55 | def check_head_for_os(self, string): 56 | # By default Fortigate shows only prompt 57 | if len(string.splitlines()) == 1: 58 | for head_re in _fortios_re: 59 | if head_re.search(string): 60 | return 50 61 | return 0 62 | 63 | def init_terminal(self, conn): 64 | conn.execute('config global') 65 | conn.execute('config system console') 66 | conn.execute('set output standard') # no paging 67 | conn.execute('end') # config system console 68 | conn.execute('end') # config global 69 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/generic.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | The default driver that is used when the OS is not recognized. 17 | """ 18 | from Exscript.protocols.drivers.driver import Driver 19 | 20 | class GenericDriver(Driver): 21 | def __init__(self): 22 | Driver.__init__(self, 'generic') 23 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/hp_pro_curve.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for HP ProCurve switches. 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _user_re = [re.compile(r'[\r\n]Username: ?$')] 22 | _password_re = [re.compile(r'[\r\n]Password: ?$')] 23 | _prompt_re = [re.compile(r'[\r\n][\-\w+\.:/]+[>#] ?$')] 24 | _error_re = [re.compile(r'(?:invalid|incomplete|ambiguous) input:', re.I)] 25 | _login_fail_re = [re.compile(r'[\r\n]invalid password', re.I), 26 | re.compile(r'unable to verify password', re.I), 27 | re.compile(r'unable to login', re.I)] 28 | _clean_res_re = [(re.compile(r'\x1bE'), "\r\n"), (re.compile(r'(?:\x1b\[|\x9b)[\x30-\x3f]*[\x40-\x7e]'), "")] 29 | 30 | class HPProCurveDriver(Driver): 31 | def __init__(self): 32 | Driver.__init__(self, 'hp_pro_curve') 33 | self.user_re = _user_re 34 | self.password_re = _password_re 35 | self.prompt_re = _prompt_re 36 | self.error_re = _error_re 37 | self.login_error_re = _login_fail_re 38 | self.clean_res_re = _clean_res_re 39 | 40 | def check_head_for_os(self, string): 41 | if 'ProCurve' in string: 42 | return 95 43 | if 'Hewlett-Packard' in string: 44 | return 50 45 | return 0 46 | 47 | def clean_response_for_re_match(self, response): 48 | start = response[:10].find('\x1b') 49 | if start != -1: 50 | response = response[start:] 51 | for regexp, sub in self.clean_res_re: 52 | response = regexp.subn(sub, response)[0] 53 | i = response.find('\x1b') 54 | if i > -1: 55 | return response[:i], response[i:] 56 | return response, '' 57 | 58 | def init_terminal(self, conn): 59 | conn.execute('\r\n') 60 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/ios.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for Cisco IOS (not IOS XR). 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _user_re = [re.compile(r'user ?name: ?$', re.I)] 22 | _password_re = [re.compile(r'(?:[\r\n]Password: ?|last resort password:)$')] 23 | _tacacs_re = re.compile(r'[\r\n]s\/key[\S ]+\r?%s' % _password_re[0].pattern) 24 | _prompt_re = [re.compile(r'[\r\n][\-\w+\.:/]+(?:\([^\)]+\))?[>#] ?$')] 25 | _error_re = [re.compile(r'%Error'), 26 | re.compile(r'invalid input', re.I), 27 | re.compile(r'(?:incomplete|ambiguous) command', re.I), 28 | re.compile(r'connection timed out', re.I), 29 | re.compile(r'[^\r\n]+ not found', re.I)] 30 | 31 | class IOSDriver(Driver): 32 | def __init__(self): 33 | Driver.__init__(self, 'ios') 34 | self.user_re = _user_re 35 | self.password_re = _password_re 36 | self.prompt_re = _prompt_re 37 | self.error_re = _error_re 38 | 39 | def check_head_for_os(self, string): 40 | if 'User Access Verification' in string: 41 | return 60 42 | if _tacacs_re.search(string): 43 | return 50 44 | if _user_re[0].search(string): 45 | return 30 46 | return 0 47 | 48 | def init_terminal(self, conn): 49 | conn.execute('term len 0') 50 | conn.execute('term width 0') 51 | 52 | def auto_authorize(self, conn, account, flush, bailout): 53 | conn.send('enable\r') 54 | conn.app_authorize(account, flush, bailout) 55 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/ios_xr.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for Cisco IOS XR. 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _user_re = [re.compile(r'[\r\n]Username: $')] 22 | _password_re = [re.compile(r'[\r\n]Password: $')] 23 | _prompt_re = [re.compile(r'[\r\n]RP/\d+/(?:RS?P)?\d+\/CPU\d+:[^#]+(?:\([^\)]+\))?#$')] 24 | 25 | class IOSXRDriver(Driver): 26 | def __init__(self): 27 | Driver.__init__(self, 'ios_xr') 28 | self.user_re = _user_re 29 | self.password_re = _password_re 30 | self.prompt_re = _prompt_re 31 | 32 | def check_response_for_os(self, string): 33 | if _prompt_re[0].search(string): 34 | return 95 35 | return 0 36 | 37 | def init_terminal(self, conn): 38 | conn.execute('terminal exec prompt no-timestamp') 39 | conn.execute('terminal len 0') 40 | conn.execute('terminal width 0') 41 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/isam.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for devices running ISAM (runs on Alcatel ISAM). 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _user_re = [re.compile(r'login: ?', re.I)] 22 | _password_re = [re.compile(r'[\r\n]password: ?', re.I)] 23 | _prompt_re = [re.compile(r'[\r\n][\- +\d+\w+\.]+(?:\([^\)]+\))?[>#] ?')] 24 | _error_re = [re.compile(r'%Error'), 25 | re.compile(r'invalid token', re.I), 26 | re.compile(r"command is not complete")] 27 | _isam_re = re.compile(r"last login : \d{1,2}/\d{1,2}/\d{1,2} \d{1,2}:\d{1,2}:\d{1,2}") 28 | 29 | class IsamDriver(Driver): 30 | def __init__(self): 31 | Driver.__init__(self, 'isam') 32 | self.user_re = _user_re 33 | self.password_re = _password_re 34 | self.prompt_re = _prompt_re 35 | self._error_re = _error_re 36 | 37 | def check_response_for_os(self, string): 38 | if _prompt_re[0].search(string): 39 | return 20 40 | return 0 41 | 42 | def check_head_for_os(self, string): 43 | if _isam_re.search(string): 44 | return 90 45 | return 0 46 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/junos.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for devices running JunOS (by Juniper). 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | # JunOS prompt examples: 22 | # sab@DD-EA3> 23 | # 24 | # [edit] 25 | # sab@DD-EA3> 26 | # 27 | # {backup} 28 | # sab@DD-EA3> 29 | # 30 | # {backup}[edit] 31 | # sab@DD-EA3> 32 | # 33 | # {backup}[edit interfaces] 34 | # sab@DD-EA3> 35 | # 36 | # {master:3} 37 | # pheller@sw3> 38 | # 39 | # {primary:node0} 40 | # pheller@fw1> 41 | # 42 | 43 | _user_re = [re.compile(r'[\r\n]login: $')] 44 | _password_re = [re.compile(r'[\r\n](Local )?[Pp]assword: ?$')] 45 | _mb = r'(?:\{master(?::\d+)?\}|\{backup(?::\d+)?\})' 46 | _ps = r'(?:\{primary:node\d+\}|\{secondary:node\d+\})' 47 | _re_re = r'(?:'+ _mb + r'|' + _ps + r')' 48 | _edit = r'(?:\[edit[^\]\r\n]*\])' 49 | _prefix = r'(?:[\r\n]+' + _re_re + r'?' + _edit + r'?)' 50 | _prompt = r'[\r\n]+[\w\-\.]+@[\-\w+\.:]+[%>#] $' 51 | _prompt_re = [re.compile(_prefix + r'?' + _prompt)] 52 | _error_re = [re.compile('^(unknown|invalid|error)', re.I)] 53 | _junos_re = re.compile(r'\bjunos\b', re.I) 54 | 55 | class JunOSDriver(Driver): 56 | def __init__(self): 57 | Driver.__init__(self, 'junos') 58 | self.user_re = _user_re 59 | self.password_re = _password_re 60 | self.prompt_re = _prompt_re 61 | self.error_re = _error_re 62 | 63 | def check_head_for_os(self, string): 64 | if _junos_re.search(string): 65 | return 80 66 | if _user_re[0].search(string): 67 | return 35 68 | return 0 69 | 70 | def init_terminal(self, conn): 71 | conn.execute('set cli screen-length 0') 72 | conn.execute('set cli screen-width 0') 73 | conn.execute('set cli terminal ansi') 74 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/junos_erx.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for devices running Juniper ERX OS. 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | from Exscript.protocols.drivers.ios import _prompt_re 21 | 22 | _user_re = [re.compile(r'[\r\n]User: $')] 23 | _password_re = [re.compile(r'[\r\n](Telnet password:|Password:) $')] 24 | _junos_re = re.compile(r'\bJuniper Networks\b', re.I) 25 | 26 | class JunOSERXDriver(Driver): 27 | def __init__(self): 28 | Driver.__init__(self, 'junos_erx') 29 | self.user_re = _user_re 30 | self.password_re = _password_re 31 | self.prompt_re = _prompt_re 32 | 33 | def check_head_for_os(self, string): 34 | if _junos_re.search(string): 35 | return 75 36 | return 0 37 | 38 | def init_terminal(self, conn): 39 | conn.execute('terminal length 60') 40 | conn.execute('terminal width 150') 41 | 42 | def auto_authorize(self, conn, account, flush, bailout): 43 | conn.send('enable 15\r') 44 | conn.app_authorize(account, flush, bailout) 45 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/nxos.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for Cisco Nexus OS (NXOS) 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _user_re = [re.compile(r'user ?name: ?$', re.I)] 22 | _password_re = [re.compile(r'(?:[\r\n]Password: ?|last resort password:)$')] 23 | _prompt_re = [re.compile(r'[\r\n][\-\w+\.:/]+(?:\([^\)]+\))?[>#] ?$')] 24 | _error_re = [re.compile(r'%Error'), 25 | re.compile(r'invalid input', re.I), 26 | re.compile(r'(?:incomplete|ambiguous) command', re.I), 27 | re.compile(r'connection timed out', re.I), 28 | re.compile(r'[^\r\n]+ not found', re.I)] 29 | 30 | 31 | class NXOSDriver(Driver): 32 | def __init__(self): 33 | Driver.__init__(self, 'nxos') 34 | self.user_re = _user_re 35 | self.password_re = _password_re 36 | self.prompt_re = _prompt_re 37 | self.error_re = _error_re 38 | 39 | def check_head_for_os(self, string): 40 | if 'Cisco Nexus Operating System (NX-OS) Software' in string: 41 | return 95 42 | return 0 43 | 44 | def init_terminal(self, conn): 45 | conn.execute('term len 0') 46 | 47 | def auto_authorize(self, conn, account, flush, bailout): 48 | pass 49 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/one_os.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for OneOS (OneAccess). 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _user_re = [re.compile(r'[\r\n]Username: ?$')] 22 | _password_re = [re.compile(r'[\r\n]Password: ?$')] 23 | _first_prompt_re = re.compile(r'\r?\n\r?\n[\-\w+\.]+[>#]$') 24 | _prompt_re = [re.compile(r'[\r\n][\-\w+\.]+(?:\([^\)]+\))?[>#] ?$')] 25 | 26 | class OneOSDriver(Driver): 27 | def __init__(self): 28 | Driver.__init__(self, 'one_os') 29 | self.user_re = _user_re 30 | self.password_re = _password_re 31 | self.prompt_re = _prompt_re 32 | 33 | def check_head_for_os(self, string): 34 | if _first_prompt_re.search(string): 35 | return 40 36 | return 0 37 | 38 | def init_terminal(self, conn): 39 | conn.execute('term len 0') 40 | 41 | def auto_authorize(self, conn, account, flush, bailout): 42 | conn.send('enable\r') 43 | conn.app_authorize(account, flush, bailout) 44 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/shell.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A generic shell driver that handles unknown unix shells. 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _user_re = [re.compile(r'(user|login): $', re.I)] 22 | _password_re = [re.compile(r'Password: ?$')] 23 | _linux_re = re.compile(r'\blinux\b', re.I) 24 | 25 | class ShellDriver(Driver): 26 | def __init__(self): 27 | Driver.__init__(self, 'shell') 28 | self.user_re = _user_re 29 | self.password_re = _password_re 30 | 31 | def check_head_for_os(self, string): 32 | if _linux_re.search(string): 33 | return 70 34 | if _user_re[0].search(string): 35 | return 20 36 | return 0 37 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/smart_edge_os.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for Redback Smart Edge OS. 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _user_re = [re.compile(r'[\r\n]login: ')] 22 | _password_re = [re.compile(r'[\r\n]Password: $')] 23 | _prompt_re = [re.compile(r'[\r\n]\[\w+\][\-\w+\.]+(?:\([^\)]+\))?[>#] ?$')] 24 | _model_re = re.compile(r'[\r\n][^\r\n]+-se800[\r\n]') 25 | 26 | class SmartEdgeOSDriver(Driver): 27 | def __init__(self): 28 | Driver.__init__(self, 'smart_edge_os') 29 | self.user_re = _user_re 30 | self.password_re = _password_re 31 | self.prompt_re = _prompt_re 32 | 33 | def check_head_for_os(self, string): 34 | if _model_re.search(string): 35 | return 60 36 | if self.user_re[0].search(string): 37 | return 20 38 | return 0 39 | 40 | def init_terminal(self, conn): 41 | conn.execute('terminal length 0') 42 | conn.execute('terminal width 65536') 43 | 44 | def auto_authorize(self, conn, account, flush, bailout): 45 | conn.send('enable\r') 46 | conn.app_authorize(account, flush, bailout) 47 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/sros.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for Alcatel SROS. 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _prompt_re = [re.compile(r'[\r\n][*]?(?:A|B):[\-\w\.>]+[#\$] ?$')] 22 | 23 | class SROSDriver(Driver): 24 | def __init__(self): 25 | Driver.__init__(self, 'sros') 26 | self.prompt_re = _prompt_re 27 | 28 | def check_head_for_os(self, string): 29 | if _prompt_re[0].search(string): 30 | return 95 31 | return 0 32 | 33 | def init_terminal(self, conn): 34 | conn.execute('environment no more') 35 | conn.execute('environment reduced-prompt 2') 36 | conn.execute('environment no saved-ind-prompt') 37 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/vrp.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for devices running VRP (by Huawei). 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _user_re = [re.compile(r'user ?name: ', re.I)] 22 | _password_re = [re.compile(r'[\r\n]Password: $')] 23 | _prompt_re = [re.compile(r'[\r\n][\-\w+\.]+(?:\([^\)]+\))?[>#] ?$')] 24 | _huawei_re = re.compile(r'\bhuawei\b', re.I) 25 | 26 | class VRPDriver(Driver): 27 | def __init__(self): 28 | Driver.__init__(self, 'vrp') 29 | self.user_re = _user_re 30 | self.password_re = _password_re 31 | self.prompt_re = _prompt_re 32 | 33 | def check_head_for_os(self, string): 34 | if _huawei_re.search(string): 35 | return 80 36 | return 0 37 | -------------------------------------------------------------------------------- /Exscript/protocols/drivers/vxworks.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for devices running Vxworks, which can be found on huawei5600T 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _user_re = [re.compile(r'user ?name:', re.I)] 22 | _password_re = [re.compile(r'(?:User )?Password:', re.I)] 23 | _prompt_re = [re.compile(r'[\r\n][\-\w+\.]+(?:\([^\)]+\))?[>#] ?$|(?:\(y/n\)\[n\])')] 24 | _error_re = [re.compile(r'%Error'), 25 | re.compile(r'(?:(?:Unknown|ambiguous|Incomplete) command)|Failure|Parameter error', re.I)] 26 | 27 | _huawei_re = re.compile(r"Huawei Integrated Access Software", re.I) 28 | 29 | _banner_re = re.compile(r"User last login information", re.I) 30 | 31 | 32 | class VxworksDriver(Driver): 33 | def __init__(self): 34 | Driver.__init__(self, 'vxworks') 35 | self.user_re = _user_re 36 | self.password_re = _password_re 37 | self.prompt_re = _prompt_re 38 | self.error_re = _error_re 39 | 40 | def auto_authorize(self, conn, account, flush, bailout): 41 | conn.send('enable\r\n') 42 | conn.app_authorize(account, flush, bailout) 43 | 44 | def check_head_for_os(self, string): 45 | if _huawei_re.search(string): 46 | return 90 47 | return 0 48 | 49 | def check_response_for_os(self, string): 50 | if _banner_re.search(string): 51 | return 90 52 | return 0 -------------------------------------------------------------------------------- /Exscript/protocols/drivers/zte.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A driver for devices running Zte operating system. 17 | """ 18 | import re 19 | from Exscript.protocols.drivers.driver import Driver 20 | 21 | _user_re = [re.compile(r'user ?name:', re.I), re.compile(r'login', re.I)] 22 | _password_re = [re.compile(r'(?:User )?Password:', re.I)] 23 | _prompt_re = [re.compile(r'[\r\n][\-\w+\.\(\)]+(?:\([^\)]+\))?[>#$] ?$|(?:\(y/n\)\[n\])'), 24 | re.compile(r"[\r\n]Password: ?", re.I)] # password prompt to be used in privilege mode when it has 25 | # a password different from the login password. 26 | _error_re = [re.compile(r'%Error'), 27 | re.compile(r'(?:Unrecognized|Incomplete) command', re.I), re.compile(r'Invalid input', re.I)] 28 | 29 | _zte_re = re.compile(r"ZTE", re.I) 30 | 31 | 32 | class ZteDriver(Driver): 33 | def __init__(self): 34 | Driver.__init__(self, 'zte') 35 | self.user_re = _user_re 36 | self.password_re = _password_re 37 | self.prompt_re = _prompt_re 38 | self.error_re = _error_re 39 | 40 | def auto_authorize(self, conn, account, flush, bailout): 41 | conn.send('enable\r\n') 42 | conn.app_authorize(account, flush, bailout) 43 | 44 | def check_head_for_os(self, string): 45 | if _zte_re.search(string): 46 | return 90 47 | return 0 -------------------------------------------------------------------------------- /Exscript/servers/Telnetd.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A Telnet server. 17 | """ 18 | import select 19 | from Exscript.servers.Server import Server 20 | 21 | class Telnetd(Server): 22 | """ 23 | A Telnet server. Usage:: 24 | 25 | device = VirtualDevice('myhost') 26 | daemon = Telnetd('localhost', 1234, device) 27 | device.add_command('ls', 'ok', prompt = True) 28 | device.add_command('exit', daemon.exit_command) 29 | daemon.start() # Start the server. 30 | daemon.exit() # Stop the server. 31 | daemon.join() # Wait until it terminates. 32 | """ 33 | 34 | def _recvline(self, conn): 35 | while not '\n' in self.buf: 36 | self._poll_child_process() 37 | r, w, x = select.select([conn], [], [], self.timeout) 38 | if not self.running: 39 | return None 40 | if not r: 41 | continue 42 | buf = conn.recv(1024) 43 | if not buf: 44 | self.running = False 45 | return None 46 | self.buf += buf.replace('\r\n', '\n').replace('\r', '\n') 47 | lines = self.buf.split('\n') 48 | self.buf = '\n'.join(lines[1:]) 49 | return lines[0] + '\n' 50 | 51 | def _shutdown_notify(self, conn): 52 | try: 53 | conn.send('Server is shutting down.\n') 54 | except Exception: 55 | pass 56 | 57 | def _handle_connection(self, conn): 58 | conn.send(self.device.init()) 59 | 60 | while self.running: 61 | line = self._recvline(conn) 62 | if not line: 63 | continue 64 | response = self.device.do(line) 65 | if response: 66 | conn.send(response) 67 | -------------------------------------------------------------------------------- /Exscript/servers/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2011 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Very simple servers, useful for emulating a device for testing. 17 | """ 18 | from Exscript.servers.Telnetd import Telnetd 19 | from Exscript.servers.SSHd import SSHd 20 | from Exscript.servers.HTTPd import HTTPd 21 | 22 | import inspect 23 | __all__ = [name for name, obj in locals().items() 24 | if not (name.startswith('_') or inspect.ismodule(obj))] 25 | -------------------------------------------------------------------------------- /Exscript/stdlib/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | from Exscript.stdlib import connection 16 | from Exscript.stdlib import crypt 17 | from Exscript.stdlib import file 18 | from Exscript.stdlib import ipv4 19 | from Exscript.stdlib import list 20 | from Exscript.stdlib import string 21 | from Exscript.stdlib import mysys 22 | 23 | functions = { 24 | 'connection.authenticate': connection.authenticate, 25 | 'connection.authorize': connection.authorize, 26 | 'connection.auto_authorize': connection.auto_authorize, 27 | 'connection.autoinit': connection.autoinit, 28 | 'connection.close': connection.close, 29 | 'connection.exec': connection.exec_, 30 | 'connection.execline': connection.execline, 31 | 'connection.guess_os': connection.guess_os, 32 | 'connection.send': connection.send, 33 | 'connection.sendline': connection.sendline, 34 | 'connection.set_error': connection.set_error, 35 | 'connection.set_prompt': connection.set_prompt, 36 | 'connection.set_timeout': connection.set_timeout, 37 | 'connection.wait_for': connection.wait_for, 38 | 'crypt.otp': crypt.otp, 39 | 'file.chmod': file.chmod, 40 | 'file.clear': file.clear, 41 | 'file.exists': file.exists, 42 | 'file.mkdir': file.mkdir, 43 | 'file.read': file.read, 44 | 'file.rm': file.rm, 45 | 'file.write': file.write, 46 | 'ipv4.in_network': ipv4.in_network, 47 | 'ipv4.mask': ipv4.mask, 48 | 'ipv4.mask2pfxlen': ipv4.mask2pfxlen, 49 | 'ipv4.pfxlen2mask': ipv4.pfxlen2mask, 50 | 'ipv4.pfxmask': ipv4.pfxmask, 51 | 'ipv4.network': ipv4.network, 52 | 'ipv4.broadcast': ipv4.broadcast, 53 | 'ipv4.remote_ip': ipv4.remote_ip, 54 | 'list.new': list.new, 55 | 'list.get': list.get, 56 | 'list.length': list.length, 57 | 'list.unique': list.unique, 58 | 'string.replace': string.replace, 59 | 'string.tolower': string.tolower, 60 | 'sys.exec': mysys.execute, 61 | 'sys.message': mysys.message, 62 | 'sys.wait': mysys.wait, 63 | } 64 | -------------------------------------------------------------------------------- /Exscript/stdlib/crypt.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | from Exscript.util import crypt 16 | from Exscript.stdlib.util import secure_function 17 | 18 | @secure_function 19 | def otp(scope, password, seed, seqs): 20 | """ 21 | Calculates a one-time password hash using the given password, seed, and 22 | sequence number and returns it. 23 | Uses the md4/sixword algorithm as supported by TACACS+ servers. 24 | 25 | @type password: string 26 | @param password: A password. 27 | @type seed: string 28 | @param seed: A username. 29 | @type seqs: int 30 | @param seqs: A sequence number, or a list of sequence numbers. 31 | @rtype: string 32 | @return: A hash, or a list of hashes. 33 | """ 34 | return [crypt.otp(password[0], seed[0], int(seq)) for seq in seqs] 35 | -------------------------------------------------------------------------------- /Exscript/stdlib/file.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | import os 16 | from Exscript.stdlib.util import secure_function 17 | 18 | def chmod(scope, filename, mode): 19 | """ 20 | Changes the permissions of the given file (or list of files) 21 | to the given mode. You probably want to use an octal representation 22 | for the integer, e.g. "chmod(myfile, 0644)". 23 | 24 | @type filename: string 25 | @param filename: A filename. 26 | @type mode: int 27 | @param mode: The access permissions. 28 | """ 29 | for file in filename: 30 | os.chmod(file, mode[0]) 31 | return True 32 | 33 | def clear(scope, filename): 34 | """ 35 | Clear the contents of the given file. The file is created if it does 36 | not exist. 37 | 38 | @type filename: string 39 | @param filename: A filename. 40 | """ 41 | file = open(filename[0], 'w') 42 | file.close() 43 | return True 44 | 45 | @secure_function 46 | def exists(scope, filename): 47 | """ 48 | Returns True if the file with the given name exists, False otherwise. 49 | If a list of files is given, the function returns True only if ALL of 50 | the files exist. 51 | 52 | @type filename: string 53 | @param filename: A filename. 54 | @rtype: bool 55 | @return: The operating system of the remote device. 56 | """ 57 | return [os.path.exists(f) for f in filename] 58 | 59 | def mkdir(scope, dirname, mode = None): 60 | """ 61 | Creates the given directory (or directories). The optional access 62 | permissions are set to the given mode, and default to whatever 63 | is the umask on your system defined. 64 | 65 | @type dirname: string 66 | @param dirname: A filename, or a list of dirnames. 67 | @type mode: int 68 | @param mode: The access permissions. 69 | """ 70 | for dir in dirname: 71 | if mode is None: 72 | os.makedirs(dir) 73 | else: 74 | os.makedirs(dir, mode[0]) 75 | return True 76 | 77 | def read(scope, filename): 78 | """ 79 | Reads the given file and returns the result. 80 | The result is also stored in the built-in __response__ variable. 81 | 82 | @type filename: string 83 | @param filename: A filename. 84 | @rtype: string 85 | @return: The content of the file. 86 | """ 87 | file = open(filename[0], 'r') 88 | lines = file.readlines() 89 | file.close() 90 | scope.define(__response__ = lines) 91 | return lines 92 | 93 | def rm(scope, filename): 94 | """ 95 | Deletes the given file (or files) from the file system. 96 | 97 | @type filename: string 98 | @param filename: A filename, or a list of filenames. 99 | """ 100 | for file in filename: 101 | os.remove(file) 102 | return True 103 | 104 | def write(scope, filename, lines, mode = ['a']): 105 | """ 106 | Writes the given string into the given file. 107 | The following modes are supported: 108 | 109 | - 'a': Append to the file if it already exists. 110 | - 'w': Replace the file if it already exists. 111 | 112 | @type filename: string 113 | @param filename: A filename. 114 | @type lines: string 115 | @param lines: The data that is written into the file. 116 | @type mode: string 117 | @param mode: Any of the above listed modes. 118 | """ 119 | file = open(filename[0], mode[0]) 120 | file.writelines(['%s\n' % line.rstrip() for line in lines]) 121 | file.close() 122 | return True 123 | -------------------------------------------------------------------------------- /Exscript/stdlib/list.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | from Exscript.stdlib.util import secure_function 16 | 17 | @secure_function 18 | def new(scope): 19 | """ 20 | Returns a new, empty list. 21 | 22 | @rtype: string 23 | @return: The model of the remote device. 24 | """ 25 | return [] 26 | 27 | @secure_function 28 | def length(scope, mylist): 29 | """ 30 | Returns the number of items in the list. 31 | 32 | @rtype: string 33 | @return: The model of the remote device. 34 | """ 35 | return [len(mylist)] 36 | 37 | @secure_function 38 | def get(scope, source, index): 39 | """ 40 | Returns a copy of the list item with the given index. 41 | It is an error if an item with teh given index does not exist. 42 | 43 | @type source: string 44 | @param source: A list of strings. 45 | @type index: string 46 | @param index: A list of strings. 47 | @rtype: string 48 | @return: The cleaned up list of strings. 49 | """ 50 | try: 51 | index = int(index[0]) 52 | except IndexError: 53 | raise ValueError('index variable is required') 54 | except ValueError: 55 | raise ValueError('index is not an integer') 56 | try: 57 | return [source[index]] 58 | except IndexError: 59 | raise ValueError('no such item in the list') 60 | 61 | @secure_function 62 | def unique(scope, source): 63 | """ 64 | Returns a copy of the given list in which all duplicates are removed 65 | such that one of each item remains in the list. 66 | 67 | @type source: string 68 | @param source: A list of strings. 69 | @rtype: string 70 | @return: The cleaned up list of strings. 71 | """ 72 | return dict(map(lambda a: (a, 1), source)).keys() 73 | -------------------------------------------------------------------------------- /Exscript/stdlib/mysys.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | import time 16 | import sys 17 | from subprocess import Popen, PIPE, STDOUT 18 | from Exscript.stdlib.util import secure_function 19 | 20 | def execute(scope, command): 21 | """ 22 | Executes the given command locally. 23 | 24 | @type command: string 25 | @param command: A shell command. 26 | """ 27 | process = Popen(command[0], 28 | shell = True, 29 | stdin = PIPE, 30 | stdout = PIPE, 31 | stderr = STDOUT, 32 | close_fds = True) 33 | scope.define(__response__ = process.stdout.read()) 34 | return True 35 | 36 | @secure_function 37 | def message(scope, string): 38 | """ 39 | Writes the given string to stdout. 40 | 41 | @type string: string 42 | @param string: A string, or a list of strings. 43 | """ 44 | sys.stdout.write(''.join(string) + '\n') 45 | return True 46 | 47 | @secure_function 48 | def wait(scope, seconds): 49 | """ 50 | Waits for the given number of seconds. 51 | 52 | @type seconds: int 53 | @param seconds: The wait time in seconds. 54 | """ 55 | time.sleep(int(seconds[0])) 56 | return True 57 | -------------------------------------------------------------------------------- /Exscript/stdlib/string.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | from Exscript.stdlib.util import secure_function 16 | 17 | @secure_function 18 | def replace(scope, strings, source, dest): 19 | """ 20 | Returns a copy of the given string (or list of strings) in which all 21 | occurrences of the given source are replaced by the given dest. 22 | 23 | @type strings: string 24 | @param strings: A string, or a list of strings. 25 | @type source: string 26 | @param source: What to replace. 27 | @type dest: string 28 | @param dest: What to replace it with. 29 | @rtype: string 30 | @return: The resulting string, or list of strings. 31 | """ 32 | return [s.replace(source[0], dest[0]) for s in strings] 33 | 34 | @secure_function 35 | def tolower(scope, strings): 36 | """ 37 | Returns the given string in lower case. 38 | 39 | @type strings: string 40 | @param strings: A string, or a list of strings. 41 | @rtype: string 42 | @return: The resulting string, or list of strings in lower case. 43 | """ 44 | return [s.lower() for s in strings] 45 | -------------------------------------------------------------------------------- /Exscript/stdlib/util.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Copyright (C) 2010 Samuel Abels. 3 | # 4 | # This program is free software; you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License version 2, as 6 | # published by the Free Software Foundation. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software 15 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 | from functools import wraps 17 | 18 | def secure_function(function): 19 | @wraps(function) 20 | def wrapper(*args, **kwargs): 21 | return function(*args, **kwargs) 22 | wrapper._is_secure = True 23 | return wrapper 24 | -------------------------------------------------------------------------------- /Exscript/util/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | 16 | import inspect 17 | __all__ = [name for name, obj in locals().items() 18 | if not (name.startswith('_') or inspect.ismodule(obj))] 19 | -------------------------------------------------------------------------------- /Exscript/util/cast.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Handy shortcuts for converting types. 17 | """ 18 | import re 19 | import Exscript 20 | 21 | def to_list(item): 22 | """ 23 | If the given item is iterable, this function returns the given item. 24 | If the item is not iterable, this function returns a list with only the 25 | item in it. 26 | 27 | @type item: object 28 | @param item: Any object. 29 | @rtype: list 30 | @return: A list with the item in it. 31 | """ 32 | if hasattr(item, '__iter__'): 33 | return item 34 | return [item] 35 | 36 | def to_host(host, default_protocol = 'telnet', default_domain = ''): 37 | """ 38 | Given a string or a Host object, this function returns a Host object. 39 | 40 | @type host: string|Host 41 | @param host: A hostname (may be URL formatted) or a Host object. 42 | @type default_protocol: str 43 | @param default_protocol: Passed to the Host constructor. 44 | @type default_domain: str 45 | @param default_domain: Appended to each hostname that has no domain. 46 | @rtype: Host 47 | @return: The Host object. 48 | """ 49 | if host is None: 50 | raise TypeError('None can not be cast to Host') 51 | if hasattr(host, 'get_address'): 52 | return host 53 | if default_domain and not '.' in host: 54 | host += '.' + default_domain 55 | return Exscript.Host(host, default_protocol = default_protocol) 56 | 57 | def to_hosts(hosts, default_protocol = 'telnet', default_domain = ''): 58 | """ 59 | Given a string or a Host object, or a list of strings or Host objects, 60 | this function returns a list of Host objects. 61 | 62 | @type hosts: string|Host|list(string)|list(Host) 63 | @param hosts: One or more hosts or hostnames. 64 | @type default_protocol: str 65 | @param default_protocol: Passed to the Host constructor. 66 | @type default_domain: str 67 | @param default_domain: Appended to each hostname that has no domain. 68 | @rtype: list[Host] 69 | @return: A list of Host objects. 70 | """ 71 | return [to_host(h, default_protocol, default_domain) 72 | for h in to_list(hosts)] 73 | 74 | def to_regex(regex, flags = 0): 75 | """ 76 | Given a string, this function returns a new re.RegexObject. 77 | Given a re.RegexObject, this function just returns the same object. 78 | 79 | @type regex: string|re.RegexObject 80 | @param regex: A regex or a re.RegexObject 81 | @type flags: int 82 | @param flags: See Python's re.compile(). 83 | @rtype: re.RegexObject 84 | @return: The Python regex object. 85 | """ 86 | if regex is None: 87 | raise TypeError('None can not be cast to re.RegexObject') 88 | if hasattr(regex, 'match'): 89 | return regex 90 | return re.compile(regex, flags) 91 | 92 | def to_regexs(regexs): 93 | """ 94 | Given a string or a re.RegexObject, or a list of strings or 95 | re.RegexObjects, this function returns a list of re.RegexObjects. 96 | 97 | @type regexs: str|re.RegexObject|list(str|re.RegexObject) 98 | @param regexs: One or more regexs or re.RegexObjects. 99 | @rtype: list(re.RegexObject) 100 | @return: A list of re.RegexObjects. 101 | """ 102 | return [to_regex(r) for r in to_list(regexs)] 103 | -------------------------------------------------------------------------------- /Exscript/util/crypt.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Encryption related utilities. 17 | """ 18 | from Exscript.external.otp import generate 19 | 20 | def otp(password, seed, sequence): 21 | """ 22 | Calculates a one-time password hash using the given password, seed, and 23 | sequence number and returns it. 24 | Uses the MD4/sixword algorithm as supported by TACACS+ servers. 25 | 26 | @type password: string 27 | @param password: A password. 28 | @type seed: string 29 | @param seed: A username. 30 | @type sequence: int 31 | @param sequence: A sequence number. 32 | @rtype: string 33 | @return: A hash. 34 | """ 35 | return generate(password, seed, sequence, 1, 'md4', 'sixword')[0] 36 | -------------------------------------------------------------------------------- /Exscript/util/daemonize.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2011 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Daemonizing a process. 17 | """ 18 | import sys 19 | import os 20 | 21 | def _redirect_output(filename): 22 | out_log = open(filename, 'a+', 0) 23 | err_log = open(filename, 'a+', 0) 24 | dev_null = open(os.devnull, 'r') 25 | os.close(sys.stdin.fileno()) 26 | os.close(sys.stdout.fileno()) 27 | os.close(sys.stderr.fileno()) 28 | os.dup2(out_log.fileno(), sys.stdout.fileno()) 29 | os.dup2(err_log.fileno(), sys.stderr.fileno()) 30 | os.dup2(dev_null.fileno(), sys.stdin.fileno()) 31 | 32 | def daemonize(): 33 | """ 34 | Forks and daemonizes the current process. Does not automatically track 35 | the process id; to do this, use L{Exscript.util.pidutil}. 36 | """ 37 | sys.stdout.flush() 38 | sys.stderr.flush() 39 | 40 | # UNIX double-fork magic. We need to fork before any threads are 41 | # created. 42 | pid = os.fork() 43 | if pid > 0: 44 | # Exit first parent. 45 | sys.exit(0) 46 | 47 | # Decouple from parent environment. 48 | os.chdir('/') 49 | os.setsid() 50 | os.umask(0) 51 | 52 | # Now fork again. 53 | pid = os.fork() 54 | if pid > 0: 55 | # Exit second parent. 56 | sys.exit(0) 57 | 58 | _redirect_output(os.devnull) 59 | -------------------------------------------------------------------------------- /Exscript/util/ip.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Wrapper around the ipv4 and ipv6 modules to handle both, ipv4 and ipv6. 17 | """ 18 | from Exscript.util import ipv4 19 | from Exscript.util import ipv6 20 | 21 | def is_ip(string): 22 | """ 23 | Returns True if the given string is an IPv4 or IPv6 address, False 24 | otherwise. 25 | 26 | @type string: string 27 | @param string: Any string. 28 | @rtype: bool 29 | @return: True if the string is an IP address, False otherwise. 30 | """ 31 | return ipv4.is_ip(string) or ipv6.is_ip(string) 32 | 33 | def _call_func(funcname, ip, *args): 34 | if ipv4.is_ip(ip): 35 | return ipv4.__dict__[funcname](ip, *args) 36 | elif ipv6.is_ip(ip): 37 | return ipv6.__dict__[funcname](ip, *args) 38 | raise ValueError('neither ipv4 nor ipv6: ' + repr(ip)) 39 | 40 | def normalize_ip(ip): 41 | """ 42 | Transform the address into a fixed-length form, such as: 43 | 44 | 192.168.0.1 -> 192.168.000.001 45 | 1234::A -> 1234:0000:0000:0000:0000:0000:0000:000a 46 | 47 | @type ip: string 48 | @param ip: An IP address. 49 | @rtype: string 50 | @return: The normalized IP. 51 | """ 52 | return _call_func('normalize_ip', ip) 53 | 54 | def clean_ip(ip): 55 | """ 56 | Cleans the ip address up, useful for removing leading zeros, e.g.:: 57 | 58 | 192.168.010.001 -> 192.168.10.1 59 | 1234:0000:0000:0000:0000:0000:0000:000A -> 1234::a 60 | 61 | @type ip: string 62 | @param ip: An IP address. 63 | @rtype: string 64 | @return: The cleaned up IP. 65 | """ 66 | return _call_func('clean_ip', ip) 67 | -------------------------------------------------------------------------------- /Exscript/util/log.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Logging utilities. 17 | """ 18 | from Exscript.FileLogger import FileLogger 19 | from Exscript.util.impl import add_label 20 | 21 | _loggers = [] 22 | 23 | def log_to(logger): 24 | """ 25 | Wraps a function that has a connection passed such that everything that 26 | happens on the connection is logged using the given logger. 27 | 28 | @type logger: Logger 29 | @param logger: The logger that handles the logging. 30 | """ 31 | logger_id = id(logger) 32 | def decorator(function): 33 | func = add_label(function, 'log_to', logger_id = logger_id) 34 | return func 35 | return decorator 36 | 37 | def log_to_file(logdir, mode = 'a', delete = False, clearmem = True): 38 | """ 39 | Like L{log_to()}, but automatically creates a new FileLogger 40 | instead of having one passed. 41 | Note that the logger stays alive (in memory) forever. If you need 42 | to control the lifetime of a logger, use L{log_to()} instead. 43 | """ 44 | logger = FileLogger(logdir, mode, delete, clearmem) 45 | _loggers.append(logger) 46 | return log_to(logger) 47 | -------------------------------------------------------------------------------- /Exscript/util/pidutil.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2011 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Handling PID (process id) files. 17 | """ 18 | import os 19 | import logging 20 | import fcntl 21 | import errno 22 | 23 | def read(path): 24 | """ 25 | Returns the process id from the given file if it exists, or None 26 | otherwise. Raises an exception for all other types of OSError 27 | while trying to access the file. 28 | 29 | @type path: str 30 | @param path: The name of the pidfile. 31 | @rtype: int or None 32 | @return: The PID, or none if the file was not found. 33 | """ 34 | # Try to read the pid from the pidfile. 35 | logging.info("Checking pidfile '%s'", path) 36 | try: 37 | return int(open(path).read()) 38 | except IOError, (code, text): 39 | if code == errno.ENOENT: # no such file or directory 40 | return None 41 | raise 42 | 43 | def isalive(path): 44 | """ 45 | Returns True if the file with the given name contains a process 46 | id that is still alive. 47 | Returns False otherwise. 48 | 49 | @type path: str 50 | @param path: The name of the pidfile. 51 | @rtype: bool 52 | @return: Whether the process is alive. 53 | """ 54 | # try to read the pid from the pidfile 55 | pid = read(path) 56 | if pid is None: 57 | return False 58 | 59 | # Check if a process with the given pid exists. 60 | try: 61 | os.kill(pid, 0) # Signal 0 does not kill, but check. 62 | except OSError, (code, text): 63 | if code == errno.ESRCH: # No such process. 64 | return False 65 | return True 66 | 67 | def kill(path): 68 | """ 69 | Kills the process, if it still exists. 70 | 71 | @type path: str 72 | @param path: The name of the pidfile. 73 | """ 74 | # try to read the pid from the pidfile 75 | pid = read(path) 76 | if pid is None: 77 | return 78 | 79 | # Try to kill the process. 80 | logging.info("Killing PID %s", pid) 81 | try: 82 | os.kill(pid, 9) 83 | except OSError, (code, text): 84 | # re-raise if the error wasn't "No such process" 85 | if code != errno.ESRCH: 86 | raise 87 | 88 | def write(path): 89 | """ 90 | Writes the current process id to the given pidfile. 91 | 92 | @type path: str 93 | @param path: The name of the pidfile. 94 | """ 95 | pid = os.getpid() 96 | logging.info("Writing PID %s to '%s'", pid, path) 97 | try: 98 | pidfile = open(path, 'wb') 99 | # get a non-blocking exclusive lock 100 | fcntl.flock(pidfile.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB) 101 | # clear out the file 102 | pidfile.seek(0) 103 | pidfile.truncate(0) 104 | # write the pid 105 | pidfile.write(str(pid)) 106 | finally: 107 | try: 108 | pidfile.close() 109 | except: 110 | pass 111 | 112 | def remove(path): 113 | """ 114 | Deletes the pidfile if it exists. 115 | 116 | @type path: str 117 | @param path: The name of the pidfile. 118 | """ 119 | logging.info("Removing pidfile '%s'", path) 120 | try: 121 | os.unlink(path) 122 | except IOError: 123 | pass 124 | -------------------------------------------------------------------------------- /Exscript/util/report.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Formatting logs into human readable reports. 17 | """ 18 | 19 | def _underline(text, line = '-'): 20 | return [text, line * len(text)] 21 | 22 | def status(logger): 23 | """ 24 | Creates a one-line summary on the actions that were logged by the given 25 | Logger. 26 | 27 | @type logger: Logger 28 | @param logger: The logger that recorded what happened in the queue. 29 | @rtype: string 30 | @return: A string summarizing the status. 31 | """ 32 | aborted = logger.get_aborted_actions() 33 | succeeded = logger.get_succeeded_actions() 34 | total = aborted + succeeded 35 | if total == 0: 36 | return 'No actions done' 37 | elif total == 1 and succeeded == 1: 38 | return 'One action done (succeeded)' 39 | elif total == 1 and succeeded == 0: 40 | return 'One action done (failed)' 41 | elif total == succeeded: 42 | return '%d actions total (all succeeded)' % total 43 | elif succeeded == 0: 44 | return '%d actions total (all failed)' % total 45 | else: 46 | msg = '%d actions total (%d failed, %d succeeded)' 47 | return msg % (total, aborted, succeeded) 48 | 49 | def summarize(logger): 50 | """ 51 | Creates a short summary on the actions that were logged by the given 52 | Logger. 53 | 54 | @type logger: Logger 55 | @param logger: The logger that recorded what happened in the queue. 56 | @rtype: string 57 | @return: A string summarizing the status of every performed task. 58 | """ 59 | summary = [] 60 | for log in logger.get_logs(): 61 | thestatus = log.has_error() and log.get_error(False) or 'ok' 62 | name = log.get_name() 63 | summary.append(name + ': ' + thestatus) 64 | return '\n'.join(summary) 65 | 66 | def format(logger, 67 | show_successful = True, 68 | show_errors = True, 69 | show_traceback = True): 70 | """ 71 | Prints a report of the actions that were logged by the given Logger. 72 | The report contains a list of successful actions, as well as the full 73 | error message on failed actions. 74 | 75 | @type logger: Logger 76 | @param logger: The logger that recorded what happened in the queue. 77 | @rtype: string 78 | @return: A string summarizing the status of every performed task. 79 | """ 80 | output = [] 81 | 82 | # Print failed actions. 83 | errors = logger.get_aborted_actions() 84 | if show_errors and errors: 85 | output += _underline('Failed actions:') 86 | for log in logger.get_aborted_logs(): 87 | if show_traceback: 88 | output.append(log.get_name() + ':') 89 | output.append(log.get_error()) 90 | else: 91 | output.append(log.get_name() + ': ' + log.get_error(False)) 92 | output.append('') 93 | 94 | # Print successful actions. 95 | if show_successful: 96 | output += _underline('Successful actions:') 97 | for log in logger.get_succeeded_logs(): 98 | output.append(log.get_name()) 99 | output.append('') 100 | 101 | return '\n'.join(output).strip() 102 | -------------------------------------------------------------------------------- /Exscript/util/sigint.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | A class for catching SIGINT, such that CTRL+c works. 17 | """ 18 | import os 19 | import sys 20 | import signal 21 | 22 | class SigIntWatcher(object): 23 | """ 24 | This class solves two problems with multithreaded programs in Python: 25 | 26 | - A signal might be delivered to any thread and 27 | - if the thread that gets the signal is waiting, the signal 28 | is ignored (which is a bug). 29 | 30 | This class forks and catches sigint for Exscript. 31 | 32 | The watcher is a concurrent process (not thread) that waits for a 33 | signal and the process that contains the threads. 34 | Works on Linux, Solaris, MacOS, and AIX. Known not to work 35 | on Windows. 36 | """ 37 | def __init__(self): 38 | """ 39 | Creates a child process, which returns. The parent 40 | process waits for a KeyboardInterrupt and then kills 41 | the child process. 42 | """ 43 | try: 44 | self.child = os.fork() 45 | except AttributeError: # platforms that don't have os.fork 46 | pass 47 | except RuntimeError: 48 | pass # prevent "not holding the import lock" on some systems. 49 | if self.child == 0: 50 | return 51 | else: 52 | self.watch() 53 | 54 | def watch(self): 55 | try: 56 | pid, status = os.wait() 57 | except KeyboardInterrupt: 58 | print '********** SIGINT RECEIVED - SHUTTING DOWN! **********' 59 | self.kill() 60 | sys.exit(1) 61 | sys.exit(status >> 8) 62 | 63 | def kill(self): 64 | try: 65 | os.kill(self.child, signal.SIGKILL) 66 | except OSError: 67 | pass 68 | -------------------------------------------------------------------------------- /Exscript/util/sigintcatcher.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | When imported, this module catches KeyboardInterrupt (SIGINT). 17 | It is a convenience wrapper around sigint.SigIntWatcher() 18 | such that all that is required for the change to take effect 19 | is the following statement:: 20 | 21 | import Exscript.util.sigintcatcher 22 | 23 | Be warned that this way of importing breaks on some systems, because a 24 | fork during an import may cause the following error:: 25 | 26 | RuntimeError: not holding the import lock 27 | 28 | So in general it is recommended to use the L{sigint.SigIntWatcher()} 29 | class directly. 30 | """ 31 | from Exscript.util.sigint import SigIntWatcher 32 | _watcher = SigIntWatcher() 33 | -------------------------------------------------------------------------------- /Exscript/util/start.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Quickstart methods for the Exscript queue. 17 | """ 18 | from Exscript import Queue 19 | from Exscript.util.interact import read_login 20 | from Exscript.util.decorator import autologin, autoauthenticate 21 | 22 | def run(users, hosts, func, **kwargs): 23 | """ 24 | Convenience function that creates an Exscript.Queue instance, adds 25 | the given accounts, and calls Queue.run() with the given 26 | hosts and function as an argument. 27 | 28 | If you also want to pass arguments to the given function, you may use 29 | util.decorator.bind() like this:: 30 | 31 | def my_callback(job, host, conn, my_arg, **kwargs): 32 | print my_arg, kwargs.get('foo') 33 | 34 | run(account, 35 | host, 36 | bind(my_callback, 'hello', foo = 'world'), 37 | max_threads = 10) 38 | 39 | @type users: Account|list[Account] 40 | @param users: The account(s) to use for logging in. 41 | @type hosts: Host|list[Host] 42 | @param hosts: A list of Host objects. 43 | @type func: function 44 | @param func: The callback function. 45 | @type kwargs: dict 46 | @param kwargs: Passed to the Exscript.Queue constructor. 47 | """ 48 | queue = Queue(**kwargs) 49 | queue.add_account(users) 50 | queue.run(hosts, func) 51 | queue.destroy() 52 | 53 | def quickrun(hosts, func, **kwargs): 54 | """ 55 | A wrapper around run() that creates the account by asking the user 56 | for entering his login information. 57 | 58 | @type hosts: Host|list[Host] 59 | @param hosts: A list of Host objects. 60 | @type func: function 61 | @param func: The callback function. 62 | @type kwargs: dict 63 | @param kwargs: Passed to the Exscript.Queue constructor. 64 | """ 65 | run(read_login(), hosts, func, **kwargs) 66 | 67 | def start(users, hosts, func, only_authenticate = False, **kwargs): 68 | """ 69 | Like run(), but automatically logs into the host before passing 70 | the host to the callback function. 71 | 72 | @type users: Account|list[Account] 73 | @param users: The account(s) to use for logging in. 74 | @type hosts: Host|list[Host] 75 | @param hosts: A list of Host objects. 76 | @type func: function 77 | @param func: The callback function. 78 | @type only_authenticate: bool 79 | @param only_authenticate: don't authorize, just authenticate? 80 | @type kwargs: dict 81 | @param kwargs: Passed to the Exscript.Queue constructor. 82 | """ 83 | if only_authenticate: 84 | run(users, hosts, autoauthenticate()(func), **kwargs) 85 | else: 86 | run(users, hosts, autologin()(func), **kwargs) 87 | 88 | def quickstart(hosts, func, only_authenticate = False, **kwargs): 89 | """ 90 | Like quickrun(), but automatically logs into the host before passing 91 | the connection to the callback function. 92 | 93 | @type hosts: Host|list[Host] 94 | @param hosts: A list of Host objects. 95 | @type func: function 96 | @param func: The callback function. 97 | @type only_authenticate: bool 98 | @param only_authenticate: don't authorize, just authenticate? 99 | @type kwargs: dict 100 | @param kwargs: Passed to the Exscript.Queue constructor. 101 | """ 102 | if only_authenticate: 103 | quickrun(hosts, autoauthenticate()(func), **kwargs) 104 | else: 105 | quickrun(hosts, autologin()(func), **kwargs) 106 | -------------------------------------------------------------------------------- /Exscript/util/syslog.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Send messages to a syslog server. 17 | """ 18 | import os 19 | import sys 20 | import imp 21 | import socket 22 | 23 | # This way of loading a module prevents Python from looking in the 24 | # current directory. (We need to avoid it due to the syslog module 25 | # name collision.) 26 | syslog = imp.load_module('syslog', *imp.find_module('syslog')) 27 | 28 | def netlog(message, 29 | source = None, 30 | host = 'localhost', 31 | port = 514, 32 | priority = syslog.LOG_DEBUG, 33 | facility = syslog.LOG_USER): 34 | """ 35 | Python's built in syslog module does not support networking, so 36 | this is the alternative. 37 | The source argument specifies the message source that is 38 | documented on the receiving server. It defaults to "scriptname[pid]", 39 | where "scriptname" is sys.argv[0], and pid is the current process id. 40 | The priority and facility arguments are equivalent to those of 41 | Python's built in syslog module. 42 | 43 | @type source: str 44 | @param source: The source address. 45 | @type host: str 46 | @param host: The IP address or hostname of the receiving server. 47 | @type port: str 48 | @param port: The TCP port number of the receiving server. 49 | @type priority: int 50 | @param priority: The message priority. 51 | @type facility: int 52 | @param facility: The message facility. 53 | """ 54 | if not source: 55 | source = '%s[%s]' + (sys.argv[0], os.getpid()) 56 | data = '<%d>%s: %s' % (priority + facility, source, message) 57 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 58 | sock.sendto(data, (host, port)) 59 | sock.close() 60 | -------------------------------------------------------------------------------- /Exscript/util/tty.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2011 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | TTY utilities. 17 | """ 18 | import os 19 | import sys 20 | import struct 21 | from subprocess import Popen, PIPE 22 | 23 | def _get_terminal_size(fd): 24 | try: 25 | import fcntl 26 | import termios 27 | except ImportError: 28 | return None 29 | s = struct.pack('HHHH', 0, 0, 0, 0) 30 | try: 31 | x = fcntl.ioctl(fd, termios.TIOCGWINSZ, s) 32 | except IOError: # Window size ioctl not supported. 33 | return None 34 | try: 35 | rows, cols, x_pixels, y_pixels = struct.unpack('HHHH', x) 36 | except struct.error: 37 | return None 38 | return rows, cols 39 | 40 | def get_terminal_size(default_rows = 25, default_cols = 80): 41 | """ 42 | Returns the number of lines and columns of the current terminal. 43 | It attempts several strategies to determine the size and if all fail, 44 | it returns (80, 25). 45 | 46 | @rtype: int, int 47 | @return: The rows and columns of the terminal. 48 | """ 49 | # Collect a list of viable input channels that may tell us something 50 | # about the terminal dimensions. 51 | fileno_list = [] 52 | try: 53 | fileno_list.append(sys.stdout.fileno()) 54 | except AttributeError: 55 | # Channel was redirected to an object that has no fileno() 56 | pass 57 | try: 58 | fileno_list.append(sys.stdin.fileno()) 59 | except AttributeError: 60 | pass 61 | try: 62 | fileno_list.append(sys.stderr.fileno()) 63 | except AttributeError: 64 | pass 65 | 66 | # Ask each channel for the terminal window size. 67 | for fd in fileno_list: 68 | try: 69 | rows, cols = _get_terminal_size(fd) 70 | except TypeError: 71 | # _get_terminal_size() returned None. 72 | pass 73 | else: 74 | return rows, cols 75 | 76 | # Try os.ctermid() 77 | try: 78 | fd = os.open(os.ctermid(), os.O_RDONLY) 79 | except AttributeError: 80 | # os.ctermid does not exist on Windows. 81 | pass 82 | except OSError: 83 | # The device pointed to by os.ctermid() does not exist. 84 | pass 85 | else: 86 | try: 87 | rows, cols = _get_terminal_size(fd) 88 | except TypeError: 89 | # _get_terminal_size() returned None. 90 | pass 91 | else: 92 | return rows, cols 93 | finally: 94 | os.close(fd) 95 | 96 | # Try `stty size` 97 | devnull = open(os.devnull, 'w') 98 | try: 99 | process = Popen(['stty', 'size'], stderr = devnull, stdout = PIPE) 100 | except OSError: 101 | pass 102 | else: 103 | errcode = process.wait() 104 | output = process.stdout.read() 105 | devnull.close() 106 | try: 107 | rows, cols = output.split() 108 | return int(rows), int(cols) 109 | except (ValueError, TypeError): 110 | pass 111 | 112 | # Try environment variables. 113 | try: 114 | return tuple(int(os.getenv(var)) for var in ('LINES', 'COLUMNS')) 115 | except (ValueError, TypeError): 116 | pass 117 | 118 | # Give up. 119 | return default_rows, default_cols 120 | -------------------------------------------------------------------------------- /Exscript/util/weakmethod.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Weak references to bound and unbound methods. 17 | """ 18 | import weakref 19 | 20 | class DeadMethodCalled(Exception): 21 | """ 22 | Raised by L{WeakMethod} if it is called when the referenced object 23 | is already dead. 24 | """ 25 | pass 26 | 27 | class WeakMethod(object): 28 | """ 29 | Do not create this class directly; use L{ref()} instead. 30 | """ 31 | __slots__ = 'name', 'callback' 32 | 33 | def __init__(self, name, callback): 34 | """ 35 | Constructor. Do not use directly, use L{ref()} instead. 36 | """ 37 | self.name = name 38 | self.callback = callback 39 | 40 | def _dead(self, ref): 41 | if self.callback is not None: 42 | self.callback(self) 43 | 44 | def get_function(self): 45 | """ 46 | Returns the referenced method/function if it is still alive. 47 | Returns None otherwise. 48 | 49 | @rtype: callable|None 50 | @return: The referenced function if it is still alive. 51 | """ 52 | raise NotImplementedError() 53 | 54 | def isalive(self): 55 | """ 56 | Returns True if the referenced function is still alive, False 57 | otherwise. 58 | 59 | @rtype: bool 60 | @return: Whether the referenced function is still alive. 61 | """ 62 | return self.get_function() is not None 63 | 64 | def __call__(self, *args, **kwargs): 65 | """ 66 | Proxied to the underlying function or method. Raises L{DeadMethodCalled} 67 | if the referenced function is dead. 68 | 69 | @rtype: object 70 | @return: Whatever the referenced function returned. 71 | """ 72 | method = self.get_function() 73 | if method is None: 74 | raise DeadMethodCalled('method called on dead object ' + self.name) 75 | method(*args, **kwargs) 76 | 77 | class _WeakMethodBound(WeakMethod): 78 | __slots__ = 'name', 'callback', 'f', 'c' 79 | 80 | def __init__(self, f, callback): 81 | name = f.__self__.__class__.__name__ + '.' + f.__func__.__name__ 82 | WeakMethod.__init__(self, name, callback) 83 | self.f = f.__func__ 84 | self.c = weakref.ref(f.__self__, self._dead) 85 | 86 | def get_function(self): 87 | cls = self.c() 88 | if cls is None: 89 | return None 90 | return getattr(cls, self.f.__name__) 91 | 92 | class _WeakMethodFree(WeakMethod): 93 | __slots__ = 'name', 'callback', 'f' 94 | 95 | def __init__(self, f, callback): 96 | WeakMethod.__init__(self, f.__class__.__name__, callback) 97 | self.f = weakref.ref(f, self._dead) 98 | 99 | def get_function(self): 100 | return self.f() 101 | 102 | def ref(function, callback = None): 103 | """ 104 | Returns a weak reference to the given method or function. 105 | If the callback argument is not None, it is called as soon 106 | as the referenced function is garbage deleted. 107 | 108 | @type function: callable 109 | @param function: The function to reference. 110 | @type callback: callable 111 | @param callback: Called when the function dies. 112 | """ 113 | try: 114 | function.__func__ 115 | except AttributeError: 116 | return _WeakMethodFree(function, callback) 117 | return _WeakMethodBound(function, callback) 118 | -------------------------------------------------------------------------------- /Exscript/version.py: -------------------------------------------------------------------------------- 1 | """ 2 | Warning: This file is automatically generated. 3 | """ 4 | __version__ = 'DEVELOPMENT' 5 | -------------------------------------------------------------------------------- /Exscript/workqueue/Job.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | import sys 16 | import threading 17 | import multiprocessing 18 | from copy import copy 19 | from functools import partial 20 | from multiprocessing import Pipe 21 | from Exscript.util.impl import serializeable_sys_exc_info 22 | 23 | class _ChildWatcher(threading.Thread): 24 | def __init__(self, child, callback): 25 | threading.Thread.__init__(self) 26 | self.child = child 27 | self.cb = callback 28 | 29 | def __copy__(self): 30 | watcher = _ChildWatcher(copy(self.child), self.cb) 31 | return watcher 32 | 33 | def run(self): 34 | to_child, to_self = Pipe() 35 | try: 36 | self.child.start(to_self) 37 | result = to_child.recv() 38 | self.child.join() 39 | except: 40 | result = sys.exc_info() 41 | finally: 42 | to_child.close() 43 | to_self.close() 44 | if result == '': 45 | self.cb(None) 46 | else: 47 | self.cb(result) 48 | 49 | def _make_process_class(base, clsname): 50 | class process_cls(base): 51 | def __init__(self, id, function, name, data): 52 | base.__init__(self, name = name) 53 | self.id = id 54 | self.pipe = None 55 | self.function = function 56 | self.failures = 0 57 | self.data = data 58 | 59 | def run(self): 60 | """ 61 | Start the associated function. 62 | """ 63 | try: 64 | self.function(self) 65 | except: 66 | self.pipe.send(serializeable_sys_exc_info()) 67 | else: 68 | self.pipe.send('') 69 | finally: 70 | self.pipe = None 71 | 72 | def start(self, pipe): 73 | self.pipe = pipe 74 | base.start(self) 75 | process_cls.__name__ = clsname 76 | return process_cls 77 | 78 | Thread = _make_process_class(threading.Thread, 'Thread') 79 | Process = _make_process_class(multiprocessing.Process, 'Process') 80 | 81 | class Job(object): 82 | __slots__ = ('id', 83 | 'func', 84 | 'name', 85 | 'times', 86 | 'failures', 87 | 'data', 88 | 'child', 89 | 'watcher') 90 | 91 | def __init__(self, function, name, times, data): 92 | self.id = None 93 | self.func = function 94 | self.name = name is None and str(id(function)) or name 95 | self.times = times 96 | self.failures = 0 97 | self.data = data 98 | self.child = None 99 | self.watcher = None 100 | 101 | def start(self, child_cls, on_complete): 102 | self.child = child_cls(self.id, self.func, self.name, self.data) 103 | self.child.failures = self.failures 104 | self.watcher = _ChildWatcher(self.child, partial(on_complete, self)) 105 | self.watcher.start() 106 | 107 | def join(self): 108 | self.watcher.join() 109 | self.child = None 110 | -------------------------------------------------------------------------------- /Exscript/workqueue/Task.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2011 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | """ 16 | Represents a batch of enqueued actions. 17 | """ 18 | from Exscript.util.event import Event 19 | 20 | class Task(object): 21 | """ 22 | Represents a batch of running actions. 23 | """ 24 | def __init__(self, workqueue): 25 | self.done_event = Event() 26 | self.workqueue = workqueue 27 | self.job_ids = set() 28 | self.completed = 0 29 | self.workqueue.job_succeeded_event.listen(self._on_job_done) 30 | self.workqueue.job_aborted_event.listen(self._on_job_done) 31 | 32 | def _on_job_done(self, job): 33 | if job.id not in self.job_ids: 34 | return 35 | self.completed += 1 36 | if self.is_completed(): 37 | self.done_event() 38 | 39 | def is_completed(self): 40 | """ 41 | Returns True if all actions in the task are completed, returns 42 | False otherwise. 43 | 44 | @rtype: bool 45 | @return: Whether the task is completed. 46 | """ 47 | return self.completed == len(self.job_ids) 48 | 49 | def wait(self): 50 | """ 51 | Waits until all actions in the task have completed. 52 | Does not use any polling. 53 | """ 54 | for theid in self.job_ids: 55 | self.workqueue.wait_for(theid) 56 | 57 | def add_job_id(self, theid): 58 | """ 59 | Adds a job to the task. 60 | 61 | @type theid: int 62 | @param theid: The id of the job. 63 | """ 64 | self.job_ids.add(theid) 65 | -------------------------------------------------------------------------------- /Exscript/workqueue/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2007-2010 Samuel Abels. 2 | # 3 | # This program is free software; you can redistribute it and/or modify 4 | # it under the terms of the GNU General Public License version 2, as 5 | # published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | from Exscript.workqueue.WorkQueue import WorkQueue 16 | from Exscript.workqueue.Task import Task 17 | from Exscript.workqueue.Pipeline import Pipeline 18 | 19 | import inspect 20 | __all__ = [name for name, obj in locals().items() 21 | if not (name.startswith('_') or inspect.ismodule(obj))] 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Climber 2 | ======= 3 | 4 | Automated auditing tool to check UNIX/Linux systems misconfigurations 5 | which may allow local privilege escalation. 6 | 7 | 8 | Dependencies 9 | ------------ 10 | 11 | * python >= 2.7 12 | * python-crypto 13 | * python-mako 14 | * python-paramiko 15 | 16 | 17 | Note 18 | ------ 19 | Climber needs Exscript, a Python module and a template processor for 20 | automating network connections over protocols such as Telnet or SSH. 21 | 22 | https://github.com/knipknap/exscript 23 | 24 | This module is already included in Climber sources. 25 | 26 | 27 | License 28 | ------- 29 | This program is free software: you can redistribute it and/or modify 30 | it under the terms of the GNU General Public License as published by 31 | the Free Software Foundation, either version 3 of the License, or 32 | (at your option) any later version. 33 | -------------------------------------------------------------------------------- /html/css/report.css: -------------------------------------------------------------------------------- 1 | @CHARSET "UTF-8"; 2 | 3 | #menu-collapsible { 4 | text-align: right; 5 | } 6 | 7 | #navigation { 8 | width:250px; 9 | } 10 | 11 | #content { 12 | width:100%; 13 | } 14 | 15 | #navigation, 16 | #content { 17 | float:left; 18 | margin:10px; 19 | } 20 | 21 | .collapsible, 22 | .page_collapsible { 23 | margin: 0; 24 | padding:10px; 25 | height:20px; 26 | 27 | border-top:#f0f0f0 1px solid; 28 | background: #cccccc; 29 | 30 | font-family: Arial, Helvetica, sans-serif; 31 | text-decoration:none; 32 | text-transform:uppercase; 33 | color: #000; 34 | font-size:1em; 35 | } 36 | 37 | .collapse-open { 38 | background:#000; 39 | color: #fff; 40 | } 41 | 42 | .collapse-open span { 43 | display:block; 44 | float:right; 45 | padding:10px; 46 | } 47 | 48 | .collapse-open span { 49 | background:url(../images/minus.png) center center no-repeat; 50 | } 51 | 52 | .collapse-close span { 53 | display:block; 54 | float:right; 55 | background:url(../images/plus.png) center center no-repeat; 56 | padding:10px; 57 | } 58 | 59 | div.container { 60 | padding:0; 61 | margin:0; 62 | } 63 | 64 | div.content { 65 | background:#f0f0f0; 66 | margin: 0; 67 | padding:10px; 68 | font-size:.9em; 69 | line-height:1.5em; 70 | font-family:"Helvetica Neue", Arial, Helvetica, Geneva, sans-serif; 71 | } 72 | 73 | div.content ul, div.content p { 74 | margin:0; 75 | padding:3px; 76 | } 77 | 78 | div.content ul li { 79 | list-style-position:inside; 80 | line-height:25px; 81 | } 82 | 83 | div.content ul li a { 84 | color:#555555; 85 | } 86 | 87 | code { 88 | overflow:auto; 89 | } 90 | -------------------------------------------------------------------------------- /html/images/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raffaele-forte/climber/5530a780446e35b1ce977bae140557050fe0b47c/html/images/minus.png -------------------------------------------------------------------------------- /html/images/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raffaele-forte/climber/5530a780446e35b1ce977bae140557050fe0b47c/html/images/plus.png -------------------------------------------------------------------------------- /html/javascripts/jquery.cookie.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Cookie Plugin v1.3.1 3 | * https://github.com/carhartl/jquery-cookie 4 | * 5 | * Copyright 2013 Klaus Hartl 6 | * Released under the MIT license 7 | */ 8 | (function (factory) { 9 | if (typeof define === 'function' && define.amd) { 10 | // AMD. Register as anonymous module. 11 | define(['jquery'], factory); 12 | } else { 13 | // Browser globals. 14 | factory(jQuery); 15 | } 16 | }(function ($) { 17 | 18 | var pluses = /\+/g; 19 | 20 | function raw(s) { 21 | return s; 22 | } 23 | 24 | function decoded(s) { 25 | return decodeURIComponent(s.replace(pluses, ' ')); 26 | } 27 | 28 | function converted(s) { 29 | if (s.indexOf('"') === 0) { 30 | // This is a quoted cookie as according to RFC2068, unescape 31 | s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); 32 | } 33 | try { 34 | return config.json ? JSON.parse(s) : s; 35 | } catch(er) {} 36 | } 37 | 38 | var config = $.cookie = function (key, value, options) { 39 | 40 | // write 41 | if (value !== undefined) { 42 | options = $.extend({}, config.defaults, options); 43 | 44 | if (typeof options.expires === 'number') { 45 | var days = options.expires, t = options.expires = new Date(); 46 | t.setDate(t.getDate() + days); 47 | } 48 | 49 | value = config.json ? JSON.stringify(value) : String(value); 50 | 51 | return (document.cookie = [ 52 | config.raw ? key : encodeURIComponent(key), 53 | '=', 54 | config.raw ? value : encodeURIComponent(value), 55 | options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE 56 | options.path ? '; path=' + options.path : '', 57 | options.domain ? '; domain=' + options.domain : '', 58 | options.secure ? '; secure' : '' 59 | ].join('')); 60 | } 61 | 62 | // read 63 | var decode = config.raw ? raw : decoded; 64 | var cookies = document.cookie.split('; '); 65 | var result = key ? undefined : {}; 66 | for (var i = 0, l = cookies.length; i < l; i++) { 67 | var parts = cookies[i].split('='); 68 | var name = decode(parts.shift()); 69 | var cookie = decode(parts.join('=')); 70 | 71 | if (key && key === name) { 72 | result = converted(cookie); 73 | break; 74 | } 75 | 76 | if (!key) { 77 | result[name] = converted(cookie); 78 | } 79 | } 80 | 81 | return result; 82 | }; 83 | 84 | config.defaults = {}; 85 | 86 | $.removeCookie = function (key, options) { 87 | if ($.cookie(key) !== undefined) { 88 | // Must not alter options, thus extending a fresh object... 89 | $.cookie(key, '', $.extend({}, options, { expires: -1 })); 90 | return true; 91 | } 92 | return false; 93 | }; 94 | 95 | })); 96 | -------------------------------------------------------------------------------- /plugins/exploit/shellshock: -------------------------------------------------------------------------------- 1 | env VAR='() { :;}; echo Bash is vulnerable!' bash -c "echo Bash is not vulnerable" -------------------------------------------------------------------------------- /plugins/file_systems/df: -------------------------------------------------------------------------------- 1 | df -h 2 | -------------------------------------------------------------------------------- /plugins/file_systems/fstab: -------------------------------------------------------------------------------- 1 | cat /etc/fstab 2 | -------------------------------------------------------------------------------- /plugins/file_systems/mount: -------------------------------------------------------------------------------- 1 | mount 2 | -------------------------------------------------------------------------------- /plugins/file_systems/sgid: -------------------------------------------------------------------------------- 1 | find / -perm -g=s -type f 2>/dev/null 2 | -------------------------------------------------------------------------------- /plugins/file_systems/sticky_bit: -------------------------------------------------------------------------------- 1 | find / -perm -1000 -type d 2>/dev/null 2 | -------------------------------------------------------------------------------- /plugins/file_systems/suid: -------------------------------------------------------------------------------- 1 | find / -perm -u=s -type f 2>/dev/null 2 | -------------------------------------------------------------------------------- /plugins/file_systems/writable_dirs: -------------------------------------------------------------------------------- 1 | find / -type d -perm -o+w 2>/dev/null 2 | -------------------------------------------------------------------------------- /plugins/file_systems/writable_files: -------------------------------------------------------------------------------- 1 | find / -type f -perm -o+w 2>/dev/null 2 | -------------------------------------------------------------------------------- /plugins/networking/arp: -------------------------------------------------------------------------------- 1 | arp -n 2 | -------------------------------------------------------------------------------- /plugins/networking/hostname: -------------------------------------------------------------------------------- 1 | hostname 2 | -------------------------------------------------------------------------------- /plugins/networking/ifconfig: -------------------------------------------------------------------------------- 1 | ifconfig -a 2 | -------------------------------------------------------------------------------- /plugins/networking/interfaces: -------------------------------------------------------------------------------- 1 | cat /etc/network/interfaces 2 | -------------------------------------------------------------------------------- /plugins/networking/iptables: -------------------------------------------------------------------------------- 1 | iptables -L 2 | -------------------------------------------------------------------------------- /plugins/networking/lsof: -------------------------------------------------------------------------------- 1 | lsof -nPi 2 | -------------------------------------------------------------------------------- /plugins/networking/netstat: -------------------------------------------------------------------------------- 1 | netstat -antup 2 | -------------------------------------------------------------------------------- /plugins/networking/networks: -------------------------------------------------------------------------------- 1 | cat /etc/networks 2 | -------------------------------------------------------------------------------- /plugins/networking/resolv.conf: -------------------------------------------------------------------------------- 1 | cat /etc/resolv.conf 2 | -------------------------------------------------------------------------------- /plugins/networking/route: -------------------------------------------------------------------------------- 1 | route -nee 2 | -------------------------------------------------------------------------------- /plugins/operating_system/crontab: -------------------------------------------------------------------------------- 1 | crontab -l 2 | -------------------------------------------------------------------------------- /plugins/operating_system/dpkg: -------------------------------------------------------------------------------- 1 | dpkg -l 2 | -------------------------------------------------------------------------------- /plugins/operating_system/env: -------------------------------------------------------------------------------- 1 | env 2 | -------------------------------------------------------------------------------- /plugins/operating_system/issue: -------------------------------------------------------------------------------- 1 | cat /etc/issue 2 | -------------------------------------------------------------------------------- /plugins/operating_system/lsb-release: -------------------------------------------------------------------------------- 1 | cat /etc/lsb-release 2 | -------------------------------------------------------------------------------- /plugins/operating_system/motd: -------------------------------------------------------------------------------- 1 | cat /etc/motd 2 | -------------------------------------------------------------------------------- /plugins/operating_system/os-release: -------------------------------------------------------------------------------- 1 | cat /etc/os-release 2 | -------------------------------------------------------------------------------- /plugins/operating_system/ps: -------------------------------------------------------------------------------- 1 | ps aux 2 | -------------------------------------------------------------------------------- /plugins/operating_system/rpm: -------------------------------------------------------------------------------- 1 | rpm -qa 2 | -------------------------------------------------------------------------------- /plugins/operating_system/top: -------------------------------------------------------------------------------- 1 | top -n 1 2 | -------------------------------------------------------------------------------- /plugins/operating_system/uname: -------------------------------------------------------------------------------- 1 | uname -a 2 | -------------------------------------------------------------------------------- /plugins/ssh/authorized_keys: -------------------------------------------------------------------------------- 1 | cat ~/.ssh/authorized_keys 2 | -------------------------------------------------------------------------------- /plugins/ssh/id_dsa: -------------------------------------------------------------------------------- 1 | cat ~/.ssh/id_dsa 2 | -------------------------------------------------------------------------------- /plugins/ssh/id_dsa.pub: -------------------------------------------------------------------------------- 1 | cat ~/.ssh/id_dsa.pub 2 | -------------------------------------------------------------------------------- /plugins/ssh/id_rsa: -------------------------------------------------------------------------------- 1 | cat ~/.ssh/id_rsa 2 | -------------------------------------------------------------------------------- /plugins/ssh/id_rsa.pub: -------------------------------------------------------------------------------- 1 | cat ~/.ssh/id_rsa.pub 2 | -------------------------------------------------------------------------------- /plugins/ssh/identity: -------------------------------------------------------------------------------- 1 | cat ~/.ssh/identity 2 | -------------------------------------------------------------------------------- /plugins/ssh/identity.pub: -------------------------------------------------------------------------------- 1 | cat ~/.ssh/identity.pub 2 | -------------------------------------------------------------------------------- /plugins/users/bash_history: -------------------------------------------------------------------------------- 1 | cat ~/.bash_history 2 | -------------------------------------------------------------------------------- /plugins/users/group: -------------------------------------------------------------------------------- 1 | cat /etc/group 2 | -------------------------------------------------------------------------------- /plugins/users/home: -------------------------------------------------------------------------------- 1 | ls -ahl /home/ 2 | -------------------------------------------------------------------------------- /plugins/users/id: -------------------------------------------------------------------------------- 1 | id 2 | -------------------------------------------------------------------------------- /plugins/users/last: -------------------------------------------------------------------------------- 1 | last 2 | -------------------------------------------------------------------------------- /plugins/users/mail: -------------------------------------------------------------------------------- 1 | ls -alh /var/mail/ 2 | -------------------------------------------------------------------------------- /plugins/users/passwd: -------------------------------------------------------------------------------- 1 | cat /etc/passwd 2 | -------------------------------------------------------------------------------- /plugins/users/root: -------------------------------------------------------------------------------- 1 | ls -ahl /root/ 2 | -------------------------------------------------------------------------------- /plugins/users/shadow: -------------------------------------------------------------------------------- 1 | cat /etc/shadow 2 | -------------------------------------------------------------------------------- /plugins/users/sudo: -------------------------------------------------------------------------------- 1 | export SUDO_ASKPASS="/usr/bin/yes" 2 | sudo -l 3 | -------------------------------------------------------------------------------- /plugins/users/sudoers: -------------------------------------------------------------------------------- 1 | cat /etc/sudoers 2 | -------------------------------------------------------------------------------- /plugins/users/w: -------------------------------------------------------------------------------- 1 | w 2 | -------------------------------------------------------------------------------- /plugins/users/who: -------------------------------------------------------------------------------- 1 | who 2 | -------------------------------------------------------------------------------- /plugins/website/htdocs: -------------------------------------------------------------------------------- 1 | ls -alhR /srv/www/htdocs/ 2 | -------------------------------------------------------------------------------- /plugins/website/html: -------------------------------------------------------------------------------- 1 | ls -alhR /var/www/html/ 2 | -------------------------------------------------------------------------------- /plugins/website/www: -------------------------------------------------------------------------------- 1 | ls -alhR /var/www/ 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Mako==1.0.4 2 | paramiko==1.16.0 3 | pycrypto==2.6.1 4 | --------------------------------------------------------------------------------