5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 - 2007 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
19 /* Implementation of Attribute Payload routines */
23 #include "silcattrs.h"
25 /******************************************************************************
29 ******************************************************************************/
31 struct SilcAttributePayloadStruct {
32 SilcAttribute attribute;
33 SilcAttributeFlags flags;
38 /* Internal routine for encoding a attribute */
40 static unsigned char *
41 silc_attribute_payload_encode_int(SilcAttribute attribute,
42 SilcAttributeFlags flags,
44 SilcUInt32 object_size,
47 SilcBuffer tmpbuf = NULL;
48 unsigned char tmp[4], *str = NULL, *ret;
51 /* Encode according to attribute type */
52 if (flags & SILC_ATTRIBUTE_FLAG_VALID) {
53 if (!object && !object_size)
58 case SILC_ATTRIBUTE_USER_INFO:
60 SilcVCard vcard = object;
61 if (object_size != sizeof(*vcard))
63 str = silc_vcard_encode(vcard, &object_size);
70 case SILC_ATTRIBUTE_SERVICE:
72 SilcAttributeObjService *service = object;
74 if (object_size != sizeof(*service))
76 len = strlen(service->address);
77 len2 = strlen(service->signon);
78 tmpbuf = silc_buffer_alloc_size(13 + len + len2);
81 silc_buffer_format(tmpbuf,
82 SILC_STR_UI_INT(service->port),
83 SILC_STR_UI_SHORT(len),
84 SILC_STR_UI_XNSTRING(service->address, len),
85 SILC_STR_UI_CHAR(service->status),
86 SILC_STR_UI_SHORT(len2),
87 SILC_STR_UI_XNSTRING(service->signon, len2),
88 SILC_STR_UI_INT(service->idle),
90 object = tmpbuf->data;
91 object_size = silc_buffer_len(tmpbuf);
95 case SILC_ATTRIBUTE_STATUS_MOOD:
96 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
98 SilcUInt32 mask = SILC_PTR_TO_32(object);
99 if (object_size != sizeof(SilcUInt32))
101 SILC_PUT32_MSB(mask, tmp);
103 object_size = sizeof(SilcUInt32);
107 case SILC_ATTRIBUTE_STATUS_FREETEXT:
108 case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
109 case SILC_ATTRIBUTE_TIMEZONE:
111 unsigned char *string = object;
112 str = silc_malloc(2 + object_size);
115 SILC_PUT16_MSB(object_size, str);
116 memcpy(str + 2, string, object_size);
122 case SILC_ATTRIBUTE_STATUS_MESSAGE:
123 case SILC_ATTRIBUTE_EXTENSION:
124 case SILC_ATTRIBUTE_USER_ICON:
126 SilcMime mime = object;
127 if (object_size != sizeof(*mime))
129 str = silc_mime_encode(mime, &object_size);
135 case SILC_ATTRIBUTE_GEOLOCATION:
137 SilcAttributeObjGeo *geo = object;
138 SilcUInt32 len1, len2, len3, len4;
139 if (object_size != sizeof(*geo))
141 len1 = (geo->longitude ? strlen(geo->longitude) : 0);
142 len2 = (geo->latitude ? strlen(geo->latitude) : 0);
143 len3 = (geo->altitude ? strlen(geo->altitude) : 0);
144 len4 = (geo->accuracy ? strlen(geo->accuracy) : 0);
145 if (len1 + len2 + len3 + len4 == 0)
147 len = len1 + len2 + len3 + len4;
148 tmpbuf = silc_buffer_alloc_size(8 + len);
151 silc_buffer_format(tmpbuf,
152 SILC_STR_UI_SHORT(len1),
153 SILC_STR_UI16_STRING(len1 ? geo->longitude : ""),
154 SILC_STR_UI_SHORT(len2),
155 SILC_STR_UI16_STRING(len2 ? geo->latitude : ""),
156 SILC_STR_UI_SHORT(len3),
157 SILC_STR_UI16_STRING(len3 ? geo->altitude : ""),
158 SILC_STR_UI_SHORT(len4),
159 SILC_STR_UI16_STRING(len4 ? geo->accuracy : ""),
161 object = tmpbuf->data;
162 object_size = silc_buffer_len(tmpbuf);
166 case SILC_ATTRIBUTE_DEVICE_INFO:
168 SilcAttributeObjDevice *dev = object;
169 SilcUInt32 len1, len2, len3, len4;
170 if (object_size != sizeof(*dev))
172 len1 = (dev->manufacturer ? strlen(dev->manufacturer) : 0);
173 len2 = (dev->version ? strlen(dev->version) : 0);
174 len3 = (dev->model ? strlen(dev->model) : 0);
175 len4 = (dev->language ? strlen(dev->language) : 0);
176 if (len1 + len2 + len3 + len4 == 0)
178 len = len1 + len2 + len3 + len4;
179 tmpbuf = silc_buffer_alloc_size(4 + 8 + len);
182 silc_buffer_format(tmpbuf,
183 SILC_STR_UI_INT(dev->type),
184 SILC_STR_UI_SHORT(len1),
185 SILC_STR_UI16_STRING(len1 ? dev->manufacturer : ""),
186 SILC_STR_UI_SHORT(len2),
187 SILC_STR_UI16_STRING(len2 ? dev->version : ""),
188 SILC_STR_UI_SHORT(len3),
189 SILC_STR_UI16_STRING(len3 ? dev->model : ""),
190 SILC_STR_UI_SHORT(len4),
191 SILC_STR_UI16_STRING(len4 ? dev->language : ""),
193 object = tmpbuf->data;
194 object_size = silc_buffer_len(tmpbuf);
198 case SILC_ATTRIBUTE_PHONE_NUMBER:
200 SilcAttributeObjPN *pn = object;
201 if (object_size != sizeof(*pn))
203 if (!pn->number || strlen(pn->number) < 5)
205 tmpbuf = silc_buffer_alloc(0);
208 if (silc_buffer_format(tmpbuf,
209 SILC_STR_UI_INT(pn->format),
210 SILC_STR_UI_SHORT(strlen(pn->number)),
211 SILC_STR_UI16_STRING(pn->number),
214 object = tmpbuf->data;
215 object_size = silc_buffer_len(tmpbuf);
219 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
220 case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
222 SilcAttributeObjPk *pk = object;
223 if (object_size != sizeof(*pk))
225 len = (pk->type ? strlen(pk->type) : 0);
226 tmpbuf = silc_buffer_alloc_size(2 + len + pk->data_len);
229 silc_buffer_format(tmpbuf,
230 SILC_STR_UI_SHORT(len),
231 SILC_STR_UI16_STRING(pk->type),
232 SILC_STR_UI_XNSTRING(pk->data, pk->data_len),
234 object = tmpbuf->data;
235 object_size = silc_buffer_len(tmpbuf);
239 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
240 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
242 SilcAttributeObjPk *pk = object;
243 if (object_size != sizeof(*pk))
246 object_size = pk->data_len;
255 ret = silc_memdup(object, object_size);
258 silc_buffer_free(tmpbuf);
262 *ret_len = object_size;
270 /* Allocates attribute payload and encodes the attribute there */
272 SilcAttributePayload silc_attribute_payload_alloc(SilcAttribute attribute,
273 SilcAttributeFlags flags,
275 SilcUInt32 object_size)
277 SilcAttributePayload attr;
280 attr = silc_calloc(1, sizeof(*attr));
284 attr->attribute = attribute;
287 silc_attribute_payload_encode_int(attribute, flags, object,
288 object_size, &tmp_len);
289 attr->data_len = (SilcUInt16)tmp_len;
298 /* Parse list of payloads */
300 SilcDList silc_attribute_payload_parse(const unsigned char *payload,
301 SilcUInt32 payload_len)
303 SilcBufferStruct buffer;
305 SilcAttributePayload newp;
309 SILC_LOG_DEBUG(("Parsing Attribute Payload list"));
311 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
312 list = silc_dlist_init();
314 while (silc_buffer_len(&buffer)) {
315 newp = silc_calloc(1, sizeof(*newp));
318 ret = silc_buffer_unformat(&buffer,
319 SILC_STR_UI_CHAR(&newp->attribute),
320 SILC_STR_UI_CHAR(&newp->flags),
321 SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
327 if (newp->data_len > silc_buffer_len(&buffer) - 4) {
328 SILC_LOG_ERROR(("Incorrect attribute payload in list"));
332 len = 4 + newp->data_len;
333 if (silc_buffer_len(&buffer) < len)
335 silc_buffer_pull(&buffer, len);
337 silc_dlist_add(list, newp);
343 silc_attribute_payload_list_free(list);
347 /* Encode one attribute payload to buffer */
349 SilcBuffer silc_attribute_payload_encode(SilcBuffer attrs,
350 SilcAttribute attribute,
351 SilcAttributeFlags flags,
353 SilcUInt32 object_size)
355 object = silc_attribute_payload_encode_int(attribute, flags, object,
356 object_size, &object_size);
357 attrs = silc_attribute_payload_encode_data(attrs, attribute, flags,
358 (const unsigned char *)object,
364 /* Encoded the attribute data directly to buffer */
366 SilcBuffer silc_attribute_payload_encode_data(SilcBuffer attrs,
367 SilcAttribute attribute,
368 SilcAttributeFlags flags,
369 const unsigned char *data,
372 SilcBuffer buffer = attrs;
375 len = 4 + (SilcUInt16)data_len;
376 buffer = silc_buffer_realloc(buffer,
377 (buffer ? silc_buffer_truelen(buffer) +
381 silc_buffer_pull(buffer, silc_buffer_len(buffer));
382 silc_buffer_pull_tail(buffer, len);
383 silc_buffer_format(buffer,
384 SILC_STR_UI_CHAR(attribute),
385 SILC_STR_UI_CHAR(flags),
386 SILC_STR_UI_SHORT((SilcUInt16)data_len),
387 SILC_STR_UI_XNSTRING(data, (SilcUInt16)data_len),
389 silc_buffer_push(buffer, buffer->data - buffer->head);
394 /* Free Attribute Payload */
396 void silc_attribute_payload_free(SilcAttributePayload payload)
398 silc_free(payload->data);
402 /* Free's list of Attribute Payloads */
404 void silc_attribute_payload_list_free(SilcDList list)
406 SilcAttributePayload entry;
408 silc_dlist_start(list);
409 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
410 silc_attribute_payload_free(entry);
411 silc_dlist_del(list, entry);
414 silc_dlist_uninit(list);
417 /* Return attribute type */
419 SilcAttribute silc_attribute_get_attribute(SilcAttributePayload payload)
421 return payload->attribute;
424 /* Return attribute flags */
426 SilcAttributeFlags silc_attribute_get_flags(SilcAttributePayload payload)
428 return payload->flags;
431 /* Return attribute data from the payload */
433 const unsigned char *silc_attribute_get_data(SilcAttributePayload payload,
434 SilcUInt32 *data_len)
437 *data_len = (SilcUInt32)payload->data_len;
438 return (const unsigned char *)payload->data;
441 /* Construct digital signature verification data */
443 unsigned char *silc_attribute_get_verify_data(SilcDList attrs,
444 SilcBool server_verification,
445 SilcUInt32 *data_len)
447 SilcAttributePayload attr;
448 SilcBufferStruct buffer;
449 unsigned char *data = NULL;
452 silc_dlist_start(attrs);
453 while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
454 switch (attr->attribute) {
455 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
456 /* Server signature is never part of the verification data */
459 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
460 /* For user signature verification this is not part of the data */
461 if (!server_verification)
464 /* Fallback, for server signature verification, user digital signature
465 is part of verification data. */
468 /* All other data is part of the verification data */
469 data = silc_realloc(data, sizeof(*data) * (4 + attr->data_len + len));
472 silc_buffer_set(&buffer, data + len, 4 + attr->data_len);
473 silc_buffer_format(&buffer,
474 SILC_STR_UI_CHAR(attr->attribute),
475 SILC_STR_UI_CHAR(attr->flags),
476 SILC_STR_UI_SHORT(attr->data_len),
477 SILC_STR_UI_XNSTRING(attr->data, attr->data_len),
479 len += 4 + attr->data_len;
490 /* Return parsed attribute object */
492 SilcBool silc_attribute_get_object(SilcAttributePayload payload,
493 void *object, SilcUInt32 object_size)
496 SilcBool ret = FALSE;
498 if (!object || payload->flags & SILC_ATTRIBUTE_FLAG_INVALID)
501 switch (payload->attribute) {
502 case SILC_ATTRIBUTE_USER_INFO:
504 SilcVCard vcard = object;
505 if (object_size != sizeof(*vcard))
507 if (!silc_vcard_decode(payload->data, payload->data_len, vcard))
513 case SILC_ATTRIBUTE_SERVICE:
515 SilcAttributeObjService *service = object;
516 SilcBufferStruct buf;
517 SilcUInt16 addr_len, signon_len;
520 if (object_size != sizeof(*service))
522 if (payload->data_len < 13)
524 silc_buffer_set(&buf, payload->data, payload->data_len);
525 res = silc_buffer_unformat(&buf,
526 SILC_STR_UI_INT(&service->port),
527 SILC_STR_UI16_NSTRING(&addr, &addr_len),
528 SILC_STR_UI_CHAR(&service->status),
529 SILC_STR_UI16_NSTRING(&signon, &signon_len),
530 SILC_STR_UI_INT(&service->idle),
534 memset(service->address, 0, sizeof(service->address));
535 memset(service->signon, 0, sizeof(service->signon));
536 memcpy(service->address, addr,
537 (addr_len < sizeof(service->address) - 1 ? addr_len :
538 sizeof(service->address) - 1));
539 memcpy(service->signon, signon,
540 (signon_len < sizeof(service->signon) - 1 ? signon_len :
541 sizeof(service->signon) - 1));
546 case SILC_ATTRIBUTE_STATUS_MOOD:
547 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
549 SilcUInt32 *mask = (SilcUInt32 *)object;
550 if (object_size != sizeof(SilcUInt32))
552 if (payload->data_len < 4)
554 SILC_GET32_MSB(*mask, payload->data);
559 case SILC_ATTRIBUTE_STATUS_FREETEXT:
560 case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
561 case SILC_ATTRIBUTE_TIMEZONE:
563 char *string = object;
564 if (payload->data_len < 2)
566 SILC_GET16_MSB(len, payload->data);
567 if (payload->data_len < 2 + len)
569 if (object_size < len)
571 memcpy(string, payload->data + 2, len);
576 case SILC_ATTRIBUTE_STATUS_MESSAGE:
577 case SILC_ATTRIBUTE_EXTENSION:
578 case SILC_ATTRIBUTE_USER_ICON:
580 SilcMime mime = object;
581 if (object_size != sizeof(*mime))
583 if (!silc_mime_decode(mime, payload->data, payload->data_len))
589 case SILC_ATTRIBUTE_GEOLOCATION:
591 SilcAttributeObjGeo *geo = object;
592 SilcBufferStruct buffer;
594 if (object_size != sizeof(*geo))
596 silc_buffer_set(&buffer, (unsigned char *)payload->data,
598 res = silc_buffer_unformat(&buffer,
599 SILC_STR_UI16_STRING_ALLOC(&geo->longitude),
600 SILC_STR_UI16_STRING_ALLOC(&geo->latitude),
601 SILC_STR_UI16_STRING_ALLOC(&geo->altitude),
602 SILC_STR_UI16_STRING_ALLOC(&geo->accuracy),
610 case SILC_ATTRIBUTE_DEVICE_INFO:
612 SilcAttributeObjDevice *dev = object;
613 SilcBufferStruct buffer;
616 if (object_size != sizeof(*dev))
618 silc_buffer_set(&buffer, (unsigned char *)payload->data,
621 silc_buffer_unformat(&buffer,
622 SILC_STR_UI_INT(&type),
623 SILC_STR_UI16_STRING_ALLOC(&dev->manufacturer),
624 SILC_STR_UI16_STRING_ALLOC(&dev->version),
625 SILC_STR_UI16_STRING_ALLOC(&dev->model),
626 SILC_STR_UI16_STRING_ALLOC(&dev->language),
635 case SILC_ATTRIBUTE_PHONE_NUMBER:
637 SilcAttributeObjPN *pn = object;
638 SilcBufferStruct buffer;
639 SilcUInt32 pn_format;
641 if (object_size != sizeof(*pn))
643 silc_buffer_set(&buffer, (unsigned char *)payload->data,
646 silc_buffer_unformat(&buffer,
647 SILC_STR_UI_INT(&pn_format),
648 SILC_STR_UI16_STRING_ALLOC(&pn->number),
652 pn->format = pn_format;
657 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
658 case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
660 SilcAttributeObjPk *pk = object;
661 SilcBufferStruct buffer;
663 if (object_size != sizeof(*pk))
665 silc_buffer_set(&buffer, (unsigned char *)payload->data,
668 silc_buffer_unformat(&buffer,
669 SILC_STR_UI16_NSTRING_ALLOC(&pk->type, &len),
671 if (res == -1 || len > silc_buffer_len(&buffer) - 2)
673 pk->data = silc_memdup(payload->data + 2 + len,
674 payload->data_len - 2 - len);
675 pk->data_len = payload->data_len - 2 - len;
680 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
681 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
683 SilcAttributeObjPk *pk = object;
684 if (object_size != sizeof(*pk))
687 pk->data = silc_memdup(payload->data, payload->data_len);
688 pk->data_len = payload->data_len;