summaryrefslogtreecommitdiff
path: root/src/conf_mode/snmp.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/conf_mode/snmp.py')
-rwxr-xr-xsrc/conf_mode/snmp.py146
1 files changed, 61 insertions, 85 deletions
diff --git a/src/conf_mode/snmp.py b/src/conf_mode/snmp.py
index bafd26edc..e9806ef47 100755
--- a/src/conf_mode/snmp.py
+++ b/src/conf_mode/snmp.py
@@ -16,20 +16,16 @@
import os
-from binascii import hexlify
-from netifaces import interfaces
-from time import sleep
from sys import exit
from vyos.config import Config
from vyos.configverify import verify_vrf
+from vyos.snmpv3_hashgen import plaintext_to_md5, plaintext_to_sha1, random
+from vyos.template import render
+from vyos.util import call
from vyos.validate import is_ipv4, is_addr_assigned
from vyos.version import get_version_data
-from vyos import ConfigError
-from vyos.util import call
-from vyos.template import render
-
-from vyos import airbag
+from vyos import ConfigError, airbag
airbag.enable()
config_file_client = r'/etc/snmp/snmp.conf'
@@ -61,7 +57,7 @@ default_config_data = {
'trap_targets': [],
'vyos_user': '',
'vyos_user_pass': '',
- 'version': '999',
+ 'version': '',
'v3_enabled': 'False',
'v3_engineid': '',
'v3_groups': [],
@@ -90,9 +86,8 @@ def get_config():
snmp['version'] = version_data['version']
# create an internal snmpv3 user of the form 'vyosxxxxxxxxxxxxxxxx'
- # os.urandom(8) returns 8 bytes of random data
- snmp['vyos_user'] = 'vyos' + hexlify(os.urandom(8)).decode('utf-8')
- snmp['vyos_user_pass'] = hexlify(os.urandom(16)).decode('utf-8')
+ snmp['vyos_user'] = 'vyos' + random(8)
+ snmp['vyos_user_pass'] = random(16)
if conf.exists('community'):
for name in conf.list_nodes('community'):
@@ -263,30 +258,30 @@ def get_config():
# cmdline option '-a'
trap_cfg['authProtocol'] = conf.return_value('v3 trap-target {0} auth type'.format(trap))
- if conf.exists('v3 trap-target {0} auth plaintext-key'.format(trap)):
+ if conf.exists('v3 trap-target {0} auth plaintext-password'.format(trap)):
# Set the authentication pass phrase used for authenticated SNMPv3 messages.
# cmdline option '-A'
- trap_cfg['authPassword'] = conf.return_value('v3 trap-target {0} auth plaintext-key'.format(trap))
+ trap_cfg['authPassword'] = conf.return_value('v3 trap-target {0} auth plaintext-password'.format(trap))
- if conf.exists('v3 trap-target {0} auth encrypted-key'.format(trap)):
+ if conf.exists('v3 trap-target {0} auth encrypted-password'.format(trap)):
# Sets the keys to be used for SNMPv3 transactions. These options allow you to set the master authentication keys.
# cmdline option '-3m'
- trap_cfg['authMasterKey'] = conf.return_value('v3 trap-target {0} auth encrypted-key'.format(trap))
+ trap_cfg['authMasterKey'] = conf.return_value('v3 trap-target {0} auth encrypted-password'.format(trap))
if conf.exists('v3 trap-target {0} privacy type'.format(trap)):
# Set the privacy protocol (DES or AES) used for encrypted SNMPv3 messages.
# cmdline option '-x'
trap_cfg['privProtocol'] = conf.return_value('v3 trap-target {0} privacy type'.format(trap))
- if conf.exists('v3 trap-target {0} privacy plaintext-key'.format(trap)):
+ if conf.exists('v3 trap-target {0} privacy plaintext-password'.format(trap)):
# Set the privacy pass phrase used for encrypted SNMPv3 messages.
# cmdline option '-X'
- trap_cfg['privPassword'] = conf.return_value('v3 trap-target {0} privacy plaintext-key'.format(trap))
+ trap_cfg['privPassword'] = conf.return_value('v3 trap-target {0} privacy plaintext-password'.format(trap))
- if conf.exists('v3 trap-target {0} privacy encrypted-key'.format(trap)):
+ if conf.exists('v3 trap-target {0} privacy encrypted-password'.format(trap)):
# Sets the keys to be used for SNMPv3 transactions. These options allow you to set the master encryption keys.
# cmdline option '-3M'
- trap_cfg['privMasterKey'] = conf.return_value('v3 trap-target {0} privacy encrypted-key'.format(trap))
+ trap_cfg['privMasterKey'] = conf.return_value('v3 trap-target {0} privacy encrypted-password'.format(trap))
if conf.exists('v3 trap-target {0} protocol'.format(trap)):
trap_cfg['ipProto'] = conf.return_value('v3 trap-target {0} protocol'.format(trap))
@@ -325,11 +320,11 @@ def get_config():
}
# v3 user {0} auth
- if conf.exists('v3 user {0} auth encrypted-key'.format(user)):
- user_cfg['authMasterKey'] = conf.return_value('v3 user {0} auth encrypted-key'.format(user))
+ if conf.exists('v3 user {0} auth encrypted-password'.format(user)):
+ user_cfg['authMasterKey'] = conf.return_value('v3 user {0} auth encrypted-password'.format(user))
- if conf.exists('v3 user {0} auth plaintext-key'.format(user)):
- user_cfg['authPassword'] = conf.return_value('v3 user {0} auth plaintext-key'.format(user))
+ if conf.exists('v3 user {0} auth plaintext-password'.format(user)):
+ user_cfg['authPassword'] = conf.return_value('v3 user {0} auth plaintext-password'.format(user))
# load default value
type = user_cfg['authProtocol']
@@ -349,11 +344,11 @@ def get_config():
user_cfg['mode'] = conf.return_value('v3 user {0} mode'.format(user))
# v3 user {0} privacy
- if conf.exists('v3 user {0} privacy encrypted-key'.format(user)):
- user_cfg['privMasterKey'] = conf.return_value('v3 user {0} privacy encrypted-key'.format(user))
+ if conf.exists('v3 user {0} privacy encrypted-password'.format(user)):
+ user_cfg['privMasterKey'] = conf.return_value('v3 user {0} privacy encrypted-password'.format(user))
- if conf.exists('v3 user {0} privacy plaintext-key'.format(user)):
- user_cfg['privPassword'] = conf.return_value('v3 user {0} privacy plaintext-key'.format(user))
+ if conf.exists('v3 user {0} privacy plaintext-password'.format(user)):
+ user_cfg['privPassword'] = conf.return_value('v3 user {0} privacy plaintext-password'.format(user))
# load default value
type = user_cfg['privProtocol']
@@ -450,16 +445,16 @@ def verify(snmp):
if 'v3_traps' in snmp.keys():
for trap in snmp['v3_traps']:
if trap['authPassword'] and trap['authMasterKey']:
- raise ConfigError('Must specify only one of encrypted-key/plaintext-key for trap auth')
+ raise ConfigError('Must specify only one of encrypted-password/plaintext-key for trap auth')
if trap['authPassword'] == '' and trap['authMasterKey'] == '':
- raise ConfigError('Must specify encrypted-key or plaintext-key for trap auth')
+ raise ConfigError('Must specify encrypted-password or plaintext-key for trap auth')
if trap['privPassword'] and trap['privMasterKey']:
- raise ConfigError('Must specify only one of encrypted-key/plaintext-key for trap privacy')
+ raise ConfigError('Must specify only one of encrypted-password/plaintext-key for trap privacy')
if trap['privPassword'] == '' and trap['privMasterKey'] == '':
- raise ConfigError('Must specify encrypted-key or plaintext-key for trap privacy')
+ raise ConfigError('Must specify encrypted-password or plaintext-key for trap privacy')
if not 'type' in trap.keys():
raise ConfigError('v3 trap: "type" must be specified')
@@ -490,19 +485,12 @@ def verify(snmp):
if error:
raise ConfigError('You must create group "{0}" first'.format(user['group']))
- # Depending on the configured security level
- # the user has to provide additional info
- if user['authPassword'] and user['authMasterKey']:
- raise ConfigError('Can not mix "encrypted-key" and "plaintext-key" for user auth')
-
+ # Depending on the configured security level the user has to provide additional info
if (not user['authPassword'] and not user['authMasterKey']):
- raise ConfigError('Must specify encrypted-key or plaintext-key for user auth')
-
- if user['privPassword'] and user['privMasterKey']:
- raise ConfigError('Can not mix "encrypted-key" and "plaintext-key" for user privacy')
+ raise ConfigError('Must specify encrypted-password or plaintext-key for user auth')
if user['privPassword'] == '' and user['privMasterKey'] == '':
- raise ConfigError('Must specify encrypted-key or plaintext-key for user privacy')
+ raise ConfigError('Must specify encrypted-password or plaintext-key for user privacy')
if user['mode'] == '':
raise ConfigError('Must specify user mode ro/rw')
@@ -524,12 +512,36 @@ def generate(snmp):
for file in config_files:
rmfile(file)
- # Reload systemd manager configuration
- call('systemctl daemon-reload')
-
if not snmp:
return None
+ if 'v3_users' in snmp.keys():
+ # net-snmp is now regenerating the configuration file in the background
+ # thus we need to re-open and re-read the file as the content changed.
+ # After that we can no read the encrypted password from the config and
+ # replace the CLI plaintext password with its encrypted version.
+ os.environ["vyos_libexec_dir"] = "/usr/libexec/vyos"
+
+ for user in snmp['v3_users']:
+ if user['authProtocol'] == 'sha':
+ hash = plaintext_to_sha1
+ else:
+ hash = plaintext_to_md5
+
+ if user['authPassword']:
+ user['authMasterKey'] = hash(user['authPassword'], snmp['v3_engineid'])
+ user['authPassword'] = ''
+
+ call('/opt/vyatta/sbin/my_set service snmp v3 user "{name}" auth encrypted-password "{authMasterKey}" > /dev/null'.format(**user))
+ call('/opt/vyatta/sbin/my_delete service snmp v3 user "{name}" auth plaintext-password > /dev/null'.format(**user))
+
+ if user['privPassword']:
+ user['privMasterKey'] = hash(user['privPassword'], snmp['v3_engineid'])
+ user['privPassword'] = ''
+
+ call('/opt/vyatta/sbin/my_set service snmp v3 user "{name}" privacy encrypted-password "{privMasterKey}" > /dev/null'.format(**user))
+ call('/opt/vyatta/sbin/my_delete service snmp v3 user "{name}" privacy plaintext-password > /dev/null'.format(**user))
+
# Write client config file
render(config_file_client, 'snmp/etc.snmp.conf.tmpl', snmp)
# Write server config file
@@ -544,50 +556,14 @@ def generate(snmp):
return None
def apply(snmp):
+ # Always reload systemd manager configuration
+ call('systemctl daemon-reload')
+
if not snmp:
return None
- # Reload systemd manager configuration
- call('systemctl daemon-reload')
# start SNMP daemon
- call("systemctl restart snmpd.service")
-
- if 'vrf' not in snmp.keys():
- # service will be restarted multiple times later on
- while (call('systemctl -q is-active snmpd.service') != 0):
- sleep(0.5)
-
- # net-snmp is now regenerating the configuration file in the background
- # thus we need to re-open and re-read the file as the content changed.
- # After that we can no read the encrypted password from the config and
- # replace the CLI plaintext password with its encrypted version.
- os.environ["vyos_libexec_dir"] = "/usr/libexec/vyos"
-
- # XXX: actually this whole logic makes less sense - why not calculate the
- # password hashed on our own and write them back into the config? I see
- # no valid reason in waiting for a third party process to do so.
- with open(config_file_user, 'r') as f:
- engineID = ''
- for line in f:
- if line.startswith('usmUser'):
- string = line.split(' ')
- cfg = {
- 'user': string[4].replace(r'"', ''),
- 'auth_pw': string[8],
- 'priv_pw': string[10]
- }
- # No need to take care about the VyOS internal user
- if cfg['user'] == snmp['vyos_user']:
- continue
-
- # Now update the running configuration
- #
- # Currently when executing call() the environment does not
- # have the vyos_libexec_dir variable set, see Phabricator T685.
- call('/opt/vyatta/sbin/my_set service snmp v3 user "{0}" auth encrypted-key "{1}" > /dev/null'.format(cfg['user'], cfg['auth_pw']))
- call('/opt/vyatta/sbin/my_set service snmp v3 user "{0}" privacy encrypted-key "{1}" > /dev/null'.format(cfg['user'], cfg['priv_pw']))
- call('/opt/vyatta/sbin/my_delete service snmp v3 user "{0}" auth plaintext-key > /dev/null'.format(cfg['user']))
- call('/opt/vyatta/sbin/my_delete service snmp v3 user "{0}" privacy plaintext-key > /dev/null'.format(cfg['user']))
+ call('systemctl restart snmpd.service')
# Enable AgentX in FRR
call('vtysh -c "configure terminal" -c "agentx" >/dev/null')