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);
58 if (idata->public_key)
59 silc_pkcs_public_key_free(idata->public_key);
62 idata->public_key = NULL;
65 /******************************************************************************
67 Server entry functions
69 ******************************************************************************/
71 /* Add new server entry. This adds the new server entry to ID cache and
72 returns the allocated entry object or NULL on error. This is called
73 when new server connects to us. We also add ourselves to cache with
77 silc_idlist_add_server(SilcIDList id_list,
78 char *server_name, int server_type,
79 SilcServerID *id, SilcServerEntry router,
82 SilcServerEntry server;
83 char *server_namec = NULL;
85 SILC_LOG_DEBUG(("Adding new server entry"));
87 /* Normalize name. This is cached, original is in server context. */
89 server_namec = silc_identifier_check(server_name, strlen(server_name),
90 SILC_STRING_UTF8, 256, NULL);
95 server = silc_calloc(1, sizeof(*server));
96 server->server_name = server_name;
97 server->server_type = server_type;
99 server->router = router;
100 server->connection = connection;
102 if (!silc_idcache_add(id_list->servers, server_namec,
103 (void *)server->id, (void *)server)) {
105 silc_free(server_namec);
112 /* Finds server by Server ID */
115 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
116 SilcBool registered, SilcIDCacheEntry *ret_entry)
118 SilcIDCacheEntry id_cache = NULL;
119 SilcServerEntry server;
124 SILC_LOG_DEBUG(("Server ID (%s)",
125 silc_id_render(id, SILC_ID_SERVER)));
127 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id, &id_cache))
130 server = (SilcServerEntry)id_cache->context;
132 if (server && registered &&
133 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
137 *ret_entry = id_cache;
139 SILC_LOG_DEBUG(("Found"));
144 /* Find server by name. The 'name' must be normalized already. */
147 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
149 SilcIDCacheEntry *ret_entry)
151 SilcIDCacheEntry id_cache = NULL;
152 SilcServerEntry server;
154 SILC_LOG_DEBUG(("Server by name `%s'", name));
156 if (!silc_idcache_find_by_name_one(id_list->servers, name, &id_cache))
159 server = (SilcServerEntry)id_cache->context;
161 if (server && registered &&
162 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
166 *ret_entry = id_cache;
168 SILC_LOG_DEBUG(("Found"));
173 /* Find server by connection parameters, hostname and port */
176 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
177 int port, SilcBool registered,
178 SilcIDCacheEntry *ret_entry)
181 SilcIDCacheEntry id_cache = NULL;
182 SilcServerEntry server = NULL;
183 SilcPacketStream sock;
184 const char *host = NULL, *ip = NULL;
186 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
188 if (!silc_idcache_get_all(id_list->servers, &list))
191 silc_list_start(list);
192 while ((id_cache = silc_list_get(list))) {
193 server = id_cache->context;
194 sock = server->connection;
196 if (sock && silc_socket_stream_get_info(
197 silc_packet_stream_get_stream(sock),
198 NULL, &host, &ip, NULL)) {
199 if (((host && !strcasecmp(host, hostname)) ||
200 (ip && !strcasecmp(ip, hostname))) &&
201 server->id->port == SILC_SWAB_16(port))
209 if (server && registered &&
210 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
214 *ret_entry = id_cache;
216 SILC_LOG_DEBUG(("Found"));
221 /* Replaces old Server ID with new one */
224 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
225 SilcServerID *new_id)
227 SilcIDCacheEntry id_cache = NULL;
228 SilcServerEntry server;
231 if (!old_id || !new_id)
234 SILC_LOG_DEBUG(("Replacing Server ID"));
236 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id, &id_cache))
239 server = (SilcServerEntry)id_cache->context;
240 name = strdup(id_cache->name);
242 /* Remove the old entry and add a new one */
244 silc_idcache_del_by_id(id_list->servers, (void *)server->id, NULL);
245 *server->id = *new_id;
246 silc_idcache_add(id_list->servers, name, server->id, server);
248 SILC_LOG_DEBUG(("Found"));
253 /* Removes and free's server entry from ID list */
255 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
258 /* Remove from cache */
259 if (!silc_idcache_del_by_context(id_list->servers, entry, NULL)) {
260 SILC_LOG_DEBUG(("Unknown server, did not delete"));
264 SILC_LOG_DEBUG(("Deleting server %s id %s", entry->server_name ?
265 entry->server_name : "",
267 silc_id_render(entry->id, SILC_ID_SERVER) : ""));
270 silc_free(entry->server_name);
271 silc_free(entry->id);
272 silc_free(entry->server_info);
274 memset(entry, 'F', sizeof(*entry));
282 /* ID Cache destructor */
284 void silc_idlist_server_destructor(SilcIDCache cache,
285 SilcIDCacheEntry entry,
289 silc_free(entry->name);
292 /******************************************************************************
294 Client entry functions
296 ******************************************************************************/
298 /* Add new client entry. This adds the client entry to ID cache system
299 and returns the allocated client entry or NULL on error. This is
300 called when new client connection is accepted to the server. If The
301 `router' is provided then the all server routines assume that the client
302 is not directly connected local client but it has router set and is
303 remote. If this is the case then `connection' must be NULL. If, on the
304 other hand, the `connection' is provided then the client is assumed
305 to be directly connected local client and `router' must be NULL. */
308 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
309 char *userinfo, SilcClientID *id,
310 SilcServerEntry router, void *connection)
312 SilcClientEntry client;
313 char *nicknamec = NULL;
315 SILC_LOG_DEBUG(("Adding new client entry"));
317 /* Normalize name. This is cached, original is in client context. */
319 nicknamec = silc_identifier_check(nickname, strlen(nickname),
320 SILC_STRING_UTF8, 128, NULL);
325 /* Check username. */
327 char u[128 + 1], h[256 + 1];
330 ret = silc_parse_userfqdn(username, u, sizeof(u), h, sizeof(h));
333 if (!silc_identifier_verify(u, strlen(u), SILC_STRING_UTF8, 128))
335 if (ret > 1 && !silc_identifier_verify(h, strlen(h),
336 SILC_STRING_UTF8, 256))
340 client = silc_calloc(1, sizeof(*client));
341 client->nickname = nickname;
342 client->username = username ? strdup(username) : NULL;
343 client->userinfo = userinfo;
345 client->router = router;
346 client->connection = connection;
347 client->channels = silc_hash_table_alloc(3, silc_hash_ptr, NULL,
348 NULL, NULL, NULL, NULL, TRUE);
350 if (!silc_idcache_add(id_list->clients, nicknamec, (void *)client->id,
352 silc_hash_table_free(client->channels);
354 silc_free(nicknamec);
361 /* Free client entry. This free's everything and removes the entry
362 from ID cache. Call silc_idlist_del_data before calling this one. */
364 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
366 SILC_LOG_DEBUG(("Delete client %p", entry));
369 /* Delete client, destructor will free data */
370 if (!silc_idcache_del_by_context(id_list->clients, entry, NULL)) {
371 SILC_LOG_DEBUG(("Unknown client, did not delete"));
380 /* ID Cache destructor */
382 void silc_idlist_client_destructor(SilcIDCache cache,
383 SilcIDCacheEntry entry,
387 SilcServer server = dest_context;
388 SilcClientEntry client;
390 client = (SilcClientEntry)entry->context;
392 /* Remove client's public key from repository, this will free it too. */
393 if (client->data.public_key)
394 silc_skr_del_public_key(server->repository, client->data.public_key,
397 assert(!silc_hash_table_count(client->channels));
398 silc_free(client->nickname);
399 silc_free(client->servername);
400 silc_free(client->username);
401 silc_free(client->userinfo);
402 silc_free(client->id);
403 silc_free(client->attrs);
404 silc_hash_table_free(client->channels);
406 memset(client, 'A', sizeof(*client));
411 /* Returns all clients matching requested nickname. Number of clients is
412 returned to `clients_count'. Caller must free the returned table.
413 The 'nickname' must be normalized already. */
415 int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
417 SilcClientEntry **clients,
418 SilcUInt32 *clients_count)
421 SilcIDCacheEntry id_cache = NULL;
423 SILC_LOG_DEBUG(("Start"));
425 if (!silc_idcache_find_by_name(id_list->clients, nickname, &list))
428 *clients = silc_realloc(*clients,
429 (silc_list_count(list) + *clients_count) *
432 silc_list_start(list);
433 while ((id_cache = silc_list_get(list)))
434 (*clients)[(*clients_count)++] = id_cache->context;
436 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
441 /* Returns all clients matching requested nickname hash. Number of clients
442 is returned to `clients_count'. Caller must free the returned table.
443 The 'nickname' must be normalized already. */
445 int silc_idlist_get_clients_by_hash(SilcIDList id_list,
446 char *nickname, char *server,
448 SilcClientEntry **clients,
449 SilcUInt32 *clients_count)
452 SilcIDCacheEntry id_cache = NULL;
453 unsigned char hash[SILC_HASH_MAXLEN];
454 SilcClientID client_id;
455 SilcClientEntry client_entry;
457 SILC_LOG_DEBUG(("Start"));
459 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
461 /* As the Client ID is hashed in the ID cache by hashing only the hash
462 from the Client ID, we can do a lookup with only the hash not the
463 other parts of the ID and get all the clients with that hash, ie.
464 with that nickname, as the hash is from the nickname. */
465 memset(&client_id, 0, sizeof(client_id));
466 memcpy(&client_id.hash, hash, sizeof(client_id.hash));
467 if (!silc_idcache_find_by_id(id_list->clients, &client_id, &list))
470 /* If server is specified, narrow the search with it. */
472 silc_list_start(list);
473 while ((id_cache = silc_list_get(list))) {
474 client_entry = id_cache->context;
475 if (!client_entry->servername)
477 if (!silc_utf8_strcasecmp(client_entry->servername, server))
478 silc_list_del(list, id_cache);
482 if (!silc_list_count(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 /* Check if anyone is watching old nickname */
562 if (server->server_type == SILC_ROUTER)
563 silc_server_check_watcher_list(server, client, nickname,
564 SILC_NOTIFY_TYPE_NICK_CHANGE);
567 if (!silc_idcache_update(id_list->clients, id_cache, new_id, nicknamec,
571 silc_free(client->nickname);
572 client->nickname = nickname ? strdup(nickname) : NULL;
574 /* Check if anyone is watching new nickname */
575 if (server->server_type == SILC_ROUTER)
576 silc_server_check_watcher_list(server, client, nickname,
577 SILC_NOTIFY_TYPE_NICK_CHANGE);
579 SILC_LOG_DEBUG(("Replaced"));
585 /******************************************************************************
587 Channel entry functions
589 ******************************************************************************/
591 /* Add new channel entry. This add the new channel entry to the ID cache
592 system and returns the allocated entry or NULL on error. */
595 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
596 SilcChannelID *id, SilcServerEntry router,
597 SilcCipher send_key, SilcCipher receive_key,
600 SilcChannelEntry channel;
601 char *channel_namec = NULL;
603 SILC_LOG_DEBUG(("Adding new channel %s", channel_name));
605 /* Normalize name. This is cached, original is in client context. */
607 channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
608 SILC_STRING_UTF8, 256, NULL);
613 channel = silc_calloc(1, sizeof(*channel));
614 channel->channel_name = channel_name;
615 channel->mode = mode;
617 channel->router = router;
618 channel->send_key = send_key;
619 channel->receive_key = receive_key;
620 channel->hmac = hmac;
621 channel->created = channel->updated = time(0);
623 if (!silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac)) {
628 channel->user_list = silc_hash_table_alloc(3, silc_hash_ptr, NULL, NULL,
629 NULL, NULL, NULL, TRUE);
631 if (!silc_idcache_add(id_list->channels, channel_namec,
632 (void *)channel->id, (void *)channel)) {
633 silc_hmac_free(channel->hmac);
634 silc_hash_table_free(channel->user_list);
636 silc_free(channel_namec);
643 /* ID Cache destructor */
645 void silc_idlist_channel_destructor(SilcIDCache cache,
646 SilcIDCacheEntry entry,
650 silc_free(entry->name);
653 /* Foreach callbcak to free all users from the channel when deleting a
656 static void silc_idlist_del_channel_foreach(void *key, void *context,
659 SilcChannelClientEntry chl = (SilcChannelClientEntry)context;
661 SILC_LOG_DEBUG(("Removing client %s from channel %s",
662 chl->client->nickname ? chl->client->nickname :
663 (unsigned char *)"", chl->channel->channel_name));
665 /* Remove the context from the client's channel hash table as that
666 table and channel's user_list hash table share this same context. */
667 silc_hash_table_del(chl->client->channels, chl->channel);
671 /* Free channel entry. This free's everything. */
673 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
676 /* Remove from cache */
677 if (!silc_idcache_del_by_context(id_list->channels, entry, NULL)) {
678 SILC_LOG_DEBUG(("Unknown channel, did not delete"));
682 SILC_LOG_DEBUG(("Deleting channel %s", entry->channel_name));
684 /* Free all client entrys from the users list. The silc_hash_table_free
685 will free all the entries so they are not freed at the foreach
687 silc_hash_table_foreach(entry->user_list, silc_idlist_del_channel_foreach,
689 silc_hash_table_free(entry->user_list);
692 silc_free(entry->channel_name);
693 silc_free(entry->id);
694 silc_free(entry->topic);
696 if (entry->invite_list)
697 silc_hash_table_free(entry->invite_list);
699 silc_hash_table_free(entry->ban_list);
702 silc_cipher_free(entry->send_key);
703 if (entry->receive_key)
704 silc_cipher_free(entry->receive_key);
706 memset(entry->key, 0, entry->key_len / 8);
707 silc_free(entry->key);
709 silc_free(entry->cipher);
711 silc_hmac_free(entry->hmac);
712 silc_free(entry->hmac_name);
713 silc_free(entry->rekey);
714 if (entry->founder_key)
715 silc_pkcs_public_key_free(entry->founder_key);
716 if (entry->channel_pubkeys)
717 silc_hash_table_free(entry->channel_pubkeys);
719 memset(entry, 'F', sizeof(*entry));
727 /* Finds channel by channel name. Channel names are unique and they
728 are not case-sensitive. The 'name' must be normalized already. */
731 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
732 SilcIDCacheEntry *ret_entry)
734 SilcIDCacheEntry id_cache = NULL;
736 SILC_LOG_DEBUG(("Channel by name %s", name));
738 if (!silc_idcache_find_by_name_one(id_list->channels, name, &id_cache))
742 *ret_entry = id_cache;
744 SILC_LOG_DEBUG(("Found"));
747 ((SilcChannelEntry)id_cache->context)->updated = time(NULL);
749 return id_cache->context;
752 /* Finds channel by Channel ID. */
755 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
756 SilcIDCacheEntry *ret_entry)
758 SilcIDCacheEntry id_cache = NULL;
759 SilcChannelEntry channel;
764 SILC_LOG_DEBUG(("Channel ID (%s)",
765 silc_id_render(id, SILC_ID_CHANNEL)));
767 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, &id_cache))
770 channel = (SilcChannelEntry)id_cache->context;
773 *ret_entry = id_cache;
775 SILC_LOG_DEBUG(("Found"));
778 channel->updated = time(NULL);
783 /* Replaces old Channel ID with new one. This is done when router forces
784 normal server to change Channel ID. */
787 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
788 SilcChannelID *new_id)
790 SilcIDCacheEntry id_cache = NULL;
791 SilcChannelEntry channel;
794 if (!old_id || !new_id)
797 SILC_LOG_DEBUG(("Replacing Channel ID"));
799 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
803 channel = (SilcChannelEntry)id_cache->context;
804 name = strdup(id_cache->name);
806 /* Remove the old entry and add a new one */
808 silc_idcache_del_by_id(id_list->channels, (void *)channel->id, NULL);
809 *channel->id = *new_id;
810 silc_idcache_add(id_list->channels, name, channel->id, channel);
812 SILC_LOG_DEBUG(("Replaced"));
815 channel->updated = time(NULL);
820 /* Returns channels from the ID list. If the `channel_id' is NULL then
821 all channels are returned. */
824 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
825 SilcUInt32 *channels_count)
828 SilcIDCacheEntry id_cache = NULL;
829 SilcChannelEntry *channels = NULL;
832 SILC_LOG_DEBUG(("Start"));
835 if (!silc_idcache_get_all(id_list->channels, &list))
838 channels = silc_calloc(silc_list_count(list), sizeof(*channels));
841 silc_list_start(list);
842 while ((id_cache = silc_list_get(list)))
843 channels[i++] = (SilcChannelEntry)id_cache->context;
845 if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache))
849 channels = silc_calloc(1, sizeof(*channels));
850 channels[0] = (SilcChannelEntry)id_cache->context;