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