X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;ds=inline;f=src%2Fsrc%2Fsearch.c;h=2a60fc78a046c6702179df3840ed038ccdcdd3e4;hb=a5dc727afcc92deab722a84ae5cf3d00ae74c5f6;hp=9d1a10a5a00f2f8f45c9903fac2c69917cedf806;hpb=7d8d08c484958a90f5d5744894b9bc2f723bee4e;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/search.c b/src/src/search.c index 9d1a10a5a..2a60fc78a 100644 --- a/src/src/search.c +++ b/src/src/search.c @@ -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 @@ -325,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; @@ -335,6 +344,13 @@ 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; @@ -353,8 +369,7 @@ sprintf(CS keybuffer, "%c%.254s", search_type + '0', if ((t = tree_search(search_tree, keybuffer))) { - c = (search_cache *)(t->data.ptr); - if (c->handle) + if ((c = (search_cache *)t->data.ptr)->handle) { DEBUG(D_lookup) debug_printf_indent(" cached open\n"); store_pool = old_pool; @@ -370,7 +385,6 @@ 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) log_write(0, LOG_MAIN|LOG_PANIC, "too many lookups open, but can't find " "one to close"); @@ -387,7 +401,6 @@ 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. */ @@ -450,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 @@ -458,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); @@ -474,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. */ @@ -490,6 +506,7 @@ 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->data.ptr; @@ -504,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, @@ -516,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 @@ -532,12 +550,14 @@ else 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->opts = opts; e->data.ptr = data; } else { 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->opts = opts; e->data.ptr = data; t = (tree_node *)(e+1); memcpy(t->name, keystring, len); @@ -594,6 +614,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 @@ -601,8 +622,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; @@ -612,9 +634,11 @@ 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 @@ -664,7 +688,7 @@ 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) { if (partial >= 0) set_null_wild = TRUE; } @@ -689,7 +713,7 @@ else if (partial >= 0) 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,7 +751,7 @@ 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) { @@ -768,7 +792,7 @@ if (!yield && starflags & SEARCH_STARAT) *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; @@ -791,7 +815,7 @@ and the second is empty. */ if (!yield && starflags & (SEARCH_STAR|SEARCH_STARAT)) { DEBUG(D_lookup) debug_printf_indent("trying to match *\n"); - yield = internal_search_find(handle, filename, US"*"); + yield = internal_search_find(handle, filename, US"*", opts); if (yield && expand_setup && *expand_setup >= 0) { *expand_setup += 1;