SILC_TASK_CALLBACK(silc_server_packet_process);
SILC_TASK_CALLBACK(silc_server_packet_parse_real);
SILC_TASK_CALLBACK(silc_server_timeout_remote);
+SILC_TASK_CALLBACK(silc_server_failure_callback);
/* Allocates a new SILC server object. This has to be done before the server
can be used. After allocation one must call silc_server_init to initialize
if (server->pending_commands)
silc_dlist_uninit(server->pending_commands);
- silc_math_primegen_uninit(); /* XXX */
silc_free(server);
}
}
/* Set log files where log message should be saved. */
server->config->server = server;
- silc_config_server_setlogfiles(server->config);
+ silc_server_config_setlogfiles(server->config);
/* Register all configured ciphers, PKCS and hash functions. */
- silc_config_server_register_ciphers(server->config);
- silc_config_server_register_pkcs(server->config);
- silc_config_server_register_hashfuncs(server->config);
+ silc_server_config_register_ciphers(server->config);
+ silc_server_config_register_pkcs(server->config);
+ silc_server_config_register_hashfuncs(server->config);
+ silc_server_config_register_hmacs(server->config);
/* Initialize random number generator for the server. */
server->rng = silc_rng_alloc();
silc_rng_init(server->rng);
- silc_math_primegen_init(); /* XXX */
+ silc_rng_global_init(server->rng);
/* Initialize hash functions for server to use */
silc_hash_alloc("md5", &server->md5hash);
is sent as argument for fast referencing in the future. */
silc_socket_alloc(sock[i], SILC_SOCKET_TYPE_SERVER, id_entry,
&newsocket);
- if (!newsocket)
- goto err0;
server->sockets[sock[i]] = newsocket;
/* Allocate connection object for hold connection specific stuff. */
sconn = silc_calloc(1, sizeof(*sconn));
sconn->server = server;
- sconn->remote_host = server->config->routers->host;
+ sconn->remote_host = strdup(server->config->routers->host);
sconn->remote_port = server->config->routers->port;
silc_task_register(server->timeout_queue, fd,
/* If we are a SILC router we need to establish all of our primary
routes. */
if (server->server_type == SILC_ROUTER) {
- SilcConfigServerSectionServerConnection *ptr;
+ SilcServerConfigSectionServerConnection *ptr;
SILC_LOG_DEBUG(("We are router"));
/* Allocate connection object for hold connection specific stuff. */
sconn = silc_calloc(1, sizeof(*sconn));
sconn->server = server;
- sconn->remote_host = ptr->host;
+ sconn->remote_host = strdup(ptr->host);
sconn->remote_port = ptr->port;
silc_task_register(server->timeout_queue, fd,
if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
/* Error occured during protocol */
silc_protocol_free(protocol);
+ silc_ske_free_key_material(ctx->keymat);
if (ctx->packet)
silc_packet_context_free(ctx->packet);
if (ctx->ske)
if (ctx->dest_id)
silc_free(ctx->dest_id);
silc_free(ctx);
- sock->protocol = NULL;
+ silc_task_unregister_by_callback(server->timeout_queue,
+ silc_server_failure_callback);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Key exchange failed");
return;
}
+ /* We now have the key material as the result of the key exchange
+ protocol. Take the key material into use. Free the raw key material
+ as soon as we've set them into use. */
+ if (!silc_server_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
+ ctx->ske->prop->cipher,
+ ctx->ske->prop->pkcs,
+ ctx->ske->prop->hash,
+ ctx->ske->prop->hmac,
+ ctx->responder)) {
+ silc_protocol_free(protocol);
+ silc_ske_free_key_material(ctx->keymat);
+ if (ctx->packet)
+ silc_packet_context_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ if (ctx->dest_id)
+ silc_free(ctx->dest_id);
+ silc_free(ctx);
+ silc_task_unregister_by_callback(server->timeout_queue,
+ silc_server_failure_callback);
+ silc_server_disconnect_remote(server, sock, "Server closed connection: "
+ "Key exchange failed");
+ return;
+ }
+ silc_ske_free_key_material(ctx->keymat);
+
/* Allocate internal context for the authentication protocol. This
is sent as context for the protocol. */
proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
proto_ctx->dest_id = ctx->dest_id;
/* Resolve the authentication method used in this connection */
- proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_PASSWORD;
+ proto_ctx->auth_meth = SILC_AUTH_PASSWORD;
if (server->config->routers) {
- SilcConfigServerSectionServerConnection *conn = NULL;
+ SilcServerConfigSectionServerConnection *conn = NULL;
/* Check if we find a match from user configured connections */
- conn = silc_config_server_find_router_conn(server->config,
+ conn = silc_server_config_find_router_conn(server->config,
sock->hostname,
sock->port);
if (conn) {
out:
/* Free the temporary connection data context */
- if (sconn)
+ if (sconn) {
+ silc_free(sconn->remote_host);
silc_free(sconn);
+ }
/* Free the protocol object */
silc_protocol_free(protocol);
if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
/* Error occured during protocol */
silc_protocol_free(protocol);
+ silc_ske_free_key_material(ctx->keymat);
if (ctx->packet)
silc_packet_context_free(ctx->packet);
if (ctx->ske)
if (ctx->dest_id)
silc_free(ctx->dest_id);
silc_free(ctx);
- if (sock)
- sock->protocol = NULL;
+ silc_task_unregister_by_callback(server->timeout_queue,
+ silc_server_failure_callback);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Key exchange failed");
server->stat.auth_failures++;
return;
}
+ /* We now have the key material as the result of the key exchange
+ protocol. Take the key material into use. Free the raw key material
+ as soon as we've set them into use. */
+ if (!silc_server_protocol_ke_set_keys(ctx->ske, ctx->sock, ctx->keymat,
+ ctx->ske->prop->cipher,
+ ctx->ske->prop->pkcs,
+ ctx->ske->prop->hash,
+ ctx->ske->prop->hmac,
+ ctx->responder)) {
+ silc_protocol_free(protocol);
+ silc_ske_free_key_material(ctx->keymat);
+ if (ctx->packet)
+ silc_packet_context_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ if (ctx->dest_id)
+ silc_free(ctx->dest_id);
+ silc_free(ctx);
+ silc_task_unregister_by_callback(server->timeout_queue,
+ silc_server_failure_callback);
+ silc_server_disconnect_remote(server, sock, "Server closed connection: "
+ "Key exchange failed");
+ server->stat.auth_failures++;
+ return;
+ }
+ silc_ske_free_key_material(ctx->keymat);
+
/* Allocate internal context for the authentication protocol. This
is sent as context for the protocol. */
proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
silc_free(ctx);
if (sock)
sock->protocol = NULL;
+ silc_task_unregister_by_callback(server->timeout_queue,
+ silc_server_failure_callback);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Authentication failed");
server->stat.auth_failures++;
silc_server_perform_heartbeat,
server->timeout_queue);
+ silc_task_unregister_by_callback(server->timeout_queue,
+ silc_server_failure_callback);
silc_protocol_free(protocol);
if (ctx->packet)
silc_packet_context_free(ctx->packet);
/* If the closed connection was our primary router connection the
start re-connecting phase. */
- if (!server->standalone && server->server_type == SILC_SERVER &&
+ if (!server->standalone && sock->type == SILC_SOCKET_TYPE_ROUTER &&
sock == server->router->connection)
silc_task_register(server->timeout_queue, 0,
silc_server_connect_to_router,
- context, 0, 500000,
+ context, 1, 0,
SILC_TASK_TIMEOUT,
SILC_TASK_PRI_NORMAL);
switch(type) {
case SILC_PACKET_DISCONNECT:
SILC_LOG_DEBUG(("Disconnect packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
break;
case SILC_PACKET_SUCCESS:
* success message is for whatever protocol is executing currently.
*/
SILC_LOG_DEBUG(("Success packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
if (sock->protocol) {
sock->protocol->execute(server->timeout_queue, 0,
sock->protocol, sock->sock, 0, 0);
* failure message is for whatever protocol is executing currently.
*/
SILC_LOG_DEBUG(("Failure packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
if (sock->protocol) {
- /* XXX Audit the failure type */
- sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
- sock->protocol->execute(server->timeout_queue, 0,
- sock->protocol, sock->sock, 0, 0);
+ SilcServerFailureContext f;
+ f = silc_calloc(1, sizeof(*f));
+ f->server = server;
+ f->sock = sock;
+
+ /* We will wait 5 seconds to process this failure packet */
+ silc_task_register(server->timeout_queue, sock->sock,
+ silc_server_failure_callback, (void *)f, 5, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
break;
case SILC_PACKET_REJECT:
SILC_LOG_DEBUG(("Reject packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
return;
break;
* router. Server then relays the notify messages to clients if needed.
*/
SILC_LOG_DEBUG(("Notify packet"));
- silc_server_notify(server, sock, packet);
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ silc_server_notify_list(server, sock, packet);
+ else
+ silc_server_notify(server, sock, packet);
break;
/*
* specially.
*/
SILC_LOG_DEBUG(("Channel Message packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
silc_server_channel_message(server, sock, packet);
break;
* never receives this channel and thus is ignored.
*/
SILC_LOG_DEBUG(("Channel Key packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
silc_server_channel_key(server, sock, packet);
break;
* command context and calls the command.
*/
SILC_LOG_DEBUG(("Command packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
silc_server_command_process(server, sock, packet);
break;
* that we've routed further.
*/
SILC_LOG_DEBUG(("Command Reply packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
silc_server_command_reply(server, sock, packet);
break;
* client or server.
*/
SILC_LOG_DEBUG(("Private Message packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
silc_server_private_message(server, sock, packet);
break;
/*
* Private message key packet.
*/
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ silc_server_private_message_key(server, sock, packet);
break;
/*
*/
case SILC_PACKET_KEY_EXCHANGE:
SILC_LOG_DEBUG(("KE packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+
if (sock->protocol && sock->protocol->protocol->type
== SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
case SILC_PACKET_KEY_EXCHANGE_1:
SILC_LOG_DEBUG(("KE 1 packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+
if (sock->protocol && sock->protocol->protocol->type
== SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
case SILC_PACKET_KEY_EXCHANGE_2:
SILC_LOG_DEBUG(("KE 2 packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+
if (sock->protocol && sock->protocol->protocol->type
== SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
* at any time.
*/
SILC_LOG_DEBUG(("Connection authentication request packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
break;
/*
/* Start of the authentication protocol. We receive here the
authentication data and will verify it. */
SILC_LOG_DEBUG(("Connection auth packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+
if (sock->protocol && sock->protocol->protocol->type
== SILC_PROTOCOL_SERVER_CONNECTION_AUTH) {
* SILC network.
*/
SILC_LOG_DEBUG(("New ID packet"));
- silc_server_new_id(server, sock, packet);
- break;
-
- case SILC_PACKET_NEW_ID_LIST:
- /*
- * Received list of ID's. This packet is used by servers and routers
- * to notify their primary router about clients and servers they have.
- */
- SILC_LOG_DEBUG(("New ID List packet"));
- silc_server_new_id_list(server, sock, packet);
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ silc_server_new_id_list(server, sock, packet);
+ else
+ silc_server_new_id(server, sock, packet);
break;
case SILC_PACKET_NEW_CLIENT:
* ID we will send it to the client.
*/
SILC_LOG_DEBUG(("New Client packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
silc_server_new_client(server, sock, packet);
break;
* connected to us.
*/
SILC_LOG_DEBUG(("New Server packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
silc_server_new_server(server, sock, packet);
break;
* network are distributed using this packet.
*/
SILC_LOG_DEBUG(("New Channel packet"));
- silc_server_new_channel(server, sock, packet);
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ silc_server_new_channel_list(server, sock, packet);
+ else
+ silc_server_new_channel(server, sock, packet);
break;
- case SILC_PACKET_NEW_CHANNEL_USER:
- /*
- * Received new channel user packet. Information about new users on a
- * channel are distributed between routers using this packet. The
- * router receiving this will redistribute it and also sent JOIN notify
- * to local clients on the same channel. Normal server sends JOIN notify
- * to its local clients on the channel.
- */
- SILC_LOG_DEBUG(("New Channel User packet"));
- silc_server_new_channel_user(server, sock, packet);
- break;
-
- case SILC_PACKET_NEW_CHANNEL_LIST:
- /*
- * List of new channel packets received. This is usually received when
- * existing server or router connects to us and distributes information
- * of all channels it has.
- */
- SILC_LOG_DEBUG(("New Channel List packet"));
- silc_server_new_channel_list(server, sock, packet);
- break;
-
- case SILC_PACKET_NEW_CHANNEL_USER_LIST:
- /*
- * List of new channel user packets received. This is usually received
- * when existing server or router connects to us and distributes
- * information of all channel users it has.
- */
- SILC_LOG_DEBUG(("New Channel User List packet"));
- silc_server_new_channel_user_list(server, sock, packet);
- break;
-
- case SILC_PACKET_REPLACE_ID:
- /*
- * Received replace ID packet. This sends the old ID that is to be
- * replaced with the new one included into the packet. Client must not
- * send this packet.
- */
- SILC_LOG_DEBUG(("Replace ID packet"));
- silc_server_replace_id(server, sock, packet);
- break;
-
- case SILC_PACKET_REMOVE_ID:
- /*
- * Received remove ID Packet.
- */
- SILC_LOG_DEBUG(("Remove ID packet"));
- silc_server_remove_id(server, sock, packet);
- break;
-
- case SILC_PACKET_REMOVE_CHANNEL_USER:
- /*
- * Received packet to remove user from a channel. Routers notify other
- * routers about a user leaving a channel.
- */
- SILC_LOG_DEBUG(("Remove Channel User packet"));
- silc_server_remove_channel_user(server, sock, packet);
- break;
-
- case SILC_PACKET_SET_MODE:
+ case SILC_PACKET_HEARTBEAT:
/*
- * Received packet to set the mode of channel or client's channel mode.
+ * Received heartbeat.
*/
- SILC_LOG_DEBUG(("Set Mode packet"));
- silc_server_set_mode(server, sock, packet);
+ SILC_LOG_DEBUG(("Heartbeat packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
break;
- case SILC_PACKET_HEARTBEAT:
+ case SILC_PACKET_KEY_AGREEMENT:
/*
* Received heartbeat.
*/
- SILC_LOG_DEBUG(("Heartbeat packet"));
+ SILC_LOG_DEBUG(("Key agreement packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ silc_server_key_agreement(server, sock, packet);
break;
default:
}
+/* Creates connection to a remote router. */
+
+void silc_server_create_connection(SilcServer server,
+ char *remote_host, unsigned int port)
+{
+ SilcServerConnection sconn;
+
+ /* Allocate connection object for hold connection specific stuff. */
+ sconn = silc_calloc(1, sizeof(*sconn));
+ sconn->server = server;
+ sconn->remote_host = strdup(remote_host);
+ sconn->remote_port = port;
+
+ silc_task_register(server->timeout_queue, 0,
+ silc_server_connect_router,
+ (void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+}
+
/* Closes connection to socket connection */
void silc_server_close_connection(SilcServer server,
SILC_LOG_DEBUG(("Disconnecting remote host"));
- SILC_LOG_INFO(("Disconnecting %s:%d (%s) [%s]", sock->hostname,
+ SILC_LOG_INFO(("Disconnecting %s:%d [%s]", sock->hostname,
sock->port,
(sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
silc_server_close_connection(server, sock);
}
-/* Free's user_data pointer from socket connection object. This also sends
+/* Frees client data and notifies about client's signoff. */
+
+void silc_server_free_client_data(SilcServer server,
+ SilcSocketConnection sock,
+ SilcClientEntry user_data, char *signoff)
+{
+ /* Send REMOVE_ID packet to routers. */
+ if (!server->standalone && server->router)
+ silc_server_send_notify_signoff(server, server->router->connection,
+ server->server_type == SILC_SERVER ?
+ FALSE : TRUE, user_data->id,
+ SILC_ID_CLIENT_LEN, signoff);
+
+ /* Remove client from all channels */
+ silc_server_remove_from_channels(server, sock, user_data, signoff);
+
+ /* XXX must take some info to history before freeing */
+
+ /* Free the client entry and everything in it */
+ silc_idlist_del_data(user_data);
+ silc_idlist_del_client(server->local_list, user_data);
+ server->stat.my_clients--;
+ server->stat.clients--;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.cell_clients--;
+}
+
+/* Frees user_data pointer from socket connection object. This also sends
appropriate notify packets to the network to inform about leaving
entities. */
case SILC_SOCKET_TYPE_CLIENT:
{
SilcClientEntry user_data = (SilcClientEntry)sock->user_data;
-
- /* Remove client from all channels */
- silc_server_remove_from_channels(server, sock, user_data);
-
- /* XXX must take some info to history before freeing */
-
- /* Send REMOVE_ID packet to routers. */
- if (!server->standalone && server->router)
- silc_server_send_remove_id(server, server->router->connection,
- server->server_type == SILC_SERVER ?
- FALSE : TRUE, user_data->id,
- SILC_ID_CLIENT_LEN, SILC_ID_CLIENT);
-
- /* Free the client entry and everything in it */
- silc_idlist_del_data(user_data);
- silc_idlist_del_client(server->local_list, user_data);
- server->stat.my_clients--;
- server->stat.clients--;
- if (server->server_type == SILC_ROUTER)
- server->stat.cell_clients--;
+ silc_server_free_client_data(server, sock, user_data, NULL);
break;
}
case SILC_SOCKET_TYPE_SERVER:
/* Send REMOVE_ID packet to routers. */
if (!server->standalone && server->router)
- silc_server_send_remove_id(server, server->router->connection,
- server->server_type == SILC_SERVER ?
- FALSE : TRUE, user_data->id,
- SILC_ID_SERVER_LEN, SILC_ID_SERVER);
+ silc_server_send_notify_server_signoff(server,
+ server->router->connection,
+ server->server_type ==
+ SILC_SERVER ?
+ FALSE : TRUE, user_data->id,
+ SILC_ID_SERVER_LEN);
/* Then also free all client entries that this server owns as
they will become invalid now as well. */
SilcIDCacheEntry id_cache = NULL;
SilcClientEntry client = NULL;
+ SILC_LOG_DEBUG(("Start"));
+
if (silc_idcache_find_by_id(server->local_list->clients,
SILC_ID_CACHE_ANY, SILC_ID_CLIENT, &list)) {
}
/* Remove the client entry */
- silc_server_remove_from_channels(server, NULL, client);
+ silc_server_remove_from_channels(server, NULL, client, NULL);
silc_idlist_del_client(server->local_list, client);
if (!silc_idcache_list_next(list, &id_cache))
}
/* Remove the client entry */
- silc_server_remove_from_channels(server, NULL, client);
+ silc_server_remove_from_channels(server, NULL, client, NULL);
silc_idlist_del_client(server->global_list, client);
if (!silc_idcache_list_next(list, &id_cache))
void silc_server_remove_from_channels(SilcServer server,
SilcSocketConnection sock,
- SilcClientEntry client)
+ SilcClientEntry client,
+ char *signoff_message)
{
SilcChannelEntry channel;
SilcChannelClientEntry chl;
silc_free(chl);
server->stat.my_chanclients--;
+ /* If there is no global users on the channel anymore mark the channel
+ as local channel. */
+ if (server->server_type == SILC_SERVER &&
+ !silc_server_channel_has_global(channel))
+ channel->global_users = FALSE;
+
/* If there is not at least one local user on the channel then we don't
need the channel entry anymore, we can remove it safely. */
if (server->server_type == SILC_SERVER &&
/* Notify about leaving client if this channel has global users. */
if (channel->global_users)
silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
- SILC_NOTIFY_TYPE_SIGNOFF, 1,
- clidp->data, clidp->len);
+ SILC_NOTIFY_TYPE_SIGNOFF,
+ signoff_message ? 2 : 1,
+ clidp->data, clidp->len,
+ signoff_message, signoff_message ?
+ strlen(signoff_message) : 0);
if (!silc_idlist_del_channel(server->local_list, channel))
silc_idlist_del_channel(server->global_list, channel);
/* Send notify to channel about client leaving SILC and thus
the entire channel. */
silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
- SILC_NOTIFY_TYPE_SIGNOFF, 1,
- clidp->data, clidp->len);
+ SILC_NOTIFY_TYPE_SIGNOFF,
+ signoff_message ? 2 : 1,
+ clidp->data, clidp->len,
+ signoff_message, signoff_message ?
+ strlen(signoff_message) : 0);
}
silc_buffer_free(clidp);
SilcChannelEntry silc_server_create_new_channel(SilcServer server,
SilcServerID *router_id,
char *cipher,
+ char *hmac,
char *channel_name,
int broadcast)
{
SILC_LOG_DEBUG(("Creating new channel"));
if (!cipher)
- cipher = "twofish";
+ cipher = "aes-256-cbc";
+ if (!hmac)
+ hmac = "hmac-sha1-96";
/* Allocate cipher */
- silc_cipher_alloc(cipher, &key);
+ if (!silc_cipher_alloc(cipher, &key))
+ return NULL;
channel_name = strdup(channel_name);
silc_id_create_channel_id(router_id, server->rng, &channel_id);
entry = silc_idlist_add_channel(server->local_list, channel_name,
SILC_CHANNEL_MODE_NONE, channel_id,
- NULL, key);
+ NULL, key, hmac);
if (!entry) {
silc_free(channel_name);
return NULL;
}
/* Now create the actual key material */
- silc_server_create_channel_key(server, entry, 16);
+ silc_server_create_channel_key(server, entry,
+ silc_cipher_get_key_len(key) / 8);
/* Notify other routers about the new channel. We send the packet
to our primary route. */
SilcChannelEntry
silc_server_create_new_channel_with_id(SilcServer server,
char *cipher,
+ char *hmac,
char *channel_name,
SilcChannelID *channel_id,
int broadcast)
SILC_LOG_DEBUG(("Creating new channel"));
if (!cipher)
- cipher = "twofish";
+ cipher = "aes-256-cbc";
+ if (!hmac)
+ hmac = "hmac-sha1-96";
/* Allocate cipher */
- silc_cipher_alloc(cipher, &key);
+ if (!silc_cipher_alloc(cipher, &key))
+ return NULL;
channel_name = strdup(channel_name);
/* Create the channel */
entry = silc_idlist_add_channel(server->local_list, channel_name,
SILC_CHANNEL_MODE_NONE, channel_id,
- NULL, key);
+ NULL, key, hmac);
if (!entry) {
silc_free(channel_name);
return NULL;
}
/* Now create the actual key material */
- silc_server_create_channel_key(server, entry, 16);
+ silc_server_create_channel_key(server, entry,
+ silc_cipher_get_key_len(key) / 8);
/* Notify other routers about the new channel. We send the packet
to our primary route. */
unsigned int len;
if (!channel->channel_key)
- silc_cipher_alloc("twofish", &channel->channel_key);
+ if (!silc_cipher_alloc("aes-256-cbc", &channel->channel_key))
+ return;
if (key_len)
len = key_len;
else if (channel->key_len)
len = channel->key_len / 8;
else
- len = sizeof(channel_key);
+ len = silc_cipher_get_key_len(channel->channel_key) / 8;
/* Create channel key */
for (i = 0; i < len; i++) channel_key[i] = silc_rng_get_byte(server->rng);
goto out;
}
- cipher = silc_channel_key_get_cipher(payload, NULL);;
+ cipher = silc_channel_key_get_cipher(payload, NULL);
if (!cipher) {
channel = NULL;
goto out;
/* Send the packet */
silc_server_packet_send(server, server->router->connection,
- SILC_PACKET_NEW_ID_LIST, 0,
+ SILC_PACKET_NEW_ID, SILC_PACKET_FLAG_LIST,
servers->data, servers->len, TRUE);
silc_buffer_free(servers);
/* Send the packet */
silc_server_packet_send(server, server->router->connection,
- SILC_PACKET_NEW_ID_LIST, 0,
+ SILC_PACKET_NEW_ID, SILC_PACKET_FLAG_LIST,
clients->data, clients->len, TRUE);
silc_buffer_free(clients);
}
}
+static SilcBuffer
+silc_server_announce_encode_join(unsigned int argc, ...)
+{
+ va_list ap;
+
+ va_start(ap, argc);
+ return silc_notify_payload_encode(SILC_NOTIFY_TYPE_JOIN, argc, ap);
+}
+
/* Returns assembled packets for all channels and users on those channels
from the given ID List. The packets are in the form dictated by the
New Channel and New Channel User payloads. */
SilcIDCacheEntry id_cache;
SilcChannelEntry channel;
SilcChannelClientEntry chl;
+ SilcBuffer chidp;
unsigned char *cid;
unsigned short name_len;
int len;
silc_buffer_pull(*channels, len);
/* Now find all users on the channel */
+ chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
silc_list_start(channel->user_list);
while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
- unsigned char *clid;
+ SilcBuffer clidp;
+ SilcBuffer tmp;
+
+ clidp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
- clid = silc_id_id2str(chl->client->id, SILC_ID_CLIENT);
-
- len = 4 + SILC_ID_CHANNEL_LEN + SILC_ID_CLIENT_LEN;
+ tmp = silc_server_announce_encode_join(2, clidp->data, clidp->len,
+ chidp->data, chidp->len);
+ len = tmp->len;
*channel_users =
silc_buffer_realloc(*channel_users,
(*channel_users ?
silc_buffer_pull_tail(*channel_users,
((*channel_users)->end -
(*channel_users)->data));
- silc_buffer_format(*channel_users,
- SILC_STR_UI_SHORT(SILC_ID_CHANNEL_LEN),
- SILC_STR_UI_XNSTRING(cid, SILC_ID_CHANNEL_LEN),
- SILC_STR_UI_SHORT(SILC_ID_CLIENT_LEN),
- SILC_STR_UI_XNSTRING(clid, SILC_ID_CLIENT_LEN),
- SILC_STR_END);
+
+ silc_buffer_put(*channel_users, tmp->data, tmp->len);
silc_buffer_pull(*channel_users, len);
- silc_free(clid);
+ silc_buffer_free(clidp);
+ silc_buffer_free(tmp);
}
+ silc_buffer_free(chidp);
silc_free(cid);
/* Send the packet */
silc_server_packet_send(server, server->router->connection,
- SILC_PACKET_NEW_CHANNEL_LIST, 0,
+ SILC_PACKET_NEW_CHANNEL, SILC_PACKET_FLAG_LIST,
channels->data, channels->len,
FALSE);
/* Send the packet */
silc_server_packet_send(server, server->router->connection,
- SILC_PACKET_NEW_CHANNEL_USER_LIST, 0,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
channel_users->data, channel_users->len,
FALSE);
silc_buffer_free(channel_users);
}
}
+
+/* Failure timeout callback. If this is called then we will immediately
+ process the received failure. We always process the failure with timeout
+ since we do not want to blindly trust to received failure packets.
+ This won't be called (the timeout is cancelled) if the failure was
+ bogus (it is bogus if remote does not close the connection after sending
+ the failure). */
+
+SILC_TASK_CALLBACK(silc_server_failure_callback)
+{
+ SilcServerFailureContext f = (SilcServerFailureContext)context;
+
+ if (f->sock->protocol) {
+ f->sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
+ f->sock->protocol->execute(f->server->timeout_queue, 0,
+ f->sock->protocol, f->sock->sock, 0, 0);
+ }
+
+ silc_free(f);
+}