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->hmac_send = idata->hmac_send;
40 data->hmac_receive = idata->hmac_receive;
41 data->psn_send = idata->psn_send;
42 data->psn_receive = idata->psn_receive;
43 data->hash = idata->hash;
44 data->public_key = idata->public_key;
45 memcpy(data->fingerprint, idata->fingerprint, sizeof(data->fingerprint));
46 data->rekey = idata->rekey;
47 data->last_receive = idata->last_receive;
48 data->last_sent = idata->last_sent;
49 data->status = idata->status;
51 data->created = time(0); /* Update creation time */
54 /* Free's all data in the common ID entry data structure. */
56 void silc_idlist_del_data(void *entry)
58 SilcIDListData idata = (SilcIDListData)entry;
60 silc_cipher_free(idata->send_key);
61 if (idata->receive_key)
62 silc_cipher_free(idata->receive_key);
64 if (idata->rekey->send_enc_key) {
65 memset(idata->rekey->send_enc_key, 0, idata->rekey->enc_key_len);
66 silc_free(idata->rekey->send_enc_key);
68 silc_free(idata->rekey);
71 silc_hmac_free(idata->hmac_send);
72 if (idata->hmac_receive)
73 silc_hmac_free(idata->hmac_receive);
75 silc_hash_free(idata->hash);
76 if (idata->public_key)
77 silc_pkcs_public_key_free(idata->public_key);
82 SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge)
84 SilcIDListPurge i = (SilcIDListPurge)context;
86 SILC_LOG_DEBUG(("Start"));
88 silc_idcache_purge(i->cache);
89 silc_schedule_task_add(i->schedule, 0,
92 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
95 /******************************************************************************
97 Server entry functions
99 ******************************************************************************/
101 /* Add new server entry. This adds the new server entry to ID cache and
102 returns the allocated entry object or NULL on error. This is called
103 when new server connects to us. We also add ourselves to cache with
107 silc_idlist_add_server(SilcIDList id_list,
108 char *server_name, int server_type,
109 SilcServerID *id, SilcServerEntry router,
112 SilcServerEntry server;
114 SILC_LOG_DEBUG(("Adding new server entry"));
116 server = silc_calloc(1, sizeof(*server));
117 server->server_name = server_name;
118 server->server_type = server_type;
120 server->router = router;
121 server->connection = connection;
123 if (!silc_idcache_add(id_list->servers, server->server_name,
124 (void *)server->id, (void *)server, FALSE)) {
132 /* Finds server by Server ID */
135 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
136 bool registered, SilcIDCacheEntry *ret_entry)
138 SilcIDCacheEntry id_cache = NULL;
139 SilcServerEntry server;
144 SILC_LOG_DEBUG(("Server ID (%s)",
145 silc_id_render(id, SILC_ID_SERVER)));
147 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id,
151 server = (SilcServerEntry)id_cache->context;
154 *ret_entry = id_cache;
156 if (server && registered &&
157 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
160 SILC_LOG_DEBUG(("Found"));
165 /* Find server by name */
168 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
169 bool registered, SilcIDCacheEntry *ret_entry)
171 SilcIDCacheEntry id_cache = NULL;
172 SilcServerEntry server;
174 SILC_LOG_DEBUG(("Server by name `%s'", name));
176 if (!silc_idcache_find_by_name_one(id_list->servers, name, &id_cache))
179 server = (SilcServerEntry)id_cache->context;
182 *ret_entry = id_cache;
184 if (server && registered &&
185 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
188 SILC_LOG_DEBUG(("Found"));
193 /* Find server by connection parameters, hostname and port */
196 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
197 int port, bool registered,
198 SilcIDCacheEntry *ret_entry)
200 SilcIDCacheList list = NULL;
201 SilcIDCacheEntry id_cache = NULL;
202 SilcServerEntry server = NULL;
203 SilcSocketConnection sock;
205 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
207 if (!silc_idcache_get_all(id_list->servers, &list))
210 if (!silc_idcache_list_first(list, &id_cache)) {
211 silc_idcache_list_free(list);
216 server = (SilcServerEntry)id_cache->context;
217 sock = (SilcSocketConnection)server->connection;
219 if (sock && ((sock->hostname && !strcasecmp(sock->hostname, hostname)) ||
220 (sock->ip && !strcasecmp(sock->ip, hostname)))
221 && sock->port == port)
227 if (!silc_idcache_list_next(list, &id_cache))
231 silc_idcache_list_free(list);
234 *ret_entry = id_cache;
236 if (server && registered &&
237 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
240 SILC_LOG_DEBUG(("Found"));
245 /* Replaces old Server ID with new one */
248 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
249 SilcServerID *new_id)
251 SilcIDCacheEntry id_cache = NULL;
252 SilcServerEntry server;
254 if (!old_id || !new_id)
257 SILC_LOG_DEBUG(("Replacing Server ID"));
259 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id,
263 server = (SilcServerEntry)id_cache->context;
265 /* Remove the old entry and add a new one */
267 silc_idcache_del_by_id(id_list->servers, (void *)server->id);
269 silc_free(server->id);
272 silc_idcache_add(id_list->servers, server->server_name, server->id,
275 SILC_LOG_DEBUG(("Found"));
280 /* Removes and free's server entry from ID list */
282 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
284 SILC_LOG_DEBUG(("Start"));
287 /* Remove from cache */
289 if (!silc_idcache_del_by_id(id_list->servers, (void *)entry->id))
293 silc_free(entry->server_name);
294 silc_free(entry->id);
296 memset(entry, 'F', sizeof(*entry));
304 /******************************************************************************
306 Client entry functions
308 ******************************************************************************/
310 /* Add new client entry. This adds the client entry to ID cache system
311 and returns the allocated client entry or NULL on error. This is
312 called when new client connection is accepted to the server. If The
313 `router' is provided then the all server routines assume that the client
314 is not directly connected local client but it has router set and is
315 remote. If this is the case then `connection' must be NULL. If, on the
316 other hand, the `connection' is provided then the client is assumed
317 to be directly connected local client and `router' must be NULL. */
320 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
321 char *userinfo, SilcClientID *id,
322 SilcServerEntry router, void *connection)
324 SilcClientEntry client;
326 SILC_LOG_DEBUG(("Adding new client entry"));
328 client = silc_calloc(1, sizeof(*client));
329 client->nickname = nickname;
330 client->username = username;
331 client->userinfo = userinfo;
333 client->router = router;
334 client->connection = connection;
335 client->channels = silc_hash_table_alloc(3, silc_hash_ptr, NULL,
336 NULL, NULL, NULL, NULL, TRUE);
338 if (!silc_idcache_add(id_list->clients, nickname, (void *)client->id,
339 (void *)client, FALSE)) {
340 silc_hash_table_free(client->channels);
348 /* Free client entry. This free's everything and removes the entry
349 from ID cache. Call silc_idlist_del_data before calling this one. */
351 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
353 SILC_LOG_DEBUG(("Start"));
356 /* Remove from cache */
358 if (!silc_idcache_del_by_context(id_list->clients, entry))
362 silc_free(entry->nickname);
363 silc_free(entry->username);
364 silc_free(entry->userinfo);
365 silc_free(entry->id);
366 silc_hash_table_free(entry->channels);
368 memset(entry, 'F', sizeof(*entry));
377 /* Returns all clients matching requested nickname. Number of clients is
378 returned to `clients_count'. Caller must free the returned table. */
380 int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
382 SilcClientEntry **clients,
383 uint32 *clients_count)
385 SilcIDCacheList list = NULL;
386 SilcIDCacheEntry id_cache = NULL;
388 SILC_LOG_DEBUG(("Start"));
390 if (!silc_idcache_find_by_name(id_list->clients, nickname, &list))
393 *clients = silc_realloc(*clients,
394 (silc_idcache_list_count(list) + *clients_count) *
397 silc_idcache_list_first(list, &id_cache);
398 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
400 while (silc_idcache_list_next(list, &id_cache))
401 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
403 silc_idcache_list_free(list);
405 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
410 /* Returns all clients matching requested nickname hash. Number of clients
411 is returned to `clients_count'. Caller must free the returned table. */
413 int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
415 SilcClientEntry **clients,
416 uint32 *clients_count)
418 SilcIDCacheList list = NULL;
419 SilcIDCacheEntry id_cache = NULL;
420 unsigned char hash[32];
421 SilcClientID client_id;
423 SILC_LOG_DEBUG(("Start"));
425 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
427 /* As the Client ID is hashed in the ID cache by hashing only the hash
428 from the Client ID, we can do a lookup with only the hash not the
429 other parts of the ID and get all the clients with that hash, ie.
430 with that nickname, as the hash is from the nickname. */
431 memset(&client_id, 0, sizeof(client_id));
432 memcpy(&client_id.hash, hash, sizeof(client_id.hash));
433 if (!silc_idcache_find_by_id(id_list->clients, &client_id, &list))
436 *clients = silc_realloc(*clients,
437 (silc_idcache_list_count(list) + *clients_count) *
440 silc_idcache_list_first(list, &id_cache);
441 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
443 while (silc_idcache_list_next(list, &id_cache))
444 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
446 silc_idcache_list_free(list);
448 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
453 /* Finds client by Client ID */
456 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
457 bool registered, SilcIDCacheEntry *ret_entry)
459 SilcIDCacheEntry id_cache = NULL;
460 SilcClientEntry client;
465 SILC_LOG_DEBUG(("Client ID (%s)",
466 silc_id_render(id, SILC_ID_CLIENT)));
468 /* Do extended search since the normal ID comparison function for
469 Client ID's compares only the hash from the Client ID and not the
470 entire ID. The silc_hash_client_id_compare compares the entire
471 Client ID as we want to find one specific Client ID. */
472 if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)id,
474 silc_hash_client_id_compare, NULL,
478 client = (SilcClientEntry)id_cache->context;
481 *ret_entry = id_cache;
483 if (client && registered &&
484 !(client->data.status & SILC_IDLIST_STATUS_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, NULL, client->id, client, FALSE);
527 SILC_LOG_DEBUG(("Replaced"));
532 /* Client cache entry destructor that is called when the cache is purged. */
534 void silc_idlist_client_destructor(SilcIDCache cache,
535 SilcIDCacheEntry entry)
537 SilcClientEntry client;
539 client = (SilcClientEntry)entry->context;
541 silc_free(client->nickname);
542 silc_free(client->username);
543 silc_free(client->userinfo);
544 silc_free(client->id);
545 silc_hash_table_free(client->channels);
547 memset(client, 'F', sizeof(*client));
552 /******************************************************************************
554 Channel entry functions
556 ******************************************************************************/
558 /* Add new channel entry. This add the new channel entry to the ID cache
559 system and returns the allocated entry or NULL on error. */
562 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
563 SilcChannelID *id, SilcServerEntry router,
564 SilcCipher channel_key, SilcHmac hmac)
566 SilcChannelEntry channel;
568 SILC_LOG_DEBUG(("Adding new channel entry"));
570 channel = silc_calloc(1, sizeof(*channel));
571 channel->channel_name = channel_name;
572 channel->mode = mode;
574 channel->router = router;
575 channel->channel_key = channel_key;
576 channel->hmac = hmac;
577 channel->created = time(0);
579 if (!silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac)) {
584 channel->user_list = silc_hash_table_alloc(3, silc_hash_ptr, NULL, NULL,
585 NULL, NULL, NULL, TRUE);
587 if (!silc_idcache_add(id_list->channels, channel->channel_name,
588 (void *)channel->id, (void *)channel, FALSE)) {
589 silc_hmac_free(channel->hmac);
590 silc_hash_table_free(channel->user_list);
598 /* Foreach callbcak to free all users from the channel when deleting a
601 static void silc_idlist_del_channel_foreach(void *key, void *context,
604 SilcChannelClientEntry chl = (SilcChannelClientEntry)context;
606 /* Remove the context from the client's channel hash table as that
607 table and channel's user_list hash table share this same context. */
608 silc_hash_table_del(chl->client->channels, chl->channel);
612 /* Free channel entry. This free's everything. */
614 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
616 SILC_LOG_DEBUG(("Start"));
619 /* Remove from cache */
621 if (!silc_idcache_del_by_id(id_list->channels, (void *)entry->id))
625 silc_free(entry->channel_name);
626 silc_free(entry->id);
627 silc_free(entry->topic);
628 if (entry->channel_key)
629 silc_cipher_free(entry->channel_key);
631 memset(entry->key, 0, entry->key_len / 8);
632 silc_free(entry->key);
634 silc_free(entry->cipher);
636 silc_hmac_free(entry->hmac);
637 silc_free(entry->hmac_name);
638 silc_free(entry->rekey);
640 /* Free all client entrys from the users list. The silc_hash_table_free
641 will free all the entries so they are not freed at the foreach
643 silc_hash_table_foreach(entry->user_list, silc_idlist_del_channel_foreach,
645 silc_hash_table_free(entry->user_list);
647 memset(entry, 'F', sizeof(*entry));
655 /* Finds channel by channel name. Channel names are unique and they
656 are not case-sensitive. */
659 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
660 SilcIDCacheEntry *ret_entry)
662 SilcIDCacheEntry id_cache = NULL;
664 SILC_LOG_DEBUG(("Channel by name"));
666 if (!silc_idcache_find_by_name_one(id_list->channels, name, &id_cache))
670 *ret_entry = id_cache;
672 SILC_LOG_DEBUG(("Found"));
674 return id_cache->context;
677 /* Finds channel by Channel ID. */
680 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
681 SilcIDCacheEntry *ret_entry)
683 SilcIDCacheEntry id_cache = NULL;
684 SilcChannelEntry channel;
689 SILC_LOG_DEBUG(("Channel ID (%s)",
690 silc_id_render(id, SILC_ID_CHANNEL)));
692 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, &id_cache))
695 channel = (SilcChannelEntry)id_cache->context;
698 *ret_entry = id_cache;
700 SILC_LOG_DEBUG(("Found"));
705 /* Replaces old Channel ID with new one. This is done when router forces
706 normal server to change Channel ID. */
709 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
710 SilcChannelID *new_id)
712 SilcIDCacheEntry id_cache = NULL;
713 SilcChannelEntry channel;
715 if (!old_id || !new_id)
718 SILC_LOG_DEBUG(("Replacing Channel ID"));
720 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
724 channel = (SilcChannelEntry)id_cache->context;
726 /* Remove the old entry and add a new one */
728 silc_idcache_del_by_id(id_list->channels, (void *)channel->id);
730 silc_free(channel->id);
731 channel->id = new_id;
733 silc_idcache_add(id_list->channels, channel->channel_name, channel->id,
736 SILC_LOG_DEBUG(("Replaced"));
741 /* Returns channels from the ID list. If the `channel_id' is NULL then
742 all channels are returned. */
745 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
746 uint32 *channels_count)
748 SilcIDCacheList list = NULL;
749 SilcIDCacheEntry id_cache = NULL;
750 SilcChannelEntry *channels = NULL;
753 SILC_LOG_DEBUG(("Start"));
756 if (!silc_idcache_get_all(id_list->channels, &list))
759 channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels));
762 silc_idcache_list_first(list, &id_cache);
763 channels[i++] = (SilcChannelEntry)id_cache->context;
765 while (silc_idcache_list_next(list, &id_cache))
766 channels[i++] = (SilcChannelEntry)id_cache->context;
768 silc_idcache_list_free(list);
770 if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache))
774 channels = silc_calloc(1, sizeof(*channels));
775 channels[0] = (SilcChannelEntry)id_cache->context;