Preliminary SILC Server 1.1 commit.
[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(hsock, NULL, (const char **)&tmp,
1494                                         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(hsock, NULL, (const char **)&tmp,
1585                                         NULL, NULL);
1586             silc_strncat(uh, sizeof(uh), tmp, strlen(tmp));
1587           }
1588
1589           silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1590                                          status, 0, ident, 3,
1591                                          2, idp->data, silc_buffer_len(idp),
1592                                          3, nh, strlen(nh),
1593                                          4, uh, strlen(uh));
1594           sent_reply = TRUE;
1595         }
1596         break;
1597
1598       case SILC_COMMAND_WHOWAS:
1599         memset(uh, 0, sizeof(uh));
1600         silc_strncat(uh, sizeof(uh), entry->username, strlen(entry->username));
1601         if (!strchr(entry->username, '@'))
1602           silc_strncat(uh, sizeof(uh), "@-private-", 10);
1603
1604         /* Send command reply */
1605         silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1606                                        status, 0, ident, 4,
1607                                        2, idp->data, silc_buffer_len(idp),
1608                                        3, nh, strlen(nh),
1609                                        4, uh, strlen(uh),
1610                                        5, entry->userinfo,
1611                                        entry->userinfo ?
1612                                        strlen(entry->userinfo) : 0);
1613         sent_reply = TRUE;
1614         break;
1615       }
1616
1617       silc_buffer_free(idp);
1618
1619       if (status == SILC_STATUS_LIST_END)
1620         break;
1621       k++;
1622     }
1623
1624     if (k == 0) {
1625       /* Not one valid entry was found, send error.  If nickname was used
1626          in query send error based on that, otherwise the query->errors
1627          already includes proper errors. */
1628       if (query->nickname[0] || (!query->ids && query->attrs))
1629         silc_server_query_add_error(server, query, 1, 1,
1630                                     SILC_STATUS_ERR_NO_SUCH_NICK);
1631
1632       /* Make sure some error is sent */
1633       if (!query->errors_count && !servers_count && !channels_count)
1634         silc_server_query_add_error(server, query, 2, 0,
1635                                     SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
1636     }
1637   }
1638
1639   /* Send servers */
1640   if (query->querycmd == SILC_COMMAND_IDENTIFY && servers_count) {
1641     SilcServerEntry entry;
1642
1643     if (status == SILC_STATUS_OK && servers_count > 1)
1644       status = SILC_STATUS_LIST_START;
1645
1646     k = 0;
1647     for (i = 0; i < servers_count; i++) {
1648       entry = servers[i];
1649
1650       if (k >= 1)
1651         status = SILC_STATUS_LIST_ITEM;
1652       if (servers_count == 1 && status != SILC_STATUS_OK && !channels_count &&
1653           !query->errors_count)
1654         status = SILC_STATUS_LIST_END;
1655       if (servers_count > 1 && k == servers_count - 1 && !channels_count &&
1656           !query->errors_count)
1657         status = SILC_STATUS_LIST_END;
1658       if (query->reply_count && k - 1 == query->reply_count)
1659         status = SILC_STATUS_LIST_END;
1660
1661       SILC_LOG_DEBUG(("%s: server %s",
1662                       (status == SILC_STATUS_OK ?         "   OK" :
1663                        status == SILC_STATUS_LIST_START ? "START" :
1664                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1665                        status == SILC_STATUS_LIST_END  ?  "  END" :
1666                        "      : "),
1667                       entry->server_name ? entry->server_name : ""));
1668
1669       /* Send command reply */
1670       idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
1671       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1672                                      status, 0, ident, 2,
1673                                      2, idp->data, silc_buffer_len(idp),
1674                                      3, entry->server_name,
1675                                      entry->server_name ?
1676                                      strlen(entry->server_name) : 0);
1677       silc_buffer_free(idp);
1678       sent_reply = TRUE;
1679
1680       if (status == SILC_STATUS_LIST_END)
1681         break;
1682       k++;
1683     }
1684   }
1685
1686   /* Send channels */
1687   if (query->querycmd == SILC_COMMAND_IDENTIFY && channels_count) {
1688     SilcChannelEntry entry;
1689
1690     if (status == SILC_STATUS_OK && channels_count > 1)
1691       status = SILC_STATUS_LIST_START;
1692
1693     k = 0;
1694     for (i = 0; i < channels_count; i++) {
1695       entry = channels[i];
1696
1697       if (k >= 1)
1698         status = SILC_STATUS_LIST_ITEM;
1699       if (channels_count == 1 && status != SILC_STATUS_OK &&
1700           !query->errors_count)
1701         status = SILC_STATUS_LIST_END;
1702       if (channels_count > 1 && k == channels_count - 1 &&
1703           !query->errors_count)
1704         status = SILC_STATUS_LIST_END;
1705       if (query->reply_count && k - 1 == query->reply_count)
1706         status = SILC_STATUS_LIST_END;
1707
1708       SILC_LOG_DEBUG(("%s: channel %s",
1709                       (status == SILC_STATUS_OK ?         "   OK" :
1710                        status == SILC_STATUS_LIST_START ? "START" :
1711                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1712                        status == SILC_STATUS_LIST_END  ?  "  END" :
1713                        "      : "),
1714                       entry->channel_name ? entry->channel_name : ""));
1715
1716       /* Send command reply */
1717       idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
1718       silc_server_send_command_reply(server, cmd->sock, SILC_COMMAND_IDENTIFY,
1719                                      status, 0, ident, 2,
1720                                      2, idp->data, silc_buffer_len(idp),
1721                                      3, entry->channel_name,
1722                                      entry->channel_name ?
1723                                      strlen(entry->channel_name) : 0);
1724       silc_buffer_free(idp);
1725       sent_reply = TRUE;
1726
1727       if (status == SILC_STATUS_LIST_END)
1728         break;
1729       k++;
1730     }
1731   }
1732
1733   /* Send errors */
1734   if (query->errors_count) {
1735     int type;
1736
1737     if (status == SILC_STATUS_OK && query->errors_count > 1)
1738       status = SILC_STATUS_LIST_START;
1739
1740     k = 0;
1741     for (i = 0; i < query->errors_count; i++) {
1742       idp = NULL;
1743
1744       /* Take error argument */
1745       if (query->errors[i].type == 1) {
1746         /* Take from sent arguments */
1747         len = 0;
1748         tmp = silc_argument_get_arg_type(cmd->args,
1749                                          query->errors[i].index, &len);
1750         type = 2;
1751       } else if (query->errors[i].type == 2) {
1752         /* No argument */
1753         len = 0;
1754         tmp = NULL;
1755         type = 0;
1756       } else if (!query->errors[i].id) {
1757         /* Take from query->ids */
1758         idp =
1759           silc_id_payload_encode(query->ids[query->errors[i].index].id,
1760                                  query->ids[query->errors[k].index].id_type);
1761         tmp = idp->data;
1762         len = silc_buffer_len(idp);
1763         type = 2;
1764       } else {
1765         /* Take added ID. */
1766         idp = silc_id_payload_encode(query->errors[i].id,
1767                                      query->errors[k].id_type);
1768         tmp = idp->data;
1769         len = silc_buffer_len(idp);
1770         type = 2;
1771       }
1772
1773       if (k >= 1)
1774         status = SILC_STATUS_LIST_ITEM;
1775       if (query->errors_count == 1 && status != SILC_STATUS_OK)
1776         status = SILC_STATUS_LIST_END;
1777       if (query->errors_count > 1 && k == query->errors_count - 1)
1778         status = SILC_STATUS_LIST_END;
1779       if (query->reply_count && k - 1 == query->reply_count)
1780         status = SILC_STATUS_LIST_END;
1781
1782       SILC_LOG_DEBUG(("%s: ERROR: %s (%d)",
1783                       (status == SILC_STATUS_OK ?         "   OK" :
1784                        status == SILC_STATUS_LIST_START ? "START" :
1785                        status == SILC_STATUS_LIST_ITEM  ? " ITEM" :
1786                        status == SILC_STATUS_LIST_END  ?  "  END" :
1787                        "      : "),
1788                       silc_get_status_message(query->errors[i].error),
1789                       query->errors[i].error));
1790
1791 #if 1 /* XXX Backwards compatibility.  Remove in 1.0. */
1792       if (query->errors[i].error == SILC_STATUS_ERR_NO_SUCH_NICK)
1793         /* Send error */
1794         silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1795                                        (status == SILC_STATUS_OK ?
1796                                         query->errors[i].error : status),
1797                                        (status == SILC_STATUS_OK ?
1798                                         0 : query->errors[i].error), ident, 2,
1799                                        type, tmp, len,
1800                                        3, tmp, len);
1801       else
1802 #endif
1803       /* Send error */
1804       silc_server_send_command_reply(server, cmd->sock, query->querycmd,
1805                                      (status == SILC_STATUS_OK ?
1806                                       query->errors[i].error : status),
1807                                      (status == SILC_STATUS_OK ?
1808                                       0 : query->errors[i].error), ident, 1,
1809                                      type, tmp, len);
1810
1811       silc_buffer_free(idp);
1812       sent_reply = TRUE;
1813
1814       if (status == SILC_STATUS_LIST_END)
1815         break;
1816       k++;
1817     }
1818   }
1819
1820   if (!sent_reply)
1821     SILC_LOG_ERROR(("BUG: Query did not send anything"));
1822
1823   /* Cleanup */
1824   silc_server_query_free(query);
1825 }
1826
1827 /* This routine is used to reply to Requested Attributes in WHOIS on behalf
1828    of the client since we were unable to resolve them from the client.
1829    Either client does not support Requested Attributes or isn't replying
1830    to them like it should. */
1831
1832 SilcBuffer silc_server_query_reply_attrs(SilcServer server,
1833                                          SilcServerQuery query,
1834                                          SilcClientEntry client_entry)
1835 {
1836   SilcBuffer buffer = NULL;
1837   SilcAttribute attribute;
1838   SilcAttributePayload attr;
1839   SilcAttributeObjPk pk;
1840   SilcAttributeObjService service;
1841   unsigned char *tmp;
1842   unsigned char sign[2048 + 1];
1843   SilcUInt32 sign_len;
1844
1845   SILC_LOG_DEBUG(("Constructing Requested Attributes"));
1846
1847   /* Go through all requested attributes */
1848   silc_dlist_start(query->attrs);
1849   while ((attr = silc_dlist_get(query->attrs)) != SILC_LIST_END) {
1850     attribute = silc_attribute_get_attribute(attr);
1851     switch (attribute) {
1852
1853     case SILC_ATTRIBUTE_SERVICE:
1854       /* Put SERVICE.  Put only SILC service. */
1855       memset(&service, 0, sizeof(service));
1856       service.port = (server->config->server_info->primary ?
1857                       server->config->server_info->primary->port : SILC_PORT);
1858       silc_strncat(service.address, sizeof(service.address),
1859                    server->server_name, strlen(server->server_name));
1860       service.status = !(client_entry->mode & SILC_UMODE_DETACHED);
1861       if (client_entry->connection)
1862         service.idle = time(NULL) - client_entry->data.last_receive;
1863       buffer = silc_attribute_payload_encode(buffer, attribute,
1864                                              SILC_ATTRIBUTE_FLAG_VALID,
1865                                              &service, sizeof(service));
1866       if (!buffer)
1867         return NULL;
1868       break;
1869
1870     case SILC_ATTRIBUTE_STATUS_MOOD:
1871       /* Put STATUS_MOOD */
1872       buffer = silc_attribute_payload_encode(buffer, attribute,
1873                                              SILC_ATTRIBUTE_FLAG_VALID,
1874                                              (void *)
1875                                              SILC_ATTRIBUTE_MOOD_NORMAL,
1876                                              sizeof(SilcUInt32));
1877       if (!buffer)
1878         return NULL;
1879       break;
1880
1881     case SILC_ATTRIBUTE_STATUS_FREETEXT:
1882       /* Put STATUS_FREETEXT.  We just tell in the message that we are
1883          replying on behalf of the client. */
1884       tmp =
1885         "This information was provided by the server on behalf of the user";
1886       buffer = silc_attribute_payload_encode(buffer, attribute,
1887                                              SILC_ATTRIBUTE_FLAG_VALID,
1888                                              tmp, strlen(tmp));
1889       if (!buffer)
1890         return NULL;
1891       break;
1892
1893     case SILC_ATTRIBUTE_PREFERRED_CONTACT:
1894       /* Put PREFERRED_CONTACT */
1895       buffer = silc_attribute_payload_encode(buffer, attribute,
1896                                              SILC_ATTRIBUTE_FLAG_VALID,
1897                                              (void *)
1898                                              SILC_ATTRIBUTE_CONTACT_CHAT,
1899                                              sizeof(SilcUInt32));
1900       if (!buffer)
1901         return NULL;
1902       break;
1903
1904     case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
1905       /* Put USER_PUBLIC_KEY */
1906       if (client_entry->data.public_key) {
1907         pk.type = "silc-rsa";
1908         pk.data = silc_pkcs_public_key_encode(client_entry->data.public_key,
1909                                               &pk.data_len);
1910         buffer = silc_attribute_payload_encode(buffer, attribute, pk.data ?
1911                                                SILC_ATTRIBUTE_FLAG_VALID :
1912                                                SILC_ATTRIBUTE_FLAG_INVALID,
1913                                                &pk, sizeof(pk));
1914         silc_free(pk.data);
1915         if (!buffer)
1916           return NULL;
1917         break;
1918       }
1919
1920       /* No public key available */
1921       buffer = silc_attribute_payload_encode(buffer, attribute,
1922                                              SILC_ATTRIBUTE_FLAG_INVALID,
1923                                              NULL, 0);
1924       if (!buffer)
1925         return NULL;
1926       break;
1927
1928     default:
1929       /* Ignore SERVER_PUBLIC_KEY since we are going to put it anyway later */
1930       if (attribute == SILC_ATTRIBUTE_SERVER_PUBLIC_KEY ||
1931           attribute == SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE)
1932         break;
1933
1934       /* For other attributes we cannot reply so mark it invalid */
1935       buffer = silc_attribute_payload_encode(buffer, attribute,
1936                                              SILC_ATTRIBUTE_FLAG_INVALID,
1937                                              NULL, 0);
1938       if (!buffer)
1939         return NULL;
1940       break;
1941     }
1942   }
1943
1944   /* Always put our public key.  This assures that we send at least
1945      something valid back always. */
1946   pk.type = "silc-rsa";
1947   pk.data = silc_pkcs_public_key_encode(server->public_key, &pk.data_len);
1948   buffer = silc_attribute_payload_encode(buffer,
1949                                          SILC_ATTRIBUTE_SERVER_PUBLIC_KEY,
1950                                          pk.data ? SILC_ATTRIBUTE_FLAG_VALID :
1951                                          SILC_ATTRIBUTE_FLAG_INVALID,
1952                                          &pk, sizeof(pk));
1953   silc_free(pk.data);
1954   if (!buffer)
1955     return NULL;
1956
1957   /* Finally compute the digital signature of all the data we provided
1958      as an indication that we provided rightfull information, and this
1959      also authenticates our public key. */
1960   if (silc_pkcs_private_key_get_len(server->private_key) / 8 <=
1961       sizeof(sign) -1  &&
1962       silc_pkcs_sign(server->private_key, buffer->data,
1963                      silc_buffer_len(buffer), sign, sizeof(sign), &sign_len,
1964                      TRUE, server->sha1hash)) {
1965     pk.type = NULL;
1966     pk.data = sign;
1967     pk.data_len = sign_len;
1968     buffer =
1969       silc_attribute_payload_encode(buffer,
1970                                     SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE,
1971                                     SILC_ATTRIBUTE_FLAG_VALID,
1972                                     &pk, sizeof(pk));
1973   }
1974   if (!buffer)
1975     return NULL;
1976
1977   return buffer;
1978 }
1979
1980 /* Find client by the Client ID indicated by the `client_id', and if not
1981    found then query it by using WHOIS command.  The client information
1982    is also resolved if the cached information is incomplete or if the
1983    `always_resolve' is set to TRUE.  The indication whether requested
1984    client was being resolved is saved into `resolved'.  If the client
1985    is not being resolved its entry is returned by this function.  NULL
1986    is returned if client is resolved. */
1987
1988 SilcClientEntry silc_server_query_client(SilcServer server,
1989                                          const SilcClientID *client_id,
1990                                          SilcBool always_resolve,
1991                                          SilcBool *resolved)
1992 {
1993   SilcClientEntry client;
1994
1995   SILC_LOG_DEBUG(("Resolving client by client ID"));
1996
1997   if (resolved)
1998     *resolved = FALSE;
1999
2000   client = silc_idlist_find_client_by_id(server->local_list,
2001                                          (SilcClientID *)client_id,
2002                                          TRUE, NULL);
2003   if (!client) {
2004     client = silc_idlist_find_client_by_id(server->global_list,
2005                                            (SilcClientID *)client_id,
2006                                            TRUE, NULL);
2007     if (!client && server->server_type == SILC_ROUTER)
2008       return NULL;
2009   }
2010
2011   if (!client && server->standalone)
2012     return NULL;
2013
2014   if (!client || !client->nickname || !client->username ||
2015       always_resolve) {
2016     SilcBuffer buffer, idp;
2017
2018     /* Statistics */
2019     server->stat.commands_sent++;
2020
2021     if (client) {
2022       client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
2023       client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
2024       client->resolve_cmd_ident = ++server->cmd_ident;
2025     }
2026
2027     idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
2028     buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
2029                                             server->cmd_ident, 1,
2030                                             4, idp->data,
2031                                             silc_buffer_len(idp));
2032     silc_server_packet_send(server, client ? client->router->connection :
2033                             SILC_PRIMARY_ROUTE(server),
2034                             SILC_PACKET_COMMAND, 0,
2035                             buffer->data, silc_buffer_len(buffer));
2036     silc_buffer_free(idp);
2037     silc_buffer_free(buffer);
2038
2039     if (resolved)
2040       *resolved = TRUE;
2041
2042     return NULL;
2043   }
2044
2045   return client;
2046 }