Remove channel keys and hamcs after LEAVE command.
[silc.git] / lib / silcclient / command_reply.c
index a487cb95084bf8bcfe4eae239d2f1ada8b9a7ca3..910aab545be02edd180c36a8dbc8e3cca64077fb 100644 (file)
@@ -822,7 +822,7 @@ SILC_FSM_STATE(silc_client_command_reply_topic)
   SilcClient client = conn->client;
   SilcCommandPayload payload = state_context;
   SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcChannelEntry channel;
+  SilcChannelEntry channel = NULL;
   char *topic;
   SilcUInt32 len;
   SilcID id;
@@ -859,6 +859,7 @@ SILC_FSM_STATE(silc_client_command_reply_topic)
   silc_client_command_callback(cmd, channel, channel->topic);
 
  out:
+  silc_client_unref_channel(client, conn, channel);
   silc_fsm_next(fsm, silc_client_command_reply_processed);
   return SILC_FSM_CONTINUE;
 }
@@ -874,7 +875,7 @@ SILC_FSM_STATE(silc_client_command_reply_invite)
   SilcClient client = conn->client;
   SilcCommandPayload payload = state_context;
   SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcChannelEntry channel;
+  SilcChannelEntry channel = NULL;
   unsigned char *tmp;
   SilcUInt32 len;
   SilcArgumentPayload invite_args = NULL;
@@ -909,6 +910,7 @@ SILC_FSM_STATE(silc_client_command_reply_invite)
     silc_argument_payload_free(invite_args);
 
  out:
+  silc_client_unref_channel(client, conn, channel);
   silc_fsm_next(fsm, silc_client_command_reply_processed);
   return SILC_FSM_CONTINUE;
 }
@@ -1113,7 +1115,7 @@ silc_client_command_reply_join_resolved(SilcClient client,
   channel->internal.resolve_cmd_ident = 0;
   silc_client_unref_channel(client, conn, channel);
 
-  SILC_FSM_CALL_CONTINUE(&cmd->thread);
+  SILC_FSM_CALL_CONTINUE_SYNC(&cmd->thread);
 }
 
 
@@ -1263,8 +1265,13 @@ SILC_FSM_STATE(silc_client_command_reply_join)
   /* Get channel key and save it */
   tmp = silc_argument_get_arg_type(args, 7, &len);
   if (tmp) {
-    silc_buffer_set(&keyp, tmp, len);
-    silc_client_save_channel_key(client, conn, &keyp, channel);
+    /* If channel key already exists on the channel then while resolving
+       the user list we have already received new key from server.  Don't
+       replace it with this old key. */
+    if (!channel->internal.send_key) {
+      silc_buffer_set(&keyp, tmp, len);
+      silc_client_save_channel_key(client, conn, &keyp, channel);
+    }
   }
 
   /* Get topic */
@@ -1420,7 +1427,7 @@ SILC_FSM_STATE(silc_client_command_reply_cmode)
   SilcArgumentPayload args = silc_command_get_args(payload);
   unsigned char *tmp;
   SilcUInt32 mode;
-  SilcChannelEntry channel;
+  SilcChannelEntry channel = NULL;
   SilcUInt32 len;
   SilcPublicKey public_key = NULL;
   SilcID id;
@@ -1481,6 +1488,7 @@ SILC_FSM_STATE(silc_client_command_reply_cmode)
                               channel->channel_pubkeys, channel->user_limit);
 
  out:
+  silc_client_unref_channel(client, conn, channel);
   if (public_key)
     silc_pkcs_public_key_free(public_key);
   silc_fsm_next(fsm, silc_client_command_reply_processed);
@@ -1499,7 +1507,7 @@ SILC_FSM_STATE(silc_client_command_reply_cumode)
   SilcCommandPayload payload = state_context;
   SilcArgumentPayload args = silc_command_get_args(payload);
   SilcClientEntry client_entry;
-  SilcChannelEntry channel;
+  SilcChannelEntry channel = NULL;
   SilcChannelUser chu;
   unsigned char *modev;
   SilcUInt32 len, mode;
@@ -1556,6 +1564,7 @@ SILC_FSM_STATE(silc_client_command_reply_cumode)
   silc_client_unref_client(client, conn, client_entry);
 
  out:
+  silc_client_unref_channel(client, conn, channel);
   silc_fsm_next(fsm, silc_client_command_reply_processed);
   return SILC_FSM_CONTINUE;
 }
@@ -1570,7 +1579,7 @@ SILC_FSM_STATE(silc_client_command_reply_kick)
   SilcCommandPayload payload = state_context;
   SilcArgumentPayload args = silc_command_get_args(payload);
   SilcClientEntry client_entry;
-  SilcChannelEntry channel;
+  SilcChannelEntry channel = NULL;
   SilcID id;
 
   /* Sanity checks */
@@ -1609,6 +1618,7 @@ SILC_FSM_STATE(silc_client_command_reply_kick)
   silc_client_unref_client(client, conn, client_entry);
 
  out:
+  silc_client_unref_channel(client, conn, channel);
   silc_fsm_next(fsm, silc_client_command_reply_processed);
   return SILC_FSM_CONTINUE;
 }
@@ -1716,7 +1726,7 @@ SILC_FSM_STATE(silc_client_command_reply_ban)
   SilcClient client = conn->client;
   SilcCommandPayload payload = state_context;
   SilcArgumentPayload args = silc_command_get_args(payload);
-  SilcChannelEntry channel;
+  SilcChannelEntry channel = NULL;
   unsigned char *tmp;
   SilcUInt32 len;
   SilcArgumentPayload invite_args = NULL;
@@ -1751,6 +1761,7 @@ SILC_FSM_STATE(silc_client_command_reply_ban)
     silc_argument_payload_free(invite_args);
 
  out:
+  silc_client_unref_channel(client, conn, channel);
   silc_fsm_next(fsm, silc_client_command_reply_processed);
   return SILC_FSM_CONTINUE;
 }
@@ -1767,6 +1778,8 @@ SILC_FSM_STATE(silc_client_command_reply_leave)
   SilcCommandPayload payload = state_context;
   SilcArgumentPayload args = silc_command_get_args(payload);
   SilcChannelEntry channel;
+  SilcCipher key;
+  SilcHmac hmac;
   SilcID id;
 
   /* Sanity checks */
@@ -1792,6 +1805,32 @@ SILC_FSM_STATE(silc_client_command_reply_leave)
   /* Notify application */
   silc_client_command_callback(cmd, channel);
 
+  /* Remove old keys and stuff.  The channel may remain even after leaving
+     but we want to remove these always. */
+  if (channel->internal.send_key)
+    silc_cipher_free(channel->internal.send_key);
+  channel->internal.send_key = NULL;
+  if (channel->internal.receive_key)
+    silc_cipher_free(channel->internal.receive_key);
+  channel->internal.receive_key = NULL;
+  if (channel->internal.hmac)
+    silc_hmac_free(channel->internal.hmac);
+  channel->internal.hmac = NULL;
+  if (channel->internal.old_channel_keys) {
+    silc_dlist_start(channel->internal.old_channel_keys);
+    while ((key = silc_dlist_get(channel->internal.old_channel_keys)))
+      silc_cipher_free(key);
+    silc_dlist_uninit(channel->internal.old_channel_keys);
+  }
+  channel->internal.old_channel_keys = NULL;
+  if (channel->internal.old_hmacs) {
+    silc_dlist_start(channel->internal.old_hmacs);
+    while ((hmac = silc_dlist_get(channel->internal.old_hmacs)))
+      silc_hmac_free(hmac);
+    silc_dlist_uninit(channel->internal.old_hmacs);
+  }
+  channel->internal.old_hmacs = NULL;
+
   /* Now delete the channel. */
   silc_client_empty_channel(client, conn, channel);
   silc_client_del_channel(client, conn, channel);