def get_options(mods): parser = OptionParser(option_class=eng_option, conflict_handler="resolve") parser.add_option("-m", "--modulation", type="choice", choices=mods.keys(), default='psk', help="Select modulation from: %s [default=%%default]" % (', '.join(mods.keys()),)) parser.add_option("", "--amplitude", type="eng_float", default=0.2, help="set Tx amplitude (0-1) (default=%default)") parser.add_option("-r", "--bitrate", type="eng_float", default=250e3, help="Select modulation bit rate (default=%default)") parser.add_option("-S", "--samples-per-symbol", type="float", default=2, help="set samples/symbol [default=%default]") parser.add_option("","--to-file", default=None, help="Output file for modulated samples") if not parser.has_option("--verbose"): parser.add_option("-v", "--verbose", action="store_true", default=False) if not parser.has_option("--log"): parser.add_option("", "--log", action="store_true", default=False) uhd_transmitter.add_options(parser) for mod in mods.values(): mod.add_options(parser) (options, args) = parser.parse_args() if len(args) != 0: parser.print_help() sys.exit(1) return (options, args)
def get_options(demods): parser = OptionParser(option_class=eng_option, conflict_handler="resolve") parser.add_option("","--from-file", default=None, help="input file of samples to demod") parser.add_option("-m", "--modulation", type="choice", choices=demods.keys(), default='psk', help="Select modulation from: %s [default=%%default]" % (', '.join(demods.keys()),)) parser.add_option("-r", "--bitrate", type="eng_float", default=250e3, help="Select modulation bit rate (default=%default)") parser.add_option("-S", "--samples-per-symbol", type="float", default=2, help="set samples/symbol [default=%default]") if not parser.has_option("--verbose"): parser.add_option("-v", "--verbose", action="store_true", default=False) if not parser.has_option("--log"): parser.add_option("", "--log", action="store_true", default=False, help="Log all parts of flow graph to files (CAUTION: lots of data)") uhd_receiver.add_options(parser) demods = digital.modulation_utils.type_1_demods() for mod in demods.values(): mod.add_options(parser) (options, args) = parser.parse_args() if len(args) != 0: parser.print_help() sys.exit(1) return (options, args)
def get_options(demods): parser = OptionParser(option_class=eng_option, conflict_handler="resolve") parser.add_option("", "--from-file", default=None, help="input file of samples to demod") parser.add_option("-m", "--modulation", type="choice", choices=list(demods.keys()), default='psk', help="Select modulation from: %s [default=%%default]" % (', '.join(list(demods.keys())),)) parser.add_option("-r", "--bitrate", type="eng_float", default=250e3, help="Select modulation bit rate (default=%default)") parser.add_option("-S", "--samples-per-symbol", type="float", default=2, help="set samples/symbol [default=%default]") if not parser.has_option("--verbose"): parser.add_option("-v", "--verbose", action="store_true", default=False) if not parser.has_option("--log"): parser.add_option("", "--log", action="store_true", default=False, help="Log all parts of flow graph to files (CAUTION: lots of data)") uhd_receiver.add_options(parser) demods = digital.modulation_utils.type_1_demods() for mod in list(demods.values()): mod.add_options(parser) (options, args) = parser.parse_args() if len(args) != 0: parser.print_help() sys.exit(1) return (options, args)
def test_option(self): parser = OptionParser() self.pi.options( parser, env={} ) self.assertEqual( parser.has_option( '--xml' ), True ) self.assertEqual( parser.has_option( '--xml-formatter' ), True ) opt = parser.get_option( '--xml' ) self.assertEqual( opt.action, 'store_true' ) self.assertEqual( opt.default, False ) opt = parser.get_option( '--xml-formatter' ) self.assertEqual( opt.action, 'store' ) self.assertEqual( opt.default, 'nosexml.PrettyPrintFormatter' )
def test_classic_migration_options(self): parser = OptionParser() migrate.add_parser_options(parser) self.assertFalse(parser.has_option("--registration-state")) self.assertTrue(parser.has_option("--org")) self.assertTrue(parser.has_option("--environment")) self.assertTrue(parser.has_option("--force")) (opts, args) = parser.parse_args([]) migrate.set_defaults(opts, five_to_six_script=False) self.assertFalse(opts.five_to_six) self.assertEquals("purge", opts.registration_state)
def testAddConfigManagementToParser(self): parser = OptionParser() sampleFunction.addConfigToParser(parser) self.assertTrue(parser.has_option('-c')) self.assertTrue(parser.has_option('--config')) parser.parse_args(args=['-c', self.configFile]) self.assertTrue(isinstance(parser.config, mc.Configuration))
class TestOptionParser(BaseTest): def setUp(self): self.parser = OptionParser() self.parser.add_option("-v", "--verbose", "-n", "--noisy", action="store_true", dest="verbose") self.parser.add_option("-q", "--quiet", "--silent", action="store_false", dest="verbose") def test_add_option_no_Option(self): self.assertTypeError(self.parser.add_option, "not an Option instance: None", None) def test_add_option_invalid_arguments(self): self.assertTypeError(self.parser.add_option, "invalid arguments", None, None) def test_get_option(self): opt1 = self.parser.get_option("-v") self.assert_(isinstance(opt1, Option)) self.assertEqual(opt1._short_opts, ["-v", "-n"]) self.assertEqual(opt1._long_opts, ["--verbose", "--noisy"]) self.assertEqual(opt1.action, "store_true") self.assertEqual(opt1.dest, "verbose") def test_get_option_equals(self): opt1 = self.parser.get_option("-v") opt2 = self.parser.get_option("--verbose") opt3 = self.parser.get_option("-n") opt4 = self.parser.get_option("--noisy") self.assert_(opt1 is opt2 is opt3 is opt4) def test_has_option(self): self.assert_(self.parser.has_option("-v")) self.assert_(self.parser.has_option("--verbose")) def assert_removed(self): self.assert_(self.parser.get_option("-v") is None) self.assert_(self.parser.get_option("--verbose") is None) self.assert_(self.parser.get_option("-n") is None) self.assert_(self.parser.get_option("--noisy") is None) self.failIf(self.parser.has_option("-v")) self.failIf(self.parser.has_option("--verbose")) self.failIf(self.parser.has_option("-n")) self.failIf(self.parser.has_option("--noisy")) self.assert_(self.parser.has_option("-q")) self.assert_(self.parser.has_option("--silent")) def test_remove_short_opt(self): self.parser.remove_option("-n") self.assert_removed() def test_remove_long_opt(self): self.parser.remove_option("--verbose") self.assert_removed() def test_remove_nonexistent(self): self.assertRaises(self.parser.remove_option, ValueError, "no such option 'foo'", funcargs=['foo'])
def test_5to6_options(self): five_to_six = True parser = OptionParser() migrate.add_parser_options(parser, five_to_six) self.assertTrue(parser.has_option("--registration-state")) self.assertFalse(parser.has_option("--org")) self.assertFalse(parser.has_option("--environment")) self.assertFalse(parser.has_option("--force")) (opts, args) = parser.parse_args([]) migrate.set_defaults(opts, five_to_six) self.assertTrue(opts.five_to_six) self.assertEquals(None, opts.org) self.assertEquals(None, opts.environment) self.assertTrue(opts.force)
def main(allowed_options=None, description=None, usage=None): from os import getcwd from sys import argv from optparse import OptionParser from rabbitvcs.util.helper import get_common_directory parser = OptionParser(usage=usage, description=description) if allowed_options: for (option_args, option_kwargs) in allowed_options: parser.add_option(*option_args, **option_kwargs) (options, args) = parser.parse_args(argv) # Convert "." to current working directory paths = args[1:] for i in range(0, len(paths)): if paths[i] == ".": paths[i] = getcwd() if not paths: paths = [getcwd()] if parser.has_option("--base-dir") and not options.base_dir: options.base_dir = get_common_directory(paths) return (options, paths)
def main(): """ Parser Options """ parser = OptionParser (option_class=eng_option) MimoMPIF.add_parser_options (parser) if not parser.has_option("--phy-addr"): parser.add_option("", "--phy-addr", type="string", default="0.0.0.0", \ help="set address for PHY [default=%default]") (options, args) = parser.parse_args () if len(args)!=0: parser.print_help() sys.exit(1) global RATE_LIMIT if (options.nchannels == 4): RATE_LIMIT = 32 elif (options.nchannels == 2): RATE_LIMIT = 16 elif (options.nchannels == 1): RATE_LIMIT = 8 mac = mimo.mac(options.phy_addr, options.mac_port) mac.start() #f = FuncThread(send_data, "tx-data", mac) f = FuncThread(send_80211data, "tx-data", mac) f.setDaemon(1) g = FuncThread(recv_data, "rx-data", mac) g.setDaemon(1) h = FuncThread(recv_ctrl, "rx-ctrl", mac) h.setDaemon(1) for x in [f,g,h]: x.start() #for x in [g,h]: x.start() raw_input("Press Enter to quit:\n") mac.shutdown() p = persist() # start a persitent thread
def testDumpDefault(self): parser = OptionParser() sampleFunction.addConfigToParser(parser) self.assertTrue(parser.has_option('-d')) self.assertTrue(parser.has_option('--dump')) dumpfile = open(self.dumpFile, 'w') sys.stdout = dumpfile self.assertRaises(SystemExit, parser.parse_args, args=['-d']) sys.stdout = self.stdout dumpfile.close() self.assertEquals(sampleFunction.loadConfig(self.dumpFile), sampleFunction.defaults)
def testPopulateParser(self): parser = OptionParser() sampleFunction2.populateParser(parser) self.assertTrue(parser.has_option('-d')) self.assertTrue(parser.has_option('--dump')) dumpfile = open(self.dumpFile, 'w') sys.stdout = dumpfile self.assertRaises(SystemExit, parser.parse_args, args=['-d']) sys.stdout = self.stdout dumpfile.close() self.assertEquals(sampleFunction.loadConfig(self.dumpFile), sampleFunction.defaults) argstring = '-x 3 -y 2.66 --func eval2 --cat mytest.cat --verbose False' self.assertTrue(parser.has_option('--cat')) self.assertTrue(parser.has_option('-v')) self.assertTrue(parser.has_option('--verbpse'))
def get_options(): parser = OptionParser(option_class=eng_option, conflict_handler="resolve") parser.add_option("-n", "--nbr-values", type="int", default=5, help="number of values [default=%default]") parser.add_option( "-a", "--alpha", type="float", default=0.1, help="set alpha or P1/P: relation between P1 and P2 [default=%default]" ) parser.add_option( "-s", "--snr", type="float", default=10, help="SNR or P/sigma^2 (dB) of a generated carrierr [default=%default]" ) # parser.add_option("-f", "--to-file", default=None, # help="File to save results of simulations") # parser.add_option("","--from-file", default=None, # help="input file of samples to demod") # if not parser.has_option("--log"): parser.add_option( "", "--log", action="store_true", default=False, help="Log all parts of flow graph to files (CAUTION: lots of data)" ) (options, args) = parser.parse_args() if len(args) != 0: parser.print_help() sys.exit(1) return (options, args)
def main(): parser = OptionParser(usage='usage: %prog [options] ...', version='%%prog %s' % VERSION) if os.name == 'posix': parser.add_option('-d', '--daemonize', action='store_true', dest='daemonize', help='run in the background as a daemon') parser.add_option('--pidfile', action='store', dest='pidfile', help='when daemonizing, file to which to write pid') options, args = parser.parse_args() if options.daemonize and options.autoreload: parser.error('the --auto-reload option cannot be used with ' '--daemonize') if parser.has_option('pidfile') and options.pidfile: options.pidfile = os.path.abspath(options.pidfile) q = queue.Queue() opt = Options('default.conf') manager = PluginManager(opt, q) manager.run() try: if options.daemonize: daemonize(pidfile=options.pidfile, progname='opcua_plugin') except OSError as e: print("%s: %s" % (e.__class__.__name__, e), file=sys.stderr) sys.exit(1) except KeyboardInterrupt: pass
def main(): usage_str="usage: %prog [options] file list ..." parser = OptionParser(usage=usage_str) parser.add_option("-f", "--field_num", dest="field_num", default=1, help="specify the field number", metavar="FIELD_NUM") parser.add_option("-z", action="store_true", dest="zero", help="set 0 for undefined value") (options, args) = parser.parse_args() # 'field_num' is specified in the range from 0(key) to 1, 2, ...(values) field_num = 1 default_value = "" if (options.field_num): field_num = int(options.field_num) if (parser.has_option("zero")): default_value = 0 files = args result= {} num_files = len(files) for i in range(num_files): fp = open(files[i]) for line in fp: line = line.rstrip('\n') name_value_list = line.split('\t') name = name_value_list[0] if (len(name_value_list) > field_num): value = name_value_list[field_num] else: value = default_value if name[:2] == 'k.': continue if not result.has_key(name): result[name] = [ default_value for j in range(num_files) ] result[name][i] = value fp.close() for name in result.keys(): print "%s\t%s"%(name, '\t'.join(map(str, result[name])))
class CommandLineParser(): # Defines what --regular means REGULAR_CMD = ['sslv2', 'sslv3', 'tlsv1', 'tlsv1_1', 'tlsv1_2', 'reneg', 'resum', 'certinfo', 'http_get', 'hide_rejected_ciphers', 'compression', 'heartbleed'] SSLYZE_USAGE = 'usage: %prog [options] target1.com target2.com:443 etc...' # StartTLS options START_TLS_PROTS = ['smtp', 'xmpp', 'pop3', 'ftp', 'imap', 'ldap', 'rdp', 'postgres', 'auto'] START_TLS_USAGE = 'STARTTLS should be one of: ' + str(START_TLS_PROTS) + \ '. The \'auto\' option will cause SSLyze to deduce the protocol' + \ ' (ftp, imap, etc.) from the supplied port number, for each target servers.' # Default values DEFAULT_RETRY_ATTEMPTS = 4 DEFAULT_TIMEOUT = 5 def __init__(self, available_plugins, sslyze_version): """ Generates SSLyze's command line parser. """ self._parser = OptionParser(version=sslyze_version, usage=self.SSLYZE_USAGE) # Add generic command line options to the parser self._add_default_options() # Add plugin-specific options to the parser self._add_plugin_options(available_plugins) # Add the --regular command line parameter as a shortcut if possible regular_help = 'Regular HTTPS scan; shortcut for' for cmd in self.REGULAR_CMD: regular_help += ' --' + cmd if cmd == 'certinfo': # gah regular_help += '=basic' if not self._parser.has_option('--' + cmd): return self._parser.add_option('--regular', action="store_true", dest=None, help=regular_help) def parse_command_line(self): """ Parses the command line used to launch SSLyze. """ (args_command_list, args_target_list) = self._parser.parse_args() # Handle the --targets_in command line and fill args_target_list if args_command_list.targets_in: if args_target_list: raise CommandLineParsingError("Cannot use --targets_list and specify targets within the command line.") try: # Read targets from a file with open(args_command_list.targets_in) as f: for target in f.readlines(): if target.strip(): # Ignore empty lines if not target.startswith('#'): # Ignore comment lines args_target_list.append(target.strip()) except IOError: raise CommandLineParsingError("Can't read targets from input file '%s'." % args_command_list.targets_in) if not args_target_list: raise CommandLineParsingError('No targets to scan.') # Handle the --regular command line parameter as a shortcut if self._parser.has_option('--regular'): if getattr(args_command_list, 'regular'): setattr(args_command_list, 'regular', False) for cmd in self.REGULAR_CMD: if cmd=="certinfo": # Allow user to override certinfo when using --regular if getattr(args_command_list, 'certinfo') is None: setattr(args_command_list, 'certinfo', 'basic') # Special case else: setattr(args_command_list, cmd, True) # Create the shared_settings object from looking at the command line shared_settings = self._process_parsing_results(args_command_list) return args_command_list, args_target_list, shared_settings def _add_default_options(self): """ Adds default command line options to the parser. """ # Client certificate options clientcert_group = OptionGroup(self._parser, 'Client certificate support', '') clientcert_group.add_option( '--cert', help='Client certificate filename.', dest='cert') clientcert_group.add_option( '--certform', help= 'Client certificate format. DER or PEM (default).', dest='certform', default='PEM') clientcert_group.add_option( '--key', help= 'Client private key filename.', dest='key') clientcert_group.add_option( '--keyform', help= 'Client private key format. DER or PEM (default).', dest='keyform', default='PEM') clientcert_group.add_option( '--pass', help= 'Client private key passphrase.', dest='keypass', default='') self._parser.add_option_group(clientcert_group) # XML output self._parser.add_option( '--xml_out', help='Writes the scan results as an XML document to the file XML_FILE.', dest='xml_file', default=None) # Read targets from input file self._parser.add_option( '--targets_in', help='Reads the list of targets to scan from the file TARGETS_IN. It should contain one host:port per line.', dest='targets_in', default=None) # Timeout self._parser.add_option( '--timeout', help= ( 'Sets the timeout value in seconds used for every socket ' 'connection made to the target server(s). Default is ' + str(self.DEFAULT_TIMEOUT) + 's.'), type='int', dest='timeout', default=self.DEFAULT_TIMEOUT) # Control connection retry attempts self._parser.add_option( '--nb_retries', help= ( 'Sets the number retry attempts for all network connections ' 'initiated throughout the scan. Increase this value if you are ' 'getting a lot of timeout/connection errors when scanning a ' 'specific server. Decrease this value to increase the speed ' 'of the scans; results may however return connection errors. ' 'Default is ' + str(self.DEFAULT_RETRY_ATTEMPTS) + ' connection attempts.'), type='int', dest='nb_retries', default=self.DEFAULT_RETRY_ATTEMPTS) # HTTP CONNECT Proxy self._parser.add_option( '--https_tunnel', help= ( 'Tunnels all traffic to the target server(s) through an HTTP ' 'CONNECT proxy. HTTP_TUNNEL should be the proxy\'s URL: ' '\'http://*****:*****@HOST:PORT/\'. For proxies requiring ' 'authentication, only Basic Authentication is supported.'), dest='https_tunnel', default=None) # STARTTLS self._parser.add_option( '--starttls', help= ( 'Performs StartTLS handshakes when connecting to the target ' 'server(s). ' + self.START_TLS_USAGE), dest='starttls', default=None) self._parser.add_option( '--xmpp_to', help= ( 'Optional setting for STARTTLS XMPP. ' ' XMPP_TO should be the hostname to be put in the \'to\' attribute ' 'of the XMPP stream. Default is the server\'s hostname.'), dest='xmpp_to', default=None) # Server Name Indication self._parser.add_option( '--sni', help= ( 'Use Server Name Indication to specify the hostname to connect to.' ' Will only affect TLS 1.0+ connections.'), dest='sni', default=None) def _add_plugin_options(self, available_plugins): """ Recovers the list of command line options implemented by the available plugins and adds them to the command line parser. """ for plugin_class in available_plugins: plugin_desc = plugin_class.get_interface() # Add the current plugin's commands to the parser group = OptionGroup(self._parser, plugin_desc.title, plugin_desc.description) for cmd in plugin_desc.get_commands(): group.add_option(cmd) # Add the current plugin's options to the parser for option in plugin_desc.get_options(): group.add_option(option) self._parser.add_option_group(group) def _process_parsing_results(self, args_command_list): """ Performs various sanity checks on the command line that was used to launch SSLyze. Returns the shared_settings object to be fed to plugins. """ shared_settings = {} # Sanity checks on the client cert options if bool(args_command_list.cert) ^ bool(args_command_list.key): raise CommandLineParsingError('No private key or certificate file were given. See --cert and --key.') # Private key and cert formats if args_command_list.certform == 'DER': args_command_list.certform = SSL_FILETYPE_ASN1 elif args_command_list.certform == 'PEM': args_command_list.certform = SSL_FILETYPE_PEM else: raise CommandLineParsingError('--certform should be DER or PEM.') if args_command_list.keyform == 'DER': args_command_list.keyform = SSL_FILETYPE_ASN1 elif args_command_list.keyform == 'PEM': args_command_list.keyform = SSL_FILETYPE_PEM else: raise CommandLineParsingError('--keyform should be DER or PEM.') # Let's try to open the cert and key files if args_command_list.cert: try: open(args_command_list.cert,"r") except: raise CommandLineParsingError('Could not open the client certificate file "' + str(args_command_list.cert) + '".') if args_command_list.key: try: open(args_command_list.key,"r") except: raise CommandLineParsingError('Could not open the client private key file "' + str(args_command_list.key) + '"') # Try to load the cert and key in OpenSSL try: sslClient = SslClient() sslClient.use_private_key(args_command_list.cert, args_command_list.certform, args_command_list.key, args_command_list.keyform, args_command_list.keypass) except _nassl.OpenSSLError as e: if 'bad decrypt' in str(e.args): raise CommandLineParsingError('Could not decrypt the private key. Wrong passphrase ?') raise CommandLineParsingError('Could not load the certificate or the private key. Passphrase needed ?') # HTTP CONNECT proxy shared_settings['https_tunnel_host'] = None if args_command_list.https_tunnel: # Parse the proxy URL parsedUrl = urlparse(args_command_list.https_tunnel) if not parsedUrl.netloc: raise CommandLineParsingError( 'Invalid Proxy URL for --https_tunnel, discarding all tasks.') if parsedUrl.scheme in 'http': defaultPort = 80 elif parsedUrl.scheme in 'https': defaultPort = 443 else: raise CommandLineParsingError( 'Invalid URL scheme for --https_tunnel, discarding all tasks.') if not parsedUrl.hostname: raise CommandLineParsingError( 'Invalid Proxy URL for --https_tunnel, discarding all tasks.') try : shared_settings['https_tunnel_port'] = parsedUrl.port if parsedUrl.port else defaultPort except ValueError: # The supplied port was not a number raise CommandLineParsingError( 'Invalid Proxy URL for --https_tunnel, discarding all tasks.') shared_settings['https_tunnel_host'] = parsedUrl.hostname shared_settings['https_tunnel_user'] = parsedUrl.username shared_settings['https_tunnel_password'] = parsedUrl.password # STARTTLS if args_command_list.starttls: if args_command_list.starttls not in self.START_TLS_PROTS: raise CommandLineParsingError(self.START_TLS_USAGE) if args_command_list.starttls and args_command_list.https_tunnel: raise CommandLineParsingError( 'Cannot have --https_tunnel and --starttls at the same time.') # Number of connection retries if args_command_list.nb_retries < 1: raise CommandLineParsingError( 'Cannot have a number smaller than 1 for --nb_retries.') # All good, let's save the data for key, value in args_command_list.__dict__.iteritems(): shared_settings[key] = value return shared_settings
class CommandLineParser(object): # Defines what --regular means REGULAR_CMD = [ 'sslv2', 'sslv3', 'tlsv1', 'tlsv1_1', 'tlsv1_2', 'tlsv1_3', 'reneg', 'resum', 'certinfo', 'http_get', 'hide_rejected_ciphers', 'compression', 'heartbleed', 'openssl_ccs', 'fallback', 'robot' ] SSLYZE_USAGE = 'usage: %prog [options] target1.com target2.com:443 target3.com:443{ip} etc...' # StartTLS options START_TLS_PROTOCOLS = [ 'smtp', 'xmpp', 'xmpp_server', 'pop3', 'ftp', 'imap', 'ldap', 'rdp', 'postgres', 'auto' ] START_TLS_USAGE = 'StartTLS should be one of: {}. The \'auto\' option will cause SSLyze to deduce the protocol ' \ '(ftp, imap, etc.) from the supplied port number, ' \ 'for each target servers.'.format(' , '.join(START_TLS_PROTOCOLS)) # Mapping of StartTls protocols and ports; useful for starttls=auto STARTTLS_PROTOCOL_DICT = { 'smtp': TlsWrappedProtocolEnum.STARTTLS_SMTP, 587: TlsWrappedProtocolEnum.STARTTLS_SMTP, 25: TlsWrappedProtocolEnum.STARTTLS_SMTP, 'xmpp': TlsWrappedProtocolEnum.STARTTLS_XMPP, 5222: TlsWrappedProtocolEnum.STARTTLS_XMPP, 'xmpp_server': TlsWrappedProtocolEnum.STARTTLS_XMPP_SERVER, 5269: TlsWrappedProtocolEnum.STARTTLS_XMPP_SERVER, 'pop3': TlsWrappedProtocolEnum.STARTTLS_POP3, 109: TlsWrappedProtocolEnum.STARTTLS_POP3, 110: TlsWrappedProtocolEnum.STARTTLS_POP3, 'imap': TlsWrappedProtocolEnum.STARTTLS_IMAP, 143: TlsWrappedProtocolEnum.STARTTLS_IMAP, 220: TlsWrappedProtocolEnum.STARTTLS_IMAP, 'ftp': TlsWrappedProtocolEnum.STARTTLS_FTP, 21: TlsWrappedProtocolEnum.STARTTLS_FTP, 'ldap': TlsWrappedProtocolEnum.STARTTLS_LDAP, 3268: TlsWrappedProtocolEnum.STARTTLS_LDAP, 389: TlsWrappedProtocolEnum.STARTTLS_LDAP, 'rdp': TlsWrappedProtocolEnum.STARTTLS_RDP, 3389: TlsWrappedProtocolEnum.STARTTLS_RDP, 'postgres': TlsWrappedProtocolEnum.STARTTLS_POSTGRES, 5432: TlsWrappedProtocolEnum.STARTTLS_POSTGRES } def __init__(self, available_plugins, sslyze_version): # type: (Set[Type[Plugin]], Text) -> None """Generate SSLyze's command line parser. """ self._parser = OptionParser(version=sslyze_version, usage=self.SSLYZE_USAGE) # Add generic command line options to the parser self._add_default_options() # Add plugin-specific options to the parser self._add_plugin_options(available_plugins) # Add the --regular command line parameter as a shortcut if possible regular_help = 'Regular HTTPS scan; shortcut for --{}'.format( ' --'.join(self.REGULAR_CMD)) self._parser.add_option('--regular', action='store_true', dest=None, help=regular_help) def parse_command_line(self): # type: () -> Tuple[List[ServerConnectivityTester], List[ServerStringParsingError], Any] """Parses the command line used to launch SSLyze. """ (args_command_list, args_target_list) = self._parser.parse_args() if args_command_list.update_trust_stores: # Just update the trust stores and do nothing TrustStoresRepository.update_default() raise TrustStoresUpdateCompleted() # Handle the --targets_in command line and fill args_target_list if args_command_list.targets_in: if args_target_list: raise CommandLineParsingError( 'Cannot use --targets_list and specify targets within the command line.' ) try: # Read targets from a file with open(args_command_list.targets_in) as f: for target in f.readlines(): if target.strip(): # Ignore empty lines if not target.startswith( '#'): # Ignore comment lines args_target_list.append(target.strip()) except IOError: raise CommandLineParsingError( 'Can\'t read targets from input file \'{}.'.format( args_command_list.targets_in)) if not args_target_list: raise CommandLineParsingError('No targets to scan.') # Handle the --regular command line parameter as a shortcut if self._parser.has_option('--regular'): if getattr(args_command_list, 'regular'): setattr(args_command_list, 'regular', False) for cmd in self.REGULAR_CMD: setattr(args_command_list, cmd, True) # Sanity checks on the command line options # Prevent --quiet and --xml_out - if args_command_list.xml_file and args_command_list.xml_file == '-' and args_command_list.quiet: raise CommandLineParsingError( 'Cannot use --quiet with --xml_out -.') # Prevent --quiet and --json_out - if args_command_list.json_file and args_command_list.json_file == '-' and args_command_list.quiet: raise CommandLineParsingError( 'Cannot use --quiet with --json_out -.') # Prevent --xml_out - and --json_out - if args_command_list.json_file and args_command_list.json_file == '-' \ and args_command_list.xml_file and args_command_list.xml_file == '-': raise CommandLineParsingError( 'Cannot use --xml_out - with --json_out -.') # Sanity checks on the client cert options client_auth_creds = None if bool(args_command_list.cert) ^ bool(args_command_list.key): raise CommandLineParsingError( 'No private key or certificate file were given. See --cert and --key.' ) elif args_command_list.cert: # Private key formats if args_command_list.keyform == 'DER': key_type = OpenSslFileTypeEnum.ASN1 elif args_command_list.keyform == 'PEM': key_type = OpenSslFileTypeEnum.PEM else: raise CommandLineParsingError( '--keyform should be DER or PEM.') # Let's try to open the cert and key files try: client_auth_creds = ClientAuthenticationCredentials( args_command_list.cert, args_command_list.key, key_type, args_command_list.keypass) except ValueError as e: raise CommandLineParsingError( 'Invalid client authentication settings: {}.'.format( e.args[0])) # HTTP CONNECT proxy http_tunneling_settings = None if args_command_list.https_tunnel: try: http_tunneling_settings = HttpConnectTunnelingSettings.from_url( args_command_list.https_tunnel) except ValueError as e: raise CommandLineParsingError( 'Invalid proxy URL for --https_tunnel: {}.'.format( e.args[0])) # STARTTLS tls_wrapped_protocol = TlsWrappedProtocolEnum.PLAIN_TLS if args_command_list.starttls: if args_command_list.starttls not in self.START_TLS_PROTOCOLS: raise CommandLineParsingError(self.START_TLS_USAGE) else: # StartTLS was specified if args_command_list.starttls in self.STARTTLS_PROTOCOL_DICT.keys( ): # Protocol was given in the command line tls_wrapped_protocol = self.STARTTLS_PROTOCOL_DICT[ args_command_list.starttls] # Create the server connectivity tester for each specified servers # A limitation when using the command line is that only one client_auth_credentials and http_tunneling_settings # can be specified, for all the servers to scan good_server_list = [] bad_server_list = [] for server_string in args_target_list: try: hostname, ip_address, port = CommandLineServerStringParser.parse_server_string( server_string) except ServerStringParsingError as e: # Will happen if the server string is malformed bad_server_list.append(e) continue try: # TODO(AD): Unicode hostnames may fail on Python2 # hostname = hostname.decode('utf-8') server_info = ServerConnectivityTester( hostname=hostname, port=port, ip_address=ip_address, tls_wrapped_protocol=tls_wrapped_protocol, tls_server_name_indication=args_command_list.sni, xmpp_to_hostname=args_command_list.xmpp_to, client_auth_credentials=client_auth_creds, http_tunneling_settings=http_tunneling_settings) good_server_list.append(server_info) except ValueError as e: # Will happen for example if xmpp_to is specified for a non-XMPP connection raise CommandLineParsingError(e.args[0]) # Command line hacks # Handle --starttls=auto now that we parsed the server strings if args_command_list.starttls == 'auto': for server_info in good_server_list: # We use the port number to deduce the protocol if server_info.port in self.STARTTLS_PROTOCOL_DICT.keys(): server_info.tls_wrapped_protocol = self.STARTTLS_PROTOCOL_DICT[ server_info.port] # Handle --http_get now that we parsed the server strings # Doing it here is hacky as the option is defined within PluginOpenSSLCipherSuites if args_command_list.http_get: for server_info in good_server_list: if server_info.port == 443: server_info.tls_wrapped_protocol = TlsWrappedProtocolEnum.HTTPS return good_server_list, bad_server_list, args_command_list def _add_default_options(self): # type: () -> None """Add default command line options to the parser. """ # Updating the trust stores update_stores_group = OptionGroup(self._parser, 'Trust stores options', '') update_stores_group.add_option( '--update_trust_stores', help= 'Update the default trust stores used by SSLyze. The latest stores will be downloaded from ' 'https://github.com/nabla-c0d3/trust_stores_observatory. This option is meant to be used separately, ' 'and will silence any other command line option supplied to SSLyze.', dest='update_trust_stores', action='store_true', ) self._parser.add_option_group(update_stores_group) # Client certificate options clientcert_group = OptionGroup(self._parser, 'Client certificate options', '') clientcert_group.add_option( '--cert', help= 'Client certificate chain filename. The certificates must be in PEM format and must be sorted ' 'starting with the subject\'s client certificate, followed by intermediate CA certificates if ' 'applicable.', dest='cert') clientcert_group.add_option('--key', help='Client private key filename.', dest='key') clientcert_group.add_option( '--keyform', help='Client private key format. DER or PEM (default).', dest='keyform', default='PEM') clientcert_group.add_option('--pass', help='Client private key passphrase.', dest='keypass', default='') self._parser.add_option_group(clientcert_group) # Input / output output_group = OptionGroup(self._parser, 'Input and output options', '') # XML output output_group.add_option( '--xml_out', help= 'Write the scan results as an XML document to the file XML_FILE. If XML_FILE is set to "-", the XML ' 'output will instead be printed to stdout.', dest='xml_file', default=None) # JSON output output_group.add_option( '--json_out', help= 'Write the scan results as a JSON document to the file JSON_FILE. If JSON_FILE is set to "-", the ' 'JSON output will instead be printed to stdout. The resulting JSON file is a serialized version of ' 'the ScanResult objects described in SSLyze\'s Python API: the nodes and attributes will be the same. ' 'See https://nabla-c0d3.github.io/sslyze/documentation/available-scan-commands.html for more details.', dest='json_file', default=None) # Read targets from input file output_group.add_option( '--targets_in', help= 'Read the list of targets to scan from the file TARGETS_IN. It should contain one host:port per ' 'line.', dest='targets_in', default=None) # No text output output_group.add_option( '--quiet', action='store_true', dest='quiet', help= 'Do not output anything to stdout; useful when using --xml_out or --json_out.' ) self._parser.add_option_group(output_group) # Connectivity option group connect_group = OptionGroup(self._parser, 'Connectivity options', '') # Connection speed connect_group.add_option( '--slow_connection', help= 'Greatly reduce the number of concurrent connections initiated by SSLyze. This will make the scans ' 'slower but more reliable if the connection between your host and the server is slow, or if the ' 'server cannot handle many concurrent connections. Enable this option if you are getting a lot of ' 'timeouts or errors.', action='store_true', dest='slow_connection', ) # HTTP CONNECT Proxy connect_group.add_option( '--https_tunnel', help= 'Tunnel all traffic to the target server(s) through an HTTP CONNECT proxy. HTTP_TUNNEL should be the ' 'proxy\'s URL: \'http://*****:*****@HOST:PORT/\'. For proxies requiring authentication, only Basic ' 'Authentication is supported.', dest='https_tunnel', default=None) # STARTTLS connect_group.add_option( '--starttls', help= 'Perform a StartTLS handshake when connecting to the target server(s). ' '{}'.format(self.START_TLS_USAGE), dest='starttls', default=None) connect_group.add_option( '--xmpp_to', help= 'Optional setting for STARTTLS XMPP. XMPP_TO should be the hostname to be put in the \'to\' ' 'attribute of the XMPP stream. Default is the server\'s hostname.', dest='xmpp_to', default=None) # Server Name Indication connect_group.add_option( '--sni', help= 'Use Server Name Indication to specify the hostname to connect to. Will only affect TLS 1.0+ ' 'connections.', dest='sni', default=None) self._parser.add_option_group(connect_group) def _add_plugin_options(self, available_plugins): # type: (Set[Type[Plugin]]) -> None """Recovers the list of command line options implemented by the available plugins and adds them to the command line parser. """ for plugin_class in available_plugins: # Add the current plugin's commands to the parser group = OptionGroup(self._parser, plugin_class.get_title(), plugin_class.get_description()) for option in plugin_class.get_cli_option_group(): group.add_option(option) self._parser.add_option_group(group)
class CommandLineParser: # Defines what --regular means REGULAR_CMD = [ "sslv2", "sslv3", "tlsv1", "tlsv1_1", "tlsv1_2", "reneg", "resum", "certinfo", "http_get", "hide_rejected_ciphers", "compression", ] SSLYZE_USAGE = "usage: %prog [options] target1.com target2.com:443 etc..." # StartTLS options START_TLS_PROTS = ["smtp", "xmpp", "pop3", "ftp", "imap", "ldap", "rdp", "auto"] START_TLS_USAGE = ( "STARTTLS should be one of: " + str(START_TLS_PROTS) + ". The 'auto' option will cause SSLyze to deduce the protocol" + " (ftp, imap, etc.) from the supplied port number, for each target servers." ) # Default values DEFAULT_RETRY_ATTEMPTS = 5 DEFAULT_TIMEOUT = 5 def __init__(self, available_plugins, sslyze_version): """ Generates SSLyze's command line parser. """ self._parser = OptionParser(version=sslyze_version, usage=self.SSLYZE_USAGE) # Add generic command line options to the parser self._add_default_options() # Add plugin-specific options to the parser self._add_plugin_options(available_plugins) # Add the --regular command line parameter as a shortcut if possible regular_help = "Regular HTTPS scan; shortcut for" for cmd in self.REGULAR_CMD: regular_help += " --" + cmd if cmd == "certinfo": # gah regular_help += "=basic" if self._parser.has_option("--" + cmd) == False: return self._parser.add_option("--regular", action="store_true", dest=None, help=regular_help) def parse_command_line(self): """ Parses the command line used to launch SSLyze. """ (args_command_list, args_target_list) = self._parser.parse_args() # Handle the --targets_in command line and fill args_target_list if args_command_list.targets_in: if args_target_list: raise CommandLineParsingError("Cannot use --targets_list and specify targets within the command line.") try: # Read targets from a file with open(args_command_list.targets_in) as f: for target in f.readlines(): if target.strip(): # Ignore empty lines if not target.startswith("#"): # Ignore comment lines args_target_list.append(target.strip()) except IOError: raise CommandLineParsingError("Can't read targets from input file '%s'." % args_command_list.targets_in) if args_target_list == []: raise CommandLineParsingError("No targets to scan.") # Handle the --regular command line parameter as a shortcut if self._parser.has_option("--regular"): if getattr(args_command_list, "regular"): setattr(args_command_list, "regular", False) for cmd in self.REGULAR_CMD: setattr(args_command_list, cmd, True) setattr(args_command_list, "certinfo", "basic") # Special case # Create the shared_settings object from looking at the command line shared_settings = self._process_parsing_results(args_command_list) return (args_command_list, args_target_list, shared_settings) def _add_default_options(self): """ Adds default command line options to the parser. """ # Client certificate options clientcert_group = OptionGroup(self._parser, "Client certificate support", "") clientcert_group.add_option("--cert", help="Client certificate filename.", dest="cert") clientcert_group.add_option( "--certform", help="Client certificate format. DER or PEM (default).", dest="certform", default="PEM" ) clientcert_group.add_option("--key", help="Client private key filename.", dest="key") clientcert_group.add_option( "--keyform", help="Client private key format. DER or PEM (default).", dest="keyform", default="PEM" ) clientcert_group.add_option("--pass", help="Client private key passphrase.", dest="keypass", default="") self._parser.add_option_group(clientcert_group) # XML output self._parser.add_option( "--xml_out", help=("Writes the scan results as an XML document to the file XML_FILE."), dest="xml_file", default=None, ) # Read targets from input file self._parser.add_option( "--targets_in", help=( "Reads the list of targets to scan from the file TARGETS_IN. It should contain one host:port per line." ), dest="targets_in", default=None, ) # Timeout self._parser.add_option( "--timeout", help=( "Sets the timeout value in seconds used for every socket " "connection made to the target server(s). Default is " + str(self.DEFAULT_TIMEOUT) + "s." ), type="int", dest="timeout", default=self.DEFAULT_TIMEOUT, ) # Control connection retry attempts self._parser.add_option( "--nb_retries", help=( "Sets the number retry attempts for all network connections " "initiated throughout the scan. Increase this value if you are " "getting a lot of timeout/connection errors when scanning a " "specific server. Decrease this value to increase the speed " "of the scans; results may however return connection errors. " "Default is " + str(self.DEFAULT_RETRY_ATTEMPTS) + " connection attempts." ), type="int", dest="nb_retries", default=self.DEFAULT_RETRY_ATTEMPTS, ) # HTTP CONNECT Proxy self._parser.add_option( "--https_tunnel", help=( "Tunnels all traffic to the target server(s) through an HTTP " "CONNECT proxy. HTTP_TUNNEL should be 'host:port'." ), dest="https_tunnel", default=None, ) # STARTTLS self._parser.add_option( "--starttls", help=("Performs StartTLS handshakes when connecting to the target " "server(s). " + self.START_TLS_USAGE), dest="starttls", default=None, ) self._parser.add_option( "--xmpp_to", help=( "Optional setting for STARTTLS XMPP. " " XMPP_TO should be the hostname to be put in the 'to' attribute " "of the XMPP stream. Default is the server's hostname." ), dest="xmpp_to", default=None, ) # Server Name Indication self._parser.add_option( "--sni", help=( "Use Server Name Indication to specify the hostname to connect to." " Will only affect TLS 1.0+ connections." ), dest="sni", default=None, ) def _add_plugin_options(self, available_plugins): """ Recovers the list of command line options implemented by the available plugins and adds them to the command line parser. """ for plugin_class in available_plugins: plugin_desc = plugin_class.get_interface() # Add the current plugin's commands to the parser group = OptionGroup(self._parser, plugin_desc.title, plugin_desc.description) for cmd in plugin_desc.get_commands(): group.add_option(cmd) # Add the current plugin's options to the parser for option in plugin_desc.get_options(): group.add_option(option) self._parser.add_option_group(group) def _process_parsing_results(self, args_command_list): """ Performs various sanity checks on the command line that was used to launch SSLyze. Returns the shared_settings object to be fed to plugins. """ shared_settings = {} # Sanity checks on the client cert options if bool(args_command_list.cert) ^ bool(args_command_list.key): raise CommandLineParsingError("No private key or certificate file were given. See --cert and --key.") # Private key and cert formats if args_command_list.certform is "DER": args_command_list.certform = SSL_FILETYPE_ASN1 elif args_command_list.certform is "PEM": args_command_list.certform = SSL_FILETYPE_PEM else: raise CommandLineParsingError("--certform should be DER or PEM.") if args_command_list.keyform is "DER": args_command_list.keyform = SSL_FILETYPE_ASN1 elif args_command_list.keyform is "PEM": args_command_list.keyform = SSL_FILETYPE_PEM else: raise CommandLineParsingError("--keyform should be DER or PEM.") # Let's try to open the cert and key files if args_command_list.cert: try: open(args_command_list.cert, "r") except: raise CommandLineParsingError( 'Could not open the client certificate file "' + str(args_command_list.cert) + '".' ) if args_command_list.key: try: open(args_command_list.key, "r") except: raise CommandLineParsingError( 'Could not open the client private key file "' + str(args_command_list.key) + '"' ) # Try to load the cert and key in OpenSSL try: sslClient = SslClient() sslClient.use_private_key( args_command_list.cert, args_command_list.certform, args_command_list.key, args_command_list.keyform, args_command_list.keypass, ) except _nassl.OpenSSLError as e: if "bad decrypt" in str(e.args): raise CommandLineParsingError("Could not decrypt the private key. Wrong passphrase ?") raise CommandLineParsingError("Could not load the certificate or the private key. Passphrase needed ?") # HTTP CONNECT proxy if args_command_list.https_tunnel: if "2.7." not in platform.python_version(): # Python 2.7 only raise CommandLineParsingError( "--https_tunnel requires Python 2.7.X. " "Current version is " + platform.python_version() + "." ) try: # Need to parse the proxy host:port string now (host, port) = TargetStringParser.parse_target_str(args_command_list.https_tunnel, 443) shared_settings["https_tunnel_host"] = host shared_settings["https_tunnel_port"] = port except InvalidTargetError: raise CommandLineParsingError("Not a valid host/port for --https_tunnel" ", discarding all tasks.") else: shared_settings["https_tunnel_host"] = None shared_settings["https_tunnel_port"] = None # STARTTLS if args_command_list.starttls: if args_command_list.starttls not in self.START_TLS_PROTS: raise CommandLineParsingError(self.START_TLS_USAGE) if args_command_list.starttls and args_command_list.https_tunnel: raise CommandLineParsingError("Cannot have --https_tunnel and --starttls at the same time.") # Number of connection retries if args_command_list.nb_retries < 1: raise CommandLineParsingError("Cannot have a number smaller than 1 for --nb_retries.") # All good, let's save the data for key, value in args_command_list.__dict__.iteritems(): shared_settings[key] = value return shared_settings
class CommandLineParser(): # Defines what --regular means REGULAR_CMD = [ 'sslv2', 'sslv3', 'tlsv1', 'reneg', 'resum', 'certinfo', 'http_get', 'hide_rejected_ciphers', 'compression', 'tlsv1_1', 'tlsv1_2' ] SSLYZE_USAGE = 'usage: %prog [options] target1.com target2.com:443 etc...' def __init__(self, available_plugins, sslyze_version, timeout): """ Generates SSLyze's command line parser. """ self._parser = OptionParser(version=sslyze_version, usage=self.SSLYZE_USAGE) # Add generic command line options to the parser self._add_default_options(timeout) # Add plugin-specific options to the parser self._add_plugin_options(available_plugins) # Add the --regular command line parameter as a shortcut if possible regular_help = 'Regular HTTPS scan; shortcut for' for cmd in self.REGULAR_CMD: regular_help += ' --' + cmd if (self._parser.has_option('--' + cmd) == False): return self._parser.add_option('--regular', action="store_true", dest=None, help=regular_help) def parse_command_line(self): """ Parses the command line used to launch SSLyze. """ (args_command_list, args_target_list) = self._parser.parse_args() # Handle the --targets_in command line and fill args_target_list if args_command_list.targets_in: if args_target_list: raise CommandLineParsingError( "Cannot use --targets_list and specify targets within the command line." ) try: # Read targets from a file with open(args_command_list.targets_in) as f: for target in f.readlines(): if target.strip(): # Ignore empty lines if not target.startswith( '#'): # Ignore comment lines args_target_list.append(target.strip()) except IOError: raise CommandLineParsingError( "Can't read targets from input file '%s'." % args_command_list.targets_in) if args_target_list == []: raise CommandLineParsingError('No targets to scan.') # Handle the --regular command line parameter as a shortcut if self._parser.has_option('--regular'): if getattr(args_command_list, 'regular'): setattr(args_command_list, 'regular', False) for cmd in self.REGULAR_CMD: setattr(args_command_list, cmd, True) setattr(args_command_list, 'certinfo', 'basic') # Special case # Create the shared_settings object from looking at the command line shared_settings = self._process_parsing_results(args_command_list) return (args_command_list, args_target_list, shared_settings) def _add_default_options(self, timeout): """ Adds default command line options to the parser. """ # Client certificate options clientcert_group = OptionGroup(self._parser, 'Client certificate support', '') clientcert_group.add_option('--cert', help='Client certificate filename.', dest='cert') clientcert_group.add_option( '--certform', help='Client certificate format. DER or PEM (default).', dest='certform', default='PEM') clientcert_group.add_option('--key', help='Client private key filename.', dest='key') clientcert_group.add_option( '--keyform', help='Client private key format. DER or PEM (default).', dest='keyform', default='PEM') clientcert_group.add_option('--pass', help='Client private key passphrase.', dest='keypass') self._parser.add_option_group(clientcert_group) # XML output self._parser.add_option( '--xml_out', help= ('Writes the scan results as an XML document to the file XML_FILE.' ), dest='xml_file', default=None) # Read targets from input file self._parser.add_option( '--targets_in', help= ('Reads the list of targets to scan from the file TARGETS_IN. It should contain one host:port per line.' ), dest='targets_in', default=None) # Timeout self._parser.add_option( '--timeout', help=('Sets the timeout value in seconds used for every socket ' 'connection made to the target server(s). Default is 5s.'), type='int', dest='timeout', default=timeout) # HTTP CONNECT Proxy self._parser.add_option( '--https_tunnel', help= ('Sets an HTTP CONNECT proxy to tunnel SSL traffic to the target ' 'server(s). HTTP_TUNNEL should be \'host:port\'. ' 'Requires Python 2.7'), dest='https_tunnel', default=None) # STARTTLS self._parser.add_option( '--starttls', help= ('Identifies the target server(s) as a SMTP or an XMPP server(s) ' 'and scans the server(s) using STARTTLS. ' 'STARTTLS should be \'smtp\' or \'xmpp\'.'), dest='starttls', default=None) self._parser.add_option( '--xmpp_to', help= ('Optional setting for STARTTLS XMPP. ' ' XMPP_TO should be the hostname to be put in the \'to\' attribute ' 'of the XMPP stream. Default is the server\'s hostname.'), dest='xmpp_to', default=None) # Server Name Indication self._parser.add_option( '--sni', help= ('Use Server Name Indication to specify the hostname to connect to.' ' Will only affect TLS 1.0+ connections.'), dest='sni', default=None) def _add_plugin_options(self, available_plugins): """ Recovers the list of command line options implemented by the available plugins and adds them to the command line parser. """ for plugin_class in available_plugins: plugin_desc = plugin_class.get_interface() # Add the current plugin's commands to the parser group = OptionGroup(self._parser, plugin_desc.title,\ plugin_desc.description) for cmd in plugin_desc.get_commands(): group.add_option(cmd) # Add the current plugin's options to the parser for option in plugin_desc.get_options(): group.add_option(option) self._parser.add_option_group(group) def _process_parsing_results(self, args_command_list): """ Performs various sanity checks on the command line that was used to launch SSLyze. Returns the shared_settings object to be fed to plugins. """ shared_settings = {} # Sanity checks on the client cert options if bool(args_command_list.cert) ^ bool(args_command_list.key): raise CommandLineParsingError( 'No private key or certificate file were given. See --cert and --key.' ) # Let's try to open the cert and key files if args_command_list.cert: try: open(args_command_list.cert, "r") except: raise CommandLineParsingError( 'Could not open the client certificate file "' + str(args_command_list.cert) + '".') if args_command_list.key: try: open(args_command_list.key, "r") except: raise CommandLineParsingError( 'Could not open the client private key file "' + str(args_command_list.key) + '"') # Parse client cert options if args_command_list.certform not in ['DER', 'PEM']: raise CommandLineParsingError('--certform should be DER or PEM.') if args_command_list.keyform not in ['DER', 'PEM']: raise CommandLineParsingError('--keyform should be DER or PEM.') # HTTP CONNECT proxy if args_command_list.https_tunnel: if '2.7.' not in platform.python_version(): # Python 2.7 only raise CommandLineParsingError( '--https_tunnel requires Python 2.7.X. ' 'Current version is ' + platform.python_version() + '.') try: # Need to parse the proxy host:port string now proxy_test = SSLServerTester(args_command_list.https_tunnel) shared_settings['https_tunnel_host'] = proxy_test.get_target( )[0] shared_settings['https_tunnel_port'] = proxy_test.get_target( )[2] except InvalidTargetError: raise CommandLineParsingError( 'Not a valid host/port for --https_tunnel' ', discarding all tasks.') else: shared_settings['https_tunnel_host'] = None shared_settings['https_tunnel_port'] = None # STARTTLS if args_command_list.starttls not in [None, 'smtp', 'xmpp']: raise CommandLineParsingError( '--starttls should be \'smtp\' or \'xmpp\'.') if args_command_list.starttls and args_command_list.https_tunnel: raise CommandLineParsingError( 'Cannot have --https_tunnel and --starttls at the same time.') # All good, let's save the data for key, value in args_command_list.__dict__.iteritems(): shared_settings[key] = value return shared_settings
def parse_opts(tmpcmdline, silent=False): myaction=None myopts = {} myfiles=[] actions = frozenset([ "clean", "check-news", "config", "depclean", "help", "info", "list-sets", "metadata", "moo", "prune", "regen", "search", "sync", "unmerge", "version", ]) longopt_aliases = {"--cols":"--columns", "--skip-first":"--skipfirst"} y_or_n = ("y", "n") true_y_or_n = ("True", "y", "n") true_y = ("True", "y") argument_options = { "--ask": { "shortopt" : "-a", "help" : "prompt before performing any actions", "type" : "choice", "choices" : true_y_or_n }, "--autounmask": { "help" : "automatically unmask packages", "type" : "choice", "choices" : true_y_or_n }, "--autounmask-unrestricted-atoms": { "help" : "write autounmask changes with >= atoms if possible", "type" : "choice", "choices" : true_y_or_n }, "--autounmask-keep-masks": { "help" : "don't add package.unmask entries", "type" : "choice", "choices" : true_y_or_n }, "--autounmask-write": { "help" : "write changes made by --autounmask to disk", "type" : "choice", "choices" : true_y_or_n }, "--accept-properties": { "help":"temporarily override ACCEPT_PROPERTIES", "action":"store" }, "--backtrack": { "help" : "Specifies how many times to backtrack if dependency " + \ "calculation fails ", "action" : "store" }, "--buildpkg": { "shortopt" : "-b", "help" : "build binary packages", "type" : "choice", "choices" : true_y_or_n }, "--buildpkg-exclude": { "help" :"A space separated list of package atoms for which " + \ "no binary packages should be built. This option overrides all " + \ "possible ways to enable building of binary packages.", "action" : "append" }, "--config-root": { "help":"specify the location for portage configuration files", "action":"store" }, "--color": { "help":"enable or disable color output", "type":"choice", "choices":("y", "n") }, "--complete-graph": { "help" : "completely account for all known dependencies", "type" : "choice", "choices" : true_y_or_n }, "--complete-graph-if-new-use": { "help" : "trigger --complete-graph behavior if USE or IUSE will change for an installed package", "type" : "choice", "choices" : y_or_n }, "--complete-graph-if-new-ver": { "help" : "trigger --complete-graph behavior if an installed package version will change (upgrade or downgrade)", "type" : "choice", "choices" : y_or_n }, "--deep": { "shortopt" : "-D", "help" : "Specifies how deep to recurse into dependencies " + \ "of packages given as arguments. If no argument is given, " + \ "depth is unlimited. Default behavior is to skip " + \ "dependencies of installed packages.", "action" : "store" }, "--depclean-lib-check": { "help" : "check for consumers of libraries before removing them", "type" : "choice", "choices" : true_y_or_n }, "--deselect": { "help" : "remove atoms/sets from the world file", "type" : "choice", "choices" : true_y_or_n }, "--dynamic-deps": { "help": "substitute the dependencies of installed packages with the dependencies of unbuilt ebuilds", "type": "choice", "choices": y_or_n }, "--exclude": { "help" :"A space separated list of package names or slot atoms. " + \ "Emerge won't install any ebuild or binary package that " + \ "matches any of the given package atoms.", "action" : "append" }, "--fail-clean": { "help" : "clean temp files after build failure", "type" : "choice", "choices" : true_y_or_n }, "--ignore-built-slot-operator-deps": { "help": "Ignore the slot/sub-slot := operator parts of dependencies that have " "been recorded when packages where built. This option is intended " "only for debugging purposes, and it only affects built packages " "that specify slot/sub-slot := operator dependencies using the " "experimental \"4-slot-abi\" EAPI.", "type": "choice", "choices": y_or_n }, "--jobs": { "shortopt" : "-j", "help" : "Specifies the number of packages to build " + \ "simultaneously.", "action" : "store" }, "--keep-going": { "help" : "continue as much as possible after an error", "type" : "choice", "choices" : true_y_or_n }, "--load-average": { "help" :"Specifies that no new builds should be started " + \ "if there are other builds running and the load average " + \ "is at least LOAD (a floating-point number).", "action" : "store" }, "--misspell-suggestions": { "help" : "enable package name misspell suggestions", "type" : "choice", "choices" : ("y", "n") }, "--with-bdeps": { "help":"include unnecessary build time dependencies", "type":"choice", "choices":("y", "n") }, "--reinstall": { "help":"specify conditions to trigger package reinstallation", "type":"choice", "choices":["changed-use"] }, "--reinstall-atoms": { "help" :"A space separated list of package names or slot atoms. " + \ "Emerge will treat matching packages as if they are not " + \ "installed, and reinstall them if necessary. Implies --deep.", "action" : "append", }, "--binpkg-respect-use": { "help" : "discard binary packages if their use flags \ don't match the current configuration", "type" : "choice", "choices" : true_y_or_n }, "--getbinpkg": { "shortopt" : "-g", "help" : "fetch binary packages", "type" : "choice", "choices" : true_y_or_n }, "--getbinpkgonly": { "shortopt" : "-G", "help" : "fetch binary packages only", "type" : "choice", "choices" : true_y_or_n }, "--usepkg-exclude": { "help" :"A space separated list of package names or slot atoms. " + \ "Emerge will ignore matching binary packages. ", "action" : "append", }, "--rebuild-exclude": { "help" :"A space separated list of package names or slot atoms. " + \ "Emerge will not rebuild these packages due to the " + \ "--rebuild flag. ", "action" : "append", }, "--rebuild-ignore": { "help" :"A space separated list of package names or slot atoms. " + \ "Emerge will not rebuild packages that depend on matching " + \ "packages due to the --rebuild flag. ", "action" : "append", }, "--package-moves": { "help" : "perform package moves when necessary", "type" : "choice", "choices" : true_y_or_n }, "--quiet": { "shortopt" : "-q", "help" : "reduced or condensed output", "type" : "choice", "choices" : true_y_or_n }, "--quiet-build": { "help" : "redirect build output to logs", "type" : "choice", "choices" : true_y_or_n, }, "--rebuild-if-new-slot": { "help" : ("Automatically rebuild or reinstall packages when slot/sub-slot := " "operator dependencies can be satisfied by a newer slot, so that " "older packages slots will become eligible for removal by the " "--depclean action as soon as possible."), "type" : "choice", "choices" : true_y_or_n }, "--rebuild-if-new-rev": { "help" : "Rebuild packages when dependencies that are " + \ "used at both build-time and run-time are built, " + \ "if the dependency is not already installed with the " + \ "same version and revision.", "type" : "choice", "choices" : true_y_or_n }, "--rebuild-if-new-ver": { "help" : "Rebuild packages when dependencies that are " + \ "used at both build-time and run-time are built, " + \ "if the dependency is not already installed with the " + \ "same version. Revision numbers are ignored.", "type" : "choice", "choices" : true_y_or_n }, "--rebuild-if-unbuilt": { "help" : "Rebuild packages when dependencies that are " + \ "used at both build-time and run-time are built.", "type" : "choice", "choices" : true_y_or_n }, "--rebuilt-binaries": { "help" : "replace installed packages with binary " + \ "packages that have been rebuilt", "type" : "choice", "choices" : true_y_or_n }, "--rebuilt-binaries-timestamp": { "help" : "use only binaries that are newer than this " + \ "timestamp for --rebuilt-binaries", "action" : "store" }, "--root": { "help" : "specify the target root filesystem for merging packages", "action" : "store" }, "--root-deps": { "help" : "modify interpretation of depedencies", "type" : "choice", "choices" :("True", "rdeps") }, "--select": { "help" : "add specified packages to the world set " + \ "(inverse of --oneshot)", "type" : "choice", "choices" : true_y_or_n }, "--selective": { "help" : "identical to --noreplace", "type" : "choice", "choices" : true_y_or_n }, "--use-ebuild-visibility": { "help" : "use unbuilt ebuild metadata for visibility checks on built packages", "type" : "choice", "choices" : true_y_or_n }, "--useoldpkg-atoms": { "help" :"A space separated list of package names or slot atoms. " + \ "Emerge will prefer matching binary packages over newer unbuilt packages. ", "action" : "append", }, "--usepkg": { "shortopt" : "-k", "help" : "use binary packages", "type" : "choice", "choices" : true_y_or_n }, "--usepkgonly": { "shortopt" : "-K", "help" : "use only binary packages", "type" : "choice", "choices" : true_y_or_n }, } from optparse import OptionParser parser = OptionParser() if parser.has_option("--help"): parser.remove_option("--help") for action_opt in actions: parser.add_option("--" + action_opt, action="store_true", dest=action_opt.replace("-", "_"), default=False) for myopt in options: parser.add_option(myopt, action="store_true", dest=myopt.lstrip("--").replace("-", "_"), default=False) for shortopt, longopt in shortmapping.items(): parser.add_option("-" + shortopt, action="store_true", dest=longopt.lstrip("--").replace("-", "_"), default=False) for myalias, myopt in longopt_aliases.items(): parser.add_option(myalias, action="store_true", dest=myopt.lstrip("--").replace("-", "_"), default=False) for myopt, kwargs in argument_options.items(): shortopt = kwargs.pop("shortopt", None) args = [myopt] if shortopt is not None: args.append(shortopt) parser.add_option(dest=myopt.lstrip("--").replace("-", "_"), *args, **kwargs) tmpcmdline = insert_optional_args(tmpcmdline) myoptions, myargs = parser.parse_args(args=tmpcmdline) if myoptions.ask in true_y: myoptions.ask = True else: myoptions.ask = None if myoptions.autounmask in true_y: myoptions.autounmask = True if myoptions.autounmask_unrestricted_atoms in true_y: myoptions.autounmask_unrestricted_atoms = True if myoptions.autounmask_keep_masks in true_y: myoptions.autounmask_keep_masks = True if myoptions.autounmask_write in true_y: myoptions.autounmask_write = True if myoptions.buildpkg in true_y: myoptions.buildpkg = True if myoptions.buildpkg_exclude: bad_atoms = _find_bad_atoms(myoptions.buildpkg_exclude, less_strict=True) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --buildpkg-exclude parameter: '%s'\n" % \ (",".join(bad_atoms),)) if myoptions.changed_use is not False: myoptions.reinstall = "changed-use" myoptions.changed_use = False if myoptions.deselect in true_y: myoptions.deselect = True if myoptions.binpkg_respect_use is not None: if myoptions.binpkg_respect_use in true_y: myoptions.binpkg_respect_use = 'y' else: myoptions.binpkg_respect_use = 'n' if myoptions.complete_graph in true_y: myoptions.complete_graph = True else: myoptions.complete_graph = None if myoptions.depclean_lib_check in true_y: myoptions.depclean_lib_check = True if myoptions.exclude: bad_atoms = _find_bad_atoms(myoptions.exclude) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --exclude parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \ (",".join(bad_atoms),)) if myoptions.reinstall_atoms: bad_atoms = _find_bad_atoms(myoptions.reinstall_atoms) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --reinstall-atoms parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \ (",".join(bad_atoms),)) if myoptions.rebuild_exclude: bad_atoms = _find_bad_atoms(myoptions.rebuild_exclude) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --rebuild-exclude parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \ (",".join(bad_atoms),)) if myoptions.rebuild_ignore: bad_atoms = _find_bad_atoms(myoptions.rebuild_ignore) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --rebuild-ignore parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \ (",".join(bad_atoms),)) if myoptions.usepkg_exclude: bad_atoms = _find_bad_atoms(myoptions.usepkg_exclude) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --usepkg-exclude parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \ (",".join(bad_atoms),)) if myoptions.useoldpkg_atoms: bad_atoms = _find_bad_atoms(myoptions.useoldpkg_atoms) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --useoldpkg-atoms parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \ (",".join(bad_atoms),)) if myoptions.fail_clean in true_y: myoptions.fail_clean = True if myoptions.getbinpkg in true_y: myoptions.getbinpkg = True else: myoptions.getbinpkg = None if myoptions.getbinpkgonly in true_y: myoptions.getbinpkgonly = True else: myoptions.getbinpkgonly = None if myoptions.keep_going in true_y: myoptions.keep_going = True else: myoptions.keep_going = None if myoptions.package_moves in true_y: myoptions.package_moves = True if myoptions.quiet in true_y: myoptions.quiet = True else: myoptions.quiet = None if myoptions.quiet_build in true_y: myoptions.quiet_build = 'y' if myoptions.rebuild_if_new_slot in true_y: myoptions.rebuild_if_new_slot = 'y' if myoptions.rebuild_if_new_ver in true_y: myoptions.rebuild_if_new_ver = True else: myoptions.rebuild_if_new_ver = None if myoptions.rebuild_if_new_rev in true_y: myoptions.rebuild_if_new_rev = True myoptions.rebuild_if_new_ver = None else: myoptions.rebuild_if_new_rev = None if myoptions.rebuild_if_unbuilt in true_y: myoptions.rebuild_if_unbuilt = True myoptions.rebuild_if_new_rev = None myoptions.rebuild_if_new_ver = None else: myoptions.rebuild_if_unbuilt = None if myoptions.rebuilt_binaries in true_y: myoptions.rebuilt_binaries = True if myoptions.root_deps in true_y: myoptions.root_deps = True if myoptions.select in true_y: myoptions.select = True myoptions.oneshot = False elif myoptions.select == "n": myoptions.oneshot = True if myoptions.selective in true_y: myoptions.selective = True if myoptions.backtrack is not None: try: backtrack = int(myoptions.backtrack) except (OverflowError, ValueError): backtrack = -1 if backtrack < 0: backtrack = None if not silent: parser.error("Invalid --backtrack parameter: '%s'\n" % \ (myoptions.backtrack,)) myoptions.backtrack = backtrack if myoptions.deep is not None: deep = None if myoptions.deep == "True": deep = True else: try: deep = int(myoptions.deep) except (OverflowError, ValueError): deep = -1 if deep is not True and deep < 0: deep = None if not silent: parser.error("Invalid --deep parameter: '%s'\n" % \ (myoptions.deep,)) myoptions.deep = deep if myoptions.jobs: jobs = None if myoptions.jobs == "True": jobs = True else: try: jobs = int(myoptions.jobs) except ValueError: jobs = -1 if jobs is not True and \ jobs < 1: jobs = None if not silent: parser.error("Invalid --jobs parameter: '%s'\n" % \ (myoptions.jobs,)) myoptions.jobs = jobs if myoptions.load_average == "True": myoptions.load_average = None if myoptions.load_average: try: load_average = float(myoptions.load_average) except ValueError: load_average = 0.0 if load_average <= 0.0: load_average = None if not silent: parser.error("Invalid --load-average parameter: '%s'\n" % \ (myoptions.load_average,)) myoptions.load_average = load_average if myoptions.rebuilt_binaries_timestamp: try: rebuilt_binaries_timestamp = int(myoptions.rebuilt_binaries_timestamp) except ValueError: rebuilt_binaries_timestamp = -1 if rebuilt_binaries_timestamp < 0: rebuilt_binaries_timestamp = 0 if not silent: parser.error("Invalid --rebuilt-binaries-timestamp parameter: '%s'\n" % \ (myoptions.rebuilt_binaries_timestamp,)) myoptions.rebuilt_binaries_timestamp = rebuilt_binaries_timestamp if myoptions.use_ebuild_visibility in true_y: myoptions.use_ebuild_visibility = True else: # None or "n" pass if myoptions.usepkg in true_y: myoptions.usepkg = True else: myoptions.usepkg = None if myoptions.usepkgonly in true_y: myoptions.usepkgonly = True else: myoptions.usepkgonly = None for myopt in options: v = getattr(myoptions, myopt.lstrip("--").replace("-", "_")) if v: myopts[myopt] = True for myopt in argument_options: v = getattr(myoptions, myopt.lstrip("--").replace("-", "_"), None) if v is not None: myopts[myopt] = v if myoptions.searchdesc: myoptions.search = True for action_opt in actions: v = getattr(myoptions, action_opt.replace("-", "_")) if v: if myaction: multiple_actions(myaction, action_opt) sys.exit(1) myaction = action_opt if myaction is None and myoptions.deselect is True: myaction = 'deselect' if myargs and isinstance(myargs[0], bytes): for i in range(len(myargs)): myargs[i] = portage._unicode_decode(myargs[i]) myfiles += myargs return myaction, myopts, myfiles
def process_cmd_line(): """ Processes the command line arguments and sets up the system control variables accordingly. If an error occurred, an error message indicating the fault will be printed before the returning False. :return Returns options if no errors occurred, otherwise False. """ # Set up parser opt_parser = OptionParser() opt_parser.prog = "direcMeasure" usage = set_usage(opt_parser.prog) opt_parser.set_usage(usage) opt_parser.set_defaults(run_type="f", verbose=False) # Main options opt_parser.add_option( "-c", "--config", type="string", action="store", dest="cfg", default='', help= "Configuration file used to control the system. Must be a JSON file.") opt_parser.add_option("-a", "--alignOnly", action="callback", callback=config_run, dest="run_type", help="Only run the alignment routine.") opt_parser.add_option("--calibrate", action="store_true", dest="calibrate", default=False, help="Run the calibration interface.") opt_parser.add_option("--plot", action="store_true", dest="plot", default=False, help="Run the calibration interface.") # Plot options opt_parser.add_option("--dataFile", type="string", action="store", dest="data_file", default='', help="Plot option. Input data file to plot") opt_parser.add_option( "--plotType", type="string", action="store", dest="plot_type", default='', help= f"Plot option. Type of plot to generate. Must be one of the following" f" {parser.ALLOWED_PLOT_TYPES}.") opt_parser.add_option( "--freq", type="string", action="store", dest="plot_freq", default='', help="Plot option. Frequency to plot at. Must be in Hz, MHz, or GHz") opt_parser.add_option( "--phi", type="float", action="store", dest="plot_phi", default=200.0, help="Plot option. Test phi angle to plot at. Must be in degrees " "and between -180 and 180 degrees.") opt_parser.add_option( "--theta", type="float", action="store", dest="plot_theta", default=200.0, help="Plot option. Test theta angle to plot at. Must be in degrees " "and between -180 and 180 degrees.") opt_parser.add_option( "--probePhi", type="float", action="store", dest="plot_p_phi", default=200.0, help="Plot option. Probe phi angle to plot at. Must be in degrees " "and between -180 and 180 degrees.") opt_parser.add_option("--sParams", type="string", action="store", dest="sParams", default="S21", help="Plot option. S parameters to plot.") opt_parser.add_option("--logName", type="string", action="store", dest="log_name", default=None, help="Filename for terminal output log.") opt_parser.add_option("--logPath", type="string", action="store", dest="log_path", default=None, help="Filepath for terminal output log.") opt_parser.add_option( "--dataPath", type="string", action="store", dest="data_path", default=None, help="Filepath for data file taken during experiment.") opt_parser.add_option( "--dataName", type="string", action="store", dest="data_name", default=None, help="Filename for data file taken during experiment.") opt_parser.add_option( "--plotName", type="string", action="store", dest="plot_name", default=None, help="Filename for plot generated during experiment.") opt_parser.add_option( "--plotPath", type="string", action="store", dest="plot_path", default=None, help="Filepath for plot generated during experiment.") opt_parser.add_option( "--setTestPhi", type="float", action="store", dest="test_phi", default=None, help= "Sets the test-side phi angle to the specified angle. Must be in degrees " "and between -180 and 180 degrees.") opt_parser.add_option( "--zeroTestPhi", action="store_true", dest="zero_test_phi", default=False, help="Sets the current test-side phi angle to be the zero reference.") opt_parser.add_option( "--alignTestPhi", action="store_true", dest="align_test_phi", default=False, help="Aligns the test-side phi motor with the end-switch.") # Test Theta Options opt_parser.add_option( "--setTestTheta", type="float", action="store", dest="test_theta", default=None, help= "Sets the test-side theta angle to the specified angle. Must be in degrees " "and between -180 and 180 degrees.") opt_parser.add_option( "--zeroTestTheta", action="store_true", dest="zero_test_theta", default=False, help="Sets the current test-side theta angle to be the zero reference." ) opt_parser.add_option( "--alignTestTheta", action="store_true", dest="align_test_theta", default=False, help="Aligns the test-side test motor with the end-switch.") # Probe Theta Options opt_parser.add_option( "--setProbePhi", type="float", action="store", dest="probe_phi", default=None, help= "Sets the probe-side phi angle to the specified angle. Must be in degrees " "and between -180 and 180 degrees.") opt_parser.add_option( "--zeroProbePhi", action="store_true", dest="zero_probe_phi", default=False, help="Sets the current probe-side phi angle to be the zero reference.") opt_parser.add_option( "--alignProbePhi", action="store_true", dest="align_probe_phi", default=False, help="Aligns the probe-side phi motor with the end-switch.") # Options determining how the motor will rotate opt_parser.add_option("--direction", action="store", dest="direction", default=None, help="The direction in which motor should rotate.") opt_parser.add_option( "--gradualAcceleration", action="store_true", dest="grad_accel", default=None, help= "Gradually accelerate the motor to its maximum frequency. Recommended for test-theta motor." ) opt_parser.add_option( "--jumpAcceleration", action="store_false", dest="grad_accel", help= "Instantly accelerate the motor to its maximum frequency. Recommended for test-phi and probe-phi motors." ) opt_parser.add_option( "--incremental", action="store_true", dest="incremental", default=False, help= "Whether input angle should be interpreted as absolute or relative to current angle." ) # Check to make sure a config file was entered with the -c index = -1 for i in range(len(sys.argv)): if sys.argv[i] == "-c" or sys.argv[i] == "--config": index = i + 1 if index >= len(sys.argv) or index > 0 and opt_parser.has_option( sys.argv[index]): sys.argv.insert(index, None) # Parse command line (options, args) = opt_parser.parse_args() # print(options) # Check for single mode if options.test_phi != None or options.zero_test_phi or options.align_test_phi or \ options.test_theta != None or options.zero_test_theta or options.align_test_theta \ or options.probe_phi != None or options.zero_probe_phi or options.align_probe_phi: if options.run_type == 'f': options.run_type = 's' else: options.run_type = 'e' # Error Checking if options.run_type == "e": util.printf( curr_phase, "Error", "Cannot simultaneously run the alignment routine only and run the system with out " "the alignment routine. See usage for more information on command line options." ) opt_parser.print_help() return False # Config file checks if options.cfg is None: util.printf( curr_phase, "Error", f"Configuration file flag detected but no configuration was detected. See usage " f"for more information on command line options. ") opt_parser.print_help() return False num_modes = int(options.cfg != '') + int(options.run_type == 'a') + int(options.run_type == 's') + \ int(options.calibrate) + int(options.plot) if num_modes == 0: util.printf( curr_phase, "Error", "Cannot configure system as no command lines arguments were inputted." " See usage for more information on command line options. ") opt_parser.print_help() return False if num_modes > 1: util.printf( curr_phase, "Error", "Mutually-exclusive options specified. Cannot simultaneously run the " "calibration routine and the run the full run the system. See usage for more " "information on command line options.") opt_parser.print_help() return False if options.calibrate: options.run_type = "c" if options.plot: options.run_type = "p" if options.data_file == '': util.printf( curr_phase, "Error", f"Plotting requested but no input data file was entered." f" See usage for more information on command line options.") opt_parser.print_help() return False if options.data_file == '' or not options.data_file.endswith(".csv"): util.printf( curr_phase, "Error", f"The input data file entered '{options.data_file}' is not a csv file. " f" See usage for more information on command line options.") opt_parser.print_help() return False if options.plot_type == '': util.printf( curr_phase, "Error", f"Plotting requested but no plot type was specified. " f" See usage for more information on command line options.") opt_parser.print_help() return False if options.plot_type not in parser.ALLOWED_PLOT_TYPES: util.printf( curr_phase, "Error", f"Plotting requested but invalid plot type {options.plot_type} was specified. " f"Plot type must one of the following {parser.ALLOWED_PLOT_TYPES}" f" See usage for more information on command line options.") opt_parser.print_help() return False if options.plot_type == "cutPhi" and options.plot_phi == 200: util.printf( curr_phase, "Error", f"Phi cut plot requested but no phi angle was specified. " f" See usage for more information on command line options.") opt_parser.print_help() return False elif options.plot_type == "cutTheta" and options.plot_theta == 200: util.printf( curr_phase, "Error", f"Theta cut plot requested but no theta angle was specified. " f" See usage for more information on command line options.") opt_parser.print_help() return False if 'MHz' in options.plot_freq: options.plot_freq = 1e6 * float(options.plot_freq[:-3]) elif 'GHz' in options.plot_freq: options.plot_freq = 1e9 * float(options.plot_freq[:-3]) elif 'Hz' in options.plot_freq: options.plot_freq = float(options.plot_freq[:-3]) else: util.printf( curr_phase, "Error", f"Plotting requested but invalid plot frequency {options.plot_freq} was specified. " f"Plot type must be in units of Hz, MHz, or GHz (e.g. 10GHz or \"10 GHz\")." f" See usage for more information on command line options.") opt_parser.print_help() return False if options.cfg != '' and not options.cfg.endswith(".json"): util.printf( curr_phase, "Error", f"The configuration file entered '{options.cfg}' is not a JSON file. " f" See the User Manual for more information on configuration files and " f"usage for more information on command line options.") opt_parser.print_help() return False return options
class CommandLineParser(object): # Defines what --regular means REGULAR_CMD = [ 'sslv2', 'sslv3', 'tlsv1', 'tlsv1_1', 'tlsv1_2', 'reneg', 'resum', 'certinfo_basic', 'http_get', 'hide_rejected_ciphers', 'compression', 'heartbleed', 'openssl_ccs', 'fallback' ] SSLYZE_USAGE = 'usage: %prog [options] target1.com target2.com:443 target3.com:443{ip} etc...' # StartTLS options START_TLS_PROTOCOLS = [ 'smtp', 'xmpp', 'xmpp_server', 'pop3', 'ftp', 'imap', 'ldap', 'rdp', 'postgres', 'auto' ] START_TLS_USAGE = 'STARTTLS should be one of: {}. The \'auto\' option will cause SSLyze to deduce the protocol ' \ '(ftp, imap, etc.) from the supplied port number, ' \ 'for each target servers.'.format(' , '.join(START_TLS_PROTOCOLS)) # Mapping of StartTls protocols and ports; useful for starttls=auto STARTTLS_PROTOCOL_DICT = { 'smtp': TlsWrappedProtocolEnum.STARTTLS_SMTP, 587: TlsWrappedProtocolEnum.STARTTLS_SMTP, 25: TlsWrappedProtocolEnum.STARTTLS_SMTP, 'xmpp': TlsWrappedProtocolEnum.STARTTLS_XMPP, 5222: TlsWrappedProtocolEnum.STARTTLS_XMPP, 'xmpp_server': TlsWrappedProtocolEnum.STARTTLS_XMPP_SERVER, 5269: TlsWrappedProtocolEnum.STARTTLS_XMPP_SERVER, 'pop3': TlsWrappedProtocolEnum.STARTTLS_POP3, 109: TlsWrappedProtocolEnum.STARTTLS_POP3, 110: TlsWrappedProtocolEnum.STARTTLS_POP3, 'imap': TlsWrappedProtocolEnum.STARTTLS_IMAP, 143: TlsWrappedProtocolEnum.STARTTLS_IMAP, 220: TlsWrappedProtocolEnum.STARTTLS_IMAP, 'ftp': TlsWrappedProtocolEnum.STARTTLS_FTP, 21: TlsWrappedProtocolEnum.STARTTLS_FTP, 'ldap': TlsWrappedProtocolEnum.STARTTLS_LDAP, 3268: TlsWrappedProtocolEnum.STARTTLS_LDAP, 389: TlsWrappedProtocolEnum.STARTTLS_LDAP, 'rdp': TlsWrappedProtocolEnum.STARTTLS_RDP, 3389: TlsWrappedProtocolEnum.STARTTLS_RDP, 'postgres': TlsWrappedProtocolEnum.STARTTLS_POSTGRES, 5432: TlsWrappedProtocolEnum.STARTTLS_POSTGRES } def __init__(self, available_plugins, sslyze_version): """Generates SSLyze's command line parser. """ self._parser = OptionParser(version=sslyze_version, usage=self.SSLYZE_USAGE) # Add generic command line options to the parser self._add_default_options() # Add plugin-specific options to the parser self._add_plugin_options(available_plugins) # Add the --regular command line parameter as a shortcut if possible regular_help = 'Regular HTTPS scan; shortcut for --{}'.format( ' --'.join(self.REGULAR_CMD)) self._parser.add_option('--regular', action="store_true", dest=None, help=regular_help) def parse_command_line(self): """Parses the command line used to launch SSLyze. """ (args_command_list, args_target_list) = self._parser.parse_args() # Handle the --targets_in command line and fill args_target_list if args_command_list.targets_in: if args_target_list: raise CommandLineParsingError( "Cannot use --targets_list and specify targets within the command line." ) try: # Read targets from a file with open(args_command_list.targets_in) as f: for target in f.readlines(): if target.strip(): # Ignore empty lines if not target.startswith( '#'): # Ignore comment lines args_target_list.append(target.strip()) except IOError: raise CommandLineParsingError( "Can't read targets from input file '{}.".format( args_command_list.targets_in)) if not args_target_list: raise CommandLineParsingError('No targets to scan.') # Handle the --regular command line parameter as a shortcut if self._parser.has_option('--regular'): if getattr(args_command_list, 'regular'): setattr(args_command_list, 'regular', False) for cmd in self.REGULAR_CMD: setattr(args_command_list, cmd, True) # Sanity checks on the command line options # Prevent --quiet and --xml_out - if args_command_list.xml_file and args_command_list.xml_file == '-' and args_command_list.quiet: raise CommandLineParsingError( 'Cannot use --quiet with --xml_out -.') # Prevent --quiet and --json_out - if args_command_list.json_file and args_command_list.json_file == '-' and args_command_list.quiet: raise CommandLineParsingError( 'Cannot use --quiet with --json_out -.') # Prevent --xml_out - and --json_out - if args_command_list.json_file and args_command_list.json_file == '-' \ and args_command_list.xml_file and args_command_list.xml_file == '-': raise CommandLineParsingError( 'Cannot use --xml_out - with --json_out -.') # Sanity checks on the client cert options client_auth_creds = None if bool(args_command_list.cert) ^ bool(args_command_list.key): raise CommandLineParsingError( 'No private key or certificate file were given. See --cert and --key.' ) elif args_command_list.cert: # Private key formats if args_command_list.keyform == 'DER': key_type = SSL_FILETYPE_ASN1 elif args_command_list.keyform == 'PEM': key_type = SSL_FILETYPE_PEM else: raise CommandLineParsingError( '--keyform should be DER or PEM.') # Let's try to open the cert and key files try: client_auth_creds = ClientAuthenticationCredentials( args_command_list.cert, args_command_list.key, key_type, args_command_list.keypass) except ValueError as e: raise CommandLineParsingError( 'Invalid client authentication settings: {}.'.format(e[0])) # HTTP CONNECT proxy http_tunneling_settings = None if args_command_list.https_tunnel: try: http_tunneling_settings = HttpConnectTunnelingSettings.from_url( args_command_list.https_tunnel) except ValueError as e: raise CommandLineParsingError( 'Invalid proxy URL for --https_tunnel: {}.'.format(e[0])) # STARTTLS tls_wrapped_protocol = TlsWrappedProtocolEnum.PLAIN_TLS if args_command_list.starttls: if args_command_list.starttls not in self.START_TLS_PROTOCOLS: raise CommandLineParsingError(self.START_TLS_USAGE) else: # StartTLS was specified if args_command_list.starttls in self.STARTTLS_PROTOCOL_DICT.keys( ): # Protocol was given in the command line tls_wrapped_protocol = self.STARTTLS_PROTOCOL_DICT[ args_command_list.starttls] # Number of connection retries if args_command_list.nb_retries < 1: raise CommandLineParsingError( 'Cannot have a number smaller than 1 for --nb_retries.') # Create the server connectivity info for each specifed servers # A limitation when using the command line is that only one client_auth_credentials and http_tunneling_settings # can be specified, for all the servers to scan good_server_list = [] bad_server_list = [] for server_string in args_target_list: # Support unicode domains server_string = unicode(server_string, 'utf-8') try: good_server_list.append( ServerConnectivityInfo.from_command_line( server_string=server_string, tls_wrapped_protocol=tls_wrapped_protocol, tls_server_name_indication=args_command_list.sni, xmpp_to_hostname=args_command_list.xmpp_to, client_auth_credentials=client_auth_creds, http_tunneling_settings=http_tunneling_settings)) except ServerConnectivityError as e: # Will happen for example if the DNS lookup failed or the server string is malformed bad_server_list.append((server_string, e)) except ValueError as e: # Will happen for example if xmpp_to is specified for a non-XMPP connection raise CommandLineParsingError(e[0]) # Command line hacks # Handle --starttls=auto now that we parsed the server strings if args_command_list.starttls == 'auto': for server_info in good_server_list: # We use the port number to deduce the protocol if server_info.port in self.STARTTLS_PROTOCOL_DICT.keys(): server_info.tls_wrapped_protocol = self.STARTTLS_PROTOCOL_DICT[ server_info.port] # Handle --http_get now that we parsed the server strings # Doing it here is hacky as the option is defined within PluginOpenSSLCipherSuites if args_command_list.http_get: for server_info in good_server_list: if server_info.port == 443: server_info.tls_wrapped_protocol = TlsWrappedProtocolEnum.HTTPS return good_server_list, bad_server_list, args_command_list def _add_default_options(self): """ Adds default command line options to the parser. """ # Client certificate options clientcert_group = OptionGroup(self._parser, 'Client certificate support', '') clientcert_group.add_option( '--cert', help= 'Client certificate chain filename. The certificates must be in PEM format and must be sorted ' 'starting with the subject\'s client certificate, followed by intermediate CA certificates if ' 'applicable.', dest='cert') clientcert_group.add_option('--key', help='Client private key filename.', dest='key') clientcert_group.add_option( '--keyform', help='Client private key format. DER or PEM (default).', dest='keyform', default='PEM') clientcert_group.add_option('--pass', help='Client private key passphrase.', dest='keypass', default='') self._parser.add_option_group(clientcert_group) # XML output self._parser.add_option( '--xml_out', help= 'Writes the scan results as an XML document to the file XML_FILE. If XML_FILE is set to "-", the XML ' 'output will instead be printed to stdout.', dest='xml_file', default=None) # JSON output self._parser.add_option( '--json_out', help= 'Writes the scan results as a JSON document to the file JSON_FILE. If JSON_FILE is set to "-", the ' 'JSON output will instead be printed to stdout.', dest='json_file', default=None) # Read targets from input file self._parser.add_option( '--targets_in', help= 'Reads the list of targets to scan from the file TARGETS_IN. It should contain one host:port per ' 'line.', dest='targets_in', default=None) # Timeout self._parser.add_option( '--timeout', help= 'Sets the timeout value in seconds used for every socket connection made to the target server(s). ' 'Default is {}s.'.format(str(SSLConnection.NETWORK_TIMEOUT)), type='int', dest='timeout', default=SSLConnection.NETWORK_TIMEOUT) # Control connection retry attempts self._parser.add_option( '--nb_retries', help= 'Sets the number retry attempts for all network connections initiated throughout the scan. Increase ' 'this value if you are getting a lot of timeout/connection errors when scanning a specific server. ' 'Decrease this value to increase the speed of the scans; results may however return connection errors.' ' Default is {} connection attempts.'.format( str(SSLConnection.NETWORK_MAX_RETRIES)), type='int', dest='nb_retries', default=SSLConnection.NETWORK_MAX_RETRIES) # HTTP CONNECT Proxy self._parser.add_option( '--https_tunnel', help= 'Tunnels all traffic to the target server(s) through an HTTP CONNECT proxy. HTTP_TUNNEL should be the ' 'proxy\'s URL: \'http://*****:*****@HOST:PORT/\'. For proxies requiring authentication, only Basic ' 'Authentication is supported.', dest='https_tunnel', default=None) # STARTTLS self._parser.add_option( '--starttls', help= 'Performs StartTLS handshakes when connecting to the target server(s). ' + self.START_TLS_USAGE, dest='starttls', default=None) self._parser.add_option( '--xmpp_to', help= 'Optional setting for STARTTLS XMPP. XMPP_TO should be the hostname to be put in the \'to\' attribute ' 'of the XMPP stream. Default is the server\'s hostname.', dest='xmpp_to', default=None) # Server Name Indication self._parser.add_option( '--sni', help= 'Use Server Name Indication to specify the hostname to connect to. Will only affect TLS 1.0+ ' 'connections.', dest='sni', default=None) # No text output self._parser.add_option( '--quiet', action="store_true", dest='quiet', help= 'Do not output anything to stdout; useful when using --xml_out or --json_out.' ) def _add_plugin_options(self, available_plugins): """Recovers the list of command line options implemented by the available plugins and adds them to the command line parser. """ for plugin_class in available_plugins: plugin_desc = plugin_class.get_interface() # Add the current plugin's commands to the parser group = OptionGroup(self._parser, plugin_desc.title, plugin_desc.description) for cmd in plugin_desc.get_commands(): group.add_option(cmd) # Add the current plugin's options to the parser for option in plugin_desc.get_options(): group.add_option(option) self._parser.add_option_group(group)
c += 1 else: if options.output: filename = options.output else: filename = inputfile output = "%s.png" % (os.path.splitext(filename)[0]) c = 1 while os.path.exists(output): output = "%s_%i.png" % (os.path.splitext(filename)[0], c) c += 1 parser = SimpleParser(inputfile) if options.solution: solution = options.solution elif parser.has_option("solution"): solution = parser.get_option("solution") else: solution = None wordlist = parser.get_questions() cwd = CrossWord(options.columns, options.rows, " ", 5000, wordlist) score = cwd.compute_crossword(best_of=options.bestof, force_solved=False) tmplist = [w.word.lower() for w in cwd.placed_words] missing = [w.word for w in cwd.wordlist if w.word.lower() not in tmplist] if missing != []: print("Could not place some words. Probably your grid is too small. Sometimes setting \"--bestof\" to a higer value also help.") print("Words that could not be placed: '%s'" % missing) if options.stats:
class LogrotateOptParser(object): ''' Class for parsing commandline options of Python logrotating. @author: Frank Brehm @contact: [email protected] ''' #------------------------------------------------------- def __init__( self, prog='%prog', version=None, local_dir=None, ): ''' Constructor. @param prog: The name of the calling process (e.g. sys.argv[0]) @type prog: str @param version: The version string to use @type version: str @param local_dir: The directory, where the i18n-files (*.mo) are located. If None, then system default (/usr/share/locale) is used. @type local_dir: str or None @return: None ''' self.prog = prog ''' @ivar: The name of the calling process @type: str ''' self.version = version ''' @ivar: The version string to use @type: str ''' self.local_dir = local_dir ''' @ivar: The directory, where the i18n-files (*.mo) are located. @type: str or None ''' self.t = gettext.translation('pylogrotate', local_dir, fallback=True) ''' @ivar: a gettext translation object @type: gettext.translation ''' _ = self.t.lgettext self.description = _('Rotates, compresses and mails system logs.') ''' @ivar: description of the program @type: str ''' msg = _("%s [options] <configfile>") self.usage = msg % (prog) ''' @ivar: the usage string in getopt help output @type: str ''' self.usage += (' %s [-h|-?|--help]\n' % (prog)) self.usage += (' %s --usage\n' % (prog)) self.usage += (' %s --version' % (prog)) self.options = None ''' @ivar: a dict with all given commandline options after calling getOpts() @type: dict or None ''' self.args = None ''' @ivar: a list with all commandline parameters, what are not options @type: list or None ''' self.parsed = False ''' @ivar: flag, whether the parsing was done @type: bool ''' if version: self.version = version self.parser = OptionParser( prog=self.prog, version=self.version, description=self.description, usage=self.usage, conflict_handler="resolve", ) ''' @ivar: the working OptionParser Object @type: optparse.OptionParser ''' self._add_options() #------------------------------------------------------- def _add_options(self): ''' Private function to add all necessary options to the OptionParser object ''' #print "" #print "Default system encoding: »%s«." \ # % (sys.getdefaultencoding()) #print "Default filesystem encoding: »%s«." \ # % (sys.getfilesystemencoding()) #print "" _ = self.t.lgettext if self.parser.has_option('--help'): self.parser.remove_option('--help') if self.parser.has_option('--version'): self.parser.remove_option('--version') msg = _('Set this do simulate commands') self.parser.add_option( '--simulate', '--test', '-T', default=False, action='store_true', dest='test', help=to_unicode_or_bust(msg), ) msg = _('Set the verbosity level') self.parser.add_option( '--verbose', '-v', default=False, action='count', dest='verbose', help=to_unicode_or_bust(msg), ) msg = _("Don't do anything, just test (implies -v and -T)") self.parser.add_option( '--debug', '-d', default=False, action='store_true', dest='debug', help=to_unicode_or_bust(msg), ) msg = _("Force file rotation") self.parser.add_option( '--force', '-f', default=False, action='store_true', dest='force', help=to_unicode_or_bust(msg), ) msg = _("Checks only the given configuration file and does " + "nothing. Conflicts with -f.") self.parser.add_option( '--config-check', '-c', default=False, action='store_true', dest='configcheck', help=to_unicode_or_bust(msg), ) msg = _('Path of state file (different to configuration)') self.parser.add_option( '--state', '-s', dest="statefile", metavar='FILE', help=to_unicode_or_bust(msg), ) msg = _('Path of PID file (different to configuration)') self.parser.add_option( '--pid-file', '-P', dest="pidfile", metavar='FILE', help=to_unicode_or_bust(msg), ) msg = _("Command to send mail (instead of using SMTP or " + "the predefined sendmail command).") self.parser.add_option( '--mail', '-m', dest="mailcmd", metavar='CMD', help=to_unicode_or_bust(msg), ) ###### # Option group for common options group = OptionGroup(self.parser, _("Common options")) msg = _('Shows a help message and exit.') group.add_option( '-h', '-?', '--help', default=False, action='help', dest='help', help=to_unicode_or_bust(msg), ) msg = _('Display brief usage message and exit.') group.add_option( '--usage', default=False, action='store_true', dest='usage', help=to_unicode_or_bust(msg), ) msg = _('Shows the version number of the program and exit.') group.add_option( '-V', '--version', default=False, action='version', dest='version', help=to_unicode_or_bust(msg), ) self.parser.add_option_group(group) #---------------------------------------------------------------------- def getOpts(self): ''' Wrapper function to OptionParser.parse_args(). Sets self.options and self.args with the appropriate values. @return: None ''' _ = self.t.lgettext if not self.parsed: self.options, self.args = self.parser.parse_args() self.parsed = True if self.options.usage: self.parser.print_usage() sys.exit(0) if self.options.force and self.options.configcheck: msg = _('Invalid usage of --force and --config-check.') raise LogrotateOptParserError(msg) if self.args is None or len(self.args) < 1: msg = _('No configuration file given.') raise LogrotateOptParserError(msg) if len(self.args) != 1: msg = _('Only one configuration file is allowed.') raise LogrotateOptParserError(msg)
def main(): from optparse import OptionParser, OptionValueError parser = OptionParser(usage="usage: %prog [options] [projenv] ...", version="%%prog %s" % VERSION) auths = {} def _auth_callback(option, opt_str, value, parser, cls): info = value.split(",", 3) if len(info) != 3: raise OptionValueError("Incorrect number of parameters for %s" % option) env_name, filename, realm = info if env_name in auths: print >>sys.stderr, "Ignoring duplicate authentication option for " "project: %s" % env_name else: auths[env_name] = cls(os.path.abspath(filename), realm) def _validate_callback(option, opt_str, value, parser, valid_values): if value not in valid_values: raise OptionValueError("%s must be one of: %s, not %s" % (opt_str, "|".join(valid_values), value)) setattr(parser.values, option.dest, value) parser.add_option( "-a", "--auth", action="callback", type="string", metavar="DIGESTAUTH", callback=_auth_callback, callback_args=(DigestAuthentication,), help="[projectdir],[htdigest_file],[realm]", ) parser.add_option( "--basic-auth", action="callback", type="string", metavar="BASICAUTH", callback=_auth_callback, callback_args=(BasicAuthentication,), help="[projectdir],[htpasswd_file],[realm]", ) parser.add_option("-p", "--port", action="store", type="int", dest="port", help="the port number to bind to") parser.add_option( "-b", "--hostname", action="store", dest="hostname", help="the host name or IP address to bind to" ) parser.add_option( "--protocol", action="callback", type="string", dest="protocol", callback=_validate_callback, callback_args=(("http", "scgi", "ajp"),), help="http|scgi|ajp", ) parser.add_option( "-e", "--env-parent-dir", action="store", dest="env_parent_dir", metavar="PARENTDIR", help="parent directory of the project environments", ) parser.add_option( "--base-path", action="store", type="string", dest="base_path", help="base path" # XXX call this url_base_path? ) parser.add_option( "-r", "--auto-reload", action="store_true", dest="autoreload", help="restart automatically when sources are modified", ) parser.add_option( "-s", "--single-env", action="store_true", dest="single_env", help="only serve a single " "project without the project list", default=False, ) if os.name == "posix": parser.add_option( "-d", "--daemonize", action="store_true", dest="daemonize", help="run in the background as a daemon" ) parser.add_option( "--pidfile", action="store", dest="pidfile", help="When daemonizing, file to which to write pid" ) parser.set_defaults(port=None, hostname="", base_path="", daemonize=False, protocol="http") options, args = parser.parse_args() if not args and not options.env_parent_dir: parser.error("either the --env-parent-dir option or at least one " "environment must be specified") if options.single_env: if options.env_parent_dir: parser.error("the --single-env option cannot be used with " "--env-parent-dir") elif len(args) > 1: parser.error("the --single-env option cannot be used with " "more than one enviroment") if options.port is None: options.port = {"http": 80, "scgi": 4000, "ajp": 8009}[options.protocol] server_address = (options.hostname, options.port) # autoreload doesn't work when daemonized and using relative paths if options.daemonize and options.autoreload: for path in args + [options.env_parent_dir, options.pidfile]: if path and not os.path.isabs(path): parser.error( '"%s" is not an absolute path.\n\n' "when using both --auto-reload and --daemonize " "all path arguments must be absolute" % path ) # relative paths don't work when daemonized args = [os.path.abspath(a) for a in args] if options.env_parent_dir: options.env_parent_dir = os.path.abspath(options.env_parent_dir) if parser.has_option("pidfile") and options.pidfile: options.pidfile = os.path.abspath(options.pidfile) wsgi_app = TracEnvironMiddleware(dispatch_request, options.env_parent_dir, args, options.single_env) if auths: if options.single_env: project_name = os.path.basename(args[0]) wsgi_app = AuthenticationMiddleware(wsgi_app, auths, project_name) else: wsgi_app = AuthenticationMiddleware(wsgi_app, auths) base_path = options.base_path.strip("/") if base_path: wsgi_app = BasePathMiddleware(wsgi_app, base_path) if options.protocol == "http": def serve(): httpd = TracHTTPServer(server_address, wsgi_app, options.env_parent_dir, args) httpd.serve_forever() elif options.protocol in ("scgi", "ajp"): def serve(): server_cls = __import__("flup.server.%s" % options.protocol, None, None, [""]).WSGIServer ret = server_cls(wsgi_app, bindAddress=server_address).run() sys.exit(ret and 42 or 0) # if SIGHUP exit with status 42 try: if os.name == "posix": if options.pidfile: options.pidfile = os.path.abspath(options.pidfile) if os.path.exists(options.pidfile): pidfile = open(options.pidfile) try: pid = int(pidfile.read()) finally: pidfile.close() try: # signal the process to see if it is still running os.kill(pid, 0) except OSError, e: if e.errno != errno.ESRCH: raise else: sys.exit("tracd is already running with pid %s" % pid) realserve = serve def serve(): try: pidfile = open(options.pidfile, "w") try: pidfile.write(str(os.getpid())) finally: pidfile.close() realserve() finally: if os.path.exists(options.pidfile): os.remove(options.pidfile) if options.daemonize: daemon.daemonize() if options.autoreload: def modification_callback(file): print >>sys.stderr, "Detected modification of %s, restarting." % file autoreload.main(serve, modification_callback) else: serve()
class TreePlottingOptParser : def __init__(self) : from optparse import OptionParser self.p = OptionParser() # file steering self.p.add_option('--bkgs',type='string',default='',dest='bkgs',help='input files for bkg (csv)') self.p.add_option('--signal',type='string',default='',dest='signal',help='input files for signal (csv)') self.p.add_option('--data',type='string',default='',dest='data',help='input file for data (csv)') # can also be specified in the config file self.p.add_option('--fb',type='float',default=1,dest='fb',help='int luminosity (fb)') self.p.add_option('--treename',type='string',default='physics',dest='treename',help='Treename (physics, CollectionTree)') self.p.add_option('-v','--variables',type='string',default='',dest='variables',help='Variables (see Variables.cxx for names)') self.p.add_option('-c','--cuts',type='string',default='',dest='cuts',help='cut string') self.p.add_option('--weight',type='string',default='',dest='weight',help='Monte Carlo event weight') self.p.add_option('--weightscale',type='string',default='',dest='weightscale',help='(built-in) function for non-event weight (xs, feff, etc)') # point to config file self.p.add_option('--config',type='string',default='',dest='config',help='Input configuration file (python module)') # histogram limits - only really useful if you are plotting a single variable self.p.add_option('--limits',type='string',default='-1,-1,-1',dest='limits',help='Limits (only useful for single plot') # plot manipulation self.p.add_option('--ratio',action='store_true',default=False,dest='ratio',help='Plot as a ratio') self.p.add_option('--pull' ,action='store_true',default=False,dest='pull' ,help='Plot as a pull distribution') self.p.add_option('--poisson',action='store_true',default=False,dest='poisson',help='Poisson errors for data') self.p.add_option('--nostack',action='store_true',default=False,dest='nostack',help='do not stack') self.p.add_option('--normalize',action='store_true',default=False,dest='normalize',help='normalize') self.p.add_option('--showflows',action='store_true',default=False,dest='showflows',help='show overflows/underflows as first and last bin') self.p.add_option('--plottext',type='string',default='',dest='plottext',help='Additional plot text') # other options self.p.add_option('--batch',action='store_true',default=False,dest='batch',help='run in batch mode') self.p.add_option('--save',action='store_true',default=False,dest='save',help='save cans to pdf') self.p.add_option('--outdir',type='string',default='',dest='outdir',help='output directory') self.p.add_option('-l','--log',action='store_true',default=False,dest='log',help='log') self.p.add_option('--xAODInit',action='store_true',default=False,dest='xAODInit',help='run xAOD::Init()') self.p.add_option('--macro',type='string',default='',dest='macro',help='Load and run a macro') def parse_args(self) : import sys,os import ROOT import importlib #LoadRootCore() self.options,self.args = self.p.parse_args() ROOT.gROOT.SetBatch(self.options.batch) self.options.stack = not self.options.nostack if self.options.save and not self.options.outdir : self.options.outdir = os.getcwd() if self.options.signal and not '.root' in self.options.signal : dir = self.options.signal self.options.signal = ','.join('%s/%s'%(dir,a) for a in os.listdir(self.options.signal)) if len(self.options.limits.split(',')) != 3 : print 'Error! Please specify --limits using 3 numbers in the format nbins,lowedge,highedge' sys.exit() self.options.variables = self.options.variables.split(',') self.options.plottext = self.options.plottext.split(',') # some defaults are not set in the option parser defaults = {'blindcut':[], 'truthcuts':[], 'mergesamples':dict(), 'colors':dict(), 'labels':dict(), 'histformat':dict(), 'usermodule':None, 'afterburner':None, 'customnormalize':None, 'variablemap':{}, } for k in defaults.keys() : setattr(self.options,k,defaults[k]) # if you indicate 'HZY' then the function weightscaleHZY() will be used. if self.options.weightscale : print 'INFO: Using weightscale function weightscale%s(tree)'%(self.options.weightscale) self.options.weightscale = eval('weightscale%s'%(self.options.weightscale)) else : def defaultweightscale(tfile) : return 1 self.options.weightscale = defaultweightscale if self.options.fb <= 0 : self.options.fb = 1. if self.options.xAODInit : if not os.getenv('AtlasArea') : print 'Error! Specified --xAODInit but did not set up ATLAS! Exiting.' import sys; sys.exit() ROOT.xAOD.Init() # to get your current directory viewable by the code: sys.path.append(os.getcwd()) # Read in options from config file: if self.options.config : usermodule = importlib.import_module(self.options.config.replace('.py','')) self.options.usermodule = usermodule for x in ['histformat','weight','weightscale','blindcut','truthcuts' ,'treename','fb','colors','labels','mergesamples','bkgs','data','signal','plottext' ,'afterburner','variablemap','customnormalize'] : if hasattr(usermodule,x) : setattr(self.options,x,getattr(usermodule,x)) if hasattr(usermodule,'cuts') : self.options.cuts = usermodule.cuts if len(self.options.cuts) > 1 : for i,c in enumerate(self.options.cuts) : self.options.cuts[i] = '('+c+')' if hasattr(usermodule,'variables') : self.options.variables = usermodule.variables # add .root to each background name. self.options.bkgs = ExpandWildcard(self.options.bkgs) self.options.bkgs = AddDotRoot(self.options.bkgs) self.options.signal = ExpandWildcard(self.options.signal) self.options.signal = AddDotRoot(self.options.signal) # add up multiple data files if self.options.data == 'all' : dirlist = os.listdir('.') datalist = [] for i in dirlist : if (not '.root' in i) or (not 'data' in i) : continue datalist.append(i) self.options.data = ','.join(datalist) self.options.data = ExpandWildcard(self.options.data) self.options.mergesamples['data'] = [] for a in self.options.data.split(',') : if not a : continue self.options.mergesamples['data'].append(a.replace('.root','')) self.options.data = AddDotRoot(self.options.data) if self.p.has_option('--bkgs') : if (not self.options.bkgs) and (not self.options.signal) and (not self.options.data) : print 'No --bkgs, --signal, or --data specified. Exiting.' SafeExit(self.options.xAODInit) self.options.xlabel = dict() self.options.rebin = dict() # turn limits into variable-specific values tmp_limits = self.options.limits self.options.limits = dict() # Prepare stuff related to the variables. for v in self.options.variables + self.options.variablemap.values() : if v == '' : continue if v in self.options.histformat.keys() : if len(self.options.histformat[v]) < 4 : self.options.histformat[v].append(v) else : n,low,high = tmp_limits.split(',') self.options.histformat[v] = [int(n),float(low),float(high),v] # set limits and xlabel: self.options.limits[v] = self.options.histformat[v][:3] self.options.xlabel[v] = self.options.histformat[v][3] if hasattr(self.options.usermodule,'rebin') and v in self.options.usermodule.rebin.keys() : self.options.rebin[v] = self.options.usermodule.rebin[v] # scripts will be looking for a python list of cuts if type(self.options.cuts) == type('') : self.options.cuts = [self.options.cuts] return self.options,self.args
def main(startstring): if not gottrac: rlog(100, 'tracserver', 'trac is not installed') return global httpd from optparse import OptionParser, OptionValueError parser = OptionParser(usage='usage: %prog [options] [projenv] ...', version='%%prog %s' % VERSION) auths = {} def _auth_callback(option, opt_str, value, parser, cls): info = value.split(',', 3) if len(info) != 3: raise OptionValueError("Incorrect number of parameters for %s" % option) env_name, filename, realm = info auths[env_name] = cls(os.path.abspath(filename), realm) def _validate_callback(option, opt_str, value, parser, valid_values): if value not in valid_values: raise OptionValueError('%s must be one of: %s, not %s' % (opt_str, '|'.join(valid_values), value)) setattr(parser.values, option.dest, value) parser.add_option('-a', '--auth', action='callback', type='string', metavar='DIGESTAUTH', callback=_auth_callback, callback_args=(DigestAuthentication, ), help='[projectdir],[htdigest_file],[realm]') parser.add_option('--basic-auth', action='callback', type='string', metavar='BASICAUTH', callback=_auth_callback, callback_args=(BasicAuthentication, ), help='[projectdir],[htpasswd_file],[realm]') parser.add_option('-p', '--port', action='store', type='int', dest='port', help='the port number to bind to') parser.add_option('-b', '--hostname', action='store', dest='hostname', help='the host name or IP address to bind to') parser.add_option('--protocol', action='callback', type="string", dest='protocol', callback=_validate_callback, callback_args=(('http', 'scgi', 'ajp', 'fcgi'), ), help='http|scgi|ajp|fcgi') parser.add_option('-e', '--env-parent-dir', action='store', dest='env_parent_dir', metavar='PARENTDIR', help='parent directory of the project environments') parser.add_option( '--base-path', action='store', type='string', # XXX call this url_base_path? dest='base_path', help='the initial portion of the request URL\'s "path"') parser.add_option('-r', '--auto-reload', action='store_true', dest='autoreload', help='restart automatically when sources are modified') parser.add_option('-s', '--single-env', action='store_true', dest='single_env', help='only serve a single ' 'project without the project list', default=False) if os.name == 'posix': parser.add_option('-d', '--daemonize', action='store_true', dest='daemonize', help='run in the background as a daemon') parser.add_option('--pidfile', action='store', dest='pidfile', help='When daemonizing, file to which to write pid') parser.add_option('--umask', action='store', type='int', dest='umask', metavar='MASK', help='When daemonizing, file mode creation mask ' 'to use (default 022)') parser.set_defaults(port=None, hostname='', base_path='', daemonize=False, protocol='http', umask=022) options, args = parser.parse_args(startstring.split()) if not args and not options.env_parent_dir: parser.error('either the --env-parent-dir option or at least one ' 'environment must be specified') if options.single_env: if options.env_parent_dir: parser.error('the --single-env option cannot be used with ' '--env-parent-dir') elif len(args) > 1: parser.error('the --single-env option cannot be used with ' 'more than one enviroment') if options.daemonize and options.autoreload: parser.error('the --auto-reload option cannot be used with ' '--daemonize') if options.port is None: options.port = { 'http': 80, 'scgi': 4000, 'ajp': 8009, 'fcgi': 8000, }[options.protocol] server_address = (options.hostname, options.port) # relative paths don't work when daemonized args = [os.path.abspath(a) for a in args] if options.env_parent_dir: options.env_parent_dir = os.path.abspath(options.env_parent_dir) if parser.has_option('pidfile') and options.pidfile: options.pidfile = os.path.abspath(options.pidfile) wsgi_app = TracEnvironMiddleware(dispatch_request, options.env_parent_dir, args, options.single_env) if auths: if options.single_env: project_name = os.path.basename(args[0]) wsgi_app = AuthenticationMiddleware(wsgi_app, auths, project_name) else: wsgi_app = AuthenticationMiddleware(wsgi_app, auths) base_path = options.base_path.strip('/') if base_path: wsgi_app = BasePathMiddleware(wsgi_app, base_path) try: httpd = TracHTTPServer(server_address, wsgi_app, options.env_parent_dir, args) except socket.error, ex: if 'already in use' in str(ex): rlog(10, 'tserver', 'server is already running') return
class CommandLineParser(): # Defines what --regular means REGULAR_CMD = ['sslv2', 'sslv3', 'tlsv1', 'reneg', 'resum', 'certinfo', 'http_get', 'hide_rejected_ciphers', 'compression', 'tlsv1_1', 'tlsv1_2'] SSLYZE_USAGE = 'usage: %prog [options] target1.com target2.com:443 etc...' def __init__(self, available_plugins, sslyze_version, timeout): """ Generates SSLyze's command line parser. """ self._parser = OptionParser(version=sslyze_version, usage=self.SSLYZE_USAGE) # Add generic command line options to the parser self._add_default_options(timeout) # Add plugin-specific options to the parser self._add_plugin_options(available_plugins) # Add the --regular command line parameter as a shortcut if possible regular_help = 'Regular HTTPS scan; shortcut for' for cmd in self.REGULAR_CMD: regular_help += ' --' + cmd if (self._parser.has_option('--' + cmd) == False): return self._parser.add_option('--regular', action="store_true", dest=None, help=regular_help) def parse_command_line(self): """ Parses the command line used to launch SSLyze. """ (args_command_list, args_target_list) = self._parser.parse_args() # Handle the --targets_in command line and fill args_target_list if args_command_list.targets_in: if args_target_list: raise CommandLineParsingError("Cannot use --targets_list and specify targets within the command line.") try: # Read targets from a file with open(args_command_list.targets_in) as f: for target in f.readlines(): if target.strip(): # Ignore empty lines if not target.startswith('#'): # Ignore comment lines args_target_list.append(target.strip()) except IOError: raise CommandLineParsingError("Can't read targets from input file '%s'." % args_command_list.targets_in) if args_target_list == []: raise CommandLineParsingError('No targets to scan.') # Handle the --regular command line parameter as a shortcut if self._parser.has_option('--regular'): if getattr(args_command_list, 'regular'): setattr(args_command_list, 'regular', False) for cmd in self.REGULAR_CMD: setattr(args_command_list, cmd, True) setattr(args_command_list, 'certinfo', 'basic') # Special case # Create the shared_settings object from looking at the command line shared_settings = self._process_parsing_results(args_command_list) return (args_command_list, args_target_list, shared_settings) def _add_default_options(self, timeout): """ Adds default command line options to the parser. """ # Client certificate options clientcert_group = OptionGroup(self._parser, 'Client certificate support', '') clientcert_group.add_option( '--cert', help='Client certificate filename.', dest='cert') clientcert_group.add_option( '--certform', help= 'Client certificate format. DER or PEM (default).', dest='certform', default='PEM') clientcert_group.add_option( '--key', help= 'Client private key filename.', dest='key') clientcert_group.add_option( '--keyform', help= 'Client private key format. DER or PEM (default).', dest='keyform', default='PEM') clientcert_group.add_option( '--pass', help= 'Client private key passphrase.', dest='keypass') self._parser.add_option_group(clientcert_group) # XML output self._parser.add_option( '--xml_out', help= ('Writes the scan results as an XML document to the file XML_FILE.'), dest='xml_file', default=None) # Read targets from input file self._parser.add_option( '--targets_in', help= ('Reads the list of targets to scan from the file TARGETS_IN. It should contain one host:port per line.'), dest='targets_in', default=None) # Timeout self._parser.add_option( '--timeout', help= ( 'Sets the timeout value in seconds used for every socket ' 'connection made to the target server(s). Default is 5s.'), type='int', dest='timeout', default=timeout) # Number of processes. self._parser.add_option( '--max_processes', help= ( 'Sets the maximum number of concurrent processes used ' ' for scanning. Default is 5 processes.'), type='int', dest='processes', default=timeout) # Verbosity self._parser.add_option( '--verbosity', help= ( 'Increases the verbosity of the program. ' 'Usable values in the range 0..3. Default is 0.'), type='int', dest='verbosity', default=0) # HTTP CONNECT Proxy self._parser.add_option( '--https_tunnel', help= ( 'Sets an HTTP CONNECT proxy to tunnel SSL traffic to the target ' 'server(s). HTTP_TUNNEL should be \'host:port\'. ' 'Requires Python 2.7'), dest='https_tunnel', default=None) # STARTTLS self._parser.add_option( '--starttls', help= ( 'Identifies the target server(s) protocols (FTP, SMTP, XMPP etc) ' 'and scans the server(s) using STARTTLS. ' 'STARTTLS should be \'ftp\', \'imap\', \'ldap\', ' '\'pop3\', \'smtp\' or \'xmpp\'. ' 'Alternatively \'auto\' can be given and the protocol will be ' 'selected based on the given port number.'), dest='starttls', default=None) self._parser.add_option( '--xmpp_to', help= ( 'Optional setting for STARTTLS XMPP. ' ' XMPP_TO should be the hostname to be put in the \'to\' attribute ' 'of the XMPP stream. Default is the server\'s hostname.'), dest='xmpp_to', default=None) # Server Name Indication self._parser.add_option( '--sni', help= ( 'Use Server Name Indication to specify the hostname to connect to.' ' Will only affect TLS 1.0+ connections.'), dest='sni', default=None) def _add_plugin_options(self, available_plugins): """ Recovers the list of command line options implemented by the available plugins and adds them to the command line parser. """ for plugin_class in available_plugins: plugin_desc = plugin_class.get_interface() # Add the current plugin's commands to the parser group = OptionGroup(self._parser, plugin_desc.title,\ plugin_desc.description) for cmd in plugin_desc.get_commands(): group.add_option(cmd) # Add the current plugin's options to the parser for option in plugin_desc.get_options(): group.add_option(option) self._parser.add_option_group(group) def _process_parsing_results(self, args_command_list): """ Performs various sanity checks on the command line that was used to launch SSLyze. Returns the shared_settings object to be fed to plugins. """ shared_settings = {} # Sanity checks on the client cert options if bool(args_command_list.cert) ^ bool(args_command_list.key): raise CommandLineParsingError('No private key or certificate file were given. See --cert and --key.') # Let's try to open the cert and key files if args_command_list.cert: try: open(args_command_list.cert,"r") except: raise CommandLineParsingError('Could not open the client certificate file "' + str(args_command_list.cert) + '".') if args_command_list.key: try: open(args_command_list.key,"r") except: raise CommandLineParsingError('Could not open the client private key file "' + str(args_command_list.key) + '"') # Parse client cert options if args_command_list.certform not in ['DER', 'PEM']: raise CommandLineParsingError('--certform should be DER or PEM.') if args_command_list.keyform not in ['DER', 'PEM']: raise CommandLineParsingError('--keyform should be DER or PEM.') # HTTP CONNECT proxy if args_command_list.https_tunnel: if '2.7.' not in platform.python_version(): # Python 2.7 only raise CommandLineParsingError( '--https_tunnel requires Python 2.7.X. ' 'Current version is ' + platform.python_version() + '.') try: # Need to parse the proxy host:port string now proxy_test = SSLServerTester(args_command_list.https_tunnel) shared_settings['https_tunnel_host'] = proxy_test.get_target()[0] shared_settings['https_tunnel_port'] = proxy_test.get_target()[2] except InvalidTargetError: raise CommandLineParsingError( 'Not a valid host/port for --https_tunnel' ', discarding all tasks.') else: shared_settings['https_tunnel_host'] = None shared_settings['https_tunnel_port'] = None # STARTTLS if args_command_list.starttls not in [None,'auto', 'ftp', 'imap', 'ldap', 'pop3', 'smtp','xmpp']: raise CommandLineParsingError( '--starttls should be \'smtp\', \'xmpp\' or \'auto\'.') if args_command_list.starttls and args_command_list.https_tunnel: raise CommandLineParsingError( 'Cannot have --https_tunnel and --starttls at the same time.') # All good, let's save the data for key, value in args_command_list.__dict__.iteritems(): shared_settings[key] = value return shared_settings
def run(): parser = OptionParser() parser.add_option("-d", "--database", dest="database", default="deska_dev", help="Name of the database to use", metavar="DB") parser.add_option("-U", "--username", dest="username", help="User to connect to the DB", metavar="USER") parser.add_option("--logfile", dest="logfile", default="deska_server.log", help="File name of the debug log") parser.add_option("--log-stderr", dest="log_stderr", action="store_true", default=False, help="Log to standard error") parser.add_option("--cfggen-backend", dest="cfggenBackend", metavar="METHOD", default="error", help= "Configuration method to use: error (throw errors upon " "using the configuration generators), fake (just do " "nothing, but do not throw errors) or git (work with a " "git repository)") parser.add_option("--cfggen-script-path", dest="cfggenScriptPath", default=None, metavar="PATH", help="Path to use when looking for the actual " "executables used for generating configuration") parser.add_option("--cfggen-git-repository", dest="cfggenGitRepo", default=None, metavar="PATH", help="Path of a git repository to use. Git " "will call `git push` from this repository, so this cannot " "be the master repo.") parser.add_option("--cfggen-git-workdir", dest="cfggenGitWorkdir", default=None, metavar="PATH", help="Path to use for storing git working " "directories for each changeset") (options, args) = parser.parse_args() # file the variables from environment if not parser.has_option("database") and os.environ.has_key("DESKA_DB"): options.database = os.environ["DESKA_DB"] if not parser.has_option("username") and os.environ.has_key("DESKA_USER"): options.username = os.environ["DESKA_USER"] if not parser.has_option("cfggenBackend") and os.environ.has_key("DESKA_CFGGEN_BACKEND"): options.cfggenBackend = os.environ["DESKA_CFGGEN_BACKEND"] if not parser.has_option("cfggenScriptPath") and os.environ.has_key("DESKA_CFGGEN_SCRIPTS"): options.cfggenScriptPath = os.environ["DESKA_CFGGEN_SCRIPTS"] if not parser.has_option("cfggenGitRepo") and os.environ.has_key("DESKA_CFGGEN_GIT_PRIMARY_CLONE"): options.cfggenGitRepo = os.environ["DESKA_CFGGEN_GIT_PRIMARY_CLONE"] if not parser.has_option("cfggenGitWorkdir") and os.environ.has_key("DESKA_CFGGEN_GIT_WC"): options.cfggenGitWorkdir = os.environ["DESKA_CFGGEN_GIT_WC"] if (options.log_stderr and options.logfile): # basicConfig() won't add duplicate loggers parser.error("Cannot log to both file and stderr -- too lazy") if options.cfggenBackend not in ("error", "fake", "git"): parser.error("Unsupported backend for configuration generators") logformat_pid = "%(levelname)s:%(name)s:%(process)s:%(message)s" if options.logfile: logging.basicConfig(filename = options.logfile, level=logging.DEBUG, format=logformat_pid) elif options.log_stderr: logging.basicConfig(stream = sys.stderr, level=logging.DEBUG, format=logformat_pid) else: logging.basicConfig(stream = sys.stderr, level=logging.CRITICAL, format=logformat_pid) logging.debug("starting deska server") dbargs = {} if options.database: dbargs["database"] = options.database if options.username: dbargs["user"] = options.username # Redirecting the stdout to stderr. This is required in order to support the # GIT_PYTHON_TRACE which blindly uses `print` for its debug output (and # clobbers our precious DBAPI communication that way). # Do NOT ever try to capture stderr this way, this will lead to infinite loops. orig_stdout = sys.stdout sys.stdout = StreamLogger() try: # Make sure that Ctrl-C on the remote side won't ever propagate to us, so that # we don't have to deal with KeyboardInterrupt exception os.setsid() except OSError, e: if e.errno == errno.EPERM: # we're already a session leader -> do nothing pass else: raise
def parse_opts(tmpcmdline, silent=False): myaction=None myopts = {} myfiles=[] global options, shortmapping actions = frozenset([ "clean", "config", "depclean", "help", "info", "list-sets", "metadata", "prune", "regen", "search", "sync", "unmerge", "version", ]) longopt_aliases = {"--cols":"--columns", "--skip-first":"--skipfirst"} argument_options = { "--accept-properties": { "help":"temporarily override ACCEPT_PROPERTIES", "action":"store" }, "--backtrack": { "help" : "Specifies how many times to backtrack if dependency " + \ "calculation fails ", "action" : "store" }, "--config-root": { "help":"specify the location for portage configuration files", "action":"store" }, "--color": { "help":"enable or disable color output", "type":"choice", "choices":("y", "n") }, "--complete-graph": { "help" : "completely account for all known dependencies", "type" : "choice", "choices" : ("True", "n") }, "--deep": { "shortopt" : "-D", "help" : "Specifies how deep to recurse into dependencies " + \ "of packages given as arguments. If no argument is given, " + \ "depth is unlimited. Default behavior is to skip " + \ "dependencies of installed packages.", "action" : "store" }, "--deselect": { "help" : "remove atoms/sets from the world file", "type" : "choice", "choices" : ("True", "n") }, "--exclude": { "help" :"A space separated list of package names or slot atoms. " + \ "Emerge won't install any ebuild or binary package that " + \ "matches any of the given package atoms.", "action" : "append" }, "--fail-clean": { "help" : "clean temp files after build failure", "type" : "choice", "choices" : ("True", "n") }, "--jobs": { "shortopt" : "-j", "help" : "Specifies the number of packages to build " + \ "simultaneously.", "action" : "store" }, "--keep-going": { "help" : "continue as much as possible after an error", "type" : "choice", "choices" : ("True", "n") }, "--load-average": { "help" :"Specifies that no new builds should be started " + \ "if there are other builds running and the load average " + \ "is at least LOAD (a floating-point number).", "action" : "store" }, "--with-bdeps": { "help":"include unnecessary build time dependencies", "type":"choice", "choices":("y", "n") }, "--reinstall": { "help":"specify conditions to trigger package reinstallation", "type":"choice", "choices":["changed-use"] }, "--binpkg-respect-use": { "help" : "discard binary packages if their use flags \ don't match the current configuration", "type" : "choice", "choices" : ("True", "y", "n") }, "--getbinpkg": { "shortopt" : "-g", "help" : "fetch binary packages", "type" : "choice", "choices" : ("True", "n") }, "--getbinpkgonly": { "shortopt" : "-G", "help" : "fetch binary packages only", "type" : "choice", "choices" : ("True", "n") }, "--rebuilt-binaries": { "help" : "replace installed packages with binary " + \ "packages that have been rebuilt", "type" : "choice", "choices" : ("True", "n") }, "--rebuilt-binaries-timestamp": { "help" : "use only binaries that are newer than this " + \ "timestamp for --rebuilt-binaries", "action" : "store" }, "--root": { "help" : "specify the target root filesystem for merging packages", "action" : "store" }, "--root-deps": { "help" : "modify interpretation of depedencies", "type" : "choice", "choices" :("True", "rdeps") }, "--select": { "help" : "add specified packages to the world set " + \ "(inverse of --oneshot)", "type" : "choice", "choices" : ("True", "n") }, "--selective": { "help" : "similar to the --noreplace but does not take " + \ "precedence over options such as --newuse", "type" : "choice", "choices" : ("True", "n") }, "--use-ebuild-visibility": { "help" : "use unbuilt ebuild metadata for visibility checks on built packages", "type" : "choice", "choices" : ("True", "n") }, "--usepkg": { "shortopt" : "-k", "help" : "use binary packages", "type" : "choice", "choices" : ("True", "n") }, "--usepkgonly": { "shortopt" : "-K", "help" : "use only binary packages", "type" : "choice", "choices" : ("True", "n") }, } from optparse import OptionParser parser = OptionParser() if parser.has_option("--help"): parser.remove_option("--help") for action_opt in actions: parser.add_option("--" + action_opt, action="store_true", dest=action_opt.replace("-", "_"), default=False) for myopt in options: parser.add_option(myopt, action="store_true", dest=myopt.lstrip("--").replace("-", "_"), default=False) for shortopt, longopt in shortmapping.items(): parser.add_option("-" + shortopt, action="store_true", dest=longopt.lstrip("--").replace("-", "_"), default=False) for myalias, myopt in longopt_aliases.items(): parser.add_option(myalias, action="store_true", dest=myopt.lstrip("--").replace("-", "_"), default=False) for myopt, kwargs in argument_options.items(): shortopt = kwargs.pop("shortopt", None) args = [myopt] if shortopt is not None: args.append(shortopt) parser.add_option(dest=myopt.lstrip("--").replace("-", "_"), *args, **kwargs) tmpcmdline = insert_optional_args(tmpcmdline) myoptions, myargs = parser.parse_args(args=tmpcmdline) if myoptions.changed_use is not False: myoptions.reinstall = "changed-use" myoptions.changed_use = False if myoptions.deselect == "True": myoptions.deselect = True if myoptions.binpkg_respect_use in ("y", "True",): myoptions.binpkg_respect_use = True else: myoptions.binpkg_respect_use = None if myoptions.complete_graph in ("y", "True",): myoptions.complete_graph = True else: myoptions.complete_graph = None if myoptions.exclude: exclude = [] bad_atoms = [] for x in ' '.join(myoptions.exclude).split(): bad_atom = False try: atom = portage.dep.Atom(x) except portage.exception.InvalidAtom: try: atom = portage.dep.Atom("null/"+x) except portage.exception.InvalidAtom: bad_atom = True if bad_atom: bad_atoms.append(x) else: if atom.operator or atom.blocker or atom.use: bad_atoms.append(x) else: exclude.append(atom) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --exclude parameter: '%s' (only package names and slot atoms allowed)\n" % \ (",".join(bad_atoms),)) if myoptions.fail_clean == "True": myoptions.fail_clean = True if myoptions.getbinpkg in ("True",): myoptions.getbinpkg = True else: myoptions.getbinpkg = None if myoptions.getbinpkgonly in ("True",): myoptions.getbinpkgonly = True else: myoptions.getbinpkgonly = None if myoptions.keep_going in ("True",): myoptions.keep_going = True else: myoptions.keep_going = None if myoptions.rebuilt_binaries in ("True",): myoptions.rebuilt_binaries = True if myoptions.root_deps == "True": myoptions.root_deps = True if myoptions.select == "True": myoptions.select = True myoptions.oneshot = False elif myoptions.select == "n": myoptions.oneshot = True if myoptions.selective == "True": myoptions.selective = True if myoptions.backtrack is not None: try: backtrack = int(myoptions.backtrack) except (OverflowError, ValueError): backtrack = -1 if backtrack < 0: backtrack = None if not silent: parser.error("Invalid --backtrack parameter: '%s'\n" % \ (myoptions.backtrack,)) myoptions.backtrack = backtrack if myoptions.deep is not None: deep = None if myoptions.deep == "True": deep = True else: try: deep = int(myoptions.deep) except (OverflowError, ValueError): deep = -1 if deep is not True and deep < 0: deep = None if not silent: parser.error("Invalid --deep parameter: '%s'\n" % \ (myoptions.deep,)) myoptions.deep = deep if myoptions.jobs: jobs = None if myoptions.jobs == "True": jobs = True else: try: jobs = int(myoptions.jobs) except ValueError: jobs = -1 if jobs is not True and \ jobs < 1: jobs = None if not silent: parser.error("Invalid --jobs parameter: '%s'\n" % \ (myoptions.jobs,)) myoptions.jobs = jobs if myoptions.load_average: try: load_average = float(myoptions.load_average) except ValueError: load_average = 0.0 if load_average <= 0.0: load_average = None if not silent: parser.error("Invalid --load-average parameter: '%s'\n" % \ (myoptions.load_average,)) myoptions.load_average = load_average if myoptions.rebuilt_binaries_timestamp: try: rebuilt_binaries_timestamp = int(myoptions.rebuilt_binaries_timestamp) except ValueError: rebuilt_binaries_timestamp = -1 if rebuilt_binaries_timestamp < 0: rebuilt_binaries_timestamp = 0 if not silent: parser.error("Invalid --rebuilt-binaries-timestamp parameter: '%s'\n" % \ (myoptions.rebuilt_binaries_timestamp,)) myoptions.rebuilt_binaries_timestamp = rebuilt_binaries_timestamp if myoptions.use_ebuild_visibility in ("True",): myoptions.use_ebuild_visibility = True else: myoptions.use_ebuild_visibility = None if myoptions.usepkg in ("True",): myoptions.usepkg = True else: myoptions.usepkg = None if myoptions.usepkgonly in ("True",): myoptions.usepkgonly = True else: myoptions.usepkgonly = None for myopt in options: v = getattr(myoptions, myopt.lstrip("--").replace("-", "_")) if v: myopts[myopt] = True for myopt in argument_options: v = getattr(myoptions, myopt.lstrip("--").replace("-", "_"), None) if v is not None: myopts[myopt] = v if myoptions.searchdesc: myoptions.search = True for action_opt in actions: v = getattr(myoptions, action_opt.replace("-", "_")) if v: if myaction: multiple_actions(myaction, action_opt) sys.exit(1) myaction = action_opt if myaction is None and myoptions.deselect is True: myaction = 'deselect' if myargs and sys.hexversion < 0x3000000 and \ not isinstance(myargs[0], unicode): for i in range(len(myargs)): myargs[i] = portage._unicode_decode(myargs[i]) myfiles += myargs return myaction, myopts, myfiles
def main(): from optparse import OptionParser, OptionValueError parser = OptionParser(usage='usage: %prog [options] [projenv] ...', version='%%prog %s' % VERSION) auths = {} def _auth_callback(option, opt_str, value, parser, cls): info = value.split(',', 3) if len(info) != 3: raise OptionValueError("Incorrect number of parameters for %s" % option) env_name, filename, realm = info if env_name in auths: print >> sys.stderr, 'Ignoring duplicate authentication option ' \ 'for project: %s' % env_name else: auths[env_name] = cls(os.path.abspath(filename), realm) def _validate_callback(option, opt_str, value, parser, valid_values): if value not in valid_values: raise OptionValueError('%s must be one of: %s, not %s' % (opt_str, '|'.join(valid_values), value)) setattr(parser.values, option.dest, value) def _octal(option, opt_str, value, parser): try: setattr(parser.values, option.dest, int(value, 8)) except ValueError: raise OptionValueError('Invalid octal umask value: %r' % value) parser.add_option('-a', '--auth', action='callback', type='string', metavar='DIGESTAUTH', callback=_auth_callback, callback_args=(DigestAuthentication,), help='[projectdir],[htdigest_file],[realm]') parser.add_option('--basic-auth', action='callback', type='string', metavar='BASICAUTH', callback=_auth_callback, callback_args=(BasicAuthentication,), help='[projectdir],[htpasswd_file],[realm]') parser.add_option('-p', '--port', action='store', type='int', dest='port', help='the port number to bind to') parser.add_option('-b', '--hostname', action='store', dest='hostname', help='the host name or IP address to bind to') parser.add_option('--protocol', action='callback', type="string", dest='protocol', callback=_validate_callback, callback_args=(('http', 'scgi', 'ajp', 'fcgi'),), help='http|scgi|ajp|fcgi') parser.add_option('-q', '--unquote', action='store_true', dest='unquote', help='unquote PATH_INFO (may be needed when using ajp)') parser.add_option('--http10', action='store_false', dest='http11', help='use HTTP/1.0 protocol version instead of HTTP/1.1') parser.add_option('--http11', action='store_true', dest='http11', help='use HTTP/1.1 protocol version (default)') parser.add_option('-e', '--env-parent-dir', action='store', dest='env_parent_dir', metavar='PARENTDIR', help='parent directory of the project environments') parser.add_option('--base-path', action='store', type='string', # XXX call this url_base_path? dest='base_path', help='the initial portion of the request URL\'s "path"') parser.add_option('-r', '--auto-reload', action='store_true', dest='autoreload', help='restart automatically when sources are modified') parser.add_option('-s', '--single-env', action='store_true', dest='single_env', help='only serve a single ' 'project without the project list', default=False) if os.name == 'posix': parser.add_option('-d', '--daemonize', action='store_true', dest='daemonize', help='run in the background as a daemon') parser.add_option('--pidfile', action='store', dest='pidfile', help='when daemonizing, file to which to write pid') parser.add_option('--umask', action='callback', type='string', dest='umask', metavar='MASK', callback=_octal, help='when daemonizing, file mode creation mask ' 'to use, in octal notation (default 022)') try: import grp, pwd def _group(option, opt_str, value, parser): try: value = int(value) except ValueError: try: value = grp.getgrnam(value)[2] except KeyError: raise OptionValueError('group not found: %r' % value) setattr(parser.values, option.dest, value) def _user(option, opt_str, value, parser): try: value = int(value) except ValueError: try: value = pwd.getpwnam(value)[2] except KeyError: raise OptionValueError('user not found: %r' % value) setattr(parser.values, option.dest, value) parser.add_option('--group', action='callback', type='string', dest='group', metavar='GROUP', callback=_group, help='the group to run as') parser.add_option('--user', action='callback', type='string', dest='user', metavar='USER', callback=_user, help='the user to run as') except ImportError: pass parser.set_defaults(port=None, hostname='', base_path='', daemonize=False, protocol='http', http11=True, umask=022, user=None, group=None) options, args = parser.parse_args() if not args and not options.env_parent_dir: parser.error('either the --env-parent-dir option or at least one ' 'environment must be specified') if options.single_env: if options.env_parent_dir: parser.error('the --single-env option cannot be used with ' '--env-parent-dir') elif len(args) > 1: parser.error('the --single-env option cannot be used with ' 'more than one enviroment') if options.daemonize and options.autoreload: parser.error('the --auto-reload option cannot be used with ' '--daemonize') if options.port is None: options.port = { 'http': 80, 'scgi': 4000, 'ajp': 8009, 'fcgi': 8000, }[options.protocol] server_address = (options.hostname, options.port) # relative paths don't work when daemonized args = [os.path.abspath(a) for a in args] if options.env_parent_dir: options.env_parent_dir = os.path.abspath(options.env_parent_dir) if parser.has_option('pidfile') and options.pidfile: options.pidfile = os.path.abspath(options.pidfile) wsgi_app = TracEnvironMiddleware(dispatch_request, options.env_parent_dir, args, options.single_env) if auths: if options.single_env: project_name = os.path.basename(args[0]) wsgi_app = AuthenticationMiddleware(wsgi_app, auths, project_name) else: wsgi_app = AuthenticationMiddleware(wsgi_app, auths) base_path = options.base_path.strip('/') if base_path: wsgi_app = BasePathMiddleware(wsgi_app, base_path) if options.protocol == 'http': def serve(): addr, port = server_address if not addr or addr == '0.0.0.0': loc = '0.0.0.0:%s view at http://127.0.0.1:%s/%s' \ % (port, port, base_path) else: loc = 'http://%s:%s/%s' % (addr, port, base_path) try: httpd = TracHTTPServer(server_address, wsgi_app, options.env_parent_dir, args, use_http_11=options.http11) except socket.error, e: print 'Error starting Trac server on %s' % loc print e.strerror sys.exit(1) print 'Server starting in PID %i.' % os.getpid() print 'Serving on %s' % loc if options.http11: print 'Using HTTP/1.1 protocol version' httpd.serve_forever()
def main(): from optparse import OptionParser, OptionValueError parser = OptionParser(usage='usage: %prog [options] [projenv] ...', version='%%prog %s' % VERSION) auths = {} def _auth_callback(option, opt_str, value, parser, cls): info = value.split(',', 3) if len(info) != 3: raise OptionValueError("Incorrect number of parameters for %s" % option) env_name, filename, realm = info if env_name in auths: print >> sys.stderr, 'Ignoring duplicate authentication option ' \ 'for project: %s' % env_name else: auths[env_name] = cls(os.path.abspath(filename), realm) def _validate_callback(option, opt_str, value, parser, valid_values): if value not in valid_values: raise OptionValueError('%s must be one of: %s, not %s' % (opt_str, '|'.join(valid_values), value)) setattr(parser.values, option.dest, value) def _octal(option, opt_str, value, parser): try: setattr(parser.values, option.dest, int(value, 8)) except ValueError: raise OptionValueError('Invalid octal umask value: %r' % value) parser.add_option('-a', '--auth', action='callback', type='string', metavar='DIGESTAUTH', callback=_auth_callback, callback_args=(DigestAuthentication,), help='[projectdir],[htdigest_file],[realm]') parser.add_option('--basic-auth', action='callback', type='string', metavar='BASICAUTH', callback=_auth_callback, callback_args=(BasicAuthentication,), help='[projectdir],[htpasswd_file],[realm]') parser.add_option('-p', '--port', action='store', type='int', dest='port', help='the port number to bind to') parser.add_option('-b', '--hostname', action='store', dest='hostname', help='the host name or IP address to bind to') parser.add_option('--protocol', action='callback', type="string", dest='protocol', callback=_validate_callback, callback_args=(('http', 'scgi', 'ajp', 'fcgi'),), help='http|scgi|ajp|fcgi') parser.add_option('-q', '--unquote', action='store_true', dest='unquote', help='unquote PATH_INFO (may be needed when using ajp)') parser.add_option('--http10', action='store_false', dest='http11', help='use HTTP/1.0 protocol version instead of HTTP/1.1') parser.add_option('--http11', action='store_true', dest='http11', help='use HTTP/1.1 protocol version (default)') parser.add_option('-e', '--env-parent-dir', action='store', dest='env_parent_dir', metavar='PARENTDIR', help='parent directory of the project environments') parser.add_option('--base-path', action='store', type='string', # XXX call this url_base_path? dest='base_path', help='the initial portion of the request URL\'s "path"') parser.add_option('-r', '--auto-reload', action='store_true', dest='autoreload', help='restart automatically when sources are modified') parser.add_option('-s', '--single-env', action='store_true', dest='single_env', help='only serve a single ' 'project without the project list', default=False) if os.name == 'posix': parser.add_option('-d', '--daemonize', action='store_true', dest='daemonize', help='run in the background as a daemon') parser.add_option('--pidfile', action='store', dest='pidfile', help='When daemonizing, file to which to write pid') parser.add_option('--umask', action='callback', type='string', dest='umask', metavar='MASK', callback=_octal, help='When daemonizing, file mode creation mask ' 'to use, in octal notation (default 022)') parser.set_defaults(port=None, hostname='', base_path='', daemonize=False, protocol='http', http11=True, umask=022) options, args = parser.parse_args() if not args and not options.env_parent_dir: parser.error('either the --env-parent-dir option or at least one ' 'environment must be specified') if options.single_env: if options.env_parent_dir: parser.error('the --single-env option cannot be used with ' '--env-parent-dir') elif len(args) > 1: parser.error('the --single-env option cannot be used with ' 'more than one enviroment') if options.daemonize and options.autoreload: parser.error('the --auto-reload option cannot be used with ' '--daemonize') if options.port is None: options.port = { 'http': 80, 'scgi': 4000, 'ajp': 8009, 'fcgi': 8000, }[options.protocol] server_address = (options.hostname, options.port) # relative paths don't work when daemonized args = [os.path.abspath(a) for a in args] if options.env_parent_dir: options.env_parent_dir = os.path.abspath(options.env_parent_dir) if parser.has_option('pidfile') and options.pidfile: options.pidfile = os.path.abspath(options.pidfile) wsgi_app = TracEnvironMiddleware(dispatch_request, options.env_parent_dir, args, options.single_env) if auths: if options.single_env: project_name = os.path.basename(args[0]) wsgi_app = AuthenticationMiddleware(wsgi_app, auths, project_name) else: wsgi_app = AuthenticationMiddleware(wsgi_app, auths) base_path = options.base_path.strip('/') if base_path: wsgi_app = BasePathMiddleware(wsgi_app, base_path) if options.protocol == 'http': def serve(): httpd = TracHTTPServer(server_address, wsgi_app, options.env_parent_dir, args, use_http_11=options.http11) print 'Server starting in PID %i.' % os.getpid() addr, port = server_address if not addr or addr == '0.0.0.0': print 'Serving on 0.0.0.0:%s view at http://127.0.0.1:%s/%s' \ % (port, port, base_path) else: print 'Serving on http://%s:%s/%s' % (addr, port, base_path) if options.http11: print 'Using HTTP/1.1 protocol version' httpd.serve_forever() elif options.protocol in ('scgi', 'ajp', 'fcgi'): def serve(): server_cls = __import__('flup.server.%s' % options.protocol, None, None, ['']).WSGIServer flup_app = wsgi_app if options.unquote: from trac.web.fcgi_frontend import FlupMiddleware flup_app = FlupMiddleware(flup_app) ret = server_cls(flup_app, bindAddress=server_address).run() sys.exit(ret and 42 or 0) # if SIGHUP exit with status 42 try: if options.daemonize: daemon.daemonize(pidfile=options.pidfile, progname='tracd', umask=options.umask) if options.autoreload: def modification_callback(file): print >> sys.stderr, 'Detected modification of %s, ' \ 'restarting.' % file autoreload.main(serve, modification_callback) else: serve() except OSError: sys.exit(1) except KeyboardInterrupt: pass
def main(): usage = "usage: %prog config_file.ini" parser = OptionParser(usage=usage) (cmd_opt, args) = parser.parse_args() if len(args) == 1: config_files = [args[0]] else: config_files = ["download_ta_bdys.ini"] parser = SafeConfigParser() found = parser.read(config_files) if not found: sys.exit("Could not load config " + config_files[0]) # set up logging logging.config.fileConfig(config_files[0], defaults={"hostname": socket.gethostname()}) logger = logging.getLogger() logger.info("Starting download TA boundaries") db_host = None db_rolename = None db_port = None db_user = None db_pass = None db_schema = "public" layer_name = None layer_geom_column = None layer_output_srid = 4167 create_grid = False grid_res = 0.05 shift_geometry = False base_uri = parser.get("source", "base_uri") db_name = parser.get("database", "name") db_schema = parser.get("database", "schema") if parser.has_option("database", "rolename"): db_rolename = parser.get("database", "rolename") if parser.has_option("database", "host"): db_host = parser.get("database", "host") if parser.has_option("database", "port"): db_port = parser.get("database", "port") if parser.has_option("database", "user"): db_user = parser.get("database", "user") if parser.has_option("database", "password"): db_pass = parser.get("database", "password") layer_name = parser.get("layer", "name") layer_geom_column = parser.get("layer", "geom_column") if parser.has_option("layer", "output_srid"): layer_output_srid = parser.getint("layer", "output_srid") if parser.has_option("layer", "create_grid"): create_grid = parser.getboolean("layer", "create_grid") if parser.has_option("layer", "grid_res"): grid_res = parser.getfloat("layer", "grid_res") if parser.has_option("layer", "shift_geometry"): shift_geometry = parser.getboolean("layer", "shift_geometry") try: output_srs = osr.SpatialReference() output_srs.ImportFromEPSG(layer_output_srid) except: logger.fatal("Output SRID %s is not valid" % (layer_output_srid)) sys.exit(1) if create_grid and not grid_res > 0: logger.fatal("Grid resolution must be greater than 0") sys.exit(1) # # Determine TA layer and its year from REST service # logger.debug(base_uri + "?f=json") response = urllib2.urlopen(base_uri + "?f=json") capabilities = json.load(response) latest_service = None latest_year = None p = re.compile("((\d{4})\_Geographies)$", flags=re.UNICODE) for service in capabilities["services"]: m = p.search(service["name"]) if m: if not latest_year or m.group(2) > latest_year: latest_year = int(m.group(2)) latest_service = m.group(1) logger.debug(base_uri + "/" + latest_service + "/MapServer?f=json") response = urllib2.urlopen(base_uri + "/" + latest_service + "/MapServer?f=json") capabilities = json.load(response) ta_layer = None p = re.compile("^Territorial\sAuthorities\s\d{4}$", flags=re.UNICODE) for layer in capabilities["layers"]: m = p.search(layer["name"]) if m: ta_layer = layer break if not ta_layer: logger.fatal("Could not find the TA layer in " + base_uri) sys.exit(1) feature_url = ( base_uri + "/" + latest_service + "/MapServer/" + str(ta_layer["id"]) + "/query?f=json&where=1=1&returnGeometry=true&outSR=" + str(layer_output_srid) ) geojson_drv = ogr.GetDriverByName("GeoJSON") if geojson_drv is None: logger.fatal("Could not load the OGR GeoJSON driver") sys.exit(1) # # Connect to the PostgreSQL database # pg_drv = ogr.GetDriverByName("PostgreSQL") if pg_drv is None: logger.fatal("Could not load the OGR PostgreSQL driver") sys.exit(1) pg_uri = "PG:dbname=" + db_name if db_host: pg_uri = pg_uri + " host=" + db_host if db_port: pg_uri = pg_uri + " port=" + db_port if db_user: pg_uri = pg_uri + " user="******" password="******"Can't open PG output database: " + str(e)) sys.exit(1)
class CommandLineParser: # Defines what --regular means REGULAR_CMD = [ "sslv2", "sslv3", "tlsv1", "tlsv1_1", "tlsv1_2", "tlsv1_3", "reneg", "resum", "certinfo", "http_get", "hide_rejected_ciphers", "compression", "heartbleed", "openssl_ccs", "fallback", "robot", ] SSLYZE_USAGE = "usage: %prog [options] target1.com target2.com:443 target3.com:443{ip} etc..." # StartTLS options START_TLS_PROTOCOLS = [ "smtp", "xmpp", "xmpp_server", "pop3", "ftp", "imap", "ldap", "rdp", "postgres", "auto" ] START_TLS_USAGE = ( "StartTLS should be one of: {}. The 'auto' option will cause SSLyze to deduce the protocol " "(ftp, imap, etc.) from the supplied port number, " "for each target servers.".format(" , ".join(START_TLS_PROTOCOLS))) # Mapping of StartTls protocols and ports; useful for starttls=auto STARTTLS_PROTOCOL_DICT = { "smtp": TlsWrappedProtocolEnum.STARTTLS_SMTP, 587: TlsWrappedProtocolEnum.STARTTLS_SMTP, 25: TlsWrappedProtocolEnum.STARTTLS_SMTP, "xmpp": TlsWrappedProtocolEnum.STARTTLS_XMPP, 5222: TlsWrappedProtocolEnum.STARTTLS_XMPP, "xmpp_server": TlsWrappedProtocolEnum.STARTTLS_XMPP_SERVER, 5269: TlsWrappedProtocolEnum.STARTTLS_XMPP_SERVER, "pop3": TlsWrappedProtocolEnum.STARTTLS_POP3, 109: TlsWrappedProtocolEnum.STARTTLS_POP3, 110: TlsWrappedProtocolEnum.STARTTLS_POP3, "imap": TlsWrappedProtocolEnum.STARTTLS_IMAP, 143: TlsWrappedProtocolEnum.STARTTLS_IMAP, 220: TlsWrappedProtocolEnum.STARTTLS_IMAP, "ftp": TlsWrappedProtocolEnum.STARTTLS_FTP, 21: TlsWrappedProtocolEnum.STARTTLS_FTP, "ldap": TlsWrappedProtocolEnum.STARTTLS_LDAP, 3268: TlsWrappedProtocolEnum.STARTTLS_LDAP, 389: TlsWrappedProtocolEnum.STARTTLS_LDAP, "rdp": TlsWrappedProtocolEnum.STARTTLS_RDP, 3389: TlsWrappedProtocolEnum.STARTTLS_RDP, "postgres": TlsWrappedProtocolEnum.STARTTLS_POSTGRES, 5432: TlsWrappedProtocolEnum.STARTTLS_POSTGRES, } def __init__(self, available_plugins: Set[Type[Plugin]], sslyze_version: str) -> None: """Generate SSLyze's command line parser. """ self._parser = OptionParser(version=sslyze_version, usage=self.SSLYZE_USAGE) # Add generic command line options to the parser self._add_default_options() # Add plugin-specific options to the parser self._add_plugin_options(available_plugins) # Add the --regular command line parameter as a shortcut if possible regular_help = "Regular HTTPS scan; shortcut for --{}".format( " --".join(self.REGULAR_CMD)) self._parser.add_option("--regular", action="store_true", dest=None, help=regular_help) def parse_command_line( self ) -> Tuple[List[ServerConnectivityTester], List[ServerStringParsingError], Any]: """Parses the command line used to launch SSLyze. """ (args_command_list, args_target_list) = self._parser.parse_args() if args_command_list.update_trust_stores: # Just update the trust stores and do nothing TrustStoresRepository.update_default() raise TrustStoresUpdateCompleted() # Handle the --targets_in command line and fill args_target_list if args_command_list.targets_in: if args_target_list: raise CommandLineParsingError( "Cannot use --targets_list and specify targets within the command line." ) try: # Read targets from a file with open(args_command_list.targets_in) as f: for target in f.readlines(): if target.strip(): # Ignore empty lines if not target.startswith( "#"): # Ignore comment lines args_target_list.append(target.strip()) except IOError: raise CommandLineParsingError( "Can't read targets from input file '{}.".format( args_command_list.targets_in)) if not args_target_list: raise CommandLineParsingError("No targets to scan.") # Handle the --regular command line parameter as a shortcut if self._parser.has_option("--regular"): if getattr(args_command_list, "regular"): setattr(args_command_list, "regular", False) for cmd in self.REGULAR_CMD: setattr(args_command_list, cmd, True) # Sanity checks on the command line options # Prevent --quiet and --xml_out - if args_command_list.xml_file and args_command_list.xml_file == "-" and args_command_list.quiet: raise CommandLineParsingError( "Cannot use --quiet with --xml_out -.") # Prevent --quiet and --json_out - if args_command_list.json_file and args_command_list.json_file == "-" and args_command_list.quiet: raise CommandLineParsingError( "Cannot use --quiet with --json_out -.") # Prevent --xml_out - and --json_out - if (args_command_list.json_file and args_command_list.json_file == "-" and args_command_list.xml_file and args_command_list.xml_file == "-"): raise CommandLineParsingError( "Cannot use --xml_out - with --json_out -.") # Sanity checks on the client cert options client_auth_creds = None if bool(args_command_list.cert) ^ bool(args_command_list.key): raise CommandLineParsingError( "No private key or certificate file were given. See --cert and --key." ) elif args_command_list.cert: # Private key formats if args_command_list.keyform == "DER": key_type = OpenSslFileTypeEnum.ASN1 elif args_command_list.keyform == "PEM": key_type = OpenSslFileTypeEnum.PEM else: raise CommandLineParsingError( "--keyform should be DER or PEM.") # Let's try to open the cert and key files try: client_auth_creds = ClientAuthenticationCredentials( args_command_list.cert, args_command_list.key, key_type, args_command_list.keypass) except ValueError as e: raise CommandLineParsingError( "Invalid client authentication settings: {}.".format( e.args[0])) # HTTP CONNECT proxy http_tunneling_settings = None if args_command_list.https_tunnel: try: http_tunneling_settings = HttpConnectTunnelingSettings.from_url( args_command_list.https_tunnel) except ValueError as e: raise CommandLineParsingError( "Invalid proxy URL for --https_tunnel: {}.".format( e.args[0])) # STARTTLS tls_wrapped_protocol = TlsWrappedProtocolEnum.PLAIN_TLS if args_command_list.starttls: if args_command_list.starttls not in self.START_TLS_PROTOCOLS: raise CommandLineParsingError(self.START_TLS_USAGE) else: # StartTLS was specified if args_command_list.starttls in self.STARTTLS_PROTOCOL_DICT.keys( ): # Protocol was given in the command line tls_wrapped_protocol = self.STARTTLS_PROTOCOL_DICT[ args_command_list.starttls] # Create the server connectivity tester for each specified servers # A limitation when using the command line is that only one client_auth_credentials and http_tunneling_settings # can be specified, for all the servers to scan good_server_list = [] bad_server_list = [] for server_string in args_target_list: try: hostname, ip_address, port = CommandLineServerStringParser.parse_server_string( server_string) except ServerStringParsingError as e: # Will happen if the server string is malformed bad_server_list.append(e) continue try: # TODO(AD): Unicode hostnames may fail on Python2 # hostname = hostname.decode('utf-8') server_info = ServerConnectivityTester( hostname=hostname, port=port, ip_address=ip_address, tls_wrapped_protocol=tls_wrapped_protocol, tls_server_name_indication=args_command_list.sni, xmpp_to_hostname=args_command_list.xmpp_to, client_auth_credentials=client_auth_creds, http_tunneling_settings=http_tunneling_settings, ) good_server_list.append(server_info) except ValueError as e: # Will happen for example if xmpp_to is specified for a non-XMPP connection raise CommandLineParsingError(e.args[0]) # Command line hacks # Handle --starttls=auto now that we parsed the server strings if args_command_list.starttls == "auto": for server_info in good_server_list: # We use the port number to deduce the protocol if server_info.port in self.STARTTLS_PROTOCOL_DICT.keys(): server_info.tls_wrapped_protocol = self.STARTTLS_PROTOCOL_DICT[ server_info.port] # Handle --http_get now that we parsed the server strings # Doing it here is hacky as the option is defined within PluginOpenSSLCipherSuites if args_command_list.http_get: for server_info in good_server_list: if server_info.port == 443: server_info.tls_wrapped_protocol = TlsWrappedProtocolEnum.HTTPS return good_server_list, bad_server_list, args_command_list def _add_default_options(self) -> None: """Add default command line options to the parser. """ # Updating the trust stores update_stores_group = OptionGroup(self._parser, "Trust stores options", "") update_stores_group.add_option( "--update_trust_stores", help= "Update the default trust stores used by SSLyze. The latest stores will be downloaded from " "https://github.com/nabla-c0d3/trust_stores_observatory. This option is meant to be used separately, " "and will silence any other command line option supplied to SSLyze.", dest="update_trust_stores", action="store_true", ) self._parser.add_option_group(update_stores_group) # Client certificate options clientcert_group = OptionGroup(self._parser, "Client certificate options", "") clientcert_group.add_option( "--cert", help= "Client certificate chain filename. The certificates must be in PEM format and must be sorted " "starting with the subject's client certificate, followed by intermediate CA certificates if " "applicable.", dest="cert", ) clientcert_group.add_option("--key", help="Client private key filename.", dest="key") clientcert_group.add_option( "--keyform", help="Client private key format. DER or PEM (default).", dest="keyform", default="PEM") clientcert_group.add_option("--pass", help="Client private key passphrase.", dest="keypass", default="") self._parser.add_option_group(clientcert_group) # Input / output output_group = OptionGroup(self._parser, "Input and output options", "") # XML output output_group.add_option( "--xml_out", help= 'Write the scan results as an XML document to the file XML_FILE. If XML_FILE is set to "-", the XML ' "output will instead be printed to stdout. The corresponding XML Schema Definition is available at " "./docs/xml_out.xsd", dest="xml_file", default=None, ) # JSON output output_group.add_option( "--json_out", help= 'Write the scan results as a JSON document to the file JSON_FILE. If JSON_FILE is set to "-", the ' "JSON output will instead be printed to stdout. The resulting JSON file is a serialized version of " "the ScanResult objects described in SSLyze's Python API: the nodes and attributes will be the same. " "See https://nabla-c0d3.github.io/sslyze/documentation/available-scan-commands.html for more details.", dest="json_file", default=None, ) # Read targets from input file output_group.add_option( "--targets_in", help= "Read the list of targets to scan from the file TARGETS_IN. It should contain one host:port per " "line.", dest="targets_in", default=None, ) # No text output output_group.add_option( "--quiet", action="store_true", dest="quiet", help= "Do not output anything to stdout; useful when using --xml_out or --json_out.", ) self._parser.add_option_group(output_group) # Connectivity option group connect_group = OptionGroup(self._parser, "Connectivity options", "") # Connection speed connect_group.add_option( "--slow_connection", help= "Greatly reduce the number of concurrent connections initiated by SSLyze. This will make the scans " "slower but more reliable if the connection between your host and the server is slow, or if the " "server cannot handle many concurrent connections. Enable this option if you are getting a lot of " "timeouts or errors.", action="store_true", dest="slow_connection", ) # HTTP CONNECT Proxy connect_group.add_option( "--https_tunnel", help= "Tunnel all traffic to the target server(s) through an HTTP CONNECT proxy. HTTP_TUNNEL should be the " "proxy's URL: 'http://*****:*****@HOST:PORT/'. For proxies requiring authentication, only Basic " "Authentication is supported.", dest="https_tunnel", default=None, ) # STARTTLS connect_group.add_option( "--starttls", help= "Perform a StartTLS handshake when connecting to the target server(s). " "{}".format(self.START_TLS_USAGE), dest="starttls", default=None, ) connect_group.add_option( "--xmpp_to", help= "Optional setting for STARTTLS XMPP. XMPP_TO should be the hostname to be put in the 'to' " "attribute of the XMPP stream. Default is the server's hostname.", dest="xmpp_to", default=None, ) # Server Name Indication connect_group.add_option( "--sni", help= "Use Server Name Indication to specify the hostname to connect to. Will only affect TLS 1.0+ " "connections.", dest="sni", default=None, ) self._parser.add_option_group(connect_group) def _add_plugin_options(self, available_plugins: Set[Type[Plugin]]) -> None: """Recovers the list of command line options implemented by the available plugins and adds them to the command line parser. """ for plugin_class in available_plugins: # Add the current plugin's commands to the parser group = OptionGroup(self._parser, plugin_class.get_title(), plugin_class.get_description()) for option in plugin_class.get_cli_option_group(): group.add_option(option) self._parser.add_option_group(group)
def buildOptions(parser=None, usage=None): """ Build a list of command-line options we will accept @param parser: optparse parser @type parser: optparse object @param usage: description of how to use the program @type usage: string @return: optparse parser @rtype: optparse object """ # Default option values defaultUsername = os.environ.get("USER", "") defaultPassword = "" defaultLoginTries = 1 defaultLoginTimeout = 10 defaultCommandTimeout = 10 defaultKeyPath = "~/.ssh/id_dsa" defaultConcurrentSessions = 10 defaultSearchPath = [] defaultExistanceTest = "test -f %s" if not usage: usage = "%prog [options] hostname[:port] command" if not parser: from optparse import OptionParser parser = OptionParser(usage=usage, ) parser.add_option( "-u", "--user", dest="username", default=defaultUsername, help="Login username", ) parser.add_option( "-P", "--password", dest="password", default=defaultPassword, help="Login password", ) parser.add_option( "-t", "--loginTries", dest="loginTries", default=defaultLoginTries, type="int", help="Number of times to attempt to login", ) parser.add_option( "-L", "--loginTimeout", dest="loginTimeout", type="float", default=defaultLoginTimeout, help="Timeout period (secs) to find login expect statments", ) parser.add_option( "-T", "--commandTimeout", dest="commandTimeout", type="float", default=defaultCommandTimeout, help="Timeout period (secs) after issuing a command", ) parser.add_option( "-K", "--keyPath", dest="keyPath", default=defaultKeyPath, help="Path to use when looking for SSH keys", ) parser.add_option( "-S", "--concurrentSessions", dest="concurrentSessions", type="int", default=defaultConcurrentSessions, help="Allowable number of concurrent SSH sessions", ) parser.add_option( "-s", "--searchPath", dest="searchPath", default=defaultSearchPath, help="Path to use when looking for commands", ) parser.add_option( "-e", "--existenceTest", dest="existenceTest", default=defaultExistanceTest, help="How to check if a command is available or not", ) if not parser.has_option("-v"): parser.add_option( "-v", "--logseverity", dest="logseverity", default=logging.INFO, type="int", help="Logging severity threshold", ) return parser
class CommandLineParser(): # Defines what --regular means REGULAR_CMD = [ 'sslv2', 'sslv3', 'tlsv1', 'tlsv1_1', 'tlsv1_2', 'reneg', 'resum', 'certinfo', 'http_get', 'hide_rejected_ciphers', 'compression', 'heartbleed' ] SSLYZE_USAGE = 'usage: %prog [options] target1.com target2.com:443 etc...' # StartTLS options START_TLS_PROTS = [ 'smtp', 'xmpp', 'pop3', 'ftp', 'imap', 'ldap', 'rdp', 'postgres', 'auto' ] START_TLS_USAGE = 'STARTTLS should be one of: ' + str(START_TLS_PROTS) + \ '. The \'auto\' option will cause SSLyze to deduce the protocol' + \ ' (ftp, imap, etc.) from the supplied port number, for each target servers.' # Default values DEFAULT_RETRY_ATTEMPTS = 4 DEFAULT_TIMEOUT = 5 def __init__(self, available_plugins, sslyze_version): """ Generates SSLyze's command line parser. """ self._parser = OptionParser(version=sslyze_version, usage=self.SSLYZE_USAGE) # Add generic command line options to the parser self._add_default_options() # Add plugin-specific options to the parser self._add_plugin_options(available_plugins) # Add the --regular command line parameter as a shortcut if possible regular_help = 'Regular HTTPS scan; shortcut for' for cmd in self.REGULAR_CMD: regular_help += ' --' + cmd if cmd == 'certinfo': # gah regular_help += '=basic' if not self._parser.has_option('--' + cmd): return self._parser.add_option('--regular', action="store_true", dest=None, help=regular_help) def parse_command_line(self): """ Parses the command line used to launch SSLyze. """ (args_command_list, args_target_list) = self._parser.parse_args() # Handle the --targets_in command line and fill args_target_list if args_command_list.targets_in: if args_target_list: raise CommandLineParsingError( "Cannot use --targets_list and specify targets within the command line." ) try: # Read targets from a file with open(args_command_list.targets_in) as f: for target in f.readlines(): if target.strip(): # Ignore empty lines if not target.startswith( '#'): # Ignore comment lines args_target_list.append(target.strip()) except IOError: raise CommandLineParsingError( "Can't read targets from input file '%s'." % args_command_list.targets_in) if not args_target_list: raise CommandLineParsingError('No targets to scan.') # Handle the --regular command line parameter as a shortcut if self._parser.has_option('--regular'): if getattr(args_command_list, 'regular'): setattr(args_command_list, 'regular', False) for cmd in self.REGULAR_CMD: if cmd == "certinfo": # Allow user to override certinfo when using --regular if getattr(args_command_list, 'certinfo') is None: setattr(args_command_list, 'certinfo', 'basic') # Special case else: setattr(args_command_list, cmd, True) # Create the shared_settings object from looking at the command line shared_settings = self._process_parsing_results(args_command_list) return args_command_list, args_target_list, shared_settings def _add_default_options(self): """ Adds default command line options to the parser. """ # Client certificate options clientcert_group = OptionGroup(self._parser, 'Client certificate support', '') clientcert_group.add_option('--cert', help='Client certificate filename.', dest='cert') clientcert_group.add_option( '--certform', help='Client certificate format. DER or PEM (default).', dest='certform', default='PEM') clientcert_group.add_option('--key', help='Client private key filename.', dest='key') clientcert_group.add_option( '--keyform', help='Client private key format. DER or PEM (default).', dest='keyform', default='PEM') clientcert_group.add_option('--pass', help='Client private key passphrase.', dest='keypass', default='') self._parser.add_option_group(clientcert_group) # XML output self._parser.add_option( '--xml_out', help= 'Writes the scan results as an XML document to the file XML_FILE.', dest='xml_file', default=None) # Read targets from input file self._parser.add_option( '--targets_in', help= 'Reads the list of targets to scan from the file TARGETS_IN. It should contain one host:port per line.', dest='targets_in', default=None) # Timeout self._parser.add_option( '--timeout', help=('Sets the timeout value in seconds used for every socket ' 'connection made to the target server(s). Default is ' + str(self.DEFAULT_TIMEOUT) + 's.'), type='int', dest='timeout', default=self.DEFAULT_TIMEOUT) # Control connection retry attempts self._parser.add_option( '--nb_retries', help=( 'Sets the number retry attempts for all network connections ' 'initiated throughout the scan. Increase this value if you are ' 'getting a lot of timeout/connection errors when scanning a ' 'specific server. Decrease this value to increase the speed ' 'of the scans; results may however return connection errors. ' 'Default is ' + str(self.DEFAULT_RETRY_ATTEMPTS) + ' connection attempts.'), type='int', dest='nb_retries', default=self.DEFAULT_RETRY_ATTEMPTS) # HTTP CONNECT Proxy self._parser.add_option( '--https_tunnel', help=( 'Tunnels all traffic to the target server(s) through an HTTP ' 'CONNECT proxy. HTTP_TUNNEL should be the proxy\'s URL: ' '\'http://*****:*****@HOST:PORT/\'. For proxies requiring ' 'authentication, only Basic Authentication is supported.'), dest='https_tunnel', default=None) # STARTTLS self._parser.add_option( '--starttls', help=('Performs StartTLS handshakes when connecting to the target ' 'server(s). ' + self.START_TLS_USAGE), dest='starttls', default=None) self._parser.add_option( '--xmpp_to', help= ('Optional setting for STARTTLS XMPP. ' ' XMPP_TO should be the hostname to be put in the \'to\' attribute ' 'of the XMPP stream. Default is the server\'s hostname.'), dest='xmpp_to', default=None) # Server Name Indication self._parser.add_option( '--sni', help= ('Use Server Name Indication to specify the hostname to connect to.' ' Will only affect TLS 1.0+ connections.'), dest='sni', default=None) def _add_plugin_options(self, available_plugins): """ Recovers the list of command line options implemented by the available plugins and adds them to the command line parser. """ for plugin_class in available_plugins: plugin_desc = plugin_class.get_interface() # Add the current plugin's commands to the parser group = OptionGroup(self._parser, plugin_desc.title, plugin_desc.description) for cmd in plugin_desc.get_commands(): group.add_option(cmd) # Add the current plugin's options to the parser for option in plugin_desc.get_options(): group.add_option(option) self._parser.add_option_group(group) def _process_parsing_results(self, args_command_list): """ Performs various sanity checks on the command line that was used to launch SSLyze. Returns the shared_settings object to be fed to plugins. """ shared_settings = {} # Sanity checks on the client cert options if bool(args_command_list.cert) ^ bool(args_command_list.key): raise CommandLineParsingError( 'No private key or certificate file were given. See --cert and --key.' ) # Private key and cert formats if args_command_list.certform == 'DER': args_command_list.certform = SSL_FILETYPE_ASN1 elif args_command_list.certform == 'PEM': args_command_list.certform = SSL_FILETYPE_PEM else: raise CommandLineParsingError('--certform should be DER or PEM.') if args_command_list.keyform == 'DER': args_command_list.keyform = SSL_FILETYPE_ASN1 elif args_command_list.keyform == 'PEM': args_command_list.keyform = SSL_FILETYPE_PEM else: raise CommandLineParsingError('--keyform should be DER or PEM.') # Let's try to open the cert and key files if args_command_list.cert: try: open(args_command_list.cert, "r") except: raise CommandLineParsingError( 'Could not open the client certificate file "' + str(args_command_list.cert) + '".') if args_command_list.key: try: open(args_command_list.key, "r") except: raise CommandLineParsingError( 'Could not open the client private key file "' + str(args_command_list.key) + '"') # Try to load the cert and key in OpenSSL try: sslClient = SslClient() sslClient.use_private_key(args_command_list.cert, args_command_list.certform, args_command_list.key, args_command_list.keyform, args_command_list.keypass) except _nassl.OpenSSLError as e: if 'bad decrypt' in str(e.args): raise CommandLineParsingError( 'Could not decrypt the private key. Wrong passphrase ?' ) raise CommandLineParsingError( 'Could not load the certificate or the private key. Passphrase needed ?' ) # HTTP CONNECT proxy shared_settings['https_tunnel_host'] = None if args_command_list.https_tunnel: # Parse the proxy URL parsedUrl = urlparse(args_command_list.https_tunnel) if not parsedUrl.netloc: raise CommandLineParsingError( 'Invalid Proxy URL for --https_tunnel, discarding all tasks.' ) if parsedUrl.scheme in 'http': defaultPort = 80 elif parsedUrl.scheme in 'https': defaultPort = 443 else: raise CommandLineParsingError( 'Invalid URL scheme for --https_tunnel, discarding all tasks.' ) if not parsedUrl.hostname: raise CommandLineParsingError( 'Invalid Proxy URL for --https_tunnel, discarding all tasks.' ) try: shared_settings[ 'https_tunnel_port'] = parsedUrl.port if parsedUrl.port else defaultPort except ValueError: # The supplied port was not a number raise CommandLineParsingError( 'Invalid Proxy URL for --https_tunnel, discarding all tasks.' ) shared_settings['https_tunnel_host'] = parsedUrl.hostname shared_settings['https_tunnel_user'] = parsedUrl.username shared_settings['https_tunnel_password'] = parsedUrl.password # STARTTLS if args_command_list.starttls: if args_command_list.starttls not in self.START_TLS_PROTS: raise CommandLineParsingError(self.START_TLS_USAGE) if args_command_list.starttls and args_command_list.https_tunnel: raise CommandLineParsingError( 'Cannot have --https_tunnel and --starttls at the same time.') # Number of connection retries if args_command_list.nb_retries < 1: raise CommandLineParsingError( 'Cannot have a number smaller than 1 for --nb_retries.') # All good, let's save the data for key, value in args_command_list.__dict__.iteritems(): shared_settings[key] = value return shared_settings
class CommandLineParser: # Defines what --regular means REGULAR_CMD = [ 'sslv2', 'sslv3', 'tlsv1', 'tlsv1_1', 'tlsv1_2', 'tlsv1_3', 'reneg', 'resum', 'certinfo', 'http_get', 'hide_rejected_ciphers', 'compression', 'heartbleed', 'openssl_ccs', 'fallback', 'robot' ] SSLYZE_USAGE = 'usage: %prog [options] target1.com target2.com:443 target3.com:443{ip} etc...' # StartTLS options START_TLS_PROTOCOLS = [ 'smtp', 'xmpp', 'xmpp_server', 'pop3', 'ftp', 'imap', 'ldap', 'rdp', 'postgres', 'auto' ] START_TLS_USAGE = 'StartTLS should be one of: {}. The \'auto\' option will cause SSLyze to deduce the protocol ' \ '(ftp, imap, etc.) from the supplied port number, ' \ 'for each target servers.'.format(' , '.join(START_TLS_PROTOCOLS)) # Mapping of StartTls protocols and ports; useful for starttls=auto STARTTLS_PROTOCOL_DICT = { 'smtp': TlsWrappedProtocolEnum.STARTTLS_SMTP, 587: TlsWrappedProtocolEnum.STARTTLS_SMTP, 25: TlsWrappedProtocolEnum.STARTTLS_SMTP, 'xmpp': TlsWrappedProtocolEnum.STARTTLS_XMPP, 5222: TlsWrappedProtocolEnum.STARTTLS_XMPP, 'xmpp_server': TlsWrappedProtocolEnum.STARTTLS_XMPP_SERVER, 5269: TlsWrappedProtocolEnum.STARTTLS_XMPP_SERVER, 'pop3': TlsWrappedProtocolEnum.STARTTLS_POP3, 109: TlsWrappedProtocolEnum.STARTTLS_POP3, 110: TlsWrappedProtocolEnum.STARTTLS_POP3, 'imap': TlsWrappedProtocolEnum.STARTTLS_IMAP, 143: TlsWrappedProtocolEnum.STARTTLS_IMAP, 220: TlsWrappedProtocolEnum.STARTTLS_IMAP, 'ftp': TlsWrappedProtocolEnum.STARTTLS_FTP, 21: TlsWrappedProtocolEnum.STARTTLS_FTP, 'ldap': TlsWrappedProtocolEnum.STARTTLS_LDAP, 3268: TlsWrappedProtocolEnum.STARTTLS_LDAP, 389: TlsWrappedProtocolEnum.STARTTLS_LDAP, 'rdp': TlsWrappedProtocolEnum.STARTTLS_RDP, 3389: TlsWrappedProtocolEnum.STARTTLS_RDP, 'postgres': TlsWrappedProtocolEnum.STARTTLS_POSTGRES, 5432: TlsWrappedProtocolEnum.STARTTLS_POSTGRES } def __init__(self, available_plugins: Set[Type[Plugin]], sslyze_version: str) -> None: """Generate SSLyze's command line parser. """ self._parser = OptionParser(version=sslyze_version, usage=self.SSLYZE_USAGE) # Add generic command line options to the parser self._add_default_options() # Add plugin-specific options to the parser self._add_plugin_options(available_plugins) # Add the --regular command line parameter as a shortcut if possible regular_help = 'Regular HTTPS scan; shortcut for --{}'.format(' --'.join(self.REGULAR_CMD)) self._parser.add_option('--regular', action='store_true', dest=None, help=regular_help) def parse_command_line(self) -> Tuple[List[ServerConnectivityTester], List[ServerStringParsingError], Any]: """Parses the command line used to launch SSLyze. """ (args_command_list, args_target_list) = self._parser.parse_args() if args_command_list.update_trust_stores: # Just update the trust stores and do nothing TrustStoresRepository.update_default() raise TrustStoresUpdateCompleted() # Handle the --targets_in command line and fill args_target_list if args_command_list.targets_in: if args_target_list: raise CommandLineParsingError('Cannot use --targets_list and specify targets within the command line.') try: # Read targets from a file with open(args_command_list.targets_in) as f: for target in f.readlines(): if target.strip(): # Ignore empty lines if not target.startswith('#'): # Ignore comment lines args_target_list.append(target.strip()) except IOError: raise CommandLineParsingError('Can\'t read targets from input file \'{}.'.format( args_command_list.targets_in)) if not args_target_list: raise CommandLineParsingError('No targets to scan.') # Handle the --regular command line parameter as a shortcut if self._parser.has_option('--regular'): if getattr(args_command_list, 'regular'): setattr(args_command_list, 'regular', False) for cmd in self.REGULAR_CMD: setattr(args_command_list, cmd, True) # Sanity checks on the command line options # Prevent --quiet and --xml_out - if args_command_list.xml_file and args_command_list.xml_file == '-' and args_command_list.quiet: raise CommandLineParsingError('Cannot use --quiet with --xml_out -.') # Prevent --quiet and --json_out - if args_command_list.json_file and args_command_list.json_file == '-' and args_command_list.quiet: raise CommandLineParsingError('Cannot use --quiet with --json_out -.') # Prevent --xml_out - and --json_out - if args_command_list.json_file and args_command_list.json_file == '-' \ and args_command_list.xml_file and args_command_list.xml_file == '-': raise CommandLineParsingError('Cannot use --xml_out - with --json_out -.') # Sanity checks on the client cert options client_auth_creds = None if bool(args_command_list.cert) ^ bool(args_command_list.key): raise CommandLineParsingError('No private key or certificate file were given. See --cert and --key.') elif args_command_list.cert: # Private key formats if args_command_list.keyform == 'DER': key_type = OpenSslFileTypeEnum.ASN1 elif args_command_list.keyform == 'PEM': key_type = OpenSslFileTypeEnum.PEM else: raise CommandLineParsingError('--keyform should be DER or PEM.') # Let's try to open the cert and key files try: client_auth_creds = ClientAuthenticationCredentials(args_command_list.cert, args_command_list.key, key_type, args_command_list.keypass) except ValueError as e: raise CommandLineParsingError('Invalid client authentication settings: {}.'.format(e.args[0])) # HTTP CONNECT proxy http_tunneling_settings = None if args_command_list.https_tunnel: try: http_tunneling_settings = HttpConnectTunnelingSettings.from_url(args_command_list.https_tunnel) except ValueError as e: raise CommandLineParsingError('Invalid proxy URL for --https_tunnel: {}.'.format(e.args[0])) # STARTTLS tls_wrapped_protocol = TlsWrappedProtocolEnum.PLAIN_TLS if args_command_list.starttls: if args_command_list.starttls not in self.START_TLS_PROTOCOLS: raise CommandLineParsingError(self.START_TLS_USAGE) else: # StartTLS was specified if args_command_list.starttls in self.STARTTLS_PROTOCOL_DICT.keys(): # Protocol was given in the command line tls_wrapped_protocol = self.STARTTLS_PROTOCOL_DICT[args_command_list.starttls] # Create the server connectivity tester for each specified servers # A limitation when using the command line is that only one client_auth_credentials and http_tunneling_settings # can be specified, for all the servers to scan good_server_list = [] bad_server_list = [] for server_string in args_target_list: try: hostname, ip_address, port = CommandLineServerStringParser.parse_server_string(server_string) except ServerStringParsingError as e: # Will happen if the server string is malformed bad_server_list.append(e) continue try: # TODO(AD): Unicode hostnames may fail on Python2 # hostname = hostname.decode('utf-8') server_info = ServerConnectivityTester( hostname=hostname, port=port, ip_address=ip_address, tls_wrapped_protocol=tls_wrapped_protocol, tls_server_name_indication=args_command_list.sni, xmpp_to_hostname=args_command_list.xmpp_to, client_auth_credentials=client_auth_creds, http_tunneling_settings=http_tunneling_settings ) good_server_list.append(server_info) except ValueError as e: # Will happen for example if xmpp_to is specified for a non-XMPP connection raise CommandLineParsingError(e.args[0]) # Command line hacks # Handle --starttls=auto now that we parsed the server strings if args_command_list.starttls == 'auto': for server_info in good_server_list: # We use the port number to deduce the protocol if server_info.port in self.STARTTLS_PROTOCOL_DICT.keys(): server_info.tls_wrapped_protocol = self.STARTTLS_PROTOCOL_DICT[server_info.port] # Handle --http_get now that we parsed the server strings # Doing it here is hacky as the option is defined within PluginOpenSSLCipherSuites if args_command_list.http_get: for server_info in good_server_list: if server_info.port == 443: server_info.tls_wrapped_protocol = TlsWrappedProtocolEnum.HTTPS return good_server_list, bad_server_list, args_command_list def _add_default_options(self) -> None: """Add default command line options to the parser. """ # Updating the trust stores update_stores_group = OptionGroup(self._parser, 'Trust stores options', '') update_stores_group.add_option( '--update_trust_stores', help='Update the default trust stores used by SSLyze. The latest stores will be downloaded from ' 'https://github.com/nabla-c0d3/trust_stores_observatory. This option is meant to be used separately, ' 'and will silence any other command line option supplied to SSLyze.', dest='update_trust_stores', action='store_true', ) self._parser.add_option_group(update_stores_group) # Client certificate options clientcert_group = OptionGroup(self._parser, 'Client certificate options', '') clientcert_group.add_option( '--cert', help='Client certificate chain filename. The certificates must be in PEM format and must be sorted ' 'starting with the subject\'s client certificate, followed by intermediate CA certificates if ' 'applicable.', dest='cert' ) clientcert_group.add_option( '--key', help='Client private key filename.', dest='key' ) clientcert_group.add_option( '--keyform', help='Client private key format. DER or PEM (default).', dest='keyform', default='PEM' ) clientcert_group.add_option( '--pass', help='Client private key passphrase.', dest='keypass', default='' ) self._parser.add_option_group(clientcert_group) # Input / output output_group = OptionGroup(self._parser, 'Input and output options', '') # XML output output_group.add_option( '--xml_out', help='Write the scan results as an XML document to the file XML_FILE. If XML_FILE is set to "-", the XML ' 'output will instead be printed to stdout. The corresponding XML Schema Definition is available at ' './docs/xml_out.xsd', dest='xml_file', default=None ) # JSON output output_group.add_option( '--json_out', help='Write the scan results as a JSON document to the file JSON_FILE. If JSON_FILE is set to "-", the ' 'JSON output will instead be printed to stdout. The resulting JSON file is a serialized version of ' 'the ScanResult objects described in SSLyze\'s Python API: the nodes and attributes will be the same. ' 'See https://nabla-c0d3.github.io/sslyze/documentation/available-scan-commands.html for more details.', dest='json_file', default=None ) # Read targets from input file output_group.add_option( '--targets_in', help='Read the list of targets to scan from the file TARGETS_IN. It should contain one host:port per ' 'line.', dest='targets_in', default=None ) # No text output output_group.add_option( '--quiet', action='store_true', dest='quiet', help='Do not output anything to stdout; useful when using --xml_out or --json_out.' ) self._parser.add_option_group(output_group) # Connectivity option group connect_group = OptionGroup(self._parser, 'Connectivity options', '') # Connection speed connect_group.add_option( '--slow_connection', help='Greatly reduce the number of concurrent connections initiated by SSLyze. This will make the scans ' 'slower but more reliable if the connection between your host and the server is slow, or if the ' 'server cannot handle many concurrent connections. Enable this option if you are getting a lot of ' 'timeouts or errors.', action='store_true', dest='slow_connection', ) # HTTP CONNECT Proxy connect_group.add_option( '--https_tunnel', help='Tunnel all traffic to the target server(s) through an HTTP CONNECT proxy. HTTP_TUNNEL should be the ' 'proxy\'s URL: \'http://*****:*****@HOST:PORT/\'. For proxies requiring authentication, only Basic ' 'Authentication is supported.', dest='https_tunnel', default=None ) # STARTTLS connect_group.add_option( '--starttls', help='Perform a StartTLS handshake when connecting to the target server(s). ' '{}'.format(self.START_TLS_USAGE), dest='starttls', default=None ) connect_group.add_option( '--xmpp_to', help='Optional setting for STARTTLS XMPP. XMPP_TO should be the hostname to be put in the \'to\' ' 'attribute of the XMPP stream. Default is the server\'s hostname.', dest='xmpp_to', default=None ) # Server Name Indication connect_group.add_option( '--sni', help='Use Server Name Indication to specify the hostname to connect to. Will only affect TLS 1.0+ ' 'connections.', dest='sni', default=None ) self._parser.add_option_group(connect_group) def _add_plugin_options(self, available_plugins: Set[Type[Plugin]]) -> None: """Recovers the list of command line options implemented by the available plugins and adds them to the command line parser. """ for plugin_class in available_plugins: # Add the current plugin's commands to the parser group = OptionGroup(self._parser, plugin_class.get_title(), plugin_class.get_description()) for option in plugin_class.get_cli_option_group(): group.add_option(option) self._parser.add_option_group(group)
def buildOptions(parser=None, usage=None): """ Build a list of command-line options we will accept @param parser: optparse parser @type parser: optparse object @param usage: description of how to use the program @type usage: string @return: optparse parser @rtype: optparse object """ #Default option values defaultUsername = os.environ.get('USER', '') defaultPassword = "" defaultLoginTries = 1 defaultLoginTimeout = 10 defaultCommandTimeout = 10 defaultKeyPath = '~/.ssh/id_dsa' defaultConcurrentSessions = 10 defaultSearchPath = [] defaultExistanceTest = 'test -f %s' if not usage: usage = "%prog [options] hostname[:port] command" if not parser: from optparse import OptionParser parser = OptionParser(usage=usage, ) parser.add_option('-u', '--user', dest='username', default=defaultUsername, help='Login username') parser.add_option('-P', '--password', dest='password', default=defaultPassword, help='Login password') parser.add_option('-t', '--loginTries', dest='loginTries', default=defaultLoginTries, type = 'int', help='Number of times to attempt to login') parser.add_option('-L', '--loginTimeout', dest='loginTimeout', type = 'float', default = defaultLoginTimeout, help='Timeout period (secs) to find login expect statments') parser.add_option('-T', '--commandTimeout', dest='commandTimeout', type = 'float', default = defaultCommandTimeout, help='Timeout period (secs) after issuing a command') parser.add_option('-K', '--keyPath', dest='keyPath', default = defaultKeyPath, help='Path to use when looking for SSH keys') parser.add_option('-S', '--concurrentSessions', dest='concurrentSessions', type='int', default = defaultConcurrentSessions, help='Allowable number of concurrent SSH sessions') parser.add_option('-s', '--searchPath', dest='searchPath', default=defaultSearchPath, help='Path to use when looking for commands') parser.add_option('-e', '--existenceTest', dest='existenceTest', default=defaultExistanceTest, help='How to check if a command is available or not') if not parser.has_option('-v'): parser.add_option('-v', '--logseverity', dest='logseverity', default=logging.INFO, type='int', help='Logging severity threshold') return parser
def main(): usage = "usage: %prog config_file.ini" parser = OptionParser(usage=usage) (cmd_opt, args) = parser.parse_args() if len(args) == 1: config_files = [args[0]] else: config_files = ['download_ta_bdys.ini'] parser = SafeConfigParser() found = parser.read(config_files) if not found: sys.exit('Could not load config ' + config_files[0]) # set up logging logging.config.fileConfig(config_files[0], defaults={'hostname': socket.gethostname()}) logger = logging.getLogger() logger.info('Starting download TA boundaries') db_host = None db_rolename = None db_port = None db_user = None db_pass = None db_schema = 'public' layer_name = None layer_geom_column = None layer_output_srid = 4167 create_grid = False grid_res = 0.05 shift_geometry = False base_uri = parser.get('source', 'base_uri') db_name = parser.get('database', 'name') db_schema = parser.get('database', 'schema') if parser.has_option('database', 'rolename'): db_rolename = parser.get('database', 'rolename') if parser.has_option('database', 'host'): db_host = parser.get('database', 'host') if parser.has_option('database', 'port'): db_port = parser.get('database', 'port') if parser.has_option('database', 'user'): db_user = parser.get('database', 'user') if parser.has_option('database', 'password'): db_pass = parser.get('database', 'password') layer_name = parser.get('layer', 'name') layer_geom_column = parser.get('layer', 'geom_column') if parser.has_option('layer', 'output_srid'): layer_output_srid = parser.getint('layer', 'output_srid') if parser.has_option('layer', 'create_grid'): create_grid = parser.getboolean('layer', 'create_grid') if parser.has_option('layer', 'grid_res'): grid_res = parser.getfloat('layer', 'grid_res') if parser.has_option('layer', 'shift_geometry'): shift_geometry = parser.getboolean('layer', 'shift_geometry') try: output_srs = osr.SpatialReference() output_srs.ImportFromEPSG(layer_output_srid) except: logger.fatal("Output SRID %s is not valid" % (layer_output_srid)) sys.exit(1) if create_grid and not grid_res > 0: logger.fatal("Grid resolution must be greater than 0") sys.exit(1) # # Determine TA layer and its year from REST service # logger.debug(base_uri + '?f=json') response = urllib2.urlopen(base_uri + '?f=json') capabilities = json.load(response) latest_service = None latest_year = None p = re.compile('((\d{4})\_Geographies)$', flags=re.UNICODE) for service in capabilities['services']: m = p.search(service['name']) if m: if not latest_year or m.group(2) > latest_year: latest_year = int(m.group(2)) latest_service = m.group(1) logger.debug(base_uri + '/' + latest_service + '/MapServer?f=json') response = urllib2.urlopen(base_uri + '/' + latest_service + '/MapServer?f=json') capabilities = json.load(response) ta_layer = None p = re.compile('^Territorial\sAuthorities\s\d{4}$', flags=re.UNICODE) for layer in capabilities['layers']: m = p.search(layer['name']) if m: ta_layer = layer break if not ta_layer: logger.fatal('Could not find the TA layer in ' + base_uri) sys.exit(1) feature_url = base_uri + '/' + latest_service + '/MapServer/' + str(ta_layer['id']) + \ '/query?f=json&where=1=1&returnGeometry=true&outSR=' + str(layer_output_srid) geojson_drv = ogr.GetDriverByName('GeoJSON') if geojson_drv is None: logger.fatal('Could not load the OGR GeoJSON driver') sys.exit(1) # # Connect to the PostgreSQL database # pg_drv = ogr.GetDriverByName('PostgreSQL') if pg_drv is None: logger.fatal('Could not load the OGR PostgreSQL driver') sys.exit(1) pg_uri = 'PG:dbname=' + db_name if db_host: pg_uri = pg_uri + ' host=' + db_host if db_port: pg_uri = pg_uri + ' port=' + db_port if db_user: pg_uri = pg_uri + ' user='******' password='******'t open PG output database: " + str(e)) sys.exit(1)
class CommandLineParser: # Defines what --regular means REGULAR_CMD = [ "sslv2", "sslv3", "tlsv1", "tlsv1_1", "tlsv1_2", "tlsv1_3", "reneg", "resum", "certinfo", "hide_rejected_ciphers", "compression", "heartbleed", "openssl_ccs", "fallback", "robot", ] SSLYZE_USAGE = "usage: %prog [options] target1.com target2.com:443 target3.com:443{ip} etc..." START_TLS_USAGE = ( "StartTLS should be one of: auto, {}. The 'auto' option will cause SSLyze to deduce the protocol " "(ftp, imap, etc.) from the supplied port number, " "for each target servers.".format(", ".join( _STARTTLS_PROTOCOL_DICT.keys()))) def __init__(self, sslyze_version: str) -> None: """Generate SSLyze's command line parser. """ self._parser = OptionParser(version=sslyze_version, usage=self.SSLYZE_USAGE) # Add generic command line options to the parser self._add_default_options() # Add plugin-specific options to the parser self._add_plugin_scan_commands() # Add the --regular command line parameter as a shortcut if possible regular_help = "Regular HTTPS scan; shortcut for --{}".format( " --".join(self.REGULAR_CMD)) self._parser.add_option("--regular", action="store_true", dest=None, help=regular_help) def parse_command_line(self) -> ParsedCommandLine: """Parses the command line used to launch SSLyze. """ (args_command_list, args_target_list) = self._parser.parse_args() if args_command_list.update_trust_stores: # Just update the trust stores and do nothing TrustStoresRepository.update_default() raise TrustStoresUpdateCompleted() # Handle the --targets_in command line and fill args_target_list if args_command_list.targets_in: if args_target_list: raise CommandLineParsingError( "Cannot use --targets_list and specify targets within the command line." ) try: # Read targets from a file with open(args_command_list.targets_in) as f: for target in f.readlines(): if target.strip(): # Ignore empty lines if not target.startswith( "#"): # Ignore comment lines args_target_list.append(target.strip()) except IOError: raise CommandLineParsingError( "Can't read targets from input file '{}.".format( args_command_list.targets_in)) if not args_target_list: raise CommandLineParsingError("No targets to scan.") # Handle the --regular command line parameter as a shortcut if self._parser.has_option("--regular"): if getattr(args_command_list, "regular"): setattr(args_command_list, "regular", False) for cmd in self.REGULAR_CMD: setattr(args_command_list, cmd, True) # Handle JSON settings should_print_json_to_console = False json_path_out: Optional[Path] = None if args_command_list.json_file: if args_command_list.json_file == "-": if args_command_list.quiet: raise CommandLineParsingError( "Cannot use --quiet with --json_out -.") should_print_json_to_console = True else: json_path_out = Path(args_command_list.json_file).absolute() # Sanity checks on the client cert options client_auth_creds = None if bool(args_command_list.cert) ^ bool(args_command_list.key): raise CommandLineParsingError( "No private key or certificate file were given. See --cert and --key." ) elif args_command_list.cert: # Private key formats if args_command_list.keyform == "DER": key_type = OpenSslFileTypeEnum.ASN1 elif args_command_list.keyform == "PEM": key_type = OpenSslFileTypeEnum.PEM else: raise CommandLineParsingError( "--keyform should be DER or PEM.") # Let's try to open the cert and key files try: client_auth_creds = ClientAuthenticationCredentials( certificate_chain_path=Path(args_command_list.cert), key_path=Path(args_command_list.key), key_password=args_command_list.keypass, key_type=key_type, ) except ValueError as e: raise CommandLineParsingError( "Invalid client authentication settings: {}.".format( e.args[0])) # HTTP CONNECT proxy http_proxy_settings = None if args_command_list.https_tunnel: try: http_proxy_settings = HttpProxySettings.from_url( args_command_list.https_tunnel) except ValueError as e: raise CommandLineParsingError( "Invalid proxy URL for --https_tunnel: {}.".format( e.args[0])) # Create the server location objects for each specified servers good_servers: List[Tuple[ServerNetworkLocation, ServerNetworkConfiguration]] = [] invalid_server_strings: List[InvalidServerStringError] = [] for server_string in args_target_list: try: # Parse the string supplied via the CLI for this server hostname, ip_address, port = CommandLineServerStringParser.parse_server_string( server_string) except InvalidServerStringError as e: # The server string is malformed invalid_server_strings.append(e) continue # If not port number was supplied, assume 443 final_port = port if port else 443 # Figure out how we're going to connect to the server server_location: ServerNetworkLocation if http_proxy_settings: # Connect to the server via an HTTP proxy # A limitation when using the CLI is that only one http_proxy_settings can be specified for all servers server_location = ServerNetworkLocationViaHttpProxy( hostname=hostname, port=final_port, http_proxy_settings=http_proxy_settings) else: # Connect to the server directly if ip_address: server_location = ServerNetworkLocationViaDirectConnection( hostname=hostname, port=final_port, ip_address=ip_address) else: # No IP address supplied - do a DNS lookup try: server_location = ServerNetworkLocationViaDirectConnection.with_ip_address_lookup( hostname=hostname, port=final_port) except ServerHostnameCouldNotBeResolved: invalid_server_strings.append( InvalidServerStringError( server_string=f"{hostname}:{final_port}", error_message= f"Could not resolve hostname {hostname}", )) continue # Figure out extra network config for this server # Opportunistic TLS opportunistic_tls: Optional[ ProtocolWithOpportunisticTlsEnum] = None if args_command_list.starttls: if args_command_list.starttls == "auto": # Special value to auto-derive the protocol from the port number opportunistic_tls = ProtocolWithOpportunisticTlsEnum.from_default_port( final_port) elif args_command_list.starttls in _STARTTLS_PROTOCOL_DICT: opportunistic_tls = _STARTTLS_PROTOCOL_DICT[ args_command_list.starttls] else: raise CommandLineParsingError(self.START_TLS_USAGE) try: sni_hostname = args_command_list.sni if args_command_list.sni else hostname network_config = ServerNetworkConfiguration( tls_opportunistic_encryption=opportunistic_tls, tls_server_name_indication=sni_hostname, tls_client_auth_credentials=client_auth_creds, xmpp_to_hostname=args_command_list.xmpp_to, ) good_servers.append((server_location, network_config)) except InvalidServerNetworkConfigurationError as e: raise CommandLineParsingError(e.args[0]) # Figure out global network settings concurrent_server_scans_limit = None per_server_concurrent_connections_limit = None if args_command_list.https_tunnel: # All the connections will go through a single proxy; only scan one server at a time to not DOS the proxy concurrent_server_scans_limit = 1 if args_command_list.slow_connection: # Go easy on the servers; only open 2 concurrent connections against each server per_server_concurrent_connections_limit = 2 # Figure out the scan commands that are enabled scan_commands: Set[ScanCommandType] = set() scan_commands_extra_arguments: ScanCommandExtraArgumentsDict = {} for scan_command in ScanCommandsRepository.get_all_scan_commands(): cli_connector_cls = ScanCommandsRepository.get_implementation_cls( scan_command).cli_connector_cls is_scan_cmd_enabled, extra_args = cli_connector_cls.find_cli_options_in_command_line( args_command_list.__dict__) if is_scan_cmd_enabled: scan_commands.add(scan_command) if extra_args: scan_commands_extra_arguments[ scan_command] = extra_args # type: ignore return ParsedCommandLine( invalid_servers=invalid_server_strings, servers_to_scans=good_servers, scan_commands=scan_commands, scan_commands_extra_arguments=scan_commands_extra_arguments, should_print_json_to_console=should_print_json_to_console, json_path_out=json_path_out, should_disable_console_output=args_command_list.quiet or args_command_list.json_file == "-", concurrent_server_scans_limit=concurrent_server_scans_limit, per_server_concurrent_connections_limit= per_server_concurrent_connections_limit, ) def _add_default_options(self) -> None: """Add default command line options to the parser. """ # Updating the trust stores update_stores_group = OptionGroup(self._parser, "Trust stores options", "") update_stores_group.add_option( "--update_trust_stores", help= "Update the default trust stores used by SSLyze. The latest stores will be downloaded from " "https://github.com/nabla-c0d3/trust_stores_observatory. This option is meant to be used separately, " "and will silence any other command line option supplied to SSLyze.", dest="update_trust_stores", action="store_true", ) self._parser.add_option_group(update_stores_group) # Client certificate options clientcert_group = OptionGroup(self._parser, "Client certificate options", "") clientcert_group.add_option( "--cert", help= "Client certificate chain filename. The certificates must be in PEM format and must be sorted " "starting with the subject's client certificate, followed by intermediate CA certificates if " "applicable.", dest="cert", ) clientcert_group.add_option("--key", help="Client private key filename.", dest="key") clientcert_group.add_option( "--keyform", help="Client private key format. DER or PEM (default).", dest="keyform", default="PEM") clientcert_group.add_option("--pass", help="Client private key passphrase.", dest="keypass", default="") self._parser.add_option_group(clientcert_group) # Input / output output_group = OptionGroup(self._parser, "Input and output options", "") # JSON output output_group.add_option( "--json_out", help= 'Write the scan results as a JSON document to the file JSON_FILE. If JSON_FILE is set to "-", the ' "JSON output will instead be printed to stdout. The resulting JSON file is a serialized version of " "the ScanResult objects described in SSLyze's Python API: the nodes and attributes will be the same. " "See https://nabla-c0d3.github.io/sslyze/documentation/available-scan-commands.html for more details.", dest="json_file", default=None, ) # Read targets from input file output_group.add_option( "--targets_in", help= "Read the list of targets to scan from the file TARGETS_IN. It should contain one host:port per " "line.", dest="targets_in", default=None, ) # No text output output_group.add_option( "--quiet", action="store_true", dest="quiet", help= "Do not output anything to stdout; useful when using --json_out.", ) self._parser.add_option_group(output_group) # Connectivity option group connect_group = OptionGroup(self._parser, "Connectivity options", "") # Connection speed connect_group.add_option( "--slow_connection", help= "Greatly reduce the number of concurrent connections initiated by SSLyze. This will make the scans " "slower but more reliable if the connection between your host and the server is slow, or if the " "server cannot handle many concurrent connections. Enable this option if you are getting a lot of " "timeouts or errors.", action="store_true", dest="slow_connection", ) # HTTP CONNECT Proxy connect_group.add_option( "--https_tunnel", help= "Tunnel all traffic to the target server(s) through an HTTP CONNECT proxy. HTTP_TUNNEL should be the " "proxy's URL: 'http://*****:*****@HOST:PORT/'. For proxies requiring authentication, only Basic " "Authentication is supported.", dest="https_tunnel", default=None, ) # STARTTLS connect_group.add_option( "--starttls", help= "Perform a StartTLS handshake when connecting to the target server(s). " "{}".format(self.START_TLS_USAGE), dest="starttls", default=None, ) connect_group.add_option( "--xmpp_to", help= "Optional setting for STARTTLS XMPP. XMPP_TO should be the hostname to be put in the 'to' " "attribute of the XMPP stream. Default is the server's hostname.", dest="xmpp_to", default=None, ) # Server Name Indication connect_group.add_option( "--sni", help= "Use Server Name Indication to specify the hostname to connect to. Will only affect TLS 1.0+ " "connections.", dest="sni", default=None, ) self._parser.add_option_group(connect_group) def _add_plugin_scan_commands(self) -> None: """Recovers the list of command line options implemented by the available plugins and adds them to the command line parser. """ scan_commands_group = OptionGroup(self._parser, "Scan commands", "") for scan_command in ScanCommandsRepository.get_all_scan_commands(): cli_connector_cls = ScanCommandsRepository.get_implementation_cls( scan_command).cli_connector_cls for option in cli_connector_cls.get_cli_options(): scan_commands_group.add_option(f"--{option.option}", help=option.help, action=option.action) self._parser.add_option_group(scan_commands_group)
def parse_opts(tmpcmdline, silent=False): myaction=None myopts = {} myfiles=[] actions = frozenset([ "clean", "check-news", "config", "depclean", "help", "info", "list-sets", "metadata", "moo", "prune", "regen", "search", "sync", "unmerge", "version", ]) longopt_aliases = {"--cols":"--columns", "--skip-first":"--skipfirst"} y_or_n = ("y", "n") true_y_or_n = ("True", "y", "n") true_y = ("True", "y") argument_options = { "--ask": { "shortopt" : "-a", "help" : "prompt before performing any actions", "type" : "choice", "choices" : true_y_or_n }, "--autounmask": { "help" : "automatically unmask packages", "type" : "choice", "choices" : true_y_or_n }, "--autounmask-unrestricted-atoms": { "help" : "write autounmask changes with >= atoms if possible", "type" : "choice", "choices" : true_y_or_n }, "--autounmask-keep-masks": { "help" : "don't add package.unmask entries", "type" : "choice", "choices" : true_y_or_n }, "--autounmask-write": { "help" : "write changes made by --autounmask to disk", "type" : "choice", "choices" : true_y_or_n }, "--accept-properties": { "help":"temporarily override ACCEPT_PROPERTIES", "action":"store" }, "--backtrack": { "help" : "Specifies how many times to backtrack if dependency " + \ "calculation fails ", "action" : "store" }, "--buildpkg": { "shortopt" : "-b", "help" : "build binary packages", "type" : "choice", "choices" : true_y_or_n }, "--buildpkg-exclude": { "help" :"A space separated list of package atoms for which " + \ "no binary packages should be built. This option overrides all " + \ "possible ways to enable building of binary packages.", "action" : "append" }, "--config-root": { "help":"specify the location for portage configuration files", "action":"store" }, "--color": { "help":"enable or disable color output", "type":"choice", "choices":("y", "n") }, "--complete-graph": { "help" : "completely account for all known dependencies", "type" : "choice", "choices" : true_y_or_n }, "--complete-graph-if-new-use": { "help" : "trigger --complete-graph behavior if USE or IUSE will change for an installed package", "type" : "choice", "choices" : y_or_n }, "--complete-graph-if-new-ver": { "help" : "trigger --complete-graph behavior if an installed package version will change (upgrade or downgrade)", "type" : "choice", "choices" : y_or_n }, "--deep": { "shortopt" : "-D", "help" : "Specifies how deep to recurse into dependencies " + \ "of packages given as arguments. If no argument is given, " + \ "depth is unlimited. Default behavior is to skip " + \ "dependencies of installed packages.", "action" : "store" }, "--depclean-lib-check": { "help" : "check for consumers of libraries before removing them", "type" : "choice", "choices" : true_y_or_n }, "--deselect": { "help" : "remove atoms/sets from the world file", "type" : "choice", "choices" : true_y_or_n }, "--dynamic-deps": { "help": "substitute the dependencies of installed packages with the dependencies of unbuilt ebuilds", "type": "choice", "choices": y_or_n }, "--exclude": { "help" :"A space separated list of package names or slot atoms. " + \ "Emerge won't install any ebuild or binary package that " + \ "matches any of the given package atoms.", "action" : "append" }, "--fail-clean": { "help" : "clean temp files after build failure", "type" : "choice", "choices" : true_y_or_n }, "--ignore-built-slot-operator-deps": { "help": "Ignore the slot/sub-slot := operator parts of dependencies that have " "been recorded when packages where built. This option is intended " "only for debugging purposes, and it only affects built packages " "that specify slot/sub-slot := operator dependencies using the " "experimental \"4-slot-abi\" EAPI.", "type": "choice", "choices": y_or_n }, "--jobs": { "shortopt" : "-j", "help" : "Specifies the number of packages to build " + \ "simultaneously.", "action" : "store" }, "--keep-going": { "help" : "continue as much as possible after an error", "type" : "choice", "choices" : true_y_or_n }, "--load-average": { "help" :"Specifies that no new builds should be started " + \ "if there are other builds running and the load average " + \ "is at least LOAD (a floating-point number).", "action" : "store" }, "--misspell-suggestions": { "help" : "enable package name misspell suggestions", "type" : "choice", "choices" : ("y", "n") }, "--with-bdeps": { "help":"include unnecessary build time dependencies", "type":"choice", "choices":("y", "n") }, "--reinstall": { "help":"specify conditions to trigger package reinstallation", "type":"choice", "choices":["changed-use"] }, "--reinstall-atoms": { "help" :"A space separated list of package names or slot atoms. " + \ "Emerge will treat matching packages as if they are not " + \ "installed, and reinstall them if necessary. Implies --deep.", "action" : "append", }, "--binpkg-respect-use": { "help" : "discard binary packages if their use flags \ don't match the current configuration", "type" : "choice", "choices" : true_y_or_n }, "--getbinpkg": { "shortopt" : "-g", "help" : "fetch binary packages", "type" : "choice", "choices" : true_y_or_n }, "--getbinpkgonly": { "shortopt" : "-G", "help" : "fetch binary packages only", "type" : "choice", "choices" : true_y_or_n }, "--usepkg-exclude": { "help" :"A space separated list of package names or slot atoms. " + \ "Emerge will ignore matching binary packages. ", "action" : "append", }, "--rebuild-exclude": { "help" :"A space separated list of package names or slot atoms. " + \ "Emerge will not rebuild these packages due to the " + \ "--rebuild flag. ", "action" : "append", }, "--rebuild-ignore": { "help" :"A space separated list of package names or slot atoms. " + \ "Emerge will not rebuild packages that depend on matching " + \ "packages due to the --rebuild flag. ", "action" : "append", }, "--package-moves": { "help" : "perform package moves when necessary", "type" : "choice", "choices" : true_y_or_n }, "--quiet": { "shortopt" : "-q", "help" : "reduced or condensed output", "type" : "choice", "choices" : true_y_or_n }, "--quiet-build": { "help" : "redirect build output to logs", "type" : "choice", "choices" : true_y_or_n, }, "--quiet-fail": { "help" : "suppresses display of the build log on stdout", "type" : "choice", "choices" : true_y_or_n, }, "--rebuild-if-new-slot": { "help" : ("Automatically rebuild or reinstall packages when slot/sub-slot := " "operator dependencies can be satisfied by a newer slot, so that " "older packages slots will become eligible for removal by the " "--depclean action as soon as possible."), "type" : "choice", "choices" : true_y_or_n }, "--rebuild-if-new-rev": { "help" : "Rebuild packages when dependencies that are " + \ "used at both build-time and run-time are built, " + \ "if the dependency is not already installed with the " + \ "same version and revision.", "type" : "choice", "choices" : true_y_or_n }, "--rebuild-if-new-ver": { "help" : "Rebuild packages when dependencies that are " + \ "used at both build-time and run-time are built, " + \ "if the dependency is not already installed with the " + \ "same version. Revision numbers are ignored.", "type" : "choice", "choices" : true_y_or_n }, "--rebuild-if-unbuilt": { "help" : "Rebuild packages when dependencies that are " + \ "used at both build-time and run-time are built.", "type" : "choice", "choices" : true_y_or_n }, "--rebuilt-binaries": { "help" : "replace installed packages with binary " + \ "packages that have been rebuilt", "type" : "choice", "choices" : true_y_or_n }, "--rebuilt-binaries-timestamp": { "help" : "use only binaries that are newer than this " + \ "timestamp for --rebuilt-binaries", "action" : "store" }, "--root": { "help" : "specify the target root filesystem for merging packages", "action" : "store" }, "--root-deps": { "help" : "modify interpretation of depedencies", "type" : "choice", "choices" :("True", "rdeps") }, "--select": { "shortopt" : "-w", "help" : "add specified packages to the world set " + \ "(inverse of --oneshot)", "type" : "choice", "choices" : true_y_or_n }, "--selective": { "help" : "identical to --noreplace", "type" : "choice", "choices" : true_y_or_n }, "--use-ebuild-visibility": { "help" : "use unbuilt ebuild metadata for visibility checks on built packages", "type" : "choice", "choices" : true_y_or_n }, "--useoldpkg-atoms": { "help" :"A space separated list of package names or slot atoms. " + \ "Emerge will prefer matching binary packages over newer unbuilt packages. ", "action" : "append", }, "--usepkg": { "shortopt" : "-k", "help" : "use binary packages", "type" : "choice", "choices" : true_y_or_n }, "--usepkgonly": { "shortopt" : "-K", "help" : "use only binary packages", "type" : "choice", "choices" : true_y_or_n }, "--verbose": { "shortopt" : "-v", "help" : "verbose output", "type" : "choice", "choices" : true_y_or_n }, } from optparse import OptionParser parser = OptionParser() if parser.has_option("--help"): parser.remove_option("--help") for action_opt in actions: parser.add_option("--" + action_opt, action="store_true", dest=action_opt.replace("-", "_"), default=False) for myopt in options: parser.add_option(myopt, action="store_true", dest=myopt.lstrip("--").replace("-", "_"), default=False) for shortopt, longopt in shortmapping.items(): parser.add_option("-" + shortopt, action="store_true", dest=longopt.lstrip("--").replace("-", "_"), default=False) for myalias, myopt in longopt_aliases.items(): parser.add_option(myalias, action="store_true", dest=myopt.lstrip("--").replace("-", "_"), default=False) for myopt, kwargs in argument_options.items(): shortopt = kwargs.pop("shortopt", None) args = [myopt] if shortopt is not None: args.append(shortopt) parser.add_option(dest=myopt.lstrip("--").replace("-", "_"), *args, **kwargs) tmpcmdline = insert_optional_args(tmpcmdline) myoptions, myargs = parser.parse_args(args=tmpcmdline) if myoptions.ask in true_y: myoptions.ask = True else: myoptions.ask = None if myoptions.autounmask in true_y: myoptions.autounmask = True if myoptions.autounmask_unrestricted_atoms in true_y: myoptions.autounmask_unrestricted_atoms = True if myoptions.autounmask_keep_masks in true_y: myoptions.autounmask_keep_masks = True if myoptions.autounmask_write in true_y: myoptions.autounmask_write = True if myoptions.buildpkg in true_y: myoptions.buildpkg = True if myoptions.buildpkg_exclude: bad_atoms = _find_bad_atoms(myoptions.buildpkg_exclude, less_strict=True) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --buildpkg-exclude parameter: '%s'\n" % \ (",".join(bad_atoms),)) if myoptions.changed_use is not False: myoptions.reinstall = "changed-use" myoptions.changed_use = False if myoptions.deselect in true_y: myoptions.deselect = True if myoptions.binpkg_respect_use is not None: if myoptions.binpkg_respect_use in true_y: myoptions.binpkg_respect_use = 'y' else: myoptions.binpkg_respect_use = 'n' if myoptions.complete_graph in true_y: myoptions.complete_graph = True else: myoptions.complete_graph = None if myoptions.depclean_lib_check in true_y: myoptions.depclean_lib_check = True if myoptions.exclude: bad_atoms = _find_bad_atoms(myoptions.exclude) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --exclude parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \ (",".join(bad_atoms),)) if myoptions.reinstall_atoms: bad_atoms = _find_bad_atoms(myoptions.reinstall_atoms) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --reinstall-atoms parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \ (",".join(bad_atoms),)) if myoptions.rebuild_exclude: bad_atoms = _find_bad_atoms(myoptions.rebuild_exclude) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --rebuild-exclude parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \ (",".join(bad_atoms),)) if myoptions.rebuild_ignore: bad_atoms = _find_bad_atoms(myoptions.rebuild_ignore) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --rebuild-ignore parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \ (",".join(bad_atoms),)) if myoptions.usepkg_exclude: bad_atoms = _find_bad_atoms(myoptions.usepkg_exclude) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --usepkg-exclude parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \ (",".join(bad_atoms),)) if myoptions.useoldpkg_atoms: bad_atoms = _find_bad_atoms(myoptions.useoldpkg_atoms) if bad_atoms and not silent: parser.error("Invalid Atom(s) in --useoldpkg-atoms parameter: '%s' (only package names and slot atoms (with wildcards) allowed)\n" % \ (",".join(bad_atoms),)) if myoptions.fail_clean in true_y: myoptions.fail_clean = True if myoptions.getbinpkg in true_y: myoptions.getbinpkg = True else: myoptions.getbinpkg = None if myoptions.getbinpkgonly in true_y: myoptions.getbinpkgonly = True else: myoptions.getbinpkgonly = None if myoptions.keep_going in true_y: myoptions.keep_going = True else: myoptions.keep_going = None if myoptions.package_moves in true_y: myoptions.package_moves = True if myoptions.quiet in true_y: myoptions.quiet = True else: myoptions.quiet = None if myoptions.quiet_build in true_y: myoptions.quiet_build = 'y' if myoptions.quiet_fail in true_y: myoptions.quiet_fail = 'y' if myoptions.rebuild_if_new_slot in true_y: myoptions.rebuild_if_new_slot = 'y' if myoptions.rebuild_if_new_ver in true_y: myoptions.rebuild_if_new_ver = True else: myoptions.rebuild_if_new_ver = None if myoptions.rebuild_if_new_rev in true_y: myoptions.rebuild_if_new_rev = True myoptions.rebuild_if_new_ver = None else: myoptions.rebuild_if_new_rev = None if myoptions.rebuild_if_unbuilt in true_y: myoptions.rebuild_if_unbuilt = True myoptions.rebuild_if_new_rev = None myoptions.rebuild_if_new_ver = None else: myoptions.rebuild_if_unbuilt = None if myoptions.rebuilt_binaries in true_y: myoptions.rebuilt_binaries = True if myoptions.root_deps in true_y: myoptions.root_deps = True if myoptions.select in true_y: myoptions.select = True myoptions.oneshot = False elif myoptions.select == "n": myoptions.oneshot = True if myoptions.selective in true_y: myoptions.selective = True if myoptions.backtrack is not None: try: backtrack = int(myoptions.backtrack) except (OverflowError, ValueError): backtrack = -1 if backtrack < 0: backtrack = None if not silent: parser.error("Invalid --backtrack parameter: '%s'\n" % \ (myoptions.backtrack,)) myoptions.backtrack = backtrack if myoptions.deep is not None: deep = None if myoptions.deep == "True": deep = True else: try: deep = int(myoptions.deep) except (OverflowError, ValueError): deep = -1 if deep is not True and deep < 0: deep = None if not silent: parser.error("Invalid --deep parameter: '%s'\n" % \ (myoptions.deep,)) myoptions.deep = deep if myoptions.jobs: jobs = None if myoptions.jobs == "True": jobs = True else: try: jobs = int(myoptions.jobs) except ValueError: jobs = -1 if jobs is not True and \ jobs < 1: jobs = None if not silent: parser.error("Invalid --jobs parameter: '%s'\n" % \ (myoptions.jobs,)) myoptions.jobs = jobs if myoptions.load_average == "True": myoptions.load_average = None if myoptions.load_average: try: load_average = float(myoptions.load_average) except ValueError: load_average = 0.0 if load_average <= 0.0: load_average = None if not silent: parser.error("Invalid --load-average parameter: '%s'\n" % \ (myoptions.load_average,)) myoptions.load_average = load_average if myoptions.rebuilt_binaries_timestamp: try: rebuilt_binaries_timestamp = int(myoptions.rebuilt_binaries_timestamp) except ValueError: rebuilt_binaries_timestamp = -1 if rebuilt_binaries_timestamp < 0: rebuilt_binaries_timestamp = 0 if not silent: parser.error("Invalid --rebuilt-binaries-timestamp parameter: '%s'\n" % \ (myoptions.rebuilt_binaries_timestamp,)) myoptions.rebuilt_binaries_timestamp = rebuilt_binaries_timestamp if myoptions.use_ebuild_visibility in true_y: myoptions.use_ebuild_visibility = True else: # None or "n" pass if myoptions.usepkg in true_y: myoptions.usepkg = True else: myoptions.usepkg = None if myoptions.usepkgonly in true_y: myoptions.usepkgonly = True else: myoptions.usepkgonly = None if myoptions.verbose in true_y: myoptions.verbose = True else: myoptions.verbose = None for myopt in options: v = getattr(myoptions, myopt.lstrip("--").replace("-", "_")) if v: myopts[myopt] = True for myopt in argument_options: v = getattr(myoptions, myopt.lstrip("--").replace("-", "_"), None) if v is not None: myopts[myopt] = v if myoptions.searchdesc: myoptions.search = True for action_opt in actions: v = getattr(myoptions, action_opt.replace("-", "_")) if v: if myaction: multiple_actions(myaction, action_opt) sys.exit(1) myaction = action_opt if myaction is None and myoptions.deselect is True: myaction = 'deselect' if myargs and isinstance(myargs[0], bytes): for i in range(len(myargs)): myargs[i] = portage._unicode_decode(myargs[i]) myfiles += myargs return myaction, myopts, myfiles
def create_command_line_parser(available_plugins, prog_version, timeout): """ Generates the list of possible command line options by calling the get_commands() method of available plugins. Then, it generates the associated command line parser and returns (parser, available_commands). """ usage = 'usage: %prog [options] target1.com target2.com:443 etc...' parser = OptionParser(version=prog_version, usage=usage) available_commands = {} # TODO: Verbose/Debug # Client certificate options clientcert_group = OptionGroup(parser, 'Client certificate support',\ '') clientcert_group.add_option( '--cert', help='Client certificate filename.', dest='cert') clientcert_group.add_option( '--certform', help= 'Client certificate format. DER or PEM (default).', dest='certform', default='PEM') clientcert_group.add_option( '--key', help= 'Client private key filename.', dest='key') clientcert_group.add_option( '--keyform', help= 'Client private key format. DER or PEM (default).', dest='keyform', default='PEM') clientcert_group.add_option( '--pass', help= 'Client private key passphrase.', dest='keypass') parser.add_option_group(clientcert_group) # XML output parser.add_option( '--xml_file', help= ( 'Output the scan results to an XML file. ' 'XML_FILE should be the name of the file to write to.'), dest='xml_file', default=None) # Timeout parser.add_option( '--timeout', help= ( 'Sets the timeout value in seconds used for every socket ' 'connection made to the target server(s). Default is 5s.'), type='int', dest='timeout', default=timeout) # HTTP CONNECT Proxy parser.add_option( '--https_tunnel', help= ( 'Sets an HTTP CONNECT proxy to tunnel SSL traffic to the target ' 'server(s). HTTP_TUNNEL should be \'host:port\'. ' 'Requires Python 2.7'), dest='https_tunnel', default=None) # STARTTLS parser.add_option( '--starttls', help= ( 'Identifies the target server(s) as a SMTP or an XMPP server(s) ' 'and scans the server(s) using STARTTLS. ' 'STARTTLS should be \'smtp\' or \'xmpp\'.'), dest='starttls', default=None) parser.add_option( '--xmpp_to', help= ( 'Optional setting for STARTTLS XMPP. ' ' XMPP_TO should be the hostname to be put in the \'to\' attribute ' 'of the XMPP stream. Default is the server\'s hostname.'), dest='xmpp_to', default=None) # Add plugin options to the parser for plugin_class in available_plugins: pluginoptiongroup = plugin_class.get_commands() # Get the list of commands implemented by the current plugin plugin_commands = (zip(*pluginoptiongroup.commands))[0] # Keep track of which plugin/module supports which command for command in plugin_commands: available_commands[command] = plugin_class # Add the current plugin's commands to the parser group = OptionGroup(parser, pluginoptiongroup.title,\ pluginoptiongroup.description) for option in pluginoptiongroup.commands: # If dest is something, store it, otherwise just use store_true if option[2] is not None: group.add_option('--' + option[0], action="store", help=option[1], dest=option[2]) else: group.add_option('--' + option[0], action="store_true", help=option[1], dest=option[2]) # Add the current plugin's options to the parser for option in pluginoptiongroup.options: # If dest is something, store it, otherwise just use store_true if option[2] is not None: group.add_option('--' + option[0], action="store", help=option[1], dest=option[2]) else: group.add_option('--' + option[0], action="store_true", help=option[1], dest=option[2]) parser.add_option_group(group) # Add the --regular command line parameter as a shortcut if parser.has_option('--sslv2') and parser.has_option('--sslv3') \ and parser.has_option('--tlsv1') and parser.has_option('--reneg') \ and parser.has_option('--resum') and parser.has_option('--certinfo') \ and parser.has_option('--http_get') \ and parser.has_option('--hide_rejected_ciphers'): parser.add_option( '--regular', action="store_true", help=( 'Regular HTTP scan. Shortcut for --sslv2 --sslv3 --tlsv1 ' '--reneg --resum --certinfo=basic --http_get ' '--hide_rejected_ciphers'), dest=None) return (parser, available_commands)
def tag(self, tag): if tag == OptionParser.has_option(tag): return lambda func: func return unittest.skip("Skip cases ha no tag:{0}".format(tag))
class CommandLineParser(object): # Defines what --regular means REGULAR_CMD = ['sslv2', 'sslv3', 'tlsv1', 'tlsv1_1', 'tlsv1_2', 'reneg', 'resum', 'certinfo_basic', 'http_get', 'hide_rejected_ciphers', 'compression', 'heartbleed', 'openssl_ccs', 'fallback'] SSLYZE_USAGE = 'usage: %prog [options] target1.com target2.com:443 target3.com:443{ip} etc...' # StartTLS options START_TLS_PROTOCOLS = ['smtp', 'xmpp', 'xmpp_server', 'pop3', 'ftp', 'imap', 'ldap', 'rdp', 'postgres', 'auto'] START_TLS_USAGE = 'STARTTLS should be one of: {}. The \'auto\' option will cause SSLyze to deduce the protocol ' \ '(ftp, imap, etc.) from the supplied port number, ' \ 'for each target servers.'.format(' , '.join(START_TLS_PROTOCOLS)) # Mapping of StartTls protocols and ports; useful for starttls=auto STARTTLS_PROTOCOL_DICT = {'smtp': TlsWrappedProtocolEnum.STARTTLS_SMTP, 587: TlsWrappedProtocolEnum.STARTTLS_SMTP, 25: TlsWrappedProtocolEnum.STARTTLS_SMTP, 'xmpp': TlsWrappedProtocolEnum.STARTTLS_XMPP, 5222 : TlsWrappedProtocolEnum.STARTTLS_XMPP, 'xmpp_server': TlsWrappedProtocolEnum.STARTTLS_XMPP_SERVER, 5269: TlsWrappedProtocolEnum.STARTTLS_XMPP_SERVER, 'pop3': TlsWrappedProtocolEnum.STARTTLS_POP3, 109: TlsWrappedProtocolEnum.STARTTLS_POP3, 110: TlsWrappedProtocolEnum.STARTTLS_POP3, 'imap': TlsWrappedProtocolEnum.STARTTLS_IMAP, 143: TlsWrappedProtocolEnum.STARTTLS_IMAP, 220: TlsWrappedProtocolEnum.STARTTLS_IMAP, 'ftp': TlsWrappedProtocolEnum.STARTTLS_FTP, 21: TlsWrappedProtocolEnum.STARTTLS_FTP, 'ldap': TlsWrappedProtocolEnum.STARTTLS_LDAP, 3268: TlsWrappedProtocolEnum.STARTTLS_LDAP, 389: TlsWrappedProtocolEnum.STARTTLS_LDAP, 'rdp': TlsWrappedProtocolEnum.STARTTLS_RDP, 3389: TlsWrappedProtocolEnum.STARTTLS_RDP, 'postgres': TlsWrappedProtocolEnum.STARTTLS_POSTGRES, 5432: TlsWrappedProtocolEnum.STARTTLS_POSTGRES} # Default values DEFAULT_RETRY_ATTEMPTS = 4 DEFAULT_TIMEOUT = 5 def __init__(self, available_plugins, sslyze_version): """Generates SSLyze's command line parser. """ self._parser = OptionParser(version=sslyze_version, usage=self.SSLYZE_USAGE) # Add generic command line options to the parser self._add_default_options() # Add plugin-specific options to the parser self._add_plugin_options(available_plugins) # Add the --regular command line parameter as a shortcut if possible regular_help = 'Regular HTTPS scan; shortcut for --{}'.format(' --'.join(self.REGULAR_CMD)) self._parser.add_option('--regular', action="store_true", dest=None, help=regular_help) def parse_command_line(self): """Parses the command line used to launch SSLyze. """ (args_command_list, args_target_list) = self._parser.parse_args() # Handle the --targets_in command line and fill args_target_list if args_command_list.targets_in: if args_target_list: raise CommandLineParsingError("Cannot use --targets_list and specify targets within the command line.") try: # Read targets from a file with open(args_command_list.targets_in) as f: for target in f.readlines(): if target.strip(): # Ignore empty lines if not target.startswith('#'): # Ignore comment lines args_target_list.append(target.strip()) except IOError: raise CommandLineParsingError("Can't read targets from input file '{}.".format( args_command_list.targets_in)) if not args_target_list: raise CommandLineParsingError('No targets to scan.') # Handle the --regular command line parameter as a shortcut if self._parser.has_option('--regular'): if getattr(args_command_list, 'regular'): setattr(args_command_list, 'regular', False) for cmd in self.REGULAR_CMD: setattr(args_command_list, cmd, True) # Sanity checks on the command line options # Prevent --quiet and --xml_out - if args_command_list.xml_file and args_command_list.xml_file == '-' and args_command_list.quiet: raise CommandLineParsingError('Cannot use --quiet with --xml_out -.') # Prevent --quiet and --json_out - if args_command_list.json_file and args_command_list.json_file == '-' and args_command_list.quiet: raise CommandLineParsingError('Cannot use --quiet with --json_out -.') # Prevent --xml_out - and --json_out - if args_command_list.json_file and args_command_list.json_file == '-'\ and args_command_list.xml_file and args_command_list.xml_file == '-'.quiet: raise CommandLineParsingError('Cannot use --xml_out - with --json_out -.') # Sanity checks on the client cert options client_auth_creds = None if bool(args_command_list.cert) ^ bool(args_command_list.key): raise CommandLineParsingError('No private key or certificate file were given. See --cert and --key.') elif args_command_list.cert: # Private key formats if args_command_list.keyform == 'DER': key_type = SSL_FILETYPE_ASN1 elif args_command_list.keyform == 'PEM': key_type = SSL_FILETYPE_PEM else: raise CommandLineParsingError('--keyform should be DER or PEM.') # Let's try to open the cert and key files try: client_auth_creds = ClientAuthenticationCredentials(args_command_list.cert, args_command_list.key, key_type, args_command_list.keypass) except ValueError as e: raise CommandLineParsingError('Invalid client authentication settings: {}.'.format(e[0])) # HTTP CONNECT proxy http_tunneling_settings = None if args_command_list.https_tunnel: try: http_tunneling_settings = HttpConnectTunnelingSettings.from_url(args_command_list.https_tunnel) except ValueError as e: raise CommandLineParsingError('Invalid proxy URL for --https_tunnel: {}.'.format(e[0])) # STARTTLS tls_wrapped_protocol = TlsWrappedProtocolEnum.PLAIN_TLS if args_command_list.starttls: if args_command_list.starttls not in self.START_TLS_PROTOCOLS: raise CommandLineParsingError(self.START_TLS_USAGE) else: # StartTLS was specified if args_command_list.starttls in self.STARTTLS_PROTOCOL_DICT.keys(): # Protocol was given in the command line tls_wrapped_protocol = self.STARTTLS_PROTOCOL_DICT[args_command_list.starttls] # Number of connection retries if args_command_list.nb_retries < 1: raise CommandLineParsingError('Cannot have a number smaller than 1 for --nb_retries.') # Create the server connectivity info for each specifed servers # A limitation when using the command line is that only one client_auth_credentials and http_tunneling_settings # can be specified, for all the servers to scan good_server_list = [] bad_server_list = [] for server_string in args_target_list: try: good_server_list.append(ServerConnectivityInfo.from_command_line( server_string=server_string, tls_wrapped_protocol=tls_wrapped_protocol, tls_server_name_indication=args_command_list.sni, xmpp_to_hostname=args_command_list.xmpp_to, client_auth_credentials=client_auth_creds, http_tunneling_settings=http_tunneling_settings) ) except ServerConnectivityError as e: # Will happen for example if the DNS lookup failed or the server string is malformed bad_server_list.append((server_string, e)) except ValueError as e: # Will happen for example if xmpp_to is specified for a non-XMPP connection raise CommandLineParsingError(e[0]) # Command line hacks # Handle --starttls=auto now that we parsed the server strings if args_command_list.starttls == 'auto': for server_info in good_server_list: # We use the port number to deduce the protocol if server_info.port in self.STARTTLS_PROTOCOL_DICT.keys(): server_info.tls_wrapped_protocol = self.STARTTLS_PROTOCOL_DICT[server_info.port] # Handle --http_get now that we parsed the server strings # Doing it here is hacky as the option is defined within PluginOpenSSLCipherSuites if args_command_list.http_get: for server_info in good_server_list: if server_info.port == 443: server_info.tls_wrapped_protocol = TlsWrappedProtocolEnum.HTTPS return good_server_list, bad_server_list, args_command_list def _add_default_options(self): """ Adds default command line options to the parser. """ # Client certificate options clientcert_group = OptionGroup(self._parser, 'Client certificate support', '') clientcert_group.add_option( '--cert', help='Client certificate chain filename. The certificates must be in PEM format and must be sorted ' 'starting with the subject\'s client certificate, followed by intermediate CA certificates if ' 'applicable.', dest='cert' ) clientcert_group.add_option( '--key', help= 'Client private key filename.', dest='key' ) clientcert_group.add_option( '--keyform', help= 'Client private key format. DER or PEM (default).', dest='keyform', default='PEM' ) clientcert_group.add_option( '--pass', help= 'Client private key passphrase.', dest='keypass', default='' ) self._parser.add_option_group(clientcert_group) # XML output self._parser.add_option( '--xml_out', help='Writes the scan results as an XML document to the file XML_FILE. If XML_FILE is set to "-", the XML ' 'output will instead be printed to stdout.', dest='xml_file', default=None ) # JSON output self._parser.add_option( '--json_out', help='Writes the scan results as a JSON document to the file JSON_FILE. If JSON_FILE is set to "-", the ' 'JSON output will instead be printed to stdout.', dest='json_file', default=None ) # Read targets from input file self._parser.add_option( '--targets_in', help='Reads the list of targets to scan from the file TARGETS_IN. It should contain one host:port per ' 'line.', dest='targets_in', default=None ) # Timeout self._parser.add_option( '--timeout', help='Sets the timeout value in seconds used for every socket connection made to the target server(s). ' 'Default is {}s.'.format(str(self.DEFAULT_TIMEOUT)), type='int', dest='timeout', default=self.DEFAULT_TIMEOUT ) # Control connection retry attempts self._parser.add_option( '--nb_retries', help='Sets the number retry attempts for all network connections initiated throughout the scan. Increase ' 'this value if you are getting a lot of timeout/connection errors when scanning a specific server. ' 'Decrease this value to increase the speed of the scans; results may however return connection errors.' ' Default is {} connection attempts.'.format(str(self.DEFAULT_RETRY_ATTEMPTS)), type='int', dest='nb_retries', default=self.DEFAULT_RETRY_ATTEMPTS ) # HTTP CONNECT Proxy self._parser.add_option( '--https_tunnel', help='Tunnels all traffic to the target server(s) through an HTTP CONNECT proxy. HTTP_TUNNEL should be the ' 'proxy\'s URL: \'http://*****:*****@HOST:PORT/\'. For proxies requiring authentication, only Basic ' 'Authentication is supported.', dest='https_tunnel', default=None ) # STARTTLS self._parser.add_option( '--starttls', help='Performs StartTLS handshakes when connecting to the target server(s). ' + self.START_TLS_USAGE, dest='starttls', default=None ) self._parser.add_option( '--xmpp_to', help='Optional setting for STARTTLS XMPP. XMPP_TO should be the hostname to be put in the \'to\' attribute ' 'of the XMPP stream. Default is the server\'s hostname.', dest='xmpp_to', default=None ) # Server Name Indication self._parser.add_option( '--sni', help='Use Server Name Indication to specify the hostname to connect to. Will only affect TLS 1.0+ ' 'connections.', dest='sni', default=None ) # No text output self._parser.add_option( '--quiet', action="store_true", dest='quiet', help='Do not output anything to stdout; useful when using --xml_out or --json_out.' ) def _add_plugin_options(self, available_plugins): """Recovers the list of command line options implemented by the available plugins and adds them to the command line parser. """ for plugin_class in available_plugins: plugin_desc = plugin_class.get_interface() # Add the current plugin's commands to the parser group = OptionGroup(self._parser, plugin_desc.title, plugin_desc.description) for cmd in plugin_desc.get_commands(): group.add_option(cmd) # Add the current plugin's options to the parser for option in plugin_desc.get_options(): group.add_option(option) self._parser.add_option_group(group)
class CommandBase(object): def __init__(self): self.parser = OptionParser() cfg = config.ClientConfig() self.cfg = cfg self.parser.add_option("-v", "--verbose", dest="verbose", action="store_true", help="show debug infomation.", default=cfg.verbose) self.parser.add_option("-H", "--host", help="server host, default is %s" % cfg.server_host, default=cfg.server_host, metavar="HOST") self.parser.add_option("-p", "--port", help="server port, default is %d" % cfg.server_port, default=cfg.server_port, type="int", metavar="PORT") self.parser.add_option("-U", "--username", help="login user name", type="str", metavar="USERNAME") self.parser.add_option("-P", "--password", help="login password", type="str", metavar="PASSWORD") _parser = self.getOptionParser() self.parser.usage = _parser.usage.rstrip() for option in _parser.option_list: if not self.parser.has_option(option.get_opt_string()): self.parser.add_option(option) def login(self, options): user_name, password = self._getLoginInfo(options) client = YumtoolsClient() if client.connect(options.host, options.port): io.debug( "upload", "yum server %s:%d connected." % (self.cfg.server_host, self.cfg.server_port)) else: io.error( "upload", "server %s:%d connect error." % (self.cfg.server_host, self.cfg.server_port)) return False, None if not client.login(user_name, password): io.error('upload', 'auth failed') return False, None else: return True, client def execute(self, args): options, args = self.parser.parse_args(args) if options.verbose: io.use_debug = True return self.run(options, args) def getOptionParser(self): raise NotImplementedError def run(self, options, args): raise NotImplementedError def showHelp(self): self.parser.print_help() def _getLoginInfo(self, options): user_name = options.username password = options.password if not user_name: user_name = io.get("username: "******"password: ") return user_name, password
def main(startstring): if not gottrac: rlog(100, 'tracserver', 'trac is not installed') return global httpd from optparse import OptionParser, OptionValueError parser = OptionParser(usage='usage: %prog [options] [projenv] ...', version='%%prog %s' % VERSION) auths = {} def _auth_callback(option, opt_str, value, parser, cls): info = value.split(',', 3) if len(info) != 3: raise OptionValueError("Incorrect number of parameters for %s" % option) env_name, filename, realm = info auths[env_name] = cls(os.path.abspath(filename), realm) def _validate_callback(option, opt_str, value, parser, valid_values): if value not in valid_values: raise OptionValueError('%s must be one of: %s, not %s' % (opt_str, '|'.join(valid_values), value)) setattr(parser.values, option.dest, value) parser.add_option('-a', '--auth', action='callback', type='string', metavar='DIGESTAUTH', callback=_auth_callback, callback_args=(DigestAuthentication,), help='[projectdir],[htdigest_file],[realm]') parser.add_option('--basic-auth', action='callback', type='string', metavar='BASICAUTH', callback=_auth_callback, callback_args=(BasicAuthentication,), help='[projectdir],[htpasswd_file],[realm]') parser.add_option('-p', '--port', action='store', type='int', dest='port', help='the port number to bind to') parser.add_option('-b', '--hostname', action='store', dest='hostname', help='the host name or IP address to bind to') parser.add_option('--protocol', action='callback', type="string", dest='protocol', callback=_validate_callback, callback_args=(('http', 'scgi', 'ajp', 'fcgi'),), help='http|scgi|ajp|fcgi') parser.add_option('-e', '--env-parent-dir', action='store', dest='env_parent_dir', metavar='PARENTDIR', help='parent directory of the project environments') parser.add_option('--base-path', action='store', type='string', # XXX call this url_base_path? dest='base_path', help='the initial portion of the request URL\'s "path"') parser.add_option('-r', '--auto-reload', action='store_true', dest='autoreload', help='restart automatically when sources are modified') parser.add_option('-s', '--single-env', action='store_true', dest='single_env', help='only serve a single ' 'project without the project list', default=False) if os.name == 'posix': parser.add_option('-d', '--daemonize', action='store_true', dest='daemonize', help='run in the background as a daemon') parser.add_option('--pidfile', action='store', dest='pidfile', help='When daemonizing, file to which to write pid') parser.add_option('--umask', action='store', type='int', dest='umask', metavar='MASK', help='When daemonizing, file mode creation mask ' 'to use (default 022)') parser.set_defaults(port=None, hostname='', base_path='', daemonize=False, protocol='http', umask=022) options, args = parser.parse_args(startstring.split()) if not args and not options.env_parent_dir: parser.error('either the --env-parent-dir option or at least one ' 'environment must be specified') if options.single_env: if options.env_parent_dir: parser.error('the --single-env option cannot be used with ' '--env-parent-dir') elif len(args) > 1: parser.error('the --single-env option cannot be used with ' 'more than one enviroment') if options.daemonize and options.autoreload: parser.error('the --auto-reload option cannot be used with ' '--daemonize') if options.port is None: options.port = { 'http': 80, 'scgi': 4000, 'ajp': 8009, 'fcgi': 8000, }[options.protocol] server_address = (options.hostname, options.port) # relative paths don't work when daemonized args = [os.path.abspath(a) for a in args] if options.env_parent_dir: options.env_parent_dir = os.path.abspath(options.env_parent_dir) if parser.has_option('pidfile') and options.pidfile: options.pidfile = os.path.abspath(options.pidfile) wsgi_app = TracEnvironMiddleware(dispatch_request, options.env_parent_dir, args, options.single_env) if auths: if options.single_env: project_name = os.path.basename(args[0]) wsgi_app = AuthenticationMiddleware(wsgi_app, auths, project_name) else: wsgi_app = AuthenticationMiddleware(wsgi_app, auths) base_path = options.base_path.strip('/') if base_path: wsgi_app = BasePathMiddleware(wsgi_app, base_path) try: httpd = TracHTTPServer(server_address, wsgi_app, options.env_parent_dir, args) except socket.error, ex: if 'already in use' in str(ex): rlog(10, 'tserver', 'server is already running') return
class CommandLineParser(): # Defines what --regular means REGULAR_CMD = ['sslv3', 'tlsv1', 'reneg', 'resum', 'certinfo', 'http_get', 'hide_rejected_ciphers', 'compression', 'tlsv1_1', 'tlsv1_2'] SSLYZE_USAGE = 'usage: %prog [options] target1.com target2.com:443 etc...' def __init__(self, available_plugins, sslyze_version, timeout): """ Generates SSLyze's command line parser. """ self._parser = OptionParser(version=sslyze_version, usage=self.SSLYZE_USAGE) # Add generic command line options to the parser self._add_default_options(timeout) # Add plugin-specific options to the parser self._add_plugin_options(available_plugins) # Add the --regular command line parameter as a shortcut if possible regular_help = 'Regular HTTPS scan; shortcut for' for cmd in self.REGULAR_CMD: regular_help += ' --' + cmd if (self._parser.has_option('--' + cmd) == False): return self._parser.add_option('--regular', action="store_true", dest=None, help=regular_help) def parse_command_line(self): """ Parses the command line used to launch SSLyze. """ (args_command_list, args_target_list) = self._parser.parse_args() # Handle the --targets_in command line and fill args_target_list if args_command_list.targets_in: if args_target_list: raise CommandLineParsingError("Cannot use --targets_list and specify targets within the command line.") try: # Read targets from a file with open(args_command_list.targets_in) as f: for target in f.readlines(): if target.strip(): # Ignore empty lines if not target.startswith('#'): # Ignore comment lines args_target_list.append(target.strip()) except IOError, e: raise CommandLineParsingError("Can't read targets from input file '%s'." % args_command_list.targets_in) if args_target_list == []: raise CommandLineParsingError('No targets to scan.') # Handle the --regular command line parameter as a shortcut if self._parser.has_option('--regular'): if getattr(args_command_list, 'regular'): setattr(args_command_list, 'regular', False) for cmd in self.REGULAR_CMD: setattr(args_command_list, cmd, True) setattr(args_command_list, 'certinfo', 'basic') # Special case # Create the shared_settings object from looking at the command line shared_settings = self._process_parsing_results(args_command_list) return (args_command_list, args_target_list, shared_settings)
class CommandBase(object): def __init__(self): self.parser = OptionParser() cfg = config.ClientConfig() self.cfg = cfg self.parser.add_option("-v", "--verbose", dest="verbose", action="store_true", help="show debug infomation.", default=cfg.verbose) self.parser.add_option("-H", "--host", help="server host, default is %s" % cfg.server_host, default=cfg.server_host, metavar="HOST") self.parser.add_option("-p", "--port", help="server port, default is %d" % cfg.server_port, default=cfg.server_port, type="int", metavar="PORT") self.parser.add_option("-U", "--username", help="login user name", type="str", metavar="USERNAME") self.parser.add_option("-P", "--password", help="login password", type="str", metavar="PASSWORD") _parser = self.getOptionParser() self.parser.usage = _parser.usage.rstrip() for option in _parser.option_list: if not self.parser.has_option(option.get_opt_string()): self.parser.add_option(option) def login(self, options): user_name, password = self._getLoginInfo(options) client = YumtoolsClient() if client.connect(options.host, options.port): io.debug("upload", "yum server %s:%d connected." % (self.cfg.server_host, self.cfg.server_port)) else: io.error("upload", "server %s:%d connect error." % (self.cfg.server_host, self.cfg.server_port)) return False, None if not client.login(user_name, password): io.error('upload', 'auth failed') return False, None else: return True, client def execute(self, args): options, args = self.parser.parse_args(args) if options.verbose: io.use_debug = True return self.run(options, args) def getOptionParser(self): raise NotImplementedError def run(self, options, args): raise NotImplementedError def showHelp(self): self.parser.print_help() def _getLoginInfo(self, options): user_name = options.username password = options.password if not user_name: user_name = io.get("username: "******"password: ") return user_name, password
def main(): # All instances we currently have. # Keys are the full name of the instance, # values are the shorthand "slug" used in usernames. all_instances = {'uio': 'uio', 'uia': 'uia', 'ofk': 'ofk', 'hiof': 'hiof', 'nmh': 'nmh', 'hih': 'hih', 'nih': 'nih', 'giske': 'gisk', 'hine': 'hine', 'webid': 'wid'} usage = "usage: %prog [options] instances" parser = OptionParser(usage) parser.add_option("-a", "--all-instances", dest="instances", action="store_const", const=all_instances, help="Shorthand for deploying on all instances") parser.add_option("--no-setup", action="store_false", dest="setup", default=True, help="Do not run setup.py") parser.add_option("-b", "--restart-bofhd", action="store_true", help="Restart bofhd") parser.add_option("-j", "--restart-job_runner", action="store_true", help="Restart job_runner. Note: Runs --quit directly, " "does not wait for jobs to finish.") parser.add_option("-s", "--reload-scheduled_jobs", action="store_true", help="Make job_runner reload new scheduled_jobs.") parser.add_option("-n", "--restart-individuation", action="store_true", help="Restart Individuation") parser.add_option("-r", "--restart-all", action="store_true", help="Restart bofhd, job_runner and Individuation") parser.add_option( "--only-insert-codes", dest="makedb", action="store_const", const="--only-insert-codes", help="makedb.py: Make sure all " "code values for the current configuration of " "cereconf.CLASS_CONSTANTS have been inserted into the " "database. Does not create tables. This is the default.") parser.add_option("--update-codes", dest="makedb", action="store_const", const="--update-codes", default="--only-insert-codes", help="makedb.py: Like --only-insert-codes, but will remove" " constants that exists in the database, but not in " "CLASS_CONSTANTS (subject to FK constraints).") options, args = parser.parse_args() if (len(args) > 0 and parser.has_option('instances')): parser.error("Are you sure you meant to deploy on all instances when " "you also specified instances?") if len(args) > 0: options.instances = dict((i, all_instances[i]) for i in args) if options.instances == None: parser.error("Must specify instances, either with --instances or " "--all-instances") if (options.restart_all and (options.restart_bofhd or options.restart_job_runner or options.restart_individuation)): parser.error("Are you sure you meant --restart-all when you also " "to restart a specific service?") if options.restart_all: options.restart_job_runner =\ options.restart_bofhd =\ options.restart_individuation = True if (options.reload_scheduled_jobs and options.restart_job_runner): parser.error("Are you sure you meant to restart job_runner when you " "also wanted to reload its scheduled_jobs?") # Production MAXIMUM for instance in options.instances.keys(): user = "******" % options.instances[instance] # git pull print("%s: Pulling…") % instance os.system("ssh cerebrum-%s \"su - %s -c 'cd /cerebrum/%s/%s/src/cerebrum; " "git pull'\"" % (instance, user, instance, user)) # setup.py if options.setup: print("%s: Setting up…") % instance os.system("ssh cerebrum-%s \"su - %s -c " "'python /cerebrum/%s/%s/src/cerebrum/setup.py install " "--prefix=/cerebrum/%s/ |egrep -v \"skipping|not\"'\"" % ( (instance, user, instance, user, instance))) # makedb.py, --only-insert-codes is default print("%s: Making database…") % instance os.system("ssh cerebrum-%s \"su - %s -c 'python " "/cerebrum/%s/%s/src/cerebrum/makedb.py --debug %s'\"" % ( (instance, user, instance, user, options.makedb))) # Restart services job_runner = "/cerebrum/%s/sbin/job_runner.py" % instance if options.restart_job_runner: print("%s: Restarting job_runner…") % instance os.system("ssh cerebrum-%s \"su - %s -c '%s --quit'\"" % ( (instance, user, job_runner))) if options.reload_scheduled_jobs: print("%s: Reloading scheduled_jobs…") % instance os.system("ssh cerebrum-%s \"su - %s -c '%s --reload'\"" % ( (instance, user, job_runner))) if options.restart_bofhd: bofhd_pid = "ps aux | grep /cerebrum/%s/sbin/bofhd.py | grep -v "\ "keep-running | grep -v grep | tr -s \" \" | cut -f 2 -d \" \""\ % instance print("%s: Killing bofhd…") % instance os.system("ssh cerebrum-%s \"su - %s -c 'kill `%s`'\"" % ( (instance, user, bofhd_pid)))