/* * called to create a directory: does in parts if needed * return 0 on success, non-zero on error */ static int unix_mkdirfcn (const char *path, const int perm) { char *ch; int err = 0; ch = (char *)path; for (;;) { for (; (*ch != '/') && (*ch != '\0'); ch++); /* at next slash or end */ if (ch > path) { /* see if path up to, not including '/' (or end), exists */ char *tstr = string_ndup (path, (int)(ch - path)); if (access (tstr, F_OK)) { if (errno == ENOENT) { /* try and create it */ err = mkdir (tstr, perm); sfree (tstr); goto out; } } sfree (tstr); if (*ch == '/') { ch++; } } else { /* leading slash */ ch++; } if (*ch == '\0') { break; /* end */ } } out: return err; }
char *grok_match_reaction_apply_filter(grok_match_t *gm, char **value, int *value_len, const char *filter, int filter_len) { int offset = 0, len = 0; int value_size; int ret; struct filter *filterobj; if (filter_len == 0) { return *value; } *value = string_ndup(*value, *value_len); /* we'll use the value_len from the function arguments */ value_size = *value_len + 1; /* skip first char which must be a '|' */ offset = 1; while (offset + len < filter_len) { if (filter[offset + len] == '|') { /* Apply the filter */ grok_log(gm->grok, LOG_REACTION, "ApplyFilter code: %.*s", len, filter + offset); filterobj = string_filter_lookup(filter + offset, len); if (filterobj == NULL) { grok_log(gm->grok, LOG_REACTION, "Can't apply filter '%.*s'; it's unknown.", len, filter + offset); } else { ret = filterobj->func(gm, value, value_len, &value_size); if (ret != 0) { grok_log(gm->grok, LOG_REACTION, "Applying filter '%.*s' returned error %d for string '%.*s'.", len, filter + offset, *value_len, *value); } } offset += len + 1; len = 0; } len++; } /* We'll always have one filter left over */ grok_log(gm->grok, LOG_REACTION, "Filter code: %.*s", len, filter + offset); filterobj = string_filter_lookup(filter + offset, len); if (filterobj == NULL) { grok_log(gm->grok, LOG_REACTION, "Can't apply filter '%.*s'; it's unknown.", len, filter + offset); } else { ret = filterobj->func(gm, value, value_len, &value_size); if (ret != 0) { grok_log(gm->grok, LOG_REACTION, "Applying filter '%.*s' returned error %d for string '%.*s'.", len, filter + offset, *value_len, *value); } } return *value; }
char *grok_matchconfig_filter_reaction(const char *str, grok_match_t *gm) { char *output; int len; int size; grok_match_t tmp_gm; int offset = 0; if (gm == NULL) { return NULL; } len = strlen(str); size = len + 1; output = malloc(size); memcpy(output, str, size); grok_log(gm->grok, LOG_REACTION, "Checking '%.*s'", len - offset, output + offset); global_matchconfig_grok.logmask = gm->grok->logmask; global_matchconfig_grok.logdepth = gm->grok->logdepth + 1; while (grok_execn(&global_matchconfig_grok, output + offset, len - offset, &tmp_gm) == GROK_OK) { grok_log(gm->grok, LOG_REACTION, "Checking '%.*s'", len - offset, output + offset); const char *name = NULL; const char *filter = NULL; char *value = NULL; char *name_copy; int name_len, value_len, filter_len; int ret = -1; int free_value = 0; const struct strmacro *patmacro; grok_match_get_named_substring(&tmp_gm, "NAME", &name, &name_len); grok_match_get_named_substring(&tmp_gm, "FILTER", &filter, &filter_len); grok_log(gm->grok, LOG_REACTION, "Matched something: %.*s", name_len, name); /* XXX: We should really make a dispatch table out of this... */ /* _macro_dispatch_func(char **value, int *value_len) ... */ /* Let gperf do the hard work for us. */ patmacro = patname2macro(name, name_len); grok_log(gm->grok, LOG_REACTION, "Checking lookup table for '%.*s': %x", name_len, name, patmacro); if (patmacro != NULL) { free_value = 1; /* We malloc stuff to 'value' here */ switch (patmacro->code) { case VALUE_LINE: value = strdup(gm->subject); value_len = strlen(value); ret = 0; break; case VALUE_START: value_len = asprintf(&value, "%d", gm->start); ret = 0; break; case VALUE_END: value_len = asprintf(&value, "%d", gm->end); ret = 0; break; case VALUE_LENGTH: value_len = asprintf(&value, "%d", gm->end - gm->start); ret = 0; break; case VALUE_MATCH: value_len = gm->end - gm->start; value = string_ndup(gm->subject + gm->start, value_len); ret = 0; break; case VALUE_JSON_SIMPLE: case VALUE_JSON_COMPLEX: { int value_offset = 0; int value_size = 0; char *pname; const char *pdata; int pname_len, pdata_len; char *entry = NULL, *tmp = NULL; int entry_len = 0, tmp_len = 0, tmp_size = 0; value = NULL; value_len = 0; /* TODO(sissel): use a json generator library? */ /* Push @FOO values first */ substr_replace(&tmp, &tmp_len, &tmp_size, 0, 0, gm->subject, strlen(gm->subject)); filter_jsonencode(gm, &tmp, &tmp_len, &tmp_size); if (patmacro->code == VALUE_JSON_SIMPLE) { entry_len = asprintf(&entry, "\"@LINE\": \"%.*s\", ", tmp_len, tmp); } else { /* VALUE_JSON_COMPLEX */ entry_len = asprintf(&entry, "{ \"@LINE\": { " "\"start\": 0, " "\"end\": %d, " "\"value\": \"%.*s\" } }, ", tmp_len, tmp_len, tmp); } substr_replace(&value, &value_len, &value_size, value_len, value_len, entry, entry_len); free(entry); substr_replace(&tmp, &tmp_len, &tmp_size, 0, tmp_len, gm->subject + gm->start, gm->end - gm->start); filter_jsonencode(gm, &tmp, &tmp_len, &tmp_size); if (patmacro->code == VALUE_JSON_SIMPLE) { entry_len = asprintf(&entry, "\"@MATCH\": \"%.*s\", ", tmp_len, tmp); } else { /* VALUE_JSON_COMPLEX */ entry_len = asprintf(&entry, "{ \"@MATCH\": { " "\"start\": %d, " "\"end\": %d, " "\"value\": \"%.*s\" } }, ", gm->start, gm->end, tmp_len, tmp); } substr_replace(&value, &value_len, &value_size, value_len, value_len, entry, entry_len); free(entry); //printf("> %.*s\n", value_len, value); value_offset += value_len; /* For every named capture, put this in our result string: * "NAME": "%{NAME|jsonencode}" */ grok_match_walk_init(gm); while (grok_match_walk_next(gm, &pname, &pname_len, &pdata, &pdata_len) == 0) { char *entry; int entry_len; substr_replace(&tmp, &tmp_len, &tmp_size, 0, tmp_len, pdata, pdata_len); filter_jsonencode(gm, &tmp, &tmp_len, &tmp_size); if (patmacro->code == VALUE_JSON_SIMPLE) { entry_len = asprintf(&entry, "\"%.*s\": \"%.*s\", ", pname_len, pname, tmp_len, tmp); } else { /* VALUE_JSON_COMPLEX */ entry_len = asprintf(&entry, "{ \"%.*s\": { " "\"start\": %ld, " "\"end\": %ld, " "\"value\": \"%.*s\"" " } }, ", pname_len, pname, pdata - gm->subject, /*start*/ (pdata - gm->subject) + pdata_len, /*end*/ tmp_len, tmp); } substr_replace(&value, &value_len, &value_size, value_offset, value_offset, entry, entry_len); value_offset += entry_len; free(entry); } grok_match_walk_end(gm); /* Insert the { at the beginning */ /* And Replace trailing ", " with " }" */ if (patmacro->code == VALUE_JSON_SIMPLE) { substr_replace(&value, &value_len, &value_size, 0, 0, "{ ", 2); substr_replace(&value, &value_len, &value_size, value_len - 2, value_len, " }", 2); /* TODO(sissel): This could be: * -3, -1, " }", 2); */ } else { /* VALUE_JSON_COMPLEX */ substr_replace(&value, &value_len, &value_size, 0, 0, "{ \"grok\": [ ", 12); substr_replace(&value, &value_len, &value_size, value_len - 2, value_len, " ] }", 4); /* TODO(sissel): This could be: * -3, -1, " ] }", 4); */ } char *old = value; grok_log(gm->grok, LOG_REACTION, "JSON intermediate: %.*s", value_len, value); value = grok_matchconfig_filter_reaction(value, gm); free(old); ret = 0; free(tmp); } break; default: grok_log(gm->grok, LOG_REACTION, "Unhandled macro code: '%.*s' (%d)", name_len, name, patmacro->code); } } else { /* XXX: Should just have get_named_substring take a * 'name, name_len' instead */ name_copy = malloc(name_len + 1); memcpy(name_copy, name, name_len); name_copy[name_len] = '\0'; ret = grok_match_get_named_substring(gm, name_copy, (const char **)&value, &value_len); free(name_copy); } if (ret != 0) { offset += tmp_gm.end; } else { /* replace %{FOO} with the value of foo */ char *old; grok_log(tmp_gm.grok, LOG_REACTION, "Start/end: %d %d", tmp_gm.start, tmp_gm.end); grok_log(tmp_gm.grok, LOG_REACTION, "Replacing %.*s", (tmp_gm.end - tmp_gm.start), output + tmp_gm.start + offset); /* apply the any filters from %{FOO|filter1|filter2...} */ old = value; grok_log(tmp_gm.grok, LOG_REACTION, "Prefilter string: %.*s", value_len, value); grok_match_reaction_apply_filter(gm, &value, &value_len, filter, filter_len); if (old != value) { if (free_value) { free(old); /* Free the old value */ } free_value = 1; } grok_log(gm->grok, LOG_REACTION, "Filter: %.*s", filter_len, filter); grok_log(tmp_gm.grok, LOG_REACTION, "Replacing %.*s with %.*s", (tmp_gm.end - tmp_gm.start), output + tmp_gm.start + offset, value_len, value); substr_replace(&output, &len, &size, offset + tmp_gm.start, offset + tmp_gm.end, value, value_len); offset += value_len; if (free_value) { free(value); } } } /* while grok_execn ... */ return output; }
/* XXX: This method is pretty long; split it up? */ static char *grok_pattern_expand(grok_t *grok) { int capture_id = 0; /* Starting capture_id, doesn't really matter what this is */ int offset = 0; /* string offset; how far we've expanded so far */ int *capture_vector = NULL; int replacement_count = 0; /* count of replacements of %{foo} with a regexp */ int full_len = -1; int full_size = -1; char *full_pattern = NULL; char capture_id_str[CAPTURE_ID_LEN + 1]; const char *patname = NULL; capture_vector = calloc(3 * g_pattern_num_captures, sizeof(int)); full_len = grok->pattern_len; full_size = full_len; full_pattern = calloc(1, full_size + 1); memcpy(full_pattern, grok->pattern, full_len + 1); grok_log(grok, LOG_REGEXPAND, "% 20s: %.*s", "start of expand", full_len, full_pattern); while (pcre_exec(g_pattern_re, NULL, full_pattern, full_len, offset, 0, capture_vector, g_pattern_num_captures * 3) >= 0) { int start, end, matchlen; const char *pattern_regex; int patname_len; size_t regexp_len; int pattern_regex_needs_free = 0; grok_log(grok, LOG_REGEXPAND, "% 20s: %.*s", "start of loop", full_len, full_pattern); replacement_count++; if (replacement_count > 1000) { free(capture_vector); free(full_pattern); grok->errstr = "Too many replacements have occurred (500), infinite recursion?"; return NULL; } start = capture_vector[0]; end = capture_vector[1]; matchlen = end - start; grok_log(grok, LOG_REGEXPAND, "Pattern length: %d", matchlen); pcre_get_substring(full_pattern, capture_vector, g_pattern_num_captures, g_cap_pattern, &patname); patname_len = capture_vector[g_cap_pattern * 2 + 1] \ - capture_vector[g_cap_pattern * 2]; grok_log(grok, LOG_REGEXPAND, "Pattern name: %.*s", patname_len, patname); grok_pattern_find(grok, patname, patname_len, &pattern_regex, ®exp_len); if (pattern_regex == NULL) { /* Pattern not found, check if this has an in-line definition */ int definition_len = capture_vector[g_cap_definition * 2 + 1] - capture_vector[g_cap_definition * 2]; if (definition_len > 0) { /* We got an in-line definition */ /* discard const-ness with reckless abandon! */ pattern_regex = string_ndup(full_pattern + capture_vector[g_cap_definition * 2], definition_len); regexp_len = definition_len; pattern_regex_needs_free = 1; grok_log(grok, LOG_REGEXPAND, "Inline-definition found: %.*s => '%.*s'", patname_len, patname, regexp_len, pattern_regex); } else { /* If we get here, there's definitely no pattern available for the * current %{thing}, so just leave it unmolested. */ offset = end; } } /* Check for nullness again because there could've been an inline * definition found above */ if (pattern_regex != NULL) { int has_predicate = (capture_vector[g_cap_predicate * 2] >= 0); const char *longname = NULL; const char *subname = NULL; grok_capture *gct = calloc(1, sizeof(grok_capture));; /* XXX: Change this to not use pcre_get_substring so we can skip a * malloc step? */ pcre_get_substring(full_pattern, capture_vector, g_pattern_num_captures, g_cap_name, &longname); pcre_get_substring(full_pattern, capture_vector, g_pattern_num_captures, g_cap_subname, &subname); snprintf(capture_id_str, CAPTURE_ID_LEN + 1, CAPTURE_FORMAT, capture_id); /* Add this capture to the list of captures */ gct->id = capture_id; gct->name = (char *)longname; /* XXX: CONST PROBLEM */ gct->name_len = strlen(gct->name); gct->subname = (char *)subname; gct->subname_len = strlen(gct->subname); grok_capture_add(grok, gct); //pcre_free_substring(longname); //pcre_free_substring(subname); /* if a predicate was given, add (?C1) to callout when the match is made, * so we can test it further */ if (has_predicate) { int pstart, pend; pstart = capture_vector[g_cap_predicate * 2]; pend = capture_vector[g_cap_predicate * 2 + 1]; grok_log(grok, LOG_REGEXPAND, "Predicate found in '%.*s'", matchlen, full_pattern + start); grok_log(grok, LOG_REGEXPAND, "Predicate is: '%.*s'", pend - pstart, full_pattern + pstart); grok_capture_add_predicate(grok, capture_id, full_pattern + pstart, pend - pstart); substr_replace(&full_pattern, &full_len, &full_size, end, 0, "(?C1)", 5); } /* Replace %{FOO} with (?<>). '5' is strlen("(?<>)") */ substr_replace(&full_pattern, &full_len, &full_size, start, end, "(?<>)", 5); grok_log(grok, LOG_REGEXPAND, "% 20s: %.*s", "replace with (?<>)", full_len, full_pattern); /* Insert the capture id into (?<FOO>) */ substr_replace(&full_pattern, &full_len, &full_size, start + 3, 0, capture_id_str, CAPTURE_ID_LEN); grok_log(grok, LOG_REGEXPAND, "% 20s: %.*s", "add capture id", full_len, full_pattern); /* Insert the pattern into (?<FOO>pattern) */ /* 3 = '(?<', 4 = strlen(capture_id_str), 1 = ")" */ substr_replace(&full_pattern, &full_len, &full_size, start + 3 + CAPTURE_ID_LEN + 1, 0, pattern_regex, regexp_len); grok_log(grok, LOG_REGEXPAND, ":: Inserted: %.*s", regexp_len, pattern_regex); grok_log(grok, LOG_REGEXPAND, ":: STR: %.*s", full_len, full_pattern); /* Invariant, full_pattern actual len must always be full_len */ assert(strlen(full_pattern) == full_len); /* Move offset to the start of the regexp pattern we just injected. * This is so when we iterate again, we can process this new pattern * to see if the regexp included itself any %{FOO} things */ offset = start; capture_id++; } if (pattern_regex_needs_free) { /* If we need to free, */ free(pattern_regex); } if (patname != NULL) { pcre_free_substring(patname); patname = NULL; } } /* while pcre_exec */ /* Unescape any "\%" strings found */ offset = 0; while (offset < full_len) { /* loop to '< full_len' because we access offset+1 */ if (full_pattern[offset] == '\\' && full_pattern[offset + 1] == '%') { substr_replace(&full_pattern, &full_len, &full_size, offset, offset + 1, "", 0); } offset++; } grok_log(grok, LOG_REGEXPAND, "Fully expanded: %.*s", full_len, full_pattern); free(capture_vector); grok->full_pattern_len = full_len; grok->full_pattern = full_pattern; return full_pattern; } /* grok_pattern_expand */