ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

handlerutils.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "backends/networking/sdl_net/handlerutils.h"
00024 #include "backends/networking/sdl_net/localwebserver.h"
00025 #include "backends/saves/default/default-saves.h"
00026 #include "common/archive.h"
00027 #include "common/config-manager.h"
00028 #include "common/file.h"
00029 #include "common/translation.h"
00030 #include "common/unzip.h"
00031 
00032 namespace Networking {
00033 
00034 #define ARCHIVE_NAME "wwwroot.zip"
00035 
00036 #define INDEX_PAGE_NAME ".index.html"
00037 
00038 Common::Archive *HandlerUtils::getZipArchive() {
00039     // first search in themepath
00040     if (ConfMan.hasKey("themepath")) {
00041         const Common::FSNode &node = Common::FSNode(ConfMan.get("themepath"));
00042         if (node.exists() && node.isReadable() && node.isDirectory()) {
00043             Common::FSNode fileNode = node.getChild(ARCHIVE_NAME);
00044             if (fileNode.exists() && fileNode.isReadable() && !fileNode.isDirectory()) {
00045                 Common::SeekableReadStream *const stream = fileNode.createReadStream();
00046                 Common::Archive *zipArchive = Common::makeZipArchive(stream);
00047                 if (zipArchive)
00048                     return zipArchive;
00049             }
00050         }
00051     }
00052 
00053     // then use SearchMan to find it
00054     Common::ArchiveMemberList fileList;
00055     SearchMan.listMatchingMembers(fileList, ARCHIVE_NAME);
00056     for (Common::ArchiveMemberList::iterator it = fileList.begin(); it != fileList.end(); ++it) {
00057         Common::ArchiveMember       const &m = **it;
00058         Common::SeekableReadStream *const stream = m.createReadStream();
00059         Common::Archive *zipArchive = Common::makeZipArchive(stream);
00060         if (zipArchive)
00061             return zipArchive;
00062     }
00063 
00064     return nullptr;
00065 }
00066 
00067 Common::ArchiveMemberList HandlerUtils::listArchive() {
00068     Common::ArchiveMemberList resultList;
00069     Common::Archive *zipArchive = getZipArchive();
00070     if (zipArchive) {
00071         zipArchive->listMembers(resultList);
00072         delete zipArchive;
00073     }
00074     return resultList;
00075 }
00076 
00077 Common::SeekableReadStream *HandlerUtils::getArchiveFile(Common::String name) {
00078     Common::SeekableReadStream *result = nullptr;
00079     Common::Archive *zipArchive = getZipArchive();
00080     if (zipArchive) {
00081         const Common::ArchiveMemberPtr ptr = zipArchive->getMember(name);
00082         if (ptr.get() == nullptr)
00083             return nullptr;
00084         result = ptr->createReadStream();
00085         delete zipArchive;
00086     }
00087     return result;
00088 }
00089 
00090 Common::String HandlerUtils::readEverythingFromStream(Common::SeekableReadStream *const stream) {
00091     Common::String result;
00092     char buf[1024];
00093     uint32 readBytes;
00094     while (!stream->eos()) {
00095         readBytes = stream->read(buf, 1024);
00096         result += Common::String(buf, readBytes);
00097     }
00098     return result;
00099 }
00100 
00101 Common::String HandlerUtils::normalizePath(const Common::String &path) {
00102     Common::String normalized;
00103     bool slash = false;
00104     for (uint32 i = 0; i < path.size(); ++i) {
00105         char c = path[i];
00106         if (c == '\\' || c == '/') {
00107             slash = true;
00108             continue;
00109         }
00110 
00111         if (slash) {
00112             normalized += '/';
00113             slash = false;
00114         }
00115 
00116         if ('A' <= c && c <= 'Z') {
00117             normalized += c - 'A' + 'a';
00118         } else {
00119             normalized += c;
00120         }
00121     }
00122     if (slash) normalized += '/';
00123     return normalized;
00124 }
00125 
00126 bool HandlerUtils::hasForbiddenCombinations(const Common::String &path) {
00127     return (path.contains("/../") || path.contains("\\..\\") || path.contains("\\../") || path.contains("/..\\"));
00128 }
00129 
00130 bool HandlerUtils::isBlacklisted(const Common::String &path) {
00131     const char *blacklist[] = {
00132         "/etc",
00133         "/bin",
00134         "c:/windows" // just saying: I know guys who install windows on another drives
00135     };
00136 
00137     // normalize path
00138     Common::String normalized = normalizePath(path);
00139 
00140     uint32 size = sizeof(blacklist) / sizeof(const char *);
00141     for (uint32 i = 0; i < size; ++i)
00142         if (normalized.hasPrefix(blacklist[i]))
00143             return true;
00144 
00145     return false;
00146 }
00147 
00148 bool HandlerUtils::hasPermittedPrefix(const Common::String &path) {
00149     // normalize path
00150     Common::String normalized = normalizePath(path);
00151 
00152     // prefix for /root/
00153     Common::String prefix;
00154     if (ConfMan.hasKey("rootpath", "cloud")) {
00155         prefix = normalizePath(ConfMan.get("rootpath", "cloud"));
00156         if (prefix == "/" || normalized.hasPrefix(prefix))
00157             return true;
00158     }
00159 
00160     // prefix for /saves/
00161 #ifdef USE_LIBCURL
00162     DefaultSaveFileManager *manager = dynamic_cast<DefaultSaveFileManager *>(g_system->getSavefileManager());
00163     prefix = (manager ? manager->concatWithSavesPath("") : ConfMan.get("savepath"));
00164 #else
00165     prefix = ConfMan.get("savepath");
00166 #endif
00167     return (normalized.hasPrefix(normalizePath(prefix)));
00168 }
00169 
00170 bool HandlerUtils::permittedPath(const Common::String path) {
00171     return hasPermittedPrefix(path) && !isBlacklisted(path);
00172 }
00173 
00174 void HandlerUtils::setMessageHandler(Client &client, Common::String message, Common::String redirectTo) {
00175     Common::String response = "<html><head><title>ScummVM</title></head><body>{message}</body></html>";
00176 
00177     // load stylish response page from the archive
00178     Common::SeekableReadStream *const stream = getArchiveFile(INDEX_PAGE_NAME);
00179     if (stream)
00180         response = readEverythingFromStream(stream);
00181 
00182     replace(response, "{message}", message);
00183     if (redirectTo.empty())
00184         LocalWebserver::setClientGetHandler(client, response);
00185     else
00186         LocalWebserver::setClientRedirectHandler(client, response, redirectTo);
00187 }
00188 
00189 void HandlerUtils::setFilesManagerErrorMessageHandler(Client &client, Common::String message, Common::String redirectTo) {
00190     setMessageHandler(
00191         client,
00192         Common::String::format(
00193             "%s<br/><a href=\"files%s?path=%s\">%s</a>",
00194             message.c_str(),
00195             client.queryParameter("ajax") == "true" ? "AJAX" : "",
00196             "%2F", //that's encoded "/"
00197             _("Back to the files manager")
00198         ),
00199         redirectTo
00200     );
00201 }
00202 
00203 } // End of namespace Networking


Generated on Sat May 25 2019 05:00:46 for ResidualVM by doxygen 1.7.1
curved edge   curved edge