The SILC Project

source navigation ]
identifier search ]
freetext search ]
file search ]

silc/silcd/command_reply.c

  1 /*
  2 
  3   command_reply.c
  4 
  5   Author: Pekka Riikonen <priikone@silcnet.org>
  6 
  7   Copyright (C) 1997 - 2005 Pekka Riikonen
  8 
  9   This program is free software; you can redistribute it and/or modify
 10   it under the terms of the GNU General Public License as published by
 11   the Free Software Foundation; version 2 of the License.
 12 
 13   This program is distributed in the hope that it will be useful,
 14   but WITHOUT ANY WARRANTY; without even the implied warranty of
 15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16   GNU General Public License for more details.
 17 
 18 */
 19 /* $Id: command_reply.c,v 1.111 2005/04/23 13:32:24 priikone Exp $ */
 20 
 21 #include "serverincludes.h"
 22 #include "server_internal.h"
 23 #include "command_reply.h"
 24 
 25 /* All functions that call the COMMAND_CHECK_STATUS macros must have
 26    out: and err: goto labels. */
 27 
 28 #define COMMAND_CHECK_STATUS                                            \
 29 do {                                                                    \
 30   SILC_LOG_DEBUG(("Start"));                                            \
 31   if (!silc_command_get_status(cmd->payload, &status, &error)) {        \
 32     if (SILC_STATUS_IS_ERROR(status))                                   \
 33       goto out;                                                         \
 34     if (status == SILC_STATUS_LIST_END)                                 \
 35       goto out;                                                         \
 36     goto err;                                                           \
 37   }                                                                     \
 38 } while(0)
 39 
 40 /* Server command reply list. Not all commands have reply function as
 41    they are never sent by server. More maybe added later if need appears. */
 42 SilcServerCommandReply silc_command_reply_list[] =
 43 {
 44   SILC_SERVER_CMD_REPLY(whois, WHOIS),
 45   SILC_SERVER_CMD_REPLY(whowas, WHOWAS),
 46   SILC_SERVER_CMD_REPLY(identify, IDENTIFY),
 47   SILC_SERVER_CMD_REPLY(info, INFO),
 48   SILC_SERVER_CMD_REPLY(motd, MOTD),
 49   SILC_SERVER_CMD_REPLY(join, JOIN),
 50   SILC_SERVER_CMD_REPLY(stats, STATS),
 51   SILC_SERVER_CMD_REPLY(users, USERS),
 52   SILC_SERVER_CMD_REPLY(getkey, GETKEY),
 53   SILC_SERVER_CMD_REPLY(list, LIST),
 54   SILC_SERVER_CMD_REPLY(watch, WATCH),
 55   SILC_SERVER_CMD_REPLY(ping, PING),
 56 
 57   { NULL, 0 },
 58 };
 59 
 60 /* Process received command reply. */
 61 
 62 void silc_server_command_reply_process(SilcServer server,
 63                                        SilcSocketConnection sock,
 64                                        SilcBuffer buffer)
 65 {
 66   SilcServerCommandReply *cmd;
 67   SilcServerCommandReplyContext ctx;
 68   SilcCommandPayload payload;
 69   SilcCommand command;
 70 
 71   SILC_LOG_DEBUG(("Start"));
 72 
 73   /* Get command reply payload from packet */
 74   payload = silc_command_payload_parse(buffer->data, buffer->len);
 75   if (!payload) {
 76     /* Silently ignore bad reply packet */
 77     SILC_LOG_DEBUG(("Bad command reply packet"));
 78     return;
 79   }
 80 
 81   /* Allocate command reply context. This must be free'd by the
 82      command reply routine receiving it. */
 83   ctx = silc_calloc(1, sizeof(*ctx));
 84   ctx->server = server;
 85   ctx->sock = silc_socket_dup(sock);
 86   ctx->payload = payload;
 87   ctx->args = silc_command_get_args(ctx->payload);
 88   ctx->ident = silc_command_get_ident(ctx->payload);
 89   command = silc_command_get(ctx->payload);
 90 
 91   /* Client is not allowed to send reply to all commands */
 92   if (sock->type == SILC_SOCKET_TYPE_CLIENT &&
 93       command != SILC_COMMAND_WHOIS) {
 94     silc_server_command_reply_free(ctx);
 95     return;
 96   }
 97 
 98   /* Check for pending commands and mark to be exeucted */
 99   ctx->callbacks =
100     silc_server_command_pending_check(server, command,
101                                       ctx->ident, &ctx->callbacks_count);
102 
103   /* Execute command reply */
104   for (cmd = silc_command_reply_list; cmd->cb; cmd++)
105     if (cmd->cmd == command)
106       break;
107 
108   if (cmd == NULL || !cmd->cb) {
109     silc_server_command_reply_free(ctx);
110     return;
111   }
112 
113   cmd->cb(ctx, NULL);
114 }
115 
116 /* Free command reply context and its internals. */
117 
118 void silc_server_command_reply_free(SilcServerCommandReplyContext cmd)
119 {
120   if (cmd) {
121     silc_command_payload_free(cmd->payload);
122     if (cmd->sock)
123       silc_socket_free(cmd->sock); /* Decrease the reference counter */
124     silc_free(cmd->callbacks);
125     silc_free(cmd);
126   }
127 }
128 
129 static void
130 silc_server_command_process_error(SilcServerCommandReplyContext cmd,
131                                   SilcStatus error)
132 {
133   SilcServer server = cmd->server;
134 
135   /* If we received notify for invalid ID we'll remove the ID if we
136      have it cached. */
137   if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID &&
138       cmd->sock->type == SILC_SOCKET_TYPE_ROUTER) {
139     SilcClientEntry client;
140     SilcUInt32 tmp_len;
141     unsigned char *tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
142     if (tmp) {
143       SilcClientID *client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
144       if (client_id) {
145         SILC_LOG_DEBUG(("Received invalid client ID notification, deleting "
146                         "the entry from cache"));
147         client = silc_idlist_find_client_by_id(server->global_list,
148                                                client_id, FALSE, NULL);
149         if (client) {
150 
151           if (client->data.public_key)
152             silc_hash_table_del_by_context(server->pk_hash,
153                                            client->data.public_key,
154                                            client);
155 
156           silc_server_remove_from_channels(server, NULL, client, TRUE,
157                                            NULL, TRUE, FALSE);
158           silc_idlist_del_data(client);
159           silc_idlist_del_client(server->global_list, client);
160         }
161         silc_free(client_id);
162       }
163     }
164   }
165 }
166 
167 /* Caches the received WHOIS information. */
168 
169 static char
170 silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
171 {
172   SilcServer server = cmd->server;
173   unsigned char *id_data, *umodes;
174   char *nickname, *username, *realname, *tmp, *servername = NULL;
175   unsigned char *fingerprint;
176   SilcClientID *client_id;
177   SilcClientEntry client;
178   SilcIDCacheEntry cache = NULL;
179   char global = FALSE;
180   char *nick = NULL;
181   SilcUInt32 mode = 0, len, len2, id_len, flen;
182 
183   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
184   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
185   username = silc_argument_get_arg_type(cmd->args, 4, &len);
186   realname = silc_argument_get_arg_type(cmd->args, 5, &len);
187   if (!id_data || !nickname || !username || !realname)
188     return FALSE;
189 
190   tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
191   if (tmp)
192     SILC_GET32_MSB(mode, tmp);
193 
194   client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
195   if (!client_id)
196     return FALSE;
197 
198   fingerprint = silc_argument_get_arg_type(cmd->args, 9, &flen);
199 
200   /* Check if we have this client cached already. */
201 
202   client = silc_idlist_find_client_by_id(server->local_list, client_id,
203                                          FALSE, NULL);
204   if (!client) {
205     client = silc_idlist_find_client_by_id(server->global_list, client_id,
206                                            FALSE, NULL);
207     global = TRUE;
208   }
209 
210   if (!client) {
211     /* If router did not find such Client ID in its lists then this must
212        be bogus client or some router in the net is buggy. */
213     if (server->server_type != SILC_SERVER)
214       return FALSE;
215 
216     /* Take hostname out of nick string if it includes it. */
217     silc_parse_userfqdn(nickname, &nick, &servername);
218 
219     /* We don't have that client anywhere, add it. The client is added
220        to global list since server didn't have it in the lists so it must be
221        global. This will check for valid nickname and username strings. */
222     client = silc_idlist_add_client(server->global_list, nick, username,
223                                     strdup(realname), client_id,
224                                     cmd->sock->user_data, NULL, 0);
225     if (!client) {
226       SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
227       silc_free(nick);
228       silc_free(servername);
229       return FALSE;
230     }
231 
232     client->data.status |=
233       (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED);
234     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
235     client->mode = mode;
236     client->servername = servername;
237   } else {
238     /* We have the client already, update the data */
239 
240     SILC_LOG_DEBUG(("Updating client data"));
241 
242     /* Check nickname */
243     silc_parse_userfqdn(nickname, &nick, &servername);
244     nickname = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8,
245                                      128, NULL);
246     if (!nickname) {
247       SILC_LOG_ERROR(("Malformed nickname '%s' received in WHOIS reply "
248                       "from %s",
249                       cmd->sock->hostname ? cmd->sock->hostname : "", nick));
250       silc_free(nick);
251       silc_free(servername);
252       return FALSE;
253     }
254 
255     /* Check username */
256     silc_parse_userfqdn(username, &tmp, NULL);
257     if (!silc_identifier_verify(tmp, strlen(tmp), SILC_STRING_UTF8, 128)) {
258       silc_free(tmp);
259       silc_free(nick);
260       silc_free(servername);
261       SILC_LOG_ERROR(("Malformed username '%s' received in WHOIS reply "
262                       "from %s",
263                       cmd->sock->hostname ? cmd->sock->hostname : "", tmp));
264       return FALSE;
265     }
266     silc_free(tmp);
267 
268     /* Remove the old cache entry  */
269     silc_idcache_del_by_context(global ? server->global_list->clients :
270                                 server->local_list->clients, client);
271 
272     silc_free(client->nickname);
273     silc_free(client->username);
274     silc_free(client->userinfo);
275     silc_free(client->servername);
276 
277     client->nickname = nick;
278     client->username = strdup(username);
279     client->userinfo = strdup(realname);
280     client->servername = servername;
281     client->mode = mode;
282     client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
283     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
284 
285     /* Create new cache entry */
286     silc_idcache_add(global ? server->global_list->clients :
287                      server->local_list->clients, nickname, client->id,
288                      client, 0, NULL);
289     silc_free(client_id);
290   }
291 
292   /* Save channel list if it was sent to us */
293   if (server->server_type == SILC_SERVER) {
294     tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
295     umodes = silc_argument_get_arg_type(cmd->args, 10, &len2);
296     if (tmp && umodes) {
297       SilcBufferStruct channels_buf, umodes_buf;
298       silc_buffer_set(&channels_buf, tmp, len);
299       silc_buffer_set(&umodes_buf, umodes, len2);
300       silc_server_save_user_channels(server, cmd->sock, client, &channels_buf,
301                                      &umodes_buf);
302     } else {
303       silc_server_save_user_channels(server, cmd->sock, client, NULL, NULL);
304     }
305 
306     /* If client is global and is not on any channel then add that we'll
307        expire the entry after a while. */
308     if (global) {
309       silc_idlist_find_client_by_id(server->global_list, client->id,
310                                     FALSE, &cache);
311       if (!silc_hash_table_count(client->channels))
312         cache->expire = time(NULL) + 300;
313       else
314         cache->expire = 0;
315     }
316   }
317 
318   if (fingerprint && flen == sizeof(client->data.fingerprint))
319     memcpy(client->data.fingerprint, fingerprint, flen);
320 
321   /* Take Requested Attributes if set. */
322   tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
323   if (tmp) {
324     silc_free(client->attrs);
325     client->attrs = silc_memdup(tmp, len);
326     client->attrs_len = len;
327 
328     /* Try to take public key from attributes if present and we don't have
329        the key already.  Do this only on normal server.  Routers do GETKEY
330        for all clients anyway. */
331     if (server->server_type != SILC_ROUTER && !client->data.public_key) {
332       SilcAttributePayload attr;
333       SilcAttributeObjPk pk;
334       unsigned char f[20];
335       SilcDList attrs = silc_attribute_payload_parse(tmp, len);
336 
337       SILC_LOG_DEBUG(("Take client public key from attributes"));
338 
339       if (attrs) {
340         silc_dlist_start(attrs);
341         while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
342           if (silc_attribute_get_attribute(attr) ==
343               SILC_ATTRIBUTE_USER_PUBLIC_KEY) {
344 
345             if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
346               continue;
347 
348             /* Take only SILC public keys */
349             if (strcmp(pk.type, "silc-rsa")) {
350               silc_free(pk.type);
351               silc_free(pk.data);
352               continue;
353             }
354 
355             /* Verify that the server provided fingerprint matches the key */
356             silc_hash_make(server->sha1hash, pk.data, pk.data_len, f);
357             if (memcmp(f, client->data.fingerprint, sizeof(f))) {
358               silc_free(pk.type);
359               silc_free(pk.data);
360               continue;
361             }
362 
363             /* Save the public key. */
364             if (!silc_pkcs_public_key_decode(pk.data, pk.data_len,
365                                              &client->data.public_key)) {
366               silc_free(pk.type);
367               silc_free(pk.data);
368               continue;
369             }
370 
371             SILC_LOG_DEBUG(("Saved client public key from attributes"));
372 
373             /* Add to public key hash table */
374             if (!silc_hash_table_find_by_context(server->pk_hash,
375                                                  client->data.public_key,
376                                                  client, NULL))
377               silc_hash_table_add(server->pk_hash,
378                                   client->data.public_key, client);
379 
380             silc_free(pk.type);
381             silc_free(pk.data);
382             break;
383           }
384         }
385 
386         silc_attribute_payload_list_free(attrs);
387       }
388     }
389   }
390 
391   return TRUE;
392 }
393 
394 /* Handle requested attributes reply in WHOIS from client */
395 
396 static char
397 silc_server_command_reply_whois_save_client(SilcServerCommandReplyContext cmd)
398 {
399   unsigned char *tmp;
400   SilcUInt32 len;
401   SilcClientEntry client = cmd->sock->user_data;
402 
403   /* Take Requested Attributes if set. */
404   tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
405   if (tmp && client) {
406     silc_free(client->attrs);
407     client->attrs = silc_memdup(tmp, len);
408     client->attrs_len = len;
409   }
410 
411   client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
412 
413   return TRUE;
414 }
415 
416 /* Reiceved reply for WHOIS command. We sent the whois request to our
417    primary router, if we are normal server, and thus has now received reply
418    to the command. We will figure out what client originally sent us the
419    command and will send the reply to it.  If we are router we will figure
420    out who server sent us the command and send reply to that one. */
421 
422 SILC_SERVER_CMD_REPLY_FUNC(whois)
423 {
424   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
425   SilcStatus status, error;
426 
427   COMMAND_CHECK_STATUS;
428 
429   if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT) {
430     if (!silc_server_command_reply_whois_save(cmd))
431       goto out;
432   } else {
433     if (!silc_server_command_reply_whois_save_client(cmd))
434       goto out;
435   }
436 
437   /* Pending callbacks are not executed if this was an list entry */
438   if (status != SILC_STATUS_OK &&
439       status != SILC_STATUS_LIST_END) {
440     silc_server_command_reply_free(cmd);
441     return;
442   }
443 
444  out:
445   silc_server_command_process_error(cmd, error);
446   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOIS);
447   silc_server_command_reply_free(cmd);
448   return;
449 
450  err:
451   silc_server_command_process_error(cmd, error);
452   silc_server_command_reply_free(cmd);
453 }
454 
455 /* Caches the received WHOWAS information for a short period of time. */
456 
457 static char
458 silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
459 {
460   SilcServer server = cmd->server;
461   SilcUInt32 len, id_len;
462   unsigned char *id_data;
463   char *nickname, *username, *realname, *servername = NULL, *tmp;
464   SilcClientID *client_id;
465   SilcClientEntry client;
466   SilcIDCacheEntry cache = NULL;
467   char *nick = NULL;
468   int global = FALSE;
469 
470   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
471   nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
472   username = silc_argument_get_arg_type(cmd->args, 4, &len);
473   if (!id_data || !nickname || !username)
474     return FALSE;
475 
476   realname = silc_argument_get_arg_type(cmd->args, 5, &len);
477 
478   client_id = silc_id_payload_parse_id(id_data, id_len, NULL);
479   if (!client_id)
480     return FALSE;
481 
482   /* Check if we have this client cached already. */
483 
484   client = silc_idlist_find_client_by_id(server->local_list, client_id,
485                                          FALSE, &cache);
486   if (!client) {
487     client = silc_idlist_find_client_by_id(server->global_list,
488                                            client_id, FALSE, &cache);
489     global = TRUE;
490   }
491 
492   if (!client) {
493     /* If router did not find such Client ID in its lists then this must
494        be bogus client or some router in the net is buggy. */
495     if (server->server_type != SILC_SERVER)
496       return FALSE;
497 
498     /* Take hostname out of nick string if it includes it. */
499     silc_parse_userfqdn(nickname, &nick, &servername);
500 
501     /* We don't have that client anywhere, add it. The client is added
502        to global list since server didn't have it in the lists so it must be
503        global. */
504     client = silc_idlist_add_client(server->global_list, nick, username,
505                                     strdup(realname),
506                                     silc_id_dup(client_id, SILC_ID_CLIENT),
507                                     cmd->sock->user_data, NULL,
508                                     SILC_ID_CACHE_EXPIRE_DEF);
509     if (!client) {
510       SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
511       silc_free(nick);
512       silc_free(servername);
513       return FALSE;
514     }
515 
516     client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
517     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
518     client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
519     client->servername = servername;
520   } else {
521     /* We have the client already, update the data */
522 
523     /* Check nickname */
524     silc_parse_userfqdn(nickname, &nick, &servername);
525     nickname = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8,
526                                      128, NULL);
527     if (!nickname) {
528       SILC_LOG_ERROR(("Malformed nickname '%s' received in WHOWAS reply "
529                       "from %s",
530                       cmd->sock->hostname ? cmd->sock->hostname : "", nick));
531       silc_free(nick);
532       silc_free(servername);
533       return FALSE;
534     }
535 
536     /* Check username */
537     silc_parse_userfqdn(username, &tmp, NULL);
538     if (!silc_identifier_verify(tmp, strlen(tmp), SILC_STRING_UTF8, 128)) {
539       silc_free(tmp);
540       silc_free(nick);
541       silc_free(servername);
542       SILC_LOG_ERROR(("Malformed username '%s' received in WHOWAS reply "
543                       "from %s",
544                       cmd->sock->hostname ? cmd->sock->hostname : "", tmp));
545       return FALSE;
546     }
547     silc_free(tmp);
548 
549     silc_free(client->nickname);
550     silc_free(client->username);
551     silc_free(client->servername);
552 
553     client->nickname = nick;
554     client->username = strdup(username);
555     client->servername = servername;
556     client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
557     client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
558 
559     /* Remove the old cache entry and create a new one */
560     silc_idcache_del_by_context(global ? server->global_list->clients :
561                                 server->local_list->clients, client);
562     silc_idcache_add(global ? server->global_list->clients :
563                      server->local_list->clients, nickname, client->id,
564                      client, 0, NULL);
565   }
566 
567   /* If client is global and is not on any channel then add that we'll
568      expire the entry after a while. */
569   if (global) {
570     silc_idlist_find_client_by_id(server->global_list, client->id,
571                                   FALSE, &cache);
572     if (!silc_hash_table_count(client->channels))
573       cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
574     else
575       cache->expire = 0;
576   }
577 
578   silc_free(client_id);
579 
580   return TRUE;
581 }
582 
583 /* Received reply for WHOWAS command. Cache the client information only for
584    a short period of time. */
585 
586 SILC_SERVER_CMD_REPLY_FUNC(whowas)
587 {
588   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
589   SilcStatus status, error;
590 
591   COMMAND_CHECK_STATUS;
592 
593   if (!silc_server_command_reply_whowas_save(cmd))
594     goto out;
595 
596   /* Pending callbacks are not executed if this was an list entry */
597   if (status != SILC_STATUS_OK &&
598       status != SILC_STATUS_LIST_END) {
599     silc_server_command_reply_free(cmd);
600     return;
601   }
602 
603  out:
604   silc_server_command_process_error(cmd, error);
605   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_WHOWAS);
606   silc_server_command_reply_free(cmd);
607   return;
608 
609  err:
610   silc_server_command_process_error(cmd, error);
611   silc_server_command_reply_free(cmd);
612 }
613 
614 /* Caches the received IDENTIFY information. */
615 
616 static char
617 silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
618 {
619   SilcServer server = cmd->server;
620   SilcUInt32 len, id_len;
621   unsigned char *id_data;
622   char *name, *info;
623   SilcClientID *client_id = NULL;
624   SilcServerID *server_id = NULL;
625   SilcChannelID *channel_id = NULL;
626   SilcClientEntry client;
627   SilcServerEntry server_entry;
628   SilcChannelEntry channel;
629   char global = FALSE;
630   char *nick = NULL;
631   SilcIDPayload idp = NULL;
632   SilcIdType id_type;
633   int expire = 0;
634 
635   id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
636   if (!id_data)
637     return FALSE;
638   idp = silc_id_payload_parse(id_data, id_len);
639   if (!idp)
640     return FALSE;
641 
642   name = silc_argument_get_arg_type(cmd->args, 3, &len);
643   info = silc_argument_get_arg_type(cmd->args, 4, &len);
644 
645   id_type = silc_id_payload_get_type(idp);
646 
647   switch (id_type) {
648   case SILC_ID_CLIENT:
649     client_id = silc_id_payload_get_id(idp);
650     if (!client_id)
651       goto error;
652 
653     SILC_LOG_DEBUG(("Received client information"));
654 
655     client = silc_idlist_find_client_by_id(server->local_list,
656                                            client_id, FALSE, NULL);
657     if (!client) {
658       client = silc_idlist_find_client_by_id(server->global_list, client_id,
659                                              FALSE, NULL);
660       global = TRUE;
661     }
662     if (!client) {
663       /* If router did not find such Client ID in its lists then this must
664          be bogus client or some router in the net is buggy. */
665       if (server->server_type != SILC_SERVER)
666         goto error;
667 
668       /* Take nickname */
669       if (name)
670         silc_parse_userfqdn(name, &nick, NULL);
671 
672       /* We don't have that client anywhere, add it. The client is added
673          to global list since server didn't have it in the lists so it must be
674          global. */
675       client = silc_idlist_add_client(server->global_list, nick, info, NULL,
676                                       client_id, cmd->sock->user_data,
677                                       NULL, time(NULL) + 300);
678       if (!client) {
679         SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
680         silc_free(nick);
681         goto error;
682       }
683 
684       client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
685       client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
686       client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
687     } else {
688       /* We have the client already, update the data */
689 
690       SILC_LOG_DEBUG(("Updating client data"));
691 
692       /* Take nickname */
693       if (name) {
694         silc_parse_userfqdn(name, &nick, NULL);
695 
696         /* Check nickname */
697         name = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8,
698                                      128, NULL);
699         if (!name) {
700           SILC_LOG_ERROR(("Malformed nickname '%s' received in IDENTIFY reply "
701                           "from %s",
702                           cmd->sock->hostname ?
703                           cmd->sock->hostname : "", nick));
704           return FALSE;
705         }
706 
707         /* Remove the old cache entry */
708         silc_idcache_del_by_context(global ? server->global_list->clients :
709                                     server->local_list->clients, client);
710 
711         silc_free(client->nickname);
712         client->nickname = nick;
713 
714         /* Add new cache entry */
715         silc_idcache_add(global ? server->global_list->clients :
716                          server->local_list->clients, name, client->id,
717                          client, expire, NULL);
718       }
719 
720       if (info) {
721         silc_free(client->username);
722         client->username = strdup(info);
723       }
724 
725       client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
726       client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
727 
728       /* If client is global and is not on any channel then add that we'll
729          expire the entry after a while. */
730       if (global && server->server_type == SILC_SERVER) {
731         SilcIDCacheEntry cache = NULL;
732         silc_idlist_find_client_by_id(server->global_list, client->id,
733                                       FALSE, &cache);
734         if (!silc_hash_table_count(client->channels))
735           cache->expire = time(NULL) + 300;
736         else
737           cache->expire = 0;
738       }
739 
740       silc_free(client_id);
741     }
742 
743     break;
744 
745   case SILC_ID_SERVER:
746     if (!name)
747       goto error;
748 
749     server_id = silc_id_payload_get_id(idp);
750     if (!server_id)
751       goto error;
752 
753     SILC_LOG_DEBUG(("Received server information"));
754 
755     server_entry = silc_idlist_find_server_by_id(server->local_list,
756                                                  server_id, FALSE, NULL);
757     if (!server_entry)
758       server_entry = silc_idlist_find_server_by_id(server->global_list,
759                                                    server_id, FALSE, NULL);
760     if (!server_entry) {
761       /* If router did not find such Server ID in its lists then this must
762          be bogus server or some router in the net is buggy. */
763       if (server->server_type != SILC_SERVER)
764         goto error;
765 
766       /* We don't have that server anywhere, add it. */
767       server_entry = silc_idlist_add_server(server->global_list,
768                                             strdup(name), 0,
769                                             server_id, server->router,
770                                             SILC_PRIMARY_ROUTE(server));
771       if (!server_entry) {
772         silc_free(server_id);
773         goto error;
774       }
775       server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
776       server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED;
777       server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
778       server_id = NULL;
779     }
780 
781     silc_free(server_id);
782     break;
783 
784   case SILC_ID_CHANNEL:
785     if (!name)
786       goto error;
787 
788     channel_id = silc_id_payload_get_id(idp);
789     if (!channel_id)
790       goto error;
791 
792     SILC_LOG_DEBUG(("Received channel information"));
793 
794     /* Check channel name */
795     info = silc_channel_name_check(name, strlen(name), SILC_STRING_UTF8,
796                                    256, NULL);
797     if (!info)
798       goto error;
799 
800     channel = silc_idlist_find_channel_by_name(server->local_list,
801                                                info, NULL);
802     if (!channel)
803       channel = silc_idlist_find_channel_by_name(server->global_list,
804                                                  info, NULL);
805     if (!channel) {
806       /* If router did not find such Channel ID in its lists then this must
807          be bogus channel or some router in the net is buggy. */
808       if (server->server_type != SILC_SERVER) {
809         silc_free(info);
810         goto error;
811       }
812 
813       /* We don't have that channel anywhere, add it. */
814       channel = silc_idlist_add_channel(server->global_list, strdup(name),
815                                         SILC_CHANNEL_MODE_NONE, channel_id,
816                                         server->router, NULL, NULL, 0);
817       if (!channel) {
818         silc_free(channel_id);
819         silc_free(info);
820         goto error;
821       }
822       silc_free(info);
823       channel_id = NULL;
824     }
825 
826     silc_free(channel_id);
827     break;
828   }
829 
830   silc_id_payload_free(idp);
831   return TRUE;
832 
833  error:
834   silc_id_payload_free(idp);
835   return FALSE;
836 }
837 
838 /* Received reply for forwarded IDENTIFY command. We have received the
839    requested identify information now and we will cache it. After this we
840    will call the pending command so that the requestee gets the information
841    after all. */
842 
843 SILC_SERVER_CMD_REPLY_FUNC(identify)
844 {
845   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
846   SilcStatus status, error;
847 
848   COMMAND_CHECK_STATUS;
849 
850   if (!silc_server_command_reply_identify_save(cmd))
851     goto out;
852 
853   /* Pending callbacks are not executed if this was an list entry */
854   if (status != SILC_STATUS_OK &&
855       status != SILC_STATUS_LIST_END) {
856     silc_server_command_reply_free(cmd);
857     return;
858   }
859 
860  out:
861   silc_server_command_process_error(cmd, error);
862   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_IDENTIFY);
863   silc_server_command_reply_free(cmd);
864   return;
865 
866  err:
867   silc_server_command_process_error(cmd, error);
868   silc_server_command_reply_free(cmd);
869 }
870 
871 /* Received reply fro INFO command. Cache the server and its information */
872 
873 SILC_SERVER_CMD_REPLY_FUNC(info)
874 {
875   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
876   SilcServer server = cmd->server;
877   SilcStatus status, error;
878   SilcServerEntry entry;
879   SilcServerID *server_id;
880   SilcUInt32 tmp_len;
881   unsigned char *tmp, *name;
882 
883   COMMAND_CHECK_STATUS;
884 
885   /* Get Server ID */
886   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
887   if (!tmp)
888     goto out;
889   server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
890   if (!server_id)
891     goto out;
892 
893   /* Get the name */
894   name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
895   if (!name)
896     goto out;
897 
898   entry = silc_idlist_find_server_by_id(server->local_list, server_id,
899                                         FALSE, NULL);
900   if (!entry) {
901     entry = silc_idlist_find_server_by_id(server->global_list, server_id,
902                                           FALSE, NULL);
903     if (!entry) {
904       /* Add the server to global list */
905       server_id = silc_id_dup(server_id, SILC_ID_SERVER);
906       entry = silc_idlist_add_server(server->global_list, strdup(name), 0,
907                                      server_id, cmd->sock->user_data,
908                                      cmd->sock);
909       if (!entry) {
910         silc_free(server_id);
911         goto out;
912       }
913       entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
914     }
915   }
916 
917   /* Get the info string */
918   tmp = silc_argument_get_arg_type(cmd->args, 4, &tmp_len);
919   if (tmp_len > 256)
920     tmp = NULL;
921 
922   entry->server_info = tmp ? strdup(tmp) : NULL;
923 
924  out:
925   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_INFO);
926  err:
927   silc_server_command_reply_free(cmd);
928 }
929 
930 /* Received reply fro MOTD command. */
931 
932 SILC_SERVER_CMD_REPLY_FUNC(motd)
933 {
934   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
935   SilcServer server = cmd->server;
936   SilcStatus status, error;
937   SilcServerEntry entry = NULL;
938   SilcServerID *server_id;
939   SilcUInt32 tmp_len;
940   unsigned char *tmp;
941 
942   COMMAND_CHECK_STATUS;
943 
944   /* Get Server ID */
945   tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
946   if (!tmp)
947     goto out;
948   server_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
949   if (!server_id)
950     goto out;
951 
952   entry = silc_idlist_find_server_by_id(server->local_list, server_id,
953                                         TRUE, NULL);
954   if (!entry) {
955     entry = silc_idlist_find_server_by_id(server->global_list, server_id,
956                                           TRUE, NULL);
957     if (!entry) {
958       SilcBuffer buffer;
959 
960       /* If router did not find such Server ID in its lists then this must
961          be bogus client or some router in the net is buggy. */
962       if (server->server_type != SILC_SERVER)
963         goto out;
964 
965       /* Statistics */
966       cmd->server->stat.commands_sent++;
967 
968       /* entry isn't known so we IDENTIFY it. otherwise the
969          silc_server_command_motd won't know about it and tell
970          the client that there is no such server */
971       buffer = silc_command_payload_encode_va(SILC_COMMAND_IDENTIFY,
972                                               ++server->cmd_ident, 5,
973                                               1, NULL, 0, 2, NULL, 0,
974                                               3, NULL, 0, 4, NULL, 0,
975                                               5, tmp, tmp_len);
976       silc_server_packet_send(server, SILC_PRIMARY_ROUTE(server),
977                               SILC_PACKET_COMMAND, 0, buffer->data,
978                               buffer->len, TRUE);
979       silc_server_command_pending(server, SILC_COMMAND_IDENTIFY,
980                                   server->cmd_ident,
981                                   silc_server_command_reply_motd,
982                                   cmd);
983       silc_buffer_free(buffer);
984       return;
985     }
986   }
987 
988   /* Get the motd */
989   tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
990   if (tmp_len > 256)
991     tmp = NULL;
992 
993   entry->motd = tmp;
994 
995  out:
996   SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
997  err:
998   silc_server_command_reply_free(cmd);
999 
1000   if (entry)
1001     entry->motd = NULL;
1002 }
1003 
1004 /* Received reply for forwarded JOIN command. Router has created or joined
1005    the client to the channel. We save some channel information locally
1006    for future use. */
1007 
1008 SILC_SERVER_CMD_REPLY_FUNC(join)
1009 {
1010   SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
1011   SilcServer server = cmd->server;
1012   SilcIDCacheEntry cache = NULL;
1013   SilcStatus status, error;
1014   SilcChannelID *id;
1015   SilcClientID *client_id = NULL;
1016   SilcChannelEntry entry;
1017   SilcHmac hmac = NULL;
1018   SilcUInt32 id_len, len, list_count;
1019   unsigned char *id_string;
1020   char *channel_name, *channel_namec = NULL, *tmp;
1021   SilcUInt32 mode, created;
1022   SilcBuffer keyp = NULL, client_id_list = NULL, client_mode_list = NULL;
1023   SilcPublicKey founder_key = NULL;
1024 
1025   COMMAND_CHECK_STATUS;
1026 
1027   /* Get channel name */
1028   channel_name = silc_argument_get_arg_type(cmd->args, 2, NULL);
1029   if (!channel_name)
1030     goto out;
1031