summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIlya Etingof <etingof@gmail.com>2019-08-04 12:16:27 +0200
committerIlya Etingof <etingof@gmail.com>2019-08-05 09:22:45 +0200
commit17a63974eb7df7eb47f822f32a05afd1081b8c06 (patch)
tree9991c89dc97c92c759d3770b547482dbda2f470b
parent9d6c7b5e44a7ec728ac9990a19edd13a61cc70d1 (diff)
downloadpysnmp-git-17a63974eb7df7eb47f822f32a05afd1081b8c06.tar.gz
Do not store incomplete USM keys and improve debug
This adds details debugging on USM initial configuration process and runtime USM user cloning. Besides that, this patch eliminates storing of incomplete USM keys (in case when master/localized keys are configured directly). On top of that, this commit fixes a bug in USM configuration which did not allow the same user names to be added under different security names.
-rw-r--r--CHANGES.txt3
-rw-r--r--pysnmp/entity/config.py114
-rw-r--r--pysnmp/proto/secmod/rfc3414/localkey.py7
-rw-r--r--pysnmp/proto/secmod/rfc3414/service.py77
-rw-r--r--pysnmp/smi/builder.py4
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: