5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
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; 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"
25 /******************************************************************************
29 ******************************************************************************/
31 /* This function is used to add keys and stuff to common ID entry data
34 void silc_idlist_add_data(void *entry, SilcIDListData idata)
36 SilcIDListData data = (SilcIDListData)entry;
37 data->send_key = idata->send_key;
38 data->receive_key = idata->receive_key;
39 data->hash = idata->hash;
40 data->hmac = idata->hmac;
41 data->hmac_key = idata->hmac_key;
42 data->hmac_key_len = idata->hmac_key_len;
43 data->public_key = idata->public_key;
44 data->last_receive = idata->last_receive;
45 data->last_sent = idata->last_sent;
46 data->registered = idata->registered;
49 /* Free's all data in the common ID entry data structure. */
51 void silc_idlist_del_data(void *entry)
53 SilcIDListData idata = (SilcIDListData)entry;
55 silc_cipher_free(idata->send_key);
56 if (idata->receive_key)
57 silc_cipher_free(idata->receive_key);
59 silc_hmac_free(idata->hmac);
60 if (idata->hmac_key) {
61 memset(idata->hmac_key, 0, idata->hmac_key_len);
62 silc_free(idata->hmac_key);
64 if (idata->public_key)
65 silc_pkcs_public_key_free(idata->public_key);
70 SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge)
72 SilcIDListPurge i = (SilcIDListPurge)context;
74 SILC_LOG_DEBUG(("Start"));
76 silc_idcache_purge(i->cache);
77 silc_task_register(i->timeout_queue, 0,
80 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
83 /******************************************************************************
85 Server entry functions
87 ******************************************************************************/
89 /* Add new server entry. This adds the new server entry to ID cache and
90 returns the allocated entry object or NULL on error. This is called
91 when new server connects to us. We also add ourselves to cache with
95 silc_idlist_add_server(SilcIDList id_list,
96 char *server_name, int server_type,
97 SilcServerID *id, SilcServerEntry router,
100 SilcServerEntry server;
102 SILC_LOG_DEBUG(("Adding new server entry"));
104 server = silc_calloc(1, sizeof(*server));
105 server->server_name = server_name;
106 server->server_type = server_type;
108 server->router = router;
109 server->connection = connection;
111 if (!silc_idcache_add(id_list->servers, server->server_name,
112 server->server_name ? strlen(server->server_name) : 0,
113 SILC_ID_SERVER, (void *)server->id,
114 (void *)server, TRUE, FALSE)) {
122 /* Finds server by Server ID */
125 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
126 SilcIDCacheEntry *ret_entry)
128 SilcIDCacheEntry id_cache = NULL;
129 SilcServerEntry server;
134 SILC_LOG_DEBUG(("Server ID (%s)",
135 silc_id_render(id, SILC_ID_SERVER)));
137 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id,
138 SILC_ID_SERVER, &id_cache))
141 server = (SilcServerEntry)id_cache->context;
144 *ret_entry = id_cache;
149 /* Find server by name */
152 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
153 SilcIDCacheEntry *ret_entry)
155 SilcIDCacheEntry id_cache = NULL;
156 SilcServerEntry server;
158 SILC_LOG_DEBUG(("Server by name `%s'", name));
160 if (!silc_idcache_find_by_data_one(id_list->servers, name, &id_cache))
163 server = (SilcServerEntry)id_cache->context;
166 *ret_entry = id_cache;
168 SILC_LOG_DEBUG(("Found"));
173 /* Find server by connection parameters, hostname and port */
176 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
177 int port, SilcIDCacheEntry *ret_entry)
179 SilcIDCacheList list = NULL;
180 SilcIDCacheEntry id_cache = NULL;
181 SilcServerEntry server = NULL;
182 SilcSocketConnection sock;
184 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
186 if (!silc_idcache_find_by_id(id_list->servers, SILC_ID_CACHE_ANY,
187 SILC_ID_SERVER, &list))
190 if (!silc_idcache_list_first(list, &id_cache)) {
191 silc_idcache_list_free(list);
196 server = (SilcServerEntry)id_cache->context;
197 sock = (SilcSocketConnection)server->connection;
199 if (sock && ((sock->hostname && !strcmp(sock->hostname, hostname)) ||
200 (sock->ip && !strcmp(sock->ip, hostname)))
201 && sock->port == port)
207 if (!silc_idcache_list_next(list, &id_cache))
211 silc_idcache_list_free(list);
214 *ret_entry = id_cache;
216 SILC_LOG_DEBUG(("Found"));
221 /* Replaces old Server ID with new one */
224 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
225 SilcServerID *new_id)
227 SilcIDCacheEntry id_cache = NULL;
228 SilcServerEntry server;
230 if (!old_id || !new_id)
233 SILC_LOG_DEBUG(("Replacing Server ID"));
235 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id,
236 SILC_ID_SERVER, &id_cache))
239 server = (SilcServerEntry)id_cache->context;
240 silc_free(server->id);
242 id_cache->id = (void *)new_id;
244 SILC_LOG_DEBUG(("Found"));
249 /* Removes and free's server entry from ID list */
251 void silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
254 /* Remove from cache */
256 silc_idcache_del_by_id(id_list->servers, SILC_ID_SERVER,
260 if (entry->server_name)
261 silc_free(entry->server_name);
263 silc_free(entry->id);
265 memset(entry, 'F', sizeof(*entry));
270 /******************************************************************************
272 Client entry functions
274 ******************************************************************************/
276 /* Add new client entry. This adds the client entry to ID cache system
277 and returns the allocated client entry or NULL on error. This is
278 called when new client connection is accepted to the server. If The
279 `router' is provided then the all server routines assume that the client
280 is not directly connected local client but it has router set and is
281 remote. If this is the case then `connection' must be NULL. If, on the
282 other hand, the `connection' is provided then the client is assumed
283 to be directly connected local client and `router' must be NULL. */
286 silc_idlist_add_client(SilcIDList id_list, unsigned char *nickname,
287 unsigned int nickname_len, char *username,
288 char *userinfo, SilcClientID *id,
289 SilcServerEntry router, void *connection)
291 SilcClientEntry client;
293 SILC_LOG_DEBUG(("Adding new client entry"));
295 client = silc_calloc(1, sizeof(*client));
296 client->nickname = nickname;
297 client->username = username;
298 client->userinfo = userinfo;
300 client->router = router;
301 client->connection = connection;
302 silc_list_init(client->channels, struct SilcChannelClientEntryStruct,
305 if (!silc_idcache_add(id_list->clients, nickname, nickname_len,
306 SILC_ID_CLIENT, (void *)client->id,
307 (void *)client, TRUE, FALSE)) {
315 /* Free client entry. This free's everything and removes the entry
316 from ID cache. Call silc_idlist_del_data before calling this one. */
318 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
321 /* Remove from cache */
323 if (!silc_idcache_del_by_id(id_list->clients, SILC_ID_CLIENT,
329 silc_free(entry->nickname);
331 silc_free(entry->username);
333 silc_free(entry->userinfo);
335 silc_free(entry->id);
337 memset(entry, 'F', sizeof(*entry));
346 /* Returns all clients matching requested nickname. Number of clients is
347 returned to `clients_count'. Caller must free the returned table. */
350 silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
351 char *server, unsigned int *clients_count)
353 SilcIDCacheList list = NULL;
354 SilcIDCacheEntry id_cache = NULL;
355 SilcClientEntry *clients;
358 SILC_LOG_DEBUG(("Start"));
360 if (!silc_idcache_find_by_data(id_list->clients, nickname, &list))
363 clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
366 silc_idcache_list_first(list, &id_cache);
367 clients[i++] = (SilcClientEntry)id_cache->context;
369 while (silc_idcache_list_next(list, &id_cache))
370 clients[i++] = (SilcClientEntry)id_cache->context;
372 silc_idcache_list_free(list);
380 /* Returns all clients matching requested nickname. Number of clients is
381 returned to `clients_count'. Caller must free the returned table. */
382 /* XXX This actually checks the data, which can be hash of the nickname
383 but is not if the client is local client. Global client on global
384 list may have hash. Thus, this is not fully reliable function.
385 Instead this should probably check the hash from the list of client ID's. */
388 silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
390 unsigned int *clients_count)
392 SilcIDCacheList list = NULL;
393 SilcIDCacheEntry id_cache = NULL;
394 SilcClientEntry *clients;
395 unsigned char hash[32];
398 SILC_LOG_DEBUG(("Start"));
400 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
402 if (!silc_idcache_find_by_data(id_list->clients, hash, &list))
405 clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
408 silc_idcache_list_first(list, &id_cache);
409 clients[i++] = (SilcClientEntry)id_cache->context;
411 while (silc_idcache_list_next(list, &id_cache))
412 clients[i++] = (SilcClientEntry)id_cache->context;
414 silc_idcache_list_free(list);
422 /* Finds client by nickname hash. */
425 silc_idlist_find_client_by_hash(SilcIDList id_list, char *nickname,
426 SilcHash md5hash, SilcIDCacheEntry *ret_entry)
428 SilcIDCacheList list = NULL;
429 SilcIDCacheEntry id_cache = NULL;
430 SilcClientEntry client = NULL;
431 unsigned char hash[32];
433 SILC_LOG_DEBUG(("Client by hash"));
435 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
437 if (!silc_idcache_find_by_id(id_list->clients, SILC_ID_CACHE_ANY,
438 SILC_ID_CLIENT, &list))
441 if (!silc_idcache_list_first(list, &id_cache)) {
442 silc_idcache_list_free(list);
447 client = (SilcClientEntry)id_cache->context;
449 if (client && !SILC_ID_COMPARE_HASH(client->id, hash))
455 if (!silc_idcache_list_next(list, &id_cache))
459 silc_idcache_list_free(list);
462 *ret_entry = id_cache;
464 SILC_LOG_DEBUG(("Found"));
469 /* Finds client by Client ID */
472 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
473 SilcIDCacheEntry *ret_entry)
475 SilcIDCacheEntry id_cache = NULL;
476 SilcClientEntry client;
481 SILC_LOG_DEBUG(("Client ID (%s)",
482 silc_id_render(id, SILC_ID_CLIENT)));
484 if (!silc_idcache_find_by_id_one(id_list->clients, (void *)id,
485 SILC_ID_CLIENT, &id_cache))
488 client = (SilcClientEntry)id_cache->context;
491 *ret_entry = id_cache;
493 SILC_LOG_DEBUG(("Found"));
498 /* Replaces old Client ID with new one */
501 silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id,
502 SilcClientID *new_id)
504 SilcIDCacheEntry id_cache = NULL;
505 SilcClientEntry client;
507 if (!old_id || !new_id)
510 SILC_LOG_DEBUG(("Replacing Client ID"));
512 if (!silc_idcache_find_by_id_one(id_list->clients, (void *)old_id,
513 SILC_ID_CLIENT, &id_cache))
516 client = (SilcClientEntry)id_cache->context;
517 silc_free(client->id);
519 id_cache->id = (void *)new_id;
521 /* If the old ID Cache data was the hash value of the old Client ID
522 replace it with the hash of new Client ID */
523 if (id_cache->data && !SILC_ID_COMPARE_HASH(old_id, id_cache->data)) {
524 silc_free(id_cache->data);
525 id_cache->data = silc_calloc(sizeof(new_id->hash), sizeof(unsigned char));
526 memcpy(id_cache->data, new_id->hash, sizeof(new_id->hash));
527 silc_idcache_sort_by_data(id_list->clients);
530 SILC_LOG_DEBUG(("Replaced"));
535 /* Client cache entry destructor that is called when the cache is purged. */
537 void silc_idlist_client_destructor(SilcIDCache cache,
538 SilcIDCacheEntry entry)
540 SilcClientEntry client;
542 SILC_LOG_DEBUG(("Start"));
544 client = (SilcClientEntry)entry->context;
546 if (client->nickname)
547 silc_free(client->nickname);
548 if (client->username)
549 silc_free(client->username);
550 if (client->userinfo)
551 silc_free(client->userinfo);
553 silc_free(client->id);
555 memset(client, 'F', sizeof(*client));
560 /******************************************************************************
562 Channel entry functions
564 ******************************************************************************/
566 /* Add new channel entry. This add the new channel entry to the ID cache
567 system and returns the allocated entry or NULL on error. */
570 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
571 SilcChannelID *id, SilcServerEntry router,
572 SilcCipher channel_key, SilcHmac hmac)
574 SilcChannelEntry channel;
576 channel = silc_calloc(1, sizeof(*channel));
577 channel->channel_name = channel_name;
578 channel->mode = mode;
580 channel->router = router;
581 channel->channel_key = channel_key;
582 channel->hmac = hmac;
584 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &channel->hmac)) {
589 silc_list_init(channel->user_list, struct SilcChannelClientEntryStruct,
592 if (!silc_idcache_add(id_list->channels, channel->channel_name,
593 channel->channel_name ? strlen(channel->channel_name) :
595 (void *)channel->id, (void *)channel, TRUE, FALSE)) {
603 /* Free channel entry. This free's everything. */
605 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
608 SilcChannelClientEntry chl;
610 /* Remove from cache */
612 if (!silc_idcache_del_by_id(id_list->channels, SILC_ID_CHANNEL,
617 if (entry->channel_name)
618 silc_free(entry->channel_name);
620 silc_free(entry->id);
622 silc_free(entry->topic);
623 if (entry->channel_key)
624 silc_cipher_free(entry->channel_key);
626 memset(entry->key, 0, entry->key_len / 8);
627 silc_free(entry->key);
630 silc_free(entry->cipher);
631 if (entry->hmac_name)
632 silc_free(entry->hmac_name);
634 /* Free all data, free also any reference from the client's channel
635 list since they share the same memory. */
636 silc_list_start(entry->user_list);
637 while ((chl = silc_list_get(entry->user_list)) != SILC_LIST_END) {
638 silc_list_del(chl->client->channels, chl);
639 silc_list_del(entry->user_list, chl);
643 memset(entry, 'F', sizeof(*entry));
651 /* Finds channel by channel name. Channel names are unique and they
652 are not case-sensitive. */
655 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
656 SilcIDCacheEntry *ret_entry)
658 SilcIDCacheList list = NULL;
659 SilcIDCacheEntry id_cache = NULL;
660 SilcChannelEntry channel;
662 SILC_LOG_DEBUG(("Channel by name"));
664 if (!silc_idcache_find_by_data_loose(id_list->channels, name, &list))
667 if (!silc_idcache_list_first(list, &id_cache)) {
668 silc_idcache_list_free(list);
672 channel = (SilcChannelEntry)id_cache->context;
675 *ret_entry = id_cache;
677 silc_idcache_list_free(list);
679 SILC_LOG_DEBUG(("Found"));
684 /* Finds channel by Channel ID. */
687 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
688 SilcIDCacheEntry *ret_entry)
690 SilcIDCacheEntry id_cache = NULL;
691 SilcChannelEntry channel;
696 SILC_LOG_DEBUG(("Channel ID (%s)",
697 silc_id_render(id, SILC_ID_CHANNEL)));
699 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id,
700 SILC_ID_CHANNEL, &id_cache))
703 channel = (SilcChannelEntry)id_cache->context;
706 *ret_entry = id_cache;
708 SILC_LOG_DEBUG(("Found"));
713 /* Replaces old Channel ID with new one. This is done when router forces
714 normal server to change Channel ID. */
717 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
718 SilcChannelID *new_id)
720 SilcIDCacheEntry id_cache = NULL;
721 SilcChannelEntry channel;
723 if (!old_id || !new_id)
726 SILC_LOG_DEBUG(("Replacing Channel ID"));
728 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
729 SILC_ID_CHANNEL, &id_cache))
732 channel = (SilcChannelEntry)id_cache->context;
733 silc_free(channel->id);
734 channel->id = new_id;
735 id_cache->id = (void *)new_id;
737 SILC_LOG_DEBUG(("Replaced"));
742 /* Returns channels from the ID list. If the `channel_id' is NULL then
743 all channels are returned. */
746 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
747 unsigned int *channels_count)
749 SilcIDCacheList list = NULL;
750 SilcIDCacheEntry id_cache = NULL;
751 SilcChannelEntry *channels;
754 SILC_LOG_DEBUG(("Start"));
756 if (!silc_idcache_find_by_id(id_list->channels, channel_id ? channel_id :
757 SILC_ID_CACHE_ANY, SILC_ID_CHANNEL, &list))
760 channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels));
763 silc_idcache_list_first(list, &id_cache);
764 channels[i++] = (SilcChannelEntry)id_cache->context;
766 while (silc_idcache_list_next(list, &id_cache))
767 channels[i++] = (SilcChannelEntry)id_cache->context;
769 silc_idcache_list_free(list);