unix pipeline causing program to terminate early - c

So I was attempting a CTF recently, and I needed to input some non-printing chars into stdin in order to overwrite a stack variable. I decided to pipe the output from a printf command into the program, and this worked to overwrite the variable, but had an unexpected side effect of killing the program whenever it hit a blocking call and was out of input.
The shortest C program I could write to demonstrate this issue is
#include <stdlib.h>
main()
{
system("/bin/sh");
}
running it normally produces the expected result
~$ ./a.out
> ls
. .. Documents etc etc
> _
but if I use a pipe on this program, I get
~$ echo "ls" | ./a.out
. .. Documents etc etc
~$
See the difference? If I use a pipe, system("/bin/sh") returns after it runs out of input and the program would normally block / wait for input. Maybe the pipe is sending an EOF causing system() to return? How can I make it not do this (act as though I typed it in normally) by changing the way I am using bash? (I cannot change the program in a CTF). Is there a better way to input non-printing chars?

Related

How can I access the file in C when the user used the '<' command on the shell?

I am trying to make a program that can process sentences in C in the POSIX environment. Assume that my program's name is "test". If the user entered just "./test", then my program will ask the user to enter some sentences. This one so far is easy.
However, if the user entered "./test < file.txt", the program should get the characters from that txt file. I do not know how I can get the characters of the file in C. I tried something like file = open(argv[2]);, but it did not work.
I will really appreciate it if you give me the answer to this question.
TL;DR: If you start your program like
./test
and you have to type in the input, then exactly the same program will read from file.txt if you start it as
./test < file.txt
Longer explanation starts here. (The following explanation is not 100% precise, but shall help to get an understanding what is going on in principle.)
In a C program you can open files with fopen. As a return value, fopen gives you a FILE pointer. However, when you start a program under Unix, three FILE pointers are already available. These default FILE pointers are stored in variables named stdin, stdout and stderr.
Of these, stdin can be used to read from, stdout and stderr can be written to. And, stdin is used as default in several C library calls, like, gets or scanf. Similarly, stdout is used by default for calls like printf.
Now, although they are called FILE pointers, they can in fact represent other things than just files. stdin could be a file, but it can also be a console where you can type in stuff.
This latter scenario is what you observe when you start your test program from the shell with the command
./test
In this case, the test process will be started with stdin just using the console from the shell from which you started the test program. Therefore, if in your test program you call, say, gets(), then your program will implicitly read from stdin, which represents the console input that was inherited from the shell. Consequently, in this case the user has to provide input by typing it in.
Now let's look at what happens if you start your process from the shell in the following way:
./test < file.txt
Here, the shell does a bit of extra work before it actually creates your test process. This is because the < file.txt part of your command line is interpreted by the shell - this is not passed as arguments to your program. Instead, what the shell does is, to open the file.txt and, when the test process is started, hand the opened file.txt over to the process such that in your test process stdin is connected to file.txt.
Then, the call to gets() in your program will again read from stdin, but this time stdin is not the console. This time stdin really corresponds to a file, that is, file.txt.

Executing more with "exec()" function corrupts line breaking in bash

I had an exercise to write a program that will do the following pipe processing:
ls -la | grep "^d" | more
After executing my program however, the bash interpreter would not break line nor display commands correctly, however after executing them the result is showed, it looks like the input for the console is not getting on stdout but somewhere else and i cant find the reason of this behavior.
I am using 3 child process with stdio redirected to connect the pipe between them.
The program finishes successfully it shows the good result, no errors are showed or whatever, also when i am using the cat instead of more everything works normally after execution, is it possible that more changes some system values and does not change them back?
It's likely that more is turning off echo and canonical mode on your TTY (see man 3 termios), and never switching them back on before it exits (either because it gets killed without a chance to, or because it doesn't think it's attached to a TTY). You can attach to more with gdb to find out why that's ahppening, or you could simply reset the terminal yourself before exiting.

Another Linux command output (Piped) as input to my C program

I'm now working on a small C program in Linux. Let me explain you what I want to do with a sample Linux command below
ls | grep hello
The above command is executed in the below passion (Let me know if I've got this wrong)
ls command will be executed first
Output will be given to grep command which will again generate output by matching "hello"
Now I would like to write a C program which takes the piped output of one command as input. Means, In the similar passion of how "grep" program was able to get the input from ls command (in my example above).
Similar question has been asked by another user here, but for some reason this thread has been marked as "Not a valid question"
I initially thought we can get this as a command line argument to C program. But this is not the case.
If you pipe the output from one command into another, that output will be available on the receiving process's standard input (stdin).
You can access it using the usual scanf or fread functions. scanf and the like operate on stdin by default (in the same way that printf operates on stdout by default; in the absence of a pipe, stdin is attached to the terminal), and the C standard library provides a FILE *stdin for functions like fread that read from a FILE stream.
POSIX also provides a STDIN_FILENO macro in unistd.h, for functions that operate one file descriptors instead. This will essentially always be 0, but it's bad form to rely on that being the case.
If fact, ls and grep starts at the same time.
ls | grep hello means, use ls's standard output as grep's standard input. ls write results to standard output, grep waits and reads any output from standard input at once.
Still have doubts? Do an experiment. run
find / | grep usr
find / will list all files on the computer, it should take a lot of time.
If ls runs first, then OS gives the output to grep, we should wait a long time with blank screen until find finished and grep started. But, we can see the results at once, that's a proof for that.

Checking if a file via stdin exists (C)

I'm having difficulty writing a function in C that checks whether a user inputed file (via stdin) exists. For instance if the program is run as ./a.out <myfile.txt, I want it to return false if this file does not exist. I can do this by passing the file as an argument (i.e ./a.out myfile.txt)using fopen(), but not sure how to do this using 'stdin' (i.e ./a.out <myfile.txt)
Ok to clarify:
The larger program is supposed to take the contents of a text file and perform actions on it. The program must be run in the command line as ./a.out arg1 arg2 <myfile.txt. If user ran the program as ./a.out arg1 arg2 or ./a.out (i.e not specifying the file to perform actions on), I want to prompt the user to include a file (using stdin <, not passed as an argument).
Stdin might not be coming from a file at all. Even if it is, when the user types "< myfile.txt" at the command line, the shell swallows that part of the command, and never passes it to the program. As far as the program is concerned, it's an anonymous stream of bytes that might be from a file, a device, a terminal, a pipe, or something else. It is possible to query which of these you have, but even if you know it's a file you won't get the name of the file given on the command line, only an inode.
Since the shell is responsible for opening the file for redirection, it will refuse to execute the command if the file doesn't open.
Input redirection is something done by the shell, not your program. It simply attaches the file to standard input.
Hence, if you try to redirect input from a non-existent file, the shell should complain bitterly and not even run your program, as shown in the following transcript:
pax> echo hello >qq.in
pax> cat <qq.in
hello
pax> cat <nosuchfile.txt
bash: nosuchfile.txt: No such file or directory
In any case, your program generally doesn't know where the input is coming from, since you can do something like:
echo hello | cat
in which no file is involved.
If you want your program to detect the existence of a file, it will have to open the file itself, meaning you should probably give the filename as an argument rather than using standard input.
Or, you could detect the file existence before running your program, with something like the following bash segment:
fspec=/tmp/infile
if [[ -f ${fspec} ]] ; then
my_prog <${fspec}
else
echo What the ...
fi
The OS prevent calling your program since it can provide a valid stdin if myfile.txt does not exists. You program will not run thus there is no way you can signal the file is missing, and this diagnostics is done at the OS level.
If user ran the program as ./a.out arg1 arg2 or ./a.out (i.e not specifying the file to perform actions on), I want to prompt the user to include a file (using stdin <, not passed as an argument).
You could use OS-specific functions to check whether stdin is terminal. Checking whether it's file is a very bad idea, because it's very useful to pipe into stdin ... in fact, that's a major reason that there is such a thing as stdin in the first place. If you only want to read from a file, not a terminal or pipe, then you should take the file name as a required argument and not read from the orginal stdin (you can still read from stdin by using freopen). If you insist that you don't want to do it that way, then I will insist that you want to do it wrong.

Use output of unfinished process in a C program

I am using tcpstat in a linux environment. I want to capture its output in a C program even though it has not finished. I tried using the popen() function, but it can only process the output after the program has finished. I want to process the output of tcpstat on the fly as and when it prints it on standard output. How do i do so?
For example,
$ tcpstat -i wlan0 1
Time:1297790227 n=2 avg=102.50 stddev=42.50 bps=1640.00
Time:1297790228 n=11 avg=86.36 stddev=19.05 bps=7600.00
Time:1297790229 n=32 avg=607.97 stddev=635.89 bps=155640.00
Time:1297790230 n=13 avg=582.92 stddev=585.55 bps=60624.00
The above output keeps going on till infinity. So I want to process the output in a C program as and when tcpstat outputs something onto stdout.
Thanks and Regards,
Hrishikesh Murali
Run tcpstat -i wlan0 -a 1 | your_program and read from the standard input in your program. This way the shell will take care of the piping.
The popen library function and the pipe system call can be used to achieve the same result at a lower level. You may want to take a look at named pipes too - they appear like files in userspace and can be manipulated in the same way.
Run tcpstat with the -F option, this will cause it to flush its output on every interval. (instead of using the default block buffering for stdout)
In addition, you may want to explicitly disable the buffering on your popen FILE handle using setbuf, eg.
setbuf(popen_fd, NULL);
Alternately, you can set it to be line buffered, using setlinebuf
setlinebuf(popen_fd);

Resources