/*
- silcargument.c
+ silcargument.c
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 2001 - 2002 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
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 {
SilcUInt32 argc;
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++) {
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;
-
+ }
+
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(&newp->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;
}
len = 0;
for (i = 0; i < argc; i++)
- len += 3 + argv_lens[i];
+ len += 3 + (SilcUInt16)argv_lens[i];
buffer = silc_buffer_alloc_size(len);
if (!buffer)
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);
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. */
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]);
/* Returns first argument from payload. */
unsigned char *silc_argument_get_first_arg(SilcArgumentPayload payload,
+ SilcUInt32 *type,
SilcUInt32 *ret_len)
{
if (!payload)
payload->pos = 0;
+ if (type)
+ *type = payload->argv_types[payload->pos];
if (ret_len)
*ret_len = payload->argv_lens[payload->pos];
/* Returns next argument from payload or NULL if no more arguments. */
unsigned char *silc_argument_get_next_arg(SilcArgumentPayload payload,
+ SilcUInt32 *type,
SilcUInt32 *ret_len)
{
if (!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];
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);
+}