From a16d9bdecb572bb266a84ec90767d613ce8ce255 Mon Sep 17 00:00:00 2001 From: Luke Bratch Date: Mon, 18 Jan 2021 21:51:00 +0000 Subject: Make the "channels" configuration file entry an array. --- TODO | 4 +--- blabouncer.c | 27 +++++++++++++++++++++------ blabouncer.conf.example | 9 ++++++--- config.c | 9 ++++++--- functions.c | 46 +++++++++++++++------------------------------- structures.h | 4 ++-- 6 files changed, 51 insertions(+), 48 deletions(-) diff --git a/TODO b/TODO index edf1fdb..8d04065 100644 --- a/TODO +++ b/TODO @@ -4,8 +4,6 @@ Configurable rotation of replay and debug logs. Configurable timestamp format in logs. -Add a make install/uninstall/etc., add an "INSTALL" file, include a dependency listing. - macOS compiler may need limits.h included in structures.h. "Starting log replay...." followed by "Unable to read replay log file!" even though replay seemed to work? @@ -16,6 +14,6 @@ Can memory usage be reduced further? (e.g. better channel struct management) Ability to load new certificate whilst running. -Make the "channels" configuration file entry an array. +JOINing a channel that is a substring of another channel breaks all sorts (e.g. both #blabouncer and #blabounce). Crash when requesting 30 hour replay. diff --git a/blabouncer.c b/blabouncer.c index 982d504..89add3e 100644 --- a/blabouncer.c +++ b/blabouncer.c @@ -1052,12 +1052,27 @@ int main(int argc, char *argv[]) { } // What, if anything, are the configured auto channels? - if (!getconfstr("channels", settings.conffile, settings.autochannels)) { - settings.autochannels[0] = '\0'; - } else { - // If something was set, make sure it's not too long - if (strlen(settings.autochannels) >= MAXAUTOCHANLEN) { - printf("main(): 'channels' option in configuration file is too long.\n"); + ret = getconfarr("channels", settings.conffile, settings.autochannels); + if (!ret) { + for (int i = 0; i < MAXCONFARR; i++) { + settings.autochannels[i][0] = '\0'; + } + } else if (ret == -1) { + // Remove any newlines from the middle of the string so error printing works nicely + for (size_t i = 0; i < strlen(settings.autochannels[0]) - 1; i++) { + if (settings.autochannels[0][i] == '\n') { + settings.autochannels[0][i] = ' '; + } + } + printf("main(): error getting 'autochannels' from configuration file: %s", settings.autochannels[0]); + exit(1); + } + + // Make sure channel/key pairs aren't too long (since getconfarr() has to use MAXDATASIZE for all string lengths) + for (int i = 0; i < MAXCONFARR; i++) { + // +1 for the space between channel name and keys + if (settings.autochannels[i][0] && strlen(settings.autochannels[i]) > MAXCHANLENGTH + 1 + MAXCHANKEYLEN) { + printf("main(): error: specified channel name/key pair '%s' is too long, maximum lengths are %d (name) and %d (key).\n", settings.autochannels[i], MAXCHANLENGTH, MAXCHANKEYLEN); exit(1); } } diff --git a/blabouncer.conf.example b/blabouncer.conf.example index 0513fdc..d77689c 100644 --- a/blabouncer.conf.example +++ b/blabouncer.conf.example @@ -32,9 +32,12 @@ nicks = { username = "bounceusr" realname = "Mr Bla Bouncer" -# Channels to automatically join (comma-separated list, defaults to none) -# Put channel keywords/passwords after channel names following a space. -#channels = "#blabouncer keyword,#test" +# Channels to automatically join (defaults to none) +# Put channel keys/passwords after channel names (separated with a space) +channels = { + "#blabouncer keyword" + "#test" +} # Auto replay mode upon a bouncer client connecting # "none" = Don't auto replay diff --git a/config.c b/config.c index 5b706b0..3fa28a7 100644 --- a/config.c +++ b/config.c @@ -344,9 +344,12 @@ int createconfigfile(char *filename) { "username = \"bounceusr\"\n" "realname = \"Mr Bla Bouncer\"\n" "\n" - "# Channels to automatically join (comma-separated list, defaults to none)\n" - "# Put channel keywords/passwords after channel names following a space.\n" - "#channels = \"#blabouncer keyword,#test\"\n" + "# Channels to automatically join (defaults to none)\n" + "# Put channel keys/passwords after channel names (separated with a space)\n" + "channels = {\n" + " \"#blabouncer keyword\"\n" + " \"#test\"\n" + "}\n" "\n" "# Auto replay mode upon a bouncer client connecting\n" "# \"none\" = Don't auto replay\n" diff --git a/functions.c b/functions.c index 5dd7586..6ed1d2f 100644 --- a/functions.c +++ b/functions.c @@ -1027,47 +1027,31 @@ int numclients(struct client *clients) { // joined in the configuration file. // Returns 1 on success or 0 on failure. int joinautochannels(SSL *server_ssl, struct client *clients, struct settings *settings) { - if (strlen(settings->autochannels) == 0) { + if (settings->autochannels[0][0] == '\0') { // None configured debugprint(DEBUG_FULL, "joinautochannels(): none configured.\n"); return 1; } - // Split string up into each channel - char tokens[MAXAUTOCHANLEN][MAXCHANLENGTH]; - int counter = 0; - - // Copy to a temporary string - char *strcopy = strdup(settings->autochannels); - // Keep track of initial pointer for free()ing later - char *strcopyPtr = strcopy; - - char *token; - - // Split on commas - while ((token = strsep(&strcopy, ",")) != NULL) { - if (*token == '\0') continue; // Skip consecutive matches - if (counter >= MAXAUTOCHANLEN) break; // Too many tokens - debugprint(DEBUG_FULL, " >> Auto channel: '%s', length '%ld'.\n", token, strlen(token)); - // Copy into the token array (strlen + 1 to get the NULL terminator) - strncpy(tokens[counter], token, strlen(token) + 1); - if (strlen(tokens[counter]) > MAXCHANLENGTH) { - printf("error: channel name '%s' from configuration file too long, max length is '%d'.\n", tokens[counter], MAXCHANLENGTH); - debugprint(DEBUG_CRIT, "error: channel name '%s' from configuration file too long, max length is '%d'.\n", tokens[counter], MAXCHANLENGTH); - exit(1); + // Join all the channels + for (int i = 0; i < MAXCONFARR; i++) { + // Unless there are none left in the array + if (settings->autochannels[i][0] == '\0') { + debugprint(DEBUG_FULL, "joinautochannels(): Finishing joining %d channels.\n", i); + return 1; } - counter++; - } - // Join all the channels - for (int i = 0; i < counter; i++) { - debugprint(DEBUG_FULL, "joinautochannels(): Joining '%s'.\n", tokens[i]); + debugprint(DEBUG_FULL, "joinautochannels(): Joining '%s'.\n", settings->autochannels[i]); char joinmsg[MAXDATASIZE]; - snprintf(joinmsg, MAXDATASIZE, "JOIN %s", tokens[i]); - sendtoserver(server_ssl, joinmsg, strlen(joinmsg), 0, clients, settings); + if (!snprintf(joinmsg, MAXDATASIZE, "JOIN %s", settings->autochannels[i])) { + fprintf(stderr, "joinautochannels(): Error while preparing JOIN message!\n"); + debugprint(DEBUG_CRIT, "joinautochannels(): Error while preparing JOIN message\n"); + joinmsg[0] = '\0'; + } else { + sendtoserver(server_ssl, joinmsg, strlen(joinmsg), 0, clients, settings); + } } - free(strcopyPtr); // TODO - Can we fail here? Return 0 if so and make callers handle this if so. return 1; } diff --git a/structures.h b/structures.h index 26b7439..9e5f575 100644 --- a/structures.h +++ b/structures.h @@ -22,11 +22,11 @@ #define MAXDATASIZE 513 // max number of bytes we can get at once (RFC2812 says 512, plus one for null terminator) #define MAXCHANLENGTH 50 // 50 according to RFC 2811 and RFC 2822 +#define MAXCHANKEYLEN 24 // Maxium channel key length, 23 determined by testing various clients/servers (plus one for null terminator) #define MAXNICKLENGTH 64 // Randomly picked (TODO - is there an actual maximum number (ignoring the RFC preference of 9)?) #define MAXUSERNAMELEN 64 // Randomly picked (TODO - is there an actual maximum username length?) #define MAXREALNAMELEN 128 // Randomly picked (TODO - is there an actual maximum real name length?) #define MAXPORTLEN 6 // Up to 65535, so 5 characters + 1 for null -#define MAXAUTOCHANLEN 1024 // Randomly picked maximum length of the auto channel list #define CLIENTCODELEN 17 // Max length of a client code + 1 for null #define MAXCLIENTCODES 64 // Max number of client codes to track #define MAXCONFARR 10 // Max number of entries that a configuration array can have @@ -67,7 +67,7 @@ struct settings { char ircusername[MAXUSERNAMELEN]; // (Is this also true for the username? Can the server change that?) char ircrealname[MAXREALNAMELEN]; char password[MAXDATASIZE]; - char autochannels[MAXAUTOCHANLEN]; + char autochannels[MAXCONFARR][MAXDATASIZE]; // MAXDATASIZE instead of MAXCHANLENGTH + 1 + MAXCHANKEYLEN so getconfarr() only has one string size to deal with char ircserver[HOST_NAME_MAX]; char ircserverport[MAXPORTLEN]; char ircserverpassword[MAXDATASIZE - 5]; // -5 for "PASS " -- cgit v1.2.3