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 #ifdef SILC_DIST_VCARD
61 SilcVCard vcard = object;
62 if (object_size != sizeof(*vcard))
64 str = silc_vcard_encode(vcard, &object_size);
68 #endif /* SILC_DIST_VCARD */
72 case SILC_ATTRIBUTE_SERVICE:
74 SilcAttributeObjService *service = object;
76 if (object_size != sizeof(*service))
78 len = strlen(service->address);
79 len2 = strlen(service->signon);
80 tmpbuf = silc_buffer_alloc_size(13 + len + len2);
83 silc_buffer_format(tmpbuf,
84 SILC_STR_UI_INT(service->port),
85 SILC_STR_UI_SHORT(len),
86 SILC_STR_UI_XNSTRING(service->address, len),
87 SILC_STR_UI_CHAR(service->status),
88 SILC_STR_UI_SHORT(len2),
89 SILC_STR_UI_XNSTRING(service->signon, len2),
90 SILC_STR_UI_INT(service->idle),
92 object = tmpbuf->data;
93 object_size = silc_buffer_len(tmpbuf);
97 case SILC_ATTRIBUTE_STATUS_MOOD:
98 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
100 SilcUInt32 mask = SILC_PTR_TO_32(object);
101 if (object_size != sizeof(SilcUInt32))
103 SILC_PUT32_MSB(mask, tmp);
105 object_size = sizeof(SilcUInt32);
109 case SILC_ATTRIBUTE_STATUS_FREETEXT:
110 case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
111 case SILC_ATTRIBUTE_TIMEZONE:
113 unsigned char *string = object;
114 str = silc_malloc(2 + object_size);
117 SILC_PUT16_MSB(object_size, str);
118 memcpy(str + 2, string, object_size);
124 case SILC_ATTRIBUTE_STATUS_MESSAGE:
125 case SILC_ATTRIBUTE_EXTENSION:
126 case SILC_ATTRIBUTE_USER_ICON:
128 SilcMime mime = object;
129 if (object_size != sizeof(*mime))
131 str = silc_mime_encode(mime, &object_size);
138 case SILC_ATTRIBUTE_GEOLOCATION:
140 SilcAttributeObjGeo *geo = object;
141 SilcUInt32 len1, len2, len3, len4;
142 if (object_size != sizeof(*geo))
144 len1 = (geo->longitude ? strlen(geo->longitude) : 0);
145 len2 = (geo->latitude ? strlen(geo->latitude) : 0);
146 len3 = (geo->altitude ? strlen(geo->altitude) : 0);
147 len4 = (geo->accuracy ? strlen(geo->accuracy) : 0);
148 if (len1 + len2 + len3 + len4 == 0)
150 len = len1 + len2 + len3 + len4;
151 tmpbuf = silc_buffer_alloc_size(8 + len);
154 silc_buffer_format(tmpbuf,
155 SILC_STR_UI_SHORT(len1),
156 SILC_STR_UI16_STRING(len1 ? geo->longitude : ""),
157 SILC_STR_UI_SHORT(len2),
158 SILC_STR_UI16_STRING(len2 ? geo->latitude : ""),
159 SILC_STR_UI_SHORT(len3),
160 SILC_STR_UI16_STRING(len3 ? geo->altitude : ""),
161 SILC_STR_UI_SHORT(len4),
162 SILC_STR_UI16_STRING(len4 ? geo->accuracy : ""),
164 object = tmpbuf->data;
165 object_size = silc_buffer_len(tmpbuf);
169 case SILC_ATTRIBUTE_DEVICE_INFO:
171 SilcAttributeObjDevice *dev = object;
172 SilcUInt32 len1, len2, len3, len4;
173 if (object_size != sizeof(*dev))
175 len1 = (dev->manufacturer ? strlen(dev->manufacturer) : 0);
176 len2 = (dev->version ? strlen(dev->version) : 0);
177 len3 = (dev->model ? strlen(dev->model) : 0);
178 len4 = (dev->language ? strlen(dev->language) : 0);
179 if (len1 + len2 + len3 + len4 == 0)
181 len = len1 + len2 + len3 + len4;
182 tmpbuf = silc_buffer_alloc_size(4 + 8 + len);
185 silc_buffer_format(tmpbuf,
186 SILC_STR_UI_INT(dev->type),
187 SILC_STR_UI_SHORT(len1),
188 SILC_STR_UI16_STRING(len1 ? dev->manufacturer : ""),
189 SILC_STR_UI_SHORT(len2),
190 SILC_STR_UI16_STRING(len2 ? dev->version : ""),
191 SILC_STR_UI_SHORT(len3),
192 SILC_STR_UI16_STRING(len3 ? dev->model : ""),
193 SILC_STR_UI_SHORT(len4),
194 SILC_STR_UI16_STRING(len4 ? dev->language : ""),
196 object = tmpbuf->data;
197 object_size = silc_buffer_len(tmpbuf);
201 case SILC_ATTRIBUTE_PHONE_NUMBER:
203 SilcAttributeObjPN *pn = object;
204 if (object_size != sizeof(*pn))
206 if (!pn->number || strlen(pn->number) < 5)
208 tmpbuf = silc_buffer_alloc(0);
211 if (silc_buffer_format(tmpbuf,
212 SILC_STR_UI_INT(pn->format),
213 SILC_STR_UI_SHORT(strlen(pn->number)),
214 SILC_STR_UI16_STRING(pn->number),
217 object = tmpbuf->data;
218 object_size = silc_buffer_len(tmpbuf);
222 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
223 case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
225 SilcAttributeObjPk *pk = object;
226 if (object_size != sizeof(*pk))
228 len = (pk->type ? strlen(pk->type) : 0);
229 tmpbuf = silc_buffer_alloc_size(2 + len + pk->data_len);
232 silc_buffer_format(tmpbuf,
233 SILC_STR_UI_SHORT(len),
234 SILC_STR_UI16_STRING(pk->type),
235 SILC_STR_UI_XNSTRING(pk->data, pk->data_len),
237 object = tmpbuf->data;
238 object_size = silc_buffer_len(tmpbuf);
242 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
243 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
245 SilcAttributeObjPk *pk = object;
246 if (object_size != sizeof(*pk))
249 object_size = pk->data_len;
258 ret = silc_memdup(object, object_size);
261 silc_buffer_free(tmpbuf);
265 *ret_len = object_size;
273 /* Allocates attribute payload and encodes the attribute there */
275 SilcAttributePayload silc_attribute_payload_alloc(SilcAttribute attribute,
276 SilcAttributeFlags flags,
278 SilcUInt32 object_size)
280 SilcAttributePayload attr;
283 attr = silc_calloc(1, sizeof(*attr));
287 attr->attribute = attribute;
290 silc_attribute_payload_encode_int(attribute, flags, object,
291 object_size, &tmp_len);
292 attr->data_len = (SilcUInt16)tmp_len;
301 /* Parse list of payloads */
303 SilcDList silc_attribute_payload_parse(const unsigned char *payload,
304 SilcUInt32 payload_len)
306 SilcBufferStruct buffer;
308 SilcAttributePayload newp;
312 SILC_LOG_DEBUG(("Parsing Attribute Payload list"));
314 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
315 list = silc_dlist_init();
317 while (silc_buffer_len(&buffer)) {
318 newp = silc_calloc(1, sizeof(*newp));
321 ret = silc_buffer_unformat(&buffer,
322 SILC_STR_UI_CHAR(&newp->attribute),
323 SILC_STR_UI_CHAR(&newp->flags),
324 SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
330 if (newp->data_len > silc_buffer_len(&buffer) - 4) {
331 SILC_LOG_ERROR(("Incorrect attribute payload in list"));
335 len = 4 + newp->data_len;
336 if (silc_buffer_len(&buffer) < len)
338 silc_buffer_pull(&buffer, len);
340 silc_dlist_add(list, newp);
346 silc_attribute_payload_list_free(list);
350 /* Encode one attribute payload to buffer */
352 SilcBuffer silc_attribute_payload_encode(SilcBuffer attrs,
353 SilcAttribute attribute,
354 SilcAttributeFlags flags,
356 SilcUInt32 object_size)
358 object = silc_attribute_payload_encode_int(attribute, flags, object,
359 object_size, &object_size);
360 attrs = silc_attribute_payload_encode_data(attrs, attribute, flags,
361 (const unsigned char *)object,
367 /* Encoded the attribute data directly to buffer */
369 SilcBuffer silc_attribute_payload_encode_data(SilcBuffer attrs,
370 SilcAttribute attribute,
371 SilcAttributeFlags flags,
372 const unsigned char *data,
375 SilcBuffer buffer = attrs;
378 len = 4 + (SilcUInt16)data_len;
379 buffer = silc_buffer_realloc(buffer,
380 (buffer ? silc_buffer_truelen(buffer) +
384 silc_buffer_pull(buffer, silc_buffer_len(buffer));
385 silc_buffer_pull_tail(buffer, len);
386 silc_buffer_format(buffer,
387 SILC_STR_UI_CHAR(attribute),
388 SILC_STR_UI_CHAR(flags),
389 SILC_STR_UI_SHORT((SilcUInt16)data_len),
390 SILC_STR_UI_XNSTRING(data, (SilcUInt16)data_len),
392 silc_buffer_push(buffer, buffer->data - buffer->head);
397 /* Free Attribute Payload */
399 void silc_attribute_payload_free(SilcAttributePayload payload)
401 silc_free(payload->data);
405 /* Free's list of Attribute Payloads */
407 void silc_attribute_payload_list_free(SilcDList list)
409 SilcAttributePayload entry;
411 silc_dlist_start(list);
412 while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
413 silc_attribute_payload_free(entry);
414 silc_dlist_del(list, entry);
417 silc_dlist_uninit(list);
420 /* Return attribute type */
422 SilcAttribute silc_attribute_get_attribute(SilcAttributePayload payload)
424 return payload->attribute;
427 /* Return attribute flags */
429 SilcAttributeFlags silc_attribute_get_flags(SilcAttributePayload payload)
431 return payload->flags;
434 /* Return attribute data from the payload */
436 const unsigned char *silc_attribute_get_data(SilcAttributePayload payload,
437 SilcUInt32 *data_len)
440 *data_len = (SilcUInt32)payload->data_len;
441 return (const unsigned char *)payload->data;
444 /* Construct digital signature verification data */
446 unsigned char *silc_attribute_get_verify_data(SilcDList attrs,
447 SilcBool server_verification,
448 SilcUInt32 *data_len)
450 SilcAttributePayload attr;
451 SilcBufferStruct buffer;
452 unsigned char *data = NULL;
455 silc_dlist_start(attrs);
456 while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
457 switch (attr->attribute) {
458 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
459 /* Server signature is never part of the verification data */
462 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
463 /* For user signature verification this is not part of the data */
464 if (!server_verification)
467 /* Fallback, for server signature verification, user digital signature
468 is part of verification data. */
471 /* All other data is part of the verification data */
472 data = silc_realloc(data, sizeof(*data) * (4 + attr->data_len + len));
475 silc_buffer_set(&buffer, data + len, 4 + attr->data_len);
476 silc_buffer_format(&buffer,
477 SILC_STR_UI_CHAR(attr->attribute),
478 SILC_STR_UI_CHAR(attr->flags),
479 SILC_STR_UI_SHORT(attr->data_len),
480 SILC_STR_UI_XNSTRING(attr->data, attr->data_len),
482 len += 4 + attr->data_len;
493 /* Return parsed attribute object */
495 SilcBool silc_attribute_get_object(SilcAttributePayload payload,
496 void *object, SilcUInt32 object_size)
499 SilcBool ret = FALSE;
501 if (!object || payload->flags & SILC_ATTRIBUTE_FLAG_INVALID)
504 switch (payload->attribute) {
505 case SILC_ATTRIBUTE_USER_INFO:
507 #ifdef SILC_DIST_VCARD
508 SilcVCard vcard = object;
509 if (object_size != sizeof(*vcard))
511 if (!silc_vcard_decode(payload->data, payload->data_len, vcard))
514 #endif /* SILC_DIST_VCARD */
518 case SILC_ATTRIBUTE_SERVICE:
520 SilcAttributeObjService *service = object;
521 SilcBufferStruct buf;
522 SilcUInt16 addr_len, signon_len;
525 if (object_size != sizeof(*service))
527 if (payload->data_len < 13)
529 silc_buffer_set(&buf, payload->data, payload->data_len);
530 res = silc_buffer_unformat(&buf,
531 SILC_STR_UI_INT(&service->port),
532 SILC_STR_UI16_NSTRING(&addr, &addr_len),
533 SILC_STR_UI_CHAR(&service->status),
534 SILC_STR_UI16_NSTRING(&signon, &signon_len),
535 SILC_STR_UI_INT(&service->idle),
539 memset(service->address, 0, sizeof(service->address));
540 memset(service->signon, 0, sizeof(service->signon));
541 memcpy(service->address, addr,
542 (addr_len < sizeof(service->address) - 1 ? addr_len :
543 sizeof(service->address) - 1));
544 memcpy(service->signon, signon,
545 (signon_len < sizeof(service->signon) - 1 ? signon_len :
546 sizeof(service->signon) - 1));
551 case SILC_ATTRIBUTE_STATUS_MOOD:
552 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
554 SilcUInt32 *mask = (SilcUInt32 *)object;
555 if (object_size != sizeof(SilcUInt32))
557 if (payload->data_len < 4)
559 SILC_GET32_MSB(*mask, payload->data);
564 case SILC_ATTRIBUTE_STATUS_FREETEXT:
565 case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
566 case SILC_ATTRIBUTE_TIMEZONE:
568 char *string = object;
569 if (payload->data_len < 2)
571 SILC_GET16_MSB(len, payload->data);
572 if (payload->data_len < 2 + len)
574 if (object_size < len)
576 memcpy(string, payload->data + 2, len);
581 case SILC_ATTRIBUTE_STATUS_MESSAGE:
582 case SILC_ATTRIBUTE_EXTENSION:
583 case SILC_ATTRIBUTE_USER_ICON:
585 SilcMime mime = object;
586 if (object_size != sizeof(*mime))
588 if (!silc_mime_decode(mime, payload->data, payload->data_len))
594 case SILC_ATTRIBUTE_GEOLOCATION:
596 SilcAttributeObjGeo *geo = object;
597 SilcBufferStruct buffer;
599 if (object_size != sizeof(*geo))
601 silc_buffer_set(&buffer, (unsigned char *)payload->data,
603 res = silc_buffer_unformat(&buffer,
604 SILC_STR_UI16_STRING_ALLOC(&geo->longitude),
605 SILC_STR_UI16_STRING_ALLOC(&geo->latitude),
606 SILC_STR_UI16_STRING_ALLOC(&geo->altitude),
607 SILC_STR_UI16_STRING_ALLOC(&geo->accuracy),
615 case SILC_ATTRIBUTE_DEVICE_INFO:
617 SilcAttributeObjDevice *dev = object;
618 SilcBufferStruct buffer;
621 if (object_size != sizeof(*dev))
623 silc_buffer_set(&buffer, (unsigned char *)payload->data,
626 silc_buffer_unformat(&buffer,
627 SILC_STR_UI_INT(&type),
628 SILC_STR_UI16_STRING_ALLOC(&dev->manufacturer),
629 SILC_STR_UI16_STRING_ALLOC(&dev->version),
630 SILC_STR_UI16_STRING_ALLOC(&dev->model),
631 SILC_STR_UI16_STRING_ALLOC(&dev->language),
640 case SILC_ATTRIBUTE_PHONE_NUMBER:
642 SilcAttributeObjPN *pn = object;
643 SilcBufferStruct buffer;
644 SilcUInt32 pn_format;
646 if (object_size != sizeof(*pn))
648 silc_buffer_set(&buffer, (unsigned char *)payload->data,
651 silc_buffer_unformat(&buffer,
652 SILC_STR_UI_INT(&pn_format),
653 SILC_STR_UI16_STRING_ALLOC(&pn->number),
657 pn->format = pn_format;
662 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
663 case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
665 SilcAttributeObjPk *pk = object;
666 SilcBufferStruct buffer;
668 if (object_size != sizeof(*pk))
670 silc_buffer_set(&buffer, (unsigned char *)payload->data,
673 silc_buffer_unformat(&buffer,
674 SILC_STR_UI16_NSTRING_ALLOC(&pk->type, &len),
676 if (res == -1 || len > silc_buffer_len(&buffer) - 2)
678 pk->data = silc_memdup(payload->data + 2 + len,
679 payload->data_len - 2 - len);
680 pk->data_len = payload->data_len - 2 - len;
685 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
686 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
688 SilcAttributeObjPk *pk = object;
689 if (object_size != sizeof(*pk))
692 pk->data = silc_memdup(payload->data, payload->data_len);
693 pk->data_len = payload->data_len;