GPS.py (39878B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\common\script\net\GPS.py 2 import marshal 3 import socket 4 import sys 5 import types 6 import blue 7 import carbon.common.lib.const as const 8 import carbon.common.script.net.machobase as macho 9 import evecrypto.crypto as Crypto 10 import localization 11 import log 12 import uthread 13 from carbon.common.script.net.GPSExceptions import GPSTransportClosed, GPSRemoteTransportClosed 14 from carbon.common.script.net.machoNetExceptions import UserRejectedByVIP 15 from carbon.common.script.util.format import CaseFold 16 from eveexceptions import UserError 17 from eveprefs import prefs, boot 18 from eve.common.script.util.writebuffer import WriteBuffer 19 Enter = blue.pyos.taskletTimer.EnterTasklet 20 Leave = blue.pyos.taskletTimer.ReturnFromTasklet 21 ClientConnectFailed = socket.error 22 23 def ClientConnectFailedString(e): 24 return e.args[1] 25 26 27 def GetHostByName_Ex(host): 28 return socket.gethostbyname_ex(host)[2] 29 30 31 def GetAddrInfo(host): 32 return [ e[4][0] for e in socket.getaddrinfo(host, None) if e[0] == socket.AF_INET and not e[4][0].startswith('0.') ] 33 34 35 error = socket.error 36 gethostname = socket.gethostname 37 38 class GPSTransportFactory(object): 39 __guid__ = 'gps.GPSTransportFactory' 40 41 def __init__(self, useacl = 0, name = '(unknown)'): 42 self.useACL = useacl 43 self.name = name 44 45 def Listen(self, address): 46 pass 47 48 def Connect(self, address): 49 pass 50 51 52 class GPSAddressable(object): 53 54 def GetAddress(self): 55 return self.address 56 57 def GetESPAddress(self): 58 return self.__GetPrefixedAddress('externalNetPrefix', natOffset=True) 59 60 def GetExternalAddress(self): 61 return self.__GetPrefixedAddress('externalNetPrefix') 62 63 def GetInternalAddress(self): 64 return self.__GetPrefixedAddress('internalNetPrefix') 65 66 def __GetPrefixedAddress(self, prefixWhat, natOffset = False): 67 host, port = self.address.split(':') 68 addresses = GetAddrInfo(host) 69 ipaddress = None 70 find = [prefixWhat + '_' + macho.mode, prefixWhat, 'externalNetPrefix'] 71 for prefValue in find: 72 prefix = str(prefs.GetValue(prefValue, '')) 73 if prefix: 74 break 75 76 if prefix: 77 if not prefs.GetValue('enableNewStyleNetworkPrefix', False): 78 lastDot = addresses[0].rindex('.') 79 ipaddress = prefix + addresses[0][lastDot + 1:] 80 if len(ipaddress.split('.')) != 4: 81 raise RuntimeError('Configuration Error: %s MUST contain precisely three dots' % prefixWhat) 82 elif prefValue == 'externalNetPrefix_proxy': 83 lastDot = addresses[0].rindex('.') 84 lastBit = int(addresses[0][lastDot + 1:]) 85 if natOffset: 86 lastBit += int(prefs.GetValue('externalNetNatOffset', 0)) 87 ipaddress = prefix + str(lastBit) 88 if len(ipaddress.split('.')) != 4: 89 raise RuntimeError('Configuration Error: %s MUST contain precisely three dots' % prefixWhat) 90 else: 91 found = False 92 for ipaddress in GetHostByName_Ex(''): 93 if ipaddress.startswith(prefix): 94 found = True 95 break 96 97 if not found: 98 raise RuntimeError('Configuration Error: unable to find IP for %s using prefix %s ' % (prefixWhat, prefix)) 99 elif len(addresses) == 1: 100 ipaddress = addresses[0] 101 elif prefs.clusterMode not in ('LIVE', 'TEST'): 102 for address in addresses: 103 if address.startswith('10.0.'): 104 continue 105 if address.startswith('172.'): 106 continue 107 ipaddress = address 108 break 109 110 if ipaddress is None: 111 raise RuntimeError('No sane interfaces found from %s', addresses) 112 else: 113 raise RuntimeError("Configuration Error: Multiple potential %s addresses, couldn't determine which one to use." % prefixWhat) 114 return '%s:%s' % (ipaddress, port) 115 116 117 class GPSTransportAcceptor(GPSAddressable): 118 __guid__ = 'gps.GPSTransportAcceptor' 119 120 def __init__(self, useACL): 121 self.useACL = useACL 122 123 def CheckACL(self, address): 124 if self.useACL: 125 return sm.services['machoNet'].CheckACL(address) 126 127 def Accept(self): 128 return None 129 130 def Close(self, reason = None, reasonCode = None, reasonArgs = {}): 131 pass 132 133 134 class GPSTransport(GPSAddressable): 135 __guid__ = 'gps.GPSTransport' 136 __mandatory_fields__ = [] 137 __HANDSHAKE_SECRET_KEY = 170472 138 139 def __init__(self, *args, **keywords): 140 self.cryptoContext = Crypto.CryptoCreateContext() 141 self.handShakePaddingLength = boot.GetValue('handShakePaddingLength', 64) 142 self.handShake = None 143 144 def ProxyAuthenticationHandshakeLoad(self, packet): 145 global blue 146 ret = blue.marshal.Load(packet, skipCrcCheck=True) 147 if macho.mode != 'proxy': 148 log.LogError('ProxyAuthenticationHandshakeLoad can only be called on a proxy, currently on: ' + macho.mode) 149 raise GPSTransportClosed('ProxyAuthenticationHandshakeLoad called on an incorrect macho.mode') 150 if isinstance(ret, GPSTransportClosed): 151 raise ret 152 if not isinstance(ret, tuple): 153 log.LogError('ProxyAuthenticationHandshakeLoad Deserialized an unexpected type ' + type(ret).__name__ + ' but only (tuple,) is allowed.') 154 raise GPSTransportClosed('ProxyAuthenticationHandshakeLoad - Deserialized an unexpected type') 155 return ret 156 157 def Read(self): 158 pass 159 160 def Write(self, packet): 161 pass 162 163 def Close(self, reason = None, reasonCode = None, reasonArgs = {}): 164 pass 165 166 def IsClosed(self): 167 return True 168 169 def ApplyWithTimeout(self, func, args, timeout = 120, message = None): 170 rts = [0] 171 t = uthread.worker('machoNet::TimeoutWorker', self.TimeoutWorker, self, timeout, rts, message) 172 try: 173 ret = func(*args) 174 finally: 175 rts[0] = 1 176 t.kill() 177 178 return ret 179 180 @staticmethod 181 def TimeoutWorker(transport, secs, rts, message = None): 182 try: 183 blue.pyos.synchro.SleepWallclock(1000 * secs) 184 if not rts[0]: 185 transport.Close(*message) 186 except TaskletExit: 187 pass 188 189 def HandleClientAuthenticationStep1(self, transportID, counter): 190 handshakeTimeout = prefs.GetValue('GpsCompatibilityHandshakeTimeout', 120) * (10 if counter else 1) 191 log.general.Log('GPS[%d]: HandleClientAuthentication waiting for handshake (timeout=%ds, counter=%d)' % (transportID, handshakeTimeout, counter), log.LGINFO) 192 message = (localization.GetByLabel('/Carbon/GPS/ConnectionTimeoutClientNotCompatible'), 'HANDSHAKE_TIMEOUT_CLIENTCOMPATIBILITYHANDSHAKE') 193 packet = self.ApplyWithTimeout(self.UnEncryptedRead, (), message=message, timeout=handshakeTimeout) 194 if len(packet) == 0: 195 log.general.Log('Handshake Failed - Empty packet from %s' % self.GetAddress(), log.LGERR) 196 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_INCOMPATIBLEPROTOCOL') 197 return 'ERR' 198 response = self.ProxyAuthenticationHandshakeLoad(packet) 199 if not isinstance(response, tuple): 200 log.general.Log('Deserialized an unexpected type %s during ClientAuthenticationStep1 where only (tuple) is allowed' % type(response).__name__, log.LGERR) 201 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_FAILEDVERIFICATION') 202 return 'ERR' 203 if len(response) != 6: 204 log.general.Log('Returned tuple type in ClientAuthenticationStep1 has length=%d but should be length=6' % len(response), log.LGERR) 205 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_FAILEDVERIFICATION') 206 return 'ERR' 207 if not isinstance(response[0], int): 208 log.general.Log('HandshakeSecretKey is of unexpected type %s, should be int' % type(response[0]).__name__, log.LGERR) 209 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_FAILEDVERIFICATION') 210 return 'ERR' 211 if response[0] != GPSTransport.__HANDSHAKE_SECRET_KEY: 212 log.general.Log('HandshakeSecretKey value=%s failed validation, should be %s' % (response[0], GPSTransport.__HANDSHAKE_SECRET_KEY), log.LGERR) 213 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_FAILEDVERIFICATION') 214 return 'ERR' 215 if not isinstance(response[1], int): 216 log.general.Log('macho.version is of unexpected type %s, should be int' % type(response[1]).__name__, log.LGERR) 217 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_INCOMPATIBLEPROTOCOL') 218 return 'ERR' 219 if macho.version != response[1]: 220 log.general.Log('Handshake Failed - Insecure Macho Version Mismatch - Client: %s - Server: %s' % (response[1], macho.version), log.LGERR) 221 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_INCOMPATIBLEPROTOCOL') 222 return 'ERR' 223 if not isinstance(response[2], int): 224 log.general.Log('loggedOnUserCount is of unexpected type %s, should be int' % type(response[2]).__name__, log.LGERR) 225 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_FAILEDVERIFICATION') 226 return 'ERR' 227 if not isinstance(response[3], float): 228 log.general.Log('boot.version is of unexpected type %s, should be float' % type(response[3]).__name__, log.LGERR) 229 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleVersion'), 'HANDSHAKE_INCOMPATIBLEVERSION') 230 return 'ERR' 231 if boot.version != response[3]: 232 log.general.Log('Handshake Failed - Insecure Boot Version Mismatch (common.ini:version) - Client: %s - Server: %s' % (response[3], boot.version), log.LGERR) 233 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleVersion'), 'HANDSHAKE_INCOMPATIBLEVERSION') 234 return 'ERR' 235 if not isinstance(response[4], (int, unicode, str)): 236 log.general.Log('boot.build is of unexpected type %s, should be one of (int, unicode, str)' % type(response[4]).__name__, log.LGERR) 237 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleBuild'), 'HANDSHAKE_INCOMPATIBLEBUILD') 238 return 'ERR' 239 if boot.build > response[4]: 240 log.general.Log('Handshake Failed - Insecure Boot Build Mismatch (common.ini:build) - Client: %s - Server: %s' % (response[4], boot.build), log.LGERR) 241 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleBuild'), 'HANDSHAKE_INCOMPATIBLEBUILD') 242 return 'ERR' 243 if not isinstance(response[5], (str, unicode)): 244 log.general.Log('Combined boot.codename+@+boot.region is of unexpected type %s, should be one of (str, unicode)' % type(response[5]).__name__, log.LGERR) 245 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_FAILEDVERIFICATION') 246 return 'ERR' 247 if '@' in response[5]: 248 codename, region = response[5].split('@') 249 else: 250 codename, region = response[5], '' 251 if str(boot.region) != region: 252 if boot.role == 'client': 253 log.general.Log('Handshake Failed - Insecure Region Code Mismatch (common.ini:region) - Client: %s - Server: %s' % (region, str(boot.region)), log.LGERR) 254 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleRegion'), 'HANDSHAKE_INCOMPATIBLEREGION') 255 return 'ERR' 256 if str(boot.codename) != codename: 257 log.general.Log('Handshake Failed - Insecure Boot Code Name Mismatch (common.ini:codename) - Client: %s - Server: %s' % (codename, str(boot.codename)), log.LGERR) 258 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleRelease'), 'HANDSHAKE_INCOMPATIBLERELEASE') 259 return 'ERR' 260 return 'OK' 261 262 def HandleClientAuthenticationStep2(self, transportID, counter, eveInVIP): 263 log.general.Log('LLV Reading Client Crypto Context OR VIP Key OR Queue Check', log.LGINFO) 264 vipKey = None 265 message = (localization.GetByLabel('/Carbon/GPS/ConnectionTimeoutNoCompatibilityHandshake'), 'HANDSHAKE_TIMEOUT_CLIENTSECUREHANDSHAKE') 266 clientCryptoContextPacket = self.ProxyAuthenticationHandshakeLoad(self.ApplyWithTimeout(self.UnEncryptedRead, (), message=message)) 267 if not isinstance(clientCryptoContextPacket, tuple): 268 log.general.Log('Deserialized an unexpected type %s during ClientAuthenticationStep2 where only (tuple) is allowed' % type(clientCryptoContextPacket).__name__, log.LGERR) 269 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_FAILEDVERIFICATION') 270 return ('ERR', None, None, None) 271 if len(clientCryptoContextPacket) not in (2, 3): 272 log.general.Log('Returned tuple type in ClientAuthenticationStep2 has length=%d but should be length=2or3' % len(clientCryptoContextPacket), log.LGERR) 273 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_FAILEDVERIFICATION') 274 return ('ERR', None, None, None) 275 if not isinstance(clientCryptoContextPacket[1], str): 276 log.general.Log('ClientCryptContextPacket element[1] is of unexpected type %s, should be str' % type(clientCryptoContextPacket[1]).__name__, log.LGERR) 277 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_FAILEDVERIFICATION') 278 return ('ERR', None, None, None) 279 if len(clientCryptoContextPacket) == 3 and not isinstance(clientCryptoContextPacket[2], str): 280 log.general.Log('ClientCryptContextPacket element[2] is of unexpected type %s, should be str' % type(clientCryptoContextPacket[2]).__name__, log.LGERR) 281 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_FAILEDVERIFICATION') 282 return ('ERR', None, None, None) 283 if clientCryptoContextPacket[0] is None and clientCryptoContextPacket[1] == 'VK': 284 vipKey = clientCryptoContextPacket[2] 285 if clientCryptoContextPacket[0] is None and clientCryptoContextPacket[1] == 'VK': 286 log.general.Log('LLV Reading Client Crypto Context OR Queue Check', log.LGINFO) 287 message = (localization.GetByLabel('/Carbon/GPS/ConnectionTimeoutNoCompatibilityHandshake'), 'HANDSHAKE_TIMEOUT_CLIENTSECUREHANDSHAKE') 288 clientCryptoContextPacket = self.ProxyAuthenticationHandshakeLoad(self.ApplyWithTimeout(self.UnEncryptedRead, (), message=message)) 289 if counter == 0: 290 sm.GetService('machoNet').PutTransportInLogonQueue(transportID) 291 logonQueuePosition = sm.GetService('machoNet').GetLogonQueuePosition(transportID, vipKey) 292 if clientCryptoContextPacket[0] is None and clientCryptoContextPacket[1] == 'QC': 293 if eveInVIP: 294 self.Close(localization.GetByLabel('/Carbon/GPS/NotAcceptingConnections'), 'ACL_NOTACCEPTING') 295 return ('OK', None, None, None) 296 log.general.Log('Logon Queue Position Query - Complete', log.LGINFO) 297 self.UnEncryptedWrite(macho.Dumps(logonQueuePosition)) 298 return ('OK', None, None, None) 299 log.general.Log('LLV Reading Client Crypto Context', log.LGINFO) 300 keyVersion, request = clientCryptoContextPacket 301 if keyVersion != getattr(macho, 'publicKeyVersion', 'placebo'): 302 log.general.Log('Handshake Failed - Public Key Mismatch - Public Key Version is %s but should be %s' % (keyVersion, getattr(macho, 'publicKeyVersion', 'placebo')), log.LGERR) 303 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatiblePublicKey'), 'HANDSHAKE_INCOMPATIBLEPUBLICKEY') 304 return ('ERR', None, None, None) 305 log.general.Log('LLV Initializing Crypto Context', log.LGINFO) 306 cryptoCtxRequest = self.cryptoContext.Initialize(request) 307 if type(cryptoCtxRequest) != types.DictType: 308 self.Close('Handshake Failed - ' + cryptoCtxRequest) 309 return ('ERR', None, None, None) 310 return (None, 311 vipKey, 312 logonQueuePosition, 313 cryptoCtxRequest) 314 315 def HandleClientAuthenticationStep3(self, request): 316 passwordVersion = 0 317 userName = None 318 passwordVersionOK = False 319 passwordVersionAttempteRemaining = 2 320 while not passwordVersionOK: 321 if passwordVersionAttempteRemaining < 1: 322 self.Close('Password version handshake failure') 323 return ('ERR', None, None) 324 passwordVersionAttempteRemaining -= 1 325 log.general.Log('LLV Reading Secure Client Handshake', log.LGINFO) 326 message = (localization.GetByLabel('/Carbon/GPS/ConnectionTimeoutNoCompatibilityHandshake'), 'HANDSHAKE_TIMEOUT_CLIENTSECUREHANDSHAKE') 327 clientChallenge, request2 = self.ProxyAuthenticationHandshakeLoad(self.ApplyWithTimeout(self.EncryptedRead, (), message=message)) 328 if not isinstance(clientChallenge, str): 329 log.general.Log('Deserialized an unexpected type %s of clientChallenge during ClientAuthenticationStep3 where only str is allowed' % type(clientChallenge).__name__, log.LGERR) 330 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_FAILEDVERIFICATION') 331 return ('ERR', None, None) 332 if not isinstance(request2, types.DictType): 333 log.general.Log('Deserialized an unexpected type %s of request2 during ClientAuthenticationStep3 where only types.DictType is allowed' % type(request2).__name__, log.LGERR) 334 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_FAILEDVERIFICATION') 335 return ('ERR', None, None) 336 request.update(request2) 337 log.general.Log('LLV Verifying Secure Client Handshake', log.LGINFO) 338 for k in self.__mandatory_fields__: 339 if k not in request: 340 self.Close('Handshake corrupt, missing %s' % k) 341 return ('ERR', None, None) 342 343 if passwordVersion == 0 or userName != request['user_name']: 344 passwordVersion = 2 345 userName = request['user_name'] 346 if passwordVersionAttempteRemaining == 1: 347 log.general.Log('LLV Writing password version', log.LGINFO) 348 self.EncryptedWrite(macho.Dumps(passwordVersion)) 349 if passwordVersion == 1: 350 if request['user_password'] is not None: 351 passwordVersionOK = True 352 else: 353 passwordVersionOK = True 354 355 log.general.Log('LLV Performing Version Check', log.LGINFO) 356 if str(boot.region) != request['boot_region']: 357 log.general.Log('Handshake Failed - Boot Region Mismatch - Boot Region is %s but should be %s' % (request['boot.region'], str(boot.region)), log.LGERR) 358 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleRegion'), 'HANDSHAKE_INCOMPATIBLEREGION') 359 return ('ERR', None, None) 360 if str(boot.codename) != request['boot_codename']: 361 log.general.Log('Handshake Failed - Boot Code Name Mismatch - Boot Code Name is %s but should be %s' % (request['boot.codeName'], str(boot.codename)), log.LGERR) 362 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleRelease'), 'HANDSHAKE_INCOMPATIBLERELEASE') 363 return ('ERR', None, None) 364 if boot.version != request['boot_version']: 365 log.general.Log('Handshake Failed - Boot Version Mismatch - Boot Version is %s but should be %s' % (request['boot.version'], boot.version), log.LGERR) 366 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleVersion'), 'HANDSHAKE_INCOMPATIBLEVERSION') 367 return ('ERR', None, None) 368 if macho.version != request['macho_version']: 369 log.general.Log('Handshake Failed - Macho Version Mismatch - Macho Version is %s but should be %s' % (request['macho.version'], macho.version), log.LGERR) 370 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_INCOMPATIBLEPROTOCOL') 371 return ('ERR', None, None) 372 if boot.build > request['boot_build']: 373 log.general.Log('Handshake Failed - Boot Build Mismatch - Boot Build is %s but should be at least %s' % (request['boot.build'], boot.build), log.LGERR) 374 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleBuild'), 'HANDSHAKE_INCOMPATIBLEBUILD') 375 return ('ERR', None, None) 376 if len(clientChallenge) != self.handShakePaddingLength: 377 self.Close(localization.GetByLabel('/Carbon/GPS/IncorrentHandshakePadding', current=len(clientChallenge), expected=self.handShakePaddingLength)) 378 return ('ERR', None, None) 379 handShakeHash = Crypto.CryptoHash(clientChallenge) 380 return (None, request, handShakeHash) 381 382 def HandleClientAuthentication(self, loggedOnUserCount, transportID, counter, sessionID, eveInVIP): 383 timer = Enter('machoNet::GPS::HandleClientAuthentication') 384 try: 385 try: 386 updateInfo = sm.GetService('machoNet').GetValidClientCodeHash() 387 except: 388 log.general.Log('Clienthash info not available', log.LGINFO) 389 updateInfo = const.responseUnknown 390 391 initialHandshakeRequest = (GPSTransport.__HANDSHAKE_SECRET_KEY, 392 macho.version, 393 loggedOnUserCount, 394 boot.version, 395 boot.build, 396 str(boot.codename) + '@' + str(boot.region), 397 updateInfo) 398 self.UnEncryptedWrite(macho.Dumps(initialHandshakeRequest)) 399 step1Response = self.HandleClientAuthenticationStep1(transportID, counter) 400 if step1Response != 'OK': 401 return step1Response 402 step2ReturnCode, vipKey, logonQueuePosition, request = self.HandleClientAuthenticationStep2(transportID, counter, eveInVIP) 403 if step2ReturnCode is not None: 404 return step2ReturnCode 405 self.UnEncryptedWrite(macho.Dumps('OK CC')) 406 step3ReturnCode, request, handShakeHash = self.HandleClientAuthenticationStep3(request) 407 if step3ReturnCode is not None: 408 return step3ReturnCode 409 try: 410 globalConfig = sm.GetService('machoNet').GetGlobalConfig() 411 except: 412 log.LogException() 413 globalConfig = {} 414 415 log.general.Log('LLV Generating Server Challenge', log.LGINFO) 416 dict = {'challenge_responsehash': handShakeHash, 417 'macho_version': macho.version, 418 'boot_version': boot.version, 419 'boot_build': boot.build, 420 'boot_codename': str(boot.codename), 421 'boot_region': str(boot.region), 422 'cluster_usercount': loggedOnUserCount, 423 'proxy_nodeid': sm.GetService('machoNet').GetNodeID(), 424 'user_logonqueueposition': logonQueuePosition, 425 'config_vals': globalConfig} 426 serverChallenge = Crypto.GetRandomBytes(self.handShakePaddingLength) 427 log.general.Log('LLV Crypting Server Challenge', log.LGINFO) 428 from carbon.server.script.net import handShake 429 code = marshal.dumps(handShake.GetHandshakeFunc()) 430 ch = (serverChallenge, 431 Crypto.Sign(code), 432 {}, 433 dict) 434 log.general.Log('LLV Writing Server Challenge', log.LGINFO) 435 self.EncryptedWrite(macho.Dumps(ch)) 436 if not request['user_name'] or not (request['user_password'] or request['user_password_hash']) or logonQueuePosition > 1: 437 return 'OK' 438 if vipKey and vipKey != Crypto.CryptoHash(CaseFold(request['user_name'] or '')): 439 self.Close(localization.GetByLabel('/Carbon/GPS/HandshakeFailedVIPKey')) 440 return 'ERR' 441 log.general.Log('LLV Reading Client Challenge-Response', log.LGINFO) 442 message = (localization.GetByLabel('/Carbon/GPS/ConnectionTimeoutClientTimeout'), 'HANDSHAKE_TIMEOUT_CLIENTRESPONSETOSERVERCHALLENGE') 443 challengeResponse, funcOutput, funcResult = self.ProxyAuthenticationHandshakeLoad(self.ApplyWithTimeout(self.EncryptedRead, (), message=message)) 444 if not isinstance(challengeResponse, str): 445 log.general.Log('Deserialized an unexpected type %s of challengeResponse where only str is allowed' % type(challengeResponse).__name__, log.LGERR) 446 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_FAILEDVERIFICATION') 447 return 'ERR' 448 if not isinstance(funcOutput, str): 449 log.general.Log('Deserialized an unexpected type %s of funcOutput where only str is allowed' % type(funcOutput).__name__, log.LGERR) 450 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_FAILEDVERIFICATION') 451 return 'ERR' 452 if not isinstance(funcResult, types.DictType): 453 log.general.Log('Deserialized an unexpected type %s of funcResult where only types.DictType is allowed' % type(funcResult).__name__, log.LGERR) 454 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_FAILEDVERIFICATION') 455 return 'ERR' 456 if funcResult.get('errors', ''): 457 log.general.Log('Errors in verifying handshake function %s' % funcResult['errors'], log.LGERR) 458 if challengeResponse != Crypto.CryptoHash(serverChallenge): 459 self.Close(localization.GetByLabel('/Carbon/GPS/HandshakeFailedHashMismatch')) 460 return 'ERR' 461 verification = handShake.Verify(funcOutput, funcResult, request) 462 if verification is not None: 463 self.Close(localization.GetByLabel('/Carbon/GPS/HandshakeFailedVerificationFailure', verification=verification), 'HANDSHAKE_FAILEDVERIFICATION') 464 return 'ERR' 465 request['handshakefunc_output'] = funcOutput 466 request['handshakefunc_result'] = funcResult 467 try: 468 authenticationResult = sm.GetService('machoNet').Authenticate(self, request, sessionID) 469 request.update(authenticationResult) 470 except UserRejectedByVIP: 471 if not sm.GetService('machoNet').IsClusterShuttingDown(): 472 log.general.Log("Handshake Failed - VIP Check - The cluster is running in VIP mode, and you're not kewl", log.LGINFO) 473 self.Close(localization.GetByLabel('/Carbon/GPS/NotAcceptingConnections'), 'ACL_NOTACCEPTING') 474 return 'OK' 475 except UserError as e: 476 self.Close(e.msg, e.msg, e.dict) 477 return 'ERR' 478 except RuntimeError as e: 479 self.Close(e.msg, e.msg, e.dict) 480 return 'ERR' 481 except Exception: 482 log.LogException('Handshake Failed - Server Failure') 483 self.Close(localization.GetByLabel('/Carbon/GPS/HandshakeFailedServerFailure')) 484 return 'ERR' 485 486 authenticationResult['live_updates'] = sm.GetService('liveUpdateMgr').GetLiveUpdates(request) 487 authenticationResult['client_hash'] = sm.GetService('machoNet').GetValidClientCodeHash() 488 log.general.Log('LLV Writing Server Challenge-Response-Ack', log.LGINFO) 489 self.EncryptedWrite(macho.Dumps(authenticationResult)) 490 log.general.Log('LLV Succeeded', log.LGINFO) 491 self.handShake = request 492 return request 493 finally: 494 Leave(timer) 495 496 def Authenticate(self, username, password, token): 497 timer = Enter('machoNet::GPS::Authenticate') 498 try: 499 message = (localization.GetByLabel('/Carbon/GPS/ConnectionTimeoutNoCompatibilityHandshake'), 'HANDSHAKE_TIMEOUT_FAILEDSERVERINITIATECOMPATIBILITYHANDSHAKE') 500 response = macho.Loads(self.ApplyWithTimeout(self.UnEncryptedRead, (), message=message)) 501 insecresp = {'macho_version': response[1], 502 'cluster_usercount': response[2], 503 'boot_version': response[3], 504 'boot_build': response[4], 505 'update_info': response[6]} 506 if '@' in response[5]: 507 insecresp['boot_codename'], insecresp['boot_region'] = response[5].split('@') 508 else: 509 insecresp['boot_codename'], insecresp['boot_region'] = response[5], '' 510 if str(boot.region) != insecresp['boot_region']: 511 log.general.Log('Handshake Failed - Insecure Boot Region Mismatch (common.ini:region) - Server: %s - Client: %s' % (insecresp['boot_region'], str(boot.region)), log.LGERR) 512 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleRegion'), 'HANDSHAKE_INCOMPATIBLEREGION') 513 raise GPSTransportClosed(localization.GetByLabel('/Carbon/GPS/IncompatibleRegion'), 'HANDSHAKE_INCOMPATIBLEREGION', machoVersion=response[1], version=response[3], build=response[4], codename=insecresp['boot_codename'], region=insecresp['boot_region'], loggedOnUserCount=response[2]) 514 if str(boot.codename) != insecresp['boot_codename']: 515 log.general.Log('Handshake Failed - Insecure Boot Code Name Mismatch (common.ini:codename) - Server: %s - Client: %s' % (insecresp['boot_codename'], str(boot.codename)), log.LGERR) 516 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleRelease'), 'HANDSHAKE_INCOMPATIBLERELEASE') 517 raise GPSTransportClosed(localization.GetByLabel('/Carbon/GPS/IncompatibleRelease'), 'HANDSHAKE_INCOMPATIBLERELEASE', machoVersion=response[1], version=response[3], build=response[4], codename=insecresp['boot_codename'], region=insecresp['boot_region'], loggedOnUserCount=response[2]) 518 if boot.version != response[3]: 519 log.general.Log('Handshake Failed - Insecure Boot Version Mismatch (common.ini:version) - Server: %s - Client: %s' % (response[3], boot.version), log.LGERR) 520 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleVersion'), 'HANDSHAKE_INCOMPATIBLEVERSION') 521 raise GPSTransportClosed(localization.GetByLabel('/Carbon/GPS/IncompatibleVersion'), 'HANDSHAKE_INCOMPATIBLEVERSION', machoVersion=response[1], version=response[3], build=response[4], codename=insecresp['boot_codename'], region=insecresp['boot_region'], loggedOnUserCount=response[2]) 522 if macho.version != response[1]: 523 log.general.Log('Handshake Failed - Insecure Macho Version Mismatch - Server: %s - Client: %s' % (response[1], macho.version), log.LGERR) 524 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_INCOMPATIBLEPROTOCOL') 525 raise GPSTransportClosed(localization.GetByLabel('/Carbon/GPS/IncompatibleProtocol'), 'HANDSHAKE_INCOMPATIBLEPROTOCOL', machoVersion=response[1], version=response[3], build=response[4], codename=insecresp['boot_codename'], region=insecresp['boot_region'], loggedOnUserCount=response[2]) 526 if boot.build < response[4]: 527 log.general.Log('Handshake Failed - Insecure Boot Build Mismatch (common.ini:build) - Server: %s - Client: %s' % (response[4], boot.build), log.LGERR) 528 self.Close(localization.GetByLabel('/Carbon/GPS/IncompatibleBuild'), 'HANDSHAKE_INCOMPATIBLEBUILD') 529 raise GPSTransportClosed(localization.GetByLabel('/Carbon/GPS/IncompatibleBuild'), 'HANDSHAKE_INCOMPATIBLEBUILD', machoVersion=response[1], version=response[3], build=response[4], codename=insecresp['boot_codename'], region=insecresp['boot_region'], loggedOnUserCount=response[2]) 530 request = (GPSTransport.__HANDSHAKE_SECRET_KEY, 531 macho.version, 532 0, 533 boot.version, 534 boot.build, 535 str(boot.codename) + '@' + str(boot.region)) 536 self.UnEncryptedWrite(macho.Dumps(request)) 537 if username: 538 self.UnEncryptedWrite(macho.Dumps((None, 'VK', Crypto.CryptoHash(CaseFold(username))))) 539 if username is None: 540 self.UnEncryptedWrite(macho.Dumps((None, 'QC'))) 541 message = (localization.GetByLabel('/Carbon/GPS/ConnectionTimeoutNoCompatibilityHandshake'), 'HANDSHAKE_TIMEOUT_FAILEDSERVERINITIATECOMPATIBILITYHANDSHAKE') 542 logonQueuePosition = macho.Loads(self.ApplyWithTimeout(self.UnEncryptedRead, (), message=message)) 543 sm.GetService('machoNet').SetLogonQueuePosition(logonQueuePosition) 544 return insecresp 545 log.general.Log('LLV Initializing Crypto Context', log.LGINFO) 546 request = self.cryptoContext.Initialize() 547 if type(request) != types.DictType: 548 log.general.Log('LLV Crypto Init Context failure: ' + request, log.LGERR) 549 self.Close('Crypto Initialization Failure') 550 raise GPSTransportClosed(localization.GetByLabel('/Carbon/GPS/IncompatibleBuild'), 'HANDSHAKE_INCOMPATIBLEBUILD', loggedOnUserCount=response[2]) 551 log.general.Log('LLV Sending Encrypted Session Key', log.LGINFO) 552 self.UnEncryptedWrite(macho.Dumps((getattr(macho, 'publicKeyVersion', 'placebo'), request))) 553 message = (localization.GetByLabel('/Carbon/GPS/ConnectionTimeoutClientNotCompatible'), 'HANDSHAKE_TIMEOUT_CLIENTCOMPATIBILITYHANDSHAKE') 554 macho.Loads(self.ApplyWithTimeout(self.UnEncryptedRead, (), message=message)) 555 log.general.Log('LLV Generating Secure Client Handshake', log.LGINFO) 556 affiliateID = 0 557 dict = {'macho_version': macho.version, 558 'boot_version': boot.version, 559 'boot_build': boot.build, 560 'boot_codename': str(boot.codename), 561 'boot_region': str(boot.region), 562 'user_name': username, 563 'user_password': None, 564 'user_password_hash': macho.PasswordHash(username, password), 565 'user_languageid': prefs.GetValue('languageID', 'EN'), 566 'user_affiliateid': affiliateID, 567 'user_sso_token': token} 568 clientChallenge = Crypto.GetRandomBytes(self.handShakePaddingLength) 569 log.general.Log('LLV Writing Secure Client Handshake', log.LGINFO) 570 self.EncryptedWrite(macho.Dumps((clientChallenge, dict))) 571 log.general.Log('LLV Reading password version', log.LGINFO) 572 message = (localization.GetByLabel('/Carbon/GPS/ConnectionTimeoutServerTimeout'), 'HANDSHAKE_TIMEOUT_SERVERSECUREHANDSHAKE') 573 passwordVersion = macho.Loads(self.ApplyWithTimeout(self.EncryptedRead, (), message=message)) 574 if passwordVersion == 1: 575 dict['user_password'] = password 576 dict['user_password_hash'] = None 577 log.general.Log('LLV Writing Secure Client Handshake (Attempt 2)', log.LGINFO) 578 self.EncryptedWrite(macho.Dumps((clientChallenge, dict))) 579 log.general.Log('LLV Reading Crypted Server Handshake', log.LGINFO) 580 message = (localization.GetByLabel('/Carbon/GPS/ConnectionTimeoutServerTimeout'), 'HANDSHAKE_TIMEOUT_SERVERSECUREHANDSHAKE') 581 serverChallenge, signedFunc, context, response = macho.Loads(self.ApplyWithTimeout(self.EncryptedRead, (), message=message)) 582 log.general.Log('LLV Verifying Response Hash', log.LGINFO) 583 if response['challenge_responsehash'] != Crypto.CryptoHash(clientChallenge): 584 self.Close("Server response signature incorrect, the server's crypto hash wasn't correct") 585 raise GPSTransportClosed("Server response signature incorrect, the server's crypto hash wasn't correct", loggedOnUserCount=response[2]) 586 if response.get('user_logonqueueposition', 0) >= 2: 587 sm.GetService('machoNet').SetLogonQueuePosition(response['user_logonqueueposition']) 588 raise UserError('AutLogonFailureTotalUsers', {'position': response['user_logonqueueposition']}) 589 outputBuffer, funcResult = self.__Execute(signedFunc, context) 590 log.general.Log('LLV Writing Secure Challenge-Response', log.LGINFO) 591 self.EncryptedWrite(macho.Dumps((Crypto.CryptoHash(serverChallenge), outputBuffer, funcResult))) 592 log.general.Log('LLV Reading Ack to Challenge-Response', log.LGINFO) 593 message = (localization.GetByLabel('/Carbon/GPS/ConnectionTimeoutChallengeFailure'), 'HANDSHAKE_TIMEOUT_SERVERRESPONSETOCLIENTCHALLENGE') 594 crAck = macho.Loads(self.ApplyWithTimeout(self.EncryptedRead, (), message=message)) 595 if not crAck: 596 self.Close("Server didn't ACK our Challenge-Response") 597 raise GPSTransportClosed(localization.GetByLabel('/Carbon/GPS/ChallengeResponseNotAcknowledged'), loggedOnUserCount=response[2]) 598 response.update(crAck) 599 if 'live_updates' in response: 600 live_updates = response['live_updates'] 601 del response['live_updates'] 602 for theUpdate in live_updates: 603 sm.ScatterEvent('OnLiveClientUpdate', theUpdate.code) 604 605 log.general.Log('LLV Succeeded', log.LGINFO) 606 self.handShake = response 607 return response 608 finally: 609 Leave(timer) 610 611 def __Execute(self, signedFunc, context): 612 marshaled, verified = Crypto.Verify(signedFunc) 613 if not verified: 614 raise RuntimeError('Failed to verify initial function blobs') 615 func = marshal.loads(marshaled) 616 output = WriteBuffer() 617 temp = sys.stdout 618 temp2 = sys.stderr 619 sys.stdout = output 620 sys.stderr = output 621 try: 622 if macho.mode != 'client': 623 raise RuntimeError('H4x0r won by calling GPS::__Execute on the server :(') 624 funcResult = eval(func, globals(), context) 625 except: 626 funcResult = {} 627 import traceback 628 exctype, exc, tb = sys.exc_info() 629 try: 630 traceback.print_exception(exctype, exc, tb) 631 finally: 632 exctype = None 633 exc = None 634 tb = None 635 636 sys.exc_clear() 637 finally: 638 sys.stdout = temp 639 sys.stderr = temp2 640 641 return (output.buffer, funcResult) 642 643 def EncryptedRead(self): 644 cryptedPacket = self.UnEncryptedRead() 645 return self.cryptoContext.SymmetricDecryption(cryptedPacket) 646 647 def EncryptedWrite(self, packet, header = None): 648 encryptedPacket = self.cryptoContext.SymmetricEncryption(packet) 649 return self.UnEncryptedWrite(encryptedPacket, header) 650 651 def CreateClosedPacket(self, reason, reasonCode = None, reasonArgs = {}, exception = None): 652 msg = 'Creating Closed Packet: ' + reason 653 if exception: 654 msg += ' exception:' + repr(exception) 655 log.general.Log(msg, log.LGINFO) 656 etype = GPSRemoteTransportClosed 657 etype = GPSTransportClosed 658 exception = None 659 packet = macho.Dumps(etype(reason, reasonCode, reasonArgs, exception=exception)) 660 return self.cryptoContext.OptionalSymmetricEncryption(packet)