Commit | Line | Data |
---|---|---|
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 | |
20 | until one can be accessed. It is now also possible to provide the server data | |
21 | as part of the query. This function manages server selection and looping; each | |
22 | lookup has its own function for actually performing the lookup. | |
23 | ||
24 | Arguments: | |
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 | ||
34 | Returns: the return from the lookup function, or DEFER | |
35 | */ | |
36 | ||
37 | int | |
55414b25 JH |
38 | lf_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 | 43 | int rc; |
b7670459 | 44 | uschar *server; |
b7670459 PH |
45 | BOOL defer_break = FALSE; |
46 | ||
0b4dfe7a | 47 | DEBUG(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 | 51 | if (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 | ||
118 | else | |
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 |
172 | return DEFER; |
173 | } | |
174 | ||
175 | /* End of lf_sqlperform.c */ |