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