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->hash = idata->hash;
40 data->hmac = idata->hmac;
41 data->hmac_key = idata->hmac_key;
42 data->hmac_key_len = idata->hmac_key_len;
43 data->pkcs = idata->pkcs;
44 data->public_key = idata->public_key;
45 data->last_receive = idata->last_receive;
46 data->last_sent = idata->last_sent;
47 data->registered = idata->registered;
50 /* Free's all data in the common ID entry data structure. */
52 void silc_idlist_del_data(void *entry)
54 SilcIDListData idata = (SilcIDListData)entry;
56 silc_cipher_free(idata->send_key);
57 if (idata->receive_key)
58 silc_cipher_free(idata->receive_key);
60 silc_hmac_free(idata->hmac);
61 if (idata->hmac_key) {
62 memset(idata->hmac_key, 0, idata->hmac_key_len);
63 silc_free(idata->hmac_key);
66 silc_pkcs_free(idata->pkcs);
67 if (idata->public_key)
68 silc_pkcs_public_key_free(idata->public_key);
71 /******************************************************************************
73 Server entry functions
75 ******************************************************************************/
77 /* Add new server entry. This adds the new server entry to ID cache and
78 returns the allocated entry object or NULL on error. This is called
79 when new server connects to us. We also add ourselves to cache with
83 silc_idlist_add_server(SilcIDList id_list,
84 char *server_name, int server_type,
85 SilcServerID *id, SilcServerEntry router,
88 SilcServerEntry server;
90 SILC_LOG_DEBUG(("Adding new server entry"));
92 server = silc_calloc(1, sizeof(*server));
93 server->server_name = server_name;
94 server->server_type = server_type;
96 server->router = router;
97 server->connection = connection;
99 if (!silc_idcache_add(id_list->servers, server->server_name, SILC_ID_SERVER,
100 (void *)server->id, (void *)server, TRUE, FALSE)) {
108 /* Finds server by Server ID */
111 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
112 SilcIDCacheEntry *ret_entry)
114 SilcIDCacheEntry id_cache = NULL;
115 SilcServerEntry server;
120 SILC_LOG_DEBUG(("Server ID (%s)",
121 silc_id_render(id, SILC_ID_SERVER)));
123 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id,
124 SILC_ID_SERVER, &id_cache))
127 server = (SilcServerEntry)id_cache->context;
130 *ret_entry = id_cache;
135 /* Find server by name */
138 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
139 SilcIDCacheEntry *ret_entry)
141 SilcIDCacheEntry id_cache = NULL;
142 SilcServerEntry server;
144 SILC_LOG_DEBUG(("Server by name `%s'", name));
146 if (!silc_idcache_find_by_data_one(id_list->servers, name, &id_cache))
149 server = (SilcServerEntry)id_cache->context;
152 *ret_entry = id_cache;
157 /* Find server by connection parameters, hostname and port */
160 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
161 int port, SilcIDCacheEntry *ret_entry)
163 SilcIDCacheList list = NULL;
164 SilcIDCacheEntry id_cache = NULL;
165 SilcServerEntry server = NULL;
166 SilcSocketConnection sock;
168 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
170 if (!silc_idcache_find_by_id(id_list->servers, SILC_ID_CACHE_ANY,
171 SILC_ID_SERVER, &list))
174 if (!silc_idcache_list_first(list, &id_cache)) {
175 silc_idcache_list_free(list);
180 server = (SilcServerEntry)id_cache->context;
181 sock = (SilcSocketConnection)server->connection;
183 if (sock && ((sock->hostname && !strcmp(sock->hostname, hostname)) ||
184 (sock->ip && !strcmp(sock->ip, hostname)))
185 && sock->port == port)
191 if (!silc_idcache_list_next(list, &id_cache))
195 silc_idcache_list_free(list);
198 *ret_entry = id_cache;
200 SILC_LOG_DEBUG(("Found"));
205 /* Replaces old Server ID with new one */
208 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
209 SilcServerID *new_id)
211 SilcIDCacheEntry id_cache = NULL;
212 SilcServerEntry server;
214 if (!old_id || !new_id)
217 SILC_LOG_DEBUG(("Replacing Server ID"));
219 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id,
220 SILC_ID_SERVER, &id_cache))
223 server = (SilcServerEntry)id_cache->context;
224 silc_free(server->id);
226 id_cache->id = (void *)new_id;
231 /* Removes and free's server entry from ID list */
233 void silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
236 /* Remove from cache */
238 silc_idcache_del_by_id(id_list->servers, SILC_ID_SERVER,
242 if (entry->server_name)
243 silc_free(entry->server_name);
245 silc_free(entry->id);
247 memset(entry, 'F', sizeof(*entry));
252 /******************************************************************************
254 Client entry functions
256 ******************************************************************************/
258 /* Add new client entry. This adds the client entry to ID cache system
259 and returns the allocated client entry or NULL on error. This is
260 called when new client connection is accepted to the server. If The
261 `router' is provided then the all server routines assume that the client
262 is not directly connected local client but it has router set and is
263 remote. If this is the case then `connection' must be NULL. If, on the
264 other hand, the `connection' is provided then the client is assumed
265 to be directly connected local client and `router' must be NULL. */
268 silc_idlist_add_client(SilcIDList id_list, unsigned char *nickname,
269 char *username, char *userinfo, SilcClientID *id,
270 SilcServerEntry router, void *connection)
272 SilcClientEntry client;
274 SILC_LOG_DEBUG(("Adding new client entry"));
276 client = silc_calloc(1, sizeof(*client));
277 client->nickname = nickname;
278 client->username = username;
279 client->userinfo = userinfo;
281 client->router = router;
282 client->connection = connection;
283 silc_list_init(client->channels, struct SilcChannelClientEntryStruct,
286 if (!silc_idcache_add(id_list->clients, nickname, SILC_ID_CLIENT,
287 (void *)client->id, (void *)client, TRUE, FALSE)) {
295 /* Free client entry. This free's everything and removes the entry
296 from ID cache. Call silc_idlist_del_data before calling this one. */
298 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
301 /* Remove from cache */
303 if (!silc_idcache_del_by_id(id_list->clients, SILC_ID_CLIENT,
309 silc_free(entry->nickname);
311 silc_free(entry->username);
313 silc_free(entry->userinfo);
315 silc_free(entry->id);
317 memset(entry, 'F', sizeof(*entry));
326 /* Returns all clients matching requested nickname. Number of clients is
327 returned to `clients_count'. Caller must free the returned table. */
330 silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
331 char *server, unsigned int *clients_count)
333 SilcIDCacheList list = NULL;
334 SilcIDCacheEntry id_cache = NULL;
335 SilcClientEntry *clients;
338 if (!silc_idcache_find_by_data(id_list->clients, nickname, &list))
341 clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
344 silc_idcache_list_first(list, &id_cache);
345 clients[i++] = (SilcClientEntry)id_cache->context;
347 while (silc_idcache_list_next(list, &id_cache))
348 clients[i++] = (SilcClientEntry)id_cache->context;
350 silc_idcache_list_free(list);
358 /* Returns all clients matching requested nickname. Number of clients is
359 returned to `clients_count'. Caller must free the returned table. */
362 silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
364 unsigned int *clients_count)
366 SilcIDCacheList list = NULL;
367 SilcIDCacheEntry id_cache = NULL;
368 SilcClientEntry *clients;
369 unsigned char hash[32];
372 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
374 if (!silc_idcache_find_by_data(id_list->clients, hash, &list))
377 clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients));
380 silc_idcache_list_first(list, &id_cache);
381 clients[i++] = (SilcClientEntry)id_cache->context;
383 while (silc_idcache_list_next(list, &id_cache))
384 clients[i++] = (SilcClientEntry)id_cache->context;
386 silc_idcache_list_free(list);
394 /* Finds client entry by nickname. */
397 silc_idlist_find_client_by_nickname(SilcIDList id_list, char *nickname,
398 char *server, SilcIDCacheEntry *ret_entry)
400 SilcIDCacheList list = NULL;
401 SilcIDCacheEntry id_cache = NULL;
402 SilcClientEntry client = NULL;
404 SILC_LOG_DEBUG(("Client by nickname"));
407 if (!silc_idcache_find_by_data(id_list->clients, nickname, &list))
411 while (silc_idcache_list_next(list, &id_cache)) {
412 client = (SilcClientEntry)id_cache->context;
414 if (!strcmp(server, XXX, strlen(server)))
421 silc_idcache_list_free(list);
426 if (!silc_idcache_find_by_data_one(id_list->clients, nickname, &id_cache))
429 client = (SilcClientEntry)id_cache->context;
432 *ret_entry = id_cache;
435 SILC_LOG_DEBUG(("Found"));
440 /* Finds client by nickname hash. */
443 silc_idlist_find_client_by_hash(SilcIDList id_list, char *nickname,
444 SilcHash md5hash, SilcIDCacheEntry *ret_entry)
446 SilcIDCacheList list = NULL;
447 SilcIDCacheEntry id_cache = NULL;
448 SilcClientEntry client = NULL;
449 unsigned char hash[32];
451 SILC_LOG_DEBUG(("Client by hash"));
453 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
455 if (!silc_idcache_find_by_id(id_list->clients, SILC_ID_CACHE_ANY,
456 SILC_ID_CLIENT, &list))
459 if (!silc_idcache_list_first(list, &id_cache)) {
460 silc_idcache_list_free(list);
465 client = (SilcClientEntry)id_cache->context;
467 if (client && !SILC_ID_COMPARE_HASH(client->id, hash))
473 if (!silc_idcache_list_next(list, &id_cache))
477 silc_idcache_list_free(list);
480 *ret_entry = id_cache;
482 SILC_LOG_DEBUG(("Found"));
487 /* Finds client by Client ID */
490 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
491 SilcIDCacheEntry *ret_entry)
493 SilcIDCacheEntry id_cache = NULL;
494 SilcClientEntry client;
499 SILC_LOG_DEBUG(("Client ID (%s)",
500 silc_id_render(id, SILC_ID_CLIENT)));
502 if (!silc_idcache_find_by_id_one(id_list->clients, (void *)id,
503 SILC_ID_CLIENT, &id_cache))
506 client = (SilcClientEntry)id_cache->context;
509 *ret_entry = id_cache;
511 SILC_LOG_DEBUG(("Found"));
516 /* Replaces old Client ID with new one */
519 silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id,
520 SilcClientID *new_id)
522 SilcIDCacheEntry id_cache = NULL;
523 SilcClientEntry client;
525 if (!old_id || !new_id)
528 SILC_LOG_DEBUG(("Replacing Client ID"));
530 if (!silc_idcache_find_by_id_one(id_list->clients, (void *)old_id,
531 SILC_ID_CLIENT, &id_cache))
534 client = (SilcClientEntry)id_cache->context;
535 silc_free(client->id);
537 id_cache->id = (void *)new_id;
539 /* If the old ID Cache data was the hash value of the old Client ID
540 replace it with the hash of new Client ID */
541 if (id_cache->data && !SILC_ID_COMPARE_HASH(old_id, id_cache->data)) {
542 silc_free(id_cache->data);
543 id_cache->data = silc_calloc(sizeof(new_id->hash), sizeof(unsigned char));
544 memcpy(id_cache->data, new_id->hash, sizeof(new_id->hash));
545 silc_idcache_sort_by_data(id_list->clients);
548 SILC_LOG_DEBUG(("Replaced"));
553 /* Client cache entry destructor that is called when the cache is purged. */
555 void silc_idlist_client_destructor(SilcIDCache cache,
556 SilcIDCacheEntry entry)
558 SilcClientEntry client;
560 SILC_LOG_DEBUG(("Start"));
562 client = (SilcClientEntry)entry->context;
564 if (client->nickname)
565 silc_free(client->nickname);
566 if (client->username)
567 silc_free(client->username);
568 if (client->userinfo)
569 silc_free(client->userinfo);
571 silc_free(client->id);
573 memset(client, 'F', sizeof(*client));
578 /******************************************************************************
580 Channel entry functions
582 ******************************************************************************/
584 /* Add new channel entry. This add the new channel entry to the ID cache
585 system and returns the allocated entry or NULL on error. */
588 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
589 SilcChannelID *id, SilcServerEntry router,
590 SilcCipher channel_key, SilcHmac hmac)
592 SilcChannelEntry channel;
594 channel = silc_calloc(1, sizeof(*channel));
595 channel->channel_name = channel_name;
596 channel->mode = mode;
598 channel->router = router;
599 channel->channel_key = channel_key;
600 channel->hmac = hmac;
602 if (!silc_hmac_alloc("hmac-sha1-96", NULL, &channel->hmac)) {
607 silc_list_init(channel->user_list, struct SilcChannelClientEntryStruct,
610 if (!silc_idcache_add(id_list->channels, channel->channel_name,
611 SILC_ID_CHANNEL, (void *)channel->id,
612 (void *)channel, TRUE, FALSE)) {
620 /* Free channel entry. This free's everything. */
622 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
625 SilcChannelClientEntry chl;
627 /* Remove from cache */
629 if (!silc_idcache_del_by_id(id_list->channels, SILC_ID_CHANNEL,
634 if (entry->channel_name)
635 silc_free(entry->channel_name);
637 silc_free(entry->id);
639 silc_free(entry->topic);
640 if (entry->channel_key)
641 silc_cipher_free(entry->channel_key);
643 memset(entry->key, 0, entry->key_len / 8);
644 silc_free(entry->key);
647 /* Free all data, free also any reference from the client's channel
648 list since they share the same memory. */
649 silc_list_start(entry->user_list);
650 while ((chl = silc_list_get(entry->user_list)) != SILC_LIST_END) {
651 silc_list_del(chl->client->channels, chl);
652 silc_list_del(entry->user_list, chl);
656 memset(entry, 'F', sizeof(*entry));
664 /* Finds channel by channel name. Channel names are unique and they
665 are not case-sensitive. */
668 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
669 SilcIDCacheEntry *ret_entry)
671 SilcIDCacheList list = NULL;
672 SilcIDCacheEntry id_cache = NULL;
673 SilcChannelEntry channel;
675 SILC_LOG_DEBUG(("Channel by name"));
677 if (!silc_idcache_find_by_data_loose(id_list->channels, name, &list))
680 if (!silc_idcache_list_first(list, &id_cache)) {
681 silc_idcache_list_free(list);
685 channel = (SilcChannelEntry)id_cache->context;
688 *ret_entry = id_cache;
690 silc_idcache_list_free(list);
692 SILC_LOG_DEBUG(("Found"));
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,
713 SILC_ID_CHANNEL, &id_cache))
716 channel = (SilcChannelEntry)id_cache->context;
719 *ret_entry = id_cache;
721 SILC_LOG_DEBUG(("Found"));
726 /* Replaces old Channel ID with new one. This is done when router forces
727 normal server to change Channel ID. */
730 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
731 SilcChannelID *new_id)
733 SilcIDCacheEntry id_cache = NULL;
734 SilcChannelEntry channel;
736 if (!old_id || !new_id)
739 SILC_LOG_DEBUG(("Replacing Channel ID"));
741 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
742 SILC_ID_CHANNEL, &id_cache))
745 channel = (SilcChannelEntry)id_cache->context;
746 silc_free(channel->id);
747 channel->id = new_id;
748 id_cache->id = (void *)new_id;