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
assert(server);
assert(server->config);
+ /* Set public and private keys */
+ if (!server->config->server_keys ||
+ !server->config->server_keys->public_key ||
+ !server->config->server_keys->private_key) {
+ SILC_LOG_ERROR(("Server public key and/or private key does not exist"));
+ return FALSE;
+ }
+ server->public_key = server->config->server_keys->public_key;
+ server->private_key = server->config->server_keys->private_key;
+
/* XXX After server is made as Silc Server Library this can be given
as argument, for now this is hard coded */
server->params = silc_calloc(1, sizeof(*server->params));
/* Initialize none cipher */
silc_cipher_alloc("none", &server->none_cipher);
- /* XXXXX Generate RSA key pair */
- {
- unsigned char *public_key;
- unsigned char *private_key;
- unsigned int pk_len, prv_len;
- struct stat st;
-
- if (stat("pubkey.pub", &st) < 0 && stat("privkey.prv", &st) < 0) {
-
- if (silc_pkcs_alloc("rsa", &server->pkcs) == FALSE) {
- SILC_LOG_ERROR(("Could not create RSA key pair"));
- goto err0;
- }
-
- if (server->pkcs->pkcs->init(server->pkcs->context,
- 1024, server->rng) == FALSE) {
- SILC_LOG_ERROR(("Could not generate RSA key pair"));
- goto err0;
- }
-
- public_key = server->pkcs->pkcs->get_public_key(server->pkcs->context,
- &pk_len);
- private_key = server->pkcs->pkcs->get_private_key(server->pkcs->context,
- &prv_len);
-
- SILC_LOG_HEXDUMP(("public key"), public_key, pk_len);
- SILC_LOG_HEXDUMP(("private key"), private_key, prv_len);
-
- server->public_key =
- silc_pkcs_public_key_alloc("rsa", "UN=root, HN=dummy",
- public_key, pk_len);
- server->private_key =
- silc_pkcs_private_key_alloc("rsa", private_key, prv_len);
-
- /* XXX Save keys */
- silc_pkcs_save_public_key("pubkey.pub", server->public_key,
- SILC_PKCS_FILE_PEM);
- silc_pkcs_save_private_key("privkey.prv", server->private_key, NULL,
- SILC_PKCS_FILE_BIN);
-
- memset(public_key, 0, pk_len);
- memset(private_key, 0, prv_len);
- silc_free(public_key);
- silc_free(private_key);
- } else {
- silc_pkcs_load_public_key("pubkey.pub", &server->public_key,
- SILC_PKCS_FILE_PEM);
- silc_pkcs_load_private_key("privkey.prv", &server->private_key,
- SILC_PKCS_FILE_BIN);
- }
- }
-
/* Create a listening server. Note that our server can listen on
multiple ports. All listeners are created here and now. */
/* XXX Still check this whether to use server_info or listen_port. */
SilcServerKEInternalContext *proto_ctx;
int sock;
+ SILC_LOG_INFO(("Connecting to the router %s on port %d",
+ sconn->remote_host, sconn->remote_port));
+
/* Connect to remote host */
sock = silc_net_create_connection(sconn->remote_port,
sconn->remote_host);
(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->pkcs,
ctx->ske->prop->hash,
ctx->ske->prop->hmac,
+ ctx->ske->prop->group,
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);
- silc_ske_free_key_material(ctx->keymat);
+ sock->protocol = NULL;
if (ctx->packet)
silc_packet_context_free(ctx->packet);
if (ctx->ske)
SilcBuffer packet;
SilcServerHBContext hb_context;
unsigned char *id_string;
+ SilcIDListData idata;
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);
/* Add the connected router to local server list */
server->standalone = FALSE;
- id_entry = silc_idlist_add_server(server->local_list, sock->hostname,
+ id_entry = silc_idlist_add_server(server->local_list, strdup(sock->hostname),
SILC_ROUTER, ctx->dest_id, NULL, sock);
if (!id_entry) {
if (ctx->dest_id)
sock->type = SILC_SOCKET_TYPE_ROUTER;
server->id_entry->router = id_entry;
server->router = id_entry;
- server->router->data.registered = TRUE;
+ idata = (SilcIDListData)sock->user_data;
+ idata->registered = TRUE;
/* Perform keepalive. The `hb_context' will be freed automatically
when finally calling the silc_socket_free function. XXX hardcoded
silc_server_perform_heartbeat,
server->timeout_queue);
+ /* Register re-key timeout */
+ idata->rekey->timeout = 3600; /* XXX hardcoded */
+ idata->rekey->context = (void *)server;
+ silc_task_register(server->timeout_queue, sock->sock,
+ silc_server_rekey_callback,
+ (void *)sock, idata->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);
process. Either we have to do our own resolver stuff or in the future
we can use threads. */
/* Perform name and address lookups for the remote host. */
- silc_net_check_host_by_sock(sock, &newsocket->hostname, &newsocket->ip);
- if ((server->params->require_reverse_mapping && !newsocket->hostname) ||
- !newsocket->ip) {
- SILC_LOG_ERROR(("IP/DNS lookup failed"));
- server->stat.conn_failures++;
- return;
+ if (!silc_net_check_host_by_sock(sock, &newsocket->hostname,
+ &newsocket->ip)) {
+ if ((server->params->require_reverse_mapping && !newsocket->hostname) ||
+ !newsocket->ip) {
+ SILC_LOG_ERROR(("IP/DNS lookup failed %s",
+ newsocket->hostname ? newsocket->hostname :
+ newsocket->ip ? newsocket->ip : ""));
+ server->stat.conn_failures++;
+ return;
+ }
+ if (!newsocket->hostname)
+ newsocket->hostname = strdup(newsocket->ip);
}
- if (!newsocket->hostname)
- newsocket->hostname = strdup(newsocket->ip);
newsocket->port = silc_net_get_remote_port(sock);
SILC_LOG_INFO(("Incoming connection from %s (%s)", newsocket->hostname,
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->pkcs,
ctx->ske->prop->hash,
ctx->ske->prop->hmac,
+ ctx->ske->prop->group,
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 (sock->outbuf->data - sock->outbuf->head)
silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
- ret = silc_server_packet_send_real(server, sock, TRUE);
+ /* Send the packet */
+ ret = silc_packet_send(sock, TRUE);
/* If returned -2 could not write to connection now, will do
it later. */
if (idata) {
idata->last_receive = time(NULL);
cipher = idata->receive_key;
- hmac = idata->hmac;
+ hmac = idata->hmac_receive;
}
/* Process the packet. This will call the parser that will then
return FALSE;
}
-
+
/* Parses whole packet, received earlier. */
SILC_TASK_CALLBACK(silc_server_packet_parse_real)
SilcServer server = (SilcServer)parse_ctx->context;
SilcSocketConnection sock = parse_ctx->sock;
SilcPacketContext *packet = parse_ctx->packet;
+ SilcIDListData idata = (SilcIDListData)sock->user_data;
int ret;
SILC_LOG_DEBUG(("Start"));
/* Decrypt the received packet */
- ret = silc_packet_decrypt(parse_ctx->cipher, parse_ctx->hmac,
+ ret = silc_packet_decrypt(idata ? idata->receive_key : NULL,
+ idata ? idata->hmac_receive : NULL,
packet->buffer, packet,
silc_server_packet_decrypt_check, parse_ctx);
if (ret < 0)
silc_server_packet_parse_type(server, sock, packet);
out:
- silc_buffer_clear(sock->inbuf);
+ /* silc_buffer_clear(sock->inbuf); */
silc_packet_context_free(packet);
silc_free(parse_ctx);
}
SilcSocketConnection sock = parser_context->sock;
switch (sock->type) {
- case SILC_SOCKET_TYPE_CLIENT:
case SILC_SOCKET_TYPE_UNKNOWN:
/* Parse the packet with timeout */
silc_task_register(server->timeout_queue, sock->sock,
SILC_TASK_TIMEOUT,
SILC_TASK_PRI_NORMAL);
break;
+ case SILC_SOCKET_TYPE_CLIENT:
+ /* Parse the packet with timeout (unless protocol is active) */
+ silc_task_register(server->timeout_queue, sock->sock,
+ silc_server_packet_parse_real,
+ (void *)parser_context, 0,
+ (sock->protocol ? 1 : 100000),
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+ break;
case SILC_SOCKET_TYPE_SERVER:
case SILC_SOCKET_TYPE_ROUTER:
/* Packets from servers are parsed as soon as possible */
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) {
-
- SilcServerKEInternalContext *proto_ctx =
- (SilcServerKEInternalContext *)sock->protocol->context;
+ if (sock->protocol && sock->protocol->protocol &&
+ (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE ||
+ sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)) {
- if (proto_ctx->packet)
- silc_packet_context_free(proto_ctx->packet);
+ if (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);
- 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(server->timeout_queue, 0,
+ sock->protocol, sock->sock, 0, 0);
+ } else {
+ SilcServerKEInternalContext *proto_ctx =
+ (SilcServerKEInternalContext *)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(server->timeout_queue, 0,
- sock->protocol, sock->sock,
- 0, 100000);
+ /* Let the protocol handle the packet */
+ sock->protocol->execute(server->timeout_queue, 0,
+ sock->protocol, sock->sock,
+ 0, 100000);
+ }
} else {
SILC_LOG_ERROR(("Received Key Exchange 1 packet but no key exchange "
"protocol active, packet dropped."));
if (packet->flags & SILC_PACKET_FLAG_LIST)
break;
- if (sock->protocol && sock->protocol->protocol->type
- == SILC_PROTOCOL_SERVER_KEY_EXCHANGE) {
-
- SilcServerKEInternalContext *proto_ctx =
- (SilcServerKEInternalContext *)sock->protocol->context;
+ if (sock->protocol && sock->protocol->protocol &&
+ (sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_KEY_EXCHANGE ||
+ sock->protocol->protocol->type == SILC_PROTOCOL_SERVER_REKEY)) {
- if (proto_ctx->packet)
- silc_packet_context_free(proto_ctx->packet);
+ if (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);
- 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(server->timeout_queue, 0,
+ sock->protocol, sock->sock, 0, 0);
+ } else {
+ SilcServerKEInternalContext *proto_ctx =
+ (SilcServerKEInternalContext *)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(server->timeout_queue, 0,
- sock->protocol, sock->sock,
- 0, 100000);
+ /* Let the protocol handle the packet */
+ sock->protocol->execute(server->timeout_queue, 0,
+ sock->protocol, sock->sock,
+ 0, 100000);
+ }
} else {
SILC_LOG_ERROR(("Received Key Exchange 2 packet but no key exchange "
"protocol active, packet dropped."));
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, 0);
+ } 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;
SILC_TASK_PRI_NORMAL);
}
+SILC_TASK_CALLBACK(silc_server_close_connection_final)
+{
+ silc_socket_free((SilcSocketConnection)context);
+}
+
/* Closes connection to socket connection */
void silc_server_close_connection(SilcServer server,
SilcSocketConnection sock)
{
- SILC_LOG_DEBUG(("Closing connection %d", sock->sock));
+ SILC_LOG_INFO(("Closing connection %s:%d [%s] (%d)", sock->hostname,
+ sock->port,
+ (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+ sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+ sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+ "Router"), sock->sock));
/* We won't listen for this connection anymore */
silc_schedule_unset_listen_fd(sock->sock);
/* Close the actual connection */
silc_net_close_connection(sock->sock);
server->sockets[sock->sock] = NULL;
- silc_socket_free(sock);
+
+ silc_task_register(server->timeout_queue, 0,
+ silc_server_close_connection_final,
+ (void *)sock, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
}
/* Sends disconnect message to remote connection and disconnects the
if (sock->outbuf->data - sock->outbuf->head)
silc_buffer_push(sock->outbuf, sock->outbuf->data - sock->outbuf->head);
- silc_server_packet_send_real(server, sock, TRUE);
+ silc_packet_send(sock, TRUE);
SILC_SET_CONNECTION_FOR_INPUT(sock->sock);
SILC_UNSET_OUTBUF_PENDING(sock);
{
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;
}
signoff_message, signoff_message ?
strlen(signoff_message) : 0);
- if (keygen) {
+ if (keygen && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
/* Re-generate channel key */
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"));
+ if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
+ SILC_LOG_DEBUG(("Channel has private keys, will not generate new key"));
+ return;
+ }
+
if (!channel->channel_key)
if (!silc_cipher_alloc("aes-256-cbc", &channel->channel_key))
return;
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"));
+
/* Decode channel key payload */
payload = silc_channel_key_payload_parse(key_payload);
if (!payload) {
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;
return silc_notify_payload_encode(SILC_NOTIFY_TYPE_JOIN, argc, ap);
}
+/* Returns assembled packets for channel users of the `channel'. */
+
+void silc_server_announce_get_channel_users(SilcServer server,
+ SilcChannelEntry channel,
+ SilcBuffer *channel_users)
+{
+ SilcChannelClientEntry chl;
+ SilcBuffer chidp, clidp;
+ SilcBuffer tmp;
+ int len;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ /* 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) {
+ clidp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
+ 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 ?
+ (*channel_users)->truelen + len : len));
+ silc_buffer_pull_tail(*channel_users,
+ ((*channel_users)->end -
+ (*channel_users)->data));
+
+ silc_buffer_put(*channel_users, tmp->data, tmp->len);
+ silc_buffer_pull(*channel_users, len);
+ silc_buffer_free(clidp);
+ silc_buffer_free(tmp);
+ }
+ silc_buffer_free(chidp);
+}
+
/* 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. */
-static void silc_server_announce_get_channels(SilcServer server,
- SilcIDList id_list,
- SilcBuffer *channels,
- SilcBuffer *channel_users)
+void silc_server_announce_get_channels(SilcServer server,
+ SilcIDList id_list,
+ SilcBuffer *channels,
+ SilcBuffer *channel_users)
{
SilcIDCacheList list;
SilcIDCacheEntry id_cache;
SilcChannelEntry channel;
- SilcChannelClientEntry chl;
- SilcBuffer chidp;
unsigned char *cid;
- unsigned short name_len;
+ uint16 name_len;
int len;
+ SILC_LOG_DEBUG(("Start"));
+
/* Go through all channels in the list */
if (silc_idcache_find_by_id(id_list->channels, SILC_ID_CACHE_ANY,
SILC_ID_CHANNEL, &list)) {
name_len),
SILC_STR_UI_SHORT(SILC_ID_CHANNEL_LEN),
SILC_STR_UI_XNSTRING(cid, SILC_ID_CHANNEL_LEN),
- SILC_STR_UI_INT(0),
+ SILC_STR_UI_INT(channel->mode),
SILC_STR_END);
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) {
- SilcBuffer clidp;
- SilcBuffer tmp;
-
- clidp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
-
- 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 ?
- (*channel_users)->truelen + len : len));
- silc_buffer_pull_tail(*channel_users,
- ((*channel_users)->end -
- (*channel_users)->data));
-
- silc_buffer_put(*channel_users, tmp->data, tmp->len);
- silc_buffer_pull(*channel_users, len);
- silc_buffer_free(clidp);
- silc_buffer_free(tmp);
- }
- silc_buffer_free(chidp);
+ silc_server_announce_get_channel_users(server, channel,
+ channel_users);
silc_free(cid);
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;
}
}
-/* Lookups route to the client indicated by `id' client ID. The connection
+/* Lookups route to the client indicated by the `id_data'. The connection
object and internal data object is returned. Returns NULL if route
could not be found to the client. If the `client_id' is specified then
it is used and the `id_data' is ignored. */
SilcSocketConnection silc_server_get_client_route(SilcServer server,
unsigned char *id_data,
- unsigned int id_len,
+ uint32 id_len,
SilcClientID *client_id,
SilcIDListData *idata)
{
/* We are of course in this case the client's router thus the real
"router" of the client is the server who owns the client. Thus
we will send the packet to that server. */
- *idata = (SilcIDListData)client->router;
+ if (idata)
+ *idata = (SilcIDListData)client->router;
return client->router->connection;
}
/* Seems that client really is directly connected to us */
- *idata = (SilcIDListData)client;
+ if (idata)
+ *idata = (SilcIDListData)client;
return client->connection;
}
server our action is to send the packet to our router. */
if (server->server_type == SILC_SERVER && !server->standalone) {
silc_free(id);
- *idata = (SilcIDListData)server->router;
+ if (idata)
+ *idata = (SilcIDListData)server->router;
return server->router->connection;
}
dst_sock = silc_server_route_get(server, id, SILC_ID_CLIENT);
silc_free(id);
- *idata = (SilcIDListData)dst_sock->user_data;
+ if (idata)
+ *idata = (SilcIDListData)dst_sock->user_data;
return dst_sock;
}
}
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)
+{
+ SilcSocketConnection sock = (SilcSocketConnection)context;
+ SilcIDListData idata = (SilcIDListData)sock->user_data;
+ SilcServer server = (SilcServer)idata->rekey->context;
+ 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->sock = sock;
+ proto_ctx->responder = FALSE;
+ proto_ctx->pfs = idata->rekey->pfs;
+
+ /* 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);
+ sock->protocol = protocol;
+
+ /* Run the protocol */
+ protocol->execute(server->timeout_queue, 0, protocol,
+ sock->sock, 0, 0);
+
+ /* Re-register re-key timeout */
+ silc_task_register(server->timeout_queue, sock->sock,
+ silc_server_rekey_callback,
+ context, idata->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_cancel(server->timeout_queue, protocol);
+ 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_free(ctx);
+ return;
+ }
+
+#if 0
+ /* Take the keys into use */
+ if (ctx->pfs == TRUE)
+ silc_server_protocol_rekey_generate_pfs(server, ctx);
+ else
+ silc_server_protocol_rekey_generate(server, ctx);
+#endif
+
+ /* 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_free(ctx);
+}