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_send = idata->hmac_send;
42 data->hmac_receive = idata->hmac_receive;
43 data->public_key = idata->public_key;
44 data->last_receive = idata->last_receive;
45 data->last_sent = idata->last_sent;
46 data->status = idata->status;
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 if (idata->rekey->send_enc_key) {
60 memset(idata->rekey->send_enc_key, 0, idata->rekey->enc_key_len);
61 silc_free(idata->rekey->send_enc_key);
63 silc_free(idata->rekey);
65 if (idata->hmac_send) /* Same as idata->hmac_receive */
66 silc_hmac_free(idata->hmac_send);
67 if (idata->public_key)
68 silc_pkcs_public_key_free(idata->public_key);
73 SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge)
75 SilcIDListPurge i = (SilcIDListPurge)context;
77 SILC_LOG_DEBUG(("Start"));
79 silc_idcache_purge(i->cache);
80 silc_schedule_task_add(i->schedule, 0,
83 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
86 /******************************************************************************
88 Server entry functions
90 ******************************************************************************/
92 /* Add new server entry. This adds the new server entry to ID cache and
93 returns the allocated entry object or NULL on error. This is called
94 when new server connects to us. We also add ourselves to cache with
98 silc_idlist_add_server(SilcIDList id_list,
99 char *server_name, int server_type,
100 SilcServerID *id, SilcServerEntry router,
103 SilcServerEntry server;
105 SILC_LOG_DEBUG(("Adding new server entry"));
107 server = silc_calloc(1, sizeof(*server));
108 server->server_name = server_name;
109 server->server_type = server_type;
111 server->router = router;
112 server->connection = connection;
114 if (!silc_idcache_add(id_list->servers, server->server_name,
115 (void *)server->id, (void *)server, FALSE)) {
123 /* Finds server by Server ID */
126 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
127 bool registered, SilcIDCacheEntry *ret_entry)
129 SilcIDCacheEntry id_cache = NULL;
130 SilcServerEntry server;
135 SILC_LOG_DEBUG(("Server ID (%s)",
136 silc_id_render(id, SILC_ID_SERVER)));
138 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id,
142 server = (SilcServerEntry)id_cache->context;
145 *ret_entry = id_cache;
147 if (server && registered &&
148 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
151 SILC_LOG_DEBUG(("Found"));
156 /* Find server by name */
159 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
160 bool registered, SilcIDCacheEntry *ret_entry)
162 SilcIDCacheEntry id_cache = NULL;
163 SilcServerEntry server;
165 SILC_LOG_DEBUG(("Server by name `%s'", name));
167 if (!silc_idcache_find_by_name_one(id_list->servers, name, &id_cache))
170 server = (SilcServerEntry)id_cache->context;
173 *ret_entry = id_cache;
175 if (server && registered &&
176 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
179 SILC_LOG_DEBUG(("Found"));
184 /* Find server by connection parameters, hostname and port */
187 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
188 int port, bool registered,
189 SilcIDCacheEntry *ret_entry)
191 SilcIDCacheList list = NULL;
192 SilcIDCacheEntry id_cache = NULL;
193 SilcServerEntry server = NULL;
194 SilcSocketConnection sock;
196 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
198 if (!silc_idcache_get_all(id_list->servers, &list))
201 if (!silc_idcache_list_first(list, &id_cache)) {
202 silc_idcache_list_free(list);
207 server = (SilcServerEntry)id_cache->context;
208 sock = (SilcSocketConnection)server->connection;
210 if (sock && ((sock->hostname && !strcasecmp(sock->hostname, hostname)) ||
211 (sock->ip && !strcasecmp(sock->ip, hostname)))
212 && sock->port == port)
218 if (!silc_idcache_list_next(list, &id_cache))
222 silc_idcache_list_free(list);
225 *ret_entry = id_cache;
227 if (server && registered &&
228 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
231 SILC_LOG_DEBUG(("Found"));
236 /* Replaces old Server ID with new one */
239 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
240 SilcServerID *new_id)
242 SilcIDCacheEntry id_cache = NULL;
243 SilcServerEntry server;
245 if (!old_id || !new_id)
248 SILC_LOG_DEBUG(("Replacing Server ID"));
250 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id,
254 server = (SilcServerEntry)id_cache->context;
256 /* Remove the old entry and add a new one */
258 silc_idcache_del_by_id(id_list->servers, (void *)server->id);
260 silc_free(server->id);
263 silc_idcache_add(id_list->servers, server->server_name, server->id,
266 SILC_LOG_DEBUG(("Found"));
271 /* Removes and free's server entry from ID list */
273 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
275 SILC_LOG_DEBUG(("Start"));
278 /* Remove from cache */
280 if (!silc_idcache_del_by_id(id_list->servers, (void *)entry->id))
284 silc_free(entry->server_name);
285 silc_free(entry->id);
287 memset(entry, 'F', sizeof(*entry));
295 /******************************************************************************
297 Client entry functions
299 ******************************************************************************/
301 /* Add new client entry. This adds the client entry to ID cache system
302 and returns the allocated client entry or NULL on error. This is
303 called when new client connection is accepted to the server. If The
304 `router' is provided then the all server routines assume that the client
305 is not directly connected local client but it has router set and is
306 remote. If this is the case then `connection' must be NULL. If, on the
307 other hand, the `connection' is provided then the client is assumed
308 to be directly connected local client and `router' must be NULL. */
311 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
312 char *userinfo, SilcClientID *id,
313 SilcServerEntry router, void *connection)
315 SilcClientEntry client;
317 SILC_LOG_DEBUG(("Adding new client entry"));
319 client = silc_calloc(1, sizeof(*client));
320 client->nickname = nickname;
321 client->username = username;
322 client->userinfo = userinfo;
324 client->router = router;
325 client->connection = connection;
326 client->channels = silc_hash_table_alloc(3, silc_hash_ptr, NULL,
327 NULL, NULL, NULL, NULL, TRUE);
329 if (!silc_idcache_add(id_list->clients, nickname, (void *)client->id,
330 (void *)client, FALSE)) {
331 silc_hash_table_free(client->channels);
339 /* Free client entry. This free's everything and removes the entry
340 from ID cache. Call silc_idlist_del_data before calling this one. */
342 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
344 SILC_LOG_DEBUG(("Start"));
347 /* Remove from cache */
349 if (!silc_idcache_del_by_context(id_list->clients, entry))
353 silc_free(entry->nickname);
354 silc_free(entry->username);
355 silc_free(entry->userinfo);
356 silc_free(entry->id);
358 memset(entry, 'F', sizeof(*entry));
367 /* Returns all clients matching requested nickname. Number of clients is
368 returned to `clients_count'. Caller must free the returned table. */
370 int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
372 SilcClientEntry **clients,
373 uint32 *clients_count)
375 SilcIDCacheList list = NULL;
376 SilcIDCacheEntry id_cache = NULL;
378 SILC_LOG_DEBUG(("Start"));
380 if (!silc_idcache_find_by_name(id_list->clients, nickname, &list))
383 *clients = silc_realloc(*clients,
384 (silc_idcache_list_count(list) + *clients_count) *
387 silc_idcache_list_first(list, &id_cache);
388 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
390 while (silc_idcache_list_next(list, &id_cache))
391 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
393 silc_idcache_list_free(list);
395 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
400 /* Returns all clients matching requested nickname hash. Number of clients
401 is returned to `clients_count'. Caller must free the returned table. */
403 int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
405 SilcClientEntry **clients,
406 uint32 *clients_count)
408 SilcIDCacheList list = NULL;
409 SilcIDCacheEntry id_cache = NULL;
410 unsigned char hash[32];
411 SilcClientID client_id;
413 SILC_LOG_DEBUG(("Start"));
415 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
417 /* As the Client ID is hashed in the ID cache by hashing only the hash
418 from the Client ID, we can do a lookup with only the hash not the
419 other parts of the ID and get all the clients with that hash, ie.
420 with that nickname, as the hash is from the nickname. */
421 memset(&client_id, 0, sizeof(client_id));
422 memcpy(&client_id.hash, hash, sizeof(client_id.hash));
423 if (!silc_idcache_find_by_id(id_list->clients, &client_id, &list))
426 *clients = silc_realloc(*clients,
427 (silc_idcache_list_count(list) + *clients_count) *
430 silc_idcache_list_first(list, &id_cache);
431 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
433 while (silc_idcache_list_next(list, &id_cache))
434 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
436 silc_idcache_list_free(list);
438 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
443 /* Finds client by Client ID */
446 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
447 bool registered, SilcIDCacheEntry *ret_entry)
449 SilcIDCacheEntry id_cache = NULL;
450 SilcClientEntry client;
455 SILC_LOG_DEBUG(("Client ID (%s)",
456 silc_id_render(id, SILC_ID_CLIENT)));
458 /* Do extended search since the normal ID comparison function for
459 Client ID's compares only the hash from the Client ID and not the
460 entire ID. The silc_hash_client_id_compare compares the entire
461 Client ID as we want to find one specific Client ID. */
462 if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)id,
464 silc_hash_client_id_compare, NULL,
468 client = (SilcClientEntry)id_cache->context;
471 *ret_entry = id_cache;
473 if (client && registered &&
474 !(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
477 SILC_LOG_DEBUG(("Found"));
482 /* Replaces old Client ID with new one */
485 silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id,
486 SilcClientID *new_id)
488 SilcIDCacheEntry id_cache = NULL;
489 SilcClientEntry client;
491 if (!old_id || !new_id)
494 SILC_LOG_DEBUG(("Replacing Client ID"));
496 /* Do extended search since the normal ID comparison function for
497 Client ID's compares only the hash from the Client ID and not the
498 entire ID. The silc_hash_client_id_compare compares the entire
499 Client ID as we want to find one specific Client ID. */
500 if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)old_id,
502 silc_hash_client_id_compare, NULL,
506 client = (SilcClientEntry)id_cache->context;
508 /* Remove the old entry and add a new one */
510 silc_idcache_del_by_context(id_list->clients, client);
512 silc_free(client->id);
515 silc_idcache_add(id_list->clients, NULL, client->id, client, FALSE);
517 SILC_LOG_DEBUG(("Replaced"));
522 /* Client cache entry destructor that is called when the cache is purged. */
524 void silc_idlist_client_destructor(SilcIDCache cache,
525 SilcIDCacheEntry entry)
527 SilcClientEntry client;
529 SILC_LOG_DEBUG(("Start"));
531 client = (SilcClientEntry)entry->context;
533 if (client->nickname)
534 silc_free(client->nickname);
535 if (client->username)
536 silc_free(client->username);
537 if (client->userinfo)
538 silc_free(client->userinfo);
540 silc_free(client->id);
542 memset(client, 'F', sizeof(*client));
547 /******************************************************************************
549 Channel entry functions
551 ******************************************************************************/
553 /* Add new channel entry. This add the new channel entry to the ID cache
554 system and returns the allocated entry or NULL on error. */
557 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
558 SilcChannelID *id, SilcServerEntry router,
559 SilcCipher channel_key, SilcHmac hmac)
561 SilcChannelEntry channel;
563 SILC_LOG_DEBUG(("Adding new channel entry"));
565 channel = silc_calloc(1, sizeof(*channel));
566 channel->channel_name = channel_name;
567 channel->mode = mode;
569 channel->router = router;
570 channel->channel_key = channel_key;
571 channel->hmac = hmac;
573 if (!silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac)) {
578 channel->user_list = silc_hash_table_alloc(3, silc_hash_ptr, NULL, NULL,
579 NULL, NULL, NULL, TRUE);
581 if (!silc_idcache_add(id_list->channels, channel->channel_name,
582 (void *)channel->id, (void *)channel, FALSE)) {
583 silc_hmac_free(channel->hmac);
584 silc_hash_table_free(channel->user_list);
592 /* Foreach callbcak to free all users from the channel when deleting a
595 static void silc_idlist_del_channel_foreach(void *key, void *context,
598 SilcChannelClientEntry chl = (SilcChannelClientEntry)context;
600 /* Remove the context from the client's channel hash table as that
601 table and channel's user_list hash table share this same context. */
602 silc_hash_table_del(chl->client->channels, chl->channel);
606 /* Free channel entry. This free's everything. */
608 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
610 SILC_LOG_DEBUG(("Start"));
613 /* Remove from cache */
615 if (!silc_idcache_del_by_id(id_list->channels, (void *)entry->id))
619 silc_free(entry->channel_name);
620 silc_free(entry->id);
621 silc_free(entry->topic);
622 if (entry->channel_key)
623 silc_cipher_free(entry->channel_key);
625 memset(entry->key, 0, entry->key_len / 8);
626 silc_free(entry->key);
628 silc_free(entry->cipher);
629 silc_free(entry->hmac_name);
630 silc_free(entry->rekey);
632 /* Free all client entrys from the users list. The silc_hash_table_free
633 will free all the entries so they are not freed at the foreach
635 silc_hash_table_foreach(entry->user_list, silc_idlist_del_channel_foreach,
637 silc_hash_table_free(entry->user_list);
639 memset(entry, 'F', sizeof(*entry));
647 /* Finds channel by channel name. Channel names are unique and they
648 are not case-sensitive. */
651 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
652 SilcIDCacheEntry *ret_entry)
654 SilcIDCacheEntry id_cache = NULL;
656 SILC_LOG_DEBUG(("Channel by name"));
658 if (!silc_idcache_find_by_name_one(id_list->channels, name, &id_cache))
662 *ret_entry = id_cache;
664 SILC_LOG_DEBUG(("Found"));
666 return id_cache->context;
669 /* Finds channel by Channel ID. */
672 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
673 SilcIDCacheEntry *ret_entry)
675 SilcIDCacheEntry id_cache = NULL;
676 SilcChannelEntry channel;
681 SILC_LOG_DEBUG(("Channel ID (%s)",
682 silc_id_render(id, SILC_ID_CHANNEL)));
684 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, &id_cache))
687 channel = (SilcChannelEntry)id_cache->context;
690 *ret_entry = id_cache;
692 SILC_LOG_DEBUG(("Found"));
697 /* Replaces old Channel ID with new one. This is done when router forces
698 normal server to change Channel ID. */
701 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
702 SilcChannelID *new_id)
704 SilcIDCacheEntry id_cache = NULL;
705 SilcChannelEntry channel;
707 if (!old_id || !new_id)
710 SILC_LOG_DEBUG(("Replacing Channel ID"));
712 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
716 channel = (SilcChannelEntry)id_cache->context;
718 /* Remove the old entry and add a new one */
720 silc_idcache_del_by_id(id_list->channels, (void *)channel->id);
722 silc_free(channel->id);
723 channel->id = new_id;
725 silc_idcache_add(id_list->channels, channel->channel_name, channel->id,
728 SILC_LOG_DEBUG(("Replaced"));
733 /* Returns channels from the ID list. If the `channel_id' is NULL then
734 all channels are returned. */
737 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
738 uint32 *channels_count)
740 SilcIDCacheList list = NULL;
741 SilcIDCacheEntry id_cache = NULL;
742 SilcChannelEntry *channels = NULL;
745 SILC_LOG_DEBUG(("Start"));
748 if (!silc_idcache_get_all(id_list->channels, &list))
751 channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels));
754 silc_idcache_list_first(list, &id_cache);
755 channels[i++] = (SilcChannelEntry)id_cache->context;
757 while (silc_idcache_list_next(list, &id_cache))
758 channels[i++] = (SilcChannelEntry)id_cache->context;
760 silc_idcache_list_free(list);
762 if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache))
766 channels = silc_calloc(1, sizeof(*channels));
767 channels[0] = (SilcChannelEntry)id_cache->context;