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->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 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 && !server->data.registered)
150 SILC_LOG_DEBUG(("Found"));
155 /* Find server by name */
158 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
159 bool registered, SilcIDCacheEntry *ret_entry)
161 SilcIDCacheEntry id_cache = NULL;
162 SilcServerEntry server;
164 SILC_LOG_DEBUG(("Server by name `%s'", name));
166 if (!silc_idcache_find_by_name_one(id_list->servers, name, &id_cache))
169 server = (SilcServerEntry)id_cache->context;
172 *ret_entry = id_cache;
174 if (server && registered && !server->data.registered)
177 SILC_LOG_DEBUG(("Found"));
182 /* Find server by connection parameters, hostname and port */
185 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
186 int port, bool registered,
187 SilcIDCacheEntry *ret_entry)
189 SilcIDCacheList list = NULL;
190 SilcIDCacheEntry id_cache = NULL;
191 SilcServerEntry server = NULL;
192 SilcSocketConnection sock;
194 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
196 if (!silc_idcache_get_all(id_list->servers, &list))
199 if (!silc_idcache_list_first(list, &id_cache)) {
200 silc_idcache_list_free(list);
205 server = (SilcServerEntry)id_cache->context;
206 sock = (SilcSocketConnection)server->connection;
208 if (sock && ((sock->hostname && !strcasecmp(sock->hostname, hostname)) ||
209 (sock->ip && !strcasecmp(sock->ip, hostname)))
210 && sock->port == port)
216 if (!silc_idcache_list_next(list, &id_cache))
220 silc_idcache_list_free(list);
223 *ret_entry = id_cache;
225 if (server && registered && !server->data.registered)
228 SILC_LOG_DEBUG(("Found"));
233 /* Replaces old Server ID with new one */
236 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
237 SilcServerID *new_id)
239 SilcIDCacheEntry id_cache = NULL;
240 SilcServerEntry server;
242 if (!old_id || !new_id)
245 SILC_LOG_DEBUG(("Replacing Server ID"));
247 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id,
251 server = (SilcServerEntry)id_cache->context;
253 /* Remove the old entry and add a new one */
255 silc_idcache_del_by_id(id_list->servers, (void *)server->id);
257 silc_free(server->id);
260 silc_idcache_add(id_list->servers, server->server_name, server->id,
263 SILC_LOG_DEBUG(("Found"));
268 /* Removes and free's server entry from ID list */
270 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
272 SILC_LOG_DEBUG(("Start"));
275 /* Remove from cache */
277 if (!silc_idcache_del_by_id(id_list->servers, (void *)entry->id))
281 if (entry->server_name)
282 silc_free(entry->server_name);
284 silc_free(entry->id);
286 memset(entry, 'F', sizeof(*entry));
294 /******************************************************************************
296 Client entry functions
298 ******************************************************************************/
300 /* Add new client entry. This adds the client entry to ID cache system
301 and returns the allocated client entry or NULL on error. This is
302 called when new client connection is accepted to the server. If The
303 `router' is provided then the all server routines assume that the client
304 is not directly connected local client but it has router set and is
305 remote. If this is the case then `connection' must be NULL. If, on the
306 other hand, the `connection' is provided then the client is assumed
307 to be directly connected local client and `router' must be NULL. */
310 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
311 char *userinfo, SilcClientID *id,
312 SilcServerEntry router, void *connection)
314 SilcClientEntry client;
316 SILC_LOG_DEBUG(("Adding new client entry"));
318 client = silc_calloc(1, sizeof(*client));
319 client->nickname = nickname;
320 client->username = username;
321 client->userinfo = userinfo;
323 client->router = router;
324 client->connection = connection;
325 client->channels = silc_hash_table_alloc(3, silc_hash_ptr, NULL,
326 NULL, NULL, NULL, NULL, TRUE);
328 if (!silc_idcache_add(id_list->clients, nickname, (void *)client->id,
329 (void *)client, FALSE)) {
330 silc_hash_table_free(client->channels);
338 /* Free client entry. This free's everything and removes the entry
339 from ID cache. Call silc_idlist_del_data before calling this one. */
341 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
343 SILC_LOG_DEBUG(("Start"));
346 /* Remove from cache */
348 if (!silc_idcache_del_by_context(id_list->clients, entry))
353 silc_free(entry->nickname);
355 silc_free(entry->username);
357 silc_free(entry->userinfo);
359 silc_free(entry->id);
361 memset(entry, 'F', sizeof(*entry));
370 /* Returns all clients matching requested nickname. Number of clients is
371 returned to `clients_count'. Caller must free the returned table. */
373 int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
375 SilcClientEntry **clients,
376 uint32 *clients_count)
378 SilcIDCacheList list = NULL;
379 SilcIDCacheEntry id_cache = NULL;
382 SILC_LOG_DEBUG(("Start"));
384 if (!silc_idcache_find_by_name(id_list->clients, nickname, &list))
387 *clients = silc_realloc(*clients,
388 (silc_idcache_list_count(list) + *clients_count) *
392 silc_idcache_list_first(list, &id_cache);
393 (*clients)[i++] = (SilcClientEntry)id_cache->context;
395 while (silc_idcache_list_next(list, &id_cache))
396 (*clients)[i++] = (SilcClientEntry)id_cache->context;
398 silc_idcache_list_free(list);
402 SILC_LOG_DEBUG(("Found %d clients", *clients_count));
407 /* Returns all clients matching requested nickname hash. Number of clients
408 is returned to `clients_count'. Caller must free the returned table. */
410 int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
412 SilcClientEntry **clients,
413 uint32 *clients_count)
415 SilcIDCacheList list = NULL;
416 SilcIDCacheEntry id_cache = NULL;
417 unsigned char hash[32];
419 SilcClientID client_id;
421 SILC_LOG_DEBUG(("Start"));
423 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
425 /* As the Client ID is hashed in the ID cache by hashing only the hash
426 from the Client ID, we can do a lookup with only the hash not the
427 other parts of the ID and get all the clients with that hash, ie.
428 with that nickname, as the hash is from the nickname. */
429 memset(&client_id, 0, sizeof(client_id));
430 memcpy(&client_id.hash, hash, sizeof(client_id.hash));
431 if (!silc_idcache_find_by_id(id_list->clients, &client_id, &list))
434 *clients = silc_realloc(*clients,
435 (silc_idcache_list_count(list) + *clients_count) *
439 silc_idcache_list_first(list, &id_cache);
440 (*clients)[i++] = (SilcClientEntry)id_cache->context;
442 while (silc_idcache_list_next(list, &id_cache))
443 (*clients)[i++] = (SilcClientEntry)id_cache->context;
445 silc_idcache_list_free(list);
449 SILC_LOG_DEBUG(("Found %d clients", *clients_count));
454 /* Finds client by Client ID */
457 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
458 bool registered, SilcIDCacheEntry *ret_entry)
460 SilcIDCacheEntry id_cache = NULL;
461 SilcClientEntry client;
466 SILC_LOG_DEBUG(("Client ID (%s)",
467 silc_id_render(id, SILC_ID_CLIENT)));
469 /* Do extended search since the normal ID comparison function for
470 Client ID's compares only the hash from the Client ID and not the
471 entire ID. The silc_hash_client_id_compare compares the entire
472 Client ID as we want to find one specific Client ID. */
473 if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)id,
475 silc_hash_client_id_compare, NULL,
479 client = (SilcClientEntry)id_cache->context;
482 *ret_entry = id_cache;
484 if (client && registered && !client->data.registered)
487 SILC_LOG_DEBUG(("Found"));
492 /* Replaces old Client ID with new one */
495 silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id,
496 SilcClientID *new_id)
498 SilcIDCacheEntry id_cache = NULL;
499 SilcClientEntry client;
501 if (!old_id || !new_id)
504 SILC_LOG_DEBUG(("Replacing Client ID"));
506 /* Do extended search since the normal ID comparison function for
507 Client ID's compares only the hash from the Client ID and not the
508 entire ID. The silc_hash_client_id_compare compares the entire
509 Client ID as we want to find one specific Client ID. */
510 if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)old_id,
512 silc_hash_client_id_compare, NULL,
516 client = (SilcClientEntry)id_cache->context;
518 /* Remove the old entry and add a new one */
520 silc_idcache_del_by_context(id_list->clients, client);
522 silc_free(client->id);
525 silc_idcache_add(id_list->clients, client->nickname, client->id,
528 SILC_LOG_DEBUG(("Replaced"));
533 /* Client cache entry destructor that is called when the cache is purged. */
535 void silc_idlist_client_destructor(SilcIDCache cache,
536 SilcIDCacheEntry entry)
538 SilcClientEntry client;
540 SILC_LOG_DEBUG(("Start"));
542 client = (SilcClientEntry)entry->context;
544 if (client->nickname)
545 silc_free(client->nickname);
546 if (client->username)
547 silc_free(client->username);
548 if (client->userinfo)
549 silc_free(client->userinfo);
551 silc_free(client->id);
553 memset(client, 'F', sizeof(*client));
558 /******************************************************************************
560 Channel entry functions
562 ******************************************************************************/
564 /* Add new channel entry. This add the new channel entry to the ID cache
565 system and returns the allocated entry or NULL on error. */
568 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
569 SilcChannelID *id, SilcServerEntry router,
570 SilcCipher channel_key, SilcHmac hmac)
572 SilcChannelEntry channel;
574 SILC_LOG_DEBUG(("Adding new channel entry"));
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 channel->user_list = silc_hash_table_alloc(3, silc_hash_ptr, NULL, NULL,
590 NULL, NULL, NULL, TRUE);
592 if (!silc_idcache_add(id_list->channels, channel->channel_name,
593 (void *)channel->id, (void *)channel, FALSE)) {
594 silc_hmac_free(channel->hmac);
595 silc_hash_table_free(channel->user_list);
603 /* Foreach callbcak to free all users from the channel when deleting a
606 static void silc_idlist_del_channel_foreach(void *key, void *context,
609 SilcChannelClientEntry chl = (SilcChannelClientEntry)context;
611 /* Remove the context from the client's channel hash table as that
612 table and channel's user_list hash table share this same context. */
613 silc_hash_table_del(chl->client->channels, chl->channel);
617 /* Free channel entry. This free's everything. */
619 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
621 SILC_LOG_DEBUG(("Start"));
624 /* Remove from cache */
626 if (!silc_idcache_del_by_id(id_list->channels, (void *)entry->id))
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 client entrys from the users list. The silc_hash_table_free
650 will free all the entries so they are not freed at the foreach
652 silc_hash_table_foreach(entry->user_list, silc_idlist_del_channel_foreach,
654 silc_hash_table_free(entry->user_list);
656 memset(entry, 'F', sizeof(*entry));
664 /* Finds channel by channel name. Channel names are unique and they
665 are not case-sensitive. */
668 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
669 SilcIDCacheEntry *ret_entry)
671 SilcIDCacheEntry id_cache = NULL;
673 SILC_LOG_DEBUG(("Channel by name"));
675 if (!silc_idcache_find_by_name_one(id_list->channels, name, &id_cache))
679 *ret_entry = id_cache;
681 SILC_LOG_DEBUG(("Found"));
683 return id_cache->context;
686 /* Finds channel by Channel ID. */
689 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
690 SilcIDCacheEntry *ret_entry)
692 SilcIDCacheEntry id_cache = NULL;
693 SilcChannelEntry channel;
698 SILC_LOG_DEBUG(("Channel ID (%s)",
699 silc_id_render(id, SILC_ID_CHANNEL)));
701 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, &id_cache))
704 channel = (SilcChannelEntry)id_cache->context;
707 *ret_entry = id_cache;
709 SILC_LOG_DEBUG(("Found"));
714 /* Replaces old Channel ID with new one. This is done when router forces
715 normal server to change Channel ID. */
718 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
719 SilcChannelID *new_id)
721 SilcIDCacheEntry id_cache = NULL;
722 SilcChannelEntry channel;
724 if (!old_id || !new_id)
727 SILC_LOG_DEBUG(("Replacing Channel ID"));
729 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
733 channel = (SilcChannelEntry)id_cache->context;
735 /* Remove the old entry and add a new one */
737 silc_idcache_del_by_id(id_list->channels, (void *)channel->id);
739 silc_free(channel->id);
740 channel->id = new_id;
742 silc_idcache_add(id_list->channels, channel->channel_name, channel->id,
745 SILC_LOG_DEBUG(("Replaced"));
750 /* Returns channels from the ID list. If the `channel_id' is NULL then
751 all channels are returned. */
754 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
755 uint32 *channels_count)
757 SilcIDCacheList list = NULL;
758 SilcIDCacheEntry id_cache = NULL;
759 SilcChannelEntry *channels = NULL;
762 SILC_LOG_DEBUG(("Start"));
765 if (!silc_idcache_get_all(id_list->channels, &list))
768 channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels));
771 silc_idcache_list_first(list, &id_cache);
772 channels[i++] = (SilcChannelEntry)id_cache->context;
774 while (silc_idcache_list_next(list, &id_cache))
775 channels[i++] = (SilcChannelEntry)id_cache->context;
777 silc_idcache_list_free(list);
779 if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache))
783 channels = silc_calloc(1, sizeof(*channels));
784 channels[0] = (SilcChannelEntry)id_cache->context;