X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=apps%2Fsilcd%2Fserver_query.c;h=3414c650c517afce54047277d32eab873454dfa7;hb=413da0f8686910f5e627393157566ae729ca99c4;hp=b8c96b13f8a11cb0c93cb5d5cd15280d1e8833e3;hpb=ac9b96fa43a85c0da14df6bdaf6abc252fc92d95;p=silc.git diff --git a/apps/silcd/server_query.c b/apps/silcd/server_query.c index b8c96b13..3414c650 100644 --- a/apps/silcd/server_query.c +++ b/apps/silcd/server_query.c @@ -1,10 +1,10 @@ /* - server_query.c + server_query.c Author: Pekka Riikonen - Copyright (C) 2002 Pekka Riikonen + Copyright (C) 2002 - 2003 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -163,7 +163,7 @@ void silc_server_query_send_error(SilcServer server, /* Send the command reply with error */ silc_server_send_command_reply(server, query->cmd->sock, - query->querycmd, error, 0, + query->querycmd, error, 0, silc_command_get_ident(query->cmd->payload), argc, data_type, data, data_len); va_end(va); @@ -292,7 +292,7 @@ void silc_server_query_send_router(SilcServer server, SilcServerQuery query) old_ident = silc_command_get_ident(query->cmd->payload); silc_command_set_ident(query->cmd->payload, ++server->cmd_ident); tmpbuf = silc_command_payload_encode_payload(query->cmd->payload); - silc_server_packet_send(server, + silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server), SILC_PACKET_COMMAND, 0, tmpbuf->data, tmpbuf->len, TRUE); @@ -329,7 +329,7 @@ void silc_server_query_send_router_reply(void *context, void *reply) silc_command_get_ident(query->cmd->payload)); buffer = silc_command_payload_encode_payload(cmdr->payload); silc_server_packet_send(server, query->cmd->sock, - SILC_PACKET_COMMAND_REPLY, 0, + SILC_PACKET_COMMAND_REPLY, 0, buffer->data, buffer->len, FALSE); silc_buffer_free(buffer); silc_server_query_free(query); @@ -388,8 +388,8 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) if (!tmp) continue; - id = silc_id_payload_parse_id(tmp, tmp_len, NULL); - if (!id) { + id = silc_id_payload_parse_id(tmp, tmp_len, &id_type); + if (!id || id_type != SILC_ID_CLIENT) { silc_server_query_add_error(server, query, TRUE, i + 4, SILC_STATUS_ERR_BAD_CLIENT_ID); continue; @@ -407,6 +407,8 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) for (i = 0; i < query->ids_count; i++) silc_free(query->ids[i].id); silc_free(query->ids); + query->ids = NULL; + query->ids_count = 0; silc_free(id); return; } @@ -426,8 +428,16 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) /* Get requested attributes if set */ tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len); - if (tmp) + if (tmp && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) { query->attrs = silc_attribute_payload_parse(tmp, tmp_len); + + /* When Requested Attributes is present we will assure that this + client cannot execute the WHOIS command too fast. This would be + same as having SILC_CF_LAG_STRICT. */ + if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT && + cmd->sock->user_data) + ((SilcClientEntry)cmd->sock->user_data)->fast_command = 6; + } break; case SILC_COMMAND_WHOWAS: @@ -506,18 +516,33 @@ void silc_server_query_parse(SilcServer server, SilcServerQuery query) /* Normal server must check whether this ID exist, and if not then send the query to router, unless done so already */ if (server->server_type == SILC_SERVER && !query->resolved) { - if (!silc_idlist_find_client_by_id(server->local_list, - id, TRUE, NULL)) { - if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || - !silc_idlist_find_client_by_id(server->global_list, + if (id_type == SILC_ID_CLIENT) { + if (!silc_idlist_find_client_by_id(server->local_list, id, TRUE, NULL)) { - silc_server_query_send_router(server, query); - for (i = 0; i < query->ids_count; i++) - silc_free(query->ids[i].id); - silc_free(query->ids); - silc_free(id); - return; + if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || + !silc_idlist_find_client_by_id(server->global_list, + id, TRUE, NULL)) { + silc_server_query_send_router(server, query); + for (i = 0; i < query->ids_count; i++) + silc_free(query->ids[i].id); + silc_free(query->ids); + query->ids = NULL; + query->ids_count = 0; + silc_free(id); + return; + } } + } else { + /* For now all other ID's except Client ID's are explicitly + sent to router for resolving. */ + silc_server_query_send_router(server, query); + for (i = 0; i < query->ids_count; i++) + silc_free(query->ids[i].id); + silc_free(query->ids); + query->ids = NULL; + query->ids_count = 0; + silc_free(id); + return; } } @@ -566,20 +591,20 @@ void silc_server_query_process(SilcServer server, SilcServerQuery query, if (query->nickname) { /* Get all clients matching nickname from local list */ - if (!silc_idlist_get_clients_by_hash(server->local_list, + if (!silc_idlist_get_clients_by_hash(server->local_list, query->nickname, server->md5hash, &clients, &clients_count)) - silc_idlist_get_clients_by_nickname(server->local_list, + silc_idlist_get_clients_by_nickname(server->local_list, query->nickname, query->nick_server, &clients, &clients_count); /* Check global list as well */ if (check_global) { - if (!silc_idlist_get_clients_by_hash(server->global_list, + if (!silc_idlist_get_clients_by_hash(server->global_list, query->nickname, server->md5hash, &clients, &clients_count)) - silc_idlist_get_clients_by_nickname(server->global_list, + silc_idlist_get_clients_by_nickname(server->global_list, query->nickname, query->nick_server, &clients, &clients_count); @@ -693,6 +718,10 @@ void silc_server_query_process(SilcServer server, SilcServerQuery query, } } + SILC_LOG_DEBUG(("Querying %d clients", clients_count)); + SILC_LOG_DEBUG(("Querying %d servers", servers_count)); + SILC_LOG_DEBUG(("Querying %d channels", channels_count)); + /* If nothing was found, then just send the errors */ if (!clients && !channels && !servers) { silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0); @@ -746,6 +775,11 @@ void silc_server_query_process(SilcServer server, SilcServerQuery query, } } + /* Remove the NOATTR status periodically */ + if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR && + client_entry->updated + 600 < time(NULL)) + client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR; + /* When requested attributes is present and local client is detached we cannot send the command to the client, we'll reply on behalf of the client instead. */ @@ -862,6 +896,21 @@ void silc_server_query_resolve(SilcServer server, SilcServerQuery query, for (i = 0; i < query->querylist_count; i++) { r = &query->querylist[i]; + /* If Requested Attributes were present put them to this resolving */ + if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) { + len = r->argc + 1; + r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len); + r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len); + r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len); + + tmp = silc_argument_get_arg_type(cmd->args, 3, &len); + if (tmp) + r->arg[r->argc] = silc_memdup(tmp, len); + r->arg_lens[r->argc] = len; + r->arg_types[r->argc] = 3; + r->argc++; + } + /* Send WHOIS command */ res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS, r->argc, r->arg, r->arg_lens, @@ -911,7 +960,7 @@ void silc_server_query_resolve(SilcServer server, SilcServerQuery query, case SILC_COMMAND_WHOIS: case SILC_COMMAND_IDENTIFY: /* Take existing query context if exist for this connection */ - for (i = 0; i < query->queries_count; i++) + for (i = 0; i < query->querylist_count; i++) if (query->querylist[i].sock == sock) { r = &query->querylist[i]; break; @@ -920,7 +969,7 @@ void silc_server_query_resolve(SilcServer server, SilcServerQuery query, if (!r) { /* Allocate new temp query list context */ query->querylist = silc_realloc(query->querylist, - sizeof(*query->querylist) * + sizeof(*query->querylist) * (query->querylist_count + 1)); r = &query->querylist[query->querylist_count]; query->querylist_count++; @@ -931,21 +980,6 @@ void silc_server_query_resolve(SilcServer server, SilcServerQuery query, r->timeout = 3; } - /* If Requested Attributes were present put them to this resolving */ - if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) { - len = r->argc + 1; - r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len); - r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len); - r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len); - - tmp = silc_argument_get_arg_type(cmd->args, 3, &len); - if (tmp) - r->arg[r->argc] = silc_memdup(tmp, len); - r->arg_lens[r->argc] = len; - r->arg_types[r->argc] = 3; - r->argc++; - } - len = r->argc + 1; r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len); r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len); @@ -977,6 +1011,7 @@ void silc_server_query_resolve(SilcServer server, SilcServerQuery query, client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING; client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED; client_entry->resolve_cmd_ident = ident; + client_entry->updated = time(NULL); /* Save the queried ID, which we will reprocess after we get this and all other queries back. */ @@ -1101,6 +1136,10 @@ void silc_server_query_send_reply(SilcServer server, bool sent_reply = FALSE; SILC_LOG_DEBUG(("Sending reply to query")); + SILC_LOG_DEBUG(("Sending %d clients", clients_count)); + SILC_LOG_DEBUG(("Sending %d servers", servers_count)); + SILC_LOG_DEBUG(("Sending %d channels", channels_count)); + SILC_LOG_DEBUG(("Sending %d errors", query->errors_count)); status = SILC_STATUS_OK; @@ -1164,7 +1203,7 @@ void silc_server_query_send_reply(SilcServer server, if (k >= 1) status = SILC_STATUS_LIST_ITEM; - if (valid_count > 1 && k == valid_count - 1 + if (valid_count > 1 && k == valid_count - 1 && !servers_count && !channels_count && !query->errors_count) status = SILC_STATUS_LIST_END; if (query->reply_count && k - 1 == query->reply_count) @@ -1195,9 +1234,9 @@ void silc_server_query_send_reply(SilcServer server, server->server_name, len); } } - + switch (query->querycmd) { - + case SILC_COMMAND_WHOIS: { unsigned char idle[4], mode[4]; @@ -1217,11 +1256,11 @@ void silc_server_query_send_reply(SilcServer server, if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) channels = - silc_server_get_client_channel_list(server, entry, FALSE, + silc_server_get_client_channel_list(server, entry, FALSE, FALSE, &umode_list); else channels = - silc_server_get_client_channel_list(server, entry, TRUE, + silc_server_get_client_channel_list(server, entry, TRUE, TRUE, &umode_list); if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty))) @@ -1237,7 +1276,7 @@ void silc_server_query_send_reply(SilcServer server, attributes we will reply to them on behalf of the client. */ len = 0; if (query->attrs) { - if (!entry->attrs) { + if (!entry->attrs && SILC_IS_LOCAL(entry)) { tmpattrs = silc_server_query_reply_attrs(server, query, entry); entry->attrs = silc_memdup(tmpattrs->data, tmpattrs->len); entry->attrs_len = tmpattrs->len; @@ -1253,7 +1292,7 @@ void silc_server_query_send_reply(SilcServer server, 2, idp->data, idp->len, 3, nh, strlen(nh), 4, uh, strlen(uh), - 5, entry->userinfo, + 5, entry->userinfo, strlen(entry->userinfo), 6, channels ? channels->data : NULL, channels ? channels->len : 0, @@ -1322,8 +1361,8 @@ void silc_server_query_send_reply(SilcServer server, 2, idp->data, idp->len, 3, nh, strlen(nh), 4, uh, strlen(uh), - 5, entry->userinfo, - entry->userinfo ? + 5, entry->userinfo, + entry->userinfo ? strlen(entry->userinfo) : 0); sent_reply = TRUE; break; @@ -1356,15 +1395,18 @@ void silc_server_query_send_reply(SilcServer server, k = 0; for (i = 0; i < servers_count; i++) { entry = servers[i]; - + if (k >= 1) status = SILC_STATUS_LIST_ITEM; + if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count && + !query->errors_count) + status = SILC_STATUS_LIST_END; if (servers_count > 1 && k == servers_count - 1 && !channels_count && !query->errors_count) status = SILC_STATUS_LIST_END; if (query->reply_count && k - 1 == query->reply_count) status = SILC_STATUS_LIST_END; - + SILC_LOG_DEBUG(("%s: server %s", (status == SILC_STATUS_OK ? " OK" : status == SILC_STATUS_LIST_START ? "START" : @@ -1377,13 +1419,13 @@ void silc_server_query_send_reply(SilcServer server, idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER); silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY, status, 0, ident, 2, - 2, idp->data, idp->len, - 3, entry->server_name, - entry->server_name ? + 2, idp->data, idp->len, + 3, entry->server_name, + entry->server_name ? strlen(entry->server_name) : 0); silc_buffer_free(idp); sent_reply = TRUE; - + if (status == SILC_STATUS_LIST_END) break; k++; @@ -1400,15 +1442,18 @@ void silc_server_query_send_reply(SilcServer server, k = 0; for (i = 0; i < channels_count; i++) { entry = channels[i]; - + if (k >= 1) status = SILC_STATUS_LIST_ITEM; + if (channels_count == 1 && status != SILC_STATUS_OK && + !query->errors_count) + status = SILC_STATUS_LIST_END; if (channels_count > 1 && k == channels_count - 1 && !query->errors_count) status = SILC_STATUS_LIST_END; if (query->reply_count && k - 1 == query->reply_count) status = SILC_STATUS_LIST_END; - + SILC_LOG_DEBUG(("%s: channel %s", (status == SILC_STATUS_OK ? " OK" : status == SILC_STATUS_LIST_START ? "START" : @@ -1421,13 +1466,13 @@ void silc_server_query_send_reply(SilcServer server, idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL); silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY, status, 0, ident, 2, - 2, idp->data, idp->len, - 3, entry->channel_name, - entry->channel_name ? + 2, idp->data, idp->len, + 3, entry->channel_name, + entry->channel_name ? strlen(entry->channel_name) : 0); silc_buffer_free(idp); sent_reply = TRUE; - + if (status == SILC_STATUS_LIST_END) break; k++; @@ -1471,6 +1516,8 @@ void silc_server_query_send_reply(SilcServer server, if (k >= 1) status = SILC_STATUS_LIST_ITEM; + if (query->errors_count == 1 && status != SILC_STATUS_OK) + status = SILC_STATUS_LIST_END; if (query->errors_count > 1 && k == query->errors_count - 1) status = SILC_STATUS_LIST_END; if (query->reply_count && k - 1 == query->reply_count) @@ -1481,7 +1528,7 @@ void silc_server_query_send_reply(SilcServer server, status == SILC_STATUS_LIST_START ? "START" : status == SILC_STATUS_LIST_ITEM ? " ITEM" : status == SILC_STATUS_LIST_END ? " END" : - " : "), + " : "), silc_get_status_message(query->errors[i].error), query->errors[i].error)); @@ -1523,7 +1570,7 @@ SilcBuffer silc_server_query_reply_attrs(SilcServer server, SilcAttributeObjPk pk; SilcAttributeObjService service; unsigned char *tmp; - unsigned char sign[2048]; + unsigned char sign[2048 + 1]; SilcUInt32 sign_len; SILC_LOG_DEBUG(("Constructing Requested Attributes")); @@ -1542,9 +1589,13 @@ SilcBuffer silc_server_query_reply_attrs(SilcServer server, silc_strncat(service.address, sizeof(service.address), server->server_name, strlen(server->server_name)); service.status = !(client_entry->mode & SILC_UMODE_DETACHED); + if (client_entry->connection) + service.idle = time(NULL) - client_entry->data.last_receive; buffer = silc_attribute_payload_encode(buffer, attribute, SILC_ATTRIBUTE_FLAG_VALID, &service, sizeof(service)); + if (!buffer) + return NULL; break; case SILC_ATTRIBUTE_STATUS_MOOD: @@ -1554,16 +1605,20 @@ SilcBuffer silc_server_query_reply_attrs(SilcServer server, (void *) SILC_ATTRIBUTE_MOOD_NORMAL, sizeof(SilcUInt32)); + if (!buffer) + return NULL; break; case SILC_ATTRIBUTE_STATUS_FREETEXT: /* Put STATUS_FREETEXT. We just tell in the message that we are replying on behalf of the client. */ - tmp = + tmp = "This information was provided by the server on behalf of the user"; buffer = silc_attribute_payload_encode(buffer, attribute, SILC_ATTRIBUTE_FLAG_VALID, tmp, strlen(tmp)); + if (!buffer) + return NULL; break; case SILC_ATTRIBUTE_PREFERRED_CONTACT: @@ -1573,6 +1628,8 @@ SilcBuffer silc_server_query_reply_attrs(SilcServer server, (void *) SILC_ATTRIBUTE_CONTACT_CHAT, sizeof(SilcUInt32)); + if (!buffer) + return NULL; break; case SILC_ATTRIBUTE_USER_PUBLIC_KEY: @@ -1586,6 +1643,8 @@ SilcBuffer silc_server_query_reply_attrs(SilcServer server, SILC_ATTRIBUTE_FLAG_INVALID, &pk, sizeof(pk)); silc_free(pk.data); + if (!buffer) + return NULL; break; } @@ -1593,6 +1652,8 @@ SilcBuffer silc_server_query_reply_attrs(SilcServer server, buffer = silc_attribute_payload_encode(buffer, attribute, SILC_ATTRIBUTE_FLAG_INVALID, NULL, 0); + if (!buffer) + return NULL; break; default: @@ -1600,11 +1661,13 @@ SilcBuffer silc_server_query_reply_attrs(SilcServer server, if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY || attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE) break; - + /* For other attributes we cannot reply so mark it invalid */ buffer = silc_attribute_payload_encode(buffer, attribute, SILC_ATTRIBUTE_FLAG_INVALID, NULL, 0); + if (!buffer) + return NULL; break; } } @@ -1619,6 +1682,8 @@ SilcBuffer silc_server_query_reply_attrs(SilcServer server, SILC_ATTRIBUTE_FLAG_INVALID, &pk, sizeof(pk)); silc_free(pk.data); + if (!buffer) + return NULL; /* Finally compute the digital signature of all the data we provided as an indication that we provided rightfull information, and this @@ -1636,6 +1701,8 @@ SilcBuffer silc_server_query_reply_attrs(SilcServer server, SILC_ATTRIBUTE_FLAG_VALID, &pk, sizeof(pk)); } + if (!buffer) + return NULL; return buffer; }