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)
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 silc_list_init(channel->user_list, struct SilcChannelClientEntryStruct,
577 if (!silc_idcache_add(id_list->channels, channel->channel_name,
578 SILC_ID_CHANNEL, (void *)channel->id,
579 (void *)channel, TRUE)) {
587 /* Free channel entry. This free's everything. */
589 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
592 SilcChannelClientEntry chl;
594 /* Remove from cache */
596 if (!silc_idcache_del_by_id(id_list->channels, SILC_ID_CHANNEL,
601 if (entry->channel_name)
602 silc_free(entry->channel_name);
604 silc_free(entry->id);
606 silc_free(entry->topic);
607 if (entry->channel_key)
608 silc_cipher_free(entry->channel_key);
610 memset(entry->key, 0, entry->key_len / 8);
611 silc_free(entry->key);
614 silc_list_start(entry->user_list);
615 while ((chl = silc_list_get(entry->user_list)) != SILC_LIST_END) {
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 SilcIDCacheList list = NULL;
636 SilcIDCacheEntry id_cache = NULL;
637 SilcChannelEntry channel;
639 SILC_LOG_DEBUG(("Channel by name"));
641 if (!silc_idcache_find_by_data_loose(id_list->channels, name, &list))
644 if (!silc_idcache_list_first(list, &id_cache)) {
645 silc_idcache_list_free(list);
649 channel = (SilcChannelEntry)id_cache->context;
652 *ret_entry = id_cache;
654 silc_idcache_list_free(list);
656 SILC_LOG_DEBUG(("Found"));
661 /* Finds channel by Channel ID. */
664 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
665 SilcIDCacheEntry *ret_entry)
667 SilcIDCacheEntry id_cache = NULL;
668 SilcChannelEntry channel;
673 SILC_LOG_DEBUG(("Channel ID (%s)",
674 silc_id_render(id, SILC_ID_CHANNEL)));
676 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id,
677 SILC_ID_CHANNEL, &id_cache))
680 channel = (SilcChannelEntry)id_cache->context;
683 *ret_entry = id_cache;
685 SILC_LOG_DEBUG(("Found"));
690 /* Replaces old Channel ID with new one. This is done when router forces
691 normal server to change Channel ID. */
694 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
695 SilcChannelID *new_id)
697 SilcIDCacheEntry id_cache = NULL;
698 SilcChannelEntry channel;
700 if (!old_id || !new_id)
703 SILC_LOG_DEBUG(("Replacing Channel ID"));
705 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
706 SILC_ID_CHANNEL, &id_cache))
709 channel = (SilcChannelEntry)id_cache->context;
710 silc_free(channel->id);
711 channel->id = new_id;
712 id_cache->id = (void *)new_id;