From 8d1a8bbf644f67f86e7e1b95cf51d6d49406251f Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Sun, 16 Sep 2001 14:53:25 +0000 Subject: [PATCH] updates. --- CHANGES | 23 +++++++++++ TODO | 9 ----- apps/silcd/command.c | 38 +++++++++++++++++- apps/silcd/server.c | 11 +++-- lib/silcclient/client.c | 1 + lib/silcclient/client_notify.c | 15 +++---- lib/silcclient/command.c | 73 ++++++++++++++++++++++++++++++---- lib/silcclient/command_reply.c | 4 +- lib/silcclient/idlist.c | 12 +++++- lib/silcclient/idlist.h | 3 +- lib/silcske/silcske.c | 2 + 11 files changed, 155 insertions(+), 36 deletions(-) diff --git a/CHANGES b/CHANGES index 0173db91..3cae5b3b 100644 --- a/CHANGES +++ b/CHANGES @@ -11,6 +11,29 @@ Sun Sep 16 12:32:58 EEST 2001 Pekka Riikonen * Print the selected security properties to the log files in the server. Affected file silcd/protocol.c. + * Add SKE's reference counter even if calling the completion + callback manually. Otherwise it goes negative, although it + does not cause any problems. The affected file is + lib/silcske/silcske.c. + + * Remove the client entry with short timeout after giving the + KILL command. Affected file lib/silcclient/command.c. + + * Fixed to send error reply in WHOIS and IDENTIFY commands in + case all found clients are already disconnected (WHOWAS would + found them) in the server. Affected file silcd/command.c. + + * Update the last_receive (time of last data received) to be + updated only when received private or channel message so that + the idle time showed in WHOIS makes more sense. + + * Added boolean field `valid' in to the SilcClientEntry in the + client library to indicate whether the entry is valid or not. + This fixes the nickname change bug on channel when changing + the nickname to be same than the old (like nick to Nick) the + nickname formatter doesn't set the new nick anymore to Nick@host. + Affected file lib/silcclient/idlist.[ch]. + Sat Sep 15 13:29:17 EEST 2001 Pekka Riikonen * Check that the public key exists in the GETKEY command before diff --git a/TODO b/TODO index aca1fcc9..6ff015e3 100644 --- a/TODO +++ b/TODO @@ -38,13 +38,6 @@ TODO/bugs in Irssi SILC client TODO/bugs In SILC Client Library ================================ - o Someone changing nickname on the channel from nick to Nick will cause - that the new nick becomes Nick@host, because the old nick is not - removed from the cache before adding the new one. This is because - of the way NICK_CHANGE notify is handled. This should be fixed so - that if the old nick is to be removed the new nick will *replace* - the old one. - o JOIN command's argument handling is buggy. See the XXX in the code. @@ -53,8 +46,6 @@ TODO/bugs In SILC Server o Add perhaps /var/run/silcd.pid for PID information for the server. - o Update idle times only for private/channel messaegs. - o Add a timeout to handling incmoing JOIN commands. It should be enforced that JOIN command is executed only once in a second or two seconds. Now it is possible to accept n incoming JOIN commands diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 0125c55e..567a0f92 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -678,6 +678,24 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd, if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED) len++; + if (len == 0 && clients_count) { + entry = clients[0]; + if (entry->nickname) { + silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS, + SILC_STATUS_ERR_NO_SUCH_NICK, + 3, entry->nickname, + strlen(entry->nickname)); + } else { + SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT); + silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOIS, + SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, + 2, idp->data, idp->len); + silc_buffer_free(idp); + } + + return; + } + status = SILC_STATUS_OK; if (len > 1) status = SILC_STATUS_LIST_START; @@ -1629,6 +1647,24 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd, if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED) len++; + if (len == 0 && clients_count) { + entry = clients[0]; + if (entry->nickname) { + silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY, + SILC_STATUS_ERR_NO_SUCH_NICK, + 3, entry->nickname, + strlen(entry->nickname)); + } else { + SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT); + silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY, + SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, + 2, idp->data, idp->len); + silc_buffer_free(idp); + } + + return; + } + if (len > 1) status = SILC_STATUS_LIST_START; @@ -1639,7 +1675,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd, if (clients_count == 1) { SilcBuffer idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT); silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY, - SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, + SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 2, idp->data, idp->len); silc_buffer_free(idp); } diff --git a/apps/silcd/server.c b/apps/silcd/server.c index 02b1cc89..5c93bed5 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -772,7 +772,7 @@ SILC_TASK_CALLBACK(silc_server_connect_to_router_second) silc_free(ctx->dest_id); silc_free(ctx); silc_schedule_task_del_by_callback(server->schedule, - silc_server_failure_callback); + silc_server_failure_callback); silc_server_disconnect_remote(server, sock, "Server closed connection: " "Key exchange failed"); return; @@ -1215,6 +1215,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) SilcServer server = (SilcServer)ctx->server; SilcSocketConnection sock = ctx->sock; SilcServerHBContext hb_context; + SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data; void *id_entry = NULL; SILC_LOG_DEBUG(("Start")); @@ -1241,6 +1242,8 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) return; } + entry->data.last_receive = time(NULL); + switch (ctx->conn_type) { case SILC_SOCKET_TYPE_CLIENT: { @@ -1363,7 +1366,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) out: silc_schedule_task_del_by_callback(server->schedule, - silc_server_failure_callback); + silc_server_failure_callback); silc_protocol_free(protocol); if (ctx->packet) silc_packet_context_free(ctx->packet); @@ -1493,7 +1496,6 @@ SILC_TASK_CALLBACK(silc_server_packet_process) /* Get keys and stuff from ID entry */ idata = (SilcIDListData)sock->user_data; if (idata) { - idata->last_receive = time(NULL); cipher = idata->receive_key; hmac = idata->hmac_receive; } @@ -1673,6 +1675,7 @@ void silc_server_packet_parse_type(SilcServer server, SilcPacketContext *packet) { SilcPacketType type = packet->type; + SilcIDListData idata = (SilcIDListData)sock->user_data; SILC_LOG_DEBUG(("Parsing packet type %d", type)); @@ -1750,6 +1753,7 @@ void silc_server_packet_parse_type(SilcServer server, SILC_LOG_DEBUG(("Channel Message packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; + idata->last_receive = time(NULL); silc_server_channel_message(server, sock, packet); break; @@ -1803,6 +1807,7 @@ void silc_server_packet_parse_type(SilcServer server, SILC_LOG_DEBUG(("Private Message packet")); if (packet->flags & SILC_PACKET_FLAG_LIST) break; + idata->last_receive = time(NULL); silc_server_private_message(server, sock, packet); break; diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index 681d9e0e..a5b3f815 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -1388,6 +1388,7 @@ void silc_client_receive_new_id(SilcClient client, conn->local_entry->hostname = strdup(client->hostname); conn->local_entry->server = strdup(conn->remote_host); conn->local_entry->id = conn->local_id; + conn->local_entry->valid = TRUE; /* Put it to the ID cache */ silc_idcache_add(conn->client_cache, strdup(conn->nickname), conn->local_id, diff --git a/lib/silcclient/client_notify.c b/lib/silcclient/client_notify.c index a0799173..82a0654f 100644 --- a/lib/silcclient/client_notify.c +++ b/lib/silcclient/client_notify.c @@ -2,7 +2,7 @@ client_notify.c - Author: Pekka Riikonen + Author: Pekka Riikonen Copyright (C) 1997 - 2001 Pekka Riikonen @@ -123,7 +123,7 @@ void silc_client_notify_by_server(SilcClient client, /* Get the channel entry */ channel = NULL; if (silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id, - &id_cache)) + &id_cache)) channel = (SilcChannelEntry)id_cache->context; /* Get sender Client ID */ @@ -202,9 +202,6 @@ void silc_client_notify_by_server(SilcClient client, silc_list_add(channel->clients, chu); } - /* XXX add support for multiple same nicks on same channel. Check - for them here */ - /* Notify application. The channel entry is sent last as this notify is for channel but application don't know it from the arguments sent by server. */ @@ -366,6 +363,8 @@ void silc_client_notify_by_server(SilcClient client, goto out; silc_free(client_id); + client_entry->valid = FALSE; + /* Get new Client ID */ tmp = silc_argument_get_arg_type(args, 2, &tmp_len); if (!tmp) @@ -767,8 +766,6 @@ void silc_client_notify_by_server(SilcClient client, out: silc_notify_payload_free(payload); - if (client_id) - silc_free(client_id); - if (channel_id) - silc_free(channel_id); + silc_free(client_id); + silc_free(channel_id); } diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index 0388f29a..b2314936 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -600,12 +600,11 @@ SILC_CLIENT_CMD_FUNC(invite) client_entry = silc_idlist_get_client(client, conn, nickname, cmd->argv[2], TRUE); if (!client_entry) { - silc_free(nickname); - if (cmd->pending) { COMMAND_ERROR; goto out; } + silc_free(nickname); /* Client entry not found, it was requested thus mark this to be pending command. */ @@ -717,6 +716,56 @@ SILC_CLIENT_CMD_FUNC(quit) silc_client_command_free(cmd); } +/* Timeout callback to remove the killed client from cache */ + +SILC_TASK_CALLBACK(silc_client_command_kill_remove_later) +{ + SilcClientCommandContext cmd = (SilcClientCommandContext)context; + SilcClient client = cmd->client; + SilcClientConnection conn = cmd->conn; + SilcClientEntry target; + char *nickname = NULL; + + /* Parse the typed nickname. */ + if (client->params->nickname_parse) + client->params->nickname_parse(cmd->argv[1], &nickname); + else + nickname = strdup(cmd->argv[1]); + + /* Get the target client */ + target = silc_idlist_get_client(cmd->client, conn, nickname, + cmd->argv[1], FALSE); + if (target) { + silc_client_remove_from_channels(client, conn, target); + silc_client_del_client(client, conn, target); + } + + silc_free(nickname); + silc_client_command_free(cmd); +} + +/* Kill command's pending command callback to actually remove the killed + client from our local cache. */ + +SILC_CLIENT_CMD_FUNC(kill_remove) +{ + SilcClientCommandContext cmd = (SilcClientCommandContext)context; + SilcClientCommandReplyContext reply = + (SilcClientCommandReplyContext)context2; + SilcCommandStatus status; + + SILC_GET16_MSB(status, silc_argument_get_arg_type(reply->args, 1, NULL)); + if (status == SILC_STATUS_OK) { + /* Remove with timeout */ + silc_schedule_task_add(cmd->client->schedule, cmd->conn->sock->sock, + silc_client_command_kill_remove_later, context, + 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + return; + } + + silc_client_command_free(cmd); +} + /* Command KILL. Router operator can use this command to remove an client fromthe SILC Network. */ @@ -752,13 +801,13 @@ SILC_CLIENT_CMD_FUNC(kill) target = silc_idlist_get_client(cmd->client, conn, nickname, cmd->argv[1], TRUE); if (!target) { - silc_free(nickname); - if (cmd->pending) { COMMAND_ERROR; goto out; } + silc_free(nickname); + /* Client entry not found, it was requested thus mark this to be pending command. */ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, @@ -773,10 +822,12 @@ SILC_CLIENT_CMD_FUNC(kill) /* Send the KILL command to the server */ idp = silc_id_payload_encode(target->id, SILC_ID_CLIENT); if (cmd->argc == 2) - buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 1, + buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, + ++conn->cmd_ident, 1, 1, idp->data, idp->len); else - buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, 0, 2, + buffer = silc_command_payload_encode_va(SILC_COMMAND_KILL, + ++conn->cmd_ident, 2, 1, idp->data, idp->len, 2, cmd->argv[2], strlen(cmd->argv[2])); @@ -788,6 +839,12 @@ SILC_CLIENT_CMD_FUNC(kill) /* Notify application */ COMMAND; + /* Register a pending callback that will actually remove the killed + client from our cache. */ + silc_client_command_pending(conn, SILC_COMMAND_KILL, conn->cmd_ident, + NULL, silc_client_command_kill_remove, + silc_client_command_dup(cmd)); + out: silc_free(nickname); silc_client_command_free(cmd); @@ -1370,13 +1427,13 @@ SILC_CLIENT_CMD_FUNC(cumode) client_entry = silc_idlist_get_client(cmd->client, conn, nickname, cmd->argv[3], TRUE); if (!client_entry) { - silc_free(nickname); - if (cmd->pending) { COMMAND_ERROR; goto out; } + silc_free(nickname); + /* Client entry not found, it was requested thus mark this to be pending command. */ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index 0396ae9c..228dce57 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -742,10 +742,8 @@ SILC_CLIENT_CMD_REPLY_FUNC(kill) SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; SilcCommandStatus status; - unsigned char *tmp; - tmp = silc_argument_get_arg_type(cmd->args, 1, NULL); - SILC_GET16_MSB(status, tmp); + SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL)); if (status != SILC_STATUS_OK) { cmd->client->ops->say(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR, "%s", silc_client_command_status_message(status)); diff --git a/lib/silcclient/idlist.c b/lib/silcclient/idlist.c index af4d3476..dae275ef 100644 --- a/lib/silcclient/idlist.c +++ b/lib/silcclient/idlist.c @@ -543,6 +543,7 @@ silc_client_add_client(SilcClient client, SilcClientConnection conn, /* Save the client infos */ client_entry = silc_calloc(1, sizeof(*client_entry)); client_entry->id = id; + client_entry->valid = TRUE; silc_parse_userfqdn(nickname, &nick, &client_entry->server); silc_parse_userfqdn(username, &client_entry->username, &client_entry->hostname); @@ -845,7 +846,7 @@ void silc_client_nickname_format(SilcClient client, char *newnick = NULL; int i, off = 0, len; SilcClientEntry *clients; - uint32 clients_count; + uint32 clients_count = 0; if (!client->params->nickname_format[0]) return; @@ -862,6 +863,13 @@ void silc_client_nickname_format(SilcClient client, if (!clients && !client->params->nickname_force_format) return; + len = 0; + for (i = 0; i < clients_count; i++) + if (clients[i]->valid) + len++; + if (!len) + return; + cp = client->params->nickname_format; while (*cp) { if (*cp == '%') { @@ -925,7 +933,7 @@ void silc_client_nickname_format(SilcClient client, break; for (i = 0; i < clients_count; i++) { - if (strncmp(clients[i]->nickname, newnick, off)) + if (strncasecmp(clients[i]->nickname, newnick, off)) continue; if (strlen(clients[i]->nickname) <= off) continue; diff --git a/lib/silcclient/idlist.h b/lib/silcclient/idlist.h index 6ff551ca..0dc48f8f 100644 --- a/lib/silcclient/idlist.h +++ b/lib/silcclient/idlist.h @@ -34,13 +34,14 @@ typedef struct { uint32 num; uint32 mode; /* User mode in SILC */ SilcClientID *id; /* The Client ID */ + bool valid; /* FALSE if this entry is not valid */ SilcCipher send_key; /* Private message key for sending */ SilcCipher receive_key; /* Private message key for receiving */ unsigned char *key; /* Set only if appliation provided the key material. NULL if the library generated the key. */ uint32 key_len; - int generated; /* TRUE if library generated the key */ + bool generated; /* TRUE if library generated the key */ SilcClientKeyAgreement ke; /* Current key agreement context or NULL */ } *SilcClientEntry; diff --git a/lib/silcske/silcske.c b/lib/silcske/silcske.c index 575c347e..e69fc0f9 100644 --- a/lib/silcske/silcske.c +++ b/lib/silcske/silcske.c @@ -580,6 +580,7 @@ SilcSKEStatus silc_ske_initiator_finish(SilcSKE ske, } /* Continue to final state */ + ske->users++; silc_ske_initiator_finish_final(ske, SILC_SKE_STATUS_OK, NULL); return SILC_SKE_STATUS_OK; @@ -933,6 +934,7 @@ SilcSKEStatus silc_ske_responder_phase_2(SilcSKE ske, } /* Continue to final state */ + ske->users++; silc_ske_responder_phase2_final(ske, SILC_SKE_STATUS_OK, NULL); return SILC_SKE_STATUS_OK; -- 2.24.0