]> git.netwichtig.de Git - user/henk/code/exim.git/blob - src/src/lookups/oracle.c
dnssec_strict, _lax, _never modifiers for dnsdb lookups
[user/henk/code/exim.git] / src / src / lookups / oracle.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) University of Cambridge 1995 - 2009 */
6 /* See the file NOTICE for conditions of use and distribution. */
7
8 /* Interface to an Oracle database. This code was originally supplied by
9 Paul Kelly, but I have hacked it around for various reasons, and tried to add
10 some 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
28 understand why. The Oracle manual just asks for 256 bytes.
29
30 That was years ago. Jin Choi suggested (March 2007) that this change should
31 be made in the source, as at worst it wastes 256 bytes, and it saves people
32 having to discover about this for themselves as more and more systems are
33 64-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
51 typedef 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
62 typedef 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
72 typedef struct oracle_connection {
73   struct oracle_connection *next;
74   uschar *server;
75   struct cda_def *handle;
76   void   *hda_mem;
77 } oracle_connection;
78
79 static 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
91 Arguments:
92   oracle_handle   the handle of the connection
93   rc              the return code
94   msg             local text message
95 */
96
97 static uschar *
98 oracle_error(struct cda_def *oracle_handle, int rc, uschar *msg)
99 {
100 uschar tmp[1024];
101 oerhms(oracle_handle, rc, tmp, sizeof(tmp));
102 return 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
113 Arguments:
114   cda        the connection
115   def
116   desc       descriptions put here
117
118 Returns:     number of fields
119 */
120
121 static sword
122 describe_define(Cda_Def *cda, Ora_Define *def, Ora_Describe *desc)
123 {
124 sword col, deflen, deftyp;
125 static ub1 *defptr;
126 static sword numwidth = 8;
127
128 /* Describe the select-list items. */
129
130 for (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
187 return col;
188 }
189
190
191
192 /*************************************************
193 *              Open entry point                  *
194 *************************************************/
195
196 /* See local README for interface description. */
197
198 static void *
199 oracle_open(uschar *filename, uschar **errmsg)
200 {
201 return (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
212 static void
213 oracle_tidy(void)
214 {
215 oracle_connection *cn;
216 while ((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
231 single server.
232
233 Arguments:
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
240 The server string is of the form "host/dbname/user/password", for compatibility
241 with MySQL and pgsql, but at present, the dbname is not used. This string is in
242 a nextinlist temporary buffer, so can be overwritten.
243
244 Returns:       OK, FAIL, or DEFER
245 */
246
247 static int
248 perform_oracle_search(uschar *query, uschar *server, uschar **resultptr,
249   uschar **errmsg, BOOL *defer_break)
250 {
251 Cda_Def *cda = NULL;
252 struct cda_def *oracle_handle = NULL;
253 Ora_Describe *desc = NULL;
254 Ora_Define *def = NULL;
255 void *hda = NULL;
256
257 int i;
258 int ssize = 0;
259 int offset = 0;
260 int yield = DEFER;
261 unsigned int num_fields = 0;
262 uschar *result = NULL;
263 oracle_connection *cn = NULL;
264 uschar *server_copy = NULL;
265 uschar *sdata[4];
266 uschar tmp[1024];
267
268 /* Disaggregate the parameters from the server argument. The order is host,
269 database, user, password. We can write to the string, since it is in a
270 nextinlist temporary buffer. The copy of the string that is used for caching
271 has the password removed. This copy is also used for debugging output. */
272
273 for (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   }
286 sdata[0] = server;   /* What's left at the start */
287
288 /* If the database is the empty string, set it NULL - the query must then
289 define it. */
290
291 if (sdata[1][0] == 0) sdata[1] = NULL;
292
293 /* See if we have a cached connection to the server */
294
295 for (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
307 if (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
347 to obliterate the password because it is in a nextinlist temporary buffer. */
348
349 else
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
357 cda = store_get(sizeof(Cda_Def));
358
359 if (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
366 if (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
376 is one, we don't add field names to the data. Otherwise we do. */
377
378 def = store_get(sizeof(Ora_Define)*MAX_SELECT_LIST_SIZE);
379 desc = store_get(sizeof(Ora_Describe)*MAX_SELECT_LIST_SIZE);
380
381 if ((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
388 if (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
396 row, we insert '\n' between them. */
397
398 while (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.
469 Otherwise, we must terminate the string which has been built; string_cat()
470 always leaves enough room for a terminating zero. */
471
472 if (result == NULL)
473   {
474   yield = FAIL;
475   *errmsg = "ORACLE: no data found";
476   }
477 else
478   {
479   result[offset] = 0;
480   store_reset(result + offset + 1);
481   }
482
483 /* Get here by goto from various error checks. */
484
485 ORACLE_EXIT:
486
487 /* Close the cursor; don't close the connection, as it is cached. */
488
489 oclose(cda);
490
491 ORACLE_EXIT_NO_VALS:
492
493 /* Non-NULL result indicates a sucessful result */
494
495 if (result != NULL)
496   {
497   *resultptr = result;
498   return OK;
499   }
500 else
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
515 arguments are not used. Loop through a list of servers while the query is
516 deferred with a retryable error. */
517
518 static int
519 oracle_find(void *handle, uschar *filename, uschar *query, int length,
520   uschar **result, uschar **errmsg, BOOL *do_cache)
521 {
522 int sep = 0;
523 uschar *server;
524 uschar *list = oracle_servers;
525 uschar buffer[512];
526
527 do_cache = do_cache;   /* Placate picky compilers */
528
529 DEBUG(D_lookup) debug_printf("ORACLE query: %s\n", query);
530
531 while ((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
538 if (oracle_servers == NULL)
539   *errmsg = "no ORACLE servers defined (oracle_servers option)";
540
541 return 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,
551 tab, carriage return, backspace, backslash itself, and the quote characters.
552 Percent and underscore are not escaped. They are only special in contexts where
553 they can be wild cards, and this isn't usually the case for data inserted from
554 messages, since that isn't likely to be treated as a pattern of any kind.
555
556 Arguments:
557   s          the string to be quoted
558   opt        additional option text or NULL if none
559
560 Returns:     the processed string or NULL for a bad option
561 */
562
563 static uschar *
564 oracle_quote(uschar *s, uschar *opt)
565 {
566 register int c;
567 int count = 0;
568 uschar *t = s;
569 uschar *quoted;
570
571 if (opt != NULL) return NULL;    /* No options are recognized */
572
573 while ((c = *t++) != 0)
574   if (strchr("\n\t\r\b\'\"\\", c) != NULL) count++;
575
576 if (count == 0) return s;
577 t = quoted = store_get((int)strlen(s) + count + 1);
578
579 while ((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;
602 return quoted;
603 }
604
605
606 /*************************************************
607 *         Version reporting entry point          *
608 *************************************************/
609
610 /* See local README for interface description. */
611
612 #include "../version.h"
613
614 void
615 oracle_version_report(FILE *f)
616 {
617 #ifdef DYNLOOKUP
618 fprintf(f, "Library version: Oracle: Exim version %s\n", EXIM_VERSION_STR);
619 #endif
620 }
621
622
623 static 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 */
631   oracle_quote,                  /* quoting function */
632   oracle_version_report          /* version reporting */
633 };
634
635 #ifdef DYNLOOKUP
636 #define oracle_lookup_module_info _lookup_module_info
637 #endif
638
639 static lookup_info *_lookup_list[] = { &_lookup_info };
640 lookup_module_info oracle_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 };
641
642 /* End of lookups/oracle.c */