Exemplo n.º 1
0
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()
Exemplo n.º 2
0
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()
Exemplo n.º 3
0
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()
Exemplo n.º 4
0
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()
Exemplo n.º 5
0
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()
Exemplo n.º 6
0
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
Exemplo n.º 7
0
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)
Exemplo n.º 8
0
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")
Exemplo n.º 9
0
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()
Exemplo n.º 10
0
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()