/* Pulls server library out of plugin folder */ int scrapePlugin (const char *filename, void * data) { lt_dlhandle pluginHandle = lt_dlopenext (filename); if (!pluginHandle) { doLog (ERROR, LOG_COMP, _("Unable to link %s\nDetails: %s."), filename, lt_dlerror()); return 0; } /* Get Info for loaded Plugin */ lt_dlinfo const * pluginInfo = lt_dlgetinfo (pluginHandle); if (!pluginInfo) { doLog (ERROR, LOG_COMP, _("Unable to get plugin SO info for %s\nDetails: %s."), filename, lt_dlerror()); return 0; } /* Continue Loading Plugin */ doLog (NOTICE, LOG_COMP, _("Found %s."), pluginInfo->name); checkAddPlugin (pluginInfo->filename, pluginInfo->name, pluginHandle); return 0; }
module_handle module_open(const char* name, enum module_type_t type, int flags){ log_message(Log_Debug, "Loading plugin '%s'\n", name); /* dlopenext tries all searchpaths and adds appropriate suffix */ lt_dlhandle handle = lt_dlopenext(name); if ( !handle ){ log_message(Log_Debug, "Failed to load plugin '%s': %s\n", name, lt_dlerror()); errnum = MODULE_NOT_FOUND; return NULL; } /* test if the module is valid by quering a symbol which must exists in * every module. */ void* sym = lt_dlsym(handle, "__module_type"); if ( !sym ){ log_message(Log_Debug, "Plugin '%s' found but is invalid\n", name); errnum = MODULE_INVALID; return NULL; } if ( type != ANY_MODULE && *((enum module_type_t*)sym) != type ){ log_message(Log_Debug, "Plugin '%s' found but is invalid\n", name); errnum = MODULE_INVALID; return NULL; } /* base functions */ void* module_init = lt_dlsym(handle, "module_init"); void* module_cleanup = lt_dlsym(handle, "module_cleanup"); void* module_alloc = lt_dlsym(handle, "module_alloc"); void* module_free = lt_dlsym(handle, "module_free"); /* create base structure (later copied into the real struct */ struct module_t base; base.handle = handle; base.info = lt_dlgetinfo(handle); base.init = (module_init_callback)module_init; base.cleanup = (module_cleanup_callback)module_cleanup; base.alloc = module_alloc ? (module_alloc_callback)module_alloc : default_alloc; base.free = module_free ? (module_free_callback)module_free : default_free; /* allocate real structure and copy base fields */ module_handle module = base.alloc(); *module = base; /* run module initialization if available */ if ( callee_init(flags) && module->init && module->init(module) != 0 ){ log_message(Log_Fatal, "Plugin `%s' initialization failed.\n", name); return NULL; } return module; }
/** * initializeScanRules * * this reads in the rules definition file for identifying the playload. * It compiles the regular * expressions and loads in the dynamic libraries as defined for later use * * @param scriptFile a file pointer to the rule definition file * */ gboolean ycInitializeScanRules ( FILE * scriptFile, GError ** err) { /* // for every rule that is "imagined" can be returned on a single call to pcre_exec, you need to multiply that number by 6 for the correct number of "vector" entries (and because of pcre limitation should be a multiple of 3) */ #define NUM_SUBSTRING_VECTS 60 const char *errorString; int errorPos; char eString[ESTRING_SIZE]; pcre *ruleScanner; pcre *pluginScanner; pcre *commentScanner; pcre *pluginArgScanner; pcre *signatureScanner; const char commentScannerExp[] = "^\\s*#[^\\n]*\\n"; const char pluginScannerExp[] = "^[[:space:]]*label[[:space:]]+([[:digit:]]+)" "[[:space:]]+plugin[[:space:]]*([^[:space:]\\n].*)\\n"; const char ruleScannerExp[] = "^[[:space:]]*label[[:space:]]+([[:digit:]]+)" "[[:space:]]+regex[[:space:]]*([^\\n].*)\\n"; const char signatureScannerExp[] = "^[[:space:]]*label[[:space:]]+([[:digit:]]+)" "[[:space:]]+signature[[:space:]]*([^\\n].*)\\n"; const char pluginArgScannerExp[] = "[[:word:]]"; int rc; int substringVects[NUM_SUBSTRING_VECTS]; char lineBuffer[LINE_BUF_SIZE]; int readLength; char *captString; unsigned int bufferOffset = 0; int currentStartPos = 0; int loop; char *ltdl_lib_path = NULL; /* first mark all plugin entries as empty, just in case */ for (loop = 0; loop < MAX_PAYLOAD_RULES; loop++) { ruleTable[loop].ruleType = EMPTY; } /* initialize the hash table */ ycPortHashInitialize(); /* initialize the dynamic loader library */ rc = lt_dlinit(); if (0 != rc) { *err = g_error_new (YAF_ERROR_DOMAIN, YAF_ERROR_IMPL, "error initializing the dynamic loader library: \"%s\"", lt_dlerror ()); return FALSE; } /* if LTDL_LIBRARY_PATH is set - add this one first */ ltdl_lib_path = getenv("LTDL_LIBRARY_PATH"); if (ltdl_lib_path) { lt_dladdsearchdir(ltdl_lib_path); } #ifdef YAF_APPLABEL_PATH /* add the applabel path based on libdir at build time */ lt_dladdsearchdir(YAF_APPLABEL_PATH); #else /* add /usr/local/lib/yaf to path since libtool can never find it */ lt_dladdsearchdir(YAF_SEARCH_PATH); lt_dladdsearchdir(ALT_SEARCH_PATH); lt_dladdsearchdir(ALT_SEARCH_PATH64); #endif /* create the hash table for library modules to library handle names */ if (!hcreate ((MAX_PAYLOAD_RULES * 20) / 100)) { *err = g_error_new (YAF_ERROR_DOMAIN, YAF_ERROR_IMPL, "couldn't create load module hash table (%d)", errno); return FALSE; } /* * take all of the rules needed to parse the rule file and compile * them into a form that // the regular expression engine can deal with */ ruleScanner = pcre_compile(ruleScannerExp, PCRE_MULTILINE, &errorString, &errorPos, NULL); if (NULL == ruleScanner) { ycDisplayScannerRuleError(eString, ESTRING_SIZE, "couldn't build the rule scanner", errorString, ruleScannerExp, errorPos); *err = g_error_new(YAF_ERROR_DOMAIN,YAF_ERROR_INTERNAL, "%s", eString); return FALSE; } pluginScanner = pcre_compile(pluginScannerExp, PCRE_MULTILINE, &errorString, &errorPos, NULL); if (NULL == pluginScanner) { ycDisplayScannerRuleError(eString, ESTRING_SIZE, "couldn't build the plugin scanner", errorString, pluginScannerExp, errorPos); *err = g_error_new(YAF_ERROR_DOMAIN,YAF_ERROR_INTERNAL, "%s", eString); return FALSE; } commentScanner = pcre_compile(commentScannerExp, PCRE_MULTILINE, &errorString, &errorPos, NULL); if (NULL == commentScanner) { ycDisplayScannerRuleError (eString, ESTRING_SIZE, "couldn't build the comment scanner", errorString, commentScannerExp, errorPos); *err = g_error_new(YAF_ERROR_DOMAIN,YAF_ERROR_INTERNAL, "%s", eString); return FALSE; } pluginArgScanner = pcre_compile(pluginArgScannerExp, PCRE_MULTILINE, &errorString, &errorPos, NULL); if (NULL == pluginArgScanner) { ycDisplayScannerRuleError(eString, ESTRING_SIZE, "couldn't build the plugin argument scanner", errorString, pluginArgScannerExp, errorPos); *err = g_error_new(YAF_ERROR_DOMAIN,YAF_ERROR_INTERNAL, "%s", eString); return FALSE; } signatureScanner = pcre_compile(signatureScannerExp, PCRE_MULTILINE, &errorString, &errorPos, NULL); if (NULL == signatureScanner) { ycDisplayScannerRuleError (eString, ESTRING_SIZE, "couldn't build the signature scanner", errorString, signatureScannerExp, errorPos); *err = g_error_new(YAF_ERROR_DOMAIN,YAF_ERROR_INTERNAL, "%s", eString); return FALSE; } /* * this is the loop that does the lion's share of the rule file * processing first read a hunk of the rule file, (this may include * multiple lines of stuff) this gets a little bit ugly, there are a * number of issues that have to handled; first, because there may be * multiple lines (which is in fact likely) it has to be able to work * its way through the buffer, a single pass of the buffer through the * pcre engine simply won't cut it; at the end, it is possible // to have * part of line, when this happens, it needs to copy the leftover part * of the read into the front of the buffer, and then read again to fill in * the rest of line. (this detail limits a single line to * LINE_BUF_SIZE size) */ do { readLength = fread (lineBuffer + bufferOffset, 1, LINE_BUF_SIZE - 1 -bufferOffset, scriptFile); if (0 == readLength) { if (ferror (scriptFile)) { *err = g_error_new(YAF_ERROR_DOMAIN, YAF_ERROR_IO, "couldn't read the rule file: %s", strerror (errno)); return FALSE; } break; } /* fread only returns how much it read from the file - need to add extra we put in the buffer from last read, if any */ readLength += bufferOffset; /* * substringVects is used by the pcre library to indicate where the * matched substrings are in the input string, but [1] points to * the very end of the total match, we use this to iterate through * the readBuffer, always reset it after a read */ substringVects[0] = 0; substringVects[1] = 0; /* parse as much of the input buffer as possible */ while (substringVects[1] < readLength) { #if YFDEBUG_APPLABEL g_debug("readLength %d startPosition %d\n", readLength, substringVects[1]); for (loop=0; loop < 10; loop++) { if (loop+substringVects[1] > readLength) { break; } char curChar = *(lineBuffer + substringVects[1] + loop); if (iscntrl(curChar)) { g_debug("."); continue; } if (isprint(curChar)) { g_debug("%c", curChar); } else { g_debug("."); } } g_debug("\n"); #endif /* get rid of CR's and LF's at the begging, use the simple manual * method, they gum up the regex works */ if ('\n' == *(lineBuffer + substringVects[1]) || '\r' == *(lineBuffer + substringVects[1])) { substringVects[1]++; continue; } /* first check for comments, and eliminate them */ currentStartPos = substringVects[1]; /* need to store the current offset, if we fail to match, we get -1 in [1] */ rc = pcre_exec (commentScanner, NULL, lineBuffer, readLength, substringVects[1], PCRE_ANCHORED, substringVects, NUM_SUBSTRING_VECTS); if (rc > 0) { #if YFDEBUG_APPLABEL g_debug("comment match pos %d to pos %d\n", substringVects[0], substringVects[1]); pcre_get_substring(lineBuffer, substringVects, rc, 0, (const char**)&captString); g_debug("comment line is \"%s\"\n", captString); pcre_free(captString); #endif continue; } substringVects[1] = currentStartPos; /* scan the line to see if it is a regex statement, and get the * arguments if it is */ rc = pcre_exec (ruleScanner, NULL, lineBuffer, readLength, substringVects[1], PCRE_ANCHORED, substringVects, NUM_SUBSTRING_VECTS); if (rc > 0) { pcre *newRule; pcre_extra *newExtra; /* get the first matched field from the regex rule expression * (the label value) */ pcre_get_substring (lineBuffer, substringVects, rc, 1, (const char **) &captString); ruleTable[numPayloadRules].payloadLabelValue = strtoul (captString, NULL, 10); #if YFDEBUG_APPLABEL g_debug("regex: rule # %u, label value %lu ", numPayloadRules, strtoul(captString, NULL, 10)); #endif pcre_free (captString); /* get the second matched field from the regex rule expression * (should be the regex) */ pcre_get_substring(lineBuffer, substringVects, rc, 2, (const char **) &captString); #if YF_DEBUG_APPLABEL g_debug(" regex \"%s\"\n", captString); #endif newRule = pcre_compile(captString, 0, &errorString, &errorPos, NULL); if (NULL == newRule) { ycDisplayScannerRuleError(eString, ESTRING_SIZE, "error in regex application labeler rule", errorString, captString, errorPos); } else { newExtra = pcre_study (newRule, 0, &errorString); ruleTable[numPayloadRules].ruleArgs.regexFields. scannerExpression = newRule; ruleTable[numPayloadRules].ruleArgs.regexFields. scannerExtra = newExtra; ruleTable[numPayloadRules].ruleType = REGEX; ycPortHashInsert(ruleTable[numPayloadRules].payloadLabelValue, numPayloadRules); numPayloadRules++; } pcre_free (captString); if (MAX_PAYLOAD_RULES == numPayloadRules) { *err = g_error_new (YAF_ERROR_DOMAIN, YAF_ERROR_LIMIT, "maximum number of application labeler" " rules has been reached"); return FALSE; } continue; } substringVects[1] = currentStartPos; /* scan the line to see if it is a plugin statement, and handle the * arguments if it is */ rc = pcre_exec (pluginScanner, NULL, lineBuffer, readLength, substringVects[1], PCRE_ANCHORED, substringVects, NUM_SUBSTRING_VECTS); if (rc > 0) { int numArgs; char **argStrings; /* get the first matched field from the regex rule expression * (the lable value) */ pcre_get_substring (lineBuffer, substringVects, rc, 1, (const char **) &captString); ruleTable[numPayloadRules].payloadLabelValue = strtoul (captString, NULL, 10); #if YFDEBUG_APPLABEL g_debug("plugin: rule # %u, label value %lu ", numPayloadRules, strtoul(captString, NULL, 10)); #endif pcre_free (captString); /* * get the second matched field, which should be the plugin * name and all of its arguments, now we need to chunk that * into an array of strings, ala argc, argv */ pcre_get_substring(lineBuffer, substringVects, rc, 2, (const char **) &captString); ycChunkString(captString, &numArgs, &argStrings); if (numArgs < 2) { g_critical("error: not enough arguments to load and call " "a plugin, at least a library name and function" " name are needed\n"); pcre_free(captString); pcre_get_substring(lineBuffer, substringVects, rc, 0, (const char **) &captString); g_critical("input line: \"%s\"\n", captString); } else { ENTRY newItem; ENTRY *foundItem; lt_dlhandle modHandle; lt_ptr funcPtr; ruleTable[numPayloadRules].ruleType = PLUGIN; ruleTable[numPayloadRules].ruleArgs.pluginArgs.numArgs = numArgs; ruleTable[numPayloadRules].ruleArgs.pluginArgs.pluginArgs = argStrings; newItem.key = strdup(argStrings[0]); if (NULL == newItem.key) { g_error("out of memory error\n"); for (loop = 0; loop < numArgs; loop++) { free ((char *) (argStrings[loop])); } free(argStrings); return FALSE; } newItem.data = NULL; foundItem = hsearch(newItem, FIND); if (NULL == foundItem) { modHandle = lt_dlopenext(newItem.key); if (NULL == modHandle) { g_critical("Couldn't open library \"%s\": %s", argStrings[0], lt_dlerror()); g_critical("Search path set to %s", lt_dlgetsearchpath()); g_critical("Set LTDL_LIBRARY_PATH to correct" " location."); for (loop = 0; loop < numArgs; loop++) { free((char *) (argStrings[loop])); } free(argStrings); pcre_free(captString); continue; } else { #if YFDEBUG_APPLABEL const lt_dlinfo *info = lt_dlgetinfo(modHandle); g_debug("Loading %s plugin from %s", info->name, info->filename); #endif } newItem.data = (void *)modHandle; hsearch(newItem, ENTER); } else { modHandle = (lt_dlhandle)foundItem->data; } funcPtr = lt_dlsym(modHandle, argStrings[1]); if (NULL == funcPtr) { g_critical("couldn't find function \"%s\" in library" " \"%s\"\n", argStrings[1], argStrings[0]); for (loop = 0; loop < numArgs; loop++) { free ((char *) (argStrings[loop])); } free (argStrings); pcre_free (captString); continue; } ruleTable[numPayloadRules].ruleArgs.pluginArgs.func = (ycScannerPlugin_fn) funcPtr; ycPortHashInsert(ruleTable[numPayloadRules].payloadLabelValue, numPayloadRules); numPayloadRules++; } pcre_free(captString); if (MAX_PAYLOAD_RULES == numPayloadRules) { g_warning ("maximum number of rules has been reached\n"); return TRUE; } continue; } substringVects[1] = currentStartPos; /* scan the line to see if it is a signature, and get the * arguments if it is */ rc = pcre_exec(signatureScanner, NULL, lineBuffer, readLength, substringVects[1], PCRE_ANCHORED, substringVects, NUM_SUBSTRING_VECTS); if (rc > 0) { pcre *newRule; pcre_extra *newExtra; /* get the first matched field from the regex rule expression * (the label value) */ pcre_get_substring(lineBuffer, substringVects, rc, 1, (const char **) &captString); sigTable[numSigRules].payloadLabelValue = strtoul(captString, NULL, 10); #if YFDEBUG_APPLABEL g_debug("signature: rule # %u, label value %lu ", numSigRules, strtoul(captString, NULL, 10)); #endif pcre_free (captString); /* get the second matched field from the regex rule expression * (should be the regex) */ pcre_get_substring(lineBuffer, substringVects, rc, 2, (const char **) &captString); #if YFDEBUG_APPLABEL g_debug(" signature \"%s\"\n", captString); #endif newRule = pcre_compile(captString, 0, &errorString, &errorPos, NULL); if (NULL == newRule) { ycDisplayScannerRuleError (eString, ESTRING_SIZE, "error in signature application " "labeler rule", errorString, captString, errorPos); } else { newExtra = pcre_study (newRule, 0, &errorString); sigTable[numSigRules].ruleArgs.regexFields. scannerExpression = newRule; sigTable[numSigRules].ruleArgs.regexFields. scannerExtra = newExtra; sigTable[numSigRules].ruleType = SIGNATURE; numSigRules++; } pcre_free(captString); if (MAX_PAYLOAD_RULES == numSigRules) { *err = g_error_new(YAF_ERROR_DOMAIN, YAF_ERROR_LIMIT, "maximum number of signature rules has " "been reached"); return FALSE; } continue; } substringVects[1] = currentStartPos; /* pcre_free (captString);*/ #if YFDEBUG_APPLABEL g_debug("plugin args: "); for (loop = 0; loop < numArgs; loop++) { g_debug("\"%s\" ", (*argStrings)[loop]); } g_debug("\n"); #endif /* * check to see if we have partial text left over at the end of * the read buffer, if we copy it to the front of the read * buffer, and on the next read, read a little less to * compensate for the left over amount */ if ((PCRE_ERROR_NOMATCH == rc) && (substringVects[1] < readLength) && !feof (scriptFile)) { memmove (lineBuffer, lineBuffer + substringVects[1], readLength - substringVects[1]); bufferOffset = readLength - substringVects[1]; break; } else if (PCRE_ERROR_NOMATCH == rc && feof (scriptFile)) { /* this is an error, we have crap left over at the end of the * file that we can't parse! */ g_critical("unparsed text at the end of the application labeler" " rule file!\n"); break; } } } while (!ferror (scriptFile) && !feof (scriptFile)); /* * get rid of the module handle lookup hash; this creates a mem leak of * the module handles, they can't be freed any longer (although this is a * crappy hash, and iterating the hash is not possible....) */ hdestroy(); g_debug("Application Labeler accepted %d rules.", numPayloadRules); g_debug("Application Labeler accepted %d signatures.", numSigRules); pcre_free(ruleScanner); pcre_free(pluginScanner); pcre_free(commentScanner); pcre_free(pluginArgScanner); pcre_free(signatureScanner); /* debug */ return TRUE; }