X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Fsearch.c;h=d929322ba0f3808ee2852bdb062fe55093151a53;hb=7e26c2f6e641307f44c7a0c88def1d43f3e67eab;hp=ebdf8a165cf800747aa2389f6d5dae9c29e75f1c;hpb=42c7f0b4ea09d8971a19beeef743ec8981d4aacc;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/search.c b/src/src/search.c index ebdf8a165..d929322ba 100644 --- a/src/src/search.c +++ b/src/src/search.c @@ -41,7 +41,7 @@ static int open_filecount = 0; /* Allow us to reset store used for lookups and lookup caching */ -static void *search_reset_point = NULL; +static rmark search_reset_point = NULL; @@ -115,6 +115,7 @@ Arguments: otherwise it's a literal string afflen the length of the affix starflags where to put the SEARCH_STAR and SEARCH_STARAT flags + opts where to put the options Returns: +ve => valid lookup name; value is offset in lookup_list -ve => invalid name; message in search_error_message. @@ -122,11 +123,12 @@ Returns: +ve => valid lookup name; value is offset in lookup_list int search_findtype_partial(const uschar *name, int *ptypeptr, const uschar **ptypeaff, - int *afflen, int *starflags) + int *afflen, int *starflags, const uschar ** opts) { int len, stype; int pv = -1; const uschar *ss = name; +const uschar * t; *starflags = 0; *ptypeaff = NULL; @@ -167,19 +169,26 @@ if (Ustrncmp(name, "partial", 7) == 0) } } -/* Now we are left with a lookup name, possibly followed by * or *@. */ +/* Now we are left with a lookup name, possibly followed by * or *@, +and then by options starting with a "," */ len = Ustrlen(ss); -if (len >= 2 && Ustrncmp(ss + len - 2, "*@", 2) == 0) +if ((t = Ustrchr(ss, '*'))) { - *starflags |= SEARCH_STARAT; - len -= 2; + len = t - ss; + *starflags |= (t[1] == '@' ? SEARCH_STARAT : SEARCH_STAR); } -else if (len >= 1 && ss[len-1] == '*') +else + t = ss; + +if ((t = Ustrchr(t, ','))) { - *starflags |= SEARCH_STAR; - len--; + int l = t - ss; + if (l < len) len = l; + *opts = string_copy(t+1); } +else + * opts = NULL; /* Check for the individual search type. Only those that are actually in the binary are valid. For query-style types, "partial" and default types are @@ -269,8 +278,7 @@ open_filecount = 0; for (int i = 0; i < lookup_list_count; i++) if (lookup_list[i]->tidy) (lookup_list[i]->tidy)(); -if (search_reset_point) store_reset(search_reset_point); -search_reset_point = NULL; +if (search_reset_point) search_reset_point = store_reset(search_reset_point); store_pool = old_pool; } @@ -326,8 +334,8 @@ Returns: an identifying handle for the open database; */ void * -search_open(uschar *filename, int search_type, int modemask, uid_t *owners, - gid_t *owngroups) +search_open(const uschar * filename, int search_type, int modemask, + uid_t * owners, gid_t * owngroups) { void *handle; tree_node *t; @@ -336,10 +344,17 @@ lookup_info *lk = lookup_list[search_type]; uschar keybuffer[256]; int old_pool = store_pool; +if (filename && is_tainted(filename)) + { + log_write(0, LOG_MAIN|LOG_PANIC, + "Tainted filename for search: '%s'", filename); + return NULL; + } + /* Change to the search store pool and remember our reset point */ store_pool = POOL_SEARCH; -if (search_reset_point == NULL) search_reset_point = store_get(0); +if (!search_reset_point) search_reset_point = store_mark(); DEBUG(D_lookup) debug_printf_indent("search_open: %s \"%s\"\n", lk->name, filename ? filename : US"NULL"); @@ -350,12 +365,11 @@ type plus '0' concatenated with the file name. There may be entries in the tree with closed files if a lot of files have been opened. */ sprintf(CS keybuffer, "%c%.254s", search_type + '0', - (filename == NULL)? US"" : filename); + filename ? filename : US""); -if ((t = tree_search(search_tree, keybuffer)) != NULL) +if ((t = tree_search(search_tree, keybuffer))) { - c = (search_cache *)(t->data.ptr); - if (c->handle != NULL) + if ((c = (search_cache *)t->data.ptr)->handle) { DEBUG(D_lookup) debug_printf_indent(" cached open\n"); store_pool = old_pool; @@ -371,8 +385,7 @@ we are holding open in the cache. If the limit is reached, close the least recently used one. */ if (lk->type == lookup_absfile && open_filecount >= lookup_open_max) - { - if (open_bot == NULL) + if (!open_bot) log_write(0, LOG_MAIN|LOG_PANIC, "too many lookups open, but can't find " "one to close"); else @@ -380,8 +393,7 @@ if (lk->type == lookup_absfile && open_filecount >= lookup_open_max) search_cache *c = (search_cache *)(open_bot->data.ptr); DEBUG(D_lookup) debug_printf_indent("Too many lookup files open\n closing %s\n", open_bot->name); - open_bot = c->up; - if (open_bot != NULL) + if ((open_bot = c->up)) ((search_cache *)(open_bot->data.ptr))->down = NULL; else open_top = NULL; @@ -389,21 +401,19 @@ if (lk->type == lookup_absfile && open_filecount >= lookup_open_max) c->handle = NULL; open_filecount--; } - } /* If opening is successful, call the file-checking function if there is one, and if all is still well, enter the open database into the tree. */ -handle = (lk->open)(filename, &search_error_message); -if (handle == NULL) +if (!(handle = (lk->open)(filename, &search_error_message))) { store_pool = old_pool; return NULL; } -if (lk->check != NULL && - !lk->check(handle, filename, modemask, owners, owngroups, - &search_error_message)) +if ( lk->check + && !lk->check(handle, filename, modemask, owners, owngroups, + &search_error_message)) { lk->close(handle); store_pool = old_pool; @@ -418,10 +428,10 @@ if (lk->type == lookup_absfile) open_filecount++; insert a new entry. On re-use, leave any cached lookup data and the lookup count alone. */ -if (t == NULL) +if (!t) { - t = store_get(sizeof(tree_node) + Ustrlen(keybuffer)); - t->data.ptr = c = store_get(sizeof(search_cache)); + t = store_get(sizeof(tree_node) + Ustrlen(keybuffer), FALSE); + t->data.ptr = c = store_get(sizeof(search_cache), FALSE); c->item_cache = NULL; Ustrcpy(t->name, keybuffer); tree_insertnode(&search_tree, t); @@ -453,6 +463,7 @@ Arguments: NULL for query-style searches keystring the keystring for single-key+file lookups, or the querystring for query-style lookups + opts type-specific options Returns: a pointer to a dynamic string containing the answer, or NULL if the query failed or was deferred; in the @@ -461,7 +472,8 @@ Returns: a pointer to a dynamic string containing the answer, */ static uschar * -internal_search_find(void *handle, uschar *filename, uschar *keystring) +internal_search_find(void * handle, const uschar * filename, uschar * keystring, + const uschar * opts) { tree_node * t = (tree_node *)handle; search_cache * c = (search_cache *)(t->data.ptr); @@ -477,8 +489,9 @@ search_error_message = US""; f.search_find_defer = FALSE; DEBUG(D_lookup) debug_printf_indent("internal_search_find: file=\"%s\"\n " - "type=%s key=\"%s\"\n", filename, - lookup_list[search_type]->name, keystring); + "type=%s key=\"%s\" opts=%s%s%s\n", filename, + lookup_list[search_type]->name, keystring, + opts ? "\"" : "", opts, opts ? "\"" : ""); /* Insurance. If the keystring is empty, just fail. */ @@ -493,9 +506,10 @@ file. No need to check c->item_cache for NULL, tree_search will do so. */ if ( (t = tree_search(c->item_cache, keystring)) && (!(e = t->data.ptr)->expiry || e->expiry > time(NULL)) + && (!opts && !e->opts || opts && e->opts && Ustrcmp(opts, e->opts) == 0) ) { /* Data was in the cache already; set the pointer from the tree node */ - data = e->ptr; + data = e->data.ptr; DEBUG(D_lookup) debug_printf_indent("cached data used for lookup of %s%s%s\n", keystring, filename ? US"\n in " : US"", filename ? filename : US""); @@ -507,7 +521,8 @@ else DEBUG(D_lookup) { - if (t) debug_printf_indent("cached data found but past valid time; "); + if (t) + debug_printf_indent("cached data found but either wrong opts or dated; "); debug_printf_indent("%s lookup required for %s%s%s\n", filename ? US"file" : US"database", keystring, @@ -519,7 +534,7 @@ else distinguish if necessary. */ if (lookup_list[search_type]->find(c->handle, filename, keystring, keylength, - &data, &search_error_message, &do_cache) == DEFER) + &data, &search_error_message, &do_cache, opts) == DEFER) f.search_find_defer = TRUE; /* A record that has been found is now in data, which is either NULL @@ -530,23 +545,23 @@ else else if (do_cache) { - int len = keylength + 1; - - if (t) /* Previous, out-of-date cache entry. Update with the */ - { /* new result and forget the old one */ - e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache; - e->ptr = data; - } - else + if (!t) /* No existing entry. Create new one. */ { - e = store_get(sizeof(expiring_data) + sizeof(tree_node) + len); + int len = keylength + 1; + e = store_get(sizeof(expiring_data) + sizeof(tree_node) + len, is_tainted(keystring)); e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache; - e->ptr = data; + e->opts = opts; + e->data.ptr = data; t = (tree_node *)(e+1); memcpy(t->name, keystring, len); t->data.ptr = e; tree_insertnode(&c->item_cache, t); } + /* Else previous, out-of-date cache entry. Update with the */ + /* new result and forget the old one */ + e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache; + e->opts = opts; + e->data.ptr = data; } /* If caching was disabled, empty the cache tree. We just set the cache @@ -597,6 +612,7 @@ Arguments: starflags SEARCH_STAR and SEARCH_STARAT flags expand_setup pointer to offset for setting up expansion strings; don't do any if < 0 + opts type-specific options Returns: a pointer to a dynamic string containing the answer, or NULL if the query failed or was deferred; in the @@ -604,8 +620,9 @@ Returns: a pointer to a dynamic string containing the answer, */ uschar * -search_find(void *handle, uschar *filename, uschar *keystring, int partial, - const uschar *affix, int affixlen, int starflags, int *expand_setup) +search_find(void * handle, const uschar * filename, uschar * keystring, + int partial, const uschar * affix, int affixlen, int starflags, + int * expand_setup, const uschar * opts) { tree_node *t = (tree_node *)handle; BOOL set_null_wild = FALSE; @@ -615,16 +632,18 @@ DEBUG(D_lookup) { if (partial < 0) affixlen = 99; /* So that "NULL" prints */ debug_printf_indent("search_find: file=\"%s\"\n key=\"%s\" " - "partial=%d affix=%.*s starflags=%x\n", - (filename == NULL)? US"NULL" : filename, - keystring, partial, affixlen, affix, starflags); + "partial=%d affix=%.*s starflags=%x opts=%s%s%s\n", + filename ? filename : US"NULL", + keystring, partial, affixlen, affix, starflags, + opts ? "\"" : "", opts, opts ? "\"" : ""); + } /* Arrange to put this database at the top of the LRU chain if it is a type that opens real files. */ -if (open_top != (tree_node *)handle && - lookup_list[t->name[0]-'0']->type == lookup_absfile) +if ( open_top != (tree_node *)handle + && lookup_list[t->name[0]-'0']->type == lookup_absfile) { search_cache *c = (search_cache *)(t->data.ptr); tree_node *up = c->up; @@ -634,20 +653,21 @@ if (open_top != (tree_node *)handle && Otherwise there will be a non-NULL up pointer, since we checked above that this block isn't already at the top of the list. */ - if (up != NULL) + if (up) { ((search_cache *)(up->data.ptr))->down = down; - if (down != NULL) + if (down) ((search_cache *)(down->data.ptr))->up = up; - else open_bot = up; + else + open_bot = up; } /* Now put it at the head of the list. */ c->up = NULL; c->down = open_top; - if (open_top == NULL) open_bot = t; else - ((search_cache *)(open_top->data.ptr))->up = t; + if (!open_top) open_bot = t; + else ((search_cache *)(open_top->data.ptr))->up = t; open_top = t; } @@ -666,9 +686,10 @@ DEBUG(D_lookup) /* First of all, try to match the key string verbatim. If matched a complete entry but could have been partial, flag to set up variables. */ -yield = internal_search_find(handle, filename, keystring); +yield = internal_search_find(handle, filename, keystring, opts); if (f.search_find_defer) return NULL; -if (yield != NULL) { if (partial >= 0) set_null_wild = TRUE; } + +if (yield) { if (partial >= 0) set_null_wild = TRUE; } /* Not matched a complete entry; handle partial lookups, but only if the full search didn't defer. Don't use string_sprintf() to construct the initial key, @@ -685,11 +706,12 @@ else if (partial >= 0) if (affixlen == 0) keystring2 = keystring; else { - keystring2 = store_get(len + affixlen + 1); + keystring2 = store_get(len + affixlen + 1, + is_tainted(keystring) || is_tainted(affix)); Ustrncpy(keystring2, affix, affixlen); Ustrcpy(keystring2 + affixlen, keystring); DEBUG(D_lookup) debug_printf_indent("trying partial match %s\n", keystring2); - yield = internal_search_find(handle, filename, keystring2); + yield = internal_search_find(handle, filename, keystring2, opts); if (f.search_find_defer) return NULL; } @@ -727,14 +749,14 @@ else if (partial >= 0) } DEBUG(D_lookup) debug_printf_indent("trying partial match %s\n", keystring3); - yield = internal_search_find(handle, filename, keystring3); + yield = internal_search_find(handle, filename, keystring3, opts); if (f.search_find_defer) return NULL; - if (yield != NULL) + if (yield) { /* First variable is the wild part; second is the fixed part. Take care to get it right when keystring3 is just "*". */ - if (expand_setup != NULL && *expand_setup >= 0) + if (expand_setup && *expand_setup >= 0) { int fixedlength = Ustrlen(keystring3) - affixlen; int wildlength = Ustrlen(keystring) - fixedlength - 1; @@ -758,7 +780,7 @@ else if (partial >= 0) replacing everything to the left of @ by *. After a match, the wild part is set to the string to the left of the @. */ -if (yield == NULL && (starflags & SEARCH_STARAT) != 0) +if (!yield && starflags & SEARCH_STARAT) { uschar *atat = Ustrrchr(keystring, '@'); if (atat != NULL && atat > keystring) @@ -768,11 +790,11 @@ if (yield == NULL && (starflags & SEARCH_STARAT) != 0) *atat = '*'; DEBUG(D_lookup) debug_printf_indent("trying default match %s\n", atat); - yield = internal_search_find(handle, filename, atat); + yield = internal_search_find(handle, filename, atat, opts); *atat = savechar; if (f.search_find_defer) return NULL; - if (yield != NULL && expand_setup != NULL && *expand_setup >= 0) + if (yield && expand_setup && *expand_setup >= 0) { *expand_setup += 1; expand_nstring[*expand_setup] = keystring; @@ -788,11 +810,11 @@ if (yield == NULL && (starflags & SEARCH_STARAT) != 0) try that. If we do match, the first variable (the wild part) is the whole key, and the second is empty. */ -if (yield == NULL && (starflags & (SEARCH_STAR|SEARCH_STARAT)) != 0) +if (!yield && starflags & (SEARCH_STAR|SEARCH_STARAT)) { DEBUG(D_lookup) debug_printf_indent("trying to match *\n"); - yield = internal_search_find(handle, filename, US"*"); - if (yield != NULL && expand_setup != NULL && *expand_setup >= 0) + yield = internal_search_find(handle, filename, US"*", opts); + if (yield && expand_setup && *expand_setup >= 0) { *expand_setup += 1; expand_nstring[*expand_setup] = keystring; @@ -810,7 +832,7 @@ chopping off any of the domain components, set up the expansion variables fixed part of the domain. The set_null_wild flag is set only when yield is not NULL. */ -if (set_null_wild && expand_setup != NULL && *expand_setup >= 0) +if (set_null_wild && expand_setup && *expand_setup >= 0) { *expand_setup += 1; expand_nstring[*expand_setup] = keystring;