5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2005, 2007 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"
24 #include "server_internal.h"
26 /******************************************************************************
30 ******************************************************************************/
32 /* This function is used to add keys and stuff to common ID entry data
35 void silc_idlist_add_data(void *entry, SilcIDListData idata)
37 SilcIDListData data = entry;
38 data->hash = idata->hash;
39 data->public_key = idata->public_key;
40 memcpy(data->fingerprint, idata->fingerprint, sizeof(data->fingerprint));
41 data->rekey = idata->rekey;
42 data->last_receive = idata->last_receive;
43 data->last_sent = idata->last_sent;
44 data->status = idata->status;
45 data->created = time(0); /* Update creation time */
48 /* Free's all data in the common ID entry data structure. */
50 void silc_idlist_del_data(void *entry)
52 SilcIDListData idata = (SilcIDListData)entry;
55 silc_hash_free(idata->hash);
56 if (idata->public_key)
57 silc_pkcs_public_key_free(idata->public_key);
60 idata->public_key = NULL;
65 SILC_TASK_CALLBACK(silc_idlist_purge)
67 SilcServer server = app_context;
68 SilcIDListPurge i = (SilcIDListPurge)context;
70 SILC_LOG_DEBUG(("Purging cache"));
74 silc_idcache_purge(i->cache);
75 silc_schedule_task_add_timeout(server->schedule, silc_idlist_purge, i,
80 /******************************************************************************
82 Server entry functions
84 ******************************************************************************/
86 /* Add new server entry. This adds the new server entry to ID cache and
87 returns the allocated entry object or NULL on error. This is called
88 when new server connects to us. We also add ourselves to cache with
92 silc_idlist_add_server(SilcIDList id_list,
93 char *server_name, int server_type,
94 SilcServerID *id, SilcServerEntry router,
97 SilcServerEntry server;
98 char *server_namec = NULL;
100 SILC_LOG_DEBUG(("Adding new server entry"));
102 /* Normalize name. This is cached, original is in server context. */
104 server_namec = silc_identifier_check(server_name, strlen(server_name),
105 SILC_STRING_UTF8, 256, NULL);
110 server = silc_calloc(1, sizeof(*server));
111 server->server_name = server_name;
112 server->server_type = server_type;
114 server->router = router;
115 server->connection = connection;
117 if (!silc_idcache_add(id_list->servers, server_namec,
118 (void *)server->id, (void *)server)) {
120 silc_free(server_namec);
127 /* Finds server by Server ID */
130 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
131 SilcBool registered, SilcIDCacheEntry *ret_entry)
133 SilcIDCacheEntry id_cache = NULL;
134 SilcServerEntry server;
139 SILC_LOG_DEBUG(("Server ID (%s)",
140 silc_id_render(id, SILC_ID_SERVER)));
142 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id, &id_cache))
145 server = (SilcServerEntry)id_cache->context;
147 if (server && registered &&
148 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
152 *ret_entry = id_cache;
154 SILC_LOG_DEBUG(("Found"));
159 /* Find server by name. The 'name' must be normalized already. */
162 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
163 SilcBool registered, SilcIDCacheEntry *ret_entry)
165 SilcIDCacheEntry id_cache = NULL;
166 SilcServerEntry server;
168 SILC_LOG_DEBUG(("Server by name `%s'", name));
170 if (!silc_idcache_find_by_name_one(id_list->servers, name, &id_cache))
173 server = (SilcServerEntry)id_cache->context;
175 if (server && registered &&
176 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
180 *ret_entry = id_cache;
182 SILC_LOG_DEBUG(("Found"));
187 /* Find server by connection parameters, hostname and port */
190 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
191 int port, SilcBool registered,
192 SilcIDCacheEntry *ret_entry)
195 SilcIDCacheEntry id_cache = NULL;
196 SilcServerEntry server = NULL;
197 SilcPacketStream sock;
198 const char *host = NULL, *ip = NULL;
200 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
202 if (!silc_idcache_get_all(id_list->servers, &list))
205 silc_list_start(list);
206 while ((id_cache = silc_list_get(list))) {
207 server = id_cache->context;
208 sock = server->connection;
210 if (sock && silc_socket_stream_get_info(sock, NULL, &host, &ip, NULL)) {
211 if (((host && !strcasecmp(host, hostname)) ||
212 (ip && !strcasecmp(ip, hostname))) &&
213 server->id->port == SILC_SWAB_16(port))
221 if (server && registered &&
222 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
226 *ret_entry = id_cache;
228 SILC_LOG_DEBUG(("Found"));
233 /* Replaces old Server ID with new one */
236 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
237 SilcServerID *new_id)
239 SilcIDCacheEntry id_cache = NULL;
240 SilcServerEntry server;
243 if (!old_id || !new_id)
246 SILC_LOG_DEBUG(("Replacing Server ID"));
248 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id, &id_cache))
251 server = (SilcServerEntry)id_cache->context;
252 name = strdup(id_cache->name);
254 /* Remove the old entry and add a new one */
256 silc_idcache_del_by_id(id_list->servers, (void *)server->id, NULL);
257 *server->id = *new_id;
258 silc_idcache_add(id_list->servers, name, server->id, server);
260 SILC_LOG_DEBUG(("Found"));
265 /* Removes and free's server entry from ID list */
267 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
270 /* Remove from cache */
271 if (!silc_idcache_del_by_context(id_list->servers, entry, NULL)) {
272 SILC_LOG_DEBUG(("Unknown server, did not delete"));
276 SILC_LOG_DEBUG(("Deleting server %s id %s", entry->server_name ?
277 entry->server_name : "",
279 silc_id_render(entry->id, SILC_ID_SERVER) : ""));
282 silc_free(entry->server_name);
283 silc_free(entry->id);
284 silc_free(entry->server_info);
286 memset(entry, 'F', sizeof(*entry));
294 /******************************************************************************
296 Client entry functions
298 ******************************************************************************/
300 /* Add new client entry. This adds the client entry to ID cache system
301 and returns the allocated client entry or NULL on error. This is
302 called when new client connection is accepted to the server. If The
303 `router' is provided then the all server routines assume that the client
304 is not directly connected local client but it has router set and is
305 remote. If this is the case then `connection' must be NULL. If, on the
306 other hand, the `connection' is provided then the client is assumed
307 to be directly connected local client and `router' must be NULL. */
310 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
311 char *userinfo, SilcClientID *id,
312 SilcServerEntry router, void *connection)
314 SilcClientEntry client;
315 char *nicknamec = NULL;
317 SILC_LOG_DEBUG(("Adding new client entry"));
319 /* Normalize name. This is cached, original is in client context. */
321 nicknamec = silc_identifier_check(nickname, strlen(nickname),
322 SILC_STRING_UTF8, 128, NULL);
327 /* Check username. */
329 char u[128 + 1], h[256 + 1];
332 ret = silc_parse_userfqdn(username, u, sizeof(u), h, sizeof(h));
335 if (!silc_identifier_verify(u, strlen(u), SILC_STRING_UTF8, 128))
337 if (ret > 1 && !silc_identifier_verify(h, strlen(h),
338 SILC_STRING_UTF8, 256))
342 client = silc_calloc(1, sizeof(*client));
343 client->nickname = nickname;
344 client->username = username ? strdup(username) : NULL;
345 client->userinfo = userinfo;
347 client->router = router;
348 client->connection = connection;
349 client->channels = silc_hash_table_alloc(3, silc_hash_ptr, NULL,
350 NULL, NULL, NULL, NULL, TRUE);
352 if (!silc_idcache_add(id_list->clients, nicknamec, (void *)client->id,
354 silc_hash_table_free(client->channels);
356 silc_free(nicknamec);
363 /* Free client entry. This free's everything and removes the entry
364 from ID cache. Call silc_idlist_del_data before calling this one. */
366 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
368 SILC_LOG_DEBUG(("Start"));
371 if (!silc_idcache_del_by_context(id_list->clients, entry, NULL /* XXX */)) {
372 SILC_LOG_DEBUG(("Unknown client, did not delete"));
376 assert(!silc_hash_table_count(entry->channels));
378 silc_free(entry->nickname);
379 silc_free(entry->servername);
380 silc_free(entry->username);
381 silc_free(entry->userinfo);
382 silc_free(entry->id);
383 silc_free(entry->attrs);
384 silc_hash_table_free(entry->channels);
386 memset(entry, 'F', sizeof(*entry));
395 /* ID Cache destructor */
397 void silc_idlist_client_destructor(SilcIDCache cache,
398 SilcIDCacheEntry entry,
402 SilcServer server = app_context;
403 SilcClientEntry client;
405 client = (SilcClientEntry)entry->context;
407 /* Remove this client from the public key hash list */
408 if (client->data.public_key)
409 silc_hash_table_del_by_context(server->pk_hash,
410 client->data.public_key, client);
412 assert(!silc_hash_table_count(client->channels));
413 silc_free(client->nickname);
414 silc_free(client->servername);
415 silc_free(client->username);
416 silc_free(client->userinfo);
417 silc_free(client->id);
418 silc_free(client->attrs);
419 if (client->data.public_key)
420 silc_pkcs_public_key_free(client->data.public_key);
421 silc_hash_table_free(client->channels);
423 memset(client, 'A', sizeof(*client));
428 /* Returns all clients matching requested nickname. Number of clients is
429 returned to `clients_count'. Caller must free the returned table.
430 The 'nickname' must be normalized already. */
432 int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
434 SilcClientEntry **clients,
435 SilcUInt32 *clients_count)
438 SilcIDCacheEntry id_cache = NULL;
440 SILC_LOG_DEBUG(("Start"));
442 if (!silc_idcache_find_by_name(id_list->clients, nickname, &list))
445 *clients = silc_realloc(*clients,
446 (silc_list_count(list) + *clients_count) *
449 silc_list_start(list);
450 while ((id_cache = silc_list_get(list)))
451 (*clients)[(*clients_count)++] = id_cache->context;
453 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
458 /* Returns all clients matching requested nickname hash. Number of clients
459 is returned to `clients_count'. Caller must free the returned table.
460 The 'nickname' must be normalized already. */
462 int silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
464 SilcClientEntry **clients,
465 SilcUInt32 *clients_count)
468 SilcIDCacheEntry id_cache = NULL;
469 unsigned char hash[SILC_HASH_MAXLEN];
470 SilcClientID client_id;
472 SILC_LOG_DEBUG(("Start"));
474 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
476 /* As the Client ID is hashed in the ID cache by hashing only the hash
477 from the Client ID, we can do a lookup with only the hash not the
478 other parts of the ID and get all the clients with that hash, ie.
479 with that nickname, as the hash is from the nickname. */
480 memset(&client_id, 0, sizeof(client_id));
481 memcpy(&client_id.hash, hash, sizeof(client_id.hash));
482 if (!silc_idcache_find_by_id(id_list->clients, &client_id, &list))
485 *clients = silc_realloc(*clients,
486 (silc_list_count(list) + *clients_count) *
489 silc_list_start(list);
490 while ((id_cache = silc_list_get(list)))
491 (*clients)[(*clients_count)++] = id_cache->context;
493 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
498 /* Finds client by Client ID */
501 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
502 SilcBool registered, SilcIDCacheEntry *ret_entry)
504 SilcIDCacheEntry id_cache = NULL;
505 SilcClientEntry client;
510 SILC_LOG_DEBUG(("Client ID (%s)",
511 silc_id_render(id, SILC_ID_CLIENT)));
513 /* Find the exact client with the exact Client ID */
514 if (!silc_idcache_find_by_id_one(id_list->clients, (void *)id, &id_cache))
517 client = (SilcClientEntry)id_cache->context;
519 if (client && registered &&
520 !(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
524 *ret_entry = id_cache;
526 SILC_LOG_DEBUG(("Found"));
531 /* Replaces old Client ID with new one */
534 silc_idlist_replace_client_id(SilcServer server,
535 SilcIDList id_list, SilcClientID *old_id,
536 SilcClientID *new_id, const char *nickname)
538 SilcIDCacheEntry id_cache = NULL;
539 SilcClientEntry client;
540 char *nicknamec = NULL;
542 if (!old_id || !new_id)
545 SILC_LOG_DEBUG(("Replacing Client ID"));
547 /* Normalize name. This is cached, original is in client context. */
549 nicknamec = silc_identifier_check(nickname, strlen(nickname),
550 SILC_STRING_UTF8, 128, NULL);
555 /* Find exact client with exact Client ID */
556 if (!silc_idcache_find_by_id_one(id_list->clients, old_id, &id_cache))
559 client = (SilcClientEntry)id_cache->context;
561 /* Remove the old entry and add a new one */
563 if (!silc_idcache_del_by_context(id_list->clients, client, server))
566 /* Check if anyone is watching old nickname */
567 if (server->server_type == SILC_ROUTER)
568 silc_server_check_watcher_list(server, client, nickname,
569 SILC_NOTIFY_TYPE_NICK_CHANGE);
571 silc_free(client->nickname);
572 *client->id = *new_id;
573 client->nickname = nickname ? strdup(nickname) : NULL;
575 /* Check if anyone is watching new nickname */
576 if (server->server_type == SILC_ROUTER)
577 silc_server_check_watcher_list(server, client, nickname,
578 SILC_NOTIFY_TYPE_NICK_CHANGE);
580 if (!silc_idcache_add(id_list->clients, nicknamec, client->id,
584 SILC_LOG_DEBUG(("Replaced"));
590 /******************************************************************************
592 Channel entry functions
594 ******************************************************************************/
596 /* Add new channel entry. This add the new channel entry to the ID cache
597 system and returns the allocated entry or NULL on error. */
600 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
601 SilcChannelID *id, SilcServerEntry router,
602 SilcCipher send_key, SilcCipher receive_key,
605 SilcChannelEntry channel;
606 char *channel_namec = NULL;
608 SILC_LOG_DEBUG(("Adding new channel %s", channel_name));
610 /* Normalize name. This is cached, original is in client context. */
612 channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
613 SILC_STRING_UTF8, 256, NULL);
618 channel = silc_calloc(1, sizeof(*channel));
619 channel->channel_name = channel_name;
620 channel->mode = mode;
622 channel->router = router;
623 channel->send_key = send_key;
624 channel->receive_key = receive_key;
625 channel->hmac = hmac;
626 channel->created = channel->updated = time(0);
628 if (!silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac)) {
633 channel->user_list = silc_hash_table_alloc(3, silc_hash_ptr, NULL, NULL,
634 NULL, NULL, NULL, TRUE);
636 if (!silc_idcache_add(id_list->channels, channel_namec,
637 (void *)channel->id, (void *)channel /*XXX, expire */)) {
638 silc_hmac_free(channel->hmac);
639 silc_hash_table_free(channel->user_list);
641 silc_free(channel_namec);
648 /* Foreach callbcak to free all users from the channel when deleting a
651 static void silc_idlist_del_channel_foreach(void *key, void *context,
654 SilcChannelClientEntry chl = (SilcChannelClientEntry)context;
656 SILC_LOG_DEBUG(("Removing client %s from channel %s",
657 chl->client->nickname ? chl->client->nickname :
658 (unsigned char *)"", chl->channel->channel_name));
660 /* Remove the context from the client's channel hash table as that
661 table and channel's user_list hash table share this same context. */
662 silc_hash_table_del(chl->client->channels, chl->channel);
666 /* Free channel entry. This free's everything. */
668 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
671 /* Remove from cache */
672 if (!silc_idcache_del_by_context(id_list->channels, entry, NULL)) {
673 SILC_LOG_DEBUG(("Unknown channel, did not delete"));
677 SILC_LOG_DEBUG(("Deleting channel %s", entry->channel_name));
679 /* Free all client entrys from the users list. The silc_hash_table_free
680 will free all the entries so they are not freed at the foreach
682 silc_hash_table_foreach(entry->user_list, silc_idlist_del_channel_foreach,
684 silc_hash_table_free(entry->user_list);
687 silc_free(entry->channel_name);
688 silc_free(entry->id);
689 silc_free(entry->topic);
691 if (entry->invite_list)
692 silc_hash_table_free(entry->invite_list);
694 silc_hash_table_free(entry->ban_list);
697 silc_cipher_free(entry->send_key);
698 if (entry->receive_key)
699 silc_cipher_free(entry->receive_key);
701 memset(entry->key, 0, entry->key_len / 8);
702 silc_free(entry->key);
704 silc_free(entry->cipher);
706 silc_hmac_free(entry->hmac);
707 silc_free(entry->hmac_name);
708 silc_free(entry->rekey);
709 if (entry->founder_key)
710 silc_pkcs_public_key_free(entry->founder_key);
711 if (entry->channel_pubkeys)
712 silc_hash_table_free(entry->channel_pubkeys);
714 memset(entry, 'F', sizeof(*entry));
722 /* Finds channel by channel name. Channel names are unique and they
723 are not case-sensitive. The 'name' must be normalized already. */
726 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
727 SilcIDCacheEntry *ret_entry)
729 SilcIDCacheEntry id_cache = NULL;
731 SILC_LOG_DEBUG(("Channel by name %s", name));
733 if (!silc_idcache_find_by_name_one(id_list->channels, name, &id_cache))
737 *ret_entry = id_cache;
739 SILC_LOG_DEBUG(("Found"));
742 ((SilcChannelEntry)id_cache->context)->updated = time(NULL);
744 return id_cache->context;
747 /* Finds channel by Channel ID. */
750 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
751 SilcIDCacheEntry *ret_entry)
753 SilcIDCacheEntry id_cache = NULL;
754 SilcChannelEntry channel;
759 SILC_LOG_DEBUG(("Channel ID (%s)",
760 silc_id_render(id, SILC_ID_CHANNEL)));
762 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, &id_cache))
765 channel = (SilcChannelEntry)id_cache->context;
768 *ret_entry = id_cache;
770 SILC_LOG_DEBUG(("Found"));
773 channel->updated = time(NULL);
778 /* Replaces old Channel ID with new one. This is done when router forces
779 normal server to change Channel ID. */
782 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
783 SilcChannelID *new_id)
785 SilcIDCacheEntry id_cache = NULL;
786 SilcChannelEntry channel;
789 if (!old_id || !new_id)
792 SILC_LOG_DEBUG(("Replacing Channel ID"));
794 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
798 channel = (SilcChannelEntry)id_cache->context;
799 name = strdup(id_cache->name);
801 /* Remove the old entry and add a new one */
803 silc_idcache_del_by_id(id_list->channels, (void *)channel->id, NULL);
804 *channel->id = *new_id;
805 silc_idcache_add(id_list->channels, name, channel->id, channel);
807 SILC_LOG_DEBUG(("Replaced"));
810 channel->updated = time(NULL);
815 /* Returns channels from the ID list. If the `channel_id' is NULL then
816 all channels are returned. */
819 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
820 SilcUInt32 *channels_count)
823 SilcIDCacheEntry id_cache = NULL;
824 SilcChannelEntry *channels = NULL;
827 SILC_LOG_DEBUG(("Start"));
830 if (!silc_idcache_get_all(id_list->channels, &list))
833 channels = silc_calloc(silc_list_count(list), sizeof(*channels));
836 silc_list_start(list);
837 while ((id_cache = silc_list_get(list)))
838 channels[i++] = (SilcChannelEntry)id_cache->context;
840 if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache))
844 channels = silc_calloc(1, sizeof(*channels));
845 channels[0] = (SilcChannelEntry)id_cache->context;