SILC_TASK_CALLBACK(silc_client_connect_to_server_second);
SILC_TASK_CALLBACK(silc_client_connect_to_server_final);
SILC_TASK_CALLBACK(silc_client_packet_parse_real);
+SILC_TASK_CALLBACK(silc_client_rekey_callback);
+SILC_TASK_CALLBACK(silc_client_rekey_final);
static void silc_client_packet_parse(SilcPacketParserContext *parser_context);
static void silc_client_packet_parse_type(SilcClient client,
conn = silc_calloc(1, sizeof(*conn));
/* Initialize ID caches */
- conn->client_cache = silc_idcache_alloc(0, NULL);
- conn->channel_cache = silc_idcache_alloc(0, NULL);
- conn->server_cache = silc_idcache_alloc(0, NULL);
+ conn->client_cache = silc_idcache_alloc(0, SILC_ID_CLIENT, NULL);
+ conn->channel_cache = silc_idcache_alloc(0, SILC_ID_CHANNEL, NULL);
+ conn->server_cache = silc_idcache_alloc(0, SILC_ID_SERVER, NULL);
conn->client = client;
conn->remote_host = strdup(hostname);
conn->remote_port = port;
if (!client->sockets) {
client->sockets = silc_calloc(1, sizeof(*client->sockets));
- client->sockets[0] = sock;
+ client->sockets[0] = silc_socket_dup(sock);
client->sockets_count = 1;
return;
}
for (i = 0; i < client->sockets_count; i++) {
if (client->sockets[i] == NULL) {
- client->sockets[i] = sock;
+ client->sockets[i] = silc_socket_dup(sock);
return;
}
}
client->sockets = silc_realloc(client->sockets, sizeof(*client->sockets) *
(client->sockets_count + 1));
- client->sockets[client->sockets_count] = sock;
+ client->sockets[client->sockets_count] = silc_socket_dup(sock);
client->sockets_count++;
}
for (i = 0; i < client->sockets_count; i++) {
if (client->sockets[i] == sock) {
+ silc_socket_free(sock);
client->sockets[i] = NULL;
return;
}
protocol as context. */
proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
proto_ctx->client = (void *)client;
- proto_ctx->sock = conn->sock;
+ proto_ctx->sock = silc_socket_dup(conn->sock);
proto_ctx->rng = client->rng;
proto_ctx->responder = FALSE;
proto_ctx->send_packet = silc_client_protocol_ke_send_packet;
SILC_CLIENT_REGISTER_CONNECTION_FOR_IO(fd);
/* Execute the protocol */
- protocol->execute(client->timeout_queue, 0, protocol, fd, 0, 0);
+ silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
return TRUE;
}
if (ctx->dest_id)
silc_free(ctx->dest_id);
ctx->sock->protocol = NULL;
- silc_task_unregister_by_callback(client->timeout_queue,
- silc_client_failure_callback);
+ silc_socket_free(ctx->sock);
/* Notify application of failure */
client->ops->connect(client, ctx->sock->user_data, FALSE);
ctx->ske->prop->cipher,
ctx->ske->prop->pkcs,
ctx->ske->prop->hash,
- ctx->ske->prop->hmac);
+ ctx->ske->prop->hmac,
+ ctx->ske->prop->group);
silc_ske_free_key_material(ctx->keymat);
/* Allocate internal context for the authentication protocol. This
if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname,
sock->port, &proto_ctx->auth_meth,
&proto_ctx->auth_data,
- &proto_ctx->auth_data_len)) {
- client->ops->say(client, ctx->sock->user_data,
- "Could not resolve authentication method to use, "
- "assume no authentication");
+ &proto_ctx->auth_data_len))
proto_ctx->auth_meth = SILC_AUTH_NONE;
- }
/* Free old protocol as it is finished now */
silc_protocol_free(protocol);
silc_free(ctx);
sock->protocol = NULL;
- /* Allocate the authentication protocol. This is allocated here
- but we won't start it yet. We will be receiving party of this
- protocol thus we will wait that connecting party will make
- their first move. */
+ /* Allocate the authenteication protocol and execute it. */
silc_protocol_alloc(SILC_PROTOCOL_CLIENT_CONNECTION_AUTH,
&sock->protocol, (void *)proto_ctx,
silc_client_connect_to_server_final);
/* Execute the protocol */
- sock->protocol->execute(client->timeout_queue, 0, sock->protocol, fd, 0, 0);
+ silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0);
}
/* Finalizes the connection to the remote SILC server. This is called
if (ctx->dest_id)
silc_free(ctx->dest_id);
conn->sock->protocol = NULL;
- silc_task_unregister_by_callback(client->timeout_queue,
- silc_client_failure_callback);
+ silc_socket_free(ctx->sock);
/* Notify application of failure */
client->ops->connect(client, ctx->sock->user_data, FALSE);
/* Save remote ID. */
conn->remote_id = ctx->dest_id;
conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
- conn->remote_id_data_len = SILC_ID_SERVER_LEN;
+ conn->remote_id_data_len = silc_id_get_len(ctx->dest_id, SILC_ID_SERVER);
+
+ /* Register re-key timeout */
+ conn->rekey->timeout = 3600; /* XXX hardcoded */
+ conn->rekey->context = (void *)client;
+ silc_task_register(client->timeout_queue, conn->sock->sock,
+ silc_client_rekey_callback,
+ (void *)conn->sock, conn->rekey->timeout, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
- silc_task_unregister_by_callback(client->timeout_queue,
- silc_client_failure_callback);
silc_protocol_free(protocol);
if (ctx->auth_data)
silc_free(ctx->auth_data);
if (ctx->ske)
silc_ske_free(ctx->ske);
+ silc_socket_free(ctx->sock);
silc_free(ctx);
conn->sock->protocol = NULL;
}
int silc_client_packet_send_real(SilcClient client,
SilcSocketConnection sock,
- int force_send)
+ bool force_send,
+ bool flush)
{
int ret;
+ /* If rekey protocol is active we must assure that all packets are
+ sent through packet queue. */
+ if (flush == FALSE && SILC_CLIENT_IS_REKEY(sock))
+ force_send = FALSE;
+
/* Send the packet */
ret = silc_packet_send(sock, force_send);
if (ret != -2)
silc_buffer_push(sock->outbuf,
sock->outbuf->data - sock->outbuf->head);
- ret = silc_client_packet_send_real(client, sock, TRUE);
+ ret = silc_client_packet_send_real(client, sock, TRUE, TRUE);
/* If returned -2 could not write to connection now, will do
it later. */
/* Process the packet. This will call the parser that will then
decrypt and parse the packet. */
if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
- silc_packet_receive_process(sock, conn->receive_key, conn->hmac,
+ silc_packet_receive_process(sock, conn->receive_key, conn->hmac_receive,
silc_client_packet_parse, client);
else
silc_packet_receive_process(sock, NULL, NULL,
/* Decrypt the received packet */
if (sock->type != SILC_SOCKET_TYPE_UNKNOWN)
- ret = silc_packet_decrypt(conn->receive_key, conn->hmac, buffer, packet,
+ ret = silc_packet_decrypt(conn->receive_key, conn->hmac_receive,
+ buffer, packet,
silc_client_packet_decrypt_check, parse_ctx);
else
ret = silc_packet_decrypt(NULL, NULL, buffer, packet,
SILC_TASK_TIMEOUT,
SILC_TASK_PRI_NORMAL);
}
-
+
/* Parses the packet type and calls what ever routines the packet type
requires. This is done for all incoming packets. */
* one protocol for connection executing at once hence this
* success message is for whatever protocol is executing currently.
*/
- if (sock->protocol) {
- sock->protocol->execute(client->timeout_queue, 0,
- sock->protocol, sock->sock, 0, 0);
- }
+ if (sock->protocol)
+ silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0);
break;
case SILC_PACKET_FAILURE:
/*
break;
/* Let the protocol handle the packet */
- sock->protocol->execute(client->timeout_queue, 0,
- sock->protocol, sock->sock, 0, 0);
+ silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0);
} else {
SILC_LOG_ERROR(("Received Key Exchange packet but no key exchange "
"protocol active, packet dropped."));
-
- /* XXX Trigger KE protocol?? Rekey actually! */
}
break;
case SILC_PACKET_KEY_EXCHANGE_1:
if (sock->protocol && sock->protocol->protocol &&
- sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
- SilcClientKEInternalContext *proto_ctx =
- (SilcClientKEInternalContext *)sock->protocol->context;
-
- if (proto_ctx->packet)
- silc_packet_context_free(proto_ctx->packet);
-
- proto_ctx->packet = silc_packet_context_dup(packet);
- proto_ctx->dest_id_type = packet->src_id_type;
- proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
- packet->src_id_type);
- if (!proto_ctx->dest_id)
- break;
-
- /* Let the protocol handle the packet */
- sock->protocol->execute(client->timeout_queue, 0,
- sock->protocol, sock->sock, 0, 0);
+ (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
+ sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
+
+ if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
+ SilcClientRekeyInternalContext *proto_ctx =
+ (SilcClientRekeyInternalContext *)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 */
+ silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0);
+ } else {
+ SilcClientKEInternalContext *proto_ctx =
+ (SilcClientKEInternalContext *)sock->protocol->context;
+
+ if (proto_ctx->packet)
+ silc_packet_context_free(proto_ctx->packet);
+
+ proto_ctx->packet = silc_packet_context_dup(packet);
+ proto_ctx->dest_id_type = packet->src_id_type;
+ proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ packet->src_id_type);
+ if (!proto_ctx->dest_id)
+ break;
+
+ /* Let the protocol handle the packet */
+ silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0);
+ }
} else {
SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
"protocol active, packet dropped."));
break;
case SILC_PACKET_KEY_EXCHANGE_2:
if (sock->protocol && sock->protocol->protocol &&
- sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE) {
- SilcClientKEInternalContext *proto_ctx =
- (SilcClientKEInternalContext *)sock->protocol->context;
-
- if (proto_ctx->packet)
- silc_packet_context_free(proto_ctx->packet);
-
- proto_ctx->packet = silc_packet_context_dup(packet);
- proto_ctx->dest_id_type = packet->src_id_type;
- proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
- packet->src_id_type);
- if (!proto_ctx->dest_id)
- break;
-
- /* Let the protocol handle the packet */
- sock->protocol->execute(client->timeout_queue, 0,
- sock->protocol, sock->sock, 0, 0);
+ (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
+ sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY)) {
+
+ if (sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
+ SilcClientRekeyInternalContext *proto_ctx =
+ (SilcClientRekeyInternalContext *)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 */
+ silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0);
+ } else {
+ SilcClientKEInternalContext *proto_ctx =
+ (SilcClientKEInternalContext *)sock->protocol->context;
+
+ if (proto_ctx->packet)
+ silc_packet_context_free(proto_ctx->packet);
+
+ proto_ctx->packet = silc_packet_context_dup(packet);
+ proto_ctx->dest_id_type = packet->src_id_type;
+ proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ packet->src_id_type);
+ if (!proto_ctx->dest_id)
+ break;
+
+ /* Let the protocol handle the packet */
+ silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0);
+ }
} else {
SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
"protocol active, packet dropped."));
silc_client_key_agreement(client, sock, packet);
break;
+ case SILC_PACKET_REKEY:
+ SILC_LOG_DEBUG(("Re-key packet"));
+ /* We ignore this for now */
+ break;
+
+ case SILC_PACKET_REKEY_DONE:
+ SILC_LOG_DEBUG(("Re-key done packet"));
+
+ if (sock->protocol && sock->protocol->protocol &&
+ sock->protocol->protocol->type == SILC_PROTOCOL_CLIENT_REKEY) {
+
+ SilcClientRekeyInternalContext *proto_ctx =
+ (SilcClientRekeyInternalContext *)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 */
+ if (proto_ctx->responder == FALSE)
+ silc_protocol_execute(sock->protocol, client->timeout_queue, 0, 0);
+ else
+ /* Let the protocol handle the packet */
+ silc_protocol_execute(sock->protocol, client->timeout_queue,
+ 0, 100000);
+ } else {
+ SILC_LOG_ERROR(("Received Re-key done packet but no re-key "
+ "protocol active, packet dropped."));
+ }
+ break;
+
default:
SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
break;
SilcCipher cipher,
SilcHmac hmac,
unsigned char *data,
- unsigned int data_len,
+ uint32 data_len,
int force_send)
{
SilcPacketContext packetdata;
+ if (!sock)
+ return;
+
SILC_LOG_DEBUG(("Sending packet, type %d", type));
/* Get data used in the packet sending, keys and stuff */
if (!cipher && ((SilcClientConnection)sock->user_data)->send_key)
cipher = ((SilcClientConnection)sock->user_data)->send_key;
- if (!hmac && ((SilcClientConnection)sock->user_data)->hmac)
- hmac = ((SilcClientConnection)sock->user_data)->hmac;
+ if (!hmac && ((SilcClientConnection)sock->user_data)->hmac_send)
+ hmac = ((SilcClientConnection)sock->user_data)->hmac_send;
if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) {
dst_id = ((SilcClientConnection)sock->user_data)->remote_id;
packetdata.flags = 0;
packetdata.type = type;
if (sock->user_data &&
- ((SilcClientConnection)sock->user_data)->local_id_data)
+ ((SilcClientConnection)sock->user_data)->local_id_data) {
packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data;
- else
+ packetdata.src_id_len =
+ silc_id_get_len(((SilcClientConnection)sock->user_data)->local_id,
+ SILC_ID_CLIENT);
+ } else {
packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char));
- packetdata.src_id_len = SILC_ID_CLIENT_LEN;
+ packetdata.src_id_len = SILC_ID_CLIENT_LEN;
+ }
packetdata.src_id_type = SILC_ID_CLIENT;
if (dst_id) {
packetdata.dst_id = silc_id_id2str(dst_id, dst_id_type);
- packetdata.dst_id_len = silc_id_get_len(dst_id_type);
+ packetdata.dst_id_len = silc_id_get_len(dst_id, dst_id_type);
packetdata.dst_id_type = dst_id_type;
} else {
packetdata.dst_id = NULL;
sock->outbuf->data, sock->outbuf->len);
/* Now actually send the packet */
- silc_client_packet_send_real(client, sock, force_send);
+ silc_client_packet_send_real(client, sock, force_send, FALSE);
}
/* Closes connection to remote end. Free's all allocated data except
/* Close the actual connection */
silc_net_close_connection(sock->sock);
+ /* Cancel any active protocol */
+ if (sock->protocol) {
+ if (sock->protocol->protocol->type ==
+ SILC_PROTOCOL_CLIENT_KEY_EXCHANGE ||
+ sock->protocol->protocol->type ==
+ SILC_PROTOCOL_CLIENT_CONNECTION_AUTH) {
+ sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute_final(sock->protocol, client->timeout_queue);
+ sock->protocol = NULL;
+ /* The application will recall this function with these protocols
+ (the ops->connect client operation). */
+ return;
+ } else {
+ sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ silc_protocol_execute_final(sock->protocol, client->timeout_queue);
+ sock->protocol = NULL;
+ }
+ }
+
/* Free everything */
if (del && sock->user_data) {
/* XXX Free all client entries and channel entries. */
- client->ops->say(client, sock->user_data,
- "Closed connection to host %s", sock->hostname);
-
/* Clear ID caches */
- silc_idcache_del_all(conn->client_cache);
- silc_idcache_del_all(conn->channel_cache);
+ if (conn->client_cache)
+ silc_idcache_del_all(conn->client_cache);
+ if (conn->channel_cache)
+ silc_idcache_del_all(conn->channel_cache);
/* Free data */
if (conn->remote_host)
silc_cipher_free(conn->send_key);
if (conn->receive_key)
silc_cipher_free(conn->receive_key);
- if (conn->hmac)
- silc_hmac_free(conn->hmac);
- if (conn->hmac_key) {
- memset(conn->hmac_key, 0, conn->hmac_key_len);
- silc_free(conn->hmac_key);
- }
+ if (conn->hmac_send) /* conn->hmac_receive is same */
+ silc_hmac_free(conn->hmac_send);
if (conn->pending_commands)
silc_dlist_uninit(conn->pending_commands);
+ if (conn->rekey)
+ silc_free(conn->rekey);
- conn->sock = NULL;
- conn->remote_port = 0;
- conn->remote_type = 0;
- conn->send_key = NULL;
- conn->receive_key = NULL;
- conn->hmac = NULL;
- conn->hmac_key = NULL;
- conn->hmac_key_len = 0;
- conn->local_id = NULL;
- conn->local_id_data = NULL;
- conn->remote_host = NULL;
- conn->current_channel = NULL;
- conn->pending_commands = NULL;
-
+ memset(conn, 0, sizeof(*conn));
silc_client_del_connection(client, conn);
}
- if (sock->protocol) {
- silc_protocol_free(sock->protocol);
- sock->protocol = NULL;
- }
silc_socket_free(sock);
}
connecting = TRUE;
/* Delete old ID from ID cache */
- silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
+ if (conn->local_id) {
+ silc_idcache_del_by_context(conn->client_cache, conn->local_entry);
+ silc_free(conn->local_id);
+ }
/* Save the new ID */
- if (conn->local_id)
- silc_free(conn->local_id);
+
if (conn->local_id_data)
silc_free(conn->local_id_data);
conn->local_entry->id = conn->local_id;
/* Put it to the ID cache */
- silc_idcache_add(conn->client_cache, conn->nickname, strlen(conn->nickname),
- SILC_ID_CLIENT, conn->local_id, (void *)conn->local_entry,
- TRUE, FALSE);
+ silc_idcache_add(conn->client_cache, conn->nickname, conn->local_id,
+ (void *)conn->local_entry, FALSE);
/* Notify application of successful connection. We do it here now that
we've received the Client ID and are allowed to send traffic. */
SilcChannelEntry silc_client_new_channel_id(SilcClient client,
SilcSocketConnection sock,
char *channel_name,
- unsigned int mode,
+ uint32 mode,
SilcIDPayload idp)
{
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
conn->current_channel = channel;
/* Put it to the ID cache */
- silc_idcache_add(conn->channel_cache, channel_name, strlen(channel_name),
- SILC_ID_CHANNEL, (void *)channel->id, (void *)channel,
- TRUE, FALSE);
+ silc_idcache_add(conn->channel_cache, channel_name, (void *)channel->id,
+ (void *)channel, FALSE);
return channel;
}
SilcChannelEntry channel;
SilcChannelUser chu;
- if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
- SILC_ID_CHANNEL, &list))
+ if (!silc_idcache_get_all(conn->channel_cache, &list))
return;
silc_idcache_list_first(list, &id_cache);
SilcChannelEntry channel;
SilcChannelUser chu;
- if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
- SILC_ID_CHANNEL, &list))
+ if (!silc_idcache_get_all(conn->channel_cache, &list))
return;
silc_idcache_list_first(list, &id_cache);
silc_idcache_list_free(list);
}
-/* Parses mode mask and returns the mode as string. */
+/* Registers failure timeout to process the received failure packet
+ with timeout. */
-char *silc_client_chmode(unsigned int mode, SilcChannelEntry channel)
+void silc_client_process_failure(SilcClient client,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
{
- char string[100];
-
- if (!mode)
- return NULL;
-
- memset(string, 0, sizeof(string));
-
- if (mode & SILC_CHANNEL_MODE_PRIVATE)
- strncat(string, "p", 1);
-
- if (mode & SILC_CHANNEL_MODE_SECRET)
- strncat(string, "s", 1);
-
- if (mode & SILC_CHANNEL_MODE_PRIVKEY)
- strncat(string, "k", 1);
-
- if (mode & SILC_CHANNEL_MODE_INVITE)
- strncat(string, "i", 1);
+ uint32 failure = 0;
- if (mode & SILC_CHANNEL_MODE_TOPIC)
- strncat(string, "t", 1);
-
- if (mode & SILC_CHANNEL_MODE_ULIMIT)
- strncat(string, "l", 1);
-
- if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
- strncat(string, "a", 1);
-
- if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
- strncat(string, "f", 1);
-
- if (mode & SILC_CHANNEL_MODE_CIPHER) {
- char cipher[30];
- memset(cipher, 0, sizeof(cipher));
- snprintf(cipher, sizeof(cipher), " c (%s)",
- channel->channel_key->cipher->name);
- strncat(string, cipher, strlen(cipher));
- }
+ if (sock->protocol) {
+ if (packet->buffer->len >= 4)
+ SILC_GET32_MSB(failure, packet->buffer->data);
- if (mode & SILC_CHANNEL_MODE_HMAC) {
- char hmac[30];
- memset(hmac, 0, sizeof(hmac));
- snprintf(hmac, sizeof(hmac), " h (%s)",
- channel->hmac->hmac->name);
- strncat(string, hmac, strlen(hmac));
+ /* Notify application */
+ client->ops->failure(client, sock->user_data, sock->protocol,
+ (void *)failure);
}
-
- /* Rest of mode is ignored */
-
- return strdup(string);
}
-/* Parses channel user mode mask and returns te mode as string */
+/* A timeout callback for the re-key. We will be the initiator of the
+ re-key protocol. */
-char *silc_client_chumode(unsigned int mode)
+SILC_TASK_CALLBACK(silc_client_rekey_callback)
{
- char string[4];
-
- if (!mode)
- return NULL;
-
- memset(string, 0, sizeof(string));
-
- if (mode & SILC_CHANNEL_UMODE_CHANFO)
- strncat(string, "f", 1);
+ SilcSocketConnection sock = (SilcSocketConnection)context;
+ SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+ SilcClient client = (SilcClient)conn->rekey->context;
+ SilcProtocol protocol;
+ SilcClientRekeyInternalContext *proto_ctx;
- if (mode & SILC_CHANNEL_UMODE_CHANOP)
- strncat(string, "o", 1);
+ SILC_LOG_DEBUG(("Start"));
- return strdup(string);
+ /* Allocate internal protocol context. This is sent as context
+ to the protocol. */
+ proto_ctx = silc_calloc(1, sizeof(*proto_ctx));
+ proto_ctx->client = (void *)client;
+ proto_ctx->sock = silc_socket_dup(sock);
+ proto_ctx->responder = FALSE;
+ proto_ctx->pfs = conn->rekey->pfs;
+
+ /* Perform rekey protocol. Will call the final callback after the
+ protocol is over. */
+ silc_protocol_alloc(SILC_PROTOCOL_CLIENT_REKEY,
+ &protocol, proto_ctx, silc_client_rekey_final);
+ sock->protocol = protocol;
+
+ /* Run the protocol */
+ silc_protocol_execute(protocol, client->timeout_queue, 0, 0);
+
+ /* Re-register re-key timeout */
+ silc_task_register(client->timeout_queue, sock->sock,
+ silc_client_rekey_callback,
+ context, conn->rekey->timeout, 0,
+ SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
}
-/* Parses channel user mode and returns it as special mode character. */
+/* The final callback for the REKEY protocol. This will actually take the
+ new key material into use. */
-char *silc_client_chumode_char(unsigned int mode)
+SILC_TASK_CALLBACK(silc_client_rekey_final)
{
- char string[4];
-
- if (!mode)
- return NULL;
-
- memset(string, 0, sizeof(string));
-
- if (mode & SILC_CHANNEL_UMODE_CHANFO)
- strncat(string, "*", 1);
-
- if (mode & SILC_CHANNEL_UMODE_CHANOP)
- strncat(string, "@", 1);
-
- return strdup(string);
-}
-
-/* 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). */
+ SilcProtocol protocol = (SilcProtocol)context;
+ SilcClientRekeyInternalContext *ctx =
+ (SilcClientRekeyInternalContext *)protocol->context;
+ SilcClient client = (SilcClient)ctx->client;
+ SilcSocketConnection sock = ctx->sock;
-SILC_TASK_CALLBACK_GLOBAL(silc_client_failure_callback)
-{
- SilcClientFailureContext *f = (SilcClientFailureContext *)context;
+ SILC_LOG_DEBUG(("Start"));
- if (f->sock->protocol) {
- f->sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
- f->sock->protocol->execute(f->client->timeout_queue, 0,
- f->sock->protocol, f->sock->sock, 0, 0);
-
- /* Notify application */
- f->client->ops->failure(f->client, f->sock->user_data, f->sock->protocol,
- (void *)f->failure);
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+ protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
+ /* Error occured during protocol */
+ silc_protocol_cancel(protocol, client->timeout_queue);
+ silc_protocol_free(protocol);
+ sock->protocol = NULL;
+ if (ctx->packet)
+ silc_packet_context_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ silc_socket_free(ctx->sock);
+ silc_free(ctx);
+ return;
}
- silc_free(f);
-}
-
-/* Registers failure timeout to process the received failure packet
- with timeout. */
-
-void silc_client_process_failure(SilcClient client,
- SilcSocketConnection sock,
- SilcPacketContext *packet)
-{
- SilcClientFailureContext *f;
- unsigned int failure = 0;
-
- if (sock->protocol) {
- if (packet->buffer->len >= 4)
- SILC_GET32_MSB(failure, packet->buffer->data);
-
- f = silc_calloc(1, sizeof(*f));
- f->client = client;
- f->sock = sock;
- f->failure = failure;
-
- /* We will wait 5 seconds to process this failure packet */
- silc_task_register(client->timeout_queue, sock->sock,
- silc_client_failure_callback, (void *)f, 5, 0,
- SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
- }
+ /* Cleanup */
+ silc_protocol_free(protocol);
+ sock->protocol = NULL;
+ if (ctx->packet)
+ silc_packet_context_free(ctx->packet);
+ if (ctx->ske)
+ silc_ske_free(ctx->ske);
+ silc_socket_free(ctx->sock);
+ silc_free(ctx);
}