Fixed channel MAC key setting in JOIN notify and command reply
[silc.git] / lib / silcclient / command_reply.c
index 2fec85c6b8da502d97636ec479a49b57de849f7b..7a7fa2b1028af8507218c5aff3c5a2e5c54391ad 100644 (file)
@@ -118,6 +118,7 @@ static void silc_client_command_process_error(SilcClientCommandContext cmd,
     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
     if (client_entry) {
       silc_client_remove_from_channels(client, conn, client_entry);
+      client_entry->internal.valid = FALSE;
       silc_client_del_client(client, conn, client_entry);
       silc_client_unref_client(client, conn, client_entry);
     }
@@ -947,6 +948,7 @@ SILC_FSM_STATE(silc_client_command_reply_kill)
   /* Remove the client */
   if (client_entry) {
     silc_client_remove_from_channels(client, conn, client_entry);
+    client_entry->internal.valid = FALSE;
     silc_client_del_client(client, conn, client_entry);
     silc_client_unref_client(client, conn, client_entry);
   }
@@ -1170,6 +1172,17 @@ SILC_FSM_STATE(silc_client_command_reply_join)
     silc_client_ref_channel(client, conn, channel);
   }
 
+  /* Get hmac */
+  hmac = silc_argument_get_arg_type(args, 11, NULL);
+  if (hmac && !silc_hmac_is_supported(hmac)) {
+    if (cmd->verbose)
+      SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
+         "Cannot join channel: Unsupported HMAC `%s'", hmac);
+    ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
+    silc_rwlock_unlock(channel->internal.lock);
+    goto out;
+  }
+
   /* Get the list count */
   tmp = silc_argument_get_arg_type(args, 12, &len);
   if (!tmp) {
@@ -1243,19 +1256,6 @@ SILC_FSM_STATE(silc_client_command_reply_join)
     }
   }
 
-  /* Get hmac */
-  hmac = silc_argument_get_arg_type(args, 11, NULL);
-  if (hmac) {
-    if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) {
-      if (cmd->verbose)
-       SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR,
-           "Cannot join channel: Unsupported HMAC `%s'", hmac);
-      ERROR_CALLBACK(SILC_STATUS_ERR_UNKNOWN_ALGORITHM);
-      silc_rwlock_unlock(channel->internal.lock);
-      goto out;
-    }
-  }
-
   /* Get channel mode */
   tmp = silc_argument_get_arg_type(args, 5, &len);
   if (tmp && len == 4)
@@ -1778,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 */
@@ -1803,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);