O_RDONLY
: Reading a File¶
Me and /etc/passwd
¶
Who am I?
$ id
$ id
uid=1000(jfasch) gid=1000(jfasch) groups=1000(jfasch),10(wheel),18(dialout)
A-Ha: being user jfasch
who belongs to groups jfasch
,
wheel
, and dialout
.
And /etc/passwd
?
$ ls -l /etc/passwd
-rw-r--r--. 1 root root 2746 Mar 3 14:12 /etc/passwd
A-ha: Read-writable by user root
, readable by members of group
root
, and by all others.
So, I (being among the others for the purpose of /etc/passwd
access), I’ll be able to read that file. Lets do that: read the entire
file, and write it to standard output.
Code: Reading A File¶
The following program
opens the file (doing basic error handling which is always a good idea)
It is at the time of
open()
-ing a file where you declare that you intend to read from it! This is the time where the system checks your intentions against the file’s permissions.
reads its contents in a loop, again handling errors
checks the end-of-file (EOF) condition - a read of 0 bytes says that there will come no more
writes the bytes that it reads to standard output, using the predefined
STDOUT_FILENO
macro (which expands to file decriptor1
)returns the exit status
0
if all is well, and arbitrarily chosen numbers for the different error situations that it may encounter
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char** argv)
{
const char* filename = argv[1];
int fd;
char buffer[128];
ssize_t nread, nwritten;
fd = open(filename, O_RDONLY);
if (fd == -1) {
perror("open");
return 1;
}
while (1) {
nread = read(fd, buffer, sizeof(buffer));
if (nread == -1) {
perror("read");
return 2;
}
// end of file (EOF) reached?
if (nread == 0)
break;
nwritten = write(STDOUT_FILENO, buffer, nread);
if (nwritten == -1) {
perror("write");
return 3;
}
}
close(fd);
return 0;
}
$ gcc -o example-O_RDONLY example-O_RDONLY.c
Sunny Case: Reading /etc/passwd
¶
As we saw, /etc/passwd
is readable for all others, so this should
be ok:
$ ./example-O_RDONLY /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
...
Note
The program read the file in chunks of 128 bytes in a loop. What we
see is that read()
continues where the previous read()
left
off.
See
Duplicating (Whats Going On?) for an explanation of what’s going on in the system to make this happen
Miscellaneous for alternative ways of reading a file that do not exhibit this behaviour (which is intended in most cases)
Error: File Not Readable¶
A file that is certainly not readable for anybody on any Linux system
is /etc/shadow
:
$ ls -l /etc/shadow
----------. 1 root root 1352 Mar 3 14:12 /etc/shadow
Proper error handling around open()
now will detect exactly that …
$ ./example-O_RDONLY /etc/shadow
open: Permission denied
Error: File Not Even There¶
Likewise, open()
obviously fails if the file does not exist:
$ ./example-O_RDONLY something-thats-not-there
open: No such file or directory