DNS: time-limit cached returns, using TTL. Bug 1395
[exim.git] / src / src / lookups / oracle.c
CommitLineData
0756eb3c
PH
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
0a49a7a4 5/* Copyright (c) University of Cambridge 1995 - 2009 */
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
257int i;
258int ssize = 0;
259int offset = 0;
260int yield = DEFER;
261unsigned int num_fields = 0;
262uschar *result = NULL;
263oracle_connection *cn = NULL;
264uschar *server_copy = NULL;
265uschar *sdata[4];
266uschar tmp[1024];
267
268/* Disaggregate the parameters from the server argument. The order is host,
269database, user, password. We can write to the string, since it is in a
270nextinlist temporary buffer. The copy of the string that is used for caching
271has the password removed. This copy is also used for debugging output. */
272
273for (i = 3; i > 0; i--)
274 {
275 uschar *pp = Ustrrchr(server, '/');
276 if (pp == NULL)
277 {
278 *errmsg = string_sprintf("incomplete ORACLE server data: %s", server);
279 *defer_break = TRUE;
280 return DEFER;
281 }
282 *pp++ = 0;
283 sdata[i] = pp;
284 if (i == 3) server_copy = string_copy(server); /* sans password */
285 }
286sdata[0] = server; /* What's left at the start */
287
288/* If the database is the empty string, set it NULL - the query must then
289define it. */
290
291if (sdata[1][0] == 0) sdata[1] = NULL;
292
293/* See if we have a cached connection to the server */
294
295for (cn = oracle_connections; cn != NULL; cn = cn->next)
296 {
297 if (strcmp(cn->server, server_copy) == 0)
298 {
299 oracle_handle = cn->handle;
300 hda = cn->hda_mem;
301 break;
302 }
303 }
304
305/* If no cached connection, we must set one up */
306
307if (cn == NULL)
308 {
309 DEBUG(D_lookup) debug_printf("ORACLE new connection: host=%s database=%s "
310 "user=%s\n", sdata[0], sdata[1], sdata[2]);
311
312 /* Get store for a new connection, initialize it, and connect to the server */
313
314 oracle_handle = store_get(sizeof(struct cda_def));
315 hda = store_get(HDA_SIZE);
316 memset(hda,'\0',HDA_SIZE);
317
318 /*
319 * Perform a default (blocking) login
320 *
321 * sdata[0] = tnsname (service name - typically host name)
322 * sdata[1] = dbname - not used at present
323 * sdata[2] = username
324 * sdata[3] = passwd
325 */
326
327 if(olog(oracle_handle, hda, sdata[2], -1, sdata[3], -1, sdata[0], -1,
328 (ub4)OCI_LM_DEF) != 0)
329 {
330 *errmsg = oracle_error(oracle_handle, oracle_handle->rc,
331 US"connection failed");
332 *defer_break = FALSE;
333 goto ORACLE_EXIT_NO_VALS;
334 }
335
336 /* Add the connection to the cache */
337
338 cn = store_get(sizeof(oracle_connection));
339 cn->server = server_copy;
340 cn->handle = oracle_handle;
341 cn->next = oracle_connections;
342 cn->hda_mem = hda;
343 oracle_connections = cn;
344 }
345
346/* Else use a previously cached connection - we can write to the server string
347to obliterate the password because it is in a nextinlist temporary buffer. */
348
349else
350 {
351 DEBUG(D_lookup)
352 debug_printf("ORACLE using cached connection for %s\n", server_copy);
353 }
354
355/* We have a connection. Open a cursor and run the query */
356
357cda = store_get(sizeof(Cda_Def));
358
359if (oopen(cda, oracle_handle, (text *)0, -1, -1, (text *)0, -1) != 0)
360 {
361 *errmsg = oracle_error(oracle_handle, cda->rc, "failed to open cursor");
362 *defer_break = FALSE;
363 goto ORACLE_EXIT_NO_VALS;
364 }
365
366if (oparse(cda, (text *)query, (sb4) -1,
367 (sword)PARSE_NO_DEFER, (ub4)PARSE_V7_LNG) != 0)
368 {
369 *errmsg = oracle_error(oracle_handle, cda->rc, "query failed");
370 *defer_break = FALSE;
371 oclose(cda);
372 goto ORACLE_EXIT_NO_VALS;
373 }
374
375/* Find the number of fields returned and sort out their types. If the number
376is one, we don't add field names to the data. Otherwise we do. */
377
378def = store_get(sizeof(Ora_Define)*MAX_SELECT_LIST_SIZE);
379desc = store_get(sizeof(Ora_Describe)*MAX_SELECT_LIST_SIZE);
380
381if ((num_fields = describe_define(cda,def,desc)) == -1)
382 {
383 *errmsg = oracle_error(oracle_handle, cda->rc, "describe_define failed");
384 *defer_break = FALSE;
385 goto ORACLE_EXIT;
386 }
387
388if (oexec(cda)!=0)
389 {
390 *errmsg = oracle_error(oracle_handle, cda->rc, "oexec failed");
391 *defer_break = FALSE;
392 goto ORACLE_EXIT;
393 }
394
395/* Get the fields and construct the result string. If there is more than one
396row, we insert '\n' between them. */
397
398while (cda->rc != NO_DATA_FOUND) /* Loop for each row */
399 {
400 ofetch(cda);
401 if(cda->rc == NO_DATA_FOUND) break;
402
403 if (result != NULL) result = string_cat(result, &ssize, &offset, "\n", 1);
404
405 /* Single field - just add on the data */
406
407 if (num_fields == 1)
408 result = string_cat(result, &ssize, &offset, def[0].buf, def[0].col_retlen);
409
410 /* Multiple fields - precede by file name, removing {lead,trail}ing WS */
411
412 else for (i = 0; i < num_fields; i++)
413 {
414 int slen;
415 uschar *s = US desc[i].buf;
416
417 while (*s != 0 && isspace(*s)) s++;
418 slen = Ustrlen(s);
419 while (slen > 0 && isspace(s[slen-1])) slen--;
420 result = string_cat(result, &ssize, &offset, s, slen);
421 result = string_cat(result, &ssize, &offset, US"=", 1);
422
423 /* int and float type wont ever need escaping. Otherwise, quote the value
424 if it contains spaces or is empty. */
425
426 if (desc[i].dbtype != INT_TYPE && desc[i].dbtype != FLOAT_TYPE &&
427 (def[i].buf[0] == 0 || strchr(def[i].buf, ' ') != NULL))
428 {
429 int j;
430 result = string_cat(result, &ssize, &offset, "\"", 1);
431 for (j = 0; j < def[i].col_retlen; j++)
432 {
433 if (def[i].buf[j] == '\"' || def[i].buf[j] == '\\')
434 result = string_cat(result, &ssize, &offset, "\\", 1);
435 result = string_cat(result, &ssize, &offset, def[i].buf+j, 1);
436 }
437 result = string_cat(result, &ssize, &offset, "\"", 1);
438 }
439
440 else switch(desc[i].dbtype)
441 {
442 case INT_TYPE:
443 sprintf(CS tmp, "%d", def[i].int_buf);
444 result = string_cat(result, &ssize, &offset, tmp, Ustrlen(tmp));
445 break;
446
447 case FLOAT_TYPE:
448 sprintf(CS tmp, "%f", def[i].flt_buf);
449 result = string_cat(result, &ssize, &offset, tmp, Ustrlen(tmp));
450 break;
451
452 case STRING_TYPE:
453 result = string_cat(result, &ssize, &offset, def[i].buf,
454 def[i].col_retlen);
455 break;
456
457 default:
458 *errmsg = string_sprintf("ORACLE: unknown field type %d", desc[i].dbtype);
459 *defer_break = FALSE;
460 result = NULL;
461 goto ORACLE_EXIT;
462 }
463
464 result = string_cat(result, &ssize, &offset, " ", 1);
465 }
466 }
467
468/* If result is NULL then no data has been found and so we return FAIL.
469Otherwise, we must terminate the string which has been built; string_cat()
470always leaves enough room for a terminating zero. */
471
472if (result == NULL)
473 {
474 yield = FAIL;
475 *errmsg = "ORACLE: no data found";
476 }
477else
478 {
479 result[offset] = 0;
480 store_reset(result + offset + 1);
481 }
482
483/* Get here by goto from various error checks. */
484
485ORACLE_EXIT:
486
487/* Close the cursor; don't close the connection, as it is cached. */
488
489oclose(cda);
490
491ORACLE_EXIT_NO_VALS:
492
493/* Non-NULL result indicates a sucessful result */
494
495if (result != NULL)
496 {
497 *resultptr = result;
498 return OK;
499 }
500else
501 {
502 DEBUG(D_lookup) debug_printf("%s\n", *errmsg);
503 return yield; /* FAIL or DEFER */
504 }
505}
506
507
508
509
510/*************************************************
511* Find entry point *
512*************************************************/
513
514/* See local README for interface description. The handle and filename
515arguments are not used. Loop through a list of servers while the query is
516deferred with a retryable error. */
517
e6d225ae 518static int
0756eb3c 519oracle_find(void *handle, uschar *filename, uschar *query, int length,
14b3c5bc 520 uschar **result, uschar **errmsg, uint *do_cache)
0756eb3c
PH
521{
522int sep = 0;
523uschar *server;
524uschar *list = oracle_servers;
525uschar buffer[512];
526
527do_cache = do_cache; /* Placate picky compilers */
528
529DEBUG(D_lookup) debug_printf("ORACLE query: %s\n", query);
530
531while ((server = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
532 {
533 BOOL defer_break;
534 int rc = perform_oracle_search(query, server, result, errmsg, &defer_break);
535 if (rc != DEFER || defer_break) return rc;
536 }
537
538if (oracle_servers == NULL)
539 *errmsg = "no ORACLE servers defined (oracle_servers option)";
540
541return DEFER;
542}
543
544
545
546/*************************************************
547* Quote entry point *
548*************************************************/
549
550/* The only characters that need to be quoted (with backslash) are newline,
551tab, carriage return, backspace, backslash itself, and the quote characters.
552Percent and underscore are not escaped. They are only special in contexts where
553they can be wild cards, and this isn't usually the case for data inserted from
554messages, since that isn't likely to be treated as a pattern of any kind.
555
556Arguments:
557 s the string to be quoted
558 opt additional option text or NULL if none
559
560Returns: the processed string or NULL for a bad option
561*/
562
e6d225ae 563static uschar *
0756eb3c
PH
564oracle_quote(uschar *s, uschar *opt)
565{
566register int c;
567int count = 0;
568uschar *t = s;
569uschar *quoted;
570
571if (opt != NULL) return NULL; /* No options are recognized */
572
573while ((c = *t++) != 0)
574 if (strchr("\n\t\r\b\'\"\\", c) != NULL) count++;
575
576if (count == 0) return s;
577t = quoted = store_get((int)strlen(s) + count + 1);
578
579while ((c = *s++) != 0)
580 {
581 if (strchr("\n\t\r\b\'\"\\", c) != NULL)
582 {
583 *t++ = '\\';
584 switch(c)
585 {
586 case '\n': *t++ = 'n';
587 break;
588 case '\t': *t++ = 't';
589 break;
590 case '\r': *t++ = 'r';
591 break;
592 case '\b': *t++ = 'b';
593 break;
594 default: *t++ = c;
595 break;
596 }
597 }
598 else *t++ = c;
599 }
600
601*t = 0;
602return quoted;
603}
604
6545de78
PP
605
606/*************************************************
607* Version reporting entry point *
608*************************************************/
609
610/* See local README for interface description. */
611
612#include "../version.h"
613
614void
615oracle_version_report(FILE *f)
616{
617#ifdef DYNLOOKUP
618fprintf(f, "Library version: Oracle: Exim version %s\n", EXIM_VERSION_STR);
619#endif
620}
621
622
e6d225ae
DW
623static lookup_info _lookup_info = {
624 US"oracle", /* lookup name */
625 lookup_querystyle, /* query-style lookup */
626 oracle_open, /* open function */
627 NULL, /* check function */
628 oracle_find, /* find function */
629 NULL, /* no close function */
630 oracle_tidy, /* tidy function */
6545de78
PP
631 oracle_quote, /* quoting function */
632 oracle_version_report /* version reporting */
e6d225ae
DW
633};
634
635#ifdef DYNLOOKUP
636#define oracle_lookup_module_info _lookup_module_info
637#endif
638
639static lookup_info *_lookup_list[] = { &_lookup_info };
640lookup_module_info oracle_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 };
0756eb3c
PH
641
642/* End of lookups/oracle.c */