void silc_client_free(SilcClient client)
{
if (client) {
+ if (client->rng)
+ silc_rng_free(client->rng);
+
silc_free(client);
}
}
/* Initialize random number generator */
client->rng = silc_rng_alloc();
silc_rng_init(client->rng);
- silc_math_primegen_init(); /* XXX */
+ silc_rng_global_init(client->rng);
/* Register protocols */
silc_client_protocols_register();
conn->nickname = strdup(client->username);
conn->sock->hostname = conn->remote_host;
+ conn->sock->ip = strdup(conn->remote_host);
conn->sock->port = conn->remote_port;
/* Allocate internal Key Exchange context. This is sent to the
SILC_LOG_DEBUG(("Start"));
- if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+ protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Error occured during protocol */
SILC_LOG_DEBUG(("Error during KE protocol"));
silc_protocol_free(protocol);
&proto_ctx->auth_data_len))
{
/* XXX do AUTH_REQUEST resolcing with server */
- proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE;
+ proto_ctx->auth_meth = SILC_AUTH_NONE;
}
/* Free old protocol as it is finished now */
SILC_LOG_DEBUG(("Start"));
- if (protocol->state == SILC_PROTOCOL_STATE_ERROR) {
+ if (protocol->state == SILC_PROTOCOL_STATE_ERROR ||
+ protocol->state == SILC_PROTOCOL_STATE_FAILURE) {
/* Error occured during protocol */
SILC_LOG_DEBUG(("Error during authentication protocol"));
silc_protocol_free(protocol);
conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER);
conn->remote_id_data_len = SILC_ID_SERVER_LEN;
- /* Notify application of successful connection */
- client->ops->connect(client, conn, TRUE);
-
silc_protocol_free(protocol);
if (ctx->auth_data)
silc_free(ctx->auth_data);
if (ctx->ske)
silc_ske_free(ctx->ske);
- if (ctx->dest_id)
- silc_free(ctx->dest_id);
silc_free(ctx);
conn->sock->protocol = NULL;
}
return;
}
- client->ops->say(client, conn, "Connection closed: premature EOF");
- SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
+ SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
client->ops->disconnect(client, conn);
silc_client_close_connection(client, sock);
return;
proto_ctx->packet = silc_packet_context_dup(packet);
proto_ctx->dest_id_type = packet->src_id_type;
- proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
+ proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ packet->src_id_type);
+ if (!proto_ctx->dest_id)
+ break;
/* Let the protocol handle the packet */
sock->protocol->execute(client->timeout_queue, 0,
proto_ctx->packet = silc_packet_context_dup(packet);
proto_ctx->dest_id_type = packet->src_id_type;
- proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_type);
+ proto_ctx->dest_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ packet->src_id_type);
+ if (!proto_ctx->dest_id)
+ break;
/* Let the protocol handle the packet */
sock->protocol->execute(client->timeout_queue, 0,
SilcIDPayload idp;
idp = silc_id_payload_parse(buffer);
+ if (!idp)
+ break;
if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
break;
break;
}
+ case SILC_PACKET_HEARTBEAT:
+ /*
+ * Received heartbeat packet
+ */
+ SILC_LOG_DEBUG(("Heartbeat packet"));
+ break;
+
default:
SILC_LOG_DEBUG(("Incorrect packet type %d, packet dropped", type));
break;
packetdata.dst_id_len = 0;
packetdata.dst_id_type = SILC_ID_NONE;
}
- packetdata.rng = client->rng;
packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
packetdata.src_id_len + packetdata.dst_id_len;
packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
packetdata.dst_id = id_string;
packetdata.dst_id_len = SILC_ID_CHANNEL_LEN;
packetdata.dst_id_type = SILC_ID_CHANNEL;
- packetdata.rng = client->rng;
packetdata.truelen = payload->len + SILC_PACKET_HEADER_LEN +
packetdata.src_id_len + packetdata.dst_id_len;
packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
packetdata.dst_id = conn->local_id_data;
packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
packetdata.dst_id_type = SILC_ID_CLIENT;
- packetdata.rng = client->rng;
packetdata.truelen = buffer->len + SILC_PACKET_HEADER_LEN +
packetdata.src_id_len + packetdata.dst_id_len;
packetdata.padlen = SILC_PACKET_PADLEN((SILC_PACKET_HEADER_LEN +
silc_net_close_connection(sock->sock);
client->ops->say(client, sock->user_data,
- "Closed connection to host %s", sock->hostname ?
- sock->hostname : sock->ip);
+ "Closed connection to host %s", sock->hostname);
/* Free everything */
if (sock->user_data) {
{
SilcPacketContext *p = (SilcPacketContext *)context;
silc_client_notify_by_server(p->context, p->sock, p);
- silc_packet_context_free(p);
+}
+
+/* Destructor for the pending command callback */
+
+static void silc_client_notify_by_server_destructor(void *context)
+{
+ silc_packet_context_free((SilcPacketContext *)context);
+}
+
+/* Resolve client information from server by Client ID. */
+
+static void silc_client_notify_by_server_resolve(SilcClient client,
+ SilcClientConnection conn,
+ SilcPacketContext *packet,
+ SilcClientID *client_id)
+{
+ SilcPacketContext *p = silc_packet_context_dup(packet);
+ SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+
+ p->context = (void *)client;
+ p->sock = conn->sock;
+
+ silc_client_send_command(client, conn, SILC_COMMAND_WHOIS, ++conn->cmd_ident,
+ 1, 3, idp->data, idp->len);
+ silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
+ silc_client_notify_by_server_destructor,
+ silc_client_notify_by_server_pending, p);
+ silc_buffer_free(idp);
}
/* Received notify message from server */
unsigned int tmp_len, mode;
payload = silc_notify_payload_parse(buffer);
+ if (!payload)
+ goto out;
+
type = silc_notify_get_type(payload);
args = silc_notify_get_args(payload);
if (!args)
goto out;
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Find Client entry and if not found query it */
- client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
+ client_entry = silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry) {
- SilcPacketContext *p = silc_packet_context_dup(packet);
- p->context = (void *)client;
- p->sock = sock;
- silc_client_command_pending(conn,SILC_COMMAND_WHOIS, 0,
- silc_client_notify_by_server_pending, p);
+ silc_client_notify_by_server_resolve(client, conn, packet, client_id);
goto out;
}
goto out;
channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id)
+ goto out;
/* XXX Will ALWAYS fail because currently we don't have way to resolve
channel information for channel that we're not joined to. */
goto out;
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Find Client entry and if not found query it */
- client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
+ client_entry = silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry) {
- SilcPacketContext *p = silc_packet_context_dup(packet);
- p->context = (void *)client;
- p->sock = sock;
- silc_client_command_pending(conn, SILC_COMMAND_WHOIS, 0,
- silc_client_notify_by_server_pending, p);
+ silc_client_notify_by_server_resolve(client, conn, packet, client_id);
goto out;
}
+ /* If nickname or username hasn't been resolved, do so */
+ if (!client_entry->nickname || !client_entry->username) {
+ silc_client_notify_by_server_resolve(client, conn, packet, client_id);
+ goto out;
+ }
+
+ /* Get Channel ID */
+ tmp = silc_argument_get_arg_type(args, 2, &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_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
SILC_ID_CHANNEL, &id_cache))
break;
goto out;
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Find Client entry */
client_entry =
- silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry)
goto out;
/* Get channel entry */
- channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ SILC_ID_CHANNEL);
+ if (!channel_id)
+ goto out;
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
SILC_ID_CHANNEL, &id_cache))
break;
goto out;
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Find Client entry */
client_entry =
- silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry)
goto out;
silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
client_entry->id);
+ /* Get signoff message */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (tmp_len > 128)
+ tmp = NULL;
+
/* Notify application */
- client->ops->notify(client, conn, type, client_entry);
+ client->ops->notify(client, conn, type, client_entry, tmp);
/* Free data */
if (client_entry->nickname)
goto out;
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Find Client entry */
client_entry =
- silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry)
goto out;
goto out;
/* Get channel entry */
- channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ SILC_ID_CHANNEL);
+ if (!channel_id)
+ goto out;
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
SILC_ID_CHANNEL, &id_cache))
break;
goto out;
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Ignore my ID */
if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
/* Find Client entry and if not found query it */
client_entry2 =
- silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
+ silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry2) {
- SilcPacketContext *p = silc_packet_context_dup(packet);
- p->context = (void *)client;
- p->sock = sock;
- silc_client_command_pending(conn, SILC_COMMAND_WHOIS, 0,
- silc_client_notify_by_server_pending, p);
+ silc_client_notify_by_server_resolve(client, conn, packet, client_id);
goto out;
}
+ silc_free(client_id);
/* Get old Client ID */
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
goto out;
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Find old Client entry */
client_entry =
- silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry)
goto out;
goto out;
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Find Client entry */
client_entry =
- silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry)
goto out;
SILC_GET32_MSB(mode, tmp);
/* Get channel entry */
- channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ SILC_ID_CHANNEL);
+ if (!channel_id)
+ goto out;
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
SILC_ID_CHANNEL, &id_cache))
break;
goto out;
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Find Client entry */
client_entry =
- silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry)
goto out;
silc_free(client_id);
client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
/* Find target Client entry */
client_entry2 =
- silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ silc_idlist_get_client_by_id(client, conn, client_id);
if (!client_entry2)
goto out;
/* Get channel entry */
- channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ SILC_ID_CHANNEL);
+ if (!channel_id)
+ goto out;
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
SILC_ID_CHANNEL, &id_cache))
break;
/* Notify application */
client->ops->notify(client, conn, type, tmp);
break;
+
+ case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
+ /*
+ * Router has enforced a new ID to a channel. Let's change the old
+ * ID to the one provided here.
+ */
+
+ /* Get the old 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 */
+ if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+ SILC_ID_CHANNEL, &id_cache))
+ break;
+
+ channel = (SilcChannelEntry)id_cache->context;
+
+ /* Free the old ID */
+ silc_free(channel_id);
+ silc_free(channel->id);
+
+ /* Get the new ID */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
+ channel->id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel->id)
+ goto out;
+
+ id_cache->id = (void *)channel->id;
+
+ /* Notify application */
+ client->ops->notify(client, conn, type, channel, channel);
+ break;
+
+ case SILC_NOTIFY_TYPE_KICKED:
+ /*
+ * A client (maybe me) was kicked from a channel
+ */
+
+ /* Get Client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!client_id)
+ goto out;
+
+ /* Find Client entry */
+ client_entry =
+ silc_idlist_get_client_by_id(client, conn, client_id);
+ if (!client_entry)
+ goto out;
+
+ /* Get channel entry */
+ channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
+ SILC_ID_CHANNEL);
+ if (!channel_id)
+ goto out;
+ if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+ SILC_ID_CHANNEL, &id_cache))
+ break;
+
+ channel = (SilcChannelEntry)id_cache->context;
+
+ /* Get comment */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+
+ /* Notify application. The channel entry is sent last as this notify
+ is for channel but application don't know it from the arguments
+ sent by server. */
+ client->ops->notify(client, conn, type, client_entry, tmp, channel);
+
+ /* If I was kicked from channel, remove the channel */
+ if (client_entry == conn->local_entry) {
+ if (conn->current_channel == channel)
+ conn->current_channel = NULL;
+ silc_idcache_del_by_id(conn->channel_cache,
+ SILC_ID_CHANNEL, channel->id);
+ silc_free(channel->channel_name);
+ silc_free(channel->id);
+ silc_free(channel->key);
+ silc_cipher_free(channel->channel_key);
+ silc_free(channel);
+ }
+ break;
default:
break;
SilcIDPayload idp)
{
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
+ int connecting = FALSE;
+
+ if (!conn->local_entry)
+ connecting = TRUE;
/* Delete old ID from ID cache */
silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id);
/* Put it to the ID cache */
silc_idcache_add(conn->client_cache, conn->nickname, SILC_ID_CLIENT,
conn->local_id, (void *)conn->local_entry, TRUE);
+
+ /* Notify application of successful connection. We do it here now that
+ we've received the Client ID and are allowed to send traffic. */
+ if (connecting)
+ client->ops->connect(client, conn, TRUE);
}
/* Processed received Channel ID for a channel. This is called when client
return;
}
- id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
+ id = silc_id_str2id(id_string, tmp_len, SILC_ID_CHANNEL);
+ if (!id) {
+ silc_channel_key_payload_free(payload);
+ return;
+ }
/* Find channel. */
if (!channel) {
SilcChannelUser chu;
SilcIDCacheEntry id_cache = NULL;
SilcClientID *client_id = NULL;
- char *nickname;
+ int found = FALSE;
/* Sanity checks */
if (packet->dst_id_type != SILC_ID_CHANNEL)
goto out;
- client_id = silc_id_str2id(packet->src_id, SILC_ID_CLIENT);
- id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+ client_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ SILC_ID_CLIENT);
+ if (!client_id)
+ goto out;
+ id = silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL);
+ if (!id)
+ goto out;
/* Find the channel entry from channels on this connection */
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
if (!payload)
goto out;
- /* Find nickname */
- nickname = "[unknown]";
+ /* Find client entry */
silc_list_start(channel->clients);
while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
if (!SILC_ID_CLIENT_COMPARE(chu->client->id, client_id)) {
- nickname = chu->client->nickname;
+ found = TRUE;
break;
}
}
/* Pass the message to application */
- client->ops->channel_message(client, conn, nickname,
- channel->channel_name,
- silc_channel_get_data(payload, NULL));
+ client->ops->channel_message(client, conn, found ? chu->client : NULL,
+ channel, silc_channel_get_data(payload, NULL));
out:
if (id)
{
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
SilcBuffer buffer = packet->buffer;
+ SilcIDCacheEntry id_cache;
+ SilcClientID *remote_id = NULL;
+ SilcClientEntry remote_client;
unsigned short nick_len;
- unsigned char *nickname, *message;
+ unsigned char *nickname, *message = NULL;
+ int ret;
+
+ if (packet->src_id_type != SILC_ID_CLIENT)
+ goto out;
/* Get nickname */
- silc_buffer_unformat(buffer,
- SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
- SILC_STR_END);
+ ret = silc_buffer_unformat(buffer,
+ SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
+ SILC_STR_END);
+ if (ret == -1)
+ return;
+
silc_buffer_pull(buffer, 2 + nick_len);
-
+
message = silc_calloc(buffer->len + 1, sizeof(char));
memcpy(message, buffer->data, buffer->len);
+ remote_id = silc_id_str2id(packet->src_id, packet->src_id_len,
+ SILC_ID_CLIENT);
+ if (!remote_id)
+ goto out;
+
+ /* Check whether we know this client already */
+ if (!silc_idcache_find_by_id_one(conn->client_cache, remote_id,
+ SILC_ID_CLIENT, &id_cache))
+ {
+ /* Allocate client entry */
+ remote_client = silc_calloc(1, sizeof(*remote_client));
+ remote_client->id = remote_id;
+ silc_parse_nickname(nickname, &remote_client->nickname,
+ &remote_client->server, &remote_client->num);
+
+ /* Save the client to cache */
+ silc_idcache_add(conn->client_cache, remote_client->nickname,
+ SILC_ID_CLIENT, remote_client->id, remote_client,
+ TRUE);
+ } else {
+ remote_client = (SilcClientEntry)id_cache->context;
+ }
+
/* Pass the private message to application */
- client->ops->private_message(client, conn, nickname, message);
+ client->ops->private_message(client, conn, remote_client, message);
/* See if we are away (gone). If we are away we will reply to the
sender with the set away message. */
if (conn->away && conn->away->away) {
- SilcClientID *remote_id;
- SilcClientEntry remote_client;
- SilcIDCacheEntry id_cache;
-
- if (packet->src_id_type != SILC_ID_CLIENT)
- goto out;
-
- remote_id = silc_id_str2id(packet->src_id, SILC_ID_CLIENT);
- if (!remote_id)
- goto out;
-
/* If it's me, ignore */
if (!SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id))
goto out;
- /* Check whether we know this client already */
- if (!silc_idcache_find_by_id_one(conn->client_cache, remote_id,
- SILC_ID_CLIENT, &id_cache))
- {
- /* Allocate client entry */
- remote_client = silc_calloc(1, sizeof(*remote_client));
- remote_client->id = remote_id;
- silc_parse_nickname(nickname, &remote_client->nickname,
- &remote_client->server, &remote_client->num);
-
- /* Save the client to cache */
- silc_idcache_add(conn->client_cache, remote_client->nickname,
- SILC_ID_CLIENT, remote_client->id, remote_client,
- TRUE);
- } else {
- silc_free(remote_id);
- remote_client = (SilcClientEntry)id_cache->context;
- }
-
/* Send the away message */
silc_client_packet_send_private_message(client, sock, remote_client,
conn->away->away,
}
out:
- memset(message, 0, buffer->len);
- silc_free(message);
+ if (remote_id)
+ silc_free(remote_id);
+
+ if (message) {
+ memset(message, 0, buffer->len);
+ silc_free(message);
+ }
silc_free(nickname);
}