5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 - 2005, 2007 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 SilcPacketStream 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 unsigned int index : 15; /* Index to IDs */
46 unsigned int type : 2; /* 0 = take from query->ids, 1 = take
47 from args, 2 = no args in error. */
48 unsigned int error : 7; /* The actual error (SilcStatus) */
49 } *SilcServerQueryError;
51 /* Query session context */
54 char nickname[128 + 1]; /* Queried nickname, normalized */
55 char nick_server[128 + 1]; /* Queried nickname's server */
56 char *server_name; /* Queried server name, normalized */
57 char *channel_name; /* Queried channel name, normalized */
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 SilcPacketStream 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->server_name);
124 silc_free(query->channel_name);
126 for (i = 0; i < query->ids_count; i++)
127 silc_free(query->ids[i].id);
128 silc_free(query->ids);
131 silc_attribute_payload_list_free(query->attrs);
133 for (i = 0; i < query->errors_count; i++)
134 silc_free(query->errors[i].id);
135 silc_free(query->errors);
137 memset(query, 'F', sizeof(*query));
141 /* Send error reply indicated by the `error' to the original sender of
144 void silc_server_query_send_error(SilcServer server,
145 SilcServerQuery query,
146 SilcStatus error, ...)
149 unsigned char *data = NULL;
150 SilcUInt32 data_len = 0, data_type = 0, argc = 0;
153 data_type = va_arg(va, SilcUInt32);
156 data = va_arg(va, unsigned char *);
157 data_len = va_arg(va, SilcUInt32);
160 SILC_LOG_DEBUG(("ERROR: %s (%d)", silc_get_status_message(error), error));
162 /* Send the command reply with error */
163 silc_server_send_command_reply(server, query->cmd->sock,
164 query->querycmd, error, 0,
165 silc_command_get_ident(query->cmd->payload),
166 argc, data_type, data, data_len);
170 /* Add error to error list. Multiple errors may occur during the query
171 processing and this function can be used to add one error. The
172 `index' is the index to the command context which includes the argument
173 which caused the error, or it is the index to query->ids, depending
174 on value of `type'. If `type' is 0 the index is to query->ids, if
175 it is 1 it is index to the command context arguments, and if it is
176 2 the index is ignored and no argument is included in the error. */
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].type = type;
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].type = 0;
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 SilcBool 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"));
296 server->stat.commands_sent++;
298 /* Send WHOIS command to our router */
299 old_ident = silc_command_get_ident(query->cmd->payload);
300 silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
301 tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
302 silc_server_packet_send(server,
303 SILC_PRIMARY_ROUTE(server),
304 SILC_PACKET_COMMAND, 0,
305 tmpbuf->data, silc_buffer_len(tmpbuf));
306 silc_command_set_ident(query->cmd->payload, old_ident);
307 silc_buffer_free(tmpbuf);
309 query->resolved = TRUE;
311 /* Continue parsing the query after received reply from router */
312 silc_server_command_pending(server, query->querycmd, server->cmd_ident,
313 silc_server_query_send_router_reply, query);
316 /* Reply callback called after primary router has replied to our initial
317 sending of the query to it. We will proceed the query in this function. */
319 void silc_server_query_send_router_reply(void *context, void *reply)
321 SilcServerQuery query = context;
322 SilcServer server = query->cmd->server;
323 SilcServerCommandReplyContext cmdr = reply;
325 SILC_LOG_DEBUG(("Received reply from router to query"));
327 /* If the original command caller has gone away, just stop. */
328 if (!silc_packet_stream_is_valid(query->cmd->sock)) {
329 SILC_LOG_DEBUG(("Original command caller vanished"));
330 silc_server_query_free(query);
334 /* Check if router sent error reply */
335 if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
338 SILC_LOG_DEBUG(("Sending error to original query"));
341 server->stat.commands_sent++;
343 /* Send the same command reply payload which contains the error */
344 silc_command_set_command(cmdr->payload, query->querycmd);
345 silc_command_set_ident(cmdr->payload,
346 silc_command_get_ident(query->cmd->payload));
347 buffer = silc_command_payload_encode_payload(cmdr->payload);
348 silc_server_packet_send(server, query->cmd->sock,
349 SILC_PACKET_COMMAND_REPLY, 0,
350 buffer->data, silc_buffer_len(buffer));
351 silc_buffer_free(buffer);
352 silc_server_query_free(query);
356 /* Continue with parsing */
357 silc_server_query_parse(server, query);
360 /* Parse the command query and start processing the queries in detail. */
362 void silc_server_query_parse(SilcServer server, SilcServerQuery query)
364 SilcServerCommandContext cmd = query->cmd;
365 SilcIDListData idata = silc_packet_get_context(cmd->sock);
367 SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
371 SILC_LOG_DEBUG(("Parsing %s query",
372 silc_get_command_name(query->querycmd)));
374 switch (query->querycmd) {
376 case SILC_COMMAND_WHOIS:
377 /* Get requested attributes if set */
378 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
379 if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
380 query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
382 /* When Requested Attributes is present we will assure that this
383 client cannot execute the WHOIS command too fast. This would be
384 same as having SILC_CF_LAG_STRICT. */
385 if (idata && idata->conn_type == SILC_CONN_CLIENT)
386 ((SilcClientEntry)idata)->fast_command = 6;
389 /* Get Client IDs if present. Take IDs always instead of nickname. */
390 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
394 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
395 if (!tmp && !query->attrs) {
396 /* No nickname, no ids and no attributes - send error */
397 silc_server_query_send_error(server, query,
398 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
399 silc_server_query_free(query);
403 /* Get the nickname@server string and parse it */
404 if (tmp && ((tmp_len > 128) ||
405 !silc_parse_userfqdn(tmp, query->nickname,
406 sizeof(query->nickname),
408 sizeof(query->nick_server)))) {
409 silc_server_query_send_error(server, query,
410 SILC_STATUS_ERR_BAD_NICKNAME, 0);
411 silc_server_query_free(query);
417 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
418 SILC_STRING_UTF8, 128, &tmp_len);
420 silc_server_query_send_error(server, query,
421 SILC_STATUS_ERR_BAD_NICKNAME, 0);
422 silc_server_query_free(query);
425 memset(query->nickname, 0, sizeof(query->nickname));
426 silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
431 /* Parse the IDs included in the query */
432 query->ids = silc_calloc(argc, sizeof(*query->ids));
434 for (i = 0; i < argc; i++) {
435 tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
439 if (!silc_id_payload_parse_id(tmp, tmp_len, &id) ||
440 id.type != SILC_ID_CLIENT) {
441 silc_server_query_add_error(server, query, 1, i + 4,
442 SILC_STATUS_ERR_BAD_CLIENT_ID);
446 /* Normal server must check whether this ID exist, and if not then
447 send the query to router, unless done so already */
448 if (server->server_type == SILC_SERVER && !query->resolved) {
449 if (!silc_idlist_find_client_by_id(server->local_list,
450 &id.u.client_id, TRUE, NULL)) {
451 if (idata->conn_type != SILC_CONN_CLIENT ||
452 !silc_idlist_find_client_by_id(server->global_list,
453 &id.u.client_id, TRUE, NULL)) {
454 silc_server_query_send_router(server, query);
455 for (i = 0; i < query->ids_count; i++)
456 silc_free(query->ids[i].id);
457 silc_free(query->ids);
459 query->ids_count = 0;
465 query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
467 query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
472 /* Get the max count of reply messages allowed */
473 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
474 if (tmp && tmp_len == sizeof(SilcUInt32))
475 SILC_GET32_MSB(query->reply_count, tmp);
478 case SILC_COMMAND_WHOWAS:
480 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
482 silc_server_query_send_error(server, query,
483 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
484 silc_server_query_free(query);
488 /* Get the nickname@server string and parse it */
490 !silc_parse_userfqdn(tmp, query->nickname, sizeof(query->nickname),
491 query->nick_server, sizeof(query->nick_server))) {
492 silc_server_query_send_error(server, query,
493 SILC_STATUS_ERR_BAD_NICKNAME, 0);
494 silc_server_query_free(query);
499 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
500 SILC_STRING_UTF8, 128, &tmp_len);
502 silc_server_query_send_error(server, query,
503 SILC_STATUS_ERR_BAD_NICKNAME, 0);
504 silc_server_query_free(query);
507 memset(query->nickname, 0, sizeof(query->nickname));
508 silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
511 /* Get the max count of reply messages allowed */
512 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
513 if (tmp && tmp_len == sizeof(SilcUInt32))
514 SILC_GET32_MSB(query->reply_count, tmp);
517 case SILC_COMMAND_IDENTIFY:
518 /* Get IDs if present. Take IDs always instead of names. */
519 tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
522 /* Try get nickname */
523 tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
525 /* Get the nickname@server string and parse it */
527 !silc_parse_userfqdn(tmp, query->nickname,
528 sizeof(query->nickname),
530 sizeof(query->nick_server)))
531 silc_server_query_add_error(server, query, 1, 1,
532 SILC_STATUS_ERR_BAD_NICKNAME);
535 tmp = silc_identifier_check(query->nickname, strlen(query->nickname),
536 SILC_STRING_UTF8, 128, &tmp_len);
538 silc_server_query_send_error(server, query,
539 SILC_STATUS_ERR_BAD_NICKNAME, 0);
540 silc_server_query_free(query);
543 memset(query->nickname, 0, sizeof(query->nickname));
544 silc_snprintf(query->nickname, sizeof(query->nickname), "%s", tmp);
548 /* Try get server name */
549 tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
551 /* Check server name */
552 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
555 silc_server_query_send_error(server, query,
556 SILC_STATUS_ERR_BAD_SERVER, 0);
557 silc_server_query_free(query);
560 query->server_name = tmp;
563 /* Get channel name */
564 tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
565 if (tmp && tmp_len <= 256) {
566 /* Check channel name */
567 tmp = silc_identifier_check(tmp, tmp_len, SILC_STRING_UTF8,
570 silc_server_query_send_error(server, query,
571 SILC_STATUS_ERR_BAD_CHANNEL, 0);
572 silc_server_query_free(query);
575 query->channel_name = tmp;
578 if (!query->nickname[0] && !query->server_name && !query->channel_name) {
579 silc_server_query_send_error(server, query,
580 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
581 silc_server_query_free(query);
586 /* Parse the IDs included in the query */
587 query->ids = silc_calloc(argc, sizeof(*query->ids));
589 for (i = 0; i < argc; i++) {
590 tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
594 if (!silc_id_payload_parse_id(tmp, tmp_len, &id)) {
595 silc_server_query_add_error(server, query, 1, i + 5,
596 SILC_STATUS_ERR_BAD_CLIENT_ID);
600 /* Normal server must check whether this ID exist, and if not then
601 send the query to router, unless done so already */
602 if (server->server_type == SILC_SERVER && !query->resolved) {
603 if (id.type == SILC_ID_CLIENT) {
604 if (!silc_idlist_find_client_by_id(server->local_list,
605 &id.u.client_id, TRUE, NULL)) {
606 if (idata->conn_type != SILC_CONN_CLIENT ||
607 !silc_idlist_find_client_by_id(server->global_list,
608 &id.u.client_id, TRUE,
610 silc_server_query_send_router(server, query);
611 for (i = 0; i < query->ids_count; i++)
612 silc_free(query->ids[i].id);
613 silc_free(query->ids);
615 query->ids_count = 0;
620 /* For now all other ID's except Client ID's are explicitly
621 sent to router for resolving. */
622 silc_server_query_send_router(server, query);
623 for (i = 0; i < query->ids_count; i++)
624 silc_free(query->ids[i].id);
625 silc_free(query->ids);
627 query->ids_count = 0;
632 if (id.type == SILC_ID_CLIENT)
633 query->ids[query->ids_count].id = silc_id_dup(&id.u.client_id,
635 if (id.type == SILC_ID_SERVER)
636 query->ids[query->ids_count].id = silc_id_dup(&id.u.server_id,
638 if (id.type == SILC_ID_CHANNEL)
639 query->ids[query->ids_count].id = silc_id_dup(&id.u.channel_id,
641 query->ids[query->ids_count].id_type = id.type;
646 /* Get the max count of reply messages allowed */
647 tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
648 if (tmp && tmp_len == sizeof(SilcUInt32))
649 SILC_GET32_MSB(query->reply_count, tmp);
653 /* Start processing the query information */
654 silc_server_query_process(server, query, TRUE);
657 /* Context for holding clients searched by public key. */
659 SilcClientEntry **clients;
660 SilcUInt32 *clients_count;
662 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
664 /* SKR find callbcak */
666 static void silc_server_query_skr_callback(SilcSKR skr,
668 SilcSKRStatus status,
672 SilcServerPublicKeyUser uc = context;
676 (*uc->clients) = silc_realloc((*uc->clients),
677 sizeof((**uc->clients)) *
678 ((*uc->clients_count) +
679 silc_dlist_count(keys)));
681 silc_dlist_start(keys);
682 while ((key = silc_dlist_get(keys)))
683 (*uc->clients)[(*uc->clients_count)++] = key->key_context;
686 silc_dlist_uninit(keys);
689 silc_skr_find_free(find);
692 /* If clients are set, limit the found clients using the attributes in
693 the query. If clients are not set, try to find some clients using
696 void silc_server_query_check_attributes(SilcServer server,
697 SilcServerQuery query,
698 SilcClientEntry **clients,
699 SilcUInt32 *clients_count) {
700 SilcClientEntry entry;
701 SilcAttributePayload attr;
702 SilcAttribute attribute;
703 SilcAttributeObjPk pk;
704 SilcPublicKey publickey, cmp_pubkey;
706 SilcBool found = FALSE, no_clients = FALSE, search_pubkey = FALSE;
709 /* If no clients were found, we only check the attributes
710 if the user wasn't searching for nickname/ids */
713 if (query->nickname[0] || query->ids_count)
717 silc_dlist_start(query->attrs);
718 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
719 attribute = silc_attribute_get_attribute(attr);
722 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
723 SILC_LOG_DEBUG(("Finding clients by public key attribute"));
725 if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
728 if (!strcmp(pk.type, "silc-rsa"))
729 type = SILC_PKCS_SILC;
730 else if (!strcmp(pk.type, "ssh-rsa"))
731 type = SILC_PKCS_SSH2;
732 else if (!strcmp(pk.type, "x509v3-sign-rsa"))
733 type = SILC_PKCS_X509V3;
734 else if (!strcmp(pk.type, "pgp-sign-rsa"))
735 type = SILC_PKCS_OPENPGP;
739 if (!silc_pkcs_public_key_alloc(type, pk.data, pk.data_len,
745 search_pubkey = TRUE;
747 /* If no clients were set on calling this function, we just search
748 for clients, otherwise we try to limit the clients. */
750 SilcServerPublicKeyUserStruct usercontext;
753 usercontext.clients = clients;
754 usercontext.clients_count = clients_count;
755 usercontext.found = FALSE;
757 find = silc_skr_find_alloc();
761 silc_skr_find_set_public_key(find, publickey);
762 silc_skr_find_set_usage(find, SILC_SKR_USAGE_IDENTIFICATION);
763 silc_skr_find(server->repository, server->schedule,
764 find, silc_server_query_skr_callback, &usercontext);
766 if (usercontext.found == TRUE)
769 for (i = 0; i < *clients_count; i++) {
770 entry = (*clients)[i];
772 if (!entry->data.public_key)
775 if (silc_server_get_public_key_by_client(server, entry,
777 if (silc_pkcs_public_key_compare(cmp_pubkey, publickey)) {
783 (*clients)[i] = NULL;
788 silc_pkcs_public_key_free(publickey);
793 if (!found && !query->nickname[0] && !query->ids)
794 silc_server_query_add_error(server, query, 2, 0,
796 SILC_STATUS_ERR_NO_SUCH_PUBLIC_KEY :
797 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
800 /* Processes the parsed query. This does the actual finding of the
801 queried information and prepares for sending reply to the original
802 sender of the query command. */
804 void silc_server_query_process(SilcServer server, SilcServerQuery query,
807 SilcServerCommandContext cmd = query->cmd;
808 SilcIDListData idata = silc_packet_get_context(cmd->sock);
809 SilcBool check_global = FALSE;
811 SilcClientEntry *clients = NULL, client_entry;
812 SilcChannelEntry *channels = NULL;
813 SilcServerEntry *servers = NULL;
814 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
817 SILC_LOG_DEBUG(("Processing %s query",
818 silc_get_command_name(query->querycmd)));
820 /* Check global lists if query is coming from client or we are not
821 normal server (we know global information). */
822 if (idata->conn_type == SILC_CONN_CLIENT)
824 else if (server->server_type != SILC_SERVER)
827 if (query->nickname[0]) {
828 /* Get all clients matching nickname from local list */
829 if (!silc_idlist_get_clients_by_hash(server->local_list,
830 query->nickname, server->md5hash,
831 &clients, &clients_count))
832 silc_idlist_get_clients_by_nickname(server->local_list,
835 /* XXX nick_server may not be set */
836 &clients, &clients_count);
838 /* Check global list as well */
840 if (!silc_idlist_get_clients_by_hash(server->global_list,
841 query->nickname, server->md5hash,
842 &clients, &clients_count))
843 silc_idlist_get_clients_by_nickname(server->global_list,
846 /* XXX nick_server may not be set */
847 &clients, &clients_count);
851 silc_server_query_add_error(server, query, 1, 1,
852 SILC_STATUS_ERR_NO_SUCH_NICK);
855 if (query->server_name) {
856 /* Find server by name */
857 entry = silc_idlist_find_server_by_name(server->local_list,
858 query->server_name, TRUE, NULL);
859 if (!entry && check_global)
860 entry = silc_idlist_find_server_by_name(server->global_list,
861 query->server_name, TRUE, NULL);
863 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
864 servers[servers_count++] = (SilcServerEntry)entry;
868 silc_server_query_add_error(server, query, 1, 2,
869 SILC_STATUS_ERR_NO_SUCH_SERVER);
872 if (query->channel_name) {
873 /* Find channel by name */
874 entry = silc_idlist_find_channel_by_name(server->local_list,
875 query->channel_name, NULL);
876 if (!entry && check_global)
877 entry = silc_idlist_find_channel_by_name(server->global_list,
878 query->channel_name, NULL);
880 channels = silc_realloc(channels, sizeof(*channels) *
881 (channels_count + 1));
882 channels[channels_count++] = (SilcChannelEntry)entry;
886 silc_server_query_add_error(server, query, 1, 3,
887 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
890 if (query->ids_count) {
891 /* Find entries by the queried IDs */
892 for (i = 0; i < query->ids_count; i++) {
893 void *id = query->ids[i].id;
897 switch (query->ids[i].id_type) {
900 /* Get client entry */
901 entry = silc_idlist_find_client_by_id(server->local_list,
903 if (!entry && check_global)
904 entry = silc_idlist_find_client_by_id(server->global_list,
907 silc_server_query_add_error(server, query, 0, i,
908 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
912 clients = silc_realloc(clients, sizeof(*clients) *
913 (clients_count + 1));
914 clients[clients_count++] = (SilcClientEntry)entry;
918 /* Get server entry */
919 entry = silc_idlist_find_server_by_id(server->local_list,
921 if (!entry && check_global)
922 entry = silc_idlist_find_server_by_id(server->global_list,
925 silc_server_query_add_error(server, query, 0, i,
926 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
930 servers = silc_realloc(servers, sizeof(*servers) *
931 (servers_count + 1));
932 servers[servers_count++] = (SilcServerEntry)entry;
935 case SILC_ID_CHANNEL:
936 /* Get channel entry */
937 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
938 if (!entry && check_global)
939 entry = silc_idlist_find_channel_by_id(server->global_list, id,
942 silc_server_query_add_error(server, query, 0, i,
943 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
947 channels = silc_realloc(channels, sizeof(*channels) *
948 (channels_count + 1));
949 channels[channels_count++] = (SilcChannelEntry)entry;
958 /* Check the attributes to narrow down the search by using them. */
960 silc_server_query_check_attributes(server, query, &clients,
963 SILC_LOG_DEBUG(("Querying %d clients", clients_count));
964 SILC_LOG_DEBUG(("Querying %d servers", servers_count));
965 SILC_LOG_DEBUG(("Querying %d channels", channels_count));
967 /* If nothing was found, then just send the errors */
968 if (!clients && !channels && !servers) {
969 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
973 /* If caller does not want us to resolve anything (has resolved already)
974 then just continue with sending the reply */
976 silc_server_query_send_reply(server, query, clients, clients_count,
977 servers, servers_count, channels,
985 /* Now process all found information and if necessary do some more
987 switch (query->querycmd) {
989 case SILC_COMMAND_WHOIS:
990 for (i = 0; i < clients_count; i++) {
991 client_entry = clients[i];
993 /* Check if cannot query this anyway, so take next one */
995 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
998 /* If Requested Attributes is set then we always resolve the client
999 information, if not then check whether the entry is complete or not
1000 and decide whether we need to resolve or not. */
1001 if (!query->attrs) {
1003 /* Even if nickname and stuff are present, we may need to resolve
1005 if (client_entry->nickname && client_entry->username &&
1006 client_entry->userinfo) {
1007 /* Check if cannot query this anyway, so take next one */
1008 if (!client_entry->router)
1011 /* If we are router, client is local to us, or client is on channel
1012 we do not need to resolve the client information. */
1013 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1014 || silc_hash_table_count(client_entry->channels) ||
1020 /* Remove the NOATTR status periodically */
1021 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
1022 client_entry->updated + 600 < time(NULL))
1023 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
1025 /* When requested attributes is present and local client is detached
1026 we cannot send the command to the client, we'll reply on behalf of
1027 the client instead. */
1028 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
1029 (client_entry->mode & SILC_UMODE_DETACHED ||
1030 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
1033 /* If attributes are present in query, and in the entry and we have
1034 done resolvings already we don't need to resolve anymore */
1035 if (query->resolved && query->attrs && client_entry->attrs)
1038 /* Resolve the detailed client information. If client is local we
1039 know that attributes were present and we will resolve directly
1040 from the client. Otherwise resolve from client's owner. */
1041 silc_server_query_resolve(server, query,
1042 (SILC_IS_LOCAL(client_entry) ?
1043 client_entry->connection :
1044 client_entry->router->connection),
1049 case SILC_COMMAND_WHOWAS:
1050 for (i = 0; i < clients_count; i++) {
1051 client_entry = clients[i];
1053 /* Check if cannot query this anyway, so take next one */
1054 if (!client_entry || !client_entry->router ||
1055 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
1058 /* If both nickname and username are present no resolving is needed */
1059 if (client_entry->nickname && client_entry->username)
1062 /* Resolve the detailed client information */
1063 silc_server_query_resolve(server, query,
1064 client_entry->router->connection,
1069 case SILC_COMMAND_IDENTIFY:
1070 for (i = 0; i < clients_count; i++) {
1071 client_entry = clients[i];
1073 /* Check if cannot query this anyway, so take next one */
1074 if (!client_entry || !client_entry->router ||
1075 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1078 /* Even if nickname is present, we may need to resolve the entry */
1079 if (client_entry->nickname) {
1081 /* If we are router, client is local to us, or client is on channel
1082 we do not need to resolve the client information. */
1083 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1084 || silc_hash_table_count(client_entry->channels) ||
1089 /* Resolve the detailed client information */
1090 silc_server_query_resolve(server, query,
1091 client_entry->router->connection,
1097 if (!query->queries_count)
1098 /* If we didn't have to do any resolving, continue with sending the
1099 command reply to the original sender. */
1100 silc_server_query_send_reply(server, query, clients, clients_count,
1101 servers, servers_count, channels,
1104 /* Now actually send the resolvings we gathered earlier */
1105 silc_server_query_resolve(server, query, NULL, NULL);
1109 silc_free(channels);
1112 /* Resolve the detailed information for the `client_entry'. Only client
1113 information needs to be resolved for being incomplete. Each incomplete
1114 client entry calls this function to do the resolving. */
1116 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
1117 SilcPacketStream sock,
1118 SilcClientEntry client_entry)
1120 SilcServerCommandContext cmd = query->cmd;
1121 SilcServerQueryList r = NULL;
1128 if (!sock && client_entry)
1131 /* If arguments are NULL we will now actually send the resolvings
1132 that earlier has been gathered by calling this function. */
1133 if (!sock && !client_entry) {
1136 SILC_LOG_DEBUG(("Sending the resolvings"));
1138 /* WHOWAS resolving has been done at the same time this function
1139 was called to add the resolving for WHOWAS, so just return. */
1140 if (query->querycmd == SILC_COMMAND_WHOWAS)
1143 for (i = 0; i < query->querylist_count; i++) {
1144 r = &query->querylist[i];
1146 /* If Requested Attributes were present put them to this resolving */
1147 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1149 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1150 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1151 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1153 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1155 r->arg[r->argc] = silc_memdup(tmp, len);
1156 r->arg_lens[r->argc] = len;
1157 r->arg_types[r->argc] = 3;
1162 server->stat.commands_sent++;
1164 /* Send WHOIS command */
1165 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1166 r->argc, r->arg, r->arg_lens,
1167 r->arg_types, r->ident);
1168 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1169 res_cmd->data, silc_buffer_len(res_cmd));
1170 silc_buffer_free(res_cmd);
1172 /* Reprocess this packet after received reply */
1173 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1175 silc_server_query_resolve_reply,
1177 query->queries_left++;
1180 /* Cleanup this temporary context */
1181 for (i = 0; i < query->querylist_count; i++) {
1183 for (k = 0; k < query->querylist[i].argc; k++)
1184 silc_free(query->querylist[i].arg[k]);
1185 silc_free(query->querylist[i].arg);
1186 silc_free(query->querylist[i].arg_lens);
1187 silc_free(query->querylist[i].arg_types);
1189 silc_free(query->querylist);
1190 query->querylist = NULL;
1191 query->querylist_count = 0;
1195 SILC_LOG_DEBUG(("Resolving client information"));
1197 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1198 /* The entry is being resolved by some other external query already.
1199 Attach to that query instead of resolving again. */
1200 ident = client_entry->resolve_cmd_ident;
1201 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1202 silc_server_query_resolve_reply, query))
1203 query->queries_left++;
1205 /* This entry will be resolved */
1206 ident = ++server->cmd_ident;
1208 switch (query->querycmd) {
1210 case SILC_COMMAND_WHOIS:
1211 case SILC_COMMAND_IDENTIFY:
1212 /* Take existing query context if exist for this connection */
1213 for (i = 0; i < query->querylist_count; i++)
1214 if (query->querylist[i].sock == sock) {
1215 r = &query->querylist[i];
1220 /* Allocate new temp query list context */
1221 query->querylist = silc_realloc(query->querylist,
1222 sizeof(*query->querylist) *
1223 (query->querylist_count + 1));
1224 r = &query->querylist[query->querylist_count];
1225 query->querylist_count++;
1226 memset(r, 0, sizeof(*r));
1229 if (SILC_IS_LOCAL(client_entry))
1234 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1235 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1236 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1238 /* Add the client entry to be resolved */
1239 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1240 r->arg[r->argc] = silc_memdup(idp->data, silc_buffer_len(idp));
1241 r->arg_lens[r->argc] = silc_buffer_len(idp);
1242 r->arg_types[r->argc] = r->argc + 4;
1244 silc_buffer_free(idp);
1248 case SILC_COMMAND_WHOWAS:
1249 /* We must send WHOWAS command since it's the only the way of
1250 resolving clients that are not present in the network anymore. */
1251 silc_server_send_command(server, sock, query->querycmd, ident, 1,
1252 1, query->nickname, strlen(query->nickname));
1253 if (silc_server_command_pending(server, query->querycmd, ident,
1254 silc_server_query_resolve_reply, query))
1255 query->queries_left++;
1260 /* Mark the entry as being resolved */
1261 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1262 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1263 client_entry->resolve_cmd_ident = ident;
1264 client_entry->updated = time(NULL);
1266 /* Save the queried ID, which we will reprocess after we get this and
1267 all other queries back. */
1268 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1269 (query->queries_count + 1));
1270 if (query->queries) {
1271 i = query->queries_count;
1272 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1273 query->queries[i].id_type = SILC_ID_CLIENT;
1274 query->queries[i].ident = ident;
1275 query->queries_count++;
1279 /* Reply callback called after one resolving has been completed. If
1280 all resolvings has been received then we will continue with sending
1281 the command reply to the original sender of the query. */
1283 void silc_server_query_resolve_reply(void *context, void *reply)
1285 SilcServerQuery query = context;
1286 SilcServer server = query->cmd->server;
1287 SilcServerCommandReplyContext cmdr = reply;
1288 SilcUInt16 ident = cmdr->ident;
1289 SilcStatus error = SILC_STATUS_OK;
1290 SilcServerQueryID id = NULL;
1291 SilcClientEntry client_entry;
1294 /* One less query left */
1295 query->queries_left--;
1297 silc_command_get_status(cmdr->payload, NULL, &error);
1298 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1299 query->queries_left, error));
1301 /* If no error then skip to other stuff */
1302 if (error == SILC_STATUS_OK)
1305 /* Error occurred during resolving */
1307 /* Find the resolved client ID */
1308 for (i = 0; i < query->queries_count; i++) {
1309 if (query->queries[i].ident != ident)
1312 id = &query->queries[i];
1314 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1316 /* If timeout occurred for local entry when resolving attributes
1317 mark that this client doesn't support attributes in WHOIS. This
1318 assures we won't send the request again to the client. */
1319 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1320 client_entry = silc_idlist_find_client_by_id(server->local_list,
1321 id->id, TRUE, NULL);
1322 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1323 silc_id_render(id->id, SILC_ID_CLIENT)));
1324 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1325 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1326 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1331 /* Remove the RESOLVING status from the client entry */
1332 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1333 client_entry = silc_idlist_find_client_by_id(server->local_list,
1334 id->id, TRUE, NULL);
1336 client_entry = silc_idlist_find_client_by_id(server->global_list,
1337 id->id, TRUE, NULL);
1339 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1346 /* If there are queries left then wait for them */
1347 if (query->queries_left)
1350 SILC_LOG_DEBUG(("Reprocess the query"));
1352 /* If the original command caller has gone away, just stop. */
1353 if (!silc_packet_stream_is_valid(query->cmd->sock)) {
1354 SILC_LOG_DEBUG(("Original command caller vanished"));
1355 silc_server_query_free(query);
1359 /* We have received all queries. Now re-search all information required
1360 to complete this query. Reason we cannot save the values found in
1361 the first search is that SilcClientEntry, SilcServerEntry and
1362 SilcChannelEntry pointers may become invalid while we were waiting
1363 for these resolvings. */
1364 silc_server_query_process(server, query, FALSE);
1367 /* Send the reply to the original query. If arguments are NULL then this
1368 sends only the errors that has occurred during the processing of the
1369 query. This sends the errors always after sending all the found
1370 information. The query is over after this function returns and the
1371 `query' will become invalid. This is called only after all informations
1372 has been resolved. This means that if something is not found or is
1373 incomplete in this function we were unable to resolve the information
1374 or it does not exist at all. */
1376 void silc_server_query_send_reply(SilcServer server,
1377 SilcServerQuery query,
1378 SilcClientEntry *clients,
1379 SilcUInt32 clients_count,
1380 SilcServerEntry *servers,
1381 SilcUInt32 servers_count,
1382 SilcChannelEntry *channels,
1383 SilcUInt32 channels_count)
1385 SilcServerCommandContext cmd = query->cmd;
1386 SilcIDListData idata = silc_packet_get_context(cmd->sock);
1387 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1392 int i, k, valid_count;
1393 char nh[384], uh[384];
1394 SilcBool sent_reply = FALSE;
1396 SILC_LOG_DEBUG(("Sending reply to query"));
1397 SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1398 SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1399 SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1400 SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1402 status = SILC_STATUS_OK;
1405 if (clients_count) {
1406 SilcClientEntry entry;
1407 SilcPacketStream hsock;
1409 /* Mark all invalid entries */
1410 for (i = 0, valid_count = 0; i < clients_count; i++) {
1415 switch (query->querycmd) {
1416 case SILC_COMMAND_WHOIS:
1417 if (!entry->nickname || !entry->username || !entry->userinfo ||
1418 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1419 /* When querying by ID, every "unfound" entry must cause error */
1421 silc_server_query_add_error_id(server, query,
1422 SILC_STATUS_ERR_TIMEDOUT,
1423 entry->id, SILC_ID_CLIENT);
1429 case SILC_COMMAND_IDENTIFY:
1430 if (!entry->nickname ||
1431 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1432 /* When querying by ID, every "unfound" entry must cause error */
1434 silc_server_query_add_error_id(server, query,
1435 SILC_STATUS_ERR_TIMEDOUT,
1436 entry->id, SILC_ID_CLIENT);
1442 case SILC_COMMAND_WHOWAS:
1443 if (!entry->nickname || !entry->username ||
1444 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1453 /* Start processing found clients */
1454 status = SILC_STATUS_OK;
1455 if (valid_count > 1)
1456 status = SILC_STATUS_LIST_START;
1458 /* Now do the sending of valid entries */
1460 for (i = 0; i < clients_count && valid_count; i++) {
1466 status = SILC_STATUS_LIST_ITEM;
1467 if (valid_count > 1 && k == valid_count - 1
1468 && !servers_count && !channels_count && !query->errors_count)
1469 status = SILC_STATUS_LIST_END;
1470 if (query->reply_count && k - 1 == query->reply_count)
1471 status = SILC_STATUS_LIST_END;
1473 SILC_LOG_DEBUG(("%s: client %s",
1474 (status == SILC_STATUS_OK ? " OK" :
1475 status == SILC_STATUS_LIST_START ? "START" :
1476 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1477 status == SILC_STATUS_LIST_END ? " END" :
1478 " : "), entry->nickname));
1480 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1481 memset(nh, 0, sizeof(nh));
1483 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1484 if (!strchr(entry->nickname, '@')) {
1485 silc_strncat(nh, sizeof(nh), "@", 1);
1486 if (entry->servername) {
1487 silc_strncat(nh, sizeof(nh), entry->servername,
1488 strlen(entry->servername));
1490 len = entry->router ? strlen(entry->router->server_name) :
1491 strlen(server->server_name);
1492 silc_strncat(nh, sizeof(nh), entry->router ?
1493 entry->router->server_name :
1494 server->server_name, len);
1498 switch (query->querycmd) {
1500 case SILC_COMMAND_WHOIS:
1502 unsigned char idle[4], mode[4];
1503 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1504 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1506 memset(fempty, 0, sizeof(fempty));
1507 memset(idle, 0, sizeof(idle));
1508 memset(uh, 0, sizeof(uh));
1510 silc_strncat(uh, sizeof(uh), entry->username,
1511 strlen(entry->username));
1512 if (!strchr(entry->username, '@') && entry->connection) {
1513 hsock = entry->connection;
1514 silc_strncat(uh, sizeof(uh), "@", 1);
1515 silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
1516 NULL, (const char **)&tmp, NULL, NULL);
1517 silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
1520 if (idata->conn_type == SILC_CONN_CLIENT)
1522 silc_server_get_client_channel_list(server, entry, FALSE,
1523 FALSE, &umode_list);
1526 silc_server_get_client_channel_list(server, entry, TRUE,
1529 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1530 fingerprint = entry->data.fingerprint;
1534 SILC_PUT32_MSB(entry->mode, mode);
1535 if (entry->connection)
1536 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1538 /* If Requested Attribute were present, and we do not have the
1539 attributes we will reply to them on behalf of the client. */
1542 if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1543 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1544 entry->attrs = silc_buffer_steal(tmpattrs, &len);
1545 entry->attrs_len = len;
1546 silc_buffer_free(tmpattrs);
1548 attrs = entry->attrs;
1549 len = entry->attrs_len;
1552 /* Send command reply */
1553 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1554 status, 0, ident, 10,
1555 2, idp->data, silc_buffer_len(idp),
1559 strlen(entry->userinfo),
1560 6, channels ? channels->data : NULL,
1561 channels ? silc_buffer_len(channels)
1566 fingerprint ? 20 : 0,
1567 10, umode_list ? umode_list->data :
1569 silc_buffer_len(umode_list) :
1574 /* For now we always delete Requested Attributes, unless the client
1575 is detached, in which case we don't want to reconstruct the
1576 same data everytime */
1577 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1578 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1579 silc_free(entry->attrs);
1580 entry->attrs = NULL;
1584 silc_buffer_free(channels);
1586 silc_buffer_free(umode_list);
1592 case SILC_COMMAND_IDENTIFY:
1593 if (!entry->username) {
1594 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1595 status, 0, ident, 2,
1596 2, idp->data, silc_buffer_len(idp),
1600 memset(uh, 0, sizeof(uh));
1601 silc_strncat(uh, sizeof(uh), entry->username,
1602 strlen(entry->username));
1603 if (!strchr(entry->username, '@') && entry->connection) {
1604 hsock = entry->connection;
1605 silc_strncat(uh, sizeof(uh), "@", 1);
1606 silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
1607 NULL, (const char **)&tmp,
1609 silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
1612 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1613 status, 0, ident, 3,
1614 2, idp->data, silc_buffer_len(idp),
1621 case SILC_COMMAND_WHOWAS:
1622 memset(uh, 0, sizeof(uh));
1623 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1624 if (!strchr(entry->username, '@'))
1625 silc_strncat(uh, sizeof(uh), "@-private-", 10);
1627 /* Send command reply */
1628 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1629 status, 0, ident, 4,
1630 2, idp->data, silc_buffer_len(idp),
1635 strlen(entry->userinfo) : 0);
1640 silc_buffer_free(idp);
1642 if (status == SILC_STATUS_LIST_END)
1648 /* Not one valid entry was found, send error. If nickname was used
1649 in query send error based on that, otherwise the query->errors
1650 already includes proper errors. */
1651 if (query->nickname[0] || (!query->ids && query->attrs))
1652 silc_server_query_add_error(server, query, 1, 1,
1653 SILC_STATUS_ERR_NO_SUCH_NICK);
1655 /* Make sure some error is sent */
1656 if (!query->errors_count && !servers_count && !channels_count)
1657 silc_server_query_add_error(server, query, 2, 0,
1658 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1663 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1664 SilcServerEntry entry;
1666 if (status == SILC_STATUS_OK && servers_count > 1)
1667 status = SILC_STATUS_LIST_START;
1670 for (i = 0; i < servers_count; i++) {
1674 status = SILC_STATUS_LIST_ITEM;
1675 if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1676 !query->errors_count)
1677 status = SILC_STATUS_LIST_END;
1678 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1679 !query->errors_count)
1680 status = SILC_STATUS_LIST_END;
1681 if (query->reply_count && k - 1 == query->reply_count)
1682 status = SILC_STATUS_LIST_END;
1684 SILC_LOG_DEBUG(("%s: server %s",
1685 (status == SILC_STATUS_OK ? " OK" :
1686 status == SILC_STATUS_LIST_START ? "START" :
1687 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1688 status == SILC_STATUS_LIST_END ? " END" :
1690 entry->server_name ? entry->server_name : ""));
1692 /* Send command reply */
1693 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1694 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1695 status, 0, ident, 2,
1696 2, idp->data, silc_buffer_len(idp),
1697 3, entry->server_name,
1698 entry->server_name ?
1699 strlen(entry->server_name) : 0);
1700 silc_buffer_free(idp);
1703 if (status == SILC_STATUS_LIST_END)
1710 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1711 SilcChannelEntry entry;
1713 if (status == SILC_STATUS_OK && channels_count > 1)
1714 status = SILC_STATUS_LIST_START;
1717 for (i = 0; i < channels_count; i++) {
1718 entry = channels[i];
1721 status = SILC_STATUS_LIST_ITEM;
1722 if (channels_count == 1 && status != SILC_STATUS_OK &&
1723 !query->errors_count)
1724 status = SILC_STATUS_LIST_END;
1725 if (channels_count > 1 && k == channels_count - 1 &&
1726 !query->errors_count)
1727 status = SILC_STATUS_LIST_END;
1728 if (query->reply_count && k - 1 == query->reply_count)
1729 status = SILC_STATUS_LIST_END;
1731 SILC_LOG_DEBUG(("%s: channel %s",
1732 (status == SILC_STATUS_OK ? " OK" :
1733 status == SILC_STATUS_LIST_START ? "START" :
1734 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1735 status == SILC_STATUS_LIST_END ? " END" :
1737 entry->channel_name ? entry->channel_name : ""));
1739 /* Send command reply */
1740 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1741 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1742 status, 0, ident, 2,
1743 2, idp->data, silc_buffer_len(idp),
1744 3, entry->channel_name,
1745 entry->channel_name ?
1746 strlen(entry->channel_name) : 0);
1747 silc_buffer_free(idp);
1750 if (status == SILC_STATUS_LIST_END)
1757 if (query->errors_count) {
1760 if (status == SILC_STATUS_OK && query->errors_count > 1)
1761 status = SILC_STATUS_LIST_START;
1764 for (i = 0; i < query->errors_count; i++) {
1767 /* Take error argument */
1768 if (query->errors[i].type == 1) {
1769 /* Take from sent arguments */
1771 tmp = silc_argument_get_arg_type(cmd->args,
1772 query->errors[i].index, &len);
1774 } else if (query->errors[i].type == 2) {
1779 } else if (!query->errors[i].id) {
1780 /* Take from query->ids */
1782 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1783 query->ids[query->errors[k].index].id_type);
1785 len = silc_buffer_len(idp);
1788 /* Take added ID. */
1789 idp = silc_id_payload_encode(query->errors[i].id,
1790 query->errors[k].id_type);
1792 len = silc_buffer_len(idp);
1797 status = SILC_STATUS_LIST_ITEM;
1798 if (query->errors_count == 1 && status != SILC_STATUS_OK)
1799 status = SILC_STATUS_LIST_END;
1800 if (query->errors_count > 1 && k == query->errors_count - 1)
1801 status = SILC_STATUS_LIST_END;
1802 if (query->reply_count && k - 1 == query->reply_count)
1803 status = SILC_STATUS_LIST_END;
1805 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1806 (status == SILC_STATUS_OK ? " OK" :
1807 status == SILC_STATUS_LIST_START ? "START" :
1808 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1809 status == SILC_STATUS_LIST_END ? " END" :
1811 silc_get_status_message(query->errors[i].error),
1812 query->errors[i].error));
1814 #if 1 /* XXX Backwards compatibility. Remove in 1.0. */
1815 if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
1817 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1818 (status == SILC_STATUS_OK ?
1819 query->errors[i].error : status),
1820 (status == SILC_STATUS_OK ?
1821 0 : query->errors[i].error), ident, 2,
1827 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1828 (status == SILC_STATUS_OK ?
1829 query->errors[i].error : status),
1830 (status == SILC_STATUS_OK ?
1831 0 : query->errors[i].error), ident, 1,
1834 silc_buffer_free(idp);
1837 if (status == SILC_STATUS_LIST_END)
1844 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1847 silc_server_query_free(query);
1850 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1851 of the client since we were unable to resolve them from the client.
1852 Either client does not support Requested Attributes or isn't replying
1853 to them like it should. */
1855 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1856 SilcServerQuery query,
1857 SilcClientEntry client_entry)
1859 SilcBuffer buffer = NULL;
1860 SilcAttribute attribute;
1861 SilcAttributePayload attr;
1862 SilcAttributeObjPk pk;
1863 SilcAttributeObjService service;
1865 unsigned char sign[2048 + 1];
1866 SilcUInt32 sign_len;
1868 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1870 /* Go through all requested attributes */
1871 silc_dlist_start(query->attrs);
1872 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1873 attribute = silc_attribute_get_attribute(attr);
1874 switch (attribute) {
1876 case SILC_ATTRIBUTE_SERVICE:
1877 /* Put SERVICE. Put only SILC service. */
1878 memset(&service, 0, sizeof(service));
1879 service.port = (server->config->server_info->primary ?
1880 server->config->server_info->primary->port : SILC_PORT);
1881 silc_strncat(service.address, sizeof(service.address),
1882 server->server_name, strlen(server->server_name));
1883 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1884 if (client_entry->connection)
1885 service.idle = time(NULL) - client_entry->data.last_receive;
1886 buffer = silc_attribute_payload_encode(buffer, attribute,
1887 SILC_ATTRIBUTE_FLAG_VALID,
1888 &service, sizeof(service));
1893 case SILC_ATTRIBUTE_STATUS_MOOD:
1894 /* Put STATUS_MOOD */
1895 buffer = silc_attribute_payload_encode(buffer, attribute,
1896 SILC_ATTRIBUTE_FLAG_VALID,
1898 SILC_ATTRIBUTE_MOOD_NORMAL,
1899 sizeof(SilcUInt32));
1904 case SILC_ATTRIBUTE_STATUS_FREETEXT:
1905 /* Put STATUS_FREETEXT. We just tell in the message that we are
1906 replying on behalf of the client. */
1908 "This information was provided by the server on behalf of the user";
1909 buffer = silc_attribute_payload_encode(buffer, attribute,
1910 SILC_ATTRIBUTE_FLAG_VALID,
1916 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1917 /* Put PREFERRED_CONTACT */
1918 buffer = silc_attribute_payload_encode(buffer, attribute,
1919 SILC_ATTRIBUTE_FLAG_VALID,
1921 SILC_ATTRIBUTE_CONTACT_CHAT,
1922 sizeof(SilcUInt32));
1927 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1928 /* Put USER_PUBLIC_KEY */
1929 if (client_entry->data.public_key) {
1930 pk.type = "silc-rsa";
1931 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1933 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1934 SILC_ATTRIBUTE_FLAG_VALID :
1935 SILC_ATTRIBUTE_FLAG_INVALID,
1943 /* No public key available */
1944 buffer = silc_attribute_payload_encode(buffer, attribute,
1945 SILC_ATTRIBUTE_FLAG_INVALID,
1952 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1953 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1954 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1957 /* For other attributes we cannot reply so mark it invalid */
1958 buffer = silc_attribute_payload_encode(buffer, attribute,
1959 SILC_ATTRIBUTE_FLAG_INVALID,
1967 /* Always put our public key. This assures that we send at least
1968 something valid back always. */
1969 pk.type = "silc-rsa";
1970 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1971 buffer = silc_attribute_payload_encode(buffer,
1972 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1973 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1974 SILC_ATTRIBUTE_FLAG_INVALID,
1980 /* Finally compute the digital signature of all the data we provided
1981 as an indication that we provided rightfull information, and this
1982 also authenticates our public key. */
1983 if (silc_pkcs_private_key_get_len(server->private_key) / 8 <=
1985 silc_pkcs_sign(server->private_key, buffer->data,
1986 silc_buffer_len(buffer), sign, sizeof(sign), &sign_len,
1987 TRUE, server->sha1hash)) {
1990 pk.data_len = sign_len;
1992 silc_attribute_payload_encode(buffer,
1993 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1994 SILC_ATTRIBUTE_FLAG_VALID,
2003 /* Find client by the Client ID indicated by the `client_id', and if not
2004 found then query it by using WHOIS command. The client information
2005 is also resolved if the cached information is incomplete or if the
2006 `always_resolve' is set to TRUE. The indication whether requested
2007 client was being resolved is saved into `resolved'. If the client
2008 is not being resolved its entry is returned by this function. NULL
2009 is returned if client is resolved. */
2011 SilcClientEntry silc_server_query_client(SilcServer server,
2012 const SilcClientID *client_id,
2013 SilcBool always_resolve,
2016 SilcClientEntry client;
2018 SILC_LOG_DEBUG(("Resolving client by client ID"));
2023 client = silc_idlist_find_client_by_id(server->local_list,
2024 (SilcClientID *)client_id,
2027 client = silc_idlist_find_client_by_id(server->global_list,
2028 (SilcClientID *)client_id,
2030 if (!client && server->server_type == SILC_ROUTER)
2034 if (!client && server->standalone)
2037 if (!client || !client->nickname || !client->username ||
2039 SilcBuffer buffer, idp;
2042 server->stat.commands_sent++;
2045 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
2046 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
2047 client->resolve_cmd_ident = ++server->cmd_ident;
2050 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
2051 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
2052 server->cmd_ident, 1,
2054 silc_buffer_len(idp));
2055 silc_server_packet_send(server, client ? client->router->connection :
2056 SILC_PRIMARY_ROUTE(server),
2057 SILC_PACKET_COMMAND, 0,
2058 buffer->data, silc_buffer_len(buffer));
2059 silc_buffer_free(idp);
2060 silc_buffer_free(buffer);