def processIncomingMsg( self, snmpEngine, messageProcessingModel, maxMessageSize, securityParameters, securityModel, securityLevel, wholeMsg, msg ): # rfc2576: 5.2.1 ( communityName, transportInformation ) = securityParameters scope = dict(communityName=communityName, transportInformation=transportInformation) snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc2576.processIncomingMsg:writable', scope ) try: securityName, contextEngineId, contextName = self._com2sec( snmpEngine, scope.get('communityName', communityName), scope.get('transportInformation', transportInformation) ) except error.StatusInformation: snmpInBadCommunityNames, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMPv2-MIB', 'snmpInBadCommunityNames') snmpInBadCommunityNames.syntax = snmpInBadCommunityNames.syntax+1 raise error.StatusInformation( errorIndication = errind.unknownCommunityName ) snmpEngineID, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') securityEngineID = snmpEngineID.syntax debug.logger & debug.flagSM and debug.logger('processIncomingMsg: looked up securityName %r securityModel %r contextEngineId %r contextName %r by communityName %r AND transportInformation %r' % (securityName, self.securityModelID, 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.flagSM and debug.logger('processIncomingMsg: generated maxSizeResponseScopedPDU %s securityStateReference %s' % (maxSizeResponseScopedPDU, securityStateReference)) return ( securityEngineID, securityName, scopedPDU, maxSizeResponseScopedPDU, securityStateReference )
def __init__(self, sock=None, sockMap=None): asyncore.dispatcher.__init__(self) if sock is None: if self.sockFamily is None: raise error.CarrierError( 'Address family %s not supported' % self.__class__.__name__ ) if self.sockType is None: raise error.CarrierError( 'Socket type %s not supported' % self.__class__.__name__ ) try: sock = socket.socket(self.sockFamily, self.sockType) except socket.error: raise error.CarrierError('socket() failed: %s' % sys.exc_info()[1]) try: for b in socket.SO_RCVBUF, socket.SO_SNDBUF: bsize = sock.getsockopt(socket.SOL_SOCKET, b) if bsize < self.bufferSize: sock.setsockopt(socket.SOL_SOCKET, b, self.bufferSize) debug.logger & debug.flagIO and debug.logger('%s: socket %d buffer size increased from %d to %d for buffer %d' % (self.__class__.__name__, sock.fileno(), bsize, self.bufferSize, b)) except Exception: debug.logger & debug.flagIO and debug.logger('%s: socket buffer size option mangling failure for buffer: %s' % (self.__class__.__name__, sys.exc_info()[1])) # The socket map is managed by the AsyncoreDispatcher on # which this transport is registered. Here we just prepare # socket and postpone transport registration at dispatcher # till AsyncoreDispatcher invokes registerSocket() sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.setblocking(0) self.set_socket(sock)
def generateResponseMsg( self, snmpEngine, messageProcessingModel, globalData, maxMessageSize, securityModel, securityEngineID, securityName, securityLevel, scopedPDU, securityStateReference ): # rfc2576: 5.2.2 msg, = globalData contextEngineId, contextName, pdu = scopedPDU cachedSecurityData = self._cache.pop(securityStateReference) communityName = cachedSecurityData['communityName'] debug.logger & debug.flagSM and debug.logger('generateResponseMsg: recovered community %r by securityStateReference %s' % (communityName, securityStateReference)) msg.setComponentByPosition(1, communityName) msg.setComponentByPosition(2) msg.getComponentByPosition(2).setComponentByType( pdu.tagSet, pdu, verifyConstraints=False ) debug.logger & debug.flagMP and debug.logger('generateResponseMsg: %s' % (msg.prettyPrint(),)) wholeMsg = encoder.encode(msg) return ( communityName, wholeMsg )
def processResponseVarBinds(self, snmpEngine, sendRequestHandle, errorIndication, PDU, cbCtx): targetName, contextEngineId, contextName, reqPDU, cbFun, cbCtx = cbCtx if errorIndication: cbFun(snmpEngine, sendRequestHandle, errorIndication, 0, 0, (), cbCtx) return varBindTable = v2c.apiPDU.getVarBindTable(reqPDU, PDU) if v2c.apiPDU.getErrorStatus(PDU): errorIndication, varBinds = None, () elif not varBindTable: errorIndication, varBinds = errind.emptyResponse, () else: errorIndication, varBinds = getNextVarBinds( varBindTable[-1], v2c.apiPDU.getVarBinds(reqPDU) ) if not cbFun(snmpEngine, sendRequestHandle, errorIndication, v2c.apiPDU.getErrorStatus(PDU), v2c.apiPDU.getErrorIndex(PDU, muteErrors=True), varBindTable, cbCtx): debug.logger & debug.flagApp and debug.logger('processResponseVarBinds: sendRequestHandle %s, app says to stop walking' % sendRequestHandle) return # app says enough if not varBinds: return # no more objects available v2c.apiPDU.setRequestID(reqPDU, v2c.getNextRequestID()) v2c.apiPDU.setVarBinds(reqPDU, varBinds) try: self.sendPdu(snmpEngine, targetName, contextEngineId, contextName, reqPDU, self.processResponseVarBinds, (targetName, contextEngineId, contextName, reqPDU, cbFun, cbCtx)) except StatusInformation: statusInformation = sys.exc_info()[1] debug.logger & debug.flagApp and debug.logger('sendVarBinds: sendPduHandle %s: sendPdu() failed with %r' % (sendRequestHandle, statusInformation)) cbFun(snmpEngine, sendRequestHandle, statusInformation['errorIndication'], 0, 0, (), cbCtx)
def generateResponseMsg(self, snmpEngine, messageProcessingModel, globalData, maxMessageSize, securityModel, securityEngineID, securityName, securityLevel, scopedPDU, securityStateReference): # rfc2576: 5.2.2 msg, = globalData contextEngineId, contextName, pdu = scopedPDU cachedSecurityData = self._cache.pop(securityStateReference) communityName = cachedSecurityData['communityName'] debug.logger & debug.flagSM and debug.logger('generateResponseMsg: recovered community %r by securityStateReference %s' % (communityName, securityStateReference)) msg.setComponentByPosition(1, communityName) msg.setComponentByPosition(2) msg.getComponentByPosition(2).setComponentByType( pdu.tagSet, pdu, verifyConstraints=False ) debug.logger & debug.flagMP and debug.logger('generateResponseMsg: %s' % (msg.prettyPrint(),)) try: return communityName, encoder.encode(msg) except PyAsn1Error: debug.logger & debug.flagMP and debug.logger('generateResponseMsg: serialization failure: %s' % sys.exc_info()[1]) raise error.StatusInformation(errorIndication=errind.serializationError)
def generateRequestMsg(self, snmpEngine, messageProcessingModel, globalData, maxMessageSize, securityModel, securityEngineId, securityName, securityLevel, scopedPDU): msg, = globalData contextEngineId, contextName, pdu = scopedPDU # rfc2576: 5.2.3 communityName = self._sec2com(snmpEngine, securityName, contextEngineId, contextName) debug.logger & debug.flagSM and debug.logger('generateRequestMsg: using community %r for securityModel %r, securityName %r, contextEngineId %r contextName %r' % (communityName, securityModel, securityName, contextEngineId, contextName)) securityParameters = communityName msg.setComponentByPosition(1, securityParameters) msg.setComponentByPosition(2) msg.getComponentByPosition(2).setComponentByType( pdu.tagSet, pdu, verifyConstraints=False ) debug.logger & debug.flagMP and debug.logger('generateRequestMsg: %s' % (msg.prettyPrint(),)) try: return securityParameters, encoder.encode(msg) except PyAsn1Error: debug.logger & debug.flagMP and debug.logger('generateRequestMsg: serialization failure: %s' % sys.exc_info()[1]) raise error.StatusInformation(errorIndication=errind.serializationError)
def handle_read(self): try: incomingMessage, transportAddress = self._recvfrom(self.socket, 65535) transportAddress = self.normalizeAddress(transportAddress) debug.logger & debug.FLAG_IO and debug.logger( 'handle_read: transportAddress %r -> %r incomingMessage (%d ' 'octets) %s' % (transportAddress, transportAddress.getLocalAddress(), len(incomingMessage), debug.hexdump(incomingMessage))) if not incomingMessage: self.handle_close() return else: self._cbFun(self, transportAddress, incomingMessage) return except socket.error as exc: if exc.args[0] in SOCK_ERRORS: debug.logger & debug.FLAG_IO and debug.logger( 'handle_read: known socket error %s' % exc) SOCK_ERRORS[exc.args[0]] and self.handle_close() return else: raise error.CarrierError('recvfrom() failed: %s' % exc)
def exportSymbols(self, modName, *anonymousSyms, **namedSyms): if modName not in self.mibSymbols: self.mibSymbols[modName] = {} mibSymbols = self.mibSymbols[modName] for symObj in anonymousSyms: debug.logger & debug.flagBld and debug.logger( 'exportSymbols: anonymous symbol %s::__pysnmp_%ld' % (modName, self._autoName)) mibSymbols['__pysnmp_%ld' % self._autoName] = symObj self._autoName += 1 for symName, symObj in namedSyms.items(): if symName in mibSymbols: raise error.SmiError( 'Symbol %s already exported at %s' % (symName, modName) ) if symName != self.moduleID and \ not isinstance(symObj, classTypes): label = symObj.getLabel() if label: symName = label else: symObj.setLabel(symName) mibSymbols[symName] = symObj debug.logger & debug.flagBld and debug.logger('exportSymbols: symbol %s::%s' % (modName, symName)) self.lastBuildId += 1
def exportSymbols(self, modName, *anonymousSyms, **namedSyms): if not self.mibSymbols.has_key(modName): self.mibSymbols[modName] = {} mibSymbols = self.mibSymbols[modName] for symObj in anonymousSyms: debug.logger & debug.flagBld and debug.logger('exportSymbols: anonymous symbol %s::__pysnmp_%ld' % (modName, self._autoName)) mibSymbols['__pysnmp_%ld' % self._autoName] = symObj self._autoName = self._autoName + 1 for symName, symObj in namedSyms.items(): if mibSymbols.has_key(symName): raise error.SmiError( 'Symbol %s already exported at %s' % (symName, modName) ) if hasattr(symObj, 'label'): symName = symObj.label or symName # class if type(symObj) == types.InstanceType: symName = symObj.getLabel() or symName # class instance mibSymbols[symName] = symObj debug.logger & debug.flagBld and debug.logger('exportSymbols: symbol %s::%s' % (modName, symName)) self.lastBuildId = self.lastBuildId + 1
def sendPdu(self, snmpEngine, targetName, contextEngineId, contextName, pdu, cbFun=None, cbCtx=None): (transportDomain, transportAddress, timeout, retryCount, params) = config.getTargetAddr(snmpEngine, targetName) (messageProcessingModel, securityModel, securityName, securityLevel) = config.getTargetParams(snmpEngine, params) # User-side API assumes SMIv2 if messageProcessingModel == 0: reqPDU = rfc2576.v2ToV1(pdu) pduVersion = 0 else: reqPDU = pdu pduVersion = 1 # 3.3.5 if reqPDU.tagSet in rfc3411.CONFIRMED_CLASS_PDUS: # Convert timeout in seconds into timeout in timer ticks timeoutInTicks = (float(timeout) / 100 / snmpEngine.transportDispatcher.getTimerResolution()) sendRequestHandle = getNextHandle() # 3.3.6a sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu( snmpEngine, transportDomain, transportAddress, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, reqPDU, True, timeoutInTicks, self.processResponsePdu, (sendRequestHandle, cbFun, cbCtx) ) debug.logger & debug.FLAG_APP and debug.logger( 'sendPdu: sendPduHandle %s, timeout %d' % (sendPduHandle, timeout)) # 3.3.6b self.__pendingReqs[sendPduHandle] = ( transportDomain, transportAddress, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pdu, timeout, retryCount, 0, 0 ) snmpEngine.transportDispatcher.jobStarted(id(self)) else: snmpEngine.msgAndPduDsp.sendPdu( snmpEngine, transportDomain, transportAddress, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, reqPDU, False ) sendRequestHandle = None debug.logger & debug.FLAG_APP and debug.logger('sendPdu: message sent') return sendRequestHandle
def returnResponsePdu( self, snmpEngine, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, PDU, maxSizeResponseScopedPDU, stateReference, statusInformation, ): """PDU dispatcher -- prepare and serialize a response""" # 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: (destTransportDomain, destTransportAddress, 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 = snmpSilentDrops.syntax + 1 raise error.StatusInformation(errorIndication=errind.tooBig) # 4.1.2.4 snmpEngine.transportDispatcher.sendMessage(outgoingMessage, destTransportDomain, destTransportAddress)
def flipFlopFsm(self, fsmTable, inputNameVals, acInfo): self.__indexMib() debug.logger & debug.flagIns and debug.logger('flipFlopFsm: inputNameVals %r' % (inputNameVals,)) mibTree, = self.mibBuilder.importSymbols('SNMPv2-SMI', 'iso') outputNameVals = [] state, status = 'start', 'ok' origExc = None while 1: k = (state, status) if k in fsmTable: fsmState = fsmTable[k] else: k = ('*', status) if k in fsmTable: fsmState = fsmTable[k] else: raise error.SmiError( 'Unresolved FSM state %s, %s' % (state, status) ) debug.logger & debug.flagIns and debug.logger('flipFlopFsm: state %s status %s -> fsmState %s' % (state, status, fsmState)) state = fsmState status = 'ok' if state == 'stop': break idx = 0 for name, val in inputNameVals: f = getattr(mibTree, state, None) if f is None: raise error.SmiError( 'Unsupported state handler %s at %s' % (state, self) ) try: # Convert to tuple to avoid ObjectName instantiation # on subscription rval = f(tuple(name), val, idx, acInfo) except error.SmiError: exc_t, exc_v, exc_tb = sys.exc_info() debug.logger & debug.flagIns and debug.logger('flipFlopFsm: fun %s exception %s for %s=%r with traceback: %s' % (f, exc_t, name, val, traceback.format_exception(exc_t, exc_v, exc_tb))) if origExc is None: # Take the first exception origExc, origTraceback = exc_v, exc_tb status = 'err' break else: debug.logger & debug.flagIns and debug.logger('flipFlopFsm: fun %s suceeded for %s=%r' % (f, name, val)) if rval is not None: outputNameVals.append((rval[0], rval[1])) idx = idx + 1 if origExc: if sys.version_info[0] <= 2: raise origExc else: try: raise origExc.with_traceback(origTraceback) finally: # Break cycle between locals and traceback object # (seems to be irrelevant on Py3 but just in case) del origTraceback return outputNameVals
def processResponseVarBinds(self, snmpEngine, sendRequestHandle, errorIndication, PDU, cbCtx): (targetName, nonRepeaters, maxRepetitions, contextEngineId, contextName, reqPDU, cbFun, cbCtx) = cbCtx if errorIndication: cbFun(snmpEngine, sendRequestHandle, errorIndication, 0, 0, (), cbCtx) return varBindTable = v2c.apiBulkPDU.getVarBindTable(reqPDU, PDU) if v2c.apiBulkPDU.getErrorStatus(PDU): errorIndication, varBinds = None, () elif not varBindTable: errorIndication, varBinds = errind.emptyResponse, () else: errorIndication, varBinds = v2c.apiBulkPDU.getNextVarBinds(varBindTable[-1]) nonRepeaters = v2c.apiBulkPDU.getNonRepeaters(reqPDU) if nonRepeaters: varBinds = v2c.apiBulkPDU.getVarBinds(reqPDU)[:int(nonRepeaters)] + varBinds[int(nonRepeaters):] if not cbFun( snmpEngine, sendRequestHandle, errorIndication, v2c.apiBulkPDU.getErrorStatus(PDU), v2c.apiBulkPDU.getErrorIndex(PDU, muteErrors=True), varBindTable, cbCtx): debug.logger & debug.FLAG_APP and debug.logger( 'processResponseVarBinds: sendRequestHandle %s, app says to stop walking' % sendRequestHandle) return # app says it's enough if not varBinds: return # no more objects available v2c.apiBulkPDU.setRequestID(reqPDU, v2c.getNextRequestID()) v2c.apiBulkPDU.setVarBinds(reqPDU, varBinds) try: self.sendPdu( snmpEngine, targetName, contextEngineId, contextName, reqPDU, self.processResponseVarBinds, (targetName, nonRepeaters, maxRepetitions, contextEngineId, contextName, reqPDU, cbFun, cbCtx)) except StatusInformation as exc: statusInformation = exc debug.logger & debug.FLAG_APP and debug.logger( 'processResponseVarBinds: sendPduHandle %s: _sendPdu() failed ' 'with %r' % (sendRequestHandle, statusInformation)) cbFun(snmpEngine, sendRequestHandle, statusInformation['errorIndication'], 0, 0, (), cbCtx)
def startProtocol(self): debug.logger & debug.flagIO and debug.logger('startProtocol: invoked') while self._writeQ: outgoingMessage, transportAddress = self._writeQ.pop(0) debug.logger & debug.flagIO and debug.logger('startProtocol: transportAddress %r outgoingMessage %s' % (transportAddress, debug.hexdump(outgoingMessage))) try: self.transport.write(outgoingMessage, transportAddress) except Exception: raise error.CarrierError('Twisted exception: %s' % (sys.exc_info()[1],))
def startProtocol(self): debug.logger & debug.flagIO and debug.logger('startProtocol: invoked') while self._writeQ: outgoingMessage, transportAddress = self._writeQ.pop(0) debug.logger & debug.flagIO and debug.logger('startProtocol: transportAddress %s outgoingMessage %s' % (transportAddress, repr(outgoingMessage))) try: self.transport.write(outgoingMessage, transportAddress) except Exception, why: raise error.CarrierError('Twisted exception: %s' % (why,))
def getMibInstrum(self, contextName): contextName = univ.OctetString(contextName).asOctets() if contextName not in self.contextNames: debug.logger & debug.flagIns and debug.logger('getMibInstrum: contextName \"%s\" not registered' % contextName) raise error.PySnmpError( 'Missing contextName %s' % contextName ) else: debug.logger & debug.flagIns and debug.logger('getMibInstrum: contextName \"%s\", mibInstum %s' % (contextName, self.contextNames[contextName])) return self.contextNames[contextName]
def handle_write(self): outgoingMessage, transportAddress = self.__outQueue.pop() debug.logger & debug.flagIO and debug.logger('handle_write: transportAddress %r outgoingMessage %r' % (transportAddress, outgoingMessage)) try: self.socket.sendto(outgoingMessage, transportAddress) except socket.error: if sys.exc_info()[1].args[0] in sockErrors: debug.logger & debug.flagIO and debug.logger('handle_write: ignoring socket error %s' % (sys.exc_info()[1],)) else: raise socket.error(sys.exc_info()[1])
def loadModules(self, *modNames, **userCtx): # Build a list of available modules if not modNames: modNames = {} for mibSource in self.__mibSources: for modName in mibSource.listdir(): modNames[modName] = None modNames = list(modNames.keys()) if not modNames: raise error.SmiError( 'No MIB module to load at %s' % (self,) ) for modName in modNames: for mibSource in self.__mibSources: debug.logger & debug.flagBld and debug.logger('loadModules: trying %s at %s' % (modName, mibSource)) try: modData, sfx = mibSource.read(modName) except IOError: debug.logger & debug.flagBld and debug.logger('loadModules: read %s from %s failed: %s' % (modName, mibSource, sys.exc_info()[1])) continue modPath = mibSource.fullPath(modName, sfx) if modPath in self.__modPathsSeen: debug.logger & debug.flagBld and debug.logger('loadModules: seen %s' % modPath) break else: self.__modPathsSeen[modPath] = 1 debug.logger & debug.flagBld and debug.logger('loadModules: evaluating %s' % modPath) g = { 'mibBuilder': self, 'userCtx': userCtx } try: exec(modData, g) except Exception: del self.__modPathsSeen[modPath] raise error.SmiError( 'MIB module \"%s\" load error: %s' % (modPath, sys.exc_info()[1]) ) self.__modSeen[modName] = modPath debug.logger & debug.flagBld and debug.logger('loadModules: loaded %s' % modPath) break if modName not in self.__modSeen: raise error.SmiError( 'MIB file \"%s\" not found in search path' % (modName and modName + ".py[co]") ) return self
def loadModule(self, modName, **userCtx): """Load and execute MIB modules as Python code""" for mibSource in self._mibSources: debug.logger & debug.FLAG_BLD and debug.logger( 'loadModule: trying %s at %s' % (modName, mibSource)) try: codeObj, sfx = mibSource.read(modName) except IOError as exc: debug.logger & debug.FLAG_BLD and debug.logger( 'loadModule: read %s from %s failed: ' '%s' % (modName, mibSource, exc)) continue modPath = mibSource.fullPath(modName, sfx) if modPath in self._modPathsSeen: debug.logger & debug.FLAG_BLD and debug.logger( 'loadModule: seen %s' % modPath) break else: self._modPathsSeen.add(modPath) debug.logger & debug.FLAG_BLD and debug.logger( 'loadModule: evaluating %s' % modPath) g = {'mibBuilder': self, 'userCtx': userCtx} try: exec(codeObj, g) except Exception: self._modPathsSeen.remove(modPath) raise error.MibLoadError( 'MIB module "%s" load error: ' '%s' % (modPath, traceback.format_exception(*sys.exc_info()))) self._modSeen[modName] = modPath debug.logger & debug.FLAG_BLD and debug.logger( 'loadModule: loaded %s' % modPath) break if modName not in self._modSeen: raise error.MibNotFoundError( 'MIB file "%s" not found in search path ' '(%s)' % (modName and modName + ".py[co]", ', '.join( [str(x) for x in self._mibSources]))) return self
def connection_made(self, transport): self.transport = transport debug.logger & debug.flagIO and debug.logger('connection_made: invoked') while self._writeQ: outgoingMessage, transportAddress = self._writeQ.pop(0) debug.logger & debug.flagIO and debug.logger('connection_made: transportAddress %r outgoingMessage %s' % (transportAddress, debug.hexdump(outgoingMessage))) try: self.transport.sendto(outgoingMessage, self.normalizeAddress(transportAddress)) except Exception: raise error.CarrierError(';'.join(traceback.format_exception(*sys.exc_info())))
def read(self, f): pycTime = pyTime = -1 for pycSfx, pycSfxLen, pycMode in self.__sfx[imp.PY_COMPILED]: try: pycData = self._getData(f + pycSfx, pycMode) except IOError: why = sys.exc_info()[1] if ENOENT == -1 or why.errno == ENOENT: debug.logger & debug.flagBld and debug.logger( 'file %s access error: %s' % (f + pycSfx, why) ) else: raise error.MibLoadError('MIB file %s access error: %s' % (f + pycSfx, why)) else: if self.__magic == pycData[:4]: pycData = pycData[4:] pycTime = struct.unpack('<L', pycData[:4])[0] pycData = pycData[4:] debug.logger & debug.flagBld and debug.logger( 'file %s mtime %d' % (f + pycSfx, pycTime) ) break else: debug.logger & debug.flagBld and debug.logger( 'bad magic in %s' % (f + pycSfx,) ) for pySfx, pySfxLen, pyMode in self.__sfx[imp.PY_SOURCE]: try: pyTime = self._getTimestamp(f + pySfx) except IOError: why = sys.exc_info()[1] if ENOENT == -1 or why.errno == ENOENT: debug.logger & debug.flagBld and debug.logger( 'file %s access error: %s' % (f + pySfx, why) ) else: raise error.MibLoadError('MIB file %s access error: %s' % (f + pySfx, why)) else: debug.logger & debug.flagBld and debug.logger( 'file %s mtime %d' % (f + pySfx, pyTime) ) break if pycTime != -1 and pycTime >= pyTime: # noinspection PyUnboundLocalVariable return marshal.loads(pycData), pycSfx if pyTime != -1: # noinspection PyUnboundLocalVariable return self._getData(f + pySfx, pyMode), pySfx raise IOError(ENOENT, 'No suitable module found', f)
def handle_write(self): outgoingMessage, transportAddress = self.__outQueue.pop() debug.logger & debug.flagIO and debug.logger( "handle_write: transportAddress %s outgoingMessage %s" % (transportAddress, repr(outgoingMessage)) ) try: self.socket.sendto(outgoingMessage, transportAddress) except socket.error, why: if sockErrors.has_key(why[0]): debug.logger & debug.flagIO and debug.logger("handle_write: ignoring socket error %s" % (why,)) else: raise socket.error, why
def loadModules(self, *modNames): # Build a list of available modules if not modNames: modNames = {} for mibPath in self.__mibPaths: try: for modName in os.listdir(mibPath): if modName == '__init__.py' or modName[-3:] != '.py': continue modNames[modName[:-3]] = None except OSError: continue modNames = modNames.keys() if not modNames: raise error.SmiError( 'No MIB module to load at %s' % (self,) ) for modName in modNames: for mibPath in self.__mibPaths: modPath = os.path.join( mibPath, modName + '.py' ) debug.logger & debug.flagBld and debug.logger('loadModules: trying %s' % modPath) try: open(modPath).close() except IOError, why: debug.logger & debug.flagBld and debug.logger('loadModules: open() %s' % why) continue if self.__modPathsSeen.has_key(modPath): debug.logger & debug.flagBld and debug.logger('loadModules: seen %s' % modPath) continue else: self.__modPathsSeen[modPath] = 1 g = { 'mibBuilder': self } try: execfile(modPath, g) except StandardError, why: del self.__modPathsSeen[modPath] raise error.SmiError( 'MIB module \"%s\" load error: %s' % (modPath, why) ) self.__modSeen[modName] = modPath debug.logger & debug.flagBld and debug.logger('loadModules: loaded %s' % modPath) break
def handle_write(self): outgoingMessage, transportAddress = self.__outQueue.pop() debug.logger & debug.flagIO and debug.logger('handle_write: transportAddress %r -> %r outgoingMessage %s' % (self.socket.getsockname(), transportAddress, debug.hexdump(outgoingMessage))) if not transportAddress: debug.logger & debug.flagIO and debug.logger('handle_write: missing dst address, loosing outgoing msg') return try: self.socket.sendto(outgoingMessage, transportAddress) except socket.error: if sys.exc_info()[1].args[0] in sockErrors: debug.logger & debug.flagIO and debug.logger('handle_write: ignoring socket error %s' % (sys.exc_info()[1],)) else: raise error.CarrierError('sendto() failed for %s: %s' % (transportAddress, sys.exc_info()[1]))
def __sec2usr(self, snmpEngine, securityName, securityEngineID=None): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder usmUserEngineID, = mibBuilder.importSymbols('SNMP-USER-BASED-SM-MIB', 'usmUserEngineID') if self.__paramsBranchId != usmUserEngineID.branchVersionId: usmUserName, usmUserSecurityName = mibBuilder.importSymbols( 'SNMP-USER-BASED-SM-MIB', 'usmUserName', 'usmUserSecurityName') self.__securityToUserMap = {} nextMibNode = usmUserEngineID while True: try: nextMibNode = usmUserEngineID.getNextNode(nextMibNode.name) except NoSuchInstanceError: self.__paramsBranchId = usmUserEngineID.branchVersionId debug.logger & debug.flagSM and debug.logger( '_sec2usr: built snmpEngineId + securityName to userName map, version %s: %r' % ( self.__paramsBranchId, self.__securityToUserMap)) break instId = nextMibNode.name[len(usmUserSecurityName.name):] __engineID = usmUserEngineID.getNode(usmUserEngineID.name + instId).syntax __userName = usmUserName.getNode(usmUserName.name + instId).syntax __securityName = usmUserSecurityName.getNode(usmUserSecurityName.name + instId).syntax k = __engineID, __securityName # first (lesser) securityName wins if k not in self.__securityToUserMap: self.__securityToUserMap[k] = __userName if securityEngineID is None: snmpEngineID, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') securityEngineID = snmpEngineID.syntax try: userName = self.__securityToUserMap[(securityEngineID, securityName)] except KeyError: debug.logger & debug.flagSM and debug.logger( '_sec2usr: no entry exists for snmpEngineId %r, securityName %r' % (securityEngineID, securityName)) raise NoSuchInstanceError() # emulate MIB lookup debug.logger & debug.flagSM and debug.logger( '_sec2usr: using userName %r for snmpEngineId %r, securityName %r' % ( userName, securityEngineID, securityName)) return userName
def flipFlopFsm(self, fsmTable, inputNameVals, acInfo): self.__indexMib() debug.logger & debug.flagIns and debug.logger('flipFlopFsm: inputNameVals %r' % (inputNameVals,)) mibTree, = self.mibBuilder.importSymbols('SNMPv2-SMI', 'iso') outputNameVals = [] state, status = 'start', 'ok' myErr = None while 1: k = (state, status) if k in fsmTable: fsmState = fsmTable[k] else: k = ('*', status) if k in fsmTable: fsmState = fsmTable[k] else: raise error.SmiError( 'Unresolved FSM state %s, %s' % (state, status) ) debug.logger & debug.flagIns and debug.logger('flipFlopFsm: state %s status %s -> fsmState %s' % (state, status, fsmState)) state = fsmState status = 'ok' if state == 'stop': break idx = 0 for name, val in inputNameVals: f = getattr(mibTree, state, None) if f is None: raise error.SmiError( 'Unsupported state handler %s at %s' % (state, self) ) try: # Convert to tuple to avoid ObjectName instantiation # on subscription rval = f(tuple(name), val, idx, acInfo) except error.SmiError: debug.logger & debug.flagIns and debug.logger('flipFlopFsm: fun %s failed %s for %s=%r' % (f, sys.exc_info()[1], name, val)) if myErr is None: # Take the first exception myErr = sys.exc_info()[1] status = 'err' break else: debug.logger & debug.flagIns and debug.logger('flipFlopFsm: fun %s suceeded for %s=%r' % (f, name, val)) if rval is not None: outputNameVals.append((rval[0], rval[1])) idx = idx + 1 if myErr: raise myErr return outputNameVals
def returnResponsePdu( self, snmpEngine, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, PDU, maxSizeResponseScopedPDU, stateReference, statusInformation ): """PDU dispatcher -- prepare and serialize a response""" # Extract input values and initialize defaults mpHandler = snmpEngine.messageProcessingSubsystems.get( int(messageProcessingModel) ) if mpHandler is None: raise error.StatusInformation( errorIndication='unsupportedMsgProcessingModel' ) debug.logger & debug.flagDsp and debug.logger('returnResponsePdu: PDU %s' % (PDU and PDU.prettyPrint() or "<empty>",)) # 4.1.2.2 try: ( destTransportDomain, destTransportAddress, 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, statusInformation: # 4.1.2.3 raise
def loadModules(self, *modNames, **userCtx): # Build a list of available modules if not modNames: modNames = {} for mibSource in self.__mibSources: for modName in mibSource.listdir(): modNames[modName] = None modNames = list(modNames.keys()) if not modNames: raise error.MibNotFoundError( 'No MIB module to load at %s' % (self,) ) for modName in modNames: try: self.loadModule(modName, **userCtx) except error.MibNotFoundError: if self.__mibCompiler: debug.logger & debug.flagBld and debug.logger('loadModules: calling MIB compiler for %s' % modName) status = self.__mibCompiler.compile(modName, genTexts=self.loadTexts) errs = '; '.join([hasattr(x, 'error') and str(x.error) or x for x in status.values() if x in ('failed', 'missing')]) if errs: raise error.MibNotFoundError('%s compilation error(s): %s' % (modName, errs)) # compilation suceeded, MIB might load now self.loadModule(modName, **userCtx) return self
def __expireRequest(self, snmpEngine,cachedParams,statusInformation=None): processResponsePdu, timeoutAt, cbCtx = cachedParams['expectResponse'] if statusInformation is None and time.time() < timeoutAt: return debug.logger & debug.flagDsp and debug.logger('__expireRequest: req cachedParams %s' % cachedParams) # Fail timed-out requests if not statusInformation: statusInformation = error.StatusInformation( errorIndication='requestTimedOut' ) self.releaseStateInformation( snmpEngine, cachedParams['sendPduHandle'], cachedParams['messageProcessingModel'] ) processResponsePdu( snmpEngine, None, None, None, None, None, None, None, None, statusInformation, cachedParams['sendPduHandle'], cbCtx ) return 1
def _listdir(self): try: return self._uniqNames(os.listdir(self._srcName)) except OSError: debug.logger & debug.flagBld and debug.logger( 'listdir() failed for %s: %s' % (self._srcName, sys.exc_info()[1])) return ()
def setMibSources(self, *mibSources): self.__mibSources = mibSources debug.logger & debug.flagBld and debug.logger( 'setMibPath: new MIB sources %s' % (self.__mibSources, ))
def processIncomingMsg(self, snmpEngine, messageProcessingModel, maxMessageSize, securityParameters, securityModel, securityLevel, wholeMsg, msg): # 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, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpInBadCommunityNames') snmpInBadCommunityNames.syntax += 1 raise error.StatusInformation(errorIndication=errind.unknownCommunityName) snmpEngineID, = snmpEngine.msgAndPduDsp.mibInstrumController.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.flagSM and debug.logger( 'processIncomingMsg: looked up securityName %r securityModel %r contextEngineId %r contextName %r by communityName %r AND transportInformation %r' % ( securityName, self.securityModelID, 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.flagSM and debug.logger( 'processIncomingMsg: generated maxSizeResponseScopedPDU %s securityStateReference %s' % ( maxSizeResponseScopedPDU, securityStateReference)) return (securityEngineID, securityName, scopedPDU, maxSizeResponseScopedPDU, securityStateReference)
def stopProtocol(self): debug.logger & debug.flagIO and debug.logger('stopProtocol: invoked')
def prepareDataElements(self, snmpEngine, transportDomain, transportAddress, wholeMsg): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder # rfc3412: 7.2.2 try: msg, restOfWholeMsg = decoder.decode(wholeMsg, asn1Spec=self._snmpMsgSpec) except PyAsn1Error: debug.logger & debug.flagMP and debug.logger( 'prepareDataElements: %s' % (sys.exc_info()[1], )) snmpInASNParseErrs, = mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpInASNParseErrs') snmpInASNParseErrs.syntax += 1 raise error.StatusInformation(errorIndication=errind.parseError) debug.logger & debug.flagMP 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 enpoint securityParameters = (communityName, (transportDomain, transportAddress)) messageProcessingModel = int(msg.getComponentByPosition(0)) securityModel = messageProcessingModel + 1 securityLevel = 1 # rfc3412: 7.2.4 -- 7.2.5 -> noop k = int(securityModel) if k in snmpEngine.securityModels: smHandler = snmpEngine.securityModels[k] else: 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.flagMP and debug.logger( 'prepareDataElements: SM returned securityEngineId %r securityName %r' % (securityEngineId, securityName)) # rfc3412: 7.2.6a --> noop # rfc3412: 7.2.7 contextEngineId, contextName, pdu = scopedPDU # rfc2576: 5.2.1 pduVersion = msgVersion pduType = pdu.tagSet # rfc3412: 7.2.8, 7.2.9 -> noop # rfc3412: 7.2.10 if pduType in rfc3411.responseClassPDUs: # 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.flagMP 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 -> noop # rfc3412: 7.2.12 if pduType in rfc3411.responseClassPDUs: # rfc3412: 7.2.12a -> noop # 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.confirmedClassPDUs: # 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.flagMP 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.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 pduType in rfc3411.unconfirmedClassPDUs: # 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 processIncomingMsg(self, snmpEngine, messageProcessingModel, maxMessageSize, securityParameters, securityModel, securityLevel, wholeMsg, msg): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder # 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, = mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpInASNParseErrs') 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 = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID')[0].syntax contextName = null snmpEngineID = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID')[0].syntax # 3.2.3 if msgAuthoritativeEngineId != snmpEngineID and \ msgAuthoritativeEngineId not in self.__timeline: if msgAuthoritativeEngineId and \ 4 < len(msgAuthoritativeEngineId) < 33: # 3.2.3a - cloned user when request was sent debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: unsynchronized securityEngineID %r' % (msgAuthoritativeEngineId, )) else: # 3.2.3b debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: peer requested snmpEngineID discovery' ) usmStatsUnknownEngineIDs, = mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnknownEngineIDs') usmStatsUnknownEngineIDs.syntax += 1 debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: null or malformed msgAuthoritativeEngineId' ) pysnmpUsmDiscoverable, = 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) 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: debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: unknown securityEngineID %r msgUserName %r' % (msgAuthoritativeEngineId, msgUserName)) usmStatsUnknownUserNames, = mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnknownUserNames') 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, = mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpInGenErrs') 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) snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc3414.processIncomingMsg', dict(securityEngineId=msgAuthoritativeEngineId, snmpEngineBoots=msgAuthoritativeEngineBoots, snmpEngineTime=msgAuthoritativeEngineTime, userName=usmUserName, securityName=usmUserSecurityName, authProtocol=usmUserAuthProtocol, authKey=usmUserAuthKeyLocalized, privProtocol=usmUserPrivProtocol, privKey=usmUserPrivKeyLocalized)) snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc3414.processIncomingMsg') # 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, = mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnsupportedSecLevels') 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: authHandler.authenticateIncomingMsg( usmUserAuthKeyLocalized, securityParameters.getComponentByPosition(4), wholeMsg) except error.StatusInformation: usmStatsWrongDigests, = mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsWrongDigests') 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') # synchronize time with authed peer self.__timeline[msgAuthoritativeEngineId] = ( securityParameters.getComponentByPosition(1), securityParameters.getComponentByPosition(2), securityParameters.getComponentByPosition(2), int(time.time())) timerResolution = snmpEngine.transportDispatcher is None and 1.0 or snmpEngine.transportDispatcher.getTimerResolution( ) expireAt = int(self.__expirationTimer + 300 / timerResolution) 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) = 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, = mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsNotInTimeWindows') 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 # noinspection PyUnboundLocalVariable if msgAuthoritativeEngineBoots > snmpEngineBoots or \ msgAuthoritativeEngineBoots == snmpEngineBoots and \ msgAuthoritativeEngineTime > latestReceivedEngineTime: self.__timeline[msgAuthoritativeEngineId] = ( msgAuthoritativeEngineBoots, msgAuthoritativeEngineTime, msgAuthoritativeEngineTime, int(time.time())) timerResolution = snmpEngine.transportDispatcher is None and 1.0 or snmpEngine.transportDispatcher.getTimerResolution( ) expireAt = int(self.__expirationTimer + 300 / timerResolution) 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, = mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsDecryptionErrors') 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, = mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnknownUserNames') 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 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._cache.newMsgID() debug.logger & debug.flagMP 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.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 = self._emptyStr debug.logger & debug.flagMP 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.messageProcessingModelID, 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, = 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, 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.confirmedClassPDUs: 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.flagMP 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.unconfirmedClassPDUs: 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.flagMP and debug.logger( 'prepareOutgoingMessage: force engineID discovery') else: securityEngineId = peerSnmpEngineData['securityEngineId'] debug.logger & debug.flagMP 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.messageProcessingModelID, 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.confirmedClassPDUs: # 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 processResponsePdu(self, snmpEngine, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, PDU, statusInformation, sendPduHandle, cbInfo): sendRequestHandle, cbFun, cbCtx = cbInfo # 3.3.6d if sendPduHandle not in self.__pendingReqs: raise error.ProtocolError('Missing sendPduHandle %s' % sendPduHandle) (origTransportDomain, origTransportAddress, origMessageProcessingModel, origSecurityModel, origSecurityName, origSecurityLevel, origContextEngineId, origContextName, origPdu, origTimeout, origRetryCount, origRetries, origDiscoveryRetries) = self.__pendingReqs.pop(sendPduHandle) snmpEngine.transportDispatcher.jobFinished(id(self)) if statusInformation: debug.logger & debug.flagApp and debug.logger( 'processResponsePdu: sendRequestHandle %s, sendPduHandle %s statusInformation %s' % ( sendRequestHandle, sendPduHandle, statusInformation)) errorIndication = statusInformation['errorIndication'] if errorIndication in (errind.notInTimeWindow, errind.unknownEngineID): origDiscoveryRetries += 1 origRetries = 0 else: origDiscoveryRetries = 0 origRetries += 1 if origRetries > origRetryCount or origDiscoveryRetries > self.__options.get('discoveryRetries', 4): debug.logger & debug.flagApp and debug.logger( 'processResponsePdu: sendRequestHandle %s, sendPduHandle %s retry count %d exceeded' % ( sendRequestHandle, sendPduHandle, origRetries)) cbFun(snmpEngine, sendRequestHandle, errorIndication, None, cbCtx) return # Convert timeout in seconds into timeout in timer ticks timeoutInTicks = float(origTimeout) / 100 / snmpEngine.transportDispatcher.getTimerResolution() # User-side API assumes SMIv2 if messageProcessingModel == 0: reqPDU = rfc2576.v2ToV1(origPdu) pduVersion = 0 else: reqPDU = origPdu pduVersion = 1 # 3.3.6a try: sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu( snmpEngine, origTransportDomain, origTransportAddress, origMessageProcessingModel, origSecurityModel, origSecurityName, origSecurityLevel, origContextEngineId, origContextName, pduVersion, reqPDU, True, timeoutInTicks, self.processResponsePdu, (sendRequestHandle, cbFun, cbCtx) ) except error.StatusInformation: statusInformation = sys.exc_info()[1] debug.logger & debug.flagApp and debug.logger( 'processResponsePdu: sendRequestHandle %s: sendPdu() failed with %r ' % ( sendRequestHandle, statusInformation)) cbFun(snmpEngine, sendRequestHandle, statusInformation['errorIndication'], None, cbCtx) return snmpEngine.transportDispatcher.jobStarted(id(self)) debug.logger & debug.flagApp and debug.logger( 'processResponsePdu: sendRequestHandle %s, sendPduHandle %s, timeout %d, retry %d of %d' % ( sendRequestHandle, sendPduHandle, origTimeout, origRetries, origRetryCount)) # 3.3.6b self.__pendingReqs[sendPduHandle] = ( origTransportDomain, origTransportAddress, origMessageProcessingModel, origSecurityModel, origSecurityName, origSecurityLevel, origContextEngineId, origContextName, origPdu, origTimeout, origRetryCount, origRetries, origDiscoveryRetries ) return # 3.3.6c # User-side API assumes SMIv2 if messageProcessingModel == 0: PDU = rfc2576.v1ToV2(PDU, origPdu) cbFun(snmpEngine, sendRequestHandle, None, PDU, cbCtx)
def prepareDataElements(self, snmpEngine, transportDomain, transportAddress, wholeMsg): # 7.2.2 msg, restOfwholeMsg = decoder.decode(wholeMsg, asn1Spec=self._snmpMsgSpec) debug.logger & debug.flagMP and debug.logger( 'prepareDataElements: %s' % (msg.prettyPrint(), )) if eoo.endOfOctets.isSameTypeWith(msg): raise error.StatusInformation(errorIndication=errind.parseError) # 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.flagMP 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, = snmpEngine.msgAndPduDsp.mibInstrumController.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, = snmpEngine.msgAndPduDsp.mibInstrumController.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.flagMP and debug.logger( 'prepareDataElements: SM succeeded') except error.StatusInformation: statusInformation, origTraceback = sys.exc_info()[1:3] debug.logger & debug.flagMP 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.flagMP and debug.logger( 'prepareDataElements: error reported') # 7.2.6b if sys.version_info[0] <= 2: raise statusInformation else: 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.internalClassPDUs: self.__engineIdCache[k] = { 'securityEngineId': securityEngineId, 'contextEngineId': contextEngineId, 'contextName': contextName } expireAt = int( self.__expirationTimer + 300 / snmpEngine.transportDispatcher.getTimerResolution()) if expireAt not in self.__engineIdCacheExpQueue: self.__engineIdCacheExpQueue[expireAt] = [] self.__engineIdCacheExpQueue[expireAt].append(k) debug.logger & debug.flagMP and debug.logger( 'prepareDataElements: cache securityEngineId %r for %r %r' % (securityEngineId, transportDomain, transportAddress)) snmpEngineID, = snmpEngine.msgAndPduDsp.mibInstrumController.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.protoVersion2c # 7.2.9 pduType = pdu.tagSet # 7.2.10 if (pduType in rfc3411.responseClassPDUs or pduType in rfc3411.internalClassPDUs): # 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.flagMP and debug.logger( 'prepareDataElements: using sendPduHandle %s for msgID %s' % (sendPduHandle, msgID)) # 7.2.11 if pduType in rfc3411.internalClassPDUs: # 7.2.11a varBinds = pMod.apiPDU.getVarBinds(pdu) if varBinds: statusInformation = error.StatusInformation( errorIndication=_snmpErrors.get( varBinds[0][0], errind.ReportPduReceived( varBinds[0][0].prettyPrint())), 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.responseClassPDUs: # 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.confirmedClassPDUs: # 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.flagMP 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.unconfirmedClassPDUs: # 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 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._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.flagMP 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.confirmedClassPDUs): 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.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 = self._emptyStr debug.logger & debug.flagMP 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.messageProcessingModelID, 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, = 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, 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.confirmedClassPDUs: # 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.flagMP 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.flagMP 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.messageProcessingModelID, msg, snmpEngineMaxMessageSize.syntax, securityModel, snmpEngineID, securityName, securityLevel, scopedPDU, securityStateReference) except error.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=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 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.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=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.flagMP 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.messageProcessingModelID, 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 v1ToV2(v1Pdu, origV2Pdu=None): pduType = v1Pdu.tagSet v2Pdu = __v1ToV2PduMap[pduType].clone() debug.logger & debug.flagPrx and debug.logger( 'v1ToV2: v1Pdu %s' % v1Pdu.prettyPrint()) v2VarBinds = [] # 3.1 if pduType in rfc3411.notificationClassPDUs: # 3.1.1 sysUpTime = v1.apiTrapPDU.getTimeStamp(v1Pdu) # 3.1.2 genericTrap = v1.apiTrapPDU.getGenericTrap(v1Pdu) if genericTrap == 6: snmpTrapOIDParam = v1.apiTrapPDU.getEnterprise(v1Pdu) + ( 0, int(v1.apiTrapPDU.getSpecificTrap(v1Pdu))) # 3.1.3 else: snmpTrapOIDParam = v2c.ObjectIdentifier( __v1ToV2TrapMap[genericTrap]) # 3.1.4 (XXX snmpTrapCommunity.0 is missing here) v2VarBinds.append((v2c.apiTrapPDU.sysUpTime, sysUpTime)) v2VarBinds.append((v2c.apiTrapPDU.snmpTrapOID, snmpTrapOIDParam)) v2VarBinds.append((v2c.apiTrapPDU.snmpTrapAddress, v1.apiTrapPDU.getAgentAddr(v1Pdu))) v2VarBinds.append( (v2c.apiTrapPDU.snmpTrapCommunity, v2c.OctetString(""))) v2VarBinds.append((v2c.apiTrapPDU.snmpTrapEnterprise, v1.apiTrapPDU.getEnterprise(v1Pdu))) varBinds = v1.apiTrapPDU.getVarBinds(v1Pdu) else: varBinds = v1.apiPDU.getVarBinds(v1Pdu) # Translate Var-Binds for oid, v1Val in varBinds: # 2.1.1.11 if v1Val.tagSet == v1.NetworkAddress.tagSet: v1Val = v1Val.getComponent() v2VarBinds.append((oid, __v1ToV2ValueMap[v1Val.tagSet].clone(v1Val))) if pduType in rfc3411.responseClassPDUs: # 4.1.2.2.1&2 errorStatus = int(v1.apiPDU.getErrorStatus(v1Pdu)) errorIndex = int(v1.apiPDU.getErrorIndex(v1Pdu, muteErrors=True)) if errorStatus == 2: # noSuchName if origV2Pdu.tagSet == v2c.GetNextRequestPDU.tagSet: v2VarBinds = [(o, rfc1905.endOfMibView) for o, v in v2VarBinds] else: v2VarBinds = [(o, rfc1905.noSuchObject) for o, v in v2VarBinds] v2c.apiPDU.setErrorStatus(v2Pdu, 0) v2c.apiPDU.setErrorIndex(v2Pdu, 0) else: # partial one-to-one mapping - 4.2.1 v2c.apiPDU.setErrorStatus(v2Pdu, errorStatus) v2c.apiPDU.setErrorIndex(v2Pdu, errorIndex) # 4.1.2.1 --> no-op elif pduType in rfc3411.confirmedClassPDUs: v2c.apiPDU.setErrorStatus(v2Pdu, 0) v2c.apiPDU.setErrorIndex(v2Pdu, 0) if pduType not in rfc3411.notificationClassPDUs: v2c.apiPDU.setRequestID(v2Pdu, int(v1.apiPDU.getRequestID(v1Pdu))) v2c.apiPDU.setVarBinds(v2Pdu, v2VarBinds) debug.logger & debug.flagPrx and debug.logger( 'v1ToV2: v2Pdu %s' % v2Pdu.prettyPrint()) return v2Pdu
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')
def __init__(self, **kwargs): SnmpV3Error.__init__(self) self.__errorIndication = kwargs debug.logger & (debug.flagDsp | debug.flagMP | debug.flagSM) and debug.logger( 'StatusInformation: %s' % kwargs)
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): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder snmpEngineId, = mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') snmpEngineId = snmpEngineId.syntax # rfc3412: 7.1.1b if pdu.tagSet in rfc3411.confirmedClassPDUs: # serve unique PDU request-id pdu.setComponentByPosition(1) msgID = self._cache.newMsgID() reqID = pdu.getComponentByPosition(0) debug.logger & debug.flagMP 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.flagMP 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.messageProcessingModelID) msg.setComponentByPosition(2) msg.getComponentByPosition(2).setComponentByType( pdu.tagSet, pdu, verifyConstraints=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.confirmedClassPDUs: # noinspection PyUnboundLocalVariable pdu.setComponentByPosition(0, msgID) # rfc3412: 7.1.9.b (securityParameters, wholeMsg) = smHandler.generateRequestMsg( snmpEngine, self.messageProcessingModelID, globalData, snmpEngineMaxMessageSize.syntax, securityModel, snmpEngineId, securityName, securityLevel, scopedPDU) # return original request-id right after PDU serialization if pdu.tagSet in rfc3411.confirmedClassPDUs: # noinspection PyUnboundLocalVariable pdu.setComponentByPosition(0, reqID) # rfc3412: 7.1.9.c if pdu.tagSet in rfc3411.confirmedClassPDUs: # 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 _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 processPdu(self, snmpEngine, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, PDU, maxSizeResponseScopedPDU, stateReference): # Agent-side API complies with SMIv2 if messageProcessingModel == 0: origPdu = PDU PDU = rfc2576.v1ToV2(PDU, snmpTrapCommunity=self.__snmpTrapCommunity) else: origPdu = None errorStatus = 'noError' errorIndex = 0 varBinds = v2c.apiPDU.getVarBinds(PDU) debug.logger & debug.flagApp and debug.logger( 'processPdu: stateReference %s, varBinds %s' % (stateReference, varBinds)) # 3.4 if PDU.tagSet in rfc3411.confirmedClassPDUs: # 3.4.1 --> no-op rspPDU = v2c.apiPDU.getResponse(PDU) # 3.4.2 v2c.apiPDU.setErrorStatus(rspPDU, errorStatus) v2c.apiPDU.setErrorIndex(rspPDU, errorIndex) v2c.apiPDU.setVarBinds(rspPDU, varBinds) debug.logger & debug.flagApp and debug.logger( 'processPdu: stateReference %s, confirm PDU %s' % (stateReference, rspPDU.prettyPrint())) # Agent-side API complies with SMIv2 if messageProcessingModel == 0: rspPDU = rfc2576.v2ToV1(rspPDU, origPdu) statusInformation = {} # 3.4.3 try: snmpEngine.msgAndPduDsp.returnResponsePdu( snmpEngine, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, rspPDU, maxSizeResponseScopedPDU, stateReference, statusInformation) except error.StatusInformation: debug.logger & debug.flagApp and debug.logger( 'processPdu: stateReference %s, statusInformation %s' % (stateReference, sys.exc_info()[1])) snmpSilentDrops, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpSilentDrops') snmpSilentDrops.syntax += 1 elif PDU.tagSet in rfc3411.unconfirmedClassPDUs: pass else: raise error.ProtocolError('Unexpected PDU class %s' % PDU.tagSet) debug.logger & debug.flagApp and debug.logger( 'processPdu: stateReference %s, user cbFun %s, cbCtx %s, varBinds %s' % (stateReference, self.__cbFun, self.__cbCtx, varBinds)) if self.__cbFunVer: self.__cbFun(snmpEngine, stateReference, contextEngineId, contextName, varBinds, self.__cbCtx) else: # Compatibility stub (handle legacy cbFun interface) try: self.__cbFun(snmpEngine, contextEngineId, contextName, varBinds, self.__cbCtx) except TypeError: self.__cbFunVer = 1 self.__cbFun(snmpEngine, stateReference, contextEngineId, contextName, varBinds, self.__cbCtx)
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 __generateRequestOrResponseMsg(self, snmpEngine, messageProcessingModel, globalData, maxMessageSize, securityModel, securityEngineID, securityName, securityLevel, scopedPDU, securityStateReference): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder snmpEngineID = 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, = 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 = True 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( '__generateRequestOrResponseMsg: %s' % (sys.exc_info()[1], )) snmpInGenErrs, = mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpInGenErrs') 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') # noinspection PyUnboundLocalVariable 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 securityLevel in (2, 3): 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) = 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)) # noinspection PyUnboundLocalVariable (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) # noinspection PyUnboundLocalVariable 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 addMibSources(self, *mibSources): self.__mibSources.extend([s.init() for s in mibSources]) debug.logger & debug.flagBld and debug.logger('addMibSources: new MIB sources %s' % (self.__mibSources,))
def connection_lost(self, exc): debug.logger & debug.flagIO and debug.logger('connection_lost: invoked')
def sendPdu(self, snmpEngine, targetName, contextEngineId, contextName, pdu, cbFun=None, cbCtx=None): (transportDomain, transportAddress, timeout, retryCount, params) = config.getTargetAddr(snmpEngine, targetName) (messageProcessingModel, securityModel, securityName, securityLevel) = config.getTargetParams(snmpEngine, params) # User-side API assumes SMIv2 if messageProcessingModel == 0: reqPDU = rfc2576.v2ToV1(pdu) pduVersion = 0 else: reqPDU = pdu pduVersion = 1 # 3.3.5 if reqPDU.tagSet in rfc3411.confirmedClassPDUs: # Convert timeout in seconds into timeout in timer ticks timeoutInTicks = float( timeout ) / 100 / snmpEngine.transportDispatcher.getTimerResolution() sendRequestHandle = getNextHandle() # 3.3.6a sendPduHandle = snmpEngine.msgAndPduDsp.sendPdu( snmpEngine, transportDomain, transportAddress, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, reqPDU, True, timeoutInTicks, self.processResponsePdu, (sendRequestHandle, cbFun, cbCtx)) debug.logger & debug.flagApp and debug.logger( 'sendPdu: sendPduHandle %s, timeout %d' % (sendPduHandle, timeout)) # 3.3.6b self.__pendingReqs[sendPduHandle] = (transportDomain, transportAddress, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pdu, timeout, retryCount, 0, 0) snmpEngine.transportDispatcher.jobStarted(id(self)) else: snmpEngine.msgAndPduDsp.sendPdu( snmpEngine, transportDomain, transportAddress, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, reqPDU, False) sendRequestHandle = None debug.logger & debug.flagApp and debug.logger( 'sendPdu: message sent') return sendRequestHandle
def setMibSources(self, *mibSources): self.__mibSources = [s.init() for s in mibSources] debug.logger & debug.flagBld and debug.logger('setMibSources: new MIB sources %s' % (self.__mibSources,))
def processIncomingMsg( self, snmpEngine, messageProcessingModel, maxMessageSize, securityParameters, securityModel, securityLevel, wholeMsg, msg # XXX ): # 3.2.1 try: securityParameters, rest = decoder.decode( securityParameters, asn1Spec=self._securityParametersSpec) except PyAsn1Error: snmpInASNParseErrs, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpInASNParseErrs') snmpInASNParseErrs.syntax = snmpInASNParseErrs.syntax + 1 raise error.StatusInformation(errorIndication='parseError') debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: %s' % (securityParameters.prettyPrint(), )) # 3.2.9 -- moved up here to be able to report # maxSizeResponseScopedPDU on error maxSizeResponseScopedPDU = maxMessageSize - 512 # XXX if maxSizeResponseScopedPDU < 0: maxSizeResponseScopedPDU = 0 # 3.2.2 securityEngineID = securityParameters.getComponentByPosition(0) securityStateReference = self._cachePush( msgUserName=securityParameters.getComponentByPosition(3)) debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: cache read securityStateReference %s by msgUserName %s' % (securityStateReference, securityParameters.getComponentByPosition(3))) # Used for error reporting contextEngineId = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineID')[0].syntax contextName = '' # 3.2.3 if not self.__timeline.has_key(securityEngineID): debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: unknown securityEngineID %s' % securityEngineID) if securityEngineID: # 3.2.3a XXX any other way to get auth engine in cache? self.__timeline[securityEngineID] = ( securityParameters.getComponentByPosition(1), securityParameters.getComponentByPosition(2), securityParameters.getComponentByPosition(2), int(time.time())) expireAt = self.__expirationTimer + 300 if not self.__timelineExpQueue.has_key(expireAt): self.__timelineExpQueue[expireAt] = [] self.__timelineExpQueue[expireAt].append(securityEngineID) debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: store timeline for securityEngineID %s' % (securityEngineID, )) else: # 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 securityEngineID') pysnmpUsmDiscoverable, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__PYSNMP-USM-MIB', 'pysnmpUsmDiscoverable') if pysnmpUsmDiscoverable.syntax: debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: request EngineID discovery') raise error.StatusInformation( errorIndication='unknownEngineID', oid=usmStatsUnknownEngineIDs.name, val=usmStatsUnknownEngineIDs.syntax, securityStateReference=securityStateReference, contextEngineId=contextEngineId, contextName=contextName, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU) else: debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: will not discover EngineID') # free securityStateReference XXX raise error.StatusInformation( errorIndication='unknownEngineID') snmpEngineID = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineID')[0].syntax msgAuthoritativeEngineID = securityParameters.getComponentByPosition(0) msgUserName = securityParameters.getComponentByPosition(3) debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: read from securityParams msgAuthoritativeEngineID %s msgUserName %s' % (msgAuthoritativeEngineID, msgUserName)) if msgUserName: # 3.2.4 try: (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: (usmUserSecurityName, usmUserAuthProtocol, usmUserAuthKeyLocalized, usmUserPrivProtocol, usmUserPrivKeyLocalized) = self.__cloneUserInfo( snmpEngine.msgAndPduDsp.mibInstrumController, securityEngineID, 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 %s msgUserName %s' % (securityEngineID, msgUserName)) if __reportUnknownName: usmStatsUnknownUserNames, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnknownUserNames') usmStatsUnknownUserNames.syntax = usmStatsUnknownUserNames.syntax + 1 raise error.StatusInformation( errorIndication='unknownSecurityName', oid=usmStatsUnknownUserNames.name, val=usmStatsUnknownUserNames.syntax, securityStateReference=securityStateReference, contextEngineId=contextEngineId, contextName=contextName, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU) else: # empty username used for engineID discovery usmUserName = usmUserSecurityName = '' usmUserAuthProtocol = usmUserAuthKeyLocalized = None usmUserPrivProtocol = usmUserPrivKeyLocalized = None debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: now have usmUserSecurityName %s usmUserAuthProtocol %s usmUserPrivProtocol %s for msgUserName %s' % (usmUserSecurityName, usmUserAuthProtocol, usmUserPrivProtocol, msgUserName)) # 3.2.5 __reportError = 0 if securityLevel == 3: if not usmUserAuthProtocol or not usmUserPrivProtocol: __reportError = 1 elif securityLevel == 2: if not usmUserAuthProtocol: __reportError = 1 if __reportError: usmStatsUnsupportedSecLevels, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnsupportedSecLevels') usmStatsUnsupportedSecLevels.syntax = usmStatsUnsupportedSecLevels.syntax + 1 raise error.StatusInformation( errorIndication='unsupportedSecurityLevel', oid=usmStatsUnknownEngineIDs.name, val=usmStatsUnknownEngineIDs.syntax, securityStateReference=securityStateReference, contextEngineId=contextEngineId, contextName=contextName, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU) # 3.2.6 if securityLevel == 3 or securityLevel == 2: authHandler = self.authServices.get(usmUserAuthProtocol) if authHandler is None: raise error.StatusInformation( errorIndication='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='authenticationFailure', oid=usmStatsWrongDigests.name, val=usmStatsWrongDigests.syntax, securityStateReference=securityStateReference, contextEngineId=contextEngineId, contextName=contextName, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU) debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: incoming msg authed') # 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 self.__timeline.has_key(securityEngineID): (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 %s, idle time %s secs' % (snmpEngineBoots, snmpEngineTime, msgAuthoritativeEngineID, idleTime)) else: raise error.ProtocolError('Peer SNMP engine info missing') msgAuthoritativeEngineBoots = securityParameters.getComponentByPosition( 1) msgAuthoritativeEngineTime = securityParameters.getComponentByPosition( 2) # 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='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())) debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: stored timeline msgAuthoritativeEngineBoots %s msgAuthoritativeEngineTime %s for msgAuthoritativeEngineID %s' % (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='notInTimeWindow') scopedPduData = msg.getComponentByPosition(3) # 3.2.8a if securityLevel == 3: privHandler = self.privServices.get(usmUserPrivProtocol) if privHandler is None: raise error.StatusInformation( errorIndication='decryptionError') encryptedPDU = scopedPduData.getComponentByPosition(1) if encryptedPDU is None: # no ciphertext raise error.StatusInformation( errorIndication='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') except error.StatusInformation: usmStatsDecryptionErrors, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsDecryptionErrors') usmStatsDecryptionErrors.syntax = usmStatsDecryptionErrors.syntax + 1 raise error.StatusInformation( errorIndication='decryptionError', oid=usmStatsDecryptionErrors.name, val=usmStatsDecryptionErrors.syntax, securityStateReference=securityStateReference, contextEngineId=contextEngineId, contextName=contextName, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU) scopedPduSpec = scopedPduData.setComponentByPosition( 0).getComponentByPosition(0) try: scopedPDU, rest = decoder.decode(decryptedData, asn1Spec=scopedPduSpec) except PyAsn1Error as why: debug.logger & debug.flagSM and debug.logger( 'processIncomingMsg: PDU decoder failed %s' % why) raise error.StatusInformation( errorIndication='decryptionError') else: # 3.2.8b scopedPDU = scopedPduData.getComponentByPosition(0) if scopedPDU is None: # no plaintext raise error.StatusInformation( errorIndication='decryptionError') # 3.2.10 securityName = usmUserSecurityName # 3.2.11 self._cachePop(securityStateReference) securityStateReference = self._cachePush( msgUserName=securityParameters.getComponentByPosition(3), usmUserAuthProtocol=usmUserAuthProtocol, usmUserAuthKeyLocalized=usmUserAuthKeyLocalized, usmUserPrivProtocol=usmUserPrivProtocol, usmUserPrivKeyLocalized=usmUserPrivKeyLocalized) 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 securityEngineID: usmStatsUnknownUserNames, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-USER-BASED-SM-MIB', 'usmStatsUnknownUserNames') usmStatsUnknownUserNames.syntax = usmStatsUnknownUserNames.syntax + 1 raise error.StatusInformation( errorIndication='unknownSecurityName', oid=usmStatsUnknownUserNames.name, val=usmStatsUnknownUserNames.syntax, securityStateReference=securityStateReference, securityEngineID=securityEngineID, contextEngineId=contextEngineId, contextName=contextName, maxSizeResponseScopedPDU=maxSizeResponseScopedPDU, PDU=scopedPDU) # 3.2.12 return (securityEngineID, securityName, scopedPDU, maxSizeResponseScopedPDU, securityStateReference)
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 1: 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 1: 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 1: try: nextMibNode = snmpCommunityName.getNextNode( nextMibNode.name) except NoSuchInstanceError: break instId = nextMibNode.name[len(snmpCommunityName.name):] securityName = snmpCommunitySecurityName.getNode( snmpCommunitySecurityName.name + instId).syntax # Filter community table by security model # *if* there are conflicting security names if securityName in self.__nameToModelMap and \ self.securityModelID not in self.__nameToModelMap[securityName]: continue contextEngineId = snmpCommunityContextEngineId.getNode( snmpCommunityContextEngineId.name + instId).syntax contextName = snmpCommunityContextName.getNode( snmpCommunityContextName.name + instId).syntax transportTag = snmpCommunityTransportTag.getNode( snmpCommunityTransportTag.name + instId).syntax self.__tagAndCommunityToSecurityMap[( transportTag, nextMibNode.syntax)] = (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 self.__emptyTag in self.__communityToTagMap[communityName]: return self.__tagAndCommunityToSecurityMap[(self.__emptyTag, communityName)] if transportInformation in self.__transportToTagMap: tags = self.__transportToTagMap[ transportInformation].intersection( self.__communityToTagMap[communityName]) if tags: return self.__tagAndCommunityToSecurityMap[(tags.pop(), communityName)] raise error.StatusInformation()
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._cachePop(securityStateReference) usmUserName = cachedSecurityData['msgUserName'] usmUserAuthProtocol = cachedSecurityData.get('usmUserAuthProtocol') usmUserAuthKeyLocalized = cachedSecurityData.get( 'usmUserAuthKeyLocalized') usmUserPrivProtocol = cachedSecurityData.get('usmUserPrivProtocol') usmUserPrivKeyLocalized = cachedSecurityData.get( 'usmUserPrivKeyLocalized') securityEngineID = snmpEngineID debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: user info read from cache') elif securityName: # 3.1.1b try: (usmUserName, usmUserAuthProtocol, usmUserAuthKeyLocalized, usmUserPrivProtocol, usmUserPrivKeyLocalized) = self.__getUserInfo( snmpEngine.msgAndPduDsp.mibInstrumController, securityEngineID, securityName) 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, usmUserAuthProtocol, usmUserAuthKeyLocalized, usmUserPrivProtocol, usmUserPrivKeyLocalized) = self.__cloneUserInfo( snmpEngine.msgAndPduDsp.mibInstrumController, securityEngineID, securityName) except NoSuchInstanceError: __reportUnknownName = 1 if __reportUnknownName: raise error.StatusInformation( errorIndication='unknownSecurityName') debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: clone user info') else: # empty username used for engineID discovery usmUserName = usmUserSecurityName = '' usmUserAuthProtocol = usmUserAuthKeyLocalized = None usmUserPrivProtocol = usmUserPrivKeyLocalized = None debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: use empty USM data') debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: local user usmUserName %s usmUserAuthProtocol %s usmUserPrivProtocol %s by securityEngineID %s securityName %s' % (usmUserName, usmUserAuthProtocol, usmUserPrivProtocol, securityEngineID, securityName)) msg = globalData # 3.1.2 if securityLevel == 3: if not usmUserAuthProtocol or not usmUserPrivProtocol: raise error.StatusInformation( errorIndication='unsupportedSecurityLevel') # 3.1.3 if securityLevel == 3 or securityLevel == 2: if not usmUserAuthProtocol: raise error.StatusInformation( errorIndication='unsupportedSecurityLevel') securityParameters = UsmSecurityParameters() scopedPDUData = msg.setComponentByPosition(3).getComponentByPosition(3) scopedPDUData.setComponentByPosition(0, scopedPDU) # 3.1.6a if securityStateReference is None and ( # request type check added securityLevel == 3 or securityLevel == 2): if self.__timeline.has_key(securityEngineID): (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 %s' % 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 %s' % (snmpEngineBoots, snmpEngineTime, securityEngineID)) # 3.1.4a if securityLevel == 3: privHandler = self.privServices.get(usmUserPrivProtocol) if privHandler is None: raise error.StatusInformation( errorIndication='encryptionError') dataToEncrypt = encoder.encode(scopedPDU) debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: scopedPDU encoded') try: (encryptedData, privParameters) = privHandler.encryptData( usmUserPrivKeyLocalized, (snmpEngineBoots, snmpEngineTime, None), dataToEncrypt) except error.StatusInformation as statusInformation: raise securityParameters.setComponentByPosition(5, privParameters) scopedPDUData.setComponentByPosition(1, encryptedData) debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: scopedPDU ciphered') # 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) securityParameters.setComponentByPosition(1, snmpEngineBoots) securityParameters.setComponentByPosition(2, snmpEngineTime) # 3.1.7 securityParameters.setComponentByPosition(3, usmUserName) # 3.1.8a if securityLevel == 3 or securityLevel == 2: authHandler = self.authServices.get(usmUserAuthProtocol) if authHandler is None: raise error.StatusInformation( errorIndication='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(), )) msg.setComponentByPosition(2, encoder.encode(securityParameters)) wholeMsg = encoder.encode(msg) try: authenticatedWholeMsg = authHandler.authenticateOutgoingMsg( usmUserAuthKeyLocalized, wholeMsg) except error.StatusInformation as statusInformation: raise debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: auth outgoing msg') # 3.1.8b else: securityParameters.setComponentByPosition(4, '') debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: %s' % (securityParameters.prettyPrint(), )) msg.setComponentByPosition(2, encoder.encode(securityParameters)) authenticatedWholeMsg = encoder.encode(msg) debug.logger & debug.flagSM and debug.logger( '__generateRequestOrResponseMsg: plain outgoing msg') # 3.1.9 return (msg.getComponentByPosition(2), authenticatedWholeMsg)
def sendVarBinds(self, snmpEngine, notificationTarget, contextEngineId, contextName, varBinds=(), cbFun=None, cbCtx=None): debug.logger & debug.flagApp and debug.logger( 'sendVarBinds: notificationTarget %s, contextEngineId %s, contextName "%s", varBinds %s' % ( notificationTarget, contextEngineId or '<default>', contextName, varBinds)) if contextName: __SnmpAdminString, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( 'SNMP-FRAMEWORK-MIB', 'SnmpAdminString') contextName = __SnmpAdminString(contextName) # 3.3 (notifyTag, notifyType) = config.getNotificationInfo(snmpEngine, notificationTarget) notificationHandle = getNextHandle() debug.logger & debug.flagApp and debug.logger( 'sendVarBinds: notificationHandle %s, notifyTag %s, notifyType %s' % ( notificationHandle, notifyTag, notifyType)) varBinds = [(v2c.ObjectIdentifier(x), y) for x, y in varBinds] # 3.3.2 & 3.3.3 snmpTrapOID, sysUpTime = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMPv2-MIB', 'snmpTrapOID', 'sysUpTime') for idx in range(len(varBinds)): if idx and varBinds[idx][0] == sysUpTime.getName(): if varBinds[0][0] == sysUpTime.getName(): varBinds[0] = varBinds[idx] else: varBinds.insert(0, varBinds[idx]) del varBinds[idx] if varBinds[0][0] != sysUpTime.getName(): varBinds.insert(0, (v2c.ObjectIdentifier(sysUpTime.getName()), sysUpTime.getSyntax().clone())) if len(varBinds) < 2 or varBinds[1][0] != snmpTrapOID.getName(): varBinds.insert(1, (v2c.ObjectIdentifier(snmpTrapOID.getName()), snmpTrapOID.getSyntax())) sendRequestHandle = -1 debug.logger & debug.flagApp and debug.logger('sendVarBinds: final varBinds %s' % (varBinds,)) for targetAddrName in config.getTargetNames(snmpEngine, notifyTag): (transportDomain, transportAddress, timeout, retryCount, params) = config.getTargetAddr(snmpEngine, targetAddrName) (messageProcessingModel, securityModel, securityName, securityLevel) = config.getTargetParams(snmpEngine, params) # 3.3.1 XXX # XXX filtering's yet to be implemented # filterProfileName = config.getNotifyFilterProfile(params) # (filterSubtree, filterMask, # filterType) = config.getNotifyFilter(filterProfileName) debug.logger & debug.flagApp and debug.logger( 'sendVarBinds: notificationHandle %s, notifyTag %s yields: transportDomain %s, transportAddress %r, securityModel %s, securityName %s, securityLevel %s' % ( notificationHandle, notifyTag, transportDomain, transportAddress, securityModel, securityName, securityLevel)) for varName, varVal in varBinds: if varName in (sysUpTime.name, snmpTrapOID.name): continue try: snmpEngine.accessControlModel[self.acmID].isAccessAllowed( snmpEngine, securityModel, securityName, securityLevel, 'notify', contextName, varName ) debug.logger & debug.flagApp and debug.logger( 'sendVarBinds: ACL succeeded for OID %s securityName %s' % (varName, securityName)) except error.StatusInformation: debug.logger & debug.flagApp and debug.logger( 'sendVarBinds: ACL denied access for OID %s securityName %s, droppping notification' % ( varName, securityName)) return # 3.3.4 if notifyType == 1: pdu = v2c.SNMPv2TrapPDU() elif notifyType == 2: pdu = v2c.InformRequestPDU() else: raise error.ProtocolError('Unknown notify-type %r', notifyType) v2c.apiPDU.setDefaults(pdu) v2c.apiPDU.setVarBinds(pdu, varBinds) # 3.3.5 try: sendRequestHandle = self.sendPdu( snmpEngine, targetAddrName, contextEngineId, contextName, pdu, self.processResponseVarBinds, (notificationHandle, cbFun, cbCtx) ) except error.StatusInformation: statusInformation = sys.exc_info()[1] debug.logger & debug.flagApp and debug.logger( 'sendVarBinds: sendRequestHandle %s: sendPdu() failed with %r' % ( sendRequestHandle, statusInformation)) if notificationHandle not in self.__pendingNotifications or \ not self.__pendingNotifications[notificationHandle]: if notificationHandle in self.__pendingNotifications: del self.__pendingNotifications[notificationHandle] if cbFun: cbFun(snmpEngine, notificationHandle, statusInformation['errorIndication'], 0, 0, (), cbCtx) return notificationHandle debug.logger & debug.flagApp and debug.logger( 'sendVarBinds: notificationHandle %s, sendRequestHandle %s, timeout %d' % ( notificationHandle, sendRequestHandle, timeout)) if notifyType == 2: if notificationHandle not in self.__pendingNotifications: self.__pendingNotifications[notificationHandle] = set() self.__pendingNotifications[notificationHandle].add(sendRequestHandle) debug.logger & debug.flagApp and debug.logger( 'sendVarBinds: notificationHandle %s, sendRequestHandle %s, notification(s) sent' % ( notificationHandle, sendRequestHandle)) return notificationHandle
def receiveMessage(self, snmpEngine, transportDomain, transportAddress, wholeMsg): """Message dispatcher -- de-serialize message into PDU""" # 4.2.1.1 snmpInPkts, = self.mibInstrumController.mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpInPkts') snmpInPkts.syntax += 1 # 4.2.1.2 try: restOfWholeMsg = null # XXX fix decoder non-recursive return msgVersion = verdec.decodeMessageVersion(wholeMsg) except error.ProtocolError: snmpInASNParseErrs, = self.mibInstrumController.mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpInASNParseErrs') snmpInASNParseErrs.syntax += 1 return null # n.b the whole buffer gets dropped debug.logger & debug.flagDsp and debug.logger( 'receiveMessage: msgVersion %s, msg decoded' % msgVersion) messageProcessingModel = msgVersion try: mpHandler = snmpEngine.messageProcessingSubsystems[int( messageProcessingModel)] except KeyError: snmpInBadVersions, = self.mibInstrumController.mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpInBadVersions') snmpInBadVersions.syntax += 1 return restOfWholeMsg # 4.2.1.3 -- no-op # 4.2.1.4 try: (messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, PDU, pduType, sendPduHandle, maxSizeResponseScopedPDU, statusInformation, stateReference) = mpHandler.prepareDataElements( snmpEngine, transportDomain, transportAddress, wholeMsg) debug.logger & debug.flagDsp and debug.logger( 'receiveMessage: MP succeded') except error.StatusInformation: statusInformation = sys.exc_info()[1] if 'sendPduHandle' in statusInformation: # Dropped REPORT -- re-run pending reqs queue as some # of them may be waiting for this REPORT debug.logger & debug.flagDsp and debug.logger( 'receiveMessage: MP failed, statusInformation %s, forcing a retry' % statusInformation) self.__expireRequest( statusInformation['sendPduHandle'], self.__cache.pop(statusInformation['sendPduHandle']), snmpEngine, statusInformation) return restOfWholeMsg except PyAsn1Error: debug.logger & debug.flagMP and debug.logger('receiveMessage: %s' % (sys.exc_info()[1], )) snmpInASNParseErrs, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMPv2-MIB', 'snmpInASNParseErrs') snmpInASNParseErrs.syntax += 1 return restOfWholeMsg debug.logger & debug.flagDsp and debug.logger( 'receiveMessage: PDU %s' % PDU.prettyPrint()) # 4.2.2 if sendPduHandle is None: # 4.2.2.1 (request or notification) debug.logger & debug.flagDsp and debug.logger( 'receiveMessage: pduType %s' % pduType) # 4.2.2.1.1 processPdu = self.getRegisteredApp(contextEngineId, pduType) # 4.2.2.1.2 if processPdu is None: # 4.2.2.1.2.a snmpUnknownPDUHandlers, = self.mibInstrumController.mibBuilder.importSymbols( '__SNMP-MPD-MIB', 'snmpUnknownPDUHandlers') snmpUnknownPDUHandlers.syntax += 1 # 4.2.2.1.2.b statusInformation = { 'errorIndication': errind.unknownPDUHandler, 'oid': snmpUnknownPDUHandlers.name, 'val': snmpUnknownPDUHandlers.syntax } debug.logger & debug.flagDsp and debug.logger( 'receiveMessage: unhandled PDU type') # 4.2.2.1.2.c try: (destTransportDomain, destTransportAddress, outgoingMessage) = mpHandler.prepareResponseMessage( snmpEngine, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, PDU, maxSizeResponseScopedPDU, stateReference, statusInformation) snmpEngine.transportDispatcher.sendMessage( outgoingMessage, destTransportDomain, destTransportAddress) except PySnmpError: debug.logger & debug.flagDsp and debug.logger( 'receiveMessage: report failed, statusInformation %s' % sys.exc_info()[1]) else: debug.logger & debug.flagDsp and debug.logger( 'receiveMessage: reporting succeeded') # 4.2.2.1.2.d return restOfWholeMsg else: snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc3412.receiveMessage:request', dict(transportDomain=transportDomain, transportAddress=transportAddress, wholeMsg=wholeMsg, messageProcessingModel=messageProcessingModel, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, pdu=PDU)) # pass transport info to app (legacy) if stateReference is not None: self.__transportInfo[stateReference] = (transportDomain, transportAddress) # 4.2.2.1.3 processPdu(snmpEngine, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, PDU, maxSizeResponseScopedPDU, stateReference) snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc3412.receiveMessage:request') # legacy if stateReference is not None: del self.__transportInfo[stateReference] debug.logger & debug.flagDsp and debug.logger( 'receiveMessage: processPdu succeeded') return restOfWholeMsg else: # 4.2.2.2 (response) # 4.2.2.2.1 cachedParams = self.__cache.pop(sendPduHandle) # 4.2.2.2.2 if cachedParams is None: snmpUnknownPDUHandlers, = self.mibInstrumController.mibBuilder.importSymbols( '__SNMP-MPD-MIB', 'snmpUnknownPDUHandlers') snmpUnknownPDUHandlers.syntax += 1 return restOfWholeMsg debug.logger & debug.flagDsp and debug.logger( 'receiveMessage: cache read by sendPduHandle %s' % sendPduHandle) # 4.2.2.2.3 # no-op ? XXX snmpEngine.observer.storeExecutionContext( snmpEngine, 'rfc3412.receiveMessage:response', dict(transportDomain=transportDomain, transportAddress=transportAddress, wholeMsg=wholeMsg, messageProcessingModel=messageProcessingModel, securityModel=securityModel, securityName=securityName, securityLevel=securityLevel, contextEngineId=contextEngineId, contextName=contextName, pdu=PDU)) # 4.2.2.2.4 processResponsePdu = cachedParams['cbFun'] processResponsePdu(snmpEngine, messageProcessingModel, securityModel, securityName, securityLevel, contextEngineId, contextName, pduVersion, PDU, statusInformation, cachedParams['sendPduHandle'], cachedParams['cbCtx']) snmpEngine.observer.clearExecutionContext( snmpEngine, 'rfc3412.receiveMessage:response') debug.logger & debug.flagDsp and debug.logger( 'receiveMessage: processResponsePdu succeeded') return restOfWholeMsg
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') snmpTrapOID, snmpTrapOIDParam = v2VarBinds[1] 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.IpAddress('0.0.0.0')) # 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 -= 1 # 4.1.2.3.1 v2ErrorStatus = v2c.apiPDU.getErrorStatus(v2Pdu) if v2ErrorStatus: v1.apiPDU.setErrorStatus(v1Pdu, __v2ToV1ErrorMap.get(v2ErrorStatus, 5)) v1.apiPDU.setErrorIndex( v1Pdu, v2c.apiPDU.getErrorIndex(v2Pdu, muteErrors=True)) elif pduType in rfc3411.confirmedClassPDUs: v1.apiPDU.setErrorStatus(v1Pdu, 0) v1.apiPDU.setErrorIndex(v1Pdu, 0) # 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 __init__(self, snmpEngineID=None, maxMessageSize=65507, msgAndPduDsp=None): self.cache = {} self.observer = observer.MetaObserver() if msgAndPduDsp is None: self.msgAndPduDsp = MsgAndPduDispatcher() else: self.msgAndPduDsp = msgAndPduDsp self.messageProcessingSubsystems = { SnmpV1MessageProcessingModel.messageProcessingModelID: SnmpV1MessageProcessingModel(), SnmpV2cMessageProcessingModel.messageProcessingModelID: SnmpV2cMessageProcessingModel(), SnmpV3MessageProcessingModel.messageProcessingModelID: SnmpV3MessageProcessingModel() } self.securityModels = { SnmpV1SecurityModel.securityModelID: SnmpV1SecurityModel(), SnmpV2cSecurityModel.securityModelID: SnmpV2cSecurityModel(), SnmpUSMSecurityModel.securityModelID: SnmpUSMSecurityModel() } self.accessControlModel = { void.Vacm.accessModelID: void.Vacm(), rfc3415.Vacm.accessModelID: rfc3415.Vacm() } self.transportDispatcher = None if self.msgAndPduDsp.mibInstrumController is None: raise error.PySnmpError('MIB instrumentation does not yet exist') snmpEngineMaxMessageSize, = self.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineMaxMessageSize') snmpEngineMaxMessageSize.syntax = snmpEngineMaxMessageSize.syntax.clone( maxMessageSize) snmpEngineBoots, = self.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineBoots') snmpEngineBoots.syntax += 1 origSnmpEngineID, = self.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineID') if snmpEngineID is None: self.snmpEngineID = origSnmpEngineID.syntax else: origSnmpEngineID.syntax = origSnmpEngineID.syntax.clone( snmpEngineID) self.snmpEngineID = origSnmpEngineID.syntax debug.logger & debug.flagApp and debug.logger( 'SnmpEngine: using custom SNMP Engine ID: %s' % self.snmpEngineID.prettyPrint()) # Attempt to make some of snmp Engine settings persistent. # This should probably be generalized as a non-volatile MIB store. persistentPath = os.path.join(tempfile.gettempdir(), '__pysnmp', self.snmpEngineID.prettyPrint()) debug.logger & debug.flagApp and debug.logger( 'SnmpEngine: using persistent directory: %s' % persistentPath) if not os.path.exists(persistentPath): try: os.makedirs(persistentPath) except OSError: return f = os.path.join(persistentPath, 'boots') try: snmpEngineBoots.syntax = snmpEngineBoots.syntax.clone( open(f).read()) except Exception: pass try: snmpEngineBoots.syntax += 1 except Exception: snmpEngineBoots.syntax = snmpEngineBoots.syntax.clone(1) try: fd, fn = tempfile.mkstemp(dir=persistentPath) os.write(fd, str2octs(snmpEngineBoots.syntax.prettyPrint())) os.close(fd) os.rename(fn, f) except Exception: debug.logger & debug.flagApp and debug.logger( 'SnmpEngine: could not stored SNMP Engine Boots: %s' % sys.exc_info()[1]) else: debug.logger & debug.flagApp and debug.logger( 'SnmpEngine: stored SNMP Engine Boots: %s' % snmpEngineBoots.syntax.prettyPrint())