def sendPdu(self, snmpEngine, transportDomain, transportAddress, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, PDU, expectResponse): """PDU dispatcher -- prepare and serialize a request or notification""" # 4.1.1.2 mpHandler = snmpEngine.messageProcessingSubsystems.get( int(messageProcessingModel)) if mpHandler is None: raise error.StatusInformation( errorIndication='unsupportedMsgProcessingModel') debug.logger & debug.flagDsp and debug.logger( 'sendPdu: PDU %s' % PDU.prettyPrint()) # 4.1.1.3 sendPduHandle = self.__newSendPduHandle() if expectResponse: self.__cacheAdd(sendPduHandle, messageProcessingModel=messageProcessingModel, sendPduHandle=sendPduHandle, expectResponse=expectResponse) debug.logger & debug.flagDsp and debug.logger( 'sendPdu: new sendPduHandle %s' % sendPduHandle) # 4.1.1.4 & 4.1.1.5 try: (destTransportDomain, destTransportAddress, outgoingMessage) = mpHandler.prepareOutgoingMessage( snmpEngine, transportDomain, transportAddress, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, PDU, expectResponse, sendPduHandle) debug.logger & debug.flagDsp and debug.logger( 'sendPdu: MP succeeded') except error.StatusInformation as statusInformation: # XXX is it still needed here? # self.releaseStateInformation(snmpEngine, sendPduHandle, messageProcessingModel) raise # 4.1.1.6 if snmpEngine.transportDispatcher is None: raise error.PySnmpError('Transport dispatcher not set') snmpEngine.transportDispatcher.sendMessage(outgoingMessage, destTransportDomain, destTransportAddress) # Update cache with orignal req params (used for retrying) if expectResponse: self.__cacheUpdate(sendPduHandle, transportDomain=transportDomain, transportAddress=transportAddress, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, pduVersion=pduVersion, PDU=PDU) return sendPduHandle
def prepareDataElements(self, snmpEngine, transportDomain, transportAddress, wholeMsg): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder # rfc3412: 7.2.2 msg, restOfWholeMsg = decoder.decode(wholeMsg, asn1Spec=self._snmpMsgSpec) debug.logger & debug.FLAG_MP and debug.logger( 'prepareDataElements: %s' % (msg.prettyPrint(), )) if eoo.endOfOctets.isSameTypeWith(msg): raise error.StatusInformation(errorIndication=errind.parseError) # rfc3412: 7.2.3 msgVersion = msg.getComponentByPosition(0) # rfc2576: 5.2.1 snmpEngineMaxMessageSize, = mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') communityName = msg.getComponentByPosition(1) # transportDomain identifies local endpoint securityParameters = (communityName, (transportDomain, transportAddress)) messageProcessingModel = int(msg.getComponentByPosition(0)) securityModel = messageProcessingModel + 1 securityLevel = 1 # rfc3412: 7.2.4 -- 7.2.5 -> no-op try: try: smHandler = snmpEngine.securityModels[securityModel] except KeyError: raise error.StatusInformation( errorIndication=errind.unsupportedSecurityModel) # rfc3412: 7.2.6 (securityEngineId, securityName, scopedPDU, maxSizeResponseScopedPDU, securityStateReference) = smHandler.processIncomingMsg( snmpEngine, messageProcessingModel, snmpEngineMaxMessageSize.syntax, securityParameters, securityModel, securityLevel, wholeMsg, msg) debug.logger & debug.FLAG_MP and debug.logger( 'prepareDataElements: SM returned securityEngineId %r ' 'securityName %r' % (securityEngineId, securityName)) except error.StatusInformation as exc: statusInformation = exc snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc2576.prepareDataElements:sm-failure', dict(transportDomain=transportDomain, transportAddress=transportAddress, securityModel=securityModel, securityLevel=securityLevel, securityParameters=securityParameters, statusInformation=statusInformation)) snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc2576.prepareDataElements:sm-failure') raise # rfc3412: 7.2.6a --> no-op # rfc3412: 7.2.7 contextEngineId, contextName, pdu = scopedPDU # rfc2576: 5.2.1 pduVersion = msgVersion pduType = pdu.tagSet # rfc3412: 7.2.8, 7.2.9 -> no-op # rfc3412: 7.2.10 if pduType in rfc3411.RESPONSE_CLASS_PDUS: # get unique PDU request-id msgID = pdu.getComponentByPosition(0) # 7.2.10a try: cachedReqParams = self._cache.popByMsgId(int(msgID)) except error.ProtocolError: smHandler.releaseStateInformation(securityStateReference) raise error.StatusInformation( errorIndication=errind.dataMismatch) # recover original PDU request-id to return to app pdu.setComponentByPosition(0, cachedReqParams['reqID']) debug.logger & debug.FLAG_MP and debug.logger( 'prepareDataElements: unique PDU request-id %s replaced with ' 'original ID %s' % (msgID, cachedReqParams['reqID'])) # 7.2.10b sendPduHandle = cachedReqParams['sendPduHandle'] else: sendPduHandle = None # no error by default statusInformation = None # rfc3412: 7.2.11 -> no-op # rfc3412: 7.2.12 if pduType in rfc3411.RESPONSE_CLASS_PDUS: # rfc3412: 7.2.12a -> no-op # rfc3412: 7.2.12b # noinspection PyUnboundLocalVariable if (securityModel != cachedReqParams['securityModel'] or securityName != cachedReqParams['securityName'] or securityLevel != cachedReqParams['securityLevel'] or contextEngineId != cachedReqParams['contextEngineId'] or contextName != cachedReqParams['contextName']): smHandler.releaseStateInformation(securityStateReference) raise error.StatusInformation( errorIndication=errind.dataMismatch) stateReference = None snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc2576.prepareDataElements:response', dict(transportDomain=transportDomain, transportAddress=transportAddress, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, securityEngineId=securityEngineId, communityName=communityName, pdu=pdu)) snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc2576.prepareDataElements:response') # rfc3412: 7.2.12c smHandler.releaseStateInformation(securityStateReference) # rfc3412: 7.2.12d return (messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, pduType, sendPduHandle, maxSizeResponseScopedPDU, statusInformation, stateReference) # rfc3412: 7.2.13 if pduType in rfc3411.CONFIRMED_CLASS_PDUS: # store original PDU request-id and replace it with a unique one reqID = pdu.getComponentByPosition(0) msgID = self._cache.newMsgID() pdu.setComponentByPosition(0, msgID) debug.logger & debug.FLAG_MP and debug.logger( 'prepareDataElements: received PDU request-id %s replaced with ' 'unique ID %s' % (reqID, msgID)) # rfc3412: 7.2.13a snmpEngineId, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') if securityEngineId != snmpEngineId.syntax: smHandler.releaseStateInformation(securityStateReference) raise error.StatusInformation( errorIndication=errind.engineIDMismatch) # rfc3412: 7.2.13b stateReference = self._cache.newStateReference() self._cache.pushByStateRef( stateReference, msgVersion=messageProcessingModel, msgID=msgID, reqID=reqID, contextEngineId=contextEngineId, contextName=contextName, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, securityStateReference=securityStateReference, msgMaxSize=snmpEngineMaxMessageSize.syntax, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU, transportDomain=transportDomain, transportAddress=transportAddress) snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc2576.prepareDataElements:confirmed', dict(transportDomain=transportDomain, transportAddress=transportAddress, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, securityEngineId=securityEngineId, communityName=communityName, pdu=pdu)) snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc2576.prepareDataElements:confirmed') debug.logger & debug.FLAG_MP and debug.logger( 'prepareDataElements: cached by new stateReference ' '%s' % stateReference) # rfc3412: 7.2.13c return (messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, pduType, sendPduHandle, maxSizeResponseScopedPDU, statusInformation, stateReference) # rfc3412: 7.2.14 if pduType in rfc3411.UNCONFIRMED_CLASS_PDUS: # Pass new stateReference to let app browse request details stateReference = self._cache.newStateReference() snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc2576.prepareDataElements:unconfirmed', dict(transportDomain=transportDomain, transportAddress=transportAddress, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, securityEngineId=securityEngineId, communityName=communityName, pdu=pdu)) snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc2576.prepareDataElements:unconfirmed') # This is not specified explicitly in RFC smHandler.releaseStateInformation(securityStateReference) return (messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, pduType, sendPduHandle, maxSizeResponseScopedPDU, statusInformation, stateReference) smHandler.releaseStateInformation(securityStateReference) raise error.StatusInformation( errorIndication=errind.unsupportedPDUtype)
def _com2sec(self, snmpEngine, communityName, transportInformation): snmpTargetAddrTAddress, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( 'SNMP-TARGET-MIB', 'snmpTargetAddrTAddress') if self.__transportBranchId != snmpTargetAddrTAddress.branchVersionId: ( SnmpTagValue, snmpTargetAddrTDomain, snmpTargetAddrTagList ) = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( 'SNMP-TARGET-MIB', 'SnmpTagValue', 'snmpTargetAddrTDomain', 'snmpTargetAddrTagList') self.__emptyTag = SnmpTagValue('') self.__transportToTagMap = {} nextMibNode = snmpTargetAddrTagList while True: try: nextMibNode = snmpTargetAddrTagList.getNextNode( nextMibNode.name) except NoSuchInstanceError: break instId = nextMibNode.name[len(snmpTargetAddrTagList.name):] targetAddrTDomain = snmpTargetAddrTDomain.getNode( snmpTargetAddrTDomain.name + instId).syntax targetAddrTAddress = snmpTargetAddrTAddress.getNode( snmpTargetAddrTAddress.name + instId).syntax targetAddrTDomain = tuple(targetAddrTDomain) if targetAddrTDomain[:len(udp.snmpUDPDomain )] == udp.snmpUDPDomain: SnmpUDPAddress, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( 'SNMPv2-TM', 'SnmpUDPAddress') targetAddrTAddress = tuple( SnmpUDPAddress(targetAddrTAddress)) elif targetAddrTDomain[:len(udp6.snmpUDP6Domain )] == udp6.snmpUDP6Domain: TransportAddressIPv6, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( 'TRANSPORT-ADDRESS-MIB', 'TransportAddressIPv6') targetAddrTAddress = tuple( TransportAddressIPv6(targetAddrTAddress)) elif targetAddrTDomain[:len(unix.snmpLocalDomain )] == unix.snmpLocalDomain: targetAddrTAddress = str(targetAddrTAddress) targetAddr = targetAddrTDomain, targetAddrTAddress targetAddrTagList = snmpTargetAddrTagList.getNode( snmpTargetAddrTagList.name + instId).syntax if targetAddr not in self.__transportToTagMap: self.__transportToTagMap[targetAddr] = set() if targetAddrTagList: self.__transportToTagMap[targetAddr].update([ SnmpTagValue(x) for x in targetAddrTagList.asOctets().split() ]) else: self.__transportToTagMap[targetAddr].add(self.__emptyTag) self.__transportBranchId = snmpTargetAddrTAddress.branchVersionId debug.logger & debug.flagSM and debug.logger( '_com2sec: built transport-to-tag map version %s: %s' % (self.__transportBranchId, self.__transportToTagMap)) snmpTargetParamsSecurityName, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( 'SNMP-TARGET-MIB', 'snmpTargetParamsSecurityName') if self.__paramsBranchId != snmpTargetParamsSecurityName.branchVersionId: snmpTargetParamsSecurityModel, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( 'SNMP-TARGET-MIB', 'snmpTargetParamsSecurityModel') self.__nameToModelMap = {} nextMibNode = snmpTargetParamsSecurityName while True: try: nextMibNode = snmpTargetParamsSecurityName.getNextNode( nextMibNode.name) except NoSuchInstanceError: break instId = nextMibNode.name[len(snmpTargetParamsSecurityName.name ):] mibNode = snmpTargetParamsSecurityModel.getNode( snmpTargetParamsSecurityModel.name + instId) if nextMibNode.syntax not in self.__nameToModelMap: self.__nameToModelMap[nextMibNode.syntax] = set() self.__nameToModelMap[nextMibNode.syntax].add(mibNode.syntax) self.__paramsBranchId = snmpTargetParamsSecurityName.branchVersionId # invalidate next map as it include this one self.__communityBranchId = -1 debug.logger & debug.flagSM and debug.logger( '_com2sec: built securityName to securityModel map, version %s: %s' % (self.__paramsBranchId, self.__nameToModelMap)) snmpCommunityName, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( 'SNMP-COMMUNITY-MIB', 'snmpCommunityName') if self.__communityBranchId != snmpCommunityName.branchVersionId: ( snmpCommunitySecurityName, snmpCommunityContextEngineId, snmpCommunityContextName, snmpCommunityTransportTag ) = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( 'SNMP-COMMUNITY-MIB', 'snmpCommunitySecurityName', 'snmpCommunityContextEngineID', 'snmpCommunityContextName', 'snmpCommunityTransportTag') self.__communityToTagMap = {} self.__tagAndCommunityToSecurityMap = {} nextMibNode = snmpCommunityName while True: try: nextMibNode = snmpCommunityName.getNextNode( nextMibNode.name) except NoSuchInstanceError: break instId = nextMibNode.name[len(snmpCommunityName.name):] securityName = snmpCommunitySecurityName.getNode( snmpCommunitySecurityName.name + instId).syntax contextEngineId = snmpCommunityContextEngineId.getNode( snmpCommunityContextEngineId.name + instId).syntax contextName = snmpCommunityContextName.getNode( snmpCommunityContextName.name + instId).syntax transportTag = snmpCommunityTransportTag.getNode( snmpCommunityTransportTag.name + instId).syntax _tagAndCommunity = transportTag, nextMibNode.syntax if _tagAndCommunity not in self.__tagAndCommunityToSecurityMap: self.__tagAndCommunityToSecurityMap[ _tagAndCommunity] = set() self.__tagAndCommunityToSecurityMap[_tagAndCommunity].add( (securityName, contextEngineId, contextName)) if nextMibNode.syntax not in self.__communityToTagMap: self.__communityToTagMap[nextMibNode.syntax] = set() self.__communityToTagMap[nextMibNode.syntax].add(transportTag) self.__communityBranchId = snmpCommunityName.branchVersionId debug.logger & debug.flagSM and debug.logger( '_com2sec: built communityName to tag map (securityModel %s), version %s: %s' % (self.securityModelID, self.__communityBranchId, self.__communityToTagMap)) debug.logger & debug.flagSM and debug.logger( '_com2sec: built tag & community to securityName map (securityModel %s), version %s: %s' % (self.securityModelID, self.__communityBranchId, self.__tagAndCommunityToSecurityMap)) if communityName in self.__communityToTagMap: if transportInformation in self.__transportToTagMap: tags = self.__transportToTagMap[ transportInformation].intersection( self.__communityToTagMap[communityName]) elif self.__emptyTag in self.__communityToTagMap[communityName]: tags = [self.__emptyTag] else: raise error.StatusInformation( errorIndication=errind.unknownCommunityName) candidateSecurityNames = [] for x in [ self.__tagAndCommunityToSecurityMap[(t, communityName)] for t in tags ]: candidateSecurityNames.extend(list(x)) # 5.2.1 (row selection in snmpCommunityTable) # Picks first match but favors entries already in targets table if candidateSecurityNames: candidateSecurityNames.sort( key=lambda x, m=self.__nameToModelMap, v=self. securityModelID: (not int(x[0] in m and v in m[x[0]]), str(x[0]))) chosenSecurityName = candidateSecurityNames[0] # min() debug.logger & debug.flagSM and debug.logger( '_com2sec: securityName candidates for communityName \'%s\' are %s; choosing securityName \'%s\'' % (communityName, candidateSecurityNames, chosenSecurityName[0])) return chosenSecurityName raise error.StatusInformation( errorIndication=errind.unknownCommunityName)
def __cloneUserInfo(self, mibInstrumController, securityEngineID, userName): snmpEngineID, = mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineID') # Proto entry usmUserEntry, = mibInstrumController.mibBuilder.importSymbols( 'SNMP-USER-BASED-SM-MIB', 'usmUserEntry') tblIdx1 = usmUserEntry.getInstIdFromIndices(snmpEngineID.syntax, userName) # Get proto protocols usmUserName = usmUserEntry.getNode(usmUserEntry.name + (2, ) + tblIdx1) usmUserSecurityName = usmUserEntry.getNode(usmUserEntry.name + (3, ) + tblIdx1) usmUserCloneFrom = usmUserEntry.getNode(usmUserEntry.name + (4, ) + tblIdx1) usmUserAuthProtocol = usmUserEntry.getNode(usmUserEntry.name + (5, ) + tblIdx1) usmUserPrivProtocol = usmUserEntry.getNode(usmUserEntry.name + (8, ) + tblIdx1) # Get proto keys pysnmpUsmKeyEntry, = mibInstrumController.mibBuilder.importSymbols( 'PYSNMP-USM-MIB', 'pysnmpUsmKeyEntry') pysnmpUsmKeyAuth = pysnmpUsmKeyEntry.getNode(pysnmpUsmKeyEntry.name + (3, ) + tblIdx1) pysnmpUsmKeyPriv = pysnmpUsmKeyEntry.getNode(pysnmpUsmKeyEntry.name + (4, ) + tblIdx1) # Create new row from proto values tblIdx2 = usmUserEntry.getInstIdFromIndices(securityEngineID, userName) # New row mibInstrumController.writeVars( ((usmUserEntry.name + (13, ) + tblIdx2, 4), )) # Set user&securityNames usmUserEntry.getNode(usmUserEntry.name + (2, ) + tblIdx2).syntax = usmUserName.syntax usmUserEntry.getNode(usmUserEntry.name + (3, ) + tblIdx2).syntax = usmUserSecurityName.syntax # Store a reference to original row usmUserEntry.getNode(usmUserEntry.name + ( 4, ) + tblIdx2).syntax = usmUserCloneFrom.syntax.clone(tblIdx1) # Set protocols usmUserEntry.getNode(usmUserEntry.name + (5, ) + tblIdx2).syntax = usmUserAuthProtocol.syntax usmUserEntry.getNode(usmUserEntry.name + (8, ) + tblIdx2).syntax = usmUserPrivProtocol.syntax # Localize and set keys pysnmpUsmKeyEntry, = mibInstrumController.mibBuilder.importSymbols( 'PYSNMP-USM-MIB', 'pysnmpUsmKeyEntry') pysnmpUsmKeyAuthLocalized = pysnmpUsmKeyEntry.getNode( pysnmpUsmKeyEntry.name + (1, ) + tblIdx2) if usmUserAuthProtocol.syntax in self.authServices: localizeKey = self.authServices[ usmUserAuthProtocol.syntax].localizeKey localAuthKey = localizeKey(pysnmpUsmKeyAuth.syntax, securityEngineID) else: raise error.StatusInformation( errorIndication=errind.unsupportedAuthProtocol) if localAuthKey is not None: pysnmpUsmKeyAuthLocalized.syntax = pysnmpUsmKeyAuthLocalized.syntax.clone( localAuthKey) pysnmpUsmKeyPrivLocalized = pysnmpUsmKeyEntry.getNode( pysnmpUsmKeyEntry.name + (2, ) + tblIdx2) if usmUserPrivProtocol.syntax in self.privServices: localizeKey = self.privServices[ usmUserPrivProtocol.syntax].localizeKey localPrivKey = localizeKey(usmUserAuthProtocol.syntax, pysnmpUsmKeyPriv.syntax, securityEngineID) else: raise error.StatusInformation( errorIndication=errind.unsupportedPrivProtocol) if localPrivKey is not None: pysnmpUsmKeyPrivLocalized.syntax = pysnmpUsmKeyPrivLocalized.syntax.clone( localPrivKey) return (usmUserName.syntax, usmUserSecurityName.syntax, usmUserAuthProtocol.syntax, pysnmpUsmKeyAuthLocalized.syntax, usmUserPrivProtocol.syntax, pysnmpUsmKeyPrivLocalized.syntax)
def processIncomingMsg( self, snmpEngine, messageProcessingModel, maxMessageSize, securityParameters, securityModel, securityLevel, wholeMsg, msg # XXX ): # 3.2.9 -- moved up here to be able to report # maxSizeResponseScopedPDU on error # (48 - maximum SNMPv3 header length) maxSizeResponseScopedPDU = int(maxMessageSize) - len( securityParameters) - 48 debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: securityParameters %s' % debug.hexdump(securityParameters)) # 3.2.1 try: securityParameters, rest = decoder.decode( securityParameters, asn1Spec=self.__securityParametersSpec) except PyAsn1Error: debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: %s' % (sys.exc_info()[1], )) snmpInASNParseErrs, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpInASNParseErrs') snmpInASNParseErrs.syntax = snmpInASNParseErrs.syntax + 1 raise error.StatusInformation(errorIndication=errind.parseError) debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: %s' % (securityParameters.prettyPrint(), )) if eoo.endOfOctets.isSameTypeWith(securityParameters): raise error.StatusInformation(errorIndication=errind.parseError) # 3.2.2 msgAuthoritativeEngineID = securityParameters.getComponentByPosition(0) securityStateReference = self._cache.push( msgUserName=securityParameters.getComponentByPosition(3)) debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: cache write securityStateReference %s by msgUserName %s' % (securityStateReference, securityParameters.getComponentByPosition(3))) scopedPduData = msg.getComponentByPosition(3) # Used for error reporting contextEngineId = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineID')[0].syntax contextName = null # 3.2.3 if msgAuthoritativeEngineID not in self.__timeline: debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: unknown securityEngineID %r' % (msgAuthoritativeEngineID, )) if not msgAuthoritativeEngineID or \ not 4 < len(msgAuthoritativeEngineID) < 33: # 3.2.3b usmStatsUnknownEngineIDs, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnknownEngineIDs') usmStatsUnknownEngineIDs.syntax = usmStatsUnknownEngineIDs.syntax + 1 debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: null or malformed msgAuthoritativeEngineID' ) pysnmpUsmDiscoverable, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__PYSNMP-USM-MIB', 'pysnmpUsmDiscoverable') if pysnmpUsmDiscoverable.syntax: debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: starting snmpEngineID discovery procedure' ) # Report original contextName if scopedPduData.getName() != 'plaintext': debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: scopedPduData not plaintext %s' % scopedPduData.prettyPrint()) raise error.StatusInformation( errorIndication=errind.unknownEngineID) # 7.2.6.a.1 scopedPdu = scopedPduData.getComponent() contextEngineId = scopedPdu.getComponentByPosition(0) contextName = scopedPdu.getComponentByPosition(1) raise error.StatusInformation( errorIndication=errind.unknownEngineID, oid=usmStatsUnknownEngineIDs.name, val=usmStatsUnknownEngineIDs.syntax, securityStateReference=securityStateReference, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, scopedPDU=scopedPdu, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU) else: debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: will not discover EngineID') # free securityStateReference XXX raise error.StatusInformation( errorIndication=errind.unknownEngineID) snmpEngineID = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineID')[0].syntax msgUserName = securityParameters.getComponentByPosition(3) debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: read from securityParams msgAuthoritativeEngineID %r msgUserName %r' % (msgAuthoritativeEngineID, msgUserName)) if msgUserName: # 3.2.4 try: (usmUserName, usmUserSecurityName, usmUserAuthProtocol, usmUserAuthKeyLocalized, usmUserPrivProtocol, usmUserPrivKeyLocalized) = self.__getUserInfo( snmpEngine.msgAndPduDsp.mibInstrumController, msgAuthoritativeEngineID, msgUserName) debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: read user info from LCD') except NoSuchInstanceError: pysnmpUsmDiscoverable, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__PYSNMP-USM-MIB', 'pysnmpUsmDiscoverable') __reportUnknownName = not pysnmpUsmDiscoverable.syntax if not __reportUnknownName: try: (usmUserName, usmUserSecurityName, usmUserAuthProtocol, usmUserAuthKeyLocalized, usmUserPrivProtocol, usmUserPrivKeyLocalized) = self.__cloneUserInfo( snmpEngine.msgAndPduDsp.mibInstrumController, msgAuthoritativeEngineID, msgUserName) debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: cloned user info') except NoSuchInstanceError: __reportUnknownName = 1 debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: unknown securityEngineID %r msgUserName %r' % (msgAuthoritativeEngineID, msgUserName)) if __reportUnknownName: usmStatsUnknownUserNames, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnknownUserNames') usmStatsUnknownUserNames.syntax = usmStatsUnknownUserNames.syntax + 1 raise error.StatusInformation( errorIndication=errind.unknownSecurityName, oid=usmStatsUnknownUserNames.name, val=usmStatsUnknownUserNames.syntax, securityStateReference=securityStateReference, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU) except PyAsn1Error: debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: %s' % (sys.exc_info()[1], )) snmpInGenErrs, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpInGenErrs') snmpInGenErrs.syntax = snmpInGenErrs.syntax + 1 raise error.StatusInformation( errorIndication=errind.invalidMsg) else: # empty username used for engineID discovery usmUserName = usmUserSecurityName = null usmUserAuthProtocol = noauth.NoAuth.serviceID usmUserPrivProtocol = nopriv.NoPriv.serviceID usmUserAuthKeyLocalized = usmUserPrivKeyLocalized = None debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: now have usmUserName %r usmUserSecurityName %r usmUserAuthProtocol %r usmUserPrivProtocol %r for msgUserName %r' % (usmUserName, usmUserSecurityName, usmUserAuthProtocol, usmUserPrivProtocol, msgUserName)) # 3.2.11 (moved up here to let Reports be authenticated & encrypted) self._cache.pop(securityStateReference) securityStateReference = self._cache.push( msgUserName=securityParameters.getComponentByPosition(3), usmUserSecurityName=usmUserSecurityName, usmUserAuthProtocol=usmUserAuthProtocol, usmUserAuthKeyLocalized=usmUserAuthKeyLocalized, usmUserPrivProtocol=usmUserPrivProtocol, usmUserPrivKeyLocalized=usmUserPrivKeyLocalized) msgAuthoritativeEngineBoots = securityParameters.getComponentByPosition( 1) msgAuthoritativeEngineTime = securityParameters.getComponentByPosition( 2) # 3.2.5 if msgAuthoritativeEngineID == snmpEngineID: # Authoritative SNMP engine: make sure securityLevel is sufficient __badSecIndication = None if securityLevel == 3: if usmUserAuthProtocol == noauth.NoAuth.serviceID: __badSecIndication = 'authPriv wanted while auth not expected' if usmUserPrivProtocol == nopriv.NoPriv.serviceID: __badSecIndication = 'authPriv wanted while priv not expected' elif securityLevel == 2: if usmUserAuthProtocol == noauth.NoAuth.serviceID: __badSecIndication = 'authNoPriv wanted while auth not expected' if usmUserPrivProtocol != nopriv.NoPriv.serviceID: # 4 (discovery phase always uses authenticated messages) if msgAuthoritativeEngineBoots or msgAuthoritativeEngineTime: __badSecIndication = 'authNoPriv wanted while priv expected' elif securityLevel == 1: if usmUserAuthProtocol != noauth.NoAuth.serviceID: __badSecIndication = 'noAuthNoPriv wanted while auth expected' if usmUserPrivProtocol != nopriv.NoPriv.serviceID: __badSecIndication = 'noAuthNoPriv wanted while priv expected' if __badSecIndication: usmStatsUnsupportedSecLevels, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnsupportedSecLevels') usmStatsUnsupportedSecLevels.syntax = usmStatsUnsupportedSecLevels.syntax + 1 debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: reporting inappropriate security level for user %s: %s' % (msgUserName, __badSecIndication)) raise error.StatusInformation( errorIndication=errind.unsupportedSecurityLevel, oid=usmStatsUnsupportedSecLevels.name, val=usmStatsUnsupportedSecLevels.syntax, securityStateReference=securityStateReference, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU) # 3.2.6 if securityLevel == 3 or securityLevel == 2: if usmUserAuthProtocol in self.authServices: authHandler = self.authServices[usmUserAuthProtocol] else: raise error.StatusInformation( errorIndication=errind.authenticationFailure) try: authenticatedWholeMsg = authHandler.authenticateIncomingMsg( usmUserAuthKeyLocalized, securityParameters.getComponentByPosition(4), wholeMsg) except error.StatusInformation: usmStatsWrongDigests, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsWrongDigests') usmStatsWrongDigests.syntax = usmStatsWrongDigests.syntax + 1 raise error.StatusInformation( errorIndication=errind.authenticationFailure, oid=usmStatsWrongDigests.name, val=usmStatsWrongDigests.syntax, securityStateReference=securityStateReference, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU) debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: incoming msg authenticated') if msgAuthoritativeEngineID: # 3.2.3a moved down here to execute only for authed msg self.__timeline[msgAuthoritativeEngineID] = ( securityParameters.getComponentByPosition(1), securityParameters.getComponentByPosition(2), securityParameters.getComponentByPosition(2), int(time.time())) expireAt = int( self.__expirationTimer + 300 / snmpEngine.transportDispatcher.getTimerResolution()) if expireAt not in self.__timelineExpQueue: self.__timelineExpQueue[expireAt] = [] self.__timelineExpQueue[expireAt].append( msgAuthoritativeEngineID) debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: store timeline for securityEngineID %r' % (msgAuthoritativeEngineID, )) # 3.2.7 if securityLevel == 3 or securityLevel == 2: if msgAuthoritativeEngineID == snmpEngineID: # Authoritative SNMP engine: use local notion (SF bug #1649032) ( snmpEngineBoots, snmpEngineTime ) = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineBoots', 'snmpEngineTime') snmpEngineBoots = snmpEngineBoots.syntax snmpEngineTime = snmpEngineTime.syntax.clone() idleTime = 0 debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: read snmpEngineBoots (%s), snmpEngineTime (%s) from LCD' % (snmpEngineBoots, snmpEngineTime)) else: # Non-authoritative SNMP engine: use cached estimates if msgAuthoritativeEngineID in self.__timeline: (snmpEngineBoots, snmpEngineTime, latestReceivedEngineTime, latestUpdateTimestamp ) = self.__timeline[msgAuthoritativeEngineID] # time passed since last talk with this SNMP engine idleTime = int(time.time()) - latestUpdateTimestamp debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: read timeline snmpEngineBoots %s snmpEngineTime %s for msgAuthoritativeEngineID %r, idle time %s secs' % (snmpEngineBoots, snmpEngineTime, msgAuthoritativeEngineID, idleTime)) else: raise error.ProtocolError('Peer SNMP engine info missing') # 3.2.7a if msgAuthoritativeEngineID == snmpEngineID: if snmpEngineBoots == 2147483647 or \ snmpEngineBoots != msgAuthoritativeEngineBoots or \ abs(idleTime + int(snmpEngineTime) - \ int(msgAuthoritativeEngineTime)) > 150: usmStatsNotInTimeWindows, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsNotInTimeWindows') usmStatsNotInTimeWindows.syntax = usmStatsNotInTimeWindows.syntax + 1 raise error.StatusInformation( errorIndication=errind.notInTimeWindow, oid=usmStatsNotInTimeWindows.name, val=usmStatsNotInTimeWindows.syntax, securityStateReference=securityStateReference, securityLevel=2, contextEngineId=contextEngineId, contextName=contextName, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU) # 3.2.7b else: # 3.2.7b.1 if msgAuthoritativeEngineBoots > snmpEngineBoots or \ msgAuthoritativeEngineBoots == snmpEngineBoots and \ msgAuthoritativeEngineTime > latestReceivedEngineTime: self.__timeline[msgAuthoritativeEngineID] = ( msgAuthoritativeEngineBoots, msgAuthoritativeEngineTime, msgAuthoritativeEngineTime, int(time.time())) expireAt = int( self.__expirationTimer + 300 / snmpEngine.transportDispatcher.getTimerResolution()) if expireAt not in self.__timelineExpQueue: self.__timelineExpQueue[expireAt] = [] self.__timelineExpQueue[expireAt].append( msgAuthoritativeEngineID) debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: stored timeline msgAuthoritativeEngineBoots %s msgAuthoritativeEngineTime %s for msgAuthoritativeEngineID %r' % (msgAuthoritativeEngineBoots, msgAuthoritativeEngineTime, msgAuthoritativeEngineID)) # 3.2.7b.2 if snmpEngineBoots == 2147483647 or \ msgAuthoritativeEngineBoots < snmpEngineBoots or \ msgAuthoritativeEngineBoots == snmpEngineBoots and \ abs(idleTime + int(snmpEngineTime) - \ int(msgAuthoritativeEngineTime)) > 150: raise error.StatusInformation( errorIndication=errind.notInTimeWindow) # 3.2.8a if securityLevel == 3: if usmUserPrivProtocol in self.privServices: privHandler = self.privServices[usmUserPrivProtocol] else: raise error.StatusInformation( errorIndication=errind.decryptionError) encryptedPDU = scopedPduData.getComponentByPosition(1) if encryptedPDU is None: # no ciphertext raise error.StatusInformation( errorIndication=errind.decryptionError) try: decryptedData = privHandler.decryptData( usmUserPrivKeyLocalized, (securityParameters.getComponentByPosition(1), securityParameters.getComponentByPosition(2), securityParameters.getComponentByPosition(5)), encryptedPDU) debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: PDU deciphered into %s' % debug.hexdump(decryptedData)) except error.StatusInformation: usmStatsDecryptionErrors, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsDecryptionErrors') usmStatsDecryptionErrors.syntax = usmStatsDecryptionErrors.syntax + 1 raise error.StatusInformation( errorIndication=errind.decryptionError, oid=usmStatsDecryptionErrors.name, val=usmStatsDecryptionErrors.syntax, securityStateReference=securityStateReference, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU) scopedPduSpec = scopedPduData.setComponentByPosition( 0).getComponentByPosition(0) try: scopedPDU, rest = decoder.decode(decryptedData, asn1Spec=scopedPduSpec) except PyAsn1Error: debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: scopedPDU decoder failed %s' % sys.exc_info()[0]) raise error.StatusInformation( errorIndication=errind.decryptionError) if eoo.endOfOctets.isSameTypeWith(scopedPDU): raise error.StatusInformation( errorIndication=errind.decryptionError) else: # 3.2.8b scopedPDU = scopedPduData.getComponentByPosition(0) if scopedPDU is None: # no plaintext raise error.StatusInformation( errorIndication=errind.decryptionError) debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: scopedPDU decoded %s' % scopedPDU.prettyPrint()) # 3.2.10 securityName = usmUserSecurityName debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: cached msgUserName %s info by securityStateReference %s' % (msgUserName, securityStateReference)) # Delayed to include details if not msgUserName and not msgAuthoritativeEngineID: usmStatsUnknownUserNames, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnknownUserNames') usmStatsUnknownUserNames.syntax = usmStatsUnknownUserNames.syntax + 1 raise error.StatusInformation( errorIndication=errind.unknownSecurityName, oid=usmStatsUnknownUserNames.name, val=usmStatsUnknownUserNames.syntax, securityStateReference=securityStateReference, securityEngineID=msgAuthoritativeEngineID, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU, PDU=scopedPDU) # 3.2.12 return (msgAuthoritativeEngineID, securityName, scopedPDU, maxSizeResponseScopedPDU, securityStateReference)
def v2ToV1(v2Pdu, origV1Pdu=None): debug.logger & debug.flagPrx and debug.logger( 'v2ToV1: v2Pdu %s' % v2Pdu.prettyPrint()) pduType = v2Pdu.tagSet if pduType in __v2ToV1PduMap: v1Pdu = __v2ToV1PduMap[pduType].clone() else: raise error.ProtocolError('Unsupported PDU type') v2VarBinds = v2c.apiPDU.getVarBinds(v2Pdu) v1VarBinds = [] # 3.2 if pduType in rfc3411.notificationClassPDUs: # 3.2.1 (snmpTrapOID, snmpTrapOIDParam) = v2VarBinds[1] if snmpTrapOID != v2c.apiTrapPDU.snmpTrapOID: raise error.ProtocolError('Second OID not snmpTrapOID') if snmpTrapOIDParam in __v2ToV1TrapMap: for oid, val in v2VarBinds: if oid == v2c.apiTrapPDU.snmpTrapEnterprise: v1.apiTrapPDU.setEnterprise(v1Pdu, val) break else: # snmpTraps v1.apiTrapPDU.setEnterprise(v1Pdu, (1, 3, 6, 1, 6, 3, 1, 1, 5)) else: if snmpTrapOIDParam[-2] == 0: v1.apiTrapPDU.setEnterprise(v1Pdu, snmpTrapOIDParam[:-2]) else: v1.apiTrapPDU.setEnterprise(v1Pdu, snmpTrapOIDParam[:-1]) # 3.2.2 for oid, val in v2VarBinds: # snmpTrapAddress if oid == v2c.apiTrapPDU.snmpTrapAddress: v1.apiTrapPDU.setAgentAddr(v1Pdu, val) break else: v1.apiTrapPDU.setAgentAddr(v1Pdu, v1.apiTrapPDU.agentAddress) # 3.2.3 if snmpTrapOIDParam in __v2ToV1TrapMap: v1.apiTrapPDU.setGenericTrap(v1Pdu, __v2ToV1TrapMap[snmpTrapOIDParam]) else: v1.apiTrapPDU.setGenericTrap(v1Pdu, 6) # 3.2.4 if snmpTrapOIDParam in __v2ToV1TrapMap: v1.apiTrapPDU.setSpecificTrap(v1Pdu, __zeroInt) else: v1.apiTrapPDU.setSpecificTrap(v1Pdu, snmpTrapOIDParam[-1]) # 3.2.5 v1.apiTrapPDU.setTimeStamp(v1Pdu, v2VarBinds[0][1]) __v2VarBinds = [] for oid, val in v2VarBinds[2:]: if oid in __v2ToV1TrapMap or \ oid in (v2c.apiTrapPDU.sysUpTime, v2c.apiTrapPDU.snmpTrapAddress, v2c.apiTrapPDU.snmpTrapEnterprise): continue __v2VarBinds.append((oid, val)) v2VarBinds = __v2VarBinds # 3.2.6 --> done below else: v1.apiPDU.setErrorStatus(v1Pdu, __zeroInt) v1.apiPDU.setErrorIndex(v1Pdu, __zeroInt) if pduType in rfc3411.responseClassPDUs: idx = len(v2VarBinds) - 1 while idx >= 0: # 4.1.2.1 oid, val = v2VarBinds[idx] if v2c.Counter64.tagSet == val.tagSet: if origV1Pdu.tagSet == v1.GetRequestPDU.tagSet: v1.apiPDU.setErrorStatus(v1Pdu, 2) v1.apiPDU.setErrorIndex(v1Pdu, idx + 1) break elif origV1Pdu.tagSet == v1.GetNextRequestPDU.tagSet: raise error.StatusInformation(idx=idx, pdu=v2Pdu) else: raise error.ProtocolError('Counter64 on the way') # 4.1.2.2.1&2 if val.tagSet in (v2c.NoSuchObject.tagSet, v2c.NoSuchInstance.tagSet, v2c.EndOfMibView.tagSet): v1.apiPDU.setErrorStatus(v1Pdu, 2) v1.apiPDU.setErrorIndex(v1Pdu, idx + 1) idx = idx - 1 # 4.1.2.3.1 v2ErrorStatus = v2c.apiPDU.getErrorStatus(v2Pdu) if v2ErrorStatus: v1.apiPDU.setErrorStatus(v1Pdu, __v2ToV1ErrorMap[v2ErrorStatus]) v1.apiPDU.setErrorIndex(v1Pdu, v2c.apiPDU.getErrorIndex(v2Pdu)) # Translate Var-Binds if pduType in rfc3411.responseClassPDUs and \ v1.apiPDU.getErrorStatus(v1Pdu): v1VarBinds = v1.apiPDU.getVarBinds(origV1Pdu) else: for oid, v2Val in v2VarBinds: v1VarBinds.append( (oid, __v2ToV1ValueMap[v2Val.tagSet].clone(v2Val))) if pduType in rfc3411.notificationClassPDUs: v1.apiTrapPDU.setVarBinds(v1Pdu, v1VarBinds) else: v1.apiPDU.setVarBinds(v1Pdu, v1VarBinds) v1.apiPDU.setRequestID(v1Pdu, v2c.apiPDU.getRequestID(v2Pdu)) debug.logger & debug.flagPrx and debug.logger( 'v2ToV1: v1Pdu %s' % v1Pdu.prettyPrint()) return v1Pdu
def returnResponsePdu(self, snmpEngine, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, PDU, maxSizeResponseScopedPDU, stateReference, statusInformation): # Extract input values and initialize defaults k = int(messageProcessingModel) if k in snmpEngine.messageProcessingSubsystems: mpHandler = snmpEngine.messageProcessingSubsystems[k] else: raise error.StatusInformation( errorIndication=errind.unsupportedMsgProcessingModel) debug.logger & debug.flagDsp and debug.logger( 'returnResponsePdu: PDU %s' % (PDU and PDU.prettyPrint() or "<empty>", )) # 4.1.2.2 try: (transportDomain, transportAddress, outgoingMessage) = mpHandler.prepareResponseMessage( snmpEngine, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, PDU, maxSizeResponseScopedPDU, stateReference, statusInformation) debug.logger & debug.flagDsp and debug.logger( 'returnResponsePdu: MP suceeded') except error.StatusInformation: # 4.1.2.3 raise # Handle oversized messages XXX transport constrains? snmpEngineMaxMessageSize, = self.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') if (snmpEngineMaxMessageSize.syntax and len(outgoingMessage) > snmpEngineMaxMessageSize.syntax): snmpSilentDrops, = self.mibInstrumController.mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpSilentDrops') snmpSilentDrops.syntax += 1 raise error.StatusInformation(errorIndication=errind.tooBig) snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc3412.returnResponsePdu', dict(transportDomain=transportDomain, transportAddress=transportAddress, outgoingMessage=outgoingMessage, messageProcessingModel=messageProcessingModel, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, pdu=PDU)) # 4.1.2.4 snmpEngine.transportDispatcher.sendMessage(outgoingMessage, transportDomain, transportAddress) snmpEngine.observer.clearExecutionContext(snmpEngine, 'rfc3412.returnResponsePdu')
# 7.2.8 pduVersion = api.protoVersion2c # 7.2.9 pduType = pdu.tagSet # 7.2.10 if rfc3411.responseClassPDUs.has_key(pduType) or \ rfc3411.internalClassPDUs.has_key(pduType): # 7.2.10a try: cachedReqParams = self._cachePopByMsgId(msgID) except error.ProtocolError: smHandler.releaseStateInformation(securityStateReference) raise error.StatusInformation(errorIndication='dataMismatch') # 7.2.10b sendPduHandle = cachedReqParams['sendPduHandle'] else: sendPduHandle = None debug.logger & debug.flagMP and debug.logger( 'prepareDataElements: using sendPduHandle %s for msgID %s' % (sendPduHandle, msgID)) # 7.2.11 if rfc3411.internalClassPDUs.has_key(pduType): # 7.2.11a varBinds = pMod.apiPDU.getVarBinds(pdu) if varBinds: statusInformation = error.StatusInformation(
def prepareResponseMessage(self, snmpEngine, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, maxSizeResponseScopedPDU, stateReference, statusInformation): snmpEngineID, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineID') snmpEngineID = snmpEngineID.syntax # 7.1.2.b cachedParams = self._cachePopByStateRef(stateReference) msgID = cachedParams['msgID'] contextEngineId = cachedParams['contextEngineId'] contextName = cachedParams['contextName'] securityModel = cachedParams['securityModel'] securityName = cachedParams['securityName'] securityLevel = cachedParams['securityLevel'] securityStateReference = cachedParams['securityStateReference'] reportableFlag = cachedParams['reportableFlag'] maxMessageSize = cachedParams['msgMaxSize'] transportDomain = cachedParams['transportDomain'] transportAddress = cachedParams['transportAddress'] debug.logger & debug.flagMP and debug.logger( 'prepareResponseMessage: stateReference %s' % (stateReference)) # 7.1.3 if statusInformation is not None and statusInformation.has_key('oid'): # 7.1.3a if pdu is not None: requestID = pdu.getComponentByPosition(0) pduType = pdu.tagSet else: pduType = None # 7.1.3b if pdu is None and not reportableFlag or \ pduType is not None and \ not rfc3411.confirmedClassPDUs.has_key(pduType): raise error.StatusInformation(errorIndication='loopTerminated') # 7.1.3c reportPDU = rfc1905.ReportPDU() pMod.apiPDU.setVarBinds( reportPDU, ((statusInformation['oid'], statusInformation['val']), )) pMod.apiPDU.setErrorStatus(reportPDU, 0) pMod.apiPDU.setErrorIndex(reportPDU, 0) if pdu is None: pMod.apiPDU.setRequestID(reportPDU, 0) else: pMod.apiPDU.setRequestID(reportPDU, requestID) # 7.1.3d.1 if statusInformation.has_key('securityLevel'): securityLevel = statusInformation['securityLevel'] else: securityLevel = 1 # 7.1.3d.2 if statusInformation.has_key('contextEngineId'): contextEngineId = statusInformation['contextEngineId'] else: contextEngineId = snmpEngineID # 7.1.3d.3 if statusInformation.has_key('contextName'): contextName = statusInformation['contextName'] else: contextName = "" # 7.1.3e pdu = reportPDU debug.logger & debug.flagMP and debug.logger( 'prepareResponseMessage: prepare report PDU for statusInformation %s' % statusInformation) # 7.1.4 if not contextEngineId: contextEngineId = snmpEngineID # XXX impl-dep manner # 7.1.5 if not contextName: contextName = '' debug.logger & debug.flagMP and debug.logger( 'prepareResponseMessage: using contextEngineId %s, contextName %s' % (contextEngineId, contextName)) # 7.1.6 scopedPDU = ScopedPDU() scopedPDU.setComponentByPosition(0, contextEngineId) scopedPDU.setComponentByPosition(1, contextName) scopedPDU.setComponentByPosition(2) scopedPDU.getComponentByPosition(2).setComponentByType(pdu.tagSet, pdu) # 7.1.7 msg = SNMPv3Message() # 7.1.7a msg.setComponentByPosition(0, 3) # version headerData = msg.setComponentByPosition(1).getComponentByPosition(1) # 7.1.7b headerData.setComponentByPosition(0, msgID) snmpEngineMaxMessageSize, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') # 7.1.7c # XXX need to coerce MIB value as it has incompatible constraints set headerData.setComponentByPosition(1, int(snmpEngineMaxMessageSize.syntax)) # 7.1.7d msgFlags = 0 if securityLevel == 1: pass elif securityLevel == 2: msgFlags = msgFlags | 0x01 elif securityLevel == 3: msgFlags = msgFlags | 0x03 else: raise error.ProtocolError('Unknown securityLevel %s' % securityLevel) if rfc3411.confirmedClassPDUs.has_key(pdu.tagSet): # XXX not needed? msgFlags = msgFlags | 0x04 headerData.setComponentByPosition(2, chr(msgFlags)) # 7.1.7e headerData.setComponentByPosition(3, securityModel) debug.logger & debug.flagMP and debug.logger( 'prepareResponseMessage: %s' % (msg.prettyPrint(), )) smHandler = snmpEngine.securityModels.get(securityModel) if smHandler is None: raise error.StatusInformation( errorIndication='unsupportedSecurityModel') # 7.1.8a try: (securityParameters, wholeMsg) = smHandler.generateResponseMsg( snmpEngine, self.messageProcessingModelID, msg, snmpEngineMaxMessageSize.syntax, securityModel, snmpEngineID, securityName, securityLevel, scopedPDU, securityStateReference) except error.StatusInformation, statusInformation: # 7.1.8.b raise
def prepareResponseMessage(self, snmpEngine, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, maxSizeResponseScopedPDU, stateReference, statusInformation): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder snmpEngineID, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') snmpEngineID = snmpEngineID.syntax # 7.1.2.b cachedParams = self._cache.popByStateRef(stateReference) msgID = cachedParams['msgID'] contextEngineId = cachedParams['contextEngineId'] contextName = cachedParams['contextName'] securityModel = cachedParams['securityModel'] securityName = cachedParams['securityName'] securityLevel = cachedParams['securityLevel'] securityStateReference = cachedParams['securityStateReference'] reportableFlag = cachedParams['reportableFlag'] maxMessageSize = cachedParams['msgMaxSize'] transportDomain = cachedParams['transportDomain'] transportAddress = cachedParams['transportAddress'] debug.logger & debug.FLAG_MP and debug.logger( 'prepareResponseMessage: stateReference %s' % stateReference) # 7.1.3 if statusInformation is not None and 'oid' in statusInformation: # 7.1.3a if pdu is None: pduType = None else: requestID = pdu.getComponentByPosition(0) pduType = pdu.tagSet # 7.1.3b if (pdu is None and not reportableFlag or pduType is not None and pduType not in rfc3411.CONFIRMED_CLASS_PDUS): raise error.StatusInformation( errorIndication=errind.loopTerminated) # 7.1.3c reportPDU = rfc1905.ReportPDU() pMod.apiPDU.setVarBinds( reportPDU, ((statusInformation['oid'], statusInformation['val']), )) pMod.apiPDU.setErrorStatus(reportPDU, 0) pMod.apiPDU.setErrorIndex(reportPDU, 0) if pdu is None: pMod.apiPDU.setRequestID(reportPDU, 0) else: # noinspection PyUnboundLocalVariable pMod.apiPDU.setRequestID(reportPDU, requestID) # 7.1.3d.1 if 'securityLevel' in statusInformation: securityLevel = statusInformation['securityLevel'] else: securityLevel = 1 # 7.1.3d.2 if 'contextEngineId' in statusInformation: contextEngineId = statusInformation['contextEngineId'] else: contextEngineId = snmpEngineID # 7.1.3d.3 if 'contextName' in statusInformation: contextName = statusInformation['contextName'] else: contextName = "" # 7.1.3e pdu = reportPDU debug.logger & debug.FLAG_MP and debug.logger( 'prepareResponseMessage: prepare report PDU for ' 'statusInformation %s' % statusInformation) # 7.1.4 if not contextEngineId: contextEngineId = snmpEngineID # XXX impl-dep manner # 7.1.5 if not contextName: contextName = self._emptyStr debug.logger & debug.FLAG_MP and debug.logger( 'prepareResponseMessage: using contextEngineId %r, contextName ' '%r' % (contextEngineId, contextName)) # 7.1.6 scopedPDU = self._scopedPDU scopedPDU.setComponentByPosition(0, contextEngineId) scopedPDU.setComponentByPosition(1, contextName) scopedPDU.setComponentByPosition(2) scopedPDU.getComponentByPosition(2).setComponentByType( pdu.tagSet, pdu, verifyConstraints=False, matchTags=False, matchConstraints=False) # 7.1.7 msg = self._snmpMsgSpec # 7.1.7a msg.setComponentByPosition(0, self.MESSAGE_PROCESSING_MODEL_ID, verifyConstraints=False, matchTags=False, matchConstraints=False) headerData = msg.setComponentByPosition(1).getComponentByPosition(1) # 7.1.7b headerData.setComponentByPosition(0, msgID, verifyConstraints=False, matchTags=False, matchConstraints=False) snmpEngineMaxMessageSize, = mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') # 7.1.7c # XXX need to coerce MIB value as it has incompatible constraints set headerData.setComponentByPosition(1, snmpEngineMaxMessageSize.syntax, verifyConstraints=False, matchTags=False, matchConstraints=False) # 7.1.7d msgFlags = 0 if securityLevel == 1: pass elif securityLevel == 2: msgFlags |= 0x01 elif securityLevel == 3: msgFlags |= 0x03 else: raise error.ProtocolError('Unknown securityLevel %s' % securityLevel) if pdu.tagSet in rfc3411.CONFIRMED_CLASS_PDUS: # XXX not needed? msgFlags |= 0x04 headerData.setComponentByPosition(2, self._msgFlags[msgFlags], verifyConstraints=False, matchTags=False, matchConstraints=False) # 7.1.7e headerData.setComponentByPosition(3, securityModel, verifyConstraints=False, matchTags=False, matchConstraints=False) debug.logger & debug.FLAG_MP and debug.logger( 'prepareResponseMessage: %s' % (msg.prettyPrint(), )) if securityModel in snmpEngine.securityModels: smHandler = snmpEngine.securityModels[securityModel] else: raise error.StatusInformation( errorIndication=errind.unsupportedSecurityModel) debug.logger & debug.FLAG_MP and debug.logger( 'prepareResponseMessage: securityModel %r, securityEngineId %r, ' 'securityName %r, securityLevel %r' % (securityModel, snmpEngineID, securityName, securityLevel)) # 7.1.8a try: securityParameters, wholeMsg = smHandler.generateResponseMsg( snmpEngine, self.MESSAGE_PROCESSING_MODEL_ID, msg, snmpEngineMaxMessageSize.syntax, securityModel, snmpEngineID, securityName, securityLevel, scopedPDU, securityStateReference) except error.StatusInformation: # 7.1.8.b raise debug.logger & debug.FLAG_MP and debug.logger( 'prepareResponseMessage: SM finished') # Message size constraint verification if len(wholeMsg) > min(snmpEngineMaxMessageSize.syntax, maxMessageSize): raise error.StatusInformation(errorIndication=errind.tooBig) snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc3412.prepareResponseMessage', dict(transportDomain=transportDomain, transportAddress=transportAddress, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, securityEngineId=snmpEngineID, pdu=pdu)) snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc3412.prepareResponseMessage') return transportDomain, transportAddress, wholeMsg
def prepareDataElements(self, snmpEngine, transportDomain, transportAddress, wholeMsg): # 7.2.2 msg, restOfwholeMsg = decoder.decode(wholeMsg, asn1Spec=self._snmpMsgSpec) debug.logger & debug.FLAG_MP and debug.logger( 'prepareDataElements: %s' % (msg.prettyPrint(), )) if eoo.endOfOctets.isSameTypeWith(msg): raise error.StatusInformation(errorIndication=errind.parseError) mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder # 7.2.3 headerData = msg.getComponentByPosition(1) msgVersion = messageProcessingModel = msg.getComponentByPosition(0) msgID = headerData.getComponentByPosition(0) msgFlags, = headerData.getComponentByPosition(2).asNumbers() maxMessageSize = headerData.getComponentByPosition(1) securityModel = headerData.getComponentByPosition(3) securityParameters = msg.getComponentByPosition(2) debug.logger & debug.FLAG_MP and debug.logger( 'prepareDataElements: msg data msgVersion %s msgID %s ' 'securityModel %s' % (msgVersion, msgID, securityModel)) # 7.2.4 if securityModel not in snmpEngine.securityModels: snmpUnknownSecurityModels, = mibBuilder.importSymbols( '__SNMP-MPD-MIB', 'snmpUnknownSecurityModels') snmpUnknownSecurityModels.syntax += 1 raise error.StatusInformation( errorIndication=errind.unsupportedSecurityModel) # 7.2.5 if msgFlags & 0x03 == 0x00: securityLevel = 1 elif (msgFlags & 0x03) == 0x01: securityLevel = 2 elif (msgFlags & 0x03) == 0x03: securityLevel = 3 else: snmpInvalidMsgs, = mibBuilder.importSymbols( '__SNMP-MPD-MIB', 'snmpInvalidMsgs') snmpInvalidMsgs.syntax += 1 raise error.StatusInformation(errorIndication=errind.invalidMsg) if msgFlags & 0x04: reportableFlag = 1 else: reportableFlag = 0 # 7.2.6 smHandler = snmpEngine.securityModels[securityModel] try: (securityEngineId, securityName, scopedPDU, maxSizeResponseScopedPDU, securityStateReference) = smHandler.processIncomingMsg( snmpEngine, messageProcessingModel, maxMessageSize, securityParameters, securityModel, securityLevel, wholeMsg, msg) debug.logger & debug.FLAG_MP and debug.logger( 'prepareDataElements: SM succeeded') except error.StatusInformation as exc: statusInformation = exc debug.logger & debug.FLAG_MP and debug.logger( 'prepareDataElements: SM failed, statusInformation ' '%s' % statusInformation) snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc3412.prepareDataElements:sm-failure', dict(transportDomain=transportDomain, transportAddress=transportAddress, securityModel=securityModel, securityLevel=securityLevel, securityParameters=securityParameters, statusInformation=statusInformation)) snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc3412.prepareDataElements:sm-failure') if 'errorIndication' in statusInformation: # 7.2.6a if 'oid' in statusInformation: # 7.2.6a1 securityStateReference = statusInformation[ 'securityStateReference'] contextEngineId = statusInformation['contextEngineId'] contextName = statusInformation['contextName'] if 'scopedPDU' in statusInformation: scopedPDU = statusInformation['scopedPDU'] pdu = scopedPDU.getComponentByPosition( 2).getComponent() else: pdu = None maxSizeResponseScopedPDU = statusInformation[ 'maxSizeResponseScopedPDU'] securityName = None # XXX secmod cache used # 7.2.6a2 stateReference = self._cache.newStateReference() self._cache.pushByStateRef( stateReference, msgVersion=messageProcessingModel, msgID=msgID, contextEngineId=contextEngineId, contextName=contextName, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, securityStateReference=securityStateReference, reportableFlag=reportableFlag, msgMaxSize=maxMessageSize, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU, transportDomain=transportDomain, transportAddress=transportAddress) # 7.2.6a3 try: snmpEngine.msgAndPduDsp.returnResponsePdu( snmpEngine, 3, securityModel, securityName, securityLevel, contextEngineId, contextName, 1, pdu, maxSizeResponseScopedPDU, stateReference, statusInformation) except error.StatusInformation: pass debug.logger & debug.FLAG_MP and debug.logger( 'prepareDataElements: error reported') # 7.2.6b if sys.version_info[0] <= 2: raise statusInformation else: origTraceback = sys.exc_info()[2] try: raise statusInformation.with_traceback(origTraceback) finally: # Break cycle between locals and traceback object # (seems to be irrelevant on Py3 but just in case) del origTraceback else: # Sniff for engineIdCache k = transportDomain, transportAddress if k not in self._engineIdCache: contextEngineId = scopedPDU[0] contextName = scopedPDU[1] pdus = scopedPDU[2] pdu = pdus.getComponent() # Here we assume that authentic/default EngineIDs # come only in the course of engine-to-engine communication. if pdu.tagSet in rfc3411.INTERNAL_CLASS_PDUS: self._engineIdCache[k] = { 'securityEngineId': securityEngineId, 'contextEngineId': contextEngineId, 'contextName': contextName } timerResolution = snmpEngine.transportDispatcher.getTimerResolution( ) expireAt = int(self._expirationTimer + 300 / timerResolution) if expireAt not in self._engineIdCacheExpQueue: self._engineIdCacheExpQueue[expireAt] = [] self._engineIdCacheExpQueue[expireAt].append(k) debug.logger & debug.FLAG_MP and debug.logger( 'prepareDataElements: cache securityEngineId %r for %r %r' % (securityEngineId, transportDomain, transportAddress)) snmpEngineID, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') snmpEngineID = snmpEngineID.syntax # 7.2.7 XXX PDU would be parsed here? contextEngineId = scopedPDU[0] contextName = scopedPDU[1] pdu = scopedPDU[2] pdu = pdu.getComponent() # PDUs # 7.2.8 pduVersion = api.SNMP_VERSION_2C # 7.2.9 pduType = pdu.tagSet # 7.2.10 if (pduType in rfc3411.RESPONSE_CLASS_PDUS or pduType in rfc3411.INTERNAL_CLASS_PDUS): # 7.2.10a try: cachedReqParams = self._cache.popByMsgId(msgID) except error.ProtocolError: smHandler.releaseStateInformation(securityStateReference) raise error.StatusInformation( errorIndication=errind.dataMismatch) # 7.2.10b sendPduHandle = cachedReqParams['sendPduHandle'] else: sendPduHandle = None debug.logger & debug.FLAG_MP and debug.logger( 'prepareDataElements: using sendPduHandle %s for msgID ' '%s' % (sendPduHandle, msgID)) # 7.2.11 if pduType in rfc3411.INTERNAL_CLASS_PDUS: # 7.2.11a varBinds = pMod.apiPDU.getVarBinds(pdu) if varBinds: errorIndication = _snmpErrors.get( varBinds[0][0], errind.ReportPduReceived(varBinds[0][0].prettyPrint())) statusInformation = error.StatusInformation( errorIndication=errorIndication, oid=varBinds[0][0], val=varBinds[0][1], sendPduHandle=sendPduHandle) else: statusInformation = error.StatusInformation( sendPduHandle=sendPduHandle) # 7.2.11b (incomplete implementation) snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc3412.prepareDataElements:internal', dict(transportDomain=transportDomain, transportAddress=transportAddress, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, securityEngineId=securityEngineId, pdu=pdu)) snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc3412.prepareDataElements:internal') # 7.2.11c smHandler.releaseStateInformation(securityStateReference) # 7.2.11d # no-op # 7.2.11e XXX may need to pass Reports up to app in some cases... raise statusInformation statusInformation = None # no errors ahead # 7.2.12 if pduType in rfc3411.RESPONSE_CLASS_PDUS: # 7.2.12a -> no-op # 7.2.12b # noinspection PyUnboundLocalVariable if (securityModel != cachedReqParams['securityModel'] or securityName != cachedReqParams['securityName'] or securityLevel != cachedReqParams['securityLevel'] or contextEngineId != cachedReqParams['contextEngineId'] or contextName != cachedReqParams['contextName']): smHandler.releaseStateInformation(securityStateReference) raise error.StatusInformation( errorIndication=errind.dataMismatch) snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc3412.prepareDataElements:response', dict(transportDomain=transportDomain, transportAddress=transportAddress, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, securityEngineId=securityEngineId, pdu=pdu)) snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc3412.prepareDataElements:response') # 7.2.12c smHandler.releaseStateInformation(securityStateReference) stateReference = None # 7.2.12d return (messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, pduType, sendPduHandle, maxSizeResponseScopedPDU, statusInformation, stateReference) # 7.2.13 if pduType in rfc3411.CONFIRMED_CLASS_PDUS: # 7.2.13a if securityEngineId != snmpEngineID: smHandler.releaseStateInformation(securityStateReference) raise error.StatusInformation( errorIndication=errind.engineIDMismatch) # 7.2.13b stateReference = self._cache.newStateReference() self._cache.pushByStateRef( stateReference, msgVersion=messageProcessingModel, msgID=msgID, contextEngineId=contextEngineId, contextName=contextName, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, securityStateReference=securityStateReference, reportableFlag=reportableFlag, msgMaxSize=maxMessageSize, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU, transportDomain=transportDomain, transportAddress=transportAddress) debug.logger & debug.FLAG_MP and debug.logger( 'prepareDataElements: new stateReference %s' % stateReference) snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc3412.prepareDataElements:confirmed', dict(transportDomain=transportDomain, transportAddress=transportAddress, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, securityEngineId=securityEngineId, pdu=pdu)) snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc3412.prepareDataElements:confirmed') # 7.2.13c return (messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, pduType, sendPduHandle, maxSizeResponseScopedPDU, statusInformation, stateReference) # 7.2.14 if pduType in rfc3411.UNCONFIRMED_CLASS_PDUS: # Pass new stateReference to let app browse request details stateReference = self._cache.newStateReference() snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc3412.prepareDataElements:unconfirmed', dict(transportDomain=transportDomain, transportAddress=transportAddress, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, securityEngineId=securityEngineId, pdu=pdu)) snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc3412.prepareDataElements:unconfirmed') # This is not specified explicitly in RFC smHandler.releaseStateInformation(securityStateReference) return (messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, pduType, sendPduHandle, maxSizeResponseScopedPDU, statusInformation, stateReference) smHandler.releaseStateInformation(securityStateReference) raise error.StatusInformation( errorIndication=errind.unsupportedPDUtype)
def prepareOutgoingMessage(self, snmpEngine, transportDomain, transportAddress, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, expectResponse, sendPduHandle): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder snmpEngineID, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') snmpEngineID = snmpEngineID.syntax # 7.1.1b msgID = self._cache.newMsgID() debug.logger & debug.FLAG_MP and debug.logger( 'prepareOutgoingMessage: new msgID %s' % msgID) k = transportDomain, transportAddress if k in self._engineIdCache: peerSnmpEngineData = self._engineIdCache[k] else: peerSnmpEngineData = None debug.logger & debug.FLAG_MP and debug.logger( 'prepareOutgoingMessage: peer SNMP engine data %s ' 'for transport %s, address ' '%s' % (peerSnmpEngineData, transportDomain, transportAddress)) # 7.1.4 if contextEngineId is None: if peerSnmpEngineData is None: contextEngineId = snmpEngineID else: contextEngineId = peerSnmpEngineData['contextEngineId'] # Defaulting contextEngineID to securityEngineId should # probably be done on Agent side (see 7.1.3.d.2,) so this # is a sort of workaround. if not contextEngineId: contextEngineId = peerSnmpEngineData['securityEngineId'] # 7.1.5 if not contextName: contextName = self._emptyStr debug.logger & debug.FLAG_MP and debug.logger( 'prepareOutgoingMessage: using contextEngineId %r, contextName ' '%r' % (contextEngineId, contextName)) # 7.1.6 scopedPDU = self._scopedPDU scopedPDU.setComponentByPosition(0, contextEngineId) scopedPDU.setComponentByPosition(1, contextName) scopedPDU.setComponentByPosition(2) scopedPDU.getComponentByPosition(2).setComponentByType( pdu.tagSet, pdu, verifyConstraints=False, matchTags=False, matchConstraints=False) # 7.1.7 msg = self._snmpMsgSpec # 7.1.7a msg.setComponentByPosition(0, self.MESSAGE_PROCESSING_MODEL_ID, verifyConstraints=False, matchTags=False, matchConstraints=False) headerData = msg.setComponentByPosition(1).getComponentByPosition(1) # 7.1.7b headerData.setComponentByPosition(0, msgID, verifyConstraints=False, matchTags=False, matchConstraints=False) snmpEngineMaxMessageSize, = mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') # 7.1.7c # XXX need to coerce MIB value as it has incompatible constraints set headerData.setComponentByPosition(1, snmpEngineMaxMessageSize.syntax, verifyConstraints=False, matchTags=False, matchConstraints=False) # 7.1.7d msgFlags = 0 if securityLevel == 1: pass elif securityLevel == 2: msgFlags |= 0x01 elif securityLevel == 3: msgFlags |= 0x03 else: raise error.ProtocolError('Unknown securityLevel %s' % securityLevel) if pdu.tagSet in rfc3411.CONFIRMED_CLASS_PDUS: msgFlags |= 0x04 headerData.setComponentByPosition(2, self._msgFlags[msgFlags], verifyConstraints=False, matchTags=False, matchConstraints=False) # 7.1.7e # XXX need to coerce MIB value as it has incompatible constraints set headerData.setComponentByPosition(3, int(securityModel)) debug.logger & debug.FLAG_MP and debug.logger( 'prepareOutgoingMessage: %s' % (msg.prettyPrint(), )) if securityModel in snmpEngine.securityModels: smHandler = snmpEngine.securityModels[securityModel] else: raise error.StatusInformation( errorIndication=errind.unsupportedSecurityModel) # 7.1.9.a if pdu.tagSet in rfc3411.UNCONFIRMED_CLASS_PDUS: securityEngineId = snmpEngineID else: if peerSnmpEngineData is None: # Force engineID discovery (rfc3414, 4) securityEngineId = securityName = self._emptyStr securityLevel = 1 # Clear possible auth&priv flags headerData.setComponentByPosition(2, self._msgFlags[msgFlags & 0xfc], verifyConstraints=False, matchTags=False, matchConstraints=False) # XXX scopedPDU = self._scopedPDU scopedPDU.setComponentByPosition(0, self._emptyStr, verifyConstraints=False, matchTags=False, matchConstraints=False) scopedPDU.setComponentByPosition(1, contextName) scopedPDU.setComponentByPosition(2) # Use dead-empty PDU for engine-discovery report emptyPdu = pdu.clone() pMod.apiPDU.setDefaults(emptyPdu) scopedPDU.getComponentByPosition(2).setComponentByType( emptyPdu.tagSet, emptyPdu, verifyConstraints=False, matchTags=False, matchConstraints=False) debug.logger & debug.FLAG_MP and debug.logger( 'prepareOutgoingMessage: force engineID discovery') else: securityEngineId = peerSnmpEngineData['securityEngineId'] debug.logger & debug.FLAG_MP and debug.logger( 'prepareOutgoingMessage: securityModel %r, securityEngineId %r, ' 'securityName %r, securityLevel ' '%r' % (securityModel, securityEngineId, securityName, securityLevel)) # 7.1.9.b securityParameters, wholeMsg = smHandler.generateRequestMsg( snmpEngine, self.MESSAGE_PROCESSING_MODEL_ID, msg, snmpEngineMaxMessageSize.syntax, securityModel, securityEngineId, securityName, securityLevel, scopedPDU) # Message size constraint verification if len(wholeMsg) > snmpEngineMaxMessageSize.syntax: raise error.StatusInformation(errorIndication=errind.tooBig) # 7.1.9.c if pdu.tagSet in rfc3411.CONFIRMED_CLASS_PDUS: # XXX rfc bug? why stateReference should be created? self._cache.pushByMsgId(msgID, sendPduHandle=sendPduHandle, msgID=msgID, snmpEngineID=snmpEngineID, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, transportDomain=transportDomain, transportAddress=transportAddress) snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc3412.prepareOutgoingMessage', dict(transportDomain=transportDomain, transportAddress=transportAddress, wholeMsg=wholeMsg, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, pdu=pdu)) snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc3412.prepareOutgoingMessage') return transportDomain, transportAddress, wholeMsg
def authenticateIncomingMsg(self, authKey, authParameters, wholeMsg): raise error.StatusInformation(errorIndication=errind.noAuthentication)
def authenticateOutgoingMsg(self, authKey, wholeMsg): raise error.StatusInformation(errorIndication=errind.noAuthentication)
def prepareOutgoingMessage( self, snmpEngine, transportDomain, transportAddress, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, expectResponse, sendPduHandle ): snmpEngineID, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') snmpEngineID = snmpEngineID.syntax # rfc3412: 7.1.1b if rfc3411.confirmedClassPDUs.has_key(pdu.tagSet): pdu.setComponentByPosition(1) msgID = pdu.getComponentByPosition(0) # rfc3412: 7.1.4 # Since there's no SNMP engine identification in v1/2c, # set destination contextEngineId to ours if not contextEngineId: contextEngineId = snmpEngineID # rfc3412: 7.1.5 if not contextName: contextName = '' debug.logger & debug.flagMP and debug.logger('prepareOutgoingMessage: using contextEngineId %s contextName %s' % (contextEngineId, contextName)) # rfc3412: 7.1.6 scopedPDU = ( contextEngineId, contextName, pdu ) msg = self._snmpMsgSpec.clone() msg.setComponentByPosition(0, self.messageProcessingModelID) msg.setComponentByPosition(2) msg.getComponentByPosition(2).setComponentByType(pdu.tagSet, pdu) # rfc3412: 7.1.7 globalData = ( msg, ) smHandler = snmpEngine.securityModels.get(int(securityModel)) if smHandler is None: raise error.StatusInformation( errorIndication = 'unsupportedSecurityModel' ) # rfc3412: 7.1.9.a & rfc2576: 5.2.1 --> no-op snmpEngineMaxMessageSize, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') # rfc3412: 7.1.9.b ( securityParameters, wholeMsg ) = smHandler.generateRequestMsg( snmpEngine, self.messageProcessingModelID, globalData, snmpEngineMaxMessageSize.syntax, securityModel, snmpEngineID, securityName, securityLevel, scopedPDU ) # rfc3412: 7.1.9.c if rfc3411.confirmedClassPDUs.has_key(pdu.tagSet): # XXX rfc bug? why stateReference should be created? self._cachePushByMsgId( long(msgID), sendPduHandle=sendPduHandle, msgID=msgID, snmpEngineID=snmpEngineID, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, transportDomain=transportDomain, transportAddress=transportAddress ) return ( transportDomain, transportAddress, wholeMsg )
def prepareDataElements(self, snmpEngine, transportDomain, transportAddress, wholeMsg): # 7.2.2 try: msg, restOfwholeMsg = decoder.decode(wholeMsg, asn1Spec=self._snmpMsgSpec) except PyAsn1Error: snmpInASNParseErrs, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpInASNParseErrs') snmpInASNParseErrs.syntax = snmpInASNParseErrs.syntax + 1 raise error.StatusInformation(errorIndication='parseError') debug.logger & debug.flagMP and debug.logger( 'prepareDataElements: %s' % (msg.prettyPrint(), )) # 7.2.3 headerData = msg.getComponentByPosition(1) msgVersion = messageProcessingModel = msg.getComponentByPosition(0) msgID = headerData.getComponentByPosition(0) msgFlags = ord(str(headerData.getComponentByPosition(2))) maxMessageSize = headerData.getComponentByPosition(1) securityModel = headerData.getComponentByPosition(3) securityParameters = msg.getComponentByPosition(2) debug.logger & debug.flagMP and debug.logger( 'prepareDataElements: msg data msgVersion %s msgID %s securityModel %s' % (msgVersion, msgID, securityModel)) # 7.2.4 if not snmpEngine.securityModels.has_key(securityModel): snmpUnknownSecurityModels, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpUnknownSecurityModels') snmpUnknownSecurityModels.syntax = snmpUnknownSecurityModels.syntax + 1 raise error.StatusInformation( errorIndication='unsupportedSecurityModel') # 7.2.5 if msgFlags & 0x03 == 0x00: securityLevel = 1 elif (msgFlags & 0x03) == 0x01: securityLevel = 2 elif (msgFlags & 0x03) == 0x03: securityLevel = 3 else: snmpInvalidMsgs = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpInvalidMsgs') snmpInvalidMsgs.syntax = snmpInvalidMsgs.syntax + 1 raise error.StatusInformation(errorIndication='invalidMsg') if msgFlags & 0x04: reportableFlag = 1 else: reportableFlag = 0 # 7.2.6 smHandler = snmpEngine.securityModels[securityModel] try: (securityEngineID, securityName, scopedPDU, maxSizeResponseScopedPDU, securityStateReference) = smHandler.processIncomingMsg( snmpEngine, messageProcessingModel, maxMessageSize, securityParameters, securityModel, securityLevel, wholeMsg, msg) debug.logger & debug.flagMP and debug.logger( 'prepareDataElements: SM succeeded') except error.StatusInformation, statusInformation: debug.logger & debug.flagMP and debug.logger( 'prepareDataElements: SM failed, statusInformation %s' % statusInformation) if statusInformation.has_key('errorIndication'): # 7.2.6a if statusInformation.has_key('oid'): # 7.2.6a1 securityStateReference = statusInformation[ 'securityStateReference'] contextEngineId = statusInformation['contextEngineId'] contextName = statusInformation['contextName'] scopedPDU = statusInformation.get('scopedPDU') if scopedPDU is not None: pdu = scopedPDU.getComponentByPosition( 2).getComponent() else: pdu = None maxSizeResponseScopedPDU = statusInformation[ 'maxSizeResponseScopedPDU'] securityName = None # XXX secmod cache used # 7.2.6a2 stateReference = self._newStateReference() self._cachePushByStateRef( stateReference, msgVersion=messageProcessingModel, msgID=msgID, contextEngineId=contextEngineId, contextName=contextName, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, securityStateReference=securityStateReference, reportableFlag=reportableFlag, msgMaxSize=maxMessageSize, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU, transportDomain=transportDomain, transportAddress=transportAddress) # 7.2.6a3 try: snmpEngine.msgAndPduDsp.returnResponsePdu( snmpEngine, 3, securityModel, securityName, securityLevel, contextEngineId, contextName, 1, pdu, maxSizeResponseScopedPDU, stateReference, statusInformation) except error.StatusInformation: pass debug.logger & debug.flagMP and debug.logger( 'prepareDataElements: error reported') # 7.2.6b raise statusInformation
def prepareDataElements( self, snmpEngine, transportDomain, transportAddress, wholeMsg ): # rfc3412: 7.2.2 try: msg, restOfwholeMsg = decoder.decode( wholeMsg, asn1Spec=self._snmpMsgSpec ) except PyAsn1Error: snmpInASNParseErrs, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMPv2-MIB', 'snmpInASNParseErrs') snmpInASNParseErrs.syntax = snmpInASNParseErrs.syntax + 1 raise error.StatusInformation( errorIndication = 'parseError' ) debug.logger & debug.flagMP and debug.logger('prepareDataElements: msg decoded') # rfc3412: 7.2.3 msgVersion = messageProcessingModel = msg.getComponentByPosition(0) pdu = msg.getComponentByPosition(2).getComponent() # (wild hack: use PDU reqID at MsgID) msgID = pdu.getComponentByPosition(0) # rfc2576: 5.2.1 snmpEngineMaxMessageSize, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') securityParameters = ( msg.getComponentByPosition(1), (transportDomain, transportAddress), ('0.0.0.0', 0) # XXX ) messageProcessingModel = int(msg.getComponentByPosition(0)) securityModel = messageProcessingModel + 1 securityLevel = 1 # rfc3412: 7.2.4 -- 7.2.5 -> noop smHandler = snmpEngine.securityModels.get(int(securityModel)) if smHandler is None: raise error.StatusInformation( errorIndication = 'unsupportedSecurityModel' ) # rfc3412: 7.2.6 ( securityEngineID, securityName, scopedPDU, maxSizeResponseScopedPDU, securityStateReference ) = smHandler.processIncomingMsg( snmpEngine, messageProcessingModel, snmpEngineMaxMessageSize.syntax, securityParameters, securityModel, securityLevel, wholeMsg, msg ) debug.logger & debug.flagMP and debug.logger('prepareDataElements: SM returned securityEngineID %s securityName %s' % (securityEngineID, securityName)) # rfc3412: 7.2.6a --> noop # rfc3412: 7.2.7 contextEngineId, contextName, pdu = scopedPDU # rfc2576: 5.2.1 pduVersion = msgVersion pduType = pdu.tagSet # XXX use cache # set stateref to null as in v3 model stateReference = securityStateReference # rfc3412: 7.2.8, 7.2.9 -> noop # rfc3412: 7.2.10 if rfc3411.responseClassPDUs.has_key(pduType): # 7.2.10a try: cachedReqParams = self._cachePopByMsgId(long(msgID)) except error.ProtocolError: smHandler.releaseStateInformation(securityStateReference) raise error.StatusInformation( errorIndication = 'dataMismatch' ) # 7.2.10b sendPduHandle = cachedReqParams['sendPduHandle'] else: sendPduHandle = None statusInformation = None # rfc3412: 7.2.11 -> noop # rfc3412: 7.2.12 if rfc3411.responseClassPDUs.has_key(pduType): # rfc3412: 7.2.12a -> noop # rfc3412: 7.2.12b if securityModel != cachedReqParams['securityModel'] or \ securityName != cachedReqParams['securityName'] or \ securityLevel != cachedReqParams['securityLevel'] or \ contextEngineId != cachedReqParams['contextEngineId'] or \ contextName != cachedReqParams['contextName']: smHandler.releaseStateInformation(securityStateReference) raise error.StatusInformation( errorIndication = 'dataMismatch' ) # rfc3412: 7.2.12c smHandler.releaseStateInformation(securityStateReference) # rfc3412: 7.2.12d return ( messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, pduType, sendPduHandle, maxSizeResponseScopedPDU, statusInformation, stateReference ) # rfc3412: 7.2.13 if rfc3411.confirmedClassPDUs.has_key(pduType): # rfc3412: 7.2.13a snmpEngineID, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') if securityEngineID != snmpEngineID.syntax: smHandler.releaseStateInformation(securityStateReference) raise error.StatusInformation( errorIndication = 'engineIDMispatch' ) # rfc3412: 7.2.13b stateReference = self._newStateReference() self._cachePushByStateRef( stateReference, msgVersion=messageProcessingModel, msgID=msgID, contextEngineId=contextEngineId, contextName=contextName, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, securityStateReference=securityStateReference, msgMaxSize=snmpEngineMaxMessageSize.syntax, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU, transportDomain=transportDomain, transportAddress=transportAddress ) debug.logger & debug.flagMP and debug.logger('prepareDataElements: cached by new stateReference %s' % stateReference) # rfc3412: 7.2.13c return ( messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, pduType, sendPduHandle, maxSizeResponseScopedPDU, statusInformation, stateReference ) # rfc3412: 7.2.14 if rfc3411.unconfirmedClassPDUs.has_key(pduType): # This is not specified explicitly in RFC smHandler.releaseStateInformation(securityStateReference) return ( messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, pduType, sendPduHandle, maxSizeResponseScopedPDU, statusInformation, stateReference ) smHandler.releaseStateInformation(securityStateReference) raise error.StatusInformation( errorIndication = 'unsupportedPDUtype' )
class SnmpV3MessageProcessingModel(AbstractMessageProcessingModel): messageProcessingModelID = 3 # SNMPv3 _snmpMsgSpec = SNMPv3Message() def __init__(self): AbstractMessageProcessingModel.__init__(self) self.__engineIDs = {} self.__engineIDsExpQueue = {} self.__expirationTimer = 0L # 7.1.1a def prepareOutgoingMessage(self, snmpEngine, transportDomain, transportAddress, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, expectResponse, sendPduHandle): snmpEngineID, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineID') snmpEngineID = snmpEngineID.syntax # 7.1.1b msgID = self._newMsgID() debug.logger & debug.flagMP and debug.logger( 'prepareOutgoingMessage: new msgID %s' % msgID) peerSnmpEngineData = self.__engineIDs.get( (transportDomain, transportAddress)) debug.logger & debug.flagMP and debug.logger( 'prepareOutgoingMessage: peer SNMP engine data %s for transport %s, address %s' % (peerSnmpEngineData, transportDomain, transportAddress)) # 7.1.4 if contextEngineId is None: if peerSnmpEngineData is None: contextEngineId = snmpEngineID else: contextEngineId = peerSnmpEngineData['contextEngineId'] # Defaulting contextEngineID to securityEngineID should # probably be done on Agent side (see 7.1.3.d.2,) so this # is a sort of workaround. if not contextEngineId: contextEngineId = peerSnmpEngineData['securityEngineID'] # 7.1.5 if not contextName: contextName = '' debug.logger & debug.flagMP and debug.logger( 'prepareOutgoingMessage: using contextEngineId %s, contextName %s' % (contextEngineId, contextName)) # 7.1.6 scopedPDU = ScopedPDU() scopedPDU.setComponentByPosition(0, contextEngineId) scopedPDU.setComponentByPosition(1, contextName) scopedPDU.setComponentByPosition(2) scopedPDU.getComponentByPosition(2).setComponentByType(pdu.tagSet, pdu) # 7.1.7 msg = SNMPv3Message() # 7.1.7a msg.setComponentByPosition(0, 3) # version headerData = msg.setComponentByPosition(1).getComponentByPosition(1) # 7.1.7b headerData.setComponentByPosition(0, msgID) snmpEngineMaxMessageSize, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') # 7.1.7c # XXX need to coerce MIB value as it has incompatible constraints set headerData.setComponentByPosition(1, int(snmpEngineMaxMessageSize.syntax)) # 7.1.7d msgFlags = 0 if securityLevel == 1: pass elif securityLevel == 2: msgFlags = msgFlags | 0x01 elif securityLevel == 3: msgFlags = msgFlags | 0x03 else: raise error.ProtocolError('Unknown securityLevel %s' % securityLevel) if rfc3411.confirmedClassPDUs.has_key(pdu.tagSet): msgFlags = msgFlags | 0x04 headerData.setComponentByPosition(2, chr(msgFlags)) # 7.1.7e # XXX need to coerce MIB value as it has incompatible constraints set headerData.setComponentByPosition(3, int(securityModel)) debug.logger & debug.flagMP and debug.logger( 'prepareOutgoingMessage: %s' % (msg.prettyPrint(), )) smHandler = snmpEngine.securityModels.get(securityModel) if smHandler is None: raise error.StatusInformation( errorIndication='unsupportedSecurityModel') # 7.1.9.a if rfc3411.unconfirmedClassPDUs.has_key(pdu.tagSet): securityEngineID = snmpEngineID else: if peerSnmpEngineData is None: # Force engineID discovery (rfc3414, 4) securityEngineID = securityName = '' securityLevel = 1 # Clear possible auth&priv flags headerData.setComponentByPosition(2, chr(msgFlags & 0xfc)) # XXX scopedPDU = ScopedPDU() scopedPDU.setComponentByPosition(0, '') scopedPDU.setComponentByPosition(1, '') scopedPDU.setComponentByPosition(2) # Use dead-empty PDU for engine-discovery report emptyPdu = pdu.clone() pMod.apiPDU.setDefaults(emptyPdu) scopedPDU.getComponentByPosition(2).setComponentByType( emptyPdu.tagSet, emptyPdu) debug.logger & debug.flagMP and debug.logger( 'prepareOutgoingMessage: force engineID discovery') else: securityEngineID = peerSnmpEngineData['securityEngineID'] debug.logger & debug.flagMP and debug.logger( 'prepareOutgoingMessage: securityEngineID %s' % securityEngineID) # 7.1.9.b (securityParameters, wholeMsg) = smHandler.generateRequestMsg( snmpEngine, self.messageProcessingModelID, msg, snmpEngineMaxMessageSize.syntax, securityModel, securityEngineID, securityName, securityLevel, scopedPDU) # Message size constraint verification if len(wholeMsg) > snmpEngineMaxMessageSize.syntax: raise error.StatusInformation(errorIndication='tooBig') # 7.1.9.c if rfc3411.confirmedClassPDUs.has_key(pdu.tagSet): # XXX rfc bug? why stateReference should be created? self._cachePushByMsgId(msgID, sendPduHandle=sendPduHandle, msgID=msgID, snmpEngineID=snmpEngineID, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, transportDomain=transportDomain, transportAddress=transportAddress) return (transportDomain, transportAddress, wholeMsg) def prepareResponseMessage(self, snmpEngine, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, maxSizeResponseScopedPDU, stateReference, statusInformation): snmpEngineID, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineID') snmpEngineID = snmpEngineID.syntax # 7.1.2.b cachedParams = self._cachePopByStateRef(stateReference) msgID = cachedParams['msgID'] contextEngineId = cachedParams['contextEngineId'] contextName = cachedParams['contextName'] securityModel = cachedParams['securityModel'] securityName = cachedParams['securityName'] securityLevel = cachedParams['securityLevel'] securityStateReference = cachedParams['securityStateReference'] reportableFlag = cachedParams['reportableFlag'] maxMessageSize = cachedParams['msgMaxSize'] transportDomain = cachedParams['transportDomain'] transportAddress = cachedParams['transportAddress'] debug.logger & debug.flagMP and debug.logger( 'prepareResponseMessage: stateReference %s' % (stateReference)) # 7.1.3 if statusInformation is not None and statusInformation.has_key('oid'): # 7.1.3a if pdu is not None: requestID = pdu.getComponentByPosition(0) pduType = pdu.tagSet else: pduType = None # 7.1.3b if pdu is None and not reportableFlag or \ pduType is not None and \ not rfc3411.confirmedClassPDUs.has_key(pduType): raise error.StatusInformation(errorIndication='loopTerminated') # 7.1.3c reportPDU = rfc1905.ReportPDU() pMod.apiPDU.setVarBinds( reportPDU, ((statusInformation['oid'], statusInformation['val']), )) pMod.apiPDU.setErrorStatus(reportPDU, 0) pMod.apiPDU.setErrorIndex(reportPDU, 0) if pdu is None: pMod.apiPDU.setRequestID(reportPDU, 0) else: pMod.apiPDU.setRequestID(reportPDU, requestID) # 7.1.3d.1 if statusInformation.has_key('securityLevel'): securityLevel = statusInformation['securityLevel'] else: securityLevel = 1 # 7.1.3d.2 if statusInformation.has_key('contextEngineId'): contextEngineId = statusInformation['contextEngineId'] else: contextEngineId = snmpEngineID # 7.1.3d.3 if statusInformation.has_key('contextName'): contextName = statusInformation['contextName'] else: contextName = "" # 7.1.3e pdu = reportPDU debug.logger & debug.flagMP and debug.logger( 'prepareResponseMessage: prepare report PDU for statusInformation %s' % statusInformation) # 7.1.4 if not contextEngineId: contextEngineId = snmpEngineID # XXX impl-dep manner # 7.1.5 if not contextName: contextName = '' debug.logger & debug.flagMP and debug.logger( 'prepareResponseMessage: using contextEngineId %s, contextName %s' % (contextEngineId, contextName)) # 7.1.6 scopedPDU = ScopedPDU() scopedPDU.setComponentByPosition(0, contextEngineId) scopedPDU.setComponentByPosition(1, contextName) scopedPDU.setComponentByPosition(2) scopedPDU.getComponentByPosition(2).setComponentByType(pdu.tagSet, pdu) # 7.1.7 msg = SNMPv3Message() # 7.1.7a msg.setComponentByPosition(0, 3) # version headerData = msg.setComponentByPosition(1).getComponentByPosition(1) # 7.1.7b headerData.setComponentByPosition(0, msgID) snmpEngineMaxMessageSize, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') # 7.1.7c # XXX need to coerce MIB value as it has incompatible constraints set headerData.setComponentByPosition(1, int(snmpEngineMaxMessageSize.syntax)) # 7.1.7d msgFlags = 0 if securityLevel == 1: pass elif securityLevel == 2: msgFlags = msgFlags | 0x01 elif securityLevel == 3: msgFlags = msgFlags | 0x03 else: raise error.ProtocolError('Unknown securityLevel %s' % securityLevel) if rfc3411.confirmedClassPDUs.has_key(pdu.tagSet): # XXX not needed? msgFlags = msgFlags | 0x04 headerData.setComponentByPosition(2, chr(msgFlags)) # 7.1.7e headerData.setComponentByPosition(3, securityModel) debug.logger & debug.flagMP and debug.logger( 'prepareResponseMessage: %s' % (msg.prettyPrint(), )) smHandler = snmpEngine.securityModels.get(securityModel) if smHandler is None: raise error.StatusInformation( errorIndication='unsupportedSecurityModel') # 7.1.8a try: (securityParameters, wholeMsg) = smHandler.generateResponseMsg( snmpEngine, self.messageProcessingModelID, msg, snmpEngineMaxMessageSize.syntax, securityModel, snmpEngineID, securityName, securityLevel, scopedPDU, securityStateReference) except error.StatusInformation, statusInformation: # 7.1.8.b raise debug.logger & debug.flagMP and debug.logger( 'prepareResponseMessage: SM finished') # Message size constraint verification if len(wholeMsg) > min(snmpEngineMaxMessageSize.syntax, maxMessageSize): raise error.StatusInformation(errorIndication='tooBig') return (transportDomain, transportAddress, wholeMsg)
def sendPdu(self, snmpEngine, transportDomain, transportAddress, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, PDU, expectResponse, timeout=0, cbFun=None, cbCtx=None): """PDU dispatcher -- prepare and serialize a request or notification""" # 4.1.1.2 k = int(messageProcessingModel) if k in snmpEngine.messageProcessingSubsystems: mpHandler = snmpEngine.messageProcessingSubsystems[k] else: raise error.StatusInformation( errorIndication=errind.unsupportedMsgProcessingModel) debug.logger & debug.flagDsp and debug.logger( 'sendPdu: securityName %s, PDU\n%s' % (securityName, PDU.prettyPrint())) # 4.1.1.3 sendPduHandle = self.__sendPduHandle() if expectResponse: self.__cache.add(sendPduHandle, messageProcessingModel=messageProcessingModel, sendPduHandle=sendPduHandle, timeout=timeout + snmpEngine.transportDispatcher.getTimerTicks(), cbFun=cbFun, cbCtx=cbCtx) debug.logger & debug.flagDsp and debug.logger( 'sendPdu: current time %d ticks, one tick is %s seconds' % (snmpEngine.transportDispatcher.getTimerTicks(), snmpEngine.transportDispatcher.getTimerResolution())) debug.logger & debug.flagDsp and debug.logger( 'sendPdu: new sendPduHandle %s, timeout %s ticks, cbFun %s' % (sendPduHandle, timeout, cbFun)) origTransportDomain = transportDomain origTransportAddress = transportAddress # 4.1.1.4 & 4.1.1.5 try: (transportDomain, transportAddress, outgoingMessage) = mpHandler.prepareOutgoingMessage( snmpEngine, origTransportDomain, origTransportAddress, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, PDU, expectResponse, sendPduHandle) debug.logger & debug.flagDsp and debug.logger( 'sendPdu: MP succeeded') except PySnmpError: if expectResponse: self.__cache.pop(sendPduHandle) self.releaseStateInformation(snmpEngine, sendPduHandle, messageProcessingModel) raise # 4.1.1.6 if snmpEngine.transportDispatcher is None: if expectResponse: self.__cache.pop(sendPduHandle) raise error.PySnmpError('Transport dispatcher not set') snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc3412.sendPdu', dict(transportDomain=transportDomain, transportAddress=transportAddress, outgoingMessage=outgoingMessage, messageProcessingModel=messageProcessingModel, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, pdu=PDU)) try: snmpEngine.transportDispatcher.sendMessage(outgoingMessage, transportDomain, transportAddress) except PySnmpError: if expectResponse: self.__cache.pop(sendPduHandle) raise snmpEngine.observer.clearExecutionContext(snmpEngine, 'rfc3412.sendPdu') # Update cache with orignal req params (used for retrying) if expectResponse: self.__cache.update(sendPduHandle, transportDomain=origTransportDomain, transportAddress=origTransportAddress, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, pduVersion=pduVersion, PDU=PDU) return sendPduHandle
def prepareOutgoingMessage(self, snmpEngine, transportDomain, transportAddress, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, expectResponse, sendPduHandle): snmpEngineID, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineID') snmpEngineID = snmpEngineID.syntax # 7.1.1b msgID = self._newMsgID() debug.logger & debug.flagMP and debug.logger( 'prepareOutgoingMessage: new msgID %s' % msgID) peerSnmpEngineData = self.__engineIDs.get( (transportDomain, transportAddress)) debug.logger & debug.flagMP and debug.logger( 'prepareOutgoingMessage: peer SNMP engine data %s for transport %s, address %s' % (peerSnmpEngineData, transportDomain, transportAddress)) # 7.1.4 if contextEngineId is None: if peerSnmpEngineData is None: contextEngineId = snmpEngineID else: contextEngineId = peerSnmpEngineData['contextEngineId'] # Defaulting contextEngineID to securityEngineID should # probably be done on Agent side (see 7.1.3.d.2,) so this # is a sort of workaround. if not contextEngineId: contextEngineId = peerSnmpEngineData['securityEngineID'] # 7.1.5 if not contextName: contextName = '' debug.logger & debug.flagMP and debug.logger( 'prepareOutgoingMessage: using contextEngineId %s, contextName %s' % (contextEngineId, contextName)) # 7.1.6 scopedPDU = ScopedPDU() scopedPDU.setComponentByPosition(0, contextEngineId) scopedPDU.setComponentByPosition(1, contextName) scopedPDU.setComponentByPosition(2) scopedPDU.getComponentByPosition(2).setComponentByType(pdu.tagSet, pdu) # 7.1.7 msg = SNMPv3Message() # 7.1.7a msg.setComponentByPosition(0, 3) # version headerData = msg.setComponentByPosition(1).getComponentByPosition(1) # 7.1.7b headerData.setComponentByPosition(0, msgID) snmpEngineMaxMessageSize, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') # 7.1.7c # XXX need to coerce MIB value as it has incompatible constraints set headerData.setComponentByPosition(1, int(snmpEngineMaxMessageSize.syntax)) # 7.1.7d msgFlags = 0 if securityLevel == 1: pass elif securityLevel == 2: msgFlags = msgFlags | 0x01 elif securityLevel == 3: msgFlags = msgFlags | 0x03 else: raise error.ProtocolError('Unknown securityLevel %s' % securityLevel) if rfc3411.confirmedClassPDUs.has_key(pdu.tagSet): msgFlags = msgFlags | 0x04 headerData.setComponentByPosition(2, chr(msgFlags)) # 7.1.7e # XXX need to coerce MIB value as it has incompatible constraints set headerData.setComponentByPosition(3, int(securityModel)) debug.logger & debug.flagMP and debug.logger( 'prepareOutgoingMessage: %s' % (msg.prettyPrint(), )) smHandler = snmpEngine.securityModels.get(securityModel) if smHandler is None: raise error.StatusInformation( errorIndication='unsupportedSecurityModel') # 7.1.9.a if rfc3411.unconfirmedClassPDUs.has_key(pdu.tagSet): securityEngineID = snmpEngineID else: if peerSnmpEngineData is None: # Force engineID discovery (rfc3414, 4) securityEngineID = securityName = '' securityLevel = 1 # Clear possible auth&priv flags headerData.setComponentByPosition(2, chr(msgFlags & 0xfc)) # XXX scopedPDU = ScopedPDU() scopedPDU.setComponentByPosition(0, '') scopedPDU.setComponentByPosition(1, '') scopedPDU.setComponentByPosition(2) # Use dead-empty PDU for engine-discovery report emptyPdu = pdu.clone() pMod.apiPDU.setDefaults(emptyPdu) scopedPDU.getComponentByPosition(2).setComponentByType( emptyPdu.tagSet, emptyPdu) debug.logger & debug.flagMP and debug.logger( 'prepareOutgoingMessage: force engineID discovery') else: securityEngineID = peerSnmpEngineData['securityEngineID'] debug.logger & debug.flagMP and debug.logger( 'prepareOutgoingMessage: securityEngineID %s' % securityEngineID) # 7.1.9.b (securityParameters, wholeMsg) = smHandler.generateRequestMsg( snmpEngine, self.messageProcessingModelID, msg, snmpEngineMaxMessageSize.syntax, securityModel, securityEngineID, securityName, securityLevel, scopedPDU) # Message size constraint verification if len(wholeMsg) > snmpEngineMaxMessageSize.syntax: raise error.StatusInformation(errorIndication='tooBig') # 7.1.9.c if rfc3411.confirmedClassPDUs.has_key(pdu.tagSet): # XXX rfc bug? why stateReference should be created? self._cachePushByMsgId(msgID, sendPduHandle=sendPduHandle, msgID=msgID, snmpEngineID=snmpEngineID, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, transportDomain=transportDomain, transportAddress=transportAddress) return (transportDomain, transportAddress, wholeMsg)
def isAccessAllowed(self, snmpEngine, securityModel, securityName, securityLevel, viewType, contextName, variableName): mibInstrumController = snmpEngine.msgAndPduDsp.mibInstrumController debug.logger & debug.flagACL and debug.logger( 'isAccessAllowed: securityModel %s, securityName %s, securityLevel %s, viewType %s, contextName %s for variableName %s' % (securityModel, securityName, securityLevel, viewType, contextName, variableName)) # 3.2.1 vacmContextEntry, = mibInstrumController.mibBuilder.importSymbols( 'SNMP-VIEW-BASED-ACM-MIB', 'vacmContextEntry') tblIdx = vacmContextEntry.getInstIdFromIndices(contextName) try: vacmContextName = vacmContextEntry.getNode(vacmContextEntry.name + (1, ) + tblIdx).syntax except NoSuchInstanceError: raise error.StatusInformation(errorIndication=errind.noSuchContext) # 3.2.2 vacmSecurityToGroupEntry, = mibInstrumController.mibBuilder.importSymbols( 'SNMP-VIEW-BASED-ACM-MIB', 'vacmSecurityToGroupEntry') tblIdx = vacmSecurityToGroupEntry.getInstIdFromIndices( securityModel, securityName) try: vacmGroupName = vacmSecurityToGroupEntry.getNode( vacmSecurityToGroupEntry.name + (3, ) + tblIdx).syntax except NoSuchInstanceError: raise error.StatusInformation(errorIndication=errind.noGroupName) # 3.2.3 vacmAccessEntry, = mibInstrumController.mibBuilder.importSymbols( 'SNMP-VIEW-BASED-ACM-MIB', 'vacmAccessEntry') # XXX partial context name match tblIdx = vacmAccessEntry.getInstIdFromIndices(vacmGroupName, contextName, securityModel, securityLevel) # 3.2.4 if viewType == 'read': entryIdx = vacmAccessEntry.name + (5, ) + tblIdx elif viewType == 'write': entryIdx = vacmAccessEntry.name + (6, ) + tblIdx elif viewType == 'notify': entryIdx = vacmAccessEntry.name + (7, ) + tblIdx else: raise error.ProtocolError('Unknown view type %s' % viewType) try: viewName = vacmAccessEntry.getNode(entryIdx).syntax except NoSuchInstanceError: raise error.StatusInformation(errorIndication=errind.noAccessEntry) if not len(viewName): raise error.StatusInformation(errorIndication=errind.noSuchView) # XXX split onto object & instance ? # 3.2.5a vacmViewTreeFamilyEntry, = mibInstrumController.mibBuilder.importSymbols( 'SNMP-VIEW-BASED-ACM-MIB', 'vacmViewTreeFamilyEntry') tblIdx = vacmViewTreeFamilyEntry.getInstIdFromIndices(viewName) # Walk over entries initialTreeName = treeName = vacmViewTreeFamilyEntry.name + ( 2, ) + tblIdx maskName = vacmViewTreeFamilyEntry.name + (3, ) + tblIdx while 1: vacmViewTreeFamilySubtree = vacmViewTreeFamilyEntry.getNextNode( treeName) vacmViewTreeFamilyMask = vacmViewTreeFamilyEntry.getNextNode( maskName) treeName = vacmViewTreeFamilySubtree.name maskName = vacmViewTreeFamilyMask.name if initialTreeName != treeName[:len(initialTreeName)]: # 3.2.5b raise error.StatusInformation(errorIndication=errind.notInView) l = len(vacmViewTreeFamilySubtree.syntax) if l > len(variableName): continue if vacmViewTreeFamilyMask.syntax: mask = [] for c in vacmViewTreeFamilyMask.syntax.asNumbers(): mask = mask + [b & c for b in __powOfTwoSeq] m = len(mask) - 1 idx = l - 1 while idx: if idx > m or mask[idx] and \ vacmViewTreeFamilySubtree.syntax[idx] != variableName[idx]: break idx -= 1 if idx: continue # no match else: # no mask if vacmViewTreeFamilySubtree.syntax != variableName[:l]: continue # no match # 3.2.5c return error.StatusInformation( errorIndication=errind.accessAllowed)
def _com2sec(self, snmpEngine, communityName, transportInformation): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder snmpTargetAddrTAddress, = mibBuilder.importSymbols( 'SNMP-TARGET-MIB', 'snmpTargetAddrTAddress') if self._transportBranchId != snmpTargetAddrTAddress.branchVersionId: (SnmpTagValue, snmpTargetAddrTDomain, snmpTargetAddrTagList) = mibBuilder.importSymbols( 'SNMP-TARGET-MIB', 'SnmpTagValue', 'snmpTargetAddrTDomain', 'snmpTargetAddrTagList') self._emptyTag = SnmpTagValue('') self._transportToTagMap = {} nextMibNode = snmpTargetAddrTagList while True: try: nextMibNode = snmpTargetAddrTagList.getNextNode( nextMibNode.name) except NoSuchInstanceError: break instId = nextMibNode.name[len(snmpTargetAddrTagList.name):] targetAddrTDomain = snmpTargetAddrTDomain.getNode( snmpTargetAddrTDomain.name + instId).syntax targetAddrTAddress = snmpTargetAddrTAddress.getNode( snmpTargetAddrTAddress.name + instId).syntax targetAddrTDomain = tuple(targetAddrTDomain) if (targetAddrTDomain[:len(udp.SNMP_UDP_DOMAIN)] == udp.SNMP_UDP_DOMAIN): SnmpUDPAddress, = mibBuilder.importSymbols( 'SNMPv2-TM', 'SnmpUDPAddress') targetAddrTAddress = tuple( SnmpUDPAddress(targetAddrTAddress)) elif (targetAddrTDomain[:len(udp6.SNMP_UDP6_DOMAIN)] == udp6.SNMP_UDP6_DOMAIN): TransportAddressIPv6, = mibBuilder.importSymbols( 'TRANSPORT-ADDRESS-MIB', 'TransportAddressIPv6') targetAddrTAddress = tuple( TransportAddressIPv6(targetAddrTAddress)) targetAddr = targetAddrTDomain, targetAddrTAddress targetAddrTagList = snmpTargetAddrTagList.getNode( snmpTargetAddrTagList.name + instId).syntax if targetAddr not in self._transportToTagMap: self._transportToTagMap[targetAddr] = set() try: if targetAddrTagList: self._transportToTagMap[targetAddr].update([ SnmpTagValue(x) for x in targetAddrTagList.asOctets().split() ]) else: self._transportToTagMap[targetAddr].add(self._emptyTag) except PyAsn1Error: debug.logger & debug.FLAG_SM and debug.logger( '_com2sec: table entries %r/%r hashing failed' % (targetAddr, targetAddrTagList)) continue self._transportBranchId = snmpTargetAddrTAddress.branchVersionId debug.logger & debug.FLAG_SM and debug.logger( '_com2sec: built transport-to-tag map version %s: ' '%s' % (self._transportBranchId, self._transportToTagMap)) snmpTargetParamsSecurityName, = mibBuilder.importSymbols( 'SNMP-TARGET-MIB', 'snmpTargetParamsSecurityName') if self._paramsBranchId != snmpTargetParamsSecurityName.branchVersionId: snmpTargetParamsSecurityModel, = mibBuilder.importSymbols( 'SNMP-TARGET-MIB', 'snmpTargetParamsSecurityModel') self._nameToModelMap = {} nextMibNode = snmpTargetParamsSecurityName while True: try: nextMibNode = snmpTargetParamsSecurityName.getNextNode( nextMibNode.name) except NoSuchInstanceError: break instId = nextMibNode.name[len(snmpTargetParamsSecurityName.name ):] mibNode = snmpTargetParamsSecurityModel.getNode( snmpTargetParamsSecurityModel.name + instId) try: if nextMibNode.syntax not in self._nameToModelMap: self._nameToModelMap[nextMibNode.syntax] = set() self._nameToModelMap[nextMibNode.syntax].add( mibNode.syntax) except PyAsn1Error: debug.logger & debug.FLAG_SM and debug.logger( '_com2sec: table entries %r/%r hashing ' 'failed' % (nextMibNode.syntax, mibNode.syntax)) continue self._paramsBranchId = snmpTargetParamsSecurityName.branchVersionId # invalidate next map as it include this one self._communityBranchId = -1 debug.logger & debug.FLAG_SM and debug.logger( '_com2sec: built securityName to securityModel map, version ' '%s: %s' % (self._paramsBranchId, self._nameToModelMap)) snmpCommunityName, = mibBuilder.importSymbols('SNMP-COMMUNITY-MIB', 'snmpCommunityName') if self._communityBranchId != snmpCommunityName.branchVersionId: (snmpCommunitySecurityName, snmpCommunityContextEngineId, snmpCommunityContextName, snmpCommunityTransportTag) = mibBuilder.importSymbols( 'SNMP-COMMUNITY-MIB', 'snmpCommunitySecurityName', 'snmpCommunityContextEngineID', 'snmpCommunityContextName', 'snmpCommunityTransportTag') self._communityToTagMap = {} self._tagAndCommunityToSecurityMap = {} nextMibNode = snmpCommunityName while True: try: nextMibNode = snmpCommunityName.getNextNode( nextMibNode.name) except NoSuchInstanceError: break instId = nextMibNode.name[len(snmpCommunityName.name):] securityName = snmpCommunitySecurityName.getNode( snmpCommunitySecurityName.name + instId).syntax contextEngineId = snmpCommunityContextEngineId.getNode( snmpCommunityContextEngineId.name + instId).syntax contextName = snmpCommunityContextName.getNode( snmpCommunityContextName.name + instId).syntax transportTag = snmpCommunityTransportTag.getNode( snmpCommunityTransportTag.name + instId).syntax _tagAndCommunity = transportTag, nextMibNode.syntax try: if _tagAndCommunity not in self._tagAndCommunityToSecurityMap: self._tagAndCommunityToSecurityMap[ _tagAndCommunity] = set() self._tagAndCommunityToSecurityMap[_tagAndCommunity].add( (securityName, contextEngineId, contextName)) if nextMibNode.syntax not in self._communityToTagMap: self._communityToTagMap[nextMibNode.syntax] = set() self._communityToTagMap[nextMibNode.syntax].add( transportTag) except PyAsn1Error: debug.logger & debug.FLAG_SM and debug.logger( '_com2sec: table entries %r/%r hashing ' 'failed' % (_tagAndCommunity, nextMibNode.syntax)) continue self._communityBranchId = snmpCommunityName.branchVersionId debug.logger & debug.FLAG_SM and debug.logger( '_com2sec: built communityName to tag map ' '(securityModel %s), version %s: ' '%s' % (self.SECURITY_MODEL_ID, self._communityBranchId, self._communityToTagMap)) debug.logger & debug.FLAG_SM and debug.logger( '_com2sec: built tag & community to securityName map ' '(securityModel %s), version %s: ' '%s' % (self.SECURITY_MODEL_ID, self._communityBranchId, self._tagAndCommunityToSecurityMap)) if communityName in self._communityToTagMap: if transportInformation in self._transportToTagMap: tags = self._transportToTagMap[ transportInformation].intersection( self._communityToTagMap[communityName]) elif self._emptyTag in self._communityToTagMap[communityName]: tags = [self._emptyTag] else: raise error.StatusInformation( errorIndication=errind.unknownCommunityName) candidateSecurityNames = [] securityNamesSets = [ self._tagAndCommunityToSecurityMap[(t, communityName)] for t in tags ] for x in securityNamesSets: candidateSecurityNames.extend(list(x)) if candidateSecurityNames: candidateSecurityNames.sort(key=self._orderSecurityNames) chosenSecurityName = candidateSecurityNames[0] # min() debug.logger & debug.FLAG_SM and debug.logger( '_com2sec: securityName candidates for communityName %s ' 'are %s; choosing securityName ' '%s' % (communityName, candidateSecurityNames, chosenSecurityName[0])) return chosenSecurityName raise error.StatusInformation( errorIndication=errind.unknownCommunityName)
def __generateRequestOrResponseMsg(self, snmpEngine, messageProcessingModel, globalData, maxMessageSize, securityModel, securityEngineID, securityName, securityLevel, scopedPDU, securityStateReference): snmpEngineID = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineID')[0].syntax # 3.1.1 if securityStateReference is not None: # 3.1.1a cachedSecurityData = self._cache.pop(securityStateReference) usmUserName = cachedSecurityData['msgUserName'] if 'usmUserSecurityName' in cachedSecurityData: usmUserSecurityName = cachedSecurityData['usmUserSecurityName'] else: usmUserSecurityName = usmUserName if 'usmUserAuthProtocol' in cachedSecurityData: usmUserAuthProtocol = cachedSecurityData['usmUserAuthProtocol'] else: usmUserAuthProtocol = noauth.NoAuth.serviceID if 'usmUserAuthKeyLocalized' in cachedSecurityData: usmUserAuthKeyLocalized = cachedSecurityData[ 'usmUserAuthKeyLocalized'] else: usmUserAuthKeyLocalized = None if 'usmUserPrivProtocol' in cachedSecurityData: usmUserPrivProtocol = cachedSecurityData['usmUserPrivProtocol'] else: usmUserPrivProtocol = nopriv.NoPriv.serviceID if 'usmUserPrivKeyLocalized' in cachedSecurityData: usmUserPrivKeyLocalized = cachedSecurityData[ 'usmUserPrivKeyLocalized'] else: usmUserPrivKeyLocalized = None securityEngineID = snmpEngineID debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: user info read from cache') elif securityName: # 3.1.1b try: (usmUserName, usmUserSecurityName, usmUserAuthProtocol, usmUserAuthKeyLocalized, usmUserPrivProtocol, usmUserPrivKeyLocalized) = self.__getUserInfo( snmpEngine.msgAndPduDsp.mibInstrumController, securityEngineID, self.__sec2usr(snmpEngine, securityName, securityEngineID)) debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: read user info') except NoSuchInstanceError: pysnmpUsmDiscovery, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__PYSNMP-USM-MIB', 'pysnmpUsmDiscovery') __reportUnknownName = not pysnmpUsmDiscovery.syntax if not __reportUnknownName: try: (usmUserName, usmUserSecurityName, usmUserAuthProtocol, usmUserAuthKeyLocalized, usmUserPrivProtocol, usmUserPrivKeyLocalized) = self.__cloneUserInfo( snmpEngine.msgAndPduDsp.mibInstrumController, securityEngineID, self.__sec2usr(snmpEngine, securityName)) except NoSuchInstanceError: __reportUnknownName = 1 if __reportUnknownName: raise error.StatusInformation( errorIndication=errind.unknownSecurityName) debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: clone user info') except PyAsn1Error: debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: %s' % (sys.exc_info()[1], )) snmpInGenErrs, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpInGenErrs') snmpInGenErrs.syntax = snmpInGenErrs.syntax + 1 raise error.StatusInformation( errorIndication=errind.invalidMsg) else: # empty username used for engineID discovery usmUserName = usmUserSecurityName = null usmUserAuthProtocol = noauth.NoAuth.serviceID usmUserPrivProtocol = nopriv.NoPriv.serviceID usmUserAuthKeyLocalized = usmUserPrivKeyLocalized = None debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: use empty USM data') debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: local usmUserName %r usmUserSecurityName %r usmUserAuthProtocol %s usmUserPrivProtocol %s securityEngineID %r securityName %r' % (usmUserName, usmUserSecurityName, usmUserAuthProtocol, usmUserPrivProtocol, securityEngineID, securityName)) msg = globalData # 3.1.2 if securityLevel == 3: if usmUserAuthProtocol == noauth.NoAuth.serviceID or \ usmUserPrivProtocol == nopriv.NoPriv.serviceID: raise error.StatusInformation( errorIndication=errind.unsupportedSecurityLevel) # 3.1.3 if securityLevel == 3 or securityLevel == 2: if usmUserAuthProtocol == noauth.NoAuth.serviceID: raise error.StatusInformation( errorIndication=errind.unsupportedSecurityLevel) securityParameters = self.__securityParametersSpec scopedPDUData = msg.setComponentByPosition(3).getComponentByPosition(3) scopedPDUData.setComponentByPosition(0, scopedPDU, verifyConstraints=False) # 3.1.6a if securityStateReference is None and ( # request type check added securityLevel == 3 or securityLevel == 2): if securityEngineID in self.__timeline: (snmpEngineBoots, snmpEngineTime, latestReceivedEngineTime, latestUpdateTimestamp) = self.__timeline[securityEngineID] debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: read snmpEngineBoots, snmpEngineTime from timeline' ) else: # 2.3 XXX is this correct? snmpEngineBoots = snmpEngineTime = 0 debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: no timeline for securityEngineID %r' % (securityEngineID, )) # 3.1.6.b elif securityStateReference is not None: # XXX Report? ( snmpEngineBoots, snmpEngineTime ) = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineBoots', 'snmpEngineTime') snmpEngineBoots = snmpEngineBoots.syntax snmpEngineTime = snmpEngineTime.syntax.clone() debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: read snmpEngineBoots, snmpEngineTime from LCD' ) # 3.1.6.c else: snmpEngineBoots = snmpEngineTime = 0 debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: assuming zero snmpEngineBoots, snmpEngineTime' ) debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: use snmpEngineBoots %s snmpEngineTime %s for securityEngineID %r' % (snmpEngineBoots, snmpEngineTime, securityEngineID)) # 3.1.4a if securityLevel == 3: if usmUserPrivProtocol in self.privServices: privHandler = self.privServices[usmUserPrivProtocol] else: raise error.StatusInformation( errorIndication=errind.encryptionError) debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: scopedPDU %s' % scopedPDU.prettyPrint()) try: dataToEncrypt = encoder.encode(scopedPDU) except PyAsn1Error: debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: scopedPDU serialization error: %s' % sys.exc_info()[1]) raise error.StatusInformation( errorIndication=errind.serializationError) debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: scopedPDU encoded into %s' % debug.hexdump(dataToEncrypt)) (encryptedData, privParameters) = privHandler.encryptData( usmUserPrivKeyLocalized, (snmpEngineBoots, snmpEngineTime, None), dataToEncrypt) securityParameters.setComponentByPosition(5, privParameters, verifyConstraints=False) scopedPDUData.setComponentByPosition(1, encryptedData, verifyConstraints=False) debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: scopedPDU ciphered into %s' % debug.hexdump(encryptedData)) # 3.1.4b elif securityLevel == 1 or securityLevel == 2: securityParameters.setComponentByPosition(5, '') debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: %s' % scopedPDUData.prettyPrint()) # 3.1.5 securityParameters.setComponentByPosition(0, securityEngineID, verifyConstraints=False) securityParameters.setComponentByPosition(1, snmpEngineBoots, verifyConstraints=False) securityParameters.setComponentByPosition(2, snmpEngineTime, verifyConstraints=False) # 3.1.7 securityParameters.setComponentByPosition(3, usmUserName, verifyConstraints=False) # 3.1.8a if securityLevel == 3 or securityLevel == 2: if usmUserAuthProtocol in self.authServices: authHandler = self.authServices[usmUserAuthProtocol] else: raise error.StatusInformation( errorIndication=errind.authenticationFailure) # extra-wild hack to facilitate BER substrate in-place re-write securityParameters.setComponentByPosition( 4, '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00') debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: %s' % (securityParameters.prettyPrint(), )) try: msg.setComponentByPosition(2, encoder.encode(securityParameters), verifyConstraints=False) except PyAsn1Error: debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: securityParameters serialization error: %s' % sys.exc_info()[1]) raise error.StatusInformation( errorIndication=errind.serializationError) debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: auth outgoing msg: %s' % msg.prettyPrint()) try: wholeMsg = encoder.encode(msg) except PyAsn1Error: debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: msg serialization error: %s' % sys.exc_info()[1]) raise error.StatusInformation( errorIndication=errind.serializationError) authenticatedWholeMsg = authHandler.authenticateOutgoingMsg( usmUserAuthKeyLocalized, wholeMsg) # 3.1.8b else: securityParameters.setComponentByPosition(4, '', verifyConstraints=False) debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: %s' % (securityParameters.prettyPrint(), )) try: msg.setComponentByPosition(2, encoder.encode(securityParameters), verifyConstraints=False) except PyAsn1Error: debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: secutiryParameters serialization error: %s' % sys.exc_info()[1]) raise error.StatusInformation( errorIndication=errind.serializationError) try: debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: plain outgoing msg: %s' % msg.prettyPrint()) authenticatedWholeMsg = encoder.encode(msg) except PyAsn1Error: debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: msg serialization error: %s' % sys.exc_info()[1]) raise error.StatusInformation( errorIndication=errind.serializationError) debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: %s outgoing msg: %s' % (securityLevel > 1 and "authenticated" or "plain", debug.hexdump(authenticatedWholeMsg))) # 3.1.9 return (msg.getComponentByPosition(2), authenticatedWholeMsg)
def _sec2com(self, snmpEngine, securityName, contextEngineId, contextName): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder snmpTargetParamsSecurityName, = mibBuilder.importSymbols( 'SNMP-TARGET-MIB', 'snmpTargetParamsSecurityName') if self._paramsBranchId != snmpTargetParamsSecurityName.branchVersionId: snmpTargetParamsSecurityModel, = mibBuilder.importSymbols( 'SNMP-TARGET-MIB', 'snmpTargetParamsSecurityModel') self._nameToModelMap = {} nextMibNode = snmpTargetParamsSecurityName while True: try: nextMibNode = snmpTargetParamsSecurityName.getNextNode( nextMibNode.name) except NoSuchInstanceError: break instId = nextMibNode.name[len(snmpTargetParamsSecurityName.name ):] mibNode = snmpTargetParamsSecurityModel.getNode( snmpTargetParamsSecurityModel.name + instId) try: if mibNode.syntax not in self._nameToModelMap: self._nameToModelMap[nextMibNode.syntax] = set() self._nameToModelMap[nextMibNode.syntax].add( mibNode.syntax) except PyAsn1Error: debug.logger & debug.FLAG_SM and debug.logger( '_sec2com: table entries %r/%r hashing ' 'failed' % (nextMibNode.syntax, mibNode.syntax)) continue self._paramsBranchId = snmpTargetParamsSecurityName.branchVersionId # invalidate next map as it include this one self._securityBranchId = -1 snmpCommunityName, = mibBuilder.importSymbols('SNMP-COMMUNITY-MIB', 'snmpCommunityName') if self._securityBranchId != snmpCommunityName.branchVersionId: (snmpCommunitySecurityName, snmpCommunityContextEngineId, snmpCommunityContextName) = mibBuilder.importSymbols( 'SNMP-COMMUNITY-MIB', 'snmpCommunitySecurityName', 'snmpCommunityContextEngineID', 'snmpCommunityContextName') self._securityMap = {} nextMibNode = snmpCommunityName while True: try: nextMibNode = snmpCommunityName.getNextNode( nextMibNode.name) except NoSuchInstanceError: break instId = nextMibNode.name[len(snmpCommunityName.name):] _securityName = snmpCommunitySecurityName.getNode( snmpCommunitySecurityName.name + instId).syntax _contextEngineId = snmpCommunityContextEngineId.getNode( snmpCommunityContextEngineId.name + instId).syntax _contextName = snmpCommunityContextName.getNode( snmpCommunityContextName.name + instId).syntax key = _securityName, _contextEngineId, _contextName try: self._securityMap[key] = nextMibNode.syntax except PyAsn1Error: debug.logger & debug.FLAG_SM and debug.logger( '_sec2com: table entries %r/%r/%r hashing failed' % key) continue self._securityBranchId = snmpCommunityName.branchVersionId debug.logger & debug.FLAG_SM and debug.logger( '_sec2com: built securityName to communityName map, version ' '%s: %s' % (self._securityBranchId, self._securityMap)) key = securityName, contextEngineId, contextName try: return self._securityMap[key] except KeyError: raise error.StatusInformation( errorIndication=errind.unknownCommunityName)
def prepareResponseMessage(self, snmpEngine, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, maxSizeResponseScopedPDU, stateReference, statusInformation): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder snmpEngineId, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') snmpEngineId = snmpEngineId.syntax # rfc3412: 7.1.2.b if stateReference is None: raise error.StatusInformation(errorIndication=errind.nonReportable) cachedParams = self._cache.popByStateRef(stateReference) msgID = cachedParams['msgID'] reqID = cachedParams['reqID'] contextEngineId = cachedParams['contextEngineId'] contextName = cachedParams['contextName'] securityModel = cachedParams['securityModel'] securityName = cachedParams['securityName'] securityLevel = cachedParams['securityLevel'] securityStateReference = cachedParams['securityStateReference'] maxMessageSize = cachedParams['msgMaxSize'] transportDomain = cachedParams['transportDomain'] transportAddress = cachedParams['transportAddress'] debug.logger & debug.FLAG_MP and debug.logger( 'prepareResponseMessage: cache read msgID %s transportDomain %s ' 'transportAddress %s by stateReference %s' % (msgID, transportDomain, transportAddress, stateReference)) # rfc3412: 7.1.3 if statusInformation: # rfc3412: 7.1.3a (N/A) # rfc3412: 7.1.3b (always discard) raise error.StatusInformation(errorIndication=errind.nonReportable) # rfc3412: 7.1.4 # Since there's no SNMP engine identification in v1/2c, # set destination contextEngineId to ours if not contextEngineId: contextEngineId = snmpEngineId # rfc3412: 7.1.5 if not contextName: contextName = null # rfc3412: 7.1.6 scopedPDU = (contextEngineId, contextName, pdu) debug.logger & debug.FLAG_MP and debug.logger( 'prepareResponseMessage: using contextEngineId %r contextName ' '%r' % (contextEngineId, contextName)) msg = self._snmpMsgSpec msg.setComponentByPosition(0, messageProcessingModel) msg.setComponentByPosition(2) msg.getComponentByPosition(2).setComponentByType( pdu.tagSet, pdu, verifyConstraints=False, matchTags=False, matchConstraints=False) # att: msgId not set back to PDU as it's up to responder app # rfc3412: 7.1.7 globalData = (msg, ) k = int(securityModel) if k in snmpEngine.securityModels: smHandler = snmpEngine.securityModels[k] else: raise error.StatusInformation( errorIndication=errind.unsupportedSecurityModel) # set original request-id right prior to PDU serialization pdu.setComponentByPosition(0, reqID) # rfc3412: 7.1.8.a securityParameters, wholeMsg = smHandler.generateResponseMsg( snmpEngine, self.MESSAGE_PROCESSING_MODEL_ID, globalData, maxMessageSize, securityModel, snmpEngineId, securityName, securityLevel, scopedPDU, securityStateReference) # recover unique request-id right after PDU serialization pdu.setComponentByPosition(0, msgID) snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc2576.prepareResponseMessage', dict(transportDomain=transportDomain, transportAddress=transportAddress, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, securityEngineId=snmpEngineId, communityName=msg.getComponentByPosition(1), pdu=pdu)) snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc2576.prepareResponseMessage') return transportDomain, transportAddress, wholeMsg
def processIncomingMsg(self, snmpEngine, messageProcessingModel, maxMessageSize, securityParameters, securityModel, securityLevel, wholeMsg, msg): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder # rfc2576: 5.2.1 communityName, transportInformation = securityParameters scope = dict(communityName=communityName, transportInformation=transportInformation) snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc2576.processIncomingMsg:writable', scope) snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc2576.processIncomingMsg:writable') try: securityName, contextEngineId, contextName = self._com2sec( snmpEngine, scope.get('communityName', communityName), scope.get('transportInformation', transportInformation)) except error.StatusInformation: snmpInBadCommunityNames, = mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpInBadCommunityNames') snmpInBadCommunityNames.syntax += 1 raise error.StatusInformation( errorIndication=errind.unknownCommunityName, communityName=communityName) snmpEngineID, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') securityEngineID = snmpEngineID.syntax snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc2576.processIncomingMsg', dict(transportInformation=transportInformation, securityEngineId=securityEngineID, securityName=securityName, communityName=communityName, contextEngineId=contextEngineId, contextName=contextName)) snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc2576.processIncomingMsg') debug.logger & debug.FLAG_SM and debug.logger( 'processIncomingMsg: looked up securityName %r securityModel %r ' 'contextEngineId %r contextName %r by communityName %r ' 'AND transportInformation ' '%r' % (securityName, self.SECURITY_MODEL_ID, contextEngineId, contextName, communityName, transportInformation)) stateReference = self._cache.push(communityName=communityName) scopedPDU = (contextEngineId, contextName, msg.getComponentByPosition(2).getComponent()) maxSizeResponseScopedPDU = maxMessageSize - 128 securityStateReference = stateReference debug.logger & debug.FLAG_SM and debug.logger( 'processIncomingMsg: generated maxSizeResponseScopedPDU ' '%s securityStateReference ' '%s' % (maxSizeResponseScopedPDU, securityStateReference)) return (securityEngineID, securityName, scopedPDU, maxSizeResponseScopedPDU, securityStateReference)
def prepareOutgoingMessage(self, snmpEngine, transportDomain, transportAddress, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, expectResponse, sendPduHandle): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder snmpEngineId, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') snmpEngineId = snmpEngineId.syntax # rfc3412: 7.1.1b if pdu.tagSet in rfc3411.CONFIRMED_CLASS_PDUS: # serve unique PDU request-id msgID = self._cache.newMsgID() reqID = pdu.getComponentByPosition(0) debug.logger & debug.FLAG_MP and debug.logger( 'prepareOutgoingMessage: PDU request-id %s replaced with ' 'unique ID %s' % (reqID, msgID)) # rfc3412: 7.1.4 # Since there's no SNMP engine identification in v1/2c, # set destination contextEngineId to ours if not contextEngineId: contextEngineId = snmpEngineId # rfc3412: 7.1.5 if not contextName: contextName = null debug.logger & debug.FLAG_MP and debug.logger( 'prepareOutgoingMessage: using contextEngineId %r contextName ' '%r' % (contextEngineId, contextName)) # rfc3412: 7.1.6 scopedPDU = contextEngineId, contextName, pdu msg = self._snmpMsgSpec msg.setComponentByPosition(0, self.MESSAGE_PROCESSING_MODEL_ID) msg.setComponentByPosition(2) msg.getComponentByPosition(2).setComponentByType( pdu.tagSet, pdu, verifyConstraints=False, matchTags=False, matchConstraints=False) # rfc3412: 7.1.7 globalData = (msg, ) k = int(securityModel) if k in snmpEngine.securityModels: smHandler = snmpEngine.securityModels[k] else: raise error.StatusInformation( errorIndication=errind.unsupportedSecurityModel) # rfc3412: 7.1.9.a & rfc2576: 5.2.1 --> no-op snmpEngineMaxMessageSize, = mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') # fix unique request-id right prior PDU serialization if pdu.tagSet in rfc3411.CONFIRMED_CLASS_PDUS: # noinspection PyUnboundLocalVariable pdu.setComponentByPosition(0, msgID) # rfc3412: 7.1.9.b securityParameters, wholeMsg = smHandler.generateRequestMsg( snmpEngine, self.MESSAGE_PROCESSING_MODEL_ID, globalData, snmpEngineMaxMessageSize.syntax, securityModel, snmpEngineId, securityName, securityLevel, scopedPDU) # return original request-id right after PDU serialization if pdu.tagSet in rfc3411.CONFIRMED_CLASS_PDUS: # noinspection PyUnboundLocalVariable pdu.setComponentByPosition(0, reqID) # rfc3412: 7.1.9.c if pdu.tagSet in rfc3411.CONFIRMED_CLASS_PDUS: # XXX rfc bug? why stateReference should be created? self._cache.pushByMsgId(int(msgID), sendPduHandle=sendPduHandle, reqID=reqID, snmpEngineId=snmpEngineId, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, transportDomain=transportDomain, transportAddress=transportAddress) communityName = msg.getComponentByPosition(1) # for observer snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc2576.prepareOutgoingMessage', dict(transportDomain=transportDomain, transportAddress=transportAddress, wholeMsg=wholeMsg, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, communityName=communityName, pdu=pdu)) snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc2576.prepareOutgoingMessage') return transportDomain, transportAddress, wholeMsg
def prepareResponseMessage( self, snmpEngine, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, pdu, maxSizeResponseScopedPDU, stateReference, statusInformation ): snmpEngineID, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') snmpEngineID = snmpEngineID.syntax # rfc3412: 7.1.2.b cachedParams = self._cachePopByStateRef(stateReference) msgID = cachedParams['msgID'] contextEngineId = cachedParams['contextEngineId'] contextName = cachedParams['contextName'] securityModel = cachedParams['securityModel'] securityName = cachedParams['securityName'] securityLevel = cachedParams['securityLevel'] securityStateReference = cachedParams['securityStateReference'] maxMessageSize = cachedParams['msgMaxSize'] transportDomain = cachedParams['transportDomain'] transportAddress = cachedParams['transportAddress'] debug.logger & debug.flagMP and debug.logger('prepareResponseMessage: cache read msgID %s transportDomain %s transportAddress %s by stateReference %s' % (msgID, transportDomain, transportAddress, stateReference)) # rfc3412: 7.1.3 if statusInformation: # rfc3412: 7.1.3a (N/A) # rfc3412: 7.1.3b (always discard) raise error.StatusInformation( errorIndication = 'nonReportable' ) # rfc3412: 7.1.4 # Since there's no SNMP engine identification in v1/2c, # set destination contextEngineId to ours if not contextEngineId: contextEngineId = snmpEngineID # rfc3412: 7.1.5 if not contextName: contextName = '' # rfc3412: 7.1.6 scopedPDU = ( contextEngineId, contextName, pdu ) debug.logger & debug.flagMP and debug.logger('prepareResponseMessage: using contextEngineId %s contextName %s' % (contextEngineId, contextName)) msg = self._snmpMsgSpec.clone() msg.setComponentByPosition(0, messageProcessingModel) msg.setComponentByPosition(2) msg.getComponentByPosition(2).setComponentByType(pdu.tagSet, pdu) # att: msgId not set back to PDU as it's up to responder app # rfc3412: 7.1.7 globalData = ( msg, ) smHandler = snmpEngine.securityModels.get(int(securityModel)) if smHandler is None: raise error.StatusInformation( errorIndication = 'unsupportedSecurityModel' ) securityEngineId = snmpEngineID # rfc3412: 7.1.8.a ( securityParameters, wholeMsg ) = smHandler.generateResponseMsg( snmpEngine, self.messageProcessingModelID, globalData, maxMessageSize, securityModel, snmpEngineID, securityName, securityLevel, scopedPDU, securityStateReference ) return ( transportDomain, transportAddress, wholeMsg )
def _sec2com(self, snmpEngine, securityName, contextEngineId, contextName): snmpTargetParamsSecurityName, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( 'SNMP-TARGET-MIB', 'snmpTargetParamsSecurityName') if self.__paramsBranchId != snmpTargetParamsSecurityName.branchVersionId: snmpTargetParamsSecurityModel, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( 'SNMP-TARGET-MIB', 'snmpTargetParamsSecurityModel') self.__nameToModelMap = {} nextMibNode = snmpTargetParamsSecurityName while 1: try: nextMibNode = snmpTargetParamsSecurityName.getNextNode( nextMibNode.name) except NoSuchInstanceError: break instId = nextMibNode.name[len(snmpTargetParamsSecurityName.name ):] mibNode = snmpTargetParamsSecurityModel.getNode( snmpTargetParamsSecurityModel.name + instId) if mibNode.syntax not in self.__nameToModelMap: self.__nameToModelMap[nextMibNode.syntax] = set() self.__nameToModelMap[nextMibNode.syntax].add(mibNode.syntax) self.__paramsBranchId = snmpTargetParamsSecurityName.branchVersionId # invalidate next map as it include this one self.__securityBranchId = -1 snmpCommunityName, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( 'SNMP-COMMUNITY-MIB', 'snmpCommunityName') if self.__securityBranchId != snmpCommunityName.branchVersionId: ( snmpCommunitySecurityName, snmpCommunityContextEngineId, snmpCommunityContextName ) = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( 'SNMP-COMMUNITY-MIB', 'snmpCommunitySecurityName', 'snmpCommunityContextEngineID', 'snmpCommunityContextName') self.__securityMap = {} nextMibNode = snmpCommunityName while 1: try: nextMibNode = snmpCommunityName.getNextNode( nextMibNode.name) except NoSuchInstanceError: break instId = nextMibNode.name[len(snmpCommunityName.name):] _securityName = snmpCommunitySecurityName.getNode( snmpCommunitySecurityName.name + instId).syntax _contextEngineId = snmpCommunityContextEngineId.getNode( snmpCommunityContextEngineId.name + instId).syntax _contextName = snmpCommunityContextName.getNode( snmpCommunityContextName.name + instId).syntax self.__securityMap[(_securityName, _contextEngineId, _contextName)] = nextMibNode.syntax self.__securityBranchId = snmpCommunityName.branchVersionId debug.logger & debug.flagSM and debug.logger( '_sec2com: built securityName to communityName map, version %s: %s' % (self.__securityBranchId, self.__securityMap)) try: return self.__securityMap[(securityName, contextEngineId, contextName)] except KeyError: raise error.StatusInformation( errorIndication=errind.unknownCommunityName)
def v2ToV1(v2Pdu, origV1Pdu=None): debug.logger & debug.FLAG_PRX and debug.logger( 'v2ToV1: v2Pdu %s' % v2Pdu.prettyPrint()) pduType = v2Pdu.tagSet if pduType in V2_TO_V1_PDU_MAP: v1Pdu = V2_TO_V1_PDU_MAP[pduType].clone() else: raise error.ProtocolError('Unsupported PDU type') v2VarBinds = v2c.apiPDU.getVarBinds(v2Pdu) v1VarBinds = [] zeroInt = v1.Integer(0) # 3.2 if pduType in rfc3411.NOTIFICATION_CLASS_PDUS: if len(v2VarBinds) < 2: raise error.ProtocolError( 'SNMP v2c TRAP PDU requires at least two var-binds') # 3.2.1 snmpTrapOID, snmpTrapOIDParam = v2VarBinds[1] if snmpTrapOID != v2c.apiTrapPDU.snmpTrapOID: raise error.ProtocolError('Second OID not snmpTrapOID') if snmpTrapOIDParam in V2_TO_V1_TRAP_MAP: for oid, val in v2VarBinds: if oid == v2c.apiTrapPDU.snmpTrapEnterprise: v1.apiTrapPDU.setEnterprise(v1Pdu, val) break else: # snmpTraps v1.apiTrapPDU.setEnterprise(v1Pdu, (1, 3, 6, 1, 6, 3, 1, 1, 5)) else: if snmpTrapOIDParam[-2] == 0: v1.apiTrapPDU.setEnterprise(v1Pdu, snmpTrapOIDParam[:-2]) else: v1.apiTrapPDU.setEnterprise(v1Pdu, snmpTrapOIDParam[:-1]) # 3.2.2 for oid, val in v2VarBinds: # snmpTrapAddress if oid == v2c.apiTrapPDU.snmpTrapAddress: # v2c.OctetString is more constrained v1.apiTrapPDU.setAgentAddr(v1Pdu, v1.IpAddress(val)) break else: v1.apiTrapPDU.setAgentAddr(v1Pdu, v1.IpAddress('0.0.0.0')) # 3.2.3 if snmpTrapOIDParam in V2_TO_V1_TRAP_MAP: v1.apiTrapPDU.setGenericTrap( v1Pdu, V2_TO_V1_TRAP_MAP[snmpTrapOIDParam]) else: v1.apiTrapPDU.setGenericTrap(v1Pdu, 6) # 3.2.4 if snmpTrapOIDParam in V2_TO_V1_TRAP_MAP: v1.apiTrapPDU.setSpecificTrap(v1Pdu, zeroInt) else: v1.apiTrapPDU.setSpecificTrap(v1Pdu, snmpTrapOIDParam[-1]) # 3.2.5 v1.apiTrapPDU.setTimeStamp(v1Pdu, v2VarBinds[0][1]) __v2VarBinds = [] for oid, val in v2VarBinds[2:]: if (oid in V2_TO_V1_TRAP_MAP or oid in (v2c.apiTrapPDU.sysUpTime, v2c.apiTrapPDU.snmpTrapAddress, v2c.apiTrapPDU.snmpTrapEnterprise)): continue __v2VarBinds.append((oid, val)) v2VarBinds = __v2VarBinds # 3.2.6 --> done below else: v1.apiPDU.setErrorStatus(v1Pdu, zeroInt) v1.apiPDU.setErrorIndex(v1Pdu, zeroInt) if pduType in rfc3411.RESPONSE_CLASS_PDUS: idx = len(v2VarBinds) - 1 while idx >= 0: # 4.1.2.1 oid, val = v2VarBinds[idx] if v2c.Counter64.tagSet == val.tagSet: if origV1Pdu.tagSet == v1.GetRequestPDU.tagSet: v1.apiPDU.setErrorStatus(v1Pdu, 2) v1.apiPDU.setErrorIndex(v1Pdu, idx + 1) break elif origV1Pdu.tagSet == v1.GetNextRequestPDU.tagSet: raise error.StatusInformation(idx=idx, pdu=v2Pdu) else: raise error.ProtocolError('Counter64 on the way') # 4.1.2.2.1&2 if val.tagSet in (v2c.NoSuchObject.tagSet, v2c.NoSuchInstance.tagSet, v2c.EndOfMibView.tagSet): v1.apiPDU.setErrorStatus(v1Pdu, 2) v1.apiPDU.setErrorIndex(v1Pdu, idx + 1) idx -= 1 # 4.1.2.3.1 v2ErrorStatus = v2c.apiPDU.getErrorStatus(v2Pdu) if v2ErrorStatus: v1.apiPDU.setErrorStatus( v1Pdu, V2_TO_V1_ERROR_MAP.get(v2ErrorStatus, 5)) v1.apiPDU.setErrorIndex(v1Pdu, v2c.apiPDU.getErrorIndex(v2Pdu, muteErrors=True)) elif pduType in rfc3411.CONFIRMED_CLASS_PDUS: v1.apiPDU.setErrorStatus(v1Pdu, 0) v1.apiPDU.setErrorIndex(v1Pdu, 0) # Translate Var-Binds if (pduType in rfc3411.RESPONSE_CLASS_PDUS and v1.apiPDU.getErrorStatus(v1Pdu)): v1VarBinds = v1.apiPDU.getVarBinds(origV1Pdu) else: for oid, v2Val in v2VarBinds: v1VarBinds.append( (oid, V2_TO_V1_VALUE_MAP[v2Val.tagSet].clone(v2Val)) ) if pduType in rfc3411.NOTIFICATION_CLASS_PDUS: v1.apiTrapPDU.setVarBinds(v1Pdu, v1VarBinds) else: v1.apiPDU.setVarBinds(v1Pdu, v1VarBinds) v1.apiPDU.setRequestID( v1Pdu, v2c.apiPDU.getRequestID(v2Pdu) ) debug.logger & debug.FLAG_PRX and debug.logger( 'v2ToV1: v1Pdu %s' % v1Pdu.prettyPrint()) return v1Pdu