Cacti extend snmp by a custom script - linux

I have created a graph on Cacti about time to access to a specific page on our infrastructure with cacti and net-snmp.
I have extended the capability with adding two new lines in file /etc/snmp/snmpd.conf :
extend stat_page1 /usr/local/bin/cacti/access_page.sh context1
extend stat_page2 /usr/local/bin/cacti/access_page.sh context2
I have restarted the daemon snmpd to load this configuration.
The script called is describe below, with other value, because for some reason, i can show this.
#!/bin/bash
domain="mydomain"
cookie_name="myCookie"
token="myToken"
if [ $# -eq 1 ]
then
if [ "$1" = "context1" ]
then
target_url="https://${domain}/${1}/page1.html"
TIME=$(curl -s -w "%{time_total}" -o /dev/null --cookie \"${cookie_name}=${token}\" ${target_url})
echo "$TIME"
elif [ "$1" = "context2" ]
then
target_url="https://${domain}/${1}/page2.html"
TIME=$(curl -s -w "%{time_total}" -o /dev/null --cookie \"${cookie_name}=${token}\" ${target_url})
echo "$TIME"
fi
If I launch the script manually i have this
$ /usr/local/bin/cacti/access_page.sh context2
0.061
$ /usr/local/bin/cacti/access_page.sh context1
0.041
When I launch the script with snmpget, I have this result:
snmpwalk -v2c -c myCommunity localhost NET-SNMP-EXTEND-MIB::nsExtendOutput2Table
NET-SNMP-EXTEND-MIB::nsExtendOutLine."stat_page1".1 = STRING: 0.000
NET-SNMP-EXTEND-MIB::nsExtendOutLine."stat_page2".1 = STRING: 0.000
All time, I get 0.000 value by snmp command and manually a real value.
Could you help me about it?, please

Recently i had an issue with snmp and the execution script that call the curl command.
This post was the closest of the problem when i searched some solutions.
I found a solution without disabling SELinux.
I am a newbie in SELinux but i solved this issue with some SELinux configuration, that could interest someone in the future.
Context :
Centos 7
Content of the configuration file for SNMP /etc/snmp/snmpd.conf :
# sec.name source community
com2sec myuser default public
# groupName securityModel securityName
group mygroup v2c pad
# name incl/excl subtree mask(optional)
view systemview included .1.3.6.1.4
view systemview included .1.3.6.1.4.1
view systemview included .1.3.6.1.4.1.1234
view systemview included .1.3.6.1.4.1.1234.1
# group context sec.model sec.level prefix read write notif
access mygroup "" any noauth exact systemview none none
perl do "/appli/snmp_scripts/agent.pl"
SNMAP agent agent.pl :
#!/usr/bin/perl
use NetSNMP::agent (':all');
use NetSNMP::ASN qw(ASN_OCTET_STR ASN_INTEGER);
sub handler {
my ($handler, $registration_info, $request_info, $requests) = #_;
my $request;
for($request = $requests; $request; $request = $request->next()) {
my $oid = $request->getOID();
if ($request_info->getMode() == MODE_GET) {
if ($oid == new NetSNMP::OID(".1.3.6.1.4.1.1581.1.6.2.1.5")) {
$request->setValue(ASN_OCTET_STR,`/path/to/myscript`);
}
}
}
}
my $AGENT_OID = ".1.3.6.1.4.1.1234";
$agent->register("MYAGENT", ".1.3.6.1.4.1.1234",
\&handler);
Solution:
When i looked for trace of the execution, with sudo systemctl status snmpd, some trace of curl were display :
snmpd: curl: (7) Failed to connect to 127.0.0.1:8081 Permission denied
However, the server was running well at this port and the script executed outside SNMP worked well.
SELinux errors have been generated in audit logs :
$> sudo grep snmp /var/log/audit/audit.log | audit2allow -w -a
type=AVC msg=audit(1528188940.802:2025): avc: denied { name_connect } for pid=26809 comm="curl" dest=8081 scontext=system_u:system_r:snmpd_t:s0 tcontext=system_u:object_r:transproxy_port_t:s0 tclass=tcp_socket
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.
$> sudo grep snmp /var/log/audit/audit.log | audit2allow -M mysnmpmodule
******************** IMPORTANT ***********************
To make this policy package active, execute:
semodule -i snmpdcanopensocket.pp
Follow the step told by audit2allow comm apply to SELinux the new created module for snmp_t. The audit2allow -M command generated two files snmpdcanopensocket.pp snmpdcanopensocket.te in your current directory.
SELinux needs the .pp file to remap it's security rules.
$> semodule -i snmpdcanopensocket.pp
Restart the SNMP service with sudo systemctl restart snmp
Now the curl in the script executed by SNMP behaves well and does not quit with a (7) error code.

I have done this test and when i call the script i have permission denied when I do this : line 34: /tmp/echo-curl: Permission denied, and I have done a script with just id to be sure that is launched with privilege user.
I have find the source of the problem, which is probably due to enforcing of SELinux – user3249935

Related

When trying to install openFOAM inside a docker container, How do I set the workDir to a location in my mac user directory

I'm using the following script to install openFOAM in a docker container:
#!/bin/sh
#------------------------------------------------------------------------------
# ========= |
# \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
# \\ / O peration |
# \\ / A nd | Copyright (C) 2017-2020 OpenFOAM Foundation
# \\/ M anipulation |
#-------------------------------------------------------------------------------
# License
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
#
# Script
# openfoam8-macos
#
# Description
# Run script for an OpenFOAM 8 Docker image at:
# https://hub.docker.com/r/openfoam
#
#------------------------------------------------------------------------------
Script=${0##*/}
VER=8
usage () {
exec 1>&2
while [ "$#" -ge 1 ]; do echo "$1"; shift; done
cat <<USAGE
Usage: ${0##*/} [OPTIONS]
options:
-d | -dir host directory mounted (defaults to current directory)
-x | -xhost use custom X authority and give container host network
-h | -help help
-p | -paraview include ParaView in the Docker image
Launches the OpenFOAM ${VER} Docker image.
- Requires installation of docker-engine.
- Runs a "containerized" bash shell environment where the user can run OpenFOAM
and, optionally, ParaView (see below).
- The container mounts the user's file system so that case files are stored
permanently. The container mounts the current directory by default, but the
user can also specify a particular directory using the "-d" option.
- Mounting the user's HOME directory is disallowed.
- The '-xhost' option is useful when accessing the host via 'ssh -X'.
This option should only be used when strictly necessary, as it relies on the
option '--net=host' when launching the container in Docker, which will
give to the container full access to the Docker host network stack and
potentially the host's system services that rely on network communication,
making it potentially insecure.
ParaView:
Graphical applications from the Docker container require installation of the
Xquartz X server to display on the host machine. While applications such as
Gedit, Emacs and GnuPlot will run effectively using Xquartz, more intensive
OpenGL applications, in particular ParaView, can be prohibitively slow.
Therefore, the default Docker image does not contain ParaView and users can
instead install ParaView directly from the vendor and use the built-in reader
module for OpenFOAM: http://www.paraview.org/download
However, if the user wishes to include ParaView with the official OpenFOAM
reader module in their Docker container, they can do so with the "-p" option.
Example:
To store data in ${HOME}/OpenFOAM/${USER}-${VER}, the user can launch
${Script} either by:
cd ${HOME}/OpenFOAM/${USER}-${VER} && ${Script}
or
${Script} -d ${HOME}/OpenFOAM/${USER}-${VER}
Further Information:
http://openfoam.org/download/8-macos
Note:
The container user name appears as "openfoam" but it is just an alias.
USAGE
exit 1
}
DOCKER_IMAGE='openfoam/openfoam8-graphical-apps'
MOUNT_DIR=$(pwd)
CUSTOM_XAUTH=""
DOCKER_OPTIONS=""
while [ "$#" -gt 0 ]
do
case "$1" in
-d | -dir)
[ "$#" -ge 2 ] || usage "'$1' option requires an argument"
MOUNT_DIR=$2
shift 2
;;
-x | -xhost)
CUSTOM_XAUTH=yes
shift
;;
-h | -help)
usage
;;
-p | -paraview)
DOCKER_IMAGE='openfoam/openfoam8-paraview56'
shift
;;
*)
usage "Invalid option '$1'"
;;
esac
done
[ -d "$MOUNT_DIR" ] || usage "No directory exists: $MOUNT_DIR"
MOUNT_DIR=$(cd "$MOUNT_DIR" && pwd -P)
[ "$MOUNT_DIR" = "$(cd "$HOME" && pwd -P)" ] && \
usage "Mount directory cannot be the user's home directory" \
"Make a subdirectory and run from there, e.g." \
" mkdir -p ${HOME}/OpenFOAM/$(whoami)-${VER}" \
" ${Script} -d ${HOME}/OpenFOAM/$(whoami)-${VER}"
if [ -n "$CUSTOM_XAUTH" ]
then
XAUTH_PATH="${MOUNT_DIR}/.docker.xauth.$$"
touch "${XAUTH_PATH}"
# Generate a custom X-authority file that allows any hostname
xauth nlist "$DISPLAY" | sed -e 's/^..../ffff/' | \
xauth -f "$XAUTH_PATH" nmerge -
DOCKER_OPTIONS="-e XAUTHORITY=$XAUTH_PATH
-v $XAUTH_PATH:$XAUTH_PATH
--net=host"
fi
USER_ID=$(id -u 2> /dev/null)
[ -n "$USER_ID" ] || usage "Cannot determine current user ID"
GROUP_ID=$(id -g)
HOME_DIR='/home/openfoam'
echo "Launching $0"
echo "User: \"$(id -un)\" (ID $USER_ID, group ID $GROUP_ID)"
IFACES=$(ifconfig | grep ^en | cut -d: -f1)
[ "$IFACES" ] || \
usage "Cannot find a network interface for DISPLAY with ifconfig" \
"Please report an issue at http://bugs.openfoam.org" \
" providing the output of the command: ifconfig"
for I in $IFACES
do
IP=$(ifconfig "$I" | grep inet | awk '$1=="inet" {print $2}')
[ "$IP" ] && break
done
[ "$IP" ] || \
usage "Cannot find a network IP for DISPLAY with ifconfig" \
"Please report an issue at http://bugs.openfoam.org" \
" providing the output of the command: ifconfig"
xhost + "$IP"
docker run -it \
--rm \
-e DISPLAY=$IP:0 \
-u $USER_ID:$GROUP_ID \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-v $MOUNT_DIR:$HOME_DIR \
$DOCKER_OPTIONS \
$DOCKER_IMAGE
[ -n "$CUSTOM_XAUTH" -a -e "${XAUTH_PATH}" ] && rm "${XAUTH_PATH}"
This creates a user 'ofuser'. Why? Once I run the above script and then
xhost +local:of_v2006
docker start of_v2006
docker attach of_v2006
I end up in docker with:
[ofuser#3032b6018d82 woo]$ whoami
ofuser
I follow instructions to do a simulation and it creates files that are supposed to be available from the mac os itself, i.e. outside the docker container, but they seem to be in locations like /home/ofuser/...../ofuser/run/..., which don't seem to exist outside the container. Part of output:
[ofuser#5b3db0ac969b woo]$ mkdir $FOAM_RUN
mkdir: cannot create directory '/home/ofuser/OpenFOAM/ofuser-v2006/run': No such file or directory
So, how do I make the user 'foam' or 'woo' instead of ofuser. How did that user come to be? How an I set the workDir to be something like /Users/woo/Containers/foam? Do I have to have that /tmp/.X11-unix stuff in the setup? The display doesn't connect to my XQuartz display I've set up, etc.
I have the same setup running and yes it is possible. Took some time for me to get it running as well but I think I can clarify a few things.
First about the question regarding the directory. This can be set up in the dockerfile. The default dockerfile provided was not sufficient for me as well.
See the extract below:
"Mounts": [
...
{
"Type": "bind",
"Source": "/home/*****/OpenFOAM/run",
"Destination": "/home/openfoam",
"Mode": "Z",
"RW": true,
"Propagation": "rprivate"
},
......
This binds the "Source" - on your machine - with the "Destination" directory inside the container. The crucial option here for me was the "Z" flag which was not present in the default docker file.
The X11 setup also depends on the rights set by the "Z" flag in the dockerfile and can / should be set there. I am not completely sure about your actual setup but this works fine for me.
"Mounts": [
...
{
"Type": "bind",
"Source": "/tmp/.X11-unix",
"Destination": "/tmp/.X11-unix",
"Mode": "Z",
"RW": true,
"Propagation": "rprivate"
},
......
Regarding the new added user I still not get the reason behind it myself but I can tell you I had to use a second user and its working fine.
Normally you only use this user to log in into the container and nothing else. Under Linux execute these steps and verify the new user is in the docker usergroup
$ sudo groupadd docker
$ sudo usermod -aG docker <user>
$ sudo groups <user>

Running linux commands inside bash script throws permission denied error

We have linux script in our environment which does ssh to remote machine with a common user and copies a script from base machine to remote machine through scp.
Script Test_RunFromBaseVM.sh
#!/bin/bash
machines = $1
for machine in $machines
do
ssh -tt -o StrictHostKeyChecking=no ${machine} "mkdir -p -m 700 ~/test"
scp -r bin conf.d ${machine}:~/test
ssh -tt ${machine} "cd ~/test; sudo bash bin/RunFromRemotevm.sh"
done
Script RunFromRemotevm.sh
#!/bin/bash
echo "$(date +"%Y/%m/%d %H:%M:%S")"
Before running Test_RunFromBaseVM.sh script base vm we run below two commands.
eval $(ssh-agent)
ssh-add
Executing ./Test_RunFromBaseVM.sh "<list_of_machine_hosts>" getting permission denied error.
[remote-vm-1] bin/RunFromRemotevm.sh:line 2: /bin/date: Permission denied
any clue or insights on this error will be of great help.
Thanks.
I believe the problem is the presence of the NOEXEC: tag in the sudoers file, corresponding to the user (or group) that's executing the "cd ~/test; sudo bash bin/RunFromRemotevm.sh" command. This causes any further execv(), execve() and fexecve() calls to be refused, in this case it's /bin/date.
The solution is obviously remove the NOEXEC: from the main /etc/sudoers file or some file under /etc/sudoers.d, whereever is this defined.

What's the best way to test if a user can sudo in Bash?

Reading the sudo man page, I see that the -v flag can be used to check if the user has sudo privileges in his workstation. I have a piece of script that needs to test it. If the user has not sudo privileges, it prints on screen:
Sorry, user tester may not run sudo on debian.
How can I suppress this message and just execute the rest of the code?
Try to append >/dev/null in your command. In case the message is printed in stderr then use 2>/dev/null or as advised in comments use &>/dev/null to redirect both stdout and stderr to null.
Using sudo -l or --list
As per the man page, sudo can be used with -l or --list to get the list of allowed and forbidden commands for any particular user.
The syntax would be: sudo -l [-AknS] [-a type] [-g group] [-h host] [-p prompt] [-U user] [-u user] [command]
If we use sudo --list without any arguments, then it will print the list of allowed and forbidden commands for the user who is executing the sudo command
sudo --list
User root may run the following commands on client:
(ALL) ALL
Depends on what you mean by "can user sudo"
Short answer:
If can_auto_sudo=$(sudo -l -n sudo &>/dev/null; echo $?) is 0, you can sudo as much as you want.
Long Answer
Do you need to test before or can you just handle error cases?
How much do you need to know, the sudoers real username is a valid piece of data to want, for example.
This question is often asking several different but related questions. So I will ask those more precisely and then answer for each.
1. Is this script being run using sudo?
[ $EUID -eq 0 ] || exit 1 # Exit if not effectively root
2. Can this user run a specific command as root using sudo?
sudo -l /usr/bin/program &>/dev/null || exit 2 # Exit if it can't run this as sudo
3. Can this user run sudo without interacting?
sudo -l -n /usr/bin/program &>/dev/null || exit 3 # Exit if requires interaction
4. Can I check all that ahead of time?
`sudo -ll -U $USER # tells you which commands can be runs with sudo by user (have to parse yourself)
5. Script being run with sudo or actually root?
[[ "$(printenv SUDO_USER)" = "" ]] || echo "$SUDO_USER is sudoing!" && exit 5

How to demand root privileges in a shell script? [duplicate]

This question already has answers here:
How to check if running as root in a bash script
(21 answers)
Closed 7 years ago.
Say you have a shell script that could potentially require root privileges. You don't want to force the user to run it as sudo. However, if it does require that privilege, you want to prompt the user to enter their password, rather than complaining and forcing them to re-enter the command with sudo.
How would you go about doing this in a Bash script? sudo true seems to work, but it feels like a hack. Is there a better way?
Here's what I often do. This is loose pseudo-code but should give you the idea:
# myscript -- possibly execute as sudo
if (passed -e option) then
read variables from envfile
else
...
need_root = ...
# set variables ...
if ($need_root && $uid != 0) then
env [or whatever] > /tmp/envfile
exec sudo myscript -e/tmp/envfile ...
fi
fi
# stuff to execute as root [or not] ...
The command
sudo -nv
checks whether the user has current sudo credentials (-v), but will fail rather than prompting if access has expired (-n).
So this:
if sudo -nv 2>/dev/null && sudo -v ; then
sudo whoami
else
echo No access
fi
will check whether the user's sudo credentials are current, and prompt for a password only if they're not.
There is a possible race condition: the user's credentials could expire just after the check.
As ghoti points out in a comment, this may not work if the sudoers file is set up to allow only certain commands to be executed. For that and other reasons, be sure to check whether each sudo command succeeded or failed.
If your plan is to use sudo for privilege escalation, one wrinkle you may have to deal with is that that sudo can be set up to permit root access to some commands and not others. For example let's imagine you've got a server that runs VirtualBox, with different people managing the applications than are managing the OS. Your sudoers file might contain something like the following:
Cmnd_Alias SAFE = /bin/true, /bin/false, /usr/bin/id, /usr/bin/who*
Cmnd_Alias SHUTDOWN = /sbin/shutdown, /sbin/halt, /sbin/reboot
Cmnd_Alias SU = /bin/su, /usr/bin/vi*, /usr/sbin/visudo
Cmnd_Alias SHELLS = /bin/sh, /bin/bash, /bin/csh, /bin/tcsh
Cmnd_Alias VBOX = /usr/bin/VBoxManage
%wheel ALL=(ALL) ALL, !SU, !SHELLS, !SHUTDOWN
%staff ALL=(ALL) !SU, !SHELLS, NOPASSWD: SAFE
%operator ALL=(ALL) SAFE, SHUTDOWN
%vboxusers ALL=(ALL) NOPASSWD: VBOX
In this case, a member of the vboxusers unix group will always get a successful response to a sudo -nv, because of the existence of the NOPASSWD entry for that group. But a member of that group running any other command than VBoxManage will get a password challenge and a security warning.
So you need to determine whether the command you need to run can be run without a password prompt. If you don't know how sudo is configured on the system where your script is running, the canonical test is to run the command. Running sudo -nv will only tell you whether you are authenticated; it won't tell you what commands you have access to.
That said, if you can safely rely on a sudo configuration where, say, membership in wheel group gives you access to all commands, for example with:
%wheel ALL=(ALL) ALL
then you can use sudo -nv to test for escalation capabilities. But your script might have some things that it runs as root, and some things it doesn't. You might also want to consider other tools besides sudo for privilege escalation.
One strategy might be to set a variable to preface commands if the need is there, but leave the variable blank if you're already root (i.e. running the entire script inside sudo).
if ! which sudo >/dev/null 2>/dev/null; then
PM_SU_CMD="su - root -c"
elif sudo -nv 2>/dev/null; then
PM_SU_CMD="sudo"
else
echo "ERROR: I can't get root." >&2
exit 1
fi
Of course, if we are already root, unset this to avoid potential conflict:
[ `ps -o uid= $$` -eq 0 ] && unset PM_SU_CMD
(Note that this is a query of the system's process table; we don't want to rely on the shell's environment, because that can be spoofed.)
Then, certain system utilities might be made more easily available using functions:
# Superuser versions for commands that need root privileges
find_s () { $PM_SU_CMD "/usr/bin/find $*"; }
mkdir_s () { $PM_SU_CMD "/bin/mkdir -p $1"; }
rm_s () { $PM_SU_CMD "/bin/rm $*"; }
Then within your script, you'd simply use the _s version of things that need to be run with root privileges.
This is of course by no means the only way to solve this problem.

Check if different user has read/write permissions to a file on linux

How can I check if a specific user with no shell assigned can write or read a file ?
As an example we can use apache user... is there any option in touch or any other commands?
Thanks
The "test" command is designed for this use case.
sudo -u otheruser test -r /path/to/file
will return 0 if otheruser can read the file, or 1 if otheruser cannot read the file. You can run test -r /path/to/file; echo "$?" to view the return code of the test command.
Use test -w to test for write permission and test -x to test for execute permission.
Test Read Permission
Attempt to read the beginning of the file and discard the normal output. You can then look for an empty string (success) or a "Permission denied" message (you can also check for other error messages such as "No such file or directory"). For example:
head -1 /path/to/file 2>&1 > /dev/null | grep 'Permission denied'
Test Write Permission
Use the touch command with the -c (--no-create) option. Combine stdout and stderr and again search for an empty string (success) or an error:
touch -c /path/to/file 2>&1 | grep 'Permission denied'
If you're explicitly testing write access of a directory, be sure to test the directory and not a file contained within, since with the -c option, there's no error condition if the file doesn't exist even in a directory you don't have write access to:
From Wikipedia: touch (Unix)
-c, if the file does not exist, do not create it and do not report this condition
Test As Specific User
The final piece of the puzzle is how to check this as a different user. As root execute the test command as the desired user with "sudo -u [username] [command]" so using your suggested user:
sudo -u apache touch -c /path/to/file 2>&1

Resources