Code

Merge branch 'libvirt-interfacenumber'
[collectd.git] / src / libcollectdclient / network_buffer.c
1 /**
2  * collectd - src/libcollectdclient/network_buffer.c
3  * Copyright (C) 2010-2012  Florian octo Forster
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *   Florian octo Forster <octo at collectd.org>
25  **/
27 #include "config.h"
29 #include <stdlib.h>
30 #include <string.h>
31 #include <math.h>
32 #include <assert.h>
33 #include <errno.h>
34 #include <arpa/inet.h> /* htons */
36 #include <pthread.h>
38 #if HAVE_LIBGCRYPT
39 #include <gcrypt.h>
40 GCRY_THREAD_OPTION_PTHREAD_IMPL;
41 #endif
43 #include "collectd/network_buffer.h"
45 #define TYPE_HOST            0x0000
46 #define TYPE_TIME            0x0001
47 #define TYPE_PLUGIN          0x0002
48 #define TYPE_PLUGIN_INSTANCE 0x0003
49 #define TYPE_TYPE            0x0004
50 #define TYPE_TYPE_INSTANCE   0x0005
51 #define TYPE_VALUES          0x0006
52 #define TYPE_INTERVAL        0x0007
54 /* Types to transmit notifications */
55 #define TYPE_MESSAGE         0x0100
56 #define TYPE_SEVERITY        0x0101
58 #define TYPE_SIGN_SHA256     0x0200
59 #define TYPE_ENCR_AES256     0x0210
61 #define PART_SIGNATURE_SHA256_SIZE 36
62 #define PART_ENCRYPTION_AES256_SIZE 42
64 #define ADD_GENERIC(nb,srcptr,size) do {         \
65   assert ((size) <= (nb)->free);                 \
66   memcpy ((nb)->ptr, (srcptr), (size));          \
67   (nb)->ptr += (size);                           \
68   (nb)->free -= (size);                          \
69 } while (0)
71 #define ADD_STATIC(nb,var) \
72   ADD_GENERIC(nb,&(var),sizeof(var));
74 /*
75  * Data types
76  */
77 struct lcc_network_buffer_s
78 {
79   char *buffer;
80   size_t size;
82   lcc_value_list_t state;
83   char *ptr;
84   size_t free;
86   lcc_security_level_t seclevel;
87   char *username;
88   char *password;
90   gcry_cipher_hd_t encr_cypher;
91   size_t encr_header_len;
92   char encr_iv[16];
93 };
95 #define SSTRNCPY(dst,src,sz) do { \
96   strncpy ((dst), (src), (sz));   \
97   (dst)[(sz) - 1] = 0;            \
98 } while (0)
100 /*
101  * Private functions
102  */
103 static _Bool have_gcrypt (void) /* {{{ */
105   static _Bool result = 0;
106   static _Bool need_init = 1;
108   if (!need_init)
109     return (result);
110   need_init = 0;
112   gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
114   if (!gcry_check_version (GCRYPT_VERSION))
115     return (0);
117   gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
118   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
120   result = 1;
121   return (1);
122 } /* }}} _Bool have_gcrypt */
124 static uint64_t htonll (uint64_t val) /* {{{ */
126   static int config = 0;
128   uint32_t hi;
129   uint32_t lo;
131   if (config == 0)
132   {
133     uint16_t h = 0x1234;
134     uint16_t n = htons (h);
136     if (h == n)
137       config = 1;
138     else
139       config = 2;
140   }
142   if (config == 1)
143     return (val);
145   hi = (uint32_t) (val >> 32);
146   lo = (uint32_t) (val & 0x00000000FFFFFFFF);
148   hi = htonl (hi);
149   lo = htonl (lo);
151   return ((((uint64_t) lo) << 32) | ((uint64_t) hi));
152 } /* }}} uint64_t htonll */
154 static double htond (double val) /* {{{ */
156   static int config = 0;
158   union { uint8_t byte[8]; double floating; } in;
159   union { uint8_t byte[8]; double floating; } out;
161   if (config == 0)
162   {
163     double d = 8.642135e130;
164     uint8_t c[8];
166     memcpy (c, &d, 8);
168     if ((c[0] == 0x2f) && (c[1] == 0x25)
169         && (c[2] == 0xc0) && (c[3] == 0xc7)
170         && (c[4] == 0x43) && (c[5] == 0x2b)
171         && (c[6] == 0x1f) && (c[7] == 0x5b))
172       config = 1; /* need nothing */
173     else if ((c[7] == 0x2f) && (c[6] == 0x25)
174         && (c[5] == 0xc0) && (c[4] == 0xc7)
175         && (c[3] == 0x43) && (c[2] == 0x2b)
176         && (c[1] == 0x1f) && (c[0] == 0x5b))
177       config = 2; /* endian flip */
178     else if ((c[4] == 0x2f) && (c[5] == 0x25)
179         && (c[6] == 0xc0) && (c[7] == 0xc7)
180         && (c[0] == 0x43) && (c[1] == 0x2b)
181         && (c[2] == 0x1f) && (c[3] == 0x5b))
182       config = 3; /* int swap */
183     else
184       config = 4;
185   }
187   if (isnan (val))
188   {
189     out.byte[0] = out.byte[1] = out.byte[2] = out.byte[3] = 0x00;
190     out.byte[4] = out.byte[5] = 0x00;
191     out.byte[6] = 0xf8;
192     out.byte[7] = 0x7f;
193     return (out.floating);
194   }
195   else if (config == 1)
196     return (val);
197   else if (config == 2)
198   {
199     in.floating = val;
200     out.byte[0] = in.byte[7];
201     out.byte[1] = in.byte[6];
202     out.byte[2] = in.byte[5];
203     out.byte[3] = in.byte[4];
204     out.byte[4] = in.byte[3];
205     out.byte[5] = in.byte[2];
206     out.byte[6] = in.byte[1];
207     out.byte[7] = in.byte[0];
208     return (out.floating);
209   }
210   else if (config == 3)
211   {
212     in.floating = val;
213     out.byte[0] = in.byte[4];
214     out.byte[1] = in.byte[5];
215     out.byte[2] = in.byte[6];
216     out.byte[3] = in.byte[7];
217     out.byte[4] = in.byte[0];
218     out.byte[5] = in.byte[1];
219     out.byte[6] = in.byte[2];
220     out.byte[7] = in.byte[3];
221     return (out.floating);
222   }
223   else
224   {
225     /* If in doubt, just copy the value back to the caller. */
226     return (val);
227   }
228 } /* }}} double htond */
230 static int nb_add_values (char **ret_buffer, /* {{{ */
231     size_t *ret_buffer_len,
232     const lcc_value_list_t *vl)
234   char *packet_ptr;
235   size_t packet_len;
237   uint16_t      pkg_type;
238   uint16_t      pkg_length;
239   uint16_t      pkg_num_values;
240   uint8_t       pkg_values_types[vl->values_len];
241   value_t       pkg_values[vl->values_len];
243   size_t offset;
244   size_t i;
246   packet_len = sizeof (pkg_type) + sizeof (pkg_length)
247     + sizeof (pkg_num_values)
248     + sizeof (pkg_values_types)
249     + sizeof (pkg_values);
251   if (*ret_buffer_len < packet_len)
252     return (ENOMEM);
254   pkg_type = htons (TYPE_VALUES);
255   pkg_length = htons ((uint16_t) packet_len);
256   pkg_num_values = htons ((uint16_t) vl->values_len);
258   for (i = 0; i < vl->values_len; i++)
259   {
260     pkg_values_types[i] = (uint8_t) vl->values_types[i];
261     switch (vl->values_types[i])
262     {
263       case LCC_TYPE_COUNTER:
264         pkg_values[i].counter = (counter_t) htonll (vl->values[i].counter);
265         break;
267       case LCC_TYPE_GAUGE:
268         pkg_values[i].gauge = (gauge_t) htond (vl->values[i].gauge);
269         break;
271       case LCC_TYPE_DERIVE:
272         pkg_values[i].derive = (derive_t) htonll (vl->values[i].derive);
273         break;
275       case LCC_TYPE_ABSOLUTE:
276         pkg_values[i].absolute = (absolute_t) htonll (vl->values[i].absolute);
277         break;
279       default:
280         return (EINVAL);
281     } /* switch (vl->values_types[i]) */
282   } /* for (vl->values_len) */
284   /*
285    * Use `memcpy' to write everything to the buffer, because the pointer
286    * may be unaligned and some architectures, such as SPARC, can't handle
287    * that.
288    */
289   packet_ptr = *ret_buffer;
290   offset = 0;
291   memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
292   offset += sizeof (pkg_type);
293   memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
294   offset += sizeof (pkg_length);
295   memcpy (packet_ptr + offset, &pkg_num_values, sizeof (pkg_num_values));
296   offset += sizeof (pkg_num_values);
297   memcpy (packet_ptr + offset, pkg_values_types, sizeof (pkg_values_types));
298   offset += sizeof (pkg_values_types);
299   memcpy (packet_ptr + offset, pkg_values, sizeof (pkg_values));
300   offset += sizeof (pkg_values);
302   assert (offset == packet_len);
304   *ret_buffer = packet_ptr + packet_len;
305   *ret_buffer_len -= packet_len;
306   return (0);
307 } /* }}} int nb_add_values */
309 static int nb_add_number (char **ret_buffer, /* {{{ */
310     size_t *ret_buffer_len,
311     uint16_t type, uint64_t value)
313   char *packet_ptr;
314   size_t packet_len;
316   uint16_t pkg_type;
317   uint16_t pkg_length;
318   uint64_t pkg_value;
320   size_t offset;
322   packet_len = sizeof (pkg_type)
323     + sizeof (pkg_length)
324     + sizeof (pkg_value);
326   if (*ret_buffer_len < packet_len)
327     return (ENOMEM);
329   pkg_type = htons (type);
330   pkg_length = htons ((uint16_t) packet_len);
331   pkg_value = htonll (value);
333   packet_ptr = *ret_buffer;
334   offset = 0;
335   memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
336   offset += sizeof (pkg_type);
337   memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
338   offset += sizeof (pkg_length);
339   memcpy (packet_ptr + offset, &pkg_value, sizeof (pkg_value));
340   offset += sizeof (pkg_value);
342   assert (offset == packet_len);
344   *ret_buffer = packet_ptr + packet_len;
345   *ret_buffer_len -= packet_len;
346   return (0);
347 } /* }}} int nb_add_number */
349 static int nb_add_string (char **ret_buffer, /* {{{ */
350     size_t *ret_buffer_len,
351     uint16_t type, const char *str, size_t str_len)
353   char *packet_ptr;
354   size_t packet_len;
356   uint16_t pkg_type;
357   uint16_t pkg_length;
359   size_t offset;
361   packet_len = sizeof (pkg_type)
362     + sizeof (pkg_length)
363     + str_len + 1;
364   if (*ret_buffer_len < packet_len)
365     return (ENOMEM);
367   pkg_type = htons (type);
368   pkg_length = htons ((uint16_t) packet_len);
370   packet_ptr = *ret_buffer;
371   offset = 0;
372   memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
373   offset += sizeof (pkg_type);
374   memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
375   offset += sizeof (pkg_length);
376   memcpy (packet_ptr + offset, str, str_len);
377   offset += str_len;
378   memset (packet_ptr + offset, 0, 1);
379   offset += 1;
381   assert (offset == packet_len);
383   *ret_buffer = packet_ptr + packet_len;
384   *ret_buffer_len -= packet_len;
385   return (0);
386 } /* }}} int nb_add_string */
388 static int nb_add_value_list (lcc_network_buffer_t *nb, /* {{{ */
389     const lcc_value_list_t *vl)
391   char *buffer = nb->ptr;
392   size_t buffer_size = nb->free;
394   const lcc_identifier_t *ident_src;
395   lcc_identifier_t *ident_dst;
397   ident_src = &vl->identifier;
398   ident_dst = &nb->state.identifier;
400   if (strcmp (ident_dst->host, ident_src->host) != 0)
401   {
402     if (nb_add_string (&buffer, &buffer_size, TYPE_HOST,
403           ident_src->host, strlen (ident_src->host)) != 0)
404       return (-1);
405     SSTRNCPY (ident_dst->host, ident_src->host, sizeof (ident_dst->host));
406   }
408   if (strcmp (ident_dst->plugin, ident_src->plugin) != 0)
409   {
410     if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN,
411           ident_src->plugin, strlen (ident_src->plugin)) != 0)
412       return (-1);
413     SSTRNCPY (ident_dst->plugin, ident_src->plugin,
414         sizeof (ident_dst->plugin));
415   }
417   if (strcmp (ident_dst->plugin_instance,
418         ident_src->plugin_instance) != 0)
419   {
420     if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN_INSTANCE,
421           ident_src->plugin_instance,
422           strlen (ident_src->plugin_instance)) != 0)
423       return (-1);
424     SSTRNCPY (ident_dst->plugin_instance, ident_src->plugin_instance,
425         sizeof (ident_dst->plugin_instance));
426   }
428   if (strcmp (ident_dst->type, ident_src->type) != 0)
429   {
430     if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE,
431           ident_src->type, strlen (ident_src->type)) != 0)
432       return (-1);
433     SSTRNCPY (ident_dst->type, ident_src->type, sizeof (ident_dst->type));
434   }
436   if (strcmp (ident_dst->type_instance,
437         ident_src->type_instance) != 0)
438   {
439     if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE_INSTANCE,
440           ident_src->type_instance,
441           strlen (ident_src->type_instance)) != 0)
442       return (-1);
443     SSTRNCPY (ident_dst->type_instance, ident_src->type_instance,
444         sizeof (ident_dst->type_instance));
445   }
447   if (nb->state.time != vl->time)
448   {
449     if (nb_add_number (&buffer, &buffer_size, TYPE_TIME,
450           (uint64_t) vl->time))
451       return (-1);
452     nb->state.time = vl->time;
453   }
455   if (nb->state.interval != vl->interval)
456   {
457     if (nb_add_number (&buffer, &buffer_size, TYPE_INTERVAL,
458           (uint64_t) vl->interval))
459       return (-1);
460     nb->state.interval = vl->interval;
461   }
463   if (nb_add_values (&buffer, &buffer_size, vl) != 0)
464     return (-1);
466   nb->ptr = buffer;
467   nb->free = buffer_size;
468   return (0);
469 } /* }}} int nb_add_value_list */
471 static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */
473   char *buffer;
474   size_t buffer_size;
476   gcry_md_hd_t hd;
477   gcry_error_t err;
478   unsigned char *hash;
479   const size_t hash_length = 32;
481   /* The type, length and username have already been filled in by
482    * "lcc_network_buffer_initialize". All we do here is calculate the hash over
483    * the username and the data and add the hash value to the buffer. */
485   buffer = nb->buffer + PART_SIGNATURE_SHA256_SIZE;
486   assert (nb->size >= (nb->free + PART_SIGNATURE_SHA256_SIZE));
487   buffer_size = nb->size - (nb->free + PART_SIGNATURE_SHA256_SIZE);
489   hd = NULL;
490   err = gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
491   if (err != 0)
492     return (-1);
494   assert (nb->password != NULL);
495   err = gcry_md_setkey (hd, nb->password, strlen (nb->password));
496   if (err != 0)
497   {
498     gcry_md_close (hd);
499     return (-1);
500   }
502   gcry_md_write (hd, buffer, buffer_size);
503   hash = gcry_md_read (hd, GCRY_MD_SHA256);
504   if (hash == NULL)
505   {
506     gcry_md_close (hd);
507     return (-1);
508   }
510   assert (((2 * sizeof (uint16_t)) + hash_length) == PART_SIGNATURE_SHA256_SIZE);
511   memcpy (nb->buffer + (2 * sizeof (uint16_t)), hash, hash_length);
513   gcry_md_close (hd);
514   return (0);
515 } /* }}} int nb_add_signature */
517 static int nb_add_encryption (lcc_network_buffer_t *nb) /* {{{ */
519   size_t package_length;
520   char *encr_ptr; /* pointer to data being encrypted */
521   size_t encr_size;
523   char *hash_ptr; /* pointer to data being hashed */
524   size_t hash_size;
525   char hash[20];
527   uint16_t pkg_length;
528   gcry_error_t err;
530   /* Fill in the package length */
531   package_length = nb->size - nb->free;
532   pkg_length = htons ((uint16_t) package_length);
533   memcpy (nb->buffer + 2, &pkg_length, sizeof (pkg_length));
535   /* Calculate what to hash */
536   hash_ptr = nb->buffer + PART_ENCRYPTION_AES256_SIZE;
537   hash_size = package_length - nb->encr_header_len;
539   /* Calculate what to encrypt */
540   encr_ptr = hash_ptr - sizeof (hash);
541   encr_size = hash_size + sizeof (hash);
543   /* Calculate the SHA-1 hash */
544   gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash_ptr, hash_size);
545   memcpy (encr_ptr, hash, sizeof (hash));
547   if (nb->encr_cypher == NULL)
548   {
549     unsigned char password_hash[32];
551     err = gcry_cipher_open (&nb->encr_cypher,
552         GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, /* flags = */ 0);
553     if (err != 0)
554       return (-1);
556     /* Calculate our 256bit key used for AES */
557     gcry_md_hash_buffer (GCRY_MD_SHA256, password_hash,
558         nb->password, strlen (nb->password));
560     err = gcry_cipher_setkey (nb->encr_cypher,
561         password_hash, sizeof (password_hash));
562     if (err != 0)
563     {
564       gcry_cipher_close (nb->encr_cypher);
565       nb->encr_cypher = NULL;
566       return (-1);
567     }
568   }
569   else /* if (nb->encr_cypher != NULL) */
570   {
571     gcry_cipher_reset (nb->encr_cypher);
572   }
574   /* Set the initialization vector */
575   err = gcry_cipher_setiv (nb->encr_cypher,
576       nb->encr_iv, sizeof (nb->encr_iv));
577   if (err != 0)
578   {
579     gcry_cipher_close (nb->encr_cypher);
580     nb->encr_cypher = NULL;
581     return (-1);
582   }
584   /* Encrypt the buffer in-place */
585   err = gcry_cipher_encrypt (nb->encr_cypher,
586       encr_ptr, encr_size,
587       /* in = */ NULL, /* in len = */ 0);
588   if (err != 0)
589   {
590     gcry_cipher_close (nb->encr_cypher);
591     nb->encr_cypher = NULL;
592     return (-1);
593   }
595   return (0);
596 } /* }}} int nb_add_encryption */
598 /*
599  * Public functions
600  */
601 lcc_network_buffer_t *lcc_network_buffer_create (size_t size) /* {{{ */
603   lcc_network_buffer_t *nb;
605   if (size == 0)
606     size = LCC_NETWORK_BUFFER_SIZE_DEFAULT;
608   if (size < 128)
609   {
610     errno = EINVAL;
611     return (NULL);
612   }
614   nb = malloc (sizeof (*nb));
615   if (nb == NULL)
616     return (NULL);
617   memset (nb, 0, sizeof (*nb));
619   nb->size = size;
620   nb->buffer = malloc (nb->size);
621   if (nb->buffer == NULL)
622   {
623     free (nb);
624     return (NULL);
625   }
626   memset (nb->buffer, 0, nb->size);
628   nb->ptr = nb->buffer;
629   nb->free = nb->size;
631   nb->seclevel = NONE;
632   nb->username = NULL;
633   nb->password = NULL;
635   return (nb);
636 } /* }}} lcc_network_buffer_t *lcc_network_buffer_create */
638 void lcc_network_buffer_destroy (lcc_network_buffer_t *nb) /* {{{ */
640   if (nb == NULL)
641     return;
643   free (nb->buffer);
644   free (nb);
645 } /* }}} void lcc_network_buffer_destroy */
647 int lcc_network_buffer_set_security_level (lcc_network_buffer_t *nb, /* {{{ */
648     lcc_security_level_t level,
649     const char *username, const char *password)
651   char *username_copy;
652   char *password_copy;
654   if (level == NONE)
655   {
656     free (nb->username);
657     free (nb->password);
658     nb->username = NULL;
659     nb->password = NULL;
660     nb->seclevel = NONE;
661     lcc_network_buffer_initialize (nb);
662     return (0);
663   }
665   if (!have_gcrypt ())
666     return (ENOTSUP);
668   username_copy = strdup (username);
669   password_copy = strdup (password);
670   if ((username_copy == NULL) || (password_copy == NULL))
671   {
672     free (username_copy);
673     free (password_copy);
674     return (ENOMEM);
675   }
677   free (nb->username);
678   free (nb->password);
679   nb->username = username_copy;
680   nb->password = password_copy;
681   nb->seclevel = level;
683   lcc_network_buffer_initialize (nb);
684   return (0);
685 } /* }}} int lcc_network_buffer_set_security_level */
687 int lcc_network_buffer_initialize (lcc_network_buffer_t *nb) /* {{{ */
689   if (nb == NULL)
690     return (EINVAL);
692   memset (nb->buffer, 0, nb->size);
693   memset (&nb->state, 0, sizeof (nb->state));
694   nb->ptr = nb->buffer;
695   nb->free = nb->size;
697   if (nb->seclevel == SIGN)
698   {
699     size_t username_len;
700     uint16_t pkg_type = htons (TYPE_SIGN_SHA256);
701     uint16_t pkg_length = PART_SIGNATURE_SHA256_SIZE;
703     assert (nb->username != NULL);
704     username_len = strlen (nb->username);
705     pkg_length = htons (pkg_length + ((uint16_t) username_len));
707     /* Fill in everything but the hash value here. */
708     memcpy (nb->ptr, &pkg_type, sizeof (pkg_type));
709     memcpy (nb->ptr + sizeof (pkg_type), &pkg_length, sizeof (pkg_length));
710     nb->ptr += PART_SIGNATURE_SHA256_SIZE;
711     nb->free -= PART_SIGNATURE_SHA256_SIZE;
713     memcpy (nb->ptr, nb->username, username_len);
714     nb->ptr += username_len;
715     nb->free -= username_len;
716   }
717   else if (nb->seclevel == ENCRYPT)
718   {
719     size_t username_length = strlen (nb->username);
720     uint16_t pkg_type = htons (TYPE_ENCR_AES256);
721     uint16_t pkg_length = 0; /* Filled in in finalize. */
722     uint16_t pkg_user_len = htons ((uint16_t) username_length);
723     char hash[20];
725     nb->encr_header_len = username_length;
726     nb->encr_header_len += PART_ENCRYPTION_AES256_SIZE;
728     gcry_randomize ((void *) &nb->encr_iv, sizeof (nb->encr_iv),
729         GCRY_STRONG_RANDOM);
731     /* Filled in in finalize. */
732     memset (hash, 0, sizeof (hash));
734     ADD_STATIC (nb, pkg_type);
735     ADD_STATIC (nb, pkg_length);
736     ADD_STATIC (nb, pkg_user_len);
737     ADD_GENERIC (nb, nb->username, username_length);
738     ADD_GENERIC (nb, nb->encr_iv, sizeof (nb->encr_iv));
739     ADD_GENERIC (nb, hash, sizeof (hash));
740     assert ((nb->encr_header_len + nb->free) == nb->size);
741   }
743   return (0);
744 } /* }}} int lcc_network_buffer_initialize */
746 int lcc_network_buffer_finalize (lcc_network_buffer_t *nb) /* {{{ */
748   if (nb == NULL)
749     return (EINVAL);
751   if (nb->seclevel == SIGN)
752     nb_add_signature (nb);
753   else if (nb->seclevel == ENCRYPT)
754     nb_add_encryption (nb);
756   return (0);
757 } /* }}} int lcc_network_buffer_finalize */
759 int lcc_network_buffer_add_value (lcc_network_buffer_t *nb, /* {{{ */
760     const lcc_value_list_t *vl)
762   int status;
764   if ((nb == NULL) || (vl == NULL))
765     return (EINVAL);
767   status = nb_add_value_list (nb, vl);
768   return (status);
769 } /* }}} int lcc_network_buffer_add_value */
771 int lcc_network_buffer_get (lcc_network_buffer_t *nb, /* {{{ */
772     void *buffer, size_t *buffer_size)
774   size_t sz_required;
775   size_t sz_available;
777   if ((nb == NULL) || (buffer_size == NULL))
778     return (EINVAL);
780   assert (nb->size >= nb->free);
781   sz_required = nb->size - nb->free;
782   sz_available = *buffer_size;
784   *buffer_size = sz_required;
785   if (buffer != NULL)
786     memcpy (buffer, nb->buffer,
787         (sz_available < sz_required) ? sz_available : sz_required);
789   return (0);
790 } /* }}} int lcc_network_buffer_get */
792 /* vim: set sw=2 sts=2 et fdm=marker : */