int silc_server_init(SilcServer server)
{
- int *sock = NULL, sock_count = 0, i;
+ int *sock = NULL, sock_count, i;
SilcServerID *id;
SilcServerEntry id_entry;
SilcIDListPurge purge;
- SilcServerConfigSectionListenPort *listen;
SILC_LOG_DEBUG(("Initializing server"));
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) {
+ if (!server->config->server_info ||
+ !server->config->server_info->public_key ||
+ !server->config->server_info->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;
+ server->public_key = server->config->server_info->public_key;
+ server->private_key = server->config->server_info->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->protocol_timeout = 60;
server->params->require_reverse_mapping = FALSE;
- /* 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))
+ if (!silc_server_config_register_ciphers(server))
silc_cipher_register_default();
- if (!silc_server_config_register_pkcs(server->config))
+ if (!silc_server_config_register_pkcs(server))
silc_pkcs_register_default();
- if (!silc_server_config_register_hashfuncs(server->config))
+ if (!silc_server_config_register_hashfuncs(server))
silc_hash_register_default();
- if (!silc_server_config_register_hmacs(server->config))
+ if (!silc_server_config_register_hmacs(server))
silc_hmac_register_default();
/* Initialize random number generator for the server. */
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);
/* Create a listening server. Note that our server can listen on multiple
ports. All listeners are created here and now. */
sock_count = 0;
- listen = server->config->listen_port;
- while(listen) {
+ while (1) {
int tmp;
- tmp = silc_net_create_server(server->config->listen_port->port,
- server->config->listen_port->listener_ip);
+ tmp = silc_net_create_server(server->config->server_info->port,
+ server->config->server_info->server_ip);
+
if (tmp < 0) {
- SILC_LOG_ERROR(("Could not create server listener: %s on %d",
- server->config->listen_port->listener_ip,
- server->config->listen_port->port));
+ SILC_LOG_ERROR(("Could not create server listener: %s on %hd",
+ server->config->server_info->server_ip,
+ server->config->server_info->port));
goto err0;
}
- sock = silc_realloc(sock, (sizeof(int *) * (sock_count + 1)));
+ sock = silc_realloc(sock, sizeof(*sock) * (sock_count + 1));
sock[sock_count] = tmp;
sock_count++;
- listen = listen->next;
+ break;
}
/* Initialize ID caches */
silc_net_set_socket_nonblock(sock[i]);
server->sock = sock[i];
+ /* Add ourselves also to the socket table. The entry allocated above
+ is sent as argument for fast referencing in the future. */
+ silc_socket_alloc(sock[i], SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
+ server->sockets[sock[i]] = newsocket;
+
+ /* Perform name and address lookups to resolve the listenning address
+ and port. */
+ if (!silc_net_check_local_by_sock(sock[i], &newsocket->hostname,
+ &newsocket->ip)) {
+ if ((server->params->require_reverse_mapping && !newsocket->hostname) ||
+ !newsocket->ip) {
+ SILC_LOG_ERROR(("IP/DNS lookup failed for local host %s",
+ newsocket->hostname ? newsocket->hostname :
+ newsocket->ip ? newsocket->ip : ""));
+ server->stat.conn_failures++;
+ goto err0;
+ }
+ if (!newsocket->hostname)
+ newsocket->hostname = strdup(newsocket->ip);
+ }
+ newsocket->port = silc_net_get_local_port(sock[i]);
+
/* Create a Server ID for the server. */
- silc_id_create_server_id(sock[i], server->rng, &id);
- if (!id) {
+ silc_id_create_server_id(newsocket->ip, newsocket->port, server->rng, &id);
+ if (!id)
goto err0;
- }
server->id = id;
server->id_string = silc_id_id2str(id, SILC_ID_SERVER);
}
id_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
- /* Add ourselves also to the socket table. The entry allocated above
- is sent as argument for fast referencing in the future. */
- silc_socket_alloc(sock[i], SILC_SOCKET_TYPE_SERVER, id_entry,
- &newsocket);
-
- server->sockets[sock[i]] = newsocket;
-
- /* Perform name and address lookups to resolve the listenning address
- and port. */
- if (!silc_net_check_local_by_sock(sock[i], &newsocket->hostname,
- &newsocket->ip)) {
- if ((server->params->require_reverse_mapping && !newsocket->hostname) ||
- !newsocket->ip) {
- SILC_LOG_ERROR(("IP/DNS lookup failed for local host %s",
- newsocket->hostname ? newsocket->hostname :
- newsocket->ip ? newsocket->ip : ""));
- server->stat.conn_failures++;
- goto err0;
- }
- if (!newsocket->hostname)
- newsocket->hostname = strdup(newsocket->ip);
- }
- newsocket->port = silc_net_get_local_port(sock[i]);
-
/* Put the allocated socket pointer also to the entry allocated above
for fast back-referencing to the socket list. */
- id_entry->connection = (void *)server->sockets[sock[i]];
+ newsocket->user_data = (void *)id_entry;
+ id_entry->connection = (void *)newsocket;
server->id_entry = id_entry;
}
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) {
- SilcServerConfigSectionServerConnection *ptr = server->config->servers;
+ SilcServerConfigSectionServer *ptr = server->config->servers;
server->server_type = SILC_ROUTER;
while (ptr) {
purge = silc_calloc(1, sizeof(*purge));
purge->cache = server->local_list->clients;
purge->schedule = server->schedule;
+ purge->timeout = 600;
silc_schedule_task_add(purge->schedule, 0,
silc_idlist_purge,
- (void *)purge, 600, 0,
+ (void *)purge, purge->timeout, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
/* Clients global list */
purge = silc_calloc(1, sizeof(*purge));
purge->cache = server->global_list->clients;
purge->schedule = server->schedule;
+ purge->timeout = 300;
silc_schedule_task_add(purge->schedule, 0,
silc_idlist_purge,
- (void *)purge, 300, 0,
+ (void *)purge, purge->timeout, 0,
SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
SILC_LOG_DEBUG(("Server initialized"));
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;
- if (!server->config->identity || !server->config->identity->user ||
- !server->config->identity->group) {
+ if (!server->config->server_info->user || !server->config->server_info->group) {
fprintf(stderr, "Error:"
"\tSILC server must not be run as root. For the security of your\n"
"\tsystem it is strongly suggested that you run SILC under dedicated\n"
}
/* Get the values given for user and group in configuration file */
- user=server->config->identity->user;
- group=server->config->identity->group;
+ user=server->config->server_info->user;
+ group=server->config->server_info->group;
/* Check whether the user/group information is text */
if (atoi(user)!=0 || atoi(group)!=0) {
{
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);
if (sconn->retry_count > server->params->retry_count &&
server->params->retry_keep_trying == FALSE) {
SILC_LOG_ERROR(("Could not connect to router, giving up"));
+ silc_free(sconn->remote_host);
+ silc_free(sconn);
return;
}
server->router_connect = time(0);
/* Connect to remote host */
- sock = silc_net_create_connection(server->config->listen_port->local_ip,
+ sock = silc_net_create_connection(server->config->server_info->server_ip,
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;
}
{
SilcServer server = (SilcServer)context;
SilcServerConnection sconn;
- SilcServerConfigSectionServerConnection *ptr;
+ SilcServerConfigSectionRouter *ptr;
SILC_LOG_DEBUG(("Connecting to router(s)"));
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,
SilcServerConnection sconn = (SilcServerConnection)ctx->context;
SilcSocketConnection sock = ctx->sock;
SilcServerConnAuthInternalContext *proto_ctx;
- SilcServerConfigSectionServerConnection *conn = NULL;
+ SilcServerConfigSectionRouter *conn = NULL;
SILC_LOG_DEBUG(("Start"));
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)
silc_packet_context_free(ctx->packet);
if (ctx->ske)
silc_ske_free(ctx->ske);
+ silc_free(ctx->auth_data);
silc_free(ctx);
}
SilcServer server = (SilcServer)context;
SilcServerKEInternalContext *proto_ctx;
void *cconfig, *sconfig, *rconfig;
- SilcServerConfigSectionDenyConnection *deny;
+ SilcServerConfigSectionDeny *deny;
int port;
SILC_LOG_DEBUG(("Start"));
port = server->sockets[server->sock]->port; /* Listenning port */
/* Check whether this connection is denied to connect to us. */
- deny = silc_server_config_denied_conn(server->config, sock->ip, port);
+ deny = silc_server_config_find_denied(server->config, sock->ip, port);
if (!deny)
- deny = silc_server_config_denied_conn(server->config, sock->hostname,
+ deny = silc_server_config_find_denied(server->config, sock->hostname,
port);
if (deny) {
/* The connection is denied */
SILC_LOG_INFO(("Connection %s (%s) is denied",
sock->hostname, sock->ip));
- silc_server_disconnect_remote(server, sock, deny->comment ?
- deny->comment :
+ silc_server_disconnect_remote(server, sock, deny->reason ?
+ deny->reason :
"Server closed connection: "
"Connection refused");
server->stat.conn_failures++;
/* Check whether we have configred this sort of connection at all. We
have to check all configurations since we don't know what type of
connection this is. */
- if (!(cconfig = silc_server_config_find_client_conn(server->config,
+ if (!(cconfig = silc_server_config_find_client(server->config,
sock->ip, port)))
- cconfig = silc_server_config_find_client_conn(server->config,
+ cconfig = silc_server_config_find_client(server->config,
sock->hostname,
port);
if (!(sconfig = silc_server_config_find_server_conn(server->config,
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"));
and other information is created after we have received NEW_CLIENT
packet from client. */
client = silc_idlist_add_client(server->local_list,
- NULL, NULL, NULL, NULL, NULL, sock);
+ NULL, NULL, NULL, NULL, NULL, sock, 0);
if (!client) {
SILC_LOG_ERROR(("Could not add new client to cache"));
silc_free(sock->user_data);
case SILC_SOCKET_TYPE_ROUTER:
{
SilcServerEntry new_server;
- SilcServerConfigSectionServerConnection *conn =
+ /* XXX FIXME: Now server and router has different table, so this is probably broken. */
+ SilcServerConfigSectionRouter *conn =
ctx->conn_type == SILC_SOCKET_TYPE_SERVER ?
ctx->sconfig : ctx->rconfig;
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. */
if (!(packet->flags & SILC_PACKET_FLAG_BROADCAST) &&
packet->dst_id_type == SILC_ID_SERVER &&
sock->type != SILC_SOCKET_TYPE_CLIENT &&
- memcmp(packet->dst_id, server->id_string, packet->dst_id_len)) {
+ memcmp(packet->dst_id, server->id_string, server->id_string_len)) {
/* Route the packet to fastest route for the destination ID */
void *id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
/* 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);
silc_hash_table_del(channel->user_list, chl2->client);
silc_free(chl2);
}
+ silc_hash_table_list_reset(&htl2);
continue;
}
if (keygen && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
/* Re-generate channel key */
if (!silc_server_create_channel_key(server, channel, 0))
- return;
+ goto out;
/* Send the channel key to the channel. The key of course is not sent
to the client who was removed from the channel. */
}
}
+ out:
+ silc_hash_table_list_reset(&htl);
silc_buffer_free(clidp);
}
silc_hash_table_del(channel->user_list, chl2->client);
silc_free(chl2);
}
+ silc_hash_table_list_reset(&htl2);
return FALSE;
}
/* 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);
+ NULL, key, newhmac, 0);
if (!entry) {
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;
}
/* Create the channel */
entry = silc_idlist_add_channel(server->local_list, channel_name,
SILC_CHANNEL_MODE_NONE, channel_id,
- NULL, key, newhmac);
+ 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);
+ 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);
}
}
+static SilcBuffer
+silc_server_announce_encode_notify(SilcNotifyType notify, uint32 argc, ...)
+{
+ va_list ap;
+ SilcBuffer p;
+
+ va_start(ap, argc);
+ p = silc_notify_payload_encode(notify, argc, ap);
+ va_end(ap);
+
+ return p;
+}
+
/* This function is used by router to announce existing servers to our
primary router when we've connected to it. If `creation_time' is non-zero
then only the servers that has been created after the `creation_time'
static void silc_server_announce_get_clients(SilcServer server,
SilcIDList id_list,
SilcBuffer *clients,
+ SilcBuffer *umodes,
unsigned long creation_time)
{
SilcIDCacheList list;
SilcIDCacheEntry id_cache;
SilcClientEntry client;
SilcBuffer idp;
+ SilcBuffer tmp;
+ unsigned char mode[4];
/* Go through all clients in the list */
if (silc_idcache_get_all(id_list->clients, &list)) {
silc_buffer_pull_tail(*clients, ((*clients)->end - (*clients)->data));
silc_buffer_put(*clients, idp->data, idp->len);
silc_buffer_pull(*clients, idp->len);
+
+ SILC_PUT32_MSB(client->mode, mode);
+ tmp = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_UMODE_CHANGE,
+ 2, idp->data, idp->len,
+ mode, 4);
+ *umodes = silc_buffer_realloc(*umodes,
+ (*umodes ?
+ (*umodes)->truelen + tmp->len :
+ tmp->len));
+ silc_buffer_pull_tail(*umodes, ((*umodes)->end - (*umodes)->data));
+ silc_buffer_put(*umodes, tmp->data, tmp->len);
+ silc_buffer_pull(*umodes, tmp->len);
+ silc_buffer_free(tmp);
+
silc_buffer_free(idp);
if (!silc_idcache_list_next(list, &id_cache))
SilcSocketConnection remote)
{
SilcBuffer clients = NULL;
+ SilcBuffer umodes = NULL;
SILC_LOG_DEBUG(("Announcing clients"));
/* Get clients in local list */
silc_server_announce_get_clients(server, server->local_list,
- &clients, creation_time);
+ &clients, &umodes, creation_time);
/* As router we announce our global list as well */
if (server->server_type == SILC_ROUTER)
silc_server_announce_get_clients(server, server->global_list,
- &clients, creation_time);
+ &clients, &umodes, creation_time);
if (clients) {
silc_buffer_push(clients, clients->data - clients->head);
silc_buffer_free(clients);
}
+
+ if (umodes) {
+ silc_buffer_push(umodes, umodes->data - umodes->head);
+ SILC_LOG_HEXDUMP(("umodes"), umodes->data, umodes->len);
+
+ /* Send the packet */
+ silc_server_packet_send(server, remote,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ umodes->data, umodes->len, TRUE);
+
+ silc_buffer_free(umodes);
+ }
}
-static SilcBuffer
-silc_server_announce_encode_notify(SilcNotifyType notify, uint32 argc, ...)
+/* Returns channel's topic for announcing it */
+
+void silc_server_announce_get_channel_topic(SilcServer server,
+ SilcChannelEntry channel,
+ SilcBuffer *topic)
{
- va_list ap;
- SilcBuffer p;
+ SilcBuffer chidp;
- va_start(ap, argc);
- p = silc_notify_payload_encode(notify, argc, ap);
- va_end(ap);
-
- return p;
+ if (channel->topic) {
+ chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+ *topic = silc_server_announce_encode_notify(SILC_NOTIFY_TYPE_TOPIC_SET, 2,
+ chidp->data, chidp->len,
+ channel->topic,
+ strlen(channel->topic));
+ silc_buffer_free(chidp);
+ }
}
/* Returns assembled packets for channel users of the `channel'. */
silc_buffer_free(clidp);
}
+ silc_hash_table_list_reset(&htl);
silc_buffer_free(chidp);
}
SilcBuffer *channel_users,
SilcBuffer **channel_users_modes,
uint32 *channel_users_modes_c,
+ SilcBuffer **channel_topics,
SilcChannelID ***channel_ids,
unsigned long creation_time)
{
silc_buffer_pull(*channels, len);
}
+ /* Channel user modes */
*channel_users_modes = silc_realloc(*channel_users_modes,
sizeof(**channel_users_modes) *
(i + 1));
channel_users,
&(*channel_users_modes)[i]);
(*channel_ids)[i] = channel->id;
+
+ /* Channel's topic */
+ *channel_topics = silc_realloc(*channel_topics,
+ sizeof(**channel_topics) * (i + 1));
+ (*channel_topics)[i] = NULL;
+ silc_server_announce_get_channel_topic(server, channel,
+ &(*channel_topics)[i]);
i++;
if (!silc_idcache_list_next(list, &id_cache))
{
SilcBuffer channels = NULL, channel_users = NULL;
SilcBuffer *channel_users_modes = NULL;
+ SilcBuffer *channel_topics = NULL;
uint32 channel_users_modes_c = 0;
SilcChannelID **channel_ids = NULL;
&channels, &channel_users,
&channel_users_modes,
&channel_users_modes_c,
+ &channel_topics,
&channel_ids, creation_time);
/* Get channels and channel users in global list */
&channels, &channel_users,
&channel_users_modes,
&channel_users_modes_c,
+ &channel_topics,
&channel_ids, creation_time);
if (channels) {
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);
silc_buffer_free(channel_users_modes[i]);
}
silc_free(channel_users_modes);
- silc_free(channel_ids);
}
+
+ if (channel_topics) {
+ int i;
+
+ for (i = 0; i < channel_users_modes_c; i++) {
+ if (!channel_topics[i])
+ continue;
+
+ silc_buffer_push(channel_topics[i],
+ channel_topics[i]->data -
+ channel_topics[i]->head);
+ SILC_LOG_HEXDUMP(("channel topic"), channel_topics[i]->data,
+ channel_topics[i]->len);
+ silc_server_packet_send_dest(server, remote,
+ SILC_PACKET_NOTIFY, SILC_PACKET_FLAG_LIST,
+ channel_ids[i], SILC_ID_CHANNEL,
+ channel_topics[i]->data,
+ channel_topics[i]->len,
+ FALSE);
+ silc_buffer_free(channel_topics[i]);
+ }
+ silc_free(channel_topics);
+ }
+
+ silc_free(channel_ids);
}
/* Failure timeout callback. If this is called then we will immediately
silc_hash_table_list(channel->user_list, &htl);
while (silc_hash_table_get(&htl, NULL, (void *)&chl))
len += (silc_id_get_len(chl->client->id, SILC_ID_CLIENT) + 4);
+ silc_hash_table_list_reset(&htl);
client_id_list = silc_buffer_alloc(len);
client_mode_list =
list_count++;
}
+ silc_hash_table_list_reset(&htl);
silc_buffer_push(client_id_list,
client_id_list->data - client_id_list->head);
silc_buffer_push(client_mode_list,
uint32 user_count)
{
int i;
+ uint16 idp_len;
+ uint32 mode;
+ SilcClientID *client_id;
+ SilcClientEntry client;
+ SilcIDCacheEntry cache;
+ bool global;
- for (i = 0; i < user_count; i++) {
- uint16 idp_len;
- uint32 mode;
- SilcClientID *client_id;
- SilcClientEntry client;
+ SILC_LOG_DEBUG(("Start"));
+ for (i = 0; i < user_count; i++) {
/* Client ID */
SILC_GET16_MSB(idp_len, user_list->data + 2);
idp_len += 4;
silc_free(client_id);
continue;
}
+
+ global = FALSE;
/* Check if we have this client cached already. */
client = silc_idlist_find_client_by_id(server->local_list, client_id,
- server->server_type, NULL);
- if (!client)
+ server->server_type, &cache);
+ if (!client) {
client = silc_idlist_find_client_by_id(server->global_list,
client_id, server->server_type,
- NULL);
+ &cache);
+ global = TRUE;
+ }
if (!client) {
/* If router did not find such Client ID in its lists then this must
be bogus client or some router in the net is buggy. */
global. */
client = silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
silc_id_dup(client_id, SILC_ID_CLIENT),
- sock->user_data, NULL);
+ sock->user_data, NULL, 0);
if (!client) {
SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
silc_free(client_id);
}
client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
+ } else {
+ /* Found, if it is from global list we'll assure that we won't
+ expire it now that the entry is on channel. */
+ if (global)
+ cache->expire = 0;
}
silc_free(client_id);
silc_buffer_pull(buffer, len);
silc_free(cid);
}
+ silc_hash_table_list_reset(&htl);
if (buffer)
silc_buffer_push(buffer, buffer->data - buffer->head);
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;
}