def initialize(self): # check communication. output = utils.__execute__(command=["ssh-add", "-l"]) #print("DEBUG; initialize output ssh-add -l:",output) if "Failed to communicate" in output or "Error connecting to agent" in output: if not self.delete()["success"]: l = subprocess.check_output(['eval', '"$(ssh-agent)"'], shell=True).decode() output = utils.__execute__(command=["ssh-add", "-l"]) if "Failed to communicate" in output or "Error connecting to agent" in output: return dev0s.response.error( "Failed to communicate with the ssh-agent.") else: output = utils.__execute__(command=["ssh-add", "-l"]) if "Failed to communicate" in output or "Error connecting to agent" in output: return dev0s.response.error( "Failed to communicate with the ssh-agent.") else: output = utils.__execute__(command=["ssh-add", "-l"]) if "Failed to communicate" in output or "Error connecting to agent" in output: return dev0s.response.error( "Failed to communicate with the ssh-agent.") # success. return dev0s.response.success( f"Successfully initialized the ssh agent.")
def __check_utils_installed__(self, usernames=[]): # iterate. if isinstance(usernames, str): usernames = [usernames] to_install = [] for username in usernames: # non existant. fp = FilePath( f"{dev0s.defaults.vars.homes}{username}/.ssht00ls/utils/.version" ) if not fp.exists(sudo=True): to_install.append(username) # check version. else: version = utils.__execute__(["sudo", "cat", fp.path]) github_version = utils.__execute__([ "curl", "https://raw.githubusercontent.com/vandenberghinc/ssht00ls/master/.version?raw=true" ]) if str(version) != str(github_version): to_install.append(username) # install. if len(to_install) > 0: response = self.__install_utils__(to_install) if response["error"] != None: return response # success. return dev0s.response.success( "Successfully verified the ssht00ls utils installation.")
def unmount( self, # the client path. path=None, # the forced umount option. forced=False, # forced option may require sudo. sudo=False, ): # checks. response = dev0s.response.parameters.check( traceback=self.__traceback__(function="unmount"), parameters={"path": path}) if not response["success"]: return response command = [] if sudo: command.append("sudo") command += ["umount"] if forced: command.append("-f") command += [path] output = utils.__execute__(command=command) if output != "": l = f"Failed to unmount directory [{path}]." return dev0s.response.error( (f"{l}, error: " + output.replace("\n", ". ").replace(". .", ".") + ".)").replace(". .", ".").replace("\r", "").replace("..", ".")) else: return dev0s.response.success( f"Successfully unmounted directory [{path}].")
def scan(self, silent=False): # list. output = utils.__execute__(["ykman", "list"], shell=False, return_format="array") # iterate. count, smartcards = 0, {} for card in output: if card not in [""]: try: serial_number = card.split("Serial: ")[1].replace(" ", "") text = card.split(" Serial:")[0] smartcards[serial_number] = SmartCard( serial_number=serial_number) except IndexError: return dev0s.response.error( "Unrecognized smart card detected. Remove the smart card and plug it back in." ) # response. return dev0s.response.success( f"Successfully scanned & detected {len(smartcards)} smart card(s).", {"smartcards": smartcards})
def __load_keys__(self, username): # make readable. if username == None: username = syst3m.defaults.vars.user sudo = syst3m.defaults.vars.user != username or True ssh_dir = FilePath(f"{syst3m.defaults.vars.homes}/{username}/.ssh/") auth_keys = FilePath(f"{syst3m.defaults.vars.homes}/{username}/.ssh/authorized_keys") # checks. if not ssh_dir.exists(sudo=sudo): ssh_dir.create( directory=True, permission=770, owner=username, group=None, sudo=sudo,) if not auth_keys.exists(sudo=sudo): auth_keys.create( directory=False, data="", permission=770, owner=username, group=None, sudo=sudo,) ssh_dir.permission.set(permission=770, sudo=sudo, silent=True) # silent for when non existant. auth_keys.permission.set(permission=770, sudo=sudo, silent=True) # silent for when non existant. auth_keys.ownership.set(owner=syst3m.defaults.vars.user, sudo=sudo) ssh_dir.ownership.set(owner=syst3m.defaults.vars.user, sudo=sudo) if sudo: command = ["sudo"] else: command = [] output = utils.__execute__(command + ["cat", f"{syst3m.defaults.vars.homes}/{username}/.ssh/authorized_keys"], return_format="array") return output
def delete(self): # delete keys. output = utils.__execute__(command=["ssh-add", "-D"]) # check success. if "Could not open a connection to your authentication agent." in output: return r3sponse.error("Failed to communicate with the ssh-agent.") elif "All identities removed." in output: return r3sponse.success(f"Successfully removed all keys from the ssh agent.") else: return r3sponse.error(f"Failed to remove all keys from the ssh agent.")
def list(self): # initialize. keys = [] # list keys. output = utils.__execute__(command=["ssh-add", "-L"], return_format="array") if "Failed to communicate" in output: return r3sponse.error("Failed to communicate with the ssh-agent.") elif "The agent has no identities." in output: keys = [] else: keys = output return r3sponse.success(f"Successfully listed the agent's keys.", { "keys":keys, })
def unmount(self, # the client path. client_path=None, # the forced umount option. forced=False, # forced option may require sudo. sudo=False, ): # checks. response = r3sponse.check_parameters(client_path, "client_path", None) if not response["success"]: return response command = [] if sudo: command.append("sudo") command += ["umount"] if forced: command.append("-f") command += [client_path] output = utils.__execute__(command=command) if output != "": l = f"Failed to unmount directory [{client_path}]." return r3sponse.error((f"{l}, error: "+output.replace("\n", ". ").replace(". .", ".")+".)").replace(". .",".").replace("\r","").replace("..",".")) else: return r3sponse.success(f"Successfully unmounted directory [{client_path}].")
def edit_comment(self, path=None, passphrase=None, comment=None): # check specific. if self.specific: if path == None: path = self.private_key # checks. path = Formats.denitialize(path) passphrase = Formats.denitialize(passphrase) comment = Formats.denitialize(comment) response = r3sponse.check_parameters({ "old":old, "passphrase":passphrase, "comment":comment, }) if not response["success"]: return response # check dir. if os.path.isdir(path): path += '/private_key' # do. output = utils.__execute__(["ssh-keygen", "-c", "-P", passphrase, "-C", comment, "-f", path]) # check fails. if "incorrect passphrase supplied" in output: return r3sponse.error(f"Provided an incorrect passphrase for key [{path}].") elif "No such file or directory" in output: return r3sponse.error(f"Key [{path}] does not exist.") # check success. elif "Comment '" in output and "' applied" in output: return r3sponse.success(f"Successfully edited the comment of key [{path}].") # unknown. else: l = f"Failed to edit the comment of key [{path}]" return r3sponse.error((f"{l}, error: "+output.replace("\n", ". ").replace(". .", ".")+".)").replace(". .",".").replace("\r","").replace("..","."))
def edit_passphrase(self, path=None, old=None, new=None): # check specific. if self.specific: if path == None: path = self.private_key # checks. path = Formats.denitialize(path) old = Formats.denitialize(old) new = Formats.denitialize(new) response = r3sponse.check_parameters({ "old":old, "new":new, "path":path, }) if not response["success"]: return response # check dir. if os.path.isdir(path): path += '/private_key' # do. output = utils.__execute__(["ssh-keygen", "-p", "-P", old, "-N", new, "-f", path]) # check fails. if "incorrect passphrase supplied" in output: return r3sponse.error(f"Provided an incorrect passphrase for key [{path}].") elif "No such file or directory" in output: return r3sponse.error(f"Key [{path}] does not exist.") # check success. elif "Your identification has been saved with the new passphrase" in output: return r3sponse.success(f"Successfully edited the passphrase of key [{path}].") # unknown. else: l = f"Failed to edit the passphrase of key [{path}]" return r3sponse.error((f"{l}, error: "+output.replace("\n", ". ").replace(". .", ".")+".)").replace(". .",".").replace("\r","").replace("..","."))
def add( self, # the private key's path. private_key=None, # the public key's path (optional). public_key=None, # the keys passphrase. passphrase=None, # enable if you are using a smart card. smartcard=False, # the smart cards pin code pin=None, # default timeout (do not use). timeout=0.5, # reattempt (do not use). reattempt=True, ): # check specific. if self.specific: if private_key == None: private_key = self.private_key if public_key == None: public_key = self.public_key if smartcard == None: smartcard = self.smartcard # initialize. private_key = private_key.replace("//", "/") response = dev0s.response.parameters.check( default=None, parameters={"private_key": private_key}, traceback=self.__traceback__(function="add")) if not response["success"]: return response if smartcard: response = dev0s.response.parameters.check( default=None, parameters={"pin": pin}, traceback=self.__traceback__(function="add")) if not response["success"]: return response else: if not Files.exists(private_key): return dev0s.response.error( f"Private key [{private_key}] does not exist.") if public_key == None: public_key = private_key.replace("/private_key", "/public_key") if not Files.exists(public_key): return dev0s.response.error( f"Public key [{public_key}] does not exist.") # check agent connection. output = utils.__execute__(["ssh-add", "-L"]) if "Failed to communicate" in output or "agent refused operation" in output or "Error connecting to agent" in output or "Connection refused" in output: if reattempt: utils.ssh_agent() return self.add( # the keys path. private_key=private_key, # the keys passphrase. passphrase=passphrase, # enable if you are using a smart card. smartcard=smartcard, # the smart cards pin code pin=pin, # default timeout (do not use). timeout=timeout, # reattempt (do not use). reattempt=False, ) else: return dev0s.response.error( "Failed to communicate with the ssh-agent. Try logging out the current system user & logging back in (or execute [$ eval `ssh-agent`])." ) # check already added. if not smartcard: response = self.check(public_key=public_key, raw=False) if response.success: return dev0s.response.success( f"Key [{private_key}] is already added to the ssh agent.") # with passphrase. if smartcard or passphrase not in [False, None, "", "none", "None"]: if smartcard: private_key = smartcards.path if dev0s.defaults.vars.os in ["macos"]: os.system(f"rm -fr {smartcards.path}") os.system( f"cp {smartcards.original_path} {smartcards.path}") os.system(f"chmod 644 {smartcards.path}") #try: # output = subprocess.check_output([f"ssh-add", "-e", f"{private_key}"]) # print("remove card output:",output) #except: a=1 spawn = pexpect.spawn(f'ssh-add -s {private_key}') else: # start. spawn = pexpect.spawn(f'ssh-add {private_key}') # send lines. output = None try: # handle pincode. if smartcard: spawn.expect( f'Enter passphrase for PKCS#11:', timeout=timeout, ) spawn.sendline(str(pin)) # handle pass. else: spawn.expect( f'Enter passphrase for {private_key}:', timeout=timeout, ) spawn.sendline(passphrase) except pexpect.exceptions.TIMEOUT: a = 1 except pexpect.exceptions.EOF: a = 1 # excpect eof. try: r = spawn.expect(["Bad passphrase", "Incorrect pin"], timeout=0.5) if r == 0: return dev0s.response.error( f"Provided an incorrect passphrase for key [{private_key}]." ) elif r == 1: return dev0s.response.error( "Provided an incorrect pin code.") else: raise ValueError(f"Unknown spawn behaviour: {spawn}") except pexpect.exceptions.TIMEOUT: a = 1 except pexpect.exceptions.EOF: a = 1 # handle output. output = spawn.read().decode() # check success. if "incorrect passphrase" in output.lower( ) or "bad passphrase" in output.lower(): return dev0s.response.error( f"Provided an incorrect passphrase for key [{private_key}]." ) elif "incorrect pin" in output.lower(): return dev0s.response.error("Provided an incorrect pin code.") elif "Failed to communicate" in output or "agent refused operation" in output or "Error connecting to agent" in output or "Connection refused" in output: if reattempt: utils.ssh_agent() return self.add( # the keys path. private_key=private_key, # the keys passphrase. passphrase=passphrase, # enable if you are using a smart card. smartcard=smartcard, # the smart cards pin code pin=pin, # default timeout (do not use). timeout=timeout, # reattempt (do not use). reattempt=False, ) else: return dev0s.response.error( "Failed to communicate with the ssh-agent. Try logging out the current system user & logging back in (or execute [$ eval `ssh-agent`])." ) elif "Identity added:" in output or "Card added:" in output: return dev0s.response.success( f"Successfully added key [{private_key}] to the ssh agent." ) elif output != "": return dev0s.response.error( f"Failed to add key [{private_key}] to the ssh agent, error: {output}" ) else: # no output check if key added. if not smartcard: response = self.check(public_key=public_key, raw=False) if response.success: return dev0s.response.success( f"Successfully added key [{private_key}] to the ssh agent." ) else: return dev0s.response.error( f"Failed to add key [{private_key}] to the ssh agent (#2) (output: {output})." ) else: return dev0s.response.error( f"Failed to add key [{private_key}] to the ssh agent (#1) (output: {output})." ) # handle eof. """try: spawn.expect(pexpect.EOF, timeout=timeout) except pexpect.ExceptionPexpect as epe: return dev0s.response.error(f"Failed to add key [{private_key}] to the ssh agent #3.")""" # without pass. else: output = utils.__execute__(command=["ssh-add", private_key], shell=False, timeout=timeout) # check success. if "Failed to communicate" in output or "agent refused operation" in output or "Error connecting to agent" in output or "Connection refused" in output: return dev0s.response.error( "Failed to communicate with the ssh-agent.") elif "Identity added:" in output: return dev0s.response.success( f"Successfully added key [{private_key}] to the ssh agent." ) else: return dev0s.response.error( f"Failed to add key [{private_key}] to the ssh agent, error: {output}" )
def check(self, public_key=None, raw=False): # check specific. if self.specific: if public_key == None: raw = False public_key = self.public_key # params. response = dev0s.response.parameters.check( {"public_key": public_key}, traceback=self.__traceback__(function="check")) if not response["success"]: return response # checks. if not raw and not Files.exists(public_key): return dev0s.response.error( f"Public key path [{public_key}] does not exist.") # load public key. if not raw: try: public_key = Files.load(public_key) except FileNotFoundError: return dev0s.response.error( f"Failed to load public key path [{public_key}].") # check. output = utils.__execute__(["ssh-add", "-L"]) if str(public_key.replace("\n", '')) in output: return dev0s.response.success( f"Public key [{public_key}] is added to the ssh agent.") else: return dev0s.response.error( f"Public key [{public_key}] is not added to the ssh agent.") ##################################################################################################################### # OLD. # retrieve id from public key. """ try: public_key_id = public_key.split("[#id:")[1].split("]")[0] except IndexError: return dev0s.response.error(f"Public key [{public_key}] does not contain any id.") # list. response = self.list() if response["error"] != None: return response success = False for key in response["keys"]: try: l_id = key.split("[#id:")[1].split("]")[0] if l_id == public_key_id: success = True break except IndexError: a=1 """ # list. response = self.list() if response["error"] != None: return response success = False for key in response["keys"]: if public_key.replace("\n", "") in key: success = True break # success. if success: return dev0s.response.success( f"Public key [{public_key}] is added to the ssh agent.") else: return dev0s.response.error( f"Public key [{public_key}] is not added to the ssh agent.")
def download( self, # the file paths. server_path=None, client_path=None, directory=False, # the ssh params. # option 1: alias=None, # option 2: username=None, ip=None, port=22, key_path=None, ): # checks. if alias == None: response = r3sponse.check_parameters(empty_value=None, parameters={ "username": username, "ip": ip, "server_path": server_path, "client_path": client_path, "key_path": key_path, "port": port, }) if not response["success"]: return response else: response = r3sponse.check_parameters(empty_value=None, parameters={ "alias": alias, "server_path": server_path, "client_path": client_path, }) if not response["success"]: return response # check client path. if Files.exists(client_path): return r3sponse.error( f"Client path [{client_path}] already exists.") # do. command = self.__build__( alias=alias, port=port, key_path=key_path, ) if directory: command += ["-r"] if alias == None: alias = f'{username}@{ip}' output = utils.__execute__(command + [f'{alias}:{server_path}', client_path], shell=False) #output = utils.__execute_script__(utils.__array_to_string__(command + [f'{alias}:{server_path}', client_path], joiner="\n"), shell=False) # check fails. if "No such file or directory" in output: return r3sponse.error( f"Server path [{server_path}] does not exist.") elif "not a regular file" in output: return r3sponse.error( f"Server path [{server_path}] is a directory.") elif "" == output: if not Files.exists(client_path): return r3sponse.error(f"Failed to download [{server_path}].") # check success. else: return r3sponse.success( f"Successfully downloaded [{server_path}].") # unknown. else: l = f"Failed to download [{client_path}]" return r3sponse.error( (f"{l}, error: " + output.replace("\n", ". ").replace(". .", ".") + ".)").replace(". .", ".").replace("\r", "").replace("..", "."))
def upload( self, # the file paths. server_path=None, client_path=None, directory=False, # the ssh params. # option 1: alias=None, # option 2: username=None, ip=None, port=22, key_path=None, ): # checks. if alias == None: response = dev0s.response.parameters.check( default=None, parameters={ "username": username, "ip": ip, "server_path": server_path, "client_path": client_path, "key_path": key_path, "port": port, }, traceback=self.__traceback__(function="upload")) if not response["success"]: return response else: response = dev0s.response.parameters.check( default=None, parameters={ "alias": alias, "server_path": server_path, "client_path": client_path, }, traceback=self.__traceback__(function="upload")) if not response["success"]: return response # check client path. if not Files.exists(client_path): return dev0s.response.error( f"Client path [{client_path}] does not exist.") # do. command = self.__build__( alias=alias, port=port, key_path=key_path, ) if directory: command += ["-r"] if alias == None: alias = f'{username}@{ip}' output = utils.__execute__(command + [client_path, f'{alias}:{server_path}'], shell=False) #output = utils.__execute_script__(utils.__array_to_string__(command + [client_path, f'{alias}:{server_path}'], joiner="\n"), shell=False) # check fails. if "No such file or directory" in output: return dev0s.response.error( f"The base path [{FilePath(server_path).base()}] of the specified file does not exist on the server." ) elif "not a regular file" in output: return dev0s.response.error( f"Client path [{client_path}] is a directory.") elif "" == output: return dev0s.response.success( f"Successfully uploaded [{client_path}].") # unknown. else: l = f"Failed to upload [{client_path}]" return dev0s.response.error( (f"{l}, error: " + output.replace("\n", ". ").replace(". .", ".") + ".)").replace(". .", ".").replace("\r", "").replace("..", "."))