Merge branch 'collectd-5.7' into collectd-5.8
[collectd.git] / src / libcollectdclient / network_parse.c
1 /**
2  * Copyright 2017 Florian Forster
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  *
22  * Authors:
23  *   Florian octo Forster <octo at collectd.org>
24  **/
25
26 #include "config.h"
27
28 #if !defined(__GNUC__) || !__GNUC__
29 #define __attribute__(x) /**/
30 #endif
31
32 #include "collectd/lcc_features.h"
33 #include "collectd/network_parse.h"
34
35 #include <errno.h>
36 #include <math.h>
37 #include <pthread.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 /* for be{16,64}toh */
42 #if HAVE_ENDIAN_H
43 #include <endian.h>
44 #elif HAVE_SYS_ENDIAN_H
45 #include <sys/endian.h>
46 #else /* fallback */
47 #include "collectd/stdendian.h"
48 #endif
49
50 #if HAVE_GCRYPT_H
51 #define GCRYPT_NO_DEPRECATED
52 #include <gcrypt.h>
53 #endif
54
55 #include <stdio.h>
56 #define DEBUG(...) printf(__VA_ARGS__)
57
58 #if HAVE_GCRYPT_H
59 #if GCRYPT_VERSION_NUMBER < 0x010600
60 GCRY_THREAD_OPTION_PTHREAD_IMPL;
61 #endif
62 #endif
63
64 /* forward declaration because parse_sign_sha256()/parse_encrypt_aes256() and
65  * network_parse() need to call each other. */
66 static int network_parse(void *data, size_t data_size, lcc_security_level_t sl,
67                          lcc_network_parse_options_t const *opts);
68
69 #if HAVE_GCRYPT_H
70 static int init_gcrypt() {
71   /* http://lists.gnupg.org/pipermail/gcrypt-devel/2003-August/000458.html
72    * Because you can't know in a library whether another library has
73    * already initialized the library */
74   if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P))
75     return (0);
76
77 /* http://www.gnupg.org/documentation/manuals/gcrypt/Multi_002dThreading.html
78  * To ensure thread-safety, it's important to set GCRYCTL_SET_THREAD_CBS
79  * *before* initalizing Libgcrypt with gcry_check_version(), which itself must
80  * be called before any other gcry_* function. GCRYCTL_ANY_INITIALIZATION_P
81  * above doesn't count, as it doesn't implicitly initalize Libgcrypt.
82  *
83  * tl;dr: keep all these gry_* statements in this exact order please. */
84 #if GCRYPT_VERSION_NUMBER < 0x010600
85   if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread)) {
86     return -1;
87   }
88 #endif
89
90   gcry_check_version(NULL);
91
92   if (gcry_control(GCRYCTL_INIT_SECMEM, 32768)) {
93     return -1;
94   }
95
96   gcry_control(GCRYCTL_INITIALIZATION_FINISHED);
97   return 0;
98 }
99 #endif
100
101 typedef struct {
102   uint8_t *data;
103   size_t len;
104 } buffer_t;
105
106 static int buffer_next(buffer_t *b, void *out, size_t n) {
107   if (b->len < n) {
108     return -1;
109   }
110   memmove(out, b->data, n);
111
112   b->data += n;
113   b->len -= n;
114
115   return 0;
116 }
117
118 static int buffer_uint16(buffer_t *b, uint16_t *out) {
119   uint16_t tmp;
120   if (buffer_next(b, &tmp, sizeof(tmp)) != 0)
121     return -1;
122
123   *out = be16toh(tmp);
124   return 0;
125 }
126
127 #define TYPE_HOST 0x0000
128 #define TYPE_TIME 0x0001
129 #define TYPE_TIME_HR 0x0008
130 #define TYPE_PLUGIN 0x0002
131 #define TYPE_PLUGIN_INSTANCE 0x0003
132 #define TYPE_TYPE 0x0004
133 #define TYPE_TYPE_INSTANCE 0x0005
134 #define TYPE_VALUES 0x0006
135 #define TYPE_INTERVAL 0x0007
136 #define TYPE_INTERVAL_HR 0x0009
137 #define TYPE_SIGN_SHA256 0x0200
138 #define TYPE_ENCR_AES256 0x0210
139
140 static int parse_int(void *payload, size_t payload_size, uint64_t *out) {
141   uint64_t tmp;
142
143   if (payload_size != sizeof(tmp))
144     return EINVAL;
145
146   memmove(&tmp, payload, sizeof(tmp));
147   *out = be64toh(tmp);
148   return 0;
149 }
150
151 static int parse_string(void *payload, size_t payload_size, char *out,
152                         size_t out_size) {
153   char *in = payload;
154
155   if ((payload_size < 1) || (in[payload_size - 1] != 0) ||
156       (payload_size > out_size))
157     return EINVAL;
158
159   strncpy(out, in, out_size);
160   return 0;
161 }
162
163 static int parse_identifier(uint16_t type, void *payload, size_t payload_size,
164                             lcc_value_list_t *state) {
165   char buf[LCC_NAME_LEN];
166
167   if (parse_string(payload, payload_size, buf, sizeof(buf)) != 0)
168     return EINVAL;
169
170   switch (type) {
171   case TYPE_HOST:
172     memmove(state->identifier.host, buf, LCC_NAME_LEN);
173     break;
174   case TYPE_PLUGIN:
175     memmove(state->identifier.plugin, buf, LCC_NAME_LEN);
176     break;
177   case TYPE_PLUGIN_INSTANCE:
178     memmove(state->identifier.plugin_instance, buf, LCC_NAME_LEN);
179     break;
180   case TYPE_TYPE:
181     memmove(state->identifier.type, buf, LCC_NAME_LEN);
182     break;
183   case TYPE_TYPE_INSTANCE:
184     memmove(state->identifier.type_instance, buf, LCC_NAME_LEN);
185     break;
186   default:
187     return EINVAL;
188   }
189
190   return 0;
191 }
192
193 static int parse_time(uint16_t type, void *payload, size_t payload_size,
194                       lcc_value_list_t *state) {
195   uint64_t tmp = 0;
196   if (parse_int(payload, payload_size, &tmp))
197     return EINVAL;
198
199   double t = (double)tmp;
200   switch (type) {
201   case TYPE_INTERVAL:
202     state->interval = t;
203     break;
204   case TYPE_INTERVAL_HR:
205     state->interval = t / 1073741824.0;
206     break;
207   case TYPE_TIME:
208     state->time = t;
209     break;
210   case TYPE_TIME_HR:
211     state->time = t / 1073741824.0;
212     break;
213   default:
214     return EINVAL;
215   }
216
217   return 0;
218 }
219
220 static double ntohd(double val) /* {{{ */
221 {
222   static int config = 0;
223
224   union {
225     uint8_t byte[8];
226     double floating;
227   } in = {
228       .floating = val,
229   };
230   union {
231     uint8_t byte[8];
232     double floating;
233   } out = {
234       .byte = {0},
235   };
236
237   if (config == 0) {
238     double d = 8.642135e130;
239     uint8_t b[8];
240
241     memcpy(b, &d, sizeof(b));
242
243     if ((b[0] == 0x2f) && (b[1] == 0x25) && (b[2] == 0xc0) && (b[3] == 0xc7) &&
244         (b[4] == 0x43) && (b[5] == 0x2b) && (b[6] == 0x1f) && (b[7] == 0x5b))
245       config = 1; /* need nothing */
246     else if ((b[7] == 0x2f) && (b[6] == 0x25) && (b[5] == 0xc0) &&
247              (b[4] == 0xc7) && (b[3] == 0x43) && (b[2] == 0x2b) &&
248              (b[1] == 0x1f) && (b[0] == 0x5b))
249       config = 2; /* endian flip */
250     else if ((b[4] == 0x2f) && (b[5] == 0x25) && (b[6] == 0xc0) &&
251              (b[7] == 0xc7) && (b[0] == 0x43) && (b[1] == 0x2b) &&
252              (b[2] == 0x1f) && (b[3] == 0x5b))
253       config = 3; /* int swap */
254     else
255       config = 4;
256   }
257
258   if (memcmp((char[]){0, 0, 0, 0, 0, 0, 0xf8, 0x7f}, in.byte, 8) == 0) {
259     return NAN;
260   } else if (config == 1) {
261     return val;
262   } else if (config == 2) {
263     in.floating = val;
264     out.byte[0] = in.byte[7];
265     out.byte[1] = in.byte[6];
266     out.byte[2] = in.byte[5];
267     out.byte[3] = in.byte[4];
268     out.byte[4] = in.byte[3];
269     out.byte[5] = in.byte[2];
270     out.byte[6] = in.byte[1];
271     out.byte[7] = in.byte[0];
272     return (out.floating);
273   } else if (config == 3) {
274     in.floating = val;
275     out.byte[0] = in.byte[4];
276     out.byte[1] = in.byte[5];
277     out.byte[2] = in.byte[6];
278     out.byte[3] = in.byte[7];
279     out.byte[4] = in.byte[0];
280     out.byte[5] = in.byte[1];
281     out.byte[6] = in.byte[2];
282     out.byte[7] = in.byte[3];
283     return out.floating;
284   } else {
285     /* If in doubt, just copy the value back to the caller. */
286     return val;
287   }
288 } /* }}} double ntohd */
289
290 static int parse_values(void *payload, size_t payload_size,
291                         lcc_value_list_t *state) {
292   buffer_t *b = &(buffer_t){
293       .data = payload, .len = payload_size,
294   };
295
296   uint16_t n;
297   if (buffer_uint16(b, &n))
298     return EINVAL;
299
300   if (((size_t)n * 9) != b->len)
301     return EINVAL;
302
303   state->values_len = (size_t)n;
304   state->values = calloc(sizeof(*state->values), state->values_len);
305   state->values_types = calloc(sizeof(*state->values_types), state->values_len);
306   if ((state->values == NULL) || (state->values_types == NULL)) {
307     return ENOMEM;
308   }
309
310   for (uint16_t i = 0; i < n; i++) {
311     uint8_t tmp;
312     if (buffer_next(b, &tmp, sizeof(tmp)))
313       return EINVAL;
314     state->values_types[i] = (int)tmp;
315   }
316
317   for (uint16_t i = 0; i < n; i++) {
318     uint64_t tmp;
319     if (buffer_next(b, &tmp, sizeof(tmp)))
320       return EINVAL;
321
322     if (state->values_types[i] == LCC_TYPE_GAUGE) {
323       union {
324         uint64_t i;
325         double d;
326       } conv = {.i = tmp};
327       state->values[i].gauge = ntohd(conv.d);
328       continue;
329     }
330
331     tmp = be64toh(tmp);
332     switch (state->values_types[i]) {
333     case LCC_TYPE_COUNTER:
334       state->values[i].counter = (counter_t)tmp;
335       break;
336     case LCC_TYPE_DERIVE:
337       state->values[i].derive = (derive_t)tmp;
338       break;
339     case LCC_TYPE_ABSOLUTE:
340       state->values[i].absolute = (absolute_t)tmp;
341       break;
342     default:
343       return EINVAL;
344     }
345   }
346
347   return 0;
348 }
349
350 #if HAVE_GCRYPT_H
351 static int verify_sha256(void *payload, size_t payload_size,
352                          char const *username, char const *password,
353                          uint8_t hash_provided[32]) {
354   gcry_md_hd_t hd = NULL;
355
356   gcry_error_t err = gcry_md_open(&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
357   if (err != 0) {
358     return (int)err;
359   }
360
361   err = gcry_md_setkey(hd, password, strlen(password));
362   if (err != 0) {
363     gcry_md_close(hd);
364     return (int)err;
365   }
366
367   gcry_md_write(hd, username, strlen(username));
368   gcry_md_write(hd, payload, payload_size);
369
370   unsigned char *hash_calculated = gcry_md_read(hd, GCRY_MD_SHA256);
371   if (!hash_calculated) {
372     gcry_md_close(hd);
373     return -1;
374   }
375
376   int ret = memcmp(hash_provided, hash_calculated, 32);
377
378   gcry_md_close(hd);
379   hash_calculated = NULL;
380
381   return !!ret;
382 }
383 #else /* !HAVE_GCRYPT_H */
384 static int verify_sha256(void *payload, size_t payload_size,
385                          char const *username, char const *password,
386                          uint8_t hash_provided[32]) {
387   return ENOTSUP;
388 }
389 #endif
390
391 static int parse_sign_sha256(void *signature, size_t signature_len,
392                              void *payload, size_t payload_size,
393                              lcc_network_parse_options_t const *opts) {
394   if (opts->password_lookup == NULL) {
395     /* The sender signed the packet but we can't verify it. Handle it as if it
396      * were unsigned, i.e. security level NONE. */
397     return network_parse(payload, payload_size, NONE, opts);
398   }
399
400   buffer_t *b = &(buffer_t){
401       .data = signature, .len = signature_len,
402   };
403
404   uint8_t hash[32];
405   if (buffer_next(b, hash, sizeof(hash)))
406     return EINVAL;
407
408   char username[b->len + 1];
409   memset(username, 0, sizeof(username));
410   if (buffer_next(b, username, sizeof(username) - 1)) {
411     return EINVAL;
412   }
413
414   char const *password = opts->password_lookup(username);
415   if (!password)
416     return network_parse(payload, payload_size, NONE, opts);
417
418   int status = verify_sha256(payload, payload_size, username, password, hash);
419   if (status != 0)
420     return status;
421
422   return network_parse(payload, payload_size, SIGN, opts);
423 }
424
425 #if HAVE_GCRYPT_H
426 static int decrypt_aes256(buffer_t *b, void *iv, size_t iv_size,
427                           char const *password) {
428   gcry_cipher_hd_t cipher = NULL;
429
430   if (gcry_cipher_open(&cipher, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB,
431                        /* flags = */ 0))
432     return -1;
433
434   uint8_t pwhash[32] = {0};
435   gcry_md_hash_buffer(GCRY_MD_SHA256, pwhash, password, strlen(password));
436
437   fprintf(stderr, "sizeof(iv) = %zu\n", sizeof(iv));
438   if (gcry_cipher_setkey(cipher, pwhash, sizeof(pwhash)) ||
439       gcry_cipher_setiv(cipher, iv, iv_size) ||
440       gcry_cipher_decrypt(cipher, b->data, b->len, /* in = */ NULL,
441                           /* in_size = */ 0)) {
442     gcry_cipher_close(cipher);
443     return -1;
444   }
445
446   gcry_cipher_close(cipher);
447   return 0;
448 }
449
450 static int parse_encrypt_aes256(void *data, size_t data_size,
451                                 lcc_network_parse_options_t const *opts) {
452   if (opts->password_lookup == NULL) {
453     /* Without a password source it's (hopefully) impossible to decrypt the
454      * network packet. */
455     return ENOENT;
456   }
457
458   buffer_t *b = &(buffer_t){
459       .data = data, .len = data_size,
460   };
461
462   uint16_t username_len;
463   if (buffer_uint16(b, &username_len))
464     return EINVAL;
465   if ((size_t)username_len > data_size)
466     return ENOMEM;
467   char username[((size_t)username_len) + 1];
468   memset(username, 0, sizeof(username));
469   if (buffer_next(b, username, (size_t)username_len))
470     return EINVAL;
471
472   char const *password = opts->password_lookup(username);
473   if (!password)
474     return ENOENT;
475
476   uint8_t iv[16];
477   if (buffer_next(b, iv, sizeof(iv)))
478     return EINVAL;
479
480   int status = decrypt_aes256(b, iv, sizeof(iv), password);
481   if (status != 0)
482     return status;
483
484   uint8_t hash_provided[20];
485   if (buffer_next(b, hash_provided, sizeof(hash_provided))) {
486     return -1;
487   }
488
489   uint8_t hash_calculated[20];
490   gcry_md_hash_buffer(GCRY_MD_SHA1, hash_calculated, b->data, b->len);
491
492   if (memcmp(hash_provided, hash_calculated, sizeof(hash_provided)) != 0) {
493     return -1;
494   }
495
496   return network_parse(b->data, b->len, ENCRYPT, opts);
497 }
498 #else /* !HAVE_GCRYPT_H */
499 static int parse_encrypt_aes256(void *data, size_t data_size,
500                                 lcc_network_parse_options_t const *opts) {
501   return ENOTSUP;
502 }
503 #endif
504
505 static int network_parse(void *data, size_t data_size, lcc_security_level_t sl,
506                          lcc_network_parse_options_t const *opts) {
507   buffer_t *b = &(buffer_t){
508       .data = data, .len = data_size,
509   };
510
511   lcc_value_list_t state = {0};
512
513   while (b->len > 0) {
514     uint16_t type = 0, sz = 0;
515     if (buffer_uint16(b, &type) || buffer_uint16(b, &sz)) {
516       DEBUG("lcc_network_parse(): reading type and/or length failed.\n");
517       return EINVAL;
518     }
519
520     if ((sz < 5) || (((size_t)sz - 4) > b->len)) {
521       DEBUG("lcc_network_parse(): invalid 'sz' field: sz = %" PRIu16
522             ", b->len = %zu\n",
523             sz, b->len);
524       return EINVAL;
525     }
526     sz -= 4;
527
528     uint8_t payload[sz];
529     if (buffer_next(b, payload, sizeof(payload)))
530       return EINVAL;
531
532     switch (type) {
533     case TYPE_HOST:
534     case TYPE_PLUGIN:
535     case TYPE_PLUGIN_INSTANCE:
536     case TYPE_TYPE:
537     case TYPE_TYPE_INSTANCE: {
538       if (parse_identifier(type, payload, sizeof(payload), &state)) {
539         DEBUG("lcc_network_parse(): parse_identifier failed.\n");
540         return EINVAL;
541       }
542       break;
543     }
544
545     case TYPE_INTERVAL:
546     case TYPE_INTERVAL_HR:
547     case TYPE_TIME:
548     case TYPE_TIME_HR: {
549       if (parse_time(type, payload, sizeof(payload), &state)) {
550         DEBUG("lcc_network_parse(): parse_time failed.\n");
551         return EINVAL;
552       }
553       break;
554     }
555
556     case TYPE_VALUES: {
557       lcc_value_list_t vl = state;
558       if (parse_values(payload, sizeof(payload), &vl)) {
559         free(vl.values);
560         free(vl.values_types);
561         DEBUG("lcc_network_parse(): parse_values failed.\n");
562         return EINVAL;
563       }
564
565       int status = 0;
566
567       /* Write metrics if they have the required security level. */
568       if (sl >= opts->security_level)
569         status = opts->writer(&vl);
570
571       free(vl.values);
572       free(vl.values_types);
573
574       if (status != 0)
575         return status;
576       break;
577     }
578
579     case TYPE_SIGN_SHA256: {
580       int status =
581           parse_sign_sha256(payload, sizeof(payload), b->data, b->len, opts);
582       if (status != 0) {
583         DEBUG("lcc_network_parse(): parse_sign_sha256() = %d\n", status);
584         return -1;
585       }
586       /* parse_sign_sha256, if successful, consumes all remaining data. */
587       b->data = NULL;
588       b->len = 0;
589       break;
590     }
591
592     case TYPE_ENCR_AES256: {
593       int status = parse_encrypt_aes256(payload, sizeof(payload), opts);
594       if (status != 0) {
595         DEBUG("lcc_network_parse(): parse_encrypt_aes256() = %d\n", status);
596         return -1;
597       }
598       break;
599     }
600
601     default: {
602       DEBUG("lcc_network_parse(): ignoring unknown type %" PRIu16 "\n", type);
603       return EINVAL;
604     }
605     }
606   }
607
608   return 0;
609 }
610
611 int lcc_network_parse(void *data, size_t data_size,
612                       lcc_network_parse_options_t opts) {
613   if (opts.password_lookup) {
614 #if HAVE_GCRYPT_H
615     int status;
616     if ((status = init_gcrypt())) {
617       return status;
618     }
619 #else
620     return ENOTSUP;
621 #endif
622   }
623
624   return network_parse(data, data_size, NONE, &opts);
625 }