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 /* Remove the client entry */
214 silc_server_remove_clients_channels(server, NULL, client, channels);
215 if (!server_signoff) {
216 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
217 id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
219 silc_idlist_del_client(server->local_list, client);
221 server->stat.clients--;
222 if (server->server_type == SILC_ROUTER)
223 server->stat.cell_clients--;
225 if (!silc_idcache_list_next(list, &id_cache))
229 silc_idcache_list_free(list);
232 if (silc_idcache_get_all(server->global_list->clients, &list)) {
234 if (silc_idcache_list_first(list, &id_cache)) {
236 client = (SilcClientEntry)id_cache->context;
237 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
238 if (!silc_idcache_list_next(list, &id_cache))
244 if (client->router != entry) {
245 if (server_signoff && client->connection) {
246 clients = silc_realloc(clients,
247 sizeof(*clients) * (clients_c + 1));
248 clients[clients_c] = client;
252 if (!silc_idcache_list_next(list, &id_cache))
258 if (server_signoff) {
259 idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
260 argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
261 argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
263 argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
265 argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
266 memcpy(argv[argc], idp->data, idp->len);
267 argv_lens[argc] = idp->len;
268 argv_types[argc] = argc + 1;
270 silc_buffer_free(idp);
273 /* Remove the client entry */
274 silc_server_remove_clients_channels(server, NULL, client, channels);
275 if (!server_signoff) {
276 client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
277 id_cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
279 silc_idlist_del_client(server->global_list, client);
281 server->stat.clients--;
282 if (server->server_type == SILC_ROUTER)
283 server->stat.cell_clients--;
285 if (!silc_idcache_list_next(list, &id_cache))
289 silc_idcache_list_free(list);
292 /* Send the SERVER_SIGNOFF notify */
293 if (server_signoff) {
294 SilcBuffer args, not;
296 /* Send SERVER_SIGNOFF notify to our primary router */
297 if (!server->standalone && server->router &&
298 server->router != entry) {
299 args = silc_argument_payload_encode(1, argv, argv_lens,
301 silc_server_send_notify_args(server,
302 server->router->connection,
303 server->server_type == SILC_SERVER ?
305 SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
307 silc_buffer_free(args);
310 /* Send to local clients. We also send the list of client ID's that
311 is to be removed for those servers that would like to use that list. */
312 args = silc_argument_payload_encode(argc, argv, argv_lens,
314 not = silc_notify_payload_encode_args(SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
316 silc_server_packet_send_clients(server, clients, clients_c,
317 SILC_PACKET_NOTIFY, 0, FALSE,
318 not->data, not->len, FALSE);
321 silc_buffer_free(args);
322 silc_buffer_free(not);
323 for (i = 0; i < argc; i++)
326 silc_free(argv_lens);
327 silc_free(argv_types);
330 /* We must now re-generate the channel key for all channels that had
331 this server's client(s) on the channel. As they left the channel we
332 must re-generate the channel key. */
333 silc_hash_table_list(channels, &htl);
334 while (silc_hash_table_get(&htl, NULL, (void *)&channel)) {
335 if (!silc_server_create_channel_key(server, channel, 0))
338 /* Do not send the channel key if private channel key mode is set */
339 if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY)
342 silc_server_send_channel_key(server, NULL, channel,
343 server->server_type == SILC_ROUTER ?
344 FALSE : !server->standalone);
346 silc_hash_table_free(channels);
351 static SilcServerEntry
352 silc_server_update_clients_by_real_server(SilcServer server,
353 SilcServerEntry from,
354 SilcClientEntry client,
356 SilcIDCacheEntry client_cache)
358 SilcServerEntry server_entry;
359 SilcIDCacheEntry id_cache = NULL;
360 SilcIDCacheList list;
362 if (!silc_idcache_get_all(server->local_list->servers, &list))
365 if (silc_idcache_list_first(list, &id_cache)) {
367 server_entry = (SilcServerEntry)id_cache->context;
368 if (server_entry != from &&
369 SILC_ID_COMPARE(server_entry->id, client->id,
370 client->id->ip.data_len)) {
371 SILC_LOG_DEBUG(("Found (local) %s",
372 silc_id_render(server_entry->id, SILC_ID_SERVER)));
374 if (!server_entry->data.send_key && server_entry->router) {
375 SILC_LOG_DEBUG(("Server not locally connected, use its router"));
376 /* If the client is not marked as local then move it to local list
377 since the server is local. */
379 SILC_LOG_DEBUG(("Moving client to local list"));
380 silc_idcache_add(server->local_list->clients, client_cache->name,
381 client_cache->id, client_cache->context,
382 client_cache->expire, NULL);
383 silc_idcache_del_by_context(server->global_list->clients, client);
385 server_entry = server_entry->router;
387 /* If the client is not marked as local then move it to local list
388 since the server is local. */
389 if (server_entry->server_type != SILC_BACKUP_ROUTER && !local) {
390 SILC_LOG_DEBUG(("Moving client to local list"));
391 silc_idcache_add(server->local_list->clients, client_cache->name,
392 client_cache->id, client_cache->context,
393 client_cache->expire, NULL);
394 silc_idcache_del_by_context(server->global_list->clients, client);
398 silc_idcache_list_free(list);
402 if (!silc_idcache_list_next(list, &id_cache))
407 silc_idcache_list_free(list);
409 if (!silc_idcache_get_all(server->global_list->servers, &list))
412 if (silc_idcache_list_first(list, &id_cache)) {
414 server_entry = (SilcServerEntry)id_cache->context;
415 if (server_entry != from &&
416 SILC_ID_COMPARE(server_entry->id, client->id,
417 client->id->ip.data_len)) {
418 SILC_LOG_DEBUG(("Found (global) %s",
419 silc_id_render(server_entry->id, SILC_ID_SERVER)));
421 if (!server_entry->data.send_key && server_entry->router) {
422 SILC_LOG_DEBUG(("Server not locally connected, use its router"));
423 /* If the client is marked as local then move it to global list
424 since the server is global. */
426 SILC_LOG_DEBUG(("Moving client to global list"));
427 silc_idcache_add(server->global_list->clients, client_cache->name,
428 client_cache->id, client_cache->context,
429 client_cache->expire, NULL);
430 silc_idcache_del_by_context(server->local_list->clients, client);
432 server_entry = server_entry->router;
434 /* If the client is marked as local then move it to global list
435 since the server is global. */
436 if (server_entry->server_type != SILC_BACKUP_ROUTER && local) {
437 SILC_LOG_DEBUG(("Moving client to global list"));
438 silc_idcache_add(server->global_list->clients, client_cache->name,
439 client_cache->id, client_cache->context,
440 client_cache->expire, NULL);
441 silc_idcache_del_by_context(server->local_list->clients, client);
445 silc_idcache_list_free(list);
449 if (!silc_idcache_list_next(list, &id_cache))
454 silc_idcache_list_free(list);
459 /* Updates the clients that are originated from the `from' to be originated
460 from the `to'. If the `resolve_real_server' is TRUE then this will
461 attempt to figure out which clients really are originated from the
462 `from' and which are originated from a server that we have connection
463 to, when we've acting as backup router. If it is FALSE the `to' will
464 be the new source. This function also removes the clients that are
465 *really* originated from `from' if `remove_from' is TRUE. These are
466 clients that the `from' owns, and not just clients that are behind
469 void silc_server_update_clients_by_server(SilcServer server,
470 SilcServerEntry from,
472 bool resolve_real_server,
475 SilcIDCacheList list = NULL;
476 SilcIDCacheEntry id_cache = NULL;
477 SilcClientEntry client = NULL;
480 SILC_LOG_DEBUG(("Start"));
482 SILC_LOG_DEBUG(("Updating %s", silc_id_render(from->id,
484 SILC_LOG_DEBUG(("to %s", silc_id_render(to->id,
489 if (silc_idcache_get_all(server->global_list->clients, &list)) {
490 if (silc_idcache_list_first(list, &id_cache)) {
492 client = (SilcClientEntry)id_cache->context;
493 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
494 if (!silc_idcache_list_next(list, &id_cache))
500 SILC_LOG_DEBUG(("Client (global) %s",
501 silc_id_render(client->id, SILC_ID_CLIENT)));
503 SILC_LOG_DEBUG(("Client->router (global) %s",
504 silc_id_render(client->router->id, SILC_ID_SERVER)));
506 if (client->router == from) {
507 /* Skip clients that are *really* owned by the `from' */
508 if (remove_from && SILC_ID_COMPARE(from->id, client->id,
509 client->id->ip.data_len)) {
510 SILC_LOG_DEBUG(("Found really owned client, skip it"));
511 if (!silc_idcache_list_next(list, &id_cache))
517 if (resolve_real_server) {
519 silc_server_update_clients_by_real_server(server, from, client,
528 if (!silc_idcache_list_next(list, &id_cache))
532 silc_idcache_list_free(list);
536 if (silc_idcache_get_all(server->local_list->clients, &list)) {
537 if (silc_idcache_list_first(list, &id_cache)) {
539 client = (SilcClientEntry)id_cache->context;
540 if (!(client->data.status & SILC_IDLIST_STATUS_REGISTERED)) {
541 if (!silc_idcache_list_next(list, &id_cache))
547 SILC_LOG_DEBUG(("Client (local) %s",
548 silc_id_render(client->id, SILC_ID_CLIENT)));
550 SILC_LOG_DEBUG(("Client->router (local) %s",
551 silc_id_render(client->router->id, SILC_ID_SERVER)));
553 if (client->router == from) {
554 /* Skip clients that are *really* owned by the `from' */
555 if (remove_from && SILC_ID_COMPARE(from->id, client->id,
556 client->id->ip.data_len)) {
557 SILC_LOG_DEBUG(("Found really owned client, skip it"));
558 if (!silc_idcache_list_next(list, &id_cache))
564 if (resolve_real_server) {
566 silc_server_update_clients_by_real_server(server, from, client,
569 client->router = from; /* on local list put old from */
575 if (!silc_idcache_list_next(list, &id_cache))
579 silc_idcache_list_free(list);
583 /* Now remove the clients that are still marked as orignated from the
584 `from'. These are the clients that really was owned by the `from' and
585 not just exist behind the `from'. */
586 silc_server_remove_clients_by_server(server, from, TRUE);
589 /* Updates servers that are from `from' to be originated from `to'. This
590 will also update the server's connection to `to's connection. */
592 void silc_server_update_servers_by_server(SilcServer server,
593 SilcServerEntry from,
596 SilcIDCacheList list = NULL;
597 SilcIDCacheEntry id_cache = NULL;
598 SilcServerEntry server_entry = NULL;
600 SILC_LOG_DEBUG(("Start"));
602 if (silc_idcache_get_all(server->local_list->servers, &list)) {
603 if (silc_idcache_list_first(list, &id_cache)) {
605 server_entry = (SilcServerEntry)id_cache->context;
606 if (server_entry->router == from) {
607 server_entry->router = to;
608 server_entry->connection = to->connection;
610 if (!silc_idcache_list_next(list, &id_cache))
614 silc_idcache_list_free(list);
617 if (silc_idcache_get_all(server->global_list->servers, &list)) {
618 if (silc_idcache_list_first(list, &id_cache)) {
620 server_entry = (SilcServerEntry)id_cache->context;
621 if (server_entry->router == from) {
622 server_entry->router = to;
623 server_entry->connection = to->connection;
625 if (!silc_idcache_list_next(list, &id_cache))
629 silc_idcache_list_free(list);
633 /* Removes channels that are from `from. */
635 void silc_server_remove_channels_by_server(SilcServer server,
636 SilcServerEntry from)
638 SilcIDCacheList list = NULL;
639 SilcIDCacheEntry id_cache = NULL;
640 SilcChannelEntry channel = NULL;
642 SILC_LOG_DEBUG(("Start"));
644 if (silc_idcache_get_all(server->global_list->channels, &list)) {
645 if (silc_idcache_list_first(list, &id_cache)) {
647 channel = (SilcChannelEntry)id_cache->context;
648 if (channel->router == from)
649 silc_idlist_del_channel(server->global_list, channel);
650 if (!silc_idcache_list_next(list, &id_cache))
654 silc_idcache_list_free(list);
658 /* Updates channels that are from `from' to be originated from `to'. */
660 void silc_server_update_channels_by_server(SilcServer server,
661 SilcServerEntry from,
664 SilcIDCacheList list = NULL;
665 SilcIDCacheEntry id_cache = NULL;
666 SilcChannelEntry channel = NULL;
668 SILC_LOG_DEBUG(("Start"));
670 if (silc_idcache_get_all(server->global_list->channels, &list)) {
671 if (silc_idcache_list_first(list, &id_cache)) {
673 channel = (SilcChannelEntry)id_cache->context;
674 if (channel->router == from)
675 channel->router = to;
676 if (!silc_idcache_list_next(list, &id_cache))
680 silc_idcache_list_free(list);
684 /* Checks whether given channel has global users. If it does this returns
685 TRUE and FALSE if there is only locally connected clients on the channel. */
687 bool silc_server_channel_has_global(SilcChannelEntry channel)
689 SilcChannelClientEntry chl;
690 SilcHashTableList htl;
692 silc_hash_table_list(channel->user_list, &htl);
693 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
694 if (chl->client->router)
701 /* Checks whether given channel has locally connected users. If it does this
702 returns TRUE and FALSE if there is not one locally connected client. */
704 bool silc_server_channel_has_local(SilcChannelEntry channel)
706 SilcChannelClientEntry chl;
707 SilcHashTableList htl;
709 silc_hash_table_list(channel->user_list, &htl);
710 while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
711 if (!chl->client->router)
718 /* Returns TRUE if the given client is on the channel. FALSE if not.
719 This works because we assure that the user list on the channel is
720 always in up to date thus we can only check the channel list from
721 `client' which is faster than checking the user list from `channel'. */
723 bool silc_server_client_on_channel(SilcClientEntry client,
724 SilcChannelEntry channel)
726 if (!client || !channel)
729 if (silc_hash_table_find(client->channels, channel, NULL, NULL))
735 /* Checks string for bad characters and returns TRUE if they are found. */
737 bool silc_server_name_bad_chars(const char *name, uint32 name_len)
741 for (i = 0; i < name_len; i++) {
742 if (!isascii(name[i]))
744 if (name[i] <= 32) return TRUE;
745 if (name[i] == ' ') return TRUE;
746 if (name[i] == '*') return TRUE;
747 if (name[i] == '?') return TRUE;
748 if (name[i] == ',') return TRUE;
754 /* Modifies the `name' if it includes bad characters and returns new
755 allocated name that does not include bad characters. */
757 char *silc_server_name_modify_bad(const char *name, uint32 name_len)
760 char *newname = strdup(name);
762 for (i = 0; i < name_len; i++) {
763 if (!isascii(newname[i])) newname[i] = '_';
764 if (newname[i] <= 32) newname[i] = '_';
765 if (newname[i] == ' ') newname[i] = '_';
766 if (newname[i] == '*') newname[i] = '_';
767 if (newname[i] == '?') newname[i] = '_';
768 if (newname[i] == ',') newname[i] = '_';