~ubuntu-branches/ubuntu/natty/exim4/natty-updates

« back to all changes in this revision

Viewing changes to src/lookups/lsearch.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Bienia
  • Date: 2010-01-01 16:28:19 UTC
  • mfrom: (2.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20100101162819-htn71my7yj4v1vkr
Tags: 4.71-3ubuntu1
* Merge with Debian unstable (lp: #501657). Remaining changes:
  + debian/patches/71_exiq_grep_error_on_messages_without_size.dpatch:
    Improve handling of broken messages when "exim4 -bp" (mailq) reports
    lines without size info.
  + Don't declare a Provides: default-mta; in Ubuntu, we want postfix to be
    the default.
  + debian/control: Change build dependencies to MySQL 5.1.
  + debian/{control,rules}: add and enable hardened build for PIE
    (Debian bug 542726).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Cambridge: exim/exim-src/src/lookups/lsearch.c,v 1.11 2009/11/16 19:50:38 nm4 Exp $ */
 
2
 
 
3
/*************************************************
 
4
*     Exim - an Internet mail transport agent    *
 
5
*************************************************/
 
6
 
 
7
/* Copyright (c) University of Cambridge 1995 - 2009 */
 
8
/* See the file NOTICE for conditions of use and distribution. */
 
9
 
 
10
#include "../exim.h"
 
11
#include "lf_functions.h"
 
12
#include "lsearch.h"
 
13
 
 
14
/* Codes for the different kinds of lsearch that are supported */
 
15
 
 
16
enum {
 
17
  LSEARCH_PLAIN,        /* Literal keys */
 
18
  LSEARCH_WILD,         /* Wild card keys, expanded */
 
19
  LSEARCH_NWILD,        /* Wild card keys, not expanded */
 
20
  LSEARCH_IP            /* IP addresses and networks */
 
21
};
 
22
 
 
23
 
 
24
 
 
25
/*************************************************
 
26
*              Open entry point                  *
 
27
*************************************************/
 
28
 
 
29
/* See local README for interface description */
 
30
 
 
31
void *
 
32
lsearch_open(uschar *filename, uschar **errmsg)
 
33
{
 
34
FILE *f = Ufopen(filename, "rb");
 
35
if (f == NULL)
 
36
  {
 
37
  int save_errno = errno;
 
38
  *errmsg = string_open_failed(errno, "%s for linear search", filename);
 
39
  errno = save_errno;
 
40
  return NULL;
 
41
  }
 
42
return f;
 
43
}
 
44
 
 
45
 
 
46
 
 
47
/*************************************************
 
48
*             Check entry point                  *
 
49
*************************************************/
 
50
 
 
51
BOOL
 
52
lsearch_check(void *handle, uschar *filename, int modemask, uid_t *owners,
 
53
  gid_t *owngroups, uschar **errmsg)
 
54
{
 
55
return lf_check_file(fileno((FILE *)handle), filename, S_IFREG, modemask,
 
56
  owners, owngroups, "lsearch", errmsg) == 0;
 
57
}
 
58
 
 
59
 
 
60
 
 
61
/*************************************************
 
62
*  Internal function for the various lsearches   *
 
63
*************************************************/
 
64
 
 
65
/* See local README for interface description, plus:
 
66
 
 
67
Extra argument:
 
68
 
 
69
  type     one of the values LSEARCH_PLAIN, LSEARCH_WILD, LSEARCH_NWILD, or
 
70
           LSEARCH_IP
 
71
 
 
72
There is some messy logic in here to cope with very long data lines that do not
 
73
fit into the fixed sized buffer. Most of the time this will never be exercised,
 
74
but people do occasionally do weird things. */
 
75
 
 
76
static int
 
77
internal_lsearch_find(void *handle, uschar *filename, uschar *keystring,
 
78
  int length, uschar **result, uschar **errmsg, int type)
 
79
{
 
80
FILE *f = (FILE *)handle;
 
81
BOOL last_was_eol = TRUE;
 
82
BOOL this_is_eol = TRUE;
 
83
int old_pool = store_pool;
 
84
void *reset_point = NULL;
 
85
uschar buffer[4096];
 
86
 
 
87
/* Wildcard searches may use up some store, because of expansions. We don't
 
88
want them to fill up our search store. What we do is set the pool to the main
 
89
pool and get a point to reset to later. Wildcard searches could also issue
 
90
lookups, but internal_search_find will take care of that, and the cache will be
 
91
safely stored in the search pool again. */
 
92
 
 
93
if(type == LSEARCH_WILD || type == LSEARCH_NWILD)
 
94
  {
 
95
  store_pool = POOL_MAIN;
 
96
  reset_point = store_get(0);
 
97
  }
 
98
 
 
99
filename = filename;  /* Keep picky compilers happy */
 
100
errmsg = errmsg;
 
101
 
 
102
rewind(f);
 
103
for (last_was_eol = TRUE;
 
104
     Ufgets(buffer, sizeof(buffer), f) != NULL;
 
105
     last_was_eol = this_is_eol)
 
106
  {
 
107
  int ptr, size;
 
108
  int p = Ustrlen(buffer);
 
109
  int linekeylength;
 
110
  BOOL this_is_comment;
 
111
  uschar *yield;
 
112
  uschar *s = buffer;
 
113
 
 
114
  /* Check whether this the final segment of a line. If it follows an
 
115
  incomplete part-line, skip it. */
 
116
 
 
117
  this_is_eol = p > 0 && buffer[p-1] == '\n';
 
118
  if (!last_was_eol) continue;
 
119
 
 
120
  /* We now have the start of a physical line. If this is a final line segment,
 
121
  remove trailing white space. */
 
122
 
 
123
  if (this_is_eol)
 
124
    {
 
125
    while (p > 0 && isspace((uschar)buffer[p-1])) p--;
 
126
    buffer[p] = 0;
 
127
    }
 
128
 
 
129
  /* If the buffer is empty it might be (a) a complete empty line, or (b) the
 
130
  start of a line that begins with so much white space that it doesn't all fit
 
131
  in the buffer. In both cases we want to skip the entire physical line.
 
132
 
 
133
  If the buffer begins with # it is a comment line; if it begins with white
 
134
  space it is a logical continuation; again, we want to skip the entire
 
135
  physical line. */
 
136
 
 
137
  if (buffer[0] == 0 || buffer[0] == '#' || isspace(buffer[0])) continue;
 
138
 
 
139
  /* We assume that they key will fit in the buffer. If the key starts with ",
 
140
  read it as a quoted string. We don't use string_dequote() because that uses
 
141
  new store for the result, and we may be doing this many times in a long file.
 
142
  We know that the dequoted string must be shorter than the original, because
 
143
  we are removing the quotes, and also any escape sequences always turn two or
 
144
  more characters into one character. Therefore, we can store the new string in
 
145
  the same buffer. */
 
146
 
 
147
  if (*s == '\"')
 
148
    {
 
149
    uschar *t = s++;
 
150
    while (*s != 0 && *s != '\"')
 
151
      {
 
152
      if (*s == '\\') *t++ = string_interpret_escape(&s);
 
153
        else *t++ = *s;
 
154
      s++;
 
155
      }
 
156
    if (*s != 0) s++;               /* Past terminating " */
 
157
    linekeylength = t - buffer;
 
158
    }
 
159
 
 
160
  /* Otherwise it is terminated by a colon or white space */
 
161
 
 
162
  else
 
163
    {
 
164
    while (*s != 0 && *s != ':' && !isspace(*s)) s++;
 
165
    linekeylength = s - buffer;
 
166
    }
 
167
 
 
168
  /* The matching test depends on which kind of lsearch we are doing */
 
169
 
 
170
  switch(type)
 
171
    {
 
172
    /* A plain lsearch treats each key as a literal */
 
173
 
 
174
    case LSEARCH_PLAIN:
 
175
    if (linekeylength != length || strncmpic(buffer, keystring, length) != 0)
 
176
      continue;
 
177
    break;      /* Key matched */
 
178
 
 
179
    /* A wild lsearch treats each key as a possible wildcarded string; no
 
180
    expansion is done for nwildlsearch. */
 
181
 
 
182
    case LSEARCH_WILD:
 
183
    case LSEARCH_NWILD:
 
184
      {
 
185
      int rc;
 
186
      int save = buffer[linekeylength];
 
187
      uschar *list = buffer;
 
188
      buffer[linekeylength] = 0;
 
189
      rc = match_isinlist(keystring,
 
190
        &list,
 
191
        UCHAR_MAX+1,              /* Single-item list */
 
192
        NULL,                     /* No anchor */
 
193
        NULL,                     /* No caching */
 
194
        MCL_STRING + ((type == LSEARCH_WILD)? 0:MCL_NOEXPAND),
 
195
        TRUE,                     /* Caseless */
 
196
        NULL);
 
197
      buffer[linekeylength] = save;
 
198
      if (rc == FAIL) continue;
 
199
      if (rc == DEFER) return DEFER;
 
200
      }
 
201
 
 
202
    /* The key has matched. If the search involved a regular expression, it
 
203
    might have caused numerical variables to be set. However, their values will
 
204
    be in the wrong storage pool for external use. Copying them to the standard
 
205
    pool is not feasible because of the caching of lookup results - a repeated
 
206
    lookup will not match the regular expression again. Therefore, we flatten
 
207
    all numeric variables at this point. */
 
208
 
 
209
    expand_nmax = -1;
 
210
    break;
 
211
 
 
212
    /* Compare an ip address against a list of network/ip addresses. We have to
 
213
    allow for the "*" case specially. */
 
214
 
 
215
    case LSEARCH_IP:
 
216
    if (linekeylength == 1 && buffer[0] == '*')
 
217
      {
 
218
      if (length != 1 || keystring[0] != '*') continue;
 
219
      }
 
220
    else if (length == 1 && keystring[0] == '*') continue;
 
221
    else
 
222
      {
 
223
      int maskoffset;
 
224
      int save = buffer[linekeylength];
 
225
      buffer[linekeylength] = 0;
 
226
      if (string_is_ip_address(buffer, &maskoffset) == 0 ||
 
227
          !host_is_in_net(keystring, buffer, maskoffset)) continue;
 
228
      buffer[linekeylength] = save;
 
229
      }
 
230
    break;      /* Key matched */
 
231
    }
 
232
 
 
233
  /* The key has matched. Skip spaces after the key, and allow an optional
 
234
  colon after the spaces. This is an odd specification, but it's for
 
235
  compatibility. */
 
236
 
 
237
  while (isspace((uschar)*s)) s++;
 
238
  if (*s == ':')
 
239
    {
 
240
    s++;
 
241
    while (isspace((uschar)*s)) s++;
 
242
    }
 
243
 
 
244
  /* Reset dynamic store, if we need to, and revert to the search pool */
 
245
 
 
246
  if (reset_point != NULL)
 
247
    {
 
248
    store_reset(reset_point);
 
249
    store_pool = old_pool;
 
250
    }
 
251
 
 
252
  /* Now we want to build the result string to contain the data. There can be
 
253
  two kinds of continuation: (a) the physical line may not all have fitted into
 
254
  the buffer, and (b) there may be logical continuation lines, for which we
 
255
  must convert all leading white space into a single blank.
 
256
 
 
257
  Initialize, and copy the first segment of data. */
 
258
 
 
259
  this_is_comment = FALSE;
 
260
  size = 100;
 
261
  ptr = 0;
 
262
  yield = store_get(size);
 
263
  if (*s != 0)
 
264
    yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
 
265
 
 
266
  /* Now handle continuations */
 
267
 
 
268
  for (last_was_eol = this_is_eol;
 
269
       Ufgets(buffer, sizeof(buffer), f) != NULL;
 
270
       last_was_eol = this_is_eol)
 
271
    {
 
272
    s = buffer;
 
273
    p = Ustrlen(buffer);
 
274
    this_is_eol = p > 0 && buffer[p-1] == '\n';
 
275
 
 
276
    /* Remove trailing white space from a physical line end */
 
277
 
 
278
    if (this_is_eol)
 
279
      {
 
280
      while (p > 0 && isspace((uschar)buffer[p-1])) p--;
 
281
      buffer[p] = 0;
 
282
      }
 
283
 
 
284
    /* If this is not a physical line continuation, skip it entirely if it's
 
285
    empty or starts with #. Otherwise, break the loop if it doesn't start with
 
286
    white space. Otherwise, replace leading white space with a single blank. */
 
287
 
 
288
    if (last_was_eol)
 
289
      {
 
290
      this_is_comment = (this_is_comment || (buffer[0] == 0 || buffer[0] == '#'));
 
291
      if (this_is_comment) continue;
 
292
      if (!isspace((uschar)buffer[0])) break;
 
293
      while (isspace((uschar)*s)) s++;
 
294
      *(--s) = ' ';
 
295
      }
 
296
    if (this_is_comment) continue;
 
297
 
 
298
    /* Join a physical or logical line continuation onto the result string. */
 
299
 
 
300
    yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
 
301
    }
 
302
 
 
303
  yield[ptr] = 0;
 
304
  store_reset(yield + ptr + 1);
 
305
  *result = yield;
 
306
  return OK;
 
307
  }
 
308
 
 
309
/* Reset dynamic store, if we need to */
 
310
 
 
311
if (reset_point != NULL)
 
312
  {
 
313
  store_reset(reset_point);
 
314
  store_pool = old_pool;
 
315
  }
 
316
 
 
317
return FAIL;
 
318
}
 
319
 
 
320
 
 
321
/*************************************************
 
322
*         Find entry point for lsearch           *
 
323
*************************************************/
 
324
 
 
325
/* See local README for interface description */
 
326
 
 
327
int
 
328
lsearch_find(void *handle, uschar *filename, uschar *keystring, int length,
 
329
  uschar **result, uschar **errmsg, BOOL *do_cache)
 
330
{
 
331
do_cache = do_cache;  /* Keep picky compilers happy */
 
332
return internal_lsearch_find(handle, filename, keystring, length, result,
 
333
  errmsg, LSEARCH_PLAIN);
 
334
}
 
335
 
 
336
 
 
337
 
 
338
/*************************************************
 
339
*      Find entry point for wildlsearch          *
 
340
*************************************************/
 
341
 
 
342
/* See local README for interface description */
 
343
 
 
344
int
 
345
wildlsearch_find(void *handle, uschar *filename, uschar *keystring, int length,
 
346
  uschar **result, uschar **errmsg, BOOL *do_cache)
 
347
{
 
348
do_cache = do_cache;  /* Keep picky compilers happy */
 
349
return internal_lsearch_find(handle, filename, keystring, length, result,
 
350
  errmsg, LSEARCH_WILD);
 
351
}
 
352
 
 
353
 
 
354
 
 
355
/*************************************************
 
356
*      Find entry point for nwildlsearch         *
 
357
*************************************************/
 
358
 
 
359
/* See local README for interface description */
 
360
 
 
361
int
 
362
nwildlsearch_find(void *handle, uschar *filename, uschar *keystring, int length,
 
363
  uschar **result, uschar **errmsg, BOOL *do_cache)
 
364
{
 
365
do_cache = do_cache;  /* Keep picky compilers happy */
 
366
return internal_lsearch_find(handle, filename, keystring, length, result,
 
367
  errmsg, LSEARCH_NWILD);
 
368
}
 
369
 
 
370
 
 
371
 
 
372
 
 
373
/*************************************************
 
374
*      Find entry point for iplsearch            *
 
375
*************************************************/
 
376
 
 
377
/* See local README for interface description */
 
378
 
 
379
int
 
380
iplsearch_find(void *handle, uschar *filename, uschar *keystring, int length,
 
381
  uschar **result, uschar **errmsg, BOOL *do_cache)
 
382
{
 
383
do_cache = do_cache;  /* Keep picky compilers happy */
 
384
if ((length == 1 && keystring[0] == '*') ||
 
385
    string_is_ip_address(keystring, NULL) != 0)
 
386
  {
 
387
  return internal_lsearch_find(handle, filename, keystring, length, result,
 
388
    errmsg, LSEARCH_IP);
 
389
  }
 
390
else
 
391
  {
 
392
  *errmsg = string_sprintf("\"%s\" is not a valid iplsearch key (an IP "
 
393
    "address, with optional CIDR mask, is wanted): "
 
394
    "in a host list, use net-iplsearch as the search type", keystring);
 
395
  return DEFER;
 
396
  }
 
397
}
 
398
 
 
399
 
 
400
 
 
401
 
 
402
/*************************************************
 
403
*              Close entry point                 *
 
404
*************************************************/
 
405
 
 
406
/* See local README for interface description */
 
407
 
 
408
void
 
409
lsearch_close(void *handle)
 
410
{
 
411
(void)fclose((FILE *)handle);
 
412
}
 
413
 
 
414
/* End of lookups/lsearch.c */