+++ /dev/null
-/*
-
- silcattrs.c
-
- Author: Pekka Riikonen <priikone@silcnet.org>
-
- Copyright (C) 2002 - 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
- 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
- GNU General Public License for more details.
-
-*/
-/* Implementation of Attribute Payload routines */
-/* $Id$ */
-
-#include "silc.h"
-#include "silcattrs.h"
-
-/******************************************************************************
-
- Attribute Payload
-
-******************************************************************************/
-
-struct SilcAttributePayloadStruct {
- SilcAttribute attribute;
- SilcAttributeFlags flags;
- SilcUInt16 data_len;
- unsigned char *data;
-};
-
-/* Internal routine for encoding a attribute */
-
-static unsigned char *
-silc_attribute_payload_encode_int(SilcAttribute attribute,
- SilcAttributeFlags flags,
- void *object,
- SilcUInt32 object_size,
- SilcUInt32 *ret_len)
-{
- SilcBuffer tmpbuf = NULL;
- unsigned char tmp[4], *str = NULL, *ret;
- SilcUInt32 len;
-
- /* Encode according to attribute type */
- if (flags & SILC_ATTRIBUTE_FLAG_VALID) {
- if (!object && !object_size)
- return NULL;
-
- switch (attribute) {
-
- case SILC_ATTRIBUTE_USER_INFO:
- {
-#ifdef SILC_DIST_VCARD
- SilcVCard vcard = object;
- if (object_size != sizeof(*vcard))
- return NULL;
- str = silc_vcard_encode(vcard, &object_size);
- if (!str)
- return NULL;
- object = str;
-#endif /* SILC_DIST_VCARD */
- }
- break;
-
- case SILC_ATTRIBUTE_SERVICE:
- {
- SilcAttributeObjService *service = object;
- SilcUInt32 len2;
- if (object_size != sizeof(*service))
- return NULL;
- len = strlen(service->address);
- len2 = strlen(service->signon);
- tmpbuf = silc_buffer_alloc_size(13 + len + len2);
- if (!tmpbuf)
- return NULL;
- silc_buffer_format(tmpbuf,
- SILC_STR_UI_INT(service->port),
- SILC_STR_UI_SHORT(len),
- SILC_STR_UI_XNSTRING(service->address, len),
- SILC_STR_UI_CHAR(service->status),
- SILC_STR_UI_SHORT(len2),
- SILC_STR_UI_XNSTRING(service->signon, len2),
- SILC_STR_UI_INT(service->idle),
- SILC_STR_END);
- object = tmpbuf->data;
- object_size = silc_buffer_len(tmpbuf);
- }
- break;
-
- case SILC_ATTRIBUTE_STATUS_MOOD:
- case SILC_ATTRIBUTE_PREFERRED_CONTACT:
- {
- SilcUInt32 mask = SILC_PTR_TO_32(object);
- if (object_size != sizeof(SilcUInt32))
- return NULL;
- SILC_PUT32_MSB(mask, tmp);
- object = tmp;
- object_size = sizeof(SilcUInt32);
- }
- break;
-
- case SILC_ATTRIBUTE_STATUS_FREETEXT:
- case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
- case SILC_ATTRIBUTE_TIMEZONE:
- {
- unsigned char *string = object;
- str = silc_malloc(2 + object_size);
- if (!str)
- return NULL;
- SILC_PUT16_MSB(object_size, str);
- memcpy(str + 2, string, object_size);
- object = str;
- object_size += 2;
- }
- break;
-
- case SILC_ATTRIBUTE_STATUS_MESSAGE:
- case SILC_ATTRIBUTE_EXTENSION:
- case SILC_ATTRIBUTE_USER_ICON:
- {
- SilcMime mime = object;
- if (object_size != sizeof(*mime))
- return NULL;
- str = silc_mime_encode(mime, &object_size);
- if (!str)
- return NULL;
- object = str;
- }
- break;
-
- case SILC_ATTRIBUTE_GEOLOCATION:
- {
- SilcAttributeObjGeo *geo = object;
- SilcUInt32 len1, len2, len3, len4;
- if (object_size != sizeof(*geo))
- return NULL;
- len1 = (geo->longitude ? strlen(geo->longitude) : 0);
- len2 = (geo->latitude ? strlen(geo->latitude) : 0);
- len3 = (geo->altitude ? strlen(geo->altitude) : 0);
- len4 = (geo->accuracy ? strlen(geo->accuracy) : 0);
- if (len1 + len2 + len3 + len4 == 0)
- return NULL;
- len = len1 + len2 + len3 + len4;
- tmpbuf = silc_buffer_alloc_size(8 + len);
- if (!tmpbuf)
- return NULL;
- silc_buffer_format(tmpbuf,
- SILC_STR_UI_SHORT(len1),
- SILC_STR_UI16_STRING(len1 ? geo->longitude : ""),
- SILC_STR_UI_SHORT(len2),
- SILC_STR_UI16_STRING(len2 ? geo->latitude : ""),
- SILC_STR_UI_SHORT(len3),
- SILC_STR_UI16_STRING(len3 ? geo->altitude : ""),
- SILC_STR_UI_SHORT(len4),
- SILC_STR_UI16_STRING(len4 ? geo->accuracy : ""),
- SILC_STR_END);
- object = tmpbuf->data;
- object_size = silc_buffer_len(tmpbuf);
- }
- break;
-
- case SILC_ATTRIBUTE_DEVICE_INFO:
- {
- SilcAttributeObjDevice *dev = object;
- SilcUInt32 len1, len2, len3, len4;
- if (object_size != sizeof(*dev))
- return NULL;
- len1 = (dev->manufacturer ? strlen(dev->manufacturer) : 0);
- len2 = (dev->version ? strlen(dev->version) : 0);
- len3 = (dev->model ? strlen(dev->model) : 0);
- len4 = (dev->language ? strlen(dev->language) : 0);
- if (len1 + len2 + len3 + len4 == 0)
- return NULL;
- len = len1 + len2 + len3 + len4;
- tmpbuf = silc_buffer_alloc_size(4 + 8 + len);
- if (!tmpbuf)
- return NULL;
- silc_buffer_format(tmpbuf,
- SILC_STR_UI_INT(dev->type),
- SILC_STR_UI_SHORT(len1),
- SILC_STR_UI16_STRING(len1 ? dev->manufacturer : ""),
- SILC_STR_UI_SHORT(len2),
- SILC_STR_UI16_STRING(len2 ? dev->version : ""),
- SILC_STR_UI_SHORT(len3),
- SILC_STR_UI16_STRING(len3 ? dev->model : ""),
- SILC_STR_UI_SHORT(len4),
- SILC_STR_UI16_STRING(len4 ? dev->language : ""),
- SILC_STR_END);
- object = tmpbuf->data;
- object_size = silc_buffer_len(tmpbuf);
- }
- break;
-
- case SILC_ATTRIBUTE_PHONE_NUMBER:
- {
- SilcAttributeObjPN *pn = object;
- if (object_size != sizeof(*pn))
- return NULL;
- if (!pn->number || strlen(pn->number) < 5)
- return NULL;
- tmpbuf = silc_buffer_alloc(0);
- if (!tmpbuf)
- return NULL;
- if (silc_buffer_format(tmpbuf,
- SILC_STR_UI_INT(pn->format),
- SILC_STR_UI_SHORT(strlen(pn->number)),
- SILC_STR_UI16_STRING(pn->number),
- SILC_STR_END) < 0)
- return NULL;
- object = tmpbuf->data;
- object_size = silc_buffer_len(tmpbuf);
- }
- break;
-
- case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
- case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
- {
- SilcAttributeObjPk *pk = object;
- if (object_size != sizeof(*pk))
- return NULL;
- len = (pk->type ? strlen(pk->type) : 0);
- tmpbuf = silc_buffer_alloc_size(2 + len + pk->data_len);
- if (!tmpbuf)
- return NULL;
- silc_buffer_format(tmpbuf,
- SILC_STR_UI_SHORT(len),
- SILC_STR_UI16_STRING(pk->type),
- SILC_STR_UI_XNSTRING(pk->data, pk->data_len),
- SILC_STR_END);
- object = tmpbuf->data;
- object_size = silc_buffer_len(tmpbuf);
- }
- break;
-
- case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
- case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
- {
- SilcAttributeObjPk *pk = object;
- if (object_size != sizeof(*pk))
- return NULL;
- object = pk->data;
- object_size = pk->data_len;
- }
- break;
-
- default:
- return NULL;
- break;
- }
-
- ret = silc_memdup(object, object_size);
-
- if (tmpbuf)
- silc_buffer_free(tmpbuf);
- silc_free(str);
-
- if (ret_len)
- *ret_len = object_size;
-
- return ret;
- }
-
- return NULL;
-}
-
-/* Allocates attribute payload and encodes the attribute there */
-
-SilcAttributePayload silc_attribute_payload_alloc(SilcAttribute attribute,
- SilcAttributeFlags flags,
- void *object,
- SilcUInt32 object_size)
-{
- SilcAttributePayload attr;
- SilcUInt32 tmp_len;
-
- attr = silc_calloc(1, sizeof(*attr));
- if (!attr)
- return NULL;
-
- attr->attribute = attribute;
- attr->flags = flags;
- attr->data =
- silc_attribute_payload_encode_int(attribute, flags, object,
- object_size, &tmp_len);
- attr->data_len = (SilcUInt16)tmp_len;
- if (!attr->data) {
- silc_free(attr);
- return NULL;
- }
-
- return attr;
-}
-
-/* Parse list of payloads */
-
-SilcDList silc_attribute_payload_parse(const unsigned char *payload,
- SilcUInt32 payload_len)
-{
- SilcBufferStruct buffer;
- SilcDList list;
- SilcAttributePayload newp;
- SilcUInt32 len;
- int ret;
-
- SILC_LOG_DEBUG(("Parsing Attribute Payload list"));
-
- silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
- list = silc_dlist_init();
-
- while (silc_buffer_len(&buffer)) {
- newp = silc_calloc(1, sizeof(*newp));
- if (!newp)
- goto err;
- ret = silc_buffer_unformat(&buffer,
- SILC_STR_UI_CHAR(&newp->attribute),
- SILC_STR_UI_CHAR(&newp->flags),
- SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
- &newp->data_len),
- SILC_STR_END);
- if (ret == -1)
- goto err;
-
- if (newp->data_len > silc_buffer_len(&buffer) - 4) {
- SILC_LOG_ERROR(("Incorrect attribute payload in list"));
- goto err;
- }
-
- len = 4 + newp->data_len;
- if (silc_buffer_len(&buffer) < len)
- break;
- silc_buffer_pull(&buffer, len);
-
- silc_dlist_add(list, newp);
- }
-
- return list;
-
- err:
- silc_attribute_payload_list_free(list);
- return NULL;
-}
-
-/* Encode one attribute payload to buffer */
-
-SilcBuffer silc_attribute_payload_encode(SilcBuffer attrs,
- SilcAttribute attribute,
- SilcAttributeFlags flags,
- void *object,
- SilcUInt32 object_size)
-{
- object = silc_attribute_payload_encode_int(attribute, flags, object,
- object_size, &object_size);
- attrs = silc_attribute_payload_encode_data(attrs, attribute, flags,
- (const unsigned char *)object,
- object_size);
- silc_free(object);
- return attrs;
-}
-
-/* Encoded the attribute data directly to buffer */
-
-SilcBuffer silc_attribute_payload_encode_data(SilcBuffer attrs,
- SilcAttribute attribute,
- SilcAttributeFlags flags,
- const unsigned char *data,
- SilcUInt32 data_len)
-{
- SilcBuffer buffer = attrs;
- SilcUInt32 len;
-
- len = 4 + (SilcUInt16)data_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_CHAR(attribute),
- SILC_STR_UI_CHAR(flags),
- SILC_STR_UI_SHORT((SilcUInt16)data_len),
- SILC_STR_UI_XNSTRING(data, (SilcUInt16)data_len),
- SILC_STR_END);
- silc_buffer_push(buffer, buffer->data - buffer->head);
-
- return buffer;
-}
-
-/* Free Attribute Payload */
-
-void silc_attribute_payload_free(SilcAttributePayload payload)
-{
- silc_free(payload->data);
- silc_free(payload);
-}
-
-/* Free's list of Attribute Payloads */
-
-void silc_attribute_payload_list_free(SilcDList list)
-{
- SilcAttributePayload entry;
-
- silc_dlist_start(list);
- while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
- silc_attribute_payload_free(entry);
- silc_dlist_del(list, entry);
- }
-
- silc_dlist_uninit(list);
-}
-
-/* Return attribute type */
-
-SilcAttribute silc_attribute_get_attribute(SilcAttributePayload payload)
-{
- return payload->attribute;
-}
-
-/* Return attribute flags */
-
-SilcAttributeFlags silc_attribute_get_flags(SilcAttributePayload payload)
-{
- return payload->flags;
-}
-
-/* Return attribute data from the payload */
-
-const unsigned char *silc_attribute_get_data(SilcAttributePayload payload,
- SilcUInt32 *data_len)
-{
- if (data_len)
- *data_len = (SilcUInt32)payload->data_len;
- return (const unsigned char *)payload->data;
-}
-
-/* Construct digital signature verification data */
-
-unsigned char *silc_attribute_get_verify_data(SilcDList attrs,
- SilcBool server_verification,
- SilcUInt32 *data_len)
-{
- SilcAttributePayload attr;
- SilcBufferStruct buffer;
- unsigned char *data = NULL;
- SilcUInt32 len = 0;
-
- silc_dlist_start(attrs);
- while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
- switch (attr->attribute) {
- case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
- /* Server signature is never part of the verification data */
- break;
-
- case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
- /* For user signature verification this is not part of the data */
- if (!server_verification)
- break;
-
- /* Fallback, for server signature verification, user digital signature
- is part of verification data. */
-
- default:
- /* All other data is part of the verification data */
- data = silc_realloc(data, sizeof(*data) * (4 + attr->data_len + len));
- if (!data)
- return NULL;
- silc_buffer_set(&buffer, data + len, 4 + attr->data_len);
- silc_buffer_format(&buffer,
- SILC_STR_UI_CHAR(attr->attribute),
- SILC_STR_UI_CHAR(attr->flags),
- SILC_STR_UI_SHORT(attr->data_len),
- SILC_STR_UI_XNSTRING(attr->data, attr->data_len),
- SILC_STR_END);
- len += 4 + attr->data_len;
- break;
- }
- }
-
- if (data_len)
- *data_len = len;
-
- return data;
-}
-
-/* Return parsed attribute object */
-
-SilcBool silc_attribute_get_object(SilcAttributePayload payload,
- void *object, SilcUInt32 object_size)
-{
- SilcUInt16 len;
- SilcBool ret = FALSE;
-
- if (!object || payload->flags & SILC_ATTRIBUTE_FLAG_INVALID)
- return FALSE;
-
- switch (payload->attribute) {
- case SILC_ATTRIBUTE_USER_INFO:
- {
-#ifdef SILC_DIST_VCARD
- SilcVCard vcard = object;
- if (object_size != sizeof(*vcard))
- break;
- if (!silc_vcard_decode(payload->data, payload->data_len, vcard))
- break;
- ret = TRUE;
-#endif /* SILC_DIST_VCARD */
- }
- break;
-
- case SILC_ATTRIBUTE_SERVICE:
- {
- SilcAttributeObjService *service = object;
- SilcBufferStruct buf;
- SilcUInt16 addr_len, signon_len;
- char *addr, *signon;
- int res;
- if (object_size != sizeof(*service))
- break;
- if (payload->data_len < 13)
- break;
- silc_buffer_set(&buf, payload->data, payload->data_len);
- res = silc_buffer_unformat(&buf,
- SILC_STR_UI_INT(&service->port),
- SILC_STR_UI16_NSTRING(&addr, &addr_len),
- SILC_STR_UI_CHAR(&service->status),
- SILC_STR_UI16_NSTRING(&signon, &signon_len),
- SILC_STR_UI_INT(&service->idle),
- SILC_STR_END);
- if (res == -1)
- break;
- memset(service->address, 0, sizeof(service->address));
- memset(service->signon, 0, sizeof(service->signon));
- memcpy(service->address, addr,
- (addr_len < sizeof(service->address) - 1 ? addr_len :
- sizeof(service->address) - 1));
- memcpy(service->signon, signon,
- (signon_len < sizeof(service->signon) - 1 ? signon_len :
- sizeof(service->signon) - 1));
- ret = TRUE;
- }
- break;
-
- case SILC_ATTRIBUTE_STATUS_MOOD:
- case SILC_ATTRIBUTE_PREFERRED_CONTACT:
- {
- SilcUInt32 *mask = (SilcUInt32 *)object;
- if (object_size != sizeof(SilcUInt32))
- break;
- if (payload->data_len < 4)
- break;
- SILC_GET32_MSB(*mask, payload->data);
- ret = TRUE;
- }
- break;
-
- case SILC_ATTRIBUTE_STATUS_FREETEXT:
- case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
- case SILC_ATTRIBUTE_TIMEZONE:
- {
- char *string = object;
- if (payload->data_len < 2)
- break;
- SILC_GET16_MSB(len, payload->data);
- if (payload->data_len < 2 + len)
- break;
- if (object_size < len)
- break;
- memcpy(string, payload->data + 2, len);
- ret = TRUE;
- }
- break;
-
- case SILC_ATTRIBUTE_STATUS_MESSAGE:
- case SILC_ATTRIBUTE_EXTENSION:
- case SILC_ATTRIBUTE_USER_ICON:
- {
- SilcMime mime = object;
- if (object_size != sizeof(*mime))
- break;
- if (!silc_mime_decode(mime, payload->data, payload->data_len))
- break;
- ret = TRUE;
- }
- break;
-
- case SILC_ATTRIBUTE_GEOLOCATION:
- {
- SilcAttributeObjGeo *geo = object;
- SilcBufferStruct buffer;
- int res;
- if (object_size != sizeof(*geo))
- break;
- silc_buffer_set(&buffer, (unsigned char *)payload->data,
- payload->data_len);
- res = silc_buffer_unformat(&buffer,
- SILC_STR_UI16_STRING_ALLOC(&geo->longitude),
- SILC_STR_UI16_STRING_ALLOC(&geo->latitude),
- SILC_STR_UI16_STRING_ALLOC(&geo->altitude),
- SILC_STR_UI16_STRING_ALLOC(&geo->accuracy),
- SILC_STR_END);
- if (res == -1)
- break;
- ret = TRUE;
- }
- break;
-
- case SILC_ATTRIBUTE_DEVICE_INFO:
- {
- SilcAttributeObjDevice *dev = object;
- SilcBufferStruct buffer;
- SilcUInt32 type;
- int res;
- if (object_size != sizeof(*dev))
- break;
- silc_buffer_set(&buffer, (unsigned char *)payload->data,
- payload->data_len);
- res =
- silc_buffer_unformat(&buffer,
- SILC_STR_UI_INT(&type),
- SILC_STR_UI16_STRING_ALLOC(&dev->manufacturer),
- SILC_STR_UI16_STRING_ALLOC(&dev->version),
- SILC_STR_UI16_STRING_ALLOC(&dev->model),
- SILC_STR_UI16_STRING_ALLOC(&dev->language),
- SILC_STR_END);
- if (res == -1)
- break;
- dev->type = type;
- ret = TRUE;
- }
- break;
-
- case SILC_ATTRIBUTE_PHONE_NUMBER:
- {
- SilcAttributeObjPN *pn = object;
- SilcBufferStruct buffer;
- SilcUInt32 pn_format;
- int res;
- if (object_size != sizeof(*pn))
- break;
- silc_buffer_set(&buffer, (unsigned char *)payload->data,
- payload->data_len);
- res =
- silc_buffer_unformat(&buffer,
- SILC_STR_UI_INT(&pn_format),
- SILC_STR_UI16_STRING_ALLOC(&pn->number),
- SILC_STR_END);
- if (res == -1)
- break;
- pn->format = pn_format;
- ret = TRUE;
- }
- break;
-
- case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
- case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
- {
- SilcAttributeObjPk *pk = object;
- SilcBufferStruct buffer;
- int res;
- if (object_size != sizeof(*pk))
- break;
- silc_buffer_set(&buffer, (unsigned char *)payload->data,
- payload->data_len);
- res =
- silc_buffer_unformat(&buffer,
- SILC_STR_UI16_NSTRING_ALLOC(&pk->type, &len),
- SILC_STR_END);
- if (res == -1 || len > silc_buffer_len(&buffer) - 2)
- break;
- pk->data = silc_memdup(payload->data + 2 + len,
- payload->data_len - 2 - len);
- pk->data_len = payload->data_len - 2 - len;
- ret = TRUE;
- }
- break;
-
- case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
- case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
- {
- SilcAttributeObjPk *pk = object;
- if (object_size != sizeof(*pk))
- break;
- pk->type = NULL;
- pk->data = silc_memdup(payload->data, payload->data_len);
- pk->data_len = payload->data_len;
- ret = TRUE;
- }
- break;
-
- default:
- break;
- }
-
- return ret;
-}