From 13b685f963e9313409f8350f718bac411829a5e7 Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Mon, 1 Aug 2005 13:20:28 +0000 Subject: [PATCH] Added support for SQLite. --- doc/doc-txt/ChangeLog | 4 +- doc/doc-txt/NewStuff | 27 ++++++- src/ACKNOWLEDGMENTS | 5 +- src/scripts/MakeLinks | 4 +- src/src/EDITME | 3 +- src/src/config.h.defaults | 3 +- src/src/drtables.c | 23 +++++- src/src/exim.c | 5 +- src/src/expand.c | 30 +++++-- src/src/lookups/Makefile | 7 +- src/src/lookups/README | 17 ++-- src/src/lookups/sqlite.c | 163 ++++++++++++++++++++++++++++++++++++++ src/src/lookups/sqlite.h | 18 +++++ src/src/macros.h | 3 +- src/src/match.c | 14 +++- src/src/verify.c | 25 ++++-- 16 files changed, 316 insertions(+), 35 deletions(-) create mode 100644 src/src/lookups/sqlite.c create mode 100644 src/src/lookups/sqlite.h diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 52519e9a0..2846c96b6 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.182 2005/07/23 20:59:16 tom Exp $ +$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.183 2005/08/01 13:20:28 ph10 Exp $ Change log file for Exim from version 4.21 ------------------------------------------- @@ -9,6 +9,8 @@ Exim version 4.53 TK/01 Added the "success_on_redirect" address verification option. See NewStuff for rationale and an example. +PH/01 Added support for SQLite, basic code supplied by David Woodhouse. + Exim version 4.52 ----------------- diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 4df98e9de..795944868 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -1,4 +1,4 @@ -$Cambridge: exim/doc/doc-txt/NewStuff,v 1.56 2005/07/27 18:27:55 fanf2 Exp $ +$Cambridge: exim/doc/doc-txt/NewStuff,v 1.57 2005/08/01 13:20:28 ph10 Exp $ New Features in Exim -------------------- @@ -22,6 +22,31 @@ TK/01 Added the "success_on_redirect" address verification option. When an In that case, verification will succeed when a router generates a new address. +PH/01 Support for SQLite database lookups has been added. This is another + query-style lookup, but it is slightly different from the others because + a file name is required in addition to the SQL query. This is because an + SQLite database is a single file and there is no daemon as in other SQL + databases. The interface to Exim requires the name of the file, as an + absolute path, to be given at the start of the query. It is separated + from the query by white space. This means that the path name cannot + contain white space. Here is a lookup expansion example: + + ${lookup sqlite {/some/thing/sqlitedb \ + select name from aliases where id='ph10';}} + + In a list, the syntax is similar. For example: + + domainlist relay_domains = sqlite;/some/thing/sqlitedb \ + select * from relays where ip='$sender_host_address'; + + The only character affected by the ${quote_sqlite: operator is a single + quote, which it doubles. + + Note that you must set LOOKUP_SQLITE=yes in Local/Makefile in order to + obtain SQLite support, and you will also need to add -lsqlite3 to the + EXTRALIBS setting. And of course, you have to install SQLite on your + host first. + Exim version 4.52 ----------------- diff --git a/src/ACKNOWLEDGMENTS b/src/ACKNOWLEDGMENTS index cd5a9a090..e8d3c7cf9 100644 --- a/src/ACKNOWLEDGMENTS +++ b/src/ACKNOWLEDGMENTS @@ -1,4 +1,4 @@ -$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.28 2005/06/28 08:49:38 ph10 Exp $ +$Cambridge: exim/src/ACKNOWLEDGMENTS,v 1.29 2005/08/01 13:20:28 ph10 Exp $ EXIM ACKNOWLEDGEMENTS @@ -20,7 +20,7 @@ relatively small patches. Philip Hazel Lists created: 20 November 2002 -Last updated: 28 June 2005 +Last updated: 29 July 2005 THE OLD LIST @@ -231,5 +231,6 @@ Joachim Wieland Patches for PostgreSQL socket support and other PostgreSQL functionality Patch for hosts_avoid_esmtp Stephen Wilcox Patch for ignore_enotdir problem +David Woodhouse SQLite support proof of concept code **** diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks index 2e24cb8d1..120a25b9d 100755 --- a/src/scripts/MakeLinks +++ b/src/scripts/MakeLinks @@ -1,5 +1,5 @@ #!/bin/sh -# $Cambridge: exim/src/scripts/MakeLinks,v 1.5 2005/06/15 08:57:10 ph10 Exp $ +# $Cambridge: exim/src/scripts/MakeLinks,v 1.6 2005/08/01 13:20:28 ph10 Exp $ # Script to build links for all the exim source files from the system- # specific build directory. It should be run from within that directory. @@ -84,6 +84,8 @@ ln -s ../../src/lookups/pgsql.h pgsql.h ln -s ../../src/lookups/pgsql.c pgsql.c ln -s ../../src/lookups/spf.h spf.h ln -s ../../src/lookups/spf.c spf.c +ln -s ../../src/lookups/sqlite.h sqlite.h +ln -s ../../src/lookups/sqlite.c sqlite.c ln -s ../../src/lookups/testdb.h testdb.h ln -s ../../src/lookups/testdb.c testdb.c ln -s ../../src/lookups/whoson.h whoson.h diff --git a/src/src/EDITME b/src/src/EDITME index 9be2b71bf..dc0892c99 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -1,4 +1,4 @@ -# $Cambridge: exim/src/src/EDITME,v 1.13 2005/07/23 20:19:41 tom Exp $ +# $Cambridge: exim/src/src/EDITME,v 1.14 2005/08/01 13:20:28 ph10 Exp $ ################################################## # The Exim mail transport agent # @@ -266,6 +266,7 @@ LOOKUP_LSEARCH=yes # LOOKUP_ORACLE=yes # LOOKUP_PASSWD=yes # LOOKUP_PGSQL=yes +# LOOKUP_SQLITE=yes # LOOKUP_WHOSON=yes # These two settings are obsolete; all three lookups are compiled when diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults index 2825f98c1..4991d6591 100644 --- a/src/src/config.h.defaults +++ b/src/src/config.h.defaults @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/config.h.defaults,v 1.6 2005/03/22 14:11:54 ph10 Exp $ */ +/* $Cambridge: exim/src/src/config.h.defaults,v 1.7 2005/08/01 13:20:28 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -78,6 +78,7 @@ in config.h unless some value is defined in Local/Makefile. */ #define LOOKUP_ORACLE #define LOOKUP_PASSWD #define LOOKUP_PGSQL +#define LOOKUP_SQLITE #define LOOKUP_TESTDB #define LOOKUP_WHOSON #define LOOKUP_WILDLSEARCH diff --git a/src/src/drtables.c b/src/src/drtables.c index e9084b2ac..ec7f52745 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/drtables.c,v 1.4 2005/05/25 20:07:55 tom Exp $ */ +/* $Cambridge: exim/src/src/drtables.c,v 1.5 2005/08/01 13:20:28 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -93,6 +93,10 @@ be NULL for methods that don't need them. */ #include "lookups/spf.h" #endif +#ifdef LOOKUP_SQLITE +#include "lookups/sqlite.h" +#endif + #ifdef LOOKUP_TESTDB #include "lookups/testdb.h" #endif @@ -458,6 +462,23 @@ Shares many functions with lsearch. */ #endif }, +/* sqlite lookup */ + + { + US"sqlite", /* lookup name */ + lookup_absfilequery, /* query-style lookup, starts with file name */ +#ifdef LOOKUP_SQLITE + sqlite_open, /* open function */ + NULL, /* no check function */ + sqlite_find, /* find function */ + sqlite_close, /* close function */ + NULL, /* no tidy function */ + sqlite_quote /* quoting function */ +#else + NULL, NULL, NULL, NULL, NULL, NULL /* lookup not present */ +#endif + }, + /* Testdb lookup is for testing Exim, not useful for normal running. For that reason, we omit the entry entirely when not building it into the binary, so that attempts to use it give "unknown lookup type" instead diff --git a/src/src/exim.c b/src/src/exim.c index 5cc0cb47c..98b01511d 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/exim.c,v 1.22 2005/06/28 10:23:35 ph10 Exp $ */ +/* $Cambridge: exim/src/src/exim.c,v 1.23 2005/08/01 13:20:28 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -918,6 +918,9 @@ fprintf(f, "Lookups:"); #ifdef LOOKUP_PGSQL fprintf(f, " pgsql"); #endif +#ifdef LOOKUP_SQLITE + fprintf(f, " sqlite"); +#endif #ifdef LOOKUP_TESTDB fprintf(f, " testdb"); #endif diff --git a/src/src/expand.c b/src/src/expand.c index 632b1d933..e4e0d21e8 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/expand.c,v 1.36 2005/06/27 14:29:43 ph10 Exp $ */ +/* $Cambridge: exim/src/src/expand.c,v 1.37 2005/08/01 13:20:28 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -3125,7 +3125,7 @@ while (*s != 0) /* Check that a key was provided for those lookup types that need it, and was not supplied for those that use the query style. */ - if (!mac_islookup(stype, lookup_querystyle)) + if (!mac_islookup(stype, lookup_querystyle|lookup_absfilequery)) { if (key == NULL) { @@ -3145,7 +3145,9 @@ while (*s != 0) } /* Get the next string in brackets and expand it. It is the file name for - single-key+file lookups, and the whole query otherwise. */ + single-key+file lookups, and the whole query otherwise. In the case of + queries that also require a file name (e.g. sqlite), the file name comes + first. */ if (*s != '{') goto EXPAND_FAILED_CURLY; filename = expand_string_internal(s+1, TRUE, &s, skipping); @@ -3154,12 +3156,30 @@ while (*s != 0) while (isspace(*s)) s++; /* If this isn't a single-key+file lookup, re-arrange the variables - to be appropriate for the search_ functions. */ + to be appropriate for the search_ functions. For query-style lookups, + there is just a "key", and no file name. For the special query-style + + file types, the query (i.e. "key") starts with a file name. */ if (key == NULL) { + while (isspace(*filename)) filename++; key = filename; - filename = NULL; + + if (mac_islookup(stype, lookup_querystyle)) + { + filename = NULL; + } + else + { + if (*filename != '/') + { + expand_string_message = string_sprintf( + "absolute file name expected for \"%s\" lookup", name); + goto EXPAND_FAILED; + } + while (*key != 0 && !isspace(*key)) key++; + if (*key != 0) *key++ = 0; + } } /* If skipping, don't do the next bit - just lookup_value == NULL, as if diff --git a/src/src/lookups/Makefile b/src/src/lookups/Makefile index 40301e0de..709ab143a 100644 --- a/src/src/lookups/Makefile +++ b/src/src/lookups/Makefile @@ -1,4 +1,4 @@ -# $Cambridge: exim/src/src/lookups/Makefile,v 1.3 2005/05/25 20:07:55 tom Exp $ +# $Cambridge: exim/src/src/lookups/Makefile,v 1.4 2005/08/01 13:20:28 ph10 Exp $ # Make file for building a library containing all the available lookups and # calling it lookups.a. This is called from the main make file, after cd'ing @@ -6,8 +6,8 @@ # defined, dummy modules get compiled. OBJ = cdb.o dbmdb.o dnsdb.o dsearch.o ibase.o ldap.o lsearch.o mysql.o nis.o \ - nisplus.o oracle.o passwd.o pgsql.o spf.o testdb.o whoson.o lf_check_file.o \ - lf_quote.o + nisplus.o oracle.o passwd.o pgsql.o spf.o sqlite.o testdb.o whoson.o \ + lf_check_file.o lf_quote.o lookups.a: $(OBJ) @/bin/rm -f lookups.a @@ -37,6 +37,7 @@ oracle.o: $(HDRS) oracle.c oracle.h passwd.o: $(HDRS) passwd.c passwd.h pgsql.o: $(HDRS) pgsql.c pgsql.h spf.o: $(HDRS) spf.c spf.h +sqlite.o: $(HDRS) sqlite.c sqlite.h testdb.o: $(HDRS) testdb.c testdb.h whoson.o: $(HDRS) whoson.c whoson.h diff --git a/src/src/lookups/README b/src/src/lookups/README index 7a16b83a2..cdaf308f3 100644 --- a/src/src/lookups/README +++ b/src/src/lookups/README @@ -1,4 +1,4 @@ -$Cambridge: exim/src/src/lookups/README,v 1.1 2004/10/07 13:10:01 ph10 Exp $ +$Cambridge: exim/src/src/lookups/README,v 1.2 2005/08/01 13:20:28 ph10 Exp $ LOOKUPS ------- @@ -26,11 +26,16 @@ key" style, where the key is associated with a "file name". For single key lookups, this means that the file name must be an absolute path. It is set for lsearch and dbm, but not for NIS, for example. -When a single-key lookup file is opened, the handle returned by the xxx_open() -function is saved, along with the file name and lookup type, in a tree. The -xxx_close() function is not called when the first lookup is completed. If there -are subsequent lookups of the same type that quote the same file name, -xxx_open() isn't called; instead the cached handle is re-used. + lookup_absfilequery + +This is a query-style lookup that must start with an absolute file name. For +example, the sqlite lookup is of this type. + +When a single-key or absfilequery lookup file is opened, the handle returned by +the xxx_open() function is saved, along with the file name and lookup type, in +a tree. The xxx_close() function is not called when the first lookup is +completed. If there are subsequent lookups of the same type that quote the same +file name, xxx_open() isn't called; instead the cached handle is re-used. Exim calls the function search_tidyup() at strategic points in its processing (e.g. after all routing and directing has been done) and this function walks diff --git a/src/src/lookups/sqlite.c b/src/src/lookups/sqlite.c new file mode 100644 index 000000000..af4c0eac6 --- /dev/null +++ b/src/src/lookups/sqlite.c @@ -0,0 +1,163 @@ +/* $Cambridge: exim/src/src/lookups/sqlite.c,v 1.1 2005/08/01 13:20:28 ph10 Exp $ */ + +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) University of Cambridge 1995 - 2005 */ +/* See the file NOTICE for conditions of use and distribution. */ + +#include "../exim.h" +#include "lf_functions.h" +#include "sqlite.h" + +#ifndef LOOKUP_SQLITE +static void dummy(int x) { dummy(x-1); } +#else +#include + + +/************************************************* +* Open entry point * +*************************************************/ + +/* See local README for interface description. */ + +void * +sqlite_open(uschar *filename, uschar **errmsg) +{ +sqlite3 *db = NULL; +int ret; + +ret = sqlite3_open((char *)filename, &db); +if (ret != 0) + { + *errmsg = (void *)sqlite3_errmsg(db); + debug_printf("Error opening database: %s\n", *errmsg); + } + +return db; +} + + +/************************************************* +* Find entry point * +*************************************************/ + +/* See local README for interface description. */ + +struct strbuf { + uschar *string; + int size; + int len; +}; + +static int sqlite_callback(void *arg, int argc, char **argv, char **azColName) +{ +struct strbuf *res = arg; +int i; + +/* For second and subsequent results, insert \n */ + +if (res->string != NULL) + res->string = string_cat(res->string, &res->size, &res->len, US"\n", 1); + +if (argc > 1) + { + /* For multiple fields, include the field name too */ + for (i = 0; i < argc; i++) + { + uschar *value = US((argv[i] != NULL)? argv[i]:""); + res->string = lf_quote(US azColName[i], value, Ustrlen(value), res->string, + &res->size, &res->len); + } + } + +else + { + res->string = string_append(res->string, &res->size, &res->len, 1, + (argv[0] != NULL)? argv[0]:""); + } + +res->string[res->len] = 0; +return 0; +} + + +int +sqlite_find(void *handle, uschar *filename, uschar *query, int length, + uschar **result, uschar **errmsg, BOOL *do_cache) +{ +int ret; +struct strbuf res = { NULL, 0, 0 }; + +ret = sqlite3_exec(handle, (char *)query, sqlite_callback, &res, (char **)errmsg); +if (ret != SQLITE_OK) + { + debug_printf("sqlite3_exec failed: %s\n", *errmsg); + return FAIL; + } + +if (res.string == NULL) *do_cache = FALSE; + +*result = res.string; +return OK; +} + + + +/************************************************* +* Close entry point * +*************************************************/ + +/* See local README for interface description. */ + +void sqlite_close(void *handle) +{ +sqlite3_close(handle); +} + + + +/************************************************* +* Quote entry point * +*************************************************/ + +/* From what I have found so far, the only character that needs to be quoted +for sqlite is the single quote, and it is quoted by doubling. + +Arguments: + s the string to be quoted + opt additional option text or NULL if none + +Returns: the processed string or NULL for a bad option +*/ + +uschar * +sqlite_quote(uschar *s, uschar *opt) +{ +register int c; +int count = 0; +uschar *t = s; +uschar *quoted; + +if (opt != NULL) return NULL; /* No options recognized */ + +while ((c = *t++) != 0) if (c == '\'') count++; + +if (count == 0) return s; +t = quoted = store_get(Ustrlen(s) + count + 1); + +while ((c = *s++) != 0) + { + if (c == '\'') *t++ = '\''; + *t++ = c; + } + +*t = 0; +return quoted; +} + +#endif /* LOOKUP_SQLITE */ + +/* End of lookups/sqlite.c */ diff --git a/src/src/lookups/sqlite.h b/src/src/lookups/sqlite.h new file mode 100644 index 000000000..3615f4fd6 --- /dev/null +++ b/src/src/lookups/sqlite.h @@ -0,0 +1,18 @@ +/* $Cambridge: exim/src/src/lookups/sqlite.h,v 1.1 2005/08/01 13:20:28 ph10 Exp $ */ + +/************************************************* +* Exim - an Internet mail transport agent * +*************************************************/ + +/* Copyright (c) University of Cambridge 1995 - 2005 */ +/* See the file NOTICE for conditions of use and distribution. */ + +/* Header for the sqlite lookup */ + +extern void *sqlite_open(uschar *, uschar **); +extern int sqlite_find(void *, uschar *, uschar *, int, uschar **, + uschar **, BOOL *); +extern void sqlite_close(void *); +extern uschar *sqlite_quote(uschar *, uschar *); + +/* End of lookups/sqlite.h */ diff --git a/src/src/macros.h b/src/src/macros.h index d4a09e875..432da931c 100644 --- a/src/src/macros.h +++ b/src/src/macros.h @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/macros.h,v 1.17 2005/07/23 20:46:42 tom Exp $ */ +/* $Cambridge: exim/src/src/macros.h,v 1.18 2005/08/01 13:20:28 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -629,6 +629,7 @@ enum { v_none, v_sender, v_recipient, v_expn }; #define lookup_querystyle 1 /* query-style lookup */ #define lookup_absfile 2 /* requires absolute file name */ +#define lookup_absfilequery 4 /* query-style starts with file name */ /* Status values for host_item blocks. Require hstatus_unusable and hstatus_unusable_expired to be last. */ diff --git a/src/src/match.c b/src/src/match.c index a957da30e..100e4c0cb 100644 --- a/src/src/match.c +++ b/src/src/match.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/match.c,v 1.7 2005/06/27 14:29:43 ph10 Exp $ */ +/* $Cambridge: exim/src/src/match.c,v 1.8 2005/08/01 13:20:28 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -266,12 +266,20 @@ up user@domain for sender rejection). There's a flag to disable it. */ if (!cb->use_partial) partial = -1; -/* Set the parameters for the two different kinds of lookup. */ +/* Set the parameters for the three different kinds of lookup. */ keyquery = semicolon + 1; while (isspace(*keyquery)) keyquery++; -if (!mac_islookup(search_type, lookup_querystyle)) +if (mac_islookup(search_type, lookup_absfilequery)) + { + filename = keyquery; + while (*keyquery != 0 && !isspace(*keyquery)) keyquery++; + filename = string_copyn(filename, keyquery - filename); + while (isspace(*keyquery)) keyquery++; + } + +else if (!mac_islookup(search_type, lookup_querystyle)) { filename = keyquery; keyquery = s; diff --git a/src/src/verify.c b/src/src/verify.c index c727177b5..5852aa293 100644 --- a/src/src/verify.c +++ b/src/src/verify.c @@ -1,4 +1,4 @@ -/* $Cambridge: exim/src/src/verify.c,v 1.23 2005/07/23 20:46:42 tom Exp $ */ +/* $Cambridge: exim/src/src/verify.c,v 1.24 2005/08/01 13:20:28 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * @@ -1938,13 +1938,22 @@ if (iplookup) if (search_type < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", search_error_message); - /* Adjust parameters for the type of lookup. For a query-style - lookup, there is no file name, and the "key" is just the query. For - a single-key lookup, the key is the current IP address, masked - appropriately, and reconverted to text form, with the mask appended. - For IPv6 addresses, specify dot separators instead of colons. */ + /* Adjust parameters for the type of lookup. For a query-style lookup, there + is no file name, and the "key" is just the query. For query-style with a file + name, we have to fish the file off the start of the query. For a single-key + lookup, the key is the current IP address, masked appropriately, and + reconverted to text form, with the mask appended. For IPv6 addresses, specify + dot separators instead of colons. */ - if (mac_islookup(search_type, lookup_querystyle)) + if (mac_islookup(search_type, lookup_absfilequery)) + { + filename = semicolon + 1; + key = filename; + while (*key != 0 && !isspace(*key)) key++; + filename = string_copyn(filename, key - filename); + while (isspace(*key)) key++; + } + else if (mac_islookup(search_type, lookup_querystyle)) { filename = NULL; key = semicolon + 1; @@ -2047,7 +2056,7 @@ if ((semicolon = Ustrchr(ss, ';')) != NULL) search_error_message, ss); return DEFER; } - isquery = mac_islookup(id, lookup_querystyle); + isquery = mac_islookup(id, lookup_querystyle|lookup_absfilequery); } if (isquery) -- 2.30.2