def sendMsgToStorage(cmd): '''Forwarder of messages to storage''' log.debug("In sendMsgToStorage - cmd: {0}".format(cmd)) try: if not util.connLock.acquire(True, 5): raise IKException( ErrorCode.operationFailed, "Failed to acquire the lock for connecting to storage.") log.debug("Sending...") connHere.send(cmd) log.debug("Sent. Receiving...") if connHere.poll(15): ret = connHere.recv() log.debug("In sendMsgToStorage - ret: {0}".format(ret)) else: ret = composeResponse( "0", "Socket timed out or no data to receive.") log.debug("Nothing to receive") util.connLock.release() except Exception as e: ret = composeResponse("0", str(e)) log.error( "In sendMsgToStorage exception received: {0}".format(ret)) return ret
def accept(self, sock, mask): try: connection, client_address = sock.accept() except Exception as e: log.error( "Exception occured: ", e ) return mp.Process( target = self.handle_connection, name = "RegdConnectionHandler", args = ( connection, client_address, util.connLock ) ).start()
def loop( self, sock ): self.cont = True self.exitcode = 0 while app.glCont: events = self.sel.select( 30 ) for key, mask in events: callback = key.data callback(key.fileobj, mask) if 0 : # not os.path.exists( self.sockfile ): log.error( "Socket file {0} is gone. Exiting.".format( self.sockfile ) ) #exit( 1 ) return else: continue
def startRegistry(servername, sockfile=None, host=None, port=None, acc=defs.PL_PRIVATE, datafile=None, binsecfile=None): srv = connStor = None def shutdown(): log.info("Registry is shutting down...") cmds.CmdSwitcher.switchCmd({"cmd": fs.FS_STOP}) log.info("Shutdown complete.") def signal_handler(signal, frame): #shutdown() # Returning normally, so that the signal notification be forwarded to # the wakeup socket. return sigHandler.push(signal.SIGINT, signal_handler) sigHandler.push(signal.SIGTERM, signal_handler) sigHandler.push(signal.SIGHUP, signal_handler) sigHandler.push(signal.SIGABRT, signal_handler) sigHandler.push(signal.SIGALRM, signal_handler) try: # Storage log.debug("Creating storage") connStor, sigStor = fs.startStorage(acc, datafile, binsecfile) # Server log.debug("Creating server instance") srv = serv.RegdServer(servername, sockfile, host, port, acc) # Info log.debug("Creating info") info.Info() log.debug("Starting server") srv.start_loop(sigStor) except Exception as e: log.error("Failed to start server: {0}".format(e)) else: #glSignal.acquire() # Wait till notification on df.SERVER_STOP #glSignal.wait() shutdown() log.info("Exiting.")
def start_loop(conn, sigConn, acc, datafile, binsectfile): '''Create FS instance and start loop''' util.setLog("DEBUG") fs = FS(conn, acc, datafile, binsectfile) log.info("Starting listening for messages...") try: fs.listenForMessages(fs.serialize) except Exception as e: log.error("Exception received: {0}".format(e)) #fs.conn.shutdown(SHUT_RDWR) conn.close() sigConn.send("Exception in storage".encode()) sigConn.shutdown(SHUT_RDWR) sigConn.close() log.info("Ended listening for messages. Quitting...") return 0
def listenForMessages(self, func): while self.cont: if self.conn.poll(30): try: cmd = self.conn.recv() try: resp = self.processCmd( cmd ) except IKException as e: resp = util.composeResponse( "0", "In listenForMessages - exception received: {0}. Continue listening...".format( e ) ) log.error( resp ) self.conn.send( resp ) except Exception as e: fh = io.StringIO() traceback.print_exc( file=fh ) log.error( "In listenForMessages - fatal exception received: {0}. Quit listening...".format( fh.getvalue() ) ) raise else: func()
def handle_connection( self, *args ): '''Exceptions-catcher wrapper''' connection = args[0] client_address = args[1] storage_lock = args[2] try: self._handle_connection( connection, client_address, storage_lock ) except IKException as e: log.error( ( "Exception while handling connection." "Client: %s ; Exception: %s" ) % ( client_address, e ) ) except Exception as e: log.error( "Exception in connection handler: %s" % ( e ) ) self.sigsock_w.send("stop".encode()) finally: connection.shutdown( socket.SHUT_RDWR ) connection.close()
def read_sec_file(self, filename=None, cmd=None, addMode=df.noOverwrite): '''Read secure tokens from a file with a user command''' if not filename: filename = self.encFile if not os.path.exists(filename): log.error("Cannot find encrypted data file. Exiting.") raise IKException(ErrorCode.operationFailed, "File not found.") try: if not cmd: cmd = self.secTokCmd.replace("FILENAME", "{0}").format(filename) ftxt = "Calling read private file command..." ftxt = subprocess.check_output(cmd, shell=True, stderr=subprocess.DEVNULL) except subprocess.CalledProcessError as e: log.error(e.output.decode() + "; " + ftxt) raise IKException(ErrorCode.operationFailed, e.output) fh = io.BytesIO(ftxt) fh.name = "BytesIO:" + filename self.fs.readFromFile(fh=fh, dest="/ses", addMode=addMode)
def _handle_connection( self, connection, client_address, storage_lock ): '''Connection handler''' if not self.host: creds = connection.getsockopt( socket.SOL_SOCKET, socket.SO_PEERCRED, struct.calcsize( "3i" ) ) pid, uid, gid = struct.unpack( "3i", creds ) log.debug( "new connection: pid: {0}; uid: {1}; gid: {2}".format( pid, uid, gid ) ) else: log.debug( "new connection: client address: %s" % ( str( client_address ) ) ) connection.settimeout( 5 ) data = bytearray() util.recvPack( connection, data ) bytesReceived = len( data ) log.debug( "data: %s" % ( data[:1000] ) ) data = data[10:] # .decode( 'utf-8' ) bresp = bytearray() cmd = None perm = False # dcmd - command dictionary. Contains three fields: # cmd - command name, received from client # params - command parameters, received from client # res - internal command processing result, set by the command processor or # command handler. This result has the server semantics, rather than the # command semantics: if it's 0 - this means a general program error, e.g. # non-existing command name. It's meant to be handled by the server before # sending response to the client. try: dcmd = util.parsePacket( data ) # 'internal' switch is only used within regd server if "internal" in dcmd: raise Exception("Unrecognized syntax.") cmd = dcmd["cmd"] log.debug( "command received: {0}".format( cmd ) ) except Exception as e: bresp = composeResponse( "0", "Exception while parsing the command: " + str( e ) ) else: # Check permission and persistency if self.host: # IP-based server if not self.trustedIps: perm = True else : try: clientIp = ipaddress.IPv4Address( client_address[0] ) except ValueError: log.error( "Client IP address format is not recognized." ) else: for i in self.trustedIps: if clientIp in i: perm = True log.debug( "Client IP is trusted." ) break if not perm: log.error( "Client IP is NOT trusted : '%s : %s" % ( client_address[0], client_address[1] ) ) else: # File socket server if self.useruid == uid: perm = True elif uid in self.trustedUserids: perm = True elif cmd not in defs.secure_cmds: if self.acc == defs.PL_PUBLIC: perm = True elif self.acc == defs.PL_PUBLIC_READ: if cmd in defs.pubread_cmds: perm = True log.debug( "perm: {0}".format( perm ) ) if not perm: bresp = composeResponse( "0", str( IKException( ErrorCode.permissionDenied, cmd ) ) ) #elif not self.datafile and defs.PERS in cmd: # bresp = composeResponse( "0", str( IKException( ErrorCode.operationFailed, None, "Persistent tokens are not enabled." ) ) ) if not len( bresp ): util.connLock = storage_lock bresp = CmdSwitcher.handleCmd( dcmd ) try: bytesSent = util.sendPack( connection, bresp ) except OSError as er: log.error( "Socket error {0}: {1}\nClient address: {2}\n".format( er.errno, er.strerror, client_address ) ) else: if type( bytesSent ) is int: info.setShared( "bytesReceived", bytesReceived, defs.SUM ) info.setShared( "bytesSent", bytesSent, defs.SUM ) if cmd == defs.STOP_SERVER and perm: self.sigsock_w.send("stop".encode()) return
def start_loop( self, sigStor ): '''Start loop.''' # Check for the previous instance if not self.host and os.path.exists( self.sockfile ): log.info( "Socket file for a server with name already exists. Checking for the server process." ) '''Socket file may remain after an unclean exit. Check if another server is running.''' try: # If the server is restarted, give the previous instance time to exit cleanly. time.sleep( 2 ) if self.servername and self.servername != "regd": s = "ps -ef | grep '{0}(/cli.py)? start .*{1} {2}' | grep -v grep".format( app.APPNAME, app.clp( defs.SERVER_NAME ), self.servername ) else: s = "ps -ef | grep -E '{0}(/cli.py)? start' | grep -v '{1}' | grep -v grep".format( app.APPNAME, app.clc( defs.SERVER_NAME ) ) res = subprocess.check_output( s, shell = True ).decode( 'utf-8' ) except subprocess.CalledProcessError as e: if e.returncode != 1: log.error( "Check for already running server instance failed: {0} ".format( e.output ) ) return -1 else: res = "" if len( res ): # TODO if res.count( "\n" ) > 2: '''Server is already running.''' log.warning( "Server is already running:\n{0}".format( res ) ) return 1 log.info( "Server process is not found. Unlinking the existing socket file." ) try: os.unlink( self.sockfile ) except OSError: if os.path.exists( self.sockfile ): raise self.useruid = os.getuid() if self.host: log.info( "Starting regd server. useruid: {0} ; host: {1} ; port: {2}.".format( self.useruid, self.host, self.port ) ) else: log.info( "Starting regd server. useruid: {0} ; sockfile: {1} ; servername: {2}.".format( self.useruid, self.sockfile, self.servername ) ) self.info["time_started"] = str( datetime.datetime.now() ).rpartition( "." )[0] # Set up sockets try: if self.host: self.sock = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) self.sock.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 ) self.sock.bind( ( self.host, int( self.port ) ) ) with open( self.sockfile, "w" ) as f: f.write( '' ) else: self.sock = socket.socket( socket.AF_UNIX, socket.SOCK_STREAM ) self.sock.bind( self.sockfile ) os.chmod( self.sockfile, mode = 0o777 ) except OSError as e: log.error( "Cannot create or bind socket: %s" % ( e ) ) return -1 self.sock.listen( 1 ) self.sock.settimeout( 30 ) self.sel = selectors.DefaultSelector() self.sigsock_r, self.sigsock_w = socket.socketpair() self.sigsock_r.setblocking( False ) self.sigsock_w.setblocking( False ) os.set_inheritable( self.sigsock_w.fileno(), True ) self.sock.setblocking( False ) signal.set_wakeup_fd( self.sigsock_w.fileno() ) self.sel.register( self.sock, selectors.EVENT_READ, self.accept ) self.sel.register( self.sigsock_r, selectors.EVENT_READ, self.stop ) self.sel.register( sigStor, selectors.EVENT_READ, self.stop ) self.loop( self.sock, )
def __init__(self, conn, acc, datafile, binsecfile=None): super(FS, self).__init__(conn) self.acc = acc self.datafile = datafile self.binsecfile = binsecfile self.info = {} self.cont = True self.fs = getstor(rootStor=None, mode=0o555) self.tokens = getstor(rootStor=None, mode=0o777) self.bintokens = getstor(rootStor=None, mode=0o777) self.systokens = getstor(rootStor=None, mode=0o600) self.fs[''] = getstor(rootStor=None, mode=0o555) self.fs[''][SESNAME] = self.tokens self.fs[''][SYSNAME] = self.systokens self.fs[''][BINNAME] = self.bintokens if self.binsecfile: self.fs.setItemAttr(BINPATH, ("{0}={1}".format( stor.SItem.persPathAttrName, self.binsecfile), )) self.tokens.rootStor = self.tokens self.bintokens.rootStor = self.bintokens self.systokens.rootStor = self.systokens self.useruid = None # Default encrypted file name self.encFile = app.homedir + "/.sec/safestor.gpg" # Flag showing whether the default enc. file has been read self.defencread = False # Command line command for reading encrypted file self.secTokCmd = df.READ_ENCFILE_CMD if self.datafile: # Persistent tokens self.perstokens = getstor(rootStor=None, mode=0o777) self.fs[''][PERSNAME] = self.perstokens self.fs.setItemAttr(PERSPATH, ("{0}={1}".format( stor.SItem.persPathAttrName, self.datafile), )) self.perstokens.rootStor = self.perstokens try: fhd = {'cur': None} stor.treeLoad = True self.fs[''][PERSNAME].serialize(fhd, read=True) stor.treeLoad = False for v in fhd.values(): if v: v.close() # read_locked( self.data_fd, self.perstokens, defs.overwrite ) # self.data_fd.close() except IKException as e: log.error("Cannot read the data file: %s" % (str(e))) raise IKException(ErrorCode.operationFailed) else: print( "Server's data file is not specified. Persistent tokens are not enabled." ) if self.binsecfile: try: fhd = {'cur': None} stor.treeLoad = True self.fs[''][BINNAME].serialize(fhd, read=True) stor.treeLoad = False for v in fhd.values(): if v: v.close() except IKException as e: log.error("Cannot read the bin_section file: %s" % (str(e))) raise IKException(ErrorCode.operationFailed) d = {} app.read_conf(d) if "encfile" in d: self.encFile = d["encfile"] if "encfile_read_cmd" in d: self.secTokCmd = d["encfile_read_cmd"] # Storing shared info self.fs[''][SYSNAME]["dataFile"] = self.datafile