views:

249

answers:

6

I'm writing a small read-only FTP-like server. Client says "give me that file" and my server sends it.

Is there any standard way (a library function?!?) to make sure that the file requested is not "../../../../../etc/passwd" or any other bad thing? It would be great if I could limit all queries to a directory (and its subdirectories).

Thank you!

+2  A: 

While this isn't perfect, you can run your ftp server under a specific user/group, and only permission certain directories to that user/group. This, however, may not be exactly what you're looking for.

You can also have a whitelist of directories users can go to, and any others they try to go to, you simply don't allow (thus, basically building your own permissioning).

I, personally, prefer the former, as the work is already done for you by the OS.

FreeMemory
+1  A: 

I don't know of a standard library that accomplishes this.

You could try:

  1. Set the permissions of the unix user who is running the server to only have read/write permissions to a certain directory. (maybe using PAM, a chrooted environment, or using standard unix user/group permissions)

  2. You could design your program so that it only accepts absolute paths (in unix, paths beginning with '/'). That way, you can check to make sure it is a valid path - for example, disallow any path which has the string ".."

edit:

From Peter: looks like there is a library function, realpath() which helps with #2 from above.

rascher
+5  A: 

Also take a look at chroot

Duck
I like this better..
Ryan Oberoi
+1  A: 

Get the inode of the root (/) directory, and that of the serving directory (say /ftp/pub). For the files they request, make sure that 1. The file exists. 2. The parents of the file (accessed using multiple "/.." on the file path) hit the serving directory inode before it hits the root directory inode.

You can use stat to find the inode of any directory. Put this in one function, and call it before serving the file.

Of course using a user/group with appropriate privilege will work as well.

Ryan Oberoi
Glad you accepted my suggestion, though I think chroot is a good way to accomplish what you want as well.
Ryan Oberoi
+1  A: 

In Windows, I would do something like (still applies to any OS though):

  1. User requests file
  2. Server finds file
  3. Server checks if path_to_file starts with "C:/SomeFolderWithFiles/"
  4. Finish transaction
kitchen
+6  A: 

Chroot is probably the best way to go, but you can use realpath(3) to determine the canonical path to a given filename. From the man page:

 char *realpath(const char *file_name, char *resolved_name);

The realpath() function resolves all symbolic links, extra '/' characters, and references to /./ and /../ in filename, and copies the resulting absolute pathname into the memory referenced by resolved name. The resolved_name argument must refer to a buffer capable of storing at least PATH_MAX characters.

From there you can restrict the request in any additional way you like.

Peter Kovacs
+1 cool, I was looking for a function like that!
rascher