Exemplo n.º 1
0
    def new(cls, host, port, user, scheme=None):
        """Create new authority instance.

        Args:
            host   (str): Hostname or IP address as an integer.
            port   (int): Port number of hostname.
            user   (str): Username assigned to hostname.
            scheme (str): Connection service scheme (optional).

        Raises:
            Exception: If required fields are invalid.

        Returns:
            Authority: An authority instance.
        """

        auth = cls()
        try:
            if scheme is not None:
                auth.set_scheme(scheme)
            auth.set_host(host)
            auth.set_port(port)
            auth.set_user(user)
        except Exception as e:
            Log.fatal("Cannot create new authority: {e}", e=str(e))
        return auth
Exemplo n.º 2
0
    def read_tmp_secrets(self, zf_secrets):
        """Read temporary secrets.

        Args:
            zf_secrets (ZipFile): ZipFile instance with secrets and passkeys.

        Raises:
            SystemExit: If manager crashes or corrupted data are found.
        """

        for each in zf_secrets.read(self.migrate_tmpfile).split("\n"):
            line = each.split("\t", self.COLUMNS)
            if len(line) == 0:
                continue
            _, _, host, ipv4, port, user, scheme, name, ptype, passkey = line
            if ptype not in Passkey.SUPPORTED_TYPES:
                Log.fatal("Unsupported passkey storage {x}", x=ptype)
            authority_args = user, host, port, scheme
            auth = self.manager.build_authority_from_args(*authority_args)
            if ptype == "privatekey":
                passkey = zf_secrets.read(passkey)
            data = {
                "name": name,
                "host": host,
                "auth": auth,
                "passkey": Passkey.SUPPORTED_TYPES.get(ptype) + passkey
            }
            self.manager.get_db().add(**data)
        Log.warn("Unsupported import for jump server, yet")
Exemplo n.º 3
0
    def get_scheme(self):
        """Authority scheme getter.

        Returns:
            unicode: Connection scheme.
        """

        if self.scheme is None:
            Log.fatal("Authority has not set a valid scheme: unset scheme")
        return unicode(self.scheme)
Exemplo n.º 4
0
    def get_user(self):
        """Authority user getter.

        Returns:
            unicode: Connection username.
        """

        if self.user is None:
            Log.fatal("Authority has not set a valid user: unset user")
        return unicode(self.user)
Exemplo n.º 5
0
def get_init_shell(self):
    """Shell getter for "init" option.
    """

    try:
        Secret.get_secret_file()
        print(OKAY_MESSAGE)
    except Exception as e:
        Log.fatal("Aborting due to an error: {e}", e=str(e))
    raise SystemExit
Exemplo n.º 6
0
    def read(self):
        """Autodetect read method and retrieve passkey.

        Raises:
            Exception: If cannot autodetect read method.
        """

        if not hasattr(self, self.__read_method):
            Log.fatal("Unsupported read method: {m}", m=self.read_method)
        self.passkey = getattr(self, self.__read_method)()
Exemplo n.º 7
0
    def get_db(self):
        """Database getter.

        Returns:
            Database: Database storage.
        """

        if isinstance(self.__database, Database):
            return self.__database
        Log.fatal("Missing database: manager not initialized?")
Exemplo n.º 8
0
    def initialize(cls, secrets):
        """Register keychain to manager's database.

        Args:
            secrets (object): Dict-like object storage.
        """

        cls.__secrets = Keychain(secrets)
        cls.__database = Database(cls.__secrets)
        Log.debug("Manager initialized...")
Exemplo n.º 9
0
    def get_secrets(self):
        """Keychain getter.

        Returns:
            Keychain: Passkeys storage.
        """

        if isinstance(self.__secrets, Keychain):
            return self.__secrets
        Log.fatal("Missing keychain: manager not initialized?")
Exemplo n.º 10
0
def get_install_shell(self):
    """Shell getter for "install" option.
    """

    try:
        deploy_unlock_script() and deploy_lock_script()
        print(SCRIPTS_CREATED)
    except Exception as e:
        Log.fatal("Aborting due to an error: {e}", e=str(e))
    raise SystemExit
Exemplo n.º 11
0
    def build_random_name(self):
        """Generate a random name with 16 characters.

        Returns:
            str: Random 16 characters.
        """

        name = uuid4().hex[:16]
        Log.debug("Generating new random name: {n}", n=name)
        return name
Exemplo n.º 12
0
    def add(self, key, value):
        """Append key to keychain.

        Args:
            key   (str): Key to append.
            value (str): Value to save for given key.
        """

        if self.has(key):
            Log.fatal("Cannot add duplicates in keychain")
        self.update(key, value)
Exemplo n.º 13
0
    def pin(self):
        """Return the prefixed secret with its appropriate type.

        Raises:
            Exception: If unsupported passkey is provided.

        Returns:
            str: Prefixed passkey.
        """

        if self.passkey is None:
            Log.fatal("Passkey has not been read yet")
        return self.passfix + self.passkey
Exemplo n.º 14
0
    def sign(cls, data):
        """Calculate CRC32 hash of given data.

        Args:
            data (str): String data to calculate CRC.

        Returns:
            str: Hex value without 0x of the calculated CRC32.
        """

        if not isinstance(data, (str, unicode)):
            Log.fatal("Cannot calculate CRC for non-string data")
        return hex(crc32(data) & 0xFFFFFFFF)[2:]  # skip 0x
Exemplo n.º 15
0
    def get_secret_file(cls):
        """Return or make a sample keys holder.

        Raises:
            Exception: If application cannot read or write file.

        Returns:
            object: Instance of opened secrets file.
        """

        secret_dir = cls.get_secret_dir()
        lockpath = "{}/{}".format(secret_dir, cls.SECRETS_LOCK)
        if path.exists(lockpath):
            Log.fatal("Secrets are locked!\nClosing...")
        fullpath = "{}/{}".format(secret_dir, cls.SECRETS_FILE)
        try:
            secret_file = read_secrets(fullpath, "c")
            chmod(fullpath, 0600)
        except Exception as e:
            Log.fatal("Cannot create secret storage file: {e}", e=str(e))
        try:
            assert secret_file[cls.VERSION]
        except KeyError:
            secret_file[cls.VERSION] = __version__
        except Exception as e:
            Log.fatal("Unsupported secrets driver or {e}", e=str(e))
        if secret_file[cls.VERSION] != __version__:
            error = "Secrets have been stored with a different version " \
                    "of Unlocker (current version {cv}; secrets {vs})\n" \
                    "Closing..."
            Log.fatal(error, cv=__version__, vs=secret_file[cls.VERSION])
        return secret_file
Exemplo n.º 16
0
    def add_host(self, name, host):
        """Create new hostname for named authority.

        Args:
            name (str): Full name of the authority to add.
            host (str): Hostname to save to keychain.

        Raises:
            Exception: If named authority already exists in keychain.
        """

        if self.storage.has(self.get_host_key(name)):
            Log.fatal("Cannot add hostname on a duplicate entry")
        self.storage.add(self.get_host_key(name), host)
Exemplo n.º 17
0
    def update_jump_auth(self, name, auth):
        """Update passkey for existing named authority.

        Args:
            name       (str): Full name of the authority to add.
            auth (Authority): New authority as jump server.

        Raises:
            Exception: If provided argument is not Authority.
        """

        if not isinstance(auth, Authority):
            Log.fatal("Expected authority instance, got {t}", t=type(auth))
        self.storage.update(self.get_jump_key(name), auth.read())
Exemplo n.º 18
0
    def update_passkey(self, name, passkey):
        """Update passkey for existing named authority.

        Args:
            name    (str): Full name of the authority to add.
            passkey (str): New processed passkey to replace the old passkey.

        Raises:
            Exception: If passkey is zero-length.
        """

        if len(passkey) == 0:
            Log.fatal("Passkey cannot be empty")
        self.storage.update(self.get_pass_key(name), passkey)
Exemplo n.º 19
0
    def migrate_secrets(cls):
        """Migrate stored secrets from another version to current version.

        Raises:
            Exception: If secrets cannot be migrated.
        """

        fullpath = "{}/{}".format(cls.get_secret_dir(), cls.SECRETS_FILE)
        try:
            secret_file = read_secrets(fullpath, "c")
            secret_file[cls.VERSION] = __version__
            secret_file.close()
        except Exception as e:
            Log.fatal("Cannot migrate secrets because {e}", e=str(e))
Exemplo n.º 20
0
    def call_secret_read_stdout_dump_option(self, name, signature, **kwargs):
        """Vulnerable passkey dump to stdout.

        Args:
            name      (str): The name of the authority to lookup.
            signature (str): The signature for an authority to find its name.

        Outputs:
            stdout: Base64 encoded passkey.

        Raises:
            Exception: If unsupported passkey is found.
        """

        def print_passkey(auth_name):
            _, _, secret = self.get_db().lookup(auth_name)
            return "{}\n{}".format(*Passkey.copy(secret))

        passkey = ""  # dummy passkey
        Log.debug("Incoming secret dump request...")
        if len(name) > 0:
            Log.debug("Got named authority {n}...", n=name)
            passkey = print_passkey(name)
        elif len(signature) > 0:
            for each, name in self.get_db().query_auth():
                if each.signature() != signature:
                    continue
                Log.debug("Records matched authority, got passkey...")
                passkey = print_passkey(name)
                break  # exit on first match
        Log.debug("Printing passkey..." if passkey else "Nothing to print...")
        Display.show_dump(passkey)
Exemplo n.º 21
0
    def add_passkey(self, name, passkey):
        """Create new passkey for a named authority.

        Args:
            name    (str): Full name of the authority to add.
            passkey (str): Processed passkey to save to keychain.

        Raises:
            Exception: If named authority already exists in keychain.
        """

        if self.exists(name):
            Log.fatal("Cannot add passkey on a duplicate entry")
        self.update_passkey(name, passkey)
Exemplo n.º 22
0
    def call_read_write_forget_option(self, signature, **kwargs):
        """Remove wrapper without explicit authority.

        Finds authority by signature and calls "remove" for passkey.

        Args:
            key (str): Possible authority signature to match or name.

        Raises:
            Exception: If named authority does not exists.

        Outputs:
            stdout: Human-readable passkey with authority details and hostname.
        """

        Log.debug("Testing if key {s} exists", s=signature)
        if len(signature) < self.MIN_NAME_LEN:
            Log.debug("Trying key as authority signature...")
            for name, auth, _, _ in self.get_db().query_all():
                if auth.signature() == signature:
                    Log.debug("Got authority with signature {s}", s=signature)
                    signature = name
                    break
        Log.debug("Running cleanup after named authority: {n}", n=signature)
        self.call_read_write_remove_option(signature)
Exemplo n.º 23
0
    def call_read_only_list_option(self, *args, **kwargs):
        """List handler.

        Outputs:
            stdout: Pager with table-like view of all hostnames.
        """

        Log.debug("Incoming list request...")
        known_hosts = [e for e in self.get_db().query_all()]
        counter = -1
        indexes = {}
        sorted_hosts = []
        Log.debug("Found {n} hosts to list...", n=len(known_hosts))
        while len(known_hosts) > 0:
            if counter >= self.MAX_ITER_LIST:
                Log.fatal("Max. iteration over list display reached...")
            name, auth, host, jump = known_hosts[0]
            counter += 1
            if auth.signature() not in indexes:
                indexes.update({auth.signature(): counter})
            if jump is None:
                sorted_hosts.append(known_hosts.pop(0))
                continue
            jump_index = indexes.get(jump.signature(), -1)
            if jump_index > -1:
                if jump_index == 0:
                    jump_index += 1
                sorted_hosts.insert(jump_index, known_hosts.pop(0))
                continue
            known_hosts.insert(len(known_hosts), known_hosts.pop(0))
        Log.debug("Sorted all known hosts and now preparing to print out...")
        Display.show_list_view(sorted_hosts, **self.args)
Exemplo n.º 24
0
    def call_read_only_recall_option(self, signature, **kwargs):
        """Lookup wrapper without explicit authority.

        Finds authority by signature and calls "lookup" for passkey.

        Args:
            key (str): Possible authority signature to match or name.

        Raises:
            Exception: If named authority does not exists.

        Outputs:
            stdout: Human-readable passkey with authority details and hostname.
        """

        Log.debug("Searching secret passkey for key {s}", s=signature)
        if len(signature) < self.MIN_NAME_LEN:
            Log.debug("Trying key as authority signature...")
            for name, auth, _, _ in self.get_db().query_all():
                if auth.signature() == signature:
                    Log.debug("Got authority with signature {s}", s=signature)
                    signature = name
                    break
        Log.debug("Running a lookup for named authority: {n}", n=signature)
        self.call_read_only_lookup_option(signature)
Exemplo n.º 25
0
def unlocker(secrets, args=()):
    """Manage unlocker's keychain.

    Can add, edit, delete and lookup keys.
    All keys stored are compressed and encoded.
    """

    # register secrets on keychain
    Manager.initialize(secrets)
    Log.debug("Preparing to boot...")

    # initialize manager and parse arguments
    mng = Manager(*args)
    mng.call()
    Log.debug("Preparing to exit...")
Exemplo n.º 26
0
    def remove(self, key):
        """Remove key from keychain.

        Args:
            key (str): Key to remove.

        Returns:
            str: Raw "as is" removed value for given key.
        """

        value = self.get(key)
        if value is None:
            Log.warn("Keychain can not remove an unset key")
        else:
            del self.keychain[key]
        return value
Exemplo n.º 27
0
    def query(self, key_type_prefix):
        """Query secrets from keychain storage.

        Args:
            key_type_prefix (str): Prefix to partial match in lookup.

        Yields:
            mixt: Entry for each matched found.
        """

        for each in self.storage.lookup(key_type_prefix):
            if each == self.VERSION:
                continue
            if self.storage.get_value(each).strip() == "":
                Log.fatal("Storage contains empty value for key {k}", k=each)
            yield each
Exemplo n.º 28
0
    def shift(self, string):
        """Shift to the right a sting to remove any prefix.

        Args:
            string (str): String to be shifted.

        Raises:
            Exeption: If provided argument is not a string.

        Returns:
            str: New shifted string without prefix.
        """

        if isinstance(string, (str, unicode)):
            return string[self.PREFIX_FIXED_LEN:]
        Log.fatal("Unsupported shift operation on {t}", t=type(string))
Exemplo n.º 29
0
    def add_auth(self, name, auth):
        """Create new authority for self named authority.

        Args:
            name       (str): Full name of the authority to add.
            auth (Authority): Authority instance to save to keychain.

        Raises:
            Exception: If named authority already exists in keychain.
        """

        if self.storage.has(self.get_auth_key(name)):
            Log.fatal("Cannot add authority on a duplicate entry")
        if not isinstance(auth, Authority):
            Log.fatal("Expected auth to be authority, got {t}", t=type(auth))
        self.storage.add(self.get_auth_key(name), auth.read())
Exemplo n.º 30
0
def main():
    """Main callable function.

    Configure logging capabilities, read input from shell or stdin (can exit
    fastly) and run unlocker manager.
    """

    # configure log
    Log.configure()
    Log.debug("Running in debug mode...")

    # read input
    args = read_input()

    # run unlocker with input args
    unlocker(args=args)