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_task_register(i->timeout_queue, 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 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;
150 /* Find server by name */
153 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
154 SilcIDCacheEntry *ret_entry)
156 SilcIDCacheEntry id_cache = NULL;
157 SilcServerEntry server;
159 SILC_LOG_DEBUG(("Server by name `%s'", name));
161 if (!silc_idcache_find_by_name_one(id_list->servers, name, &id_cache))
164 server = (SilcServerEntry)id_cache->context;
167 *ret_entry = id_cache;
169 SILC_LOG_DEBUG(("Found"));
174 /* Find server by connection parameters, hostname and port */
177 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
178 int port, SilcIDCacheEntry *ret_entry)
180 SilcIDCacheList list = NULL;
181 SilcIDCacheEntry id_cache = NULL;
182 SilcServerEntry server = NULL;
183 SilcSocketConnection sock;
185 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
187 if (!silc_idcache_get_all(id_list->servers, &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 && !strcasecmp(sock->hostname, hostname)) ||
200 (sock->ip && !strcasecmp(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,
239 server = (SilcServerEntry)id_cache->context;
240 silc_free(server->id);
243 /* Remove the old entry and add a new one */
244 silc_idcache_del_by_context(id_list->servers, server);
245 silc_idcache_add(id_list->servers, server->server_name, server->id,
248 SILC_LOG_DEBUG(("Found"));
253 /* Removes and free's server entry from ID list */
255 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
257 SILC_LOG_DEBUG(("Start"));
260 /* Remove from cache */
262 if (!silc_idcache_del_by_id(id_list->servers, (void *)entry->id))
266 if (entry->server_name)
267 silc_free(entry->server_name);
269 silc_free(entry->id);
271 memset(entry, 'F', sizeof(*entry));
279 /******************************************************************************
281 Client entry functions
283 ******************************************************************************/
285 /* Add new client entry. This adds the client entry to ID cache system
286 and returns the allocated client entry or NULL on error. This is
287 called when new client connection is accepted to the server. If The
288 `router' is provided then the all server routines assume that the client
289 is not directly connected local client but it has router set and is
290 remote. If this is the case then `connection' must be NULL. If, on the
291 other hand, the `connection' is provided then the client is assumed
292 to be directly connected local client and `router' must be NULL. */
295 silc_idlist_add_client(SilcIDList id_list, char *nickname, 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, (void *)client->id,
314 (void *)client, FALSE)) {
322 /* Free client entry. This free's everything and removes the entry
323 from ID cache. Call silc_idlist_del_data before calling this one. */
325 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
327 SILC_LOG_DEBUG(("Start"));
330 /* Remove from cache */
332 if (!silc_idcache_del_by_context(id_list->clients, entry))
337 silc_free(entry->nickname);
339 silc_free(entry->username);
341 silc_free(entry->userinfo);
343 silc_free(entry->id);
345 memset(entry, 'F', sizeof(*entry));
354 /* Returns all clients matching requested nickname. Number of clients is
355 returned to `clients_count'. Caller must free the returned table. */
357 int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
359 SilcClientEntry **clients,
360 uint32 *clients_count)
362 SilcIDCacheList list = NULL;
363 SilcIDCacheEntry id_cache = NULL;
366 SILC_LOG_DEBUG(("Start"));
368 if (!silc_idcache_find_by_name(id_list->clients, nickname, &list))
371 *clients = silc_realloc(*clients,
372 (silc_idcache_list_count(list) + *clients_count) *
376 silc_idcache_list_first(list, &id_cache);
377 (*clients)[i++] = (SilcClientEntry)id_cache->context;
379 while (silc_idcache_list_next(list, &id_cache))
380 (*clients)[i++] = (SilcClientEntry)id_cache->context;
382 silc_idcache_list_free(list);
386 SILC_LOG_DEBUG(("Found %d clients", *clients_count));
391 /* Returns all clients matching requested nickname hash. Number of clients
392 is returned to `clients_count'. Caller must free the returned table. */
394 int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
396 SilcClientEntry **clients,
397 uint32 *clients_count)
399 SilcIDCacheList list = NULL;
400 SilcIDCacheEntry id_cache = NULL;
401 unsigned char hash[32];
403 SilcClientID client_id;
405 SILC_LOG_DEBUG(("Start"));
407 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
409 /* As the Client ID is hashed in the ID cache by hashing only the hash
410 from the Client ID, we can do a lookup with only the hash not the
411 other parts of the ID and get all the clients with that hash, ie.
412 with that nickname, as the hash is from the nickname. */
413 memset(&client_id, 0, sizeof(client_id));
414 memcpy(&client_id.hash, hash, sizeof(client_id.hash));
415 if (!silc_idcache_find_by_id(id_list->clients, &client_id, &list))
418 *clients = silc_realloc(*clients,
419 (silc_idcache_list_count(list) + *clients_count) *
423 silc_idcache_list_first(list, &id_cache);
424 (*clients)[i++] = (SilcClientEntry)id_cache->context;
426 while (silc_idcache_list_next(list, &id_cache))
427 (*clients)[i++] = (SilcClientEntry)id_cache->context;
429 silc_idcache_list_free(list);
433 SILC_LOG_DEBUG(("Found %d clients", *clients_count));
438 /* Finds client by Client ID */
441 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
442 SilcIDCacheEntry *ret_entry)
444 SilcIDCacheEntry id_cache = NULL;
445 SilcClientEntry client;
450 SILC_LOG_DEBUG(("Client ID (%s)",
451 silc_id_render(id, SILC_ID_CLIENT)));
453 /* Do extended search since the normal ID comparison function for
454 Client ID's compares only the hash from the Client ID and not the
455 entire ID. The silc_hash_client_id_compare compares the entire
456 Client ID as we want to find one specific Client ID. */
457 if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)id,
459 silc_hash_client_id_compare, NULL,
463 client = (SilcClientEntry)id_cache->context;
466 *ret_entry = id_cache;
468 SILC_LOG_DEBUG(("Found"));
473 /* Replaces old Client ID with new one */
476 silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id,
477 SilcClientID *new_id)
479 SilcIDCacheEntry id_cache = NULL;
480 SilcClientEntry client;
482 if (!old_id || !new_id)
485 SILC_LOG_DEBUG(("Replacing Client ID"));
487 /* Do extended search since the normal ID comparison function for
488 Client ID's compares only the hash from the Client ID and not the
489 entire ID. The silc_hash_client_id_compare compares the entire
490 Client ID as we want to find one specific Client ID. */
491 if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)old_id,
493 silc_hash_client_id_compare, NULL,
497 client = (SilcClientEntry)id_cache->context;
498 silc_free(client->id);
501 /* Remove the old entry and add a new one */
502 silc_idcache_del_by_context(id_list->clients, client);
503 silc_idcache_add(id_list->clients, client->nickname, client->id,
506 SILC_LOG_DEBUG(("Replaced"));
511 /* Client cache entry destructor that is called when the cache is purged. */
513 void silc_idlist_client_destructor(SilcIDCache cache,
514 SilcIDCacheEntry entry)
516 SilcClientEntry client;
518 SILC_LOG_DEBUG(("Start"));
520 client = (SilcClientEntry)entry->context;
522 if (client->nickname)
523 silc_free(client->nickname);
524 if (client->username)
525 silc_free(client->username);
526 if (client->userinfo)
527 silc_free(client->userinfo);
529 silc_free(client->id);
531 memset(client, 'F', sizeof(*client));
536 /******************************************************************************
538 Channel entry functions
540 ******************************************************************************/
542 /* Add new channel entry. This add the new channel entry to the ID cache
543 system and returns the allocated entry or NULL on error. */
546 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
547 SilcChannelID *id, SilcServerEntry router,
548 SilcCipher channel_key, SilcHmac hmac)
550 SilcChannelEntry channel;
552 channel = silc_calloc(1, sizeof(*channel));
553 channel->channel_name = channel_name;
554 channel->mode = mode;
556 channel->router = router;
557 channel->channel_key = channel_key;
558 channel->hmac = hmac;
560 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &channel->hmac)) {
565 silc_list_init(channel->user_list, struct SilcChannelClientEntryStruct,
568 if (!silc_idcache_add(id_list->channels, channel->channel_name,
569 (void *)channel->id, (void *)channel, FALSE)) {
577 /* Free channel entry. This free's everything. */
579 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
581 SILC_LOG_DEBUG(("Start"));
584 SilcChannelClientEntry chl;
586 /* Remove from cache */
588 if (!silc_idcache_del_by_id(id_list->channels, (void *)entry->id))
592 if (entry->channel_name)
593 silc_free(entry->channel_name);
595 silc_free(entry->id);
597 silc_free(entry->topic);
598 if (entry->channel_key)
599 silc_cipher_free(entry->channel_key);
601 memset(entry->key, 0, entry->key_len / 8);
602 silc_free(entry->key);
605 silc_free(entry->cipher);
606 if (entry->hmac_name)
607 silc_free(entry->hmac_name);
609 silc_free(entry->rekey);
611 /* Free all data, free also any reference from the client's channel
612 list since they share the same memory. */
613 silc_list_start(entry->user_list);
614 while ((chl = silc_list_get(entry->user_list)) != SILC_LIST_END) {
615 silc_list_del(chl->client->channels, chl);
616 silc_list_del(entry->user_list, chl);
620 memset(entry, 'F', sizeof(*entry));
628 /* Finds channel by channel name. Channel names are unique and they
629 are not case-sensitive. */
632 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
633 SilcIDCacheEntry *ret_entry)
635 SilcIDCacheEntry id_cache = NULL;
637 SILC_LOG_DEBUG(("Channel by name"));
639 if (!silc_idcache_find_by_name_one(id_list->channels, name, &id_cache))
643 *ret_entry = id_cache;
645 SILC_LOG_DEBUG(("Found"));
647 return id_cache->context;
650 /* Finds channel by Channel ID. */
653 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
654 SilcIDCacheEntry *ret_entry)
656 SilcIDCacheEntry id_cache = NULL;
657 SilcChannelEntry channel;
662 SILC_LOG_DEBUG(("Channel ID (%s)",
663 silc_id_render(id, SILC_ID_CHANNEL)));
665 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, &id_cache))
668 channel = (SilcChannelEntry)id_cache->context;
671 *ret_entry = id_cache;
673 SILC_LOG_DEBUG(("Found"));
678 /* Replaces old Channel ID with new one. This is done when router forces
679 normal server to change Channel ID. */
682 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
683 SilcChannelID *new_id)
685 SilcIDCacheEntry id_cache = NULL;
686 SilcChannelEntry channel;
688 if (!old_id || !new_id)
691 SILC_LOG_DEBUG(("Replacing Channel ID"));
693 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
697 channel = (SilcChannelEntry)id_cache->context;
698 silc_free(channel->id);
699 channel->id = new_id;
701 /* Remove the old entry and add a new one */
702 silc_idcache_del_by_context(id_list->channels, channel);
703 silc_idcache_add(id_list->channels, channel->channel_name, channel->id,
706 SILC_LOG_DEBUG(("Replaced"));
711 /* Returns channels from the ID list. If the `channel_id' is NULL then
712 all channels are returned. */
715 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
716 uint32 *channels_count)
718 SilcIDCacheList list = NULL;
719 SilcIDCacheEntry id_cache = NULL;
720 SilcChannelEntry *channels = NULL;
723 SILC_LOG_DEBUG(("Start"));
726 if (!silc_idcache_get_all(id_list->channels, &list))
729 channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels));
732 silc_idcache_list_first(list, &id_cache);
733 channels[i++] = (SilcChannelEntry)id_cache->context;
735 while (silc_idcache_list_next(list, &id_cache))
736 channels[i++] = (SilcChannelEntry)id_cache->context;
738 silc_idcache_list_free(list);
740 if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache))
744 channels = silc_calloc(1, sizeof(*channels));
745 channels[0] = (SilcChannelEntry)id_cache->context;