| OLD | NEW |
| (Empty) |
| 1 import os, base64, binascii | |
| 2 try: | |
| 3 import pwd | |
| 4 except ImportError: | |
| 5 pwd = None | |
| 6 else: | |
| 7 import crypt | |
| 8 | |
| 9 try: | |
| 10 # get this from http://www.twistedmatrix.com/users/z3p/files/pyshadow-0.2.ta
r.gz | |
| 11 import shadow | |
| 12 except: | |
| 13 shadow = None | |
| 14 | |
| 15 try: | |
| 16 import pamauth | |
| 17 except ImportError: | |
| 18 pamauth = None | |
| 19 | |
| 20 from twisted.conch import error | |
| 21 from twisted.conch.ssh import keys | |
| 22 from twisted.cred.checkers import ICredentialsChecker | |
| 23 from twisted.cred.credentials import IUsernamePassword, ISSHPrivateKey, IPluggab
leAuthenticationModules | |
| 24 from twisted.cred.error import UnauthorizedLogin, UnhandledCredentials | |
| 25 from twisted.internet import defer | |
| 26 from twisted.python import failure, reflect, log | |
| 27 from zope import interface | |
| 28 | |
| 29 def verifyCryptedPassword(crypted, pw): | |
| 30 if crypted[0] == '$': # md5_crypt encrypted | |
| 31 salt = '$1$' + crypted.split('$')[2] | |
| 32 else: | |
| 33 salt = crypted[:2] | |
| 34 return crypt.crypt(pw, salt) == crypted | |
| 35 | |
| 36 class UNIXPasswordDatabase: | |
| 37 credentialInterfaces = IUsernamePassword, | |
| 38 interface.implements(ICredentialsChecker) | |
| 39 | |
| 40 def requestAvatarId(self, credentials): | |
| 41 if pwd: | |
| 42 try: | |
| 43 cryptedPass = pwd.getpwnam(credentials.username)[1] | |
| 44 except KeyError: | |
| 45 return defer.fail(UnauthorizedLogin()) | |
| 46 else: | |
| 47 if cryptedPass not in ['*', 'x'] and \ | |
| 48 verifyCryptedPassword(cryptedPass, credentials.password): | |
| 49 return defer.succeed(credentials.username) | |
| 50 if shadow: | |
| 51 gid = os.getegid() | |
| 52 uid = os.geteuid() | |
| 53 os.setegid(0) | |
| 54 os.seteuid(0) | |
| 55 try: | |
| 56 shadowPass = shadow.getspnam(credentials.username)[1] | |
| 57 except KeyError: | |
| 58 os.setegid(gid) | |
| 59 os.seteuid(uid) | |
| 60 return defer.fail(UnauthorizedLogin()) | |
| 61 os.setegid(gid) | |
| 62 os.seteuid(uid) | |
| 63 if verifyCryptedPassword(shadowPass, credentials.password): | |
| 64 return defer.succeed(credentials.username) | |
| 65 return defer.fail(UnauthorizedLogin()) | |
| 66 | |
| 67 return defer.fail(UnauthorizedLogin()) | |
| 68 | |
| 69 | |
| 70 class SSHPublicKeyDatabase: | |
| 71 credentialInterfaces = ISSHPrivateKey, | |
| 72 interface.implements(ICredentialsChecker) | |
| 73 | |
| 74 def requestAvatarId(self, credentials): | |
| 75 d = defer.maybeDeferred(self.checkKey, credentials) | |
| 76 d.addCallback(self._cbRequestAvatarId, credentials) | |
| 77 d.addErrback(self._ebRequestAvatarId) | |
| 78 return d | |
| 79 | |
| 80 def _cbRequestAvatarId(self, validKey, credentials): | |
| 81 if not validKey: | |
| 82 return failure.Failure(UnauthorizedLogin()) | |
| 83 if not credentials.signature: | |
| 84 return failure.Failure(error.ValidPublicKey()) | |
| 85 else: | |
| 86 try: | |
| 87 pubKey = keys.getPublicKeyObject(data = credentials.blob) | |
| 88 if keys.verifySignature(pubKey, credentials.signature, | |
| 89 credentials.sigData): | |
| 90 return credentials.username | |
| 91 except: # any error should be treated as a failed login | |
| 92 f = failure.Failure() | |
| 93 log.err() | |
| 94 return f | |
| 95 return failure.Failure(UnauthorizedLogin()) | |
| 96 | |
| 97 def checkKey(self, credentials): | |
| 98 sshDir = os.path.expanduser('~%s/.ssh/' % credentials.username) | |
| 99 if sshDir.startswith('~'): # didn't expand | |
| 100 return 0 | |
| 101 uid, gid = os.geteuid(), os.getegid() | |
| 102 ouid, ogid = pwd.getpwnam(credentials.username)[2:4] | |
| 103 os.setegid(0) | |
| 104 os.seteuid(0) | |
| 105 os.setegid(ogid) | |
| 106 os.seteuid(ouid) | |
| 107 for name in ['authorized_keys2', 'authorized_keys']: | |
| 108 if not os.path.exists(sshDir+name): | |
| 109 continue | |
| 110 lines = open(sshDir+name).xreadlines() | |
| 111 os.setegid(0) | |
| 112 os.seteuid(0) | |
| 113 os.setegid(gid) | |
| 114 os.seteuid(uid) | |
| 115 for l in lines: | |
| 116 l2 = l.split() | |
| 117 if len(l2) < 2: | |
| 118 continue | |
| 119 try: | |
| 120 if base64.decodestring(l2[1]) == credentials.blob: | |
| 121 return 1 | |
| 122 except binascii.Error: | |
| 123 continue | |
| 124 return 0 | |
| 125 | |
| 126 def _ebRequestAvatarId(self, f): | |
| 127 if not f.check(UnauthorizedLogin, error.ValidPublicKey): | |
| 128 log.msg(f) | |
| 129 return failure.Failure(UnauthorizedLogin()) | |
| 130 return f | |
| 131 | |
| 132 | |
| 133 class SSHProtocolChecker: | |
| 134 interface.implements(ICredentialsChecker) | |
| 135 | |
| 136 checkers = {} | |
| 137 | |
| 138 successfulCredentials = {} | |
| 139 | |
| 140 def get_credentialInterfaces(self): | |
| 141 return self.checkers.keys() | |
| 142 | |
| 143 credentialInterfaces = property(get_credentialInterfaces) | |
| 144 | |
| 145 def registerChecker(self, checker, *credentialInterfaces): | |
| 146 if not credentialInterfaces: | |
| 147 credentialInterfaces = checker.credentialInterfaces | |
| 148 for credentialInterface in credentialInterfaces: | |
| 149 self.checkers[credentialInterface] = checker | |
| 150 | |
| 151 def requestAvatarId(self, credentials): | |
| 152 ifac = interface.providedBy(credentials) | |
| 153 for i in ifac: | |
| 154 c = self.checkers.get(i) | |
| 155 if c is not None: | |
| 156 return c.requestAvatarId(credentials).addCallback( | |
| 157 self._cbGoodAuthentication, credentials) | |
| 158 return defer.fail(UnhandledCredentials("No checker for %s" % \ | |
| 159 ', '.join(map(reflect.qal, ifac)))) | |
| 160 | |
| 161 def _cbGoodAuthentication(self, avatarId, credentials): | |
| 162 if avatarId not in self.successfulCredentials: | |
| 163 self.successfulCredentials[avatarId] = [] | |
| 164 self.successfulCredentials[avatarId].append(credentials) | |
| 165 if self.areDone(avatarId): | |
| 166 del self.successfulCredentials[avatarId] | |
| 167 return avatarId | |
| 168 else: | |
| 169 raise error.NotEnoughAuthentication() | |
| 170 | |
| 171 def areDone(self, avatarId): | |
| 172 """Override to determine if the authentication is finished for a given | |
| 173 avatarId. | |
| 174 """ | |
| 175 return 1 | |
| 176 | |
| OLD | NEW |