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->rekey = idata->rekey;
40 data->hash = idata->hash;
41 data->hmac_send = idata->hmac_send;
42 data->hmac_receive = idata->hmac_receive;
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 if (idata->rekey->send_enc_key) {
60 memset(idata->rekey->send_enc_key, 0, idata->rekey->enc_key_len);
61 silc_free(idata->rekey->send_enc_key);
63 silc_free(idata->rekey);
65 if (idata->hmac_send) /* Same as idata->hmac_receive */
66 silc_hmac_free(idata->hmac_send);
67 if (idata->public_key)
68 silc_pkcs_public_key_free(idata->public_key);
73 SILC_TASK_CALLBACK_GLOBAL(silc_idlist_purge)
75 SilcIDListPurge i = (SilcIDListPurge)context;
77 SILC_LOG_DEBUG(("Start"));
79 silc_idcache_purge(i->cache);
80 silc_task_register(i->timeout_queue, 0,
83 SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
86 /******************************************************************************
88 Server entry functions
90 ******************************************************************************/
92 /* Add new server entry. This adds the new server entry to ID cache and
93 returns the allocated entry object or NULL on error. This is called
94 when new server connects to us. We also add ourselves to cache with
98 silc_idlist_add_server(SilcIDList id_list,
99 char *server_name, int server_type,
100 SilcServerID *id, SilcServerEntry router,
103 SilcServerEntry server;
105 SILC_LOG_DEBUG(("Adding new server entry"));
107 server = silc_calloc(1, sizeof(*server));
108 server->server_name = server_name;
109 server->server_type = server_type;
111 server->router = router;
112 server->connection = connection;
114 if (!silc_idcache_add(id_list->servers, server->server_name,
115 server->server_name ? strlen(server->server_name) : 0,
116 (void *)server->id, (void *)server, FALSE)) {
124 /* Finds server by Server ID */
127 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
128 SilcIDCacheEntry *ret_entry)
130 SilcIDCacheEntry id_cache = NULL;
131 SilcServerEntry server;
136 SILC_LOG_DEBUG(("Server ID (%s)",
137 silc_id_render(id, SILC_ID_SERVER)));
139 if (!silc_idcache_find_by_id(id_list->servers, (void *)id,
143 server = (SilcServerEntry)id_cache->context;
146 *ret_entry = id_cache;
151 /* Find server by name */
154 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
155 SilcIDCacheEntry *ret_entry)
157 SilcIDCacheEntry id_cache = NULL;
158 SilcServerEntry server;
160 SILC_LOG_DEBUG(("Server by name `%s'", name));
162 if (!silc_idcache_find_by_data_one(id_list->servers, name, strlen(name),
166 server = (SilcServerEntry)id_cache->context;
169 *ret_entry = id_cache;
171 SILC_LOG_DEBUG(("Found"));
176 /* Find server by connection parameters, hostname and port */
179 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
180 int port, SilcIDCacheEntry *ret_entry)
182 SilcIDCacheList list = NULL;
183 SilcIDCacheEntry id_cache = NULL;
184 SilcServerEntry server = NULL;
185 SilcSocketConnection sock;
187 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
189 if (!silc_idcache_get_all(id_list->servers, &list))
192 if (!silc_idcache_list_first(list, &id_cache)) {
193 silc_idcache_list_free(list);
198 server = (SilcServerEntry)id_cache->context;
199 sock = (SilcSocketConnection)server->connection;
201 if (sock && ((sock->hostname && !strcmp(sock->hostname, hostname)) ||
202 (sock->ip && !strcmp(sock->ip, hostname)))
203 && sock->port == port)
209 if (!silc_idcache_list_next(list, &id_cache))
213 silc_idcache_list_free(list);
216 *ret_entry = id_cache;
218 SILC_LOG_DEBUG(("Found"));
223 /* Replaces old Server ID with new one */
226 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
227 SilcServerID *new_id)
229 SilcIDCacheEntry id_cache = NULL;
230 SilcServerEntry server;
232 if (!old_id || !new_id)
235 SILC_LOG_DEBUG(("Replacing Server ID"));
237 if (!silc_idcache_find_by_id(id_list->servers, (void *)old_id, &id_cache))
240 server = (SilcServerEntry)id_cache->context;
241 silc_free(server->id);
243 id_cache->id = (void *)new_id;
245 SILC_LOG_DEBUG(("Found"));
250 /* Removes and free's server entry from ID list */
252 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
254 SILC_LOG_DEBUG(("Start"));
257 /* Remove from cache */
259 if (!silc_idcache_del_by_id(id_list->servers, (void *)entry->id))
263 if (entry->server_name)
264 silc_free(entry->server_name);
266 silc_free(entry->id);
268 memset(entry, 'F', sizeof(*entry));
276 /******************************************************************************
278 Client entry functions
280 ******************************************************************************/
282 /* Add new client entry. This adds the client entry to ID cache system
283 and returns the allocated client entry or NULL on error. This is
284 called when new client connection is accepted to the server. If The
285 `router' is provided then the all server routines assume that the client
286 is not directly connected local client but it has router set and is
287 remote. If this is the case then `connection' must be NULL. If, on the
288 other hand, the `connection' is provided then the client is assumed
289 to be directly connected local client and `router' must be NULL. */
292 silc_idlist_add_client(SilcIDList id_list, unsigned char *nickname,
293 uint32 nickname_len, char *username,
294 char *userinfo, SilcClientID *id,
295 SilcServerEntry router, void *connection)
297 SilcClientEntry client;
299 SILC_LOG_DEBUG(("Adding new client entry"));
301 client = silc_calloc(1, sizeof(*client));
302 client->nickname = nickname;
303 client->username = username;
304 client->userinfo = userinfo;
306 client->router = router;
307 client->connection = connection;
308 silc_list_init(client->channels, struct SilcChannelClientEntryStruct,
311 if (!silc_idcache_add(id_list->clients, nickname, nickname_len,
312 (void *)client->id, (void *)client, FALSE)) {
320 /* Free client entry. This free's everything and removes the entry
321 from ID cache. Call silc_idlist_del_data before calling this one. */
323 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
325 SILC_LOG_DEBUG(("Start"));
328 /* Remove from cache */
330 if (!silc_idcache_del_by_id(id_list->clients, (void *)entry->id))
335 silc_free(entry->nickname);
337 silc_free(entry->username);
339 silc_free(entry->userinfo);
341 silc_free(entry->id);
343 memset(entry, 'F', sizeof(*entry));
352 /* Returns all clients matching requested nickname. Number of clients is
353 returned to `clients_count'. Caller must free the returned table. */
355 int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
357 SilcClientEntry **clients,
358 uint32 *clients_count)
360 SilcIDCacheList list = NULL;
361 SilcIDCacheEntry id_cache = NULL;
364 SILC_LOG_DEBUG(("Start"));
366 if (!silc_idcache_find_by_data(id_list->clients, nickname, strlen(nickname),
370 *clients = silc_realloc(*clients,
371 (silc_idcache_list_count(list) + *clients_count) *
375 silc_idcache_list_first(list, &id_cache);
376 (*clients)[i++] = (SilcClientEntry)id_cache->context;
378 while (silc_idcache_list_next(list, &id_cache))
379 (*clients)[i++] = (SilcClientEntry)id_cache->context;
381 silc_idcache_list_free(list);
388 /* Returns all clients matching requested nickname. Number of clients is
389 returned to `clients_count'. Caller must free the returned table. */
390 /* XXX This actually checks the data, which can be hash of the nickname
391 but is not if the client is local client. Global client on global
392 list may have hash. Thus, this is not fully reliable function.
393 Instead this should probably check the hash from the list of client ID's. */
395 int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
397 SilcClientEntry **clients,
398 uint32 *clients_count)
400 SilcIDCacheList list = NULL;
401 SilcIDCacheEntry id_cache = NULL;
402 unsigned char hash[32];
405 SILC_LOG_DEBUG(("Start"));
407 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
409 if (!silc_idcache_find_by_data(id_list->clients, hash,
410 md5hash->hash->hash_len, &list))
413 *clients = silc_realloc(*clients,
414 (silc_idcache_list_count(list) + *clients_count) *
418 silc_idcache_list_first(list, &id_cache);
419 (*clients)[i++] = (SilcClientEntry)id_cache->context;
421 while (silc_idcache_list_next(list, &id_cache))
422 (*clients)[i++] = (SilcClientEntry)id_cache->context;
424 silc_idcache_list_free(list);
431 /* Finds client by Client ID */
434 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
435 SilcIDCacheEntry *ret_entry)
437 SilcIDCacheEntry id_cache = NULL;
438 SilcClientEntry client;
443 SILC_LOG_DEBUG(("Client ID (%s)",
444 silc_id_render(id, SILC_ID_CLIENT)));
446 if (!silc_idcache_find_by_id(id_list->clients, (void *)id, &id_cache))
449 client = (SilcClientEntry)id_cache->context;
452 *ret_entry = id_cache;
454 SILC_LOG_DEBUG(("Found"));
459 /* Replaces old Client ID with new one */
462 silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id,
463 SilcClientID *new_id)
465 SilcIDCacheEntry id_cache = NULL;
466 SilcClientEntry client;
468 if (!old_id || !new_id)
471 SILC_LOG_DEBUG(("Replacing Client ID"));
473 if (!silc_idcache_find_by_id(id_list->clients, (void *)old_id, &id_cache))
476 client = (SilcClientEntry)id_cache->context;
477 silc_free(client->id);
479 id_cache->id = (void *)new_id;
481 /* XXX does not work correctly with the new ID Cache */
483 /* If the old ID Cache data was the hash value of the old Client ID
484 replace it with the hash of new Client ID */
485 if (id_cache->data && SILC_ID_COMPARE_HASH(old_id, id_cache->data)) {
486 silc_free(id_cache->data);
487 id_cache->data = silc_calloc(sizeof(new_id->hash), sizeof(unsigned char));
488 memcpy(id_cache->data, new_id->hash, sizeof(new_id->hash));
491 SILC_LOG_DEBUG(("Replaced"));
496 /* Client cache entry destructor that is called when the cache is purged. */
498 void silc_idlist_client_destructor(SilcIDCache cache,
499 SilcIDCacheEntry entry)
501 SilcClientEntry client;
503 SILC_LOG_DEBUG(("Start"));
505 client = (SilcClientEntry)entry->context;
507 if (client->nickname)
508 silc_free(client->nickname);
509 if (client->username)
510 silc_free(client->username);
511 if (client->userinfo)
512 silc_free(client->userinfo);
514 silc_free(client->id);
516 memset(client, 'F', sizeof(*client));
521 /******************************************************************************
523 Channel entry functions
525 ******************************************************************************/
527 /* Add new channel entry. This add the new channel entry to the ID cache
528 system and returns the allocated entry or NULL on error. */
531 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
532 SilcChannelID *id, SilcServerEntry router,
533 SilcCipher channel_key, SilcHmac hmac)
535 SilcChannelEntry channel;
537 channel = silc_calloc(1, sizeof(*channel));
538 channel->channel_name = channel_name;
539 channel->mode = mode;
541 channel->router = router;
542 channel->channel_key = channel_key;
543 channel->hmac = hmac;
545 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &channel->hmac)) {
550 silc_list_init(channel->user_list, struct SilcChannelClientEntryStruct,
553 if (!silc_idcache_add(id_list->channels, channel->channel_name,
554 strlen(channel->channel_name),
555 (void *)channel->id, (void *)channel, FALSE)) {
563 /* Free channel entry. This free's everything. */
565 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
567 SILC_LOG_DEBUG(("Start"));
570 SilcChannelClientEntry chl;
572 /* Remove from cache */
574 if (!silc_idcache_del_by_id(id_list->channels, (void *)entry->id))
578 if (entry->channel_name)
579 silc_free(entry->channel_name);
581 silc_free(entry->id);
583 silc_free(entry->topic);
584 if (entry->channel_key)
585 silc_cipher_free(entry->channel_key);
587 memset(entry->key, 0, entry->key_len / 8);
588 silc_free(entry->key);
591 silc_free(entry->cipher);
592 if (entry->hmac_name)
593 silc_free(entry->hmac_name);
595 silc_free(entry->rekey);
597 /* Free all data, free also any reference from the client's channel
598 list since they share the same memory. */
599 silc_list_start(entry->user_list);
600 while ((chl = silc_list_get(entry->user_list)) != SILC_LIST_END) {
601 silc_list_del(chl->client->channels, chl);
602 silc_list_del(entry->user_list, chl);
606 memset(entry, 'F', sizeof(*entry));
614 /* Finds channel by channel name. Channel names are unique and they
615 are not case-sensitive. */
618 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
619 SilcIDCacheEntry *ret_entry)
621 SilcIDCacheList list = NULL;
622 SilcIDCacheEntry id_cache = NULL;
623 SilcChannelEntry channel;
625 SILC_LOG_DEBUG(("Channel by name"));
627 if (!silc_idcache_find_by_data(id_list->channels, name, strlen(name), &list))
630 if (!silc_idcache_list_first(list, &id_cache)) {
631 silc_idcache_list_free(list);
635 channel = (SilcChannelEntry)id_cache->context;
638 *ret_entry = id_cache;
640 silc_idcache_list_free(list);
642 SILC_LOG_DEBUG(("Found"));
647 /* Finds channel by Channel ID. */
650 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
651 SilcIDCacheEntry *ret_entry)
653 SilcIDCacheEntry id_cache = NULL;
654 SilcChannelEntry channel;
659 SILC_LOG_DEBUG(("Channel ID (%s)",
660 silc_id_render(id, SILC_ID_CHANNEL)));
662 if (!silc_idcache_find_by_id(id_list->channels, (void *)id, &id_cache))
665 channel = (SilcChannelEntry)id_cache->context;
668 *ret_entry = id_cache;
670 SILC_LOG_DEBUG(("Found"));
675 /* Replaces old Channel ID with new one. This is done when router forces
676 normal server to change Channel ID. */
679 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
680 SilcChannelID *new_id)
682 SilcIDCacheEntry id_cache = NULL;
683 SilcChannelEntry channel;
685 if (!old_id || !new_id)
688 SILC_LOG_DEBUG(("Replacing Channel ID"));
690 if (!silc_idcache_find_by_id(id_list->channels, (void *)old_id, &id_cache))
693 channel = (SilcChannelEntry)id_cache->context;
694 silc_free(channel->id);
695 channel->id = new_id;
696 id_cache->id = (void *)new_id;
698 SILC_LOG_DEBUG(("Replaced"));
703 /* Returns channels from the ID list. If the `channel_id' is NULL then
704 all channels are returned. */
707 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
708 uint32 *channels_count)
710 SilcIDCacheList list = NULL;
711 SilcIDCacheEntry id_cache = NULL;
712 SilcChannelEntry *channels = NULL;
715 SILC_LOG_DEBUG(("Start"));
718 if (!silc_idcache_get_all(id_list->channels, &list))
721 channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels));
724 silc_idcache_list_first(list, &id_cache);
725 channels[i++] = (SilcChannelEntry)id_cache->context;
727 while (silc_idcache_list_next(list, &id_cache))
728 channels[i++] = (SilcChannelEntry)id_cache->context;
730 silc_idcache_list_free(list);
732 if (!silc_idcache_find_by_id(id_list->channels, channel_id, &id_cache))
736 channels = silc_calloc(1, sizeof(*channels));
737 channels[0] = (SilcChannelEntry)id_cache->context;