Static analyzer bug fixes
[silc.git] / lib / silccore / silcattrs.c
1 /*
2
3   silcattrs.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2002 - 2014 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$ */
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   if (ret_len)
52     *ret_len = 0;
53
54   /* Encode according to attribute type */
55   if (flags & SILC_ATTRIBUTE_FLAG_VALID) {
56     if (!object || !object_size)
57       return NULL;
58
59     switch (attribute) {
60
61     case SILC_ATTRIBUTE_USER_INFO:
62       {
63 #ifdef SILC_DIST_VCARD
64         SilcVCard vcard = object;
65         if (object_size != sizeof(*vcard))
66           return NULL;
67         str = silc_vcard_encode(vcard, &object_size);
68         if (!str)
69           return NULL;
70         object = str;
71 #endif /* SILC_DIST_VCARD */
72       }
73       break;
74
75     case SILC_ATTRIBUTE_SERVICE:
76       {
77         SilcAttributeObjService *service = object;
78         SilcUInt32 len2;
79         if (object_size != sizeof(*service))
80           return NULL;
81         len = strlen(service->address);
82         len2 = strlen(service->signon);
83         tmpbuf = silc_buffer_alloc_size(13 + len + len2);
84         if (!tmpbuf)
85           return NULL;
86         silc_buffer_format(tmpbuf,
87                            SILC_STR_UI_INT(service->port),
88                            SILC_STR_UI_SHORT(len),
89                            SILC_STR_UI_XNSTRING(service->address, len),
90                            SILC_STR_UI_CHAR(service->status),
91                            SILC_STR_UI_SHORT(len2),
92                            SILC_STR_UI_XNSTRING(service->signon, len2),
93                            SILC_STR_UI_INT(service->idle),
94                            SILC_STR_END);
95         object = tmpbuf->data;
96         object_size = silc_buffer_len(tmpbuf);
97       }
98       break;
99
100     case SILC_ATTRIBUTE_STATUS_MOOD:
101     case SILC_ATTRIBUTE_PREFERRED_CONTACT:
102       {
103         SilcUInt32 mask = SILC_PTR_TO_32(object);
104         if (object_size != sizeof(SilcUInt32))
105           return NULL;
106         SILC_PUT32_MSB(mask, tmp);
107         object = tmp;
108         object_size = sizeof(SilcUInt32);
109       }
110       break;
111
112     case SILC_ATTRIBUTE_STATUS_FREETEXT:
113     case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
114     case SILC_ATTRIBUTE_TIMEZONE:
115       {
116         unsigned char *string = object;
117         str = silc_malloc(2 + object_size);
118         if (!str)
119           return NULL;
120         SILC_PUT16_MSB(object_size, str);
121         memcpy(str + 2, string, object_size);
122         object = str;
123         object_size += 2;
124       }
125       break;
126
127     case SILC_ATTRIBUTE_STATUS_MESSAGE:
128     case SILC_ATTRIBUTE_EXTENSION:
129     case SILC_ATTRIBUTE_USER_ICON:
130       {
131         SilcMime mime = object;
132         if (object_size != sizeof(*mime))
133           return NULL;
134         str = silc_mime_encode(mime, &object_size);
135         if (!str)
136           return NULL;
137         object = str;
138       }
139       break;
140
141     case SILC_ATTRIBUTE_GEOLOCATION:
142       {
143         SilcAttributeObjGeo *geo = object;
144         SilcUInt32 len1, len2, len3, len4;
145         if (object_size != sizeof(*geo))
146           return NULL;
147         len1 = (geo->longitude ? strlen(geo->longitude) : 0);
148         len2 = (geo->latitude  ? strlen(geo->latitude)  : 0);
149         len3 = (geo->altitude  ? strlen(geo->altitude)  : 0);
150         len4 = (geo->accuracy  ? strlen(geo->accuracy)  : 0);
151         if (len1 + len2 + len3 + len4 == 0)
152           return NULL;
153         len = len1 + len2 + len3 + len4;
154         tmpbuf = silc_buffer_alloc_size(8 + len);
155         if (!tmpbuf)
156           return NULL;
157         silc_buffer_format(tmpbuf,
158                            SILC_STR_UI_SHORT(len1),
159                            SILC_STR_UI16_STRING(len1 ? geo->longitude : ""),
160                            SILC_STR_UI_SHORT(len2),
161                            SILC_STR_UI16_STRING(len2 ? geo->latitude : ""),
162                            SILC_STR_UI_SHORT(len3),
163                            SILC_STR_UI16_STRING(len3 ? geo->altitude : ""),
164                            SILC_STR_UI_SHORT(len4),
165                            SILC_STR_UI16_STRING(len4 ? geo->accuracy : ""),
166                            SILC_STR_END);
167         object = tmpbuf->data;
168         object_size = silc_buffer_len(tmpbuf);
169       }
170       break;
171
172     case SILC_ATTRIBUTE_DEVICE_INFO:
173       {
174         SilcAttributeObjDevice *dev = object;
175         SilcUInt32 len1, len2, len3, len4;
176         if (object_size != sizeof(*dev))
177           return NULL;
178         len1 = (dev->manufacturer ? strlen(dev->manufacturer) : 0);
179         len2 = (dev->version      ? strlen(dev->version)      : 0);
180         len3 = (dev->model        ? strlen(dev->model)        : 0);
181         len4 = (dev->language     ? strlen(dev->language)     : 0);
182         if (len1 + len2 + len3 + len4 == 0)
183           return NULL;
184         len = len1 + len2 + len3 + len4;
185         tmpbuf = silc_buffer_alloc_size(4 + 8 + len);
186         if (!tmpbuf)
187           return NULL;
188         silc_buffer_format(tmpbuf,
189                            SILC_STR_UI_INT(dev->type),
190                            SILC_STR_UI_SHORT(len1),
191                            SILC_STR_UI16_STRING(len1 ? dev->manufacturer : ""),
192                            SILC_STR_UI_SHORT(len2),
193                            SILC_STR_UI16_STRING(len2 ? dev->version : ""),
194                            SILC_STR_UI_SHORT(len3),
195                            SILC_STR_UI16_STRING(len3 ? dev->model : ""),
196                            SILC_STR_UI_SHORT(len4),
197                            SILC_STR_UI16_STRING(len4 ? dev->language : ""),
198                            SILC_STR_END);
199         object = tmpbuf->data;
200         object_size = silc_buffer_len(tmpbuf);
201       }
202       break;
203
204     case SILC_ATTRIBUTE_PHONE_NUMBER:
205       {
206         SilcAttributeObjPN *pn = object;
207         if (object_size != sizeof(*pn))
208           return NULL;
209         if (!pn->number || strlen(pn->number) < 5)
210           return NULL;
211         tmpbuf = silc_buffer_alloc(0);
212         if (!tmpbuf)
213           return NULL;
214         if (silc_buffer_format(tmpbuf,
215                                SILC_STR_UI_INT(pn->format),
216                                SILC_STR_UI_SHORT(strlen(pn->number)),
217                                SILC_STR_UI16_STRING(pn->number),
218                                SILC_STR_END) < 0)
219           return NULL;
220         object = tmpbuf->data;
221         object_size = silc_buffer_len(tmpbuf);
222       }
223       break;
224
225     case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
226     case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
227       {
228         SilcAttributeObjPk *pk = object;
229         if (object_size != sizeof(*pk))
230           return NULL;
231         len = (pk->type ? strlen(pk->type) : 0);
232         tmpbuf = silc_buffer_alloc_size(2 + len + pk->data_len);
233         if (!tmpbuf)
234           return NULL;
235         silc_buffer_format(tmpbuf,
236                            SILC_STR_UI_SHORT(len),
237                            SILC_STR_UI16_STRING(pk->type),
238                            SILC_STR_UI_XNSTRING(pk->data, pk->data_len),
239                            SILC_STR_END);
240         object = tmpbuf->data;
241         object_size = silc_buffer_len(tmpbuf);
242       }
243       break;
244
245     case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
246     case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
247       {
248         SilcAttributeObjPk *pk = object;
249         if (object_size != sizeof(*pk))
250           return NULL;
251         object = pk->data;
252         object_size = pk->data_len;
253       }
254       break;
255
256     default:
257       return NULL;
258       break;
259     }
260
261     ret = silc_memdup(object, object_size);
262
263     if (tmpbuf)
264       silc_buffer_free(tmpbuf);
265     silc_free(str);
266
267     if (ret_len)
268       *ret_len = object_size;
269
270     return ret;
271   }
272
273   return NULL;
274 }
275
276 /* Allocates attribute payload and encodes the attribute there */
277
278 SilcAttributePayload silc_attribute_payload_alloc(SilcAttribute attribute,
279                                                   SilcAttributeFlags flags,
280                                                   void *object,
281                                                   SilcUInt32 object_size)
282 {
283   SilcAttributePayload attr;
284   SilcUInt32 tmp_len;
285
286   attr = silc_calloc(1, sizeof(*attr));
287   if (!attr)
288     return NULL;
289
290   attr->attribute = attribute;
291   attr->flags = flags;
292   attr->data =
293     silc_attribute_payload_encode_int(attribute, flags, object,
294                                       object_size, &tmp_len);
295   if (!attr->data) {
296     silc_free(attr);
297     return NULL;
298   }
299   attr->data_len = (SilcUInt16)tmp_len;
300
301   return attr;
302 }
303
304 /* Parse list of payloads */
305
306 SilcDList silc_attribute_payload_parse(const unsigned char *payload,
307                                        SilcUInt32 payload_len)
308 {
309   SilcBufferStruct buffer;
310   SilcDList list;
311   SilcAttributePayload newp;
312   SilcUInt32 len;
313   int ret;
314
315   SILC_LOG_DEBUG(("Parsing Attribute Payload list"));
316
317   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
318   list = silc_dlist_init();
319
320   while (silc_buffer_len(&buffer)) {
321     newp = silc_calloc(1, sizeof(*newp));
322     if (!newp)
323       goto err;
324     ret = silc_buffer_unformat(&buffer,
325                                SILC_STR_UI_CHAR(&newp->attribute),
326                                SILC_STR_UI_CHAR(&newp->flags),
327                                SILC_STR_UI16_NSTRING_ALLOC(&newp->data,
328                                                            &newp->data_len),
329                                SILC_STR_END);
330     if (ret == -1)
331       goto err;
332
333     if (newp->data_len > silc_buffer_len(&buffer) - 4) {
334       SILC_LOG_ERROR(("Incorrect attribute payload in list"));
335       goto err;
336     }
337
338     len = 4 + newp->data_len;
339     if (silc_buffer_len(&buffer) < len)
340       break;
341     silc_buffer_pull(&buffer, len);
342
343     silc_dlist_add(list, newp);
344   }
345
346   return list;
347
348  err:
349   silc_attribute_payload_list_free(list);
350   return NULL;
351 }
352
353 /* Encode one attribute payload to buffer */
354
355 SilcBuffer silc_attribute_payload_encode(SilcBuffer attrs,
356                                          SilcAttribute attribute,
357                                          SilcAttributeFlags flags,
358                                          void *object,
359                                          SilcUInt32 object_size)
360 {
361   object = silc_attribute_payload_encode_int(attribute, flags, object,
362                                              object_size, &object_size);
363   attrs = silc_attribute_payload_encode_data(attrs, attribute, flags,
364                                              (const unsigned char *)object,
365                                              object_size);
366   silc_free(object);
367   return attrs;
368 }
369
370 /* Encoded the attribute data directly to buffer */
371
372 SilcBuffer silc_attribute_payload_encode_data(SilcBuffer attrs,
373                                               SilcAttribute attribute,
374                                               SilcAttributeFlags flags,
375                                               const unsigned char *data,
376                                               SilcUInt32 data_len)
377 {
378   SilcBuffer buffer = attrs;
379   SilcUInt32 len;
380
381   len = 4 + (SilcUInt16)data_len;
382   buffer = silc_buffer_realloc(buffer,
383                                (buffer ? silc_buffer_truelen(buffer) +
384                                 len : len));
385   if (!buffer)
386     return NULL;
387   silc_buffer_pull(buffer, silc_buffer_len(buffer));
388   silc_buffer_pull_tail(buffer, len);
389   silc_buffer_format(buffer,
390                      SILC_STR_UI_CHAR(attribute),
391                      SILC_STR_UI_CHAR(flags),
392                      SILC_STR_UI_SHORT((SilcUInt16)data_len),
393                      SILC_STR_UI_XNSTRING(data, (SilcUInt16)data_len),
394                      SILC_STR_END);
395   silc_buffer_push(buffer, buffer->data - buffer->head);
396
397   return buffer;
398 }
399
400 /* Free Attribute Payload */
401
402 void silc_attribute_payload_free(SilcAttributePayload payload)
403 {
404   silc_free(payload->data);
405   silc_free(payload);
406 }
407
408 /* Free's list of Attribute Payloads */
409
410 void silc_attribute_payload_list_free(SilcDList list)
411 {
412   SilcAttributePayload entry;
413
414   silc_dlist_start(list);
415   while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
416     silc_attribute_payload_free(entry);
417     silc_dlist_del(list, entry);
418   }
419
420   silc_dlist_uninit(list);
421 }
422
423 /* Return attribute type */
424
425 SilcAttribute silc_attribute_get_attribute(SilcAttributePayload payload)
426 {
427   return payload->attribute;
428 }
429
430 /* Return attribute flags */
431
432 SilcAttributeFlags silc_attribute_get_flags(SilcAttributePayload payload)
433 {
434   return payload->flags;
435 }
436
437 /* Return attribute data from the payload */
438
439 const unsigned char *silc_attribute_get_data(SilcAttributePayload payload,
440                                              SilcUInt32 *data_len)
441 {
442   if (data_len)
443     *data_len = (SilcUInt32)payload->data_len;
444   return (const unsigned char *)payload->data;
445 }
446
447 /* Construct digital signature verification data */
448
449 unsigned char *silc_attribute_get_verify_data(SilcDList attrs,
450                                               SilcBool server_verification,
451                                               SilcUInt32 *data_len)
452 {
453   SilcAttributePayload attr;
454   SilcBufferStruct buffer;
455   unsigned char *data = NULL;
456   SilcUInt32 len = 0;
457
458   silc_dlist_start(attrs);
459   while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
460     switch (attr->attribute) {
461     case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
462       /* Server signature is never part of the verification data */
463       break;
464
465     case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
466       /* For user signature verification this is not part of the data */
467       if (!server_verification)
468         break;
469
470       /* Fallback, for server signature verification, user digital signature
471          is part of verification data. */
472
473     default:
474       /* All other data is part of the verification data */
475       data = silc_realloc(data, sizeof(*data) * (4 + attr->data_len + len));
476       if (!data)
477         return NULL;
478       silc_buffer_set(&buffer, data + len, 4 + attr->data_len);
479       silc_buffer_format(&buffer,
480                          SILC_STR_UI_CHAR(attr->attribute),
481                          SILC_STR_UI_CHAR(attr->flags),
482                          SILC_STR_UI_SHORT(attr->data_len),
483                          SILC_STR_UI_XNSTRING(attr->data, attr->data_len),
484                          SILC_STR_END);
485       len += 4 + attr->data_len;
486       break;
487     }
488   }
489
490   if (data_len)
491     *data_len = len;
492
493   return data;
494 }
495
496 /* Return parsed attribute object */
497
498 SilcBool silc_attribute_get_object(SilcAttributePayload payload,
499                                    void *object, SilcUInt32 object_size)
500 {
501   SilcUInt16 len;
502   SilcBool ret = FALSE;
503
504   if (!object || payload->flags & SILC_ATTRIBUTE_FLAG_INVALID)
505     return FALSE;
506
507   switch (payload->attribute) {
508   case SILC_ATTRIBUTE_USER_INFO:
509     {
510 #ifdef SILC_DIST_VCARD
511       SilcVCard vcard = object;
512       if (object_size != sizeof(*vcard))
513         break;
514       if (!silc_vcard_decode(payload->data, payload->data_len, vcard))
515         break;
516       ret = TRUE;
517 #endif /* SILC_DIST_VCARD */
518     }
519     break;
520
521   case SILC_ATTRIBUTE_SERVICE:
522     {
523       SilcAttributeObjService *service = object;
524       SilcBufferStruct buf;
525       SilcUInt16 addr_len, signon_len;
526       char *addr, *signon;
527       int res;
528       if (object_size != sizeof(*service))
529         break;
530       if (payload->data_len < 13)
531         break;
532       silc_buffer_set(&buf, payload->data, payload->data_len);
533       res = silc_buffer_unformat(&buf,
534                                  SILC_STR_UI_INT(&service->port),
535                                  SILC_STR_UI16_NSTRING(&addr, &addr_len),
536                                  SILC_STR_UI_CHAR(&service->status),
537                                  SILC_STR_UI16_NSTRING(&signon, &signon_len),
538                                  SILC_STR_UI_INT(&service->idle),
539                                  SILC_STR_END);
540       if (res == -1)
541         break;
542       memset(service->address, 0, sizeof(service->address));
543       memset(service->signon, 0, sizeof(service->signon));
544       memcpy(service->address, addr,
545              (addr_len < sizeof(service->address) - 1 ? addr_len :
546               sizeof(service->address) - 1));
547       memcpy(service->signon, signon,
548              (signon_len < sizeof(service->signon) - 1 ? signon_len :
549               sizeof(service->signon) - 1));
550       ret = TRUE;
551     }
552     break;
553
554   case SILC_ATTRIBUTE_STATUS_MOOD:
555   case SILC_ATTRIBUTE_PREFERRED_CONTACT:
556     {
557       SilcUInt32 *mask = (SilcUInt32 *)object;
558       if (object_size != sizeof(SilcUInt32))
559         break;
560       if (payload->data_len < 4)
561         break;
562       SILC_GET32_MSB(*mask, payload->data);
563       ret = TRUE;
564     }
565     break;
566
567   case SILC_ATTRIBUTE_STATUS_FREETEXT:
568   case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
569   case SILC_ATTRIBUTE_TIMEZONE:
570     {
571       char *string = object;
572       if (payload->data_len < 2)
573         break;
574       SILC_GET16_MSB(len, payload->data);
575       if (payload->data_len < 2 + len)
576         break;
577       if (object_size < len)
578         break;
579       memcpy(string, payload->data + 2, len);
580       ret = TRUE;
581     }
582     break;
583
584   case SILC_ATTRIBUTE_STATUS_MESSAGE:
585   case SILC_ATTRIBUTE_EXTENSION:
586   case SILC_ATTRIBUTE_USER_ICON:
587     {
588       SilcMime mime = object;
589       if (object_size != sizeof(*mime))
590         break;
591       if (!silc_mime_decode(mime, payload->data, payload->data_len))
592         break;
593       ret = TRUE;
594     }
595     break;
596
597   case SILC_ATTRIBUTE_GEOLOCATION:
598     {
599       SilcAttributeObjGeo *geo = object;
600       SilcBufferStruct buffer;
601       int res;
602       if (object_size != sizeof(*geo))
603         break;
604       silc_buffer_set(&buffer, (unsigned char *)payload->data,
605                       payload->data_len);
606       res = silc_buffer_unformat(&buffer,
607                                  SILC_STR_UI16_STRING_ALLOC(&geo->longitude),
608                                  SILC_STR_UI16_STRING_ALLOC(&geo->latitude),
609                                  SILC_STR_UI16_STRING_ALLOC(&geo->altitude),
610                                  SILC_STR_UI16_STRING_ALLOC(&geo->accuracy),
611                                  SILC_STR_END);
612       if (res == -1)
613         break;
614       ret = TRUE;
615     }
616     break;
617
618   case SILC_ATTRIBUTE_DEVICE_INFO:
619     {
620       SilcAttributeObjDevice *dev = object;
621       SilcBufferStruct buffer;
622       SilcUInt32 type;
623       int res;
624       if (object_size != sizeof(*dev))
625         break;
626       silc_buffer_set(&buffer, (unsigned char *)payload->data,
627                       payload->data_len);
628       res =
629         silc_buffer_unformat(&buffer,
630                              SILC_STR_UI_INT(&type),
631                              SILC_STR_UI16_STRING_ALLOC(&dev->manufacturer),
632                              SILC_STR_UI16_STRING_ALLOC(&dev->version),
633                              SILC_STR_UI16_STRING_ALLOC(&dev->model),
634                              SILC_STR_UI16_STRING_ALLOC(&dev->language),
635                              SILC_STR_END);
636       if (res == -1)
637         break;
638       dev->type = type;
639       ret = TRUE;
640     }
641     break;
642
643   case SILC_ATTRIBUTE_PHONE_NUMBER:
644     {
645       SilcAttributeObjPN *pn = object;
646       SilcBufferStruct buffer;
647       SilcUInt32 pn_format;
648       int res;
649       if (object_size != sizeof(*pn))
650         break;
651       silc_buffer_set(&buffer, (unsigned char *)payload->data,
652                       payload->data_len);
653       res =
654         silc_buffer_unformat(&buffer,
655                              SILC_STR_UI_INT(&pn_format),
656                              SILC_STR_UI16_STRING_ALLOC(&pn->number),
657                              SILC_STR_END);
658       if (res == -1)
659         break;
660       pn->format = pn_format;
661       ret = TRUE;
662     }
663     break;
664
665   case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
666   case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
667     {
668       SilcAttributeObjPk *pk = object;
669       SilcBufferStruct buffer;
670       int res;
671       if (object_size != sizeof(*pk))
672         break;
673       silc_buffer_set(&buffer, (unsigned char *)payload->data,
674                       payload->data_len);
675       res =
676         silc_buffer_unformat(&buffer,
677                              SILC_STR_UI16_NSTRING_ALLOC(&pk->type, &len),
678                              SILC_STR_END);
679       if (res == -1 || len > silc_buffer_len(&buffer) - 2)
680         break;
681       pk->data = silc_memdup(payload->data + 2 + len,
682                              payload->data_len - 2 - len);
683       pk->data_len = payload->data_len - 2 - len;
684       ret = TRUE;
685     }
686     break;
687
688   case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
689   case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
690     {
691       SilcAttributeObjPk *pk = object;
692       if (object_size != sizeof(*pk))
693         break;
694       pk->type = NULL;
695       pk->data = silc_memdup(payload->data, payload->data_len);
696       pk->data_len = payload->data_len;
697       ret = TRUE;
698     }
699     break;
700
701   default:
702     break;
703   }
704
705   return ret;
706 }