Copyright updates:
[exim.git] / src / src / lookups / lf_sqlperform.c
CommitLineData
b7670459
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
f9ba5e22 5/* Copyright (c) University of Cambridge 1995 - 2018 */
1e1ddfac 6/* Copyright (c) The Exim Maintainers 2020 */
b7670459
PH
7/* See the file NOTICE for conditions of use and distribution. */
8
9
10#include "../exim.h"
11#include "lf_functions.h"
12
13
14
15/*************************************************
16* Call SQL server(s) to run an actual query *
17*************************************************/
18
19/* All the SQL lookups are of the same form, with a list of servers to try
20until one can be accessed. It is now also possible to provide the server data
21as part of the query. This function manages server selection and looping; each
22lookup has its own function for actually performing the lookup.
23
24Arguments:
25 name the lookup name, e.g. "MySQL"
26 optionname the name of the servers option, e.g. "mysql_servers"
27 optserverlist the value of the servers option
28 query the query
29 result where to pass back the result
30 errmsg where to pass back an error message
14b3c5bc 31 do_cache to be set zero if data is changed
b7670459
PH
32 func the lookup function to call
33
34Returns: the return from the lookup function, or DEFER
35*/
36
37int
55414b25
JH
38lf_sqlperform(const uschar *name, const uschar *optionname,
39 const uschar *optserverlist, const uschar *query,
0b4dfe7a
JH
40 uschar **result, uschar **errmsg, uint *do_cache, const uschar * opts,
41 int(*fn)(const uschar *, uschar *, uschar **, uschar **, BOOL *, uint *, const uschar *))
b7670459 42{
0b4dfe7a 43int rc;
b7670459 44uschar *server;
b7670459
PH
45BOOL defer_break = FALSE;
46
0b4dfe7a 47DEBUG(D_lookup) debug_printf_indent("%s query: \"%s\" opts '%s'\n", name, query, opts);
b7670459
PH
48
49/* Handle queries that do have server information at the start. */
50
0b4dfe7a 51if (Ustrncmp(query, "servers", 7) == 0)
b7670459 52 {
0b4dfe7a 53 int qsep = 0;
55414b25
JH
54 const uschar *s, *ss;
55 const uschar *qserverlist;
b7670459 56 uschar *qserver;
b7670459
PH
57
58 s = query + 7;
0b4dfe7a 59 skip_whitespace(&s);
b7670459
PH
60 if (*s++ != '=')
61 {
62 *errmsg = string_sprintf("missing = after \"servers\" in %s lookup", name);
63 return DEFER;
64 }
0b4dfe7a 65 skip_whitespace(&s);
b7670459
PH
66
67 ss = Ustrchr(s, ';');
0b4dfe7a 68 if (!ss)
b7670459
PH
69 {
70 *errmsg = string_sprintf("missing ; after \"servers=\" in %s lookup",
71 name);
72 return DEFER;
73 }
74
75 if (ss == s)
76 {
77 *errmsg = string_sprintf("\"servers=\" defines no servers in \"%s\"",
78 query);
79 return DEFER;
80 }
81
bb07bcd3 82 qserverlist = string_sprintf("%.*s", (int)(ss - s), s);
b7670459 83
0b4dfe7a 84 while ((qserver = string_nextinlist(&qserverlist, &qsep, NULL, 0)))
b7670459 85 {
0b4dfe7a 86 if (Ustrchr(qserver, '/'))
b7670459
PH
87 server = qserver;
88 else
89 {
90 int len = Ustrlen(qserver);
0b4dfe7a 91 const uschar * serverlist = optserverlist;
b7670459 92
0b4dfe7a 93 for (int sep = 0; server = string_nextinlist(&serverlist, &sep, NULL, 0);)
b7670459
PH
94 if (Ustrncmp(server, qserver, len) == 0 && server[len] == '/')
95 break;
b7670459 96
0b4dfe7a 97 if (!server)
b7670459
PH
98 {
99 *errmsg = string_sprintf("%s server \"%s\" not found in %s", name,
100 qserver, optionname);
101 return DEFER;
102 }
103 }
104
0b4dfe7a
JH
105 if (is_tainted(server))
106 {
107 *errmsg = string_sprintf("%s server \"%s\" is tainted", name, server);
108 return DEFER;
109 }
110
111 rc = (*fn)(ss+1, server, result, errmsg, &defer_break, do_cache, opts);
b7670459
PH
112 if (rc != DEFER || defer_break) return rc;
113 }
114 }
115
0b4dfe7a
JH
116/* Handle queries that do not have server information at the start. */
117
118else
119 {
120 const uschar * serverlist = NULL;
121
122 /* If options are present, scan for a server definition. Default to
123 the "optserverlist" srgument. */
124
125 if (opts)
126 {
127 uschar * ele;
128 for (int sep = ','; ele = string_nextinlist(&opts, &sep, NULL, 0); )
129 if (Ustrncmp(ele, "servers=", 8) == 0)
130 { serverlist = ele + 8; break; }
131 }
132
133 if (!serverlist)
134 serverlist = optserverlist;
135 if (!serverlist)
136 *errmsg = string_sprintf("no %s servers defined (%s option)", name,
137 optionname);
138 else
139 for (int d = 0; (server = string_nextinlist(&serverlist, &d, NULL, 0)); )
140 {
141 /* If not a full spec assume from options; scan main list for matching
142 hostname */
143
144 if (!Ustrchr(server, '/'))
145 {
146 int len = Ustrlen(server);
147 const uschar * slist = optserverlist;
148 uschar * ele;
149 for (int sep = 0; ele = string_nextinlist(&slist, &sep, NULL, 0); )
150 if (Ustrncmp(ele, server, len) == 0 && ele[len] == '/')
151 break;
152 if (!ele)
153 {
154 *errmsg = string_sprintf("%s server \"%s\" not found in %s", name,
155 server, optionname);
156 return DEFER;
157 }
158 server = ele;
159 }
160
161 if (is_tainted(server))
162 {
163 *errmsg = string_sprintf("%s server \"%s\" is tainted", name, server);
164 return DEFER;
165 }
166
167 rc = (*fn)(query, server, result, errmsg, &defer_break, do_cache, opts);
168 if (rc != DEFER || defer_break) return rc;
169 }
170 }
171
b7670459
PH
172return DEFER;
173}
174
175/* End of lf_sqlperform.c */