/* * Copyright (C) 2001, 2002, and 2003 Roy Keene * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * email: dact@rkeene.org */ #include "dact.h" #define __DACT_C #include #include #include #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #include "parse.h" #include "dendian.h" #include "crc.h" #include "math.h" #include "dact_common.h" #include "algorithms.h" #include "ciphers.h" #include "module.h" #include "header.h" #include "parse.h" #include "net.h" #include "sfx.h" #include "ui.h" #ifdef HAVE_ZLIB_H #include #endif #ifdef HAVE_BZLIB_H #include #endif char dact_nonetwork=0; uint32_t dact_blksize_calc(int fsize) { uint32_t ret=0; if (fsize==0) return(DACT_BLK_SIZE_DEF); if (fsize<(204800)) { ret=(fsize+5); } if (ret==0) ret=(((int) ((((float) fsize)/102400.0)-(0.9999999)))*65535); if (ret>DACT_BLK_SIZE_MAX) ret=DACT_BLK_SIZE_MAX; return(ret); } int dact_config_execute(const char *cmd, char *options, uint32_t *blksize) { char *line=NULL, *line_s, *item_buf[4]={NULL, NULL, NULL, NULL}; int i; line_s=line=strdup(cmd); if (line[0]=='#') return(0); while (line[strlen(line)-1]<32) line[strlen(line)-1]='\0'; for (i=0;i<4;i++) item_buf[i]=NULL; for (i=0;i<4;i++) { if ((item_buf[i]=strsep(&line, "\t "))==NULL) break; if (item_buf[i][0]==0) i--; } if (item_buf[0]==NULL || item_buf[1]==NULL) return(0); /* This means all commands must have arguments. */ switch (elfcrc(0, item_buf[0], strlen(item_buf[0]))) { case 164209419: /* binary_check */ options[DACT_OPT_BINCHK]=!!strcmp(item_buf[1],"off"); break; case 9456603: /* version_check */ options[DACT_OPT_VERCHK]=!!strcmp(item_buf[1],"off"); break; case 204349618: /* module_dir */ if ((sizeof(moduledirectory)-strlen(moduledirectory)-1)<=0) break; strncat(moduledirectory,":",sizeof(moduledirectory)-strlen(moduledirectory)-1); strncat(moduledirectory,item_buf[1],sizeof(moduledirectory)-strlen(moduledirectory)-1); break; case 247248556: /* module_load_all */ if (strcmp(item_buf[1], "on")==0) { init_modules(); load_modules_all(options); } break; case 48402100: /* module_load */ case 106360197: /* load_module */ init_modules(); load_module(item_buf[1], options); break; case 164097267: /* network_access */ #ifndef NO_NETWORK dact_nonetwork=!strcmp(item_buf[1],"off"); #endif break; case 209445231: /* exclude_algo */ i=(atoi(item_buf[1])&0xff); algorithms[i]=DACT_FAILED_ALGO; break; case 168825941: /* block_size */ if (blksize!=NULL) { *blksize=atoi2(item_buf[1]); } break; case 162975987: /* use_urls */ options[DACT_OPT_URL]=!!strcmp(item_buf[1],"off"); break; case 104235033: /* color_ui */ dact_ui_setopt(DACT_UI_OPT_COLOR,!!strcmp(item_buf[1],"off")); break; case 164800901: /* module_upgrade */ if (strcmp(item_buf[1],"on")==0) options[DACT_OPT_UPGRADE]=1; break; case 63160590: /* pass_use_stdin */ case 191551086: /* use_stdin */ dact_ui_setopt(DACT_UI_OPT_PASSSTDIN, 1); break; #ifdef DEBUG default: fprintf(stderr, "Unknown command %s (%i)\n",item_buf[0],elfcrc(0,item_buf[0],strlen(item_buf[0]))); break; #endif } free(line_s); return(1); } void dact_config_loadfile(const char *path, char *options, uint32_t *blksize) { char *line=NULL; FILE *cfd; line=malloc(512); if ((cfd=fopen(path,"r"))==NULL) return; while (!feof(cfd)) { fgets(line, 511, cfd); dact_config_execute(line, options, blksize); } free(line); fclose(cfd); } uint32_t dact_blk_decompress(char *ret, const char *srcbuf, const uint32_t size, const char *options, const int algo, uint32_t bufsize) { uint32_t retval; if (algo==0xff) return(0); if (algorithms[algo]==NULL) { PRINTERR("Algorithm unavailble."); return(0); } retval=algorithms[algo](DACT_MODE_DECMP, NULL, srcbuf, ret, size, bufsize); return(retval); } uint32_t dact_blk_compress(char *algo, char *ret, const char *srcbuf, const uint32_t size, const char *options, uint32_t bufsize) { char *tmpbuf, *smallbuf=NULL; int i, highest_algo=0; char smallest_algo; uint32_t smallest_size=-1, x; #ifndef DACT_UNSAFE char *verif_bf=NULL; uint32_t m; if ((verif_bf=malloc(size))==NULL) { PERROR("malloc"); return(0); } #endif if ((tmpbuf=malloc(bufsize))==NULL) { PERROR("malloc"); return(0); } for (i=0;i<256;i++) { if (algorithms[i]!=NULL && algorithms[i]!=DACT_FAILED_ALGO) highest_algo=i; } for (i=0;i<=highest_algo;i++) { if (algorithms[i]!=NULL && algorithms[i]!=DACT_FAILED_ALGO) { x=algorithms[i](DACT_MODE_COMPR, NULL, srcbuf, tmpbuf, size, bufsize); #ifndef DACT_UNSAFE if ((x2) { PRINT_LINE; fprintf(stderr, "dact: \033[%im----| %03i | %-7i | %s\033[0m\n", (smallest_algo==i)*7 , i, x, algorithm_names[i]); } } } free(tmpbuf); #ifndef DACT_UNSAFE free(verif_bf); #endif if (smallest_size==-1) { return(0); } memcpy(algo, &smallest_algo, sizeof(char)); memcpy(ret, smallbuf, smallest_size); /* This was MISSING ! memory leak. */ free(smallbuf); return(smallest_size); } uint64_t dact_process_file(const int src, const int dest, const int mode, const char *options, const char *filename, uint32_t *crcs, uint32_t dact_blksize, int cipher) { struct stat filestats; FILE *extd_urlfile; char *file_extd_urls[256]; unsigned char algo; char ch; char *in_buf, *out_buf, *hdr_buf, *keybuf=NULL, *tmpbuf=NULL; char version[3]={DACT_VER_MAJOR, DACT_VER_MINOR, DACT_VER_REVISION}; char file_opts=0; uint32_t bytes_read, retsize; uint64_t filesize=0, fileoutsize=0, out_bufsize=0; uint32_t blk_cnt=0, file_extd_size=0, blksize=0, blksize_uncomp=0; uint32_t magic=0, file_extd_read=0, file_extd_urlcnt=0; int hdr_reg_size=28; int blksize_size; int x=0, new_fd, canlseek=0; ssize_t offset=0; if (fstat(src, &filestats)<0) { PERROR("fstat"); return(0); } if (mode==DACT_MODE_COMPR) { blksize=dact_blksize; if (blksize==0) { blksize=dact_blksize_calc(filestats.st_size); } if (options[DACT_OPT_SFX]) { offset=sfx_init_compress(dest); if (offset<0) { PRINTERR("Couldn't initialize self-extracting header."); return(0); } dact_hdr_ext_regn(DACT_HDR_SFXLEN, offset, sizeof(offset)); } out_bufsize=blksize*2; if (((in_buf=malloc(blksize))==NULL) || \ ((out_buf=malloc(out_bufsize))==NULL)) { PERROR("malloc"); return(0); } dact_ui_setup(((float) (filestats.st_size/blksize)+0.9999)); if (cipher!=-1) { dact_hdr_ext_regn(DACT_HDR_CIPHER, cipher, sizeof(cipher)); keybuf=malloc(DACT_KEY_SIZE); ciphers[cipher](NULL, NULL, 0, keybuf, DACT_MODE_CINIT+DACT_MODE_CENC); } blksize_size=BYTESIZE(blksize); if (!options[DACT_OPT_ORIG] && filename!=NULL) dact_hdr_ext_regs(DACT_HDR_NAME, filename, strlen(filename)); file_extd_size=(dact_hdr_ext_size()+14); /* The +14 is for crc0 and crc1 */ write_de(dest, DACT_MAGIC_NUMBER, 4); write(dest, &version[0], 1); write(dest, &version[1], 1); write(dest, &version[2], 1); write_de(dest, 0, 8); /* Place holder for ORIG FILE SIZE */ write_de(dest, 0, 4); /* Place holder for NUM BLOCKS */ write_de(dest, blksize, 4); write_de(dest, file_opts, 1); /* XXX: Option byte... Or not? */ write_de(dest, file_extd_size, 4); /* Place holder for SIZEOF EXTENDED DTA */ /* Fill the header with NOPs incase we can't come back and put the CRCs */ ch=DACT_HDR_NOP; for (x=0;x1) { PRINTERR("Blk | Algo | Size | Name"); PRINTERR("----+------+---------+---------------------------"); } memset(in_buf, 0, blksize); while ( (bytes_read=read_f(src, in_buf, blksize))>0) { filesize+=bytes_read; blk_cnt++; retsize=dact_blk_compress(&algo, out_buf, in_buf, blksize, options, out_bufsize); /* CIPHER the data if an encryption algorithm is specified. */ if (cipher!=-1) { tmpbuf=malloc(retsize*2); x=ciphers[cipher](out_buf, tmpbuf, retsize, keybuf, DACT_MODE_CENC); memcpy(out_buf,tmpbuf,x); free(tmpbuf); } if (retsize>0) { if (options[DACT_OPT_VERB]>1) { if (options[DACT_OPT_VERB]>2) { PRINTERR("^^^\\ /^^^^\\ /^^^^^^^\\ /^^^^^^^^^^^^^^^^^^^^^^^^^^"); } PRINT_LINE; fprintf(stderr, "dact: %03i | %03i | %-7i | %s\n",blk_cnt,algo,retsize,algorithm_names[algo]); if (options[DACT_OPT_VERB]>2) { PRINTERR("___/ \\____/ \\_______/ \\__________________________"); } } dact_ui_incrblkcnt(1); dact_ui_status(DACT_UI_LVL_GEN, "Algorithm "); dact_ui_status_append(DACT_UI_LVL_GEN,algorithm_names[algo]); crcs[0]=crc(crcs[0], out_buf, retsize); /* Do not generate a CRC of the plaintext if encrypting */ if (cipher==-1) { crcs[1]=crc(crcs[1], in_buf, blksize); } if (!options[DACT_OPT_HDONLY]) { write(dest, &algo, 1); write_de(dest, retsize, blksize_size); if (write(dest, out_buf, retsize)!=retsize) { PERROR("write"); free(in_buf); free(out_buf); return(0); } } } else { PRINTERR("Compression resulted in 0-byte block."); free(in_buf); free(out_buf); return(0); } memset(in_buf, 0, blksize); } if (bytes_read<0) { PERROR("read"); } free(in_buf); free(out_buf); /* Put the filesize and file block count in the header, if possible. */ if (lseek_net(dest, offset+7, SEEK_SET)<0) { /* If we can't rewind the stream, put magic+fileisze */ write_de(dest, DACT_MAGIC_PEOF, 4); write_de(dest, filesize, 8); } else { write_de(dest, filesize, 8); write_de(dest, blk_cnt, 4); } if (lseek_net(dest, offset+hdr_reg_size, SEEK_SET)>0) { if (!options[DACT_OPT_NOCRC]) { dact_hdr_ext_regn(DACT_HDR_CRC0, crcs[0], 4); dact_hdr_ext_regn(DACT_HDR_CRC1, crcs[1], 4); } write(dest, dact_hdr_ext_data(), dact_hdr_ext_size()); } dact_hdr_ext_clear(); return(filesize); } if (mode==DACT_MODE_DECMP) { dact_ui_status(DACT_UI_LVL_GEN, "Decompressing."); dact_hdr_ext_clear(); read_de(src, &magic, 4, sizeof(magic)); if (magic!=DACT_MAGIC_NUMBER) { dact_ui_status(DACT_UI_LVL_GEN, "Bad DACT magic, checking others..."); return(dact_process_other(src,dest,magic,options)); } read(src, &version[0], 1); read(src, &version[1], 1); read(src, &version[2], 1); #ifndef DACT_DONT_SUPPORT_OLDDACT if (DACT_VERS(version[0], version[1], version[2])filesize && filesize!=0) { write(dest, out_buf, blksize_uncomp-(fileoutsize-filesize)); } else { write(dest, out_buf, bytes_read); } free(in_buf); } free(out_buf); if ((crcs[0]!=crcs[2] && crcs[0]!=0 && crcs[2]!=0) \ || (crcs[1]!=crcs[3] && crcs[1]!=0 && crcs[3]!=0)) { dact_ui_status(DACT_UI_LVL_GEN, "CRC error."); if (!options[DACT_OPT_NOCRC] || options[DACT_OPT_FORCE]<1) return(0); } dact_hdr_ext_clear(); return(filesize); } if (mode==DACT_MODE_STAT) { read_de(src, &magic, 4, sizeof(magic)); read(src, &version[0], 1); read(src, &version[1], 1); read(src, &version[2], 1); #ifndef DACT_DONT_SUPPORT_OLDDACT if (DACT_VERS(version[0], version[1], version[2]) */ if (lseek_net(src, 0, SEEK_SET)<0) { /* * lseek_net() should make this obsolete. * ... EXCEPT! when reading from stdin. */ tmpfd=mkstemp(tmpbuf); write_de(tmpfd, magic, 4); buf=malloc(1024); while (1) { x=read_f(src, buf, 1024); write(tmpfd, buf, x); if (x<1024) break; } close(src); src=tmpfd; lseek_net(src, 0, SEEK_SET); /* Now bitch. */ free(buf); } #if defined(HAVE_LIBZ) && defined(HAVE_GZDOPEN) if ((magic&0xffff0000)==0x1f8b0000) { /* gzip */ dact_ui_status(DACT_UI_LVL_GEN, "Gunzipping..."); buf=malloc(1024); gzfd=gzdopen(src, "r"); /*XXX: need to dact_ui_setup() */ while (1) { dact_ui_incrblkcnt(1); x=gzread(gzfd,buf,1024); filesize+=write(dest, buf, x); if (x<1024) break; } free(buf); if (tmpfd!=0) unlink(tmpbuf); return(filesize); } #endif #if defined(HAVE_LIBBZ2) && (defined(HAVE_BZDOPEN) || defined(HAVE_NEW_BZDOPEN)) if ((magic&0xffffff00)==0x425a6800) { /* bzip2 */ dact_ui_status(DACT_UI_LVL_GEN, "Bunzipping..."); buf=malloc(1024); #ifdef HAVE_NEW_BZDOPEN bzfd=BZ2_bzdopen(src, "r"); #else bzfd=bzdopen(src, "r"); #endif /*XXX: need to dact_ui_setup() */ while(1) { dact_ui_incrblkcnt(1); #ifdef HAVE_NEW_BZDOPEN x=BZ2_bzread(bzfd, buf, 1024); #else x=bzread(bzfd, buf, 1024); #endif filesize+=write(dest, buf, x); if (x<1024) break; } free(buf); if (tmpfd!=0) unlink(tmpbuf); return(filesize); } #endif return(0); }