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