S_ISREG returns 0 - c

So I want to test if a file given is regular or not.
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
int main(int argc, char **argv)
{
// Input check.
if (argc != 2) {
fprintf(stdout,"Format: %s <filename.txt>\n", argv[0]);
return -1;
}
// Make sure the file is a regular file.
int fd;
if ((fd = open(argv[1], O_RDONLY) == -1)) {
fprintf(stdout, "%s", strerror(errno));
return -1;
}
struct stat st;
if ((fstat(fd, &st) == -1)) {
fprintf(stdout, "%s\n", strerror(errno));
return -1;
}
if (!(S_ISREG(st.st_mode))) {
fprintf(stdout, "Error, invalid file\n");
return -1;
}
close(fd);
return 0;
}
I run: .\a in.txt
I don't know what exactly is going on, but when I'm trying to test if the file is regular (last if statement), it fails. I tested to see if fstat fails, but it doesn't.

Here's the problem:
if ((fd = open(argv[1], O_RDONLY) == -1)) {
The equality operator == has higher precedence than the assignment operator =. So the above parses as:
if (fd = (open(argv[1], O_RDONLY) == -1)) {
Which assigns to fd the result of the comparison which will be either 0 or 1. These values both happen to be valid open file descriptors for stdin and stdout so the fstat call is successful and gets you the status of one of these streams.
You'll need to adjust the parenthesis to do the assignment first:
if ((fd = open(argv[1], O_RDONLY)) == -1) {
Also, it looks like you have other if statements that have a redundant set of parenthesis that you can remove. You want to avoid this because those extra parenthesis can silence warnings about exactly what you did.

Related

open()'s "mode" argument won't set the correct permissions for the file

My intention was to open two files, where the second one would be brand new, with the same permissions as the first file. So to test my code I changed the first file permissions to "777". Then I proceeded to run my program. And to my surprise, the permission of the newborn file2 were wrong! They where set to 755. Even weirder is when I set the first file to "111" and tried again, the result now was "1204".
Can someone explain to me this weird behavior?
Here's my code
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char *args[]) {
struct stat stats;
int fd1, fd2;
fd1 = open("testfile.txt", O_RDONLY);
/* Error check*/
if (fd1 == -1) {
/* Error handling */
perror("Opening");
printf("Unable to open file: %s\n", "testfile.txt");
printf("ERROR: %s\n", strerror(errno));
return 1;
}
if(fstat(fd1, &stats) == -1)
{
printf("Error while getting stats: %s\n", strerror(errno));
exit(-1);
}
//Receives the output file as a main argument . . .
if (argc > 1)
{
//(stats.st_mode = Gets the mask of the first file)
fd2 = open(args[1], O_WRONLY|O_CREAT, stats.st_mode);
/* Error check*/
if (fd2 == -1) {
/* Error handling */
perror("Opening");
printf("Unable to open file: %s\n",args[1]);
printf("ERROR: %s\n", strerror(errno));
return 1;
}
}
//. . . if it doesn't it creates a standard one warning you about it
else
{
fd2 = open("Nope.txt", O_WRONLY|O_CREAT, stats.st_mode);
/* Error check*/
if (fd2 == -1) {
/* Error handling */
perror("Opening");
printf("Unable to open file: %s\n",args[1]);
printf("ERROR: %s\n", strerror(errno));
return 1;
}
printf("Standard file created\n");
}
close(fd1);
close(fd2);
return 0;
}
I tried to make it as tidy as I could :)
From open(2) man page on the part about O_CREATE:
The effective mode is modified by the process's umask in the usual way: in the absence of a default ACL, the mode of the created file is (mode & ~umask).
If you type umask in bash you can see what value is used and which bits get cleared from the mode you provide.

How to bypass the check of setuid

I am now taking a security class. And the professor asked us to exploit a program to gain higher privilege.
This is the code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#define BUFSIZE 512
int main(int argc, char *argv[]) {
struct stat buf;
char cmd[BUFSIZE];
FILE *f = NULL;
if (argv[1] == NULL) {
fprintf(stderr, "Please provide an argument\n");
exit(1);
}
if (stat(argv[1], &buf)) {
fprintf(stderr, "Can't stat the file\n");
exit(1);
}
if (buf.st_gid != getegid()) {
fprintf(stderr, "The file must be owned by group %d\n", getegid());
exit(1);
}
sleep(1);
if ((f = fopen(argv[1], "r")) == NULL) {
fprintf(stderr, "Cannot open command file\n");
return 1;
}
while (fgets(cmd, BUFSIZE, f)) {
if ((cmd[0] == '\n') || (cmd[0] == 0x7f)) {
fprintf(stderr, "Found empty line, quitting!\n");
return 2;
}
system(cmd);
}
printf("Done!\n");
return 0;
}
The particular situation is:
There is a binary code for this program for us to run. And the SUID of the binary code is set to higher level(here I assume level2). However, buf.st_gid != getegid() will always check if the file we specified is owned by root. Most important thing is, I only have level1 privilege. There is only one file owned by level2 I can use which is provided by our professor. And I certainly tried to pass in that filename. But nothing happens. I don't know if there is anyway I can exploit this program.(To execute some commands during runtime using the privilege of level2)

C Program that makes a copy of a file using standard I/O and system calls

I am trying to write a C program which uses standard I/O and System calls to perform copying of contents of one file to another file.
So far, I have done this :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fd1, fd2;
char buffer[1024];
long int n1;
if(((fd1 = open(argv[1], O_RDONLY)) == -1) || ((fd2=open(argv[2],O_CREAT|O_WRONLY|O_TRUNC, 0700)) == -1)){
perror("file problem");
exit(1);
}
while((n1=read(fd1, buffer, 1024) > 0)){
if(write(fd2, buffer, n1) != n1){
perror("writing problem ");
exit(3);
}
}
close(fd1);
close(fd2);
}
When I run the program like this :
cc copyContents.c
./a.out one.txt two.txt
Assuming that one.txt is well defined, what I want is to create a new file called two.txt and copy over all the contents of one.txt
When I look into the contents of two.txt after running the program, it has literally nothing in it. Just a blank file.
Where am I going wrong?
You wrote
while((n1=read(fd1, buffer, 1024) > 0)){
instead of
while ( (n1 = read(fd1, buffer, 1024)) > 0)
In your code the code int the while condition boils down to:
n1 = (read(fd1, buffer, 1024) > 0)
So the read is done correctly, it's return value is compared to 0, the result of the comparision (0 or 1) is assigned to n1.
This shows once more how important it is to format your code in a way that makes it readable.
You could have debugged this easily yourself with a debugger or by inserting one or two printfs in your code.
Input:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
void typefile (char *filename)
{
int fd, nread;
char buf[1024];
fd = open (filename, O_RDONLY);
if (fd == -1) {
perror (filename);
return;
}
while ((nread = read (fd, buf, sizeof (buf))) > 0)
write (1, buf, nread);
close (fd);
}
int main (int argc, char **argv)
{
int argno;
for (argno = 1; argno < argc; argno )
typefile (argv[argno]);
exit (0);
}
Output:
student#ubuntu:~$gcc –o prg10.out prg10.c
student#ubuntu:~$cat > ff
hello`enter code here`
hai
student#ubuntu:~$./prg10.out ff
hello
hai
This is the best solution and easily executable.
input:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int f1, f2;
char buff[50];
long int n;
if(((f1 = open(argv[1], O_RDONLY)) == -1 || ((f2=open(argv[2], O_CREAT |
O_WRONLY | O_TRUNC, 0700))== 1)))
{
perror("problem in file");
exit(1);
}
while((n=read(f1, buff, 50))>0)
if(write(f2, buff, n)!=n)
{
perror("problem in writing");
exit(3);
}
if(n==-1)
{
perror("problem in reading");
exit(2);
}
close(f2);
exit(0);
}
Output:
cc sys.c
./a.out a.txt b.txt
cat b.txt
So, a.txt should have some content and this content is copied to b.txt
by "cat b.txt" you can cross-check the content(which is in "a.txt").
Narenda checks if n==-1 inside the loop, but, the loop test is n>0, so, that'll never happen.
Also, the test for a bad read should precede the attempt to write.

Confused with the st_ino?

#include "stdio.h"
#include <sys/stat.h>
int
main(int argc, char *argv[]) {
struct stat buf;
//int fd = open("./fstatat.c", "r");
//int fd2 = fstatat(fd, "a.txt", &buf, 0);
//printf("%d\n", buf.st_ino);
stat("./fstatat.c", &buf);
printf("%d\n", buf.st_ino);
return 0;
}
if i use the function stat to get a struct stat, the st_ino is the same as the i-node number with the ls -i.
1305609
[inmove#localhost chapter-four]$ ls -i
1305607 a.txt 1305606 fstatat.bin 1305609 fstatat.c 1305605 tmp.txt
buf if i use the function fstat, the st_ino is always the 4195126.
anyone can tell me why this happen?
The problem is that you are not using open correctly and don't check the return values for errors. So you are then calling fstat on the invalid file descriptor value -1 returned by open on error, which will also fail and not touch buf at all, so the uninitialized garbage in the struct is still there (4195126, hex 0x400336 smells a lot like a return address of a previous function call still being on the stack or something like this.)
As davmac already pointed out, the second parameter to open must be a list of flags, which are numeric. Check the docs.
So, the correct code would be:
#include "stdio.h"
#include <sys/stat.h>
#include <sys/fcntl.h> // for the O_RDONLY constant
#include <errno.h> // for error output
int main(int argc, char *argv[]) {
struct stat buf;
int fd = open("./fstatat.c", O_RDONLY);
if(fd == -1) {
printf("Error calling open: %s\n", strerror(errno));
} else {
if(fstat(fd, &buf) == -1) {
printf("Error calling fstat: %s\n", strerror(errno));
} else {
printf("%d\n", buf.st_ino);
if(close(fd) == -1) {
printf("Error calling close: %s\n", strerror(errno));
}
}
}
return 0;
}

dup2() is preventing output

my code is pasted below.
I'm trying to use dup2 to redirect my output to file.
if I use it to redirect it works fine (if I remove the comments), output in file and not on stdout. ex: ls > test , results in ls outputting to test.
the problem is that ls, without the > doesn't output anything. If I leave the comments ls outputs just as it should, albeit with no ability to redirect.
redirect[0] is either < or > or nothing
redirect[1] is the path for the file to redirect to
command is is an array of cstrings with the pices of the command commands is as well
example output
with code commented
xxxxx#myshell:/home/majors/kingacev/ubuntumap/cop4610/proj1> ls
a.out myshell.c myshell.c~
xxxxx#myshell:/home/majors/kingacev/ubuntumap/cop4610/proj1>
with code uncommented
xxxxx#myshell:/home/majors/kingacev/ubuntumap/cop4610/proj1> ls
xxxxx#myshell:/home/majors/kingacev/ubuntumap/cop4610/proj1>
/*
if (!strcmp(redirect[0],">")){
if ((fd = open(redirect[1], O_RDWR | O_CREAT)) != -1)
dup2(fd, STDOUT_FILENO);
close(fd);
}
*/
if (command[0][0] == '/'){
int c = execv(command[0], commands);
if (c != 0){
printf("ERROR: command does not exist at path specified\n");
exit(0);
}
}
else if (!execv(path, commands)){
exit(0);
}
This code works, redirecting to file.out:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
int fd;
char *redirect[] = { ">", "file.out" };
char *command[] = { "/bin/ls", "-l", 0 };
if (!strcmp(redirect[0], ">"))
{
if ((fd = open(redirect[1], O_WRONLY | O_CREAT, 0644)) != -1)
{
fprintf(stderr, "Dupping stdout to %s\n", redirect[1]);
dup2(fd, STDOUT_FILENO);
close(fd);
}
}
if (command[0][0] == '/')
{
execv(command[0], command);
fprintf(stderr, "ERROR: command %s does not exist at path specified\n", command[0]);
return(1);
}
else
{
fprintf(stderr, "ERROR: not handling relative names like %s\n", command[0]);
return(1);
}
return 0;
}
This code works too, not redirecting to file:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
int fd;
char *redirect[] = { "<", "file.in" };
char *command[] = { "/bin/ls", "-l", 0 };
if (!strcmp(redirect[0], ">"))
{
if ((fd = open(redirect[1], O_WRONLY | O_CREAT, 0644)) != -1)
{
fprintf(stderr, "Dupping stdout to %s\n", redirect[1]);
dup2(fd, STDOUT_FILENO);
close(fd);
}
}
if (command[0][0] == '/')
{
execv(command[0], command);
fprintf(stderr, "ERROR: command %s does not exist at path specified\n", command[0]);
return(1);
}
else
{
fprintf(stderr, "ERROR: not handling relative names like %s\n", command[0]);
return(1);
}
return 0;
}
Note that it sets up the command array and uses execv(command[0], command); — this is the recommended way of doing business. Your code appears to have a variable commands with presumably the arguments to the program; you also appear to have a variable path with presumably the path name of the program. Since we can't see what's in those, it is hard to know what they contain and where there might be problems. Note the explicit null pointer (0) at the end of the command array. That is crucial. Note too that the error messages identify what was failing. There are few things more frustrating than a program that says "it went wrong" without identifying what 'it' is.

Resources