5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2005 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; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "serverincludes.h"
24 #include "server_internal.h"
26 /******************************************************************************
30 ******************************************************************************/
32 /* This function is used to add keys and stuff to common ID entry data
35 void silc_idlist_add_data(void *entry, SilcIDListData idata)
37 SilcIDListData data = (SilcIDListData)entry;
38 data->send_key = idata->send_key;
39 data->receive_key = idata->receive_key;
40 data->hmac_send = idata->hmac_send;
41 data->hmac_receive = idata->hmac_receive;
42 data->psn_send = idata->psn_send;
43 data->psn_receive = idata->psn_receive;
44 data->hash = idata->hash;
45 data->public_key = idata->public_key;
46 memcpy(data->fingerprint, idata->fingerprint, sizeof(data->fingerprint));
47 data->rekey = idata->rekey;
48 data->last_receive = idata->last_receive;
49 data->last_sent = idata->last_sent;
50 data->status = idata->status;
52 data->created = time(0); /* Update creation time */
55 /* Free's all data in the common ID entry data structure. */
57 void silc_idlist_del_data(void *entry)
59 SilcIDListData idata = (SilcIDListData)entry;
61 silc_cipher_free(idata->send_key);
62 if (idata->receive_key)
63 silc_cipher_free(idata->receive_key);
65 if (idata->rekey->send_enc_key) {
66 memset(idata->rekey->send_enc_key, 0, idata->rekey->enc_key_len);
67 silc_free(idata->rekey->send_enc_key);
69 silc_free(idata->rekey);
72 silc_hmac_free(idata->hmac_send);
73 if (idata->hmac_receive)
74 silc_hmac_free(idata->hmac_receive);
76 silc_hash_free(idata->hash);
77 if (idata->public_key)
78 silc_pkcs_public_key_free(idata->public_key);
80 idata->send_key = NULL;
81 idata->receive_key = NULL;
83 idata->hmac_send = NULL;
84 idata->hmac_receive = NULL;
86 idata->public_key = NULL;
91 SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge)
93 SilcServer server = app_context;
94 SilcIDListPurge i = (SilcIDListPurge)context;
96 SILC_LOG_DEBUG(("Purging cache"));
98 silc_idcache_purge(i->cache);
99 silc_schedule_task_add(server->schedule, 0, silc_idlist_purge,
100 (void *)i, i->timeout, 0,
101 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
104 /******************************************************************************
106 Server entry functions
108 ******************************************************************************/
110 /* Add new server entry. This adds the new server entry to ID cache and
111 returns the allocated entry object or NULL on error. This is called
112 when new server connects to us. We also add ourselves to cache with
116 silc_idlist_add_server(SilcIDList id_list,
117 char *server_name, int server_type,
118 SilcServerID *id, SilcServerEntry router,
121 SilcServerEntry server;
122 char *server_namec = NULL;
124 SILC_LOG_DEBUG(("Adding new server entry"));
126 /* Normalize name. This is cached, original is in server context. */
128 server_namec = silc_identifier_check(server_name, strlen(server_name),
129 SILC_STRING_UTF8, 256, NULL);
134 server = silc_calloc(1, sizeof(*server));
135 server->server_name = server_name;
136 server->server_type = server_type;
138 server->router = router;
139 server->connection = connection;
141 if (!silc_idcache_add(id_list->servers, server_namec,
142 (void *)server->id, (void *)server, 0, NULL)) {
144 silc_free(server_namec);
151 /* Finds server by Server ID */
154 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
155 bool registered, SilcIDCacheEntry *ret_entry)
157 SilcIDCacheEntry id_cache = NULL;
158 SilcServerEntry server;
163 SILC_LOG_DEBUG(("Server ID (%s)",
164 silc_id_render(id, SILC_ID_SERVER)));
166 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id,
170 server = (SilcServerEntry)id_cache->context;
172 if (server && registered &&
173 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
177 *ret_entry = id_cache;
179 SILC_LOG_DEBUG(("Found"));
184 /* Find server by name. The 'name' must be normalized already. */
187 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
188 bool registered, SilcIDCacheEntry *ret_entry)
190 SilcIDCacheEntry id_cache = NULL;
191 SilcServerEntry server;
193 SILC_LOG_DEBUG(("Server by name `%s'", name));
195 if (!silc_idcache_find_by_name_one(id_list->servers, name, &id_cache))
198 server = (SilcServerEntry)id_cache->context;
200 if (server && registered &&
201 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
205 *ret_entry = id_cache;
207 SILC_LOG_DEBUG(("Found"));
212 /* Find server by connection parameters, hostname and port */
215 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
216 int port, bool registered,
217 SilcIDCacheEntry *ret_entry)
219 SilcIDCacheList list = NULL;
220 SilcIDCacheEntry id_cache = NULL;
221 SilcServerEntry server = NULL;
222 SilcSocketConnection sock;
224 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
226 if (!silc_idcache_get_all(id_list->servers, &list))
229 if (!silc_idcache_list_first(list, &id_cache)) {
230 silc_idcache_list_free(list);
235 server = (SilcServerEntry)id_cache->context;
236 sock = (SilcSocketConnection)server->connection;
238 if (sock && ((sock->hostname && !strcasecmp(sock->hostname, hostname)) ||
239 (sock->ip && !strcasecmp(sock->ip, hostname)))
240 && server->id->port == SILC_SWAB_16(port))
246 if (!silc_idcache_list_next(list, &id_cache))
250 silc_idcache_list_free(list);
252 if (server && registered &&
253 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
257 *ret_entry = id_cache;
259 SILC_LOG_DEBUG(("Found"));
264 /* Replaces old Server ID with new one */
267 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
268 SilcServerID *new_id)
270 SilcIDCacheEntry id_cache = NULL;
271 SilcServerEntry server;
274 if (!old_id || !new_id)
277 SILC_LOG_DEBUG(("Replacing Server ID"));
279 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id,
283 server = (SilcServerEntry)id_cache->context;
284 name = strdup(id_cache->name);
286 /* Remove the old entry and add a new one */
288 silc_idcache_del_by_id(id_list->servers, (void *)server->id);
290 silc_free(server->id);
293 silc_idcache_add(id_list->servers, name, server->id, server, 0, NULL);
295 SILC_LOG_DEBUG(("Found"));
300 /* Removes and free's server entry from ID list */
302 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
305 /* Remove from cache */
306 if (!silc_idcache_del_by_context(id_list->servers, entry)) {
307 SILC_LOG_DEBUG(("Unknown server, did not delete"));
311 SILC_LOG_DEBUG(("Deleting server %s id %s", entry->server_name ?
312 entry->server_name : "",
314 silc_id_render(entry->id, SILC_ID_SERVER) : ""));
317 silc_free(entry->server_name);
318 silc_free(entry->id);
319 silc_free(entry->server_info);
321 memset(entry, 'F', sizeof(*entry));
329 /******************************************************************************
331 Client entry functions
333 ******************************************************************************/
335 /* Add new client entry. This adds the client entry to ID cache system
336 and returns the allocated client entry or NULL on error. This is
337 called when new client connection is accepted to the server. If The
338 `router' is provided then the all server routines assume that the client
339 is not directly connected local client but it has router set and is
340 remote. If this is the case then `connection' must be NULL. If, on the
341 other hand, the `connection' is provided then the client is assumed
342 to be directly connected local client and `router' must be NULL. */
345 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
346 char *userinfo, SilcClientID *id,
347 SilcServerEntry router, void *connection,
350 SilcClientEntry client;
351 char *nicknamec = NULL;
353 SILC_LOG_DEBUG(("Adding new client entry"));
355 /* Normalize name. This is cached, original is in client context. */
357 nicknamec = silc_identifier_check(nickname, strlen(nickname),
358 SILC_STRING_UTF8, 128, NULL);
363 /* Check username. */
365 char *u = NULL, *h = NULL;
366 silc_parse_userfqdn(username, &u, &h);
369 if (!silc_identifier_verify(u, strlen(u), SILC_STRING_UTF8, 128)) {
374 if (h && !silc_identifier_verify(h, strlen(h), SILC_STRING_UTF8, 256)) {
381 client = silc_calloc(1, sizeof(*client));
382 client->nickname = nickname;
383 client->username = username ? strdup(username) : NULL;
384 client->userinfo = userinfo;
386 client->router = router;
387 client->connection = connection;
388 client->channels = silc_hash_table_alloc(3, silc_hash_ptr, NULL,
389 NULL, NULL, NULL, NULL, TRUE);
391 if (!silc_idcache_add(id_list->clients, nicknamec, (void *)client->id,
392 (void *)client, expire, NULL)) {
393 silc_hash_table_free(client->channels);
395 silc_free(nicknamec);
402 /* Free client entry. This free's everything and removes the entry
403 from ID cache. Call silc_idlist_del_data before calling this one. */
405 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
407 SILC_LOG_DEBUG(("Start"));
410 if (!silc_idcache_del_by_context(id_list->clients, entry)) {
411 SILC_LOG_DEBUG(("Unknown client, did not delete"));
415 assert(!silc_hash_table_count(entry->channels));
417 silc_free(entry->nickname);
418 silc_free(entry->servername);
419 silc_free(entry->username);
420 silc_free(entry->userinfo);
421 silc_free(entry->id);
422 silc_free(entry->attrs);
423 silc_hash_table_free(entry->channels);
425 memset(entry, 'F', sizeof(*entry));
434 /* ID Cache destructor */
436 void silc_idlist_client_destructor(SilcIDCache cache,
437 SilcIDCacheEntry entry,
440 SilcServer server = context;
441 SilcClientEntry client;
443 client = (SilcClientEntry)entry->context;
445 /* Remove this client from the public key hash list */
446 if (client->data.public_key)
447 silc_hash_table_del_by_context(server->pk_hash,
448 client->data.public_key, client);
450 assert(!silc_hash_table_count(client->channels));
451 silc_free(client->nickname);
452 silc_free(client->servername);
453 silc_free(client->username);
454 silc_free(client->userinfo);
455 silc_free(client->id);
456 silc_free(client->attrs);
457 if (client->data.public_key)
458 silc_pkcs_public_key_free(client->data.public_key);
459 silc_hash_table_free(client->channels);
461 memset(client, 'A', sizeof(*client));
466 /* Returns all clients matching requested nickname. Number of clients is
467 returned to `clients_count'. Caller must free the returned table.
468 The 'nickname' must be normalized already. */
470 int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
472 SilcClientEntry **clients,
473 SilcUInt32 *clients_count)
475 SilcIDCacheList list = NULL;
476 SilcIDCacheEntry id_cache = NULL;
478 SILC_LOG_DEBUG(("Start"));
480 if (!silc_idcache_find_by_name(id_list->clients, nickname, &list))
483 *clients = silc_realloc(*clients,
484 (silc_idcache_list_count(list) + *clients_count) *
487 silc_idcache_list_first(list, &id_cache);
488 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
490 while (silc_idcache_list_next(list, &id_cache))
491 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
492 silc_idcache_list_free(list);
494 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
499 /* Returns all clients matching requested nickname hash. Number of clients
500 is returned to `clients_count'. Caller must free the returned table.
501 The 'nickname' must be normalized already. */
503 int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
505 SilcClientEntry **clients,
506 SilcUInt32 *clients_count)
508 SilcIDCacheList list = NULL;
509 SilcIDCacheEntry id_cache = NULL;
510 unsigned char hash[SILC_HASH_MAXLEN];
511 SilcClientID client_id;
513 SILC_LOG_DEBUG(("Start"));
515 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
517 /* As the Client ID is hashed in the ID cache by hashing only the hash
518 from the Client ID, we can do a lookup with only the hash not the
519 other parts of the ID and get all the clients with that hash, ie.
520 with that nickname, as the hash is from the nickname. */
521 memset(&client_id, 0, sizeof(client_id));
522 memcpy(&client_id.hash, hash, sizeof(client_id.hash));
523 if (!silc_idcache_find_by_id(id_list->clients, &client_id, &list))
526 *clients = silc_realloc(*clients,
527 (silc_idcache_list_count(list) + *clients_count) *
530 silc_idcache_list_first(list, &id_cache);
531 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
533 while (silc_idcache_list_next(list, &id_cache))
534 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
536 silc_idcache_list_free(list);
538 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
543 /* Finds client by Client ID */
546 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
547 bool registered, SilcIDCacheEntry *ret_entry)
549 SilcIDCacheEntry id_cache = NULL;
550 SilcClientEntry client;
555 SILC_LOG_DEBUG(("Client ID (%s)",
556 silc_id_render(id, SILC_ID_CLIENT)));
558 /* Do extended search since the normal ID comparison function for
559 Client ID's compares only the hash from the Client ID and not the
560 entire ID. The silc_hash_client_id_compare compares the entire
561 Client ID as we want to find one specific Client ID. */
562 if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)id,
564 silc_hash_client_id_compare, NULL,
568 client = (SilcClientEntry)id_cache->context;
570 if (client && registered &&
571 !(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
575 *ret_entry = id_cache;
577 SILC_LOG_DEBUG(("Found"));
582 /* Replaces old Client ID with new one */
585 silc_idlist_replace_client_id(SilcServer server,
586 SilcIDList id_list, SilcClientID *old_id,
587 SilcClientID *new_id, const char *nickname)
589 SilcIDCacheEntry id_cache = NULL;
590 SilcClientEntry client;
591 char *nicknamec = NULL;
593 if (!old_id || !new_id)
596 SILC_LOG_DEBUG(("Replacing Client ID"));
598 /* Normalize name. This is cached, original is in client context. */
600 nicknamec = silc_identifier_check(nickname, strlen(nickname),
601 SILC_STRING_UTF8, 128, NULL);
606 /* Do extended search since the normal ID comparison function for
607 Client ID's compares only the hash from the Client ID and not the
608 entire ID. The silc_hash_client_id_compare compares the entire
609 Client ID as we want to find one specific Client ID. */
610 if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)old_id,
612 silc_hash_client_id_compare, NULL,
616 client = (SilcClientEntry)id_cache->context;
618 /* Remove the old entry and add a new one */
620 if (!silc_idcache_del_by_context(id_list->clients, client))
623 /* Check if anyone is watching old nickname */
624 if (server->server_type == SILC_ROUTER)
625 silc_server_check_watcher_list(server, client, nickname,
626 SILC_NOTIFY_TYPE_NICK_CHANGE);
628 silc_free(client->id);
629 silc_free(client->nickname);
631 client->nickname = nickname ? strdup(nickname) : NULL;
633 /* Check if anyone is watching new nickname */
634 if (server->server_type == SILC_ROUTER)
635 silc_server_check_watcher_list(server, client, nickname,
636 SILC_NOTIFY_TYPE_NICK_CHANGE);
638 if (!silc_idcache_add(id_list->clients, nicknamec, client->id,
642 SILC_LOG_DEBUG(("Replaced"));
648 /******************************************************************************
650 Channel entry functions
652 ******************************************************************************/
654 /* Add new channel entry. This add the new channel entry to the ID cache
655 system and returns the allocated entry or NULL on error. */
658 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
659 SilcChannelID *id, SilcServerEntry router,
660 SilcCipher channel_key, SilcHmac hmac,
663 SilcChannelEntry channel;
664 char *channel_namec = NULL;
666 SILC_LOG_DEBUG(("Adding new channel %s", channel_name));
668 /* Normalize name. This is cached, original is in client context. */
670 channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
671 SILC_STRING_UTF8, 256, NULL);
676 channel = silc_calloc(1, sizeof(*channel));
677 channel->channel_name = channel_name;
678 channel->mode = mode;
680 channel->router = router;
681 channel->channel_key = channel_key;
682 channel->hmac = hmac;
683 channel->created = channel->updated = time(0);
685 if (!silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac)) {
690 channel->user_list = silc_hash_table_alloc(3, silc_hash_ptr, NULL, NULL,
691 NULL, NULL, NULL, TRUE);
693 if (!silc_idcache_add(id_list->channels, channel_namec,
694 (void *)channel->id, (void *)channel, expire, NULL)) {
695 silc_hmac_free(channel->hmac);
696 silc_hash_table_free(channel->user_list);
698 silc_free(channel_namec);
705 /* Foreach callbcak to free all users from the channel when deleting a
708 static void silc_idlist_del_channel_foreach(void *key, void *context,
711 SilcChannelClientEntry chl = (SilcChannelClientEntry)context;
713 SILC_LOG_DEBUG(("Removing client %s from channel %s",
714 chl->client->nickname ? chl->client->nickname :
715 (unsigned char *)"", chl->channel->channel_name));
717 /* Remove the context from the client's channel hash table as that
718 table and channel's user_list hash table share this same context. */
719 silc_hash_table_del(chl->client->channels, chl->channel);
723 /* Free channel entry. This free's everything. */
725 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
728 /* Remove from cache */
729 if (!silc_idcache_del_by_context(id_list->channels, entry)) {
730 SILC_LOG_DEBUG(("Unknown channel, did not delete"));
734 SILC_LOG_DEBUG(("Deleting channel %s", entry->channel_name));
736 /* Free all client entrys from the users list. The silc_hash_table_free
737 will free all the entries so they are not freed at the foreach
739 silc_hash_table_foreach(entry->user_list, silc_idlist_del_channel_foreach,
741 silc_hash_table_free(entry->user_list);
744 silc_free(entry->channel_name);
745 silc_free(entry->id);
746 silc_free(entry->topic);
748 if (entry->invite_list)
749 silc_hash_table_free(entry->invite_list);
751 silc_hash_table_free(entry->ban_list);
753 if (entry->channel_key)
754 silc_cipher_free(entry->channel_key);
756 memset(entry->key, 0, entry->key_len / 8);
757 silc_free(entry->key);
759 silc_free(entry->cipher);
761 silc_hmac_free(entry->hmac);
762 silc_free(entry->hmac_name);
763 silc_free(entry->rekey);
764 if (entry->founder_key)
765 silc_pkcs_public_key_free(entry->founder_key);
766 if (entry->channel_pubkeys)
767 silc_hash_table_free(entry->channel_pubkeys);
769 memset(entry, 'F', sizeof(*entry));
777 /* Finds channel by channel name. Channel names are unique and they
778 are not case-sensitive. The 'name' must be normalized already. */
781 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
782 SilcIDCacheEntry *ret_entry)
784 SilcIDCacheEntry id_cache = NULL;
786 SILC_LOG_DEBUG(("Channel by name %s", name));
788 if (!silc_idcache_find_by_name_one(id_list->channels, name, &id_cache))
792 *ret_entry = id_cache;
794 SILC_LOG_DEBUG(("Found"));
797 ((SilcChannelEntry)id_cache->context)->updated = time(NULL);
799 return id_cache->context;
802 /* Finds channel by Channel ID. */
805 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
806 SilcIDCacheEntry *ret_entry)
808 SilcIDCacheEntry id_cache = NULL;
809 SilcChannelEntry channel;
814 SILC_LOG_DEBUG(("Channel ID (%s)",
815 silc_id_render(id, SILC_ID_CHANNEL)));
817 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, &id_cache))
820 channel = (SilcChannelEntry)id_cache->context;
823 *ret_entry = id_cache;
825 SILC_LOG_DEBUG(("Found"));
828 channel->updated = time(NULL);
833 /* Replaces old Channel ID with new one. This is done when router forces
834 normal server to change Channel ID. */
837 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
838 SilcChannelID *new_id)
840 SilcIDCacheEntry id_cache = NULL;
841 SilcChannelEntry channel;
844 if (!old_id || !new_id)
847 SILC_LOG_DEBUG(("Replacing Channel ID"));
849 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
853 channel = (SilcChannelEntry)id_cache->context;
854 name = strdup(id_cache->name);
856 /* Remove the old entry and add a new one */
858 silc_idcache_del_by_id(id_list->channels, (void *)channel->id);
860 silc_free(channel->id);
861 channel->id = new_id;
863 silc_idcache_add(id_list->channels, name, channel->id, channel, 0, NULL);
865 SILC_LOG_DEBUG(("Replaced"));
868 channel->updated = time(NULL);
873 /* Returns channels from the ID list. If the `channel_id' is NULL then
874 all channels are returned. */
877 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
878 SilcUInt32 *channels_count)
880 SilcIDCacheList list = NULL;
881 SilcIDCacheEntry id_cache = NULL;
882 SilcChannelEntry *channels = NULL;
885 SILC_LOG_DEBUG(("Start"));
888 if (!silc_idcache_get_all(id_list->channels, &list))
891 channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels));
894 silc_idcache_list_first(list, &id_cache);
895 channels[i++] = (SilcChannelEntry)id_cache->context;
897 while (silc_idcache_list_next(list, &id_cache))
898 channels[i++] = (SilcChannelEntry)id_cache->context;
900 silc_idcache_list_free(list);
902 if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache))
906 channels = silc_calloc(1, sizeof(*channels));
907 channels[0] = (SilcChannelEntry)id_cache->context;