ccc3932440d78e64284c0057ed49a2a4f9df43e1
[silc.git] / apps / silcd / server_query.c
1 /*
2
3   server_query.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2002 - 2003 Pekka Riikonen
8
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.
12
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.
17
18 */
19 /* $Id$ */
20
21 #include "serverincludes.h"
22 #include "server_internal.h"
23
24 typedef struct {
25   SilcSocketConnection sock;        /* Connection of this query */
26   unsigned char **arg;              /* Query argument */
27   SilcUInt32 *arg_lens;             /* Query argument lengths */
28   SilcUInt32 *arg_types;            /* Query argument types */
29   SilcUInt32 argc;                  /* Number of query arguments */
30   SilcUInt32 timeout;               /* Max timeout for query to complete */
31   SilcUInt16 ident;                 /* Query command identifier */
32 } *SilcServerQueryList;
33
34 /* Represents an SILC ID */
35 typedef struct {
36   void *id;                         /* ID */
37   SilcIdType id_type;               /* ID type */
38   SilcUInt16 ident;                 /* Command identifier */
39 } *SilcServerQueryID;
40
41 /* Represents one error occurred during query */
42 typedef struct {
43   void *id;                         /* ID */
44   SilcIdType id_type;               /* ID type */
45   SilcUInt16 index;                 /* Index to IDs */
46   unsigned int from_cmd : 1;        /* TRUE if `index' is from command args,
47                                        otherwise from query->ids */
48   unsigned int error : 7;           /* The actual error (SilcStatus) */
49 } *SilcServerQueryError;
50
51 /* Query session context */
52 typedef struct {
53   /* Queried data */
54   char *nickname;                   /* Queried nickname */
55   char *nick_server;                /* Queried nickname's server */
56   char *server_name;                /* Queried server name */
57   char *channel_name;               /* Queried channel name */
58   SilcServerQueryID ids;            /* Queried IDs */
59   SilcUInt32 ids_count;             /* number of queried IDs */
60   SilcUInt32 reply_count;           /* Requested reply count */
61   SilcDList attrs;                  /* Requested Attributes in WHOIS */
62
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 */
75 } *SilcServerQuery;
76
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,
83                                  bool from_cmd,
84                                  SilcUInt32 index,
85                                  SilcStatus error);
86 void silc_server_query_add_error_id(SilcServer server,
87                                     SilcServerQuery query,
88                                     SilcStatus error,
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,
94                                bool resolve);
95 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
96                                SilcSocketConnection sock,
97                                SilcClientEntry client_entry);
98 void silc_server_query_resolve_reply(void *context, void *reply);
99 void silc_server_query_send_reply(SilcServer server,
100                                   SilcServerQuery query,
101                                   SilcClientEntry *clients,
102                                   SilcUInt32 clients_count,
103                                   SilcServerEntry *servers,
104                                   SilcUInt32 servers_count,
105                                   SilcChannelEntry *channels,
106                                   SilcUInt32 channels_count);
107 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
108                                          SilcServerQuery query,
109                                          SilcClientEntry client_entry);
110
111 /* Free the query context structure and all allocated resources. */
112
113 void silc_server_query_free(SilcServerQuery query)
114 {
115   int i;
116
117   silc_server_command_free(query->cmd);
118
119   for (i = 0; i < query->queries_count; i++)
120     silc_free(query->queries[i].id);
121   silc_free(query->queries);
122
123   silc_free(query->nickname);
124   silc_free(query->nick_server);
125   silc_free(query->server_name);
126   silc_free(query->channel_name);
127
128   for (i = 0; i < query->ids_count; i++)
129     silc_free(query->ids[i].id);
130   silc_free(query->ids);
131
132   if (query->attrs)
133     silc_attribute_payload_list_free(query->attrs);
134
135   for (i = 0; i < query->errors_count; i++)
136     silc_free(query->errors[i].id);
137   silc_free(query->errors);
138
139   memset(query, 'F', sizeof(*query));
140   silc_free(query);
141 }
142
143 /* Send error reply indicated by the `error' to the original sender of
144    the query. */
145
146 void silc_server_query_send_error(SilcServer server,
147                                   SilcServerQuery query,
148                                   SilcStatus error, ...)
149 {
150   va_list va;
151   unsigned char *data = NULL;
152   SilcUInt32 data_len = 0, data_type = 0, argc = 0;
153
154   va_start(va, error);
155   data_type = va_arg(va, SilcUInt32);
156   if (data_type) {
157     argc = 1;
158     data = va_arg(va, unsigned char *);
159     data_len = va_arg(va, SilcUInt32);
160   }
161
162   SILC_LOG_DEBUG(("ERROR: %s (%d)", silc_get_status_message(error), error));
163
164   /* Send the command reply with error */
165   silc_server_send_command_reply(server, query->cmd->sock,
166                                  query->querycmd, error, 0,
167                                  silc_command_get_ident(query->cmd->payload),
168                                  argc, data_type, data, data_len);
169   va_end(va);
170 }
171
172 /* Add error to error list.  Multiple errors may occur during the query
173    processing and this function can be used to add one error.  The
174    `index' is the index to the command context which includes the argument
175    which caused the error, or it is the index to query->ids, depending
176    on value of `from_cmd'. */
177
178 void silc_server_query_add_error(SilcServer server,
179                                  SilcServerQuery query,
180                                  bool from_cmd,
181                                  SilcUInt32 index,
182                                  SilcStatus error)
183 {
184   query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
185                                (query->errors_count + 1));
186   if (!query->errors)
187     return;
188   query->errors[query->errors_count].index = index;
189   query->errors[query->errors_count].from_cmd = from_cmd;
190   query->errors[query->errors_count].error = error;
191   query->errors[query->errors_count].id = NULL;
192   query->errors[query->errors_count].id_type = 0;
193   query->errors_count++;
194 }
195
196 /* Same as silc_server_query_add_error but adds the ID data to be used
197    with error sending with this error type. */
198
199 void silc_server_query_add_error_id(SilcServer server,
200                                     SilcServerQuery query,
201                                     SilcStatus error,
202                                     void *id, SilcIdType id_type)
203 {
204   query->errors = silc_realloc(query->errors, sizeof(*query->errors) *
205                                (query->errors_count + 1));
206   if (!query->errors)
207     return;
208   query->errors[query->errors_count].index = 0;
209   query->errors[query->errors_count].from_cmd = FALSE;
210   query->errors[query->errors_count].error = error;
211   query->errors[query->errors_count].id = silc_id_dup(id, id_type);
212   query->errors[query->errors_count].id_type = id_type;
213   query->errors_count++;
214 }
215
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. */
222
223 bool silc_server_query_command(SilcServer server, SilcCommand querycmd,
224                                SilcServerCommandContext cmd)
225 {
226   SilcServerQuery query;
227
228   SILC_LOG_DEBUG(("Query %s command", silc_get_command_name(querycmd)));
229
230   query = silc_calloc(1, sizeof(*query));
231   query->querycmd = querycmd;
232   query->cmd = silc_server_command_dup(cmd);
233
234   switch (querycmd) {
235
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
239        router */
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);
247       return TRUE;
248     }
249     break;
250
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);
256       return TRUE;
257     }
258     break;
259
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
263        name). */
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);
268       return TRUE;
269     }
270     break;
271
272   default:
273     SILC_LOG_ERROR(("Bad query using %d command", querycmd));
274     silc_server_query_free(query);
275     return FALSE;
276   }
277
278   /* Now parse the request */
279   silc_server_query_parse(server, query);
280
281   return TRUE;
282 }
283
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. */
287
288 void silc_server_query_send_router(SilcServer server, SilcServerQuery query)
289 {
290   SilcBuffer tmpbuf;
291   SilcUInt16 old_ident;
292
293   SILC_LOG_DEBUG(("Forwarding the query to router for processing"));
294
295   /* Send WHOIS command to our router */
296   old_ident = silc_command_get_ident(query->cmd->payload);
297   silc_command_set_ident(query->cmd->payload, ++server->cmd_ident);
298   tmpbuf = silc_command_payload_encode_payload(query->cmd->payload);
299   silc_server_packet_send(server,
300                           SILC_PRIMARY_ROUTE(server),
301                           SILC_PACKET_COMMAND, 0,
302                           tmpbuf->data, tmpbuf->len, TRUE);
303   silc_command_set_ident(query->cmd->payload, old_ident);
304   silc_buffer_free(tmpbuf);
305
306   query->resolved = TRUE;
307
308   /* Continue parsing the query after received reply from router */
309   silc_server_command_pending(server, query->querycmd, server->cmd_ident,
310                               silc_server_query_send_router_reply, query);
311 }
312
313 /* Reply callback called after primary router has replied to our initial
314    sending of the query to it.  We will proceed the query in this function. */
315
316 void silc_server_query_send_router_reply(void *context, void *reply)
317 {
318   SilcServerQuery query = context;
319   SilcServer server = query->cmd->server;
320   SilcServerCommandReplyContext cmdr = reply;
321
322   SILC_LOG_DEBUG(("Received reply from router to query"));
323
324   /* Check if router sent error reply */
325   if (cmdr && !silc_command_get_status(cmdr->payload, NULL, NULL)) {
326     SilcBuffer buffer;
327
328     SILC_LOG_DEBUG(("Sending error to original query"));
329
330     /* Send the same command reply payload which contains the error */
331     silc_command_set_command(cmdr->payload, query->querycmd);
332     silc_command_set_ident(cmdr->payload,
333                            silc_command_get_ident(query->cmd->payload));
334     buffer = silc_command_payload_encode_payload(cmdr->payload);
335     silc_server_packet_send(server, query->cmd->sock,
336                             SILC_PACKET_COMMAND_REPLY, 0,
337                             buffer->data, buffer->len, FALSE);
338     silc_buffer_free(buffer);
339     silc_server_query_free(query);
340     return;
341   }
342
343   /* Continue with parsing */
344   silc_server_query_parse(server, query);
345 }
346
347 /* Parse the command query and start processing the queries in detail. */
348
349 void silc_server_query_parse(SilcServer server, SilcServerQuery query)
350 {
351   SilcServerCommandContext cmd = query->cmd;
352   unsigned char *tmp;
353   SilcUInt32 tmp_len, argc = silc_argument_get_arg_num(cmd->args);
354   void *id;
355   SilcIdType id_type;
356   int i;
357
358   SILC_LOG_DEBUG(("Parsing %s query",
359                   silc_get_command_name(query->querycmd)));
360
361   switch (query->querycmd) {
362
363   case SILC_COMMAND_WHOIS:
364     /* Get requested attributes if set */
365     tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
366     if (tmp && !query->attrs && tmp_len <= SILC_ATTRIBUTE_MAX_REQUEST_LEN) {
367       query->attrs = silc_attribute_payload_parse(tmp, tmp_len);
368
369       /* When Requested Attributes is present we will assure that this
370          client cannot execute the WHOIS command too fast.  This would be
371          same as having SILC_CF_LAG_STRICT. */
372       if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
373           cmd->sock->user_data)
374         ((SilcClientEntry)cmd->sock->user_data)->fast_command = 6;
375     }
376
377     /* Get Client IDs if present. Take IDs always instead of nickname. */
378     tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
379     if (!tmp) {
380
381       /* Get nickname */
382       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
383       if (!tmp && !query->attrs) {
384         /* No nickname, no ids and no attributes - send error */
385         silc_server_query_send_error(server, query,
386                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
387         silc_server_query_free(query);
388         return;
389       }
390
391       /* Get the nickname@server string and parse it */
392       if (tmp && ((tmp_len > 128) ||
393           !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))) {
394         silc_server_query_send_error(server, query,
395                                      SILC_STATUS_ERR_BAD_NICKNAME, 0);
396         silc_server_query_free(query);
397         return;
398       }
399
400     } else {
401       /* Parse the IDs included in the query */
402       query->ids = silc_calloc(argc, sizeof(*query->ids));
403
404       for (i = 0; i < argc; i++) {
405         tmp = silc_argument_get_arg_type(cmd->args, i + 4, &tmp_len);
406         if (!tmp)
407           continue;
408
409         id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
410         if (!id || id_type != SILC_ID_CLIENT) {
411           silc_server_query_add_error(server, query, TRUE, i + 4,
412                                       SILC_STATUS_ERR_BAD_CLIENT_ID);
413           continue;
414         }
415
416         /* Normal server must check whether this ID exist, and if not then
417            send the query to router, unless done so already */
418         if (server->server_type == SILC_SERVER && !query->resolved) {
419           if (!silc_idlist_find_client_by_id(server->local_list,
420                                              id, TRUE, NULL)) {
421             if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
422                 !silc_idlist_find_client_by_id(server->global_list,
423                                                id, TRUE, NULL)) {
424               silc_server_query_send_router(server, query);
425               for (i = 0; i < query->ids_count; i++)
426                 silc_free(query->ids[i].id);
427               silc_free(query->ids);
428               query->ids = NULL;
429               query->ids_count = 0;
430               silc_free(id);
431               return;
432             }
433           }
434         }
435
436         query->ids[query->ids_count].id = id;
437         query->ids[query->ids_count].id_type = SILC_ID_CLIENT;
438         query->ids_count++;
439       }
440     }
441
442     /* Get the max count of reply messages allowed */
443     tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
444     if (tmp && tmp_len == sizeof(SilcUInt32))
445       SILC_GET32_MSB(query->reply_count, tmp);
446    break;
447
448   case SILC_COMMAND_WHOWAS:
449     /* Get nickname */
450     tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
451     if (!tmp) {
452       silc_server_query_send_error(server, query,
453                                    SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
454       silc_server_query_free(query);
455       return;
456     }
457
458     /* Get the nickname@server string and parse it */
459     if (tmp_len > 128 ||
460         !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server)) {
461       silc_server_query_send_error(server, query,
462                                    SILC_STATUS_ERR_BAD_NICKNAME, 0);
463       silc_server_query_free(query);
464       return;
465     }
466
467     /* Get the max count of reply messages allowed */
468     tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
469     if (tmp && tmp_len == sizeof(SilcUInt32))
470       SILC_GET32_MSB(query->reply_count, tmp);
471     break;
472
473   case SILC_COMMAND_IDENTIFY:
474     /* Get IDs if present. Take IDs always instead of names. */
475     tmp = silc_argument_get_arg_type(cmd->args, 5, &tmp_len);
476     if (!tmp) {
477
478       /* Try get nickname */
479       tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
480       if (tmp) {
481         /* Get the nickname@server string and parse it */
482         if (tmp_len > 128 ||
483             !silc_parse_userfqdn(tmp, &query->nickname, &query->nick_server))
484           silc_server_query_add_error(server, query, TRUE, 1,
485                                       SILC_STATUS_ERR_BAD_NICKNAME);
486       }
487
488       /* Try get server name */
489       tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
490       if (tmp)
491         query->server_name = silc_memdup(tmp, tmp_len);
492
493       /* Get channel name */
494       tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
495       if (tmp && tmp_len <= 256)
496         query->channel_name = silc_memdup(tmp, tmp_len);
497
498       if (!query->nickname && !query->server_name && !query->channel_name) {
499         silc_server_query_send_error(server, query,
500                                      SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
501         silc_server_query_free(query);
502         return;
503       }
504
505     } else {
506       /* Parse the IDs included in the query */
507       query->ids = silc_calloc(argc, sizeof(*query->ids));
508
509       for (i = 0; i < argc; i++) {
510         tmp = silc_argument_get_arg_type(cmd->args, i + 5, &tmp_len);
511         if (!tmp)
512           continue;
513
514         id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
515         if (!id) {
516           silc_server_query_add_error(server, query, TRUE, i + 5,
517                                       SILC_STATUS_ERR_BAD_CLIENT_ID);
518           continue;
519         }
520
521         /* Normal server must check whether this ID exist, and if not then
522            send the query to router, unless done so already */
523         if (server->server_type == SILC_SERVER && !query->resolved) {
524           if (id_type == SILC_ID_CLIENT) {
525             if (!silc_idlist_find_client_by_id(server->local_list,
526                                                id, TRUE, NULL)) {
527               if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT ||
528                   !silc_idlist_find_client_by_id(server->global_list,
529                                                  id, TRUE, NULL)) {
530                 silc_server_query_send_router(server, query);
531                 for (i = 0; i < query->ids_count; i++)
532                   silc_free(query->ids[i].id);
533                 silc_free(query->ids);
534                 query->ids = NULL;
535                 query->ids_count = 0;
536                 silc_free(id);
537                 return;
538               }
539             }
540           } else {
541             /* For now all other ID's except Client ID's are explicitly
542                sent to router for resolving. */
543             silc_server_query_send_router(server, query);
544             for (i = 0; i < query->ids_count; i++)
545               silc_free(query->ids[i].id);
546             silc_free(query->ids);
547             query->ids = NULL;
548             query->ids_count = 0;
549             silc_free(id);
550             return;
551           }
552         }
553
554         query->ids[query->ids_count].id = id;
555         query->ids[query->ids_count].id_type = id_type;
556         query->ids_count++;
557       }
558     }
559
560     /* Get the max count of reply messages allowed */
561     tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
562     if (tmp && tmp_len == sizeof(SilcUInt32))
563       SILC_GET32_MSB(query->reply_count, tmp);
564     break;
565   }
566
567   /* Start processing the query information */
568   silc_server_query_process(server, query, TRUE);
569 }
570
571 /* Context for holding clients searched by public key. */
572 typedef struct {
573   SilcClientEntry **clients;
574   SilcUInt32 *clients_count;
575   bool found;
576 } *SilcServerPublicKeyUser, SilcServerPublicKeyUserStruct;
577
578 void silc_server_public_key_hash_foreach(void *key, void *context,
579                                          void *user_context)
580 {
581   SilcServerPublicKeyUser uc = user_context;
582   SilcClientEntry entry = context;
583
584   /* Nothing was found, just return */
585   if (!context)
586     return;
587
588   uc->found = TRUE;
589
590   (*uc->clients) = silc_realloc((*uc->clients),
591                                 sizeof((**uc->clients)) *
592                                 ((*uc->clients_count) + 1));
593   (*uc->clients)[(*uc->clients_count)++] = entry;
594 }
595
596 /* If clients are set, limit the found clients using the attributes in
597    the query. If clients are not set, try to find some clients using
598    the attributes */
599
600 void silc_server_query_check_attributes(SilcServer server,
601                                         SilcServerQuery query,
602                                         SilcClientEntry **clients,
603                                         SilcUInt32 *clients_count) {
604   SilcClientEntry entry;
605   SilcAttributePayload attr;
606   SilcAttribute attribute;
607   SilcAttributeObjPk pk;
608   SilcPublicKey publickey;
609   int i;
610   bool found = FALSE, no_clients = FALSE;
611
612   /* If no clients were found, we only check the attributes
613      if the user wasn't searching for nickname/ids */
614   if (!*clients) {
615     no_clients = TRUE;
616     if (query->nickname || query->ids_count)
617       return;
618   }
619
620   silc_dlist_start(query->attrs);
621   while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
622     attribute = silc_attribute_get_attribute(attr);
623     switch (attribute) {
624
625       case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
626         SILC_LOG_DEBUG(("Finding clients by public key attribute"));
627
628         if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
629           continue;
630
631         if (!silc_pkcs_public_key_decode(pk.data, pk.data_len,
632                                          &publickey)) {
633           silc_free(pk.type);
634           silc_free(pk.data);
635           continue;
636         }
637
638         /* If no clients were set on calling this function, we
639            just search for clients, otherwise we try to limit
640            the clients */
641         if (no_clients) {
642           SilcServerPublicKeyUserStruct usercontext;
643
644           usercontext.clients = clients;
645           usercontext.clients_count = clients_count;
646           usercontext.found = FALSE;
647
648           silc_hash_table_find_foreach(server->pk_hash, publickey,
649                                        silc_server_public_key_hash_foreach,
650                                        &usercontext);
651
652           if (usercontext.found == TRUE) 
653             found = TRUE;
654         } else {
655           for (i = 0; i < *clients_count; i++) {
656             entry = (*clients)[i];
657
658             if (!entry->data.public_key)
659               continue;
660
661             if (!silc_hash_table_find_by_context(server->pk_hash, publickey,
662                                                  entry, NULL))
663               (*clients)[i] = NULL;
664             else
665               found = TRUE;
666           }
667         }
668         silc_free(pk.type);
669         silc_free(pk.data);
670         silc_pkcs_public_key_free(publickey);
671         break;
672     }
673   }
674
675   if (!found && !query->nickname && !query->ids) {
676     silc_server_query_send_error(server, query,
677                                  SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
678   }
679 }
680
681 /* Processes the parsed query.  This does the actual finding of the
682    queried information and prepares for sending reply to the original
683    sender of the query command. */
684
685 void silc_server_query_process(SilcServer server, SilcServerQuery query,
686                                bool resolve)
687 {
688   SilcServerCommandContext cmd = query->cmd;
689   bool check_global = FALSE;
690   void *entry;
691   SilcClientEntry *clients = NULL, client_entry;
692   SilcChannelEntry *channels = NULL;
693   SilcServerEntry *servers = NULL;
694   SilcUInt32 clients_count = 0, channels_count = 0, servers_count = 0;
695   int i;
696
697   SILC_LOG_DEBUG(("Processing %s query",
698                   silc_get_command_name(query->querycmd)));
699
700   /* Check global lists if query is coming from client or we are not
701      normal server (we know global information). */
702   if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
703     check_global = TRUE;
704   else if (server->server_type != SILC_SERVER)
705     check_global = TRUE;
706
707   if (query->nickname) {
708     /* Get all clients matching nickname from local list */
709     if (!silc_idlist_get_clients_by_hash(server->local_list,
710                                          query->nickname, server->md5hash,
711                                          &clients, &clients_count))
712       silc_idlist_get_clients_by_nickname(server->local_list,
713                                           query->nickname,
714                                           query->nick_server,
715                                           &clients, &clients_count);
716
717     /* Check global list as well */
718     if (check_global) {
719       if (!silc_idlist_get_clients_by_hash(server->global_list,
720                                            query->nickname, server->md5hash,
721                                            &clients, &clients_count))
722         silc_idlist_get_clients_by_nickname(server->global_list,
723                                             query->nickname,
724                                             query->nick_server,
725                                             &clients, &clients_count);
726     }
727
728     if (!clients)
729       silc_server_query_add_error(server, query, TRUE, 1,
730                                   SILC_STATUS_ERR_NO_SUCH_NICK);
731   }
732
733   if (query->server_name) {
734     /* Find server by name */
735     entry = silc_idlist_find_server_by_name(server->local_list,
736                                             query->server_name, TRUE, NULL);
737     if (!entry && check_global)
738       entry = silc_idlist_find_server_by_name(server->global_list,
739                                               query->server_name, TRUE, NULL);
740     if (entry) {
741       servers = silc_realloc(servers, sizeof(*servers) * (servers_count + 1));
742       servers[servers_count++] = (SilcServerEntry)entry;
743     }
744
745     if (!servers)
746       silc_server_query_add_error(server, query, TRUE, 2,
747                                   SILC_STATUS_ERR_NO_SUCH_SERVER);
748   }
749
750   if (query->channel_name) {
751     /* Find channel by name */
752     entry = silc_idlist_find_channel_by_name(server->local_list,
753                                              query->channel_name, NULL);
754     if (!entry && check_global)
755       entry = silc_idlist_find_channel_by_name(server->global_list,
756                                                query->channel_name, NULL);
757     if (entry) {
758       channels = silc_realloc(channels, sizeof(*channels) *
759                               (channels_count + 1));
760       channels[channels_count++] = (SilcChannelEntry)entry;
761     }
762
763     if (!channels)
764       silc_server_query_add_error(server, query, TRUE, 3,
765                                   SILC_STATUS_ERR_NO_SUCH_CHANNEL);
766   }
767
768   if (query->ids_count) {
769     /* Find entries by the queried IDs */
770     for (i = 0; i < query->ids_count; i++) {
771       void *id = query->ids[i].id;
772       if (!id)
773         continue;
774
775       switch (query->ids[i].id_type) {
776
777       case SILC_ID_CLIENT:
778         /* Get client entry */
779         entry = silc_idlist_find_client_by_id(server->local_list,
780                                               id, TRUE, NULL);
781         if (!entry && check_global)
782           entry = silc_idlist_find_client_by_id(server->global_list,
783                                                 id, TRUE, NULL);
784         if (!entry) {
785           silc_server_query_add_error(server, query, FALSE, i,
786                                       SILC_STATUS_ERR_NO_SUCH_CLIENT_ID);
787           continue;
788         }
789
790         clients = silc_realloc(clients, sizeof(*clients) *
791                                (clients_count + 1));
792         clients[clients_count++] = (SilcClientEntry)entry;
793         break;
794
795       case SILC_ID_SERVER:
796         /* Get server entry */
797         entry = silc_idlist_find_server_by_id(server->local_list,
798                                               id, TRUE, NULL);
799         if (!entry && check_global)
800           entry = silc_idlist_find_server_by_id(server->global_list,
801                                                 id, TRUE, NULL);
802         if (!entry) {
803           silc_server_query_add_error(server, query, FALSE, i,
804                                       SILC_STATUS_ERR_NO_SUCH_SERVER_ID);
805           continue;
806         }
807
808         servers = silc_realloc(servers, sizeof(*servers) *
809                                (servers_count + 1));
810         servers[servers_count++] = (SilcServerEntry)entry;
811         break;
812
813       case SILC_ID_CHANNEL:
814         /* Get channel entry */
815         entry = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
816         if (!entry && check_global)
817           entry = silc_idlist_find_channel_by_id(server->global_list, id,
818                                                  NULL);
819         if (!entry) {
820           silc_server_query_add_error(server, query, FALSE, i,
821                                       SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID);
822           continue;
823         }
824
825         channels = silc_realloc(channels, sizeof(*channels) *
826                                 (channels_count + 1));
827         channels[channels_count++] = (SilcChannelEntry)entry;
828         break;
829
830       default:
831         break;
832       }
833     }
834   }
835
836   /* Check the attributes to narrow down the search by using them. */
837   if (query->attrs)
838     silc_server_query_check_attributes(server, query, &clients,
839                                        &clients_count);
840
841   SILC_LOG_DEBUG(("Querying %d clients", clients_count));
842   SILC_LOG_DEBUG(("Querying %d servers", servers_count));
843   SILC_LOG_DEBUG(("Querying %d channels", channels_count));
844
845   /* If nothing was found, then just send the errors */
846   if (!clients && !channels && !servers) {
847     silc_server_query_send_reply(server, query, NULL, 0, NULL, 0, NULL, 0);
848     return;
849   }
850
851   /* If caller does not want us to resolve anything (has resolved already)
852      then just continue with sending the reply */
853   if (!resolve) {
854     silc_server_query_send_reply(server, query, clients, clients_count,
855                                  servers, servers_count, channels,
856                                  channels_count);
857     silc_free(clients);
858     silc_free(servers);
859     silc_free(channels);
860     return;
861   }
862
863   /* Now process all found information and if necessary do some more
864      resolving. */
865   switch (query->querycmd) {
866
867   case SILC_COMMAND_WHOIS:
868     for (i = 0; i < clients_count; i++) {
869       client_entry = clients[i];
870
871       /* Check if cannot query this anyway, so take next one */
872       if (!client_entry ||
873           !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
874         continue;
875
876       /* If Requested Attributes is set then we always resolve the client
877          information, if not then check whether the entry is complete or not
878          and decide whether we need to resolve or not. */
879       if (!query->attrs) {
880
881         /* Even if nickname and stuff are present, we may need to resolve
882            the entry */
883         if (client_entry->nickname && client_entry->username &&
884             client_entry->userinfo) {
885           /* Check if cannot query this anyway, so take next one */
886           if (!client_entry->router)
887             continue;
888
889           /* If we are router, client is local to us, or client is on channel
890              we do not need to resolve the client information. */
891           if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
892               || silc_hash_table_count(client_entry->channels) ||
893               query->resolved)
894             continue;
895         }
896       }
897
898       /* Remove the NOATTR status periodically */
899       if (client_entry->data.status & SILC_IDLIST_STATUS_NOATTR &&
900           client_entry->updated + 600 < time(NULL))
901         client_entry->data.status &= ~SILC_IDLIST_STATUS_NOATTR;
902
903       /* When requested attributes is present and local client is detached
904          we cannot send the command to the client, we'll reply on behalf of
905          the client instead. */
906       if (query->attrs && SILC_IS_LOCAL(client_entry) &&
907           (client_entry->mode & SILC_UMODE_DETACHED ||
908            client_entry->data.status & SILC_IDLIST_STATUS_NOATTR))
909         continue;
910
911       /* If attributes are present in query, and in the entry and we have
912          done resolvings already we don't need to resolve anymore */
913       if (query->resolved && query->attrs && client_entry->attrs)
914         continue;
915
916       /* Resolve the detailed client information. If client is local we
917          know that attributes were present and we will resolve directly
918          from the client. Otherwise resolve from client's owner. */
919       silc_server_query_resolve(server, query,
920                                 (SILC_IS_LOCAL(client_entry) ?
921                                  client_entry->connection :
922                                  client_entry->router->connection),
923                                 client_entry);
924     }
925     break;
926
927   case SILC_COMMAND_WHOWAS:
928     for (i = 0; i < clients_count; i++) {
929       client_entry = clients[i];
930
931       /* Check if cannot query this anyway, so take next one */
932       if (!client_entry || !client_entry->router ||
933           client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED)
934         continue;
935
936       /* If both nickname and username are present no resolving is needed */
937       if (client_entry->nickname && client_entry->username)
938         continue;
939
940       /* Resolve the detailed client information */
941       silc_server_query_resolve(server, query,
942                                 client_entry->router->connection,
943                                 client_entry);
944     }
945     break;
946
947   case SILC_COMMAND_IDENTIFY:
948     for (i = 0; i < clients_count; i++) {
949       client_entry = clients[i];
950
951       /* Check if cannot query this anyway, so take next one */
952       if (!client_entry || !client_entry->router ||
953           !(client_entry->data.status & SILC_IDLIST_STATUS_REGISTERED))
954         continue;
955
956       /* Even if nickname is present, we may need to resolve the entry */
957       if (client_entry->nickname) {
958
959         /* If we are router, client is local to us, or client is on channel
960            we do not need to resolve the client information. */
961         if (server->server_type != SILC_SERVER || SILC_IS_LOCAL(client_entry)
962             || silc_hash_table_count(client_entry->channels) ||
963             query->resolved)
964           continue;
965       }
966
967       /* Resolve the detailed client information */
968       silc_server_query_resolve(server, query,
969                                 client_entry->router->connection,
970                                 client_entry);
971     }
972     break;
973   }
974
975   if (!query->queries_count)
976     /* If we didn't have to do any resolving, continue with sending the
977        command reply to the original sender. */
978     silc_server_query_send_reply(server, query, clients, clients_count,
979                                  servers, servers_count, channels,
980                                  channels_count);
981   else
982     /* Now actually send the resolvings we gathered earlier */
983     silc_server_query_resolve(server, query, NULL, NULL);
984
985   silc_free(clients);
986   silc_free(servers);
987   silc_free(channels);
988 }
989
990 /* Resolve the detailed information for the `client_entry'.  Only client
991    information needs to be resolved for being incomplete.  Each incomplete
992    client entry calls this function to do the resolving. */
993
994 void silc_server_query_resolve(SilcServer server, SilcServerQuery query,
995                                SilcSocketConnection sock,
996                                SilcClientEntry client_entry)
997 {
998   SilcServerCommandContext cmd = query->cmd;
999   SilcServerQueryList r = NULL;
1000   SilcBuffer idp;
1001   unsigned char *tmp;
1002   SilcUInt32 len;
1003   SilcUInt16 ident;
1004   int i;
1005
1006   if (!sock && client_entry)
1007     return;
1008
1009   /* If arguments are NULL we will now actually send the resolvings
1010      that earlier has been gathered by calling this function. */
1011   if (!sock && !client_entry) {
1012     SilcBuffer res_cmd;
1013
1014     SILC_LOG_DEBUG(("Sending the resolvings"));
1015
1016     /* WHOWAS resolving has been done at the same time this function
1017        was called to add the resolving for WHOWAS, so just return. */
1018     if (query->querycmd == SILC_COMMAND_WHOWAS)
1019       return;
1020
1021     for (i = 0; i < query->querylist_count; i++) {
1022       r = &query->querylist[i];
1023
1024       /* If Requested Attributes were present put them to this resolving */
1025       if (query->attrs && query->querycmd == SILC_COMMAND_WHOIS) {
1026         len = r->argc + 1;
1027         r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1028         r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1029         r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1030
1031         tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
1032         if (tmp)
1033           r->arg[r->argc] = silc_memdup(tmp, len);
1034         r->arg_lens[r->argc] = len;
1035         r->arg_types[r->argc] = 3;
1036         r->argc++;
1037       }
1038
1039       /* Send WHOIS command */
1040       res_cmd = silc_command_payload_encode(SILC_COMMAND_WHOIS,
1041                                             r->argc, r->arg, r->arg_lens,
1042                                             r->arg_types, r->ident);
1043       silc_server_packet_send(server, r->sock, SILC_PACKET_COMMAND, 0,
1044                               res_cmd->data, res_cmd->len, FALSE);
1045       silc_buffer_free(res_cmd);
1046
1047       /* Reprocess this packet after received reply */
1048       if (silc_server_command_pending_timed(server, SILC_COMMAND_WHOIS,
1049                                             r->ident,
1050                                             silc_server_query_resolve_reply,
1051                                             query, r->timeout))
1052         query->queries_left++;
1053     }
1054
1055     /* Cleanup this temporary context */
1056     for (i = 0; i < query->querylist_count; i++) {
1057       int k;
1058       for (k = 0; k < query->querylist[i].argc; k++)
1059         silc_free(query->querylist[i].arg[k]);
1060       silc_free(query->querylist[i].arg);
1061       silc_free(query->querylist[i].arg_lens);
1062       silc_free(query->querylist[i].arg_types);
1063     }
1064     silc_free(query->querylist);
1065     query->querylist = NULL;
1066     query->querylist_count = 0;
1067     return;
1068   }
1069
1070   SILC_LOG_DEBUG(("Resolving client information"));
1071
1072   if (client_entry->data.status & SILC_IDLIST_STATUS_RESOLVING) {
1073     /* The entry is being resolved by some other external query already.
1074        Attach to that query instead of resolving again. */
1075     ident = client_entry->resolve_cmd_ident;
1076     if (silc_server_command_pending(server, SILC_COMMAND_NONE, ident,
1077                                     silc_server_query_resolve_reply, query))
1078       query->queries_left++;
1079   } else {
1080     /* This entry will be resolved */
1081     ident = ++server->cmd_ident;
1082
1083     switch (query->querycmd) {
1084
1085     case SILC_COMMAND_WHOIS:
1086     case SILC_COMMAND_IDENTIFY:
1087       /* Take existing query context if exist for this connection */
1088       for (i = 0; i < query->querylist_count; i++)
1089         if (query->querylist[i].sock == sock) {
1090           r = &query->querylist[i];
1091           break;
1092         }
1093
1094       if (!r) {
1095         /* Allocate new temp query list context */
1096         query->querylist = silc_realloc(query->querylist,
1097                                         sizeof(*query->querylist) *
1098                                         (query->querylist_count + 1));
1099         r = &query->querylist[query->querylist_count];
1100         query->querylist_count++;
1101         memset(r, 0, sizeof(*r));
1102         r->sock = sock;
1103         r->ident = ident;
1104         if (SILC_IS_LOCAL(client_entry))
1105           r->timeout = 3;
1106       }
1107
1108       len = r->argc + 1;
1109       r->arg = silc_realloc(r->arg, sizeof(*r->arg) * len);
1110       r->arg_lens = silc_realloc(r->arg_lens, sizeof(*r->arg_lens) * len);
1111       r->arg_types = silc_realloc(r->arg_types, sizeof(*r->arg_types) * len);
1112
1113       /* Add the client entry to be resolved */
1114       idp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
1115       r->arg[r->argc] = silc_memdup(idp->data, idp->len);
1116       r->arg_lens[r->argc] = idp->len;
1117       r->arg_types[r->argc] = r->argc + 4;
1118       r->argc++;
1119       silc_buffer_free(idp);
1120
1121       break;
1122
1123     case SILC_COMMAND_WHOWAS:
1124       /* We must send WHOWAS command since it's the only the way of
1125          resolving clients that are not present in the network anymore. */
1126       silc_server_send_command(server, sock, query->querycmd, ident, 1,
1127                                1, query->nickname, strlen(query->nickname));
1128       if (silc_server_command_pending(server, query->querycmd, ident,
1129                                       silc_server_query_resolve_reply, query))
1130         query->queries_left++;
1131       break;
1132     }
1133   }
1134
1135   /* Mark the entry as being resolved */
1136   client_entry->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1137   client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1138   client_entry->resolve_cmd_ident = ident;
1139   client_entry->updated = time(NULL);
1140
1141   /* Save the queried ID, which we will reprocess after we get this and
1142      all other queries back. */
1143   query->queries = silc_realloc(query->queries, sizeof(*query->queries) *
1144                                 (query->queries_count + 1));
1145   if (query->queries) {
1146     i = query->queries_count;
1147     query->queries[i].id = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1148     query->queries[i].id_type = SILC_ID_CLIENT;
1149     query->queries[i].ident = ident;
1150     query->queries_count++;
1151   }
1152 }
1153
1154 /* Reply callback called after one resolving has been completed.  If
1155    all resolvings has been received then we will continue with sending
1156    the command reply to the original sender of the query. */
1157
1158 void silc_server_query_resolve_reply(void *context, void *reply)
1159 {
1160   SilcServerQuery query = context;
1161   SilcServer server = query->cmd->server;
1162   SilcServerCommandReplyContext cmdr = reply;
1163   SilcUInt16 ident = cmdr->ident;
1164   SilcStatus error = SILC_STATUS_OK;
1165   SilcServerQueryID id = NULL;
1166   SilcClientEntry client_entry;
1167   int i;
1168
1169   /* One less query left */
1170   query->queries_left--;
1171
1172   silc_command_get_status(cmdr->payload, NULL, &error);
1173   SILC_LOG_DEBUG(("Received reply to resolving (%d left) (status=%d)",
1174                   query->queries_left, error));
1175
1176   /* If no error then skip to other stuff */
1177   if (error == SILC_STATUS_OK)
1178     goto out;
1179
1180   /* Error occurred during resolving */
1181
1182   /* Find the resolved client ID */
1183   for (i = 0; i < query->queries_count; i++) {
1184     if (query->queries[i].ident != ident)
1185       continue;
1186
1187     id = &query->queries[i];
1188
1189     if (error == SILC_STATUS_ERR_TIMEDOUT) {
1190
1191       /* If timeout occurred for local entry when resolving attributes
1192          mark that this client doesn't support attributes in WHOIS. This
1193          assures we won't send the request again to the client. */
1194       if (query->querycmd == SILC_COMMAND_WHOIS && query->attrs) {
1195         client_entry = silc_idlist_find_client_by_id(server->local_list,
1196                                                      id->id, TRUE, NULL);
1197         SILC_LOG_DEBUG(("Client %s does not support Requested Attributes",
1198                         silc_id_render(id->id, SILC_ID_CLIENT)));
1199         if (client_entry && SILC_IS_LOCAL(client_entry)) {
1200           client_entry->data.status |= SILC_IDLIST_STATUS_NOATTR;
1201           client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1202           continue;
1203         }
1204       }
1205
1206       /* Remove the RESOLVING status from the client entry */
1207       if (query->querycmd != SILC_COMMAND_WHOWAS) {
1208         client_entry = silc_idlist_find_client_by_id(server->local_list,
1209                                                      id->id, TRUE, NULL);
1210         if (!client_entry)
1211           client_entry = silc_idlist_find_client_by_id(server->global_list,
1212                                                        id->id, TRUE, NULL);
1213         if (client_entry)
1214           client_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
1215       }
1216     }
1217   }
1218
1219  out:
1220
1221   /* If there are queries left then wait for them */
1222   if (query->queries_left)
1223     return;
1224
1225   SILC_LOG_DEBUG(("Reprocess the query"));
1226
1227   /* We have received all queries.  Now re-search all information required
1228      to complete this query.  Reason we cannot save the values found in
1229      the first search is that SilcClientEntry, SilcServerEntry and
1230      SilcChannelEntry pointers may become invalid while we were waiting
1231      for these resolvings. */
1232   silc_server_query_process(server, query, FALSE);
1233 }
1234
1235 /* Send the reply to the original query.  If arguments are NULL then this
1236    sends only the errors that has occurred during the processing of the
1237    query.  This sends the errors always after sending all the found
1238    information.  The query is over after this function returns and the
1239    `query' will become invalid.  This is called only after all informations
1240    has been resolved.  This means that if something is not found or is
1241    incomplete in this function we were unable to resolve the information
1242    or it does not exist at all. */
1243
1244 void silc_server_query_send_reply(SilcServer server,
1245                                   SilcServerQuery query,
1246                                   SilcClientEntry *clients,
1247                                   SilcUInt32 clients_count,
1248                                   SilcServerEntry *servers,
1249                                   SilcUInt32 servers_count,
1250                                   SilcChannelEntry *channels,
1251                                   SilcUInt32 channels_count)
1252 {
1253   SilcServerCommandContext cmd = query->cmd;
1254   SilcUInt16 ident = silc_command_get_ident(cmd->payload);
1255   SilcStatus status;
1256   unsigned char *tmp;
1257   SilcUInt32 len;
1258   SilcBuffer idp;
1259   int i, k, valid_count;
1260   char nh[256], uh[256];
1261   bool sent_reply = FALSE;
1262
1263   SILC_LOG_DEBUG(("Sending reply to query"));
1264   SILC_LOG_DEBUG(("Sending %d clients", clients_count));
1265   SILC_LOG_DEBUG(("Sending %d servers", servers_count));
1266   SILC_LOG_DEBUG(("Sending %d channels", channels_count));
1267   SILC_LOG_DEBUG(("Sending %d errors", query->errors_count));
1268
1269   status = SILC_STATUS_OK;
1270
1271   /* Send clients */
1272   if (clients_count) {
1273     SilcClientEntry entry;
1274     SilcSocketConnection hsock;
1275
1276     /* Mark all invalid entries */
1277     for (i = 0, valid_count = 0; i < clients_count; i++) {
1278       entry = clients[i];
1279       if (!entry)
1280         continue;
1281
1282       switch (query->querycmd) {
1283       case SILC_COMMAND_WHOIS:
1284         if (!entry->nickname || !entry->username || !entry->userinfo ||
1285             !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1286           /* When querying by ID, every "unfound" entry must cause error */
1287           if (query->ids)
1288             silc_server_query_add_error_id(server, query,
1289                                            SILC_STATUS_ERR_TIMEDOUT,
1290                                            entry->id, SILC_ID_CLIENT);
1291           clients[i] = NULL;
1292           continue;
1293         }
1294         break;
1295
1296       case SILC_COMMAND_IDENTIFY:
1297         if (!entry->nickname ||
1298             !(entry->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
1299           /* When querying by ID, every "unfound" entry must cause error */
1300           if (query->ids)
1301             silc_server_query_add_error_id(server, query,
1302                                            SILC_STATUS_ERR_TIMEDOUT,
1303                                            entry->id, SILC_ID_CLIENT);
1304           clients[i] = NULL;
1305           continue;
1306         }
1307         break;
1308
1309       case SILC_COMMAND_WHOWAS:
1310         if (!entry->nickname || !entry->username ||
1311             entry->data.status & SILC_IDLIST_STATUS_REGISTERED) {
1312           clients[i] = NULL;
1313           continue;
1314         }
1315         break;
1316       }
1317       valid_count++;
1318     }
1319
1320     /* Start processing found clients */
1321     status = SILC_STATUS_OK;
1322     if (valid_count > 1)
1323       status = SILC_STATUS_LIST_START;
1324
1325     /* Now do the sending of valid entries */
1326     k = 0;
1327     for (i = 0; i < clients_count && valid_count; i++) {
1328       entry = clients[i];
1329       if (!entry)
1330         continue;
1331
1332       if (k >= 1)
1333         status = SILC_STATUS_LIST_ITEM;
1334       if (valid_count > 1 && k == valid_count - 1
1335           && !servers_count && !channels_count && !query->errors_count)
1336         status = SILC_STATUS_LIST_END;
1337       if (query->reply_count && k - 1 == query->reply_count)
1338         status = SILC_STATUS_LIST_END;
1339
1340       SILC_LOG_DEBUG(("%s: client %s",
1341                       (status == SILC_STATUS_OK ?         "   OK" :
1342                        status == SILC_STATUS_LIST_START ? "START" :
1343                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1344                        status == SILC_STATUS_LIST_END  ?  "  END" :
1345                        "      : "), entry->nickname));
1346
1347       idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
1348       memset(uh, 0, sizeof(uh));
1349       memset(nh, 0, sizeof(nh));
1350
1351       silc_strncat(nh, sizeof(nh), entry->nickname, strlen(entry->nickname));
1352       if (!strchr(entry->nickname, '@')) {
1353         silc_strncat(nh, sizeof(nh), "@", 1);
1354         if (entry->servername) {
1355           silc_strncat(nh, sizeof(nh), entry->servername,
1356                        strlen(entry->servername));
1357         } else {
1358           len = entry->router ? strlen(entry->router->server_name) :
1359             strlen(server->server_name);
1360           silc_strncat(nh, sizeof(nh), entry->router ?
1361                        entry->router->server_name :
1362                        server->server_name, len);
1363         }
1364       }
1365
1366       switch (query->querycmd) {
1367
1368       case SILC_COMMAND_WHOIS:
1369         {
1370           unsigned char idle[4], mode[4];
1371           unsigned char *fingerprint, fempty[20], *attrs = NULL;
1372           SilcBuffer channels, umode_list = NULL, tmpattrs = NULL;
1373
1374           memset(fempty, 0, sizeof(fempty));
1375           memset(idle, 0, sizeof(idle));
1376           silc_strncat(uh, sizeof(uh), entry->username,
1377                        strlen(entry->username));
1378           if (!strchr(entry->username, '@') && entry->connection) {
1379             hsock = entry->connection;
1380             silc_strncat(uh, sizeof(uh), "@", 1);
1381             len = strlen(hsock->hostname);
1382             silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1383           }
1384
1385           if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
1386             channels =
1387               silc_server_get_client_channel_list(server, entry, FALSE,
1388                                                   FALSE, &umode_list);
1389           else
1390             channels =
1391               silc_server_get_client_channel_list(server, entry, TRUE,
1392                                                   TRUE, &umode_list);
1393
1394           if (memcmp(entry->data.fingerprint, fempty, sizeof(fempty)))
1395             fingerprint = entry->data.fingerprint;
1396           else
1397             fingerprint = NULL;
1398
1399           SILC_PUT32_MSB(entry->mode, mode);
1400           if (entry->connection)
1401             SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
1402
1403           /* If Requested Attribute were present, and we do not have the
1404              attributes we will reply to them on behalf of the client. */
1405           len = 0;
1406           if (query->attrs) {
1407             if (!entry->attrs && SILC_IS_LOCAL(entry)) {
1408               tmpattrs = silc_server_query_reply_attrs(server, query, entry);
1409               entry->attrs = silc_buffer_steal(tmpattrs, &len);
1410               entry->attrs_len = len;
1411               silc_buffer_free(tmpattrs);
1412             }
1413             attrs = entry->attrs;
1414             len = entry->attrs_len;
1415           }
1416
1417           /* Send command reply */
1418           silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1419                                          status, 0, ident, 10,
1420                                          2, idp->data, idp->len,
1421                                          3, nh, strlen(nh),
1422                                          4, uh, strlen(uh),
1423                                          5, entry->userinfo,
1424                                          strlen(entry->userinfo),
1425                                          6, channels ? channels->data : NULL,
1426                                          channels ? channels->len : 0,
1427                                          7, mode, 4,
1428                                          8, idle, 4,
1429                                          9, fingerprint,
1430                                          fingerprint ? 20 : 0,
1431                                          10, umode_list ? umode_list->data :
1432                                          NULL, umode_list ? umode_list->len :
1433                                          0, 11, attrs, len);
1434
1435           sent_reply = TRUE;
1436
1437           /* For now we always delete Requested Attributes, unless the client
1438              is detached, in which case we don't want to reconstruct the
1439              same data everytime */
1440           if (!(entry->mode & SILC_UMODE_DETACHED) &&
1441               !(entry->data.status & SILC_IDLIST_STATUS_NOATTR)) {
1442             silc_free(entry->attrs);
1443             entry->attrs = NULL;
1444           }
1445
1446           if (channels)
1447             silc_buffer_free(channels);
1448           if (umode_list) {
1449             silc_buffer_free(umode_list);
1450             umode_list = NULL;
1451           }
1452         }
1453         break;
1454
1455       case SILC_COMMAND_IDENTIFY:
1456         if (!entry->username) {
1457           silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1458                                          status, 0, ident, 2,
1459                                          2, idp->data, idp->len,
1460                                          3, nh, strlen(nh));
1461           sent_reply = TRUE;
1462         } else {
1463           silc_strncat(uh, sizeof(uh), entry->username,
1464                        strlen(entry->username));
1465           if (!strchr(entry->username, '@') && entry->connection) {
1466             hsock = entry->connection;
1467             silc_strncat(uh, sizeof(uh), "@", 1);
1468             len = strlen(hsock->hostname);
1469             silc_strncat(uh, sizeof(uh), hsock->hostname, len);
1470           }
1471
1472           silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1473                                          status, 0, ident, 3,
1474                                          2, idp->data, idp->len,
1475                                          3, nh, strlen(nh),
1476                                          4, uh, strlen(uh));
1477           sent_reply = TRUE;
1478         }
1479         break;
1480
1481       case SILC_COMMAND_WHOWAS:
1482         silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1483         if (!strchr(entry->username, '@'))
1484           silc_strncat(uh, sizeof(uh), "@*private*", 10);
1485
1486         /* Send command reply */
1487         silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1488                                        status, 0, ident, 4,
1489                                        2, idp->data, idp->len,
1490                                        3, nh, strlen(nh),
1491                                        4, uh, strlen(uh),
1492                                        5, entry->userinfo,
1493                                        entry->userinfo ?
1494                                        strlen(entry->userinfo) : 0);
1495         sent_reply = TRUE;
1496         break;
1497       }
1498
1499       silc_buffer_free(idp);
1500
1501       if (status == SILC_STATUS_LIST_END)
1502         break;
1503       k++;
1504     }
1505
1506     if (k == 0) {
1507       /* Not one valid entry was found, send error.  If nickname was used
1508          in query send error based on that, otherwise the query->errors
1509          already includes proper errors. */
1510       if (query->nickname || (!query->nickname && !query->ids && query->attrs))
1511         silc_server_query_add_error(server, query, TRUE, 1,
1512                                     SILC_STATUS_ERR_NO_SUCH_NICK);
1513     }
1514   }
1515
1516   /* Send servers */
1517   if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1518     SilcServerEntry entry;
1519
1520     if (status == SILC_STATUS_OK && servers_count > 1)
1521       status = SILC_STATUS_LIST_START;
1522
1523     k = 0;
1524     for (i = 0; i < servers_count; i++) {
1525       entry = servers[i];
1526
1527       if (k >= 1)
1528         status = SILC_STATUS_LIST_ITEM;
1529       if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1530           !query->errors_count)
1531         status = SILC_STATUS_LIST_END;
1532       if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1533           !query->errors_count)
1534         status = SILC_STATUS_LIST_END;
1535       if (query->reply_count && k - 1 == query->reply_count)
1536         status = SILC_STATUS_LIST_END;
1537
1538       SILC_LOG_DEBUG(("%s: server %s",
1539                       (status == SILC_STATUS_OK ?         "   OK" :
1540                        status == SILC_STATUS_LIST_START ? "START" :
1541                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1542                        status == SILC_STATUS_LIST_END  ?  "  END" :
1543                        "      : "),
1544                       entry->server_name ? entry->server_name : ""));
1545
1546       /* Send command reply */
1547       idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1548       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1549                                      status, 0, ident, 2,
1550                                      2, idp->data, idp->len,
1551                                      3, entry->server_name,
1552                                      entry->server_name ?
1553                                      strlen(entry->server_name) : 0);
1554       silc_buffer_free(idp);
1555       sent_reply = TRUE;
1556
1557       if (status == SILC_STATUS_LIST_END)
1558         break;
1559       k++;
1560     }
1561   }
1562
1563   /* Send channels */
1564   if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1565     SilcChannelEntry entry;
1566
1567     if (status == SILC_STATUS_OK && channels_count > 1)
1568       status = SILC_STATUS_LIST_START;
1569
1570     k = 0;
1571     for (i = 0; i < channels_count; i++) {
1572       entry = channels[i];
1573
1574       if (k >= 1)
1575         status = SILC_STATUS_LIST_ITEM;
1576       if (channels_count == 1 && status != SILC_STATUS_OK &&
1577           !query->errors_count)
1578         status = SILC_STATUS_LIST_END;
1579       if (channels_count > 1 && k == channels_count - 1 &&
1580           !query->errors_count)
1581         status = SILC_STATUS_LIST_END;
1582       if (query->reply_count && k - 1 == query->reply_count)
1583         status = SILC_STATUS_LIST_END;
1584
1585       SILC_LOG_DEBUG(("%s: channel %s",
1586                       (status == SILC_STATUS_OK ?         "   OK" :
1587                        status == SILC_STATUS_LIST_START ? "START" :
1588                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1589                        status == SILC_STATUS_LIST_END  ?  "  END" :
1590                        "      : "),
1591                       entry->channel_name ? entry->channel_name : ""));
1592
1593       /* Send command reply */
1594       idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1595       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1596                                      status, 0, ident, 2,
1597                                      2, idp->data, idp->len,
1598                                      3, entry->channel_name,
1599                                      entry->channel_name ?
1600                                      strlen(entry->channel_name) : 0);
1601       silc_buffer_free(idp);
1602       sent_reply = TRUE;
1603
1604       if (status == SILC_STATUS_LIST_END)
1605         break;
1606       k++;
1607     }
1608   }
1609
1610   /* Send errors */
1611   if (query->errors_count) {
1612     int type;
1613
1614     if (status == SILC_STATUS_OK && query->errors_count > 1)
1615       status = SILC_STATUS_LIST_START;
1616
1617     k = 0;
1618     for (i = 0; i < query->errors_count; i++) {
1619       idp = NULL;
1620
1621       /* Take error argument */
1622       if (query->errors[i].from_cmd) {
1623         len = 0;
1624         tmp = silc_argument_get_arg_type(cmd->args,
1625                                          query->errors[i].index, &len);
1626         if (query->errors[i].index == 1)
1627           type = 3;                 /* Nickname */
1628         else
1629           type = 2;                 /* ID */
1630       } else if (!query->errors[i].id) {
1631         idp =
1632           silc_id_payload_encode(query->ids[query->errors[i].index].id,
1633                                  query->ids[query->errors[k].index].id_type);
1634         tmp = idp->data;
1635         len = idp->len;
1636         type = 2;
1637       } else {
1638         idp = silc_id_payload_encode(query->errors[i].id,
1639                                      query->errors[k].id_type);
1640         tmp = idp->data;
1641         len = idp->len;
1642         type = 2;
1643       }
1644
1645       if (k >= 1)
1646         status = SILC_STATUS_LIST_ITEM;
1647       if (query->errors_count == 1 && status != SILC_STATUS_OK)
1648         status = SILC_STATUS_LIST_END;
1649       if (query->errors_count > 1 && k == query->errors_count - 1)
1650         status = SILC_STATUS_LIST_END;
1651       if (query->reply_count && k - 1 == query->reply_count)
1652         status = SILC_STATUS_LIST_END;
1653
1654       SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1655                       (status == SILC_STATUS_OK ?         "   OK" :
1656                        status == SILC_STATUS_LIST_START ? "START" :
1657                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1658                        status == SILC_STATUS_LIST_END  ?  "  END" :
1659                        "      : "),
1660                       silc_get_status_message(query->errors[i].error),
1661                       query->errors[i].error));
1662
1663       /* Send error */
1664       silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1665                                      (status == SILC_STATUS_OK ?
1666                                       query->errors[i].error : status),
1667                                      (status == SILC_STATUS_OK ?
1668                                       0 : query->errors[i].error), ident, 1,
1669                                      type, tmp, len);
1670       silc_buffer_free(idp);
1671       sent_reply = TRUE;
1672
1673       if (status == SILC_STATUS_LIST_END)
1674         break;
1675       k++;
1676     }
1677   }
1678
1679   if (!sent_reply)
1680     SILC_LOG_ERROR(("BUG: Query did not send anything"));
1681
1682   /* Cleanup */
1683   silc_server_query_free(query);
1684 }
1685
1686 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1687    of the client since we were unable to resolve them from the client.
1688    Either client does not support Requested Attributes or isn't replying
1689    to them like it should. */
1690
1691 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1692                                          SilcServerQuery query,
1693                                          SilcClientEntry client_entry)
1694 {
1695   SilcBuffer buffer = NULL;
1696   SilcAttribute attribute;
1697   SilcAttributePayload attr;
1698   SilcAttributeObjPk pk;
1699   SilcAttributeObjService service;
1700   unsigned char *tmp;
1701   unsigned char sign[2048 + 1];
1702   SilcUInt32 sign_len;
1703
1704   SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1705
1706   /* Go through all requested attributes */
1707   silc_dlist_start(query->attrs);
1708   while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1709     attribute = silc_attribute_get_attribute(attr);
1710     switch (attribute) {
1711
1712     case SILC_ATTRIBUTE_SERVICE:
1713       /* Put SERVICE.  Put only SILC service. */
1714       memset(&service, 0, sizeof(service));
1715       service.port = (server->config->server_info->primary ?
1716                       server->config->server_info->primary->port : SILC_PORT);
1717       silc_strncat(service.address, sizeof(service.address),
1718                    server->server_name, strlen(server->server_name));
1719       service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1720       if (client_entry->connection)
1721         service.idle = time(NULL) - client_entry->data.last_receive;
1722       buffer = silc_attribute_payload_encode(buffer, attribute,
1723                                              SILC_ATTRIBUTE_FLAG_VALID,
1724                                              &service, sizeof(service));
1725       if (!buffer)
1726         return NULL;
1727       break;
1728
1729     case SILC_ATTRIBUTE_STATUS_MOOD:
1730       /* Put STATUS_MOOD */
1731       buffer = silc_attribute_payload_encode(buffer, attribute,
1732                                              SILC_ATTRIBUTE_FLAG_VALID,
1733                                              (void *)
1734                                              SILC_ATTRIBUTE_MOOD_NORMAL,
1735                                              sizeof(SilcUInt32));
1736       if (!buffer)
1737         return NULL;
1738       break;
1739
1740     case SILC_ATTRIBUTE_STATUS_FREETEXT:
1741       /* Put STATUS_FREETEXT.  We just tell in the message that we are
1742          replying on behalf of the client. */
1743       tmp =
1744         "This information was provided by the server on behalf of the user";
1745       buffer = silc_attribute_payload_encode(buffer, attribute,
1746                                              SILC_ATTRIBUTE_FLAG_VALID,
1747                                              tmp, strlen(tmp));
1748       if (!buffer)
1749         return NULL;
1750       break;
1751
1752     case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1753       /* Put PREFERRED_CONTACT */
1754       buffer = silc_attribute_payload_encode(buffer, attribute,
1755                                              SILC_ATTRIBUTE_FLAG_VALID,
1756                                              (void *)
1757                                              SILC_ATTRIBUTE_CONTACT_CHAT,
1758                                              sizeof(SilcUInt32));
1759       if (!buffer)
1760         return NULL;
1761       break;
1762
1763     case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1764       /* Put USER_PUBLIC_KEY */
1765       if (client_entry->data.public_key) {
1766         pk.type = "silc-rsa";
1767         pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1768                                               &pk.data_len);
1769         buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1770                                                SILC_ATTRIBUTE_FLAG_VALID :
1771                                                SILC_ATTRIBUTE_FLAG_INVALID,
1772                                                &pk, sizeof(pk));
1773         silc_free(pk.data);
1774         if (!buffer)
1775           return NULL;
1776         break;
1777       }
1778
1779       /* No public key available */
1780       buffer = silc_attribute_payload_encode(buffer, attribute,
1781                                              SILC_ATTRIBUTE_FLAG_INVALID,
1782                                              NULL, 0);
1783       if (!buffer)
1784         return NULL;
1785       break;
1786
1787     default:
1788       /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1789       if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1790           attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1791         break;
1792
1793       /* For other attributes we cannot reply so mark it invalid */
1794       buffer = silc_attribute_payload_encode(buffer, attribute,
1795                                              SILC_ATTRIBUTE_FLAG_INVALID,
1796                                              NULL, 0);
1797       if (!buffer)
1798         return NULL;
1799       break;
1800     }
1801   }
1802
1803   /* Always put our public key.  This assures that we send at least
1804      something valid back always. */
1805   pk.type = "silc-rsa";
1806   pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1807   buffer = silc_attribute_payload_encode(buffer,
1808                                          SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1809                                          pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1810                                          SILC_ATTRIBUTE_FLAG_INVALID,
1811                                          &pk, sizeof(pk));
1812   silc_free(pk.data);
1813   if (!buffer)
1814     return NULL;
1815
1816   /* Finally compute the digital signature of all the data we provided
1817      as an indication that we provided rightfull information, and this
1818      also authenticates our public key. */
1819   if (silc_pkcs_get_key_len(server->pkcs) / 8 <= sizeof(sign) -1  &&
1820       silc_pkcs_sign_with_hash(server->pkcs, server->sha1hash,
1821                                buffer->data, buffer->len,
1822                                sign, &sign_len)) {
1823     pk.type = NULL;
1824     pk.data = sign;
1825     pk.data_len = sign_len;
1826     buffer =
1827       silc_attribute_payload_encode(buffer,
1828                                     SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1829                                     SILC_ATTRIBUTE_FLAG_VALID,
1830                                     &pk, sizeof(pk));
1831   }
1832   if (!buffer)
1833     return NULL;
1834
1835   return buffer;
1836 }
1837
1838 /* Find client by the Client ID indicated by the `client_id', and if not
1839    found then query it by using WHOIS command.  The client information
1840    is also resolved if the cached information is incomplete or if the
1841    `always_resolve' is set to TRUE.  The indication whether requested
1842    client was being resolved is saved into `resolved'.  If the client
1843    is not being resolved its entry is returned by this function.  NULL
1844    is returned if client is resolved. */
1845
1846 SilcClientEntry silc_server_query_client(SilcServer server,
1847                                          const SilcClientID *client_id,
1848                                          bool always_resolve,
1849                                          bool *resolved)
1850 {
1851   SilcClientEntry client;
1852
1853   SILC_LOG_DEBUG(("Resolving client by client ID"));
1854
1855   if (resolved)
1856     *resolved = FALSE;
1857
1858   client = silc_idlist_find_client_by_id(server->local_list,
1859                                          (SilcClientID *)client_id,
1860                                          TRUE, NULL);
1861   if (!client) {
1862     client = silc_idlist_find_client_by_id(server->global_list,
1863                                            (SilcClientID *)client_id,
1864                                            TRUE, NULL);
1865     if (!client && server->server_type == SILC_ROUTER)
1866       return NULL;
1867   }
1868
1869   if (!client && server->standalone)
1870     return NULL;
1871
1872   if (!client || !client->nickname || !client->username ||
1873       always_resolve) {
1874     SilcBuffer buffer, idp;
1875
1876     if (client) {
1877       client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
1878       client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
1879       client->resolve_cmd_ident = ++server->cmd_ident;
1880     }
1881
1882     idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
1883     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
1884                                             server->cmd_ident, 1,
1885                                             4, idp->data, idp->len);
1886     silc_server_packet_send(server, client ? client->router->connection :
1887                             SILC_PRIMARY_ROUTE(server),
1888                             SILC_PACKET_COMMAND, 0,
1889                             buffer->data, buffer->len, FALSE);
1890     silc_buffer_free(idp);
1891     silc_buffer_free(buffer);
1892
1893     if (resolved)
1894       *resolved = TRUE;
1895
1896     return NULL;
1897   }
1898
1899   return client;
1900 }