From ecde8110ee66be51aaea6f121f2e017e40af8cbd Mon Sep 17 00:00:00 2001 From: "Hongli Lai (Phusion)" Date: Wed, 12 Mar 2008 14:45:38 +0100 Subject: [PATCH] Canonicalize Rails application root paths. --- ext/apache2/Hooks.cpp | 30 +++++++++++++++++------------- ext/apache2/Utils.cpp | 25 +++++++++++++++++++++++++ ext/apache2/Utils.h | 9 +++++++++ 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/ext/apache2/Hooks.cpp b/ext/apache2/Hooks.cpp index 34cb8e0901..d239802c5b 100644 --- a/ext/apache2/Hooks.cpp +++ b/ext/apache2/Hooks.cpp @@ -72,7 +72,9 @@ class Hooks { const string &base(*it); if ( base == "/" || ( uri_len == base.size() && memcmp(uri, base.c_str(), uri_len) == 0 ) - || ( uri_len > base.size() && memcmp(uri, base.c_str(), base.size()) == 0 && uri[base.size()] == '/' )) { + || ( uri_len > base.size() && memcmp(uri, base.c_str(), base.size()) == 0 + && uri[base.size()] == '/' ) + ) { return apr_pstrdup(r->pool, base.c_str()); } } @@ -85,24 +87,26 @@ class Hooks { return NULL; } - const char *determineRailsDir(request_rec *r, const char *baseURI) { + string determineRailsDir(request_rec *r, const char *baseURI) { const char *docRoot = ap_document_root(r); size_t len = strlen(docRoot); if (len > 0) { - string temp; + string path; if (docRoot[len - 1] == '/') { - temp.assign(docRoot, len - 1); + path.assign(docRoot, len - 1); } else { - temp.assign(docRoot, len); + path.assign(docRoot, len); } - temp.append(baseURI); - return apr_pstrdup(r->pool, temp.c_str()); + if (strcmp(baseURI, "/") != 0) { + path.append(baseURI); + } + return path; } else { - return NULL; + return ""; } } - bool verifyRailsDir(apr_pool_t *pool, const char *dir) { + bool verifyRailsDir(apr_pool_t *pool, const string &dir) { string temp(dir); temp.append("/../config/environment.rb"); return fileExists(temp.c_str()); @@ -316,8 +320,8 @@ class Hooks { return DECLINED; } - const char *railsDir = determineRailsDir(r, railsBaseURI); - if (railsDir == NULL) { + string railsDir(determineRailsDir(r, railsBaseURI)); + if (railsDir.empty()) { ap_set_content_type(r, "text/html; charset=UTF-8"); ap_rputs("

Passenger error #1

\n", r); ap_rputs("Cannot determine the location of the Rails application's \"public\" directory.", r); @@ -326,7 +330,7 @@ class Hooks { ap_set_content_type(r, "text/html; charset=UTF-8"); ap_rputs("

Passenger error #2

\n", r); ap_rputs("Passenger thinks that the Rails application's \"public\" directory is \"", r); - ap_rputs(ap_escape_html(r->pool, railsDir), r); + ap_rputs(ap_escape_html(r->pool, railsDir.c_str()), r); ap_rputs("\", but it doesn't seem to be valid.", r); return OK; } @@ -343,7 +347,7 @@ class Hooks { P_DEBUG("Processing HTTP request: " << r->uri); try { - session = applicationPool->get(string(railsDir) + "/.."); + session = applicationPool->get(canonicalizePath(railsDir + "/..")); } catch (const SpawnException &e) { if (e.hasErrorPage()) { ap_set_content_type(r, "text/html; charset=utf-8"); diff --git a/ext/apache2/Utils.cpp b/ext/apache2/Utils.cpp index 6972386155..5d47f4ec5d 100644 --- a/ext/apache2/Utils.cpp +++ b/ext/apache2/Utils.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -79,4 +80,28 @@ findSpawnServer() { return ""; } +string +canonicalizePath(const string &path) { + #ifdef __GLIBC__ + // We're using a GNU extension here. See the 'BUGS' + // section of the realpath(3) Linux manpage for + // rationale. + char *tmp = realpath(path.c_str(), NULL); + if (tmp == NULL) { + return ""; + } else { + string result(tmp); + free(tmp); + return result; + } + #else + char tmp[PATH_MAX]; + if (realpath(path.c_str(), tmp) == NULL) { + return ""; + } else { + return tmp; + } + #endif +} + } // namespace Passenger diff --git a/ext/apache2/Utils.h b/ext/apache2/Utils.h index fca3c9d0e9..fec612b3c6 100644 --- a/ext/apache2/Utils.h +++ b/ext/apache2/Utils.h @@ -88,6 +88,15 @@ bool fileExists(const char *filename); */ string findSpawnServer(); +/** + * Returns a canonical version of the specified path. All symbolic links + * and relative path elements are resolved. + * Returns an empty string if something went wrong. + * + * @ingroup Support + */ +string canonicalizePath(const string &path); + #ifdef PASSENGER_DEBUG #define P_DEBUG(expr) \