Example #1
0
    def _get_parms_for_page(self):
        user_root = self.getUserDB().get_root_dir(self.getUsername())
        user_root_b = encode_s(user_root)
        user_repos = self.getUserDB().get_repos(self.getUsername())
        repoList = []
        for user_repo in user_repos:
            try:
                # Get reference to a repo object
                repo_obj = librdiff.RdiffRepo(user_root_b, encode_s(user_repo))
                path = repo_obj.path
                name = repo_obj.display_name
                in_progress = repo_obj.in_progress
                last_backup_date = repo_obj.last_backup_date
                failed = False
            except librdiff.FileError:
                logging.exception("invalid user path %s" % user_repo)
                path = encode_s(user_repo)
                name = user_repo
                in_progress = False
                last_backup_date = 0
                failed = True
            repoList.append({"path": path,
                             "name": name,
                             "last_backup_date": last_backup_date,
                             'in_progress': in_progress,
                             'failed': failed})

        return {"repos": repoList}
Example #2
0
 def check_user_exists(l, r):
     if len(r) != 1:
         raise ValueError("user [%s] not found" % username)
     # Bind using the user credentials. Throws an exception in case of
     # error.
     l.simple_bind_s(r[0][0], encode_s(old_password))
     l.passwd_s(r[0][0], encode_s(old_password), encode_s(password))
     l.unbind_s()
     logger.info("password for user [%s] is updated in LDAP" % username)
Example #3
0
    def validate_user_path(self, path_b):
        '''Takes a path relative to the user's root dir and validates that it
        is valid and within the user's root'''
        assert isinstance(path_b, str)

        # Add a ending slash (/) to avoid matching wrong repo. Ref #56
        path_b = path_b.strip(b'/') + b'/'

        # NOTE: a blank path is allowed, since the user root directory might be
        # a repository.

        logger.debug("check user access to path [%s]" %
                     decode_s(path_b, 'replace'))

        # Get reference to user repos
        user_repos = self.app.currentuser.repos

        # Check if any of the repos matches the given path.
        user_repos_matches = [
            encode_s(user_repo).strip(b'/')
            for user_repo in user_repos
            if path_b.startswith(encode_s(user_repo).strip(b'/') + b'/')]
        if not user_repos_matches:
            # No repo matches
            logger.error("user doesn't have access to [%s]" %
                         decode_s(path_b, 'replace'))
            raise librdiff.AccessDeniedError
        repo_b = user_repos_matches[0]

        # Get reference to user_root
        user_root_b = encode_s(self.app.currentuser.root_dir)

        # Check path vs real path value
        full_path_b = os.path.join(user_root_b, path_b).rstrip(b"/")
        real_path_b = os.path.realpath(full_path_b).rstrip(b"/")
        if full_path_b != real_path_b:
            # We can safely assume the realpath contains a symbolic link. If
            # the symbolic link is valid, we display the content of the "real"
            # path.
            if real_path_b.startswith(os.path.join(user_root_b, repo_b)):
                path_b = os.path.relpath(real_path_b, user_root_b)
            else:
                logger.warn("access is denied [%s] vs [%s]" % (
                    decode_s(full_path_b, 'replace'),
                    decode_s(real_path_b, 'replace')))
                raise librdiff.AccessDeniedError

        # Get reference to the repository (this ensure the repository does
        # exists and is valid.)
        repo_obj = librdiff.RdiffRepo(user_root_b, repo_b)

        # Get reference to the path.
        path_b = path_b[len(repo_b):]
        path_obj = repo_obj.get_path(path_b)

        return (repo_obj, path_obj)
Example #4
0
    def validate_user_path(self, path_b):
        """Takes a path relative to the user's root dir and validates that it
        is valid and within the user's root"""
        assert isinstance(path_b, str)
        path_b = path_b.strip(b"/") + b"/"

        # NOTE: a blank path is allowed, since the user root directory might be
        # a repository.

        logger.debug("check user access to path [%s]" % decode_s(path_b, "replace"))

        # Get reference to user repos
        user_repos = self.getUserDB().get_repos(self.getUsername())

        # Check if any of the repos matches the given path.
        user_repos_matches = filter(lambda x: path_b.startswith(encode_s(x).strip(b"/") + b"/"), user_repos)
        if not user_repos_matches:
            # No repo matches
            logger.error("user doesn't have access to [%s]" % decode_s(path_b, "replace"))
            raise librdiff.AccessDeniedError
        repo_b = encode_s(user_repos_matches[0]).strip(b"/")

        # Get reference to user_root
        user_root = self.getUserDB().get_root_dir(self.getUsername())
        user_root_b = encode_s(user_root)

        # Check path vs real path value
        full_path_b = os.path.join(user_root_b, path_b).rstrip(b"/")
        real_path_b = os.path.realpath(full_path_b).rstrip(b"/")
        if full_path_b != real_path_b:
            # We can safely assume the realpath contains a symbolic link. If
            # the symbolic link is valid, we display the content of the "real"
            # path.
            if real_path_b.startswith(os.path.join(user_root_b, repo_b)):
                path_b = os.path.relpath(real_path_b, user_root_b)
            else:
                logger.warn(
                    "access is denied [%s] vs [%s]"
                    % (decode_s(full_path_b, "replace"), decode_s(real_path_b, "replace"))
                )
                raise librdiff.AccessDeniedError

        # Get reference to the repository (this ensure the repository does
        # exists and is valid.)
        repo_obj = librdiff.RdiffRepo(user_root_b, repo_b)

        # Get reference to the path.
        path_b = path_b[len(repo_b) :]
        path_obj = repo_obj.get_path(path_b)

        return (repo_obj, path_obj)
Example #5
0
    def restore(self, name, restore_date, use_zip):
        """Used to restore the given file located in this path."""
        assert isinstance(name, str)
        assert isinstance(restore_date, rdw_helpers.rdwTime)
        name = name.lstrip(b"/")

        # Determine the file name to be restore (from rdiff-backup
        # point of view).
        file_to_restore = os.path.join(self.full_path, name)
        file_to_restore = self.repo.unquote(file_to_restore)

        # Convert the date into epoch.
        date_epoch = str(restore_date.getSeconds())

        # Define a location where to restore the data
        if name == b"" and self.path == b"":
            filename = b"root"
        if self.path != b"":
            filename = os.path.basename(self.path)
        if name != b"":
            filename = name
        # Generate a temporary location used to restore data.
        tempdir = rdw_helpers.encode_s(rdw_config.get_config("tempdir",
                                                             default=None))
        output = os.path.join(tempfile.mkdtemp(dir=tempdir), filename)

        # Execute rdiff-backup to restore the data.
        logger.info(b"execute rdiff-backup --restore-as-of=%s '%s' '%s'" %
                    (date_epoch, file_to_restore, output))
        results = self._execute(
            b"rdiff-backup",
            b"--restore-as-of=" + date_epoch,
            file_to_restore,
            output)

        # Check the result
        if results['exitCode'] != 0 or not os.access(output, os.F_OK):
            error = results['stderr']
            if not error:
                error = '''rdiff-backup claimed success, but did not restore
                        anything. This indicates a bug in rdiffweb. Please
                        report this to a developer.'''
            raise UnknownError('unable to restore!\n' + error)

        # The path restored is a directory and need to be archived using zip
        # or tar
        if os.path.isdir(output):
            output_dir = output
            try:
                if use_zip:
                    output = output_dir + ZIP_SUFFIX
                    self._recursiveZipDir(output_dir, output)
                else:
                    output = output_dir + TARGZ_SUFFIX
                    self._recursiveTarDir(output_dir, output)
            finally:
                rdw_helpers.remove_dir(output_dir)

        # Return the location of the file to be restored
        return output
Example #6
0
 def _hashPassword(self, password):
     # At this point the password should be unicode. We converted it into
     # system encoding.
     password_b = encode_s(password)
     import sha
     hasher = sha.new()
     hasher.update(password_b)
     return decode_s(hasher.hexdigest())
Example #7
0
 def get_config_str(self, key, default=""):
     """
     A convenience method which coerces the key to an str.
     """
     try:
         return rdw_helpers.encode_s(self.get_config(key, default))
     except:
         return default
Example #8
0
    def _get_parms_for_page(self):
        """
        Build the params for the locations templates.
        """
        # Get user's locations.
        user_root = self.app.currentuser.root_dir
        user_root_b = encode_s(user_root)
        user_repos = self.app.currentuser.repos
        repos = []
        for user_repo in user_repos:
            try:
                # Get reference to a repo object
                repo_obj = librdiff.RdiffRepo(user_root_b, encode_s(user_repo))
                path = repo_obj.path
                name = repo_obj.display_name
                in_progress = repo_obj.in_progress
                last_backup_date = repo_obj.last_backup_date
                failed = False
            except librdiff.FileError:
                logging.exception("invalid user path %s" % user_repo)
                path = encode_s(user_repo)
                name = user_repo
                in_progress = False
                last_backup_date = 0
                failed = True
            # Create an entry to represent the repository
            repos.append({
                "path": path,
                "name": name,
                "last_backup_date": last_backup_date,
                'in_progress': in_progress,
                'failed': failed
            })
        params = {
            "repos": repos,
            "templates_before_content": list(),
        }

        # Add plugins params.
        self.app.plugins.run(
            lambda x: x.locations_update_params(params),
            rdw_plugin.ILocationsPagePlugin.CATEGORY)

        # Return the complete list of params.
        return params
Example #9
0
    def _execute(self, username, function):
        assert isinstance(username, unicode)

        """Reusable method to run LDAP operation."""

        # try STARTLS if configured
        if self.tls:
            ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)

        # Check LDAP credential only.
        l = ldap.initialize(self.uri)

        # Set v2 or v3
        if self.version == 2:
            l.protocol_version = ldap.VERSION2
        else:
            l.protocol_version = ldap.VERSION3

        try:
            # Bind to the LDAP server
            logger.debug("binding to ldap server {}".format(self.uri))
            l.simple_bind_s(self.bind_dn, self.bind_password)

            # Search the LDAP server
            search_filter = "(&{}({}={}))".format(
                self.filter, self.attribute, username)
            logger.info("search ldap server: {}/{}?{}?{}?{}".format(
                self.uri, self.base_dn, self.attribute, self.scope,
                search_filter))
            r = l.search_s(encode_s(self.base_dn),
                           self.scope,
                           encode_s(search_filter))

            # Execute operation
            return function(l, r)
        except ldap.LDAPError as e:
            l.unbind_s()
            if isinstance(e.message, dict) and 'desc' in e.message:
                raise ValueError(e.message['desc'])
            else:
                raise ValueError(e.message['info'])
Example #10
0
        def check_crendential(l, r):
            # Check results
            if len(r) != 1:
                logger.warn("user [%s] not found in LDAP" % username)
                return False

            # Bind using the user credentials. Throws an exception in case of
            # error.
            l.simple_bind_s(r[0][0], encode_s(password))
            l.unbind_s()
            logger.info("user [%s] found in LDAP" % username)
            return True
Example #11
0
 def __str__(self):
     return rdw_helpers.encode_s(unicode(self))
Example #12
0
    def _getUserMessages(self,
                         repos,
                         includeSuccess,
                         includeFailure,
                         earliest_date,
                         latest_date):

        user_root = self.app.userdb.get_user_root(self.app.currentuser.username)
        user_root_b = encode_s(user_root)

        repoErrors = []
        allBackups = []
        for repo in repos:
            # Get binary representation of the repo
            repo_b = encode_s(repo) if isinstance(repo, unicode) else repo
            repo_b = repo_b.lstrip(b"/")
            try:
                repo_obj = librdiff.RdiffRepo(user_root_b, repo_b)
                backups = repo_obj.get_history_entries(-1, earliest_date,
                                                       latest_date)
                allBackups += [{"repo_path": repo_obj.path,
                                "repo_name": repo_obj.display_name,
                                "date": backup.date,
                                "size": backup.size,
                                "errors": backup.errors} for backup in backups]
            except librdiff.FileError as e:
                repoErrors.append(
                    {"repo_path": repo_b,
                     "repo_name": decode_s(repo_b, 'replace'),
                     "error": unicode(e)})

        allBackups.sort(lambda x, y: cmp(y["date"], x["date"]))
        failedBackups = filter(lambda x: x["errors"], allBackups)

        # group successful backups by day
        successfulBackups = filter(lambda x: not x["errors"], allBackups)
        if successfulBackups:
            lastSuccessDate = successfulBackups[0]["date"]
        successfulBackups = rdw_helpers.groupby(
            successfulBackups, lambda x: x["date"].getLocalDaysSinceEpoch())

        userMessages = []

        # generate failure messages
        if includeFailure:
            for job in failedBackups:
                date = job["date"]
                job.update(
                    {"is_success": False,
                     "date": date,
                     "repoErrors": [],
                     "backups": [],
                     "repo_path": job["repo_path"],
                     "repo_name": job["repo_name"]})
                userMessages.append(job)

        # generate success messages (publish date is most recent backup date)
        if includeSuccess:
            for day in successfulBackups.keys():
                date = successfulBackups[day][0]["date"]

                # include repository errors in most recent entry
                if date == lastSuccessDate:
                    repoErrorsForMsg = repoErrors
                else:
                    repoErrorsForMsg = []

                userMessages.append(
                    {"is_success": True,
                     "date": date,
                     "repoErrors": repoErrorsForMsg,
                     "backups": successfulBackups[day]})

        # sort messages by date
        userMessages.sort(lambda x, y: cmp(y["date"], x["date"]))
        return userMessages