diff options
author | elie <elie> | 2013-05-25 15:05:14 +0000 |
---|---|---|
committer | elie <elie> | 2013-05-25 15:05:14 +0000 |
commit | a1436307bc73418e0a2796d541b10e8cee215cf2 (patch) | |
tree | 1bb4a74925f54a04457cf3beec4ff3eda1fc2370 | |
parent | b3b0746e1f9ecff315473fe6420f498f813bd44d (diff) | |
download | pysnmp-a1436307bc73418e0a2796d541b10e8cee215cf2.tar.gz |
the userName parameter is now fully separated from securityName at
usmUserTable.
-rw-r--r-- | CHANGES | 6 | ||||
-rw-r--r-- | pysnmp/entity/config.py | 18 | ||||
-rw-r--r-- | pysnmp/entity/rfc3413/oneliner/auth.py | 21 | ||||
-rw-r--r-- | pysnmp/entity/rfc3413/oneliner/cmdgen.py | 13 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/service.py | 144 |
5 files changed, 135 insertions, 67 deletions
@@ -35,9 +35,9 @@ Revision 4.2.5rc2 methods now accept optional authData parameter to remove specific entries from LCD. This can be useful for modifying security parameters for specific securityName. -- SNMP credentials management reworked to allow multiple securityNames's in - snmpCommunityEntry and usmUserEntry tables. Changes made to addV1System(), - addV3User() functions as well as to their oneliner's wrappers. +- SNMP credentials management reworked to separate userName from securityName + in snmpCommunityEntry and usmUserEntry tables. Changes made to addV1System(), + addV3User() functions as well as to their oneliner's wrappers. - The contextEngineId parameter of config.addV3User() and auth.UsmUserData() renamed into securityEngineId as it's semantically correct - Oneliner transport target classes now support the getTransportInfo() diff --git a/pysnmp/entity/config.py b/pysnmp/entity/config.py index f5652a9..d351ea6 100644 --- a/pysnmp/entity/config.py +++ b/pysnmp/entity/config.py @@ -110,17 +110,20 @@ def __cookV3UserInfo(snmpEngine, securityName, securityEngineId): return snmpEngineID, usmUserEntry, tblIdx1, pysnmpUsmSecretEntry, tblIdx2 -def addV3User(snmpEngine, securityName, +def addV3User(snmpEngine, userName, authProtocol=usmNoAuthProtocol, authKey=None, privProtocol=usmNoPrivProtocol, privKey=None, securityEngineId=None, + securityName=None, # deprecated parameters follow contextEngineId=None): + if securityName is None: + securityName = userName if securityEngineId is None: # backward compatibility securityEngineId = contextEngineId ( snmpEngineID, usmUserEntry, tblIdx1, pysnmpUsmSecretEntry, tblIdx2 ) = __cookV3UserInfo( - snmpEngine, securityName, securityEngineId + snmpEngine, userName, securityEngineId ) # Load augmenting table before creating new row in base one @@ -134,7 +137,7 @@ def addV3User(snmpEngine, securityName, ) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( ((usmUserEntry.name + (13,) + tblIdx1, 'createAndGo'), - (usmUserEntry.name + (2,) + tblIdx1, securityName), + (usmUserEntry.name + (2,) + tblIdx1, userName), (usmUserEntry.name + (3,) + tblIdx1, securityName), (usmUserEntry.name + (4,) + tblIdx1, zeroDotZero.name), (usmUserEntry.name + (5,) + tblIdx1, authProtocol), @@ -184,15 +187,18 @@ def addV3User(snmpEngine, securityName, ) def delV3User(snmpEngine, - securityName, + userName, securityEngineId=None, + securityName=None, # deprecated parameters follow contextEngineId=None): + if securityName is None: + securityName = userName if securityEngineId is None: # backward compatibility securityEngineId = contextEngineId ( snmpEngineID, usmUserEntry, tblIdx1, pysnmpUsmSecretEntry, tblIdx2 ) = __cookV3UserInfo( - snmpEngine, securityName, securityEngineId + snmpEngine, userName, securityEngineId ) snmpEngine.msgAndPduDsp.mibInstrumController.writeVars( ((usmUserEntry.name + (13,) + tblIdx1, 'destroy'),) @@ -204,7 +210,7 @@ def delV3User(snmpEngine, # Drop all derived rows varBinds = initialVarBinds = ( (usmUserEntry.name + (1,), None), # usmUserEngineID - (usmUserEntry.name + (3,), None), # usmSecurityName + (usmUserEntry.name + (2,), None), # usmUserName (usmUserEntry.name + (4,), None) # usmUserCloneFrom ) while varBinds: diff --git a/pysnmp/entity/rfc3413/oneliner/auth.py b/pysnmp/entity/rfc3413/oneliner/auth.py index 56333d6..a2ab5f3 100644 --- a/pysnmp/entity/rfc3413/oneliner/auth.py +++ b/pysnmp/entity/rfc3413/oneliner/auth.py @@ -55,14 +55,20 @@ class UsmUserData: contextName = null # the contextEngineId/contextName values stored here should # be used for USM configuration only, not for PDU contents - def __init__(self, securityName, + def __init__(self, userName, authKey=None, privKey=None, authProtocol=None, privProtocol=None, securityEngineId=None, - # deprecated parameters follow + # deprecated parameters begin contextName=None, - contextEngineId=None): - self.securityName = securityName + contextEngineId=None, + # deprecated parameters end + securityName=None): + self.userName = userName + if securityName is None: + self.securityName = userName + else: + self.securityName = securityName if authKey is not None: self.authKey = authKey @@ -96,10 +102,11 @@ class UsmUserData: raise TypeError('%s is not hashable' % self.__class__.__name__) def __repr__(self): - return '%s("%s", <AUTHKEY>, <PRIVKEY>, %r, %r, %r)' % ( + return '%s("%s", <AUTHKEY>, <PRIVKEY>, %r, %r, %r, securityName=%r)'%( self.__class__.__name__, - self.securityName, + self.userName, self.authProtocol, self.privProtocol, - self.securityEngineId + self.securityEngineId, + self.securityName ) diff --git a/pysnmp/entity/rfc3413/oneliner/cmdgen.py b/pysnmp/entity/rfc3413/oneliner/cmdgen.py index 7566896..56d5fdc 100644 --- a/pysnmp/entity/rfc3413/oneliner/cmdgen.py +++ b/pysnmp/entity/rfc3413/oneliner/cmdgen.py @@ -56,14 +56,15 @@ class AsynCommandGenerator: ) self.__knownAuths[authData.communityIndex] = authData elif isinstance(authData, UsmUserData): - authDataKey = authData.securityName, authData.securityEngineId + authDataKey = authData.userName, authData.securityEngineId if authDataKey not in self.__knownAuths: config.addV3User( self.snmpEngine, - authData.securityName, + authData.userName, authData.authProtocol, authData.authKey, authData.privProtocol, authData.privKey, - authData.securityEngineId + authData.securityEngineId, + securityName=authData.securityName ) self.__knownAuths[authDataKey] = authData else: @@ -121,7 +122,7 @@ class AsynCommandGenerator: if isinstance(authData, CommunityData): authDataKey = authData.communityIndex elif isinstance(authData, UsmUserData): - authDataKey = authData.securityName, authData.securityEngineId + authDataKey = authData.userName, authData.securityEngineId else: raise error.PySnmpError('Unsupported authentication object') if authDataKey in self.__knownAuths: @@ -144,7 +145,7 @@ class AsynCommandGenerator: elif isinstance(authDataX, UsmUserData): config.delV3User( self.snmpEngine, - authDataX.securityName, + authDataX.userName, authDataX.securityEngineId ) else: @@ -161,7 +162,7 @@ class AsynCommandGenerator: ) paramsNames.add(paramsName) else: - raise error.PySnmpError('Unknown target %s/%s/%s' % paramsKey) + raise error.PySnmpError('Unknown target %s' % paramsKey) addrKeys = [ x for x in self.__knownTransportAddrs if x[0] == paramsName ] diff --git a/pysnmp/proto/secmod/rfc3414/service.py b/pysnmp/proto/secmod/rfc3414/service.py index bc44b15..6284755 100644 --- a/pysnmp/proto/secmod/rfc3414/service.py +++ b/pysnmp/proto/secmod/rfc3414/service.py @@ -46,20 +46,67 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): self.__timeline = {} self.__timelineExpQueue = {} self.__expirationTimer = 0 + self.__paramsBranchId = -1 + + def __sec2usr(self, snmpEngine, securityName, securityEngineID=None): + usmUserEngineID, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('SNMP-USER-BASED-SM-MIB', 'usmUserEngineID') + if self.__paramsBranchId != usmUserEngineID.branchVersionId: + usmUserName, usmUserSecurityName = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('SNMP-USER-BASED-SM-MIB', 'usmUserName', 'usmUserSecurityName') + + self.__securityToUserMap = {} + + nextMibNode = usmUserEngineID + while 1: + 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, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__SNMP-FRAMEWORK-MIB', 'snmpEngineID') + securityEngineID = snmpEngineID.syntax + + userName = self.__securityToUserMap.get( + (securityEngineID, securityName), securityName + ) + + debug.logger & debug.flagSM and debug.logger('_sec2usr: using userName %r for snmpEngineId %r, securityName %r' % (userName, securityEngineID, securityName)) + + return userName def __getUserInfo( - self, mibInstrumController, securityEngineID, securityName + self, mibInstrumController, securityEngineID, userName ): usmUserEntry, = mibInstrumController.mibBuilder.importSymbols( 'SNMP-USER-BASED-SM-MIB', 'usmUserEntry' - ) + ) tblIdx = usmUserEntry.getInstIdFromIndices( - securityEngineID, securityName - ) - # Get protocols + securityEngineID, userName + ) + # Get userName & securityName + usmUserName = usmUserEntry.getNode( + usmUserEntry.name + (2,) + tblIdx + ).syntax usmUserSecurityName = usmUserEntry.getNode( usmUserEntry.name + (3,) + tblIdx - ).syntax + ).syntax + # Get protocols usmUserAuthProtocol = usmUserEntry.getNode( usmUserEntry.name + (5,) + tblIdx ).syntax @@ -77,65 +124,66 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): pysnmpUsmKeyEntry.name + (2,) + tblIdx ).syntax return ( - usmUserSecurityName, # XXX function needed? + usmUserName, + usmUserSecurityName, usmUserAuthProtocol, pysnmpUsmKeyAuthLocalized, usmUserPrivProtocol, pysnmpUsmKeyPrivLocalized - ) + ) def __cloneUserInfo( - self, mibInstrumController, securityEngineID, securityName + self, mibInstrumController, securityEngineID, userName ): snmpEngineID, = mibInstrumController.mibBuilder.importSymbols( '__SNMP-FRAMEWORK-MIB', 'snmpEngineID' - ) + ) # Proto entry usmUserEntry, = mibInstrumController.mibBuilder.importSymbols( 'SNMP-USER-BASED-SM-MIB', 'usmUserEntry' - ) + ) tblIdx1 = usmUserEntry.getInstIdFromIndices( - snmpEngineID.syntax, securityName - ) + snmpEngineID.syntax, userName + ) # Get proto protocols usmUserName = usmUserEntry.getNode( usmUserEntry.name + (2,) + tblIdx1 - ) + ) usmUserSecurityName = usmUserEntry.getNode( usmUserEntry.name + (3,) + tblIdx1 - ) + ) usmUserCloneFrom = usmUserEntry.getNode( usmUserEntry.name + (4,) + tblIdx1 - ) + ) usmUserAuthProtocol = usmUserEntry.getNode( usmUserEntry.name + (5,) + tblIdx1 - ) + ) usmUserPrivProtocol = usmUserEntry.getNode( usmUserEntry.name + (8,) + tblIdx1 - ) + ) # Get proto keys pysnmpUsmKeyEntry, = mibInstrumController.mibBuilder.importSymbols( 'PYSNMP-USM-MIB', 'pysnmpUsmKeyEntry' - ) + ) pysnmpUsmKeyAuth = pysnmpUsmKeyEntry.getNode( pysnmpUsmKeyEntry.name + (3,) + tblIdx1 - ) + ) pysnmpUsmKeyPriv = pysnmpUsmKeyEntry.getNode( pysnmpUsmKeyEntry.name + (4,) + tblIdx1 - ) + ) # Create new row from proto values tblIdx2 = usmUserEntry.getInstIdFromIndices( - securityEngineID, securityName - ) + securityEngineID, userName + ) # New row mibInstrumController.writeVars( ((usmUserEntry.name + (13,) + tblIdx2, 4),) - ) + ) - # Set usernames + # Set user&securityNames usmUserEntry.getNode( usmUserEntry.name + (2,) + tblIdx2 ).syntax = usmUserName.syntax @@ -192,12 +240,13 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): if localPrivKey is not None: pysnmpUsmKeyPrivLocalized.syntax = pysnmpUsmKeyPrivLocalized.syntax.clone(localPrivKey) return ( - usmUserSecurityName.syntax, # XXX function needed? + usmUserName.syntax, + usmUserSecurityName.syntax, usmUserAuthProtocol.syntax, pysnmpUsmKeyAuthLocalized.syntax, usmUserPrivProtocol.syntax, pysnmpUsmKeyPrivLocalized.syntax - ) + ) def __generateRequestOrResponseMsg( self, @@ -240,13 +289,15 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): # 3.1.1b try: ( usmUserName, + usmUserSecurityName, usmUserAuthProtocol, usmUserAuthKeyLocalized, usmUserPrivProtocol, usmUserPrivKeyLocalized ) = self.__getUserInfo( snmpEngine.msgAndPduDsp.mibInstrumController, - securityEngineID, securityName - ) + securityEngineID, + self.__sec2usr(snmpEngine, securityName, securityEngineID) + ) debug.logger & debug.flagSM and debug.logger('__generateRequestOrResponseMsg: read user info') except NoSuchInstanceError: pysnmpUsmDiscovery, = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder.importSymbols('__PYSNMP-USM-MIB', 'pysnmpUsmDiscovery') @@ -254,14 +305,15 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): if not __reportUnknownName: try: ( usmUserName, + usmUserSecurityName, usmUserAuthProtocol, usmUserAuthKeyLocalized, usmUserPrivProtocol, usmUserPrivKeyLocalized ) = self.__cloneUserInfo( snmpEngine.msgAndPduDsp.mibInstrumController, securityEngineID, - securityName - ) + self.__sec2usr(snmpEngine, securityName) + ) except NoSuchInstanceError: __reportUnknownName = 1 @@ -278,7 +330,7 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): usmUserAuthKeyLocalized = 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 %r usmUserAuthProtocol %s usmUserPrivProtocol %s securityEngineID %r securityName %r' % (usmUserName, usmUserAuthProtocol, usmUserPrivProtocol, securityEngineID, securityName)) + 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 @@ -360,14 +412,14 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): 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)) @@ -380,18 +432,18 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): # 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: @@ -615,7 +667,8 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): if msgUserName: # 3.2.4 try: - ( usmUserSecurityName, + ( usmUserName, + usmUserSecurityName, usmUserAuthProtocol, usmUserAuthKeyLocalized, usmUserPrivProtocol, @@ -623,14 +676,15 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): 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, + ( usmUserName, + usmUserSecurityName, usmUserAuthProtocol, usmUserAuthKeyLocalized, usmUserPrivProtocol, @@ -638,7 +692,7 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): snmpEngine.msgAndPduDsp.mibInstrumController, msgAuthoritativeEngineID, msgUserName - ) + ) debug.logger & debug.flagSM and debug.logger('processIncomingMsg: cloned user info') except NoSuchInstanceError: __reportUnknownName = 1 @@ -663,7 +717,7 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): usmUserPrivProtocol = nopriv.NoPriv.serviceID usmUserAuthKeyLocalized = 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)) + 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) @@ -673,7 +727,7 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): usmUserAuthKeyLocalized=usmUserAuthKeyLocalized, usmUserPrivProtocol=usmUserPrivProtocol, usmUserPrivKeyLocalized=usmUserPrivKeyLocalized - ) + ) # 3.2.5 if msgAuthoritativeEngineID == snmpEngineID: |