forked from Telodendria/Telodendria
Compare commits
2 commits
18488d463e
...
fbc4486930
Author | SHA1 | Date | |
---|---|---|---|
fbc4486930 | |||
74ab3f350f |
6 changed files with 177 additions and 481 deletions
93
Schema/Config.json
Normal file
93
Schema/Config.json
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
417
src/Config.c
417
src/Config.c
|
@ -21,7 +21,7 @@
|
|||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include <Config.h>
|
||||
#include <Schema/Config.h>
|
||||
#include <Cytoplasm/Memory.h>
|
||||
#include <Cytoplasm/Json.h>
|
||||
#include <Cytoplasm/HashMap.h>
|
||||
|
@ -41,378 +41,60 @@
|
|||
#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
|
||||
#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 *
|
||||
ConfigParse(HashMap * config)
|
||||
{
|
||||
Config *tConfig;
|
||||
JsonValue *value;
|
||||
|
||||
size_t i;
|
||||
|
||||
if (!config)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tConfig = Malloc(sizeof(Config));
|
||||
if (!tConfig)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(tConfig, 0, sizeof(Config));
|
||||
|
||||
CONFIG_REQUIRE("listen", JSON_ARRAY);
|
||||
if (!ConfigParseListen(tConfig, JsonValueAsArray(value)))
|
||||
tConfig->maxCache = Int64Create(0, 0);
|
||||
|
||||
if (!ConfigFromJson(config, tConfig, &tConfig->err))
|
||||
{
|
||||
ConfigFree(tConfig);
|
||||
goto error;
|
||||
}
|
||||
|
||||
CONFIG_REQUIRE("serverName", JSON_STRING);
|
||||
CONFIG_COPY_STRING(tConfig->serverName);
|
||||
|
||||
value = HashMapGet(config, "baseUrl");
|
||||
if (value)
|
||||
{
|
||||
CONFIG_COPY_STRING(tConfig->baseUrl);
|
||||
}
|
||||
else
|
||||
if (!tConfig->baseUrl)
|
||||
{
|
||||
size_t len = strlen(tConfig->serverName) + 10;
|
||||
|
||||
tConfig->baseUrl = Malloc(len);
|
||||
if (!tConfig->baseUrl)
|
||||
{
|
||||
tConfig->err = "Error allocating memory for default config value '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'.";
|
||||
tConfig->err = "Couldn't allocate enough memory for 'baseUrl'.";
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
CONFIG_OPTIONAL_INTEGER(tConfig->maxCache, "maxCache", 0);
|
||||
|
||||
CONFIG_REQUIRE("federation", JSON_BOOLEAN);
|
||||
if (JsonValueAsBoolean(value))
|
||||
if (!tConfig->log.timestampFormat)
|
||||
{
|
||||
tConfig->flags |= CONFIG_FEDERATION;
|
||||
tConfig->log.timestampFormat = StrDuplicate("default");
|
||||
}
|
||||
|
||||
CONFIG_REQUIRE("registration", JSON_BOOLEAN);
|
||||
if (JsonValueAsBoolean(value))
|
||||
for (i = 0; i < ArraySize(tConfig->listen); i++)
|
||||
{
|
||||
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->err = NULL;
|
||||
return tConfig;
|
||||
|
@ -435,41 +117,7 @@ ConfigCreateDefault(Db * db)
|
|||
HashMap *json;
|
||||
Array *listeners;
|
||||
HashMap *listen;
|
||||
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Config *
|
||||
|
@ -493,6 +141,17 @@ ConfigLock(Db * db)
|
|||
return config;
|
||||
}
|
||||
|
||||
void
|
||||
ConfigFullyFree(Config * config)
|
||||
{
|
||||
if (!config)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ConfigFree(config);
|
||||
Free(config);
|
||||
}
|
||||
int
|
||||
ConfigUnlock(Config * config)
|
||||
{
|
||||
|
@ -507,6 +166,6 @@ ConfigUnlock(Config * config)
|
|||
db = config->db;
|
||||
dbRef = config->ref;
|
||||
|
||||
ConfigFree(config);
|
||||
ConfigFullyFree(config);
|
||||
return DbUnlock(db, dbRef);
|
||||
}
|
||||
|
|
80
src/Main.c
80
src/Main.c
|
@ -277,17 +277,18 @@ start:
|
|||
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
|
||||
{
|
||||
Free(tConfig->logTimestamp);
|
||||
tConfig->logTimestamp = NULL;
|
||||
/* TODO */
|
||||
/*Free(tConfig->logTimestamp);
|
||||
tConfig->logTimestamp = NULL;*/
|
||||
}
|
||||
|
||||
if (tConfig->flags & CONFIG_LOG_COLOR)
|
||||
if (tConfig->log.color)
|
||||
{
|
||||
LogConfigFlagSet(LogConfigGlobal(), LOG_FLAG_COLOR);
|
||||
}
|
||||
|
@ -296,9 +297,10 @@ start:
|
|||
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");
|
||||
|
||||
|
@ -306,18 +308,14 @@ start:
|
|||
{
|
||||
Log(LOG_ERR, "Unable to open log file for appending.");
|
||||
exit = EXIT_FAILURE;
|
||||
tConfig->flags &= CONFIG_LOG_STDOUT;
|
||||
/*tConfig->flags &= CONFIG_LOG_STDOUT;*/
|
||||
goto finish;
|
||||
}
|
||||
|
||||
Log(LOG_INFO, "Logging to the log file. Check there for all future messages.");
|
||||
LogConfigOutputSet(LogConfigGlobal(), logFile);
|
||||
}
|
||||
else if (tConfig->flags & CONFIG_LOG_STDOUT)
|
||||
{
|
||||
Log(LOG_DEBUG, "Already logging to standard output.");
|
||||
}
|
||||
else if (tConfig->flags & CONFIG_LOG_SYSLOG)
|
||||
else if (tConfig->log.output == CONFIG_LOG_OUTPUT_SYSLOG)
|
||||
{
|
||||
Log(LOG_INFO, "Logging to the syslog. Check there for all future messages.");
|
||||
LogConfigFlagSet(LogConfigGlobal(), LOG_FLAG_SYSLOG);
|
||||
|
@ -327,13 +325,6 @@ start:
|
|||
* messages get passed to the syslog */
|
||||
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
|
||||
* log */
|
||||
|
@ -348,9 +339,9 @@ start:
|
|||
Log(LOG_DEBUG, "Server Name: %s", tConfig->serverName);
|
||||
Log(LOG_DEBUG, "Base URL: %s", tConfig->baseUrl);
|
||||
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, "Flags: %x", tConfig->flags);
|
||||
/*Log(LOG_DEBUG, "Flags: %x", tConfig->flags);*/
|
||||
LogConfigUnindent(LogConfigGlobal());
|
||||
|
||||
httpServers = ArrayCreate();
|
||||
|
@ -362,41 +353,50 @@ start:
|
|||
}
|
||||
|
||||
/* 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);
|
||||
LogConfigIndent(LogConfigGlobal());
|
||||
Log(LOG_DEBUG, "Port: %hu", serverCfg->port);
|
||||
Log(LOG_DEBUG, "Threads: %u", serverCfg->threads);
|
||||
Log(LOG_DEBUG, "Max Connections: %u", serverCfg->maxConnections);
|
||||
Log(LOG_DEBUG, "Flags: %d", serverCfg->flags);
|
||||
Log(LOG_DEBUG, "TLS Cert: %s", serverCfg->tlsCert);
|
||||
Log(LOG_DEBUG, "TLS Key: %s", serverCfg->tlsKey);
|
||||
/*Log(LOG_DEBUG, "Flags: %d", serverCfg->flags);*/
|
||||
Log(LOG_DEBUG, "TLS Cert: %s", serverCfg->tls.cert);
|
||||
Log(LOG_DEBUG, "TLS Key: %s", serverCfg->tls.key);
|
||||
LogConfigUnindent(LogConfigGlobal());
|
||||
|
||||
serverCfg->handler = MatrixHttpHandler;
|
||||
serverCfg->handlerArgs = &matrixArgs;
|
||||
args.port = serverCfg->port;
|
||||
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;
|
||||
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;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
server = HttpServerCreate(serverCfg);
|
||||
server = HttpServerCreate(&args);
|
||||
if (!server)
|
||||
{
|
||||
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());
|
||||
|
||||
if (tConfig->uid && tConfig->gid)
|
||||
if (tConfig->runAs.uid && tConfig->runAs.gid)
|
||||
{
|
||||
userInfo = getpwnam(tConfig->uid);
|
||||
groupInfo = getgrnam(tConfig->gid);
|
||||
userInfo = getpwnam(tConfig->runAs.uid);
|
||||
groupInfo = getgrnam(tConfig->runAs.gid);
|
||||
|
||||
if (!userInfo || !groupInfo)
|
||||
{
|
||||
|
@ -450,7 +450,7 @@ start:
|
|||
}
|
||||
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
|
||||
|
@ -462,7 +462,7 @@ start:
|
|||
}
|
||||
else
|
||||
{
|
||||
if (tConfig->uid && tConfig->gid)
|
||||
if (tConfig->runAs.uid && tConfig->runAs.gid)
|
||||
{
|
||||
if (getuid() != userInfo->pw_uid || getgid() != groupInfo->gr_gid)
|
||||
{
|
||||
|
|
|
@ -118,7 +118,7 @@ ROUTE_IMPL(RouteConfig, path, argp)
|
|||
response = MatrixErrorCreate(M_BAD_JSON, newConf->err);
|
||||
}
|
||||
|
||||
ConfigFree(newConf);
|
||||
ConfigFullyFree(newConf);
|
||||
JsonFree(request);
|
||||
break;
|
||||
case HTTP_PUT:
|
||||
|
@ -165,7 +165,7 @@ ROUTE_IMPL(RouteConfig, path, argp)
|
|||
response = MatrixErrorCreate(M_BAD_JSON, newConf->err);
|
||||
}
|
||||
|
||||
ConfigFree(newConf);
|
||||
ConfigFullyFree(newConf);
|
||||
JsonFree(request);
|
||||
JsonFree(newJson);
|
||||
break;
|
||||
|
|
|
@ -134,7 +134,7 @@ ROUTE_IMPL(RouteRegister, path, argp)
|
|||
uiaFlows = ArrayCreate();
|
||||
ArrayAdd(uiaFlows, RouteRegisterRegFlow());
|
||||
|
||||
if (config->flags & CONFIG_REGISTRATION)
|
||||
if (config->registration)
|
||||
{
|
||||
ArrayAdd(uiaFlows, UiaDummyFlow());
|
||||
}
|
||||
|
|
|
@ -48,68 +48,12 @@
|
|||
* .Xr telodendria-config 7 .
|
||||
*/
|
||||
|
||||
#include <Schema/Config.h>
|
||||
|
||||
#include <Cytoplasm/HashMap.h>
|
||||
#include <Cytoplasm/Array.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
|
||||
* 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
|
||||
* when this function returns.
|
||||
*/
|
||||
extern void ConfigFree(Config *);
|
||||
extern void ConfigFullyFree(Config *);
|
||||
|
||||
/**
|
||||
* Check whether or not the configuration exists in the database,
|
||||
|
|
Loading…
Reference in a new issue