5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 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"
24 #include "server_internal.h"
26 /******************************************************************************
30 ******************************************************************************/
32 /* This function is used to add keys and stuff to common ID entry data
35 void silc_idlist_add_data(void *entry, SilcIDListData idata)
37 SilcIDListData data = (SilcIDListData)entry;
38 data->send_key = idata->send_key;
39 data->receive_key = idata->receive_key;
40 data->hmac_send = idata->hmac_send;
41 data->hmac_receive = idata->hmac_receive;
42 data->psn_send = idata->psn_send;
43 data->psn_receive = idata->psn_receive;
44 data->hash = idata->hash;
45 data->public_key = idata->public_key;
46 memcpy(data->fingerprint, idata->fingerprint, sizeof(data->fingerprint));
47 data->rekey = idata->rekey;
48 data->last_receive = idata->last_receive;
49 data->last_sent = idata->last_sent;
50 data->status = idata->status;
52 data->created = time(0); /* Update creation time */
55 /* Free's all data in the common ID entry data structure. */
57 void silc_idlist_del_data(void *entry)
59 SilcIDListData idata = (SilcIDListData)entry;
61 silc_cipher_free(idata->send_key);
62 if (idata->receive_key)
63 silc_cipher_free(idata->receive_key);
65 if (idata->rekey->send_enc_key) {
66 memset(idata->rekey->send_enc_key, 0, idata->rekey->enc_key_len);
67 silc_free(idata->rekey->send_enc_key);
69 silc_free(idata->rekey);
72 silc_hmac_free(idata->hmac_send);
73 if (idata->hmac_receive)
74 silc_hmac_free(idata->hmac_receive);
76 silc_hash_free(idata->hash);
77 if (idata->public_key)
78 silc_pkcs_public_key_free(idata->public_key);
83 SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge)
85 SilcIDListPurge i = (SilcIDListPurge)context;
87 SILC_LOG_DEBUG(("Start"));
89 silc_idcache_purge(i->cache);
90 silc_schedule_task_add(i->schedule, 0,
92 (void *)i, i->timeout, 0,
93 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
96 /******************************************************************************
98 Server entry functions
100 ******************************************************************************/
102 /* Add new server entry. This adds the new server entry to ID cache and
103 returns the allocated entry object or NULL on error. This is called
104 when new server connects to us. We also add ourselves to cache with
108 silc_idlist_add_server(SilcIDList id_list,
109 char *server_name, int server_type,
110 SilcServerID *id, SilcServerEntry router,
113 SilcServerEntry server;
115 SILC_LOG_DEBUG(("Adding new server entry"));
117 server = silc_calloc(1, sizeof(*server));
118 server->server_name = server_name;
119 server->server_type = server_type;
121 server->router = router;
122 server->connection = connection;
124 if (!silc_idcache_add(id_list->servers, server->server_name,
125 (void *)server->id, (void *)server, 0, NULL)) {
133 /* Finds server by Server ID */
136 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
137 bool registered, SilcIDCacheEntry *ret_entry)
139 SilcIDCacheEntry id_cache = NULL;
140 SilcServerEntry server;
145 SILC_LOG_DEBUG(("Server ID (%s)",
146 silc_id_render(id, SILC_ID_SERVER)));
148 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id,
152 server = (SilcServerEntry)id_cache->context;
155 *ret_entry = id_cache;
157 if (server && registered &&
158 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
161 SILC_LOG_DEBUG(("Found"));
166 /* Find server by name */
169 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
170 bool registered, SilcIDCacheEntry *ret_entry)
172 SilcIDCacheEntry id_cache = NULL;
173 SilcServerEntry server;
175 SILC_LOG_DEBUG(("Server by name `%s'", name));
177 if (!silc_idcache_find_by_name_one(id_list->servers, name, &id_cache))
180 server = (SilcServerEntry)id_cache->context;
183 *ret_entry = id_cache;
185 if (server && registered &&
186 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
189 SILC_LOG_DEBUG(("Found"));
194 /* Find server by connection parameters, hostname and port */
197 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
198 int port, bool registered,
199 SilcIDCacheEntry *ret_entry)
201 SilcIDCacheList list = NULL;
202 SilcIDCacheEntry id_cache = NULL;
203 SilcServerEntry server = NULL;
204 SilcSocketConnection sock;
206 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
208 if (!silc_idcache_get_all(id_list->servers, &list))
211 if (!silc_idcache_list_first(list, &id_cache)) {
212 silc_idcache_list_free(list);
217 server = (SilcServerEntry)id_cache->context;
218 sock = (SilcSocketConnection)server->connection;
220 if (sock && ((sock->hostname && !strcasecmp(sock->hostname, hostname)) ||
221 (sock->ip && !strcasecmp(sock->ip, hostname)))
222 && sock->port == port)
228 if (!silc_idcache_list_next(list, &id_cache))
232 silc_idcache_list_free(list);
235 *ret_entry = id_cache;
237 if (server && registered &&
238 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
241 SILC_LOG_DEBUG(("Found"));
246 /* Replaces old Server ID with new one */
249 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
250 SilcServerID *new_id)
252 SilcIDCacheEntry id_cache = NULL;
253 SilcServerEntry server;
255 if (!old_id || !new_id)
258 SILC_LOG_DEBUG(("Replacing Server ID"));
260 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id,
264 server = (SilcServerEntry)id_cache->context;
266 /* Remove the old entry and add a new one */
268 silc_idcache_del_by_id(id_list->servers, (void *)server->id);
270 silc_free(server->id);
273 silc_idcache_add(id_list->servers, server->server_name, server->id,
276 SILC_LOG_DEBUG(("Found"));
281 /* Removes and free's server entry from ID list */
283 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
285 SILC_LOG_DEBUG(("Start"));
288 /* Remove from cache */
290 if (!silc_idcache_del_by_id(id_list->servers, (void *)entry->id))
294 silc_free(entry->server_name);
295 silc_free(entry->id);
297 memset(entry, 'F', sizeof(*entry));
305 /******************************************************************************
307 Client entry functions
309 ******************************************************************************/
311 /* Add new client entry. This adds the client entry to ID cache system
312 and returns the allocated client entry or NULL on error. This is
313 called when new client connection is accepted to the server. If The
314 `router' is provided then the all server routines assume that the client
315 is not directly connected local client but it has router set and is
316 remote. If this is the case then `connection' must be NULL. If, on the
317 other hand, the `connection' is provided then the client is assumed
318 to be directly connected local client and `router' must be NULL. */
321 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
322 char *userinfo, SilcClientID *id,
323 SilcServerEntry router, void *connection,
326 SilcClientEntry client;
328 SILC_LOG_DEBUG(("Adding new client entry"));
330 client = silc_calloc(1, sizeof(*client));
331 client->nickname = nickname;
332 client->username = username;
333 client->userinfo = userinfo;
335 client->router = router;
336 client->connection = connection;
337 client->channels = silc_hash_table_alloc(3, silc_hash_ptr, NULL,
338 NULL, NULL, NULL, NULL, TRUE);
340 if (!silc_idcache_add(id_list->clients, nickname, (void *)client->id,
341 (void *)client, expire, NULL)) {
342 silc_hash_table_free(client->channels);
350 /* Free client entry. This free's everything and removes the entry
351 from ID cache. Call silc_idlist_del_data before calling this one. */
353 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
355 SILC_LOG_DEBUG(("Start"));
358 /* Remove from cache */
360 if (!silc_idcache_del_by_context(id_list->clients, entry))
364 silc_free(entry->nickname);
365 silc_free(entry->username);
366 silc_free(entry->userinfo);
367 silc_free(entry->id);
368 silc_hash_table_free(entry->channels);
370 memset(entry, 'F', sizeof(*entry));
379 /* Returns all clients matching requested nickname. Number of clients is
380 returned to `clients_count'. Caller must free the returned table. */
382 int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
384 SilcClientEntry **clients,
385 SilcUInt32 *clients_count)
387 SilcIDCacheList list = NULL;
388 SilcIDCacheEntry id_cache = NULL;
390 SILC_LOG_DEBUG(("Start"));
392 if (!silc_idcache_find_by_name(id_list->clients, nickname, &list))
395 *clients = silc_realloc(*clients,
396 (silc_idcache_list_count(list) + *clients_count) *
399 silc_idcache_list_first(list, &id_cache);
400 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
402 while (silc_idcache_list_next(list, &id_cache))
403 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
405 silc_idcache_list_free(list);
407 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
412 /* Returns all clients matching requested nickname hash. Number of clients
413 is returned to `clients_count'. Caller must free the returned table. */
415 int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
417 SilcClientEntry **clients,
418 SilcUInt32 *clients_count)
420 SilcIDCacheList list = NULL;
421 SilcIDCacheEntry id_cache = NULL;
422 unsigned char hash[32];
423 SilcClientID client_id;
426 SILC_LOG_DEBUG(("Start"));
428 memset(nick, 0, sizeof(nick));
429 silc_to_lower(nickname, nick, sizeof(nick) - 1);
430 silc_hash_make(md5hash, nick, strlen(nick), hash);
432 /* As the Client ID is hashed in the ID cache by hashing only the hash
433 from the Client ID, we can do a lookup with only the hash not the
434 other parts of the ID and get all the clients with that hash, ie.
435 with that nickname, as the hash is from the nickname. */
436 memset(&client_id, 0, sizeof(client_id));
437 memcpy(&client_id.hash, hash, sizeof(client_id.hash));
438 if (!silc_idcache_find_by_id(id_list->clients, &client_id, &list))
441 *clients = silc_realloc(*clients,
442 (silc_idcache_list_count(list) + *clients_count) *
445 silc_idcache_list_first(list, &id_cache);
446 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
448 while (silc_idcache_list_next(list, &id_cache))
449 (*clients)[(*clients_count)++] = (SilcClientEntry)id_cache->context;
451 silc_idcache_list_free(list);
453 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
458 /* Finds client by Client ID */
461 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
462 bool registered, SilcIDCacheEntry *ret_entry)
464 SilcIDCacheEntry id_cache = NULL;
465 SilcClientEntry client;
470 SILC_LOG_DEBUG(("Client ID (%s)",
471 silc_id_render(id, SILC_ID_CLIENT)));
473 /* Do extended search since the normal ID comparison function for
474 Client ID's compares only the hash from the Client ID and not the
475 entire ID. The silc_hash_client_id_compare compares the entire
476 Client ID as we want to find one specific Client ID. */
477 if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)id,
479 silc_hash_client_id_compare, NULL,
483 client = (SilcClientEntry)id_cache->context;
486 *ret_entry = id_cache;
488 if (client && registered &&
489 !(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
492 SILC_LOG_DEBUG(("Found"));
497 /* Replaces old Client ID with new one */
500 silc_idlist_replace_client_id(SilcServer server,
501 SilcIDList id_list, SilcClientID *old_id,
502 SilcClientID *new_id, const char *nickname)
504 SilcIDCacheEntry id_cache = NULL;
505 SilcClientEntry client;
507 if (!old_id || !new_id)
510 SILC_LOG_DEBUG(("Replacing Client ID"));
512 /* Do extended search since the normal ID comparison function for
513 Client ID's compares only the hash from the Client ID and not the
514 entire ID. The silc_hash_client_id_compare compares the entire
515 Client ID as we want to find one specific Client ID. */
516 if (!silc_idcache_find_by_id_one_ext(id_list->clients, (void *)old_id,
518 silc_hash_client_id_compare, NULL,
522 client = (SilcClientEntry)id_cache->context;
524 /* Remove the old entry and add a new one */
526 if (!silc_idcache_del_by_context(id_list->clients, client))
529 /* Check if anyone is watching this nickname */
530 if (server->server_type == SILC_ROUTER)
531 silc_server_check_watcher_list(server, client, nickname,
532 SILC_NOTIFY_TYPE_NICK_CHANGE);
534 silc_free(client->id);
535 silc_free(client->nickname);
537 client->nickname = nickname ? strdup(nickname) : NULL;
539 if (!silc_idcache_add(id_list->clients, client->nickname, client->id,
543 SILC_LOG_DEBUG(("Replaced"));
548 /* Client cache entry destructor that is called when the cache is purged. */
550 void silc_idlist_client_destructor(SilcIDCache cache,
551 SilcIDCacheEntry entry)
553 SilcClientEntry client;
555 client = (SilcClientEntry)entry->context;
557 silc_free(client->nickname);
558 silc_free(client->username);
559 silc_free(client->userinfo);
560 silc_free(client->id);
561 silc_hash_table_free(client->channels);
563 memset(client, 'F', sizeof(*client));
568 /******************************************************************************
570 Channel entry functions
572 ******************************************************************************/
574 /* Add new channel entry. This add the new channel entry to the ID cache
575 system and returns the allocated entry or NULL on error. */
578 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
579 SilcChannelID *id, SilcServerEntry router,
580 SilcCipher channel_key, SilcHmac hmac,
583 SilcChannelEntry channel;
585 SILC_LOG_DEBUG(("Adding new channel entry"));
587 channel = silc_calloc(1, sizeof(*channel));
588 channel->channel_name = channel_name;
589 channel->mode = mode;
591 channel->router = router;
592 channel->channel_key = channel_key;
593 channel->hmac = hmac;
594 channel->created = time(0);
596 if (!silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac)) {
601 channel->user_list = silc_hash_table_alloc(3, silc_hash_ptr, NULL, NULL,
602 NULL, NULL, NULL, TRUE);
604 if (!silc_idcache_add(id_list->channels, channel->channel_name,
605 (void *)channel->id, (void *)channel, expire, NULL)) {
606 silc_hmac_free(channel->hmac);
607 silc_hash_table_free(channel->user_list);
615 /* Foreach callbcak to free all users from the channel when deleting a
618 static void silc_idlist_del_channel_foreach(void *key, void *context,
621 SilcChannelClientEntry chl = (SilcChannelClientEntry)context;
623 SILC_LOG_DEBUG(("Removing client %s from channel %s",
624 chl->client->nickname, chl->channel->channel_name));
626 /* Remove the context from the client's channel hash table as that
627 table and channel's user_list hash table share this same context. */
628 silc_hash_table_del(chl->client->channels, chl->channel);
632 /* Free channel entry. This free's everything. */
634 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
636 SILC_LOG_DEBUG(("Start"));
639 /* Remove from cache */
641 if (!silc_idcache_del_by_id(id_list->channels, (void *)entry->id))
644 /* Free all client entrys from the users list. The silc_hash_table_free
645 will free all the entries so they are not freed at the foreach
647 silc_hash_table_foreach(entry->user_list, silc_idlist_del_channel_foreach,
649 silc_hash_table_free(entry->user_list);
652 silc_free(entry->channel_name);
653 silc_free(entry->id);
654 silc_free(entry->topic);
655 if (entry->channel_key)
656 silc_cipher_free(entry->channel_key);
658 memset(entry->key, 0, entry->key_len / 8);
659 silc_free(entry->key);
661 silc_free(entry->cipher);
663 silc_hmac_free(entry->hmac);
664 silc_free(entry->hmac_name);
665 silc_free(entry->rekey);
667 memset(entry, 'F', sizeof(*entry));
675 /* Finds channel by channel name. Channel names are unique and they
676 are not case-sensitive. */
679 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
680 SilcIDCacheEntry *ret_entry)
682 SilcIDCacheEntry id_cache = NULL;
684 SILC_LOG_DEBUG(("Channel by name %s", name));
686 if (!silc_idcache_find_by_name_one(id_list->channels, name, &id_cache))
690 *ret_entry = id_cache;
692 SILC_LOG_DEBUG(("Found"));
694 return id_cache->context;
697 /* Finds channel by Channel ID. */
700 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
701 SilcIDCacheEntry *ret_entry)
703 SilcIDCacheEntry id_cache = NULL;
704 SilcChannelEntry channel;
709 SILC_LOG_DEBUG(("Channel ID (%s)",
710 silc_id_render(id, SILC_ID_CHANNEL)));
712 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, &id_cache))
715 channel = (SilcChannelEntry)id_cache->context;
718 *ret_entry = id_cache;
720 SILC_LOG_DEBUG(("Found"));
725 /* Replaces old Channel ID with new one. This is done when router forces
726 normal server to change Channel ID. */
729 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
730 SilcChannelID *new_id)
732 SilcIDCacheEntry id_cache = NULL;
733 SilcChannelEntry channel;
735 if (!old_id || !new_id)
738 SILC_LOG_DEBUG(("Replacing Channel ID"));
740 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
744 channel = (SilcChannelEntry)id_cache->context;
746 /* Remove the old entry and add a new one */
748 silc_idcache_del_by_id(id_list->channels, (void *)channel->id);
750 silc_free(channel->id);
751 channel->id = new_id;
753 silc_idcache_add(id_list->channels, channel->channel_name, channel->id,
756 SILC_LOG_DEBUG(("Replaced"));
761 /* Returns channels from the ID list. If the `channel_id' is NULL then
762 all channels are returned. */
765 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
766 SilcUInt32 *channels_count)
768 SilcIDCacheList list = NULL;
769 SilcIDCacheEntry id_cache = NULL;
770 SilcChannelEntry *channels = NULL;
773 SILC_LOG_DEBUG(("Start"));
776 if (!silc_idcache_get_all(id_list->channels, &list))
779 channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels));
782 silc_idcache_list_first(list, &id_cache);
783 channels[i++] = (SilcChannelEntry)id_cache->context;
785 while (silc_idcache_list_next(list, &id_cache))
786 channels[i++] = (SilcChannelEntry)id_cache->context;
788 silc_idcache_list_free(list);
790 if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache))
794 channels = silc_calloc(1, sizeof(*channels));
795 channels[0] = (SilcChannelEntry)id_cache->context;