binary.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. /*
  2. * binary.c -- handles:
  3. * misc update functions
  4. * md5 hash verifying
  5. *
  6. */
  7. #include "common.h"
  8. #include "binary.h"
  9. #include "settings.h"
  10. #include "crypt.h"
  11. #include "shell.h"
  12. #include "misc.h"
  13. #include "main.h"
  14. #include "misc_file.h"
  15. #include <sys/wait.h>
  16. #include <sys/types.h>
  17. #include <signal.h>
  18. settings_t settings = {
  19. "\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200",
  20. /* -- STATIC -- */
  21. "", "", "", "", "", "", "", "", "", "",
  22. /* -- DYNAMIC -- */
  23. "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  24. /* -- PADDING */
  25. ""
  26. };
  27. #define PACK_ENC 1
  28. #define PACK_DEC 2
  29. static void edpack(settings_t *, const char *, int);
  30. int checked_bin_buf = 0;
  31. static char *
  32. bin_checksum(const char *fname, int todo)
  33. {
  34. MD5_CTX ctx;
  35. static char hash[MD5_HASH_LENGTH + 1] = "";
  36. unsigned char md5out[MD5_HASH_LENGTH + 1] = "", buf[PREFIXLEN + 1] = "";
  37. FILE *f = NULL;
  38. size_t len = 0;
  39. MD5_Init(&ctx);
  40. checked_bin_buf++;
  41. hash[0] = 0;
  42. if (todo == GET_CHECKSUM) {
  43. if (!(f = fopen(fname, "rb")))
  44. werr(ERR_BINSTAT);
  45. while ((len = fread(buf, 1, sizeof buf - 1, f))) {
  46. if (!memcmp(buf, &settings.prefix, PREFIXLEN))
  47. break;
  48. MD5_Update(&ctx, buf, len);
  49. }
  50. fclose(f);
  51. f = NULL;
  52. MD5_Final(md5out, &ctx);
  53. strlcpy(hash, btoh(md5out, MD5_DIGEST_LENGTH), sizeof(hash));
  54. OPENSSL_cleanse(&ctx, sizeof(ctx));
  55. }
  56. if (todo == GET_CONF) {
  57. char *oldhash = strdup(settings.hash);
  58. if (!(f = fopen(fname, "rb")))
  59. werr(ERR_BINSTAT);
  60. while ((len = fread(buf, 1, sizeof buf - 1, f)))
  61. if (!memcmp(buf, &settings.prefix, PREFIXLEN))
  62. break;
  63. char *tmpbuf = (char *) my_calloc(1, SIZE_PACK);
  64. if ((len = fread(tmpbuf, 1, SIZE_PACK, f))) {
  65. edpack(&settings, oldhash, PACK_ENC);
  66. len = fread(&settings.bots, 1, SIZE_CONF, f);
  67. edpack(&settings, oldhash, PACK_DEC);
  68. } else
  69. return NULL;
  70. free(oldhash);
  71. fclose(f);
  72. return settings.hash;
  73. }
  74. if (todo & WRITE_CHECKSUM) {
  75. Tempfile *newbin = new Tempfile("bin");
  76. char *fname_bak = NULL;
  77. size_t size = 0, newpos = 0;
  78. size = strlen(fname) + 2;
  79. fname_bak = (char *) my_calloc(1, size);
  80. simple_snprintf(fname_bak, size, "%s~", fname);
  81. size = 0;
  82. if (!(f = fopen(fname, "rb")))
  83. goto fatal;
  84. fseek(f, 0, SEEK_END);
  85. size = ftell(f);
  86. fseek(f, 0, SEEK_SET);
  87. newpos = 0;
  88. while ((len = fread(buf, 1, sizeof(buf) - 1, f))) {
  89. if (fwrite(buf, 1, len, newbin->f) != len)
  90. goto fatal;
  91. newpos += len;
  92. if (!memcmp(buf, &settings.prefix, PREFIXLEN)) { /* found the settings struct! */
  93. MD5_Final(md5out, &ctx);
  94. strlcpy(hash, btoh(md5out, MD5_DIGEST_LENGTH), sizeof(hash));
  95. OPENSSL_cleanse(&ctx, sizeof(ctx));
  96. strlcpy(settings.hash, hash, 65);
  97. edpack(&settings, hash, PACK_ENC); /* encrypt the entire struct with the hash (including hash) */
  98. if (todo & WRITE_PACK) {
  99. fwrite(&settings.hash, SIZE_PACK, 1, newbin->f);
  100. sdprintf("writing pack: %d\n", SIZE_PACK);
  101. } else {
  102. char *tmpbuf = (char *) my_calloc(1, SIZE_PACK);
  103. if ((len = fread(tmpbuf, 1, SIZE_PACK, f))) {
  104. if (fwrite(tmpbuf, 1, len, newbin->f) != len) {
  105. free(tmpbuf);
  106. goto fatal;
  107. }
  108. }
  109. free(tmpbuf);
  110. }
  111. newpos += SIZE_PACK;
  112. if (todo & WRITE_CONF) {
  113. fwrite(&settings.bots, SIZE_CONF, 1, newbin->f);
  114. sdprintf("writing conf: %d\n", SIZE_CONF);
  115. } else {
  116. char *tmpbuf = (char *) my_calloc(1, SIZE_CONF);
  117. if ((len = fread(tmpbuf, 1, SIZE_CONF, f))) {
  118. if (fwrite(tmpbuf, 1, len, newbin->f) != len) {
  119. free(tmpbuf);
  120. goto fatal;
  121. }
  122. }
  123. free(tmpbuf);
  124. }
  125. newpos += SIZE_CONF;
  126. fseek(newbin->f, newpos + SIZE_PAD, SEEK_SET);
  127. newpos += SIZE_PAD;
  128. /* skip reading over the stuff we already wrote */
  129. fseek(f, newpos, SEEK_SET);
  130. } else if (!hash[0]) /* hash as long as we haven't reached the prefix */
  131. MD5_Update(&ctx, buf, len);
  132. }
  133. fclose(f);
  134. f = NULL;
  135. newbin->my_close();
  136. if (size != newpos) {
  137. delete newbin;
  138. fatal("Binary corrupted", 0);
  139. }
  140. if (movefile(fname, fname_bak)) {
  141. printf("Failed to move file (%s -> %s): %s\n", fname, fname_bak, strerror(errno));
  142. delete newbin;
  143. fatal("", 0);
  144. }
  145. if (movefile(newbin->file, fname)) {
  146. printf("Failed to move file (%s -> %s): %s\n", newbin->file, fname, strerror(errno));
  147. delete newbin;
  148. fatal("", 0);
  149. }
  150. fixmod(fname);
  151. unlink(fname_bak);
  152. delete newbin;
  153. return hash;
  154. fatal:
  155. if (f)
  156. fclose(f);
  157. delete newbin;
  158. werr(ERR_BINSTAT);
  159. }
  160. return hash;
  161. }
  162. static int
  163. readcfg(const char *cfgfile)
  164. {
  165. FILE *f = NULL;
  166. if ((f = fopen(cfgfile, "r")) == NULL) {
  167. printf("Error: Can't open '%s' for reading\n", cfgfile);
  168. exit(1);
  169. }
  170. char *buffer = NULL, *p = NULL;
  171. int skip = 0, line = 0;
  172. printf("Reading '%s' ", cfgfile);
  173. while ((!feof(f)) && ((buffer = step_thru_file(f)) != NULL)) {
  174. line++;
  175. if ((*buffer)) {
  176. if (strchr(buffer, '\n'))
  177. *(char *) strchr(buffer, '\n') = 0;
  178. if ((skipline(buffer, &skip)))
  179. continue;
  180. if (strchr(buffer, '<') || strchr(buffer, '>')) {
  181. printf(" Failed\n");
  182. printf("%s:%d: error: Look at your configuration file again...\n", cfgfile, line);
  183. exit(1);
  184. }
  185. p = strchr(buffer, ' ');
  186. while (p && (strchr(LISTSEPERATORS, p[0])))
  187. *p++ = 0;
  188. if (p) {
  189. if (!egg_strcasecmp(buffer, "packname")) {
  190. strlcpy(settings.packname, trim(p), sizeof settings.packname);
  191. printf(".");
  192. } else if (!egg_strcasecmp(buffer, "shellhash")) {
  193. strlcpy(settings.shellhash, trim(p), sizeof settings.shellhash);
  194. printf(".");
  195. } else if (!egg_strcasecmp(buffer, "bdhash")) {
  196. strlcpy(settings.bdhash, trim(p), sizeof settings.bdhash);
  197. printf(".");
  198. } else if (!egg_strcasecmp(buffer, "dccprefix")) {
  199. strlcpy(settings.dcc_prefix, trim(p), sizeof settings.dcc_prefix);
  200. printf(".");
  201. } else if (!egg_strcasecmp(buffer, "owner")) {
  202. strcat(settings.owners, trim(p));
  203. strcat(settings.owners, ",");
  204. printf(".");
  205. } else if (!egg_strcasecmp(buffer, "owneremail")) {
  206. strcat(settings.owneremail, trim(p));
  207. strcat(settings.owneremail, ",");
  208. printf(".");
  209. } else if (!egg_strcasecmp(buffer, "hub")) {
  210. strcat(settings.hubs, trim(p));
  211. strcat(settings.hubs, ",");
  212. printf(".");
  213. } else if (!egg_strcasecmp(buffer, "salt1")) {
  214. strcat(settings.salt1, trim(p));
  215. printf(".");
  216. } else if (!egg_strcasecmp(buffer, "salt2")) {
  217. strcat(settings.salt2, trim(p));
  218. printf(".");
  219. } else {
  220. printf("%s %s\n", buffer, p);
  221. printf(",");
  222. }
  223. }
  224. }
  225. buffer = NULL;
  226. }
  227. if (f)
  228. fclose(f);
  229. if (!settings.salt1[0] || !settings.salt2[0]) {
  230. /* Write salts back to the cfgfile */
  231. char salt1[SALT1LEN + 1] = "", salt2[SALT2LEN + 1] = "";
  232. printf("Creating Salts");
  233. if ((f = fopen(cfgfile, "a")) == NULL) {
  234. printf("Cannot open cfgfile for appending.. aborting\n");
  235. exit(1);
  236. }
  237. make_rand_str(salt1, SALT1LEN);
  238. make_rand_str(salt2, SALT2LEN);
  239. salt1[sizeof salt1] = salt2[sizeof salt2] = 0;
  240. fprintf(f, "SALT1 %s\n", salt1);
  241. fprintf(f, "SALT2 %s\n", salt2);
  242. fflush(f);
  243. fclose(f);
  244. }
  245. printf(" Success\n");
  246. return 1;
  247. }
  248. static void edpack(settings_t *incfg, const char *hash, int what)
  249. {
  250. char *tmp = NULL;
  251. unsigned char *(*enc_dec_string)(const char *, unsigned char *, size_t *);
  252. size_t len = 0;
  253. if (what == PACK_ENC)
  254. enc_dec_string = encrypt_binary;
  255. else
  256. enc_dec_string = decrypt_binary;
  257. #define dofield(_field) do { \
  258. if (_field) { \
  259. len = sizeof(_field) - 1; \
  260. tmp = (char *) enc_dec_string(hash, (unsigned char *) _field, &len); \
  261. if (what == PACK_ENC) \
  262. egg_memcpy(_field, tmp, len); \
  263. else \
  264. simple_snprintf(_field, sizeof(_field), "%s", tmp); \
  265. free(tmp); \
  266. } \
  267. } while (0)
  268. #ifdef no
  269. egg_memcpy(_field, tmp, len); \
  270. #endif
  271. /* -- STATIC -- */
  272. dofield(incfg->hash);
  273. dofield(incfg->packname);
  274. dofield(incfg->shellhash);
  275. dofield(incfg->bdhash);
  276. dofield(incfg->dcc_prefix);
  277. dofield(incfg->owners);
  278. dofield(incfg->owneremail);
  279. dofield(incfg->hubs);
  280. dofield(incfg->salt1);
  281. dofield(incfg->salt2);
  282. /* -- DYNAMIC -- */
  283. dofield(incfg->bots);
  284. dofield(incfg->uid);
  285. dofield(incfg->autouname);
  286. dofield(incfg->pscloak);
  287. dofield(incfg->autocron);
  288. dofield(incfg->watcher);
  289. dofield(incfg->uname);
  290. dofield(incfg->username);
  291. dofield(incfg->tempdir);
  292. dofield(incfg->homedir);
  293. dofield(incfg->binpath);
  294. dofield(incfg->binname);
  295. dofield(incfg->portmin);
  296. dofield(incfg->portmax);
  297. #undef dofield
  298. }
  299. #ifdef DEBUG
  300. static void
  301. tellconfig(settings_t *incfg)
  302. {
  303. #define dofield(_field) printf("%s: %s\n", #_field, _field);
  304. // -- STATIC --
  305. dofield(incfg->hash);
  306. dofield(incfg->packname);
  307. dofield(incfg->shellhash);
  308. dofield(incfg->bdhash);
  309. dofield(incfg->dcc_prefix);
  310. dofield(incfg->owners);
  311. dofield(incfg->owneremail);
  312. dofield(incfg->hubs);
  313. dofield(incfg->salt1);
  314. dofield(incfg->salt2);
  315. // -- DYNAMIC --
  316. dofield(incfg->bots);
  317. dofield(incfg->uid);
  318. dofield(incfg->autouname);
  319. dofield(incfg->pscloak);
  320. dofield(incfg->autocron);
  321. dofield(incfg->watcher);
  322. dofield(incfg->uname);
  323. dofield(incfg->username);
  324. dofield(incfg->tempdir);
  325. dofield(incfg->homedir);
  326. dofield(incfg->binpath);
  327. dofield(incfg->binname);
  328. dofield(incfg->portmin);
  329. dofield(incfg->portmax);
  330. #undef dofield
  331. }
  332. #endif
  333. void
  334. check_sum(const char *fname, const char *cfgfile)
  335. {
  336. if (!settings.hash[0]) {
  337. if (!cfgfile)
  338. fatal("Binary not initialized.", 0);
  339. readcfg(cfgfile);
  340. // tellconfig(&settings);
  341. if (bin_checksum(fname, WRITE_CHECKSUM|WRITE_CONF|WRITE_PACK))
  342. printf("* Wrote settings to binary.\n");
  343. exit(0);
  344. } else {
  345. char *hash = bin_checksum(fname, GET_CHECKSUM);
  346. // tellconfig(&settings);
  347. edpack(&settings, hash, PACK_DEC);
  348. #ifdef DEBUG
  349. tellconfig(&settings);
  350. #endif
  351. if (strcmp(settings.hash, hash)) {
  352. unlink(fname);
  353. fatal("!! Invalid binary", 0);
  354. }
  355. }
  356. }
  357. static bool check_bin_initialized(const char *fname)
  358. {
  359. int i = 0;
  360. size_t len = strlen(fname) + 3 + 1;
  361. char *path = (char *) my_calloc(1, len);
  362. simple_snprintf(path, len, "%s -q", fname);
  363. i = system(path);
  364. free(path);
  365. if (i != -1 && WEXITSTATUS(i) == 4)
  366. return 1;
  367. return 0;
  368. }
  369. void write_settings(const char *fname, int die, bool conf)
  370. {
  371. char *hash = NULL;
  372. int bits = WRITE_CHECKSUM;
  373. /* see if the binary is already initialized or not */
  374. bool initialized = check_bin_initialized(fname);
  375. /* only write pack data if the binary is uninitialized
  376. * otherwise, assume it has similar/correct/updated pack data
  377. */
  378. if (!initialized)
  379. bits |= WRITE_PACK;
  380. if (conf)
  381. bits |= WRITE_CONF;
  382. /* only bother writing anything if we have pack or conf, checksum is worthless to write out */
  383. if (bits & (WRITE_PACK|WRITE_CONF)) {
  384. if ((hash = bin_checksum(fname, bits))) {
  385. printf("* Wrote %ssettings to: %s.\n", ((bits & WRITE_PACK) && !(bits & WRITE_CONF)) ? "pack " :
  386. ((bits & WRITE_CONF) && !(bits & WRITE_PACK)) ? "conf " :
  387. ((bits & WRITE_PACK) && (bits & WRITE_CONF)) ? "pack/conf " :
  388. "",
  389. fname);
  390. if (die == -1) /* only bother decrypting if we aren't about to exit */
  391. edpack(&settings, hash, PACK_DEC);
  392. }
  393. }
  394. if (die >= 0)
  395. exit(die);
  396. }
  397. static void
  398. clear_settings(void)
  399. {
  400. // egg_memset(&settings.bots, 0, sizeof(settings_t) - SIZE_PACK - PREFIXLEN);
  401. egg_memset(&settings.bots, 0, SIZE_CONF);
  402. }
  403. void conf_to_bin(conf_t *in, bool move, int die)
  404. {
  405. conf_bot *bot = NULL;
  406. char *newbin = NULL;
  407. clear_settings();
  408. sdprintf("converting conf to bin\n");
  409. simple_sprintf(settings.uid, "%d", in->uid);
  410. simple_sprintf(settings.watcher, "%d", in->watcher);
  411. simple_sprintf(settings.autocron, "%d", in->autocron);
  412. simple_sprintf(settings.autouname, "%d", in->autouname);
  413. simple_sprintf(settings.portmin, "%d", in->portmin);
  414. simple_sprintf(settings.portmax, "%d", in->portmax);
  415. simple_sprintf(settings.pscloak, "%d", in->pscloak);
  416. strlcpy(settings.binname, in->binname, sizeof(settings.binname));
  417. strlcpy(settings.username, in->username, sizeof(settings.username));
  418. strlcpy(settings.uname, in->uname, sizeof(settings.uname));
  419. strlcpy(settings.tempdir, in->tempdir, sizeof(settings.tempdir));
  420. strlcpy(settings.homedir, in->homedir, sizeof(settings.homedir));
  421. strlcpy(settings.binpath, in->binpath, sizeof(settings.binpath));
  422. for (bot = in->bots; bot && bot->nick; bot = bot->next) {
  423. simple_snprintf(settings.bots, sizeof(settings.bots), "%s%s%s %s %s%s %s,",
  424. settings.bots && settings.bots[0] ? settings.bots : "",
  425. bot->disabled ? "/" : "",
  426. bot->nick,
  427. bot->net.ip ? bot->net.ip : ".",
  428. bot->net.host6 ? "+" : "",
  429. bot->net.host ? bot->net.host : (bot->net.host6 ? bot->net.host6 : "."),
  430. bot->net.ip6 ? bot->net.ip6 : "");
  431. }
  432. if (move)
  433. newbin = move_bin(in->binpath, in->binname, 0);
  434. else
  435. newbin = binname;
  436. // tellconfig(&settings);
  437. write_settings(newbin, -1, 1);
  438. if (die >= 0)
  439. exit(die);
  440. }
  441. void reload_bin_data() {
  442. if (bin_checksum(binname, GET_CONF)) {
  443. putlog(LOG_MISC, "*", "Rehashed config data from binary.");
  444. conf_bot *oldbots = NULL;
  445. oldbots = conf_bots_dup(conf.bots);
  446. /* free up our current conf struct */
  447. free_conf();
  448. /* Fill conf[] with binary data from settings[] */
  449. bin_to_conf();
  450. /* fill up conf.bot using origbotname */
  451. fill_conf_bot();
  452. /* If we don't have conf.bot, then all bots were removed or just our own record */
  453. if ((!conf.bot && oldbots->localhub) || (conf.bot && !conf.bot->localhub && oldbots->localhub)) {
  454. /* no longer the localhub (or removed), need to alert the new one to rehash */
  455. if (conf.bots->pid)
  456. conf_killbot(NULL, conf.bots, SIGHUP); //restart the new localhub
  457. else
  458. spawnbot(conf.bots->nick); //spawn the new localhub
  459. }
  460. if (conf.bot && conf.bot->localhub) {
  461. /* kill and remove bots removed from conf */
  462. kill_removed_bots(oldbots, conf.bots);
  463. /* add any bots not in userfile */
  464. conf_add_userlist_bots();
  465. /* start/disable new bots as necesary */
  466. conf_checkpids();
  467. spawnbots(1); //1 signifies to not start me!
  468. } else
  469. free_conf_bots(conf.bots);
  470. free_conf_bots(oldbots);
  471. }
  472. }