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"
17 server_len_for_logging(const uschar * server)
19 const uschar * s = Ustrchr(server, '/');
21 if (!(s = Ustrchr(s+1, '/'))) return 64;
22 return (int) (s - server);
25 /*************************************************
26 * Call SQL server(s) to run an actual query *
27 *************************************************/
29 /* All the SQL lookups are of the same form, with a list of servers to try
30 until one can be accessed. It is now also possible to provide the server data
31 as part of the query. This function manages server selection and looping; each
32 lookup has its own function for actually performing the lookup.
35 name the lookup name, e.g. "MySQL"
36 optionname the name of the servers option, e.g. "mysql_servers"
37 optserverlist the value of the servers option
39 result where to pass back the result
40 errmsg where to pass back an error message
41 do_cache to be set zero if data is changed
42 opts options (which suffixed the lookup name, minus cache-control ones) or NULL
43 func the lookup function to call
45 Returns: the return from the lookup function, or DEFER
49 lf_sqlperform(const uschar *name, const uschar *optionname,
50 const uschar *optserverlist, const uschar *query,
51 uschar **result, uschar **errmsg, uint *do_cache, const uschar * opts,
52 int(*fn)(const uschar *, uschar *, uschar **, uschar **, BOOL *, uint *, const uschar *))
56 BOOL defer_break = FALSE;
58 DEBUG(D_lookup) debug_printf_indent("%s query: \"%s\" opts '%s'\n", name, query, opts);
60 /* Handle queries that do have server information at the start (old style). */
62 if (Ustrncmp(query, "servers", 7) == 0)
65 const uschar * s, * ss, * qserverlist;
67 log_write(0, LOG_MAIN|LOG_CONFIG_IN, "WARNING: obsolete syntax used for lookup");
73 *errmsg = string_sprintf("missing = after \"servers\" in %s lookup", name);
81 *errmsg = string_sprintf("missing ; after \"servers=\" in %s lookup",
88 *errmsg = string_sprintf("\"servers=\" defines no servers in \"%s\"",
93 qserverlist = string_sprintf("%.*s", (int)(ss - s), s);
96 for (uschar * qsrv; qsrv = string_nextinlist(&qserverlist, &qsep, NULL, 0); )
98 if (Ustrchr(qsrv, '/'))
99 server = qsrv; /* full server spec */
101 { /* only name; search in option list */
102 int len = Ustrlen(qsrv);
103 const uschar * serverlist = optserverlist;
105 for (int sep = 0; server = string_nextinlist(&serverlist, &sep, NULL, 0);)
106 if (Ustrncmp(server, qsrv, len) == 0 && server[len] == '/')
111 *errmsg = string_sprintf("%s server \"%.*s\" not found in %s",
112 name, server_len_for_logging(qsrv), qsrv, optionname);
117 if (is_tainted(server))
119 *errmsg = string_sprintf("%s server \"%.*s\" is tainted",
120 name, server_len_for_logging(server), server);
124 rc = (*fn)(query, server, result, errmsg, &defer_break, do_cache, opts);
125 if (rc != DEFER || defer_break) return rc;
129 /* Handle queries that do not have server information at the start. */
133 const uschar * serverlist = NULL;
135 /* If options are present, scan for a server definition. Default to
136 the "optserverlist" srgument. */
141 for (int sep = ','; ele = string_nextinlist(&opts, &sep, NULL, 0); )
142 if (Ustrncmp(ele, "servers=", 8) == 0)
143 { serverlist = ele + 8; break; }
147 serverlist = optserverlist;
149 *errmsg = string_sprintf("no %s servers defined (%s option)", name,
152 for (int d = 0; server = string_nextinlist(&serverlist, &d, NULL, 0); )
154 /* If not a full spec assume from options; scan main list for matching
157 if (!Ustrchr(server, '/'))
159 int len = Ustrlen(server);
160 const uschar * slist = optserverlist;
162 for (int sep = 0; ele = string_nextinlist(&slist, &sep, NULL, 0); )
163 if (Ustrncmp(ele, server, len) == 0 && ele[len] == '/')
167 *errmsg = string_sprintf("%s server \"%s\" not found in %s", name,
174 if (is_tainted(server))
176 *errmsg = string_sprintf("%s server \"%.*s\" is tainted",
177 name, server_len_for_logging(server), server);
181 rc = (*fn)(query, server, result, errmsg, &defer_break, do_cache, opts);
182 if (rc != DEFER || defer_break) return rc;
189 /* End of lf_sqlperform.c */