Merge branch 'ff/netlib'
[collectd.git] / src / libcollectdclient / network_buffer.c
1 /**
2  * collectd - src/libcollectdclient/network_buffer.c
3  * Copyright (C) 2010  Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation; only version 2.1 of the License is
8  * applicable.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  * Authors:
20  *   Florian octo Forster <octo at verplant.org>
21  **/
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <math.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <arpa/inet.h> /* htons */
31
32 #include <pthread.h>
33
34 #if HAVE_LIBGCRYPT
35 #include <gcrypt.h>
36 GCRY_THREAD_OPTION_PTHREAD_IMPL;
37 #endif
38
39 #include "collectd/network_buffer.h"
40
41 #define TYPE_HOST            0x0000
42 #define TYPE_TIME            0x0001
43 #define TYPE_PLUGIN          0x0002
44 #define TYPE_PLUGIN_INSTANCE 0x0003
45 #define TYPE_TYPE            0x0004
46 #define TYPE_TYPE_INSTANCE   0x0005
47 #define TYPE_VALUES          0x0006
48 #define TYPE_INTERVAL        0x0007
49
50 /* Types to transmit notifications */
51 #define TYPE_MESSAGE         0x0100
52 #define TYPE_SEVERITY        0x0101
53
54 #define TYPE_SIGN_SHA256     0x0200
55 #define TYPE_ENCR_AES256     0x0210
56
57 #define PART_SIGNATURE_SHA256_SIZE 36
58 #define PART_ENCRYPTION_AES256_SIZE 42
59
60 #define ADD_GENERIC(nb,srcptr,size) do {         \
61   assert ((size) <= (nb)->free);                 \
62   memcpy ((nb)->ptr, (srcptr), (size));          \
63   (nb)->ptr += (size);                           \
64   (nb)->free -= (size);                          \
65 } while (0)
66
67 #define ADD_STATIC(nb,var) \
68   ADD_GENERIC(nb,&(var),sizeof(var));
69
70 /*
71  * Data types
72  */
73 struct lcc_network_buffer_s
74 {
75   char *buffer;
76   size_t size;
77
78   lcc_value_list_t state;
79   char *ptr;
80   size_t free;
81
82   lcc_security_level_t seclevel;
83   char *username;
84   char *password;
85
86   gcry_cipher_hd_t encr_cypher;
87   size_t encr_header_len;
88   char encr_iv[16];
89 };
90
91 #define SSTRNCPY(dst,src,sz) do { \
92   strncpy ((dst), (src), (sz));   \
93   (dst)[(sz) - 1] = 0;            \
94 } while (0)
95
96 /*
97  * Private functions
98  */
99 static _Bool have_gcrypt (void) /* {{{ */
100 {
101   static _Bool result = 0;
102   static _Bool need_init = 1;
103
104   if (!need_init)
105     return (result);
106   need_init = 0;
107
108   gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
109
110   if (!gcry_check_version (GCRYPT_VERSION))
111     return (0);
112
113   gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
114   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
115
116   result = 1;
117   return (1);
118 } /* }}} _Bool have_gcrypt */
119
120 static uint64_t htonll (uint64_t val) /* {{{ */
121 {
122   static int config = 0;
123
124   uint32_t hi;
125   uint32_t lo;
126
127   if (config == 0)
128   {
129     uint16_t h = 0x1234;
130     uint16_t n = htons (h);
131
132     if (h == n)
133       config = 1;
134     else
135       config = 2;
136   }
137
138   if (config == 1)
139     return (val);
140
141   hi = (uint32_t) (val >> 32);
142   lo = (uint32_t) (val & 0x00000000FFFFFFFF);
143
144   hi = htonl (hi);
145   lo = htonl (lo);
146
147   return ((((uint64_t) lo) << 32) | ((uint64_t) hi));
148 } /* }}} uint64_t htonll */
149
150 static double htond (double val) /* {{{ */
151 {
152   static int config = 0;
153
154   union { uint8_t byte[8]; double floating; } in;
155   union { uint8_t byte[8]; double floating; } out;
156
157   if (config == 0)
158   {
159     double d = 8.642135e130;
160     uint8_t c[8];
161
162     memcpy (c, &d, 8);
163
164     if ((c[0] == 0x2f) && (c[1] == 0x25)
165         && (c[2] == 0xc0) && (c[3] == 0xc7)
166         && (c[4] == 0x43) && (c[5] == 0x2b)
167         && (c[6] == 0x1f) && (c[7] == 0x5b))
168       config = 1; /* need nothing */
169     else if ((c[7] == 0x2f) && (c[6] == 0x25)
170         && (c[5] == 0xc0) && (c[4] == 0xc7)
171         && (c[3] == 0x43) && (c[2] == 0x2b)
172         && (c[1] == 0x1f) && (c[0] == 0x5b))
173       config = 2; /* endian flip */
174     else if ((c[4] == 0x2f) && (c[5] == 0x25)
175         && (c[6] == 0xc0) && (c[7] == 0xc7)
176         && (c[0] == 0x43) && (c[1] == 0x2b)
177         && (c[2] == 0x1f) && (c[3] == 0x5b))
178       config = 3; /* int swap */
179     else
180       config = 4;
181   }
182
183   if (isnan (val))
184   {
185     out.byte[0] = out.byte[1] = out.byte[2] = out.byte[3] = 0x00;
186     out.byte[4] = out.byte[5] = 0x00;
187     out.byte[6] = 0xf8;
188     out.byte[7] = 0x7f;
189     return (out.floating);
190   }
191   else if (config == 1)
192     return (val);
193   else if (config == 2)
194   {
195     in.floating = val;
196     out.byte[0] = in.byte[7];
197     out.byte[1] = in.byte[6];
198     out.byte[2] = in.byte[5];
199     out.byte[3] = in.byte[4];
200     out.byte[4] = in.byte[3];
201     out.byte[5] = in.byte[2];
202     out.byte[6] = in.byte[1];
203     out.byte[7] = in.byte[0];
204     return (out.floating);
205   }
206   else if (config == 3)
207   {
208     in.floating = val;
209     out.byte[0] = in.byte[4];
210     out.byte[1] = in.byte[5];
211     out.byte[2] = in.byte[6];
212     out.byte[3] = in.byte[7];
213     out.byte[4] = in.byte[0];
214     out.byte[5] = in.byte[1];
215     out.byte[6] = in.byte[2];
216     out.byte[7] = in.byte[3];
217     return (out.floating);
218   }
219   else
220   {
221     /* If in doubt, just copy the value back to the caller. */
222     return (val);
223   }
224 } /* }}} double htond */
225
226 static int nb_add_values (char **ret_buffer, /* {{{ */
227     size_t *ret_buffer_len,
228     const lcc_value_list_t *vl)
229 {
230   char *packet_ptr;
231   size_t packet_len;
232
233   uint16_t      pkg_type;
234   uint16_t      pkg_length;
235   uint16_t      pkg_num_values;
236   uint8_t       pkg_values_types[vl->values_len];
237   value_t       pkg_values[vl->values_len];
238
239   size_t offset;
240   size_t i;
241
242   packet_len = sizeof (pkg_type) + sizeof (pkg_length)
243     + sizeof (pkg_num_values)
244     + sizeof (pkg_values_types)
245     + sizeof (pkg_values);
246
247   if (*ret_buffer_len < packet_len)
248     return (ENOMEM);
249
250   pkg_type = htons (TYPE_VALUES);
251   pkg_length = htons ((uint16_t) packet_len);
252   pkg_num_values = htons ((uint16_t) vl->values_len);
253
254   for (i = 0; i < vl->values_len; i++)
255   {
256     pkg_values_types[i] = (uint8_t) vl->values_types[i];
257     switch (vl->values_types[i])
258     {
259       case LCC_TYPE_COUNTER:
260         pkg_values[i].counter = (counter_t) htonll (vl->values[i].counter);
261         break;
262
263       case LCC_TYPE_GAUGE:
264         pkg_values[i].gauge = (gauge_t) htond (vl->values[i].gauge);
265         break;
266
267       case LCC_TYPE_DERIVE:
268         pkg_values[i].derive = (derive_t) htonll (vl->values[i].derive);
269         break;
270
271       case LCC_TYPE_ABSOLUTE:
272         pkg_values[i].absolute = (absolute_t) htonll (vl->values[i].absolute);
273         break;
274
275       default:
276         return (EINVAL);
277     } /* switch (vl->values_types[i]) */
278   } /* for (vl->values_len) */
279
280   /*
281    * Use `memcpy' to write everything to the buffer, because the pointer
282    * may be unaligned and some architectures, such as SPARC, can't handle
283    * that.
284    */
285   packet_ptr = *ret_buffer;
286   offset = 0;
287   memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
288   offset += sizeof (pkg_type);
289   memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
290   offset += sizeof (pkg_length);
291   memcpy (packet_ptr + offset, &pkg_num_values, sizeof (pkg_num_values));
292   offset += sizeof (pkg_num_values);
293   memcpy (packet_ptr + offset, pkg_values_types, sizeof (pkg_values_types));
294   offset += sizeof (pkg_values_types);
295   memcpy (packet_ptr + offset, pkg_values, sizeof (pkg_values));
296   offset += sizeof (pkg_values);
297
298   assert (offset == packet_len);
299
300   *ret_buffer = packet_ptr + packet_len;
301   *ret_buffer_len -= packet_len;
302   return (0);
303 } /* }}} int nb_add_values */
304
305 static int nb_add_number (char **ret_buffer, /* {{{ */
306     size_t *ret_buffer_len,
307     uint16_t type, uint64_t value)
308 {
309   char *packet_ptr;
310   size_t packet_len;
311
312   uint16_t pkg_type;
313   uint16_t pkg_length;
314   uint64_t pkg_value;
315
316   size_t offset;
317
318   packet_len = sizeof (pkg_type)
319     + sizeof (pkg_length)
320     + sizeof (pkg_value);
321
322   if (*ret_buffer_len < packet_len)
323     return (ENOMEM);
324
325   pkg_type = htons (type);
326   pkg_length = htons ((uint16_t) packet_len);
327   pkg_value = htonll (value);
328
329   packet_ptr = *ret_buffer;
330   offset = 0;
331   memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
332   offset += sizeof (pkg_type);
333   memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
334   offset += sizeof (pkg_length);
335   memcpy (packet_ptr + offset, &pkg_value, sizeof (pkg_value));
336   offset += sizeof (pkg_value);
337
338   assert (offset == packet_len);
339
340   *ret_buffer = packet_ptr + packet_len;
341   *ret_buffer_len -= packet_len;
342   return (0);
343 } /* }}} int nb_add_number */
344
345 static int nb_add_string (char **ret_buffer, /* {{{ */
346     size_t *ret_buffer_len,
347     uint16_t type, const char *str, size_t str_len)
348 {
349   char *packet_ptr;
350   size_t packet_len;
351
352   uint16_t pkg_type;
353   uint16_t pkg_length;
354
355   size_t offset;
356
357   packet_len = sizeof (pkg_type)
358     + sizeof (pkg_length)
359     + str_len + 1;
360   if (*ret_buffer_len < packet_len)
361     return (ENOMEM);
362
363   pkg_type = htons (type);
364   pkg_length = htons ((uint16_t) packet_len);
365
366   packet_ptr = *ret_buffer;
367   offset = 0;
368   memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
369   offset += sizeof (pkg_type);
370   memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
371   offset += sizeof (pkg_length);
372   memcpy (packet_ptr + offset, str, str_len);
373   offset += str_len;
374   memset (packet_ptr + offset, 0, 1);
375   offset += 1;
376
377   assert (offset == packet_len);
378
379   *ret_buffer = packet_ptr + packet_len;
380   *ret_buffer_len -= packet_len;
381   return (0);
382 } /* }}} int nb_add_string */
383
384 static int nb_add_value_list (lcc_network_buffer_t *nb, /* {{{ */
385     const lcc_value_list_t *vl)
386 {
387   char *buffer = nb->ptr;
388   size_t buffer_size = nb->free;
389
390   const lcc_identifier_t *ident_src;
391   lcc_identifier_t *ident_dst;
392
393   ident_src = &vl->identifier;
394   ident_dst = &nb->state.identifier;
395
396   if (strcmp (ident_dst->host, ident_src->host) != 0)
397   {
398     if (nb_add_string (&buffer, &buffer_size, TYPE_HOST,
399           ident_src->host, strlen (ident_src->host)) != 0)
400       return (-1);
401     SSTRNCPY (ident_dst->host, ident_src->host, sizeof (ident_dst->host));
402   }
403
404   if (strcmp (ident_dst->plugin, ident_src->plugin) != 0)
405   {
406     if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN,
407           ident_src->plugin, strlen (ident_src->plugin)) != 0)
408       return (-1);
409     SSTRNCPY (ident_dst->plugin, ident_src->plugin,
410         sizeof (ident_dst->plugin));
411   }
412
413   if (strcmp (ident_dst->plugin_instance,
414         ident_src->plugin_instance) != 0)
415   {
416     if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN_INSTANCE,
417           ident_src->plugin_instance,
418           strlen (ident_src->plugin_instance)) != 0)
419       return (-1);
420     SSTRNCPY (ident_dst->plugin_instance, ident_src->plugin_instance,
421         sizeof (ident_dst->plugin_instance));
422   }
423
424   if (strcmp (ident_dst->type, ident_src->type) != 0)
425   {
426     if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE,
427           ident_src->type, strlen (ident_src->type)) != 0)
428       return (-1);
429     SSTRNCPY (ident_dst->type, ident_src->type, sizeof (ident_dst->type));
430   }
431
432   if (strcmp (ident_dst->type_instance,
433         ident_src->type_instance) != 0)
434   {
435     if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE_INSTANCE,
436           ident_src->type_instance,
437           strlen (ident_src->type_instance)) != 0)
438       return (-1);
439     SSTRNCPY (ident_dst->type_instance, ident_src->type_instance,
440         sizeof (ident_dst->type_instance));
441   }
442
443   if (nb->state.time != vl->time)
444   {
445     if (nb_add_number (&buffer, &buffer_size, TYPE_TIME,
446           (uint64_t) vl->time))
447       return (-1);
448     nb->state.time = vl->time;
449   }
450
451   if (nb->state.interval != vl->interval)
452   {
453     if (nb_add_number (&buffer, &buffer_size, TYPE_INTERVAL,
454           (uint64_t) vl->interval))
455       return (-1);
456     nb->state.interval = vl->interval;
457   }
458
459   if (nb_add_values (&buffer, &buffer_size, vl) != 0)
460     return (-1);
461
462   nb->ptr = buffer;
463   nb->free = buffer_size;
464   return (0);
465 } /* }}} int nb_add_value_list */
466
467 static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */
468 {
469   char *buffer;
470   size_t buffer_size;
471
472   gcry_md_hd_t hd;
473   gcry_error_t err;
474   unsigned char *hash;
475   const size_t hash_length = 32;
476
477   /* The type, length and username have already been filled in by
478    * "lcc_network_buffer_initialize". All we do here is calculate the hash over
479    * the username and the data and add the hash value to the buffer. */
480
481   buffer = nb->buffer + PART_SIGNATURE_SHA256_SIZE;
482   assert (nb->size >= (nb->free + PART_SIGNATURE_SHA256_SIZE));
483   buffer_size = nb->size - (nb->free + PART_SIGNATURE_SHA256_SIZE);
484
485   hd = NULL;
486   err = gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
487   if (err != 0)
488     return (-1);
489
490   assert (nb->password != NULL);
491   err = gcry_md_setkey (hd, nb->password, strlen (nb->password));
492   if (err != 0)
493   {
494     gcry_md_close (hd);
495     return (-1);
496   }
497
498   gcry_md_write (hd, buffer, buffer_size);
499   hash = gcry_md_read (hd, GCRY_MD_SHA256);
500   if (hash == NULL)
501   {
502     gcry_md_close (hd);
503     return (-1);
504   }
505
506   assert (((2 * sizeof (uint16_t)) + hash_length) == PART_SIGNATURE_SHA256_SIZE);
507   memcpy (nb->buffer + (2 * sizeof (uint16_t)), hash, hash_length);
508
509   gcry_md_close (hd);
510   return (0);
511 } /* }}} int nb_add_signature */
512
513 static int nb_add_encryption (lcc_network_buffer_t *nb) /* {{{ */
514 {
515   size_t package_length;
516   char *encr_ptr; /* pointer to data being encrypted */
517   size_t encr_size;
518
519   char *hash_ptr; /* pointer to data being hashed */
520   size_t hash_size;
521   char hash[20];
522
523   uint16_t pkg_length;
524   gcry_error_t err;
525
526   /* Fill in the package length */
527   package_length = nb->size - nb->free;
528   pkg_length = htons ((uint16_t) package_length);
529   memcpy (nb->buffer + 2, &pkg_length, sizeof (pkg_length));
530
531   /* Calculate what to hash */
532   hash_ptr = nb->buffer + PART_ENCRYPTION_AES256_SIZE;
533   hash_size = package_length - nb->encr_header_len;
534
535   /* Calculate what to encrypt */
536   encr_ptr = hash_ptr - sizeof (hash);
537   encr_size = hash_size + sizeof (hash);
538
539   /* Calculate the SHA-1 hash */
540   gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash_ptr, hash_size);
541   memcpy (encr_ptr, hash, sizeof (hash));
542
543   if (nb->encr_cypher == NULL)
544   {
545     unsigned char password_hash[32];
546
547     err = gcry_cipher_open (&nb->encr_cypher,
548         GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, /* flags = */ 0);
549     if (err != 0)
550       return (-1);
551
552     /* Calculate our 256bit key used for AES */
553     gcry_md_hash_buffer (GCRY_MD_SHA256, password_hash,
554         nb->password, strlen (nb->password));
555
556     err = gcry_cipher_setkey (nb->encr_cypher,
557         password_hash, sizeof (password_hash));
558     if (err != 0)
559     {
560       gcry_cipher_close (nb->encr_cypher);
561       nb->encr_cypher = NULL;
562       return (-1);
563     }
564   }
565   else /* if (nb->encr_cypher != NULL) */
566   {
567     gcry_cipher_reset (nb->encr_cypher);
568   }
569
570   /* Set the initialization vector */
571   err = gcry_cipher_setiv (nb->encr_cypher,
572       nb->encr_iv, sizeof (nb->encr_iv));
573   if (err != 0)
574   {
575     gcry_cipher_close (nb->encr_cypher);
576     nb->encr_cypher = NULL;
577     return (-1);
578   }
579
580   /* Encrypt the buffer in-place */
581   err = gcry_cipher_encrypt (nb->encr_cypher,
582       encr_ptr, encr_size,
583       /* in = */ NULL, /* in len = */ 0);
584   if (err != 0)
585   {
586     gcry_cipher_close (nb->encr_cypher);
587     nb->encr_cypher = NULL;
588     return (-1);
589   }
590
591   return (0);
592 } /* }}} int nb_add_encryption */
593
594 /*
595  * Public functions
596  */
597 lcc_network_buffer_t *lcc_network_buffer_create (size_t size) /* {{{ */
598 {
599   lcc_network_buffer_t *nb;
600
601   if (size == 0)
602     size = LCC_NETWORK_BUFFER_SIZE_DEFAULT;
603
604   if (size < 128)
605   {
606     errno = EINVAL;
607     return (NULL);
608   }
609
610   nb = malloc (sizeof (*nb));
611   if (nb == NULL)
612     return (NULL);
613   memset (nb, 0, sizeof (*nb));
614
615   nb->size = size;
616   nb->buffer = malloc (nb->size);
617   if (nb->buffer == NULL)
618   {
619     free (nb);
620     return (NULL);
621   }
622   memset (nb->buffer, 0, nb->size);
623
624   nb->ptr = nb->buffer;
625   nb->free = nb->size;
626
627   nb->seclevel = NONE;
628   nb->username = NULL;
629   nb->password = NULL;
630
631   return (nb);
632 } /* }}} lcc_network_buffer_t *lcc_network_buffer_create */
633
634 void lcc_network_buffer_destroy (lcc_network_buffer_t *nb) /* {{{ */
635 {
636   if (nb == NULL)
637     return;
638
639   free (nb->buffer);
640   free (nb);
641 } /* }}} void lcc_network_buffer_destroy */
642
643 int lcc_network_buffer_set_security_level (lcc_network_buffer_t *nb, /* {{{ */
644     lcc_security_level_t level,
645     const char *username, const char *password)
646 {
647   char *username_copy;
648   char *password_copy;
649
650   if (level == NONE)
651   {
652     free (nb->username);
653     free (nb->password);
654     nb->username = NULL;
655     nb->password = NULL;
656     nb->seclevel = NONE;
657     lcc_network_buffer_initialize (nb);
658     return (0);
659   }
660
661   if (!have_gcrypt ())
662     return (ENOTSUP);
663
664   username_copy = strdup (username);
665   password_copy = strdup (password);
666   if ((username_copy == NULL) || (password_copy == NULL))
667   {
668     free (username_copy);
669     free (password_copy);
670     return (ENOMEM);
671   }
672
673   free (nb->username);
674   free (nb->password);
675   nb->username = username_copy;
676   nb->password = password_copy;
677   nb->seclevel = level;
678
679   lcc_network_buffer_initialize (nb);
680   return (0);
681 } /* }}} int lcc_network_buffer_set_security_level */
682
683 int lcc_network_buffer_initialize (lcc_network_buffer_t *nb) /* {{{ */
684 {
685   if (nb == NULL)
686     return (EINVAL);
687
688   memset (nb->buffer, 0, nb->size);
689   memset (&nb->state, 0, sizeof (nb->state));
690   nb->ptr = nb->buffer;
691   nb->free = nb->size;
692
693   if (nb->seclevel == SIGN)
694   {
695     size_t username_len;
696     uint16_t pkg_type = htons (TYPE_SIGN_SHA256);
697     uint16_t pkg_length = PART_SIGNATURE_SHA256_SIZE;
698
699     assert (nb->username != NULL);
700     username_len = strlen (nb->username);
701     pkg_length = htons (pkg_length + ((uint16_t) username_len));
702
703     /* Fill in everything but the hash value here. */
704     memcpy (nb->ptr, &pkg_type, sizeof (pkg_type));
705     memcpy (nb->ptr + sizeof (pkg_type), &pkg_length, sizeof (pkg_length));
706     nb->ptr += PART_SIGNATURE_SHA256_SIZE;
707     nb->free -= PART_SIGNATURE_SHA256_SIZE;
708
709     memcpy (nb->ptr, nb->username, username_len);
710     nb->ptr += username_len;
711     nb->free -= username_len;
712   }
713   else if (nb->seclevel == ENCRYPT)
714   {
715     size_t username_length = strlen (nb->username);
716     uint16_t pkg_type = htons (TYPE_ENCR_AES256);
717     uint16_t pkg_length = 0; /* Filled in in finalize. */
718     uint16_t pkg_user_len = htons ((uint16_t) username_length);
719     char hash[20];
720
721     nb->encr_header_len = username_length;
722     nb->encr_header_len += PART_ENCRYPTION_AES256_SIZE;
723
724     gcry_randomize ((void *) &nb->encr_iv, sizeof (nb->encr_iv),
725         GCRY_STRONG_RANDOM);
726
727     /* Filled in in finalize. */
728     memset (hash, 0, sizeof (hash));
729
730     ADD_STATIC (nb, pkg_type);
731     ADD_STATIC (nb, pkg_length);
732     ADD_STATIC (nb, pkg_user_len);
733     ADD_GENERIC (nb, nb->username, username_length);
734     ADD_GENERIC (nb, nb->encr_iv, sizeof (nb->encr_iv));
735     ADD_GENERIC (nb, hash, sizeof (hash));
736     assert ((nb->encr_header_len + nb->free) == nb->size);
737   }
738
739   return (0);
740 } /* }}} int lcc_network_buffer_initialize */
741
742 int lcc_network_buffer_finalize (lcc_network_buffer_t *nb) /* {{{ */
743 {
744   if (nb == NULL)
745     return (EINVAL);
746
747   if (nb->seclevel == SIGN)
748     nb_add_signature (nb);
749   else if (nb->seclevel == ENCRYPT)
750     nb_add_encryption (nb);
751
752   return (0);
753 } /* }}} int lcc_network_buffer_finalize */
754
755 int lcc_network_buffer_add_value (lcc_network_buffer_t *nb, /* {{{ */
756     const lcc_value_list_t *vl)
757 {
758   int status;
759
760   if ((nb == NULL) || (vl == NULL))
761     return (EINVAL);
762
763   status = nb_add_value_list (nb, vl);
764   return (status);
765 } /* }}} int lcc_network_buffer_add_value */
766
767 int lcc_network_buffer_get (lcc_network_buffer_t *nb, /* {{{ */
768     void *buffer, size_t *buffer_size)
769 {
770   size_t sz_required;
771   size_t sz_available;
772
773   if ((nb == NULL) || (buffer_size == NULL))
774     return (EINVAL);
775
776   assert (nb->size >= nb->free);
777   sz_required = nb->size - nb->free;
778   sz_available = *buffer_size;
779
780   *buffer_size = sz_required;
781   if (buffer != NULL)
782     memcpy (buffer, nb->buffer,
783         (sz_available < sz_required) ? sz_available : sz_required);
784
785   return (0);
786 } /* }}} int lcc_network_buffer_get */
787
788 /* vim: set sw=2 sts=2 et fdm=marker : */