* 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 <priikone@silcnet.org>
* Check that the public key exists in the GETKEY command before
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.
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
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;
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;
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);
}
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;
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"));
return;
}
+ entry->data.last_receive = time(NULL);
+
switch (ctx->conn_type) {
case SILC_SOCKET_TYPE_CLIENT:
{
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);
/* 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;
}
SilcPacketContext *packet)
{
SilcPacketType type = packet->type;
+ SilcIDListData idata = (SilcIDListData)sock->user_data;
SILC_LOG_DEBUG(("Parsing packet type %d", type));
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;
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;
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,
client_notify.c
- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
+ Author: Pekka Riikonen <priikone@silcnet.org>
Copyright (C) 1997 - 2001 Pekka Riikonen
/* 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 */
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. */
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)
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);
}
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. */
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. */
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,
/* 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]));
/* 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);
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,
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));
/* 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);
char *newnick = NULL;
int i, off = 0, len;
SilcClientEntry *clients;
- uint32 clients_count;
+ uint32 clients_count = 0;
if (!client->params->nickname_format[0])
return;
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 == '%') {
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;
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;
}
/* Continue to final state */
+ ske->users++;
silc_ske_initiator_finish_final(ske, SILC_SKE_STATUS_OK, NULL);
return SILC_SKE_STATUS_OK;
}
/* Continue to final state */
+ ske->users++;
silc_ske_responder_phase2_final(ske, SILC_SKE_STATUS_OK, NULL);
return SILC_SKE_STATUS_OK;