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 /* FreeBSD's copy of libgcrypt extends the existing GCRYPT_NO_DEPRECATED
48 * to properly hide all deprecated functionality.
49 * http://svnweb.freebsd.org/ports/head/security/libgcrypt/files/patch-src__gcrypt.h.in
50 */
51 # define GCRYPT_NO_DEPRECATED
52 # include <gcrypt.h>
53 # if defined __APPLE__
54 /* Re enable deprecation warnings */
55 # pragma GCC diagnostic warning "-Wdeprecated-declarations"
56 # endif
57 GCRY_THREAD_OPTION_PTHREAD_IMPL;
58 #endif
60 #include "collectd/network_buffer.h"
62 #define TYPE_HOST 0x0000
63 #define TYPE_TIME 0x0001
64 #define TYPE_TIME_HR 0x0008
65 #define TYPE_PLUGIN 0x0002
66 #define TYPE_PLUGIN_INSTANCE 0x0003
67 #define TYPE_TYPE 0x0004
68 #define TYPE_TYPE_INSTANCE 0x0005
69 #define TYPE_VALUES 0x0006
70 #define TYPE_INTERVAL 0x0007
71 #define TYPE_INTERVAL_HR 0x0009
73 /* Types to transmit notifications */
74 #define TYPE_MESSAGE 0x0100
75 #define TYPE_SEVERITY 0x0101
77 #define TYPE_SIGN_SHA256 0x0200
78 #define TYPE_ENCR_AES256 0x0210
80 #define PART_SIGNATURE_SHA256_SIZE 36
81 #define PART_ENCRYPTION_AES256_SIZE 42
83 #define ADD_GENERIC(nb,srcptr,size) do { \
84 assert ((size) <= (nb)->free); \
85 memcpy ((nb)->ptr, (srcptr), (size)); \
86 (nb)->ptr += (size); \
87 (nb)->free -= (size); \
88 } while (0)
90 #define ADD_STATIC(nb,var) \
91 ADD_GENERIC(nb,&(var),sizeof(var));
93 /*
94 * Data types
95 */
96 struct lcc_network_buffer_s
97 {
98 char *buffer;
99 size_t size;
101 lcc_value_list_t state;
102 char *ptr;
103 size_t free;
105 lcc_security_level_t seclevel;
106 char *username;
107 char *password;
109 #if HAVE_LIBGCRYPT
110 gcry_cipher_hd_t encr_cypher;
111 size_t encr_header_len;
112 char encr_iv[16];
113 #endif
114 };
116 #define SSTRNCPY(dst,src,sz) do { \
117 strncpy ((dst), (src), (sz)); \
118 (dst)[(sz) - 1] = 0; \
119 } while (0)
121 /*
122 * Private functions
123 */
124 static _Bool have_gcrypt (void) /* {{{ */
125 {
126 static _Bool result = 0;
127 static _Bool need_init = 1;
129 if (!need_init)
130 return (result);
131 need_init = 0;
133 #if HAVE_LIBGCRYPT
134 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
136 if (!gcry_check_version (GCRYPT_VERSION))
137 return (0);
139 gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
140 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
142 result = 1;
143 return (1);
144 #else
145 return(0);
146 #endif
147 } /* }}} _Bool have_gcrypt */
149 static uint64_t htonll (uint64_t val) /* {{{ */
150 {
151 static int config = 0;
153 uint32_t hi;
154 uint32_t lo;
156 if (config == 0)
157 {
158 uint16_t h = 0x1234;
159 uint16_t n = htons (h);
161 if (h == n)
162 config = 1;
163 else
164 config = 2;
165 }
167 if (config == 1)
168 return (val);
170 hi = (uint32_t) (val >> 32);
171 lo = (uint32_t) (val & 0x00000000FFFFFFFF);
173 hi = htonl (hi);
174 lo = htonl (lo);
176 return ((((uint64_t) lo) << 32) | ((uint64_t) hi));
177 } /* }}} uint64_t htonll */
179 static double htond (double val) /* {{{ */
180 {
181 static int config = 0;
183 union { uint8_t byte[8]; double floating; } in;
184 union { uint8_t byte[8]; double floating; } out;
186 if (config == 0)
187 {
188 double d = 8.642135e130;
189 uint8_t c[8];
191 memcpy (c, &d, 8);
193 if ((c[0] == 0x2f) && (c[1] == 0x25)
194 && (c[2] == 0xc0) && (c[3] == 0xc7)
195 && (c[4] == 0x43) && (c[5] == 0x2b)
196 && (c[6] == 0x1f) && (c[7] == 0x5b))
197 config = 1; /* need nothing */
198 else if ((c[7] == 0x2f) && (c[6] == 0x25)
199 && (c[5] == 0xc0) && (c[4] == 0xc7)
200 && (c[3] == 0x43) && (c[2] == 0x2b)
201 && (c[1] == 0x1f) && (c[0] == 0x5b))
202 config = 2; /* endian flip */
203 else if ((c[4] == 0x2f) && (c[5] == 0x25)
204 && (c[6] == 0xc0) && (c[7] == 0xc7)
205 && (c[0] == 0x43) && (c[1] == 0x2b)
206 && (c[2] == 0x1f) && (c[3] == 0x5b))
207 config = 3; /* int swap */
208 else
209 config = 4;
210 }
212 if (isnan (val))
213 {
214 out.byte[0] = out.byte[1] = out.byte[2] = out.byte[3] = 0x00;
215 out.byte[4] = out.byte[5] = 0x00;
216 out.byte[6] = 0xf8;
217 out.byte[7] = 0x7f;
218 return (out.floating);
219 }
220 else if (config == 1)
221 return (val);
222 else if (config == 2)
223 {
224 in.floating = val;
225 out.byte[0] = in.byte[7];
226 out.byte[1] = in.byte[6];
227 out.byte[2] = in.byte[5];
228 out.byte[3] = in.byte[4];
229 out.byte[4] = in.byte[3];
230 out.byte[5] = in.byte[2];
231 out.byte[6] = in.byte[1];
232 out.byte[7] = in.byte[0];
233 return (out.floating);
234 }
235 else if (config == 3)
236 {
237 in.floating = val;
238 out.byte[0] = in.byte[4];
239 out.byte[1] = in.byte[5];
240 out.byte[2] = in.byte[6];
241 out.byte[3] = in.byte[7];
242 out.byte[4] = in.byte[0];
243 out.byte[5] = in.byte[1];
244 out.byte[6] = in.byte[2];
245 out.byte[7] = in.byte[3];
246 return (out.floating);
247 }
248 else
249 {
250 /* If in doubt, just copy the value back to the caller. */
251 return (val);
252 }
253 } /* }}} double htond */
255 static int nb_add_values (char **ret_buffer, /* {{{ */
256 size_t *ret_buffer_len,
257 const lcc_value_list_t *vl)
258 {
259 char *packet_ptr;
260 size_t packet_len;
262 uint16_t pkg_type;
263 uint16_t pkg_length;
264 uint16_t pkg_num_values;
265 uint8_t pkg_values_types[vl->values_len];
266 value_t pkg_values[vl->values_len];
268 size_t offset;
269 size_t i;
271 packet_len = sizeof (pkg_type) + sizeof (pkg_length)
272 + sizeof (pkg_num_values)
273 + sizeof (pkg_values_types)
274 + sizeof (pkg_values);
276 if (*ret_buffer_len < packet_len)
277 return (ENOMEM);
279 pkg_type = htons (TYPE_VALUES);
280 pkg_length = htons ((uint16_t) packet_len);
281 pkg_num_values = htons ((uint16_t) vl->values_len);
283 for (i = 0; i < vl->values_len; i++)
284 {
285 pkg_values_types[i] = (uint8_t) vl->values_types[i];
286 switch (vl->values_types[i])
287 {
288 case LCC_TYPE_COUNTER:
289 pkg_values[i].counter = (counter_t) htonll (vl->values[i].counter);
290 break;
292 case LCC_TYPE_GAUGE:
293 pkg_values[i].gauge = (gauge_t) htond (vl->values[i].gauge);
294 break;
296 case LCC_TYPE_DERIVE:
297 pkg_values[i].derive = (derive_t) htonll (vl->values[i].derive);
298 break;
300 case LCC_TYPE_ABSOLUTE:
301 pkg_values[i].absolute = (absolute_t) htonll (vl->values[i].absolute);
302 break;
304 default:
305 return (EINVAL);
306 } /* switch (vl->values_types[i]) */
307 } /* for (vl->values_len) */
309 /*
310 * Use `memcpy' to write everything to the buffer, because the pointer
311 * may be unaligned and some architectures, such as SPARC, can't handle
312 * that.
313 */
314 packet_ptr = *ret_buffer;
315 offset = 0;
316 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
317 offset += sizeof (pkg_type);
318 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
319 offset += sizeof (pkg_length);
320 memcpy (packet_ptr + offset, &pkg_num_values, sizeof (pkg_num_values));
321 offset += sizeof (pkg_num_values);
322 memcpy (packet_ptr + offset, pkg_values_types, sizeof (pkg_values_types));
323 offset += sizeof (pkg_values_types);
324 memcpy (packet_ptr + offset, pkg_values, sizeof (pkg_values));
325 offset += sizeof (pkg_values);
327 assert (offset == packet_len);
329 *ret_buffer = packet_ptr + packet_len;
330 *ret_buffer_len -= packet_len;
331 return (0);
332 } /* }}} int nb_add_values */
334 static int nb_add_number (char **ret_buffer, /* {{{ */
335 size_t *ret_buffer_len,
336 uint16_t type, uint64_t value)
337 {
338 char *packet_ptr;
339 size_t packet_len;
341 uint16_t pkg_type;
342 uint16_t pkg_length;
343 uint64_t pkg_value;
345 size_t offset;
347 packet_len = sizeof (pkg_type)
348 + sizeof (pkg_length)
349 + sizeof (pkg_value);
351 if (*ret_buffer_len < packet_len)
352 return (ENOMEM);
354 pkg_type = htons (type);
355 pkg_length = htons ((uint16_t) packet_len);
356 pkg_value = htonll (value);
358 packet_ptr = *ret_buffer;
359 offset = 0;
360 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
361 offset += sizeof (pkg_type);
362 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
363 offset += sizeof (pkg_length);
364 memcpy (packet_ptr + offset, &pkg_value, sizeof (pkg_value));
365 offset += sizeof (pkg_value);
367 assert (offset == packet_len);
369 *ret_buffer = packet_ptr + packet_len;
370 *ret_buffer_len -= packet_len;
371 return (0);
372 } /* }}} int nb_add_number */
374 static int nb_add_time (char **ret_buffer, /* {{{ */
375 size_t *ret_buffer_len,
376 uint16_t type, double value)
377 {
378 /* Convert to collectd's "cdtime" representation. */
379 uint64_t cdtime_value = (uint64_t) (value * 1073741824.0);
380 return (nb_add_number (ret_buffer, ret_buffer_len, type, cdtime_value));
381 } /* }}} int nb_add_time */
383 static int nb_add_string (char **ret_buffer, /* {{{ */
384 size_t *ret_buffer_len,
385 uint16_t type, const char *str, size_t str_len)
386 {
387 char *packet_ptr;
388 size_t packet_len;
390 uint16_t pkg_type;
391 uint16_t pkg_length;
393 size_t offset;
395 packet_len = sizeof (pkg_type)
396 + sizeof (pkg_length)
397 + str_len + 1;
398 if (*ret_buffer_len < packet_len)
399 return (ENOMEM);
401 pkg_type = htons (type);
402 pkg_length = htons ((uint16_t) packet_len);
404 packet_ptr = *ret_buffer;
405 offset = 0;
406 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
407 offset += sizeof (pkg_type);
408 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
409 offset += sizeof (pkg_length);
410 memcpy (packet_ptr + offset, str, str_len);
411 offset += str_len;
412 memset (packet_ptr + offset, 0, 1);
413 offset += 1;
415 assert (offset == packet_len);
417 *ret_buffer = packet_ptr + packet_len;
418 *ret_buffer_len -= packet_len;
419 return (0);
420 } /* }}} int nb_add_string */
422 static int nb_add_value_list (lcc_network_buffer_t *nb, /* {{{ */
423 const lcc_value_list_t *vl)
424 {
425 char *buffer = nb->ptr;
426 size_t buffer_size = nb->free;
428 const lcc_identifier_t *ident_src;
429 lcc_identifier_t *ident_dst;
431 ident_src = &vl->identifier;
432 ident_dst = &nb->state.identifier;
434 if (strcmp (ident_dst->host, ident_src->host) != 0)
435 {
436 if (nb_add_string (&buffer, &buffer_size, TYPE_HOST,
437 ident_src->host, strlen (ident_src->host)) != 0)
438 return (-1);
439 SSTRNCPY (ident_dst->host, ident_src->host, sizeof (ident_dst->host));
440 }
442 if (strcmp (ident_dst->plugin, ident_src->plugin) != 0)
443 {
444 if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN,
445 ident_src->plugin, strlen (ident_src->plugin)) != 0)
446 return (-1);
447 SSTRNCPY (ident_dst->plugin, ident_src->plugin,
448 sizeof (ident_dst->plugin));
449 }
451 if (strcmp (ident_dst->plugin_instance,
452 ident_src->plugin_instance) != 0)
453 {
454 if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN_INSTANCE,
455 ident_src->plugin_instance,
456 strlen (ident_src->plugin_instance)) != 0)
457 return (-1);
458 SSTRNCPY (ident_dst->plugin_instance, ident_src->plugin_instance,
459 sizeof (ident_dst->plugin_instance));
460 }
462 if (strcmp (ident_dst->type, ident_src->type) != 0)
463 {
464 if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE,
465 ident_src->type, strlen (ident_src->type)) != 0)
466 return (-1);
467 SSTRNCPY (ident_dst->type, ident_src->type, sizeof (ident_dst->type));
468 }
470 if (strcmp (ident_dst->type_instance,
471 ident_src->type_instance) != 0)
472 {
473 if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE_INSTANCE,
474 ident_src->type_instance,
475 strlen (ident_src->type_instance)) != 0)
476 return (-1);
477 SSTRNCPY (ident_dst->type_instance, ident_src->type_instance,
478 sizeof (ident_dst->type_instance));
479 }
481 if (nb->state.time != vl->time)
482 {
483 if (nb_add_time (&buffer, &buffer_size, TYPE_TIME_HR, vl->time))
484 return (-1);
485 nb->state.time = vl->time;
486 }
488 if (nb->state.interval != vl->interval)
489 {
490 if (nb_add_time (&buffer, &buffer_size, TYPE_INTERVAL_HR, vl->interval))
491 return (-1);
492 nb->state.interval = vl->interval;
493 }
495 if (nb_add_values (&buffer, &buffer_size, vl) != 0)
496 return (-1);
498 nb->ptr = buffer;
499 nb->free = buffer_size;
500 return (0);
501 } /* }}} int nb_add_value_list */
503 #if HAVE_LIBGCRYPT
504 static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */
505 {
506 char *buffer;
507 size_t buffer_size;
509 gcry_md_hd_t hd;
510 gcry_error_t err;
511 unsigned char *hash;
512 const size_t hash_length = 32;
514 /* The type, length and username have already been filled in by
515 * "lcc_network_buffer_initialize". All we do here is calculate the hash over
516 * the username and the data and add the hash value to the buffer. */
518 buffer = nb->buffer + PART_SIGNATURE_SHA256_SIZE;
519 assert (nb->size >= (nb->free + PART_SIGNATURE_SHA256_SIZE));
520 buffer_size = nb->size - (nb->free + PART_SIGNATURE_SHA256_SIZE);
522 hd = NULL;
523 err = gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
524 if (err != 0)
525 return (-1);
527 assert (nb->password != NULL);
528 err = gcry_md_setkey (hd, nb->password, strlen (nb->password));
529 if (err != 0)
530 {
531 gcry_md_close (hd);
532 return (-1);
533 }
535 gcry_md_write (hd, buffer, buffer_size);
536 hash = gcry_md_read (hd, GCRY_MD_SHA256);
537 if (hash == NULL)
538 {
539 gcry_md_close (hd);
540 return (-1);
541 }
543 assert (((2 * sizeof (uint16_t)) + hash_length) == PART_SIGNATURE_SHA256_SIZE);
544 memcpy (nb->buffer + (2 * sizeof (uint16_t)), hash, hash_length);
546 gcry_md_close (hd);
547 return (0);
548 } /* }}} int nb_add_signature */
550 static int nb_add_encryption (lcc_network_buffer_t *nb) /* {{{ */
551 {
552 size_t package_length;
553 char *encr_ptr; /* pointer to data being encrypted */
554 size_t encr_size;
556 char *hash_ptr; /* pointer to data being hashed */
557 size_t hash_size;
558 char hash[20];
560 uint16_t pkg_length;
561 gcry_error_t err;
563 /* Fill in the package length */
564 package_length = nb->size - nb->free;
565 pkg_length = htons ((uint16_t) package_length);
566 memcpy (nb->buffer + 2, &pkg_length, sizeof (pkg_length));
568 /* Calculate what to hash */
569 hash_ptr = nb->buffer + PART_ENCRYPTION_AES256_SIZE;
570 hash_size = package_length - nb->encr_header_len;
572 /* Calculate what to encrypt */
573 encr_ptr = hash_ptr - sizeof (hash);
574 encr_size = hash_size + sizeof (hash);
576 /* Calculate the SHA-1 hash */
577 gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash_ptr, hash_size);
578 memcpy (encr_ptr, hash, sizeof (hash));
580 if (nb->encr_cypher == NULL)
581 {
582 unsigned char password_hash[32];
584 err = gcry_cipher_open (&nb->encr_cypher,
585 GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, /* flags = */ 0);
586 if (err != 0)
587 return (-1);
589 /* Calculate our 256bit key used for AES */
590 gcry_md_hash_buffer (GCRY_MD_SHA256, password_hash,
591 nb->password, strlen (nb->password));
593 err = gcry_cipher_setkey (nb->encr_cypher,
594 password_hash, sizeof (password_hash));
595 if (err != 0)
596 {
597 gcry_cipher_close (nb->encr_cypher);
598 nb->encr_cypher = NULL;
599 return (-1);
600 }
601 }
602 else /* if (nb->encr_cypher != NULL) */
603 {
604 gcry_cipher_reset (nb->encr_cypher);
605 }
607 /* Set the initialization vector */
608 err = gcry_cipher_setiv (nb->encr_cypher,
609 nb->encr_iv, sizeof (nb->encr_iv));
610 if (err != 0)
611 {
612 gcry_cipher_close (nb->encr_cypher);
613 nb->encr_cypher = NULL;
614 return (-1);
615 }
617 /* Encrypt the buffer in-place */
618 err = gcry_cipher_encrypt (nb->encr_cypher,
619 encr_ptr, encr_size,
620 /* in = */ NULL, /* in len = */ 0);
621 if (err != 0)
622 {
623 gcry_cipher_close (nb->encr_cypher);
624 nb->encr_cypher = NULL;
625 return (-1);
626 }
628 return (0);
629 } /* }}} int nb_add_encryption */
630 #endif
632 /*
633 * Public functions
634 */
635 lcc_network_buffer_t *lcc_network_buffer_create (size_t size) /* {{{ */
636 {
637 lcc_network_buffer_t *nb;
639 if (size == 0)
640 size = LCC_NETWORK_BUFFER_SIZE_DEFAULT;
642 if (size < 128)
643 {
644 errno = EINVAL;
645 return (NULL);
646 }
648 nb = malloc (sizeof (*nb));
649 if (nb == NULL)
650 return (NULL);
651 memset (nb, 0, sizeof (*nb));
653 nb->size = size;
654 nb->buffer = malloc (nb->size);
655 if (nb->buffer == NULL)
656 {
657 free (nb);
658 return (NULL);
659 }
660 memset (nb->buffer, 0, nb->size);
662 nb->ptr = nb->buffer;
663 nb->free = nb->size;
665 nb->seclevel = NONE;
666 nb->username = NULL;
667 nb->password = NULL;
669 return (nb);
670 } /* }}} lcc_network_buffer_t *lcc_network_buffer_create */
672 void lcc_network_buffer_destroy (lcc_network_buffer_t *nb) /* {{{ */
673 {
674 if (nb == NULL)
675 return;
677 free (nb->buffer);
678 free (nb);
679 } /* }}} void lcc_network_buffer_destroy */
681 int lcc_network_buffer_set_security_level (lcc_network_buffer_t *nb, /* {{{ */
682 lcc_security_level_t level,
683 const char *username, const char *password)
684 {
685 char *username_copy;
686 char *password_copy;
688 if (level == NONE)
689 {
690 free (nb->username);
691 free (nb->password);
692 nb->username = NULL;
693 nb->password = NULL;
694 nb->seclevel = NONE;
695 lcc_network_buffer_initialize (nb);
696 return (0);
697 }
699 if (!have_gcrypt ())
700 return (ENOTSUP);
702 username_copy = strdup (username);
703 password_copy = strdup (password);
704 if ((username_copy == NULL) || (password_copy == NULL))
705 {
706 free (username_copy);
707 free (password_copy);
708 return (ENOMEM);
709 }
711 free (nb->username);
712 free (nb->password);
713 nb->username = username_copy;
714 nb->password = password_copy;
715 nb->seclevel = level;
717 lcc_network_buffer_initialize (nb);
718 return (0);
719 } /* }}} int lcc_network_buffer_set_security_level */
721 int lcc_network_buffer_initialize (lcc_network_buffer_t *nb) /* {{{ */
722 {
723 if (nb == NULL)
724 return (EINVAL);
726 memset (nb->buffer, 0, nb->size);
727 memset (&nb->state, 0, sizeof (nb->state));
728 nb->ptr = nb->buffer;
729 nb->free = nb->size;
731 #if HAVE_LIBGCRYPT
732 if (nb->seclevel == SIGN)
733 {
734 size_t username_len;
735 uint16_t pkg_type = htons (TYPE_SIGN_SHA256);
736 uint16_t pkg_length = PART_SIGNATURE_SHA256_SIZE;
738 assert (nb->username != NULL);
739 username_len = strlen (nb->username);
740 pkg_length = htons (pkg_length + ((uint16_t) username_len));
742 /* Fill in everything but the hash value here. */
743 memcpy (nb->ptr, &pkg_type, sizeof (pkg_type));
744 memcpy (nb->ptr + sizeof (pkg_type), &pkg_length, sizeof (pkg_length));
745 nb->ptr += PART_SIGNATURE_SHA256_SIZE;
746 nb->free -= PART_SIGNATURE_SHA256_SIZE;
748 memcpy (nb->ptr, nb->username, username_len);
749 nb->ptr += username_len;
750 nb->free -= username_len;
751 }
752 else if (nb->seclevel == ENCRYPT)
753 {
754 size_t username_length = strlen (nb->username);
755 uint16_t pkg_type = htons (TYPE_ENCR_AES256);
756 uint16_t pkg_length = 0; /* Filled in in finalize. */
757 uint16_t pkg_user_len = htons ((uint16_t) username_length);
758 char hash[20];
760 nb->encr_header_len = username_length;
761 nb->encr_header_len += PART_ENCRYPTION_AES256_SIZE;
763 gcry_randomize ((void *) &nb->encr_iv, sizeof (nb->encr_iv),
764 GCRY_STRONG_RANDOM);
766 /* Filled in in finalize. */
767 memset (hash, 0, sizeof (hash));
769 ADD_STATIC (nb, pkg_type);
770 ADD_STATIC (nb, pkg_length);
771 ADD_STATIC (nb, pkg_user_len);
772 ADD_GENERIC (nb, nb->username, username_length);
773 ADD_GENERIC (nb, nb->encr_iv, sizeof (nb->encr_iv));
774 ADD_GENERIC (nb, hash, sizeof (hash));
775 assert ((nb->encr_header_len + nb->free) == nb->size);
776 }
777 #endif
779 return (0);
780 } /* }}} int lcc_network_buffer_initialize */
782 int lcc_network_buffer_finalize (lcc_network_buffer_t *nb) /* {{{ */
783 {
784 if (nb == NULL)
785 return (EINVAL);
787 #if HAVE_LIBGCRYPT
788 if (nb->seclevel == SIGN)
789 nb_add_signature (nb);
790 else if (nb->seclevel == ENCRYPT)
791 nb_add_encryption (nb);
792 #endif
794 return (0);
795 } /* }}} int lcc_network_buffer_finalize */
797 int lcc_network_buffer_add_value (lcc_network_buffer_t *nb, /* {{{ */
798 const lcc_value_list_t *vl)
799 {
800 int status;
802 if ((nb == NULL) || (vl == NULL))
803 return (EINVAL);
805 status = nb_add_value_list (nb, vl);
806 return (status);
807 } /* }}} int lcc_network_buffer_add_value */
809 int lcc_network_buffer_get (lcc_network_buffer_t *nb, /* {{{ */
810 void *buffer, size_t *buffer_size)
811 {
812 size_t sz_required;
813 size_t sz_available;
815 if ((nb == NULL) || (buffer_size == NULL))
816 return (EINVAL);
818 assert (nb->size >= nb->free);
819 sz_required = nb->size - nb->free;
820 sz_available = *buffer_size;
822 *buffer_size = sz_required;
823 if (buffer != NULL)
824 memcpy (buffer, nb->buffer,
825 (sz_available < sz_required) ? sz_available : sz_required);
827 return (0);
828 } /* }}} int lcc_network_buffer_get */
830 /* vim: set sw=2 sts=2 et fdm=marker : */