X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=lib%2Fsilcclient%2Fcommand_reply.c;h=ede887535fdcdc97b6219d0c8d73f11b45867021;hp=61e4d73a082dea7df0a86f0d6791a9576612b313;hb=HEAD;hpb=52e57c880aba9c5e89f59d962eb9af75670b76e0 diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index 61e4d73a..ede88753 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -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); } @@ -822,7 +823,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 +860,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 +876,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 +911,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; } @@ -945,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); } @@ -1109,11 +1113,34 @@ silc_client_command_reply_join_resolved(SilcClient client, { SilcClientCommandContext cmd = context; SilcChannelEntry channel = cmd->context; + SilcCommandPayload payload = silc_fsm_get_state_context(&cmd->thread); + SilcArgumentPayload args = silc_command_get_args(payload); + SilcUInt32 list_count; + unsigned char *tmp; + char msg[512]; + + if (!clients) { + silc_snprintf(msg, sizeof(msg), "Error resolving channel %s user list", + channel->channel_name); + SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, msg); + } else { + tmp = silc_argument_get_arg_type(args, 12, NULL); + if (tmp) { + SILC_GET32_MSB(list_count, tmp); + if (list_count - silc_dlist_count(clients) > 5) { + silc_snprintf(msg, sizeof(msg), + "Channel %s user list was not fully resolved. " + "The channel may not be fully synced.", + channel->channel_name); + SAY(client, conn, SILC_CLIENT_MESSAGE_WARNING, msg); + } + } + } 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); } @@ -1170,7 +1197,7 @@ SILC_FSM_STATE(silc_client_command_reply_join) /* Get the list count */ tmp = silc_argument_get_arg_type(args, 12, &len); - if (!tmp) { + if (!tmp || len != 4) { ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } @@ -1208,7 +1235,6 @@ SILC_FSM_STATE(silc_client_command_reply_join) /* Add clients we received in the reply to the channel */ for (i = 0; i < list_count; i++) { SilcUInt16 idp_len; - SilcUInt32 mode; SilcID id; SilcClientEntry client_entry; @@ -1263,8 +1289,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 +1451,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; @@ -1480,7 +1511,22 @@ SILC_FSM_STATE(silc_client_command_reply_cmode) silc_client_command_callback(cmd, channel, mode, public_key, channel->channel_pubkeys, channel->user_limit); + silc_rwlock_wrlock(channel->internal.lock); + + /* If founder key changed, update it */ + if (public_key && + (!channel->founder_key || + !silc_pkcs_public_key_compare(public_key, channel->founder_key))) { + if (channel->founder_key) + silc_pkcs_public_key_free(channel->founder_key); + channel->founder_key = public_key; + public_key = NULL; + } + + silc_rwlock_unlock(channel->internal.lock); + 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 +1545,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 +1602,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 +1617,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 +1656,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 +1764,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 +1799,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 +1816,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 +1843,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); @@ -1851,8 +1928,8 @@ SILC_FSM_STATE(silc_client_command_reply_users) SilcCommandPayload payload = state_context; SilcArgumentPayload args = silc_command_get_args(payload); unsigned char *tmp; - SilcUInt32 tmp_len, list_count; - SilcUInt16 idp_len, mode; + SilcUInt32 tmp_len, list_count, mode; + SilcUInt16 idp_len; SilcHashTableList htl; SilcBufferStruct client_id_list, client_mode_list; SilcChannelEntry channel = NULL; @@ -1997,6 +2074,8 @@ SILC_FSM_STATE(silc_client_command_reply_getkey) goto out; } if (!silc_public_key_payload_decode(tmp, len, &public_key)) { + SAY(client, conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, + "Cannot decode public key: malformed/unsupported public key"); ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; }