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));
98 silc_free(server_namec);
101 server->server_name = server_name;
102 server->server_type = server_type;
104 server->router = router;
105 server->connection = connection;
107 if (!silc_idcache_add(id_list->servers, server_namec,
108 (void *)server->id, (void *)server)) {
110 silc_free(server_namec);
117 /* Finds server by Server ID */
120 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
121 SilcBool registered, SilcIDCacheEntry *ret_entry)
123 SilcIDCacheEntry id_cache = NULL;
124 SilcServerEntry server;
129 SILC_LOG_DEBUG(("Server ID (%s)",
130 silc_id_render(id, SILC_ID_SERVER)));
132 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id, &id_cache))
135 server = (SilcServerEntry)id_cache->context;
137 if (server && registered &&
138 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
142 *ret_entry = id_cache;
144 SILC_LOG_DEBUG(("Found"));
149 /* Find server by name. The 'name' must be normalized already. */
152 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
154 SilcIDCacheEntry *ret_entry)
156 SilcIDCacheEntry id_cache = NULL;
157 SilcServerEntry server;
159 SILC_LOG_DEBUG(("Server by name `%s'", name));
161 if (!silc_idcache_find_by_name_one(id_list->servers, name, &id_cache))
164 server = (SilcServerEntry)id_cache->context;
166 if (server && registered &&
167 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
171 *ret_entry = id_cache;
173 SILC_LOG_DEBUG(("Found"));
178 /* Find server by connection parameters, hostname and port */
181 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
182 int port, SilcBool registered,
183 SilcIDCacheEntry *ret_entry)
186 SilcIDCacheEntry id_cache = NULL;
187 SilcServerEntry server = NULL;
188 SilcPacketStream sock;
189 const char *host = NULL, *ip = NULL;
191 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
193 if (!silc_idcache_get_all(id_list->servers, &list))
196 silc_list_start(list);
197 while ((id_cache = silc_list_get(list))) {
198 server = id_cache->context;
199 sock = server->connection;
201 if (sock && silc_socket_stream_get_info(
202 silc_packet_stream_get_stream(sock),
203 NULL, &host, &ip, NULL)) {
204 if (((host && !strcasecmp(host, hostname)) ||
205 (ip && !strcasecmp(ip, hostname))) &&
206 server->id->port == SILC_SWAB_16(port))
214 if (server && registered &&
215 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
219 *ret_entry = id_cache;
221 SILC_LOG_DEBUG(("Found"));
226 /* Replaces old Server ID with new one */
229 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
230 SilcServerID *new_id)
232 SilcIDCacheEntry id_cache = NULL;
233 SilcServerEntry server;
236 if (!old_id || !new_id)
239 SILC_LOG_DEBUG(("Replacing Server ID"));
241 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id, &id_cache))
244 server = (SilcServerEntry)id_cache->context;
245 name = strdup(id_cache->name);
247 /* Remove the old entry and add a new one */
249 silc_idcache_del_by_id(id_list->servers, (void *)server->id, NULL);
250 *server->id = *new_id;
251 silc_idcache_add(id_list->servers, name, server->id, server);
253 SILC_LOG_DEBUG(("Found"));
258 /* Removes and free's server entry from ID list */
260 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
263 /* Remove from cache */
264 if (!silc_idcache_del_by_context(id_list->servers, entry, NULL)) {
265 SILC_LOG_DEBUG(("Unknown server, did not delete"));
269 SILC_LOG_DEBUG(("Deleting server %s id %s", entry->server_name ?
270 entry->server_name : "",
272 silc_id_render(entry->id, SILC_ID_SERVER) : ""));
275 silc_free(entry->server_name);
276 silc_free(entry->id);
277 silc_free(entry->server_info);
279 memset(entry, 'F', sizeof(*entry));
287 /* ID Cache destructor */
289 void silc_idlist_server_destructor(SilcIDCache cache,
290 SilcIDCacheEntry entry,
294 silc_free(entry->name);
297 /******************************************************************************
299 Client entry functions
301 ******************************************************************************/
303 /* Add new client entry. This adds the client entry to ID cache system
304 and returns the allocated client entry or NULL on error. This is
305 called when new client connection is accepted to the server. If The
306 `router' is provided then the all server routines assume that the client
307 is not directly connected local client but it has router set and is
308 remote. If this is the case then `connection' must be NULL. If, on the
309 other hand, the `connection' is provided then the client is assumed
310 to be directly connected local client and `router' must be NULL. */
313 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
314 char *userinfo, SilcClientID *id,
315 SilcServerEntry router, void *connection)
317 SilcClientEntry client;
318 char *nicknamec = NULL;
320 SILC_LOG_DEBUG(("Adding new client entry"));
322 /* Normalize name. This is cached, original is in client context. */
324 nicknamec = silc_identifier_check(nickname, strlen(nickname),
325 SILC_STRING_UTF8, 128, NULL);
330 /* Check username. */
332 char u[128 + 1], h[256 + 1];
335 ret = silc_parse_userfqdn(username, u, sizeof(u), h, sizeof(h));
338 if (!silc_identifier_verify(u, strlen(u), SILC_STRING_UTF8, 128))
340 if (ret > 1 && !silc_identifier_verify(h, strlen(h),
341 SILC_STRING_UTF8, 256))
345 client = silc_calloc(1, sizeof(*client));
348 client->nickname = nickname;
349 client->username = username ? strdup(username) : NULL;
350 client->userinfo = userinfo;
352 client->router = router;
353 client->connection = connection;
354 client->channels = silc_hash_table_alloc(3, silc_hash_ptr, NULL,
355 NULL, NULL, NULL, NULL, TRUE);
357 if (!silc_idcache_add(id_list->clients, nicknamec, (void *)client->id,
359 silc_hash_table_free(client->channels);
361 silc_free(nicknamec);
368 /* Free client entry. This free's everything and removes the entry
369 from ID cache. Call silc_idlist_del_data before calling this one. */
371 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
373 SILC_LOG_DEBUG(("Delete client %p", entry));
376 /* Delete client, destructor will free data */
377 if (!silc_idcache_del_by_context(id_list->clients, entry, NULL)) {
378 SILC_LOG_DEBUG(("Unknown client, did not delete"));
387 /* ID Cache destructor */
389 void silc_idlist_client_destructor(SilcIDCache cache,
390 SilcIDCacheEntry entry,
394 SilcServer server = dest_context;
395 SilcClientEntry client;
397 client = (SilcClientEntry)entry->context;
399 /* Remove client's public key from repository, this will free it too. */
400 if (client->data.public_key)
401 silc_skr_del_public_key(server->repository, client->data.public_key,
404 assert(!silc_hash_table_count(client->channels));
405 silc_free(entry->name);
406 silc_free(client->nickname);
407 silc_free(client->servername);
408 silc_free(client->username);
409 silc_free(client->userinfo);
410 silc_free(client->id);
411 silc_free(client->attrs);
412 silc_hash_table_free(client->channels);
414 memset(client, 'A', sizeof(*client));
419 /* Returns all clients matching requested nickname. Number of clients is
420 returned to `clients_count'. Caller must free the returned table.
421 The 'nickname' must be normalized already. */
423 int silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname,
425 SilcClientEntry **clients,
426 SilcUInt32 *clients_count)
429 SilcIDCacheEntry id_cache = NULL;
431 SILC_LOG_DEBUG(("Start"));
433 if (!silc_idcache_find_by_name(id_list->clients, nickname, &list))
436 *clients = silc_realloc(*clients,
437 (silc_list_count(list) + *clients_count) *
440 silc_list_start(list);
441 while ((id_cache = silc_list_get(list)))
442 (*clients)[(*clients_count)++] = id_cache->context;
444 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
449 /* Returns all clients matching requested nickname hash. Number of clients
450 is returned to `clients_count'. Caller must free the returned table.
451 The 'nickname' must be normalized already. */
453 int silc_idlist_get_clients_by_hash(SilcIDList id_list,
454 char *nickname, char *server,
456 SilcClientEntry **clients,
457 SilcUInt32 *clients_count)
460 SilcIDCacheEntry id_cache = NULL;
461 unsigned char hash[SILC_HASH_MAXLEN];
462 SilcClientID client_id;
463 SilcClientEntry client_entry;
465 SILC_LOG_DEBUG(("Start"));
467 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
469 /* As the Client ID is hashed in the ID cache by hashing only the hash
470 from the Client ID, we can do a lookup with only the hash not the
471 other parts of the ID and get all the clients with that hash, ie.
472 with that nickname, as the hash is from the nickname. */
473 memset(&client_id, 0, sizeof(client_id));
474 memcpy(&client_id.hash, hash, sizeof(client_id.hash));
475 if (!silc_idcache_find_by_id(id_list->clients, &client_id, &list))
478 /* If server is specified, narrow the search with it. */
480 silc_list_start(list);
481 while ((id_cache = silc_list_get(list))) {
482 client_entry = id_cache->context;
483 if (!client_entry->servername)
485 if (!silc_utf8_strcasecmp(client_entry->servername, server))
486 silc_list_del(list, id_cache);
490 if (!silc_list_count(list))
493 *clients = silc_realloc(*clients,
494 (silc_list_count(list) + *clients_count) *
497 silc_list_start(list);
498 while ((id_cache = silc_list_get(list)))
499 (*clients)[(*clients_count)++] = id_cache->context;
501 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
506 /* Finds client by Client ID */
509 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
510 SilcBool registered, SilcIDCacheEntry *ret_entry)
512 SilcIDCacheEntry id_cache = NULL;
513 SilcClientEntry client;
518 SILC_LOG_DEBUG(("Client ID (%s)",
519 silc_id_render(id, SILC_ID_CLIENT)));
521 /* Find the exact client with the exact Client ID */
522 if (!silc_idcache_find_by_id_one(id_list->clients, (void *)id, &id_cache))
525 client = (SilcClientEntry)id_cache->context;
527 if (client && registered &&
528 !(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
532 *ret_entry = id_cache;
534 SILC_LOG_DEBUG(("Found"));
539 /* Replaces old Client ID with new one */
542 silc_idlist_replace_client_id(SilcServer server,
543 SilcIDList id_list, SilcClientID *old_id,
544 SilcClientID *new_id, const char *nickname)
546 SilcIDCacheEntry id_cache = NULL;
547 SilcClientEntry client;
548 char *nicknamec = NULL;
550 if (!old_id || !new_id)
553 SILC_LOG_DEBUG(("Replacing Client ID"));
555 /* Normalize name. This is cached, original is in client context. */
557 nicknamec = silc_identifier_check(nickname, strlen(nickname),
558 SILC_STRING_UTF8, 128, NULL);
563 /* Find exact client with exact Client ID */
564 if (!silc_idcache_find_by_id_one(id_list->clients, old_id, &id_cache))
567 client = (SilcClientEntry)id_cache->context;
569 /* Check if anyone is watching old nickname */
570 if (server->server_type == SILC_ROUTER)
571 silc_server_check_watcher_list(server, client, nickname,
572 SILC_NOTIFY_TYPE_NICK_CHANGE);
575 if (!silc_idcache_update(id_list->clients, id_cache, new_id, nicknamec,
579 silc_free(client->nickname);
580 client->nickname = nickname ? strdup(nickname) : NULL;
582 /* Check if anyone is watching new nickname */
583 if (server->server_type == SILC_ROUTER)
584 silc_server_check_watcher_list(server, client, nickname,
585 SILC_NOTIFY_TYPE_NICK_CHANGE);
587 SILC_LOG_DEBUG(("Replaced"));
593 /******************************************************************************
595 Channel entry functions
597 ******************************************************************************/
599 /* Add new channel entry. This add the new channel entry to the ID cache
600 system and returns the allocated entry or NULL on error. */
603 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
604 SilcChannelID *id, SilcServerEntry router,
605 SilcCipher send_key, SilcCipher receive_key,
608 SilcChannelEntry channel;
609 char *channel_namec = NULL;
611 SILC_LOG_DEBUG(("Adding new channel %s", channel_name));
613 /* Normalize name. This is cached, original is in client context. */
615 channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
616 SILC_STRING_UTF8, 256, NULL);
621 channel = silc_calloc(1, sizeof(*channel));
623 silc_free(channel_namec);
626 channel->channel_name = channel_name;
627 channel->mode = mode;
629 channel->router = router;
630 channel->send_key = send_key;
631 channel->receive_key = receive_key;
632 channel->hmac = hmac;
633 channel->created = channel->updated = time(0);
635 if (!silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac)) {
640 channel->user_list = silc_hash_table_alloc(3, silc_hash_ptr, NULL, NULL,
641 NULL, NULL, NULL, TRUE);
643 if (!silc_idcache_add(id_list->channels, channel_namec,
644 (void *)channel->id, (void *)channel)) {
645 silc_hmac_free(channel->hmac);
646 silc_hash_table_free(channel->user_list);
648 silc_free(channel_namec);
655 /* ID Cache destructor */
657 void silc_idlist_channel_destructor(SilcIDCache cache,
658 SilcIDCacheEntry entry,
662 silc_free(entry->name);
665 /* Foreach callbcak to free all users from the channel when deleting a
668 static void silc_idlist_del_channel_foreach(void *key, void *context,
671 SilcChannelClientEntry chl = (SilcChannelClientEntry)context;
673 SILC_LOG_DEBUG(("Removing client %s from channel %s",
674 chl->client->nickname ? chl->client->nickname :
675 (unsigned char *)"", chl->channel->channel_name));
677 /* Remove the context from the client's channel hash table as that
678 table and channel's user_list hash table share this same context. */
679 silc_hash_table_del(chl->client->channels, chl->channel);
683 /* Free channel entry. This free's everything. */
685 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
688 /* Remove from cache */
689 if (!silc_idcache_del_by_context(id_list->channels, entry, NULL)) {
690 SILC_LOG_DEBUG(("Unknown channel, did not delete"));
694 SILC_LOG_DEBUG(("Deleting channel %s", entry->channel_name));
696 /* Free all client entrys from the users list. The silc_hash_table_free
697 will free all the entries so they are not freed at the foreach
699 silc_hash_table_foreach(entry->user_list, silc_idlist_del_channel_foreach,
701 silc_hash_table_free(entry->user_list);
704 silc_free(entry->channel_name);
705 silc_free(entry->id);
706 silc_free(entry->topic);
708 if (entry->invite_list)
709 silc_hash_table_free(entry->invite_list);
711 silc_hash_table_free(entry->ban_list);
714 silc_cipher_free(entry->send_key);
715 if (entry->receive_key)
716 silc_cipher_free(entry->receive_key);
718 memset(entry->key, 0, entry->key_len / 8);
719 silc_free(entry->key);
721 silc_free(entry->cipher);
723 silc_hmac_free(entry->hmac);
724 silc_free(entry->hmac_name);
725 silc_free(entry->rekey);
726 if (entry->founder_key)
727 silc_pkcs_public_key_free(entry->founder_key);
728 if (entry->channel_pubkeys)
729 silc_hash_table_free(entry->channel_pubkeys);
731 memset(entry, 'F', sizeof(*entry));
739 /* Finds channel by channel name. Channel names are unique and they
740 are not case-sensitive. The 'name' must be normalized already. */
743 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
744 SilcIDCacheEntry *ret_entry)
746 SilcIDCacheEntry id_cache = NULL;
748 SILC_LOG_DEBUG(("Channel by name %s", name));
750 if (!silc_idcache_find_by_name_one(id_list->channels, name, &id_cache))
754 *ret_entry = id_cache;
756 SILC_LOG_DEBUG(("Found"));
759 ((SilcChannelEntry)id_cache->context)->updated = time(NULL);
761 return id_cache->context;
764 /* Finds channel by Channel ID. */
767 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
768 SilcIDCacheEntry *ret_entry)
770 SilcIDCacheEntry id_cache = NULL;
771 SilcChannelEntry channel;
776 SILC_LOG_DEBUG(("Channel ID (%s)",
777 silc_id_render(id, SILC_ID_CHANNEL)));
779 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, &id_cache))
782 channel = (SilcChannelEntry)id_cache->context;
785 *ret_entry = id_cache;
787 SILC_LOG_DEBUG(("Found"));
790 channel->updated = time(NULL);
795 /* Replaces old Channel ID with new one. This is done when router forces
796 normal server to change Channel ID. */
799 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
800 SilcChannelID *new_id)
802 SilcIDCacheEntry id_cache = NULL;
803 SilcChannelEntry channel;
806 if (!old_id || !new_id)
809 SILC_LOG_DEBUG(("Replacing Channel ID"));
811 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
815 channel = (SilcChannelEntry)id_cache->context;
816 name = strdup(id_cache->name);
818 /* Remove the old entry and add a new one */
820 silc_idcache_del_by_id(id_list->channels, (void *)channel->id, NULL);
821 *channel->id = *new_id;
822 silc_idcache_add(id_list->channels, name, channel->id, channel);
824 SILC_LOG_DEBUG(("Replaced"));
827 channel->updated = time(NULL);
832 /* Returns channels from the ID list. If the `channel_id' is NULL then
833 all channels are returned. */
836 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
837 SilcUInt32 *channels_count)
840 SilcIDCacheEntry id_cache = NULL;
841 SilcChannelEntry *channels = NULL;
844 SILC_LOG_DEBUG(("Start"));
847 if (!silc_idcache_get_all(id_list->channels, &list))
850 channels = silc_calloc(silc_list_count(list), sizeof(*channels));
855 silc_list_start(list);
856 while ((id_cache = silc_list_get(list)))
857 channels[i++] = (SilcChannelEntry)id_cache->context;
859 if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache))
863 channels = silc_calloc(1, sizeof(*channels));
866 channels[0] = (SilcChannelEntry)id_cache->context;