X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcclient%2Fcommand_reply.c;h=ee71a4264b0c6fa3d7f107fd98fc2a72661bfa02;hb=4d3f87f2f076bd332fa73f878fe198b7a94671b5;hp=39e0f92837e71ecabbb53d3f1ea81e5972e7a900;hpb=03df183a5ada5bad0eed82b78d93ca6f4fd51213;p=crypto.git diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index 39e0f928..ee71a426 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -42,12 +42,12 @@ do { \ SILC_LOG_DEBUG(("%s", silc_get_command_name(cmd->cmd))); \ if (cmd->error != SILC_STATUS_OK) { \ if (cmd->verbose) \ - SAY(cmd->conn->client, cmd->conn, SILC_CLIENT_MESSAGE_ERROR, \ + SAY(cmd->conn->client, cmd->conn, SILC_CLIENT_MESSAGE_COMMAND_ERROR, \ msg "%s", silc_get_status_message(cmd->error)); \ ERROR_CALLBACK(cmd->error); \ silc_client_command_process_error(cmd, state_context, cmd->error); \ silc_fsm_next(fsm, silc_client_command_reply_processed); \ - SILC_FSM_CONTINUE; \ + return SILC_FSM_CONTINUE; \ } /* Check for correct arguments */ @@ -56,7 +56,7 @@ do { \ silc_argument_get_arg_num(args) > max) { \ ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); \ silc_fsm_next(fsm, silc_client_command_reply_processed); \ - SILC_FSM_CONTINUE; \ + return SILC_FSM_CONTINUE; \ } #define SAY cmd->conn->client->internal->ops->say @@ -127,7 +127,7 @@ static void silc_client_command_process_error(SilcClientCommandContext cmd, if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID) { SilcChannelEntry channel; - /* Remove unknown client entry from cache */ + /* Remove unknown channel entry from cache */ if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) return; @@ -143,7 +143,7 @@ static void silc_client_command_process_error(SilcClientCommandContext cmd, if (cmd->error == SILC_STATUS_ERR_NO_SUCH_SERVER_ID) { SilcServerEntry server_entry; - /* Remove unknown client entry from cache */ + /* Remove unknown server entry from cache */ if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL)) return; @@ -174,7 +174,7 @@ SILC_FSM_STATE(silc_client_command_reply) silc_packet_free(packet); if (!payload) { SILC_LOG_DEBUG(("Bad command reply packet")); - SILC_FSM_FINISH; + return SILC_FSM_FINISH; } cmd_ident = silc_command_get_ident(payload); @@ -196,15 +196,18 @@ SILC_FSM_STATE(silc_client_command_reply) SILC_LOG_DEBUG(("Unknown command reply %s, ident %d", silc_get_command_name(command), cmd_ident)); silc_command_payload_free(payload); - SILC_FSM_FINISH; + return SILC_FSM_FINISH; } - /* Signal command thread that command reply has arrived */ + /* Signal command thread that command reply has arrived. We continue + command reply processing synchronously because we save the command + payload into state context. No other reply may arrive to this command + while we're processing this reply. */ silc_fsm_set_state_context(&cmd->thread, payload); silc_fsm_next(&cmd->thread, silc_client_command_reply_process); silc_fsm_continue_sync(&cmd->thread); - SILC_FSM_FINISH; + return SILC_FSM_FINISH; } /* Wait here for command reply to arrive from remote host */ @@ -218,8 +221,8 @@ SILC_FSM_STATE(silc_client_command_reply_wait) /** Wait for command reply */ silc_fsm_set_state_context(fsm, NULL); silc_fsm_next_later(fsm, silc_client_command_reply_timeout, - cmd->cmd != SILC_COMMAND_PING ? 25 : 60, 0); - SILC_FSM_WAIT; + cmd->cmd != SILC_COMMAND_PING ? 40 : 60, 0); + return SILC_FSM_WAIT; } /* Timeout occurred while waiting command reply */ @@ -235,7 +238,7 @@ SILC_FSM_STATE(silc_client_command_reply_timeout) silc_list_del(conn->internal->pending_commands, cmd); if (!cmd->called) ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT); - SILC_FSM_FINISH; + return SILC_FSM_FINISH; } SILC_LOG_DEBUG(("Command %s timeout", silc_get_command_name(cmd->cmd))); @@ -243,7 +246,7 @@ SILC_FSM_STATE(silc_client_command_reply_timeout) /* Timeout, reply not received in timely fashion */ silc_list_del(conn->internal->pending_commands, cmd); ERROR_CALLBACK(SILC_STATUS_ERR_TIMEDOUT); - SILC_FSM_FINISH; + return SILC_FSM_FINISH; } /* Process received command reply payload */ @@ -365,10 +368,10 @@ SILC_FSM_STATE(silc_client_command_reply_process) silc_fsm_next(fsm, silc_client_command_reply_service); break; default: - SILC_FSM_FINISH; + return SILC_FSM_FINISH; } - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /* Completes command reply processing */ @@ -383,7 +386,7 @@ SILC_FSM_STATE(silc_client_command_reply_processed) if (cmd->status == SILC_STATUS_OK || cmd->status == SILC_STATUS_LIST_END || SILC_STATUS_IS_ERROR(cmd->status)) - SILC_FSM_FINISH; + return SILC_FSM_FINISH; /* Add back to pending command reply list */ silc_mutex_lock(conn->internal->lock); @@ -393,7 +396,7 @@ SILC_FSM_STATE(silc_client_command_reply_processed) /** Wait more command payloads */ silc_fsm_next(fsm, silc_client_command_reply_wait); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /******************************** WHOIS *************************************/ @@ -480,6 +483,8 @@ SILC_FSM_STATE(silc_client_command_reply_whois) nickname, username, realname, mode); } + silc_rwlock_wrlock(client_entry->internal.lock); + if (fingerprint && fingerprint_len == sizeof(client_entry->fingerprint)) memcpy(client_entry->fingerprint, fingerprint, fingerprint_len); @@ -491,6 +496,8 @@ SILC_FSM_STATE(silc_client_command_reply_whois) client_entry->attrs = silc_attribute_payload_parse(tmp, len); } + silc_rwlock_unlock(client_entry->internal.lock); + /* Parse channel and channel user mode list */ if (has_channels) { channel_list = silc_channel_payload_parse_list(silc_buffer_data(&channels), @@ -507,13 +514,13 @@ SILC_FSM_STATE(silc_client_command_reply_whois) silc_client_unref_client(client, conn, client_entry); if (has_channels) { - silc_dlist_uninit(channel_list); + silc_channel_payload_list_free(channel_list); silc_free(umodes); } out: silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /******************************** WHOWAS ************************************/ @@ -561,7 +568,7 @@ SILC_FSM_STATE(silc_client_command_reply_whowas) out: silc_client_unref_client(client, conn, client_entry); silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /******************************** IDENTIFY **********************************/ @@ -670,14 +677,15 @@ SILC_FSM_STATE(silc_client_command_reply_identify) } /* Notify application */ - silc_client_command_callback(cmd, channel_entry, name, info); + silc_client_command_callback(cmd, channel_entry, + channel_entry->channel_name, info); silc_client_unref_channel(client, conn, channel_entry); break; } out: silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************** NICK ************************************/ @@ -718,21 +726,26 @@ SILC_FSM_STATE(silc_client_command_reply_nick) goto out; } + silc_rwlock_wrlock(conn->local_entry->internal.lock); + /* Change the nickname */ old_client_id = *conn->local_id; if (!silc_client_change_nickname(client, conn, conn->local_entry, nick, &id.u.client_id, idp, idp_len)) { ERROR_CALLBACK(SILC_STATUS_ERR_BAD_NICKNAME); + silc_rwlock_unlock(conn->local_entry->internal.lock); goto out; } + silc_rwlock_unlock(conn->local_entry->internal.lock); + /* Notify application */ silc_client_command_callback(cmd, conn->local_entry, conn->local_entry->nickname, &old_client_id); out: silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************** LIST ************************************/ @@ -758,7 +771,7 @@ SILC_FSM_STATE(silc_client_command_reply_list) /* There were no channels in the network. */ silc_client_command_callback(cmd, NULL, NULL, NULL, 0); silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } CHECK_ARGS(3, 5); @@ -789,12 +802,13 @@ SILC_FSM_STATE(silc_client_command_reply_list) } /* Notify application */ - silc_client_command_callback(cmd, channel_entry, name, topic, usercount); + silc_client_command_callback(cmd, channel_entry, channel_entry->channel_name, + topic, usercount); out: silc_client_unref_channel(client, conn, channel_entry); silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************* TOPIC ************************************/ @@ -808,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; @@ -830,6 +844,8 @@ SILC_FSM_STATE(silc_client_command_reply_topic) goto out; } + silc_rwlock_wrlock(channel->internal.lock); + /* Take topic */ topic = silc_argument_get_arg_type(args, 3, &len); if (topic) { @@ -837,12 +853,15 @@ SILC_FSM_STATE(silc_client_command_reply_topic) channel->topic = silc_memdup(topic, len); } + silc_rwlock_unlock(channel->internal.lock); + /* Notify application */ 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); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************* INVITE ***********************************/ @@ -856,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; @@ -891,8 +910,9 @@ 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); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************** KILL ************************************/ @@ -933,7 +953,7 @@ SILC_FSM_STATE(silc_client_command_reply_kill) out: silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************** INFO ************************************/ @@ -994,7 +1014,7 @@ SILC_FSM_STATE(silc_client_command_reply_info) out: silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************** STATS ***********************************/ @@ -1051,7 +1071,7 @@ SILC_FSM_STATE(silc_client_command_reply_stats) out: silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************** PING ************************************/ @@ -1075,7 +1095,7 @@ SILC_FSM_STATE(silc_client_command_reply_ping) silc_client_command_callback(cmd); silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************** JOIN ************************************/ @@ -1091,6 +1111,29 @@ 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); @@ -1152,7 +1195,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; } @@ -1185,10 +1228,11 @@ SILC_FSM_STATE(silc_client_command_reply_join) } silc_buffer_set(&client_mode_list, tmp, len); + silc_rwlock_wrlock(channel->internal.lock); + /* 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; @@ -1203,17 +1247,22 @@ SILC_FSM_STATE(silc_client_command_reply_join) /* Get client entry */ client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id); - if (!client_entry) - continue; - - /* Join client to the channel */ - silc_client_add_to_channel(client, conn, channel, client_entry, mode); + if (client_entry && client_entry->internal.valid) { + /* Join client to the channel */ + silc_rwlock_wrlock(client_entry->internal.lock); + silc_client_add_to_channel(client, conn, channel, client_entry, mode); + silc_rwlock_unlock(client_entry->internal.lock); + } silc_client_unref_client(client, conn, client_entry); - if (!silc_buffer_pull(&client_id_list, idp_len)) + if (!silc_buffer_pull(&client_id_list, idp_len)) { + silc_rwlock_unlock(channel->internal.lock); goto out; - if (!silc_buffer_pull(&client_mode_list, 4)) + } + if (!silc_buffer_pull(&client_mode_list, 4)) { + silc_rwlock_unlock(channel->internal.lock); goto out; + } } /* Get hmac */ @@ -1221,16 +1270,17 @@ SILC_FSM_STATE(silc_client_command_reply_join) if (hmac) { if (!silc_hmac_alloc(hmac, NULL, &channel->internal.hmac)) { if (cmd->verbose) - SAY(client, conn, SILC_CLIENT_MESSAGE_ERROR, + 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, NULL); - if (tmp) + tmp = silc_argument_get_arg_type(args, 5, &len); + if (tmp && len == 4) SILC_GET32_MSB(mode, tmp); channel->mode = mode; @@ -1267,18 +1317,19 @@ SILC_FSM_STATE(silc_client_command_reply_join) /* Get channel public key list */ tmp = silc_argument_get_arg_type(args, 16, &len); if (tmp) - channel->channel_pubkeys = - silc_argument_list_parse_decoded(tmp, len, SILC_ARGUMENT_PUBLIC_KEY); + silc_client_channel_save_public_keys(channel, tmp, len, FALSE); /* Set current channel */ conn->current_channel = channel; + silc_rwlock_unlock(channel->internal.lock); + cipher = (channel->internal.send_key ? silc_cipher_get_name(channel->internal.send_key) : NULL); silc_hash_table_list(channel->user_list, &htl); /* Notify application */ - silc_client_command_callback(cmd, channel_name, channel, mode, &htl, + silc_client_command_callback(cmd, channel->channel_name, channel, mode, &htl, topic, cipher, hmac, channel->founder_key, channel->channel_pubkeys, channel->user_limit); @@ -1287,7 +1338,7 @@ SILC_FSM_STATE(silc_client_command_reply_join) out: silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************** MOTD ************************************/ @@ -1341,7 +1392,7 @@ SILC_FSM_STATE(silc_client_command_reply_motd) out: silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************** UMODE ***********************************/ @@ -1368,14 +1419,16 @@ SILC_FSM_STATE(silc_client_command_reply_umode) } SILC_GET32_MSB(mode, tmp); + silc_rwlock_wrlock(conn->local_entry->internal.lock); conn->local_entry->mode = mode; + silc_rwlock_unlock(conn->local_entry->internal.lock); /* Notify application */ silc_client_command_callback(cmd, mode); out: silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************** CMODE ***********************************/ @@ -1391,10 +1444,9 @@ 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; - SilcDList channel_pubkeys = NULL; SilcID id; /* Sanity checks */ @@ -1414,21 +1466,20 @@ SILC_FSM_STATE(silc_client_command_reply_cmode) goto out; } + /* Get founder public key */ + tmp = silc_argument_get_arg_type(args, 4, &len); + if (tmp) + silc_public_key_payload_decode(tmp, len, &public_key); + /* Get channel mode */ tmp = silc_argument_get_arg_type(args, 3, &len); if (!tmp || len != 4) { ERROR_CALLBACK(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } - - /* Save the mode */ SILC_GET32_MSB(mode, tmp); - channel->mode = mode; - /* Get founder public key */ - tmp = silc_argument_get_arg_type(args, 4, &len); - if (tmp) - silc_public_key_payload_decode(tmp, len, &public_key); + silc_rwlock_wrlock(channel->internal.lock); /* Get user limit */ tmp = silc_argument_get_arg_type(args, 6, &len); @@ -1440,20 +1491,39 @@ SILC_FSM_STATE(silc_client_command_reply_cmode) /* Get channel public key(s) */ tmp = silc_argument_get_arg_type(args, 5, &len); if (tmp) - channel_pubkeys = - silc_argument_list_parse_decoded(tmp, len, SILC_ARGUMENT_PUBLIC_KEY); + silc_client_channel_save_public_keys(channel, tmp, len, FALSE); + else if (channel->mode & SILC_CHANNEL_MODE_CHANNEL_AUTH) + silc_client_channel_save_public_keys(channel, NULL, 0, TRUE); + + /* Save the mode */ + channel->mode = mode; + + silc_rwlock_unlock(channel->internal.lock); /* Notify application */ silc_client_command_callback(cmd, channel, mode, public_key, - channel_pubkeys, channel->user_limit); + channel->channel_pubkeys, channel->user_limit); + + silc_rwlock_wrlock(channel->internal.lock); - silc_argument_list_free(channel_pubkeys, SILC_ARGUMENT_PUBLIC_KEY); + /* 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); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************** CUMODE **********************************/ @@ -1468,7 +1538,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; @@ -1513,9 +1583,11 @@ SILC_FSM_STATE(silc_client_command_reply_cumode) } /* Save the mode */ + silc_rwlock_wrlock(channel->internal.lock); chu = silc_client_on_channel(channel, client_entry); if (chu) chu->mode = mode; + silc_rwlock_unlock(channel->internal.lock); /* Notify application */ silc_client_command_callback(cmd, mode, channel, client_entry); @@ -1523,8 +1595,9 @@ 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); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************** KICK ************************************/ @@ -1537,7 +1610,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 */ @@ -1576,8 +1649,9 @@ 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); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /******************************** SILCOPER **********************************/ @@ -1592,11 +1666,14 @@ SILC_FSM_STATE(silc_client_command_reply_silcoper) CHECK_STATUS("Cannot change mode: "); CHECK_ARGS(1, 1); + /* Set user mode */ + cmd->conn->local_entry->mode |= SILC_UMODE_ROUTER_OPERATOR; + /* Notify application */ silc_client_command_callback(cmd); silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************** OPER ************************************/ @@ -1611,11 +1688,14 @@ SILC_FSM_STATE(silc_client_command_reply_oper) CHECK_STATUS("Cannot change mode: "); CHECK_ARGS(1, 1); + /* Set user mode */ + cmd->conn->local_entry->mode |= SILC_UMODE_SERVER_OPERATOR; + /* Notify application */ silc_client_command_callback(cmd); silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************* DETACH ***********************************/ @@ -1646,7 +1726,7 @@ SILC_FSM_STATE(silc_client_command_reply_detach) out: silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************** WATCH ***********************************/ @@ -1665,7 +1745,7 @@ SILC_FSM_STATE(silc_client_command_reply_watch) silc_client_command_callback(cmd); silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /*********************************** BAN ************************************/ @@ -1677,7 +1757,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; @@ -1712,8 +1792,9 @@ 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); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************** LEAVE ***********************************/ @@ -1759,7 +1840,7 @@ SILC_FSM_STATE(silc_client_command_reply_leave) out: silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************* USERS ************************************/ @@ -1812,8 +1893,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; @@ -1877,6 +1958,8 @@ SILC_FSM_STATE(silc_client_command_reply_users) SILC_LOG_DEBUG(("channel %s, %d users", channel->channel_name, list_count)); + silc_rwlock_wrlock(channel->internal.lock); + /* Cache the received Client ID's and modes. */ for (i = 0; i < list_count; i++) { SILC_GET16_MSB(idp_len, client_id_list.data + 2); @@ -1890,16 +1973,25 @@ SILC_FSM_STATE(silc_client_command_reply_users) /* Save the client on this channel. Unknown clients are ignored as they clearly do not exist since the resolving didn't find them. */ client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id); - if (client_entry) + if (client_entry && client_entry->internal.valid) { + silc_rwlock_wrlock(client_entry->internal.lock); silc_client_add_to_channel(client, conn, channel, client_entry, mode); + silc_rwlock_unlock(client_entry->internal.lock); + } silc_client_unref_client(client, conn, client_entry); - if (!silc_buffer_pull(&client_id_list, idp_len)) + if (!silc_buffer_pull(&client_id_list, idp_len)) { + silc_rwlock_unlock(channel->internal.lock); goto out; - if (!silc_buffer_pull(&client_mode_list, 4)) + } + if (!silc_buffer_pull(&client_mode_list, 4)) { + silc_rwlock_unlock(channel->internal.lock); goto out; + } } + silc_rwlock_unlock(channel->internal.lock); + /* Notify application */ silc_hash_table_list(channel->user_list, &htl); silc_client_command_callback(cmd, channel, &htl); @@ -1908,7 +2000,7 @@ SILC_FSM_STATE(silc_client_command_reply_users) out: silc_client_unref_channel(client, conn, channel); silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************** GETKEY **********************************/ @@ -1947,6 +2039,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; } @@ -1959,6 +2053,8 @@ SILC_FSM_STATE(silc_client_command_reply_getkey) goto out; } + silc_rwlock_wrlock(client_entry->internal.lock); + /* Save fingerprint */ if (!client_entry->fingerprint) silc_hash_make(conn->internal->sha1hash, tmp + 4, len - 4, @@ -1968,6 +2064,8 @@ SILC_FSM_STATE(silc_client_command_reply_getkey) public_key = NULL; } + silc_rwlock_unlock(client_entry->internal.lock); + /* Notify application */ silc_client_command_callback(cmd, SILC_ID_CLIENT, client_entry, client_entry->public_key); @@ -1980,11 +2078,15 @@ SILC_FSM_STATE(silc_client_command_reply_getkey) goto out; } + silc_rwlock_wrlock(server_entry->internal.lock); + if (!server_entry->public_key) { server_entry->public_key = public_key; public_key = NULL; } + silc_rwlock_unlock(server_entry->internal.lock); + /* Notify application */ silc_client_command_callback(cmd, SILC_ID_SERVER, server_entry, server_entry->public_key); @@ -1995,7 +2097,7 @@ SILC_FSM_STATE(silc_client_command_reply_getkey) if (public_key) silc_pkcs_public_key_free(public_key); silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /********************************** SERVICE *********************************/ @@ -2024,7 +2126,7 @@ SILC_FSM_STATE(silc_client_command_reply_service) silc_client_command_callback(cmd, service_list, name); silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; } /*********************************** QUIT ***********************************/ @@ -2034,5 +2136,5 @@ SILC_FSM_STATE(silc_client_command_reply_service) SILC_FSM_STATE(silc_client_command_reply_quit) { silc_fsm_next(fsm, silc_client_command_reply_processed); - SILC_FSM_CONTINUE; + return SILC_FSM_CONTINUE; }