1# 2# This file is part of pysnmp software. 3# 4# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com> 5# License: http://snmplabs.com/pysnmp/license.html 6# 7import time 8import sys 9from pysnmp.proto.secmod.base import AbstractSecurityModel 10from pysnmp.proto.secmod.rfc3414.auth import hmacmd5, hmacsha, noauth 11from pysnmp.proto.secmod.rfc3414.priv import des, nopriv 12from pysnmp.proto.secmod.rfc3826.priv import aes 13from pysnmp.proto.secmod.rfc7860.auth import hmacsha2 14from pysnmp.proto.secmod.eso.priv import des3, aes192, aes256 15from pysnmp.smi.error import NoSuchInstanceError 16from pysnmp.proto import rfc1155, errind, error 17from pysnmp import debug 18from pyasn1.type import univ, namedtype, constraint 19from pyasn1.codec.ber import encoder, decoder, eoo 20from pyasn1.error import PyAsn1Error 21from pyasn1.compat.octets import null 22 23 24# USM security params 25 26class UsmSecurityParameters(rfc1155.TypeCoercionHackMixIn, univ.Sequence): 27 componentType = namedtype.NamedTypes( 28 namedtype.NamedType('msgAuthoritativeEngineId', univ.OctetString()), 29 namedtype.NamedType('msgAuthoritativeEngineBoots', 30 univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, 2147483647))), 31 namedtype.NamedType('msgAuthoritativeEngineTime', 32 univ.Integer().subtype(subtypeSpec=constraint.ValueRangeConstraint(0, 2147483647))), 33 namedtype.NamedType('msgUserName', 34 univ.OctetString().subtype(subtypeSpec=constraint.ValueSizeConstraint(0, 32))), 35 namedtype.NamedType('msgAuthenticationParameters', univ.OctetString()), 36 namedtype.NamedType('msgPrivacyParameters', univ.OctetString()) 37 ) 38 39 40class SnmpUSMSecurityModel(AbstractSecurityModel): 41 securityModelID = 3 42 authServices = {hmacmd5.HmacMd5.serviceID: hmacmd5.HmacMd5(), 43 hmacsha.HmacSha.serviceID: hmacsha.HmacSha(), 44 hmacsha2.HmacSha2.sha224ServiceID: hmacsha2.HmacSha2(hmacsha2.HmacSha2.sha224ServiceID), 45 hmacsha2.HmacSha2.sha256ServiceID: hmacsha2.HmacSha2(hmacsha2.HmacSha2.sha256ServiceID), 46 hmacsha2.HmacSha2.sha384ServiceID: hmacsha2.HmacSha2(hmacsha2.HmacSha2.sha384ServiceID), 47 hmacsha2.HmacSha2.sha512ServiceID: hmacsha2.HmacSha2(hmacsha2.HmacSha2.sha512ServiceID), 48 noauth.NoAuth.serviceID: noauth.NoAuth(), 49 } 50 privServices = {des.Des.serviceID: des.Des(), 51 des3.Des3.serviceID: des3.Des3(), 52 aes.Aes.serviceID: aes.Aes(), 53 aes192.AesBlumenthal192.serviceID: aes192.AesBlumenthal192(), 54 aes256.AesBlumenthal256.serviceID: aes256.AesBlumenthal256(), 55 aes192.Aes192.serviceID: aes192.Aes192(), # non-standard 56 aes256.Aes256.serviceID: aes256.Aes256(), # non-standard 57 nopriv.NoPriv.serviceID: nopriv.NoPriv()} 58 59 def __init__(self): 60 AbstractSecurityModel.__init__(self) 61 self.__securityParametersSpec = UsmSecurityParameters() 62 self.__timeline = {} 63 self.__timelineExpQueue = {} 64 self.__expirationTimer = 0 65 self.__paramsBranchId = -1 66 67 def __sec2usr(self, snmpEngine, securityName, securityEngineID=None): 68 mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder 69 usmUserEngineID, = mibBuilder.importSymbols('SNMP-USER-BASED-SM-MIB', 70 'usmUserEngineID') 71 if self.__paramsBranchId != usmUserEngineID.branchVersionId: 72 usmUserName, usmUserSecurityName = mibBuilder.importSymbols( 73 'SNMP-USER-BASED-SM-MIB', 'usmUserName', 'usmUserSecurityName') 74 75 self.__securityToUserMap = {} 76 77 nextMibNode = usmUserEngineID 78 79 while True: 80 try: 81 nextMibNode = usmUserEngineID.getNextNode(nextMibNode.name) 82 83 except NoSuchInstanceError: 84 self.__paramsBranchId = usmUserEngineID.branchVersionId 85 debug.logger & debug.flagSM and debug.logger( 86 '_sec2usr: built snmpEngineId + securityName to userName map, version %s: %r' % ( 87 self.__paramsBranchId, self.__securityToUserMap)) 88 break 89 90 instId = nextMibNode.name[len(usmUserSecurityName.name):] 91 92 __engineID = usmUserEngineID.getNode(usmUserEngineID.name + instId).syntax 93 __userName = usmUserName.getNode(usmUserName.name + instId).syntax 94 __securityName = usmUserSecurityName.getNode(usmUserSecurityName.name + instId).syntax 95 96 k = __engineID, __securityName 97 98 # first (lesser) securityName wins 99 if k not in self.__securityToUserMap: 100 self.__securityToUserMap[k] = __userName 101 102 if securityEngineID is None: 103 snmpEngineID, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') 104 securityEngineID = snmpEngineID.syntax 105 106 try: 107 userName = self.__securityToUserMap[(securityEngineID, securityName)] 108 except KeyError: 109 debug.logger & debug.flagSM and debug.logger( 110 '_sec2usr: no entry exists for snmpEngineId %r, securityName %r' % (securityEngineID, securityName)) 111 raise NoSuchInstanceError() # emulate MIB lookup 112 113 debug.logger & debug.flagSM and debug.logger( 114 '_sec2usr: using userName %r for snmpEngineId %r, securityName %r' % ( 115 userName, securityEngineID, securityName)) 116 117 return userName 118 119 @staticmethod 120 def __getUserInfo(mibInstrumController, securityEngineID, userName): 121 usmUserEntry, = mibInstrumController.mibBuilder.importSymbols( 122 'SNMP-USER-BASED-SM-MIB', 'usmUserEntry' 123 ) 124 tblIdx = usmUserEntry.getInstIdFromIndices(securityEngineID, userName) 125 # Get userName & securityName 126 usmUserName = usmUserEntry.getNode(usmUserEntry.name + (2,) + tblIdx).syntax 127 usmUserSecurityName = usmUserEntry.getNode(usmUserEntry.name + (3,) + tblIdx).syntax 128 # Get protocols 129 usmUserAuthProtocol = usmUserEntry.getNode(usmUserEntry.name + (5,) + tblIdx).syntax 130 usmUserPrivProtocol = usmUserEntry.getNode(usmUserEntry.name + (8,) + tblIdx).syntax 131 # Get keys 132 pysnmpUsmKeyEntry, = mibInstrumController.mibBuilder.importSymbols( 133 'PYSNMP-USM-MIB', 'pysnmpUsmKeyEntry' 134 ) 135 pysnmpUsmKeyAuthLocalized = pysnmpUsmKeyEntry.getNode(pysnmpUsmKeyEntry.name + (1,) + tblIdx).syntax 136 pysnmpUsmKeyPrivLocalized = pysnmpUsmKeyEntry.getNode(pysnmpUsmKeyEntry.name + (2,) + tblIdx).syntax 137 return (usmUserName, usmUserSecurityName, usmUserAuthProtocol, 138 pysnmpUsmKeyAuthLocalized, usmUserPrivProtocol, 139 pysnmpUsmKeyPrivLocalized) 140 141 def __cloneUserInfo(self, mibInstrumController, securityEngineID, 142 userName): 143 snmpEngineID, = mibInstrumController.mibBuilder.importSymbols( 144 '__SNMP-FRAMEWORK-MIB', 'snmpEngineID' 145 ) 146 # Proto entry 147 usmUserEntry, = mibInstrumController.mibBuilder.importSymbols( 148 'SNMP-USER-BASED-SM-MIB', 'usmUserEntry' 149 ) 150 tblIdx1 = usmUserEntry.getInstIdFromIndices( 151 snmpEngineID.syntax, userName 152 ) 153 # Get proto protocols 154 usmUserName = usmUserEntry.getNode(usmUserEntry.name + (2,) + tblIdx1) 155 usmUserSecurityName = usmUserEntry.getNode(usmUserEntry.name + (3,) + tblIdx1) 156 usmUserCloneFrom = usmUserEntry.getNode(usmUserEntry.name + (4,) + tblIdx1) 157 usmUserAuthProtocol = usmUserEntry.getNode(usmUserEntry.name + (5,) + tblIdx1) 158 usmUserPrivProtocol = usmUserEntry.getNode(usmUserEntry.name + (8,) + tblIdx1) 159 # Get proto keys 160 pysnmpUsmKeyEntry, = mibInstrumController.mibBuilder.importSymbols( 161 'PYSNMP-USM-MIB', 'pysnmpUsmKeyEntry' 162 ) 163 pysnmpUsmKeyAuth = pysnmpUsmKeyEntry.getNode(pysnmpUsmKeyEntry.name + (3,) + tblIdx1) 164 pysnmpUsmKeyPriv = pysnmpUsmKeyEntry.getNode(pysnmpUsmKeyEntry.name + (4,) + tblIdx1) 165 166 # Create new row from proto values 167 168 tblIdx2 = usmUserEntry.getInstIdFromIndices(securityEngineID, userName) 169 170 # New row 171 mibInstrumController.writeVars( 172 ((usmUserEntry.name + (13,) + tblIdx2, 4),) 173 ) 174 175 # Set user&securityNames 176 usmUserEntry.getNode(usmUserEntry.name + (2,) + tblIdx2).syntax = usmUserName.syntax 177 usmUserEntry.getNode(usmUserEntry.name + (3,) + tblIdx2).syntax = usmUserSecurityName.syntax 178 179 # Store a reference to original row 180 usmUserEntry.getNode(usmUserEntry.name + (4,) + tblIdx2).syntax = usmUserCloneFrom.syntax.clone(tblIdx1) 181 182 # Set protocols 183 usmUserEntry.getNode(usmUserEntry.name + (5,) + tblIdx2).syntax = usmUserAuthProtocol.syntax 184 usmUserEntry.getNode(usmUserEntry.name + (8,) + tblIdx2).syntax = usmUserPrivProtocol.syntax 185 186 # Localize and set keys 187 pysnmpUsmKeyEntry, = mibInstrumController.mibBuilder.importSymbols( 188 'PYSNMP-USM-MIB', 'pysnmpUsmKeyEntry' 189 ) 190 pysnmpUsmKeyAuthLocalized = pysnmpUsmKeyEntry.getNode( 191 pysnmpUsmKeyEntry.name + (1,) + tblIdx2 192 ) 193 if usmUserAuthProtocol.syntax in self.authServices: 194 localizeKey = self.authServices[usmUserAuthProtocol.syntax].localizeKey 195 localAuthKey = localizeKey(pysnmpUsmKeyAuth.syntax, 196 securityEngineID) 197 else: 198 raise error.StatusInformation( 199 errorIndication=errind.unsupportedAuthProtocol 200 ) 201 if localAuthKey is not None: 202 pysnmpUsmKeyAuthLocalized.syntax = pysnmpUsmKeyAuthLocalized.syntax.clone(localAuthKey) 203 pysnmpUsmKeyPrivLocalized = pysnmpUsmKeyEntry.getNode( 204 pysnmpUsmKeyEntry.name + (2,) + tblIdx2 205 ) 206 if usmUserPrivProtocol.syntax in self.privServices: 207 localizeKey = self.privServices[usmUserPrivProtocol.syntax].localizeKey 208 localPrivKey = localizeKey(usmUserAuthProtocol.syntax, 209 pysnmpUsmKeyPriv.syntax, 210 securityEngineID) 211 else: 212 raise error.StatusInformation(errorIndication=errind.unsupportedPrivProtocol) 213 if localPrivKey is not None: 214 pysnmpUsmKeyPrivLocalized.syntax = pysnmpUsmKeyPrivLocalized.syntax.clone(localPrivKey) 215 return (usmUserName.syntax, usmUserSecurityName.syntax, 216 usmUserAuthProtocol.syntax, pysnmpUsmKeyAuthLocalized.syntax, 217 usmUserPrivProtocol.syntax, pysnmpUsmKeyPrivLocalized.syntax) 218 219 def __generateRequestOrResponseMsg(self, snmpEngine, 220 messageProcessingModel, 221 globalData, maxMessageSize, 222 securityModel, securityEngineID, 223 securityName, securityLevel, 224 scopedPDU, securityStateReference): 225 mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder 226 snmpEngineID = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID')[0].syntax 227 228 # 3.1.1 229 if securityStateReference is not None: 230 # 3.1.1a 231 cachedSecurityData = self._cache.pop(securityStateReference) 232 usmUserName = cachedSecurityData['msgUserName'] 233 if 'usmUserSecurityName' in cachedSecurityData: 234 usmUserSecurityName = cachedSecurityData['usmUserSecurityName'] 235 else: 236 usmUserSecurityName = usmUserName 237 if 'usmUserAuthProtocol' in cachedSecurityData: 238 usmUserAuthProtocol = cachedSecurityData['usmUserAuthProtocol'] 239 else: 240 usmUserAuthProtocol = noauth.NoAuth.serviceID 241 if 'usmUserAuthKeyLocalized' in cachedSecurityData: 242 usmUserAuthKeyLocalized = cachedSecurityData['usmUserAuthKeyLocalized'] 243 else: 244 usmUserAuthKeyLocalized = None 245 if 'usmUserPrivProtocol' in cachedSecurityData: 246 usmUserPrivProtocol = cachedSecurityData['usmUserPrivProtocol'] 247 else: 248 usmUserPrivProtocol = nopriv.NoPriv.serviceID 249 if 'usmUserPrivKeyLocalized' in cachedSecurityData: 250 usmUserPrivKeyLocalized = cachedSecurityData['usmUserPrivKeyLocalized'] 251 else: 252 usmUserPrivKeyLocalized = None 253 securityEngineID = snmpEngineID 254 debug.logger & debug.flagSM and debug.logger('__generateRequestOrResponseMsg: user info read from cache') 255 elif securityName: 256 # 3.1.1b 257 try: 258 (usmUserName, usmUserSecurityName, usmUserAuthProtocol, 259 usmUserAuthKeyLocalized, usmUserPrivProtocol, 260 usmUserPrivKeyLocalized) = self.__getUserInfo( 261 snmpEngine.msgAndPduDsp.mibInstrumController, 262 securityEngineID, 263 self.__sec2usr(snmpEngine, securityName, securityEngineID) 264 ) 265 debug.logger & debug.flagSM and debug.logger('__generateRequestOrResponseMsg: read user info') 266 267 except NoSuchInstanceError: 268 pysnmpUsmDiscovery, = mibBuilder.importSymbols('__PYSNMP-USM-MIB', 'pysnmpUsmDiscovery') 269 reportUnknownName = not pysnmpUsmDiscovery.syntax 270 if not reportUnknownName: 271 try: 272 (usmUserName, usmUserSecurityName, 273 usmUserAuthProtocol, usmUserAuthKeyLocalized, 274 usmUserPrivProtocol, 275 usmUserPrivKeyLocalized) = self.__cloneUserInfo( 276 snmpEngine.msgAndPduDsp.mibInstrumController, 277 securityEngineID, 278 self.__sec2usr(snmpEngine, securityName) 279 ) 280 281 except NoSuchInstanceError: 282 reportUnknownName = True 283 284 if reportUnknownName: 285 raise error.StatusInformation( 286 errorIndication=errind.unknownSecurityName 287 ) 288 289 debug.logger & debug.flagSM and debug.logger('__generateRequestOrResponseMsg: clone user info') 290 291 except PyAsn1Error: 292 debug.logger & debug.flagSM and debug.logger( 293 '__generateRequestOrResponseMsg: %s' % (sys.exc_info()[1],)) 294 snmpInGenErrs, = mibBuilder.importSymbols('__SNMPv2-MIB', 'snmpInGenErrs') 295 snmpInGenErrs.syntax += 1 296 raise error.StatusInformation( 297 errorIndication=errind.invalidMsg 298 ) 299 else: 300 # empty username used for engineID discovery 301 usmUserName = usmUserSecurityName = null 302 usmUserAuthProtocol = noauth.NoAuth.serviceID 303 usmUserPrivProtocol = nopriv.NoPriv.serviceID 304 usmUserAuthKeyLocalized = usmUserPrivKeyLocalized = None 305 debug.logger & debug.flagSM and debug.logger('__generateRequestOrResponseMsg: use empty USM data') 306 307 # noinspection PyUnboundLocalVariable 308 debug.logger & debug.flagSM and debug.logger( 309 '__generateRequestOrResponseMsg: local usmUserName %r usmUserSecurityName %r usmUserAuthProtocol %s usmUserPrivProtocol %s securityEngineID %r securityName %r' % ( 310 usmUserName, usmUserSecurityName, usmUserAuthProtocol, usmUserPrivProtocol, securityEngineID, securityName)) 311 312 msg = globalData 313 314 # 3.1.2 315 if securityLevel == 3: 316 if (usmUserAuthProtocol == noauth.NoAuth.serviceID or 317 usmUserPrivProtocol == nopriv.NoPriv.serviceID): 318 raise error.StatusInformation( 319 errorIndication=errind.unsupportedSecurityLevel 320 ) 321 322 # 3.1.3 323 if securityLevel == 3 or securityLevel == 2: 324 if usmUserAuthProtocol == noauth.NoAuth.serviceID: 325 raise error.StatusInformation( 326 errorIndication=errind.unsupportedSecurityLevel 327 ) 328 329 securityParameters = self.__securityParametersSpec 330 331 scopedPDUData = msg.setComponentByPosition(3).getComponentByPosition(3) 332 scopedPDUData.setComponentByPosition( 333 0, scopedPDU, verifyConstraints=False, matchTags=False, matchConstraints=False 334 ) 335 336 # 3.1.6a 337 if securityStateReference is None and securityLevel in (2, 3): 338 if securityEngineID in self.__timeline: 339 (snmpEngineBoots, snmpEngineTime, latestReceivedEngineTime, 340 latestUpdateTimestamp) = self.__timeline[securityEngineID] 341 debug.logger & debug.flagSM and debug.logger( 342 '__generateRequestOrResponseMsg: read snmpEngineBoots, snmpEngineTime from timeline') 343 else: 344 # 2.3 XXX is this correct? 345 snmpEngineBoots = snmpEngineTime = 0 346 debug.logger & debug.flagSM and debug.logger( 347 '__generateRequestOrResponseMsg: no timeline for securityEngineID %r' % (securityEngineID,)) 348 # 3.1.6.b 349 elif securityStateReference is not None: # XXX Report? 350 (snmpEngineBoots, 351 snmpEngineTime) = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineBoots', 'snmpEngineTime') 352 snmpEngineBoots = snmpEngineBoots.syntax 353 snmpEngineTime = snmpEngineTime.syntax.clone() 354 debug.logger & debug.flagSM and debug.logger( 355 '__generateRequestOrResponseMsg: read snmpEngineBoots, snmpEngineTime from LCD') 356 # 3.1.6.c 357 else: 358 snmpEngineBoots = snmpEngineTime = 0 359 debug.logger & debug.flagSM and debug.logger( 360 '__generateRequestOrResponseMsg: assuming zero snmpEngineBoots, snmpEngineTime') 361 362 debug.logger & debug.flagSM and debug.logger( 363 '__generateRequestOrResponseMsg: use snmpEngineBoots %s snmpEngineTime %s for securityEngineID %r' % ( 364 snmpEngineBoots, snmpEngineTime, securityEngineID)) 365 366 # 3.1.4a 367 if securityLevel == 3: 368 if usmUserPrivProtocol in self.privServices: 369 privHandler = self.privServices[usmUserPrivProtocol] 370 else: 371 raise error.StatusInformation( 372 errorIndication=errind.encryptionError 373 ) 374 375 debug.logger & debug.flagSM and debug.logger( 376 '__generateRequestOrResponseMsg: scopedPDU %s' % scopedPDU.prettyPrint()) 377 378 try: 379 dataToEncrypt = encoder.encode(scopedPDU) 380 381 except PyAsn1Error: 382 debug.logger & debug.flagSM and debug.logger( 383 '__generateRequestOrResponseMsg: scopedPDU serialization error: %s' % sys.exc_info()[1]) 384 raise error.StatusInformation( 385 errorIndication=errind.serializationError 386 ) 387 388 debug.logger & debug.flagSM and debug.logger( 389 '__generateRequestOrResponseMsg: scopedPDU encoded into %s' % debug.hexdump(dataToEncrypt)) 390 391 # noinspection PyUnboundLocalVariable 392 (encryptedData, 393 privParameters) = privHandler.encryptData( 394 usmUserPrivKeyLocalized, 395 (snmpEngineBoots, snmpEngineTime, None), dataToEncrypt 396 ) 397 398 securityParameters.setComponentByPosition( 399 5, privParameters, verifyConstraints=False, matchTags=False, matchConstraints=False 400 ) 401 scopedPDUData.setComponentByPosition( 402 1, encryptedData, verifyConstraints=False, matchTags=False, matchConstraints=False 403 ) 404 405 debug.logger & debug.flagSM and debug.logger( 406 '__generateRequestOrResponseMsg: scopedPDU ciphered into %s' % debug.hexdump(encryptedData)) 407 408 # 3.1.4b 409 elif securityLevel == 1 or securityLevel == 2: 410 securityParameters.setComponentByPosition(5, '') 411 412 debug.logger & debug.flagSM and debug.logger('__generateRequestOrResponseMsg: %s' % scopedPDUData.prettyPrint()) 413 414 # 3.1.5 415 securityParameters.setComponentByPosition( 416 0, securityEngineID, verifyConstraints=False, matchTags=False, matchConstraints=False 417 ) 418 securityParameters.setComponentByPosition( 419 1, snmpEngineBoots, verifyConstraints=False, matchTags=False, matchConstraints=False 420 ) 421 securityParameters.setComponentByPosition( 422 2, snmpEngineTime, verifyConstraints=False, matchTags=False, matchConstraints=False 423 ) 424 425 # 3.1.7 426 securityParameters.setComponentByPosition( 427 3, usmUserName, verifyConstraints=False, matchTags=False, matchConstraints=False 428 ) 429 430 # 3.1.8a 431 if securityLevel == 3 or securityLevel == 2: 432 if usmUserAuthProtocol in self.authServices: 433 authHandler = self.authServices[usmUserAuthProtocol] 434 else: 435 raise error.StatusInformation( 436 errorIndication=errind.authenticationFailure 437 ) 438 439 # extra-wild hack to facilitate BER substrate in-place re-write 440 securityParameters.setComponentByPosition( 441 4, '\x00' * authHandler.digestLength 442 ) 443 444 debug.logger & debug.flagSM and debug.logger( 445 '__generateRequestOrResponseMsg: %s' % (securityParameters.prettyPrint(),)) 446 447 try: 448 msg.setComponentByPosition(2, encoder.encode(securityParameters), verifyConstraints=False) 449 450 except PyAsn1Error: 451 debug.logger & debug.flagSM and debug.logger( 452 '__generateRequestOrResponseMsg: securityParameters serialization error: %s' % sys.exc_info()[1]) 453 raise error.StatusInformation( 454 errorIndication=errind.serializationError 455 ) 456 457 debug.logger & debug.flagSM and debug.logger( 458 '__generateRequestOrResponseMsg: auth outgoing msg: %s' % msg.prettyPrint()) 459 460 try: 461 wholeMsg = encoder.encode(msg) 462 463 except PyAsn1Error: 464 debug.logger & debug.flagSM and debug.logger( 465 '__generateRequestOrResponseMsg: msg serialization error: %s' % sys.exc_info()[1]) 466 raise error.StatusInformation( 467 errorIndication=errind.serializationError 468 ) 469 470 # noinspection PyUnboundLocalVariable 471 authenticatedWholeMsg = authHandler.authenticateOutgoingMsg( 472 usmUserAuthKeyLocalized, wholeMsg 473 ) 474 475 # 3.1.8b 476 else: 477 securityParameters.setComponentByPosition( 478 4, '', verifyConstraints=False, matchTags=False, matchConstraints=False 479 ) 480 481 debug.logger & debug.flagSM and debug.logger( 482 '__generateRequestOrResponseMsg: %s' % (securityParameters.prettyPrint(),)) 483 484 try: 485 msg.setComponentByPosition(2, encoder.encode(securityParameters), verifyConstraints=False, matchTags=False, matchConstraints=False) 486 487 except PyAsn1Error: 488 debug.logger & debug.flagSM and debug.logger( 489 '__generateRequestOrResponseMsg: secutiryParameters serialization error: %s' % sys.exc_info()[1]) 490 raise error.StatusInformation( 491 errorIndication=errind.serializationError 492 ) 493 494 try: 495 debug.logger & debug.flagSM and debug.logger( 496 '__generateRequestOrResponseMsg: plain outgoing msg: %s' % msg.prettyPrint()) 497 authenticatedWholeMsg = encoder.encode(msg) 498 499 except PyAsn1Error: 500 debug.logger & debug.flagSM and debug.logger( 501 '__generateRequestOrResponseMsg: msg serialization error: %s' % sys.exc_info()[1]) 502 raise error.StatusInformation( 503 errorIndication=errind.serializationError 504 ) 505 506 debug.logger & debug.flagSM and debug.logger('__generateRequestOrResponseMsg: %s outgoing msg: %s' % ( 507 securityLevel > 1 and "authenticated" or "plain", debug.hexdump(authenticatedWholeMsg))) 508 509 # 3.1.9 510 return msg.getComponentByPosition(2), authenticatedWholeMsg 511 512 def generateRequestMsg(self, snmpEngine, messageProcessingModel, 513 globalData, maxMessageSize, securityModel, 514 securityEngineID, securityName, securityLevel, 515 scopedPDU): 516 return self.__generateRequestOrResponseMsg(snmpEngine, 517 messageProcessingModel, 518 globalData, 519 maxMessageSize, 520 securityModel, 521 securityEngineID, 522 securityName, 523 securityLevel, 524 scopedPDU, 525 None) 526 527 def generateResponseMsg(self, snmpEngine, messageProcessingModel, 528 globalData, maxMessageSize, securityModel, 529 securityEngineID, securityName, securityLevel, 530 scopedPDU, securityStateReference): 531 return self.__generateRequestOrResponseMsg( 532 snmpEngine, messageProcessingModel, globalData, 533 maxMessageSize, securityModel, securityEngineID, 534 securityName, securityLevel, scopedPDU, securityStateReference 535 ) 536 537 # 3.2 538 def processIncomingMsg(self, snmpEngine, messageProcessingModel, 539 maxMessageSize, securityParameters, 540 securityModel, securityLevel, wholeMsg, msg): 541 mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder 542 543 # 3.2.9 -- moved up here to be able to report 544 # maxSizeResponseScopedPDU on error 545 # (48 - maximum SNMPv3 header length) 546 maxSizeResponseScopedPDU = int(maxMessageSize) - len(securityParameters) - 48 547 548 debug.logger & debug.flagSM and debug.logger( 549 'processIncomingMsg: securityParameters %s' % debug.hexdump(securityParameters)) 550 551 # 3.2.1 552 securityParameters, rest = decoder.decode( 553 securityParameters, asn1Spec=self.__securityParametersSpec 554 ) 555 556 debug.logger & debug.flagSM and debug.logger('processIncomingMsg: %s' % (securityParameters.prettyPrint(),)) 557 558 if eoo.endOfOctets.isSameTypeWith(securityParameters): 559 raise error.StatusInformation(errorIndication=errind.parseError) 560 561 # 3.2.2 562 msgAuthoritativeEngineId = securityParameters.getComponentByPosition(0) 563 securityStateReference = self._cache.push( 564 msgUserName=securityParameters.getComponentByPosition(3) 565 ) 566 567 debug.logger & debug.flagSM and debug.logger( 568 'processIncomingMsg: cache write securityStateReference %s by msgUserName %s' % ( 569 securityStateReference, securityParameters.getComponentByPosition(3))) 570 571 scopedPduData = msg.getComponentByPosition(3) 572 573 # Used for error reporting 574 contextEngineId = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID')[0].syntax 575 contextName = null 576 577 snmpEngineID = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID')[0].syntax 578 579 # 3.2.3 580 if (msgAuthoritativeEngineId != snmpEngineID and 581 msgAuthoritativeEngineId not in self.__timeline): 582 if (msgAuthoritativeEngineId and 583 4 < len(msgAuthoritativeEngineId) < 33): 584 # 3.2.3a - cloned user when request was sent 585 debug.logger & debug.flagSM and debug.logger( 586 'processIncomingMsg: non-synchronized securityEngineID %r' % (msgAuthoritativeEngineId,)) 587 else: 588 # 3.2.3b 589 debug.logger & debug.flagSM and debug.logger( 590 'processIncomingMsg: peer requested snmpEngineID discovery') 591 usmStatsUnknownEngineIDs, = mibBuilder.importSymbols( 592 '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnknownEngineIDs') 593 usmStatsUnknownEngineIDs.syntax += 1 594 debug.logger & debug.flagSM and debug.logger( 595 'processIncomingMsg: null or malformed msgAuthoritativeEngineId') 596 pysnmpUsmDiscoverable, = mibBuilder.importSymbols( 597 '__PYSNMP-USM-MIB', 'pysnmpUsmDiscoverable') 598 if pysnmpUsmDiscoverable.syntax: 599 debug.logger & debug.flagSM and debug.logger( 600 'processIncomingMsg: starting snmpEngineID discovery procedure') 601 602 # Report original contextName 603 if scopedPduData.getName() != 'plaintext': 604 debug.logger & debug.flagSM and debug.logger( 605 'processIncomingMsg: scopedPduData not plaintext %s' % scopedPduData.prettyPrint()) 606 raise error.StatusInformation( 607 errorIndication=errind.unknownEngineID 608 ) 609 610 # 7.2.6.a.1 611 scopedPdu = scopedPduData.getComponent() 612 contextEngineId = scopedPdu.getComponentByPosition(0) 613 contextName = scopedPdu.getComponentByPosition(1) 614 615 raise error.StatusInformation( 616 errorIndication=errind.unknownEngineID, 617 oid=usmStatsUnknownEngineIDs.name, 618 val=usmStatsUnknownEngineIDs.syntax, 619 securityStateReference=securityStateReference, 620 securityLevel=securityLevel, 621 contextEngineId=contextEngineId, 622 contextName=contextName, 623 scopedPDU=scopedPdu, 624 maxSizeResponseScopedPDU=maxSizeResponseScopedPDU 625 ) 626 else: 627 debug.logger & debug.flagSM and debug.logger('processIncomingMsg: will not discover EngineID') 628 # free securityStateReference XXX 629 raise error.StatusInformation( 630 errorIndication=errind.unknownEngineID 631 ) 632 633 msgUserName = securityParameters.getComponentByPosition(3) 634 635 debug.logger & debug.flagSM and debug.logger( 636 'processIncomingMsg: read from securityParams msgAuthoritativeEngineId %r msgUserName %r' % ( 637 msgAuthoritativeEngineId, msgUserName)) 638 639 if msgUserName: 640 # 3.2.4 641 try: 642 (usmUserName, 643 usmUserSecurityName, 644 usmUserAuthProtocol, 645 usmUserAuthKeyLocalized, 646 usmUserPrivProtocol, 647 usmUserPrivKeyLocalized) = self.__getUserInfo( 648 snmpEngine.msgAndPduDsp.mibInstrumController, 649 msgAuthoritativeEngineId, msgUserName 650 ) 651 debug.logger & debug.flagSM and debug.logger('processIncomingMsg: read user info from LCD') 652 653 except NoSuchInstanceError: 654 debug.logger & debug.flagSM and debug.logger( 655 'processIncomingMsg: unknown securityEngineID %r msgUserName %r' % ( 656 msgAuthoritativeEngineId, msgUserName)) 657 658 usmStatsUnknownUserNames, = mibBuilder.importSymbols( 659 '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnknownUserNames') 660 usmStatsUnknownUserNames.syntax += 1 661 662 raise error.StatusInformation( 663 errorIndication=errind.unknownSecurityName, 664 oid=usmStatsUnknownUserNames.name, 665 val=usmStatsUnknownUserNames.syntax, 666 securityStateReference=securityStateReference, 667 securityLevel=securityLevel, 668 contextEngineId=contextEngineId, 669 contextName=contextName, 670 msgUserName=msgUserName, 671 maxSizeResponseScopedPDU=maxSizeResponseScopedPDU 672 ) 673 674 except PyAsn1Error: 675 debug.logger & debug.flagSM and debug.logger('processIncomingMsg: %s' % (sys.exc_info()[1],)) 676 snmpInGenErrs, = mibBuilder.importSymbols('__SNMPv2-MIB', 'snmpInGenErrs') 677 snmpInGenErrs.syntax += 1 678 raise error.StatusInformation(errorIndication=errind.invalidMsg) 679 else: 680 # empty username used for engineID discovery 681 usmUserName = usmUserSecurityName = null 682 usmUserAuthProtocol = noauth.NoAuth.serviceID 683 usmUserPrivProtocol = nopriv.NoPriv.serviceID 684 usmUserAuthKeyLocalized = usmUserPrivKeyLocalized = None 685 686 debug.logger & debug.flagSM and debug.logger( 687 'processIncomingMsg: now have usmUserName %r usmUserSecurityName %r usmUserAuthProtocol %r usmUserPrivProtocol %r for msgUserName %r' % ( 688 usmUserName, usmUserSecurityName, usmUserAuthProtocol, usmUserPrivProtocol, msgUserName)) 689 690 # 3.2.11 (moved up here to let Reports be authenticated & encrypted) 691 self._cache.pop(securityStateReference) 692 securityStateReference = self._cache.push( 693 msgUserName=securityParameters.getComponentByPosition(3), 694 usmUserSecurityName=usmUserSecurityName, 695 usmUserAuthProtocol=usmUserAuthProtocol, 696 usmUserAuthKeyLocalized=usmUserAuthKeyLocalized, 697 usmUserPrivProtocol=usmUserPrivProtocol, 698 usmUserPrivKeyLocalized=usmUserPrivKeyLocalized 699 ) 700 701 msgAuthoritativeEngineBoots = securityParameters.getComponentByPosition(1) 702 msgAuthoritativeEngineTime = securityParameters.getComponentByPosition(2) 703 704 snmpEngine.observer.storeExecutionContext( 705 snmpEngine, 'rfc3414.processIncomingMsg', 706 dict(securityEngineId=msgAuthoritativeEngineId, 707 snmpEngineBoots=msgAuthoritativeEngineBoots, 708 snmpEngineTime=msgAuthoritativeEngineTime, 709 userName=usmUserName, 710 securityName=usmUserSecurityName, 711 authProtocol=usmUserAuthProtocol, 712 authKey=usmUserAuthKeyLocalized, 713 privProtocol=usmUserPrivProtocol, 714 privKey=usmUserPrivKeyLocalized) 715 ) 716 snmpEngine.observer.clearExecutionContext( 717 snmpEngine, 'rfc3414.processIncomingMsg' 718 ) 719 720 # 3.2.5 721 if msgAuthoritativeEngineId == snmpEngineID: 722 # Authoritative SNMP engine: make sure securityLevel is sufficient 723 badSecIndication = None 724 if securityLevel == 3: 725 if usmUserAuthProtocol == noauth.NoAuth.serviceID: 726 badSecIndication = 'authPriv wanted while auth not expected' 727 if usmUserPrivProtocol == nopriv.NoPriv.serviceID: 728 badSecIndication = 'authPriv wanted while priv not expected' 729 elif securityLevel == 2: 730 if usmUserAuthProtocol == noauth.NoAuth.serviceID: 731 badSecIndication = 'authNoPriv wanted while auth not expected' 732 if usmUserPrivProtocol != nopriv.NoPriv.serviceID: 733 # 4 (discovery phase always uses authenticated messages) 734 if msgAuthoritativeEngineBoots or msgAuthoritativeEngineTime: 735 badSecIndication = 'authNoPriv wanted while priv expected' 736 737 elif securityLevel == 1: 738 if usmUserAuthProtocol != noauth.NoAuth.serviceID: 739 badSecIndication = 'noAuthNoPriv wanted while auth expected' 740 if usmUserPrivProtocol != nopriv.NoPriv.serviceID: 741 badSecIndication = 'noAuthNoPriv wanted while priv expected' 742 if badSecIndication: 743 usmStatsUnsupportedSecLevels, = mibBuilder.importSymbols( 744 '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnsupportedSecLevels') 745 usmStatsUnsupportedSecLevels.syntax += 1 746 debug.logger & debug.flagSM and debug.logger( 747 'processIncomingMsg: reporting inappropriate security level for user %s: %s' % ( 748 msgUserName, badSecIndication)) 749 raise error.StatusInformation( 750 errorIndication=errind.unsupportedSecurityLevel, 751 oid=usmStatsUnsupportedSecLevels.name, 752 val=usmStatsUnsupportedSecLevels.syntax, 753 securityStateReference=securityStateReference, 754 securityLevel=securityLevel, 755 contextEngineId=contextEngineId, 756 contextName=contextName, 757 msgUserName=msgUserName, 758 maxSizeResponseScopedPDU=maxSizeResponseScopedPDU 759 ) 760 761 # 3.2.6 762 if securityLevel == 3 or securityLevel == 2: 763 if usmUserAuthProtocol in self.authServices: 764 authHandler = self.authServices[usmUserAuthProtocol] 765 else: 766 raise error.StatusInformation( 767 errorIndication=errind.authenticationFailure 768 ) 769 770 try: 771 authHandler.authenticateIncomingMsg( 772 usmUserAuthKeyLocalized, 773 securityParameters.getComponentByPosition(4), 774 wholeMsg 775 ) 776 777 except error.StatusInformation: 778 usmStatsWrongDigests, = mibBuilder.importSymbols( 779 '__SNMP-USER-BASED-SM-MIB', 'usmStatsWrongDigests') 780 usmStatsWrongDigests.syntax += 1 781 raise error.StatusInformation( 782 errorIndication=errind.authenticationFailure, 783 oid=usmStatsWrongDigests.name, 784 val=usmStatsWrongDigests.syntax, 785 securityStateReference=securityStateReference, 786 securityLevel=securityLevel, 787 contextEngineId=contextEngineId, 788 contextName=contextName, 789 msgUserName=msgUserName, 790 maxSizeResponseScopedPDU=maxSizeResponseScopedPDU 791 ) 792 793 debug.logger & debug.flagSM and debug.logger('processIncomingMsg: incoming msg authenticated') 794 795 # synchronize time with authed peer 796 self.__timeline[msgAuthoritativeEngineId] = ( 797 securityParameters.getComponentByPosition(1), 798 securityParameters.getComponentByPosition(2), 799 securityParameters.getComponentByPosition(2), 800 int(time.time()) 801 ) 802 803 timerResolution = snmpEngine.transportDispatcher is None and 1.0 or snmpEngine.transportDispatcher.getTimerResolution() 804 expireAt = int(self.__expirationTimer + 300 / timerResolution) 805 if expireAt not in self.__timelineExpQueue: 806 self.__timelineExpQueue[expireAt] = [] 807 self.__timelineExpQueue[expireAt].append(msgAuthoritativeEngineId) 808 809 debug.logger & debug.flagSM and debug.logger( 810 'processIncomingMsg: store timeline for securityEngineID %r' % (msgAuthoritativeEngineId,)) 811 812 # 3.2.7 813 if securityLevel == 3 or securityLevel == 2: 814 if msgAuthoritativeEngineId == snmpEngineID: 815 # Authoritative SNMP engine: use local notion (SF bug #1649032) 816 (snmpEngineBoots, 817 snmpEngineTime) = mibBuilder.importSymbols( 818 '__SNMP-FRAMEWORK-MIB', 'snmpEngineBoots', 'snmpEngineTime') 819 snmpEngineBoots = snmpEngineBoots.syntax 820 snmpEngineTime = snmpEngineTime.syntax.clone() 821 idleTime = 0 822 debug.logger & debug.flagSM and debug.logger( 823 'processIncomingMsg: read snmpEngineBoots (%s), snmpEngineTime (%s) from LCD' % ( 824 snmpEngineBoots, snmpEngineTime)) 825 else: 826 # Non-authoritative SNMP engine: use cached estimates 827 if msgAuthoritativeEngineId in self.__timeline: 828 (snmpEngineBoots, snmpEngineTime, 829 latestReceivedEngineTime, 830 latestUpdateTimestamp) = self.__timeline[ 831 msgAuthoritativeEngineId 832 ] 833 # time passed since last talk with this SNMP engine 834 idleTime = int(time.time()) - latestUpdateTimestamp 835 debug.logger & debug.flagSM and debug.logger( 836 'processIncomingMsg: read timeline snmpEngineBoots %s snmpEngineTime %s for msgAuthoritativeEngineId %r, idle time %s secs' % ( 837 snmpEngineBoots, snmpEngineTime, msgAuthoritativeEngineId, idleTime)) 838 else: 839 raise error.ProtocolError('Peer SNMP engine info missing') 840 841 # 3.2.7a 842 if msgAuthoritativeEngineId == snmpEngineID: 843 if (snmpEngineBoots == 2147483647 or 844 snmpEngineBoots != msgAuthoritativeEngineBoots or 845 abs(idleTime + int(snmpEngineTime) - int(msgAuthoritativeEngineTime)) > 150): 846 usmStatsNotInTimeWindows, = mibBuilder.importSymbols( 847 '__SNMP-USER-BASED-SM-MIB', 'usmStatsNotInTimeWindows') 848 usmStatsNotInTimeWindows.syntax += 1 849 raise error.StatusInformation( 850 errorIndication=errind.notInTimeWindow, 851 oid=usmStatsNotInTimeWindows.name, 852 val=usmStatsNotInTimeWindows.syntax, 853 securityStateReference=securityStateReference, 854 securityLevel=2, 855 contextEngineId=contextEngineId, 856 contextName=contextName, 857 msgUserName=msgUserName, 858 maxSizeResponseScopedPDU=maxSizeResponseScopedPDU 859 ) 860 # 3.2.7b 861 else: 862 # 3.2.7b.1 863 # noinspection PyUnboundLocalVariable 864 if (msgAuthoritativeEngineBoots > snmpEngineBoots or 865 msgAuthoritativeEngineBoots == snmpEngineBoots and 866 msgAuthoritativeEngineTime > latestReceivedEngineTime): 867 self.__timeline[msgAuthoritativeEngineId] = ( 868 msgAuthoritativeEngineBoots, 869 msgAuthoritativeEngineTime, 870 msgAuthoritativeEngineTime, 871 int(time.time()) 872 ) 873 874 timerResolution = snmpEngine.transportDispatcher is None and 1.0 or snmpEngine.transportDispatcher.getTimerResolution() 875 expireAt = int(self.__expirationTimer + 300 / timerResolution) 876 if expireAt not in self.__timelineExpQueue: 877 self.__timelineExpQueue[expireAt] = [] 878 self.__timelineExpQueue[expireAt].append(msgAuthoritativeEngineId) 879 880 debug.logger & debug.flagSM and debug.logger( 881 'processIncomingMsg: stored timeline msgAuthoritativeEngineBoots %s msgAuthoritativeEngineTime %s for msgAuthoritativeEngineId %r' % ( 882 msgAuthoritativeEngineBoots, msgAuthoritativeEngineTime, msgAuthoritativeEngineId)) 883 884 # 3.2.7b.2 885 if (snmpEngineBoots == 2147483647 or 886 msgAuthoritativeEngineBoots < snmpEngineBoots or 887 msgAuthoritativeEngineBoots == snmpEngineBoots and 888 abs(idleTime + int(snmpEngineTime) - int(msgAuthoritativeEngineTime)) > 150): 889 raise error.StatusInformation( 890 errorIndication=errind.notInTimeWindow, 891 msgUserName=msgUserName 892 ) 893 894 # 3.2.8a 895 if securityLevel == 3: 896 if usmUserPrivProtocol in self.privServices: 897 privHandler = self.privServices[usmUserPrivProtocol] 898 else: 899 raise error.StatusInformation( 900 errorIndication=errind.decryptionError, 901 msgUserName=msgUserName 902 ) 903 encryptedPDU = scopedPduData.getComponentByPosition(1) 904 if encryptedPDU is None: # no ciphertext 905 raise error.StatusInformation( 906 errorIndication=errind.decryptionError, 907 msgUserName=msgUserName 908 ) 909 910 try: 911 decryptedData = privHandler.decryptData( 912 usmUserPrivKeyLocalized, 913 (securityParameters.getComponentByPosition(1), 914 securityParameters.getComponentByPosition(2), 915 securityParameters.getComponentByPosition(5)), 916 encryptedPDU 917 ) 918 debug.logger & debug.flagSM and debug.logger( 919 'processIncomingMsg: PDU deciphered into %s' % debug.hexdump(decryptedData)) 920 921 except error.StatusInformation: 922 usmStatsDecryptionErrors, = mibBuilder.importSymbols( 923 '__SNMP-USER-BASED-SM-MIB', 'usmStatsDecryptionErrors') 924 usmStatsDecryptionErrors.syntax += 1 925 raise error.StatusInformation( 926 errorIndication=errind.decryptionError, 927 oid=usmStatsDecryptionErrors.name, 928 val=usmStatsDecryptionErrors.syntax, 929 securityStateReference=securityStateReference, 930 securityLevel=securityLevel, 931 contextEngineId=contextEngineId, 932 contextName=contextName, 933 msgUserName=msgUserName, 934 maxSizeResponseScopedPDU=maxSizeResponseScopedPDU 935 ) 936 scopedPduSpec = scopedPduData.setComponentByPosition(0).getComponentByPosition(0) 937 try: 938 scopedPDU, rest = decoder.decode(decryptedData, asn1Spec=scopedPduSpec) 939 940 except PyAsn1Error: 941 debug.logger & debug.flagSM and debug.logger( 942 'processIncomingMsg: scopedPDU decoder failed %s' % sys.exc_info()[0]) 943 raise error.StatusInformation( 944 errorIndication=errind.decryptionError, 945 msgUserName=msgUserName 946 ) 947 948 if eoo.endOfOctets.isSameTypeWith(scopedPDU): 949 raise error.StatusInformation( 950 errorIndication=errind.decryptionError, 951 msgUserName=msgUserName 952 ) 953 else: 954 # 3.2.8b 955 scopedPDU = scopedPduData.getComponentByPosition(0) 956 if scopedPDU is None: # no plaintext 957 raise error.StatusInformation( 958 errorIndication=errind.decryptionError, 959 msgUserName=msgUserName 960 ) 961 962 debug.logger & debug.flagSM and debug.logger( 963 'processIncomingMsg: scopedPDU decoded %s' % scopedPDU.prettyPrint()) 964 965 # 3.2.10 966 securityName = usmUserSecurityName 967 968 debug.logger & debug.flagSM and debug.logger( 969 'processIncomingMsg: cached msgUserName %s info by securityStateReference %s' % ( 970 msgUserName, securityStateReference)) 971 972 # Delayed to include details 973 if not msgUserName and not msgAuthoritativeEngineId: 974 usmStatsUnknownUserNames, = mibBuilder.importSymbols( 975 '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnknownUserNames') 976 usmStatsUnknownUserNames.syntax += 1 977 raise error.StatusInformation( 978 errorIndication=errind.unknownSecurityName, 979 oid=usmStatsUnknownUserNames.name, 980 val=usmStatsUnknownUserNames.syntax, 981 securityStateReference=securityStateReference, 982 securityEngineID=msgAuthoritativeEngineId, 983 securityLevel=securityLevel, 984 contextEngineId=contextEngineId, 985 contextName=contextName, 986 msgUserName=msgUserName, 987 maxSizeResponseScopedPDU=maxSizeResponseScopedPDU, 988 PDU=scopedPDU 989 ) 990 991 # 3.2.12 992 return (msgAuthoritativeEngineId, securityName, scopedPDU, 993 maxSizeResponseScopedPDU, securityStateReference) 994 995 def __expireTimelineInfo(self): 996 if self.__expirationTimer in self.__timelineExpQueue: 997 for engineIdKey in self.__timelineExpQueue[self.__expirationTimer]: 998 if engineIdKey in self.__timeline: 999 del self.__timeline[engineIdKey] 1000 debug.logger & debug.flagSM and debug.logger('__expireTimelineInfo: expiring %r' % (engineIdKey,)) 1001 del self.__timelineExpQueue[self.__expirationTimer] 1002 self.__expirationTimer += 1 1003 1004 def receiveTimerTick(self, snmpEngine, timeNow): 1005 self.__expireTimelineInfo() 1006