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,
165 SilcBool registered, SilcIDCacheEntry *ret_entry)
167 SilcIDCacheEntry id_cache = NULL;
168 SilcServerEntry server;
170 SILC_LOG_DEBUG(("Server by name `%s'", name));
172 if (!silc_idcache_find_by_name_one(id_list->servers, name, &id_cache))
175 server = (SilcServerEntry)id_cache->context;
177 if (server && registered &&
178 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
182 *ret_entry = id_cache;
184 SILC_LOG_DEBUG(("Found"));
189 /* Find server by connection parameters, hostname and port */
192 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
193 int port, SilcBool registered,
194 SilcIDCacheEntry *ret_entry)
197 SilcIDCacheEntry id_cache = NULL;
198 SilcServerEntry server = NULL;
199 SilcPacketStream sock;
200 const char *host = NULL, *ip = NULL;
202 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
204 if (!silc_idcache_get_all(id_list->servers, &list))
207 silc_list_start(list);
208 while ((id_cache = silc_list_get(list))) {
209 server = id_cache->context;
210 sock = server->connection;
212 if (sock && silc_socket_stream_get_info(
213 silc_packet_stream_get_stream(sock),
214 NULL, &host, &ip, NULL)) {
215 if (((host && !strcasecmp(host, hostname)) ||
216 (ip && !strcasecmp(ip, hostname))) &&
217 server->id->port == SILC_SWAB_16(port))
225 if (server && registered &&
226 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
230 *ret_entry = id_cache;
232 SILC_LOG_DEBUG(("Found"));
237 /* Replaces old Server ID with new one */
240 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
241 SilcServerID *new_id)
243 SilcIDCacheEntry id_cache = NULL;
244 SilcServerEntry server;
247 if (!old_id || !new_id)
250 SILC_LOG_DEBUG(("Replacing Server ID"));
252 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id, &id_cache))
255 server = (SilcServerEntry)id_cache->context;
256 name = strdup(id_cache->name);
258 /* Remove the old entry and add a new one */
260 silc_idcache_del_by_id(id_list->servers, (void *)server->id, NULL);
261 *server->id = *new_id;
262 silc_idcache_add(id_list->servers, name, server->id, server);
264 SILC_LOG_DEBUG(("Found"));
269 /* Removes and free's server entry from ID list */
271 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
274 /* Remove from cache */
275 if (!silc_idcache_del_by_context(id_list->servers, entry, NULL)) {
276 SILC_LOG_DEBUG(("Unknown server, did not delete"));
280 SILC_LOG_DEBUG(("Deleting server %s id %s", entry->server_name ?
281 entry->server_name : "",
283 silc_id_render(entry->id, SILC_ID_SERVER) : ""));
286 silc_free(entry->server_name);
287 silc_free(entry->id);
288 silc_free(entry->server_info);
290 memset(entry, 'F', sizeof(*entry));
298 /******************************************************************************
300 Client entry functions
302 ******************************************************************************/
304 /* Add new client entry. This adds the client entry to ID cache system
305 and returns the allocated client entry or NULL on error. This is
306 called when new client connection is accepted to the server. If The
307 `router' is provided then the all server routines assume that the client
308 is not directly connected local client but it has router set and is
309 remote. If this is the case then `connection' must be NULL. If, on the
310 other hand, the `connection' is provided then the client is assumed
311 to be directly connected local client and `router' must be NULL. */
314 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
315 char *userinfo, SilcClientID *id,
316 SilcServerEntry router, void *connection)
318 SilcClientEntry client;
319 char *nicknamec = NULL;
321 SILC_LOG_DEBUG(("Adding new client entry"));
323 /* Normalize name. This is cached, original is in client context. */
325 nicknamec = silc_identifier_check(nickname, strlen(nickname),
326 SILC_STRING_UTF8, 128, NULL);
331 /* Check username. */
333 char u[128 + 1], h[256 + 1];
336 ret = silc_parse_userfqdn(username, u, sizeof(u), h, sizeof(h));
339 if (!silc_identifier_verify(u, strlen(u), SILC_STRING_UTF8, 128))
341 if (ret > 1 && !silc_identifier_verify(h, strlen(h),
342 SILC_STRING_UTF8, 256))
346 client = silc_calloc(1, sizeof(*client));
347 client->nickname = nickname;
348 client->username = username ? strdup(username) : NULL;
349 client->userinfo = userinfo;
351 client->router = router;
352 client->connection = connection;
353 client->channels = silc_hash_table_alloc(3, silc_hash_ptr, NULL,
354 NULL, NULL, NULL, NULL, TRUE);
356 if (!silc_idcache_add(id_list->clients, nicknamec, (void *)client->id,
358 silc_hash_table_free(client->channels);
360 silc_free(nicknamec);
367 /* Free client entry. This free's everything and removes the entry
368 from ID cache. Call silc_idlist_del_data before calling this one. */
370 int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry)
372 SILC_LOG_DEBUG(("Start"));
375 /* Delete client, destructor will free data */
376 if (!silc_idcache_del_by_context(id_list->clients, entry, NULL)) {
377 SILC_LOG_DEBUG(("Unknown client, did not delete"));
386 /* ID Cache destructor */
388 void silc_idlist_client_destructor(SilcIDCache cache,
389 SilcIDCacheEntry entry,
393 SilcServer server = app_context;
394 SilcClientEntry client;
396 client = (SilcClientEntry)entry->context;
398 /* Remove this client from the public key hash list */
399 if (client->data.public_key)
400 silc_hash_table_del_by_context(server->pk_hash,
401 client->data.public_key, client);
403 assert(!silc_hash_table_count(client->channels));
404 silc_free(client->nickname);
405 silc_free(client->servername);
406 silc_free(client->username);
407 silc_free(client->userinfo);
408 silc_free(client->id);
409 silc_free(client->attrs);
410 if (client->data.public_key)
411 silc_pkcs_public_key_free(client->data.public_key);
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, char *nickname,
455 SilcClientEntry **clients,
456 SilcUInt32 *clients_count)
459 SilcIDCacheEntry id_cache = NULL;
460 unsigned char hash[SILC_HASH_MAXLEN];
461 SilcClientID client_id;
463 SILC_LOG_DEBUG(("Start"));
465 silc_hash_make(md5hash, nickname, strlen(nickname), hash);
467 /* As the Client ID is hashed in the ID cache by hashing only the hash
468 from the Client ID, we can do a lookup with only the hash not the
469 other parts of the ID and get all the clients with that hash, ie.
470 with that nickname, as the hash is from the nickname. */
471 memset(&client_id, 0, sizeof(client_id));
472 memcpy(&client_id.hash, hash, sizeof(client_id.hash));
473 if (!silc_idcache_find_by_id(id_list->clients, &client_id, &list))
476 *clients = silc_realloc(*clients,
477 (silc_list_count(list) + *clients_count) *
480 silc_list_start(list);
481 while ((id_cache = silc_list_get(list)))
482 (*clients)[(*clients_count)++] = id_cache->context;
484 SILC_LOG_DEBUG(("Found total %d clients", *clients_count));
489 /* Finds client by Client ID */
492 silc_idlist_find_client_by_id(SilcIDList id_list, SilcClientID *id,
493 SilcBool registered, SilcIDCacheEntry *ret_entry)
495 SilcIDCacheEntry id_cache = NULL;
496 SilcClientEntry client;
501 SILC_LOG_DEBUG(("Client ID (%s)",
502 silc_id_render(id, SILC_ID_CLIENT)));
504 /* Find the exact client with the exact Client ID */
505 if (!silc_idcache_find_by_id_one(id_list->clients, (void *)id, &id_cache))
508 client = (SilcClientEntry)id_cache->context;
510 if (client && registered &&
511 !(client->data.status & SILC_IDLIST_STATUS_REGISTERED))
515 *ret_entry = id_cache;
517 SILC_LOG_DEBUG(("Found"));
522 /* Replaces old Client ID with new one */
525 silc_idlist_replace_client_id(SilcServer server,
526 SilcIDList id_list, SilcClientID *old_id,
527 SilcClientID *new_id, const char *nickname)
529 SilcIDCacheEntry id_cache = NULL;
530 SilcClientEntry client;
531 char *nicknamec = NULL;
533 if (!old_id || !new_id)
536 SILC_LOG_DEBUG(("Replacing Client ID"));
538 /* Normalize name. This is cached, original is in client context. */
540 nicknamec = silc_identifier_check(nickname, strlen(nickname),
541 SILC_STRING_UTF8, 128, NULL);
546 /* Find exact client with exact Client ID */
547 if (!silc_idcache_find_by_id_one(id_list->clients, old_id, &id_cache))
550 client = (SilcClientEntry)id_cache->context;
552 /* Remove the old entry and add a new one */
554 if (!silc_idcache_del_by_context(id_list->clients, client, server))
557 /* Check if anyone is watching old nickname */
558 if (server->server_type == SILC_ROUTER)
559 silc_server_check_watcher_list(server, client, nickname,
560 SILC_NOTIFY_TYPE_NICK_CHANGE);
562 silc_free(client->nickname);
563 *client->id = *new_id;
564 client->nickname = nickname ? strdup(nickname) : NULL;
566 /* Check if anyone is watching new nickname */
567 if (server->server_type == SILC_ROUTER)
568 silc_server_check_watcher_list(server, client, nickname,
569 SILC_NOTIFY_TYPE_NICK_CHANGE);
571 if (!silc_idcache_add(id_list->clients, nicknamec, client->id,
575 SILC_LOG_DEBUG(("Replaced"));
581 /******************************************************************************
583 Channel entry functions
585 ******************************************************************************/
587 /* Add new channel entry. This add the new channel entry to the ID cache
588 system and returns the allocated entry or NULL on error. */
591 silc_idlist_add_channel(SilcIDList id_list, char *channel_name, int mode,
592 SilcChannelID *id, SilcServerEntry router,
593 SilcCipher send_key, SilcCipher receive_key,
596 SilcChannelEntry channel;
597 char *channel_namec = NULL;
599 SILC_LOG_DEBUG(("Adding new channel %s", channel_name));
601 /* Normalize name. This is cached, original is in client context. */
603 channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
604 SILC_STRING_UTF8, 256, NULL);
609 channel = silc_calloc(1, sizeof(*channel));
610 channel->channel_name = channel_name;
611 channel->mode = mode;
613 channel->router = router;
614 channel->send_key = send_key;
615 channel->receive_key = receive_key;
616 channel->hmac = hmac;
617 channel->created = channel->updated = time(0);
619 if (!silc_hmac_alloc(SILC_DEFAULT_HMAC, NULL, &channel->hmac)) {
624 channel->user_list = silc_hash_table_alloc(3, silc_hash_ptr, NULL, NULL,
625 NULL, NULL, NULL, TRUE);
627 if (!silc_idcache_add(id_list->channels, channel_namec,
628 (void *)channel->id, (void *)channel /*XXX, expire */)) {
629 silc_hmac_free(channel->hmac);
630 silc_hash_table_free(channel->user_list);
632 silc_free(channel_namec);
639 /* Foreach callbcak to free all users from the channel when deleting a
642 static void silc_idlist_del_channel_foreach(void *key, void *context,
645 SilcChannelClientEntry chl = (SilcChannelClientEntry)context;
647 SILC_LOG_DEBUG(("Removing client %s from channel %s",
648 chl->client->nickname ? chl->client->nickname :
649 (unsigned char *)"", chl->channel->channel_name));
651 /* Remove the context from the client's channel hash table as that
652 table and channel's user_list hash table share this same context. */
653 silc_hash_table_del(chl->client->channels, chl->channel);
657 /* Free channel entry. This free's everything. */
659 int silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
662 /* Remove from cache */
663 if (!silc_idcache_del_by_context(id_list->channels, entry, NULL)) {
664 SILC_LOG_DEBUG(("Unknown channel, did not delete"));
668 SILC_LOG_DEBUG(("Deleting channel %s", entry->channel_name));
670 /* Free all client entrys from the users list. The silc_hash_table_free
671 will free all the entries so they are not freed at the foreach
673 silc_hash_table_foreach(entry->user_list, silc_idlist_del_channel_foreach,
675 silc_hash_table_free(entry->user_list);
678 silc_free(entry->channel_name);
679 silc_free(entry->id);
680 silc_free(entry->topic);
682 if (entry->invite_list)
683 silc_hash_table_free(entry->invite_list);
685 silc_hash_table_free(entry->ban_list);
688 silc_cipher_free(entry->send_key);
689 if (entry->receive_key)
690 silc_cipher_free(entry->receive_key);
692 memset(entry->key, 0, entry->key_len / 8);
693 silc_free(entry->key);
695 silc_free(entry->cipher);
697 silc_hmac_free(entry->hmac);
698 silc_free(entry->hmac_name);
699 silc_free(entry->rekey);
700 if (entry->founder_key)
701 silc_pkcs_public_key_free(entry->founder_key);
702 if (entry->channel_pubkeys)
703 silc_hash_table_free(entry->channel_pubkeys);
705 memset(entry, 'F', sizeof(*entry));
713 /* Finds channel by channel name. Channel names are unique and they
714 are not case-sensitive. The 'name' must be normalized already. */
717 silc_idlist_find_channel_by_name(SilcIDList id_list, char *name,
718 SilcIDCacheEntry *ret_entry)
720 SilcIDCacheEntry id_cache = NULL;
722 SILC_LOG_DEBUG(("Channel by name %s", name));
724 if (!silc_idcache_find_by_name_one(id_list->channels, name, &id_cache))
728 *ret_entry = id_cache;
730 SILC_LOG_DEBUG(("Found"));
733 ((SilcChannelEntry)id_cache->context)->updated = time(NULL);
735 return id_cache->context;
738 /* Finds channel by Channel ID. */
741 silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id,
742 SilcIDCacheEntry *ret_entry)
744 SilcIDCacheEntry id_cache = NULL;
745 SilcChannelEntry channel;
750 SILC_LOG_DEBUG(("Channel ID (%s)",
751 silc_id_render(id, SILC_ID_CHANNEL)));
753 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)id, &id_cache))
756 channel = (SilcChannelEntry)id_cache->context;
759 *ret_entry = id_cache;
761 SILC_LOG_DEBUG(("Found"));
764 channel->updated = time(NULL);
769 /* Replaces old Channel ID with new one. This is done when router forces
770 normal server to change Channel ID. */
773 silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
774 SilcChannelID *new_id)
776 SilcIDCacheEntry id_cache = NULL;
777 SilcChannelEntry channel;
780 if (!old_id || !new_id)
783 SILC_LOG_DEBUG(("Replacing Channel ID"));
785 if (!silc_idcache_find_by_id_one(id_list->channels, (void *)old_id,
789 channel = (SilcChannelEntry)id_cache->context;
790 name = strdup(id_cache->name);
792 /* Remove the old entry and add a new one */
794 silc_idcache_del_by_id(id_list->channels, (void *)channel->id, NULL);
795 *channel->id = *new_id;
796 silc_idcache_add(id_list->channels, name, channel->id, channel);
798 SILC_LOG_DEBUG(("Replaced"));
801 channel->updated = time(NULL);
806 /* Returns channels from the ID list. If the `channel_id' is NULL then
807 all channels are returned. */
810 silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
811 SilcUInt32 *channels_count)
814 SilcIDCacheEntry id_cache = NULL;
815 SilcChannelEntry *channels = NULL;
818 SILC_LOG_DEBUG(("Start"));
821 if (!silc_idcache_get_all(id_list->channels, &list))
824 channels = silc_calloc(silc_list_count(list), sizeof(*channels));
827 silc_list_start(list);
828 while ((id_cache = silc_list_get(list)))
829 channels[i++] = (SilcChannelEntry)id_cache->context;
831 if (!silc_idcache_find_by_id_one(id_list->channels, channel_id, &id_cache))
835 channels = silc_calloc(1, sizeof(*channels));
836 channels[0] = (SilcChannelEntry)id_cache->context;