binary.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935
  1. /*
  2. * Copyright (C) 1997 Robey Pointer
  3. * Copyright (C) 1999 - 2002 Eggheads Development Team
  4. * Copyright (C) 2002 - 2014 Bryan Drewery
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. */
  20. /*
  21. * binary.c -- handles:
  22. * misc update functions
  23. * md5 hash verifying
  24. *
  25. */
  26. #include "common.h"
  27. #include "binary.h"
  28. #include "settings.h"
  29. #include "crypt.h"
  30. #include "shell.h"
  31. #include "misc.h"
  32. #include "main.h"
  33. #include "misc_file.h"
  34. #include "tandem.h"
  35. #include "botnet.h"
  36. #include "net.h"
  37. #include "userrec.h"
  38. #include <bdlib/src/Array.h>
  39. #include <bdlib/src/String.h>
  40. #include <sys/wait.h>
  41. #include <sys/types.h>
  42. #include <sys/mman.h>
  43. #include <signal.h>
  44. #include <sys/stat.h>
  45. #include <fcntl.h>
  46. #include <termios.h>
  47. #include <libelf.h>
  48. #include <gelf.h>
  49. settings_t settings = {
  50. SETTINGS_HEADER,
  51. /* -- STATIC -- */
  52. "", "", "", "", "", "", "", "", "", "",
  53. /* -- DYNAMIC -- */
  54. "", "", "", "", "", "", "", "", "", "",
  55. /* -- PADDING */
  56. ""
  57. };
  58. static void edpack(settings_t *, const char *, int);
  59. #ifdef DEBUG
  60. static void tellconfig(settings_t *);
  61. #endif
  62. #define PACK_ENC 1
  63. #define PACK_DEC 2
  64. int checked_bin_buf = 0;
  65. #define MMAP_READ(_map, _dest, _offset, _len) \
  66. memcpy((_dest), &(_map)[(_offset)], (_len)); \
  67. (_offset) += (_len);
  68. static size_t
  69. elf_find_data_offset(int fd) {
  70. Elf *elf = NULL;
  71. GElf_Shdr shdr;
  72. Elf_Scn *scn = NULL;
  73. const char *sh_name;
  74. size_t shstrndx;
  75. size_t offset = 0;
  76. if (elf_version(EV_CURRENT) == EV_NONE)
  77. goto failure;
  78. if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
  79. goto failure;
  80. if (elf_kind(elf) != ELF_K_ELF)
  81. goto failure;
  82. elf_getshdrstrndx(elf, &shstrndx);
  83. while ((scn = elf_nextscn(elf, scn)) != NULL) {
  84. if (gelf_getshdr(scn, &shdr) != &shdr)
  85. goto failure;
  86. if (shdr.sh_type != SHT_PROGBITS)
  87. continue;
  88. if ((sh_name = elf_strptr(elf, shstrndx, shdr.sh_name)) == NULL)
  89. goto failure;
  90. if (strcmp(sh_name, ".data"))
  91. continue;
  92. offset = shdr.sh_offset;
  93. break;
  94. }
  95. goto cleanup;
  96. failure:
  97. offset = 0;
  98. #ifdef DEBUG
  99. printf("Elf error: %s\n", elf_errmsg(-1));
  100. #endif
  101. cleanup:
  102. if (elf != NULL)
  103. elf_end(elf);
  104. lseek(fd, 0, SEEK_SET);
  105. return offset;
  106. }
  107. static size_t
  108. elf_find_data_mem_offset(int fd, unsigned char *map, size_t map_size,
  109. void *symbol_header, size_t symbol_header_len) {
  110. size_t data_offset;
  111. unsigned char *symbol_start;
  112. if ((data_offset = elf_find_data_offset(fd)) == 0)
  113. return 0;
  114. symbol_start = (unsigned char*)memmem(map + data_offset,
  115. map_size - data_offset, symbol_header, symbol_header_len);
  116. if (symbol_start == NULL)
  117. return 0;
  118. return symbol_start - map;
  119. }
  120. static char *
  121. bin_checksum(const char *fname, int todo)
  122. {
  123. MD5_CTX ctx;
  124. static char hash[MD5_HASH_LENGTH + 1] = "";
  125. unsigned char md5out[MD5_HASH_LENGTH + 1] = "";
  126. int fd = -1;
  127. size_t offset = 0, size = 0, newpos = 0;
  128. unsigned char *map = NULL, *outmap = NULL;
  129. char *fname_bak = NULL;
  130. Tempfile *newbin = NULL;
  131. MD5_Init(&ctx);
  132. ++checked_bin_buf;
  133. hash[0] = 0;
  134. fixmod(fname);
  135. if (todo == GET_CHECKSUM) {
  136. fd = open(fname, O_RDONLY);
  137. if (fd == -1) werr(ERR_BINSTAT);
  138. size = lseek(fd, 0, SEEK_END);
  139. map = (unsigned char*) mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);
  140. if ((void*)map == MAP_FAILED) goto fatal;
  141. if ((offset = elf_find_data_mem_offset(fd, map, size, &settings.prefix,
  142. PREFIXLEN)) == 0) {
  143. goto fatal;
  144. }
  145. MD5_Update(&ctx, map, offset);
  146. /* Hash everything after the packdata too */
  147. offset += sizeof(settings_t);
  148. MD5_Update(&ctx, &map[offset], size - offset);
  149. MD5_Final(md5out, &ctx);
  150. btoh(md5out, MD5_DIGEST_LENGTH, hash, sizeof(hash));
  151. OPENSSL_cleanse(&ctx, sizeof(ctx));
  152. munmap(map, size);
  153. close(fd);
  154. } else if (todo == GET_CONF) {
  155. fd = open(fname, O_RDONLY);
  156. if (fd == -1) werr(ERR_BINSTAT);
  157. size = lseek(fd, 0, SEEK_END);
  158. map = (unsigned char*) mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);
  159. if ((void*)map == MAP_FAILED) goto fatal;
  160. /* Find the packdata */
  161. if ((offset = elf_find_data_mem_offset(fd, map, size, &settings.prefix,
  162. PREFIXLEN)) == 0) {
  163. goto fatal;
  164. }
  165. MD5_Update(&ctx, map, offset);
  166. /* Hash everything after the packdata too */
  167. MD5_Update(&ctx, &map[offset + sizeof(settings_t)], size - (offset + sizeof(settings_t)));
  168. MD5_Final(md5out, &ctx);
  169. btoh(md5out, MD5_DIGEST_LENGTH, hash, sizeof(hash));
  170. OPENSSL_cleanse(&ctx, sizeof(ctx));
  171. settings_t newsettings;
  172. /* Read the settings struct into newsettings */
  173. MMAP_READ(map, &newsettings, offset, sizeof(settings));
  174. /* Decrypt the new data */
  175. edpack(&newsettings, hash, PACK_DEC);
  176. OPENSSL_cleanse(hash, sizeof(hash));
  177. /* Copy over only the dynamic data, leaving the pack config static */
  178. memcpy(&settings.DYNAMIC_HEADER, &newsettings.DYNAMIC_HEADER, SIZE_CONF);
  179. OPENSSL_cleanse(&newsettings, sizeof(settings_t));
  180. munmap(map, size);
  181. close(fd);
  182. return ".";
  183. } else if (todo & WRITE_CHECKSUM) {
  184. newbin = new Tempfile("bin", 0);
  185. size = strlen(fname) + 2;
  186. fname_bak = (char *) my_calloc(1, size);
  187. simple_snprintf(fname_bak, size, "%s~", fname);
  188. fd = open(fname, O_RDONLY);
  189. if (fd == -1) werr(ERR_BINSTAT);
  190. size = lseek(fd, 0, SEEK_END);
  191. map = (unsigned char*) mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);
  192. if ((void*)map == MAP_FAILED) goto fatal;
  193. /* Find settings struct in original binary */
  194. if ((offset = elf_find_data_mem_offset(fd, map, size, &settings.prefix,
  195. PREFIXLEN)) == 0) {
  196. goto fatal;
  197. }
  198. MD5_Update(&ctx, map, offset);
  199. /* Hash everything after the packdata too */
  200. MD5_Update(&ctx, &map[offset + sizeof(settings_t)], size - (offset + sizeof(settings_t)));
  201. MD5_Final(md5out, &ctx);
  202. btoh(md5out, MD5_DIGEST_LENGTH, hash, sizeof(hash));
  203. OPENSSL_cleanse(&ctx, sizeof(ctx));
  204. strlcpy(settings.hash, hash, sizeof(settings.hash));
  205. /* encrypt the entire struct with the hash (including hash) */
  206. edpack(&settings, hash, PACK_ENC);
  207. //Don't clear hash if requested during the write.
  208. if (!(todo & GET_CHECKSUM))
  209. OPENSSL_cleanse(hash, sizeof(hash));
  210. if (ftruncate(newbin->fd, size)) goto fatal;
  211. /* Copy everything up to this point into the new binary (including the settings header/prefix) */
  212. outmap = (unsigned char*) mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, newbin->fd, 0);
  213. if ((void*)outmap == MAP_FAILED) goto fatal;
  214. offset += PREFIXLEN;
  215. memcpy(outmap, map, offset);
  216. newpos = offset;
  217. if (todo & WRITE_PACK) {
  218. /* Now copy in our encrypted settings struct */
  219. memcpy(&outmap[newpos], &settings.hash, SIZE_PACK);
  220. #ifdef DEBUG
  221. sdprintf(STR("writing pack: %zu\n"), SIZE_PACK);
  222. #endif
  223. } else {
  224. /* Just copy the original pack data to the new binary */
  225. memcpy(&outmap[newpos], &map[offset], SIZE_PACK);
  226. }
  227. offset += SIZE_PACK;
  228. newpos += SIZE_PACK;
  229. if (todo & WRITE_CONF) {
  230. /* Copy in the encrypted conf data */
  231. memcpy(&outmap[newpos], &settings.DYNAMIC_HEADER, SIZE_CONF);
  232. #ifdef DEBUG
  233. sdprintf(STR("writing conf: %zu\n"), SIZE_CONF);
  234. #endif
  235. } else {
  236. /* Just copy the original conf data to the new binary */
  237. memcpy(&outmap[newpos], &map[offset], SIZE_CONF);
  238. }
  239. newpos += SIZE_CONF;
  240. offset += SIZE_CONF;
  241. /* Write the rest of the binary */
  242. memcpy(&outmap[newpos], &map[offset], size - offset);
  243. newpos += size - offset;
  244. offset += size - offset;
  245. munmap(map, size);
  246. close(fd);
  247. munmap(outmap, size);
  248. newbin->my_close();
  249. if (size != newpos) {
  250. delete newbin;
  251. fatal(STR("Binary corrupted"), 0);
  252. }
  253. if (movefile(fname, fname_bak)) {
  254. printf(STR("Failed to move file (%s -> %s): %s\n"), fname, fname_bak, strerror(errno));
  255. delete newbin;
  256. fatal("", 0);
  257. }
  258. if (movefile(newbin->file, fname)) {
  259. printf(STR("Failed to move file (%s -> %s): %s\n"), newbin->file, fname, strerror(errno));
  260. delete newbin;
  261. fatal("", 0);
  262. }
  263. fixmod(fname);
  264. unlink(fname_bak);
  265. delete newbin;
  266. return hash;
  267. fatal:
  268. if ((void*)map != MAP_FAILED)
  269. munmap(map, size);
  270. if (fd != -1)
  271. close(fd);
  272. if ((void*)outmap != MAP_FAILED)
  273. munmap(outmap, size);
  274. delete newbin;
  275. werr(ERR_BINSTAT);
  276. }
  277. return hash;
  278. }
  279. static int
  280. features_find(const char *buffer)
  281. {
  282. if (!md5cmp(STR("9c24e09d643af8808b3e985a8bf1f2ce"), buffer))
  283. return FEATURE_1;
  284. else if (!md5cmp(STR("5593f7d910fde28a5988e3efbdb30bbf"), buffer))
  285. return FEATURE_2;
  286. return 0;
  287. }
  288. /* It is desirable to use this bit on systems that have it.
  289. The only bit of terminal state we want to twiddle is echoing, which is
  290. done in software; there is no need to change the state of the terminal
  291. hardware. */
  292. #ifndef TCSASOFT
  293. # define TCSASOFT 0
  294. #endif
  295. typedef struct line_list {
  296. struct line_list* next;
  297. int line;
  298. } line_list_t;
  299. static int
  300. readcfg(const char *cfgfile, bool read_stdin)
  301. {
  302. FILE *f = NULL;
  303. struct termios s, t;
  304. bool tty_changed = false;
  305. line_list_t *error_list = NULL, *error_line = NULL;
  306. if (read_stdin) {
  307. f = stdin;
  308. setbuf(stdin, NULL);
  309. setbuf(stdout, NULL);
  310. /* Taken from libc: getpass.c */
  311. /* Turn echoing off if it is on now. */
  312. if (tcgetattr (fileno (stdin), &t) == 0) {
  313. s = t;
  314. t.c_lflag &= ~(ECHO | ISIG);
  315. tty_changed = (tcsetattr (fileno (stdin), TCSAFLUSH | TCSASOFT, &t) == 0);
  316. }
  317. printf(STR("// Paste in your PACKCONFIG. Reference http://wraith.botpack.net/wiki/PackConfig\n"));
  318. printf(STR("// Press <enter> if it gets hung up. If that doesn't work hit ^D (CTRL+d)\n"));
  319. fflush(stdout);
  320. } else {
  321. if ((f = fopen(cfgfile, "r")) == NULL) {
  322. fprintf(stderr, STR("Error: Can't open '%s' for reading\n"), cfgfile);
  323. exit(1);
  324. }
  325. }
  326. char *buffer = NULL, *p = NULL;
  327. int skip = 0, line = 0, feature = 0;
  328. bool error = 0;
  329. bd::Array<bd::String> words;
  330. bd::String line_str;
  331. #define ADD_ERROR(str) \
  332. if (line != -1) { \
  333. fprintf(stderr, "\n[Line %2d]: %s\n", line, str); \
  334. error_line = (line_list_t *) my_calloc(1, sizeof(line_list_t)); \
  335. error_line->line = line; \
  336. error_line->next = NULL; \
  337. list_append((struct list_type **) &(error_list), (struct list_type *) error_line); \
  338. } else \
  339. fprintf(stderr, "\n%s\n", str); \
  340. error = 1
  341. settings.salt1[0] = settings.salt2[0] = 0;
  342. if (!read_stdin) {
  343. printf(STR("Reading '%s' "), cfgfile);
  344. fflush(stdout);
  345. }
  346. while ((!feof(f)) && ((buffer = step_thru_file(f)) != NULL)) {
  347. if (tty_changed) {
  348. printf(".");
  349. fflush(stdout);
  350. }
  351. ++line;
  352. if ((*buffer)) {
  353. if (strchr(buffer, '\n'))
  354. *(char *) strchr(buffer, '\n') = 0;
  355. if ((skipline(buffer, &skip)))
  356. continue;
  357. if ((strchr(buffer, '<') || strchr(buffer, '>')) && !strstr(buffer, "SALT")) {
  358. ADD_ERROR(STR("Invalid <>"));
  359. }
  360. p = strchr(buffer, ' ');
  361. while (p && (strchr(LISTSEPERATORS, p[0])))
  362. *p++ = 0;
  363. if (p) {
  364. line_str = bd::String(trim(p));
  365. words = line_str.split(" ");
  366. if (!strcasecmp(buffer, STR("packname"))) {
  367. if (words.length() == 0) {
  368. ADD_ERROR(STR("PACKNAME requires argument"));
  369. }
  370. strlcpy(settings.packname, line_str.c_str(), sizeof settings.packname);
  371. } else if (!strcasecmp(buffer, STR("shellhash")) || !strcasecmp(buffer, STR("binarypass"))) {
  372. if (line_str.length() != 40 && line_str.length() != 47) {
  373. ADD_ERROR(STR("BINARYPASS should be a SHA1 hash or salted-SHA1 hash."));
  374. }
  375. strlcpy(settings.shellhash, line_str.c_str(), sizeof settings.shellhash);
  376. } else if (!strcasecmp(buffer, STR("dccprefix"))) {
  377. if (words.length() == 0) {
  378. ADD_ERROR(STR("DCCPREFIX requires argument"));
  379. }
  380. strlcpy(settings.dcc_prefix, line_str.c_str(), 2);
  381. } else if (!strcasecmp(buffer, STR("owner"))) {
  382. if (words.length() < 2) {
  383. ADD_ERROR(STR("OWNER requires 2 arguments: nick password"));
  384. }
  385. strlcat(settings.owners, line_str.c_str(), sizeof(settings.owners));
  386. strlcat(settings.owners, ",", sizeof(settings.owners));
  387. } else if (!strcasecmp(buffer, STR("hub"))) {
  388. if (words.length() < 3) {
  389. ADD_ERROR(STR("HUB requires 3 arguments: nick host port"));
  390. }
  391. strlcat(settings.hubs, line_str.c_str(), sizeof(settings.hubs));
  392. strlcat(settings.hubs, ",", sizeof(settings.hubs));
  393. } else if (!strcasecmp(buffer, STR("salt1"))) {
  394. if (words.length() == 0) {
  395. ADD_ERROR(STR("SALT1 requires argument"));
  396. }
  397. strlcat(settings.salt1, line_str.c_str(), sizeof(settings.salt1));
  398. } else if (!strcasecmp(buffer, STR("salt2"))) {
  399. if (words.length() == 0) {
  400. ADD_ERROR(STR("SALT2 requires argument"));
  401. }
  402. strlcat(settings.salt2, line_str.c_str(), sizeof(settings.salt2));
  403. if (read_stdin) break;
  404. }
  405. } else { /* SINGLE DIRECTIVES */
  406. if ((feature = features_find(buffer))) {
  407. int features = atol(settings.features);
  408. features |= feature;
  409. simple_snprintf(settings.features, sizeof(settings.features), "%d", features);
  410. }
  411. }
  412. }
  413. buffer = NULL;
  414. }
  415. if (f && !read_stdin) {
  416. fclose(f);
  417. } else if (read_stdin && tty_changed) {
  418. /* Restore the original setting. */
  419. tcsetattr (fileno (stdin), TCSAFLUSH | TCSASOFT, &s);
  420. }
  421. line = -1;
  422. /* Was the entire pack read in? */
  423. if (!settings.packname[0]) {
  424. ADD_ERROR(STR("Missing PACKNAME"));
  425. }
  426. if (!settings.dcc_prefix[0]) {
  427. ADD_ERROR(STR("Missing DCCPREFIX"));
  428. }
  429. if (!settings.shellhash[0]) {
  430. ADD_ERROR(STR("Missing BINARYPASS"));
  431. }
  432. if (!settings.owners[0]) {
  433. ADD_ERROR(STR("Missing OWNER"));
  434. }
  435. if (!settings.hubs[0]) {
  436. ADD_ERROR(STR("Missing HUBS"));
  437. }
  438. if (!settings.salt1[0] || !settings.salt2[0]) {
  439. ADD_ERROR(STR("Missing SALTS"));
  440. }
  441. if (error) {
  442. printf("\n");
  443. fprintf(stderr, STR("Error: Look at your configuration again and fix any errors.\n"));
  444. for (error_line = error_list; error_line; error_line = error_line->next)
  445. fprintf(stderr, STR("Line %d\n"), error_line->line);
  446. exit(1);
  447. }
  448. if (!read_stdin) printf(STR(" Success\n"));
  449. else printf("\n");
  450. return 1;
  451. }
  452. void writecfg() {
  453. const char salt1[] = SALT1;
  454. const char salt2[] = SALT2;
  455. bd::Array<bd::String> owners(bd::String(settings.owners).split(","));
  456. const bd::Array<bd::String> hubs(conf.hubs);
  457. bd::Array<bd::String> hubInfo;
  458. printf("PACKNAME %s\n", settings.packname);
  459. // Display the shellhash as salted-sha1 if it is not already
  460. bd::String shellhash(settings.shellhash);
  461. printf("BINARYPASS %s\n", (shellhash.length() == 40 || shellhash.length() == 47) ? shellhash.c_str() : salted_sha1(shellhash.c_str()));
  462. printf("DCCPREFIX %s\n", settings.dcc_prefix);
  463. for (size_t i = 0; i < owners.length(); ++i) {
  464. bd::Array<bd::String> ownerInfo(static_cast<bd::String>(owners[i]).split(" "));
  465. // Ensure the pass is salted-sha1
  466. const size_t ownerPassLength = static_cast<bd::String>(ownerInfo[1]).length();
  467. if (ownerPassLength != 40 && ownerPassLength != 47) {
  468. ownerInfo[1] = bd::String(salted_sha1(static_cast<bd::String>(ownerInfo[1]).c_str()));
  469. }
  470. printf("OWNER %s\n", ownerInfo.join(" ").c_str());
  471. }
  472. for (size_t i = 0; i < hubs.length(); ++i) {
  473. hubInfo = static_cast<bd::String>(hubs[i]).split(' ');
  474. // Trim away hublevel
  475. if (hubInfo.length() == 4) {
  476. hubInfo.resize(3);
  477. }
  478. printf("HUB %s\n", static_cast<bd::String>(hubInfo.join(" ")).c_str());
  479. }
  480. printf("SALT1 %s\n", salt1);
  481. printf("SALT2 %s\n", salt2);
  482. }
  483. static void edpack(settings_t *incfg, const char *in_hash, int what)
  484. {
  485. char *tmp = NULL, *hash = (char *) in_hash, nhash[51] = "";
  486. unsigned char *(*enc_dec_string)(const char *, unsigned char *, size_t *);
  487. size_t len = 0;
  488. if (what == PACK_ENC)
  489. enc_dec_string = aes_encrypt_ecb_binary;
  490. else
  491. enc_dec_string = aes_decrypt_ecb_binary;
  492. #define dofield(_field) do { \
  493. if (_field) { \
  494. len = sizeof(_field) - 1; \
  495. tmp = (char *) enc_dec_string(hash, (unsigned char *) _field, &len); \
  496. if (what == PACK_ENC) \
  497. memcpy(_field, tmp, len); \
  498. else \
  499. simple_snprintf(_field, sizeof(_field), "%s", tmp); \
  500. OPENSSL_cleanse(tmp, len); \
  501. free(tmp); \
  502. } \
  503. } while (0)
  504. #define dohash(_field) do { \
  505. if (what == PACK_ENC) \
  506. strlcat(nhash, _field, sizeof(nhash)); \
  507. dofield(_field); \
  508. if (what == PACK_DEC) \
  509. strlcat(nhash, _field, sizeof(nhash)); \
  510. } while (0)
  511. #define update_hash() do { \
  512. MD5(NULL); \
  513. hash = MD5(nhash); \
  514. OPENSSL_cleanse(nhash, sizeof(nhash)); \
  515. nhash[0] = 0; \
  516. } while (0)
  517. /* -- STATIC -- */
  518. dohash(incfg->hash);
  519. dohash(incfg->packname);
  520. update_hash();
  521. dohash(incfg->shellhash);
  522. update_hash();
  523. dofield(incfg->dcc_prefix);
  524. dofield(incfg->features);
  525. dofield(incfg->owners);
  526. dofield(incfg->hubs);
  527. dohash(incfg->salt1);
  528. dohash(incfg->salt2);
  529. update_hash();
  530. /* -- DYNAMIC -- */
  531. dofield(incfg->dynamic_initialized);
  532. dofield(incfg->conf_hubs);
  533. dofield(incfg->bots);
  534. dofield(incfg->uid);
  535. dofield(incfg->autocron);
  536. dofield(incfg->username);
  537. dofield(incfg->datadir);
  538. dofield(incfg->homedir);
  539. dofield(incfg->portmin);
  540. dofield(incfg->portmax);
  541. OPENSSL_cleanse(nhash, sizeof(nhash));
  542. #undef dofield
  543. #undef dohash
  544. #undef update_hash
  545. }
  546. #ifdef DEBUG
  547. static void
  548. tellconfig(settings_t *incfg)
  549. {
  550. #define dofield(_field) printf("%s: %s\n", #_field, _field);
  551. // -- STATIC --
  552. dofield(incfg->hash);
  553. dofield(incfg->packname);
  554. dofield(incfg->shellhash);
  555. dofield(incfg->dcc_prefix);
  556. dofield(incfg->features);
  557. dofield(incfg->owners);
  558. dofield(incfg->hubs);
  559. // dofield(incfg->salt1);
  560. // dofield(incfg->salt2);
  561. // -- DYNAMIC --
  562. dofield(incfg->dynamic_initialized);
  563. dofield(incfg->conf_hubs);
  564. dofield(incfg->bots);
  565. dofield(incfg->uid);
  566. dofield(incfg->autocron);
  567. dofield(incfg->username);
  568. dofield(incfg->datadir);
  569. dofield(incfg->homedir);
  570. dofield(incfg->portmin);
  571. dofield(incfg->portmax);
  572. #undef dofield
  573. }
  574. #endif
  575. void
  576. check_sum(const char *fname, const char *cfgfile, bool read_stdin)
  577. {
  578. if (!settings.hash[0]) {
  579. if (!cfgfile && !read_stdin)
  580. fatal(STR("Binary not initialized."), 0);
  581. readcfg(cfgfile, read_stdin);
  582. // tellconfig(&settings);
  583. if (bin_checksum(fname, WRITE_CHECKSUM|WRITE_CONF|WRITE_PACK))
  584. printf(STR("* Wrote settings to binary.\n"));
  585. exit(0);
  586. } else {
  587. char *hash = bin_checksum(fname, GET_CHECKSUM);
  588. // tellconfig(&settings);
  589. edpack(&settings, hash, PACK_DEC);
  590. INIT_SALTS;
  591. OPENSSL_cleanse(settings.salt1, sizeof(settings.salt1));
  592. OPENSSL_cleanse(settings.salt2, sizeof(settings.salt2));
  593. #ifdef DEBUG
  594. tellconfig(&settings);
  595. #endif
  596. int n = strcmp(settings.hash, hash);
  597. OPENSSL_cleanse(settings.hash, sizeof(settings.hash));
  598. OPENSSL_cleanse(hash, strlen(hash));
  599. if (n) {
  600. OPENSSL_cleanse(&settings, sizeof(settings_t));
  601. CLEAR_SALTS;
  602. }
  603. }
  604. }
  605. /*
  606. * @returns 0 = initialized, 1 = not initialized, 2 = corrupted
  607. */
  608. int check_bin_initialized(const char *fname)
  609. {
  610. const char* argv[] = {fname, "-p", 0};
  611. int i = simple_exec(argv);
  612. if (i != -1) {
  613. if (WEXITSTATUS(i) == 4)
  614. return 0;
  615. else if (WEXITSTATUS(i) == 5)
  616. return 1;
  617. }
  618. return 2;
  619. }
  620. bool check_bin_compat(const char *fname)
  621. {
  622. size_t len = strlen(shell_escape(fname)) + 3 + 1;
  623. char *path = (char *) my_calloc(1, len);
  624. char *out = NULL;
  625. simple_snprintf(path, len, STR("%s -3"), shell_escape(fname));
  626. if (shell_exec(path, NULL, &out, NULL, 1)) {
  627. if (out) {
  628. char *buf = out;
  629. size_t settings_ver = atoi(newsplit(&buf)), settings_len = atoi(newsplit(&buf));
  630. if (settings_ver == SETTINGS_VER && settings_len == sizeof(settings_t)) {
  631. free(path);
  632. free(out);
  633. return 1;
  634. }
  635. free(out);
  636. }
  637. }
  638. free(path);
  639. return 0;
  640. }
  641. void write_settings(const char *fname, int die, bool doconf, int initialized)
  642. {
  643. char *hash = NULL;
  644. int bits = WRITE_CHECKSUM;
  645. /* see if the binary is already initialized or not */
  646. if (initialized == -1)
  647. initialized = check_bin_initialized(fname) ? 0 : 1;
  648. /* only write pack data if the binary is uninitialized
  649. * otherwise, assume it has similar/correct/updated pack data
  650. */
  651. if (!initialized)
  652. bits |= WRITE_PACK;
  653. if (doconf)
  654. bits |= WRITE_CONF;
  655. /* only bother writing anything if we have pack or doconf, checksum is worthless to write out */
  656. if (bits & (WRITE_PACK|WRITE_CONF)) {
  657. // Also get the checksum
  658. if (die == -1)
  659. bits |= GET_CHECKSUM;
  660. const char salt1[] = SALT1;
  661. const char salt2[] = SALT2;
  662. strlcpy(settings.salt1, salt1, sizeof(settings.salt1));
  663. strlcpy(settings.salt2, salt2, sizeof(settings.salt2));
  664. if ((hash = bin_checksum(fname, bits))) {
  665. printf(STR("* Wrote %ssettings to: %s.\n"), ((bits & WRITE_PACK) && !(bits & WRITE_CONF)) ? "pack " :
  666. ((bits & WRITE_CONF) && !(bits & WRITE_PACK)) ? "conf " :
  667. ((bits & WRITE_PACK) && (bits & WRITE_CONF)) ? "pack/conf " :
  668. "",
  669. fname);
  670. if (die == -1) { /* only bother decrypting if we aren't about to exit */
  671. edpack(&settings, hash, PACK_DEC);
  672. INIT_SALTS;
  673. OPENSSL_cleanse(hash, strlen(hash));
  674. }
  675. }
  676. if (die == -1) {
  677. OPENSSL_cleanse(settings.salt1, sizeof(settings.salt1));
  678. OPENSSL_cleanse(settings.salt2, sizeof(settings.salt2));
  679. }
  680. }
  681. if (die >= 0)
  682. exit(die);
  683. }
  684. static void
  685. clear_settings(void)
  686. {
  687. // memset(&settings.bots, 0, sizeof(settings_t) - SIZE_PACK - PREFIXLEN);
  688. memset(&settings.DYNAMIC_HEADER, 0, SIZE_CONF);
  689. }
  690. void conf_to_bin(conf_t *in, bool move, int die)
  691. {
  692. conf_bot *bot = NULL;
  693. char *newbin = NULL;
  694. clear_settings();
  695. sdprintf("converting conf to bin\n");
  696. simple_snprintf(settings.uid, sizeof(settings.uid), "%d", in->uid);
  697. strlcpy(settings.dynamic_initialized, "1", sizeof(settings.dynamic_initialized));
  698. simple_snprintf(settings.autocron, sizeof(settings.autocron), "%d", in->autocron);
  699. simple_snprintf(settings.portmin, sizeof(settings.portmin), "%d", in->portmin);
  700. simple_snprintf(settings.portmax, sizeof(settings.portmax), "%d", in->portmax);
  701. if (in->username)
  702. strlcpy(settings.username, in->username, sizeof(settings.username));
  703. strlcpy(settings.datadir, in->datadir, sizeof(settings.datadir));
  704. if (in->homedir)
  705. strlcpy(settings.homedir, in->homedir, sizeof(settings.homedir));
  706. for (bot = in->bots; bot && bot->nick; bot = bot->next) {
  707. simple_snprintf(settings.bots, sizeof(settings.bots), STR("%s%s%s %s %s%s %s,"),
  708. settings.bots && settings.bots[0] ? settings.bots : "",
  709. bot->disabled ? "/" : "",
  710. bot->nick,
  711. bot->net.ip ? bot->net.ip : "*",
  712. bot->net.host6 ? "+" : "",
  713. bot->net.host ? bot->net.host : (bot->net.host6 ? bot->net.host6 : "*"),
  714. bot->net.ip6 ? bot->net.ip6 : "");
  715. }
  716. simple_snprintf(settings.conf_hubs, sizeof(settings.conf_hubs), in->hubs.join(',').c_str());
  717. newbin = binname;
  718. // tellconfig(&settings);
  719. write_settings(newbin, -1, 1);
  720. if (die >= 0)
  721. exit(die);
  722. }
  723. void reload_bin_data() {
  724. if (bin_checksum(binname, GET_CONF)) {
  725. putlog(LOG_MISC, "*", STR("Rehashed config data from binary."));
  726. conf_bot *oldbots = NULL, *oldbot = NULL;
  727. bool was_localhub = conf.bot->localhub ? 1 : 0;
  728. /* save the old bots list */
  729. if (conf.bots)
  730. oldbots = conf_bots_dup(conf.bots);
  731. /* Save the old conf.bot */
  732. oldbot = (conf_bot *) my_calloc(1, sizeof(conf_bot));
  733. conf_bot_dup(oldbot, conf.bot);
  734. /* free up our current conf struct */
  735. free_conf();
  736. /* Fill conf[] with binary data from settings[] */
  737. bin_to_conf();
  738. /* fill up conf.bot using origbotname */
  739. fill_conf_bot(0); /* 0 to avoid exiting if conf.bot cannot be filled */
  740. if (was_localhub) {
  741. /* add any new bots not in userfile */
  742. conf_add_userlist_bots();
  743. /* deluser removed bots from conf */
  744. if (oldbots)
  745. deluser_removed_bots(oldbots, conf.bots);
  746. }
  747. if (conf.bot && conf.bot->disabled) {
  748. if (tands > 0) {
  749. botnet_send_chat(-1, conf.bot->nick, STR("Bot disabled in binary."));
  750. botnet_send_bye(STR("Bot disabled in binary."));
  751. }
  752. if (server_online)
  753. nuke_server(STR("bbl"));
  754. werr(ERR_BOTDISABLED);
  755. } else if (!conf.bot) {
  756. conf.bot = oldbot;
  757. if (tands > 0) {
  758. botnet_send_chat(-1, conf.bot->nick, STR("Bot removed from binary."));
  759. botnet_send_bye(STR("Bot removed from binary."));
  760. }
  761. if (server_online)
  762. nuke_server(STR("it's been good, cya"));
  763. werr(ERR_BADBOT);
  764. }
  765. /* The bot nick changed! (case) */
  766. if (strcmp(conf.bot->nick, oldbot->nick)) {
  767. change_handle(conf.bot->u, conf.bot->nick);
  768. // var_set_by_name(conf.bot->nick, "nick", conf.bot->nick);
  769. // var_set_userentry(conf.bot->nick, "nick", conf.bot->nick);
  770. }
  771. free_bot(oldbot);
  772. if (oldbots)
  773. free_conf_bots(oldbots);
  774. if (!conf.bot->localhub && !conf.bot->hub) {
  775. free_conf_bots(conf.bots);
  776. if (was_localhub) {
  777. //Close the listening port
  778. for (int i = 0; i < dcc_total; i++) {
  779. if (dcc[i].type && (dcc[i].type == &DCC_TELNET) && (strchr(dcc[i].host, '/'))) {
  780. unlink(dcc[i].host);
  781. killsock(dcc[i].sock);
  782. lostdcc(i);
  783. }
  784. }
  785. }
  786. }
  787. }
  788. }
  789. /* vim: set sts=2 sw=2 ts=8 et: */