dup2 not switching to file? - c

I'm trying to learn dup2 and switch the stdout to a file rather than terminal. This is the example that works everywhere but not sure why it is not working for me. I don't think I need a fork() because I don't need a different process for execute just the print statement in file.
Where function is called:
int main(int argc, char **argv){
char *something = "hello";
saveHistoryToFile(something);
}
//This is the function. There is a file names history .txt
void saveHistoryToFile(char *history){
int fw = open("history.txt",O_WRONLY | O_APPEND);
dup2(fw, 1);
printf("%s", history);
}
THE ERROR: it prints into terminal not file!

Your code with error checking:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int saveHistoryToFile(char *history);
int main(int argc, char **argv){
char *something = "hello";
if(0>saveHistoryToFile(something)) return 1;
if(0>fclose(stdout)) return perror("fclose"),-1;
}
int saveHistoryToFile(char *history){
int fw = open("history.txt",O_WRONLY | O_APPEND /*|O_CREAT, 0640*/ );
if (0>fw) return perror("open"),-1;
if (0>dup2(fw, 1)) return perror("dup2"),-1;
if (0>(printf("%s", history))) return perror("printf"),-1;
}
On a first run, I get "open: No such file or directory" because I do not have "history.txt" in my current directory.
If I add it or uncomment the O_CREAT, 0640, it runs fine on my machine.
Of course, you might run into other problems (e.g, EPERM) but the perrors should give you a hint.

Related

How can one overwrite the return address without buffers on on the stack?

In the below program, I have a few buffers, but they are global variables, not stored on the stack. Thus, I'm not seeing a viable way of overwriting the return address to execute a shellcode.
Is there a vulnerability in the below that I am missing? The path constructed in snprintf seems pretty solid - not seeing a way to redirect the execution path.
C program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libgen.h>
char buffer[256] = "";
char filename[256] = "";
int main(int argc, char *argv[])
{
setreuid(geteuid(), geteuid());
setregid(getegid(), getegid());
if (argv[1]) {
snprintf(filename, 255, "/var/smash/g6/%s", basename(argv[1]));
printf("Checking filename %s\n", filename);
if (access(filename, X_OK)) {
fprintf(stderr, "You do not have the permission to execute this file\n");
return 1;
}
}
else {
fprintf(stderr, "Please provide the program name. Currently available programs:\n");
system("/bin/ls /var/smash/v6");
return 2;
}
if (argv[2]) {
strcpy(buffer, argv[2]);
}
else {
printf("Provide the parameter(s):\n");
gets(buffer);
}
printf("Executing filename %s\n", filename);
execlp(filename, filename, buffer, (char *)0);
return 0;
}
Without trying it, it looks as if the vulnerability is that you provide a filename, which is checked to see that you have access, but then you read a string that isn't constrained to buffer but can overflow into filename such that your program will then execute the new filename without being constrained by the earlier checks.

Doesn't GCC recognize the function "read"?

I was solving the pwnable.kr's fd problem and wondered how does the fd.c code works.
So I copied the c code and I put it on GCC to see how it works. And it has an error says: "implicit declaration of function ‘read’; did you mean ‘fread’?" Does GCC not recognize the Read function on C?
The code looks like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char buf[32];
int main(int argc, char* argv[], char* envp[]){
if(argc<2){
printf("pass argv[1] a number\n");
return 0;
}
int fd = atoi( argv[1] ) - 0x1234;
int len = 0;
len = read(fd, buf, 32);
if(!strcmp("LETMEWIN\n", buf)){
printf("good job :)\n");
system("/bin/cat flag");
exit(0);
}
printf("learn about Linux file IO\n");
return 0;
}
Thank you
From the man page (man 2 read) :
NAME
read - read from a file descriptor
SYNOPSIS
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
You must include unistd.h and the warning will go away.

Undefined Reference to 'main' when code is compiled

I created a C program which would create a directory and file.
I have tried to debug the error, but it didn't work
#include <dirent.h>
#include <errno.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
create_dir(char* outputdir,char* str_outpath,char* value){
DIR* dir = opendir(outputdir);
FILE *f;
if (dir) {
/* Directory exists. */
closedir(dir);
} else if (ENOENT == errno) {
/* Directory does not exist. */
mkdir(outputdir, 0700);
closedir(dir);
printf("Successfully created the directory %s ", outputdir);
} else {
printf("Creation of the directory %s failed",outputdir);
/* opendir() failed for some other reason. */
}
f = fopen(str_outpath, "a");
fprintf(f,"%s",value);
fclose(f);
}
I want it to create a file and a directory successfully
As others have mentioned. You do not have a main function.
Also your create_dir function is missing a type. I'll assume it's void since you are not returning anything. This should compile.
#include <dirent.h>
#include <errno.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
void create_dir(char* outputdir,char* str_outpath,char* value){
DIR* dir = opendir(outputdir);
FILE *f;
if (dir) {
/* Directory exists. */
closedir(dir);
} else if (ENOENT == errno) {
/* Directory does not exist. */
mkdir(outputdir, 0700);
closedir(dir);
printf("Successfully created the directory %s ", outputdir);
} else {
printf("Creation of the directory %s failed",outputdir);
/* opendir() failed for some other reason. */
}
f = fopen(str_outpath, "a");
fprintf(f,"%s",value);
fclose(f);
}
int main(){
char directory[] = "/users/me/documents/testdir";
char filepath[] = "testfile";
char data[] = "hello world";
create_dir(directory,filepath,data);
return 0;
}
I did not execute the code to check whether it works. I merely copied and pasted yours and called the function.
In C under most cases you need to have a main function. So in order to run your code you'll need to have something like this (assuming that you want to pass in the parameters from the command-line) underneath that function:
int main(int argc, char *argv[]) {
if (argc < 4) {
printf("Proper Usage is ./program otputdir str_outpath value\n");
return -1;
}
char *outputdir = argv[1];
char *str_outpath = argv[2];
char *value = argv[3];
create_dir(outputdir, str_outpath, value);
return 0;
}
EDIT: fixed an issue with not checking argc

fopen returns null and perror prints invalid argument

I created a file named "test" but I'm unable to open it using fopen.
Here is the code-
#include<stdio.h>
int main()
{
FILE *fp;
fp=fopen("test.txt","r");
if(fp==NULL)
{
perror("Error: ");
}
fclose(fp);
return 0;
}
When I run the above code, I get the following output:
Error: Invalid argument
What could be the reason? When does perror return "Invalid argument" error message?
Have a look at man fopen:
EINVAL The mode provided to fopen(), fdopen(), or freopen() was invalid.
Probably test.txt is not readable.
Try compiling with -g. This lets you use gdb to debug the program step by step; look up how to use it. Probably a better way of doing this is with stat(2). Here is a sample of code that will return an error if the file does not exist, or is not a regular file:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
struct stat s;
int check = stat("test.txt", &s);
if(check != 0){
printf("ERROR: File does not exist!\n");
return -1;
}
return 0;
}
Stat stores a lot of information about a file (such as lenght, type, etc.) in the struct stat, which in this case is named "s". It also returns an integer value, which is non-zero if the file does not exist.

changing a program in c, so it takes an optional command line argument *infile*

Now I do have a hw question for everyone...I've been staring at this for a couple of days kind of tinkering and playing around but even with that I end up with a load of errors...
What I'm trying to do is take the program below and change it so that it takes an optional command line argument infile. If infile is given, then copy infile to standard output, otherwise copy standard input to standard output as before.
The trick about this is that the solution must use the original copy loop (lines 9-11) for both cases. One can only insert code, and not change any of the existing code. Any help would be great. Thanks.
/* $begin cpfile */
include "csapp.h"
int main(int argc, char **argv)
{
int n;
rio_t rio;
char buf[MAXLINE];
Rio_readinitb(&rio, STDIN_FILENO); //line 9
while((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) //line 10
Rio_writen(STDOUT_FILENO, buf, n); //line 11
/* $end cpfile */
exit(0);
/* $begin cpfile */
}
/* $end cpfile */
C programs get command line arguments through the two arguments to main(), traditionally called argc and argv (for argument count and argument vector, respectively).
Arguments are not "named" anything, they're just strings.
A solution for you could look like this:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fileno;
/* ... your definitions should remain here, too */
if(argc > 1)
{
/* Assume first argument is filename, and open it. */
fileno = open(argv[1], O_RDONLY);
if(fileno < 0)
{
printf("Unable to open file, aborting\n");
return 1;
}
}
else
fileno = STDIN_FILENO;
/* ... your code goes here ... */
}
Then you'd of course need to change the call to Rio_readinitb() to use the fileno variable for the file descriptor.
If you literally can't change that line, for whatever reason ... I guess you can use the preprocessor to make the symbol evaluate to the new variable name:
#undef STDIN_FILENO
#define STDIN_FILENO fileno
This is of course not exactly pretty, but should work.
Make sure you put those preprocessor macros after the fileno = STDIN_FILENO; line.
You can insert dup2 before the lines 9 - 11 and it seems that you will not need change code on the lines 9 - 11. This is an example.
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int file_handle;
int dup2_res;
if (argc == 2) {
file_handle = open(argv[1], O_RDONLY);
dup2_res = dup2 (file_handle, STDIN_FILENO);
}
char buffer[100];
ssize_t read_bytes = 1;
while (read_bytes)
{
read_bytes = read(STDIN_FILENO, &buffer, sizeof(buffer) );
buffer[read_bytes] = 0;
printf("%s", buffer);
}
close(file_handle);
return 0;
}
If STDIN_FILENO cannot be reassigned, it sounds like a task for freopen():
freopen(argv[1], "r", stdin);

Resources