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->conn_type = idata->conn_type;
39 data->sconn = idata->sconn;
40 data->hash = idata->hash;
41 data->public_key = idata->public_key;
42 memcpy(data->fingerprint, idata->fingerprint, sizeof(data->fingerprint));
43 data->rekey = idata->rekey;
44 data->last_receive = idata->last_receive;
45 data->last_sent = idata->last_sent;
46 data->status = idata->status;
47 data->created = time(0); /* Update creation time */
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;
57 silc_hash_free(idata->hash);
58 if (idata->public_key)
59 silc_pkcs_public_key_free(idata->public_key);
62 idata->public_key = NULL;
67 SILC_TASK_CALLBACK(silc_idlist_purge)
69 SilcServer server = app_context;
70 SilcIDListPurge i = (SilcIDListPurge)context;
72 SILC_LOG_DEBUG(("Purging cache"));
76 silc_idcache_purge(i->cache);
77 silc_schedule_task_add_timeout(server->schedule, silc_idlist_purge, i,
82 /******************************************************************************
84 Server entry functions
86 ******************************************************************************/
88 /* Add new server entry. This adds the new server entry to ID cache and
89 returns the allocated entry object or NULL on error. This is called
90 when new server connects to us. We also add ourselves to cache with
94 silc_idlist_add_server(SilcIDList id_list,
95 char *server_name, int server_type,
96 SilcServerID *id, SilcServerEntry router,
99 SilcServerEntry server;
100 char *server_namec = NULL;
102 SILC_LOG_DEBUG(("Adding new server entry"));
104 /* Normalize name. This is cached, original is in server context. */
106 server_namec = silc_identifier_check(server_name, strlen(server_name),
107 SILC_STRING_UTF8, 256, NULL);
112 server = silc_calloc(1, sizeof(*server));
113 server->server_name = server_name;
114 server->server_type = server_type;
116 server->router = router;
117 server->connection = connection;
119 if (!silc_idcache_add(id_list->servers, server_namec,
120 (void *)server->id, (void *)server)) {
122 silc_free(server_namec);
129 /* Finds server by Server ID */
132 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
133 SilcBool registered, SilcIDCacheEntry *ret_entry)
135 SilcIDCacheEntry id_cache = NULL;
136 SilcServerEntry server;
141 SILC_LOG_DEBUG(("Server ID (%s)",
142 silc_id_render(id, SILC_ID_SERVER)));
144 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id, &id_cache))
147 server = (SilcServerEntry)id_cache->context;
149 if (server && registered &&
150 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
154 *ret_entry = id_cache;
156 SILC_LOG_DEBUG(("Found"));
161 /* Find server by name. The 'name' must be normalized already. */
164 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
166 SilcIDCacheEntry *ret_entry)
168 SilcIDCacheEntry id_cache = NULL;
169 SilcServerEntry server;
171 SILC_LOG_DEBUG(("Server by name `%s'", name));
173 if (!silc_idcache_find_by_name_one(id_list->servers, name, &id_cache))
176 server = (SilcServerEntry)id_cache->context;
178 if (server && registered &&
179 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
183 *ret_entry = id_cache;
185 SILC_LOG_DEBUG(("Found"));
190 /* Find server by connection parameters, hostname and port */
193 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
194 int port, SilcBool registered,
195 SilcIDCacheEntry *ret_entry)
198 SilcIDCacheEntry id_cache = NULL;
199 SilcServerEntry server = NULL;
200 SilcPacketStream sock;
201 const char *host = NULL, *ip = NULL;
203 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
205 if (!silc_idcache_get_all(id_list->servers, &list))
208 silc_list_start(list);
209 while ((id_cache = silc_list_get(list))) {
210 server = id_cache->context;
211 sock = server->connection;
213 if (sock && silc_socket_stream_get_info(
214 silc_packet_stream_get_stream(sock),
215 NULL, &host, &ip, NULL)) {
216 if (((host && !strcasecmp(host, hostname)) ||
217 (ip && !strcasecmp(ip, hostname))) &&
218 server->id->port == SILC_SWAB_16(port))
226 if (server && registered &&
227 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
231 *ret_entry = id_cache;
233 SILC_LOG_DEBUG(("Found"));
238 /* Replaces old Server ID with new one */
241 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
242 SilcServerID *new_id)
244 SilcIDCacheEntry id_cache = NULL;
245 SilcServerEntry server;
248 if (!old_id || !new_id)
251 SILC_LOG_DEBUG(("Replacing Server ID"));
253 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id, &id_cache))
256 server = (SilcServerEntry)id_cache->context;
257 name = strdup(id_cache->name);
259 /* Remove the old entry and add a new one */
261 silc_idcache_del_by_id(id_list->servers, (void *)server->id, NULL);
262 *server->id = *new_id;
263 silc_idcache_add(id_list->servers, name, server->id, server);
265 SILC_LOG_DEBUG(("Found"));
270 /* Removes and free's server entry from ID list */
272 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
275 /* Remove from cache */
276 if (!silc_idcache_del_by_context(id_list->servers, entry, NULL)) {
277 SILC_LOG_DEBUG(("Unknown server, did not delete"));
281 SILC_LOG_DEBUG(("Deleting server %s id %s", entry->server_name ?
282 entry->server_name : "",
284 silc_id_render(entry->id, SILC_ID_SERVER) : ""));
287 silc_free(entry->server_name);
288 silc_free(entry->id);
289 silc_free(entry->server_info);
291 memset(entry, 'F', sizeof(*entry));
299 /* ID Cache destructor */
301 void silc_idlist_server_destructor(SilcIDCache cache,
302 SilcIDCacheEntry entry,
306 silc_free(entry->name);
309 /******************************************************************************
311 Client entry functions
313 ******************************************************************************/
315 /* Add new client entry. This adds the client entry to ID cache system
316 and returns the allocated client entry or NULL on error. This is
317 called when new client connection is accepted to the server. If The
318 `router' is provided then the all server routines assume that the client
319 is not directly connected local client but it has router set and is
320 remote. If this is the case then `connection' must be NULL. If, on the
321 other hand, the `connection' is provided then the client is assumed
322 to be directly connected local client and `router' must be NULL. */
325 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
326 char *userinfo, SilcClientID *id,
327 SilcServerEntry router, void *connection)
329 SilcClientEntry client;
330 char *nicknamec = NULL;
332 SILC_LOG_DEBUG(("Adding new client entry"));
334 /* Normalize name. This is cached, original is in client context. */
336 nicknamec = silc_identifier_check(nickname, strlen(nickname),
337 SILC_STRING_UTF8, 128, NULL);
342 /* Check username. */
344 char u[128 + 1], h[256 + 1];
347 ret = silc_parse_userfqdn(username, u, sizeof(u), h, sizeof(h));
350 if (!silc_identifier_verify(u, strlen(u), SILC_STRING_UTF8, 128))
352 if (ret > 1 && !silc_identifier_verify(h, strlen(h),
353 SILC_STRING_UTF8, 256))
357 client = silc_calloc(1, sizeof(*client));
358 client->nickname = nickname;
359 client->username = username ? strdup(username) : NULL;
360 client->userinfo = userinfo;
362 client->router = router;
363 client->connection = connection;
364 client->channels = silc_hash_table_alloc(3, silc_hash_ptr, NULL,
365 NULL, NULL, NULL, NULL, TRUE);
367 if (!silc_idcache_add(id_list->clients, nicknamec, (void *)client->id,
369 silc_hash_table_free(client->channels);
371 silc_free(nicknamec);
378 /* Free client entry. This free's everything and removes the entry
379 from ID cache. Call silc_idlist_del_data before calling this one. */
381 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
383 SILC_LOG_DEBUG(("Start"));
386 /* Delete client, destructor will free data */
387 if (!silc_idcache_del_by_context(id_list->clients, entry, NULL)) {
388 SILC_LOG_DEBUG(("Unknown client, did not delete"));
397 /* ID Cache destructor */
399 void silc_idlist_client_destructor(SilcIDCache cache,
400 SilcIDCacheEntry entry,
404 SilcServer server = dest_context;
405 SilcClientEntry client;
407 client = (SilcClientEntry)entry->context;
409 /* Remove client's public key from repository, this will free it too. */
410 if (client->data.public_key)
411 silc_skr_del_public_key(server->repository, client->data.public_key,
414 assert(!silc_hash_table_count(client->channels));
415 silc_free(client->nickname);
416 silc_free(client->servername);
417 silc_free(client->username);
418 silc_free(client->userinfo);
419 silc_free(client->id);
420 silc_free(client->attrs);
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)) {
638 silc_hmac_free(channel->hmac);
639 silc_hash_table_free(channel->user_list);
641 silc_free(channel_namec);
648 /* ID Cache destructor */
650 void silc_idlist_channel_destructor(SilcIDCache cache,
651 SilcIDCacheEntry entry,
655 silc_free(entry->name);
658 /* Foreach callbcak to free all users from the channel when deleting a
661 static void silc_idlist_del_channel_foreach(void *key, void *context,
664 SilcChannelClientEntry chl = (SilcChannelClientEntry)context;
666 SILC_LOG_DEBUG(("Removing client %s from channel %s",
667 chl->client->nickname ? chl->client->nickname :
668 (unsigned char *)"", chl->channel->channel_name));
670 /* Remove the context from the client's channel hash table as that
671 table and channel's user_list hash table share this same context. */
672 silc_hash_table_del(chl->client->channels, chl->channel);
676 /* Free channel entry. This free's everything. */
678 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
681 /* Remove from cache */
682 if (!silc_idcache_del_by_context(id_list->channels, entry, NULL)) {
683 SILC_LOG_DEBUG(("Unknown channel, did not delete"));
687 SILC_LOG_DEBUG(("Deleting channel %s", entry->channel_name));
689 /* Free all client entrys from the users list. The silc_hash_table_free
690 will free all the entries so they are not freed at the foreach
692 silc_hash_table_foreach(entry->user_list, silc_idlist_del_channel_foreach,
694 silc_hash_table_free(entry->user_list);
697 silc_free(entry->channel_name);
698 silc_free(entry->id);
699 silc_free(entry->topic);
701 if (entry->invite_list)
702 silc_hash_table_free(entry->invite_list);
704 silc_hash_table_free(entry->ban_list);
707 silc_cipher_free(entry->send_key);
708 if (entry->receive_key)
709 silc_cipher_free(entry->receive_key);
711 memset(entry->key, 0, entry->key_len / 8);
712 silc_free(entry->key);
714 silc_free(entry->cipher);
716 silc_hmac_free(entry->hmac);
717 silc_free(entry->hmac_name);
718 silc_free(entry->rekey);
719 if (entry->founder_key)
720 silc_pkcs_public_key_free(entry->founder_key);
721 if (entry->channel_pubkeys)
722 silc_hash_table_free(entry->channel_pubkeys);
724 memset(entry, 'F', sizeof(*entry));
732 /* Finds channel by channel name. Channel names are unique and they
733 are not case-sensitive. The 'name' must be normalized already. */
736 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
737 SilcIDCacheEntry *ret_entry)
739 SilcIDCacheEntry id_cache = NULL;
741 SILC_LOG_DEBUG(("Channel by name %s", name));
743 if (!silc_idcache_find_by_name_one(id_list->channels, name, &id_cache))
747 *ret_entry = id_cache;
749 SILC_LOG_DEBUG(("Found"));
752 ((SilcChannelEntry)id_cache->context)->updated = time(NULL);
754 return id_cache->context;
757 /* Finds channel by Channel ID. */
760 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
761 SilcIDCacheEntry *ret_entry)
763 SilcIDCacheEntry id_cache = NULL;
764 SilcChannelEntry channel;
769 SILC_LOG_DEBUG(("Channel ID (%s)",
770 silc_id_render(id, SILC_ID_CHANNEL)));
772 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, &id_cache))
775 channel = (SilcChannelEntry)id_cache->context;
778 *ret_entry = id_cache;
780 SILC_LOG_DEBUG(("Found"));
783 channel->updated = time(NULL);
788 /* Replaces old Channel ID with new one. This is done when router forces
789 normal server to change Channel ID. */
792 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
793 SilcChannelID *new_id)
795 SilcIDCacheEntry id_cache = NULL;
796 SilcChannelEntry channel;
799 if (!old_id || !new_id)
802 SILC_LOG_DEBUG(("Replacing Channel ID"));
804 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
808 channel = (SilcChannelEntry)id_cache->context;
809 name = strdup(id_cache->name);
811 /* Remove the old entry and add a new one */
813 silc_idcache_del_by_id(id_list->channels, (void *)channel->id, NULL);
814 *channel->id = *new_id;
815 silc_idcache_add(id_list->channels, name, channel->id, channel);
817 SILC_LOG_DEBUG(("Replaced"));
820 channel->updated = time(NULL);
825 /* Returns channels from the ID list. If the `channel_id' is NULL then
826 all channels are returned. */
829 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
830 SilcUInt32 *channels_count)
833 SilcIDCacheEntry id_cache = NULL;
834 SilcChannelEntry *channels = NULL;
837 SILC_LOG_DEBUG(("Start"));
840 if (!silc_idcache_get_all(id_list->channels, &list))
843 channels = silc_calloc(silc_list_count(list), sizeof(*channels));
846 silc_list_start(list);
847 while ((id_cache = silc_list_get(list)))
848 channels[i++] = (SilcChannelEntry)id_cache->context;
850 if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache))
854 channels = silc_calloc(1, sizeof(*channels));
855 channels[0] = (SilcChannelEntry)id_cache->context;