From 8763262ca87be2c00479b25c27dfa505fc4f349c Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Fri, 3 May 2002 11:08:20 +0000 Subject: [PATCH] updates. --- CHANGES | 22 +++ TODO | 13 +- apps/irssi/src/silc/core/silc-channels.c | 1 + apps/silcd/command.c | 236 ++++++++++++----------- apps/silcd/command_reply.c | 122 ++++++------ apps/silcd/packet_receive.c | 17 +- apps/silcd/server.c | 2 +- lib/silcclient/client.c | 2 +- lib/silcclient/client_ftp.c | 1 + lib/silcclient/client_notify.c | 11 ++ lib/silcclient/client_resume.c | 6 +- lib/silcclient/command.c | 3 + lib/silcclient/command_reply.c | 56 ++++-- lib/silcclient/idlist.c | 2 +- lib/silcclient/protocol.c | 5 +- lib/silccore/silcstatus.h | 2 + 16 files changed, 290 insertions(+), 211 deletions(-) diff --git a/CHANGES b/CHANGES index 603b64b2..1ff1a6c3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,25 @@ +Fri May 3 11:37:10 EEST 2002 Pekka Riikonen + + * Fixed rekey protocol with PFS in the client library. + Affected file is lib/silcclient/protocol.c. + + * Added support for list of errors in client library + command reply handling. Affected file is + lib/silcclient/command_reply.c. + + * Defined that the WHOIS and IDENTIFY commands can send + list of errors. Updated the protocol specs. Protocol + TODO #2. + + * Added support for sending list of errors to WHOIS and + IDENTIFY commands in server. Added support for receiving + list of errors in server. Affected files are + silcd/command.c and silcd/command_reply.c. + + * Fixed client info resolving on LEAVE command in client + library to not crash. Affected file is + lib/silcclient/client_notify.c. + Thu May 2 08:45:11 CEST 2002 Pekka Riikonen * Defined that the NICK command replies with thew changed diff --git a/TODO b/TODO index 66547e95..419f7b45 100644 --- a/TODO +++ b/TODO @@ -14,11 +14,6 @@ TODO/bugs In SILC Client Library set the key only if application wishes to set (accept the key) it (Do this to 1.0). - o Additions to do after protocol version 1.1: - - o Add support for list of errors in command replies. Protocol - TODO entry 1. - TODO/bugs In SILC Server ======================== @@ -33,13 +28,7 @@ TODO/bugs In SILC Server and router does not have founder on channel (founder is left or there's no founder on channel at all), the router will accept the server's founder mode change, even though it perhaps should not do that (Fix - this to 0.9). - - o The router should check for validity of received notify packets from - routers (fix this to 0.9). Following NOTIFYs needs to be verified: - - o JOIN (check that joining is allowed) - o SIGNOFF (maybe should check that notifier owns the client) + this to 0.9) (Protocol TODO #17 relates). o Implement the SILC_CUMODE_QUIET user mode (Do this to 0.9.x). diff --git a/apps/irssi/src/silc/core/silc-channels.c b/apps/irssi/src/silc/core/silc-channels.c index 9a11cb66..6235e6f0 100644 --- a/apps/irssi/src/silc/core/silc-channels.c +++ b/apps/irssi/src/silc/core/silc-channels.c @@ -156,6 +156,7 @@ static void command_part(const char *data, SILC_SERVER_REC *server, signal_emit("message part", 5, server, chanrec->name, server->nick, userhost, ""); + chanrec->left = TRUE; silc_command_exec(server, "LEAVE", chanrec->name); signal_stop(); diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 9efae737..0d222bd3 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -477,16 +477,18 @@ silc_server_command_pending_error_check(SilcServerCommandContext cmd, typedef struct { void *id; + SilcIdType id_type; SilcUInt32 index; SilcStatus error; } *ResolveError; -#define ADD_ERROR(errptr, errptr_count, _id, _index, _status) \ +#define ADD_ERROR(errptr, errptr_count, _id, _id_type, _index, _status) \ do { \ errptr = silc_realloc(errptr, sizeof(*errptr) * (errptr_count + 1)); \ if (!errptr) \ return FALSE; \ errptr[errptr_count].id = _id; \ + errptr[errptr_count].id_type = _id_type; \ errptr[errptr_count].index = _index; \ errptr[errptr_count].error = _status; \ errptr_count++; \ @@ -509,7 +511,7 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd, int i, k; /* If client ID is in the command it must be used instead of nickname */ - tmp = silc_argument_get_arg_type(cmd->args, 3, &len); + tmp = silc_argument_get_arg_type(cmd->args, 4, &len); if (!tmp) { /* No ID, get the nickname@server string and parse it. */ tmp = silc_argument_get_arg_type(cmd->args, 1, NULL); @@ -524,7 +526,7 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd, /* Command includes ID, we must use that. Take all ID's from the command packet */ for (k = 0, i = 0; i < argc; i++) { - tmp = silc_argument_get_arg_type(cmd->args, i + 3, &len); + tmp = silc_argument_get_arg_type(cmd->args, i + 4, &len); if (!tmp) continue; id = silc_id_payload_parse_id(tmp, len, NULL); @@ -535,7 +537,7 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd, (*client_id_count)++; k++; } else { - ADD_ERROR((*error_client), (*error_client_count), NULL, i + 3, + ADD_ERROR((*error_client), (*error_client_count), NULL, 0, i + 4, SILC_STATUS_ERR_BAD_CLIENT_ID); } } @@ -543,11 +545,10 @@ silc_server_command_whois_parse(SilcServerCommandContext cmd, /* Get the max count of reply messages allowed */ tmp = silc_argument_get_arg_type(cmd->args, 2, NULL); - if (tmp) { + if (tmp) SILC_GET32_MSB(*count, tmp); - } else { + else *count = 0; - } return TRUE; } @@ -653,7 +654,7 @@ silc_server_command_whois_check(SilcServerCommandContext cmd, sizeof(**r->res_argv)); memcpy(r->res_argv[r->res_argc], idp->data, idp->len); r->res_argv_lens[r->res_argc] = idp->len; - r->res_argv_types[r->res_argc] = r->res_argc + 3; + r->res_argv_types[r->res_argc] = r->res_argc + 4; r->res_argc++; silc_buffer_free(idp); @@ -834,7 +835,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd, umode_list = NULL; } - if (count && k - 1 == count) + if (status == SILC_STATUS_LIST_END) break; k++; } @@ -870,7 +871,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd, silc_buffer_free(idp); idp = NULL; - if (count && k - 1 == count) + if (status == SILC_STATUS_LIST_END) break; k++; } @@ -963,8 +964,8 @@ silc_server_command_whois_process(SilcServerCommandContext cmd) goto out; } - ADD_ERROR(error_client, error_client_count, client_id[i], 0, - SILC_STATUS_ERR_NO_SUCH_CLIENT_ID); + ADD_ERROR(error_client, error_client_count, client_id[i], + SILC_ID_CLIENT, 0, SILC_STATUS_ERR_NO_SUCH_CLIENT_ID); } } } else if (nick) { @@ -1079,11 +1080,10 @@ silc_server_command_whowas_parse(SilcServerCommandContext cmd, /* Get the max count of reply messages allowed */ tmp = silc_argument_get_arg_type(cmd->args, 2, NULL); - if (tmp) { + if (tmp) SILC_GET32_MSB(*count, tmp); - } else { + else *count = 0; - } return TRUE; } @@ -1160,13 +1160,10 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd, if (!valid_count) { /* No valid entries found at all, just send error */ - unsigned char *tmp; - tmp = silc_argument_get_arg_type(cmd->args, 1, NULL); - if (tmp) - silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS, - SILC_STATUS_ERR_NO_SUCH_NICK, 0, - 3, tmp, strlen(tmp)); + silc_server_command_send_status_data(cmd, SILC_COMMAND_WHOWAS, + SILC_STATUS_ERR_NO_SUCH_NICK, 0, + 3, tmp, tmp ? strlen(tmp) : 0); return; } @@ -1184,8 +1181,6 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd, status = SILC_STATUS_LIST_END; if (count && k - 1 == count) status = SILC_STATUS_LIST_END; - if (count && k - 1 > count) - break; /* Send WHOWAS reply */ idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT); @@ -1227,6 +1222,8 @@ silc_server_command_whowas_send_reply(SilcServerCommandContext cmd, silc_buffer_free(packet); silc_buffer_free(idp); + if (status == SILC_STATUS_LIST_END) + break; k++; } } @@ -1382,7 +1379,9 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd, SilcUInt32 *servers_count, SilcChannelEntry **channels, SilcUInt32 *channels_count, - SilcUInt32 *count) + SilcUInt32 *count, + ResolveError *error_id, + SilcUInt32 *error_id_count) { SilcServer server = cmd->server; unsigned char *tmp; @@ -1392,7 +1391,6 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd, bool check_global = FALSE; void *entry; int i; - bool error = FALSE; if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) check_global = TRUE; @@ -1513,26 +1511,19 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd, continue; idp = silc_id_payload_parse(tmp, len); - if (!idp) { - silc_free(*clients); - silc_free(*servers); - silc_free(*channels); - silc_server_command_send_status_reply( - cmd, SILC_COMMAND_IDENTIFY, - SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0); - return 0; - } + if (!idp) + ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); id = silc_id_payload_get_id(idp); - switch (silc_id_payload_get_type(idp)) { case SILC_ID_CLIENT: - entry = (void *)silc_idlist_find_client_by_id(server->local_list, - id, TRUE, NULL); + entry = silc_idlist_find_client_by_id(server->local_list, + id, TRUE, NULL); if (!entry && check_global) - entry = (void *)silc_idlist_find_client_by_id(server->global_list, - id, TRUE, NULL); + entry = silc_idlist_find_client_by_id(server->global_list, + id, TRUE, NULL); if (entry) { *clients = silc_realloc(*clients, sizeof(**clients) * (*clients_count + 1)); @@ -1547,24 +1538,22 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd, silc_free(*clients); silc_free(*servers); silc_free(*channels); + silc_free(*error_id); return -1; - } else { - silc_server_command_send_status_data( - cmd, SILC_COMMAND_IDENTIFY, - SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, - 0, 2, tmp, len); - error = TRUE; } + + ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5, + SILC_STATUS_ERR_NO_SUCH_CLIENT_ID); } break; case SILC_ID_SERVER: - entry = (void *)silc_idlist_find_server_by_id(server->local_list, - id, TRUE, NULL); + entry = silc_idlist_find_server_by_id(server->local_list, + id, TRUE, NULL); if (!entry && check_global) - entry = (void *)silc_idlist_find_server_by_id(server->global_list, - id, TRUE, NULL); + entry = silc_idlist_find_server_by_id(server->global_list, + id, TRUE, NULL); if (entry) { *servers = silc_realloc(*servers, sizeof(**servers) * (*servers_count + 1)); @@ -1579,23 +1568,20 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd, silc_free(*clients); silc_free(*servers); silc_free(*channels); + silc_free(*error_id); return -1; - } else { - silc_server_command_send_status_data( - cmd, SILC_COMMAND_IDENTIFY, - SILC_STATUS_ERR_NO_SUCH_SERVER_ID, - 0, 2, tmp, len); - error = TRUE; } + + ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5, + SILC_STATUS_ERR_NO_SUCH_SERVER_ID); } break; case SILC_ID_CHANNEL: - entry = (void *)silc_idlist_find_channel_by_id(server->local_list, - id, NULL); + entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL); if (!entry && check_global) - entry = (void *)silc_idlist_find_channel_by_id(server->global_list, - id, NULL); + entry = silc_idlist_find_channel_by_id(server->global_list, id, + NULL); if (entry) { *channels = silc_realloc(*channels, sizeof(**channels) * (*channels_count + 1)); @@ -1610,14 +1596,12 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd, silc_free(*clients); silc_free(*servers); silc_free(*channels); + silc_free(*error_id); return -1; - } else { - silc_server_command_send_status_data( - cmd, SILC_COMMAND_IDENTIFY, - SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID, - 0, 2, tmp, len); - error = TRUE; } + + ADD_ERROR((*error_id), (*error_id_count), NULL, 0, i + 5, + SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID); } break; } @@ -1626,20 +1610,12 @@ silc_server_command_identify_parse(SilcServerCommandContext cmd, } } - if (error) { - silc_free(*clients); - silc_free(*servers); - silc_free(*channels); - return FALSE; - } - /* Get the max count of reply messages allowed */ tmp = silc_argument_get_arg_type(cmd->args, 4, NULL); - if (tmp) { + if (tmp) SILC_GET32_MSB(*count, tmp); - } else { + else *count = 0; - } return 1; } @@ -1737,7 +1713,7 @@ silc_server_command_identify_check_client(SilcServerCommandContext cmd, sizeof(**r->res_argv)); memcpy(r->res_argv[r->res_argc], idp->data, idp->len); r->res_argv_lens[r->res_argc] = idp->len; - r->res_argv_types[r->res_argc] = r->res_argc + 3; + r->res_argv_types[r->res_argc] = r->res_argc + 4; r->res_argc++; silc_buffer_free(idp); @@ -1793,46 +1769,46 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd, SilcUInt32 servers_count, SilcChannelEntry *channels, SilcUInt32 channels_count, + ResolveError errors, + SilcUInt32 errors_count, int count) { SilcServer server = cmd->server; - int i, k, len, valid_count; + int i, k, valid_count; + SilcUInt32 len; SilcBuffer packet, idp; SilcStatus status; SilcUInt16 ident = silc_command_get_ident(cmd->payload); char nh[256], uh[256]; SilcSocketConnection hsock; + unsigned char *tmp; status = SILC_STATUS_OK; if (clients) { SilcClientEntry entry; + valid_count = clients_count; + + if (silc_argument_get_arg_type(cmd->args, 1, NULL)) { + /* Process only valid clients and ignore those that are not registered. + This is checked with nickname only because when resolved client IDs + we check that they are registered earlier. */ + valid_count = 0; + for (i = 0; i < clients_count; i++) { + if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED) + valid_count++; + else + clients[i] = NULL; + } - /* Process only valid entries. */ - valid_count = 0; - for (i = 0; i < clients_count; i++) { - if (clients[i]->data.status & SILC_IDLIST_STATUS_REGISTERED) - valid_count++; - else - clients[i] = NULL; - } - - if (!valid_count) { - /* No valid entries found at all, just send error */ - unsigned char *tmp; - - tmp = silc_argument_get_arg_type(cmd->args, 1, NULL); - if (tmp) { + if (!valid_count) { + /* No valid entries found at all, just send error */ + tmp = silc_argument_get_arg_type(cmd->args, 1, NULL); silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY, SILC_STATUS_ERR_NO_SUCH_NICK, 0, - 3, tmp, strlen(tmp)); - } else { - tmp = silc_argument_get_arg_type(cmd->args, 5, (SilcUInt32 *)&len); - silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY, - SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, - 0, 2, tmp, len); + 3, tmp, tmp ? strlen(tmp) : 0); + return; } - return; } /* Process all valid client entries and send command replies */ @@ -1848,7 +1824,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd, if (k >= 1) status = SILC_STATUS_LIST_ITEM; if (valid_count > 1 && k == valid_count - 1 - && !servers_count && !channels_count) + && !servers_count && !channels_count && !errors_count) status = SILC_STATUS_LIST_END; if (count && k - 1 == count) status = SILC_STATUS_LIST_END; @@ -1898,9 +1874,8 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd, silc_buffer_free(packet); silc_buffer_free(idp); - if (count && k - 1 == count) + if (status == SILC_STATUS_LIST_END) break; - k++; } } @@ -1916,7 +1891,8 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd, if (k >= 1) status = SILC_STATUS_LIST_ITEM; - if (servers_count > 1 && k == servers_count - 1 && !channels_count) + if (servers_count > 1 && k == servers_count - 1 && !channels_count && + !errors_count) status = SILC_STATUS_LIST_END; if (count && k - 1 == count) status = SILC_STATUS_LIST_END; @@ -1936,9 +1912,8 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd, silc_buffer_free(packet); silc_buffer_free(idp); - if (count && k - 1 == count) + if (status == SILC_STATUS_LIST_END) break; - k++; } } @@ -1954,7 +1929,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd, if (k >= 1) status = SILC_STATUS_LIST_ITEM; - if (channels_count > 1 && k == channels_count - 1) + if (channels_count > 1 && k == channels_count - 1 && !errors_count) status = SILC_STATUS_LIST_END; if (count && k - 1 == count) status = SILC_STATUS_LIST_END; @@ -1974,9 +1949,46 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd, silc_buffer_free(packet); silc_buffer_free(idp); - if (count && k - 1 == count) + if (status == SILC_STATUS_LIST_END) break; + k++; + } + } + + /* Send error replies */ + if (errors) { + if (status == SILC_STATUS_OK && errors_count > 1) + status = SILC_STATUS_LIST_START; + idp = NULL; + for (i = 0, k = 0; i < errors_count; i++) { + if (errors[i].id) { + idp = silc_id_payload_encode(errors[i].id, SILC_ID_CLIENT); + tmp = idp->data; + len = idp->len; + } else { + tmp = silc_argument_get_arg_type(cmd->args, errors[i].index, &len); + } + + if (k >= 1) + status = SILC_STATUS_LIST_ITEM; + if (errors_count > 1 && k == errors_count - 1) + status = SILC_STATUS_LIST_END; + if (count && k - 1 == count) + status = SILC_STATUS_LIST_END; + + /* Send error */ + silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY, + (status == SILC_STATUS_OK ? + errors[i].error : status), + (status == SILC_STATUS_OK ? + 0 : errors[i].error), + 2, tmp, len); + silc_buffer_free(idp); + idp = NULL; + + if (status == SILC_STATUS_LIST_END) + break; k++; } } @@ -1991,21 +2003,23 @@ silc_server_command_identify_process(SilcServerCommandContext cmd) SilcServerEntry *servers = NULL; SilcChannelEntry *channels = NULL; SilcUInt32 clients_count = 0, servers_count = 0, channels_count = 0; + SilcUInt32 errors_count = 0; + ResolveError errors = NULL; /* Parse the IDENTIFY request */ ret = silc_server_command_identify_parse(cmd, &clients, &clients_count, &servers, &servers_count, &channels, &channels_count, - &count); + &count, &errors, &errors_count); if (ret < 1) return ret; ret = 0; /* Check that all mandatory fields are present and request those data from the server who owns the client if necessary. */ - if (clients && !silc_server_command_identify_check_client(cmd, clients, - clients_count)) { + if (!silc_server_command_identify_check_client(cmd, clients, + clients_count)) { ret = -1; goto out; } @@ -2015,12 +2029,14 @@ silc_server_command_identify_process(SilcServerCommandContext cmd) clients, clients_count, servers, servers_count, channels, channels_count, + errors, errors_count, count); out: silc_free(clients); silc_free(servers); silc_free(channels); + silc_free(errors); return ret; } diff --git a/apps/silcd/command_reply.c b/apps/silcd/command_reply.c index eb56f929..9b344cda 100644 --- a/apps/silcd/command_reply.c +++ b/apps/silcd/command_reply.c @@ -24,13 +24,18 @@ #include "command_reply.h" /* All functions that call the COMMAND_CHECK_STATUS macros must have - out: goto label. */ - -#define COMMAND_CHECK_STATUS \ -do { \ - SILC_LOG_DEBUG(("Start")); \ - if (!silc_command_get_status(cmd->payload, &status, &error)) \ - goto out; \ + out: and err: goto labels. */ + +#define COMMAND_CHECK_STATUS \ +do { \ + SILC_LOG_DEBUG(("Start")); \ + if (!silc_command_get_status(cmd->payload, &status, &error)) { \ + if (SILC_STATUS_IS_ERROR(status)) \ + goto out; \ + if (status == SILC_STATUS_LIST_END) \ + goto out; \ + goto err; \ + } \ } while(0) /* Server command reply list. Not all commands have reply function as @@ -115,6 +120,37 @@ void silc_server_command_reply_free(SilcServerCommandReplyContext cmd) } } +static void +silc_server_command_process_error(SilcServerCommandReplyContext cmd, + SilcStatus error) +{ + SilcServer server = cmd->server; + + /* If we received notify for invalid ID we'll remove the ID if we + have it cached. */ + if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID && + cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) { + SilcClientEntry client; + SilcUInt32 tmp_len; + unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len); + if (tmp) { + SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL); + if (client_id) { + SILC_LOG_DEBUG(("Received invalid client ID notification, deleting " + "the entry from cache")); + client = silc_idlist_find_client_by_id(server->global_list, + client_id, FALSE, NULL); + if (client) { + silc_server_remove_from_channels(server, NULL, client, TRUE, + NULL, TRUE); + silc_idlist_del_client(server->global_list, client); + } + silc_free(client_id); + } + } + } +} + /* Caches the received WHOIS information. */ static char @@ -253,7 +289,6 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd) SILC_SERVER_CMD_REPLY_FUNC(whois) { SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context; - SilcServer server = cmd->server; SilcStatus status, error; COMMAND_CHECK_STATUS; @@ -269,32 +304,14 @@ SILC_SERVER_CMD_REPLY_FUNC(whois) } out: - /* If we received notify for invalid ID we'll remove the ID if we - have it cached. */ - if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID && - cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) { - SilcClientEntry client; - SilcUInt32 tmp_len; - unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len); - if (tmp) { - SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL); - if (client_id) { - SILC_LOG_DEBUG(("Received invalid client ID notification, deleting " - "the entry from cache")); - client = silc_idlist_find_client_by_id(server->global_list, - client_id, FALSE, NULL); - if (client) { - silc_server_remove_from_channels(server, NULL, client, TRUE, - NULL, TRUE); - silc_idlist_del_client(server->global_list, client); - } - silc_free(client_id); - } - } - } - + silc_server_command_process_error(cmd, error); SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS); silc_server_command_reply_free(cmd); + return; + + err: + silc_server_command_process_error(cmd, error); + silc_server_command_reply_free(cmd); } /* Caches the received WHOWAS information for a short period of time. */ @@ -406,6 +423,7 @@ SILC_SERVER_CMD_REPLY_FUNC(whowas) out: SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS); + err: silc_server_command_reply_free(cmd); } @@ -614,7 +632,6 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd) SILC_SERVER_CMD_REPLY_FUNC(identify) { SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context; - SilcServer server = cmd->server; SilcStatus status, error; COMMAND_CHECK_STATUS; @@ -630,32 +647,14 @@ SILC_SERVER_CMD_REPLY_FUNC(identify) } out: - /* If we received notify for invalid ID we'll remove the ID if we - have it cached. */ - if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID && - cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) { - SilcClientEntry client; - SilcUInt32 tmp_len; - unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len); - if (tmp) { - SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL); - if (client_id) { - SILC_LOG_DEBUG(("Received invalid client ID notification, deleting " - "the entry from cache")); - client = silc_idlist_find_client_by_id(server->global_list, - client_id, FALSE, NULL); - if (client) { - silc_server_remove_from_channels(server, NULL, client, TRUE, - NULL, TRUE); - silc_idlist_del_client(server->global_list, client); - } - silc_free(client_id); - } - } - } - + silc_server_command_process_error(cmd, error); SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY); silc_server_command_reply_free(cmd); + return; + + err: + silc_server_command_process_error(cmd, error); + silc_server_command_reply_free(cmd); } /* Received reply fro INFO command. Cache the server and its information */ @@ -712,6 +711,7 @@ SILC_SERVER_CMD_REPLY_FUNC(info) out: SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO); + err: silc_server_command_reply_free(cmd); } @@ -755,6 +755,7 @@ SILC_SERVER_CMD_REPLY_FUNC(motd) out: SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD); + err: silc_server_command_reply_free(cmd); if (entry) @@ -958,6 +959,7 @@ SILC_SERVER_CMD_REPLY_FUNC(join) out: SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN); + err: silc_free(client_id); silc_server_command_reply_free(cmd); @@ -1005,6 +1007,8 @@ SILC_SERVER_CMD_REPLY_FUNC(stats) out: SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_STATS); + err: + silc_server_command_reply_free(cmd); } SILC_SERVER_CMD_REPLY_FUNC(users) @@ -1096,6 +1100,7 @@ SILC_SERVER_CMD_REPLY_FUNC(users) out: SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_USERS); silc_free(channel_id); + err: silc_server_command_reply_free(cmd); } @@ -1183,6 +1188,7 @@ SILC_SERVER_CMD_REPLY_FUNC(getkey) silc_free(server_id); if (public_key) silc_pkcs_public_key_free(public_key); + err: silc_server_command_reply_free(cmd); } @@ -1260,6 +1266,7 @@ SILC_SERVER_CMD_REPLY_FUNC(list) out: SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_LIST); silc_free(channel_id); + err: silc_server_command_reply_free(cmd); } @@ -1272,5 +1279,6 @@ SILC_SERVER_CMD_REPLY_FUNC(watch) out: SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WATCH); + err: silc_server_command_reply_free(cmd); } diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index 080e9eb5..20dd6210 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -2993,7 +2993,7 @@ void silc_server_resume_client(SilcServer server, unsigned char *id_string, *auth = NULL; SilcUInt16 id_len, auth_len = 0; int ret, nickfail = 0; - bool resolved, local, nick_change = FALSE; + bool resolved, local, nick_change = FALSE, resolve = FALSE; SilcChannelEntry channel; SilcHashTableList htl; SilcChannelClientEntry chl; @@ -3060,10 +3060,15 @@ void silc_server_resume_client(SilcServer server, return; } - /* Check that the client is detached, and that we have other info too */ - if (!(detached_client->mode & SILC_UMODE_DETACHED) || - !silc_hash_table_count(detached_client->channels) || - !detached_client->nickname) { + if (!(detached_client->mode & SILC_UMODE_DETACHED)) + resolve = TRUE; + if (!silc_hash_table_count(detached_client->channels) && + detached_client->router) + resolve = TRUE; + if (!detached_client->nickname) + resolve = TRUE; + + if (resolve) { if (server->server_type == SILC_SERVER && !server->standalone) { /* The client info is being resolved. Reprocess this packet after receiving the reply to the query. */ @@ -3094,7 +3099,7 @@ void silc_server_resume_client(SilcServer server, /* Check that we have the public key of the client, if not then we must resolve it first. */ if (!detached_client->data.public_key) { - if (server->standalone) { + if (server->server_type == SILC_SERVER && server->standalone) { silc_server_disconnect_remote(server, sock, SILC_STATUS_ERR_INCOMPLETE_INFORMATION, "Resuming not possible"); diff --git a/apps/silcd/server.c b/apps/silcd/server.c index 6aaf3e55..6037be57 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -4336,7 +4336,7 @@ SilcClientEntry silc_server_get_client_resolve(SilcServer server, idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT); buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS, server->cmd_ident, 1, - 3, idp->data, idp->len); + 4, idp->data, idp->len); silc_server_packet_send(server, client ? client->router->connection : server->router->connection, SILC_PACKET_COMMAND, 0, diff --git a/lib/silcclient/client.c b/lib/silcclient/client.c index ac05ae50..b05f81b6 100644 --- a/lib/silcclient/client.c +++ b/lib/silcclient/client.c @@ -1498,7 +1498,7 @@ void silc_client_disconnected_by_server(SilcClient client, if (packet->len > 1 && silc_utf8_valid(packet->data + 1, packet->len - 1)) - message = silc_memdup(packet->data, packet->len); + message = silc_memdup(packet->data + 1, packet->len - 1); client->internal->ops->say(client, sock->user_data, SILC_CLIENT_MESSAGE_AUDIT, diff --git a/lib/silcclient/client_ftp.c b/lib/silcclient/client_ftp.c index 1f19f945..d22d4e4c 100644 --- a/lib/silcclient/client_ftp.c +++ b/lib/silcclient/client_ftp.c @@ -769,6 +769,7 @@ void silc_client_ftp_session_free(SilcClientFtpSession session) silc_free(session->hostname); silc_free(session->filepath); + silc_free(session->path); silc_free(session); } diff --git a/lib/silcclient/client_notify.c b/lib/silcclient/client_notify.c index 7a2d83e5..b272e242 100644 --- a/lib/silcclient/client_notify.c +++ b/lib/silcclient/client_notify.c @@ -892,6 +892,17 @@ void silc_client_notify_by_server(SilcClient client, silc_hash_table_del(channel->user_list, client_entry); silc_free(chu); } + + if (!silc_hash_table_count(client_entry->channels)) { + SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res)); + res->context = client; + res->sock = silc_socket_dup(conn->sock); + res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT); + silc_schedule_task_add(client->schedule, 0, + silc_client_notify_check_client, res, + (5 + (silc_rng_get_rn16(client->rng) % 529)), + 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL); + } } break; diff --git a/lib/silcclient/client_resume.c b/lib/silcclient/client_resume.c index 6cccf3c7..e7d88301 100644 --- a/lib/silcclient/client_resume.c +++ b/lib/silcclient/client_resume.c @@ -208,14 +208,14 @@ SILC_TASK_CALLBACK(silc_client_resume_call_completion) SilcClientResumeSession session = context; int i; - session->callback(session->client, session->conn, session->success, - session->context); - for (i = 0; i < session->cmd_idents_count; i++) silc_client_command_pending_del(session->conn, SILC_COMMAND_IDENTIFY, session->cmd_idents[i]); silc_free(session->cmd_idents); + session->callback(session->client, session->conn, session->success, + session->context); + memset(session, 'F', sizeof(*session)); silc_free(session); } diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index 15af4c38..9373396e 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -129,6 +129,9 @@ void silc_client_command_pending_del(SilcClientConnection conn, { SilcClientCommandPending *r; + if (!conn->pending_commands) + return; + silc_dlist_start(conn->pending_commands); while ((r = silc_dlist_get(conn->pending_commands)) != SILC_LIST_END) { if (r->reply_cmd == reply_cmd && r->ident == ident) { diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index ddb4b0d3..73d553cb 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -39,14 +39,36 @@ #define SAY cmd->client->internal->ops->say /* All functions that call the COMMAND_CHECK_STATUS macro must have - out: goto label. */ + out: and err: goto labels. out label should call the pending + command replies, and the err label just handle error condition. */ #define COMMAND_CHECK_STATUS \ do { \ SILC_LOG_DEBUG(("Start")); \ if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \ + if (SILC_STATUS_IS_ERROR(cmd->status)) { \ + /* Single error */ \ + COMMAND_REPLY_ERROR; \ + goto out; \ + } \ + /* List of errors */ \ COMMAND_REPLY_ERROR; \ - goto out; \ + if (cmd->status == SILC_STATUS_LIST_END) \ + goto out; \ + goto err; \ + } \ +} while(0) + +/* Same as COMMAND_CHECK_STATUS but doesn't call client operation */ +#define COMMAND_CHECK_STATUS_I \ +do { \ + SILC_LOG_DEBUG(("Start")); \ + if (!silc_command_get_status(cmd->payload, NULL, NULL)) { \ + if (SILC_STATUS_IS_ERROR(cmd->status)) \ + goto out; \ + if (cmd->status == SILC_STATUS_LIST_END) \ + goto out; \ + goto err; \ } \ } while(0) @@ -236,6 +258,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(whois) out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS); + err: /* If we received notify for invalid ID we'll remove the ID if we have it cached. */ if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) { @@ -312,6 +335,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(whowas) out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS); + err: silc_client_command_reply_free(cmd); } @@ -454,6 +478,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(identify) out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY); + err: /* If we received notify for invalid ID we'll remove the ID if we have it cached. */ if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) { @@ -599,6 +624,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(list) out: silc_free(channel_id); SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST); + err: silc_client_command_reply_free(cmd); } @@ -1595,7 +1621,7 @@ silc_client_command_reply_users_save(SilcClientCommandReplyContext cmd, (res_argc + 1)); res_argv[res_argc] = client_id_list.data; res_argv_lens[res_argc] = idp_len; - res_argv_types[res_argc] = res_argc + 3; + res_argv_types[res_argc] = res_argc + 4; res_argc++; } else { if (!silc_client_on_channel(channel, client_entry)) { @@ -1793,10 +1819,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(whois_i) SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; - SILC_LOG_DEBUG(("Start")); - - if (cmd->error != SILC_STATUS_OK) - goto out; + COMMAND_CHECK_STATUS_I; /* Save WHOIS info */ silc_client_command_reply_whois_save(cmd, cmd->status, FALSE); @@ -1811,6 +1834,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(whois_i) out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS); + err: /* If we received notify for invalid ID we'll remove the ID if we have it cached. */ if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) { @@ -1844,10 +1868,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(identify_i) SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data; - SILC_LOG_DEBUG(("Start")); - - if (cmd->error != SILC_STATUS_OK) - goto out; + COMMAND_CHECK_STATUS_I; /* Save IDENTIFY info */ silc_client_command_reply_identify_save(cmd, cmd->status, FALSE); @@ -1862,6 +1883,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(identify_i) out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY); + err: /* If we received notify for invalid ID we'll remove the ID if we have it cached. */ if (cmd->error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) { @@ -1900,10 +1922,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(info_i) char *server_name, *server_info; SilcUInt32 len; - SILC_LOG_DEBUG(("Start")); - - if (cmd->error != SILC_STATUS_OK) - goto out; + COMMAND_CHECK_STATUS_I; /* Get server ID */ tmp = silc_argument_get_arg_type(cmd->args, 2, &len); @@ -1935,6 +1954,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(info_i) out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INFO); silc_free(server_id); + err: silc_client_command_reply_free(cmd); } @@ -1964,10 +1984,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(users_i) { SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context; - SILC_LOG_DEBUG(("Start")); - - if (cmd->error != SILC_STATUS_OK) - goto out; + COMMAND_CHECK_STATUS_I; /* Save USERS info */ if (silc_client_command_reply_users_save( @@ -1979,6 +1996,7 @@ SILC_CLIENT_CMD_REPLY_FUNC(users_i) out: SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_USERS); + err: /* Unregister this command reply */ silc_client_command_unregister(cmd->client, SILC_COMMAND_USERS, NULL, silc_client_command_reply_users_i, diff --git a/lib/silcclient/idlist.c b/lib/silcclient/idlist.c index 2d5a8c0c..a7fd0f71 100644 --- a/lib/silcclient/idlist.c +++ b/lib/silcclient/idlist.c @@ -558,7 +558,7 @@ void silc_client_get_client_by_id_resolve(SilcClient client, /* Send the command */ idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT); silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident, - 1, 3, idp->data, idp->len); + 1, 4, idp->data, idp->len); silc_buffer_free(idp); /* Add pending callback */ diff --git a/lib/silcclient/protocol.c b/lib/silcclient/protocol.c index 6ab25d68..4e955a6e 100644 --- a/lib/silcclient/protocol.c +++ b/lib/silcclient/protocol.c @@ -1079,7 +1079,10 @@ SILC_TASK_CALLBACK(silc_client_protocol_rekey) /* We received the REKEY_DONE packet and all packets after this is encrypted with the new key so set the decryption key to the new key */ - silc_client_protocol_rekey_generate(client, ctx, FALSE); + if (ctx->pfs == TRUE) + silc_client_protocol_rekey_generate_pfs(client, ctx, FALSE); + else + silc_client_protocol_rekey_generate(client, ctx, FALSE); /* Protocol has ended, call the final callback */ if (protocol->final_callback) diff --git a/lib/silccore/silcstatus.h b/lib/silccore/silcstatus.h index dea64e94..f619ea9e 100644 --- a/lib/silccore/silcstatus.h +++ b/lib/silccore/silcstatus.h @@ -101,4 +101,6 @@ typedef SilcUInt8 SilcStatus; #define SILC_STATUS_ERR_BAD_VERSION 53 /***/ +#define SILC_STATUS_IS_ERROR(status) (status >= SILC_STATUS_ERR_NO_SUCH_NICK) + #endif /* SILCSTATUS_H */ -- 2.24.0