Hello.
I have created a user groud called funcionarios, that have access to all permissions, except Policy, because I dont want those users to modify other users passwords, but I want them to be able do modify scripts.
So i have set all scripts to not need the Policy permission.
I have two scripts, one that starts the global variables bandwidthsourceand switchseconds when i turn on the device, or restart it.
:global switchseconds 60
:global bandwidthsource MAIN
And have a second script, that checks that same global variable:
:if ($bandwidthsource="MAIN" && $switchseconds>10) do={
:if ([/ping 8.8.4.4 count=2]=0) do={:set switchseconds ($switchseconds - 10);
:log error "TROCANDO PARA INTERNET SIGNET EM $switchseconds SEGUNDOS"} else={:set switchseconds ($switchseconds + 10);
:if ($switchseconds<60) do={:log error "TROCADANDO PARA SIGNET EM $switchseconds SECONDS"}}}
The problem is: the script will only work if it have have the permission Policy. The script 2 can’t read that global variable value declared in the script 1 if it doesnt the policy permission
Can anyone help?
Is this a bug?
Thanks
It would be useful to know which version of RouterOS you are using.
What part of your script is it that fails?
Scripts, global variables and schedulers all have an “owner”.
This owner is commonly set to the user that created the object, or the last user that edited the object.
In older versions of RouterOS a global variable had an owner defined, this meant that a global variable created by UserA couldn’t be seen or accessed by UserB, and visa versa. Each user could even have their own separate global variable with the same name.
You can see all these global variables (and rather they have an owner assigned) in the “System → Scripts → Environment tab” menu of WinBox. But this requires full admin rights to view.
All scripts have an owner which defines what commands it is allowed to use (and which owned global variables it could see).
It is possible to change the owner of a script in the newer versions of RouterOS, but allowing this with any kind of automation will be a huge security risk and you may as well give them full admin rights.
Same for schedulers to a degree, expect their ownership can’t be changed, you have to recreate it.
This means that it is a HUGE headache to have multiple users manage scripts if they don’t all have the same permissions. And it is even worse on older RouterOS versions where global variables had owners.
Normally it is a good rule of thumb to ensure that a global variables is defined before you try to use/set it in a script.
For Example:
# Normally defined global variable.
:global test "yay"
:if ($test = "yay") do={
:log info "Test says yay"
}
# Ensuring global variable is defined, without changing value.
:global test
:if ($test = "yay") do={
:log info "Test still says yay"
}
# Delete the global variable.
/system script environment remove [find name=test]
# Deleted/Nonexistent global variable, may fail silently.
:if ($test = "yay") do={
:log info "Test doesn't says yay"
}
# Attempting to set a deleted/nonexistent global variable, will throw an error.
:set test "yay"
:if ($test = "yay") do={
:log info "Test complains about its existence"
}
The version is RouterOS 6.33.3, and tested with 6.35.4 too. The same happens.
The problem happens when script2 tries to modify or read a global variable value created by script1. Both scripts doesn’t have the ‘policy’ permission, so that the user group I created could modify the script when needed. Both scripts have the same owner.
I created a user group that doesnt have all permissions, except ‘policy’, so that it won’t have permission to modify another user password, or create other ones
If I print or compare the value of the a global variable in another script (that is not the one that created the global variables), its value is empty when the script is run without the ‘policy’ permission.
AFAIK, reading variables requires that you have both “read” and “write” permissions, but I thought that’s about it.
To prevent a user/script from being able to change passwords, you also need to disable the “password” policy BTW. The “policy” policy allows a user/script to change user permissions instead… and looking up the full policy descriptions, it seems that if the variable was created by another user, you also need “policy” to read it.
So that seems to be your key issue here… Even though both scripts have the same owner, the user who first initializes the variables is the one to take the ownership. I’d suggest you make a 3rd script which initializes the global variables, and nothing else. Remove the current variables, and run that script. If you’re running your current two scripts with the scheduler instead of “manually”, also run the initialization script with a schedule (as the “schedule” user is a different untouchable one).
the scritp1 is already just to initialize the global variables and is started by a scheduler
the script2 reads them, compare and changes them. This script is run each 10 seconds
it seens like it will need the admin with full privileges to modify scripts when neeed. Or a user just to that. Just because de global variables
here are the full scripts
Script 1: starts the variables when turn on the mikrotik
:global switchseconds 60
:global bandwidthsource MAIN
script2: runs every 10 seconds, to make a fail-over. It have some kind of pool, when it is empty, it changes the default route distance. It prevents fails over and back all the time then there is a lot of packet loss.
:global bandwidthsource
:global switchseconds
[size=85][font=Helvetica Neue, Helvetica, Arial, sans-serif]:if ($switchseconds>60) do={:set switchseconds 60}[/font][/size]
:if ($switchseconds<0) do={:set switchseconds 0}
:if ($bandwidthsource="MAIN" && $switchseconds<=10) do={
:set bandwidthsource BACKUP;
/ip route set [find comment="Signet"] distance=5;
:log error "INTERNET TROCADA PARA A SIGNET"}
:if ($bandwidthsource="BACKUP" && $switchseconds>=50) do={
:set bandwidthsource MAIN;
/ip route set [find comment="Signet"] distance=15;
:log warning "INTERNET TROCADA PARA PRODATA"}
:if ($bandwidthsource="MAIN" && $switchseconds>10) do={
:if ([/ping 8.8.4.4 count=2]=0) do={:set switchseconds ($switchseconds - 10);
:log error "TROCANDO PARA INTERNET SIGNET EM $switchseconds SEGUNDOS"} else={:set switchseconds ($switchseconds + 10);
:if ($switchseconds<60) do={:log error "TROCADANDO PARA SIGNET EM $switchseconds SECONDS"}}}
:if ($bandwidthsource="BACKUP" && $switchseconds<50) do={
:if ([/ping 8.8.4.4 count=2]=2) do={:set switchseconds ($switchseconds + 10);
:log warning "INTERNET PRODATA JÁ ESTÁ ONLINE POR $switchseconds SEGUNDOS. SERA UTILIZADA QUANDO CHEGAR EM 60 SEGUNDOS"} else={:set switchseconds ($switchseconds - 10);
:if ($switchseconds>0) do={:log warning "INTERNET PRODATA JÁ ESTÁ ONLINE POR $switchseconds SEGUNDOS. SERA UTILIZADA QUANDO CHEGAR EM 60 SEGUNDOS"}}}
Script seems harmless and simple.
One thing you could do is save the two variables as a static DNS entry instead. Simply make the first oct 127, “bandwidthsource” as the comment and “switchseconds” as the last oct, then save it as “whatever.localhost”.
I’ll give a code example in the morning if you need it.
if possible, it would be a nice idea to try that solution.
Thanks
Loading:
# Load variables from static DNS.
:global bandwidthsource
:global switchseconds
:if ([:len $bandwidthsource] = 0 || [:len $switchseconds] = 0) do={
/ip dns static {
:set bandwidthsource
:set switchseconds
:local codedIP
:local o [find where name="whatever.localhost"]
:if ([:len $o] != 0) do={
:set bandwidthsource [get $o comment]
:set codedIP ([get $o address])
:for i from=0 to=3 do={
:local p [:find $codedIP "."]
:if ([:len $p] != 0) do={
:set codedIP [:pick $codedIP ($p + 1) 255]
} else={
:set switchseconds [:tonum $codedIP]
}
}
}
}
}
:put $bandwidthsource
:put $switchseconds
Saving:
# Save variables to static DNS.
:global bandwidthsource
:global switchseconds
:if ([:len $bandwidthsource] != 0 || [:len $switchseconds] != 0) do={
/ip dns static {
:local o [find where name="whatever.localhost"]
:local codedIP ("127.0.0." . $switchseconds)
:if ([:len $o] != 0) do={
set $o comment=$bandwidthsource
set $o address=$codedIP
} else={
add name="whatever.localhost" address=$codedIP comment=$bandwidthsource
}
}
}
Only problem I foresee, is that that you need to save the variables to the static DNS every time you change them.
But I hope it helps.