1 /*
2
3 silcattrs.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 2002 - 2007 Pekka Riikonen
8
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.
12
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.
17
18 */
19 /* Implementation of Attribute Payload routines */
20 /* $Id: silcattrs.c,v 1.26 2007/11/05 20:35:34 priikone Exp $ */
21
22 #include "silc.h"
23 #include "silcattrs.h"
24
25 /******************************************************************************
26
27 Attribute Payload
28
29 ******************************************************************************/
30
31 struct SilcAttributePayloadStruct {
32 SilcAttribute attribute;
33 SilcAttributeFlags flags;
34 SilcUInt16 data_len;
35 unsigned char *data;
36 };
37
38 /* Internal routine for encoding a attribute */
39
40 static unsigned char *
41 silc_attribute_payload_encode_int(SilcAttribute attribute,
42 SilcAttributeFlags flags,
43 void *object,
44 SilcUInt32 object_size,
45 SilcUInt32 *ret_len)
46 {
47 SilcBuffer tmpbuf = NULL;
48 unsigned char tmp[4], *str = NULL, *ret;
49 SilcUInt32 len;
50
51 /* Encode according to attribute type */
52 if (flags & SILC_ATTRIBUTE_FLAG_VALID) {
53 if (!object && !object_size)
54 return NULL;
55
56 switch (attribute) {
57
58 case SILC_ATTRIBUTE_USER_INFO:
59 {
60 #ifdef SILC_DIST_VCARD
61 SilcVCard vcard = object;
62 if (object_size != sizeof(*vcard))
63 return NULL;
64 str = silc_vcard_encode(vcard, &object_size);
65 if (!str)
66 return NULL;
67 object = str;
68 #endif /* SILC_DIST_VCARD */
69 }
70 break;
71
72 case SILC_ATTRIBUTE_SERVICE:
73 {
74 SilcAttributeObjService *service = object;
75 SilcUInt32 len2;
76 if (object_size != sizeof(*service))
77 return NULL;
78 len = strlen(service->address);
79 len2 = strlen(service->signon);
80 tmpbuf = silc_buffer_alloc_size(13 + len + len2);
81 if (!tmpbuf)
82 return NULL;
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),
91 SILC_STR_END);
92 object = tmpbuf->data;
93 object_size = silc_buffer_len(tmpbuf);
94 }
95 break;
96
97 case SILC_ATTRIBUTE_STATUS_MOOD:
98 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
99 {
100 SilcUInt32 mask = SILC_PTR_TO_32(object);
101 if (object_size != sizeof(SilcUInt32))
102 return NULL;
103 SILC_PUT32_MSB(mask, tmp);
104 object = tmp;
105 object_size = sizeof(SilcUInt32);
106 }
107 break;
108
109 case SILC_ATTRIBUTE_STATUS_FREETEXT:
110 case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
111 case SILC_ATTRIBUTE_TIMEZONE:
112 {
113 unsigned char *string = object;
114 str = silc_malloc(2 + object_size);
115 if (!str)
116 return NULL;
117 SILC_PUT16_MSB(object_size, str);
118 memcpy(str + 2, string, object_size);
119 object = str;
120 object_size += 2;
121 }
122 break;
123
124 case SILC_ATTRIBUTE_STATUS_MESSAGE:
125 case SILC_ATTRIBUTE_EXTENSION:
126 case SILC_ATTRIBUTE_USER_ICON:
127 {
128 SilcMime mime = object;
129 if (object_size != sizeof(*mime))
130 return NULL;
131 str = silc_mime_encode(mime, &object_size);
132 if (!str)
133 return NULL;
134 object = str;
135 }
136 break;
137
138 case SILC_ATTRIBUTE_GEOLOCATION:
139 {
140 SilcAttributeObjGeo *geo = object;
141 SilcUInt32 len1, len2, len3, len4;
142 if (object_size != sizeof(*geo))
143 return NULL;
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)
149 return NULL;
150 len = len1 + len2 + len3 + len4;
151 tmpbuf = silc_buffer_alloc_size(8 + len);
152 if (!tmpbuf)
153 return NULL;
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 : ""),
163 SILC_STR_END);
164 object = tmpbuf->data;
165 object_size = silc_buffer_len(tmpbuf);
166 }
167 break;
168
169 case SILC_ATTRIBUTE_DEVICE_INFO:
170 {
171 SilcAttributeObjDevice *dev = object;
172 SilcUInt32 len1, len2, len3, len4;
173 if (object_size != sizeof(*dev))
174 return NULL;
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)
180 return NULL;
181 len = len1 + len2 + len3 + len4;
182 tmpbuf = silc_buffer_alloc_size(4 + 8 + len);
183 if (!tmpbuf)
184 return NULL;
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 : ""),
195 SILC_STR_END);
196 object = tmpbuf->data;
197 object_size = silc_buffer_len(tmpbuf);
198 }
199 break;
200
201 case SILC_ATTRIBUTE_PHONE_NUMBER:
202 {
203 SilcAttributeObjPN *pn = object;
204 if (object_size != sizeof(*pn))
205 return NULL;
206 if (!pn->number || strlen(pn->number) < 5)
207 return NULL;
208 tmpbuf = silc_buffer_alloc(0);
209 if (!tmpbuf)
210 return NULL;
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),
215 SILC_STR_END) < 0)
216 return NULL;
217 object = tmpbuf->data;
218 object_size = silc_buffer_len(tmpbuf);
219 }
220 break;
221
222 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
223 case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
224 {
225 SilcAttributeObjPk *pk = object;
226 if (object_size != sizeof(*pk))
227 return NULL;
228 len = (pk->type ? strlen(pk->type) : 0);
229 tmpbuf = silc_buffer_alloc_size(2 + len + pk->data_len);
230 if (!tmpbuf)
231 return NULL;
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),
236 SILC_STR_END);
237 object = tmpbuf->data;
238 object_size = silc_buffer_len(tmpbuf);
239 }
240 break;
241
242 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
243 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
244 {
245 SilcAttributeObjPk *pk = object;
246 if (object_size != sizeof(*pk))
247 return NULL;
248 object = pk->data;
249 object_size = pk->data_len;
250 }
251 break;
252
253 default:
254 return NULL;
255 break;
256 }
257
258 ret = silc_memdup(object, object_size);
259
260 if (tmpbuf)
261 silc_buffer_free(tmpbuf);
262 silc_free(str);
263
264 if (ret_len)
265 *ret_len = object_size;
266
267 return ret;
268 }
269
270 return NULL;
271 }
272
273 /* Allocates attribute payload and encodes the attribute there */
274
275 SilcAttributePayload silc_attribute_payload_alloc(SilcAttribute attribute,
276 SilcAttributeFlags flags,
277 void *object,
278 SilcUInt32 object_size)
279 {
280 SilcAttributePayload attr;
281 SilcUInt32 tmp_len;
282
283 attr = silc_calloc(1, sizeof(*attr));
284 if (!attr)
285 return NULL;
286
287 attr->attribute = attribute;
288 attr->flags = flags;
289 attr->data =
290 silc_attribute_payload_encode_int(attribute, flags, object,
291 object_size, &tmp_len);
292 attr->data_len = (SilcUInt16)tmp_len;
293 if (!attr->data) {
294 silc_free(attr);
295 return NULL;
296 }
297
298 return attr;
299 }
300
301 /* Parse list of payloads */
302
303 SilcDList silc_attribute_payload_parse(const unsigned char *payload,
304 SilcUInt32 payload_len)
305 {
306 SilcBufferStruct buffer;
307 SilcDList list;
308 SilcAttributePayload newp;
309 SilcUInt32 len;
310 int ret;
311
312 SILC_LOG_DEBUG(("Parsing Attribute Payload list"));
313
314 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
315 list = silc_dlist_init();
316
317 while (silc_buffer_len(&buffer)) {
318 newp = silc_calloc(1, sizeof(*newp));
319 if (!newp)
320 goto err;
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,
325 &newp->data_len),
326 SILC_STR_END);
327 if (ret == -1)
328 goto err;
329
330 if (newp->data_len > silc_buffer_len(&buffer) - 4) {
331 SILC_LOG_ERROR(("Incorrect attribute payload in list"));
332 goto err;
333 }
334
335 len = 4 + newp->data_len;
336 if (silc_buffer_len(&buffer) < len)
337 break;
338 silc_buffer_pull(&buffer, len);
339
340 silc_dlist_add(list, newp);
341 }
342
343 return list;
344
345 err:
346 silc_attribute_payload_list_free(list);
347 return NULL;
348 }
349
350 /* Encode one attribute payload to buffer */
351
352 SilcBuffer silc_attribute_payload_encode(SilcBuffer attrs,
353 SilcAttribute attribute,
354 SilcAttributeFlags flags,
355 void *object,
356 SilcUInt32 object_size)
357 {
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,
362 object_size);
363 silc_free(object);
364 return attrs;
365 }
366
367 /* Encoded the attribute data directly to buffer */
368
369 SilcBuffer silc_attribute_payload_encode_data(SilcBuffer attrs,
370 SilcAttribute attribute,
371 SilcAttributeFlags flags,
372 const unsigned char *data,
373 SilcUInt32 data_len)
374 {
375 SilcBuffer buffer = attrs;
376 SilcUInt32 len;
377
378 len = 4 + (SilcUInt16)data_len;
379 buffer = silc_buffer_realloc(buffer,
380 (buffer ? silc_buffer_truelen(buffer) +
381 len : len));
382 if (!buffer)
383 return NULL;
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),
391 SILC_STR_END);
392 silc_buffer_push(buffer, buffer->data - buffer->head);
393
394 return buffer;
395 }
396
397 /* Free Attribute Payload */
398
399 void silc_attribute_payload_free(SilcAttributePayload payload)
400 {
401 silc_free(payload->data);
402 silc_free(payload);
403 }
404
405 /* Free's list of Attribute Payloads */
406
407 void silc_attribute_payload_list_free(SilcDList list)
408 {
409 SilcAttributePayload entry;
410
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);
415 }
416
417 silc_dlist_uninit(list);
418 }
419
420 /* Return attribute type */
421
422 SilcAttribute silc_attribute_get_attribute(SilcAttributePayload payload)
423 {
424 return payload->attribute;
425 }
426
427 /* Return attribute flags */
428
429 SilcAttributeFlags silc_attribute_get_flags(SilcAttributePayload payload)
430 {
431 return payload->flags;
432 }
433
434 /* Return attribute data from the payload */
435
436 const unsigned char *silc_attribute_get_data(SilcAttributePayload payload,
437 SilcUInt32 *data_len)
438 {
439 if (data_len)
440 *data_len = (SilcUInt32)payload->data_len;
441 return (const unsigned char *)payload->data;
442 }
443
444 /* Construct digital signature verification data */
445
446 unsigned char *silc_attribute_get_verify_data(SilcDList attrs,
447 SilcBool server_verification,
448 SilcUInt32 *data_len)
449 {
450 SilcAttributePayload attr;
451 SilcBufferStruct buffer;
452 unsigned char *data = NULL;
453 SilcUInt32 len = 0;
454
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 */
460 break;
461
462 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
463 /* For user signature verification this is not part of the data */
464 if (!server_verification)
465 break;
466
467 /* Fallback, for server signature verification, user digital signature
468 is part of verification data. */
469
470 default:
471 /* All other data is part of the verification data */
472 data = silc_realloc(data, sizeof(*data) * (4 + attr->data_len + len));
473 if (!data)
474 return NULL;
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),
481 SILC_STR_END);
482 len += 4 + attr->data_len;
483 break;
484 }
485 }
486
487 if (data_len)
488 *data_len = len;
489
490 return data;
491 }
492
493 /* Return parsed attribute object */
494
495 SilcBool silc_attribute_get_object(SilcAttributePayload payload,
496 void *object, SilcUInt32 object_size)
497 {
498 SilcUInt16 len;
499 SilcBool ret = FALSE;
500
501 if (!object || payload->flags & SILC_ATTRIBUTE_FLAG_INVALID)
502 return FALSE;
503
504 switch (payload->attribute) {
505 case SILC_ATTRIBUTE_USER_INFO:
506 {
507 #ifdef SILC_DIST_VCARD
508 SilcVCard vcard = object;
509 if (object_size != sizeof(*vcard))
510 break;
511 if (!silc_vcard_decode(payload->data, payload->data_len, vcard))
512 break;
513 ret = TRUE;
514 #endif /* SILC_DIST_VCARD */
515 }
516 break;
517
518 case SILC_ATTRIBUTE_SERVICE:
519 {
520 SilcAttributeObjService *service = object;
521 SilcBufferStruct buf;
522 SilcUInt16 addr_len, signon_len;
523 char *addr, *signon;
524 int res;
525 if (object_size != sizeof(*service))
526 break;
527 if (payload->data_len < 13)
528 break;
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),
536 SILC_STR_END);
537 if (res == -1)
538 break;
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));
547 ret = TRUE;
548 }
549 break;
550
551 case SILC_ATTRIBUTE_STATUS_MOOD:
552 case SILC_ATTRIBUTE_PREFERRED_CONTACT:
553 {
554 SilcUInt32 *mask = (SilcUInt32 *)object;
555 if (object_size != sizeof(SilcUInt32))
556 break;
557 if (payload->data_len < 4)
558 break;
559 SILC_GET32_MSB(*mask, payload->data);
560 ret = TRUE;
561 }
562 break;
563
564 case SILC_ATTRIBUTE_STATUS_FREETEXT:
565 case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
566 case SILC_ATTRIBUTE_TIMEZONE:
567 {
568 char *string = object;
569 if (payload->data_len < 2)
570 break;
571 SILC_GET16_MSB(len, payload->data);
572 if (payload->data_len < 2 + len)
573 break;
574 if (object_size < len)
575 break;
576 memcpy(string, payload->data + 2, len);
577 ret = TRUE;
578 }
579 break;
580
581 case SILC_ATTRIBUTE_STATUS_MESSAGE:
582 case SILC_ATTRIBUTE_EXTENSION:
583 case SILC_ATTRIBUTE_USER_ICON:
584 {
585 SilcMime mime = object;
586 if (object_size != sizeof(*mime))
587 break;
588 if (!silc_mime_decode(mime, payload->data, payload->data_len))
589 break;
590 ret = TRUE;
591 }
592 break;
593
594 case SILC_ATTRIBUTE_GEOLOCATION:
595 {
596 SilcAttributeObjGeo *geo = object;
597 SilcBufferStruct buffer;
598 int res;
599 if (object_size != sizeof(*geo))
600 break;
601 silc_buffer_set(&buffer, (unsigned char *)payload->data,
602 payload->data_len);
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),
608 SILC_STR_END);
609 if (res == -1)
610 break;
611 ret = TRUE;
612 }
613 break;
614
615 case SILC_ATTRIBUTE_DEVICE_INFO:
616 {
617 SilcAttributeObjDevice *dev = object;
618 SilcBufferStruct buffer;
619 SilcUInt32 type;
620 int res;
621 if (object_size != sizeof(*dev))
622 break;
623 silc_buffer_set(&buffer, (unsigned char *)payload->data,
624 payload->data_len);
625 res =
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),
632 SILC_STR_END);
633 if (res == -1)
634 break;
635 dev->type = type;
636 ret = TRUE;
637 }
638 break;
639
640 case SILC_ATTRIBUTE_PHONE_NUMBER:
641 {
642 SilcAttributeObjPN *pn = object;
643 SilcBufferStruct buffer;
644 SilcUInt32 pn_format;
645 int res;
646 if (object_size != sizeof(*pn))
647 break;
648 silc_buffer_set(&buffer, (unsigned char *)payload->data,
649 payload->data_len);
650 res =
651 silc_buffer_unformat(&buffer,
652 SILC_STR_UI_INT(&pn_format),
653 SILC_STR_UI16_STRING_ALLOC(&pn->number),
654 SILC_STR_END);
655 if (res == -1)
656 break;
657 pn->format = pn_format;
658 ret = TRUE;
659 }
660 break;
661
662 case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
663 case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
664 {
665 SilcAttributeObjPk *pk = object;
666 SilcBufferStruct buffer;
667 int res;
668 if (object_size != sizeof(*pk))
669 break;
670 silc_buffer_set(&buffer, (unsigned char *)payload->data,
671 payload->data_len);
672 res =
673 silc_buffer_unformat(&buffer,
674 SILC_STR_UI16_NSTRING_ALLOC(&pk->type, &len),
675 SILC_STR_END);
676 if (res == -1 || len > silc_buffer_len(&buffer) - 2)
677 break;
678 pk->data = silc_memdup(payload->data + 2 + len,
679 payload->data_len - 2 - len);
680 pk->data_len = payload->data_len - 2 - len;
681 ret = TRUE;
682 }
683 break;
684
685 case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
686 case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
687 {
688 SilcAttributeObjPk *pk = object;
689 if (object_size != sizeof(*pk))
690 break;
691 pk->type = NULL;
692 pk->data = silc_memdup(payload->data, payload->data_len);
693 pk->data_len = payload->data_len;
694 ret = TRUE;
695 }
696 break;
697
698 default:
699 break;
700 }
701
702 return ret;
703 }
704
This page was automatically generated by the LXR engine.
Free-text search provided by Glimpse