Parse a argv in c to a command in unix - c

I am new to unix and require some help.
I have another program call projectc which is an suid program located on another user call userb . userb has a directory pass that only has permission for write and read for its owner (userb)
I am trying to use the printf to do a command printf(system("cat /home/userb/pass")) through the argv argument.
I am able to do it in the c code printf(system("cat /home/userb/pass")) directly but doing it in the argv argument, i am unable to do it).
Is there anyway to parse the argv[1] parameter into a command?
this is my c program that I was trying to run in unix.
int main( int argc, char **argv){
printf(argv[1]);
return 0;
}

printf(system("cat /home/userb/pass"))
The reason this seemed to work is because the spawned subprocess printed on the screen. The printf was not only unnecessary but actually a bug. The first parameter to printf is a string (char*), while the retrn value from systemis an int.
A correct call would be:
int success = system("cat /home/userb/pass");
If argv[1] is the command you want to run you can just call:
int status = system(argv[1]);
You could then run your program like this:
myprogram "cat /home/userb/pass"
Note the double quotes - they ensure that the entire command is passed as a single parameter. Without the quotes it would be divided into two parameters.
And please turn up your compiler warning level. printf(system("cat /home/userb/pass")) should give some big warnings/errors when you compile.

Related

How to accept file argument in C?

I know, if ran in bash, my program is supposed to able to handle arguments like (where a.out is the name of file):
$ a.out <inputFile
Does this mean that inputFile is argv[1]? If so, what is the data type of argv[1] in case I need to pass it in to some other function? Would I read it using something like:
FILE *fopen( const char * filename, const char * mode );
OR
Does that mean I have to accept input from user getchar() or something?
How do I deal with such situations?
There's two ways to receive input:
Via STDIN, which is a pre-defined filehandle (fd 0 or STDIN_FILENO) you can read from at any time.
Via command-line arguments passed by argv
The shell interprets redirection operators to adjust what STDIN actually is, so by the time the program runs the only arguments left are:
"a.out"
The redirection is gone. It's just "piped" into STDIN.
Shell operators like <, > and | are interpreted by the shell before your program is run. The same goes for interpolation like $ variables and other shell-specific functions.
The command
./a.out < inputFile
isn't passing arguments to the program, instead if does redirection.
That means the shell will set up standard input (stdin, which e.g. scanf reads from) in your program to read from the redirected file.
To pass an actual argument to the program you need to run it as:
./a.out inputFile
In this case argc will be equal to 2, and argv[1] will be the string "inputFile". Which you can then pass on to e.g. fopen.
You need to pass a path to the c program then use fopen()
Using "<" means you are redirecting standard input of your process to be read from inputFile. So, all the standard read routines (getchar(), cin << ...) can be used.
If you omit "<", then inputFile becomes command argument and it is passed as part of char* argv[] to your main. After checking argc, validating file exists etc., you can use file reading routines, like fopen.

Fill argv[1] in C with max input

I am trying figure out a simple way to fill argv[1] with an extremely large string of input to see how much input my program can handle. Any ideas on the simplest way to do this?
If you're using a POSIX shell (Like Bash on Linux or similar) then you could use a simply Python script to "fill" an argument, and call it using the shell back-tick to execute commands "inline":
./your_program `python -c "print('A'*100)"`
The above will create a string of 100 A characters as the first argument to the program.
If you are calling your program from a shell, you typically take the advantage of that.
For instance, for POSIX, something like:
./program `printf '%*s' 500 | tr ' ' x`
(Taken from Creating string of repeated characters in shell script)
You can also create the string dynamically over a loop to test the program until it crashes, etc.
If you want a C solution (without spawning another process, e.g. using something like system or OS-specific APIs), I would suggest you rename your main() into a different function, and then write a new main() that calls the old one with an argv customized however you like:
int old_main(int argc, char *argv[]) { ... }
int main()
{
int argc = 2;
char *argv[2] = {
"program",
"xxxxxxxxxxxxxxxxxxxxxxx",
};
return old_main(argc, argv);
}

Why isn't redirected input considered a command line argument?

I'm trying to read command line arguments that have been redirected from a file. The command I'm using is ./a.out < test.txt
And the contents of test.txt is: Hello world.
But the output of my program below isn't printing Hello
world. Instead it is only showing ./a.out. Why is this?
int main(int argc, char* argv[], char* envp[]) {
for (int i = 1; i < argc; i++) {
printf("%s\n", argv[i]);
}
}
The shell intercepts the redirection commands before preparing the command line for the program:
myProg <infile -t >outfile
will pass to the program
myProg -t
with stdin and stdout already rerouted before the pogram starts. So the program never sees the rediretion.
There a lot of cases, besides simple derirection:
dir > myfile.txt
Especially you can pipe output from one program to another:
dir | more
It will send output if dir command to more command. Since program launch handled by OS shell, it handles a redirection too.
Because the language is defined that way. Suppose what you say is true —
All the user input will have to come from command line arguments, but text redirected from a file can satisfy input required in different functions. This can be achieved if the input appears as command line arguments.
Consider this program:
#include <stdio.h>
int is_dict(char *word)
{
/* code to look up a dictionary */
int result = 1;
return result;
}
int main(int argc, char *argv[])
{
if(argc == 2 && is_dict(argv[1]))
printf("%s found", argv[1]);
return 0;
}
If the program is written that way to accommodate it, then the input would have to come from the command line arguments. How would you take input when it is not redirected? It would require more program overhead to detect the missing inputs.
Moreover, imagine a text file containing a million words: it is unfeasible to expect each word to arrive as an argv[n].
There are other objections too. Suppose the program prints a series of prompts for responses. The user would have to know in advance what the prompts are, to supply the answers before the prompts appear.
Lastly, if the program is run from a GUI, then all the program's input will have to be edited into its properties before it is run.

Segmentation fault when I pipe stdout to my program

I don't know if I have to tell it again, but english is not my native language and I'm not a very good student, I've seen you are able to correct my message so it's fine but I'd like to apologize once again.
Here is the deal, I have a program, which convert a given graph passed in argument to Dimacs format that I'll store in a .cnf file. (We use it to solve it with a SAT-solver)
He's perfectly working when I use it by myself, so I'd like to have another program, graph_generator, that I'll pipe into myprogram to have random graphes.
I've made my graph_generator program, and he correctly prints graph at the format I want, so I've tried to do basically ./graph_generator | ./myprogram but I instantly get a segmentation fault, I can't see why, graph_generator returns exactly what it's expected, and when I want to use a debugger, I don't see how it's possible knowing that I pipe a result, when I copy paste the result of graph_generator myprogram correctly generates my .cnf file.
I don't know where the problem could come from, I have a theory but it's a bit lame, it's that the stdout of graph_generator, once piped myprogram considers the space as an argument and there is the problem. Anyone could help me please?
int main (int argc, char* argv[]){
graph* mygraph;
int taille, nbEdge;
int i;
FILE* resultat;
printf("mark 1");
taille = atoi(argv[1]);
nbEdge = atoi(argv[2]);
printf("mark 2");
mygraph = build_empty_graph(taille);
for(i = 3; i < argc; i+= 2)
add_edge(atoi(argv[i]), atoi(argv[i+1]), mygraph);
resultat = fopen("resultat.cnf", "w");
write_result_comments(resultat);
write_result_header(resultat, mygraph);
write_first_stack(resultat, mygraph);
write_second_stack(resultat, mygraph);
fclose(resultat);
return 0;
}
Here is the main of myprogram, when I use it with the pipe, the message "mark1" doesn't even appears
It is segfaulting because you don't check argc and are passing no values as arguments.
Please note that stdin is a separate stream from the arguments in argv.
Best way to fix this is to build up hierarchically:
tokenizer: read stdin in a loop with getchar until you get to whitespace (space, tab or newline).
parser: atoi is fine, since you only pass ints.
state machine: first two args to taille and nbEdge, rest in pairs (x, y) to call the program. Maybe use a switch statement and a state variable in a loop.
program: the rest of your program pretty much as is.

C - Executing Bash Commands with Execvp

I want to write a program Shellcode.c that accepts in input a text file, which contains bash commands separeted by newline, and executes every commands in the text file: for example, the text file will contain:
echo Hello World
mkdir goofy
ls
I tried this one (just to begin practicing with one of the exec functions):
#include <stdio.h>
#include <unistd.h>
void main() {
char *name[3];
name[0] = "echo";
name[1] = "Hello World";
name[2] = NULL;
execvp("/bin/sh", name);
}
I get, in return,
echo: Can't open Hello World
I'm stuck with the execvp function, where did I go wrong?
You're doing it wrong.
The first array index is the name of the program, as explained in the docs:
The execv(), execvp(), and execvpe() functions provide an array of pointers to null-terminated strings that represent the argument list available to the new program. The first argument, by convention, should point to the filename associated with the file being executed. The array of pointers must be terminated by a NULL pointer.
Also, bash doesn't expect free-form argument like that, you need to tell it you're going to pass commands using the -c option:
So, you need:
name[0] = "sh";
name[1] = "-c";
name[2] = "echo hello world";
name[3] = NULL;
To pass a script to bash on the command line you must add the option '-c' and pass the whole script as a single string, i.e.
#include <stdio.h>
#include <unistd.h>
void main() {
char *name[] = {
"/bin/bash",
"-c",
"echo 'Hello World'",
NULL
};
execvp(name[0], name);
}
Many problems here: The exec() family of functions do not execute multiple programs - these functions execute a single program, and replace the currently running process in memory with the new program. The null-pointer-terminated array of strings you pass to execvp is supposed to contain the command-line arguments to the program executed by execvp.
If you want to execute multiple programs, you'll need to loop over each line and execute the programs one by one. But you can't use execvp because that immediately replaces the currently executing process (your C program) with the process executed via the shell, meaning that the rest of your C program will never be executed. You need to learn how to use fork() combined with execvp so you can execute child processes. You first call fork() to create a child process, and then from the child process you call execvp. Fork + Exec is a common strategy in UNIX environments to launch other processes from a parent process.

Resources