5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2003 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;
123 SILC_LOG_DEBUG(("Adding new server entry"));
125 server = silc_calloc(1, sizeof(*server));
126 server->server_name = server_name;
127 server->server_type = server_type;
129 server->router = router;
130 server->connection = connection;
132 if (!silc_idcache_add(id_list->servers, server->server_name,
133 (void *)server->id, (void *)server, 0, NULL)) {
141 /* Finds server by Server ID */
144 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
145 bool registered, SilcIDCacheEntry *ret_entry)
147 SilcIDCacheEntry id_cache = NULL;
148 SilcServerEntry server;
153 SILC_LOG_DEBUG(("Server ID (%s)",
154 silc_id_render(id, SILC_ID_SERVER)));
156 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id,
160 server = (SilcServerEntry)id_cache->context;
162 if (server && registered &&
163 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
167 *ret_entry = id_cache;
169 SILC_LOG_DEBUG(("Found"));
174 /* Find server by name */
177 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
178 bool registered, SilcIDCacheEntry *ret_entry)
180 SilcIDCacheEntry id_cache = NULL;
181 SilcServerEntry server;
183 SILC_LOG_DEBUG(("Server by name `%s'", name));
185 if (!silc_idcache_find_by_name_one(id_list->servers, name, &id_cache))
188 server = (SilcServerEntry)id_cache->context;
190 if (server && registered &&
191 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
195 *ret_entry = id_cache;
197 SILC_LOG_DEBUG(("Found"));
202 /* Find server by connection parameters, hostname and port */
205 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
206 int port, bool registered,
207 SilcIDCacheEntry *ret_entry)
209 SilcIDCacheList list = NULL;
210 SilcIDCacheEntry id_cache = NULL;
211 SilcServerEntry server = NULL;
212 SilcSocketConnection sock;
214 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
216 if (!silc_idcache_get_all(id_list->servers, &list))
219 if (!silc_idcache_list_first(list, &id_cache)) {
220 silc_idcache_list_free(list);
225 server = (SilcServerEntry)id_cache->context;
226 sock = (SilcSocketConnection)server->connection;
228 if (sock && ((sock->hostname && !strcasecmp(sock->hostname, hostname)) ||
229 (sock->ip && !strcasecmp(sock->ip, hostname)))
230 && server->id->port == SILC_SWAB_16(port))
236 if (!silc_idcache_list_next(list, &id_cache))
240 silc_idcache_list_free(list);
242 if (server && registered &&
243 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
247 *ret_entry = id_cache;
249 SILC_LOG_DEBUG(("Found"));
254 /* Replaces old Server ID with new one */
257 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
258 SilcServerID *new_id)
260 SilcIDCacheEntry id_cache = NULL;
261 SilcServerEntry server;
263 if (!old_id || !new_id)
266 SILC_LOG_DEBUG(("Replacing Server ID"));
268 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id,
272 server = (SilcServerEntry)id_cache->context;
274 /* Remove the old entry and add a new one */
276 silc_idcache_del_by_id(id_list->servers, (void *)server->id);
278 silc_free(server->id);
281 silc_idcache_add(id_list->servers, server->server_name, server->id,
284 SILC_LOG_DEBUG(("Found"));
289 /* Removes and free's server entry from ID list */
291 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
294 /* Remove from cache */
295 if (!silc_idcache_del_by_context(id_list->servers, entry)) {
296 SILC_LOG_DEBUG(("Unknown server, did not delete"));
300 SILC_LOG_DEBUG(("Deleting server %s id %s", entry->server_name ?
301 entry->server_name : "",
303 silc_id_render(entry->id, SILC_ID_SERVER) : ""));
306 silc_free(entry->server_name);
307 silc_free(entry->id);
308 silc_free(entry->server_info);
310 memset(entry, 'F', sizeof(*entry));
318 /******************************************************************************
320 Client entry functions
322 ******************************************************************************/
324 /* Add new client entry. This adds the client entry to ID cache system
325 and returns the allocated client entry or NULL on error. This is
326 called when new client connection is accepted to the server. If The
327 `router' is provided then the all server routines assume that the client
328 is not directly connected local client but it has router set and is
329 remote. If this is the case then `connection' must be NULL. If, on the
330 other hand, the `connection' is provided then the client is assumed
331 to be directly connected local client and `router' must be NULL. */
334 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
335 char *userinfo, SilcClientID *id,
336 SilcServerEntry router, void *connection,
339 SilcClientEntry client;
341 SILC_LOG_DEBUG(("Adding new client entry"));
343 client = silc_calloc(1, sizeof(*client));
344 client->nickname = nickname;
345 client->username = username;
346 client->userinfo = userinfo;
348 client->router = router;
349 client->connection = connection;
350 client->channels = silc_hash_table_alloc(3, silc_hash_ptr, NULL,
351 NULL, NULL, NULL, NULL, TRUE);
353 if (!silc_idcache_add(id_list->clients, nickname, (void *)client->id,
354 (void *)client, expire, NULL)) {
355 silc_hash_table_free(client->channels);
363 /* Free client entry. This free's everything and removes the entry
364 from ID cache. Call silc_idlist_del_data before calling this one. */
366 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
368 SILC_LOG_DEBUG(("Start"));
371 /* Remove from cache */
372 if (!silc_idcache_del_by_context(id_list->clients, entry)) {
373 SILC_LOG_DEBUG(("Unknown client, did not delete"));
377 assert(!silc_hash_table_count(entry->channels));
380 silc_free(entry->nickname);
381 silc_free(entry->servername);
382 silc_free(entry->username);
383 silc_free(entry->userinfo);
384 silc_free(entry->id);
385 silc_free(entry->attrs);
386 silc_hash_table_free(entry->channels);
388 memset(entry, 'F', sizeof(*entry));
397 /* Returns all clients matching requested nickname. Number of clients is
398 returned to `clients_count'. Caller must free the returned table. */
400 int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
402 SilcClientEntry **clients,
403 SilcUInt32 *clients_count)
405 SilcIDCacheList list = NULL;
406 SilcIDCacheEntry id_cache = NULL;
408 SILC_LOG_DEBUG(("Start"));
410 if (!silc_idcache_find_by_name(id_list->clients, nickname, &list))
413 *clients = silc_realloc(*clients,
414 (silc_idcache_list_count(list) + *clients_count) *
417 silc_idcache_list_first(list, &id_cache);
418 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
420 while (silc_idcache_list_next(list, &id_cache))
421 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
423 silc_idcache_list_free(list);
425 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
430 /* Returns all clients matching requested nickname hash. Number of clients
431 is returned to `clients_count'. Caller must free the returned table. */
433 int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
435 SilcClientEntry **clients,
436 SilcUInt32 *clients_count)
438 SilcIDCacheList list = NULL;
439 SilcIDCacheEntry id_cache = NULL;
440 unsigned char hash[32];
441 SilcClientID client_id;
444 SILC_LOG_DEBUG(("Start"));
446 memset(nick, 0, sizeof(nick));
447 silc_to_lower(nickname, nick, sizeof(nick) - 1);
448 silc_hash_make(md5hash, nick, strlen(nick), hash);
450 /* As the Client ID is hashed in the ID cache by hashing only the hash
451 from the Client ID, we can do a lookup with only the hash not the
452 other parts of the ID and get all the clients with that hash, ie.
453 with that nickname, as the hash is from the nickname. */
454 memset(&client_id, 0, sizeof(client_id));
455 memcpy(&client_id.hash, hash, sizeof(client_id.hash));
456 if (!silc_idcache_find_by_id(id_list->clients, &client_id, &list))
459 *clients = silc_realloc(*clients,
460 (silc_idcache_list_count(list) + *clients_count) *
463 silc_idcache_list_first(list, &id_cache);
464 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
466 while (silc_idcache_list_next(list, &id_cache))
467 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
469 silc_idcache_list_free(list);
471 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
476 /* Finds client by Client ID */
479 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
480 bool registered, SilcIDCacheEntry *ret_entry)
482 SilcIDCacheEntry id_cache = NULL;
483 SilcClientEntry client;
488 SILC_LOG_DEBUG(("Client ID (%s)",
489 silc_id_render(id, SILC_ID_CLIENT)));
491 /* Do extended search since the normal ID comparison function for
492 Client ID's compares only the hash from the Client ID and not the
493 entire ID. The silc_hash_client_id_compare compares the entire
494 Client ID as we want to find one specific Client ID. */
495 if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)id,
497 silc_hash_client_id_compare, NULL,
501 client = (SilcClientEntry)id_cache->context;
503 if (client && registered &&
504 !(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
508 *ret_entry = id_cache;
510 SILC_LOG_DEBUG(("Found"));
515 /* Replaces old Client ID with new one */
518 silc_idlist_replace_client_id(SilcServer server,
519 SilcIDList id_list, SilcClientID *old_id,
520 SilcClientID *new_id, const char *nickname)
522 SilcIDCacheEntry id_cache = NULL;
523 SilcClientEntry client;
525 if (!old_id || !new_id)
528 SILC_LOG_DEBUG(("Replacing Client ID"));
530 /* Do extended search since the normal ID comparison function for
531 Client ID's compares only the hash from the Client ID and not the
532 entire ID. The silc_hash_client_id_compare compares the entire
533 Client ID as we want to find one specific Client ID. */
534 if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)old_id,
536 silc_hash_client_id_compare, NULL,
540 client = (SilcClientEntry)id_cache->context;
542 /* Remove the old entry and add a new one */
544 if (!silc_idcache_del_by_context(id_list->clients, client))
547 /* Check if anyone is watching old nickname */
548 if (server->server_type == SILC_ROUTER)
549 silc_server_check_watcher_list(server, client, nickname,
550 SILC_NOTIFY_TYPE_NICK_CHANGE);
552 silc_free(client->id);
553 silc_free(client->nickname);
555 client->nickname = nickname ? strdup(nickname) : NULL;
557 /* Check if anyone is watching new nickname */
558 if (server->server_type == SILC_ROUTER)
559 silc_server_check_watcher_list(server, client, nickname,
560 SILC_NOTIFY_TYPE_NICK_CHANGE);
562 if (!silc_idcache_add(id_list->clients, client->nickname, client->id,
566 SILC_LOG_DEBUG(("Replaced"));
571 /* Client cache entry destructor that is called when the cache is purged. */
573 void silc_idlist_client_destructor(SilcIDCache cache,
574 SilcIDCacheEntry entry)
576 SilcClientEntry client;
578 client = (SilcClientEntry)entry->context;
580 assert(!silc_hash_table_count(client->channels));
581 silc_free(client->nickname);
582 silc_free(client->username);
583 silc_free(client->userinfo);
584 silc_free(client->id);
585 silc_free(client->attrs);
586 silc_hash_table_free(client->channels);
588 memset(client, 'A', sizeof(*client));
593 /******************************************************************************
595 Channel entry functions
597 ******************************************************************************/
599 /* Add new channel entry. This add the new channel entry to the ID cache
600 system and returns the allocated entry or NULL on error. */
603 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
604 SilcChannelID *id, SilcServerEntry router,
605 SilcCipher channel_key, SilcHmac hmac,
608 SilcChannelEntry channel;
610 SILC_LOG_DEBUG(("Adding new channel %s", channel_name));
612 channel = silc_calloc(1, sizeof(*channel));
613 channel->channel_name = channel_name;
614 channel->mode = mode;
616 channel->router = router;
617 channel->channel_key = channel_key;
618 channel->hmac = hmac;
619 channel->created = channel->updated = time(0);
621 if (!silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac)) {
626 channel->user_list = silc_hash_table_alloc(3, silc_hash_ptr, NULL, NULL,
627 NULL, NULL, NULL, TRUE);
629 if (!silc_idcache_add(id_list->channels, channel->channel_name,
630 (void *)channel->id, (void *)channel, expire, NULL)) {
631 silc_hmac_free(channel->hmac);
632 silc_hash_table_free(channel->user_list);
640 /* Foreach callbcak to free all users from the channel when deleting a
643 static void silc_idlist_del_channel_foreach(void *key, void *context,
646 SilcChannelClientEntry chl = (SilcChannelClientEntry)context;
648 SILC_LOG_DEBUG(("Removing client %s from channel %s",
649 chl->client->nickname ? chl->client->nickname :
650 (unsigned char *)"", chl->channel->channel_name));
652 /* Remove the context from the client's channel hash table as that
653 table and channel's user_list hash table share this same context. */
654 silc_hash_table_del(chl->client->channels, chl->channel);
658 /* Free channel entry. This free's everything. */
660 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
663 /* Remove from cache */
664 if (!silc_idcache_del_by_context(id_list->channels, entry)) {
665 SILC_LOG_DEBUG(("Unknown channel, did not delete"));
669 SILC_LOG_DEBUG(("Deleting channel %s", entry->channel_name));
671 /* Free all client entrys from the users list. The silc_hash_table_free
672 will free all the entries so they are not freed at the foreach
674 silc_hash_table_foreach(entry->user_list, silc_idlist_del_channel_foreach,
676 silc_hash_table_free(entry->user_list);
679 silc_free(entry->channel_name);
680 silc_free(entry->id);
681 silc_free(entry->topic);
683 if (entry->invite_list)
684 silc_hash_table_free(entry->invite_list);
686 silc_hash_table_free(entry->ban_list);
688 if (entry->channel_key)
689 silc_cipher_free(entry->channel_key);
691 memset(entry->key, 0, entry->key_len / 8);
692 silc_free(entry->key);
694 silc_free(entry->cipher);
696 silc_hmac_free(entry->hmac);
697 silc_free(entry->hmac_name);
698 silc_free(entry->rekey);
699 if (entry->founder_key)
700 silc_pkcs_public_key_free(entry->founder_key);
701 if (entry->channel_pubkeys)
702 silc_hash_table_free(entry->channel_pubkeys);
704 memset(entry, 'F', sizeof(*entry));
712 /* Finds channel by channel name. Channel names are unique and they
713 are not case-sensitive. */
716 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
717 SilcIDCacheEntry *ret_entry)
719 SilcIDCacheEntry id_cache = NULL;
721 SILC_LOG_DEBUG(("Channel by name %s", name));
723 if (!silc_idcache_find_by_name_one(id_list->channels, name, &id_cache))
727 *ret_entry = id_cache;
729 SILC_LOG_DEBUG(("Found"));
732 ((SilcChannelEntry)id_cache->context)->updated = time(NULL);
734 return id_cache->context;
737 /* Finds channel by Channel ID. */
740 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
741 SilcIDCacheEntry *ret_entry)
743 SilcIDCacheEntry id_cache = NULL;
744 SilcChannelEntry channel;
749 SILC_LOG_DEBUG(("Channel ID (%s)",
750 silc_id_render(id, SILC_ID_CHANNEL)));
752 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, &id_cache))
755 channel = (SilcChannelEntry)id_cache->context;
758 *ret_entry = id_cache;
760 SILC_LOG_DEBUG(("Found"));
763 channel->updated = time(NULL);
768 /* Replaces old Channel ID with new one. This is done when router forces
769 normal server to change Channel ID. */
772 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
773 SilcChannelID *new_id)
775 SilcIDCacheEntry id_cache = NULL;
776 SilcChannelEntry channel;
778 if (!old_id || !new_id)
781 SILC_LOG_DEBUG(("Replacing Channel ID"));
783 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
787 channel = (SilcChannelEntry)id_cache->context;
789 /* Remove the old entry and add a new one */
791 silc_idcache_del_by_id(id_list->channels, (void *)channel->id);
793 silc_free(channel->id);
794 channel->id = new_id;
796 silc_idcache_add(id_list->channels, channel->channel_name, channel->id,
799 SILC_LOG_DEBUG(("Replaced"));
802 channel->updated = time(NULL);
807 /* Returns channels from the ID list. If the `channel_id' is NULL then
808 all channels are returned. */
811 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
812 SilcUInt32 *channels_count)
814 SilcIDCacheList list = NULL;
815 SilcIDCacheEntry id_cache = NULL;
816 SilcChannelEntry *channels = NULL;
819 SILC_LOG_DEBUG(("Start"));
822 if (!silc_idcache_get_all(id_list->channels, &list))
825 channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels));
828 silc_idcache_list_first(list, &id_cache);
829 channels[i++] = (SilcChannelEntry)id_cache->context;
831 while (silc_idcache_list_next(list, &id_cache))
832 channels[i++] = (SilcChannelEntry)id_cache->context;
834 silc_idcache_list_free(list);
836 if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache))
840 channels = silc_calloc(1, sizeof(*channels));
841 channels[0] = (SilcChannelEntry)id_cache->context;