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