/* $Id: plugin.c,v 1.2 2011/03/31 02:55:04 khorben Exp $ */ /* Copyright (c) 2011 khorben of Uberwall */ /* 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 version 2 of the License. * * 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 #include #include #include #include #include #include "plugins/plugin.h" #include "UWfirmforce.h" /* macros */ #define max(a, b) ((a) > (b) ? (a) : (b)) /* Plugin */ /* types */ typedef enum _PluginFlag { PF_VERBOSE = 0x01, PF_EXTRACT = 0x02 } PluginFlag; struct _PluginHelperData { PluginFlag flags; char const * filename; int pass; }; struct _PluginHandle { Plugin * plugin; void * handle; }; PluginHandle * plugin_new(char const * filename) { PluginHandle * plugin; if((plugin = malloc(sizeof(*plugin))) == NULL) { UWfirmforce_error(filename, 0); return NULL; } if((plugin->handle = dlopen(filename, RTLD_LAZY)) == NULL) { UWfirmforce_dlerror(filename, 0); plugin_delete(plugin); return NULL; } if((plugin->plugin = dlsym(plugin->handle, "plugin")) == NULL || plugin->plugin->name == NULL) { UWfirmforce_dlerror(filename, 0); plugin_delete(plugin); return NULL; } return plugin; } /* plugin_delete */ void plugin_delete(PluginHandle * plugin) { if(plugin->handle != NULL && dlclose(plugin->handle) != 0) UWfirmforce_dlerror("plugin_delete", 0); free(plugin); } /* accessors */ /* plugin_get_name */ char const * plugin_get_name(PluginHandle * plugin) { return plugin->plugin->name; } /* plugin_get_buffer_size */ size_t plugin_get_buffer_size(PluginHandle * plugin) { unsigned int i; size_t len = 0; if(plugin->plugin->magic == NULL) return 0; for(i = 0; plugin->plugin->magic[i].magic != NULL; i++) { len = max(len, plugin->plugin->magic[i].overhead); len = max(len, plugin->plugin->magic[i].offset + plugin->plugin->magic[i].magic_len); } return len; } /* useful */ /* plugin_do */ static int _do_printf(PluginHelper * ph, char const * format, ...); static FILE * _do_fopen(struct _PluginHelper * ph, const char * pathname); static size_t _do_fwrite(const void * ptr, size_t size, size_t nmemb, FILE * fp); static int _do_fclose(FILE * fp); int plugin_do(PluginHandle * plugin, int signature, int verbose, int extract, char const * filename, FILE * fp) { static PluginHelperData data = { 0, NULL, -1 }; static PluginHelper ph = { &data, _do_printf, _do_fopen, _do_fwrite, _do_fclose }; if(plugin->plugin->callback == NULL) return 0; if(data.filename != filename) data.pass = -1; data.flags = verbose ? PF_VERBOSE : 0; data.flags |= extract ? PF_EXTRACT : 0; data.filename = filename; return plugin->plugin->callback(&ph, signature, fp); } static int _do_printf(PluginHelper * ph, char const * format, ...) { int ret; va_list arg; if(!(ph->data->flags & PF_VERBOSE)) return 0; va_start(arg, format); ret = vprintf(format, arg); va_end(arg); /* fflush(stdout); FIXME find a more optimal solution */ return ret; } static char * _fopen_directory(PluginHelperData * data); static void _fopen_sanitize(char * filename); static FILE * _do_fopen(struct _PluginHelper * ph, const char * pathname) { char * str; size_t len; char * p; char * q; FILE * fp; if(!(ph->data->flags & PF_EXTRACT)) return NULL; /* check for available directories */ if((str = _fopen_directory(ph->data)) == NULL) return NULL; len = strlen(str); /* sanitize pathname */ if((p = strdup(pathname)) == NULL) { UWfirmforce_error(pathname, 0); free(str); return NULL; } _fopen_sanitize(p); if((q = realloc(str, len + strlen(p) + 2)) == NULL) { UWfirmforce_error(ph->data->filename, 0); free(p); free(str); return NULL; } str = q; sprintf(&str[len], "/%s", p); if((fp = fopen(str, "w")) == NULL) /* FIXME may overwrite stuff */ UWfirmforce_error(str, 0); free(p); free(str); return fp; } static char * _fopen_directory(PluginHelperData * data) { size_t len = strlen(data->filename); char * str; int i; struct stat st; if((str = malloc(len + 5)) == NULL) { UWfirmforce_error(data->filename, 0); return NULL; } strncpy(str, data->filename, len); if(data->pass >= 0 && data->pass < 1000) { snprintf(&str[len], 5, ".%03d", data->pass); return str; } for(i = 0; i < 1000; i++) /* more will overflow the buffer */ { snprintf(&str[len], 5, ".%03d", i); if(stat(str, &st) == 0 || errno != ENOENT) continue; if(mkdir(str, 0777) != 0) /* create the output directory */ { UWfirmforce_error(str, 0); break; } /* FIXME then create "%03d-%s", cnt, pluginname) */ data->pass = i; return str; } free(str); return NULL; } static void _fopen_sanitize(char * filename) /* FIXME audit this */ { size_t i; size_t parent = 0; size_t len = strlen(filename); #ifdef DEBUG fprintf(stderr, "DEBUG: sanitized \"%s\"", filename); #endif for(i = 0; filename[i] != '\0'; i++) { if(filename[i] != '\0' && filename[i] != '/') continue; if(strncmp(&filename[i + 1], "..", 2) != 0) continue; if(filename[i + 3] != '\0' && filename[i + 3] != '/') continue; memmove(&filename[parent], &filename[i + 3], len - i); parent = i; len -= (len - i); } #ifdef DEBUG fprintf(stderr, " to \"%s\"\n", filename); #endif } static size_t _do_fwrite(const void * ptr, size_t size, size_t nmemb, FILE * fp) { if(fp == NULL || nmemb == 0) return nmemb; /* FIXME implement */ return fwrite(ptr, size, nmemb, fp); } static int _do_fclose(FILE * fp) { if(fp == NULL) return 0; return fclose(fp); } /* plugin_info */ void plugin_info(PluginHandle * plugin) { struct { PluginType type; char const * description; } td[] = { { PT_COMPRESSION, "compressed" }, { PT_EXECUTABLE, "executable" }, { PT_ARCHIVE, "archive" }, { PT_FORENSIC, "forensic" }, { 0, NULL } }; unsigned int i; printf("%s:", plugin->plugin->name); for(i = 0; td[i].description != NULL; i++) if((td[i].type & plugin->plugin->type) == td[i].type) printf(" %s", td[i].description); fputc('\n', stdout); } /* plugin_match * RETURNS: >= 0 matched signature id returned * else nothing was found or an error occured */ int plugin_match(PluginHandle * plugin, char const * buf, size_t buf_cnt) { unsigned int i; PluginMagic * magic; for(i = 0; (magic = &plugin->plugin->magic[i]) != NULL && magic->magic != NULL; i++) { if(buf_cnt < magic->offset + magic->magic_len || memcmp(&buf[magic->offset], magic->magic, magic->magic_len) != 0) continue; return i; } return -1; }