SilcNotifyPayload payload;
SilcNotifyType type;
SilcArgumentPayload args;
- SilcChannelID *channel_id;
+ SilcChannelID *channel_id, *channel_id2;
SilcClientID *client_id, *client_id2;
SilcChannelEntry channel;
SilcClientEntry client;
SilcChannelClientEntry chl;
+ SilcIDCacheEntry cache;
unsigned int mode;
unsigned char *tmp;
unsigned int tmp_len;
/* Get the route to the client */
dst_sock = silc_server_get_client_route(server, packet->dst_id,
- packet->dst_id_len, &idata);
+ packet->dst_id_len, NULL, &idata);
if (dst_sock)
/* Relay the packet */
silc_server_relay_packet(server, dst_sock, idata->send_key,
goto out;
client =
- silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
+ silc_idlist_add_client(server->global_list, NULL, 0, NULL, NULL,
silc_id_dup(client_id, SILC_ID_CLIENT),
sock->user_data, NULL);
if (!client) {
silc_free(client_id);
goto out;
}
+
+ client->data.registered = TRUE;
}
}
/* Get client entry */
client = silc_idlist_find_client_by_id(server->global_list,
- client_id, NULL);
+ client_id, &cache);
if (!client) {
client = silc_idlist_find_client_by_id(server->local_list,
- client_id, NULL);
+ client_id, &cache);
if (!client) {
silc_free(client_id);
goto out;
/* Remove the client from all channels */
silc_server_remove_from_channels(server, NULL, client, TRUE, tmp, TRUE);
+ client->data.registered = FALSE;
+ cache->expire = SILC_ID_CACHE_EXPIRE_DEF;
+
+#if 0
/* Remove the client entry */
if (!silc_idlist_del_client(server->global_list, client))
silc_idlist_del_client(server->local_list, client);
+#endif
break;
case SILC_NOTIFY_TYPE_TOPIC_SET:
/* Change mode */
channel->mode = mode;
silc_free(channel_id);
+
+ /* Get the hmac */
+ tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
+ if (tmp) {
+ unsigned char hash[32];
+
+ if (channel->hmac)
+ silc_hmac_free(channel->hmac);
+ if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
+ goto out;
+
+ /* Set the HMAC key out of current channel key. The client must do
+ this locally. */
+ silc_hash_make(channel->hmac->hash, channel->key, channel->key_len / 8,
+ hash);
+ silc_hmac_set_key(channel->hmac, hash,
+ silc_hash_len(channel->hmac->hash));
+ memset(hash, 0, sizeof(hash));
+ }
+
break;
case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
break;
case SILC_NOTIFY_TYPE_INVITE:
- SILC_LOG_DEBUG(("INVITE notify (not-impl XXX)"));
+
+ if (packet->dst_id_type == SILC_ID_CLIENT)
+ goto out;
+
+ SILC_LOG_DEBUG(("INVITE notify"));
+
+ /* Get Channel ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id)
+ goto out;
+
+ /* Get channel entry */
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_free(channel_id);
+ goto out;
+ }
+ }
+ silc_free(channel_id);
+
+ /* Get the added invite */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (tmp) {
+ if (!channel->invite_list)
+ channel->invite_list = silc_calloc(tmp_len + 2,
+ sizeof(*channel->invite_list));
+ else
+ channel->invite_list = silc_realloc(channel->invite_list,
+ sizeof(*channel->invite_list) *
+ (tmp_len +
+ strlen(channel->invite_list) +
+ 2));
+ if (tmp[tmp_len - 1] == ',')
+ tmp[tmp_len - 1] = '\0';
+
+ strncat(channel->invite_list, tmp, tmp_len);
+ strncat(channel->invite_list, ",", 1);
+ }
+
+ /* Get the deleted invite */
+ tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
+ if (tmp && channel->invite_list) {
+ char *start, *end, *n;
+
+ if (!strncmp(channel->invite_list, tmp,
+ strlen(channel->invite_list) - 1)) {
+ silc_free(channel->invite_list);
+ channel->invite_list = NULL;
+ } else {
+ start = strstr(channel->invite_list, tmp);
+ if (start && strlen(start) >= tmp_len) {
+ end = start + tmp_len;
+ n = silc_calloc(strlen(channel->invite_list) - tmp_len, sizeof(*n));
+ strncat(n, channel->invite_list, start - channel->invite_list);
+ strncat(n, end + 1, ((channel->invite_list +
+ strlen(channel->invite_list)) - end) - 1);
+ silc_free(channel->invite_list);
+ channel->invite_list = n;
+ }
+ }
+ }
+
break;
case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
- SILC_LOG_DEBUG(("CHANNEL CHANGE notify (not-impl XXX)"));
+ /*
+ * Distribute to the local clients on the channel and change the
+ * channel ID.
+ */
+
+ SILC_LOG_DEBUG(("CHANNEL CHANGE"));
+
+ /* Get the old Channel ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id)
+ goto out;
+
+ /* Get the channel entry */
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_free(channel_id);
+ goto out;
+ }
+ }
+
+ /* Send the notify to the channel */
+ silc_server_packet_send_to_channel(server, sock, channel, packet->type,
+ FALSE, packet->buffer->data,
+ packet->buffer->len, FALSE);
+
+ /* Get the new Channel ID */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
+ channel_id2 = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id2)
+ goto out;
+
+ /* Replace the Channel ID */
+ if (!silc_idlist_replace_channel_id(server->global_list, channel_id,
+ channel_id2))
+ silc_idlist_replace_channel_id(server->local_list, channel_id,
+ channel_id2);
+
+ silc_free(channel_id);
+ silc_free(channel_id2);
+
break;
case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
break;
+ case SILC_NOTIFY_TYPE_BAN:
+ /*
+ * Save the ban
+ */
+
+ SILC_LOG_DEBUG(("BAN notify"));
+
+ /* Get Channel ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id)
+ goto out;
+
+ /* Get channel entry */
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_free(channel_id);
+ goto out;
+ }
+ }
+ silc_free(channel_id);
+
+ /* Get the new ban and add it to the ban list */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (tmp) {
+ if (!channel->ban_list)
+ channel->ban_list = silc_calloc(tmp_len + 2,
+ sizeof(*channel->ban_list));
+ else
+ channel->ban_list = silc_realloc(channel->ban_list,
+ sizeof(*channel->ban_list) *
+ (tmp_len +
+ strlen(channel->ban_list) + 2));
+ strncat(channel->ban_list, tmp, tmp_len);
+ strncat(channel->ban_list, ",", 1);
+ }
+
+ /* Get the ban to be removed and remove it from the list */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (tmp && channel->ban_list) {
+ char *start, *end, *n;
+
+ if (!strcmp(channel->ban_list, tmp)) {
+ silc_free(channel->ban_list);
+ channel->ban_list = NULL;
+ } else {
+ start = strstr(channel->ban_list, tmp);
+ if (start && strlen(start) >= tmp_len) {
+ end = start + tmp_len;
+ n = silc_calloc(strlen(channel->ban_list) - tmp_len, sizeof(*n));
+ strncat(n, channel->ban_list, start - channel->ban_list);
+ strncat(n, end + 1, ((channel->ban_list +
+ strlen(channel->ban_list)) - end) - 1);
+ silc_free(channel->ban_list);
+ channel->ban_list = n;
+ }
+ }
+ }
+
+ break;
+
/* Ignore rest of the notify types for now */
case SILC_NOTIFY_TYPE_NONE:
case SILC_NOTIFY_TYPE_MOTD:
/* Get the route to the client */
dst_sock = silc_server_get_client_route(server, packet->dst_id,
- packet->dst_id_len, &idata);
+ packet->dst_id_len, NULL, &idata);
if (!dst_sock)
return;
/* Get the route to the client */
dst_sock = silc_server_get_client_route(server, packet->dst_id,
- packet->dst_id_len, &idata);
+ packet->dst_id_len, NULL, &idata);
if (!dst_sock)
return;
sock->type == SILC_SOCKET_TYPE_ROUTER &&
!(channel->mode & SILC_CHANNEL_MODE_PRIVKEY)) {
SilcBuffer chp;
- unsigned int iv_len, i, data_len;
+ unsigned int iv_len, i;
+ unsigned short data_len, flags;
iv_len = silc_cipher_get_block_len(channel->channel_key);
if (channel->iv[0] == '\0')
silc_hash_make(server->md5hash, channel->iv, iv_len, channel->iv);
/* Encode new payload. This encrypts it also. */
- SILC_GET16_MSB(data_len, packet->buffer->data);
- chp = silc_channel_message_payload_encode(data_len,
- packet->buffer->data + 2,
+ SILC_GET16_MSB(flags, packet->buffer->data);
+ SILC_GET16_MSB(data_len, packet->buffer->data + 2);
+ chp = silc_channel_message_payload_encode(flags, data_len,
+ packet->buffer->data + 4,
iv_len, channel->iv,
channel->channel_key,
- channel->hmac, server->rng);
+ channel->hmac);
silc_buffer_put(packet->buffer, chp->data, chp->len);
silc_buffer_free(chp);
}
SilcServerID *server_id;
SilcIDListData idata;
unsigned char *server_name, *id_string;
- unsigned short id_len;
+ unsigned short id_len, name_len;
int ret;
SILC_LOG_DEBUG(("Creating new server"));
/* Parse the incoming packet */
ret = silc_buffer_unformat(buffer,
SILC_STR_UI16_NSTRING_ALLOC(&id_string, &id_len),
- SILC_STR_UI16_STRING_ALLOC(&server_name),
+ SILC_STR_UI16_NSTRING_ALLOC(&server_name,
+ &name_len),
SILC_STR_END);
if (ret == -1) {
if (id_string)
return NULL;
}
+ if (name_len > 256)
+ server_name[255] = '\0';
+
/* Get Server ID */
server_id = silc_id_str2id(id_string, id_len, SILC_ID_SERVER);
if (!server_id) {
list. The client is put to global list and we will take the hash
value of the Client ID and save it to the ID Cache system for fast
searching in the future. */
- hash = silc_calloc(sizeof(((SilcClientID *)id)->hash),
+ hash = silc_calloc(sizeof(((SilcClientID *)id)->hash),
sizeof(unsigned char));
memcpy(hash, ((SilcClientID *)id)->hash,
sizeof(((SilcClientID *)id)->hash));
- entry = silc_idlist_add_client(id_list, hash, NULL, NULL, id,
- router, NULL);
+ entry = silc_idlist_add_client(id_list, hash,
+ sizeof(((SilcClientID *)id)->hash),
+ NULL, NULL, id, router, NULL);
entry->nickname = NULL;
+ entry->data.registered = TRUE;
if (sock->type == SILC_SOCKET_TYPE_SERVER)
server->stat.cell_clients++;
server->stat.clients++;
-
-#if 0
- /* XXX Adding two ID's with same IP number replaces the old entry thus
- gives wrong route. Thus, now disabled until figured out a better way
- to do this or when removed the whole thing. This could be removed
- because entry->router->connection gives always the most optimal route
- for the ID anyway (unless new routes (faster perhaps) are established
- after receiving this ID, this we don't know however). */
- /* Add route cache for this ID */
- silc_server_route_add(silc_server_route_hash(
- ((SilcClientID *)id)->ip.s_addr,
- server->id->port), ((SilcClientID *)id)->ip.s_addr,
- router);
-#endif
}
break;
if (sock->type == SILC_SOCKET_TYPE_SERVER)
server->stat.cell_servers++;
server->stat.servers++;
-
-#if 0
- /* Add route cache for this ID */
- silc_server_route_add(silc_server_route_hash(
- ((SilcServerID *)id)->ip.s_addr,
- ((SilcServerID *)id)->port),
- ((SilcServerID *)id)->ip.s_addr,
- router);
-#endif
break;
case SILC_ID_CHANNEL:
/* Get the route to the client */
dst_sock = silc_server_get_client_route(server, packet->dst_id,
- packet->dst_id_len, &idata);
+ packet->dst_id_len, NULL, &idata);
if (!dst_sock)
return;
silc_server_relay_packet(server, dst_sock, idata->send_key,
idata->hmac, packet, FALSE);
}
+
+/* Received connection auth request packet that is used during connection
+ phase to resolve the mandatory authentication method. This packet can
+ actually be received at anytime but usually it is used only during
+ the connection authentication phase. Now, protocol says that this packet
+ can come from client or server, however, we support only this coming
+ from client and expect that server's always knows what authentication
+ method to use. */
+
+void silc_server_connection_auth_request(SilcServer server,
+ SilcSocketConnection sock,
+ SilcPacketContext *packet)
+{
+ SilcServerConfigSectionClientConnection *client = NULL;
+ unsigned short conn_type;
+ int ret;
+ SilcAuthMethod auth_meth;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (packet->src_id_type && packet->src_id_type != SILC_ID_CLIENT)
+ return;
+
+ /* Parse the payload */
+ ret = silc_buffer_unformat(packet->buffer,
+ SILC_STR_UI_SHORT(&conn_type),
+ SILC_STR_UI_SHORT(NULL),
+ SILC_STR_END);
+ if (ret == -1)
+ return;
+
+ if (conn_type != SILC_SOCKET_TYPE_CLIENT)
+ return;
+
+ /* Get the authentication method for the client */
+ auth_meth = SILC_AUTH_NONE;
+ client = silc_server_config_find_client_conn(server->config,
+ sock->ip,
+ sock->port);
+ if (!client)
+ client = silc_server_config_find_client_conn(server->config,
+ sock->hostname,
+ sock->port);
+ if (client)
+ auth_meth = client->auth_meth;
+
+ /* Send it back to the client */
+ silc_server_send_connection_auth_request(server, sock,
+ conn_type,
+ auth_meth);
+}