X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilccore%2Fsilcargument.c;h=eac8bdf60e72d5dfef128924ba389df5fbee842f;hb=52e57c880aba9c5e89f59d962eb9af75670b76e0;hp=471e92c78fe18130da9bbbd89caac6ad4d7e8394;hpb=4e64dd02ccecc9c497b8db8ecb09d017b9cef9a4;p=silc.git diff --git a/lib/silccore/silcargument.c b/lib/silccore/silcargument.c index 471e92c7..eac8bdf6 100644 --- a/lib/silccore/silcargument.c +++ b/lib/silccore/silcargument.c @@ -1,10 +1,10 @@ /* - silcargument.c + silcargument.c Author: Pekka Riikonen - Copyright (C) 2001 Pekka Riikonen + Copyright (C) 2001 - 2007 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 @@ -16,48 +16,50 @@ GNU General Public License for more details. */ -/* Implementation of Argument Payload routines */ +/* Implementation of Argument Payload routines */ /* $Id$ */ -#include "silcincludes.h" +#include "silc.h" #include "silcargument.h" -/****************************************************************************** - - Argument Payload - -******************************************************************************/ +/*************************** Argument Payload *******************************/ struct SilcArgumentPayloadStruct { - uint32 argc; + SilcUInt32 argc; unsigned char **argv; - uint32 *argv_lens; - uint32 *argv_types; - uint32 pos; + SilcUInt32 *argv_lens; + SilcUInt32 *argv_types; + SilcUInt32 pos; }; /* Parses arguments and returns them into Argument Payload structure. */ SilcArgumentPayload silc_argument_payload_parse(const unsigned char *payload, - uint32 payload_len, - uint32 argc) + SilcUInt32 payload_len, + SilcUInt32 argc) { SilcBufferStruct buffer; - SilcArgumentPayload new; - uint16 p_len = 0; + SilcArgumentPayload newp; + SilcUInt16 p_len = 0; unsigned char arg_num = 0; unsigned char arg_type = 0; - uint32 pull_len = 0; + SilcUInt32 pull_len = 0; int i = 0, ret; - SILC_LOG_DEBUG(("Parsing argument payload")); - silc_buffer_set(&buffer, (unsigned char *)payload, payload_len); - new = silc_calloc(1, sizeof(*new)); - new->argv = silc_calloc(argc, sizeof(unsigned char *)); - new->argv_lens = silc_calloc(argc, sizeof(uint32)); - new->argv_types = silc_calloc(argc, sizeof(uint32)); - + newp = silc_calloc(1, sizeof(*newp)); + if (!newp) + return NULL; + newp->argv = silc_calloc(argc, sizeof(unsigned char *)); + if (!newp->argv) + goto err; + newp->argv_lens = silc_calloc(argc, sizeof(SilcUInt32)); + if (!newp->argv_lens) + goto err; + newp->argv_types = silc_calloc(argc, sizeof(SilcUInt32)); + if (!newp->argv_types) + goto err; + /* Get arguments */ arg_num = 1; for (i = 0; i < argc; i++) { @@ -65,84 +67,82 @@ SilcArgumentPayload silc_argument_payload_parse(const unsigned char *payload, SILC_STR_UI_SHORT(&p_len), SILC_STR_UI_CHAR(&arg_type), SILC_STR_END); - if (ret == -1) + if (ret == -1 || p_len > silc_buffer_len(&buffer) - 3) { + SILC_LOG_DEBUG(("Malformed argument payload")); goto err; - - new->argv_lens[i] = p_len; - new->argv_types[i] = arg_type; + } + + newp->argv_lens[i] = p_len; + newp->argv_types[i] = arg_type; - if (p_len > buffer.len - 3) - break; - /* Get argument data */ silc_buffer_pull(&buffer, 3); ret = silc_buffer_unformat(&buffer, - SILC_STR_UI_XNSTRING_ALLOC(&new->argv[i], + SILC_STR_UI_XNSTRING_ALLOC(&newp->argv[i], p_len), SILC_STR_END); - if (ret == -1) + if (ret == -1) { + SILC_LOG_DEBUG(("Malformed argument payload")); goto err; + } silc_buffer_pull(&buffer, p_len); pull_len += 3 + p_len; } - if (buffer.len != 0) + if (silc_buffer_len(&buffer) != 0) { + SILC_LOG_DEBUG(("Malformed argument payload")); goto err; + } - new->argc = argc; - new->pos = 0; + newp->argc = argc; + newp->pos = 0; silc_buffer_push(&buffer, pull_len); - return new; + return newp; err: - if (i) { - int k; - - for (k = 0; k < i; k++) - silc_free(new->argv[k]); - } + SILC_LOG_DEBUG(("Error parsing argument payload")); + if (i) + for (ret = 0; ret < i; ret++) + silc_free(newp->argv[ret]); - silc_free(new->argv); - silc_free(new->argv_lens); - silc_free(new->argv_types); - - if (new) - silc_free(new); + silc_free(newp->argv); + silc_free(newp->argv_lens); + silc_free(newp->argv_types); + silc_free(newp); return NULL; } /* Encodes arguments in to Argument Paylods returning them to SilcBuffer. */ -SilcBuffer silc_argument_payload_encode(uint32 argc, +SilcBuffer silc_argument_payload_encode(SilcUInt32 argc, unsigned char **argv, - uint32 *argv_lens, - uint32 *argv_types) + SilcUInt32 *argv_lens, + SilcUInt32 *argv_types) { SilcBuffer buffer; - uint32 len; + SilcUInt32 len; int i; - SILC_LOG_DEBUG(("Encoding Argument payload")); - len = 0; for (i = 0; i < argc; i++) - len += 3 + argv_lens[i]; + len += 3 + (SilcUInt16)argv_lens[i]; - buffer = silc_buffer_alloc(len); - silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); + buffer = silc_buffer_alloc_size(len); + if (!buffer) + return NULL; /* Put arguments */ for (i = 0; i < argc; i++) { silc_buffer_format(buffer, SILC_STR_UI_SHORT(argv_lens[i]), SILC_STR_UI_CHAR(argv_types[i]), - SILC_STR_UI_XNSTRING(argv[i], argv_lens[i]), + SILC_STR_UI_XNSTRING(argv[i], (SilcUInt16)argv_lens[i]), SILC_STR_END); - silc_buffer_pull(buffer, 3 + argv_lens[i]); + silc_buffer_pull(buffer, 3 + (SilcUInt16)argv_lens[i]); } silc_buffer_push(buffer, len); @@ -150,30 +150,57 @@ SilcBuffer silc_argument_payload_encode(uint32 argc, return buffer; } +/* Encode one argument to buffer */ + +SilcBuffer silc_argument_payload_encode_one(SilcBuffer args, + unsigned char *arg, + SilcUInt32 arg_len, + SilcUInt32 arg_type) +{ + SilcBuffer buffer = args; + SilcUInt32 len; + + len = 3 + (SilcUInt16)arg_len; + buffer = silc_buffer_realloc(buffer, + (buffer ? silc_buffer_truelen(buffer) + + len : len)); + if (!buffer) + return NULL; + silc_buffer_pull(buffer, silc_buffer_len(buffer)); + silc_buffer_pull_tail(buffer, len); + silc_buffer_format(buffer, + SILC_STR_UI_SHORT(arg_len), + SILC_STR_UI_CHAR(arg_type), + SILC_STR_UI_XNSTRING(arg, (SilcUInt16)arg_len), + SILC_STR_END); + silc_buffer_push(buffer, buffer->data - buffer->head); + + return buffer; +} + /* Same as above but encode the buffer from SilcArgumentPayload structure instead of raw data. */ SilcBuffer silc_argument_payload_encode_payload(SilcArgumentPayload payload) { SilcBuffer buffer; - uint32 len; + SilcUInt32 len; int i; - SILC_LOG_DEBUG(("Encoding Argument payload")); - len = 0; for (i = 0; i < payload->argc; i++) len += 3 + payload->argv_lens[i]; - buffer = silc_buffer_alloc(len); - silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); + buffer = silc_buffer_alloc_size(len); + if (!buffer) + return NULL; /* Put arguments */ for (i = 0; i < payload->argc; i++) { silc_buffer_format(buffer, SILC_STR_UI_SHORT(payload->argv_lens[i]), SILC_STR_UI_CHAR(payload->argv_types[i]), - SILC_STR_UI_XNSTRING(payload->argv[i], + SILC_STR_UI_XNSTRING(payload->argv[i], payload->argv_lens[i]), SILC_STR_END); silc_buffer_pull(buffer, 3 + payload->argv_lens[i]); @@ -203,7 +230,7 @@ void silc_argument_payload_free(SilcArgumentPayload payload) /* Returns number of arguments in payload */ -uint32 silc_argument_get_arg_num(SilcArgumentPayload payload) +SilcUInt32 silc_argument_get_arg_num(SilcArgumentPayload payload) { return payload ? payload->argc : 0; } @@ -211,13 +238,16 @@ uint32 silc_argument_get_arg_num(SilcArgumentPayload payload) /* Returns first argument from payload. */ unsigned char *silc_argument_get_first_arg(SilcArgumentPayload payload, - uint32 *ret_len) + SilcUInt32 *type, + SilcUInt32 *ret_len) { if (!payload) return NULL; payload->pos = 0; + if (type) + *type = payload->argv_types[payload->pos]; if (ret_len) *ret_len = payload->argv_lens[payload->pos]; @@ -227,7 +257,8 @@ unsigned char *silc_argument_get_first_arg(SilcArgumentPayload payload, /* Returns next argument from payload or NULL if no more arguments. */ unsigned char *silc_argument_get_next_arg(SilcArgumentPayload payload, - uint32 *ret_len) + SilcUInt32 *type, + SilcUInt32 *ret_len) { if (!payload) return NULL; @@ -235,6 +266,8 @@ unsigned char *silc_argument_get_next_arg(SilcArgumentPayload payload, if (payload->pos >= payload->argc) return NULL; + if (type) + *type = payload->argv_types[payload->pos]; if (ret_len) *ret_len = payload->argv_lens[payload->pos]; @@ -244,8 +277,8 @@ unsigned char *silc_argument_get_next_arg(SilcArgumentPayload payload, /* Returns argument which type is `type'. */ unsigned char *silc_argument_get_arg_type(SilcArgumentPayload payload, - uint32 type, - uint32 *ret_len) + SilcUInt32 type, + SilcUInt32 *ret_len) { int i; @@ -264,3 +297,205 @@ unsigned char *silc_argument_get_arg_type(SilcArgumentPayload payload, return payload->argv[i]; } + +/* Return argument already decoded */ + +static SilcBool silc_argument_decode(unsigned char *data, + SilcUInt32 data_len, + SilcArgumentDecodeType dec_type, + void *ret_arg, + void **ret_arg_alloc) +{ + switch (dec_type) { + + case SILC_ARGUMENT_ID: + if (ret_arg) + if (!silc_id_payload_parse_id(data, data_len, (SilcID *)ret_arg)) + return FALSE; + + if (ret_arg_alloc) { + SilcID id; + if (!silc_id_payload_parse_id(data, data_len, &id)) + return FALSE; + *ret_arg_alloc = silc_memdup(&id, sizeof(id)); + } + break; + + case SILC_ARGUMENT_PUBLIC_KEY: + { + SilcPublicKey public_key; + + if (!ret_arg_alloc) + return FALSE; + + if (!silc_public_key_payload_decode(data, data_len, &public_key)) + return FALSE; + + *ret_arg_alloc = public_key; + } + break; + + case SILC_ARGUMENT_ATTRIBUTES: + if (!ret_arg_alloc) + return FALSE; + + *ret_arg_alloc = silc_attribute_payload_parse(data, data_len); + break; + + case SILC_ARGUMENT_UINT32: + if (data_len != 4) + return FALSE; + + if (ret_arg) { + SilcUInt32 *i = ret_arg; + SILC_GET32_MSB(*i, data); + } + + if (ret_arg_alloc) { + SilcUInt32 i; + SILC_GET32_MSB(i, data); + *ret_arg_alloc = silc_memdup(&i, sizeof(i)); + } + break; + + case SILC_ARGUMENT_BOOL: + if (data_len != sizeof(SilcBool)) + return FALSE; + + if (ret_arg) { + SilcBool *b = ret_arg; + *b = (data[0] == 0x01 ? TRUE : FALSE); + } + + if (ret_arg_alloc) { + SilcBool b; + b = (data[0] == 0x01 ? TRUE : FALSE); + *ret_arg_alloc = silc_memdup(&b, sizeof(b)); + } + break; + + default: + return FALSE; + } + + return TRUE; +} + +/* Return argument already decoded */ + +SilcBool silc_argument_get_decoded(SilcArgumentPayload payload, + SilcUInt32 type, + SilcArgumentDecodeType dec_type, + void *ret_arg, + void **ret_arg_alloc) +{ + unsigned char *tmp; + SilcUInt32 tmp_len; + + tmp = silc_argument_get_arg_type(payload, type, &tmp_len); + if (!tmp) + return FALSE; + + return silc_argument_decode(tmp, tmp_len, dec_type, ret_arg, ret_arg_alloc); +} + +/************************* Argument List Payload ****************************/ + +/* Parses argument payload list */ + +SilcArgumentPayload +silc_argument_list_parse(const unsigned char *payload, + SilcUInt32 payload_len) +{ + SilcArgumentPayload arg; + SilcUInt16 argc; + + if (payload_len < 5) + return NULL; + + SILC_GET16_MSB(argc, payload); + + arg = silc_argument_payload_parse(payload + 2, payload_len - 2, argc); + + return arg; +} + +/* Parses argument payload list of specific argument types */ + +SilcDList +silc_argument_list_parse_decoded(const unsigned char *payload, + SilcUInt32 payload_len, + SilcArgumentDecodeType dec_type) +{ + SilcArgumentPayload arg; + SilcArgumentDecodedList dec; + unsigned char *data; + SilcUInt32 data_len, type; + SilcDList list; + + arg = silc_argument_list_parse(payload, payload_len); + if (!arg) + return NULL; + + list = silc_dlist_init(); + if (!list) { + silc_argument_payload_free(arg); + return NULL; + } + + data = silc_argument_get_first_arg(arg, &type, &data_len); + while (data) { + dec = silc_calloc(1, sizeof(*dec)); + if (!dec) + continue; + dec->arg_type = type; + if (silc_argument_decode(data, data_len, dec_type, NULL, &dec->argument)) + silc_dlist_add(list, dec); + else + silc_free(dec); + data = silc_argument_get_next_arg(arg, &type, &data_len); + } + + silc_argument_payload_free(arg); + + silc_dlist_start(list); + + return list; +} + +/* Free decoded argument payload list */ + +void silc_argument_list_free(SilcDList list, SilcArgumentDecodeType dec_type) +{ + SilcArgumentDecodedList dec; + + if (!list) + return; + + silc_dlist_start(list); + while ((dec = silc_dlist_get(list))) { + switch (dec_type) { + + case SILC_ARGUMENT_ID: + case SILC_ARGUMENT_UINT32: + case SILC_ARGUMENT_BOOL: + silc_free(dec->argument); + break; + + case SILC_ARGUMENT_PUBLIC_KEY: + silc_pkcs_public_key_free(dec->argument); + break; + + case SILC_ARGUMENT_ATTRIBUTES: + silc_attribute_payload_free(dec->argument); + break; + + default: + break; + } + + silc_free(dec); + } + + silc_dlist_uninit(list); +}