Close all connections and listeners in silc_server_stop.
+Tue Jun 18 17:14:52 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * When authenticating as founder during JOIN command, check
+ that the one authenticating becomes the only founder on the
+ channel. Affected file silcd/command.c.
+
+ * Better checking for founder mode setting when CUMODE_CHANGE
+ notify is received. Affected file silcd/packet_receive.c.
+
+ * Close all connections when shutting down the server by sending
+ DISCONNECT packet. Close all listeners too when shutting
+ down the server. Affected file silcd/server.c.
+
+ * Handle DISCONNECT packet correctly in client library by
+ calling the "disconnect" client operation. Affected file
+ lib/silcclient/client.c.
+
Tue Jun 18 10:26:27 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
* The log file is not dupped internally anymore in
TODO/bugs In SILC Server
========================
- o Make the "one founder per channel" check during join -founder as well.
-
- o Make the "one founder per channel" during CUMODE notify as well.
-
o Implement the <Requested Attributes> and the Attribute Payload to
the core library, client and server. Maybe implementations of
RFC 2425 and RFC 2426 to make it complete.
*/
if (auth && auth_len && channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
SilcIDListData idata = (SilcIDListData)client;
+ SilcChannelClientEntry chl2;
+ SilcHashTableList htl;
if (channel->founder_key && idata->public_key &&
silc_pkcs_public_key_compare(channel->founder_key,
if (silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY,
channel->founder_key, 0, server->sha1hash,
client->id, SILC_ID_CLIENT)) {
+
+ /* There cannot be anyone else as founder on the channel now. This
+ client is definitely the founder due to this authentication */
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
+ if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
+ chl2->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+ silc_server_force_cumode_change(server, NULL, channel, chl2,
+ chl2->mode);
+ break;
+ }
+ silc_hash_table_list_reset(&htl);
+
umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
founder = TRUE;
}
we'll ignore it (in packet_receive.c) so we must send it here. If
we are router then this will send it to local clients and local
servers. */
+ SILC_LOG_DEBUG(("Send JOIN notify to channel"));
silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
SILC_NOTIFY_TYPE_JOIN, 2,
clidp->data, clidp->len,
notify the mode change to the channel. */
if (founder) {
SILC_PUT32_MSB(chl->mode, mode);
+ SILC_LOG_DEBUG(("Send CUMODE_CHANGE notify to channel"));
silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
clidp->data, clidp->len,
mode, 4, clidp->data, clidp->len,
fkey, fkey_len);
-
- /* Set CUMODE notify type to network */
- if (!server->standalone)
- silc_server_send_notify_cumode(server, server->router->connection,
- server->server_type == SILC_ROUTER ?
- TRUE : FALSE, channel,
- chl->mode, client->id, SILC_ID_CLIENT,
- client->id, channel->founder_key);
}
}
+ /* Set CUMODE notify type to network */
+ if (founder && !server->standalone)
+ silc_server_send_notify_cumode(server, server->router->connection,
+ server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, channel,
+ chl->mode, client->id, SILC_ID_CLIENT,
+ client->id, channel->founder_key);
+
silc_buffer_free(reply);
silc_buffer_free(clidp);
silc_buffer_free(chidp);
}
}
- /* Get target channel entry */
+ /* Get target channel user entry */
if (!silc_server_client_on_channel(client2, channel, &chl))
goto out;
if (mode & SILC_CHANNEL_UMODE_CHANFO &&
- !(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && !client &&
- server->server_type == SILC_ROUTER) {
- /* Get the founder of the channel and if found then this client
- cannot be the founder since there already is one. */
- silc_hash_table_list(channel->user_list, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
- if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
- mode &= ~SILC_CHANNEL_UMODE_CHANFO;
- silc_server_force_cumode_change(server, sock, channel, chl, mode);
- notify_sent = TRUE;
- break;
- }
- silc_hash_table_list_reset(&htl);
- if (!(mode & SILC_CHANNEL_UMODE_CHANFO))
- break;
- }
-
- if (client && mode & SILC_CHANNEL_UMODE_CHANFO &&
- !(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
- server->server_type == SILC_ROUTER) {
- /* Check whether this client is allowed to be channel founder on
- this channel. */
+ !(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
+ server->server_type == SILC_ROUTER &&
+ sock->user_data != server->router) {
SilcPublicKey founder_key = NULL;
/* If channel doesn't have founder auth mode then it's impossible
that someone would be getting founder rights with CUMODE command.
In that case there already either is founder or there isn't
founder at all on the channel. */
- if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
+ if (client && !(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
/* Force the mode to not have founder mode */
mode &= ~SILC_CHANNEL_UMODE_CHANFO;
silc_server_force_cumode_change(server, sock, channel, chl, mode);
while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
mode &= ~SILC_CHANNEL_UMODE_CHANFO;
- silc_server_force_cumode_change(server, sock, channel, chl, mode);
+ silc_server_force_cumode_change(server, sock, channel,
+ chl, mode);
notify_sent = TRUE;
break;
}
break;
}
- /* Now match the public key we have cached and public key sent.
- They must match. */
- if (client->data.public_key &&
- !silc_pkcs_public_key_compare(channel->founder_key,
- client->data.public_key)) {
- mode &= ~SILC_CHANNEL_UMODE_CHANFO;
- silc_server_force_cumode_change(server, sock, channel, chl, mode);
- notify_sent = TRUE;
- break;
- }
- if (!silc_pkcs_public_key_compare(channel->founder_key,
- founder_key)) {
- mode &= ~SILC_CHANNEL_UMODE_CHANFO;
- silc_server_force_cumode_change(server, sock, channel, chl, mode);
- notify_sent = TRUE;
- break;
+ if (channel->founder_key) {
+ /* Now match the public key we have cached and public key sent.
+ They must match. */
+ if (client && client->data.public_key &&
+ !silc_pkcs_public_key_compare(channel->founder_key,
+ client->data.public_key)) {
+ mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+ silc_server_force_cumode_change(server, sock, channel, chl, mode);
+ notify_sent = TRUE;
+ break;
+ }
+ if (!silc_pkcs_public_key_compare(channel->founder_key,
+ founder_key)) {
+ mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+ silc_server_force_cumode_change(server, sock, channel, chl, mode);
+ notify_sent = TRUE;
+ break;
+ }
}
+ /* There cannot be anyone else as founder on the channel now. This
+ client is definitely the founder due to this authentication */
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl2))
+ if (chl2->mode & SILC_CHANNEL_UMODE_CHANFO) {
+ chl2->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+ silc_server_force_cumode_change(server, NULL, channel, chl2,
+ chl2->mode);
+ break;
+ }
+ silc_hash_table_list_reset(&htl);
+
if (founder_key)
silc_pkcs_public_key_free(founder_key);
}
+ if (server->server_type == SILC_ROUTER && chl->mode == mode) {
+ SILC_LOG_DEBUG(("Mode is changed already"));
+ break;
+ }
+
SILC_LOG_DEBUG(("Changing the channel user mode"));
/* Change the mode */
/* Set the packet context pointers */
packetdata.type = type;
packetdata.flags = flags;
- packetdata.src_id = silc_id_id2str(server->id, server->id_type);
- packetdata.src_id_len = silc_id_get_len(server->id, server->id_type);
- packetdata.src_id_type = server->id_type;
+ packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
+ packetdata.src_id_len = silc_id_get_len(server->id, SILC_ID_SERVER);
+ packetdata.src_id_type = SILC_ID_SERVER;
packetdata.dst_id = dst_id_data;
packetdata.dst_id_len = dst_id_len;
packetdata.dst_id_type = dst_id_type;
silc_socket_alloc(sock_list[sock],
SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
server->sockets[sock_list[sock]] = newsocket;
+ SILC_SET_LISTENER(newsocket);
/* Perform name and address lookups to resolve the listenning address
and port. */
is sent as argument for fast referencing in the future. */
silc_socket_alloc(sock, SILC_SOCKET_TYPE_SERVER, NULL, &newsocket);
server->sockets[sock] = newsocket;
+ SILC_SET_LISTENER(newsocket);
/* Perform name and address lookups to resolve the listenning address
and port. */
server->id = id;
server->id_string = silc_id_id2str(id, SILC_ID_SERVER);
server->id_string_len = silc_id_get_len(id, SILC_ID_SERVER);
- server->id_type = SILC_ID_SERVER;
server->server_name = server->config->server_info->server_name;
server->config->server_info->server_name = NULL;
if (server->schedule) {
int i;
+ /* Close all connections */
for (i = 0; i < server->config->param.connections_max; i++) {
if (!server->sockets[i])
continue;
- silc_socket_free(server->sockets[i]);
+ if (!SILC_IS_LISTENER(server->sockets[i])) {
+ silc_schedule_task_del_by_context(server->schedule,
+ server->sockets[i]);
+ silc_server_disconnect_remote(server, server->sockets[i],
+ SILC_STATUS_OK,
+ "Server is shutting down");
+ } else {
+ silc_socket_free(server->sockets[i]);
+ server->sockets[i] = NULL;
+ }
}
- silc_free(server->sockets);
- server->sockets = NULL;
+
+ /* We are not connected to network anymore */
+ server->standalone = TRUE;
silc_schedule_stop(server->schedule);
silc_schedule_uninit(server->schedule);
server->schedule = NULL;
+
+ silc_free(server->sockets);
+ server->sockets = NULL;
}
silc_server_protocols_unregister();
sock->ip));
/* Listenning port */
+ if (!server->sockets[(SilcUInt32)proto_ctx->context]) {
+ silc_server_disconnect_remote(server, sock,
+ SILC_STATUS_ERR_RESOURCE_LIMIT,
+ "Connection refused");
+ server->stat.conn_failures++;
+ silc_free(proto_ctx);
+ return;
+ }
port = server->sockets[(SilcUInt32)proto_ctx->context]->port;
/* Check whether this connection is denied to connect to us. */
status = (SilcStatus)packet->buffer->data[0];
if (packet->buffer->len > 1 &&
silc_utf8_valid(packet->buffer->data + 1, packet->buffer->len - 1))
- message = silc_memdup(packet->buffer->data, packet->buffer->len);
+ message = silc_memdup(packet->buffer->data + 1,
+ packet->buffer->len - 1);
SILC_LOG_ERROR(("Disconnected by %s (%s): %s (%d) %s",
sock->ip, sock->hostname,
*/
struct SilcServerStruct {
char *server_name;
- int server_type;
int sock;
+ SilcServerEntry id_entry;
SilcServerID *id;
unsigned char *id_string;
SilcUInt32 id_string_len;
- SilcIdType id_type;
-
SilcUInt32 starttime;
- bool standalone; /* TRUE if server is standalone, and
+
+ unsigned int server_type : 2; /* Server type (server.h) */
+ unsigned int standalone : 1; /* Set if server is standalone, and
does not have connection to network. */
- bool listenning; /* TRUE if server is listenning for
+ unsigned int listenning : 1; /* Set if server is listenning for
incoming connections. */
- bool background;
- SilcServerEntry id_entry; /* Server's own ID entry */
+ unsigned int background : 1; /* Set when server is on background */
+ unsigned int backup_router : 1; /* Set if this is backup router */
+ unsigned int backup_primary : 1; /* Set if we've switched our primary
+ router to a backup router. */
+
SilcServerEntry router; /* Pointer to the primary router */
unsigned long router_connect; /* Time when router was connected */
- SilcServerBackup backup; /* Backup routers */
- bool backup_router; /* TRUE if this is backup router */
- bool backup_primary; /* TRUE if we've switched our primary
- router to a backup router. */
SilcServerConnection router_conn; /* non-NULL when connecting to the
primary router, and NULL otherwise. */
+ SilcServerBackup backup; /* Backup routers */
/* Current command identifier, 0 not used */
SilcUInt16 cmd_ident;
SILC_TASK_CALLBACK(silc_client_disconnected_by_server_later)
{
SilcClient client = (SilcClient)context;
+ SilcClientConnection conn;
SilcSocketConnection sock;
SILC_CLIENT_GET_SOCK(client, fd, sock);
if (sock == NULL)
return;
+ conn = (SilcClientConnection)sock->user_data;
+ if (sock == conn->sock && sock->type != SILC_SOCKET_TYPE_CLIENT)
+ client->internal->ops->disconnect(client, conn);
+
silc_client_close_connection_real(client, sock, sock->user_data);
}
#define SILC_SF_HOST_LOOKUP 5 /* performing host lookup for socket */
#define SILC_SF_DISABLED 6 /* socket connection is disabled,
no data is sent or received. */
+#define SILC_SF_LISTENER 7
/****s* silcutil/SilcSocketConnectionAPI/SilcSocketConnectionStruct
*
#define SILC_SET_DISCONNECTING(x) SF_SET((x), SILC_SF_DISCONNECTING)
#define SILC_SET_DISCONNECTED(x) SF_SET((x), SILC_SF_DISCONNECTED)
#define SILC_SET_HOST_LOOKUP(x) SF_SET((x), SILC_SF_HOST_LOOKUP)
-#define SILC_SET_DISABLED(x) SF_SET((x), SILC_SF_HOST_LOOKUP)
+#define SILC_SET_DISABLED(x) SF_SET((x), SILC_SF_DISABLED)
+#define SILC_SET_LISTENER(x) SF_SET((x), SILC_SF_LISTENER)
#define SILC_UNSET_OUTBUF_PENDING(x) SF_UNSET((x), SILC_SF_OUTBUF_PENDING)
#define SILC_UNSET_INBUF_PENDING(x) SF_UNSET((x), SILC_SF_INBUF_PENDING)
#define SILC_UNSET_DISCONNECTING(x) SF_UNSET((x), SILC_SF_DISCONNECTING)
#define SILC_UNSET_DISCONNECTED(x) SF_UNSET((x), SILC_SF_DISCONNECTED)
#define SILC_UNSET_HOST_LOOKUP(x) SF_UNSET((x), SILC_SF_HOST_LOOKUP)
#define SILC_UNSET_DISABLED(x) SF_UNSET((x), SILC_SF_DISABLED)
+#define SILC_UNSET_LISTENER(x) SF_UNSET((x), SILC_SF_LISTENER)
/* Checking for flags */
#define SILC_IS_OUTBUF_PENDING(x) SF_IS((x), SILC_SF_OUTBUF_PENDING)
#define SILC_IS_DISCONNECTED(x) SF_IS((x), SILC_SF_DISCONNECTED)
#define SILC_IS_HOST_LOOKUP(x) SF_IS((x), SILC_SF_HOST_LOOKUP)
#define SILC_IS_DISABLED(x) SF_IS((x), SILC_SF_DISABLED)
+#define SILC_IS_LISTENER(x) SF_IS((x), SILC_SF_LISTENER)
/* Prototypes */