updates.
[silc.git] / apps / silcd / server_util.c
1 /*
2
3   server_util.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2001 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 /* Removes the client from channels and possibly removes the channels
25    as well.  After removing those channels that exist, their channel
26    keys are regnerated. This is called only by the function
27    silc_server_remove_clients_by_server. */
28
29 static void silc_server_remove_clients_channels(SilcServer server, 
30                                                 SilcSocketConnection sock,
31                                                 SilcClientEntry client,
32                                                 SilcHashTable channels)
33 {
34   SilcChannelEntry channel;
35   SilcChannelClientEntry chl;
36   SilcHashTableList htl;
37   SilcBuffer clidp;
38
39   SILC_LOG_DEBUG(("Start"));
40
41   if (!client || !client->id)
42     return;
43
44   clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
45
46   /* Remove the client from all channels. The client is removed from
47      the channels' user list. */
48   silc_hash_table_list(client->channels, &htl);
49   while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
50     channel = chl->channel;
51
52     /* Remove channel from client's channel list */
53     silc_hash_table_del(client->channels, channel);
54
55     /* Remove channel if there is no users anymore */
56     if (server->server_type == SILC_ROUTER &&
57         silc_hash_table_count(channel->user_list) < 2) {
58
59       if (silc_hash_table_find(channels, channel, NULL, NULL))
60         silc_hash_table_del(channels, channel);
61
62       if (channel->rekey)
63         silc_schedule_task_del_by_context(server->schedule, channel->rekey);
64
65       if (silc_idlist_del_channel(server->local_list, channel))
66         server->stat.my_channels--;
67       else 
68         silc_idlist_del_channel(server->global_list, channel);
69       continue;
70     }
71
72     /* Remove client from channel's client list */
73     silc_hash_table_del(channel->user_list, chl->client);
74
75     /* If there is no global users on the channel anymore mark the channel
76        as local channel. Do not check if the removed client is local client. */
77     if (server->server_type != SILC_ROUTER && channel->global_users && 
78         chl->client->router && !silc_server_channel_has_global(channel))
79       channel->global_users = FALSE;
80
81     silc_free(chl);
82     server->stat.my_chanclients--;
83
84     /* If there is not at least one local user on the channel then we don't
85        need the channel entry anymore, we can remove it safely. */
86     if (server->server_type != SILC_ROUTER &&
87         !silc_server_channel_has_local(channel)) {
88
89       if (silc_hash_table_find(channels, channel, NULL, NULL))
90         silc_hash_table_del(channels, channel);
91
92       if (channel->rekey)
93         silc_schedule_task_del_by_context(server->schedule, channel->rekey);
94
95       if (channel->founder_key) {
96         /* The founder auth data exists, do not remove the channel entry */
97         SilcChannelClientEntry chl2;
98         SilcHashTableList htl2;
99
100         channel->disabled = TRUE;
101
102         silc_hash_table_list(channel->user_list, &htl2);
103         while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
104           silc_hash_table_del(chl2->client->channels, channel);
105           silc_hash_table_del(channel->user_list, chl2->client);
106           silc_free(chl2);
107         }
108         continue;
109       }
110
111       /* Remove the channel entry */
112       if (silc_idlist_del_channel(server->local_list, channel))
113         server->stat.my_channels--;
114       else 
115         silc_idlist_del_channel(server->global_list, channel);
116       continue;
117     }
118
119     /* Add the channel to the the channels list to regenerate the 
120        channel key */
121     if (!silc_hash_table_find(channels, channel, NULL, NULL))
122       silc_hash_table_add(channels, channel, channel);
123   }
124
125   silc_buffer_free(clidp);
126 }
127
128 /* This function is used to remove all client entries by the server `entry'.
129    This is called when the connection is lost to the server. In this case
130    we must invalidate all the client entries owned by the server `entry'. 
131    If the `server_signoff' is TRUE then the SERVER_SIGNOFF notify is
132    distributed to our local clients. */
133
134 bool silc_server_remove_clients_by_server(SilcServer server, 
135                                           SilcServerEntry entry,
136                                           bool server_signoff)
137 {
138   SilcIDCacheList list = NULL;
139   SilcIDCacheEntry id_cache = NULL;
140   SilcClientEntry client = NULL;
141   SilcBuffer idp;
142   SilcClientEntry *clients = NULL;
143   uint32 clients_c = 0;
144   unsigned char **argv = NULL;
145   uint32 *argv_lens = NULL, *argv_types = NULL, argc = 0;
146   SilcHashTableList htl;
147   SilcChannelEntry channel;
148   SilcHashTable channels;
149   int i;
150
151   SILC_LOG_DEBUG(("Start"));
152
153   /* Allocate the hash table that holds the channels that require
154      channel key re-generation after we've removed this server's clients
155      from the channels. */
156   channels = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL, NULL,
157                                    NULL, NULL, TRUE);
158
159   if (server_signoff) {
160     idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
161     argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
162     argv_lens = silc_realloc(argv_lens,  sizeof(*argv_lens) * (argc + 1));
163     argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
164     argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
165     memcpy(argv[argc], idp->data, idp->len);
166     argv_lens[argc] = idp->len;
167     argv_types[argc] = argc + 1;
168     argc++;
169     silc_buffer_free(idp);
170   }
171
172   if (silc_idcache_get_all(server->local_list->clients, &list)) {
173
174     if (silc_idcache_list_first(list, &id_cache)) {
175       while (id_cache) {
176         client = (SilcClientEntry)id_cache->context;
177         if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
178           if (!silc_idcache_list_next(list, &id_cache))
179             break;
180           else
181             continue;
182         }
183
184         if (client->router != entry) {
185           if (server_signoff) {
186             clients = silc_realloc(clients, 
187                                    sizeof(*clients) * (clients_c + 1));
188             clients[clients_c] = client;
189             clients_c++;
190           }
191
192           if (!silc_idcache_list_next(list, &id_cache))
193             break;
194           else
195             continue;
196         }
197
198         if (server_signoff) {
199           idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
200           argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
201           argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
202                                    (argc + 1));
203           argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
204                                     (argc + 1));
205           argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
206           memcpy(argv[argc], idp->data, idp->len);
207           argv_lens[argc] = idp->len;
208           argv_types[argc] = argc + 1;
209           argc++;
210           silc_buffer_free(idp);
211         }
212
213         /* Remove the client entry */
214         silc_server_remove_clients_channels(server, NULL, client, channels);
215         silc_idlist_del_client(server->local_list, client);
216
217         if (!silc_idcache_list_next(list, &id_cache))
218           break;
219       }
220     }
221     silc_idcache_list_free(list);
222   }
223   
224   if (silc_idcache_get_all(server->global_list->clients, &list)) {
225
226     if (silc_idcache_list_first(list, &id_cache)) {
227       while (id_cache) {
228         client = (SilcClientEntry)id_cache->context;
229         if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
230           if (!silc_idcache_list_next(list, &id_cache))
231             break;
232           else
233             continue;
234         }
235         
236         if (client->router != entry) {
237           if (server_signoff && client->connection) {
238             clients = silc_realloc(clients, 
239                                    sizeof(*clients) * (clients_c + 1));
240             clients[clients_c] = client;
241             clients_c++;
242           }
243
244           if (!silc_idcache_list_next(list, &id_cache))
245             break;
246           else
247             continue;
248         }
249
250         if (server_signoff) {
251           idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
252           argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
253           argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
254                                    (argc + 1));
255           argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
256                                     (argc + 1));
257           argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
258           memcpy(argv[argc], idp->data, idp->len);
259           argv_lens[argc] = idp->len;
260           argv_types[argc] = argc + 1;
261           argc++;
262           silc_buffer_free(idp);
263         }
264
265         /* Remove the client entry */
266         silc_server_remove_clients_channels(server, NULL, client, channels);
267         silc_idlist_del_client(server->global_list, client);
268
269         if (!silc_idcache_list_next(list, &id_cache))
270           break;
271       }
272     }
273     silc_idcache_list_free(list);
274   }
275
276   /* Send the SERVER_SIGNOFF notify */
277   if (server_signoff) {
278     SilcBuffer args, not;
279
280     /* Send SERVER_SIGNOFF notify to our primary router */
281     if (!server->standalone && server->router &&
282         server->router != entry) {
283       args = silc_argument_payload_encode(1, argv, argv_lens,
284                                           argv_types);
285       silc_server_send_notify_args(server, 
286                                    server->router->connection,
287                                    server->server_type == SILC_SERVER ? 
288                                    FALSE : TRUE, 
289                                    SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
290                                    argc, args);
291       silc_buffer_free(args);
292     }
293
294     /* Send to local clients */
295     args = silc_argument_payload_encode(argc, argv, argv_lens,
296                                         argv_types);
297     not = silc_notify_payload_encode_args(SILC_NOTIFY_TYPE_SERVER_SIGNOFF, 
298                                           argc, args);
299     silc_server_packet_send_clients(server, clients, clients_c,
300                                     SILC_PACKET_NOTIFY, 0, FALSE,
301                                     not->data, not->len, FALSE);
302
303     silc_free(clients);
304     silc_buffer_free(args);
305     silc_buffer_free(not);
306     for (i = 0; i < argc; i++)
307       silc_free(argv[i]);
308     silc_free(argv);
309     silc_free(argv_lens);
310     silc_free(argv_types);
311   }
312
313   /* We must now re-generate the channel key for all channels that had
314      this server's client(s) on the channel. As they left the channel we
315      must re-generate the channel key. */
316   silc_hash_table_list(channels, &htl);
317   while (silc_hash_table_get(&htl, NULL, (void *)&channel)) {
318     if (!silc_server_create_channel_key(server, channel, 0))
319       return FALSE;
320
321     /* Do not send the channel key if private channel key mode is set */
322     if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY)
323       continue;
324
325     silc_server_send_channel_key(server, NULL, channel, 
326                                  server->server_type == SILC_ROUTER ? 
327                                  FALSE : !server->standalone);
328   }
329   silc_hash_table_free(channels);
330
331   return TRUE;
332 }
333
334 static SilcServerEntry
335 silc_server_update_clients_by_real_server(SilcServer server,
336                                           SilcServerEntry from,
337                                           SilcClientEntry client,
338                                           bool local,
339                                           SilcIDCacheEntry client_cache)
340 {
341   SilcServerEntry server_entry;
342   SilcIDCacheEntry id_cache = NULL;
343   SilcIDCacheList list;
344
345   if (!silc_idcache_get_all(server->local_list->servers, &list))
346     return NULL;
347
348   if (silc_idcache_list_first(list, &id_cache)) {
349     while (id_cache) {
350       server_entry = (SilcServerEntry)id_cache->context;
351       if (server_entry != from &&
352           SILC_ID_COMPARE(server_entry->id, client->id, 
353                           client->id->ip.data_len)) {
354         SILC_LOG_DEBUG(("Found (local) %s",
355                         silc_id_render(server_entry->id, SILC_ID_SERVER)));
356
357         if (!server_entry->data.send_key && server_entry->router) {
358           SILC_LOG_DEBUG(("Server not locally connected, use its router"));
359           /* If the client is not marked as local then move it to local list
360              since the server is local. */
361           if (!local) {
362             SILC_LOG_DEBUG(("Moving client to local list"));
363             silc_idcache_add(server->local_list->clients, client_cache->name,
364                              client_cache->id, client_cache->context,
365                              client_cache->expire);
366             silc_idcache_del_by_context(server->global_list->clients, client);
367           }
368           server_entry = server_entry->router;
369         } else {
370           /* If the client is not marked as local then move it to local list
371              since the server is local. */
372           if (server_entry->server_type != SILC_BACKUP_ROUTER && !local) {
373             SILC_LOG_DEBUG(("Moving client to local list"));
374             silc_idcache_add(server->local_list->clients, client_cache->name,
375                              client_cache->id, client_cache->context,
376                              client_cache->expire);
377             silc_idcache_del_by_context(server->global_list->clients, client);
378           }
379         }
380
381         silc_idcache_list_free(list);
382         return server_entry;
383       }
384
385       if (!silc_idcache_list_next(list, &id_cache))
386         break;
387     }
388   }
389
390   silc_idcache_list_free(list);
391
392   if (!silc_idcache_get_all(server->global_list->servers, &list))
393     return NULL;
394
395   if (silc_idcache_list_first(list, &id_cache)) {
396     while (id_cache) {
397       server_entry = (SilcServerEntry)id_cache->context;
398       if (server_entry != from &&
399           SILC_ID_COMPARE(server_entry->id, client->id, 
400                           client->id->ip.data_len)) {
401         SILC_LOG_DEBUG(("Found (global) %s",
402                         silc_id_render(server_entry->id, SILC_ID_SERVER)));
403
404         if (!server_entry->data.send_key && server_entry->router) {
405           SILC_LOG_DEBUG(("Server not locally connected, use its router"));
406           /* If the client is marked as local then move it to global list
407              since the server is global. */
408           if (local) {
409             SILC_LOG_DEBUG(("Moving client to global list"));
410             silc_idcache_add(server->global_list->clients, client_cache->name,
411                              client_cache->id, client_cache->context,
412                              client_cache->expire);
413             silc_idcache_del_by_context(server->local_list->clients, client);
414           }
415           server_entry = server_entry->router;
416         } else {
417           /* If the client is marked as local then move it to global list
418              since the server is global. */
419           if (server_entry->server_type != SILC_BACKUP_ROUTER && local) {
420             SILC_LOG_DEBUG(("Moving client to global list"));
421             silc_idcache_add(server->global_list->clients, client_cache->name,
422                              client_cache->id, client_cache->context,
423                              client_cache->expire);
424             silc_idcache_del_by_context(server->local_list->clients, client);
425           }
426         }
427
428         silc_idcache_list_free(list);
429         return server_entry;
430       }
431
432       if (!silc_idcache_list_next(list, &id_cache))
433         break;
434     }
435   }
436
437   silc_idcache_list_free(list);
438
439   return NULL;
440 }
441
442 /* Updates the clients that are originated from the `from' to be originated
443    from the `to'. If the `resolve_real_server' is TRUE then this will
444    attempt to figure out which clients really are originated from the
445    `from' and which are originated from a server that we have connection
446    to, when we've acting as backup router. If it is FALSE the `to' will
447    be the new source. This function also removes the clients that are
448    *really* originated from `from' if `remove_from' is TRUE. These are
449    clients that the `from' owns, and not just clients that are behind
450    the `from'. */
451
452 void silc_server_update_clients_by_server(SilcServer server, 
453                                           SilcServerEntry from,
454                                           SilcServerEntry to,
455                                           bool resolve_real_server,
456                                           bool remove_from)
457 {
458   SilcIDCacheList list = NULL;
459   SilcIDCacheEntry id_cache = NULL;
460   SilcClientEntry client = NULL;
461   bool local;
462
463   SILC_LOG_DEBUG(("Start"));
464
465   SILC_LOG_DEBUG(("Updating %s", silc_id_render(from->id,
466                                                 SILC_ID_SERVER)));
467   SILC_LOG_DEBUG(("to %s", silc_id_render(to->id,
468                                           SILC_ID_SERVER)));
469
470
471   local = FALSE;
472   if (silc_idcache_get_all(server->global_list->clients, &list)) {
473     if (silc_idcache_list_first(list, &id_cache)) {
474       while (id_cache) {
475         client = (SilcClientEntry)id_cache->context;
476         
477
478         if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
479           if (!silc_idcache_list_next(list, &id_cache))
480             break;
481           else
482             continue;
483         }
484
485         SILC_LOG_DEBUG(("Client (global) %s", 
486                         silc_id_render(client->id, SILC_ID_CLIENT)));
487         if (client->router)
488           SILC_LOG_DEBUG(("Client->router (global) %s", 
489                           silc_id_render(client->router->id, SILC_ID_SERVER)));
490
491         if (client->router == from) {
492           /* Skip clients that are *really* owned by the `from' */
493           if (remove_from && SILC_ID_COMPARE(from->id, client->id, 
494                                              client->id->ip.data_len)) {
495             SILC_LOG_DEBUG(("Found really owned client, skip it"));
496             if (!silc_idcache_list_next(list, &id_cache))
497               break;
498             else
499               continue;
500           }
501
502           if (resolve_real_server) {
503             client->router = 
504               silc_server_update_clients_by_real_server(server, from, client,
505                                                         local, id_cache);
506             if (!client->router)
507               client->router = to;
508           } else {
509             client->router = to;
510           }
511         }
512
513         if (!silc_idcache_list_next(list, &id_cache))
514           break;
515       }
516     }
517     silc_idcache_list_free(list);
518   }
519
520   local = TRUE;
521   if (silc_idcache_get_all(server->local_list->clients, &list)) {
522     if (silc_idcache_list_first(list, &id_cache)) {
523       while (id_cache) {
524         client = (SilcClientEntry)id_cache->context;
525
526         if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
527           if (!silc_idcache_list_next(list, &id_cache))
528             break;
529           else
530             continue;
531         }
532
533         SILC_LOG_DEBUG(("Client (local) %s", 
534                         silc_id_render(client->id, SILC_ID_CLIENT)));
535         if (client->router)
536           SILC_LOG_DEBUG(("Client->router (local) %s", 
537                           silc_id_render(client->router->id, SILC_ID_SERVER)));
538
539         if (client->router == from) {
540           /* Skip clients that are *really* owned by the `from' */
541           if (remove_from && SILC_ID_COMPARE(from->id, client->id, 
542                                              client->id->ip.data_len)) {
543             SILC_LOG_DEBUG(("Found really owned client, skip it"));
544             if (!silc_idcache_list_next(list, &id_cache))
545               break;
546             else
547               continue;
548           }
549
550           if (resolve_real_server) {
551             client->router = 
552               silc_server_update_clients_by_real_server(server, from, client,
553                                                         local, id_cache);
554             if (!client->router)
555               client->router = from; /* on local list put old from */
556           } else {
557             client->router = to;
558           }
559         }
560
561         if (!silc_idcache_list_next(list, &id_cache))
562           break;
563       }
564     }
565     silc_idcache_list_free(list);
566   }
567
568   if (remove_from)
569     /* Now remove the clients that are still marked as orignated from the
570        `from'. These are the clients that really was owned by the `from' and
571        not just exist behind the `from'. */
572     silc_server_remove_clients_by_server(server, from, TRUE);
573 }
574
575 /* Updates servers that are from `from' to be originated from `to'.  This
576    will also update the server's connection to `to's connection. */
577
578 void silc_server_update_servers_by_server(SilcServer server, 
579                                           SilcServerEntry from,
580                                           SilcServerEntry to)
581 {
582   SilcIDCacheList list = NULL;
583   SilcIDCacheEntry id_cache = NULL;
584   SilcServerEntry server_entry = NULL;
585
586   SILC_LOG_DEBUG(("Start"));
587
588   if (silc_idcache_get_all(server->local_list->servers, &list)) {
589     if (silc_idcache_list_first(list, &id_cache)) {
590       while (id_cache) {
591         server_entry = (SilcServerEntry)id_cache->context;
592         if (server_entry->router == from) {
593           server_entry->router = to;
594           server_entry->connection = to->connection;
595         }
596         if (!silc_idcache_list_next(list, &id_cache))
597           break;
598       }
599     }
600     silc_idcache_list_free(list);
601   }
602
603   if (silc_idcache_get_all(server->global_list->servers, &list)) {
604     if (silc_idcache_list_first(list, &id_cache)) {
605       while (id_cache) {
606         server_entry = (SilcServerEntry)id_cache->context;
607         if (server_entry->router == from) {
608           server_entry->router = to;
609           server_entry->connection = to->connection;
610         }
611         if (!silc_idcache_list_next(list, &id_cache))
612           break;
613       }
614     }
615     silc_idcache_list_free(list);
616   }
617 }
618
619 /* Checks whether given channel has global users.  If it does this returns
620    TRUE and FALSE if there is only locally connected clients on the channel. */
621
622 bool silc_server_channel_has_global(SilcChannelEntry channel)
623 {
624   SilcChannelClientEntry chl;
625   SilcHashTableList htl;
626
627   silc_hash_table_list(channel->user_list, &htl);
628   while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
629     if (chl->client->router)
630       return TRUE;
631   }
632
633   return FALSE;
634 }
635
636 /* Checks whether given channel has locally connected users.  If it does this
637    returns TRUE and FALSE if there is not one locally connected client. */
638
639 bool silc_server_channel_has_local(SilcChannelEntry channel)
640 {
641   SilcChannelClientEntry chl;
642   SilcHashTableList htl;
643
644   silc_hash_table_list(channel->user_list, &htl);
645   while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
646     if (!chl->client->router)
647       return TRUE;
648   }
649
650   return FALSE;
651 }
652
653 /* Returns TRUE if the given client is on the channel.  FALSE if not. 
654    This works because we assure that the user list on the channel is
655    always in up to date thus we can only check the channel list from 
656    `client' which is faster than checking the user list from `channel'. */
657
658 bool silc_server_client_on_channel(SilcClientEntry client,
659                                    SilcChannelEntry channel)
660 {
661   if (!client || !channel)
662     return FALSE;
663
664   if (silc_hash_table_find(client->channels, channel, NULL, NULL))
665     return TRUE;
666
667   return FALSE;
668 }