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