diff options
-rw-r--r-- | CHANGES.txt | 3 | ||||
-rw-r--r-- | pysnmp/entity/config.py | 114 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/localkey.py | 7 | ||||
-rw-r--r-- | pysnmp/proto/secmod/rfc3414/service.py | 77 | ||||
-rw-r--r-- | pysnmp/smi/builder.py | 4 |
5 files changed, 166 insertions, 39 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index e5ad5a84..0813d057 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -103,6 +103,9 @@ Revision 4.4.11, released 2019-08-XX ------------------------------------ - Added SNMPv3 USM master and localized keys support to LCD configuration +- Improved initial and runtime USM debugging +- Fixed a bug in USM configuration which did not allow the same user names + to be added under different security names Revision 4.4.10, released 2019-07-29 ------------------------------------ diff --git a/pysnmp/entity/config.py b/pysnmp/entity/config.py index ea6ca00b..bba225de 100644 --- a/pysnmp/entity/config.py +++ b/pysnmp/entity/config.py @@ -22,6 +22,7 @@ from pysnmp.proto.secmod.eso.priv import des3 from pysnmp.proto import rfc1902 from pysnmp.proto import rfc1905 from pysnmp import error +from pysnmp import debug # A shortcut to popular constants @@ -110,6 +111,8 @@ def addV1System(snmpEngine, communityIndex, communityName, if contextName is None: contextName = null + securityName = securityName is not None and securityName or communityIndex + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (snmpCommunityEntry.name + (8,) + tblIdx, 'destroy'), snmpEngine=snmpEngine @@ -118,9 +121,7 @@ def addV1System(snmpEngine, communityIndex, communityName, snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (snmpCommunityEntry.name + (1,) + tblIdx, communityIndex), (snmpCommunityEntry.name + (2,) + tblIdx, communityName), - (snmpCommunityEntry.name + (3,) + tblIdx, ( - securityName is not None and securityName or - communityIndex)), + (snmpCommunityEntry.name + (3,) + tblIdx, securityName), (snmpCommunityEntry.name + (4,) + tblIdx, contextEngineId), (snmpCommunityEntry.name + (5,) + tblIdx, contextName), (snmpCommunityEntry.name + (6,) + tblIdx, transportTag), @@ -129,6 +130,13 @@ def addV1System(snmpEngine, communityIndex, communityName, snmpEngine=snmpEngine ) + debug.logger & debug.FLAG_SM and debug.logger( + 'addV1System: added new table entry ' + 'communityIndex "%s" communityName "%s" securityName "%s" ' + 'contextEngineId "%s" contextName "%s" transportTag ' + '"%s"' % (communityIndex, communityName, securityName, + contextEngineId, contextName, transportTag)) + def delV1System(snmpEngine, communityIndex): (snmpCommunityEntry, tblIdx, @@ -139,6 +147,10 @@ def delV1System(snmpEngine, communityIndex): snmpEngine=snmpEngine ) + debug.logger & debug.FLAG_SM and debug.logger( + 'delV1System: deleted table entry by communityIndex ' + '"%s"' % (communityIndex,)) + def __cookV3UserInfo(snmpEngine, securityName, securityEngineId): mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder @@ -147,22 +159,22 @@ def __cookV3UserInfo(snmpEngine, securityName, securityEngineId): '__SNMP-FRAMEWORK-MIB', 'snmpEngineID') if securityEngineId is None: - snmpEngineID = snmpEngineID.syntax + securityEngineId = snmpEngineID.syntax else: - snmpEngineID = snmpEngineID.syntax.clone(securityEngineId) + securityEngineId = snmpEngineID.syntax.clone(securityEngineId) usmUserEntry, = mibBuilder.importSymbols( 'SNMP-USER-BASED-SM-MIB', 'usmUserEntry') - tblIdx1 = usmUserEntry.getInstIdFromIndices(snmpEngineID, securityName) + tblIdx1 = usmUserEntry.getInstIdFromIndices(securityEngineId, securityName) pysnmpUsmSecretEntry, = mibBuilder.importSymbols( 'PYSNMP-USM-MIB', 'pysnmpUsmSecretEntry') tblIdx2 = pysnmpUsmSecretEntry.getInstIdFromIndices(securityName) - return snmpEngineID, usmUserEntry, tblIdx1, pysnmpUsmSecretEntry, tblIdx2 + return securityEngineId, usmUserEntry, tblIdx1, pysnmpUsmSecretEntry, tblIdx2 def addV3User(snmpEngine, userName, @@ -172,14 +184,15 @@ def addV3User(snmpEngine, userName, securityName=None, authKeyType=USM_KEY_TYPE_PASSPHRASE, privKeyType=USM_KEY_TYPE_PASSPHRASE): + mibBuilder = snmpEngine.msgAndPduDsp.mibInstrumController.mibBuilder if securityName is None: securityName = userName - (snmpEngineID, usmUserEntry, tblIdx1, + (securityEngineId, usmUserEntry, tblIdx1, pysnmpUsmSecretEntry, tblIdx2) = __cookV3UserInfo( - snmpEngine, userName, securityEngineId) + snmpEngine, securityName, securityEngineId) # Load augmenting table before creating new row in base one pysnmpUsmKeyEntry, = mibBuilder.importSymbols( @@ -217,6 +230,8 @@ def addV3User(snmpEngine, userName, # Localize authentication key unless given + authKey = authKey and rfc1902.OctetString(authKey) + masterAuthKey = localAuthKey = authKey if authKeyType < USM_KEY_TYPE_MASTER: # master key is not given @@ -226,15 +241,17 @@ def addV3User(snmpEngine, userName, if authKeyType < USM_KEY_TYPE_LOCALIZED: # localized key is not given localAuthKey = AUTH_SERVICES[authProtocol].localizeKey( - masterAuthKey, snmpEngineID + masterAuthKey, securityEngineId ) # Localize privacy key unless given - masterPrivKey = localPrivKey = privKey - privKeyType = pysnmpUsmKeyType.syntax.clone(privKeyType) + privKey = privKey and rfc1902.OctetString(privKey) + + masterPrivKey = localPrivKey = privKey + if privKeyType < USM_KEY_TYPE_MASTER: # master key is not given masterPrivKey = PRIV_SERVICES[privProtocol].hashPassphrase( authProtocol, privKey or null @@ -242,37 +259,81 @@ def addV3User(snmpEngine, userName, if privKeyType < USM_KEY_TYPE_LOCALIZED: # localized key is not given localPrivKey = PRIV_SERVICES[privProtocol].localizeKey( - authProtocol, masterPrivKey, snmpEngineID + authProtocol, masterPrivKey, securityEngineId ) - # Commit master and localized keys + # Commit only the keys we have + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (pysnmpUsmKeyEntry.name + (1,) + tblIdx1, localAuthKey), + snmpEngine=snmpEngine + ) + + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (pysnmpUsmKeyEntry.name + (2,) + tblIdx1, localPrivKey), - (pysnmpUsmKeyEntry.name + (3,) + tblIdx1, masterAuthKey), - (pysnmpUsmKeyEntry.name + (4,) + tblIdx1, masterPrivKey), - snmpEngine=snmpEngine + snmpEngine = snmpEngine ) + if authKeyType < USM_KEY_TYPE_LOCALIZED: + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( + (pysnmpUsmKeyEntry.name + (3,) + tblIdx1, masterAuthKey), + snmpEngine=snmpEngine + ) + + if privKeyType < USM_KEY_TYPE_LOCALIZED: + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( + (pysnmpUsmKeyEntry.name + (4,) + tblIdx1, masterPrivKey), + snmpEngine=snmpEngine + ) + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( (pysnmpUsmSecretEntry.name + (4,) + tblIdx2, 'destroy'), - snmpEngine=snmpEngine + snmpEngine=snmpEngine ) - # Commit plain-text pass-phrases + # Commit plain-text pass-phrases if we have them + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( - (pysnmpUsmSecretEntry.name + (1,) + tblIdx2, userName), - (pysnmpUsmSecretEntry.name + (2,) + tblIdx2, authKey), - (pysnmpUsmSecretEntry.name + (3,) + tblIdx2, privKey), (pysnmpUsmSecretEntry.name + (4,) + tblIdx2, 'createAndGo'), snmpEngine=snmpEngine ) + if authKeyType < USM_KEY_TYPE_MASTER: + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( + (pysnmpUsmSecretEntry.name + (1,) + tblIdx2, userName), + (pysnmpUsmSecretEntry.name + (2,) + tblIdx2, authKey), + snmpEngine=snmpEngine + ) + + if privKeyType < USM_KEY_TYPE_MASTER: + snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( + (pysnmpUsmSecretEntry.name + (1,) + tblIdx2, userName), + (pysnmpUsmSecretEntry.name + (3,) + tblIdx2, privKey), + snmpEngine=snmpEngine + ) + + debug.logger & debug.FLAG_SM and debug.logger( + 'addV3User: added new table entries ' + 'userName "%s" securityName "%s" authProtocol %s ' + 'privProtocol %s localAuthKey "%s" localPrivKey "%s" ' + 'masterAuthKey "%s" masterPrivKey "%s" authKey "%s" ' + 'privKey "%s" by index securityName "%s" securityEngineId ' + '"%s"' % ( + userName, securityName, authProtocol, privProtocol, + localAuthKey and localAuthKey.prettyPrint(), + localPrivKey and localPrivKey.prettyPrint(), + masterAuthKey and masterAuthKey.prettyPrint(), + masterPrivKey and masterPrivKey.prettyPrint(), + authKey and authKey.prettyPrint(), + privKey and privKey.prettyPrint(), + securityName, + securityEngineId and securityEngineId.prettyPrint())) + def delV3User(snmpEngine, userName, securityEngineId=None): - (snmpEngineID, usmUserEntry, tblIdx1, pysnmpUsmSecretEntry, + (securityEngineId, usmUserEntry, tblIdx1, pysnmpUsmSecretEntry, tblIdx2) = __cookV3UserInfo(snmpEngine, userName, securityEngineId) snmpEngine.msgAndPduDsp.mibInstrumController.writeMibObjects( @@ -285,6 +346,13 @@ def delV3User(snmpEngine, snmpEngine=snmpEngine ) + debug.logger & debug.FLAG_SM and debug.logger( + 'delV3User: deleted table entries by index ' + 'userName "%s" securityEngineId ' + '"%s"' % ( + userName, + securityEngineId.prettyPrint())) + # Drop all derived rows def _cbFun(varBinds, **context): diff --git a/pysnmp/proto/secmod/rfc3414/localkey.py b/pysnmp/proto/secmod/rfc3414/localkey.py index bc4faa91..61ce5ff9 100644 --- a/pysnmp/proto/secmod/rfc3414/localkey.py +++ b/pysnmp/proto/secmod/rfc3414/localkey.py @@ -36,8 +36,8 @@ def hashPassphrase(passphrase, hashFunc): mark = e - ringBufferLen count += 1 - - return hasher.digest() + digest = hasher.digest() + return univ.OctetString(digest) def passwordToKey(passphrase, snmpEngineId, hashFunc): @@ -49,7 +49,8 @@ def localizeKey(passKey, snmpEngineId, hashFunc): passKey = univ.OctetString(passKey).asOctets() # noinspection PyDeprecation,PyCallingNonCallable - return hashFunc(passKey + snmpEngineId.asOctets() + passKey).digest() + digest = hashFunc(passKey + snmpEngineId.asOctets() + passKey).digest() + return univ.OctetString(digest) # RFC3414: A.2.1 diff --git a/pysnmp/proto/secmod/rfc3414/service.py b/pysnmp/proto/secmod/rfc3414/service.py index 0a8f54e5..f20df861 100644 --- a/pysnmp/proto/secmod/rfc3414/service.py +++ b/pysnmp/proto/secmod/rfc3414/service.py @@ -344,7 +344,22 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): securityEngineID = snmpEngineID debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: user info read from cache') + '__generateRequestOrResponseMsg: using cached USM user entry ' + 'usmUserName "%s" ' + 'usmUserSecurityName "%s" ' + 'usmUserAuthProtocol "%s" ' + 'usmUserAuthKeyLocalized "%s" ' + 'usmUserPrivProtocol "%s" ' + 'usmUserPrivKeyLocalized "%s" for ' + 'securityEngineID "%s" and securityName "%s" found by ' + 'securityStateReference "%s" ' % ( + usmUserName, usmUserSecurityName, + usmUserAuthProtocol, + usmUserAuthKeyLocalized and usmUserAuthKeyLocalized.prettyPrint(), + usmUserPrivProtocol, + usmUserPrivKeyLocalized and usmUserPrivKeyLocalized.prettyPrint(), + securityEngineID.prettyPrint(), + securityName, securityStateReference)) elif securityName: # 3.1.1b @@ -356,8 +371,23 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): securityEngineID, self._sec2usr(snmpEngine, securityName, securityEngineID) ) + debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: read user info') + '__generateRequestOrResponseMsg: found USM user entry ' + 'usmUserName "%s" ' + 'usmUserSecurityName "%s" ' + 'usmUserAuthProtocol "%s" ' + 'usmUserAuthKeyLocalized "%s" ' + 'usmUserPrivProtocol "%s" ' + 'usmUserPrivKeyLocalized "%s" by ' + 'securityEngineID "%s" and securityName "%s"' % ( + usmUserName, usmUserSecurityName, + usmUserAuthProtocol, + usmUserAuthKeyLocalized.prettyPrint(), + usmUserPrivProtocol, + usmUserPrivKeyLocalized.prettyPrint(), + securityEngineID.prettyPrint(), + securityName)) except NoSuchInstanceError: pysnmpUsmDiscovery, = mibBuilder.importSymbols( @@ -375,7 +405,28 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): self._sec2usr(snmpEngine, securityName) ) + debug.logger & debug.FLAG_SM and debug.logger( + '__generateRequestOrResponseMsg: cloned USM user entry ' + 'usmUserName "%s" ' + 'usmUserSecurityName "%s" ' + 'usmUserAuthProtocol "%s" ' + 'usmUserAuthKeyLocalized "%s" ' + 'usmUserPrivProtocol "%s" ' + 'usmUserPrivKeyLocalized "%s" for ' + 'securityEngineID "%s" and securityName "%s"' % ( + usmUserName, usmUserSecurityName, + usmUserAuthProtocol, + usmUserAuthKeyLocalized.prettyPrint(), + usmUserPrivProtocol, + usmUserPrivKeyLocalized.prettyPrint(), + securityEngineID.prettyPrint(), securityName)) + except NoSuchInstanceError: + debug.logger & debug.FLAG_SM and debug.logger( + '__generateRequestOrResponseMsg: failed to clone ' + 'USM user for securityEngineID "%s" securityName ' + '"%s"' % (securityEngineID, securityName)) + reportUnknownName = True if reportUnknownName: @@ -404,16 +455,18 @@ class SnmpUSMSecurityModel(AbstractSecurityModel): usmUserAuthKeyLocalized = usmUserPrivKeyLocalized = None debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: use empty USM data') - - # noinspection PyUnboundLocalVariable - debug.logger & debug.FLAG_SM and debug.logger( - '__generateRequestOrResponseMsg: local usmUserName %r ' - 'usmUserSecurityName %r usmUserAuthProtocol %s ' - 'usmUserPrivProtocol %s securityEngineID %r ' - 'securityName %r' % ( - usmUserName, usmUserSecurityName, usmUserAuthProtocol, - usmUserPrivProtocol, securityEngineID, securityName)) + '__generateRequestOrResponseMsg: using blank USM info ' + 'usmUserName "%s" ' + 'usmUserSecurityName "%s" ' + 'usmUserAuthProtocol "%s" ' + 'usmUserAuthKeyLocalized "%s" ' + 'usmUserPrivProtocol "%s" ' + 'usmUserPrivKeyLocalized "%s" for ' + 'securityEngineID "%s" and securityName "%s"' % ( + usmUserName, usmUserSecurityName, + usmUserAuthProtocol, usmUserAuthKeyLocalized, + usmUserPrivProtocol, usmUserPrivKeyLocalized, + securityEngineID.prettyPrint(), securityName)) msg = globalData diff --git a/pysnmp/smi/builder.py b/pysnmp/smi/builder.py index da03764d..0a3a6a1c 100644 --- a/pysnmp/smi/builder.py +++ b/pysnmp/smi/builder.py @@ -100,8 +100,10 @@ class __AbstractMibSource(object): for pycSfx in BYTECODE_SUFFIXES: + pycFile = f + pycSfx + try: - pycData, pycPath = self._getData(f + pycSfx, 'rb') + pycData, pycPath = self._getData(pycFile, 'rb') except IOError as exc: if ENOENT == -1 or exc.errno == ENOENT: |