5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 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);
59 silc_ske_free_rekey_material(idata->rekey);
63 idata->public_key = NULL;
66 /******************************************************************************
68 Server entry functions
70 ******************************************************************************/
72 /* Add new server entry. This adds the new server entry to ID cache and
73 returns the allocated entry object or NULL on error. This is called
74 when new server connects to us. We also add ourselves to cache with
78 silc_idlist_add_server(SilcIDList id_list,
79 char *server_name, int server_type,
80 SilcServerID *id, SilcServerEntry router,
83 SilcServerEntry server;
84 char *server_namec = NULL;
86 SILC_LOG_DEBUG(("Adding new server entry"));
88 /* Normalize name. This is cached, original is in server context. */
90 server_namec = silc_identifier_check(server_name, strlen(server_name),
91 SILC_STRING_UTF8, 256, NULL);
96 server = silc_calloc(1, sizeof(*server));
97 server->server_name = server_name;
98 server->server_type = server_type;
100 server->router = router;
101 server->connection = connection;
103 if (!silc_idcache_add(id_list->servers, server_namec,
104 (void *)server->id, (void *)server)) {
106 silc_free(server_namec);
113 /* Finds server by Server ID */
116 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
117 SilcBool registered, SilcIDCacheEntry *ret_entry)
119 SilcIDCacheEntry id_cache = NULL;
120 SilcServerEntry server;
125 SILC_LOG_DEBUG(("Server ID (%s)",
126 silc_id_render(id, SILC_ID_SERVER)));
128 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id, &id_cache))
131 server = (SilcServerEntry)id_cache->context;
133 if (server && registered &&
134 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
138 *ret_entry = id_cache;
140 SILC_LOG_DEBUG(("Found"));
145 /* Find server by name. The 'name' must be normalized already. */
148 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
150 SilcIDCacheEntry *ret_entry)
152 SilcIDCacheEntry id_cache = NULL;
153 SilcServerEntry server;
155 SILC_LOG_DEBUG(("Server by name `%s'", name));
157 if (!silc_idcache_find_by_name_one(id_list->servers, name, &id_cache))
160 server = (SilcServerEntry)id_cache->context;
162 if (server && registered &&
163 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
167 *ret_entry = id_cache;
169 SILC_LOG_DEBUG(("Found"));
174 /* Find server by connection parameters, hostname and port */
177 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
178 int port, SilcBool registered,
179 SilcIDCacheEntry *ret_entry)
182 SilcIDCacheEntry id_cache = NULL;
183 SilcServerEntry server = NULL;
184 SilcPacketStream sock;
185 const char *host = NULL, *ip = NULL;
187 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
189 if (!silc_idcache_get_all(id_list->servers, &list))
192 silc_list_start(list);
193 while ((id_cache = silc_list_get(list))) {
194 server = id_cache->context;
195 sock = server->connection;
197 if (sock && silc_socket_stream_get_info(
198 silc_packet_stream_get_stream(sock),
199 NULL, &host, &ip, NULL)) {
200 if (((host && !strcasecmp(host, hostname)) ||
201 (ip && !strcasecmp(ip, hostname))) &&
202 server->id->port == SILC_SWAB_16(port))
210 if (server && registered &&
211 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
215 *ret_entry = id_cache;
217 SILC_LOG_DEBUG(("Found"));
222 /* Replaces old Server ID with new one */
225 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
226 SilcServerID *new_id)
228 SilcIDCacheEntry id_cache = NULL;
229 SilcServerEntry server;
232 if (!old_id || !new_id)
235 SILC_LOG_DEBUG(("Replacing Server ID"));
237 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id, &id_cache))
240 server = (SilcServerEntry)id_cache->context;
241 name = strdup(id_cache->name);
243 /* Remove the old entry and add a new one */
245 silc_idcache_del_by_id(id_list->servers, (void *)server->id, NULL);
246 *server->id = *new_id;
247 silc_idcache_add(id_list->servers, name, server->id, server);
249 SILC_LOG_DEBUG(("Found"));
254 /* Removes and free's server entry from ID list */
256 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
259 /* Remove from cache */
260 if (!silc_idcache_del_by_context(id_list->servers, entry, NULL)) {
261 SILC_LOG_DEBUG(("Unknown server, did not delete"));
265 SILC_LOG_DEBUG(("Deleting server %s id %s", entry->server_name ?
266 entry->server_name : "",
268 silc_id_render(entry->id, SILC_ID_SERVER) : ""));
271 silc_free(entry->server_name);
272 silc_free(entry->id);
273 silc_free(entry->server_info);
275 memset(entry, 'F', sizeof(*entry));
283 /* ID Cache destructor */
285 void silc_idlist_server_destructor(SilcIDCache cache,
286 SilcIDCacheEntry entry,
290 silc_free(entry->name);
293 /******************************************************************************
295 Client entry functions
297 ******************************************************************************/
299 /* Add new client entry. This adds the client entry to ID cache system
300 and returns the allocated client entry or NULL on error. This is
301 called when new client connection is accepted to the server. If The
302 `router' is provided then the all server routines assume that the client
303 is not directly connected local client but it has router set and is
304 remote. If this is the case then `connection' must be NULL. If, on the
305 other hand, the `connection' is provided then the client is assumed
306 to be directly connected local client and `router' must be NULL. */
309 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
310 char *userinfo, SilcClientID *id,
311 SilcServerEntry router, void *connection)
313 SilcClientEntry client;
314 char *nicknamec = NULL;
316 SILC_LOG_DEBUG(("Adding new client entry"));
318 /* Normalize name. This is cached, original is in client context. */
320 nicknamec = silc_identifier_check(nickname, strlen(nickname),
321 SILC_STRING_UTF8, 128, NULL);
326 /* Check username. */
328 char u[128 + 1], h[256 + 1];
331 ret = silc_parse_userfqdn(username, u, sizeof(u), h, sizeof(h));
334 if (!silc_identifier_verify(u, strlen(u), SILC_STRING_UTF8, 128))
336 if (ret > 1 && !silc_identifier_verify(h, strlen(h),
337 SILC_STRING_UTF8, 256))
341 client = silc_calloc(1, sizeof(*client));
344 client->nickname = nickname;
345 client->username = username ? strdup(username) : NULL;
346 client->userinfo = userinfo;
348 client->router = router;
349 client->connection = connection;
350 client->channels = silc_hash_table_alloc(3, silc_hash_ptr, NULL,
351 NULL, NULL, NULL, NULL, TRUE);
353 if (!silc_idcache_add(id_list->clients, nicknamec, (void *)client->id,
355 silc_hash_table_free(client->channels);
357 silc_free(nicknamec);
364 /* Free client entry. This free's everything and removes the entry
365 from ID cache. Call silc_idlist_del_data before calling this one. */
367 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
369 SILC_LOG_DEBUG(("Delete client %p", entry));
372 /* Delete client, destructor will free data */
373 if (!silc_idcache_del_by_context(id_list->clients, entry, NULL)) {
374 SILC_LOG_DEBUG(("Unknown client, did not delete"));
383 /* ID Cache destructor */
385 void silc_idlist_client_destructor(SilcIDCache cache,
386 SilcIDCacheEntry entry,
390 SilcServer server = dest_context;
391 SilcClientEntry client;
393 client = (SilcClientEntry)entry->context;
395 /* Remove client's public key from repository, this will free it too. */
396 if (client->data.public_key)
397 silc_skr_del_public_key(server->repository, client->data.public_key,
400 assert(!silc_hash_table_count(client->channels));
401 silc_free(entry->name);
402 silc_free(client->nickname);
403 silc_free(client->servername);
404 silc_free(client->username);
405 silc_free(client->userinfo);
406 silc_free(client->id);
407 silc_free(client->attrs);
408 silc_hash_table_free(client->channels);
410 memset(client, 'A', sizeof(*client));
415 /* Returns all clients matching requested nickname. Number of clients is
416 returned to `clients_count'. Caller must free the returned table.
417 The 'nickname' must be normalized already. */
419 int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
421 SilcClientEntry **clients,
422 SilcUInt32 *clients_count)
425 SilcIDCacheEntry id_cache = NULL;
427 SILC_LOG_DEBUG(("Start"));
429 if (!silc_idcache_find_by_name(id_list->clients, nickname, &list))
432 *clients = silc_realloc(*clients,
433 (silc_list_count(list) + *clients_count) *
436 silc_list_start(list);
437 while ((id_cache = silc_list_get(list)))
438 (*clients)[(*clients_count)++] = id_cache->context;
440 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
445 /* Returns all clients matching requested nickname hash. Number of clients
446 is returned to `clients_count'. Caller must free the returned table.
447 The 'nickname' must be normalized already. */
449 int silc_idlist_get_clients_by_hash(SilcIDList id_list,
450 char *nickname, char *server,
452 SilcClientEntry **clients,
453 SilcUInt32 *clients_count)
456 SilcIDCacheEntry id_cache = NULL;
457 unsigned char hash[SILC_HASH_MAXLEN];
458 SilcClientID client_id;
459 SilcClientEntry client_entry;
461 SILC_LOG_DEBUG(("Start"));
463 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
465 /* As the Client ID is hashed in the ID cache by hashing only the hash
466 from the Client ID, we can do a lookup with only the hash not the
467 other parts of the ID and get all the clients with that hash, ie.
468 with that nickname, as the hash is from the nickname. */
469 memset(&client_id, 0, sizeof(client_id));
470 memcpy(&client_id.hash, hash, sizeof(client_id.hash));
471 if (!silc_idcache_find_by_id(id_list->clients, &client_id, &list))
474 /* If server is specified, narrow the search with it. */
476 silc_list_start(list);
477 while ((id_cache = silc_list_get(list))) {
478 client_entry = id_cache->context;
479 if (!client_entry->servername)
481 if (!silc_utf8_strcasecmp(client_entry->servername, server))
482 silc_list_del(list, id_cache);
486 if (!silc_list_count(list))
489 *clients = silc_realloc(*clients,
490 (silc_list_count(list) + *clients_count) *
493 silc_list_start(list);
494 while ((id_cache = silc_list_get(list)))
495 (*clients)[(*clients_count)++] = id_cache->context;
497 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
502 /* Finds client by Client ID */
505 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
506 SilcBool registered, SilcIDCacheEntry *ret_entry)
508 SilcIDCacheEntry id_cache = NULL;
509 SilcClientEntry client;
514 SILC_LOG_DEBUG(("Client ID (%s)",
515 silc_id_render(id, SILC_ID_CLIENT)));
517 /* Find the exact client with the exact Client ID */
518 if (!silc_idcache_find_by_id_one(id_list->clients, (void *)id, &id_cache))
521 client = (SilcClientEntry)id_cache->context;
523 if (client && registered &&
524 !(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
528 *ret_entry = id_cache;
530 SILC_LOG_DEBUG(("Found"));
535 /* Replaces old Client ID with new one */
538 silc_idlist_replace_client_id(SilcServer server,
539 SilcIDList id_list, SilcClientID *old_id,
540 SilcClientID *new_id, const char *nickname)
542 SilcIDCacheEntry id_cache = NULL;
543 SilcClientEntry client;
544 char *nicknamec = NULL;
546 if (!old_id || !new_id)
549 SILC_LOG_DEBUG(("Replacing Client ID"));
551 /* Normalize name. This is cached, original is in client context. */
553 nicknamec = silc_identifier_check(nickname, strlen(nickname),
554 SILC_STRING_UTF8, 128, NULL);
559 /* Find exact client with exact Client ID */
560 if (!silc_idcache_find_by_id_one(id_list->clients, old_id, &id_cache))
563 client = (SilcClientEntry)id_cache->context;
565 /* Check if anyone is watching old nickname */
566 if (server->server_type == SILC_ROUTER)
567 silc_server_check_watcher_list(server, client, nickname,
568 SILC_NOTIFY_TYPE_NICK_CHANGE);
571 if (!silc_idcache_update(id_list->clients, id_cache, new_id, nicknamec,
575 silc_free(client->nickname);
576 client->nickname = nickname ? strdup(nickname) : NULL;
578 /* Check if anyone is watching new nickname */
579 if (server->server_type == SILC_ROUTER)
580 silc_server_check_watcher_list(server, client, nickname,
581 SILC_NOTIFY_TYPE_NICK_CHANGE);
583 SILC_LOG_DEBUG(("Replaced"));
589 /******************************************************************************
591 Channel entry functions
593 ******************************************************************************/
595 /* Add new channel entry. This add the new channel entry to the ID cache
596 system and returns the allocated entry or NULL on error. */
599 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
600 SilcChannelID *id, SilcServerEntry router,
601 SilcCipher send_key, SilcCipher receive_key,
604 SilcChannelEntry channel;
605 char *channel_namec = NULL;
607 SILC_LOG_DEBUG(("Adding new channel %s", channel_name));
609 /* Normalize name. This is cached, original is in client context. */
611 channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
612 SILC_STRING_UTF8, 256, NULL);
617 channel = silc_calloc(1, sizeof(*channel));
618 channel->channel_name = channel_name;
619 channel->mode = mode;
621 channel->router = router;
622 channel->send_key = send_key;
623 channel->receive_key = receive_key;
624 channel->hmac = hmac;
625 channel->created = channel->updated = time(0);
627 if (!silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac)) {
632 channel->user_list = silc_hash_table_alloc(3, silc_hash_ptr, NULL, NULL,
633 NULL, NULL, NULL, TRUE);
635 if (!silc_idcache_add(id_list->channels, channel_namec,
636 (void *)channel->id, (void *)channel)) {
637 silc_hmac_free(channel->hmac);
638 silc_hash_table_free(channel->user_list);
640 silc_free(channel_namec);
647 /* ID Cache destructor */
649 void silc_idlist_channel_destructor(SilcIDCache cache,
650 SilcIDCacheEntry entry,
654 silc_free(entry->name);
657 /* Foreach callbcak to free all users from the channel when deleting a
660 static void silc_idlist_del_channel_foreach(void *key, void *context,
663 SilcChannelClientEntry chl = (SilcChannelClientEntry)context;
665 SILC_LOG_DEBUG(("Removing client %s from channel %s",
666 chl->client->nickname ? chl->client->nickname :
667 (unsigned char *)"", chl->channel->channel_name));
669 /* Remove the context from the client's channel hash table as that
670 table and channel's user_list hash table share this same context. */
671 silc_hash_table_del(chl->client->channels, chl->channel);
675 /* Free channel entry. This free's everything. */
677 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
680 /* Remove from cache */
681 if (!silc_idcache_del_by_context(id_list->channels, entry, NULL)) {
682 SILC_LOG_DEBUG(("Unknown channel, did not delete"));
686 SILC_LOG_DEBUG(("Deleting channel %s", entry->channel_name));
688 /* Free all client entrys from the users list. The silc_hash_table_free
689 will free all the entries so they are not freed at the foreach
691 silc_hash_table_foreach(entry->user_list, silc_idlist_del_channel_foreach,
693 silc_hash_table_free(entry->user_list);
696 silc_free(entry->channel_name);
697 silc_free(entry->id);
698 silc_free(entry->topic);
700 if (entry->invite_list)
701 silc_hash_table_free(entry->invite_list);
703 silc_hash_table_free(entry->ban_list);
706 silc_cipher_free(entry->send_key);
707 if (entry->receive_key)
708 silc_cipher_free(entry->receive_key);
710 memset(entry->key, 0, entry->key_len / 8);
711 silc_free(entry->key);
713 silc_free(entry->cipher);
715 silc_hmac_free(entry->hmac);
716 silc_free(entry->hmac_name);
717 silc_free(entry->rekey);
718 if (entry->founder_key)
719 silc_pkcs_public_key_free(entry->founder_key);
720 if (entry->channel_pubkeys)
721 silc_hash_table_free(entry->channel_pubkeys);
723 memset(entry, 'F', sizeof(*entry));
731 /* Finds channel by channel name. Channel names are unique and they
732 are not case-sensitive. The 'name' must be normalized already. */
735 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
736 SilcIDCacheEntry *ret_entry)
738 SilcIDCacheEntry id_cache = NULL;
740 SILC_LOG_DEBUG(("Channel by name %s", name));
742 if (!silc_idcache_find_by_name_one(id_list->channels, name, &id_cache))
746 *ret_entry = id_cache;
748 SILC_LOG_DEBUG(("Found"));
751 ((SilcChannelEntry)id_cache->context)->updated = time(NULL);
753 return id_cache->context;
756 /* Finds channel by Channel ID. */
759 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
760 SilcIDCacheEntry *ret_entry)
762 SilcIDCacheEntry id_cache = NULL;
763 SilcChannelEntry channel;
768 SILC_LOG_DEBUG(("Channel ID (%s)",
769 silc_id_render(id, SILC_ID_CHANNEL)));
771 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, &id_cache))
774 channel = (SilcChannelEntry)id_cache->context;
777 *ret_entry = id_cache;
779 SILC_LOG_DEBUG(("Found"));
782 channel->updated = time(NULL);
787 /* Replaces old Channel ID with new one. This is done when router forces
788 normal server to change Channel ID. */
791 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
792 SilcChannelID *new_id)
794 SilcIDCacheEntry id_cache = NULL;
795 SilcChannelEntry channel;
798 if (!old_id || !new_id)
801 SILC_LOG_DEBUG(("Replacing Channel ID"));
803 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
807 channel = (SilcChannelEntry)id_cache->context;
808 name = strdup(id_cache->name);
810 /* Remove the old entry and add a new one */
812 silc_idcache_del_by_id(id_list->channels, (void *)channel->id, NULL);
813 *channel->id = *new_id;
814 silc_idcache_add(id_list->channels, name, channel->id, channel);
816 SILC_LOG_DEBUG(("Replaced"));
819 channel->updated = time(NULL);
824 /* Returns channels from the ID list. If the `channel_id' is NULL then
825 all channels are returned. */
828 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
829 SilcUInt32 *channels_count)
832 SilcIDCacheEntry id_cache = NULL;
833 SilcChannelEntry *channels = NULL;
836 SILC_LOG_DEBUG(("Start"));
839 if (!silc_idcache_get_all(id_list->channels, &list))
842 channels = silc_calloc(silc_list_count(list), sizeof(*channels));
845 silc_list_start(list);
846 while ((id_cache = silc_list_get(list)))
847 channels[i++] = (SilcChannelEntry)id_cache->context;
849 if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache))
853 channels = silc_calloc(1, sizeof(*channels));
854 channels[0] = (SilcChannelEntry)id_cache->context;