X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/0a49a7a4f1090b6f1ce1d0f9d969804c9226b53e..a85c067ba6c6940512cf57ec213277a370d87e70:/src/src/lookups/lf_sqlperform.c diff --git a/src/src/lookups/lf_sqlperform.c b/src/src/lookups/lf_sqlperform.c index 2cb02ac81..cf4b9cd0b 100644 --- a/src/src/lookups/lf_sqlperform.c +++ b/src/src/lookups/lf_sqlperform.c @@ -1,11 +1,11 @@ -/* $Cambridge: exim/src/src/lookups/lf_sqlperform.c,v 1.2 2009/11/16 19:50:38 nm4 Exp $ */ - /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2009 */ +/* Copyright (c) The Exim Maintainers 2020 - 2022 */ +/* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-only */ #include "../exim.h" @@ -29,63 +29,44 @@ Arguments: query the query result where to pass back the result errmsg where to pass back an error message - do_cache to be set FALSE if data is changed + do_cache to be set zero if data is changed func the lookup function to call Returns: the return from the lookup function, or DEFER */ int -lf_sqlperform(uschar *name, uschar *optionname, uschar *optserverlist, - uschar *query, uschar **result, uschar **errmsg, BOOL *do_cache, - int(*fn)(uschar *, uschar *, uschar **, uschar **, BOOL *, BOOL *)) +lf_sqlperform(const uschar *name, const uschar *optionname, + const uschar *optserverlist, const uschar *query, + uschar **result, uschar **errmsg, uint *do_cache, const uschar * opts, + int(*fn)(const uschar *, uschar *, uschar **, uschar **, BOOL *, uint *, const uschar *)) { -int sep, rc; +int rc; uschar *server; -uschar *serverlist; -uschar buffer[512]; BOOL defer_break = FALSE; -DEBUG(D_lookup) debug_printf("%s query: %s\n", name, query); - -/* Handle queries that do not have server information at the start. */ - -if (Ustrncmp(query, "servers", 7) != 0) - { - sep = 0; - serverlist = optserverlist; - while ((server = string_nextinlist(&serverlist, &sep, buffer, - sizeof(buffer))) != NULL) - { - rc = (*fn)(query, server, result, errmsg, &defer_break, do_cache); - if (rc != DEFER || defer_break) return rc; - } - if (optserverlist == NULL) - *errmsg = string_sprintf("no %s servers defined (%s option)", name, - optionname); - } +DEBUG(D_lookup) debug_printf_indent("%s query: \"%s\" opts '%s'\n", name, query, opts); /* Handle queries that do have server information at the start. */ -else +if (Ustrncmp(query, "servers", 7) == 0) { - int qsep; - uschar *s, *ss; - uschar *qserverlist; + int qsep = 0; + const uschar *s, *ss; + const uschar *qserverlist; uschar *qserver; - uschar qbuffer[512]; s = query + 7; - while (isspace(*s)) s++; + skip_whitespace(&s); if (*s++ != '=') { *errmsg = string_sprintf("missing = after \"servers\" in %s lookup", name); return DEFER; } - while (isspace(*s)) s++; + skip_whitespace(&s); ss = Ustrchr(s, ';'); - if (ss == NULL) + if (!ss) { *errmsg = string_sprintf("missing ; after \"servers=\" in %s lookup", name); @@ -99,28 +80,22 @@ else return DEFER; } - qserverlist = string_sprintf("%.*s", ss - s, s); - qsep = 0; + qserverlist = string_sprintf("%.*s", (int)(ss - s), s); - while ((qserver = string_nextinlist(&qserverlist, &qsep, qbuffer, - sizeof(qbuffer))) != NULL) + while ((qserver = string_nextinlist(&qserverlist, &qsep, NULL, 0))) { - if (Ustrchr(qserver, '/') != NULL) + if (Ustrchr(qserver, '/')) server = qserver; else { int len = Ustrlen(qserver); + const uschar * serverlist = optserverlist; - sep = 0; - serverlist = optserverlist; - while ((server = string_nextinlist(&serverlist, &sep, buffer, - sizeof(buffer))) != NULL) - { + for (int sep = 0; server = string_nextinlist(&serverlist, &sep, NULL, 0);) if (Ustrncmp(server, qserver, len) == 0 && server[len] == '/') break; - } - if (server == NULL) + if (!server) { *errmsg = string_sprintf("%s server \"%s\" not found in %s", name, qserver, optionname); @@ -128,11 +103,73 @@ else } } - rc = (*fn)(ss+1, server, result, errmsg, &defer_break, do_cache); + if (is_tainted(server)) + { + *errmsg = string_sprintf("%s server \"%s\" is tainted", name, server); + return DEFER; + } + + rc = (*fn)(ss+1, server, result, errmsg, &defer_break, do_cache, opts); if (rc != DEFER || defer_break) return rc; } } +/* Handle queries that do not have server information at the start. */ + +else + { + const uschar * serverlist = NULL; + + /* If options are present, scan for a server definition. Default to + the "optserverlist" srgument. */ + + if (opts) + { + uschar * ele; + for (int sep = ','; ele = string_nextinlist(&opts, &sep, NULL, 0); ) + if (Ustrncmp(ele, "servers=", 8) == 0) + { serverlist = ele + 8; break; } + } + + if (!serverlist) + serverlist = optserverlist; + if (!serverlist) + *errmsg = string_sprintf("no %s servers defined (%s option)", name, + optionname); + else + for (int d = 0; (server = string_nextinlist(&serverlist, &d, NULL, 0)); ) + { + /* If not a full spec assume from options; scan main list for matching + hostname */ + + if (!Ustrchr(server, '/')) + { + int len = Ustrlen(server); + const uschar * slist = optserverlist; + uschar * ele; + for (int sep = 0; ele = string_nextinlist(&slist, &sep, NULL, 0); ) + if (Ustrncmp(ele, server, len) == 0 && ele[len] == '/') + break; + if (!ele) + { + *errmsg = string_sprintf("%s server \"%s\" not found in %s", name, + server, optionname); + return DEFER; + } + server = ele; + } + + if (is_tainted(server)) + { + *errmsg = string_sprintf("%s server \"%s\" is tainted", name, server); + return DEFER; + } + + rc = (*fn)(query, server, result, errmsg, &defer_break, do_cache, opts); + if (rc != DEFER || defer_break) return rc; + } + } + return DEFER; }