5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 - 2003 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "serverincludes.h"
22 #include "server_internal.h"
25 SilcSocketConnection sock; /* Connection of this query */
26 unsigned char **arg; /* Query argument */
27 SilcUInt32 *arg_lens; /* Query argument lengths */
28 SilcUInt32 *arg_types; /* Query argument types */
29 SilcUInt32 argc; /* Number of query arguments */
30 SilcUInt32 timeout; /* Max timeout for query to complete */
31 SilcUInt16 ident; /* Query command identifier */
32 } *SilcServerQueryList;
34 /* Represents an SILC ID */
37 SilcIdType id_type; /* ID type */
38 SilcUInt16 ident; /* Command identifier */
41 /* Represents one error occurred during query */
44 SilcIdType id_type; /* ID type */
45 SilcUInt16 index; /* Index to IDs */
46 unsigned int from_cmd : 1; /* TRUE if `index' is from command args,
47 otherwise from query->ids */
48 unsigned int error : 7; /* The actual error (SilcStatus) */
49 } *SilcServerQueryError;
51 /* Query session context */
54 char *nickname; /* Queried nickname */
55 char *nick_server; /* Queried nickname's server */
56 char *server_name; /* Queried server name */
57 char *channel_name; /* Queried channel name */
58 SilcServerQueryID ids; /* Queried IDs */
59 SilcUInt32 ids_count; /* number of queried IDs */
60 SilcUInt32 reply_count; /* Requested reply count */
61 SilcDList attrs; /* Requested Attributes in WHOIS */
63 /* Query session data */
64 SilcServerCommandContext cmd; /* Command context for query */
65 SilcServerQueryList querylist; /* Temporary query list context */
66 SilcServerQueryID queries; /* Ongoing queries */
67 SilcServerQueryError errors; /* Query errors */
68 SilcUInt16 querylist_count; /* Number of query lists */
69 SilcUInt16 queries_count; /* Number of ongoing queries */
70 SilcUInt16 queries_left; /* Number of ongoing queries left */
71 SilcUInt16 errors_count; /* number of errors */
72 unsigned int querycmd : 7; /* Query command (SilcCommand) */
73 unsigned int resolved : 1; /* TRUE if normal server has resolved
74 information from router */
77 void silc_server_query_free(SilcServerQuery query);
78 void silc_server_query_send_error(SilcServer server,
79 SilcServerQuery query,
80 SilcStatus error, ...);
81 void silc_server_query_add_error(SilcServer server,
82 SilcServerQuery query,
86 void silc_server_query_add_error_id(SilcServer server,
87 SilcServerQuery query,
89 void *id, SilcIdType id_type);
90 void silc_server_query_send_router(SilcServer server, SilcServerQuery query);
91 void silc_server_query_send_router_reply(void *context, void *reply);
92 void silc_server_query_parse(SilcServer server, SilcServerQuery query);
93 void silc_server_query_process(SilcServer server, SilcServerQuery query,
95 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
96 SilcSocketConnection sock,
97 SilcClientEntry client_entry);
98 void silc_server_query_resolve_reply(void *context, void *reply);
99 void silc_server_query_send_reply(SilcServer server,
100 SilcServerQuery query,
101 SilcClientEntry *clients,
102 SilcUInt32 clients_count,
103 SilcServerEntry *servers,
104 SilcUInt32 servers_count,
105 SilcChannelEntry *channels,
106 SilcUInt32 channels_count);
107 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
108 SilcServerQuery query,
109 SilcClientEntry client_entry);
111 /* Free the query context structure and all allocated resources. */
113 void silc_server_query_free(SilcServerQuery query)
117 silc_server_command_free(query->cmd);
119 for (i = 0; i < query->queries_count; i++)
120 silc_free(query->queries[i].id);
121 silc_free(query->queries);
123 silc_free(query->nickname);
124 silc_free(query->nick_server);
125 silc_free(query->server_name);
126 silc_free(query->channel_name);
128 for (i = 0; i < query->ids_count; i++)
129 silc_free(query->ids[i].id);
130 silc_free(query->ids);
133 silc_attribute_payload_list_free(query->attrs);
135 for (i = 0; i < query->errors_count; i++)
136 silc_free(query->errors[i].id);
137 silc_free(query->errors);
139 memset(query, 'F', sizeof(*query));
143 /* Send error reply indicated by the `error' to the original sender of
146 void silc_server_query_send_error(SilcServer server,
147 SilcServerQuery query,
148 SilcStatus error, ...)
151 unsigned char *data = NULL;
152 SilcUInt32 data_len = 0, data_type = 0, argc = 0;
155 data_type = va_arg(va, SilcUInt32);
158 data = va_arg(va, unsigned char *);
159 data_len = va_arg(va, SilcUInt32);
162 SILC_LOG_DEBUG(("ERROR: %s (%d)", silc_get_status_message(error), error));
164 /* Send the command reply with error */
165 silc_server_send_command_reply(server, query->cmd->sock,
166 query->querycmd, error, 0,
167 silc_command_get_ident(query->cmd->payload),
168 argc, data_type, data, data_len);
172 /* Add error to error list. Multiple errors may occur during the query
173 processing and this function can be used to add one error. The
174 `index' is the index to the command context which includes the argument
175 which caused the error, or it is the index to query->ids, depending
176 on value of `from_cmd'. */
178 void silc_server_query_add_error(SilcServer server,
179 SilcServerQuery query,
184 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
185 (query->errors_count + 1));
188 query->errors[query->errors_count].index = index;
189 query->errors[query->errors_count].from_cmd = from_cmd;
190 query->errors[query->errors_count].error = error;
191 query->errors[query->errors_count].id = NULL;
192 query->errors[query->errors_count].id_type = 0;
193 query->errors_count++;
196 /* Same as silc_server_query_add_error but adds the ID data to be used
197 with error sending with this error type. */
199 void silc_server_query_add_error_id(SilcServer server,
200 SilcServerQuery query,
202 void *id, SilcIdType id_type)
204 query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
205 (query->errors_count + 1));
208 query->errors[query->errors_count].index = 0;
209 query->errors[query->errors_count].from_cmd = FALSE;
210 query->errors[query->errors_count].error = error;
211 query->errors[query->errors_count].id = silc_id_dup(id, id_type);
212 query->errors[query->errors_count].id_type = id_type;
213 query->errors_count++;
216 /* Processes query as command. The `query' is the command that is
217 being processed indicated by the `cmd'. The `query' can be one of
218 the following: SILC_COMMAND_WHOIS, SILC_COMMAND_WHOWAS or
219 SILC_COMMAND_IDENTIFY. This function handles the reply sending
220 to the entity who sent this query to us automatically. Returns
221 TRUE if the query is being processed or FALSE on error. */
223 bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
224 SilcServerCommandContext cmd)
226 SilcServerQuery query;
228 SILC_LOG_DEBUG(("Query %s command", silc_get_command_name(querycmd)));
230 query = silc_calloc(1, sizeof(*query));
231 query->querycmd = querycmd;
232 query->cmd = silc_server_command_dup(cmd);
236 case SILC_COMMAND_WHOIS:
237 /* If we are normal server and query contains nickname OR query
238 doesn't contain nickname or ids BUT attributes, send it to the
240 if (server->server_type != SILC_ROUTER && !server->standalone &&
241 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
242 (silc_argument_get_arg_type(cmd->args, 1, NULL) ||
243 (!silc_argument_get_arg_type(cmd->args, 1, NULL) &&
244 !silc_argument_get_arg_type(cmd->args, 4, NULL) &&
245 silc_argument_get_arg_type(cmd->args, 3, NULL)))) {
246 silc_server_query_send_router(server, query);
251 case SILC_COMMAND_WHOWAS:
252 /* WHOWAS query is always sent to router if we are normal server */
253 if (server->server_type == SILC_SERVER && !server->standalone &&
254 cmd->sock != SILC_PRIMARY_ROUTE(server)) {
255 silc_server_query_send_router(server, query);
260 case SILC_COMMAND_IDENTIFY:
261 /* If we are normal server and query does not contain IDs, send it
262 directly to router (it contains nickname, server name or channel
264 if (server->server_type == SILC_SERVER && !server->standalone &&
265 cmd->sock != SILC_PRIMARY_ROUTE(server) &&
266 !silc_argument_get_arg_type(cmd->args, 5, NULL)) {
267 silc_server_query_send_router(server, query);
273 SILC_LOG_ERROR(("Bad query using %d command", querycmd));
274 silc_server_query_free(query);
278 /* Now parse the request */
279 silc_server_query_parse(server, query);
284 /* Send the received query to our primary router since we could not
285 handle the query directly. We will reprocess the query after our
286 router replies back. */
288 void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
291 SilcUInt16 old_ident;
293 SILC_LOG_DEBUG(("Forwarding the query to router for processing"));
295 /* Send WHOIS command to our router */
296 old_ident = silc_command_get_ident(query->cmd->payload);
297 silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
298 tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
299 silc_server_packet_send(server,
300 SILC_PRIMARY_ROUTE(server),
301 SILC_PACKET_COMMAND, 0,
302 tmpbuf->data, tmpbuf->len, TRUE);
303 silc_command_set_ident(query->cmd->payload, old_ident);
304 silc_buffer_free(tmpbuf);
306 query->resolved = TRUE;
308 /* Continue parsing the query after received reply from router */
309 silc_server_command_pending(server, query->querycmd, server->cmd_ident,
310 silc_server_query_send_router_reply, query);
313 /* Reply callback called after primary router has replied to our initial
314 sending of the query to it. We will proceed the query in this function. */
316 void silc_server_query_send_router_reply(void *context, void *reply)
318 SilcServerQuery query = context;
319 SilcServer server = query->cmd->server;
320 SilcServerCommandReplyContext cmdr = reply;
322 SILC_LOG_DEBUG(("Received reply from router to query"));
324 /* Check if router sent error reply */
325 if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
328 SILC_LOG_DEBUG(("Sending error to original query"));
330 /* Send the same command reply payload which contains the error */
331 silc_command_set_command(cmdr->payload, query->querycmd);
332 silc_command_set_ident(cmdr->payload,
333 silc_command_get_ident(query->cmd->payload));
334 buffer = silc_command_payload_encode_payload(cmdr->payload);
335 silc_server_packet_send(server, query->cmd->sock,
336 SILC_PACKET_COMMAND_REPLY, 0,
337 buffer->data, buffer->len, FALSE);
338 silc_buffer_free(buffer);
339 silc_server_query_free(query);
343 /* Continue with parsing */
344 silc_server_query_parse(server, query);
347 /* Parse the command query and start processing the queries in detail. */
349 void silc_server_query_parse(SilcServer server, SilcServerQuery query)
351 SilcServerCommandContext cmd = query->cmd;
353 SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
358 SILC_LOG_DEBUG(("Parsing %s query",
359 silc_get_command_name(query->querycmd)));
361 switch (query->querycmd) {
363 case SILC_COMMAND_WHOIS:
364 /* Get requested attributes if set */
365 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
366 if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
367 query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
369 /* When Requested Attributes is present we will assure that this
370 client cannot execute the WHOIS command too fast. This would be
371 same as having SILC_CF_LAG_STRICT. */
372 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
373 cmd->sock->user_data)
374 ((SilcClientEntry)cmd->sock->user_data)->fast_command = 6;
377 /* Get Client IDs if present. Take IDs always instead of nickname. */
378 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
382 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
383 if (!tmp && !query->attrs) {
384 /* No nickname, no ids and no attributes - send error */
385 silc_server_query_send_error(server, query,
386 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
387 silc_server_query_free(query);
391 /* Get the nickname@server string and parse it */
392 if (tmp && ((tmp_len > 128) ||
393 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))) {
394 silc_server_query_send_error(server, query,
395 SILC_STATUS_ERR_BAD_NICKNAME, 0);
396 silc_server_query_free(query);
401 /* Parse the IDs included in the query */
402 query->ids = silc_calloc(argc, sizeof(*query->ids));
404 for (i = 0; i < argc; i++) {
405 tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
409 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
410 if (!id || id_type != SILC_ID_CLIENT) {
411 silc_server_query_add_error(server, query, TRUE, i + 4,
412 SILC_STATUS_ERR_BAD_CLIENT_ID);
416 /* Normal server must check whether this ID exist, and if not then
417 send the query to router, unless done so already */
418 if (server->server_type == SILC_SERVER && !query->resolved) {
419 if (!silc_idlist_find_client_by_id(server->local_list,
421 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
422 !silc_idlist_find_client_by_id(server->global_list,
424 silc_server_query_send_router(server, query);
425 for (i = 0; i < query->ids_count; i++)
426 silc_free(query->ids[i].id);
427 silc_free(query->ids);
429 query->ids_count = 0;
436 query->ids[query->ids_count].id = id;
437 query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
442 /* Get the max count of reply messages allowed */
443 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
444 if (tmp && tmp_len == sizeof(SilcUInt32))
445 SILC_GET32_MSB(query->reply_count, tmp);
448 case SILC_COMMAND_WHOWAS:
450 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
452 silc_server_query_send_error(server, query,
453 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
454 silc_server_query_free(query);
458 /* Get the nickname@server string and parse it */
460 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
461 silc_server_query_send_error(server, query,
462 SILC_STATUS_ERR_BAD_NICKNAME, 0);
463 silc_server_query_free(query);
467 /* Get the max count of reply messages allowed */
468 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
469 if (tmp && tmp_len == sizeof(SilcUInt32))
470 SILC_GET32_MSB(query->reply_count, tmp);
473 case SILC_COMMAND_IDENTIFY:
474 /* Get IDs if present. Take IDs always instead of names. */
475 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
478 /* Try get nickname */
479 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
481 /* Get the nickname@server string and parse it */
483 !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
484 silc_server_query_add_error(server, query, TRUE, 1,
485 SILC_STATUS_ERR_BAD_NICKNAME);
488 /* Try get server name */
489 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
491 query->server_name = silc_memdup(tmp, tmp_len);
493 /* Get channel name */
494 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
495 if (tmp && tmp_len <= 256)
496 query->channel_name = silc_memdup(tmp, tmp_len);
498 if (!query->nickname && !query->server_name && !query->channel_name) {
499 silc_server_query_send_error(server, query,
500 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
501 silc_server_query_free(query);
506 /* Parse the IDs included in the query */
507 query->ids = silc_calloc(argc, sizeof(*query->ids));
509 for (i = 0; i < argc; i++) {
510 tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
514 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
516 silc_server_query_add_error(server, query, TRUE, i + 5,
517 SILC_STATUS_ERR_BAD_CLIENT_ID);
521 /* Normal server must check whether this ID exist, and if not then
522 send the query to router, unless done so already */
523 if (server->server_type == SILC_SERVER && !query->resolved) {
524 if (id_type == SILC_ID_CLIENT) {
525 if (!silc_idlist_find_client_by_id(server->local_list,
527 if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
528 !silc_idlist_find_client_by_id(server->global_list,
530 silc_server_query_send_router(server, query);
531 for (i = 0; i < query->ids_count; i++)
532 silc_free(query->ids[i].id);
533 silc_free(query->ids);
535 query->ids_count = 0;
541 /* For now all other ID's except Client ID's are explicitly
542 sent to router for resolving. */
543 silc_server_query_send_router(server, query);
544 for (i = 0; i < query->ids_count; i++)
545 silc_free(query->ids[i].id);
546 silc_free(query->ids);
548 query->ids_count = 0;
554 query->ids[query->ids_count].id = id;
555 query->ids[query->ids_count].id_type = id_type;
560 /* Get the max count of reply messages allowed */
561 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
562 if (tmp && tmp_len == sizeof(SilcUInt32))
563 SILC_GET32_MSB(query->reply_count, tmp);
567 /* Start processing the query information */
568 silc_server_query_process(server, query, TRUE);
571 /* Context for holding clients searched by public key. */
573 SilcClientEntry **clients;
574 SilcUInt32 *clients_count;
576 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
578 void silc_server_public_key_hash_foreach(void *key, void *context,
581 SilcServerPublicKeyUser uc = user_context;
582 SilcClientEntry entry = context;
584 /* Nothing was found, just return */
590 (*uc->clients) = silc_realloc((*uc->clients),
591 sizeof((**uc->clients)) *
592 ((*uc->clients_count) + 1));
593 (*uc->clients)[(*uc->clients_count)++] = entry;
596 /* If clients are set, limit the found clients using the attributes in
597 the query. If clients are not set, try to find some clients using
600 void silc_server_query_check_attributes(SilcServer server,
601 SilcServerQuery query,
602 SilcClientEntry **clients,
603 SilcUInt32 *clients_count) {
604 SilcClientEntry entry;
605 SilcAttributePayload attr;
606 SilcAttribute attribute;
607 SilcAttributeObjPk pk;
608 SilcPublicKey publickey;
610 bool found = FALSE, no_clients = FALSE;
612 /* If no clients were found, we only check the attributes
613 if the user wasn't searching for nickname/ids */
616 if (query->nickname || query->ids_count)
620 silc_dlist_start(query->attrs);
621 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
622 attribute = silc_attribute_get_attribute(attr);
625 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
626 SILC_LOG_DEBUG(("Finding clients by public key attribute"));
628 if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
631 if (!silc_pkcs_public_key_decode(pk.data, pk.data_len,
638 /* If no clients were set on calling this function, we
639 just search for clients, otherwise we try to limit
642 SilcServerPublicKeyUserStruct usercontext;
644 usercontext.clients = clients;
645 usercontext.clients_count = clients_count;
646 usercontext.found = FALSE;
648 silc_hash_table_find_foreach(server->pk_hash, publickey,
649 silc_server_public_key_hash_foreach,
652 if (usercontext.found == TRUE)
655 for (i = 0; i < *clients_count; i++) {
656 entry = (*clients)[i];
658 if (!entry->data.public_key)
661 if (!silc_hash_table_find_by_context(server->pk_hash, publickey,
663 (*clients)[i] = NULL;
670 silc_pkcs_public_key_free(publickey);
675 if (!found && !query->nickname && !query->ids) {
676 silc_server_query_send_error(server, query,
677 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
681 /* Processes the parsed query. This does the actual finding of the
682 queried information and prepares for sending reply to the original
683 sender of the query command. */
685 void silc_server_query_process(SilcServer server, SilcServerQuery query,
688 SilcServerCommandContext cmd = query->cmd;
689 bool check_global = FALSE;
691 SilcClientEntry *clients = NULL, client_entry;
692 SilcChannelEntry *channels = NULL;
693 SilcServerEntry *servers = NULL;
694 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
697 SILC_LOG_DEBUG(("Processing %s query",
698 silc_get_command_name(query->querycmd)));
700 /* Check global lists if query is coming from client or we are not
701 normal server (we know global information). */
702 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
704 else if (server->server_type != SILC_SERVER)
707 if (query->nickname) {
708 /* Get all clients matching nickname from local list */
709 if (!silc_idlist_get_clients_by_hash(server->local_list,
710 query->nickname, server->md5hash,
711 &clients, &clients_count))
712 silc_idlist_get_clients_by_nickname(server->local_list,
715 &clients, &clients_count);
717 /* Check global list as well */
719 if (!silc_idlist_get_clients_by_hash(server->global_list,
720 query->nickname, server->md5hash,
721 &clients, &clients_count))
722 silc_idlist_get_clients_by_nickname(server->global_list,
725 &clients, &clients_count);
729 silc_server_query_add_error(server, query, TRUE, 1,
730 SILC_STATUS_ERR_NO_SUCH_NICK);
733 if (query->server_name) {
734 /* Find server by name */
735 entry = silc_idlist_find_server_by_name(server->local_list,
736 query->server_name, TRUE, NULL);
737 if (!entry && check_global)
738 entry = silc_idlist_find_server_by_name(server->global_list,
739 query->server_name, TRUE, NULL);
741 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
742 servers[servers_count++] = (SilcServerEntry)entry;
746 silc_server_query_add_error(server, query, TRUE, 2,
747 SILC_STATUS_ERR_NO_SUCH_SERVER);
750 if (query->channel_name) {
751 /* Find channel by name */
752 entry = silc_idlist_find_channel_by_name(server->local_list,
753 query->channel_name, NULL);
754 if (!entry && check_global)
755 entry = silc_idlist_find_channel_by_name(server->global_list,
756 query->channel_name, NULL);
758 channels = silc_realloc(channels, sizeof(*channels) *
759 (channels_count + 1));
760 channels[channels_count++] = (SilcChannelEntry)entry;
764 silc_server_query_add_error(server, query, TRUE, 3,
765 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
768 if (query->ids_count) {
769 /* Find entries by the queried IDs */
770 for (i = 0; i < query->ids_count; i++) {
771 void *id = query->ids[i].id;
775 switch (query->ids[i].id_type) {
778 /* Get client entry */
779 entry = silc_idlist_find_client_by_id(server->local_list,
781 if (!entry && check_global)
782 entry = silc_idlist_find_client_by_id(server->global_list,
785 silc_server_query_add_error(server, query, FALSE, i,
786 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
790 clients = silc_realloc(clients, sizeof(*clients) *
791 (clients_count + 1));
792 clients[clients_count++] = (SilcClientEntry)entry;
796 /* Get server entry */
797 entry = silc_idlist_find_server_by_id(server->local_list,
799 if (!entry && check_global)
800 entry = silc_idlist_find_server_by_id(server->global_list,
803 silc_server_query_add_error(server, query, FALSE, i,
804 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
808 servers = silc_realloc(servers, sizeof(*servers) *
809 (servers_count + 1));
810 servers[servers_count++] = (SilcServerEntry)entry;
813 case SILC_ID_CHANNEL:
814 /* Get channel entry */
815 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
816 if (!entry && check_global)
817 entry = silc_idlist_find_channel_by_id(server->global_list, id,
820 silc_server_query_add_error(server, query, FALSE, i,
821 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
825 channels = silc_realloc(channels, sizeof(*channels) *
826 (channels_count + 1));
827 channels[channels_count++] = (SilcChannelEntry)entry;
836 /* Check the attributes to narrow down the search by using them. */
838 silc_server_query_check_attributes(server, query, &clients,
841 SILC_LOG_DEBUG(("Querying %d clients", clients_count));
842 SILC_LOG_DEBUG(("Querying %d servers", servers_count));
843 SILC_LOG_DEBUG(("Querying %d channels", channels_count));
845 /* If nothing was found, then just send the errors */
846 if (!clients && !channels && !servers) {
847 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
851 /* If caller does not want us to resolve anything (has resolved already)
852 then just continue with sending the reply */
854 silc_server_query_send_reply(server, query, clients, clients_count,
855 servers, servers_count, channels,
863 /* Now process all found information and if necessary do some more
865 switch (query->querycmd) {
867 case SILC_COMMAND_WHOIS:
868 for (i = 0; i < clients_count; i++) {
869 client_entry = clients[i];
871 /* Check if cannot query this anyway, so take next one */
873 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
876 /* If Requested Attributes is set then we always resolve the client
877 information, if not then check whether the entry is complete or not
878 and decide whether we need to resolve or not. */
881 /* Even if nickname and stuff are present, we may need to resolve
883 if (client_entry->nickname && client_entry->username &&
884 client_entry->userinfo) {
885 /* Check if cannot query this anyway, so take next one */
886 if (!client_entry->router)
889 /* If we are router, client is local to us, or client is on channel
890 we do not need to resolve the client information. */
891 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
892 || silc_hash_table_count(client_entry->channels) ||
898 /* Remove the NOATTR status periodically */
899 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
900 client_entry->updated + 600 < time(NULL))
901 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
903 /* When requested attributes is present and local client is detached
904 we cannot send the command to the client, we'll reply on behalf of
905 the client instead. */
906 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
907 (client_entry->mode & SILC_UMODE_DETACHED ||
908 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
911 /* If attributes are present in query, and in the entry and we have
912 done resolvings already we don't need to resolve anymore */
913 if (query->resolved && query->attrs && client_entry->attrs)
916 /* Resolve the detailed client information. If client is local we
917 know that attributes were present and we will resolve directly
918 from the client. Otherwise resolve from client's owner. */
919 silc_server_query_resolve(server, query,
920 (SILC_IS_LOCAL(client_entry) ?
921 client_entry->connection :
922 client_entry->router->connection),
927 case SILC_COMMAND_WHOWAS:
928 for (i = 0; i < clients_count; i++) {
929 client_entry = clients[i];
931 /* Check if cannot query this anyway, so take next one */
932 if (!client_entry || !client_entry->router ||
933 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
936 /* If both nickname and username are present no resolving is needed */
937 if (client_entry->nickname && client_entry->username)
940 /* Resolve the detailed client information */
941 silc_server_query_resolve(server, query,
942 client_entry->router->connection,
947 case SILC_COMMAND_IDENTIFY:
948 for (i = 0; i < clients_count; i++) {
949 client_entry = clients[i];
951 /* Check if cannot query this anyway, so take next one */
952 if (!client_entry || !client_entry->router ||
953 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
956 /* Even if nickname is present, we may need to resolve the entry */
957 if (client_entry->nickname) {
959 /* If we are router, client is local to us, or client is on channel
960 we do not need to resolve the client information. */
961 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
962 || silc_hash_table_count(client_entry->channels) ||
967 /* Resolve the detailed client information */
968 silc_server_query_resolve(server, query,
969 client_entry->router->connection,
975 if (!query->queries_count)
976 /* If we didn't have to do any resolving, continue with sending the
977 command reply to the original sender. */
978 silc_server_query_send_reply(server, query, clients, clients_count,
979 servers, servers_count, channels,
982 /* Now actually send the resolvings we gathered earlier */
983 silc_server_query_resolve(server, query, NULL, NULL);
990 /* Resolve the detailed information for the `client_entry'. Only client
991 information needs to be resolved for being incomplete. Each incomplete
992 client entry calls this function to do the resolving. */
994 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
995 SilcSocketConnection sock,
996 SilcClientEntry client_entry)
998 SilcServerCommandContext cmd = query->cmd;
999 SilcServerQueryList r = NULL;
1006 if (!sock && client_entry)
1009 /* If arguments are NULL we will now actually send the resolvings
1010 that earlier has been gathered by calling this function. */
1011 if (!sock && !client_entry) {
1014 SILC_LOG_DEBUG(("Sending the resolvings"));
1016 /* WHOWAS resolving has been done at the same time this function
1017 was called to add the resolving for WHOWAS, so just return. */
1018 if (query->querycmd == SILC_COMMAND_WHOWAS)
1021 for (i = 0; i < query->querylist_count; i++) {
1022 r = &query->querylist[i];
1024 /* If Requested Attributes were present put them to this resolving */
1025 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1027 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1028 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1029 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1031 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1033 r->arg[r->argc] = silc_memdup(tmp, len);
1034 r->arg_lens[r->argc] = len;
1035 r->arg_types[r->argc] = 3;
1039 /* Send WHOIS command */
1040 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1041 r->argc, r->arg, r->arg_lens,
1042 r->arg_types, r->ident);
1043 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1044 res_cmd->data, res_cmd->len, FALSE);
1045 silc_buffer_free(res_cmd);
1047 /* Reprocess this packet after received reply */
1048 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1050 silc_server_query_resolve_reply,
1052 query->queries_left++;
1055 /* Cleanup this temporary context */
1056 for (i = 0; i < query->querylist_count; i++) {
1058 for (k = 0; k < query->querylist[i].argc; k++)
1059 silc_free(query->querylist[i].arg[k]);
1060 silc_free(query->querylist[i].arg);
1061 silc_free(query->querylist[i].arg_lens);
1062 silc_free(query->querylist[i].arg_types);
1064 silc_free(query->querylist);
1065 query->querylist = NULL;
1066 query->querylist_count = 0;
1070 SILC_LOG_DEBUG(("Resolving client information"));
1072 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1073 /* The entry is being resolved by some other external query already.
1074 Attach to that query instead of resolving again. */
1075 ident = client_entry->resolve_cmd_ident;
1076 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1077 silc_server_query_resolve_reply, query))
1078 query->queries_left++;
1080 /* This entry will be resolved */
1081 ident = ++server->cmd_ident;
1083 switch (query->querycmd) {
1085 case SILC_COMMAND_WHOIS:
1086 case SILC_COMMAND_IDENTIFY:
1087 /* Take existing query context if exist for this connection */
1088 for (i = 0; i < query->querylist_count; i++)
1089 if (query->querylist[i].sock == sock) {
1090 r = &query->querylist[i];
1095 /* Allocate new temp query list context */
1096 query->querylist = silc_realloc(query->querylist,
1097 sizeof(*query->querylist) *
1098 (query->querylist_count + 1));
1099 r = &query->querylist[query->querylist_count];
1100 query->querylist_count++;
1101 memset(r, 0, sizeof(*r));
1104 if (SILC_IS_LOCAL(client_entry))
1109 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1110 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1111 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1113 /* Add the client entry to be resolved */
1114 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1115 r->arg[r->argc] = silc_memdup(idp->data, idp->len);
1116 r->arg_lens[r->argc] = idp->len;
1117 r->arg_types[r->argc] = r->argc + 4;
1119 silc_buffer_free(idp);
1123 case SILC_COMMAND_WHOWAS:
1124 /* We must send WHOWAS command since it's the only the way of
1125 resolving clients that are not present in the network anymore. */
1126 silc_server_send_command(server, sock, query->querycmd, ident, 1,
1127 1, query->nickname, strlen(query->nickname));
1128 if (silc_server_command_pending(server, query->querycmd, ident,
1129 silc_server_query_resolve_reply, query))
1130 query->queries_left++;
1135 /* Mark the entry as being resolved */
1136 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1137 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1138 client_entry->resolve_cmd_ident = ident;
1139 client_entry->updated = time(NULL);
1141 /* Save the queried ID, which we will reprocess after we get this and
1142 all other queries back. */
1143 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1144 (query->queries_count + 1));
1145 if (query->queries) {
1146 i = query->queries_count;
1147 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1148 query->queries[i].id_type = SILC_ID_CLIENT;
1149 query->queries[i].ident = ident;
1150 query->queries_count++;
1154 /* Reply callback called after one resolving has been completed. If
1155 all resolvings has been received then we will continue with sending
1156 the command reply to the original sender of the query. */
1158 void silc_server_query_resolve_reply(void *context, void *reply)
1160 SilcServerQuery query = context;
1161 SilcServer server = query->cmd->server;
1162 SilcServerCommandReplyContext cmdr = reply;
1163 SilcUInt16 ident = cmdr->ident;
1164 SilcStatus error = SILC_STATUS_OK;
1165 SilcServerQueryID id = NULL;
1166 SilcClientEntry client_entry;
1169 /* One less query left */
1170 query->queries_left--;
1172 silc_command_get_status(cmdr->payload, NULL, &error);
1173 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1174 query->queries_left, error));
1176 /* If no error then skip to other stuff */
1177 if (error == SILC_STATUS_OK)
1180 /* Error occurred during resolving */
1182 /* Find the resolved client ID */
1183 for (i = 0; i < query->queries_count; i++) {
1184 if (query->queries[i].ident != ident)
1187 id = &query->queries[i];
1189 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1191 /* If timeout occurred for local entry when resolving attributes
1192 mark that this client doesn't support attributes in WHOIS. This
1193 assures we won't send the request again to the client. */
1194 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1195 client_entry = silc_idlist_find_client_by_id(server->local_list,
1196 id->id, TRUE, NULL);
1197 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1198 silc_id_render(id->id, SILC_ID_CLIENT)));
1199 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1200 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1201 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1206 /* Remove the RESOLVING status from the client entry */
1207 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1208 client_entry = silc_idlist_find_client_by_id(server->local_list,
1209 id->id, TRUE, NULL);
1211 client_entry = silc_idlist_find_client_by_id(server->global_list,
1212 id->id, TRUE, NULL);
1214 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1221 /* If there are queries left then wait for them */
1222 if (query->queries_left)
1225 SILC_LOG_DEBUG(("Reprocess the query"));
1227 /* We have received all queries. Now re-search all information required
1228 to complete this query. Reason we cannot save the values found in
1229 the first search is that SilcClientEntry, SilcServerEntry and
1230 SilcChannelEntry pointers may become invalid while we were waiting
1231 for these resolvings. */
1232 silc_server_query_process(server, query, FALSE);
1235 /* Send the reply to the original query. If arguments are NULL then this
1236 sends only the errors that has occurred during the processing of the
1237 query. This sends the errors always after sending all the found
1238 information. The query is over after this function returns and the
1239 `query' will become invalid. This is called only after all informations
1240 has been resolved. This means that if something is not found or is
1241 incomplete in this function we were unable to resolve the information
1242 or it does not exist at all. */
1244 void silc_server_query_send_reply(SilcServer server,
1245 SilcServerQuery query,
1246 SilcClientEntry *clients,
1247 SilcUInt32 clients_count,
1248 SilcServerEntry *servers,
1249 SilcUInt32 servers_count,
1250 SilcChannelEntry *channels,
1251 SilcUInt32 channels_count)
1253 SilcServerCommandContext cmd = query->cmd;
1254 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1259 int i, k, valid_count;
1260 char nh[256], uh[256];
1261 bool sent_reply = FALSE;
1263 SILC_LOG_DEBUG(("Sending reply to query"));
1264 SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1265 SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1266 SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1267 SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1269 status = SILC_STATUS_OK;
1272 if (clients_count) {
1273 SilcClientEntry entry;
1274 SilcSocketConnection hsock;
1276 /* Mark all invalid entries */
1277 for (i = 0, valid_count = 0; i < clients_count; i++) {
1282 switch (query->querycmd) {
1283 case SILC_COMMAND_WHOIS:
1284 if (!entry->nickname || !entry->username || !entry->userinfo ||
1285 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1286 /* When querying by ID, every "unfound" entry must cause error */
1288 silc_server_query_add_error_id(server, query,
1289 SILC_STATUS_ERR_TIMEDOUT,
1290 entry->id, SILC_ID_CLIENT);
1296 case SILC_COMMAND_IDENTIFY:
1297 if (!entry->nickname ||
1298 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1299 /* When querying by ID, every "unfound" entry must cause error */
1301 silc_server_query_add_error_id(server, query,
1302 SILC_STATUS_ERR_TIMEDOUT,
1303 entry->id, SILC_ID_CLIENT);
1309 case SILC_COMMAND_WHOWAS:
1310 if (!entry->nickname || !entry->username ||
1311 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1320 /* Start processing found clients */
1321 status = SILC_STATUS_OK;
1322 if (valid_count > 1)
1323 status = SILC_STATUS_LIST_START;
1325 /* Now do the sending of valid entries */
1327 for (i = 0; i < clients_count && valid_count; i++) {
1333 status = SILC_STATUS_LIST_ITEM;
1334 if (valid_count > 1 && k == valid_count - 1
1335 && !servers_count && !channels_count && !query->errors_count)
1336 status = SILC_STATUS_LIST_END;
1337 if (query->reply_count && k - 1 == query->reply_count)
1338 status = SILC_STATUS_LIST_END;
1340 SILC_LOG_DEBUG(("%s: client %s",
1341 (status == SILC_STATUS_OK ? " OK" :
1342 status == SILC_STATUS_LIST_START ? "START" :
1343 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1344 status == SILC_STATUS_LIST_END ? " END" :
1345 " : "), entry->nickname));
1347 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1348 memset(uh, 0, sizeof(uh));
1349 memset(nh, 0, sizeof(nh));
1351 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1352 if (!strchr(entry->nickname, '@')) {
1353 silc_strncat(nh, sizeof(nh), "@", 1);
1354 if (entry->servername) {
1355 silc_strncat(nh, sizeof(nh), entry->servername,
1356 strlen(entry->servername));
1358 len = entry->router ? strlen(entry->router->server_name) :
1359 strlen(server->server_name);
1360 silc_strncat(nh, sizeof(nh), entry->router ?
1361 entry->router->server_name :
1362 server->server_name, len);
1366 switch (query->querycmd) {
1368 case SILC_COMMAND_WHOIS:
1370 unsigned char idle[4], mode[4];
1371 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1372 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1374 memset(fempty, 0, sizeof(fempty));
1375 memset(idle, 0, sizeof(idle));
1376 silc_strncat(uh, sizeof(uh), entry->username,
1377 strlen(entry->username));
1378 if (!strchr(entry->username, '@') && entry->connection) {
1379 hsock = entry->connection;
1380 silc_strncat(uh, sizeof(uh), "@", 1);
1381 len = strlen(hsock->hostname);
1382 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1385 if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1387 silc_server_get_client_channel_list(server, entry, FALSE,
1388 FALSE, &umode_list);
1391 silc_server_get_client_channel_list(server, entry, TRUE,
1394 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1395 fingerprint = entry->data.fingerprint;
1399 SILC_PUT32_MSB(entry->mode, mode);
1400 if (entry->connection)
1401 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1403 /* If Requested Attribute were present, and we do not have the
1404 attributes we will reply to them on behalf of the client. */
1407 if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1408 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1409 entry->attrs = silc_buffer_steal(tmpattrs, &len);
1410 entry->attrs_len = len;
1411 silc_buffer_free(tmpattrs);
1413 attrs = entry->attrs;
1414 len = entry->attrs_len;
1417 /* Send command reply */
1418 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1419 status, 0, ident, 10,
1420 2, idp->data, idp->len,
1424 strlen(entry->userinfo),
1425 6, channels ? channels->data : NULL,
1426 channels ? channels->len : 0,
1430 fingerprint ? 20 : 0,
1431 10, umode_list ? umode_list->data :
1432 NULL, umode_list ? umode_list->len :
1437 /* For now we always delete Requested Attributes, unless the client
1438 is detached, in which case we don't want to reconstruct the
1439 same data everytime */
1440 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1441 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1442 silc_free(entry->attrs);
1443 entry->attrs = NULL;
1447 silc_buffer_free(channels);
1449 silc_buffer_free(umode_list);
1455 case SILC_COMMAND_IDENTIFY:
1456 if (!entry->username) {
1457 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1458 status, 0, ident, 2,
1459 2, idp->data, idp->len,
1463 silc_strncat(uh, sizeof(uh), entry->username,
1464 strlen(entry->username));
1465 if (!strchr(entry->username, '@') && entry->connection) {
1466 hsock = entry->connection;
1467 silc_strncat(uh, sizeof(uh), "@", 1);
1468 len = strlen(hsock->hostname);
1469 silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1472 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1473 status, 0, ident, 3,
1474 2, idp->data, idp->len,
1481 case SILC_COMMAND_WHOWAS:
1482 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1483 if (!strchr(entry->username, '@'))
1484 silc_strncat(uh, sizeof(uh), "@*private*", 10);
1486 /* Send command reply */
1487 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1488 status, 0, ident, 4,
1489 2, idp->data, idp->len,
1494 strlen(entry->userinfo) : 0);
1499 silc_buffer_free(idp);
1501 if (status == SILC_STATUS_LIST_END)
1507 /* Not one valid entry was found, send error. If nickname was used
1508 in query send error based on that, otherwise the query->errors
1509 already includes proper errors. */
1510 if (query->nickname || (!query->nickname && !query->ids && query->attrs))
1511 silc_server_query_add_error(server, query, TRUE, 1,
1512 SILC_STATUS_ERR_NO_SUCH_NICK);
1517 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1518 SilcServerEntry entry;
1520 if (status == SILC_STATUS_OK && servers_count > 1)
1521 status = SILC_STATUS_LIST_START;
1524 for (i = 0; i < servers_count; i++) {
1528 status = SILC_STATUS_LIST_ITEM;
1529 if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1530 !query->errors_count)
1531 status = SILC_STATUS_LIST_END;
1532 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1533 !query->errors_count)
1534 status = SILC_STATUS_LIST_END;
1535 if (query->reply_count && k - 1 == query->reply_count)
1536 status = SILC_STATUS_LIST_END;
1538 SILC_LOG_DEBUG(("%s: server %s",
1539 (status == SILC_STATUS_OK ? " OK" :
1540 status == SILC_STATUS_LIST_START ? "START" :
1541 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1542 status == SILC_STATUS_LIST_END ? " END" :
1544 entry->server_name ? entry->server_name : ""));
1546 /* Send command reply */
1547 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1548 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1549 status, 0, ident, 2,
1550 2, idp->data, idp->len,
1551 3, entry->server_name,
1552 entry->server_name ?
1553 strlen(entry->server_name) : 0);
1554 silc_buffer_free(idp);
1557 if (status == SILC_STATUS_LIST_END)
1564 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1565 SilcChannelEntry entry;
1567 if (status == SILC_STATUS_OK && channels_count > 1)
1568 status = SILC_STATUS_LIST_START;
1571 for (i = 0; i < channels_count; i++) {
1572 entry = channels[i];
1575 status = SILC_STATUS_LIST_ITEM;
1576 if (channels_count == 1 && status != SILC_STATUS_OK &&
1577 !query->errors_count)
1578 status = SILC_STATUS_LIST_END;
1579 if (channels_count > 1 && k == channels_count - 1 &&
1580 !query->errors_count)
1581 status = SILC_STATUS_LIST_END;
1582 if (query->reply_count && k - 1 == query->reply_count)
1583 status = SILC_STATUS_LIST_END;
1585 SILC_LOG_DEBUG(("%s: channel %s",
1586 (status == SILC_STATUS_OK ? " OK" :
1587 status == SILC_STATUS_LIST_START ? "START" :
1588 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1589 status == SILC_STATUS_LIST_END ? " END" :
1591 entry->channel_name ? entry->channel_name : ""));
1593 /* Send command reply */
1594 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1595 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1596 status, 0, ident, 2,
1597 2, idp->data, idp->len,
1598 3, entry->channel_name,
1599 entry->channel_name ?
1600 strlen(entry->channel_name) : 0);
1601 silc_buffer_free(idp);
1604 if (status == SILC_STATUS_LIST_END)
1611 if (query->errors_count) {
1614 if (status == SILC_STATUS_OK && query->errors_count > 1)
1615 status = SILC_STATUS_LIST_START;
1618 for (i = 0; i < query->errors_count; i++) {
1621 /* Take error argument */
1622 if (query->errors[i].from_cmd) {
1624 tmp = silc_argument_get_arg_type(cmd->args,
1625 query->errors[i].index, &len);
1626 if (query->errors[i].index == 1)
1627 type = 3; /* Nickname */
1630 } else if (!query->errors[i].id) {
1632 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1633 query->ids[query->errors[k].index].id_type);
1638 idp = silc_id_payload_encode(query->errors[i].id,
1639 query->errors[k].id_type);
1646 status = SILC_STATUS_LIST_ITEM;
1647 if (query->errors_count == 1 && status != SILC_STATUS_OK)
1648 status = SILC_STATUS_LIST_END;
1649 if (query->errors_count > 1 && k == query->errors_count - 1)
1650 status = SILC_STATUS_LIST_END;
1651 if (query->reply_count && k - 1 == query->reply_count)
1652 status = SILC_STATUS_LIST_END;
1654 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1655 (status == SILC_STATUS_OK ? " OK" :
1656 status == SILC_STATUS_LIST_START ? "START" :
1657 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1658 status == SILC_STATUS_LIST_END ? " END" :
1660 silc_get_status_message(query->errors[i].error),
1661 query->errors[i].error));
1664 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1665 (status == SILC_STATUS_OK ?
1666 query->errors[i].error : status),
1667 (status == SILC_STATUS_OK ?
1668 0 : query->errors[i].error), ident, 1,
1670 silc_buffer_free(idp);
1673 if (status == SILC_STATUS_LIST_END)
1680 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1683 silc_server_query_free(query);
1686 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1687 of the client since we were unable to resolve them from the client.
1688 Either client does not support Requested Attributes or isn't replying
1689 to them like it should. */
1691 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1692 SilcServerQuery query,
1693 SilcClientEntry client_entry)
1695 SilcBuffer buffer = NULL;
1696 SilcAttribute attribute;
1697 SilcAttributePayload attr;
1698 SilcAttributeObjPk pk;
1699 SilcAttributeObjService service;
1701 unsigned char sign[2048 + 1];
1702 SilcUInt32 sign_len;
1704 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1706 /* Go through all requested attributes */
1707 silc_dlist_start(query->attrs);
1708 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1709 attribute = silc_attribute_get_attribute(attr);
1710 switch (attribute) {
1712 case SILC_ATTRIBUTE_SERVICE:
1713 /* Put SERVICE. Put only SILC service. */
1714 memset(&service, 0, sizeof(service));
1715 service.port = (server->config->server_info->primary ?
1716 server->config->server_info->primary->port : SILC_PORT);
1717 silc_strncat(service.address, sizeof(service.address),
1718 server->server_name, strlen(server->server_name));
1719 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1720 if (client_entry->connection)
1721 service.idle = time(NULL) - client_entry->data.last_receive;
1722 buffer = silc_attribute_payload_encode(buffer, attribute,
1723 SILC_ATTRIBUTE_FLAG_VALID,
1724 &service, sizeof(service));
1729 case SILC_ATTRIBUTE_STATUS_MOOD:
1730 /* Put STATUS_MOOD */
1731 buffer = silc_attribute_payload_encode(buffer, attribute,
1732 SILC_ATTRIBUTE_FLAG_VALID,
1734 SILC_ATTRIBUTE_MOOD_NORMAL,
1735 sizeof(SilcUInt32));
1740 case SILC_ATTRIBUTE_STATUS_FREETEXT:
1741 /* Put STATUS_FREETEXT. We just tell in the message that we are
1742 replying on behalf of the client. */
1744 "This information was provided by the server on behalf of the user";
1745 buffer = silc_attribute_payload_encode(buffer, attribute,
1746 SILC_ATTRIBUTE_FLAG_VALID,
1752 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1753 /* Put PREFERRED_CONTACT */
1754 buffer = silc_attribute_payload_encode(buffer, attribute,
1755 SILC_ATTRIBUTE_FLAG_VALID,
1757 SILC_ATTRIBUTE_CONTACT_CHAT,
1758 sizeof(SilcUInt32));
1763 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1764 /* Put USER_PUBLIC_KEY */
1765 if (client_entry->data.public_key) {
1766 pk.type = "silc-rsa";
1767 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1769 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1770 SILC_ATTRIBUTE_FLAG_VALID :
1771 SILC_ATTRIBUTE_FLAG_INVALID,
1779 /* No public key available */
1780 buffer = silc_attribute_payload_encode(buffer, attribute,
1781 SILC_ATTRIBUTE_FLAG_INVALID,
1788 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1789 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1790 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1793 /* For other attributes we cannot reply so mark it invalid */
1794 buffer = silc_attribute_payload_encode(buffer, attribute,
1795 SILC_ATTRIBUTE_FLAG_INVALID,
1803 /* Always put our public key. This assures that we send at least
1804 something valid back always. */
1805 pk.type = "silc-rsa";
1806 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1807 buffer = silc_attribute_payload_encode(buffer,
1808 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1809 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1810 SILC_ATTRIBUTE_FLAG_INVALID,
1816 /* Finally compute the digital signature of all the data we provided
1817 as an indication that we provided rightfull information, and this
1818 also authenticates our public key. */
1819 if (silc_pkcs_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1 &&
1820 silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
1821 buffer->data, buffer->len,
1825 pk.data_len = sign_len;
1827 silc_attribute_payload_encode(buffer,
1828 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1829 SILC_ATTRIBUTE_FLAG_VALID,
1838 /* Find client by the Client ID indicated by the `client_id', and if not
1839 found then query it by using WHOIS command. The client information
1840 is also resolved if the cached information is incomplete or if the
1841 `always_resolve' is set to TRUE. The indication whether requested
1842 client was being resolved is saved into `resolved'. If the client
1843 is not being resolved its entry is returned by this function. NULL
1844 is returned if client is resolved. */
1846 SilcClientEntry silc_server_query_client(SilcServer server,
1847 const SilcClientID *client_id,
1848 bool always_resolve,
1851 SilcClientEntry client;
1853 SILC_LOG_DEBUG(("Resolving client by client ID"));
1858 client = silc_idlist_find_client_by_id(server->local_list,
1859 (SilcClientID *)client_id,
1862 client = silc_idlist_find_client_by_id(server->global_list,
1863 (SilcClientID *)client_id,
1865 if (!client && server->server_type == SILC_ROUTER)
1869 if (!client && server->standalone)
1872 if (!client || !client->nickname || !client->username ||
1874 SilcBuffer buffer, idp;
1877 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1878 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1879 client->resolve_cmd_ident = ++server->cmd_ident;
1882 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1883 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
1884 server->cmd_ident, 1,
1885 4, idp->data, idp->len);
1886 silc_server_packet_send(server, client ? client->router->connection :
1887 SILC_PRIMARY_ROUTE(server),
1888 SILC_PACKET_COMMAND, 0,
1889 buffer->data, buffer->len, FALSE);
1890 silc_buffer_free(idp);
1891 silc_buffer_free(buffer);