1 /**
2 * collectd - src/libcollectdclient/network_buffer.c
3 * Copyright (C) 2010-2015 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 # if defined __APPLE__
40 /* default xcode compiler throws warnings even when deprecated functionality
41 * is not used. -Werror breaks the build because of erroneous warnings.
42 * http://stackoverflow.com/questions/10556299/compiler-warnings-with-libgcrypt-v1-5-0/12830209#12830209
43 */
44 # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
45 # endif
46 /* FreeBSD's copy of libgcrypt extends the existing GCRYPT_NO_DEPRECATED
47 * to properly hide all deprecated functionality.
48 * http://svnweb.freebsd.org/ports/head/security/libgcrypt/files/patch-src__gcrypt.h.in
49 */
50 # define GCRYPT_NO_DEPRECATED
51 # include <gcrypt.h>
52 # if defined __APPLE__
53 /* Re enable deprecation warnings */
54 # pragma GCC diagnostic warning "-Wdeprecated-declarations"
55 # endif
56 # if GCRYPT_VERSION_NUMBER < 0x010600
57 GCRY_THREAD_OPTION_PTHREAD_IMPL;
58 # endif
59 #endif
61 #include "collectd/network_buffer.h"
63 #define TYPE_HOST 0x0000
64 #define TYPE_TIME 0x0001
65 #define TYPE_TIME_HR 0x0008
66 #define TYPE_PLUGIN 0x0002
67 #define TYPE_PLUGIN_INSTANCE 0x0003
68 #define TYPE_TYPE 0x0004
69 #define TYPE_TYPE_INSTANCE 0x0005
70 #define TYPE_VALUES 0x0006
71 #define TYPE_INTERVAL 0x0007
72 #define TYPE_INTERVAL_HR 0x0009
74 /* Types to transmit notifications */
75 #define TYPE_MESSAGE 0x0100
76 #define TYPE_SEVERITY 0x0101
78 #define TYPE_SIGN_SHA256 0x0200
79 #define TYPE_ENCR_AES256 0x0210
81 #define PART_SIGNATURE_SHA256_SIZE 36
82 #define PART_ENCRYPTION_AES256_SIZE 42
84 #define ADD_GENERIC(nb,srcptr,size) do { \
85 assert ((size) <= (nb)->free); \
86 memcpy ((nb)->ptr, (srcptr), (size)); \
87 (nb)->ptr += (size); \
88 (nb)->free -= (size); \
89 } while (0)
91 #define ADD_STATIC(nb,var) \
92 ADD_GENERIC(nb,&(var),sizeof(var));
94 /*
95 * Data types
96 */
97 struct lcc_network_buffer_s
98 {
99 char *buffer;
100 size_t size;
102 lcc_value_list_t state;
103 char *ptr;
104 size_t free;
106 lcc_security_level_t seclevel;
107 char *username;
108 char *password;
110 #if HAVE_LIBGCRYPT
111 gcry_cipher_hd_t encr_cypher;
112 size_t encr_header_len;
113 char encr_iv[16];
114 #endif
115 };
117 #define SSTRNCPY(dst,src,sz) do { \
118 strncpy ((dst), (src), (sz)); \
119 (dst)[(sz) - 1] = 0; \
120 } while (0)
122 /*
123 * Private functions
124 */
125 static _Bool have_gcrypt (void) /* {{{ */
126 {
127 static _Bool result = 0;
128 static _Bool need_init = 1;
130 if (!need_init)
131 return (result);
132 need_init = 0;
134 #if HAVE_LIBGCRYPT
135 # if GCRYPT_VERSION_NUMBER < 0x010600
136 if (gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread))
137 return (0);
138 # endif
140 if (!gcry_check_version (GCRYPT_VERSION))
141 return (0);
143 if (!gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0))
144 return (0);
146 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
148 result = 1;
149 return (1);
150 #else
151 return(0);
152 #endif
153 } /* }}} _Bool have_gcrypt */
155 #ifndef HAVE_HTONLL
156 static uint64_t htonll (uint64_t val) /* {{{ */
157 {
158 static int config = 0;
160 uint32_t hi;
161 uint32_t lo;
163 if (config == 0)
164 {
165 uint16_t h = 0x1234;
166 uint16_t n = htons (h);
168 if (h == n)
169 config = 1;
170 else
171 config = 2;
172 }
174 if (config == 1)
175 return (val);
177 hi = (uint32_t) (val >> 32);
178 lo = (uint32_t) (val & 0x00000000FFFFFFFF);
180 hi = htonl (hi);
181 lo = htonl (lo);
183 return ((((uint64_t) lo) << 32) | ((uint64_t) hi));
184 } /* }}} uint64_t htonll */
185 #endif
187 static double htond (double val) /* {{{ */
188 {
189 static int config = 0;
191 union { uint8_t byte[8]; double floating; } in;
192 union { uint8_t byte[8]; double floating; } out;
194 if (config == 0)
195 {
196 double d = 8.642135e130;
197 uint8_t c[8];
199 memcpy (c, &d, 8);
201 if ((c[0] == 0x2f) && (c[1] == 0x25)
202 && (c[2] == 0xc0) && (c[3] == 0xc7)
203 && (c[4] == 0x43) && (c[5] == 0x2b)
204 && (c[6] == 0x1f) && (c[7] == 0x5b))
205 config = 1; /* need nothing */
206 else if ((c[7] == 0x2f) && (c[6] == 0x25)
207 && (c[5] == 0xc0) && (c[4] == 0xc7)
208 && (c[3] == 0x43) && (c[2] == 0x2b)
209 && (c[1] == 0x1f) && (c[0] == 0x5b))
210 config = 2; /* endian flip */
211 else if ((c[4] == 0x2f) && (c[5] == 0x25)
212 && (c[6] == 0xc0) && (c[7] == 0xc7)
213 && (c[0] == 0x43) && (c[1] == 0x2b)
214 && (c[2] == 0x1f) && (c[3] == 0x5b))
215 config = 3; /* int swap */
216 else
217 config = 4;
218 }
220 if (isnan (val))
221 {
222 out.byte[0] = out.byte[1] = out.byte[2] = out.byte[3] = 0x00;
223 out.byte[4] = out.byte[5] = 0x00;
224 out.byte[6] = 0xf8;
225 out.byte[7] = 0x7f;
226 return (out.floating);
227 }
228 else if (config == 1)
229 return (val);
230 else if (config == 2)
231 {
232 in.floating = val;
233 out.byte[0] = in.byte[7];
234 out.byte[1] = in.byte[6];
235 out.byte[2] = in.byte[5];
236 out.byte[3] = in.byte[4];
237 out.byte[4] = in.byte[3];
238 out.byte[5] = in.byte[2];
239 out.byte[6] = in.byte[1];
240 out.byte[7] = in.byte[0];
241 return (out.floating);
242 }
243 else if (config == 3)
244 {
245 in.floating = val;
246 out.byte[0] = in.byte[4];
247 out.byte[1] = in.byte[5];
248 out.byte[2] = in.byte[6];
249 out.byte[3] = in.byte[7];
250 out.byte[4] = in.byte[0];
251 out.byte[5] = in.byte[1];
252 out.byte[6] = in.byte[2];
253 out.byte[7] = in.byte[3];
254 return (out.floating);
255 }
256 else
257 {
258 /* If in doubt, just copy the value back to the caller. */
259 return (val);
260 }
261 } /* }}} double htond */
263 static int nb_add_values (char **ret_buffer, /* {{{ */
264 size_t *ret_buffer_len,
265 const lcc_value_list_t *vl)
266 {
267 char *packet_ptr;
268 size_t packet_len;
270 uint16_t pkg_type;
271 uint16_t pkg_length;
272 uint16_t pkg_num_values;
273 uint8_t pkg_values_types[vl->values_len];
274 value_t pkg_values[vl->values_len];
276 size_t offset;
278 packet_len = sizeof (pkg_type) + sizeof (pkg_length)
279 + sizeof (pkg_num_values)
280 + sizeof (pkg_values_types)
281 + sizeof (pkg_values);
283 if (*ret_buffer_len < packet_len)
284 return (ENOMEM);
286 pkg_type = htons (TYPE_VALUES);
287 pkg_length = htons ((uint16_t) packet_len);
288 pkg_num_values = htons ((uint16_t) vl->values_len);
290 for (size_t i = 0; i < vl->values_len; i++)
291 {
292 pkg_values_types[i] = (uint8_t) vl->values_types[i];
293 switch (vl->values_types[i])
294 {
295 case LCC_TYPE_COUNTER:
296 pkg_values[i].counter = (counter_t) htonll (vl->values[i].counter);
297 break;
299 case LCC_TYPE_GAUGE:
300 pkg_values[i].gauge = (gauge_t) htond (vl->values[i].gauge);
301 break;
303 case LCC_TYPE_DERIVE:
304 pkg_values[i].derive = (derive_t) htonll (vl->values[i].derive);
305 break;
307 case LCC_TYPE_ABSOLUTE:
308 pkg_values[i].absolute = (absolute_t) htonll (vl->values[i].absolute);
309 break;
311 default:
312 return (EINVAL);
313 } /* switch (vl->values_types[i]) */
314 } /* for (vl->values_len) */
316 /*
317 * Use `memcpy' to write everything to the buffer, because the pointer
318 * may be unaligned and some architectures, such as SPARC, can't handle
319 * that.
320 */
321 packet_ptr = *ret_buffer;
322 offset = 0;
323 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
324 offset += sizeof (pkg_type);
325 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
326 offset += sizeof (pkg_length);
327 memcpy (packet_ptr + offset, &pkg_num_values, sizeof (pkg_num_values));
328 offset += sizeof (pkg_num_values);
329 memcpy (packet_ptr + offset, pkg_values_types, sizeof (pkg_values_types));
330 offset += sizeof (pkg_values_types);
331 memcpy (packet_ptr + offset, pkg_values, sizeof (pkg_values));
332 offset += sizeof (pkg_values);
334 assert (offset == packet_len);
336 *ret_buffer = packet_ptr + packet_len;
337 *ret_buffer_len -= packet_len;
338 return (0);
339 } /* }}} int nb_add_values */
341 static int nb_add_number (char **ret_buffer, /* {{{ */
342 size_t *ret_buffer_len,
343 uint16_t type, uint64_t value)
344 {
345 char *packet_ptr;
346 size_t packet_len;
348 uint16_t pkg_type;
349 uint16_t pkg_length;
350 uint64_t pkg_value;
352 size_t offset;
354 packet_len = sizeof (pkg_type)
355 + sizeof (pkg_length)
356 + sizeof (pkg_value);
358 if (*ret_buffer_len < packet_len)
359 return (ENOMEM);
361 pkg_type = htons (type);
362 pkg_length = htons ((uint16_t) packet_len);
363 pkg_value = htonll (value);
365 packet_ptr = *ret_buffer;
366 offset = 0;
367 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
368 offset += sizeof (pkg_type);
369 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
370 offset += sizeof (pkg_length);
371 memcpy (packet_ptr + offset, &pkg_value, sizeof (pkg_value));
372 offset += sizeof (pkg_value);
374 assert (offset == packet_len);
376 *ret_buffer = packet_ptr + packet_len;
377 *ret_buffer_len -= packet_len;
378 return (0);
379 } /* }}} int nb_add_number */
381 static int nb_add_time (char **ret_buffer, /* {{{ */
382 size_t *ret_buffer_len,
383 uint16_t type, double value)
384 {
385 /* Convert to collectd's "cdtime" representation. */
386 uint64_t cdtime_value = (uint64_t) (value * 1073741824.0);
387 return (nb_add_number (ret_buffer, ret_buffer_len, type, cdtime_value));
388 } /* }}} int nb_add_time */
390 static int nb_add_string (char **ret_buffer, /* {{{ */
391 size_t *ret_buffer_len,
392 uint16_t type, const char *str, size_t str_len)
393 {
394 char *packet_ptr;
395 size_t packet_len;
397 uint16_t pkg_type;
398 uint16_t pkg_length;
400 size_t offset;
402 packet_len = sizeof (pkg_type)
403 + sizeof (pkg_length)
404 + str_len + 1;
405 if (*ret_buffer_len < packet_len)
406 return (ENOMEM);
408 pkg_type = htons (type);
409 pkg_length = htons ((uint16_t) packet_len);
411 packet_ptr = *ret_buffer;
412 offset = 0;
413 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
414 offset += sizeof (pkg_type);
415 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
416 offset += sizeof (pkg_length);
417 memcpy (packet_ptr + offset, str, str_len);
418 offset += str_len;
419 memset (packet_ptr + offset, 0, 1);
420 offset += 1;
422 assert (offset == packet_len);
424 *ret_buffer = packet_ptr + packet_len;
425 *ret_buffer_len -= packet_len;
426 return (0);
427 } /* }}} int nb_add_string */
429 static int nb_add_value_list (lcc_network_buffer_t *nb, /* {{{ */
430 const lcc_value_list_t *vl)
431 {
432 char *buffer = nb->ptr;
433 size_t buffer_size = nb->free;
435 const lcc_identifier_t *ident_src;
436 lcc_identifier_t *ident_dst;
438 ident_src = &vl->identifier;
439 ident_dst = &nb->state.identifier;
441 if (strcmp (ident_dst->host, ident_src->host) != 0)
442 {
443 if (nb_add_string (&buffer, &buffer_size, TYPE_HOST,
444 ident_src->host, strlen (ident_src->host)) != 0)
445 return (-1);
446 SSTRNCPY (ident_dst->host, ident_src->host, sizeof (ident_dst->host));
447 }
449 if (strcmp (ident_dst->plugin, ident_src->plugin) != 0)
450 {
451 if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN,
452 ident_src->plugin, strlen (ident_src->plugin)) != 0)
453 return (-1);
454 SSTRNCPY (ident_dst->plugin, ident_src->plugin,
455 sizeof (ident_dst->plugin));
456 }
458 if (strcmp (ident_dst->plugin_instance,
459 ident_src->plugin_instance) != 0)
460 {
461 if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN_INSTANCE,
462 ident_src->plugin_instance,
463 strlen (ident_src->plugin_instance)) != 0)
464 return (-1);
465 SSTRNCPY (ident_dst->plugin_instance, ident_src->plugin_instance,
466 sizeof (ident_dst->plugin_instance));
467 }
469 if (strcmp (ident_dst->type, ident_src->type) != 0)
470 {
471 if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE,
472 ident_src->type, strlen (ident_src->type)) != 0)
473 return (-1);
474 SSTRNCPY (ident_dst->type, ident_src->type, sizeof (ident_dst->type));
475 }
477 if (strcmp (ident_dst->type_instance,
478 ident_src->type_instance) != 0)
479 {
480 if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE_INSTANCE,
481 ident_src->type_instance,
482 strlen (ident_src->type_instance)) != 0)
483 return (-1);
484 SSTRNCPY (ident_dst->type_instance, ident_src->type_instance,
485 sizeof (ident_dst->type_instance));
486 }
488 if (nb->state.time != vl->time)
489 {
490 if (nb_add_time (&buffer, &buffer_size, TYPE_TIME_HR, vl->time))
491 return (-1);
492 nb->state.time = vl->time;
493 }
495 if (nb->state.interval != vl->interval)
496 {
497 if (nb_add_time (&buffer, &buffer_size, TYPE_INTERVAL_HR, vl->interval))
498 return (-1);
499 nb->state.interval = vl->interval;
500 }
502 if (nb_add_values (&buffer, &buffer_size, vl) != 0)
503 return (-1);
505 nb->ptr = buffer;
506 nb->free = buffer_size;
507 return (0);
508 } /* }}} int nb_add_value_list */
510 #if HAVE_LIBGCRYPT
511 static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */
512 {
513 char *buffer;
514 size_t buffer_size;
516 gcry_md_hd_t hd;
517 gcry_error_t err;
518 unsigned char *hash;
519 const size_t hash_length = 32;
521 /* The type, length and username have already been filled in by
522 * "lcc_network_buffer_initialize". All we do here is calculate the hash over
523 * the username and the data and add the hash value to the buffer. */
525 buffer = nb->buffer + PART_SIGNATURE_SHA256_SIZE;
526 assert (nb->size >= (nb->free + PART_SIGNATURE_SHA256_SIZE));
527 buffer_size = nb->size - (nb->free + PART_SIGNATURE_SHA256_SIZE);
529 hd = NULL;
530 err = gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
531 if (err != 0)
532 return (-1);
534 assert (nb->password != NULL);
535 err = gcry_md_setkey (hd, nb->password, strlen (nb->password));
536 if (err != 0)
537 {
538 gcry_md_close (hd);
539 return (-1);
540 }
542 gcry_md_write (hd, buffer, buffer_size);
543 hash = gcry_md_read (hd, GCRY_MD_SHA256);
544 if (hash == NULL)
545 {
546 gcry_md_close (hd);
547 return (-1);
548 }
550 assert (((2 * sizeof (uint16_t)) + hash_length) == PART_SIGNATURE_SHA256_SIZE);
551 memcpy (nb->buffer + (2 * sizeof (uint16_t)), hash, hash_length);
553 gcry_md_close (hd);
554 return (0);
555 } /* }}} int nb_add_signature */
557 static int nb_add_encryption (lcc_network_buffer_t *nb) /* {{{ */
558 {
559 size_t package_length;
560 char *encr_ptr; /* pointer to data being encrypted */
561 size_t encr_size;
563 char *hash_ptr; /* pointer to data being hashed */
564 size_t hash_size;
565 char hash[20];
567 uint16_t pkg_length;
568 gcry_error_t err;
570 /* Fill in the package length */
571 package_length = nb->size - nb->free;
572 pkg_length = htons ((uint16_t) package_length);
573 memcpy (nb->buffer + 2, &pkg_length, sizeof (pkg_length));
575 /* Calculate what to hash */
576 hash_ptr = nb->buffer + PART_ENCRYPTION_AES256_SIZE;
577 hash_size = package_length - nb->encr_header_len;
579 /* Calculate what to encrypt */
580 encr_ptr = hash_ptr - sizeof (hash);
581 encr_size = hash_size + sizeof (hash);
583 /* Calculate the SHA-1 hash */
584 gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash_ptr, hash_size);
585 memcpy (encr_ptr, hash, sizeof (hash));
587 if (nb->encr_cypher == NULL)
588 {
589 unsigned char password_hash[32];
591 err = gcry_cipher_open (&nb->encr_cypher,
592 GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, /* flags = */ 0);
593 if (err != 0)
594 return (-1);
596 /* Calculate our 256bit key used for AES */
597 gcry_md_hash_buffer (GCRY_MD_SHA256, password_hash,
598 nb->password, strlen (nb->password));
600 err = gcry_cipher_setkey (nb->encr_cypher,
601 password_hash, sizeof (password_hash));
602 if (err != 0)
603 {
604 gcry_cipher_close (nb->encr_cypher);
605 nb->encr_cypher = NULL;
606 return (-1);
607 }
608 }
609 else /* if (nb->encr_cypher != NULL) */
610 {
611 gcry_cipher_reset (nb->encr_cypher);
612 }
614 /* Set the initialization vector */
615 err = gcry_cipher_setiv (nb->encr_cypher,
616 nb->encr_iv, sizeof (nb->encr_iv));
617 if (err != 0)
618 {
619 gcry_cipher_close (nb->encr_cypher);
620 nb->encr_cypher = NULL;
621 return (-1);
622 }
624 /* Encrypt the buffer in-place */
625 err = gcry_cipher_encrypt (nb->encr_cypher,
626 encr_ptr, encr_size,
627 /* in = */ NULL, /* in len = */ 0);
628 if (err != 0)
629 {
630 gcry_cipher_close (nb->encr_cypher);
631 nb->encr_cypher = NULL;
632 return (-1);
633 }
635 return (0);
636 } /* }}} int nb_add_encryption */
637 #endif
639 /*
640 * Public functions
641 */
642 lcc_network_buffer_t *lcc_network_buffer_create (size_t size) /* {{{ */
643 {
644 lcc_network_buffer_t *nb;
646 if (size == 0)
647 size = LCC_NETWORK_BUFFER_SIZE_DEFAULT;
649 if (size < 128)
650 {
651 errno = EINVAL;
652 return (NULL);
653 }
655 nb = calloc (1, sizeof (*nb));
656 if (nb == NULL)
657 return (NULL);
659 nb->size = size;
660 nb->buffer = calloc (1, nb->size);
661 if (nb->buffer == NULL)
662 {
663 free (nb);
664 return (NULL);
665 }
667 nb->ptr = nb->buffer;
668 nb->free = nb->size;
670 nb->seclevel = NONE;
671 nb->username = NULL;
672 nb->password = NULL;
674 return (nb);
675 } /* }}} lcc_network_buffer_t *lcc_network_buffer_create */
677 void lcc_network_buffer_destroy (lcc_network_buffer_t *nb) /* {{{ */
678 {
679 if (nb == NULL)
680 return;
682 free (nb->buffer);
683 free (nb);
684 } /* }}} void lcc_network_buffer_destroy */
686 int lcc_network_buffer_set_security_level (lcc_network_buffer_t *nb, /* {{{ */
687 lcc_security_level_t level,
688 const char *username, const char *password)
689 {
690 char *username_copy;
691 char *password_copy;
693 if (level == NONE)
694 {
695 free (nb->username);
696 free (nb->password);
697 nb->username = NULL;
698 nb->password = NULL;
699 nb->seclevel = NONE;
700 lcc_network_buffer_initialize (nb);
701 return (0);
702 }
704 if (!have_gcrypt ())
705 return (ENOTSUP);
707 username_copy = strdup (username);
708 password_copy = strdup (password);
709 if ((username_copy == NULL) || (password_copy == NULL))
710 {
711 free (username_copy);
712 free (password_copy);
713 return (ENOMEM);
714 }
716 free (nb->username);
717 free (nb->password);
718 nb->username = username_copy;
719 nb->password = password_copy;
720 nb->seclevel = level;
722 lcc_network_buffer_initialize (nb);
723 return (0);
724 } /* }}} int lcc_network_buffer_set_security_level */
726 int lcc_network_buffer_initialize (lcc_network_buffer_t *nb) /* {{{ */
727 {
728 if (nb == NULL)
729 return (EINVAL);
731 memset (nb->buffer, 0, nb->size);
732 memset (&nb->state, 0, sizeof (nb->state));
733 nb->ptr = nb->buffer;
734 nb->free = nb->size;
736 #if HAVE_LIBGCRYPT
737 if (nb->seclevel == SIGN)
738 {
739 size_t username_len;
740 uint16_t pkg_type = htons (TYPE_SIGN_SHA256);
741 uint16_t pkg_length = PART_SIGNATURE_SHA256_SIZE;
743 assert (nb->username != NULL);
744 username_len = strlen (nb->username);
745 pkg_length = htons (pkg_length + ((uint16_t) username_len));
747 /* Fill in everything but the hash value here. */
748 memcpy (nb->ptr, &pkg_type, sizeof (pkg_type));
749 memcpy (nb->ptr + sizeof (pkg_type), &pkg_length, sizeof (pkg_length));
750 nb->ptr += PART_SIGNATURE_SHA256_SIZE;
751 nb->free -= PART_SIGNATURE_SHA256_SIZE;
753 memcpy (nb->ptr, nb->username, username_len);
754 nb->ptr += username_len;
755 nb->free -= username_len;
756 }
757 else if (nb->seclevel == ENCRYPT)
758 {
759 size_t username_length = strlen (nb->username);
760 uint16_t pkg_type = htons (TYPE_ENCR_AES256);
761 uint16_t pkg_length = 0; /* Filled in in finalize. */
762 uint16_t pkg_user_len = htons ((uint16_t) username_length);
763 /* Filled in in finalize. */
764 char hash[20] = { 0 };
766 nb->encr_header_len = username_length;
767 nb->encr_header_len += PART_ENCRYPTION_AES256_SIZE;
769 gcry_randomize ((void *) &nb->encr_iv, sizeof (nb->encr_iv),
770 GCRY_STRONG_RANDOM);
772 ADD_STATIC (nb, pkg_type);
773 ADD_STATIC (nb, pkg_length);
774 ADD_STATIC (nb, pkg_user_len);
775 ADD_GENERIC (nb, nb->username, username_length);
776 ADD_GENERIC (nb, nb->encr_iv, sizeof (nb->encr_iv));
777 ADD_GENERIC (nb, hash, sizeof (hash));
778 assert ((nb->encr_header_len + nb->free) == nb->size);
779 }
780 #endif
782 return (0);
783 } /* }}} int lcc_network_buffer_initialize */
785 int lcc_network_buffer_finalize (lcc_network_buffer_t *nb) /* {{{ */
786 {
787 if (nb == NULL)
788 return (EINVAL);
790 #if HAVE_LIBGCRYPT
791 if (nb->seclevel == SIGN)
792 return nb_add_signature (nb);
793 else if (nb->seclevel == ENCRYPT)
794 return nb_add_encryption (nb);
795 #endif
797 return (0);
798 } /* }}} int lcc_network_buffer_finalize */
800 int lcc_network_buffer_add_value (lcc_network_buffer_t *nb, /* {{{ */
801 const lcc_value_list_t *vl)
802 {
803 int status;
805 if ((nb == NULL) || (vl == NULL))
806 return (EINVAL);
808 status = nb_add_value_list (nb, vl);
809 return (status);
810 } /* }}} int lcc_network_buffer_add_value */
812 int lcc_network_buffer_get (lcc_network_buffer_t *nb, /* {{{ */
813 void *buffer, size_t *buffer_size)
814 {
815 size_t sz_required;
816 size_t sz_available;
818 if ((nb == NULL) || (buffer_size == NULL))
819 return (EINVAL);
821 assert (nb->size >= nb->free);
822 sz_required = nb->size - nb->free;
823 sz_available = *buffer_size;
825 *buffer_size = sz_required;
826 if (buffer != NULL)
827 memcpy (buffer, nb->buffer,
828 (sz_available < sz_required) ? sz_available : sz_required);
830 return (0);
831 } /* }}} int lcc_network_buffer_get */
833 /* vim: set sw=2 sts=2 et fdm=marker : */