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