| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662 |
- /*
- * binary.c -- handles:
- * misc update functions
- * md5 hash verifying
- *
- */
- #include "common.h"
- #include "binary.h"
- #include "settings.h"
- #include "crypt.h"
- #include "shell.h"
- #include "misc.h"
- #include "main.h"
- #include "misc_file.h"
- #include "tandem.h"
- #include "botnet.h"
- #include "userrec.h"
- #include <sys/wait.h>
- #include <sys/types.h>
- #include <signal.h>
- settings_t settings = {
- "\200\200\200\200\200\200\200\200\200\200\200\200\200\200\200",
- /* -- STATIC -- */
- "", "", "", "", "", "", "", "", "", "", "",
- /* -- DYNAMIC -- */
- "", "", "", "", "", "", "", "", "", "", "", "", "", "",
- /* -- PADDING */
- ""
- };
- static void edpack(settings_t *, const char *, int);
- #define PACK_ENC 1
- #define PACK_DEC 2
- int checked_bin_buf = 0;
- static char *
- bin_checksum(const char *fname, int todo)
- {
- MD5_CTX ctx;
- static char hash[MD5_HASH_LENGTH + 1] = "";
- unsigned char md5out[MD5_HASH_LENGTH + 1] = "", buf[PREFIXLEN + 1] = "";
- FILE *f = NULL;
- size_t len = 0;
- MD5_Init(&ctx);
- checked_bin_buf++;
-
- hash[0] = 0;
- fixmod(fname);
- if (todo == GET_CHECKSUM) {
- if (!(f = fopen(fname, "rb")))
- werr(ERR_BINSTAT);
- while ((len = fread(buf, 1, sizeof buf - 1, f))) {
- if (!memcmp(buf, &settings.prefix, PREFIXLEN))
- break;
- MD5_Update(&ctx, buf, len);
- }
- fclose(f);
- f = NULL;
- MD5_Final(md5out, &ctx);
- strlcpy(hash, btoh(md5out, MD5_DIGEST_LENGTH), sizeof(hash));
- OPENSSL_cleanse(&ctx, sizeof(ctx));
- }
- if (todo == GET_CONF) {
- char *oldhash = strdup(settings.hash);
- if (!(f = fopen(fname, "rb")))
- werr(ERR_BINSTAT);
- while ((len = fread(buf, 1, sizeof buf - 1, f)))
- if (!memcmp(buf, &settings.prefix, PREFIXLEN))
- break;
- char *tmpbuf = (char *) my_calloc(1, SIZE_PACK);
-
- if ((len = fread(tmpbuf, 1, SIZE_PACK, f))) {
- edpack(&settings, oldhash, PACK_ENC);
- len = fread(&settings.bots, 1, SIZE_CONF, f);
- edpack(&settings, oldhash, PACK_DEC);
- } else
- return NULL;
- free(oldhash);
- fclose(f);
- return settings.hash;
- }
- if (todo & WRITE_CHECKSUM) {
- Tempfile *newbin = new Tempfile("bin");
- char *fname_bak = NULL;
- size_t size = 0, newpos = 0;
- size = strlen(fname) + 2;
- fname_bak = (char *) my_calloc(1, size);
- simple_snprintf(fname_bak, size, "%s~", fname);
- size = 0;
- if (!(f = fopen(fname, "rb")))
- goto fatal;
- fseek(f, 0, SEEK_END);
- size = ftell(f);
- fseek(f, 0, SEEK_SET);
- newpos = 0;
- while ((len = fread(buf, 1, sizeof(buf) - 1, f))) {
- if (fwrite(buf, 1, len, newbin->f) != len)
- goto fatal;
- newpos += len;
- if (!memcmp(buf, &settings.prefix, PREFIXLEN)) { /* found the settings struct! */
- MD5_Final(md5out, &ctx);
- strlcpy(hash, btoh(md5out, MD5_DIGEST_LENGTH), sizeof(hash));
- OPENSSL_cleanse(&ctx, sizeof(ctx));
- strlcpy(settings.hash, hash, 65);
- edpack(&settings, hash, PACK_ENC); /* encrypt the entire struct with the hash (including hash) */
- if (todo & WRITE_PACK) {
- fwrite(&settings.hash, SIZE_PACK, 1, newbin->f);
- sdprintf("writing pack: %d\n", SIZE_PACK);
- } else {
- char *tmpbuf = (char *) my_calloc(1, SIZE_PACK);
- if ((len = fread(tmpbuf, 1, SIZE_PACK, f))) {
- if (fwrite(tmpbuf, 1, len, newbin->f) != len) {
- free(tmpbuf);
- goto fatal;
- }
- }
- free(tmpbuf);
- }
- newpos += SIZE_PACK;
- if (todo & WRITE_CONF) {
- fwrite(&settings.bots, SIZE_CONF, 1, newbin->f);
- sdprintf("writing conf: %d\n", SIZE_CONF);
- } else {
- char *tmpbuf = (char *) my_calloc(1, SIZE_CONF);
- if ((len = fread(tmpbuf, 1, SIZE_CONF, f))) {
- if (fwrite(tmpbuf, 1, len, newbin->f) != len) {
- free(tmpbuf);
- goto fatal;
- }
- }
- free(tmpbuf);
- }
- newpos += SIZE_CONF;
- fseek(newbin->f, newpos + SIZE_PAD, SEEK_SET);
- newpos += SIZE_PAD;
- /* skip reading over the stuff we already wrote */
- fseek(f, newpos, SEEK_SET);
- } else if (!hash[0]) /* hash as long as we haven't reached the prefix */
- MD5_Update(&ctx, buf, len);
- }
- fclose(f);
- f = NULL;
- newbin->my_close();
- if (size != newpos) {
- delete newbin;
- fatal("Binary corrupted", 0);
- }
- if (movefile(fname, fname_bak)) {
- printf("Failed to move file (%s -> %s): %s\n", fname, fname_bak, strerror(errno));
- delete newbin;
- fatal("", 0);
- }
- if (movefile(newbin->file, fname)) {
- printf("Failed to move file (%s -> %s): %s\n", newbin->file, fname, strerror(errno));
- delete newbin;
- fatal("", 0);
- }
- fixmod(fname);
- unlink(fname_bak);
- delete newbin;
-
- return hash;
- fatal:
- if (f)
- fclose(f);
- delete newbin;
- werr(ERR_BINSTAT);
- }
- return hash;
- }
- static int
- features_find(const char *buffer)
- {
- if (!egg_strcasecmp(buffer, STR("no_take")))
- return FEATURE_NO_TAKE;
- else if (!egg_strcasecmp(buffer, STR("no_mdop")))
- return FEATURE_NO_MDOP;
- else if (!egg_strcasecmp(buffer, STR("beta")))
- return FEATURE_BETA;
- return 0;
- }
- static int
- readcfg(const char *cfgfile)
- {
- FILE *f = NULL;
- if ((f = fopen(cfgfile, "r")) == NULL) {
- printf("Error: Can't open '%s' for reading\n", cfgfile);
- exit(1);
- }
- char *buffer = NULL, *p = NULL;
- int skip = 0, line = 0, feature = 0;
- printf("Reading '%s' ", cfgfile);
- while ((!feof(f)) && ((buffer = step_thru_file(f)) != NULL)) {
- line++;
- if ((*buffer)) {
- if (strchr(buffer, '\n'))
- *(char *) strchr(buffer, '\n') = 0;
- if ((skipline(buffer, &skip)))
- continue;
- if (strchr(buffer, '<') || strchr(buffer, '>')) {
- printf(" Failed\n");
- printf("%s:%d: error: Look at your configuration file again...\n", cfgfile, line);
- // exit(1);
- }
- p = strchr(buffer, ' ');
- while (p && (strchr(LISTSEPERATORS, p[0])))
- *p++ = 0;
- if (p) {
- if (!egg_strcasecmp(buffer, "packname")) {
- strlcpy(settings.packname, trim(p), sizeof settings.packname);
- printf(".");
- } else if (!egg_strcasecmp(buffer, "shellhash")) {
- strlcpy(settings.shellhash, trim(p), sizeof settings.shellhash);
- printf(".");
- } else if (!egg_strcasecmp(buffer, "bdhash")) {
- strlcpy(settings.bdhash, trim(p), sizeof settings.bdhash);
- printf(".");
- } else if (!egg_strcasecmp(buffer, "dccprefix")) {
- strlcpy(settings.dcc_prefix, trim(p), sizeof settings.dcc_prefix);
- printf(".");
- } else if (!egg_strcasecmp(buffer, "owner")) {
- strcat(settings.owners, trim(p));
- strcat(settings.owners, ",");
- printf(".");
- } else if (!egg_strcasecmp(buffer, "owneremail")) {
- strcat(settings.owneremail, trim(p));
- strcat(settings.owneremail, ",");
- printf(".");
- } else if (!egg_strcasecmp(buffer, "hub")) {
- strcat(settings.hubs, trim(p));
- strcat(settings.hubs, ",");
- printf(".");
- } else if (!egg_strcasecmp(buffer, "salt1")) {
- strcat(settings.salt1, trim(p));
- printf(".");
- } else if (!egg_strcasecmp(buffer, "salt2")) {
- strcat(settings.salt2, trim(p));
- printf(".");
- } else {
- printf("%s %s\n", buffer, p);
- printf(",");
- }
- } else { /* SINGLE DIRECTIVES */
- if ((feature = features_find(buffer))) {
- int features = atol(settings.features);
- features |= feature;
- simple_snprintf(settings.features, sizeof(settings.features), "%d", features);
- printf(".");
- }
- }
- }
- buffer = NULL;
- }
- if (f)
- fclose(f);
- if (!settings.salt1[0] || !settings.salt2[0]) {
- /* Write salts back to the cfgfile */
- char salt1[SALT1LEN + 1] = "", salt2[SALT2LEN + 1] = "";
- printf("Creating Salts");
- if ((f = fopen(cfgfile, "a")) == NULL) {
- printf("Cannot open cfgfile for appending.. aborting\n");
- exit(1);
- }
- make_rand_str(salt1, SALT1LEN);
- make_rand_str(salt2, SALT2LEN);
- salt1[sizeof salt1] = salt2[sizeof salt2] = 0;
- fprintf(f, "SALT1 %s\n", salt1);
- fprintf(f, "SALT2 %s\n", salt2);
- fflush(f);
- fclose(f);
- }
- printf(" Success\n");
- return 1;
- }
- static void edpack(settings_t *incfg, const char *in_hash, int what)
- {
- char *tmp = NULL, *hash = (char *) in_hash, nhash[51] = "";
- unsigned char *(*enc_dec_string)(const char *, unsigned char *, size_t *);
- size_t len = 0;
- if (what == PACK_ENC)
- enc_dec_string = encrypt_binary;
- else
- enc_dec_string = decrypt_binary;
- #define dofield(_field) do { \
- if (_field) { \
- len = sizeof(_field) - 1; \
- tmp = (char *) enc_dec_string(hash, (unsigned char *) _field, &len); \
- if (what == PACK_ENC) \
- egg_memcpy(_field, tmp, len); \
- else \
- simple_snprintf(_field, sizeof(_field), "%s", tmp); \
- free(tmp); \
- } \
- } while (0)
- //FIXME: Maybe this should be done for EACH dofield(), ie, each entry changes the encryption for next line?
- //makes it harder to fuck with, then again, maybe current is fine?
- #define dohash(_field) do { \
- if (what == PACK_ENC) \
- simple_snprintf(nhash, sizeof(nhash), "%s%s", nhash[0] ? nhash : "", _field); \
- dofield(_field); \
- if (what == PACK_DEC) \
- simple_snprintf(nhash, sizeof(nhash), "%s%s", nhash[0] ? nhash : "", _field); \
- } while (0)
- #define update_hash() do { \
- hash = MD5(nhash); \
- nhash[0] = 0; \
- } while (0)
- /* -- STATIC -- */
- dohash(incfg->hash);
- dohash(incfg->packname);
- update_hash();
- dohash(incfg->shellhash);
- dohash(incfg->bdhash);
- update_hash();
- dofield(incfg->dcc_prefix);
- dofield(incfg->features);
- dofield(incfg->owners);
- dofield(incfg->owneremail);
- dofield(incfg->hubs);
- dohash(incfg->salt1);
- dohash(incfg->salt2);
- update_hash();
- /* -- DYNAMIC -- */
- dofield(incfg->bots);
- dofield(incfg->uid);
- dofield(incfg->autouname);
- dofield(incfg->pscloak);
- dofield(incfg->autocron);
- dofield(incfg->watcher);
- dofield(incfg->uname);
- dofield(incfg->username);
- dofield(incfg->datadir);
- dofield(incfg->homedir);
- dofield(incfg->binpath);
- dofield(incfg->binname);
- dofield(incfg->portmin);
- dofield(incfg->portmax);
- OPENSSL_cleanse(nhash, sizeof(nhash));
- #undef dofield
- #undef dohash
- #undef update_hash
- }
- #ifdef DEBUG
- static void
- tellconfig(settings_t *incfg)
- {
- #define dofield(_field) printf("%s: %s\n", #_field, _field);
- // -- STATIC --
- dofield(incfg->hash);
- dofield(incfg->packname);
- dofield(incfg->shellhash);
- dofield(incfg->bdhash);
- dofield(incfg->dcc_prefix);
- dofield(incfg->features);
- dofield(incfg->owners);
- dofield(incfg->owneremail);
- dofield(incfg->hubs);
- dofield(incfg->salt1);
- dofield(incfg->salt2);
- // -- DYNAMIC --
- dofield(incfg->bots);
- dofield(incfg->uid);
- dofield(incfg->autouname);
- dofield(incfg->pscloak);
- dofield(incfg->autocron);
- dofield(incfg->watcher);
- dofield(incfg->uname);
- dofield(incfg->username);
- dofield(incfg->datadir);
- dofield(incfg->homedir);
- dofield(incfg->binpath);
- dofield(incfg->binname);
- dofield(incfg->portmin);
- dofield(incfg->portmax);
- #undef dofield
- }
- #endif
- void
- check_sum(const char *fname, const char *cfgfile)
- {
- if (!settings.hash[0]) {
- if (!cfgfile)
- fatal("Binary not initialized.", 0);
- readcfg(cfgfile);
- // tellconfig(&settings);
- if (bin_checksum(fname, WRITE_CHECKSUM|WRITE_CONF|WRITE_PACK))
- printf("* Wrote settings to binary.\n");
- exit(0);
- } else {
- char *hash = bin_checksum(fname, GET_CHECKSUM);
- // tellconfig(&settings);
- edpack(&settings, hash, PACK_DEC);
- #ifdef DEBUG
- tellconfig(&settings);
- #endif
- if (strcmp(settings.hash, hash)) {
- unlink(fname);
- fatal("!! Invalid binary", 0);
- }
- }
- }
- static bool check_bin_initialized(const char *fname)
- {
- int i = 0;
- size_t len = strlen(shell_escape(fname)) + 3 + 1;
- char *path = (char *) my_calloc(1, len);
- simple_snprintf(path, len, "%s -p", shell_escape(fname));
- i = system(path);
- free(path);
- if (i != -1 && WEXITSTATUS(i) == 4)
- return 1;
- return 0;
- }
- void write_settings(const char *fname, int die, bool conf)
- {
- char *hash = NULL;
- int bits = WRITE_CHECKSUM;
- /* see if the binary is already initialized or not */
- bool initialized = check_bin_initialized(fname);
- /* only write pack data if the binary is uninitialized
- * otherwise, assume it has similar/correct/updated pack data
- */
- if (!initialized)
- bits |= WRITE_PACK;
- if (conf)
- bits |= WRITE_CONF;
- /* only bother writing anything if we have pack or conf, checksum is worthless to write out */
- if (bits & (WRITE_PACK|WRITE_CONF)) {
- if ((hash = bin_checksum(fname, bits))) {
- printf("* Wrote %ssettings to: %s.\n", ((bits & WRITE_PACK) && !(bits & WRITE_CONF)) ? "pack " :
- ((bits & WRITE_CONF) && !(bits & WRITE_PACK)) ? "conf " :
- ((bits & WRITE_PACK) && (bits & WRITE_CONF)) ? "pack/conf " :
- "",
- fname);
- if (die == -1) /* only bother decrypting if we aren't about to exit */
- edpack(&settings, hash, PACK_DEC);
- }
- }
- if (die >= 0)
- exit(die);
- }
- static void
- clear_settings(void)
- {
- // egg_memset(&settings.bots, 0, sizeof(settings_t) - SIZE_PACK - PREFIXLEN);
- egg_memset(&settings.bots, 0, SIZE_CONF);
- }
- void conf_to_bin(conf_t *in, bool move, int die)
- {
- conf_bot *bot = NULL;
- char *newbin = NULL;
- clear_settings();
- sdprintf("converting conf to bin\n");
- simple_sprintf(settings.uid, "%d", in->uid);
- simple_sprintf(settings.watcher, "%d", in->watcher);
- simple_sprintf(settings.autocron, "%d", in->autocron);
- simple_sprintf(settings.autouname, "%d", in->autouname);
- simple_sprintf(settings.portmin, "%d", in->portmin);
- simple_sprintf(settings.portmax, "%d", in->portmax);
- simple_sprintf(settings.pscloak, "%d", in->pscloak);
- strlcpy(settings.binname, in->binname, sizeof(settings.binname));
- if (in->username)
- strlcpy(settings.username, in->username, sizeof(settings.username));
- if (in->uname)
- strlcpy(settings.uname, in->uname, sizeof(settings.uname));
- strlcpy(settings.datadir, in->datadir, sizeof(settings.datadir));
- if (in->homedir)
- strlcpy(settings.homedir, in->homedir, sizeof(settings.homedir));
- strlcpy(settings.binpath, in->binpath, sizeof(settings.binpath));
- for (bot = in->bots; bot && bot->nick; bot = bot->next) {
- simple_snprintf(settings.bots, sizeof(settings.bots), "%s%s%s %s %s%s %s,",
- settings.bots && settings.bots[0] ? settings.bots : "",
- bot->disabled ? "/" : "",
- bot->nick,
- bot->net.ip ? bot->net.ip : ".",
- bot->net.host6 ? "+" : "",
- bot->net.host ? bot->net.host : (bot->net.host6 ? bot->net.host6 : "."),
- bot->net.ip6 ? bot->net.ip6 : "");
- }
- #ifndef CYGWIN_HACKS
- if (move)
- newbin = move_bin(in->binpath, in->binname, 0);
- else
- #endif /* !CYGWIN_HACKS */
- newbin = binname;
- // tellconfig(&settings);
- write_settings(newbin, -1, 1);
- if (die >= 0)
- exit(die);
- }
- void reload_bin_data() {
- if (bin_checksum(binname, GET_CONF)) {
- putlog(LOG_MISC, "*", "Rehashed config data from binary.");
- conf_bot *oldbots = NULL, *oldbot = NULL;
- bool was_localhub = conf.bot->localhub ? 1 : 0;
-
- /* save the old bots list */
- if (conf.bots)
- oldbots = conf_bots_dup(conf.bots);
- /* Save the old conf.bot */
- oldbot = (conf_bot *) my_calloc(1, sizeof(conf_bot));
- conf_bot_dup(oldbot, conf.bot);
- /* free up our current conf struct */
- free_conf();
- /* Fill conf[] with binary data from settings[] */
- bin_to_conf();
- /* fill up conf.bot using origbotname */
- fill_conf_bot(0); /* 0 to avoid exiting if conf.bot cannot be filled */
- if (was_localhub) {
- /* add any new bots not in userfile */
- conf_add_userlist_bots();
- /* deluser removed bots from conf */
- if (oldbots)
- deluser_removed_bots(oldbots, conf.bots);
- #ifdef this_is_handled_by_confedit_now
- /* no longer the localhub (or removed), need to alert the new one to rehash (or start it) */
- if (!conf.bot || !conf.bot->localhub) {
- conf_bot *localhub = conf_getlocalhub(conf.bots);
- /* then SIGHUP new localhub or spawn new localhub */
- if (localhub) {
- /* Check for pid again - may be using fork-interval */
- localhub->pid = checkpid(localhub->nick, localhub, NULL);
- if (localhub->pid)
- conf_killbot(NULL, localhub, SIGHUP); //restart the new localhub
- /* else
- start new localhub - done below in spawnbots() */
- }
- }
- /* start/disable new bots as necesary */
- conf_checkpids(conf.bots);
- spawnbots(1); //1 signifies to not start me!
- #endif
- }
- if (conf.bot && conf.bot->disabled) {
- if (tands > 0) {
- botnet_send_chat(-1, conf.bot->nick, "Bot disabled in binary.");
- botnet_send_bye("Bot disabled in binary.");
- }
- if (server_online)
- nuke_server("bbl");
- werr(ERR_BOTDISABLED);
- } else if (!conf.bot) {
- conf.bot = oldbot;
- if (tands > 0) {
- botnet_send_chat(-1, conf.bot->nick, "Bot removed from binary.");
- botnet_send_bye("Bot removed from binary.");
- }
- if (server_online)
- nuke_server("it's been good, cya");
- werr(ERR_BADBOT);
- }
- /* The bot nick changed! (case) */
- if (strcmp(conf.bot->nick, oldbot->nick)) {
- change_handle(conf.bot->u, conf.bot->nick);
- // var_set_by_name(conf.bot->nick, "nick", conf.bot->nick);
- // var_set_userentry(conf.bot->nick, "nick", conf.bot->nick);
- }
- free_bot(oldbot);
- if (oldbots)
- free_conf_bots(oldbots);
- if (!conf.bot->localhub)
- free_conf_bots(conf.bots);
- }
- }
|