Code

Merge branch 'collectd-5.1'
[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 <pthread.h>
40 # if defined __APPLE__
41 /* default xcode compiler throws warnings even when deprecated functionality
42  * is not used. -Werror breaks the build because of erroneous warnings.
43  * http://stackoverflow.com/questions/10556299/compiler-warnings-with-libgcrypt-v1-5-0/12830209#12830209
44  */
45 #  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
46 # endif
47 # include <gcrypt.h>
48 # if defined __APPLE__
49 /* Re enable deprecation warnings */
50 #  pragma GCC diagnostic warning "-Wdeprecated-declarations"
51 # endif
52 GCRY_THREAD_OPTION_PTHREAD_IMPL;
53 #endif
55 #include "collectd/network_buffer.h"
57 #define TYPE_HOST            0x0000
58 #define TYPE_TIME            0x0001
59 #define TYPE_TIME_HR         0x0008
60 #define TYPE_PLUGIN          0x0002
61 #define TYPE_PLUGIN_INSTANCE 0x0003
62 #define TYPE_TYPE            0x0004
63 #define TYPE_TYPE_INSTANCE   0x0005
64 #define TYPE_VALUES          0x0006
65 #define TYPE_INTERVAL        0x0007
66 #define TYPE_INTERVAL_HR     0x0009
68 /* Types to transmit notifications */
69 #define TYPE_MESSAGE         0x0100
70 #define TYPE_SEVERITY        0x0101
72 #define TYPE_SIGN_SHA256     0x0200
73 #define TYPE_ENCR_AES256     0x0210
75 #define PART_SIGNATURE_SHA256_SIZE 36
76 #define PART_ENCRYPTION_AES256_SIZE 42
78 #define ADD_GENERIC(nb,srcptr,size) do {         \
79   assert ((size) <= (nb)->free);                 \
80   memcpy ((nb)->ptr, (srcptr), (size));          \
81   (nb)->ptr += (size);                           \
82   (nb)->free -= (size);                          \
83 } while (0)
85 #define ADD_STATIC(nb,var) \
86   ADD_GENERIC(nb,&(var),sizeof(var));
88 /*
89  * Data types
90  */
91 struct lcc_network_buffer_s
92 {
93   char *buffer;
94   size_t size;
96   lcc_value_list_t state;
97   char *ptr;
98   size_t free;
100   lcc_security_level_t seclevel;
101   char *username;
102   char *password;
104   gcry_cipher_hd_t encr_cypher;
105   size_t encr_header_len;
106   char encr_iv[16];
107 };
109 #define SSTRNCPY(dst,src,sz) do { \
110   strncpy ((dst), (src), (sz));   \
111   (dst)[(sz) - 1] = 0;            \
112 } while (0)
114 /*
115  * Private functions
116  */
117 static _Bool have_gcrypt (void) /* {{{ */
119   static _Bool result = 0;
120   static _Bool need_init = 1;
122   if (!need_init)
123     return (result);
124   need_init = 0;
126   gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
128   if (!gcry_check_version (GCRYPT_VERSION))
129     return (0);
131   gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
132   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
134   result = 1;
135   return (1);
136 } /* }}} _Bool have_gcrypt */
138 static uint64_t htonll (uint64_t val) /* {{{ */
140   static int config = 0;
142   uint32_t hi;
143   uint32_t lo;
145   if (config == 0)
146   {
147     uint16_t h = 0x1234;
148     uint16_t n = htons (h);
150     if (h == n)
151       config = 1;
152     else
153       config = 2;
154   }
156   if (config == 1)
157     return (val);
159   hi = (uint32_t) (val >> 32);
160   lo = (uint32_t) (val & 0x00000000FFFFFFFF);
162   hi = htonl (hi);
163   lo = htonl (lo);
165   return ((((uint64_t) lo) << 32) | ((uint64_t) hi));
166 } /* }}} uint64_t htonll */
168 static double htond (double val) /* {{{ */
170   static int config = 0;
172   union { uint8_t byte[8]; double floating; } in;
173   union { uint8_t byte[8]; double floating; } out;
175   if (config == 0)
176   {
177     double d = 8.642135e130;
178     uint8_t c[8];
180     memcpy (c, &d, 8);
182     if ((c[0] == 0x2f) && (c[1] == 0x25)
183         && (c[2] == 0xc0) && (c[3] == 0xc7)
184         && (c[4] == 0x43) && (c[5] == 0x2b)
185         && (c[6] == 0x1f) && (c[7] == 0x5b))
186       config = 1; /* need nothing */
187     else if ((c[7] == 0x2f) && (c[6] == 0x25)
188         && (c[5] == 0xc0) && (c[4] == 0xc7)
189         && (c[3] == 0x43) && (c[2] == 0x2b)
190         && (c[1] == 0x1f) && (c[0] == 0x5b))
191       config = 2; /* endian flip */
192     else if ((c[4] == 0x2f) && (c[5] == 0x25)
193         && (c[6] == 0xc0) && (c[7] == 0xc7)
194         && (c[0] == 0x43) && (c[1] == 0x2b)
195         && (c[2] == 0x1f) && (c[3] == 0x5b))
196       config = 3; /* int swap */
197     else
198       config = 4;
199   }
201   if (isnan (val))
202   {
203     out.byte[0] = out.byte[1] = out.byte[2] = out.byte[3] = 0x00;
204     out.byte[4] = out.byte[5] = 0x00;
205     out.byte[6] = 0xf8;
206     out.byte[7] = 0x7f;
207     return (out.floating);
208   }
209   else if (config == 1)
210     return (val);
211   else if (config == 2)
212   {
213     in.floating = val;
214     out.byte[0] = in.byte[7];
215     out.byte[1] = in.byte[6];
216     out.byte[2] = in.byte[5];
217     out.byte[3] = in.byte[4];
218     out.byte[4] = in.byte[3];
219     out.byte[5] = in.byte[2];
220     out.byte[6] = in.byte[1];
221     out.byte[7] = in.byte[0];
222     return (out.floating);
223   }
224   else if (config == 3)
225   {
226     in.floating = val;
227     out.byte[0] = in.byte[4];
228     out.byte[1] = in.byte[5];
229     out.byte[2] = in.byte[6];
230     out.byte[3] = in.byte[7];
231     out.byte[4] = in.byte[0];
232     out.byte[5] = in.byte[1];
233     out.byte[6] = in.byte[2];
234     out.byte[7] = in.byte[3];
235     return (out.floating);
236   }
237   else
238   {
239     /* If in doubt, just copy the value back to the caller. */
240     return (val);
241   }
242 } /* }}} double htond */
244 static int nb_add_values (char **ret_buffer, /* {{{ */
245     size_t *ret_buffer_len,
246     const lcc_value_list_t *vl)
248   char *packet_ptr;
249   size_t packet_len;
251   uint16_t      pkg_type;
252   uint16_t      pkg_length;
253   uint16_t      pkg_num_values;
254   uint8_t       pkg_values_types[vl->values_len];
255   value_t       pkg_values[vl->values_len];
257   size_t offset;
258   size_t i;
260   packet_len = sizeof (pkg_type) + sizeof (pkg_length)
261     + sizeof (pkg_num_values)
262     + sizeof (pkg_values_types)
263     + sizeof (pkg_values);
265   if (*ret_buffer_len < packet_len)
266     return (ENOMEM);
268   pkg_type = htons (TYPE_VALUES);
269   pkg_length = htons ((uint16_t) packet_len);
270   pkg_num_values = htons ((uint16_t) vl->values_len);
272   for (i = 0; i < vl->values_len; i++)
273   {
274     pkg_values_types[i] = (uint8_t) vl->values_types[i];
275     switch (vl->values_types[i])
276     {
277       case LCC_TYPE_COUNTER:
278         pkg_values[i].counter = (counter_t) htonll (vl->values[i].counter);
279         break;
281       case LCC_TYPE_GAUGE:
282         pkg_values[i].gauge = (gauge_t) htond (vl->values[i].gauge);
283         break;
285       case LCC_TYPE_DERIVE:
286         pkg_values[i].derive = (derive_t) htonll (vl->values[i].derive);
287         break;
289       case LCC_TYPE_ABSOLUTE:
290         pkg_values[i].absolute = (absolute_t) htonll (vl->values[i].absolute);
291         break;
293       default:
294         return (EINVAL);
295     } /* switch (vl->values_types[i]) */
296   } /* for (vl->values_len) */
298   /*
299    * Use `memcpy' to write everything to the buffer, because the pointer
300    * may be unaligned and some architectures, such as SPARC, can't handle
301    * that.
302    */
303   packet_ptr = *ret_buffer;
304   offset = 0;
305   memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
306   offset += sizeof (pkg_type);
307   memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
308   offset += sizeof (pkg_length);
309   memcpy (packet_ptr + offset, &pkg_num_values, sizeof (pkg_num_values));
310   offset += sizeof (pkg_num_values);
311   memcpy (packet_ptr + offset, pkg_values_types, sizeof (pkg_values_types));
312   offset += sizeof (pkg_values_types);
313   memcpy (packet_ptr + offset, pkg_values, sizeof (pkg_values));
314   offset += sizeof (pkg_values);
316   assert (offset == packet_len);
318   *ret_buffer = packet_ptr + packet_len;
319   *ret_buffer_len -= packet_len;
320   return (0);
321 } /* }}} int nb_add_values */
323 static int nb_add_number (char **ret_buffer, /* {{{ */
324     size_t *ret_buffer_len,
325     uint16_t type, uint64_t value)
327   char *packet_ptr;
328   size_t packet_len;
330   uint16_t pkg_type;
331   uint16_t pkg_length;
332   uint64_t pkg_value;
334   size_t offset;
336   packet_len = sizeof (pkg_type)
337     + sizeof (pkg_length)
338     + sizeof (pkg_value);
340   if (*ret_buffer_len < packet_len)
341     return (ENOMEM);
343   pkg_type = htons (type);
344   pkg_length = htons ((uint16_t) packet_len);
345   pkg_value = htonll (value);
347   packet_ptr = *ret_buffer;
348   offset = 0;
349   memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
350   offset += sizeof (pkg_type);
351   memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
352   offset += sizeof (pkg_length);
353   memcpy (packet_ptr + offset, &pkg_value, sizeof (pkg_value));
354   offset += sizeof (pkg_value);
356   assert (offset == packet_len);
358   *ret_buffer = packet_ptr + packet_len;
359   *ret_buffer_len -= packet_len;
360   return (0);
361 } /* }}} int nb_add_number */
363 static int nb_add_time (char **ret_buffer, /* {{{ */
364     size_t *ret_buffer_len,
365     uint16_t type, double value)
367   /* Convert to collectd's "cdtime" representation. */
368   uint64_t cdtime_value = (uint64_t) (value * 1073741824.0);
369   return (nb_add_number (ret_buffer, ret_buffer_len, type, cdtime_value));
370 } /* }}} int nb_add_time */
372 static int nb_add_string (char **ret_buffer, /* {{{ */
373     size_t *ret_buffer_len,
374     uint16_t type, const char *str, size_t str_len)
376   char *packet_ptr;
377   size_t packet_len;
379   uint16_t pkg_type;
380   uint16_t pkg_length;
382   size_t offset;
384   packet_len = sizeof (pkg_type)
385     + sizeof (pkg_length)
386     + str_len + 1;
387   if (*ret_buffer_len < packet_len)
388     return (ENOMEM);
390   pkg_type = htons (type);
391   pkg_length = htons ((uint16_t) packet_len);
393   packet_ptr = *ret_buffer;
394   offset = 0;
395   memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
396   offset += sizeof (pkg_type);
397   memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
398   offset += sizeof (pkg_length);
399   memcpy (packet_ptr + offset, str, str_len);
400   offset += str_len;
401   memset (packet_ptr + offset, 0, 1);
402   offset += 1;
404   assert (offset == packet_len);
406   *ret_buffer = packet_ptr + packet_len;
407   *ret_buffer_len -= packet_len;
408   return (0);
409 } /* }}} int nb_add_string */
411 static int nb_add_value_list (lcc_network_buffer_t *nb, /* {{{ */
412     const lcc_value_list_t *vl)
414   char *buffer = nb->ptr;
415   size_t buffer_size = nb->free;
417   const lcc_identifier_t *ident_src;
418   lcc_identifier_t *ident_dst;
420   ident_src = &vl->identifier;
421   ident_dst = &nb->state.identifier;
423   if (strcmp (ident_dst->host, ident_src->host) != 0)
424   {
425     if (nb_add_string (&buffer, &buffer_size, TYPE_HOST,
426           ident_src->host, strlen (ident_src->host)) != 0)
427       return (-1);
428     SSTRNCPY (ident_dst->host, ident_src->host, sizeof (ident_dst->host));
429   }
431   if (strcmp (ident_dst->plugin, ident_src->plugin) != 0)
432   {
433     if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN,
434           ident_src->plugin, strlen (ident_src->plugin)) != 0)
435       return (-1);
436     SSTRNCPY (ident_dst->plugin, ident_src->plugin,
437         sizeof (ident_dst->plugin));
438   }
440   if (strcmp (ident_dst->plugin_instance,
441         ident_src->plugin_instance) != 0)
442   {
443     if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN_INSTANCE,
444           ident_src->plugin_instance,
445           strlen (ident_src->plugin_instance)) != 0)
446       return (-1);
447     SSTRNCPY (ident_dst->plugin_instance, ident_src->plugin_instance,
448         sizeof (ident_dst->plugin_instance));
449   }
451   if (strcmp (ident_dst->type, ident_src->type) != 0)
452   {
453     if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE,
454           ident_src->type, strlen (ident_src->type)) != 0)
455       return (-1);
456     SSTRNCPY (ident_dst->type, ident_src->type, sizeof (ident_dst->type));
457   }
459   if (strcmp (ident_dst->type_instance,
460         ident_src->type_instance) != 0)
461   {
462     if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE_INSTANCE,
463           ident_src->type_instance,
464           strlen (ident_src->type_instance)) != 0)
465       return (-1);
466     SSTRNCPY (ident_dst->type_instance, ident_src->type_instance,
467         sizeof (ident_dst->type_instance));
468   }
470   if (nb->state.time != vl->time)
471   {
472     if (nb_add_time (&buffer, &buffer_size, TYPE_TIME_HR, vl->time))
473       return (-1);
474     nb->state.time = vl->time;
475   }
477   if (nb->state.interval != vl->interval)
478   {
479     if (nb_add_time (&buffer, &buffer_size, TYPE_INTERVAL_HR, vl->interval))
480       return (-1);
481     nb->state.interval = vl->interval;
482   }
484   if (nb_add_values (&buffer, &buffer_size, vl) != 0)
485     return (-1);
487   nb->ptr = buffer;
488   nb->free = buffer_size;
489   return (0);
490 } /* }}} int nb_add_value_list */
492 static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */
494   char *buffer;
495   size_t buffer_size;
497   gcry_md_hd_t hd;
498   gcry_error_t err;
499   unsigned char *hash;
500   const size_t hash_length = 32;
502   /* The type, length and username have already been filled in by
503    * "lcc_network_buffer_initialize". All we do here is calculate the hash over
504    * the username and the data and add the hash value to the buffer. */
506   buffer = nb->buffer + PART_SIGNATURE_SHA256_SIZE;
507   assert (nb->size >= (nb->free + PART_SIGNATURE_SHA256_SIZE));
508   buffer_size = nb->size - (nb->free + PART_SIGNATURE_SHA256_SIZE);
510   hd = NULL;
511   err = gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
512   if (err != 0)
513     return (-1);
515   assert (nb->password != NULL);
516   err = gcry_md_setkey (hd, nb->password, strlen (nb->password));
517   if (err != 0)
518   {
519     gcry_md_close (hd);
520     return (-1);
521   }
523   gcry_md_write (hd, buffer, buffer_size);
524   hash = gcry_md_read (hd, GCRY_MD_SHA256);
525   if (hash == NULL)
526   {
527     gcry_md_close (hd);
528     return (-1);
529   }
531   assert (((2 * sizeof (uint16_t)) + hash_length) == PART_SIGNATURE_SHA256_SIZE);
532   memcpy (nb->buffer + (2 * sizeof (uint16_t)), hash, hash_length);
534   gcry_md_close (hd);
535   return (0);
536 } /* }}} int nb_add_signature */
538 static int nb_add_encryption (lcc_network_buffer_t *nb) /* {{{ */
540   size_t package_length;
541   char *encr_ptr; /* pointer to data being encrypted */
542   size_t encr_size;
544   char *hash_ptr; /* pointer to data being hashed */
545   size_t hash_size;
546   char hash[20];
548   uint16_t pkg_length;
549   gcry_error_t err;
551   /* Fill in the package length */
552   package_length = nb->size - nb->free;
553   pkg_length = htons ((uint16_t) package_length);
554   memcpy (nb->buffer + 2, &pkg_length, sizeof (pkg_length));
556   /* Calculate what to hash */
557   hash_ptr = nb->buffer + PART_ENCRYPTION_AES256_SIZE;
558   hash_size = package_length - nb->encr_header_len;
560   /* Calculate what to encrypt */
561   encr_ptr = hash_ptr - sizeof (hash);
562   encr_size = hash_size + sizeof (hash);
564   /* Calculate the SHA-1 hash */
565   gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash_ptr, hash_size);
566   memcpy (encr_ptr, hash, sizeof (hash));
568   if (nb->encr_cypher == NULL)
569   {
570     unsigned char password_hash[32];
572     err = gcry_cipher_open (&nb->encr_cypher,
573         GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, /* flags = */ 0);
574     if (err != 0)
575       return (-1);
577     /* Calculate our 256bit key used for AES */
578     gcry_md_hash_buffer (GCRY_MD_SHA256, password_hash,
579         nb->password, strlen (nb->password));
581     err = gcry_cipher_setkey (nb->encr_cypher,
582         password_hash, sizeof (password_hash));
583     if (err != 0)
584     {
585       gcry_cipher_close (nb->encr_cypher);
586       nb->encr_cypher = NULL;
587       return (-1);
588     }
589   }
590   else /* if (nb->encr_cypher != NULL) */
591   {
592     gcry_cipher_reset (nb->encr_cypher);
593   }
595   /* Set the initialization vector */
596   err = gcry_cipher_setiv (nb->encr_cypher,
597       nb->encr_iv, sizeof (nb->encr_iv));
598   if (err != 0)
599   {
600     gcry_cipher_close (nb->encr_cypher);
601     nb->encr_cypher = NULL;
602     return (-1);
603   }
605   /* Encrypt the buffer in-place */
606   err = gcry_cipher_encrypt (nb->encr_cypher,
607       encr_ptr, encr_size,
608       /* in = */ NULL, /* in len = */ 0);
609   if (err != 0)
610   {
611     gcry_cipher_close (nb->encr_cypher);
612     nb->encr_cypher = NULL;
613     return (-1);
614   }
616   return (0);
617 } /* }}} int nb_add_encryption */
619 /*
620  * Public functions
621  */
622 lcc_network_buffer_t *lcc_network_buffer_create (size_t size) /* {{{ */
624   lcc_network_buffer_t *nb;
626   if (size == 0)
627     size = LCC_NETWORK_BUFFER_SIZE_DEFAULT;
629   if (size < 128)
630   {
631     errno = EINVAL;
632     return (NULL);
633   }
635   nb = malloc (sizeof (*nb));
636   if (nb == NULL)
637     return (NULL);
638   memset (nb, 0, sizeof (*nb));
640   nb->size = size;
641   nb->buffer = malloc (nb->size);
642   if (nb->buffer == NULL)
643   {
644     free (nb);
645     return (NULL);
646   }
647   memset (nb->buffer, 0, nb->size);
649   nb->ptr = nb->buffer;
650   nb->free = nb->size;
652   nb->seclevel = NONE;
653   nb->username = NULL;
654   nb->password = NULL;
656   return (nb);
657 } /* }}} lcc_network_buffer_t *lcc_network_buffer_create */
659 void lcc_network_buffer_destroy (lcc_network_buffer_t *nb) /* {{{ */
661   if (nb == NULL)
662     return;
664   free (nb->buffer);
665   free (nb);
666 } /* }}} void lcc_network_buffer_destroy */
668 int lcc_network_buffer_set_security_level (lcc_network_buffer_t *nb, /* {{{ */
669     lcc_security_level_t level,
670     const char *username, const char *password)
672   char *username_copy;
673   char *password_copy;
675   if (level == NONE)
676   {
677     free (nb->username);
678     free (nb->password);
679     nb->username = NULL;
680     nb->password = NULL;
681     nb->seclevel = NONE;
682     lcc_network_buffer_initialize (nb);
683     return (0);
684   }
686   if (!have_gcrypt ())
687     return (ENOTSUP);
689   username_copy = strdup (username);
690   password_copy = strdup (password);
691   if ((username_copy == NULL) || (password_copy == NULL))
692   {
693     free (username_copy);
694     free (password_copy);
695     return (ENOMEM);
696   }
698   free (nb->username);
699   free (nb->password);
700   nb->username = username_copy;
701   nb->password = password_copy;
702   nb->seclevel = level;
704   lcc_network_buffer_initialize (nb);
705   return (0);
706 } /* }}} int lcc_network_buffer_set_security_level */
708 int lcc_network_buffer_initialize (lcc_network_buffer_t *nb) /* {{{ */
710   if (nb == NULL)
711     return (EINVAL);
713   memset (nb->buffer, 0, nb->size);
714   memset (&nb->state, 0, sizeof (nb->state));
715   nb->ptr = nb->buffer;
716   nb->free = nb->size;
718   if (nb->seclevel == SIGN)
719   {
720     size_t username_len;
721     uint16_t pkg_type = htons (TYPE_SIGN_SHA256);
722     uint16_t pkg_length = PART_SIGNATURE_SHA256_SIZE;
724     assert (nb->username != NULL);
725     username_len = strlen (nb->username);
726     pkg_length = htons (pkg_length + ((uint16_t) username_len));
728     /* Fill in everything but the hash value here. */
729     memcpy (nb->ptr, &pkg_type, sizeof (pkg_type));
730     memcpy (nb->ptr + sizeof (pkg_type), &pkg_length, sizeof (pkg_length));
731     nb->ptr += PART_SIGNATURE_SHA256_SIZE;
732     nb->free -= PART_SIGNATURE_SHA256_SIZE;
734     memcpy (nb->ptr, nb->username, username_len);
735     nb->ptr += username_len;
736     nb->free -= username_len;
737   }
738   else if (nb->seclevel == ENCRYPT)
739   {
740     size_t username_length = strlen (nb->username);
741     uint16_t pkg_type = htons (TYPE_ENCR_AES256);
742     uint16_t pkg_length = 0; /* Filled in in finalize. */
743     uint16_t pkg_user_len = htons ((uint16_t) username_length);
744     char hash[20];
746     nb->encr_header_len = username_length;
747     nb->encr_header_len += PART_ENCRYPTION_AES256_SIZE;
749     gcry_randomize ((void *) &nb->encr_iv, sizeof (nb->encr_iv),
750         GCRY_STRONG_RANDOM);
752     /* Filled in in finalize. */
753     memset (hash, 0, sizeof (hash));
755     ADD_STATIC (nb, pkg_type);
756     ADD_STATIC (nb, pkg_length);
757     ADD_STATIC (nb, pkg_user_len);
758     ADD_GENERIC (nb, nb->username, username_length);
759     ADD_GENERIC (nb, nb->encr_iv, sizeof (nb->encr_iv));
760     ADD_GENERIC (nb, hash, sizeof (hash));
761     assert ((nb->encr_header_len + nb->free) == nb->size);
762   }
764   return (0);
765 } /* }}} int lcc_network_buffer_initialize */
767 int lcc_network_buffer_finalize (lcc_network_buffer_t *nb) /* {{{ */
769   if (nb == NULL)
770     return (EINVAL);
772   if (nb->seclevel == SIGN)
773     nb_add_signature (nb);
774   else if (nb->seclevel == ENCRYPT)
775     nb_add_encryption (nb);
777   return (0);
778 } /* }}} int lcc_network_buffer_finalize */
780 int lcc_network_buffer_add_value (lcc_network_buffer_t *nb, /* {{{ */
781     const lcc_value_list_t *vl)
783   int status;
785   if ((nb == NULL) || (vl == NULL))
786     return (EINVAL);
788   status = nb_add_value_list (nb, vl);
789   return (status);
790 } /* }}} int lcc_network_buffer_add_value */
792 int lcc_network_buffer_get (lcc_network_buffer_t *nb, /* {{{ */
793     void *buffer, size_t *buffer_size)
795   size_t sz_required;
796   size_t sz_available;
798   if ((nb == NULL) || (buffer_size == NULL))
799     return (EINVAL);
801   assert (nb->size >= nb->free);
802   sz_required = nb->size - nb->free;
803   sz_available = *buffer_size;
805   *buffer_size = sz_required;
806   if (buffer != NULL)
807     memcpy (buffer, nb->buffer,
808         (sz_available < sz_required) ? sz_available : sz_required);
810   return (0);
811 } /* }}} int lcc_network_buffer_get */
813 /* vim: set sw=2 sts=2 et fdm=marker : */