1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) The Exim Maintainers 2020 - 2024 */
6 /* Copyright (c) University of Cambridge 1995 - 2018 */
7 /* See the file NOTICE for conditions of use and distribution. */
8 /* SPDX-License-Identifier: GPL-2.0-or-later */
12 #include "lf_functions.h"
16 /*************************************************
17 * Call SQL server(s) to run an actual query *
18 *************************************************/
20 /* All the SQL lookups are of the same form, with a list of servers to try
21 until one can be accessed. It is now also possible to provide the server data
22 as part of the query. This function manages server selection and looping; each
23 lookup has its own function for actually performing the lookup.
26 name the lookup name, e.g. "MySQL"
27 optionname the name of the servers option, e.g. "mysql_servers"
28 optserverlist the value of the servers option
30 result where to pass back the result
31 errmsg where to pass back an error message
32 do_cache to be set zero if data is changed
33 func the lookup function to call
35 Returns: the return from the lookup function, or DEFER
39 lf_sqlperform(const uschar *name, const uschar *optionname,
40 const uschar *optserverlist, const uschar *query,
41 uschar **result, uschar **errmsg, uint *do_cache, const uschar * opts,
42 int(*fn)(const uschar *, uschar *, uschar **, uschar **, BOOL *, uint *, const uschar *))
46 BOOL defer_break = FALSE;
48 DEBUG(D_lookup) debug_printf_indent("%s query: \"%s\" opts '%s'\n", name, query, opts);
50 /* Handle queries that do have server information at the start. */
52 if (Ustrncmp(query, "servers", 7) == 0)
56 const uschar *qserverlist;
59 log_write(0, LOG_MAIN|LOG_CONFIG_IN, "WARNING: obslete syntax used for lookup\n");
65 *errmsg = string_sprintf("missing = after \"servers\" in %s lookup", name);
73 *errmsg = string_sprintf("missing ; after \"servers=\" in %s lookup",
80 *errmsg = string_sprintf("\"servers=\" defines no servers in \"%s\"",
85 qserverlist = string_sprintf("%.*s", (int)(ss - s), s);
87 while ((qserver = string_nextinlist(&qserverlist, &qsep, NULL, 0)))
89 if (Ustrchr(qserver, '/'))
93 int len = Ustrlen(qserver);
94 const uschar * serverlist = optserverlist;
96 for (int sep = 0; server = string_nextinlist(&serverlist, &sep, NULL, 0);)
97 if (Ustrncmp(server, qserver, len) == 0 && server[len] == '/')
102 *errmsg = string_sprintf("%s server \"%s\" not found in %s", name,
103 qserver, optionname);
108 if (is_tainted(server))
110 *errmsg = string_sprintf("%s server \"%s\" is tainted", name, server);
114 rc = (*fn)(ss+1, server, result, errmsg, &defer_break, do_cache, opts);
115 if (rc != DEFER || defer_break) return rc;
119 /* Handle queries that do not have server information at the start. */
123 const uschar * serverlist = NULL;
125 /* If options are present, scan for a server definition. Default to
126 the "optserverlist" srgument. */
131 for (int sep = ','; ele = string_nextinlist(&opts, &sep, NULL, 0); )
132 if (Ustrncmp(ele, "servers=", 8) == 0)
133 { serverlist = ele + 8; break; }
137 serverlist = optserverlist;
139 *errmsg = string_sprintf("no %s servers defined (%s option)", name,
142 for (int d = 0; (server = string_nextinlist(&serverlist, &d, NULL, 0)); )
144 /* If not a full spec assume from options; scan main list for matching
147 if (!Ustrchr(server, '/'))
149 int len = Ustrlen(server);
150 const uschar * slist = optserverlist;
152 for (int sep = 0; ele = string_nextinlist(&slist, &sep, NULL, 0); )
153 if (Ustrncmp(ele, server, len) == 0 && ele[len] == '/')
157 *errmsg = string_sprintf("%s server \"%s\" not found in %s", name,
164 if (is_tainted(server))
166 *errmsg = string_sprintf("%s server \"%s\" is tainted", name, server);
170 rc = (*fn)(query, server, result, errmsg, &defer_break, do_cache, opts);
171 if (rc != DEFER || defer_break) return rc;
178 /* End of lf_sqlperform.c */