From 34d410dc82e05f4255ec23a9deaff212b7903955 Mon Sep 17 00:00:00 2001
From: Luke Bratch <luke@bratch.co.uk>
Date: Sat, 11 May 2019 22:11:42 +0100
Subject: Implement authentication in the form of the bouncer having a
 configurable server password

---
 blabouncer.c    | 184 ++++++++++++++++++++++++++++++++++++++++----------------
 blabouncer.conf |   3 +
 config.c        |  47 ++++++++++++++-
 config.h        |   2 +
 replay.c        |   3 +
 5 files changed, 186 insertions(+), 53 deletions(-)

diff --git a/blabouncer.c b/blabouncer.c
index 29b90ae..c748ebc 100644
--- a/blabouncer.c
+++ b/blabouncer.c
@@ -8,9 +8,9 @@
 // - Add blabouncer MOTD (375, 372, 376)
 // - "01:53:47 -!- ServerMode/#test [b] by irc.tghost.co.uk" on existing clients when new client connects
 // - Keep track of changing user nicks/modes
-// - Relay log can just be "log/resend everything that ever hit sendto[all]client[s]()" (or maybe just PRIVMSGs?  + NOTICEs and friends?)
+// - Should relay log do more than PRIVMSGs?
 // - Implement TLS
-// - Implement password/login
+// - Check authentication before even getting to the send functions to save unnecessary processing
 //
 // Example WHOIS reply:
 // BOUNCER-SERVER RECEIVED: :irc.tghost.co.uk 307 blabounce l_bratch :is identified for this nick
@@ -79,9 +79,20 @@ struct ircdstrings {
 int debugmode = 0;
 
 // Send whatever string to a specific client by providing the FD
-int sendtoclient(int fd, char *str) {
+int sendtoclient(int fd, char *str, int arr_clients[], int arr_authed[]) {
   appendcrlf(str); // Do this just before sending so callers don't need to worry about it
 
+  // Find the client in the clients array and make sure they are authenticated
+  for (int i = 0; i < MAXCLIENTS; i++) {
+    if (arr_clients[i] == fd) {
+      // Found client in array, check authentication status
+      if (!arr_authed[i]) {
+        printf("sendtoclient(): skipping unauthenticated client with fd %d.\n", arr_clients[i]);
+        return 0;
+      }
+    }
+  }
+
   printf("sendtoclient(): sending \"%s\" (length %zd) to client with fd %d.\n", str, strlen(str), fd);
   if (send(fd, str, strlen(str), 0) == -1) {
     perror("error: sendtoclient() send()\n");
@@ -92,8 +103,9 @@ int sendtoclient(int fd, char *str) {
 }
 
 // Disconnect the client fd "fd" by close()ing it and remove
-// it from the arr_clients array of clients
-int disconnectclient(int fd, int arr_clients[]) {
+// it from the arr_clients array of clients.
+// Also set its authentication status to 0.
+int disconnectclient(int fd, int arr_clients[], int arr_authed[]) {
   printf("disconnectclient(): disconnecting client fd '%d'\n", fd);
   close(fd); // bye!
   // Remove the client from the clients array
@@ -101,6 +113,7 @@ int disconnectclient(int fd, int arr_clients[]) {
     if (arr_clients[j] == fd) {
       printf("found and clearing fd %d from arr_clients[%d]\n", fd, j);
       arr_clients[j] = 0;
+      arr_authed[j] = 0;
       return 1;
     }
   }
@@ -112,8 +125,9 @@ int disconnectclient(int fd, int arr_clients[]) {
 
 // Relay/send message to all clients (optionally except one)
 // "except" is used to send to all clients _except_ the fd provided (except = 0 (EXCEPT_NONE) avoids this, i.e. sends to all)
+// "except" is really the "sourcefd" and is also used as part of the authentication check - this is messy and they should perhaps be two separate arguments.
 // TODO - is passing str_len useful if we're appendcrlfing and then using strlen(str) in the send?  I guess not...  (As long as we're always null terminated in the correct place.)
-int sendtoallclients(int *clientsockfd, int fdmax, int arr_clients[], char *str, int except) {
+int sendtoallclients(int *clientsockfd, int fdmax, int arr_clients[], char *str, int except, int arr_authed[]) {
 
   char *sendertype;
 
@@ -128,6 +142,22 @@ int sendtoallclients(int *clientsockfd, int fdmax, int arr_clients[], char *str,
     sendertype = "bouncer-server";
   }
 
+  // Find the sending client in the clients array and make sure they are authenticated
+  for (int i = 0; i < MAXCLIENTS; i++) {
+    // Trust clientfd of 0, only we can set that ourselves
+    if (!except) {
+      printf("sendtoallclients(): trusting clientfd of 0.\n");
+      break;
+    }
+    if (arr_clients[i] == except) {
+      // Found client in array, check authentication status
+      if (!arr_authed[i]) {
+        printf("sendtoallclients(): skipping unauthenticated client with fd %d.\n", arr_clients[i]);
+        return 0;
+      }
+    }
+  }
+
   // relay/send to all clients...
   for (int i = *clientsockfd + 1; i <= fdmax; i++) {
     // Skip the current client if "except" non-zero (no need to send back to itself)
@@ -138,7 +168,11 @@ int sendtoallclients(int *clientsockfd, int fdmax, int arr_clients[], char *str,
     // ...but only if they are connected
     for (int j = 0; j < MAXCLIENTS; j++) {
       if (arr_clients[j] == i) {
-        printf("sendtoallclients(): %s: sending %s to client with fd %d.\n", sendertype, str, i);
+        if (!arr_authed[j]) {
+          printf("sendtoallclients(): skipping unauthenticated client with fd %d.\n", arr_clients[j]);
+          continue;
+        }
+        printf("sendtoallclients(): %s: sending '%s' to client with fd %d.\n", sendertype, str, i);
         if (send(i, str, strlen(str), 0) == -1) {
           perror("error: sendtoallclients() send()\n");
         }
@@ -150,15 +184,36 @@ int sendtoallclients(int *clientsockfd, int fdmax, int arr_clients[], char *str,
 }
 
 // Send whatever string to the real IRC server
-int sendtoserver(int *serversockfd, char *str, int str_len) {
+// Client FD and arrays needed to make sure anything relayed from a client is from an authenticated client.
+// clientfd of "0" means trusted, used when we are sending things ourselves that weren't relayed
+// from a relay client.
+int sendtoserver(int *serversockfd, char *str, int str_len, int clientfd, int arr_clients[], int arr_authed[]) {
   appendcrlf(str); // Do this just before sending so callers don't need to worry about it
   str_len = strlen(str); // Recalculate str_len in case it changed (TODO: so do we even need to pass it to this function?)
+
+  // Find the sending client in the clients array and make sure they are authenticated
+  for (int i = 0; i < MAXCLIENTS; i++) {
+    // Trust clientfd of 0, only we can set that ourselves
+    if (!clientfd) {
+      printf("sendtoserver(): trusting clientfd of 0.\n");
+      break;
+    }
+    if (arr_clients[i] == clientfd) {
+      // Found client in array, check authentication status
+      if (!arr_authed[i]) {
+        printf("sendtoserver(): skipping unauthenticated client with fd %d.\n", arr_clients[i]);
+        return 0;
+      }
+    }
+  }
+
   printf("sendtoserver(): sending %s to IRC server (length %d).\n", str, str_len);
   if (send(*serversockfd, str, str_len, 0) == -1) { // 0 is bitwise OR for no send() flags
     printf("error: sendtoserver() send()\n");
+    return 0;
   }
 
-  return 0;
+  return 1;
 }
 
 int createchannel(struct channel *channels, char *name, char *topic, char *topicwho, char *topicwhen, char *modes, char *namestype) {
@@ -336,7 +391,7 @@ int removechannel(struct channel *channels, char *name) {
 // Figure out what to do with each CRLF-split IRC message (if anything)
 // by splitting out the different components by space character (ASCII 0x20).
 //
-// serversockfd, clientsockfd, fdmax, arr_clients, except all passed to here so we can
+// serversockfd, clientsockfd, fdmax, arr_clients, arr_authed, all passed to here so we can
 // send/relay a response to server or (other) client(s) directly from this function if
 // we want to.
 //
@@ -347,7 +402,7 @@ int removechannel(struct channel *channels, char *name) {
 // Return 1 if we processed something and expect the caller to not need to do anything more
 // Return 0 if we didn't process it and the caller might want to do something
 //int processircmessage(int *serversockfd, int *clientsockfd, char *str, int source) {
-int processircmessage(int *serversockfd, int *clientsockfd, char *str, int source, int fdmax, int arr_clients[], int sourcefd, struct ircdstrings *ircdstrings, struct channel *channels) {
+int processircmessage(int *serversockfd, int *clientsockfd, char *str, int source, int fdmax, int arr_clients[], int sourcefd, struct ircdstrings *ircdstrings, struct channel *channels, int arr_authed[]) {
   // Track which space-separated token within this response we're on
   int counter = 0;
 
@@ -383,7 +438,8 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
           fprintf(stderr, "Error while preparing PONG response!\n");
           exit(1);
         }
-        sendtoserver(serversockfd, outgoingmsg, strlen(outgoingmsg));
+        // sourcefd = 0 as this is a trusted response
+        sendtoserver(serversockfd, outgoingmsg, strlen(outgoingmsg), 0, arr_clients, arr_authed);
 
         // We processed something so return true
         return 1;
@@ -455,7 +511,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
           }
 
           // And then send to all clients
-          sendtoallclients(clientsockfd, fdmax, arr_clients, str, sourcefd);
+          sendtoallclients(clientsockfd, fdmax, arr_clients, str, sourcefd, arr_authed);
           return 1;
         }
 
@@ -476,7 +532,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
           }
 
           // And then send to all clients
-          sendtoallclients(clientsockfd, fdmax, arr_clients, str, sourcefd);
+          sendtoallclients(clientsockfd, fdmax, arr_clients, str, sourcefd, arr_authed);
           return 1;
         }
 
@@ -543,7 +599,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
           setchanneltopicwhotime(channels, tokens[2], prefixcopy, timenowstr);
 
           // And then finally relay to all clients
-          sendtoallclients(clientsockfd, fdmax, arr_clients, str, sourcefd);
+          sendtoallclients(clientsockfd, fdmax, arr_clients, str, sourcefd, arr_authed);
           return 1;
         }
 
@@ -551,7 +607,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
         if (strncmp(tokens[1], "PRIVMSG", strlen(tokens[1])) == 0) {
           printf("Server PRIVMSG found and it is: %s with length %zd!  Next token is '%s'.  Relaying to all clients.\n", tokens[0], strlen(tokens[0]), tokens[2]);
 
-          sendtoallclients(clientsockfd, fdmax, arr_clients, str, sourcefd);
+          sendtoallclients(clientsockfd, fdmax, arr_clients, str, sourcefd, arr_authed);
 
           // Write to relay log
           writerelayline(str);
@@ -564,23 +620,40 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
 
       break;
     case SOURCE_CLIENT: // If message(s) were from a real IRC client
+      // PASS received?  User is trying to log in, check their password.
+      if (strncmp(tokens[0], "PASS", strlen(tokens[0])) == 0) {
+        if (checkpassword(tokens[1])) {
+          printf("Password accepted!  Setting fd %d to authenticated.\n", sourcefd);
+          // Find the client in the clients array and set them as authenticated
+          for (int i = 0; i < MAXCLIENTS; i++) {
+            if (arr_clients[i] == sourcefd) {
+              // Found client in array, set to authenticated
+              arr_authed[i] = 1;
+              printf("Found and authenticated fd in arr_authed.\n");
+            }
+          }
+        } else {
+          printf("Password rejected, disconnecting fd %d.\n", sourcefd);
+          disconnectclient(sourcefd, arr_clients, arr_authed);
+        }
+
+        return 1;
+      }
+
       // USER received?  If so, assume this is a new client connecting and catch them on up on the state
       if (strncmp(tokens[0], "USER", strlen(tokens[0])) == 0) {
-        // Need to sort out channel structure first!!
-        printf("TODO: USER received!\n");
-
         // Somewhere to store the several strings we will need to build and send
         char outgoingmsg[MAXDATASIZE]; // String to send to client
 
         // Send IRC greeting strings (001/RPL_WELCOME, 002/RPL_YOURHOST, 003/RPL_CREATED, 004/RPL_MYINFO) to client
         snprintf(outgoingmsg, MAXDATASIZE, "%s", ircdstrings->greeting001);
-        sendtoclient(sourcefd, outgoingmsg);
+        sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed);
         snprintf(outgoingmsg, MAXDATASIZE, "%s", ircdstrings->greeting002);
-        sendtoclient(sourcefd, outgoingmsg);
+        sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed);
         snprintf(outgoingmsg, MAXDATASIZE, "%s", ircdstrings->greeting003);
-        sendtoclient(sourcefd, outgoingmsg);
+        sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed);
         snprintf(outgoingmsg, MAXDATASIZE, "%s", ircdstrings->greeting004);
-        sendtoclient(sourcefd, outgoingmsg);
+        sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed);
 
         // Get the channel count so we can enumerate over all channels.
         // Storing separately so we can skip over blank channels.
@@ -601,7 +674,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
             fprintf(stderr, "Error while preparing USER just connected, channel JOIN responses!\n");
             exit(1);
           }
-          sendtoclient(sourcefd, outgoingmsg);
+          sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed);
 
           // Send topic (or lack thereof) to client
           // If there isn't one set (we guess this if topic timestamp is 0), send 331 RPL_NOTOPIC
@@ -612,7 +685,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
               exit(1);
             }
             // ..and send it to the client
-            sendtoclient(sourcefd, outgoingmsg);
+            sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed);
           // If there is one set, send 332 RPL_TOPIC and 333 RPL_TOPICWHOTIME
           } else {
             // Prepare the topic message...
@@ -621,7 +694,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
               exit(1);
             }
             // ..and send it to the client
-            sendtoclient(sourcefd, outgoingmsg);
+            sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed);
 
             // Next prepare the topic who/when message...
             if (!snprintf(outgoingmsg, MAXDATASIZE, ":%s 333 %s %s %s %s", ircdstrings->ircdname, ircdstrings->ircnick, channels[i].name, channels[i].topicwho, channels[i].topicwhen)) {
@@ -629,7 +702,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
               exit(1);
             }
             // ..and send it to the client
-            sendtoclient(sourcefd, outgoingmsg);
+            sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed);
           }
 
           // Send list of names
@@ -649,7 +722,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
               fprintf(stderr, "Error while preparing USER just connected, channel NAMES responses!\n");
               exit(1);
             }
-            sendtoclient(sourcefd, outgoingmsg);
+            sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed);
           }
 
           // Once all names are sent, send the "end of /NAMES" 366 (RPL_ENDOFNAMES) message
@@ -657,7 +730,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
             fprintf(stderr, "Error while preparing USER just connected, end of NAMES response!\n");
             exit(1);
           }
-          sendtoclient(sourcefd, outgoingmsg);
+          sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed);
         }
 
         // Send the client however many relay lines have been requested
@@ -679,7 +752,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
             exit(1);
           }
           printf("Sending relay line: '%s'.\n", outgoingmsg);
-          sendtoclient(sourcefd, outgoingmsg);
+          sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed);
         }
 
         return 1;
@@ -694,7 +767,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
           fprintf(stderr, "Error while preparing PONG response!\n");
           exit(1);
         }
-        sendtoclient(sourcefd, outgoingmsg);
+        sendtoclient(sourcefd, outgoingmsg, arr_clients, arr_authed);
 
         // We processed something so return true
         return 1;
@@ -709,7 +782,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
       // Just send NICK to server and let it change all clients' nicks if needed
       if (strncmp(tokens[0], "NICK", strlen(tokens[0])) == 0) {
         printf("Client NICK found and it is: %s with length %zd!  Sending to server...\n", tokens[0], strlen(tokens[0]));
-        sendtoserver(serversockfd, str, strlen(str));
+        sendtoserver(serversockfd, str, strlen(str), sourcefd, arr_clients, arr_authed);
         return 1;
       }
 
@@ -717,7 +790,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
       if (strncmp(tokens[0], "PRIVMSG", strlen(tokens[0])) == 0) {
         printf("Client PRIVMSG found and it is: %s with length %zd!  Sending to server then back to other clients...\n", tokens[0], strlen(tokens[0]));
         // Send original request straight to server
-        sendtoserver(serversockfd, str, strlen(str));
+        sendtoserver(serversockfd, str, strlen(str), sourcefd, arr_clients, arr_authed);
 
         // Rebuild to full PRIVMSG string and relay to all other clients
         char outgoingmsg[MAXDATASIZE]; // String to send to client
@@ -727,7 +800,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
           exit(1);
         }
         // Send to all except source client
-        sendtoallclients(clientsockfd, fdmax, arr_clients, outgoingmsg, sourcefd);
+        sendtoallclients(clientsockfd, fdmax, arr_clients, outgoingmsg, sourcefd, arr_authed);
 
         // Write to relay log
         writerelayline(outgoingmsg);
@@ -738,7 +811,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
       // Just send JOIN to server and let it talk back to clients as required
       if (strncmp(tokens[0], "JOIN", strlen(tokens[0])) == 0) {
         printf("Client JOIN found and it is: %s with length %zd!  Sending to server...\n", tokens[0], strlen(tokens[0]));
-        sendtoserver(serversockfd, str, strlen(str));
+        sendtoserver(serversockfd, str, strlen(str), sourcefd, arr_clients, arr_authed);
         return 1;
       }
 
@@ -747,21 +820,21 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
       if (strncmp(tokens[0], "QUIT", strlen(tokens[0])) == 0) {
         printf("Client QUIT found from fd %d and it is: %s with length %zd!  Disconnecting that fd.\n", sourcefd, tokens[0], strlen(tokens[0]));
         close(sourcefd);
-        disconnectclient(sourcefd, arr_clients);
+        disconnectclient(sourcefd, arr_clients, arr_authed);
         return 1;
       }
 
       // Just send PART to server and let it talk back to clients as required
       if (strncmp(tokens[0], "PART", strlen(tokens[0])) == 0) {
         printf("Client PART found and it is: %s with length %zd!  Sending to server...\n", tokens[0], strlen(tokens[0]));
-        sendtoserver(serversockfd, str, strlen(str));
+        sendtoserver(serversockfd, str, strlen(str), sourcefd, arr_clients, arr_authed);
         return 1;
       }
 
       // Just send TOPIC to server and let it talk back to clients as required
       if (strncmp(tokens[0], "TOPIC", strlen(tokens[0])) == 0) {
         printf("Client TOPIC found and it is: %s with length %zd!  Sending to server...\n", tokens[0], strlen(tokens[0]));
-        sendtoserver(serversockfd, str, strlen(str));
+        sendtoserver(serversockfd, str, strlen(str), sourcefd, arr_clients, arr_authed);
         return 1;
       }
 
@@ -784,7 +857,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
 // or send on to all other clients (if from the server) or to the server (if from a client)
 // if we don't know how to.
 //
-// serversockfd, clientsockfd, fdmax, arr_clients, except all passed to here so we can
+// serversockfd, clientsockfd, fdmax, arr_clients, arr_authed all passed to here so we can
 // send/relay a response to server or (other) client(s) for things we don't know how to process here,
 // or for any other reasons we need to send stuff for
 //
@@ -794,7 +867,7 @@ int processircmessage(int *serversockfd, int *clientsockfd, char *str, int sourc
 //
 // Return 0 if something went wrong
 // Return 1 if everything OK
-int processrawstring(int *serversockfd, int *clientsockfd, char *str, int source, int fdmax, int arr_clients[], int sourcefd, struct ircdstrings *ircdstrings, struct channel *channels) {
+int processrawstring(int *serversockfd, int *clientsockfd, char *str, int source, int fdmax, int arr_clients[], int sourcefd, struct ircdstrings *ircdstrings, struct channel *channels, int arr_authed[]) {
   // Copy to a temporary string so we still have the original in case it's not processed
   char *strcopy = strdup(str);
 
@@ -823,7 +896,7 @@ int processrawstring(int *serversockfd, int *clientsockfd, char *str, int source
   for (int i = 0; i < messagecount; i++) {
     // Copy to a temporary string so we still have the original in case it's not processed
     char *messagecopy = strdup(messages[i]);
-    if (processircmessage(serversockfd, clientsockfd, messagecopy, source, fdmax, arr_clients, sourcefd, ircdstrings, channels)) {
+    if (processircmessage(serversockfd, clientsockfd, messagecopy, source, fdmax, arr_clients, sourcefd, ircdstrings, channels, arr_authed)) {
       printf("Message processed: \"%s\", NULLing...\n", messages[i]);
       messages[i][0] = '\0';
     }
@@ -839,16 +912,16 @@ int processrawstring(int *serversockfd, int *clientsockfd, char *str, int source
           // Relay/send to all clients ("except" = 0 because this should send to all clients)
           // TODO - Is this really going to send the original string if we have messed it with it in processrawstring() and friends!?
           printf("bouncer-server: sending unprocessed server messasge \"%s\" to all clients, length %zd.\n", messages[i], strlen(messages[i]));
-          sendtoallclients(clientsockfd, fdmax, arr_clients, messages[i], EXCEPT_NONE);
+          sendtoallclients(clientsockfd, fdmax, arr_clients, messages[i], EXCEPT_NONE, arr_authed);
           break;
         case SOURCE_CLIENT: // If message(s) were from a real IRC client
           // Send to server
           printf("bouncer-client: sending unprocessed client messasge \"%s\" to the server, length %zd.\n", messages[i], strlen(messages[i]));
-          sendtoserver(serversockfd, messages[i], strlen(messages[i]));
+          sendtoserver(serversockfd, messages[i], strlen(messages[i]), sourcefd, arr_clients, arr_authed);
 
           printf("bouncer-client: sending unprocessed client messasge \"%s\" to all other clients, length %zd.\n", messages[i], strlen(messages[i]));
           // send the same thing to all *other* clients (all except for source fd)
-          sendtoallclients(clientsockfd, fdmax, arr_clients, messages[i], sourcefd);
+          sendtoallclients(clientsockfd, fdmax, arr_clients, messages[i], sourcefd, arr_authed);
           break;
         default:
           fprintf(stderr, "Unexpected raw IRC string source for unprocessed messasge \"%s\", length %zd.!\n", messages[i], strlen(messages[i]));
@@ -869,7 +942,8 @@ void dochat(int *serversockfd, int *clientsockfd) {
   int servernumbytes; // Number of bytes received from remote server
   char outgoingmsg[MAXDATASIZE]; // String to send to server
   int outgoingmsgrc; // Return code from getstdin() for outgoing message
-  int arr_clients[MAXCLIENTS]; // Array of all clients - 0 means not connected, greater than 0 means connected and the value is the fd number (so we know which ones to try to read)
+  int arr_clients[MAXCLIENTS]; // Array of all client FDs - 0 means not connected, greater than 0 means connected and the value is the fd number (so we know which ones to try to read)
+  int arr_authed[MAXCLIENTS]; // Array of client authentication statuses - 0 means not authenticated, 1 means authenticated.  Element numbers match those of arr_clients.
   int num_clients = 0; // Current number of clients
 
   int fdmax; // highest numbered socket fd
@@ -884,9 +958,10 @@ void dochat(int *serversockfd, int *clientsockfd) {
 
   fd_set rfds; // set of read fds to monitor with select() - 0: stdin, 1: stdout, 2: stderr, 3 and higher: sockets (at time of writing, 3: real IRC server, 4: client listener, 5 and higher: clients)
 
-  // set all the clients to be "not connected"
+  // Set all the clients to be "not connected" and "not authenticated"
   for (int i = 0; i < MAXCLIENTS; i++) {
     arr_clients[i] = 0;
+    arr_authed[i] = 0;
   }
 
   // <=============================================
@@ -914,12 +989,14 @@ void dochat(int *serversockfd, int *clientsockfd) {
 
   // Send our NICK
   snprintf(outgoingmsg, MAXDATASIZE, "NICK %s", ircdstrings.ircnick); // TODO - Check for success (with return code)
-  sendtoserver(serversockfd, outgoingmsg, strlen(outgoingmsg));
+  // sourcefd = 0 as this is a trusted message
+  sendtoserver(serversockfd, outgoingmsg, strlen(outgoingmsg), 0, arr_clients, arr_authed);
 
   // Send our USER
   snprintf(outgoingmsg, MAXDATASIZE, "USER %s 8 * : %s", ircdstrings.ircusername, ircdstrings.ircrealname); // TODO - Check for success (with return code)
                                                                                 // TODO - Send a more intelligent/correct USER string
-  sendtoserver(serversockfd, outgoingmsg, strlen(outgoingmsg));
+  // sourcefd = 0 as this is a trusted message
+  sendtoserver(serversockfd, outgoingmsg, strlen(outgoingmsg), 0, arr_clients, arr_authed);
 
   // Struct of channels we're in
   struct channel *channels;
@@ -973,7 +1050,7 @@ void dochat(int *serversockfd, int *clientsockfd) {
 
       // Try to process received string (which should contain one or more server responses/commands)
       // TODO - What if there were two server respones/commands and only one didn't need relaying?
-      if (!processrawstring(serversockfd, clientsockfd, serverbuf, SOURCE_SERVER, fdmax, arr_clients, EXCEPT_NONE, &ircdstrings, channels)) {
+      if (!processrawstring(serversockfd, clientsockfd, serverbuf, SOURCE_SERVER, fdmax, arr_clients, EXCEPT_NONE, &ircdstrings, channels, arr_authed)) {
         fprintf(stderr, "Error: bouncer-server failed to process raw string.\n");
         exit(1);
       }
@@ -1013,7 +1090,8 @@ void dochat(int *serversockfd, int *clientsockfd) {
         continue;
       }
 
-      sendtoserver(serversockfd, outgoingmsg, strlen(outgoingmsg));
+      // sourcefd = 0 as this is a trusted message
+      sendtoserver(serversockfd, outgoingmsg, strlen(outgoingmsg), 0, arr_clients, arr_authed);
     }
 
     // go through all the remaining sockets to see if there's anything from the client sockets (either new connections or existing clients sending messages)
@@ -1049,6 +1127,8 @@ void dochat(int *serversockfd, int *clientsockfd) {
             for (int j = 0; j < MAXCLIENTS; j++) {
                 if (arr_clients[j] == 0) {
                   arr_clients[j] = newfd;
+                  // Ensure its authentication status is set to 0
+                  arr_authed[j] = 0;
                   break;
                 }
             }
@@ -1069,7 +1149,7 @@ void dochat(int *serversockfd, int *clientsockfd) {
               perror("recv");
             }
             // Disconnect the client
-            disconnectclient(i, arr_clients);
+            disconnectclient(i, arr_clients, arr_authed);
             FD_CLR(i, &rfds); // remove from master set - TODO is this needed at the moment since we just add everything from *clientsockfd to fdmax to rfds
             // TODO - Handle the "remove the client" loop not finding the old fd
             num_clients--; // Track total number of clients
@@ -1086,7 +1166,7 @@ void dochat(int *serversockfd, int *clientsockfd) {
 
             // Try to process received string (which should contain one or more client responses/commands)
             // TODO - What if there were two server respones/commands and only one didn't need relaying?
-            if (!processrawstring(serversockfd, clientsockfd, clientbuf, SOURCE_CLIENT, fdmax, arr_clients, i, &ircdstrings, channels)) {
+            if (!processrawstring(serversockfd, clientsockfd, clientbuf, SOURCE_CLIENT, fdmax, arr_clients, i, &ircdstrings, channels, arr_authed)) {
               fprintf(stderr, "Error: bouncer-client failed to process raw string.\n");
               exit(1);
             }
diff --git a/blabouncer.conf b/blabouncer.conf
index 5b68918..5be29ca 100644
--- a/blabouncer.conf
+++ b/blabouncer.conf
@@ -10,3 +10,6 @@ realname = "Mr Bla Bouncer"
 
 # How many seconds of relay log should be sent to connecting clients
 relayseconds = "7200"
+
+# Connect password clients must provided to connect
+password = "bananas"
diff --git a/config.c b/config.c
index 7fec4de..8bfead9 100644
--- a/config.c
+++ b/config.c
@@ -1,6 +1,6 @@
 #include "config.h"
 
-// TODO - Multiple functions here (at least readnames() and relayseconds() have the file opening code, rewrite.
+// TODO - Multiple functions here (at least readnames(), relayseconds() and checkpassword()) have the file opening code, rewrite.
 
 // TODO - Can isconf() and getconf() just be merged into one function?
 
@@ -136,5 +136,50 @@ int confrelayseconds() {
     }
   }
 
+  fclose(fp);
   return seconds;
 }
+
+// Check the password provided in the string 'str' against what is in
+// the config file.
+// Return 0 for password mismatch, or 1 for password match.
+int checkpassword(char *password) {
+  FILE *fp;
+  char str[MAXCHAR];
+  char* filename = "blabouncer.conf";
+
+  fp = fopen(filename, "r");
+
+  if (fp == NULL) {
+    printf("error: could not open configuration file '%s'.\n", filename);
+    exit(1);
+  }
+
+  while (fgets(str, MAXCHAR, fp) != NULL) {
+    long int len;
+    if ((len = isconf(str, "password"))) {
+      getconf(str, len);
+      printf("confpassword is: '%s', length '%ld'.\n", str, strlen(str));
+      // Ensure password are the same length
+      if (strlen(str) != strlen(password)) {
+        printf("Password length mismatch!\n");
+        fclose(fp);
+        return 0;
+      }
+      // Ensure passwords match
+      if (strncmp(str, password, strlen(password)) == 0) {
+        printf("confpassword matches password.\n");
+        fclose(fp);
+        return 1;
+      } else {
+        printf("confpassword does NOT match password!\n");
+        fclose(fp);
+        return 0;
+      }
+    }
+  }
+
+  fclose(fp);
+  printf("No password read from configuration file, quitting.\n");
+  exit(1);
+}
diff --git a/config.h b/config.h
index 57defb6..d74af82 100644
--- a/config.h
+++ b/config.h
@@ -11,4 +11,6 @@ int readnames(char *nick, char *username, char *realname);
 
 int confrelayseconds();
 
+int checkpassword(char *password);
+
 #endif
diff --git a/replay.c b/replay.c
index 36817fb..0ab3238 100644
--- a/replay.c
+++ b/replay.c
@@ -166,6 +166,7 @@ int relaylines(int seconds) {
     int timestamp = gettimestamp(str);
     if (timestamp < 1) {
       printf("Error reading timestamp from replay log file.\n");
+      fclose(fp);
       return -1;
     }
     
@@ -221,6 +222,7 @@ int readrelayline(int seconds, int linenum, char *str) {
 
         strncpy(str, line, strlen(line));
         str[strlen(line)] = '\0';
+        fclose(fp);
         return 1;
       }
       count++;
@@ -228,6 +230,7 @@ int readrelayline(int seconds, int linenum, char *str) {
   }
 
   // If we got here something went wrong
+  fclose(fp);
   return 0;
 }
 
-- 
cgit v1.2.3