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 # 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 # if GCRYPT_VERSION_NUMBER < 0x010600
58 GCRY_THREAD_OPTION_PTHREAD_IMPL;
59 # endif
60 #endif
62 #include "collectd/network_buffer.h"
64 #define TYPE_HOST 0x0000
65 #define TYPE_TIME 0x0001
66 #define TYPE_TIME_HR 0x0008
67 #define TYPE_PLUGIN 0x0002
68 #define TYPE_PLUGIN_INSTANCE 0x0003
69 #define TYPE_TYPE 0x0004
70 #define TYPE_TYPE_INSTANCE 0x0005
71 #define TYPE_VALUES 0x0006
72 #define TYPE_INTERVAL 0x0007
73 #define TYPE_INTERVAL_HR 0x0009
75 /* Types to transmit notifications */
76 #define TYPE_MESSAGE 0x0100
77 #define TYPE_SEVERITY 0x0101
79 #define TYPE_SIGN_SHA256 0x0200
80 #define TYPE_ENCR_AES256 0x0210
82 #define PART_SIGNATURE_SHA256_SIZE 36
83 #define PART_ENCRYPTION_AES256_SIZE 42
85 #define ADD_GENERIC(nb,srcptr,size) do { \
86 assert ((size) <= (nb)->free); \
87 memcpy ((nb)->ptr, (srcptr), (size)); \
88 (nb)->ptr += (size); \
89 (nb)->free -= (size); \
90 } while (0)
92 #define ADD_STATIC(nb,var) \
93 ADD_GENERIC(nb,&(var),sizeof(var));
95 /*
96 * Data types
97 */
98 struct lcc_network_buffer_s
99 {
100 char *buffer;
101 size_t size;
103 lcc_value_list_t state;
104 char *ptr;
105 size_t free;
107 lcc_security_level_t seclevel;
108 char *username;
109 char *password;
111 #if HAVE_LIBGCRYPT
112 gcry_cipher_hd_t encr_cypher;
113 size_t encr_header_len;
114 char encr_iv[16];
115 #endif
116 };
118 #define SSTRNCPY(dst,src,sz) do { \
119 strncpy ((dst), (src), (sz)); \
120 (dst)[(sz) - 1] = 0; \
121 } while (0)
123 /*
124 * Private functions
125 */
126 static _Bool have_gcrypt (void) /* {{{ */
127 {
128 static _Bool result = 0;
129 static _Bool need_init = 1;
131 if (!need_init)
132 return (result);
133 need_init = 0;
135 #if HAVE_LIBGCRYPT
136 # if GCRYPT_VERSION_NUMBER < 0x010600
137 if (gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread))
138 return (0);
139 # endif
141 if (!gcry_check_version (GCRYPT_VERSION))
142 return (0);
144 if (!gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0))
145 return (0);
147 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
149 result = 1;
150 return (1);
151 #else
152 return(0);
153 #endif
154 } /* }}} _Bool have_gcrypt */
156 #ifndef HAVE_HTONLL
157 static uint64_t htonll (uint64_t val) /* {{{ */
158 {
159 static int config = 0;
161 uint32_t hi;
162 uint32_t lo;
164 if (config == 0)
165 {
166 uint16_t h = 0x1234;
167 uint16_t n = htons (h);
169 if (h == n)
170 config = 1;
171 else
172 config = 2;
173 }
175 if (config == 1)
176 return (val);
178 hi = (uint32_t) (val >> 32);
179 lo = (uint32_t) (val & 0x00000000FFFFFFFF);
181 hi = htonl (hi);
182 lo = htonl (lo);
184 return ((((uint64_t) lo) << 32) | ((uint64_t) hi));
185 } /* }}} uint64_t htonll */
186 #endif
188 static double htond (double val) /* {{{ */
189 {
190 static int config = 0;
192 union { uint8_t byte[8]; double floating; } in;
193 union { uint8_t byte[8]; double floating; } out;
195 if (config == 0)
196 {
197 double d = 8.642135e130;
198 uint8_t c[8];
200 memcpy (c, &d, 8);
202 if ((c[0] == 0x2f) && (c[1] == 0x25)
203 && (c[2] == 0xc0) && (c[3] == 0xc7)
204 && (c[4] == 0x43) && (c[5] == 0x2b)
205 && (c[6] == 0x1f) && (c[7] == 0x5b))
206 config = 1; /* need nothing */
207 else if ((c[7] == 0x2f) && (c[6] == 0x25)
208 && (c[5] == 0xc0) && (c[4] == 0xc7)
209 && (c[3] == 0x43) && (c[2] == 0x2b)
210 && (c[1] == 0x1f) && (c[0] == 0x5b))
211 config = 2; /* endian flip */
212 else if ((c[4] == 0x2f) && (c[5] == 0x25)
213 && (c[6] == 0xc0) && (c[7] == 0xc7)
214 && (c[0] == 0x43) && (c[1] == 0x2b)
215 && (c[2] == 0x1f) && (c[3] == 0x5b))
216 config = 3; /* int swap */
217 else
218 config = 4;
219 }
221 if (isnan (val))
222 {
223 out.byte[0] = out.byte[1] = out.byte[2] = out.byte[3] = 0x00;
224 out.byte[4] = out.byte[5] = 0x00;
225 out.byte[6] = 0xf8;
226 out.byte[7] = 0x7f;
227 return (out.floating);
228 }
229 else if (config == 1)
230 return (val);
231 else if (config == 2)
232 {
233 in.floating = val;
234 out.byte[0] = in.byte[7];
235 out.byte[1] = in.byte[6];
236 out.byte[2] = in.byte[5];
237 out.byte[3] = in.byte[4];
238 out.byte[4] = in.byte[3];
239 out.byte[5] = in.byte[2];
240 out.byte[6] = in.byte[1];
241 out.byte[7] = in.byte[0];
242 return (out.floating);
243 }
244 else if (config == 3)
245 {
246 in.floating = val;
247 out.byte[0] = in.byte[4];
248 out.byte[1] = in.byte[5];
249 out.byte[2] = in.byte[6];
250 out.byte[3] = in.byte[7];
251 out.byte[4] = in.byte[0];
252 out.byte[5] = in.byte[1];
253 out.byte[6] = in.byte[2];
254 out.byte[7] = in.byte[3];
255 return (out.floating);
256 }
257 else
258 {
259 /* If in doubt, just copy the value back to the caller. */
260 return (val);
261 }
262 } /* }}} double htond */
264 static int nb_add_values (char **ret_buffer, /* {{{ */
265 size_t *ret_buffer_len,
266 const lcc_value_list_t *vl)
267 {
268 char *packet_ptr;
269 size_t packet_len;
271 uint16_t pkg_type;
272 uint16_t pkg_length;
273 uint16_t pkg_num_values;
274 uint8_t pkg_values_types[vl->values_len];
275 value_t pkg_values[vl->values_len];
277 size_t offset;
278 size_t i;
280 packet_len = sizeof (pkg_type) + sizeof (pkg_length)
281 + sizeof (pkg_num_values)
282 + sizeof (pkg_values_types)
283 + sizeof (pkg_values);
285 if (*ret_buffer_len < packet_len)
286 return (ENOMEM);
288 pkg_type = htons (TYPE_VALUES);
289 pkg_length = htons ((uint16_t) packet_len);
290 pkg_num_values = htons ((uint16_t) vl->values_len);
292 for (i = 0; i < vl->values_len; i++)
293 {
294 pkg_values_types[i] = (uint8_t) vl->values_types[i];
295 switch (vl->values_types[i])
296 {
297 case LCC_TYPE_COUNTER:
298 pkg_values[i].counter = (counter_t) htonll (vl->values[i].counter);
299 break;
301 case LCC_TYPE_GAUGE:
302 pkg_values[i].gauge = (gauge_t) htond (vl->values[i].gauge);
303 break;
305 case LCC_TYPE_DERIVE:
306 pkg_values[i].derive = (derive_t) htonll (vl->values[i].derive);
307 break;
309 case LCC_TYPE_ABSOLUTE:
310 pkg_values[i].absolute = (absolute_t) htonll (vl->values[i].absolute);
311 break;
313 default:
314 return (EINVAL);
315 } /* switch (vl->values_types[i]) */
316 } /* for (vl->values_len) */
318 /*
319 * Use `memcpy' to write everything to the buffer, because the pointer
320 * may be unaligned and some architectures, such as SPARC, can't handle
321 * that.
322 */
323 packet_ptr = *ret_buffer;
324 offset = 0;
325 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
326 offset += sizeof (pkg_type);
327 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
328 offset += sizeof (pkg_length);
329 memcpy (packet_ptr + offset, &pkg_num_values, sizeof (pkg_num_values));
330 offset += sizeof (pkg_num_values);
331 memcpy (packet_ptr + offset, pkg_values_types, sizeof (pkg_values_types));
332 offset += sizeof (pkg_values_types);
333 memcpy (packet_ptr + offset, pkg_values, sizeof (pkg_values));
334 offset += sizeof (pkg_values);
336 assert (offset == packet_len);
338 *ret_buffer = packet_ptr + packet_len;
339 *ret_buffer_len -= packet_len;
340 return (0);
341 } /* }}} int nb_add_values */
343 static int nb_add_number (char **ret_buffer, /* {{{ */
344 size_t *ret_buffer_len,
345 uint16_t type, uint64_t value)
346 {
347 char *packet_ptr;
348 size_t packet_len;
350 uint16_t pkg_type;
351 uint16_t pkg_length;
352 uint64_t pkg_value;
354 size_t offset;
356 packet_len = sizeof (pkg_type)
357 + sizeof (pkg_length)
358 + sizeof (pkg_value);
360 if (*ret_buffer_len < packet_len)
361 return (ENOMEM);
363 pkg_type = htons (type);
364 pkg_length = htons ((uint16_t) packet_len);
365 pkg_value = htonll (value);
367 packet_ptr = *ret_buffer;
368 offset = 0;
369 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
370 offset += sizeof (pkg_type);
371 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
372 offset += sizeof (pkg_length);
373 memcpy (packet_ptr + offset, &pkg_value, sizeof (pkg_value));
374 offset += sizeof (pkg_value);
376 assert (offset == packet_len);
378 *ret_buffer = packet_ptr + packet_len;
379 *ret_buffer_len -= packet_len;
380 return (0);
381 } /* }}} int nb_add_number */
383 static int nb_add_time (char **ret_buffer, /* {{{ */
384 size_t *ret_buffer_len,
385 uint16_t type, double value)
386 {
387 /* Convert to collectd's "cdtime" representation. */
388 uint64_t cdtime_value = (uint64_t) (value * 1073741824.0);
389 return (nb_add_number (ret_buffer, ret_buffer_len, type, cdtime_value));
390 } /* }}} int nb_add_time */
392 static int nb_add_string (char **ret_buffer, /* {{{ */
393 size_t *ret_buffer_len,
394 uint16_t type, const char *str, size_t str_len)
395 {
396 char *packet_ptr;
397 size_t packet_len;
399 uint16_t pkg_type;
400 uint16_t pkg_length;
402 size_t offset;
404 packet_len = sizeof (pkg_type)
405 + sizeof (pkg_length)
406 + str_len + 1;
407 if (*ret_buffer_len < packet_len)
408 return (ENOMEM);
410 pkg_type = htons (type);
411 pkg_length = htons ((uint16_t) packet_len);
413 packet_ptr = *ret_buffer;
414 offset = 0;
415 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
416 offset += sizeof (pkg_type);
417 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
418 offset += sizeof (pkg_length);
419 memcpy (packet_ptr + offset, str, str_len);
420 offset += str_len;
421 memset (packet_ptr + offset, 0, 1);
422 offset += 1;
424 assert (offset == packet_len);
426 *ret_buffer = packet_ptr + packet_len;
427 *ret_buffer_len -= packet_len;
428 return (0);
429 } /* }}} int nb_add_string */
431 static int nb_add_value_list (lcc_network_buffer_t *nb, /* {{{ */
432 const lcc_value_list_t *vl)
433 {
434 char *buffer = nb->ptr;
435 size_t buffer_size = nb->free;
437 const lcc_identifier_t *ident_src;
438 lcc_identifier_t *ident_dst;
440 ident_src = &vl->identifier;
441 ident_dst = &nb->state.identifier;
443 if (strcmp (ident_dst->host, ident_src->host) != 0)
444 {
445 if (nb_add_string (&buffer, &buffer_size, TYPE_HOST,
446 ident_src->host, strlen (ident_src->host)) != 0)
447 return (-1);
448 SSTRNCPY (ident_dst->host, ident_src->host, sizeof (ident_dst->host));
449 }
451 if (strcmp (ident_dst->plugin, ident_src->plugin) != 0)
452 {
453 if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN,
454 ident_src->plugin, strlen (ident_src->plugin)) != 0)
455 return (-1);
456 SSTRNCPY (ident_dst->plugin, ident_src->plugin,
457 sizeof (ident_dst->plugin));
458 }
460 if (strcmp (ident_dst->plugin_instance,
461 ident_src->plugin_instance) != 0)
462 {
463 if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN_INSTANCE,
464 ident_src->plugin_instance,
465 strlen (ident_src->plugin_instance)) != 0)
466 return (-1);
467 SSTRNCPY (ident_dst->plugin_instance, ident_src->plugin_instance,
468 sizeof (ident_dst->plugin_instance));
469 }
471 if (strcmp (ident_dst->type, ident_src->type) != 0)
472 {
473 if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE,
474 ident_src->type, strlen (ident_src->type)) != 0)
475 return (-1);
476 SSTRNCPY (ident_dst->type, ident_src->type, sizeof (ident_dst->type));
477 }
479 if (strcmp (ident_dst->type_instance,
480 ident_src->type_instance) != 0)
481 {
482 if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE_INSTANCE,
483 ident_src->type_instance,
484 strlen (ident_src->type_instance)) != 0)
485 return (-1);
486 SSTRNCPY (ident_dst->type_instance, ident_src->type_instance,
487 sizeof (ident_dst->type_instance));
488 }
490 if (nb->state.time != vl->time)
491 {
492 if (nb_add_time (&buffer, &buffer_size, TYPE_TIME_HR, vl->time))
493 return (-1);
494 nb->state.time = vl->time;
495 }
497 if (nb->state.interval != vl->interval)
498 {
499 if (nb_add_time (&buffer, &buffer_size, TYPE_INTERVAL_HR, vl->interval))
500 return (-1);
501 nb->state.interval = vl->interval;
502 }
504 if (nb_add_values (&buffer, &buffer_size, vl) != 0)
505 return (-1);
507 nb->ptr = buffer;
508 nb->free = buffer_size;
509 return (0);
510 } /* }}} int nb_add_value_list */
512 #if HAVE_LIBGCRYPT
513 static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */
514 {
515 char *buffer;
516 size_t buffer_size;
518 gcry_md_hd_t hd;
519 gcry_error_t err;
520 unsigned char *hash;
521 const size_t hash_length = 32;
523 /* The type, length and username have already been filled in by
524 * "lcc_network_buffer_initialize". All we do here is calculate the hash over
525 * the username and the data and add the hash value to the buffer. */
527 buffer = nb->buffer + PART_SIGNATURE_SHA256_SIZE;
528 assert (nb->size >= (nb->free + PART_SIGNATURE_SHA256_SIZE));
529 buffer_size = nb->size - (nb->free + PART_SIGNATURE_SHA256_SIZE);
531 hd = NULL;
532 err = gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
533 if (err != 0)
534 return (-1);
536 assert (nb->password != NULL);
537 err = gcry_md_setkey (hd, nb->password, strlen (nb->password));
538 if (err != 0)
539 {
540 gcry_md_close (hd);
541 return (-1);
542 }
544 gcry_md_write (hd, buffer, buffer_size);
545 hash = gcry_md_read (hd, GCRY_MD_SHA256);
546 if (hash == NULL)
547 {
548 gcry_md_close (hd);
549 return (-1);
550 }
552 assert (((2 * sizeof (uint16_t)) + hash_length) == PART_SIGNATURE_SHA256_SIZE);
553 memcpy (nb->buffer + (2 * sizeof (uint16_t)), hash, hash_length);
555 gcry_md_close (hd);
556 return (0);
557 } /* }}} int nb_add_signature */
559 static int nb_add_encryption (lcc_network_buffer_t *nb) /* {{{ */
560 {
561 size_t package_length;
562 char *encr_ptr; /* pointer to data being encrypted */
563 size_t encr_size;
565 char *hash_ptr; /* pointer to data being hashed */
566 size_t hash_size;
567 char hash[20];
569 uint16_t pkg_length;
570 gcry_error_t err;
572 /* Fill in the package length */
573 package_length = nb->size - nb->free;
574 pkg_length = htons ((uint16_t) package_length);
575 memcpy (nb->buffer + 2, &pkg_length, sizeof (pkg_length));
577 /* Calculate what to hash */
578 hash_ptr = nb->buffer + PART_ENCRYPTION_AES256_SIZE;
579 hash_size = package_length - nb->encr_header_len;
581 /* Calculate what to encrypt */
582 encr_ptr = hash_ptr - sizeof (hash);
583 encr_size = hash_size + sizeof (hash);
585 /* Calculate the SHA-1 hash */
586 gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash_ptr, hash_size);
587 memcpy (encr_ptr, hash, sizeof (hash));
589 if (nb->encr_cypher == NULL)
590 {
591 unsigned char password_hash[32];
593 err = gcry_cipher_open (&nb->encr_cypher,
594 GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, /* flags = */ 0);
595 if (err != 0)
596 return (-1);
598 /* Calculate our 256bit key used for AES */
599 gcry_md_hash_buffer (GCRY_MD_SHA256, password_hash,
600 nb->password, strlen (nb->password));
602 err = gcry_cipher_setkey (nb->encr_cypher,
603 password_hash, sizeof (password_hash));
604 if (err != 0)
605 {
606 gcry_cipher_close (nb->encr_cypher);
607 nb->encr_cypher = NULL;
608 return (-1);
609 }
610 }
611 else /* if (nb->encr_cypher != NULL) */
612 {
613 gcry_cipher_reset (nb->encr_cypher);
614 }
616 /* Set the initialization vector */
617 err = gcry_cipher_setiv (nb->encr_cypher,
618 nb->encr_iv, sizeof (nb->encr_iv));
619 if (err != 0)
620 {
621 gcry_cipher_close (nb->encr_cypher);
622 nb->encr_cypher = NULL;
623 return (-1);
624 }
626 /* Encrypt the buffer in-place */
627 err = gcry_cipher_encrypt (nb->encr_cypher,
628 encr_ptr, encr_size,
629 /* in = */ NULL, /* in len = */ 0);
630 if (err != 0)
631 {
632 gcry_cipher_close (nb->encr_cypher);
633 nb->encr_cypher = NULL;
634 return (-1);
635 }
637 return (0);
638 } /* }}} int nb_add_encryption */
639 #endif
641 /*
642 * Public functions
643 */
644 lcc_network_buffer_t *lcc_network_buffer_create (size_t size) /* {{{ */
645 {
646 lcc_network_buffer_t *nb;
648 if (size == 0)
649 size = LCC_NETWORK_BUFFER_SIZE_DEFAULT;
651 if (size < 128)
652 {
653 errno = EINVAL;
654 return (NULL);
655 }
657 nb = malloc (sizeof (*nb));
658 if (nb == NULL)
659 return (NULL);
660 memset (nb, 0, sizeof (*nb));
662 nb->size = size;
663 nb->buffer = malloc (nb->size);
664 if (nb->buffer == NULL)
665 {
666 free (nb);
667 return (NULL);
668 }
669 memset (nb->buffer, 0, nb->size);
671 nb->ptr = nb->buffer;
672 nb->free = nb->size;
674 nb->seclevel = NONE;
675 nb->username = NULL;
676 nb->password = NULL;
678 return (nb);
679 } /* }}} lcc_network_buffer_t *lcc_network_buffer_create */
681 void lcc_network_buffer_destroy (lcc_network_buffer_t *nb) /* {{{ */
682 {
683 if (nb == NULL)
684 return;
686 free (nb->buffer);
687 free (nb);
688 } /* }}} void lcc_network_buffer_destroy */
690 int lcc_network_buffer_set_security_level (lcc_network_buffer_t *nb, /* {{{ */
691 lcc_security_level_t level,
692 const char *username, const char *password)
693 {
694 char *username_copy;
695 char *password_copy;
697 if (level == NONE)
698 {
699 free (nb->username);
700 free (nb->password);
701 nb->username = NULL;
702 nb->password = NULL;
703 nb->seclevel = NONE;
704 lcc_network_buffer_initialize (nb);
705 return (0);
706 }
708 if (!have_gcrypt ())
709 return (ENOTSUP);
711 username_copy = strdup (username);
712 password_copy = strdup (password);
713 if ((username_copy == NULL) || (password_copy == NULL))
714 {
715 free (username_copy);
716 free (password_copy);
717 return (ENOMEM);
718 }
720 free (nb->username);
721 free (nb->password);
722 nb->username = username_copy;
723 nb->password = password_copy;
724 nb->seclevel = level;
726 lcc_network_buffer_initialize (nb);
727 return (0);
728 } /* }}} int lcc_network_buffer_set_security_level */
730 int lcc_network_buffer_initialize (lcc_network_buffer_t *nb) /* {{{ */
731 {
732 if (nb == NULL)
733 return (EINVAL);
735 memset (nb->buffer, 0, nb->size);
736 memset (&nb->state, 0, sizeof (nb->state));
737 nb->ptr = nb->buffer;
738 nb->free = nb->size;
740 #if HAVE_LIBGCRYPT
741 if (nb->seclevel == SIGN)
742 {
743 size_t username_len;
744 uint16_t pkg_type = htons (TYPE_SIGN_SHA256);
745 uint16_t pkg_length = PART_SIGNATURE_SHA256_SIZE;
747 assert (nb->username != NULL);
748 username_len = strlen (nb->username);
749 pkg_length = htons (pkg_length + ((uint16_t) username_len));
751 /* Fill in everything but the hash value here. */
752 memcpy (nb->ptr, &pkg_type, sizeof (pkg_type));
753 memcpy (nb->ptr + sizeof (pkg_type), &pkg_length, sizeof (pkg_length));
754 nb->ptr += PART_SIGNATURE_SHA256_SIZE;
755 nb->free -= PART_SIGNATURE_SHA256_SIZE;
757 memcpy (nb->ptr, nb->username, username_len);
758 nb->ptr += username_len;
759 nb->free -= username_len;
760 }
761 else if (nb->seclevel == ENCRYPT)
762 {
763 size_t username_length = strlen (nb->username);
764 uint16_t pkg_type = htons (TYPE_ENCR_AES256);
765 uint16_t pkg_length = 0; /* Filled in in finalize. */
766 uint16_t pkg_user_len = htons ((uint16_t) username_length);
767 char hash[20];
769 nb->encr_header_len = username_length;
770 nb->encr_header_len += PART_ENCRYPTION_AES256_SIZE;
772 gcry_randomize ((void *) &nb->encr_iv, sizeof (nb->encr_iv),
773 GCRY_STRONG_RANDOM);
775 /* Filled in in finalize. */
776 memset (hash, 0, sizeof (hash));
778 ADD_STATIC (nb, pkg_type);
779 ADD_STATIC (nb, pkg_length);
780 ADD_STATIC (nb, pkg_user_len);
781 ADD_GENERIC (nb, nb->username, username_length);
782 ADD_GENERIC (nb, nb->encr_iv, sizeof (nb->encr_iv));
783 ADD_GENERIC (nb, hash, sizeof (hash));
784 assert ((nb->encr_header_len + nb->free) == nb->size);
785 }
786 #endif
788 return (0);
789 } /* }}} int lcc_network_buffer_initialize */
791 int lcc_network_buffer_finalize (lcc_network_buffer_t *nb) /* {{{ */
792 {
793 if (nb == NULL)
794 return (EINVAL);
796 #if HAVE_LIBGCRYPT
797 if (nb->seclevel == SIGN)
798 return nb_add_signature (nb);
799 else if (nb->seclevel == ENCRYPT)
800 return nb_add_encryption (nb);
801 #endif
803 return (0);
804 } /* }}} int lcc_network_buffer_finalize */
806 int lcc_network_buffer_add_value (lcc_network_buffer_t *nb, /* {{{ */
807 const lcc_value_list_t *vl)
808 {
809 int status;
811 if ((nb == NULL) || (vl == NULL))
812 return (EINVAL);
814 status = nb_add_value_list (nb, vl);
815 return (status);
816 } /* }}} int lcc_network_buffer_add_value */
818 int lcc_network_buffer_get (lcc_network_buffer_t *nb, /* {{{ */
819 void *buffer, size_t *buffer_size)
820 {
821 size_t sz_required;
822 size_t sz_available;
824 if ((nb == NULL) || (buffer_size == NULL))
825 return (EINVAL);
827 assert (nb->size >= nb->free);
828 sz_required = nb->size - nb->free;
829 sz_available = *buffer_size;
831 *buffer_size = sz_required;
832 if (buffer != NULL)
833 memcpy (buffer, nb->buffer,
834 (sz_available < sz_required) ? sz_available : sz_required);
836 return (0);
837 } /* }}} int lcc_network_buffer_get */
839 /* vim: set sw=2 sts=2 et fdm=marker : */