SILC_TASK_CALLBACK(silc_server_packet_parse_real);
SILC_TASK_CALLBACK(silc_server_timeout_remote);
SILC_TASK_CALLBACK(silc_server_failure_callback);
+SILC_TASK_CALLBACK(silc_server_rekey_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
{
unsigned char *public_key;
unsigned char *private_key;
- unsigned int pk_len, prv_len;
+ uint32 pk_len, prv_len;
struct stat st;
if (stat("pubkey.pub", &st) < 0 && stat("privkey.prv", &st) < 0) {
(SilcServerKEInternalContext *)protocol->context;
SilcServer server = (SilcServer)ctx->server;
SilcServerConnection sconn = (SilcServerConnection)ctx->context;
- SilcSocketConnection sock = NULL;
+ SilcSocketConnection sock = server->sockets[fd];
SilcServerConnAuthInternalContext *proto_ctx;
SilcServerConfigSectionServerConnection *conn = NULL;
SILC_LOG_DEBUG(("Start"));
- if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+ protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Error occured during protocol */
silc_protocol_free(protocol);
+ sock->protocol = NULL;
silc_ske_free_key_material(ctx->keymat);
if (ctx->packet)
silc_packet_context_free(ctx->packet);
ctx->ske->prop->hmac,
ctx->responder)) {
silc_protocol_free(protocol);
+ sock->protocol = NULL;
silc_ske_free_key_material(ctx->keymat);
if (ctx->packet)
silc_packet_context_free(ctx->packet);
proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
proto_ctx->server = (void *)server;
proto_ctx->context = (void *)sconn;
- proto_ctx->sock = sock = server->sockets[fd];
+ proto_ctx->sock = sock;
proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
proto_ctx->dest_id_type = ctx->dest_id_type;
proto_ctx->dest_id = ctx->dest_id;
SILC_LOG_ERROR(("Could not find connection data for %s (%s) on port",
sock->hostname, sock->ip, sock->port));
silc_protocol_free(protocol);
+ sock->protocol = NULL;
if (ctx->packet)
silc_packet_context_free(ctx->packet);
if (ctx->ske)
SilcServerEntry id_entry;
SilcBuffer packet;
SilcServerHBContext hb_context;
+ SilcServerRekeyContext rekey;
unsigned char *id_string;
SILC_LOG_DEBUG(("Start"));
- if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+ protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Error occured during protocol */
if (ctx->dest_id)
silc_free(ctx->dest_id);
silc_server_perform_heartbeat,
server->timeout_queue);
+ /* Registed re-key timeout */
+ rekey = silc_calloc(1, sizeof(*rekey));
+ rekey->server = server;
+ rekey->sock = sock;
+ rekey->timeout = 3600; /* XXX hardcoded */
+ silc_task_register(server->timeout_queue, sock->sock,
+ silc_server_rekey_callback,
+ (void *)rekey, rekey->timeout, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+
/* If we are router then announce our possible servers. */
if (server->server_type == SILC_ROUTER)
silc_server_announce_servers(server);
SilcServerKEInternalContext *ctx =
(SilcServerKEInternalContext *)protocol->context;
SilcServer server = (SilcServer)ctx->server;
- SilcSocketConnection sock = NULL;
+ SilcSocketConnection sock = server->sockets[fd];
SilcServerConnAuthInternalContext *proto_ctx;
SILC_LOG_DEBUG(("Start"));
protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Error occured during protocol */
silc_protocol_free(protocol);
+ sock->protocol = NULL;
silc_ske_free_key_material(ctx->keymat);
if (ctx->packet)
silc_packet_context_free(ctx->packet);
ctx->ske->prop->hmac,
ctx->responder)) {
silc_protocol_free(protocol);
+ sock->protocol = NULL;
silc_ske_free_key_material(ctx->keymat);
if (ctx->packet)
silc_packet_context_free(ctx->packet);
is sent as context for the protocol. */
proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
proto_ctx->server = (void *)server;
- proto_ctx->sock = sock = server->sockets[fd];
+ proto_ctx->sock = sock;
proto_ctx->ske = ctx->ske; /* Save SKE object from previous protocol */
proto_ctx->responder = TRUE;
proto_ctx->dest_id_type = ctx->dest_id_type;
protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Error occured during protocol */
silc_protocol_free(protocol);
+ sock->protocol = NULL;
if (ctx->packet)
silc_packet_context_free(ctx->packet);
if (ctx->ske)
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
- if (sock->protocol && sock->protocol->protocol->type
- == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
+ if (sock->protocol && sock->protocol->protocol &&
+ sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
SilcServerKEInternalContext *proto_ctx =
(SilcServerKEInternalContext *)sock->protocol->context;
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
- if (sock->protocol && sock->protocol->protocol->type
- == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
+ if (sock->protocol && sock->protocol->protocol &&
+ sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
SilcServerKEInternalContext *proto_ctx =
(SilcServerKEInternalContext *)sock->protocol->context;
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
- if (sock->protocol && sock->protocol->protocol->type
- == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
+ if (sock->protocol && sock->protocol->protocol &&
+ sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
SilcServerKEInternalContext *proto_ctx =
(SilcServerKEInternalContext *)sock->protocol->context;
silc_server_key_agreement(server, sock, packet);
break;
+ case SILC_PACKET_REKEY:
+ /*
+ * Received re-key packet. The sender wants to regenerate the session
+ * keys.
+ */
+ SILC_LOG_DEBUG(("Re-key packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+ silc_server_rekey(server, sock, packet);
+ break;
+
+ case SILC_PACKET_REKEY_DONE:
+ /*
+ * The re-key is done.
+ */
+ SILC_LOG_DEBUG(("Re-key done packet"));
+ if (packet->flags & SILC_PACKET_FLAG_LIST)
+ break;
+
+ if (sock->protocol && sock->protocol->protocol &&
+ sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY) {
+
+ SilcServerRekeyInternalContext *proto_ctx =
+ (SilcServerRekeyInternalContext *)sock->protocol->context;
+
+ if (proto_ctx->packet)
+ silc_packet_context_free(proto_ctx->packet);
+
+ proto_ctx->packet = silc_packet_context_dup(packet);
+
+ /* Let the protocol handle the packet */
+ sock->protocol->execute(server->timeout_queue, 0,
+ sock->protocol, sock->sock,
+ 0, 100000);
+ } else {
+ SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
+ "protocol active, packet dropped."));
+ }
+ break;
+
default:
SILC_LOG_ERROR(("Incorrect packet type %d, packet dropped", type));
break;
/* Creates connection to a remote router. */
void silc_server_create_connection(SilcServer server,
- char *remote_host, unsigned int port)
+ char *remote_host, uint32 port)
{
SilcServerConnection sconn;
{
SilcServerEntry user_data = (SilcServerEntry)sock->user_data;
- /* Send REMOVE_ID packet to routers. */
- if (!server->standalone && server->router)
- 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. */
- silc_server_remove_clients_by_server(server, user_data);
+ /* Free all client entries that this server owns as they will
+ become invalid now as well. */
+ silc_server_remove_clients_by_server(server, user_data, TRUE);
/* If this was our primary router connection then we're lost to
the outside world. */
/* This function is used to remove all client entries by the server `entry'.
This is called when the connection is lost to the server. In this case
- we must invalidate all the client entries owned by the server `entry'. */
+ we must invalidate all the client entries owned by the server `entry'.
+ If the `server_signoff' is TRUE then the SERVER_SIGNOFF notify is
+ distributed to our local clients. */
int silc_server_remove_clients_by_server(SilcServer server,
- SilcServerEntry entry)
+ SilcServerEntry entry,
+ int server_signoff)
{
SilcIDCacheList list = NULL;
SilcIDCacheEntry id_cache = NULL;
SilcClientEntry client = NULL;
+ SilcBuffer idp;
+ SilcClientEntry *clients = NULL;
+ uint32 clients_c = 0;
+ unsigned char **argv = NULL;
+ uint32 *argv_lens = NULL, *argv_types = NULL, argc = 0;
+ int i;
SILC_LOG_DEBUG(("Start"));
+ if (server_signoff) {
+ idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
+ argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
+ argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) * (argc + 1));
+ argv_types = silc_realloc(argv_types, sizeof(*argv_types) * (argc + 1));
+ argv[argc] = idp->data;
+ argv_lens[argc] = idp->len;
+ argv_types[argc] = argc + 1;
+ argc++;
+ silc_buffer_free(idp);
+ }
+
if (silc_idcache_find_by_id(server->local_list->clients,
SILC_ID_CACHE_ANY, SILC_ID_CLIENT, &list)) {
if (silc_idcache_list_first(list, &id_cache)) {
while (id_cache) {
client = (SilcClientEntry)id_cache->context;
-
+ if (client->data.registered == FALSE) {
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ else
+ continue;
+ }
+
if (client->router != entry) {
+ if (server_signoff && client->connection) {
+ clients = silc_realloc(clients,
+ sizeof(*clients) * (clients_c + 1));
+ clients[clients_c] = client;
+ clients_c++;
+ }
+
if (!silc_idcache_list_next(list, &id_cache))
break;
else
continue;
}
+ if (server_signoff) {
+ idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
+ argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
+ (argc + 1));
+ argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
+ (argc + 1));
+ argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
+ memcpy(argv[argc], idp->data, idp->len);
+ argv_lens[argc] = idp->len;
+ argv_types[argc] = argc + 1;
+ argc++;
+ silc_buffer_free(idp);
+ }
+
/* Remove the client entry */
- silc_server_remove_from_channels(server, NULL, client, TRUE,
- NULL, TRUE);
+ silc_server_remove_from_channels(server, NULL, client, FALSE,
+ NULL, FALSE);
silc_idlist_del_client(server->local_list, client);
if (!silc_idcache_list_next(list, &id_cache))
if (silc_idcache_list_first(list, &id_cache)) {
while (id_cache) {
client = (SilcClientEntry)id_cache->context;
+ if (client->data.registered == FALSE) {
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+ else
+ continue;
+ }
if (client->router != entry) {
+ if (server_signoff && client->connection) {
+ clients = silc_realloc(clients,
+ sizeof(*clients) * (clients_c + 1));
+ clients[clients_c] = client;
+ clients_c++;
+ }
+
if (!silc_idcache_list_next(list, &id_cache))
break;
else
continue;
}
+ if (server_signoff) {
+ idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ argv = silc_realloc(argv, sizeof(*argv) * (argc + 1));
+ argv_lens = silc_realloc(argv_lens, sizeof(*argv_lens) *
+ (argc + 1));
+ argv_types = silc_realloc(argv_types, sizeof(*argv_types) *
+ (argc + 1));
+ argv[argc] = silc_calloc(idp->len, sizeof(*argv[0]));
+ memcpy(argv[argc], idp->data, idp->len);
+ argv_lens[argc] = idp->len;
+ argv_types[argc] = argc + 1;
+ argc++;
+ silc_buffer_free(idp);
+ }
+
/* Remove the client entry */
- silc_server_remove_from_channels(server, NULL, client, TRUE,
- NULL, TRUE);
+ silc_server_remove_from_channels(server, NULL, client, FALSE,
+ NULL, FALSE);
silc_idlist_del_client(server->global_list, client);
if (!silc_idcache_list_next(list, &id_cache))
}
silc_idcache_list_free(list);
}
-
+
+ /* Send the SERVER_SIGNOFF notify */
+ if (server_signoff) {
+ SilcBuffer args;
+
+ /* Send SERVER_SIGNOFF notify to our primary router */
+ if (!server->standalone && server->router) {
+ args = silc_argument_payload_encode(1, argv, argv_lens,
+ argv_types);
+ silc_server_send_notify_args(server,
+ server->router->connection,
+ server->server_type ==
+ SILC_SERVER ? FALSE : TRUE,
+ SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
+ argc, args);
+ silc_buffer_free(args);
+ }
+
+ args = silc_argument_payload_encode(argc, argv, argv_lens,
+ argv_types);
+ /* Send to local clients */
+ for (i = 0; i < clients_c; i++) {
+ silc_server_send_notify_args(server, clients[i]->connection,
+ FALSE, SILC_NOTIFY_TYPE_SERVER_SIGNOFF,
+ argc, args);
+ }
+
+ silc_free(clients);
+ silc_buffer_free(args);
+ silc_free(argv);
+ silc_free(argv_lens);
+ silc_free(argv_types);
+ }
+
return TRUE;
}
/* Remove channel if there is no users anymore */
if (server->server_type == SILC_ROUTER &&
silc_list_count(channel->user_list) < 2) {
+ server->stat.my_channels--;
+
+ if (channel->rekey)
+ silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
+
+ if (channel->founder_key) {
+ /* The founder auth data exists, do not remove the channel entry */
+ SilcChannelClientEntry chl2;
+
+ channel->id = NULL;
+
+ silc_list_start(channel->user_list);
+ while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ silc_list_del(chl2->client->channels, chl2);
+ silc_list_del(channel->user_list, chl2);
+ silc_free(chl2);
+ }
+ continue;
+ }
+
if (!silc_idlist_del_channel(server->local_list, channel))
silc_idlist_del_channel(server->global_list, channel);
- server->stat.my_channels--;
continue;
}
signoff_message, signoff_message ?
strlen(signoff_message) : 0);
+ server->stat.my_channels--;
+
+ if (channel->rekey)
+ silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
+
+ if (channel->founder_key) {
+ /* The founder auth data exists, do not remove the channel entry */
+ SilcChannelClientEntry chl2;
+
+ channel->id = NULL;
+
+ silc_list_start(channel->user_list);
+ while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ silc_list_del(chl2->client->channels, chl2);
+ silc_list_del(channel->user_list, chl2);
+ silc_free(chl2);
+ }
+ continue;
+ }
+
if (!silc_idlist_del_channel(server->local_list, channel))
silc_idlist_del_channel(server->global_list, channel);
- server->stat.my_channels--;
continue;
}
silc_server_create_channel_key(server, channel, 0);
/* Send the channel key to the channel. The key of course is not sent
- to the client who was removed f rom the channel. */
+ to the client who was removed from the channel. */
silc_server_send_channel_key(server, client->connection, channel,
server->server_type == SILC_ROUTER ?
FALSE : !server->standalone);
/* Remove channel if there is no users anymore */
if (server->server_type == SILC_ROUTER &&
silc_list_count(channel->user_list) < 2) {
+ if (channel->rekey)
+ silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
if (!silc_idlist_del_channel(server->local_list, channel))
silc_idlist_del_channel(server->global_list, channel);
silc_buffer_free(clidp);
SILC_NOTIFY_TYPE_LEAVE, 1,
clidp->data, clidp->len);
+ server->stat.my_channels--;
+ silc_buffer_free(clidp);
+
+ if (channel->rekey)
+ silc_task_unregister_by_context(server->timeout_queue, channel->rekey);
+
+ if (channel->founder_key) {
+ /* The founder auth data exists, do not remove the channel entry */
+ SilcChannelClientEntry chl2;
+
+ channel->id = NULL;
+
+ silc_list_start(channel->user_list);
+ while ((chl2 = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ silc_list_del(chl2->client->channels, chl2);
+ silc_list_del(channel->user_list, chl2);
+ silc_free(chl2);
+ }
+ return FALSE;
+ }
+
if (!silc_idlist_del_channel(server->local_list, channel))
silc_idlist_del_channel(server->global_list, channel);
- silc_buffer_free(clidp);
- server->stat.my_channels--;
return FALSE;
}
return entry;
}
+/* Channel's key re-key timeout callback. */
+
+SILC_TASK_CALLBACK(silc_server_channel_key_rekey)
+{
+ SilcServerChannelRekey rekey = (SilcServerChannelRekey)context;
+ SilcServer server = (SilcServer)rekey->context;
+
+ silc_server_create_channel_key(server, rekey->channel, rekey->key_len);
+ silc_server_send_channel_key(server, NULL, rekey->channel, FALSE);
+
+ silc_task_register(server->timeout_queue, 0,
+ silc_server_channel_key_rekey,
+ (void *)rekey, 3600, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+}
+
/* Generates new channel key. This is used to create the initial channel key
but also to re-generate new key for channel. If `key_len' is provided
it is the bytes of the key length. */
void silc_server_create_channel_key(SilcServer server,
SilcChannelEntry channel,
- unsigned int key_len)
+ uint32 key_len)
{
int i;
unsigned char channel_key[32], hash[32];
- unsigned int len;
+ uint32 len;
SILC_LOG_DEBUG(("Generating channel key"));
silc_hash_make(channel->hmac->hash, channel->key, len, hash);
silc_hmac_set_key(channel->hmac, hash, silc_hash_len(channel->hmac->hash));
memset(hash, 0, sizeof(hash));
+
+ if (server->server_type == SILC_ROUTER) {
+ if (!channel->rekey)
+ channel->rekey = silc_calloc(1, sizeof(*channel->rekey));
+ channel->rekey->context = (void *)server;
+ channel->rekey->channel = channel;
+ channel->rekey->key_len = key_len;
+
+ silc_task_unregister_by_callback(server->timeout_queue,
+ silc_server_channel_key_rekey);
+ silc_task_register(server->timeout_queue, 0,
+ silc_server_channel_key_rekey,
+ (void *)channel->rekey, 3600, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ }
}
/* Saves the channel key found in the encoded `key_payload' buffer. This
SilcChannelKeyPayload payload = NULL;
SilcChannelID *id = NULL;
unsigned char *tmp, hash[32];
- unsigned int tmp_len;
+ uint32 tmp_len;
char *cipher;
SILC_LOG_DEBUG(("Start"));
memset(hash, 0, sizeof(hash));
memset(tmp, 0, tmp_len);
+ if (server->server_type == SILC_ROUTER) {
+ if (!channel->rekey)
+ channel->rekey = silc_calloc(1, sizeof(*channel->rekey));
+ channel->rekey->context = (void *)server;
+ channel->rekey->channel = channel;
+
+ silc_task_unregister_by_callback(server->timeout_queue,
+ silc_server_channel_key_rekey);
+ silc_task_register(server->timeout_queue, 0,
+ silc_server_channel_key_rekey,
+ (void *)channel->rekey, 3600, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ }
+
out:
if (id)
silc_free(id);
}
static SilcBuffer
-silc_server_announce_encode_join(unsigned int argc, ...)
+silc_server_announce_encode_join(uint32 argc, ...)
{
va_list ap;
SilcIDCacheEntry id_cache;
SilcChannelEntry channel;
unsigned char *cid;
- unsigned short name_len;
+ uint16 name_len;
int len;
SILC_LOG_DEBUG(("Start"));
SilcChannelEntry channel,
SilcBuffer *user_list,
SilcBuffer *mode_list,
- unsigned int *user_count)
+ uint32 *user_count)
{
SilcChannelClientEntry chl;
SilcBuffer client_id_list;
SilcBuffer client_mode_list;
SilcBuffer idp;
- unsigned int list_count = 0;
+ uint32 list_count = 0;
client_id_list = silc_buffer_alloc((SILC_ID_CLIENT_LEN + 4) *
silc_list_count(channel->user_list));
SilcClientID *noadd,
SilcBuffer user_list,
SilcBuffer mode_list,
- unsigned int user_count)
+ uint32 user_count)
{
int i;
whenever server sends notify message to channel. It means two things;
some user has joined or leaved the channel. XXX TODO! */
for (i = 0; i < user_count; i++) {
- unsigned short idp_len;
- unsigned int mode;
+ uint16 idp_len;
+ uint32 mode;
SilcClientID *client_id;
SilcClientEntry client;
SilcSocketConnection silc_server_get_client_route(SilcServer server,
unsigned char *id_data,
- unsigned int id_len,
+ uint32 id_len,
SilcClientID *client_id,
SilcIDListData *idata)
{
SilcChannelEntry channel;
SilcChannelClientEntry chl;
unsigned char *cid;
- unsigned short name_len;
+ uint16 name_len;
int len;
silc_list_start(client->channels);
return client;
}
+
+/* A timeout callback for the re-key. We will be the initiator of the
+ re-key protocol. */
+
+SILC_TASK_CALLBACK(silc_server_rekey_callback)
+{
+ SilcServerRekeyContext rekey = (SilcServerRekeyContext)context;
+ SilcServer server = rekey->server;
+ SilcProtocol protocol;
+ SilcServerRekeyInternalContext *proto_ctx;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* Allocate internal protocol context. This is sent as context
+ to the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->server = (void *)server;
+ proto_ctx->context = context;
+ proto_ctx->sock = rekey->sock;
+ proto_ctx->responder = FALSE;
+
+ /* Perform rekey protocol. Will call the final callback after the
+ protocol is over. */
+ silc_protocol_alloc(SILC_PROTOCOL_SERVER_REKEY,
+ &protocol, proto_ctx, silc_server_rekey_final);
+ rekey->sock->protocol = protocol;
+
+ /* Run the protocol */
+ protocol->execute(server->timeout_queue, 0, protocol,
+ rekey->sock->sock, 0, 0);
+
+ /* Re-register re-key timeout */
+ silc_task_register(server->timeout_queue, 0,
+ silc_server_rekey_callback,
+ context, rekey->timeout, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
+}
+
+/* The final callback for the REKEY protocol. This will actually take the
+ new key material into use. */
+
+SILC_TASK_CALLBACK_GLOBAL(silc_server_rekey_final)
+{
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcServerRekeyInternalContext *ctx =
+ (SilcServerRekeyInternalContext *)protocol->context;
+ SilcServer server = (SilcServer)ctx->server;
+ SilcSocketConnection sock = ctx->sock;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+ protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
+ /* Error occured during protocol */
+ silc_protocol_free(protocol);
+ sock->protocol = NULL;
+ if (ctx->keymat)
+ silc_ske_free_key_material(ctx->keymat);
+ if (ctx->packet)
+ silc_packet_context_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ silc_free(ctx);
+ return;
+ }
+
+ /* Take the keys into use */
+ if (ctx->pfs == TRUE) {
+
+ } else {
+ /* Then just generate the new keys and take them into use */
+ silc_server_protocol_rekey_generate(server, ctx);
+ }
+
+ /* Cleanup */
+ silc_protocol_free(protocol);
+ sock->protocol = NULL;
+ if (ctx->keymat)
+ silc_ske_free_key_material(ctx->keymat);
+ if (ctx->packet)
+ silc_packet_context_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ silc_free(ctx);
+}