X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=lib%2Fsilccore%2Fsilcchannel.c;h=5c83bbb422801ac4b472c19a18409a4ac8bde860;hp=c2226da4439c056d0deadd753eb8ed61ed1c2b3e;hb=382d15d447b7a95390decfa783836ae4fe255b3d;hpb=d56fa9060fe64259cf6a94a282d82e9eaaf1b32e diff --git a/lib/silccore/silcchannel.c b/lib/silccore/silcchannel.c index c2226da4..5c83bbb4 100644 --- a/lib/silccore/silcchannel.c +++ b/lib/silccore/silcchannel.c @@ -1,16 +1,15 @@ /* - silcchannel.c + silcchannel.c - Author: Pekka Riikonen + Author: Pekka Riikonen - Copyright (C) 1997 - 2000 Pekka Riikonen + Copyright (C) 1997 - 2002 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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - + the Free Software Foundation; version 2 of the License. + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the @@ -29,129 +28,203 @@ ******************************************************************************/ -/* Channel Payload structure. Contents of this structure is parsed +/* Channel Message Payload structure. Contents of this structure is parsed from SILC packets. */ struct SilcChannelPayloadStruct { - unsigned short data_len; - unsigned char *data; - unsigned short iv_len; - unsigned char *iv; + unsigned char *channel_name; + unsigned char *channel_id; + SilcUInt32 mode; + SilcUInt16 name_len; + SilcUInt16 id_len; }; -/* Parses channel payload returning new channel payload structure */ +/* Parses channel payload returning new channel payload structure. */ -SilcChannelPayload silc_channel_payload_parse(SilcBuffer buffer) +SilcChannelPayload silc_channel_payload_parse(const unsigned char *payload, + SilcUInt32 payload_len) { - SilcChannelPayload new; + SilcBufferStruct buffer; + SilcChannelPayload newp; + int ret; SILC_LOG_DEBUG(("Parsing channel payload")); - new = silc_calloc(1, sizeof(*new)); + silc_buffer_set(&buffer, (unsigned char *)payload, payload_len); + newp = silc_calloc(1, sizeof(*newp)); + if (!newp) + return NULL; - /* Parse the Channel Payload. Ignore padding and IV, we don't need - them. */ - silc_buffer_unformat(buffer, - SILC_STR_UI16_NSTRING_ALLOC(&new->data, &new->data_len), - SILC_STR_UI16_NSTRING_ALLOC(NULL, NULL), - SILC_STR_END); + /* Parse the Channel Payload. Ignore the padding. */ + ret = silc_buffer_unformat(&buffer, + SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_name, + &newp->name_len), + SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_id, + &newp->id_len), + SILC_STR_UI_INT(&newp->mode), + SILC_STR_END); + if (ret == -1) + goto err; - if (new->data_len < 1 || new->data_len > buffer->len) { + if ((newp->name_len < 1 || newp->name_len > buffer.len - 8) || + (newp->id_len < 1 || newp->id_len > buffer.len - 8) || + (newp->id_len + newp->name_len > buffer.len - 8)) { SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped")); goto err; } - return new; + return newp; err: - if (new->data) - silc_free(new->data); - if (new->iv) - silc_free(new->iv); - silc_free(new); + silc_channel_payload_free(newp); return NULL; } -/* Encodes channel payload into a buffer and returns it. This is used - to add channel payload into a packet. As the channel payload is - encrypted separately from other parts of the packet padding must - be applied to the payload. */ +/* Parses list of channel payloads returning list of payloads. */ -SilcBuffer silc_channel_payload_encode(unsigned short data_len, - unsigned char *data, - unsigned short iv_len, - unsigned char *iv, - SilcRng rng) +SilcDList silc_channel_payload_parse_list(const unsigned char *payload, + SilcUInt32 payload_len) { - int i; - SilcBuffer buffer; - unsigned int len, pad_len; - unsigned char pad[SILC_PACKET_MAX_PADLEN]; + SilcBufferStruct buffer; + SilcDList list; + SilcChannelPayload newp; + SilcUInt32 len; + int ret; + + SILC_LOG_DEBUG(("Parsing channel payload list")); + + silc_buffer_set(&buffer, (unsigned char *)payload, payload_len); + list = silc_dlist_init(); + + while (buffer.len) { + newp = silc_calloc(1, sizeof(*newp)); + if (!newp) + goto err; + ret = silc_buffer_unformat(&buffer, + SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_name, + &newp->name_len), + SILC_STR_UI16_NSTRING_ALLOC(&newp->channel_id, + &newp->id_len), + SILC_STR_UI_INT(&newp->mode), + SILC_STR_END); + if (ret == -1) + goto err; + + if ((newp->name_len < 1 || newp->name_len > buffer.len) || + (newp->id_len < 1 || newp->id_len > buffer.len)) { + SILC_LOG_ERROR(("Incorrect channel payload in packet, packet dropped")); + goto err; + } + + len = 2 + newp->name_len + 2 + newp->id_len + 4; + if (buffer.len < len) + break; + silc_buffer_pull(&buffer, len); + + silc_dlist_add(list, newp); + } + + return list; - SILC_LOG_DEBUG(("Encoding channel payload")); + err: + silc_channel_payload_list_free(list); + return NULL; +} - /* Calculate length of padding. IV is not included into the calculation - since it is not encrypted. */ - len = 2 + data_len + 2; - pad_len = SILC_PACKET_PADLEN((len + 2)); +/* Encode new channel payload and returns it as buffer. */ - /* Allocate channel payload buffer */ - len += pad_len; - buffer = silc_buffer_alloc(len + iv_len); +SilcBuffer silc_channel_payload_encode(const unsigned char *channel_name, + SilcUInt16 channel_name_len, + const unsigned char *channel_id, + SilcUInt32 channel_id_len, + SilcUInt32 mode) +{ + SilcBuffer buffer; - /* Generate padding */ - for (i = 0; i < pad_len; i++) - pad[i] = silc_rng_get_byte(rng); + SILC_LOG_DEBUG(("Encoding message payload")); - silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); + buffer = silc_buffer_alloc_size(2 + channel_name_len + 2 + + channel_id_len + 4); + if (!buffer) + return NULL; /* Encode the Channel Payload */ silc_buffer_format(buffer, - SILC_STR_UI_SHORT(data_len), - SILC_STR_UI_XNSTRING(data, data_len), - SILC_STR_UI_SHORT(pad_len), - SILC_STR_UI_XNSTRING(pad, pad_len), - SILC_STR_UI_XNSTRING(iv, iv_len), + SILC_STR_UI_SHORT(channel_name_len), + SILC_STR_UI_XNSTRING(channel_name, channel_name_len), + SILC_STR_UI_SHORT(channel_id_len), + SILC_STR_UI_XNSTRING(channel_id, channel_id_len), + SILC_STR_UI_INT(mode), SILC_STR_END); - memset(pad, 0, pad_len); return buffer; } -/* Free's Channel Payload */ +/* Frees Channel Payload */ void silc_channel_payload_free(SilcChannelPayload payload) { - if (payload) { - if (payload->data) - silc_free(payload->data); - if (payload->iv) - silc_free(payload->iv); - silc_free(payload); + silc_free(payload->channel_name); + silc_free(payload->channel_id); + silc_free(payload); +} + +/* Free's list of Channel Payloads */ + +void silc_channel_payload_list_free(SilcDList list) +{ + SilcChannelPayload entry; + + silc_dlist_start(list); + while ((entry = silc_dlist_get(list)) != SILC_LIST_END) { + silc_free(entry->channel_name); + silc_free(entry->channel_id); + silc_dlist_del(list, entry); + silc_free(entry); } + + silc_dlist_uninit(list); } -/* Return data */ +/* Return the channel name */ -unsigned char *silc_channel_get_data(SilcChannelPayload payload, - unsigned int *data_len) +unsigned char *silc_channel_get_name(SilcChannelPayload payload, + SilcUInt32 *channel_name_len) { - if (data_len) - *data_len = payload->data_len; + if (channel_name_len) + *channel_name_len = payload->name_len; - return payload->data; + return payload->channel_name; } -/* Return initial vector */ +/* Return the channel ID */ -unsigned char *silc_channel_get_iv(SilcChannelPayload payload, - unsigned int *iv_len) +unsigned char *silc_channel_get_id(SilcChannelPayload payload, + SilcUInt32 *channel_id_len) { - if (iv_len) - *iv_len = payload->iv_len; + if (channel_id_len) + *channel_id_len = payload->id_len; + + return payload->channel_id; +} - return payload->iv; +/* Return the channel ID as parsed ID. */ + +SilcChannelID *silc_channel_get_id_parse(SilcChannelPayload payload) +{ + return silc_id_str2id(payload->channel_id, payload->id_len, + SILC_ID_CHANNEL); } +/* Return the mode. The mode is arbitrary. It can be the mode of the + channel or perhaps the mode of the client on the channel. The protocol + dictates what the usage of the mode is in different circumstances. */ + +SilcUInt32 silc_channel_get_mode(SilcChannelPayload payload) +{ + return payload->mode; +} + + /****************************************************************************** Channel Key Payload @@ -161,75 +234,83 @@ unsigned char *silc_channel_get_iv(SilcChannelPayload payload, /* Channel Key Payload structrue. Channel keys are parsed from SILC packets into this structure. */ struct SilcChannelKeyPayloadStruct { - unsigned short id_len; unsigned char *id; - unsigned short cipher_len; unsigned char *cipher; - unsigned short key_len; unsigned char *key; + SilcUInt16 id_len; + SilcUInt16 cipher_len; + SilcUInt16 key_len; }; /* Parses channel key payload returning new channel key payload structure */ -SilcChannelKeyPayload silc_channel_key_payload_parse(SilcBuffer buffer) +SilcChannelKeyPayload +silc_channel_key_payload_parse(const unsigned char *payload, + SilcUInt32 payload_len) { - SilcChannelKeyPayload new; + SilcBufferStruct buffer; + SilcChannelKeyPayload newp; + int ret; SILC_LOG_DEBUG(("Parsing channel key payload")); - new = silc_calloc(1, sizeof(*new)); + silc_buffer_set(&buffer, (unsigned char *)payload, payload_len); + newp = silc_calloc(1, sizeof(*newp)); + if (!newp) + return NULL; /* Parse the Channel Key Payload */ - silc_buffer_unformat(buffer, - SILC_STR_UI16_NSTRING_ALLOC(&new->id, &new->id_len), - SILC_STR_UI16_NSTRING_ALLOC(&new->cipher, - &new->cipher_len), - SILC_STR_UI16_NSTRING_ALLOC(&new->key, &new->key_len), - SILC_STR_END); - - if (new->id_len < 1 || new->key_len < 1 || new->cipher_len < 1) { + ret = + silc_buffer_unformat(&buffer, + SILC_STR_UI16_NSTRING_ALLOC(&newp->id, &newp->id_len), + SILC_STR_UI16_NSTRING_ALLOC(&newp->cipher, + &newp->cipher_len), + SILC_STR_UI16_NSTRING_ALLOC(&newp->key, + &newp->key_len), + SILC_STR_END); + if (ret == -1) + goto err; + + if (newp->id_len < 1 || newp->key_len < 1 || newp->cipher_len < 1 || + newp->id_len + newp->cipher_len + newp->key_len > buffer.len - 6) { SILC_LOG_ERROR(("Incorrect channel key payload in packet")); goto err; } - return new; + return newp; err: - if (new->id) - silc_free(new->id); - if (new->cipher) - silc_free(new->cipher); - if (new->key) - silc_free(new->key); - silc_free(new); + if (newp->id) + silc_free(newp->id); + if (newp->cipher) + silc_free(newp->cipher); + if (newp->key) + silc_free(newp->key); + silc_free(newp); return NULL; } /* Encodes channel key payload into a buffer and returns it. This is used to add channel key payload into a packet. */ -SilcBuffer silc_channel_key_payload_encode(unsigned short id_len, - unsigned char *id, - unsigned short cipher_len, - unsigned char *cipher, - unsigned short key_len, - unsigned char *key) +SilcBuffer silc_channel_key_payload_encode(SilcUInt16 id_len, + const unsigned char *id, + SilcUInt16 cipher_len, + const unsigned char *cipher, + SilcUInt16 key_len, + const unsigned char *key) { SilcBuffer buffer; - unsigned int len; + SilcUInt32 len; SILC_LOG_DEBUG(("Encoding channel key payload")); - /* Sanity checks */ - if (!id_len || !key_len || !id || !key || !cipher_len || !cipher) - return NULL; - /* Allocate channel payload buffer. Length is 2 + id + 2 + key + 2 + cipher */ len = 2 + id_len + 2 + key_len + 2 + cipher_len; - buffer = silc_buffer_alloc(len); - - silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); + buffer = silc_buffer_alloc_size(len); + if (!buffer) + return NULL; /* Encode the Channel Payload */ silc_buffer_format(buffer, @@ -244,15 +325,13 @@ SilcBuffer silc_channel_key_payload_encode(unsigned short id_len, return buffer; } -/* Free's Channel Key Payload */ +/* Frees Channel Key Payload */ void silc_channel_key_payload_free(SilcChannelKeyPayload payload) { if (payload) { - if (payload->id) - silc_free(payload->id); - if (payload->cipher) - silc_free(payload->cipher); + silc_free(payload->id); + silc_free(payload->cipher); if (payload->key) { memset(payload->key, 0, payload->key_len); silc_free(payload->key); @@ -264,7 +343,7 @@ void silc_channel_key_payload_free(SilcChannelKeyPayload payload) /* Return ID */ unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, - unsigned int *id_len) + SilcUInt32 *id_len) { if (id_len) *id_len = payload->id_len; @@ -275,7 +354,7 @@ unsigned char *silc_channel_key_get_id(SilcChannelKeyPayload payload, /* Return cipher name */ unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload, - unsigned int *cipher_len) + SilcUInt32 *cipher_len) { if (cipher_len) *cipher_len = payload->cipher_len; @@ -286,7 +365,7 @@ unsigned char *silc_channel_key_get_cipher(SilcChannelKeyPayload payload, /* Return key */ unsigned char *silc_channel_key_get_key(SilcChannelKeyPayload payload, - unsigned int *key_len) + SilcUInt32 *key_len) { if (key_len) *key_len = payload->key_len;