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->rekey = idata->rekey;
40 data->hash = idata->hash;
41 data->hmac = idata->hmac;
42 data->public_key = idata->public_key;
43 data->last_receive = idata->last_receive;
44 data->last_sent = idata->last_sent;
45 data->registered = idata->registered;
48 /* Free's all data in the common ID entry data structure. */
50 void silc_idlist_del_data(void *entry)
52 SilcIDListData idata = (SilcIDListData)entry;
54 silc_cipher_free(idata->send_key);
55 if (idata->receive_key)
56 silc_cipher_free(idata->receive_key);
58 if (idata->rekey->send_enc_key) {
59 memset(idata->rekey->send_enc_key, 0, idata->rekey->enc_key_len);
60 silc_free(idata->rekey->send_enc_key);
62 silc_free(idata->rekey);
65 silc_hmac_free(idata->hmac);
66 if (idata->public_key)
67 silc_pkcs_public_key_free(idata->public_key);
72 SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge)
74 SilcIDListPurge i = (SilcIDListPurge)context;
76 SILC_LOG_DEBUG(("Start"));
78 silc_idcache_purge(i->cache);
79 silc_task_register(i->timeout_queue, 0,
82 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
85 /******************************************************************************
87 Server entry functions
89 ******************************************************************************/
91 /* Add new server entry. This adds the new server entry to ID cache and
92 returns the allocated entry object or NULL on error. This is called
93 when new server connects to us. We also add ourselves to cache with
97 silc_idlist_add_server(SilcIDList id_list,
98 char *server_name, int server_type,
99 SilcServerID *id, SilcServerEntry router,
102 SilcServerEntry server;
104 SILC_LOG_DEBUG(("Adding new server entry"));
106 server = silc_calloc(1, sizeof(*server));
107 server->server_name = server_name;
108 server->server_type = server_type;
110 server->router = router;
111 server->connection = connection;
113 if (!silc_idcache_add(id_list->servers, server->server_name,
114 server->server_name ? strlen(server->server_name) : 0,
115 SILC_ID_SERVER, (void *)server->id,
116 (void *)server, TRUE, FALSE)) {
124 /* Finds server by Server ID */
127 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
128 SilcIDCacheEntry *ret_entry)
130 SilcIDCacheEntry id_cache = NULL;
131 SilcServerEntry server;
136 SILC_LOG_DEBUG(("Server ID (%s)",
137 silc_id_render(id, SILC_ID_SERVER)));
139 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id,
140 SILC_ID_SERVER, &id_cache))
143 server = (SilcServerEntry)id_cache->context;
146 *ret_entry = id_cache;
151 /* Find server by name */
154 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
155 SilcIDCacheEntry *ret_entry)
157 SilcIDCacheEntry id_cache = NULL;
158 SilcServerEntry server;
160 SILC_LOG_DEBUG(("Server by name `%s'", name));
162 if (!silc_idcache_find_by_data_one(id_list->servers, name, &id_cache))
165 server = (SilcServerEntry)id_cache->context;
168 *ret_entry = id_cache;
170 SILC_LOG_DEBUG(("Found"));
175 /* Find server by connection parameters, hostname and port */
178 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
179 int port, SilcIDCacheEntry *ret_entry)
181 SilcIDCacheList list = NULL;
182 SilcIDCacheEntry id_cache = NULL;
183 SilcServerEntry server = NULL;
184 SilcSocketConnection sock;
186 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
188 if (!silc_idcache_find_by_id(id_list->servers, SILC_ID_CACHE_ANY,
189 SILC_ID_SERVER, &list))
192 if (!silc_idcache_list_first(list, &id_cache)) {
193 silc_idcache_list_free(list);
198 server = (SilcServerEntry)id_cache->context;
199 sock = (SilcSocketConnection)server->connection;
201 if (sock && ((sock->hostname && !strcmp(sock->hostname, hostname)) ||
202 (sock->ip && !strcmp(sock->ip, hostname)))
203 && sock->port == port)
209 if (!silc_idcache_list_next(list, &id_cache))
213 silc_idcache_list_free(list);
216 *ret_entry = id_cache;
218 SILC_LOG_DEBUG(("Found"));
223 /* Replaces old Server ID with new one */
226 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
227 SilcServerID *new_id)
229 SilcIDCacheEntry id_cache = NULL;
230 SilcServerEntry server;
232 if (!old_id || !new_id)
235 SILC_LOG_DEBUG(("Replacing Server ID"));
237 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id,
238 SILC_ID_SERVER, &id_cache))
241 server = (SilcServerEntry)id_cache->context;
242 silc_free(server->id);
244 id_cache->id = (void *)new_id;
246 SILC_LOG_DEBUG(("Found"));
251 /* Removes and free's server entry from ID list */
253 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
255 SILC_LOG_DEBUG(("Start"));
258 /* Remove from cache */
260 if (!silc_idcache_del_by_id(id_list->servers, SILC_ID_SERVER,
265 if (entry->server_name)
266 silc_free(entry->server_name);
268 silc_free(entry->id);
270 memset(entry, 'F', sizeof(*entry));
278 /******************************************************************************
280 Client entry functions
282 ******************************************************************************/
284 /* Add new client entry. This adds the client entry to ID cache system
285 and returns the allocated client entry or NULL on error. This is
286 called when new client connection is accepted to the server. If The
287 `router' is provided then the all server routines assume that the client
288 is not directly connected local client but it has router set and is
289 remote. If this is the case then `connection' must be NULL. If, on the
290 other hand, the `connection' is provided then the client is assumed
291 to be directly connected local client and `router' must be NULL. */
294 silc_idlist_add_client(SilcIDList id_list, unsigned char *nickname,
295 uint32 nickname_len, char *username,
296 char *userinfo, SilcClientID *id,
297 SilcServerEntry router, void *connection)
299 SilcClientEntry client;
301 SILC_LOG_DEBUG(("Adding new client entry"));
303 client = silc_calloc(1, sizeof(*client));
304 client->nickname = nickname;
305 client->username = username;
306 client->userinfo = userinfo;
308 client->router = router;
309 client->connection = connection;
310 silc_list_init(client->channels, struct SilcChannelClientEntryStruct,
313 if (!silc_idcache_add(id_list->clients, nickname, nickname_len,
314 SILC_ID_CLIENT, (void *)client->id,
315 (void *)client, TRUE, FALSE)) {
323 /* Free client entry. This free's everything and removes the entry
324 from ID cache. Call silc_idlist_del_data before calling this one. */
326 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
328 SILC_LOG_DEBUG(("Start"));
331 /* Remove from cache */
333 if (!silc_idcache_del_by_id(id_list->clients, SILC_ID_CLIENT,
339 silc_free(entry->nickname);
341 silc_free(entry->username);
343 silc_free(entry->userinfo);
345 silc_free(entry->id);
347 memset(entry, 'F', sizeof(*entry));
356 /* Returns all clients matching requested nickname. Number of clients is
357 returned to `clients_count'. Caller must free the returned table. */
359 int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
361 SilcClientEntry **clients,
362 uint32 *clients_count)
364 SilcIDCacheList list = NULL;
365 SilcIDCacheEntry id_cache = NULL;
368 SILC_LOG_DEBUG(("Start"));
370 if (!silc_idcache_find_by_data(id_list->clients, nickname, &list))
373 *clients = silc_realloc(*clients,
374 (silc_idcache_list_count(list) + *clients_count) *
378 silc_idcache_list_first(list, &id_cache);
379 (*clients)[i++] = (SilcClientEntry)id_cache->context;
381 while (silc_idcache_list_next(list, &id_cache))
382 (*clients)[i++] = (SilcClientEntry)id_cache->context;
384 silc_idcache_list_free(list);
391 /* Returns all clients matching requested nickname. Number of clients is
392 returned to `clients_count'. Caller must free the returned table. */
393 /* XXX This actually checks the data, which can be hash of the nickname
394 but is not if the client is local client. Global client on global
395 list may have hash. Thus, this is not fully reliable function.
396 Instead this should probably check the hash from the list of client ID's. */
398 int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
400 SilcClientEntry **clients,
401 uint32 *clients_count)
403 SilcIDCacheList list = NULL;
404 SilcIDCacheEntry id_cache = NULL;
405 unsigned char hash[32];
408 SILC_LOG_DEBUG(("Start"));
410 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
412 if (!silc_idcache_find_by_data(id_list->clients, hash, &list))
415 *clients = silc_realloc(*clients,
416 (silc_idcache_list_count(list) + *clients_count) *
420 silc_idcache_list_first(list, &id_cache);
421 (*clients)[i++] = (SilcClientEntry)id_cache->context;
423 while (silc_idcache_list_next(list, &id_cache))
424 (*clients)[i++] = (SilcClientEntry)id_cache->context;
426 silc_idcache_list_free(list);
433 /* Finds client by nickname hash. */
436 silc_idlist_find_client_by_hash(SilcIDList id_list, char *nickname,
437 SilcHash md5hash, SilcIDCacheEntry *ret_entry)
439 SilcIDCacheList list = NULL;
440 SilcIDCacheEntry id_cache = NULL;
441 SilcClientEntry client = NULL;
442 unsigned char hash[32];
444 SILC_LOG_DEBUG(("Client by hash"));
446 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
448 if (!silc_idcache_find_by_id(id_list->clients, SILC_ID_CACHE_ANY,
449 SILC_ID_CLIENT, &list))
452 if (!silc_idcache_list_first(list, &id_cache)) {
453 silc_idcache_list_free(list);
458 client = (SilcClientEntry)id_cache->context;
460 if (client && !SILC_ID_COMPARE_HASH(client->id, hash))
466 if (!silc_idcache_list_next(list, &id_cache))
470 silc_idcache_list_free(list);
473 *ret_entry = id_cache;
475 SILC_LOG_DEBUG(("Found"));
480 /* Finds client by Client ID */
483 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
484 SilcIDCacheEntry *ret_entry)
486 SilcIDCacheEntry id_cache = NULL;
487 SilcClientEntry client;
492 SILC_LOG_DEBUG(("Client ID (%s)",
493 silc_id_render(id, SILC_ID_CLIENT)));
495 if (!silc_idcache_find_by_id_one(id_list->clients, (void *)id,
496 SILC_ID_CLIENT, &id_cache))
499 client = (SilcClientEntry)id_cache->context;
502 *ret_entry = id_cache;
504 SILC_LOG_DEBUG(("Found"));
509 /* Replaces old Client ID with new one */
512 silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id,
513 SilcClientID *new_id)
515 SilcIDCacheEntry id_cache = NULL;
516 SilcClientEntry client;
518 if (!old_id || !new_id)
521 SILC_LOG_DEBUG(("Replacing Client ID"));
523 if (!silc_idcache_find_by_id_one(id_list->clients, (void *)old_id,
524 SILC_ID_CLIENT, &id_cache))
527 client = (SilcClientEntry)id_cache->context;
528 silc_free(client->id);
530 id_cache->id = (void *)new_id;
532 /* If the old ID Cache data was the hash value of the old Client ID
533 replace it with the hash of new Client ID */
534 if (id_cache->data && !SILC_ID_COMPARE_HASH(old_id, id_cache->data)) {
535 silc_free(id_cache->data);
536 id_cache->data = silc_calloc(sizeof(new_id->hash), sizeof(unsigned char));
537 memcpy(id_cache->data, new_id->hash, sizeof(new_id->hash));
538 silc_idcache_sort_by_data(id_list->clients);
541 SILC_LOG_DEBUG(("Replaced"));
546 /* Client cache entry destructor that is called when the cache is purged. */
548 void silc_idlist_client_destructor(SilcIDCache cache,
549 SilcIDCacheEntry entry)
551 SilcClientEntry client;
553 SILC_LOG_DEBUG(("Start"));
555 client = (SilcClientEntry)entry->context;
557 if (client->nickname)
558 silc_free(client->nickname);
559 if (client->username)
560 silc_free(client->username);
561 if (client->userinfo)
562 silc_free(client->userinfo);
564 silc_free(client->id);
566 memset(client, 'F', sizeof(*client));
571 /******************************************************************************
573 Channel entry functions
575 ******************************************************************************/
577 /* Add new channel entry. This add the new channel entry to the ID cache
578 system and returns the allocated entry or NULL on error. */
581 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
582 SilcChannelID *id, SilcServerEntry router,
583 SilcCipher channel_key, SilcHmac hmac)
585 SilcChannelEntry channel;
587 channel = silc_calloc(1, sizeof(*channel));
588 channel->channel_name = channel_name;
589 channel->mode = mode;
591 channel->router = router;
592 channel->channel_key = channel_key;
593 channel->hmac = hmac;
595 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &channel->hmac)) {
600 silc_list_init(channel->user_list, struct SilcChannelClientEntryStruct,
603 if (!silc_idcache_add(id_list->channels, channel->channel_name,
604 channel->channel_name ? strlen(channel->channel_name) :
606 (void *)channel->id, (void *)channel, TRUE, FALSE)) {
614 /* Free channel entry. This free's everything. */
616 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
618 SILC_LOG_DEBUG(("Start"));
621 SilcChannelClientEntry chl;
623 /* Remove from cache */
625 if (!silc_idcache_del_by_id(id_list->channels, SILC_ID_CHANNEL,
630 if (entry->channel_name)
631 silc_free(entry->channel_name);
633 silc_free(entry->id);
635 silc_free(entry->topic);
636 if (entry->channel_key)
637 silc_cipher_free(entry->channel_key);
639 memset(entry->key, 0, entry->key_len / 8);
640 silc_free(entry->key);
643 silc_free(entry->cipher);
644 if (entry->hmac_name)
645 silc_free(entry->hmac_name);
647 silc_free(entry->rekey);
649 /* Free all data, free also any reference from the client's channel
650 list since they share the same memory. */
651 silc_list_start(entry->user_list);
652 while ((chl = silc_list_get(entry->user_list)) != SILC_LIST_END) {
653 silc_list_del(chl->client->channels, chl);
654 silc_list_del(entry->user_list, chl);
658 memset(entry, 'F', sizeof(*entry));
666 /* Finds channel by channel name. Channel names are unique and they
667 are not case-sensitive. */
670 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
671 SilcIDCacheEntry *ret_entry)
673 SilcIDCacheList list = NULL;
674 SilcIDCacheEntry id_cache = NULL;
675 SilcChannelEntry channel;
677 SILC_LOG_DEBUG(("Channel by name"));
679 if (!silc_idcache_find_by_data_loose(id_list->channels, name, &list))
682 if (!silc_idcache_list_first(list, &id_cache)) {
683 silc_idcache_list_free(list);
687 channel = (SilcChannelEntry)id_cache->context;
690 *ret_entry = id_cache;
692 silc_idcache_list_free(list);
694 SILC_LOG_DEBUG(("Found"));
699 /* Finds channel by Channel ID. */
702 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
703 SilcIDCacheEntry *ret_entry)
705 SilcIDCacheEntry id_cache = NULL;
706 SilcChannelEntry channel;
711 SILC_LOG_DEBUG(("Channel ID (%s)",
712 silc_id_render(id, SILC_ID_CHANNEL)));
714 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id,
715 SILC_ID_CHANNEL, &id_cache))
718 channel = (SilcChannelEntry)id_cache->context;
721 *ret_entry = id_cache;
723 SILC_LOG_DEBUG(("Found"));
728 /* Replaces old Channel ID with new one. This is done when router forces
729 normal server to change Channel ID. */
732 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
733 SilcChannelID *new_id)
735 SilcIDCacheEntry id_cache = NULL;
736 SilcChannelEntry channel;
738 if (!old_id || !new_id)
741 SILC_LOG_DEBUG(("Replacing Channel ID"));
743 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
744 SILC_ID_CHANNEL, &id_cache))
747 channel = (SilcChannelEntry)id_cache->context;
748 silc_free(channel->id);
749 channel->id = new_id;
750 id_cache->id = (void *)new_id;
752 SILC_LOG_DEBUG(("Replaced"));
757 /* Returns channels from the ID list. If the `channel_id' is NULL then
758 all channels are returned. */
761 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
762 uint32 *channels_count)
764 SilcIDCacheList list = NULL;
765 SilcIDCacheEntry id_cache = NULL;
766 SilcChannelEntry *channels;
769 SILC_LOG_DEBUG(("Start"));
771 if (!silc_idcache_find_by_id(id_list->channels, channel_id ? channel_id :
772 SILC_ID_CACHE_ANY, SILC_ID_CHANNEL, &list))
775 channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels));
778 silc_idcache_list_first(list, &id_cache);
779 channels[i++] = (SilcChannelEntry)id_cache->context;
781 while (silc_idcache_list_next(list, &id_cache))
782 channels[i++] = (SilcChannelEntry)id_cache->context;
784 silc_idcache_list_free(list);