/* $Id$ * User options handling code of libcaptive * Copyright (C) 2003 Jan Kratochvil * * 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; exactly version 2 of June 1991 is required * * 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 */ #include "config.h" #include "captive/options.h" /* self */ #include #include "captive/macros.h" #include #include #include "captive/rtl-file.h" #include #include #include #include #include #include #include #include static void module_check_captivemodid(struct captive_options_module *options_module,const gchar *pathname_utf8) { #ifdef HAVE_LIBXML_XMLREADER_H if (!captive_options->captivemodid) { if (!captive_options->load_untested) g_error(_( "You do not have loaded any .captivemodid.xml database using: --modid-path\n" "Unable to check MS-Windows module file validity. You should load the database first.\n" "You may also force loading of the module although it may not be tested: --load-untested")); g_message(_("Loading possibly INCOMPATIBLE module as no database is present. Forced by: --load-untested: %s"), pathname_utf8); return; } if (captive_captivemodid_module_md5_lookup(captive_options->captivemodid,options_module->u.pe32.md5)) return; if (!captive_options->load_untested) g_error(_( "Attempted to load UNTESTED and possibly INCOMPATIBLE module: %s\n" "You should get more recent identifications database: %s\n" "Otherwise you may also force the loading by the option: --load-untested"), pathname_utf8,captive_captivemodid_get_pathname_loaded(captive_options->captivemodid)); g_message(_( "Loading UNTESTED and possibly INCOMPATIBLE module: %s\n" "Although forced by --load-untested you really should get more recent modid database: %s\n"), pathname_utf8,captive_captivemodid_get_pathname_loaded(captive_options->captivemodid)); #endif /* HAVE_LIBXML_XMLREADER_H */ } gboolean captive_options_module_load(struct captive_options_module *options_module,const gchar *pathname_utf8) { const guint8 magic_mscf[]={'M','S','C','F',0,0,0,0}; g_return_val_if_fail(options_module!=NULL,FALSE); g_return_val_if_fail(pathname_utf8!=NULL,FALSE); /* Open the Module */ options_module->type=CAPTIVE_OPTIONS_MODULE_TYPE_PE32; options_module->pathname_utf8=g_strdup(pathname_utf8); options_module->u.pe32.mapped=TRUE; options_module->u.pe32.base=captive_rtl_file_mmap( &options_module->u.pe32.length, /* lenp */ pathname_utf8, /* path */ O_RDONLY, /* open_flags */ PROT_READ, /* mmap_prot */ MAP_SHARED); /* mmap_flags */ /* FIXME: convert errno instead of STATUS_INSUFFICIENT_RESOURCES */ g_return_val_if_fail(options_module->u.pe32.base!=NULL,FALSE); if (options_module->u.pe32.length>=2 && (('M'<<8U)|('Z'<<0U))==GUINT16_FROM_BE(*(const guint16 *)options_module->u.pe32.base)) { unsigned char md5_bin[1+128/8]; /* 128 bits==16 bytes; '1+' for leading stub to prevent shorter output of BN_bn2hex() */ BIGNUM *bignum; char *hex,*s; /* already done above */ /* Calculate MD5 sum and convert it to hex string: */ MD5(options_module->u.pe32.base,options_module->u.pe32.length,md5_bin+1); md5_bin[0]=0xFF; /* stub to prevent shorter output of BN_bn2hex() */ bignum=BN_bin2bn(md5_bin,1+128/8,NULL); hex=BN_bn2hex(bignum); g_assert(strlen(hex)==2*(1+128/8)); options_module->u.pe32.md5=g_strdup(hex+2); OPENSSL_free(hex); BN_free(bignum); /* BN_bn2hex() returns uppercased string: */ g_assert(strlen(options_module->u.pe32.md5)==32); for (s=options_module->u.pe32.md5;*s;s++) { g_assert(isxdigit(*s)); *s=tolower(*s); g_assert(isxdigit(*s)); } module_check_captivemodid(options_module,pathname_utf8); } else if (options_module->u.pe32.length>=sizeof(magic_mscf) && !memcmp(options_module->u.pe32.base,magic_mscf,sizeof(magic_mscf))) { g_error(_("Compressed cabinet file (\"*.??_\") not loadable - you must use cabextract(1) or EXPAND.EXE first: %s"), pathname_utf8); } else { captive_rtl_file_munmap(options_module->u.pe32.base); options_module->type=CAPTIVE_OPTIONS_MODULE_TYPE_GMODULE; options_module->u.gmodule.pathname=g_strdup(pathname_utf8); } return TRUE; } void captive_options_module_copy(struct captive_options_module *dest,const struct captive_options_module *src) { g_return_if_fail(dest!=NULL); g_return_if_fail(src!=NULL); dest->pathname_utf8=g_strdup(src->pathname_utf8); dest->type=src->type; switch (src->type) { case CAPTIVE_OPTIONS_MODULE_TYPE_EMPTY: g_assert_not_reached(); case CAPTIVE_OPTIONS_MODULE_TYPE_PE32: dest->u.pe32.base=g_memdup(src->u.pe32.base,src->u.pe32.length); dest->u.pe32.length=src->u.pe32.length; dest->u.pe32.mapped=FALSE; dest->u.pe32.md5=g_strdup(src->u.pe32.md5); break; case CAPTIVE_OPTIONS_MODULE_TYPE_GMODULE: dest->u.gmodule.pathname=g_strdup(src->u.gmodule.pathname); break; default: g_assert_not_reached(); } } void captive_options_module_free(struct captive_options_module *options_module) { g_return_if_fail(options_module!=NULL); g_free(options_module->pathname_utf8); switch (options_module->type) { case CAPTIVE_OPTIONS_MODULE_TYPE_EMPTY: break; case CAPTIVE_OPTIONS_MODULE_TYPE_PE32: if (options_module->u.pe32.mapped) captive_rtl_file_munmap(options_module->u.pe32.base); else g_free(options_module->u.pe32.base); g_free(options_module->u.pe32.md5); break; case CAPTIVE_OPTIONS_MODULE_TYPE_GMODULE: g_free(options_module->u.gmodule.pathname); break; default: g_assert_not_reached(); } }