Nagios core check: Is it possible to pipe sort -u in a check command? - nagios

Is it possible to |sort -u in a check command?
#check_active_Node
define command{
command_name check_active_node_list
command_line /usr/lib/nagios/plugins/check_active_node.sh '$ARG1$' '$ARG2$'|sort -u

Normally no. The pipe character "|" would normally not be allowed as part of the line being executed by Nagios - there are important security reasons for this. There are ways around it, but I'd not recommend using any of them. Your best solution would be to modify the plugin (create a check_active_node_custom.sh and edit that), and add what ever sorting you need to the script itself. Remember that the Nagios system expects certain return codes and text from a plugin, and that should still function as expected after your edits.

Related

Is it possible to override SSH expecting password input from /dev/tty in C

I am developing a piece of software in C that needs to SSH to another machine and run commands as root.
Something that looks like this:
char* GetPasswd(void);
void run(char* apnSshCommand)
{
FILE* lphSshFD = popen(apnSshCommand,"w");
fprintf(lphSshFD,GetPasswd());
fflush(lphSshFD);
fprintf(lphSshFD,"#Command to run in shell");
fflush(lphSshFD);
}
GetPasswd() would be a callback to a gui where the user has typed in the password
I know that the above code is not possible since SSH looks to it's own /dev/tty to provide the password for authentication.
I have read posts such as this that teases an answer using ioctl() and fcntl() but does not provide one. Along with this that shows it is possible from the command line however I have not been able to translate it.
Using expect is NOT an option
Using SSH keys are NOT an option
The SSH C library is NOT an option
Using sshpass is NOT an option
Without these, the only thing that I can think of is starting a new child process and redirect/close file descriptors to control what ssh has access to.
EDIT: These restrictions come from the fact that the system I am working on is extremely old and does not contain tools such as expect, sshpass and the SSH C library as well as being subject to multiple restrictions in regards to when sshkeys can be used
This works for me:
Create a script called pwd.sh that emits the password:
#!/bin/bash
echo -n mypassword
Run ssh in a new session like this:
SSH_ASKPASS=/path/to/pwd.sh DISPLAY= setsid -w ssh root#192.168.1.10 <command>
The effect of setsid is to run ssh detached from the controlling terminal, which is what is needed for it to respect SSH_ASKPASS.
I haven't tried, but I would expect to be able to run this command from C using system().
For the record, I tested this with OpenSSH_7.2p2 on Ubuntu.
I was able to come up with a solution by looking at the source code for sshpass which I found here

ftp file upload fails when special character is present in password

I was trying to upload a file through application i wrote in c.
As i did not find any API, i decided to go through commands.
Input command line looked like this.
ftp -u ftp://ftpuser:password#123#x.x.x.x/test.txt /tmp/test.txt
Whenever a special character is present, login will fail. when i tried with different user without any special characters in the password upload works.
How this issue can be resolved or is there any another method available like API which can be made use of.
If any sample code available then it will be of great help.
Special character means #, $, # (Ex : password#123, password$123)
code snippet:
RunCommandWithPipe(PSTRING CmdLine)
{
FILE *fp;
int status;
fp = popen(CmdLine, "r");
if (fp == NULL)
{
ErrGen(constErrOpenFile);
}
status = pclose(fp);
if (status == -1)
{
ErrGen(constErrCloseFile);
}
}
The reason why this doesn't work is because you are passing unfiltered meta characters into the shell. This is very dangerous. If someone untrustworthy gets to decide the value of any of the parameters to your ftp command, such as the username, password, ftp server, or file name, then that person will be able to run arbitrary shell commands.
You can see what's going on by putting an "echo" in front of your ftp command:
echo ftp -u ftp://ftpuser:password$123#x.x.x.x/test.txt /tmp/test.txt
You'll get this result:
ftp -u ftp://ftpuser:password23#x.x.x.x/test.txt /tmp/test.txt
The shell is trying to evaluate $1 as a variable, leaving an empty result.
There's a couple of things you can do.
1) Make the command safe by escaping all the meta characters. Here you need to be very careful, using a whitelist approach rather than just trying to get rid of the special characters you've thought of. In the whitelist approach you accept that some set of characters are safe, such as [A-Za-z0-9:_-]. Every other character you either strip out or escape by preceding it with a backslash. (eg. "foo:bar$baz&abc" becomes "foo:bar\$bazabc") If you do this way don't try to think of all the characters you know of that are special and escape those. You will most likely forget some, and not handle input this like:
ftp -u ftp://ftpuser:; rm -rf /;echo #x.x.x.x/test.txt /tmp/test.txt
2) Don't pass arguments on the shell, instead control the FTP client through fread()/fwrite() on the pipe that popen() gave you.
In this case what you do is launch the ftp client with no arguments. Then you write "OPEN 192.168.1.1" or wherever you want to connect. Then you write the username. Then you write the password. Then you write the GET or PUT command want. Then you write "EXIT" or write an EOF. You should read the result codes from the server. You'll get 200 series results on success. You'll get a 500 series result if the login is bad, etc.
You still have to watch out when piping into the FTP command because it will take shell escapes like "!rm -rf /", but there is much less opportunity for that than on the shell. You just need to make sure the strings you get to build your FTP commands are one line and that you always precede them with a valid FTP command. You should also watch out for any funny business with untrustworthy filenames. (eg. don't allow absolute paths, "..", and so forth)
You propably using a wrong charset to send the password

Execute any command-line shell like into execve

In case this is helpful, here's my environment: debian 8, gcc (with std = gnu99).
I am facing the following situation:
In my C program, I get a string (char* via a socket).
This string represents a bash command to execute (like 'ls ls').
This command can be any bash, as it may be complex (pipelines, lists, compound commands, coprocesses, shell function definitions ...).
I can not use system or popen to execute this command, so I use currently execve.
My concern is that I have to "filter" certain command.
For example, for the rm command, I can apply it only on the "/home/test/" directory. All other destinations is prohibited.
So I have to prevent the command "rm -r /" but also "ls ls && rm -r /".
So I have to parse the command line that is given me, to find all the command and apply filters on them.
And that's when I'm begin to be really lost.
The command can be of any complexity, so if I want to make pipelines (execve execute a command at a time) or if I want to find all commands for applying my filters, I'll have to develop parser identical to that of sh.
I do not like creating the wheel again, especially if I make it square.
So I wonder if there is a feature in the C library (or that of gnu) for that.
I have heard of wordexp, but I do not see how manage pipelines, redirection or other (in fact, this does not seem made for this) and i do not see how can I retrieve all the command inside the commande.
I read the man of sh(1) to see if I can use it to "parse" but not execute a command, but so far, I find nothing.
Do I need to code a parser from the beginning?
Thank for your reading, and I apologies for my bad english : it's not my motherlanguage (thanks google translate ...).
Your problem:
I am facing the following situation: In my C program, I get a string
(char* via a socket). This string represents a bash command to execute
(like 'ls ls'). This command can be any bash, as it may be complex
(pipelines, lists, compound commands, coprocesses, shell function
definitions ...).
How do you plan on authenticating who is at the other end of the socket connection?
You need to implement a command parser, with security considerations? Apparently to run commands remotely, as implied by "I get a string (char* via a socket)"?
The real solution:
How to set up SSH without passwords
Your aim
You want to use Linux and OpenSSH to automate your tasks. Therefore
you need an automatic login from host A / user a to Host B / user b.
You don't want to enter any passwords, because you want to call ssh
from a within a shell script.
Seriously.
That's how you solve this problem:
I receive on a socket a string that is a shell command and I have to
execute it. But before execute it, i have to ensure that there is not
a command in conflict with all the rules (like 'rm only inside this
directory, etc etc). For executing the command, I can't use system or
popen (I use execve). The rest is up to me.
Given
And that's when I'm begin to be really lost.
Because what you're being asked to do is implement security features and command parsing. Go look at the amount of code in SSH and bash.
Your OS comes with security features. SSH does authentication.
Don't try to reinvent those. You won't do it well - no one can. Look how long it's taken for bash and SSH to get where they are security-wise. (Hint: it's decades because there's literally decades of history and knowledge that were built into bash and SSH when they were first coded...)

Hooks on terminal. Can I call a method before a command is run in the terminal?

I am wanting to make a terminal app that stores information about files/directories. I want a way to keep the information if the file is moved or renamed.
What I thought I could do is have a function execute before any command is run. I found this:
http://www.twistedmatrix.com/users/glyph/preexec.bash.txt
But I was wondering if this would be a good way to go about it. Or should I do something else?
I would like to call that function from a C program whenever mv is entered I suppose.
If what you're trying to do is attach some sort of metadata to files, there's a much better supported way to do that -- extended attributes.
Another solution might be to use the file's inode number as an index into a database you maintain yourself.
Can you alias the mv command? in .profile or .bashrc
alias mv=/usr/bin/local/mymv
where mymv is a compiled executable that runs your C code function and calls /usr/bin/mv.
precmd and preeexec add some overhead to every bash script that gets run, even if the script never calls mv. The downside to alias is that it requires new code in /usr/local and if scripts or users employ /usr/bin/mv instead of mv it will not do what you want. Generally doing something like this often means there is a better way to handle the problem with some kind of service (daemon) or driver. Plus, what happens if your C code cannot correctly handle interesting input like
mv somefille /dev/null
If you want to run command each time after some command was executed in the terminal, just put the following in ~/.bashrc:
PROMPT_COMMAND="your_command;$PROMPT_COMMAND"
If you want your command to be executed each time before mv is executing, put the following in ~/.bashrc:
alias mv="your_script"
Make sure that your script will execute real mv if needed.
You can use inotify library to track filesystem changes. It's good solution, but once user remove file, it's already gone.
You might be able to make use of the DEBUG trap in Bash.
From man bash:
If a sigspec is DEBUG, the command arg is executed before every
simple command, for command, case command, select command, every
arithmetic for command, and before the first command executes in
a shell function
I found this article when I was forced to work in tcsh and wanted to ensure a specific environemtn variable was present when the user ran a program from a certain folder (without setting that variable globally)
tcsh can do this.
tcsh has special alias, one of which is precmd
This can be used to run a script just before the shell prompt is printed.
e.g. I used set precmd 'bash $HOME/.local/bin/on_cd.sh'
This might be one of the very few useful features in csh.
It is a shame but I don't think the same or similar feature is in bash or other sh derivites (ash, dash etc). Related answer.

How to redirect output away from /dev/null

I have an application that runs the a command as below:
<command> <switches> >& /dev/null
I can configure <command>, but I have no control over <switches> . All the output generated by this command goes to /dev/null. I want the output to be visible on screen or redirected to a log file.
I tried to use freopen() and related functions to reopen /dev/null to another file, but could not get it working.
Do you have any other ideas? Is this possible at all?
Thanks for your time.
PS: I am working on Linux.
Terrible Hack:
use a text editor in binary mode open the app, find '/dev/null/' and replace it with a string of the same length
e.g '~/tmp/log'
make a backup first
be carefull
be very carefull
did I mention the backup?
Since you can modify the command you run you can use a simple shell script as a wrapper to redirect the output to a file.
#!/bin/bash
"$#" >> logfile
If you save this in your path as capture_output.sh then you can add capture_output.sh to the start of your command to append the output of your program to logfile.
Append # at the end of your command so it becomes <command> # >& /dev/null, thus commenting out the undesired part.
Your application is probably running a shell and passing it that command line.
You need to make it run a script written by you. That script will replace >/dev/null in the command line with >>/your/log and call the real shell with the modified command line.
The first step is to change the shell used by the application. Changing the environment variable SHELL should suffice, i.e., run your application as
SHELL=/home/user/bin/myshell theApp
If that doesn't work, try momentarily linking /bin/sh to your script.
myshell will call the original shell, but after pattern-replacing the parameters:
#!/bin/bash
sh ${1+"${#/\>\/dev\/null/>>\/your\/log}"}
Something along these lines should work.
You can do this with an already running process by using gdb. See the following page: http://etbe.coker.com.au/2008/02/27/redirecting-output-from-a-running-process/
Can you create an alias for that command? If so, alias it to another command that dumps output to a file.
The device file /dev/tty references your application's controlling terminal - if that hasn't changed, then this should work:
freopen("/dev/tty", "w", stdout);
freopen("/dev/tty", "w", stderr);
Alternatively, you can reopen them to point to a log file:
freopen("/var/log/myapp.log", "a", stdout);
freopen("/var/log/myapp.err", "a", stderr);
EDIT: This is NOT a good idea and certainly not worth trying unless you know what this can break. It works for me, may work for you as well.
Ok, This is a really bad hack and probably not worth doing. Assuming that none of the other commands works, and you simply do not have access to the binary/application (which contains the command with /dev/null) and you cannot re-direct the output to other file (by replacing /dev/null).
Then, you can delete /dev/null ($> rm /dev/null) and create your own file at its place (preferably with a soft link) where all the data can be directed. When you are done, you can create the /dev/null once again using following command:
$> mknod -m 666 /dev/null c 1 3
Just to be very clear, this is a bad hack and certainly requires root permissions to work. High chances that your re-directed file may contain data from many other applications/binaries which are running and use /dev/null as sink.
It may not exactly redirect, but it allows to get the output wherever it's being sent
strace -ewrite -p $PID
It's not that cleen (shows lines like: write(#,) ), but works! (and is single-line :D ) You might also dislike the fact, that arguments are abbreviated. To control that use -s parameter that sets the maxlength of strings displayed.
It catches all streams, so You might want to filter that somehow.
You can filter it:
strace -ewrite -p $PID 2>&1 | grep "write(1"
shows only descriptor 1 calls. 2>&1 is to redirect stderr to stdout, as strace writes to stderr by default.
In perl, if you just want to redirect STDOUT to something slightly more useful, you can just do something like:
open STDOUT, '>>', '/var/log/myscript.log';
open STDERR, '>>', '/var/log/myscript.err';
at the beginning of your script, and that'll redirect it for the rest of your script.
Along the lines of e-t172's answer, can you set the last switch to (or append to it):
; echo
If you can put something inline before passing things to /dev/null (not sure if you are dealing with a hardcoded command), you could use tee to redirect to something of your choice.
Example from Wikipedia which allows escalation of a command:
echo "Body of file..." | sudo tee root_owned_file > /dev/null
http://en.wikipedia.org/wiki/Tee_(command)

Resources