+Mon May 6 19:46:12 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Added silc_pkcs_public_key_copy function into the
+ lib/silccrypt/silcpkcs.[ch].
+
+ * Remove the `iv' from the SilcChannelEntry since we can
+ live without it. Affected files are silcd/idlist.h and
+ silcd/packet_receive.c.
+
+ * Added support for sending the founder's public key in
+ the CMODE_CHANGE notify packet in the server. Affected
+ files are silcd/packet_send.[ch], silcd/packet_receive.c,
+ silcd/command.c and silcd/server.c.
+
+ * Changed the FOUNDER_AUTH authentication to use only
+ public key authentication as defined by new protocol
+ specs. Passphrase authentication with that mode cannot
+ be used anymore. It is now possible to reclaim founder
+ mode from any server in the network. Affected files are
+ silcd/command.c, silcd/idlist.h and silcd/command_reply.c.
+
+ * Added permanent channels support by making the channel
+ permanent when FOUNDER_AUTH mode is set on the channel.
+ The channel will not be destroyed even if channel is empty
+ when that mode is set. Protocol TODO #17. Affected
+ files are silcd/server.[ch], server_util.[ch],
+ silcd/command.c, silcd/packet_receive.c and
+ lib/silcclient/command.c.
+
Fri May 3 18:36:51 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
* Added reference counter to the command reply context in
for single IP address, key exchange frequency, key exchange
frequency for single IP. Add also frequency base.
- o If server send CUMODE_CHANGE notify (like setting founder) to router
- and router does not have founder on channel (founder is left or there's
- no founder on channel at all), the router will accept the server's
- founder mode change, even though it perhaps should not do that (Fix
- this to 0.9).
-
o Implement the SILC_CUMODE_QUIET user mode (Do this to 0.9.x).
o Implement the <Requested Attributes> and the Attribute Payload to
o Write "Platform Implementations" document to describe what platforms
Toolkit support, what has been implemented, what has not been, what
works differently etc.
-
-
-TODO in SILC Protocol
-=====================
-
- 17. Cell wide channel founder support, and permanent channels when
- founder mode set.
be provided when joining to the channel.
c <cipher> Set/unset channel's cipher
h <hmac> Set/unset channel's hmac
- f <-pubkey|<password>
- Set/unset channel founder authentication.
+ f Set/unset channel founder authentication.
Channel founder may set this mode so that
if the client leaves the channel it can
claim the founder rights when it returns
- to the channel. If -pubkey is set then
- the authentication will be done using the
- client's public key. You can claim the
- founder rights using the CUMODE command.
+ to the channel, and to set the channel to
+ be permanent channel. You can claim the
+ founder rights using CUMODE or JOIN commands.
Multiple modes can be set/unset at once if the modes does not
require any arguments. If mode requires an argument then only
one mode can be set at once.
-See also: CUMODE, UMODE
+See also: CUMODE, UMODE, JOIN
both founder and operator rights, can be used
only to remove both modes at once).
- f <nickname>[@<server>] [-pubkey|<password>]
+ f <nickname>[@<server>] [-pubkey]
Set/Unset channel founder. If the -pubkey
option or <password> is provided then the
client is claiming the founder rights by
- providing the channel founder authentication
- data. If the -pubkey is provided then the
- authentication is performed using the
- client's public key. If you are channel
- founder you can set the channel founder
- authentication using CMODE command.
+ providing your public key as argument. If
+ you are channel founder you can set the channel
+ founder authentication using CMODEc command.
o <nickname>[@<server>]
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,
+ if (silc_auth_verify_data(auth, auth_len, SILC_AUTH_PUBLIC_KEY,
+ channel->founder_key, 0,
idata->hash, 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,
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 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, idata->hash,
+ 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;
- }
- }
-
- silc_auth_payload_free(auth);
+ channel->founder_key = silc_pkcs_public_key_copy(idata->public_key);
+ founder_key = channel->founder_key;
+ fkey = silc_pkcs_public_key_encode(founder_key, &fkey_len);
}
}
} 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);
}
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;
+
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, idata->hash,
+ 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;
}
them in the entry */
if (!(mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) && entry->founder_key) {
silc_pkcs_public_key_free(entry->founder_key);
- silc_free(entry->founder_passwd);
- entry->founder_passwd = NULL;
+ entry->founder_key = NULL;
}
}
silc_hmac_free(entry->hmac);
silc_free(entry->hmac_name);
silc_free(entry->rekey);
+ if (entry->founder_key)
+ silc_pkcs_public_key_free(entry->founder_key);
memset(entry, 'F', sizeof(*entry));
silc_free(entry);
the cipher to be used. This can be set at SILC_COMMAND_JOIN.
SilcPublicKey founder_key
- SilcAuthMethod founder_method
- unsigned char *founder_passwd
- SilcUInt32 founder_passwd_len
- If the SILC_CMODE_FOUNDER_AUTH has been set then these will include
- the founder's public key, authentication method and the password
- if the method is SILC_AUTH_PASSWORD. If it is SILC_AUTH_PUBLIC_KEY
- then the `founder_passwd' is NULL.
+ If the SILC_CMODE_FOUNDER_AUTH has been set then this will include
+ the founder's public key. When the mode and this key is set the
+ channel is also permanent channel and cannot be destroyed.
SilcHashTable user_list
char *channel_name;
SilcUInt32 mode;
SilcChannelID *id;
- bool global_users;
char *topic;
char *cipher;
char *hmac_name;
-
SilcPublicKey founder_key;
- SilcAuthMethod founder_method;
- unsigned char *founder_passwd;
- SilcUInt32 founder_passwd_len;
SilcUInt32 user_limit;
unsigned char *passphrase;
SilcCipher channel_key;
unsigned char *key;
SilcUInt32 key_len;
- unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
SilcHmac hmac;
SilcServerChannelRekey rekey;
-
unsigned long created;
- bool disabled;
- bool users_resolved;
+
+ /* Flags */
+ unsigned int global_users : 1;
+ unsigned int disabled : 1;
+ unsigned int users_resolved : 1;
};
/*
FALSE : !server->standalone);
}
- /* Change mode */
- channel->mode = mode;
-
/* Get the hmac */
tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
if (tmp) {
channel->passphrase = silc_memdup(tmp, tmp_len);
}
+ /* Get founder public key */
+ tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
+ if (tmp && mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) {
+ if (channel->founder_key)
+ silc_pkcs_public_key_free(channel->founder_key);
+ channel->founder_key = NULL;
+ silc_pkcs_public_key_decode(tmp, tmp_len, &channel->founder_key);
+
+ if (!channel->founder_key ||
+ (client && client->data.public_key &&
+ server->server_type == SILC_ROUTER &&
+ !silc_pkcs_public_key_compare(channel->founder_key,
+ client->data.public_key))) {
+ /* A really buggy server isn't checking public keys correctly.
+ It's not possible that the mode setter and founder wouldn't
+ have same public key. */
+ SILC_LOG_DEBUG(("Enforcing sender to change channel mode"));
+
+ mode &= ~SILC_CHANNEL_MODE_FOUNDER_AUTH;
+ silc_server_send_notify_cmode(server, sock, FALSE, channel,
+ mode, server->id, SILC_ID_SERVER,
+ channel->cipher,
+ channel->hmac_name,
+ channel->passphrase, NULL);
+ if (channel->founder_key)
+ silc_pkcs_public_key_free(channel->founder_key);
+ channel->founder_key = NULL;
+ } else if (!client->data.public_key) {
+ client->data.public_key =
+ silc_pkcs_public_key_copy(channel->founder_key);
+ }
+ }
+
+ /* Change mode */
+ channel->mode = mode;
+
+ if (!(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH) &&
+ channel->founder_key) {
+ silc_pkcs_public_key_free(channel->founder_key);
+ channel->founder_key = NULL;
+ }
+
break;
case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
}
}
- /* Get entry to the channel user list */
- silc_hash_table_list(channel->user_list, &htl);
- while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
- /* If the mode is channel founder and we already find a client
- to have that mode on the channel we will enforce the sender
- to change the channel founder mode away. There can be only one
- channel founder on the channel. */
- if (server->server_type == SILC_ROUTER &&
- mode & SILC_CHANNEL_UMODE_CHANFO &&
- chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
- SilcBuffer idp;
- unsigned char cumode[4];
-
- if (chl->client == client && chl->mode == mode) {
- notify_sent = TRUE;
- break;
- }
-
+ if (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. */
+
+ /* 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)) {
+ /* Force the mode to not have founder mode */
mode &= ~SILC_CHANNEL_UMODE_CHANFO;
- silc_server_send_notify_cumode(server, sock, FALSE, channel, mode,
- client2->id, SILC_ID_CLIENT,
- client2->id);
-
- idp = silc_id_payload_encode(client2->id, SILC_ID_CLIENT);
- SILC_PUT32_MSB(mode, cumode);
- silc_server_send_notify_to_channel(server, sock, channel, FALSE,
- SILC_NOTIFY_TYPE_CUMODE_CHANGE,
- 3, idp->data, idp->len,
- cumode, 4,
- idp->data, idp->len);
- silc_buffer_free(idp);
+ silc_server_force_cumode_change(server, sock, channel, chl, mode);
notify_sent = TRUE;
-
- /* Force the mode change if we alredy set the mode */
- if (chl2) {
- chl2->mode = mode;
- silc_free(channel_id);
- silc_hash_table_list_reset(&htl);
- goto out;
- }
+ break;
}
-
- if (chl->client == client2) {
- if (chl->mode == mode) {
+
+ /* 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;
+
+ /* XXX Founder not found of the channel. Since the founder auth mode
+ is set on the channel now check whether this is the client that
+ originally set the mode. If we don't have the public key it
+ is resolved first.
+ if (!silc_pkcs_public_key_compare(channel->founder_key,
+ client->data.public_key))
+ */
+
+ }
- SILC_LOG_DEBUG(("Changing the channel user mode"));
+ SILC_LOG_DEBUG(("Changing the channel user mode"));
+
+ /* Change the mode */
+ chl->mode = mode;
- /* Change the mode */
- chl->mode = mode;
- if (!(mode & SILC_CHANNEL_UMODE_CHANFO))
- break;
-
- chl2 = chl;
- }
- }
- silc_hash_table_list_reset(&htl);
-
/* Send the same notify to the channel */
if (!notify_sent)
silc_server_packet_send_to_channel(server, sock, channel,
SILC_LOG_DEBUG(("Forcing the server to change channel mode"));
silc_server_send_notify_cmode(server, sock, FALSE, channel,
channel->mode, server->id,
- SILC_ID_SERVER,
- channel->cipher, channel->hmac_name,
- channel->passphrase);
+ SILC_ID_SERVER, channel->cipher,
+ channel->hmac_name,
+ channel->passphrase,
+ channel->founder_key);
}
/* Create new key for the channel and send it to the server and
everybody else possibly on the channel. */
-
if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
if (!silc_server_create_channel_key(server, channel, 0))
return;
channel->channel_key) {
SilcUInt32 mac_len = silc_hmac_len(channel->hmac);
SilcUInt32 iv_len = silc_cipher_get_block_len(channel->channel_key);
+ unsigned char iv[SILC_CIPHER_MAX_IV_SIZE];
if (data_len <= mac_len + iv_len) {
SILC_LOG_WARNING(("Corrupted channel message, cannot relay it"));
return FALSE;
}
- memcpy(channel->iv, data + (data_len - iv_len), iv_len);
+ memcpy(iv, data + (data_len - iv_len), iv_len);
silc_channel_message_payload_encrypt(data, data_len - iv_len - mac_len,
- data_len, channel->iv, iv_len,
+ data_len, iv, iv_len,
channel->channel_key, channel->hmac);
}
SilcChannelEntry channel,
SilcUInt32 mode_mask,
void *id, SilcIdType id_type,
- char *cipher, char *hmac,
- char *passphrase)
+ const char *cipher, const char *hmac,
+ const char *passphrase,
+ SilcPublicKey founder_key)
{
SilcBuffer idp;
- unsigned char mode[4];
+ unsigned char mode[4], *key = NULL;
+ SilcUInt32 key_len = 0;
idp = silc_id_payload_encode((void *)id, id_type);
SILC_PUT32_MSB(mode_mask, mode);
+ if (founder_key)
+ key = silc_pkcs_public_key_encode(founder_key, &key_len);
silc_server_send_notify_dest(server, sock, broadcast, (void *)channel->id,
SILC_ID_CHANNEL, SILC_NOTIFY_TYPE_CMODE_CHANGE,
cipher, cipher ? strlen(cipher) : 0,
hmac, hmac ? strlen(hmac) : 0,
passphrase, passphrase ?
- strlen(passphrase) : 0);
+ strlen(passphrase) : 0,
+ key, key_len);
+ silc_free(key);
silc_buffer_free(idp);
}
-/* Sends CUMODE_CHANGE notify type. This tells that `client_id' changed the
+/* Sends CUMODE_CHANGE notify type. This tells that `id' changed the
`target' client's mode on `channel'. The notify packet is always
destined to the channel. */
SilcChannelEntry channel,
SilcUInt32 mode_mask,
void *id, SilcIdType id_type,
- char *cipher, char *hmac,
- char *passphrase);
+ const char *cipher, const char *hmac,
+ const char *passphrase,
+ SilcPublicKey founder_key);
void silc_server_send_notify_cumode(SilcServer server,
SilcSocketConnection sock,
bool broadcast,
void silc_server_remove_from_channels(SilcServer server,
SilcSocketConnection sock,
SilcClientEntry client,
- int notify,
- char *signoff_message,
- int keygen)
+ bool notify,
+ const char *signoff_message,
+ bool keygen)
{
SilcChannelEntry channel;
SilcChannelClientEntry chl;
return;
clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ if (!clidp)
+ notify = FALSE;
/* Remove the client from all channels. The client is removed from
the channels' user list. */
while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
channel = chl->channel;
- /* Remove channel from client's channel list */
- silc_hash_table_del(client->channels, channel);
-
- /* Remove channel if there is no users anymore */
+ /* Remove channel if this is last client leaving the channel, unless
+ the channel is permanent. */
if (server->server_type == SILC_ROUTER &&
silc_hash_table_count(channel->user_list) < 2) {
- if (channel->rekey)
- silc_schedule_task_del_by_context(server->schedule, channel->rekey);
- if (silc_idlist_del_channel(server->local_list, channel))
- server->stat.my_channels--;
- else
- silc_idlist_del_channel(server->global_list, channel);
+ silc_server_channel_delete(server, channel);
continue;
}
- /* Remove client from channel's client list */
+ silc_hash_table_del(client->channels, channel);
silc_hash_table_del(channel->user_list, chl->client);
channel->user_count--;
server->stat.my_chanclients--;
/* If there is not at least one local user on the channel then we don't
- need the channel entry anymore, we can remove it safely. */
+ need the channel entry anymore, we can remove it safely, unless the
+ channel is permanent channel */
if (server->server_type != SILC_ROUTER &&
!silc_server_channel_has_local(channel)) {
/* Notify about leaving client if this channel has global users. */
signoff_message, signoff_message ?
strlen(signoff_message) : 0);
- if (channel->rekey)
- silc_schedule_task_del_by_context(server->schedule, channel->rekey);
-
- if (channel->founder_key) {
- /* The founder auth data exists, do not remove the channel entry */
- SilcChannelClientEntry chl2;
- SilcHashTableList htl2;
-
- channel->disabled = TRUE;
-
- silc_hash_table_list(channel->user_list, &htl2);
- while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
- silc_hash_table_del(chl2->client->channels, channel);
- silc_hash_table_del(channel->user_list, chl2->client);
- channel->user_count--;
- silc_free(chl2);
- }
- silc_hash_table_list_reset(&htl2);
- continue;
- }
-
- /* Remove the channel entry */
- if (silc_idlist_del_channel(server->local_list, channel))
- server->stat.my_channels--;
- else
- silc_idlist_del_channel(server->global_list, channel);
+ silc_schedule_task_del_by_context(server->schedule, channel->rekey);
+ silc_server_channel_delete(server, channel);
+ silc_buffer_free(clidp);
continue;
}
- /* Send notify to channel about client leaving SILC and thus
- the entire channel. */
+ /* Send notify to channel about client leaving SILC and channel too */
if (notify)
silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
SILC_NOTIFY_TYPE_SIGNOFF,
signoff_message, signoff_message ?
strlen(signoff_message) : 0);
+ /* Re-generate channel key if needed */
if (keygen && !(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
- /* Re-generate channel key */
if (!silc_server_create_channel_key(server, channel, 0))
- goto out;
+ continue;
/* 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);
}
last client leaves the channel. If `notify' is FALSE notify messages
are not sent. */
-int silc_server_remove_from_one_channel(SilcServer server,
- SilcSocketConnection sock,
- SilcChannelEntry channel,
- SilcClientEntry client,
- int notify)
+bool silc_server_remove_from_one_channel(SilcServer server,
+ SilcSocketConnection sock,
+ SilcChannelEntry channel,
+ SilcClientEntry client,
+ bool notify)
{
SilcChannelClientEntry chl;
SilcBuffer clidp;
- SILC_LOG_DEBUG(("Start"));
+ SILC_LOG_DEBUG(("Removing %s from channel %s",
+ silc_id_render(client->id, SILC_ID_CLIENT),
+ channel->channel_name));
/* Get the entry to the channel, if this client is not on the channel
then return Ok. */
if (!silc_hash_table_find(client->channels, channel, NULL, (void *)&chl))
return TRUE;
- /* Remove the client from the channel. The client is removed from
- the channel's user list. */
-
- clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
-
- /* Remove channel from client's channel list */
- silc_hash_table_del(client->channels, chl->channel);
-
- /* Remove channel if there is no users anymore */
+ /* Remove channel if this is last client leaving the channel, unless
+ the channel is permanent. */
if (server->server_type == SILC_ROUTER &&
silc_hash_table_count(channel->user_list) < 2) {
- if (channel->rekey)
- silc_schedule_task_del_by_context(server->schedule, channel->rekey);
- if (silc_idlist_del_channel(server->local_list, channel))
- server->stat.my_channels--;
- else
- silc_idlist_del_channel(server->global_list, channel);
- silc_buffer_free(clidp);
+ silc_server_channel_delete(server, channel);
return FALSE;
}
- /* Remove client from channel's client list */
+ silc_hash_table_del(client->channels, chl->channel);
silc_hash_table_del(channel->user_list, chl->client);
channel->user_count--;
silc_free(chl);
server->stat.my_chanclients--;
+ clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ if (!clidp)
+ notify = FALSE;
+
/* If there is not at least one local user on the channel then we don't
- need the channel entry anymore, we can remove it safely. */
+ need the channel entry anymore, we can remove it safely, unless the
+ channel is permanent channel */
if (server->server_type != SILC_ROUTER &&
!silc_server_channel_has_local(channel)) {
/* Notify about leaving client if this channel has global users. */
SILC_NOTIFY_TYPE_LEAVE, 1,
clidp->data, clidp->len);
+ silc_schedule_task_del_by_context(server->schedule, channel->rekey);
+ silc_server_channel_delete(server, channel);
silc_buffer_free(clidp);
-
- if (channel->rekey)
- silc_schedule_task_del_by_context(server->schedule, channel->rekey);
-
- if (channel->founder_key) {
- /* The founder auth data exists, do not remove the channel entry */
- SilcChannelClientEntry chl2;
- SilcHashTableList htl2;
-
- channel->disabled = TRUE;
-
- silc_hash_table_list(channel->user_list, &htl2);
- while (silc_hash_table_get(&htl2, NULL, (void *)&chl2)) {
- silc_hash_table_del(chl2->client->channels, channel);
- silc_hash_table_del(channel->user_list, chl2->client);
- channel->user_count--;
- silc_free(chl2);
- }
- silc_hash_table_list_reset(&htl2);
- return FALSE;
- }
-
- /* Remove the channel entry */
- if (silc_idlist_del_channel(server->local_list, channel))
- server->stat.my_channels--;
- else
- silc_idlist_del_channel(server->global_list, channel);
return FALSE;
}
void silc_server_remove_from_channels(SilcServer server,
SilcSocketConnection sock,
SilcClientEntry client,
- int notify,
- char *signoff_message,
- int keygen);
-int silc_server_remove_from_one_channel(SilcServer server,
- SilcSocketConnection sock,
- SilcChannelEntry channel,
- SilcClientEntry client,
- int notify);
+ bool notify,
+ const char *signoff_message,
+ bool keygen);
+bool silc_server_remove_from_one_channel(SilcServer server,
+ SilcSocketConnection sock,
+ SilcChannelEntry channel,
+ SilcClientEntry client,
+ bool notify);
void silc_server_disconnect_remote(SilcServer server,
SilcSocketConnection sock,
SilcStatus status, ...);
while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
channel = chl->channel;
- /* Remove channel from client's channel list */
- silc_hash_table_del(client->channels, channel);
-
- /* Remove channel if there is no users anymore */
+ /* Remove channel if this is last client leaving the channel, unless
+ the channel is permanent. */
if (server->server_type == SILC_ROUTER &&
silc_hash_table_count(channel->user_list) < 2) {
-
if (silc_hash_table_find(channels, channel, NULL, NULL))
silc_hash_table_del(channels, channel);
-
- if (channel->rekey)
- silc_schedule_task_del_by_context(server->schedule, channel->rekey);
-
- if (silc_idlist_del_channel(server->local_list, channel))
- server->stat.my_channels--;
- else
- silc_idlist_del_channel(server->global_list, channel);
+ silc_schedule_task_del_by_context(server->schedule, channel->rekey);
+ silc_server_channel_delete(server, channel);
continue;
}
- /* Remove client from channel's client list */
+ silc_hash_table_del(client->channels, channel);
silc_hash_table_del(channel->user_list, chl->client);
channel->user_count--;
server->stat.my_chanclients--;
/* If there is not at least one local user on the channel then we don't
- need the channel entry anymore, we can remove it safely. */
+ need the channel entry anymore, we can remove it safely, unless the
+ channel is permanent channel */
if (server->server_type != SILC_ROUTER &&
!silc_server_channel_has_local(channel)) {
-
if (silc_hash_table_find(channels, channel, NULL, NULL))
silc_hash_table_del(channels, channel);
-
- if (channel->rekey)
- silc_schedule_task_del_by_context(server->schedule, channel->rekey);
-
- if (channel->founder_key) {
- /* The founder auth data exists, do not remove the channel entry */
- SilcChannelClientEntry chl2;
- SilcHashTableList htl2;
-
- channel->disabled = TRUE;
-
- silc_hash_table_list(channel->user_list, &htl2);
- while (silc_hash_table_get(&htl2, NULL, (void **)&chl2)) {
- silc_hash_table_del(chl2->client->channels, channel);
- silc_hash_table_del(channel->user_list, chl2->client);
- channel->user_count--;
- silc_free(chl2);
- }
- silc_hash_table_list_reset(&htl2);
- continue;
- }
-
- /* Remove the channel entry */
- if (silc_idlist_del_channel(server->local_list, channel))
- server->stat.my_channels--;
- else
- silc_idlist_del_channel(server->global_list, channel);
+ silc_schedule_task_del_by_context(server->schedule, channel->rekey);
+ silc_server_channel_delete(server, channel);
continue;
}
silc_hash_table_add(channels, channel, channel);
}
silc_hash_table_list_reset(&htl);
-
silc_buffer_free(clidp);
}
return FALSE;
}
+/* This function removes the channel and all users on the channel, unless
+ the channel is permanent. In this case the channel is disabled but all
+ users are removed from the channel. Returns TRUE if the channel is
+ destroyed totally, and FALSE if it is permanent and remains. */
+
+bool silc_server_channel_delete(SilcServer server,
+ SilcChannelEntry channel)
+{
+ SilcChannelClientEntry chl;
+ SilcHashTableList htl;
+ bool delchan = !(channel->mode & SILC_CHANNEL_MODE_FOUNDER_AUTH);
+
+ if (delchan) {
+ SILC_LOG_DEBUG(("Deleting %s channel", channel->channel_name));
+
+ /* Totally delete the channel and all users on the channel. The
+ users are deleted automatically in silc_idlist_del_channel. */
+ silc_schedule_task_del_by_context(server->schedule, channel->rekey);
+ if (silc_idlist_del_channel(server->local_list, channel))
+ server->stat.my_channels--;
+ else
+ silc_idlist_del_channel(server->global_list, channel);
+ return FALSE;
+ }
+
+ /* Channel is permanent, do not remove it, remove only users */
+ channel->disabled = TRUE;
+ silc_hash_table_list(channel->user_list, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
+ silc_hash_table_del(chl->client->channels, channel);
+ silc_hash_table_del(channel->user_list, chl->client);
+ channel->user_count--;
+ silc_free(chl);
+ }
+ silc_hash_table_list_reset(&htl);
+
+ SILC_LOG_DEBUG(("Channel %s remains", channel->channel_name));
+
+ return TRUE;
+}
+
/* Returns TRUE if the given client is on the channel. FALSE if not.
This works because we assure that the user list on the channel is
always in up to date thus we can only check the channel list from
return found;
}
+
+/* Force the client indicated by `chl' to change the channel user mode
+ on channel indicated by `channel' to `forced_mode'. */
+
+bool silc_server_force_cumode_change(SilcServer server,
+ SilcSocketConnection sock,
+ SilcChannelEntry channel,
+ SilcChannelClientEntry chl,
+ SilcUInt32 forced_mode)
+{
+ SilcBuffer idp1, idp2;
+ unsigned char cumode[4];
+
+ silc_server_send_notify_cumode(server, sock, FALSE, channel, forced_mode,
+ server->id, SILC_ID_SERVER,
+ chl->client->id);
+
+ idp1 = silc_id_payload_encode(server->id, SILC_ID_SERVER);
+ idp2 = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
+ SILC_PUT32_MSB(forced_mode, cumode);
+ silc_server_send_notify_to_channel(server, sock, channel, FALSE,
+ SILC_NOTIFY_TYPE_CUMODE_CHANGE,
+ 3, idp1->data, idp1->len,
+ cumode, sizeof(cumode),
+ idp2->data, idp2->len);
+ silc_buffer_free(idp1);
+ silc_buffer_free(idp2);
+}
returns TRUE and FALSE if there is not one locally connected client. */
bool silc_server_channel_has_local(SilcChannelEntry channel);
+/* This function removes the channel and all users on the channel, unless
+ the channel is permanent. In this case the channel is disabled but all
+ users are removed from the channel. Returns TRUE if the channel is
+ destroyed totally, and FALSE if it is permanent and remains. */
+bool silc_server_channel_delete(SilcServer server,
+ SilcChannelEntry channel);
+
/* Returns TRUE if the given client is on the channel. FALSE if not.
This works because we assure that the user list on the channel is
always in up to date thus we can only check the channel list from
bool silc_server_del_from_watcher_list(SilcServer server,
SilcClientEntry client);
+/* Force the client indicated by `chl' to change the channel user mode
+ on channel indicated by `channel' to `forced_mode'. */
+bool silc_server_force_cumode_change(SilcServer server,
+ SilcSocketConnection sock,
+ SilcChannelEntry channel,
+ SilcChannelClientEntry chl,
+ SilcUInt32 forced_mode);
+
#endif /* SERVER_UTIL_H */
/* Unregister all tasks */
silc_schedule_task_del_by_fd(client->schedule, sock->sock);
- silc_schedule_task_del_by_fd(client->schedule, sock->sock);
/* Close the actual connection */
silc_net_close_connection(sock->sock);
res->context = client;
res->sock = silc_socket_dup(conn->sock);
res->packet = silc_id_dup(client_id, SILC_ID_CLIENT);
- silc_schedule_task_add(client->schedule, 0,
+ silc_schedule_task_add(client->schedule, conn->sock->sock,
silc_client_notify_check_client, res,
(5 + (silc_rng_get_rn16(client->rng) % 29)),
0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
res->context = client;
res->sock = silc_socket_dup(conn->sock);
res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
- silc_schedule_task_add(client->schedule, 0,
+ silc_schedule_task_add(client->schedule, conn->sock->sock,
silc_client_notify_check_client, res,
(5 + (silc_rng_get_rn16(client->rng) % 529)),
0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
if (add) {
mode |= SILC_CHANNEL_MODE_FOUNDER_AUTH;
type = 7;
-
- if (cmd->argc < 4) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
- COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- if (!strcasecmp(cmd->argv[3], "-pubkey")) {
- auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
- cmd->client->private_key,
- cmd->client->rng,
- conn->hash,
- conn->local_id,
- SILC_ID_CLIENT);
- } else {
- auth = silc_auth_payload_encode(SILC_AUTH_PASSWORD, NULL, 0,
- cmd->argv[3], cmd->argv_lens[3]);
- }
-
+ auth = silc_auth_public_key_auth_generate(cmd->client->public_key,
+ cmd->client->private_key,
+ cmd->client->rng,
+ conn->hash,
+ conn->local_id,
+ SILC_ID_CLIENT);
arg = auth->data;
arg_len = auth->len;
} else {
return FALSE;
}
+/* Copies the public key indicated by `public_key' and returns new allocated
+ public key which is indentical to the `public_key'. */
+
+SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key)
+{
+ SilcPublicKey key = silc_calloc(1, sizeof(*key));
+ if (!key)
+ return NULL;
+
+ key->len = public_key->len;
+ key->name = silc_memdup(public_key->name, strlen(public_key->name));
+ key->identifier = silc_memdup(public_key->identifier,
+ strlen(public_key->identifier));
+ key->pk = silc_memdup(public_key->pk, public_key->pk_len);
+ key->pk_len = public_key->pk_len;
+
+ return key;
+}
+
/* Encodes SILC private key from SilcPrivateKey. Returns the encoded data. */
unsigned char *
int silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len,
SilcPublicKey *public_key);
bool silc_pkcs_public_key_compare(SilcPublicKey key1, SilcPublicKey key2);
+SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key);
unsigned char *
silc_pkcs_private_key_encode(SilcPrivateKey private_key, SilcUInt32 *len);
unsigned char *