Comparar commits

7 Commits

Autor SHA1 Mensaje Fecha
8d685dc581 Makefile: Remove -lseccomp as we don't need it anymore 2021-09-29 18:33:45 +02:00
ed43f5f700 submodules: update cpp-httplib 2021-09-29 18:28:18 +02:00
10f00aeb45 main: Pass absolute path of config file
As sandboxing code chroots and chdirs away,
2021-09-23 17:13:08 +02:00
67eb8b6428 sandbox: adjust to latest qssb.h 2021-09-23 17:13:08 +02:00
f26fd19fb4 submodules: sync with latest upstream 2021-09-23 17:13:08 +02:00
204a72da1f setup: Fix broken FTS DELETE op
Thie previous DELETE statement lead to strange
behaviours. It was pure luck this did not blow up
before all these years. It appears it may leave the index
in an undefined state, and the database recently started
to display strange behaviour in connection with newer sqlite
version.

Now, just remove the previous revision from the FTS index,
as for now, search only cares about the most recent revisions.

Also, remove redundant UPDATE trigger on revision table
We never update revisions, thus such trigger is simply
redundant.

Relevant: https://gitlab.gnome.org/GNOME/tracker/-/merge_requests/353
2021-09-23 17:13:08 +02:00
88816a4015 utils: html_xss(): Add ' and &
They REALLY should have been there from the beginning...
2021-06-15 18:37:52 +02:00
Se han modificado 21 ficheros con 115 adiciones y 229 borrados

3
.gitmodules vendido
Ver fichero

@ -7,6 +7,3 @@
[submodule "submodules/qssb.h"] [submodule "submodules/qssb.h"]
path = submodules/qssb.h path = submodules/qssb.h
url = https://gitea.quitesimple.org/crtxcr/qssb.h.git url = https://gitea.quitesimple.org/crtxcr/qssb.h.git
[submodule "submodules/qsmaddy"]
path = submodules/qsmaddy
url = https://gitea.quitesimple.org/crtxcr/qsmaddy

Ver fichero

@ -2,8 +2,8 @@
CXXFLAGS=-std=c++17 -O0 -g -no-pie -pipe -MMD -Wall -Wextra CXXFLAGS=-std=c++17 -O0 -g -no-pie -pipe -MMD -Wall -Wextra
RELEASE_CXXFLAGS=-std=c++17 -O3 -pipe -MMD -Wall -Wextra RELEASE_CXXFLAGS=-std=c++17 -O3 -pipe -MMD -Wall -Wextra
LDFLAGS=-lsqlite3 -lpthread -lcrypto -lstdc++fs -lseccomp LDFLAGS=-lsqlite3 -lpthread -lcrypto -lstdc++fs
INCLUDEFLAGS=-I submodules/sqlitemoderncpp/hdr -I submodules/cpp-httplib -I submodules/qssb.h -I submodules/qsmaddy/include/ INCLUDEFLAGS=-I submodules/sqlitemoderncpp/hdr -I submodules/cpp-httplib -I submodules/qssb.h
CXX=g++ CXX=g++

Ver fichero

@ -71,7 +71,6 @@ Config::Config(const std::map<std::string, std::string> &map)
this->configmap = map; this->configmap = map;
this->wikipath = optional("wikipath", "/"); this->wikipath = optional("wikipath", "/");
this->parser = optional("parser", "markdown");
this->handlersConfig.anon_username = optional("anon_username", "anonymouse"); this->handlersConfig.anon_username = optional("anon_username", "anonymouse");
this->handlersConfig.wikiname = required("wikiname"); this->handlersConfig.wikiname = required("wikiname");
this->logfile = required("logfile"); this->logfile = required("logfile");

Ver fichero

@ -86,7 +86,6 @@ class Config
std::string templateprefix; std::string templateprefix;
std::string logfile; std::string logfile;
std::string connectionstring; std::string connectionstring;
std::string parser;
int session_max_lifetime; int session_max_lifetime;
int threadscount; int threadscount;

Ver fichero

@ -9,13 +9,10 @@
#include "../database/queryoption.h" #include "../database/queryoption.h"
#include "../logger.h" #include "../logger.h"
#include "../cache/icache.h" #include "../cache/icache.h"
#include "../iparser.h"
class Handler class Handler
{ {
protected: protected:
ICache *cache; ICache *cache;
IParser *parser;
Template *templ; Template *templ;
Database *database; Database *database;
Session *userSession; Session *userSession;
@ -28,7 +25,7 @@ class Handler
public: public:
Handler(HandlerConfig &handlersConfig, Template &templ, Database &db, Session &userSession, UrlProvider &provider, Handler(HandlerConfig &handlersConfig, Template &templ, Database &db, Session &userSession, UrlProvider &provider,
ICache &cache, IParser &parser) ICache &cache)
{ {
this->handlersConfig = &handlersConfig; this->handlersConfig = &handlersConfig;
this->templ = &templ; this->templ = &templ;
@ -36,7 +33,6 @@ class Handler
this->userSession = &userSession; this->userSession = &userSession;
this->urlProvider = &provider; this->urlProvider = &provider;
this->cache = &cache; this->cache = &cache;
this->parser = &parser;
} }
virtual Response handle(const Request &r); virtual Response handle(const Request &r);

Ver fichero

@ -10,16 +10,15 @@ class HandlerFactory
Database &db; Database &db;
UrlProvider &urlProvider; UrlProvider &urlProvider;
ICache &cache; ICache &cache;
IParser &parser;
template <class T> inline std::unique_ptr<T> produce(Session &userSession) template <class T> inline std::unique_ptr<T> produce(Session &userSession)
{ {
return std::make_unique<T>(handlerConfig, templ, db, userSession, urlProvider, cache, parser); return std::make_unique<T>(handlerConfig, templ, db, userSession, urlProvider, cache);
} }
public: public:
HandlerFactory(HandlerConfig &handlerConfig, Template &templ, Database &db, UrlProvider &urlprovider, ICache &cache, IParser &parser) HandlerFactory(HandlerConfig &handlerConfig, Template &templ, Database &db, UrlProvider &urlprovider, ICache &cache)
: handlerConfig(handlerConfig), templ(templ), db(db), urlProvider(urlprovider), cache(cache), parser(parser) : handlerConfig(handlerConfig), templ(templ), db(db), urlProvider(urlprovider), cache(cache)
{ {
} }
std::unique_ptr<Handler> createHandler(const std::string &action, Session &userSession); std::unique_ptr<Handler> createHandler(const std::string &action, Session &userSession);

Ver fichero

@ -21,8 +21,8 @@ SOFTWARE.
#include "handlerpageedit.h" #include "handlerpageedit.h"
#include "../database/exceptions.h" #include "../database/exceptions.h"
#include "../request.h" #include "../request.h"
#include "../parserlegacy.h"
#include "../parser.h"
bool HandlerPageEdit::canAccess(std::string page) bool HandlerPageEdit::canAccess(std::string page)
{ {
return this->userSession->user.permissions.canEdit(); return this->userSession->user.permissions.canEdit();
@ -59,7 +59,7 @@ Response HandlerPageEdit::handleRequest(PageDao &pageDao, std::string pagename,
// TODO: must check, whether categories differ, and perhaps don't allow every user // TODO: must check, whether categories differ, and perhaps don't allow every user
// to set categories // to set categories
ParserLegacy parser; Parser parser;
std::vector<std::string> cats = parser.extractCategories(newContent); std::vector<std::string> cats = parser.extractCategories(newContent);
try try
{ {
@ -107,7 +107,7 @@ Response HandlerPageEdit::handleRequest(PageDao &pageDao, std::string pagename,
if(r.post("do") == "preview") if(r.post("do") == "preview")
{ {
std::string newContent = r.post("content"); std::string newContent = r.post("content");
ParserLegacy parser; Parser parser;
TemplatePage templatePage = this->templ->getPage("page_creation_preview"); TemplatePage templatePage = this->templ->getPage("page_creation_preview");
templatePage.setVar("actionurl", urlProvider->editPage(pagename)); templatePage.setVar("actionurl", urlProvider->editPage(pagename));
templatePage.setVar("preview_content", parser.parse(pageDao, *this->urlProvider, newContent)); templatePage.setVar("preview_content", parser.parse(pageDao, *this->urlProvider, newContent));

Ver fichero

@ -21,7 +21,7 @@ SOFTWARE.
#include "handlerpageview.h" #include "handlerpageview.h"
#include "../database/exceptions.h" #include "../database/exceptions.h"
#include "../logger.h" #include "../logger.h"
#include "../parserlegacy.h" #include "../parser.h"
#include "../htmllink.h" #include "../htmllink.h"
bool HandlerPageView::canAccess(std::string page) bool HandlerPageView::canAccess(std::string page)
@ -130,7 +130,7 @@ Response HandlerPageView::handleRequest(PageDao &pageDao, std::string pagename,
TemplatePage &page = this->templ->getPage(templatepartname); TemplatePage &page = this->templ->getPage(templatepartname);
Parser parser;
Response result; Response result;
result.setStatus(200); result.setStatus(200);
std::string indexcontent; std::string indexcontent;
@ -138,8 +138,8 @@ Response HandlerPageView::handleRequest(PageDao &pageDao, std::string pagename,
if(revisionid > 0) if(revisionid > 0)
{ {
indexcontent = createIndexContent(*parser, revision->content); indexcontent = createIndexContent(parser, revision->content);
parsedcontent = parser->parse(pageDao, *this->urlProvider, revision->content); parsedcontent = parser.parse(pageDao, *this->urlProvider, revision->content);
} }
else else
{ {
@ -153,7 +153,7 @@ Response HandlerPageView::handleRequest(PageDao &pageDao, std::string pagename,
} }
else else
{ {
indexcontent = createIndexContent(*parser, revision->content); indexcontent = createIndexContent(parser, revision->content);
this->cache->put(cachekeyindexcontent, indexcontent); this->cache->put(cachekeyindexcontent, indexcontent);
} }
if(cachedparsedcontent) if(cachedparsedcontent)
@ -162,7 +162,7 @@ Response HandlerPageView::handleRequest(PageDao &pageDao, std::string pagename,
} }
else else
{ {
parsedcontent = parser->parse(pageDao, *this->urlProvider, revision->content); parsedcontent = parser.parse(pageDao, *this->urlProvider, revision->content);
this->cache->put(cachekeyparsedcontent, parsedcontent); this->cache->put(cachekeyparsedcontent, parsedcontent);
} }
} }

Ver fichero

@ -5,8 +5,6 @@
#include "headline.h" #include "headline.h"
#include "database/pagedao.h" #include "database/pagedao.h"
#include "urlprovider.h" #include "urlprovider.h"
class IParser class IParser
{ {
public: public:
@ -18,6 +16,4 @@ class IParser
virtual ~IParser(){}; virtual ~IParser(){};
}; };
#endif // PARSER_H #endif // PARSER_H

Ver fichero

@ -24,22 +24,29 @@ SOFTWARE.
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
#include <iterator> #include <iterator>
#include "parserlegacy.h" #include "parser.h"
#include "utils.h" #include "utils.h"
#include "htmllink.h" #include "htmllink.h"
std::vector<Headline> ParserLegacy::extractHeadlines(std::string content) const std::vector<Headline> Parser::extractHeadlines(std::string content) const
{ {
std::vector<Headline> result; std::vector<Headline> result;
utils::regex_callback_extractor(std::regex(R"(\[h(1|2|3)\](.*?)\[/h\1\])"), content, [&](std::smatch &smatch) { std::string reg = R"(\[h(1|2|3)\](.*?)\[/h\1\])";
std::regex headerfinder(reg);
auto begin = std::sregex_iterator(content.begin(), content.end(), headerfinder);
auto end = std::sregex_iterator();
for(auto it = begin; it != end; it++)
{
auto smatch = *it;
Headline h; Headline h;
h.level = utils::toUInt(smatch.str(1)); h.level = utils::toUInt(smatch.str(1));
h.title = smatch.str(2); h.title = smatch.str(2);
result.push_back(h); result.push_back(h);
}); }
return result; return result;
} }
std::vector<std::string> ParserLegacy::extractCategories(std::string content) const std::vector<std::string> Parser::extractCategories(std::string content) const
{ {
std::vector<std::string> result; std::vector<std::string> result;
std::string reg = R"(\[category\](.*?)\[/category\])"; std::string reg = R"(\[category\](.*?)\[/category\])";
@ -55,7 +62,7 @@ std::vector<std::string> ParserLegacy::extractCategories(std::string content) co
return result; return result;
} }
std::string ParserLegacy::extractCommand(std::string cmdname, std::string content) const std::string Parser::extractCommand(std::string cmdname, std::string content) const
{ {
std::string cmd = "[cmd:" + cmdname + "]"; std::string cmd = "[cmd:" + cmdname + "]";
std::string cmdend = "[/cmd:" + cmdname + "]"; std::string cmdend = "[/cmd:" + cmdname + "]";
@ -74,7 +81,7 @@ std::string ParserLegacy::extractCommand(std::string cmdname, std::string conten
} }
return ""; return "";
} }
std::string ParserLegacy::processLink(const PageDao &pageDao, UrlProvider &urlProvider, std::smatch &match) const std::string Parser::processLink(const PageDao &pageDao, UrlProvider &urlProvider, std::smatch &match) const
{ {
std::string linktag = match.str(1); std::string linktag = match.str(1);
std::string inside = match.str(2); std::string inside = match.str(2);
@ -109,7 +116,7 @@ std::string ParserLegacy::processLink(const PageDao &pageDao, UrlProvider &urlPr
return htmllink.render(); return htmllink.render();
} }
std::string ParserLegacy::parse(const PageDao &pagedao, UrlProvider &provider, std::string content) const std::string Parser::parse(const PageDao &pagedao, UrlProvider &provider, std::string content) const
{ {
std::string result; std::string result;
// we don't care about commands, but we nevertheless replace them with empty strings // we don't care about commands, but we nevertheless replace them with empty strings

Ver fichero

@ -2,7 +2,7 @@
#define PARSER_H #define PARSER_H
#include "iparser.h" #include "iparser.h"
class ParserLegacy : public IParser class Parser : public IParser
{ {
private: private:
std::string processLink(const PageDao &pageDao, UrlProvider &urlProvider, std::smatch &match) const; std::string processLink(const PageDao &pageDao, UrlProvider &urlProvider, std::smatch &match) const;
@ -13,7 +13,7 @@ class ParserLegacy : public IParser
std::vector<std::string> extractCategories(std::string content) const override; std::vector<std::string> extractCategories(std::string content) const override;
std::string parse(const PageDao &pagedao, UrlProvider &provider, std::string content) const override; std::string parse(const PageDao &pagedao, UrlProvider &provider, std::string content) const override;
using IParser::IParser; using IParser::IParser;
~ParserLegacy(){}; ~Parser(){};
}; };
#endif // PARSER_H #endif // PARSER_H

Ver fichero

@ -1,71 +0,0 @@
#include "parsermarkdown.h"
#include "logger.h"
#include "htmllink.h"
std::string ParserMarkdown::processLink(const PageDao &pageDao, UrlProvider &urlProvider, std::smatch &match) const
{
std::string inner = match.str(1);
std::string link = match.str(2);
HtmlLink htmllink;
htmllink.href = link;
htmllink.innervalue = inner;
if(link.find("http://") == 0 || link.find("https://") == 0)
{
return htmllink.render();
}
if(pageDao.exists(link))
{
htmllink.cssclass = "exists";
}
else
{
htmllink.cssclass = "notexists";
}
htmllink.href = urlProvider.page(htmllink.href);
return htmllink.render();
}
ParserMarkdown::ParserMarkdown()
{
}
std::vector<Headline> ParserMarkdown::extractHeadlines(std::string content) const
{
std::vector<Headline> result;
utils::regex_callback_extractor(std::regex(R"((#{1,6}) (.*))"), content, [&](std::smatch &smatch) {
Headline h;
h.level = smatch.str(1).length();
h.title = smatch.str(2);
result.push_back(h);
});
return result;
}
std::string ParserMarkdown::parse(const PageDao &pagedao, UrlProvider &provider, std::string content) const
{
std::shared_ptr<maddy::ParserConfig> config = std::make_shared<maddy::ParserConfig>();
auto maddy = std::make_shared<maddy::Parser>(config);
auto linkParser = std::make_shared<maddy::LinkParser>();
linkParser->setCallback([&](std::smatch &match) { return processLink(pagedao, provider, match); });
maddy->setLinkParser(linkParser);
// TODO: hack because the parser breaks if there is an \r
content = utils::strreplace(content, "\r", "");
std::stringstream s{content};
std::string result = maddy->Parse(s);
return result;
}
std::string ParserMarkdown::extractCommand(std::string cmdname, std::string content) const
{
return "";
}
std::vector<std::string> ParserMarkdown::extractCategories(std::string content) const
{
return { };
}

Ver fichero

@ -1,21 +0,0 @@
#ifndef PARSER_MARKDOWN_H
#define PARSER_MARKDOWN_H
#include "iparser.h"
#include "maddy/parser.h"
class ParserMarkdown : public IParser
{
private:
std::string processLink(const PageDao &pageDao, UrlProvider &urlProvider, std::smatch &match) const;
public:
ParserMarkdown();
std::vector<Headline> extractHeadlines(std::string content) const;
std::string parse(const PageDao &pagedao, UrlProvider &provider, std::string content) const;
std::string extractCommand(std::string cmdname, std::string content) const;
std::vector<std::string> extractCategories(std::string content) const;
};
#endif // PARSER_MARKDOWN_H

Ver fichero

@ -37,10 +37,6 @@ SOFTWARE.
#include "requestworker.h" #include "requestworker.h"
#include "cache/fscache.h" #include "cache/fscache.h"
#include "sandbox/sandboxfactory.h" #include "sandbox/sandboxfactory.h"
#include "iparser.h"
#include "parserlegacy.h"
#include "parsermarkdown.h"
void sigterm_handler(int arg) void sigterm_handler(int arg)
{ {
// TODO: proper shutdown. // TODO: proper shutdown.
@ -67,17 +63,6 @@ std::unique_ptr<ICache> createCache(const ConfigVariableResolver &resolver)
return std::make_unique<FsCache>(path); return std::make_unique<FsCache>(path);
} }
std::unique_ptr<IParser> createParser(const ConfigVariableResolver &resolver)
{
std::string parser = resolver.getConfig("parser");
if(parser == "legacy")
{
return std::make_unique<ParserLegacy>();
}
return std::make_unique<ParserMarkdown>();
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
if(geteuid() == 0) if(geteuid() == 0)
@ -92,21 +77,21 @@ int main(int argc, char **argv)
Logger::error() << "Sandbox is not supported, exiting"; Logger::error() << "Sandbox is not supported, exiting";
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if(argc < 2)
{
std::cerr << "no path to config file provided" << std::endl;
return 1;
}
std::string configpath = std::filesystem::absolute(argv[1]).string();
if(!sandbox->enableForInit()) if(!sandbox->enableForInit())
{ {
Logger::error() << "Sandboxing for init mode could not be activated."; Logger::error() << "Sandboxing for init mode could not be activated.";
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if(argc < 2)
{
std::cerr << "no path to config file provided" << std::endl;
return 1;
}
try try
{ {
ConfigReader configreader(argv[1]); ConfigReader configreader(configpath);
Config config = configreader.readConfig(); Config config = configreader.readConfig();
// TODO: config.connectiontring only works as long as we only support sqlite of course // TODO: config.connectiontring only works as long as we only support sqlite of course
@ -150,10 +135,7 @@ int main(int argc, char **argv)
auto cache = createCache(config.configVarResolver); auto cache = createCache(config.configVarResolver);
cache->clear(); cache->clear();
auto parser = createParser(config.configVarResolver); HandlerFactory handlerFactory{config.handlersConfig, siteTemplate, *database.get(), urlProvider, *cache.get()};
HandlerFactory handlerFactory{config.handlersConfig, siteTemplate, *database.get(), urlProvider, *cache.get(), *parser.get()};
RequestWorker requestWorker{handlerFactory, database->createSessionDao(), siteTemplate}; RequestWorker requestWorker{handlerFactory, database->createSessionDao(), siteTemplate};
auto interface = createGateway(config); auto interface = createGateway(config);

Ver fichero

@ -26,16 +26,26 @@
bool SandboxLinux::enableForInit() bool SandboxLinux::enableForInit()
{ {
umask(0027); umask(0027);
struct qssb_policy policy = {0}; struct qssb_policy *policy = qssb_init_policy();
int blacklisted_syscalls[] = {QSSB_SYS(execveat), QSSB_SYS(execve), -1}; if(policy == NULL)
policy.blacklisted_syscalls = blacklisted_syscalls;
policy.no_new_privs = 1;
int result = qssb_enable_policy(&policy);
if(result != 0)
{ {
Logger::error() << "Failed to install sandboxing policy (init): " << result; Logger::error() << "Failed to init sandboxing policy (init)";
return false; return false;
} }
policy->namespace_options = QSSB_UNSHARE_USER;
policy->drop_caps = 0;
qssb_append_syscall_policy(policy, QSSB_SYSCALL_DENY_KILL_PROCESS, QSSB_SYS(execveat));
qssb_append_syscall_policy(policy, QSSB_SYSCALL_DENY_KILL_PROCESS, QSSB_SYS(execve));
qssb_append_syscall_default_policy(policy, QSSB_SYSCALL_ALLOW);
int result = qssb_enable_policy(policy);
if(result != 0)
{
Logger::error() << "Failed to enable sandboxing policy (init): " << result;
qssb_free_policy(policy);
return false;
}
qssb_free_policy(policy);
return true; return true;
} }
@ -44,28 +54,34 @@ bool SandboxLinux::enablePreWorker(std::vector<std::string> fsPaths)
std::sort(fsPaths.begin(), fsPaths.end(), std::sort(fsPaths.begin(), fsPaths.end(),
[](const std::string &a, const std::string &b) { return a.length() < b.length(); }); [](const std::string &a, const std::string &b) { return a.length() < b.length(); });
struct qssb_path_policy *policies = new qssb_path_policy[fsPaths.size()]; struct qssb_policy *policy = qssb_init_policy();
if(policy == NULL)
{
Logger::error() << "Failed to init sandboxing policy (pre)";
return false;
}
for(unsigned int i = 0; i < fsPaths.size(); i++) for(unsigned int i = 0; i < fsPaths.size(); i++)
{ {
policies[i].next = policies + (i + 1); qssb_append_path_policy(policy, QSSB_FS_ALLOW_READ | QSSB_FS_ALLOW_WRITE, fsPaths[i].c_str());
policies[i].mountpoint = fsPaths[i].c_str();
policies[i].policy = QSSB_MOUNT_ALLOW_READ | QSSB_MOUNT_ALLOW_WRITE;
} }
policies[fsPaths.size() - 1].next = NULL;
struct qssb_policy policy = {0}; policy->namespace_options = QSSB_UNSHARE_MOUNT;
policy.path_policies = policies; policy->drop_caps = 0;
policy.namespace_options |= QSSB_UNSHARE_MOUNT; policy->mount_path_policies_to_chroot = 1;
policy.namespace_options |= QSSB_UNSHARE_USER;
int blacklisted_syscalls[] = {QSSB_SYS(execveat), QSSB_SYS(execve), -1}; qssb_append_syscall_policy(policy, QSSB_SYSCALL_DENY_KILL_PROCESS, QSSB_SYS(execveat));
policy.blacklisted_syscalls = blacklisted_syscalls; qssb_append_syscall_policy(policy, QSSB_SYSCALL_DENY_KILL_PROCESS, QSSB_SYS(execve));
int result = qssb_enable_policy(&policy); qssb_append_syscall_default_policy(policy, QSSB_SYSCALL_ALLOW);
int result = qssb_enable_policy(policy);
if(result != 0) if(result != 0)
{ {
Logger::error() << "Failed to install sandboxing policy (preworker): %i" << result; Logger::error() << "Failed to install sandboxing policy (preworker): %i" << result;
qssb_free_policy(policy);
return false; return false;
} }
delete[] policies; qssb_free_policy(policy);
return true; return true;
} }
@ -88,30 +104,35 @@ bool SandboxLinux::supported()
} }
bool SandboxLinux::enableForWorker() bool SandboxLinux::enableForWorker()
{ {
struct qssb_policy policy = {0}; struct qssb_policy *policy = qssb_init_policy();
policy.drop_caps = 1; if(policy == NULL)
policy.not_dumpable = 1; {
policy.no_new_privs = 1; Logger::error() << "Failed to init sandboxing policy (worker) ";
return false;
}
policy->drop_caps = 1;
policy->not_dumpable = 1;
policy->no_new_privs = 1;
policy->namespace_options = 0;
/* TODO: as said, a whitelist approach is better. As such, this list is bound to be incomplete in the /* TODO: as said, a whitelist approach is better. As such, this list is bound to be incomplete in the
* sense that more could be listed here and some critical ones are probably missing */ * sense that more could be listed here and some critical ones are probably missing */
int blacklisted_syscalls[] = {QSSB_SYS(setuid),
QSSB_SYS(connect), /* TODO: use qssb groups */
QSSB_SYS(chroot), long blacklisted_syscalls[] = {QSSB_SYS(setuid), QSSB_SYS(connect), QSSB_SYS(chroot), QSSB_SYS(pivot_root),
QSSB_SYS(pivot_root), QSSB_SYS(mount), QSSB_SYS(setns), QSSB_SYS(unshare), QSSB_SYS(ptrace),
QSSB_SYS(mount), QSSB_SYS(personality), QSSB_SYS(prctl)};
QSSB_SYS(setns),
QSSB_SYS(unshare), qssb_append_syscalls_policy(policy, QSSB_SYSCALL_DENY_KILL_PROCESS, blacklisted_syscalls,
QSSB_SYS(ptrace), sizeof(blacklisted_syscalls) / sizeof(blacklisted_syscalls[0]));
QSSB_SYS(personality), qssb_append_syscall_default_policy(policy, QSSB_SYSCALL_ALLOW);
QSSB_SYS(prctl),
-1}; if(qssb_enable_policy(policy) != 0)
policy.blacklisted_syscalls = blacklisted_syscalls;
if(qssb_enable_policy(&policy) != 0)
{ {
Logger::error() << "Sandbox: Activation of seccomp blacklist failed!"; Logger::error() << "Sandbox: Activation of seccomp blacklist failed!";
qssb_free_policy(policy);
return false; return false;
} }
qssb_free_policy(policy);
return true; return true;
} }

Ver fichero

@ -25,24 +25,13 @@ count integer
CREATE TABLE category(id INTEGER PRIMARY KEY, name varchar(255)); CREATE TABLE category(id INTEGER PRIMARY KEY, name varchar(255));
CREATE TABLE categorymember(id INTEGER PRIMARY KEY, category REFERENCES category(id), page REFERENCES page (id)); CREATE TABLE categorymember(id INTEGER PRIMARY KEY, category REFERENCES category(id), page REFERENCES page (id));
CREATE INDEX revisionid ON revision (revisionid DESC); CREATE INDEX revisionid ON revision (revisionid DESC);
CREATE INDEX pagename ON page (name) CREATE INDEX pagename ON page (name);
; CREATE INDEX token ON session (token);
CREATE INDEX token ON session (token) CREATE VIRTUAL TABLE search USING fts5(content, page UNINDEXED, content=revision,content_rowid=id);
;
CREATE TRIGGER search_ai AFTER INSERT ON revision BEGIN
DELETE FROM search WHERE page = new.page;
INSERT INTO search(rowid, content, page) VALUES (new.id, new.content, new.page);
END;
CREATE TRIGGER search_au AFTER UPDATE ON revision BEGIN
DELETE FROM search WHERE page = old.page;
INSERT INTO search(rowid, content, page) VALUES (new.id, new.content, new.page);
END;
CREATE VIRTUAL TABLE search USING fts5(content, page UNINDEXED, content=revision,content_rowid=id)
/* search(content,page) */;
CREATE TABLE IF NOT EXISTS 'search_data'(id INTEGER PRIMARY KEY, block BLOB);
CREATE TABLE IF NOT EXISTS 'search_idx'(segid, term, pgno, PRIMARY KEY(segid, term)) WITHOUT ROWID;
CREATE TABLE IF NOT EXISTS 'search_docsize'(id INTEGER PRIMARY KEY, sz BLOB);
CREATE TABLE IF NOT EXISTS 'search_config'(k PRIMARY KEY, v) WITHOUT ROWID;
CREATE TRIGGER search_ad AFTER DELETE ON revision BEGIN CREATE TRIGGER search_ad AFTER DELETE ON revision BEGIN
INSERT INTO search(search, rowid, content, page) VALUES('delete', old.id, old.content, old.page); INSERT INTO search(search, rowid, content, page) VALUES('delete', old.id, old.content, old.page);
END; END;
CREATE TRIGGER search_ai AFTER INSERT ON revision BEGIN
INSERT INTO search(search, rowid, content, page) SELECT 'delete', id, content, page FROM revision WHERE page = new.page AND revisionid = new.revisionid - 1;
INSERT INTO search(rowid, content, page) VALUES (new.id, new.content, new.page);
END;

Ver fichero

@ -46,6 +46,12 @@ std::string utils::html_xss(std::string_view str)
case '%': case '%':
result += "&#37;"; result += "&#37;";
break; break;
case '\'':
result += "&#x27;";
break;
case '&':
result += "&amp;";
break;
default: default:
result += c; result += c;
} }
@ -175,14 +181,3 @@ std::string utils::toISODate(time_t t)
} }
return std::string{result}; return std::string{result};
} }
void utils::regex_callback_extractor(std::regex regex, const std::string &input, std::function<void (std::smatch &)> callback)
{
auto begin = std::sregex_iterator(input.begin(), input.end(), regex);
auto end = std::sregex_iterator();
for(auto it = begin; it != end; it++)
{
std::smatch smatch = *it;
callback(smatch);
}
}

Ver fichero

@ -60,7 +60,6 @@ template <class T, class U> std::vector<U> getAll(std::multimap<T, U> map, T key
std::string regex_callback_replacer(std::regex regex, const std::string &input, std::string regex_callback_replacer(std::regex regex, const std::string &input,
std::function<std::string(std::smatch &)> callback); std::function<std::string(std::smatch &)> callback);
void regex_callback_extractor(std::regex regex, const std::string &input, std::function<void(std::smatch &)> callback);
std::string readCompleteFile(std::string_view filepath); std::string readCompleteFile(std::string_view filepath);
inline std::string nz(const char *s) inline std::string nz(const char *s)