def Main(): # TODO: can_process_remote should be suppressed because it duplicates CanProcessRemote cgiEnv = lib_common.ScriptEnvironment(can_process_remote=True) pid = int(cgiEnv.GetId()) machine_name = cgiEnv.GetHost() grph = cgiEnv.GetGraph() cimom_url = lib_wbem.HostnameToWbemServer(machine_name) logging.debug("currentHostname=%s pid=%d machine_name=%s cimom_url=%s", lib_util.currentHostname, pid, machine_name, cimom_url) try: conn_wbem = lib_wbem.WbemConnection(cimom_url) except Exception as exc: lib_common.ErrorMessageHtml("Connecting to :" + cimom_url + " Caught:" + str(exc)) name_space = "root/cimv2" try: inst_lists = conn_wbem.ExecQuery( "WQL", 'select * from CIM_Process where Handle="%s"' % pid, name_space) except Exception as exc: lib_common.ErrorMessageHtml("Error:" + str(exc)) class_name = "CIM_Process" dict_props = {"Handle": pid} root_node = lib_util.EntityClassNode(class_name, name_space, cimom_url, "WBEM") # There should be only one object, hopefully. for an_inst in inst_lists: dict_inst = dict(an_inst) host_only = lib_util.EntHostToIp(cimom_url) uri_inst = lib_uris.MachineBox(host_only).node_from_dict( class_name, dict_props) grph.add((root_node, lib_common.MakeProp(class_name), uri_inst)) url_namespace = lib_wbem.NamespaceUrl(name_space, cimom_url, class_name) nod_namespace = lib_common.NodeUrl(url_namespace) grph.add((root_node, pc.property_cim_subnamespace, nod_namespace)) # None properties are not printed. for iname_key in dict_inst: iname_val = dict_inst[iname_key] # TODO: If this is a reference, create a Node !!!!!!! if not iname_val is None: grph.add((uri_inst, lib_common.MakeProp(iname_key), lib_util.NodeLiteral(iname_val))) # TODO: Call the method Associators(). Idem References(). cgiEnv.OutCgiRdf()
def Main(): cgiEnv = lib_common.ScriptEnvironment() hostname = cgiEnv.GetId() nodeHost = lib_uris.gUriGen.HostnameUri(hostname) grph = cgiEnv.GetGraph() # Loop over the shares. shareresume = 0 while 1: try: # If running on the local machine, pass the host as None otherwise authorization is checked # just like a remote machine, which means User Account Control (UAC) disabling, # and maybe setting LocalAccountTokenFilterPolicy=1 if lib_util.is_local_address(hostname): hostname_or_None = None level = 2 # 1,2 else: hostname_or_None = hostname level = 1 # 1,2 sharedata, total, shareresume = win32net.NetShareEnum( hostname_or_None, level, shareresume) except Exception as exc: # "Access is denied." lib_common.ErrorMessageHtml("Hostname=" + hostname + ". Exception:" + str(exc)) for share in sharedata: logging.debug("share=%s", str(share)) # share={'remark': 'Remote Admin', 'passwd': None, 'current_uses': 0, 'netname': 'ADMIN$', 'max_uses': 4294967295, 'path': 'C:\\\\Windows', 'type': 2147483648, 'permissions': 0} share_netname = share['netname'] try: share_path = share['path'] share_remark = share['remark'] except: share_path = "" share_remark = "" shareNode = lib_uris.MachineBox(hostname).SmbShareUri( share_netname) grph.add((nodeHost, pc.property_smbshare, shareNode)) if share_path: mountNode = lib_uris.gUriGen.FileUri(share_path) grph.add((shareNode, pc.property_smbmount, mountNode)) if share_remark: grph.add((shareNode, pc.property_information, lib_util.NodeLiteral(share_remark))) if not shareresume: break cgiEnv.OutCgiRdf()
def Main(): cgiEnv = lib_common.ScriptEnvironment() smb_server = cgiEnv.GetId() grph = cgiEnv.GetGraph() node_smb_shr = lib_uris.gUriGen.SmbServerUri(smb_server) smbclient_cmd = ["smbclient", "-L", smb_server, "-N"] smbclient_pipe = lib_common.SubProcPOpen(smbclient_cmd) smbclient_last_output, smbclient_err = smbclient_pipe.communicate() lines = smbclient_last_output.split('\n') mode_shared_list = False for lin in lines: # Normally this is only the first line # session setup failed: NT_STATUS_LOGON_FAILURE mtch_net = re.match(r"^.*(NT_STATUS_.*)", lin) if mtch_net: lib_common.ErrorMessageHtml("Smb failure: " + mtch_net.group(1) + " to smb share:" + smb_server) if re.match(r"^\sServer\s+Comment", lin): mode_shared_list = False continue if re.match(r"^\sWorkgroup\s+Master", lin): mode_shared_list = False continue if re.match(r"^\sSharename\s+Type\s+Comment", lin): mode_shared_list = True continue if re.match(r"^\s*----+ +---+ +", lin): continue if mode_shared_list: # The type can be "Disk", "Printer" or "IPC". mtch_share = re.match(r"^\s+([^\s]+)\s+Disk\s+(.*)$", lin) if mtch_share: share_name = mtch_share.group(1) share_node = lib_uris.MachineBox(smb_server).SmbShareUri( share_name) grph.add((node_smb_shr, pc.property_smbshare, share_node)) cgiEnv.OutCgiRdf()
def Main(): cgiEnv = lib_common.ScriptEnvironment() grph = cgiEnv.GetGraph() # C:\Users\the_user>wmic logicaldisk get name,description,ProviderName # Description Name ProviderName # Local Fixed Disk C: # Local Fixed Disk D: # Local Fixed Disk E: # CD-ROM Disc F: # Network Connection Y: \\192.168.1.115\EmuleDownload # Network Connection Z: \\192.168.1.61\Public drivelist = lib_common.SubProcPOpen('wmic logicaldisk get name,description,ProviderName') drivelisto, err = drivelist.communicate() strlist = drivelisto if lib_util.is_py3: strlist_str = str(strlist, encoding='utf8') else: strlist_str = str(strlist) drive_lines = strlist_str.split('\n') for lin in drive_lines[1:]: devtype = lin[0:18].strip() devname = lin[20:21] devprov = lin[22:].strip() # End of the list not interesting. if devtype == "": break if devtype != "Network Connection": continue dev_split = devprov.split('\\') host_name = dev_split[2] share_name = dev_split[3] share_box = lib_uris.MachineBox(host_name) remote_share_node = share_box.SmbShareUri(share_name) host_node = lib_uris.gUriGen.HostnameUri(host_name) # See net_use.py which creates the same type of output. Win32_NetworkConnection key is the disk name. connected_disk_node = lib_uris.gUriGen.Win32_NetworkConnectionUri(devname) connected_file_node = lib_uris.gUriGen.FileUri(devname) logging.debug("share_name=%s", share_name) logging.debug("share_box=%s", share_box) grph.add((connected_disk_node, pc.property_mount, remote_share_node)) grph.add((host_node, pc.property_smbshare, remote_share_node)) cgiEnv.OutCgiRdf()
def Main(): cgiEnv = lib_common.ScriptEnvironment() # TODO: Should test Linux instead ? if lib_util.isPlatformWindows: lib_common.ErrorMessageHtml("smbtree not available on Windows") grph = cgiEnv.GetGraph() smbtree_cmd = ["smbtree", "-N", "-b", "--debuglevel=0"] smbtree_pipe = lib_common.SubProcPOpen(smbtree_cmd) smbtree_last_output, smbtree_err = smbtree_pipe.communicate() lines = smbtree_last_output.split('\n') for lin in lines: tst_domain = re.match(r'^([A-Z]+) *', lin) if tst_domain: domain = tst_domain.group(1) continue tst_machine = re.match(r'^[ \t]+\\\\([A-Z0-9_]+)[ \t]+([^\t].*)', lin) if tst_machine: machine = tst_machine.group(1) addr = NetBiosLookup(machine) node_host = lib_uris.gUriGen.HostnameUri(addr) grph.add((node_host, pc.property_netbios, lib_uris.gUriGen.SmbServerUri(machine))) # TODO: Maybe will create a specific node for a domain. grph.add((node_host, pc.property_domain, lib_uris.gUriGen.SmbDomainUri(domain))) continue tst_share = re.match(r'^[ \t]+\\\\([A-Z0-9_]+)\\([^ \t]+)[ \t]+([^\t].*)', lin) if tst_share: machine = tst_share.group(1) share = tst_share.group(2) share_node = lib_uris.MachineBox(machine).SmbShareUri(share) grph.add((node_host, pc.property_smbshare, share_node)) continue cgiEnv.OutCgiRdf()
def SmbBothUriSplit(smb_both): """This receives a SMB share and returns its node, plus the share and the directory.""" shr_mtch = re.match("//([^/]+)/([^/]+)/(.*)", smb_both) if not shr_mtch: return None smb_host = shr_mtch.group(1) smb_shr = shr_mtch.group(2) smb_dir = shr_mtch.group(3) smb_box = lib_uris.MachineBox(smb_host) # Needed if this is the top directory. if smb_dir == "" or smb_dir == "/": node_smb = smb_box.SmbShareUri(smb_shr) else: # Otherwise it is the directory of the current file. node_smb = smb_box.SmbFileUri(smb_shr, smb_dir) return node_smb, smb_shr, smb_dir
def recursive_walk_on_scripts(callback_grph_add, parent_node, entity_type, entity_id, entity_host, flag_show_all): """ This adds to a RDF graph the tree of scripts which can be applied to an object (sometimes called entity) defined by its class and the values of its attributes. If the class is not defined, then it is a top-level script. Scripts are defined by a RDF node: The URL contains the script and the arguments. :param callback_grph_add: The graph to which the scripts are added. :param parent_node: :param entity_type: :param entity_id: :param entity_host: :param flag_show_all: If True, disabled scripts are also returned. :return: """ # This is used when disabled script as returned. script_error_property = lib_common.MakeProp("Script error") def directory_usability_error_node(relative_dir, depth_call): # Maybe there is a usability test in the current module. # The goal is to control all scripts in the subdirectories, from here. try: entity_class = ".".join(relative_dir.split("/")[2:]) imported_module = lib_util.GetEntityModule(entity_class) if imported_module: error_msg = _test_usability(imported_module, entity_type, entity_ids_arr) if error_msg: # If set to True, the directory is displayed even if all its script are not usable. return lib_util.NodeLiteral(error_msg) except IndexError: # If we are at the top-level, no interest for the module. pass return None def recursive_walk_aux(a_parent_node, grand_parent_node, curr_dir, relative_dir, depth_call=1): """This lists the scripts and generate RDF nodes. Returns True if something was added.""" # In case there is nothing. dirs = None for path, dirs, files in os.walk(curr_dir): break # Maybe this class is not defined in our ontology. if dirs == None: logging.warning("dir_to_menu_aux(2) No content in %s", curr_dir) return False # Will still be None if nothing is added. rdf_node = None sub_path = path[len(curr_dir):] relative_dir_sub_path = relative_dir + sub_path arg_dir = relative_dir_sub_path.replace("/", ".")[1:] # If this is a remote host, all scripts are checked because they might have # the flag CanProcessRemote which is defined at the script level, not the directory level. if not entity_host: err_dir_node = directory_usability_error_node(relative_dir, depth_call) if err_dir_node: if flag_show_all: arg_dir_split = arg_dir.split(".") curr_dir_node = lib_util.DirDocNode(".".join(arg_dir_split[:-1]), arg_dir_split[-1]) if not curr_dir_node: curr_dir_node = lib_util.NodeLiteral("Cannot parse relative dir:%s" % arg_dir) callback_grph_add((grand_parent_node, pc.property_script, curr_dir_node), depth_call) callback_grph_add((curr_dir_node, script_error_property, err_dir_node), depth_call) # The directory is not usable, so leave immediately. return False contains_something = False for dir in dirs: # This directory may be generated by our Python interpreter. if dir == "__pycache__": continue full_sub_dir = os.path.join(curr_dir, dir) try: curr_dir_node = lib_util.DirDocNode(arg_dir, dir) except Exception as exc: logging.error("exc=%s", exc) raise if not curr_dir_node: logging.warning("curr_dir_node is None: arg_dir=%s dir=%s", arg_dir, dir) continue sub_relative_dir = relative_dir + "/" + dir sub_entity_class = ".".join(sub_relative_dir.split("/")[2:]) onto_keys = lib_util.OntologyClassKeys(sub_entity_class) # TODO: Beware, if not ontology, returns empty array. Why not returning None ? if onto_keys != []: # Maybe this is a subclass with its own ontology. # So its scripts do not apply to the current class. logging.info("sub_entity_class=%s onto_keys=%s", sub_entity_class, onto_keys) continue something_added = recursive_walk_aux( curr_dir_node, a_parent_node, full_sub_dir, sub_relative_dir, depth_call + 1) # This adds the directory name only if it contains a script. if something_added: # It works both ways, possibly with different properties. callback_grph_add((a_parent_node, pc.property_script, curr_dir_node), depth_call) contains_something = contains_something | something_added for fil in files: # We want to list only the usable Python scripts. if not fil.endswith(".py") or fil == "__init__.py": continue script_path = relative_dir_sub_path + "/" + fil rdf_node = gen_obj.node_from_script_path(script_path, entity_type, encoded_entity_id) error_msg = None try: imported_mod = lib_util.GetScriptModule(arg_dir, fil) except Exception as exc: logging.warning("Caught:%s", exc) error_msg = exc imported_mod = None if not flag_show_all: continue if not error_msg: # Show only scripts which want to be shown. Each script can have an optional function # called Usable(): If it is there and returns False, the script is not displayed. error_msg = _test_usability(imported_mod, entity_type, entity_ids_arr) if error_msg: pass # If this is a local host if not flag_show_all and error_msg and not entity_host: continue # If the entity is on another host, does the script run on remote entities ? # The concept of "CanProcessRemote" is a short-hand to avoid checking # if the remote is in the entity ids. This flag means: # "It is worth anyway investigating on a remote host, if the entity exists there." if entity_host: try: # Script can be used on a remote entity. can_process_remote = imported_mod.CanProcessRemote except AttributeError: can_process_remote = False if not can_process_remote: if not error_msg: error_msg = "%s is local" % entity_host if not flag_show_all: continue else: logging.debug("Script %s %s CAN work on remote entities", arg_dir, fil) # Here, we are sure that the script is added. # TODO: If no script is added, should not add the directory? callback_grph_add((a_parent_node, pc.property_script, rdf_node), depth_call) # Default doc text is file name minus the ".py" extension. nod_modu = lib_util.module_doc_string(imported_mod, fil[:-3]) # nod_modu contains a literal of a str. if not isinstance(nod_modu, rdflib.term.Literal): logging.error("nod_modu=%s should be Literal instead of %s", nod_modu, type(nod_modu)) callback_grph_add((rdf_node, pc.property_information, nod_modu), depth_call) if error_msg: callback_grph_add((rdf_node, script_error_property, lib_util.NodeLiteral(error_msg)), depth_call) # This tells if a script was added in this directory or one of the subdirs. return (rdf_node is not None) | contains_something if entity_host: logging.debug("entity_host=%s", entity_host) # This will not be needed anymore when node_from_script_path properly encode chars like node_from_dict. # TODO: Use base64 for urls, everywhere. Use appropriate encoding for XML, SVG or HTML text. encoded_entity_id = lib_util.EncodeUri(entity_id) entity_ids_arr = lib_util.EntityIdToArray(entity_type, entity_id) if entity_type: # entity_type might contain a slash, for example: "sqlite/table" relative_dir = "/sources_types/" + entity_type else: relative_dir = "/sources_types" directory = lib_util.gblTopScripts + relative_dir gen_obj = lib_uris.MachineBox(entity_host) recursive_walk_aux(parent_node, None, directory, relative_dir, depth_call=1) if entity_type: _add_cim_links(callback_grph_add, parent_node, entity_type, entity_id, gen_obj)
def Main(): cgiEnv = lib_common.ScriptEnvironment(can_process_remote = True) server = cgiEnv.m_entity_id_dict["Domain"] group_name = cgiEnv.m_entity_id_dict["Name"] grph = cgiEnv.GetGraph() try: lib_win32.WNetAddConnect(server) except Exception as exc: lib_common.ErrorMessageHtml("Server=%s Caught:%s" % (server, str(exc))) if lib_util.is_local_address(server): serv_name_or_none = None # So it is compatible with WMI: ".home" removal. serv_name_not_none = lib_uris.TruncateHostname(lib_util.currentHostname) else: serv_name_or_none = server serv_name_not_none = server server_box = lib_uris.MachineBox(server) node_group = survol_Win32_Group.MakeUri(group_name, serv_name_not_none) try: memberresume = 0 while True: member_data, total, member_resume = win32net.NetLocalGroupGetMembers( serv_name_or_none, group_name, 2, memberresume) prop_sid_usage = lib_common.MakeProp("SID Usage") prop_security_identifier = lib_common.MakeProp("Security Identifier") for member in member_data: sid_usage = member['sidusage'] # Converts Sid to username try: member_name, domain, type = win32security.LookupAccountSid(server, member['sid']) except Exception as exc: logging.error("Server=%s Caught:%s", server, str(exc)) continue logging.debug("Member: %s:", str(member)) logging.debug("Lookup: %s: %s", member_name, member['domainandname']) member_node = _member_name_to_node(sid_usage, member_name, serv_name_not_none) grph.add((member_node, pc.property_group, node_group)) grph.add((member_node, prop_sid_usage, lib_util.NodeLiteral(_sid_usage_to_string(sid_usage)))) grph.add((member_node, prop_security_identifier, lib_util.NodeLiteral(member['sid']))) if serv_name_or_none: node_member_remote = serv_name_or_none(sid_usage, member_name, serv_name_or_none, server_box) # TODO: Instead, both object must have the same universal alias grph.add((member_node, pc.property_alias, node_member_remote)) if member_resume == 0: break except Exception as exc: lib_common.ErrorMessageHtml("win32 local groups:" + str(exc)) cgiEnv.OutCgiRdf("LAYOUT_SPLINE")
def Main(): cgiEnv = lib_common.ScriptEnvironment() grph = cgiEnv.GetGraph() net_use_cmd = ["net", "use"] net_use_pipe = lib_common.SubProcPOpen(net_use_cmd) net_use_last_output, net_use_err = net_use_pipe.communicate() # Converts to string for Python3. if lib_util.is_py3: asstr = net_use_last_output.decode("utf-8") else: asstr = net_use_last_output assert isinstance(asstr, str) lines = asstr.split('\n') seen_hyphens = False # When the remote field is too long, the content is split into two lines. for lin in lines: logging.debug("lin=%s", lin) assert isinstance(lin, str) if re.match(".*-------.*", lin): seen_hyphens = True continue if re.match(".*The command completed successfully.*", lin): break if not seen_hyphens: continue lin = lin.strip() if lin.startswith("Microsoft Windows Network"): # End of the previous line. continue lin_split = lin.split() if lin_split[0] not in ["OK", "Disconnected", "Unavailable"]: lib_common.ErrorMessageHtml("Line is not ok:" + str(lin_split)) if re.match("[A-Z]:", lin_split[1]): the_disk = lin_split[1][0].upper() the_path = lin_split[2] else: the_disk = "" the_path = lin_split[1] if not the_path.startswith("\\\\"): # "\\192.168.0.15\the_directory" lib_common.ErrorMessageHtml("Invalid path:" + the_path) the_path_split = the_path.split("\\") try: share_host = the_path_split[2] share_name = the_path_split[3] except IndexError: lib_common.ErrorMessageHtml("Cannot parse the_path=%s", the_path) # "\\192.168.0.15\the_directory Microsoft Windows Network" # This is a normal share but on a remote machine. share_box = lib_uris.MachineBox(share_host) remote_share_node = share_box.SmbShareUri(share_host) remote_server_node = lib_uris.gUriGen.HostnameUri(share_host) # Win32_NetworkConnection: The key is the disk name. connected_disk_node = lib_uris.gUriGen.Win32_NetworkConnectionUri( the_disk) connected_file_node = lib_uris.gUriGen.FileUri(the_disk) logging.debug("share_name=%s", share_name) logging.debug("share_box=%s", share_box) grph.add((connected_disk_node, pc.property_mount, remote_share_node)) grph.add((remote_server_node, pc.property_smbshare, remote_share_node)) cgiEnv.OutCgiRdf()
def Main(): cgiEnv = lib_common.ScriptEnvironment() # Ex: "//LONW00052257.euro.net.intra/D$" smb_shr = cgiEnv.GetId() if not lib_util.isPlatformWindows: lib_common.ErrorMessageHtml("NET command on Windows only") # If called fron cgiserver.py, double slashes are collapsed into one. shr_match = re.match("/?/([^/]+)/([^/]+)", smb_shr) if not shr_match: # It can also tolerate backslahes. smb_shr = smb_shr.replace("\\", "/") shr_match = re.match("/?/([^/]+)/([^/]+)", smb_shr) if not shr_match: # It also accepts backslashes instead of slashes. lib_common.ErrorMessageHtml("Invalid share name:%s" % smb_shr) host_name = shr_match.group(1) host_node = lib_uris.gUriGen.HostnameUri(host_name) shr_nam = shr_match.group(2) node_smb_shr = lib_uris.gUriGen.SmbShareUri(smb_shr) grph = cgiEnv.GetGraph() # TODO: This can work only on the local machine. net_share_cmd = ["net", "share", shr_nam] net_share_pipe = lib_common.SubProcPOpen(net_share_cmd) net_share_last_output, net_share_err = net_share_pipe.communicate() # Converts to string for Python3. asstr = net_share_last_output.decode("utf-8") # Share name ShrProvTuto # Path C:\Users\jsmith\Developpement\ReverseEngineeringApps\SharedProviderTutorial # Remark # Maximum users No limit lines = asstr.split('\n') prop_map = dict() shr_path = None for lin in lines: txt_content = lin[18:].strip() if lin.startswith("Path"): shr_path = txt_content else: prop_key = lin[:18].strip() if prop_key: prop_map[prop_key] = txt_content for prop_key in prop_map: prop_val = prop_map[prop_key] grph.add((node_smb_shr, lib_common.MakeProp(prop_key), rdflib.Literal(prop_val))) if shr_path: mount_node = lib_uris.MachineBox( lib_util.currentHostname).FileUri(shr_path) grph.add((node_smb_shr, pc.property_smbmount, mount_node)) grph.add((node_smb_shr, pc.property_host, host_node)) cgiEnv.OutCgiRdf()