def get_db_host(): if cfg.exists('database_admin_url'): return osdb.get_url_host(cfg.get('database_admin_url')) elif cfg.exists('database_url'): return osdb.get_url_host(cfg.get('database_url')) return "localhost"
def __exclude__(self): if cfg.exists("dababase_user_url"): db_url = cfg.get("database_user_url") elif cfg.exists("database_url"): db_url = cfg.get("database_url") else: return not osdb.has_sqlalchemy() return not osdb.has_dialect(osdb.get_dialect(db_url))
def get_db_engine(): if cfg.exists('database_admin_url'): engine = osdb.get_url_driver(cfg.get('database_admin_url')) elif cfg.exists('database_url'): engine = osdb.get_url_driver(cfg.get('database_url')) else: engine = "mysql" if engine not in SUPPORTED_BACKENDS: logger.error("bad database engine ({}), supported: {}".format( engine, " ".join(SUPPORTED_BACKENDS))) return None return engine
def get_admin_db_url(self, db_name): engine = osdb.get_db_engine() if not engine: return None if cfg.exists('database_admin_url'): admin_url = cfg.get("database_admin_url") if engine == "postgres": admin_url = osdb.set_url_db(admin_url, 'postgres') else: if engine == 'postgres': if getuser() != "postgres": logger.error("Command must be run as 'postgres' user: "******"sudo -u postgres opensips-cli ...") return None """ For PG, do the initial setup using 'postgres' as role + DB """ admin_url = "postgres://postgres@localhost/postgres" else: admin_url = "{}://root@localhost".format(engine) if osdb.get_url_pswd(admin_url) is None: pswd = getpass("Password for admin {} user ({}): ".format( osdb.get_url_driver(admin_url, capitalize=True), osdb.get_url_user(admin_url))) logger.debug("read password: '******'", pswd) admin_url = osdb.set_url_password(admin_url, pswd) logger.debug("admin DB URL: '{}'".format(admin_url)) return admin_url
def update_instance(self, instance): # first of all, let's handle logging self.current_instance = instance self.update_logger() # Update the intro and prompt self.intro = cfg.get('prompt_intro') self.prompt = '(%s): ' % cfg.get('prompt_name') # initialize communcation handler self.handler = comm.initialize() # remove all loaded modules self.modules = {} if not self.execute: print(self.intro) # add the built-in modules and commands list for mod in ['clear', 'help', 'history', 'exit', 'quit']: self.modules[mod] = (self, None) if not cfg.exists('skip_modules'): skip_modules = [] else: skip_modules = cfg.get('skip_modules') available_modules = { key[20:]: sys.modules[key] for key in sys.modules.keys() if key.startswith("opensipscli.modules.") and key[20:] not in skip_modules } for name, module in available_modules.items(): m = importlib.import_module("opensipscli.modules.{}".format(name)) if not hasattr(m, "Module"): logger.debug( "Skipping module '{}' - does not extend Module".format( name)) continue if not hasattr(m, name): logger.debug( "Skipping module '{}' - module implementation not found". format(name)) continue mod = getattr(module, name) if not hasattr(mod, '__exclude__') or not hasattr( mod, '__get_methods__'): logger.debug( "Skipping module '{}' - module does not implement Module". format(name)) continue if mod.__exclude__(mod): logger.debug( "Skipping module '{}' - excluded on purpose".format(name)) continue logger.debug("Loaded module '{}'".format(name)) imod = mod() self.modules[name] = (imod, mod.__get_methods__(imod))
def __exclude__(self): """ method exlusion list """ if cfg.exists("database_url"): db_url = cfg.get("database_url") return not osdb.has_dialect(osdb.get_dialect(db_url)) else: return not osdb.has_sqlalchemy()
def create_tables(self, db_name, db_url, admin_db, tables=[], create_std=True): """ create database tables """ db_url = osdb.set_url_db(db_url, db_name) # 2) prepare new object store database instance # use it to connect to the created database db = self.get_db(db_url, db_name) if db is None: return -1 if not db.exists(): logger.warning("database '{}' does not exist!".format(db_name)) return -1 schema_path = self.get_schema_path(db.dialect) if schema_path is None: return -1 if create_std: standard_file_path = os.path.join(schema_path, "standard-create.sql") if not os.path.isfile(standard_file_path): logger.error( "cannot find stardard OpenSIPS DB file: '{}'!".format( standard_file_path)) return -1 table_files = {'standard': standard_file_path} else: table_files = {} # check to see what tables we shall deploy if tables: pass elif cfg.exists("database_modules"): # we know exactly what modules we want to instsall tables_line = cfg.get("database_modules").strip().lower() if tables_line == "all": logger.debug("Creating all tables") tables = [ f.replace('-create.sql', '') \ for f in os.listdir(schema_path) \ if os.path.isfile(os.path.join(schema_path, f)) and \ f.endswith('-create.sql') ] else: logger.debug("Creating custom tables") tables = tables_line.split(" ") else: logger.debug("Creating standard tables") tables = STANDARD_DB_MODULES # check for corresponding SQL schemas files in system path logger.debug("checking tables: {}".format(" ".join(tables))) for table in tables: if table == "standard": # already checked for it continue table_file_path = os.path.join(schema_path, "{}-create.sql".format(table)) if not os.path.isfile(table_file_path): logger.warn("cannot find SQL file for module {}: {}".format( table, table_file_path)) else: table_files[table] = table_file_path username = osdb.get_url_user(db_url) admin_db.connect(db_name) # create tables from SQL schemas for module, table_file in table_files.items(): logger.info("Running {}...".format(os.path.basename(table_file))) try: db.create_module(table_file) if db.dialect == "postgres": self.pg_grant_table_access(table_file, username, admin_db) except osdbModuleAlreadyExistsError: logger.error("{} table(s) are already created!".format(module)) except osdbError as ex: logger.error("cannot import: {}".format(ex)) # terminate active database connection db.destroy() return 0
def _do_create(self, db, db_name=None, do_all_tables=False): if db_name is None: db_name = db.db_name # check to see if the database has already been created if db.exists(db_name): logger.error("database '{}' already exists!".format(db_name)) return -2 db_schema = db.db_url.split(":")[0] schema_path = self.get_schema_path(db_schema) if schema_path is None: return -1 standard_file_path = os.path.join(schema_path, "standard-create.sql") if not os.path.isfile(standard_file_path): logger.error("cannot find stardard OpenSIPS DB file: '{}'!". format(standard_file_path)) return -1 tables_files = [ standard_file_path ] # all good now - check to see what tables we shall deploy if cfg.read_param(None, "Create [a]ll tables or just the [c]urrently configured ones?", default="a").lower() == "a": print("Creating all tables ...") tables = [ f.replace('-create.sql', '') \ for f in os.listdir(schema_path) \ if os.path.isfile(os.path.join(schema_path, f)) and \ f.endswith('-create.sql') ] else: print("Creating the currently configured set of tables ...") if cfg.exists("database_modules"): tables = cfg.get("database_modules").split(" ") else: tables = STANDARD_DB_MODULES logger.debug("deploying tables {}".format(" ".join(tables))) for table in tables: if table == "standard": # already checked for it continue table_file_path = os.path.join(schema_path, "{}-create.sql".format(table)) if not os.path.isfile(table_file_path): logger.warn("cannot find file to create {}: {}". format(table, table_file_path)) else: tables_files.append(table_file_path) db.create(db_name) db.use(db_name) for table_file in tables_files: print("Running {}...".format(os.path.basename(table_file))) try: db.create_module(table_file) except osdbError as ex: logger.error("cannot import: {}".format(ex)) print("The '{}' database has been successfully created!".format(db_name))
def do_rootCA(self, params): global cfg logger.info("Preparing to generate CA cert + key...") # TODO # separate cli.cfg files for TLS are fully deprecated, this if block is # only kept for backwards-compatibility. Remove starting from v3.2! <3 if cfg.exists('tls_ca_config'): tls_cfg = cfg.get('tls_ca_config') cfg = OpenSIPSCLIConfig() cfg.parse(tls_cfg) ca_dir = cfg.read_param("tls_ca_dir", "Output directory", "/etc/opensips/tls/rootCA/") cert_file = cfg.read_param("tls_ca_cert_file", "Output cert file", "cacert.pem") key_file = cfg.read_param("tls_ca_key_file", "Output key file", "private/cakey.pem") c_f = join(ca_dir, cert_file) k_f = join(ca_dir, key_file) if (exists(c_f) or exists(k_f)) and not cfg.read_param( "tls_ca_overwrite", "CA certificate or key already exists, overwrite?", "yes", True): return # create a self-signed cert cert = crypto.X509() cert.get_subject().CN = cfg.read_param("tls_ca_common_name", "Website address (CN)", "opensips.org") cert.get_subject().C = cfg.read_param("tls_ca_country", "Country (C)", "RO") cert.get_subject().ST = cfg.read_param("tls_ca_state", "State (ST)", "Bucharest") cert.get_subject().L = cfg.read_param("tls_ca_locality", "Locality (L)", "Bucharest") cert.get_subject().O = cfg.read_param("tls_ca_organisation", "Organization (O)", "OpenSIPS") cert.get_subject().OU = cfg.read_param("tls_ca_organisational_unit", "Organisational Unit (OU)", "Project") cert.set_serial_number(randrange(100000)) cert.gmtime_adj_notBefore(0) notafter = int( cfg.read_param("tls_ca_notafter", "Certificate validity (seconds)", 315360000)) cert.gmtime_adj_notAfter(notafter) cert.set_issuer(cert.get_subject()) # create a key pair key = crypto.PKey() key_size = int( cfg.read_param("tls_ca_key_size", "RSA key size (bits)", 4096)) key.generate_key(crypto.TYPE_RSA, key_size) cert.set_pubkey(key) md = cfg.read_param("tls_ca_md", "Digest Algorithm", "SHA1") cert.sign(key, md) try: if not exists(dirname(c_f)): makedirs(dirname(c_f)) open(c_f, "wt").write( crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode('utf-8')) except Exception as e: logger.exception(e) logger.error("Failed to write to %s", c_f) return try: if not exists(dirname(k_f)): makedirs(dirname(k_f)) open(k_f, "wt").write( crypto.dump_privatekey(crypto.FILETYPE_PEM, key).decode('utf-8')) except Exception as e: logger.exception(e) logger.error("Failed to write to %s", k_f) return logger.info("CA certificate created in " + c_f) logger.info("CA private key created in " + k_f)
def do_trap(self, params): self.pids = [] self.gdb_outputs = {} self.process_info = "" if cfg.exists("trap_file"): trap_file = cfg.get("trap_file") else: trap_file = TRAP_FILE_NAME logger.info("Trapping {} in {}".format(PROCESS_NAME, trap_file)) if params and len(params) > 0: self.pids = params else: thread = Thread(target=self.get_pids) thread.start() thread.join(timeout=1) if len(self.pids) == 0: logger.warning("could not get OpenSIPS pids through MI!") try: ps_pids = subprocess.check_output(["pidof",PROCESS_NAME]) self.pids = ps_pids.split() except: logger.warning("could not find any OpenSIPS running!") self.pids = [] if len(self.pids) < 1: logger.error("could not find OpenSIPS' pids") return -1 logger.debug("Dumping PIDs: {}".format(", ".join(self.pids))) # get process line of first pid process = os.readlink("/proc/{}/exe".format(self.pids[0])) threads = [] for pid in self.pids: thread = Thread(target=self.get_gdb_output, args=(process, pid)) thread.start() threads.append(thread) for thread in threads: thread.join() if len(self.gdb_outputs) == 0: logger.error("could not get output of gdb") return -1 with open(trap_file, "w") as tf: tf.write(self.process_info) for pid in self.pids: if pid not in self.gdb_outputs: logger.warning("No output from pid {}".format(pid)) continue try: procinfo = subprocess.check_output( ["ps", "--no-headers", "-ww", "-fp", pid]).decode()[:-1] except: procinfo = "UNKNOWN" tf.write("\n\n---start {} ({})\n{}". format(pid, procinfo, self.gdb_outputs[pid])) print("Trap file: {}".format(trap_file))
def do_create(self, params=None): db_url = cfg.read_param("database_url", "Please provide us the URL of the database") if db_url is None: print() logger.error("no URL specified: aborting!") return -1 if params and len(params) > 0: db_name = params[0] else: db_name = cfg.read_param("database_name", "Please provide the database to create", DEFAULT_DB_NAME) db = osdb(db_url, db_name) # check to see if the database has already been created if db.exists(): logger.warn("database '{}' already exists!".format(db_name)) return -2 db_schema = db_url.split(":")[0] schema_path = self.get_schema_path(db_schema) if schema_path is None: return -1 standard_file_path = os.path.join(schema_path, "standard-create.sql") if not os.path.isfile(standard_file_path): logger.error("cannot find stardard OpenSIPS DB file: '{}'!".format( standard_file_path)) return -1 tables_files = [standard_file_path] # all good now - check to see what tables we shall deploy if cfg.exists("database_modules"): tables = cfg.get("database_modules").split(" ") else: tables = STANDARD_DB_MODULES logger.debug("deploying tables {}".format(" ".join(tables))) for table in tables: if table == "standard": # already checked for it continue table_file_path = os.path.join(schema_path, "{}-create.sql".format(table)) if not os.path.isfile(table_file_path): logger.warn("cannot find file to create {}: {}".format( table, table_file_path)) else: tables_files.append(table_file_path) db.create() db.use() for table_file in tables_files: try: db.create_module(table_file) except osdbError as ex: logger.error("cannot import: {}".format(ex)) db.destroy() logger.info("The database has been successfully created.") return 0
def do_userCERT(self, params): global cfg logger.info("Preparing to generate user cert + key + CA list...") # TODO # separate cli.cfg files for TLS are fully deprecated, this if block is # only kept for backwards-compatibility. Remove starting from v3.2! <3 if cfg.exists('tls_user_config'): tls_cfg = cfg.get('tls_user_config') cfg = OpenSIPSCLIConfig() cfg.parse(tls_cfg) user_dir = cfg.read_param("tls_user_dir", "Output directory", "/etc/opensips/tls/user/") cert_file = cfg.read_param("tls_user_cert_file", "Output cert file", "user-cert.pem") key_file = cfg.read_param("tls_user_key_file", "Output key file", "user-privkey.pem") calist_file = cfg.read_param("tls_user_calist_file", "Output CA list file", "user-calist.pem") c_f = join(user_dir, cert_file) k_f = join(user_dir, key_file) ca_f = join(user_dir, calist_file) if (exists(c_f) or exists(k_f) or exists(ca_f)) and not cfg.read_param("tls_user_overwrite", "User certificate, key or CA list file already exists, overwrite?", "yes", True): return cacert = cfg.read_param("tls_user_cacert", "CA cert file", "/etc/opensips/tls/rootCA/cacert.pem") cakey = cfg.read_param("tls_user_cakey", "CA key file", "/etc/opensips/tls/rootCA/private/cakey.pem") try: ca_cert = crypto.load_certificate(crypto.FILETYPE_PEM, open(cacert, 'rt').read()) except Exception as e: logger.exception(e) logger.error("Failed to load %s", cacert) return try: ca_key = crypto.load_privatekey(crypto.FILETYPE_PEM, open(cakey, 'rt').read()) except Exception as e: logger.exception(e) logger.error("Failed to load %s", cakey) return # create a self-signed cert cert = crypto.X509() cert.set_version(2) cert.get_subject().CN = cfg.read_param("tls_user_common_name", "Website address (CN)", "www.opensips.org") cert.get_subject().C = cfg.read_param("tls_user_country", "Country (C)", "RO") cert.get_subject().ST = cfg.read_param("tls_user_state", "State (ST)", "Bucharest") cert.get_subject().L = cfg.read_param("tls_user_locality", "Locality (L)", "Bucharest") cert.get_subject().O = cfg.read_param("tls_user_organisation", "Organization (O)", "OpenSIPS") cert.get_subject().OU = cfg.read_param("tls_user_organisational_unit", "Organisational Unit (OU)", "Project") cert.set_serial_number(randrange(100000)) cert.gmtime_adj_notBefore(0) notafter = int(cfg.read_param("tls_user_notafter", "Certificate validity (seconds)", 315360000)) cert.gmtime_adj_notAfter(notafter) cert.set_issuer(ca_cert.get_subject()) extensions = [ crypto.X509Extension(b'basicConstraints', False, b'CA:FALSE'), crypto.X509Extension(b'extendedKeyUsage', False, b'clientAuth,serverAuth') ] cert.add_extensions(extensions) # create a key pair key = crypto.PKey() key_size = int(cfg.read_param("tls_user_key_size", "RSA key size (bits)", 4096)) key.generate_key(crypto.TYPE_RSA, key_size) cert.set_pubkey(key) md = cfg.read_param("tls_user_md", "Digest Algorithm", "SHA256") cert.sign(ca_key, md) try: if not exists(dirname(c_f)): makedirs(dirname(c_f)) open(c_f, "wt").write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode('utf-8')) except Exception as e: logger.exception(e) logger.error("Failed to write to %s", c_f) return try: if not exists(dirname(k_f)): makedirs(dirname(k_f)) open(k_f, "wt").write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key).decode('utf-8')) except Exception as e: logger.exception(e) logger.error("Failed to write to %s", k_f) return try: if not exists(dirname(ca_f)): makedirs(dirname(ca_f)) open(ca_f, "wt").write(crypto.dump_certificate(crypto.FILETYPE_PEM, ca_cert).decode('utf-8')) except Exception as e: logger.exception(e) logger.error("Failed to write to %s", ca_f) return logger.info("user certificate created in " + c_f) logger.info("user private key created in " + k_f) logger.info("user CA list (chain of trust) created in " + ca_f)
def do_trace(self, params): filters = [] if params is None: caller_f = input("Caller filter: ") if caller_f != "": filters.append(caller_f) callee_f = input("Callee filter: ") if callee_f != "": filters.append(callee_f) ip_f = input("Source IP filter: ") if ip_f != "": filters.append(ip_f) if len(filters) == 0: ans = cfg.read_param(None, "No filter specified! "\ "Continue without a filter?", False, True) if not ans: return False filters = None else: filters = params s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) if cfg.exists("trace_listen_ip"): trace_ip = cfg.get("trace_listen_ip") else: trace_ip = "127.0.0.1" if cfg.exists("trace_listen_port"): trace_port = cfg.get("trace_listen_port") else: trace_port = 0 s.bind((trace_ip, int(trace_port))) if trace_port == 0: trace_port = s.getsockname()[1] s.listen(1) conn = None trace_name = "opensips-cli.{}".format(random.randint(0, 65536)) trace_socket = "hep:{}:{};transport=tcp;version=3".format( trace_ip, trace_port) args = { 'id': trace_name, 'uri': trace_socket, } if filters: args['filters'] = filters logger.debug("filters are {}".format(filters)) trace_started = comm.execute('trace_start', args) if not trace_started: return False try: conn, addr = s.accept() logger.debug("New TCP connection from {}:{}". format(addr[0], addr[1])) remaining = b'' while True: data = conn.recv(TRACE_BUFFER_SIZE) if not data: break remaining = self.__print_hep(remaining + data) if remaining is None: break except KeyboardInterrupt: comm.execute('trace_stop', {'id' : trace_name }, True) if conn is not None: conn.close()
def create_tables(self, db_name=None, do_all_tables=False, db_url=None): """ create database tables """ if db_url is None: db_url = cfg.read_param( "database_url", "Please provide the URL connecting to the database") if db_url is None: logger.error("no URL specified: aborting!") return -1 # 2) prepare new object store database instance # use it to connect to the created database db = self.get_db(db_url, db_name) if db is None: return -1 # connect to the database db.connect(db_name) # check to see if the database has already been created #if db.exists(db_name): # logger.error("database '{}' already exists!".format(db_name)) # return -2 db_schema = db.db_url.split(":")[0] schema_path = self.get_schema_path(db_schema) if schema_path is None: return -1 standard_file_path = os.path.join(schema_path, "standard-create.sql") if not os.path.isfile(standard_file_path): logger.error("cannot find stardard OpenSIPS DB file: '{}'!".format( standard_file_path)) return -1 tables_files = [standard_file_path] # check to see what tables we shall deploy if cfg.read_param( None, "Create [a]ll tables or just the [c]urrently configured ones?", default="a").lower() == "a": print("Creating all tables ...") tables = [ f.replace('-create.sql', '') \ for f in os.listdir(schema_path) \ if os.path.isfile(os.path.join(schema_path, f)) and \ f.endswith('-create.sql') ] else: print("Creating the currently configured set of tables ...") if cfg.exists("database_modules"): tables = cfg.get("database_modules").split(" ") else: tables = STANDARD_DB_MODULES # check for corresponding SQL schemas files in system path logger.debug("deploying tables {}".format(" ".join(tables))) for table in tables: if table == "standard": # already checked for it continue table_file_path = os.path.join(schema_path, "{}-create.sql".format(table)) if not os.path.isfile(table_file_path): logger.warn("cannot find file to create {}: {}".format( table, table_file_path)) else: tables_files.append(table_file_path) # create tables from SQL schemas for table_file in tables_files: print("Running {}...".format(os.path.basename(table_file))) try: db.create_module(table_file) except osdbError as ex: logger.error("cannot import: {}".format(ex)) logger.info("database tables have been successfully created.") # terminate active database connection db.destroy() return 0