Expansions: acl expansion error detail
[exim.git] / src / src / lookups / oracle.c
CommitLineData
0756eb3c
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
8d6d5106 5/* Copyright (c) University of Cambridge 1995 - 2015 */
0756eb3c
PH
6/* See the file NOTICE for conditions of use and distribution. */
7
8/* Interface to an Oracle database. This code was originally supplied by
9Paul Kelly, but I have hacked it around for various reasons, and tried to add
10some comments from my position of Oracle ignorance. */
11
12
13#include "../exim.h"
14
15
0756eb3c
PH
16/* The Oracle system headers */
17
18#include <oratypes.h>
19#include <ocidfn.h>
20#include <ocikpr.h>
21
0756eb3c
PH
22#define PARSE_NO_DEFER 0 /* parse straight away */
23#define PARSE_V7_LNG 2
24#define MAX_ITEM_BUFFER_SIZE 1024 /* largest size of a cell of data */
25#define MAX_SELECT_LIST_SIZE 32 /* maximum number of columns (not rows!) */
26
27/* Paul's comment on this was "change this to 512 for 64bit cpu", but I don't
dee5a20a 28understand why. The Oracle manual just asks for 256 bytes.
0756eb3c 29
dee5a20a
PH
30That was years ago. Jin Choi suggested (March 2007) that this change should
31be made in the source, as at worst it wastes 256 bytes, and it saves people
32having to discover about this for themselves as more and more systems are
3364-bit. So I have changed 256 to 512. */
34
35#define HDA_SIZE 512
0756eb3c
PH
36
37/* Internal/external datatype codes */
38
39#define NUMBER_TYPE 2
40#define INT_TYPE 3
41#define FLOAT_TYPE 4
42#define STRING_TYPE 5
43#define ROWID_TYPE 11
44#define DATE_TYPE 12
45
46/* ORACLE error codes used in demonstration programs */
47
48#define VAR_NOT_IN_LIST 1007
49#define NO_DATA_FOUND 1403
50
51typedef struct Ora_Describe {
52 sb4 dbsize;
53 sb2 dbtype;
54 sb1 buf[MAX_ITEM_BUFFER_SIZE];
55 sb4 buflen;
56 sb4 dsize;
57 sb2 precision;
58 sb2 scale;
59 sb2 nullok;
60} Ora_Describe;
61
62typedef struct Ora_Define {
63 ub1 buf[MAX_ITEM_BUFFER_SIZE];
64 float flt_buf;
65 sword int_buf;
66 sb2 indp;
67 ub2 col_retlen, col_retcode;
68} Ora_Define;
69
70/* Structure and anchor for caching connections. */
71
72typedef struct oracle_connection {
73 struct oracle_connection *next;
74 uschar *server;
75 struct cda_def *handle;
76 void *hda_mem;
77} oracle_connection;
78
79static oracle_connection *oracle_connections = NULL;
80
81
82
83
84
85/*************************************************
86* Set up message after error *
87*************************************************/
88
89/* Sets up a message from a local string plus whatever Oracle gives.
90
91Arguments:
92 oracle_handle the handle of the connection
93 rc the return code
94 msg local text message
95*/
96
97static uschar *
98oracle_error(struct cda_def *oracle_handle, int rc, uschar *msg)
99{
100uschar tmp[1024];
101oerhms(oracle_handle, rc, tmp, sizeof(tmp));
102return string_sprintf("ORACLE %s: %s", msg, tmp);
103}
104
105
106
107/*************************************************
108* Describe and define the select list items *
109*************************************************/
110
111/* Figures out sizes, types, and numbers.
112
113Arguments:
114 cda the connection
115 def
116 desc descriptions put here
117
118Returns: number of fields
119*/
120
121static sword
122describe_define(Cda_Def *cda, Ora_Define *def, Ora_Describe *desc)
123{
124sword col, deflen, deftyp;
125static ub1 *defptr;
126static sword numwidth = 8;
127
128/* Describe the select-list items. */
129
130for (col = 0; col < MAX_SELECT_LIST_SIZE; col++)
131 {
132 desc[col].buflen = MAX_ITEM_BUFFER_SIZE;
133
134 if (odescr(cda, col + 1, &desc[col].dbsize,
135 &desc[col].dbtype, &desc[col].buf[0],
136 &desc[col].buflen, &desc[col].dsize,
137 &desc[col].precision, &desc[col].scale,
138 &desc[col].nullok) != 0)
139 {
140 /* Break on end of select list. */
141 if (cda->rc == VAR_NOT_IN_LIST) break; else return -1;
142 }
143
144 /* Adjust sizes and types for display, handling NUMBER with scale as float. */
145
146 if (desc[col].dbtype == NUMBER_TYPE)
147 {
148 desc[col].dbsize = numwidth;
149 if (desc[col].scale != 0)
150 {
151 defptr = (ub1 *)&def[col].flt_buf;
152 deflen = (sword) sizeof(float);
153 deftyp = FLOAT_TYPE;
154 desc[col].dbtype = FLOAT_TYPE;
155 }
156 else
157 {
158 defptr = (ub1 *)&def[col].int_buf;
159 deflen = (sword) sizeof(sword);
160 deftyp = INT_TYPE;
161 desc[col].dbtype = INT_TYPE;
162 }
163 }
164 else
165 {
166 if (desc[col].dbtype == DATE_TYPE)
167 desc[col].dbsize = 9;
168 if (desc[col].dbtype == ROWID_TYPE)
169 desc[col].dbsize = 18;
170 defptr = def[col].buf;
171 deflen = desc[col].dbsize > MAX_ITEM_BUFFER_SIZE ?
172 MAX_ITEM_BUFFER_SIZE : desc[col].dbsize + 1;
173 deftyp = STRING_TYPE;
174 desc[col].dbtype = STRING_TYPE;
175 }
176
177 /* Define an output variable */
178
179 if (odefin(cda, col + 1,
180 defptr, deflen, deftyp,
181 -1, &def[col].indp, (text *) 0, -1, -1,
182 &def[col].col_retlen,
183 &def[col].col_retcode) != 0)
184 return -1;
185 } /* Loop for each column */
186
187return col;
188}
189
190
191
192/*************************************************
193* Open entry point *
194*************************************************/
195
196/* See local README for interface description. */
197
e6d225ae 198static void *
0756eb3c
PH
199oracle_open(uschar *filename, uschar **errmsg)
200{
201return (void *)(1); /* Just return something non-null */
202}
203
204
205
206/*************************************************
207* Tidy entry point *
208*************************************************/
209
210/* See local README for interface description. */
211
e6d225ae 212static void
0756eb3c
PH
213oracle_tidy(void)
214{
215oracle_connection *cn;
216while ((cn = oracle_connections) != NULL)
217 {
218 oracle_connections = cn->next;
219 DEBUG(D_lookup) debug_printf("close ORACLE connection: %s\n", cn->server);
220 ologof(cn->handle);
221 }
222}
223
224
225
226/*************************************************
227* Internal search function *
228*************************************************/
229
230/* This function is called from the find entry point to do the search for a
231single server.
232
233Arguments:
234 query the query string
235 server the server string
236 resultptr where to store the result
237 errmsg where to point an error message
238 defer_break TRUE if no more servers are to be tried after DEFER
239
240The server string is of the form "host/dbname/user/password", for compatibility
241with MySQL and pgsql, but at present, the dbname is not used. This string is in
242a nextinlist temporary buffer, so can be overwritten.
243
244Returns: OK, FAIL, or DEFER
245*/
246
247static int
248perform_oracle_search(uschar *query, uschar *server, uschar **resultptr,
249 uschar **errmsg, BOOL *defer_break)
250{
251Cda_Def *cda = NULL;
252struct cda_def *oracle_handle = NULL;
253Ora_Describe *desc = NULL;
254Ora_Define *def = NULL;
255void *hda = NULL;
256
0756eb3c
PH
257int yield = DEFER;
258unsigned int num_fields = 0;
acec9514 259gstring * result = NULL;
0756eb3c
PH
260oracle_connection *cn = NULL;
261uschar *server_copy = NULL;
262uschar *sdata[4];
0756eb3c
PH
263
264/* Disaggregate the parameters from the server argument. The order is host,
265database, user, password. We can write to the string, since it is in a
266nextinlist temporary buffer. The copy of the string that is used for caching
267has the password removed. This copy is also used for debugging output. */
268
d7978c0f 269for (int i = 3; i > 0; i--)
0756eb3c
PH
270 {
271 uschar *pp = Ustrrchr(server, '/');
272 if (pp == NULL)
273 {
274 *errmsg = string_sprintf("incomplete ORACLE server data: %s", server);
275 *defer_break = TRUE;
276 return DEFER;
277 }
278 *pp++ = 0;
279 sdata[i] = pp;
280 if (i == 3) server_copy = string_copy(server); /* sans password */
281 }
282sdata[0] = server; /* What's left at the start */
283
284/* If the database is the empty string, set it NULL - the query must then
285define it. */
286
287if (sdata[1][0] == 0) sdata[1] = NULL;
288
289/* See if we have a cached connection to the server */
290
acec9514 291for (cn = oracle_connections; cn; cn = cn->next)
0756eb3c
PH
292 if (strcmp(cn->server, server_copy) == 0)
293 {
294 oracle_handle = cn->handle;
295 hda = cn->hda_mem;
296 break;
297 }
0756eb3c
PH
298
299/* If no cached connection, we must set one up */
300
acec9514 301if (!cn)
0756eb3c
PH
302 {
303 DEBUG(D_lookup) debug_printf("ORACLE new connection: host=%s database=%s "
304 "user=%s\n", sdata[0], sdata[1], sdata[2]);
305
306 /* Get store for a new connection, initialize it, and connect to the server */
307
308 oracle_handle = store_get(sizeof(struct cda_def));
309 hda = store_get(HDA_SIZE);
310 memset(hda,'\0',HDA_SIZE);
311
312 /*
313 * Perform a default (blocking) login
314 *
315 * sdata[0] = tnsname (service name - typically host name)
316 * sdata[1] = dbname - not used at present
317 * sdata[2] = username
318 * sdata[3] = passwd
319 */
320
321 if(olog(oracle_handle, hda, sdata[2], -1, sdata[3], -1, sdata[0], -1,
322 (ub4)OCI_LM_DEF) != 0)
323 {
324 *errmsg = oracle_error(oracle_handle, oracle_handle->rc,
325 US"connection failed");
326 *defer_break = FALSE;
327 goto ORACLE_EXIT_NO_VALS;
328 }
329
330 /* Add the connection to the cache */
331
332 cn = store_get(sizeof(oracle_connection));
333 cn->server = server_copy;
334 cn->handle = oracle_handle;
335 cn->next = oracle_connections;
336 cn->hda_mem = hda;
337 oracle_connections = cn;
338 }
339
340/* Else use a previously cached connection - we can write to the server string
341to obliterate the password because it is in a nextinlist temporary buffer. */
342
343else
344 {
345 DEBUG(D_lookup)
346 debug_printf("ORACLE using cached connection for %s\n", server_copy);
347 }
348
349/* We have a connection. Open a cursor and run the query */
350
351cda = store_get(sizeof(Cda_Def));
352
353if (oopen(cda, oracle_handle, (text *)0, -1, -1, (text *)0, -1) != 0)
354 {
355 *errmsg = oracle_error(oracle_handle, cda->rc, "failed to open cursor");
356 *defer_break = FALSE;
357 goto ORACLE_EXIT_NO_VALS;
358 }
359
360if (oparse(cda, (text *)query, (sb4) -1,
361 (sword)PARSE_NO_DEFER, (ub4)PARSE_V7_LNG) != 0)
362 {
363 *errmsg = oracle_error(oracle_handle, cda->rc, "query failed");
364 *defer_break = FALSE;
365 oclose(cda);
366 goto ORACLE_EXIT_NO_VALS;
367 }
368
369/* Find the number of fields returned and sort out their types. If the number
370is one, we don't add field names to the data. Otherwise we do. */
371
372def = store_get(sizeof(Ora_Define)*MAX_SELECT_LIST_SIZE);
373desc = store_get(sizeof(Ora_Describe)*MAX_SELECT_LIST_SIZE);
374
375if ((num_fields = describe_define(cda,def,desc)) == -1)
376 {
377 *errmsg = oracle_error(oracle_handle, cda->rc, "describe_define failed");
378 *defer_break = FALSE;
379 goto ORACLE_EXIT;
380 }
381
382if (oexec(cda)!=0)
383 {
384 *errmsg = oracle_error(oracle_handle, cda->rc, "oexec failed");
385 *defer_break = FALSE;
386 goto ORACLE_EXIT;
387 }
388
389/* Get the fields and construct the result string. If there is more than one
390row, we insert '\n' between them. */
391
392while (cda->rc != NO_DATA_FOUND) /* Loop for each row */
393 {
394 ofetch(cda);
395 if(cda->rc == NO_DATA_FOUND) break;
396
acec9514 397 if (result) result = string_catn(result, "\n", 1);
0756eb3c
PH
398
399 /* Single field - just add on the data */
400
401 if (num_fields == 1)
acec9514 402 result = string_catn(result, def[0].buf, def[0].col_retlen);
0756eb3c
PH
403
404 /* Multiple fields - precede by file name, removing {lead,trail}ing WS */
405
d7978c0f 406 else for (int i = 0; i < num_fields; i++)
0756eb3c
PH
407 {
408 int slen;
409 uschar *s = US desc[i].buf;
410
411 while (*s != 0 && isspace(*s)) s++;
412 slen = Ustrlen(s);
413 while (slen > 0 && isspace(s[slen-1])) slen--;
acec9514
JH
414 result = string_catn(result, s, slen);
415 result = string_catn(result, US"=", 1);
0756eb3c 416
aded2255 417 /* int and float type won't ever need escaping. Otherwise, quote the value
0756eb3c
PH
418 if it contains spaces or is empty. */
419
420 if (desc[i].dbtype != INT_TYPE && desc[i].dbtype != FLOAT_TYPE &&
421 (def[i].buf[0] == 0 || strchr(def[i].buf, ' ') != NULL))
422 {
acec9514 423 result = string_catn(result, "\"", 1);
d7978c0f 424 for (int j = 0; j < def[i].col_retlen; j++)
0756eb3c
PH
425 {
426 if (def[i].buf[j] == '\"' || def[i].buf[j] == '\\')
acec9514
JH
427 result = string_catn(result, "\\", 1);
428 result = string_catn(result, def[i].buf+j, 1);
0756eb3c 429 }
acec9514 430 result = string_catn(result, "\"", 1);
0756eb3c
PH
431 }
432
433 else switch(desc[i].dbtype)
434 {
435 case INT_TYPE:
acec9514
JH
436 result = string_cat(result, string_sprintf("%d", def[i].int_buf));
437 break;
0756eb3c
PH
438
439 case FLOAT_TYPE:
acec9514
JH
440 result = string_cat(result, string_sprintf("%f", def[i].flt_buf));
441 break;
0756eb3c
PH
442
443 case STRING_TYPE:
acec9514
JH
444 result = string_catn(result, def[i].buf, def[i].col_retlen);
445 break;
0756eb3c
PH
446
447 default:
acec9514
JH
448 *errmsg = string_sprintf("ORACLE: unknown field type %d", desc[i].dbtype);
449 *defer_break = FALSE;
450 result = NULL;
451 goto ORACLE_EXIT;
0756eb3c
PH
452 }
453
acec9514 454 result = string_catn(result, " ", 1);
0756eb3c
PH
455 }
456 }
457
458/* If result is NULL then no data has been found and so we return FAIL.
459Otherwise, we must terminate the string which has been built; string_cat()
460always leaves enough room for a terminating zero. */
461
acec9514 462if (!result)
0756eb3c
PH
463 {
464 yield = FAIL;
465 *errmsg = "ORACLE: no data found";
466 }
467else
acec9514 468 store_reset(result->s + result->ptr + 1);
0756eb3c
PH
469
470/* Get here by goto from various error checks. */
471
472ORACLE_EXIT:
473
474/* Close the cursor; don't close the connection, as it is cached. */
475
476oclose(cda);
477
478ORACLE_EXIT_NO_VALS:
479
4c04137d 480/* Non-NULL result indicates a successful result */
0756eb3c 481
acec9514 482if (result)
0756eb3c 483 {
acec9514 484 *resultptr = string_from_gstring(result);
0756eb3c
PH
485 return OK;
486 }
487else
488 {
489 DEBUG(D_lookup) debug_printf("%s\n", *errmsg);
490 return yield; /* FAIL or DEFER */
491 }
492}
493
494
495
496
497/*************************************************
498* Find entry point *
499*************************************************/
500
501/* See local README for interface description. The handle and filename
502arguments are not used. Loop through a list of servers while the query is
503deferred with a retryable error. */
504
e6d225ae 505static int
0756eb3c 506oracle_find(void *handle, uschar *filename, uschar *query, int length,
14b3c5bc 507 uschar **result, uschar **errmsg, uint *do_cache)
0756eb3c
PH
508{
509int sep = 0;
510uschar *server;
511uschar *list = oracle_servers;
512uschar buffer[512];
513
514do_cache = do_cache; /* Placate picky compilers */
515
516DEBUG(D_lookup) debug_printf("ORACLE query: %s\n", query);
517
518while ((server = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
519 {
520 BOOL defer_break;
521 int rc = perform_oracle_search(query, server, result, errmsg, &defer_break);
522 if (rc != DEFER || defer_break) return rc;
523 }
524
525if (oracle_servers == NULL)
526 *errmsg = "no ORACLE servers defined (oracle_servers option)";
527
528return DEFER;
529}
530
531
532
533/*************************************************
534* Quote entry point *
535*************************************************/
536
537/* The only characters that need to be quoted (with backslash) are newline,
538tab, carriage return, backspace, backslash itself, and the quote characters.
539Percent and underscore are not escaped. They are only special in contexts where
540they can be wild cards, and this isn't usually the case for data inserted from
541messages, since that isn't likely to be treated as a pattern of any kind.
542
543Arguments:
544 s the string to be quoted
545 opt additional option text or NULL if none
546
547Returns: the processed string or NULL for a bad option
548*/
549
e6d225ae 550static uschar *
0756eb3c
PH
551oracle_quote(uschar *s, uschar *opt)
552{
553register int c;
554int count = 0;
555uschar *t = s;
556uschar *quoted;
557
558if (opt != NULL) return NULL; /* No options are recognized */
559
560while ((c = *t++) != 0)
561 if (strchr("\n\t\r\b\'\"\\", c) != NULL) count++;
562
563if (count == 0) return s;
564t = quoted = store_get((int)strlen(s) + count + 1);
565
566while ((c = *s++) != 0)
567 {
568 if (strchr("\n\t\r\b\'\"\\", c) != NULL)
569 {
570 *t++ = '\\';
571 switch(c)
572 {
573 case '\n': *t++ = 'n';
574 break;
575 case '\t': *t++ = 't';
576 break;
577 case '\r': *t++ = 'r';
578 break;
579 case '\b': *t++ = 'b';
580 break;
581 default: *t++ = c;
582 break;
583 }
584 }
585 else *t++ = c;
586 }
587
588*t = 0;
589return quoted;
590}
591
6545de78
PP
592
593/*************************************************
594* Version reporting entry point *
595*************************************************/
596
597/* See local README for interface description. */
598
599#include "../version.h"
600
601void
602oracle_version_report(FILE *f)
603{
604#ifdef DYNLOOKUP
605fprintf(f, "Library version: Oracle: Exim version %s\n", EXIM_VERSION_STR);
606#endif
607}
608
609
e6d225ae
DW
610static lookup_info _lookup_info = {
611 US"oracle", /* lookup name */
612 lookup_querystyle, /* query-style lookup */
613 oracle_open, /* open function */
614 NULL, /* check function */
615 oracle_find, /* find function */
616 NULL, /* no close function */
617 oracle_tidy, /* tidy function */
6545de78
PP
618 oracle_quote, /* quoting function */
619 oracle_version_report /* version reporting */
e6d225ae
DW
620};
621
622#ifdef DYNLOOKUP
623#define oracle_lookup_module_info _lookup_module_info
624#endif
625
626static lookup_info *_lookup_list[] = { &_lookup_info };
627lookup_module_info oracle_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 };
0756eb3c
PH
628
629/* End of lookups/oracle.c */