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);
60 idata->public_key = NULL;
63 /******************************************************************************
65 Server entry functions
67 ******************************************************************************/
69 /* Add new server entry. This adds the new server entry to ID cache and
70 returns the allocated entry object or NULL on error. This is called
71 when new server connects to us. We also add ourselves to cache with
75 silc_idlist_add_server(SilcIDList id_list,
76 char *server_name, int server_type,
77 SilcServerID *id, SilcServerEntry router,
80 SilcServerEntry server;
81 char *server_namec = NULL;
83 SILC_LOG_DEBUG(("Adding new server entry"));
85 /* Normalize name. This is cached, original is in server context. */
87 server_namec = silc_identifier_check(server_name, strlen(server_name),
88 SILC_STRING_UTF8, 256, NULL);
93 server = silc_calloc(1, sizeof(*server));
94 server->server_name = server_name;
95 server->server_type = server_type;
97 server->router = router;
98 server->connection = connection;
100 if (!silc_idcache_add(id_list->servers, server_namec,
101 (void *)server->id, (void *)server)) {
103 silc_free(server_namec);
110 /* Finds server by Server ID */
113 silc_idlist_find_server_by_id(SilcIDList id_list, SilcServerID *id,
114 SilcBool registered, SilcIDCacheEntry *ret_entry)
116 SilcIDCacheEntry id_cache = NULL;
117 SilcServerEntry server;
122 SILC_LOG_DEBUG(("Server ID (%s)",
123 silc_id_render(id, SILC_ID_SERVER)));
125 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)id, &id_cache))
128 server = (SilcServerEntry)id_cache->context;
130 if (server && registered &&
131 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
135 *ret_entry = id_cache;
137 SILC_LOG_DEBUG(("Found"));
142 /* Find server by name. The 'name' must be normalized already. */
145 silc_idlist_find_server_by_name(SilcIDList id_list, char *name,
147 SilcIDCacheEntry *ret_entry)
149 SilcIDCacheEntry id_cache = NULL;
150 SilcServerEntry server;
152 SILC_LOG_DEBUG(("Server by name `%s'", name));
154 if (!silc_idcache_find_by_name_one(id_list->servers, name, &id_cache))
157 server = (SilcServerEntry)id_cache->context;
159 if (server && registered &&
160 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
164 *ret_entry = id_cache;
166 SILC_LOG_DEBUG(("Found"));
171 /* Find server by connection parameters, hostname and port */
174 silc_idlist_find_server_by_conn(SilcIDList id_list, char *hostname,
175 int port, SilcBool registered,
176 SilcIDCacheEntry *ret_entry)
179 SilcIDCacheEntry id_cache = NULL;
180 SilcServerEntry server = NULL;
181 SilcPacketStream sock;
182 const char *host = NULL, *ip = NULL;
184 SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
186 if (!silc_idcache_get_all(id_list->servers, &list))
189 silc_list_start(list);
190 while ((id_cache = silc_list_get(list))) {
191 server = id_cache->context;
192 sock = server->connection;
194 if (sock && silc_socket_stream_get_info(
195 silc_packet_stream_get_stream(sock),
196 NULL, &host, &ip, NULL)) {
197 if (((host && !strcasecmp(host, hostname)) ||
198 (ip && !strcasecmp(ip, hostname))) &&
199 server->id->port == SILC_SWAB_16(port))
207 if (server && registered &&
208 !(server->data.status & SILC_IDLIST_STATUS_REGISTERED))
212 *ret_entry = id_cache;
214 SILC_LOG_DEBUG(("Found"));
219 /* Replaces old Server ID with new one */
222 silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id,
223 SilcServerID *new_id)
225 SilcIDCacheEntry id_cache = NULL;
226 SilcServerEntry server;
229 if (!old_id || !new_id)
232 SILC_LOG_DEBUG(("Replacing Server ID"));
234 if (!silc_idcache_find_by_id_one(id_list->servers, (void *)old_id, &id_cache))
237 server = (SilcServerEntry)id_cache->context;
238 name = strdup(id_cache->name);
240 /* Remove the old entry and add a new one */
242 silc_idcache_del_by_id(id_list->servers, (void *)server->id, NULL);
243 *server->id = *new_id;
244 silc_idcache_add(id_list->servers, name, server->id, server);
246 SILC_LOG_DEBUG(("Found"));
251 /* Removes and free's server entry from ID list */
253 int silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry)
256 /* Remove from cache */
257 if (!silc_idcache_del_by_context(id_list->servers, entry, NULL)) {
258 SILC_LOG_DEBUG(("Unknown server, did not delete"));
262 SILC_LOG_DEBUG(("Deleting server %s id %s", entry->server_name ?
263 entry->server_name : "",
265 silc_id_render(entry->id, SILC_ID_SERVER) : ""));
268 silc_free(entry->server_name);
269 silc_free(entry->id);
270 silc_free(entry->server_info);
272 memset(entry, 'F', sizeof(*entry));
280 /* ID Cache destructor */
282 void silc_idlist_server_destructor(SilcIDCache cache,
283 SilcIDCacheEntry entry,
287 silc_free(entry->name);
290 /******************************************************************************
292 Client entry functions
294 ******************************************************************************/
296 /* Add new client entry. This adds the client entry to ID cache system
297 and returns the allocated client entry or NULL on error. This is
298 called when new client connection is accepted to the server. If The
299 `router' is provided then the all server routines assume that the client
300 is not directly connected local client but it has router set and is
301 remote. If this is the case then `connection' must be NULL. If, on the
302 other hand, the `connection' is provided then the client is assumed
303 to be directly connected local client and `router' must be NULL. */
306 silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
307 char *userinfo, SilcClientID *id,
308 SilcServerEntry router, void *connection)
310 SilcClientEntry client;
311 char *nicknamec = NULL;
313 SILC_LOG_DEBUG(("Adding new client entry"));
315 /* Normalize name. This is cached, original is in client context. */
317 nicknamec = silc_identifier_check(nickname, strlen(nickname),
318 SILC_STRING_UTF8, 128, NULL);
323 /* Check username. */
325 char u[128 + 1], h[256 + 1];
328 ret = silc_parse_userfqdn(username, u, sizeof(u), h, sizeof(h));
331 if (!silc_identifier_verify(u, strlen(u), SILC_STRING_UTF8, 128))
333 if (ret > 1 && !silc_identifier_verify(h, strlen(h),
334 SILC_STRING_UTF8, 256))
338 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;