1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) University of Cambridge 1995 - 2015 */
6 /* Copyright (c) The Exim Maintainers 2020 */
7 /* See the file NOTICE for conditions of use and distribution. */
9 /* Interface to an Oracle database. This code was originally supplied by
10 Paul Kelly, but I have hacked it around for various reasons, and tried to add
11 some comments from my position of Oracle ignorance. */
17 /* The Oracle system headers */
23 #define PARSE_NO_DEFER 0 /* parse straight away */
24 #define PARSE_V7_LNG 2
25 #define MAX_ITEM_BUFFER_SIZE 1024 /* largest size of a cell of data */
26 #define MAX_SELECT_LIST_SIZE 32 /* maximum number of columns (not rows!) */
28 /* Paul's comment on this was "change this to 512 for 64bit cpu", but I don't
29 understand why. The Oracle manual just asks for 256 bytes.
31 That was years ago. Jin Choi suggested (March 2007) that this change should
32 be made in the source, as at worst it wastes 256 bytes, and it saves people
33 having to discover about this for themselves as more and more systems are
34 64-bit. So I have changed 256 to 512. */
38 /* Internal/external datatype codes */
47 /* ORACLE error codes used in demonstration programs */
49 #define VAR_NOT_IN_LIST 1007
50 #define NO_DATA_FOUND 1403
52 typedef struct Ora_Describe {
55 sb1 buf[MAX_ITEM_BUFFER_SIZE];
63 typedef struct Ora_Define {
64 ub1 buf[MAX_ITEM_BUFFER_SIZE];
68 ub2 col_retlen, col_retcode;
71 /* Structure and anchor for caching connections. */
73 typedef struct oracle_connection {
74 struct oracle_connection *next;
76 struct cda_def *handle;
80 static oracle_connection *oracle_connections = NULL;
86 /*************************************************
87 * Set up message after error *
88 *************************************************/
90 /* Sets up a message from a local string plus whatever Oracle gives.
93 oracle_handle the handle of the connection
95 msg local text message
99 oracle_error(struct cda_def *oracle_handle, int rc, uschar *msg)
102 oerhms(oracle_handle, rc, tmp, sizeof(tmp));
103 return string_sprintf("ORACLE %s: %s", msg, tmp);
108 /*************************************************
109 * Describe and define the select list items *
110 *************************************************/
112 /* Figures out sizes, types, and numbers.
117 desc descriptions put here
119 Returns: number of fields
123 describe_define(Cda_Def *cda, Ora_Define *def, Ora_Describe *desc)
125 sword col, deflen, deftyp;
127 static sword numwidth = 8;
129 /* Describe the select-list items. */
131 for (col = 0; col < MAX_SELECT_LIST_SIZE; col++)
133 desc[col].buflen = MAX_ITEM_BUFFER_SIZE;
135 if (odescr(cda, col + 1, &desc[col].dbsize,
136 &desc[col].dbtype, &desc[col].buf[0],
137 &desc[col].buflen, &desc[col].dsize,
138 &desc[col].precision, &desc[col].scale,
139 &desc[col].nullok) != 0)
141 /* Break on end of select list. */
142 if (cda->rc == VAR_NOT_IN_LIST) break; else return -1;
145 /* Adjust sizes and types for display, handling NUMBER with scale as float. */
147 if (desc[col].dbtype == NUMBER_TYPE)
149 desc[col].dbsize = numwidth;
150 if (desc[col].scale != 0)
152 defptr = (ub1 *)&def[col].flt_buf;
153 deflen = (sword) sizeof(float);
155 desc[col].dbtype = FLOAT_TYPE;
159 defptr = (ub1 *)&def[col].int_buf;
160 deflen = (sword) sizeof(sword);
162 desc[col].dbtype = INT_TYPE;
167 if (desc[col].dbtype == DATE_TYPE)
168 desc[col].dbsize = 9;
169 if (desc[col].dbtype == ROWID_TYPE)
170 desc[col].dbsize = 18;
171 defptr = def[col].buf;
172 deflen = desc[col].dbsize > MAX_ITEM_BUFFER_SIZE ?
173 MAX_ITEM_BUFFER_SIZE : desc[col].dbsize + 1;
174 deftyp = STRING_TYPE;
175 desc[col].dbtype = STRING_TYPE;
178 /* Define an output variable */
180 if (odefin(cda, col + 1,
181 defptr, deflen, deftyp,
182 -1, &def[col].indp, (text *) 0, -1, -1,
183 &def[col].col_retlen,
184 &def[col].col_retcode) != 0)
186 } /* Loop for each column */
193 /*************************************************
195 *************************************************/
197 /* See local README for interface description. */
200 oracle_open(const uschar * filename, uschar ** errmsg)
202 return (void *)(1); /* Just return something non-null */
207 /*************************************************
209 *************************************************/
211 /* See local README for interface description. */
216 oracle_connection *cn;
217 while ((cn = oracle_connections) != NULL)
219 oracle_connections = cn->next;
220 DEBUG(D_lookup) debug_printf_indent("close ORACLE connection: %s\n", cn->server);
227 /*************************************************
228 * Internal search function *
229 *************************************************/
231 /* This function is called from the find entry point to do the search for a
235 query the query string
236 server the server string
237 resultptr where to store the result
238 errmsg where to point an error message
239 defer_break TRUE if no more servers are to be tried after DEFER
241 The server string is of the form "host/dbname/user/password", for compatibility
242 with MySQL and pgsql, but at present, the dbname is not used. This string is in
243 a nextinlist temporary buffer, so can be overwritten.
245 Returns: OK, FAIL, or DEFER
249 perform_oracle_search(uschar *query, uschar *server, uschar **resultptr,
250 uschar **errmsg, BOOL *defer_break)
253 struct cda_def *oracle_handle = NULL;
254 Ora_Describe *desc = NULL;
255 Ora_Define *def = NULL;
259 unsigned int num_fields = 0;
260 gstring * result = NULL;
261 oracle_connection *cn = NULL;
262 uschar *server_copy = NULL;
265 /* Disaggregate the parameters from the server argument. The order is host,
266 database, user, password. We can write to the string, since it is in a
267 nextinlist temporary buffer. The copy of the string that is used for caching
268 has the password removed. This copy is also used for debugging output. */
270 for (int i = 3; i > 0; i--)
272 uschar *pp = Ustrrchr(server, '/');
275 *errmsg = string_sprintf("incomplete ORACLE server data: %s", server);
281 if (i == 3) server_copy = string_copy(server); /* sans password */
283 sdata[0] = server; /* What's left at the start */
285 /* If the database is the empty string, set it NULL - the query must then
288 if (sdata[1][0] == 0) sdata[1] = NULL;
290 /* See if we have a cached connection to the server */
292 for (cn = oracle_connections; cn; cn = cn->next)
293 if (strcmp(cn->server, server_copy) == 0)
295 oracle_handle = cn->handle;
300 /* If no cached connection, we must set one up */
304 DEBUG(D_lookup) debug_printf_indent("ORACLE new connection: host=%s database=%s "
305 "user=%s\n", sdata[0], sdata[1], sdata[2]);
307 /* Get store for a new connection, initialize it, and connect to the server */
309 oracle_handle = store_get(sizeof(struct cda_def), FALSE);
310 hda = store_get(HDA_SIZE, FALSE);
311 memset(hda,'\0',HDA_SIZE);
314 * Perform a default (blocking) login
316 * sdata[0] = tnsname (service name - typically host name)
317 * sdata[1] = dbname - not used at present
318 * sdata[2] = username
322 if(olog(oracle_handle, hda, sdata[2], -1, sdata[3], -1, sdata[0], -1,
323 (ub4)OCI_LM_DEF) != 0)
325 *errmsg = oracle_error(oracle_handle, oracle_handle->rc,
326 US"connection failed");
327 *defer_break = FALSE;
328 goto ORACLE_EXIT_NO_VALS;
331 /* Add the connection to the cache */
333 cn = store_get(sizeof(oracle_connection), FALSE);
334 cn->server = server_copy;
335 cn->handle = oracle_handle;
336 cn->next = oracle_connections;
338 oracle_connections = cn;
341 /* Else use a previously cached connection - we can write to the server string
342 to obliterate the password because it is in a nextinlist temporary buffer. */
347 debug_printf_indent("ORACLE using cached connection for %s\n", server_copy);
350 /* We have a connection. Open a cursor and run the query */
352 cda = store_get(sizeof(Cda_Def), FALSE);
354 if (oopen(cda, oracle_handle, (text *)0, -1, -1, (text *)0, -1) != 0)
356 *errmsg = oracle_error(oracle_handle, cda->rc, "failed to open cursor");
357 *defer_break = FALSE;
358 goto ORACLE_EXIT_NO_VALS;
361 if (oparse(cda, (text *)query, (sb4) -1,
362 (sword)PARSE_NO_DEFER, (ub4)PARSE_V7_LNG) != 0)
364 *errmsg = oracle_error(oracle_handle, cda->rc, "query failed");
365 *defer_break = FALSE;
367 goto ORACLE_EXIT_NO_VALS;
370 /* Find the number of fields returned and sort out their types. If the number
371 is one, we don't add field names to the data. Otherwise we do. */
373 def = store_get(sizeof(Ora_Define)*MAX_SELECT_LIST_SIZE, FALSE);
374 desc = store_get(sizeof(Ora_Describe)*MAX_SELECT_LIST_SIZE, FALSE);
376 if ((num_fields = describe_define(cda,def,desc)) == -1)
378 *errmsg = oracle_error(oracle_handle, cda->rc, "describe_define failed");
379 *defer_break = FALSE;
385 *errmsg = oracle_error(oracle_handle, cda->rc, "oexec failed");
386 *defer_break = FALSE;
390 /* Get the fields and construct the result string. If there is more than one
391 row, we insert '\n' between them. */
393 while (cda->rc != NO_DATA_FOUND) /* Loop for each row */
396 if(cda->rc == NO_DATA_FOUND) break;
398 if (result) result = string_catn(result, "\n", 1);
400 /* Single field - just add on the data */
403 result = string_catn(result, def[0].buf, def[0].col_retlen);
405 /* Multiple fields - precede by file name, removing {lead,trail}ing WS */
407 else for (int i = 0; i < num_fields; i++)
410 uschar *s = US desc[i].buf;
412 while (*s != 0 && isspace(*s)) s++;
414 while (slen > 0 && isspace(s[slen-1])) slen--;
415 result = string_catn(result, s, slen);
416 result = string_catn(result, US"=", 1);
418 /* int and float type won't ever need escaping. Otherwise, quote the value
419 if it contains spaces or is empty. */
421 if (desc[i].dbtype != INT_TYPE && desc[i].dbtype != FLOAT_TYPE &&
422 (def[i].buf[0] == 0 || strchr(def[i].buf, ' ') != NULL))
424 result = string_catn(result, "\"", 1);
425 for (int j = 0; j < def[i].col_retlen; j++)
427 if (def[i].buf[j] == '\"' || def[i].buf[j] == '\\')
428 result = string_catn(result, "\\", 1);
429 result = string_catn(result, def[i].buf+j, 1);
431 result = string_catn(result, "\"", 1);
434 else switch(desc[i].dbtype)
437 result = string_cat(result, string_sprintf("%d", def[i].int_buf));
441 result = string_cat(result, string_sprintf("%f", def[i].flt_buf));
445 result = string_catn(result, def[i].buf, def[i].col_retlen);
449 *errmsg = string_sprintf("ORACLE: unknown field type %d", desc[i].dbtype);
450 *defer_break = FALSE;
455 result = string_catn(result, " ", 1);
459 /* If result is NULL then no data has been found and so we return FAIL.
460 Otherwise, we must terminate the string which has been built; string_cat()
461 always leaves enough room for a terminating zero. */
466 *errmsg = "ORACLE: no data found";
469 gstring_release_unused(result);
471 /* Get here by goto from various error checks. */
475 /* Close the cursor; don't close the connection, as it is cached. */
481 /* Non-NULL result indicates a successful result */
485 *resultptr = string_from_gstring(result);
490 DEBUG(D_lookup) debug_printf_indent("%s\n", *errmsg);
491 return yield; /* FAIL or DEFER */
498 /*************************************************
500 *************************************************/
502 /* See local README for interface description. The handle and filename
503 arguments are not used. Loop through a list of servers while the query is
504 deferred with a retryable error. */
507 oracle_find(void * handle, const uschar * filename, uschar * query, int length,
508 uschar ** result, uschar ** errmsg, uint * do_cache, const uschar * opts)
512 uschar *list = oracle_servers;
514 do_cache = do_cache; /* Placate picky compilers */
516 DEBUG(D_lookup) debug_printf_indent("ORACLE query: %s\n", query);
518 while ((server = string_nextinlist(&list, &sep, NULL, 0)))
521 int rc = perform_oracle_search(query, server, result, errmsg, &defer_break);
522 if (rc != DEFER || defer_break) return rc;
526 *errmsg = "no ORACLE servers defined (oracle_servers option)";
533 /*************************************************
534 * Quote entry point *
535 *************************************************/
537 /* The only characters that need to be quoted (with backslash) are newline,
538 tab, carriage return, backspace, backslash itself, and the quote characters.
539 Percent and underscore are not escaped. They are only special in contexts where
540 they can be wild cards, and this isn't usually the case for data inserted from
541 messages, since that isn't likely to be treated as a pattern of any kind.
544 s the string to be quoted
545 opt additional option text or NULL if none
547 Returns: the processed string or NULL for a bad option
551 oracle_quote(uschar *s, uschar *opt)
558 if (opt != NULL) return NULL; /* No options are recognized */
560 while ((c = *t++) != 0)
561 if (strchr("\n\t\r\b\'\"\\", c) != NULL) count++;
563 if (count == 0) return s;
564 t = quoted = store_get((int)strlen(s) + count + 1, is_tainted(s));
566 while ((c = *s++) != 0)
568 if (strchr("\n\t\r\b\'\"\\", c) != NULL)
573 case '\n': *t++ = 'n';
575 case '\t': *t++ = 't';
577 case '\r': *t++ = 'r';
579 case '\b': *t++ = 'b';
593 /*************************************************
594 * Version reporting entry point *
595 *************************************************/
597 /* See local README for interface description. */
599 #include "../version.h"
602 oracle_version_report(FILE *f)
605 fprintf(f, "Library version: Oracle: Exim version %s\n", EXIM_VERSION_STR);
610 static lookup_info _lookup_info = {
611 .name = US"oracle", /* lookup name */
612 .type = lookup_querystyle, /* query-style lookup */
613 .open = oracle_open, /* open function */
614 .check = NULL, /* check function */
615 .find = oracle_find, /* find function */
616 .close = NULL, /* no close function */
617 .tidy = oracle_tidy, /* tidy function */
618 .quote = oracle_quote, /* quoting function */
619 .version_report = oracle_version_report /* version reporting */
623 #define oracle_lookup_module_info _lookup_module_info
626 static lookup_info *_lookup_list[] = { &_lookup_info };
627 lookup_module_info oracle_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 };
629 /* End of lookups/oracle.c */