Prevent accessing files outside of given working directory - c

I am trying to prevent the access on files outside of a given working directory.
My first attempt was to use chdir and chroot, but chroot can only be used by root users.
Is there any other possibility? I have heard something about another one, but I can't remember.
Perhaps a simple function to check if the path is outside of the working directory or second argument.
Some details about the program:
shall be run on Linux
simple shell programm without any interactive elements
takes a directory argument, which is the working directory
Thanks for any advices.
EDIT:
After some research I found different aproachments, but I can't use any of them.
pivot_root
set_fs_root (linux kernel)
Is there any possibility to use that?
Perhaps there is a possibility to open a file which is contained by a given directory. So I call the function with the argument file path and the "root" path where to look.

I'm assuming that you're on a Linux/MacOSX platform. There are a couple of ways. One is to create a special user for your program who owns that directory, but doesn't have write permissions to anything else in the system*. The other option is to use a program like SELinux to only allow certain operations to the program, but that seems like overkill.
*: You must always give the user read permissions. How will your program run without read access to glibc?

You might want to look into a restricted shell; I think most of the common shells have options for a restricted mode that disables cd, prevents changes to certain environment variables, and some other things. For pdksh, it would be /bin/ksh -r. The option differ for other shells, though, so read the appropriate manual page.

Related

C Programming: How to create a parent directory and insert files manually?

My goal is to, inside my C program, make a new directory. Within this directory, I want to create 15 simple text files. The part that I am stuck on is how to generate the 15 text files inside the newly created directory. I have created the new directory like this:
mkdir("new_dir", 0755);
But I am unsure of how to create a text file within it (in the same program). Any tips for this?
I am guessing you are on some POSIX system. The C11 standard (read n1570) does not know about directories (an abstraction provided by your operating system). If you are on Windows, it has a different WinAPI (you should then use CreateDirectory)
First, your call to mkdir(2) could fail (for a variety of reasons, including the fact that the directory did already exist). And very probably, you actually want to create the directory in the home directory, or document that you are creating it in the current working directory (e.g. leave the burden of some appropriate and prior cd shell builtin to your user). Practically speaking, the directory path should be computed at runtime as a string (perhaps using snprintf(3) or asprintf(3)).
So if you wanted to create a directory in the home directory of the user (remember that ~/foo/ is expanded by the shell during globbing, see glob(7)...; you need to fetch the home directory from environ(7)), you would code something like:
char pathbuf[256];
snprintf(pathbuf, sizeof(pathbuf), "%s/new_dir", getenv("HOME"));
to compute that string. Of course, you need to handle failure (of getenv(3), or of snprintf). I am leaving these checks as an exercise. You might want to keep the result of getenv("HOME") in some automatic variable.
Then you need to make the directory, and check against failure. At the very least (using perror(3) and see errno(3)):
if (mkdir (pathbuf, 0750)) { perror(pathbuf); exit(EXIT_FAILURE); }
BTW, the mode passed to mkdir might not allow every other user to write or access it (if it did, you could have some security vulnerability). So I prefer 0750 to yours 0755.
At last you need to create files inside it, perhaps using fopen(3) before writing into them. So some code like
int i = somenumber();
snprintf(pathbuf, sizeof(pathbuf),
"%s/new_dir/file%d.txt", getenv("HOME"), i);
FILE* f = fopen(pathbuf, "w");
if (!f) { perror(pathbuf); exit(EXIT_FAILURE); };
As Jonathan Leffler wisely commented, there are other ways.
My recommendation is to document some convention. Do you want your program to create a directory in the current working directory, or to create it in some "absolute" path, perhaps related to the home directory of your user? If your program is started by some user (and is not setuid or doesn't have root permissions, see credentials(7)) it is not permitted to create directories or files at arbitrary places (see hier(7)).
If on Linux, you'll better read some system programming book like ALP or newer. If you use a different OS, you should read the documentation of its system API.

How to create a file inside the `/etc` folder in Linux with C?

I'm writing a program in C that will have to check a configuration file every time it starts to set some variables.
At the first start of the program I suppose there won't be any configuration file, so I need to create it (with default settings).
I've been said configurations files of program belongs to the folder /etc, more specifically to a particular folder created on purpose for the program itself (i.e. /etc/myprog). Here comes the first question I should have asked: is it true? Why /etc?
In any case I tried to create that file using this:
open("/etc/myprog/myprog.conf", O_WRONLY | O_CREAT, 0644);
the open returns -1 and sets errno global variable to 2 (i.e. folder does not exist).
If I try to create the file straight inside /etc (therefore "/etc/myprog.conf" as first argument of the open) I get instead an errno set to 13 (i.e. permission denied).
Is there a way to grant my program permissions to write in /etc?
EDIT: I see most users are suggesting to use sudo. If possible I would have preferred to avoid this option as this file has to be created just once (at the first start). Maybe I should make 2 different executables? (e.g. myprog_bootstrap and myprog, having to run only the first one with sudo)
You need root privileges to create a file in /etc. Run your executable with sudo in front:
sudo executable_name
Another possibility might be to make your executable setuid. Your program would then call very appropriately the setreuid(2) system call.
However, be very careful. Programs like /bin/login (or /usr/bin/sudo itself) are coded this way, but any subtle error in your program opens a can of worms of security holes. So please be paranoid when writing such a code, and get it reviewed by someone else.
Perhaps a better approach might be to have your installation procedure make /etc/yourfile some symlink (created once at installation time to some writable file elsewhere) ....
BTW, you might create a group for your program, and make -at installation time- the /etc/yourfile writable to the group, and make your program setgid.
Or even, dedicate a user for your program, and have this /etc/yourfile belonging to that user.
Or, at installation time, have the /etc/myprog/ directory created and belonging to the appropriate user (or group) and being writable to that user (or group).
PS. Read also Advanced Linux Programming, capabilities(7), credentials(7) and execve(2)

How to find your directory manually in Linux?

I am about to write a command that shows the current directory in linux. I know I can use the "pwd" command, but that's what I need to implement myself!... in other words, when entering the so called "findme" command, I want to return back the directory that I am in at the moment. I have managed to create the my "findme" command (which is very simple,I know), but how am I supposed to know where in I am after executing the command, in order to show the whole directory?
It seems a rather odd requirement: 'implement pwd' (this isn't homework, is it?). Can you give a little more context?
Probably relevant bits of information are:
the directory .. is linked to the parent directory, and . to the current one; so...
changing directory to .. goes up one level in the filesystem (unless you're at the top); plus
every directory will have an 'inode number', so if you consider a directory foo, then both it and the directory foo/. will have the same inode number.
I don't know how pwd actually does it, but I'd lay money you could reimplement it with this information.
XV6 isn't at all the same as GNU/Linux. pwd was not implemented in UNIX V6, that's why it's a good exercise. You would probably want to implement getcwd() as a syscall.

permission denied for rename function in C on windows

I have an application developed in C. This application is supported across multiple platforms. There is one functionality where we are transferring files via file transfer protocol to different machine or to any other directory on local machine. I want to include a functionality where I can transfer the file with some temporary name and once the transfer is complete, I want to rename the file with the correct name (the actual file name).
I tried using simple rename() function. It works fine in Unix and Linux machines. But it does not work on Windows. It is giving me an error code of 13(Permission denied error).
First thing, I checked in msdn to know the functionality of rename if I have to grant some permissions to the file etc.
I granted full permissions to the file (lets say it is 777).
I read in few other posts that I should close the file descriptor before renaming the file. I did that too. It still gives the same error.
Few other posts mentioned about the owner of the file and that of the application. The application will run as a SYSTEM user. (But this should not affect the behavior, because I tried the same rename function in my application as follows:
This works fine from my application:
rename("C:/abc/aaa.txt","C:/abc/zzz.txt");
but
rename(My_path,"C:/abc/zzz.txt");
doesn't work, where My_path when printed displays C:/abc/test.txt.
How can I rename a file? I need it to work on multiple platforms.
Are there any other things I should be trying to make it work.?
I had this same problem, but the issue was slightly different. If I did the following sequence of function calls, I got "Permission Denied" when calling the rename function.
fopen
fwrite
rename
fclose
The solution was to close the file first, before doing the rename.
fopen
fwrite
fclose
rename
If
rename("C:/abc/aaa.txt","C:/abc/zzz.txt");
works but
rename(My_path,"C:/abc/zzz.txt");
does not, in the exact same spot in the program (i.e. replacing one line with another and making no changes), then there might be something wrong with the variable My_path. What is the type of this variable? If it is a char array (since this is C), is it terminated appropriately? And is it exactly equal to "C:/abc/aaa.txt"?
(I wish I could post this as a comment/clarification rather than as an answer but my rep isn't good enough :( )

How do i use vfs_readdir in linux kernel?

I'm trying to use a system call to display the contents of a directory. I've been pointed in the direction of vfs_readdir, but I have no clue of how to use it or what to pass to it to get the contents of a directory. All I want to do is be able to list files in a directory similar to how ls works. (I eventually intend to store this in some sort of buffer, but for now just being able to print the contents of a dir would be enough).
I think you probably have to open the directory using filp_open.
For the "flags" argument, you proably need to put some combination of the LOOKUP_ flags listed in include/linux/namei.h
You can see what build_open_flags does here: http://lxr.linux.no/#linux+v3.1.5/fs/open.c#L876 to provide flags to filp_open.
As far as I know, filp_open IS the correct way of opening a file in kernel-space. However, doing so is discouraged.
Provided you do so from the context of a "normal" thread belonging to a user process, I think you will be ok.

Resources