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 void silc_server_public_key_hash_foreach(void *key, void *context,
667 SilcServerPublicKeyUser uc = user_context;
668 SilcClientEntry entry = context;
670 /* Nothing was found, just return */
676 (*uc->clients) = silc_realloc((*uc->clients),
677 sizeof((**uc->clients)) *
678 ((*uc->clients_count) + 1));
679 (*uc->clients)[(*uc->clients_count)++] = entry;
682 /* If clients are set, limit the found clients using the attributes in
683 the query. If clients are not set, try to find some clients using
686 void silc_server_query_check_attributes(SilcServer server,
687 SilcServerQuery query,
688 SilcClientEntry **clients,
689 SilcUInt32 *clients_count) {
690 SilcClientEntry entry;
691 SilcAttributePayload attr;
692 SilcAttribute attribute;
693 SilcAttributeObjPk pk;
694 SilcPublicKey publickey;
696 SilcBool found = FALSE, no_clients = FALSE;
699 /* If no clients were found, we only check the attributes
700 if the user wasn't searching for nickname/ids */
703 if (query->nickname[0] || query->ids_count)
707 silc_dlist_start(query->attrs);
708 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
709 attribute = silc_attribute_get_attribute(attr);
712 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
713 SILC_LOG_DEBUG(("Finding clients by public key attribute"));
715 if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
718 if (!strcmp(pk.type, "silc-rsa"))
719 type = SILC_PKCS_SILC;
720 else if (!strcmp(pk.type, "ssh-rsa"))
721 type = SILC_PKCS_SSH2;
722 else if (!strcmp(pk.type, "x509v3-sign-rsa"))
723 type = SILC_PKCS_X509V3;
724 else if (!strcmp(pk.type, "pgp-sign-rsa"))
725 type = SILC_PKCS_OPENPGP;
729 if (!silc_pkcs_public_key_alloc(type, pk.data, pk.data_len,
736 /* If no clients were set on calling this function, we
737 just search for clients, otherwise we try to limit
740 SilcServerPublicKeyUserStruct usercontext;
742 usercontext.clients = clients;
743 usercontext.clients_count = clients_count;
744 usercontext.found = FALSE;
746 silc_hash_table_find_foreach(server->pk_hash, publickey,
747 silc_server_public_key_hash_foreach,
750 if (usercontext.found == TRUE)
753 for (i = 0; i < *clients_count; i++) {
754 entry = (*clients)[i];
756 if (!entry->data.public_key)
759 if (!silc_hash_table_find_by_context(server->pk_hash, publickey,
761 (*clients)[i] = NULL;
768 silc_pkcs_public_key_free(publickey);
773 if (!found && !query->nickname[0] && !query->ids)
774 silc_server_query_add_error(server, query, 2, 0,
775 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
778 /* Processes the parsed query. This does the actual finding of the
779 queried information and prepares for sending reply to the original
780 sender of the query command. */
782 void silc_server_query_process(SilcServer server, SilcServerQuery query,
785 SilcServerCommandContext cmd = query->cmd;
786 SilcIDListData idata = silc_packet_get_context(cmd->sock);
787 SilcBool check_global = FALSE;
789 SilcClientEntry *clients = NULL, client_entry;
790 SilcChannelEntry *channels = NULL;
791 SilcServerEntry *servers = NULL;
792 SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
795 SILC_LOG_DEBUG(("Processing %s query",
796 silc_get_command_name(query->querycmd)));
798 /* Check global lists if query is coming from client or we are not
799 normal server (we know global information). */
800 if (idata->conn_type == SILC_CONN_CLIENT)
802 else if (server->server_type != SILC_SERVER)
805 if (query->nickname[0]) {
806 /* Get all clients matching nickname from local list */
807 if (!silc_idlist_get_clients_by_hash(server->local_list,
808 query->nickname, server->md5hash,
809 &clients, &clients_count))
810 silc_idlist_get_clients_by_nickname(server->local_list,
813 /* XXX nick_server may not be set */
814 &clients, &clients_count);
816 /* Check global list as well */
818 if (!silc_idlist_get_clients_by_hash(server->global_list,
819 query->nickname, server->md5hash,
820 &clients, &clients_count))
821 silc_idlist_get_clients_by_nickname(server->global_list,
824 /* XXX nick_server may not be set */
825 &clients, &clients_count);
829 silc_server_query_add_error(server, query, 1, 1,
830 SILC_STATUS_ERR_NO_SUCH_NICK);
833 if (query->server_name) {
834 /* Find server by name */
835 entry = silc_idlist_find_server_by_name(server->local_list,
836 query->server_name, TRUE, NULL);
837 if (!entry && check_global)
838 entry = silc_idlist_find_server_by_name(server->global_list,
839 query->server_name, TRUE, NULL);
841 servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
842 servers[servers_count++] = (SilcServerEntry)entry;
846 silc_server_query_add_error(server, query, 1, 2,
847 SILC_STATUS_ERR_NO_SUCH_SERVER);
850 if (query->channel_name) {
851 /* Find channel by name */
852 entry = silc_idlist_find_channel_by_name(server->local_list,
853 query->channel_name, NULL);
854 if (!entry && check_global)
855 entry = silc_idlist_find_channel_by_name(server->global_list,
856 query->channel_name, NULL);
858 channels = silc_realloc(channels, sizeof(*channels) *
859 (channels_count + 1));
860 channels[channels_count++] = (SilcChannelEntry)entry;
864 silc_server_query_add_error(server, query, 1, 3,
865 SILC_STATUS_ERR_NO_SUCH_CHANNEL);
868 if (query->ids_count) {
869 /* Find entries by the queried IDs */
870 for (i = 0; i < query->ids_count; i++) {
871 void *id = query->ids[i].id;
875 switch (query->ids[i].id_type) {
878 /* Get client entry */
879 entry = silc_idlist_find_client_by_id(server->local_list,
881 if (!entry && check_global)
882 entry = silc_idlist_find_client_by_id(server->global_list,
885 silc_server_query_add_error(server, query, 0, i,
886 SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
890 clients = silc_realloc(clients, sizeof(*clients) *
891 (clients_count + 1));
892 clients[clients_count++] = (SilcClientEntry)entry;
896 /* Get server entry */
897 entry = silc_idlist_find_server_by_id(server->local_list,
899 if (!entry && check_global)
900 entry = silc_idlist_find_server_by_id(server->global_list,
903 silc_server_query_add_error(server, query, 0, i,
904 SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
908 servers = silc_realloc(servers, sizeof(*servers) *
909 (servers_count + 1));
910 servers[servers_count++] = (SilcServerEntry)entry;
913 case SILC_ID_CHANNEL:
914 /* Get channel entry */
915 entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
916 if (!entry && check_global)
917 entry = silc_idlist_find_channel_by_id(server->global_list, id,
920 silc_server_query_add_error(server, query, 0, i,
921 SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
925 channels = silc_realloc(channels, sizeof(*channels) *
926 (channels_count + 1));
927 channels[channels_count++] = (SilcChannelEntry)entry;
936 /* Check the attributes to narrow down the search by using them. */
938 silc_server_query_check_attributes(server, query, &clients,
941 SILC_LOG_DEBUG(("Querying %d clients", clients_count));
942 SILC_LOG_DEBUG(("Querying %d servers", servers_count));
943 SILC_LOG_DEBUG(("Querying %d channels", channels_count));
945 /* If nothing was found, then just send the errors */
946 if (!clients && !channels && !servers) {
947 silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
951 /* If caller does not want us to resolve anything (has resolved already)
952 then just continue with sending the reply */
954 silc_server_query_send_reply(server, query, clients, clients_count,
955 servers, servers_count, channels,
963 /* Now process all found information and if necessary do some more
965 switch (query->querycmd) {
967 case SILC_COMMAND_WHOIS:
968 for (i = 0; i < clients_count; i++) {
969 client_entry = clients[i];
971 /* Check if cannot query this anyway, so take next one */
973 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
976 /* If Requested Attributes is set then we always resolve the client
977 information, if not then check whether the entry is complete or not
978 and decide whether we need to resolve or not. */
981 /* Even if nickname and stuff are present, we may need to resolve
983 if (client_entry->nickname && client_entry->username &&
984 client_entry->userinfo) {
985 /* Check if cannot query this anyway, so take next one */
986 if (!client_entry->router)
989 /* If we are router, client is local to us, or client is on channel
990 we do not need to resolve the client information. */
991 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
992 || silc_hash_table_count(client_entry->channels) ||
998 /* Remove the NOATTR status periodically */
999 if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
1000 client_entry->updated + 600 < time(NULL))
1001 client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
1003 /* When requested attributes is present and local client is detached
1004 we cannot send the command to the client, we'll reply on behalf of
1005 the client instead. */
1006 if (query->attrs && SILC_IS_LOCAL(client_entry) &&
1007 (client_entry->mode & SILC_UMODE_DETACHED ||
1008 client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
1011 /* If attributes are present in query, and in the entry and we have
1012 done resolvings already we don't need to resolve anymore */
1013 if (query->resolved && query->attrs && client_entry->attrs)
1016 /* Resolve the detailed client information. If client is local we
1017 know that attributes were present and we will resolve directly
1018 from the client. Otherwise resolve from client's owner. */
1019 silc_server_query_resolve(server, query,
1020 (SILC_IS_LOCAL(client_entry) ?
1021 client_entry->connection :
1022 client_entry->router->connection),
1027 case SILC_COMMAND_WHOWAS:
1028 for (i = 0; i < clients_count; i++) {
1029 client_entry = clients[i];
1031 /* Check if cannot query this anyway, so take next one */
1032 if (!client_entry || !client_entry->router ||
1033 client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
1036 /* If both nickname and username are present no resolving is needed */
1037 if (client_entry->nickname && client_entry->username)
1040 /* Resolve the detailed client information */
1041 silc_server_query_resolve(server, query,
1042 client_entry->router->connection,
1047 case SILC_COMMAND_IDENTIFY:
1048 for (i = 0; i < clients_count; i++) {
1049 client_entry = clients[i];
1051 /* Check if cannot query this anyway, so take next one */
1052 if (!client_entry || !client_entry->router ||
1053 !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
1056 /* Even if nickname is present, we may need to resolve the entry */
1057 if (client_entry->nickname) {
1059 /* If we are router, client is local to us, or client is on channel
1060 we do not need to resolve the client information. */
1061 if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
1062 || silc_hash_table_count(client_entry->channels) ||
1067 /* Resolve the detailed client information */
1068 silc_server_query_resolve(server, query,
1069 client_entry->router->connection,
1075 if (!query->queries_count)
1076 /* If we didn't have to do any resolving, continue with sending the
1077 command reply to the original sender. */
1078 silc_server_query_send_reply(server, query, clients, clients_count,
1079 servers, servers_count, channels,
1082 /* Now actually send the resolvings we gathered earlier */
1083 silc_server_query_resolve(server, query, NULL, NULL);
1087 silc_free(channels);
1090 /* Resolve the detailed information for the `client_entry'. Only client
1091 information needs to be resolved for being incomplete. Each incomplete
1092 client entry calls this function to do the resolving. */
1094 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
1095 SilcPacketStream sock,
1096 SilcClientEntry client_entry)
1098 SilcServerCommandContext cmd = query->cmd;
1099 SilcServerQueryList r = NULL;
1106 if (!sock && client_entry)
1109 /* If arguments are NULL we will now actually send the resolvings
1110 that earlier has been gathered by calling this function. */
1111 if (!sock && !client_entry) {
1114 SILC_LOG_DEBUG(("Sending the resolvings"));
1116 /* WHOWAS resolving has been done at the same time this function
1117 was called to add the resolving for WHOWAS, so just return. */
1118 if (query->querycmd == SILC_COMMAND_WHOWAS)
1121 for (i = 0; i < query->querylist_count; i++) {
1122 r = &query->querylist[i];
1124 /* If Requested Attributes were present put them to this resolving */
1125 if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1127 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1128 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1129 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1131 tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1133 r->arg[r->argc] = silc_memdup(tmp, len);
1134 r->arg_lens[r->argc] = len;
1135 r->arg_types[r->argc] = 3;
1140 server->stat.commands_sent++;
1142 /* Send WHOIS command */
1143 res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1144 r->argc, r->arg, r->arg_lens,
1145 r->arg_types, r->ident);
1146 silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1147 res_cmd->data, silc_buffer_len(res_cmd));
1148 silc_buffer_free(res_cmd);
1150 /* Reprocess this packet after received reply */
1151 if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1153 silc_server_query_resolve_reply,
1155 query->queries_left++;
1158 /* Cleanup this temporary context */
1159 for (i = 0; i < query->querylist_count; i++) {
1161 for (k = 0; k < query->querylist[i].argc; k++)
1162 silc_free(query->querylist[i].arg[k]);
1163 silc_free(query->querylist[i].arg);
1164 silc_free(query->querylist[i].arg_lens);
1165 silc_free(query->querylist[i].arg_types);
1167 silc_free(query->querylist);
1168 query->querylist = NULL;
1169 query->querylist_count = 0;
1173 SILC_LOG_DEBUG(("Resolving client information"));
1175 if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1176 /* The entry is being resolved by some other external query already.
1177 Attach to that query instead of resolving again. */
1178 ident = client_entry->resolve_cmd_ident;
1179 if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1180 silc_server_query_resolve_reply, query))
1181 query->queries_left++;
1183 /* This entry will be resolved */
1184 ident = ++server->cmd_ident;
1186 switch (query->querycmd) {
1188 case SILC_COMMAND_WHOIS:
1189 case SILC_COMMAND_IDENTIFY:
1190 /* Take existing query context if exist for this connection */
1191 for (i = 0; i < query->querylist_count; i++)
1192 if (query->querylist[i].sock == sock) {
1193 r = &query->querylist[i];
1198 /* Allocate new temp query list context */
1199 query->querylist = silc_realloc(query->querylist,
1200 sizeof(*query->querylist) *
1201 (query->querylist_count + 1));
1202 r = &query->querylist[query->querylist_count];
1203 query->querylist_count++;
1204 memset(r, 0, sizeof(*r));
1207 if (SILC_IS_LOCAL(client_entry))
1212 r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1213 r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1214 r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1216 /* Add the client entry to be resolved */
1217 idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1218 r->arg[r->argc] = silc_memdup(idp->data, silc_buffer_len(idp));
1219 r->arg_lens[r->argc] = silc_buffer_len(idp);
1220 r->arg_types[r->argc] = r->argc + 4;
1222 silc_buffer_free(idp);
1226 case SILC_COMMAND_WHOWAS:
1227 /* We must send WHOWAS command since it's the only the way of
1228 resolving clients that are not present in the network anymore. */
1229 silc_server_send_command(server, sock, query->querycmd, ident, 1,
1230 1, query->nickname, strlen(query->nickname));
1231 if (silc_server_command_pending(server, query->querycmd, ident,
1232 silc_server_query_resolve_reply, query))
1233 query->queries_left++;
1238 /* Mark the entry as being resolved */
1239 client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1240 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1241 client_entry->resolve_cmd_ident = ident;
1242 client_entry->updated = time(NULL);
1244 /* Save the queried ID, which we will reprocess after we get this and
1245 all other queries back. */
1246 query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1247 (query->queries_count + 1));
1248 if (query->queries) {
1249 i = query->queries_count;
1250 query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1251 query->queries[i].id_type = SILC_ID_CLIENT;
1252 query->queries[i].ident = ident;
1253 query->queries_count++;
1257 /* Reply callback called after one resolving has been completed. If
1258 all resolvings has been received then we will continue with sending
1259 the command reply to the original sender of the query. */
1261 void silc_server_query_resolve_reply(void *context, void *reply)
1263 SilcServerQuery query = context;
1264 SilcServer server = query->cmd->server;
1265 SilcServerCommandReplyContext cmdr = reply;
1266 SilcUInt16 ident = cmdr->ident;
1267 SilcStatus error = SILC_STATUS_OK;
1268 SilcServerQueryID id = NULL;
1269 SilcClientEntry client_entry;
1272 /* One less query left */
1273 query->queries_left--;
1275 silc_command_get_status(cmdr->payload, NULL, &error);
1276 SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1277 query->queries_left, error));
1279 /* If no error then skip to other stuff */
1280 if (error == SILC_STATUS_OK)
1283 /* Error occurred during resolving */
1285 /* Find the resolved client ID */
1286 for (i = 0; i < query->queries_count; i++) {
1287 if (query->queries[i].ident != ident)
1290 id = &query->queries[i];
1292 if (error == SILC_STATUS_ERR_TIMEDOUT) {
1294 /* If timeout occurred for local entry when resolving attributes
1295 mark that this client doesn't support attributes in WHOIS. This
1296 assures we won't send the request again to the client. */
1297 if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1298 client_entry = silc_idlist_find_client_by_id(server->local_list,
1299 id->id, TRUE, NULL);
1300 SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1301 silc_id_render(id->id, SILC_ID_CLIENT)));
1302 if (client_entry && SILC_IS_LOCAL(client_entry)) {
1303 client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1304 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1309 /* Remove the RESOLVING status from the client entry */
1310 if (query->querycmd != SILC_COMMAND_WHOWAS) {
1311 client_entry = silc_idlist_find_client_by_id(server->local_list,
1312 id->id, TRUE, NULL);
1314 client_entry = silc_idlist_find_client_by_id(server->global_list,
1315 id->id, TRUE, NULL);
1317 client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1324 /* If there are queries left then wait for them */
1325 if (query->queries_left)
1328 SILC_LOG_DEBUG(("Reprocess the query"));
1330 /* If the original command caller has gone away, just stop. */
1331 if (!silc_packet_stream_is_valid(query->cmd->sock)) {
1332 SILC_LOG_DEBUG(("Original command caller vanished"));
1333 silc_server_query_free(query);
1337 /* We have received all queries. Now re-search all information required
1338 to complete this query. Reason we cannot save the values found in
1339 the first search is that SilcClientEntry, SilcServerEntry and
1340 SilcChannelEntry pointers may become invalid while we were waiting
1341 for these resolvings. */
1342 silc_server_query_process(server, query, FALSE);
1345 /* Send the reply to the original query. If arguments are NULL then this
1346 sends only the errors that has occurred during the processing of the
1347 query. This sends the errors always after sending all the found
1348 information. The query is over after this function returns and the
1349 `query' will become invalid. This is called only after all informations
1350 has been resolved. This means that if something is not found or is
1351 incomplete in this function we were unable to resolve the information
1352 or it does not exist at all. */
1354 void silc_server_query_send_reply(SilcServer server,
1355 SilcServerQuery query,
1356 SilcClientEntry *clients,
1357 SilcUInt32 clients_count,
1358 SilcServerEntry *servers,
1359 SilcUInt32 servers_count,
1360 SilcChannelEntry *channels,
1361 SilcUInt32 channels_count)
1363 SilcServerCommandContext cmd = query->cmd;
1364 SilcIDListData idata = silc_packet_get_context(cmd->sock);
1365 SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1370 int i, k, valid_count;
1371 char nh[384], uh[384];
1372 SilcBool sent_reply = FALSE;
1374 SILC_LOG_DEBUG(("Sending reply to query"));
1375 SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1376 SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1377 SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1378 SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1380 status = SILC_STATUS_OK;
1383 if (clients_count) {
1384 SilcClientEntry entry;
1385 SilcPacketStream hsock;
1387 /* Mark all invalid entries */
1388 for (i = 0, valid_count = 0; i < clients_count; i++) {
1393 switch (query->querycmd) {
1394 case SILC_COMMAND_WHOIS:
1395 if (!entry->nickname || !entry->username || !entry->userinfo ||
1396 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1397 /* When querying by ID, every "unfound" entry must cause error */
1399 silc_server_query_add_error_id(server, query,
1400 SILC_STATUS_ERR_TIMEDOUT,
1401 entry->id, SILC_ID_CLIENT);
1407 case SILC_COMMAND_IDENTIFY:
1408 if (!entry->nickname ||
1409 !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1410 /* When querying by ID, every "unfound" entry must cause error */
1412 silc_server_query_add_error_id(server, query,
1413 SILC_STATUS_ERR_TIMEDOUT,
1414 entry->id, SILC_ID_CLIENT);
1420 case SILC_COMMAND_WHOWAS:
1421 if (!entry->nickname || !entry->username ||
1422 entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1431 /* Start processing found clients */
1432 status = SILC_STATUS_OK;
1433 if (valid_count > 1)
1434 status = SILC_STATUS_LIST_START;
1436 /* Now do the sending of valid entries */
1438 for (i = 0; i < clients_count && valid_count; i++) {
1444 status = SILC_STATUS_LIST_ITEM;
1445 if (valid_count > 1 && k == valid_count - 1
1446 && !servers_count && !channels_count && !query->errors_count)
1447 status = SILC_STATUS_LIST_END;
1448 if (query->reply_count && k - 1 == query->reply_count)
1449 status = SILC_STATUS_LIST_END;
1451 SILC_LOG_DEBUG(("%s: client %s",
1452 (status == SILC_STATUS_OK ? " OK" :
1453 status == SILC_STATUS_LIST_START ? "START" :
1454 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1455 status == SILC_STATUS_LIST_END ? " END" :
1456 " : "), entry->nickname));
1458 idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1459 memset(nh, 0, sizeof(nh));
1461 silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1462 if (!strchr(entry->nickname, '@')) {
1463 silc_strncat(nh, sizeof(nh), "@", 1);
1464 if (entry->servername) {
1465 silc_strncat(nh, sizeof(nh), entry->servername,
1466 strlen(entry->servername));
1468 len = entry->router ? strlen(entry->router->server_name) :
1469 strlen(server->server_name);
1470 silc_strncat(nh, sizeof(nh), entry->router ?
1471 entry->router->server_name :
1472 server->server_name, len);
1476 switch (query->querycmd) {
1478 case SILC_COMMAND_WHOIS:
1480 unsigned char idle[4], mode[4];
1481 unsigned char *fingerprint, fempty[20], *attrs = NULL;
1482 SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1484 memset(fempty, 0, sizeof(fempty));
1485 memset(idle, 0, sizeof(idle));
1486 memset(uh, 0, sizeof(uh));
1488 silc_strncat(uh, sizeof(uh), entry->username,
1489 strlen(entry->username));
1490 if (!strchr(entry->username, '@') && entry->connection) {
1491 hsock = entry->connection;
1492 silc_strncat(uh, sizeof(uh), "@", 1);
1493 silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
1494 NULL, (const char **)&tmp, NULL, NULL);
1495 silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
1498 if (idata->conn_type == SILC_CONN_CLIENT)
1500 silc_server_get_client_channel_list(server, entry, FALSE,
1501 FALSE, &umode_list);
1504 silc_server_get_client_channel_list(server, entry, TRUE,
1507 if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1508 fingerprint = entry->data.fingerprint;
1512 SILC_PUT32_MSB(entry->mode, mode);
1513 if (entry->connection)
1514 SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1516 /* If Requested Attribute were present, and we do not have the
1517 attributes we will reply to them on behalf of the client. */
1520 if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1521 tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1522 entry->attrs = silc_buffer_steal(tmpattrs, &len);
1523 entry->attrs_len = len;
1524 silc_buffer_free(tmpattrs);
1526 attrs = entry->attrs;
1527 len = entry->attrs_len;
1530 /* Send command reply */
1531 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1532 status, 0, ident, 10,
1533 2, idp->data, silc_buffer_len(idp),
1537 strlen(entry->userinfo),
1538 6, channels ? channels->data : NULL,
1539 channels ? silc_buffer_len(channels)
1544 fingerprint ? 20 : 0,
1545 10, umode_list ? umode_list->data :
1547 silc_buffer_len(umode_list) :
1552 /* For now we always delete Requested Attributes, unless the client
1553 is detached, in which case we don't want to reconstruct the
1554 same data everytime */
1555 if (!(entry->mode & SILC_UMODE_DETACHED) &&
1556 !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1557 silc_free(entry->attrs);
1558 entry->attrs = NULL;
1562 silc_buffer_free(channels);
1564 silc_buffer_free(umode_list);
1570 case SILC_COMMAND_IDENTIFY:
1571 if (!entry->username) {
1572 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1573 status, 0, ident, 2,
1574 2, idp->data, silc_buffer_len(idp),
1578 memset(uh, 0, sizeof(uh));
1579 silc_strncat(uh, sizeof(uh), entry->username,
1580 strlen(entry->username));
1581 if (!strchr(entry->username, '@') && entry->connection) {
1582 hsock = entry->connection;
1583 silc_strncat(uh, sizeof(uh), "@", 1);
1584 silc_socket_stream_get_info(silc_packet_stream_get_stream(hsock),
1585 NULL, (const char **)&tmp,
1587 silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
1590 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1591 status, 0, ident, 3,
1592 2, idp->data, silc_buffer_len(idp),
1599 case SILC_COMMAND_WHOWAS:
1600 memset(uh, 0, sizeof(uh));
1601 silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1602 if (!strchr(entry->username, '@'))
1603 silc_strncat(uh, sizeof(uh), "@-private-", 10);
1605 /* Send command reply */
1606 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1607 status, 0, ident, 4,
1608 2, idp->data, silc_buffer_len(idp),
1613 strlen(entry->userinfo) : 0);
1618 silc_buffer_free(idp);
1620 if (status == SILC_STATUS_LIST_END)
1626 /* Not one valid entry was found, send error. If nickname was used
1627 in query send error based on that, otherwise the query->errors
1628 already includes proper errors. */
1629 if (query->nickname[0] || (!query->ids && query->attrs))
1630 silc_server_query_add_error(server, query, 1, 1,
1631 SILC_STATUS_ERR_NO_SUCH_NICK);
1633 /* Make sure some error is sent */
1634 if (!query->errors_count && !servers_count && !channels_count)
1635 silc_server_query_add_error(server, query, 2, 0,
1636 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1641 if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1642 SilcServerEntry entry;
1644 if (status == SILC_STATUS_OK && servers_count > 1)
1645 status = SILC_STATUS_LIST_START;
1648 for (i = 0; i < servers_count; i++) {
1652 status = SILC_STATUS_LIST_ITEM;
1653 if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1654 !query->errors_count)
1655 status = SILC_STATUS_LIST_END;
1656 if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1657 !query->errors_count)
1658 status = SILC_STATUS_LIST_END;
1659 if (query->reply_count && k - 1 == query->reply_count)
1660 status = SILC_STATUS_LIST_END;
1662 SILC_LOG_DEBUG(("%s: server %s",
1663 (status == SILC_STATUS_OK ? " OK" :
1664 status == SILC_STATUS_LIST_START ? "START" :
1665 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1666 status == SILC_STATUS_LIST_END ? " END" :
1668 entry->server_name ? entry->server_name : ""));
1670 /* Send command reply */
1671 idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1672 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1673 status, 0, ident, 2,
1674 2, idp->data, silc_buffer_len(idp),
1675 3, entry->server_name,
1676 entry->server_name ?
1677 strlen(entry->server_name) : 0);
1678 silc_buffer_free(idp);
1681 if (status == SILC_STATUS_LIST_END)
1688 if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1689 SilcChannelEntry entry;
1691 if (status == SILC_STATUS_OK && channels_count > 1)
1692 status = SILC_STATUS_LIST_START;
1695 for (i = 0; i < channels_count; i++) {
1696 entry = channels[i];
1699 status = SILC_STATUS_LIST_ITEM;
1700 if (channels_count == 1 && status != SILC_STATUS_OK &&
1701 !query->errors_count)
1702 status = SILC_STATUS_LIST_END;
1703 if (channels_count > 1 && k == channels_count - 1 &&
1704 !query->errors_count)
1705 status = SILC_STATUS_LIST_END;
1706 if (query->reply_count && k - 1 == query->reply_count)
1707 status = SILC_STATUS_LIST_END;
1709 SILC_LOG_DEBUG(("%s: channel %s",
1710 (status == SILC_STATUS_OK ? " OK" :
1711 status == SILC_STATUS_LIST_START ? "START" :
1712 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1713 status == SILC_STATUS_LIST_END ? " END" :
1715 entry->channel_name ? entry->channel_name : ""));
1717 /* Send command reply */
1718 idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1719 silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1720 status, 0, ident, 2,
1721 2, idp->data, silc_buffer_len(idp),
1722 3, entry->channel_name,
1723 entry->channel_name ?
1724 strlen(entry->channel_name) : 0);
1725 silc_buffer_free(idp);
1728 if (status == SILC_STATUS_LIST_END)
1735 if (query->errors_count) {
1738 if (status == SILC_STATUS_OK && query->errors_count > 1)
1739 status = SILC_STATUS_LIST_START;
1742 for (i = 0; i < query->errors_count; i++) {
1745 /* Take error argument */
1746 if (query->errors[i].type == 1) {
1747 /* Take from sent arguments */
1749 tmp = silc_argument_get_arg_type(cmd->args,
1750 query->errors[i].index, &len);
1752 } else if (query->errors[i].type == 2) {
1757 } else if (!query->errors[i].id) {
1758 /* Take from query->ids */
1760 silc_id_payload_encode(query->ids[query->errors[i].index].id,
1761 query->ids[query->errors[k].index].id_type);
1763 len = silc_buffer_len(idp);
1766 /* Take added ID. */
1767 idp = silc_id_payload_encode(query->errors[i].id,
1768 query->errors[k].id_type);
1770 len = silc_buffer_len(idp);
1775 status = SILC_STATUS_LIST_ITEM;
1776 if (query->errors_count == 1 && status != SILC_STATUS_OK)
1777 status = SILC_STATUS_LIST_END;
1778 if (query->errors_count > 1 && k == query->errors_count - 1)
1779 status = SILC_STATUS_LIST_END;
1780 if (query->reply_count && k - 1 == query->reply_count)
1781 status = SILC_STATUS_LIST_END;
1783 SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1784 (status == SILC_STATUS_OK ? " OK" :
1785 status == SILC_STATUS_LIST_START ? "START" :
1786 status == SILC_STATUS_LIST_ITEM ? " ITEM" :
1787 status == SILC_STATUS_LIST_END ? " END" :
1789 silc_get_status_message(query->errors[i].error),
1790 query->errors[i].error));
1792 #if 1 /* XXX Backwards compatibility. Remove in 1.0. */
1793 if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
1795 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1796 (status == SILC_STATUS_OK ?
1797 query->errors[i].error : status),
1798 (status == SILC_STATUS_OK ?
1799 0 : query->errors[i].error), ident, 2,
1805 silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1806 (status == SILC_STATUS_OK ?
1807 query->errors[i].error : status),
1808 (status == SILC_STATUS_OK ?
1809 0 : query->errors[i].error), ident, 1,
1812 silc_buffer_free(idp);
1815 if (status == SILC_STATUS_LIST_END)
1822 SILC_LOG_ERROR(("BUG: Query did not send anything"));
1825 silc_server_query_free(query);
1828 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1829 of the client since we were unable to resolve them from the client.
1830 Either client does not support Requested Attributes or isn't replying
1831 to them like it should. */
1833 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1834 SilcServerQuery query,
1835 SilcClientEntry client_entry)
1837 SilcBuffer buffer = NULL;
1838 SilcAttribute attribute;
1839 SilcAttributePayload attr;
1840 SilcAttributeObjPk pk;
1841 SilcAttributeObjService service;
1843 unsigned char sign[2048 + 1];
1844 SilcUInt32 sign_len;
1846 SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1848 /* Go through all requested attributes */
1849 silc_dlist_start(query->attrs);
1850 while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1851 attribute = silc_attribute_get_attribute(attr);
1852 switch (attribute) {
1854 case SILC_ATTRIBUTE_SERVICE:
1855 /* Put SERVICE. Put only SILC service. */
1856 memset(&service, 0, sizeof(service));
1857 service.port = (server->config->server_info->primary ?
1858 server->config->server_info->primary->port : SILC_PORT);
1859 silc_strncat(service.address, sizeof(service.address),
1860 server->server_name, strlen(server->server_name));
1861 service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1862 if (client_entry->connection)
1863 service.idle = time(NULL) - client_entry->data.last_receive;
1864 buffer = silc_attribute_payload_encode(buffer, attribute,
1865 SILC_ATTRIBUTE_FLAG_VALID,
1866 &service, sizeof(service));
1871 case SILC_ATTRIBUTE_STATUS_MOOD:
1872 /* Put STATUS_MOOD */
1873 buffer = silc_attribute_payload_encode(buffer, attribute,
1874 SILC_ATTRIBUTE_FLAG_VALID,
1876 SILC_ATTRIBUTE_MOOD_NORMAL,
1877 sizeof(SilcUInt32));
1882 case SILC_ATTRIBUTE_STATUS_FREETEXT:
1883 /* Put STATUS_FREETEXT. We just tell in the message that we are
1884 replying on behalf of the client. */
1886 "This information was provided by the server on behalf of the user";
1887 buffer = silc_attribute_payload_encode(buffer, attribute,
1888 SILC_ATTRIBUTE_FLAG_VALID,
1894 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1895 /* Put PREFERRED_CONTACT */
1896 buffer = silc_attribute_payload_encode(buffer, attribute,
1897 SILC_ATTRIBUTE_FLAG_VALID,
1899 SILC_ATTRIBUTE_CONTACT_CHAT,
1900 sizeof(SilcUInt32));
1905 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1906 /* Put USER_PUBLIC_KEY */
1907 if (client_entry->data.public_key) {
1908 pk.type = "silc-rsa";
1909 pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1911 buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1912 SILC_ATTRIBUTE_FLAG_VALID :
1913 SILC_ATTRIBUTE_FLAG_INVALID,
1921 /* No public key available */
1922 buffer = silc_attribute_payload_encode(buffer, attribute,
1923 SILC_ATTRIBUTE_FLAG_INVALID,
1930 /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1931 if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1932 attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1935 /* For other attributes we cannot reply so mark it invalid */
1936 buffer = silc_attribute_payload_encode(buffer, attribute,
1937 SILC_ATTRIBUTE_FLAG_INVALID,
1945 /* Always put our public key. This assures that we send at least
1946 something valid back always. */
1947 pk.type = "silc-rsa";
1948 pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1949 buffer = silc_attribute_payload_encode(buffer,
1950 SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1951 pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1952 SILC_ATTRIBUTE_FLAG_INVALID,
1958 /* Finally compute the digital signature of all the data we provided
1959 as an indication that we provided rightfull information, and this
1960 also authenticates our public key. */
1961 if (silc_pkcs_private_key_get_len(server->private_key) / 8 <=
1963 silc_pkcs_sign(server->private_key, buffer->data,
1964 silc_buffer_len(buffer), sign, sizeof(sign), &sign_len,
1965 TRUE, server->sha1hash)) {
1968 pk.data_len = sign_len;
1970 silc_attribute_payload_encode(buffer,
1971 SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1972 SILC_ATTRIBUTE_FLAG_VALID,
1981 /* Find client by the Client ID indicated by the `client_id', and if not
1982 found then query it by using WHOIS command. The client information
1983 is also resolved if the cached information is incomplete or if the
1984 `always_resolve' is set to TRUE. The indication whether requested
1985 client was being resolved is saved into `resolved'. If the client
1986 is not being resolved its entry is returned by this function. NULL
1987 is returned if client is resolved. */
1989 SilcClientEntry silc_server_query_client(SilcServer server,
1990 const SilcClientID *client_id,
1991 SilcBool always_resolve,
1994 SilcClientEntry client;
1996 SILC_LOG_DEBUG(("Resolving client by client ID"));
2001 client = silc_idlist_find_client_by_id(server->local_list,
2002 (SilcClientID *)client_id,
2005 client = silc_idlist_find_client_by_id(server->global_list,
2006 (SilcClientID *)client_id,
2008 if (!client && server->server_type == SILC_ROUTER)
2012 if (!client && server->standalone)
2015 if (!client || !client->nickname || !client->username ||
2017 SilcBuffer buffer, idp;
2020 server->stat.commands_sent++;
2023 client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
2024 client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
2025 client->resolve_cmd_ident = ++server->cmd_ident;
2028 idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
2029 buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
2030 server->cmd_ident, 1,
2032 silc_buffer_len(idp));
2033 silc_server_packet_send(server, client ? client->router->connection :
2034 SILC_PRIMARY_ROUTE(server),
2035 SILC_PACKET_COMMAND, 0,
2036 buffer->data, silc_buffer_len(buffer));
2037 silc_buffer_free(idp);
2038 silc_buffer_free(buffer);