Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2003 Pekka Riikonen
+ Copyright (C) 1997 - 2005 Pekka Riikonen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
ctx->payload = silc_command_payload_parse(packet->buffer->data,
packet->buffer->len);
if (!ctx->payload) {
- SILC_LOG_ERROR(("Bad command payload, packet dropped"));
+ SILC_LOG_ERROR(("Bad command payload, dropped (%s:%d [%s])",
+ sock->hostname, sock->port,
+ (sock->type == SILC_SOCKET_TYPE_UNKNOWN ? "Unknown" :
+ sock->type == SILC_SOCKET_TYPE_CLIENT ? "Client" :
+ sock->type == SILC_SOCKET_TYPE_SERVER ? "Server" :
+ "Router")));
silc_packet_context_free(packet);
silc_socket_free(ctx->sock);
silc_free(ctx);
SilcBuffer packet, nidp, oidp = NULL;
SilcClientID *new_id;
SilcUInt32 nick_len;
- char *nick;
+ unsigned char *nick, *nickc = NULL;
SilcUInt16 ident = silc_command_get_ident(cmd->payload);
- int nickfail = 0;
if (cmd->sock->type != SILC_SOCKET_TYPE_CLIENT || !client)
goto out;
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_NICK, cmd, 1, 1);
- /* Check nickname */
+ /* Get nickname */
nick = silc_argument_get_arg_type(cmd->args, 1, &nick_len);
if (!nick) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
SILC_STATUS_ERR_BAD_NICKNAME, 0);
goto out;
}
- if (nick_len > 128)
+
+ /* Truncate over long nicks */
+ if (nick_len > 128) {
nick[128] = '\0';
- if (silc_server_name_bad_chars(nick, nick_len) == TRUE) {
+ nick_len = 128;
+ }
+
+ /* Check for valid nickname string. This is cached, original is saved
+ in the client context. */
+ nickc = silc_identifier_check(nick, nick_len, SILC_STRING_UTF8, 128, NULL);
+ if (!nickc) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
SILC_STATUS_ERR_BAD_NICKNAME, 0);
goto out;
}
/* Check for same nickname */
- if (!strcmp(client->nickname, nick)) {
+ if (strlen(client->nickname) == nick_len &&
+ !memcmp(client->nickname, nick, nick_len)) {
nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ silc_free(nickc);
goto send_reply;
}
/* Create new Client ID */
- while (!silc_id_create_client_id(cmd->server, cmd->server->id,
- cmd->server->rng,
- cmd->server->md5hash, nick,
- &new_id)) {
- nickfail++;
- if (nickfail > 9) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
- SILC_STATUS_ERR_BAD_NICKNAME, 0);
- goto out;
- }
- snprintf(&nick[strlen(nick) - 1], 1, "%d", nickfail);
+ if (!silc_id_create_client_id(cmd->server, cmd->server->id,
+ cmd->server->rng,
+ cmd->server->md5hash,
+ nickc, strlen(nickc), &new_id)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_NICK,
+ SILC_STATUS_ERR_BAD_NICKNAME, 0);
+ silc_free(nickc);
+ goto out;
}
/* Send notify about nickname change to our router. We send the new
client->nickname = strdup(nick);
/* Update client cache */
- silc_idcache_add(server->local_list->clients, client->nickname,
+ silc_idcache_add(server->local_list->clients, nickc,
client->id, (void *)client, 0, NULL);
nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK,
SILC_STATUS_OK, 0, ident, 2,
2, nidp->data, nidp->len,
- 3, nick, strlen(nick));
+ 3, nick, nick_len);
silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
0, packet->data, packet->len, FALSE);
valid_rcount++;
}
+ if (!lch_count && !gch_count) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_LIST,
+ SILC_STATUS_OK, 0);
+ return;
+ }
+
status = SILC_STATUS_OK;
if ((lch_count + gch_count) > 1)
status = SILC_STATUS_LIST_START;
goto out;
}
+ if (!silc_utf8_valid(tmp, strlen(tmp))) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+ 0);
+ goto out;
+ }
+
/* See whether the client is on channel and has rights to change topic */
if (!silc_server_client_on_channel(client, channel, &chl)) {
tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
/* Check if the ID is in the list already */
silc_hash_table_list(channel->invite_list, &htl);
- while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2)) {
+ while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2)) {
if (type == 3 && !memcmp(tmp2->data, tmp, len)) {
tmp = NULL;
break;
}
/* Now add or delete the information. */
- silc_server_inviteban_process(server, channel->invite_list,
- (SilcUInt8)atype[0], args);
+ if (!silc_server_inviteban_process(server, channel->invite_list,
+ (SilcUInt8)atype[0], args)) {
+ silc_server_command_send_status_reply(
+ cmd, SILC_COMMAND_INVITE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+ 0);
+ goto out;
+ }
}
silc_argument_payload_free(args);
}
channel->invite_list)),
SILC_STR_END);
silc_hash_table_list(channel->invite_list, &htl);
- while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2))
+ while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
type);
silc_hash_table_list_reset(&htl);
SilcServer server = app_context;
QuitInternal q = (QuitInternal)context;
- /* Free all client specific data, such as client entry and entires
- on channels this client may be on. */
- silc_server_free_client_data(server, q->sock, q->sock->user_data,
- TRUE, q->signoff);
- q->sock->user_data = NULL;
+ if (q->sock->user_data) {
+ /* Free all client specific data, such as client entry and entires
+ on channels this client may be on. */
+ silc_server_free_client_data(server, q->sock, q->sock->user_data,
+ TRUE, q->signoff);
+ q->sock->user_data = NULL;
+ }
- /* Close the connection on our side */
- silc_server_close_connection(server, q->sock);
+ if (!SILC_IS_DISCONNECTED(q->sock))
+ /* Close the connection on our side */
+ silc_server_close_connection(server, q->sock);
silc_socket_free(q->sock);
silc_free(q->signoff);
SilcBuffer packet, idp;
unsigned char *tmp;
SilcUInt32 tmp_len;
- char *dest_server, *server_info = NULL, *server_name;
+ char *dest_server = NULL, *server_info = NULL, *server_name;
SilcUInt16 ident = silc_command_get_ident(cmd->payload);
SilcServerEntry entry = NULL;
SilcServerID *server_id = NULL;
/* Get server name */
dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ if (dest_server) {
+ /* Check server name. */
+ dest_server = silc_identifier_check(dest_server, strlen(dest_server),
+ SILC_STRING_UTF8, 256, &tmp_len);
+ if (!dest_server) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+ SILC_STATUS_ERR_BAD_SERVER, 0);
+ goto out;
+ }
+ }
/* Get Server ID */
tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
if ((!dest_server && !server_id && !entry) || (entry &&
entry == server->id_entry) ||
(dest_server && !cmd->pending &&
- !strncasecmp(dest_server, server->server_name, strlen(dest_server)))) {
+ !memcmp(dest_server, server->server_name, strlen(dest_server)))) {
/* Send our reply */
char info_string[256];
silc_free(server_id);
if (!entry) {
- if (dest_server)
+ if (dest_server) {
+ silc_free(dest_server);
+ dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
silc_server_command_send_status_data(cmd, SILC_COMMAND_INFO,
SILC_STATUS_ERR_NO_SUCH_SERVER, 0,
2, dest_server,
strlen(dest_server));
+ dest_server = NULL;
+ }
goto out;
}
silc_buffer_free(idp);
out:
+ silc_free(dest_server);
silc_server_command_free(cmd);
}
SilcSocketConnection sock = cmd->sock;
unsigned char *tmp;
SilcUInt32 tmp_len, user_count;
- unsigned char *passphrase = NULL, mode[4], tmp2[4], tmp3[4];
+ unsigned char *passphrase = NULL, mode[4], tmp2[4], tmp3[4], ulimit[4];
SilcClientEntry client;
SilcChannelClientEntry chl;
SilcBuffer reply, chidp, clidp, keyp = NULL;
&resolve);
if (!client) {
if (!resolve || cmd->pending) {
- silc_server_command_send_status_reply(
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ silc_server_command_send_status_data(
cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0,
+ 2, tmp, tmp_len);
goto out;
}
if (!strchr(client->nickname, '@')) {
silc_strncat(check2, sizeof(check2), "@", 1);
silc_strncat(check2, sizeof(check2),
- server->server_name, strlen(server->server_name));
+ SILC_IS_LOCAL(client) ? server->server_name :
+ client->router->server_name,
+ SILC_IS_LOCAL(client) ? strlen(server->server_name) :
+ strlen(client->router->server_name));
}
silc_strncat(check2, sizeof(check2), "!", 1);
silc_strncat(check2, sizeof(check2),
passphrase = silc_memdup(tmp, tmp_len);
if (!passphrase || !channel->passphrase ||
+ strlen(channel->passphrase) != strlen(passphrase) ||
memcmp(passphrase, channel->passphrase, strlen(channel->passphrase))) {
chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
SILC_PUT32_MSB(channel->mode, mode);
SILC_PUT32_MSB(created, tmp2);
SILC_PUT32_MSB(user_count, tmp3);
+ if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
+ SILC_PUT32_MSB(channel->user_limit, ulimit);
if (!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
tmp = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
SILC_STR_END);
silc_hash_table_list(channel->invite_list, &htl);
- while (silc_hash_table_get(&htl, (void **)&tmp_len, (void **)&reply))
+ while (silc_hash_table_get(&htl, (void *)&tmp_len, (void *)&reply))
invite_list = silc_argument_payload_encode_one(invite_list,
reply->data,
reply->len, tmp_len);
SILC_STR_END);
silc_hash_table_list(channel->ban_list, &htl);
- while (silc_hash_table_get(&htl, (void **)&tmp_len, (void **)&reply))
+ while (silc_hash_table_get(&htl, (void *)&tmp_len, (void *)&reply))
ban_list = silc_argument_payload_encode_one(ban_list,
reply->data,
reply->len, tmp_len);
reply =
silc_command_reply_payload_encode_va(SILC_COMMAND_JOIN,
- SILC_STATUS_OK, 0, ident, 15,
+ SILC_STATUS_OK, 0, ident, 16,
2, channel->channel_name,
strlen(channel->channel_name),
3, chidp->data, chidp->len,
15, fkey ? fkey->data : NULL,
fkey ? fkey->len : 0,
16, chpklist ? chpklist->data : NULL,
- chpklist ? chpklist->len : 0);
+ chpklist ? chpklist->len : 0,
+ 17, (channel->mode &
+ SILC_CHANNEL_MODE_ULIMIT ?
+ ulimit : NULL),
+ (channel->mode &
+ SILC_CHANNEL_MODE_ULIMIT ?
+ sizeof(ulimit) : 0));
/* Send command reply */
silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
SilcServer server = cmd->server;
unsigned char *auth, *cauth;
SilcUInt32 tmp_len, auth_len, cauth_len;
- char *tmp, *channel_name = NULL, *cipher, *hmac;
+ char *tmp, *channel_name, *channel_namec = NULL, *cipher, *hmac;
SilcChannelEntry channel;
SilcUInt32 umode = 0;
bool created = FALSE, create_key = TRUE;
0);
goto out;
}
- channel_name = tmp;
- if (tmp_len > 256)
- channel_name[255] = '\0';
+ /* Truncate over long channel names */
+ if (tmp_len > 256) {
+ tmp[256] = '\0';
+ tmp_len = 256;
+ }
+ channel_name = tmp;
- if (silc_server_name_bad_chchars(channel_name, tmp_len) == TRUE) {
+ /* Check for valid channel name. This is cached, the original is saved
+ in the channel context. */
+ channel_namec = silc_channel_name_check(tmp, tmp_len, SILC_STRING_UTF8, 256,
+ NULL);
+ if (!channel_namec) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
SILC_STATUS_ERR_BAD_CHANNEL, 0);
goto out;
tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
if (!tmp) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+ SILC_STATUS_ERR_NO_CLIENT_ID,
0);
goto out;
}
client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
if (!client_id) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
- 0);
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_BAD_CLIENT_ID, 0,
+ 2, tmp, tmp_len);
goto out;
}
/* See if the channel exists */
channel = silc_idlist_find_channel_by_name(server->local_list,
- channel_name, NULL);
+ channel_namec, NULL);
if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) {
SilcClientEntry entry = (SilcClientEntry)cmd->sock->user_data;
/* We are router and the channel does not seem exist so we will check
our global list as well for the channel. */
channel = silc_idlist_find_channel_by_name(server->global_list,
- channel_name, NULL);
+ channel_namec, NULL);
if (!channel) {
/* Channel really does not exist, create it */
channel = silc_server_create_new_channel(server, server->id, cipher,
/* We are router and the channel does not seem exist so we will check
our global list as well for the channel. */
channel = silc_idlist_find_channel_by_name(server->global_list,
- channel_name, NULL);
+ channel_namec, NULL);
if (!channel) {
/* Channel really does not exist, create it */
channel = silc_server_create_new_channel(server, server->id, cipher,
silc_free(client_id);
out:
+ silc_free(channel_namec);
silc_server_command_free(cmd);
}
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcBuffer packet, idp;
- char *motd, *dest_server;
+ char *motd, *dest_server = NULL;
SilcUInt32 motd_len;
SilcUInt16 ident = silc_command_get_ident(cmd->payload);
goto out;
}
- if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
+ /* Check server name */
+ dest_server = silc_identifier_check(dest_server, strlen(dest_server),
+ SILC_STRING_UTF8, 256, NULL);
+ if (!dest_server) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
+ SILC_STATUS_ERR_BAD_SERVER,
+ 0);
+ goto out;
+ }
+
+ if (!memcmp(dest_server, server->server_name, strlen(dest_server))) {
/* Send our MOTD */
idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
SILC_STATUS_OK, 0,
ident, 2,
- 2, idp, idp->len,
+ 2, idp->data, idp->len,
3, motd, motd_len);
} else {
/* No motd */
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
SILC_STATUS_OK, 0,
ident, 1,
- 2, idp, idp->len);
+ 2, idp->data, idp->len);
}
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
goto out;
}
- if (!entry && !cmd->pending && !server->standalone) {
+ /* Send to primary router only if we don't know the server
+ * the client requested or if the server is not locally connected */
+ if ((!entry || !(entry->data.status & SILC_IDLIST_STATUS_LOCAL))
+ && !cmd->pending && !server->standalone) {
/* Send to the primary router */
SilcBuffer tmpbuf;
SilcUInt16 old_ident;
}
if (!entry) {
+ silc_free(dest_server);
+ dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
silc_server_command_send_status_data(cmd, SILC_COMMAND_MOTD,
SILC_STATUS_ERR_NO_SUCH_SERVER, 0,
2, dest_server,
strlen(dest_server));
+ dest_server = NULL;
goto out;
}
- idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
+ idp = silc_id_payload_encode(entry->id, SILC_ID_SERVER);
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
SILC_STATUS_OK, 0, ident, 2,
- 2, idp, idp->len,
+ 2, idp->data, idp->len,
3, entry->motd,
entry->motd ?
strlen(entry->motd) : 0);
}
out:
+ silc_free(dest_server);
silc_server_command_free(cmd);
}
}
/* Anonymous mode cannot be set by client */
- if (mask & SILC_UMODE_ANONYMOUS) {
- if (!(client->mode & SILC_UMODE_ANONYMOUS)) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
- SILC_STATUS_ERR_PERM_DENIED, 0);
- goto out;
- }
- } else {
- if (client->mode & SILC_UMODE_ANONYMOUS) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
- SILC_STATUS_ERR_PERM_DENIED, 0);
- goto out;
- }
+ if (mask & SILC_UMODE_ANONYMOUS &&
+ !(client->mode & SILC_UMODE_ANONYMOUS)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_UMODE,
+ SILC_STATUS_ERR_PERM_DENIED, 0);
+ goto out;
}
/* Update statistics */
server->stat.my_aways--;
}
+ /* If the client has anonymous mode set, preserve it. */
+ if (client->mode & SILC_UMODE_ANONYMOUS)
+ mask |= SILC_UMODE_ANONYMOUS;
+
/* Change the mode */
client->mode = mask;
SilcChannelClientEntry chl;
SilcBuffer packet, cidp;
unsigned char *tmp, *tmp_id, *tmp_mask, *chpkdata = NULL;
- char *cipher = NULL, *hmac = NULL, *passphrase = NULL;
+ char *cipher = NULL, *hmac = NULL, *passphrase = NULL, ulimit[4];
SilcUInt32 mode_mask = 0, old_mask = 0, tmp_len, tmp_len2, chpklen;
SilcUInt16 ident = silc_command_get_ident(cmd->payload);
bool set_mask = FALSE, set_chpk = FALSE;
channel->founder_key = NULL;
goto out;
}
- has_founder:
}
} else {
if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
}
}
}
+ has_founder:
if (mode_mask & SILC_CHANNEL_MODE_CHANNEL_AUTH) {
if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE, st, 0);
goto out;
}
- has_pk_list:
}
} else {
if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
}
}
}
+ has_pk_list:
/* Finally, set the mode */
old_mask = channel->mode = mode_mask;
/* Send CMODE_CHANGE notify. */
cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ if (mode_mask & SILC_CHANNEL_MODE_ULIMIT)
+ SILC_PUT32_MSB(channel->user_limit, ulimit);
silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
- SILC_NOTIFY_TYPE_CMODE_CHANGE, 7,
+ SILC_NOTIFY_TYPE_CMODE_CHANGE, 8,
cidp->data, cidp->len,
tmp_mask, 4,
cipher, cipher ? strlen(cipher) : 0,
fkey ? fkey->data : NULL,
fkey ? fkey->len : 0,
chpkdata ? chpkdata : NULL,
- chpkdata ? chpklen : 0);
+ chpkdata ? chpklen : 0,
+ mode_mask & SILC_CHANNEL_MODE_ULIMIT ?
+ ulimit : NULL,
+ mode_mask & SILC_CHANNEL_MODE_ULIMIT ?
+ sizeof(ulimit) : 0);
/* Set CMODE notify type to network */
if (chpkdata && chpklen)
/* Send command reply to sender */
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
- SILC_STATUS_OK, 0, ident, 4,
+ SILC_STATUS_OK, 0, ident, 5,
2, tmp_id, tmp_len2,
3, tmp_mask, 4,
4, fkey ? fkey->data : NULL,
fkey ? fkey->len : 0,
5, chpklist ? chpklist->data :
NULL, chpklist ? chpklist->len
- : 0);
+ : 0,
+ 6, (mode_mask &
+ SILC_CHANNEL_MODE_ULIMIT ?
+ ulimit : NULL),
+ (mode_mask &
+ SILC_CHANNEL_MODE_ULIMIT ?
+ sizeof(ulimit) : 0));
+
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
packet->data, packet->len, FALSE);
/* Get target client's entry */
target_client = silc_idlist_find_client_by_id(server->local_list,
client_id, TRUE, NULL);
- if (!target_client) {
+ if (!target_client)
target_client = silc_idlist_find_client_by_id(server->global_list,
client_id, TRUE, NULL);
- }
if (target_client != client &&
!(sender_mask & SILC_CHANNEL_UMODE_CHANFO) &&
!(sender_mask & SILC_CHANNEL_UMODE_CHANOP)) {
silc_server_command_send_status_data(cmd, SILC_COMMAND_CUMODE,
- SILC_STATUS_ERR_NO_CHANNEL_PRIV, 0,
+ SILC_STATUS_ERR_NOT_YOU, 0,
2, tmp_ch_id, tmp_ch_len);
goto out;
}
if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
if (target_client != client) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
- SILC_STATUS_ERR_NOT_YOU, 0);
+ SILC_STATUS_ERR_NO_CHANNEL_FOPRIV,
+ 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);
+ client is definitely the founder due to this authentication. This
+ is done only on router, not on server, since server cannot know
+ whether router will accept this mode change or not. XXX This
+ probably shouldn't be done anymore at all, may cause problems in
+ router-router connections too (maybe just AUTH_FAILED error should
+ be returned). -Pekka */
+ if (server->server_type == SILC_ROUTER) {
+ 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;
}
packet->data, packet->len, FALSE);
silc_buffer_free(packet);
- /* Send command reply to sender */
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_KICK,
- SILC_STATUS_OK, 0);
-
/* Send KICKED notify to local clients on the channel */
idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
silc_server_send_notify_to_channel(server, NULL, channel, FALSE, TRUE,
silc_argument_payload_encode_one(NULL, target_idp, target_idp_len, 3);
SilcArgumentPayload args =
silc_argument_payload_parse(ab->data, ab->len, 1);
+
silc_server_inviteban_process(server, channel->invite_list, 1, args);
silc_buffer_free(ab);
silc_argument_payload_free(args);
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
- unsigned char *username, *auth;
+ unsigned char *username = NULL, *auth;
SilcUInt32 tmp_len;
SilcServerConfigAdmin *admin;
SilcIDListData idata = (SilcIDListData)client;
goto out;
}
+ /* Check username */
+ username = silc_identifier_check(username, strlen(username),
+ SILC_STRING_UTF8, 128, &tmp_len);
+ if (!username) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+ SILC_STATUS_ERR_BAD_USERNAME,
+ 0);
+ goto out;
+ }
+
/* Get the admin configuration */
admin = silc_server_config_find_admin(server, cmd->sock->ip,
username, client->nickname);
SILC_STATUS_OK, 0);
out:
+ silc_free(username);
silc_server_command_free(cmd);
}
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
char *add_nick, *del_nick;
- SilcUInt32 add_nick_len, del_nick_len, tmp_len;
- char nick[128 + 1];
- unsigned char hash[16], *tmp;
+ SilcUInt32 add_nick_len, del_nick_len, tmp_len, pk_len;
+ unsigned char hash[16], *tmp, *pk, *nick;
SilcClientEntry client;
SilcClientID *client_id = NULL;
+ SilcUInt16 old_ident;
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_WATCH, cmd, 1, 3);
if (!cmd->pending) {
/* Send the command to router */
SilcBuffer tmpbuf;
- SilcUInt16 old_ident;
+
+ /* If backup receives this from primary, handle it locally */
+ if (server->server_type == SILC_BACKUP_ROUTER &&
+ cmd->sock == SILC_PRIMARY_ROUTE(server))
+ goto process_watch;
SILC_LOG_DEBUG(("Forwarding WATCH to router"));
cmd->pending = TRUE;
silc_command_set_ident(cmd->payload, old_ident);
silc_buffer_free(tmpbuf);
- } else if (context2) {
- /* Received reply from router, just send same data to the client. */
+ goto out;
+ } else {
SilcServerCommandReplyContext reply = context2;
SilcStatus status;
- SILC_LOG_DEBUG(("Received reply to WATCH from router"));
+ if (!reply)
+ goto out;
+
silc_command_get_status(reply->payload, &status, NULL);
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH, status,
- 0);
- }
- goto out;
+ /* Backup router handles the WATCH command also. */
+ if (server->server_type != SILC_BACKUP_ROUTER ||
+ SILC_STATUS_IS_ERROR(status)) {
+ /* Received reply from router, just send same data to the client. */
+ SILC_LOG_DEBUG(("Received reply to WATCH from router"));
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH, status,
+ 0);
+ goto out;
+ }
+ }
}
/* We are router and keep the watch list for local cell */
+ process_watch:
/* Get the client ID */
tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
client = silc_idlist_find_client_by_id(server->local_list,
client_id, TRUE, NULL);
if (!client) {
- silc_server_command_send_status_data(cmd, SILC_COMMAND_WATCH,
- SILC_STATUS_ERR_NO_SUCH_CLIENT_ID, 0,
- 2, tmp, tmp_len);
- goto out;
+ /* Backup checks global list also */
+ if (server->server_type == SILC_BACKUP_ROUTER)
+ client = silc_idlist_find_client_by_id(server->global_list,
+ client_id, TRUE, NULL);
+ if (!client) {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_WATCH,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+ 0, 2, tmp, tmp_len);
+ goto out;
+ }
}
+ /* Take public key for watching by public key */
+ pk = silc_argument_get_arg_type(cmd->args, 4, &pk_len);
+
/* Take nickname */
add_nick = silc_argument_get_arg_type(cmd->args, 2, &add_nick_len);
del_nick = silc_argument_get_arg_type(cmd->args, 3, &del_nick_len);
- if (!add_nick && !del_nick) {
+ if (!add_nick && !del_nick && !pk) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
0);
goto out;
}
- if (add_nick && add_nick_len > 128)
+ if (add_nick && add_nick_len > 128) {
add_nick[128] = '\0';
- if (del_nick && del_nick_len > 128)
+ add_nick_len = 128;
+ }
+ if (del_nick && del_nick_len > 128) {
del_nick[128] = '\0';
-
- memset(nick, 0, sizeof(nick));
+ del_nick_len = 128;
+ }
/* Add new nickname to be watched in our cell */
if (add_nick) {
- if (silc_server_name_bad_chars(add_nick, strlen(add_nick)) == TRUE) {
+ nick = silc_identifier_check(add_nick, add_nick_len, SILC_STRING_UTF8, 128,
+ &add_nick_len);
+ if (!nick) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
SILC_STATUS_ERR_BAD_NICKNAME, 0);
goto out;
/* Hash the nick, we have the hash saved, not nicks because we can
do one to one mapping to the nick from Client ID hash this way. */
- silc_to_lower(add_nick, nick, sizeof(nick) - 1);
- silc_hash_make(server->md5hash, nick, strlen(nick), hash);
+ silc_hash_make(server->md5hash, nick, add_nick_len, hash);
/* Check whether this client is already watching this nickname */
if (silc_hash_table_find_by_context(server->watcher_list, hash,
silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
SILC_STATUS_ERR_NICKNAME_IN_USE,
0);
+ silc_free(nick);
goto out;
}
/* Get the nickname from the watcher list and use the same key in
new entries as well. If key doesn't exist then create it. */
- if (!silc_hash_table_find(server->watcher_list, hash, (void **)&tmp, NULL))
+ if (!silc_hash_table_find(server->watcher_list, hash, (void *)&tmp, NULL))
tmp = silc_memdup(hash, CLIENTID_HASH_LEN);
/* Add the client to the watcher list with the specified nickname hash. */
silc_hash_table_add(server->watcher_list, tmp, client);
+ silc_free(nick);
}
/* Delete nickname from watch list */
if (del_nick) {
- if (silc_server_name_bad_chars(del_nick, strlen(del_nick)) == TRUE) {
+ nick = silc_identifier_check(del_nick, del_nick_len, SILC_STRING_UTF8, 128,
+ &del_nick_len);
+ if (!nick) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
SILC_STATUS_ERR_BAD_NICKNAME, 0);
goto out;
/* Hash the nick, we have the hash saved, not nicks because we can
do one to one mapping to the nick from Client ID hash this way. */
- silc_to_lower(del_nick, nick, sizeof(nick) - 1);
- silc_hash_make(server->md5hash, nick, strlen(nick), hash);
+ silc_hash_make(server->md5hash, nick, del_nick_len, hash);
/* Check that this client is watching for this nickname */
if (!silc_hash_table_find_by_context(server->watcher_list, hash,
- client, (void **)&tmp)) {
+ client, (void *)&tmp)) {
/* Nickname is alredy being watched for this client */
silc_server_command_send_status_data(cmd, SILC_COMMAND_WATCH,
SILC_STATUS_ERR_NO_SUCH_NICK, 0,
- 2, nick, strlen(nick));
+ 2, nick, del_nick_len);
+ silc_free(nick);
goto out;
}
then free the key to not leak memory. */
if (!silc_hash_table_find(server->watcher_list, hash, NULL, NULL))
silc_free(tmp);
+ silc_free(nick);
}
+ /* Add/del public key */
+ if (pk) {
+ SilcUInt16 pkargc;
+ SilcArgumentPayload pkargs;
+ SilcUInt32 type;
+ SilcPublicKey public_key, pkkey;
+
+ if (pk_len < 2) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+ 0);
+ goto out;
+ }
+
+ /* Get the argument from the Argument List Payload */
+ SILC_GET16_MSB(pkargc, pk);
+ pkargs = silc_argument_payload_parse(pk + 2, pk_len - 2, pkargc);
+ if (!pkargs) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+ 0);
+ goto out;
+ }
+
+ pk = silc_argument_get_next_arg(pkargs, &type, &pk_len);
+ while (pk) {
+ if (!silc_pkcs_public_key_payload_decode(pk, pk_len, &public_key))
+ continue;
+ if (type == 0x03)
+ type = 0x00;
+
+ if (type == 0x00) {
+ /* Add public key to watch list */
+
+ /* Check whether this client is already watching this public key */
+ if (silc_hash_table_find_by_context(server->watcher_list_pk,
+ public_key, client, NULL)) {
+ silc_pkcs_public_key_free(public_key);
+ silc_server_command_send_status_reply(
+ cmd, SILC_COMMAND_WATCH,
+ SILC_STATUS_ERR_NICKNAME_IN_USE, 0);
+ goto out;
+ }
+
+ /* Get the public key from the watcher list and use the same key in
+ new entries as well. If key doesn't exist then create it. */
+ pkkey = NULL;
+ if (!silc_hash_table_find(server->watcher_list_pk, public_key,
+ (void *)&pkkey, NULL))
+ pkkey = public_key;
+ else
+ silc_pkcs_public_key_free(public_key);
+
+ /* Add the client to the watcher list with the specified public
+ key. */
+ silc_hash_table_add(server->watcher_list_pk, pkkey, client);
+
+ } else if (type == 0x01) {
+ /* Delete public key from watch list */
+
+ /* Check that this client is watching this public key */
+ if (silc_hash_table_find_by_context(server->watcher_list_pk,
+ public_key, client,
+ (void *)&pkkey)) {
+ silc_pkcs_public_key_free(public_key);
+ silc_server_command_send_status_reply(
+ cmd, SILC_COMMAND_WATCH,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS, 0);
+ goto out;
+ }
+
+ /* Delete the public key from the watcher list. */
+ silc_hash_table_del_by_context(server->watcher_list_pk,
+ public_key, client);
+
+ /* Now check whether there still exists entries with this key, if
+ not then free the key to not leak memory. */
+ if (!silc_hash_table_find(server->watcher_list_pk, hash, NULL, NULL))
+ silc_pkcs_public_key_free(pkkey);
+ silc_pkcs_public_key_free(public_key);
+ }
+
+ pk = silc_argument_get_next_arg(pkargs, &type, &pk_len);
+ }
+ }
+
+ /* Send reply */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
+ SILC_STATUS_OK, 0);
+
/* Distribute the watch list to backup routers too */
if (server->backup) {
SilcBuffer tmpbuf;
+ old_ident = silc_command_get_ident(cmd->payload);
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,
+ silc_server_backup_send(server, cmd->sock->user_data, SILC_PACKET_COMMAND,
cmd->packet->flags, tmpbuf->data, tmpbuf->len,
FALSE, TRUE);
+ silc_command_set_ident(cmd->payload, old_ident);
silc_buffer_free(tmpbuf);
}
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_WATCH,
- SILC_STATUS_OK, 0);
-
out:
silc_free(client_id);
silc_server_command_free(cmd);
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
- unsigned char *username, *auth;
+ unsigned char *username = NULL, *auth;
SilcUInt32 tmp_len;
SilcServerConfigAdmin *admin;
SilcIDListData idata = (SilcIDListData)client;
goto out;
}
+ /* Check username */
+ username = silc_identifier_check(username, tmp_len, SILC_STRING_UTF8, 128,
+ &tmp_len);
+ if (!username) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_OPER,
+ SILC_STATUS_ERR_BAD_USERNAME,
+ 0);
+ goto out;
+ }
+
/* Get the admin configuration */
admin = silc_server_config_find_admin(server, cmd->sock->ip,
username, client->nickname);
SILC_STATUS_OK, 0);
out:
+ silc_free(username);
silc_server_command_free(cmd);
}
}
/* Now add or delete the information. */
- silc_server_inviteban_process(server, channel->ban_list,
- (SilcUInt8)atype[0], args);
+ if (!silc_server_inviteban_process(server, channel->ban_list,
+ (SilcUInt8)atype[0], args)) {
+ silc_server_command_send_status_reply(
+ cmd, SILC_COMMAND_BAN,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS,
+ 0);
+ goto out;
+ }
}
silc_argument_payload_free(args);
}
channel->ban_list)),
SILC_STR_END);
silc_hash_table_list(channel->ban_list, &htl);
- while (silc_hash_table_get(&htl, (void **)&type, (void **)&tmp2))
+ while (silc_hash_table_get(&htl, (void *)&type, (void *)&tmp2))
list = silc_argument_payload_encode_one(list, tmp2->data, tmp2->len,
type);
silc_hash_table_list_reset(&htl);
unsigned char lc[4];
SilcUInt32 list_count = 0;
SilcUInt16 ident = silc_command_get_ident(cmd->payload);
- char *channel_name;
+ char *channel_name, *channel_namec = NULL;
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_USERS, cmd, 1, 2);
goto out;
}
+ /* Check channel name */
+ if (channel_name) {
+ channel_namec = silc_channel_name_check(channel_name, strlen(channel_name),
+ SILC_STRING_UTF8, 256, NULL);
+ if (!channel_namec) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
+ SILC_STATUS_ERR_BAD_CHANNEL, 0);
+ goto out;
+ }
+ }
+
+ /* Check Channel ID */
if (channel_id) {
id = silc_id_payload_parse_id(channel_id, channel_id_len, NULL);
if (!id) {
channel = silc_idlist_find_channel_by_id(server->local_list, id, NULL);
else
channel = silc_idlist_find_channel_by_name(server->local_list,
- channel_name, NULL);
+ channel_namec, NULL);
if (!channel || (!server->standalone && (channel->disabled ||
!channel->users_resolved))) {
channel = silc_idlist_find_channel_by_id(server->global_list, id, NULL);
else
channel = silc_idlist_find_channel_by_name(server->global_list,
- channel_name, NULL);
+ channel_namec, NULL);
if (!channel) {
/* Channel really does not exist */
if (id)
silc_free(id);
out:
+ silc_free(channel_namec);
silc_server_command_free(cmd);
}
SILC_GET32_MSB(port, tmp);
server_entry = silc_idlist_find_server_by_conn(server->local_list,
- name, port, FALSE, NULL);
+ name, port, TRUE, NULL);
if (!server_entry)
server_entry = silc_idlist_find_server_by_conn(server->global_list,
- name, port, FALSE, NULL);
+ name, port, TRUE, NULL);
if (!server_entry) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
SILC_STATUS_ERR_NO_SERVER_ID, 0);
/* Close the connection to the server */
sock = (SilcSocketConnection)server_entry->connection;
+ if (server_entry->server_type == SILC_BACKUP_ROUTER) {
+ server->backup_closed = TRUE;
+ silc_server_backup_del(server, server_entry);
+ }
+
server->backup_noswitch = TRUE;
if (server->router == server_entry) {
server->id_entry->router = NULL;