Просмотр исходного кода

Merge branch 'ducch-fish-for-chans'

* ducch-fish-for-chans:
  * Update docs
  * Trim key when setting it
  * Use a bd::String for key
  * Cleanup fish-key to be consistent with other Chanchars
  * Fix wrong chanchar name for 'fish-key' when writing userfile
  * Fix bot-initiated key exchange due to FiSH support in notice()
  * Don't allow setting FiSH key in channel via cmd_setkey
  * Make the size of the key a const size_t
  * Only remove key if it exists
  * Update docs
  * Support FiSH for channel targets in privmsg/notice
  * FiSH key in .chanset instead of .setkey
  * DRY set_fish_key(target, key). empty to remove key.
  * Random FiSH key support in .setkey
Bryan Drewery 14 лет назад
Родитель
Сommit
a50307d79f

+ 4 - 3
doc/UPDATES

@@ -10,9 +10,10 @@
   * Fix blowfish not working correctly on 64bit
   * Fix blowfish not working correctly on 64bit
   * Suicide will now remove all bots related to the binary being removed (fixes #435)
   * Suicide will now remove all bots related to the binary being removed (fixes #435)
   * FiSH message support added.
   * FiSH message support added.
-  * FiSH support for DH1080 key-exchange. 'keyx' command added to start from bot, and responds to key-exchanges.
-  * Auto FiSH key-exchange when accepting users via callerid (controllable with set 'fish-auto-keyx')
-  * Automatic re-key exchange after every message to avoid replay attacks (controllable with set 'fish-paranoid')
+    * FiSH support for DH1080 key-exchange. 'keyx' command added to start from bot, and responds to key-exchanges.
+    * Auto FiSH key-exchange when accepting users via callerid (controllable with set 'fish-auto-keyx')
+    * Automatic re-key exchange after every message to avoid replay attacks (controllable with set 'fish-paranoid')
+    * Set FiSH key via cmd_setkey and 'chanset fish-key'
   * When 'mdop' protection is on, re-op all previously opped clients automatically.
   * When 'mdop' protection is on, re-op all previously opped clients automatically.
   * When 'mop' protection is on, deop all previously regular clients automatically.
   * When 'mop' protection is on, deop all previously regular clients automatically.
   * Add './wraith -V' which will display the packconfig that the bot is using.
   * Add './wraith -V' which will display the packconfig that the bot is using.

+ 4 - 1
doc/help.txt

@@ -411,6 +411,8 @@ See also: link%{+a}, newhub%{-}
  
  
         $bflood-lock-time$b   How long in seconds to keep the channel locked
         $bflood-lock-time$b   How long in seconds to keep the channel locked
                          during drone floods.
                          during drone floods.
+        $bfish-key$b          The key to use for FiSH encryption. Use '{ key }'
+                          to set and '{}' to unset.
  
  
         $binvite-time$b       Set here how long temporary invites will last (in
         $binvite-time$b       Set here how long temporary invites will last (in
                           minutes). If you set this setting to 0, the bot will
                           minutes). If you set this setting to 0, the bot will
@@ -1741,10 +1743,11 @@ See also: reload, backup
  
  
 See also: botset
 See also: botset
 :leaf:setkey
 :leaf:setkey
-### $bsetkey$b <nick|channel> [key]
+### $bsetkey$b <nick> [key|rand]
  
  
     Sets the FiSH key for the given target.
     Sets the FiSH key for the given target.
     Use no key to clear the currently set key.
     Use no key to clear the currently set key.
+    Use 'rand' to generate a random key.
  
  
 See also: keyx
 See also: keyx
 ::sha1
 ::sha1

+ 1 - 0
src/chan.h

@@ -214,6 +214,7 @@ struct chanset_t {
   char mns[21];			/* negative mode changes		*/
   char mns[21];			/* negative mode changes		*/
   char key_prot[121];		/* desired password			*/
   char key_prot[121];		/* desired password			*/
   bd::Array<bd::String> *groups;/* groups that should join */
   bd::Array<bd::String> *groups;/* groups that should join */
+  char fish_key[50];
 /* Chanchar template
 /* Chanchar template
  *char temp[121];
  *char temp[121];
  */
  */

+ 48 - 5
src/chanprog.c

@@ -890,17 +890,20 @@ struct chanset_t* find_common_opped_chan(bd::String nick) {
 
 
 void privmsg(bd::String target, bd::String msg, int idx) {
 void privmsg(bd::String target, bd::String msg, int idx) {
   struct chanset_t* chan = NULL;
   struct chanset_t* chan = NULL;
-  if (have_cprivmsg && !strchr(CHANMETA, target[0]))
+  bool talking_to_chan = strchr(CHANMETA, target[0]);
+  if (have_cprivmsg && !talking_to_chan)
     chan = find_common_opped_chan(target);
     chan = find_common_opped_chan(target);
   bool cleartextPrefix = (msg(0, 3) == "+p ");
   bool cleartextPrefix = (msg(0, 3) == "+p ");
 
 
   // Encrypt with FiSH?
   // Encrypt with FiSH?
-  if (!strchr(CHANMETA, target[0]) && !cleartextPrefix && FishKeys.contains(target) && FishKeys[target]->sharedKey.length()) {
+  if (!cleartextPrefix && FishKeys.contains(target) && FishKeys[target]->sharedKey.length()) {
     msg = "+OK " + egg_bf_encrypt(msg, FishKeys[target]->sharedKey);
     msg = "+OK " + egg_bf_encrypt(msg, FishKeys[target]->sharedKey);
   }
   }
+
   if (cleartextPrefix) {
   if (cleartextPrefix) {
     msg += static_cast<size_t>(3);
     msg += static_cast<size_t>(3);
   }
   }
+
   if (chan)
   if (chan)
     dprintf(idx, "CPRIVMSG %s %s :%s\n", target.c_str(), chan->name, msg.c_str());
     dprintf(idx, "CPRIVMSG %s %s :%s\n", target.c_str(), chan->name, msg.c_str());
   else
   else
@@ -909,8 +912,19 @@ void privmsg(bd::String target, bd::String msg, int idx) {
 
 
 void notice(bd::String target, bd::String msg, int idx) {
 void notice(bd::String target, bd::String msg, int idx) {
   struct chanset_t* chan = NULL;
   struct chanset_t* chan = NULL;
-  if (have_cnotice && !strchr(CHANMETA, target[0]))
+  bool talking_to_chan = strchr(CHANMETA, target[0]);
+  if (have_cnotice && !talking_to_chan)
     chan = find_common_opped_chan(target);
     chan = find_common_opped_chan(target);
+  bool cleartextPrefix = (msg(0, 3) == "+p ");
+
+  if (!cleartextPrefix && FishKeys.contains(target) && FishKeys[target]->sharedKey.length()) {
+    msg = "+OK " + egg_bf_encrypt(msg, FishKeys[target]->sharedKey);
+  }
+
+  if (cleartextPrefix) {
+    msg += static_cast<size_t>(3);
+  }
+
   if (chan)
   if (chan)
     dprintf(idx, "CNOTICE %s %s :%s\n", target.c_str(), chan->name, msg.c_str());
     dprintf(idx, "CNOTICE %s %s :%s\n", target.c_str(), chan->name, msg.c_str());
   else
   else
@@ -923,12 +937,41 @@ void keyx(const bd::String &target) {
 
 
   DH1080_gen(myPrivateKey, myPublicKeyB64);
   DH1080_gen(myPrivateKey, myPublicKeyB64);
 
 
-  putlog(LOG_MSGS, "*", "[FiSH] Initiating DH1080 key-exchange with %s - sending my public key", target.c_str());
-  notice(target, "DH1080_INIT " + myPublicKeyB64, DP_HELP);
   fish_data_t* fishData = FishKeys.contains(target) ? FishKeys[target] : new fish_data_t;
   fish_data_t* fishData = FishKeys.contains(target) ? FishKeys[target] : new fish_data_t;
   fishData->sharedKey.clear();
   fishData->sharedKey.clear();
+  putlog(LOG_MSGS, "*", "[FiSH] Initiating DH1080 key-exchange with %s - sending my public key", target.c_str());
+  notice(target, "DH1080_INIT " + myPublicKeyB64, DP_HELP);
   fishData->myPublicKeyB64 = myPublicKeyB64;
   fishData->myPublicKeyB64 = myPublicKeyB64;
   fishData->myPrivateKey = myPrivateKey;
   fishData->myPrivateKey = myPrivateKey;
   fishData->timestamp = now;
   fishData->timestamp = now;
   FishKeys[target] = fishData;
   FishKeys[target] = fishData;
 }
 }
+
+void set_fish_key(char *target, bd::String key)
+{
+  fish_data_t* fishData = FishKeys.contains(target) ? FishKeys[target] : NULL;
+
+  if (!key.length()) { //remove key
+    if (fishData) {
+      FishKeys.remove(target);
+      delete fishData;
+    }
+  } else { //set key
+    fishData = new fish_data_t;
+
+    if (key == "rand") {
+      // Set a RANDOM key
+      const size_t randomKeyLength = 32;
+      char *rand_key = (char*)my_calloc(1, randomKeyLength+1);
+      make_rand_str(rand_key, randomKeyLength);
+      fishData->sharedKey = rand_key;
+      free(rand_key);
+    } else {
+      fishData->sharedKey = key;
+    }
+
+    // Set the key
+    fishData->timestamp = now;
+    FishKeys[target] = fishData;
+  }
+}

+ 1 - 0
src/chanprog.h

@@ -34,6 +34,7 @@ void setup_HQ(int);
 void privmsg(bd::String target, bd::String msg, int idx);
 void privmsg(bd::String target, bd::String msg, int idx);
 void notice(bd::String target, bd::String msg, int idx);
 void notice(bd::String target, bd::String msg, int idx);
 void keyx(const bd::String& target);
 void keyx(const bd::String& target);
+void set_fish_key(char *, bd::String);
 
 
 extern struct chanset_t		*chanset, *chanset_default;
 extern struct chanset_t		*chanset, *chanset_default;
 extern char			admin[], origbotnick[HANDLEN + 1], origbotname[NICKLEN], jupenick[NICKLEN], botname[NICKLEN], *def_chanset;
 extern char			admin[], origbotnick[HANDLEN + 1], origbotname[NICKLEN], jupenick[NICKLEN], botname[NICKLEN], *def_chanset;

+ 13 - 3
src/mod/channels.mod/chanmisc.c

@@ -387,6 +387,17 @@ int channel_modify(char *result, struct chanset_t *chan, int items, char **item,
       }
       }
       chan->limitraise = atoi(item[i]);
       chan->limitraise = atoi(item[i]);
       chan->limit_prot = 0;
       chan->limit_prot = 0;
+    } else if (!strcmp(item[i], "fish-key")) {
+      i++;
+      if (i >= items) {
+        if (result)
+          strlcpy(result, "channel fish-key needs argument", RESULT_LEN);
+        return ERROR;
+      }
+      bd::String key(item[i]);
+      key.trim();
+      set_fish_key(chan->dname, key);
+      strlcpy(chan->fish_key, key.c_str(), sizeof(chan->fish_key));
 /*
 /*
     } else if (!strcmp(item[i], "revenge-mode")) {
     } else if (!strcmp(item[i], "revenge-mode")) {
       i++;
       i++;
@@ -565,7 +576,7 @@ int channel_modify(char *result, struct chanset_t *chan, int items, char **item,
         return ERROR;
         return ERROR;
       }
       }
       chan->protect_backup = atoi(item[i]);
       chan->protect_backup = atoi(item[i]);
-     
+    }
 
 
 /* Chanint template
 /* Chanint template
  *  } else if (!strcmp(item[i], "temp")) {
  *  } else if (!strcmp(item[i], "temp")) {
@@ -577,8 +588,6 @@ int channel_modify(char *result, struct chanset_t *chan, int items, char **item,
  *    }
  *    }
  *    chan->temp = atoi(item[i]);
  *    chan->temp = atoi(item[i]);
  */
  */
-    }
-
 
 
     else if (!strcmp(item[i], "+enforcebans"))
     else if (!strcmp(item[i], "+enforcebans"))
       chan->status |= CHAN_ENFORCEBANS;
       chan->status |= CHAN_ENFORCEBANS;
@@ -1009,6 +1018,7 @@ int channel_add(char *result, const char *newname, char *options, bool isdefault
     chan->groups = new bd::Array<bd::String>;
     chan->groups = new bd::Array<bd::String>;
     *(chan->groups) << "main";
     *(chan->groups) << "main";
     chan->protect_backup = 1;
     chan->protect_backup = 1;
+    chan->fish_key[0] = 0;
     chan->knock_flags = 0;
     chan->knock_flags = 0;
     chan->flood_lock_time = 120;
     chan->flood_lock_time = 120;
     chan->flood_exempt_mode = 0;
     chan->flood_exempt_mode = 0;

+ 1 - 0
src/mod/channels.mod/cmdschan.c

@@ -1185,6 +1185,7 @@ static void cmd_chaninfo(int idx, char *par)
     get_mode_protect(chan, work, sizeof(work));
     get_mode_protect(chan, work, sizeof(work));
     dprintf(idx, "Protect modes (chanmode): %s\n", work[0] ? work : "None");
     dprintf(idx, "Protect modes (chanmode): %s\n", work[0] ? work : "None");
     dprintf(idx, "Groups: %s\n", chan->groups && chan->groups->length() ? static_cast<bd::String>(chan->groups->join(" ")).c_str() : "None");
     dprintf(idx, "Groups: %s\n", chan->groups && chan->groups->length() ? static_cast<bd::String>(chan->groups->join(" ")).c_str() : "None");
+    dprintf(idx, "FiSH Key: %s\n", chan->fish_key[0] ? chan->fish_key : "not set");
 //    dprintf(idx, "Protect topic (topic)   : %s\n", chan->topic[0] ? chan->topic : "");
 //    dprintf(idx, "Protect topic (topic)   : %s\n", chan->topic[0] ? chan->topic : "");
 /* Chanchar template
 /* Chanchar template
  *  dprintf(idx, "String temp: %s\n", chan->temp[0] ? chan->temp : "NULL");
  *  dprintf(idx, "String temp: %s\n", chan->temp[0] ? chan->temp : "NULL");

+ 2 - 1
src/mod/channels.mod/userchan.c

@@ -719,7 +719,7 @@ flood-chan %d:%d flood-ctcp %d:%d flood-join %d:%d \
 flood-kick %d:%d flood-deop %d:%d flood-nick %d:%d flood-mjoin %d:%d \
 flood-kick %d:%d flood-deop %d:%d flood-nick %d:%d flood-mjoin %d:%d \
 closed-ban %d closed-invite %d closed-private %d ban-time %d \
 closed-ban %d closed-invite %d closed-private %d ban-time %d \
 exempt-time %d invite-time %d voice-non-ident %d auto-delay %d \
 exempt-time %d invite-time %d voice-non-ident %d auto-delay %d \
-flood-exempt %d flood-lock-time %d knock %d \
+flood-exempt %d flood-lock-time %d knock %d fish-key { %s } \
 %cmeankicks %cenforcebans %cdynamicbans %cuserbans %cbitch \
 %cmeankicks %cenforcebans %cdynamicbans %cuserbans %cbitch \
 %cprivate %ccycle %cinactive %cdynamicexempts %cuserexempts \
 %cprivate %ccycle %cinactive %cdynamicexempts %cuserexempts \
 %cdynamicinvites %cuserinvites %cnodesynch %cclosed %cvoice \
 %cdynamicinvites %cuserinvites %cnodesynch %cclosed %cvoice \
@@ -758,6 +758,7 @@ flood-exempt %d flood-lock-time %d knock %d \
         chan->flood_exempt_mode,
         chan->flood_exempt_mode,
         chan->flood_lock_time,
         chan->flood_lock_time,
         chan->knock_flags,
         chan->knock_flags,
+        chan->fish_key,
  	PLSMNS(channel_meankicks(chan)),
  	PLSMNS(channel_meankicks(chan)),
  	PLSMNS(channel_enforcebans(chan)),
  	PLSMNS(channel_enforcebans(chan)),
 	PLSMNS(channel_dynamicbans(chan)),
 	PLSMNS(channel_dynamicbans(chan)),

+ 14 - 14
src/mod/server.mod/cmdsserv.c

@@ -131,33 +131,33 @@ static void cmd_keyx(int idx, char *par) {
 static void cmd_setkey(int idx, char *par) {
 static void cmd_setkey(int idx, char *par) {
   putlog(LOG_CMDS, "*", "#%s# setkey %s", dcc[idx].nick, par);
   putlog(LOG_CMDS, "*", "#%s# setkey %s", dcc[idx].nick, par);
 
 
-  if (!par[0]) {
-    dprintf(idx, "Usage: setkey <nick|channel> [key]\n");
+  const bool target_is_chan = par[0] && strchr(CHANMETA, par[0]);
+
+  if (!par[0] || target_is_chan) {
+    dprintf(idx, "Usage: setkey <nick> [key|rand]\n");
+    if (target_is_chan) {
+      dprintf(idx, "Use 'chanset fish-key' to set a key for a channel.\n");
+    }
     return;
     return;
   }
   }
 
 
   char *target = newsplit(&par);
   char *target = newsplit(&par);
-  char *key = newsplit(&par);
+  char *newkey = newsplit(&par);
   bool have_key = FishKeys.contains(target);
   bool have_key = FishKeys.contains(target);
-  fish_data_t* fishData = NULL;
 
 
-  if (!key[0]) {
+  if (!newkey[0]) {
     // Clear the key
     // Clear the key
     if (have_key) {
     if (have_key) {
-      fishData = FishKeys[target];
-      FishKeys.remove(target);
-      delete fishData;
+      set_fish_key(target, "");
       dprintf(idx, "Key cleared for '%s'\n", target);
       dprintf(idx, "Key cleared for '%s'\n", target);
     } else {
     } else {
       dprintf(idx, "No key found for '%s'\n", target);
       dprintf(idx, "No key found for '%s'\n", target);
     }
     }
   } else {
   } else {
-    // Set the key
-    fishData = new fish_data_t;
-    fishData->sharedKey = key;
-    fishData->timestamp = now;
-    FishKeys[target] = fishData;
-    dprintf(idx, "Set key for '%s' to: %s", target, key);
+    // Set a new key
+    set_fish_key(target, newkey);
+    fish_data_t* fishData = FishKeys[target];
+    dprintf(idx, "Set key for '%s' to: %s", target, fishData->sharedKey.c_str());
   }
   }
   return;
   return;
 }
 }