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