def DispCrons(dom, grph, configNode, configName): attr_name = GetDefaultApp(dom) for elt_crontable in dom.getElementsByTagName('crontable'): for elt_cronrules in elt_crontable.getElementsByTagName('cronrules'): attr_cronrules_cronid = elt_cronrules.getAttributeNode( 'cronid').value nodeCronrules = AC2_cronrules.MakeUri(configName, attr_cronrules_cronid) grph.add((configNode, AC2.propCronRules, nodeCronrules)) for elt_trigger in elt_cronrules.getElementsByTagName('trigger'): attr_trigger_name = elt_trigger.getAttributeNode('name').value attr_trigger_name_no_sharp = attr_trigger_name.replace( "CRON#", "Cron ") nodeTrigger = AC2_trigger.MakeUri(configName, attr_cronrules_cronid, attr_trigger_name_no_sharp) # Many optional attributes. attr_trigger_action = elt_trigger.getAttributeNode('action') if attr_trigger_action: grph.add( (nodeTrigger, lib_common.MakeProp("action"), lib_common.NodeLiteral(attr_trigger_action.value))) attr_trigger_force = elt_trigger.getAttributeNode('force') if attr_trigger_force: grph.add( (nodeTrigger, lib_common.MakeProp("force"), lib_common.NodeLiteral(attr_trigger_force.value))) attr_trigger_components = elt_trigger.getAttributeNode( 'components') if attr_trigger_components: componentList = attr_trigger_components.value.split(",") for compNam in componentList: nodeComponent = AC2_component.MakeUri( configName, attr_name, compNam) grph.add( (nodeTrigger, AC2.propComponents, nodeComponent)) attr_trigger_propagate = elt_trigger.getAttributeNode( 'propagate') if attr_trigger_propagate: grph.add( (nodeTrigger, lib_common.MakeProp("propagate"), lib_common.NodeLiteral(attr_trigger_propagate.value))) attr_trigger_expression = elt_trigger.getAttributeNode( 'expression') if attr_trigger_expression: grph.add((nodeTrigger, lib_common.MakeProp("expression"), lib_common.NodeLiteral( attr_trigger_expression.value))) grph.add((nodeCronrules, AC2.propTrigger, nodeTrigger)) return
def AddFileProperties(grph, current_node, current_filename): try: import win32api import lib_win32 prop_dict = lib_win32.getFileProperties(current_filename) for prp, val in prop_dict.items(): val = prop_dict[prp] if val is None: continue if isinstance(val, dict): val = json.dumps(val) # TODO: Unicode error encoding=ascii # 169 251 A9 10101001 "Copyright" © © Copyright sign # Might contain this: "LegalCopyright Copyright \u00a9 2010" val = val.replace("\\", "\\\\") grph.add((current_node, lib_common.MakeProp(prp), lib_common.NodeLiteral(val))) except ImportError: pass file_mime_type = lib_mime.FilenameToMime(current_filename) if file_mime_type: if file_mime_type[0]: grph.add((current_node, lib_common.MakeProp("Mime type"), lib_common.NodeLiteral(str(file_mime_type))))
def Main(): cgiEnv = lib_common.CgiEnv() grph = cgiEnv.GetGraph() for lin_cg in open("/proc/cgroups"): # Just in case there would be a comment. lin_cg = lin_cg.strip() if lin_cg.startswith("#"): continue split_cg = lin_cg.split('\t') subsys_name = split_cg[0] hierarchy = split_cg[1] num_cgroups = split_cg[2] enabled = split_cg[3] cgrpNode = survol_cgroup.MakeUri(subsys_name) grph.add((cgrpNode, lib_common.MakeProp("Hierarchy"), lib_common.NodeLiteral(hierarchy))) grph.add((cgrpNode, lib_common.MakeProp("Num CGroups"), lib_common.NodeLiteral(num_cgroups))) grph.add((cgrpNode, lib_common.MakeProp("Enabled"), lib_common.NodeLiteral(enabled))) cgiEnv.OutCgiRdf()
def AddConnections(grph,listConnections,configNam,nodeManager): for objConnect in listConnections: namConnect = objConnect["name"] DEBUG("namConnect=%s",namConnect) nodeConnect = survol_rabbitmq_connection.MakeUri(configNam,namConnect) try: grph.add( ( nodeConnect, lib_common.MakeProp("Protocol"), lib_common.NodeLiteral(objConnect["protocol"]) ) ) except KeyError: pass try: grph.add( ( nodeConnect, lib_common.MakeProp("Node"), lib_common.NodeLiteral(objConnect["node"]) ) ) except KeyError: pass nodeUser = survol_rabbitmq_user.MakeUri(configNam,objConnect["user"]) try: grph.add( ( nodeConnect, lib_common.MakeProp("User"), nodeUser ) ) except KeyError: pass # '127.0.0.1:51532 -> 127.0.0.1:5672' # http://localhost:12345/#/connections/127.0.0.1%3A51532%20-%3E%20127.0.0.1%3A5672 namConnectCgi = namConnect.replace(">",">") DEBUG("namConnectCgi=%s",namConnectCgi) managementUrl = rabbitmq.ManagementUrlPrefix(configNam,"connections",namConnectCgi) grph.add( ( nodeConnect, lib_common.MakeProp("Management"), lib_common.NodeUrl(managementUrl) ) ) grph.add( ( nodeManager, lib_common.MakeProp("Connection"), nodeConnect ) )
def AddInfo(grph, node, entity_ids_arr): subscriptionName = entity_ids_arr[0] # This function is called from entity.py which does not connect to anything, # so we can do it here. Beware if there are too many connections, # because we could connect to all of them. try: (subscription_id, certificate_path) = lib_credentials.GetCredentials( "Azure", subscriptionName) if not subscription_id: errMsg = "No credential for subscriptionName=%s" % subscriptionName grph.add((node, lib_common.MakeProp("Azure Error"), lib_common.NodeLiteral(errMsg))) return sms = ServiceManagementService(subscription_id, certificate_path) except: exc = sys.exc_info()[1] errMsg = "subscriptionName=%s:%s" % (subscriptionName, str(exc)) grph.add((node, lib_common.MakeProp("Azure Error"), lib_common.NodeLiteral(errMsg))) return # There are a lot of informations grph.add((node, lib_common.MakeProp(".cert_file"), lib_common.NodeLiteral(sms.cert_file))) grph.add((node, lib_common.MakeProp(".requestid"), lib_common.NodeLiteral(sms.requestid))) grph.add((node, lib_common.MakeProp(".x_ms_version"), lib_common.NodeLiteral(sms.x_ms_version)))
def Main(): # If this flag is set, the script uses SLP to discover WBEM Agents. paramkeySLP = "Service Location Protocol" cgiEnv = lib_common.CgiEnv(parameters={paramkeySLP: False}) flagSLP = bool(cgiEnv.GetParameters(paramkeySLP)) grph = cgiEnv.GetGraph() WbemServersDisplay(grph) if flagSLP: dictServices = survol_neighborhood.GetSLPServices("survol") for keyService in dictServices: wbemNode = AddFromWbemCimom(grph, keyService) if not wbemNode: continue grph.add((wbemNode, pc.property_information, lib_common.NodeLiteral("Service Location Protocol"))) attrsService = dictServices[keyService] for keyAttr in attrsService: propAttr = lib_common.MakeProp(keyAttr) valAttr = attrsService[keyAttr] grph.add((wbemNode, propAttr, lib_common.NodeLiteral(valAttr))) cgiEnv.OutCgiRdf()
def WbemKeyValues(key_value_items, display_none_values=False): dict_key_values = {} for wbem_key_name, wbem_value_literal in key_value_items: wbem_property = lib_properties.MakeProp(wbem_key_name) if isinstance(wbem_value_literal, lib_util.scalar_data_types): wbem_value_node = lib_common.NodeLiteral(wbem_value_literal) elif isinstance(wbem_value_literal, (tuple)): tuple_joined = " ; ".join(wbem_value_literal) wbem_value_node = lib_common.NodeLiteral(tuple_joined) elif wbem_value_literal is None: if display_none_values: wbem_value_node = lib_common.NodeLiteral("None") else: wbem_value_node = lib_common.NodeLiteral( "type=" + str(type(wbem_value_literal)) + ":" + str(wbem_value_literal)) #try: # refMoniker = str(wbem_value_literal.path()) # instance_url = lib_util.EntityUrlFromMoniker(refMoniker) # wbem_value_node = lib_common.NodeUrl(instance_url) #except AttributeError as exc: # wbem_value_node = lib_common.NodeLiteral(str(exc)) dict_key_values[wbem_property] = wbem_value_node return dict_key_values
def Main(): # If this flag is set, the script uses SLP to discover Survol Agents. paramkeySLP = "Service Location Protocol" cgiEnv = lib_common.CgiEnv(parameters={paramkeySLP: False}) flagSLP = bool(cgiEnv.GetParameters(paramkeySLP)) grph = cgiEnv.GetGraph() SurvolServersDisplay(grph) if flagSLP: dictServices = survol_neighborhood.GetSLPServices("survol") for keyService in dictServices: nodeSurvolUrl = CallbackNodeAdder(grph, keyService) grph.add((nodeSurvolUrl, pc.property_information, lib_common.NodeLiteral("Service Location Protocol"))) attrsService = dictServices[keyService] for keyAttr in attrsService: propAttr = lib_common.MakeProp(keyAttr) valAttr = attrsService[keyAttr] grph.add( (nodeSurvolUrl, propAttr, lib_common.NodeLiteral(valAttr))) cgiEnv.OutCgiRdf()
def AddFileProperties(grph,currNode,currFilNam): try: import win32api import lib_win32 propDict = lib_win32.getFileProperties(currFilNam) for prp, val in propDict.items(): val = propDict[prp] if val is None: continue if isinstance( val, dict ): # val = ", ".join( "%s=%s" % (k,val[k]) for k in val ) val = json.dumps(val) # TODO: Unicode error encoding=ascii # 169 251 A9 10101001 "Copyright" © © Copyright sign # Might contain this: "LegalCopyright Copyright \u00a9 2010" val = val.replace("\\","\\\\") grph.add( ( currNode, lib_common.MakeProp(prp), lib_common.NodeLiteral(val) ) ) except ImportError: pass mimTy = lib_mime.FilenameToMime(currFilNam) if mimTy: if mimTy[0]: grph.add( ( currNode, lib_common.MakeProp("Mime type"), lib_common.NodeLiteral(str(mimTy)) ) )
def AddInfoFromImport(grph, packageNode, packageKey): try: the_module = importlib.import_module(packageKey) except ImportError: lib_common.ErrorMessageHtml("Importing %s: Error %s" % (packageKey, str(sys.exc_info()))) try: initFilNam = the_module.__file__ filNode = lib_common.gUriGen.FileUri(initFilNam) grph.add((packageNode, propPythonPackage, filNode)) except AttributeError: pass try: txtDoc = the_module.__doc__ if txtDoc: grph.add((packageNode, pc.property_information, lib_common.NodeLiteral(txtDoc))) except AttributeError: pass propsPackage = {"Author": "__author__", "Version": "__version__"} for keyProp in propsPackage: valProp = propsPackage[keyProp] try: txtVal = getattr(the_module, valProp) if txtVal: grph.add((packageNode, lib_common.MakeProp(keyProp), lib_common.NodeLiteral(txtVal))) except AttributeError: pass
def AddInfoFromPip(grph, node, packageKey): try: # TODO: What about several Python versions ? installed_packages = lib_python.PipGetInstalledDistributions() # TODO: Maybe the version should be part of the key. for pckg in installed_packages: if packageKey == pckg.key: FillOnePackage(grph, node, pckg) else: for subReq in pckg.requires(): # sys.stderr.write("subReq.key=%s pckg.key=%s\n"%(subReq.key,packageKey)) if subReq.key == packageKey: subNode = MakeUri(pckg.key) # [('>=', '4.0.0')]+[]+[('>=','4.0')]+[] aSpecs = subReq.specs if aSpecs: # TODO: This should be displayed on the edge !!! grph.add( (node, lib_common.MakeProp("Condition " + pckg.key), lib_common.NodeLiteral(str(aSpecs)))) grph.add((subNode, propPythonRequires, node)) break except Exception: exc = sys.exc_info()[1] grph.add( (node, pc.property_information, lib_common.NodeLiteral(str(exc))))
def Main(): cgiEnv = lib_common.CgiEnv() grph = cgiEnv.GetGraph() dsnNam = survol_odbc_dsn.GetDsnNameFromCgi(cgiEnv) DEBUG("dsn=(%s)", dsnNam) nodeDsn = survol_odbc_dsn.MakeUri(dsnNam) ODBC_ConnectString = survol_odbc_dsn.MakeOdbcConnectionString(dsnNam) try: cnxn = pyodbc.connect(ODBC_ConnectString) DEBUG("Connected: %s", dsnNam) # for prmstr in sqlgetinfo_params: for prmstr in dir(pyodbc): if not prmstr.startswith("SQL_"): continue #sys.stderr.write("prmstr: %s\n" % prmstr) # Some keywords are not interesting. This is a bit arbitrary. if prmstr in ["SQL_KEYWORDS"]: continue nicestr = prmstr[4:].replace("_", " ").capitalize() prop = lib_common.MakeProp(nicestr) try: prm = getattr(pyodbc, prmstr) # except AttributeError: except: grph.add( (nodeDsn, prop, lib_common.NodeLiteral("Unavailable"))) continue try: prm_value = cnxn.getinfo(prm) except: #txt = str( sys.exc_info()[1] ) #grph.add( (nodeDsn, prop, lib_common.NodeLiteral(txt) ) ) continue try: grph.add((nodeDsn, prop, lib_common.NodeLiteral(prm_value))) except: txt = str(sys.exc_info()[1]) grph.add((nodeDsn, prop, lib_common.NodeLiteral(txt))) continue except Exception: exc = sys.exc_info()[0] lib_common.ErrorMessageHtml("nodeDsn=%s Unexpected error:%s" % (dsnNam, str(sys.exc_info()))) cgiEnv.OutCgiRdf()
def Main(): cgiEnv = lib_common.CgiEnv() configNam = cgiEnv.GetId() nodeManager = survol_rabbitmq_manager.MakeUri(configNam) creds = lib_credentials.GetCredentials( "RabbitMQ", configNam ) # cl = Client('localhost:12345', 'guest', 'guest') cl = Client(configNam, creds[0], creds[1]) grph = cgiEnv.GetGraph() # >>> cl.get_all_vhosts() # http://localhost:12345/api/vhosts # [{u'name': u'/', u'tracing': False, u'messages_details': {u'rate': 0.0}, u'messages': 0, u'message_stats': {u'deliver_no_ack': 0, u' # publish_out': 0, u'get_no_ack': 13, u'return_unroutable': 0, u'confirm': 0, u'deliver_get': 13, u'publish': 13, u'confirm_details': # {u'rate': 0.0}, u'ack_details': {u'rate': 0.0}, u'get': 0, u'deliver': 0, u'publish_out_details': {u'rate': 0.0}, u'redeliver_detail # s': {u'rate': 0.0}, u'deliver_details': {u'rate': 0.0}, u'deliver_get_details': {u'rate': 0.0}, u'publish_details': {u'rate': 0.0}, # u'publish_in_details': {u'rate': 0.0}, u'ack': 0, u'publish_in': 0, u'return_unroutable_details': {u'rate': 0.0}, u'get_details': {u # 'rate': 0.0}, u'get_no_ack_details': {u'rate': 0.0}, u'deliver_no_ack_details': {u'rate': 0.0}, u'redeliver': 0}, u'messages_unackno # wledged_details': {u'rate': 0.0}, u'messages_ready_details': {u'rate': 0.0}, u'messages_unacknowledged': 0, u'messages_ready': 0}] try: # listVHosts = cl.get_all_vhosts() except: # exc = sys.exc_info()[1] lib_common.ErrorMessageHtml("Caught:"+str(exc)) for objVHost in listVHosts: namVHost = objVHost["name"] sys.stderr.write("q=%s\n"%(namVHost)) nodeVHost = survol_rabbitmq_vhost.MakeUri(configNam,namVHost) try: grph.add( ( nodeVHost, lib_common.MakeProp("tracing"), lib_common.NodeLiteral(objVHost["tracing"]) ) ) except KeyError: pass try: grph.add( ( nodeVHost, lib_common.MakeProp("messages"), lib_common.NodeLiteral(objVHost["messages"]) ) ) except KeyError: pass # http://127.0.0.1:12345/#/vhosts// managementUrl = rabbitmq.ManagementUrlPrefix(configNam,"vhosts",namVHost) grph.add( ( nodeVHost, lib_common.MakeProp("Management"), lib_common.NodeUrl(managementUrl) ) ) grph.add( ( nodeManager, lib_common.MakeProp("Virtual host"), nodeVHost ) ) cgiEnv.OutCgiRdf()
def Main(): cgiEnv = lib_common.CgiEnv() grph = cgiEnv.GetGraph() propPidPath = lib_common.MakeProp("Process") propType = lib_common.MakeProp("Type") propState = lib_common.MakeProp("State") propINode = lib_common.MakeProp("INode") args = [ "netstat", '-a', '--unix', '-p', ] pOpNetstat = lib_common.SubProcPOpen(args) (netstat_last_output, netstat_err) = pOpNetstat.communicate() asstr = netstat_last_output.decode("utf-8") DEBUG("assstr:%s", asstr) # Do not read the header on the first four lines. for lin in asstr.split('\n')[4:]: try: sockType = lin[25:36].strip() # sys.stderr.write("sockType %s\n"%sockType) sockState = lin[36:50].strip() # sys.stderr.write("sockState %s\n"%sockState) sockINode = lin[50:59].strip() # sys.stderr.write("sockINode %s\n"%sockINode) sockPath = lin[80:].strip() except: WARNING("Cannot parse:%s", lin) continue if sockPath: nodePath = lib_common.gUriGen.FileUri(sockPath) grph.add((nodePath, propType, lib_common.NodeLiteral(sockType))) grph.add((nodePath, propState, lib_common.NodeLiteral(sockState))) grph.add((nodePath, propINode, lib_common.NodeLiteral(sockINode))) sockPidProg = lin[59:80].strip() if sockPidProg not in ["-", ""]: sockPidProgSplit = sockPidProg.split("/") sockPid = sockPidProgSplit[0] # sys.stderr.write("sockPid %s\n"%sockPid) # Not used, and index error on Python 3. # sockProgNam = sockPidProgSplit[1] nodeProc = lib_common.gUriGen.PidUri(sockPid) if sockPath: grph.add((nodePath, propPidPath, nodeProc)) # grph.add( ( nodeProc, pc.property_information, lib_common.NodeLiteral(sockProgNam) ) ) cgiEnv.OutCgiRdf()
def Main(): cgiEnv = lib_common.CgiEnv() grph = cgiEnv.GetGraph() dsnNam = survol_odbc_dsn.GetDsnNameFromCgi(cgiEnv) sys.stderr.write("dsn=(%s)\n" % dsnNam) nodeDsn = survol_sqlserver_dsn.MakeUri(dsnNam) ODBC_ConnectString = survol_odbc_dsn.MakeOdbcConnectionString(dsnNam) try: cnxn = pyodbc.connect(ODBC_ConnectString) sys.stderr.write("Connected: %s\n" % dsnNam) cursorQueries = cnxn.cursor() qryQueries = """ SELECT sqltext.TEXT, req.session_id, req.status, sess.host_process_id, sess.host_name FROM sys.dm_exec_requests req CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS sqltext , sys.dm_exec_sessions sess where sess.session_id = req.session_id """ propSqlServerSqlQuery = lib_common.MakeProp("Sql query") propSqlServerHostProcess = lib_common.MakeProp("Host process") propSqlServerStatus = lib_common.MakeProp("Status") for rowQry in cursorQueries.execute(qryQueries): sys.stderr.write("rowQry.session_id=(%s)\n" % rowQry.session_id) nodeSession = session.MakeUri(dsnNam, rowQry.session_id) # A bit of cleanup. queryClean = rowQry.TEXT.replace("\n", " ").strip() # TODO: Must add connection information so we can go from the tables to sqlserver itself. nodeSqlQuery = sql_query.MakeUri(queryClean, dsnNam) grph.add((nodeSession, propSqlServerSqlQuery, nodeSqlQuery)) node_process = lib_common.RemoteBox(rowQry.host_name).PidUri( rowQry.host_process_id) grph.add((node_process, pc.property_pid, lib_common.NodeLiteral(rowQry.host_process_id))) grph.add((nodeSession, propSqlServerHostProcess, node_process)) grph.add((nodeSession, propSqlServerStatus, lib_common.NodeLiteral(rowQry.status))) except Exception: exc = sys.exc_info()[0] lib_common.ErrorMessageHtml("nodeDsn=%s Unexpected error:%s" % (dsnNam, str(sys.exc_info()))) cgiEnv.OutCgiRdf()
def Main(): cgiEnv = lib_common.CgiEnv() grph = cgiEnv.GetGraph() for part in psutil.disk_partitions(): # partition(device='D:\\\\', mountpoint='D:\\\\', fstype='NTFS', opts='rw,fixed') DEBUG("device=%s fstype=%s", part.device, part.fstype) DEBUG("All=%s", str(part)) # BEWARE: This is not very clear. if lib_util.isPlatformWindows: # sdiskpart(device='C:\\', mountpoint='C:\\', fstype='NTFS', opts='rw,fixed') # DeviceID : X: # DriveType : 4 # ProviderName : \\192.168.1.81\rchateau # FreeSpace : 170954825728 # Size : 2949169561600 # VolumeName : rchateau # # WMI does not want a backslash at the end: "C:". # Replacing backslashes is necessary on Windows. partition_name = part.device.replace('\\', '') # We could as well take "Win32_LogicalDisk" because it inherits from "CIM_LogicalDisk" nodePartition = lib_common.gUriGen.UriMake("CIM_LogicalDisk", partition_name) else: # The class CIM_LogicalDisk represents a contiguous range of logical blocks # that is identifiable by a FileSystem via the Disk's DeviceId (key) field. # Each storage extent with the capability of or already hosting a file system # is represented as a sub-class of CIM_LogicalDisk. # The class CIM_LogicalDisk is the connector between File Systems and Storage Extents # [sdiskpart(device='/dev/vda1', mountpoint='/var/lib/docker/containers', fstype='ext4', opts='rw,seclabel,relatime,data=ordered'),] # This does not really work on Windows because WMI expects # something like 'Win32_DiskPartition.DeviceID="Disk #0.Partition #0"' partition_name = part.device nodePartition = lib_common.gUriGen.DiskPartitionUri(partition_name) mount_point = part.mountpoint.replace('\\', '/') nodeMount = lib_common.gUriGen.DirectoryUri(mount_point) # TODO: Check this list. if part.fstype != "": # partition(device='T:\\\\', mountpoint='T:\\\\', fstype='', opts='cdrom') grph.add((nodePartition, pc.property_file_system_type, lib_common.NodeLiteral(part.fstype))) grph.add((nodeMount, pc.property_mount, nodePartition)) if part.opts != "": grph.add((nodeMount, pc.property_mount_options, lib_common.NodeLiteral(part.opts))) cgiEnv.OutCgiRdf()
def Main(): cgiEnv = lib_common.CgiEnv() userNameWithHost = cgiEnv.GetId() if not lib_util.isPlatformLinux: lib_common.ErrorMessageHtml("id command on Linux only") # Usernames have the syntax user@host userSplit = userNameWithHost.split('@') userName = userSplit[0] if len(userSplit) > 1: userHost = userSplit[1] if userHost != lib_util.currentHostname: # TODO: Should interrogate other host with "finger" protocol. lib_common.ErrorMessageHtml( "Cannot get user properties on different host:" + userHost) if not userName: lib_common.ErrorMessageHtml( "Linux username should not be an empty string") grph = cgiEnv.GetGraph() userNode = lib_common.gUriGen.UserUri(userName) id_cmd = ["id", userName] id_pipe = lib_common.SubProcPOpen(id_cmd) (id_last_output, id_err) = id_pipe.communicate() lines = id_last_output.split('\n') sys.stderr.write("id=" + userName + " lines=" + str(lines) + "\n") sys.stderr.write("Lines=" + str(len(lines)) + "\n") # $ id rchateau # uid=500(rchateau) gid=500(guest) groupes=500(guest),81(audio) firstLine = lines[0] sys.stderr.write("First=" + firstLine + "\n") firstSplit = SplitId(firstLine) userId = ParseIdNam(firstSplit[0])[0] grph.add((userNode, pc.property_userid, lib_common.NodeLiteral(userId))) for grpStr in firstSplit[2].split(','): (grpId, grpNam) = ParseIdNam(grpStr) grpNode = lib_common.gUriGen.GroupUri(grpNam) grph.add((grpNode, pc.property_groupid, lib_common.NodeLiteral(grpId))) grph.add((userNode, pc.property_group, grpNode)) cgiEnv.OutCgiRdf()
def Main(): cgiEnv = lib_oracle.OracleEnv() oraSession = cgiEnv.m_entity_id_dict["Session"] grph = cgiEnv.GetGraph() node_oraSession = oracle_session.MakeUri(cgiEnv.m_oraDatabase, oraSession) # TYPE = "VIEW", "TABLE", "PACKAGE BODY" sql_query = "select SID,STATUS,USERNAME,SERVER,SCHEMANAME,COMMAND,MACHINE,PORT,OSUSER,PROCESS,SERVICE_NAME,ACTION from V$SESSION where SID='%s'" % oraSession sys.stderr.write("sql_query=%s\n" % sql_query) result = lib_oracle.ExecuteQuery(cgiEnv.ConnectStr(), sql_query) # There should be only one. for row in result: sys.stderr.write("SID=%s\n" % row[0]) grph.add((node_oraSession, lib_common.MakeProp("Status"), lib_common.NodeLiteral(row[1]))) grph.add((node_oraSession, lib_common.MakeProp("Username"), lib_common.NodeLiteral(row[2]))) grph.add((node_oraSession, lib_common.MakeProp("Server"), lib_common.NodeLiteral(row[3]))) # grph.add( ( node_oraSession, lib_common.MakeProp("Schema"), lib_common.NodeLiteral(row[4]) ) ) nodeSchema = oracle_schema.MakeUri(cgiEnv.m_oraDatabase, str(row[4])) grph.add((node_oraSession, pc.property_oracle_schema, nodeSchema)) grph.add((node_oraSession, lib_common.MakeProp("Command"), lib_common.NodeLiteral(row[5]))) # This returns an IP address from "WORKGROUP\RCHATEAU-HP" user_machine = lib_oracle.OraMachineToIp(row[6]) nodeMachine = lib_common.gUriGen.HostnameUri(user_machine) grph.add((nodeMachine, pc.property_information, lib_common.NodeLiteral(row[6]))) grph.add((node_oraSession, lib_common.MakeProp("Port"), lib_common.NodeLiteral(row[7]))) grph.add((node_oraSession, lib_common.MakeProp("OsUser"), lib_common.NodeLiteral(row[8]))) # grph.add( ( node_oraSession, lib_common.MakeProp("Process"), lib_common.NodeLiteral(row[9]) ) ) sessPidTid = row[9] # 7120:4784 sessPid = sessPidTid.split(":")[0] node_process = lib_common.RemoteBox(user_machine).PidUri(sessPid) grph.add((node_process, lib_common.MakeProp("Pid"), lib_common.NodeLiteral(sessPid))) grph.add((node_oraSession, pc.property_oracle_session, node_process)) grph.add( (node_oraSession, lib_common.MakeProp("Hostname"), nodeMachine)) grph.add((node_oraSession, lib_common.MakeProp("ServiceName"), lib_common.NodeLiteral(row[10]))) grph.add((node_oraSession, lib_common.MakeProp("Action"), lib_common.NodeLiteral(row[11]))) cgiEnv.OutCgiRdf("LAYOUT_RECT")
def AddFileOwnerWindows(grph, filNode, filNam): import win32api import win32con import win32security from sources_types import Win32_UserAccount from sources_types import Win32_Group def SID_CodeToName(typeSID): mapSIDList = { win32security.SidTypeUser: "******", win32security.SidTypeGroup: "Group SID", win32security.SidTypeDomain: "Domain SID", win32security.SidTypeAlias: "Alias SID", win32security.SidTypeWellKnownGroup: "Well-known group", win32security.SidTypeDeletedAccount: "Deleted account", win32security.SidTypeInvalid: "Invalid SID", win32security.SidTypeUnknown: "Unknown type SID", win32security.SidTypeComputer: "Computer SID", # win32security.SidTypeLabel: "Mandatory integrity label SID" # NOT DEFINED } try: return mapSIDList[typeSID] except: return "Unknown SID" #print "I am", win32api.GetUserNameEx (win32con.NameSamCompatible) try: sd = win32security.GetFileSecurity (filNam, win32security.OWNER_SECURITY_INFORMATION) except: exc = sys.exc_info()[1] msg = str(exc) grph.add( ( filNode, pc.property_owner, lib_common.NodeLiteral(msg) ) ) return owner_sid = sd.GetSecurityDescriptorOwner () accountName, domainName, typeCode = win32security.LookupAccountSid (None, owner_sid) typNam = SID_CodeToName(typeCode) sys.stderr.write("Domain=%s Name=%s Type=%s\n" % (domainName, accountName,typNam) ) if typeCode == win32security.SidTypeUser: accountNode = Win32_UserAccount.MakeUri(accountName,domainName) elif typeCode == win32security.SidTypeGroup: accountNode = Win32_Group.MakeUri(accountName,domainName) elif typeCode == win32security.SidTypeWellKnownGroup: accountNode = Win32_Group.MakeUri(accountName,domainName) else: # What else can we do ? accountNode = Win32_UserAccount.MakeUri(accountName,domainName) # TODO: What can we do with the domain ? grph.add( ( accountNode, lib_common.MakeProp("Domain"), lib_common.NodeLiteral(domainName) ) ) grph.add( ( accountNode, lib_common.MakeProp("SID"), lib_common.NodeLiteral(typNam) ) ) grph.add( ( filNode, pc.property_owner, accountNode ) )
def Main(): cgiEnv = lib_common.CgiEnv() configNam = cgiEnv.GetId() nodeManager = survol_rabbitmq_manager.MakeUri(configNam) creds = lib_credentials.GetCredentials("RabbitMQ", configNam) # cl = Client('localhost:12345', 'guest', 'guest') cl = Client(configNam, creds[0], creds[1]) grph = cgiEnv.GetGraph() # cl.is_alive() #>>> cl.get_users() #[{u'hashing_algorithm': u'rabbit_password_hashing_sha256', u'name': u'guest', u'tags': u'administrator', u'password_hash': u'xxxxxx'}] try: # listUsers = cl.get_users() except: # exc = sys.exc_info()[1] lib_common.ErrorMessageHtml("Caught:" + str(exc)) for objUser in listUsers: namUser = objUser["name"] DEBUG("q=%s", namUser) nodeUser = survol_rabbitmq_user.MakeUri(configNam, namUser) try: grph.add((nodeUser, lib_common.MakeProp("Tags"), lib_common.NodeLiteral(objUser["tags"]))) except KeyError: pass try: grph.add((nodeUser, lib_common.MakeProp("Hashing algorithm"), lib_common.NodeLiteral(objUser["hashing_algorithm"]))) except KeyError: pass # http://127.0.0.1:12345/#/users/guest managementUrl = rabbitmq.ManagementUrlPrefix(configNam, "users", namUser) grph.add((nodeUser, lib_common.MakeProp("Management"), lib_common.NodeUrl(managementUrl))) grph.add((nodeManager, lib_common.MakeProp("User"), nodeUser)) cgiEnv.OutCgiRdf()
def Main(): cgiEnv = lib_common.CgiEnv() userNameWithHost = cgiEnv.GetId() # Usernames have the syntax user@host user_split = userNameWithHost.split('@') user_name = user_split[0] if len(user_split) > 1: user_host = user_split[1] if user_host != lib_util.currentHostname: # TODO: Should interrogate other host with "finger" protocol. lib_common.ErrorMessageHtml( "Cannot get user properties on different host:" + user_host) if not user_name: lib_common.ErrorMessageHtml( "Linux username should not be an empty string") grph = cgiEnv.GetGraph() user_node = lib_common.gUriGen.UserUri(user_name) # It runs this Linux command which returns a single line. id_cmd = ["id", user_name] id_pipe = lib_common.SubProcPOpen(id_cmd) (id_last_output, id_err) = id_pipe.communicate() lines = id_last_output.split(b'\n') sys.stderr.write("lines=%s\n" % lines) DEBUG("id=" + user_name + " lines=" + str(lines)) # $ id my_user # uid=500(my_user) gid=500(guest) groupes=500(guest),81(audio) first_line = lines[0] first_split = split_id(first_line) user_id = parse_id_name(first_split[0])[0] grph.add((user_node, pc.property_userid, lib_common.NodeLiteral(user_id))) for grp_str in first_split[2].split(b','): sys.stderr.write("grp_str=%s\n" % grp_str) (group_id, group_name) = parse_id_name(grp_str) grpNode = lib_common.gUriGen.GroupUri(group_name) grph.add( (grpNode, pc.property_groupid, lib_common.NodeLiteral(group_id))) grph.add((user_node, pc.property_group, grpNode)) cgiEnv.OutCgiRdf()
def Main(): cgiEnv = lib_common.CgiEnv() pidInt = int(cgiEnv.GetId()) pidMBean = cgiEnv.m_entity_id_dict["Handle"] # TODO: Not convenient. # mbeanObjNam = cgiEnv.m_entity_id_dict["Name"].replace("*",",").replace("-","=") mbeanObjNam = cgiEnv.m_entity_id_dict["Name"] mbeanObjNam = mbeanObjNam.replace("*", ",").replace("-", "=") # mbeanObjNam = cgi.unescape(mbeanObjNam) grph = cgiEnv.GetGraph() node_process = lib_common.gUriGen.PidUri(pidInt) # proc_obj = psutil.Process(pidInt) jmxData = survol_java.GetJavaDataFromJmx(pidInt, mbeanObjNam) jmxDataMBeans = jmxData["allMBeans"] propMBean = lib_common.MakeProp("MBean") # There should be only one. for jmxMBean in jmxDataMBeans: clsNam = jmxMBean["className"] objNam = jmxMBean["objectName"] if objNam != mbeanObjNam: sys.stderr.write("THIS SHOULD NOT HAPPEN: %s != %s\n" % (objNam, mbeanObjNam)) # "=sun.management.ManagementFactoryHelper$1[java.nio:type=BufferPool,name=mapped]" sys.stderr.write("jmxMBean=%s\n" % jmxMBean) # Not sure about the file name nodeClass = survol_mbean.MakeUri(pidInt, clsNam) grph.add((nodeClass, lib_common.MakeProp("Object name"), lib_common.NodeLiteral(objNam))) dictMBeanInfo = jmxMBean["info"] for keyInfo in dictMBeanInfo: valInfo = dictMBeanInfo[keyInfo] grph.add((nodeClass, lib_common.MakeProp(keyInfo), lib_common.NodeLiteral(valInfo))) grph.add((nodeClass, lib_common.MakeProp("Attributes"), lib_common.NodeLiteral(jmxMBean["attrs"]))) grph.add((node_process, propMBean, nodeClass)) # sys.stderr.write("jmxData=%s\n"%jmxData) cgiEnv.OutCgiRdf()
def DecorateAppWithXml(grph, appNode, elt_app): attr_version = elt_app.getAttributeNode('version').value grph.add((appNode, lib_common.MakeProp("Version"), lib_common.NodeLiteral(attr_version))) attr_notifref = elt_app.getAttributeNode('notifref').value grph.add((appNode, lib_common.MakeProp("Notifref"), lib_common.NodeLiteral(attr_notifref))) attr_cronref = elt_app.getAttributeNode('cronref').value grph.add((appNode, lib_common.MakeProp("Cronref"), lib_common.NodeLiteral(attr_cronref)))
def Main(): cgiEnv = lib_common.CgiEnv() grph = cgiEnv.GetGraph() # Not really useful. grph.add((lib_common.nodeMachine, pc.property_hostname, lib_common.NodeLiteral(lib_util.currentHostname))) mapToProc = {} for proc in CIM_Process.ProcessIter(): # TODO: Instead, should test psutil version !!! try: FunctionProcess(mapToProc, proc) except CIM_Process.AccessDenied: pass except Exception: lib_common.ErrorMessageHtml("Unexpected error:" + str(sys.exc_info()[0])) # sys.stderr.write( "Leaving processes enumeration\n" ) addedProcs = {} # Now display only memory maps with more than one process linked to it. for mapPath, procLst in lib_util.six_iteritems(mapToProc): if len(procLst) <= 0: continue uriMemMap = lib_common.gUriGen.MemMapUri(mapPath) for pid in procLst: try: nodeProcess = addedProcs[pid] except KeyError: nodeProcess = lib_common.gUriGen.PidUri(pid) addedProcs[pid] = nodeProcess grph.add((nodeProcess, pc.property_memmap, uriMemMap)) # sys.stderr.write( "Leaving second maps enumeration\n" ) # TODO: They could also be displayed based on the hierarchy of their # associated file in the directory tree. for pid, nodeProcess in lib_util.six_iteritems(addedProcs): grph.add((nodeProcess, pc.property_pid, lib_common.NodeLiteral(pid))) # TODO: Petit bug: Ca duplique les memmap. Forcement, l'affichage en tables # suppose que c'est un arbre. Mais c'est plus rapide et plus clair. # cgiEnv.OutCgiRdf("",[pc.property_memmap]) cgiEnv.OutCgiRdf("LAYOUT_SPLINE")
def Main(): paramkeyExtensiveScan = "Extensive scan" # Beware that unchecked checkboxes are not posted, i.e. boolean variables set to False. # http://stackoverflow.com/questions/1809494/post-the-checkboxes-that-are-unchecked cgiEnv = lib_common.CgiEnv(parameters={paramkeyExtensiveScan: False}) pidint = int(cgiEnv.GetId()) grph = cgiEnv.GetGraph() paramExtensiveScan = cgiEnv.GetParameters(paramkeyExtensiveScan) # By default, uses a small map of possible connection strings keyword. # Otherwise it is very slow to scan the whole process memory. if paramExtensiveScan: mapRgx = survol_odbc.mapRgxODBC else: mapRgx = survol_odbc.mapRgxODBC_Light aggregDsns = GetAggregDsns(pidint, mapRgx) node_process = lib_common.gUriGen.PidUri(pidint) # TODO: Add a parameter to choose between light and heavy connection string definition. # TODO: Eliminate aggregated strings containing one or two tokens, # because they cannot be genuine DSNs. # 29812569: SERVER=\RCHATEAU-HP # 34515016: Driver={SQL Server};Server=.\SQLEXPRESS;Database=ExpressDB;Trusted_Connection=yes # 34801013: SERVER=\RCHATEAU-HP # 35634904: Driver={SQL Server};Server=.\SQLEXPRESS;Database=ExpressDB;Trusted_Connection=yes for aggregOffset in aggregDsns: # Do not take the character before the keyword. aggregDSN = aggregDsns[aggregOffset] dsnFull = str(aggregOffset) + ": " + aggregDSN sys.stderr.write("aggregOffset=%s dsnFull=%s\n" % (aggregOffset, dsnFull)) grph.add((node_process, pc.property_information, lib_common.NodeLiteral(dsnFull))) ### NO! Confusion between DSN and connection string. # All the existing code does: ODBC_ConnectString = survol_odbc_dsn.MakeOdbcConnectionString(dsnNam) # which basically creates "DSN=dsvNam;PWD=..." but here we already have the connection string. # TODO: Should we assimilate both ??? nodeDsn = survol_odbc_dsn.MakeUri(aggregDSN) grph.add((node_process, pc.property_odbc_dsn, nodeDsn)) # Fix this message. grph.add((nodeDsn, pc.property_odbc_driver, lib_common.NodeLiteral("ODBC driver"))) cgiEnv.OutCgiRdf()
def AddDefaultNodes(grph, rootNode, entity_host): currentNodeHostname = lib_common.gUriGen.HostnameUri( lib_util.currentHostname) grph.add( (currentNodeHostname, pc.property_information, lib_common.NodeLiteral("Current host:" + lib_util.currentHostname))) grph.add((rootNode, pc.property_rdf_data_nolist2, currentNodeHostname)) currUsername = FunctionGetUser() currentNodeUser = lib_common.gUriGen.UserUri(currUsername) grph.add((currentNodeUser, pc.property_information, lib_common.NodeLiteral("Current user:" + currUsername))) grph.add((rootNode, pc.property_rdf_data_nolist2, currentNodeUser))
def DoRemote(grph, cimomSrv): import wmi # TODO: Add the host address to the connection. # TODO: Cache for the connection ? # wmiCnnct = wmi.WMI(cimomSrv) wmiCnnct = wmi.WMI() # TODO: This works but is very slow (About 30 seconds). for winProd in wmiCnnct.Win32_Product(): # instance of Win32_Product # { # AssignmentType = 1; # Caption = "Microsoft Web Deploy 3.5"; # Description = "Microsoft Web Deploy 3.5"; # IdentifyingNumber = "{69A998C5-00A9-42CA-AB4E-C31CFFCD9251}"; # InstallDate = "20150709"; # InstallSource = "C:\\ProgramData\\Package Cache\\{69A998C5-00A9-42CA-AB4E-C31CFFCD9251}v3.1237.1763\\packages\\WebDeploy\\"; # # InstallState = 5; # Language = "1033"; # LocalPackage = "C:\\windows\\Installer\\8a43794.msi"; # Name = "Microsoft Web Deploy 3.5"; # PackageCache = "C:\\windows\\Installer\\8a43794.msi"; # PackageCode = "{28DAC33F-DD0E-4293-9BB0-5585B4D89CB9}"; # PackageName = "WebDeploy_x64.msi"; # Vendor = "Microsoft Corporation"; # Version = "3.1237.1763"; # WordCount = 2; # }; # {69A998C5-00A9-42CA-AB4E-C31CFFCD9251} # Product(Language=u'1033', ProductName=u'Microsoft Web Deploy 3.5', PackageCode=u'{28DAC33F-DD0E-4293-9BB0-5585B4D89CB9}', Transforms # =u'', AssignmentType=u'1', PackageName=u'WebDeploy_x64.msi', InstalledProductName=u'Microsoft Web Deploy 3.5', VersionString=u'3.123 # 7.1763', RegCompany=u'', RegOwner=u'', ProductID=u'', ProductIcon=u'C:\\windows\\Installer\\{69A998C5-00A9-42CA-AB4E-C31CFFCD9251}\\ # MSDeployIcon.exe', InstallLocation=u'', InstallSource=u'C:\\ProgramData\\Package Cache\\{69A998C5-00A9-42CA-AB4E-C31CFFCD9251}v3.123 # 7.1763\\packages\\WebDeploy\\', InstallDate=u'20150709', Publisher=u'Microsoft Corporation', LocalPackage=u'C:\\windows\\Installer\\ # 8a43794.msi', HelpLink=u'', HelpTelephone=u'', URLInfoAbout=u'', URLUpdateInfo=u'') try: productNode = Win32_Product.MakeUri(winProd.Caption) grph.add((productNode, pc.property_information, lib_common.NodeLiteral(winProd.Description))) grph.add((productNode, lib_common.MakeProp("IdentifyingNumber"), lib_common.NodeLiteral(winProd.IdentifyingNumber))) Win32_Product.AddInstallSource(grph, productNode, winProd) grph.add((lib_common.nodeMachine, lib_common.MakeProp("Win32_Product"), productNode)) except: exc = sys.exc_info()[1] lib_common.ErrorMessageHtml("Caught:%s" % str(exc))
def Main(): cgiEnv = lib_common.CgiEnv() # TODO: The subscription will become a parameter with a default value. # serviceName = cgiEnv.GetId() diskName = cgiEnv.m_entity_id_dict["Disk"] # TODO: This should be a parameter. subscriptionName = cgiEnv.m_entity_id_dict["Subscription"] # subscriptionName=Azure.DefaultSubscription() grph = cgiEnv.GetGraph() (subscription_id,certificate_path) = lib_credentials.GetCredentials( "Azure", subscriptionName ) sms = ServiceManagementService(subscription_id, certificate_path) subscriptionNode = subscription.MakeUri( subscriptionName ) dsk = sms.get_disk(diskName) sys.stderr.write("dsk=%s\n"% str(dir(dsk))) diskNode = disk.MakeUri( diskName, subscriptionName ) grph.add( ( subscriptionNode, lib_common.MakeProp("Service"), diskNode ) ) # grph.add( ( diskNode, lib_common.MakeProp("xxx"), lib_common.NodeLiteral(str(dir(dsk))) ) ) grph.add( ( diskNode, lib_common.MakeProp("affinity_group"), lib_common.NodeLiteral(dsk.affinity_group))) # grph.add( ( diskNode, lib_common.MakeProp("attached_to"), lib_common.NodeLiteral(str(dir(dsk.attached_to)))) ) grph.add( ( diskNode, lib_common.MakeProp("has_operating_system"), lib_common.NodeLiteral(dsk.has_operating_system))) grph.add( ( diskNode, lib_common.MakeProp("is_corrupted"), lib_common.NodeLiteral(dsk.is_corrupted)) ) grph.add( ( diskNode, lib_common.MakeProp("label"), lib_common.NodeLiteral(dsk.label)) ) grph.add( ( diskNode, lib_common.MakeProp("Size"), lib_common.NodeLiteral(dsk.logical_disk_size_in_gb))) grph.add( ( diskNode, lib_common.MakeProp("name"), lib_common.NodeLiteral(dsk.name))) grph.add( ( diskNode, lib_common.MakeProp("os"), lib_common.NodeLiteral(dsk.os))) grph.add( ( diskNode, lib_common.MakeProp("source_image_name"), lib_common.NodeLiteral(dsk.source_image_name))) grph.add( ( diskNode, lib_common.MakeProp("media link"), lib_common.NodeUrl(dsk.media_link))) locaNode = location.MakeUri( dsk.location, subscriptionName ) grph.add( ( diskNode, lib_common.MakeProp("Location"), locaNode ) ) srvNode = service.MakeUri( dsk.attached_to.hosted_service_name, subscriptionName ) grph.add( ( srvNode, lib_common.MakeProp("Role"), lib_common.NodeLiteral(dsk.attached_to.role_name) ) ) grph.add( ( srvNode, lib_common.MakeProp("Deployment"), lib_common.NodeLiteral(dsk.attached_to.deployment_name) ) ) grph.add( ( diskNode, lib_common.MakeProp("Service"), srvNode ) ) # media_link cgiEnv.OutCgiRdf("LAYOUT_RECT_TB")
def Main(): cgiEnv = lib_common.CgiEnv() args = [ "nmap", '-oX', '-', '--script', "broadcast-netbios-master-browser", ] # The returned IP address is wrong when launched from a Windows machine where the DB is running. p = lib_common.SubProcPOpen(args) grph = cgiEnv.GetGraph() (nmap_last_output, nmap_err) = p.communicate() dom = xml.dom.minidom.parseString(nmap_last_output) # <script id="broadcast-netbios-master-browser" output="..."/> # TODO: Remove line "ip server domain" for aScript in dom.getElementsByTagName('script'): # output="
ip server domain
192.168.0.15 WDMYCLOUDMIRROR WORKGROUP
" anOutput = aScript.getAttributeNode('output').value.strip() sys.stderr.write("anOutput=%s\n" % str(anOutput)) arrSplit = [aWrd.strip() for aWrd in anOutput.split("\n")] sys.stderr.write("arrSplit=%s\n" % str(arrSplit)) theMachFull = arrSplit[1].strip() sys.stderr.write("theMachFull=%s\n" % str(theMachFull)) machSplit = re.split("[\t ]+", theMachFull) sys.stderr.write("machSplit=%s\n" % str(machSplit)) machIp = machSplit[0].strip() machNam = machSplit[1].strip() nameDomain = machSplit[2].strip() nodeHost = lib_common.gUriGen.HostnameUri(machNam) grph.add((nodeHost, lib_common.MakeProp("IP address"), lib_common.NodeLiteral(machIp))) grph.add((nodeHost, lib_common.MakeProp("Domain"), lib_common.NodeLiteral(nameDomain))) grph.add((nodeHost, pc.property_information, lib_common.NodeLiteral(arrSplit[0]))) cgiEnv.OutCgiRdf()
def Main(): cgiEnv = lib_common.CgiEnv() grph = cgiEnv.GetGraph() # With a dictionary so node are created once only. # This attribute belongs to the function (defintion), and not to the function call. # Must be mindful of threading and recursion. Main.dict__pid_to_node = {} def _pid_to_node(pid): try: return Main.dict__pid_to_node[pid] except KeyError: node = lib_common.gUriGen.PidUri(pid) Main.dict__pid_to_node[pid] = node return node # Problem here: There is a second loopkup to get the name of the process. # In the mean time, the process might have disappeared. # Another problem due to Windows is that a parent process might have exit, # although it children processes are not reassigned (As it is the case on Unix). # This is a "non-existent process". for proc in CIM_Process.ProcessIter(): if lib_common.is_useless_process(proc): continue pid = proc.pid parent_pid = CIM_Process.PsutilProcToPPid(proc) # Built the same way in other RDF documents. node_process = _pid_to_node(pid) parent_node_process = _pid_to_node(parent_pid) # We avoid duplicating the edges. Why would the RDF merge do? grph.add((node_process, pc.property_ppid, parent_node_process)) grph.add((node_process, pc.property_pid, lib_common.NodeLiteral(pid))) usr_nam = CIM_Process.PsutilProcToUser(proc, None) if usr_nam: grph.add((node_process, pc.property_user, lib_common.NodeLiteral(usr_nam))) # TODO: Add the username as a property ? Change the color with the username ? # TODO: Get icons of users or programs, use their colors ? # TODO: Or get the graphic chart of any software related to a resource ? cgiEnv.OutCgiRdf()