/* Set log files where log message should be saved. */
server->config->server = server;
- silc_server_config_setlogfiles(server->config);
/* Register all configured ciphers, PKCS and hash functions. */
if (!silc_server_config_register_ciphers(server->config))
silc_hash_alloc("md5", &server->md5hash);
silc_hash_alloc("sha1", &server->sha1hash);
- /* Initialize none cipher */
- silc_cipher_alloc("none", &server->none_cipher);
-
/* Allocate PKCS context for local public and private keys */
silc_pkcs_alloc(server->public_key->name, &server->pkcs);
silc_pkcs_public_key_set(server->pkcs, server->public_key);
server->schedule = silc_schedule_init(SILC_SERVER_MAX_CONNECTIONS);
if (!server->schedule)
goto err0;
-
+
/* Add the first task to the scheduler. This is task that is executed by
timeout. It expires as soon as the caller calls silc_server_run. This
task performs authentication protocol and key exchange with our
SILC_TASK_PRI_NORMAL);
server->listenning = TRUE;
+ /* Send log file configuration */
+ silc_server_config_setlogfiles(server->config, server->schedule);
+
/* If server connections has been configured then we must be router as
normal server cannot have server connections, only router connections. */
if (server->config->servers) {
return FALSE;
}
-/* Fork server to background and set gid+uid to non-root */
+/* Fork server to background */
void silc_server_daemonise(SilcServer server)
{
int i;
- i = fork ();
+ SILC_LOG_DEBUG(("Forking SILC server to background"));
- if (i) {
- if (i > 0) {
- if (geteuid())
- SILC_LOG_DEBUG(("Server started as user"));
- else
- SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
+ i = fork();
- SILC_LOG_DEBUG(("Forking SILC server to background"));
- exit(0);
- } else {
- SILC_LOG_DEBUG(("fork() failed, cannot proceed"));
- exit(1);
- }
+ if (i < 0) {
+ SILC_LOG_DEBUG(("fork() failed, cannot proceed"));
+ exit(1);
+ }
+ else if (i) {
+ if (geteuid())
+ SILC_LOG_DEBUG(("Server started as user"));
+ else
+ SILC_LOG_DEBUG(("Server started as root. Dropping privileges."));
+ exit(0);
}
setsid();
}
{
/* Are we executing silcd as root or a regular user? */
if (!geteuid()) {
-
struct passwd *pw;
struct group *gr;
char *user, *group;
{
SILC_LOG_DEBUG(("Stopping server"));
- silc_schedule_stop(server->schedule);
- silc_schedule_uninit(server->schedule);
+ if (server->schedule) {
+ silc_schedule_stop(server->schedule);
+ silc_schedule_uninit(server->schedule);
+ server->schedule = NULL;
+ }
silc_server_protocols_unregister();
SilcServerKEInternalContext *proto_ctx;
void *context;
+ /* Cancel any possible retry timeouts */
+ silc_schedule_task_del_by_callback(server->schedule,
+ silc_server_connect_router);
+
/* Set socket options */
silc_net_set_socket_nonblock(sock);
silc_net_set_socket_opt(sock, SOL_SOCKET, SO_REUSEADDR, 1);
sconn->remote_port,
sconn->remote_host);
if (sock < 0) {
- SILC_LOG_ERROR(("Could not connect to router"));
- silc_schedule_task_add(server->schedule, fd,
- silc_server_connect_to_router_retry,
- context, 0, 1, SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_NORMAL);
+ SILC_LOG_ERROR(("Could not connect to router %s:%d",
+ sconn->remote_host, sconn->remote_port));
+ if (!sconn->no_reconnect)
+ silc_schedule_task_add(server->schedule, fd,
+ silc_server_connect_to_router_retry,
+ context, 0, 1, SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
return;
}
sconn->backup_replace_port = ptr->backup_replace_port;
}
+ if (!server->router_conn && !sconn->backup)
+ server->router_conn = sconn;
+
silc_schedule_task_add(server->schedule, fd,
silc_server_connect_router,
(void *)sconn, 0, 1, SILC_TASK_TIMEOUT,
timeout!! */
hb_context = silc_calloc(1, sizeof(*hb_context));
hb_context->server = server;
- silc_socket_set_heartbeat(sock, 600, hb_context,
+ silc_socket_set_heartbeat(sock, 300, hb_context,
silc_server_perform_heartbeat,
server->schedule);
silc_free(sconn->backup_replace_ip);
silc_free(sconn);
}
+ if (sconn == server->router_conn)
+ server->router_conn = NULL;
/* Free the protocol object */
if (sock->protocol == protocol)
sock->hostname,
port);
if (!cconfig && !sconfig && !rconfig) {
+ SILC_LOG_INFO(("Connection %s (%s) is not allowed",
+ sock->hostname, sock->ip));
silc_server_disconnect_remote(server, sock,
"Server closed connection: "
"Connection refused");
SilcSocketConnection sock = ctx->sock;
SilcServerHBContext hb_context;
SilcUnknownEntry entry = (SilcUnknownEntry)sock->user_data;
- void *id_entry = NULL;
+ void *id_entry;
SILC_LOG_DEBUG(("Start"));
break;
}
default:
+ goto out;
break;
}
sock->type = ctx->conn_type;
/* Add the common data structure to the ID entry. */
- if (id_entry)
- silc_idlist_add_data(id_entry, (SilcIDListData)sock->user_data);
-
+ silc_idlist_add_data(id_entry, (SilcIDListData)sock->user_data);
+
/* Add to sockets internal pointer for fast referencing */
silc_free(sock->user_data);
sock->user_data = id_entry;
timeout!! */
hb_context = silc_calloc(1, sizeof(*hb_context));
hb_context->server = server;
- silc_socket_set_heartbeat(sock, 600, hb_context,
+ silc_socket_set_heartbeat(sock, 400, hb_context,
silc_server_perform_heartbeat,
server->schedule);
close the connection */
if (SILC_IS_DISCONNECTING(sock)) {
if (sock->user_data)
- silc_server_free_sock_user_data(server, sock);
+ silc_server_free_sock_user_data(server, sock, NULL);
silc_server_close_connection(server, sock);
return;
}
SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
SILC_SET_DISCONNECTING(sock);
- if (sock->user_data)
- silc_server_free_sock_user_data(server, sock);
+ if (sock->user_data) {
+ char tmp[128];
+ if (silc_socket_get_error(sock, tmp, sizeof(tmp) - 1))
+ silc_server_free_sock_user_data(server, sock, tmp);
+ else
+ silc_server_free_sock_user_data(server, sock, NULL);
+ } else if (server->router_conn && server->router_conn->sock == sock &&
+ !server->router && server->standalone)
+ silc_schedule_task_add(server->schedule, 0,
+ silc_server_connect_to_router,
+ server, 1, 0,
+ SILC_TASK_TIMEOUT,
+ SILC_TASK_PRI_NORMAL);
+
silc_server_close_connection(server, sock);
return;
}
/* Process the packet. This will call the parser that will then
decrypt and parse the packet. */
- silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ?
- TRUE : FALSE, cipher, hmac, sequence,
- silc_server_packet_parse, server);
+ ret = silc_packet_receive_process(sock, server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, cipher, hmac, sequence,
+ silc_server_packet_parse, server);
+
+ /* If this socket connection is not authenticated yet and the packet
+ processing failed we will drop the connection since it can be
+ a malicious flooder. */
+ if (sock->type == SILC_SOCKET_TYPE_UNKNOWN && ret == FALSE &&
+ (!sock->protocol || sock->protocol->protocol->type ==
+ SILC_PROTOCOL_SERVER_KEY_EXCHANGE)) {
+ SILC_LOG_DEBUG(("Bad data sent from unknown connection %d", sock->sock));
+ SILC_SET_DISCONNECTING(sock);
+
+ if (sock->user_data)
+ silc_server_free_sock_user_data(server, sock, NULL);
+ silc_server_close_connection(server, sock);
+ }
}
/* Parses whole packet, received earlier. */
/* Creates connection to a remote router. */
void silc_server_create_connection(SilcServer server,
- char *remote_host, uint32 port)
+ const char *remote_host, uint32 port)
{
SilcServerConnection sconn;
sconn->server = server;
sconn->remote_host = strdup(remote_host);
sconn->remote_port = port;
+ sconn->no_reconnect = TRUE;
silc_schedule_task_add(server->schedule, 0,
silc_server_connect_router,
SilcSocketConnection sock,
SilcClientEntry client,
int notify,
- char *signoff)
+ const char *signoff)
{
FreeClientInternal i = silc_calloc(1, sizeof(*i));
/* Remove client from all channels */
if (notify)
silc_server_remove_from_channels(server, NULL, client,
- TRUE, signoff, TRUE);
+ TRUE, (char *)signoff, TRUE);
else
silc_server_remove_from_channels(server, NULL, client,
FALSE, NULL, FALSE);
+ /* Update statistics */
+ server->stat.my_clients--;
+ server->stat.clients--;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.cell_clients--;
+ SILC_OPER_STATS_UPDATE(client, server, SILC_UMODE_SERVER_OPERATOR);
+ SILC_OPER_STATS_UPDATE(client, router, SILC_UMODE_ROUTER_OPERATOR);
+
/* We will not delete the client entry right away. We will take it
into history (for WHOWAS command) for 5 minutes */
i->server = server;
client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
client->router = NULL;
client->connection = NULL;
-
- /* Free the client entry and everything in it */
- server->stat.my_clients--;
- server->stat.clients--;
- if (server->server_type == SILC_ROUTER)
- server->stat.cell_clients--;
+ client->mode = 0;
}
/* Frees user_data pointer from socket connection object. This also sends
entities. */
void silc_server_free_sock_user_data(SilcServer server,
- SilcSocketConnection sock)
+ SilcSocketConnection sock,
+ const char *signoff_message)
{
SILC_LOG_DEBUG(("Start"));
case SILC_SOCKET_TYPE_CLIENT:
{
SilcClientEntry user_data = (SilcClientEntry)sock->user_data;
- silc_server_free_client_data(server, sock, user_data, TRUE, NULL);
+ silc_server_free_client_data(server, sock, user_data, TRUE,
+ signoff_message);
break;
}
case SILC_SOCKET_TYPE_SERVER:
/* Check whether we have a backup router connection */
if (!backup_router || backup_router == user_data) {
silc_schedule_task_add(server->schedule, 0,
- silc_server_connect_to_router,
+ silc_server_connect_to_router,
server, 1, 0,
SILC_TASK_TIMEOUT,
SILC_TASK_PRI_NORMAL);
/* If we have protocol active we must assure that we call the protocol's
final callback so that all the memory is freed. */
if (sock->protocol) {
+ silc_protocol_cancel(sock->protocol, server->schedule);
sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
silc_protocol_execute_final(sock->protocol, server->schedule);
+ sock->protocol = NULL;
return;
}
if (sock->user_data)
- silc_server_free_sock_user_data(server, sock);
+ silc_server_free_sock_user_data(server, sock, NULL);
silc_server_disconnect_remote(server, sock, "Server closed connection: "
"Connection timeout");
channel_name = strdup(channel_name);
- /* Create the channel */
+ /* Create the channel ID */
if (!silc_id_create_channel_id(server, router_id, server->rng,
&channel_id)) {
silc_free(channel_name);
silc_hmac_free(newhmac);
return NULL;
}
+
+ /* Create the channel */
entry = silc_idlist_add_channel(server->local_list, channel_name,
SILC_CHANNEL_MODE_NONE, channel_id,
NULL, key, newhmac, 0);
silc_free(channel_name);
silc_cipher_free(key);
silc_hmac_free(newhmac);
+ silc_free(channel_id);
return NULL;
}
/* Now create the actual key material */
if (!silc_server_create_channel_key(server, entry,
silc_cipher_get_key_len(key) / 8)) {
- silc_free(channel_name);
- silc_cipher_free(key);
- silc_hmac_free(newhmac);
- silc_free(entry->cipher);
- silc_free(entry->hmac_name);
+ silc_idlist_del_channel(server->local_list, entry);
return NULL;
}
SILC_CHANNEL_MODE_NONE, channel_id,
NULL, key, newhmac, 0);
if (!entry) {
+ silc_cipher_free(key);
+ silc_hmac_free(newhmac);
silc_free(channel_name);
return NULL;
}
/* Now create the actual key material */
if (!silc_server_create_channel_key(server, entry,
silc_cipher_get_key_len(key) / 8)) {
- silc_free(channel_name);
+ silc_idlist_del_channel(server->local_list, entry);
return NULL;
}
SILC_LOG_DEBUG(("Start"));
/* Decode channel key payload */
- payload = silc_channel_key_payload_parse(key_payload->data,
+ payload = silc_channel_key_payload_parse(key_payload->data,
key_payload->len);
if (!payload) {
- SILC_LOG_ERROR(("Bad channel key payload, dropped"));
+ SILC_LOG_ERROR(("Bad channel key payload received, dropped"));
channel = NULL;
goto out;
}
if (!channel) {
channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
if (!channel) {
- SILC_LOG_ERROR(("Received key for non-existent channel"));
+ SILC_LOG_ERROR(("Received key for non-existent channel %s",
+ silc_id_render(id, SILC_ID_CHANNEL)));
goto out;
}
}
{
SilcServerHBContext hb = (SilcServerHBContext)hb_context;
- SILC_LOG_DEBUG(("Sending heartbeat to %s (%s)", sock->hostname,
- sock->ip));
+ SILC_LOG_DEBUG(("Sending heartbeat to %s (%s)", sock->hostname, sock->ip));
/* Send the heartbeat */
silc_server_send_heartbeat(hb->server, sock);
int i;
for (i = 0; i < channel_users_modes_c; i++) {
+ if (!channel_users_modes[i])
+ continue;
silc_buffer_push(channel_users_modes[i],
channel_users_modes[i]->data -
channel_users_modes[i]->head);
SilcIDCacheEntry cache;
bool global;
+ SILC_LOG_DEBUG(("Start"));
+
for (i = 0; i < user_count; i++) {
/* Client ID */
SILC_GET16_MSB(idp_len, user_list->data + 2);
it using WHOIS command. */
SilcClientEntry silc_server_get_client_resolve(SilcServer server,
- SilcClientID *client_id)
+ SilcClientID *client_id,
+ bool *resolved)
{
SilcClientEntry client;
+ if (resolved)
+ *resolved = FALSE;
+
client = silc_idlist_find_client_by_id(server->local_list, client_id,
TRUE, NULL);
if (!client) {
buffer->data, buffer->len, FALSE);
silc_buffer_free(idp);
silc_buffer_free(buffer);
+
+ if (resolved)
+ *resolved = TRUE;
+
return NULL;
}