Преглед изворни кода

Merge branch 'ducch-fish-for-chans' into next

* ducch-fish-for-chans:
  * 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 година
родитељ
комит
14a37ee4a3

+ 4 - 3
doc/UPDATES

@@ -16,9 +16,10 @@ next
   * 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.

+ 2 - 1
doc/help.txt

@@ -1747,10 +1747,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

@@ -186,6 +186,7 @@ struct chanset_t {
   interval_t auto_delay;
   interval_t auto_delay;
   int knock_flags;
   int knock_flags;
   int protect_backup;
   int protect_backup;
+  char fish_key[50];
 /* Chanint template 
 /* Chanint template 
  *int temp;
  *int temp;
  */
  */

+ 46 - 3
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
@@ -967,3 +981,32 @@ void keyx(const bd::String &target) {
   fishData->timestamp = now;
   fishData->timestamp = now;
   FishKeys[target] = fishData;
   FishKeys[target] = fishData;
 }
 }
+
+void set_fish_key(char *target, char *key)
+{
+  fish_data_t* fishData = FishKeys.contains(target) ? FishKeys[target] : NULL;
+
+  if (!key || !key[0]) { //remove key
+    if (fishData) {
+      FishKeys.remove(target);
+      delete fishData;
+    }
+  } else { //set key
+    fishData = new fish_data_t;
+
+    if (!strcmp(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

@@ -35,6 +35,7 @@ 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 check_removed_server(bool = 1);
 void check_removed_server(bool = 1);
 void keyx(const bd::String& target);
 void keyx(const bd::String& target);
+void set_fish_key(char *, char *);
 
 
 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;

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

@@ -586,7 +586,15 @@ 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]);
-     
+    } else if (!strcmp(item[i], "fish-key")) {
+      i++;
+      if (i >= items) {
+        set_fish_key(chan->dname, "");
+        return ERROR;
+      }
+      set_fish_key(chan->dname, item[i]);
+      strlcpy(chan->fish_key, item[i], sizeof(chan->fish_key));
+    }
 
 
 /* Chanint template
 /* Chanint template
  *  } else if (!strcmp(item[i], "temp")) {
  *  } else if (!strcmp(item[i], "temp")) {
@@ -598,8 +606,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;
@@ -1030,6 +1036,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;

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

@@ -1257,6 +1257,8 @@ static void cmd_chaninfo(int idx, char *par)
     SHOW_INT("Protect-backup: ", chan->protect_backup, "Do!", "Don't!");
     SHOW_INT("Protect-backup: ", chan->protect_backup, "Do!", "Don't!");
     SHOW_INT("Voice-non-ident: ", chan->voice_non_ident, "Do!", "Don't!");
     SHOW_INT("Voice-non-ident: ", chan->voice_non_ident, "Do!", "Don't!");
 
 
+    dprintf(idx, "FiSH Key: %s\n", FishKeys.contains(chan->dname) && FishKeys[chan->dname]->sharedKey.length() ? FishKeys[chan->dname]->sharedKey.c_str() : "not set");
+
     dprintf(idx, "Flood settings:   chan ctcp join kick deop nick mjoin\n");
     dprintf(idx, "Flood settings:   chan ctcp join kick deop nick mjoin\n");
     dprintf(idx, "  number:          %3d  %3d  %3d  %3d  %3d  %3d  %3d\n",
     dprintf(idx, "  number:          %3d  %3d  %3d  %3d  %3d  %3d  %3d\n",
 	    chan->flood_pub_thr, chan->flood_ctcp_thr,
 	    chan->flood_pub_thr, chan->flood_ctcp_thr,

+ 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 closed-exempt %d ban-time %d \
 closed-ban %d closed-invite %d closed-private %d closed-exempt %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 \
@@ -759,6 +759,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;
 }
 }