1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-07-10 05:43:12 +02:00

Fixed return values/checks for helper functions/macros, return empty string instead of NULL when reading zero length strings, discard tkl->subtype and store spamf as a char instead of unsigned int, remove rewriting after DB read, also renamed TKLines/TKLs/etc to *-Lines for uniformity with other code

This commit is contained in:
GottemHams
2019-06-03 20:45:56 +02:00
parent bb91ac1c56
commit 52b39acf78
+76 -64
View File
@@ -1,5 +1,5 @@
/*
* Stores active TKLines (G:Lines etc) inside a .db file for persistency
* Stores active *-Lines (G:Lines etc) inside a .db file for persistency
* (C) Copyright 2019 Gottem and the UnrealIRCd team
*
* This program is free software; you can redistribute it and/or modify
@@ -44,8 +44,8 @@
#define R_SAFE(x) \
do { \
if (!(x)) { \
close(fd); \
config_warn("[tkldb] Read error from the persistent storage file '%s' (possible corruption): %s", cfg.database, strerror(errno)); \
close(fd); \
FreeTKLRead(); \
return 0; \
} \
@@ -54,8 +54,8 @@
#define W_SAFE(x) \
do { \
if (!(x)) { \
close(fd); \
config_warn("[tkldb] Write error from the persistent storage tempfile '%s': %s (DATABASE NOT SAVED)", tmpfname, strerror(errno)); \
close(fd); \
return 0; \
} \
} while(0)
@@ -88,17 +88,17 @@ static ModDataInfo *tkldb_md;
static unsigned tkl_db_version = TKL_DB_VERSION;
struct cfgstruct {
char *database;
// Stored .db might still work with flags instead of actual values (will be corrected on next write)
// This backport stuff will eventually be removed ;]
unsigned backport_tkl1000;
};
static struct cfgstruct cfg;
// Stored .db might still work with flags instead of actual values (will be corrected on next write)
// This backport stuff will eventually be removed ;]
unsigned backport_tkl1000;
ModuleHeader MOD_HEADER(tkldb) = {
"tkldb",
"v1.10",
"Stores active TKL entries persistently/across IRCd restarts",
"Stores active TKL entries (*-Lines) persistently/across IRCd restarts",
"3.2-b8-1",
NULL
};
@@ -114,7 +114,7 @@ MOD_INIT(tkldb)
{
MARK_AS_OFFICIAL_MODULE(modinfo);
// MOD_INIT is also called on rehash, so we gotta make sure to not re-add TKLines every time
// MOD_INIT is also called on rehash, so we gotta make sure to not re-add *-Lines every time
// There might be a cleaner way to do this though (i.e. without moddata) :D
setcfg();
if (!(tkldb_md = findmoddata_byname("tkldb_inited", MODDATATYPE_CLIENT)))
@@ -166,6 +166,7 @@ void setcfg(void)
// Default: data/tkl.db
cfg.database = strdup("tkl.db");
convert_to_absolute_path(&cfg.database, PERMDATADIR);
cfg.backport_tkl1000 = 0;
}
void freecfg(void)
@@ -234,7 +235,6 @@ int write_tkldb(void)
int fd;
uint64_t tklcount;
int index, index2;
int err;
aTKline *tkl;
// Write to a tempfile first, then rename it if everything succeeded
@@ -248,7 +248,7 @@ int write_tkldb(void)
W_SAFE(write_data(fd, &tkl_db_version, sizeof(tkl_db_version)));
// Count the tkl's
// Count the *-Lines
tklcount = 0;
// First the ones in the hash table
@@ -260,7 +260,7 @@ int write_tkldb(void)
tklcount++;
}
}
// Then the regular tkl's
// Then the regular *-Lines
for (index = 0; index < TKLISTLEN; index++)
{
for (tkl = tklines[index]; tkl; tkl = tkl->next)
@@ -273,33 +273,36 @@ int write_tkldb(void)
}
W_SAFE(write_data(fd, &tklcount, sizeof(tklcount)));
// Now write the actual tkl's
err = 0;
// First the ones in the hash table
for (index = 0; !err && index < TKLIPHASHLEN1; index++)
// Now write the actual *-Lines, first the ones in the hash table
for (index = 0; index < TKLIPHASHLEN1; index++)
{
for (index2 = 0; !err && index2 < TKLIPHASHLEN2; index2++)
for (index2 = 0; index2 < TKLIPHASHLEN2; index2++)
{
for (tkl = tklines_ip_hash[index][index2]; !err && tkl; tkl = tkl->next)
err = write_tkline(fd, tmpfname, tkl);
for (tkl = tklines_ip_hash[index][index2]; tkl; tkl = tkl->next) {
if(!write_tkline(fd, tmpfname, tkl)) // write_tkline() closes the fd on errors itself
return 0;
}
}
}
// Then the regular tkl's
for (index = 0; !err && index < TKLISTLEN; index++)
// Then the regular *-Lines
for (index = 0; index < TKLISTLEN; index++)
{
for (tkl = tklines[index]; !err && tkl; tkl = tkl->next)
for (tkl = tklines[index]; tkl; tkl = tkl->next)
{
// Local spamfilter means it was added through the conf or is built-in, so let's not even write those
if ((tkl->type & TKL_SPAMF) && !(tkl->type & TKL_GLOBAL)) // Also need to skip this here
continue;
err = write_tkline(fd, tmpfname, tkl);
if(!write_tkline(fd, tmpfname, tkl))
return 0;
}
}
if (err != 0)
return 0;
// Everything seems to have gone well, attempt to rename the tempfile
close(fd);
// Everything seems to have gone well, attempt to close and rename the tempfile
if(close(fd) < 0)
{
config_warn("[tkldb] Got an error when trying to close the persistent storage file '%s' (possible corruption occurred, DATABASE NOT SAVED): %s", cfg.database, strerror(errno));
return 0;
}
if (rename(tmpfname, cfg.database) < 0)
{
config_warn("[tkldb] Error renaming '%s' to '%s': %s (DATABASE NOT SAVED)", tmpfname, cfg.database, strerror(errno));
@@ -314,12 +317,12 @@ int write_tkline(int fd, const char *tmpfname, aTKline *tkl)
// These will be used to reconstruct the proper internal m_tkl() call ;]
char tkltype[2];
char usermask_subtype[256]; // Might need to prefix something to usermask
char spamf_action; // Storing the action not as unsigned short, but as char is more reliable for the future
uint64_t expire_at, set_at, spamf_tkl_duration; // To prevent 32 vs 64 bit incompatibilies regarding the TS data type(def)
tkltype[0] = tkl_typetochar(tkl->type);
tkltype[1] = '\0';
W_SAFE(write_str(fd, tkltype)); // TKL char
W_SAFE(write_data(fd, &tkl->subtype, sizeof(tkl->subtype))); // Unsigned short (only used for spamfilters/softbans but set to 0 for everything else regardless)
// Might be a softban
if (!tkl->ptr.spamf && (tkl->subtype & TKL_SUBTYPE_SOFT))
@@ -343,9 +346,9 @@ int write_tkline(int fd, const char *tmpfname, aTKline *tkl)
if (tkl->ptr.spamf)
{
W_SAFE(write_str(fd, "SPAMF")); // Write a string so we know to expect more when reading the DB
W_SAFE(write_data(fd, &tkl->ptr.spamf->action, sizeof(tkl->ptr.spamf->action))); // Unsigned short (block, GZ:Line, etc; also refer to BAN_ACT_*)
spamf_action = banact_valtochar(tkl->ptr.spamf->action); // Block, GZ:Line, etc; also refer to BAN_ACT_*
W_SAFE(write_data(fd, &spamf_action, sizeof(spamf_action)));
W_SAFE(write_str(fd, tkl->ptr.spamf->tkl_reason));
spamf_tkl_duration = tkl->ptr.spamf->tkl_duration;
W_SAFE(write_data(fd, &spamf_tkl_duration, sizeof(spamf_tkl_duration)));
W_SAFE(write_str(fd, tkl->ptr.spamf->expr->str)); // Actual expression/regex/etc
@@ -368,11 +371,12 @@ int read_tkldb(void)
uint64_t i;
uint64_t tklcount = 0;
size_t tklcount_tkl1000 = 0;
uint64_t num = 0;
uint64_t rewrite = 0;
uint64_t added = 0;
uint64_t skipped = 0;
unsigned version;
// Variables for all TKL types
// Some of them need to be declared and NULL initialised early due to the macro FreeTKLRead() being used by R_SAFE() on error
char *tkltype = NULL;
char *usermask = NULL;
char *hostmask = NULL;
@@ -383,8 +387,8 @@ int read_tkldb(void)
char *spamf_check = NULL;
char *spamf_matchtype = NULL;
ircd_log(LOG_ERROR, "[tkldb] Reading stored X:Lines from '%s'", cfg.database);
sendto_realops("[tkldb] Reading stored X:Lines from '%s'", cfg.database); // Probably won't be seen ever, but just in case ;]
ircd_log(LOG_ERROR, "[tkldb] Reading stored *-Lines from '%s'", cfg.database);
sendto_realops("[tkldb] Reading stored *-Lines from '%s'", cfg.database); // Probably won't be seen ever, but just in case ;]
OpenFile(fd, cfg.database, O_RDONLY);
if (fd < 0)
{
@@ -404,12 +408,13 @@ int read_tkldb(void)
{
// Older DBs should still work with newer versions of this module
config_warn("[tkldb] Database '%s' has a wrong version: expected it to be <= %u but got %u instead", cfg.database, tkl_db_version, version);
close(fd);
if(close(fd) < 0)
config_warn("[tkldb] Got an error when trying to close the persistent storage file '%s' (possible corruption occurred): %s", cfg.database, strerror(errno));
return 0;
}
backport_tkl1000 = (version <= 1000 ? 1 : 0);
if (backport_tkl1000)
cfg.backport_tkl1000 = (version <= 1000 ? 1 : 0);
if (cfg.backport_tkl1000)
{
R_SAFE(read_data(fd, &tklcount_tkl1000, sizeof(tklcount_tkl1000)));
tklcount = tklcount_tkl1000;
@@ -438,7 +443,8 @@ int read_tkldb(void)
// Some stuff related to spamfilters
spamf_check = NULL;
int spamf = 0;
unsigned short spamf_action;
char spamf_action;
unsigned short spamf_actionval;
char *spamf_tkl_reason = NULL;
TS spamf_tkl_duration_tkl1000;
uint64_t spamf_tkl_duration;
@@ -465,26 +471,26 @@ int read_tkldb(void)
NULL, // 12: Some functions rely on the post-last entry being NULL =]
};
if (backport_tkl1000)
if (cfg.backport_tkl1000)
{
R_SAFE(read_data(fd, &type, sizeof(type)));
tklflag = tkl_typetochar(type);
tkltype = MyMallocEx(2);
tkltype[0] = tklflag;
tkltype[1] = '\0';
R_SAFE(read_data(fd, &subtype, sizeof(subtype))); // Subtype is kinda redundant so we're not using it past v1000 anymore
}
else {
R_SAFE(read_str(fd, &tkltype)); // No need for tkl_typetochar() on read anymore
tklflag = tkltype[0];
}
R_SAFE(read_data(fd, &subtype, sizeof(subtype)));
R_SAFE(read_str(fd, &usermask));
R_SAFE(read_str(fd, &hostmask));
R_SAFE(read_str(fd, &reason));
R_SAFE(read_str(fd, &setby));
if (backport_tkl1000)
if (cfg.backport_tkl1000)
{
R_SAFE(read_data(fd, &expire_at_tkl1000, sizeof(expire_at_tkl1000)));
R_SAFE(read_data(fd, &set_at_tkl1000, sizeof(set_at_tkl1000)));
@@ -500,10 +506,18 @@ int read_tkldb(void)
if (!strcmp(spamf_check, "SPAMF"))
{
spamf = 1;
R_SAFE(read_data(fd, &spamf_action, sizeof(spamf_action)));
if (cfg.backport_tkl1000)
{
R_SAFE(read_data(fd, &spamf_actionval, sizeof(spamf_actionval)));
} else {
R_SAFE(read_data(fd, &spamf_action, sizeof(spamf_action)));
spamf_actionval = banact_chartoval(spamf_action);
}
R_SAFE(read_str(fd, &spamf_tkl_reason));
if (backport_tkl1000)
if (cfg.backport_tkl1000)
{
R_SAFE(read_data(fd, &spamf_tkl_duration_tkl1000, sizeof(spamf_tkl_duration_tkl1000)));
spamf_tkl_duration = spamf_tkl_duration_tkl1000;
@@ -512,7 +526,7 @@ int read_tkldb(void)
}
R_SAFE(read_str(fd, &spamf_expr));
if (backport_tkl1000)
if (cfg.backport_tkl1000)
{
R_SAFE(read_data(fd, &matchtype, sizeof(matchtype)));
if (matchtype == MATCH_PCRE_REGEX)
@@ -535,7 +549,7 @@ int read_tkldb(void)
{
ircd_log(LOG_ERROR, "[tkldb] Not re-adding %c:Line '%s@%s' [%s] because it should be expired", tklflag, usermask, hostmask, reason);
sendto_realops("[tkldb] Not re-adding %c:Line '%s@%s' [%s] because it should be expired", tklflag, usermask, hostmask, reason); // Probably won't be seen ever, but just in case ;]
rewrite++;
skipped++;
FreeTKLRead();
continue;
}
@@ -595,25 +609,20 @@ int read_tkldb(void)
if (doadd)
{
m_tkl(&me, &me, NULL, parc, tkllayer);
num++;
added++;
}
FreeTKLRead();
}
close(fd);
if (num)
// No need to return from the function at this point, as all *-Lines have been successfully retrieved anyways =]
if(close(fd) < 0)
config_warn("[tkldb] Got an error when trying to close the persistent storage file '%s' (possible corruption occurred): %s", cfg.database, strerror(errno));
if (added || skipped)
{
ircd_log(LOG_ERROR, "[tkldb] Re-added %li X:Lines", num);
sendto_realops("[tkldb] Re-added %li X:Lines", num); // Probably won't be seen ever, but just in case ;]
ircd_log(LOG_ERROR, "[tkldb] Re-added %li and skipped %li *-Lines", added, skipped);
sendto_realops("[tkldb] Re-added %li and skipped %li *-Lines", added, skipped); // Probably won't be seen ever, but just in case ;]
}
if (rewrite)
{
ircd_log(LOG_ERROR, "[tkldb] Rewriting DB file due to %li skipped/expired X:Line%s", rewrite, (rewrite > 1 ? "s" : ""));
sendto_realops("[tkldb] Rewriting DB file due to %li skipped/expired X:Line%s", rewrite, (rewrite > 1 ? "s" : "")); // Probably won't be seen ever, but just in case ;]
return write_tkldb();
}
return 1;
}
@@ -634,11 +643,11 @@ static inline int write_data(int fd, void *buf, size_t len)
static int write_str(int fd, char *x)
{
uint64_t len = (x ? strlen(x) : 0);
if (write_data(fd, &len, sizeof(len)))
if (!write_data(fd, &len, sizeof(len)))
return 0;
if (len)
{
if (write_data(fd, x, len))
if (!write_data(fd, x, len))
return 0;
}
return 1;
@@ -647,12 +656,12 @@ static int write_str(int fd, char *x)
static int read_str(int fd, char **x)
{
uint64_t len;
size_t len_tkl1000; // len used to be of type size_t, but this has portability problems
size_t len_tkl1000; // len used to be of type size_t, but this has portability problems when writing to/reading from binary files
size_t size;
*x = NULL;
if (backport_tkl1000)
if (cfg.backport_tkl1000)
{
if (!read_data(fd, &len_tkl1000, sizeof(len_tkl1000)))
return 0;
@@ -664,16 +673,19 @@ static int read_str(int fd, char **x)
}
if (!len)
{
*x = strdup(""); // It's safer for m_tkl to work with empty strings instead of NULLs
return 1;
}
size = len;
*x = MyMallocEx(size + 1);
if (read_data(fd, *x, size))
if (!read_data(fd, *x, size))
{
MyFree(*x);
*x = NULL;
return 0;
}
(*x)[len] = 0;
return 0;
return 1;
}