+++ /dev/null
-/*
-
- server_entry.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 1997 - 2006 Pekka Riikonen
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
-*/
-/* $Id$ */
-
-#include "silc.h"
-#include "silcserver.h"
-#include "server_internal.h"
-
-/* XXX locking missing from routines! */
-
-/************************ Static utility functions **************************/
-
-/* Foreach callbcak to free all users from the channel when deleting a
- channel entry. */
-
-static void silc_server_del_channel_foreach(void *key, void *context,
- void *user_context)
-{
- SilcChannelClientEntry chl = (SilcChannelClientEntry)context;
-
- SILC_LOG_DEBUG(("Removing client %s from channel %s",
- chl->client->nickname ? chl->client->nickname :
- (unsigned char *)"", chl->channel->channel_name));
-
- /* Remove the context from the client's channel hash table as that
- table and channel's user_list hash table share this same context. */
- silc_hash_table_del(chl->client->channels, chl->channel);
- silc_free(chl);
-}
-
-
-/****************************** Server entry ********************************/
-
-void silc_server_destructor_server(SilcIDCache cache,
- const SilcIDCacheEntry entry,
- void *destructor_context,
- void *app_context)
-{
-
-}
-
-/* Adds new server entry to server */
-
-SilcServerEntry silc_server_add_server(SilcServer server,
- const char *server_name,
- SilcServerType server_type,
- SilcServerID *id,
- SilcPacketStream origin)
-{
- SilcServerEntry entry;
- char *server_namec = NULL;
-
- if (!id || !origin)
- return NULL;
-
- entry = silc_calloc(1, sizeof(*entry));
- if (!entry)
- return NULL;
-
- SILC_LOG_DEBUG(("Adding server entry %p %s", entry,
- silc_id_render(id, SILC_ID_SERVER)));
-
- /* Normalize name. This is cached, original is in server context. */
- if (server_name) {
- server_namec = silc_identifier_check(server_name, strlen(server_name),
- SILC_STRING_UTF8, 256, NULL);
- if (!server_namec) {
- silc_free(entry);
- return NULL;
- }
-
- entry->server_name = strdup(server_name);
- if (!server->server_name) {
- silc_free(server_namec);
- silc_free(entry);
- return NULL;
- }
- }
-
- entry->server_type = server_type;
- entry->id = *id;
- entry->stream = origin;
-
- /* Add to cache */
- if (!silc_idcache_add(server->servers, server_namec, &entry->id,
- entry)) {
- silc_free(server_namec);
- silc_free(entry->server_name);
- silc_free(entry);
- return NULL;
- }
-
- /* Take reference of the packet stream */
- silc_packet_stream_ref(origin);
-
- return entry;
-}
-
-/* Delete server entry */
-
-SilcBool silc_server_del_server(SilcServer server, SilcServerEntry entry)
-{
- SILC_LOG_DEBUG(("Deleting server %s id %s", entry->server_name ?
- entry->server_name : "??", &entry->id ?
- silc_id_render(&entry->id, SILC_ID_SERVER) : "??"));
-
- /* Delete */
- if (!silc_idcache_del_by_context(server->servers, entry, NULL)) {
- SILC_LOG_ERROR(("Unknown server %s, could not delete from cache",
- &entry->id ? silc_id_render(&entry->id, SILC_ID_SERVER) :
- "??"));
- return FALSE;
- }
-
- return TRUE;
-}
-
-/* Find server by Server ID */
-
-SilcServerEntry
-silc_server_find_server_by_id(SilcServer server,
- SilcServerID *id,
- SilcBool registered,
- SilcIDCacheEntry *ret_entry)
-{
- SilcIDCacheEntry id_cache = NULL;
- SilcServerEntry entry;
-
- if (!id)
- return NULL;
-
- SILC_LOG_DEBUG(("Find Server ID (%s)",
- silc_id_render(id, SILC_ID_SERVER)));
-
- if (!silc_idcache_find_by_id_one(server->servers, (void *)id,
- &id_cache))
- return NULL;
-
- entry = id_cache->context;
-
- if (entry && registered && !(entry->data.registered))
- return NULL;
-
- if (ret_entry)
- *ret_entry = id_cache;
-
- SILC_LOG_DEBUG(("Found"));
-
- return entry;
-}
-
-/* Find server by name. The 'name' must be normalized already. */
-
-SilcServerEntry
-silc_server_find_server_by_name(SilcServer server, char *name,
- SilcBool registered,
- SilcIDCacheEntry *ret_entry)
-{
- SilcIDCacheEntry id_cache = NULL;
- SilcServerEntry entry;
-
- SILC_LOG_DEBUG(("Find server by name `%s'", name));
-
- if (!silc_idcache_find_by_name_one(server->servers, name, &id_cache))
- return NULL;
-
- entry = id_cache->context;
-
- if (entry && registered && !(entry->data.registered))
- return NULL;
-
- if (ret_entry)
- *ret_entry = id_cache;
-
- SILC_LOG_DEBUG(("Found"));
-
- return entry;
-}
-
-/* Find server by connection parameters, hostname and port */
-
-SilcServerEntry
-silc_server_find_server_by_conn(SilcServer server, char *hostname,
- int port, SilcBool registered,
- SilcIDCacheEntry *ret_entry)
-{
- SilcIDCacheEntry id_cache;
- SilcServerEntry entry;
- SilcStream stream;
- SilcList list;
- const char *h;
- SilcUInt16 p;
-
- SILC_LOG_DEBUG(("Server by hostname %s and port %d", hostname, port));
-
- if (!silc_idcache_get_all(server->servers, &list))
- return NULL;
-
- while ((id_cache = silc_list_get(list)) != SILC_LIST_END) {
- entry = id_cache->context;
- stream = silc_packet_stream_get_stream(entry->stream);
-
- if (entry && registered && !(entry->data.registered))
- continue;
-
- if (silc_socket_stream_get_info(stream, NULL, &h, NULL, &p)) {
- if (silc_utf8_strcasecmp(hostname, h) && p == port)
- break;
- }
- }
- if (!id_cache)
- entry = NULL;
-
- if (ret_entry)
- *ret_entry = id_cache;
-
- SILC_LOG_DEBUG(("Found"));
-
- return entry;
-}
-
-/* Replaces old Server ID with new one */
-
-SilcServerEntry
-silc_server_replace_server_id(SilcServer server, SilcServerID *old_id,
- SilcServerID *new_id)
-{
- SilcIDCacheEntry id_cache = NULL;
-
- if (!old_id || !new_id)
- return NULL;
-
- SILC_LOG_DEBUG(("Replacing Server ID %s",
- silc_id_render(old_id, SILC_ID_SERVER)));
- SILC_LOG_DEBUG(("New Server ID %s",
- silc_id_render(new_id, SILC_ID_SERVER)));
-
- if (!silc_idcache_find_by_id_one(server->servers, old_id, &id_cache))
- return NULL;
- if (!silc_idcache_update(server->servers, id_cache, old_id, new_id,
- NULL, NULL)) {
- SILC_LOG_ERROR(("Error updating Server ID"));
- return NULL;
- }
-
- SILC_LOG_DEBUG(("Replaced"));
-
- return id_cache->context;
-}
-
-
-/****************************** Client entry ********************************/
-
-void silc_server_destructor_client(SilcIDCache cache,
- const SilcIDCacheEntry entry,
- void *destructor_context,
- void *app_context)
-{
-
-}
-
-/* Adds new client to server */
-
-SilcClientEntry silc_server_add_client(SilcServer server,
- const char *nickname,
- const char *username,
- const char *userinfo,
- SilcClientID *id,
- SilcUInt32 mode,
- SilcPacketStream origin)
-{
- SilcClientEntry client;
- char *nicknamec = NULL;
- char u[128], h[256];
- int ret;
-
- if (!id || !origin || !nickname || !username)
- return NULL;
-
- client = silc_calloc(1, sizeof(*client));
- if (!client)
- return NULL;
-
- SILC_LOG_DEBUG(("Adding client entry %p", client));
-
- /* Normalize name. This is cached, original is in client context. */
- nicknamec = silc_identifier_check(nickname, strlen(nickname),
- SILC_STRING_UTF8, 128, NULL);
- if (!nicknamec)
- goto err;
-
- /* Check username */
- ret = silc_parse_userfqdn(username, u, sizeof(u), h, sizeof(h));
- if (!ret)
- goto err;
- if (!silc_identifier_verify(u, strlen(u), SILC_STRING_UTF8, 128))
- goto err;
- if (ret == 2 &&
- !silc_identifier_verify(h, strlen(h), SILC_STRING_UTF8, 256))
- goto err;
-
- client->nickname = strdup(nickname);
- if (!client->nickname)
- goto err;
-
- client->username = strdup(username);
- if (!client->username)
- goto err;
-
- client->userinfo = userinfo ? strdup(userinfo) : NULL;
- if (!client->userinfo)
- goto err;
-
- client->id = *id;
- client->mode = mode;
- client->stream = origin;
-
- client->channels = silc_hash_table_alloc(0, silc_hash_ptr, NULL,
- NULL, NULL, NULL, NULL, TRUE);
- if (!client->channels)
- goto err;
-
- if (!silc_idcache_add(server->clients, nicknamec, (void *)&client->id,
- (void *)client))
- goto err;
-
- /* Take reference of the packet stream */
- silc_packet_stream_ref(origin);
-
- return client;
-
- err:
- if (client->channels)
- silc_hash_table_free(client->channels);
- silc_free(client->nickname);
- silc_free(client->username);
- silc_free(client->userinfo);
- silc_free(client);
- silc_free(nicknamec);
- return NULL;
-}
-
-/* Delete client entry */
-
-SilcBool silc_server_del_client(SilcServer server, SilcClientEntry entry)
-{
- SILC_LOG_DEBUG(("Deleting client %s id %s", entry->nickname ?
- entry->nickname : (unsigned char *)"??", &entry->id ?
- silc_id_render(&entry->id, SILC_ID_CLIENT) : "??"));
-
- /* Delete */
- if (!silc_idcache_del_by_context(server->clients, entry, NULL)) {
- SILC_LOG_ERROR(("Unknown client %s, could not delete from cache",
- &entry->id ? silc_id_render(&entry->id, SILC_ID_CLIENT) :
- "??"));
- return FALSE;
- }
-
- return TRUE;
-}
-
-/* Finds all clients matching the nickanem `nickname'. Returns list of
- SilcIDCacheEntry entries. The `nickname' must be normalized. */
-
-SilcBool silc_server_find_clients(SilcServer server, char *nickname,
- SilcList *list)
-{
- SilcClientID client_id;
- unsigned char hash[16];
-
- SILC_LOG_DEBUG(("Find clients named %s", nickname));
-
- /* Find using Client ID hash, as Client ID is based on the nickname,
- we can find clients quickly using the hash of the nickname. */
- memset(&client_id, 0, sizeof(client_id));
- silc_hash_make(server->md5hash, nickname, strlen(nickname), hash);
- memcpy(client_id.hash, hash, CLIENTID_HASH_LEN);
-
- if (!silc_idcache_find_by_id(server->clients, &client_id, list))
- return FALSE;
-
- SILC_LOG_DEBUG(("Found %d clients", silc_list_count(*list)));
-
- return TRUE;
-}
-
-/* Finds client by Client ID */
-
-SilcClientEntry silc_server_find_client_by_id(SilcServer server,
- SilcClientID *id,
- SilcBool registered,
- SilcIDCacheEntry *ret_entry)
-{
- SilcIDCacheEntry id_cache = NULL;
- SilcClientEntry client;
-
- if (!id)
- return NULL;
-
- SILC_LOG_DEBUG(("Client ID (%s)", silc_id_render(id, SILC_ID_CLIENT)));
-
- if (!silc_idcache_find_by_id_one(server->clients, (void *)id, &id_cache))
- return NULL;
-
- client = id_cache->context;
-
- if (client && registered && !(client->data.registered))
- return NULL;
-
- if (ret_entry)
- *ret_entry = id_cache;
-
- SILC_LOG_DEBUG(("Found"));
-
- return client;
-}
-
-/* Replaces old Client ID with new one */
-
-SilcClientEntry
-silc_server_replace_client_id(SilcServer server, SilcClientID *old_id,
- SilcClientID *new_id, const char *nickname)
-{
- SilcIDCacheEntry id_cache = NULL;
- SilcClientEntry entry;
- char *name, *nicknamec = NULL;
-
- if (!old_id || !new_id)
- return NULL;
-
- SILC_LOG_DEBUG(("Replacing Client ID %s",
- silc_id_render(old_id, SILC_ID_CLIENT)));
- SILC_LOG_DEBUG(("New Client ID %s",
- silc_id_render(new_id, SILC_ID_CLIENT)));
-
- /* Normalize name. This is cached, original is in client context. */
- if (nickname) {
- nicknamec = silc_identifier_check(nickname, strlen(nickname),
- SILC_STRING_UTF8, 128, NULL);
- if (!nicknamec)
- return NULL;
- }
-
- if (!silc_idcache_find_by_id_one(server->clients, old_id, &id_cache))
- return NULL;
- entry = id_cache->context;
- name = id_cache->name;
- if (!silc_idcache_update(server->clients, id_cache, old_id, new_id,
- name, nicknamec)) {
- SILC_LOG_ERROR(("Error updating Client ID"));
- return NULL;
- }
- if (nicknamec)
- silc_free(name);
-
- /* Check if anyone is watching old nickname */
- if (server->server_type == SILC_ROUTER)
- silc_server_check_watcher_list(server, entry, nickname,
- SILC_NOTIFY_TYPE_NICK_CHANGE);
-
- silc_free(entry->nickname);
- entry->nickname = nickname ? strdup(nickname) : NULL;
-
- /* Check if anyone is watching new nickname */
- if (server->server_type == SILC_ROUTER)
- silc_server_check_watcher_list(server, entry, nickname,
- SILC_NOTIFY_TYPE_NICK_CHANGE);
-
- SILC_LOG_DEBUG(("Replaced"));
-
- return entry;
-}
-
-
-/****************************** Channel entry *******************************/
-
-void silc_server_destructor_channel(SilcIDCache cache,
- const SilcIDCacheEntry entry,
- void *destructor_context,
- void *app_context)
-{
-
-}
-
-/* Add new channel */
-
-SilcChannelEntry silc_server_add_channel(SilcServer server,
- const char *channel_name,
- SilcUInt32 mode,
- SilcChannelID *id,
- SilcPacketStream origin,
- SilcCipher channel_key,
- SilcHmac hmac)
-{
- SilcChannelEntry channel;
- char *channel_namec = NULL;
-
- if (!id || !channel_key || !hmac)
- return NULL;
-
- channel = silc_calloc(1, sizeof(*channel));
- if (!channel)
- return NULL;
-
- SILC_LOG_DEBUG(("Adding new channel %s %p", channel_name, channel));
-
- /* Normalize name. This is cached, original is in client context. */
- if (channel_name) {
- channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
- SILC_STRING_UTF8, 256, NULL);
- if (!channel_namec) {
- silc_free(channel);
- return NULL;
- }
- }
-
- channel->channel_name = channel_name ? strdup(channel_name) : NULL;
- if (!channel) {
- silc_free(channel);
- silc_free(channel_namec);
- return NULL;
- }
-
- channel->mode = mode;
- channel->id = *id;
- channel->channel_key = channel_key;
- channel->hmac = hmac;
- channel->router = origin;
-
- channel->user_list = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL,
- NULL, NULL, NULL, TRUE);
- if (!channel->user_list) {
- silc_cipher_free(channel->channel_key);
- silc_hmac_free(channel->hmac);
- silc_free(channel->channel_name);
- silc_free(channel);
- silc_free(channel_namec);
- return NULL;
- }
-
- if (!silc_idcache_add(server->channels, channel_namec,
- (void *)&channel->id, (void *)channel)) {
- silc_cipher_free(channel->channel_key);
- silc_hmac_free(channel->hmac);
- silc_free(channel->channel_name);
- silc_hash_table_free(channel->user_list);
- silc_free(channel);
- silc_free(channel_namec);
- return NULL;
- }
-
- /* Take reference of the packet stream */
- silc_packet_stream_ref(origin);
-
- return channel;
-}
-
-/* Free channel entry. This free's everything. */
-
-SilcBool silc_server_del_channel(SilcServer server, SilcChannelEntry entry)
-{
- SILC_LOG_DEBUG(("Deleting channel %s", entry->channel_name));
-
- /* Remove from cache */
- if (!silc_idcache_del_by_context(server->channels, entry, NULL)) {
- SILC_LOG_DEBUG(("Unknown channel %s, did not delete",
- entry->channel_name));
- return FALSE;
- }
-
- return TRUE;
-}
-
-/* Finds channel by channel name. Channel names are unique and they
- are not case-sensitive. The 'name' must be normalized already. */
-
-SilcChannelEntry silc_server_find_channel_by_name(SilcServer server,
- const char *name,
- SilcIDCacheEntry *ret_entry)
-{
- SilcIDCacheEntry id_cache = NULL;
-
- SILC_LOG_DEBUG(("Channel by name %s", name));
-
- if (!silc_idcache_find_by_name_one(server->channels, (char *)name,
- &id_cache))
- return NULL;
-
- if (ret_entry)
- *ret_entry = id_cache;
-
- SILC_LOG_DEBUG(("Found"));
-
- return id_cache->context;
-}
-
-/* Finds channel by Channel ID. */
-
-SilcChannelEntry silc_server_find_channel_by_id(SilcServer server,
- SilcChannelID *id,
- SilcIDCacheEntry *ret_entry)
-{
- SilcIDCacheEntry id_cache = NULL;
-
- if (!id)
- return NULL;
-
- SILC_LOG_DEBUG(("Channel ID (%s)", silc_id_render(id, SILC_ID_CHANNEL)));
-
- if (!silc_idcache_find_by_id_one(server->channels, (void *)id, &id_cache))
- return NULL;
-
- if (ret_entry)
- *ret_entry = id_cache;
-
- SILC_LOG_DEBUG(("Found"));
-
- return id_cache->context;
-}
-
-/* Replaces old Channel ID with new one. This is done when router forces
- normal server to change Channel ID. */
-
-SilcChannelEntry silc_server_replace_channel_id(SilcServer server,
- SilcChannelID *old_id,
- SilcChannelID *new_id)
-{
- SilcIDCacheEntry id_cache = NULL;
-
- if (!old_id || !new_id)
- return NULL;
-
- SILC_LOG_DEBUG(("Replacing Channel ID %s",
- silc_id_render(old_id, SILC_ID_CHANNEL)));
- SILC_LOG_DEBUG(("New Channel ID %s",
- silc_id_render(new_id, SILC_ID_CHANNEL)));
-
- if (!silc_idcache_find_by_id_one(server->channels, old_id, &id_cache))
- return NULL;
- if (!silc_idcache_update(server->channels, id_cache, old_id, new_id,
- NULL, NULL)) {
- SILC_LOG_ERROR(("Error updating Channel ID"));
- return NULL;
- }
-
- SILC_LOG_DEBUG(("Replaced"));
-
- return id_cache->context;
-}
-
-/* Returns channels from the ID list. If the `channel_id' is NULL then
- all channels are returned. Returns list of SilcIDCacheEntry entries. */
-
-SilcBool silc_server_get_channels(SilcServer server,
- SilcChannelID *channel_id,
- SilcList *list)
-{
- SILC_LOG_DEBUG(("Start"));
-
- if (!channel_id) {
- if (!silc_idcache_get_all(server->channels, list))
- return FALSE;
- } else {
- if (!silc_idcache_find_by_id(server->channels, channel_id, list))
- return FALSE;
- }
-
- return TRUE;
-}