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)) {
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)) {
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"));
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, char *hmac)
566 SilcChannelEntry channel;
568 channel = silc_calloc(1, sizeof(*channel));
569 channel->channel_name = channel_name;
570 channel->mode = mode;
572 channel->router = router;
573 channel->channel_key = channel_key;
574 channel->hmac = hmac ? strdup(hmac) : strdup("hmac-sha1-96");
575 silc_list_init(channel->user_list, struct SilcChannelClientEntryStruct,
578 if (!silc_idcache_add(id_list->channels, channel->channel_name,
579 SILC_ID_CHANNEL, (void *)channel->id,
580 (void *)channel, TRUE)) {
588 /* Free channel entry. This free's everything. */
590 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
593 SilcChannelClientEntry chl;
595 /* Remove from cache */
597 if (!silc_idcache_del_by_id(id_list->channels, SILC_ID_CHANNEL,
602 if (entry->channel_name)
603 silc_free(entry->channel_name);
605 silc_free(entry->id);
607 silc_free(entry->topic);
608 if (entry->channel_key)
609 silc_cipher_free(entry->channel_key);
611 memset(entry->key, 0, entry->key_len / 8);
612 silc_free(entry->key);
615 /* Free all data, free also any reference from the client's channel
616 list since they share the same memory. */
617 silc_list_start(entry->user_list);
618 while ((chl = silc_list_get(entry->user_list)) != SILC_LIST_END) {
619 silc_list_del(chl->client->channels, chl);
620 silc_list_del(entry->user_list, chl);
624 memset(entry, 'F', sizeof(*entry));
632 /* Finds channel by channel name. Channel names are unique and they
633 are not case-sensitive. */
636 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
637 SilcIDCacheEntry *ret_entry)
639 SilcIDCacheList list = NULL;
640 SilcIDCacheEntry id_cache = NULL;
641 SilcChannelEntry channel;
643 SILC_LOG_DEBUG(("Channel by name"));
645 if (!silc_idcache_find_by_data_loose(id_list->channels, name, &list))
648 if (!silc_idcache_list_first(list, &id_cache)) {
649 silc_idcache_list_free(list);
653 channel = (SilcChannelEntry)id_cache->context;
656 *ret_entry = id_cache;
658 silc_idcache_list_free(list);
660 SILC_LOG_DEBUG(("Found"));
665 /* Finds channel by Channel ID. */
668 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
669 SilcIDCacheEntry *ret_entry)
671 SilcIDCacheEntry id_cache = NULL;
672 SilcChannelEntry channel;
677 SILC_LOG_DEBUG(("Channel ID (%s)",
678 silc_id_render(id, SILC_ID_CHANNEL)));
680 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id,
681 SILC_ID_CHANNEL, &id_cache))
684 channel = (SilcChannelEntry)id_cache->context;
687 *ret_entry = id_cache;
689 SILC_LOG_DEBUG(("Found"));
694 /* Replaces old Channel ID with new one. This is done when router forces
695 normal server to change Channel ID. */
698 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
699 SilcChannelID *new_id)
701 SilcIDCacheEntry id_cache = NULL;
702 SilcChannelEntry channel;
704 if (!old_id || !new_id)
707 SILC_LOG_DEBUG(("Replacing Channel ID"));
709 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
710 SILC_ID_CHANNEL, &id_cache))
713 channel = (SilcChannelEntry)id_cache->context;
714 silc_free(channel->id);
715 channel->id = new_id;
716 id_cache->id = (void *)new_id;