コード例 #1
0
ファイル: osx_stack.py プロジェクト: EPFL-ENAC/ENACdrives
def pexpect_ask_password(values):
    """
        Interact with process when pexpect found a matching string for password question
        It may Ack previously entered password if several password are asked in the same run.

        This is a mirror from lin_stack.pexpect_ask_password
    """
    process_question = values["child_result_list"][-1]
    try:
        for pattern, auth_realm in values["extra_args"]["auth_realms"]:
            if re.search(pattern, process_question):
                if values["extra_args"]["process_meta"].setdefault(
                        "previous_auth_realm", None) == None:
                    password_mistyped = False
                elif values["extra_args"]["process_meta"][
                        "previous_auth_realm"] != auth_realm:
                    values["extra_args"]["key_chain"].ack_password(
                        values["extra_args"]["process_meta"]
                        ["previous_auth_realm"])
                    password_mistyped = False
                else:
                    password_mistyped = True
                values["extra_args"]["process_meta"][
                    "previous_auth_realm"] = auth_realm
                return values["extra_args"]["key_chain"].get_password(
                    auth_realm, password_mistyped) + "\n"
    except CancelOperationException:
        Output.normal("Operation cancelled.")
        values["extra_args"]["process_meta"]["was_cancelled"] = True
        # Stop current process
        return True
コード例 #2
0
ファイル: cli.py プロジェクト: EPFL-ENAC/ENACdrives
    def __init__(self, args):
        self.args = args
        self.key_chain = Key_Chain(self)

        self.returncode = None

        self.set_username(args)
        self.cfg = conf.get_config()
        Output.verbose(pprint.pformat(self.cfg))

        self.networks_check = Networks_Check(self.cfg, self)
        self.networks_check.scan()

        self.entries = []
        already_added = []
        for m_name in self.cfg["global"].get("entries_order", ()):
            if m_name in self.cfg["CIFS_mount"]:
                entry = CIFS_Mount(self, self.cfg, m_name, self.key_chain)
                self.entries.append(entry)
                already_added.append(m_name)
                self.cfg["CIFS_mount"][m_name]["entry"] = entry
            else:
                Output.warning("Entry not found '{0}'.".format(m_name))
        for m_name in self.cfg["CIFS_mount"]:
            if m_name not in already_added:
                entry = CIFS_Mount(self, self.cfg, m_name, self.key_chain)
                self.entries.append(entry)
                self.cfg["CIFS_mount"][m_name]["entry"] = entry

        os_check(self)
コード例 #3
0
def open_file_manager(mount):
    def _cb(success, output, exit_code):
        pass

    path = mount.settings["Windows_letter"]
    cmd = [s.format(path=path) for s in WIN_CONST.CMD_OPEN.split(" ")]
    Output.verbose("cmd: " + " ".join(cmd))
    NonBlockingQtProcess(cmd, _cb)
コード例 #4
0
ファイル: conf.py プロジェクト: EPFL-ENAC/ENACdrives
 def expect_option(entry, section, option, alert=True, ored_options=None):
     if option not in entry:
         if alert:
             if ored_options is not None:
                 option = "' or '".join(ored_options)
             Output.error("expected '{}' option in {} section.".format(option, section))
         return False
     return True
コード例 #5
0
ファイル: conf.py プロジェクト: EPFL-ENAC/ENACdrives
 def save_current_section():
     try:
         name = current_section_values["name"]
         del(current_section_values["name"])
         cfg.setdefault(current_section_name, {})
         cfg[current_section_name].setdefault(name, {})
         cfg[current_section_name][name].update(current_section_values)
     except KeyError:
         Output.error("Expected name option not found at line {}. Skipping that section.".format(section_line_nb))
コード例 #6
0
ファイル: cli.py プロジェクト: EPFL-ENAC/ENACdrives
 def get_password(self, realm, password_mistyped):
     # For Key_Chain
     if password_mistyped:
         Output.cli(
             "Password mistyped. Please re-type '{}' password".format(
                 realm))
     else:
         Output.cli("Please type '{}' password".format(realm))
     return getpass.getpass()
コード例 #7
0
ファイル: cli.py プロジェクト: EPFL-ENAC/ENACdrives
 def set_username(self, args):
     if args.username is not None:
         validation_answer = validate_username(args.username)
         if validation_answer == "ok":
             Output.cli(
                 "\033[01;37m*** ENACdrives username set to {} ***\033[00m".
                 format(args.username))
             conf.save_username(args.username)
         else:
             Output.error(validation_answer)
             self.execution_status(2)
コード例 #8
0
 def _cb(is_m):
     # Output.debug("cifs_mount._cb")
     if is_m != self._cache["is_mounted"]:
         Output.normal("--> CIFS_mount {} : {} -> {}".format(self.settings["name"], self._cache["is_mounted"], is_m))
         if is_m:
             cifs_post_mount(self)
         else:
             cifs_post_umount(self)
         self._cache["is_mounted"] = is_m
     if cb is not None:
         cb(is_m)
コード例 #9
0
ファイル: osx_stack.py プロジェクト: EPFL-ENAC/ENACdrives
def cifs_umount(mount):
    def _cb(success, output, exit_code):
        if not success:
            mount.ui.notify_user("Umount failure :<br>{}".format(output))

    cmd = [OSX_CONST.CMD_UMOUNT, "\"{local_path}\"".format(**mount.settings)]
    Output.verbose("cmd: " + " ".join(cmd))
    NonBlockingQtProcess(
        cmd,
        _cb,
    )
コード例 #10
0
ファイル: osx_stack.py プロジェクト: EPFL-ENAC/ENACdrives
def cifs_post_umount(mount):
    """
    Performs tasks when umount is done.
    May happen some seconds after cifs_umount is completed (OS)
    """
    if (os.path.isdir(mount.settings["local_path"])
            and os.listdir(mount.settings["local_path"]) == []):
        try:
            os.rmdir(mount.settings["local_path"])
        except OSError as e:
            Output.warning("Could not rmdir : {0}".format(e))
コード例 #11
0
ファイル: cli.py プロジェクト: EPFL-ENAC/ENACdrives
 def show_msgs(self):
     for msg in self.cfg["msg"]:
         pre = " "
         post = ""
         if self.cfg["msg"][msg]["icon"] == "info":
             pre = "\033[01;37m -> INFO: "
             post = " <-\033[00m"
         if self.cfg["msg"][msg]["icon"] == "warning":
             pre = "\033[01;33m !! WARNING: "
             post = " !!\033[00m"
         if self.cfg["msg"][msg]["icon"] == "critical":
             pre = "\033[01;31m !!! CRITICAL: "
             post = " !!!\033[00m"
         Output.cli(pre + self.cfg["msg"][msg]["text"] + post)
コード例 #12
0
def cifs_umount(mount):
    try:
        Output.verbose("Doing umount of {0}".format(
            mount.settings["Windows_letter"]))
        win32wnet.WNetCancelConnection2(mount.settings["Windows_letter"], 0,
                                        False)
        cifs_uncache_is_mounted(mount)
    except pywintypes.error as e:
        if e.winerror == 2401:  # (2401, "WNetCancelConnection2", "There are open files on the connection.")
            mount.ui.notify_user(e.strerror)
        elif e.winerror == 2250:  # (2250, 'WNetCancelConnection2', 'This network connection does not exist.')
            mount.ui.notify_user(e.strerror)
        else:
            Output.error("failed : {0}".format(e))
            debug_send("umount:\n{0}".format(e))
コード例 #13
0
def open_file_manager(mount):
    def _cb(success, output, exit_code):
        pass

    if (mount.settings["Linux_CIFS_method"] == "gvfs"
            and not mount.settings["Linux_gvfs_symlink"]):
        path = None
        for f in os.listdir(LIN_CONST.GVFS_DIR):
            if LIN_CONST.GVFS_GENERATION == 1:
                if re.match(
                        r"{server_share} \S+ {server_name}".format(
                            **mount.settings), f):
                    path = os.path.join(LIN_CONST.GVFS_DIR, f,
                                        mount.settings["server_subdir"])
            else:
                if (re.match(r"^smb-share:", f) and re.search(
                        r"domain={realm_domain}(,|$)".format(**mount.settings),
                        f,
                        flags=re.IGNORECASE) and re.search(
                            r"server={server_name}(,|$)".format(
                                **mount.settings), f) and re.search(
                                    r"share={server_share}(,|$)".format(
                                        **mount.settings), f)
                        and re.search(
                            r"user={realm_username}(,|$)".format(
                                **mount.settings), f)):
                    path = os.path.join(LIN_CONST.GVFS_DIR, f,
                                        mount.settings["server_subdir"])
        if path is None:
            raise Exception("Error: Could not find the GVFS mountpoint.")
    else:
        path = mount.settings["local_path"]
    if LIN_CONST.CMD_OPEN is None:
        Output.warning(
            "Cannot open location '{}', xdg-open not found.".format(path))
        return
    cmd = [s.format(path=path) for s in LIN_CONST.CMD_OPEN.split(" ")]
    Output.verbose("cmd: " + " ".join(cmd))
    NonBlockingQtProcess(
        cmd,
        _cb,
    )
コード例 #14
0
def cifs_post_umount(mount):
    """
    Performs tasks when umount is done.
    May happen some seconds after cifs_umount is completed (OS)
    """
    if mount.settings["Linux_CIFS_method"] == "gvfs":
        # 2) Remove symlink
        if mount.settings["Linux_gvfs_symlink"]:
            if (os.path.lexists(mount.settings["local_path"])
                    and not os.path.exists(mount.settings["local_path"])):
                os.unlink(mount.settings["local_path"])

    else:  # "mount.cifs"
        # 2) Remove mount dir
        try:
            if (os.path.exists(mount.settings["local_path"])
                    and os.listdir(mount.settings["local_path"]) == []):
                os.rmdir(mount.settings["local_path"])
        except OSError as e:
            Output.warning("Could not rmdir : {0}".format(e))
コード例 #15
0
    def load_config(self):
        self.cfg = conf.get_config()
        self.networks_check = Networks_Check(self.cfg, self)
        Output.verbose(pprint.pformat(self.cfg))

        # Delete previous config
        for entry in self.entries:
            entry.destroy()
        self.entries = []

        for msg in self.msgs:
            msg.destroy()
        self.msgs = []

        # Instanciate new config objects
        entries_added = []
        for entry_name in self.cfg["global"].get("entries_order", ()):
            if entry_name in self.cfg["CIFS_mount"]:
                entry = CIFS_Mount(self, self.cfg, entry_name, self.key_chain)
                self.entries.append(UI_Mount_Entry(self, entry))
                entries_added.append(entry_name)
            else:
                Output.warning("Entry not found '{0}'.".format(entry_name))
        for entry_name in self.cfg.get("CIFS_mount", {}):
            if entry_name not in entries_added:
                entry = CIFS_Mount(self, self.cfg, entry_name, self.key_chain)
                self.entries.append(UI_Mount_Entry(self, entry))
        if CONST.OS_SYS == "Windows":
            self.windows_letter_manager.refresh_letters()

        for entry in self.entries:
            self.entries_layer.addLayout(entry)

        for msg in self.cfg["msg"]:
            msg_item = UI_Msg(self.cfg["msg"][msg]["text"],
                              self.cfg["msg"][msg]["icon"])
            self.msgs.append(msg_item)
            self.msgs_layout.addWidget(msg_item)
コード例 #16
0
ファイル: conf.py プロジェクト: EPFL-ENAC/ENACdrives
def save_windows_letter(section_name, letter):
    """
    Parse config file and change/add only what is necessary
    """

    lines = ["", ]
    try:
        with open(CONST.USER_CONF_FILE, "r") as f:
            lines = f.readlines()

        # Parse file, search for name = section_name in [CIFS_mount]
        line_nb = -1
        good_section_name = False
        letter_w_no_section_name_line_nb = None
        skip_this_section = True
        section_name_line_nb = None
        option_line_nb = None
        for l in lines:
            line_nb += 1
            if l.startswith("["):
                good_section_name = False
                letter_w_no_section_name_line_nb = None
                try:
                    current_section = re.match(r"\[(\S+)\]$", l).groups()[0]
                    if current_section == "CIFS_mount":
                        skip_this_section = False
                except AttributeError:
                    skip_this_section = True
                continue
            if skip_this_section:
                continue

            try:
                k, v = re.match(r"([^=]*)=(.*)", l).groups()
                k, v = k.strip(), v.strip()
            except AttributeError:
                continue
            if k == "name":
                if v == section_name:
                    good_section_name = True
                    if letter_w_no_section_name_line_nb is not None:
                        option_line_nb = letter_w_no_section_name_line_nb
                        break
                    if section_name_line_nb is None:
                        section_name_line_nb = line_nb
                else:
                    skip_this_section = True
                continue
            elif k == "Windows_letter":
                if good_section_name:
                    option_line_nb = line_nb
                    break
                else:  # Unknown name=xyz yet
                    letter_w_no_section_name_line_nb = line_nb

        # Windows_letter found in config file
        if option_line_nb is not None:
            Output.verbose("Changing {}'s Windows_letter='{}' in config file {}".format(section_name, letter, CONST.USER_CONF_FILE))
            lines[option_line_nb] = "Windows_letter = {}\n".format(letter)

        # Windows_letter not found, but [CIFS_mount] found
        elif section_name_line_nb is not None:
            Output.verbose("Saving {}'s Windows_letter='{}' in config file {}".format(section_name, letter, CONST.USER_CONF_FILE))
            lines.insert(section_name_line_nb+1, "Windows_letter = {}\n".format(letter))

        # [CIFS_mount] not found
        else:
            Output.verbose("Saving {}'s Windows_letter='{}' in config file {}".format(section_name, letter, CONST.USER_CONF_FILE))
            lines.append("[CIFS_mount]\n")
            lines.append("name = {}\n".format(section_name))
            lines.append("Windows_letter = {}\n".format(letter))
            lines.append("\n")

    except FileNotFoundException:
        Output.verbose("Saving {}'s Windows_letter='{}' to new config file {}".format(section_name, letter, CONST.USER_CONF_FILE))
        lines.append("[CIFS_mount]\n")
        lines.append("name = {}\n".format(section_name))
        lines.append("Windows_letter = {}\n".format(letter))
        lines.append("\n")

    with open(CONST.USER_CONF_FILE, "w") as f:
        f.writelines(lines)
コード例 #17
0
ファイル: cli.py プロジェクト: EPFL-ENAC/ENACdrives
 def notify_user(self, msg):
     # For CIFS_Mount
     Output.cli("Notify_user: " + msg)
コード例 #18
0
def cifs_is_mounted(mount, cb=None):
    """
        evaluate if this mount is mounted
        if cb is None make it synchronously (CLI)
        else make it asynchronously (GUI)
    """
    def _cb_gvfs(success, output, exit_code):
        # Output.debug("lin_stack._cb_gvfs")
        # Output.debug("-> gvfs-mount -l : \n{0}\n\n".format(output))
        share_format1 = re.sub(r"\$", r"\\$", mount.settings["server_share"])
        share_format2 = re.sub(r" ", r"%20", mount.settings["server_share"])
        share_format2 = re.sub(r"\$", r"\\$", share_format2)
        i_search = r"{share_format1} .+ {server_name} -> smb://{realm_domain};{realm_username}@{server_name}/{share_format2}".format(
            share_format1=share_format1,
            share_format2=share_format2,
            **mount.settings)
        for l in output.split("\n"):
            if re.search(i_search, l, flags=re.IGNORECASE):
                # Output.debug(l)
                if cb is None:
                    return True
                else:
                    cb(True)
                    return
        if cb is None:
            return False
        else:
            cb(False)

    def _target_mountcifs():
        return os.path.ismount(mount.settings["local_path"])

    # Output.debug("lin_stack.cifs_is_mounted")
    if mount.settings["Linux_CIFS_method"] == "gvfs":
        if LIN_CONST.GVFS_GENERATION <= 3:
            if LIN_CONST.CMD_GVFS_MOUNT is None:
                Output.error("'gvfs-mount' not installed.")
                return _cb_gvfs(False, "'gvfs-mount' not installed.", 1)
            cmd = [LIN_CONST.CMD_GVFS_MOUNT, "-l"]
        else:
            if LIN_CONST.CMD_GIO_MOUNT is None:
                Output.error("'gio' not installed.")
                return _cb_gvfs(False, "'gio' not installed.", 1)
            cmd = [LIN_CONST.CMD_GIO_MOUNT, "mount", "-l"]
        # Output.debug("cmd: " + " ".join(cmd))
        if cb is None:
            return _cb_gvfs(**BlockingProcess.run(
                cmd,
                env=dict(os.environ, LANG="C", LC_ALL="C", LANGUAGE="C"),
                cache=True,
            ))
        else:
            NonBlockingQtProcess(
                cmd,
                _cb_gvfs,
                env=dict(os.environ, LANG="C", LC_ALL="C", LANGUAGE="C"),
                cache=True,
            )
    else:  # "mount.cifs"
        if cb is None:
            return _target_mountcifs()
        else:
            NonBlockingQtThread(
                "os.path.ismounted.{}".format(mount.settings["local_path"]),
                _target_mountcifs, cb)
コード例 #19
0
ファイル: conf.py プロジェクト: EPFL-ENAC/ENACdrives
def get_config():
    # Create cache_dir if not already existent
    if not os.path.exists(CONST.USER_CACHE_DIR):
        os.makedirs(CONST.USER_CACHE_DIR)

    # HARD CODED CONFIG
    default_config = {
        'global': {
         'Linux_CIFS_method': 'gvfs',
         'Linux_gvfs_symlink': False,
         'Linux_mountcifs_dirmode': '0770',
         'Linux_mountcifs_filemode': '0770',
         'Linux_mountcifs_options': 'rw,nobrl,noserverino,iocharset=utf8,sec=ntlm'},
        'CIFS_mount': {},
        'network': {},
        'realm': {},
        'msg': {},
    }
    cfg = default_config

    # USER CONFIG -> get only username from [global]
    user_config = None
    username = None
    try:
        with open(CONST.USER_CONF_FILE, "r") as f:
            user_config = read_config_source(f)
        username = user_config.get("global", {}).get("username", None)
        if username is not None:
            Output.verbose("Loaded username '{}' from User context. ({})".format(username, CONST.USER_CONF_FILE))
        else:
            Output.normal("Username not found in User context. ({})".format(CONST.USER_CONF_FILE))
    except FileNotFoundException:
        Output.normal("Username not found in User context. ({})".format(CONST.USER_CONF_FILE))

    if username is None:
        if CONST.AD_USERNAME is not None:
            username = CONST.AD_USERNAME
            Output.verbose("Loaded username '{}' from environment variables (user in domain '{}').".format(username, CONST.AD_DOMAIN))
            # Save to config file and reload it for after
            save_username(username)
            with open(CONST.USER_CONF_FILE, "r") as f:
                user_config = read_config_source(f)
        else:
            Output.normal("Username not found in environment variables (user not in a domain).")

    # ENACDRIVE SERVER CONFIG (included cache function)
    if username is not None:
        config_url = CONST.CONFIG_URL.format(username=username)
        cache_filename = os.path.join(CONST.USER_CACHE_DIR, hashlib.md5(config_url.encode()).hexdigest())
        try:
            with urllib.request.urlopen(config_url, timeout=CONST.URL_TIMEOUT) as response:
                lines = [bytes_decode(l) for l in response.readlines()]
                # Output.debug("get_config {} : {}".format(config_url, lines))
                s_io = io.StringIO("".join(lines))
                enacdrives_config = read_config_source(s_io)
                merge_configs(cfg, enacdrives_config)
                s_io.seek(0)
                with open(cache_filename, "w") as f:
                    f.writelines(s_io.readlines())
            Output.verbose("Loaded config from ENACdrives server ({})".format(config_url))
        except (socket.timeout, urllib.error.URLError, ConfigException) as e:
            Output.warning("Could not load config ENACdrives server. ({})".format(config_url))
            Output.warning("Got error : {}".format(e))
            try:
                with open(cache_filename, "r") as f:
                    cached_config = read_config_source(f)
                    merge_configs(cfg, cached_config)
                Output.normal("Loaded config from cache file. ({})".format(cache_filename))
            except FileNotFoundException:
                Output.warning("Could not load config from cache file. ({})".format(cache_filename))
    else:
        Output.normal("Skipping config from ENACdrives server (no username).")

    # SYSTEM CONFIG
    try:
        with open(CONST.SYSTEM_CONF_FILE, "r") as f:
            system_config = read_config_source(f)
            merge_configs(cfg, system_config)
        Output.verbose("Loaded config from System context. ({})".format(CONST.SYSTEM_CONF_FILE))
    except FileNotFoundException:
        Output.normal("No config found from System context. ({})".format(CONST.SYSTEM_CONF_FILE))

    # USER CONFIG
    if user_config is not None:
        merge_configs(cfg, user_config)
        Output.verbose("Loaded config from User context. ({})".format(CONST.USER_CONF_FILE))
    else:
        Output.normal("No config found from User context. ({})".format(CONST.USER_CONF_FILE))

    cfg = validate_config(cfg)
    return cfg
コード例 #20
0
ファイル: cli.py プロジェクト: EPFL-ENAC/ENACdrives
def main_CLI(args):
    Output.verbose("*" * 10 + " " + str(datetime.datetime.now()) + " " +
                   "*" * 10)
    Output.verbose("ENACdrives " + CONST.FULL_VERSION)
    Output.verbose("Detected OS : " + CONST.OS_DISTRIB + " " + CONST.OS_SYS +
                   " " + CONST.OS_VERSION + "\n")
    Output.debug("LOCAL_USERNAME:"******"LOCAL_GROUPNAME:" + CONST.LOCAL_GROUPNAME)
    Output.debug("LOCAL_UID:" + str(CONST.LOCAL_UID))
    Output.debug("LOCAL_GID:" + str(CONST.LOCAL_GID))
    Output.debug("HOME_DIR:" + CONST.HOME_DIR)
    Output.debug("USER_CONF_FILE:" + CONST.USER_CONF_FILE)
    Output.debug("RESOURCES_DIR:" + CONST.RESOURCES_DIR + "\n")
    Output.debug("IMAGES_DIR:" + CONST.IMAGES_DIR + "\n")
    Output.debug("DEFAULT_MNT_DIR:" + CONST.DEFAULT_MNT_DIR + "\n")

    release_number_validation = validate_release_number()
    if release_number_validation == 'too old':
        Output.warning(CONST.NEED_TO_UPDATE_MSG)
    elif release_number_validation == 'newer':
        Output.normal(CONST.NEWER_THAN_PROD_MSG)
    if args.version:
        Output.cli("ENACdrives " + CONST.FULL_VERSION)
        sys.exit(0)
    ui = CLI(args)
    sys.exit(ui.run())
コード例 #21
0
ファイル: conf.py プロジェクト: EPFL-ENAC/ENACdrives
def read_config_source(src):
    """
        Readlines on src
            [global]
            username = bancal
            Linux_CIFS_method = gvfs
            Linux_mountcifs_filemode = 0770
            Linux_mountcifs_dirmode = 0770
            Linux_mountcifs_options = rw,nobrl,noserverino,iocharset=utf8,sec=ntlm
            Linux_gvfs_symlink = true

            [msg]
            name = name this msg
            text = This is a warning notification
            icon = warning

            [network]
            name = Internet
            ping = www.epfl.ch
            ping = enacit.epfl.ch
            error_msg = Error, you are not connected to the network. You won't be able to mount this resource.

            [network]
            name = Epfl
            parent = Internet
            cifs = files0.epfl.ch
            cifs = files1.epfl.ch
            cifs = files8.epfl.ch
            cifs = files9.epfl.ch
            cifs = enac1files.epfl.ch
            error_msg = Error, you are not connected to the intranet of EPFL. Run a VPN client to be able to mount this resource.

            [realm]
            name = EPFL
            domain = INTRANET
            username = bancal

            [CIFS_mount]
            name = private
            label = bancal@files9
            require_network = Epfl
            realm = EPFL
            server_name = files9.epfl.ch
            server_path = data/bancal
            local_path = {MNT_DIR}/bancal_on_files9
            #    {MNT_DIR}
            #    {HOME_DIR}
            #    {DESKTOP_DIR}
            #    {LOCAL_USERNAME}
            #    {LOCAL_GROUPNAME}
            bookmark = false
            #    default : False
            Linux_CIFS_method = gvfs
            #    mount.cifs : Linux's mount.cifs (requires sudo ability)
            #    gvfs : Linux's gvfs-mount
            Linux_mountcifs_filemode = 0770
            Linux_mountcifs_dirmode = 0770
            Linux_mountcifs_options = rw,nobrl,noserverino,iocharset=utf8,sec=ntlm
            Linux_gvfs_symlink = yes
            #    Enables the creation of a symbolic link to "local_path" after mount with gvfs method.
            #    default : False
            Windows_letter = Z:
            #    Drive letter to use for the mount

        And return cfg as
            {'CIFS_mount': {
              'private': {
               'Linux_CIFS_method': 'gvfs',
               'Linux_gvfs_symlink': True,
               'Linux_mountcifs_dirmode': '0770',
               'Linux_mountcifs_filemode': '0770',
               'Linux_mountcifs_options': 'rw,nobrl,noserverino,iocharset=utf8,sec=ntlm',
               'Windows_letter': 'Z:',
               'label': 'bancal@files9',
               'local_path': '{MNT_DIR}/bancal_on_files9',
               'realm': 'EPFL',
               'server_name': 'files9.epfl.ch',
               'server_path': 'data/bancal',
               'bookmark': False,
               'require_network': 'Epfl'}},
             'network': {
              'Internet': {
               'ping': ['www.epfl.ch', 'enacit.epfl.ch'],
               'error_msg': 'Error, you are not connected to the network. You won't be able to mount this resource.'
              },
              'Epfl': {
               'ping': ['files0.epfl.ch', 'files1.epfl.ch', 'files8.epfl.ch', 'files9.epfl.ch'],
               'parent': 'Internet',
               'error_msg': 'Error, you are not connected to the intranet of EPFL. Run a VPN client to be able to mount this resource.'
              }
             }
             'global': {
              'username': '******',
              'Linux_CIFS_method': 'gvfs',
              'Linux_gvfs_symlink': True,
              'Linux_mountcifs_dirmode': '0770',
              'Linux_mountcifs_filemode': '0770',
              'Linux_mountcifs_options': 'rw,nobrl,noserverino,iocharset=utf8,sec=ntlm'},
             'realm': {
              'EPFL': {
               'domain': 'INTRANET',
               'username': '******'}}}

       If >50% of the lines have unexpected content ... then raise ConfigException()
    """

    def save_current_section():
        try:
            name = current_section_values["name"]
            del(current_section_values["name"])
            cfg.setdefault(current_section_name, {})
            cfg[current_section_name].setdefault(name, {})
            cfg[current_section_name][name].update(current_section_values)
        except KeyError:
            Output.error("Expected name option not found at line {}. Skipping that section.".format(section_line_nb))

    multi_entries_sections = ("msg", "CIFS_mount", "realm", "network")
    allowed_options = {
        "global": (
            "username",
            "entries_order",
            "require_network",
            "realm",
            "Linux_CIFS_method",
            "Linux_mountcifs_filemode",
            "Linux_mountcifs_dirmode",
            "Linux_mountcifs_options",
            "Linux_gvfs_symlink",
        ),
        "msg": (
            "name",
            "text",
            "icon",
        ),
        "CIFS_mount": (
            "name",
            "label",
            "require_network",
            "realm",
            "unc",
            "server_name",
            "server_path",
            "local_path",
            "bookmark",
            "Linux_CIFS_method",
            "Linux_mountcifs_filemode",
            "Linux_mountcifs_dirmode",
            "Linux_mountcifs_options",
            "Linux_gvfs_symlink",
            "Windows_letter",
        ),
        "realm": (
            "name",
            "domain",
            "username",
        ),
        "network": (
            "name",
            "parent",
            "ping",
            "cifs",
            "error_msg",
        )
    }

    cfg = {}
    current_section_name = ""
    current_section_values = {}
    line_nb = 0
    section_line_nb = 0
    nb_unexpected_lines = 0
    for line in src.readlines():
        if type(line) == bytes:
            line = bytes_decode(line)
        line_nb += 1
        l = line
        l = re.sub(r"#.*", "", l)  # remove comments
        l = l.strip()  # remove white spaces
        if l == "":
            continue
        # Output.debug(l)

        # New section
        if l.startswith("["):
            try:
                new_section = re.match(r"\[(\S+)\]$", l).groups()[0]
            except AttributeError:
                Output.error("Unexpected content at line {}:\n{}".format(line_nb, line))
                nb_unexpected_lines += 1
                continue
            if current_section_name in multi_entries_sections and current_section_values != {}:
                # Save previous section content
                save_current_section()
            if new_section in allowed_options:
                current_section_name = new_section
                current_section_values = {}
                section_line_nb = line_nb
            else:
                Output.error("Unexpected section name '{}' at line {}:\n{}".format(new_section, line_nb, line))
                current_section_name = ""
                nb_unexpected_lines += 1
            continue

        if current_section_name == "":
            Output.error("Unexpected content at line {}:\n{}".format(line_nb, line))
            nb_unexpected_lines += 1
            continue

        # New option
        try:
            k, v = re.match(r"([^=]*)=(.*)", l).groups()
            k, v = k.strip(), v.strip()
        except AttributeError:
            nb_unexpected_lines += 1
            continue
        if k not in allowed_options[current_section_name]:
            Output.error("Unexpected option at line {}:\n{}".format(line_nb, line))
            nb_unexpected_lines += 1
            continue

        try:
            if current_section_name in multi_entries_sections:
                # This is a multi entries section type
                if current_section_name == "network" and k == "ping":
                    # network.ping is a list
                    current_section_values.setdefault(k, [])
                    current_section_values[k].append(validate_value(k, v))
                elif current_section_name == "network" and k == "cifs":
                    # network.cifs is a list
                    current_section_values.setdefault(k, [])
                    current_section_values[k].append(validate_value(k, v))
                else:
                    # other are literals
                    current_section_values[k] = validate_value(k, v)
            else:
                # This is a single entry section type
                cfg.setdefault(current_section_name, {})[k] = validate_value(k, v)
        except ConfigException as e:
            Output.error(str(e))

        # Output.debug("'{}' = '{}'".format(k, v))

    if current_section_name in multi_entries_sections and current_section_values != {}:
        # Save last section content
        save_current_section()

    if nb_unexpected_lines > (line_nb / 2):
        Output.warning("Found {}/{} ({}%) unexpected lines. Skipping this source.".format(nb_unexpected_lines, line_nb, nb_unexpected_lines*100.0/line_nb))
        raise ConfigException("Too many unexpected lines found. Skipping this source.")
    elif nb_unexpected_lines > 0:
        Output.warning("Found {}/{} ({}%) unexpected lines.".format(nb_unexpected_lines, line_nb, nb_unexpected_lines*100.0/line_nb))

    return cfg
コード例 #22
0
def cifs_mount(mount):
    if mount.settings["Linux_CIFS_method"] == "gvfs":
        # 1) Remove broken symlink or empty dir
        if mount.settings["Linux_gvfs_symlink"]:
            if (os.path.lexists(mount.settings["local_path"])
                    and not os.path.exists(mount.settings["local_path"])):
                os.unlink(mount.settings["local_path"])
            if (os.path.isdir(mount.settings["local_path"])
                    and os.listdir(mount.settings["local_path"]) == []):
                os.rmdir(mount.settings["local_path"])
            if os.path.exists(mount.settings["local_path"]):
                mount.ui.notify_user("Error : Path {} already exists".format(
                    mount.settings["local_path"]))
                return False

        # 2) Mount
        share = re.sub(r" ", r"%20", mount.settings["server_share"])
        if LIN_CONST.GVFS_GENERATION <= 3:
            cmd = [
                LIN_CONST.CMD_GVFS_MOUNT,
                r"smb://{realm_domain}\;{realm_username}@{server_name}/{share}"
                .format(share=share, **mount.settings)
            ]
        else:
            cmd = [
                LIN_CONST.CMD_GIO_MOUNT, "mount",
                r"smb://{realm_domain}\;{realm_username}@{server_name}/{share}"
                .format(share=share, **mount.settings)
            ]
        Output.verbose("cmd: " + " ".join(cmd))
        process_meta = {
            "was_cancelled": False,
        }
        try:
            (output, exit_status) = pexpect.runu(
                command=" ".join(cmd),
                events={
                    "Password:"******"auth_realms": [(r"Password:"******"realm"])],
                    "key_chain": mount.key_chain,
                    "process_meta": process_meta,
                },
                env=dict(os.environ, LANG="C", LC_ALL="C"),
                withexitstatus=True,
                timeout=CONST.MOUNT_TIMEOUT,
            )
        except pexpect.ExceptionPexpect as exc:
            mount.ui.notify_user("Error while mounting :<br>{}".format(
                exc.value))
            return False
        if "error" not in output.lower() and exit_status == 0:
            mount.key_chain.ack_password(mount.settings["realm"])
        else:
            mount.key_chain.invalidate_if_no_ack_password(
                mount.settings["realm"])
            if process_meta["was_cancelled"]:
                return False
            else:
                mount.ui.notify_user("Mount failure :<br>{}".format(output))
                return False
        cifs_uncache_is_mounted(mount)

    else:  # "mount.cifs"
        if LIN_CONST.CMD_MOUNT_CIFS is None:
            mount.ui.notify_user(
                "Error missing binary <b>mount.cifs</b>. On Ubuntu you can install it with <i>sudo apt-get install cifs-utils</i>"
            )
            return False

        # 1) Make mount dir (remove broken symlink if needed)
        if (os.path.lexists(mount.settings["local_path"])
                and not os.path.exists(mount.settings["local_path"])):
            os.unlink(mount.settings["local_path"])
        if not os.path.exists(mount.settings["local_path"]):
            try:
                os.makedirs(mount.settings["local_path"])
            except OSError:
                pass
        if (os.path.islink(mount.settings["local_path"])
                or not os.path.isdir(mount.settings["local_path"])):
            mount.ui.notify_user("Error while creating dir : %s" %
                                 mount.settings["local_path"])
            return False

        # 2) Mount
        s_path = re.sub(" ", "\\ ", mount.settings["server_path"])
        cmd = [
            LIN_CONST.CMD_MOUNT_CIFS, "//{server_name}/{s_path}",
            "{local_path}", "-o",
            "user={realm_username},domain={realm_domain},"
            "uid={local_uid},gid={local_gid},"
            "file_mode={Linux_mountcifs_filemode},"
            "dir_mode={Linux_mountcifs_filemode},"
            "{Linux_mountcifs_options}"
        ]
        if CONST.LOCAL_UID != 0:
            cmd.insert(0, "sudo")
        cmd = [s.format(s_path=s_path, **mount.settings) for s in cmd]
        Output.verbose("cmd: " + " ".join(cmd))
        # for i in xrange(3): # 3 attempts (for passwords mistyped)
        process_meta = {
            "was_cancelled": False,
        }
        (output, exit_status) = pexpect.runu(
            command=" ".join(cmd),
            events={
                "(?i)password": pexpect_ask_password,
            },
            extra_args={
                "auth_realms": [(r"\[sudo\] password", "sudo"),
                                (r"Password", mount.settings["realm"])],
                "key_chain":
                mount.key_chain,
                "process_meta":
                process_meta,
            },
            env=dict(os.environ, LANG="C", LC_ALL="C"),
            withexitstatus=True,
            timeout=CONST.MOUNT_TIMEOUT,
        )
        if exit_status == 0:
            mount.key_chain.ack_password("sudo")
            mount.key_chain.ack_password(mount.settings["realm"])
        else:
            mount.key_chain.invalidate_if_no_ack_password("sudo")
            mount.key_chain.invalidate_if_no_ack_password(
                mount.settings["realm"])
            if process_meta["was_cancelled"]:
                if (os.path.exists(mount.settings["local_path"])
                        and os.listdir(mount.settings["local_path"]) == []):
                    try:
                        os.rmdir(mount.settings["local_path"])
                    except OSError as e:
                        Output.warning("Could not rmdir : {0}".format(e))
            else:
                mount.ui.notify_user("Mount failure : {}".format(output))
                return False
    return True
コード例 #23
0
def cifs_umount(mount):
    def _cb_gvfs(success, output, exit_code):
        if not success:
            mount.ui.notify_user("Umount failure :<br>{}".format(output))
        cifs_uncache_is_mounted(mount)

    if mount.settings["Linux_CIFS_method"] == "gvfs":
        # gvfs umount apparently never locks on open files.

        # 1) Umount
        share = re.sub(r" ", r"%20", mount.settings["server_share"])
        if LIN_CONST.GVFS_GENERATION <= 3:
            cmd = [
                LIN_CONST.CMD_GVFS_MOUNT, "-u",
                r"smb://{realm_domain};{realm_username}@{server_name}/{share}".
                format(share=share, **mount.settings)
            ]
        else:
            cmd = [
                LIN_CONST.CMD_GIO_MOUNT, "mount", "-u",
                r"smb://{realm_domain};{realm_username}@{server_name}/{share}".
                format(share=share, **mount.settings)
            ]
        Output.verbose("cmd: " + " ".join(cmd))

        if mount.ui.UI_TYPE == "GUI":
            NonBlockingQtProcess(
                cmd,
                _cb_gvfs,
                env=dict(os.environ, LANG="C", LC_ALL="C", LANGUAGE="C"),
            )
        else:
            _cb_gvfs(**BlockingProcess.run(
                cmd,
                env=dict(os.environ, LANG="C", LC_ALL="C", LANGUAGE="C"),
            ))

    else:  # "mount.cifs"
        # 1) uMount
        cmd = [LIN_CONST.CMD_UMOUNT, "{local_path}"]
        if CONST.LOCAL_UID != 0:
            cmd.insert(0, "sudo")
        cmd = [s.format(**mount.settings) for s in cmd]
        Output.verbose("cmd: " + " ".join(cmd))
        # for i in xrange(3): # 3 attempts (for passwords mistyped)
        process_meta = {
            "was_cancelled": False,
        }
        (output, exit_status) = pexpect.runu(
            command=" ".join(cmd),
            events={
                "(?i)password": pexpect_ask_password,
            },
            extra_args={
                "auth_realms": [
                    (r"\[sudo\] password", "sudo"),
                ],
                "key_chain": mount.key_chain,
                "process_meta": process_meta,
            },
            env=dict(os.environ, LANG="C", LC_ALL="C"),
            withexitstatus=True,
            timeout=CONST.UMOUNT_TIMEOUT,
        )
        if exit_status == 0:
            mount.key_chain.ack_password("sudo")
        else:
            if process_meta["was_cancelled"]:
                mount.key_chain.invalidate_if_no_ack_password("sudo")
            elif "device is busy" in output:
                mount.key_chain.ack_password("sudo")
                mount.ui.notify_user("Umount failure: Device is busy.")
                return False
            else:
                mount.key_chain.invalidate_if_no_ack_password("sudo")
                mount.ui.notify_user("Umount failure")
                return False
コード例 #24
0
ファイル: conf.py プロジェクト: EPFL-ENAC/ENACdrives
def save_username(username):
    """
    Parse config file and change/add only what is necessary
    """

    lines = ["", ]
    try:
        with open(CONST.USER_CONF_FILE, "r") as f:
            lines = f.readlines()

        # Parse file, search for username = xxx in [global]
        current_section = None
        line_nb = -1
        global_section_line_nb = None
        username_line_nb = None
        for l in lines:
            line_nb += 1
            if l.startswith("["):
                try:
                    current_section = re.match(r"\[(\S+)\]$", l).groups()[0]
                    if current_section == "global" and global_section_line_nb is None:
                        global_section_line_nb = line_nb
                except AttributeError:
                    current_section = None
                continue
            if current_section != "global":
                continue
            try:
                k, v = re.match(r"([^=]*)=(.*)", l).groups()
                k, v = k.strip(), v.strip()
            except AttributeError:
                continue
            if k == "username":
                username_line_nb = line_nb
                break

        # username found in config file
        if username_line_nb is not None:
            Output.verbose("Changing to username='******' in config file {}".format(username, CONST.USER_CONF_FILE))
            lines[username_line_nb] = "username = {}\n".format(username)

        # username not found, but [global] found
        elif global_section_line_nb is not None:
            Output.verbose("Saving username='******' in config file {}".format(username, CONST.USER_CONF_FILE))
            lines.insert(global_section_line_nb+1, "username = {}\n".format(username))

        # [global] not found
        else:
            Output.verbose("Saving username='******' in config file {}".format(username, CONST.USER_CONF_FILE))
            lines.insert(0, "[global]\n")
            lines.insert(1, "username = {}\n".format(username))
            lines.insert(2, "\n")

    except FileNotFoundException:
        Output.verbose("Saving username='******' to new config file {}".format(username, CONST.USER_CONF_FILE))
        lines.insert(0, "[global]\n")
        lines.insert(1, "username = {}\n".format(username))
        lines.insert(2, "\n")

    with open(CONST.USER_CONF_FILE, "w") as f:
        f.writelines(lines)
コード例 #25
0
ファイル: osx_stack.py プロジェクト: EPFL-ENAC/ENACdrives
def cifs_mount(mount):
    # 1) Make mountpoint
    if not os.path.exists(mount.settings["local_path"]):
        try:
            os.makedirs(mount.settings["local_path"])
        except OSError:
            pass
    if not os.path.isdir(mount.settings["local_path"]):
        raise Exception("Error while creating dir : %s" %
                        mount.settings["local_path"])

    # 2) Mount
    s_path = re.sub(r" ", r"%20", mount.settings["server_path"])
    cmd = [
        OSX_CONST.CMD_MOUNT_SMBFS,
        r"//{realm_domain}\;{realm_username}@{server_name}/{s_path}".format(
            s_path=s_path, **mount.settings),
        "\"{local_path}\"".format(**mount.settings)
    ]
    Output.verbose("cmd: " + " ".join(cmd))
    for _ in range(3):  # 3 attempts (for passwords mistyped)
        process_meta = {
            "was_cancelled": False,
        }
        try:
            (output, exit_status) = pexpect.runu(
                command=" ".join(cmd),
                events={
                    "(?i)password": pexpect_ask_password,
                },
                extra_args={
                    "auth_realms": [(r"Password", mount.settings["realm"])],
                    "key_chain": mount.key_chain,
                    "process_meta": process_meta,
                },
                env=dict(os.environ, LANG="C", LC_ALL="C"),
                withexitstatus=True,
                timeout=CONST.MOUNT_TIMEOUT,
            )
        except pexpect.ExceptionPexpect as e:
            raise Exception("Error while mounting : %s" % e.value)
        if exit_status == 0:
            mount.key_chain.ack_password(mount.settings["realm"])
            return True
        elif exit_status == 77:  # Bad password
            mount.key_chain.invalidate_if_no_ack_password(
                mount.settings["realm"])
        else:
            mount.key_chain.invalidate_if_no_ack_password(
                mount.settings["realm"])
            if process_meta["was_cancelled"]:
                if (os.path.isdir(mount.settings["local_path"])
                        and os.listdir(mount.settings["local_path"]) == []):
                    try:
                        os.rmdir(mount.settings["local_path"])
                    except OSError as e:
                        Output.warning("Could not rmdir : {}".format(e))
                return False
            else:
                mount.ui.notify_user("Mount failure :<br>{}".format(output))
                return False
    mount.ui.notify_user("Mount failure")
コード例 #26
0
ファイル: conf.py プロジェクト: EPFL-ENAC/ENACdrives
def validate_config(cfg):
    """
    Validates that there is everything necessary in the config to do the job.
    Will output error message otherwise
    """

    def expect_option(entry, section, option, alert=True, ored_options=None):
        if option not in entry:
            if alert:
                if ored_options is not None:
                    option = "' or '".join(ored_options)
                Output.error("expected '{}' option in {} section.".format(option, section))
            return False
        return True

    invalid_cifs_m = []
    invalid_realm = []
    invalid_network = []
    invalid_msg = []
    expected_realms = {}
    expected_networks_by_CIFS_m = {}
    for m_name in cfg.get("CIFS_mount", {}):
        # If not defined, deduct local_path from m_name
        if "local_path" not in cfg["CIFS_mount"][m_name]:
            cfg["CIFS_mount"][m_name]["local_path"] = "{MNT_DIR}/" + m_name

        # If not defined, deduct label from m_name
        if "label" not in cfg["CIFS_mount"][m_name]:
            cfg["CIFS_mount"][m_name]["label"] = m_name

        # If specified, extract server_name and server_path from unc
        if "unc" in cfg["CIFS_mount"][m_name]:
            m = re.match(r"[\\/]{2}([^\\/]+)[\\/](.*)$", cfg["CIFS_mount"][m_name]["unc"])
            if m:
                cfg["CIFS_mount"][m_name]["server_name"] = m.group(1)
                cfg["CIFS_mount"][m_name]["server_path"] = m.group(2)
            else:
                Output.error("unrecognized 'unc' option in CIFS_mount section ({}).".format(cfg["CIFS_mount"][m_name]["unc"]))

        is_ok = (
            expect_option(cfg["CIFS_mount"][m_name], "CIFS_mount", "label") and
            expect_option(cfg["CIFS_mount"][m_name], "CIFS_mount", "server_name") and
            expect_option(cfg["CIFS_mount"][m_name], "CIFS_mount", "server_path") and
            expect_option(cfg["CIFS_mount"][m_name], "CIFS_mount", "local_path") and
            (expect_option(cfg.get("global", {}), "CIFS_mount", "realm", alert=False) or
             expect_option(cfg["CIFS_mount"][m_name], "CIFS_mount", "realm"))
        )
        if is_ok:
            if "realm" in cfg["CIFS_mount"][m_name]:
                realm = cfg["CIFS_mount"][m_name]["realm"]
            else:
                realm = cfg["global"]["realm"]
            expected_realms.setdefault(realm, [])
            expected_realms[realm].append(m_name)
            net = cfg["CIFS_mount"][m_name].get("network")
            if net is not None:
                expected_networks_by_CIFS_m.setdefault(net, [])
                expected_networks_by_CIFS_m[net].append(m_name)
        else:
            Output.error("Removing incomplete CIFS_mount '{}'.".format(m_name))
            invalid_cifs_m.append(m_name)

    for realm in expected_realms:
        if realm not in cfg.get("realm", []):
            Output.error("Missing realm '{}'.".format(realm))
            for m_name in expected_realms[realm]:
                Output.error("Removing CIFS_mount '{}' depending on realm '{}'.".format(m_name, realm))
                invalid_cifs_m.append(m_name)

    for realm in cfg.get("realm", []):
        is_ok = (
            expect_option(cfg["realm"][realm], "realm", "username") and
            expect_option(cfg["realm"][realm], "realm", "domain")
        )
        if not is_ok:
            Output.error("Removing incomplete realm '{}'.".format(realm))
            invalid_realm.append(realm)
            for m_name in expected_realms.get(realm, []):
                Output.error("Removing CIFS_mount '{}' depending on realm '{}'.".format(m_name, realm))
                invalid_cifs_m.append(m_name)

    for net in expected_networks_by_CIFS_m:
        if net not in cfg.get("network", []):
            Output.error("Missing network '{}'.".format(net))
            for m_name in expected_networks_by_CIFS_m[net]:
                Output.error("Removing 'require_network' to CIFS_mount '{}'.".format(m_name))
                del(cfg["CIFS_mount"][m_name]["require_network"])

    for net in cfg.get("network", []):
        is_ok = (
            (expect_option(cfg["network"][net], "network", "ping", alert=False) or
             expect_option(cfg["network"][net], "network", "cifs", ored_options=("ping", "cifs"))) and
            expect_option(cfg["network"][net], "network", "error_msg")
        )
        if not is_ok:
            Output.error("Removing incomplete network '{}'.".format(net))
            invalid_network.append(net)

    had_change = True
    while had_change:
        had_change = False
        for net in cfg.get("network", []):
            if net in invalid_network:
                continue
            parent_network = cfg["network"][net].get("parent")
            if parent_network is None:
                continue
            if (
             parent_network in invalid_network or
             parent_network not in cfg["network"]):
                invalid_network.append(net)
                had_change = True

    for msg in cfg.get("msg", []):
        is_ok = (
            expect_option(cfg["msg"][msg], "msg", "text")
        )
        cfg["msg"][msg].setdefault("icon", "none")
        if not is_ok:
            Output.error("Removing incomplete msg '{}'.".format(msg))
            invalid_msg.append(msg)

    for m_name in invalid_cifs_m:
        del(cfg["CIFS_mount"][m_name])

    for realm in invalid_realm:
        del(cfg["realm"][realm])

    for net in invalid_network:
        del(cfg["network"][net])
        for m_name in expected_networks_by_CIFS_m.get(net, []):
            Output.error("Removing 'require_network' to CIFS_mount '{}'.".format(m_name))
            del(cfg["CIFS_mount"][m_name]["require_network"])

    for msg in invalid_msg:
        del(cfg["msg"][msg])

    return cfg
コード例 #27
0
ファイル: conf.py プロジェクト: EPFL-ENAC/ENACdrives
def main():
    with Output():
        cfg = get_config()
        Output.debug(pprint.pformat(cfg))
コード例 #28
0
ファイル: cli.py プロジェクト: EPFL-ENAC/ENACdrives
    def show_summary(self, expected_status=None):
        if expected_status is None:
            expected_status = {}
        special_chars = {
            "unicode": {
                "stared": "\u272F",
                "unstared": " ",  # "\u274F"  # "\u274d"
                "no_network": "\u2757",
                "mounted": "\u2713",
                "umounted": "\u2717",
            },
            "ascii": {
                "stared": "*",
                "unstared": " ",  # "\u274F"  # "\u274d"
                "no_network": "!",
                "mounted": "v",
                "umounted": "x",
            },
        }
        display_mode = "unicode"  # may be switched to "ascii" if necessary

        def is_bookmarked(entry):
            if entry.settings["bookmark"]:
                return "\033[01;33m{}\033[00m".format(
                    special_chars[display_mode]["stared"])
            else:
                return "{}".format(special_chars[display_mode]["unstared"])

        def is_mounted(entry):
            required_network = entry.settings.get("require_network")
            if required_network is not None:
                net_status, net_msg = self.networks_check.get_status(
                    required_network)
                if not net_status:
                    return "\033[01;31m{}\033[00m {}".format(
                        special_chars[display_mode]["no_network"], net_msg)
            if entry.is_mounted():
                return "\033[01;32m{}\033[00m on {}".format(
                    special_chars[display_mode]["mounted"],
                    entry.settings["local_path"])
            else:
                return "\033[01;31m{}\033[00m".format(
                    special_chars[display_mode]["umounted"])

        if self.cfg["global"].get("username") is None:
            Output.cli("\033[01;37m*** ENACdrives entries summary ***\033[00m")
        else:
            Output.cli(
                "\033[01;37m*** ENACdrives entries summary for user {} ***\033[00m"
                .format(self.cfg["global"]["username"]))
        name_width = 1
        label_width = 1
        for entry in self.entries:
            name_width = max(name_width, len(entry.settings["name"]))
            label_width = max(label_width, len(entry.settings["label"]))
        for entry in self.entries:
            if expected_status.get(entry.settings["name"]) is not None:
                iteration_max = 3
                while expected_status[
                        entry.settings["name"]] != entry.is_mounted():
                    time.sleep(0.5)
                    entry.uncache_is_mounted()
                    iteration_max -= 1
                    if iteration_max <= 0:
                        break
            try:
                Output.cli(
                    "{}  \033[00;37m{:<{name_width}}\033[00m  \033[01;37m{:<{label_width}}\033[00m  {}"
                    .format(is_bookmarked(entry),
                            entry.settings["name"],
                            entry.settings["label"],
                            is_mounted(entry),
                            name_width=name_width,
                            label_width=label_width))
            except UnicodeEncodeError:  # UnicodeEncodeError: 'ascii' codec can't encode character '\u2717' in position 86: ordinal not in range(128)
                display_mode = "ascii"
                Output.cli(
                    "{}  \033[00;37m{:<{name_width}}\033[00m  \033[01;37m{:<{label_width}}\033[00m  {}"
                    .format(is_bookmarked(entry),
                            entry.settings["name"],
                            entry.settings["label"],
                            is_mounted(entry),
                            name_width=name_width,
                            label_width=label_width))
        if len(self.entries) == 0:
            Output.cli("No entry found.")
        if self.cfg["global"].get("username") is None:
            Output.warning(
                "username not defined. You can set it with argument --username=username"
            )
            self.execution_status(1)
コード例 #29
0
def cifs_mount(mount):
    remote = r"\\{server_name}\{server_path}".format(**mount.settings)
    local = mount.settings["Windows_letter"]
    Output.normal("remote={}\nlocal={}".format(remote, local))

    # 1st attempt without password
    try:
        Output.verbose("1st attempt without password")
        win32wnet.WNetAddConnection2(
            win32netcon.RESOURCETYPE_DISK,
            local,
            remote,
        )
        Output.verbose("succeeded")
        cifs_uncache_is_mounted(mount)
        return True
    except pywintypes.error as e:
        if e.winerror == 5:  # (5, 'WNetAddConnection2', 'Access is denied.')
            pass
        elif e.winerror == 86:  # (86, "WNetAddConnection2", "The specified network password is not correct.")
            pass
        elif e.winerror == 1326:  # (1326, "WNetAddConnection2", "Logon failure: unknown user name or bad password.")
            pass
        elif e.winerror == 31:  # (31, 'WNetAddConnection2', 'A device attached to the system is not functioning.')
            pass
        elif e.winerror == 53:  # (53, 'WNetAddConnection2', 'The network path was not found.')
            mount.ui.notify_user(e.strerror)
            return False
        elif e.winerror == 55:  # (55, 'WNetAddConnection2', 'The specified network resource or device is no longer available.')
            mount.ui.notify_user(e.strerror)
            return False
        elif e.winerror == 64:  # (64, 'WNetAddConnection2', 'Le nom réseau spécifié n’est plus disponible.')
            mount.ui.notify_user(e.strerror)
            return False
        elif e.winerror == 67:  # (67, 'WNetAddConnection2', 'The network name cannot be found.')
            mount.ui.notify_user(e.strerror)
            return False
        elif e.winerror == 71:  # (71, 'WNetAddConnection2', 'No more connections can be made to this remote computer at this time because there are already as many connections as the computer can accept.')
            mount.ui.notify_user(e.strerror)
            return False
        elif e.winerror == 85:  # (85, 'WNetAddConnection2', 'The local device name is already in use.')
            mount.ui.notify_user(e.strerror)
            return False
        elif e.winerror == 121:  # (121, 'WNetAddConnection2', 'The semaphore timeout period has expired.')
            mount.ui.notify_user(e.strerror)
            return False
        elif e.winerror == 1202:  # (1202, 'WNetAddConnection2', 'The local device name has a remembered connection to another network resource.')
            mount.ui.notify_user(e.strerror)
            return False
        elif e.winerror == 1208:  # (1208, 'WNetAddConnection2', 'An extended error has occurred.')
            mount.ui.notify_user(e.strerror)
            return False
        elif e.winerror == 1219:  # (1219, 'WNetAddConnection2', 'Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the server or shared resource and try again.')
            mount.ui.notify_user(e.strerror)
            return False
        elif e.winerror == 1222:  # (1222, 'WNetAddConnection2', 'The network is not present or not started.')
            mount.ui.notify_user(e.strerror)
            return False
        elif e.winerror == 1265:  # (1265, 'WNetAddConnection2', 'The system detected a possible attempt to compromise security. Please ensure that you can contact the server that authenticated you.')
            mount.ui.notify_user(e.strerror)
            return False
        elif e.winerror == 1272:  # (1272, 'WNetAddConnection2', "You can't access this shared folder because your organization's security policies block unauthenticated guest access. These policies help protect your PC from unsafe or malicious devices on the network.")
            mount.ui.notify_user(e.strerror)
            return False
        elif e.winerror == 1311:  # (1311, 'WNetAddConnection2', 'There are currently no logon servers available to service the logon request.')
            # (1311, 'WNetAddConnection2', "We can't sign you in with this credential because your domain isn't available. Make sure your device is connected to your organization's network and try again. If you previously signed in on this device with another credential, you can sign in with that credential.")
            mount.ui.notify_user(e.strerror)
            return False
        elif e.winerror == 1331:  # (1331, 'WNetAddConnection2', "This user can't sign in because this account is currently disabled.")
            mount.ui.notify_user(e.strerror)
            return False
        elif e.winerror == 1907:  # (1907, 'WNetAddConnection2', "The user's password must be changed before signing in.")
            pass
        else:
            Output.error("failed : {0}".format(e))
            debug_send("mount without password:\n{0}".format(e))

    # 2nd attempt with password
    wrong_password = False
    for _ in range(3):
        try:
            pw = mount.key_chain.get_password(mount.settings["realm"],
                                              wrong_password)
            wrong_password = False
            Output.verbose("New attempt with password")
            win32wnet.WNetAddConnection2(
                win32netcon.RESOURCETYPE_DISK, local, remote, None,
                r"{0}\{1}".format(mount.settings["realm_domain"],
                                  mount.settings["realm_username"]), pw, 0)
            mount.key_chain.ack_password(mount.settings["realm"])
            Output.verbose("succeeded")
            cifs_uncache_is_mounted(mount)
            return True
        except pywintypes.error as e:
            if e.winerror == 86:  # (86, "WNetAddConnection2", "The specified network password is not correct.")
                mount.key_chain.invalidate_if_no_ack_password(
                    mount.settings["realm"])
                wrong_password = True
            elif e.winerror == 1326:  # (1326, "WNetAddConnection2", "Logon failure: unknown user name or bad password.")
                mount.key_chain.invalidate_if_no_ack_password(
                    mount.settings["realm"])
                wrong_password = True
            elif e.winerror == 5:  # (5, 'WNetAddConnection2', 'Access is denied.')
                mount.ui.notify_user(e.strerror)
                return False
            elif e.winerror == 31:  # (31, 'WNetAddConnection2', 'A device attached to the system is not functioning.')
                mount.ui.notify_user(e.strerror)
                return False
            elif e.winerror == 53:  # (53, 'WNetAddConnection2', 'The network path was not found.')
                mount.ui.notify_user(e.strerror)
                return False
            elif e.winerror == 55:  # (55, 'WNetAddConnection2', 'The specified network resource or device is no longer available.')
                mount.ui.notify_user(e.strerror)
                return False
            elif e.winerror == 64:  # (64, 'WNetAddConnection2', 'Le nom réseau spécifié n’est plus disponible.')
                mount.ui.notify_user(e.strerror)
                return False
            elif e.winerror == 67:  # (67, 'WNetAddConnection2', 'The network name cannot be found.')
                mount.ui.notify_user(e.strerror)
                return False
            elif e.winerror == 71:  # (71, 'WNetAddConnection2', 'No more connections can be made to this remote computer at this time because there are already as many connections as the computer can accept.')
                mount.ui.notify_user(e.strerror)
                return False
            elif e.winerror == 85:  # (85, 'WNetAddConnection2', 'The local device name is already in use.')
                mount.ui.notify_user(e.strerror)
                return False
            elif e.winerror == 121:  # (121, 'WNetAddConnection2', 'The semaphore timeout period has expired.')
                mount.ui.notify_user(e.strerror)
                return False
            elif e.winerror == 1202:  # (1202, 'WNetAddConnection2', 'The local device name has a remembered connection to another network resource.')
                mount.ui.notify_user(e.strerror)
                return False
            elif e.winerror == 1208:  # (1208, 'WNetAddConnection2', 'An extended error has occurred.')
                mount.ui.notify_user(e.strerror)
                return False
            elif e.winerror == 1219:  # (1219, 'WNetAddConnection2', 'Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the server or shared resource and try again.')
                mount.ui.notify_user(e.strerror)
                return False
            elif e.winerror == 1222:  # (1222, 'WNetAddConnection2', 'The network is not present or not started.')
                mount.ui.notify_user(e.strerror)
                return False
            elif e.winerror == 1265:  # (1265, 'WNetAddConnection2', 'The system detected a possible attempt to compromise security. Please ensure that you can contact the server that authenticated you.')
                mount.ui.notify_user(e.strerror)
                return False
            elif e.winerror == 1272:  # (1272, 'WNetAddConnection2', "You can't access this shared folder because your organization's security policies block unauthenticated guest access. These policies help protect your PC from unsafe or malicious devices on the network.")
                mount.ui.notify_user(e.strerror)
                return False
            elif e.winerror == 1311:  # (1311, 'WNetAddConnection2', 'There are currently no logon servers available to service the logon request.')
                # (1311, 'WNetAddConnection2', "We can't sign you in with this credential because your domain isn't available. Make sure your device is connected to your organization's network and try again. If you previously signed in on this device with another credential, you can sign in with that credential.")
                mount.ui.notify_user(e.strerror)
                return False
            elif e.winerror == 1331:  # (1331, 'WNetAddConnection2', "This user can't sign in because this account is currently disabled.")
                mount.ui.notify_user(e.strerror)
                return False
            elif e.winerror == 1907:  # (1907, 'WNetAddConnection2', "The user's password must be changed before signing in.")
                mount.ui.notify_user(e.strerror)
                return False
            else:
                Output.error("failed : {0}".format(e))
                debug_send("mount with password:\n{0}".format(e))
                mount.ui.notify_user(e.strerror)
        except CancelOperationException:
            Output.verbose("Operation cancelled.")
            return False
    return False
コード例 #30
0
ファイル: cli.py プロジェクト: EPFL-ENAC/ENACdrives
    def run(self):
        enacit1logs_notify(self)
        self.show_msgs()
        if self.returncode is not None:
            return self.returncode

        if self.args.add_bookmark is not None:
            self.execution_status(0)
            for m_name in self.args.add_bookmark:
                if m_name in self.cfg["CIFS_mount"]:
                    conf.save_bookmark(m_name, True)
                    self.cfg["CIFS_mount"][m_name]["entry"].settings[
                        "bookmark"] = True
                else:
                    self.execution_status(1)
                    Output.warning(
                        "Skipping to add bookmark {}: Unknown entry.".format(
                            m_name))

        if self.args.rm_bookmark is not None:
            self.execution_status(0)
            for m_name in self.args.rm_bookmark:
                if m_name in self.cfg["CIFS_mount"]:
                    conf.save_bookmark(m_name, False)
                    self.cfg["CIFS_mount"][m_name]["entry"].settings[
                        "bookmark"] = False
                else:
                    self.execution_status(1)
                    Output.warning(
                        "Skipping to rm bookmark {}: Unknown entry.".format(
                            m_name))

        if self.returncode is not None:
            self.show_summary()
            return self.returncode

        if self.args.summary:
            self.execution_status(0)
            self.show_summary()
            return self.returncode

        which_entries = []
        if self.args.all:
            self.execution_status(0)
            for entry in self.entries:
                which_entries.append(entry)
        if self.args.named is not None:
            self.execution_status(0)
            for m_name in self.args.named:
                if m_name in self.cfg["CIFS_mount"]:
                    which_entries.append(
                        self.cfg["CIFS_mount"][m_name]["entry"])
                else:
                    self.execution_status(1)
                    Output.warning(
                        "Skipping named '{}'. Unknown entry.".format(m_name))
        if self.args.bookmarked:
            self.execution_status(0)
            for entry in self.entries:
                if entry.settings["bookmark"]:
                    which_entries.append(entry)

        if len(which_entries) == 0 and self.args.username is None:
            self.execution_status(1)
            Output.warning("No entry selected to (u)mount.")

        expected_status = {}
        if self.args.umount:
            umount_list = []
            for entry in which_entries:
                if entry.is_mounted():
                    umount_list.append(entry)
            for entry in umount_list:
                required_network = entry.settings.get("require_network")
                if required_network is not None:
                    net_status, net_msg = self.networks_check.get_status(
                        required_network)
                    if not net_status:
                        print("! Skip Umounting {} : {}".format(
                            entry.settings["name"], net_msg))
                        self.execution_status(1)
                        continue
                print("- Umounting {}".format(entry.settings["name"]))
                entry.umount()
                expected_status[entry.settings["name"]] = False
        else:
            mount_list = []
            for entry in which_entries:
                if not entry.is_mounted():
                    mount_list.append(entry)
            for entry in mount_list:
                required_network = entry.settings.get("require_network")
                if required_network is not None:
                    net_status, net_msg = self.networks_check.get_status(
                        required_network)
                    if not net_status:
                        print("! Skip Mounting {} : {}".format(
                            entry.settings["name"], net_msg))
                        self.execution_status(1)
                        continue
                print("+ Mounting {}".format(entry.settings["name"]))
                entry.mount()
                expected_status[entry.settings["name"]] = True
        self.show_summary(expected_status)

        return self.returncode