5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2001 Pekka Riikonen
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.
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.
21 #include "serverincludes.h"
22 #include "server_internal.h"
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. */
29 static void silc_server_remove_clients_channels(SilcServer server,
30 SilcSocketConnection sock,
31 SilcClientEntry client,
32 SilcHashTable channels)
34 SilcChannelEntry channel;
35 SilcChannelClientEntry chl;
36 SilcHashTableList htl;
39 SILC_LOG_DEBUG(("Start"));
41 if (!client || !client->id)
44 clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
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;
52 /* Remove channel from client's channel list */
53 silc_hash_table_del(client->channels, channel);
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) {
59 if (silc_hash_table_find(channels, channel, NULL, NULL))
60 silc_hash_table_del(channels, channel);
63 silc_schedule_task_del_by_context(server->schedule, channel->rekey);
65 if (silc_idlist_del_channel(server->local_list, channel))
66 server->stat.my_channels--;
68 silc_idlist_del_channel(server->global_list, channel);
72 /* Remove client from channel's client list */
73 silc_hash_table_del(channel->user_list, chl->client);
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;
82 server->stat.my_chanclients--;
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)) {
89 if (silc_hash_table_find(channels, channel, NULL, NULL))
90 silc_hash_table_del(channels, channel);
93 silc_schedule_task_del_by_context(server->schedule, channel->rekey);
95 if (channel->founder_key) {
96 /* The founder auth data exists, do not remove the channel entry */
97 SilcChannelClientEntry chl2;
98 SilcHashTableList htl2;
100 channel->disabled = TRUE;
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);
111 /* Remove the channel entry */
112 if (silc_idlist_del_channel(server->local_list, channel))
113 server->stat.my_channels--;
115 silc_idlist_del_channel(server->global_list, channel);
119 /* Add the channel to the the channels list to regenerate the
121 if (!silc_hash_table_find(channels, channel, NULL, NULL))
122 silc_hash_table_add(channels, channel, channel);
125 silc_buffer_free(clidp);
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. */
134 bool silc_server_remove_clients_by_server(SilcServer server,
135 SilcServerEntry entry,
138 SilcIDCacheList list = NULL;
139 SilcIDCacheEntry id_cache = NULL;
140 SilcClientEntry client = NULL;
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;
151 SILC_LOG_DEBUG(("Start"));
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,
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;
169 silc_buffer_free(idp);
172 if (silc_idcache_get_all(server->local_list->clients, &list)) {
174 if (silc_idcache_list_first(list, &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))
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;
192 if (!silc_idcache_list_next(list, &id_cache))
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) *
203 argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
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;
210 silc_buffer_free(idp);
213 /* Update statistics */
214 server->stat.clients--;
215 if (server->server_type == SILC_ROUTER)
216 server->stat.cell_clients--;
217 SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
218 SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
220 /* Remove the client entry */
221 silc_server_remove_clients_channels(server, NULL, client, channels);
222 if (!server_signoff) {
223 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
224 id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
226 silc_idlist_del_client(server->local_list, client);
229 if (!silc_idcache_list_next(list, &id_cache))
233 silc_idcache_list_free(list);
236 if (silc_idcache_get_all(server->global_list->clients, &list)) {
238 if (silc_idcache_list_first(list, &id_cache)) {
240 client = (SilcClientEntry)id_cache->context;
241 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
242 if (!silc_idcache_list_next(list, &id_cache))
248 if (client->router != entry) {
249 if (server_signoff && client->connection) {
250 clients = silc_realloc(clients,
251 sizeof(*clients) * (clients_c + 1));
252 clients[clients_c] = client;
256 if (!silc_idcache_list_next(list, &id_cache))
262 if (server_signoff) {
263 idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
264 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
265 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
267 argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
269 argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
270 memcpy(argv[argc], idp->data, idp->len);
271 argv_lens[argc] = idp->len;
272 argv_types[argc] = argc + 1;
274 silc_buffer_free(idp);
277 /* Update statistics */
278 server->stat.clients--;
279 if (server->server_type == SILC_ROUTER)
280 server->stat.cell_clients--;
281 SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
282 SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
284 /* Remove the client entry */
285 silc_server_remove_clients_channels(server, NULL, client, channels);
286 if (!server_signoff) {
287 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
288 id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
290 silc_idlist_del_client(server->global_list, client);
293 if (!silc_idcache_list_next(list, &id_cache))
297 silc_idcache_list_free(list);
300 /* Send the SERVER_SIGNOFF notify */
301 if (server_signoff) {
302 SilcBuffer args, not;
304 /* Send SERVER_SIGNOFF notify to our primary router */
305 if (!server->standalone && server->router &&
306 server->router != entry) {
307 args = silc_argument_payload_encode(1, argv, argv_lens,
309 silc_server_send_notify_args(server,
310 server->router->connection,
311 server->server_type == SILC_SERVER ?
313 SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
315 silc_buffer_free(args);
318 /* Send to local clients. We also send the list of client ID's that
319 is to be removed for those servers that would like to use that list. */
320 args = silc_argument_payload_encode(argc, argv, argv_lens,
322 not = silc_notify_payload_encode_args(SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
324 silc_server_packet_send_clients(server, clients, clients_c,
325 SILC_PACKET_NOTIFY, 0, FALSE,
326 not->data, not->len, FALSE);
329 silc_buffer_free(args);
330 silc_buffer_free(not);
331 for (i = 0; i < argc; i++)
334 silc_free(argv_lens);
335 silc_free(argv_types);
338 /* We must now re-generate the channel key for all channels that had
339 this server's client(s) on the channel. As they left the channel we
340 must re-generate the channel key. */
341 silc_hash_table_list(channels, &htl);
342 while (silc_hash_table_get(&htl, NULL, (void *)&channel)) {
343 if (!silc_server_create_channel_key(server, channel, 0))
346 /* Do not send the channel key if private channel key mode is set */
347 if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY)
350 silc_server_send_channel_key(server, NULL, channel,
351 server->server_type == SILC_ROUTER ?
352 FALSE : !server->standalone);
354 silc_hash_table_free(channels);
359 static SilcServerEntry
360 silc_server_update_clients_by_real_server(SilcServer server,
361 SilcServerEntry from,
362 SilcClientEntry client,
364 SilcIDCacheEntry client_cache)
366 SilcServerEntry server_entry;
367 SilcIDCacheEntry id_cache = NULL;
368 SilcIDCacheList list;
370 if (!silc_idcache_get_all(server->local_list->servers, &list))
373 if (silc_idcache_list_first(list, &id_cache)) {
375 server_entry = (SilcServerEntry)id_cache->context;
376 if (server_entry != from &&
377 SILC_ID_COMPARE(server_entry->id, client->id,
378 client->id->ip.data_len)) {
379 SILC_LOG_DEBUG(("Found (local) %s",
380 silc_id_render(server_entry->id, SILC_ID_SERVER)));
382 if (!server_entry->data.send_key && server_entry->router) {
383 SILC_LOG_DEBUG(("Server not locally connected, use its router"));
384 /* If the client is not marked as local then move it to local list
385 since the server is local. */
387 SILC_LOG_DEBUG(("Moving client to local list"));
388 silc_idcache_add(server->local_list->clients, client_cache->name,
389 client_cache->id, client_cache->context,
390 client_cache->expire, NULL);
391 silc_idcache_del_by_context(server->global_list->clients, client);
393 server_entry = server_entry->router;
395 /* If the client is not marked as local then move it to local list
396 since the server is local. */
397 if (server_entry->server_type != SILC_BACKUP_ROUTER && !local) {
398 SILC_LOG_DEBUG(("Moving client to local list"));
399 silc_idcache_add(server->local_list->clients, client_cache->name,
400 client_cache->id, client_cache->context,
401 client_cache->expire, NULL);
402 silc_idcache_del_by_context(server->global_list->clients, client);
406 silc_idcache_list_free(list);
410 if (!silc_idcache_list_next(list, &id_cache))
415 silc_idcache_list_free(list);
417 if (!silc_idcache_get_all(server->global_list->servers, &list))
420 if (silc_idcache_list_first(list, &id_cache)) {
422 server_entry = (SilcServerEntry)id_cache->context;
423 if (server_entry != from &&
424 SILC_ID_COMPARE(server_entry->id, client->id,
425 client->id->ip.data_len)) {
426 SILC_LOG_DEBUG(("Found (global) %s",
427 silc_id_render(server_entry->id, SILC_ID_SERVER)));
429 if (!server_entry->data.send_key && server_entry->router) {
430 SILC_LOG_DEBUG(("Server not locally connected, use its router"));
431 /* If the client is marked as local then move it to global list
432 since the server is global. */
434 SILC_LOG_DEBUG(("Moving client to global list"));
435 silc_idcache_add(server->global_list->clients, client_cache->name,
436 client_cache->id, client_cache->context,
437 client_cache->expire, NULL);
438 silc_idcache_del_by_context(server->local_list->clients, client);
440 server_entry = server_entry->router;
442 /* If the client is marked as local then move it to global list
443 since the server is global. */
444 if (server_entry->server_type != SILC_BACKUP_ROUTER && local) {
445 SILC_LOG_DEBUG(("Moving client to global list"));
446 silc_idcache_add(server->global_list->clients, client_cache->name,
447 client_cache->id, client_cache->context,
448 client_cache->expire, NULL);
449 silc_idcache_del_by_context(server->local_list->clients, client);
453 silc_idcache_list_free(list);
457 if (!silc_idcache_list_next(list, &id_cache))
462 silc_idcache_list_free(list);
467 /* Updates the clients that are originated from the `from' to be originated
468 from the `to'. If the `resolve_real_server' is TRUE then this will
469 attempt to figure out which clients really are originated from the
470 `from' and which are originated from a server that we have connection
471 to, when we've acting as backup router. If it is FALSE the `to' will
472 be the new source. This function also removes the clients that are
473 *really* originated from `from' if `remove_from' is TRUE. These are
474 clients that the `from' owns, and not just clients that are behind
477 void silc_server_update_clients_by_server(SilcServer server,
478 SilcServerEntry from,
480 bool resolve_real_server,
483 SilcIDCacheList list = NULL;
484 SilcIDCacheEntry id_cache = NULL;
485 SilcClientEntry client = NULL;
488 SILC_LOG_DEBUG(("Start"));
490 SILC_LOG_DEBUG(("Updating %s", silc_id_render(from->id,
492 SILC_LOG_DEBUG(("to %s", silc_id_render(to->id,
497 if (silc_idcache_get_all(server->global_list->clients, &list)) {
498 if (silc_idcache_list_first(list, &id_cache)) {
500 client = (SilcClientEntry)id_cache->context;
501 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
502 if (!silc_idcache_list_next(list, &id_cache))
508 SILC_LOG_DEBUG(("Client (global) %s",
509 silc_id_render(client->id, SILC_ID_CLIENT)));
511 SILC_LOG_DEBUG(("Client->router (global) %s",
512 silc_id_render(client->router->id, SILC_ID_SERVER)));
514 if (client->router == from) {
515 /* Skip clients that are *really* owned by the `from' */
516 if (remove_from && SILC_ID_COMPARE(from->id, client->id,
517 client->id->ip.data_len)) {
518 SILC_LOG_DEBUG(("Found really owned client, skip it"));
519 if (!silc_idcache_list_next(list, &id_cache))
525 if (resolve_real_server) {
527 silc_server_update_clients_by_real_server(server, from, client,
536 if (!silc_idcache_list_next(list, &id_cache))
540 silc_idcache_list_free(list);
544 if (silc_idcache_get_all(server->local_list->clients, &list)) {
545 if (silc_idcache_list_first(list, &id_cache)) {
547 client = (SilcClientEntry)id_cache->context;
548 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
549 if (!silc_idcache_list_next(list, &id_cache))
555 SILC_LOG_DEBUG(("Client (local) %s",
556 silc_id_render(client->id, SILC_ID_CLIENT)));
558 SILC_LOG_DEBUG(("Client->router (local) %s",
559 silc_id_render(client->router->id, SILC_ID_SERVER)));
561 if (client->router == from) {
562 /* Skip clients that are *really* owned by the `from' */
563 if (remove_from && SILC_ID_COMPARE(from->id, client->id,
564 client->id->ip.data_len)) {
565 SILC_LOG_DEBUG(("Found really owned client, skip it"));
566 if (!silc_idcache_list_next(list, &id_cache))
572 if (resolve_real_server) {
574 silc_server_update_clients_by_real_server(server, from, client,
577 client->router = from; /* on local list put old from */
583 if (!silc_idcache_list_next(list, &id_cache))
587 silc_idcache_list_free(list);
591 /* Now remove the clients that are still marked as orignated from the
592 `from'. These are the clients that really was owned by the `from' and
593 not just exist behind the `from'. */
594 silc_server_remove_clients_by_server(server, from, TRUE);
597 /* Updates servers that are from `from' to be originated from `to'. This
598 will also update the server's connection to `to's connection. */
600 void silc_server_update_servers_by_server(SilcServer server,
601 SilcServerEntry from,
604 SilcIDCacheList list = NULL;
605 SilcIDCacheEntry id_cache = NULL;
606 SilcServerEntry server_entry = NULL;
608 SILC_LOG_DEBUG(("Start"));
610 if (silc_idcache_get_all(server->local_list->servers, &list)) {
611 if (silc_idcache_list_first(list, &id_cache)) {
613 server_entry = (SilcServerEntry)id_cache->context;
614 if (server_entry->router == from) {
615 server_entry->router = to;
616 server_entry->connection = to->connection;
618 if (!silc_idcache_list_next(list, &id_cache))
622 silc_idcache_list_free(list);
625 if (silc_idcache_get_all(server->global_list->servers, &list)) {
626 if (silc_idcache_list_first(list, &id_cache)) {
628 server_entry = (SilcServerEntry)id_cache->context;
629 if (server_entry->router == from) {
630 server_entry->router = to;
631 server_entry->connection = to->connection;
633 if (!silc_idcache_list_next(list, &id_cache))
637 silc_idcache_list_free(list);
641 /* Removes channels that are from `from. */
643 void silc_server_remove_channels_by_server(SilcServer server,
644 SilcServerEntry from)
646 SilcIDCacheList list = NULL;
647 SilcIDCacheEntry id_cache = NULL;
648 SilcChannelEntry channel = NULL;
650 SILC_LOG_DEBUG(("Start"));
652 if (silc_idcache_get_all(server->global_list->channels, &list)) {
653 if (silc_idcache_list_first(list, &id_cache)) {
655 channel = (SilcChannelEntry)id_cache->context;
656 if (channel->router == from)
657 silc_idlist_del_channel(server->global_list, channel);
658 if (!silc_idcache_list_next(list, &id_cache))
662 silc_idcache_list_free(list);
666 /* Updates channels that are from `from' to be originated from `to'. */
668 void silc_server_update_channels_by_server(SilcServer server,
669 SilcServerEntry from,
672 SilcIDCacheList list = NULL;
673 SilcIDCacheEntry id_cache = NULL;
674 SilcChannelEntry channel = NULL;
676 SILC_LOG_DEBUG(("Start"));
678 if (silc_idcache_get_all(server->global_list->channels, &list)) {
679 if (silc_idcache_list_first(list, &id_cache)) {
681 channel = (SilcChannelEntry)id_cache->context;
682 if (channel->router == from)
683 channel->router = to;
684 if (!silc_idcache_list_next(list, &id_cache))
688 silc_idcache_list_free(list);
692 /* Checks whether given channel has global users. If it does this returns
693 TRUE and FALSE if there is only locally connected clients on the channel. */
695 bool silc_server_channel_has_global(SilcChannelEntry channel)
697 SilcChannelClientEntry chl;
698 SilcHashTableList htl;
700 silc_hash_table_list(channel->user_list, &htl);
701 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
702 if (chl->client->router)
709 /* Checks whether given channel has locally connected users. If it does this
710 returns TRUE and FALSE if there is not one locally connected client. */
712 bool silc_server_channel_has_local(SilcChannelEntry channel)
714 SilcChannelClientEntry chl;
715 SilcHashTableList htl;
717 silc_hash_table_list(channel->user_list, &htl);
718 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
719 if (!chl->client->router)
726 /* Returns TRUE if the given client is on the channel. FALSE if not.
727 This works because we assure that the user list on the channel is
728 always in up to date thus we can only check the channel list from
729 `client' which is faster than checking the user list from `channel'. */
731 bool silc_server_client_on_channel(SilcClientEntry client,
732 SilcChannelEntry channel)
734 if (!client || !channel)
737 return silc_hash_table_find(client->channels, channel, NULL, NULL);
740 /* Checks string for bad characters and returns TRUE if they are found. */
742 bool silc_server_name_bad_chars(const char *name, uint32 name_len)
746 for (i = 0; i < name_len; i++) {
747 if (!isascii(name[i]))
749 if (name[i] <= 32) return TRUE;
750 if (name[i] == ' ') return TRUE;
751 if (name[i] == '*') return TRUE;
752 if (name[i] == '?') return TRUE;
753 if (name[i] == ',') return TRUE;
759 /* Modifies the `name' if it includes bad characters and returns new
760 allocated name that does not include bad characters. */
762 char *silc_server_name_modify_bad(const char *name, uint32 name_len)
765 char *newname = strdup(name);
767 for (i = 0; i < name_len; i++) {
768 if (!isascii(newname[i])) newname[i] = '_';
769 if (newname[i] <= 32) newname[i] = '_';
770 if (newname[i] == ' ') newname[i] = '_';
771 if (newname[i] == '*') newname[i] = '_';
772 if (newname[i] == '?') newname[i] = '_';
773 if (newname[i] == ',') newname[i] = '_';