04-28-2024 01:01 PM
I have the plan to run a script when a certain command is intered into the CLI, check if the command is allowed to run or not, and then return a corresponding value 1 or 0 to the $_exit_status variable in order to allow or prevent the command from running. I have following configuration:
event manager applet FILTERCMD1
event cli pattern "^show version" sync yes
action 001 cli command "enable"
action 002 cli command "tclsh flash:/company/localscripts/filtercmd.tcl $_cli_msg"
action 003 puts "the return from the filtercmd script is: $_cli_result"
action 004 set _exit_status "$_cli_result"
event manager applet FILTERCMD2
event cli pattern "^show running-config" sync yes
action 001 cli command "enable"
action 002 cli command "tclsh flash:/company/localscripts/filtercmd.tcl $_cli_msg"
action 003 puts "the return from the filtercmd script is: $_cli_result"
action 004 set _exit_status "$_cli_result"
The content of the filtercmd.tcl script is:
# return a 1 to run the command
# return a 0 to prevent the command from running
exec "send log facility MANAGEMENT severity 7 mnemonics TESTING these are all the arguments: $argv"
if {$argv == "show version"} {
exec "send log facility MANAGEMENT severity 7 mnemonics TESTING the command show version has been used"
puts -nonewline 0
}
if {$argv == "show running-config"} {
exec "send log facility MANAGEMENT severity 7 mnemonics TESTING the command show running-config has been used"
puts -nonewline 1
}
So what i want to achieve is, that if i enter show version, the command should not get run and if i enter show running-config the command should be run. So i enabled debug event manager action cli and did some testing. this is the result:
roTST11#show version
the return from the filtercmd script is: 0
roTST11#
%EEM: variable must have value between 0 and 2147483647 inclusive.
roTST11#
Apr 28 21:18:22.855: %HA_EM-6-LOG: FILTERCMD1 : DEBUG(cli_lib) : : CTL : cli_open called.
Apr 28 21:18:22.955: %HA_EM-6-LOG: FILTERCMD1 : DEBUG(cli_lib) : : OUT : roTST11>
Apr 28 21:18:22.955: %HA_EM-6-LOG: FILTERCMD1 : DEBUG(cli_lib) : : IN : roTST11>enable
Apr 28 21:18:22.965: %PARSER-5-CFGLOG_LOGGEDCMD: User:admin logged command:!exec: enable
Apr 28 21:18:22.968: %HA_EM-6-LOG: FILTERCMD1 : DEBUG(cli_lib) : : OUT : roTST11#
Apr 28 21:18:22.968: %HA_EM-6-LOG: FILTERCMD1 : DEBUG(cli_lib) : : IN : roTST11#tclsh flash:/company/localscripts/filtercmd.tcl show version
Apr 28 21:18:23.046: %MANAGEMENT-7-TESTING: Message from tty3(user id: admin): these are all the arguments: show version
Apr 28 21:18:23.048: %MANAGEMENT-7-TESTING: Message from tty3(user id: admin): the command show version has been used
Apr 28 21:18:23.080: %HA_EM-6-LOG: FILTERCMD1 : DEBUG(cli_lib) : : OUT : 0
Apr 28 21:18:23.080: %HA_EM-6-LOG: FILTERCMD1 : DEBUG(cli_lib) : : OUT : roTST11#
Apr 28 21:18:23.080:
roTST11#%HA_EM-6-LOG: FILTERCMD1 : DEBUG(cli_lib) : : CTL : cli_close called.
Apr 28 21:18:23.082:
Apr 28 21:18:23.082: tty is now going through its de ath sequence
and
roTST11#show running-config
the return from the filtercmd script is: 1
roTST11#
%EEM: variable must have value between 0 and 2147483647 inclusive.
roTST11#
Apr 28 21:18:40.315: %HA_EM-6-LOG: FILTERCMD2 : DEBUG(cli_lib) : : CTL : cli_open called.
Apr 28 21:18:40.415: %HA_EM-6-LOG: FILTERCMD2 : DEBUG(cli_lib) : : OUT : roTST11>
Apr 28 21:18:40.415: %HA_EM-6-LOG: FILTERCMD2 : DEBUG(cli_lib) : : IN : roTST11>enable
Apr 28 21:18:40.425: %PARSER-5-CFGLOG_LOGGEDCMD: User:admin logged command:!exec: enable
Apr 28 21:18:40.428: %HA_EM-6-LOG: FILTERCMD2 : DEBUG(cli_lib) : : OUT : roTST11#
Apr 28 21:18:40.428: %HA_EM-6-LOG: FILTERCMD2 : DEBUG(cli_lib) : : IN : roTST11#tclsh flash:/company/localscripts/filtercmd.tcl show running-config
Apr 28 21:18:40.516: %MANAGEMENT-7-TESTING: Message from tty3(user id: admin): these are all the arguments: show running-config
Apr 28 21:18:40.517: %MANAGEMENT-7-TESTING: Message from tty3(user id: admin): the command show running-config has been used
Apr 28 21:18:40.540: %HA_EM-6-LOG: FILTERCMD2 : DEBUG(cli_lib) : : OUT : 1
Apr 28 21:18:40.540: %HA_EM-6-LOG: FILTERCMD2 : DEBUG(cli_lib) : : OUT : roTST11#
Apr 28 21:18:40.541:
roTST11#%HA_EM-6-LOG: FILTERCMD2 : DEBUG(cli_lib) : : CTL : cli_close called.
Apr 28 21:18:40.543:
Apr 28 21:18:40.543: tty is now going through its de ath sequence
So basically, i get the error message: %EEM: variable must have value between 0 and 2147483647 inclusive.
So im guessing this is becuase the variable $_exit_status is not getting filled with a valid value. But we can see from the puts message (action 003) that the return value from the script is a 1 or a 0 corresponding. But none of the commands will run. So what am i missing here?
I have tried to use return 1 and return 0 within the TCL script instead of puts -nonewline 1 but i get the same error message and i dont "see" the returned value from the action 003 puts message. If i dont use the -nonewline parameter, the script returns an additional empty line before exiting. It looks like this:
Apr 28 21:03:31.062: %MANAGEMENT-7-TESTING: Message from tty3(user id: admin): the command show running-config has been used
Apr 28 21:03:31.148: %HA_EM-6-LOG: FILTERCMD3 : DEBUG(cli_lib) : : OUT : 1
Apr 28 21:03:31.148: %HA_EM-6-LOG: FILTERCMD3 : DEBUG(cli_lib) : : OUT :
Apr 28 21:03:31.148: %HA_EM-6-LOG: FILTERCMD3 : DEBUG(cli_lib) : : OUT : roTST11#
Apr 28 21:03:31.149: %HA_EM-6-LOG: FILTERCMD3 : DEBUG(cli_lib) : : CTL : cli_close called.
I thought maybe the additional empty line breaks the $_exit_status variable but i get the same error message with both scenarios.
Please dont point out that i can achieve my goal by using some other methods like priviledge levels and so on. I have another goal in mind that for simplicity purposes i dont want to get into. Thanks for understanding.
Edit: had to split the word D E A T H in the debug as cisco does not allow me to post this offensive word
Solved! Go to Solution.
04-29-2024 02:50 AM
OK i found the solution. I can just set the value for this variable within the TCL script and the EEM will take over whatever i set. This works great. The full script is:
set blockcommand 0
if {$argv == "show version"} {
set blockcommand 1
}
if {$argv == "show running-config"} {
set blockcommand 0
}
if {$blockcommand == 1} {
# block this command and let the user know
puts -nonewline "This command is blockedENDOFMESSAGE"
set _exit_status 0
} else {
# allow this command
set _exit_status 1
}
And the configuration block looks like this. i had to do some regexing in order to prevent the output of empty lines:
no event manager applet FILTERCMD1
event manager applet FILTERCMD1
event cli pattern "^show version" sync yes
action 001 cli command "enable"
action 002 cli command "tclsh flash:/merbag/localscripts/filtercmd.tcl $_cli_msg"
action 003 regexp "(.*)ENDOFMESSAGE" "$_cli_result" fullmatch returnmessage
action 004 puts nonewline "$returnmessage"
no event manager applet FILTERCMD2
event manager applet FILTERCMD2
event cli pattern "^show running-config" sync yes
action 001 cli command "enable"
action 002 cli command "tclsh flash:/merbag/localscripts/filtercmd.tcl $_cli_msg"
action 003 regexp "(.*)ENDOFMESSAGE" "$_cli_result" fullmatch returnmessage
action 004 puts nonewline "$returnmessage"
Now when i enter the command, it works fine:
roTST11#show version
This command is blocked
roTST11#show running-config
Building configuration...
--- retracted ---
04-28-2024 08:22 PM
If you need TCL I would write the entire policy in EEM TCL and not call tclsh from an applet. Here is aTCL policy that prohibits three commands "show running-config, show ip interface brief, show version" and the exit status is set to 0 for these, otherwise set exit to 1 so the command will run. Denied cli commands use "OR" operator in regexp below. Entire policy is attached as it has notes included. The policy needs to be loaded as documented in the file attached and can not be loaded in tclsh.
::cisco::eem::event_register_cli pattern "show" sync yes
namespace import ::cisco::eem::*
namespace import ::cisco::lib::*
array set _sinfo [sys_reqinfo_routername]
set host $_sinfo(routername)
array set arr_einfo [event_reqinfo]
set clicmd "$arr_einfo(msg)"
# Default is to allow cli command, and specific list to deny cli
if [regexp {show version|ip interface brief|running-config} $clicmd ] {
action_syslog msg "Not Permitted: $clicmd"
exit 0
} else {
exit 1
}
Here are the three commands that are denied along with show clock that is permitted.
sdip#show run
sdip#
*Apr 29 03:18:14.964: %HA_EM-6-LOG: cliPriv.tcl: Not Permitted: show running-config
sdip#
sdip#show ver
sdip#show version
sdip#
*Apr 29 03:18:22.056: %HA_EM-6-LOG: cliPriv.tcl: Not Permitted: show version
sdip#
sdip#show ip int brief
sdip#
*Apr 29 03:18:28.963: %HA_EM-6-LOG: cliPriv.tcl: Not Permitted: show ip interface brief
sdip#
sdip#show clock
*03:18:34.495 UTC Mon Apr 29 2024
sdip#
04-29-2024 12:58 AM
Thank you for your answer. I have already looked into that and the "prevent" or "allow" part works great in this way. But the problem here is, that eem policies are very slow. i timed your script and it take around 180-185ms per run. My script i posted above only takes 5ms. The complete script that i built with the eem policy takes around 750-800ms and i want it to run on every command entered. So this way just slows down the CLI alot so that was the reason i was looking into an eem applet solution because its much quicker to execute.
04-29-2024 02:50 AM
OK i found the solution. I can just set the value for this variable within the TCL script and the EEM will take over whatever i set. This works great. The full script is:
set blockcommand 0
if {$argv == "show version"} {
set blockcommand 1
}
if {$argv == "show running-config"} {
set blockcommand 0
}
if {$blockcommand == 1} {
# block this command and let the user know
puts -nonewline "This command is blockedENDOFMESSAGE"
set _exit_status 0
} else {
# allow this command
set _exit_status 1
}
And the configuration block looks like this. i had to do some regexing in order to prevent the output of empty lines:
no event manager applet FILTERCMD1
event manager applet FILTERCMD1
event cli pattern "^show version" sync yes
action 001 cli command "enable"
action 002 cli command "tclsh flash:/merbag/localscripts/filtercmd.tcl $_cli_msg"
action 003 regexp "(.*)ENDOFMESSAGE" "$_cli_result" fullmatch returnmessage
action 004 puts nonewline "$returnmessage"
no event manager applet FILTERCMD2
event manager applet FILTERCMD2
event cli pattern "^show running-config" sync yes
action 001 cli command "enable"
action 002 cli command "tclsh flash:/merbag/localscripts/filtercmd.tcl $_cli_msg"
action 003 regexp "(.*)ENDOFMESSAGE" "$_cli_result" fullmatch returnmessage
action 004 puts nonewline "$returnmessage"
Now when i enter the command, it works fine:
roTST11#show version
This command is blocked
roTST11#show running-config
Building configuration...
--- retracted ---
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide