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 = idata->hmac;
40 data->hmac_key = idata->hmac_key;
41 data->hmac_key_len = idata->hmac_key_len;
42 data->pkcs = idata->pkcs;
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 silc_hmac_free(idata->hmac);
60 if (idata->hmac_key) {
61 memset(idata->hmac_key, 0, idata->hmac_key_len);
62 silc_free(idata->hmac_key);
65 silc_pkcs_free(idata->pkcs);
66 if (idata->public_key)
67 silc_pkcs_public_key_free(idata->public_key);
70 /******************************************************************************
72 Server entry functions
74 ******************************************************************************/
76 /* Add new server entry. This adds the new server entry to ID cache and
77 returns the allocated entry object or NULL on error. This is called
78 when new server connects to us. We also add ourselves to cache with
82 silc_idlist_add_server(SilcIDList id_list,
83 char *server_name, int server_type,
84 SilcServerID *id, SilcServerEntry router,
87 SilcServerEntry server;
89 SILC_LOG_DEBUG(("Adding new server entry"));
91 server = silc_calloc(1, sizeof(*server));
92 server->server_name = server_name;
93 server->server_type = server_type;
95 server->router = router;
96 server->connection = connection;
98 if (!silc_idcache_add(id_list->servers, server->server_name, SILC_ID_SERVER,
99 (void *)server->id, (void *)server, TRUE, FALSE)) {
107 /* Finds server by Server ID */
110 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
111 SilcIDCacheEntry *ret_entry)
113 SilcIDCacheEntry id_cache = NULL;
114 SilcServerEntry server;
119 SILC_LOG_DEBUG(("Server ID (%s)",
120 silc_id_render(id, SILC_ID_SERVER)));
122 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id,
123 SILC_ID_SERVER, &id_cache))
126 server = (SilcServerEntry)id_cache->context;
129 *ret_entry = id_cache;
134 /* Find server by name */
137 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
138 SilcIDCacheEntry *ret_entry)
140 SilcIDCacheEntry id_cache = NULL;
141 SilcServerEntry server;
143 SILC_LOG_DEBUG(("Server by name `%s'", name));
145 if (!silc_idcache_find_by_data_one(id_list->servers, name, &id_cache))
148 server = (SilcServerEntry)id_cache->context;
151 *ret_entry = id_cache;
156 /* Find server by connection parameters, hostname and port */
159 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
160 int port, SilcIDCacheEntry *ret_entry)
162 SilcIDCacheList list = NULL;
163 SilcIDCacheEntry id_cache = NULL;
164 SilcServerEntry server = NULL;
165 SilcSocketConnection sock;
167 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
169 if (!silc_idcache_find_by_id(id_list->servers, SILC_ID_CACHE_ANY,
170 SILC_ID_SERVER, &list))
173 if (!silc_idcache_list_first(list, &id_cache)) {
174 silc_idcache_list_free(list);
179 server = (SilcServerEntry)id_cache->context;
180 sock = (SilcSocketConnection)server->connection;
182 if (sock && (!strcmp(sock->hostname, hostname) ||
183 !strcmp(sock->ip, hostname)) && sock->port == port)
189 if (!silc_idcache_list_next(list, &id_cache))
193 silc_idcache_list_free(list);
196 *ret_entry = id_cache;
198 SILC_LOG_DEBUG(("Found"));
203 /* Replaces old Server ID with new one */
206 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
207 SilcServerID *new_id)
209 SilcIDCacheEntry id_cache = NULL;
210 SilcServerEntry server;
212 if (!old_id || !new_id)
215 SILC_LOG_DEBUG(("Replacing Server ID"));
217 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id,
218 SILC_ID_SERVER, &id_cache))
221 server = (SilcServerEntry)id_cache->context;
222 silc_free(server->id);
224 id_cache->id = (void *)new_id;
229 /* Removes and free's server entry from ID list */
231 void silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
234 /* Remove from cache */
236 silc_idcache_del_by_id(id_list->servers, SILC_ID_SERVER,
240 if (entry->server_name)
241 silc_free(entry->server_name);
243 silc_free(entry->id);
245 memset(entry, 'F', sizeof(*entry));
250 /******************************************************************************
252 Client entry functions
254 ******************************************************************************/
256 /* Add new client entry. This adds the client entry to ID cache system
257 and returns the allocated client entry or NULL on error. This is
258 called when new client connection is accepted to the server. If The
259 `router' is provided then the all server routines assume that the client
260 is not directly connected local client but it has router set and is
261 remote. If this is the case then `connection' must be NULL. If, on the
262 other hand, the `connection' is provided then the client is assumed
263 to be directly connected local client and `router' must be NULL. */
266 silc_idlist_add_client(SilcIDList id_list, unsigned char *nickname,
267 char *username, char *userinfo, SilcClientID *id,
268 SilcServerEntry router, void *connection)
270 SilcClientEntry client;
272 SILC_LOG_DEBUG(("Adding new client entry"));
274 client = silc_calloc(1, sizeof(*client));
275 client->nickname = nickname;
276 client->username = username;
277 client->userinfo = userinfo;
279 client->router = router;
280 client->connection = connection;
281 silc_list_init(client->channels, struct SilcChannelClientEntryStruct,
284 if (!silc_idcache_add(id_list->clients, nickname, SILC_ID_CLIENT,
285 (void *)client->id, (void *)client, TRUE, FALSE)) {
293 /* Free client entry. This free's everything and removes the entry
294 from ID cache. Call silc_idlist_del_data before calling this one. */
296 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
299 /* Remove from cache */
301 if (!silc_idcache_del_by_id(id_list->clients, SILC_ID_CLIENT,
307 silc_free(entry->nickname);
309 silc_free(entry->username);
311 silc_free(entry->userinfo);
313 silc_free(entry->id);
315 memset(entry, 'F', sizeof(*entry));
324 /* Returns all clients matching requested nickname. Number of clients is
325 returned to `clients_count'. Caller must free the returned table. */
328 silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
329 char *server, unsigned int *clients_count)
331 SilcIDCacheList list = NULL;
332 SilcIDCacheEntry id_cache = NULL;
333 SilcClientEntry *clients;
336 if (!silc_idcache_find_by_data(id_list->clients, nickname, &list))
339 clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
342 silc_idcache_list_first(list, &id_cache);
343 clients[i++] = (SilcClientEntry)id_cache->context;
345 while (silc_idcache_list_next(list, &id_cache))
346 clients[i++] = (SilcClientEntry)id_cache->context;
348 silc_idcache_list_free(list);
356 /* Returns all clients matching requested nickname. Number of clients is
357 returned to `clients_count'. Caller must free the returned table. */
360 silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
362 unsigned int *clients_count)
364 SilcIDCacheList list = NULL;
365 SilcIDCacheEntry id_cache = NULL;
366 SilcClientEntry *clients;
367 unsigned char hash[32];
370 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
372 if (!silc_idcache_find_by_data(id_list->clients, hash, &list))
375 clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
378 silc_idcache_list_first(list, &id_cache);
379 clients[i++] = (SilcClientEntry)id_cache->context;
381 while (silc_idcache_list_next(list, &id_cache))
382 clients[i++] = (SilcClientEntry)id_cache->context;
384 silc_idcache_list_free(list);
392 /* Finds client entry by nickname. */
395 silc_idlist_find_client_by_nickname(SilcIDList id_list, char *nickname,
396 char *server, SilcIDCacheEntry *ret_entry)
398 SilcIDCacheList list = NULL;
399 SilcIDCacheEntry id_cache = NULL;
400 SilcClientEntry client = NULL;
402 SILC_LOG_DEBUG(("Client by nickname"));
405 if (!silc_idcache_find_by_data(id_list->clients, nickname, &list))
409 while (silc_idcache_list_next(list, &id_cache)) {
410 client = (SilcClientEntry)id_cache->context;
412 if (!strcmp(server, XXX, strlen(server)))
419 silc_idcache_list_free(list);
424 if (!silc_idcache_find_by_data_one(id_list->clients, nickname, &id_cache))
427 client = (SilcClientEntry)id_cache->context;
430 *ret_entry = id_cache;
433 SILC_LOG_DEBUG(("Found"));
438 /* Finds client by nickname hash. */
441 silc_idlist_find_client_by_hash(SilcIDList id_list, char *nickname,
442 SilcHash md5hash, SilcIDCacheEntry *ret_entry)
444 SilcIDCacheList list = NULL;
445 SilcIDCacheEntry id_cache = NULL;
446 SilcClientEntry client = NULL;
447 unsigned char hash[32];
449 SILC_LOG_DEBUG(("Client by hash"));
451 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
453 if (!silc_idcache_find_by_id(id_list->clients, SILC_ID_CACHE_ANY,
454 SILC_ID_CLIENT, &list))
457 if (!silc_idcache_list_first(list, &id_cache)) {
458 silc_idcache_list_free(list);
463 client = (SilcClientEntry)id_cache->context;
465 if (client && !SILC_ID_COMPARE_HASH(client->id, hash))
471 if (!silc_idcache_list_next(list, &id_cache))
475 silc_idcache_list_free(list);
478 *ret_entry = id_cache;
480 SILC_LOG_DEBUG(("Found"));
485 /* Finds client by Client ID */
488 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
489 SilcIDCacheEntry *ret_entry)
491 SilcIDCacheEntry id_cache = NULL;
492 SilcClientEntry client;
497 SILC_LOG_DEBUG(("Client ID (%s)",
498 silc_id_render(id, SILC_ID_CLIENT)));
500 if (!silc_idcache_find_by_id_one(id_list->clients, (void *)id,
501 SILC_ID_CLIENT, &id_cache))
504 client = (SilcClientEntry)id_cache->context;
507 *ret_entry = id_cache;
509 SILC_LOG_DEBUG(("Found"));
514 /* Replaces old Client ID with new one */
517 silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id,
518 SilcClientID *new_id)
520 SilcIDCacheEntry id_cache = NULL;
521 SilcClientEntry client;
523 if (!old_id || !new_id)
526 SILC_LOG_DEBUG(("Replacing Client ID"));
528 if (!silc_idcache_find_by_id_one(id_list->clients, (void *)old_id,
529 SILC_ID_CLIENT, &id_cache))
532 client = (SilcClientEntry)id_cache->context;
533 silc_free(client->id);
535 id_cache->id = (void *)new_id;
537 /* If the old ID Cache data was the hash value of the old Client ID
538 replace it with the hash of new Client ID */
539 if (id_cache->data && !SILC_ID_COMPARE_HASH(old_id, id_cache->data)) {
540 silc_free(id_cache->data);
541 id_cache->data = silc_calloc(sizeof(new_id->hash), sizeof(unsigned char));
542 memcpy(id_cache->data, new_id->hash, sizeof(new_id->hash));
543 silc_idcache_sort_by_data(id_list->clients);
546 SILC_LOG_DEBUG(("Replaced"));
551 /* Client cache entry destructor that is called when the cache is purged. */
553 void silc_idlist_client_destructor(SilcIDCache cache,
554 SilcIDCacheEntry entry)
556 SilcClientEntry client;
558 SILC_LOG_DEBUG(("Start"));
560 client = (SilcClientEntry)entry->context;
562 if (client->nickname)
563 silc_free(client->nickname);
564 if (client->username)
565 silc_free(client->username);
566 if (client->userinfo)
567 silc_free(client->userinfo);
569 silc_free(client->id);
571 memset(client, 'F', sizeof(*client));
576 /******************************************************************************
578 Channel entry functions
580 ******************************************************************************/
582 /* Add new channel entry. This add the new channel entry to the ID cache
583 system and returns the allocated entry or NULL on error. */
586 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
587 SilcChannelID *id, SilcServerEntry router,
588 SilcCipher channel_key, SilcHmac hmac)
590 SilcChannelEntry channel;
592 channel = silc_calloc(1, sizeof(*channel));
593 channel->channel_name = channel_name;
594 channel->mode = mode;
596 channel->router = router;
597 channel->channel_key = channel_key;
598 channel->hmac = hmac;
600 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &channel->hmac)) {
605 silc_list_init(channel->user_list, struct SilcChannelClientEntryStruct,
608 if (!silc_idcache_add(id_list->channels, channel->channel_name,
609 SILC_ID_CHANNEL, (void *)channel->id,
610 (void *)channel, TRUE, FALSE)) {
618 /* Free channel entry. This free's everything. */
620 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
623 SilcChannelClientEntry chl;
625 /* Remove from cache */
627 if (!silc_idcache_del_by_id(id_list->channels, SILC_ID_CHANNEL,
632 if (entry->channel_name)
633 silc_free(entry->channel_name);
635 silc_free(entry->id);
637 silc_free(entry->topic);
638 if (entry->channel_key)
639 silc_cipher_free(entry->channel_key);
641 memset(entry->key, 0, entry->key_len / 8);
642 silc_free(entry->key);
645 /* Free all data, free also any reference from the client's channel
646 list since they share the same memory. */
647 silc_list_start(entry->user_list);
648 while ((chl = silc_list_get(entry->user_list)) != SILC_LIST_END) {
649 silc_list_del(chl->client->channels, chl);
650 silc_list_del(entry->user_list, chl);
654 memset(entry, 'F', sizeof(*entry));
662 /* Finds channel by channel name. Channel names are unique and they
663 are not case-sensitive. */
666 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
667 SilcIDCacheEntry *ret_entry)
669 SilcIDCacheList list = NULL;
670 SilcIDCacheEntry id_cache = NULL;
671 SilcChannelEntry channel;
673 SILC_LOG_DEBUG(("Channel by name"));
675 if (!silc_idcache_find_by_data_loose(id_list->channels, name, &list))
678 if (!silc_idcache_list_first(list, &id_cache)) {
679 silc_idcache_list_free(list);
683 channel = (SilcChannelEntry)id_cache->context;
686 *ret_entry = id_cache;
688 silc_idcache_list_free(list);
690 SILC_LOG_DEBUG(("Found"));
695 /* Finds channel by Channel ID. */
698 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
699 SilcIDCacheEntry *ret_entry)
701 SilcIDCacheEntry id_cache = NULL;
702 SilcChannelEntry channel;
707 SILC_LOG_DEBUG(("Channel ID (%s)",
708 silc_id_render(id, SILC_ID_CHANNEL)));
710 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id,
711 SILC_ID_CHANNEL, &id_cache))
714 channel = (SilcChannelEntry)id_cache->context;
717 *ret_entry = id_cache;
719 SILC_LOG_DEBUG(("Found"));
724 /* Replaces old Channel ID with new one. This is done when router forces
725 normal server to change Channel ID. */
728 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
729 SilcChannelID *new_id)
731 SilcIDCacheEntry id_cache = NULL;
732 SilcChannelEntry channel;
734 if (!old_id || !new_id)
737 SILC_LOG_DEBUG(("Replacing Channel ID"));
739 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
740 SILC_ID_CHANNEL, &id_cache))
743 channel = (SilcChannelEntry)id_cache->context;
744 silc_free(channel->id);
745 channel->id = new_id;
746 id_cache->id = (void *)new_id;