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