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