Smart-Home am Beispiel der Präsenzerkennung im Raum Projektarbeit Lennart Heimbs, Johannes Krug, Sebastian Dohle und Kevin Holzschuh bei Prof. Oliver Hofmann SS2019
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MyMainLinuxGeneric.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. /*
  2. * The MySensors Arduino library handles the wireless radio link and protocol
  3. * between your home built sensors/actuators and HA controller of choice.
  4. * The sensors forms a self healing radio network with optional repeaters. Each
  5. * repeater and gateway builds a routing tables in EEPROM which keeps track of the
  6. * network topology allowing messages to be routed to nodes.
  7. *
  8. * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
  9. * Copyright (C) 2013-2018 Sensnology AB
  10. * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
  11. *
  12. * Documentation: http://www.mysensors.org
  13. * Support Forum: http://forum.mysensors.org
  14. *
  15. * This program is free software; you can redistribute it and/or
  16. * modify it under the terms of the GNU General Public License
  17. * version 2 as published by the Free Software Foundation.
  18. */
  19. // Initialize library and handle sketch functions like we want to
  20. #include <stdio.h>
  21. #include <csignal>
  22. #include <cstdlib>
  23. #include <unistd.h>
  24. #include <sys/stat.h>
  25. #include <fcntl.h>
  26. #include <syslog.h>
  27. #include <errno.h>
  28. #include <getopt.h>
  29. #include "log.h"
  30. #include "config.h"
  31. #include "MySensorsCore.h"
  32. void handle_sigint(int sig)
  33. {
  34. if (sig == SIGINT) {
  35. logNotice("Received SIGINT\n\n");
  36. } else if (sig == SIGTERM) {
  37. logNotice("Received SIGTERM\n\n");
  38. } else {
  39. return;
  40. }
  41. #ifdef MY_RF24_IRQ_PIN
  42. detachInterrupt(MY_RF24_IRQ_PIN);
  43. #endif
  44. #if defined(MY_GATEWAY_SERIAL)
  45. MY_SERIALDEVICE.end();
  46. #endif
  47. logClose();
  48. exit(EXIT_SUCCESS);
  49. }
  50. static int daemonize(void)
  51. {
  52. pid_t pid, sid;
  53. /* Fork off the parent process */
  54. pid = fork();
  55. if (pid < 0) {
  56. logError("fork: %s\n", strerror(errno));
  57. return -1;
  58. }
  59. /* If we got a good PID, then we can exit the parent process. */
  60. if (pid > 0) {
  61. exit(EXIT_SUCCESS);
  62. }
  63. /* At this point we are executing as the child process */
  64. /* Change the file mode mask */
  65. umask(0);
  66. /* Create a new SID for the child process */
  67. sid = setsid();
  68. if (sid < 0) {
  69. logError("setsid: %s\n", strerror(errno));
  70. return -1;
  71. }
  72. /* Change the current working directory. This prevents the current
  73. directory from being locked; hence not being able to remove it. */
  74. if ((chdir("/")) < 0) {
  75. logError("chdir(\"/\"): %s\n", strerror(errno));
  76. return -1;
  77. }
  78. if (freopen( "/dev/null", "r", stdin) == NULL) {
  79. logError("freopen: %s\n", strerror(errno));
  80. }
  81. if (freopen( "/dev/null", "r", stdout) == NULL) {
  82. logError("freopen: %s\n", strerror(errno));
  83. }
  84. if (freopen( "/dev/null", "r", stderr) == NULL) {
  85. logError("freopen: %s\n", strerror(errno));
  86. }
  87. return 0;
  88. }
  89. void print_usage()
  90. {
  91. printf("Usage: mysgw [options]\n\n" \
  92. "Options:\n" \
  93. " -c, --config-file Config file. [" MY_LINUX_CONFIG_FILE "]\n" \
  94. " -h, --help Display a short summary of all program options.\n" \
  95. " -q, --quiet Quiet mode, disable log messages written to the terminal.\n" \
  96. " --daemon Run as a daemon.\n" \
  97. " --gen-soft-hmac-key Generate and print a soft hmac key.\n" \
  98. " --gen-soft-serial-key Generate and print a soft serial key.\n" \
  99. " --gen-aes-key Generate and print an aes encryption key.\n");
  100. }
  101. void print_soft_sign_hmac_key(uint8_t *key_ptr = NULL)
  102. {
  103. uint8_t key[32];
  104. if (key_ptr == NULL) {
  105. hwReadConfigBlock(&key, reinterpret_cast<void*>EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32);
  106. key_ptr = key;
  107. }
  108. printf("soft_hmac_key=");
  109. for (int i = 0; i < 32; i++) {
  110. printf("%02X", key_ptr[i]);
  111. }
  112. printf("\n\n");
  113. printf("The next line is intended to be used in SecurityPersonalizer.ino:\n");
  114. printf("#define MY_HMAC_KEY ");
  115. for (int i=0; i<32; i++) {
  116. printf("%#02X", key_ptr[i]);
  117. if (i < 31) {
  118. printf(",");
  119. }
  120. }
  121. printf("\n\n");
  122. }
  123. void generate_soft_sign_hmac_key(char *config_file = NULL)
  124. {
  125. uint8_t key[32];
  126. printf("Generating key...");
  127. while (hwGetentropy(&key, sizeof(key)) != sizeof(key));
  128. printf(" done.\n");
  129. printf("To use the new key, update the value in %s witn:\n",
  130. config_file?config_file:MY_LINUX_CONFIG_FILE);
  131. print_soft_sign_hmac_key(key);
  132. #if defined(MY_SIGNING_SIMPLE_PASSWD)
  133. printf("Note: The gateway was built with simplified signing using the password: %s\n" \
  134. " Any key set with soft_hmac_key option in the config file is ignored.\n\n",
  135. MY_SIGNING_SIMPLE_PASSWD);
  136. #elif !defined(MY_SIGNING_FEATURE)
  137. printf("Note: The gateway was not built with signing support.\n" \
  138. " Any key set with soft_hmac_key option in the config file is ignored.\n\n");
  139. #endif
  140. }
  141. void set_soft_sign_hmac_key(char *key_str)
  142. {
  143. uint8_t key[32];
  144. if (strlen(key_str) != 64) {
  145. logWarning("Invalid HMAC key!\n");
  146. } else {
  147. for (int i = 0; i < 64; ++i) {
  148. int n;
  149. char c = key_str[i];
  150. if (c <= '9') {
  151. n = c - '0';
  152. } else if (c >= 'a') {
  153. n = c - 'a' + 10;
  154. } else {
  155. n = c - 'A' + 10;
  156. }
  157. if ((i & 0x1) == 0) {
  158. key[i/2] = n * 16;
  159. } else {
  160. key[i/2] += n;
  161. }
  162. }
  163. hwWriteConfigBlock(&key, reinterpret_cast<void*>EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32);
  164. }
  165. }
  166. void print_soft_sign_serial_key(uint8_t *key_ptr = NULL)
  167. {
  168. uint8_t key[9];
  169. if (key_ptr == NULL) {
  170. hwReadConfigBlock(&key, reinterpret_cast<void*>EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9);
  171. key_ptr = key;
  172. }
  173. printf("soft_serial_key=");
  174. for (int i = 0; i < 9; i++) {
  175. printf("%02X", key_ptr[i]);
  176. }
  177. printf("\n\n");
  178. printf("The next line is intended to be used in SecurityPersonalizer.ino:\n");
  179. printf("#define MY_SOFT_SERIAL ");
  180. for (int i=0; i<9; i++) {
  181. printf("%#02X", key_ptr[i]);
  182. if (i < 8) {
  183. printf(",");
  184. }
  185. }
  186. printf("\n\n");
  187. }
  188. void generate_soft_sign_serial_key(char *config_file = NULL)
  189. {
  190. uint8_t key[9];
  191. printf("Generating key...");
  192. while (hwGetentropy(&key, sizeof(key)) != sizeof(key));
  193. printf(" done.\n");
  194. printf("To use the new key, update the value in %s witn:\n",
  195. config_file?config_file:MY_LINUX_CONFIG_FILE);
  196. print_soft_sign_serial_key(key);
  197. #if defined(MY_SIGNING_SIMPLE_PASSWD)
  198. printf("Note: The gateway was built with simplified signing using the password: %s\n" \
  199. " Any key set with soft_serial_key option in the config file is ignored.\n\n",
  200. MY_SIGNING_SIMPLE_PASSWD);
  201. #elif !defined(MY_SIGNING_FEATURE)
  202. printf("Note: The gateway was not built with signing support.\n" \
  203. " Any key set with soft_serial_key option in the config file is ignored.\n\n");
  204. #endif
  205. }
  206. void set_soft_sign_serial_key(char *key_str)
  207. {
  208. uint8_t key[9];
  209. if (strlen(key_str) != 18) {
  210. logWarning("Invalid soft serial key!\n");
  211. } else {
  212. for (int i = 0; i < 18; ++i) {
  213. int n;
  214. char c = key_str[i];
  215. if (c <= '9') {
  216. n = c - '0';
  217. } else if (c >= 'a') {
  218. n = c - 'a' + 10;
  219. } else {
  220. n = c - 'A' + 10;
  221. }
  222. if ((i & 0x1) == 0) {
  223. key[i/2] = n * 16;
  224. } else {
  225. key[i/2] += n;
  226. }
  227. }
  228. hwWriteConfigBlock(&key, reinterpret_cast<void*>EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9);
  229. }
  230. }
  231. void print_aes_key(uint8_t *key_ptr = NULL)
  232. {
  233. uint8_t key[16];
  234. if (key_ptr == NULL) {
  235. hwReadConfigBlock(&key, reinterpret_cast<void*>EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
  236. key_ptr = key;
  237. }
  238. printf("aes_key=");
  239. for (int i = 0; i < 16; i++) {
  240. printf("%02X", key_ptr[i]);
  241. }
  242. printf("\n\n");
  243. printf("The next line is intended to be used in SecurityPersonalizer.ino:\n");
  244. printf("#define MY_AES_KEY ");
  245. for (int i=0; i<16; i++) {
  246. printf("%#02X", key_ptr[i]);
  247. if (i < 15) {
  248. printf(",");
  249. }
  250. }
  251. printf("\n\n");
  252. }
  253. void generate_aes_key(char *config_file = NULL)
  254. {
  255. uint8_t key[16];
  256. printf("Generating key...");
  257. while (hwGetentropy(&key, sizeof(key)) != sizeof(key));
  258. printf(" done.\n");
  259. printf("To use the new key, update the value in %s witn:\n",
  260. config_file?config_file:MY_LINUX_CONFIG_FILE);
  261. print_aes_key(key);
  262. #if defined(MY_ENCRYPTION_SIMPLE_PASSWD)
  263. printf("Note: The gateway was built with simplified encryption using the password: %s\n" \
  264. " Any key set with aes_key option in the config file is ignored.\n\n",
  265. MY_ENCRYPTION_SIMPLE_PASSWD);
  266. #elif !defined(MY_ENCRYPTION_FEATURE)
  267. printf("Note: The gateway was not built with encryption support.\n" \
  268. " Any key set with aes_key option in the config file is ignored.\n\n");
  269. #endif
  270. }
  271. void set_aes_key(char *key_str)
  272. {
  273. uint8_t key[16];
  274. if (strlen(key_str) != 32) {
  275. logWarning("Invalid AES key!\n");
  276. } else {
  277. for (int i = 0; i < 32; ++i) {
  278. int n;
  279. char c = key_str[i];
  280. if (c <= '9') {
  281. n = c - '0';
  282. } else if (c >= 'a') {
  283. n = c - 'a' + 10;
  284. } else {
  285. n = c - 'A' + 10;
  286. }
  287. if ((i & 0x1) == 0) {
  288. key[i/2] = n * 16;
  289. } else {
  290. key[i/2] += n;
  291. }
  292. }
  293. hwWriteConfigBlock(&key, reinterpret_cast<void*>EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
  294. }
  295. }
  296. int main(int argc, char *argv[])
  297. {
  298. int opt, daemon = 0, quiet = 0;
  299. char *config_file = NULL;
  300. bool gen_soft_sign_hmac_key = false;
  301. bool gen_soft_sign_serial_key = false;
  302. bool gen_aes_key = false;
  303. /* register the signal handler */
  304. signal(SIGINT, handle_sigint);
  305. signal(SIGTERM, handle_sigint);
  306. signal(SIGPIPE, handle_sigint);
  307. hwRandomNumberInit();
  308. static struct option long_options[] = {
  309. {"config-file", required_argument, 0, 'c'},
  310. {"daemon", no_argument, 0, 'J'},
  311. {"help", no_argument, 0, 'h'},
  312. {"quiet", no_argument, 0, 'q'},
  313. {"gen-soft-hmac-key", no_argument, 0, 'A'},
  314. {"gen-soft-serial-key", no_argument, 0, 'B'},
  315. {"gen-aes-key", no_argument, 0, 'C'},
  316. {0, 0, 0, 0}
  317. };
  318. int long_index = 0;
  319. while ((opt = getopt_long(argc, argv,"chqABCJ", long_options, &long_index )) != -1) {
  320. switch (opt) {
  321. case 'c':
  322. config_file = strdup(optarg);
  323. break;
  324. case 'h':
  325. print_usage();
  326. exit(EXIT_SUCCESS);
  327. case 'q':
  328. quiet = 1;
  329. break;
  330. case 'A':
  331. gen_soft_sign_hmac_key = true;
  332. break;
  333. case 'B':
  334. gen_soft_sign_serial_key = true;
  335. break;
  336. case 'C':
  337. gen_aes_key = true;
  338. break;
  339. case 'J':
  340. daemon = 1;
  341. break;
  342. default:
  343. print_usage();
  344. exit(EXIT_SUCCESS);
  345. }
  346. }
  347. if (gen_soft_sign_hmac_key || gen_soft_sign_serial_key || gen_aes_key) {
  348. if (gen_soft_sign_hmac_key) {
  349. generate_soft_sign_hmac_key(config_file);
  350. }
  351. if (gen_soft_sign_serial_key) {
  352. generate_soft_sign_serial_key(config_file);
  353. }
  354. if (gen_aes_key) {
  355. generate_aes_key(config_file);
  356. }
  357. exit(EXIT_SUCCESS);
  358. }
  359. if (daemon) {
  360. if (daemonize() != 0) {
  361. exit(EXIT_FAILURE);
  362. }
  363. quiet = 1;
  364. }
  365. if (config_parse(config_file?config_file:MY_LINUX_CONFIG_FILE) != 0) {
  366. exit(EXIT_FAILURE);
  367. }
  368. logSetQuiet(quiet);
  369. logSetLevel(conf.verbose);
  370. if (conf.log_file) {
  371. if (logSetFile(conf.log_filepath) != 0) {
  372. logError("Failed to open log file.\n");
  373. }
  374. }
  375. if (conf.log_pipe) {
  376. if (logSetPipe(conf.log_pipe_file) != 0) {
  377. logError("Failed to open log pipe.\n");
  378. }
  379. }
  380. if (conf.syslog) {
  381. logSetSyslog(LOG_CONS, LOG_USER);
  382. }
  383. logInfo("Starting gateway...\n");
  384. logInfo("Protocol version - %s\n", MYSENSORS_LIBRARY_VERSION);
  385. _begin(); // Startup MySensors library
  386. // EEPROM is initialized within _begin()
  387. // any operation on it must be done hereafter
  388. #if defined(MY_SIGNING_FEATURE) && !defined(MY_SIGNING_SIMPLE_PASSWD)
  389. // Check if we need to update the signing keys in EEPROM
  390. if (conf.soft_hmac_key) {
  391. set_soft_sign_hmac_key(conf.soft_hmac_key);
  392. } else {
  393. logError("soft_hmac_key was not found in %s\n", config_file?config_file:MY_LINUX_CONFIG_FILE);
  394. exit(EXIT_FAILURE);
  395. }
  396. if (conf.soft_serial_key) {
  397. set_soft_sign_serial_key(conf.soft_serial_key);
  398. } else {
  399. logError("soft_serial_key was not found in %s\n", config_file?config_file:MY_LINUX_CONFIG_FILE);
  400. exit(EXIT_FAILURE);
  401. }
  402. #endif
  403. #if defined(MY_ENCRYPTION_FEATURE) && !defined(MY_ENCRYPTION_SIMPLE_PASSWD)
  404. // Check if we need to update the encryption key in EEPROM
  405. if (conf.aes_key) {
  406. set_aes_key(conf.aes_key);
  407. } else {
  408. logError("aes_key was not found in %s\n", config_file?config_file:MY_LINUX_CONFIG_FILE);
  409. exit(EXIT_FAILURE);
  410. }
  411. #endif
  412. if (config_file) {
  413. free(config_file);
  414. }
  415. for (;;) {
  416. _process(); // Process incoming data
  417. if (loop) {
  418. loop(); // Call sketch loop
  419. }
  420. }
  421. return 0;
  422. }