Compare commits

...

2 commits

Author SHA1 Message Date
lda
fbc4486930
[MOD/WIP] Refactor out code to use the j2s schema.
Do note this is more of a hack/bodge than anything right now,
and this is still a WIP.
2023-12-02 17:03:31 +01:00
lda
74ab3f350f
[WIP/ADD] Start replacing the config with a j2s schema.
Note that this *won't* build as of now.
2023-12-02 12:51:08 +01:00
6 changed files with 177 additions and 481 deletions

93
Schema/Config.json Normal file
View file

@ -0,0 +1,93 @@
{
"guard": "TELODENDRIA_SCHEMA_CONFIG_H",
"header": "Schema\/Config.h",
"include": [ "Cytoplasm\/Db.h", "Cytoplasm/HttpServer.h" ],
"types": {
"ConfigTls": {
"fields": {
"cert": { "type": "string" },
"key": { "type": "string" }
},
"type": "struct"
},
"HttpHandler *": { "type": "extern" },
"void *": { "type": "extern" },
"ConfigListener": {
"fields": {
"handler": { "type": "HttpHandler *", "ignore": true },
"handlerArgs": { "type": "void *", "ignore": true },
"port": { "type": "integer", "required": true },
"threads": { "type": "integer", "required": false },
"maxConnections": { "type": "integer", "required": false },
"tls": { "type": "ConfigTls", "required": false }
},
"type": "struct"
},
"ConfigRunAs": {
"fields": {
"uid": { "type": "string", "required": false },
"gid": { "type": "string", "required": true }
},
"type": "struct"
},
"ConfigLogOutput": {
"fields": {
"stdout": { "name": "CONFIG_LOG_OUTPUT_STDOUT" },
"file": { "name": "CONFIG_LOG_OUTPUT_FILE" },
"syslog": { "name": "CONFIG_LOG_OUTPUT_SYSLOG" }
},
"type": "enum"
},
"ConfigLogLevel": {
"fields": {
"message": { "name": "CONFIG_LOG_LEVEL_MESSAGE" },
"debug": { "name": "CONFIG_LOG_LEVEL_DEBUG" },
"notice": { "name": "CONFIG_LOG_LEVEL_NOTICE" },
"warning": { "name": "CONFIG_LOG_LEVEL_WARNING" },
"error": { "name": "CONFIG_LOG_LEVEL_ERROR" }
},
"type": "enum"
},
"ConfigLogConfig": {
"fields": {
"output": { "type": "ConfigLogOutput", "required": true },
"level": { "type": "ConfigLogLevel", "required": false },
"timestampFormat":{ "type": "string", "required": false },
"color": { "type": "boolean", "required": false }
},
"type": "struct"
},
"Db *": { "type": "extern" },
"DbRef *": { "type": "extern" },
"char *": { "type": "extern" },
"Config": {
"fields": {
"db": { "type": "Db *", "ignore": true },
"ref": { "type": "DbRef *", "ignore": true },
"ok": { "type": "boolean", "ignore": true },
"err": { "type": "char *", "ignore": true },
"listen": { "type": "[ConfigListener]", "required": true },
"runAs": { "type": "ConfigRunAs", "required": false },
"log": { "type": "ConfigLogConfig", "required": true },
"serverName": { "type": "string", "required": true },
"baseUrl": { "type": "string", "required": false },
"identityServer": { "type": "string", "required": false },
"maxCache": { "type": "integer", "required": false },
"federation": { "type": "boolean", "required": true },
"registration": { "type": "boolean", "required": true }
},
"type": "struct"
}
}
}

View file

@ -21,7 +21,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
*/ */
#include <Config.h> #include <Schema/Config.h>
#include <Cytoplasm/Memory.h> #include <Cytoplasm/Memory.h>
#include <Cytoplasm/Json.h> #include <Cytoplasm/Json.h>
#include <Cytoplasm/HashMap.h> #include <Cytoplasm/HashMap.h>
@ -41,378 +41,60 @@
#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX #define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
#endif #endif
#define CONFIG_REQUIRE(key, type) \
value = HashMapGet(config, key); \
if (!value) \
{ \
tConfig->err = "Missing required " key " directive."; \
goto error; \
} \
if (JsonValueType(value) == JSON_NULL) \
{ \
tConfig->err = "Missing value for " key " directive."; \
goto error; \
} \
if (JsonValueType(value) != type) \
{ \
tConfig->err = "Expected " key " to be of type " #type; \
goto error; \
}
#define CONFIG_COPY_STRING(into) \
into = StrDuplicate(JsonValueAsString(value));
#define CONFIG_OPTIONAL_STRING(into, key, default) \
value = HashMapGet(config, key); \
if (value && JsonValueType(value) != JSON_NULL) \
{ \
if (JsonValueType(value) != JSON_STRING) \
{ \
tConfig->err = "Expected " key " to be of type JSON_STRING"; \
goto error; \
} \
into = StrDuplicate(JsonValueAsString(value)); \
} \
else \
{ \
into = default ? StrDuplicate(default) : NULL; \
}
#define CONFIG_OPTIONAL_INTEGER(into, key, default) \
value = HashMapGet(config, key); \
if (value && JsonValueType(value) != JSON_NULL) \
{ \
if (JsonValueType(value) != JSON_INTEGER) \
{ \
tConfig->err = "Expected " key " to be of type JSON_INTEGER"; \
goto error; \
} \
into = Int64Low(JsonValueAsInteger(value)); \
} \
else \
{ \
into = default; \
}
static int
ConfigParseRunAs(Config * tConfig, HashMap * config)
{
JsonValue *value;
CONFIG_REQUIRE("uid", JSON_STRING);
CONFIG_COPY_STRING(tConfig->uid);
CONFIG_OPTIONAL_STRING(tConfig->gid, "gid", tConfig->uid);
return 1;
error:
return 0;
}
static int
ConfigParseListen(Config * tConfig, Array * listen)
{
size_t i;
if (!ArraySize(listen))
{
tConfig->err = "Listen array cannot be empty; you must specify at least one listener.";
goto error;
}
if (!tConfig->servers)
{
tConfig->servers = ArrayCreate();
if (!tConfig->servers)
{
tConfig->err = "Unable to allocate memory for listener configurations.";
goto error;
}
}
for (i = 0; i < ArraySize(listen); i++)
{
JsonValue *val = ArrayGet(listen, i);
HashMap *obj;
HttpServerConfig *serverCfg = Malloc(sizeof(HttpServerConfig));
if (!serverCfg)
{
tConfig->err = "Unable to allocate memory for listener configuration.";
goto error;
}
if (JsonValueType(val) != JSON_OBJECT)
{
tConfig->err = "Invalid value in listener array. All listeners must be objects.";
goto error;
}
obj = JsonValueAsObject(val);
serverCfg->port = Int64Low(JsonValueAsInteger(HashMapGet(obj, "port")));
serverCfg->threads = Int64Low(JsonValueAsInteger(HashMapGet(obj, "threads")));
serverCfg->maxConnections = Int64Low(JsonValueAsInteger(HashMapGet(obj, "maxConnections")));
if (!serverCfg->port)
{
Free(serverCfg);
continue;
}
if (!serverCfg->threads)
{
serverCfg->threads = 4;
}
if (!serverCfg->maxConnections)
{
serverCfg->maxConnections = 32;
}
val = HashMapGet(obj, "tls");
if ((JsonValueType(val) == JSON_BOOLEAN && !JsonValueAsBoolean(val)) || JsonValueType(val) == JSON_NULL)
{
serverCfg->flags = HTTP_FLAG_NONE;
serverCfg->tlsCert = NULL;
serverCfg->tlsKey = NULL;
}
else if (JsonValueType(val) != JSON_OBJECT)
{
tConfig->err = "Invalid value for listener.tls. It must be an object.";
goto error;
}
else
{
serverCfg->flags = HTTP_FLAG_TLS;
obj = JsonValueAsObject(val);
serverCfg->tlsCert = StrDuplicate(JsonValueAsString(HashMapGet(obj, "cert")));
serverCfg->tlsKey = StrDuplicate(JsonValueAsString(HashMapGet(obj, "key")));
if (!serverCfg->tlsCert || !serverCfg->tlsKey)
{
tConfig->err = "TLS cert and key must both be valid file names.";
goto error;
}
}
ArrayAdd(tConfig->servers, serverCfg);
}
return 1;
error:
return 0;
}
static int
ConfigParseLog(Config * tConfig, HashMap * config)
{
JsonValue *value;
char *str;
CONFIG_REQUIRE("output", JSON_STRING);
str = JsonValueAsString(value);
if (StrEquals(str, "stdout"))
{
tConfig->flags |= CONFIG_LOG_STDOUT;
}
else if (StrEquals(str, "file"))
{
tConfig->flags |= CONFIG_LOG_FILE;
}
else if (StrEquals(str, "syslog"))
{
tConfig->flags |= CONFIG_LOG_SYSLOG;
}
else
{
tConfig->err = "Invalid value for log.output";
goto error;
}
CONFIG_OPTIONAL_STRING(str, "level", "message");
if (StrEquals(str, "message"))
{
tConfig->logLevel = LOG_INFO;
}
else if (StrEquals(str, "debug"))
{
tConfig->logLevel = LOG_DEBUG;
}
else if (StrEquals(str, "notice"))
{
tConfig->logLevel = LOG_NOTICE;
}
else if (StrEquals(str, "warning"))
{
tConfig->logLevel = LOG_WARNING;
}
else if (StrEquals(str, "error"))
{
tConfig->logLevel = LOG_ERR;
}
else
{
tConfig->err = "Invalid value for log.level.";
goto error;
}
Free(str);
CONFIG_OPTIONAL_STRING(tConfig->logTimestamp, "timestampFormat", "default");
if (StrEquals(tConfig->logTimestamp, "none"))
{
Free(tConfig->logTimestamp);
tConfig->logTimestamp = NULL;
}
value = HashMapGet(config, "color");
if (value && JsonValueType(value) != JSON_NULL)
{
if (JsonValueType(value) != JSON_BOOLEAN)
{
tConfig->err = "Expected type JSON_BOOLEAN for log.color.";
goto error;
}
if (JsonValueAsBoolean(value))
{
tConfig->flags |= CONFIG_LOG_COLOR;
}
}
return 1;
error:
return 0;
}
void
ConfigFree(Config * tConfig)
{
if (!tConfig)
{
return;
}
Free(tConfig->serverName);
Free(tConfig->baseUrl);
Free(tConfig->identityServer);
Free(tConfig->uid);
Free(tConfig->gid);
Free(tConfig->logTimestamp);
if (tConfig->servers)
{
size_t i;
for (i = 0; i < ArraySize(tConfig->servers); i++)
{
HttpServerConfig *serverCfg = ArrayGet(tConfig->servers, i);
Free(serverCfg->tlsCert);
Free(serverCfg->tlsKey);
Free(serverCfg);
}
ArrayFree(tConfig->servers);
}
Free(tConfig);
}
Config * Config *
ConfigParse(HashMap * config) ConfigParse(HashMap * config)
{ {
Config *tConfig; Config *tConfig;
JsonValue *value; JsonValue *value;
size_t i;
if (!config) if (!config)
{ {
return NULL; return NULL;
} }
tConfig = Malloc(sizeof(Config)); tConfig = Malloc(sizeof(Config));
if (!tConfig)
{
return NULL;
}
memset(tConfig, 0, sizeof(Config)); memset(tConfig, 0, sizeof(Config));
CONFIG_REQUIRE("listen", JSON_ARRAY); tConfig->maxCache = Int64Create(0, 0);
if (!ConfigParseListen(tConfig, JsonValueAsArray(value)))
if (!ConfigFromJson(config, tConfig, &tConfig->err))
{ {
ConfigFree(tConfig);
goto error; goto error;
} }
if (!tConfig->baseUrl)
CONFIG_REQUIRE("serverName", JSON_STRING);
CONFIG_COPY_STRING(tConfig->serverName);
value = HashMapGet(config, "baseUrl");
if (value)
{
CONFIG_COPY_STRING(tConfig->baseUrl);
}
else
{ {
size_t len = strlen(tConfig->serverName) + 10; size_t len = strlen(tConfig->serverName) + 10;
tConfig->baseUrl = Malloc(len); tConfig->baseUrl = Malloc(len);
if (!tConfig->baseUrl) if (!tConfig->baseUrl)
{ {
tConfig->err = "Error allocating memory for default config value 'baseUrl'."; tConfig->err = "Couldn't allocate enough memory for 'baseUrl'.";
goto error;
}
snprintf(tConfig->baseUrl, len, "https://%s", tConfig->serverName);
}
CONFIG_OPTIONAL_STRING(tConfig->identityServer, "identityServer", NULL);
value = HashMapGet(config, "runAs");
if (value && JsonValueType(value) != JSON_NULL)
{
if (JsonValueType(value) == JSON_OBJECT)
{
if (!ConfigParseRunAs(tConfig, JsonValueAsObject(value)))
{
goto error;
}
}
else
{
tConfig->err = "Config directive 'runAs' should be a JSON object that contains a 'uid' and 'gid'.";
goto error; goto error;
} }
} }
if (!tConfig->log.timestampFormat)
CONFIG_OPTIONAL_INTEGER(tConfig->maxCache, "maxCache", 0);
CONFIG_REQUIRE("federation", JSON_BOOLEAN);
if (JsonValueAsBoolean(value))
{ {
tConfig->flags |= CONFIG_FEDERATION; tConfig->log.timestampFormat = StrDuplicate("default");
} }
for (i = 0; i < ArraySize(tConfig->listen); i++)
CONFIG_REQUIRE("registration", JSON_BOOLEAN);
if (JsonValueAsBoolean(value))
{ {
tConfig->flags |= CONFIG_REGISTRATION; ConfigListener *listener = ArrayGet(tConfig->listen, i);
if (Int64Eq(listener->maxConnections, Int64Create(0, 0)))
{
listener->maxConnections = Int64Create(0, 32);
}
if (Int64Eq(listener->threads, Int64Create(0, 0)))
{
listener->threads = Int64Create(0, 4);
}
if (Int64Eq(listener->port, Int64Create(0, 0)))
{
listener->port = Int64Create(0, 8008);
}
} }
CONFIG_REQUIRE("log", JSON_OBJECT);
if (!ConfigParseLog(tConfig, JsonValueAsObject(value)))
{
goto error;
}
tConfig->ok = 1; tConfig->ok = 1;
tConfig->err = NULL; tConfig->err = NULL;
return tConfig; return tConfig;
@ -435,41 +117,7 @@ ConfigCreateDefault(Db * db)
HashMap *json; HashMap *json;
Array *listeners; Array *listeners;
HashMap *listen; HashMap *listen;
return 0;
char hostname[HOST_NAME_MAX + 1];
if (!db)
{
return 0;
}
ref = DbCreate(db, 1, "config");
if (!ref)
{
return 0;
}
json = DbJson(ref);
JsonSet(json, JsonValueString("file"), 2, "log", "output");
listeners = ArrayCreate();
listen = HashMapCreate();
HashMapSet(listen, "port", JsonValueInteger(Int64Create(0, 8008)));
HashMapSet(listen, "tls", JsonValueBoolean(0));
ArrayAdd(listeners, JsonValueObject(listen));
HashMapSet(json, "listen", JsonValueArray(listeners));
if (gethostname(hostname, HOST_NAME_MAX + 1) < 0)
{
strncpy(hostname, "localhost", HOST_NAME_MAX);
}
HashMapSet(json, "serverName", JsonValueString(hostname));
HashMapSet(json, "federation", JsonValueBoolean(1));
HashMapSet(json, "registration", JsonValueBoolean(0));
return DbUnlock(db, ref);
} }
Config * Config *
@ -493,6 +141,17 @@ ConfigLock(Db * db)
return config; return config;
} }
void
ConfigFullyFree(Config * config)
{
if (!config)
{
return;
}
ConfigFree(config);
Free(config);
}
int int
ConfigUnlock(Config * config) ConfigUnlock(Config * config)
{ {
@ -507,6 +166,6 @@ ConfigUnlock(Config * config)
db = config->db; db = config->db;
dbRef = config->ref; dbRef = config->ref;
ConfigFree(config); ConfigFullyFree(config);
return DbUnlock(db, dbRef); return DbUnlock(db, dbRef);
} }

View file

@ -277,17 +277,18 @@ start:
goto finish; goto finish;
} }
if (!tConfig->logTimestamp || !StrEquals(tConfig->logTimestamp, "default")) if (!tConfig->log.timestampFormat || !StrEquals(tConfig->log.timestampFormat, "default"))
{ {
LogConfigTimeStampFormatSet(LogConfigGlobal(), tConfig->logTimestamp); LogConfigTimeStampFormatSet(LogConfigGlobal(), tConfig->log.timestampFormat);
} }
else else
{ {
Free(tConfig->logTimestamp); /* TODO */
tConfig->logTimestamp = NULL; /*Free(tConfig->logTimestamp);
tConfig->logTimestamp = NULL;*/
} }
if (tConfig->flags & CONFIG_LOG_COLOR) if (tConfig->log.color)
{ {
LogConfigFlagSet(LogConfigGlobal(), LOG_FLAG_COLOR); LogConfigFlagSet(LogConfigGlobal(), LOG_FLAG_COLOR);
} }
@ -296,9 +297,10 @@ start:
LogConfigFlagClear(LogConfigGlobal(), LOG_FLAG_COLOR); LogConfigFlagClear(LogConfigGlobal(), LOG_FLAG_COLOR);
} }
LogConfigLevelSet(LogConfigGlobal(), flags & ARG_VERBOSE ? LOG_DEBUG : tConfig->logLevel); /* TODO: Set level properly here. */
/*LogConfigLevelSet(LogConfigGlobal(), flags & ARG_VERBOSE ? LOG_DEBUG : tConfig->logLevel);*/
if (tConfig->flags & CONFIG_LOG_FILE) if (tConfig->log.output == CONFIG_LOG_OUTPUT_FILE)
{ {
logFile = StreamOpen("telodendria.log", "a"); logFile = StreamOpen("telodendria.log", "a");
@ -306,18 +308,14 @@ start:
{ {
Log(LOG_ERR, "Unable to open log file for appending."); Log(LOG_ERR, "Unable to open log file for appending.");
exit = EXIT_FAILURE; exit = EXIT_FAILURE;
tConfig->flags &= CONFIG_LOG_STDOUT; /*tConfig->flags &= CONFIG_LOG_STDOUT;*/
goto finish; goto finish;
} }
Log(LOG_INFO, "Logging to the log file. Check there for all future messages."); Log(LOG_INFO, "Logging to the log file. Check there for all future messages.");
LogConfigOutputSet(LogConfigGlobal(), logFile); LogConfigOutputSet(LogConfigGlobal(), logFile);
} }
else if (tConfig->flags & CONFIG_LOG_STDOUT) else if (tConfig->log.output == CONFIG_LOG_OUTPUT_SYSLOG)
{
Log(LOG_DEBUG, "Already logging to standard output.");
}
else if (tConfig->flags & CONFIG_LOG_SYSLOG)
{ {
Log(LOG_INFO, "Logging to the syslog. Check there for all future messages."); Log(LOG_INFO, "Logging to the syslog. Check there for all future messages.");
LogConfigFlagSet(LogConfigGlobal(), LOG_FLAG_SYSLOG); LogConfigFlagSet(LogConfigGlobal(), LOG_FLAG_SYSLOG);
@ -327,13 +325,6 @@ start:
* messages get passed to the syslog */ * messages get passed to the syslog */
setlogmask(LOG_UPTO(LOG_DEBUG)); setlogmask(LOG_UPTO(LOG_DEBUG));
} }
else
{
Log(LOG_ERR, "Unknown logging method in flags: '%d'", tConfig->flags);
Log(LOG_ERR, "This is a programmer error; please report it.");
exit = EXIT_FAILURE;
goto finish;
}
/* If a token was created with a default config, print it to the /* If a token was created with a default config, print it to the
* log */ * log */
@ -348,9 +339,9 @@ start:
Log(LOG_DEBUG, "Server Name: %s", tConfig->serverName); Log(LOG_DEBUG, "Server Name: %s", tConfig->serverName);
Log(LOG_DEBUG, "Base URL: %s", tConfig->baseUrl); Log(LOG_DEBUG, "Base URL: %s", tConfig->baseUrl);
Log(LOG_DEBUG, "Identity Server: %s", tConfig->identityServer); Log(LOG_DEBUG, "Identity Server: %s", tConfig->identityServer);
Log(LOG_DEBUG, "Run As: %s:%s", tConfig->uid, tConfig->gid); Log(LOG_DEBUG, "Run As: %s:%s", tConfig->runAs.uid, tConfig->runAs.gid);
Log(LOG_DEBUG, "Max Cache: %ld", tConfig->maxCache); Log(LOG_DEBUG, "Max Cache: %ld", tConfig->maxCache);
Log(LOG_DEBUG, "Flags: %x", tConfig->flags); /*Log(LOG_DEBUG, "Flags: %x", tConfig->flags);*/
LogConfigUnindent(LogConfigGlobal()); LogConfigUnindent(LogConfigGlobal());
httpServers = ArrayCreate(); httpServers = ArrayCreate();
@ -362,41 +353,50 @@ start:
} }
/* Bind servers before possibly dropping permissions. */ /* Bind servers before possibly dropping permissions. */
for (i = 0; i < ArraySize(tConfig->servers); i++) for (i = 0; i < ArraySize(tConfig->listen); i++)
{ {
HttpServerConfig *serverCfg = ArrayGet(tConfig->servers, i); ConfigListener *serverCfg = ArrayGet(tConfig->listen, i);
/* TODO: Think of a nicer solution. */
HttpServerConfig args;
Log(LOG_DEBUG, "HTTP listener: %lu", i); Log(LOG_DEBUG, "HTTP listener: %lu", i);
LogConfigIndent(LogConfigGlobal()); LogConfigIndent(LogConfigGlobal());
Log(LOG_DEBUG, "Port: %hu", serverCfg->port); Log(LOG_DEBUG, "Port: %hu", serverCfg->port);
Log(LOG_DEBUG, "Threads: %u", serverCfg->threads); Log(LOG_DEBUG, "Threads: %u", serverCfg->threads);
Log(LOG_DEBUG, "Max Connections: %u", serverCfg->maxConnections); Log(LOG_DEBUG, "Max Connections: %u", serverCfg->maxConnections);
Log(LOG_DEBUG, "Flags: %d", serverCfg->flags); /*Log(LOG_DEBUG, "Flags: %d", serverCfg->flags);*/
Log(LOG_DEBUG, "TLS Cert: %s", serverCfg->tlsCert); Log(LOG_DEBUG, "TLS Cert: %s", serverCfg->tls.cert);
Log(LOG_DEBUG, "TLS Key: %s", serverCfg->tlsKey); Log(LOG_DEBUG, "TLS Key: %s", serverCfg->tls.key);
LogConfigUnindent(LogConfigGlobal()); LogConfigUnindent(LogConfigGlobal());
serverCfg->handler = MatrixHttpHandler; args.port = serverCfg->port;
serverCfg->handlerArgs = &matrixArgs; args.threads = serverCfg->maxConnections;
args.maxConnections = serverCfg->maxConnections;
args.tlsCert = serverCfg->tls.cert;
args.tlsKey = serverCfg->tls.key;
if (serverCfg->flags & HTTP_FLAG_TLS) args.handler = MatrixHttpHandler;
args.handlerArgs = &matrixArgs;
if (serverCfg->tls.cert && serverCfg->tls.key)
{ {
if (UInt64Eq(UtilLastModified(serverCfg->tlsCert), UInt64Create(0, 0))) if (UInt64Eq(UtilLastModified(serverCfg->tls.cert), UInt64Create(0, 0)))
{ {
Log(LOG_ERR, "%s: %s", strerror(errno), serverCfg->tlsCert); Log(LOG_ERR, "%s: %s", strerror(errno), serverCfg->tls.cert);
exit = EXIT_FAILURE; exit = EXIT_FAILURE;
goto finish; goto finish;
} }
if (UInt64Eq(UtilLastModified(serverCfg->tlsKey), UInt64Create(0, 0))) if (UInt64Eq(UtilLastModified(serverCfg->tls.key), UInt64Create(0, 0)))
{ {
Log(LOG_ERR, "%s: %s", strerror(errno), serverCfg->tlsKey); Log(LOG_ERR, "%s: %s", strerror(errno), serverCfg->tls.key);
exit = EXIT_FAILURE; exit = EXIT_FAILURE;
goto finish; goto finish;
} }
} }
server = HttpServerCreate(serverCfg); server = HttpServerCreate(&args);
if (!server) if (!server)
{ {
Log(LOG_ERR, "Unable to create HTTP server on port %d: %s", Log(LOG_ERR, "Unable to create HTTP server on port %d: %s",
@ -417,10 +417,10 @@ start:
Log(LOG_DEBUG, "Running as uid:gid: %d:%d.", getuid(), getgid()); Log(LOG_DEBUG, "Running as uid:gid: %d:%d.", getuid(), getgid());
if (tConfig->uid && tConfig->gid) if (tConfig->runAs.uid && tConfig->runAs.gid)
{ {
userInfo = getpwnam(tConfig->uid); userInfo = getpwnam(tConfig->runAs.uid);
groupInfo = getgrnam(tConfig->gid); groupInfo = getgrnam(tConfig->runAs.gid);
if (!userInfo || !groupInfo) if (!userInfo || !groupInfo)
{ {
@ -450,7 +450,7 @@ start:
} }
else else
{ {
Log(LOG_DEBUG, "Set uid/gid to %s:%s.", tConfig->uid, tConfig->gid); Log(LOG_DEBUG, "Set uid/gid to %s:%s.", tConfig->runAs.uid, tConfig->runAs.gid);
} }
} }
else else
@ -462,7 +462,7 @@ start:
} }
else else
{ {
if (tConfig->uid && tConfig->gid) if (tConfig->runAs.uid && tConfig->runAs.gid)
{ {
if (getuid() != userInfo->pw_uid || getgid() != groupInfo->gr_gid) if (getuid() != userInfo->pw_uid || getgid() != groupInfo->gr_gid)
{ {

View file

@ -118,7 +118,7 @@ ROUTE_IMPL(RouteConfig, path, argp)
response = MatrixErrorCreate(M_BAD_JSON, newConf->err); response = MatrixErrorCreate(M_BAD_JSON, newConf->err);
} }
ConfigFree(newConf); ConfigFullyFree(newConf);
JsonFree(request); JsonFree(request);
break; break;
case HTTP_PUT: case HTTP_PUT:
@ -165,7 +165,7 @@ ROUTE_IMPL(RouteConfig, path, argp)
response = MatrixErrorCreate(M_BAD_JSON, newConf->err); response = MatrixErrorCreate(M_BAD_JSON, newConf->err);
} }
ConfigFree(newConf); ConfigFullyFree(newConf);
JsonFree(request); JsonFree(request);
JsonFree(newJson); JsonFree(newJson);
break; break;

View file

@ -134,7 +134,7 @@ ROUTE_IMPL(RouteRegister, path, argp)
uiaFlows = ArrayCreate(); uiaFlows = ArrayCreate();
ArrayAdd(uiaFlows, RouteRegisterRegFlow()); ArrayAdd(uiaFlows, RouteRegisterRegFlow());
if (config->flags & CONFIG_REGISTRATION) if (config->registration)
{ {
ArrayAdd(uiaFlows, UiaDummyFlow()); ArrayAdd(uiaFlows, UiaDummyFlow());
} }

View file

@ -48,68 +48,12 @@
* .Xr telodendria-config 7 . * .Xr telodendria-config 7 .
*/ */
#include <Schema/Config.h>
#include <Cytoplasm/HashMap.h> #include <Cytoplasm/HashMap.h>
#include <Cytoplasm/Array.h> #include <Cytoplasm/Array.h>
#include <Cytoplasm/Db.h> #include <Cytoplasm/Db.h>
/**
* Bit flags that can be set in the flags field of the configuration
* structure.
*/
typedef enum ConfigFlag
{
CONFIG_FEDERATION = (1 << 0),
CONFIG_REGISTRATION = (1 << 1),
CONFIG_LOG_COLOR = (1 << 2),
CONFIG_LOG_FILE = (1 << 3),
CONFIG_LOG_STDOUT = (1 << 4),
CONFIG_LOG_SYSLOG = (1 << 5)
} ConfigFlag;
/**
* The configuration structure is not opaque like many of the other
* structures present in the other public APIs. This is intentional;
* defining functions for all of the fields would simply add too much
* unnecessary overhead.
*/
typedef struct Config
{
/*
* These are used internally and should not be touched outside of
* the functions defined in this API.
*/
Db *db;
DbRef *ref;
/*
* Whether or not the parsing was successful. If this boolean
* value is 0, then read the error message and assume that all
* other fields are invalid.
*/
int ok;
char *err;
char *serverName;
char *baseUrl;
char *identityServer;
char *uid;
char *gid;
unsigned int flags;
size_t maxCache;
char *logTimestamp;
int logLevel;
/*
* An array of HttpServerConfig structures. Consult the HttpServer
* API.
*/
Array *servers;
} Config;
/** /**
* Parse a JSON object, extracting the necessary values, validating * Parse a JSON object, extracting the necessary values, validating
* them, and adding them to the configuration structure for use by the * them, and adding them to the configuration structure for use by the
@ -127,7 +71,7 @@ extern Config * ConfigParse(HashMap *);
* as well as the structure itself, such that it is completely invalid * as well as the structure itself, such that it is completely invalid
* when this function returns. * when this function returns.
*/ */
extern void ConfigFree(Config *); extern void ConfigFullyFree(Config *);
/** /**
* Check whether or not the configuration exists in the database, * Check whether or not the configuration exists in the database,