summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Bratch <luke@bratch.co.uk>2019-05-27 17:14:42 +0100
committerLuke Bratch <luke@bratch.co.uk>2019-05-27 17:14:42 +0100
commit3c60bbdb928da1ebcec9153fb199ad740ad41856 (patch)
treeb6e4fabbe4d64a40ebe9310db08a1597ba46c740
parent18be86d3c8ede6eb36b2a75ac357b071cb3b6e4c (diff)
Allow the BLABOUNCER REPLAY command time to be specified with days:hours:minutes:seconds.
-rw-r--r--README2
-rw-r--r--TODO4
-rw-r--r--blabouncer.c83
3 files changed, 79 insertions, 10 deletions
diff --git a/README b/README
index ccb7596..7528ecf 100644
--- a/README
+++ b/README
@@ -18,7 +18,7 @@ If you don't specify one using "-c /path/to/configuration/file" then the example
Once connected to blabouncer with a client, you can use the following commands:
-"BLABOUNCER REPLAY [seconds]" (Where [seconds] is the number of seconds of replay log to replay.)
+"BLABOUNCER REPLAY [[[[days:]hours:]minutes:]seconds]" (To replay a given length of time of replay log.)
Blabouncer commands are all prefixed with BLABOUNCER which you can usually send using "/QUOTE BLABOUNCER".
diff --git a/TODO b/TODO
index 0eee5d6..c9b87a3 100644
--- a/TODO
+++ b/TODO
@@ -7,8 +7,8 @@ Add various auto replay options:
- All logs since X seconds ago (already implemented)
- All logs since the current client last disconnected (track clients with some special token the client auto sends on connect)
-Allow log replay time to be specified with days:hours:minutes:seconds.
-
Might need to #include <limits.h> in blabouncer.c to make some operating systems and/or compilers happy.
Reconnect server if we get disconnected for some reason.
+
+Make sure MAXTOKENS being exceeded can't cause a buffer overflow.
diff --git a/blabouncer.c b/blabouncer.c
index e837977..f8671f5 100644
--- a/blabouncer.c
+++ b/blabouncer.c
@@ -1479,7 +1479,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli
sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);
snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Valid blabouncer commands are:", ircdstrings->ircnick);
sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);
- snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER REPLAY [seconds]\" (Where [seconds] is the number of seconds of replay log to replay.)", ircdstrings->ircnick);
+ snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER REPLAY [[[[days:]hours:]minutes:]seconds]\" (To replay a given length of time of replay log.)", ircdstrings->ircnick);
sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);
// Get the channel count so we can enumerate over all channels.
@@ -1747,19 +1747,88 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli
if (strncasecmp(tokens[0], "BLABOUNCER", strlen(tokens[0])) == 0) {
char outgoingmsg[MAXDATASIZE];
printf("Client BLABOUNCER found and it is: %s with length %zd!\n", tokens[1], strlen(tokens[1]));
- // REPLAY received, send the requested number of seconds of replay to the client
+ // REPLAY received, send the requested length of replay time to the client
if (strncasecmp(tokens[1], "REPLAY", strlen("REPLAY")) == 0) {
printf("Client BLABOUNCER REPLAY (custom blabouncer command) found and it is: %s with length %zd!\n", tokens[1], strlen(tokens[1]));
- int replayseconds;
- if ((replayseconds = strtol(tokens[2], NULL, 10)) == 0) {
- printf("Invalid number of replay seconds provided by REPLAY. Telling client.\n");
- snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Invalid number of seconds of replay requested by REPLAY command.", ircdstrings->ircnick);
+
+ // Split the request into days:hours:minutes:seconds
+
+ // Track which colon-separated token within this request we're on
+ int timecounter = 0;
+
+ // Build array of colon-separated tokens
+ char timetokens[MAXTOKENS][MAXDATASIZE];
+ // Copy to a temporary string so we still have the original in case it's not processed
+ char *timestrcopy = strdup(tokens[2]);
+ // Keep track of initial pointer for free()ing later
+ char *timestrcopyPtr = timestrcopy;
+
+ char *timetoken;
+ while ((timetoken = strsep(&timestrcopy, ":")) != NULL) {
+ if (*timetoken == '\0') continue; // Skip consecutive matches
+ if (timecounter >= MAXTOKENS) break; // Too many tokens
+ printf("Time token: \"%s\", length %zd.\n", timetoken, strlen(timetoken));
+ // Copy into the token array (strlen + 1 to get the NULL terminator)
+ strncpy(timetokens[timecounter], timetoken, strlen(timetoken) + 1);
+ timecounter++;
+ }
+
+ // Make sure we don't have more than four (d:h:m:s) components
+ if (timecounter > 4) {
+ printf("Too many time components requested by REPLAY command. Telling client.\n");
+ snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Too many time components requestd by REPLAY command. Expected up to four (days:hours:minutes:seconds).", ircdstrings->ircnick);
sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);
+ free(timestrcopyPtr);
free(strcopyPtr);
return 1;
}
+ // Make sure all the components are numbers
+ for (int i = 0; i < timecounter; i++) {
+ int check;
+ if ((check = strtol(timetokens[i], NULL, 10)) == 0) {
+ printf("Invalid number '%s' requested by REPLAY command. Telling client.\n", timetokens[i]);
+ if (!snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Invalid number '%s' requested by REPLAY command.", ircdstrings->ircnick, timetokens[i])) {
+ fprintf(stderr, "Error while preparing REPLAY invalid number response!\n");
+ exit(1);
+ }
+ sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);
+ free(timestrcopyPtr);
+ free(strcopyPtr);
+ return 1;
+ }
+ }
+
+ // How many seconds we're going to replay
+ int replayseconds = 0;
+
+ // If d:h:m:s provided
+ if (timecounter == 4) {
+ replayseconds += 86400 * strtol(timetokens[0], NULL, 10);
+ replayseconds += 3600 * strtol(timetokens[1], NULL, 10);
+ replayseconds += 60 * strtol(timetokens[2], NULL, 10);
+ replayseconds += strtol(timetokens[3], NULL, 10);
+ }
+ // If h:m:s provided
+ if (timecounter == 3) {
+ replayseconds += 3600 * strtol(timetokens[0], NULL, 10);
+ replayseconds += 60 * strtol(timetokens[1], NULL, 10);
+ replayseconds += strtol(timetokens[2], NULL, 10);
+ }
+ // If m:s provided
+ if (timecounter == 2) {
+ replayseconds += 60 * strtol(timetokens[0], NULL, 10);
+ replayseconds += strtol(timetokens[1], NULL, 10);
+ }
+ // If s provided
+ if (timecounter == 1) {
+ replayseconds += strtol(timetokens[0], NULL, 10);
+ }
+
+ printf("Replaying '%s' which is '%d' seconds.\n", tokens[2], replayseconds);
+
doreplay(sourcefd, replayseconds, clients, settings, ircdstrings, channels);
+ free(timestrcopyPtr);
free(strcopyPtr);
return 1;
// Unrecognised BLABOUNCER command received, send some help instructions
@@ -1767,7 +1836,7 @@ int processircmessage(SSL *server_ssl, char *str, int source, struct client *cli
printf("Client BLABOUNCER unrecognised command found and it is: %s with length %zd! Sending a help message.\n", tokens[1], strlen(tokens[1]));
snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :Unrecognised BLABOUNCER command received. Valid commands are:", ircdstrings->ircnick);
sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);
- snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER REPLAY [seconds]\" (Where [seconds] is the number of seconds of replay log to replay.)", ircdstrings->ircnick);
+ snprintf(outgoingmsg, MAXDATASIZE, "NOTICE %s :\"BLABOUNCER REPLAY [[[[days:]hours:]minutes:]seconds]\" (To replay a given length of time of replay log.)", ircdstrings->ircnick);
sendtoclient(sourcefd, outgoingmsg, clients, settings, 0);
free(strcopyPtr);
return 1;