| OLD | NEW |
| (Empty) |
| 1 # Copyright (c) 2001-2004 Twisted Matrix Laboratories. | |
| 2 # See LICENSE for details. | |
| 3 | |
| 4 # | |
| 5 from twisted.conch.error import ConchError | |
| 6 from twisted.conch.ssh import common, keys, userauth, agent | |
| 7 from twisted.internet import defer, protocol, reactor | |
| 8 from twisted.python import log | |
| 9 | |
| 10 import agent | |
| 11 | |
| 12 import os, sys, base64, getpass | |
| 13 | |
| 14 def verifyHostKey(transport, host, pubKey, fingerprint): | |
| 15 goodKey = isInKnownHosts(host, pubKey, transport.factory.options) | |
| 16 if goodKey == 1: # good key | |
| 17 return defer.succeed(1) | |
| 18 elif goodKey == 2: # AAHHHHH changed | |
| 19 return defer.fail(ConchError('changed host key')) | |
| 20 else: | |
| 21 oldout, oldin = sys.stdout, sys.stdin | |
| 22 sys.stdin = sys.stdout = open('/dev/tty','r+') | |
| 23 if host == transport.transport.getPeer().host: | |
| 24 khHost = host | |
| 25 else: | |
| 26 host = '%s (%s)' % (host, | |
| 27 transport.transport.getPeer().host) | |
| 28 khHost = '%s,%s' % (host, | |
| 29 transport.transport.getPeer().host) | |
| 30 keyType = common.getNS(pubKey)[0] | |
| 31 print """The authenticity of host '%s' can't be established. | |
| 32 %s key fingerprint is %s.""" % (host, | |
| 33 {'ssh-dss':'DSA', 'ssh-rsa':'RSA'}[keyType], | |
| 34 fingerprint) | |
| 35 try: | |
| 36 ans = raw_input('Are you sure you want to continue connecting (yes/n
o)? ') | |
| 37 except KeyboardInterrupt: | |
| 38 return defer.fail(ConchError("^C")) | |
| 39 while ans.lower() not in ('yes', 'no'): | |
| 40 ans = raw_input("Please type 'yes' or 'no': ") | |
| 41 sys.stdout,sys.stdin=oldout,oldin | |
| 42 if ans == 'no': | |
| 43 print 'Host key verification failed.' | |
| 44 return defer.fail(ConchError('bad host key')) | |
| 45 print "Warning: Permanently added '%s' (%s) to the list of known hosts."
% (khHost, {'ssh-dss':'DSA', 'ssh-rsa':'RSA'}[keyType]) | |
| 46 known_hosts = open(os.path.expanduser('~/.ssh/known_hosts'), 'r+') | |
| 47 known_hosts.seek(-1, 2) | |
| 48 if known_hosts.read(1) != '\n': | |
| 49 known_hosts.write('\n') | |
| 50 encodedKey = base64.encodestring(pubKey).replace('\n', '') | |
| 51 known_hosts.write('%s %s %s\n' % (khHost, keyType, encodedKey)) | |
| 52 known_hosts.close() | |
| 53 return defer.succeed(1) | |
| 54 | |
| 55 def isInKnownHosts(host, pubKey, options): | |
| 56 """checks to see if host is in the known_hosts file for the user. | |
| 57 returns 0 if it isn't, 1 if it is and is the same, 2 if it's changed. | |
| 58 """ | |
| 59 keyType = common.getNS(pubKey)[0] | |
| 60 retVal = 0 | |
| 61 | |
| 62 if not options['known-hosts'] and not os.path.exists(os.path.expanduser('~/.
ssh/')): | |
| 63 print 'Creating ~/.ssh directory...' | |
| 64 os.mkdir(os.path.expanduser('~/.ssh')) | |
| 65 kh_file = options['known-hosts'] or '~/.ssh/known_hosts' | |
| 66 try: | |
| 67 known_hosts = open(os.path.expanduser(kh_file)) | |
| 68 except IOError: | |
| 69 return 0 | |
| 70 for line in known_hosts.xreadlines(): | |
| 71 split = line.split() | |
| 72 if len(split) < 3: | |
| 73 continue | |
| 74 hosts, hostKeyType, encodedKey = split[:3] | |
| 75 if host not in hosts.split(','): # incorrect host | |
| 76 continue | |
| 77 if hostKeyType != keyType: # incorrect type of key | |
| 78 continue | |
| 79 try: | |
| 80 decodedKey = base64.decodestring(encodedKey) | |
| 81 except: | |
| 82 continue | |
| 83 if decodedKey == pubKey: | |
| 84 return 1 | |
| 85 else: | |
| 86 retVal = 2 | |
| 87 return retVal | |
| 88 | |
| 89 class SSHUserAuthClient(userauth.SSHUserAuthClient): | |
| 90 | |
| 91 def __init__(self, user, options, *args): | |
| 92 userauth.SSHUserAuthClient.__init__(self, user, *args) | |
| 93 self.keyAgent = None | |
| 94 self.options = options | |
| 95 self.usedFiles = [] | |
| 96 if not options.identitys: | |
| 97 options.identitys = ['~/.ssh/id_rsa', '~/.ssh/id_dsa'] | |
| 98 | |
| 99 def serviceStarted(self): | |
| 100 if 'SSH_AUTH_SOCK' in os.environ and not self.options['noagent']: | |
| 101 log.msg('using agent') | |
| 102 cc = protocol.ClientCreator(reactor, agent.SSHAgentClient) | |
| 103 d = cc.connectUNIX(os.environ['SSH_AUTH_SOCK']) | |
| 104 d.addCallback(self._setAgent) | |
| 105 d.addErrback(self._ebSetAgent) | |
| 106 else: | |
| 107 userauth.SSHUserAuthClient.serviceStarted(self) | |
| 108 | |
| 109 def serviceStopped(self): | |
| 110 if self.keyAgent: | |
| 111 self.keyAgent.transport.loseConnection() | |
| 112 self.keyAgent = None | |
| 113 | |
| 114 def _setAgent(self, a): | |
| 115 self.keyAgent = a | |
| 116 d = self.keyAgent.getPublicKeys() | |
| 117 d.addBoth(self._ebSetAgent) | |
| 118 return d | |
| 119 | |
| 120 def _ebSetAgent(self, f): | |
| 121 userauth.SSHUserAuthClient.serviceStarted(self) | |
| 122 | |
| 123 def _getPassword(self, prompt): | |
| 124 try: | |
| 125 oldout, oldin = sys.stdout, sys.stdin | |
| 126 sys.stdin = sys.stdout = open('/dev/tty','r+') | |
| 127 p=getpass.getpass(prompt) | |
| 128 sys.stdout,sys.stdin=oldout,oldin | |
| 129 return p | |
| 130 except (KeyboardInterrupt, IOError): | |
| 131 print | |
| 132 raise ConchError('PEBKAC') | |
| 133 | |
| 134 def getPassword(self, prompt = None): | |
| 135 if not prompt: | |
| 136 prompt = "%s@%s's password: " % (self.user, self.transport.transport
.getPeer().host) | |
| 137 try: | |
| 138 p = self._getPassword(prompt) | |
| 139 return defer.succeed(p) | |
| 140 except ConchError: | |
| 141 return defer.fail() | |
| 142 | |
| 143 def getPublicKey(self): | |
| 144 if self.keyAgent: | |
| 145 blob = self.keyAgent.getPublicKey() | |
| 146 if blob: | |
| 147 return blob | |
| 148 files = [x for x in self.options.identitys if x not in self.usedFiles] | |
| 149 log.msg(str(self.options.identitys)) | |
| 150 log.msg(str(files)) | |
| 151 if not files: | |
| 152 return None | |
| 153 file = files[0] | |
| 154 log.msg(file) | |
| 155 self.usedFiles.append(file) | |
| 156 file = os.path.expanduser(file) | |
| 157 file += '.pub' | |
| 158 if not os.path.exists(file): | |
| 159 return self.getPublicKey() # try again | |
| 160 try: | |
| 161 return keys.getPublicKeyString(file) | |
| 162 except: | |
| 163 return self.getPublicKey() # try again | |
| 164 | |
| 165 def signData(self, publicKey, signData): | |
| 166 if not self.usedFiles: # agent key | |
| 167 return self.keyAgent.signData(publicKey, signData) | |
| 168 else: | |
| 169 return userauth.SSHUserAuthClient.signData(self, publicKey, signData
) | |
| 170 | |
| 171 def getPrivateKey(self): | |
| 172 file = os.path.expanduser(self.usedFiles[-1]) | |
| 173 if not os.path.exists(file): | |
| 174 return None | |
| 175 try: | |
| 176 return defer.succeed(keys.getPrivateKeyObject(file)) | |
| 177 except keys.BadKeyError, e: | |
| 178 if e.args[0] == 'encrypted key with no passphrase': | |
| 179 for i in range(3): | |
| 180 prompt = "Enter passphrase for key '%s': " % \ | |
| 181 self.usedFiles[-1] | |
| 182 try: | |
| 183 p = self._getPassword(prompt) | |
| 184 return defer.succeed(keys.getPrivateKeyObject(file, pass
phrase = p)) | |
| 185 except (keys.BadKeyError, ConchError): | |
| 186 pass | |
| 187 return defer.fail(ConchError('bad password')) | |
| 188 raise | |
| 189 except KeyboardInterrupt: | |
| 190 print | |
| 191 reactor.stop() | |
| 192 | |
| 193 def getGenericAnswers(self, name, instruction, prompts): | |
| 194 responses = [] | |
| 195 try: | |
| 196 oldout, oldin = sys.stdout, sys.stdin | |
| 197 sys.stdin = sys.stdout = open('/dev/tty','r+') | |
| 198 if name: | |
| 199 print name | |
| 200 if instruction: | |
| 201 print instruction | |
| 202 for prompt, echo in prompts: | |
| 203 if echo: | |
| 204 responses.append(raw_input(prompt)) | |
| 205 else: | |
| 206 responses.append(getpass.getpass(prompt)) | |
| 207 finally: | |
| 208 sys.stdout,sys.stdin=oldout,oldin | |
| 209 return defer.succeed(responses) | |
| OLD | NEW |