I noticed that the agent++ example static_table allows users in the usmUserTable to be used for gets/sets even if the usmUserStatus has been set to notInService. I had a look through RFC3414 which doesn’t specifically mention how the agent should behave if a user has been set to notInService.
I have tested the behaviour with another SNMP implementation, and with that the agent returned
‘Unknown user name’ when trying to authenticate with a user which has been set to notInService.
Independent of the used versions, in SNMPv3 access security has to be implemented in the View Access Control Model. Using User Based Security Model for implicit access security can have unexpected results.
For example, the sender of a SNMPv3 PDU can decide which security level the GET or SET request has. The USM then processes the messages according to the security level. If it is noAuthNoPriv, neither authentication nor privacy takes places. That means a unauthenticated GET/SET PDU is forwarded to the agent and if the VAM is not in place or not properly defined, the request will be processed!
Therefore always use the VACM to security your agent (do not rely on USM user notInService for example).
when setting the status of a user in the UsmUserTable to notInService, the code in UsmUserTableStatus::set() deletes the localized user from the USM, so after this the localized user no longer exists in snmp++.
Unfortunately the example static_table adds all users to the UsmUserTable using passwords and does not set the addPasswordsToUSM parameter to false (it is omited and default is true). So the USM still has the username and passwords and will create the localized user when the next request arrives.
A SNMP agent should not use passwords for its USM users, localised keys should be used instead!
The SNMP-USER-BASED-SM-MIB does not cover non-localised users. That might cause misunderstandings, and the agent will not contain any secure information in memory, that can be used to exploit other devices.
The two different USM user types (localised vs. non-localised), are the reason why setting a row in the usmUserTable to notInService will not affect the non-localised user in the SNMP++ USM.
Yes, it is surprisingly and that’s why I recommend to always use the VACM to implement access security in order to avoid accidentally created security holes.
Your suggested fix works, until the agent gets restarted. If I clone a user the new user gets added as nonVolatile. I can then set the new user to notInService and the agent responds with “Unknown user name” if I try to authenticate with it. After restarting the agent (I have persistent storage enabled) the new user will still be shown as notInService, but now I can successfully authenticate again with the disabled user.
Can you think of any fix that would work after a restart for nonVolatile users ?
I have tried Franks fix for UsmUserTable::row_init and it fixes the reboot issue.
I have found one more issue. I can deactivate a user, but reactivating fails:
# deactivating user SHAAES128
snmpusm -v 3 -l authNoPriv -u SHA -a sha -A SHAUserAuthPassword 127.0.0.1 deactivate SHAAES128
User successfully deactivated.
# re-activating user SHAAES128
snmpusm -v 3 -l authNoPriv -u SHA -a sha -A SHAUserAuthPassword 127.0.0.1 activate SHAAES128
Error in packet.
Reason: inconsistentValue (The set value is illegal or unsupported in some way)
Failed object: SNMP-USER-BASED-SM-MIB::usmUserStatus."...p.ubuntu1804.."."SHAAES128"
# deleting user SHAAES128
snmpusm -v 3 -l authNoPriv -u SHA -a sha -A SHAUserAuthPassword 127.0.0.1 delete SHAAES128
User successfully deleted.
I have fixed the bug. There were changes necessary at several locations in v3_mibs.h and v3_mibs.cpp.
This fix will be included in release 4.1.3 which will be released on 2020-02-16T23:00:00Z if all further pending tests are fine.
I think I might have found another issue. I have applied all the patches in this thread including the one from above to fix the issue with re-activating a user, but if I try the same sequence on a user with storageType set to permanent and then try to reactive the user I get the same error.
I have modified the static_table example code to create the SHAAES128 user like this:
# deactivating user SHAAES128
snmpusm -v 3 -l authNoPriv -u SHA -a sha -A SHAUserAuthPassword 127.0.0.1 deactivate SHAAES128
User successfully deactivated.
# re-activating user SHAAES128
snmpusm -v 3 -l authNoPriv -u SHA -a sha -A SHAUserAuthPassword 127.0.0.1 activate SHAAES128
Error in packet.
Reason: inconsistentValue (The set value is illegal or unsupported in some way)
Failed object: SNMP-USER-BASED-SM-MIB::usmUserStatus."...p.ubuntu1804.."."SHAAES128"
# deleting user SHAAES128
snmpusm -v 3 -l authNoPriv -u SHA -a sha -A SHAUserAuthPassword 127.0.0.1 delete SHAAES128
User successfully deleted.
Additionally, I don’t think I should be able to delete a permanent user. RFC2579 says:
A row which is permanent(4) can be changed but not deleted.
To be able to reactive a permanent user you need to change the StorageType::value_ok method to:
bool StorageType::value_ok(const Vbx& vb)
{
long v;
if (vb.get_value(v) != SNMP_CLASS_SUCCESS)
return FALSE;
if ((v < 1) || (v > 5)) return FALSE;
if ((valid()) && (get_state() < storageType_permanent) &&
(v >=storageType_permanent)) return FALSE;
if ((valid()) && (get_state() >= storageType_readOnly)) return FALSE;
return TRUE;
}
In the current version the last comparison uses storageType_permanent instead of storageType_readOnly.
For the fix to protect readonly and permanent rows for modification and deletion respectively, a more complex patch is needed, but that is already implemented and working (using a MibTableVoter).