2

I'm currently writing an HTTP Server over UNIX Sockets in C, and I'm about to implement the part of the GET request that checks the requested file to make sure it has appropriate permissions.

Before I knew anything about HTTP servers, I set up an Apache server, and it is my understanding that there is a single directory which the HTTP server looks to find a requested file. I do not know if this is because the server somehow has no permissions outside of the directory, or if it actually validates the path to ensure it is inside the directory.

Now that I am about to implement this on my own, I'm not sure how to properly handle this. Is there a function in C that will allow me to determine if a path is inside a given directory (e.g. is foo/bar/../../baz inside foo/)?

In python, I would use os.path.relpath and check if the result starts with .., to ensure that the path is not outside the given directory.

For example, if the directory is /foo/bar/htdocs, and the given path is index.html/../../passwords.txt, I want ../passwords.txt, so I can see from the leading .. that the file is outside the /foo/bar/htdocs directory.

Casey Kuball
  • 7,717
  • 5
  • 38
  • 70

4 Answers4

1

You'd be surprised how much of Python's I/O functionality more or less maps directly to what POSIX can do. :)

In other words, look up realpath().

It's awesome when POSIX has the more descriptive name for a function, with that extra letter included! :)

unwind
  • 391,730
  • 64
  • 469
  • 606
  • I think you're misinterpreting my question, I want a *relative* path from a specific directory (e.g. `htdocs`), so that I can determine if the file path is good. – Casey Kuball Feb 22 '13 at 17:36
0

How to get the absolute path for a given relative path programmatically in Linux?

#include <stdlib.h> 
#include <stdio.h> 
int main() 
{ 
        char resolved_path[100]; 
        realpath("../../", resolved_path); 
        printf("\n%s\n",resolved_path); 
        return 0; 
}

You can try that. As the same ser (unwind) answered there.

Community
  • 1
  • 1
  • I need a relative path from a directory to a given relative path, I guess the original question wasn't clear, I will edit. – Casey Kuball Feb 22 '13 at 17:42
0

The way it works is much simpler: once the server receives a request, it ONLY looks at its htdoc (static contents) directory to check if the requested resource exists:

char *htdoc = "/opt/server/htdoc"; // here a sub-directory of the server program
char *request = "GET /index.html"; // the client request
char *req_path = strchr(request, ' ') + 1; // the URI path

char filepath[512]; // build the file-system path
snprintf(filepath, sizeof(filepath) - 1, "%s/%s", htdos, req_path);

FILE *f = fopen(filepath, "r"); // try to open the file
...

Note that this code is unsafe because it does not check if the request ventures in the file system by containing "../" patterns (and other tricks). You should also use stat() to make sure that the file is a regular file and that the server has permissions to read it.

Gil
  • 3,279
  • 1
  • 15
  • 25
  • That last paragraph of yours is the exact problem that I was trying to fix, lol. – Casey Kuball Feb 24 '13 at 18:44
  • Then, you can either follow my above guidelines or find how it is done in open-source Web servers. Writing such code is not a trivial task (especially if done correctly *and* efficiently), so it can't reasonably be posted here (too specific, too long, too complex). – Gil Feb 25 '13 at 07:34
0

As a simple (but incomplete) solution, I just decided to write a bit of code to check the file path for any ...

int is_valid_fname(char *fname) {
    char *it = fname;
    while(TRUE) {
        if (strncmp(it, "..", 2) == 0) {
            return FALSE;
        }
        it = strchr(it, '/');
        if (it == NULL) break;
        it++;
    }
    return TRUE;
}
Casey Kuball
  • 7,717
  • 5
  • 38
  • 70