SilcServerCommand *cmd;
SilcCommand command;
+ SILC_LOG_DEBUG(("Start"));
+
/* Allocate command context. This must be free'd by the
command routine receiving it. */
ctx = silc_server_command_alloc();
packet->buffer->len);
if (!ctx->payload) {
SILC_LOG_ERROR(("Bad command payload, packet dropped"));
- silc_buffer_free(packet->buffer);
silc_packet_context_free(packet);
silc_socket_free(ctx->sock);
silc_free(ctx);
char check[512], check2[512];
bool founder = FALSE;
bool resolve;
+ unsigned char *fkey = NULL;
+ SilcUInt32 fkey_len = 0;
SILC_LOG_DEBUG(("Start"));
if (channel->founder_key && idata->public_key &&
silc_pkcs_public_key_compare(channel->founder_key,
idata->public_key)) {
- void *auth_data = (channel->founder_method == SILC_AUTH_PASSWORD ?
- (void *)channel->founder_passwd :
- (void *)channel->founder_key);
- SilcUInt32 auth_data_len =
- (channel->founder_method == SILC_AUTH_PASSWORD ?
- channel->founder_passwd_len : 0);
-
/* Check whether the client is to become founder */
- if (silc_auth_verify_data(auth, auth_len, channel->founder_method,
- auth_data, auth_data_len,
- idata->hash, client->id, SILC_ID_CLIENT)) {
+ if (silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY,
+ channel->founder_key, 0, server->sha1hash,
+ client->id, SILC_ID_CLIENT)) {
umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
founder = TRUE;
}
silc_hash_table_add(channel->user_list, client, chl);
silc_hash_table_add(client->channels, channel, chl);
channel->user_count++;
+ channel->disabled = FALSE;
/* Get users on the channel */
silc_server_get_users_on_channel(server, channel, &user_list, &mode_list,
silc_free(tmp);
}
+ if (channel->founder_key)
+ fkey = silc_pkcs_public_key_encode(channel->founder_key, &fkey_len);
+
reply =
silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
- SILC_STATUS_OK, 0, ident, 13,
+ SILC_STATUS_OK, 0, ident, 14,
2, channel->channel_name,
strlen(channel->channel_name),
3, chidp->data, chidp->len,
12, tmp3, 4,
13, user_list->data, user_list->len,
14, mode_list->data,
- mode_list->len);
+ mode_list->len,
+ 15, fkey, fkey_len);
/* Send command reply */
silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
/* Distribute the channel key to all backup routers. */
silc_server_backup_send(server, NULL, SILC_PACKET_CHANNEL_KEY, 0,
keyp->data, keyp->len, FALSE, TRUE);
- }
- /* If client became founder by providing correct founder auth data
- notify the mode change to the channel. */
- if (founder) {
- SILC_PUT32_MSB(chl->mode, mode);
- silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
- SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
- clidp->data, clidp->len,
- mode, 4, clidp->data, clidp->len);
+ /* If client became founder by providing correct founder auth data
+ notify the mode change to the channel. */
+ if (founder) {
+ SILC_PUT32_MSB(chl->mode, mode);
+ 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);
+ /* 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);
+ }
}
silc_buffer_free(reply);
silc_buffer_free(keyp);
silc_buffer_free(user_list);
silc_buffer_free(mode_list);
+ silc_free(fkey);
out:
silc_free(passphrase);
SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
client_id = silc_id_dup(entry->id, SILC_ID_CLIENT);
- if (!channel || channel->disabled) {
+ if (!channel ||
+ (channel->disabled && server->server_type != SILC_ROUTER)) {
/* Channel not found */
/* If we are standalone server we don't have a router, we just create
}
if (silc_command_get(reply->payload) == SILC_COMMAND_WHOIS &&
- !silc_hash_table_count(channel->user_list))
+ !channel->disabled && !silc_hash_table_count(channel->user_list))
created = TRUE;
}
/* If the channel does not have global users and is also empty the client
will be the channel founder and operator. */
- if (!channel->global_users && !silc_hash_table_count(channel->user_list))
+ if (!channel->disabled &&
+ !channel->global_users && !silc_hash_table_count(channel->user_list))
umode = (SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO);
/* Join to the channel */
SilcUInt32 mode_mask = 0, tmp_len, tmp_len2;
SilcUInt16 ident = silc_command_get_ident(cmd->payload);
bool set_mask = FALSE;
+ SilcPublicKey founder_key = NULL;
+ unsigned char *fkey = NULL;
+ SilcUInt32 fkey_len = 0;
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CMODE, cmd, 1, 7);
if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)) {
/* Set the founder authentication */
- SilcAuthPayload auth;
-
tmp = silc_argument_get_arg_type(cmd->args, 7, &tmp_len);
if (!tmp) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ silc_server_command_send_status_reply(
+ cmd, SILC_COMMAND_CMODE,
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
goto out;
}
- auth = silc_auth_payload_parse(tmp, tmp_len);
- if (!auth) {
+ /* Verify the payload before setting the mode */
+ if (!silc_auth_verify_data(tmp, tmp_len, SILC_AUTH_PUBLIC_KEY,
+ idata->public_key, 0, server->sha1hash,
+ client->id, SILC_ID_CLIENT)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
+ SILC_STATUS_ERR_AUTH_FAILED,
+ 0);
goto out;
}
/* Save the public key */
- tmp = silc_pkcs_public_key_encode(idata->public_key, &tmp_len);
- silc_pkcs_public_key_decode(tmp, tmp_len, &channel->founder_key);
- silc_free(tmp);
-
- channel->founder_method = silc_auth_get_method(auth);
-
- if (channel->founder_method == SILC_AUTH_PASSWORD) {
- tmp = silc_auth_get_data(auth, &tmp_len);
- channel->founder_passwd = silc_memdup(tmp, tmp_len);
- channel->founder_passwd_len = tmp_len;
- } else {
- /* Verify the payload before setting the mode */
- if (!silc_auth_verify(auth, channel->founder_method,
- channel->founder_key, 0, idata->hash,
- client->id, SILC_ID_CLIENT)) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
- SILC_STATUS_ERR_AUTH_FAILED,
- 0);
- goto out;
- }
- }
+ channel->founder_key = silc_pkcs_public_key_copy(idata->public_key);
+ if (!channel->founder_key) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_AUTH_FAILED,
+ 0);
+ goto out;
+ }
- silc_auth_payload_free(auth);
+ founder_key = channel->founder_key;
+ fkey = silc_pkcs_public_key_encode(founder_key, &fkey_len);
+ if (!fkey) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_AUTH_FAILED,
+ 0);
+ goto out;
+ }
}
}
} else {
if (channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
if (channel->founder_key)
silc_pkcs_public_key_free(channel->founder_key);
- if (channel->founder_passwd) {
- silc_free(channel->founder_passwd);
- channel->founder_passwd = NULL;
- }
+ channel->founder_key = NULL;
}
}
}
/* Send CMODE_CHANGE notify. */
cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
- SILC_NOTIFY_TYPE_CMODE_CHANGE, 5,
+ SILC_NOTIFY_TYPE_CMODE_CHANGE, 6,
cidp->data, cidp->len,
tmp_mask, 4,
cipher, cipher ? strlen(cipher) : 0,
hmac, hmac ? strlen(hmac) : 0,
passphrase, passphrase ?
- strlen(passphrase) : 0);
+ strlen(passphrase) : 0,
+ fkey, fkey_len);
/* Set CMODE notify type to network */
if (!server->standalone)
server->server_type == SILC_ROUTER ?
TRUE : FALSE, channel,
mode_mask, client->id, SILC_ID_CLIENT,
- cipher, hmac, passphrase);
+ cipher, hmac, passphrase, founder_key);
/* Send command reply to sender */
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
silc_buffer_free(cidp);
out:
+ silc_free(fkey);
silc_free(channel_id);
silc_server_command_free(cmd);
}
SilcUInt32 target_mask, sender_mask = 0, tmp_len, tmp_ch_len;
int notify = FALSE;
SilcUInt16 ident = silc_command_get_ident(cmd->payload);
+ SilcPublicKey founder_key = NULL;
+ unsigned char *fkey = NULL;
+ SilcUInt32 fkey_len = 0;
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CUMODE, cmd, 3, 4);
if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
/* The client tries to claim the founder rights. */
unsigned char *tmp_auth;
- SilcUInt32 tmp_auth_len, auth_len;
- void *auth;
-
+ SilcUInt32 tmp_auth_len;
+ SilcChannelClientEntry chl2;
+ SilcHashTableList htl;
+
if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) ||
!channel->founder_key || !idata->public_key ||
!silc_pkcs_public_key_compare(channel->founder_key,
idata->public_key)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
- SILC_STATUS_ERR_NOT_YOU, 0);
+ SILC_STATUS_ERR_AUTH_FAILED, 0);
goto out;
}
tmp_auth = silc_argument_get_arg_type(cmd->args, 4, &tmp_auth_len);
if (!tmp_auth) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
+ SILC_STATUS_ERR_AUTH_FAILED, 0);
goto out;
}
- auth = (channel->founder_method == SILC_AUTH_PASSWORD ?
- (void *)channel->founder_passwd : (void *)channel->founder_key);
- auth_len = (channel->founder_method == SILC_AUTH_PASSWORD ?
- channel->founder_passwd_len : 0);
-
- if (!silc_auth_verify_data(tmp_auth, tmp_auth_len,
- channel->founder_method, auth, auth_len,
- idata->hash, client->id, SILC_ID_CLIENT)) {
+ /* Verify the authentication payload */
+ if (!silc_auth_verify_data(tmp_auth, tmp_auth_len, SILC_AUTH_PUBLIC_KEY,
+ channel->founder_key, 0, server->sha1hash,
+ client->id, SILC_ID_CLIENT)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
SILC_STATUS_ERR_AUTH_FAILED, 0);
goto out;
}
-
- sender_mask = chl->mode |= SILC_CHANNEL_UMODE_CHANFO;
+
notify = TRUE;
+ founder_key = channel->founder_key;
+ fkey = silc_pkcs_public_key_encode(founder_key, &fkey_len);
+ if (!fkey) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_AUTH_FAILED, 0);
+ goto out;
+ }
+
+ /* 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);
+
+ sender_mask = chl->mode |= SILC_CHANNEL_UMODE_CHANFO;
}
} else {
if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
/* Promote to operator */
if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
- if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
- !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
- SILC_STATUS_ERR_NO_CHANNEL_PRIV,
- 0);
- goto out;
- }
-
chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
notify = TRUE;
}
} else {
if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
- if (!(sender_mask & SILC_CHANNEL_UMODE_CHANOP) &&
- !(sender_mask & SILC_CHANNEL_UMODE_CHANFO)) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
- SILC_STATUS_ERR_NO_CHANNEL_PRIV,
- 0);
- goto out;
- }
-
/* Demote to normal user */
chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
notify = TRUE;
}
}
+ if (target_mask & SILC_CHANNEL_UMODE_QUIET) {
+ if (!(chl->mode & SILC_CHANNEL_UMODE_QUIET)) {
+ if (client == target_client) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_PERM_DENIED, 0);
+ goto out;
+ }
+ chl->mode |= SILC_CHANNEL_UMODE_QUIET;
+ notify = TRUE;
+ }
+ } else {
+ if (chl->mode & SILC_CHANNEL_UMODE_QUIET) {
+ if (client == target_client) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_PERM_DENIED, 0);
+ goto out;
+ }
+ chl->mode &= ~SILC_CHANNEL_UMODE_QUIET;
+ notify = TRUE;
+ }
+ }
+
idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
/* Send notify to channel, notify only if mode was actually changed. */
if (notify) {
silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
- SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
+ SILC_NOTIFY_TYPE_CUMODE_CHANGE, 4,
idp->data, idp->len,
tmp_mask, 4,
- tmp_id, tmp_len);
+ tmp_id, tmp_len,
+ fkey, fkey_len);
/* Set CUMODE notify type to network */
if (!server->standalone)
TRUE : FALSE, channel,
target_mask, client->id,
SILC_ID_CLIENT,
- target_client->id);
+ target_client->id, founder_key);
}
/* Send command reply to sender */
silc_buffer_free(idp);
out:
+ silc_free(fkey);
silc_server_command_free(cmd);
}
SILC_TASK_CALLBACK(silc_server_command_detach_timeout)
{
QuitInternal q = (QuitInternal)context;
- SilcClientEntry client = (SilcClientEntry)q->sock;
+ SilcClientID *client_id = (SilcClientID *)q->sock;
+ SilcClientEntry client;
SILC_LOG_DEBUG(("Start"));
- if (client->mode & SILC_UMODE_DETACHED)
+ client = silc_idlist_find_client_by_id(q->server->local_list, client_id,
+ FALSE, NULL);
+
+ if (client && client->mode & SILC_UMODE_DETACHED)
silc_server_free_client_data(q->server, NULL, client, TRUE,
"Detach timeout");
+
+ silc_free(client_id);
silc_free(q);
}
if (server->config->detach_disabled) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_DETACH,
- SILC_STATUS_ERR_UNKNOWN_COMMAND,
- 0);
+ SILC_STATUS_ERR_UNKNOWN_COMMAND, 0);
goto out;
}
/* Send the user mode notify to notify that client is detached */
client->mode |= SILC_UMODE_DETACHED;
client->data.status &= ~SILC_IDLIST_STATUS_RESUMED;
+ client->last_command = 0;
+ client->fast_command = 0;
if (!server->standalone)
silc_server_send_notify_umode(server, server->router->connection,
server->server_type == SILC_SERVER ?
if (server->config->detach_timeout) {
q = silc_calloc(1, sizeof(*q));
q->server = server;
- q->sock = (void *)client;
+ q->sock = silc_id_dup(client->id, SILC_ID_CLIENT);
silc_schedule_task_add(server->schedule, 0,
silc_server_command_detach_timeout,
q, server->config->detach_timeout * 60,
silc_free(tmp);
}
+ /* Distribute the watch list to backup routers too */
+ if (server->backup) {
+ SilcBuffer tmpbuf;
+ silc_command_set_ident(cmd->payload, ++server->cmd_ident);
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+ silc_server_backup_send(server, NULL, SILC_PACKET_COMMAND,
+ cmd->packet->flags, tmpbuf->data, tmpbuf->len,
+ FALSE, TRUE);
+ silc_buffer_free(tmpbuf);
+ }
+
silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
SILC_STATUS_OK, 0);
channel = silc_idlist_find_channel_by_name(server->local_list,
channel_name, NULL);
- if (!channel || channel->disabled || !channel->users_resolved) {
+ if (!channel || (!server->standalone && (channel->disabled ||
+ !channel->users_resolved))) {
if (server->server_type != SILC_ROUTER && !server->standalone &&
!cmd->pending) {
SilcBuffer tmpbuf;
}
/* Get the users list */
- silc_server_get_users_on_channel(server, channel, &client_id_list,
- &client_mode_list, &list_count);
+ if (!silc_server_get_users_on_channel(server, channel, &client_id_list,
+ &client_mode_list, &list_count)) {
+ list_count = 0;
+ client_id_list = NULL;
+ client_mode_list = NULL;
+ }
/* List count */
SILC_PUT32_MSB(list_count, lc);
SILC_STATUS_OK, 0, ident, 4,
2, idp->data, idp->len,
3, lc, 4,
- 4, client_id_list->data,
- client_id_list->len,
- 5, client_mode_list->data,
- client_mode_list->len);
+ 4, client_id_list ?
+ client_id_list->data : NULL,
+ client_id_list ?
+ client_id_list->len : 0,
+ 5, client_mode_list ?
+ client_mode_list->data : NULL,
+ client_mode_list ?
+ client_mode_list->len : 0);
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
packet->data, packet->len, FALSE);
silc_buffer_free(idp);
silc_buffer_free(packet);
- silc_buffer_free(client_id_list);
- silc_buffer_free(client_mode_list);
+ if (client_id_list)
+ silc_buffer_free(client_id_list);
+ if (client_mode_list)
+ silc_buffer_free(client_mode_list);
silc_free(id);
out: