Lookups: per-searchtype options framework
[exim.git] / src / src / lookups / dsearch.c
1 /*************************************************
2 *     Exim - an Internet mail transport agent    *
3 *************************************************/
4
5 /* Copyright (c) University of Cambridge 1995 - 2015 */
6 /* See the file NOTICE for conditions of use and distribution. */
7
8 /* The idea for this code came from Matthew Byng-Maddick, but his original has
9 been heavily reworked a lot for Exim 4 (and it now uses stat() (more precisely:
10 lstat()) rather than a directory scan). */
11
12
13 #include "../exim.h"
14 #include "lf_functions.h"
15
16
17
18 /*************************************************
19 *              Open entry point                  *
20 *************************************************/
21
22 /* See local README for interface description. We open the directory to test
23 whether it exists and whether it is searchable. However, we don't need to keep
24 it open, because the "search" can be done by a call to lstat() rather than
25 actually scanning through the list of files. */
26
27 static void *
28 dsearch_open(const uschar * dirname, uschar ** errmsg)
29 {
30 DIR * dp = exim_opendir(dirname);
31 if (!dp)
32   {
33   int save_errno = errno;
34   *errmsg = string_open_failed(errno, "%s for directory search", dirname);
35   errno = save_errno;
36   return NULL;
37   }
38 closedir(dp);
39 return (void *)(-1);
40 }
41
42
43 /*************************************************
44 *             Check entry point                  *
45 *************************************************/
46
47 /* The handle will always be (void *)(-1), but don't try casting it to an
48 integer as this gives warnings on 64-bit systems. */
49
50 static BOOL
51 dsearch_check(void * handle, const uschar * filename, int modemask,
52   uid_t * owners, gid_t * owngroups, uschar ** errmsg)
53 {
54 handle = handle;
55 if (*filename == '/')
56   return lf_check_file(-1, filename, S_IFDIR, modemask, owners, owngroups,
57     "dsearch", errmsg) == 0;
58 *errmsg = string_sprintf("dirname '%s' for dsearch is not absolute", filename);
59 return FALSE;
60 }
61
62
63 /*************************************************
64 *              Find entry point                  *
65 *************************************************/
66
67 /* See local README for interface description. We use lstat() instead of
68 scanning the directory, as it is hopefully faster to let the OS do the scanning
69 for us. */
70
71 static int
72 dsearch_find(void * handle, const uschar * dirname, const uschar * keystring,
73   int length, uschar ** result, uschar ** errmsg, uint * do_cache,
74   const uschar * opts)
75 {
76 struct stat statbuf;
77 int save_errno;
78 uschar * filename;
79
80 handle = handle;  /* Keep picky compilers happy */
81 length = length;
82 do_cache = do_cache;
83
84 if (Ustrchr(keystring, '/') != 0)
85   {
86   *errmsg = string_sprintf("key for dsearch lookup contains a slash: %s",
87     keystring);
88   return DEFER;
89   }
90
91 filename = string_sprintf("%s/%s", dirname, keystring);
92 if (Ulstat(filename, &statbuf) >= 0)
93   {
94   /* Since the filename exists in the filesystem, we can return a
95   non-tainted result. */
96   *result = string_copy_taint(keystring, FALSE);
97   return OK;
98   }
99
100 if (errno == ENOENT) return FAIL;
101
102 save_errno = errno;
103 *errmsg = string_sprintf("%s: lstat failed", filename);
104 errno = save_errno;
105 return DEFER;
106 }
107
108
109 /*************************************************
110 *              Close entry point                 *
111 *************************************************/
112
113 /* See local README for interface description */
114
115 void
116 static dsearch_close(void *handle)
117 {
118 handle = handle;   /* Avoid compiler warning */
119 }
120
121
122 /*************************************************
123 *         Version reporting entry point          *
124 *************************************************/
125
126 /* See local README for interface description. */
127
128 #include "../version.h"
129
130 void
131 dsearch_version_report(FILE *f)
132 {
133 #ifdef DYNLOOKUP
134 fprintf(f, "Library version: dsearch: Exim version %s\n", EXIM_VERSION_STR);
135 #endif
136 }
137
138
139 static lookup_info _lookup_info = {
140   US"dsearch",                   /* lookup name */
141   lookup_absfile,                /* uses absolute file name */
142   dsearch_open,                  /* open function */
143   dsearch_check,                 /* check function */
144   dsearch_find,                  /* find function */
145   dsearch_close,                 /* close function */
146   NULL,                          /* no tidy function */
147   NULL,                          /* no quoting function */
148   dsearch_version_report         /* version reporting */
149 };
150
151 #ifdef DYNLOOKUP
152 #define dsearch_lookup_module_info _lookup_module_info
153 #endif
154
155 static lookup_info *_lookup_list[] = { &_lookup_info };
156 lookup_module_info dsearch_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 };
157
158 /* End of lookups/dsearch.c */