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 /* 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;