2021SC@SDUSC
(continued from the previous article:)
__ daemonize__(self): daemon method
If you receive the signal.SIGTERM (terminate the process), call self.stop
When the user enters kill sigterm pid. The corresponding process will receive this signal. The signal process can capture and specify function processing, such as program cleaning, or ignore this signal
def __daemonize__(self): signal.signal(signal.SIGTERM, self.stop)
Create a child process
try: pid = os.fork() #If pid > 0, it indicates that it is currently in the parent process (the value of pid is the process number of the child process) if pid > 0: #Exit the first parent process sys.exit(0) #Failed to create the child process, and the corresponding error message is output except OSError, e: sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) sys.exit(1)
Decouple from parent environment
os.setsid(): when the process is the leading process of the session, the setsid() call fails and returns (- 1).
After the setsid() call is successful, the ID of the new session is returned. The process calling the setsid function becomes the leader process of the new session and is separated from the session group and process group of its parent process.
# The os.chdir() method is used to change the current working directory to the specified path. os.chdir("/") #Call system call setsid() os.setsid() #Set the current value umask and return the previous umask os.umask(0)
Create the second child process, the same process as when creating the first child process
try: pid = os.fork() if pid > 0: #Exit the second parent process sys.exit(0) except OSError, e: sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) sys.exit(1)
Redirect standard file descriptor
sys.stdout.flush(), sys.stderr.flush(): standard output and standard error stream
sys.stdout.flush() sys.stderr.flush()
file(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None):
r: Open the file as read-only. The pointer to the file will be placed at the beginning of the file. This is the default mode.
A +: open a file for reading and writing. If the file already exists, the file pointer will be placed at the end of the file. The file is opened in append mode. If the file does not exist, create a new file for reading and writing.
0: error level
si = file('/dev/null', 'r') so = file('/dev/null', 'a+') se = file('/dev/null', 'a+', 0)
os.dup2(): used to copy one file descriptor FD to another file descriptor fd2.
fileno(): returns an integer file descriptor (FD integer), which can be used for I/O operations of the underlying operating system.
Copy input, output, error file descriptors to standard input, standard output, standard error stream
os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno())
Write pid file
atexit.register(): used to register an exit function in the python interpreter. This function is automatically executed when the interpreter terminates normally. It is generally used to clean up resources (here is to delete pid files)
atexit.register(self.delpid) pid = str(os.getpid()) file(self.pidfile, 'w+').write("%s\n" % pid) os.chmod(self.pidfile, 0644)
delpid(self): deletes the pid file
def delpid(self): Delete the pid file os.remove(self.pidfile)
stop(self, sig, params): terminate the frameworkd process
def stop(self, sig, params): try: pf = file(self.pidfile, 'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None if not pid: message = "pidfile %s does not exist. Daemon not running? or not in daemon mode?\n" sys.stderr.write(message % self.pidfile) return
Terminate daemon
try: while 1: os.kill(pid, signal.SIGTERM) time.sleep(0.1) except OSError, err: err = str(err) if err.find("No such process") > 0: if os.path.exists(self.pidfile): os.remove(self.pidfile) else: print str(err) sys.exit(1)
Wait forever (self): wait for Control-C and terminate all threads
def waitforever(self): while 1: try: time.sleep(1) #The isAlive method inherits from threading, is_ The alive () method queries whether the thread is still running if not self.__listener.isAlive(): logger.info("Listener in down... exiting...") pid = os.getpid() os.kill(pid, signal.SIGKILL) break except KeyboardInterrupt: pid = os.getpid() os.kill(pid, signal.SIGKILL)
__init_log(self, daemon_mode)
def __init_log(self, daemon_mode): verbose = "info" Logger.add_file_handler('%s/frameworkd.log' % self.__conf[VAR_LOG_DIR]) Logger.add_error_file_handler('%s/frameworkd_error.log' % self.__conf[VAR_LOG_DIR]) if daemon_mode: Logger.remove_console_handler()
The command line function was parsed earlier__ parse_ - v parameter in options (self)
parser.add_option("-v", "--verbose", dest="verbose", action="count",help="make lots of noise")
Command line parameters
-v -> self.options.verbose = 1
-vv -> self.options.verbose = 2
if self._options.verbose is not None: for i in range(self._options.verbose): verbose = Logger.next_verbose_level(verbose) Logger.set_verbose(verbose) try: os.chmod('%s/frameworkd.log' % self.__conf[VAR_LOG_DIR], 0644) os.chmod('%s/frameworkd_error.log' % self.__conf[VAR_LOG_DIR], 0644) except Exception, e: print str(e)
Check encryption key (self): check the encryption key file.
Check whether the file exists and whether the key is stored in the database
def checkEncryptionKey(self): mydb = OssimDB(self.__conf[VAR_DB_HOST], self.__conf[VAR_DB_SCHEMA], self.__conf[VAR_DB_USER], self.__conf[VAR_DB_PASSWORD]) mydb.connect() select_query = "select value from config where conf=\"encryption_key\";" insert_query = "REPLACE INTO config VALUES ('encryption_key', '%s')" data = mydb.exec_query(select_query)
keyFilePath = self.__conf[VAR_KEY_FILE] if keyFilePath == "" or keyFilePath is None: logger.error("Frameworkd can't start. Please check the value of %s in the config table" % VAR_KEY_FILE) sys.exit(2) if not os.path.isfile(self.__conf[VAR_KEY_FILE]) or data is None or data == "" or len(data) == 0: logger.info( "Encryption key file doesn't exist... making it at .. %s and save it to db" % self.__conf[VAR_KEY_FILE]) output = sub.Popen('/usr/bin/alienvault-system-id', stdout=sub.PIPE) s_uuid = output.stdout.read().upper() reg_str = "(?P<uuid>[a-zA-Z0-9]-[a-zA-Z0-9]-[a-zA-Z0-9]-[a-zA-Z0-9]-[a-zA-Z0-9])" pt = re.compile(reg_str, re.M) match_data = pt.search(s_uuid) key = "" extra_data = "" d = datetime.today() if match_data is not None: key = match_data.group('uuid') extra_data = "#Generated using alienvault-system-id\n" else: logger.error( "I can't obtain system uuid. Generating a random uuid. Please do backup your encrytion key file: %s" % self.__conf[VAR_KEY_FILE]) extra_data = "#Generated using random uuid on %s\n" % d.isoformat(' ') key = uuid.uuid4() newfile = open(self.__conf[VAR_KEY_FILE], 'w') mydb.exec_query(insert_query % key) key = "key=%s\n" % key newfile.write("#This file is generated automatically by ossim. Please don't modify it!\n") newfile.write(extra_data) newfile.write("[key-value]\n") newfile.write(key) newfile.close() # insert the key in db.. pw = pwd.getpwnam('www-data') os.chown(self.__conf[VAR_KEY_FILE], pw.pw_uid, pw.pw_gid) os.chmod(self.__conf[VAR_KEY_FILE], stat.S_IRUSR)
__ check_pid(self): check whether the pid file exists
def __check_pid(self): try: pf = file(self.pidfile, 'r') pid = int(pf.read().strip()) pf.close() except IOError: pid = None if pid: message = "pidfile %s already exist. Daemon already running?\n" sys.stderr.write(message % self.pidfile) sys.exit(1)
Previous (Framework source code analysis (I)): OSSIM open source security information management system (V)
Next (Framework source code analysis (III)):