X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilccore%2Fsilcattrs.c;h=27f25f7373ebea728ba10e1c984ce7d5e9bca532;hb=40f8443d8d3a6577336ee66d18e04d9ac4d956bb;hp=652333e35c63ed963699541b9393db412d602ba7;hpb=81a20cc52aceb480932652db71f9622e4a5030e1;p=silc.git diff --git a/lib/silccore/silcattrs.c b/lib/silccore/silcattrs.c index 652333e3..27f25f73 100644 --- a/lib/silccore/silcattrs.c +++ b/lib/silccore/silcattrs.c @@ -1,10 +1,10 @@ /* - silcattrs.c + silcattrs.c Author: Pekka Riikonen - Copyright (C) 2002 Pekka Riikonen + Copyright (C) 2002 - 2005 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 @@ -19,7 +19,7 @@ /* Implementation of Attribute Payload routines */ /* $Id$ */ -#include "silcincludes.h" +#include "silc.h" #include "silcattrs.h" /****************************************************************************** @@ -35,112 +35,285 @@ struct SilcAttributePayloadStruct { unsigned char *data; }; -/* Parse one attribute payload */ +/* Internal routine for encoding a attribute */ -SilcAttributePayload -silc_attribute_payload_parse(const unsigned char *payload, - SilcUInt32 payload_len) +static unsigned char * +silc_attribute_payload_encode_int(SilcAttribute attribute, + SilcAttributeFlags flags, + void *object, + SilcUInt32 object_size, + SilcUInt32 *ret_len) { - SilcBufferStruct buffer; - SilcAttributePayload newp; - int ret; + 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: + { + SilcVCard vcard = object; + if (object_size != sizeof(*vcard)) + return NULL; + str = silc_vcard_encode(vcard, &object_size); + if (!str) + return NULL; + object = str; + } + break; - SILC_LOG_DEBUG(("Parsing attribute payload")); + 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); + 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; - silc_buffer_set(&buffer, (unsigned char *)payload, payload_len); - newp = silc_calloc(1, sizeof(*newp)); - if (!newp) - return NULL; + 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; - /* Parse the Attribute Payload. */ - 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; + 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; - if (newp->data_len > buffer.len - 4) { - SILC_LOG_ERROR(("Incorrect attribute payload")); - goto err; - } + 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; + } + break; - return newp; + 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_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; + } - err: - silc_attribute_payload_free(newp); return NULL; } -/* Encode one attribute payload */ +/* Allocates attribute payload and encodes the attribute there */ -SilcBuffer silc_attribute_payload_encode(SilcAttribute attribute, - SilcAttributeFlags flags, - const unsigned char *data, - SilcUInt32 data_len) +SilcAttributePayload silc_attribute_payload_alloc(SilcAttribute attribute, + SilcAttributeFlags flags, + void *object, + SilcUInt32 object_size) { - SilcBuffer buffer; - - SILC_LOG_DEBUG(("Encoding Attribute Payload")); + SilcAttributePayload attr; + SilcUInt32 tmp_len; - buffer = silc_buffer_alloc_size(4 + data_len); - if (!buffer) + attr = silc_calloc(1, sizeof(*attr)); + if (!attr) return NULL; - /* Encode the Attribute Payload */ - 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, data_len), - SILC_STR_END); + 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 buffer; + return attr; } /* Parse list of payloads */ -SilcDList silc_attribute_payload_parse_list(const unsigned char *payload, - SilcUInt32 payload_len) +SilcDList silc_attribute_payload_parse(const unsigned char *payload, + SilcUInt32 payload_len) { SilcBufferStruct buffer; SilcDList list; SilcAttributePayload newp; - int len, ret; + 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 (buffer.len) { + 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, + SILC_STR_UI16_NSTRING_ALLOC(&newp->data, &newp->data_len), SILC_STR_END); if (ret == -1) goto err; - if (newp->data_len > buffer.len) { + 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 (buffer.len < len) + if (silc_buffer_len(&buffer) < len) break; silc_buffer_pull(&buffer, len); silc_dlist_add(list, newp); } - + return list; err: @@ -148,47 +321,48 @@ SilcDList silc_attribute_payload_parse_list(const unsigned char *payload, return NULL; } -/* Encode list of payloads */ +/* Encode one attribute payload to buffer */ -SilcBuffer silc_attribute_payload_encode_list(SilcUInt32 num_attrs, ...) +SilcBuffer silc_attribute_payload_encode(SilcBuffer attrs, + SilcAttribute attribute, + SilcAttributeFlags flags, + void *object, + SilcUInt32 object_size) { - SilcBuffer buffer = NULL; - va_list ap; - int i, len = 0; - SilcAttribute attribute; - SilcAttributeFlags flags; - unsigned char *data; - SilcUInt32 data_len; + 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; +} - if (!num_attrs) - return NULL; +/* Encoded the attribute data directly to buffer */ - va_start(ap, num_attrs); - for (i = 0; i < num_attrs; i++) { - attribute = va_arg(ap, SilcUInt32); - flags = va_arg(ap, SilcUInt32); - data = va_arg(ap, unsigned char *); - data_len = va_arg(ap, SilcUInt32); - - if (data || !data_len) - continue; - - len = 4 + data_len; - buffer = silc_buffer_realloc(buffer, - (buffer ? buffer->truelen + len : len)); - silc_buffer_pull_tail(buffer, (buffer->end - buffer->data)); - 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, data_len), - SILC_STR_END); - silc_buffer_pull(buffer, len); - } - va_end(ap); +SilcBuffer silc_attribute_payload_encode_data(SilcBuffer attrs, + SilcAttribute attribute, + SilcAttributeFlags flags, + const unsigned char *data, + SilcUInt32 data_len) +{ + SilcBuffer buffer = attrs; + SilcUInt32 len; - if (buffer) - silc_buffer_push(buffer, buffer->data - buffer->head); + 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; } @@ -236,42 +410,111 @@ const unsigned char *silc_attribute_get_data(SilcAttributePayload payload, SilcUInt32 *data_len) { if (data_len) - *data_len = payload->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 */ -bool silc_attribute_get_object(SilcAttributePayload payload, - SilcAttribute attribute, - void **object, SilcUInt32 object_size) +SilcBool silc_attribute_get_object(SilcAttributePayload payload, + void *object, SilcUInt32 object_size) { SilcUInt16 len; - bool ret = FALSE; + SilcBool ret = FALSE; - if (!attribute || !object || !(*object)) + if (!object || payload->flags & SILC_ATTRIBUTE_FLAG_INVALID) return FALSE; - switch (attribute) { + switch (payload->attribute) { case SILC_ATTRIBUTE_USER_INFO: - SILC_NOT_IMPLEMENTED("SILC_ATTRIBUTE_USER_INFO"); + { + SilcVCard vcard = object; + if (object_size != sizeof(*vcard)) + break; + if (!silc_vcard_decode(payload->data, payload->data_len, vcard)) + break; + ret = TRUE; + } break; case SILC_ATTRIBUTE_SERVICE: { - SilcAttributeObjService *service = *object; + 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 < 7) + if (payload->data_len < 13) break; - SILC_GET32_MSB(service->port, payload->data); - SILC_GET16_MSB(len, payload->data + 4); - if (payload->data_len < 7 + len) + 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; - memcpy(service->address, payload->data + 6, - (len < sizeof(service->address) - 1 ? len : + 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)); - service->status = payload->data[6 + len] ? TRUE : FALSE; + memcpy(service->signon, signon, + (signon_len < sizeof(service->signon) - 1 ? signon_len : + sizeof(service->signon) - 1)); ret = TRUE; } break; @@ -279,7 +522,7 @@ bool silc_attribute_get_object(SilcAttributePayload payload, case SILC_ATTRIBUTE_STATUS_MOOD: case SILC_ATTRIBUTE_PREFERRED_CONTACT: { - SilcUInt32 *mask = *object; + SilcUInt32 *mask = (SilcUInt32 *)object; if (object_size != sizeof(SilcUInt32)) break; if (payload->data_len < 4) @@ -293,7 +536,7 @@ bool silc_attribute_get_object(SilcAttributePayload payload, case SILC_ATTRIBUTE_PREFERRED_LANGUAGE: case SILC_ATTRIBUTE_TIMEZONE: { - char *string = *object; + char *string = object; if (payload->data_len < 2) break; SILC_GET16_MSB(len, payload->data); @@ -308,19 +551,20 @@ bool silc_attribute_get_object(SilcAttributePayload payload, case SILC_ATTRIBUTE_STATUS_MESSAGE: case SILC_ATTRIBUTE_EXTENSION: + case SILC_ATTRIBUTE_USER_ICON: { - SilcAttributeObjMime *mime = *object; + SilcMime mime = object; if (object_size != sizeof(*mime)) break; - mime->mime = silc_memdup(payload->data, payload->data_len); - mime->mime_len = payload->data_len; + if (!silc_mime_decode(mime, payload->data, payload->data_len)) + break; ret = TRUE; } break; case SILC_ATTRIBUTE_GEOLOCATION: { - SilcAttributeObjGeo *geo = *object; + SilcAttributeObjGeo *geo = object; SilcBufferStruct buffer; int res; if (object_size != sizeof(*geo)) @@ -333,7 +577,7 @@ bool silc_attribute_get_object(SilcAttributePayload payload, SILC_STR_UI16_STRING_ALLOC(&geo->altitude), SILC_STR_UI16_STRING_ALLOC(&geo->accuracy), SILC_STR_END); - if (res == 1) + if (res == -1) break; ret = TRUE; } @@ -341,7 +585,7 @@ bool silc_attribute_get_object(SilcAttributePayload payload, case SILC_ATTRIBUTE_DEVICE_INFO: { - SilcAttributeObjDevice *dev = *object; + SilcAttributeObjDevice *dev = object; SilcBufferStruct buffer; SilcUInt32 type; int res; @@ -357,7 +601,7 @@ bool silc_attribute_get_object(SilcAttributePayload payload, SILC_STR_UI16_STRING_ALLOC(&dev->model), SILC_STR_UI16_STRING_ALLOC(&dev->language), SILC_STR_END); - if (res == 1) + if (res == -1) break; dev->type = type; ret = TRUE; @@ -367,7 +611,7 @@ bool silc_attribute_get_object(SilcAttributePayload payload, case SILC_ATTRIBUTE_USER_PUBLIC_KEY: case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY: { - SilcAttributeObjPk *pk = *object; + SilcAttributeObjPk *pk = object; SilcBufferStruct buffer; int res; if (object_size != sizeof(*pk)) @@ -378,7 +622,7 @@ bool silc_attribute_get_object(SilcAttributePayload payload, silc_buffer_unformat(&buffer, SILC_STR_UI16_NSTRING_ALLOC(&pk->type, &len), SILC_STR_END); - if (res == 1) + if (res == -1 || len > silc_buffer_len(&buffer) - 2) break; pk->data = silc_memdup(payload->data + 2 + len, payload->data_len - 2 - len); @@ -390,7 +634,7 @@ bool silc_attribute_get_object(SilcAttributePayload payload, case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE: case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE: { - SilcAttributeObjPk *pk = *object; + SilcAttributeObjPk *pk = object; if (object_size != sizeof(*pk)) break; pk->type = NULL;