~dustin-spy/twisted/dustin

« back to all changes in this revision

Viewing changes to twisted/conch/userauth.py

  • Committer: z3p
  • Date: 2002-07-17 14:44:36 UTC
  • Revision ID: vcs-imports@canonical.com-20020717144436-6dce525e73d836e2
moving secsh to conch.
Conch: The Twisted Shell

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import os.path, base64
 
2
from twisted.internet import defer
 
3
from common import NS, getNS, MP
 
4
import keys, transport, service
 
5
 
 
6
class SSHUserAuthServer(service.SSHService):
 
7
    name = 'ssh-userauth'
 
8
    protocolMessages = None # set later
 
9
    supportedAuthentications = ('publickey','password')
 
10
    authenticatedWith = []
 
11
 
 
12
    def tryAuth(self, kind, user, data):
 
13
        print 'trying auth %s for %s' % (kind, user)
 
14
        #print 'with data: %s' % repr(data)
 
15
        f= getattr(self,'auth_%s'%kind, None)
 
16
        if f:
 
17
            return f(user, data)
 
18
        return 0
 
19
 
 
20
    def ssh_USERAUTH_REQUEST(self, packet):
 
21
        user, nextService, method, rest = getNS(packet, 3)
 
22
        self.nextService = nextService
 
23
        r = self.tryAuth(method, user, rest)
 
24
        if r<0: # sent a different packet type back
 
25
            return
 
26
        if type(r) != type(defer.Deferred()):
 
27
            if r:
 
28
                r = defer.succeed(None)
 
29
            else:
 
30
                r = defer.fail(None)
 
31
        r.addCallbacks(self._cbGoodAuth, self._cbBadAuth, callbackArgs = (method,))
 
32
 
 
33
    def _cbGoodAuth(self, foo, method):
 
34
        self.authenticatedWith.append(method)
 
35
        if self.areDone():
 
36
            self.transport.sendPacket(MSG_USERAUTH_SUCCESS, '')
 
37
            self.transport.setService(self.transport.factory.services[self.nextService]())
 
38
        else:
 
39
            self.transport.sendPacket(MSG_USERAUTH_FAILURE, NS(','.join(self.supportedAuthentications))+'\xff')
 
40
 
 
41
    def _cbBadAuth(self, foo):
 
42
        self.transport.sendPacket(MSG_USERAUTH_FAILURE, NS(','.join(self.supportedAuthentications))+'\x00')
 
43
 
 
44
    def auth_publickey(self, user, packet):
 
45
        hasSig = ord(packet[0])
 
46
        self.hasSigType = hasSig # protocol impl.s differ in this
 
47
        algName, blob, rest = getNS(packet[1:], 2)
 
48
        print hasSig, algName
 
49
        if hasSig:
 
50
            if self.isValidKeyFor(user, blob) and self.verifySignatureFor(user, blob, getNS(rest)[0]):
 
51
                    return 1
 
52
            return 0
 
53
        else:
 
54
            if self.isValidKeyFor(user, blob):
 
55
                self.transport.sendPacket(MSG_USERAUTH_PK_OK, packet[1:])
 
56
                return -1
 
57
            return 0
 
58
 
 
59
    def verifySignatureFor(self, user, blob, signature):
 
60
        pubKey = keys.getPublicKeyObject(data = blob)
 
61
        b = NS(self.transport.sessionID) + chr(MSG_USERAUTH_REQUEST) + \
 
62
            NS(user) + NS(self.nextService) + NS('publickey') + chr(self.hasSigType) + \
 
63
            NS(keys.objectType(pubKey)) + NS(blob)
 
64
        return keys.verifySignature(pubKey, signature, b)
 
65
 
 
66
#    def aut
 
67
 
 
68
    # overwrite on the client side            
 
69
    def areDone(self):
 
70
        return len(self.authenticatedWith)>0
 
71
        
 
72
    def isValidKeyFor(self, user, pubKey):
 
73
        home = os.path.expanduser('~%s/.ssh/' % user)
 
74
        for file in ['authorized_keys', 'authorized_keys2']:
 
75
            if os.path.exists(home+file):
 
76
                lines = open(home+file).readlines()
 
77
                for l in lines:
 
78
                    if base64.decodestring(l.split()[1])==pubKey:
 
79
                        return 1
 
80
        print 'not vaild key'
 
81
        return 0
 
82
 
 
83
class SSHUserAuthClient(service.SSHService):
 
84
    name = 'ssh-userauth'
 
85
    protocolMessages = None # set later
 
86
    def __init__(self, user, instance):
 
87
        self.user = user
 
88
        self.instance = instance
 
89
        self.authenticatedWith = []
 
90
        self.triedPublicKeys = []
 
91
 
 
92
    def serviceStarted(self):
 
93
        self.askForAuth('none', '')
 
94
 
 
95
    def askForAuth(self, kind, extraData):
 
96
        self.lastAuth = kind
 
97
        self.transport.sendPacket(MSG_USERAUTH_REQUEST, NS(self.user) + \
 
98
                                  NS(self.instance.name) + NS(kind) + extraData)
 
99
    def tryAuth(self, kind):
 
100
        f= getattr(self,'auth_%s'%kind, None)
 
101
        if f:
 
102
            return f()
 
103
        
 
104
    def ssh_USERAUTH_SUCCESS(self, packet):
 
105
        self.transport.setService(self.instance)
 
106
 
 
107
    def ssh_USERAUTH_FAILURE(self, packet):
 
108
        canContinue, partial = getNS(packet)
 
109
        canContinue = canContinue.split(',')
 
110
        print canContinue
 
111
        partial = ord(partial)
 
112
        if partial:
 
113
            self.authenticatedWith.append(self.lastAuth)
 
114
        for method in canContinue:
 
115
            if method not in self.authenticatedWith and self.tryAuth(method):
 
116
                break
 
117
 
 
118
    def ssh_USERAUTH_PK_OK(self, packet):
 
119
        if self.lastAuth == 'publickey':
 
120
            # this is ok
 
121
            privateKey = keys.getPrivateKeyObject(os.path.expanduser('~/.ssh/id_rsa'))
 
122
            publicKey = keys.getPublicKeyString(os.path.expanduser('~/.ssh/id_rsa.pub'))
 
123
            b = NS(self.transport.sessionID) + chr(MSG_USERAUTH_REQUEST) + \
 
124
                NS(self.user) + NS(self.instance.name) + NS('publickey') + '\xff' + \
 
125
                NS('ssh-rsa') + NS(publicKey)
 
126
            self.askForAuth('publickey', '\xff' + NS('ssh-rsa') + NS(publicKey) + \
 
127
                            NS(keys.signData(privateKey, b)))
 
128
        elif self.lastAuth == 'password':
 
129
            prompt, language, rest = getNS(packet, 2)
 
130
            op = getpass('Old Password: ')
 
131
            np = getpass(prompt)
 
132
            self.askForAuth('password', '\xff'+NS(op)+NS(np))
 
133
 
 
134
    def auth_publickey(self):
 
135
        if os.path.exists(os.path.expanduser('~/.ssh/id_rsa')) and not 'file' in self.triedPublicKeys:
 
136
            self.triedPublicKeys.append('file')
 
137
            self.askForAuth('publickey', '\x00' + NS('ssh-rsa') + \
 
138
                            NS(keys.getPublicKeyString(os.path.expanduser('~/.ssh/id_rsa.pub'))))
 
139
            return 1
 
140
 
 
141
    def auth_password(self):
 
142
        d = self.getPassword()
 
143
        d.addCallback(self._cbPassword)
 
144
        return 1
 
145
 
 
146
    def _cbPassword(self, password):
 
147
        self.askForAuth('password', '\x00'+NS(password))
 
148
 
 
149
    def getPassword(self, prompt = None):
 
150
        if not prompt:
 
151
            prompt = 'Password for %s: ' % self.user
 
152
        return defer.succeed(getpass(prompt))
 
153
 
 
154
def getpass(prompt = "Password: "):
 
155
    import termios, sys
 
156
    fd = sys.stdin.fileno()
 
157
    old = termios.tcgetattr(fd)
 
158
    new = termios.tcgetattr(fd)
 
159
    new[3] = new[3] & ~termios.ECHO          # lflags
 
160
    try:
 
161
        termios.tcsetattr(fd, termios.TCSADRAIN, new)
 
162
        passwd = raw_input(prompt)
 
163
    finally:
 
164
        termios.tcsetattr(fd, termios.TCSADRAIN, old)
 
165
    return passwd
 
166
 
 
167
MSG_USERAUTH_REQUEST          = 50
 
168
MSG_USERAUTH_FAILURE          = 51
 
169
MSG_USERAUTH_SUCCESS          = 52
 
170
MSG_USERAUTH_BANNER           = 53
 
171
MSG_USERAUTH_PASSWD_CHANGEREQ = 60
 
172
MSG_USERAUTH_PK_OK            = 60
 
173
 
 
174
messages = {}
 
175
import userauth
 
176
for v in dir(userauth):
 
177
    if v[:4]=='MSG_':
 
178
        messages[getattr(userauth,v)] = v # doesn't handle doubles
 
179
 
 
180
SSHUserAuthServer.protocolMessages = messages
 
181
SSHUserAuthClient.protocolMessages = messages
 
182
 
 
183
 
 
184
 
 
185