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;
48 data->created = time(0); /* Update creation time */
51 /* Free's all data in the common ID entry data structure. */
53 void silc_idlist_del_data(void *entry)
55 SilcIDListData idata = (SilcIDListData)entry;
57 silc_cipher_free(idata->send_key);
58 if (idata->receive_key)
59 silc_cipher_free(idata->receive_key);
61 if (idata->rekey->send_enc_key) {
62 memset(idata->rekey->send_enc_key, 0, idata->rekey->enc_key_len);
63 silc_free(idata->rekey->send_enc_key);
65 silc_free(idata->rekey);
67 if (idata->hmac_send) /* Same as idata->hmac_receive */
68 silc_hmac_free(idata->hmac_send);
69 if (idata->public_key)
70 silc_pkcs_public_key_free(idata->public_key);
75 SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge)
77 SilcIDListPurge i = (SilcIDListPurge)context;
79 SILC_LOG_DEBUG(("Start"));
81 silc_idcache_purge(i->cache);
82 silc_schedule_task_add(i->schedule, 0,
85 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
88 /******************************************************************************
90 Server entry functions
92 ******************************************************************************/
94 /* Add new server entry. This adds the new server entry to ID cache and
95 returns the allocated entry object or NULL on error. This is called
96 when new server connects to us. We also add ourselves to cache with
100 silc_idlist_add_server(SilcIDList id_list,
101 char *server_name, int server_type,
102 SilcServerID *id, SilcServerEntry router,
105 SilcServerEntry server;
107 SILC_LOG_DEBUG(("Adding new server entry"));
109 server = silc_calloc(1, sizeof(*server));
110 server->server_name = server_name;
111 server->server_type = server_type;
113 server->router = router;
114 server->connection = connection;
116 if (!silc_idcache_add(id_list->servers, server->server_name,
117 (void *)server->id, (void *)server, FALSE)) {
125 /* Finds server by Server ID */
128 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
129 bool registered, SilcIDCacheEntry *ret_entry)
131 SilcIDCacheEntry id_cache = NULL;
132 SilcServerEntry server;
137 SILC_LOG_DEBUG(("Server ID (%s)",
138 silc_id_render(id, SILC_ID_SERVER)));
140 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id,
144 server = (SilcServerEntry)id_cache->context;
147 *ret_entry = id_cache;
149 if (server && registered &&
150 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
153 SILC_LOG_DEBUG(("Found"));
158 /* Find server by name */
161 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
162 bool registered, SilcIDCacheEntry *ret_entry)
164 SilcIDCacheEntry id_cache = NULL;
165 SilcServerEntry server;
167 SILC_LOG_DEBUG(("Server by name `%s'", name));
169 if (!silc_idcache_find_by_name_one(id_list->servers, name, &id_cache))
172 server = (SilcServerEntry)id_cache->context;
175 *ret_entry = id_cache;
177 if (server && registered &&
178 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
181 SILC_LOG_DEBUG(("Found"));
186 /* Find server by connection parameters, hostname and port */
189 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
190 int port, bool registered,
191 SilcIDCacheEntry *ret_entry)
193 SilcIDCacheList list = NULL;
194 SilcIDCacheEntry id_cache = NULL;
195 SilcServerEntry server = NULL;
196 SilcSocketConnection sock;
198 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
200 if (!silc_idcache_get_all(id_list->servers, &list))
203 if (!silc_idcache_list_first(list, &id_cache)) {
204 silc_idcache_list_free(list);
209 server = (SilcServerEntry)id_cache->context;
210 sock = (SilcSocketConnection)server->connection;
212 if (sock && ((sock->hostname && !strcasecmp(sock->hostname, hostname)) ||
213 (sock->ip && !strcasecmp(sock->ip, hostname)))
214 && sock->port == port)
220 if (!silc_idcache_list_next(list, &id_cache))
224 silc_idcache_list_free(list);
227 *ret_entry = id_cache;
229 if (server && registered &&
230 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
233 SILC_LOG_DEBUG(("Found"));
238 /* Replaces old Server ID with new one */
241 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
242 SilcServerID *new_id)
244 SilcIDCacheEntry id_cache = NULL;
245 SilcServerEntry server;
247 if (!old_id || !new_id)
250 SILC_LOG_DEBUG(("Replacing Server ID"));
252 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id,
256 server = (SilcServerEntry)id_cache->context;
258 /* Remove the old entry and add a new one */
260 silc_idcache_del_by_id(id_list->servers, (void *)server->id);
262 silc_free(server->id);
265 silc_idcache_add(id_list->servers, server->server_name, server->id,
268 SILC_LOG_DEBUG(("Found"));
273 /* Removes and free's server entry from ID list */
275 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
277 SILC_LOG_DEBUG(("Start"));
280 /* Remove from cache */
282 if (!silc_idcache_del_by_id(id_list->servers, (void *)entry->id))
286 silc_free(entry->server_name);
287 silc_free(entry->id);
289 memset(entry, 'F', sizeof(*entry));
297 /******************************************************************************
299 Client entry functions
301 ******************************************************************************/
303 /* Add new client entry. This adds the client entry to ID cache system
304 and returns the allocated client entry or NULL on error. This is
305 called when new client connection is accepted to the server. If The
306 `router' is provided then the all server routines assume that the client
307 is not directly connected local client but it has router set and is
308 remote. If this is the case then `connection' must be NULL. If, on the
309 other hand, the `connection' is provided then the client is assumed
310 to be directly connected local client and `router' must be NULL. */
313 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
314 char *userinfo, SilcClientID *id,
315 SilcServerEntry router, void *connection)
317 SilcClientEntry client;
319 SILC_LOG_DEBUG(("Adding new client entry"));
321 client = silc_calloc(1, sizeof(*client));
322 client->nickname = nickname;
323 client->username = username;
324 client->userinfo = userinfo;
326 client->router = router;
327 client->connection = connection;
328 client->channels = silc_hash_table_alloc(3, silc_hash_ptr, NULL,
329 NULL, NULL, NULL, NULL, TRUE);
331 if (!silc_idcache_add(id_list->clients, nickname, (void *)client->id,
332 (void *)client, FALSE)) {
333 silc_hash_table_free(client->channels);
341 /* Free client entry. This free's everything and removes the entry
342 from ID cache. Call silc_idlist_del_data before calling this one. */
344 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
346 SILC_LOG_DEBUG(("Start"));
349 /* Remove from cache */
351 if (!silc_idcache_del_by_context(id_list->clients, entry))
355 silc_free(entry->nickname);
356 silc_free(entry->username);
357 silc_free(entry->userinfo);
358 silc_free(entry->id);
360 memset(entry, 'F', sizeof(*entry));
369 /* Returns all clients matching requested nickname. Number of clients is
370 returned to `clients_count'. Caller must free the returned table. */
372 int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
374 SilcClientEntry **clients,
375 uint32 *clients_count)
377 SilcIDCacheList list = NULL;
378 SilcIDCacheEntry id_cache = NULL;
380 SILC_LOG_DEBUG(("Start"));
382 if (!silc_idcache_find_by_name(id_list->clients, nickname, &list))
385 *clients = silc_realloc(*clients,
386 (silc_idcache_list_count(list) + *clients_count) *
389 silc_idcache_list_first(list, &id_cache);
390 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
392 while (silc_idcache_list_next(list, &id_cache))
393 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
395 silc_idcache_list_free(list);
397 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
402 /* Returns all clients matching requested nickname hash. Number of clients
403 is returned to `clients_count'. Caller must free the returned table. */
405 int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
407 SilcClientEntry **clients,
408 uint32 *clients_count)
410 SilcIDCacheList list = NULL;
411 SilcIDCacheEntry id_cache = NULL;
412 unsigned char hash[32];
413 SilcClientID client_id;
415 SILC_LOG_DEBUG(("Start"));
417 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
419 /* As the Client ID is hashed in the ID cache by hashing only the hash
420 from the Client ID, we can do a lookup with only the hash not the
421 other parts of the ID and get all the clients with that hash, ie.
422 with that nickname, as the hash is from the nickname. */
423 memset(&client_id, 0, sizeof(client_id));
424 memcpy(&client_id.hash, hash, sizeof(client_id.hash));
425 if (!silc_idcache_find_by_id(id_list->clients, &client_id, &list))
428 *clients = silc_realloc(*clients,
429 (silc_idcache_list_count(list) + *clients_count) *
432 silc_idcache_list_first(list, &id_cache);
433 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
435 while (silc_idcache_list_next(list, &id_cache))
436 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
438 silc_idcache_list_free(list);
440 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
445 /* Finds client by Client ID */
448 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
449 bool registered, SilcIDCacheEntry *ret_entry)
451 SilcIDCacheEntry id_cache = NULL;
452 SilcClientEntry client;
457 SILC_LOG_DEBUG(("Client ID (%s)",
458 silc_id_render(id, SILC_ID_CLIENT)));
460 /* Do extended search since the normal ID comparison function for
461 Client ID's compares only the hash from the Client ID and not the
462 entire ID. The silc_hash_client_id_compare compares the entire
463 Client ID as we want to find one specific Client ID. */
464 if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)id,
466 silc_hash_client_id_compare, NULL,
470 client = (SilcClientEntry)id_cache->context;
473 *ret_entry = id_cache;
475 if (client && registered &&
476 !(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
479 SILC_LOG_DEBUG(("Found"));
484 /* Replaces old Client ID with new one */
487 silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id,
488 SilcClientID *new_id)
490 SilcIDCacheEntry id_cache = NULL;
491 SilcClientEntry client;
493 if (!old_id || !new_id)
496 SILC_LOG_DEBUG(("Replacing Client ID"));
498 /* Do extended search since the normal ID comparison function for
499 Client ID's compares only the hash from the Client ID and not the
500 entire ID. The silc_hash_client_id_compare compares the entire
501 Client ID as we want to find one specific Client ID. */
502 if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)old_id,
504 silc_hash_client_id_compare, NULL,
508 client = (SilcClientEntry)id_cache->context;
510 /* Remove the old entry and add a new one */
512 silc_idcache_del_by_context(id_list->clients, client);
514 silc_free(client->id);
517 silc_idcache_add(id_list->clients, NULL, client->id, client, FALSE);
519 SILC_LOG_DEBUG(("Replaced"));
524 /* Client cache entry destructor that is called when the cache is purged. */
526 void silc_idlist_client_destructor(SilcIDCache cache,
527 SilcIDCacheEntry entry)
529 SilcClientEntry client;
531 SILC_LOG_DEBUG(("Start"));
533 client = (SilcClientEntry)entry->context;
535 if (client->nickname)
536 silc_free(client->nickname);
537 if (client->username)
538 silc_free(client->username);
539 if (client->userinfo)
540 silc_free(client->userinfo);
542 silc_free(client->id);
544 memset(client, 'F', sizeof(*client));
549 /******************************************************************************
551 Channel entry functions
553 ******************************************************************************/
555 /* Add new channel entry. This add the new channel entry to the ID cache
556 system and returns the allocated entry or NULL on error. */
559 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
560 SilcChannelID *id, SilcServerEntry router,
561 SilcCipher channel_key, SilcHmac hmac)
563 SilcChannelEntry channel;
565 SILC_LOG_DEBUG(("Adding new channel entry"));
567 channel = silc_calloc(1, sizeof(*channel));
568 channel->channel_name = channel_name;
569 channel->mode = mode;
571 channel->router = router;
572 channel->channel_key = channel_key;
573 channel->hmac = hmac;
574 channel->created = time(0);
576 if (!silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac)) {
581 channel->user_list = silc_hash_table_alloc(3, silc_hash_ptr, NULL, NULL,
582 NULL, NULL, NULL, TRUE);
584 if (!silc_idcache_add(id_list->channels, channel->channel_name,
585 (void *)channel->id, (void *)channel, FALSE)) {
586 silc_hmac_free(channel->hmac);
587 silc_hash_table_free(channel->user_list);
595 /* Foreach callbcak to free all users from the channel when deleting a
598 static void silc_idlist_del_channel_foreach(void *key, void *context,
601 SilcChannelClientEntry chl = (SilcChannelClientEntry)context;
603 /* Remove the context from the client's channel hash table as that
604 table and channel's user_list hash table share this same context. */
605 silc_hash_table_del(chl->client->channels, chl->channel);
609 /* Free channel entry. This free's everything. */
611 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
613 SILC_LOG_DEBUG(("Start"));
616 /* Remove from cache */
618 if (!silc_idcache_del_by_id(id_list->channels, (void *)entry->id))
622 silc_free(entry->channel_name);
623 silc_free(entry->id);
624 silc_free(entry->topic);
625 if (entry->channel_key)
626 silc_cipher_free(entry->channel_key);
628 memset(entry->key, 0, entry->key_len / 8);
629 silc_free(entry->key);
631 silc_free(entry->cipher);
632 silc_free(entry->hmac_name);
633 silc_free(entry->rekey);
635 /* Free all client entrys from the users list. The silc_hash_table_free
636 will free all the entries so they are not freed at the foreach
638 silc_hash_table_foreach(entry->user_list, silc_idlist_del_channel_foreach,
640 silc_hash_table_free(entry->user_list);
642 memset(entry, 'F', sizeof(*entry));
650 /* Finds channel by channel name. Channel names are unique and they
651 are not case-sensitive. */
654 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
655 SilcIDCacheEntry *ret_entry)
657 SilcIDCacheEntry id_cache = NULL;
659 SILC_LOG_DEBUG(("Channel by name"));
661 if (!silc_idcache_find_by_name_one(id_list->channels, name, &id_cache))
665 *ret_entry = id_cache;
667 SILC_LOG_DEBUG(("Found"));
669 return id_cache->context;
672 /* Finds channel by Channel ID. */
675 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
676 SilcIDCacheEntry *ret_entry)
678 SilcIDCacheEntry id_cache = NULL;
679 SilcChannelEntry channel;
684 SILC_LOG_DEBUG(("Channel ID (%s)",
685 silc_id_render(id, SILC_ID_CHANNEL)));
687 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, &id_cache))
690 channel = (SilcChannelEntry)id_cache->context;
693 *ret_entry = id_cache;
695 SILC_LOG_DEBUG(("Found"));
700 /* Replaces old Channel ID with new one. This is done when router forces
701 normal server to change Channel ID. */
704 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
705 SilcChannelID *new_id)
707 SilcIDCacheEntry id_cache = NULL;
708 SilcChannelEntry channel;
710 if (!old_id || !new_id)
713 SILC_LOG_DEBUG(("Replacing Channel ID"));
715 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
719 channel = (SilcChannelEntry)id_cache->context;
721 /* Remove the old entry and add a new one */
723 silc_idcache_del_by_id(id_list->channels, (void *)channel->id);
725 silc_free(channel->id);
726 channel->id = new_id;
728 silc_idcache_add(id_list->channels, channel->channel_name, channel->id,
731 SILC_LOG_DEBUG(("Replaced"));
736 /* Returns channels from the ID list. If the `channel_id' is NULL then
737 all channels are returned. */
740 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
741 uint32 *channels_count)
743 SilcIDCacheList list = NULL;
744 SilcIDCacheEntry id_cache = NULL;
745 SilcChannelEntry *channels = NULL;
748 SILC_LOG_DEBUG(("Start"));
751 if (!silc_idcache_get_all(id_list->channels, &list))
754 channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels));
757 silc_idcache_list_first(list, &id_cache);
758 channels[i++] = (SilcChannelEntry)id_cache->context;
760 while (silc_idcache_list_next(list, &id_cache))
761 channels[i++] = (SilcChannelEntry)id_cache->context;
763 silc_idcache_list_free(list);
765 if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache))
769 channels = silc_calloc(1, sizeof(*channels));
770 channels[0] = (SilcChannelEntry)id_cache->context;