View | Details | Raw Unified | Return to bug 46381
Collapse All | Expand All

(-)exim.orig/exim_monitor/em_globals.c (-2 / +4 lines)
Lines 3-8 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2021 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
8
9
Lines 81-87 Link Here
81
int     queue_update = 60;
82
int     queue_update = 60;
82
int     queue_width = 600;
83
int     queue_width = 600;
83
84
84
pcre   *yyyymmdd_regex;
85
pcre2_code   *yyyymmdd_regex;
85
86
86
uschar *size_stripchart = NULL;
87
uschar *size_stripchart = NULL;
87
uschar *size_stripchart_name = NULL;
88
uschar *size_stripchart_name = NULL;
Lines 89-95 Link Here
89
int     start_small = FALSE;
90
int     start_small = FALSE;
90
int     stripchart_height = 90;
91
int     stripchart_height = 90;
91
int     stripchart_number = 1;
92
int     stripchart_number = 1;
92
pcre  **stripchart_regex;
93
pcre2_code  **stripchart_regex;
93
uschar **stripchart_title;
94
uschar **stripchart_title;
94
int    *stripchart_total;
95
int    *stripchart_total;
95
int     stripchart_update = 60;
96
int     stripchart_update = 60;
Lines 196-201 Link Here
196
int     received_count         = 0;
197
int     received_count         = 0;
197
uschar *received_protocol      = NULL;
198
uschar *received_protocol      = NULL;
198
struct timeval received_time   = { 0, 0 };
199
struct timeval received_time   = { 0, 0 };
200
struct timeval received_time_complete = { 0, 0 };
199
int     recipients_count       = 0;
201
int     recipients_count       = 0;
200
recipient_item *recipients_list = NULL;
202
recipient_item *recipients_list = NULL;
201
int     recipients_list_max    = 0;
203
int     recipients_list_max    = 0;
(-)exim.orig/exim_monitor/em_hdr.h (-5 / +8 lines)
Lines 3-8 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2009 */
5
/* Copyright (c) University of Cambridge 1995 - 2009 */
6
/* Copyright (c) The Exim Maintainers 2021 - 2022 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
8
9
Lines 85-91 Link Here
85
86
86
/* Regular expression include */
87
/* Regular expression include */
87
88
88
#include <pcre.h>
89
#define PCRE2_CODE_UNIT_WIDTH 8
90
#include <pcre2.h>
89
91
90
/* Includes from the main source of Exim.  One of these days I should tidy up
92
/* Includes from the main source of Exim.  One of these days I should tidy up
91
this interface so that this kind of kludge isn't needed. */
93
this interface so that this kind of kludge isn't needed. */
Lines 93-106 Link Here
93
#ifndef NS_MAXMSG
95
#ifndef NS_MAXMSG
94
# define NS_MAXMSG 65535
96
# define NS_MAXMSG 65535
95
#endif
97
#endif
96
typedef void hctx;
98
typedef void * hctx;
97
99
98
#include "local_scan.h"
100
#include "local_scan.h"
99
#include "macros.h"
101
#include "macros.h"
100
#include "structs.h"
102
#include "structs.h"
101
#include "blob.h"
103
#include "blob.h"
102
#include "globals.h"
104
#include "globals.h"
103
#include "dbstuff.h"
105
#include "hintsdb.h"
106
#include "hintsdb_structs.h"
104
#include "functions.h"
107
#include "functions.h"
105
#include "osfunctions.h"
108
#include "osfunctions.h"
106
109
Lines 273-279 Link Here
273
extern int     queue_update;        /* update interval */
276
extern int     queue_update;        /* update interval */
274
extern int     queue_width;         /* width of queue window */
277
extern int     queue_width;         /* width of queue window */
275
278
276
extern pcre   *yyyymmdd_regex;    /* for matching yyyy-mm-dd */
279
extern pcre2_code   *yyyymmdd_regex;    /* for matching yyyy-mm-dd */
277
280
278
extern uschar *size_stripchart;     /* path for size monitoring */
281
extern uschar *size_stripchart;     /* path for size monitoring */
279
extern uschar *size_stripchart_name; /* name for size stripchart */
282
extern uschar *size_stripchart_name; /* name for size stripchart */
Lines 282-288 Link Here
282
extern int     start_small;         /* True to start with small window */
285
extern int     start_small;         /* True to start with small window */
283
extern int     stripchart_height;   /* height of stripcharts */
286
extern int     stripchart_height;   /* height of stripcharts */
284
extern int     stripchart_number;   /* number of stripcharts */
287
extern int     stripchart_number;   /* number of stripcharts */
285
extern pcre  **stripchart_regex;  /* vector of regexps */
288
extern pcre2_code  **stripchart_regex;  /* vector of regexps */
286
extern uschar **stripchart_title;    /* vector of titles */
289
extern uschar **stripchart_title;    /* vector of titles */
287
extern int    *stripchart_total;    /* vector of accumulating values */
290
extern int    *stripchart_total;    /* vector of accumulating values */
288
extern int     stripchart_update;   /* update interval */
291
extern int     stripchart_update;   /* update interval */
(-)exim.orig/exim_monitor/em_init.c (-54 / +55 lines)
Lines 3-9 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2009 */
5
/* Copyright (c) University of Cambridge 1995 - 2009 */
6
/* Copyright (c) The Exim Maintainers 2020 */
6
/* Copyright (c) The Exim Maintainers 2020 - 2021 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* This module contains code to initialize things from the
9
/* This module contains code to initialize things from the
Lines 32-38 Link Here
32
work. */
32
work. */
33
33
34
for (i = 0; i <= 1; i++)
34
for (i = 0; i <= 1; i++)
35
36
  {
35
  {
37
  int first = 1;
36
  int first = 1;
38
  int count = 0;
37
  int count = 0;
Lines 69-81 Link Here
69
      buffer[p-pp] = 0;
68
      buffer[p-pp] = 0;
70
      if (first)
69
      if (first)
71
        {
70
        {
72
        int offset;
71
        size_t offset;
73
        const uschar *error;
72
        int err;
74
        if (!(stripchart_regex[indx] = pcre_compile(CS buffer, PCRE_COPT,
73
75
          CCSS &error, &offset, NULL)))
74
        if (!(stripchart_regex[indx] =
75
		pcre2_compile((PCRE2_SPTR)buffer,
76
		      PCRE2_ZERO_TERMINATED, PCRE_COPT,
77
		      &err, &offset, NULL)))
76
          {
78
          {
77
          printf("regular expression error: %s at offset %d "
79
	  uschar errbuf[128];
78
            "while compiling %s\n", error, offset, buffer);
80
	  pcre2_get_error_message(err, errbuf, sizeof(errbuf));
81
          printf("regular expression error: %s at offset %ld "
82
            "while compiling %s\n", errbuf, (long)offset, buffer);
79
          exit(99);
83
          exit(99);
80
          }
84
          }
81
        }
85
        }
Lines 95-101 Link Here
95
  if (i == 0)
99
  if (i == 0)
96
    {
100
    {
97
    stripchart_number += count;
101
    stripchart_number += count;
98
    stripchart_regex = (pcre **)store_malloc(stripchart_number * sizeof(pcre *));
102
    stripchart_regex = (pcre2_code **)store_malloc(stripchart_number * sizeof(pcre2_code *));
99
    stripchart_title = (uschar **)store_malloc(stripchart_number * sizeof(uschar *));
103
    stripchart_title = (uschar **)store_malloc(stripchart_number * sizeof(uschar *));
100
    }
104
    }
101
  }
105
  }
Lines 109-148 Link Here
109
void init(int argc, uschar **argv)
113
void init(int argc, uschar **argv)
110
{
114
{
111
int x;
115
int x;
112
int erroroffset;
116
size_t erroroffset;
113
uschar *s;
117
uschar *s;
114
const uschar *error;
115
118
116
argc = argc;     /* These are currently unused. */
119
argc = argc;     /* These are currently unused. */
117
argv = argv;
120
argv = argv;
118
121
119
/* Deal with simple values in the environment. */
122
/* Deal with simple values in the environment. */
120
123
121
s = US getenv("ACTION_OUTPUT");
124
if ((s = US getenv("ACTION_OUTPUT")))
122
if (s != NULL)
123
  {
125
  {
124
  if (Ustrcmp(s, "no") == 0) action_output = FALSE;
126
  if (Ustrcmp(s, "no") == 0) action_output = FALSE;
125
  if (Ustrcmp(s, "yes") == 0) action_output = TRUE;
127
  if (Ustrcmp(s, "yes") == 0) action_output = TRUE;
126
  }
128
  }
127
129
128
s = US getenv("ACTION_QUEUE_UPDATE");
130
if ((s = US getenv("ACTION_QUEUE_UPDATE")))
129
if (s != NULL)
130
  {
131
  {
131
  if (Ustrcmp(s, "no") == 0) action_queue_update = FALSE;
132
  if (Ustrcmp(s, "no") == 0) action_queue_update = FALSE;
132
  if (Ustrcmp(s, "yes") == 0) action_queue_update = TRUE;
133
  if (Ustrcmp(s, "yes") == 0) action_queue_update = TRUE;
133
  }
134
  }
134
135
135
s = US getenv("BODY_MAX");
136
s = US getenv("BODY_MAX");
136
if (s != NULL && (x = Uatoi(s)) != 0) body_max = x;
137
if (s && (x = Uatoi(s)) != 0) body_max = x;
137
138
138
s = US getenv("EXIM_PATH");
139
if ((s = US getenv("EXIM_PATH")))
139
if (s != NULL) exim_path = string_copy(s);
140
  exim_path = string_copy(s);
140
141
141
s = US getenv("EXIMON_EXIM_CONFIG");
142
if ((s = US getenv("EXIMON_EXIM_CONFIG")))
142
if (s != NULL) alternate_config = string_copy(s);
143
  alternate_config = string_copy(s);
143
144
144
s = US getenv("LOG_BUFFER");
145
if ((s = US getenv("LOG_BUFFER")))
145
if (s != NULL)
146
  {
146
  {
147
  uschar c[1];
147
  uschar c[1];
148
  if (sscanf(CS s, "%d%c", &x, c) > 0)
148
  if (sscanf(CS s, "%d%c", &x, c) > 0)
Lines 154-216 Link Here
154
  }
154
  }
155
155
156
s = US getenv("LOG_DEPTH");
156
s = US getenv("LOG_DEPTH");
157
if (s != NULL && (x = Uatoi(s)) != 0) log_depth = x;
157
if (s && (x = Uatoi(s)) != 0) log_depth = x;
158
158
159
s = US getenv("LOG_FILE_NAME");
159
if ((s = US getenv("LOG_FILE_NAME")))
160
if (s != NULL) log_file = string_copy(s);
160
  log_file = string_copy(s);
161
161
162
s = US getenv("LOG_FONT");
162
if ((s = US getenv("LOG_FONT")))
163
if (s != NULL) log_font = string_copy(s);
163
  log_font = string_copy(s);
164
164
165
s = US getenv("LOG_WIDTH");
165
s = US getenv("LOG_WIDTH");
166
if (s != NULL && (x = Uatoi(s)) != 0) log_width = x;
166
if (s && (x = Uatoi(s)) != 0) log_width = x;
167
167
168
s = US getenv("MENU_EVENT");
168
if ((s = US getenv("MENU_EVENT")))
169
if (s != NULL) menu_event = string_copy(s);
169
  menu_event = string_copy(s);
170
170
171
s = US getenv("MIN_HEIGHT");
171
s = US getenv("MIN_HEIGHT");
172
if (s != NULL && (x = Uatoi(s)) > 0) min_height = x;
172
if (s && (x = Uatoi(s)) > 0) min_height = x;
173
173
174
s = US getenv("MIN_WIDTH");
174
s = US getenv("MIN_WIDTH");
175
if (s != NULL && (x = Uatoi(s)) > 0) min_width = x;
175
if (s && (x = Uatoi(s)) > 0) min_width = x;
176
176
177
s = US getenv("QUALIFY_DOMAIN");
177
if ((s = US getenv("QUALIFY_DOMAIN")))
178
if (s != NULL) qualify_domain = string_copy(s);
178
  qualify_domain = string_copy(s);
179
  else qualify_domain = US"";  /* Don't want NULL */
179
else
180
  qualify_domain = US"";  /* Don't want NULL */
180
181
181
s = US getenv("QUEUE_DEPTH");
182
s = US getenv("QUEUE_DEPTH");
182
if (s != NULL && (x = Uatoi(s)) != 0) queue_depth = x;
183
if (s && (x = Uatoi(s)) != 0) queue_depth = x;
183
184
184
s = US getenv("QUEUE_FONT");
185
if ((s = US getenv("QUEUE_FONT")))
185
if (s != NULL) queue_font = string_copy(s);
186
  queue_font = string_copy(s);
186
187
187
s = US getenv("QUEUE_INTERVAL");
188
s = US getenv("QUEUE_INTERVAL");
188
if (s != NULL && (x = Uatoi(s)) != 0) queue_update = x;
189
if (s && (x = Uatoi(s)) != 0) queue_update = x;
189
190
190
s = US getenv("QUEUE_MAX_ADDRESSES");
191
s = US getenv("QUEUE_MAX_ADDRESSES");
191
if (s != NULL && (x = Uatoi(s)) != 0) queue_max_addresses = x;
192
if (s && (x = Uatoi(s)) != 0) queue_max_addresses = x;
192
193
193
s = US getenv("QUEUE_WIDTH");
194
s = US getenv("QUEUE_WIDTH");
194
if (s != NULL && (x = Uatoi(s)) != 0) queue_width = x;
195
if (s && (x = Uatoi(s)) != 0) queue_width = x;
195
196
196
s = US getenv("SPOOL_DIRECTORY");
197
if ((s = US getenv("SPOOL_DIRECTORY")))
197
if (s != NULL) spool_directory = string_copy(s);
198
  spool_directory = string_copy(s);
198
199
199
s = US getenv("START_SMALL");
200
s = US getenv("START_SMALL");
200
if (s != NULL && Ustrcmp(s, "yes") == 0) start_small = 1;
201
if (s && Ustrcmp(s, "yes") == 0) start_small = 1;
201
202
202
s = US getenv("TEXT_DEPTH");
203
s = US getenv("TEXT_DEPTH");
203
if (s != NULL && (x = Uatoi(s)) != 0) text_depth = x;
204
if (s && (x = Uatoi(s)) != 0) text_depth = x;
204
205
205
s = US getenv("WINDOW_TITLE");
206
if ((s = US getenv("WINDOW_TITLE")))
206
if (s != NULL) window_title = string_copy(s);
207
  window_title = string_copy(s);
207
208
208
/* Deal with stripchart configuration. First see if we are monitoring
209
/* Deal with stripchart configuration. First see if we are monitoring
209
the size of a partition, then deal with log stripcharts in a separate
210
the size of a partition, then deal with log stripcharts in a separate
210
function */
211
function */
211
212
212
s = US getenv("SIZE_STRIPCHART");
213
s = US getenv("SIZE_STRIPCHART");
213
if (s != NULL && *s != 0)
214
if (s && *s)
214
  {
215
  {
215
  stripchart_number++;
216
  stripchart_number++;
216
  stripchart_varstart++;
217
  stripchart_varstart++;
Lines 219-237 Link Here
219
  if (s != NULL && *s != 0) size_stripchart_name = string_copy(s);
220
  if (s != NULL && *s != 0) size_stripchart_name = string_copy(s);
220
  }
221
  }
221
222
222
s = US getenv("LOG_STRIPCHARTS");
223
if ((s = US getenv("LOG_STRIPCHARTS")))
223
if (s != NULL) decode_stripchart_config(s);
224
  decode_stripchart_config(s);
224
225
225
s = US getenv("STRIPCHART_INTERVAL");
226
s = US getenv("STRIPCHART_INTERVAL");
226
if (s != NULL && (x = Uatoi(s)) != 0) stripchart_update = x;
227
if (s && (x = Uatoi(s)) != 0) stripchart_update = x;
227
228
228
s = US getenv("QUEUE_STRIPCHART_NAME");
229
s = US getenv("QUEUE_STRIPCHART_NAME");
229
queue_stripchart_name = (s != NULL)? string_copy(s) : US"queue";
230
queue_stripchart_name = s ? string_copy(s) : US"queue";
230
231
231
/* Compile the regex for matching yyyy-mm-dd at the start of a string. */
232
/* Compile the regex for matching yyyy-mm-dd at the start of a string. */
232
233
233
yyyymmdd_regex = pcre_compile("^\\d{4}-\\d\\d-\\d\\d\\s", PCRE_COPT,
234
yyyymmdd_regex = pcre2_compile((PCRE2_SPTR)"^\\d{4}-\\d\\d-\\d\\d\\s",
234
  CCSS &error, &erroroffset, NULL);
235
  PCRE2_ZERO_TERMINATED, PCRE_COPT, &x, &erroroffset, NULL);
235
}
236
}
236
237
237
/* End of em_init.c */
238
/* End of em_init.c */
(-)exim.orig/exim_monitor/em_log.c (-13 / +13 lines)
Lines 3-8 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainters 2021 - 2022 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
8
/* This module contains code for scanning the main log,
9
/* This module contains code for scanning the main log,
Lines 229-235 Link Here
229
    uschar *p = buffer;
230
    uschar *p = buffer;
230
    rmark reset_point;
231
    rmark reset_point;
231
    int length = Ustrlen(buffer);
232
    int length = Ustrlen(buffer);
232
    int i;
233
    pcre2_match_data * md = pcre2_match_data_create(1, NULL);
233
234
234
    /* Skip totally blank lines (paranoia: there shouldn't be any) */
235
    /* Skip totally blank lines (paranoia: there shouldn't be any) */
235
236
Lines 246-272 Link Here
246
    stripchart is the queue length, which is handled elsewhere, and the
247
    stripchart is the queue length, which is handled elsewhere, and the
247
    1st may the a size monitor. */
248
    1st may the a size monitor. */
248
249
249
    for (i = stripchart_varstart; i < stripchart_number; i++)
250
    for (int i = stripchart_varstart; i < stripchart_number; i++)
250
      {
251
      if (pcre2_match(stripchart_regex[i], (PCRE2_SPTR)buffer, length,
251
      if (pcre_exec(stripchart_regex[i], NULL, CS buffer, length, 0, PCRE_EOPT,
252
			0, PCRE_EOPT, md, NULL) >= 0)
252
            NULL, 0) >= 0)
253
        stripchart_total[i]++;
253
        stripchart_total[i]++;
254
      }
255
254
256
    /* Munge the log entry and display shortened form on one line.
255
    /* Munge the log entry and display shortened form on one line.
257
    We omit the date and show only the time. Remove any time zone offset.
256
    We omit the date and show only the time. Remove any time zone offset.
258
    Take note of the presence of [pid]. */
257
    Take note of the presence of [pid]. */
259
258
260
    if (pcre_exec(yyyymmdd_regex,NULL,CS buffer,length,0,PCRE_EOPT,NULL,0) >= 0)
259
    if (pcre2_match(yyyymmdd_regex, (PCRE2_SPTR) buffer, length, 0, PCRE_EOPT,
260
		      md, NULL) >= 0)
261
      {
261
      {
262
      int pidlength = 0;
262
      int pidlength = 0;
263
      if ((buffer[20] == '+' || buffer[20] == '-') &&
263
      if (  (buffer[20] == '+' || buffer[20] == '-')
264
          isdigit(buffer[21]) && buffer[25] == ' ')
264
         && isdigit(buffer[21]) && buffer[25] == ' ')
265
        memmove(buffer + 20, buffer + 26, Ustrlen(buffer + 26) + 1);
265
        memmove(buffer + 20, buffer + 26, Ustrlen(buffer + 26) + 1);
266
      if (buffer[20] == '[')
266
      if (buffer[20] == '[')
267
        {
267
        while (Ustrchr("[]0123456789", buffer[20+pidlength++]) != NULL)
268
        while (Ustrchr("[]0123456789", buffer[20+pidlength++]) != NULL);
268
	  ;
269
        }
270
      id = string_copyn(buffer + 20 + pidlength, MESSAGE_ID_LENGTH);
269
      id = string_copyn(buffer + 20 + pidlength, MESSAGE_ID_LENGTH);
271
      show_log("%s", buffer+11);
270
      show_log("%s", buffer+11);
272
      }
271
      }
Lines 275-280 Link Here
275
      id = US"";
274
      id = US"";
276
      show_log("%s", buffer);
275
      show_log("%s", buffer);
277
      }
276
      }
277
    pcre2_match_data_free(md);
278
278
279
    /* Deal with frozen and unfrozen messages */
279
    /* Deal with frozen and unfrozen messages */
280
280
Lines 292-298 Link Here
292
    if ((p = Ustrstr(buffer, "==")) != NULL)
292
    if ((p = Ustrstr(buffer, "==")) != NULL)
293
      {
293
      {
294
      queue_item *qq = find_queue(id, queue_noop, 0);
294
      queue_item *qq = find_queue(id, queue_noop, 0);
295
      if (qq != NULL)
295
      if (qq)
296
        {
296
        {
297
        dest_item *d;
297
        dest_item *d;
298
        uschar *q, *r;
298
        uschar *q, *r;
(-)exim.orig/exim_monitor/em_main.c (-37 / +46 lines)
Lines 3-8 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2021 - 2022 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
8
9
Lines 173-180 Link Here
173
vfprintf(stderr, format, ap);
174
vfprintf(stderr, format, ap);
174
fprintf(stderr, "\n");
175
fprintf(stderr, "\n");
175
va_end(ap);
176
va_end(ap);
176
selector = selector;     /* Keep picky compilers happy */
177
flags = flags;
178
}
177
}
179
178
180
179
Lines 198-216 Link Here
198
*/
197
*/
199
198
200
int
199
int
201
host_address_extract_port(uschar *address)
200
host_address_extract_port(uschar * address)
202
{
201
{
203
int skip = -3;                     /* Skip 3 dots in IPv4 addresses */
202
int port = 0;
204
address--;
203
uschar *endptr;
205
while (*(++address) != 0)
204
206
  {
205
/* Handle the "bracketed with colon on the end" format */
207
  int ch = *address;
206
208
  if (ch == ':') skip = 0;         /* Skip 0 dots in IPv6 addresses */
207
if (*address == '[')
209
    else if (ch == '.' && skip++ >= 0) break;
208
  {
210
  }
209
  uschar *rb = address + 1;
211
if (*address == 0) return 0;
210
  while (*rb != 0 && *rb != ']') rb++;
212
*address++ = 0;
211
  if (*rb++ == 0) return 0;		/* Missing ]; leave invalid address */
213
return Uatoi(address);
212
  if (*rb == ':')
213
    {
214
    port = Ustrtol(rb + 1, &endptr, 10);
215
    if (*endptr != 0) return 0;		/* Invalid port; leave invalid address */
216
    }
217
  else if (*rb != 0) return 0;		/* Bad syntax; leave invalid address */
218
  memmove(address, address + 1, rb - address - 2);
219
  rb[-2] = 0;
220
  }
221
222
/* Handle the "dot on the end" format */
223
224
else
225
  {
226
  int skip = -3;			/* Skip 3 dots in IPv4 addresses */
227
  address--;
228
  while (*(++address) != 0)
229
    {
230
    int ch = *address;
231
    if (ch == ':') skip = 0;		/* Skip 0 dots in IPv6 addresses */
232
      else if (ch == '.' && skip++ >= 0) break;
233
    }
234
  if (*address == 0) return 0;
235
  port = Ustrtol(address + 1, &endptr, 10);
236
  if (*endptr != 0) return 0;		/* Invalid port; leave invalid address */
237
  *address = 0;
238
  }
239
240
return port;
214
}
241
}
215
242
216
243
Lines 240-248 Link Here
240
267
241
void updateAction(Widget w, XtPointer client_data, XtPointer call_data)
268
void updateAction(Widget w, XtPointer client_data, XtPointer call_data)
242
{
269
{
243
w = w;       /* Keep picky compilers happy */
244
client_data = client_data;
245
call_data = call_data;
246
scan_spool_input(TRUE);
270
scan_spool_input(TRUE);
247
queue_display();
271
queue_display();
248
tick_queue_accumulator = 0;
272
tick_queue_accumulator = 0;
Lines 250-258 Link Here
250
274
251
void hideAction(Widget w, XtPointer client_data, XtPointer call_data)
275
void hideAction(Widget w, XtPointer client_data, XtPointer call_data)
252
{
276
{
253
w = w;       /* Keep picky compilers happy */
254
client_data = client_data;
255
call_data = call_data;
256
actioned_message[0] = 0;
277
actioned_message[0] = 0;
257
dialog_ref_widget = w;
278
dialog_ref_widget = w;
258
dialog_action = da_hide;
279
dialog_action = da_hide;
Lines 263-273 Link Here
263
{
284
{
264
skip_item *sk = queue_skip;
285
skip_item *sk = queue_skip;
265
286
266
w = w;       /* Keep picky compilers happy */
287
while (sk)
267
client_data = client_data;
268
call_data = call_data;
269
270
while (sk != NULL)
271
  {
288
  {
272
  skip_item *next = sk->next;
289
  skip_item *next = sk->next;
273
  store_free(sk);
290
  store_free(sk);
Lines 285-293 Link Here
285
302
286
void quitAction(Widget w, XtPointer client_data, XtPointer call_data)
303
void quitAction(Widget w, XtPointer client_data, XtPointer call_data)
287
{
304
{
288
w = w;       /* Keep picky compilers happy */
289
client_data = client_data;
290
call_data = call_data;
291
exit(0);
305
exit(0);
292
}
306
}
293
307
Lines 318-327 Link Here
318
XWindowAttributes a;
332
XWindowAttributes a;
319
Window w = XtWindow(toplevel_widget);
333
Window w = XtWindow(toplevel_widget);
320
334
321
button = button;    /* Keep picky compilers happy */
322
client_data = client_data;
323
call_data = call_data;
324
325
/* Get the position and size of the top level widget. */
335
/* Get the position and size of the top level widget. */
326
336
327
sizepos_args[0].value = (XtArgVal)(&width);
337
sizepos_args[0].value = (XtArgVal)(&width);
Lines 473-481 Link Here
473
tick_stripchart_accumulator += tick_interval;
483
tick_stripchart_accumulator += tick_interval;
474
read_log();
484
read_log();
475
485
476
pt = pt;    /* Keep picky compilers happy */
477
i = i;
478
479
/* If we have passed the queue update time, we must do a full
486
/* If we have passed the queue update time, we must do a full
480
scan of the queue, checking for new arrivals, etc. This will
487
scan of the queue, checking for new arrivals, etc. This will
481
as a by-product set the count of items for use by the stripchart
488
as a by-product set the count of items for use by the stripchart
Lines 592-598 Link Here
592
*               Initialize                       *
599
*               Initialize                       *
593
*************************************************/
600
*************************************************/
594
601
595
int main(int argc, char **argv)
602
int
603
main(int argc, char **argv)
596
{
604
{
597
int i;
605
int i;
598
struct stat statdata;
606
struct stat statdata;
Lines 613-619 Link Here
613
constructing file names and things. This call will initialize
621
constructing file names and things. This call will initialize
614
the store_get() function. */
622
the store_get() function. */
615
623
616
big_buffer = store_get(big_buffer_size, FALSE);
624
store_init();
625
big_buffer = store_get(big_buffer_size, GET_UNTAINTED);
617
626
618
/* Set up the version string and date and output them */
627
/* Set up the version string and date and output them */
619
628
(-)exim.orig/exim_monitor/em_menu.c (-112 / +48 lines)
Lines 3-8 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2021 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
8
9
Lines 115-124 Link Here
115
*        Destroy the menu when popped down       *
116
*        Destroy the menu when popped down       *
116
*************************************************/
117
*************************************************/
117
118
118
static void popdownAction(Widget w, XtPointer client_data, XtPointer call_data)
119
static void
120
popdownAction(Widget w, XtPointer client_data, XtPointer call_data)
119
{
121
{
120
client_data = client_data;    /* Keep picky compilers happy */
121
call_data = call_data;
122
if (highlighted_x >= 0)
122
if (highlighted_x >= 0)
123
  XawTextSinkDisplayText(queue_text_sink,
123
  XawTextSinkDisplayText(queue_text_sink,
124
    highlighted_x, highlighted_y,
124
    highlighted_x, highlighted_y,
Lines 136-152 Link Here
136
static void
136
static void
137
msglogAction(Widget w, XtPointer client_data, XtPointer call_data)
137
msglogAction(Widget w, XtPointer client_data, XtPointer call_data)
138
{
138
{
139
int i;
140
Widget text = text_create(US client_data, text_depth);
139
Widget text = text_create(US client_data, text_depth);
141
uschar * fname = NULL;
140
uschar * fname = NULL;
142
FILE * f = NULL;
141
FILE * f = NULL;
143
142
144
w = w;      /* Keep picky compilers happy */
145
call_data = call_data;
146
147
/* End up with the split version, so message looks right when non-exist */
143
/* End up with the split version, so message looks right when non-exist */
148
144
149
for (i = 0; i < (spool_is_split ? 2:1); i++)
145
for (int i = 0; i < (spool_is_split ? 2:1); i++)
150
  {
146
  {
151
  message_subdir[0] = i != 0 ? (US client_data)[5] : 0;
147
  message_subdir[0] = i != 0 ? (US client_data)[5] : 0;
152
  fname = spool_fname(US"msglog", message_subdir, US client_data, US"");
148
  fname = spool_fname(US"msglog", message_subdir, US client_data, US"");
Lines 173-186 Link Here
173
static void
169
static void
174
bodyAction(Widget w, XtPointer client_data, XtPointer call_data)
170
bodyAction(Widget w, XtPointer client_data, XtPointer call_data)
175
{
171
{
176
int i;
177
Widget text = text_create(US client_data, text_depth);
172
Widget text = text_create(US client_data, text_depth);
178
FILE *f = NULL;
173
FILE *f = NULL;
179
174
180
w = w;      /* Keep picky compilers happy */
175
for (int i = 0; i < (spool_is_split? 2:1); i++)
181
call_data = call_data;
182
183
for (i = 0; i < (spool_is_split? 2:1); i++)
184
  {
176
  {
185
  uschar * fname;
177
  uschar * fname;
186
  message_subdir[0] = i != 0 ? (US client_data)[5] : 0;
178
  message_subdir[0] = i != 0 ? (US client_data)[5] : 0;
Lines 189-195 Link Here
189
    break;
181
    break;
190
  }
182
  }
191
183
192
if (f == NULL)
184
if (!f)
193
  text_showf(text, "Failed to open file: %s\n", strerror(errno));
185
  text_showf(text, "Failed to open file: %s\n", strerror(errno));
194
else
186
else
195
  {
187
  {
Lines 221-227 Link Here
221
the command whether we want the output or not, so the pipe has to be set up in
213
the command whether we want the output or not, so the pipe has to be set up in
222
all cases. */
214
all cases. */
223
215
224
static void ActOnMessage(uschar *id, uschar *action, uschar *address_arg)
216
static void
217
ActOnMessage(uschar *id, uschar *action, uschar *address_arg)
225
{
218
{
226
int pid;
219
int pid;
227
int pipe_fd[2];
220
int pipe_fd[2];
Lines 407-447 Link Here
407
*        Cause a message to be delivered         *
400
*        Cause a message to be delivered         *
408
*************************************************/
401
*************************************************/
409
402
410
static void deliverAction(Widget w, XtPointer client_data, XtPointer call_data)
403
static void
404
deliverAction(Widget w, XtPointer client_data, XtPointer call_data)
411
{
405
{
412
w = w;      /* Keep picky compilers happy */
413
call_data = call_data;
414
ActOnMessage(US client_data, US"-v -M", US"");
406
ActOnMessage(US client_data, US"-v -M", US"");
415
}
407
}
416
408
417
418
419
/*************************************************
409
/*************************************************
420
*        Cause a message to be Frozen            *
410
*        Cause a message to be Frozen            *
421
*************************************************/
411
*************************************************/
422
412
423
static void freezeAction(Widget w, XtPointer client_data, XtPointer call_data)
413
static void
414
freezeAction(Widget w, XtPointer client_data, XtPointer call_data)
424
{
415
{
425
w = w;      /* Keep picky compilers happy */
426
call_data = call_data;
427
ActOnMessage(US client_data, US"-Mf", US"");
416
ActOnMessage(US client_data, US"-Mf", US"");
428
}
417
}
429
418
430
431
432
/*************************************************
419
/*************************************************
433
*        Cause a message to be thawed            *
420
*        Cause a message to be thawed            *
434
*************************************************/
421
*************************************************/
435
422
436
static void thawAction(Widget w, XtPointer client_data, XtPointer call_data)
423
static void
424
thawAction(Widget w, XtPointer client_data, XtPointer call_data)
437
{
425
{
438
w = w;      /* Keep picky compilers happy */
439
call_data = call_data;
440
ActOnMessage(US client_data, US"-Mt", US"");
426
ActOnMessage(US client_data, US"-Mt", US"");
441
}
427
}
442
428
443
444
445
/*************************************************
429
/*************************************************
446
*          Take action using dialog data         *
430
*          Take action using dialog data         *
447
*************************************************/
431
*************************************************/
Lines 450-474 Link Here
450
in. It is global because it is set up in the action table at
434
in. It is global because it is set up in the action table at
451
start-up time. If the string is empty, do nothing. */
435
start-up time. If the string is empty, do nothing. */
452
436
453
XtActionProc dialogAction(Widget w, XEvent *event, String *ss, Cardinal *c)
437
XtActionProc
438
dialogAction(Widget w, XEvent *event, String *ss, Cardinal *c)
454
{
439
{
455
uschar *s = US XawDialogGetValueString(dialog_widget);
440
uschar *s = US XawDialogGetValueString(dialog_widget);
456
441
457
w = w;      /* Keep picky compilers happy */
458
event = event;
459
ss = ss;
460
c = c;
461
462
XtPopdown((Widget)dialog_shell);
442
XtPopdown((Widget)dialog_shell);
463
XtDestroyWidget((Widget)dialog_shell);
443
XtDestroyWidget((Widget)dialog_shell);
464
while (isspace(*s)) s++;
444
while (isspace(*s)) s++;
465
if (s[0] != 0)
445
if (s[0] != 0)
466
  {
467
  if (actioned_message[0] != 0)
446
  if (actioned_message[0] != 0)
468
    ActOnMessage(actioned_message, action_required, s);
447
    ActOnMessage(actioned_message, action_required, s);
469
  else
448
  else
470
    NonMessageDialogue(s);    /* When called from somewhere else */
449
    NonMessageDialogue(s);    /* When called from somewhere else */
471
  }
472
return NULL;
450
return NULL;
473
}
451
}
474
452
Lines 482-488 Link Here
482
be done to the application until the box is filled in. This
460
be done to the application until the box is filled in. This
483
function is also used by the Hide button handler. */
461
function is also used by the Hide button handler. */
484
462
485
void create_dialog(uschar *label, uschar *value)
463
void
464
create_dialog(uschar *label, uschar *value)
486
{
465
{
487
Arg warg[4];
466
Arg warg[4];
488
Dimension x, y, xx, yy;
467
Dimension x, y, xx, yy;
Lines 544-552 Link Here
544
}
523
}
545
524
546
525
547
548
549
550
/*************************************************
526
/*************************************************
551
*        Cause a recipient to be added           *
527
*        Cause a recipient to be added           *
552
*************************************************/
528
*************************************************/
Lines 554-563 Link Here
554
/* This just sets up the dialog box; the action happens when it has been filled
530
/* This just sets up the dialog box; the action happens when it has been filled
555
in. */
531
in. */
556
532
557
static void addrecipAction(Widget w, XtPointer client_data, XtPointer call_data)
533
static void
534
addrecipAction(Widget w, XtPointer client_data, XtPointer call_data)
558
{
535
{
559
w = w;      /* Keep picky compilers happy */
560
call_data = call_data;
561
Ustrncpy(actioned_message, client_data, 24);
536
Ustrncpy(actioned_message, client_data, 24);
562
actioned_message[23] = '\0';
537
actioned_message[23] = '\0';
563
action_required = US"-Mar";
538
action_required = US"-Mar";
Lines 565-580 Link Here
565
create_dialog(US"Recipient address to add?", US"");
540
create_dialog(US"Recipient address to add?", US"");
566
}
541
}
567
542
568
569
570
/*************************************************
543
/*************************************************
571
*    Cause an address to be marked delivered     *
544
*    Cause an address to be marked delivered     *
572
*************************************************/
545
*************************************************/
573
546
574
static void markdelAction(Widget w, XtPointer client_data, XtPointer call_data)
547
static void
548
markdelAction(Widget w, XtPointer client_data, XtPointer call_data)
575
{
549
{
576
w = w;      /* Keep picky compilers happy */
577
call_data = call_data;
578
Ustrncpy(actioned_message, client_data, 24);
550
Ustrncpy(actioned_message, client_data, 24);
579
actioned_message[23] = '\0';
551
actioned_message[23] = '\0';
580
action_required = US"-Mmd";
552
action_required = US"-Mmd";
Lines 582-611 Link Here
582
create_dialog(US"Recipient address to mark delivered?", US"");
554
create_dialog(US"Recipient address to mark delivered?", US"");
583
}
555
}
584
556
585
586
/*************************************************
557
/*************************************************
587
*   Cause all addresses to be marked delivered   *
558
*   Cause all addresses to be marked delivered   *
588
*************************************************/
559
*************************************************/
589
560
590
static void markalldelAction(Widget w, XtPointer client_data, XtPointer call_data)
561
static void
562
markalldelAction(Widget w, XtPointer client_data, XtPointer call_data)
591
{
563
{
592
w = w;      /* Keep picky compilers happy */
593
call_data = call_data;
594
ActOnMessage(US client_data, US"-Mmad", US"");
564
ActOnMessage(US client_data, US"-Mmad", US"");
595
}
565
}
596
566
597
598
/*************************************************
567
/*************************************************
599
*        Edit the message's sender               *
568
*        Edit the message's sender               *
600
*************************************************/
569
*************************************************/
601
570
602
static void editsenderAction(Widget w, XtPointer client_data,
571
static void
603
  XtPointer call_data)
572
editsenderAction(Widget w, XtPointer client_data, XtPointer call_data)
604
{
573
{
605
queue_item *q;
574
queue_item *q;
606
uschar *sender;
575
uschar *sender;
607
w = w;      /* Keep picky compilers happy */
576
608
call_data = call_data;
609
Ustrncpy(actioned_message, client_data, 24);
577
Ustrncpy(actioned_message, client_data, 24);
610
actioned_message[23] = '\0';
578
actioned_message[23] = '\0';
611
q = find_queue(actioned_message, queue_noop, 0);
579
q = find_queue(actioned_message, queue_noop, 0);
Lines 615-661 Link Here
615
create_dialog(US"New sender address?", sender);
583
create_dialog(US"New sender address?", sender);
616
}
584
}
617
585
618
619
/*************************************************
586
/*************************************************
620
*    Cause a message to be returned to sender    *
587
*    Cause a message to be returned to sender    *
621
*************************************************/
588
*************************************************/
622
589
623
static void giveupAction(Widget w, XtPointer client_data, XtPointer call_data)
590
static void
591
giveupAction(Widget w, XtPointer client_data, XtPointer call_data)
624
{
592
{
625
w = w;      /* Keep picky compilers happy */
626
call_data = call_data;
627
ActOnMessage(US client_data, US"-v -Mg", US"");
593
ActOnMessage(US client_data, US"-v -Mg", US"");
628
}
594
}
629
595
630
631
632
/*************************************************
596
/*************************************************
633
*      Cause a message to be cancelled           *
597
*      Cause a message to be cancelled           *
634
*************************************************/
598
*************************************************/
635
599
636
static void removeAction(Widget w, XtPointer client_data, XtPointer call_data)
600
static void
601
removeAction(Widget w, XtPointer client_data, XtPointer call_data)
637
{
602
{
638
w = w;      /* Keep picky compilers happy */
639
call_data = call_data;
640
ActOnMessage(US client_data, US"-Mrm", US"");
603
ActOnMessage(US client_data, US"-Mrm", US"");
641
}
604
}
642
605
643
644
645
/*************************************************
606
/*************************************************
646
*             Display a message's headers        *
607
*             Display a message's headers        *
647
*************************************************/
608
*************************************************/
648
609
649
static void headersAction(Widget w, XtPointer client_data, XtPointer call_data)
610
static void
611
headersAction(Widget w, XtPointer client_data, XtPointer call_data)
650
{
612
{
651
uschar buffer[256];
613
uschar buffer[256];
652
header_line *h, *next;
653
Widget text = text_create(US client_data, text_depth);
614
Widget text = text_create(US client_data, text_depth);
654
rmark reset_point;
615
rmark reset_point;
655
616
656
w = w;      /* Keep picky compilers happy */
657
call_data = call_data;
658
659
/* Remember the point in the dynamic store so we can recover to it afterwards.
617
/* Remember the point in the dynamic store so we can recover to it afterwards.
660
Then use Exim's function to read the header. */
618
Then use Exim's function to read the header. */
661
619
Lines 678-703 Link Here
678
  return;
636
  return;
679
  }
637
  }
680
638
681
if (sender_address != NULL)
639
if (sender_address)
682
  {
683
  text_showf(text, "%s sender: <%s>\n", f.sender_local ? "Local" : "Remote",
640
  text_showf(text, "%s sender: <%s>\n", f.sender_local ? "Local" : "Remote",
684
    sender_address);
641
    sender_address);
685
  }
686
642
687
if (recipients_list != NULL)
643
if (recipients_list)
688
  {
644
  {
689
  int i;
690
  text_show(text, US"Recipients:\n");
645
  text_show(text, US"Recipients:\n");
691
  for (i = 0; i < recipients_count; i++)
646
  for (int i = 0; i < recipients_count; i++)
692
    {
693
    text_showf(text, "  %s %s\n",
647
    text_showf(text, "  %s %s\n",
694
      (tree_search(tree_nonrecipients, recipients_list[i].address) == NULL)?
648
      tree_search(tree_nonrecipients, recipients_list[i].address)
695
        " ":"*", recipients_list[i].address);
649
        ? "*" : " ",
696
    }
650
      recipients_list[i].address);
697
  text_show(text, US"\n");
651
  text_show(text, US"\n");
698
  }
652
  }
699
653
700
for (h = header_list; h != NULL; h = next)
654
for (header_line * next, * h = header_list; h; h = next)
701
  {
655
  {
702
  next = h->next;
656
  next = h->next;
703
  text_showf(text, "%c ", h->type);   /* Don't push h->text through a %s */
657
  text_showf(text, "%c ", h->type);   /* Don't push h->text through a %s */
Lines 707-726 Link Here
707
store_reset(reset_point);
661
store_reset(reset_point);
708
}
662
}
709
663
710
711
712
713
/*************************************************
664
/*************************************************
714
*              Dismiss a text window             *
665
*              Dismiss a text window             *
715
*************************************************/
666
*************************************************/
716
667
717
static void dismissAction(Widget w, XtPointer client_data, XtPointer call_data)
668
static void
669
dismissAction(Widget w, XtPointer client_data, XtPointer call_data)
718
{
670
{
719
pipe_item *p = pipe_chain;
720
721
w = w;      /* Keep picky compilers happy */
722
call_data = call_data;
723
724
XtPopdown((Widget)client_data);
671
XtPopdown((Widget)client_data);
725
XtDestroyWidget((Widget)client_data);
672
XtDestroyWidget((Widget)client_data);
726
673
Lines 729-744 Link Here
729
to search the parents of the saved widget to see if one of them
676
to search the parents of the saved widget to see if one of them
730
is what we have just destroyed. */
677
is what we have just destroyed. */
731
678
732
while (p != NULL)
679
for (pipe_item * p = pipe_chain; p; p = p->next)
733
  {
680
  for (Widget pp = p->widget; pp; pp = XtParent(pp))
734
  Widget pp = p->widget;
735
  while (pp != NULL)
736
    {
737
    if (pp == (Widget)client_data) { p->widget = NULL; return; }
681
    if (pp == (Widget)client_data) { p->widget = NULL; return; }
738
    pp = XtParent(pp);
739
    }
740
  p = p->next;
741
  }
742
}
682
}
743
683
744
684
Lines 747-753 Link Here
747
*             Set up popup text window           *
687
*             Set up popup text window           *
748
*************************************************/
688
*************************************************/
749
689
750
static Widget text_create(uschar *name, int height)
690
static Widget
691
text_create(uschar *name, int height)
751
{
692
{
752
Widget textshell, form, text, button;
693
Widget textshell, form, text, button;
753
694
Lines 798-806 Link Here
798
return text;
739
return text;
799
}
740
}
800
741
801
802
803
804
/*************************************************
742
/*************************************************
805
*            Set up menu in queue window         *
743
*            Set up menu in queue window         *
806
*************************************************/
744
*************************************************/
Lines 808-814 Link Here
808
/* We have added an action table that causes this function to
746
/* We have added an action table that causes this function to
809
be called, and set up button 2 in the text widgets to call it. */
747
be called, and set up button 2 in the text widgets to call it. */
810
748
811
void menu_create(Widget w, XEvent *event, String *actargs, Cardinal *count)
749
void
750
menu_create(Widget w, XEvent *event, String *actargs, Cardinal *count)
812
{
751
{
813
int line;
752
int line;
814
int i;
753
int i;
Lines 824-832 Link Here
824
   <BtnUp>:         MenuPopdown()notify()unhighlight()\n\
763
   <BtnUp>:         MenuPopdown()notify()unhighlight()\n\
825
  ");
764
  ");
826
765
827
actargs = actargs;   /* Keep picky compilers happy */
828
count = count;
829
830
/* Get the sink and source and the current text pointer */
766
/* Get the sink and source and the current text pointer */
831
767
832
queue_get_arg[0].value = (XtArgVal)(&queue_text_sink);
768
queue_get_arg[0].value = (XtArgVal)(&queue_text_sink);
(-)exim.orig/exim_monitor/em_queue.c (-3 / +3 lines)
Lines 3-9 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
6
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 138-145 Link Here
138
acl_var_create(uschar *name)
138
acl_var_create(uschar *name)
139
{
139
{
140
tree_node *node, **root;
140
tree_node *node, **root;
141
root = (name[0] == 'c')? &acl_var_c : &acl_var_m;
141
root = name[0] == 'c' ? &acl_var_c : &acl_var_m;
142
node = store_get(sizeof(tree_node) + Ustrlen(name), FALSE);
142
node = store_get(sizeof(tree_node) + Ustrlen(name), GET_UNTAINTED);
143
Ustrcpy(node->name, name);
143
Ustrcpy(node->name, name);
144
node->data.ptr = NULL;
144
node->data.ptr = NULL;
145
(void)tree_insertnode(root, node);
145
(void)tree_insertnode(root, node);
(-)exim.orig/exim_monitor/em_TextPop.c (-4 / +4 lines)
Lines 1-4 Link Here
1
/***********************************************************
1
/***********************************************************
2
Copyright (c) The Exim Maintainers 2022
2
Copyright 1989 by the Massachusetts Institute of Technology,
3
Copyright 1989 by the Massachusetts Institute of Technology,
3
Cambridge, Massachusetts.
4
Cambridge, Massachusetts.
4
5
Lines 246-252 Link Here
246
  Arg args[1];
247
  Arg args[1];
247
248
248
#ifdef notdef
249
#ifdef notdef
249
  if (ctx->text.source->Search == NULL) {
250
  if (!ctx->text.source->Search) {
250
      XBell(XtDisplay(w), 0);
251
      XBell(XtDisplay(w), 0);
251
      return;
252
      return;
252
  }
253
  }
Lines 279-294 Link Here
279
    return;
280
    return;
280
  }
281
  }
281
282
282
  if (ctx->text.search== NULL) {
283
  if (!ctx->text.search) {
283
    ctx->text.search = XtNew(struct SearchAndReplace);
284
    ctx->text.search = XtNew(struct SearchAndReplace);
284
    ctx->text.search->search_popup = CreateDialog(w, ptr, "search",
285
    ctx->text.search->search_popup = CreateDialog(w, ptr, "search",
285
						  AddSearchChildren);
286
						  AddSearchChildren);
286
    XtRealizeWidget(ctx->text.search->search_popup);
287
    XtRealizeWidget(ctx->text.search->search_popup);
287
    SetWMProtocolTranslations(ctx->text.search->search_popup);
288
    SetWMProtocolTranslations(ctx->text.search->search_popup);
288
  }
289
  }
289
  else if (*num_params > 1) {
290
  else if (*num_params > 1)
290
    XtVaSetValues(ctx->text.search->search_text, XtNstring, ptr, NULL);
291
    XtVaSetValues(ctx->text.search->search_text, XtNstring, ptr, NULL);
291
  }
292
292
293
  XtSetArg(args[0], XtNeditType,&edit_mode);
293
  XtSetArg(args[0], XtNeditType,&edit_mode);
294
  XtGetValues(ctx->text.source, args, ONE);
294
  XtGetValues(ctx->text.source, args, ONE);
(-)exim.orig/exim_monitor/em_version.c (-1 / +1 lines)
Lines 3-9 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
6
/* Copyright (c) The Exim Maintainers 2020 - 2021 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#define EM_VERSION_C
9
#define EM_VERSION_C
(-)exim.orig/Makefile (+2 lines)
Lines 2-7 Link Here
2
# appropriate links, and then creating and running the main makefile in that
2
# appropriate links, and then creating and running the main makefile in that
3
# directory.
3
# directory.
4
4
5
# Copyright (c) The Exim Maintainers 2022
5
# Copyright (c) University of Cambridge, 1995 - 2018
6
# Copyright (c) University of Cambridge, 1995 - 2018
6
# See the file NOTICE for conditions of use and distribution.
7
# See the file NOTICE for conditions of use and distribution.
7
8
Lines 102-107 Link Here
102
cscope.files: FRC
103
cscope.files: FRC
103
	echo "-q" > $@
104
	echo "-q" > $@
104
	echo "-p3" >> $@
105
	echo "-p3" >> $@
106
	-bd=build-$(buildname); [ -d $$bd ] && echo -e "$$bd/config.h\n$$bd/Makefile" >> $@
105
	find src Local OS exim_monitor -name "*.[cshyl]" -print \
107
	find src Local OS exim_monitor -name "*.[cshyl]" -print \
106
		    -o -name "os.[ch]*" -print \
108
		    -o -name "os.[ch]*" -print \
107
		    -o -name "*akefile*" -print \
109
		    -o -name "*akefile*" -print \
(-)exim.orig/OS/Makefile-Base (-9 / +11 lines)
Lines 5-12 Link Here
5
# optional, Local/* files at the front of this file, to create Makefile in the
5
# optional, Local/* files at the front of this file, to create Makefile in the
6
# build directory.
6
# build directory.
7
#
7
#
8
# Copyright (c) The Exim Maintainers 1995 - 2018
8
# Copyright (c) The Exim Maintainers 1995 - 2022
9
# Copyright (c) The Exim Maintainers 2020
10
9
11
SHELL      = $(MAKE_SHELL)
10
SHELL      = $(MAKE_SHELL)
12
SCRIPTS    = ../scripts
11
SCRIPTS    = ../scripts
Lines 81-87 Link Here
81
# Build (link) the os.h file
80
# Build (link) the os.h file
82
81
83
os.h:	$(SCRIPTS)/Configure-os.h \
82
os.h:	$(SCRIPTS)/Configure-os.h \
84
	$(O)/os.h-Darwin	\
85
	$(O)/os.h-FreeBSD	\
83
	$(O)/os.h-FreeBSD	\
86
	$(O)/os.h-GNU		\
84
	$(O)/os.h-GNU		\
87
	$(O)/os.h-Linux		\
85
	$(O)/os.h-Linux		\
Lines 113-119 Link Here
113
111
114
OBJ_MACRO = macro_predef.o \
112
OBJ_MACRO = macro_predef.o \
115
	macro-globals.o macro-readconf.o macro-route.o macro-transport.o macro-drtables.o \
113
	macro-globals.o macro-readconf.o macro-route.o macro-transport.o macro-drtables.o \
116
	macro-tls.o \
114
	macro-acl.o macro-tls.o \
117
	macro-appendfile.o macro-autoreply.o macro-lmtp.o macro-pipe.o macro-queuefile.o \
115
	macro-appendfile.o macro-autoreply.o macro-lmtp.o macro-pipe.o macro-queuefile.o \
118
	macro-smtp.o macro-accept.o macro-dnslookup.o macro-ipliteral.o macro-iplookup.o \
116
	macro-smtp.o macro-accept.o macro-dnslookup.o macro-ipliteral.o macro-iplookup.o \
119
	macro-manualroute.o macro-queryprogram.o macro-redirect.o \
117
	macro-manualroute.o macro-queryprogram.o macro-redirect.o \
Lines 141-146 Link Here
141
macro-drtables.o :	drtables.c
139
macro-drtables.o :	drtables.c
142
	@echo "$(CC) -DMACRO_PREDEF drtables.c"
140
	@echo "$(CC) -DMACRO_PREDEF drtables.c"
143
	$(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ drtables.c
141
	$(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ drtables.c
142
macro-acl.o:	acl.c
143
	@echo "$(CC) -DMACRO_PREDEF acl.c"
144
	$(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ acl.c
144
macro-tls.o:	tls.c tls-gnu.c tls-openssl.c
145
macro-tls.o:	tls.c tls-gnu.c tls-openssl.c
145
	@echo "$(CC) -DMACRO_PREDEF tls.c"
146
	@echo "$(CC) -DMACRO_PREDEF tls.c"
146
	$(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ tls.c
147
	$(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ tls.c
Lines 474-480 Link Here
474
			dmarc.o \
475
			dmarc.o \
475
			imap_utf7.o \
476
			imap_utf7.o \
476
			spf.o \
477
			spf.o \
477
			srs.o \
478
			utf8.o
478
			utf8.o
479
479
480
# Targets for final binaries; the main one has a build number which is
480
# Targets for final binaries; the main one has a build number which is
Lines 484-490 Link Here
484
484
485
OBJ_EXIM = acl.o base64.o child.o crypt16.o daemon.o dbfn.o debug.o deliver.o \
485
OBJ_EXIM = acl.o base64.o child.o crypt16.o daemon.o dbfn.o debug.o deliver.o \
486
        directory.o dns.o drtables.o enq.o exim.o expand.o filter.o \
486
        directory.o dns.o drtables.o enq.o exim.o expand.o filter.o \
487
        filtertest.o globals.o dkim.o dkim_transport.o hash.o \
487
        filtertest.o globals.o dkim.o dkim_transport.o dnsbl.o hash.o \
488
        header.o host.o ip.o log.o lss.o match.o md5.o moan.o \
488
        header.o host.o ip.o log.o lss.o match.o md5.o moan.o \
489
        os.o parse.o priv.o queue.o \
489
        os.o parse.o priv.o queue.o \
490
        rda.o readconf.o receive.o retry.o rewrite.o rfc2047.o \
490
        rda.o readconf.o receive.o retry.o rewrite.o rfc2047.o \
Lines 635-645 Link Here
635
HDRS  =	blob.h \
635
HDRS  =	blob.h \
636
	config.h \
636
	config.h \
637
	dbfunctions.h \
637
	dbfunctions.h \
638
	dbstuff.h \
639
	exim.h \
638
	exim.h \
640
	functions.h \
639
	functions.h \
641
	globals.h \
640
	globals.h \
642
	hash.h \
641
	hash.h \
642
	hintsdb.h \
643
	hintsdb_structs.h \
643
	local_scan.h \
644
	local_scan.h \
644
	macros.h \
645
	macros.h \
645
	mytypes.h \
646
	mytypes.h \
Lines 648-657 Link Here
648
	os.h
649
	os.h
649
PHDRS = ../config.h \
650
PHDRS = ../config.h \
650
	../dbfunctions.h \
651
	../dbfunctions.h \
651
	../dbstuff.h \
652
	../exim.h \
652
	../exim.h \
653
	../functions.h \
653
	../functions.h \
654
	../globals.h \
654
	../globals.h \
655
	../hintsdb.h \
656
	../hintsdb_structs.h \
655
	../local_scan.h \
657
	../local_scan.h \
656
	../macros.h \
658
	../macros.h \
657
	../mytypes.h \
659
	../mytypes.h \
Lines 774-779 Link Here
774
deliver.o:       $(HDRS) transports/smtp.h deliver.c
776
deliver.o:       $(HDRS) transports/smtp.h deliver.c
775
directory.o:     $(HDRS) directory.c
777
directory.o:     $(HDRS) directory.c
776
dns.o:           $(HDRS) dns.c
778
dns.o:           $(HDRS) dns.c
779
dnsbl.o:         $(HDRS) dnsbl.c
777
enq.o:           $(HDRS) enq.c
780
enq.o:           $(HDRS) enq.c
778
exim.o:          $(HDRS) exim.c
781
exim.o:          $(HDRS) exim.c
779
expand.o:        $(HDRS) expand.c
782
expand.o:        $(HDRS) expand.c
Lines 839-845 Link Here
839
dmarc.o:	$(HDRS) pdkim/pdkim.h dmarc.h dmarc.c
842
dmarc.o:	$(HDRS) pdkim/pdkim.h dmarc.h dmarc.c
840
imap_utf7.o:	$(HDRS) imap_utf7.c
843
imap_utf7.o:	$(HDRS) imap_utf7.c
841
spf.o:		$(HDRS) spf.h spf.c
844
spf.o:		$(HDRS) spf.h spf.c
842
srs.o:		$(HDRS) srs.h srs.c
843
utf8.o:		$(HDRS) utf8.c
845
utf8.o:		$(HDRS) utf8.c
844
846
845
# The module containing tables of available lookups, routers, auths, and
847
# The module containing tables of available lookups, routers, auths, and
(-)exim.orig/OS/Makefile-Default (-1 / +1 lines)
Lines 89-95 Link Here
89
89
90
# PCRE_LIBS contains the library to be linked for PCRE
90
# PCRE_LIBS contains the library to be linked for PCRE
91
91
92
PCRE_LIBS=-lpcre
92
PCRE_LIBS=-lpcre2-8
93
93
94
94
95
# LIBS and EXTRALIBS contain library settings that are used on linking
95
# LIBS and EXTRALIBS contain library settings that are used on linking
(-)exim.orig/OS/Makefile-FreeBSD (-1 / +1 lines)
Lines 2-8 Link Here
2
# Copyright (c) The Exim Maintainers 2020
2
# Copyright (c) The Exim Maintainers 2020
3
3
4
CHOWN_COMMAND=/usr/sbin/chown
4
CHOWN_COMMAND=/usr/sbin/chown
5
STRIP_COMMAND=/usr/bin/strip
5
#STRIP_COMMAND=/usr/bin/strip
6
CHMOD_COMMAND=/bin/chmod
6
CHMOD_COMMAND=/bin/chmod
7
7
8
8
(-)exim.orig/OS/Makefile-OpenBSD (-3 / +3 lines)
Lines 1-5 Link Here
1
# Exim: OS-specific make file for OpenBSD
1
# Exim: OS-specific make file for OpenBSD
2
# Copyright (c) The Exim Maintainers 2020
2
# Copyright (c) The Exim Maintainers 2022
3
3
4
CHOWN_COMMAND=/usr/sbin/chown
4
CHOWN_COMMAND=/usr/sbin/chown
5
CHGRP_COMMAND=/usr/sbin/chgrp
5
CHGRP_COMMAND=/usr/sbin/chgrp
Lines 24-30 Link Here
24
24
25
HAVE_IPV6=YES
25
HAVE_IPV6=YES
26
26
27
# OpenBSD always ships with Berkeley DB
27
# OpenBSD ships with a too-old Berkeley DB.  NDBM is the default if we don't specify one.
28
USE_DB=yes
28
#USE_DB=yes
29
29
30
# End
30
# End
(-)exim.orig/OS/os.c-FreeBSD (-2 / +4 lines)
Lines 3-8 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) Jeremy Harris 1995 - 2020 */
5
/* Copyright (c) Jeremy Harris 1995 - 2020 */
6
/* Copyright (c) The Exim Maintainers 2021 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
8
/* FreeBSD-specific code. This is concatenated onto the generic
9
/* FreeBSD-specific code. This is concatenated onto the generic
Lines 16-25 Link Here
16
ssize_t
17
ssize_t
17
os_sendfile(int out, int in, off_t * offp, size_t cnt)
18
os_sendfile(int out, int in, off_t * offp, size_t cnt)
18
{
19
{
19
off_t loff = *offp, written;
20
off_t loff = offp ? *offp : 0;
21
off_t written;
20
22
21
if (sendfile(in, out, loff, cnt, NULL, &written, 0) < 0) return (ssize_t)-1;
23
if (sendfile(in, out, loff, cnt, NULL, &written, 0) < 0) return (ssize_t)-1;
22
*offp = loff + written;
24
if (offp) *offp = loff + written;
23
return (ssize_t)written;
25
return (ssize_t)written;
24
}
26
}
25
27
(-)exim.orig/OS/os.h-FreeBSD (-1 / +11 lines)
Lines 1-6 Link Here
1
/* Exim: OS-specific C header file for FreeBSD */
1
/* Exim: OS-specific C header file for FreeBSD */
2
/* Copyright (c) University of Cambridge 1995 - 2018 */
2
/* Copyright (c) University of Cambridge 1995 - 2018 */
3
/* Copyright (c) The Exim Maintainers 2020 */
3
/* Copyright (c) The Exim Maintainers 2020 - 2021 */
4
/* See the file NOTICE for conditions of use and distribution. */
4
/* See the file NOTICE for conditions of use and distribution. */
5
5
6
6
Lines 11-19 Link Here
11
#define HAVE_SETCLASSRESOURCES
11
#define HAVE_SETCLASSRESOURCES
12
#define HAVE_MMAP
12
#define HAVE_MMAP
13
#define HAVE_SYS_MOUNT_H
13
#define HAVE_SYS_MOUNT_H
14
#define HAVE_GETIFADDRS
14
#define SIOCGIFCONF_GIVES_ADDR
15
#define SIOCGIFCONF_GIVES_ADDR
15
#define HAVE_SRANDOMDEV
16
#define HAVE_SRANDOMDEV
16
#define HAVE_ARC4RANDOM
17
#define HAVE_ARC4RANDOM
18
#define EXIM_HAVE_OPENAT
19
#define EXIM_HAVE_FUTIMENS
17
20
18
/* Applications should not call arc4random_stir() explicitly after
21
/* Applications should not call arc4random_stir() explicitly after
19
 * FreeBSD r227520 (approximately 1000002).
22
 * FreeBSD r227520 (approximately 1000002).
Lines 55-60 Link Here
55
#define OS_SENDFILE
58
#define OS_SENDFILE
56
extern ssize_t os_sendfile(int, int, off_t *, size_t);
59
extern ssize_t os_sendfile(int, int, off_t *, size_t);
57
60
61
#ifdef PID_T_FMT
62
# undef PID_T_FMT
63
#endif
64
#define PID_T_FMT "%d"
65
58
66
59
/*******************/
67
/*******************/
60
68
Lines 68-71 Link Here
68
76
69
/*******************/
77
/*******************/
70
78
79
#define EXIM_HAVE_KEVENT
80
71
/* End */
81
/* End */
(-)exim.orig/OS/os.h-GNU (-1 / +1 lines)
Lines 1-5 Link Here
1
/* Exim: OS-specific C header file for GNU/Hurd */
1
/* Exim: OS-specific C header file for GNU/Hurd */
2
/* Copyright (c) The Exim Maintainers 2020 */
2
/* Copyright (c) The Exim Maintainers 2020 - 2021 */
3
3
4
#include <features.h>
4
#include <features.h>
5
5
(-)exim.orig/OS/os.h-Linux (-1 / +11 lines)
Lines 1-5 Link Here
1
/* Exim: OS-specific C header file for Linux */
1
/* Exim: OS-specific C header file for Linux */
2
/* Copyright (c) University of Cambridge 1995 - 2020 */
2
/* Copyright (c) University of Cambridge 1995 - 2020 */
3
/* Copyright (c) The Exim Maintainers 2021 */
3
/* See the file NOTICE for conditions of use and distribution. */
4
/* See the file NOTICE for conditions of use and distribution. */
4
5
5
6
Lines 16-21 Link Here
16
#define HAVE_MMAP
17
#define HAVE_MMAP
17
#define HAVE_BSD_GETLOADAVG
18
#define HAVE_BSD_GETLOADAVG
18
#define HAVE_SYS_STATVFS_H
19
#define HAVE_SYS_STATVFS_H
20
#define HAVE_GETIFADDRS
19
#define NO_IP_VAR_H
21
#define NO_IP_VAR_H
20
#define SIG_IGN_WORKS
22
#define SIG_IGN_WORKS
21
23
Lines 71-78 Link Here
71
# define LLONG_MAX LONG_LONG_MAX
73
# define LLONG_MAX LONG_LONG_MAX
72
#endif
74
#endif
73
75
74
#if _POSIX_C_SOURCE >= 200809L || _ATFILE_SOUCE
76
#if _POSIX_C_SOURCE >= 200809L || _ATFILE_SOURCE
75
# define EXIM_HAVE_OPENAT
77
# define EXIM_HAVE_OPENAT
78
# define EXIM_HAVE_FUTIMENS
76
#endif
79
#endif
77
80
78
/* TCP Fast Open support */
81
/* TCP Fast Open support */
Lines 90-94 Link Here
90
/* "Abstract" Unix-socket names */
93
/* "Abstract" Unix-socket names */
91
#define EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
94
#define EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
92
95
96
/* inotify(7) etc syscalls */
97
#define EXIM_HAVE_INOTIFY
98
99
/* Needed for uClibc */
100
#ifndef NS_MAXMSG
101
# define NS_MAXMSG 65535
102
#endif
93
103
94
/* End */
104
/* End */
(-)exim.orig/OS/os.h-OpenBSD (-1 / +6 lines)
Lines 1-12 Link Here
1
/* Exim: OS-specific C header file for OpenBSD */
1
/* Exim: OS-specific C header file for OpenBSD */
2
/* Copyright (c) University of Cambridge 1995 - 2018 */
2
/* Copyright (c) University of Cambridge 1995 - 2018 */
3
/* Copyright (c) The Exim Maintainers 2021 */
3
/* See the file NOTICE for conditions of use and distribution. */
4
/* See the file NOTICE for conditions of use and distribution. */
4
5
5
6
6
#define HAVE_BSD_GETLOADAVG
7
#define HAVE_BSD_GETLOADAVG
7
#define HAVE_MMAP
8
#define HAVE_MMAP
8
#define HAVE_SYS_MOUNT_H
9
#define HAVE_SYS_MOUNT_H
9
#define SIOCGIFCONF_GIVES_ADDR
10
#define HAVE_GETIFADDRS
11
#define EXIM_HAVE_OPENAT
12
#define EXIM_HAVE_FUTIMENS
10
#define HAVE_ARC4RANDOM
13
#define HAVE_ARC4RANDOM
11
/* In May 2014, OpenBSD 5.5 was released which cleaned up the arc4random_* API
14
/* In May 2014, OpenBSD 5.5 was released which cleaned up the arc4random_* API
12
   which removed the arc4random_stir() function. Set NOT_HAVE_ARC4RANDOM_STIR
15
   which removed the arc4random_stir() function. Set NOT_HAVE_ARC4RANDOM_STIR
Lines 57-60 Link Here
57
Space-constrained devices could use much smaller; a few k. */
60
Space-constrained devices could use much smaller; a few k. */
58
#define NS_MAXMSG 65535
61
#define NS_MAXMSG 65535
59
62
63
#define EXIM_HAVE_KEVENT
64
60
/* End */
65
/* End */
(-)exim.orig/OS/os.h-SunOS5 (+7 lines)
Lines 1-4 Link Here
1
/* Exim: OS-specific C header file for SunOS5 aka Solaris */
1
/* Exim: OS-specific C header file for SunOS5 aka Solaris */
2
/* Copyright (c) The Exim Maintainers 2021 */
2
3
3
#define CRYPT_H
4
#define CRYPT_H
4
#define HAVE_MMAP
5
#define HAVE_MMAP
Lines 8-13 Link Here
8
9
9
#define HAVE_GETIPNODEBYNAME    1
10
#define HAVE_GETIPNODEBYNAME    1
10
#define HAVE_GETIPNODEBYADDR    1
11
#define HAVE_GETIPNODEBYADDR    1
12
#define EXIM_HAVE_OPENAT
13
#define EXIM_HAVE_FUTIMENS
11
14
12
#define HAVE_KSTAT
15
#define HAVE_KSTAT
13
#define LOAD_AVG_KSTAT         "system_misc"
16
#define LOAD_AVG_KSTAT         "system_misc"
Lines 36-41 Link Here
36
# define MISSING_UNSETENV_3
39
# define MISSING_UNSETENV_3
37
#endif
40
#endif
38
41
42
#if _POSIX_C_SOURCE < 200809L
43
# define MISSING_POSIX_MEMALIGN
44
#endif
45
39
46
40
/* SunOS5 doesn't accept getcwd(NULL, 0) to auto-allocate
47
/* SunOS5 doesn't accept getcwd(NULL, 0) to auto-allocate
41
a buffer */
48
a buffer */
(-)exim.orig/OS/unsupported/os.c-IRIX (-1 / +2 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2022 */
5
/* Copyright (c) University of Cambridge 2001 */
6
/* Copyright (c) University of Cambridge 2001 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 59-65 Link Here
59
  log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
60
  log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
60
    strerror(errno));
61
    strerror(errno));
61
62
62
buf = store_get(needed, FALSE);
63
buf = store_get(needed, GET_UNTAINTED);
63
64
64
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
65
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
65
  log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
66
  log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
(-)exim.orig/OS/unsupported/os.c-IRIX6 (-1 / +2 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2022 */
5
/* Copyright (c) University of Cambridge 2001 */
6
/* Copyright (c) University of Cambridge 2001 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 59-65 Link Here
59
  log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
60
  log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
60
    strerror(errno));
61
    strerror(errno));
61
62
62
buf = store_get(needed, FALSE);
63
buf = store_get(needed, GET_UNTAINTED);
63
64
64
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
65
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
65
  log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
66
  log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
(-)exim.orig/OS/unsupported/os.c-IRIX632 (-1 / +2 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2022 */
5
/* Copyright (c) University of Cambridge 2001 */
6
/* Copyright (c) University of Cambridge 2001 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 59-65 Link Here
59
  log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
60
  log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
60
    strerror(errno));
61
    strerror(errno));
61
62
62
buf = store_get(needed, FALSE);
63
buf = store_get(needed, GET_UNTAINTED);
63
64
64
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
65
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
65
  log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
66
  log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
(-)exim.orig/OS/unsupported/os.c-IRIX65 (-1 / +2 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2022 */
5
/* Copyright (c) University of Cambridge 2001 */
6
/* Copyright (c) University of Cambridge 2001 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 59-65 Link Here
59
  log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
60
  log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
60
    strerror(errno));
61
    strerror(errno));
61
62
62
buf = store_get(needed, FALSE);
63
buf = store_get(needed, GET_UNTAINTED);
63
64
64
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
65
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
65
  log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
66
  log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
(-)exim.orig/OS/unsupported/os.h-NetBSD (+3 lines)
Lines 1-4 Link Here
1
/* Exim: OS-specific C header file for NetBSD */
1
/* Exim: OS-specific C header file for NetBSD */
2
/* Copyright (c) The Exim Maintainers 2021 */
2
3
3
#define HAVE_BSD_GETLOADAVG
4
#define HAVE_BSD_GETLOADAVG
4
#define HAVE_GETIFADDRS
5
#define HAVE_GETIFADDRS
Lines 25-28 Link Here
25
/* default is non-const */
26
/* default is non-const */
26
#define ICONV_ARG2_TYPE const char **
27
#define ICONV_ARG2_TYPE const char **
27
28
29
#define EXIM_HAVE_KEVENT
30
28
/* End */
31
/* End */
(-)exim.orig/scripts/Configure-Makefile (-5 / +25 lines)
Lines 7-13 Link Here
7
# just got too horrendous to get it right in "make", because of the optionally
7
# just got too horrendous to get it right in "make", because of the optionally
8
# existing configuration files.
8
# existing configuration files.
9
#
9
#
10
# Copyright (c) The Exim Maintainers 1995 - 2020
10
# Copyright (c) The Exim Maintainers 1995 - 2021
11
11
12
12
13
# First off, get the OS type, and check that there is a make file for it.
13
# First off, get the OS type, and check that there is a make file for it.
Lines 150-156 Link Here
150
egrep "^[$st]*(AUTH|LOOKUP)_[A-Z0-9_]*[$st]*=[$st]*" $mft | \
150
egrep "^[$st]*(AUTH|LOOKUP)_[A-Z0-9_]*[$st]*=[$st]*" $mft | \
151
  sed "s/[$st]*=/='/" | \
151
  sed "s/[$st]*=/='/" | \
152
  sed "s/\$/'/" > $mftt
152
  sed "s/\$/'/" > $mftt
153
egrep "^[$st]*((USE_(OPENSSL|GNUTLS)_PC)|SUPPORT_TLS|USE_GNUTLS|PCRE_CONFIG|AVOID_GNUTLS_PKCS11)[$st]*=[$st]*" $mft | \
153
egrep "^[$st]*((USE_(OPENSSL|GNUTLS)_PC)|SUPPORT_TLS|USE_GNUTLS|PCRE2?_CONFIG|AVOID_GNUTLS_PKCS11)[$st]*=[$st]*" $mft | \
154
  sed "s/[$st]*=/='/" | \
154
  sed "s/[$st]*=/='/" | \
155
  sed "s/\$/'/" >> $mftt
155
  sed "s/\$/'/" >> $mftt
156
if test -s $mftt
156
if test -s $mftt
Lines 233-244 Link Here
233
      PCRE_CONFIG)
233
      PCRE_CONFIG)
234
        case $PCRE_CONFIG in
234
        case $PCRE_CONFIG in
235
          yes|YES|y|Y)
235
          yes|YES|y|Y)
236
            cflags=`pcre-config --cflags`
236
	     echo >&2 "pcre is no longer supported; migrate to pcre2"
237
	     exit 1
238
239
#            cflags=`pcre-config --cflags`
240
#            if [ $? -ne 0 ]; then
241
#              echo >&2 "*** Missing pcre-config for regular expression support"
242
#              exit 1
243
#            fi
244
#            libs=`pcre-config --libs`
245
#            if [ ".$cflags" != "." ]; then
246
#              echo "INCLUDE += $cflags"
247
#            fi
248
#            echo "PCRE_LIBS=$libs"
249
            ;;
250
        esac
251
        ;;
252
253
      PCRE2_CONFIG)
254
        case $PCRE2_CONFIG in
255
          yes|YES|y|Y)
256
            cflags=`pcre2-config --cflags`
237
            if [ $? -ne 0 ]; then
257
            if [ $? -ne 0 ]; then
238
              echo >&2 "*** Missing pcre-config for regular expression support"
258
              echo >&2 "*** Missing pcre2-config for regular expression support"
239
              exit 1
259
              exit 1
240
            fi
260
            fi
241
            libs=`pcre-config --libs`
261
            libs=`pcre2-config --libs8`
242
            if [ ".$cflags" != "." ]; then
262
            if [ ".$cflags" != "." ]; then
243
              echo "INCLUDE += $cflags"
263
              echo "INCLUDE += $cflags"
244
            fi
264
            fi
(-)exim.orig/scripts/lookups-Makefile (-6 / +3 lines)
Lines 1-5 Link Here
1
#! /bin/sh
1
#! /bin/sh
2
2
3
# Copyright (c) The Exim Maintainers 1995 - 2021
4
3
# We turn the configure-built build-$foo/lookups/Makefile.predynamic into Makefile
5
# We turn the configure-built build-$foo/lookups/Makefile.predynamic into Makefile
4
6
5
# We always re-exec ourselves at least once, because it's the cleanest and
7
# We always re-exec ourselves at least once, because it's the cleanest and
Lines 160-166 Link Here
160
sed -n "1,/$tag_marker/p" < "$input"
162
sed -n "1,/$tag_marker/p" < "$input"
161
163
162
for name_mod in \
164
for name_mod in \
163
    CDB DBM:dbmdb DNSDB DSEARCH IBASE JSON LSEARCH MYSQL NIS NISPLUS ORACLE \
165
    CDB DBM:dbmdb DNSDB DSEARCH IBASE JSON LMDB LSEARCH MYSQL NIS NISPLUS ORACLE \
164
    PASSWD PGSQL REDIS SQLITE TESTDB WHOSON
166
    PASSWD PGSQL REDIS SQLITE TESTDB WHOSON
165
do
167
do
166
  emit_module_rule $name_mod
168
  emit_module_rule $name_mod
Lines 177-187 Link Here
177
179
178
OBJ="${OBJ} spf.o"
180
OBJ="${OBJ} spf.o"
179
181
180
if want_experimental LMDB
181
then
182
  OBJ="${OBJ} lmdb.o"
183
fi
184
185
# readsock is always wanted as it implements the ${readsock } expansion
182
# readsock is always wanted as it implements the ${readsock } expansion
186
OBJ="${OBJ} readsock.o"
183
OBJ="${OBJ} readsock.o"
187
184
(-)exim.orig/scripts/MakeLinks (-4 / +4 lines)
Lines 3-9 Link Here
3
# Script to build links for all the exim source files from the system-
3
# Script to build links for all the exim source files from the system-
4
# specific build directory. It should be run from within that directory.
4
# specific build directory. It should be run from within that directory.
5
#
5
#
6
# Copyright (c) The Exim Maintainers 1995 - 2020
6
# Copyright (c) The Exim Maintainers 1995 - 2022
7
7
8
test ! -d ../src && \
8
test ! -d ../src && \
9
  echo "*** $0 should be run in a system-specific subdirectory." && \
9
  echo "*** $0 should be run in a system-specific subdirectory." && \
Lines 95-106 Link Here
95
# but local_scan.c does not, because its location is taken from the build-time
95
# but local_scan.c does not, because its location is taken from the build-time
96
# configuration. Likewise for the os.c file, which gets build dynamically.
96
# configuration. Likewise for the os.c file, which gets build dynamically.
97
97
98
for f in blob.h dbfunctions.h dbstuff.h exim.h functions.h globals.h \
98
for f in blob.h dbfunctions.h exim.h functions.h globals.h \
99
  hash.h local_scan.h \
99
  hash.h hintsdb.h hintsdb_structs.h local_scan.h \
100
  macros.h mytypes.h osfunctions.h store.h structs.h lookupapi.h sha_ver.h \
100
  macros.h mytypes.h osfunctions.h store.h structs.h lookupapi.h sha_ver.h \
101
  \
101
  \
102
  acl.c buildconfig.c base64.c child.c crypt16.c daemon.c dbfn.c debug.c \
102
  acl.c buildconfig.c base64.c child.c crypt16.c daemon.c dbfn.c debug.c \
103
  deliver.c directory.c dns.c drtables.c dummies.c enq.c exim.c \
103
  deliver.c directory.c dns.c dnsbl.c drtables.c dummies.c enq.c exim.c \
104
  exim_dbmbuild.c exim_dbutil.c exim_lock.c expand.c filter.c filtertest.c \
104
  exim_dbmbuild.c exim_dbutil.c exim_lock.c expand.c filter.c filtertest.c \
105
  globals.c hash.c header.c host.c ip.c log.c lss.c match.c md5.c moan.c \
105
  globals.c hash.c header.c host.c ip.c log.c lss.c match.c md5.c moan.c \
106
  parse.c perl.c priv.c queue.c rda.c readconf.c receive.c retry.c rewrite.c \
106
  parse.c perl.c priv.c queue.c rda.c readconf.c receive.c retry.c rewrite.c \
(-)exim.orig/scripts/reversion (-4 / +11 lines)
Lines 1-5 Link Here
1
#!/bin/sh
1
#!/bin/sh
2
# Copyright (c) The Exim Maintainers 1995 - 2018
2
# Copyright (c) The Exim Maintainers 1995 - 2021
3
3
4
set -e
4
set -e
5
LC_ALL=C
5
LC_ALL=C
Lines 29-35 Link Here
29
# Read version information that was generated by a previous run of
29
# Read version information that was generated by a previous run of
30
# this script, or during the release process.
30
# this script, or during the release process.
31
31
32
if   [ -f ./version.sh ]; then
32
# Override, used for automated testing w/o access to the
33
# .git directory (w.g. inside a git worktree)
34
if   [ -n "$EXIM_RELEASE_VERSION" ]; then
35
    :
36
elif   [ -f ./version.sh ]; then
33
    .    ./version.sh
37
    .    ./version.sh
34
elif [ -f ../src/version.sh ]; then
38
elif [ -f ../src/version.sh ]; then
35
    .    ../src/version.sh
39
    .    ../src/version.sh
Lines 51-59 Link Here
51
            EXIM_VARIANT_VERSION="$3"
55
            EXIM_VARIANT_VERSION="$3"
52
            rm -f version.h
56
            rm -f version.h
53
    fi
57
    fi
54
else
58
fi
59
60
if [ -z "$EXIM_RELEASE_VERSION" ]; then
55
    echo "Cannot determine the release number" >&2
61
    echo "Cannot determine the release number" >&2
56
    exit
62
    echo "You may want to override it with EXIM_RELEASE_VERSION" >&2
63
    exit 1
57
fi
64
fi
58
65
59
# If you are maintaining a patched version of Exim, you can either
66
# If you are maintaining a patched version of Exim, you can either
(-)exim.orig/src/acl.c (-89 / +401 lines)
Lines 2-20 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Code for handling Access Control Lists (ACLs) */
9
/* Code for handling Access Control Lists (ACLs) */
10
10
11
#include "exim.h"
11
#include "exim.h"
12
12
13
#ifndef MACRO_PREDEF
13
14
14
/* Default callout timeout */
15
/* Default callout timeout */
15
16
16
#define CALLOUT_TIMEOUT_DEFAULT 30
17
#define CALLOUT_TIMEOUT_DEFAULT 30
17
18
19
/* Default quota cache TTLs */
20
21
#define QUOTA_POS_DEFAULT (5*60)
22
#define QUOTA_NEG_DEFAULT (60*60)
23
24
18
/* ACL verb codes - keep in step with the table of verbs that follows */
25
/* ACL verb codes - keep in step with the table of verbs that follows */
19
26
20
enum { ACL_ACCEPT, ACL_DEFER, ACL_DENY, ACL_DISCARD, ACL_DROP, ACL_REQUIRE,
27
enum { ACL_ACCEPT, ACL_DEFER, ACL_DENY, ACL_DISCARD, ACL_DROP, ACL_REQUIRE,
Lines 47-52 Link Here
47
  [ACL_WARN] =		BIT(OK)
54
  [ACL_WARN] =		BIT(OK)
48
  };
55
  };
49
56
57
#endif
58
50
/* ACL condition and modifier codes - keep in step with the table that
59
/* ACL condition and modifier codes - keep in step with the table that
51
follows.
60
follows.
52
down. */
61
down. */
Lines 97-102 Link Here
97
       ACLC_REGEX,
106
       ACLC_REGEX,
98
#endif
107
#endif
99
       ACLC_REMOVE_HEADER,
108
       ACLC_REMOVE_HEADER,
109
       ACLC_SEEN,
100
       ACLC_SENDER_DOMAINS,
110
       ACLC_SENDER_DOMAINS,
101
       ACLC_SENDERS,
111
       ACLC_SENDERS,
102
       ACLC_SET,
112
       ACLC_SET,
Lines 282-287 Link Here
282
				    ACL_BIT_MIME | ACL_BIT_NOTSMTP |
292
				    ACL_BIT_MIME | ACL_BIT_NOTSMTP |
283
				    ACL_BIT_NOTSMTP_START),
293
				    ACL_BIT_NOTSMTP_START),
284
  },
294
  },
295
  [ACLC_SEEN] =			{ US"seen",		TRUE, FALSE,	0 },
285
  [ACLC_SENDER_DOMAINS] =	{ US"sender_domains",	FALSE, FALSE,
296
  [ACLC_SENDER_DOMAINS] =	{ US"sender_domains",	FALSE, FALSE,
286
				  ACL_BIT_AUTH | ACL_BIT_CONNECT |
297
				  ACL_BIT_AUTH | ACL_BIT_CONNECT |
287
				    ACL_BIT_HELO |
298
				    ACL_BIT_HELO |
Lines 332-337 Link Here
332
};
343
};
333
344
334
345
346
#ifdef MACRO_PREDEF
347
# include "macro_predef.h"
348
void
349
features_acl(void)
350
{
351
for (condition_def * c = conditions; c < conditions + nelem(conditions); c++)
352
  {
353
  uschar buf[64], * p, * s;
354
  int n = sprintf(CS buf, "_ACL_%s_", c->is_modifier ? "MOD" : "COND");
355
  for (p = buf + n, s = c->name; *s; s++) *p++ = toupper(*s);
356
  *p = '\0';
357
  builtin_macro_create(buf);
358
  }
359
}
360
#endif
361
362
363
#ifndef MACRO_PREDEF
335
364
336
/* Return values from decode_control(); used as index so keep in step
365
/* Return values from decode_control(); used as index so keep in step
337
with the controls_list table that follows! */
366
with the controls_list table that follows! */
Lines 613-618 Link Here
613
static int acl_check_wargs(int, address_item *, const uschar *, uschar **,
642
static int acl_check_wargs(int, address_item *, const uschar *, uschar **,
614
    uschar **);
643
    uschar **);
615
644
645
static acl_block * acl_current = NULL;
646
616
647
617
/*************************************************
648
/*************************************************
618
*            Find control in list                *
649
*            Find control in list                *
Lines 777-783 Link Here
777
      *error = string_sprintf("malformed ACL line \"%s\"", saveline);
808
      *error = string_sprintf("malformed ACL line \"%s\"", saveline);
778
      return NULL;
809
      return NULL;
779
      }
810
      }
780
    this = store_get(sizeof(acl_block), FALSE);
811
    this = store_get(sizeof(acl_block), GET_UNTAINTED);
781
    *lastp = this;
812
    *lastp = this;
782
    lastp = &(this->next);
813
    lastp = &(this->next);
783
    this->next = NULL;
814
    this->next = NULL;
Lines 824-830 Link Here
824
    return NULL;
855
    return NULL;
825
    }
856
    }
826
857
827
  cond = store_get(sizeof(acl_condition_block), FALSE);
858
  cond = store_get(sizeof(acl_condition_block), GET_UNTAINTED);
828
  cond->next = NULL;
859
  cond->next = NULL;
829
  cond->type = c;
860
  cond->type = c;
830
  cond->u.negated = negated;
861
  cond->u.negated = negated;
Lines 1023-1029 Link Here
1023
    {
1054
    {
1024
    /* The header_line struct itself is not tainted, though it points to
1055
    /* The header_line struct itself is not tainted, though it points to
1025
    possibly tainted data. */
1056
    possibly tainted data. */
1026
    header_line * h = store_get(sizeof(header_line), FALSE);
1057
    header_line * h = store_get(sizeof(header_line), GET_UNTAINTED);
1027
    h->text = hdr;
1058
    h->text = hdr;
1028
    h->next = NULL;
1059
    h->next = NULL;
1029
    h->type = newtype;
1060
    h->type = newtype;
Lines 1180-1190 Link Here
1180
{
1211
{
1181
int rc;
1212
int rc;
1182
1213
1183
user_msgptr = user_msgptr;  /* stop compiler warning */
1184
1185
/* Previous success */
1214
/* Previous success */
1186
1215
1187
if (sender_host_name != NULL) return OK;
1216
if (sender_host_name) return OK;
1188
1217
1189
/* Previous failure */
1218
/* Previous failure */
1190
1219
Lines 1309-1319 Link Here
1309
tree_node *t;
1338
tree_node *t;
1310
const uschar *found;
1339
const uschar *found;
1311
int priority, weight, port;
1340
int priority, weight, port;
1312
dns_answer * dnsa = store_get_dns_answer();
1341
dns_answer * dnsa;
1313
dns_scan dnss;
1342
dns_scan dnss;
1314
dns_record *rr;
1343
dns_record *rr;
1315
int rc, type;
1344
int rc, type, yield;
1316
uschar target[256];
1345
#define TARGET_SIZE 256
1346
uschar * target = store_get(TARGET_SIZE, GET_TAINTED);
1317
1347
1318
/* Work out the domain we are using for the CSA lookup. The default is the
1348
/* Work out the domain we are using for the CSA lookup. The default is the
1319
client's HELO domain. If the client has not said HELO, use its IP address
1349
client's HELO domain. If the client has not said HELO, use its IP address
Lines 1321-1328 Link Here
1321
1351
1322
while (isspace(*domain) && *domain != '\0') ++domain;
1352
while (isspace(*domain) && *domain != '\0') ++domain;
1323
if (*domain == '\0') domain = sender_helo_name;
1353
if (*domain == '\0') domain = sender_helo_name;
1324
if (domain == NULL) domain = sender_host_address;
1354
if (!domain) domain = sender_host_address;
1325
if (sender_host_address == NULL) return CSA_UNKNOWN;
1355
if (!sender_host_address) return CSA_UNKNOWN;
1326
1356
1327
/* If we have an address literal, strip off the framing ready for turning it
1357
/* If we have an address literal, strip off the framing ready for turning it
1328
into a domain. The framing consists of matched square brackets possibly
1358
into a domain. The framing consists of matched square brackets possibly
Lines 1352-1384 Link Here
1352
for this domain. The name is filled in now, and the value is filled in when
1382
for this domain. The name is filled in now, and the value is filled in when
1353
we return from this function. */
1383
we return from this function. */
1354
1384
1355
t = tree_search(csa_cache, domain);
1385
if ((t = tree_search(csa_cache, domain)))
1356
if (t != NULL) return t->data.val;
1386
  return t->data.val;
1357
1387
1358
t = store_get_perm(sizeof(tree_node) + Ustrlen(domain), is_tainted(domain));
1388
t = store_get_perm(sizeof(tree_node) + Ustrlen(domain), domain);
1359
Ustrcpy(t->name, domain);
1389
Ustrcpy(t->name, domain);
1360
(void)tree_insertnode(&csa_cache, t);
1390
(void)tree_insertnode(&csa_cache, t);
1361
1391
1362
/* Now we are ready to do the actual DNS lookup(s). */
1392
/* Now we are ready to do the actual DNS lookup(s). */
1363
1393
1364
found = domain;
1394
found = domain;
1395
dnsa = store_get_dns_answer();
1365
switch (dns_special_lookup(dnsa, domain, T_CSA, &found))
1396
switch (dns_special_lookup(dnsa, domain, T_CSA, &found))
1366
  {
1397
  {
1367
  /* If something bad happened (most commonly DNS_AGAIN), defer. */
1398
  /* If something bad happened (most commonly DNS_AGAIN), defer. */
1368
1399
1369
  default:
1400
  default:
1370
  return t->data.val = CSA_DEFER_SRV;
1401
    yield = CSA_DEFER_SRV;
1402
    goto out;
1371
1403
1372
  /* If we found nothing, the client's authorization is unknown. */
1404
  /* If we found nothing, the client's authorization is unknown. */
1373
1405
1374
  case DNS_NOMATCH:
1406
  case DNS_NOMATCH:
1375
  case DNS_NODATA:
1407
  case DNS_NODATA:
1376
  return t->data.val = CSA_UNKNOWN;
1408
    yield = CSA_UNKNOWN;
1409
    goto out;
1377
1410
1378
  /* We got something! Go on to look at the reply in more detail. */
1411
  /* We got something! Go on to look at the reply in more detail. */
1379
1412
1380
  case DNS_SUCCEED:
1413
  case DNS_SUCCEED:
1381
  break;
1414
    break;
1382
  }
1415
  }
1383
1416
1384
/* Scan the reply for well-formed CSA SRV records. */
1417
/* Scan the reply for well-formed CSA SRV records. */
Lines 1409-1415 Link Here
1409
  SRV records of their own. */
1442
  SRV records of their own. */
1410
1443
1411
  if (Ustrcmp(found, domain) != 0)
1444
  if (Ustrcmp(found, domain) != 0)
1412
    return t->data.val = port & 1 ? CSA_FAIL_EXPLICIT : CSA_UNKNOWN;
1445
    {
1446
    yield = port & 1 ? CSA_FAIL_EXPLICIT : CSA_UNKNOWN;
1447
    goto out;
1448
    }
1413
1449
1414
  /* This CSA SRV record refers directly to our domain, so we check the value
1450
  /* This CSA SRV record refers directly to our domain, so we check the value
1415
  in the weight field to work out the domain's authorization. 0 and 1 are
1451
  in the weight field to work out the domain's authorization. 0 and 1 are
Lines 1417-1423 Link Here
1417
  address in order to authenticate it, so we treat it as unknown; values
1453
  address in order to authenticate it, so we treat it as unknown; values
1418
  greater than 3 are undefined. */
1454
  greater than 3 are undefined. */
1419
1455
1420
  if (weight < 2) return t->data.val = CSA_FAIL_DOMAIN;
1456
  if (weight < 2)
1457
    {
1458
    yield = CSA_FAIL_DOMAIN;
1459
    goto out;
1460
    }
1421
1461
1422
  if (weight > 2) continue;
1462
  if (weight > 2) continue;
1423
1463
Lines 1426-1432 Link Here
1426
  target hostname then break to scan the additional data for its addresses. */
1466
  target hostname then break to scan the additional data for its addresses. */
1427
1467
1428
  (void)dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, p,
1468
  (void)dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, p,
1429
    (DN_EXPAND_ARG4_TYPE)target, sizeof(target));
1469
    (DN_EXPAND_ARG4_TYPE)target, TARGET_SIZE);
1430
1470
1431
  DEBUG(D_acl) debug_printf_indent("CSA target is %s\n", target);
1471
  DEBUG(D_acl) debug_printf_indent("CSA target is %s\n", target);
1432
1472
Lines 1435-1441 Link Here
1435
1475
1436
/* If we didn't break the loop then no appropriate records were found. */
1476
/* If we didn't break the loop then no appropriate records were found. */
1437
1477
1438
if (!rr) return t->data.val = CSA_UNKNOWN;
1478
if (!rr)
1479
  {
1480
  yield = CSA_UNKNOWN;
1481
  goto out;
1482
  }
1439
1483
1440
/* Do not check addresses if the target is ".", in accordance with RFC 2782.
1484
/* Do not check addresses if the target is ".", in accordance with RFC 2782.
1441
A target of "." indicates there are no valid addresses, so the client cannot
1485
A target of "." indicates there are no valid addresses, so the client cannot
Lines 1443-1449 Link Here
1443
equivalent to weight=1, but we check for it in order to keep load off the
1487
equivalent to weight=1, but we check for it in order to keep load off the
1444
root name servers.) Note that dn_expand() turns "." into "". */
1488
root name servers.) Note that dn_expand() turns "." into "". */
1445
1489
1446
if (Ustrcmp(target, "") == 0) return t->data.val = CSA_FAIL_NOADDR;
1490
if (Ustrcmp(target, "") == 0)
1491
  {
1492
  yield = CSA_FAIL_NOADDR;
1493
  goto out;
1494
  }
1447
1495
1448
/* Scan the additional section of the CSA SRV reply for addresses belonging
1496
/* Scan the additional section of the CSA SRV reply for addresses belonging
1449
to the target. If the name server didn't return any additional data (e.g.
1497
to the target. If the name server didn't return any additional data (e.g.
Lines 1451-1457 Link Here
1451
to obtain the target addresses; otherwise we have a definitive result. */
1499
to obtain the target addresses; otherwise we have a definitive result. */
1452
1500
1453
rc = acl_verify_csa_address(dnsa, &dnss, RESET_ADDITIONAL, target);
1501
rc = acl_verify_csa_address(dnsa, &dnss, RESET_ADDITIONAL, target);
1454
if (rc != CSA_FAIL_NOADDR) return t->data.val = rc;
1502
if (rc != CSA_FAIL_NOADDR)
1503
  {
1504
  yield = rc;
1505
  goto out;
1506
  }
1455
1507
1456
/* The DNS lookup type corresponds to the IP version used by the client. */
1508
/* The DNS lookup type corresponds to the IP version used by the client. */
1457
1509
Lines 1469-1481 Link Here
1469
  /* If something bad happened (most commonly DNS_AGAIN), defer. */
1521
  /* If something bad happened (most commonly DNS_AGAIN), defer. */
1470
1522
1471
  default:
1523
  default:
1472
    return t->data.val = CSA_DEFER_ADDR;
1524
    yield = CSA_DEFER_ADDR;
1525
    break;
1473
1526
1474
  /* If the query succeeded, scan the addresses and return the result. */
1527
  /* If the query succeeded, scan the addresses and return the result. */
1475
1528
1476
  case DNS_SUCCEED:
1529
  case DNS_SUCCEED:
1477
    rc = acl_verify_csa_address(dnsa, &dnss, RESET_ANSWERS, target);
1530
    rc = acl_verify_csa_address(dnsa, &dnss, RESET_ANSWERS, target);
1478
    if (rc != CSA_FAIL_NOADDR) return t->data.val = rc;
1531
    if (rc != CSA_FAIL_NOADDR)
1532
      {
1533
      yield = rc;
1534
      break;
1535
      }
1479
    /* else fall through */
1536
    /* else fall through */
1480
1537
1481
  /* If the target has no IP addresses, the client cannot have an authorized
1538
  /* If the target has no IP addresses, the client cannot have an authorized
Lines 1484-1491 Link Here
1484
1541
1485
  case DNS_NOMATCH:
1542
  case DNS_NOMATCH:
1486
  case DNS_NODATA:
1543
  case DNS_NODATA:
1487
    return t->data.val = CSA_FAIL_NOADDR;
1544
    yield = CSA_FAIL_NOADDR;
1545
    break;
1488
  }
1546
  }
1547
1548
out:
1549
1550
store_free_dns_answer(dnsa);
1551
return t->data.val = yield;
1489
}
1552
}
1490
1553
1491
1554
Lines 1511-1524 Link Here
1511
    { US"certificate",	  	VERIFY_CERT,	 	(unsigned)~0,	TRUE,  0 },
1574
    { US"certificate",	  	VERIFY_CERT,	 	(unsigned)~0,	TRUE,  0 },
1512
    { US"helo",	  		VERIFY_HELO,	 	(unsigned)~0,	TRUE,  0 },
1575
    { US"helo",	  		VERIFY_HELO,	 	(unsigned)~0,	TRUE,  0 },
1513
    { US"csa",	  		VERIFY_CSA,	 	(unsigned)~0,	FALSE, 0 },
1576
    { US"csa",	  		VERIFY_CSA,	 	(unsigned)~0,	FALSE, 0 },
1514
    { US"header_syntax",	VERIFY_HDR_SYNTAX,	ACL_BIT_DATA | ACL_BIT_NOTSMTP, TRUE, 0 },
1577
    { US"header_syntax",	VERIFY_HDR_SYNTAX,	ACL_BITS_HAVEDATA, TRUE, 0 },
1515
    { US"not_blind",	  	VERIFY_NOT_BLIND,	ACL_BIT_DATA | ACL_BIT_NOTSMTP, FALSE, 0 },
1578
    { US"not_blind",	  	VERIFY_NOT_BLIND,	ACL_BITS_HAVEDATA, FALSE, 0 },
1516
    { US"header_sender",	VERIFY_HDR_SNDR,	ACL_BIT_DATA | ACL_BIT_NOTSMTP, FALSE, 0 },
1579
    { US"header_sender",	VERIFY_HDR_SNDR,	ACL_BITS_HAVEDATA, FALSE, 0 },
1517
    { US"sender",	  	VERIFY_SNDR,		ACL_BIT_MAIL | ACL_BIT_RCPT
1580
    { US"sender",	  	VERIFY_SNDR,		ACL_BIT_MAIL | ACL_BIT_RCPT
1518
			|ACL_BIT_PREDATA | ACL_BIT_DATA | ACL_BIT_NOTSMTP,
1581
			| ACL_BIT_PREDATA | ACL_BIT_DATA | ACL_BIT_NOTSMTP,
1519
										FALSE, 6 },
1582
										FALSE, 6 },
1520
    { US"recipient",	  	VERIFY_RCPT,	 	ACL_BIT_RCPT,	FALSE, 0 },
1583
    { US"recipient",	  	VERIFY_RCPT,	 	ACL_BIT_RCPT,	FALSE, 0 },
1521
    { US"header_names_ascii",	VERIFY_HDR_NAMES_ASCII, ACL_BIT_DATA | ACL_BIT_NOTSMTP, TRUE, 0 },
1584
    { US"header_names_ascii",	VERIFY_HDR_NAMES_ASCII, ACL_BITS_HAVEDATA, TRUE, 0 },
1522
#ifdef EXPERIMENTAL_ARC
1585
#ifdef EXPERIMENTAL_ARC
1523
    { US"arc",			VERIFY_ARC,	 	ACL_BIT_DATA,	FALSE , 0 },
1586
    { US"arc",			VERIFY_ARC,	 	ACL_BIT_DATA,	FALSE , 0 },
1524
#endif
1587
#endif
Lines 1556-1561 Link Here
1556
1619
1557
1620
1558
1621
1622
static int
1623
v_period(const uschar * s, const uschar * arg, uschar ** log_msgptr)
1624
{
1625
int period;
1626
if ((period = readconf_readtime(s, 0, FALSE)) < 0)
1627
  {
1628
  *log_msgptr = string_sprintf("bad time value in ACL condition "
1629
    "\"verify %s\"", arg);
1630
  }
1631
return period;
1632
}
1633
1634
1635
1559
/* This function implements the "verify" condition. It is called when
1636
/* This function implements the "verify" condition. It is called when
1560
encountered in any ACL, because some tests are almost always permitted. Some
1637
encountered in any ACL, because some tests are almost always permitted. Some
1561
just don't make sense, and always fail (for example, an attempt to test a host
1638
just don't make sense, and always fail (for example, an attempt to test a host
Lines 1590-1595 Link Here
1590
BOOL callout_defer_ok = FALSE;
1667
BOOL callout_defer_ok = FALSE;
1591
BOOL no_details = FALSE;
1668
BOOL no_details = FALSE;
1592
BOOL success_on_redirect = FALSE;
1669
BOOL success_on_redirect = FALSE;
1670
BOOL quota = FALSE;
1671
int quota_pos_cache = QUOTA_POS_DEFAULT, quota_neg_cache = QUOTA_NEG_DEFAULT;
1593
address_item *sender_vaddr = NULL;
1672
address_item *sender_vaddr = NULL;
1594
uschar *verify_sender_address = NULL;
1673
uschar *verify_sender_address = NULL;
1595
uschar *pm_mailfrom = NULL;
1674
uschar *pm_mailfrom = NULL;
Lines 1746-1752 Link Here
1746
    in place of the actual sender (rare special-case requirement). */
1825
    in place of the actual sender (rare special-case requirement). */
1747
    {
1826
    {
1748
    uschar *s = ss + 6;
1827
    uschar *s = ss + 6;
1749
    if (*s == 0)
1828
    if (!*s)
1750
      verify_sender_address = sender_address;
1829
      verify_sender_address = sender_address;
1751
    else
1830
    else
1752
      {
1831
      {
Lines 1792-1810 Link Here
1792
  else if (strncmpic(ss, US"callout", 7) == 0)
1871
  else if (strncmpic(ss, US"callout", 7) == 0)
1793
    {
1872
    {
1794
    callout = CALLOUT_TIMEOUT_DEFAULT;
1873
    callout = CALLOUT_TIMEOUT_DEFAULT;
1795
    ss += 7;
1874
    if (*(ss += 7))
1796
    if (*ss != 0)
1797
      {
1875
      {
1798
      while (isspace(*ss)) ss++;
1876
      while (isspace(*ss)) ss++;
1799
      if (*ss++ == '=')
1877
      if (*ss++ == '=')
1800
        {
1878
        {
1801
	const uschar * sublist = ss;
1879
	const uschar * sublist = ss;
1802
        int optsep = ',';
1880
        int optsep = ',';
1803
        uschar buffer[256];
1804
	uschar * opt;
1805
1881
1806
        while (isspace(*sublist)) sublist++;
1882
        while (isspace(*sublist)) sublist++;
1807
        while ((opt = string_nextinlist(&sublist, &optsep, NULL, 0)))
1883
        for (uschar * opt; opt = string_nextinlist(&sublist, &optsep, NULL, 0); )
1808
          {
1884
          {
1809
	  callout_opt_t * op;
1885
	  callout_opt_t * op;
1810
	  double period = 1.0F;
1886
	  double period = 1.0F;
Lines 1826-1837 Link Here
1826
              }
1902
              }
1827
            while (isspace(*opt)) opt++;
1903
            while (isspace(*opt)) opt++;
1828
	    }
1904
	    }
1829
	  if (op->timeval && (period = readconf_readtime(opt, 0, FALSE)) < 0)
1905
	  if (op->timeval && (period = v_period(opt, arg, log_msgptr)) < 0)
1830
	    {
1831
	    *log_msgptr = string_sprintf("bad time value in ACL condition "
1832
	      "\"verify %s\"", arg);
1833
	    return ERROR;
1906
	    return ERROR;
1834
	    }
1835
1907
1836
	  switch(op->value)
1908
	  switch(op->value)
1837
	    {
1909
	    {
Lines 1864-1869 Link Here
1864
      }
1936
      }
1865
    }
1937
    }
1866
1938
1939
  /* The quota option has sub-options, comma-separated */
1940
1941
  else if (strncmpic(ss, US"quota", 5) == 0)
1942
    {
1943
    quota = TRUE;
1944
    if (*(ss += 5))
1945
      {
1946
      while (isspace(*ss)) ss++;
1947
      if (*ss++ == '=')
1948
        {
1949
	const uschar * sublist = ss;
1950
        int optsep = ',';
1951
	int period;
1952
1953
        while (isspace(*sublist)) sublist++;
1954
        for (uschar * opt; opt = string_nextinlist(&sublist, &optsep, NULL, 0); )
1955
	  if (Ustrncmp(opt, "cachepos=", 9) == 0)
1956
	    if ((period = v_period(opt += 9, arg, log_msgptr)) < 0)
1957
	      return ERROR;
1958
	    else
1959
	      quota_pos_cache = period;
1960
	  else if (Ustrncmp(opt, "cacheneg=", 9) == 0)
1961
	    if ((period = v_period(opt += 9, arg, log_msgptr)) < 0)
1962
	      return ERROR;
1963
	    else
1964
	      quota_neg_cache = period;
1965
	  else if (Ustrcmp(opt, "no_cache") == 0)
1966
	    quota_pos_cache = quota_neg_cache = 0;
1967
	}
1968
      }
1969
    }
1970
1867
  /* Option not recognized */
1971
  /* Option not recognized */
1868
1972
1869
  else
1973
  else
Lines 1882-1887 Link Here
1882
  return ERROR;
1986
  return ERROR;
1883
  }
1987
  }
1884
1988
1989
/* Handle quota verification */
1990
if (quota)
1991
  {
1992
  if (vp->value != VERIFY_RCPT)
1993
    {
1994
    *log_msgptr = US"can only verify quota of recipient";
1995
    return ERROR;
1996
    }
1997
1998
  if ((rc = verify_quota_call(addr->address,
1999
	      quota_pos_cache, quota_neg_cache, log_msgptr)) != OK)
2000
    {
2001
    *basic_errno = errno;
2002
    if (smtp_return_error_details)
2003
      {
2004
      if (!*user_msgptr && *log_msgptr)
2005
        *user_msgptr = string_sprintf("Rejected after %s: %s",
2006
	    smtp_names[smtp_connection_had[SMTP_HBUFF_PREV(smtp_ch_index)]],
2007
	    *log_msgptr);
2008
      if (rc == DEFER) f.acl_temp_details = TRUE;
2009
      }
2010
    }
2011
2012
  return rc;
2013
  }
2014
1885
/* Handle sender-in-header verification. Default the user message to the log
2015
/* Handle sender-in-header verification. Default the user message to the log
1886
message if giving out verification details. */
2016
message if giving out verification details. */
1887
2017
Lines 1928-1935 Link Here
1928
    }
2058
    }
1929
2059
1930
  sender_vaddr = verify_checked_sender(verify_sender_address);
2060
  sender_vaddr = verify_checked_sender(verify_sender_address);
1931
  if (sender_vaddr != NULL &&               /* Previously checked */
2061
  if (   sender_vaddr				/* Previously checked */
1932
      callout <= 0)                         /* No callout needed this time */
2062
      && callout <= 0)				/* No callout needed this time */
1933
    {
2063
    {
1934
    /* If the "routed" flag is set, it means that routing worked before, so
2064
    /* If the "routed" flag is set, it means that routing worked before, so
1935
    this check can give OK (the saved return code value, if set, belongs to a
2065
    this check can give OK (the saved return code value, if set, belongs to a
Lines 1996-2009 Link Here
1996
        *basic_errno = sender_vaddr->basic_errno;
2126
        *basic_errno = sender_vaddr->basic_errno;
1997
      else
2127
      else
1998
	DEBUG(D_acl)
2128
	DEBUG(D_acl)
1999
	  {
2000
	  if (Ustrcmp(sender_vaddr->address, verify_sender_address) != 0)
2129
	  if (Ustrcmp(sender_vaddr->address, verify_sender_address) != 0)
2001
	    debug_printf_indent("sender %s verified ok as %s\n",
2130
	    debug_printf_indent("sender %s verified ok as %s\n",
2002
	      verify_sender_address, sender_vaddr->address);
2131
	      verify_sender_address, sender_vaddr->address);
2003
	  else
2132
	  else
2004
	    debug_printf_indent("sender %s verified ok\n",
2133
	    debug_printf_indent("sender %s verified ok\n",
2005
	      verify_sender_address);
2134
	      verify_sender_address);
2006
	  }
2007
      }
2135
      }
2008
    else
2136
    else
2009
      rc = OK;  /* Null sender */
2137
      rc = OK;  /* Null sender */
Lines 2047-2054 Link Here
2047
2175
2048
  *basic_errno = addr2.basic_errno;
2176
  *basic_errno = addr2.basic_errno;
2049
  *log_msgptr = addr2.message;
2177
  *log_msgptr = addr2.message;
2050
  *user_msgptr = (addr2.user_message != NULL)?
2178
  *user_msgptr = addr2.user_message ? addr2.user_message : addr2.message;
2051
    addr2.user_message : addr2.message;
2052
2179
2053
  /* Allow details for temporary error if the address is so flagged. */
2180
  /* Allow details for temporary error if the address is so flagged. */
2054
  if (testflag((&addr2), af_pass_message)) f.acl_temp_details = TRUE;
2181
  if (testflag((&addr2), af_pass_message)) f.acl_temp_details = TRUE;
Lines 2059-2066 Link Here
2059
2186
2060
/* We have a result from the relevant test. Handle defer overrides first. */
2187
/* We have a result from the relevant test. Handle defer overrides first. */
2061
2188
2062
if (rc == DEFER && (defer_ok ||
2189
if (  rc == DEFER
2063
   (callout_defer_ok && *basic_errno == ERRNO_CALLOUTDEFER)))
2190
   && (  defer_ok
2191
      || callout_defer_ok && *basic_errno == ERRNO_CALLOUTDEFER
2192
   )  )
2064
  {
2193
  {
2065
  HDEBUG(D_acl) debug_printf_indent("verify defer overridden by %s\n",
2194
  HDEBUG(D_acl) debug_printf_indent("verify defer overridden by %s\n",
2066
    defer_ok? "defer_ok" : "callout_defer_ok");
2195
    defer_ok? "defer_ok" : "callout_defer_ok");
Lines 2070-2076 Link Here
2070
/* If we've failed a sender, set up a recipient message, and point
2199
/* If we've failed a sender, set up a recipient message, and point
2071
sender_verified_failed to the address item that actually failed. */
2200
sender_verified_failed to the address item that actually failed. */
2072
2201
2073
if (rc != OK && verify_sender_address != NULL)
2202
if (rc != OK && verify_sender_address)
2074
  {
2203
  {
2075
  if (rc != DEFER)
2204
  if (rc != DEFER)
2076
    *log_msgptr = *user_msgptr = US"Sender verify failed";
2205
    *log_msgptr = *user_msgptr = US"Sender verify failed";
Lines 2089-2095 Link Here
2089
/* Verifying an address messes up the values of $domain and $local_part,
2218
/* Verifying an address messes up the values of $domain and $local_part,
2090
so reset them before returning if this is a RCPT ACL. */
2219
so reset them before returning if this is a RCPT ACL. */
2091
2220
2092
if (addr != NULL)
2221
if (addr)
2093
  {
2222
  {
2094
  deliver_domain = addr->domain;
2223
  deliver_domain = addr->domain;
2095
  deliver_localpart = addr->local_part;
2224
  deliver_localpart = addr->local_part;
Lines 2458-2464 Link Here
2458
    /* No Bloom filter. This basic ratelimit block is initialized below. */
2587
    /* No Bloom filter. This basic ratelimit block is initialized below. */
2459
    HDEBUG(D_acl) debug_printf_indent("ratelimit creating new rate data block\n");
2588
    HDEBUG(D_acl) debug_printf_indent("ratelimit creating new rate data block\n");
2460
    dbdb_size = sizeof(*dbd);
2589
    dbdb_size = sizeof(*dbd);
2461
    dbdb = store_get(dbdb_size, FALSE);		/* not tainted */
2590
    dbdb = store_get(dbdb_size, GET_UNTAINTED);
2462
    }
2591
    }
2463
  else
2592
  else
2464
    {
2593
    {
Lines 2472-2478 Link Here
2472
    extra = (int)limit * 2 - sizeof(dbdb->bloom);
2601
    extra = (int)limit * 2 - sizeof(dbdb->bloom);
2473
    if (extra < 0) extra = 0;
2602
    if (extra < 0) extra = 0;
2474
    dbdb_size = sizeof(*dbdb) + extra;
2603
    dbdb_size = sizeof(*dbdb) + extra;
2475
    dbdb = store_get(dbdb_size, FALSE);		/* not tainted */
2604
    dbdb = store_get(dbdb_size, GET_UNTAINTED);
2476
    dbdb->bloom_epoch = tv.tv_sec;
2605
    dbdb->bloom_epoch = tv.tv_sec;
2477
    dbdb->bloom_size = sizeof(dbdb->bloom) + extra;
2606
    dbdb->bloom_size = sizeof(dbdb->bloom) + extra;
2478
    memset(dbdb->bloom, 0, dbdb->bloom_size);
2607
    memset(dbdb->bloom, 0, dbdb->bloom_size);
Lines 2692-2698 Link Here
2692
/* Store the result in the tree for future reference.  Take the taint status
2821
/* Store the result in the tree for future reference.  Take the taint status
2693
from the key for consistency even though it's unlikely we'll ever expand this. */
2822
from the key for consistency even though it's unlikely we'll ever expand this. */
2694
2823
2695
t = store_get(sizeof(tree_node) + Ustrlen(key), is_tainted(key));
2824
t = store_get(sizeof(tree_node) + Ustrlen(key), key);
2696
t->data.ptr = dbd;
2825
t->data.ptr = dbd;
2697
Ustrcpy(t->name, key);
2826
Ustrcpy(t->name, key);
2698
(void)tree_insertnode(anchor, t);
2827
(void)tree_insertnode(anchor, t);
Lines 2712-2717 Link Here
2712
2841
2713
2842
2714
/*************************************************
2843
/*************************************************
2844
*      Handle a check for previously-seen        *
2845
*************************************************/
2846
2847
/*
2848
ACL clauses like:   seen = -5m / key=$foo / readonly
2849
2850
Return is true for condition-true - but the semantics
2851
depend heavily on the actual use-case.
2852
2853
Negative times test for seen-before, positive for seen-more-recently-than
2854
(the given interval before current time).
2855
2856
All are subject to history not having been cleaned from the DB.
2857
2858
Default for seen-before is to create if not present, and to
2859
update if older than 10d (with the seen-test time).
2860
Default for seen-since is to always create or update.
2861
2862
Options:
2863
  key=value.  Default key is $sender_host_address
2864
  readonly
2865
  write
2866
  refresh=<interval>:  update an existing DB entry older than given
2867
			amount.  Default refresh lacking this option is 10d.
2868
			The update sets the record timestamp to the seen-test time.
2869
2870
XXX do we need separate nocreate, noupdate controls?
2871
2872
Arguments:
2873
  arg         the option string for seen=
2874
  where       ACL_WHERE_xxxx indicating which ACL this is
2875
  log_msgptr  for error messages
2876
2877
Returns:       OK        - Condition is true
2878
               FAIL      - Condition is false
2879
               DEFER     - Problem opening history database
2880
               ERROR     - Syntax error in options
2881
*/
2882
2883
static int
2884
acl_seen(const uschar * arg, int where, uschar ** log_msgptr)
2885
{
2886
enum { SEEN_DEFAULT, SEEN_READONLY, SEEN_WRITE };
2887
2888
const uschar * list = arg;
2889
int slash = '/', interval, mode = SEEN_DEFAULT, yield = FAIL;
2890
BOOL before;
2891
int refresh = 10 * 24 * 60 * 60;	/* 10 days */
2892
const uschar * ele, * key = sender_host_address;
2893
open_db dbblock, * dbm;
2894
dbdata_seen * dbd;
2895
time_t now;
2896
2897
/* Parse the first element, the time-relation. */
2898
2899
if (!(ele = string_nextinlist(&list, &slash, NULL, 0)))
2900
  goto badparse;
2901
if ((before = *ele == '-'))
2902
  ele++;
2903
if ((interval = readconf_readtime(ele, 0, FALSE)) < 0)
2904
  goto badparse;
2905
2906
/* Remaining elements are options */
2907
2908
while ((ele = string_nextinlist(&list, &slash, NULL, 0)))
2909
  if (Ustrncmp(ele, "key=", 4) == 0)
2910
    key = ele + 4;
2911
  else if (Ustrcmp(ele, "readonly") == 0)
2912
    mode = SEEN_READONLY;
2913
  else if (Ustrcmp(ele, "write") == 0)
2914
    mode = SEEN_WRITE;
2915
  else if (Ustrncmp(ele, "refresh=", 8) == 0)
2916
    {
2917
    if ((refresh = readconf_readtime(ele + 8, 0, FALSE)) < 0)
2918
      goto badparse;
2919
    }
2920
  else
2921
    goto badopt;
2922
2923
if (!(dbm = dbfn_open(US"seen", O_RDWR, &dbblock, TRUE, TRUE)))
2924
  {
2925
  HDEBUG(D_acl) debug_printf_indent("database for 'seen' not available\n");
2926
  *log_msgptr = US"database for 'seen' not available";
2927
  return DEFER;
2928
  }
2929
2930
dbd = dbfn_read_with_length(dbm, key, NULL);
2931
now = time(NULL);
2932
if (dbd)		/* an existing record */
2933
  {
2934
  time_t diff = now - dbd->time_stamp;	/* time since the record was written */
2935
2936
  if (before ? diff >= interval : diff < interval)
2937
    yield = OK;
2938
2939
  if (mode == SEEN_READONLY)
2940
    { HDEBUG(D_acl) debug_printf_indent("seen db not written (readonly)\n"); }
2941
  else if (mode == SEEN_WRITE || !before)
2942
    {
2943
    dbd->time_stamp = now;
2944
    dbfn_write(dbm, key, dbd, sizeof(*dbd));
2945
    HDEBUG(D_acl) debug_printf_indent("seen db written (update)\n");
2946
    }
2947
  else if (diff >= refresh)
2948
    {
2949
    dbd->time_stamp = now - interval;
2950
    dbfn_write(dbm, key, dbd, sizeof(*dbd));
2951
    HDEBUG(D_acl) debug_printf_indent("seen db written (refresh)\n");
2952
    }
2953
  }
2954
else
2955
  {			/* No record found, yield always FAIL */
2956
  if (mode != SEEN_READONLY)
2957
    {
2958
    dbdata_seen d = {.time_stamp = now};
2959
    dbfn_write(dbm, key, &d, sizeof(*dbd));
2960
    HDEBUG(D_acl) debug_printf_indent("seen db written (create)\n");
2961
    }
2962
  else
2963
    HDEBUG(D_acl) debug_printf_indent("seen db not written (readonly)\n");
2964
  }
2965
2966
dbfn_close(dbm);
2967
return yield;
2968
2969
2970
badparse:
2971
  *log_msgptr = string_sprintf("failed to parse '%s'", arg);
2972
  return ERROR;
2973
badopt:
2974
  *log_msgptr = string_sprintf("unrecognised option '%s' in '%s'", ele, arg);
2975
  return ERROR;
2976
}
2977
2978
2979
2980
/*************************************************
2715
*            The udpsend ACL modifier            *
2981
*            The udpsend ACL modifier            *
2716
*************************************************/
2982
*************************************************/
2717
2983
Lines 2765-2771 Link Here
2765
  }
3031
  }
2766
3032
2767
/* Make a single-item host list. */
3033
/* Make a single-item host list. */
2768
h = store_get(sizeof(host_item), FALSE);
3034
h = store_get(sizeof(host_item), GET_UNTAINTED);
2769
memset(h, 0, sizeof(host_item));
3035
memset(h, 0, sizeof(host_item));
2770
h->name = hostname;
3036
h->name = hostname;
2771
h->port = portnum;
3037
h->port = portnum;
Lines 3131-3143 Link Here
3131
3397
3132
	case CONTROL_FAKEREJECT:
3398
	case CONTROL_FAKEREJECT:
3133
	  cancel_cutthrough_connection(TRUE, US"fakereject");
3399
	  cancel_cutthrough_connection(TRUE, US"fakereject");
3134
	  case CONTROL_FAKEDEFER:
3400
	case CONTROL_FAKEDEFER:
3135
	  fake_response = (control_type == CONTROL_FAKEDEFER) ? DEFER : FAIL;
3401
	  fake_response = (control_type == CONTROL_FAKEDEFER) ? DEFER : FAIL;
3136
	  if (*p == '/')
3402
	  if (*p == '/')
3137
	    {
3403
	    {
3138
	    const uschar *pp = p + 1;
3404
	    const uschar *pp = p + 1;
3139
	    while (*pp) pp++;
3405
	    while (*pp) pp++;
3140
	    fake_response_text = expand_string(string_copyn(p+1, pp-p-1));
3406
	    /* The entire control= line was expanded at top so no need to expand
3407
	    the part after the / */
3408
	    fake_response_text = string_copyn(p+1, pp-p-1);
3141
	    p = pp;
3409
	    p = pp;
3142
	    }
3410
	    }
3143
	   else /* Explicitly reset to default string */
3411
	   else /* Explicitly reset to default string */
Lines 3213-3221 Link Here
3213
3481
3214
	case CONTROL_DEBUG:
3482
	case CONTROL_DEBUG:
3215
	  {
3483
	  {
3216
	  uschar * debug_tag = NULL;
3484
	  uschar * debug_tag = NULL, * debug_opts = NULL;
3217
	  uschar * debug_opts = NULL;
3485
	  BOOL kill = FALSE, stop = FALSE;
3218
	  BOOL kill = FALSE;
3219
3486
3220
	  while (*p == '/')
3487
	  while (*p == '/')
3221
	    {
3488
	    {
Lines 3232-3249 Link Here
3232
	      }
3499
	      }
3233
	    else if (Ustrncmp(pp, "kill", 4) == 0)
3500
	    else if (Ustrncmp(pp, "kill", 4) == 0)
3234
	      {
3501
	      {
3235
	      for (pp += 4; *pp && *pp != '/';) pp++;
3502
	      pp += 4;
3236
	      kill = TRUE;
3503
	      kill = TRUE;
3237
	      }
3504
	      }
3238
	    else
3505
	    else if (Ustrncmp(pp, "stop", 4) == 0)
3239
	      while (*pp && *pp != '/') pp++;
3506
	      {
3507
	      pp += 4;
3508
	      stop = TRUE;
3509
	      }
3510
	    else if (Ustrncmp(pp, "pretrigger=", 11) == 0)
3511
		debug_pretrigger_setup(pp+11);
3512
	    else if (Ustrncmp(pp, "trigger=", 8) == 0)
3513
	      {
3514
	      if (Ustrncmp(pp += 8, "now", 3) == 0)
3515
		{
3516
		pp += 3;
3517
		debug_trigger_fire();
3518
		}
3519
	      else if (Ustrncmp(pp, "paniclog", 8) == 0)
3520
		{
3521
		pp += 8;
3522
		dtrigger_selector |= BIT(DTi_panictrigger);
3523
		}
3524
	      }
3525
	    while (*pp && *pp != '/') pp++;
3240
	    p = pp;
3526
	    p = pp;
3241
	    }
3527
	    }
3242
3528
3243
	    if (kill)
3529
	  if (kill)
3244
	      debug_logging_stop();
3530
	    debug_logging_stop(TRUE);
3245
	    else
3531
	  else if (stop)
3246
	      debug_logging_activate(debug_tag, debug_opts);
3532
	    debug_logging_stop(FALSE);
3533
	  else if (debug_tag || debug_opts)
3534
	    debug_logging_activate(debug_tag, debug_opts);
3247
	  break;
3535
	  break;
3248
	  }
3536
	  }
3249
3537
Lines 3434-3440 Link Here
3434
      }
3722
      }
3435
    break;
3723
    break;
3436
3724
3437
    #ifndef DISABLE_DKIM
3725
#ifndef DISABLE_DKIM
3438
    case ACLC_DKIM_SIGNER:
3726
    case ACLC_DKIM_SIGNER:
3439
    if (dkim_cur_signer)
3727
    if (dkim_cur_signer)
3440
      rc = match_isinlist(dkim_cur_signer,
3728
      rc = match_isinlist(dkim_cur_signer,
Lines 3447-3453 Link Here
3447
    rc = match_isinlist(dkim_verify_status,
3735
    rc = match_isinlist(dkim_verify_status,
3448
                        &arg, 0, NULL, NULL, MCL_STRING, TRUE, NULL);
3736
                        &arg, 0, NULL, NULL, MCL_STRING, TRUE, NULL);
3449
    break;
3737
    break;
3450
    #endif
3738
#endif
3451
3739
3452
#ifdef SUPPORT_DMARC
3740
#ifdef SUPPORT_DMARC
3453
    case ACLC_DMARC_STATUS:
3741
    case ACLC_DMARC_STATUS:
Lines 3632-3637 Link Here
3632
    setup_remove_header(arg);
3920
    setup_remove_header(arg);
3633
    break;
3921
    break;
3634
3922
3923
    case ACLC_SEEN:
3924
    rc = acl_seen(arg, where, log_msgptr);
3925
    break;
3926
3635
    case ACLC_SENDER_DOMAINS:
3927
    case ACLC_SENDER_DOMAINS:
3636
      {
3928
      {
3637
      uschar *sdomain;
3929
      uschar *sdomain;
Lines 3910-3915 Link Here
3910
4202
3911
4203
3912
4204
4205
/************************************************/
4206
/* For error messages, a string describing the config location
4207
associated with current processing. NULL if not in an ACL. */
4208
4209
uschar *
4210
acl_current_verb(void)
4211
{
4212
if (acl_current) return string_sprintf(" (ACL %s, %s %d)",
4213
    verbs[acl_current->verb], acl_current->srcfile, acl_current->srcline);
4214
return NULL;
4215
}
4216
3913
/*************************************************
4217
/*************************************************
3914
*        Check access using an ACL               *
4218
*        Check access using an ACL               *
3915
*************************************************/
4219
*************************************************/
Lines 3984-3989 Link Here
3984
4288
3985
acl_text = ss;
4289
acl_text = ss;
3986
4290
4291
if (is_tainted(acl_text) && !f.running_in_test_harness)
4292
  {
4293
  log_write(0, LOG_MAIN|LOG_PANIC,
4294
    "attempt to use tainted ACL text \"%s\"", acl_text);
4295
  /* Avoid leaking info to an attacker */
4296
  *log_msgptr = US"internal configuration error";
4297
  return ERROR;
4298
  }
4299
3987
/* Handle the case of a string that does not contain any spaces. Look for a
4300
/* Handle the case of a string that does not contain any spaces. Look for a
3988
named ACL among those read from the configuration, or a previously read file.
4301
named ACL among those read from the configuration, or a previously read file.
3989
It is possible that the pointer to the ACL is NULL if the configuration
4302
It is possible that the pointer to the ACL is NULL if the configuration
Lines 4007-4020 Link Here
4007
  else if (*ss == '/')
4320
  else if (*ss == '/')
4008
    {
4321
    {
4009
    struct stat statbuf;
4322
    struct stat statbuf;
4010
    if (is_tainted(ss))
4011
      {
4012
      log_write(0, LOG_MAIN|LOG_PANIC,
4013
	"attempt to open tainted ACL file name \"%s\"", ss);
4014
      /* Avoid leaking info to an attacker */
4015
      *log_msgptr = US"internal configuration error";
4016
      return ERROR;
4017
      }
4018
    if ((fd = Uopen(ss, O_RDONLY, 0)) < 0)
4323
    if ((fd = Uopen(ss, O_RDONLY, 0)) < 0)
4019
      {
4324
      {
4020
      *log_msgptr = string_sprintf("failed to open ACL file \"%s\": %s", ss,
4325
      *log_msgptr = string_sprintf("failed to open ACL file \"%s\": %s", ss,
Lines 4029-4035 Link Here
4029
      }
4334
      }
4030
4335
4031
    /* If the string being used as a filename is tainted, so is the file content */
4336
    /* If the string being used as a filename is tainted, so is the file content */
4032
    acl_text = store_get(statbuf.st_size + 1, is_tainted(ss));
4337
    acl_text = store_get(statbuf.st_size + 1, ss);
4033
    acl_text_end = acl_text + statbuf.st_size + 1;
4338
    acl_text_end = acl_text + statbuf.st_size + 1;
4034
4339
4035
    if (read(fd, acl_text, statbuf.st_size) != statbuf.st_size)
4340
    if (read(fd, acl_text, statbuf.st_size) != statbuf.st_size)
Lines 4059-4065 Link Here
4059
  if (!acl && *log_msgptr) return ERROR;
4364
  if (!acl && *log_msgptr) return ERROR;
4060
  if (fd >= 0)
4365
  if (fd >= 0)
4061
    {
4366
    {
4062
    tree_node *t = store_get_perm(sizeof(tree_node) + Ustrlen(ss), is_tainted(ss));
4367
    tree_node * t = store_get_perm(sizeof(tree_node) + Ustrlen(ss), ss);
4063
    Ustrcpy(t->name, ss);
4368
    Ustrcpy(t->name, ss);
4064
    t->data.ptr = acl;
4369
    t->data.ptr = acl;
4065
    (void)tree_insertnode(&acl_anchor, t);
4370
    (void)tree_insertnode(&acl_anchor, t);
Lines 4068-4074 Link Here
4068
4373
4069
/* Now we have an ACL to use. It's possible it may be NULL. */
4374
/* Now we have an ACL to use. It's possible it may be NULL. */
4070
4375
4071
while (acl)
4376
while ((acl_current = acl))
4072
  {
4377
  {
4073
  int cond;
4378
  int cond;
4074
  int basic_errno = 0;
4379
  int basic_errno = 0;
Lines 4215-4222 Link Here
4215
      else if (cond == DEFER && LOGGING(acl_warn_skipped))
4520
      else if (cond == DEFER && LOGGING(acl_warn_skipped))
4216
	log_write(0, LOG_MAIN, "%s Warning: ACL \"warn\" statement skipped: "
4521
	log_write(0, LOG_MAIN, "%s Warning: ACL \"warn\" statement skipped: "
4217
	  "condition test deferred%s%s", host_and_ident(TRUE),
4522
	  "condition test deferred%s%s", host_and_ident(TRUE),
4218
	  (*log_msgptr == NULL)? US"" : US": ",
4523
	  *log_msgptr ? US": " : US"",
4219
	  (*log_msgptr == NULL)? US"" : *log_msgptr);
4524
	  *log_msgptr ? *log_msgptr : US"");
4220
      *log_msgptr = *user_msgptr = NULL;  /* In case implicit DENY follows */
4525
      *log_msgptr = *user_msgptr = NULL;  /* In case implicit DENY follows */
4221
      break;
4526
      break;
4222
4527
Lines 4541-4547 Link Here
4541
tree_node * node, ** root = name[0] == 'c' ? &acl_var_c : &acl_var_m;
4846
tree_node * node, ** root = name[0] == 'c' ? &acl_var_c : &acl_var_m;
4542
if (!(node = tree_search(*root, name)))
4847
if (!(node = tree_search(*root, name)))
4543
  {
4848
  {
4544
  node = store_get(sizeof(tree_node) + Ustrlen(name), is_tainted(name));
4849
  node = store_get(sizeof(tree_node) + Ustrlen(name), name);
4545
  Ustrcpy(node->name, name);
4850
  Ustrcpy(node->name, name);
4546
  (void)tree_insertnode(root, node);
4851
  (void)tree_insertnode(root, node);
4547
  }
4852
  }
Lines 4572-4584 Link Here
4572
*/
4877
*/
4573
4878
4574
void
4879
void
4575
acl_var_write(uschar *name, uschar *value, void *ctx)
4880
acl_var_write(uschar * name, uschar * value, void * ctx)
4576
{
4881
{
4577
FILE *f = (FILE *)ctx;
4882
FILE * f = (FILE *)ctx;
4578
if (is_tainted(value)) putc('-', f);
4883
putc('-', f);
4579
fprintf(f, "-acl%c %s %d\n%s\n", name[0], name+1, Ustrlen(value), value);
4884
if (is_tainted(value))
4885
  {
4886
  int q = quoter_for_address(value);
4887
  putc('-', f);
4888
  if (is_real_quoter(q)) fprintf(f, "(%s)", lookup_list[q]->name);
4889
  }
4890
fprintf(f, "acl%c %s %d\n%s\n", name[0], name+1, Ustrlen(value), value);
4580
}
4891
}
4581
4892
4893
#endif	/* !MACRO_PREDEF */
4582
/* vi: aw ai sw=2
4894
/* vi: aw ai sw=2
4583
*/
4895
*/
4584
/* End of acl.c */
4896
/* End of acl.c */
(-)exim.orig/src/arc.c (-28 / +53 lines)
Lines 3-8 Link Here
3
*************************************************/
3
*************************************************/
4
/* Experimental ARC support for Exim
4
/* Experimental ARC support for Exim
5
   Copyright (c) Jeremy Harris 2018 - 2020
5
   Copyright (c) Jeremy Harris 2018 - 2020
6
   Copyright (c) The Exim Maintainers 2021 - 2022
6
   License: GPL
7
   License: GPL
7
*/
8
*/
8
9
Lines 141-147 Link Here
141
  }
142
  }
142
143
143
DEBUG(D_acl) debug_printf("ARC: new instance %u\n", i);
144
DEBUG(D_acl) debug_printf("ARC: new instance %u\n", i);
144
*pas = as = store_get(sizeof(arc_set), FALSE);
145
*pas = as = store_get(sizeof(arc_set), GET_UNTAINTED);
145
memset(as, 0, sizeof(arc_set));
146
memset(as, 0, sizeof(arc_set));
146
as->next = next;
147
as->next = next;
147
as->prev = prev;
148
as->prev = prev;
Lines 199-205 Link Here
199
200
200
if (!instance_only)
201
if (!instance_only)
201
  {
202
  {
202
  al->rawsig_no_b_val.data = store_get(h->slen + 1, TRUE);	/* tainted */
203
  al->rawsig_no_b_val.data = store_get(h->slen + 1, GET_TAINTED);
203
  memcpy(al->rawsig_no_b_val.data, h->text, off);	/* copy the header name blind */
204
  memcpy(al->rawsig_no_b_val.data, h->text, off);	/* copy the header name blind */
204
  r = al->rawsig_no_b_val.data + off;
205
  r = al->rawsig_no_b_val.data + off;
205
  al->rawsig_no_b_val.len = off;
206
  al->rawsig_no_b_val.len = off;
Lines 385-391 Link Here
385
{
386
{
386
unsigned i;
387
unsigned i;
387
arc_set * as;
388
arc_set * as;
388
arc_line * al = store_get(sizeof(arc_line), FALSE), ** alp;
389
arc_line * al = store_get(sizeof(arc_line), GET_UNTAINTED), ** alp;
389
uschar * e;
390
uschar * e;
390
391
391
memset(al, 0, sizeof(arc_line));
392
memset(al, 0, sizeof(arc_line));
Lines 496-502 Link Here
496
DEBUG(D_acl) debug_printf("ARC: collecting arc sets\n");
497
DEBUG(D_acl) debug_printf("ARC: collecting arc sets\n");
497
for (h = header_list; h; h = h->next)
498
for (h = header_list; h; h = h->next)
498
  {
499
  {
499
  r = store_get(sizeof(hdr_rlist), FALSE);
500
  r = store_get(sizeof(hdr_rlist), GET_UNTAINTED);
500
  r->prev = rprev;
501
  r->prev = rprev;
501
  r->used = FALSE;
502
  r->used = FALSE;
502
  r->h = h;
503
  r->h = h;
Lines 568-574 Link Here
568
569
569
      len = Ustrlen(s);
570
      len = Ustrlen(s);
570
      DEBUG(D_acl) pdkim_quoteprint(s, len);
571
      DEBUG(D_acl) pdkim_quoteprint(s, len);
571
      exim_sha_update(&hhash_ctx, s, Ustrlen(s));
572
      exim_sha_update_string(&hhash_ctx, s);
572
      r->used = TRUE;
573
      r->used = TRUE;
573
      break;
574
      break;
574
      }
575
      }
Lines 1102-1108 Link Here
1102
static hdr_rlist *
1103
static hdr_rlist *
1103
arc_rlist_entry(hdr_rlist * list, const uschar * s, int len)
1104
arc_rlist_entry(hdr_rlist * list, const uschar * s, int len)
1104
{
1105
{
1105
hdr_rlist * r = store_get(sizeof(hdr_rlist) + sizeof(header_line), FALSE);
1106
hdr_rlist * r = store_get(sizeof(hdr_rlist) + sizeof(header_line), GET_UNTAINTED);
1106
header_line * h = r->h = (header_line *)(r+1);
1107
header_line * h = r->h = (header_line *)(r+1);
1107
1108
1108
r->prev = list;
1109
r->prev = list;
Lines 1112-1122 Link Here
1112
h->slen = len;
1113
h->slen = len;
1113
h->text = US s;
1114
h->text = US s;
1114
1115
1115
/* This works for either NL or CRLF lines; also nul-termination */
1116
while (*++s)
1117
  if (*s == '\n' && s[1] != '\t' && s[1] != ' ') break;
1118
s++;		/* move past end of line */
1119
1120
return r;
1116
return r;
1121
}
1117
}
1122
1118
Lines 1194-1200 Link Here
1194
{
1190
{
1195
int aar_off = gstring_length(g);
1191
int aar_off = gstring_length(g);
1196
arc_set * as =
1192
arc_set * as =
1197
  store_get(sizeof(arc_set) + sizeof(arc_line) + sizeof(header_line), FALSE);
1193
  store_get(sizeof(arc_set) + sizeof(arc_line) + sizeof(header_line), GET_UNTAINTED);
1198
arc_line * al = (arc_line *)(as+1);
1194
arc_line * al = (arc_line *)(as+1);
1199
header_line * h = (header_line *)(al+1);
1195
header_line * h = (header_line *)(al+1);
1200
1196
Lines 1304-1310 Link Here
1304
int hashtype = pdkim_hashname_to_hashtype(US"sha256", 6);	/*XXX hardwired */
1300
int hashtype = pdkim_hashname_to_hashtype(US"sha256", 6);	/*XXX hardwired */
1305
blob sig;
1301
blob sig;
1306
int ams_off;
1302
int ams_off;
1307
arc_line * al = store_get(sizeof(header_line) + sizeof(arc_line), FALSE);
1303
arc_line * al = store_get(sizeof(header_line) + sizeof(arc_line), GET_UNTAINTED);
1308
header_line * h = (header_line *)(al+1);
1304
header_line * h = (header_line *)(al+1);
1309
1305
1310
/* debug_printf("%s\n", __FUNCTION__); */
1306
/* debug_printf("%s\n", __FUNCTION__); */
Lines 1419-1425 Link Here
1419
{
1415
{
1420
gstring * arcset;
1416
gstring * arcset;
1421
uschar * status = arc_ar_cv_status(ar);
1417
uschar * status = arc_ar_cv_status(ar);
1422
arc_line * al = store_get(sizeof(header_line) + sizeof(arc_line), FALSE);
1418
arc_line * al = store_get(sizeof(header_line) + sizeof(arc_line), GET_UNTAINTED);
1423
header_line * h = (header_line *)(al+1);
1419
header_line * h = (header_line *)(al+1);
1424
uschar * badline_str;
1420
uschar * badline_str;
1425
1421
Lines 1531-1536 Link Here
1531
arc_sign_init(void)
1527
arc_sign_init(void)
1532
{
1528
{
1533
memset(&arc_sign_ctx, 0, sizeof(arc_sign_ctx));
1529
memset(&arc_sign_ctx, 0, sizeof(arc_sign_ctx));
1530
headers_rlist = NULL;
1534
}
1531
}
1535
1532
1536
1533
Lines 1557-1562 Link Here
1557
1554
1558
1555
1559
1556
1557
/* Per RFCs 6376, 7489 the only allowed chars in either an ADMD id
1558
or a selector are ALPHA/DIGGIT/'-'/'.'
1559
1560
Check, to help catch misconfigurations such as a missing selector
1561
element in the arc_sign list.
1562
*/
1563
1564
static BOOL
1565
arc_valid_id(const uschar * s)
1566
{
1567
for (uschar c; c = *s++; )
1568
  if (!isalnum(c) && c != '-' && c != '.') return FALSE;
1569
return TRUE;
1570
}
1571
1572
1573
1560
/* ARC signing.  Called from the smtp transport, if the arc_sign option is set.
1574
/* ARC signing.  Called from the smtp transport, if the arc_sign option is set.
1561
The dkim_exim_sign() function has already been called, so will have hashed the
1575
The dkim_exim_sign() function has already been called, so will have hashed the
1562
message body for us so long as we requested a hash previously.
1576
message body for us so long as we requested a hash previously.
Lines 1590-1606 Link Here
1590
1604
1591
/* Parse the signing specification */
1605
/* Parse the signing specification */
1592
1606
1593
identity = string_nextinlist(&signspec, &sep, NULL, 0);
1607
if (!(identity = string_nextinlist(&signspec, &sep, NULL, 0)) || !*identity)
1594
selector = string_nextinlist(&signspec, &sep, NULL, 0);
1608
  { s = US"identity"; goto bad_arg_ret; }
1595
if (  !*identity || !*selector
1609
if (!(selector = string_nextinlist(&signspec, &sep, NULL, 0)) || !*selector)
1596
   || !(privkey = string_nextinlist(&signspec, &sep, NULL, 0)) || !*privkey)
1610
  { s = US"selector"; goto bad_arg_ret; }
1597
  {
1611
if (!(privkey = string_nextinlist(&signspec, &sep, NULL, 0))  || !*privkey)
1598
  log_write(0, LOG_MAIN, "ARC: bad signing-specification (%s)",
1612
  { s = US"privkey"; goto bad_arg_ret; }
1599
    !*identity ? "identity" : !*selector ? "selector" : "private-key");
1613
if (!arc_valid_id(identity))
1600
  return sigheaders ? sigheaders : string_get(0);
1614
  { s = US"identity"; goto bad_arg_ret; }
1601
  }
1615
if (!arc_valid_id(selector))
1616
  { s = US"selector"; goto bad_arg_ret; }
1602
if (*privkey == '/' && !(privkey = expand_file_big_buffer(privkey)))
1617
if (*privkey == '/' && !(privkey = expand_file_big_buffer(privkey)))
1603
  return sigheaders ? sigheaders : string_get(0);
1618
  goto ret_sigheaders;
1604
1619
1605
if ((opts = string_nextinlist(&signspec, &sep, NULL, 0)))
1620
if ((opts = string_nextinlist(&signspec, &sep, NULL, 0)))
1606
  {
1621
  {
Lines 1659-1665 Link Here
1659
if (!(arc_sign_find_ar(headers, identity, &ar)))
1674
if (!(arc_sign_find_ar(headers, identity, &ar)))
1660
  {
1675
  {
1661
  log_write(0, LOG_MAIN, "ARC: no Authentication-Results header for signing");
1676
  log_write(0, LOG_MAIN, "ARC: no Authentication-Results header for signing");
1662
  return sigheaders ? sigheaders : string_get(0);
1677
  goto ret_sigheaders;
1663
  }
1678
  }
1664
1679
1665
/* We previously built the data-struct for the existing ARC chain, if any, using a headers
1680
/* We previously built the data-struct for the existing ARC chain, if any, using a headers
Lines 1715-1723 Link Here
1715
/* Finally, append the dkim headers and return the lot. */
1730
/* Finally, append the dkim headers and return the lot. */
1716
1731
1717
if (sigheaders) g = string_catn(g, sigheaders->s, sigheaders->ptr);
1732
if (sigheaders) g = string_catn(g, sigheaders->s, sigheaders->ptr);
1718
(void) string_from_gstring(g);
1733
1719
gstring_release_unused(g);
1734
out:
1720
return g;
1735
  if (!g) return string_get(1);
1736
  (void) string_from_gstring(g);
1737
  gstring_release_unused(g);
1738
  return g;
1739
1740
1741
bad_arg_ret:
1742
  log_write(0, LOG_MAIN, "ARC: bad signing-specification (%s)", s);
1743
ret_sigheaders:
1744
  g = sigheaders;
1745
  goto out;
1721
}
1746
}
1722
1747
1723
1748
(-)exim.orig/src/auths/auth-spa.c (-2 / +2 lines)
Lines 8-13 Link Here
8
8
9
 * All the original code used here was torn by Marc Prud'hommeaux out of the
9
 * All the original code used here was torn by Marc Prud'hommeaux out of the
10
 * Samba project (by Andrew Tridgell, Jeremy Allison, and others).
10
 * Samba project (by Andrew Tridgell, Jeremy Allison, and others).
11
 *
12
 * Copyright (c) The Exim Maintainers 2021
11
13
12
 * Tom Kistner provided additional code, adding spa_build_auth_challenge() to
14
 * Tom Kistner provided additional code, adding spa_build_auth_challenge() to
13
 * support server authentication mode.
15
 * support server authentication mode.
Lines 1395-1402 Link Here
1395
int p = (int)getpid();
1397
int p = (int)getpid();
1396
int random_seed = (int)time(NULL) ^ ((p << 16) | p);
1398
int random_seed = (int)time(NULL) ^ ((p << 16) | p);
1397
1399
1398
request = request;  /* Added by PH to stop compilers whinging */
1399
1400
/* Ensure challenge data is cleared, in case it isn't all used. This
1400
/* Ensure challenge data is cleared, in case it isn't all used. This
1401
patch added by PH on suggestion of Russell King */
1401
patch added by PH on suggestion of Russell King */
1402
1402
(-)exim.orig/src/auths/call_pam.c (-2 / +2 lines)
Lines 3-9 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
6
/* Copyright (c) The Exim Maintainers 2020 - 2021 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#include "../exim.h"
9
#include "../exim.h"
Lines 88-94 Link Here
88
	arg = US"";
88
	arg = US"";
89
	pam_arg_ended = TRUE;
89
	pam_arg_ended = TRUE;
90
	}
90
	}
91
      reply[i].resp = CS string_copy_malloc(arg); /* PAM frees resp */
91
      reply[i].resp = strdup(CCS arg); /* Use libc malloc, PAM frees resp directly*/
92
      reply[i].resp_retcode = PAM_SUCCESS;
92
      reply[i].resp_retcode = PAM_SUCCESS;
93
      break;
93
      break;
94
94
(-)exim.orig/src/auths/call_radius.c (-21 / +12 lines)
Lines 2-24 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 */
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
6
/* Copyright (c) University of Cambridge 1995 - 2016 */
6
/* Copyright (c) University of Cambridge 1995 - 2016 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* This file was originally supplied by Ian Kirk. The libradius support came
9
/* This file was originally supplied by Ian Kirk. The libradius support came
10
from Alex Kiernan. */
10
from Alex Kiernan. */
11
11
12
/* ugly hack to work around redefinition of ENV by radiusclient.h and
13
 * db.h: define _DB_H_ so the db.h include thinks it's already included,
14
 * we can get away with it like this, since this file doesn't use any db
15
 * functions. */
16
#ifndef _DB_H_
17
# define _DB_H_ 1
18
# define _DB_EXT_PROT_IN_ 1
19
# define DB void
20
#endif
21
22
#include "../exim.h"
12
#include "../exim.h"
23
13
24
/* This module contains functions that call the Radius authentication
14
/* This module contains functions that call the Radius authentication
Lines 44-60 Link Here
44
using its original API. At release 0.4.0 the API changed. */
34
using its original API. At release 0.4.0 the API changed. */
45
35
46
#ifdef RADIUS_LIB_RADLIB
36
#ifdef RADIUS_LIB_RADLIB
47
  #include <radlib.h>
37
# include <radlib.h>
48
#else
38
#else
49
  #if !defined(RADIUS_LIB_RADIUSCLIENT) && !defined(RADIUS_LIB_RADIUSCLIENTNEW)
39
# if !defined(RADIUS_LIB_RADIUSCLIENT) && !defined(RADIUS_LIB_RADIUSCLIENTNEW)
50
  # define RADIUS_LIB_RADIUSCLIENT
40
#  define RADIUS_LIB_RADIUSCLIENT
51
  #endif
41
# endif
52
42
53
  #ifdef RADIUS_LIB_RADIUSCLIENTNEW
43
# ifdef RADIUS_LIB_RADIUSCLIENTNEW
54
  # include <freeradius-client.h>
44
#  define ENV FREERADIUSCLIENT_ENV	/* Avoid clash with Berkeley DB */
55
  #else
45
#  include <freeradius-client.h>
56
  # include <radiusclient.h>
46
# else
57
  #endif
47
#  include <radiusclient.h>
48
# endif
58
#endif
49
#endif
59
50
60
51
(-)exim.orig/src/auths/cyrus_sasl.c (-11 / +13 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* This code was originally contributed by Matthew Byng-Maddick */
9
/* This code was originally contributed by Matthew Byng-Maddick */
Lines 71-77 Link Here
71
int auth_cyrus_sasl_server(auth_instance *ablock, uschar *data) {return 0;}
71
int auth_cyrus_sasl_server(auth_instance *ablock, uschar *data) {return 0;}
72
int auth_cyrus_sasl_client(auth_instance *ablock, void * sx,
72
int auth_cyrus_sasl_client(auth_instance *ablock, void * sx,
73
  int timeout, uschar *buffer, int buffsize) {return 0;}
73
  int timeout, uschar *buffer, int buffsize) {return 0;}
74
void auth_cyrus_sasl_version_report(FILE *f) {}
74
gstring * auth_cyrus_sasl_version_report(gstring * g) {return NULL;}
75
75
76
#else   /*!MACRO_PREDEF*/
76
#else   /*!MACRO_PREDEF*/
77
77
Lines 378-384 Link Here
378
    HDEBUG(D_auth)
378
    HDEBUG(D_auth)
379
      debug_printf("Cyrus SASL library will not tell us the username: %s\n",
379
      debug_printf("Cyrus SASL library will not tell us the username: %s\n",
380
	  sasl_errstring(rc, NULL, NULL));
380
	  sasl_errstring(rc, NULL, NULL));
381
    log_write(0, LOG_REJECT, "%s authenticator (%s):\n  "
381
    log_write(0, LOG_REJECT, "%s authenticator (%s): "
382
       "Cyrus SASL username fetch problem: %s", ablock->name, ob->server_mech,
382
       "Cyrus SASL username fetch problem: %s", ablock->name, ob->server_mech,
383
       sasl_errstring(rc, NULL, NULL));
383
       sasl_errstring(rc, NULL, NULL));
384
    sasl_dispose(&conn);
384
    sasl_dispose(&conn);
Lines 397-403 Link Here
397
      /* these are considered permanent failure codes */
397
      /* these are considered permanent failure codes */
398
      HDEBUG(D_auth)
398
      HDEBUG(D_auth)
399
	debug_printf("Cyrus SASL permanent failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
399
	debug_printf("Cyrus SASL permanent failure %d (%s)\n", rc, sasl_errstring(rc, NULL, NULL));
400
      log_write(0, LOG_REJECT, "%s authenticator (%s):\n  "
400
      log_write(0, LOG_REJECT, "%s authenticator (%s): "
401
	 "Cyrus SASL permanent failure: %s", ablock->name, ob->server_mech,
401
	 "Cyrus SASL permanent failure: %s", ablock->name, ob->server_mech,
402
	 sasl_errstring(rc, NULL, NULL));
402
	 sasl_errstring(rc, NULL, NULL));
403
      sasl_dispose(&conn);
403
      sasl_dispose(&conn);
Lines 427-433 Link Here
427
	HDEBUG(D_auth)
427
	HDEBUG(D_auth)
428
	  debug_printf("Cyrus SASL library will not tell us the SSF: %s\n",
428
	  debug_printf("Cyrus SASL library will not tell us the SSF: %s\n",
429
	      sasl_errstring(rc, NULL, NULL));
429
	      sasl_errstring(rc, NULL, NULL));
430
	log_write(0, LOG_REJECT, "%s authenticator (%s):\n  "
430
	log_write(0, LOG_REJECT, "%s authenticator (%s): "
431
	    "Cyrus SASL SSF value not available: %s", ablock->name, ob->server_mech,
431
	    "Cyrus SASL SSF value not available: %s", ablock->name, ob->server_mech,
432
	    sasl_errstring(rc, NULL, NULL));
432
	    sasl_errstring(rc, NULL, NULL));
433
	sasl_dispose(&conn);
433
	sasl_dispose(&conn);
Lines 441-447 Link Here
441
	{
441
	{
442
	HDEBUG(D_auth)
442
	HDEBUG(D_auth)
443
	  debug_printf("Exim does not implement SASL wrapping (needed for SSF %d).\n", negotiated_ssf);
443
	  debug_printf("Exim does not implement SASL wrapping (needed for SSF %d).\n", negotiated_ssf);
444
	log_write(0, LOG_REJECT, "%s authenticator (%s):\n  "
444
	log_write(0, LOG_REJECT, "%s authenticator (%s): "
445
	    "Cyrus SASL SSF %d not supported by Exim", ablock->name, ob->server_mech, negotiated_ssf);
445
	    "Cyrus SASL SSF %d not supported by Exim", ablock->name, ob->server_mech, negotiated_ssf);
446
	sasl_dispose(&conn);
446
	sasl_dispose(&conn);
447
	sasl_done();
447
	sasl_done();
Lines 476-490 Link Here
476
*                Diagnostic API                  *
476
*                Diagnostic API                  *
477
*************************************************/
477
*************************************************/
478
478
479
void
479
gstring *
480
auth_cyrus_sasl_version_report(FILE *f)
480
auth_cyrus_sasl_version_report(gstring * g)
481
{
481
{
482
const char *implementation, *version;
482
const char * implementation, * version;
483
sasl_version_info(&implementation, &version, NULL, NULL, NULL, NULL);
483
sasl_version_info(&implementation, &version, NULL, NULL, NULL, NULL);
484
fprintf(f, "Library version: Cyrus SASL: Compile: %d.%d.%d\n"
484
g = string_fmt_append(g,
485
	   "                             Runtime: %s [%s]\n",
485
	"Library version: Cyrus SASL: Compile: %d.%d.%d\n"
486
	"                             Runtime: %s [%s]\n",
486
	SASL_VERSION_MAJOR, SASL_VERSION_MINOR, SASL_VERSION_STEP,
487
	SASL_VERSION_MAJOR, SASL_VERSION_MINOR, SASL_VERSION_STEP,
487
	version, implementation);
488
	version, implementation);
489
return g;
488
}
490
}
489
491
490
/*************************************************
492
/*************************************************
(-)exim.orig/src/auths/cyrus_sasl.h (-1 / +2 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2012 */
6
/* Copyright (c) University of Cambridge 1995 - 2012 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 30-35 Link Here
30
extern void auth_cyrus_sasl_init(auth_instance *);
31
extern void auth_cyrus_sasl_init(auth_instance *);
31
extern int auth_cyrus_sasl_server(auth_instance *, uschar *);
32
extern int auth_cyrus_sasl_server(auth_instance *, uschar *);
32
extern int auth_cyrus_sasl_client(auth_instance *, void *, int, uschar *, int);
33
extern int auth_cyrus_sasl_client(auth_instance *, void *, int, uschar *, int);
33
extern void auth_cyrus_sasl_version_report(FILE *f);
34
extern gstring * auth_cyrus_sasl_version_report(gstring *);
34
35
35
/* End of cyrus_sasl.h */
36
/* End of cyrus_sasl.h */
(-)exim.orig/src/auths/dovecot.c (-3 / +12 lines)
Lines 1-6 Link Here
1
/*
1
/*
2
 * Copyright (c) The Exim Maintainers 2006 - 2022
2
 * Copyright (c) 2004 Andrey Panin <pazke@donpac.ru>
3
 * Copyright (c) 2004 Andrey Panin <pazke@donpac.ru>
3
 * Copyright (c) 2006-2020 The Exim Maintainers
4
 *
4
 *
5
 * This program is free software; you can redistribute it and/or modify
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published
6
 * it under the terms of the GNU General Public License as published
Lines 275-285 Link Here
275
# ifndef DISABLE_TLS
275
# ifndef DISABLE_TLS
276
if (ob->server_tls)
276
if (ob->server_tls)
277
  {
277
  {
278
  uschar * s;
278
  union sockaddr_46 interface_sock;
279
  EXIM_SOCKLEN_T size = sizeof(interface_sock);
279
  smtp_connect_args conn_args = { .host = &host };
280
  smtp_connect_args conn_args = { .host = &host };
280
  tls_support tls_dummy = {.sni=NULL};
281
  tls_support tls_dummy = { .sni = NULL };
281
  uschar * errstr;
282
  uschar * errstr;
282
283
284
  if (getsockname(cctx->sock, (struct sockaddr *) &interface_sock, &size) == 0)
285
    conn_args.sending_ip_address = host_ntoa(-1, &interface_sock, NULL, NULL);
286
  else
287
    {
288
    *errmsg = string_sprintf("getsockname failed: %s", strerror(errno));
289
    goto bad;
290
    }
291
283
  if (!tls_client_start(&cctx, &conn_args, NULL, &tls_dummy, &errstr))
292
  if (!tls_client_start(&cctx, &conn_args, NULL, &tls_dummy, &errstr))
284
    {
293
    {
285
    auth_defer_msg = string_sprintf("TLS connect failed: %s", errstr);
294
    auth_defer_msg = string_sprintf("TLS connect failed: %s", errstr);
(-)exim.orig/src/auths/get_data.c (-1 / +1 lines)
Lines 3-9 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
6
/* Copyright (c) The Exim Maintainers 2020 - 2021 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#include "../exim.h"
9
#include "../exim.h"
(-)exim.orig/src/auths/gsasl_exim.c (-98 / +140 lines)
Lines 2-8 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2019-2020 */
5
/* Copyright (c) The Exim Maintainers 2019 - 2022 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
Lines 27-33 Link Here
27
*/
27
*/
28
28
29
#include "../exim.h"
29
#include "../exim.h"
30
#define CHANNELBIND_HACK
31
30
32
#ifndef AUTH_GSASL
31
#ifndef AUTH_GSASL
33
/* dummy function to satisfy compilers when we link in an "empty" file. */
32
/* dummy function to satisfy compilers when we link in an "empty" file. */
Lines 40-53 Link Here
40
#include "gsasl_exim.h"
39
#include "gsasl_exim.h"
41
40
42
41
43
#if GSASL_VERSION_MINOR >= 9
42
#if GSASL_VERSION_MINOR >= 10
43
# define EXIM_GSASL_HAVE_SCRAM_SHA_256
44
# define EXIM_GSASL_SCRAM_S_KEY
45
46
#elif GSASL_VERSION_MINOR == 9
44
# define EXIM_GSASL_HAVE_SCRAM_SHA_256
47
# define EXIM_GSASL_HAVE_SCRAM_SHA_256
45
48
46
# if GSASL_VERSION_PATCH >= 1
49
# if GSASL_VERSION_PATCH >= 1
47
#  define EXIM_GSASL_SCRAM_S_KEY
50
#  define EXIM_GSASL_SCRAM_S_KEY
48
# endif
51
# endif
52
# if GSASL_VERSION_PATCH < 2
53
#  define CHANNELBIND_HACK
54
# endif
55
56
#else
57
# define CHANNELBIND_HACK
49
#endif
58
#endif
50
59
60
/* Convenience for testing strings */
61
62
#define STREQIC(Foo, Bar) (strcmpic((Foo), (Bar)) == 0)
63
51
64
52
/* Authenticator-specific options. */
65
/* Authenticator-specific options. */
53
/* I did have server_*_condition options for various mechanisms, but since
66
/* I did have server_*_condition options for various mechanisms, but since
Lines 99-105 Link Here
99
int auth_gsasl_server(auth_instance *ablock, uschar *data) {return 0;}
112
int auth_gsasl_server(auth_instance *ablock, uschar *data) {return 0;}
100
int auth_gsasl_client(auth_instance *ablock, void * sx,
113
int auth_gsasl_client(auth_instance *ablock, void * sx,
101
  int timeout, uschar *buffer, int buffsize) {return 0;}
114
  int timeout, uschar *buffer, int buffsize) {return 0;}
102
void auth_gsasl_version_report(FILE *f) {}
115
gstring * auth_gsasl_version_report(gstring * g) {return NULL;}
103
116
104
void
117
void
105
auth_gsasl_macros(void)
118
auth_gsasl_macros(void)
Lines 191-205 Link Here
191
	    "GNU SASL does not support mechanism \"%s\"",
204
	    "GNU SASL does not support mechanism \"%s\"",
192
	    ablock->name, ob->server_mech);
205
	    ablock->name, ob->server_mech);
193
206
194
ablock->server = TRUE;
207
if (ablock->server_condition)
208
  ablock->server = TRUE;
209
else if(  ob->server_mech
210
       && !STREQIC(ob->server_mech, US"EXTERNAL")
211
       && !STREQIC(ob->server_mech, US"ANONYMOUS")
212
       && !STREQIC(ob->server_mech, US"PLAIN")
213
       && !STREQIC(ob->server_mech, US"LOGIN")
214
       )
215
  {
216
  /* At present, for mechanisms we don't panic on absence of server_condition;
217
  need to figure out the most generically correct approach to deciding when
218
  it's critical and when it isn't.  Eg, for simple validation (PLAIN mechanism,
219
  etc) it clearly is critical.
220
  */
195
221
196
if (  !ablock->server_condition
197
   && (  streqic(ob->server_mech, US"EXTERNAL")
198
      || streqic(ob->server_mech, US"ANONYMOUS")
199
      || streqic(ob->server_mech, US"PLAIN")
200
      || streqic(ob->server_mech, US"LOGIN")
201
   )  )
202
  {
203
  ablock->server = FALSE;
222
  ablock->server = FALSE;
204
  HDEBUG(D_auth) debug_printf("%s authenticator:  "
223
  HDEBUG(D_auth) debug_printf("%s authenticator:  "
205
	    "Need server_condition for %s mechanism\n",
224
	    "Need server_condition for %s mechanism\n",
Lines 210-216 Link Here
210
which properties will be needed. */
229
which properties will be needed. */
211
230
212
if (  !ob->server_realm
231
if (  !ob->server_realm
213
   && streqic(ob->server_mech, US"DIGEST-MD5"))
232
   && STREQIC(ob->server_mech, US"DIGEST-MD5"))
214
  {
233
  {
215
  ablock->server = FALSE;
234
  ablock->server = FALSE;
216
  HDEBUG(D_auth) debug_printf("%s authenticator:  "
235
  HDEBUG(D_auth) debug_printf("%s authenticator:  "
Lines 218-229 Link Here
218
	    ablock->name, ob->server_mech);
237
	    ablock->name, ob->server_mech);
219
  }
238
  }
220
239
221
/* At present, for mechanisms we don't panic on absence of server_condition;
222
need to figure out the most generically correct approach to deciding when
223
it's critical and when it isn't.  Eg, for simple validation (PLAIN mechanism,
224
etc) it clearly is critical.
225
*/
226
227
ablock->client = ob->client_username && ob->client_password;
240
ablock->client = ob->client_username && ob->client_password;
228
}
241
}
229
242
Lines 299-342 Link Here
299
{
312
{
300
switch (prop)
313
switch (prop)
301
  {
314
  {
302
  case GSASL_AUTHID: return US"AUTHID";
315
  case GSASL_AUTHID:			return US"AUTHID";
303
  case GSASL_AUTHZID: return US"AUTHZID";
316
  case GSASL_AUTHZID:			return US"AUTHZID";
304
  case GSASL_PASSWORD: return US"PASSWORD";
317
  case GSASL_PASSWORD:			return US"PASSWORD";
305
  case GSASL_ANONYMOUS_TOKEN: return US"ANONYMOUS_TOKEN";
318
  case GSASL_ANONYMOUS_TOKEN:		return US"ANONYMOUS_TOKEN";
306
  case GSASL_SERVICE: return US"SERVICE";
319
  case GSASL_SERVICE:			return US"SERVICE";
307
  case GSASL_HOSTNAME: return US"HOSTNAME";
320
  case GSASL_HOSTNAME:			return US"HOSTNAME";
308
  case GSASL_GSSAPI_DISPLAY_NAME: return US"GSSAPI_DISPLAY_NAME";
321
  case GSASL_GSSAPI_DISPLAY_NAME:	return US"GSSAPI_DISPLAY_NAME";
309
  case GSASL_PASSCODE: return US"PASSCODE";
322
  case GSASL_PASSCODE:			return US"PASSCODE";
310
  case GSASL_SUGGESTED_PIN: return US"SUGGESTED_PIN";
323
  case GSASL_SUGGESTED_PIN:		return US"SUGGESTED_PIN";
311
  case GSASL_PIN: return US"PIN";
324
  case GSASL_PIN:			return US"PIN";
312
  case GSASL_REALM: return US"REALM";
325
  case GSASL_REALM:			return US"REALM";
313
  case GSASL_DIGEST_MD5_HASHED_PASSWORD: return US"DIGEST_MD5_HASHED_PASSWORD";
326
  case GSASL_DIGEST_MD5_HASHED_PASSWORD:	return US"DIGEST_MD5_HASHED_PASSWORD";
314
  case GSASL_QOPS: return US"QOPS";
327
  case GSASL_QOPS:			return US"QOPS";
315
  case GSASL_QOP: return US"QOP";
328
  case GSASL_QOP:			return US"QOP";
316
  case GSASL_SCRAM_ITER: return US"SCRAM_ITER";
329
  case GSASL_SCRAM_ITER:		return US"SCRAM_ITER";
317
  case GSASL_SCRAM_SALT: return US"SCRAM_SALT";
330
  case GSASL_SCRAM_SALT:		return US"SCRAM_SALT";
318
  case GSASL_SCRAM_SALTED_PASSWORD: return US"SCRAM_SALTED_PASSWORD";
331
  case GSASL_SCRAM_SALTED_PASSWORD:	return US"SCRAM_SALTED_PASSWORD";
319
#ifdef EXIM_GSASL_SCRAM_S_KEY
320
  case GSASL_SCRAM_STOREDKEY: return US"SCRAM_STOREDKEY";
321
  case GSASL_SCRAM_SERVERKEY: return US"SCRAM_SERVERKEY";
322
#endif
323
  case GSASL_CB_TLS_UNIQUE: return US"CB_TLS_UNIQUE";
324
  case GSASL_SAML20_IDP_IDENTIFIER: return US"SAML20_IDP_IDENTIFIER";
325
  case GSASL_SAML20_REDIRECT_URL: return US"SAML20_REDIRECT_URL";
326
  case GSASL_OPENID20_REDIRECT_URL: return US"OPENID20_REDIRECT_URL";
327
  case GSASL_OPENID20_OUTCOME_DATA: return US"OPENID20_OUTCOME_DATA";
328
  case GSASL_SAML20_AUTHENTICATE_IN_BROWSER: return US"SAML20_AUTHENTICATE_IN_BROWSER";
329
  case GSASL_OPENID20_AUTHENTICATE_IN_BROWSER: return US"OPENID20_AUTHENTICATE_IN_BROWSER";
330
#ifdef EXIM_GSASL_SCRAM_S_KEY
332
#ifdef EXIM_GSASL_SCRAM_S_KEY
331
  case GSASL_SCRAM_CLIENTKEY: return US"SCRAM_CLIENTKEY";
333
  case GSASL_SCRAM_STOREDKEY:		return US"SCRAM_STOREDKEY";
334
  case GSASL_SCRAM_SERVERKEY:		return US"SCRAM_SERVERKEY";
332
#endif
335
#endif
333
  case GSASL_VALIDATE_SIMPLE: return US"VALIDATE_SIMPLE";
336
  case GSASL_CB_TLS_UNIQUE:		return US"CB_TLS_UNIQUE";
334
  case GSASL_VALIDATE_EXTERNAL: return US"VALIDATE_EXTERNAL";
337
  case GSASL_SAML20_IDP_IDENTIFIER:	return US"SAML20_IDP_IDENTIFIER";
335
  case GSASL_VALIDATE_ANONYMOUS: return US"VALIDATE_ANONYMOUS";
338
  case GSASL_SAML20_REDIRECT_URL:	return US"SAML20_REDIRECT_URL";
336
  case GSASL_VALIDATE_GSSAPI: return US"VALIDATE_GSSAPI";
339
  case GSASL_OPENID20_REDIRECT_URL:	return US"OPENID20_REDIRECT_URL";
337
  case GSASL_VALIDATE_SECURID: return US"VALIDATE_SECURID";
340
  case GSASL_OPENID20_OUTCOME_DATA:	return US"OPENID20_OUTCOME_DATA";
338
  case GSASL_VALIDATE_SAML20: return US"VALIDATE_SAML20";
341
  case GSASL_SAML20_AUTHENTICATE_IN_BROWSER:	return US"SAML20_AUTHENTICATE_IN_BROWSER";
339
  case GSASL_VALIDATE_OPENID20: return US"VALIDATE_OPENID20";
342
  case GSASL_OPENID20_AUTHENTICATE_IN_BROWSER:	return US"OPENID20_AUTHENTICATE_IN_BROWSER";
343
  case GSASL_VALIDATE_SIMPLE:		return US"VALIDATE_SIMPLE";
344
  case GSASL_VALIDATE_EXTERNAL:		return US"VALIDATE_EXTERNAL";
345
  case GSASL_VALIDATE_ANONYMOUS:	return US"VALIDATE_ANONYMOUS";
346
  case GSASL_VALIDATE_GSSAPI:		return US"VALIDATE_GSSAPI";
347
  case GSASL_VALIDATE_SECURID:		return US"VALIDATE_SECURID";
348
  case GSASL_VALIDATE_SAML20:		return US"VALIDATE_SAML20";
349
  case GSASL_VALIDATE_OPENID20:		return US"VALIDATE_OPENID20";
340
  }
350
  }
341
return CUS string_sprintf("(unknown prop: %d)", (int)prop);
351
return CUS string_sprintf("(unknown prop: %d)", (int)prop);
342
}
352
}
Lines 365-371 Link Here
365
#ifndef DISABLE_TLS
375
#ifndef DISABLE_TLS
366
if (tls_in.channelbinding && ob->server_channelbinding)
376
if (tls_in.channelbinding && ob->server_channelbinding)
367
  {
377
  {
368
# ifdef EXPERIMENTAL_TLS_RESUME
378
# ifndef DISABLE_TLS_RESUME
369
  if (!tls_in.ext_master_secret && tls_in.resumption == RESUME_USED)
379
  if (!tls_in.ext_master_secret && tls_in.resumption == RESUME_USED)
370
    {		/* per RFC 7677 section 4 */
380
    {		/* per RFC 7677 section 4 */
371
    HDEBUG(D_auth) debug_printf(
381
    HDEBUG(D_auth) debug_printf(
Lines 374-382 Link Here
374
    }
384
    }
375
# endif
385
# endif
376
# ifdef CHANNELBIND_HACK
386
# ifdef CHANNELBIND_HACK
377
/* This is a gross hack to get around the library a) requiring that
387
/* This is a gross hack to get around the library before 1.9.2
378
c-b was already set, at the _start() call, and b) caching a b64'd
388
a) requiring that c-b was already set, at the _start() call, and
379
version of the binding then which it never updates. */
389
b) caching a b64'd version of the binding then which it never updates. */
380
390
381
  gsasl_callback_hook_set(gsasl_ctx, tls_in.channelbinding);
391
  gsasl_callback_hook_set(gsasl_ctx, tls_in.channelbinding);
382
# endif
392
# endif
Lines 429-434 Link Here
429
  would then result in mechanism name changes on a library update, we
439
  would then result in mechanism name changes on a library update, we
430
  have little choice but to default it off and let the admin choose to
440
  have little choice but to default it off and let the admin choose to
431
  enable it.  *sigh*
441
  enable it.  *sigh*
442
443
  Earlier library versions need this set early, during the _start() call,
444
  so we had to misuse gsasl_callback_hook_set/get() as a data transfer
445
  mech for the callback done at that time to get the bind-data.  More recently
446
  the callback is done (if needed) during the first gsasl_stop().  We know
447
  the bind-data here so can set it (and should not get a callback).
432
  */
448
  */
433
  if (ob->server_channelbinding)
449
  if (ob->server_channelbinding)
434
    {
450
    {
Lines 570-583 Link Here
570
}
586
}
571
587
572
588
589
/* Set the "next" $auth[n] and increment expand_nmax */
590
573
static void
591
static void
574
set_exim_authvar_from_prop(Gsasl_session * sctx, Gsasl_property prop)
592
set_exim_authvar_from_prop(Gsasl_session * sctx, Gsasl_property prop)
575
{
593
{
576
uschar * propval = US gsasl_property_fast(sctx, prop);
594
uschar * propval = US gsasl_property_fast(sctx, prop);
577
int i = expand_nmax, j = i + 1;
595
int i = expand_nmax, j = i + 1;
578
propval = propval ? string_copy(propval) : US"";
596
propval = propval ? string_copy(propval) : US"";
579
auth_vars[i] = expand_nstring[j] = propval;
597
HDEBUG(D_auth) debug_printf("auth[%d] <=  %s'%s'\n",
598
			    j, gsasl_prop_code_to_name(prop), propval);
599
expand_nstring[j] = propval;
580
expand_nlength[j] = Ustrlen(propval);
600
expand_nlength[j] = Ustrlen(propval);
601
if (i < AUTH_VARS) auth_vars[i] = propval;
581
expand_nmax = j;
602
expand_nmax = j;
582
}
603
}
583
604
Lines 621-630 Link Here
621
server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop,
642
server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop,
622
  auth_instance *ablock)
643
  auth_instance *ablock)
623
{
644
{
624
char *tmps;
645
char * tmps;
625
uschar *s, *propval;
646
uschar * s;
626
int cbrc = GSASL_NO_CALLBACK;
647
int cbrc = GSASL_NO_CALLBACK;
627
auth_gsasl_options_block *ob =
648
auth_gsasl_options_block * ob =
628
  (auth_gsasl_options_block *)(ablock->options_block);
649
  (auth_gsasl_options_block *)(ablock->options_block);
629
650
630
HDEBUG(D_auth) debug_printf("GNU SASL callback %s for %s/%s as server\n",
651
HDEBUG(D_auth) debug_printf("GNU SASL callback %s for %s/%s as server\n",
Lines 740-746 Link Here
740
    for memory wiping, so expanding strings will leave stuff laying around.
761
    for memory wiping, so expanding strings will leave stuff laying around.
741
    But no need to compound the problem, so get rid of the one we can. */
762
    But no need to compound the problem, so get rid of the one we can. */
742
763
743
    memset(tmps, '\0', strlen(tmps));
764
    if (US tmps != s) memset(tmps, '\0', strlen(tmps));
744
    cbrc = GSASL_OK;
765
    cbrc = GSASL_OK;
745
    break;
766
    break;
746
767
Lines 765-771 Link Here
765
  unsigned flags, uschar * buffer, int buffsize)
786
  unsigned flags, uschar * buffer, int buffsize)
766
{
787
{
767
uschar * s;
788
uschar * s;
768
int rc;
769
789
770
if (!val) return !!(flags & PROP_OPTIONAL);
790
if (!val) return !!(flags & PROP_OPTIONAL);
771
if (!(s = expand_string(val)) || !(flags & PROP_OPTIONAL) && !*s)
791
if (!(s = expand_string(val)) || !(flags & PROP_OPTIONAL) && !*s)
Lines 814-831 Link Here
814
#ifndef DISABLE_TLS
834
#ifndef DISABLE_TLS
815
if (tls_out.channelbinding && ob->client_channelbinding)
835
if (tls_out.channelbinding && ob->client_channelbinding)
816
  {
836
  {
817
# ifdef EXPERIMENTAL_TLS_RESUME
837
# ifndef DISABLE_TLS_RESUME
818
  if (!tls_out.ext_master_secret && tls_out.resumption == RESUME_USED)
838
  if (!tls_out.ext_master_secret && tls_out.resumption == RESUME_USED)
819
    {		/* per RFC 7677 section 4 */
839
    {	/* Per RFC 7677 section 4.  See also RFC 7627, "Triple Handshake"
840
	vulnerability, and https://www.mitls.org/pages/attacks/3SHAKE */
820
    string_format(buffer, buffsize, "%s",
841
    string_format(buffer, buffsize, "%s",
821
      "channel binding not usable on resumed TLS without extended-master-secret");
842
      "channel binding not usable on resumed TLS without extended-master-secret");
822
    return FAIL;
843
    return FAIL;
823
    }
844
    }
824
# endif
845
# endif
825
# ifdef CHANNELBIND_HACK
846
# ifdef CHANNELBIND_HACK
826
  /* This is a gross hack to get around the library a) requiring that
847
  /* This is a gross hack to get around the library before 1.9.2
827
  c-b was already set, at the _start() call, and b) caching a b64'd
848
  a) requiring that c-b was already set, at the _start() call, and
828
  version of the binding then which it never updates. */
849
  b) caching a b64'd version of the binding then which it never updates. */
829
850
830
  gsasl_callback_hook_set(gsasl_ctx, tls_out.channelbinding);
851
  gsasl_callback_hook_set(gsasl_ctx, tls_out.channelbinding);
831
# endif
852
# endif
Lines 846-855 Link Here
846
867
847
/* Set properties */
868
/* Set properties */
848
869
849
if (  !set_client_prop(sctx, GSASL_SCRAM_SALTED_PASSWORD, ob->client_spassword,
870
if (  !set_client_prop(sctx, GSASL_PASSWORD, ob->client_password,
850
		  0, buffer, buffsize)
851
      &&
852
      !set_client_prop(sctx, GSASL_PASSWORD, ob->client_password,
853
		  0, buffer, buffsize)
871
		  0, buffer, buffsize)
854
   || !set_client_prop(sctx, GSASL_AUTHID, ob->client_username,
872
   || !set_client_prop(sctx, GSASL_AUTHID, ob->client_username,
855
		  0, buffer, buffsize)
873
		  0, buffer, buffsize)
Lines 879-902 Link Here
879
for(s = NULL; ;)
897
for(s = NULL; ;)
880
  {
898
  {
881
  uschar * outstr;
899
  uschar * outstr;
882
  BOOL fail;
900
  BOOL fail = TRUE;
883
901
884
  rc = gsasl_step64(sctx, CS s, CSS &outstr);
902
  rc = gsasl_step64(sctx, CS s, CSS &outstr);
885
903
886
  fail = initial
904
  if (rc == GSASL_NEEDS_MORE || rc == GSASL_OK)
887
    ? smtp_write_command(sx, SCMD_FLUSH,
888
			outstr ? "AUTH %s %s\r\n" : "AUTH %s\r\n",
889
			ablock->public_name, outstr) <= 0
890
    : outstr
891
    ? smtp_write_command(sx, SCMD_FLUSH, "%s\r\n", outstr) <= 0
892
    : FALSE;
893
  if (outstr && *outstr) free(outstr);
894
  if (fail)
895
    {
905
    {
896
    yield = FAIL_SEND;
906
    fail = initial
897
    goto done;
907
      ? smtp_write_command(sx, SCMD_FLUSH,
908
			  outstr ? "AUTH %s %s\r\n" : "AUTH %s\r\n",
909
			  ablock->public_name, outstr) <= 0
910
      : outstr
911
      ? smtp_write_command(sx, SCMD_FLUSH, "%s\r\n", outstr) <= 0
912
      : FALSE;
913
    free(outstr);
914
    if (fail)
915
      {
916
      yield = FAIL_SEND;
917
      goto done;
918
      }
919
    initial = FALSE;
898
    }
920
    }
899
  initial = FALSE;
900
921
901
  if (rc != GSASL_NEEDS_MORE)
922
  if (rc != GSASL_NEEDS_MORE)
902
    {
923
    {
Lines 927-936 Link Here
927
  }
948
  }
928
949
929
done:
950
done:
930
HDEBUG(D_auth)
951
if (yield == OK)
931
  {
952
  {
932
  const uschar * s = CUS gsasl_property_fast(sctx, GSASL_SCRAM_SALTED_PASSWORD);
953
  expand_nmax = 0;
933
  if (s) debug_printf(" - SaltedPassword: '%s'\n", s);
954
  set_exim_authvar_from_prop(sctx, GSASL_AUTHID);
955
  set_exim_authvar_from_prop(sctx, GSASL_SCRAM_ITER);
956
  set_exim_authvar_from_prop(sctx, GSASL_SCRAM_SALT);
957
  set_exim_authvar_from_prop(sctx, GSASL_SCRAM_SALTED_PASSWORD);
934
  }
958
  }
935
959
936
gsasl_finish(sctx);
960
gsasl_finish(sctx);
Lines 944-954 Link Here
944
	    gsasl_prop_code_to_name(prop), ablock->name, ablock->public_name);
968
	    gsasl_prop_code_to_name(prop), ablock->name, ablock->public_name);
945
switch (prop)
969
switch (prop)
946
  {
970
  {
947
  case GSASL_CB_TLS_UNIQUE:
971
  case GSASL_CB_TLS_UNIQUE:	/*XXX should never get called for this */
948
    HDEBUG(D_auth)
972
    HDEBUG(D_auth)
949
      debug_printf(" filling in\n");
973
      debug_printf(" filling in\n");
950
    gsasl_property_set(sctx, GSASL_CB_TLS_UNIQUE, CCS tls_out.channelbinding);
974
    gsasl_property_set(sctx, GSASL_CB_TLS_UNIQUE, CCS tls_out.channelbinding);
975
    return GSASL_OK;
976
  case GSASL_SCRAM_SALTED_PASSWORD:
977
    {
978
    uschar * client_spassword =
979
      ((auth_gsasl_options_block *) ablock->options_block)->client_spassword;
980
    uschar dummy[4];
981
    HDEBUG(D_auth) if (!client_spassword)
982
      debug_printf(" client_spassword option unset\n");
983
    if (client_spassword)
984
      {
985
      expand_nmax = 0;
986
      set_exim_authvar_from_prop(sctx, GSASL_AUTHID);
987
      set_exim_authvar_from_prop(sctx, GSASL_SCRAM_ITER);
988
      set_exim_authvar_from_prop(sctx, GSASL_SCRAM_SALT);
989
      set_client_prop(sctx, GSASL_SCRAM_SALTED_PASSWORD, client_spassword,
990
		  0, dummy, sizeof(dummy));
991
      for (int i = 0; i < AUTH_VARS; i++) auth_vars[i] = NULL;
992
      expand_nmax = 0;
993
      }
951
    break;
994
    break;
995
    }
952
  default:
996
  default:
953
    HDEBUG(D_auth)
997
    HDEBUG(D_auth)
954
      debug_printf(" not providing one\n");
998
      debug_printf(" not providing one\n");
Lines 961-974 Link Here
961
*                Diagnostic API                  *
1005
*                Diagnostic API                  *
962
*************************************************/
1006
*************************************************/
963
1007
964
void
1008
gstring *
965
auth_gsasl_version_report(FILE *f)
1009
auth_gsasl_version_report(gstring * g)
966
{
1010
{
967
const char *runtime;
1011
return string_fmt_append(g, "Library version: GNU SASL: Compile: %s\n"
968
runtime = gsasl_check_version(NULL);
1012
			    "                           Runtime: %s\n",
969
fprintf(f, "Library version: GNU SASL: Compile: %s\n"
1013
	GSASL_VERSION, gsasl_check_version(NULL));
970
	   "                           Runtime: %s\n",
971
	GSASL_VERSION, runtime);
972
}
1014
}
973
1015
974
1016
(-)exim.orig/src/auths/gsasl_exim.h (-2 / +2 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2019 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2012 */
6
/* Copyright (c) University of Cambridge 1995 - 2012 */
6
/* Copyright (c) The Exim Maintainers 2019-2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Copyright (c) Twitter Inc 2012 */
9
/* Copyright (c) Twitter Inc 2012 */
Lines 47-53 Link Here
47
extern int auth_gsasl_server(auth_instance *, uschar *);
47
extern int auth_gsasl_server(auth_instance *, uschar *);
48
extern int auth_gsasl_client(auth_instance *, void *,
48
extern int auth_gsasl_client(auth_instance *, void *,
49
				int, uschar *, int);
49
				int, uschar *, int);
50
extern void auth_gsasl_version_report(FILE *f);
50
extern gstring * auth_gsasl_version_report(gstring *);
51
extern void auth_gsasl_macros(void);
51
extern void auth_gsasl_macros(void);
52
52
53
/* End of gsasl_exim.h */
53
/* End of gsasl_exim.h */
(-)exim.orig/src/auths/heimdal_gssapi.c (-7 / +8 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Copyright (c) Twitter Inc 2012
9
/* Copyright (c) Twitter Inc 2012
Lines 85-91 Link Here
85
int auth_heimdal_gssapi_server(auth_instance *ablock, uschar *data) {return 0;}
85
int auth_heimdal_gssapi_server(auth_instance *ablock, uschar *data) {return 0;}
86
int auth_heimdal_gssapi_client(auth_instance *ablock, void * sx,
86
int auth_heimdal_gssapi_client(auth_instance *ablock, void * sx,
87
  int timeout, uschar *buffer, int buffsize) {return 0;}
87
  int timeout, uschar *buffer, int buffsize) {return 0;}
88
void auth_heimdal_gssapi_version_report(FILE *f) {}
88
gstring * auth_heimdal_gssapi_version_report(gstring * g) {}
89
89
90
#else   /*!MACRO_PREDEF*/
90
#else   /*!MACRO_PREDEF*/
91
91
Lines 601-614 Link Here
601
*                Diagnostic API                  *
601
*                Diagnostic API                  *
602
*************************************************/
602
*************************************************/
603
603
604
void
604
gstring *
605
auth_heimdal_gssapi_version_report(FILE *f)
605
auth_heimdal_gssapi_version_report(gstring * g)
606
{
606
{
607
/* No build-time constants available unless we link against libraries at
607
/* No build-time constants available unless we link against libraries at
608
build-time and export the result as a string into a header ourselves. */
608
build-time and export the result as a string into a header ourselves. */
609
fprintf(f, "Library version: Heimdal: Runtime: %s\n"
609
610
	   " Build Info: %s\n",
610
return string_fmt_append(g, "Library version: Heimdal: Runtime: %s\n"
611
	heimdal_version, heimdal_long_version);
611
			    " Build Info: %s\n",
612
	heimdal_version, heimdal_long_version));
612
}
613
}
613
614
614
#endif   /*!MACRO_PREDEF*/
615
#endif   /*!MACRO_PREDEF*/
(-)exim.orig/src/auths/heimdal_gssapi.h (-1 / +2 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2012 */
6
/* Copyright (c) University of Cambridge 1995 - 2012 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 33-38 Link Here
33
extern void auth_heimdal_gssapi_init(auth_instance *);
34
extern void auth_heimdal_gssapi_init(auth_instance *);
34
extern int auth_heimdal_gssapi_server(auth_instance *, uschar *);
35
extern int auth_heimdal_gssapi_server(auth_instance *, uschar *);
35
extern int auth_heimdal_gssapi_client(auth_instance *, void *, int, uschar *, int);
36
extern int auth_heimdal_gssapi_client(auth_instance *, void *, int, uschar *, int);
36
extern void auth_heimdal_gssapi_version_report(FILE *f);
37
extern void auth_heimdal_gssapi_version_report(BOOL);
37
38
38
/* End of heimdal_gssapi.h */
39
/* End of heimdal_gssapi.h */
(-)exim.orig/src/auths/plaintext.c (-2 / +2 lines)
Lines 3-9 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
6
/* Copyright (c) The Exim Maintainers 2020 - 2021 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#include "../exim.h"
9
#include "../exim.h"
Lines 109-115 Link Here
109
out as prompts, and get a data item back. If the data item is "*", abandon the
109
out as prompts, and get a data item back. If the data item is "*", abandon the
110
authentication attempt. Otherwise, split it into items as above. */
110
authentication attempt. Otherwise, split it into items as above. */
111
111
112
while (  (s = string_nextinlist(&prompts, &sep, big_buffer, big_buffer_size))
112
while (  (s = string_nextinlist(&prompts, &sep, NULL, 0))
113
      && expand_nmax < EXPAND_MAXN)
113
      && expand_nmax < EXPAND_MAXN)
114
  if (number++ > expand_nmax)
114
  if (number++ > expand_nmax)
115
    if ((rc = auth_prompt(CUS s)) != OK)
115
    if ((rc = auth_prompt(CUS s)) != OK)
(-)exim.orig/src/auths/pwcheck.c (-7 / +2 lines)
Lines 3-8 Link Here
3
 * Tim Martin
3
 * Tim Martin
4
 * $Id: checkpw.c,v 1.49 2002/03/07 19:14:04 ken3 Exp $
4
 * $Id: checkpw.c,v 1.49 2002/03/07 19:14:04 ken3 Exp $
5
 */
5
 */
6
/* Copyright (c) The Exim Maintainers 2021 - 2022 */
6
/*
7
/*
7
 * Copyright (c) 2001 Carnegie Mellon University.  All rights reserved.
8
 * Copyright (c) 2001 Carnegie Mellon University.  All rights reserved.
8
 *
9
 *
Lines 86-93 Link Here
86
                            const char *passwd,
87
                            const char *passwd,
87
                            const char **reply)
88
                            const char **reply)
88
{
89
{
89
userid = userid;  /* Keep picky compilers happy */
90
passwd = passwd;
91
*reply = "pwcheck support is not included in this Exim binary";
90
*reply = "pwcheck support is not included in this Exim binary";
92
return PWCHECK_FAIL;
91
return PWCHECK_FAIL;
93
}
92
}
Lines 163-172 Link Here
163
                const uschar *realm,
162
                const uschar *realm,
164
                const uschar **reply)
163
                const uschar **reply)
165
{
164
{
166
userid = userid;  /* Keep picky compilers happy */
167
passwd = passwd;
168
service = service;
169
realm = realm;
170
*reply = US"saslauthd support is not included in this Exim binary";
165
*reply = US"saslauthd support is not included in this Exim binary";
171
return PWCHECK_FAIL;
166
return PWCHECK_FAIL;
172
}
167
}
Lines 297-303 Link Here
297
            return -1;
292
            return -1;
298
        } else {
293
        } else {
299
	    /* Assume the file is trusted, so no tainting */
294
	    /* Assume the file is trusted, so no tainting */
300
            *retval = store_get(count + 1, FALSE);
295
            *retval = store_get(count + 1, GET_UNTAINTED);
301
            rc = (retry_read(fd, *retval, count) < (int) count);
296
            rc = (retry_read(fd, *retval, count) < (int) count);
302
            (*retval)[count] = '\0';
297
            (*retval)[count] = '\0';
303
            return count;
298
            return count;
(-)exim.orig/src/auths/xtextdecode.c (-1 / +2 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2009 */
6
/* Copyright (c) University of Cambridge 1995 - 2009 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 33-39 Link Here
33
auth_xtextdecode(uschar *code, uschar **ptr)
34
auth_xtextdecode(uschar *code, uschar **ptr)
34
{
35
{
35
register int x;
36
register int x;
36
uschar *result = store_get(Ustrlen(code) + 1, is_tainted(code));
37
uschar * result = store_get(Ustrlen(code) + 1, code);
37
*ptr = result;
38
*ptr = result;
38
39
39
while ((x = (*code++)) != 0)
40
while ((x = (*code++)) != 0)
(-)exim.orig/src/auths/xtextencode.c (-1 / +2 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 40-46 Link Here
40
while (c -- > 0)
41
while (c -- > 0)
41
  count += ((x = *p++) < 33 || x > 127 || x == '+' || x == '=')? 3 : 1;
42
  count += ((x = *p++) < 33 || x > 127 || x == '+' || x == '=')? 3 : 1;
42
43
43
pp = code = store_get(count, is_tainted(clear));
44
pp = code = store_get(count, clear);
44
45
45
p = US clear;
46
p = US clear;
46
c = len;
47
c = len;
(-)exim.orig/src/base64.c (-8 / +9 lines)
Lines 6-12 Link Here
6
/* License: GPL */
6
/* License: GPL */
7
7
8
/* Copyright (c) University of Cambridge 1995 - 2018 */
8
/* Copyright (c) University of Cambridge 1995 - 2018 */
9
/* Copyright (c) The Exim Maintainers 2020 */
9
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
10
/* See the file NOTICE for conditions of use and distribution. */
10
/* See the file NOTICE for conditions of use and distribution. */
11
11
12
12
Lines 157-166 Link Here
157
int x, y;
157
int x, y;
158
uschar *result;
158
uschar *result;
159
159
160
{
160
 {
161
  int l = Ustrlen(code);
161
  int l = Ustrlen(code);
162
  *ptr = result = store_get(1 + l/4 * 3 + l%4, is_tainted(code));
162
  *ptr = result = store_get(1 + l/4 * 3 + l%4, code);
163
}
163
 }
164
164
165
/* Each cycle of the loop handles a quantum of 4 input bytes. For the last
165
/* Each cycle of the loop handles a quantum of 4 input bytes. For the last
166
quantum this may decode to 1, 2, or 3 output bytes. */
166
quantum this may decode to 1, 2, or 3 output bytes. */
Lines 234-239 Link Here
234
Arguments:
234
Arguments:
235
  clear       points to the clear text bytes
235
  clear       points to the clear text bytes
236
  len         the number of bytes to encode
236
  len         the number of bytes to encode
237
  proto_mem   taint indicator
237
238
238
Returns:      a pointer to the zero-terminated base 64 string, which
239
Returns:      a pointer to the zero-terminated base 64 string, which
239
              is in working store
240
              is in working store
Lines 243-252 Link Here
243
  US"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
244
  US"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
244
245
245
uschar *
246
uschar *
246
b64encode_taint(const uschar * clear, int len, BOOL tainted)
247
b64encode_taint(const uschar * clear, int len, const void * proto_mem)
247
{
248
{
248
uschar *code = store_get(4*((len+2)/3) + 1, tainted);
249
uschar * code = store_get(4*((len+2)/3) + 1, proto_mem);
249
uschar *p = code;
250
uschar * p = code;
250
251
251
while (len-- >0)
252
while (len-- >0)
252
  {
253
  {
Lines 287-293 Link Here
287
uschar *
288
uschar *
288
b64encode(const uschar * clear, int len)
289
b64encode(const uschar * clear, int len)
289
{
290
{
290
return b64encode_taint(clear, len, is_tainted(clear));
291
return b64encode_taint(clear, len, clear);
291
}
292
}
292
293
293
294
(-)exim.orig/src/bmi_spam.c (-6 / +9 lines)
Lines 5-10 Link Here
5
/* Code for calling Brightmail AntiSpam.
5
/* Code for calling Brightmail AntiSpam.
6
   Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004
6
   Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004
7
   License: GPL */
7
   License: GPL */
8
/* Copyright (c) The Exim Maintainers 2021 - 2022 */
8
9
9
#include "exim.h"
10
#include "exim.h"
10
#ifdef EXPERIMENTAL_BRIGHTMAIL
11
#ifdef EXPERIMENTAL_BRIGHTMAIL
Lines 193-208 Link Here
193
  /* Get store for the verdict string.  Since we are processing message data, assume that
194
  /* Get store for the verdict string.  Since we are processing message data, assume that
194
  the verdict is tainted.  XXX this should use a growable-string  */
195
  the verdict is tainted.  XXX this should use a growable-string  */
195
196
196
  verdicts = store_get(1, TRUE);
197
  verdicts = store_get(1, GET_TAINTED);
197
  *verdicts = '\0';
198
  *verdicts = '\0';
198
199
199
  for ( err = bmiAccessFirstVerdict(message, &verdict);
200
  for ( err = bmiAccessFirstVerdict(message, &verdict);
200
        verdict != NULL;
201
        verdict;
201
        err = bmiAccessNextVerdict(message, verdict, &verdict) ) {
202
        err = bmiAccessNextVerdict(message, verdict, &verdict) ) {
202
    char *verdict_str;
203
    char *verdict_str;
203
204
204
    err = bmiCreateStrFromVerdict(verdict,&verdict_str);
205
    err = bmiCreateStrFromVerdict(verdict,&verdict_str);
205
    if (!store_extend(verdicts, TRUE,
206
    if (!store_extend(verdicts,
206
	  Ustrlen(verdicts)+1, Ustrlen(verdicts)+1+strlen(verdict_str)+1)) {
207
	  Ustrlen(verdicts)+1, Ustrlen(verdicts)+1+strlen(verdict_str)+1)) {
207
      /* can't allocate more store */
208
      /* can't allocate more store */
208
      return NULL;
209
      return NULL;
Lines 302-308 Link Here
302
  }
303
  }
303
  else {
304
  else {
304
    /* deliver to alternate location */
305
    /* deliver to alternate location */
305
    rc = store_get(strlen(bmiVerdictAccessDestination(verdict))+1, TRUE);
306
    rc = store_get(strlen(bmiVerdictAccessDestination(verdict))+1, GET_TAINTED);
306
    Ustrcpy(rc, bmiVerdictAccessDestination(verdict));
307
    Ustrcpy(rc, bmiVerdictAccessDestination(verdict));
307
    rc[strlen(bmiVerdictAccessDestination(verdict))] = '\0';
308
    rc[strlen(bmiVerdictAccessDestination(verdict))] = '\0';
308
  };
309
  };
Lines 327-333 Link Here
327
    return NULL;
328
    return NULL;
328
329
329
  /* allocate room for the b64 verdict string */
330
  /* allocate room for the b64 verdict string */
330
  verdict_buffer = store_get(Ustrlen(bmi_verdicts)+1, TRUE);
331
  verdict_buffer = store_get(Ustrlen(bmi_verdicts)+1, GET_TAINTED);
331
332
332
  /* loop through verdicts */
333
  /* loop through verdicts */
333
  verdict_ptr = bmi_verdicts;
334
  verdict_ptr = bmi_verdicts;
Lines 448-456 Link Here
448
  }
449
  }
449
450
450
  /* loop through numbers */
451
  /* loop through numbers */
452
  /* option_list doesn't seem to be expanded so cannot be tainted.  If it ever is we
453
  will trap here */
451
  rule_ptr = option_list;
454
  rule_ptr = option_list;
452
  while ((rule_num = string_nextinlist(&rule_ptr, &sep,
455
  while ((rule_num = string_nextinlist(&rule_ptr, &sep,
453
                                       rule_buffer, 32)) != NULL) {
456
                                       rule_buffer, sizeof(rule_buffer)))) {
454
    int rule_int = -1;
457
    int rule_int = -1;
455
458
456
    /* try to translate to int */
459
    /* try to translate to int */
(-)exim.orig/src/buildconfig.c (-5 / +3 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 51-57 Link Here
51
  char *data;
52
  char *data;
52
} save_item;
53
} save_item;
53
54
54
static const char *db_opts[] = { "", "USE_DB", "USE_GDBM", "USE_TDB" };
55
static const char *db_opts[] = { "", "USE_DB", "USE_GDBM", "USE_TDB", "USE_NDBM" };
55
56
56
static int have_ipv6 = 0;
57
static int have_ipv6 = 0;
57
static int have_iconv = 0;
58
static int have_iconv = 0;
Lines 221-228 Link Here
221
222
222
/* Now search the makefile for certain settings */
223
/* Now search the makefile for certain settings */
223
224
224
base = fopen("Makefile", "rb");
225
if (!(base = fopen("Makefile", "rb")))
225
if (base == NULL)
226
  {
226
  {
227
  printf("*** Buildconfig: failed to open Makefile\n");
227
  printf("*** Buildconfig: failed to open Makefile\n");
228
  (void)fclose(new);
228
  (void)fclose(new);
Lines 387-393 Link Here
387
  encountered. */
387
  encountered. */
388
388
389
  for (i = 1; i < sizeof(db_opts)/sizeof(char *); i++)
389
  for (i = 1; i < sizeof(db_opts)/sizeof(char *); i++)
390
    {
391
    if (strcmp(name, db_opts[i]) == 0)
390
    if (strcmp(name, db_opts[i]) == 0)
392
      {
391
      {
393
      if (use_which_db == i)
392
      if (use_which_db == i)
Lines 397-403 Link Here
397
        fprintf(new, "/* %s not set */\n", name);
396
        fprintf(new, "/* %s not set */\n", name);
398
      break;
397
      break;
399
      }
398
      }
400
    }
401
  if (i < sizeof(db_opts)/sizeof(char *)) continue;
399
  if (i < sizeof(db_opts)/sizeof(char *)) continue;
402
400
403
  /* EXIM_USER is a special case. We look in the environment for EXIM_USER or
401
  /* EXIM_USER is a special case. We look in the environment for EXIM_USER or
(-)exim.orig/src/child.c (-17 / +34 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2015 */
6
/* 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. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 27-33 Link Here
27
Returns:       nothing
27
Returns:       nothing
28
*/
28
*/
29
29
30
static void
30
void
31
force_fd(int oldfd, int newfd)
31
force_fd(int oldfd, int newfd)
32
{
32
{
33
if (oldfd == newfd) return;
33
if (oldfd == newfd) return;
Lines 76-97 Link Here
76
int extra = pcount ? *pcount : 0;
76
int extra = pcount ? *pcount : 0;
77
uschar **argv;
77
uschar **argv;
78
78
79
argv = store_get((extra + acount + MAX_CLMACROS + 21) * sizeof(char *), FALSE);
79
argv = store_get((extra + acount + MAX_CLMACROS + 24) * sizeof(char *), GET_UNTAINTED);
80
80
81
/* In all case, the list starts out with the path, any macros, and a changed
81
/* In all case, the list starts out with the path, any macros, and a changed
82
config file. */
82
config file. */
83
83
84
argv[n++] = exim_path;
84
argv[n++] = exim_path;		/* assume untainted */
85
if (clmacro_count > 0)
85
if (clmacro_count > 0)
86
  {
86
  {
87
  memcpy(argv + n, clmacros, clmacro_count * sizeof(uschar *));
87
  memcpy(argv + n, clmacros, clmacro_count * sizeof(uschar *));
88
  n += clmacro_count;
88
  n += clmacro_count;
89
  }
89
  }
90
if (f.config_changed)
90
if (f.config_changed)
91
  {
91
  { argv[n++] = US"-C"; argv[n++] = config_main_filename; }
92
  argv[n++] = US"-C";
93
  argv[n++] = config_main_filename;
94
  }
95
92
96
/* These values are added only for non-minimal cases. If debug_selector is
93
/* These values are added only for non-minimal cases. If debug_selector is
97
precisely D_v, we have to assume this was started by a non-admin user, and
94
precisely D_v, we have to assume this was started by a non-admin user, and
Lines 108-131 Link Here
108
  else
105
  else
109
    {
106
    {
110
    if (debug_selector != 0)
107
    if (debug_selector != 0)
108
      {
111
      argv[n++] = string_sprintf("-d=0x%x", debug_selector);
109
      argv[n++] = string_sprintf("-d=0x%x", debug_selector);
110
      if (debug_fd > 2)
111
	{
112
	int flags = fcntl(debug_fd, F_GETFD);
113
	if (flags != -1) (void)fcntl(debug_fd, F_SETFD, flags & ~FD_CLOEXEC);
114
	close(2);
115
	dup2(debug_fd, 2);
116
	close(debug_fd);
117
	}
118
      }
112
    }
119
    }
120
  if (debug_pretrigger_buf)
121
    { argv[n++] = US"-dp"; argv[n++] = string_sprintf("0x%x", debug_pretrigger_bsize); }
122
  if (dtrigger_selector != 0)
123
    argv[n++] = string_sprintf("-dt=0x%x", dtrigger_selector);
113
  DEBUG(D_any)
124
  DEBUG(D_any)
114
    {
125
    {
115
    argv[n++] = US"-MCd";
126
    argv[n++] = US"-MCd";
116
    argv[n++] = US process_purpose;
127
    argv[n++] = US process_purpose;
117
    }
128
    }
118
  if (!f.testsuite_delays) argv[n++] = US"-odd";
129
  if (!f.testsuite_delays)	argv[n++] = US"-odd";
119
  if (f.dont_deliver) argv[n++] = US"-N";
130
  if (f.dont_deliver)		argv[n++] = US"-N";
120
  if (f.queue_smtp) argv[n++] = US"-odqs";
131
  if (f.queue_smtp)		argv[n++] = US"-odqs";
121
  if (f.synchronous_delivery) argv[n++] = US"-odi";
132
  if (f.synchronous_delivery)	argv[n++] = US"-odi";
122
  if (connection_max_messages >= 0)
133
  if (connection_max_messages >= 0)
123
    argv[n++] = string_sprintf("-oB%d", connection_max_messages);
134
    argv[n++] = string_sprintf("-oB%d", connection_max_messages);
124
  if (*queue_name)
135
  if (*queue_name)
125
    {
136
    { argv[n++] = US"-MCG"; argv[n++] = queue_name; }
126
    argv[n++] = US"-MCG";
127
    argv[n++] = queue_name;
128
    }
129
  }
137
  }
130
138
131
/* Now add in any others that are in the call. Remember which they were,
139
/* Now add in any others that are in the call. Remember which they were,
Lines 159-165 Link Here
159
execv(CS argv[0], (char *const *)argv);
167
execv(CS argv[0], (char *const *)argv);
160
168
161
log_write(0,
169
log_write(0,
162
  LOG_MAIN | ((exec_type == CEE_EXEC_EXIT)? LOG_PANIC : LOG_PANIC_DIE),
170
  LOG_MAIN | (exec_type == CEE_EXEC_EXIT ? LOG_PANIC : LOG_PANIC_DIE),
163
  "re-exec of exim (%s) with %s failed: %s", exim_path, argv[first_special],
171
  "re-exec of exim (%s) with %s failed: %s", exim_path, argv[first_special],
164
  strerror(errno));
172
  strerror(errno));
165
173
Lines 269-274 Link Here
269
    }
277
    }
270
  }
278
  }
271
279
280
testharness_pause_ms(100); /* let child work even longer, for exec */
281
272
/* Parent process. Save fork() errno and close the reading end of the stdin
282
/* Parent process. Save fork() errno and close the reading end of the stdin
273
pipe. */
283
pipe. */
274
284
Lines 333-338 Link Here
333
int inpfd[2], outpfd[2];
343
int inpfd[2], outpfd[2];
334
pid_t pid;
344
pid_t pid;
335
345
346
if (is_tainted(argv[0]))
347
  {
348
  log_write(0, LOG_MAIN | LOG_PANIC, "Attempt to exec tainted path: '%s'", argv[0]);
349
  errno = EPERM;
350
  return (pid_t)(-1);
351
  }
352
336
/* Create the pipes. */
353
/* Create the pipes. */
337
354
338
if (pipe(inpfd) != 0) return (pid_t)(-1);
355
if (pipe(inpfd) != 0) return (pid_t)(-1);
(-)exim.orig/src/config.h.defaults (-8 / +11 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2018 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2018-2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* The default settings for Exim configuration variables. A #define without
9
/* The default settings for Exim configuration variables. A #define without
Lines 31-37 Link Here
31
#define AUTH_SPA
31
#define AUTH_SPA
32
#define AUTH_TLS
32
#define AUTH_TLS
33
33
34
#define AUTH_VARS                     3
34
#define AUTH_VARS                     4
35
35
36
#define BIN_DIRECTORY
36
#define BIN_DIRECTORY
37
37
Lines 46-59 Link Here
46
#define DEFAULT_CRYPT              crypt
46
#define DEFAULT_CRYPT              crypt
47
#define DELIVER_IN_BUFFER_SIZE     8192
47
#define DELIVER_IN_BUFFER_SIZE     8192
48
#define DELIVER_OUT_BUFFER_SIZE    8192
48
#define DELIVER_OUT_BUFFER_SIZE    8192
49
50
#define DISABLE_CLIENT_CMD_LOG
51
#define DISABLE_D_OPTION
49
#define DISABLE_DNSSEC
52
#define DISABLE_DNSSEC
50
#define DISABLE_DKIM
53
#define DISABLE_DKIM
51
#define DISABLE_EVENT
54
#define DISABLE_EVENT
52
#define DISABLE_OCSP
55
#define DISABLE_OCSP
53
#define DISABLE_PIPE_CONNECT
56
#define DISABLE_PIPE_CONNECT
54
#define DISABLE_PRDR
57
#define DISABLE_PRDR
58
#define DISABLE_QUEUE_RAMP
55
#define DISABLE_TLS
59
#define DISABLE_TLS
56
#define DISABLE_D_OPTION
60
#define DISABLE_TLS_RESUME
57
61
58
#define ENABLE_DISABLE_FSYNC
62
#define ENABLE_DISABLE_FSYNC
59
63
Lines 97-102 Link Here
97
#define LOOKUP_IBASE
101
#define LOOKUP_IBASE
98
#define LOOKUP_JSON
102
#define LOOKUP_JSON
99
#define LOOKUP_LDAP
103
#define LOOKUP_LDAP
104
#define LOOKUP_LMDB
100
#define LOOKUP_LSEARCH
105
#define LOOKUP_LSEARCH
101
#define LOOKUP_MYSQL
106
#define LOOKUP_MYSQL
102
#define LOOKUP_NIS
107
#define LOOKUP_NIS
Lines 156-161 Link Here
156
#define SUPPORT_PROXY
161
#define SUPPORT_PROXY
157
#define SUPPORT_SOCKS
162
#define SUPPORT_SOCKS
158
#define SUPPORT_SPF
163
#define SUPPORT_SPF
164
#define SUPPORT_SRS
159
#define SUPPORT_TRANSLATE_IP_ADDRESS
165
#define SUPPORT_TRANSLATE_IP_ADDRESS
160
166
161
#define SYSLOG_LOG_PID
167
#define SYSLOG_LOG_PID
Lines 175-180 Link Here
175
#define USE_GDBM
181
#define USE_GDBM
176
#define USE_GNUTLS
182
#define USE_GNUTLS
177
#define AVOID_GNUTLS_PKCS11
183
#define AVOID_GNUTLS_PKCS11
184
#define USE_NDBM
178
#define USE_OPENSSL
185
#define USE_OPENSSL
179
#define USE_READLINE
186
#define USE_READLINE
180
#define USE_TCP_WRAPPERS
187
#define USE_TCP_WRAPPERS
Lines 201-212 Link Here
201
#define EXPERIMENTAL_BRIGHTMAIL
208
#define EXPERIMENTAL_BRIGHTMAIL
202
#define EXPERIMENTAL_DCC
209
#define EXPERIMENTAL_DCC
203
#define EXPERIMENTAL_DSN_INFO
210
#define EXPERIMENTAL_DSN_INFO
204
#define EXPERIMENTAL_LMDB
211
#define EXPERIMENTAL_ESMTP_LIMITS
205
#define EXPERIMENTAL_QUEUE_RAMP
206
#define EXPERIMENTAL_QUEUEFILE
212
#define EXPERIMENTAL_QUEUEFILE
207
#define EXPERIMENTAL_SRS
208
#define EXPERIMENTAL_SRS_NATIVE
209
#define EXPERIMENTAL_TLS_RESUME
210
213
211
214
212
/* For developers */
215
/* For developers */
(-)exim.orig/src/configure.default (-24 / +29 lines)
Lines 147-161 Link Here
147
# spamd_address = 127.0.0.1 783
147
# spamd_address = 127.0.0.1 783
148
148
149
149
150
# If Exim is compiled with support for TLS, you may want to enable the
150
# If Exim is compiled with support for TLS, you may want to change the
151
# following options so that Exim allows clients to make encrypted
151
# following option so that Exim disallows certain clients from makeing encrypted
152
# connections. In the authenticators section below, there are template
152
# connections. The default is to allow all.
153
# configurations for plaintext username/password authentication. This kind
153
# In the authenticators section below, there are template configurations for
154
# of authentication is only safe when used within a TLS connection, so the
154
# plaintext username/password authentication. This kind of authentication is
155
# authenticators will only work if the following TLS settings are turned on
155
# only safe when used within a TLS connection, so the authenticators will only
156
# as well.
156
# work if TLS is allowed here.
157
157
158
# Allow any client to use TLS.
158
# This is equivalent to the default.
159
159
160
# tls_advertise_hosts = *
160
# tls_advertise_hosts = *
161
161
Lines 169-175 Link Here
169
# tls_privatekey = /etc/ssl/exim.pem
169
# tls_privatekey = /etc/ssl/exim.pem
170
170
171
# For OpenSSL, prefer EC- over RSA-authenticated ciphers
171
# For OpenSSL, prefer EC- over RSA-authenticated ciphers
172
# tls_require_ciphers = ECDSA:RSA:!COMPLEMENTOFDEFAULT
172
.ifdef _HAVE_OPENSSL
173
tls_require_ciphers = ECDSA:RSA:!COMPLEMENTOFDEFAULT
174
.endif
175
176
# Don't offer resumption to (most) MUAs, who we don't want to reuse
177
# tickets.  Once the TLS extension for vended ticket numbers comes
178
# though, re-examine since resumption on a single-use ticket is still a benefit.
179
.ifdef _HAVE_TLS_RESUME
180
tls_resumption_hosts = ${if inlist {$received_port}{587:465} {:}{*}}
181
.endif
173
182
174
# In order to support roaming users who wish to send email from anywhere,
183
# In order to support roaming users who wish to send email from anywhere,
175
# you may want to make Exim listen on other ports as well as port 25, in
184
# you may want to make Exim listen on other ports as well as port 25, in
Lines 495-505 Link Here
495
          control       = submission
504
          control       = submission
496
          control       = dkim_disable_verify
505
          control       = dkim_disable_verify
497
506
498
  # Insist that a HELO/EHLO was accepted.
499
500
  require message       = nice hosts say HELO first
501
          condition     = ${if def:sender_helo_name}
502
503
  # Insist that any other recipient address that we accept is either in one of
507
  # Insist that any other recipient address that we accept is either in one of
504
  # our local domains, or is in a domain for which we explicitly allow
508
  # our local domains, or is in a domain for which we explicitly allow
505
  # relaying. Any other domain is rejected as being unacceptable for relaying.
509
  # relaying. Any other domain is rejected as being unacceptable for relaying.
Lines 545-555 Link Here
545
  # to the first recipient must be deferred unless the sender talks PRDR.
549
  # to the first recipient must be deferred unless the sender talks PRDR.
546
  #
550
  #
547
  # defer  !condition     = $prdr_requested
551
  # defer  !condition     = $prdr_requested
548
  #        condition      = ${if > {0}{$receipients_count}}
552
  #        condition      = ${if > {0}{$recipients_count}}
549
  #        condition      = ${if !eq {$acl_m_content_filter} \
553
  #        condition      = ${if !eq {$acl_m_content_filter} \
550
  #                                  {${lookup PER_RCPT_CONTENT_FILTER}}}
554
  #                                  {${lookup PER_RCPT_CONTENT_FILTER}}}
551
  # warn   !condition     = $prdr_requested
555
  # warn   !condition     = $prdr_requested
552
  #        condition      = ${if > {0}{$receipients_count}}
556
  #        condition      = ${if > {0}{$recipients_count}}
553
  #        set acl_m_content_filter = ${lookup PER_RCPT_CONTENT_FILTER}
557
  #        set acl_m_content_filter = ${lookup PER_RCPT_CONTENT_FILTER}
554
  #############################################################################
558
  #############################################################################
555
559
Lines 815-827 Link Here
815
819
816
820
817
# This transport is used for delivering messages over SMTP connections.
821
# This transport is used for delivering messages over SMTP connections.
818
# Refuse to send any message with over-long lines, which could have
819
# been received other than via SMTP. The use of message_size_limit to
820
# enforce this is a red herring.
821
822
822
remote_smtp:
823
remote_smtp:
823
  driver = smtp
824
  driver = smtp
824
  message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}}
825
.ifdef _HAVE_TLS_RESUME
826
  tls_resumption_hosts = *
827
.endif
825
828
826
829
827
# This transport is used for delivering messages to a smarthost, if the
830
# This transport is used for delivering messages to a smarthost, if the
Lines 833-839 Link Here
833
836
834
smarthost_smtp:
837
smarthost_smtp:
835
  driver = smtp
838
  driver = smtp
836
  message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}}
837
  multi_domain
839
  multi_domain
838
  #
840
  #
839
.ifdef _HAVE_TLS
841
.ifdef _HAVE_TLS
Lines 841-849 Link Here
841
  # request with your smarthost provider to get things fixed:
843
  # request with your smarthost provider to get things fixed:
842
  hosts_require_tls = *
844
  hosts_require_tls = *
843
  tls_verify_hosts = *
845
  tls_verify_hosts = *
844
  # As long as tls_verify_hosts is enabled, this won't matter, but if you
846
  # As long as tls_verify_hosts is enabled, this this will have no effect,
845
  # have to comment it out then this will at least log whether you succeed
847
  # but if you have to comment it out then this will at least log whether
846
  # or not:
848
  # you succeed or not:
847
  tls_try_verify_hosts = *
849
  tls_try_verify_hosts = *
848
  #
850
  #
849
  # The SNI name should match the name which we'll expect to verify;
851
  # The SNI name should match the name which we'll expect to verify;
Lines 859-864 Link Here
859
.ifdef _HAVE_GNUTLS
861
.ifdef _HAVE_GNUTLS
860
  tls_require_ciphers = SECURE192:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1
862
  tls_require_ciphers = SECURE192:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1
861
.endif
863
.endif
864
.ifdef _HAVE_TLS_RESUME
865
  tls_resumption_hosts = *
866
.endif
862
.endif
867
.endif
863
868
864
869
(-)exim.orig/src/daemon.c (-161 / +217 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Functions concerned with running Exim as a daemon */
9
/* Functions concerned with running Exim as a daemon */
Lines 59-65 Link Here
59
static void
59
static void
60
sighup_handler(int sig)
60
sighup_handler(int sig)
61
{
61
{
62
sig = sig;    /* Keep picky compilers happy */
63
sighup_seen = TRUE;
62
sighup_seen = TRUE;
64
signal(SIGHUP, sighup_handler);
63
signal(SIGHUP, sighup_handler);
65
}
64
}
Lines 83-95 Link Here
83
static void
82
static void
84
main_sigchld_handler(int sig)
83
main_sigchld_handler(int sig)
85
{
84
{
86
sig = sig;    /* Keep picky compilers happy */
87
os_non_restarting_signal(SIGCHLD, SIG_DFL);
85
os_non_restarting_signal(SIGCHLD, SIG_DFL);
88
sigchld_seen = TRUE;
86
sigchld_seen = TRUE;
89
}
87
}
90
88
91
89
92
/* SIGTERM handler.  Try to get the damon pif file removed
90
/* SIGTERM handler.  Try to get the daemon pid file removed
93
before exiting. */
91
before exiting. */
94
92
95
static void
93
static void
Lines 143-149 Link Here
143
141
144
static void
142
static void
145
close_daemon_sockets(int daemon_notifier_fd,
143
close_daemon_sockets(int daemon_notifier_fd,
146
  int * listen_sockets, int listen_socket_count)
144
  struct pollfd * fd_polls, int listen_socket_count)
147
{
145
{
148
if (daemon_notifier_fd >= 0)
146
if (daemon_notifier_fd >= 0)
149
  {
147
  {
Lines 154-160 Link Here
154
#endif
152
#endif
155
  }
153
  }
156
154
157
for (int i = 0; i < listen_socket_count; i++) (void) close(listen_sockets[i]);
155
for (int i = 0; i < listen_socket_count; i++) (void) close(fd_polls[i].fd);
158
}
156
}
159
157
160
158
Lines 169-175 Link Here
169
leak store in this process - reset the stacking pool at the end.
167
leak store in this process - reset the stacking pool at the end.
170
168
171
Arguments:
169
Arguments:
172
  listen_sockets        sockets which are listening for incoming calls
170
  fd_polls        sockets which are listening for incoming calls
173
  listen_socket_count   count of listening sockets
171
  listen_socket_count   count of listening sockets
174
  accept_socket         socket of the current accepted call
172
  accept_socket         socket of the current accepted call
175
  accepted              socket information about the current call
173
  accepted              socket information about the current call
Lines 178-184 Link Here
178
*/
176
*/
179
177
180
static void
178
static void
181
handle_smtp_call(int *listen_sockets, int listen_socket_count,
179
handle_smtp_call(struct pollfd *fd_polls, int listen_socket_count,
182
  int accept_socket, struct sockaddr *accepted)
180
  int accept_socket, struct sockaddr *accepted)
183
{
181
{
184
pid_t pid;
182
pid_t pid;
Lines 277-283 Link Here
277
if (smtp_load_reserve >= 0)
275
if (smtp_load_reserve >= 0)
278
  {
276
  {
279
  load_average = OS_GETLOADAVG();
277
  load_average = OS_GETLOADAVG();
280
  if (smtp_reserve_hosts == NULL && load_average > smtp_load_reserve)
278
  if (!smtp_reserve_hosts && load_average > smtp_load_reserve)
281
    {
279
    {
282
    DEBUG(D_any) debug_printf("rejecting SMTP connection: load average = %.2f\n",
280
    DEBUG(D_any) debug_printf("rejecting SMTP connection: load average = %.2f\n",
283
      (double)load_average/1000.0);
281
      (double)load_average/1000.0);
Lines 297-306 Link Here
297
this is in the daemon mainline, only fast expansions (such as inline address
295
this is in the daemon mainline, only fast expansions (such as inline address
298
checks) should be used. The documentation is full of warnings. */
296
checks) should be used. The documentation is full of warnings. */
299
297
300
if (smtp_accept_max_per_host != NULL)
298
if (smtp_accept_max_per_host)
301
  {
299
  {
302
  uschar *expanded = expand_string(smtp_accept_max_per_host);
300
  uschar *expanded = expand_string(smtp_accept_max_per_host);
303
  if (expanded == NULL)
301
  if (!expanded)
304
    {
302
    {
305
    if (!f.expand_string_forcedfail)
303
    if (!f.expand_string_forcedfail)
306
      log_write(0, LOG_MAIN|LOG_PANIC, "expansion of smtp_accept_max_per_host "
304
      log_write(0, LOG_MAIN|LOG_PANIC, "expansion of smtp_accept_max_per_host "
Lines 312-318 Link Here
312
    uschar *s = expanded;
310
    uschar *s = expanded;
313
    while (isdigit(*s))
311
    while (isdigit(*s))
314
      max_for_this_host = max_for_this_host * 10 + *s++ - '0';
312
      max_for_this_host = max_for_this_host * 10 + *s++ - '0';
315
    if (*s != 0)
313
    if (*s)
316
      log_write(0, LOG_MAIN|LOG_PANIC, "expansion of smtp_accept_max_per_host "
314
      log_write(0, LOG_MAIN|LOG_PANIC, "expansion of smtp_accept_max_per_host "
317
        "for %s contains non-digit: %s", whofrom->s, expanded);
315
        "for %s contains non-digit: %s", whofrom->s, expanded);
318
    }
316
    }
Lines 322-329 Link Here
322
per host_address checks. Note that at this stage smtp_accept_count contains the
320
per host_address checks. Note that at this stage smtp_accept_count contains the
323
count of *other* connections, not including this one. */
321
count of *other* connections, not including this one. */
324
322
325
if ((max_for_this_host > 0) &&
323
if (max_for_this_host > 0 && smtp_accept_count >= max_for_this_host)
326
    (smtp_accept_count >= max_for_this_host))
327
  {
324
  {
328
  int host_accept_count = 0;
325
  int host_accept_count = 0;
329
  int other_host_count = 0;    /* keep a count of non matches to optimise */
326
  int other_host_count = 0;    /* keep a count of non matches to optimise */
Lines 340-347 Link Here
340
      early, either by hitting the target, or finding there are not enough
337
      early, either by hitting the target, or finding there are not enough
341
      connections left to make the target. */
338
      connections left to make the target. */
342
339
343
      if ((host_accept_count >= max_for_this_host) ||
340
      if (  host_accept_count >= max_for_this_host
344
         ((smtp_accept_count - other_host_count) < max_for_this_host))
341
         || smtp_accept_count - other_host_count < max_for_this_host)
345
       break;
342
       break;
346
      }
343
      }
347
344
Lines 377-383 Link Here
377
  {
374
  {
378
  uschar *list = hosts_connection_nolog;
375
  uschar *list = hosts_connection_nolog;
379
  memset(sender_host_cache, 0, sizeof(sender_host_cache));
376
  memset(sender_host_cache, 0, sizeof(sender_host_cache));
380
  if (list != NULL && verify_check_host(&list) == OK)
377
  if (list && verify_check_host(&list) == OK)
381
    save_log_selector &= ~L_smtp_connection;
378
    save_log_selector &= ~L_smtp_connection;
382
  else
379
  else
383
    log_write(L_smtp_connection, LOG_MAIN, "SMTP connection from %s "
380
    log_write(L_smtp_connection, LOG_MAIN, "SMTP connection from %s "
Lines 399-410 Link Here
399
  int save_debug_selector = debug_selector;
396
  int save_debug_selector = debug_selector;
400
  BOOL local_queue_only;
397
  BOOL local_queue_only;
401
  BOOL session_local_queue_only;
398
  BOOL session_local_queue_only;
402
  #ifdef SA_NOCLDWAIT
399
#ifdef SA_NOCLDWAIT
403
  struct sigaction act;
400
  struct sigaction act;
404
  #endif
401
#endif
405
402
406
  smtp_accept_count++;    /* So that it includes this process */
403
  smtp_accept_count++;    /* So that it includes this process */
407
404
405
  /* If the listen backlog was over the monitoring level, log it. */
406
407
  if (smtp_listen_backlog > smtp_backlog_monitor)
408
    log_write(0, LOG_MAIN, "listen backlog %d I=[%s]:%d",
409
		smtp_listen_backlog, interface_address, interface_port);
410
408
  /* May have been modified for the subprocess */
411
  /* May have been modified for the subprocess */
409
412
410
  *log_selector = save_log_selector;
413
  *log_selector = save_log_selector;
Lines 456-462 Link Here
456
  extensive comment before the reception loop in exim.c for a fuller
459
  extensive comment before the reception loop in exim.c for a fuller
457
  explanation of this logic. */
460
  explanation of this logic. */
458
461
459
  close_daemon_sockets(daemon_notifier_fd, listen_sockets, listen_socket_count);
462
  close_daemon_sockets(daemon_notifier_fd, fd_polls, listen_socket_count);
460
463
461
  /* Set FD_CLOEXEC on the SMTP socket. We don't want any rogue child processes
464
  /* Set FD_CLOEXEC on the SMTP socket. We don't want any rogue child processes
462
  to be able to communicate with them, under any circumstances. */
465
  to be able to communicate with them, under any circumstances. */
Lines 465-478 Link Here
465
  (void)fcntl(dup_accept_socket, F_SETFD,
468
  (void)fcntl(dup_accept_socket, F_SETFD,
466
              fcntl(dup_accept_socket, F_GETFD) | FD_CLOEXEC);
469
              fcntl(dup_accept_socket, F_GETFD) | FD_CLOEXEC);
467
470
468
  #ifdef SA_NOCLDWAIT
471
#ifdef SA_NOCLDWAIT
469
  act.sa_handler = SIG_IGN;
472
  act.sa_handler = SIG_IGN;
470
  sigemptyset(&(act.sa_mask));
473
  sigemptyset(&(act.sa_mask));
471
  act.sa_flags = SA_NOCLDWAIT;
474
  act.sa_flags = SA_NOCLDWAIT;
472
  sigaction(SIGCHLD, &act, NULL);
475
  sigaction(SIGCHLD, &act, NULL);
473
  #else
476
#else
474
  signal(SIGCHLD, SIG_IGN);
477
  signal(SIGCHLD, SIG_IGN);
475
  #endif
478
#endif
476
  signal(SIGTERM, SIG_DFL);
479
  signal(SIGTERM, SIG_DFL);
477
  signal(SIGINT, SIG_DFL);
480
  signal(SIGINT, SIG_DFL);
478
481
Lines 558-564 Link Here
558
        }
561
        }
559
      if (message_id[0] == 0) continue;   /* No message was accepted */
562
      if (message_id[0] == 0) continue;   /* No message was accepted */
560
      }
563
      }
561
    else
564
    else				/* bad smtp_setup_msg() */
562
      {
565
      {
563
      if (smtp_out)
566
      if (smtp_out)
564
	{
567
	{
Lines 678-693 Link Here
678
      {
681
      {
679
      pid_t dpid;
682
      pid_t dpid;
680
683
681
      /* Before forking, ensure that the C output buffer is flushed. Otherwise
684
      /* We used to flush smtp_out before forking so that buffered data was not
682
      anything that it in it will get duplicated, leading to duplicate copies
685
      duplicated, but now we want to pipeline the responses for data and quit.
683
      of the pending output. */
686
      Instead, hard-close the fd underlying smtp_out right after fork to discard
684
687
      the data buffer. */
685
      mac_smtp_fflush();
686
688
687
      if ((dpid = exim_fork(US"daemon-accept-delivery")) == 0)
689
      if ((dpid = exim_fork(US"daemon-accept-delivery")) == 0)
688
        {
690
        {
689
        (void)fclose(smtp_in);
691
        (void)fclose(smtp_in);
692
	(void)close(fileno(smtp_out));
690
        (void)fclose(smtp_out);
693
        (void)fclose(smtp_out);
694
	smtp_in = smtp_out = NULL;
691
695
692
        /* Don't ever molest the parent's SSL connection, but do clean up
696
        /* Don't ever molest the parent's SSL connection, but do clean up
693
        the data structures if necessary. */
697
        the data structures if necessary. */
Lines 789-798 Link Here
789
the incoming host address and an expanded active_hostname. */
793
the incoming host address and an expanded active_hostname. */
790
794
791
log_close_all();
795
log_close_all();
792
interface_address =
796
interface_address = sender_host_name = sender_host_address = NULL;
793
sender_host_address = NULL;
794
store_reset(reset_point);
797
store_reset(reset_point);
795
sender_host_address = NULL;
796
}
798
}
797
799
798
800
Lines 956-981 Link Here
956
the file. FIXME.
958
the file. FIXME.
957
Returns: true on success, false + errno==EACCES otherwise
959
Returns: true on success, false + errno==EACCES otherwise
958
*/
960
*/
961
959
static BOOL
962
static BOOL
960
operate_on_pid_file(const enum pid_op operation, const pid_t pid)
963
operate_on_pid_file(const enum pid_op operation, const pid_t pid)
961
{
964
{
962
char pid_line[sizeof(int) * 3 + 2];
965
char pid_line[sizeof(int) * 3 + 2];
963
const int pid_len = snprintf(pid_line, sizeof(pid_line), "%d\n", (int)pid);
966
const int pid_len = snprintf(pid_line, sizeof(pid_line), "%d\n", (int)pid);
964
BOOL lines_match = FALSE;
967
BOOL lines_match = FALSE;
965
968
uschar * path, * base, * dir;
966
char * path = NULL;
967
char * base = NULL;
968
char * dir = NULL;
969
969
970
const int dir_flags = O_RDONLY | O_NONBLOCK;
970
const int dir_flags = O_RDONLY | O_NONBLOCK;
971
const int base_flags = O_NOFOLLOW | O_NONBLOCK;
971
const int base_flags = O_NOFOLLOW | O_NONBLOCK;
972
const mode_t base_mode = 0644;
972
const mode_t base_mode = 0644;
973
struct stat sb;
973
struct stat sb;
974
974
int cwd_fd = -1, dir_fd = -1, base_fd = -1;
975
int cwd_fd = -1;
976
int dir_fd = -1;
977
int base_fd = -1;
978
979
BOOL success = FALSE;
975
BOOL success = FALSE;
980
errno = EACCES;
976
errno = EACCES;
981
977
Lines 983-1006 Link Here
983
if (!f.running_in_test_harness && real_uid != root_uid && real_uid != exim_uid) goto cleanup;
979
if (!f.running_in_test_harness && real_uid != root_uid && real_uid != exim_uid) goto cleanup;
984
if (pid_len < 2 || pid_len >= (int)sizeof(pid_line)) goto cleanup;
980
if (pid_len < 2 || pid_len >= (int)sizeof(pid_line)) goto cleanup;
985
981
986
path = CS string_copy(pid_file_path);
982
path = string_copy(pid_file_path);
987
if ((base = Ustrrchr(path, '/')) == NULL) /* should not happen, but who knows */
983
if ((base = Ustrrchr(path, '/')) == NULL)	/* should not happen, but who knows */
988
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "pid file path \"%s\" does not contain a '/'", pid_file_path);
984
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "pid file path \"%s\" does not contain a '/'", pid_file_path);
989
985
990
dir = (base != path) ? path : "/";
986
dir = base != path ? path : US"/";
991
*base++ = '\0';
987
*base++ = '\0';
992
988
993
if (!dir || !*dir || *dir != '/') goto cleanup;
989
if (!dir || !*dir || *dir != '/') goto cleanup;
994
if (!base || !*base || strchr(base, '/') != NULL) goto cleanup;
990
if (!base || !*base || Ustrchr(base, '/') != NULL) goto cleanup;
995
991
996
cwd_fd = open(".", dir_flags);
992
cwd_fd = open(".", dir_flags);
997
if (cwd_fd < 0 || fstat(cwd_fd, &sb) != 0 || !S_ISDIR(sb.st_mode)) goto cleanup;
993
if (cwd_fd < 0 || fstat(cwd_fd, &sb) != 0 || !S_ISDIR(sb.st_mode)) goto cleanup;
998
dir_fd = open(dir, dir_flags);
994
dir_fd = open(CS dir, dir_flags);
999
if (dir_fd < 0 || fstat(dir_fd, &sb) != 0 || !S_ISDIR(sb.st_mode)) goto cleanup;
995
if (dir_fd < 0 || fstat(dir_fd, &sb) != 0 || !S_ISDIR(sb.st_mode)) goto cleanup;
1000
996
1001
/* emulate openat */
997
/* emulate openat */
1002
if (fchdir(dir_fd) != 0) goto cleanup;
998
if (fchdir(dir_fd) != 0) goto cleanup;
1003
base_fd = open(base, O_RDONLY | base_flags);
999
base_fd = open(CS base, O_RDONLY | base_flags);
1004
if (fchdir(cwd_fd) != 0)
1000
if (fchdir(cwd_fd) != 0)
1005
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "can't return to previous working dir: %s", strerror(errno));
1001
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "can't return to previous working dir: %s", strerror(errno));
1006
1002
Lines 1019-1025 Link Here
1019
1015
1020
  if (strspn(line, "0123456789") != (size_t)len-1) goto cleanup;
1016
  if (strspn(line, "0123456789") != (size_t)len-1) goto cleanup;
1021
  if (line[len-1] != '\n') goto cleanup;
1017
  if (line[len-1] != '\n') goto cleanup;
1022
  lines_match = (len == pid_len && strcmp(line, pid_line) == 0);
1018
  lines_match = len == pid_len && strcmp(line, pid_line) == 0;
1023
  }
1019
  }
1024
1020
1025
if (operation == PID_WRITE)
1021
if (operation == PID_WRITE)
Lines 1031-1037 Link Here
1031
      int error = -1;
1027
      int error = -1;
1032
      /* emulate unlinkat */
1028
      /* emulate unlinkat */
1033
      if (fchdir(dir_fd) != 0) goto cleanup;
1029
      if (fchdir(dir_fd) != 0) goto cleanup;
1034
      error = unlink(base);
1030
      error = unlink(CS base);
1035
      if (fchdir(cwd_fd) != 0)
1031
      if (fchdir(cwd_fd) != 0)
1036
        log_write(0, LOG_MAIN|LOG_PANIC_DIE, "can't return to previous working dir: %s", strerror(errno));
1032
        log_write(0, LOG_MAIN|LOG_PANIC_DIE, "can't return to previous working dir: %s", strerror(errno));
1037
      if (error) goto cleanup;
1033
      if (error) goto cleanup;
Lines 1040-1046 Link Here
1040
     }
1036
     }
1041
    /* emulate openat */
1037
    /* emulate openat */
1042
    if (fchdir(dir_fd) != 0) goto cleanup;
1038
    if (fchdir(dir_fd) != 0) goto cleanup;
1043
    base_fd = open(base, O_WRONLY | O_CREAT | O_EXCL | base_flags, base_mode);
1039
    base_fd = open(CS base, O_WRONLY | O_CREAT | O_EXCL | base_flags, base_mode);
1044
    if (fchdir(cwd_fd) != 0)
1040
    if (fchdir(cwd_fd) != 0)
1045
        log_write(0, LOG_MAIN|LOG_PANIC_DIE, "can't return to previous working dir: %s", strerror(errno));
1041
        log_write(0, LOG_MAIN|LOG_PANIC_DIE, "can't return to previous working dir: %s", strerror(errno));
1046
    if (base_fd < 0) goto cleanup;
1042
    if (base_fd < 0) goto cleanup;
Lines 1057-1063 Link Here
1057
    int error = -1;
1053
    int error = -1;
1058
    /* emulate unlinkat */
1054
    /* emulate unlinkat */
1059
    if (fchdir(dir_fd) != 0) goto cleanup;
1055
    if (fchdir(dir_fd) != 0) goto cleanup;
1060
    error = unlink(base);
1056
    error = unlink(CS base);
1061
    if (fchdir(cwd_fd) != 0)
1057
    if (fchdir(cwd_fd) != 0)
1062
        log_write(0, LOG_MAIN|LOG_PANIC_DIE, "can't return to previous working dir: %s", strerror(errno));
1058
        log_write(0, LOG_MAIN|LOG_PANIC_DIE, "can't return to previous working dir: %s", strerror(errno));
1063
    if (error) goto cleanup;
1059
    if (error) goto cleanup;
Lines 1144-1149 Link Here
1144
struct sockaddr_un sa_un = {.sun_family = AF_UNIX};
1140
struct sockaddr_un sa_un = {.sun_family = AF_UNIX};
1145
int len;
1141
int len;
1146
1142
1143
if (!notifier_socket || !*notifier_socket)
1144
  {
1145
  DEBUG(D_any) debug_printf("-oY used so not creating notifier socket\n");
1146
  return;
1147
  }
1147
if (override_local_interfaces && !override_pid_file_path)
1148
if (override_local_interfaces && !override_pid_file_path)
1148
  {
1149
  {
1149
  DEBUG(D_any)
1150
  DEBUG(D_any)
Lines 1272-1285 Link Here
1272
buf[sz] = 0;
1273
buf[sz] = 0;
1273
switch (buf[0])
1274
switch (buf[0])
1274
  {
1275
  {
1275
#ifdef EXPERIMENTAL_QUEUE_RAMP
1276
#ifndef DISABLE_QUEUE_RAMP
1276
  case NOTIFY_MSG_QRUN:
1277
  case NOTIFY_MSG_QRUN:
1277
    /* this should be a message_id */
1278
    /* this should be a message_id */
1278
    DEBUG(D_queue_run)
1279
    DEBUG(D_queue_run)
1279
      debug_printf("%s: qrunner trigger: %s\n", __FUNCTION__, buf+1);
1280
      debug_printf("%s: qrunner trigger: %s\n", __FUNCTION__, buf+1);
1280
    memcpy(queuerun_msgid, buf+1, MESSAGE_ID_LENGTH+1);
1281
    memcpy(queuerun_msgid, buf+1, MESSAGE_ID_LENGTH+1);
1281
    return TRUE;
1282
    return TRUE;
1282
#endif	/*EXPERIMENTAL_QUEUE_RAMP*/
1283
#endif
1283
1284
1284
  case NOTIFY_QUEUE_SIZE_REQ:
1285
  case NOTIFY_QUEUE_SIZE_REQ:
1285
    {
1286
    {
Lines 1300-1305 Link Here
1300
}
1301
}
1301
1302
1302
1303
1304
1305
1303
/*************************************************
1306
/*************************************************
1304
*              Exim Daemon Mainline              *
1307
*              Exim Daemon Mainline              *
1305
*************************************************/
1308
*************************************************/
Lines 1326-1335 Link Here
1326
void
1329
void
1327
daemon_go(void)
1330
daemon_go(void)
1328
{
1331
{
1329
struct passwd *pw;
1332
struct passwd * pw;
1330
int *listen_sockets = NULL;
1333
struct pollfd * fd_polls, * tls_watch_poll = NULL, * dnotify_poll = NULL;
1331
int listen_socket_count = 0;
1334
int listen_socket_count = 0, poll_fd_count;
1332
ip_address_item *addresses = NULL;
1335
ip_address_item * addresses = NULL;
1333
time_t last_connection_time = (time_t)0;
1336
time_t last_connection_time = (time_t)0;
1334
int local_queue_run_max = atoi(CS expand_string(queue_run_max));
1337
int local_queue_run_max = atoi(CS expand_string(queue_run_max));
1335
1338
Lines 1340-1355 Link Here
1340
1343
1341
DEBUG(D_any|D_v) debug_selector |= D_pid;
1344
DEBUG(D_any|D_v) debug_selector |= D_pid;
1342
1345
1346
/* Allocate enough pollstructs for inetd mode plus the ancillary sockets;
1347
also used when there are no listen sockets. */
1348
1349
fd_polls = store_get(sizeof(struct pollfd) * 3, GET_UNTAINTED);
1350
1343
if (f.inetd_wait_mode)
1351
if (f.inetd_wait_mode)
1344
  {
1352
  {
1345
  listen_socket_count = 1;
1353
  listen_socket_count = 1;
1346
  listen_sockets = store_get(sizeof(int), FALSE);
1347
  (void) close(3);
1354
  (void) close(3);
1348
  if (dup2(0, 3) == -1)
1355
  if (dup2(0, 3) == -1)
1349
    log_write(0, LOG_MAIN|LOG_PANIC_DIE,
1356
    log_write(0, LOG_MAIN|LOG_PANIC_DIE,
1350
        "failed to dup inetd socket safely away: %s", strerror(errno));
1357
        "failed to dup inetd socket safely away: %s", strerror(errno));
1351
1358
1352
  listen_sockets[0] = 3;
1359
  fd_polls[0].fd = 3;
1360
  fd_polls[0].events = POLLIN;
1353
  (void) close(0);
1361
  (void) close(0);
1354
  (void) close(1);
1362
  (void) close(1);
1355
  (void) close(2);
1363
  (void) close(2);
Lines 1386-1396 Link Here
1386
  for those OS for which this is necessary the first time it is called (in
1394
  for those OS for which this is necessary the first time it is called (in
1387
  order to perform an "open" on the kernel memory file). */
1395
  order to perform an "open" on the kernel memory file). */
1388
1396
1389
  #ifdef LOAD_AVG_NEEDS_ROOT
1397
#ifdef LOAD_AVG_NEEDS_ROOT
1390
  if (queue_only_load >= 0 || smtp_load_reserve >= 0 ||
1398
  if (queue_only_load >= 0 || smtp_load_reserve >= 0 ||
1391
       (deliver_queue_load_max >= 0 && deliver_drop_privilege))
1399
       (deliver_queue_load_max >= 0 && deliver_drop_privilege))
1392
    (void)os_getloadavg();
1400
    (void)os_getloadavg();
1393
  #endif
1401
#endif
1394
  }
1402
  }
1395
1403
1396
1404
Lines 1526-1532 Link Here
1526
  sep = 0;
1534
  sep = 0;
1527
  while ((s = string_nextinlist(&list, &sep, NULL, 0)))
1535
  while ((s = string_nextinlist(&list, &sep, NULL, 0)))
1528
    pct++;
1536
    pct++;
1529
  default_smtp_port = store_get((pct+1) * sizeof(int), FALSE);
1537
  default_smtp_port = store_get((pct+1) * sizeof(int), GET_UNTAINTED);
1530
  list = daemon_smtp_port;
1538
  list = daemon_smtp_port;
1531
  sep = 0;
1539
  sep = 0;
1532
  for (pct = 0;
1540
  for (pct = 0;
Lines 1554-1559 Link Here
1554
1562
1555
  list = tls_in.on_connect_ports;
1563
  list = tls_in.on_connect_ports;
1556
  sep = 0;
1564
  sep = 0;
1565
  /* the list isn't expanded so cannot be tainted.  If it ever is we will trap here */
1557
  while ((s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
1566
  while ((s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
1558
    if (!isdigit(*s))
1567
    if (!isdigit(*s))
1559
      {
1568
      {
Lines 1614-1620 Link Here
1614
    ipa->port = default_smtp_port[0];
1623
    ipa->port = default_smtp_port[0];
1615
    for (int i = 1; default_smtp_port[i] > 0; i++)
1624
    for (int i = 1; default_smtp_port[i] > 0; i++)
1616
      {
1625
      {
1617
      ip_address_item *new = store_get(sizeof(ip_address_item), FALSE);
1626
      ip_address_item * new = store_get(sizeof(ip_address_item), GET_UNTAINTED);
1618
1627
1619
      memcpy(new->address, ipa->address, Ustrlen(ipa->address) + 1);
1628
      memcpy(new->address, ipa->address, Ustrlen(ipa->address) + 1);
1620
      new->port = default_smtp_port[i];
1629
      new->port = default_smtp_port[i];
Lines 1668-1678 Link Here
1668
        }
1677
        }
1669
    }
1678
    }
1670
1679
1671
  /* Get a vector to remember all the sockets in */
1680
  /* Get a vector to remember all the sockets in.
1681
  Two extra elements for the ancillary sockets */
1672
1682
1673
  for (ipa = addresses; ipa; ipa = ipa->next)
1683
  for (ipa = addresses; ipa; ipa = ipa->next)
1674
    listen_socket_count++;
1684
    listen_socket_count++;
1675
  listen_sockets = store_get(sizeof(int) * listen_socket_count, FALSE);
1685
  fd_polls = store_get(sizeof(struct pollfd) * (listen_socket_count + 2),
1686
			    GET_UNTAINTED);
1687
  for (struct pollfd * p = fd_polls; p < fd_polls + listen_socket_count + 2;
1688
       p++)
1689
    { p->fd = -1; p->events = POLLIN; }
1676
1690
1677
  } /* daemon_listen but not inetd_wait_mode */
1691
  } /* daemon_listen but not inetd_wait_mode */
1678
1692
Lines 1695-1701 Link Here
1695
1709
1696
  if (smtp_accept_max > 0)
1710
  if (smtp_accept_max > 0)
1697
    {
1711
    {
1698
    smtp_slots = store_get(smtp_accept_max * sizeof(smtp_slot), FALSE);
1712
    smtp_slots = store_get(smtp_accept_max * sizeof(smtp_slot), GET_UNTAINTED);
1699
    for (int i = 0; i < smtp_accept_max; i++) smtp_slots[i] = empty_smtp_slot;
1713
    for (int i = 0; i < smtp_accept_max; i++) smtp_slots[i] = empty_smtp_slot;
1700
    }
1714
    }
1701
  }
1715
  }
Lines 1763-1770 Link Here
1763
  for (ipa = addresses, sk = 0; sk < listen_socket_count; ipa = ipa->next, sk++)
1777
  for (ipa = addresses, sk = 0; sk < listen_socket_count; ipa = ipa->next, sk++)
1764
    {
1778
    {
1765
    BOOL wildcard;
1779
    BOOL wildcard;
1766
    ip_address_item *ipa2;
1780
    ip_address_item * ipa2;
1767
    int af;
1781
    int fd, af;
1768
1782
1769
    if (Ustrchr(ipa->address, ':') != NULL)
1783
    if (Ustrchr(ipa->address, ':') != NULL)
1770
      {
1784
      {
Lines 1777-1783 Link Here
1777
      wildcard = ipa->address[0] == 0;
1791
      wildcard = ipa->address[0] == 0;
1778
      }
1792
      }
1779
1793
1780
    if ((listen_sockets[sk] = ip_socket(SOCK_STREAM, af)) < 0)
1794
    if ((fd_polls[sk].fd = fd = ip_socket(SOCK_STREAM, af)) < 0)
1781
      {
1795
      {
1782
      if (check_special_case(0, addresses, ipa, FALSE))
1796
      if (check_special_case(0, addresses, ipa, FALSE))
1783
        {
1797
        {
Lines 1786-1792 Link Here
1786
        goto SKIP_SOCKET;
1800
        goto SKIP_SOCKET;
1787
        }
1801
        }
1788
      log_write(0, LOG_PANIC_DIE, "IPv%c socket creation failed: %s",
1802
      log_write(0, LOG_PANIC_DIE, "IPv%c socket creation failed: %s",
1789
        (af == AF_INET6)? '6' : '4', strerror(errno));
1803
        af == AF_INET6 ? '6' : '4', strerror(errno));
1790
      }
1804
      }
1791
1805
1792
    /* If this is an IPv6 wildcard socket, set IPV6_V6ONLY if that option is
1806
    /* If this is an IPv6 wildcard socket, set IPV6_V6ONLY if that option is
Lines 1795-1802 Link Here
1795
1809
1796
#ifdef IPV6_V6ONLY
1810
#ifdef IPV6_V6ONLY
1797
    if (af == AF_INET6 && wildcard &&
1811
    if (af == AF_INET6 && wildcard &&
1798
        setsockopt(listen_sockets[sk], IPPROTO_IPV6, IPV6_V6ONLY, CS (&on),
1812
        setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0)
1799
          sizeof(on)) < 0)
1800
      log_write(0, LOG_MAIN, "Setting IPV6_V6ONLY on daemon's IPv6 wildcard "
1813
      log_write(0, LOG_MAIN, "Setting IPV6_V6ONLY on daemon's IPv6 wildcard "
1801
        "socket failed (%s): carrying on without it", strerror(errno));
1814
        "socket failed (%s): carrying on without it", strerror(errno));
1802
#endif  /* IPV6_V6ONLY */
1815
#endif  /* IPV6_V6ONLY */
Lines 1805-1820 Link Here
1805
    is being handled.  Without this, a connection will prevent reuse of the
1818
    is being handled.  Without this, a connection will prevent reuse of the
1806
    smtp port for listening. */
1819
    smtp port for listening. */
1807
1820
1808
    if (setsockopt(listen_sockets[sk], SOL_SOCKET, SO_REUSEADDR,
1821
    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
1809
                   US (&on), sizeof(on)) < 0)
1810
      log_write(0, LOG_MAIN|LOG_PANIC_DIE, "setting SO_REUSEADDR on socket "
1822
      log_write(0, LOG_MAIN|LOG_PANIC_DIE, "setting SO_REUSEADDR on socket "
1811
        "failed when starting daemon: %s", strerror(errno));
1823
        "failed when starting daemon: %s", strerror(errno));
1812
1824
1813
    /* Set TCP_NODELAY; Exim does its own buffering. There is a switch to
1825
    /* Set TCP_NODELAY; Exim does its own buffering. There is a switch to
1814
    disable this because it breaks some broken clients. */
1826
    disable this because it breaks some broken clients. */
1815
1827
1816
    if (tcp_nodelay) setsockopt(listen_sockets[sk], IPPROTO_TCP, TCP_NODELAY,
1828
    if (tcp_nodelay) setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
1817
      US (&on), sizeof(on));
1818
1829
1819
    /* Now bind the socket to the required port; if Exim is being restarted
1830
    /* Now bind the socket to the required port; if Exim is being restarted
1820
    it may not always be possible to bind immediately, even with SO_REUSEADDR
1831
    it may not always be possible to bind immediately, even with SO_REUSEADDR
Lines 1832-1843 Link Here
1832
    for(;;)
1843
    for(;;)
1833
      {
1844
      {
1834
      uschar *msg, *addr;
1845
      uschar *msg, *addr;
1835
      if (ip_bind(listen_sockets[sk], af, ipa->address, ipa->port) >= 0) break;
1846
      if (ip_bind(fd, af, ipa->address, ipa->port) >= 0) break;
1836
      if (check_special_case(errno, addresses, ipa, TRUE))
1847
      if (check_special_case(errno, addresses, ipa, TRUE))
1837
        {
1848
        {
1838
        DEBUG(D_any) debug_printf("wildcard IPv4 bind() failed after IPv6 "
1849
        DEBUG(D_any) debug_printf("wildcard IPv4 bind() failed after IPv6 "
1839
          "listen() success; EADDRINUSE ignored\n");
1850
          "listen() success; EADDRINUSE ignored\n");
1840
        (void)close(listen_sockets[sk]);
1851
        (void)close(fd);
1841
        goto SKIP_SOCKET;
1852
        goto SKIP_SOCKET;
1842
        }
1853
        }
1843
      msg = US strerror(errno);
1854
      msg = US strerror(errno);
Lines 1865-1894 Link Here
1865
      else
1876
      else
1866
        debug_printf("listening on %s port %d\n", ipa->address, ipa->port);
1877
        debug_printf("listening on %s port %d\n", ipa->address, ipa->port);
1867
1878
1879
    /* Start listening on the bound socket, establishing the maximum backlog of
1880
    connections that is allowed. On success, add to the set of sockets for select
1881
    and continue to the next address. */
1882
1868
#if defined(TCP_FASTOPEN) && !defined(__APPLE__)
1883
#if defined(TCP_FASTOPEN) && !defined(__APPLE__)
1869
    if (  f.tcp_fastopen_ok
1884
    if (  f.tcp_fastopen_ok
1870
       && setsockopt(listen_sockets[sk], IPPROTO_TCP, TCP_FASTOPEN,
1885
       && setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN,
1871
		    &smtp_connect_backlog, sizeof(smtp_connect_backlog)))
1886
		    &smtp_connect_backlog, sizeof(smtp_connect_backlog)))
1872
      {
1887
      {
1873
      DEBUG(D_any) debug_printf("setsockopt FASTOPEN: %s\n", strerror(errno));
1888
      DEBUG(D_any) debug_printf("setsockopt FASTOPEN: %s\n", strerror(errno));
1874
      f.tcp_fastopen_ok = FALSE;
1889
      f.tcp_fastopen_ok = FALSE;
1875
      }
1890
      }
1876
#endif
1891
#endif
1877
1892
    if (listen(fd, smtp_connect_backlog) >= 0)
1878
    /* Start listening on the bound socket, establishing the maximum backlog of
1879
    connections that is allowed. On success, continue to the next address. */
1880
1881
    if (listen(listen_sockets[sk], smtp_connect_backlog) >= 0)
1882
      {
1893
      {
1883
#if defined(TCP_FASTOPEN) && defined(__APPLE__)
1894
#if defined(TCP_FASTOPEN) && defined(__APPLE__)
1884
      if (  f.tcp_fastopen_ok
1895
      if (  f.tcp_fastopen_ok
1885
	 && setsockopt(listen_sockets[sk], IPPROTO_TCP, TCP_FASTOPEN,
1896
	 && setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN, &on, sizeof(on)))
1886
		      &on, sizeof(on)))
1887
	{
1897
	{
1888
	DEBUG(D_any) debug_printf("setsockopt FASTOPEN: %s\n", strerror(errno));
1898
	DEBUG(D_any) debug_printf("setsockopt FASTOPEN: %s\n", strerror(errno));
1889
	f.tcp_fastopen_ok = FALSE;
1899
	f.tcp_fastopen_ok = FALSE;
1890
	}
1900
	}
1891
#endif
1901
#endif
1902
      fd_polls[sk].fd = fd;
1892
      continue;
1903
      continue;
1893
      }
1904
      }
1894
1905
Lines 1906-1912 Link Here
1906
1917
1907
    DEBUG(D_any) debug_printf("wildcard IPv4 listen() failed after IPv6 "
1918
    DEBUG(D_any) debug_printf("wildcard IPv4 listen() failed after IPv6 "
1908
      "listen() success; EADDRINUSE ignored\n");
1919
      "listen() success; EADDRINUSE ignored\n");
1909
    (void)close(listen_sockets[sk]);
1920
    (void)close(fd);
1910
1921
1911
    /* Come here if there has been a problem with the socket which we
1922
    /* Come here if there has been a problem with the socket which we
1912
    are going to ignore. We remove the address from the chain, and back up the
1923
    are going to ignore. We remove the address from the chain, and back up the
Lines 1955-1960 Link Here
1955
  }
1966
  }
1956
1967
1957
/* Set up the handler for SIGHUP, which causes a restart of the daemon. */
1968
/* Set up the handler for SIGHUP, which causes a restart of the daemon. */
1969
1958
sighup_seen = FALSE;
1970
sighup_seen = FALSE;
1959
signal(SIGHUP, sighup_handler);
1971
signal(SIGHUP, sighup_handler);
1960
1972
Lines 1979-1985 Link Here
1979
1991
1980
if (queue_interval > 0 && local_queue_run_max > 0)
1992
if (queue_interval > 0 && local_queue_run_max > 0)
1981
  {
1993
  {
1982
  queue_pid_slots = store_get(local_queue_run_max * sizeof(pid_t), FALSE);
1994
  queue_pid_slots = store_get(local_queue_run_max * sizeof(pid_t), GET_UNTAINTED);
1983
  for (int i = 0; i < local_queue_run_max; i++) queue_pid_slots[i] = 0;
1995
  for (int i = 0; i < local_queue_run_max; i++) queue_pid_slots[i] = 0;
1984
  }
1996
  }
1985
1997
Lines 2164-2169 Link Here
2164
#ifdef SUPPORT_SPF
2176
#ifdef SUPPORT_SPF
2165
spf_init();
2177
spf_init();
2166
#endif
2178
#endif
2179
#ifndef DISABLE_TLS
2180
tls_daemon_init();
2181
#endif
2182
2183
/* Add ancillary sockets to the set for select */
2184
2185
poll_fd_count = listen_socket_count;
2186
#ifndef DISABLE_TLS
2187
if (tls_watch_fd >= 0)
2188
  {
2189
  tls_watch_poll = &fd_polls[poll_fd_count++];
2190
  tls_watch_poll->fd = tls_watch_fd;
2191
  tls_watch_poll->events = POLLIN;
2192
  }
2193
#endif
2194
if (daemon_notifier_fd >= 0)
2195
  {
2196
  dnotify_poll = &fd_polls[poll_fd_count++];
2197
  dnotify_poll->fd = daemon_notifier_fd;
2198
  dnotify_poll->events = POLLIN;
2199
  }
2167
2200
2168
/* Close the log so it can be renamed and moved. In the few cases below where
2201
/* Close the log so it can be renamed and moved. In the few cases below where
2169
this long-running process writes to the log (always exceptional conditions), it
2202
this long-running process writes to the log (always exceptional conditions), it
Lines 2185-2197 Link Here
2185
2218
2186
for (;;)
2219
for (;;)
2187
  {
2220
  {
2188
  #if HAVE_IPV6
2189
  struct sockaddr_in6 accepted;
2190
  #else
2191
  struct sockaddr_in accepted;
2192
  #endif
2193
2194
  EXIM_SOCKLEN_T len;
2195
  pid_t pid;
2221
  pid_t pid;
2196
2222
2197
  if (sigterm_seen)
2223
  if (sigterm_seen)
Lines 2246-2252 Link Here
2246
    else
2272
    else
2247
      {
2273
      {
2248
      DEBUG(D_any) debug_printf("%s received\n",
2274
      DEBUG(D_any) debug_printf("%s received\n",
2249
#ifdef EXPERIMENTAL_QUEUE_RAMP
2275
#ifndef DISABLE_QUEUE_RAMP
2250
	*queuerun_msgid ? "qrun notification" :
2276
	*queuerun_msgid ? "qrun notification" :
2251
#endif
2277
#endif
2252
	"SIGALRM");
2278
	"SIGALRM");
Lines 2269-2275 Link Here
2269
          /* Close any open listening sockets in the child */
2295
          /* Close any open listening sockets in the child */
2270
2296
2271
	  close_daemon_sockets(daemon_notifier_fd,
2297
	  close_daemon_sockets(daemon_notifier_fd,
2272
	    listen_sockets, listen_socket_count);
2298
	    fd_polls, listen_socket_count);
2273
2299
2274
          /* Reset SIGHUP and SIGCHLD in the child in both cases. */
2300
          /* Reset SIGHUP and SIGCHLD in the child in both cases. */
2275
2301
Lines 2292-2298 Link Here
2292
            *p++ = '-';
2318
            *p++ = '-';
2293
            *p++ = 'q';
2319
            *p++ = 'q';
2294
            if (  f.queue_2stage
2320
            if (  f.queue_2stage
2295
#ifdef EXPERIMENTAL_QUEUE_RAMP
2321
#ifndef DISABLE_QUEUE_RAMP
2296
	       && !*queuerun_msgid
2322
	       && !*queuerun_msgid
2297
#endif
2323
#endif
2298
	       ) *p++ = 'q';
2324
	       ) *p++ = 'q';
Lines 2304-2310 Link Here
2304
	    extra[0] = *queue_name
2330
	    extra[0] = *queue_name
2305
	      ? string_sprintf("%sG%s", opt, queue_name) : opt;
2331
	      ? string_sprintf("%sG%s", opt, queue_name) : opt;
2306
2332
2307
#ifdef EXPERIMENTAL_QUEUE_RAMP
2333
#ifndef DISABLE_QUEUE_RAMP
2308
	    if (*queuerun_msgid)
2334
	    if (*queuerun_msgid)
2309
	      {
2335
	      {
2310
	      log_write(0, LOG_MAIN, "notify triggered queue run");
2336
	      log_write(0, LOG_MAIN, "notify triggered queue run");
Lines 2339-2345 Link Here
2339
2365
2340
          /* No need to re-exec; SIGALRM remains set to the default handler */
2366
          /* No need to re-exec; SIGALRM remains set to the default handler */
2341
2367
2342
#ifdef EXPERIMENTAL_QUEUE_RAMP
2368
#ifndef DISABLE_QUEUE_RAMP
2343
	  if (*queuerun_msgid)
2369
	  if (*queuerun_msgid)
2344
	    {
2370
	    {
2345
	    log_write(0, LOG_MAIN, "notify triggered queue run");
2371
	    log_write(0, LOG_MAIN, "notify triggered queue run");
Lines 2375-2381 Link Here
2375
      /* Reset the alarm clock */
2401
      /* Reset the alarm clock */
2376
2402
2377
      sigalrm_seen = FALSE;
2403
      sigalrm_seen = FALSE;
2378
#ifdef EXPERIMENTAL_QUEUE_RAMP
2404
#ifndef DISABLE_QUEUE_RAMP
2379
      if (*queuerun_msgid)
2405
      if (*queuerun_msgid)
2380
	*queuerun_msgid = 0;
2406
	*queuerun_msgid = 0;
2381
      else
2407
      else
Lines 2397-2415 Link Here
2397
2423
2398
  if (f.daemon_listen)
2424
  if (f.daemon_listen)
2399
    {
2425
    {
2400
    int lcount, select_errno;
2426
    int lcount;
2401
    int max_socket = 0;
2402
    BOOL select_failed = FALSE;
2427
    BOOL select_failed = FALSE;
2403
    fd_set select_listen;
2404
2405
    FD_ZERO(&select_listen);
2406
    if (daemon_notifier_fd >= 0)
2407
      FD_SET(daemon_notifier_fd, &select_listen);
2408
    for (int sk = 0; sk < listen_socket_count; sk++)
2409
      {
2410
      FD_SET(listen_sockets[sk], &select_listen);
2411
      if (listen_sockets[sk] > max_socket) max_socket = listen_sockets[sk];
2412
      }
2413
2428
2414
    DEBUG(D_any) debug_printf("Listening...\n");
2429
    DEBUG(D_any) debug_printf("Listening...\n");
2415
2430
Lines 2426-2433 Link Here
2426
      errno = EINTR;
2441
      errno = EINTR;
2427
      }
2442
      }
2428
    else
2443
    else
2429
      lcount = select(max_socket + 1, (SELECT_ARG2_TYPE *)&select_listen,
2444
      lcount = poll(fd_polls, poll_fd_count, -1);
2430
        NULL, NULL, NULL);
2431
2445
2432
    if (lcount < 0)
2446
    if (lcount < 0)
2433
      {
2447
      {
Lines 2442-2455 Link Here
2442
    old one had just finished. Preserve the errno from any select() failure for
2456
    old one had just finished. Preserve the errno from any select() failure for
2443
    the use of the common select/accept error processing below. */
2457
    the use of the common select/accept error processing below. */
2444
2458
2445
    select_errno = errno;
2459
      {
2446
    handle_ending_processes();
2460
      int select_errno = errno;
2447
    errno = select_errno;
2461
      handle_ending_processes();
2448
2462
2449
#ifndef DISABLE_TLS
2463
#ifndef DISABLE_TLS
2450
    /* Create or rotate any required keys */
2464
      {
2451
    tls_daemon_init();
2465
      int old_tfd;
2466
      /* Create or rotate any required keys; handle (delayed) filewatch event */
2467
2468
      if ((old_tfd = tls_daemon_tick()) >= 0)
2469
	for (struct pollfd * p = &fd_polls[listen_socket_count];
2470
	     p < fd_polls + poll_fd_count; p++)
2471
	  if (p->fd == old_tfd) { p->fd = tls_watch_fd ; break; }
2472
      }
2452
#endif
2473
#endif
2474
      errno = select_errno;
2475
      }
2453
2476
2454
    /* Loop for all the sockets that are currently ready to go. If select
2477
    /* Loop for all the sockets that are currently ready to go. If select
2455
    actually failed, we have set the count to 1 and select_failed=TRUE, so as
2478
    actually failed, we have set the count to 1 and select_failed=TRUE, so as
Lines 2458-2480 Link Here
2458
    while (lcount-- > 0)
2481
    while (lcount-- > 0)
2459
      {
2482
      {
2460
      int accept_socket = -1;
2483
      int accept_socket = -1;
2484
#if HAVE_IPV6
2485
      struct sockaddr_in6 accepted;
2486
#else
2487
      struct sockaddr_in accepted;
2488
#endif
2461
2489
2462
      if (!select_failed)
2490
      if (!select_failed)
2463
	{
2491
	{
2464
	if (  daemon_notifier_fd >= 0
2492
#if !defined(DISABLE_TLS) && (defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT))
2465
	   && FD_ISSET(daemon_notifier_fd, &select_listen))
2493
	if (tls_watch_poll && tls_watch_poll->revents & POLLIN)
2494
	  {
2495
	  tls_watch_poll->revents = 0;
2496
          tls_watch_trigger_time = time(NULL);	/* Set up delayed event */
2497
	  tls_watch_discard_event(tls_watch_fd);
2498
	  break;	/* to top of daemon loop */
2499
	  }
2500
#endif
2501
	if (dnotify_poll && dnotify_poll->revents & POLLIN)
2466
	  {
2502
	  {
2467
	  FD_CLR(daemon_notifier_fd, &select_listen);
2503
	  dnotify_poll->revents = 0;
2468
	  sigalrm_seen = daemon_notification();
2504
	  sigalrm_seen = daemon_notification();
2469
	  break;	/* to top of daemon loop */
2505
	  break;	/* to top of daemon loop */
2470
	  }
2506
	  }
2471
        for (int sk = 0; sk < listen_socket_count; sk++)
2507
	for (struct pollfd * p = fd_polls; p < fd_polls + listen_socket_count;
2472
          if (FD_ISSET(listen_sockets[sk], &select_listen))
2508
	     p++)
2509
	  if (p->revents & POLLIN)
2473
            {
2510
            {
2474
            len = sizeof(accepted);
2511
	    EXIM_SOCKLEN_T alen = sizeof(accepted);
2475
            accept_socket = accept(listen_sockets[sk],
2512
#ifdef TCP_INFO
2476
              (struct sockaddr *)&accepted, &len);
2513
	    struct tcp_info ti;
2477
            FD_CLR(listen_sockets[sk], &select_listen);
2514
	    socklen_t tlen = sizeof(ti);
2515
2516
	    /* If monitoring the backlog is wanted, grab for later logging */
2517
2518
	    smtp_listen_backlog = 0;
2519
	    if (  smtp_backlog_monitor > 0
2520
	       && getsockopt(p->fd, IPPROTO_TCP, TCP_INFO, &ti, &tlen) == 0)
2521
	      {
2522
# ifdef EXIM_HAVE_TCPI_UNACKED
2523
	      DEBUG(D_interface) debug_printf("listen fd %d queue max %u curr %u\n",
2524
		      p->fd, ti.tcpi_sacked, ti.tcpi_unacked);
2525
	      smtp_listen_backlog = ti.tcpi_unacked;
2526
# elif defined(__FreeBSD__)	/* This does not work. Investigate kernel sourcecode. */
2527
	      DEBUG(D_interface) debug_printf("listen fd %d queue max %u curr %u\n",
2528
		      p->fd, ti.__tcpi_sacked, ti.__tcpi_unacked);
2529
	      smtp_listen_backlog = ti.__tcpi_unacked;
2530
# endif
2531
	      }
2532
#endif
2533
	    p->revents = 0;
2534
            accept_socket = accept(p->fd, (struct sockaddr *)&accepted, &alen);
2478
            break;
2535
            break;
2479
            }
2536
            }
2480
	}
2537
	}
Lines 2499-2539 Link Here
2499
        else if (  errno != accept_retry_errno
2556
        else if (  errno != accept_retry_errno
2500
		|| select_failed != accept_retry_select_failed
2557
		|| select_failed != accept_retry_select_failed
2501
		|| accept_retry_count >= 50)
2558
		|| accept_retry_count >= 50)
2502
            {
2559
	  {
2503
            log_write(0, LOG_MAIN | (accept_retry_count >= 50? LOG_PANIC : 0),
2560
	  log_write(0, LOG_MAIN | (accept_retry_count >= 50 ? LOG_PANIC : 0),
2504
              "%d %s() failure%s: %s",
2561
	    "%d %s() failure%s: %s",
2505
              accept_retry_count,
2562
	    accept_retry_count,
2506
              accept_retry_select_failed? "select" : "accept",
2563
	    accept_retry_select_failed ? "select" : "accept",
2507
              accept_retry_count == 1 ? "" : "s",
2564
	    accept_retry_count == 1 ? "" : "s",
2508
              strerror(accept_retry_errno));
2565
	    strerror(accept_retry_errno));
2509
            log_close_all();
2566
	  log_close_all();
2510
            accept_retry_count = 0;
2567
	  accept_retry_count = 0;
2511
            accept_retry_errno = errno;
2568
	  accept_retry_errno = errno;
2512
            accept_retry_select_failed = select_failed;
2569
	  accept_retry_select_failed = select_failed;
2513
            }
2570
	  }
2514
        accept_retry_count++;
2571
        accept_retry_count++;
2515
        }
2572
        }
2516
      else
2573
      else if (accept_retry_count > 0)
2517
        {
2574
	{
2518
        if (accept_retry_count > 0)
2575
	log_write(0, LOG_MAIN, "%d %s() failure%s: %s",
2519
          {
2576
	  accept_retry_count,
2520
          log_write(0, LOG_MAIN, "%d %s() failure%s: %s",
2577
	  accept_retry_select_failed ? "select" : "accept",
2521
            accept_retry_count,
2578
	  accept_retry_count == 1 ? "" : "s",
2522
            accept_retry_select_failed? "select" : "accept",
2579
	  strerror(accept_retry_errno));
2523
            (accept_retry_count == 1)? "" : "s",
2580
	log_close_all();
2524
            strerror(accept_retry_errno));
2581
	accept_retry_count = 0;
2525
          log_close_all();
2582
	}
2526
          accept_retry_count = 0;
2527
          }
2528
        }
2529
2583
2530
      /* If select/accept succeeded, deal with the connection. */
2584
      /* If select/accept succeeded, deal with the connection. */
2531
2585
2532
      if (accept_socket >= 0)
2586
      if (accept_socket >= 0)
2533
        {
2587
        {
2588
#ifdef TCP_QUICKACK /* Avoid pure-ACKs while in tls protocol pingpong phase */
2589
	/* Unfortunately we cannot be certain to do this before a TLS-on-connect
2590
	Client Hello arrives and is acked. We do it as early as possible. */
2591
	(void) setsockopt(accept_socket, IPPROTO_TCP, TCP_QUICKACK, US &off, sizeof(off));
2592
#endif
2534
        if (inetd_wait_timeout)
2593
        if (inetd_wait_timeout)
2535
          last_connection_time = time(NULL);
2594
          last_connection_time = time(NULL);
2536
        handle_smtp_call(listen_sockets, listen_socket_count, accept_socket,
2595
        handle_smtp_call(fd_polls, listen_socket_count, accept_socket,
2537
          (struct sockaddr *)&accepted);
2596
          (struct sockaddr *)&accepted);
2538
        }
2597
        }
2539
      }
2598
      }
Lines 2548-2557 Link Here
2548
2607
2549
  else
2608
  else
2550
    {
2609
    {
2551
    struct timeval tv;
2610
    struct pollfd p;
2552
    tv.tv_sec = queue_interval;
2611
    poll(&p, 0, queue_interval * 1000);
2553
    tv.tv_usec = 0;
2554
    select(0, NULL, NULL, NULL, &tv);
2555
    handle_ending_processes();
2612
    handle_ending_processes();
2556
    }
2613
    }
2557
2614
Lines 2576-2583 Link Here
2576
    {
2633
    {
2577
    log_write(0, LOG_MAIN, "pid %d: SIGHUP received: re-exec daemon",
2634
    log_write(0, LOG_MAIN, "pid %d: SIGHUP received: re-exec daemon",
2578
      getpid());
2635
      getpid());
2579
    close_daemon_sockets(daemon_notifier_fd,
2636
    close_daemon_sockets(daemon_notifier_fd, fd_polls, listen_socket_count);
2580
      listen_sockets, listen_socket_count);
2581
    ALARM_CLR(0);
2637
    ALARM_CLR(0);
2582
    signal(SIGHUP, SIG_IGN);
2638
    signal(SIGHUP, SIG_IGN);
2583
    sighup_argv[0] = exim_path;
2639
    sighup_argv[0] = exim_path;
(-)exim.orig/src/dbfn.c (-64 / +72 lines)
Lines 2-14 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
10
#include "exim.h"
10
#include "exim.h"
11
11
12
/* We have buffers holding path names for database files.
13
PATH_MAX could be used here, but would be wasting memory, as we deal
14
with database files like $spooldirectory/db/<name> */
15
#define PATHLEN 256
16
12
17
13
/* Functions for accessing Exim's hints database, which consists of a number of
18
/* Functions for accessing Exim's hints database, which consists of a number of
14
different DBM files. This module does not contain code for reading DBM files
19
different DBM files. This module does not contain code for reading DBM files
Lines 34-64 Link Here
34
39
35
40
36
/*************************************************
41
/*************************************************
37
*         Berkeley DB error callback             *
38
*************************************************/
39
40
/* For Berkeley DB >= 2, we can define a function to be called in case of DB
41
errors. This should help with debugging strange DB problems, e.g. getting "File
42
exists" when you try to open a db file. The API for this function was changed
43
at DB release 4.3. */
44
45
#if defined(USE_DB) && defined(DB_VERSION_STRING)
46
void
47
#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
48
dbfn_bdb_error_callback(const DB_ENV *dbenv, const char *pfx, const char *msg)
49
{
50
dbenv = dbenv;
51
#else
52
dbfn_bdb_error_callback(const char *pfx, char *msg)
53
{
54
#endif
55
pfx = pfx;
56
log_write(0, LOG_MAIN, "Berkeley DB error: %s", msg);
57
}
58
#endif
59
60
61
/*************************************************
62
*          Open and lock a database file         *
42
*          Open and lock a database file         *
63
*************************************************/
43
*************************************************/
64
44
Lines 90-96 Link Here
90
int rc, save_errno;
70
int rc, save_errno;
91
BOOL read_only = flags == O_RDONLY;
71
BOOL read_only = flags == O_RDONLY;
92
flock_t lock_data;
72
flock_t lock_data;
93
uschar dirname[256], filename[256];
73
uschar dirname[PATHLEN], filename[PATHLEN];
94
74
95
DEBUG(D_hints_lookup) acl_level++;
75
DEBUG(D_hints_lookup) acl_level++;
96
76
Lines 121-127 Link Here
121
if (dbblock->lockfd < 0)
101
if (dbblock->lockfd < 0)
122
  {
102
  {
123
  log_write(0, LOG_MAIN, "%s",
103
  log_write(0, LOG_MAIN, "%s",
124
    string_open_failed(errno, "database lock file %s", filename));
104
    string_open_failed("database lock file %s", filename));
125
  errno = 0;      /* Indicates locking failure */
105
  errno = 0;      /* Indicates locking failure */
126
  DEBUG(D_hints_lookup) acl_level--;
106
  DEBUG(D_hints_lookup) acl_level--;
127
  return NULL;
107
  return NULL;
Lines 167-178 Link Here
167
snprintf(CS filename, sizeof(filename), "%s/%s", dirname, name);
147
snprintf(CS filename, sizeof(filename), "%s/%s", dirname, name);
168
148
169
priv_drop_temp(exim_uid, exim_gid);
149
priv_drop_temp(exim_uid, exim_gid);
170
EXIM_DBOPEN(filename, dirname, flags, EXIMDB_MODE, &(dbblock->dbptr));
150
dbblock->dbptr = exim_dbopen(filename, dirname, flags, EXIMDB_MODE);
171
if (!dbblock->dbptr && errno == ENOENT && flags == O_RDWR)
151
if (!dbblock->dbptr && errno == ENOENT && flags == O_RDWR)
172
  {
152
  {
173
  DEBUG(D_hints_lookup)
153
  DEBUG(D_hints_lookup)
174
    debug_printf_indent("%s appears not to exist: trying to create\n", filename);
154
    debug_printf_indent("%s appears not to exist: trying to create\n", filename);
175
  EXIM_DBOPEN(filename, dirname, flags|O_CREAT, EXIMDB_MODE, &(dbblock->dbptr));
155
  dbblock->dbptr = exim_dbopen(filename, dirname, flags|O_CREAT, EXIMDB_MODE);
176
  }
156
  }
177
save_errno = errno;
157
save_errno = errno;
178
priv_restore();
158
priv_restore();
Lines 183-194 Link Here
183
163
184
if (!dbblock->dbptr)
164
if (!dbblock->dbptr)
185
  {
165
  {
166
  errno = save_errno;
186
  if (lof && save_errno != ENOENT)
167
  if (lof && save_errno != ENOENT)
187
    log_write(0, LOG_MAIN, "%s", string_open_failed(save_errno, "DB file %s",
168
    log_write(0, LOG_MAIN, "%s", string_open_failed("DB file %s",
188
        filename));
169
        filename));
189
  else
170
  else
190
    DEBUG(D_hints_lookup)
171
    DEBUG(D_hints_lookup)
191
      debug_printf_indent("%s\n", CS string_open_failed(save_errno, "DB file %s",
172
      debug_printf_indent("%s\n", CS string_open_failed("DB file %s",
192
          filename));
173
          filename));
193
  (void)close(dbblock->lockfd);
174
  (void)close(dbblock->lockfd);
194
  errno = save_errno;
175
  errno = save_errno;
Lines 226-232 Link Here
226
void
207
void
227
dbfn_close(open_db *dbblock)
208
dbfn_close(open_db *dbblock)
228
{
209
{
229
EXIM_DBCLOSE(dbblock->dbptr);
210
exim_dbclose(dbblock->dbptr);
230
(void)close(dbblock->lockfd);
211
(void)close(dbblock->lockfd);
231
DEBUG(D_hints_lookup)
212
DEBUG(D_hints_lookup)
232
  { debug_printf_indent("closed hints database and lockfile\n"); acl_level--; }
213
  { debug_printf_indent("closed hints database and lockfile\n"); acl_level--; }
Lines 262-292 Link Here
262
void *yield;
243
void *yield;
263
EXIM_DATUM key_datum, result_datum;
244
EXIM_DATUM key_datum, result_datum;
264
int klen = Ustrlen(key) + 1;
245
int klen = Ustrlen(key) + 1;
265
uschar * key_copy = store_get(klen, is_tainted(key));
246
uschar * key_copy = store_get(klen, key);
266
247
267
memcpy(key_copy, key, klen);
248
memcpy(key_copy, key, klen);
268
249
269
DEBUG(D_hints_lookup) debug_printf_indent("dbfn_read: key=%s\n", key);
250
DEBUG(D_hints_lookup) debug_printf_indent("dbfn_read: key=%s\n", key);
270
251
271
EXIM_DATUM_INIT(key_datum);         /* Some DBM libraries require the datum */
252
exim_datum_init(&key_datum);         /* Some DBM libraries require the datum */
272
EXIM_DATUM_INIT(result_datum);      /* to be cleared before use. */
253
exim_datum_init(&result_datum);      /* to be cleared before use. */
273
EXIM_DATUM_DATA(key_datum) = CS key_copy;
254
exim_datum_data_set(&key_datum, key_copy);
274
EXIM_DATUM_SIZE(key_datum) = klen;
255
exim_datum_size_set(&key_datum, klen);
275
256
276
if (!EXIM_DBGET(dbblock->dbptr, key_datum, result_datum)) return NULL;
257
if (!exim_dbget(dbblock->dbptr, &key_datum, &result_datum)) return NULL;
277
258
278
/* Assume the data store could have been tainted.  Properly, we should
259
/* Assume the data store could have been tainted.  Properly, we should
279
store the taint status with the data. */
260
store the taint status with the data. */
280
261
281
yield = store_get(EXIM_DATUM_SIZE(result_datum), TRUE);
262
yield = store_get(exim_datum_size_get(&result_datum), GET_TAINTED);
282
memcpy(yield, EXIM_DATUM_DATA(result_datum), EXIM_DATUM_SIZE(result_datum));
263
memcpy(yield, exim_datum_data_get(&result_datum), exim_datum_size_get(&result_datum));
283
if (length != NULL) *length = EXIM_DATUM_SIZE(result_datum);
264
if (length) *length = exim_datum_size_get(&result_datum);
284
265
285
EXIM_DATUM_FREE(result_datum);    /* Some DBM libs require freeing */
266
exim_datum_free(&result_datum);    /* Some DBM libs require freeing */
286
return yield;
267
return yield;
287
}
268
}
288
269
289
270
271
/* Read a record.  If the length is not as expected then delete it, write
272
an error log line, delete the record and return NULL.
273
Use this for fixed-size records (so not retry or wait records).
274
275
Arguments:
276
  dbblock   a pointer to an open database block
277
  key       the key of the record to be read
278
  length    the expected record length
279
280
Returns: a pointer to the retrieved record, or
281
         NULL if the record is not found/bad
282
*/
283
284
void *
285
dbfn_read_enforce_length(open_db * dbblock, const uschar * key, size_t length)
286
{
287
int rlen;
288
void * yield = dbfn_read_with_length(dbblock, key, &rlen);
289
290
if (yield)
291
  {
292
  if (rlen == length) return yield;
293
  log_write(0, LOG_MAIN|LOG_PANIC, "Bad db record size for '%s'", key);
294
  dbfn_delete(dbblock, key);
295
  }
296
return NULL;
297
}
298
290
299
291
/*************************************************
300
/*************************************************
292
*             Write to database file             *
301
*             Write to database file             *
Lines 309-328 Link Here
309
EXIM_DATUM key_datum, value_datum;
318
EXIM_DATUM key_datum, value_datum;
310
dbdata_generic *gptr = (dbdata_generic *)ptr;
319
dbdata_generic *gptr = (dbdata_generic *)ptr;
311
int klen = Ustrlen(key) + 1;
320
int klen = Ustrlen(key) + 1;
312
uschar * key_copy = store_get(klen, is_tainted(key));
321
uschar * key_copy = store_get(klen, key);
313
322
314
memcpy(key_copy, key, klen);
323
memcpy(key_copy, key, klen);
315
gptr->time_stamp = time(NULL);
324
gptr->time_stamp = time(NULL);
316
325
317
DEBUG(D_hints_lookup) debug_printf_indent("dbfn_write: key=%s\n", key);
326
DEBUG(D_hints_lookup) debug_printf_indent("dbfn_write: key=%s\n", key);
318
327
319
EXIM_DATUM_INIT(key_datum);         /* Some DBM libraries require the datum */
328
exim_datum_init(&key_datum);         /* Some DBM libraries require the datum */
320
EXIM_DATUM_INIT(value_datum);       /* to be cleared before use. */
329
exim_datum_init(&value_datum);       /* to be cleared before use. */
321
EXIM_DATUM_DATA(key_datum) = CS key_copy;
330
exim_datum_data_set(&key_datum, key_copy);
322
EXIM_DATUM_SIZE(key_datum) = klen;
331
exim_datum_size_set(&key_datum, klen);
323
EXIM_DATUM_DATA(value_datum) = CS ptr;
332
exim_datum_data_set(&value_datum, ptr);
324
EXIM_DATUM_SIZE(value_datum) = length;
333
exim_datum_size_set(&value_datum, length);
325
return EXIM_DBPUT(dbblock->dbptr, key_datum, value_datum);
334
return exim_dbput(dbblock->dbptr, &key_datum, &value_datum);
326
}
335
}
327
336
328
337
Lines 343-358 Link Here
343
dbfn_delete(open_db *dbblock, const uschar *key)
352
dbfn_delete(open_db *dbblock, const uschar *key)
344
{
353
{
345
int klen = Ustrlen(key) + 1;
354
int klen = Ustrlen(key) + 1;
346
uschar * key_copy = store_get(klen, is_tainted(key));
355
uschar * key_copy = store_get(klen, key);
356
EXIM_DATUM key_datum;
347
357
348
DEBUG(D_hints_lookup) debug_printf_indent("dbfn_delete: key=%s\n", key);
358
DEBUG(D_hints_lookup) debug_printf_indent("dbfn_delete: key=%s\n", key);
349
359
350
memcpy(key_copy, key, klen);
360
memcpy(key_copy, key, klen);
351
EXIM_DATUM key_datum;
361
exim_datum_init(&key_datum);         /* Some DBM libraries require clearing */
352
EXIM_DATUM_INIT(key_datum);         /* Some DBM libraries require clearing */
362
exim_datum_data_set(&key_datum, key_copy);
353
EXIM_DATUM_DATA(key_datum) = CS key_copy;
363
exim_datum_size_set(&key_datum, klen);
354
EXIM_DATUM_SIZE(key_datum) = klen;
364
return exim_dbdel(dbblock->dbptr, &key_datum);
355
return EXIM_DBDEL(dbblock->dbptr, key_datum);
356
}
365
}
357
366
358
367
Lines 378-400 Link Here
378
{
387
{
379
EXIM_DATUM key_datum, value_datum;
388
EXIM_DATUM key_datum, value_datum;
380
uschar *yield;
389
uschar *yield;
381
value_datum = value_datum;    /* dummy; not all db libraries use this */
382
390
383
DEBUG(D_hints_lookup) debug_printf_indent("dbfn_scan\n");
391
DEBUG(D_hints_lookup) debug_printf_indent("dbfn_scan\n");
384
392
385
/* Some dbm require an initialization */
393
/* Some dbm require an initialization */
386
394
387
if (start) EXIM_DBCREATE_CURSOR(dbblock->dbptr, cursor);
395
if (start) *cursor = exim_dbcreate_cursor(dbblock->dbptr);
388
396
389
EXIM_DATUM_INIT(key_datum);         /* Some DBM libraries require the datum */
397
exim_datum_init(&key_datum);         /* Some DBM libraries require the datum */
390
EXIM_DATUM_INIT(value_datum);       /* to be cleared before use. */
398
exim_datum_init(&value_datum);       /* to be cleared before use. */
391
399
392
yield = (EXIM_DBSCAN(dbblock->dbptr, key_datum, value_datum, start, *cursor))?
400
yield = exim_dbscan(dbblock->dbptr, &key_datum, &value_datum, start, *cursor)
393
  US EXIM_DATUM_DATA(key_datum) : NULL;
401
  ? US exim_datum_data_get(&key_datum) : NULL;
394
402
395
/* Some dbm require a termination */
403
/* Some dbm require a termination */
396
404
397
if (!yield) EXIM_DBDELETE_CURSOR(*cursor);
405
if (!yield) exim_dbdelete_cursor(*cursor);
398
return yield;
406
return yield;
399
}
407
}
400
408
(-)exim.orig/src/dbfunctions.h (-4 / +9 lines)
Lines 2-10 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2015 */
5
/* Copyright (c) The Exim Maintainers 2022 */
6
/* Copyright (c) University of Cambridge 1995 - 2021 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
9
#ifndef DBFUNCTIONS_H
10
#define DBFUNCTIONS_H
8
11
9
/* Functions for reading/writing exim database files */
12
/* Functions for reading/writing exim database files */
10
13
Lines 12-17 Link Here
12
int      dbfn_delete(open_db *, const uschar *);
15
int      dbfn_delete(open_db *, const uschar *);
13
open_db *dbfn_open(uschar *, int, open_db *, BOOL, BOOL);
16
open_db *dbfn_open(uschar *, int, open_db *, BOOL, BOOL);
14
void    *dbfn_read_with_length(open_db *, const uschar *, int *);
17
void    *dbfn_read_with_length(open_db *, const uschar *, int *);
18
void    *dbfn_read_enforce_length(open_db *, const uschar *, size_t);
15
uschar  *dbfn_scan(open_db *, BOOL, EXIM_CURSOR **);
19
uschar  *dbfn_scan(open_db *, BOOL, EXIM_CURSOR **);
16
int      dbfn_write(open_db *, const uschar *, void *, int);
20
int      dbfn_write(open_db *, const uschar *, void *, int);
17
21
Lines 23-33 Link Here
23
changed at release 4.3. */
27
changed at release 4.3. */
24
28
25
#if defined(USE_DB) && defined(DB_VERSION_STRING)
29
#if defined(USE_DB) && defined(DB_VERSION_STRING)
26
#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
30
# if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
27
void     dbfn_bdb_error_callback(const DB_ENV *, const char *, const char *);
31
void     dbfn_bdb_error_callback(const DB_ENV *, const char *, const char *);
28
#else
32
# else
29
void     dbfn_bdb_error_callback(const char *, char *);
33
void     dbfn_bdb_error_callback(const char *, char *);
30
#endif
34
# endif
31
#endif
35
#endif
32
36
37
#endif
33
/* End of dbfunctions.h */
38
/* End of dbfunctions.h */
(-)exim.orig/src/dcc.c (-384 / +410 lines)
Lines 7-13 Link Here
7
 * wbreyha@gmx.net
7
 * wbreyha@gmx.net
8
 * See the file NOTICE for conditions of use and distribution.
8
 * See the file NOTICE for conditions of use and distribution.
9
 *
9
 *
10
 * Copyright (c) The Exim Maintainers 2015 - 2019
10
 * Copyright (c) The Exim Maintainers 2015 - 2021
11
 */
11
 */
12
12
13
/* Code for calling dccifd. Called from acl.c. */
13
/* Code for calling dccifd. Called from acl.c. */
Lines 23-464 Link Here
23
int dcc_rc = 0;
23
int dcc_rc = 0;
24
24
25
/* This function takes a file descriptor and a buffer as input and
25
/* This function takes a file descriptor and a buffer as input and
26
 * returns either 0 for success or errno in case of error. */
26
returns either 0 for success or errno in case of error. */
27
27
28
int flushbuffer (int socket, gstring *buffer)
28
static int flushbuffer
29
(int socket, gstring *buffer)
29
{
30
{
30
  int retval, rsp;
31
int rsp;
31
  rsp = write(socket, buffer->s, buffer->ptr);
32
33
rsp = write(socket, buffer->s, buffer->ptr);
34
DEBUG(D_acl)
35
  debug_printf("DCC: flushbuffer(): Result of the write() = %d\n", rsp);
36
if(rsp < 0)
37
  {
32
  DEBUG(D_acl)
38
  DEBUG(D_acl)
33
    debug_printf("DCC: flushbuffer(): Result of the write() = %d\n", rsp);
39
    debug_printf("DCC: flushbuffer(): Error writing buffer to socket: %s\n", strerror(errno));
34
  if(rsp < 0) {
40
  return errno;
35
    DEBUG(D_acl)
36
      debug_printf("DCC: flushbuffer(): Error writing buffer to socket: %s\n", strerror(errno));
37
    retval = errno;
38
  }
41
  }
39
  else {
42
DEBUG(D_acl)
40
    DEBUG(D_acl)
43
  debug_printf("DCC: flushbuffer(): Wrote buffer to socket:\n%.*s\n", buffer->ptr, buffer->s);
41
      debug_printf("DCC: flushbuffer(): Wrote buffer to socket:\n%.*s\n", buffer->ptr, buffer->s);
44
return 0;
42
    retval = 0;
43
  }
44
  return retval;
45
}
45
}
46
46
47
int
47
int
48
dcc_process(uschar **listptr)
48
dcc_process(uschar **listptr)
49
{
49
{
50
  int sep = 0;
50
int sep = 0;
51
  const uschar *list = *listptr;
51
const uschar *list = *listptr;
52
  FILE *data_file;
52
FILE *data_file;
53
  uschar *dcc_default_ip_option = US"127.0.0.1";
53
uschar *dcc_default_ip_option = US"127.0.0.1";
54
  uschar *dcc_helo_option = US"localhost";
54
uschar *dcc_helo_option = US"localhost";
55
  uschar *xtra_hdrs = NULL;
55
uschar *xtra_hdrs = NULL;
56
  uschar *override_client_ip  = NULL;
56
uschar *override_client_ip  = NULL;
57
57
58
  /* from local_scan */
58
/* from local_scan */
59
  int dcc_resplen, retval, sockfd, resp;
59
int dcc_resplen, retval, sockfd, resp;
60
  unsigned int portnr;
60
unsigned int portnr;
61
  struct sockaddr_un  serv_addr;
61
struct sockaddr_un  serv_addr;
62
  struct sockaddr_in  serv_addr_in;
62
struct sockaddr_in  serv_addr_in;
63
  struct hostent *ipaddress;
63
struct hostent *ipaddress;
64
  uschar sockpath[128];
64
uschar sockpath[128];
65
  uschar sockip[40], client_ip[40];
65
uschar sockip[40], client_ip[40];
66
  gstring *dcc_headers;
66
gstring *dcc_headers;
67
  gstring *sendbuf;
67
gstring *sendbuf;
68
  uschar *dcc_return_text;
68
uschar *dcc_return_text = US"''";
69
  struct header_line *mail_headers;
69
struct header_line *mail_headers;
70
  uschar *dcc_acl_options;
70
uschar *dcc_acl_options;
71
  gstring *dcc_xtra_hdrs;
71
gstring *dcc_xtra_hdrs;
72
  gstring *dcc_header_str;
72
gstring *dcc_header_str;
73
73
74
  /* grep 1st option */
74
/* grep 1st option */
75
  if ((dcc_acl_options = string_nextinlist(&list, &sep, NULL, 0))) {
75
if ((dcc_acl_options = string_nextinlist(&list, &sep, NULL, 0)))
76
    /* parse 1st option */
76
  {
77
    if (  strcmpic(dcc_acl_options, US"false") == 0
77
  /* parse 1st option */
78
       || Ustrcmp(dcc_acl_options, "0") == 0)
78
  if (  strcmpic(dcc_acl_options, US"false") == 0
79
      return FAIL;	/* explicitly no matching */
79
     || Ustrcmp(dcc_acl_options, "0") == 0)
80
    return FAIL;	/* explicitly no matching */
80
  }
81
  }
81
  else
82
else
82
    return FAIL;	/* empty means "don't match anything" */
83
  return FAIL;	/* empty means "don't match anything" */
83
84
  sep = 0;
85
84
86
  /* if we scanned this message last time, just return */
85
sep = 0;
87
  if (dcc_ok)
88
    return dcc_rc;
89
86
90
  /* open the spooled body */
87
/* if we scanned this message last time, just return */
91
  for (int i = 0; i < 2; i++) {
88
if (dcc_ok)
92
    uschar message_subdir[2];
89
  return dcc_rc;
93
    set_subdir_str(message_subdir, message_id, i);
94
    if ((data_file = Ufopen(
95
	    spool_fname(US"input", message_subdir, message_id, US"-D"), "rb")))
96
      break;
97
  }
98
99
  if (!data_file) {
100
    /* error while spooling */
101
    log_write(0, LOG_MAIN|LOG_PANIC,
102
           "DCC: error while opening spool file");
103
    return DEFER;
104
  }
105
106
  /* Initialize the variables */
107
90
108
  bzero(sockip,sizeof(sockip));
91
/* open the spooled body */
109
  if (dccifd_address) {
92
for (int i = 0; i < 2; i++)
110
    if (dccifd_address[0] == '/')
93
  {
111
      Ustrncpy(sockpath, dccifd_address, sizeof(sockpath));
94
  uschar message_subdir[2];
112
    else
95
  set_subdir_str(message_subdir, message_id, i);
113
      if( sscanf(CS dccifd_address, "%s %u", sockip, &portnr) != 2) {
96
  if ((data_file = Ufopen(
114
        log_write(0, LOG_MAIN,
97
	  spool_fname(US"input", message_subdir, message_id, US"-D"), "rb")))
115
          "DCC: warning - invalid dccifd address: '%s'", dccifd_address);
98
    break;
116
        (void)fclose(data_file);
99
  }
117
        return DEFER;
100
101
if (!data_file)
102
  {
103
  /* error while spooling */
104
  log_write(0, LOG_MAIN|LOG_PANIC,
105
	 "DCC: error while opening spool file");
106
  return DEFER;
107
  }
108
109
/* Initialize the variables */
110
111
bzero(sockip,sizeof(sockip));
112
if (dccifd_address)
113
  {
114
  if (dccifd_address[0] == '/')
115
    Ustrncpy(sockpath, dccifd_address, sizeof(sockpath));
116
  else
117
    if( sscanf(CS dccifd_address, "%s %u", sockip, &portnr) != 2)
118
      {
119
      log_write(0, LOG_MAIN,
120
	"DCC: warning - invalid dccifd address: '%s'", dccifd_address);
121
      (void)fclose(data_file);
122
      return DEFER;
118
      }
123
      }
119
  }
124
  }
120
125
121
  /* dcc_headers is what we send as dccifd options - see man dccifd */
126
/* dcc_headers is what we send as dccifd options - see man dccifd */
122
  /* We don't support any other option than 'header' so just copy that */
127
/* We don't support any other option than 'header' so just copy that */
123
  dcc_headers = string_cat(NULL, dccifd_options);
128
dcc_headers = string_cat(NULL, dccifd_options);
124
  /* if $acl_m_dcc_override_client_ip is set use it */
129
/* if $acl_m_dcc_override_client_ip is set use it */
125
  if (((override_client_ip = expand_string(US"$acl_m_dcc_override_client_ip")) != NULL) &&
130
if (((override_client_ip = expand_string(US"$acl_m_dcc_override_client_ip")) != NULL) &&
126
       (override_client_ip[0] != '\0')) {
131
     (override_client_ip[0] != '\0'))
127
    Ustrncpy(client_ip, override_client_ip, sizeof(client_ip)-1);
132
  {
128
    DEBUG(D_acl)
133
  Ustrncpy(client_ip, override_client_ip, sizeof(client_ip)-1);
129
      debug_printf("DCC: Client IP (overridden): %s\n", client_ip);
134
  DEBUG(D_acl)
135
    debug_printf("DCC: Client IP (overridden): %s\n", client_ip);
130
  }
136
  }
131
  else if(sender_host_address) {
137
else if(sender_host_address)
138
  {
132
  /* else if $sender_host_address is available use that? */
139
  /* else if $sender_host_address is available use that? */
133
    Ustrncpy(client_ip, sender_host_address, sizeof(client_ip)-1);
140
  Ustrncpy(client_ip, sender_host_address, sizeof(client_ip)-1);
134
    DEBUG(D_acl)
141
  DEBUG(D_acl)
135
      debug_printf("DCC: Client IP (sender_host_address): %s\n", client_ip);
142
    debug_printf("DCC: Client IP (sender_host_address): %s\n", client_ip);
136
  }
143
  }
137
  else {
144
else
138
    /* sender_host_address is NULL which means it comes from localhost */
145
  {
139
    Ustrncpy(client_ip, dcc_default_ip_option, sizeof(client_ip)-1);
146
  /* sender_host_address is NULL which means it comes from localhost */
140
    DEBUG(D_acl)
147
  Ustrncpy(client_ip, dcc_default_ip_option, sizeof(client_ip)-1);
141
      debug_printf("DCC: Client IP (default): %s\n", client_ip);
148
  DEBUG(D_acl)
149
    debug_printf("DCC: Client IP (default): %s\n", client_ip);
142
  }
150
  }
143
  /* build options block */
151
/* build options block */
144
  dcc_headers = string_append(dcc_headers, 5, US"\n", client_ip, US"\nHELO ", dcc_helo_option, US"\n");
152
dcc_headers = string_append(dcc_headers, 5, US"\n", client_ip, US"\nHELO ", dcc_helo_option, US"\n");
145
153
146
  /* initialize the other variables */
154
/* initialize the other variables */
147
  mail_headers = header_list;
155
mail_headers = header_list;
148
  /* we set the default return value to DEFER */
156
/* we set the default return value to DEFER */
149
  retval = DEFER;
157
retval = DEFER;
150
158
151
  /* send a null return path as "<>". */
159
/* send a null return path as "<>". */
152
  dcc_headers = string_cat (dcc_headers, *sender_address ? sender_address : US"<>");
160
dcc_headers = string_cat (dcc_headers, *sender_address ? sender_address : US"<>");
153
  dcc_headers = string_catn(dcc_headers, US"\n", 1);
161
dcc_headers = string_catn(dcc_headers, US"\n", 1);
154
162
155
  /**************************************
163
/**************************************
156
   * Now creating the socket connection *
164
 * Now creating the socket connection *
157
   **************************************/
165
 **************************************/
158
166
159
  /* If sockip contains an ip, we use a tcp socket, otherwise a UNIX socket */
167
/* If sockip contains an ip, we use a tcp socket, otherwise a UNIX socket */
160
  if(Ustrcmp(sockip, "")) {
168
if(Ustrcmp(sockip, ""))
161
    ipaddress = gethostbyname(CS sockip);
169
  {
162
    bzero(CS  &serv_addr_in, sizeof(serv_addr_in));
170
  ipaddress = gethostbyname(CS sockip);
163
    serv_addr_in.sin_family = AF_INET;
171
  bzero(CS  &serv_addr_in, sizeof(serv_addr_in));
164
    bcopy(CS ipaddress->h_addr, CS &serv_addr_in.sin_addr.s_addr, ipaddress->h_length);
172
  serv_addr_in.sin_family = AF_INET;
165
    serv_addr_in.sin_port = htons(portnr);
173
  bcopy(CS ipaddress->h_addr, CS &serv_addr_in.sin_addr.s_addr, ipaddress->h_length);
166
    if ((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0) {
174
  serv_addr_in.sin_port = htons(portnr);
167
      DEBUG(D_acl)
175
  if ((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0)
168
        debug_printf("DCC: Creating TCP socket connection failed: %s\n", strerror(errno));
176
    {
169
      log_write(0,LOG_PANIC,"DCC: Creating TCP socket connection failed: %s\n", strerror(errno));
177
    DEBUG(D_acl)
170
      /* if we cannot create the socket, defer the mail */
178
      debug_printf("DCC: Creating TCP socket connection failed: %s\n", strerror(errno));
171
      (void)fclose(data_file);
179
    log_write(0,LOG_PANIC,"DCC: Creating TCP socket connection failed: %s\n", strerror(errno));
172
      return retval;
180
    /* if we cannot create the socket, defer the mail */
181
    (void)fclose(data_file);
182
    return retval;
173
    }
183
    }
174
    /* Now connecting the socket (INET) */
184
  /* Now connecting the socket (INET) */
175
    if (connect(sockfd, (struct sockaddr *)&serv_addr_in, sizeof(serv_addr_in)) < 0) {
185
  if (connect(sockfd, (struct sockaddr *)&serv_addr_in, sizeof(serv_addr_in)) < 0)
176
      DEBUG(D_acl)
186
    {
177
        debug_printf("DCC: Connecting to TCP socket failed: %s\n", strerror(errno));
187
    DEBUG(D_acl)
178
      log_write(0,LOG_PANIC,"DCC: Connecting to TCP socket failed: %s\n", strerror(errno));
188
      debug_printf("DCC: Connecting to TCP socket failed: %s\n", strerror(errno));
179
      /* if we cannot contact the socket, defer the mail */
189
    log_write(0,LOG_PANIC,"DCC: Connecting to TCP socket failed: %s\n", strerror(errno));
180
      (void)fclose(data_file);
190
    /* if we cannot contact the socket, defer the mail */
181
      return retval;
191
    (void)fclose(data_file);
192
    return retval;
182
    }
193
    }
183
  }
194
  }
184
  else {
195
else
185
    /* connecting to the dccifd UNIX socket */
196
  {
186
    bzero(&serv_addr, sizeof(serv_addr));
197
  /* connecting to the dccifd UNIX socket */
187
    serv_addr.sun_family = AF_UNIX;
198
  bzero(&serv_addr, sizeof(serv_addr));
188
    Ustrncpy(US serv_addr.sun_path, sockpath, sizeof(serv_addr.sun_path));
199
  serv_addr.sun_family = AF_UNIX;
189
    if ((sockfd = socket(AF_UNIX, SOCK_STREAM,0)) < 0) {
200
  Ustrncpy(US serv_addr.sun_path, sockpath, sizeof(serv_addr.sun_path));
190
      DEBUG(D_acl)
201
  if ((sockfd = socket(AF_UNIX, SOCK_STREAM,0)) < 0)
191
        debug_printf("DCC: Creating UNIX socket connection failed: %s\n", strerror(errno));
202
    {
192
      log_write(0,LOG_PANIC,"DCC: Creating UNIX socket connection failed: %s\n", strerror(errno));
203
    DEBUG(D_acl)
193
      /* if we cannot create the socket, defer the mail */
204
      debug_printf("DCC: Creating UNIX socket connection failed: %s\n", strerror(errno));
194
      (void)fclose(data_file);
205
    log_write(0,LOG_PANIC,"DCC: Creating UNIX socket connection failed: %s\n", strerror(errno));
195
      return retval;
206
    /* if we cannot create the socket, defer the mail */
207
    (void)fclose(data_file);
208
    return retval;
196
    }
209
    }
197
    /* Now connecting the socket (UNIX) */
210
  /* Now connecting the socket (UNIX) */
198
    if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
211
  if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
199
      DEBUG(D_acl)
212
    {
200
        debug_printf("DCC: Connecting to UNIX socket failed: %s\n", strerror(errno));
213
    DEBUG(D_acl)
201
      log_write(0,LOG_PANIC,"DCC: Connecting to UNIX socket failed: %s\n", strerror(errno));
214
      debug_printf("DCC: Connecting to UNIX socket failed: %s\n", strerror(errno));
202
      /* if we cannot contact the socket, defer the mail */
215
    log_write(0,LOG_PANIC,"DCC: Connecting to UNIX socket failed: %s\n", strerror(errno));
203
      (void)fclose(data_file);
216
    /* if we cannot contact the socket, defer the mail */
204
      return retval;
217
    (void)fclose(data_file);
218
    return retval;
205
    }
219
    }
206
  }
220
  }
207
  /* the socket is open, now send the options to dccifd*/
221
/* the socket is open, now send the options to dccifd*/
222
DEBUG(D_acl)
223
  debug_printf("DCC: -----------------------------------\nDCC: Socket opened; now sending input\n"
224
	       "DCC: -----------------------------------\n");
225
226
/* let's send each of the recipients to dccifd */
227
for (int i = 0; i < recipients_count; i++)
228
  {
208
  DEBUG(D_acl)
229
  DEBUG(D_acl)
209
    debug_printf("DCC: -----------------------------------\nDCC: Socket opened; now sending input\n"
230
    debug_printf("DCC: recipient = %s\n",recipients_list[i].address);
210
                 "DCC: -----------------------------------\n");
231
  dcc_headers = string_append(dcc_headers, 2, recipients_list[i].address, "\n");
211
212
  /* let's send each of the recipients to dccifd */
213
  for (int i = 0; i < recipients_count; i++) {
214
    DEBUG(D_acl)
215
      debug_printf("DCC: recipient = %s\n",recipients_list[i].address);
216
    dcc_headers = string_append(dcc_headers, 2, recipients_list[i].address, "\n");
217
  }
232
  }
218
  /* send a blank line between options and message */
233
/* send a blank line between options and message */
219
  dcc_headers = string_catn(dcc_headers, US"\n", 1);
234
dcc_headers = string_catn(dcc_headers, US"\n", 1);
220
  /* Now we send the input buffer */
235
/* Now we send the input buffer */
221
  (void) string_from_gstring(dcc_headers);
236
(void) string_from_gstring(dcc_headers);
222
  DEBUG(D_acl)
237
DEBUG(D_acl)
223
    debug_printf("DCC: ***********************************\nDCC: Sending options:\n%s"
238
  debug_printf("DCC: ***********************************\nDCC: Sending options:\n%s"
224
                 "DCC: ***********************************\n", dcc_headers->s);
239
	       "DCC: ***********************************\n", dcc_headers->s);
225
  if (flushbuffer(sockfd, dcc_headers) != 0) {
240
if (flushbuffer(sockfd, dcc_headers) != 0)
226
      (void)fclose(data_file);
241
  {
227
      return retval;
242
  (void)fclose(data_file);
243
  return retval;
228
  }
244
  }
229
245
230
  /* now send the message */
246
/* now send the message */
231
  /* First send the headers */
247
/* First send the headers */
232
  DEBUG(D_acl)
248
DEBUG(D_acl)
233
    debug_printf("DCC: ***********************************\nDCC: Sending headers:\n");
249
  debug_printf("DCC: ***********************************\nDCC: Sending headers:\n");
234
  sendbuf = string_get(8192);
250
sendbuf = string_get(8192);
251
sendbuf = string_catn(sendbuf, mail_headers->text, mail_headers->slen);
252
while((mail_headers=mail_headers->next))
235
  sendbuf = string_catn(sendbuf, mail_headers->text, mail_headers->slen);
253
  sendbuf = string_catn(sendbuf, mail_headers->text, mail_headers->slen);
236
  while((mail_headers=mail_headers->next)) {
237
    sendbuf = string_catn(sendbuf, mail_headers->text, mail_headers->slen);
238
  }
239
254
240
  /* a blank line separates header from body */
255
/* a blank line separates header from body */
241
  sendbuf = string_catn(sendbuf, US"\r\n", 2);
256
sendbuf = string_catn(sendbuf, US"\r\n", 2);
242
  (void) string_from_gstring(sendbuf);
257
(void) string_from_gstring(sendbuf);
243
  gstring_release_unused(sendbuf);
258
gstring_release_unused(sendbuf);
244
  DEBUG(D_acl)
259
DEBUG(D_acl)
245
    debug_printf("%sDCC: ***********************************\n", sendbuf->s);
260
  debug_printf("%sDCC: ***********************************\n", sendbuf->s);
246
  if (flushbuffer(sockfd, sendbuf) != 0) {
261
if (flushbuffer(sockfd, sendbuf) != 0)
247
      (void)fclose(data_file);
262
  {
248
      return retval;
263
  (void)fclose(data_file);
264
  return retval;
249
  }
265
  }
250
266
251
  /* now send the body */
267
/* now send the body */
252
  DEBUG(D_acl)
268
DEBUG(D_acl)
253
    debug_printf("DCC: ***********************************\nDCC: Writing body:\n");
269
  debug_printf("DCC: ***********************************\nDCC: Writing body:\n");
254
  (void)fseek(data_file, SPOOL_DATA_START_OFFSET, SEEK_SET);
270
(void)fseek(data_file, SPOOL_DATA_START_OFFSET, SEEK_SET);
255
271
256
  gstring filebuf = { .size = big_buffer_size, .ptr = 0, .s = big_buffer };
272
gstring filebuf = { .size = big_buffer_size, .ptr = 0, .s = big_buffer };
257
273
258
  while((filebuf.ptr = fread(filebuf.s, 1, filebuf.size, data_file)) > 0) {
274
while((filebuf.ptr = fread(filebuf.s, 1, filebuf.size, data_file)) > 0)
259
    if (flushbuffer(sockfd, &filebuf) != 0) {
275
  if (flushbuffer(sockfd, &filebuf) != 0)
260
        (void)fclose(data_file);
276
    {
261
        return retval;
277
    (void)fclose(data_file);
278
    return retval;
262
    }
279
    }
263
  }
280
DEBUG(D_acl)
264
  DEBUG(D_acl)
281
  debug_printf("DCC: ***********************************\n");
265
    debug_printf("DCC: ***********************************\n");
266
282
267
  /* shutdown() the socket */
283
/* shutdown() the socket */
268
  if(shutdown(sockfd, SHUT_WR) < 0) {
284
if(shutdown(sockfd, SHUT_WR) < 0)
285
  {
286
  DEBUG(D_acl)
287
    debug_printf("DCC: Couldn't shutdown socket: %s\n", strerror(errno));
288
  log_write(0,LOG_MAIN,"DCC: Couldn't shutdown socket: %s\n", strerror(errno));
289
  /* If there is a problem with the shutdown()
290
   * defer the mail. */
291
  (void)fclose(data_file);
292
  return retval;
293
  }
294
DEBUG(D_acl)
295
  debug_printf("DCC: Input sent.\n"
296
	       "DCC: +++++++++++++++++++++++++++++++++++\n"
297
	       "DCC: Now receiving output from server\n"
298
	       "DCC: -----------------------------------\n");
299
300
/********************************
301
 * receiving output from dccifd *
302
 ********************************/
303
304
/******************************************************************
305
 * We should get 3 lines:                                         *
306
 * 1/ First line is overall result: either 'A' for Accept,        *
307
 *    'R' for Reject, 'S' for accept Some recipients or           *
308
 *    'T' for a Temporary error.                                  *
309
 * 2/ Second line contains the list of Accepted/Rejected          *
310
 *    recipients in the form AARRA (A = accepted, R = rejected).  *
311
 * 3/ Third line contains the X-DCC header.                       *
312
 ******************************************************************/
313
314
int line = 1;    /* we start at the first line of the output */
315
int bufoffset;
316
317
dcc_header_str = string_get(DCC_HEADER_LIMIT + 2);
318
/* Let's read from the socket until there's nothing left to read */
319
while((dcc_resplen = read(sockfd, big_buffer, big_buffer_size-1)) > 0)
320
  {
321
  /* fail on read error */
322
  if(dcc_resplen < 0)
323
    {
269
    DEBUG(D_acl)
324
    DEBUG(D_acl)
270
      debug_printf("DCC: Couldn't shutdown socket: %s\n", strerror(errno));
325
      debug_printf("DCC: Error reading from socket: %s\n", strerror(errno));
271
    log_write(0,LOG_MAIN,"DCC: Couldn't shutdown socket: %s\n", strerror(errno));
272
    /* If there is a problem with the shutdown()
273
     * defer the mail. */
274
    (void)fclose(data_file);
326
    (void)fclose(data_file);
275
    return retval;
327
    return retval;
276
  }
277
  DEBUG(D_acl)
278
    debug_printf("DCC: Input sent.\n"
279
                 "DCC: +++++++++++++++++++++++++++++++++++\n"
280
                 "DCC: Now receiving output from server\n"
281
                 "DCC: -----------------------------------\n");
282
283
  /********************************
284
   * receiving output from dccifd *
285
   ********************************/
286
287
  /******************************************************************
288
   * We should get 3 lines:                                         *
289
   * 1/ First line is overall result: either 'A' for Accept,        *
290
   *    'R' for Reject, 'S' for accept Some recipients or           *
291
   *    'T' for a Temporary error.                                  *
292
   * 2/ Second line contains the list of Accepted/Rejected          *
293
   *    recipients in the form AARRA (A = accepted, R = rejected).  *
294
   * 3/ Third line contains the X-DCC header.                       *
295
   ******************************************************************/
296
297
  int line = 1;    /* we start at the first line of the output */
298
  int bufoffset;
299
300
  dcc_header_str = string_get(DCC_HEADER_LIMIT + 2);
301
  /* Let's read from the socket until there's nothing left to read */
302
  while((dcc_resplen = read(sockfd, big_buffer, big_buffer_size-1)) > 0) {
303
    /* fail on read error */
304
    if(dcc_resplen < 0) {
305
      DEBUG(D_acl)
306
        debug_printf("DCC: Error reading from socket: %s\n", strerror(errno));
307
      (void)fclose(data_file);
308
      return retval;
309
    }
328
    }
310
    /* make the answer 0-terminated. only needed for debug_printf */
329
  /* make the answer 0-terminated. only needed for debug_printf */
311
    DEBUG(D_acl)
330
  DEBUG(D_acl)
312
      debug_printf("DCC: Length of the output buffer is: %d\nDCC: Output buffer is:\n"
331
    debug_printf("DCC: Length of the output buffer is: %d\nDCC: Output buffer is:\n"
313
                   "DCC: -----------------------------------\n%.*s\n"
332
		 "DCC: -----------------------------------\n%.*s\n"
314
                   "DCC: -----------------------------------\n", dcc_resplen, dcc_resplen, big_buffer);
333
		 "DCC: -----------------------------------\n", dcc_resplen, dcc_resplen, big_buffer);
315
334
316
    /* Now let's read each character and see what we've got */
335
  /* Now let's read each character and see what we've got */
317
    for(bufoffset = 0; bufoffset < dcc_resplen, line <= 2; bufoffset++) {
336
  for(bufoffset = 0; bufoffset < dcc_resplen && line <= 2; bufoffset++)
318
      /* First check if we reached the end of the line and
337
    {
319
       * then increment the line counter */
338
    /* First check if we reached the end of the line and
320
      if(big_buffer[bufoffset] == '\n')
339
    then increment the line counter */
321
        line++;
340
    if(big_buffer[bufoffset] == '\n')
322
      else {
341
      line++;
323
        /* The first character of the first line is the
342
    else
324
         * overall response. If there's another character
343
      {
325
         * on that line it is not correct. */
344
      /* The first character of the first line is the overall response. If
326
        if(line == 1) {
345
      there's another character on that line it is not correct. */
327
          if(bufoffset == 0) {
346
      if(line == 1)
328
            /* Now get the value and set the
347
	{
329
             * return value accordingly */
348
	if(bufoffset == 0)
330
            switch(big_buffer[bufoffset]) {
349
	  {
331
              case 'A':
350
	  /* Now get the value and set the return value accordingly */
332
                DEBUG(D_acl)
351
	  switch (big_buffer[bufoffset])
333
                  debug_printf("DCC: Overall result = A\treturning OK\n");
352
	    {
334
                dcc_return_text = US"Mail accepted by DCC";
353
	    case 'A':
335
                dcc_result = US"A";
354
	      DEBUG(D_acl)
336
                retval = OK;
355
		debug_printf("DCC: Overall result = A\treturning OK\n");
337
                break;
356
	      dcc_return_text = US"Mail accepted by DCC";
338
              case 'R':
357
	      dcc_result = US"A";
339
                DEBUG(D_acl)
358
	      retval = OK;
340
                  debug_printf("DCC: Overall result = R\treturning FAIL\n");
359
	      break;
341
                dcc_return_text = US"Rejected by DCC";
360
	    case 'R':
342
                dcc_result = US"R";
361
	      DEBUG(D_acl)
343
                retval = FAIL;
362
		debug_printf("DCC: Overall result = R\treturning FAIL\n");
344
                if(sender_host_name)
363
	      dcc_return_text = US"Rejected by DCC";
345
                  log_write(0, LOG_MAIN, "H=%s [%s] F=<%s>: rejected by DCC",
364
	      dcc_result = US"R";
346
                             sender_host_name, sender_host_address, sender_address);
365
	      retval = FAIL;
347
                else
366
	      if(sender_host_name)
348
                  log_write(0, LOG_MAIN, "H=[%s] F=<%s>: rejected by DCC",
367
		log_write(0, LOG_MAIN, "H=%s [%s] F=<%s>: rejected by DCC",
349
                             sender_host_address, sender_address);
368
			   sender_host_name, sender_host_address, sender_address);
350
                break;
369
	      else
351
              case 'S':
370
		log_write(0, LOG_MAIN, "H=[%s] F=<%s>: rejected by DCC",
352
                DEBUG(D_acl)
371
			   sender_host_address, sender_address);
353
                  debug_printf("DCC: Overall result  = S\treturning OK\n");
372
	      break;
354
                dcc_return_text = US"Not all recipients accepted by DCC";
373
	    case 'S':
355
                /* Since we're in an ACL we want a global result
374
	      DEBUG(D_acl)
356
                 * so we accept for all */
375
		debug_printf("DCC: Overall result  = S\treturning OK\n");
357
                dcc_result = US"A";
376
	      dcc_return_text = US"Not all recipients accepted by DCC";
358
                retval = OK;
377
	      /* Since we're in an ACL we want a global result so we accept for all */
359
                break;
378
	      dcc_result = US"A";
360
              case 'G':
379
	      retval = OK;
361
                DEBUG(D_acl)
380
	      break;
362
                  debug_printf("DCC: Overall result  = G\treturning FAIL\n");
381
	    case 'G':
363
                dcc_return_text = US"Greylisted by DCC";
382
	      DEBUG(D_acl)
364
                dcc_result = US"G";
383
		debug_printf("DCC: Overall result  = G\treturning FAIL\n");
365
                retval = FAIL;
384
	      dcc_return_text = US"Greylisted by DCC";
366
                break;
385
	      dcc_result = US"G";
367
              case 'T':
386
	      retval = FAIL;
368
                DEBUG(D_acl)
387
	      break;
369
                  debug_printf("DCC: Overall result = T\treturning DEFER\n");
388
	    case 'T':
370
                dcc_return_text = US"Temporary error with DCC";
389
	      DEBUG(D_acl)
371
                dcc_result = US"T";
390
		debug_printf("DCC: Overall result = T\treturning DEFER\n");
372
                retval = DEFER;
391
	      dcc_return_text = US"Temporary error with DCC";
373
                log_write(0,LOG_MAIN,"Temporary error with DCC: %s\n", big_buffer);
392
	      dcc_result = US"T";
374
                break;
393
	      retval = DEFER;
375
              default:
394
	      log_write(0,LOG_MAIN,"Temporary error with DCC: %s\n", big_buffer);
376
                DEBUG(D_acl)
395
	      break;
377
                  debug_printf("DCC: Overall result = something else\treturning DEFER\n");
396
	    default:
378
		dcc_return_text = US"Unknown DCC response";
397
	      DEBUG(D_acl)
379
                dcc_result = US"T";
398
		debug_printf("DCC: Overall result = something else\treturning DEFER\n");
380
                retval = DEFER;
399
	      dcc_return_text = US"Unknown DCC response";
381
                log_write(0,LOG_MAIN,"Unknown DCC response: %s\n", big_buffer);
400
	      dcc_result = US"T";
382
                break;
401
	      retval = DEFER;
383
            }
402
	      log_write(0,LOG_MAIN,"Unknown DCC response: %s\n", big_buffer);
384
          }
403
	      break;
385
          else {
404
	    }
386
            /* We're on the first line but not on the first character,
405
	}
387
             * there must be something wrong. */
406
	else
388
            DEBUG(D_acl) debug_printf("DCC: Line = %d but bufoffset = %d != 0"
407
	  {
389
		"  character is %c - This is wrong!\n", line, bufoffset, big_buffer[bufoffset]);
408
	  /* We're on the first line but not on the first character,
390
            log_write(0,LOG_MAIN,"Wrong header from DCC, output is %s\n", big_buffer);
409
	   * there must be something wrong. */
391
          }
410
	  DEBUG(D_acl) debug_printf("DCC: Line = %d but bufoffset = %d != 0"
392
        }
411
	      "  character is %c - This is wrong!\n", line, bufoffset, big_buffer[bufoffset]);
393
        else if(line == 2) {
412
	  log_write(0,LOG_MAIN,"Wrong header from DCC, output is %s\n", big_buffer);
394
          /* On the second line we get a list of
413
	  }
395
           * answers for each recipient. We don't care about
414
	}
396
           * it because we're in an acl and take the
415
      else if(line == 2)
397
           * global result. */
416
	{
398
        }
417
	/* On the second line we get a list of answers for each recipient. We
418
	don't care about it because we're in an acl and take the global result. */
419
	}
399
      }
420
      }
400
    }
421
    }
401
    if(line > 2) {
422
  if(line > 2)
402
      /* The third and following lines are the X-DCC header,
423
    {
403
       * so we store it in dcc_header_str up to our limit. */
424
    /* The third and following lines are the X-DCC header, so we store it in
404
      /* check if buffer contains the end of the header .."\n\n" and truncate it */
425
    dcc_header_str up to our limit. */
405
      if ((big_buffer[dcc_resplen-1] == '\n') &&
426
    /* check if buffer contains the end of the header .."\n\n" and truncate it */
406
          (big_buffer[dcc_resplen-2] == '\n'))
427
    if ((big_buffer[dcc_resplen-1] == '\n') &&
407
        dcc_resplen -= 2;
428
	(big_buffer[dcc_resplen-2] == '\n'))
408
      dcc_resplen -= bufoffset;
429
      dcc_resplen -= 2;
409
      if (dcc_header_str->ptr + dcc_resplen > DCC_HEADER_LIMIT) {
430
    dcc_resplen -= bufoffset;
410
        dcc_resplen = DCC_HEADER_LIMIT - dcc_header_str->ptr;
431
    if (dcc_header_str->ptr + dcc_resplen > DCC_HEADER_LIMIT)
411
        DEBUG(D_acl) debug_printf("DCC: We got more output than we can store"
432
      {
412
	                   "in the X-DCC header. Truncating at 120 characters.\n");
433
      dcc_resplen = DCC_HEADER_LIMIT - dcc_header_str->ptr;
434
      DEBUG(D_acl) debug_printf("DCC: We got more output than we can store"
435
			 "in the X-DCC header. Truncating at 120 characters.\n");
413
      }
436
      }
414
      dcc_header_str = string_catn(dcc_header_str, &big_buffer[bufoffset], dcc_resplen);
437
    dcc_header_str = string_catn(dcc_header_str, &big_buffer[bufoffset], dcc_resplen);
415
    }
438
    }
416
  }
439
  }
417
  /* We have read everything from the socket. make sure the header ends with "\n" */
440
/* We have read everything from the socket. make sure the header ends with "\n" */
418
  dcc_header_str = string_catn(dcc_header_str, US"\n", 1);
441
dcc_header_str = string_catn(dcc_header_str, US"\n", 1);
419
442
420
  (void) string_from_gstring(dcc_header_str);
443
(void) string_from_gstring(dcc_header_str);
421
  /* Now let's sum up what we've got. */
444
/* Now let's sum up what we've got. */
422
  DEBUG(D_acl)
445
DEBUG(D_acl)
423
    debug_printf("\nDCC: --------------------------\nDCC: Overall result = %d\n"
446
  debug_printf("\nDCC: --------------------------\nDCC: Overall result = %d\n"
424
                 "DCC: X-DCC header: %sReturn message: %s\nDCC: dcc_result: %s\n",
447
	       "DCC: X-DCC header: %sReturn message: %s\nDCC: dcc_result: %s\n",
425
                   retval, dcc_header_str->s, dcc_return_text, dcc_result);
448
		 retval, dcc_header_str->s, dcc_return_text, dcc_result);
426
449
427
  /* We only add the X-DCC header if it starts with X-DCC */
450
/* We only add the X-DCC header if it starts with X-DCC */
428
  if(!(Ustrncmp(dcc_header_str->s, "X-DCC", 5))) {
451
if(!(Ustrncmp(dcc_header_str->s, "X-DCC", 5)))
429
    dcc_header = dcc_header_str->s;
452
  {
430
    if(dcc_direct_add_header) {
453
  dcc_header = dcc_header_str->s;
431
      header_add(' ' , "%s", dcc_header_str->s);
454
  if(dcc_direct_add_header)
432
  /* since the MIME ACL already writes the .eml file to disk without DCC Header we've to erase it */
455
    {
433
      unspool_mbox();
456
    header_add(' ' , "%s", dcc_header_str->s);
457
/* since the MIME ACL already writes the .eml file to disk without DCC Header we've to erase it */
458
    unspool_mbox();
434
    }
459
    }
435
  }
460
  }
436
  else {
461
else
437
    DEBUG(D_acl)
462
  DEBUG(D_acl)
438
      debug_printf("DCC: Wrong format of the X-DCC header: %.*s\n", dcc_header_str->ptr, dcc_header_str->s);
463
    debug_printf("DCC: Wrong format of the X-DCC header: %.*s\n", dcc_header_str->ptr, dcc_header_str->s);
439
  }
440
464
441
  /* check if we should add additional headers passed in acl_m_dcc_add_header */
465
/* check if we should add additional headers passed in acl_m_dcc_add_header */
442
  if(dcc_direct_add_header) {
466
if (dcc_direct_add_header)
443
    if (((xtra_hdrs = expand_string(US"$acl_m_dcc_add_header")) != NULL) && (xtra_hdrs[0] != '\0')) {
467
  {
444
      dcc_xtra_hdrs = string_cat(NULL, xtra_hdrs);
468
  if (((xtra_hdrs = expand_string(US"$acl_m_dcc_add_header")) != NULL) && (xtra_hdrs[0] != '\0'))
445
      if (dcc_xtra_hdrs->s[dcc_xtra_hdrs->ptr - 1] != '\n')
469
    {
446
        dcc_xtra_hdrs = string_catn(dcc_xtra_hdrs, US"\n", 1);
470
    dcc_xtra_hdrs = string_cat(NULL, xtra_hdrs);
447
      header_add(' ', "%s", string_from_gstring(dcc_xtra_hdrs));
471
    if (dcc_xtra_hdrs->s[dcc_xtra_hdrs->ptr - 1] != '\n')
448
      DEBUG(D_acl)
472
      dcc_xtra_hdrs = string_catn(dcc_xtra_hdrs, US"\n", 1);
449
        debug_printf("DCC: adding additional headers in $acl_m_dcc_add_header: %.*s", dcc_xtra_hdrs->ptr, dcc_xtra_hdrs->s);
473
    header_add(' ', "%s", string_from_gstring(dcc_xtra_hdrs));
474
    DEBUG(D_acl)
475
      debug_printf("DCC: adding additional headers in $acl_m_dcc_add_header: %.*s", dcc_xtra_hdrs->ptr, dcc_xtra_hdrs->s);
450
    }
476
    }
451
  }
477
  }
452
478
453
  dcc_ok = 1;
479
dcc_ok = 1;
454
  /* Now return to exim main process */
480
/* Now return to exim main process */
455
  DEBUG(D_acl)
481
DEBUG(D_acl)
456
    debug_printf("DCC: Before returning to exim main process:\nDCC: return_text = %s - retval = %d\n"
482
  debug_printf("DCC: Before returning to exim main process:\nDCC: return_text = %s - retval = %d\n"
457
                 "DCC: dcc_result = %s\n", dcc_return_text, retval, dcc_result);
483
	       "DCC: dcc_result = %s\n", dcc_return_text, retval, dcc_result);
458
484
459
  (void)fclose(data_file);
485
(void)fclose(data_file);
460
  dcc_rc = retval;
486
dcc_rc = retval;
461
  return dcc_rc;
487
return dcc_rc;
462
}
488
}
463
489
464
#endif
490
#endif
(-)exim.orig/src/debug.c (-15 / +102 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2015 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 12-17 Link Here
12
static uschar *debug_ptr = debug_buffer;
13
static uschar *debug_ptr = debug_buffer;
13
static int     debug_prefix_length = 0;
14
static int     debug_prefix_length = 0;
14
15
16
static unsigned pretrigger_writeoff;
17
static unsigned pretrigger_readoff;
15
18
16
19
17
const uschar * rc_names[] = {		/* Mostly for debug output */
20
const uschar * rc_names[] = {		/* Mostly for debug output */
Lines 52-59 Link Here
52
moves down the page. This function is used only in debugging circumstances. The
55
moves down the page. This function is used only in debugging circumstances. The
53
output is done via debug_printf(). */
56
output is done via debug_printf(). */
54
57
55
#define tree_printlinesize 132   /* line size for printing */
58
#define TREE_PRINTLINESIZE 132   /* line size for printing */
56
static uschar tree_printline[tree_printlinesize];
59
static uschar tree_printline[TREE_PRINTLINESIZE];
57
60
58
/* Internal recursive subroutine.
61
/* Internal recursive subroutine.
59
62
Lines 66-77 Link Here
66
*/
69
*/
67
70
68
static void
71
static void
69
tree_printsub(tree_node *p, int pos, int barswitch)
72
tree_printsub(tree_node * p, int pos, int barswitch)
70
{
73
{
71
if (p->right) tree_printsub(p->right, pos+2, 1);
74
if (p->right) tree_printsub(p->right, pos+2, 1);
72
for (int i = 0; i <= pos-1; i++) debug_printf("%c", tree_printline[i]);
75
for (int i = 0; i <= pos-1; i++) debug_printf_indent(" %c", tree_printline[i]);
73
debug_printf("-->%s [%d]\n", p->name, p->balance);
76
debug_printf_indent(" -->%s [%d]\n", p->name, p->balance);
74
tree_printline[pos] = barswitch? '|' : ' ';
77
tree_printline[pos] = barswitch ? '|' : ' ';
75
if (p->left)
78
if (p->left)
76
  {
79
  {
77
  tree_printline[pos+2] = '|';
80
  tree_printline[pos+2] = '|';
Lines 82-92 Link Here
82
/* The external function, with just a tree node argument. */
85
/* The external function, with just a tree node argument. */
83
86
84
void
87
void
85
debug_print_tree(tree_node *p)
88
debug_print_tree(const char * title, tree_node * p)
86
{
89
{
87
for (int i = 0; i < tree_printlinesize; i++) tree_printline[i] = ' ';
90
debug_printf_indent("%s:\n", title);
88
if (!p) debug_printf("Empty Tree\n"); else tree_printsub(p, 0, 0);
91
for (int i = 0; i < TREE_PRINTLINESIZE; i++) tree_printline[i] = ' ';
89
debug_printf("---- End of tree ----\n");
92
if (!p) debug_printf_indent(" Empty Tree\n"); else tree_printsub(p, 0, 0);
93
debug_printf_indent("---- End of tree ----\n");
90
}
94
}
91
95
92
96
Lines 316-323 Link Here
316
      }
320
      }
317
    }
321
    }
318
322
319
  fprintf(debug_file, "%s", CS debug_buffer);
323
  if (debug_pretrigger_buf)
320
  fflush(debug_file);
324
    {
325
    int needed = Ustrlen(debug_buffer)+1, avail;
326
    char c;
327
328
    if (needed > debug_pretrigger_bsize)
329
      needed = debug_pretrigger_bsize;
330
    if ((avail = pretrigger_readoff - pretrigger_writeoff) <= 0)
331
      avail += debug_pretrigger_bsize;
332
333
    /* We have a pretrigger set up, trigger not yet hit. Copy the line(s) to the
334
    pretrig buffer, dropping earlier lines if needed but truncating this line if
335
    the pbuf is maxed out.  In the PTB the lines are NOT nul-terminated. */
336
337
    while (avail < needed)
338
      do
339
	{
340
	avail++;
341
        c = debug_pretrigger_buf[pretrigger_readoff];
342
	if (++pretrigger_readoff >= debug_pretrigger_bsize) pretrigger_readoff = 0;
343
	}
344
      while (c && c != '\n' && pretrigger_readoff != pretrigger_writeoff);
345
346
    needed--;
347
    for (int i = 0; needed; i++, needed--)
348
      {
349
      debug_pretrigger_buf[pretrigger_writeoff] = debug_buffer[i];
350
      if (++pretrigger_writeoff >= debug_pretrigger_bsize) pretrigger_writeoff = 0;
351
      }
352
    }
353
  else
354
    {
355
    fprintf(debug_file, "%s", CS debug_buffer);
356
    fflush(debug_file);
357
    }
321
  debug_ptr = debug_buffer;
358
  debug_ptr = debug_buffer;
322
  debug_prefix_length = 0;
359
  debug_prefix_length = 0;
323
  }
360
  }
Lines 351-357 Link Here
351
	g = string_fmt_append(g, " lcl [%s]:%u",
388
	g = string_fmt_append(g, " lcl [%s]:%u",
352
	  inet_ntoa(sinp->sin_addr), ntohs(sinp->sin_port));
389
	  inet_ntoa(sinp->sin_addr), ntohs(sinp->sin_port));
353
	alen = sizeof(*sinp);
390
	alen = sizeof(*sinp);
354
	if (getpeername(fd, sinp, &alen) == 0)
391
	if (getpeername(fd, (struct sockaddr *)sinp, &alen) == 0)
355
	  g = string_fmt_append(g, " rmt [%s]:%u",
392
	  g = string_fmt_append(g, " rmt [%s]:%u",
356
	    inet_ntoa(sinp->sin_addr), ntohs(sinp->sin_port));
393
	    inet_ntoa(sinp->sin_addr), ntohs(sinp->sin_port));
357
	break;
394
	break;
Lines 363-369 Link Here
363
	  inet_ntop(AF_INET6, &sin6p->sin6_addr, CS buf, sizeof(buf)),
400
	  inet_ntop(AF_INET6, &sin6p->sin6_addr, CS buf, sizeof(buf)),
364
	  ntohs(sin6p->sin6_port));
401
	  ntohs(sin6p->sin6_port));
365
	alen = sizeof(*sin6p);
402
	alen = sizeof(*sin6p);
366
	if (getpeername(fd, sin6p, &alen) == 0)
403
	if (getpeername(fd, (struct sockaddr *)sin6p, &alen) == 0)
367
	  g = string_fmt_append(g, " rmt [%s]:%u",
404
	  g = string_fmt_append(g, " rmt [%s]:%u",
368
	    inet_ntop(AF_INET6, &sin6p->sin6_addr, CS buf, sizeof(buf)),
405
	    inet_ntop(AF_INET6, &sin6p->sin6_addr, CS buf, sizeof(buf)),
369
	    ntohs(sin6p->sin6_port));
406
	    ntohs(sin6p->sin6_port));
Lines 376-382 Link Here
376
            sunp->sun_path[0] ? US"" : US"@",
413
            sunp->sun_path[0] ? US"" : US"@",
377
            sunp->sun_path[0] ? sunp->sun_path : sunp->sun_path+1);
414
            sunp->sun_path[0] ? sunp->sun_path : sunp->sun_path+1);
378
        alen = sizeof(*sunp);
415
        alen = sizeof(*sunp);
379
        if (getpeername(fd, sunp, &alen) == 0)
416
        if (getpeername(fd, (struct sockaddr *)sunp, &alen) == 0)
380
          g = string_fmt_append(g, " rmt %s%s",
417
          g = string_fmt_append(g, " rmt %s%s",
381
            sunp->sun_path[0] ? US"" : US"@",
418
            sunp->sun_path[0] ? US"" : US"@",
382
            sunp->sun_path[0] ? sunp->sun_path : sunp->sun_path+1);
419
            sunp->sun_path[0] ? sunp->sun_path : sunp->sun_path+1);
Lines 408-411 Link Here
408
}
445
}
409
446
410
447
448
/**************************************************************/
449
/* Pretrigger handling for debug.  The debug_printf implementation
450
diverts output to a circular buffer if the buffer is set up.
451
The routines here set up the buffer, and unload it to file (and release it).
452
What ends up in the buffer is subject to the usual debug_selector. */
453
454
void
455
debug_pretrigger_setup(const uschar * size_string)
456
{
457
long size = Ustrtol(size_string, NULL, 0);
458
if (size > 0)
459
  {
460
  unsigned bufsize = MIN(size, 16384);
461
462
  dtrigger_selector |= BIT(DTi_pretrigger);
463
  if (debug_pretrigger_buf) store_free(debug_pretrigger_buf);
464
  debug_pretrigger_buf = store_malloc((size_t)(debug_pretrigger_bsize = bufsize));
465
  pretrigger_readoff = pretrigger_writeoff = 0;
466
  }
467
}
468
469
void
470
debug_trigger_fire(void)
471
{
472
int nbytes;
473
474
if (!debug_pretrigger_buf) return;
475
476
if (debug_file && (nbytes = pretrigger_writeoff - pretrigger_readoff) != 0)
477
  if (nbytes > 0)
478
    fwrite(debug_pretrigger_buf + pretrigger_readoff, 1, nbytes, debug_file);
479
  else
480
    {
481
    fwrite(debug_pretrigger_buf + pretrigger_readoff, 1,
482
      debug_pretrigger_bsize - pretrigger_readoff, debug_file);
483
    fwrite(debug_pretrigger_buf, 1, pretrigger_writeoff, debug_file);
484
    }
485
486
debug_pretrigger_discard();
487
}
488
489
void
490
debug_pretrigger_discard(void)
491
{
492
if (debug_pretrigger_buf) store_free(debug_pretrigger_buf);
493
debug_pretrigger_buf = NULL;
494
dtrigger_selector = 0;
495
}
496
497
411
/* End of debug.c */
498
/* End of debug.c */
(-)exim.orig/src/deliver.c (-195 / +159 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* The main code for delivering a message. */
9
/* The main code for delivering a message. */
Lines 74-79 Link Here
74
static BOOL remove_journal;
74
static BOOL remove_journal;
75
static int  parcount = 0;
75
static int  parcount = 0;
76
static pardata *parlist = NULL;
76
static pardata *parlist = NULL;
77
static struct pollfd *parpoll;
77
static int  return_count;
78
static int  return_count;
78
static uschar *frozen_info = US"";
79
static uschar *frozen_info = US"";
79
static uschar *used_return_path = NULL;
80
static uschar *used_return_path = NULL;
Lines 145-151 Link Here
145
address_item *
146
address_item *
146
deliver_make_addr(uschar *address, BOOL copy)
147
deliver_make_addr(uschar *address, BOOL copy)
147
{
148
{
148
address_item *addr = store_get(sizeof(address_item), FALSE);
149
address_item * addr = store_get(sizeof(address_item), GET_UNTAINTED);
149
*addr = address_defaults;
150
*addr = address_defaults;
150
if (copy) address = string_copy(address);
151
if (copy) address = string_copy(address);
151
addr->address = address;
152
addr->address = address;
Lines 521-528 Link Here
521
  else if (one->port != two->port)
522
  else if (one->port != two->port)
522
    return FALSE;
523
    return FALSE;
523
524
524
  /* Hosts matched */
525
#ifdef SUPPORT_DANE
526
  /* DNSSEC equality */
527
  if (one->dnssec != two->dnssec) return FALSE;
528
#endif
525
529
530
  /* Hosts matched */
526
  one = one->next;
531
  one = one->next;
527
  two = two->next;
532
  two = two->next;
528
  }
533
  }
Lines 792-797 Link Here
792
if (LOGGING(outgoing_port))
797
if (LOGGING(outgoing_port))
793
  g = string_fmt_append(g, ":%d", h->port);
798
  g = string_fmt_append(g, ":%d", h->port);
794
799
800
if (continue_sequence > 1)		/*XXX this is wrong for a dropped proxyconn.  Would have to pass back from transport */
801
  g = string_catn(g, US"*", 1);
802
795
#ifdef SUPPORT_SOCKS
803
#ifdef SUPPORT_SOCKS
796
if (LOGGING(proxy) && proxy_local_address)
804
if (LOGGING(proxy) && proxy_local_address)
797
  {
805
  {
Lines 820-826 Link Here
820
if (LOGGING(tls_cipher) && addr->cipher)
828
if (LOGGING(tls_cipher) && addr->cipher)
821
  {
829
  {
822
  g = string_append(g, 2, US" X=", addr->cipher);
830
  g = string_append(g, 2, US" X=", addr->cipher);
823
#ifdef EXPERIMENTAL_TLS_RESUME
831
#ifndef DISABLE_TLS_RESUME
824
  if (LOGGING(tls_resumption) && testflag(addr, af_tls_resume))
832
  if (LOGGING(tls_resumption) && testflag(addr, af_tls_resume))
825
    g = string_catn(g, US"*", 1);
833
    g = string_catn(g, US"*", 1);
826
#endif
834
#endif
Lines 846-853 Link Here
846
854
847
855
848
#ifndef DISABLE_EVENT
856
#ifndef DISABLE_EVENT
857
/* Distribute a named event to any listeners.
858
859
Args:	action	config option specifying listener
860
	event	name of the event
861
	ev_data	associated data for the event
862
	errnop	pointer to errno for modification, or null
863
864
Return: string expansion from listener, or NULL
865
*/
866
849
uschar *
867
uschar *
850
event_raise(uschar * action, const uschar * event, uschar * ev_data)
868
event_raise(uschar * action, const uschar * event, uschar * ev_data, int * errnop)
851
{
869
{
852
uschar * s;
870
uschar * s;
853
if (action)
871
if (action)
Lines 874-880 Link Here
874
    {
892
    {
875
    DEBUG(D_deliver)
893
    DEBUG(D_deliver)
876
      debug_printf("Event(%s): event_action returned \"%s\"\n", event, s);
894
      debug_printf("Event(%s): event_action returned \"%s\"\n", event, s);
877
    errno = ERRNO_EVENT;
895
    if (errnop)
896
      *errnop = ERRNO_EVENT;
878
    return s;
897
    return s;
879
    }
898
    }
880
  }
899
  }
Lines 903-909 Link Here
903
     a filter was used which triggered a fail command (in such a case
922
     a filter was used which triggered a fail command (in such a case
904
     a transport isn't needed).  Convert it to an internal fail event. */
923
     a transport isn't needed).  Convert it to an internal fail event. */
905
924
906
    (void) event_raise(event_action, US"msg:fail:internal", addr->message);
925
    (void) event_raise(event_action, US"msg:fail:internal", addr->message, NULL);
907
    }
926
    }
908
  }
927
  }
909
else
928
else
Lines 915-921 Link Here
915
	    || Ustrcmp(addr->transport->driver_name, "smtp") == 0
934
	    || Ustrcmp(addr->transport->driver_name, "smtp") == 0
916
	    || Ustrcmp(addr->transport->driver_name, "lmtp") == 0
935
	    || Ustrcmp(addr->transport->driver_name, "lmtp") == 0
917
	    || Ustrcmp(addr->transport->driver_name, "autoreply") == 0
936
	    || Ustrcmp(addr->transport->driver_name, "autoreply") == 0
918
	   ? addr->message : NULL);
937
	   ? addr->message : NULL,
938
	   NULL);
919
  }
939
  }
920
940
921
deliver_host_port =    save_port;
941
deliver_host_port =    save_port;
Lines 933-941 Link Here
933
953
934
954
935
/*************************************************
955
/*************************************************
936
*        Generate local prt for logging          *
956
*        Generate local part for logging         *
937
*************************************************/
957
*************************************************/
938
958
959
static uschar *
960
string_get_lpart_sub(const address_item * addr, uschar * s)
961
{
962
#ifdef SUPPORT_I18N
963
if (testflag(addr, af_utf8_downcvt))
964
  {
965
  uschar * t = string_localpart_utf8_to_alabel(s, NULL);
966
  return t ? t : s;	/* t is NULL on a failed conversion */
967
  }
968
#endif
969
return s;
970
}
971
939
/* This function is a subroutine for use in string_log_address() below.
972
/* This function is a subroutine for use in string_log_address() below.
940
973
941
Arguments:
974
Arguments:
Lines 950-981 Link Here
950
{
983
{
951
uschar * s;
984
uschar * s;
952
985
953
s = addr->prefix;
986
if (testflag(addr, af_include_affixes) && (s = addr->prefix))
954
if (testflag(addr, af_include_affixes) && s)
987
  yield = string_cat(yield, string_get_lpart_sub(addr, s));
955
  {
956
#ifdef SUPPORT_I18N
957
  if (testflag(addr, af_utf8_downcvt))
958
    s = string_localpart_utf8_to_alabel(s, NULL);
959
#endif
960
  yield = string_cat(yield, s);
961
  }
962
988
963
s = addr->local_part;
989
yield = string_cat(yield, string_get_lpart_sub(addr, addr->local_part));
964
#ifdef SUPPORT_I18N
965
if (testflag(addr, af_utf8_downcvt))
966
  s = string_localpart_utf8_to_alabel(s, NULL);
967
#endif
968
yield = string_cat(yield, s);
969
990
970
s = addr->suffix;
991
if (testflag(addr, af_include_affixes) && (s = addr->suffix))
971
if (testflag(addr, af_include_affixes) && s)
992
  yield = string_cat(yield, string_get_lpart_sub(addr, s));
972
  {
973
#ifdef SUPPORT_I18N
974
  if (testflag(addr, af_utf8_downcvt))
975
    s = string_localpart_utf8_to_alabel(s, NULL);
976
#endif
977
  yield = string_cat(yield, s);
978
  }
979
993
980
return yield;
994
return yield;
981
}
995
}
Lines 1128-1134 Link Here
1128
#endif
1142
#endif
1129
1143
1130
reset_point = store_mark();
1144
reset_point = store_mark();
1131
g = string_get_tainted(256, TRUE);	/* addrs will be tainted, so avoid copy */
1145
g = string_get_tainted(256, GET_TAINTED);	/* addrs will be tainted, so avoid copy */
1132
1146
1133
if (msg)
1147
if (msg)
1134
  g = string_append(g, 2, host_and_ident(TRUE), US" ");
1148
  g = string_append(g, 2, host_and_ident(TRUE), US" ");
Lines 1152-1162 Link Here
1152
if (*queue_name)
1166
if (*queue_name)
1153
  g = string_append(g, 2, US" Q=", queue_name);
1167
  g = string_append(g, 2, US" Q=", queue_name);
1154
1168
1155
#ifdef EXPERIMENTAL_SRS
1156
if(addr->prop.srs_sender)
1157
  g = string_append(g, 3, US" SRS=<", addr->prop.srs_sender, US">");
1158
#endif
1159
1160
/* You might think that the return path must always be set for a successful
1169
/* You might think that the return path must always be set for a successful
1161
delivery; indeed, I did for some time, until this statement crashed. The case
1170
delivery; indeed, I did for some time, until this statement crashed. The case
1162
when it is not set is for a delivery to /dev/null which is optimised by not
1171
when it is not set is for a delivery to /dev/null which is optimised by not
Lines 1195-1202 Link Here
1195
  if (addr->host_used)
1204
  if (addr->host_used)
1196
    {
1205
    {
1197
    g = d_hostlog(g, addr);
1206
    g = d_hostlog(g, addr);
1198
    if (continue_sequence > 1)		/*XXX this is wrong for a dropped proxyconn.  Would have to pass back from transport */
1199
      g = string_catn(g, US"*", 1);
1200
1207
1201
#ifndef DISABLE_EVENT
1208
#ifndef DISABLE_EVENT
1202
    deliver_host_address = addr->host_used->address;
1209
    deliver_host_address = addr->host_used->address;
Lines 1268-1275 Link Here
1268
/* Time on queue and actual time taken to deliver */
1275
/* Time on queue and actual time taken to deliver */
1269
1276
1270
if (LOGGING(queue_time))
1277
if (LOGGING(queue_time))
1271
  g = string_append(g, 2, US" QT=",
1278
  g = string_append(g, 2, US" QT=", string_timesince(
1272
    string_timesince(&received_time));
1279
    LOGGING(queue_time_exclusive) ? &received_time_complete : &received_time));
1273
1280
1274
if (LOGGING(deliver_time))
1281
if (LOGGING(deliver_time))
1275
  g = string_append(g, 2, US" DT=", string_timediff(&addr->delivery_time));
1282
  g = string_append(g, 2, US" DT=", string_timediff(&addr->delivery_time));
Lines 1325-1344 Link Here
1325
g = string_fmt_append(g, " defer (%d)", addr->basic_errno);
1332
g = string_fmt_append(g, " defer (%d)", addr->basic_errno);
1326
1333
1327
if (addr->basic_errno > 0)
1334
if (addr->basic_errno > 0)
1328
  g = string_append(g, 2, US": ",
1335
  g = string_append(g, 2, US": ", US strerror(addr->basic_errno));
1329
    US strerror(addr->basic_errno));
1330
1336
1331
if (addr->host_used)
1337
if (addr->host_used)
1332
  {
1338
  g = d_hostlog(g, addr);
1333
  g = string_append(g, 5,
1334
		    US" H=", addr->host_used->name,
1335
		    US" [",  addr->host_used->address, US"]");
1336
  if (LOGGING(outgoing_port))
1337
    {
1338
    int port = addr->host_used->port;
1339
    g = string_fmt_append(g, ":%d", port == PORT_NONE ? 25 : port);
1340
    }
1341
  }
1342
1339
1343
if (LOGGING(deliver_time))
1340
if (LOGGING(deliver_time))
1344
  g = string_append(g, 2, US" DT=", string_timediff(&addr->delivery_time));
1341
  g = string_append(g, 2, US" DT=", string_timediff(&addr->delivery_time));
Lines 1589-1594 Link Here
1589
  (void)close(addr->return_file);
1586
  (void)close(addr->return_file);
1590
  }
1587
  }
1591
1588
1589
/* Check if the transport notifed continue-conn status explicitly, and
1590
update our knowlege. */
1591
1592
if (testflag(addr, af_new_conn))       continue_sequence = 1;
1593
else if (testflag(addr, af_cont_conn)) continue_sequence++;
1594
1592
/* The success case happens only after delivery by a transport. */
1595
/* The success case happens only after delivery by a transport. */
1593
1596
1594
if (result == OK)
1597
if (result == OK)
Lines 2128-2134 Link Here
2128
Returns:     nothing
2131
Returns:     nothing
2129
*/
2132
*/
2130
2133
2131
static void
2134
void
2132
deliver_local(address_item *addr, BOOL shadowing)
2135
deliver_local(address_item *addr, BOOL shadowing)
2133
{
2136
{
2134
BOOL use_initgroups;
2137
BOOL use_initgroups;
Lines 2146-2172 Link Here
2146
2149
2147
if(addr->prop.errors_address)
2150
if(addr->prop.errors_address)
2148
  return_path = addr->prop.errors_address;
2151
  return_path = addr->prop.errors_address;
2149
#ifdef EXPERIMENTAL_SRS
2150
else if (addr->prop.srs_sender)
2151
  return_path = addr->prop.srs_sender;
2152
#endif
2153
else
2152
else
2154
  return_path = sender_address;
2153
  return_path = sender_address;
2155
2154
2156
if (tp->return_path)
2155
if (tp->return_path)
2157
  {
2156
  {
2158
  uschar *new_return_path = expand_string(tp->return_path);
2157
  uschar * new_return_path = expand_string(tp->return_path);
2159
  if (!new_return_path)
2158
  if (new_return_path)
2160
    {
2159
    return_path = new_return_path;
2161
    if (!f.expand_string_forcedfail)
2160
  else if (!f.expand_string_forcedfail)
2162
      {
2161
    {
2163
      common_error(TRUE, addr, ERRNO_EXPANDFAIL,
2162
    common_error(TRUE, addr, ERRNO_EXPANDFAIL,
2164
        US"Failed to expand return path \"%s\" in %s transport: %s",
2163
      US"Failed to expand return path \"%s\" in %s transport: %s",
2165
        tp->return_path, tp->name, expand_string_message);
2164
      tp->return_path, tp->name, expand_string_message);
2166
      return;
2165
    return;
2167
      }
2168
    }
2166
    }
2169
  else return_path = new_return_path;
2170
  }
2167
  }
2171
2168
2172
/* For local deliveries, one at a time, the value used for logging can just be
2169
/* For local deliveries, one at a time, the value used for logging can just be
Lines 2373-2399 Link Here
2373
    {
2370
    {
2374
    BOOL ok = TRUE;
2371
    BOOL ok = TRUE;
2375
    set_process_info("delivering %s to %s using %s", message_id,
2372
    set_process_info("delivering %s to %s using %s", message_id,
2376
     addr->local_part, addr->transport->name);
2373
     addr->local_part, tp->name);
2377
2374
2378
    /* Setting this global in the subprocess means we need never clear it */
2375
    /* Setting these globals in the subprocess means we need never clear them */
2379
    transport_name = addr->transport->name;
2376
    transport_name = addr->transport->name;
2377
    driver_srcfile = tp->srcfile;
2378
    driver_srcline = tp->srcline;
2380
2379
2381
    /* If a transport filter has been specified, set up its argument list.
2380
    /* If a transport filter has been specified, set up its argument list.
2382
    Any errors will get put into the address, and FALSE yielded. */
2381
    Any errors will get put into the address, and FALSE yielded. */
2383
2382
2384
    if (addr->transport->filter_command)
2383
    if (tp->filter_command)
2385
      {
2384
      {
2386
      ok = transport_set_up_command(&transport_filter_argv,
2385
      ok = transport_set_up_command(&transport_filter_argv,
2387
        addr->transport->filter_command,
2386
        tp->filter_command,
2388
        TRUE, PANIC, addr, US"transport filter", NULL);
2387
        TRUE, PANIC, addr, FALSE, US"transport filter", NULL);
2389
      transport_filter_timeout = addr->transport->filter_timeout;
2388
      transport_filter_timeout = tp->filter_timeout;
2390
      }
2389
      }
2391
    else transport_filter_argv = NULL;
2390
    else transport_filter_argv = NULL;
2392
2391
2393
    if (ok)
2392
    if (ok)
2394
      {
2393
      {
2395
      debug_print_string(addr->transport->debug_string);
2394
      debug_print_string(tp->debug_string);
2396
      replicate = !(addr->transport->info->code)(addr->transport, addr);
2395
      replicate = !(tp->info->code)(addr->transport, addr);
2397
      }
2396
      }
2398
    }
2397
    }
2399
2398
Lines 2413-2425 Link Here
2413
    uschar *s;
2412
    uschar *s;
2414
    int ret;
2413
    int ret;
2415
2414
2416
    if(  (ret = write(pfd[pipe_write], &addr2->transport_return, sizeof(int))) != sizeof(int)
2415
    if(  (i = addr2->transport_return, (ret = write(pfd[pipe_write], &i, sizeof(int))) != sizeof(int))
2417
      || (ret = write(pfd[pipe_write], &transport_count, sizeof(transport_count))) != sizeof(transport_count)
2416
      || (ret = write(pfd[pipe_write], &transport_count, sizeof(transport_count))) != sizeof(transport_count)
2418
      || (ret = write(pfd[pipe_write], &addr2->flags, sizeof(addr2->flags))) != sizeof(addr2->flags)
2417
      || (ret = write(pfd[pipe_write], &addr2->flags, sizeof(addr2->flags))) != sizeof(addr2->flags)
2419
      || (ret = write(pfd[pipe_write], &addr2->basic_errno,    sizeof(int))) != sizeof(int)
2418
      || (ret = write(pfd[pipe_write], &addr2->basic_errno,    sizeof(int))) != sizeof(int)
2420
      || (ret = write(pfd[pipe_write], &addr2->more_errno,     sizeof(int))) != sizeof(int)
2419
      || (ret = write(pfd[pipe_write], &addr2->more_errno,     sizeof(int))) != sizeof(int)
2421
      || (ret = write(pfd[pipe_write], &addr2->delivery_time,  sizeof(struct timeval))) != sizeof(struct timeval)
2420
      || (ret = write(pfd[pipe_write], &addr2->delivery_time,  sizeof(struct timeval))) != sizeof(struct timeval)
2422
      || (ret = write(pfd[pipe_write], &addr2->special_action, sizeof(int))) != sizeof(int)
2421
      || (i = addr2->special_action, (ret = write(pfd[pipe_write], &i, sizeof(int))) != sizeof(int))
2423
      || (ret = write(pfd[pipe_write], &addr2->transport,
2422
      || (ret = write(pfd[pipe_write], &addr2->transport,
2424
        sizeof(transport_instance *))) != sizeof(transport_instance *)
2423
        sizeof(transport_instance *))) != sizeof(transport_instance *)
2425
2424
Lines 2487-2493 Link Here
2487
    len = read(pfd[pipe_read], &addr2->basic_errno,    sizeof(int));
2486
    len = read(pfd[pipe_read], &addr2->basic_errno,    sizeof(int));
2488
    len = read(pfd[pipe_read], &addr2->more_errno,     sizeof(int));
2487
    len = read(pfd[pipe_read], &addr2->more_errno,     sizeof(int));
2489
    len = read(pfd[pipe_read], &addr2->delivery_time,  sizeof(struct timeval));
2488
    len = read(pfd[pipe_read], &addr2->delivery_time,  sizeof(struct timeval));
2490
    len = read(pfd[pipe_read], &addr2->special_action, sizeof(int));
2489
    len = read(pfd[pipe_read], &i, sizeof(int)); addr2->special_action = i;
2491
    len = read(pfd[pipe_read], &addr2->transport,
2490
    len = read(pfd[pipe_read], &addr2->transport,
2492
      sizeof(transport_instance *));
2491
      sizeof(transport_instance *));
2493
2492
Lines 2889-2898 Link Here
2889
  deliveries (e.g. to pipes) can take a substantial time. */
2888
  deliveries (e.g. to pipes) can take a substantial time. */
2890
2889
2891
  if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE)))
2890
  if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE)))
2892
    {
2893
    DEBUG(D_deliver|D_retry|D_hints_lookup)
2891
    DEBUG(D_deliver|D_retry|D_hints_lookup)
2894
      debug_printf("no retry data available\n");
2892
      debug_printf("no retry data available\n");
2895
    }
2896
2893
2897
  addr2 = addr;
2894
  addr2 = addr;
2898
  addr3 = NULL;
2895
  addr3 = NULL;
Lines 3048-3054 Link Here
3048
    else for (addr2 = addr; addr2; addr2 = addr2->next)
3045
    else for (addr2 = addr; addr2; addr2 = addr2->next)
3049
      if (addr2->transport_return == OK)
3046
      if (addr2->transport_return == OK)
3050
	{
3047
	{
3051
	addr3 = store_get(sizeof(address_item), FALSE);
3048
	addr3 = store_get(sizeof(address_item), GET_UNTAINTED);
3052
	*addr3 = *addr2;
3049
	*addr3 = *addr2;
3053
	addr3->next = NULL;
3050
	addr3->next = NULL;
3054
	addr3->shadow_message = US &addr2->shadow_message;
3051
	addr3->shadow_message = US &addr2->shadow_message;
Lines 3196-3201 Link Here
3196
uschar *pattern;
3193
uschar *pattern;
3197
uschar patbuf[256];
3194
uschar patbuf[256];
3198
3195
3196
/*XXX The list is used before expansion. Not sure how that ties up with the docs */
3199
while (  *aptr
3197
while (  *aptr
3200
      && (pattern = string_nextinlist(&listptr, &sep, patbuf, sizeof(patbuf)))
3198
      && (pattern = string_nextinlist(&listptr, &sep, patbuf, sizeof(patbuf)))
3201
      )
3199
      )
Lines 3308-3314 Link Here
3308
3306
3309
/* Loop through all items, reading from the pipe when necessary. The pipe
3307
/* Loop through all items, reading from the pipe when necessary. The pipe
3310
used to be non-blocking. But I do not see a reason for using non-blocking I/O
3308
used to be non-blocking. But I do not see a reason for using non-blocking I/O
3311
here, as the preceding select() tells us, if data is available for reading.
3309
here, as the preceding poll() tells us, if data is available for reading.
3312
3310
3313
A read() on a "selected" handle should never block, but(!) it may return
3311
A read() on a "selected" handle should never block, but(!) it may return
3314
less data then we expected. (The buffer size we pass to read() shouldn't be
3312
less data then we expected. (The buffer size we pass to read() shouldn't be
Lines 3442-3448 Link Here
3442
3440
3443
      if (!r || !(*ptr & rf_delete))
3441
      if (!r || !(*ptr & rf_delete))
3444
	{
3442
	{
3445
	r = store_get(sizeof(retry_item), FALSE);
3443
	r = store_get(sizeof(retry_item), GET_UNTAINTED);
3446
	r->next = addr->retries;
3444
	r->next = addr->retries;
3447
	addr->retries = r;
3445
	addr->retries = r;
3448
	r->flags = *ptr++;
3446
	r->flags = *ptr++;
Lines 3581-3587 Link Here
3581
3579
3582
      switch (*subid)
3580
      switch (*subid)
3583
	{
3581
	{
3584
  #ifdef SUPPORT_SOCKS
3582
	case 3:		/* explicit notification of continued-connection (non)use;
3583
			overrides caller's knowlege. */
3584
	  if (*ptr & BIT(1))      setflag(addr, af_new_conn);
3585
	  else if (*ptr & BIT(2)) setflag(addr, af_cont_conn);
3586
	  break;
3587
3588
#ifdef SUPPORT_SOCKS
3585
	case '2':	/* proxy information; must arrive before A0 and applies to that addr XXX oops*/
3589
	case '2':	/* proxy information; must arrive before A0 and applies to that addr XXX oops*/
3586
	  proxy_session = TRUE;	/*XXX should this be cleared somewhere? */
3590
	  proxy_session = TRUE;	/*XXX should this be cleared somewhere? */
3587
	  if (*ptr == 0)
3591
	  if (*ptr == 0)
Lines 3594-3602 Link Here
3594
	    ptr += sizeof(proxy_local_port);
3598
	    ptr += sizeof(proxy_local_port);
3595
	    }
3599
	    }
3596
	  break;
3600
	  break;
3597
  #endif
3601
#endif
3598
3602
3599
  #ifdef EXPERIMENTAL_DSN_INFO
3603
#ifdef EXPERIMENTAL_DSN_INFO
3600
	case '1':	/* must arrive before A0, and applies to that addr */
3604
	case '1':	/* must arrive before A0, and applies to that addr */
3601
			/* Two strings: smtp_greeting and helo_response */
3605
			/* Two strings: smtp_greeting and helo_response */
3602
	  addr->smtp_greeting = string_copy(ptr);
3606
	  addr->smtp_greeting = string_copy(ptr);
Lines 3604-3610 Link Here
3604
	  addr->helo_response = string_copy(ptr);
3608
	  addr->helo_response = string_copy(ptr);
3605
	  while(*ptr++);
3609
	  while(*ptr++);
3606
	  break;
3610
	  break;
3607
  #endif
3611
#endif
3608
3612
3609
	case '0':
3613
	case '0':
3610
	  DEBUG(D_deliver) debug_printf("A0 %s tret %d\n", addr->address, *ptr);
3614
	  DEBUG(D_deliver) debug_printf("A0 %s tret %d\n", addr->address, *ptr);
Lines 3627-3633 Link Here
3627
3631
3628
	  if (*ptr)
3632
	  if (*ptr)
3629
	    {
3633
	    {
3630
	    h = store_get(sizeof(host_item), FALSE);
3634
	    h = store_get(sizeof(host_item), GET_UNTAINTED);
3631
	    h->name = string_copy(ptr);
3635
	    h->name = string_copy(ptr);
3632
	    while (*ptr++);
3636
	    while (*ptr++);
3633
	    h->address = string_copy(ptr);
3637
	    h->address = string_copy(ptr);
Lines 3836-3842 Link Here
3836
par_wait(void)
3840
par_wait(void)
3837
{
3841
{
3838
int poffset, status;
3842
int poffset, status;
3839
address_item *addr, *addrlist;
3843
address_item * addr, * addrlist;
3840
pid_t pid;
3844
pid_t pid;
3841
3845
3842
set_process_info("delivering %s: waiting for a remote delivery subprocess "
3846
set_process_info("delivering %s: waiting for a remote delivery subprocess "
Lines 3846-3863 Link Here
3846
existence - in which case give an error return. We cannot proceed just by
3850
existence - in which case give an error return. We cannot proceed just by
3847
waiting for a completion, because a subprocess may have filled up its pipe, and
3851
waiting for a completion, because a subprocess may have filled up its pipe, and
3848
be waiting for it to be emptied. Therefore, if no processes have finished, we
3852
be waiting for it to be emptied. Therefore, if no processes have finished, we
3849
wait for one of the pipes to acquire some data by calling select(), with a
3853
wait for one of the pipes to acquire some data by calling poll(), with a
3850
timeout just in case.
3854
timeout just in case.
3851
3855
3852
The simple approach is just to iterate after reading data from a ready pipe.
3856
The simple approach is just to iterate after reading data from a ready pipe.
3853
This leads to non-ideal behaviour when the subprocess has written its final Z
3857
This leads to non-ideal behaviour when the subprocess has written its final Z
3854
item, closed the pipe, and is in the process of exiting (the common case). A
3858
item, closed the pipe, and is in the process of exiting (the common case). A
3855
call to waitpid() yields nothing completed, but select() shows the pipe ready -
3859
call to waitpid() yields nothing completed, but poll() shows the pipe ready -
3856
reading it yields EOF, so you end up with busy-waiting until the subprocess has
3860
reading it yields EOF, so you end up with busy-waiting until the subprocess has
3857
actually finished.
3861
actually finished.
3858
3862
3859
To avoid this, if all the data that is needed has been read from a subprocess
3863
To avoid this, if all the data that is needed has been read from a subprocess
3860
after select(), an explicit wait() for it is done. We know that all it is doing
3864
after poll(), an explicit wait() for it is done. We know that all it is doing
3861
is writing to the pipe and then exiting, so the wait should not be long.
3865
is writing to the pipe and then exiting, so the wait should not be long.
3862
3866
3863
The non-blocking waitpid() is to some extent just insurance; if we could
3867
The non-blocking waitpid() is to some extent just insurance; if we could
Lines 3877-3885 Link Here
3877
  {
3881
  {
3878
  while ((pid = waitpid(-1, &status, WNOHANG)) <= 0)
3882
  while ((pid = waitpid(-1, &status, WNOHANG)) <= 0)
3879
    {
3883
    {
3880
    struct timeval tv;
3884
    int readycount;
3881
    fd_set select_pipes;
3882
    int maxpipe, readycount;
3883
3885
3884
    /* A return value of -1 can mean several things. If errno != ECHILD, it
3886
    /* A return value of -1 can mean several things. If errno != ECHILD, it
3885
    either means invalid options (which we discount), or that this process was
3887
    either means invalid options (which we discount), or that this process was
Lines 3903-3909 Link Here
3903
    subprocesses are still in existence. If kill() gives an OK return, we know
3905
    subprocesses are still in existence. If kill() gives an OK return, we know
3904
    it must be for one of our processes - it can't be for a re-use of the pid,
3906
    it must be for one of our processes - it can't be for a re-use of the pid,
3905
    because if our process had finished, waitpid() would have found it. If any
3907
    because if our process had finished, waitpid() would have found it. If any
3906
    of our subprocesses are in existence, we proceed to use select() as if
3908
    of our subprocesses are in existence, we proceed to use poll() as if
3907
    waitpid() had returned zero. I think this is safe. */
3909
    waitpid() had returned zero. I think this is safe. */
3908
3910
3909
    if (pid < 0)
3911
    if (pid < 0)
Lines 3927-3933 Link Here
3927
      if (poffset >= remote_max_parallel)
3929
      if (poffset >= remote_max_parallel)
3928
        {
3930
        {
3929
        DEBUG(D_deliver) debug_printf("*** no delivery children found\n");
3931
        DEBUG(D_deliver) debug_printf("*** no delivery children found\n");
3930
        return NULL;   /* This is the error return */
3932
	return NULL;	/* This is the error return */
3931
        }
3933
        }
3932
      }
3934
      }
3933
3935
Lines 3936-3963 Link Here
3936
    subprocess, but there are no completed subprocesses. See if any pipes are
3938
    subprocess, but there are no completed subprocesses. See if any pipes are
3937
    ready with any data for reading. */
3939
    ready with any data for reading. */
3938
3940
3939
    DEBUG(D_deliver) debug_printf("selecting on subprocess pipes\n");
3941
    DEBUG(D_deliver) debug_printf("polling subprocess pipes\n");
3940
3942
3941
    maxpipe = 0;
3942
    FD_ZERO(&select_pipes);
3943
    for (poffset = 0; poffset < remote_max_parallel; poffset++)
3943
    for (poffset = 0; poffset < remote_max_parallel; poffset++)
3944
      if (parlist[poffset].pid != 0)
3944
      if (parlist[poffset].pid != 0)
3945
        {
3945
	{
3946
        int fd = parlist[poffset].fd;
3946
	parpoll[poffset].fd = parlist[poffset].fd;
3947
        FD_SET(fd, &select_pipes);
3947
	parpoll[poffset].events = POLLIN;
3948
        if (fd > maxpipe) maxpipe = fd;
3948
	}
3949
        }
3949
      else
3950
	parpoll[poffset].fd = -1;
3950
3951
3951
    /* Stick in a 60-second timeout, just in case. */
3952
    /* Stick in a 60-second timeout, just in case. */
3952
3953
3953
    tv.tv_sec = 60;
3954
    readycount = poll(parpoll, remote_max_parallel, 60 * 1000);
3954
    tv.tv_usec = 0;
3955
3956
    readycount = select(maxpipe + 1, (SELECT_ARG2_TYPE *)&select_pipes,
3957
         NULL, NULL, &tv);
3958
3955
3959
    /* Scan through the pipes and read any that are ready; use the count
3956
    /* Scan through the pipes and read any that are ready; use the count
3960
    returned by select() to stop when there are no more. Select() can return
3957
    returned by poll() to stop when there are no more. Select() can return
3961
    with no processes (e.g. if interrupted). This shouldn't matter.
3958
    with no processes (e.g. if interrupted). This shouldn't matter.
3962
3959
3963
    If par_read_pipe() returns TRUE, it means that either the terminating Z was
3960
    If par_read_pipe() returns TRUE, it means that either the terminating Z was
Lines 3974-3980 Link Here
3974
         poffset++)
3971
         poffset++)
3975
      {
3972
      {
3976
      if (  (pid = parlist[poffset].pid) != 0
3973
      if (  (pid = parlist[poffset].pid) != 0
3977
         && FD_ISSET(parlist[poffset].fd, &select_pipes)
3974
	 && parpoll[poffset].revents
3978
	 )
3975
	 )
3979
        {
3976
        {
3980
        readycount--;
3977
        readycount--;
Lines 4012-4018 Link Here
4012
    "transport process list", pid);
4009
    "transport process list", pid);
4013
  }  /* End of the "for" loop */
4010
  }  /* End of the "for" loop */
4014
4011
4015
/* Come here when all the data was completely read after a select(), and
4012
/* Come here when all the data was completely read after a poll(), and
4016
the process in pid has been wait()ed for. */
4013
the process in pid has been wait()ed for. */
4017
4014
4018
PROCESS_DONE:
4015
PROCESS_DONE:
Lines 4047-4053 Link Here
4047
    "%s %d",
4044
    "%s %d",
4048
    addrlist->transport->driver_name,
4045
    addrlist->transport->driver_name,
4049
    status,
4046
    status,
4050
    (msb == 0)? "terminated by signal" : "exit code",
4047
    msb == 0 ? "terminated by signal" : "exit code",
4051
    code);
4048
    code);
4052
4049
4053
  if (msb != 0 || (code != SIGTERM && code != SIGKILL && code != SIGQUIT))
4050
  if (msb != 0 || (code != SIGTERM && code != SIGKILL && code != SIGQUIT))
Lines 4065-4071 Link Here
4065
/* Else complete reading the pipe to get the result of the delivery, if all
4062
/* Else complete reading the pipe to get the result of the delivery, if all
4066
the data has not yet been obtained. */
4063
the data has not yet been obtained. */
4067
4064
4068
else if (!parlist[poffset].done) (void)par_read_pipe(poffset, TRUE);
4065
else if (!parlist[poffset].done)
4066
  (void) par_read_pipe(poffset, TRUE);
4069
4067
4070
/* Put the data count and return path into globals, mark the data slot unused,
4068
/* Put the data count and return path into globals, mark the data slot unused,
4071
decrement the count of subprocesses, and return the address chain. */
4069
decrement the count of subprocesses, and return the address chain. */
Lines 4211-4219 Link Here
4211
4209
4212
if (!parlist)
4210
if (!parlist)
4213
  {
4211
  {
4214
  parlist = store_get(remote_max_parallel * sizeof(pardata), FALSE);
4212
  parlist = store_get(remote_max_parallel * sizeof(pardata), GET_UNTAINTED);
4215
  for (poffset = 0; poffset < remote_max_parallel; poffset++)
4213
  for (poffset = 0; poffset < remote_max_parallel; poffset++)
4216
    parlist[poffset].pid = 0;
4214
    parlist[poffset].pid = 0;
4215
  parpoll = store_get(remote_max_parallel * sizeof(struct pollfd), GET_UNTAINTED);
4217
  }
4216
  }
4218
4217
4219
/* Now loop for each remote delivery */
4218
/* Now loop for each remote delivery */
Lines 4441-4450 Link Here
4441
4440
4442
  if(addr->prop.errors_address)
4441
  if(addr->prop.errors_address)
4443
    return_path = addr->prop.errors_address;
4442
    return_path = addr->prop.errors_address;
4444
#ifdef EXPERIMENTAL_SRS
4445
  else if(addr->prop.srs_sender)
4446
    return_path = addr->prop.srs_sender;
4447
#endif
4448
  else
4443
  else
4449
    return_path = sender_address;
4444
    return_path = sender_address;
4450
4445
Lines 4609-4615 Link Here
4609
    that it can use either of them, though it prefers O_NONBLOCK, which
4604
    that it can use either of them, though it prefers O_NONBLOCK, which
4610
    distinguishes between EOF and no-more-data. */
4605
    distinguishes between EOF and no-more-data. */
4611
4606
4612
/* The data appears in a timely manner and we already did a select on
4607
/* The data appears in a timely manner and we already did a poll on
4613
all pipes, so I do not see a reason to use non-blocking IO here
4608
all pipes, so I do not see a reason to use non-blocking IO here
4614
4609
4615
#ifdef O_NONBLOCK
4610
#ifdef O_NONBLOCK
Lines 4665-4672 Link Here
4665
    int fd = pfd[pipe_write];
4660
    int fd = pfd[pipe_write];
4666
    host_item *h;
4661
    host_item *h;
4667
4662
4668
    /* Setting this global in the subprocess means we need never clear it */
4663
    /* Setting these globals in the subprocess means we need never clear them */
4669
    transport_name = tp->name;
4664
    transport_name = addr->transport->name;
4665
    driver_srcfile = tp->srcfile;
4666
    driver_srcline = tp->srcline;
4670
4667
4671
    /* There are weird circumstances in which logging is disabled */
4668
    /* There are weird circumstances in which logging is disabled */
4672
    f.disable_logging = tp->disable_logging;
4669
    f.disable_logging = tp->disable_logging;
Lines 4786-4792 Link Here
4786
#ifdef SUPPORT_DANE
4783
#ifdef SUPPORT_DANE
4787
      if (tls_out.dane_verified)        setflag(addr, af_dane_verified);
4784
      if (tls_out.dane_verified)        setflag(addr, af_dane_verified);
4788
#endif
4785
#endif
4789
# ifdef EXPERIMENTAL_TLS_RESUME
4786
# ifndef DISABLE_TLS_RESUME
4790
      if (tls_out.resumption & RESUME_USED) setflag(addr, af_tls_resume);
4787
      if (tls_out.resumption & RESUME_USED) setflag(addr, af_tls_resume);
4791
# endif
4788
# endif
4792
4789
Lines 4895-4900 Link Here
4895
        rmt_dlv_checked_write(fd, 'R', '0', big_buffer, ptr - big_buffer);
4892
        rmt_dlv_checked_write(fd, 'R', '0', big_buffer, ptr - big_buffer);
4896
        }
4893
        }
4897
4894
4895
      if (testflag(addr, af_new_conn) || testflag(addr, af_cont_conn))
4896
	{
4897
	DEBUG(D_deliver) debug_printf("%scontinued-connection\n",
4898
	  testflag(addr, af_new_conn) ? "non-" : "");
4899
	big_buffer[0] = testflag(addr, af_new_conn) ? BIT(1) : BIT(2);
4900
        rmt_dlv_checked_write(fd, 'A', '3', big_buffer, 1);
4901
	}
4902
4898
#ifdef SUPPORT_SOCKS
4903
#ifdef SUPPORT_SOCKS
4899
      if (LOGGING(proxy) && proxy_session)
4904
      if (LOGGING(proxy) && proxy_session)
4900
	{
4905
	{
Lines 5104-5110 Link Here
5104
this, Jan 1999.] We know the syntax is valid, so this can be done by simply
5109
this, Jan 1999.] We know the syntax is valid, so this can be done by simply
5105
removing quoting backslashes and any unquoted doublequotes. */
5110
removing quoting backslashes and any unquoted doublequotes. */
5106
5111
5107
t = addr->cc_local_part = store_get(len+1, is_tainted(address));
5112
t = addr->cc_local_part = store_get(len+1, address);
5108
while(len-- > 0)
5113
while(len-- > 0)
5109
  {
5114
  {
5110
  int c = *address++;
5115
  int c = *address++;
Lines 5147-5153 Link Here
5147
5152
5148
  if (new_address)
5153
  if (new_address)
5149
    {
5154
    {
5150
    address_item *new_parent = store_get(sizeof(address_item), FALSE);
5155
    address_item * new_parent = store_get(sizeof(address_item), GET_UNTAINTED);
5151
    *new_parent = *addr;
5156
    *new_parent = *addr;
5152
    addr->parent = new_parent;
5157
    addr->parent = new_parent;
5153
    new_parent->child_count = 1;
5158
    new_parent->child_count = 1;
Lines 5341-5350 Link Here
5341
*/
5346
*/
5342
5347
5343
static void
5348
static void
5344
print_address_error(address_item *addr, FILE *f, uschar *t)
5349
print_address_error(address_item * addr, FILE * f, const uschar * t)
5345
{
5350
{
5346
int count = Ustrlen(t);
5351
int count = Ustrlen(t);
5347
uschar *s = testflag(addr, af_pass_message) ? addr->message : NULL;
5352
uschar * s = testflag(addr, af_pass_message) ? addr->message : NULL;
5348
5353
5349
if (!s && !(s = addr->user_message))
5354
if (!s && !(s = addr->user_message))
5350
  return;
5355
  return;
Lines 5884-5890 Link Here
5884
    return continue_closedown();   /* yields DELIVER_NOT_ATTEMPTED */
5889
    return continue_closedown();   /* yields DELIVER_NOT_ATTEMPTED */
5885
    }
5890
    }
5886
5891
5887
  /* Make a C stream out of it. */
5892
  /* Make a stdio stream out of it. */
5888
5893
5889
  if (!(message_log = fdopen(fd, "a")))
5894
  if (!(message_log = fdopen(fd, "a")))
5890
    {
5895
    {
Lines 6331-6337 Link Here
6331
	    string_copyn(addr+start, dom ? (dom-1) - start : end - start);
6336
	    string_copyn(addr+start, dom ? (dom-1) - start : end - start);
6332
	  deliver_domain = dom ? CUS string_copyn(addr+dom, end - dom) : CUS"";
6337
	  deliver_domain = dom ? CUS string_copyn(addr+dom, end - dom) : CUS"";
6333
6338
6334
	  event_raise(event_action, US"msg:fail:internal", new->message);
6339
	  (void) event_raise(event_action, US"msg:fail:internal", new->message, NULL);
6335
6340
6336
	  deliver_localpart = save_local;
6341
	  deliver_localpart = save_local;
6337
	  deliver_domain = save_domain;
6342
	  deliver_domain = save_domain;
Lines 6411-6420 Link Here
6411
  while (addr_new)
6416
  while (addr_new)
6412
    {
6417
    {
6413
    int rc;
6418
    int rc;
6414
    uschar *p;
6419
    tree_node * tnode;
6415
    tree_node *tnode;
6420
    dbdata_retry * domain_retry_record, * address_retry_record;
6416
    dbdata_retry *domain_retry_record;
6417
    dbdata_retry *address_retry_record;
6418
6421
6419
    addr = addr_new;
6422
    addr = addr_new;
6420
    addr_new = addr->next;
6423
    addr_new = addr->next;
Lines 6540-6553 Link Here
6540
6543
6541
      /* Treat /dev/null as a special case and abandon the delivery. This
6544
      /* Treat /dev/null as a special case and abandon the delivery. This
6542
      avoids having to specify a uid on the transport just for this case.
6545
      avoids having to specify a uid on the transport just for this case.
6543
      Arrange for the transport name to be logged as "**bypassed**". */
6546
      Arrange for the transport name to be logged as "**bypassed**".
6547
      Copy the transport for this fairly unusual case rather than having
6548
      to make all transports mutable. */
6544
6549
6545
      if (Ustrcmp(addr->address, "/dev/null") == 0)
6550
      if (Ustrcmp(addr->address, "/dev/null") == 0)
6546
        {
6551
        {
6547
        uschar *save = addr->transport->name;
6552
	transport_instance * save_t = addr->transport;
6548
        addr->transport->name = US"**bypassed**";
6553
	transport_instance * t = store_get(sizeof(*t), save_t);
6554
	*t = *save_t;
6555
	t->name = US"**bypassed**";
6556
	addr->transport = t;
6549
        (void)post_process_one(addr, OK, LOG_MAIN, EXIM_DTYPE_TRANSPORT, '=');
6557
        (void)post_process_one(addr, OK, LOG_MAIN, EXIM_DTYPE_TRANSPORT, '=');
6550
        addr->transport->name = save;
6558
        addr->transport= save_t;
6551
        continue;   /* with the next new address */
6559
        continue;   /* with the next new address */
6552
        }
6560
        }
6553
6561
Lines 6626-6633 Link Here
6626
    /* Ensure that the domain in the unique field is lower cased, because
6634
    /* Ensure that the domain in the unique field is lower cased, because
6627
    domains are always handled caselessly. */
6635
    domains are always handled caselessly. */
6628
6636
6629
    p = Ustrrchr(addr->unique, '@');
6637
    for (uschar * p = Ustrrchr(addr->unique, '@'); *p; p++) *p = tolower(*p);
6630
    while (*p != 0) { *p = tolower(*p); p++; }
6631
6638
6632
    DEBUG(D_deliver|D_route) debug_printf("unique = %s\n", addr->unique);
6639
    DEBUG(D_deliver|D_route) debug_printf("unique = %s\n", addr->unique);
6633
6640
Lines 6824-6830 Link Here
6824
      addr_route = addr->next;
6831
      addr_route = addr->next;
6825
6832
6826
      deliver_domain = addr->domain;  /* set $domain */
6833
      deliver_domain = addr->domain;  /* set $domain */
6827
      if ((rc = match_isinlist(addr->domain, (const uschar **)&queue_domains, 0,
6834
      if ((rc = match_isinlist(addr->domain, CUSS &queue_domains, 0,
6828
            &domainlist_anchor, addr->domain_cache, MCL_DOMAIN, TRUE, NULL))
6835
            &domainlist_anchor, addr->domain_cache, MCL_DOMAIN, TRUE, NULL))
6829
              != OK)
6836
              != OK)
6830
        if (rc == DEFER)
6837
        if (rc == DEFER)
Lines 7095-7101 Link Here
7095
    debug_printf("deferring local deliveries due to continued-transport\n");
7102
    debug_printf("deferring local deliveries due to continued-transport\n");
7096
  if (addr_defer)
7103
  if (addr_defer)
7097
    {
7104
    {
7098
    address_item *addr = addr_defer;
7105
    address_item * addr = addr_defer;
7099
    while (addr->next) addr = addr->next;
7106
    while (addr->next) addr = addr->next;
7100
    addr->next = addr_local;
7107
    addr->next = addr_local;
7101
    }
7108
    }
Lines 7377-7383 Link Here
7377
    {
7384
    {
7378
    /* copy and relink address_item and send report with all of them at once later */
7385
    /* copy and relink address_item and send report with all of them at once later */
7379
    address_item * addr_next = addr_senddsn;
7386
    address_item * addr_next = addr_senddsn;
7380
    addr_senddsn = store_get(sizeof(address_item), FALSE);
7387
    addr_senddsn = store_get(sizeof(address_item), GET_UNTAINTED);
7381
    *addr_senddsn = *a;
7388
    *addr_senddsn = *a;
7382
    addr_senddsn->next = addr_next;
7389
    addr_senddsn->next = addr_next;
7383
    }
7390
    }
Lines 8077-8083 Link Here
8077
  f.deliver_freeze = FALSE;
8084
  f.deliver_freeze = FALSE;
8078
8085
8079
#ifndef DISABLE_EVENT
8086
#ifndef DISABLE_EVENT
8080
  (void) event_raise(event_action, US"msg:complete", NULL);
8087
  (void) event_raise(event_action, US"msg:complete", NULL, NULL);
8081
#endif
8088
#endif
8082
  }
8089
  }
8083
8090
Lines 8426-8432 Link Here
8426
  /* If this was a first delivery attempt, unset the first time flag, and
8433
  /* If this was a first delivery attempt, unset the first time flag, and
8427
  ensure that the spool gets updated. */
8434
  ensure that the spool gets updated. */
8428
8435
8429
  if (f.deliver_firsttime)
8436
  if (f.deliver_firsttime && !f.queue_2stage)
8430
    {
8437
    {
8431
    f.deliver_firsttime = FALSE;
8438
    f.deliver_firsttime = FALSE;
8432
    update_spool = TRUE;
8439
    update_spool = TRUE;
Lines 8559-8610 Link Here
8559
}
8566
}
8560
8567
8561
8568
8562
uschar *
8563
deliver_get_sender_address (uschar * id)
8564
{
8565
int rc;
8566
uschar * new_sender_address,
8567
       * save_sender_address;
8568
BOOL save_qr = f.queue_running;
8569
uschar * spoolname;
8570
8571
/* make spool_open_datafile non-noisy on fail */
8572
8573
f.queue_running = TRUE;
8574
8575
/* Side effect: message_subdir is set for the (possibly split) spool directory */
8576
8577
deliver_datafile = spool_open_datafile(id);
8578
f.queue_running = save_qr;
8579
if (deliver_datafile < 0)
8580
  return NULL;
8581
8582
/* Save and restore the global sender_address.  I'm not sure if we should
8583
not save/restore all the other global variables too, because
8584
spool_read_header() may change all of them. But OTOH, when this
8585
deliver_get_sender_address() gets called, the current message is done
8586
already and nobody needs the globals anymore. (HS12, 2015-08-21) */
8587
8588
spoolname = string_sprintf("%s-H", id);
8589
save_sender_address = sender_address;
8590
8591
rc = spool_read_header(spoolname, TRUE, TRUE);
8592
8593
new_sender_address = sender_address;
8594
sender_address = save_sender_address;
8595
8596
if (rc != spool_read_OK)
8597
  return NULL;
8598
8599
assert(new_sender_address);
8600
8601
(void)close(deliver_datafile);
8602
deliver_datafile = -1;
8603
8604
return new_sender_address;
8605
}
8606
8607
8569
8570
/* Called from a commandline, or from the daemon, to do a delivery.
8571
We need to regain privs; do this by exec of the exim binary. */
8608
8572
8609
void
8573
void
8610
delivery_re_exec(int exec_type)
8574
delivery_re_exec(int exec_type)
Lines 8639-8645 Link Here
8639
    if (pid == 0)	/* child: will fork again to totally disconnect */
8603
    if (pid == 0)	/* child: will fork again to totally disconnect */
8640
      {
8604
      {
8641
      smtp_proxy_tls(cutthrough.cctx.tls_ctx, big_buffer, big_buffer_size,
8605
      smtp_proxy_tls(cutthrough.cctx.tls_ctx, big_buffer, big_buffer_size,
8642
		      pfd, 5*60);
8606
		      pfd, 5*60, cutthrough.host.name);
8643
      /* does not return */
8607
      /* does not return */
8644
      }
8608
      }
8645
8609
(-)exim.orig/src/directory.c (-2 / +5 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2010 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2009 */
6
/* Copyright (c) University of Cambridge 1995 - 2009 */
6
/* Copyright (c) The Exim Maintainers 2010 - 2018 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#include "exim.h"
9
#include "exim.h"
Lines 44-49 Link Here
44
struct stat statbuf;
44
struct stat statbuf;
45
uschar * path;
45
uschar * path;
46
46
47
if (is_tainted(name)) 
48
  { p = US"create"; path = US name; errno = ERRNO_TAINT; goto bad; }
49
47
if (parent)
50
if (parent)
48
  {
51
  {
49
  path = string_sprintf("%s%s%s", parent, US"/", name);
52
  path = string_sprintf("%s%s%s", parent, US"/", name);
Lines 85-91 Link Here
85
88
86
bad:
89
bad:
87
  if (panic) log_write(0, LOG_MAIN|LOG_PANIC_DIE,
90
  if (panic) log_write(0, LOG_MAIN|LOG_PANIC_DIE,
88
    "Failed to %s directory \"%s\": %s\n", p, path, strerror(errno));
91
    "Failed to %s directory \"%s\": %s\n", p, path, exim_errstr(errno));
89
  return FALSE;
92
  return FALSE;
90
}
93
}
91
94
(-)exim.orig/src/dkim.c (-19 / +23 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge, 1995 - 2018 */
6
/* Copyright (c) University of Cambridge, 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Code for DKIM support. Other DKIM relevant code is in
9
/* Code for DKIM support. Other DKIM relevant code is in
Lines 50-60 Link Here
50
dns_answer * dnsa = store_get_dns_answer();
50
dns_answer * dnsa = store_get_dns_answer();
51
dns_scan dnss;
51
dns_scan dnss;
52
rmark reset_point = store_mark();
52
rmark reset_point = store_mark();
53
gstring * g = NULL;
53
gstring * g = string_get_tainted(256, GET_TAINTED);
54
54
55
lookup_dnssec_authenticated = NULL;
55
lookup_dnssec_authenticated = NULL;
56
if (dns_lookup(dnsa, name, T_TXT, NULL) != DNS_SUCCEED)
56
if (dns_lookup(dnsa, name, T_TXT, NULL) != DNS_SUCCEED)
57
  return NULL;	/*XXX better error detail?  logging? */
57
  goto bad;
58
58
59
/* Search for TXT record */
59
/* Search for TXT record */
60
60
Lines 62-73 Link Here
62
     rr;
62
     rr;
63
     rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
63
     rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
64
  if (rr->type == T_TXT)
64
  if (rr->type == T_TXT)
65
    {
65
    {			/* Copy record content to the answer buffer */
66
    int rr_offset = 0;
66
    for (int rr_offset = 0; rr_offset < rr->size; )
67
68
    /* Copy record content to the answer buffer */
69
70
    while (rr_offset < rr->size)
71
      {
67
      {
72
      uschar len = rr->data[rr_offset++];
68
      uschar len = rr->data[rr_offset++];
73
69
Lines 78-95 Link Here
78
      rr_offset += len;
74
      rr_offset += len;
79
      }
75
      }
80
76
81
    /* check if this looks like a DKIM record */
77
    /* Check if this looks like a DKIM record */
82
    if (Ustrncmp(g->s, "v=", 2) != 0 || strncasecmp(CS g->s, "v=dkim", 6) == 0)
78
    if (Ustrncmp(g->s, "v=", 2) != 0 || strncasecmp(CS g->s, "v=dkim", 6) == 0)
83
      {
79
      {
80
      store_free_dns_answer(dnsa);
84
      gstring_release_unused(g);
81
      gstring_release_unused(g);
85
      return string_from_gstring(g);
82
      return string_from_gstring(g);
86
      }
83
      }
87
84
88
    if (g) g->ptr = 0;		/* overwrite previous record */
85
    g->ptr = 0;		/* overwrite previous record */
89
    }
86
    }
90
87
91
bad:
88
bad:
92
store_reset(reset_point);
89
store_reset(reset_point);
90
store_free_dns_answer(dnsa);
93
return NULL;	/*XXX better error detail?  logging? */
91
return NULL;	/*XXX better error detail?  logging? */
94
}
92
}
95
93
Lines 109-120 Link Here
109
{
107
{
110
dkim_exim_init();
108
dkim_exim_init();
111
109
112
/* There is a store-reset between header & body reception
110
/* There is a store-reset between header & body reception for the main pool
113
so cannot use the main pool. Any allocs done by Exim
111
(actually, after every header line) so cannot use that as we need the data we
114
memory-handling must use the perm pool. */
112
store per-header, during header processing, at the end of body reception
113
for evaluating the signature.  Any allocs done for dkim verify
114
memory-handling must use a different pool.  We use a separate one that we
115
can reset per message. */
115
116
116
dkim_verify_oldpool = store_pool;
117
dkim_verify_oldpool = store_pool;
117
store_pool = POOL_PERM;
118
store_pool = POOL_MESSAGE;
118
119
119
/* Free previous context if there is one */
120
/* Free previous context if there is one */
120
121
Lines 127-145 Link Here
127
dkim_collect_input = dkim_verify_ctx ? DKIM_MAX_SIGNATURES : 0;
128
dkim_collect_input = dkim_verify_ctx ? DKIM_MAX_SIGNATURES : 0;
128
dkim_collect_error = NULL;
129
dkim_collect_error = NULL;
129
130
130
/* Start feed up with any cached data */
131
/* Start feed up with any cached data, but limited to message data */
131
receive_get_cache();
132
receive_get_cache(chunking_state == CHUNKING_LAST
133
		  ? chunking_data_left : GETC_BUFFER_UNLIMITED);
132
134
133
store_pool = dkim_verify_oldpool;
135
store_pool = dkim_verify_oldpool;
134
}
136
}
135
137
136
138
139
/* Submit a chunk of data for verification input.
140
Only use the data when the feed is activated. */
137
void
141
void
138
dkim_exim_verify_feed(uschar * data, int len)
142
dkim_exim_verify_feed(uschar * data, int len)
139
{
143
{
140
int rc;
144
int rc;
141
145
142
store_pool = POOL_PERM;
146
store_pool = POOL_MESSAGE;
143
if (  dkim_collect_input
147
if (  dkim_collect_input
144
   && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
148
   && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
145
  {
149
  {
Lines 305-311 Link Here
305
gstring * g = NULL;
309
gstring * g = NULL;
306
const uschar * errstr = NULL;
310
const uschar * errstr = NULL;
307
311
308
store_pool = POOL_PERM;
312
store_pool = POOL_MESSAGE;
309
313
310
/* Delete eventual previous signature chain */
314
/* Delete eventual previous signature chain */
311
315
(-)exim.orig/src/dkim_transport.c (-1 / +2 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 169-175 Link Here
169
#ifdef EXPERIMENTAL_ARC
170
#ifdef EXPERIMENTAL_ARC
170
if (dkim->arc_signspec)			/* Prepend ARC headers */
171
if (dkim->arc_signspec)			/* Prepend ARC headers */
171
  {
172
  {
172
  uschar * e;
173
  uschar * e = NULL;
173
  if (!(dkim_signature = arc_sign(dkim->arc_signspec, dkim_signature, &e)))
174
  if (!(dkim_signature = arc_sign(dkim->arc_signspec, dkim_signature, &e)))
174
    {
175
    {
175
    *err = e;
176
    *err = e;
(-)exim.orig/src/dmarc.c (-23 / +36 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
/* DMARC support.
4
/* DMARC support.
5
   Copyright (c) The Exim Maintainers 2019 - 2022
5
   Copyright (c) Todd Lyons <tlyons@exim.org> 2012 - 2014
6
   Copyright (c) Todd Lyons <tlyons@exim.org> 2012 - 2014
6
   Copyright (c) The Exim Maintainers 2019
7
   License: GPL */
7
   License: GPL */
8
8
9
/* Portions Copyright (c) 2012, 2013, The Trusted Domain Project;
9
/* Portions Copyright (c) 2012, 2013, The Trusted Domain Project;
Lines 51-71 Link Here
51
  { US"reject",     DMARC_RECORD_P_REJECT },
51
  { US"reject",     DMARC_RECORD_P_REJECT },
52
  { NULL,           0 }
52
  { NULL,           0 }
53
};
53
};
54
55
56
gstring *
57
dmarc_version_report(gstring * g)
58
{
59
return string_fmt_append(g, "Library version: dmarc: Compile: %d.%d.%d.%d\n",
60
    (OPENDMARC_LIB_VERSION & 0xff000000) >> 24, (OPENDMARC_LIB_VERSION & 0x00ff0000) >> 16,
61
    (OPENDMARC_LIB_VERSION & 0x0000ff00) >> 8, OPENDMARC_LIB_VERSION & 0x000000ff);
62
}
63
64
54
/* Accept an error_block struct, initialize if empty, parse to the
65
/* Accept an error_block struct, initialize if empty, parse to the
55
 * end, and append the two strings passed to it.  Used for adding
66
end, and append the two strings passed to it.  Used for adding
56
 * variable amounts of value:pair data to the forensic emails. */
67
variable amounts of value:pair data to the forensic emails. */
57
68
58
static error_block *
69
static error_block *
59
add_to_eblock(error_block *eblock, uschar *t1, uschar *t2)
70
add_to_eblock(error_block *eblock, uschar *t1, uschar *t2)
60
{
71
{
61
error_block *eb = store_malloc(sizeof(error_block));
72
error_block *eb = store_malloc(sizeof(error_block));
62
if (eblock == NULL)
73
if (!eblock)
63
  eblock = eb;
74
  eblock = eb;
64
else
75
else
65
  {
76
  {
66
  /* Find the end of the eblock struct and point it at eb */
77
  /* Find the end of the eblock struct and point it at eb */
67
  error_block *tmp = eblock;
78
  error_block *tmp = eblock;
68
  while(tmp->next != NULL)
79
  while(tmp->next)
69
    tmp = tmp->next;
80
    tmp = tmp->next;
70
  tmp->next = eb;
81
  tmp->next = eb;
71
  }
82
  }
Lines 76-83 Link Here
76
}
87
}
77
88
78
/* dmarc_init sets up a context that can be re-used for several
89
/* dmarc_init sets up a context that can be re-used for several
79
   messages on the same SMTP connection (that come from the
90
messages on the same SMTP connection (that come from the
80
   same host with the same HELO string) */
91
same host with the same HELO string) */
81
92
82
int
93
int
83
dmarc_init()
94
dmarc_init()
Lines 218-224 Link Here
218
  for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr;
229
  for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr;
219
       rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
230
       rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
220
    if (rr->type == T_TXT && rr->size > 3)
231
    if (rr->type == T_TXT && rr->size > 3)
221
      return string_copyn(US rr->data, rr->size);
232
      {
233
      store_free_dns_answer(dnsa);
234
      return string_copyn_taint(US rr->data, rr->size, GET_TAINTED);
235
      }
236
store_free_dns_answer(dnsa);
222
return NULL;
237
return NULL;
223
}
238
}
224
239
Lines 226-231 Link Here
226
static int
241
static int
227
dmarc_write_history_file()
242
dmarc_write_history_file()
228
{
243
{
244
int history_file_fd;
245
ssize_t written_len;
229
int tmp_ans;
246
int tmp_ans;
230
u_char **rua; /* aggregate report addressees */
247
u_char **rua; /* aggregate report addressees */
231
uschar *history_buffer = NULL;
248
uschar *history_buffer = NULL;
Lines 235-240 Link Here
235
  DEBUG(D_receive) debug_printf("DMARC history file not set\n");
252
  DEBUG(D_receive) debug_printf("DMARC history file not set\n");
236
  return DMARC_HIST_DISABLED;
253
  return DMARC_HIST_DISABLED;
237
  }
254
  }
255
history_file_fd = log_open_as_exim(dmarc_history_file);
256
257
if (history_file_fd < 0)
258
  {
259
  log_write(0, LOG_MAIN|LOG_PANIC, "failure to create DMARC history file: %s",
260
			   dmarc_history_file);
261
  return DMARC_HIST_FILE_ERR;
262
  }
238
263
239
/* Generate the contents of the history file */
264
/* Generate the contents of the history file */
240
history_buffer = string_sprintf(
265
history_buffer = string_sprintf(
Lines 286-313 Link Here
286
  }
311
  }
287
else
312
else
288
  {
313
  {
289
  ssize_t written_len;
290
  const int history_file_fd = log_open_as_exim(dmarc_history_file);
291
292
  if (history_file_fd < 0)
293
    {
294
    log_write(0, LOG_MAIN|LOG_PANIC, "failure to create DMARC history file: %s",
295
			   dmarc_history_file);
296
    return DMARC_HIST_FILE_ERR;
297
    }
298
299
  written_len = write_to_fd_buf(history_file_fd,
314
  written_len = write_to_fd_buf(history_file_fd,
300
				history_buffer,
315
				history_buffer,
301
				Ustrlen(history_buffer));
316
				Ustrlen(history_buffer));
302
317
  if (written_len == 0)
303
  (void)close(history_file_fd);
304
305
  if (written_len <= 0)
306
    {
318
    {
307
    log_write(0, LOG_MAIN|LOG_PANIC, "failure to write to DMARC history file: %s",
319
    log_write(0, LOG_MAIN|LOG_PANIC, "failure to write to DMARC history file: %s",
308
			   dmarc_history_file);
320
			   dmarc_history_file);
309
    return DMARC_HIST_WRITE_ERR;
321
    return DMARC_HIST_WRITE_ERR;
310
    }
322
    }
323
  (void)close(history_file_fd);
311
  }
324
  }
312
return DMARC_HIST_OK;
325
return DMARC_HIST_OK;
313
}
326
}
Lines 517-523 Link Here
517
  /* Can't use exim's string manipulation functions so allocate memory
530
  /* Can't use exim's string manipulation functions so allocate memory
518
  for libopendmarc using its max hostname length definition. */
531
  for libopendmarc using its max hostname length definition. */
519
532
520
  dmarc_domain = store_get(DMARC_MAXHOSTNAMELEN, TRUE);
533
  dmarc_domain = store_get(DMARC_MAXHOSTNAMELEN, GET_TAINTED);
521
  libdm_status = opendmarc_policy_fetch_utilized_domain(dmarc_pctx,
534
  libdm_status = opendmarc_policy_fetch_utilized_domain(dmarc_pctx,
522
    dmarc_domain, DMARC_MAXHOSTNAMELEN-1);
535
    dmarc_domain, DMARC_MAXHOSTNAMELEN-1);
523
  store_release_above(dmarc_domain + Ustrlen(dmarc_domain)+1);
536
  store_release_above(dmarc_domain + Ustrlen(dmarc_domain)+1);
(-)exim.orig/src/dmarc.h (-3 / +2 lines)
Lines 3-8 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Experimental DMARC support.
5
/* Experimental DMARC support.
6
   Copyright (c) The Exim Maintainers 2021 - 2022
6
   Copyright (c) Todd Lyons <tlyons@exim.org> 2012 - 2014
7
   Copyright (c) Todd Lyons <tlyons@exim.org> 2012 - 2014
7
   License: GPL */
8
   License: GPL */
8
9
Lines 17-31 Link Here
17
# endif /* SUPPORT_SPF */
18
# endif /* SUPPORT_SPF */
18
19
19
/* prototypes */
20
/* prototypes */
21
gstring * dmarc_version_report(gstring *);
20
int dmarc_init();
22
int dmarc_init();
21
int dmarc_store_data(header_line *);
23
int dmarc_store_data(header_line *);
22
int dmarc_process();
24
int dmarc_process();
23
uschar *dmarc_exim_expand_query(int);
25
uschar *dmarc_exim_expand_query(int);
24
uschar *dmarc_exim_expand_defaults(int);
26
uschar *dmarc_exim_expand_defaults(int);
25
uschar *dmarc_auth_results_header(header_line *,uschar *);
26
static int dmarc_write_history_file();
27
27
28
#define DMARC_AR_HEADER        US"Authentication-Results:"
29
#define DMARC_VERIFY_STATUS    1
28
#define DMARC_VERIFY_STATUS    1
30
29
31
#define DMARC_HIST_OK          1
30
#define DMARC_HIST_OK          1
(-)exim.orig/src/dns.c (-61 / +49 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Functions for interfacing with the DNS. */
9
/* Functions for interfacing with the DNS. */
Lines 258-264 Link Here
258
  {
258
  {
259
  int v6[4];
259
  int v6[4];
260
260
261
  g = string_get_tainted(32, is_tainted(string));
261
  g = string_get_tainted(32, string);
262
  (void)host_aton(string, v6);
262
  (void)host_aton(string, v6);
263
263
264
  /* The original specification for IPv6 reverse lookup was to invert each
264
  /* The original specification for IPv6 reverse lookup was to invert each
Lines 334-340 Link Here
334
#ifdef rr_trace
334
#ifdef rr_trace
335
# define TRACE DEBUG(D_dns)
335
# define TRACE DEBUG(D_dns)
336
#else
336
#else
337
trace = trace;
338
# define TRACE if (FALSE)
337
# define TRACE if (FALSE)
339
#endif
338
#endif
340
339
Lines 638-644 Link Here
638
  e = previous->data.ptr;
637
  e = previous->data.ptr;
639
else
638
else
640
  {
639
  {
641
  e = store_get_perm(DNS_FAILNODE_SIZE, is_tainted(name));
640
  e = store_get_perm(DNS_FAILNODE_SIZE, name);
642
  new = (void *)(e+1);
641
  new = (void *)(e+1);
643
  dns_fail_tag(new->name, name, type);
642
  dns_fail_tag(new->name, name, type);
644
  new->data.ptr = e;
643
  new->data.ptr = e;
Lines 672-684 Link Here
672
val = e->data.val;
671
val = e->data.val;
673
rc = e->expiry && e->expiry <= time(NULL) ? -1 : val;
672
rc = e->expiry && e->expiry <= time(NULL) ? -1 : val;
674
673
675
DEBUG(D_dns) debug_printf("DNS lookup of %.255s-%s: %scached value %s%s\n",
674
DEBUG(D_dns) debug_printf("DNS lookup of %.255s (%s): %scached value %s%s\n",
676
  name, dns_text_type(type),
675
  name, dns_text_type(type),
677
  rc == -1 ? "" : "using ",
676
  rc == -1 ? "" : "using ",
678
    val == DNS_NOMATCH ? "DNS_NOMATCH" :
677
  dns_rc_names[val],
679
    val == DNS_NODATA ? "DNS_NODATA" :
680
    val == DNS_AGAIN ? "DNS_AGAIN" :
681
    val == DNS_FAIL ? "DNS_FAIL" : "??",
682
  rc == -1 ? " past valid time" : "");
678
  rc == -1 ? " past valid time" : "");
683
679
684
return rc;
680
return rc;
Lines 695-703 Link Here
695
replacement value. (The only way to fix this properly would be to
691
replacement value. (The only way to fix this properly would be to
696
re-implement res_search() and res_query() so that they don't muddle their
692
re-implement res_search() and res_query() so that they don't muddle their
697
success and packet length return values.) For added safety we only reset
693
success and packet length return values.) For added safety we only reset
698
the packet length if the packet header looks plausible. */
694
the packet length if the packet header looks plausible.
699
695
700
static void
696
Return TRUE iff it seemed ok */
697
698
static BOOL
701
fake_dnsa_len_for_fail(dns_answer * dnsa, int type)
699
fake_dnsa_len_for_fail(dns_answer * dnsa, int type)
702
{
700
{
703
const HEADER * h = (const HEADER *)dnsa->answer;
701
const HEADER * h = (const HEADER *)dnsa->answer;
Lines 714-720 Link Here
714
  DEBUG(D_dns) debug_printf("faking res_search(%s) response length as %d\n",
712
  DEBUG(D_dns) debug_printf("faking res_search(%s) response length as %d\n",
715
    dns_text_type(type), (int)sizeof(dnsa->answer));
713
    dns_text_type(type), (int)sizeof(dnsa->answer));
716
  dnsa->answerlen = sizeof(dnsa->answer);
714
  dnsa->answerlen = sizeof(dnsa->answer);
715
  return TRUE;
717
  }
716
  }
717
DEBUG(D_dns) debug_printf("DNS: couldn't fake dnsa len\n");
718
/* Maybe we should just do a second lookup for an SOA? */
719
return FALSE;
718
}
720
}
719
721
720
722
Lines 728-764 Link Here
728
{
730
{
729
dns_scan dnss;
731
dns_scan dnss;
730
732
731
fake_dnsa_len_for_fail(dnsa, type);
733
if (fake_dnsa_len_for_fail(dnsa, type))
734
  for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY);
735
       rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)
736
      ) if (rr->type == T_SOA)
737
    {
738
    const uschar * p = rr->data;
739
    uschar discard_buf[256];
740
    int len;
741
    unsigned long ttl;
742
743
    /* Skip the mname & rname strings */
744
745
    if ((len = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen,
746
	p, (DN_EXPAND_ARG4_TYPE)discard_buf, 256)) < 0)
747
      break;
748
    p += len;
749
    if ((len = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen,
750
	p, (DN_EXPAND_ARG4_TYPE)discard_buf, 256)) < 0)
751
      break;
752
    p += len;
753
754
    /* Skip the SOA serial, refresh, retry & expire.  Grab the TTL */
755
756
    if (p > dnsa->answer + dnsa->answerlen - 5 * INT32SZ)
757
      break;
758
    p += 4 * INT32SZ;
759
    GETLONG(ttl, p);
732
760
733
for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY);
761
    return time(NULL) + ttl;
734
     rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)
762
    }
735
    ) if (rr->type == T_SOA)
736
  {
737
  const uschar * p = rr->data;
738
  uschar discard_buf[256];
739
  int len;
740
  unsigned long ttl;
741
742
  /* Skip the mname & rname strings */
743
744
  if ((len = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen,
745
      p, (DN_EXPAND_ARG4_TYPE)discard_buf, 256)) < 0)
746
    break;
747
  p += len;
748
  if ((len = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen,
749
      p, (DN_EXPAND_ARG4_TYPE)discard_buf, 256)) < 0)
750
    break;
751
  p += len;
752
753
  /* Skip the SOA serial, refresh, retry & expire.  Grab the TTL */
754
755
  if (p > dnsa->answer + dnsa->answerlen - 5 * INT32SZ)
756
    break;
757
  p += 4 * INT32SZ;
758
  GETLONG(ttl, p);
759
763
760
  return time(NULL) + ttl;
761
  }
762
DEBUG(D_dns) debug_printf("DNS: no SOA record found for neg-TTL\n");
764
DEBUG(D_dns) debug_printf("DNS: no SOA record found for neg-TTL\n");
763
return 0;
765
return 0;
764
}
766
}
Lines 848-858 Link Here
848
850
849
if (check_dns_names_pattern[0] != 0 && type != T_PTR && type != T_TXT)
851
if (check_dns_names_pattern[0] != 0 && type != T_PTR && type != T_TXT)
850
  {
852
  {
851
  int ovector[3*(EXPAND_MAXN+1)];
852
853
  dns_pattern_init();
853
  dns_pattern_init();
854
  if (pcre_exec(regex_check_dns_names, NULL, CCS name, Ustrlen(name),
854
  if (!regex_match(regex_check_dns_names, name, -1, NULL))
855
      0, PCRE_EOPT, ovector, nelem(ovector)) < 0)
856
    {
855
    {
857
    DEBUG(D_dns)
856
    DEBUG(D_dns)
858
      debug_printf("DNS name syntax check failed: %s (%s)\n", name,
857
      debug_printf("DNS name syntax check failed: %s (%s)\n", name,
Lines 1066-1072 Link Here
1066
    return DNS_FAIL;
1065
    return DNS_FAIL;
1067
1066
1068
  /* DNS data comes from the outside, hence tainted */
1067
  /* DNS data comes from the outside, hence tainted */
1069
  data = store_get(256, TRUE);
1068
  data = store_get(256, GET_TAINTED);
1070
  if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen,
1069
  if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen,
1071
      cname_rr.data, (DN_EXPAND_ARG4_TYPE)data, 256) < 0)
1070
      cname_rr.data, (DN_EXPAND_ARG4_TYPE)data, 256) < 0)
1072
    return DNS_FAIL;
1071
    return DNS_FAIL;
Lines 1149-1155 Link Here
1149
  case T_CSA:
1148
  case T_CSA:
1150
    {
1149
    {
1151
    uschar *srvname, *namesuff, *tld;
1150
    uschar *srvname, *namesuff, *tld;
1152
    int priority, weight, port;
1151
    int priority, dummy_weight, port;
1153
    int limit, rc, i;
1152
    int limit, rc, i;
1154
    BOOL ipv6;
1153
    BOOL ipv6;
1155
    dns_record *rr;
1154
    dns_record *rr;
Lines 1203-1220 Link Here
1203
    If the TLD and the 2LD exist but the explicit CSA record lookup failed, then
1202
    If the TLD and the 2LD exist but the explicit CSA record lookup failed, then
1204
    the AUTHORITY SOA will be the 2LD's or a subdomain thereof. */
1203
    the AUTHORITY SOA will be the 2LD's or a subdomain thereof. */
1205
1204
1206
    if (rc == DNS_NOMATCH)
1205
    if (rc == DNS_NOMATCH) return DNS_NOMATCH;
1207
      {
1208
      fake_dnsa_len_for_fail(dnsa, T_CSA);
1209
1210
      for (rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY);
1211
	   rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)
1212
	  )
1213
	if (rr->type != T_SOA) continue;
1214
	else if (strcmpic(rr->name, US"") == 0 ||
1215
		 strcmpic(rr->name, tld) == 0) return DNS_NOMATCH;
1216
	else break;
1217
      }
1218
1206
1219
    for (i = 0; i < limit; i++)
1207
    for (i = 0; i < limit; i++)
1220
      {
1208
      {
Lines 1249-1255 Link Here
1249
1237
1250
	/* Extract the numerical SRV fields (p is incremented) */
1238
	/* Extract the numerical SRV fields (p is incremented) */
1251
	GETSHORT(priority, p);
1239
	GETSHORT(priority, p);
1252
	GETSHORT(weight, p);	weight = weight; /* compiler quietening */
1240
	GETSHORT(dummy_weight, p);
1253
	GETSHORT(port, p);
1241
	GETSHORT(port, p);
1254
1242
1255
	/* Check the CSA version number */
1243
	/* Check the CSA version number */
Lines 1305-1311 Link Here
1305
  if (p + 4 <= dnsa_lim)
1293
  if (p + 4 <= dnsa_lim)
1306
    {
1294
    {
1307
    /* the IP is not regarded as tainted */
1295
    /* the IP is not regarded as tainted */
1308
    yield = store_get(sizeof(dns_address) + 20, FALSE);
1296
    yield = store_get(sizeof(dns_address) + 20, GET_UNTAINTED);
1309
    (void)sprintf(CS yield->address, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
1297
    (void)sprintf(CS yield->address, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
1310
    yield->next = NULL;
1298
    yield->next = NULL;
1311
    }
1299
    }
Lines 1319-1325 Link Here
1319
    {
1307
    {
1320
    struct in6_addr in6;
1308
    struct in6_addr in6;
1321
    for (int i = 0; i < 16; i++) in6.s6_addr[i] = rr->data[i];
1309
    for (int i = 0; i < 16; i++) in6.s6_addr[i] = rr->data[i];
1322
    yield = store_get(sizeof(dns_address) + 50, FALSE);
1310
    yield = store_get(sizeof(dns_address) + 50, GET_UNTAINTED);
1323
    inet_ntop(AF_INET6, &in6, CS yield->address, 50);
1311
    inet_ntop(AF_INET6, &in6, CS yield->address, 50);
1324
    yield->next = NULL;
1312
    yield->next = NULL;
1325
    }
1313
    }
(-)exim.orig/src/drtables.c (-11 / +11 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 518-524 Link Here
518
static void
518
static void
519
addlookupmodule(void *dl, struct lookup_module_info *info)
519
addlookupmodule(void *dl, struct lookup_module_info *info)
520
{
520
{
521
struct lookupmodulestr *p = store_get(sizeof(struct lookupmodulestr), FALSE);
521
struct lookupmodulestr *p = store_get(sizeof(struct lookupmodulestr), GET_UNTAINTED);
522
522
523
p->dl = dl;
523
p->dl = dl;
524
p->info = info;
524
p->info = info;
Lines 602-608 Link Here
602
#if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
602
#if defined(LOOKUP_REDIS) && LOOKUP_REDIS!=2
603
extern lookup_module_info redis_lookup_module_info;
603
extern lookup_module_info redis_lookup_module_info;
604
#endif
604
#endif
605
#if defined(EXPERIMENTAL_LMDB)
605
#if defined(LOOKUP_LMDB)
606
extern lookup_module_info lmdb_lookup_module_info;
606
extern lookup_module_info lmdb_lookup_module_info;
607
#endif
607
#endif
608
#if defined(SUPPORT_SPF)
608
#if defined(SUPPORT_SPF)
Lines 698-704 Link Here
698
addlookupmodule(NULL, &redis_lookup_module_info);
698
addlookupmodule(NULL, &redis_lookup_module_info);
699
#endif
699
#endif
700
700
701
#ifdef EXPERIMENTAL_LMDB
701
#ifdef LOOKUP_LMDB
702
addlookupmodule(NULL, &lmdb_lookup_module_info);
702
addlookupmodule(NULL, &lmdb_lookup_module_info);
703
#endif
703
#endif
704
704
Lines 728-742 Link Here
728
  }
728
  }
729
else
729
else
730
  {
730
  {
731
  const pcre *regex_islookupmod = regex_must_compile(
731
  const pcre2_code *regex_islookupmod = regex_must_compile(
732
    US"\\." DYNLIB_FN_EXT "$", FALSE, TRUE);
732
    US"\\." DYNLIB_FN_EXT "$", FALSE, TRUE);
733
733
734
  DEBUG(D_lookup) debug_printf("Loading lookup modules from %s\n", LOOKUP_MODULE_DIR);
734
  DEBUG(D_lookup) debug_printf("Loading lookup modules from %s\n", LOOKUP_MODULE_DIR);
735
  while ((ent = readdir(dd)))
735
  while ((ent = readdir(dd)))
736
    {
736
    {
737
    char *name = ent->d_name;
737
    char * name = ent->d_name;
738
    int len = (int)strlen(name);
738
    int len = (int)strlen(name);
739
    if (pcre_exec(regex_islookupmod, NULL, name, len, 0, PCRE_EOPT, NULL, 0) >= 0)
739
    if (regex_match(regex_islookupmod, US name, len, NUL))
740
      {
740
      {
741
      int pathnamelen = len + (int)strlen(LOOKUP_MODULE_DIR) + 2;
741
      int pathnamelen = len + (int)strlen(LOOKUP_MODULE_DIR) + 2;
742
      void *dl;
742
      void *dl;
Lines 764-773 Link Here
764
	}
764
	}
765
765
766
      /* FreeBSD nsdispatch() can trigger dlerror() errors about
766
      /* FreeBSD nsdispatch() can trigger dlerror() errors about
767
       * _nss_cache_cycle_prevention_function; we need to clear the dlerror()
767
      _nss_cache_cycle_prevention_function; we need to clear the dlerror()
768
       * state before calling dlsym(), so that any error afterwards only
768
      state before calling dlsym(), so that any error afterwards only comes
769
       * comes from dlsym().
769
      from dlsym().  */
770
       */
770
771
      errormsg = dlerror();
771
      errormsg = dlerror();
772
772
773
      info = (struct lookup_module_info*) dlsym(dl, "_lookup_module_info");
773
      info = (struct lookup_module_info*) dlsym(dl, "_lookup_module_info");
(-)exim.orig/src/dummies.c (-14 / +1 lines)
Lines 3-8 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2009 */
5
/* Copyright (c) University of Cambridge 1995 - 2009 */
6
/* Copyright (c) The Exim Maintainers 2021 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
8
/* This file is not part of the main Exim code. There are little bits of test
9
/* This file is not part of the main Exim code. There are little bits of test
Lines 47-54 Link Here
47
vfprintf(stderr, format, ap);
48
vfprintf(stderr, format, ap);
48
fprintf(stderr, "\n");
49
fprintf(stderr, "\n");
49
va_end(ap);
50
va_end(ap);
50
selector = selector;     /* Keep picky compilers happy */
51
flags = flags;
52
}
51
}
53
52
54
53
Lines 103-109 Link Here
103
void
102
void
104
sigalrm_handler(int sig)
103
sigalrm_handler(int sig)
105
{
104
{
106
sig = sig;            /* Keep picky compilers happy */
107
sigalrm_seen = TRUE;
105
sigalrm_seen = TRUE;
108
}
106
}
109
107
Lines 116-134 Link Here
116
int
114
int
117
header_checkname(void *h, char *name, int len)
115
header_checkname(void *h, char *name, int len)
118
{
116
{
119
h = h;            /* Keep picky compilers happy */
120
name = name;
121
len = len;
122
return 0;
117
return 0;
123
}
118
}
124
119
125
void
120
void
126
directory_make(char *parent, char *name, int mode, int panic)
121
directory_make(char *parent, char *name, int mode, int panic)
127
{
122
{
128
parent = parent;  /* Keep picky compilers happy */
129
name = name;
130
mode = mode;
131
panic = panic;
132
}
123
}
133
124
134
void
125
void
Lines 140-149 Link Here
140
char *
131
char *
141
host_ntoa(int type, const void *arg, char *buffer, int *portptr)
132
host_ntoa(int type, const void *arg, char *buffer, int *portptr)
142
{
133
{
143
type = type;      /* Keep picky compilers happy */
144
arg = arg;
145
buffer = buffer;
146
portptr = portptr;
147
return NULL;
134
return NULL;
148
}
135
}
149
#endif
136
#endif
(-)exim.orig/src/EDITME (-35 / +36 lines)
Lines 198-204 Link Here
198
# the libraries and headers are installed, as the pkg-config .pc
198
# the libraries and headers are installed, as the pkg-config .pc
199
# specification should include all -L/-I information necessary.
199
# specification should include all -L/-I information necessary.
200
# Enabling the USE_*_PC options should be sufficient. If not using
200
# Enabling the USE_*_PC options should be sufficient. If not using
201
# pkg-config, then you have to specify the libraries, and you mmight
201
# pkg-config, then you have to specify the libraries, and you might
202
# need to specify the locations too.
202
# need to specify the locations too.
203
203
204
# Uncomment the following lines if you want
204
# Uncomment the following lines if you want
Lines 207-213 Link Here
207
# Unless you do this, you must define one of USE_OPENSSL or USE_GNUTLS
207
# Unless you do this, you must define one of USE_OPENSSL or USE_GNUTLS
208
# below.
208
# below.
209
209
210
# If you are buliding with TLS, the library configuration must be done:
210
# If you are building with TLS, the library configuration must be done:
211
211
212
# Uncomment this if you are using OpenSSL
212
# Uncomment this if you are using OpenSSL
213
# USE_OPENSSL=yes
213
# USE_OPENSSL=yes
Lines 276-281 Link Here
276
# specified in INCLUDE.
276
# specified in INCLUDE.
277
277
278
278
279
# Uncomment the following line to remove support for TLS Resumption
280
# DISABLE_TLS_RESUME=yes
281
279
282
280
###############################################################################
283
###############################################################################
281
#           THESE ARE THINGS YOU PROBABLY WANT TO SPECIFY                     #
284
#           THESE ARE THINGS YOU PROBABLY WANT TO SPECIFY                     #
Lines 411-416 Link Here
411
# LOOKUP_IBASE=yes
414
# LOOKUP_IBASE=yes
412
# LOOKUP_JSON=yes
415
# LOOKUP_JSON=yes
413
# LOOKUP_LDAP=yes
416
# LOOKUP_LDAP=yes
417
# LOOKUP_LMDB=yes
418
414
# LOOKUP_MYSQL=yes
419
# LOOKUP_MYSQL=yes
415
# LOOKUP_MYSQL_PC=mariadb
420
# LOOKUP_MYSQL_PC=mariadb
416
# LOOKUP_NIS=yes
421
# LOOKUP_NIS=yes
Lines 452-470 Link Here
452
457
453
458
454
#------------------------------------------------------------------------------
459
#------------------------------------------------------------------------------
455
# The PCRE library is required for Exim.  There is no longer an embedded
460
# The PCRE2 library is required for Exim.  There is no longer an embedded
456
# version of the PCRE library included with the source code, instead you
461
# version of the PCRE library included with the source code, instead you
457
# must use a system library or build your own copy of PCRE.
462
# must use a system library or build your own copy of PCRE2.
458
# In either case you must specify the library link info here.  If the
463
# In either case you must specify the library link info here.  If the
459
# PCRE header files are not in the standard search path you must also
464
# PCRE2 header files are not in the standard search path you must also
460
# modify the INCLUDE path (above)
465
# modify the INCLUDE path (above)
461
#
466
#
462
# Use PCRE_CONFIG to query the pcre-config command (first found in $PATH)
467
# Use PCRE_CONFIG to query the pcre-config command (first found in $PATH)
463
# to find the include files and libraries, else use PCRE_LIBS and set INCLUDE
468
# to find the include files and libraries, else use PCRE_LIBS and set INCLUDE
464
# too if needed.
469
# too if needed.
465
470
466
PCRE_CONFIG=yes
471
PCRE2_CONFIG=yes
467
# PCRE_LIBS=-lpcre
472
# PCRE_LIBS=-lpcre2
468
473
469
474
470
#------------------------------------------------------------------------------
475
#------------------------------------------------------------------------------
Lines 487-493 Link Here
487
# You do not need to use this for any lookup information added via pkg-config.
492
# You do not need to use this for any lookup information added via pkg-config.
488
493
489
# LOOKUP_INCLUDE=-I /usr/local/ldap/include -I /usr/local/mysql/include -I /usr/local/pgsql/include
494
# LOOKUP_INCLUDE=-I /usr/local/ldap/include -I /usr/local/mysql/include -I /usr/local/pgsql/include
490
# LOOKUP_LIBS=-L/usr/local/lib -lldap -llber -lmysqlclient -lpq -lgds -lsqlite3
495
# LOOKUP_INCLUDE +=-I /usr/local/include
496
# LOOKUP_LIBS=-L/usr/local/lib -lldap -llber -lmysqlclient -lpq -lgds -lsqlite3 -llmdb
497
498
#------------------------------------------------------------------------------
499
# If you included LOOKUP_LMDB above you will need the library. Depending
500
# on where installed you may also need an include directory
501
#
502
# LOOKUP_INCLUDE += -I/usr/local/include
503
# LOOKUP_LIBS += -llmdb
491
504
492
505
493
#------------------------------------------------------------------------------
506
#------------------------------------------------------------------------------
Lines 560-566 Link Here
560
# DISABLE_DNSSEC=yes
573
# DISABLE_DNSSEC=yes
561
574
562
# To disable support for Events set DISABLE_EVENT to "yes"
575
# To disable support for Events set DISABLE_EVENT to "yes"
563
564
# DISABLE_EVENT=yes
576
# DISABLE_EVENT=yes
565
577
566
578
Lines 569-574 Link Here
569
# DISABLE_PIPE_CONNECT=yes
581
# DISABLE_PIPE_CONNECT=yes
570
582
571
583
584
# Uncomment the following to remove the fast-ramp two-phase-queue-run support
585
# DISABLE_QUEUE_RAMP=yes
586
587
# Uncomment the following lines to add SRS (Sender Rewriting Scheme) support
588
# using only native facilities.
589
# SUPPORT_SRS=yes
590
591
572
#------------------------------------------------------------------------------
592
#------------------------------------------------------------------------------
573
# Compiling Exim with experimental features. These are documented in
593
# Compiling Exim with experimental features. These are documented in
574
# experimental-spec.txt. "Experimental" means that the way these features are
594
# experimental-spec.txt. "Experimental" means that the way these features are
Lines 580-600 Link Here
580
600
581
# EXPERIMENTAL_DCC=yes
601
# EXPERIMENTAL_DCC=yes
582
602
583
# Uncomment the following lines to add SRS (Sender rewriting scheme) support.
584
# You need to have libsrs_alt installed on your system (srs.mirtol.com).
585
# Depending on where it is installed you may have to edit the CFLAGS and
586
# LDFLAGS lines.
587
588
# EXPERIMENTAL_SRS=yes
589
# CFLAGS  += -I/usr/local/include
590
# LDFLAGS += -lsrs_alt
591
592
# Uncomment the following lines to add SRS (Sender rewriting scheme) support
593
# using only native facilities.
594
# EXPERIMENTAL_SRS_NATIVE=yes
595
596
# Uncomment the following line to add DMARC checking capability, implemented
603
# Uncomment the following line to add DMARC checking capability, implemented
597
# using libopendmarc libraries. You must have SPF and DKIM support enabled also.
604
# using libopendmarc libraries. You must have SPF and DKIM support enabled also.
605
# Library version libopendmarc-1.4.1-1.fc33.x86_64  (on Fedora 33) is known broken;
606
# 1.3.2-3 works.  I seems that the OpenDMARC project broke their API.
598
# SUPPORT_DMARC=yes
607
# SUPPORT_DMARC=yes
599
# CFLAGS += -I/usr/local/include
608
# CFLAGS += -I/usr/local/include
600
# LDFLAGS += -lopendmarc
609
# LDFLAGS += -lopendmarc
Lines 618-639 Link Here
618
# Uncomment the following to include extra information in fail DSN message (bounces)
627
# Uncomment the following to include extra information in fail DSN message (bounces)
619
# EXPERIMENTAL_DSN_INFO=yes
628
# EXPERIMENTAL_DSN_INFO=yes
620
629
621
# Uncomment the following to add LMDB lookup support
622
# You need to have LMDB installed on your system (https://github.com/LMDB/lmdb)
623
# Depending on where it is installed you may have to edit the CFLAGS and LDFLAGS lines.
624
# EXPERIMENTAL_LMDB=yes
625
# CFLAGS += -I/usr/local/include
626
# LDFLAGS += -llmdb
627
628
# Uncomment the following line to add queuefile transport support
630
# Uncomment the following line to add queuefile transport support
629
# EXPERIMENTAL_QUEUEFILE=yes
631
# EXPERIMENTAL_QUEUEFILE=yes
630
632
631
# Uncomment the following line to include support for TLS Resumption
632
# EXPERIMENTAL_TLS_RESUME=yes
633
634
# Uncomment the following to include the fast-ramp two-phase-queue-run support
635
# EXPERIMENTAL_QUEUE_RAMP=yes
636
637
###############################################################################
633
###############################################################################
638
#                 THESE ARE THINGS YOU MIGHT WANT TO SPECIFY                  #
634
#                 THESE ARE THINGS YOU MIGHT WANT TO SPECIFY                  #
639
###############################################################################
635
###############################################################################
Lines 1493-1496 Link Here
1493
# For development, add this to include code to time various stages and report.
1489
# For development, add this to include code to time various stages and report.
1494
# CFLAGS += -DMEASURE_TIMING
1490
# CFLAGS += -DMEASURE_TIMING
1495
1491
1492
# For a very slightly smaller build, for constrained systems, uncomment this.
1493
# The feature involved is purely for debugging.
1494
1495
# DISABLE_CLIENT_CMD_LOG=yes
1496
1496
# End of EDITME for Exim 4.
1497
# End of EDITME for Exim 4.
(-)exim.orig/src/enq.c (-2 / +3 lines)
Lines 3-8 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2015 */
5
/* Copyright (c) University of Cambridge 1995 - 2015 */
6
/* Copyright (c) The Exim Maintainers 2021 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
8
/* Functions concerned with serialization. */
9
/* Functions concerned with serialization. */
Lines 53-59 Link Here
53
/* See if there is a record for this host or queue run; if there is, we cannot
54
/* See if there is a record for this host or queue run; if there is, we cannot
54
proceed with the connection unless the record is very old. */
55
proceed with the connection unless the record is very old. */
55
56
56
serial_record = dbfn_read(dbm_file, key);
57
serial_record = dbfn_read_enforce_length(dbm_file, key, sizeof(dbdata_serialize));
57
if (serial_record && time(NULL) - serial_record->time_stamp < 6*60*60)
58
if (serial_record && time(NULL) - serial_record->time_stamp < 6*60*60)
58
  {
59
  {
59
  if (serial_record->count >= lim)
60
  if (serial_record->count >= lim)
Lines 102-108 Link Here
102
DEBUG(D_transport) debug_printf("end serialized: %s\n", key);
103
DEBUG(D_transport) debug_printf("end serialized: %s\n", key);
103
104
104
if (  !(dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE))
105
if (  !(dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE))
105
   || !(serial_record = dbfn_read(dbm_file, key))
106
   || !(serial_record = dbfn_read_enforce_length(dbm_file, key, sizeof(dbdata_serialize)))
106
   )
107
   )
107
  return;
108
  return;
108
if (--serial_record->count > 0)
109
if (--serial_record->count > 0)
(-)exim.orig/src/exigrep.src (-67 / +71 lines)
Lines 9-15 Link Here
9
use File::Basename;
9
use File::Basename;
10
10
11
# Copyright (c) 2007-2017 University of Cambridge.
11
# Copyright (c) 2007-2017 University of Cambridge.
12
# Copyright (c) The Exim Maintainers 2020
12
# Copyright (c) The Exim Maintainers 2020 - 2021
13
# See the file NOTICE for conditions of use and distribution.
13
# See the file NOTICE for conditions of use and distribution.
14
14
15
# Except when they appear in comments, the following placeholders in this
15
# Except when they appear in comments, the following placeholders in this
Lines 45-64 Link Here
45
# the number of seconds since the epoch. It handles optional timezone
45
# the number of seconds since the epoch. It handles optional timezone
46
# information.
46
# information.
47
47
48
sub seconds {
48
sub seconds
49
my($year,$month,$day,$hour,$min,$sec,$tzs,$tzh,$tzm) =
49
  {
50
  $_[0] =~ /^(\d{4})-(\d\d)-(\d\d)\s(\d\d):(\d\d):(\d\d)(?:.\d+)?(?>\s([+-])(\d\d)(\d\d))?/o;
50
  my($year,$month,$day,$hour,$min,$sec,$tzs,$tzh,$tzm) =
51
    $_[0] =~ /^(\d{4})-(\d\d)-(\d\d)\s(\d\d):(\d\d):(\d\d)(?:.\d+)?(?>\s([+-])(\d\d)(\d\d))?/o;
51
52
52
my $seconds = mktime $sec, $min, $hour, $day, $month - 1, $year - 1900;
53
  my $seconds = mktime $sec, $min, $hour, $day, $month - 1, $year - 1900;
53
54
54
if (defined $tzs)
55
  if (defined $tzs)
55
  {
56
    {
56
  $seconds -= $tzh * 3600 + $tzm * 60 if $tzs eq "+";
57
    $seconds -= $tzh * 3600 + $tzm * 60 if $tzs eq "+";
57
  $seconds += $tzh * 3600 + $tzm * 60 if $tzs eq "-";
58
    $seconds += $tzh * 3600 + $tzm * 60 if $tzs eq "-";
58
  }
59
    }
59
60
60
return $seconds;
61
  return $seconds;
61
}
62
  }
62
63
63
64
64
# This subroutine processes a single line (in $_) from a log file. Program
65
# This subroutine processes a single line (in $_) from a log file. Program
Lines 78-154 Link Here
78
my $related_re='';
79
my $related_re='';
79
my @Mids = ();
80
my @Mids = ();
80
81
81
sub do_line {
82
sub do_line
83
  {
82
84
83
# Convert syslog lines to mainlog format, as in eximstats.
85
  # Convert syslog lines to mainlog format, as in eximstats.
84
86
85
if (!/^\d{4}-/o) { $_ =~ s/^.*? exim\b.*?: //o; }
87
  if (!/^\d{4}-/o) { $_ =~ s/^.*? exim\b.*?: //o; }
86
88
87
return unless
89
  return unless
88
  my($date,$id) = /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d(?:\.\d+)? (?:[+-]\d{4} )?)(?:\[\d+\] )?(\w{6}\-\w{6}\-\w{2})?/o;
90
    my($date,$id) = /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d(?:\.\d+)? (?:[+-]\d{4} )?)(?:\[\d+\] )?(\w{6}\-\w{6}\-\w{2})?/o;
89
91
90
# Handle the case when the log line belongs to a specific message. We save
92
  # Handle the case when the log line belongs to a specific message. We save
91
# lines for specific messages until the message is complete. Then either print
93
  # lines for specific messages until the message is complete. Then either print
92
# or discard.
94
  # or discard.
93
95
94
if (defined $id)
96
  if (defined $id)
95
  {
97
    {
96
  $saved{$id} = '' unless defined($saved{$id});
98
    $saved{$id} = '' unless defined($saved{$id});
97
99
98
  # Save up the data for this message in case it becomes interesting later.
100
    # Save up the data for this message in case it becomes interesting later.
99
101
100
  $saved{$id} .= $_;
102
    $saved{$id} .= $_;
101
103
102
  # Are we interested in this id ? Short circuit if we already were interested.
104
    # Are we interested in this id ? Short circuit if we already were interested.
103
105
104
  if ($invert)
106
    if ($invert)
105
    {
106
    $id_list{$id} = 1 if (!defined($id_list{$id}));
107
    $id_list{$id} = 0 if (($insensitive && /$pattern/io) || /$pattern/o);
108
    }
109
  else
110
    {
111
    if (defined $id_list{$id} ||
112
      ($insensitive && /$pattern/io) || /$pattern/o)
113
      {
107
      {
114
      $id_list{$id} = 1;
108
      $id_list{$id} = 1 if (!defined($id_list{$id}));
115
      get_related_ids($id) if $related;
109
      $id_list{$id} = 0 if (($insensitive && /$pattern/io) || /$pattern/o);
116
      }
110
      }
117
    elsif ($related && $related_re)
111
    else
118
      {
112
      {
119
      grep_for_related($_, $id);
113
      if (defined $id_list{$id} ||
114
	($insensitive && /$pattern/io) || /$pattern/o)
115
	{
116
	$id_list{$id} = 1;
117
	get_related_ids($id) if $related;
118
	}
119
      elsif ($related && $related_re)
120
	{
121
	grep_for_related($_, $id);
122
	}
120
      }
123
      }
121
    }
122
124
123
  # See if this is a completion for some message. If it is interesting,
125
    # See if this is a completion for some message. If it is interesting,
124
  # print it, but in any event, throw away what was saved.
126
    # print it, but in any event, throw away what was saved.
125
127
126
  if (index($_, 'Completed') != -1 ||
128
    if (index($_, 'Completed') != -1 ||
127
      index($_, 'SMTP data timeout') != -1 ||
129
	index($_, 'SMTP data timeout') != -1 ||
128
        (index($_, 'rejected') != -1 &&
130
	  (index($_, 'rejected') != -1 &&
129
          /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d(?:\.\d+)? (?:[+-]\d{4} )?)(?:\[\d+\] )?\w{6}\-\w{6}\-\w{2} rejected/o))
131
	    /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d(?:\.\d+)? (?:[+-]\d{4} )?)(?:\[\d+\] )?\w{6}\-\w{6}\-\w{2} rejected/o))
130
    {
131
    if ($queue_time != -1 &&
132
        $saved{$id} =~ /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d ([+-]\d{4} )?)/o)
133
      {
132
      {
134
      my $old_sec = &seconds($1);
133
      if ($queue_time != -1 &&
135
      my $sec = &seconds($date);
134
	  $saved{$id} =~ /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d ([+-]\d{4} )?)/o)
136
      $id_list{$id} = 0 if $id_list{$id} && $sec - $old_sec <= $queue_time;
135
	{
136
	my $old_sec = &seconds($1);
137
	my $sec = &seconds($date);
138
	$id_list{$id} = 0 if $id_list{$id} && $sec - $old_sec <= $queue_time;
139
	}
140
141
      print "$saved{$id}\n" if ($id_list{$id});
142
      delete $id_list{$id};
143
      delete $saved{$id};
137
      }
144
      }
138
139
    print "$saved{$id}\n" if ($id_list{$id});
140
    delete $id_list{$id};
141
    delete $saved{$id};
142
    }
145
    }
143
  }
144
146
145
# Handle the case where the log line does not belong to a specific message.
147
  # Handle the case where the log line does not belong to a specific message.
146
# Print it if it is interesting.
148
  # Print it if it is interesting.
147
149
148
elsif ( ($invert && (($insensitive && !/$pattern/io) || !/$pattern/o)) ||
150
  elsif ( ($invert && (($insensitive && !/$pattern/io) || !/$pattern/o)) ||
149
       (!$invert && (($insensitive &&  /$pattern/io) ||  /$pattern/o)) )
151
	 (!$invert && (($insensitive &&  /$pattern/io) ||  /$pattern/o)) )
150
  { print "$_\n"; }
152
    { print "$_\n"; }
151
}
153
  }
152
154
153
# Rotated log files are frequently compressed and there are a variety of
155
# Rotated log files are frequently compressed and there are a variety of
154
# formats it could be compressed with. Rather than use just one that is
156
# formats it could be compressed with. Rather than use just one that is
Lines 200-216 Link Here
200
  return $cmdline;
202
  return $cmdline;
201
  }
203
  }
202
204
203
sub grep_for_related {
205
sub grep_for_related
206
  {
204
  my ($line,$id) = @_;
207
  my ($line,$id) = @_;
205
  $id_list{$id} = 1 if $line =~ m/$related_re/;
208
  $id_list{$id} = 1 if $line =~ m/$related_re/;
206
}
209
  }
207
210
208
sub get_related_ids {
211
sub get_related_ids
212
  {
209
  my ($id) = @_;
213
  my ($id) = @_;
210
  push @Mids, $id unless grep /\b$id\b/, @Mids;
214
  push @Mids, $id unless grep /\b$id\b/, @Mids;
211
  my $re = join '|', @Mids;
215
  my $re = join '|', @Mids;
212
  $related_re = qr/$re/;
216
  $related_re = qr/$re/;
213
}
217
  }
214
218
215
# The main program. Extract the pattern and make sure any relevant characters
219
# The main program. Extract the pattern and make sure any relevant characters
216
# are quoted if the -l flag is given. The -t flag gives a time-on-queue value
220
# are quoted if the -l flag is given. The -t flag gives a time-on-queue value
(-)exim.orig/src/exim.c (-331 / +574 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 40-70 Link Here
40
for store allocation via Exim's store manager. The normal calls are actually
40
for store allocation via Exim's store manager. The normal calls are actually
41
macros that pass over location information to make tracing easier. These
41
macros that pass over location information to make tracing easier. These
42
functions just interface to the standard macro calls. A good compiler will
42
functions just interface to the standard macro calls. A good compiler will
43
optimize out the tail recursion and so not make them too expensive. There
43
optimize out the tail recursion and so not make them too expensive. */
44
are two sets of functions; one for use when we want to retain the compiled
45
regular expression for a long time; the other for short-term use. */
46
44
47
static void *
45
static void *
48
function_store_get(size_t size)
46
function_store_malloc(PCRE2_SIZE size, void * tag)
49
{
50
/* For now, regard all RE results as potentially tainted.  We might need
51
more intelligence on this point. */
52
return store_get((int)size, TRUE);
53
}
54
55
static void
56
function_dummy_free(void *block) { block = block; }
57
58
static void *
59
function_store_malloc(size_t size)
60
{
47
{
61
return store_malloc((int)size);
48
return store_malloc((int)size);
62
}
49
}
63
50
64
static void
51
static void
65
function_store_free(void *block)
52
function_store_free(void * block, void * tag)
66
{
53
{
67
store_free(block);
54
/* At least some version of pcre2 pass a null pointer */
55
if (block) store_free(block);
68
}
56
}
69
57
70
58
Lines 98-126 Link Here
98
Returns:      pointer to the compiled pattern
86
Returns:      pointer to the compiled pattern
99
*/
87
*/
100
88
101
const pcre *
89
const pcre2_code *
102
regex_must_compile(const uschar *pattern, BOOL caseless, BOOL use_malloc)
90
regex_must_compile(const uschar * pattern, BOOL caseless, BOOL use_malloc)
103
{
91
{
104
int offset;
92
size_t offset;
105
int options = PCRE_COPT;
93
int options = caseless ? PCRE_COPT|PCRE2_CASELESS : PCRE_COPT;
106
const pcre *yield;
94
const pcre2_code * yield;
107
const uschar *error;
95
int err;
96
pcre2_general_context * gctx;
97
pcre2_compile_context * cctx;
98
108
if (use_malloc)
99
if (use_malloc)
109
  {
100
  {
110
  pcre_malloc = function_store_malloc;
101
  gctx = pcre2_general_context_create(function_store_malloc, function_store_free, NULL);
111
  pcre_free = function_store_free;
102
  cctx = pcre2_compile_context_create(gctx);
112
  }
103
  }
113
if (caseless) options |= PCRE_CASELESS;
104
else
114
yield = pcre_compile(CCS pattern, options, CCSS &error, &offset, NULL);
105
  cctx = pcre_cmp_ctx;
115
pcre_malloc = function_store_get;
106
116
pcre_free = function_dummy_free;
107
if (!(yield = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, options,
117
if (yield == NULL)
108
  &err, &offset, cctx)))
109
  {
110
  uschar errbuf[128];
111
  pcre2_get_error_message(err, errbuf, sizeof(errbuf));
118
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "regular expression error: "
112
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "regular expression error: "
119
    "%s at offset %d while compiling %s", error, offset, pattern);
113
    "%s at offset %ld while compiling %s", errbuf, (long)offset, pattern);
114
  }
115
116
if (use_malloc)
117
  {
118
  pcre2_compile_context_free(cctx);
119
  pcre2_general_context_free(gctx);
120
  }
120
return yield;
121
return yield;
121
}
122
}
122
123
123
124
125
static void
126
pcre_init(void)
127
{
128
pcre_gen_ctx = pcre2_general_context_create(function_store_malloc, function_store_free, NULL);
129
pcre_cmp_ctx = pcre2_compile_context_create(pcre_gen_ctx);
130
pcre_mtc_ctx = pcre2_match_context_create(pcre_gen_ctx);
131
}
132
133
124
134
125
135
126
/*************************************************
136
/*************************************************
Lines 128-134 Link Here
128
*************************************************/
138
*************************************************/
129
139
130
/* This function runs a regular expression match, and sets up the pointers to
140
/* This function runs a regular expression match, and sets up the pointers to
131
the matched substrings.
141
the matched substrings.  The matched strings are copied so the lifetime of
142
the subject is not a problem.
132
143
133
Arguments:
144
Arguments:
134
  re          the compiled expression
145
  re          the compiled expression
Lines 138-169 Link Here
138
              if >= 0 setup from setup+1 onwards,
149
              if >= 0 setup from setup+1 onwards,
139
                excluding the full matched string
150
                excluding the full matched string
140
151
141
Returns:      TRUE or FALSE
152
Returns:      TRUE if matched, or FALSE
142
*/
153
*/
143
154
144
BOOL
155
BOOL
145
regex_match_and_setup(const pcre *re, const uschar *subject, int options, int setup)
156
regex_match_and_setup(const pcre2_code * re, const uschar * subject, int options, int setup)
146
{
157
{
147
int ovector[3*(EXPAND_MAXN+1)];
158
pcre2_match_data * md = pcre2_match_data_create_from_pattern(re, pcre_gen_ctx);
148
uschar * s = string_copy(subject);	/* de-constifying */
159
int res = pcre2_match(re, (PCRE2_SPTR)subject, PCRE2_ZERO_TERMINATED, 0,
149
int n = pcre_exec(re, NULL, CS s, Ustrlen(s), 0,
160
			PCRE_EOPT | options, md, pcre_mtc_ctx);
150
  PCRE_EOPT | options, ovector, nelem(ovector));
161
BOOL yield;
151
BOOL yield = n >= 0;
162
152
if (n == 0) n = EXPAND_MAXN + 1;
163
if ((yield = (res >= 0)))
153
if (yield)
154
  {
164
  {
165
  res = pcre2_get_ovector_count(md);
155
  expand_nmax = setup < 0 ? 0 : setup + 1;
166
  expand_nmax = setup < 0 ? 0 : setup + 1;
156
  for (int nn = setup < 0 ? 0 : 2; nn < n*2; nn += 2)
167
  for (int matchnum = setup < 0 ? 0 : 1; matchnum < res; matchnum++)
157
    {
168
    {
158
    expand_nstring[expand_nmax] = s + ovector[nn];
169
    PCRE2_SIZE len;
159
    expand_nlength[expand_nmax++] = ovector[nn+1] - ovector[nn];
170
    pcre2_substring_get_bynumber(md, matchnum,
171
      (PCRE2_UCHAR **)&expand_nstring[expand_nmax], &len);
172
    expand_nlength[expand_nmax++] = (int)len;
160
    }
173
    }
161
  expand_nmax--;
174
  expand_nmax--;
162
  }
175
  }
176
else if (res != PCRE2_ERROR_NOMATCH) DEBUG(D_any)
177
  {
178
  uschar errbuf[128];
179
  pcre2_get_error_message(res, errbuf, sizeof(errbuf));
180
  debug_printf_indent("pcre2: %s\n", errbuf);
181
  }
182
pcre2_match_data_free(md);
163
return yield;
183
return yield;
164
}
184
}
165
185
166
186
187
/* Check just for match with regex.  Uses the common memory-handling.
188
189
Arguments:
190
	re	compiled regex
191
	subject	string to be checked
192
	slen	length of subject; -1 for nul-terminated
193
	rptr	pointer for matched string, copied, or NULL
194
195
Return: TRUE for a match.
196
*/
197
198
BOOL
199
regex_match(const pcre2_code * re, const uschar * subject, int slen, uschar ** rptr)
200
{
201
pcre2_match_data * md = pcre2_match_data_create(1, pcre_gen_ctx);
202
int rc = pcre2_match(re, (PCRE2_SPTR)subject,
203
		      slen >= 0 ? slen : PCRE2_ZERO_TERMINATED,
204
		      0, PCRE_EOPT, md, pcre_mtc_ctx);
205
PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md);
206
if (rc < 0)
207
  return FALSE;
208
if (rptr)
209
  *rptr = string_copyn(subject + ovec[0], ovec[1] - ovec[0]);
210
return TRUE;
211
}
212
167
213
168
214
169
/*************************************************
215
/*************************************************
Lines 211-216 Link Here
211
}
257
}
212
258
213
259
260
/***********************************************
261
*            Handler for SIGSEGV               *
262
***********************************************/
263
264
static void
265
#ifdef SA_SIGINFO
266
segv_handler(int sig, siginfo_t * info, void * uctx)
267
{
268
log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (fault address: %p)", info->si_addr);
269
# if defined(SEGV_MAPERR) && defined(SEGV_ACCERR) && defined(SEGV_BNDERR) && defined(SEGV_PKUERR)
270
switch (info->si_code)
271
  {
272
  case SEGV_MAPERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_MAPERR"); break;
273
  case SEGV_ACCERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_ACCERR"); break;
274
  case SEGV_BNDERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_BNDERR"); break;
275
  case SEGV_PKUERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_PKUERR"); break;
276
  }
277
# endif
278
if (US info->si_addr < US 4096)
279
  log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (null pointer indirection)");
280
else
281
  log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (maybe attempt to write to immutable memory)");
282
if (process_info_len > 0)
283
  log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (%.*s)", process_info_len, process_info);
284
signal(SIGSEGV, SIG_DFL);
285
kill(getpid(), sig);
286
}
287
288
#else
289
segv_handler(int sig)
290
{
291
log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (maybe attempt to write to immutable memory)");
292
if (process_info_len > 0)
293
  log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (%.*s)", process_info_len, process_info);
294
signal(SIGSEGV, SIG_DFL);
295
kill(getpid(), sig);
296
}
297
#endif
298
299
214
/*************************************************
300
/*************************************************
215
*             Handler for SIGUSR1                *
301
*             Handler for SIGUSR1                *
216
*************************************************/
302
*************************************************/
Lines 269-275 Link Here
269
void
355
void
270
sigalrm_handler(int sig)
356
sigalrm_handler(int sig)
271
{
357
{
272
sig = sig;      /* Keep picky compilers happy */
273
sigalrm_seen = TRUE;
358
sigalrm_seen = TRUE;
274
os_non_restarting_signal(SIGALRM, sigalrm_handler);
359
os_non_restarting_signal(SIGALRM, sigalrm_handler);
275
}
360
}
Lines 432-440 Link Here
432
clocks that go backwards.
517
clocks that go backwards.
433
518
434
Arguments:
519
Arguments:
435
  tgt_tv       A timeval which was used to create uniqueness; its usec field
520
  prev_tv      A timeval which was used to create uniqueness; its usec field
436
                 has been rounded down to the value of the resolution.
521
                 has been rounded down to the value of the resolution.
437
                 We want to be sure the current time is greater than this.
522
                 We want to be sure the current time is greater than this.
523
		 On return, updated to current (rounded down).
438
  resolution   The resolution that was used to divide the microseconds
524
  resolution   The resolution that was used to divide the microseconds
439
                 (1 for maildir, larger for message ids)
525
                 (1 for maildir, larger for message ids)
440
526
Lines 442-448 Link Here
442
*/
528
*/
443
529
444
void
530
void
445
exim_wait_tick(struct timeval * tgt_tv, int resolution)
531
exim_wait_tick(struct timeval * prev_tv, int resolution)
446
{
532
{
447
struct timeval now_tv;
533
struct timeval now_tv;
448
long int now_true_usec;
534
long int now_true_usec;
Lines 451-463 Link Here
451
now_true_usec = now_tv.tv_usec;
537
now_true_usec = now_tv.tv_usec;
452
now_tv.tv_usec = (now_true_usec/resolution) * resolution;
538
now_tv.tv_usec = (now_true_usec/resolution) * resolution;
453
539
454
while (exim_tvcmp(&now_tv, tgt_tv) <= 0)
540
while (exim_tvcmp(&now_tv, prev_tv) <= 0)
455
  {
541
  {
456
  struct itimerval itval;
542
  struct itimerval itval;
457
  itval.it_interval.tv_sec = 0;
543
  itval.it_interval.tv_sec = 0;
458
  itval.it_interval.tv_usec = 0;
544
  itval.it_interval.tv_usec = 0;
459
  itval.it_value.tv_sec = tgt_tv->tv_sec - now_tv.tv_sec;
545
  itval.it_value.tv_sec = prev_tv->tv_sec - now_tv.tv_sec;
460
  itval.it_value.tv_usec = tgt_tv->tv_usec + resolution - now_true_usec;
546
  itval.it_value.tv_usec = prev_tv->tv_usec + resolution - now_true_usec;
461
547
462
  /* We know that, overall, "now" is less than or equal to "then". Therefore, a
548
  /* We know that, overall, "now" is less than or equal to "then". Therefore, a
463
  negative value for the microseconds is possible only in the case when "now"
549
  negative value for the microseconds is possible only in the case when "now"
Lines 475-481 Link Here
475
    if (!f.running_in_test_harness)
561
    if (!f.running_in_test_harness)
476
      {
562
      {
477
      debug_printf("tick check: " TIME_T_FMT ".%06lu " TIME_T_FMT ".%06lu\n",
563
      debug_printf("tick check: " TIME_T_FMT ".%06lu " TIME_T_FMT ".%06lu\n",
478
        tgt_tv->tv_sec, (long) tgt_tv->tv_usec,
564
        prev_tv->tv_sec, (long) prev_tv->tv_usec,
479
       	now_tv.tv_sec, (long) now_tv.tv_usec);
565
       	now_tv.tv_sec, (long) now_tv.tv_usec);
480
      debug_printf("waiting " TIME_T_FMT ".%06lu sec\n",
566
      debug_printf("waiting " TIME_T_FMT ".%06lu sec\n",
481
        itval.it_value.tv_sec, (long) itval.it_value.tv_usec);
567
        itval.it_value.tv_sec, (long) itval.it_value.tv_usec);
Lines 487-496 Link Here
487
  /* Be prapared to go around if the kernel does not implement subtick
573
  /* Be prapared to go around if the kernel does not implement subtick
488
  granularity (GNU Hurd) */
574
  granularity (GNU Hurd) */
489
575
490
  (void)gettimeofday(&now_tv, NULL);
576
  exim_gettime(&now_tv);
491
  now_true_usec = now_tv.tv_usec;
577
  now_true_usec = now_tv.tv_usec;
492
  now_tv.tv_usec = (now_true_usec/resolution) * resolution;
578
  now_tv.tv_usec = (now_true_usec/resolution) * resolution;
493
  }
579
  }
580
*prev_tv = now_tv;
494
}
581
}
495
582
496
583
Lines 555-561 Link Here
555
    {
642
    {
556
    if (devnull < 0) devnull = open("/dev/null", O_RDWR);
643
    if (devnull < 0) devnull = open("/dev/null", O_RDWR);
557
    if (devnull < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
644
    if (devnull < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
558
      string_open_failed(errno, "/dev/null", NULL));
645
      string_open_failed("/dev/null", NULL));
559
    if (devnull != i) (void)dup2(devnull, i);
646
    if (devnull != i) (void)dup2(devnull, i);
560
    }
647
    }
561
  }
648
  }
Lines 652-658 Link Here
652
*/
739
*/
653
740
654
void
741
void
655
exim_setugid(uid_t uid, gid_t gid, BOOL igflag, uschar *msg)
742
exim_setugid(uid_t uid, gid_t gid, BOOL igflag, const uschar * msg)
656
{
743
{
657
uid_t euid = geteuid();
744
uid_t euid = geteuid();
658
gid_t egid = getegid();
745
gid_t egid = getegid();
Lines 861-867 Link Here
861
  int rc = verify_address(deliver_make_addr(address,TRUE), stdout, flags, -1,
948
  int rc = verify_address(deliver_make_addr(address,TRUE), stdout, flags, -1,
862
    -1, -1, NULL, NULL, NULL);
949
    -1, -1, NULL, NULL, NULL);
863
  if (rc == FAIL) *exit_value = 2;
950
  if (rc == FAIL) *exit_value = 2;
864
    else if (rc == DEFER && *exit_value == 0) *exit_value = 1;
951
  else if (rc == DEFER && *exit_value == 0) *exit_value = 1;
865
  }
952
  }
866
}
953
}
867
954
Lines 872-925 Link Here
872
*************************************************/
959
*************************************************/
873
960
874
static void
961
static void
875
show_db_version(FILE * f)
962
show_string(BOOL is_stdout, gstring * g)
963
{
964
const uschar * s = string_from_gstring(g);
965
if (s)
966
  if (is_stdout) fputs(CCS s, stdout);
967
  else debug_printf("%s", s);
968
}
969
970
971
static gstring *
972
show_db_version(gstring * g)
876
{
973
{
877
#ifdef DB_VERSION_STRING
974
#ifdef DB_VERSION_STRING
878
DEBUG(D_any)
975
DEBUG(D_any)
879
  {
976
  {
880
  fprintf(f, "Library version: BDB: Compile: %s\n", DB_VERSION_STRING);
977
  g = string_fmt_append(g, "Library version: BDB: Compile: %s\n", DB_VERSION_STRING);
881
  fprintf(f, "                      Runtime: %s\n",
978
  g = string_fmt_append(g, "                      Runtime: %s\n",
882
    db_version(NULL, NULL, NULL));
979
    db_version(NULL, NULL, NULL));
883
  }
980
  }
884
else
981
else
885
  fprintf(f, "Berkeley DB: %s\n", DB_VERSION_STRING);
982
  g = string_fmt_append(g, "Berkeley DB: %s\n", DB_VERSION_STRING);
886
983
887
#elif defined(BTREEVERSION) && defined(HASHVERSION)
984
#elif defined(BTREEVERSION) && defined(HASHVERSION)
888
  #ifdef USE_DB
985
# ifdef USE_DB
889
  fprintf(f, "Probably Berkeley DB version 1.8x (native mode)\n");
986
  g = string_cat(g, US"Probably Berkeley DB version 1.8x (native mode)\n");
890
  #else
987
# else
891
  fprintf(f, "Probably Berkeley DB version 1.8x (compatibility mode)\n");
988
  g = string_cat(g, US"Probably Berkeley DB version 1.8x (compatibility mode)\n");
892
  #endif
989
# endif
893
990
894
#elif defined(_DBM_RDONLY) || defined(dbm_dirfno)
991
#elif defined(_DBM_RDONLY) || defined(dbm_dirfno)
895
fprintf(f, "Probably ndbm\n");
992
g = string_cat(g, US"Probably ndbm\n");
896
#elif defined(USE_TDB)
993
#elif defined(USE_TDB)
897
fprintf(f, "Using tdb\n");
994
g = string_cat(g, US"Using tdb\n");
898
#else
995
#else
899
  #ifdef USE_GDBM
996
# ifdef USE_GDBM
900
  fprintf(f, "Probably GDBM (native mode)\n");
997
  g = string_cat(g, US"Probably GDBM (native mode)\n");
901
  #else
998
# else
902
  fprintf(f, "Probably GDBM (compatibility mode)\n");
999
  g = string_cat(g, US"Probably GDBM (compatibility mode)\n");
903
  #endif
1000
# endif
904
#endif
1001
#endif
1002
return g;
905
}
1003
}
906
1004
907
1005
908
/* This function is called for -bV/--version and for -d to output the optional
1006
/* This function is called for -bV/--version and for -d to output the optional
909
features of the current Exim binary.
1007
features of the current Exim binary.
910
1008
911
Arguments:  a FILE for printing
1009
Arguments:  BOOL, true for stdout else debug channel
912
Returns:    nothing
1010
Returns:    nothing
913
*/
1011
*/
914
1012
915
static void
1013
static void
916
show_whats_supported(FILE * fp)
1014
show_whats_supported(BOOL is_stdout)
917
{
1015
{
918
rmark reset_point = store_mark();
1016
rmark reset_point = store_mark();
919
gstring * g;
1017
gstring * g = NULL;
920
DEBUG(D_any) {} else show_db_version(fp);
921
1018
922
g = string_cat(NULL, US"Support for:");
1019
DEBUG(D_any) {} else g = show_db_version(g);
1020
1021
g = string_cat(g, US"Support for:");
923
#ifdef SUPPORT_CRYPTEQ
1022
#ifdef SUPPORT_CRYPTEQ
924
  g = string_cat(g, US" crypteq");
1023
  g = string_cat(g, US" crypteq");
925
#endif
1024
#endif
Lines 950-955 Link Here
950
#ifdef USE_OPENSSL
1049
#ifdef USE_OPENSSL
951
  g = string_cat(g, US" OpenSSL");
1050
  g = string_cat(g, US" OpenSSL");
952
#endif
1051
#endif
1052
#ifndef DISABLE_TLS_RESUME
1053
  g = string_cat(g, US" TLS_resume");
1054
#endif
953
#ifdef SUPPORT_TRANSLATE_IP_ADDRESS
1055
#ifdef SUPPORT_TRANSLATE_IP_ADDRESS
954
  g = string_cat(g, US" translate_ip_address");
1056
  g = string_cat(g, US" translate_ip_address");
955
#endif
1057
#endif
Lines 965-970 Link Here
965
#ifndef DISABLE_DKIM
1067
#ifndef DISABLE_DKIM
966
  g = string_cat(g, US" DKIM");
1068
  g = string_cat(g, US" DKIM");
967
#endif
1069
#endif
1070
#ifdef SUPPORT_DMARC
1071
  g = string_cat(g, US" DMARC");
1072
#endif
968
#ifndef DISABLE_DNSSEC
1073
#ifndef DISABLE_DNSSEC
969
  g = string_cat(g, US" DNSSEC");
1074
  g = string_cat(g, US" DNSSEC");
970
#endif
1075
#endif
Lines 978-984 Link Here
978
  g = string_cat(g, US" OCSP");
1083
  g = string_cat(g, US" OCSP");
979
#endif
1084
#endif
980
#ifndef DISABLE_PIPE_CONNECT
1085
#ifndef DISABLE_PIPE_CONNECT
981
  g = string_cat(g, US" PIPE_CONNECT");
1086
  g = string_cat(g, US" PIPECONNECT");
982
#endif
1087
#endif
983
#ifndef DISABLE_PRDR
1088
#ifndef DISABLE_PRDR
984
  g = string_cat(g, US" PRDR");
1089
  g = string_cat(g, US" PRDR");
Lines 986-999 Link Here
986
#ifdef SUPPORT_PROXY
1091
#ifdef SUPPORT_PROXY
987
  g = string_cat(g, US" PROXY");
1092
  g = string_cat(g, US" PROXY");
988
#endif
1093
#endif
1094
#ifndef DISABLE_QUEUE_RAMP
1095
  g = string_cat(g, US" Queue_Ramp");
1096
#endif
989
#ifdef SUPPORT_SOCKS
1097
#ifdef SUPPORT_SOCKS
990
  g = string_cat(g, US" SOCKS");
1098
  g = string_cat(g, US" SOCKS");
991
#endif
1099
#endif
992
#ifdef SUPPORT_SPF
1100
#ifdef SUPPORT_SPF
993
  g = string_cat(g, US" SPF");
1101
  g = string_cat(g, US" SPF");
994
#endif
1102
#endif
995
#ifdef SUPPORT_DMARC
1103
#if defined(SUPPORT_SRS)
996
  g = string_cat(g, US" DMARC");
1104
  g = string_cat(g, US" SRS");
997
#endif
1105
#endif
998
#ifdef TCP_FASTOPEN
1106
#ifdef TCP_FASTOPEN
999
  tcp_init();
1107
  tcp_init();
Lines 1011-1031 Link Here
1011
#ifdef EXPERIMENTAL_DSN_INFO
1119
#ifdef EXPERIMENTAL_DSN_INFO
1012
  g = string_cat(g, US" Experimental_DSN_info");
1120
  g = string_cat(g, US" Experimental_DSN_info");
1013
#endif
1121
#endif
1014
#ifdef EXPERIMENTAL_LMDB
1122
#ifdef EXPERIMENTAL_ESMTP_LIMITS
1015
  g = string_cat(g, US" Experimental_LMDB");
1123
  g = string_cat(g, US" Experimental_ESMTP_Limits");
1016
#endif
1017
#ifdef EXPERIMENTAL_QUEUE_RAMP
1018
  g = string_cat(g, US" Experimental_Queue_Ramp");
1019
#endif
1124
#endif
1020
#ifdef EXPERIMENTAL_QUEUEFILE
1125
#ifdef EXPERIMENTAL_QUEUEFILE
1021
  g = string_cat(g, US" Experimental_QUEUEFILE");
1126
  g = string_cat(g, US" Experimental_QUEUEFILE");
1022
#endif
1127
#endif
1023
#if defined(EXPERIMENTAL_SRS) || defined(EXPERIMENTAL_SRS_NATIVE)
1024
  g = string_cat(g, US" Experimental_SRS");
1025
#endif
1026
#ifdef EXPERIMENTAL_TLS_RESUME
1027
  g = string_cat(g, US" Experimental_TLS_resume");
1028
#endif
1029
g = string_cat(g, US"\n");
1128
g = string_cat(g, US"\n");
1030
1129
1031
g = string_cat(g, US"Lookups (built-in):");
1130
g = string_cat(g, US"Lookups (built-in):");
Lines 1053-1059 Link Here
1053
#if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2
1152
#if defined(LOOKUP_LDAP) && LOOKUP_LDAP!=2
1054
  g = string_cat(g, US" ldap ldapdn ldapm");
1153
  g = string_cat(g, US" ldap ldapdn ldapm");
1055
#endif
1154
#endif
1056
#ifdef EXPERIMENTAL_LMDB
1155
#ifdef LOOKUP_LMDB
1057
  g = string_cat(g, US" lmdb");
1156
  g = string_cat(g, US" lmdb");
1058
#endif
1157
#endif
1059
#if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
1158
#if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
Lines 1095-1100 Link Here
1095
#ifdef WITH_CONTENT_SCAN
1194
#ifdef WITH_CONTENT_SCAN
1096
g = malware_show_supported(g);
1195
g = malware_show_supported(g);
1097
#endif
1196
#endif
1197
show_string(is_stdout, g); g = NULL;
1098
1198
1099
if (fixed_never_users[0] > 0)
1199
if (fixed_never_users[0] > 0)
1100
  {
1200
  {
Lines 1106-1124 Link Here
1106
  }
1206
  }
1107
1207
1108
g = string_fmt_append(g, "Configure owner: %d:%d\n", config_uid, config_gid);
1208
g = string_fmt_append(g, "Configure owner: %d:%d\n", config_uid, config_gid);
1109
fputs(CS string_from_gstring(g), fp);
1110
1209
1111
fprintf(fp, "Size of off_t: " SIZE_T_FMT "\n", sizeof(off_t));
1210
g = string_fmt_append(g, "Size of off_t: " SIZE_T_FMT "\n", sizeof(off_t));
1112
1211
1113
/* Everything else is details which are only worth reporting when debugging.
1212
/* Everything else is details which are only worth reporting when debugging.
1114
Perhaps the tls_version_report should move into this too. */
1213
Perhaps the tls_version_report should move into this too. */
1115
DEBUG(D_any) do {
1214
DEBUG(D_any)
1215
  {
1116
1216
1117
/* clang defines __GNUC__ (at least, for me) so test for it first */
1217
/* clang defines __GNUC__ (at least, for me) so test for it first */
1118
#if defined(__clang__)
1218
#if defined(__clang__)
1119
  fprintf(fp, "Compiler: CLang [%s]\n", __clang_version__);
1219
  g = string_fmt_append(g, "Compiler: CLang [%s]\n", __clang_version__);
1120
#elif defined(__GNUC__)
1220
#elif defined(__GNUC__)
1121
  fprintf(fp, "Compiler: GCC [%s]\n",
1221
  g = string_fmt_append(g, "Compiler: GCC [%s]\n",
1122
# ifdef __VERSION__
1222
# ifdef __VERSION__
1123
      __VERSION__
1223
      __VERSION__
1124
# else
1224
# else
Lines 1126-1157 Link Here
1126
# endif
1226
# endif
1127
      );
1227
      );
1128
#else
1228
#else
1129
  fprintf(fp, "Compiler: <unknown>\n");
1229
  g = string_cat(g, US"Compiler: <unknown>\n");
1130
#endif
1230
#endif
1131
1231
1132
#if defined(__GLIBC__) && !defined(__UCLIBC__)
1232
#if defined(__GLIBC__) && !defined(__UCLIBC__)
1133
  fprintf(fp, "Library version: Glibc: Compile: %d.%d\n",
1233
  g = string_fmt_append(g, "Library version: Glibc: Compile: %d.%d\n",
1134
	       	__GLIBC__, __GLIBC_MINOR__);
1234
	       	__GLIBC__, __GLIBC_MINOR__);
1135
  if (__GLIBC_PREREQ(2, 1))
1235
  if (__GLIBC_PREREQ(2, 1))
1136
    fprintf(fp, "                        Runtime: %s\n",
1236
    g = string_fmt_append(g, "                        Runtime: %s\n",
1137
	       	gnu_get_libc_version());
1237
	       	gnu_get_libc_version());
1138
#endif
1238
#endif
1139
1239
1140
show_db_version(fp);
1240
g = show_db_version(g);
1141
1241
1142
#ifndef DISABLE_TLS
1242
#ifndef DISABLE_TLS
1143
  tls_version_report(fp);
1243
  g = tls_version_report(g);
1144
#endif
1244
#endif
1145
#ifdef SUPPORT_I18N
1245
#ifdef SUPPORT_I18N
1146
  utf8_version_report(fp);
1246
  g = utf8_version_report(g);
1247
#endif
1248
#ifdef SUPPORT_DMARC
1249
  g = dmarc_version_report(g);
1147
#endif
1250
#endif
1148
#ifdef SUPPORT_SPF
1251
#ifdef SUPPORT_SPF
1149
  spf_lib_version_report(fp);
1252
  g = spf_lib_version_report(g);
1150
#endif
1253
#endif
1151
1254
1152
  for (auth_info * authi = auths_available; *authi->driver_name != '\0'; ++authi)
1255
show_string(is_stdout, g);
1153
    if (authi->version_report)
1256
g = NULL;
1154
      (*authi->version_report)(fp);
1257
1258
for (auth_info * authi = auths_available; *authi->driver_name != '\0'; ++authi)
1259
  if (authi->version_report)
1260
    g = (*authi->version_report)(g);
1155
1261
1156
  /* PCRE_PRERELEASE is either defined and empty or a bare sequence of
1262
  /* PCRE_PRERELEASE is either defined and empty or a bare sequence of
1157
  characters; unless it's an ancient version of PCRE in which case it
1263
  characters; unless it's an ancient version of PCRE in which case it
Lines 1161-1191 Link Here
1161
#endif
1267
#endif
1162
#define QUOTE(X) #X
1268
#define QUOTE(X) #X
1163
#define EXPAND_AND_QUOTE(X) QUOTE(X)
1269
#define EXPAND_AND_QUOTE(X) QUOTE(X)
1164
  fprintf(fp, "Library version: PCRE: Compile: %d.%d%s\n"
1270
  {
1165
             "                       Runtime: %s\n",
1271
  uschar buf[24];
1166
          PCRE_MAJOR, PCRE_MINOR,
1272
  pcre2_config(PCRE2_CONFIG_VERSION, buf);
1167
          EXPAND_AND_QUOTE(PCRE_PRERELEASE) "",
1273
  g = string_fmt_append(g, "Library version: PCRE2: Compile: %d.%d%s\n"
1168
          pcre_version());
1274
              "                        Runtime: %s\n",
1275
          PCRE2_MAJOR, PCRE2_MINOR,
1276
          EXPAND_AND_QUOTE(PCRE2_PRERELEASE) "",
1277
          buf);
1278
  }
1169
#undef QUOTE
1279
#undef QUOTE
1170
#undef EXPAND_AND_QUOTE
1280
#undef EXPAND_AND_QUOTE
1171
1281
1172
  init_lookup_list();
1282
show_string(is_stdout, g);
1173
  for (int i = 0; i < lookup_list_count; i++)
1283
g = NULL;
1174
    if (lookup_list[i]->version_report)
1284
1175
      lookup_list[i]->version_report(fp);
1285
init_lookup_list();
1286
for (int i = 0; i < lookup_list_count; i++)
1287
  if (lookup_list[i]->version_report)
1288
    g = lookup_list[i]->version_report(g);
1289
show_string(is_stdout, g);
1290
g = NULL;
1176
1291
1177
#ifdef WHITELIST_D_MACROS
1292
#ifdef WHITELIST_D_MACROS
1178
  fprintf(fp, "WHITELIST_D_MACROS: \"%s\"\n", WHITELIST_D_MACROS);
1293
  g = string_fmt_append(g, "WHITELIST_D_MACROS: \"%s\"\n", WHITELIST_D_MACROS);
1179
#else
1294
#else
1180
  fprintf(fp, "WHITELIST_D_MACROS unset\n");
1295
  g = string_cat(g, US"WHITELIST_D_MACROS unset\n");
1181
#endif
1296
#endif
1182
#ifdef TRUSTED_CONFIG_LIST
1297
#ifdef TRUSTED_CONFIG_LIST
1183
  fprintf(fp, "TRUSTED_CONFIG_LIST: \"%s\"\n", TRUSTED_CONFIG_LIST);
1298
  g = string_fmt_append(g, "TRUSTED_CONFIG_LIST: \"%s\"\n", TRUSTED_CONFIG_LIST);
1184
#else
1299
#else
1185
  fprintf(fp, "TRUSTED_CONFIG_LIST unset\n");
1300
  g = string_cat(g, US"TRUSTED_CONFIG_LIST unset\n");
1186
#endif
1301
#endif
1302
  }
1187
1303
1188
} while (0);
1304
show_string(is_stdout, g);
1189
store_reset(reset_point);
1305
store_reset(reset_point);
1190
}
1306
}
1191
1307
Lines 1337-1392 Link Here
1337
get_stdinput(char *(*fn_readline)(const char *), void(*fn_addhist)(const char *))
1453
get_stdinput(char *(*fn_readline)(const char *), void(*fn_addhist)(const char *))
1338
{
1454
{
1339
gstring * g = NULL;
1455
gstring * g = NULL;
1456
BOOL had_input = FALSE;
1340
1457
1341
if (!fn_readline) { printf("> "); fflush(stdout); }
1458
if (!fn_readline) { printf("> "); fflush(stdout); }
1342
1459
1343
for (int i = 0;; i++)
1460
for (int i = 0;; i++)
1344
  {
1461
  {
1345
  uschar buffer[1024];
1462
  uschar buffer[1024];
1346
  uschar *p, *ss;
1463
  uschar * p, * ss;
1347
1464
1348
  #ifdef USE_READLINE
1465
#ifdef USE_READLINE
1349
  char *readline_line = NULL;
1466
  char *readline_line = NULL;
1350
  if (fn_readline)
1467
  if (fn_readline)
1351
    {
1468
    {
1352
    if (!(readline_line = fn_readline((i > 0)? "":"> "))) break;
1469
    if (!(readline_line = fn_readline((i > 0)? "":"> "))) break;
1353
    if (*readline_line != 0 && fn_addhist) fn_addhist(readline_line);
1470
    if (*readline_line && fn_addhist) fn_addhist(readline_line);
1354
    p = US readline_line;
1471
    p = US readline_line;
1355
    }
1472
    }
1356
  else
1473
  else
1357
  #endif
1474
#endif
1358
1475
1359
  /* readline() not in use */
1476
  /* readline() not in use */
1360
1477
1361
    {
1478
    {
1362
    if (Ufgets(buffer, sizeof(buffer), stdin) == NULL) break;
1479
    if (Ufgets(buffer, sizeof(buffer), stdin) == NULL) break;	/*EOF*/
1363
    p = buffer;
1480
    p = buffer;
1364
    }
1481
    }
1365
1482
1366
  /* Handle the line */
1483
  /* Handle the line */
1367
1484
1368
  ss = p + (int)Ustrlen(p);
1485
  had_input = TRUE;
1369
  while (ss > p && isspace(ss[-1])) ss--;
1486
  ss = p + Ustrlen(p);
1487
  while (ss > p && isspace(ss[-1])) ss--; /* strip trailing newline (and spaces) */
1370
1488
1371
  if (i > 0)
1489
  if (i > 0)
1372
    while (p < ss && isspace(*p)) p++;   /* leading space after cont */
1490
    while (p < ss && isspace(*p)) p++;   /* strip leading space after cont */
1373
1491
1374
  g = string_catn(g, p, ss - p);
1492
  g = string_catn(g, p, ss - p);
1375
1493
1376
  #ifdef USE_READLINE
1494
#ifdef USE_READLINE
1377
  if (fn_readline) free(readline_line);
1495
  if (fn_readline) free(readline_line);
1378
  #endif
1496
#endif
1379
1497
1380
  /* g can only be NULL if ss==p */
1498
  /* g can only be NULL if ss==p */
1381
  if (ss == p || g->s[g->ptr-1] != '\\')
1499
  if (ss == p || g->s[g->ptr-1] != '\\') /* not continuation; done */
1382
    break;
1500
    break;
1383
1501
1384
  --g->ptr;
1502
  --g->ptr;				/* drop the \ */
1385
  (void) string_from_gstring(g);
1386
  }
1503
  }
1387
1504
1388
if (!g) printf("\n");
1505
if (had_input) return g ? string_from_gstring(g) : US"";
1389
return string_from_gstring(g);
1506
printf("\n");
1507
return NULL;
1390
}
1508
}
1391
1509
1392
1510
Lines 1518-1531 Link Here
1518
    continue;
1636
    continue;
1519
  if ((len = m->replen) == 0)
1637
  if ((len = m->replen) == 0)
1520
    continue;
1638
    continue;
1521
  n = pcre_exec(regex_whitelisted_macro, NULL, CS m->replacement, len,
1639
  if (!regex_match(regex_whitelisted_macro, m->replacement, len, NULL))
1522
   0, PCRE_EOPT, NULL, 0);
1523
  if (n < 0)
1524
    {
1525
    if (n != PCRE_ERROR_NOMATCH)
1526
      debug_printf("macros_trusted checking %s returned %d\n", m->name, n);
1527
    return FALSE;
1640
    return FALSE;
1528
    }
1529
  }
1641
  }
1530
DEBUG(D_any) debug_printf("macros_trusted overridden to true by whitelisting\n");
1642
DEBUG(D_any) debug_printf("macros_trusted overridden to true by whitelisting\n");
1531
return TRUE;
1643
return TRUE;
Lines 1601-1607 Link Here
1601
int  list_queue_option = 0;
1713
int  list_queue_option = 0;
1602
int  msg_action = 0;
1714
int  msg_action = 0;
1603
int  msg_action_arg = -1;
1715
int  msg_action_arg = -1;
1604
int  namelen = (argv[0] == NULL)? 0 : Ustrlen(argv[0]);
1716
int  namelen = argv[0] ? Ustrlen(argv[0]) : 0;
1605
int  queue_only_reason = 0;
1717
int  queue_only_reason = 0;
1606
#ifdef EXIM_PERL
1718
#ifdef EXIM_PERL
1607
int  perl_start_option = 0;
1719
int  perl_start_option = 0;
Lines 1626-1632 Link Here
1626
BOOL list_options = FALSE;
1738
BOOL list_options = FALSE;
1627
BOOL list_config = FALSE;
1739
BOOL list_config = FALSE;
1628
BOOL local_queue_only;
1740
BOOL local_queue_only;
1629
BOOL more = TRUE;
1630
BOOL one_msg_action = FALSE;
1741
BOOL one_msg_action = FALSE;
1631
BOOL opt_D_used = FALSE;
1742
BOOL opt_D_used = FALSE;
1632
BOOL queue_only_set = FALSE;
1743
BOOL queue_only_set = FALSE;
Lines 1638-1643 Link Here
1638
BOOL usage_wanted = FALSE;
1749
BOOL usage_wanted = FALSE;
1639
BOOL verify_address_mode = FALSE;
1750
BOOL verify_address_mode = FALSE;
1640
BOOL verify_as_sender = FALSE;
1751
BOOL verify_as_sender = FALSE;
1752
BOOL rcpt_verify_quota = FALSE;
1641
BOOL version_printed = FALSE;
1753
BOOL version_printed = FALSE;
1642
uschar *alias_arg = NULL;
1754
uschar *alias_arg = NULL;
1643
uschar *called_as = US"";
1755
uschar *called_as = US"";
Lines 1679-1684 Link Here
1679
(void)gettimeofday(&timestamp_startup, NULL);
1791
(void)gettimeofday(&timestamp_startup, NULL);
1680
#endif
1792
#endif
1681
1793
1794
store_init();	/* Initialise the memory allocation susbsystem */
1795
pcre_init();	/* Set up memory handling for pcre */
1796
1682
/* If the Exim user and/or group and/or the configuration file owner/group were
1797
/* If the Exim user and/or group and/or the configuration file owner/group were
1683
defined by ref:name at build time, we must now find the actual uid/gid values.
1798
defined by ref:name at build time, we must now find the actual uid/gid values.
1684
This is a feature to make the lives of binary distributors easier. */
1799
This is a feature to make the lives of binary distributors easier. */
Lines 1742-1747 Link Here
1742
  debug_store = TRUE;
1857
  debug_store = TRUE;
1743
1858
1744
/* Protect against abusive argv[0] */
1859
/* Protect against abusive argv[0] */
1860
if (!argv[0] || !argc) exim_fail("exim: executable name required\n");
1745
exim_str_fail_toolong(argv[0], PATH_MAX, "argv[0]");
1861
exim_str_fail_toolong(argv[0], PATH_MAX, "argv[0]");
1746
1862
1747
/* The C standard says that the equivalent of setlocale(LC_ALL, "C") is obeyed
1863
/* The C standard says that the equivalent of setlocale(LC_ALL, "C") is obeyed
Lines 1778-1792 Link Here
1778
1894
1779
if (fstat(fileno(stderr), &statbuf) >= 0) log_stderr = stderr;
1895
if (fstat(fileno(stderr), &statbuf) >= 0) log_stderr = stderr;
1780
1896
1781
/* Arrange for the PCRE regex library to use our store functions. Note that
1782
the normal calls are actually macros that add additional arguments for
1783
debugging purposes so we have to assign specially constructed functions here.
1784
The default is to use store in the stacking pool, but this is overridden in the
1785
regex_must_compile() function. */
1786
1787
pcre_malloc = function_store_get;
1788
pcre_free = function_dummy_free;
1789
1790
/* Ensure there is a big buffer for temporary use in several places. It is put
1897
/* Ensure there is a big buffer for temporary use in several places. It is put
1791
in malloc store so that it can be freed for enlargement if necessary. */
1898
in malloc store so that it can be freed for enlargement if necessary. */
1792
1899
Lines 1795-1803 Link Here
1795
/* Set up the handler for the data request signal, and set the initial
1902
/* Set up the handler for the data request signal, and set the initial
1796
descriptive text. */
1903
descriptive text. */
1797
1904
1798
process_info = store_get(PROCESS_INFO_SIZE, TRUE);	/* tainted */
1905
process_info = store_get(PROCESS_INFO_SIZE, GET_TAINTED);
1799
set_process_info("initializing");
1906
set_process_info("initializing");
1800
os_restarting_signal(SIGUSR1, usr1_handler);
1907
os_restarting_signal(SIGUSR1, usr1_handler);		/* exiwhat */
1908
#ifdef SA_SIGINFO
1909
  {
1910
  struct sigaction act = { .sa_sigaction = segv_handler, .sa_flags = SA_RESETHAND | SA_SIGINFO };
1911
  sigaction(SIGSEGV, &act, NULL);
1912
  }
1913
#else
1914
signal(SIGSEGV, segv_handler);				/* log faults */
1915
#endif
1801
1916
1802
/* If running in a dockerized environment, the TERM signal is only
1917
/* If running in a dockerized environment, the TERM signal is only
1803
delegated to the PID 1 if we request it by setting an signal handler */
1918
delegated to the PID 1 if we request it by setting an signal handler */
Lines 2158-2164 Link Here
2158
	  if (!*argrest || Ustrcmp(argrest, "c") == 0)
2273
	  if (!*argrest || Ustrcmp(argrest, "c") == 0)
2159
	    {
2274
	    {
2160
	    if (++i >= argc) { badarg = TRUE; break; }
2275
	    if (++i >= argc) { badarg = TRUE; break; }
2161
	    sender_host_address = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_IPADDR_MAX, "-bh"), TRUE);
2276
	    sender_host_address = string_copy_taint(
2277
		  exim_str_fail_toolong(argv[i], EXIM_IPADDR_MAX, "-bh"),
2278
		  GET_TAINTED);
2162
	    host_checking = checking = f.log_testing_mode = TRUE;
2279
	    host_checking = checking = f.log_testing_mode = TRUE;
2163
	    f.host_checking_callout = *argrest == 'c';
2280
	    f.host_checking_callout = *argrest == 'c';
2164
	    message_logs = FALSE;
2281
	    message_logs = FALSE;
Lines 2268-2274 Link Here
2268
	case 'P':
2385
	case 'P':
2269
2386
2270
	  /* -bP config: we need to setup here, because later,
2387
	  /* -bP config: we need to setup here, because later,
2271
	   * when list_options is checked, the config is read already */
2388
	  when list_options is checked, the config is read already */
2272
	  if (*argrest)
2389
	  if (*argrest)
2273
	    badarg = TRUE;
2390
	    badarg = TRUE;
2274
	  else if (argv[i+1] && Ustrcmp(argv[i+1], "config") == 0)
2391
	  else if (argv[i+1] && Ustrcmp(argv[i+1], "config") == 0)
Lines 2349-2355 Link Here
2349
	      version_cnumber, version_date);
2466
	      version_cnumber, version_date);
2350
	    printf("%s\n", CS version_copyright);
2467
	    printf("%s\n", CS version_copyright);
2351
	    version_printed = TRUE;
2468
	    version_printed = TRUE;
2352
	    show_whats_supported(stdout);
2469
	    show_whats_supported(TRUE);
2353
	    f.log_testing_mode = TRUE;
2470
	    f.log_testing_mode = TRUE;
2354
	    }
2471
	    }
2355
	  else badarg = TRUE;
2472
	  else badarg = TRUE;
Lines 2386-2391 Link Here
2386
      int len = Ustrlen(ALT_CONFIG_PREFIX);
2503
      int len = Ustrlen(ALT_CONFIG_PREFIX);
2387
      const uschar *list = argrest;
2504
      const uschar *list = argrest;
2388
      uschar *filename;
2505
      uschar *filename;
2506
      /* The argv is untainted, so big_buffer (also untainted) is ok to use */
2389
      while((filename = string_nextinlist(&list, &sep, big_buffer,
2507
      while((filename = string_nextinlist(&list, &sep, big_buffer,
2390
             big_buffer_size)))
2508
             big_buffer_size)))
2391
        if (  (  Ustrlen(filename) < len
2509
        if (  (  Ustrlen(filename) < len
Lines 2543-2563 Link Here
2543
    #endif
2661
    #endif
2544
    break;
2662
    break;
2545
2663
2546
    /* -d: Set debug level (see also -v below) or set the drop_cr option.
2547
    The latter is now a no-op, retained for compatibility only. If -dd is used,
2548
    debugging subprocesses of the daemon is disabled. */
2549
2550
    case 'd':
2664
    case 'd':
2665
2666
    /* -dropcr: Set this option.  Now a no-op, retained for compatibility only. */
2667
2551
    if (Ustrcmp(argrest, "ropcr") == 0)
2668
    if (Ustrcmp(argrest, "ropcr") == 0)
2552
      {
2669
      {
2553
      /* drop_cr = TRUE; */
2670
      /* drop_cr = TRUE; */
2554
      }
2671
      }
2555
2672
2556
    /* Use an intermediate variable so that we don't set debugging while
2673
    /* -dp: Set up a debug pretrigger buffer with given size. */
2557
    decoding the debugging bits. */
2674
2675
    else if (Ustrcmp(argrest, "p") == 0)
2676
      if (++i >= argc)
2677
	badarg = TRUE;
2678
      else
2679
	debug_pretrigger_setup(argv[i]);
2680
2681
    /* -dt: Set a debug trigger selector */
2682
2683
    else if (Ustrncmp(argrest, "t=", 2) == 0)
2684
      dtrigger_selector = (unsigned int) Ustrtol(argrest + 2, NULL, 0);
2685
2686
    /* -d: Set debug level (see also -v below).
2687
    If -dd is used, debugging subprocesses of the daemon is disabled. */
2558
2688
2559
    else
2689
    else
2560
      {
2690
      {
2691
      /* Use an intermediate variable so that we don't set debugging while
2692
      decoding the debugging bits. */
2693
2561
      unsigned int selector = D_default;
2694
      unsigned int selector = D_default;
2562
      debug_selector = 0;
2695
      debug_selector = 0;
2563
      debug_file = NULL;
2696
      debug_file = NULL;
Lines 2615-2621 Link Here
2615
    case 'F':
2748
    case 'F':
2616
    if (!*argrest)
2749
    if (!*argrest)
2617
      if (++i < argc) argrest = argv[i]; else { badarg = TRUE; break; }
2750
      if (++i < argc) argrest = argv[i]; else { badarg = TRUE; break; }
2618
    originator_name = string_copy_taint(exim_str_fail_toolong(argrest, EXIM_HUMANNAME_MAX, "-F"), TRUE);
2751
    originator_name = string_copy_taint(
2752
		  exim_str_fail_toolong(argrest, EXIM_HUMANNAME_MAX, "-F"),
2753
		  GET_TAINTED);
2619
    f.sender_name_forced = TRUE;
2754
    f.sender_name_forced = TRUE;
2620
    break;
2755
    break;
2621
2756
Lines 2643-2649 Link Here
2643
        if (i+1 < argc) argrest = argv[++i]; else { badarg = TRUE; break; }
2778
        if (i+1 < argc) argrest = argv[++i]; else { badarg = TRUE; break; }
2644
      (void) exim_str_fail_toolong(argrest, EXIM_DISPLAYMAIL_MAX, "-f");
2779
      (void) exim_str_fail_toolong(argrest, EXIM_DISPLAYMAIL_MAX, "-f");
2645
      if (!*argrest)
2780
      if (!*argrest)
2646
        *(sender_address = store_get(1, FALSE)) = '\0';  /* Ensure writeable memory */
2781
        *(sender_address = store_get(1, GET_UNTAINTED)) = '\0';  /* Ensure writeable memory */
2647
      else
2782
      else
2648
        {
2783
        {
2649
        uschar * temp = argrest + Ustrlen(argrest) - 1;
2784
        uschar * temp = argrest + Ustrlen(argrest) - 1;
Lines 2658-2664 Link Here
2658
		  &dummy_start, &dummy_end, &sender_address_domain, TRUE)))
2793
		  &dummy_start, &dummy_end, &sender_address_domain, TRUE)))
2659
          exim_fail("exim: bad -f address \"%s\": %s\n", argrest, errmess);
2794
          exim_fail("exim: bad -f address \"%s\": %s\n", argrest, errmess);
2660
2795
2661
	sender_address = string_copy_taint(sender_address, TRUE);
2796
	sender_address = string_copy_taint(sender_address, GET_TAINTED);
2662
#ifdef SUPPORT_I18N
2797
#ifdef SUPPORT_I18N
2663
	message_smtputf8 =  string_is_utf8(sender_address);
2798
	message_smtputf8 =  string_is_utf8(sender_address);
2664
	allow_utf8_domains = FALSE;
2799
	allow_utf8_domains = FALSE;
Lines 2708-2714 Link Here
2708
      exim_fail("exim: the -L syslog name is too long: \"%s\"\n", argrest);
2843
      exim_fail("exim: the -L syslog name is too long: \"%s\"\n", argrest);
2709
    if (sz < 1)
2844
    if (sz < 1)
2710
      exim_fail("exim: the -L syslog name is too short\n");
2845
      exim_fail("exim: the -L syslog name is too short\n");
2711
    cmdline_syslog_name = string_copy_taint(argrest, TRUE);
2846
    cmdline_syslog_name = string_copy_taint(argrest, GET_TAINTED);
2712
    break;
2847
    break;
2713
2848
2714
    case 'M':
2849
    case 'M':
Lines 2738-2746 Link Here
2738
      if (msg_action_arg >= 0)
2873
      if (msg_action_arg >= 0)
2739
        exim_fail("exim: incompatible arguments\n");
2874
        exim_fail("exim: incompatible arguments\n");
2740
2875
2741
      continue_transport = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-C internal transport"), TRUE);
2876
      continue_transport = string_copy_taint(
2742
      continue_hostname = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_HOSTNAME_MAX, "-C internal hostname"), TRUE);
2877
	exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-C internal transport"),
2743
      continue_host_address = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-C internal hostaddr"), TRUE);
2878
	GET_TAINTED);
2879
      continue_hostname = string_copy_taint(
2880
	exim_str_fail_toolong(argv[++i], EXIM_HOSTNAME_MAX, "-C internal hostname"),
2881
	GET_TAINTED);
2882
      continue_host_address = string_copy_taint(
2883
	exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-C internal hostaddr"),
2884
	GET_TAINTED);
2744
      continue_sequence = Uatoi(argv[++i]);
2885
      continue_sequence = Uatoi(argv[++i]);
2745
      msg_action = MSG_DELIVER;
2886
      msg_action = MSG_DELIVER;
2746
      msg_action_arg = ++i;
2887
      msg_action_arg = ++i;
Lines 2785-2797 Link Here
2785
    /* -MCd: for debug, set a process-purpose string */
2926
    /* -MCd: for debug, set a process-purpose string */
2786
2927
2787
	case 'd': if (++i < argc)
2928
	case 'd': if (++i < argc)
2788
		    process_purpose = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-MCd"), TRUE);
2929
		    process_purpose = string_copy_taint(
2930
		      exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-MCd"),
2931
		      GET_TAINTED);
2789
		  else badarg = TRUE;
2932
		  else badarg = TRUE;
2790
		  break;
2933
		  break;
2791
2934
2792
    /* -MCG: set the queue name, to a non-default value */
2935
    /* -MCG: set the queue name, to a non-default value. Arguably, anything
2793
2936
       from the commandline should be tainted - but we will need an untainted
2794
	case 'G': if (++i < argc) queue_name = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-MCG"), TRUE);
2937
       value for the spoolfile when doing a -odi delivery process. */
2938
2939
	case 'G': if (++i < argc) queue_name = string_copy_taint(
2940
		      exim_str_fail_toolong(argv[i], EXIM_DRIVERNAME_MAX, "-MCG"),
2941
		      GET_UNTAINTED);
2795
		  else badarg = TRUE;
2942
		  else badarg = TRUE;
2796
		  break;
2943
		  break;
2797
2944
Lines 2799-2809 Link Here
2799
2946
2800
	case 'K': smtp_peer_options |= OPTION_CHUNKING; break;
2947
	case 'K': smtp_peer_options |= OPTION_CHUNKING; break;
2801
2948
2949
#ifdef EXPERIMENTAL_ESMTP_LIMITS
2950
    /* -MCL: peer used LIMITS RCPTMAX and/or RCPTDOMAINMAX */
2951
	case 'L': if (++i < argc) continue_limit_mail = Uatoi(argv[i]);
2952
		  else badarg = TRUE;
2953
		  if (++i < argc) continue_limit_rcpt = Uatoi(argv[i]);
2954
		  else badarg = TRUE;
2955
		  if (++i < argc) continue_limit_rcptdom = Uatoi(argv[i]);
2956
		  else badarg = TRUE;
2957
		  break;
2958
#endif
2959
2802
    /* -MCP: set the smtp_use_pipelining flag; this is useful only when
2960
    /* -MCP: set the smtp_use_pipelining flag; this is useful only when
2803
    it preceded -MC (see above) */
2961
    it preceded -MC (see above) */
2804
2962
2805
	case 'P': smtp_peer_options |= OPTION_PIPE; break;
2963
	case 'P': smtp_peer_options |= OPTION_PIPE; break;
2806
2964
2965
#ifdef SUPPORT_SOCKS
2966
    /* -MCp: Socks proxy in use; nearside IP, port, external IP, port */
2967
	case 'p': proxy_session = TRUE;
2968
		  if (++i < argc)
2969
		    {
2970
		    proxy_local_address = string_copy_taint(argv[i], GET_TAINTED);
2971
		    if (++i < argc)
2972
		      {
2973
		      proxy_local_port = Uatoi(argv[i]);
2974
		      if (++i < argc)
2975
			{
2976
			proxy_external_address = string_copy_taint(argv[i], GET_TAINTED);
2977
			if (++i < argc)
2978
			  {
2979
			  proxy_external_port = Uatoi(argv[i]);
2980
			  break;
2981
		    } } } }
2982
		  badarg = TRUE;
2983
		  break;
2984
#endif
2807
    /* -MCQ: pass on the pid of the queue-running process that started
2985
    /* -MCQ: pass on the pid of the queue-running process that started
2808
    this chain of deliveries and the fd of its synchronizing pipe; this
2986
    this chain of deliveries and the fd of its synchronizing pipe; this
2809
    is useful only when it precedes -MC (see above) */
2987
    is useful only when it precedes -MC (see above) */
Lines 2814-2819 Link Here
2814
		  else badarg = TRUE;
2992
		  else badarg = TRUE;
2815
		  break;
2993
		  break;
2816
2994
2995
    /* -MCq: do a quota check on the given recipient for the given size
2996
    of message.  Separate from -MC. */
2997
	case 'q': rcpt_verify_quota = TRUE;
2998
		  if (++i < argc) message_size = Uatoi(argv[i]);
2999
		  else badarg = TRUE;
3000
		  break;
3001
2817
    /* -MCS: set the smtp_use_size flag; this is useful only when it
3002
    /* -MCS: set the smtp_use_size flag; this is useful only when it
2818
    precedes -MC (see above) */
3003
    precedes -MC (see above) */
2819
3004
Lines 2826-2832 Link Here
2826
	case 'r':
3011
	case 'r':
2827
	case 's': if (++i < argc)
3012
	case 's': if (++i < argc)
2828
		    {
3013
		    {
2829
		    continue_proxy_sni = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_HOSTNAME_MAX, "-MCr/-MCs"), TRUE);
3014
		    continue_proxy_sni = string_copy_taint(
3015
		      exim_str_fail_toolong(argv[i], EXIM_HOSTNAME_MAX, "-MCr/-MCs"),
3016
		      GET_TAINTED);
2830
		    if (argrest[1] == 'r') continue_proxy_dane = TRUE;
3017
		    if (argrest[1] == 'r') continue_proxy_dane = TRUE;
2831
		    }
3018
		    }
2832
		  else badarg = TRUE;
3019
		  else badarg = TRUE;
Lines 2838-2850 Link Here
2838
    and the TLS cipher. */
3025
    and the TLS cipher. */
2839
3026
2840
	case 't': if (++i < argc)
3027
	case 't': if (++i < argc)
2841
		    sending_ip_address = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_IPADDR_MAX, "-MCt IP"), TRUE);
3028
		    sending_ip_address = string_copy_taint(
3029
		      exim_str_fail_toolong(argv[i], EXIM_IPADDR_MAX, "-MCt IP"),
3030
		      GET_TAINTED);
2842
		  else badarg = TRUE;
3031
		  else badarg = TRUE;
2843
		  if (++i < argc)
3032
		  if (++i < argc)
2844
		    sending_port = (int)(Uatol(argv[i]));
3033
		    sending_port = (int)(Uatol(argv[i]));
2845
		  else badarg = TRUE;
3034
		  else badarg = TRUE;
2846
		  if (++i < argc)
3035
		  if (++i < argc)
2847
		    continue_proxy_cipher = string_copy_taint(exim_str_fail_toolong(argv[i], EXIM_CIPHERNAME_MAX, "-MCt cipher"), TRUE);
3036
		    continue_proxy_cipher = string_copy_taint(
3037
		      exim_str_fail_toolong(argv[i], EXIM_CIPHERNAME_MAX, "-MCt cipher"),
3038
		      GET_TAINTED);
2848
		  else badarg = TRUE;
3039
		  else badarg = TRUE;
2849
		  /*FALLTHROUGH*/
3040
		  /*FALLTHROUGH*/
2850
3041
Lines 2907-2918 Link Here
2907
   else if (Ustrcmp(argrest, "G") == 0)
3098
   else if (Ustrcmp(argrest, "G") == 0)
2908
      {
3099
      {
2909
      msg_action = MSG_SETQUEUE;
3100
      msg_action = MSG_SETQUEUE;
2910
      queue_name_dest = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-MG"), TRUE);
3101
      queue_name_dest = string_copy_taint(
2911
      }
3102
	exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-MG"),
2912
    else if (Ustrcmp(argrest, "mad") == 0)
3103
	GET_TAINTED);
2913
      {
2914
      msg_action = MSG_MARK_ALL_DELIVERED;
2915
      }
3104
      }
3105
    else if (Ustrcmp(argrest, "mad") == 0) msg_action = MSG_MARK_ALL_DELIVERED;
2916
    else if (Ustrcmp(argrest, "md") == 0)
3106
    else if (Ustrcmp(argrest, "md") == 0)
2917
      {
3107
      {
2918
      msg_action = MSG_MARK_DELIVERED;
3108
      msg_action = MSG_MARK_DELIVERED;
Lines 3120-3146 Link Here
3120
	/* -oMa: Set sender host address */
3310
	/* -oMa: Set sender host address */
3121
3311
3122
	if (Ustrcmp(argrest, "a") == 0)
3312
	if (Ustrcmp(argrest, "a") == 0)
3123
	  sender_host_address = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMa"), TRUE);
3313
	  sender_host_address = string_copy_taint(
3314
	    exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMa"),
3315
	    GET_TAINTED);
3124
3316
3125
	/* -oMaa: Set authenticator name */
3317
	/* -oMaa: Set authenticator name */
3126
3318
3127
	else if (Ustrcmp(argrest, "aa") == 0)
3319
	else if (Ustrcmp(argrest, "aa") == 0)
3128
	  sender_host_authenticated = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMaa"), TRUE);
3320
	  sender_host_authenticated = string_copy_taint(
3321
	    exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMaa"),
3322
	    GET_TAINTED);
3129
3323
3130
	/* -oMas: setting authenticated sender */
3324
	/* -oMas: setting authenticated sender */
3131
3325
3132
	else if (Ustrcmp(argrest, "as") == 0)
3326
	else if (Ustrcmp(argrest, "as") == 0)
3133
	  authenticated_sender = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMas"), TRUE);
3327
	  authenticated_sender = string_copy_taint(
3328
	    exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMas"),
3329
	    GET_TAINTED);
3134
3330
3135
	/* -oMai: setting authenticated id */
3331
	/* -oMai: setting authenticated id */
3136
3332
3137
	else if (Ustrcmp(argrest, "ai") == 0)
3333
	else if (Ustrcmp(argrest, "ai") == 0)
3138
	  authenticated_id = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMas"), TRUE);
3334
	  authenticated_id = string_copy_taint(
3335
	    exim_str_fail_toolong(argv[++i], EXIM_EMAILADDR_MAX, "-oMas"),
3336
	    GET_TAINTED);
3139
3337
3140
	/* -oMi: Set incoming interface address */
3338
	/* -oMi: Set incoming interface address */
3141
3339
3142
	else if (Ustrcmp(argrest, "i") == 0)
3340
	else if (Ustrcmp(argrest, "i") == 0)
3143
	  interface_address = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMi"), TRUE);
3341
	  interface_address = string_copy_taint(
3342
	    exim_str_fail_toolong(argv[++i], EXIM_IPADDR_MAX, "-oMi"),
3343
	    GET_TAINTED);
3144
3344
3145
	/* -oMm: Message reference */
3345
	/* -oMm: Message reference */
3146
3346
Lines 3160-3178 Link Here
3160
	  if (received_protocol)
3360
	  if (received_protocol)
3161
	    exim_fail("received_protocol is set already\n");
3361
	    exim_fail("received_protocol is set already\n");
3162
	  else
3362
	  else
3163
	    received_protocol = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMr"), TRUE);
3363
	    received_protocol = string_copy_taint(
3364
	      exim_str_fail_toolong(argv[++i], EXIM_DRIVERNAME_MAX, "-oMr"),
3365
	      GET_TAINTED);
3164
3366
3165
	/* -oMs: Set sender host name */
3367
	/* -oMs: Set sender host name */
3166
3368
3167
	else if (Ustrcmp(argrest, "s") == 0)
3369
	else if (Ustrcmp(argrest, "s") == 0)
3168
	  sender_host_name = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_HOSTNAME_MAX, "-oMs"), TRUE);
3370
	  sender_host_name = string_copy_taint(
3371
	    exim_str_fail_toolong(argv[++i], EXIM_HOSTNAME_MAX, "-oMs"),
3372
	    GET_TAINTED);
3169
3373
3170
	/* -oMt: Set sender ident */
3374
	/* -oMt: Set sender ident */
3171
3375
3172
	else if (Ustrcmp(argrest, "t") == 0)
3376
	else if (Ustrcmp(argrest, "t") == 0)
3173
	  {
3377
	  {
3174
	  sender_ident_set = TRUE;
3378
	  sender_ident_set = TRUE;
3175
	  sender_ident = string_copy_taint(exim_str_fail_toolong(argv[++i], EXIM_IDENTUSER_MAX, "-oMt"), TRUE);
3379
	  sender_ident = string_copy_taint(
3380
	    exim_str_fail_toolong(argv[++i], EXIM_IDENTUSER_MAX, "-oMt"),
3381
	    GET_TAINTED);
3176
	  }
3382
	  }
3177
3383
3178
	/* Else a bad argument */
3384
	/* Else a bad argument */
Lines 3230-3236 Link Here
3230
3436
3231
      case 'X':
3437
      case 'X':
3232
	if (*argrest) badarg = TRUE;
3438
	if (*argrest) badarg = TRUE;
3233
	else override_local_interfaces = string_copy_taint(exim_str_fail_toolong(argv[++i], 1024, "-oX"), TRUE);
3439
	else override_local_interfaces = string_copy_taint(
3440
	  exim_str_fail_toolong(argv[++i], 1024, "-oX"),
3441
	  GET_TAINTED);
3442
	break;
3443
3444
      /* -oY: Override creation of daemon notifier socket */
3445
3446
      case 'Y':
3447
	if (*argrest) badarg = TRUE;
3448
	else notifier_socket = NULL;
3234
	break;
3449
	break;
3235
3450
3236
      /* Unknown -o argument */
3451
      /* Unknown -o argument */
Lines 3271-3282 Link Here
3271
        exim_fail("received_protocol is set already\n");
3486
        exim_fail("received_protocol is set already\n");
3272
3487
3273
      if (!hn)
3488
      if (!hn)
3274
        received_protocol = string_copy_taint(exim_str_fail_toolong(argrest, EXIM_DRIVERNAME_MAX, "-p<protocol>"), TRUE);
3489
        received_protocol = string_copy_taint(
3490
	  exim_str_fail_toolong(argrest, EXIM_DRIVERNAME_MAX, "-p<protocol>"),
3491
	  GET_TAINTED);
3275
      else
3492
      else
3276
        {
3493
        {
3277
        (void) exim_str_fail_toolong(argrest, (EXIM_DRIVERNAME_MAX+1+EXIM_HOSTNAME_MAX), "-p<protocol>:<host>");
3494
        (void) exim_str_fail_toolong(argrest, (EXIM_DRIVERNAME_MAX+1+EXIM_HOSTNAME_MAX), "-p<protocol>:<host>");
3278
        received_protocol = string_copyn_taint(argrest, hn - argrest, TRUE);
3495
        received_protocol = string_copyn_taint(argrest, hn - argrest, GET_TAINTED);
3279
        sender_host_name = string_copy_taint(hn + 1, TRUE);
3496
        sender_host_name = string_copy_taint(hn + 1, GET_TAINTED);
3280
        }
3497
        }
3281
      }
3498
      }
3282
    break;
3499
    break;
Lines 3345-3353 Link Here
3345
	{
3562
	{
3346
	queue_interval = 0;
3563
	queue_interval = 0;
3347
	if (i+1 < argc && mac_ismsgid(argv[i+1]))
3564
	if (i+1 < argc && mac_ismsgid(argv[i+1]))
3348
	  start_queue_run_id = string_copy_taint(argv[++i], TRUE);
3565
	  start_queue_run_id = string_copy_taint(argv[++i], GET_TAINTED);
3349
	if (i+1 < argc && mac_ismsgid(argv[i+1]))
3566
	if (i+1 < argc && mac_ismsgid(argv[i+1]))
3350
	  stop_queue_run_id = string_copy_taint(argv[++i], TRUE);
3567
	  stop_queue_run_id = string_copy_taint(argv[++i], GET_TAINTED);
3351
	}
3568
	}
3352
3569
3353
    /* -q[f][f][l][G<name>/]<n>: Run the queue at regular intervals, optionally
3570
    /* -q[f][f][l][G<name>/]<n>: Run the queue at regular intervals, optionally
Lines 3395-3401 Link Here
3395
	tainted_selectstr = argv[++i];
3612
	tainted_selectstr = argv[++i];
3396
      else
3613
      else
3397
	exim_fail("exim: string expected after -R\n");
3614
	exim_fail("exim: string expected after -R\n");
3398
      deliver_selectstring = string_copy_taint(exim_str_fail_toolong(tainted_selectstr, EXIM_EMAILADDR_MAX, "-R"), TRUE);
3615
      deliver_selectstring = string_copy_taint(
3616
	exim_str_fail_toolong(tainted_selectstr, EXIM_EMAILADDR_MAX, "-R"),
3617
	GET_TAINTED);
3399
      }
3618
      }
3400
    break;
3619
    break;
3401
3620
Lines 3438-3444 Link Here
3438
	tainted_selectstr = argv[++i];
3657
	tainted_selectstr = argv[++i];
3439
      else
3658
      else
3440
	exim_fail("exim: string expected after -S\n");
3659
	exim_fail("exim: string expected after -S\n");
3441
      deliver_selectstring_sender = string_copy_taint(exim_str_fail_toolong(tainted_selectstr, EXIM_EMAILADDR_MAX, "-S"), TRUE);
3660
      deliver_selectstring_sender = string_copy_taint(
3661
	exim_str_fail_toolong(tainted_selectstr, EXIM_EMAILADDR_MAX, "-S"),
3662
	GET_TAINTED);
3442
      }
3663
      }
3443
    break;
3664
    break;
3444
3665
Lines 3449-3455 Link Here
3449
3670
3450
    case 'T':
3671
    case 'T':
3451
    if (f.running_in_test_harness && Ustrcmp(argrest, "qt") == 0)
3672
    if (f.running_in_test_harness && Ustrcmp(argrest, "qt") == 0)
3452
      fudged_queue_times = string_copy_taint(argv[++i], TRUE);
3673
      fudged_queue_times = string_copy_taint(argv[++i], GET_TAINTED);
3453
    else badarg = TRUE;
3674
    else badarg = TRUE;
3454
    break;
3675
    break;
3455
3676
Lines 3526-3532 Link Here
3526
    case 'z':
3747
    case 'z':
3527
    if (!*argrest)
3748
    if (!*argrest)
3528
      if (++i < argc)
3749
      if (++i < argc)
3529
	log_oneline = string_copy_taint(exim_str_fail_toolong(argv[i], 2048, "-z logtext"), TRUE);
3750
	log_oneline = string_copy_taint(
3751
	  exim_str_fail_toolong(argv[i], 2048, "-z logtext"),
3752
	  GET_TAINTED);
3530
      else
3753
      else
3531
        exim_fail("exim: file name expected after %s\n", argv[i-1]);
3754
        exim_fail("exim: file name expected after %s\n", argv[i-1]);
3532
    break;
3755
    break;
Lines 3561-3614 Link Here
3561
if (usage_wanted) exim_usage(called_as);
3784
if (usage_wanted) exim_usage(called_as);
3562
3785
3563
/* Arguments have been processed. Check for incompatibilities. */
3786
/* Arguments have been processed. Check for incompatibilities. */
3564
if ((
3787
if (  (  (smtp_input || extract_recipients || recipients_arg < argc)
3565
    (smtp_input || extract_recipients || recipients_arg < argc) &&
3788
      && (  f.daemon_listen || queue_interval >= 0 || bi_option
3566
    (f.daemon_listen || queue_interval >= 0 || bi_option ||
3789
	 || test_retry_arg >= 0 || test_rewrite_arg >= 0
3567
      test_retry_arg >= 0 || test_rewrite_arg >= 0 ||
3790
	 || filter_test != FTEST_NONE
3568
      filter_test != FTEST_NONE || (msg_action_arg > 0 && !one_msg_action))
3791
	 || msg_action_arg > 0 && !one_msg_action
3569
    ) ||
3792
      )  )
3570
    (
3793
   || (  msg_action_arg > 0
3571
    msg_action_arg > 0 &&
3794
      && (  f.daemon_listen || queue_interval > 0 || list_options
3572
    (f.daemon_listen || queue_interval > 0 || list_options ||
3795
	 || checking && msg_action != MSG_LOAD
3573
      (checking && msg_action != MSG_LOAD) ||
3796
	 || bi_option || test_retry_arg >= 0 || test_rewrite_arg >= 0
3574
      bi_option || test_retry_arg >= 0 || test_rewrite_arg >= 0)
3797
      )  )
3575
    ) ||
3798
   || (  (f.daemon_listen || queue_interval > 0)
3576
    (
3799
      && (  sender_address || list_options || list_queue || checking
3577
    (f.daemon_listen || queue_interval > 0) &&
3800
	 || bi_option
3578
    (sender_address != NULL || list_options || list_queue || checking ||
3801
      )  )
3579
      bi_option)
3802
   || f.daemon_listen && queue_interval == 0
3580
    ) ||
3803
   || f.inetd_wait_mode && queue_interval >= 0
3581
    (
3804
   || (  list_options
3582
    f.daemon_listen && queue_interval == 0
3805
      && (  checking || smtp_input || extract_recipients
3583
    ) ||
3806
	 || filter_test != FTEST_NONE || bi_option
3584
    (
3807
      )  )
3585
    f.inetd_wait_mode && queue_interval >= 0
3808
   || (  verify_address_mode
3586
    ) ||
3809
      && (  f.address_test_mode || smtp_input || extract_recipients
3587
    (
3810
	 || filter_test != FTEST_NONE || bi_option
3588
    list_options &&
3811
      )  )
3589
    (checking || smtp_input || extract_recipients ||
3812
   || (  f.address_test_mode
3590
      filter_test != FTEST_NONE || bi_option)
3813
      && (  smtp_input || extract_recipients || filter_test != FTEST_NONE
3591
    ) ||
3814
	 || bi_option
3592
    (
3815
      )  )
3593
    verify_address_mode &&
3816
   || (  smtp_input
3594
    (f.address_test_mode || smtp_input || extract_recipients ||
3817
      && (sender_address || filter_test != FTEST_NONE || extract_recipients)
3595
      filter_test != FTEST_NONE || bi_option)
3818
      )
3596
    ) ||
3819
   || deliver_selectstring && queue_interval < 0
3597
    (
3820
   || msg_action == MSG_LOAD && (!expansion_test || expansion_test_message)
3598
    f.address_test_mode && (smtp_input || extract_recipients ||
3599
      filter_test != FTEST_NONE || bi_option)
3600
    ) ||
3601
    (
3602
    smtp_input && (sender_address != NULL || filter_test != FTEST_NONE ||
3603
      extract_recipients)
3604
    ) ||
3605
    (
3606
    deliver_selectstring != NULL && queue_interval < 0
3607
    ) ||
3608
    (
3609
    msg_action == MSG_LOAD &&
3610
      (!expansion_test || expansion_test_message != NULL)
3611
    )
3612
   )
3821
   )
3613
  exim_fail("exim: incompatible command-line options or arguments\n");
3822
  exim_fail("exim: incompatible command-line options or arguments\n");
3614
3823
Lines 3628-3634 Link Here
3628
      version_string, (long int)real_uid, (long int)real_gid, (int)getpid(),
3837
      version_string, (long int)real_uid, (long int)real_gid, (int)getpid(),
3629
      debug_selector);
3838
      debug_selector);
3630
    if (!version_printed)
3839
    if (!version_printed)
3631
      show_whats_supported(stderr);
3840
      show_whats_supported(FALSE);
3632
    }
3841
    }
3633
  }
3842
  }
3634
3843
Lines 3646-3652 Link Here
3646
  {
3855
  {
3647
  struct rlimit rlp;
3856
  struct rlimit rlp;
3648
3857
3649
  #ifdef RLIMIT_NOFILE
3858
#ifdef RLIMIT_NOFILE
3650
  if (getrlimit(RLIMIT_NOFILE, &rlp) < 0)
3859
  if (getrlimit(RLIMIT_NOFILE, &rlp) < 0)
3651
    {
3860
    {
3652
    log_write(0, LOG_MAIN|LOG_PANIC, "getrlimit(RLIMIT_NOFILE) failed: %s",
3861
    log_write(0, LOG_MAIN|LOG_PANIC, "getrlimit(RLIMIT_NOFILE) failed: %s",
Lines 3669-3677 Link Here
3669
          strerror(errno));
3878
          strerror(errno));
3670
      }
3879
      }
3671
    }
3880
    }
3672
  #endif
3881
#endif
3673
3882
3674
  #ifdef RLIMIT_NPROC
3883
#ifdef RLIMIT_NPROC
3675
  if (getrlimit(RLIMIT_NPROC, &rlp) < 0)
3884
  if (getrlimit(RLIMIT_NPROC, &rlp) < 0)
3676
    {
3885
    {
3677
    log_write(0, LOG_MAIN|LOG_PANIC, "getrlimit(RLIMIT_NPROC) failed: %s",
3886
    log_write(0, LOG_MAIN|LOG_PANIC, "getrlimit(RLIMIT_NPROC) failed: %s",
Lines 3679-3698 Link Here
3679
    rlp.rlim_cur = rlp.rlim_max = 0;
3888
    rlp.rlim_cur = rlp.rlim_max = 0;
3680
    }
3889
    }
3681
3890
3682
  #ifdef RLIM_INFINITY
3891
# ifdef RLIM_INFINITY
3683
  if (rlp.rlim_cur != RLIM_INFINITY && rlp.rlim_cur < 1000)
3892
  if (rlp.rlim_cur != RLIM_INFINITY && rlp.rlim_cur < 1000)
3684
    {
3893
    {
3685
    rlp.rlim_cur = rlp.rlim_max = RLIM_INFINITY;
3894
    rlp.rlim_cur = rlp.rlim_max = RLIM_INFINITY;
3686
  #else
3895
# else
3687
  if (rlp.rlim_cur < 1000)
3896
  if (rlp.rlim_cur < 1000)
3688
    {
3897
    {
3689
    rlp.rlim_cur = rlp.rlim_max = 1000;
3898
    rlp.rlim_cur = rlp.rlim_max = 1000;
3690
  #endif
3899
# endif
3691
    if (setrlimit(RLIMIT_NPROC, &rlp) < 0)
3900
    if (setrlimit(RLIMIT_NPROC, &rlp) < 0)
3692
      log_write(0, LOG_MAIN|LOG_PANIC, "setrlimit(RLIMIT_NPROC) failed: %s",
3901
      log_write(0, LOG_MAIN|LOG_PANIC, "setrlimit(RLIMIT_NPROC) failed: %s",
3693
        strerror(errno));
3902
        strerror(errno));
3694
    }
3903
    }
3695
  #endif
3904
#endif
3696
  }
3905
  }
3697
3906
3698
/* Exim is normally entered as root (but some special configurations are
3907
/* Exim is normally entered as root (but some special configurations are
Lines 3815-3820 Link Here
3815
This needs to happen before we read the main configuration. */
4024
This needs to happen before we read the main configuration. */
3816
init_lookup_list();
4025
init_lookup_list();
3817
4026
4027
/*XXX this excrescence could move to the testsuite standard config setup file */
3818
#ifdef SUPPORT_I18N
4028
#ifdef SUPPORT_I18N
3819
if (f.running_in_test_harness) smtputf8_advertise_hosts = NULL;
4029
if (f.running_in_test_harness) smtputf8_advertise_hosts = NULL;
3820
#endif
4030
#endif
Lines 3853-3871 Link Here
3853
defined) */
4063
defined) */
3854
4064
3855
  {
4065
  {
4066
  int old_pool = store_pool;
3856
#ifdef MEASURE_TIMING
4067
#ifdef MEASURE_TIMING
3857
  struct timeval t0, diff;
4068
  struct timeval t0;
3858
  (void)gettimeofday(&t0, NULL);
4069
  (void)gettimeofday(&t0, NULL);
3859
#endif
4070
#endif
3860
4071
4072
  store_pool = POOL_CONFIG;
3861
  readconf_main(checking || list_options);
4073
  readconf_main(checking || list_options);
4074
  store_pool = old_pool;
3862
4075
3863
#ifdef MEASURE_TIMING
4076
#ifdef MEASURE_TIMING
3864
  report_time_since(&t0, US"readconf_main (delta)");
4077
  report_time_since(&t0, US"readconf_main (delta)");
3865
#endif
4078
#endif
3866
  }
4079
  }
3867
4080
3868
3869
/* Now in directory "/" */
4081
/* Now in directory "/" */
3870
4082
3871
if (cleanup_environment() == FALSE)
4083
if (cleanup_environment() == FALSE)
Lines 4168-4177 Link Here
4168
4380
4169
if (Uchdir(spool_directory) != 0)
4381
if (Uchdir(spool_directory) != 0)
4170
  {
4382
  {
4171
  int dummy;
4383
  (void) directory_make(spool_directory, US"", SPOOL_DIRECTORY_MODE, FALSE);
4172
  (void)directory_make(spool_directory, US"", SPOOL_DIRECTORY_MODE, FALSE);
4384
  (void) Uchdir(spool_directory);
4173
  dummy = /* quieten compiler */ Uchdir(spool_directory);
4174
  dummy = dummy;	/* yet more compiler quietening, sigh */
4175
  }
4385
  }
4176
4386
4177
/* Handle calls with the -bi option. This is a sendmail option to rebuild *the*
4387
/* Handle calls with the -bi option. This is a sendmail option to rebuild *the*
Lines 4182-4204 Link Here
4182
4392
4183
if (bi_option)
4393
if (bi_option)
4184
  {
4394
  {
4185
  (void)fclose(config_file);
4395
  (void) fclose(config_file);
4186
  if (bi_command)
4396
  if (bi_command && *bi_command)
4187
    {
4397
    {
4188
    int i = 0;
4398
    int i = 0;
4189
    uschar *argv[3];
4399
    uschar *argv[3];
4190
    argv[i++] = bi_command;
4400
    argv[i++] = bi_command;	/* nonexpanded option so assume untainted */
4191
    if (alias_arg) argv[i++] = alias_arg;
4401
    if (alias_arg) argv[i++] = alias_arg;
4192
    argv[i++] = NULL;
4402
    argv[i++] = NULL;
4193
4403
4194
    setgroups(group_count, group_list);
4404
    setgroups(group_count, group_list);
4195
    exim_setugid(real_uid, real_gid, FALSE, US"running bi_command");
4405
    exim_setugid(real_uid, real_gid, FALSE, US"running bi_command");
4196
4406
4197
    DEBUG(D_exec) debug_printf("exec %.256s %.256s\n", argv[0],
4407
    DEBUG(D_exec) debug_printf("exec '%.256s' %s%.256s%s\n", argv[0],
4198
      argv[1] ? argv[1] : US"");
4408
      argv[1] ? "'" : "", argv[1] ? argv[1] : US"", argv[1] ? "'" : "");
4199
4409
4200
    execv(CS argv[0], (char *const *)argv);
4410
    execv(CS argv[0], (char *const *)argv);
4201
    exim_fail("exim: exec failed: %s\n", strerror(errno));
4411
    exim_fail("exim: exec '%s' failed: %s\n", argv[0], strerror(errno));
4202
    }
4412
    }
4203
  else
4413
  else
4204
    {
4414
    {
Lines 4232-4238 Link Here
4232
     || queue_name_dest && prod_requires_admin
4442
     || queue_name_dest && prod_requires_admin
4233
     || debugset && !f.running_in_test_harness
4443
     || debugset && !f.running_in_test_harness
4234
     )
4444
     )
4235
    exim_fail("exim:%s permission denied\n", debugset? " debugging" : "");
4445
    exim_fail("exim:%s permission denied\n", debugset ? " debugging" : "");
4236
  }
4446
  }
4237
4447
4238
/* If the real user is not root or the exim uid, the argument for passing
4448
/* If the real user is not root or the exim uid, the argument for passing
Lines 4241-4251 Link Here
4241
one that supplied an input message, or we are using a patched exim for
4451
one that supplied an input message, or we are using a patched exim for
4242
regression testing. */
4452
regression testing. */
4243
4453
4244
if (real_uid != root_uid && real_uid != exim_uid &&
4454
if (  real_uid != root_uid && real_uid != exim_uid
4245
     (continue_hostname != NULL ||
4455
   && (  continue_hostname
4246
       (f.dont_deliver &&
4456
      || (  f.dont_deliver
4247
         (queue_interval >= 0 || f.daemon_listen || msg_action_arg > 0)
4457
	 && (queue_interval >= 0 || f.daemon_listen || msg_action_arg > 0)
4248
       )) && !f.running_in_test_harness)
4458
      )  )
4459
   && !f.running_in_test_harness
4460
   )
4249
  exim_fail("exim: Permission denied\n");
4461
  exim_fail("exim: Permission denied\n");
4250
4462
4251
/* If the caller is not trusted, certain arguments are ignored when running for
4463
/* If the caller is not trusted, certain arguments are ignored when running for
Lines 4267-4275 Link Here
4267
4479
4268
else
4480
else
4269
  {
4481
  {
4270
  if (sender_host_address != NULL)
4482
  if (sender_host_address)
4271
    sender_host_port = check_port(sender_host_address);
4483
    sender_host_port = check_port(sender_host_address);
4272
  if (interface_address != NULL)
4484
  if (interface_address)
4273
    interface_port = check_port(interface_address);
4485
    interface_port = check_port(interface_address);
4274
  }
4486
  }
4275
4487
Lines 4356-4373 Link Here
4356
situation (controlled by the TRUE below), in order to be as close as possible
4568
situation (controlled by the TRUE below), in order to be as close as possible
4357
to the state Exim usually runs in. */
4569
to the state Exim usually runs in. */
4358
4570
4359
if (!unprivileged &&                      /* originally had root AND */
4571
if (  !unprivileged				/* originally had root AND */
4360
    !removed_privilege &&                 /* still got root AND      */
4572
   && !removed_privilege			/* still got root AND      */
4361
    !f.daemon_listen &&                     /* not starting the daemon */
4573
   && !f.daemon_listen				/* not starting the daemon */
4362
    queue_interval <= 0 &&                /* (either kind of daemon) */
4574
   && queue_interval <= 0			/* (either kind of daemon) */
4363
      (                                   /*    AND EITHER           */
4575
   && (						/*    AND EITHER           */
4364
      deliver_drop_privilege ||           /* requested unprivileged  */
4576
         deliver_drop_privilege			/* requested unprivileged  */
4365
        (                                 /*       OR                */
4577
      || (					/*       OR                */
4366
        queue_interval < 0 &&             /* not running the queue   */
4578
            queue_interval < 0			/* not running the queue   */
4367
        (msg_action_arg < 0 ||            /*       and               */
4579
         && (  msg_action_arg < 0		/*       and               */
4368
          msg_action != MSG_DELIVER) &&   /* not delivering and      */
4580
            || msg_action != MSG_DELIVER	/* not delivering          */
4369
        (!checking || !f.address_test_mode) /* not address checking    */
4581
	    )					/*       and               */
4370
   )  ) )
4582
         && (!checking || !f.address_test_mode)	/* not address checking    */
4583
	 && !rcpt_verify_quota			/* and not quota checking  */
4584
   )  )  )
4371
  exim_setugid(exim_uid, exim_gid, TRUE, US"privilege not needed");
4585
  exim_setugid(exim_uid, exim_gid, TRUE, US"privilege not needed");
4372
4586
4373
/* When we are retaining a privileged uid, we still change to the exim gid. */
4587
/* When we are retaining a privileged uid, we still change to the exim gid. */
Lines 4398-4405 Link Here
4398
#ifdef WITH_CONTENT_SCAN
4612
#ifdef WITH_CONTENT_SCAN
4399
  int result;
4613
  int result;
4400
  set_process_info("scanning file for malware");
4614
  set_process_info("scanning file for malware");
4401
  result = malware_in_file(malware_test_file);
4615
  if ((result = malware_in_file(malware_test_file)) == FAIL)
4402
  if (result == FAIL)
4403
    {
4616
    {
4404
    printf("No malware found.\n");
4617
    printf("No malware found.\n");
4405
    exit(EXIT_SUCCESS);
4618
    exit(EXIT_SUCCESS);
Lines 4451-4457 Link Here
4451
  event_action gets expanded */
4664
  event_action gets expanded */
4452
4665
4453
  if (msg_action == MSG_REMOVE)
4666
  if (msg_action == MSG_REMOVE)
4667
    {
4668
    int old_pool = store_pool;
4669
    store_pool = POOL_CONFIG;
4454
    readconf_rest();
4670
    readconf_rest();
4671
    store_pool = old_pool;
4672
    store_writeprotect(POOL_CONFIG);
4673
    }
4455
4674
4456
  if (!one_msg_action)
4675
  if (!one_msg_action)
4457
    {
4676
    {
Lines 4476-4493 Link Here
4476
needed in transports so we lost the optimisation. */
4695
needed in transports so we lost the optimisation. */
4477
4696
4478
  {
4697
  {
4698
  int old_pool = store_pool;
4479
#ifdef MEASURE_TIMING
4699
#ifdef MEASURE_TIMING
4480
  struct timeval t0, diff;
4700
  struct timeval t0;
4481
  (void)gettimeofday(&t0, NULL);
4701
  (void)gettimeofday(&t0, NULL);
4482
#endif
4702
#endif
4483
4703
4704
  store_pool = POOL_CONFIG;
4484
  readconf_rest();
4705
  readconf_rest();
4706
  store_pool = old_pool;
4707
4708
  /* -be can add macro definitions, needing to link to the macro structure
4709
  chain.  Otherwise, make the memory used for config data readonly. */
4710
4711
  if (!expansion_test)
4712
    store_writeprotect(POOL_CONFIG);
4485
4713
4486
#ifdef MEASURE_TIMING
4714
#ifdef MEASURE_TIMING
4487
  report_time_since(&t0, US"readconf_rest (delta)");
4715
  report_time_since(&t0, US"readconf_rest (delta)");
4488
#endif
4716
#endif
4489
  }
4717
  }
4490
4718
4719
/* Handle a request to check quota */
4720
if (rcpt_verify_quota)
4721
  if (real_uid != root_uid && real_uid != exim_uid)
4722
    exim_fail("exim: Permission denied\n");
4723
  else if (recipients_arg >= argc)
4724
    exim_fail("exim: missing recipient for quota check\n");
4725
  else
4726
    {
4727
    verify_quota(argv[recipients_arg]);
4728
    exim_exit(EXIT_SUCCESS);
4729
    }
4730
4491
/* Handle the -brt option. This is for checking out retry configurations.
4731
/* Handle the -brt option. This is for checking out retry configurations.
4492
The next three arguments are a domain name or a complete address, and
4732
The next three arguments are a domain name or a complete address, and
4493
optionally two error numbers. All it does is to call the function that
4733
optionally two error numbers. All it does is to call the function that
Lines 4762-4768 Link Here
4762
5002
4763
        if (gecos_pattern && gecos_name)
5003
        if (gecos_pattern && gecos_name)
4764
          {
5004
          {
4765
          const pcre *re;
5005
          const pcre2_code *re;
4766
          re = regex_must_compile(gecos_pattern, FALSE, TRUE); /* Use malloc */
5006
          re = regex_must_compile(gecos_pattern, FALSE, TRUE); /* Use malloc */
4767
5007
4768
          if (regex_match_and_setup(re, name, 0, -1))
5008
          if (regex_match_and_setup(re, name, 0, -1))
Lines 4803-4818 Link Here
4803
configuration specifies something to use. When running in the test harness,
5043
configuration specifies something to use. When running in the test harness,
4804
any setting of unknown_login overrides the actual name. */
5044
any setting of unknown_login overrides the actual name. */
4805
5045
4806
if (originator_login == NULL || f.running_in_test_harness)
5046
if (!originator_login || f.running_in_test_harness)
4807
  {
5047
  {
4808
  if (unknown_login != NULL)
5048
  if (unknown_login)
4809
    {
5049
    {
4810
    originator_login = expand_string(unknown_login);
5050
    originator_login = expand_string(unknown_login);
4811
    if (originator_name == NULL && unknown_username != NULL)
5051
    if (!originator_name && unknown_username)
4812
      originator_name = expand_string(unknown_username);
5052
      originator_name = expand_string(unknown_username);
4813
    if (originator_name == NULL) originator_name = US"";
5053
    if (!originator_name) originator_name = US"";
4814
    }
5054
    }
4815
  if (originator_login == NULL)
5055
  if (!originator_login)
4816
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Failed to get user name for uid %d",
5056
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Failed to get user name for uid %d",
4817
      (int)real_uid);
5057
      (int)real_uid);
4818
  }
5058
  }
Lines 4820-4826 Link Here
4820
/* Ensure that the user name is in a suitable form for use as a "phrase" in an
5060
/* Ensure that the user name is in a suitable form for use as a "phrase" in an
4821
RFC822 address.*/
5061
RFC822 address.*/
4822
5062
4823
originator_name = parse_fix_phrase(originator_name, Ustrlen(originator_name));
5063
originator_name = US parse_fix_phrase(originator_name, Ustrlen(originator_name));
4824
5064
4825
/* If a message is created by this call of Exim, the uid/gid of its originator
5065
/* If a message is created by this call of Exim, the uid/gid of its originator
4826
are those of the caller. These values are overridden if an existing message is
5066
are those of the caller. These values are overridden if an existing message is
Lines 4851-4857 Link Here
4851
  routines in it, so call even if tls_require_ciphers is unset */
5091
  routines in it, so call even if tls_require_ciphers is unset */
4852
    {
5092
    {
4853
# ifdef MEASURE_TIMING
5093
# ifdef MEASURE_TIMING
4854
    struct timeval t0, diff;
5094
    struct timeval t0;
4855
    (void)gettimeofday(&t0, NULL);
5095
    (void)gettimeofday(&t0, NULL);
4856
# endif
5096
# endif
4857
    if (!tls_dropprivs_validate_require_cipher(FALSE))
5097
    if (!tls_dropprivs_validate_require_cipher(FALSE))
Lines 4922-4929 Link Here
4922
  sender, or if a sender other than <> is set, override with the originator's
5162
  sender, or if a sender other than <> is set, override with the originator's
4923
  login (which will get qualified below), except when checking things. */
5163
  login (which will get qualified below), except when checking things. */
4924
5164
4925
  if (sender_address == NULL             /* No sender_address set */
5165
  if (  !sender_address                  /* No sender_address set */
4926
       ||                                /*         OR            */
5166
     ||                                  /*         OR            */
4927
       (sender_address[0] != 0 &&        /* Non-empty sender address, AND */
5167
       (sender_address[0] != 0 &&        /* Non-empty sender address, AND */
4928
       !checking))                       /* Not running tests, including filter tests */
5168
       !checking))                       /* Not running tests, including filter tests */
4929
    {
5169
    {
Lines 4974-4984 Link Here
4974
    }
5214
    }
4975
5215
4976
  if (recipients_arg < argc)
5216
  if (recipients_arg < argc)
4977
    {
4978
    while (recipients_arg < argc)
5217
    while (recipients_arg < argc)
4979
      {
5218
      {
4980
      /* Supplied addresses are tainted since they come from a user */
5219
      /* Supplied addresses are tainted since they come from a user */
4981
      uschar * s = string_copy_taint(exim_str_fail_toolong(argv[recipients_arg++], EXIM_DISPLAYMAIL_MAX, "address verification"), TRUE);
5220
      uschar * s = string_copy_taint(
5221
	exim_str_fail_toolong(argv[recipients_arg++], EXIM_DISPLAYMAIL_MAX, "address verification"),
5222
	GET_TAINTED);
4982
      while (*s)
5223
      while (*s)
4983
        {
5224
        {
4984
        BOOL finished = FALSE;
5225
        BOOL finished = FALSE;
Lines 4990-5002 Link Here
4990
          while (*++s == ',' || isspace(*s)) ;
5231
          while (*++s == ',' || isspace(*s)) ;
4991
        }
5232
        }
4992
      }
5233
      }
4993
    }
4994
5234
4995
  else for (;;)
5235
  else for (;;)
4996
    {
5236
    {
4997
    uschar * s = get_stdinput(NULL, NULL);
5237
    uschar * s = get_stdinput(NULL, NULL);
4998
    if (!s) break;
5238
    if (!s) break;
4999
    test_address(string_copy_taint(exim_str_fail_toolong(s, EXIM_DISPLAYMAIL_MAX, "address verification (stdin)"), TRUE), flags, &exit_value);
5239
    test_address(string_copy_taint(
5240
	exim_str_fail_toolong(s, EXIM_DISPLAYMAIL_MAX, "address verification (stdin)"),
5241
	GET_TAINTED),
5242
      flags, &exit_value);
5000
    }
5243
    }
5001
5244
5002
  route_tidyup();
5245
  route_tidyup();
Lines 5019-5025 Link Here
5019
    message_id = US exim_str_fail_toolong(argv[msg_action_arg], MESSAGE_ID_LENGTH, "message-id");
5262
    message_id = US exim_str_fail_toolong(argv[msg_action_arg], MESSAGE_ID_LENGTH, "message-id");
5020
    /* Checking the length of the ID is sufficient to validate it.
5263
    /* Checking the length of the ID is sufficient to validate it.
5021
    Get an untainted version so file opens can be done. */
5264
    Get an untainted version so file opens can be done. */
5022
    message_id = string_copy_taint(message_id, FALSE);
5265
    message_id = string_copy_taint(message_id, GET_UNTAINTED);
5023
5266
5024
    spoolname = string_sprintf("%s-H", message_id);
5267
    spoolname = string_sprintf("%s-H", message_id);
5025
    if ((deliver_datafile = spool_open_datafile(message_id)) < 0)
5268
    if ((deliver_datafile = spool_open_datafile(message_id)) < 0)
Lines 5136-5142 Link Here
5136
  it. The code works for both IPv4 and IPv6, as it happens. */
5379
  it. The code works for both IPv4 and IPv6, as it happens. */
5137
5380
5138
  size = host_aton(sender_host_address, x);
5381
  size = host_aton(sender_host_address, x);
5139
  sender_host_address = store_get(48, FALSE);  /* large enough for full IPv6 */
5382
  sender_host_address = store_get(48, GET_UNTAINTED);  /* large enough for full IPv6 */
5140
  (void)host_nmtoa(size, x, -1, sender_host_address, ':');
5383
  (void)host_nmtoa(size, x, -1, sender_host_address, ':');
5141
5384
5142
  /* Now set up for testing */
5385
  /* Now set up for testing */
Lines 5304-5310 Link Here
5304
  {
5547
  {
5305
  if (!f.is_inetd) set_process_info("accepting a local %sSMTP message from <%s>",
5548
  if (!f.is_inetd) set_process_info("accepting a local %sSMTP message from <%s>",
5306
    smtp_batched_input? "batched " : "",
5549
    smtp_batched_input? "batched " : "",
5307
    (sender_address!= NULL)? sender_address : originator_login);
5550
    sender_address ? sender_address : originator_login);
5308
  }
5551
  }
5309
else
5552
else
5310
  {
5553
  {
Lines 5354-5360 Link Here
5354
    }
5597
    }
5355
  }
5598
  }
5356
5599
5357
/* Otherwise, set up the input size limit here. */
5600
/* Otherwise, set up the input size limit here and set no stdin stdio buffer
5601
(we handle buferring so as to have visibility of fill level). */
5358
5602
5359
else
5603
else
5360
  {
5604
  {
Lines 5366-5371 Link Here
5366
    else
5610
    else
5367
      log_write(0, LOG_MAIN|LOG_PANIC_DIE, "invalid value for "
5611
      log_write(0, LOG_MAIN|LOG_PANIC_DIE, "invalid value for "
5368
        "message_size_limit: %s", expand_string_message);
5612
        "message_size_limit: %s", expand_string_message);
5613
5614
  setvbuf(stdin, NULL, _IONBF, 0);
5369
  }
5615
  }
5370
5616
5371
/* Loop for several messages when reading SMTP input. If we fork any child
5617
/* Loop for several messages when reading SMTP input. If we fork any child
Lines 5398-5412 Link Here
5398
5644
5399
if (!f.synchronous_delivery)
5645
if (!f.synchronous_delivery)
5400
  {
5646
  {
5401
  #ifdef SA_NOCLDWAIT
5647
#ifdef SA_NOCLDWAIT
5402
  struct sigaction act;
5648
  struct sigaction act;
5403
  act.sa_handler = SIG_IGN;
5649
  act.sa_handler = SIG_IGN;
5404
  sigemptyset(&(act.sa_mask));
5650
  sigemptyset(&(act.sa_mask));
5405
  act.sa_flags = SA_NOCLDWAIT;
5651
  act.sa_flags = SA_NOCLDWAIT;
5406
  sigaction(SIGCHLD, &act, NULL);
5652
  sigaction(SIGCHLD, &act, NULL);
5407
  #else
5653
#else
5408
  signal(SIGCHLD, SIG_IGN);
5654
  signal(SIGCHLD, SIG_IGN);
5409
  #endif
5655
#endif
5410
  }
5656
  }
5411
5657
5412
/* Save the current store pool point, for resetting at the start of
5658
/* Save the current store pool point, for resetting at the start of
Lines 5418-5424 Link Here
5418
messages to be read (SMTP input), or FALSE otherwise (not SMTP, or SMTP channel
5664
messages to be read (SMTP input), or FALSE otherwise (not SMTP, or SMTP channel
5419
collapsed). */
5665
collapsed). */
5420
5666
5421
while (more)
5667
for (BOOL more = TRUE; more; )
5422
  {
5668
  {
5423
  rmark reset_point = store_mark();
5669
  rmark reset_point = store_mark();
5424
  message_id[0] = 0;
5670
  message_id[0] = 0;
Lines 5460-5469 Link Here
5460
      /* Now get the data for the message */
5706
      /* Now get the data for the message */
5461
5707
5462
      more = receive_msg(extract_recipients);
5708
      more = receive_msg(extract_recipients);
5463
      if (message_id[0] == 0)
5709
      if (!message_id[0])
5464
        {
5710
        {
5465
	cancel_cutthrough_connection(TRUE, US"receive dropped");
5711
	cancel_cutthrough_connection(TRUE, US"receive dropped");
5466
        if (more) goto moreloop;
5712
        if (more) goto MORELOOP;
5467
        smtp_log_no_mail();               /* Log no mail if configured */
5713
        smtp_log_no_mail();               /* Log no mail if configured */
5468
        exim_exit(EXIT_FAILURE);
5714
        exim_exit(EXIT_FAILURE);
5469
        }
5715
        }
Lines 5505-5515 Link Here
5505
      uschar * errmess;
5751
      uschar * errmess;
5506
      /* There can be multiple addresses, so EXIM_DISPLAYMAIL_MAX (tuned for 1) is too short.
5752
      /* There can be multiple addresses, so EXIM_DISPLAYMAIL_MAX (tuned for 1) is too short.
5507
       * We'll still want to cap it to something, just in case. */
5753
       * We'll still want to cap it to something, just in case. */
5508
      uschar * s = string_copy_taint(exim_str_fail_toolong(list[i], BIG_BUFFER_SIZE, "address argument"), TRUE);
5754
      uschar * s = string_copy_taint(
5755
	exim_str_fail_toolong(list[i], BIG_BUFFER_SIZE, "address argument"),
5756
	GET_TAINTED);
5509
5757
5510
      /* Loop for each comma-separated address */
5758
      /* Loop for each comma-separated address */
5511
5759
5512
      while (*s != 0)
5760
      while (*s)
5513
        {
5761
        {
5514
        BOOL finished = FALSE;
5762
        BOOL finished = FALSE;
5515
        uschar *recipient;
5763
        uschar *recipient;
Lines 5571-5577 Link Here
5571
                errors_sender_rc : EXIT_FAILURE;
5819
                errors_sender_rc : EXIT_FAILURE;
5572
            }
5820
            }
5573
5821
5574
        receive_add_recipient(string_copy_taint(recipient, TRUE), -1);
5822
        receive_add_recipient(string_copy_taint(recipient, GET_TAINTED), -1);
5575
        s = ss;
5823
        s = ss;
5576
        if (!finished)
5824
        if (!finished)
5577
          while (*(++s) != 0 && (*s == ',' || isspace(*s)));
5825
          while (*(++s) != 0 && (*s == ',' || isspace(*s)));
Lines 5610-5622 Link Here
5610
    the file copy. */
5858
    the file copy. */
5611
5859
5612
    if (!receive_timeout)
5860
    if (!receive_timeout)
5613
      {
5861
      if (poll_one_fd(0, POLLIN, 30*60*1000) == 0)	/* 30 minutes */
5614
      struct timeval t = { .tv_sec = 30*60, .tv_usec = 0 };	/* 30 minutes */
5862
	mainlog_close();
5615
      fd_set r;
5616
5617
      FD_ZERO(&r); FD_SET(0, &r);
5618
      if (select(1, &r, NULL, NULL, &t) == 0) mainlog_close();
5619
      }
5620
5863
5621
    /* Read the data for the message. If filter_test is not FTEST_NONE, this
5864
    /* Read the data for the message. If filter_test is not FTEST_NONE, this
5622
    will just read the headers for the message, and not write anything onto the
5865
    will just read the headers for the message, and not write anything onto the
Lines 5629-5635 Link Here
5629
    for real; when reading the headers of a message for filter testing,
5872
    for real; when reading the headers of a message for filter testing,
5630
    it is TRUE if the headers were terminated by '.' and FALSE otherwise. */
5873
    it is TRUE if the headers were terminated by '.' and FALSE otherwise. */
5631
5874
5632
    if (message_id[0] == 0) exim_exit(EXIT_FAILURE);
5875
    if (!message_id[0]) exim_exit(EXIT_FAILURE);
5633
    }  /* Non-SMTP message reception */
5876
    }  /* Non-SMTP message reception */
5634
5877
5635
  /* If this is a filter testing run, there are headers in store, but
5878
  /* If this is a filter testing run, there are headers in store, but
Lines 5822-5832 Link Here
5822
  finished subprocesses here, in case there are lots of messages coming in
6065
  finished subprocesses here, in case there are lots of messages coming in
5823
  from the same source. */
6066
  from the same source. */
5824
6067
5825
  #ifndef SIG_IGN_WORKS
6068
#ifndef SIG_IGN_WORKS
5826
  while (waitpid(-1, NULL, WNOHANG) > 0);
6069
  while (waitpid(-1, NULL, WNOHANG) > 0);
5827
  #endif
6070
#endif
5828
6071
5829
moreloop:
6072
MORELOOP:
5830
  return_path = sender_address = NULL;
6073
  return_path = sender_address = NULL;
5831
  authenticated_sender = NULL;
6074
  authenticated_sender = NULL;
5832
  deliver_localpart_orig = NULL;
6075
  deliver_localpart_orig = NULL;
(-)exim.orig/src/exim_dbmbuild.c (-45 / +33 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 31-37 Link Here
31
31
32
#include "exim.h"
32
#include "exim.h"
33
33
34
uschar * spool_directory = NULL;	/* dummy for dbstuff.h */
34
uschar * spool_directory = NULL;	/* dummy for hintsdb.h */
35
35
36
/******************************************************************************/
36
/******************************************************************************/
37
					/* dummies needed by Solaris build */
37
					/* dummies needed by Solaris build */
Lines 42-51 Link Here
42
readconf_printtime(int t)
42
readconf_printtime(int t)
43
{ return NULL; }
43
{ return NULL; }
44
void *
44
void *
45
store_get_3(int size, BOOL tainted, const char *filename, int linenumber)
45
store_get_3(int size, const void * proto_mem, const char *filename, int linenumber)
46
{ return NULL; }
46
{ return NULL; }
47
void **
47
void **
48
store_reset_3(void **ptr, int pool, const char *filename, int linenumber)
48
store_reset_3(void **ptr, const char *filename, int linenumber)
49
{ return NULL; }
49
{ return NULL; }
50
void
50
void
51
store_release_above_3(void *ptr, const char *func, int linenumber)
51
store_release_above_3(void *ptr, const char *func, int linenumber)
Lines 70-75 Link Here
70
unsigned int		log_selector[1];
70
unsigned int		log_selector[1];
71
uschar *		queue_name;
71
uschar *		queue_name;
72
BOOL			split_spool_directory;
72
BOOL			split_spool_directory;
73
74
75
/* These introduced by the taintwarn handling */
76
rmark
77
store_mark_3(const char *func, int linenumber)
78
{ return NULL; }
79
#ifdef ALLOW_INSECURE_TAINTED_DATA
80
BOOL    allow_insecure_tainted_data;
81
#endif
82
73
/******************************************************************************/
83
/******************************************************************************/
74
84
75
85
Lines 96-121 Link Here
96
#endif /* STRERROR_FROM_ERRLIST */
106
#endif /* STRERROR_FROM_ERRLIST */
97
107
98
108
99
/* For Berkeley DB >= 2, we can define a function to be called in case of DB
100
errors. This should help with debugging strange DB problems, e.g. getting "File
101
exists" when you try to open a db file. The API changed at release 4.3. */
102
103
#if defined(USE_DB) && defined(DB_VERSION_STRING)
104
void
105
# if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
106
dbfn_bdb_error_callback(const DB_ENV *dbenv, const char *pfx, const char *msg)
107
{
108
dbenv = dbenv;
109
# else
110
dbfn_bdb_error_callback(const char *pfx, char *msg)
111
{
112
# endif
113
pfx = pfx;
114
printf("Berkeley DB error: %s\n", msg);
115
}
116
#endif
117
118
119
109
120
/*************************************************
110
/*************************************************
121
*          Interpret escape sequence             *
111
*          Interpret escape sequence             *
Lines 256-264 Link Here
256
/* It is apparently necessary to open with O_RDWR for this to work
246
/* It is apparently necessary to open with O_RDWR for this to work
257
with gdbm-1.7.3, though no reading is actually going to be done. */
247
with gdbm-1.7.3, though no reading is actually going to be done. */
258
248
259
EXIM_DBOPEN(temp_dbmname, dirname, O_RDWR|O_CREAT|O_EXCL, 0644, &d);
249
if (!(d = exim_dbopen(temp_dbmname, dirname, O_RDWR|O_CREAT|O_EXCL, 0644)))
260
261
if (d == NULL)
262
  {
250
  {
263
  printf("exim_dbmbuild: unable to create %s: %s\n", temp_dbmname,
251
  printf("exim_dbmbuild: unable to create %s: %s\n", temp_dbmname,
264
    strerror(errno));
252
    strerror(errno));
Lines 337-347 Link Here
337
325
338
    if (started)
326
    if (started)
339
      {
327
      {
340
      EXIM_DATUM_INIT(content);
328
      exim_datum_init(&content);
341
      EXIM_DATUM_DATA(content) = CS buffer;
329
      exim_datum_data_set(&content, buffer);
342
      EXIM_DATUM_SIZE(content) = bptr - buffer + add_zero;
330
      exim_datum_size_set(&content, bptr - buffer + add_zero);
343
331
344
      switch(rc = EXIM_DBPUTB(d, key, content))
332
      switch(rc = exim_dbputb(d, &key, &content))
345
        {
333
        {
346
        case EXIM_DBPUTB_OK:
334
        case EXIM_DBPUTB_OK:
347
	  count++;
335
	  count++;
Lines 351-357 Link Here
351
	  if (warn) fprintf(stderr, "** Duplicate key \"%s\"\n", keybuffer);
339
	  if (warn) fprintf(stderr, "** Duplicate key \"%s\"\n", keybuffer);
352
	  dupcount++;
340
	  dupcount++;
353
	  if(duperr) yield = 1;
341
	  if(duperr) yield = 1;
354
	  if (lastdup) EXIM_DBPUT(d, key, content);
342
	  if (lastdup) exim_dbput(d, &key, &content);
355
	  break;
343
	  break;
356
344
357
        default:
345
        default:
Lines 364-371 Link Here
364
      bptr = buffer;
352
      bptr = buffer;
365
      }
353
      }
366
354
367
    EXIM_DATUM_INIT(key);
355
    exim_datum_init(&key);
368
    EXIM_DATUM_DATA(key) = CS keybuffer;
356
    exim_datum_data_set(&key, keybuffer);
369
357
370
    /* Deal with quoted keys. Escape sequences always make one character
358
    /* Deal with quoted keys. Escape sequences always make one character
371
    out of several, so we can re-build in place. */
359
    out of several, so we can re-build in place. */
Lines 382-397 Link Here
382
        s++;
370
        s++;
383
        }
371
        }
384
      if (*s != 0) s++;               /* Past terminating " */
372
      if (*s != 0) s++;               /* Past terminating " */
385
      EXIM_DATUM_SIZE(key) = t - keystart + add_zero;
373
      exim_datum_size_set(&key, t - keystart + add_zero);
386
      }
374
      }
387
    else
375
    else
388
      {
376
      {
389
      keystart = s;
377
      keystart = s;
390
      while (*s != 0 && *s != ':' && !isspace(*s)) s++;
378
      while (*s != 0 && *s != ':' && !isspace(*s)) s++;
391
      EXIM_DATUM_SIZE(key) = s - keystart + add_zero;
379
      exim_datum_size_set(&key, s - keystart + add_zero);
392
      }
380
      }
393
381
394
    if (EXIM_DATUM_SIZE(key) > 256)
382
    if (exim_datum_size_get(&key) > 256)
395
      {
383
      {
396
      printf("Keys longer than 255 characters cannot be handled\n");
384
      printf("Keys longer than 255 characters cannot be handled\n");
397
      started = 0;
385
      started = 0;
Lines 400-409 Link Here
400
      }
388
      }
401
389
402
    if (lowercase)
390
    if (lowercase)
403
      for (i = 0; i < EXIM_DATUM_SIZE(key) - add_zero; i++)
391
      for (i = 0; i < exim_datum_size_get(&key) - add_zero; i++)
404
        keybuffer[i] = tolower(keystart[i]);
392
        keybuffer[i] = tolower(keystart[i]);
405
    else
393
    else
406
      for (i = 0; i < EXIM_DATUM_SIZE(key) - add_zero; i++)
394
      for (i = 0; i < exim_datum_size_get(&key) - add_zero; i++)
407
        keybuffer[i] = keystart[i];
395
        keybuffer[i] = keystart[i];
408
396
409
    keybuffer[i] = 0;
397
    keybuffer[i] = 0;
Lines 427-437 Link Here
427
if (started)
415
if (started)
428
  {
416
  {
429
  int rc;
417
  int rc;
430
  EXIM_DATUM_INIT(content);
418
  exim_datum_init(&content);
431
  EXIM_DATUM_DATA(content) = CS buffer;
419
  exim_datum_data_set(&content, buffer);
432
  EXIM_DATUM_SIZE(content) = bptr - buffer + add_zero;
420
  exim_datum_size_set(&content, bptr - buffer + add_zero);
433
421
434
  switch(rc = EXIM_DBPUTB(d, key, content))
422
  switch(rc = exim_dbputb(d, &key, &content))
435
    {
423
    {
436
    case EXIM_DBPUTB_OK:
424
    case EXIM_DBPUTB_OK:
437
    count++;
425
    count++;
Lines 441-447 Link Here
441
    if (warn) fprintf(stderr, "** Duplicate key \"%s\"\n", keybuffer);
429
    if (warn) fprintf(stderr, "** Duplicate key \"%s\"\n", keybuffer);
442
    dupcount++;
430
    dupcount++;
443
    if (duperr) yield = 1;
431
    if (duperr) yield = 1;
444
    if (lastdup) EXIM_DBPUT(d, key, content);
432
    if (lastdup) exim_dbput(d, &key, &content);
445
    break;
433
    break;
446
434
447
    default:
435
    default:
Lines 456-462 Link Here
456
444
457
TIDYUP:
445
TIDYUP:
458
446
459
EXIM_DBCLOSE(d);
447
exim_dbclose(d);
460
(void)fclose(f);
448
(void)fclose(f);
461
449
462
/* If successful, output the number of entries and rename the temporary
450
/* If successful, output the number of entries and rename the temporary
(-)exim.orig/src/exim_dbutil.c (-91 / +115 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 17-27 Link Here
17
In all cases, the first argument is the name of the spool directory. The second
17
In all cases, the first argument is the name of the spool directory. The second
18
argument is the name of the database file. The available names are:
18
argument is the name of the database file. The available names are:
19
19
20
  retry:      retry delivery information
20
  callout:	callout verification cache
21
  misc:       miscellaneous hints data
21
  misc:		miscellaneous hints data
22
  wait-<t>:   message waiting information; <t> is a transport name
22
  ratelimit:	record for ACL "ratelimit" condition
23
  callout:    callout verification cache
23
  retry:	etry delivery information
24
  tls:	      TLS session resumption cache
24
  seen:		imestamp records for ACL "seen" condition
25
  tls:		TLS session resumption cache
26
  wait-<t>:	message waiting information; <t> is a transport name
25
27
26
There are a number of common subroutines, followed by three main programs,
28
There are a number of common subroutines, followed by three main programs,
27
whose inclusion is controlled by -D on the compilation command. */
29
whose inclusion is controlled by -D on the compilation command. */
Lines 38-49 Link Here
38
#define type_callout   4
40
#define type_callout   4
39
#define type_ratelimit 5
41
#define type_ratelimit 5
40
#define type_tls       6
42
#define type_tls       6
43
#define type_seen      7
41
44
42
45
43
/* This is used by our cut-down dbfn_open(). */
46
/* This is used by our cut-down dbfn_open(). */
44
47
45
uschar *spool_directory;
48
uschar *spool_directory;
46
49
50
BOOL keyonly = FALSE;
51
BOOL utc = FALSE;
52
47
53
48
/******************************************************************************/
54
/******************************************************************************/
49
      /* dummies needed by Solaris build */
55
      /* dummies needed by Solaris build */
Lines 69-100 Link Here
69
unsigned int		log_selector[1];
75
unsigned int		log_selector[1];
70
uschar *		queue_name;
76
uschar *		queue_name;
71
BOOL			split_spool_directory;
77
BOOL			split_spool_directory;
72
/******************************************************************************/
73
74
75
/*************************************************
76
*         Berkeley DB error callback             *
77
*************************************************/
78
78
79
/* For Berkeley DB >= 2, we can define a function to be called in case of DB
80
errors. This should help with debugging strange DB problems, e.g. getting "File
81
exists" when you try to open a db file. The API changed at release 4.3. */
82
79
83
#if defined(USE_DB) && defined(DB_VERSION_STRING)
80
/* These introduced by the taintwarn handling */
84
void
81
#ifdef ALLOW_INSECURE_TAINTED_DATA
85
#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
82
BOOL    allow_insecure_tainted_data;
86
dbfn_bdb_error_callback(const DB_ENV *dbenv, const char *pfx, const char *msg)
87
{
88
dbenv = dbenv;
89
#else
90
dbfn_bdb_error_callback(const char *pfx, char *msg)
91
{
92
#endif
93
pfx = pfx;
94
printf("Berkeley DB error: %s\n", msg);
95
}
96
#endif
83
#endif
97
84
85
/******************************************************************************/
98
86
99
87
100
/*************************************************
88
/*************************************************
Lines 106-112 Link Here
106
void
94
void
107
sigalrm_handler(int sig)
95
sigalrm_handler(int sig)
108
{
96
{
109
sig = sig;            /* Keep picky compilers happy */
110
sigalrm_seen = 1;
97
sigalrm_seen = 1;
111
}
98
}
112
99
Lines 120-127 Link Here
120
usage(uschar *name, uschar *options)
107
usage(uschar *name, uschar *options)
121
{
108
{
122
printf("Usage: exim_%s%s  <spool-directory> <database-name>\n", name, options);
109
printf("Usage: exim_%s%s  <spool-directory> <database-name>\n", name, options);
123
printf("  <database-name> = retry | misc | wait-<transport-name> | callout | ratelimit | tls\n");
110
printf("  <database-name> = retry | misc | wait-<transport-name> | callout | ratelimit | tls | seen\n");
124
exit(1);
111
exit(EXIT_FAILURE);
125
}
112
}
126
113
127
114
Lines 136-155 Link Here
136
static int
123
static int
137
check_args(int argc, uschar **argv, uschar *name, uschar *options)
124
check_args(int argc, uschar **argv, uschar *name, uschar *options)
138
{
125
{
139
if (argc == 3)
126
uschar * aname = argv[optind + 1];
127
if (argc - optind == 2)
140
  {
128
  {
141
  if (Ustrcmp(argv[2], "retry") == 0) return type_retry;
129
  if (Ustrcmp(aname, "retry") == 0)	return type_retry;
142
  if (Ustrcmp(argv[2], "misc") == 0) return type_misc;
130
  if (Ustrcmp(aname, "misc") == 0)	return type_misc;
143
  if (Ustrncmp(argv[2], "wait-", 5) == 0) return type_wait;
131
  if (Ustrncmp(aname, "wait-", 5) == 0)	return type_wait;
144
  if (Ustrcmp(argv[2], "callout") == 0) return type_callout;
132
  if (Ustrcmp(aname, "callout") == 0)	return type_callout;
145
  if (Ustrcmp(argv[2], "ratelimit") == 0) return type_ratelimit;
133
  if (Ustrcmp(aname, "ratelimit") == 0)	return type_ratelimit;
146
  if (Ustrcmp(argv[2], "tls") == 0) return type_tls;
134
  if (Ustrcmp(aname, "tls") == 0)	return type_tls;
135
  if (Ustrcmp(aname, "seen") == 0)	return type_seen;
147
  }
136
  }
148
usage(name, options);
137
usage(name, options);
149
return -1;              /* Never obeyed */
138
return -1;              /* Never obeyed */
150
}
139
}
151
140
152
141
142
FUNC_MAYBE_UNUSED
143
static void
144
options(int argc, uschar * argv[], uschar * name, const uschar * opts)
145
{
146
int opt;
147
148
opterr = 0;
149
while ((opt = getopt(argc, (char * const *)argv, CCS opts)) != -1)
150
  switch (opt)
151
  {
152
  case 'k':	keyonly = TRUE; break;
153
  case 'z':	utc = TRUE; break;
154
  default:	usage(name, US" [-z] [-k]");
155
  }
156
}
157
158
159
153
160
154
/*************************************************
161
/*************************************************
155
*         Handle attempts to write the log       *
162
*         Handle attempts to write the log       *
Lines 177-184 Link Here
177
vfprintf(stderr, format, ap);
184
vfprintf(stderr, format, ap);
178
fprintf(stderr, "\n");
185
fprintf(stderr, "\n");
179
va_end(ap);
186
va_end(ap);
180
selector = selector;     /* Keep picky compilers happy */
181
flags = flags;
182
}
187
}
183
188
184
189
Lines 192-198 Link Here
192
uschar *
197
uschar *
193
print_time(time_t t)
198
print_time(time_t t)
194
{
199
{
195
struct tm *tmstr = localtime(&t);
200
struct tm *tmstr = utc ? gmtime(&t) : localtime(&t);
196
Ustrftime(time_buffer, sizeof(time_buffer), "%d-%b-%Y %H:%M:%S", tmstr);
201
Ustrftime(time_buffer, sizeof(time_buffer), "%d-%b-%Y %H:%M:%S", tmstr);
197
return time_buffer;
202
return time_buffer;
198
}
203
}
Lines 206-213 Link Here
206
uschar *
211
uschar *
207
print_cache(int value)
212
print_cache(int value)
208
{
213
{
209
return (value == ccache_accept)? US"accept" :
214
return value == ccache_accept ? US"accept" :
210
       (value == ccache_reject)? US"reject" :
215
       value == ccache_reject ? US"reject" :
211
       US"unknown";
216
       US"unknown";
212
}
217
}
213
218
Lines 337-343 Link Here
337
#else
342
#else
338
filename = string_sprintf("%s/%s", dirname, name);
343
filename = string_sprintf("%s/%s", dirname, name);
339
#endif
344
#endif
340
EXIM_DBOPEN(filename, dirname, flags, 0, &dbblock->dbptr);
345
dbblock->dbptr = exim_dbopen(filename, dirname, flags, 0);
341
346
342
if (!dbblock->dbptr)
347
if (!dbblock->dbptr)
343
  {
348
  {
Lines 373-379 Link Here
373
void
378
void
374
dbfn_close(open_db *dbblock)
379
dbfn_close(open_db *dbblock)
375
{
380
{
376
EXIM_DBCLOSE(dbblock->dbptr);
381
exim_dbclose(dbblock->dbptr);
377
(void)close(dbblock->lockfd);
382
(void)close(dbblock->lockfd);
378
}
383
}
379
384
Lines 403-427 Link Here
403
void *yield;
408
void *yield;
404
EXIM_DATUM key_datum, result_datum;
409
EXIM_DATUM key_datum, result_datum;
405
int klen = Ustrlen(key) + 1;
410
int klen = Ustrlen(key) + 1;
406
uschar * key_copy = store_get(klen, is_tainted(key));
411
uschar * key_copy = store_get(klen, key);
407
412
408
memcpy(key_copy, key, klen);
413
memcpy(key_copy, key, klen);
409
414
410
EXIM_DATUM_INIT(key_datum);         /* Some DBM libraries require the datum */
415
exim_datum_init(&key_datum);         /* Some DBM libraries require the datum */
411
EXIM_DATUM_INIT(result_datum);      /* to be cleared before use. */
416
exim_datum_init(&result_datum);      /* to be cleared before use. */
412
EXIM_DATUM_DATA(key_datum) = CS key_copy;
417
exim_datum_data_set(&key_datum, key_copy);
413
EXIM_DATUM_SIZE(key_datum) = klen;
418
exim_datum_size_set(&key_datum, klen);
414
419
415
if (!EXIM_DBGET(dbblock->dbptr, key_datum, result_datum)) return NULL;
420
if (!exim_dbget(dbblock->dbptr, &key_datum, &result_datum)) return NULL;
416
421
417
/* Assume for now that anything stored could have been tainted. Properly
422
/* Assume for now that anything stored could have been tainted. Properly
418
we should store the taint status along with the data. */
423
we should store the taint status along with the data. */
419
424
420
yield = store_get(EXIM_DATUM_SIZE(result_datum), TRUE);
425
yield = store_get(exim_datum_size_get(&result_datum), GET_TAINTED);
421
memcpy(yield, EXIM_DATUM_DATA(result_datum), EXIM_DATUM_SIZE(result_datum));
426
memcpy(yield, exim_datum_data_get(&result_datum), exim_datum_size_get(&result_datum));
422
if (length) *length = EXIM_DATUM_SIZE(result_datum);
427
if (length) *length = exim_datum_size_get(&result_datum);
423
428
424
EXIM_DATUM_FREE(result_datum);    /* Some DBM libs require freeing */
429
exim_datum_free(&result_datum);    /* Some DBM libs require freeing */
425
return yield;
430
return yield;
426
}
431
}
427
432
Lines 450-467 Link Here
450
EXIM_DATUM key_datum, value_datum;
455
EXIM_DATUM key_datum, value_datum;
451
dbdata_generic *gptr = (dbdata_generic *)ptr;
456
dbdata_generic *gptr = (dbdata_generic *)ptr;
452
int klen = Ustrlen(key) + 1;
457
int klen = Ustrlen(key) + 1;
453
uschar * key_copy = store_get(klen, is_tainted(key));
458
uschar * key_copy = store_get(klen, key);
454
459
455
memcpy(key_copy, key, klen);
460
memcpy(key_copy, key, klen);
456
gptr->time_stamp = time(NULL);
461
gptr->time_stamp = time(NULL);
457
462
458
EXIM_DATUM_INIT(key_datum);         /* Some DBM libraries require the datum */
463
exim_datum_init(&key_datum);         /* Some DBM libraries require the datum */
459
EXIM_DATUM_INIT(value_datum);       /* to be cleared before use. */
464
exim_datum_init(&value_datum);       /* to be cleared before use. */
460
EXIM_DATUM_DATA(key_datum) = CS key_copy;
465
exim_datum_data_set(&key_datum, key_copy);
461
EXIM_DATUM_SIZE(key_datum) = klen;
466
exim_datum_size_set(&key_datum, klen);
462
EXIM_DATUM_DATA(value_datum) = CS ptr;
467
exim_datum_data_set(&value_datum, ptr);
463
EXIM_DATUM_SIZE(value_datum) = length;
468
exim_datum_size_set(&value_datum, length);
464
return EXIM_DBPUT(dbblock->dbptr, key_datum, value_datum);
469
return exim_dbput(dbblock->dbptr, &key_datum, &value_datum);
465
}
470
}
466
471
467
472
Lines 482-495 Link Here
482
dbfn_delete(open_db *dbblock, const uschar *key)
487
dbfn_delete(open_db *dbblock, const uschar *key)
483
{
488
{
484
int klen = Ustrlen(key) + 1;
489
int klen = Ustrlen(key) + 1;
485
uschar * key_copy = store_get(klen, is_tainted(key));
490
uschar * key_copy = store_get(klen, key);
491
EXIM_DATUM key_datum;
486
492
487
memcpy(key_copy, key, klen);
493
memcpy(key_copy, key, klen);
488
EXIM_DATUM key_datum;
494
exim_datum_init(&key_datum);         /* Some DBM libraries require clearing */
489
EXIM_DATUM_INIT(key_datum);         /* Some DBM libraries require clearing */
495
exim_datum_data_set(&key_datum, key_copy);
490
EXIM_DATUM_DATA(key_datum) = CS key_copy;
496
exim_datum_size_set(&key_datum, klen);
491
EXIM_DATUM_SIZE(key_datum) = klen;
497
return exim_dbdel(dbblock->dbptr, &key_datum);
492
return EXIM_DBDEL(dbblock->dbptr, key_datum);
493
}
498
}
494
499
495
#endif  /* EXIM_TIDYDB || EXIM_FIXDB */
500
#endif  /* EXIM_TIDYDB || EXIM_FIXDB */
Lines 518-538 Link Here
518
{
523
{
519
EXIM_DATUM key_datum, value_datum;
524
EXIM_DATUM key_datum, value_datum;
520
uschar *yield;
525
uschar *yield;
521
value_datum = value_datum;    /* dummy; not all db libraries use this */
522
526
523
/* Some dbm require an initialization */
527
/* Some dbm require an initialization */
524
528
525
if (start) EXIM_DBCREATE_CURSOR(dbblock->dbptr, cursor);
529
if (start) *cursor = exim_dbcreate_cursor(dbblock->dbptr);
526
530
527
EXIM_DATUM_INIT(key_datum);         /* Some DBM libraries require the datum */
531
exim_datum_init(&key_datum);         /* Some DBM libraries require the datum */
528
EXIM_DATUM_INIT(value_datum);       /* to be cleared before use. */
532
exim_datum_init(&value_datum);       /* to be cleared before use. */
529
533
530
yield = (EXIM_DBSCAN(dbblock->dbptr, key_datum, value_datum, start, *cursor))?
534
yield = exim_dbscan(dbblock->dbptr, &key_datum, &value_datum, start, *cursor)
531
  US EXIM_DATUM_DATA(key_datum) : NULL;
535
  ? US exim_datum_data_get(&key_datum) : NULL;
532
536
533
/* Some dbm require a termination */
537
/* Some dbm require a termination */
534
538
535
if (!yield) EXIM_DBDELETE_CURSOR(*cursor);
539
if (!yield) exim_dbdelete_cursor(*cursor);
536
return yield;
540
return yield;
537
}
541
}
538
#endif  /* EXIM_DUMPDB || EXIM_TIDYDB */
542
#endif  /* EXIM_DUMPDB || EXIM_TIDYDB */
Lines 555-565 Link Here
555
uschar **argv = USS cargv;
559
uschar **argv = USS cargv;
556
uschar keybuffer[1024];
560
uschar keybuffer[1024];
557
561
562
store_init();
563
options(argc, argv, US"dumpdb", US"kz");
564
558
/* Check the arguments, and open the database */
565
/* Check the arguments, and open the database */
559
566
560
dbdata_type = check_args(argc, argv, US"dumpdb", US"");
567
dbdata_type = check_args(argc, argv, US"dumpdb", US" [-z] [-k]");
561
spool_directory = argv[1];
568
argc -= optind; argv += optind;
562
if (!(dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE, TRUE)))
569
spool_directory = argv[0];
570
571
if (!(dbm = dbfn_open(argv[1], O_RDONLY, &dbblock, FALSE, TRUE)))
563
  exit(1);
572
  exit(1);
564
573
565
/* Scan the file, formatting the information for each entry. Note
574
/* Scan the file, formatting the information for each entry. Note
Lines 576-581 Link Here
576
  dbdata_ratelimit *ratelimit;
585
  dbdata_ratelimit *ratelimit;
577
  dbdata_ratelimit_unique *rate_unique;
586
  dbdata_ratelimit_unique *rate_unique;
578
  dbdata_tls_session *session;
587
  dbdata_tls_session *session;
588
  dbdata_seen *seen;
579
  int count_bad = 0;
589
  int count_bad = 0;
580
  int length;
590
  int length;
581
  uschar *t;
591
  uschar *t;
Lines 593-604 Link Here
593
    }
603
    }
594
  Ustrcpy(keybuffer, key);
604
  Ustrcpy(keybuffer, key);
595
605
596
  if (!(value = dbfn_read_with_length(dbm, keybuffer, &length)))
606
  if (keyonly)
607
    printf("  %s\n", keybuffer);
608
  else if (!(value = dbfn_read_with_length(dbm, keybuffer, &length)))
597
    fprintf(stderr, "**** Entry \"%s\" was in the key scan, but the record "
609
    fprintf(stderr, "**** Entry \"%s\" was in the key scan, but the record "
598
                    "was not found in the file - something is wrong!\n",
610
                    "was not found in the file - something is wrong!\n",
599
      CS keybuffer);
611
      CS keybuffer);
600
  else
612
  else
601
    {
602
    /* Note: don't use print_time more than once in one statement, since
613
    /* Note: don't use print_time more than once in one statement, since
603
    it uses a single buffer. */
614
    it uses a single buffer. */
604
615
Lines 715-722 Link Here
715
	session = (dbdata_tls_session *)value;
726
	session = (dbdata_tls_session *)value;
716
	printf("  %s %.*s\n", keybuffer, length, session->session);
727
	printf("  %s %.*s\n", keybuffer, length, session->session);
717
	break;
728
	break;
729
730
      case type_seen:
731
	seen = (dbdata_seen *)value;
732
	printf("%s\t%s\n", keybuffer, print_time(seen->time_stamp));
733
	break;
718
      }
734
      }
719
    }
720
  store_reset(reset_point);
735
  store_reset(reset_point);
721
  }
736
  }
722
737
Lines 761-781 Link Here
761
is re-used. */
776
is re-used. */
762
777
763
778
764
int main(int argc, char **cargv)
779
int
780
main(int argc, char **cargv)
765
{
781
{
766
int dbdata_type;
782
int dbdata_type;
767
uschar **argv = USS cargv;
783
uschar **argv = USS cargv;
768
uschar buffer[256];
784
uschar buffer[256];
769
uschar name[256];
785
uschar name[256];
770
rmark reset_point;
786
rmark reset_point;
787
uschar * aname;
771
788
789
store_init();
790
options(argc, argv, US"fixdb", US"z");
772
name[0] = 0;  /* No name set */
791
name[0] = 0;  /* No name set */
773
792
774
/* Sort out the database type, verify what we are working on and then process
793
/* Sort out the database type, verify what we are working on and then process
775
user requests */
794
user requests */
776
795
777
dbdata_type = check_args(argc, argv, US"fixdb", US"");
796
dbdata_type = check_args(argc, argv, US"fixdb", US" [-z]");
778
printf("Modifying Exim hints database %s/db/%s\n", argv[1], argv[2]);
797
argc -= optind; argv += optind;
798
spool_directory = argv[0];
799
aname = argv[1];
800
801
printf("Modifying Exim hints database %s/db/%s\n", spool_directory, aname);
779
802
780
for(; (reset_point = store_mark()); store_reset(reset_point))
803
for(; (reset_point = store_mark()); store_reset(reset_point))
781
  {
804
  {
Lines 822-830 Link Here
822
  if (field[0] != 0)
845
  if (field[0] != 0)
823
    {
846
    {
824
    int verify = 1;
847
    int verify = 1;
825
    spool_directory = argv[1];
826
848
827
    if (!(dbm = dbfn_open(argv[2], O_RDWR, &dbblock, FALSE, TRUE)))
849
    if (!(dbm = dbfn_open(aname, O_RDWR, &dbblock, FALSE, TRUE)))
828
      continue;
850
      continue;
829
851
830
    if (Ustrcmp(field, "d") == 0)
852
    if (Ustrcmp(field, "d") == 0)
Lines 993-1000 Link Here
993
1015
994
  /* Handle a read request, or verify after an update. */
1016
  /* Handle a read request, or verify after an update. */
995
1017
996
  spool_directory = argv[1];
1018
  if (!(dbm = dbfn_open(aname, O_RDONLY, &dbblock, FALSE, TRUE)))
997
  if (!(dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE, TRUE)))
998
    continue;
1019
    continue;
999
1020
1000
  if (!(record = dbfn_read_with_length(dbm, name, &oldlength)))
1021
  if (!(record = dbfn_read_with_length(dbm, name, &oldlength)))
Lines 1124-1130 Link Here
1124
} key_item;
1145
} key_item;
1125
1146
1126
1147
1127
int main(int argc, char **cargv)
1148
int
1149
main(int argc, char **cargv)
1128
{
1150
{
1129
struct stat statbuf;
1151
struct stat statbuf;
1130
int maxkeep = 30 * 24 * 60 * 60;
1152
int maxkeep = 30 * 24 * 60 * 60;
Lines 1138-1143 Link Here
1138
uschar buffer[256];
1160
uschar buffer[256];
1139
uschar *key;
1161
uschar *key;
1140
1162
1163
store_init();
1164
1141
/* Scan the options */
1165
/* Scan the options */
1142
1166
1143
for (i = 1; i < argc; i++)
1167
for (i = 1; i < argc; i++)
Lines 1203-1209 Link Here
1203
     key;
1227
     key;
1204
     key = dbfn_scan(dbm, FALSE, &cursor))
1228
     key = dbfn_scan(dbm, FALSE, &cursor))
1205
  {
1229
  {
1206
  key_item *k = store_get(sizeof(key_item) + Ustrlen(key), is_tainted(key));
1230
  key_item * k = store_get(sizeof(key_item) + Ustrlen(key), key);
1207
  k->next = keychain;
1231
  k->next = keychain;
1208
  keychain = k;
1232
  keychain = k;
1209
  Ustrcpy(k->key, key);
1233
  Ustrcpy(k->key, key);
(-)exim.orig/src/exim.h (-6 / +29 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2021 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 87-92 Link Here
87
# include <limits.h>
88
# include <limits.h>
88
#endif
89
#endif
89
90
91
#ifdef EXIM_HAVE_INOTIFY
92
# include <sys/inotify.h>
93
#endif
94
#ifdef EXIM_HAVE_KEVENT
95
# include <sys/event.h>
96
#endif
97
90
/* C99 integer types, figure out how to undo this if needed for older systems */
98
/* C99 integer types, figure out how to undo this if needed for older systems */
91
99
92
#include <inttypes.h>
100
#include <inttypes.h>
Lines 515-521 Link Here
515
523
516
/* The header from the PCRE regex package */
524
/* The header from the PCRE regex package */
517
525
518
#include <pcre.h>
526
#define PCRE2_CODE_UNIT_WIDTH 8
527
#include <pcre2.h>
519
528
520
/* Exim includes are in several files. Note that local_scan.h #includes
529
/* Exim includes are in several files. Note that local_scan.h #includes
521
config.h, mytypes.h, and store.h, so we don't need to mention them explicitly.
530
config.h, mytypes.h, and store.h, so we don't need to mention them explicitly.
Lines 523-533 Link Here
523
532
524
#include "local_scan.h"
533
#include "local_scan.h"
525
#include "macros.h"
534
#include "macros.h"
526
#include "dbstuff.h"
535
#include "hintsdb.h"
536
#include "hintsdb_structs.h"
527
#include "structs.h"
537
#include "structs.h"
528
#include "blob.h"
538
#include "blob.h"
529
#include "globals.h"
530
#include "hash.h"
539
#include "hash.h"
540
#include "globals.h"
531
#include "functions.h"
541
#include "functions.h"
532
#include "dbfunctions.h"
542
#include "dbfunctions.h"
533
#include "osfunctions.h"
543
#include "osfunctions.h"
Lines 538-546 Link Here
538
#ifdef SUPPORT_SPF
548
#ifdef SUPPORT_SPF
539
# include "spf.h"
549
# include "spf.h"
540
#endif
550
#endif
541
#ifdef EXPERIMENTAL_SRS
542
# include "srs.h"
543
#endif
544
#ifndef DISABLE_DKIM
551
#ifndef DISABLE_DKIM
545
# include "dkim.h"
552
# include "dkim.h"
546
#endif
553
#endif
Lines 644-648 Link Here
644
# define EXIM_GROUPLIST_SIZE NGROUPS_MAX
651
# define EXIM_GROUPLIST_SIZE NGROUPS_MAX
645
#endif
652
#endif
646
653
654
/* Linux has TCP_CORK, FreeBSD has TCP_NOPUSH; they do pretty much the same */
655
656
#ifdef TCP_CORK
657
# define EXIM_TCP_CORK TCP_CORK
658
#elif defined(TCP_NOPUSH)
659
# define EXIM_TCP_CORK TCP_NOPUSH
660
#endif
661
662
/* LibreSSL seems to not push out the SMTP response to QUIT with our usual
663
handling which is trying to get the client to FIN first so that the server does
664
not get the TIME_WAIT */
665
666
#if !defined(DISABLE_TLS) && defined(USE_OPENSSL) && defined(LIBRESSL_VERSION_NUMBER)
667
# define SERVERSIDE_CLOSE_NOWAIT
668
#endif
669
647
#endif
670
#endif
648
/* End of exim.h */
671
/* End of exim.h */
(-)exim.orig/src/exim_lock.c (-3 / +2 lines)
Lines 10-16 Link Here
10
10
11
Argument: the name of the lock file
11
Argument: the name of the lock file
12
12
13
Copyright (c) The Exim Maintainers 2016
13
Copyright (c) The Exim Maintainers 2016 - 2021
14
*/
14
*/
15
15
16
#include "os.h"
16
#include "os.h"
Lines 87-93 Link Here
87
static void
87
static void
88
sigalrm_handler(int sig)
88
sigalrm_handler(int sig)
89
{
89
{
90
sig = sig;      /* Keep picky compilers happy */
91
sigalrm_seen = TRUE;
90
sigalrm_seen = TRUE;
92
}
91
}
93
92
Lines 584-590 Link Here
584
if (restore_times)
583
if (restore_times)
585
  {
584
  {
586
  struct stat strestore;
585
  struct stat strestore;
587
#ifdef EXIM_HAVE_OPENAT
586
#ifdef EXIM_HAVE_FUTIMENS
588
  int fd = open(filename, O_RDWR); /* use fd for both get & restore */
587
  int fd = open(filename, O_RDWR); /* use fd for both get & restore */
589
  struct timespec tt[2];
588
  struct timespec tt[2];
590
589
(-)exim.orig/src/exiqgrep.src (-3 / +8 lines)
Lines 2-7 Link Here
2
2
3
# Utility for searching and displaying queue information.
3
# Utility for searching and displaying queue information.
4
# Written by Matt Hubbard 15 August 2002
4
# Written by Matt Hubbard 15 August 2002
5
#
6
# Copyright (c) The Exim Maintainers 2021 - 2022
5
7
6
# Except when they appear in comments, the following placeholders in this
8
# Except when they appear in comments, the following placeholders in this
7
# source are replaced when it is turned into a runnable script:
9
# source are replaced when it is turned into a runnable script:
Lines 53-64 Link Here
53
        exit 0;
55
        exit 0;
54
}
56
}
55
57
56
getopts('hf:r:y:o:s:C:zxlibRcaG:',\%opt);
58
if (!getopts('hf:r:y:o:s:C:zxlibRcaG:E:',\%opt)) { &help; exit; }
57
if ($ARGV[0]) { &help; exit;}
59
if ($opt{h}) { &help; exit; }
58
if ($opt{h}) { &help; exit;}
60
if ($ARGV[0] || !($opt{f} || $opt{r} || $opt{s} || $opt{y} || $opt{o} || $opt{z} || $opt{x} || $opt{c}))
61
   { &help; exit(1); }
59
if ($opt{a}) { $eargs = '-bp'; }
62
if ($opt{a}) { $eargs = '-bp'; }
60
if ($opt{C} && -e $opt{C} && -f $opt{C} && -R $opt{C}) { $eargs .= ' -C '.$opt{C}; }
63
if ($opt{C} && -e $opt{C} && -f $opt{C} && -R $opt{C}) { $eargs .= ' -C '.$opt{C}; }
61
if ($opt{G}) { $eargs .= ' -qG'.$opt{G}; }
64
if ($opt{G}) { $eargs .= ' -qG'.$opt{G}; }
65
if ($opt{E}) { $exim = $opt{E}; }
62
66
63
# Read message queue output into hash
67
# Read message queue output into hash
64
&collect();
68
&collect();
Lines 75-80 Link Here
75
79
76
	-h		This help message.
80
	-h		This help message.
77
	-C		Specify which exim.conf to use.
81
	-C		Specify which exim.conf to use.
82
	-E		Specify exim binary to use.
78
83
79
Selection criteria:
84
Selection criteria:
80
	-f <regexp>	Match sender address sender (field is "< >" wrapped)
85
	-f <regexp>	Match sender address sender (field is "< >" wrapped)
(-)exim.orig/src/expand.c (-1489 / +1637 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 131-137 Link Here
131
  US"run",
131
  US"run",
132
  US"sg",
132
  US"sg",
133
  US"sort",
133
  US"sort",
134
#ifdef EXPERIMENTAL_SRS_NATIVE
134
#ifdef SUPPORT_SRS
135
  US"srs_encode",
135
  US"srs_encode",
136
#endif
136
#endif
137
  US"substr",
137
  US"substr",
Lines 166-172 Link Here
166
  EITEM_RUN,
166
  EITEM_RUN,
167
  EITEM_SG,
167
  EITEM_SG,
168
  EITEM_SORT,
168
  EITEM_SORT,
169
#ifdef EXPERIMENTAL_SRS_NATIVE
169
#ifdef SUPPORT_SRS
170
  EITEM_SRS_ENCODE,
170
  EITEM_SRS_ENCODE,
171
#endif
171
#endif
172
  EITEM_SUBSTR,
172
  EITEM_SUBSTR,
Lines 177-183 Link Here
177
cases to introduce arguments, whereas for other it is part of the name. This is
177
cases to introduce arguments, whereas for other it is part of the name. This is
178
an historical mis-design. */
178
an historical mis-design. */
179
179
180
static uschar *op_table_underscore[] = {
180
static uschar * op_table_underscore[] = {
181
  US"from_utf8",
181
  US"from_utf8",
182
  US"local_part",
182
  US"local_part",
183
  US"quote_local_part",
183
  US"quote_local_part",
Lines 216-222 Link Here
216
  US"base62d",
216
  US"base62d",
217
  US"base64",
217
  US"base64",
218
  US"base64d",
218
  US"base64d",
219
  US"bless",
220
  US"domain",
219
  US"domain",
221
  US"escape",
220
  US"escape",
222
  US"escape8bit",
221
  US"escape8bit",
Lines 264-270 Link Here
264
  EOP_BASE62D,
263
  EOP_BASE62D,
265
  EOP_BASE64,
264
  EOP_BASE64,
266
  EOP_BASE64D,
265
  EOP_BASE64D,
267
  EOP_BLESS,
268
  EOP_DOMAIN,
266
  EOP_DOMAIN,
269
  EOP_ESCAPE,
267
  EOP_ESCAPE,
270
  EOP_ESCAPE8BIT,
268
  EOP_ESCAPE8BIT,
Lines 334-340 Link Here
334
  US"gei",
332
  US"gei",
335
  US"gt",
333
  US"gt",
336
  US"gti",
334
  US"gti",
337
#ifdef EXPERIMENTAL_SRS_NATIVE
335
#ifdef SUPPORT_SRS
338
  US"inbound_srs",
336
  US"inbound_srs",
339
#endif
337
#endif
340
  US"inlist",
338
  US"inlist",
Lines 387-393 Link Here
387
  ECOND_STR_GEI,
385
  ECOND_STR_GEI,
388
  ECOND_STR_GT,
386
  ECOND_STR_GT,
389
  ECOND_STR_GTI,
387
  ECOND_STR_GTI,
390
#ifdef EXPERIMENTAL_SRS_NATIVE
388
#ifdef SUPPORT_SRS
391
  ECOND_INBOUND_SRS,
389
  ECOND_INBOUND_SRS,
392
#endif
390
#endif
393
  ECOND_INLIST,
391
  ECOND_INLIST,
Lines 446-454 Link Here
446
  vtype_pspace,         /* partition space; value is T/F for spool/log */
444
  vtype_pspace,         /* partition space; value is T/F for spool/log */
447
  vtype_pinodes,        /* partition inodes; value is T/F for spool/log */
445
  vtype_pinodes,        /* partition inodes; value is T/F for spool/log */
448
  vtype_cert		/* SSL certificate */
446
  vtype_cert		/* SSL certificate */
449
  #ifndef DISABLE_DKIM
447
#ifndef DISABLE_DKIM
450
  ,vtype_dkim           /* Lookup of value in DKIM signature */
448
  ,vtype_dkim           /* Lookup of value in DKIM signature */
451
  #endif
449
#endif
452
};
450
};
453
451
454
/* Type for main variable table */
452
/* Type for main variable table */
Lines 585-593 Link Here
585
  { "interface_address",   vtype_stringptr,   &interface_address },
583
  { "interface_address",   vtype_stringptr,   &interface_address },
586
  { "interface_port",      vtype_int,         &interface_port },
584
  { "interface_port",      vtype_int,         &interface_port },
587
  { "item",                vtype_stringptr,   &iterate_item },
585
  { "item",                vtype_stringptr,   &iterate_item },
588
  #ifdef LOOKUP_LDAP
586
#ifdef LOOKUP_LDAP
589
  { "ldap_dn",             vtype_stringptr,   &eldap_dn },
587
  { "ldap_dn",             vtype_stringptr,   &eldap_dn },
590
  #endif
588
#endif
591
  { "load_average",        vtype_load_avg,    NULL },
589
  { "load_average",        vtype_load_avg,    NULL },
592
  { "local_part",          vtype_stringptr,   &deliver_localpart },
590
  { "local_part",          vtype_stringptr,   &deliver_localpart },
593
  { "local_part_data",     vtype_stringptr,   &deliver_localpart_data },
591
  { "local_part_data",     vtype_stringptr,   &deliver_localpart_data },
Lines 752-769 Link Here
752
  { "spool_directory",     vtype_stringptr,   &spool_directory },
750
  { "spool_directory",     vtype_stringptr,   &spool_directory },
753
  { "spool_inodes",        vtype_pinodes,     (void *)TRUE },
751
  { "spool_inodes",        vtype_pinodes,     (void *)TRUE },
754
  { "spool_space",         vtype_pspace,      (void *)TRUE },
752
  { "spool_space",         vtype_pspace,      (void *)TRUE },
755
#ifdef EXPERIMENTAL_SRS
753
#ifdef SUPPORT_SRS
756
  { "srs_db_address",      vtype_stringptr,   &srs_db_address },
757
  { "srs_db_key",          vtype_stringptr,   &srs_db_key },
758
  { "srs_orig_recipient",  vtype_stringptr,   &srs_orig_recipient },
759
  { "srs_orig_sender",     vtype_stringptr,   &srs_orig_sender },
760
#endif
761
#if defined(EXPERIMENTAL_SRS) || defined(EXPERIMENTAL_SRS_NATIVE)
762
  { "srs_recipient",       vtype_stringptr,   &srs_recipient },
754
  { "srs_recipient",       vtype_stringptr,   &srs_recipient },
763
#endif
755
#endif
764
#ifdef EXPERIMENTAL_SRS
765
  { "srs_status",          vtype_stringptr,   &srs_status },
766
#endif
767
  { "thisaddress",         vtype_stringptr,   &filter_thisaddress },
756
  { "thisaddress",         vtype_stringptr,   &filter_thisaddress },
768
757
769
  /* The non-(in,out) variables are now deprecated */
758
  /* The non-(in,out) variables are now deprecated */
Lines 779-785 Link Here
779
  { "tls_in_ourcert",      vtype_cert,        &tls_in.ourcert },
768
  { "tls_in_ourcert",      vtype_cert,        &tls_in.ourcert },
780
  { "tls_in_peercert",     vtype_cert,        &tls_in.peercert },
769
  { "tls_in_peercert",     vtype_cert,        &tls_in.peercert },
781
  { "tls_in_peerdn",       vtype_stringptr,   &tls_in.peerdn },
770
  { "tls_in_peerdn",       vtype_stringptr,   &tls_in.peerdn },
782
#ifdef EXPERIMENTAL_TLS_RESUME
771
#ifndef DISABLE_TLS_RESUME
783
  { "tls_in_resumption",   vtype_int,         &tls_in.resumption },
772
  { "tls_in_resumption",   vtype_int,         &tls_in.resumption },
784
#endif
773
#endif
785
#ifndef DISABLE_TLS
774
#ifndef DISABLE_TLS
Lines 797-803 Link Here
797
  { "tls_out_ourcert",     vtype_cert,        &tls_out.ourcert },
786
  { "tls_out_ourcert",     vtype_cert,        &tls_out.ourcert },
798
  { "tls_out_peercert",    vtype_cert,        &tls_out.peercert },
787
  { "tls_out_peercert",    vtype_cert,        &tls_out.peercert },
799
  { "tls_out_peerdn",      vtype_stringptr,   &tls_out.peerdn },
788
  { "tls_out_peerdn",      vtype_stringptr,   &tls_out.peerdn },
800
#ifdef EXPERIMENTAL_TLS_RESUME
789
#ifndef DISABLE_TLS_RESUME
801
  { "tls_out_resumption",  vtype_int,         &tls_out.resumption },
790
  { "tls_out_resumption",  vtype_int,         &tls_out.resumption },
802
#endif
791
#endif
803
#ifndef DISABLE_TLS
792
#ifndef DISABLE_TLS
Lines 1299-1305 Link Here
1299
const uschar * tlist = list;
1288
const uschar * tlist = list;
1300
int sep = 0;
1289
int sep = 0;
1301
/* Tainted mem for the throwaway element copies */
1290
/* Tainted mem for the throwaway element copies */
1302
uschar * dummy = store_get(2, TRUE);
1291
uschar * dummy = store_get(2, GET_TAINTED);
1303
1292
1304
if (field < 0)
1293
if (field < 0)
1305
  {
1294
  {
Lines 1595-1601 Link Here
1595
*/
1584
*/
1596
1585
1597
static uschar *
1586
static uschar *
1598
find_header(uschar *name, int *newsize, unsigned flags, uschar *charset)
1587
find_header(uschar *name, int *newsize, unsigned flags, const uschar *charset)
1599
{
1588
{
1600
BOOL found = !name;
1589
BOOL found = !name;
1601
int len = name ? Ustrlen(name) : 0;
1590
int len = name ? Ustrlen(name) : 0;
Lines 1709-1717 Link Here
1709
if (sender_host_name)
1698
if (sender_host_name)
1710
  g = string_append(g, 3, US";\n\tiprev=pass (", sender_host_name, US")");
1699
  g = string_append(g, 3, US";\n\tiprev=pass (", sender_host_name, US")");
1711
else if (host_lookup_deferred)
1700
else if (host_lookup_deferred)
1712
  g = string_catn(g, US";\n\tiprev=temperror", 19);
1701
  g = string_cat(g, US";\n\tiprev=temperror");
1713
else if (host_lookup_failed)
1702
else if (host_lookup_failed)
1714
  g = string_catn(g, US";\n\tiprev=fail", 13);
1703
  g = string_cat(g, US";\n\tiprev=fail");
1715
else
1704
else
1716
  return g;
1705
  return g;
1717
1706
Lines 1762-1769 Link Here
1762
#ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
1751
#ifndef EXIM_HAVE_ABSTRACT_UNIX_SOCKETS
1763
uschar * sname;
1752
uschar * sname;
1764
#endif
1753
#endif
1765
fd_set fds;
1766
struct timeval tv;
1767
1754
1768
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
1755
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
1769
  {
1756
  {
Lines 1807-1815 Link Here
1807
buf[0] = NOTIFY_QUEUE_SIZE_REQ;
1794
buf[0] = NOTIFY_QUEUE_SIZE_REQ;
1808
if (send(fd, buf, 1, 0) < 0) { where = US"send"; goto bad; }
1795
if (send(fd, buf, 1, 0) < 0) { where = US"send"; goto bad; }
1809
1796
1810
FD_ZERO(&fds); FD_SET(fd, &fds);
1797
if (poll_one_fd(fd, POLLIN, 2 * 1000) != 1)
1811
tv.tv_sec = 2; tv.tv_usec = 0;
1812
if (select(fd + 1, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &tv) != 1)
1813
  {
1798
  {
1814
  DEBUG(D_expand) debug_printf("no daemon response; using local evaluation\n");
1799
  DEBUG(D_expand) debug_printf("no daemon response; using local evaluation\n");
1815
  len = snprintf(CS buf, sizeof(buf), "%u", queue_count_cached());
1800
  len = snprintf(CS buf, sizeof(buf), "%u", queue_count_cached());
Lines 1856-1862 Link Here
1856
                something non-NULL if exists_only is TRUE
1841
                something non-NULL if exists_only is TRUE
1857
*/
1842
*/
1858
1843
1859
static uschar *
1844
static const uschar *
1860
find_variable(uschar *name, BOOL exists_only, BOOL skipping, int *newsize)
1845
find_variable(uschar *name, BOOL exists_only, BOOL skipping, int *newsize)
1861
{
1846
{
1862
var_entry * vp;
1847
var_entry * vp;
Lines 1894-1908 Link Here
1894
  {
1879
  {
1895
  uschar *endptr;
1880
  uschar *endptr;
1896
  int n = Ustrtoul(name + 4, &endptr, 10);
1881
  int n = Ustrtoul(name + 4, &endptr, 10);
1897
  if (*endptr == 0 && n != 0 && n <= AUTH_VARS)
1882
  if (!*endptr && n != 0 && n <= AUTH_VARS)
1898
    return !auth_vars[n-1] ? US"" : auth_vars[n-1];
1883
    return auth_vars[n-1] ? auth_vars[n-1] : US"";
1899
  }
1884
  }
1900
else if (Ustrncmp(name, "regex", 5) == 0)
1885
else if (Ustrncmp(name, "regex", 5) == 0)
1901
  {
1886
  {
1902
  uschar *endptr;
1887
  uschar *endptr;
1903
  int n = Ustrtoul(name + 5, &endptr, 10);
1888
  int n = Ustrtoul(name + 5, &endptr, 10);
1904
  if (*endptr == 0 && n != 0 && n <= REGEX_VARS)
1889
  if (!*endptr && n != 0 && n <= REGEX_VARS)
1905
    return !regex_vars[n-1] ? US"" : regex_vars[n-1];
1890
    return regex_vars[n-1] ? regex_vars[n-1] : US"";
1906
  }
1891
  }
1907
1892
1908
/* For all other variables, search the table */
1893
/* For all other variables, search the table */
Lines 1985-1995 Link Here
1985
    ss = (uschar **)(val);
1970
    ss = (uschar **)(val);
1986
    if (!*ss && deliver_datafile >= 0)  /* Read body when needed */
1971
    if (!*ss && deliver_datafile >= 0)  /* Read body when needed */
1987
      {
1972
      {
1988
      uschar *body;
1973
      uschar * body;
1989
      off_t start_offset = SPOOL_DATA_START_OFFSET;
1974
      off_t start_offset = SPOOL_DATA_START_OFFSET;
1990
      int len = message_body_visible;
1975
      int len = message_body_visible;
1976
1991
      if (len > message_size) len = message_size;
1977
      if (len > message_size) len = message_size;
1992
      *ss = body = store_malloc(len+1);
1978
      *ss = body = store_get(len+1, GET_TAINTED);
1993
      body[0] = 0;
1979
      body[0] = 0;
1994
      if (vp->type == vtype_msgbody_end)
1980
      if (vp->type == vtype_msgbody_end)
1995
	{
1981
	{
Lines 2004-2011 Link Here
2004
      if (lseek(deliver_datafile, start_offset, SEEK_SET) < 0)
1990
      if (lseek(deliver_datafile, start_offset, SEEK_SET) < 0)
2005
	log_write(0, LOG_MAIN|LOG_PANIC_DIE, "deliver_datafile lseek: %s",
1991
	log_write(0, LOG_MAIN|LOG_PANIC_DIE, "deliver_datafile lseek: %s",
2006
	  strerror(errno));
1992
	  strerror(errno));
2007
      len = read(deliver_datafile, body, len);
1993
      if ((len = read(deliver_datafile, body, len)) > 0)
2008
      if (len > 0)
2009
	{
1994
	{
2010
	body[len] = 0;
1995
	body[len] = 0;
2011
	if (message_body_newlines)   /* Separate loops for efficiency */
1996
	if (message_body_newlines)   /* Separate loops for efficiency */
Lines 2440-2446 Link Here
2440
2425
2441
2426
2442
2427
2443
#ifdef EXPERIMENTAL_SRS_NATIVE
2428
#ifdef SUPPORT_SRS
2444
/* Do an hmac_md5.  The result is _not_ nul-terminated, and is sized as
2429
/* Do an hmac_md5.  The result is _not_ nul-terminated, and is sized as
2445
the smaller of a full hmac_md5 result (16 bytes) or the supplied output buffer.
2430
the smaller of a full hmac_md5 result (16 bytes) or the supplied output buffer.
2446
2431
Lines 2515-2521 Link Here
2515
  }
2500
  }
2516
return;
2501
return;
2517
}
2502
}
2518
#endif /*EXPERIMENTAL_SRS_NATIVE*/
2503
#endif /*SUPPORT_SRS*/
2519
2504
2520
2505
2521
/*************************************************
2506
/*************************************************
Lines 2545-2560 Link Here
2545
BOOL *subcondptr;
2530
BOOL *subcondptr;
2546
BOOL sub2_honour_dollar = TRUE;
2531
BOOL sub2_honour_dollar = TRUE;
2547
BOOL is_forany, is_json, is_jsons;
2532
BOOL is_forany, is_json, is_jsons;
2548
int rc, cond_type, roffset;
2533
int rc, cond_type;
2549
int_eximarith_t num[2];
2534
int_eximarith_t num[2];
2550
struct stat statbuf;
2535
struct stat statbuf;
2551
uschar * opname;
2536
uschar * opname;
2552
uschar name[256];
2537
uschar name[256];
2553
const uschar *sub[10];
2538
const uschar *sub[10];
2554
2539
2555
const pcre *re;
2556
const uschar *rerror;
2557
2558
for (;;)
2540
for (;;)
2559
  if (Uskip_whitespace(&s) == '!') { testfor = !testfor; s++; } else break;
2541
  if (Uskip_whitespace(&s) == '!') { testfor = !testfor; s++; } else break;
2560
2542
Lines 2565-2571 Link Here
2565
2547
2566
  case ECOND_DEF:
2548
  case ECOND_DEF:
2567
    {
2549
    {
2568
    uschar * t;
2550
    const uschar * t;
2569
2551
2570
    if (*s != ':')
2552
    if (*s != ':')
2571
      {
2553
      {
Lines 2916-3058 Link Here
2916
    {
2898
    {
2917
    case ECOND_NUM_E:
2899
    case ECOND_NUM_E:
2918
    case ECOND_NUM_EE:
2900
    case ECOND_NUM_EE:
2919
    tempcond = (num[0] == num[1]);
2901
      tempcond = (num[0] == num[1]); break;
2920
    break;
2921
2902
2922
    case ECOND_NUM_G:
2903
    case ECOND_NUM_G:
2923
    tempcond = (num[0] > num[1]);
2904
      tempcond = (num[0] > num[1]); break;
2924
    break;
2925
2905
2926
    case ECOND_NUM_GE:
2906
    case ECOND_NUM_GE:
2927
    tempcond = (num[0] >= num[1]);
2907
      tempcond = (num[0] >= num[1]); break;
2928
    break;
2929
2908
2930
    case ECOND_NUM_L:
2909
    case ECOND_NUM_L:
2931
    tempcond = (num[0] < num[1]);
2910
      tempcond = (num[0] < num[1]); break;
2932
    break;
2933
2911
2934
    case ECOND_NUM_LE:
2912
    case ECOND_NUM_LE:
2935
    tempcond = (num[0] <= num[1]);
2913
      tempcond = (num[0] <= num[1]); break;
2936
    break;
2937
2914
2938
    case ECOND_STR_LT:
2915
    case ECOND_STR_LT:
2939
    tempcond = (Ustrcmp(sub[0], sub[1]) < 0);
2916
      tempcond = (Ustrcmp(sub[0], sub[1]) < 0); break;
2940
    break;
2941
2917
2942
    case ECOND_STR_LTI:
2918
    case ECOND_STR_LTI:
2943
    tempcond = (strcmpic(sub[0], sub[1]) < 0);
2919
      tempcond = (strcmpic(sub[0], sub[1]) < 0); break;
2944
    break;
2945
2920
2946
    case ECOND_STR_LE:
2921
    case ECOND_STR_LE:
2947
    tempcond = (Ustrcmp(sub[0], sub[1]) <= 0);
2922
      tempcond = (Ustrcmp(sub[0], sub[1]) <= 0); break;
2948
    break;
2949
2923
2950
    case ECOND_STR_LEI:
2924
    case ECOND_STR_LEI:
2951
    tempcond = (strcmpic(sub[0], sub[1]) <= 0);
2925
      tempcond = (strcmpic(sub[0], sub[1]) <= 0); break;
2952
    break;
2953
2926
2954
    case ECOND_STR_EQ:
2927
    case ECOND_STR_EQ:
2955
    tempcond = (Ustrcmp(sub[0], sub[1]) == 0);
2928
      tempcond = (Ustrcmp(sub[0], sub[1]) == 0); break;
2956
    break;
2957
2929
2958
    case ECOND_STR_EQI:
2930
    case ECOND_STR_EQI:
2959
    tempcond = (strcmpic(sub[0], sub[1]) == 0);
2931
      tempcond = (strcmpic(sub[0], sub[1]) == 0); break;
2960
    break;
2961
2932
2962
    case ECOND_STR_GT:
2933
    case ECOND_STR_GT:
2963
    tempcond = (Ustrcmp(sub[0], sub[1]) > 0);
2934
      tempcond = (Ustrcmp(sub[0], sub[1]) > 0); break;
2964
    break;
2965
2935
2966
    case ECOND_STR_GTI:
2936
    case ECOND_STR_GTI:
2967
    tempcond = (strcmpic(sub[0], sub[1]) > 0);
2937
      tempcond = (strcmpic(sub[0], sub[1]) > 0); break;
2968
    break;
2969
2938
2970
    case ECOND_STR_GE:
2939
    case ECOND_STR_GE:
2971
    tempcond = (Ustrcmp(sub[0], sub[1]) >= 0);
2940
      tempcond = (Ustrcmp(sub[0], sub[1]) >= 0); break;
2972
    break;
2973
2941
2974
    case ECOND_STR_GEI:
2942
    case ECOND_STR_GEI:
2975
    tempcond = (strcmpic(sub[0], sub[1]) >= 0);
2943
      tempcond = (strcmpic(sub[0], sub[1]) >= 0); break;
2976
    break;
2977
2944
2978
    case ECOND_MATCH:   /* Regular expression match */
2945
    case ECOND_MATCH:   /* Regular expression match */
2979
    if (!(re = pcre_compile(CS sub[1], PCRE_COPT, CCSS &rerror,
2980
			    &roffset, NULL)))
2981
      {
2946
      {
2982
      expand_string_message = string_sprintf("regular expression error in "
2947
      const pcre2_code * re;
2983
        "\"%s\": %s at offset %d", sub[1], rerror, roffset);
2948
      PCRE2_SIZE offset;
2984
      return NULL;
2949
      int err;
2950
2951
      if (!(re = pcre2_compile((PCRE2_SPTR)sub[1], PCRE2_ZERO_TERMINATED,
2952
				PCRE_COPT, &err, &offset, pcre_cmp_ctx)))
2953
	{
2954
	uschar errbuf[128];
2955
	pcre2_get_error_message(err, errbuf, sizeof(errbuf));
2956
	expand_string_message = string_sprintf("regular expression error in "
2957
	  "\"%s\": %s at offset %ld", sub[1], errbuf, (long)offset);
2958
	return NULL;
2959
	}
2960
2961
      tempcond = regex_match_and_setup(re, sub[0], 0, -1);
2962
      break;
2985
      }
2963
      }
2986
    tempcond = regex_match_and_setup(re, sub[0], 0, -1);
2987
    break;
2988
2964
2989
    case ECOND_MATCH_ADDRESS:  /* Match in an address list */
2965
    case ECOND_MATCH_ADDRESS:  /* Match in an address list */
2990
    rc = match_address_list(sub[0], TRUE, FALSE, &(sub[1]), NULL, -1, 0, NULL);
2966
      rc = match_address_list(sub[0], TRUE, FALSE, &(sub[1]), NULL, -1, 0,
2991
    goto MATCHED_SOMETHING;
2967
			      CUSS &lookup_value);
2968
      goto MATCHED_SOMETHING;
2992
2969
2993
    case ECOND_MATCH_DOMAIN:   /* Match in a domain list */
2970
    case ECOND_MATCH_DOMAIN:   /* Match in a domain list */
2994
    rc = match_isinlist(sub[0], &(sub[1]), 0, &domainlist_anchor, NULL,
2971
      rc = match_isinlist(sub[0], &(sub[1]), 0, &domainlist_anchor, NULL,
2995
      MCL_DOMAIN + MCL_NOEXPAND, TRUE, NULL);
2972
	MCL_DOMAIN + MCL_NOEXPAND, TRUE, CUSS &lookup_value);
2996
    goto MATCHED_SOMETHING;
2973
      goto MATCHED_SOMETHING;
2997
2974
2998
    case ECOND_MATCH_IP:       /* Match IP address in a host list */
2975
    case ECOND_MATCH_IP:       /* Match IP address in a host list */
2999
    if (sub[0][0] != 0 && string_is_ip_address(sub[0], NULL) == 0)
2976
      if (sub[0][0] != 0 && string_is_ip_address(sub[0], NULL) == 0)
3000
      {
2977
	{
3001
      expand_string_message = string_sprintf("\"%s\" is not an IP address",
2978
	expand_string_message = string_sprintf("\"%s\" is not an IP address",
3002
        sub[0]);
2979
	  sub[0]);
3003
      return NULL;
2980
	return NULL;
3004
      }
2981
	}
3005
    else
2982
      else
3006
      {
2983
	{
3007
      unsigned int *nullcache = NULL;
2984
	unsigned int *nullcache = NULL;
3008
      check_host_block cb;
2985
	check_host_block cb;
3009
2986
3010
      cb.host_name = US"";
2987
	cb.host_name = US"";
3011
      cb.host_address = sub[0];
2988
	cb.host_address = sub[0];
3012
2989
3013
      /* If the host address starts off ::ffff: it is an IPv6 address in
2990
	/* If the host address starts off ::ffff: it is an IPv6 address in
3014
      IPv4-compatible mode. Find the IPv4 part for checking against IPv4
2991
	IPv4-compatible mode. Find the IPv4 part for checking against IPv4
3015
      addresses. */
2992
	addresses. */
3016
2993
3017
      cb.host_ipv4 = (Ustrncmp(cb.host_address, "::ffff:", 7) == 0)?
2994
	cb.host_ipv4 = (Ustrncmp(cb.host_address, "::ffff:", 7) == 0)?
3018
        cb.host_address + 7 : cb.host_address;
2995
	  cb.host_address + 7 : cb.host_address;
3019
2996
3020
      rc = match_check_list(
2997
	rc = match_check_list(
3021
             &sub[1],                   /* the list */
2998
	       &sub[1],                   /* the list */
3022
             0,                         /* separator character */
2999
	       0,                         /* separator character */
3023
             &hostlist_anchor,          /* anchor pointer */
3000
	       &hostlist_anchor,          /* anchor pointer */
3024
             &nullcache,                /* cache pointer */
3001
	       &nullcache,                /* cache pointer */
3025
             check_host,                /* function for testing */
3002
	       check_host,                /* function for testing */
3026
             &cb,                       /* argument for function */
3003
	       &cb,                       /* argument for function */
3027
             MCL_HOST,                  /* type of check */
3004
	       MCL_HOST,                  /* type of check */
3028
             sub[0],                    /* text for debugging */
3005
	       sub[0],                    /* text for debugging */
3029
             NULL);                     /* where to pass back data */
3006
	       CUSS &lookup_value);       /* where to pass back data */
3030
      }
3007
	}
3031
    goto MATCHED_SOMETHING;
3008
      goto MATCHED_SOMETHING;
3032
3009
3033
    case ECOND_MATCH_LOCAL_PART:
3010
    case ECOND_MATCH_LOCAL_PART:
3034
    rc = match_isinlist(sub[0], &(sub[1]), 0, &localpartlist_anchor, NULL,
3011
      rc = match_isinlist(sub[0], &(sub[1]), 0, &localpartlist_anchor, NULL,
3035
      MCL_LOCALPART + MCL_NOEXPAND, TRUE, NULL);
3012
	MCL_LOCALPART + MCL_NOEXPAND, TRUE, CUSS &lookup_value);
3036
    /* Fall through */
3013
      /* Fall through */
3037
    /* VVVVVVVVVVVV */
3014
      /* VVVVVVVVVVVV */
3038
    MATCHED_SOMETHING:
3015
      MATCHED_SOMETHING:
3039
    switch(rc)
3016
      switch(rc)
3040
      {
3017
	{
3041
      case OK:
3018
	case OK:   tempcond = TRUE;  break;
3042
      tempcond = TRUE;
3019
	case FAIL: tempcond = FALSE; break;
3043
      break;
3044
3045
      case FAIL:
3046
      tempcond = FALSE;
3047
      break;
3048
3020
3049
      case DEFER:
3021
	case DEFER:
3050
      expand_string_message = string_sprintf("unable to complete match "
3022
	  expand_string_message = string_sprintf("unable to complete match "
3051
        "against \"%s\": %s", sub[1], search_error_message);
3023
	    "against \"%s\": %s", sub[1], search_error_message);
3052
      return NULL;
3024
	  return NULL;
3053
      }
3025
	}
3054
3026
3055
    break;
3027
      break;
3056
3028
3057
    /* Various "encrypted" comparisons. If the second string starts with
3029
    /* Various "encrypted" comparisons. If the second string starts with
3058
    "{" then an encryption type is given. Default to crypt() or crypt16()
3030
    "{" then an encryption type is given. Default to crypt() or crypt16()
Lines 3061-3198 Link Here
3061
3033
3062
    case ECOND_CRYPTEQ:
3034
    case ECOND_CRYPTEQ:
3063
    #ifndef SUPPORT_CRYPTEQ
3035
    #ifndef SUPPORT_CRYPTEQ
3064
    goto COND_FAILED_NOT_COMPILED;
3036
      goto COND_FAILED_NOT_COMPILED;
3065
    #else
3037
    #else
3066
    if (strncmpic(sub[1], US"{md5}", 5) == 0)
3038
      if (strncmpic(sub[1], US"{md5}", 5) == 0)
3067
      {
3039
	{
3068
      int sublen = Ustrlen(sub[1]+5);
3040
	int sublen = Ustrlen(sub[1]+5);
3069
      md5 base;
3041
	md5 base;
3070
      uschar digest[16];
3042
	uschar digest[16];
3071
3043
3072
      md5_start(&base);
3044
	md5_start(&base);
3073
      md5_end(&base, sub[0], Ustrlen(sub[0]), digest);
3045
	md5_end(&base, sub[0], Ustrlen(sub[0]), digest);
3074
3046
3075
      /* If the length that we are comparing against is 24, the MD5 digest
3047
	/* If the length that we are comparing against is 24, the MD5 digest
3076
      is expressed as a base64 string. This is the way LDAP does it. However,
3048
	is expressed as a base64 string. This is the way LDAP does it. However,
3077
      some other software uses a straightforward hex representation. We assume
3049
	some other software uses a straightforward hex representation. We assume
3078
      this if the length is 32. Other lengths fail. */
3050
	this if the length is 32. Other lengths fail. */
3079
3051
3080
      if (sublen == 24)
3052
	if (sublen == 24)
3081
        {
3053
	  {
3082
        uschar *coded = b64encode(CUS digest, 16);
3054
	  uschar *coded = b64encode(CUS digest, 16);
3083
        DEBUG(D_auth) debug_printf("crypteq: using MD5+B64 hashing\n"
3055
	  DEBUG(D_auth) debug_printf("crypteq: using MD5+B64 hashing\n"
3084
          "  subject=%s\n  crypted=%s\n", coded, sub[1]+5);
3056
	    "  subject=%s\n  crypted=%s\n", coded, sub[1]+5);
3085
        tempcond = (Ustrcmp(coded, sub[1]+5) == 0);
3057
	  tempcond = (Ustrcmp(coded, sub[1]+5) == 0);
3086
        }
3058
	  }
3087
      else if (sublen == 32)
3059
	else if (sublen == 32)
3088
        {
3060
	  {
3089
        uschar coded[36];
3061
	  uschar coded[36];
3090
        for (int i = 0; i < 16; i++) sprintf(CS (coded+2*i), "%02X", digest[i]);
3062
	  for (int i = 0; i < 16; i++) sprintf(CS (coded+2*i), "%02X", digest[i]);
3091
        coded[32] = 0;
3063
	  coded[32] = 0;
3092
        DEBUG(D_auth) debug_printf("crypteq: using MD5+hex hashing\n"
3064
	  DEBUG(D_auth) debug_printf("crypteq: using MD5+hex hashing\n"
3093
          "  subject=%s\n  crypted=%s\n", coded, sub[1]+5);
3065
	    "  subject=%s\n  crypted=%s\n", coded, sub[1]+5);
3094
        tempcond = (strcmpic(coded, sub[1]+5) == 0);
3066
	  tempcond = (strcmpic(coded, sub[1]+5) == 0);
3095
        }
3067
	  }
3096
      else
3068
	else
3097
        {
3069
	  {
3098
        DEBUG(D_auth) debug_printf("crypteq: length for MD5 not 24 or 32: "
3070
	  DEBUG(D_auth) debug_printf("crypteq: length for MD5 not 24 or 32: "
3099
          "fail\n  crypted=%s\n", sub[1]+5);
3071
	    "fail\n  crypted=%s\n", sub[1]+5);
3100
        tempcond = FALSE;
3072
	  tempcond = FALSE;
3101
        }
3073
	  }
3102
      }
3074
	}
3103
3104
    else if (strncmpic(sub[1], US"{sha1}", 6) == 0)
3105
      {
3106
      int sublen = Ustrlen(sub[1]+6);
3107
      hctx h;
3108
      uschar digest[20];
3109
3075
3110
      sha1_start(&h);
3076
      else if (strncmpic(sub[1], US"{sha1}", 6) == 0)
3111
      sha1_end(&h, sub[0], Ustrlen(sub[0]), digest);
3077
	{
3078
	int sublen = Ustrlen(sub[1]+6);
3079
	hctx h;
3080
	uschar digest[20];
3112
3081
3113
      /* If the length that we are comparing against is 28, assume the SHA1
3082
	sha1_start(&h);
3114
      digest is expressed as a base64 string. If the length is 40, assume a
3083
	sha1_end(&h, sub[0], Ustrlen(sub[0]), digest);
3115
      straightforward hex representation. Other lengths fail. */
3116
3084
3117
      if (sublen == 28)
3085
	/* If the length that we are comparing against is 28, assume the SHA1
3118
        {
3086
	digest is expressed as a base64 string. If the length is 40, assume a
3119
        uschar *coded = b64encode(CUS digest, 20);
3087
	straightforward hex representation. Other lengths fail. */
3120
        DEBUG(D_auth) debug_printf("crypteq: using SHA1+B64 hashing\n"
3088
3121
          "  subject=%s\n  crypted=%s\n", coded, sub[1]+6);
3089
	if (sublen == 28)
3122
        tempcond = (Ustrcmp(coded, sub[1]+6) == 0);
3090
	  {
3123
        }
3091
	  uschar *coded = b64encode(CUS digest, 20);
3124
      else if (sublen == 40)
3092
	  DEBUG(D_auth) debug_printf("crypteq: using SHA1+B64 hashing\n"
3125
        {
3093
	    "  subject=%s\n  crypted=%s\n", coded, sub[1]+6);
3126
        uschar coded[44];
3094
	  tempcond = (Ustrcmp(coded, sub[1]+6) == 0);
3127
        for (int i = 0; i < 20; i++) sprintf(CS (coded+2*i), "%02X", digest[i]);
3095
	  }
3128
        coded[40] = 0;
3096
	else if (sublen == 40)
3129
        DEBUG(D_auth) debug_printf("crypteq: using SHA1+hex hashing\n"
3097
	  {
3130
          "  subject=%s\n  crypted=%s\n", coded, sub[1]+6);
3098
	  uschar coded[44];
3131
        tempcond = (strcmpic(coded, sub[1]+6) == 0);
3099
	  for (int i = 0; i < 20; i++) sprintf(CS (coded+2*i), "%02X", digest[i]);
3132
        }
3100
	  coded[40] = 0;
3133
      else
3101
	  DEBUG(D_auth) debug_printf("crypteq: using SHA1+hex hashing\n"
3134
        {
3102
	    "  subject=%s\n  crypted=%s\n", coded, sub[1]+6);
3135
        DEBUG(D_auth) debug_printf("crypteq: length for SHA-1 not 28 or 40: "
3103
	  tempcond = (strcmpic(coded, sub[1]+6) == 0);
3136
          "fail\n  crypted=%s\n", sub[1]+6);
3104
	  }
3137
	tempcond = FALSE;
3105
	else
3138
        }
3106
	  {
3139
      }
3107
	  DEBUG(D_auth) debug_printf("crypteq: length for SHA-1 not 28 or 40: "
3108
	    "fail\n  crypted=%s\n", sub[1]+6);
3109
	  tempcond = FALSE;
3110
	  }
3111
	}
3140
3112
3141
    else   /* {crypt} or {crypt16} and non-{ at start */
3113
      else   /* {crypt} or {crypt16} and non-{ at start */
3142
           /* }-for-text-editors */
3114
	     /* }-for-text-editors */
3143
      {
3115
	{
3144
      int which = 0;
3116
	int which = 0;
3145
      uschar *coded;
3117
	uschar *coded;
3146
3118
3147
      if (strncmpic(sub[1], US"{crypt}", 7) == 0)
3119
	if (strncmpic(sub[1], US"{crypt}", 7) == 0)
3148
        {
3120
	  {
3149
        sub[1] += 7;
3121
	  sub[1] += 7;
3150
        which = 1;
3122
	  which = 1;
3151
        }
3123
	  }
3152
      else if (strncmpic(sub[1], US"{crypt16}", 9) == 0)
3124
	else if (strncmpic(sub[1], US"{crypt16}", 9) == 0)
3153
        {
3125
	  {
3154
        sub[1] += 9;
3126
	  sub[1] += 9;
3155
        which = 2;
3127
	  which = 2;
3156
        }
3128
	  }
3157
      else if (sub[1][0] == '{')		/* }-for-text-editors */
3129
	else if (sub[1][0] == '{')		/* }-for-text-editors */
3158
        {
3130
	  {
3159
        expand_string_message = string_sprintf("unknown encryption mechanism "
3131
	  expand_string_message = string_sprintf("unknown encryption mechanism "
3160
          "in \"%s\"", sub[1]);
3132
	    "in \"%s\"", sub[1]);
3161
        return NULL;
3133
	  return NULL;
3162
        }
3134
	  }
3163
3135
3164
      switch(which)
3136
	switch(which)
3165
        {
3137
	  {
3166
        case 0:  coded = US DEFAULT_CRYPT(CS sub[0], CS sub[1]); break;
3138
	  case 0:  coded = US DEFAULT_CRYPT(CS sub[0], CS sub[1]); break;
3167
        case 1:  coded = US crypt(CS sub[0], CS sub[1]); break;
3139
	  case 1:  coded = US crypt(CS sub[0], CS sub[1]); break;
3168
        default: coded = US crypt16(CS sub[0], CS sub[1]); break;
3140
	  default: coded = US crypt16(CS sub[0], CS sub[1]); break;
3169
        }
3141
	  }
3170
3142
3171
      #define STR(s) # s
3143
	#define STR(s) # s
3172
      #define XSTR(s) STR(s)
3144
	#define XSTR(s) STR(s)
3173
      DEBUG(D_auth) debug_printf("crypteq: using %s()\n"
3145
	DEBUG(D_auth) debug_printf("crypteq: using %s()\n"
3174
        "  subject=%s\n  crypted=%s\n",
3146
	  "  subject=%s\n  crypted=%s\n",
3175
        which == 0 ? XSTR(DEFAULT_CRYPT) : which == 1 ? "crypt" : "crypt16",
3147
	  which == 0 ? XSTR(DEFAULT_CRYPT) : which == 1 ? "crypt" : "crypt16",
3176
        coded, sub[1]);
3148
	  coded, sub[1]);
3177
      #undef STR
3149
	#undef STR
3178
      #undef XSTR
3150
	#undef XSTR
3179
3151
3180
      /* If the encrypted string contains fewer than two characters (for the
3152
	/* If the encrypted string contains fewer than two characters (for the
3181
      salt), force failure. Otherwise we get false positives: with an empty
3153
	salt), force failure. Otherwise we get false positives: with an empty
3182
      string the yield of crypt() is an empty string! */
3154
	string the yield of crypt() is an empty string! */
3183
3155
3184
      if (coded)
3156
	if (coded)
3185
	tempcond = Ustrlen(sub[1]) < 2 ? FALSE : Ustrcmp(coded, sub[1]) == 0;
3157
	  tempcond = Ustrlen(sub[1]) < 2 ? FALSE : Ustrcmp(coded, sub[1]) == 0;
3186
      else if (errno == EINVAL)
3158
	else if (errno == EINVAL)
3187
	tempcond = FALSE;
3159
	  tempcond = FALSE;
3188
      else
3160
	else
3189
	{
3161
	  {
3190
	expand_string_message = string_sprintf("crypt error: %s\n",
3162
	  expand_string_message = string_sprintf("crypt error: %s\n",
3191
	  US strerror(errno));
3163
	    US strerror(errno));
3192
	return NULL;
3164
	  return NULL;
3165
	  }
3193
	}
3166
	}
3194
      }
3167
      break;
3195
    break;
3196
    #endif  /* SUPPORT_CRYPTEQ */
3168
    #endif  /* SUPPORT_CRYPTEQ */
3197
3169
3198
    case ECOND_INLIST:
3170
    case ECOND_INLIST:
Lines 3215-3220 Link Here
3215
        if (compare(sub[0], iterate_item) == 0)
3187
        if (compare(sub[0], iterate_item) == 0)
3216
          {
3188
          {
3217
          tempcond = TRUE;
3189
          tempcond = TRUE;
3190
	  lookup_value = iterate_item;
3218
          break;
3191
          break;
3219
          }
3192
          }
3220
	}
3193
	}
Lines 3445-3458 Link Here
3445
    return s;
3418
    return s;
3446
    }
3419
    }
3447
3420
3448
#ifdef EXPERIMENTAL_SRS_NATIVE
3421
#ifdef SUPPORT_SRS
3449
  case ECOND_INBOUND_SRS:
3422
  case ECOND_INBOUND_SRS:
3450
    /* ${if inbound_srs {local_part}{secret}  {yes}{no}} */
3423
    /* ${if inbound_srs {local_part}{secret}  {yes}{no}} */
3451
    {
3424
    {
3452
    uschar * sub[2];
3425
    uschar * sub[2];
3453
    const pcre * re;
3426
    const pcre2_code * re;
3454
    int ovec[3*(4+1)];
3427
    pcre2_match_data * md;
3455
    int n;
3428
    PCRE2_SIZE * ovec;
3429
    int quoting = 0;
3456
    uschar cksum[4];
3430
    uschar cksum[4];
3457
    BOOL boolvalue = FALSE;
3431
    BOOL boolvalue = FALSE;
3458
3432
Lines 3468-3485 Link Here
3468
3442
3469
    re = regex_must_compile(US"^(?i)SRS0=([^=]+)=([A-Z2-7]+)=([^=]*)=(.*)$",
3443
    re = regex_must_compile(US"^(?i)SRS0=([^=]+)=([A-Z2-7]+)=([^=]*)=(.*)$",
3470
			    TRUE, FALSE);
3444
			    TRUE, FALSE);
3471
    if (pcre_exec(re, NULL, CS sub[0], Ustrlen(sub[0]), 0, PCRE_EOPT,
3445
    md = pcre2_match_data_create(4+1, pcre_gen_ctx);
3472
		  ovec, nelem(ovec)) < 0)
3446
    if (pcre2_match(re, sub[0], PCRE2_ZERO_TERMINATED, 0, PCRE_EOPT,
3447
		    md, pcre_mtc_ctx) < 0)
3473
      {
3448
      {
3474
      DEBUG(D_expand) debug_printf("no match for SRS'd local-part pattern\n");
3449
      DEBUG(D_expand) debug_printf("no match for SRS'd local-part pattern\n");
3475
      goto srs_result;
3450
      goto srs_result;
3476
      }
3451
      }
3452
    ovec = pcre2_get_ovector_pointer(md);
3477
3453
3478
    /* Side-effect: record the decoded recipient */
3454
    if (sub[0][0] == '"')
3479
3455
      quoting = 1;
3480
    srs_recipient = string_sprintf("%.*S@%.*S",   		/* lowercased */
3456
    else for (uschar * s = sub[0]; *s; s++)
3481
		      ovec[9]-ovec[8], sub[0] + ovec[8],	/* substring 4 */
3457
      if (!isalnum(*s) && Ustrchr(".!#$%&'*+-/=?^_`{|}~", *s) == NULL)
3482
		      ovec[7]-ovec[6], sub[0] + ovec[6]);	/* substring 3 */
3458
	{ quoting = 1; break; }
3459
    if (quoting)
3460
      DEBUG(D_expand) debug_printf_indent("auto-quoting local part\n");
3461
3462
    /* Record the (quoted, if needed) decoded recipient as $srs_recipient */
3463
3464
    srs_recipient = string_sprintf("%.*s%.*S%.*s@%.*S",   	/* lowercased */
3465
		      quoting, "\"",
3466
		      (int) (ovec[9]-ovec[8]), sub[0] + ovec[8],  /* substr 4 */
3467
		      quoting, "\"",
3468
		      (int) (ovec[7]-ovec[6]), sub[0] + ovec[6]); /* substr 3 */
3483
3469
3484
    /* If a zero-length secret was given, we're done.  Otherwise carry on
3470
    /* If a zero-length secret was given, we're done.  Otherwise carry on
3485
    and validate the given SRS local_part againt our secret. */
3471
    and validate the given SRS local_part againt our secret. */
Lines 3495-3500 Link Here
3495
      struct timeval now;
3481
      struct timeval now;
3496
      uschar * ss = sub[0] + ovec[4];	/* substring 2, the timestamp */
3482
      uschar * ss = sub[0] + ovec[4];	/* substring 2, the timestamp */
3497
      long d;
3483
      long d;
3484
      int n;
3498
3485
3499
      gettimeofday(&now, NULL);
3486
      gettimeofday(&now, NULL);
3500
      now.tv_sec /= 86400;		/* days since epoch */
3487
      now.tv_sec /= 86400;		/* days since epoch */
Lines 3537-3543 Link Here
3537
    if (yield) *yield = (boolvalue == testfor);
3524
    if (yield) *yield = (boolvalue == testfor);
3538
    return s;
3525
    return s;
3539
    }
3526
    }
3540
#endif /*EXPERIMENTAL_SRS_NATIVE*/
3527
#endif /*SUPPORT_SRS*/
3541
3528
3542
  /* Unknown condition */
3529
  /* Unknown condition */
3543
3530
Lines 3588-3594 Link Here
3588
*/
3575
*/
3589
3576
3590
static int
3577
static int
3591
save_expand_strings(uschar **save_expand_nstring, int *save_expand_nlength)
3578
save_expand_strings(const uschar **save_expand_nstring, int *save_expand_nlength)
3592
{
3579
{
3593
for (int i = 0; i <= expand_nmax; i++)
3580
for (int i = 0; i <= expand_nmax; i++)
3594
  {
3581
  {
Lines 3615-3621 Link Here
3615
*/
3602
*/
3616
3603
3617
static void
3604
static void
3618
restore_expand_strings(int save_expand_nmax, uschar **save_expand_nstring,
3605
restore_expand_strings(int save_expand_nmax, const uschar **save_expand_nstring,
3619
  int *save_expand_nlength)
3606
  int *save_expand_nlength)
3620
{
3607
{
3621
expand_nmax = save_expand_nmax;
3608
expand_nmax = save_expand_nmax;
Lines 3829-3836 Link Here
3829
static uschar *
3816
static uschar *
3830
prvs_daystamp(int day_offset)
3817
prvs_daystamp(int day_offset)
3831
{
3818
{
3832
uschar *days = store_get(32, FALSE);         /* Need at least 24 for cases */
3819
uschar * days = store_get(32, GET_UNTAINTED);      /* Need at least 24 for cases */
3833
(void)string_format(days, 32, TIME_T_FMT,    /* where TIME_T_FMT is %lld */
3820
(void)string_format(days, 32, TIME_T_FMT, 	   /* where TIME_T_FMT is %lld */
3834
  (time(NULL) + day_offset*86400)/86400);
3821
  (time(NULL) + day_offset*86400)/86400);
3835
return (Ustrlen(days) >= 3) ? &days[Ustrlen(days)-3] : US"100";
3822
return (Ustrlen(days) >= 3) ? &days[Ustrlen(days)-3] : US"100";
3836
}
3823
}
Lines 3901-3907 Link Here
3901
3888
3902
/* Hashing is deemed sufficient to de-taint any input data */
3889
/* Hashing is deemed sufficient to de-taint any input data */
3903
3890
3904
p = finalhash_hex = store_get(40, FALSE);
3891
p = finalhash_hex = store_get(40, GET_UNTAINTED);
3905
for (int i = 0; i < 3; i++)
3892
for (int i = 0; i < 3; i++)
3906
  {
3893
  {
3907
  *p++ = hex_digits[(finalhash[i] & 0xf0) >> 4];
3894
  *p++ = hex_digits[(finalhash[i] & 0xf0) >> 4];
Lines 3932-3938 Link Here
3932
*/
3919
*/
3933
3920
3934
gstring *
3921
gstring *
3935
cat_file(FILE *f, gstring *yield, uschar *eol)
3922
cat_file(FILE * f, gstring * yield, uschar * eol)
3936
{
3923
{
3937
uschar buffer[1024];
3924
uschar buffer[1024];
3938
3925
Lines 3944-3951 Link Here
3944
  if (eol && buffer[len])
3931
  if (eol && buffer[len])
3945
    yield = string_cat(yield, eol);
3932
    yield = string_cat(yield, eol);
3946
  }
3933
  }
3947
3948
(void) string_from_gstring(yield);
3949
return yield;
3934
return yield;
3950
}
3935
}
3951
3936
Lines 3967-3973 Link Here
3967
/* We assume that all errors, and any returns of zero bytes,
3952
/* We assume that all errors, and any returns of zero bytes,
3968
are actually EOF. */
3953
are actually EOF. */
3969
3954
3970
(void) string_from_gstring(yield);
3971
return yield;
3955
return yield;
3972
}
3956
}
3973
#endif
3957
#endif
Lines 4293-4298 Link Here
4293
}
4277
}
4294
4278
4295
4279
4280
/* Expand a named list.  Return false on failure. */
4281
static gstring *
4282
expand_listnamed(gstring * yield, const uschar * name, const uschar * listtype)
4283
{
4284
tree_node *t = NULL;
4285
const uschar * list;
4286
int sep = 0;
4287
uschar * item;
4288
BOOL needsep = FALSE;
4289
#define LISTNAMED_BUF_SIZE 256
4290
uschar b[LISTNAMED_BUF_SIZE];
4291
uschar * buffer = b;
4292
4293
if (*name == '+') name++;
4294
if (!listtype)		/* no-argument version */
4295
  {
4296
  if (  !(t = tree_search(addresslist_anchor, name))
4297
     && !(t = tree_search(domainlist_anchor,  name))
4298
     && !(t = tree_search(hostlist_anchor,    name)))
4299
    t = tree_search(localpartlist_anchor, name);
4300
  }
4301
else switch(*listtype)	/* specific list-type version */
4302
  {
4303
  case 'a': t = tree_search(addresslist_anchor,   name); break;
4304
  case 'd': t = tree_search(domainlist_anchor,    name); break;
4305
  case 'h': t = tree_search(hostlist_anchor,      name); break;
4306
  case 'l': t = tree_search(localpartlist_anchor, name); break;
4307
  default:
4308
    expand_string_message = US"bad suffix on \"list\" operator";
4309
    return yield;
4310
  }
4311
4312
if(!t)
4313
  {
4314
  expand_string_message = string_sprintf("\"%s\" is not a %snamed list",
4315
    name, !listtype?""
4316
      : *listtype=='a'?"address "
4317
      : *listtype=='d'?"domain "
4318
      : *listtype=='h'?"host "
4319
      : *listtype=='l'?"localpart "
4320
      : 0);
4321
  return yield;
4322
  }
4323
4324
list = ((namedlist_block *)(t->data.ptr))->string;
4325
4326
/* The list could be quite long so we (re)use a buffer for each element
4327
rather than getting each in new memory */
4328
4329
if (is_tainted(list)) buffer = store_get(LISTNAMED_BUF_SIZE, GET_TAINTED);
4330
while ((item = string_nextinlist(&list, &sep, buffer, LISTNAMED_BUF_SIZE)))
4331
  {
4332
  uschar * buf = US" : ";
4333
  if (needsep)
4334
    yield = string_catn(yield, buf, 3);
4335
  else
4336
    needsep = TRUE;
4337
4338
  if (*item == '+')	/* list item is itself a named list */
4339
    {
4340
    yield = expand_listnamed(yield, item, listtype);
4341
    if (expand_string_message)
4342
      return yield;
4343
    }
4344
4345
  else if (sep != ':')	/* item from non-colon-sep list, re-quote for colon list-separator */
4346
    {
4347
    char tok[3];
4348
    tok[0] = sep; tok[1] = ':'; tok[2] = 0;
4349
4350
    for(char * cp; cp = strpbrk(CCS item, tok); item = US cp)
4351
      {
4352
      yield = string_catn(yield, item, cp - CS item);
4353
      if (*cp++ == ':')	/* colon in a non-colon-sep list item, needs doubling */
4354
	yield = string_catn(yield, US"::", 2);
4355
      else		/* sep in item; should already be doubled; emit once */
4356
	{
4357
	yield = string_catn(yield, US tok, 1);
4358
	if (*cp == sep) cp++;
4359
	}
4360
      }
4361
    yield = string_cat(yield, item);
4362
    }
4363
  else
4364
    yield = string_cat(yield, item);
4365
  }
4366
return yield;
4367
}
4368
4369
4370
4371
/************************************************/
4372
static void
4373
debug_expansion_interim(const uschar * what, const uschar * value, int nchar,
4374
  BOOL skipping)
4375
{
4376
DEBUG(D_noutf8)
4377
  debug_printf_indent("|");
4378
else
4379
  debug_printf_indent(UTF8_VERT_RIGHT);
4380
4381
for (int fill = 11 - Ustrlen(what); fill > 0; fill--)
4382
  DEBUG(D_noutf8)
4383
    debug_printf("-");
4384
  else
4385
    debug_printf(UTF8_HORIZ);
4386
4387
debug_printf("%s: %.*s\n", what, nchar, value);
4388
if (is_tainted(value))
4389
  {
4390
  DEBUG(D_noutf8)
4391
    debug_printf_indent("%s     \\__", skipping ? "|     " : "      ");
4392
  else
4393
    debug_printf_indent("%s",
4394
      skipping
4395
      ? UTF8_VERT "             " : "           " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ);
4396
  debug_printf("(tainted)\n");
4397
  }
4398
}
4399
4400
4296
/*************************************************
4401
/*************************************************
4297
*                 Expand string                  *
4402
*                 Expand string                  *
4298
*************************************************/
4403
*************************************************/
Lines 4363-4385 Link Here
4363
rmark reset_point = store_mark();
4468
rmark reset_point = store_mark();
4364
gstring * yield = string_get(Ustrlen(string) + 64);
4469
gstring * yield = string_get(Ustrlen(string) + 64);
4365
int item_type;
4470
int item_type;
4366
const uschar *s = string;
4471
const uschar * s = string;
4367
uschar *save_expand_nstring[EXPAND_MAXN+1];
4472
const uschar * save_expand_nstring[EXPAND_MAXN+1];
4368
int save_expand_nlength[EXPAND_MAXN+1];
4473
int save_expand_nlength[EXPAND_MAXN+1];
4369
BOOL resetok = TRUE;
4474
BOOL resetok = TRUE, first = TRUE;
4370
4475
4371
expand_level++;
4476
expand_level++;
4372
DEBUG(D_expand)
4373
  DEBUG(D_noutf8)
4374
    debug_printf_indent("/%s: %s\n",
4375
      skipping ? "---scanning" : "considering", string);
4376
  else
4377
    debug_printf_indent(UTF8_DOWN_RIGHT "%s: %s\n",
4378
      skipping
4379
      ? UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ "scanning"
4380
      : "considering",
4381
      string);
4382
4383
f.expand_string_forcedfail = FALSE;
4477
f.expand_string_forcedfail = FALSE;
4384
expand_string_message = US"";
4478
expand_string_message = US"";
4385
4479
Lines 4391-4401 Link Here
4391
  goto EXPAND_FAILED;
4485
  goto EXPAND_FAILED;
4392
  }
4486
  }
4393
4487
4394
while (*s != 0)
4488
while (*s)
4395
  {
4489
  {
4396
  uschar *value;
4397
  uschar name[256];
4490
  uschar name[256];
4398
4491
4492
  DEBUG(D_expand)
4493
    {
4494
    DEBUG(D_noutf8)
4495
      debug_printf_indent("%c%s: %s\n",
4496
	first ? '/' : '|',
4497
	skipping ? "---scanning" : "considering", s);
4498
    else
4499
      debug_printf_indent("%s%s: %s\n",
4500
	first ? UTF8_DOWN_RIGHT : UTF8_VERT_RIGHT,
4501
	skipping
4502
	? UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ "scanning"
4503
	: "considering",
4504
	s);
4505
    first = FALSE;
4506
    }
4507
4399
  /* \ escapes the next character, which must exist, or else
4508
  /* \ escapes the next character, which must exist, or else
4400
  the expansion fails. There's a special escape, \N, which causes
4509
  the expansion fails. There's a special escape, \N, which causes
4401
  copying of the subject verbatim up to the next \N. Otherwise,
4510
  copying of the subject verbatim up to the next \N. Otherwise,
Lines 4412-4443 Link Here
4412
    if (s[1] == 'N')
4521
    if (s[1] == 'N')
4413
      {
4522
      {
4414
      const uschar * t = s + 2;
4523
      const uschar * t = s + 2;
4415
      for (s = t; *s != 0; s++) if (*s == '\\' && s[1] == 'N') break;
4524
      for (s = t; *s ; s++) if (*s == '\\' && s[1] == 'N') break;
4525
4526
      DEBUG(D_expand)
4527
	debug_expansion_interim(US"protected", t, (int)(s - t), skipping);
4416
      yield = string_catn(yield, t, s - t);
4528
      yield = string_catn(yield, t, s - t);
4417
      if (*s != 0) s += 2;
4529
      if (*s) s += 2;
4418
      }
4530
      }
4419
4420
    else
4531
    else
4421
      {
4532
      {
4422
      uschar ch[1];
4533
      uschar ch[1];
4534
      DEBUG(D_expand)
4535
	DEBUG(D_noutf8)
4536
	  debug_printf_indent("|backslashed: '\\%c'\n", s[1]);
4537
	else
4538
	  debug_printf_indent(UTF8_VERT_RIGHT "backslashed: '\\%c'\n", s[1]);
4423
      ch[0] = string_interpret_escape(&s);
4539
      ch[0] = string_interpret_escape(&s);
4424
      s++;
4540
      s++;
4425
      yield = string_catn(yield, ch, 1);
4541
      yield = string_catn(yield, ch, 1);
4426
      }
4542
      }
4427
4428
    continue;
4543
    continue;
4429
    }
4544
    }
4430
4545
4431
  /*{*/
4546
									/*{{*/
4432
  /* Anything other than $ is just copied verbatim, unless we are
4547
  /* Anything other than $ is just copied verbatim, unless we are
4433
  looking for a terminating } character. */
4548
  looking for a terminating } character. */
4434
4549
4435
  /*{*/
4436
  if (ket_ends && *s == '}') break;
4550
  if (ket_ends && *s == '}') break;
4437
4551
4438
  if (*s != '$' || !honour_dollar)
4552
  if (*s != '$' || !honour_dollar)
4439
    {
4553
    {
4440
    yield = string_catn(yield, s++, 1);
4554
    int i = 1;								/*{*/
4555
    for (const uschar * t = s+1;
4556
	*t && *t != '$' && *t != '}' && *t != '\\'; t++) i++;
4557
4558
    DEBUG(D_expand) debug_expansion_interim(US"text", s, i, skipping);
4559
4560
    yield = string_catn(yield, s, i);
4561
    s += i;
4441
    continue;
4562
    continue;
4442
    }
4563
    }
4443
4564
Lines 4449-4458 Link Here
4449
  "$header_". A non-existent header yields a NULL value; nothing is
4570
  "$header_". A non-existent header yields a NULL value; nothing is
4450
  inserted. */	/*}*/
4571
  inserted. */	/*}*/
4451
4572
4452
  if (isalpha((*(++s))))
4573
  if (isalpha(*++s))
4453
    {
4574
    {
4454
    int len;
4575
    const uschar * value;
4455
    int newsize = 0;
4576
    int newsize = 0, len;
4456
    gstring * g = NULL;
4577
    gstring * g = NULL;
4457
    uschar * t;
4578
    uschar * t;
4458
4579
Lines 4462-4474 Link Here
4462
    buffer. */
4583
    buffer. */
4463
4584
4464
    if (!yield)
4585
    if (!yield)
4465
      g = store_get(sizeof(gstring), FALSE);
4586
      g = store_get(sizeof(gstring), GET_UNTAINTED);
4466
    else if (yield->ptr == 0)
4587
    else if (yield->ptr == 0)
4467
      {
4588
      {
4468
      if (resetok) reset_point = store_reset(reset_point);
4589
      if (resetok) reset_point = store_reset(reset_point);
4469
      yield = NULL;
4590
      yield = NULL;
4470
      reset_point = store_mark();
4591
      reset_point = store_mark();
4471
      g = store_get(sizeof(gstring), FALSE);	/* alloc _before_ calling find_variable() */
4592
      g = store_get(sizeof(gstring), GET_UNTAINTED);	/* alloc _before_ calling find_variable() */
4472
      }
4593
      }
4473
4594
4474
    /* Header */
4595
    /* Header */
Lines 4482-4488 Link Here
4482
      unsigned flags = *name == 'r' ? FH_WANT_RAW
4603
      unsigned flags = *name == 'r' ? FH_WANT_RAW
4483
		      : *name == 'l' ? FH_WANT_RAW|FH_WANT_LIST
4604
		      : *name == 'l' ? FH_WANT_RAW|FH_WANT_LIST
4484
		      : 0;
4605
		      : 0;
4485
      uschar * charset = *name == 'b' ? NULL : headers_charset;
4606
      const uschar * charset = *name == 'b' ? NULL : headers_charset;
4486
4607
4487
      s = read_header_name(name, sizeof(name), s);
4608
      s = read_header_name(name, sizeof(name), s);
4488
      value = find_header(name, &newsize, flags, charset);
4609
      value = find_header(name, &newsize, flags, charset);
Lines 4493-4499 Link Here
4493
      But there is no error here - nothing gets inserted. */
4614
      But there is no error here - nothing gets inserted. */
4494
4615
4495
      if (!value)
4616
      if (!value)
4496
        {
4617
        {								/*{*/
4497
        if (Ustrchr(name, '}')) malformed_header = TRUE;
4618
        if (Ustrchr(name, '}')) malformed_header = TRUE;
4498
        continue;
4619
        continue;
4499
        }
4620
        }
Lines 4523-4529 Link Here
4523
      yield = g;
4644
      yield = g;
4524
      yield->size = newsize;
4645
      yield->size = newsize;
4525
      yield->ptr = len;
4646
      yield->ptr = len;
4526
      yield->s = value;
4647
      yield->s = US value; /* known to be in new store i.e. a copy, so deconst safe */
4527
      }
4648
      }
4528
    else
4649
    else
4529
      yield = string_catn(yield, value, len);
4650
      yield = string_catn(yield, value, len);
Lines 4549-4562 Link Here
4549
    }
4670
    }
4550
4671
4551
  /* After { there can be various things, but they all start with
4672
  /* After { there can be various things, but they all start with
4552
  an initial word, except for a number for a string match variable. */
4673
  an initial word, except for a number for a string match variable. */	/*}*/
4553
4674
4554
  if (isdigit((*(++s))))
4675
  if (isdigit(*++s))
4555
    {
4676
    {
4556
    int n;
4677
    int n;
4557
    s = read_cnumber(&n, s);		/*{*/
4678
    s = read_cnumber(&n, s);						/*{{*/
4558
    if (*s++ != '}')
4679
    if (*s++ != '}')
4559
      {					/*{*/
4680
      {
4560
      expand_string_message = US"} expected after number";
4681
      expand_string_message = US"} expected after number";
4561
      goto EXPAND_FAILED;
4682
      goto EXPAND_FAILED;
4562
      }
4683
      }
Lines 4573-4583 Link Here
4573
4694
4574
  /* Allow "-" in names to cater for substrings with negative
4695
  /* Allow "-" in names to cater for substrings with negative
4575
  arguments. Since we are checking for known names after { this is
4696
  arguments. Since we are checking for known names after { this is
4576
  OK. */
4697
  OK. */								/*}*/
4577
4698
4578
  s = read_name(name, sizeof(name), s, US"_-");
4699
  s = read_name(name, sizeof(name), s, US"_-");
4579
  item_type = chop_match(name, item_table, nelem(item_table));
4700
  item_type = chop_match(name, item_table, nelem(item_table));
4580
4701
4702
  /* Switch on item type.  All nondefault choices should "continue* when
4703
  skipping, but "break" otherwise so we get debug output for the item
4704
  expansion. */
4705
  {
4706
  int start = gstring_length(yield);
4581
  switch(item_type)
4707
  switch(item_type)
4582
    {
4708
    {
4583
    /* Call an ACL from an expansion.  We feed data in via $acl_arg1 - $acl_arg9.
4709
    /* Call an ACL from an expansion.  We feed data in via $acl_arg1 - $acl_arg9.
Lines 4592-4599 Link Here
4592
    case EITEM_ACL:
4718
    case EITEM_ACL:
4593
      /* ${acl {name} {arg1}{arg2}...} */
4719
      /* ${acl {name} {arg1}{arg2}...} */
4594
      {
4720
      {
4595
      uschar *sub[10];	/* name + arg1-arg9 (which must match number of acl_arg[]) */
4721
      uschar * sub[10];	/* name + arg1-arg9 (which must match number of acl_arg[]) */
4596
      uschar *user_msg;
4722
      uschar * user_msg;
4597
      int rc;
4723
      int rc;
4598
4724
4599
      switch(read_subs(sub, nelem(sub), 1, &s, skipping, TRUE, name,
4725
      switch(read_subs(sub, nelem(sub), 1, &s, skipping, TRUE, name,
Lines 4614-4620 Link Here
4614
	    debug_printf_indent("acl expansion yield: %s\n", user_msg);
4740
	    debug_printf_indent("acl expansion yield: %s\n", user_msg);
4615
	  if (user_msg)
4741
	  if (user_msg)
4616
            yield = string_cat(yield, user_msg);
4742
            yield = string_cat(yield, user_msg);
4617
	  continue;
4743
	  break;
4618
4744
4619
	case DEFER:
4745
	case DEFER:
4620
          f.expand_string_forcedfail = TRUE;
4746
          f.expand_string_forcedfail = TRUE;
Lines 4624-4635 Link Here
4624
	    rc_names[rc], sub[0]);
4750
	    rc_names[rc], sub[0]);
4625
	  goto EXPAND_FAILED;
4751
	  goto EXPAND_FAILED;
4626
	}
4752
	}
4753
      break;
4627
      }
4754
      }
4628
4755
4629
    case EITEM_AUTHRESULTS:
4756
    case EITEM_AUTHRESULTS:
4630
      /* ${authresults {mysystemname}} */
4757
      /* ${authresults {mysystemname}} */
4631
      {
4758
      {
4632
      uschar *sub_arg[1];
4759
      uschar * sub_arg[1];
4633
4760
4634
      switch(read_subs(sub_arg, nelem(sub_arg), 1, &s, skipping, TRUE, name,
4761
      switch(read_subs(sub_arg, nelem(sub_arg), 1, &s, skipping, TRUE, name,
4635
		      &resetok))
4762
		      &resetok))
Lines 4658-4664 Link Here
4658
#ifdef EXPERIMENTAL_ARC
4785
#ifdef EXPERIMENTAL_ARC
4659
      yield = authres_arc(yield);
4786
      yield = authres_arc(yield);
4660
#endif
4787
#endif
4661
      continue;
4788
      break;
4662
      }
4789
      }
4663
4790
4664
    /* Handle conditionals - preserve the values of the numerical expansion
4791
    /* Handle conditionals - preserve the values of the numerical expansion
Lines 4672-4698 Link Here
4672
      const uschar *next_s;
4799
      const uschar *next_s;
4673
      int save_expand_nmax =
4800
      int save_expand_nmax =
4674
        save_expand_strings(save_expand_nstring, save_expand_nlength);
4801
        save_expand_strings(save_expand_nstring, save_expand_nlength);
4802
      uschar * save_lookup_value = lookup_value;
4675
4803
4676
      Uskip_whitespace(&s);
4804
      Uskip_whitespace(&s);
4677
      if (!(next_s = eval_condition(s, &resetok, skipping ? NULL : &cond)))
4805
      if (!(next_s = eval_condition(s, &resetok, skipping ? NULL : &cond)))
4678
	goto EXPAND_FAILED;  /* message already set */
4806
	goto EXPAND_FAILED;  /* message already set */
4679
4807
4680
      DEBUG(D_expand)
4808
      DEBUG(D_expand)
4681
	DEBUG(D_noutf8)
4809
	{
4682
	  {
4810
	debug_expansion_interim(US"condition", s, (int)(next_s - s), skipping);
4683
	  debug_printf_indent("|--condition: %.*s\n", (int)(next_s - s), s);
4811
	debug_expansion_interim(US"result",
4684
	  debug_printf_indent("|-----result: %s\n", cond ? "true" : "false");
4812
	  cond ? US"true" : US"false", cond ? 4 : 5, skipping);
4685
	  }
4813
	}
4686
	else
4687
	  {
4688
	  debug_printf_indent(UTF8_VERT_RIGHT UTF8_HORIZ UTF8_HORIZ
4689
	    "condition: %.*s\n",
4690
	    (int)(next_s - s), s);
4691
	  debug_printf_indent(UTF8_VERT_RIGHT UTF8_HORIZ UTF8_HORIZ
4692
	    UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
4693
	    "result: %s\n",
4694
	    cond ? "true" : "false");
4695
	  }
4696
4814
4697
      s = next_s;
4815
      s = next_s;
4698
4816
Lines 4715-4728 Link Here
4715
      /* Restore external setting of expansion variables for continuation
4833
      /* Restore external setting of expansion variables for continuation
4716
      at this level. */
4834
      at this level. */
4717
4835
4836
      lookup_value = save_lookup_value;
4718
      restore_expand_strings(save_expand_nmax, save_expand_nstring,
4837
      restore_expand_strings(save_expand_nmax, save_expand_nstring,
4719
        save_expand_nlength);
4838
        save_expand_nlength);
4720
      continue;
4839
      break;
4721
      }
4840
      }
4722
4841
4723
#ifdef SUPPORT_I18N
4842
#ifdef SUPPORT_I18N
4724
    case EITEM_IMAPFOLDER:
4843
    case EITEM_IMAPFOLDER:
4725
      {				/* ${imapfolder {name}{sep]{specials}} */
4844
      {				/* ${imapfolder {name}{sep}{specials}} */
4726
      uschar *sub_arg[3];
4845
      uschar *sub_arg[3];
4727
      uschar *encoded;
4846
      uschar *encoded;
4728
4847
Lines 4748-4761 Link Here
4748
	goto EXPAND_FAILED;
4867
	goto EXPAND_FAILED;
4749
	}
4868
	}
4750
4869
4751
      if (!skipping)
4870
      if (skipping) continue;
4752
	{
4871
4753
	if (!(encoded = imap_utf7_encode(sub_arg[0], headers_charset,
4872
      if (!(encoded = imap_utf7_encode(sub_arg[0], headers_charset,
4754
			    sub_arg[1][0], sub_arg[2], &expand_string_message)))
4873
			  sub_arg[1][0], sub_arg[2], &expand_string_message)))
4755
	  goto EXPAND_FAILED;
4874
	goto EXPAND_FAILED;
4756
	yield = string_cat(yield, encoded);
4875
      yield = string_cat(yield, encoded);
4757
	}
4876
      break;
4758
      continue;
4759
      }
4877
      }
4760
#endif
4878
#endif
4761
4879
Lines 4771-4783 Link Here
4771
      int stype, partial, affixlen, starflags;
4889
      int stype, partial, affixlen, starflags;
4772
      int expand_setup = 0;
4890
      int expand_setup = 0;
4773
      int nameptr = 0;
4891
      int nameptr = 0;
4774
      uschar *key, *filename;
4892
      uschar * key, * filename;
4775
      const uschar * affix, * opts;
4893
      const uschar * affix, * opts;
4776
      uschar *save_lookup_value = lookup_value;
4894
      uschar * save_lookup_value = lookup_value;
4777
      int save_expand_nmax =
4895
      int save_expand_nmax =
4778
        save_expand_strings(save_expand_nstring, save_expand_nlength);
4896
        save_expand_strings(save_expand_nstring, save_expand_nlength);
4779
4897
4780
      if ((expand_forbid & RDO_LOOKUP) != 0)
4898
      if (expand_forbid & RDO_LOOKUP)
4781
        {
4899
        {
4782
        expand_string_message = US"lookup expansions are not permitted";
4900
        expand_string_message = US"lookup expansions are not permitted";
4783
        goto EXPAND_FAILED;
4901
        goto EXPAND_FAILED;
Lines 4841-4855 Link Here
4841
          goto EXPAND_FAILED;
4959
          goto EXPAND_FAILED;
4842
          }
4960
          }
4843
        }
4961
        }
4844
      else
4962
      else if (key)
4845
        {
4963
	{
4846
        if (key)
4964
	expand_string_message = string_sprintf("a single key was given for "
4847
          {
4965
	  "lookup type \"%s\", which is not a single-key lookup type", name);
4848
          expand_string_message = string_sprintf("a single key was given for "
4966
	goto EXPAND_FAILED;
4849
            "lookup type \"%s\", which is not a single-key lookup type", name);
4967
	}
4850
          goto EXPAND_FAILED;
4851
          }
4852
        }
4853
4968
4854
      /* Get the next string in brackets and expand it. It is the file name for
4969
      /* Get the next string in brackets and expand it. It is the file name for
4855
      single-key+file lookups, and the whole query otherwise. In the case of
4970
      single-key+file lookups, and the whole query otherwise. In the case of
Lines 4859-4868 Link Here
4859
      if (*s != '{')
4974
      if (*s != '{')
4860
        {
4975
        {
4861
	expand_string_message = US"missing '{' for lookup file-or-query arg";
4976
	expand_string_message = US"missing '{' for lookup file-or-query arg";
4862
	goto EXPAND_FAILED_CURLY;
4977
	goto EXPAND_FAILED_CURLY;						/*}}*/
4863
	}
4978
	}
4864
      if (!(filename = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok)))
4979
      if (!(filename = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok)))
4865
	goto EXPAND_FAILED;
4980
	goto EXPAND_FAILED;
4981
      										/*{{*/
4866
      if (*s++ != '}')
4982
      if (*s++ != '}')
4867
        {
4983
        {
4868
	expand_string_message = US"missing '}' closing lookup file-or-query arg";
4984
	expand_string_message = US"missing '}' closing lookup file-or-query arg";
Lines 4876-4896 Link Here
4876
      file types, the query (i.e. "key") starts with a file name. */
4992
      file types, the query (i.e. "key") starts with a file name. */
4877
4993
4878
      if (!key)
4994
      if (!key)
4879
        {
4995
	key = search_args(stype, name, filename, &filename, opts);
4880
	Uskip_whitespace(&filename);
4881
        key = filename;
4882
4883
        if (mac_islookup(stype, lookup_querystyle))
4884
          filename = NULL;
4885
        else
4886
          if (*filename == '/')
4887
	    {
4888
	    while (*key && !isspace(*key)) key++;
4889
	    if (*key) *key++ = '\0';
4890
	    }
4891
	  else
4892
	    filename = NULL;
4893
        }
4894
4996
4895
      /* If skipping, don't do the next bit - just lookup_value == NULL, as if
4997
      /* If skipping, don't do the next bit - just lookup_value == NULL, as if
4896
      the entry was not found. Note that there is no search_close() function.
4998
      the entry was not found. Note that there is no search_close() function.
Lines 4909-4915 Link Here
4909
        lookup_value = NULL;
5011
        lookup_value = NULL;
4910
      else
5012
      else
4911
        {
5013
        {
4912
        void *handle = search_open(filename, stype, 0, NULL, NULL);
5014
        void * handle = search_open(filename, stype, 0, NULL, NULL);
4913
        if (!handle)
5015
        if (!handle)
4914
          {
5016
          {
4915
          expand_string_message = search_error_message;
5017
          expand_string_message = search_error_message;
Lines 4948-4954 Link Here
4948
5050
4949
      restore_expand_strings(save_expand_nmax, save_expand_nstring,
5051
      restore_expand_strings(save_expand_nmax, save_expand_nstring,
4950
        save_expand_nlength);
5052
        save_expand_nlength);
4951
      continue;
5053
5054
      if (skipping) continue;
5055
      break;
4952
      }
5056
      }
4953
5057
4954
    /* If Perl support is configured, handle calling embedded perl subroutines,
5058
    /* If Perl support is configured, handle calling embedded perl subroutines,
Lines 4956-4975 Link Here
4956
    or ${perl{sub}{arg1}{arg2}} or up to a maximum of EXIM_PERL_MAX_ARGS
5060
    or ${perl{sub}{arg1}{arg2}} or up to a maximum of EXIM_PERL_MAX_ARGS
4957
    arguments (defined below). */
5061
    arguments (defined below). */
4958
5062
4959
    #define EXIM_PERL_MAX_ARGS 8
5063
#define EXIM_PERL_MAX_ARGS 8
4960
5064
4961
    case EITEM_PERL:
5065
    case EITEM_PERL:
4962
    #ifndef EXIM_PERL
5066
#ifndef EXIM_PERL
4963
    expand_string_message = US"\"${perl\" encountered, but this facility "	/*}*/
5067
      expand_string_message = US"\"${perl\" encountered, but this facility "	/*}*/
4964
      "is not included in this binary";
5068
	"is not included in this binary";
4965
    goto EXPAND_FAILED;
5069
      goto EXPAND_FAILED;
4966
5070
4967
    #else   /* EXIM_PERL */
5071
#else   /* EXIM_PERL */
4968
      {
5072
      {
4969
      uschar *sub_arg[EXIM_PERL_MAX_ARGS + 2];
5073
      uschar * sub_arg[EXIM_PERL_MAX_ARGS + 2];
4970
      gstring *new_yield;
5074
      gstring * new_yield;
4971
5075
4972
      if ((expand_forbid & RDO_PERL) != 0)
5076
      if (expand_forbid & RDO_PERL)
4973
        {
5077
        {
4974
        expand_string_message = US"Perl calls are not permitted";
5078
        expand_string_message = US"Perl calls are not permitted";
4975
        goto EXPAND_FAILED;
5079
        goto EXPAND_FAILED;
Lines 4991-4997 Link Here
4991
5095
4992
      if (!opt_perl_started)
5096
      if (!opt_perl_started)
4993
        {
5097
        {
4994
        uschar *initerror;
5098
        uschar * initerror;
4995
        if (!opt_perl_startup)
5099
        if (!opt_perl_startup)
4996
          {
5100
          {
4997
          expand_string_message = US"A setting of perl_startup is needed when "
5101
          expand_string_message = US"A setting of perl_startup is needed when "
Lines 5035-5051 Link Here
5035
5139
5036
      f.expand_string_forcedfail = FALSE;
5140
      f.expand_string_forcedfail = FALSE;
5037
      yield = new_yield;
5141
      yield = new_yield;
5038
      continue;
5142
      break;
5039
      }
5143
      }
5040
    #endif /* EXIM_PERL */
5144
#endif /* EXIM_PERL */
5041
5145
5042
    /* Transform email address to "prvs" scheme to use
5146
    /* Transform email address to "prvs" scheme to use
5043
       as BATV-signed return path */
5147
       as BATV-signed return path */
5044
5148
5045
    case EITEM_PRVS:
5149
    case EITEM_PRVS:
5046
      {
5150
      {
5047
      uschar *sub_arg[3];
5151
      uschar * sub_arg[3], * p, * domain;
5048
      uschar *p,*domain;
5049
5152
5050
      switch(read_subs(sub_arg, 3, 2, &s, skipping, TRUE, name, &resetok))
5153
      switch(read_subs(sub_arg, 3, 2, &s, skipping, TRUE, name, &resetok))
5051
        {
5154
        {
Lines 5094-5110 Link Here
5094
      yield = string_catn(yield, US"@", 1);
5197
      yield = string_catn(yield, US"@", 1);
5095
      yield = string_cat (yield, domain);
5198
      yield = string_cat (yield, domain);
5096
5199
5097
      continue;
5200
      break;
5098
      }
5201
      }
5099
5202
5100
    /* Check a prvs-encoded address for validity */
5203
    /* Check a prvs-encoded address for validity */
5101
5204
5102
    case EITEM_PRVSCHECK:
5205
    case EITEM_PRVSCHECK:
5103
      {
5206
      {
5104
      uschar *sub_arg[3];
5207
      uschar * sub_arg[3], * p;
5105
      gstring * g;
5208
      gstring * g;
5106
      const pcre *re;
5209
      const pcre2_code * re;
5107
      uschar *p;
5108
5210
5109
      /* TF: Ugliness: We want to expand parameter 1 first, then set
5211
      /* TF: Ugliness: We want to expand parameter 1 first, then set
5110
         up expansion variables that are used in the expansion of
5212
         up expansion variables that are used in the expansion of
Lines 5114-5120 Link Here
5114
         PH: Actually, that isn't necessary. The read_subs() function is
5216
         PH: Actually, that isn't necessary. The read_subs() function is
5115
         designed to work this way for the ${if and ${lookup expansions. I've
5217
         designed to work this way for the ${if and ${lookup expansions. I've
5116
         tidied the code.
5218
         tidied the code.
5117
      */
5219
      */								/*}}*/
5118
5220
5119
      /* Reset expansion variables */
5221
      /* Reset expansion variables */
5120
      prvscheck_result = NULL;
5222
      prvscheck_result = NULL;
Lines 5133-5143 Link Here
5133
5235
5134
      if (regex_match_and_setup(re,sub_arg[0],0,-1))
5236
      if (regex_match_and_setup(re,sub_arg[0],0,-1))
5135
        {
5237
        {
5136
        uschar *local_part = string_copyn(expand_nstring[4],expand_nlength[4]);
5238
        uschar * local_part = string_copyn(expand_nstring[4],expand_nlength[4]);
5137
        uschar *key_num = string_copyn(expand_nstring[1],expand_nlength[1]);
5239
        uschar * key_num = string_copyn(expand_nstring[1],expand_nlength[1]);
5138
        uschar *daystamp = string_copyn(expand_nstring[2],expand_nlength[2]);
5240
        uschar * daystamp = string_copyn(expand_nstring[2],expand_nlength[2]);
5139
        uschar *hash = string_copyn(expand_nstring[3],expand_nlength[3]);
5241
        uschar * hash = string_copyn(expand_nstring[3],expand_nlength[3]);
5140
        uschar *domain = string_copyn(expand_nstring[5],expand_nlength[5]);
5242
        uschar * domain = string_copyn(expand_nstring[5],expand_nlength[5]);
5141
5243
5142
        DEBUG(D_expand) debug_printf_indent("prvscheck localpart: %s\n", local_part);
5244
        DEBUG(D_expand) debug_printf_indent("prvscheck localpart: %s\n", local_part);
5143
        DEBUG(D_expand) debug_printf_indent("prvscheck key number: %s\n", key_num);
5245
        DEBUG(D_expand) debug_printf_indent("prvscheck key number: %s\n", key_num);
Lines 5235-5249 Link Here
5235
          case 3: goto EXPAND_FAILED;
5337
          case 3: goto EXPAND_FAILED;
5236
          }
5338
          }
5237
5339
5238
      continue;
5340
      if (skipping) continue;
5341
      break;
5239
      }
5342
      }
5240
5343
5241
    /* Handle "readfile" to insert an entire file */
5344
    /* Handle "readfile" to insert an entire file */
5242
5345
5243
    case EITEM_READFILE:
5346
    case EITEM_READFILE:
5244
      {
5347
      {
5245
      FILE *f;
5348
      FILE * f;
5246
      uschar *sub_arg[2];
5349
      uschar * sub_arg[2];
5247
5350
5248
      if ((expand_forbid & RDO_READFILE) != 0)
5351
      if ((expand_forbid & RDO_READFILE) != 0)
5249
        {
5352
        {
Lines 5266-5278 Link Here
5266
5369
5267
      if (!(f = Ufopen(sub_arg[0], "rb")))
5370
      if (!(f = Ufopen(sub_arg[0], "rb")))
5268
        {
5371
        {
5269
        expand_string_message = string_open_failed(errno, "%s", sub_arg[0]);
5372
        expand_string_message = string_open_failed("%s", sub_arg[0]);
5270
        goto EXPAND_FAILED;
5373
        goto EXPAND_FAILED;
5271
        }
5374
        }
5272
5375
5273
      yield = cat_file(f, yield, sub_arg[1]);
5376
      yield = cat_file(f, yield, sub_arg[1]);
5274
      (void)fclose(f);
5377
      (void)fclose(f);
5275
      continue;
5378
      break;
5276
      }
5379
      }
5277
5380
5278
    /* Handle "readsocket" to insert data from a socket, either
5381
    /* Handle "readsocket" to insert data from a socket, either
Lines 5378-5415 Link Here
5378
      /* The whole thing has worked (or we were skipping). If there is a
5481
      /* The whole thing has worked (or we were skipping). If there is a
5379
      failure string following, we need to skip it. */
5482
      failure string following, we need to skip it. */
5380
5483
5381
      if (*s == '{')
5484
      if (*s == '{')							/*}*/
5382
        {
5485
        {
5383
        if (!expand_string_internal(s+1, TRUE, &s, TRUE, TRUE, &resetok))
5486
        if (!expand_string_internal(s+1, TRUE, &s, TRUE, TRUE, &resetok))
5384
          goto EXPAND_FAILED;
5487
          goto EXPAND_FAILED;						/*{*/
5385
        if (*s++ != '}')
5488
        if (*s++ != '}')
5386
	  {
5489
	  {								/*{*/
5387
	  expand_string_message = US"missing '}' closing failstring for readsocket";
5490
	  expand_string_message = US"missing '}' closing failstring for readsocket";
5388
	  goto EXPAND_FAILED_CURLY;
5491
	  goto EXPAND_FAILED_CURLY;
5389
	  }
5492
	  }
5390
        Uskip_whitespace(&s);
5493
        Uskip_whitespace(&s);
5391
        }
5494
        }
5392
5495
5393
    READSOCK_DONE:
5496
    READSOCK_DONE:							/*{*/
5394
      if (*s++ != '}')
5497
      if (*s++ != '}')
5395
        {
5498
        {								/*{*/
5396
	expand_string_message = US"missing '}' closing readsocket";
5499
	expand_string_message = US"missing '}' closing readsocket";
5397
	goto EXPAND_FAILED_CURLY;
5500
	goto EXPAND_FAILED_CURLY;
5398
	}
5501
	}
5399
      continue;
5502
      if (skipping) continue;
5503
      break;
5400
5504
5401
      /* Come here on failure to create socket, connect socket, write to the
5505
      /* Come here on failure to create socket, connect socket, write to the
5402
      socket, or timeout on reading. If another substring follows, expand and
5506
      socket, or timeout on reading. If another substring follows, expand and
5403
      use it. Otherwise, those conditions give expand errors. */
5507
      use it. Otherwise, those conditions give expand errors. */
5404
5508
5405
    SOCK_FAIL:
5509
    SOCK_FAIL:
5406
      if (*s != '{') goto EXPAND_FAILED;
5510
      if (*s != '{') goto EXPAND_FAILED;				/*}*/
5407
      DEBUG(D_any) debug_printf("%s\n", expand_string_message);
5511
      DEBUG(D_any) debug_printf("%s\n", expand_string_message);
5408
      if (!(arg = expand_string_internal(s+1, TRUE, &s, FALSE, TRUE, &resetok)))
5512
      if (!(arg = expand_string_internal(s+1, TRUE, &s, FALSE, TRUE, &resetok)))
5409
        goto EXPAND_FAILED;
5513
        goto EXPAND_FAILED;
5410
      yield = string_cat(yield, arg);
5514
      yield = string_cat(yield, arg);					/*{*/
5411
      if (*s++ != '}')
5515
      if (*s++ != '}')
5412
        {
5516
        {								/*{*/
5413
	expand_string_message = US"missing '}' closing failstring for readsocket";
5517
	expand_string_message = US"missing '}' closing failstring for readsocket";
5414
	goto EXPAND_FAILED_CURLY;
5518
	goto EXPAND_FAILED_CURLY;
5415
	}
5519
	}
Lines 5421-5431 Link Here
5421
5525
5422
    case EITEM_RUN:
5526
    case EITEM_RUN:
5423
      {
5527
      {
5424
      FILE *f;
5528
      FILE * f;
5425
      uschar *arg;
5529
      const uschar * arg, ** argv;
5426
      const uschar **argv;
5530
      BOOL late_expand = TRUE;
5427
      pid_t pid;
5428
      int fd_in, fd_out;
5429
5531
5430
      if ((expand_forbid & RDO_RUN) != 0)
5532
      if ((expand_forbid & RDO_RUN) != 0)
5431
        {
5533
        {
Lines 5433-5449 Link Here
5433
        goto EXPAND_FAILED;
5535
        goto EXPAND_FAILED;
5434
        }
5536
        }
5435
5537
5538
      /* Handle options to the "run" */
5539
5540
      while (*s == ',')
5541
	{
5542
	if (Ustrncmp(++s, "preexpand", 9) == 0)
5543
	  { late_expand = FALSE; s += 9; }
5544
	else
5545
	  {
5546
	  const uschar * t = s;
5547
	  while (isalpha(*++t)) ;
5548
	  expand_string_message = string_sprintf("bad option '%.*s' for run",
5549
						  (int)(t-s), s);
5550
	  goto EXPAND_FAILED;
5551
	  }
5552
	}
5436
      Uskip_whitespace(&s);
5553
      Uskip_whitespace(&s);
5437
      if (*s != '{')
5554
5555
      if (*s != '{')					/*}*/
5438
        {
5556
        {
5439
	expand_string_message = US"missing '{' for command arg of run";
5557
	expand_string_message = US"missing '{' for command arg of run";
5440
	goto EXPAND_FAILED_CURLY;
5558
	goto EXPAND_FAILED_CURLY;			/*"}*/
5441
	}
5559
	}
5442
      if (!(arg = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok)))
5560
      s++;
5443
	goto EXPAND_FAILED;
5561
5444
      Uskip_whitespace(&s);
5562
      if (late_expand)		/* this is the default case */
5563
	{
5564
	int n = Ustrcspn(s, "}");
5565
	arg = skipping ? NULL : string_copyn(s, n);
5566
	s += n;
5567
	}
5568
      else
5569
	{
5570
	if (!(arg = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok)))
5571
	  goto EXPAND_FAILED;
5572
	Uskip_whitespace(&s);
5573
	}
5574
							/*{*/
5445
      if (*s++ != '}')
5575
      if (*s++ != '}')
5446
        {
5576
        {						/*{*/
5447
	expand_string_message = US"missing '}' closing command arg of run";
5577
	expand_string_message = US"missing '}' closing command arg of run";
5448
	goto EXPAND_FAILED_CURLY;
5578
	goto EXPAND_FAILED_CURLY;
5449
	}
5579
	}
Lines 5455-5467 Link Here
5455
	}
5585
	}
5456
      else
5586
      else
5457
        {
5587
        {
5588
	int fd_in, fd_out;
5589
	pid_t pid;
5590
5458
        if (!transport_set_up_command(&argv,    /* anchor for arg list */
5591
        if (!transport_set_up_command(&argv,    /* anchor for arg list */
5459
            arg,                                /* raw command */
5592
            arg,                                /* raw command */
5460
            FALSE,                              /* don't expand the arguments */
5593
	    late_expand,		/* expand args if not already done */
5461
            0,                                  /* not relevant when... */
5594
            0,                          /* not relevant when... */
5462
            NULL,                               /* no transporting address */
5595
            NULL,                       /* no transporting address */
5463
            US"${run} expansion",               /* for error messages */
5596
	    late_expand,		/* allow tainted args, when expand-after-split */
5464
            &expand_string_message))            /* where to put error message */
5597
            US"${run} expansion",       /* for error messages */
5598
            &expand_string_message))    /* where to put error message */
5465
          goto EXPAND_FAILED;
5599
          goto EXPAND_FAILED;
5466
5600
5467
        /* Create the child process, making it a group leader. */
5601
        /* Create the child process, making it a group leader. */
Lines 5472-5478 Link Here
5472
          expand_string_message =
5606
          expand_string_message =
5473
            string_sprintf("couldn't create child process: %s", strerror(errno));
5607
            string_sprintf("couldn't create child process: %s", strerror(errno));
5474
          goto EXPAND_FAILED;
5608
          goto EXPAND_FAILED;
5475
          }
5609
	  }
5476
5610
5477
        /* Nothing is written to the standard input. */
5611
        /* Nothing is written to the standard input. */
5478
5612
Lines 5530-5536 Link Here
5530
        case 2: goto EXPAND_FAILED_CURLY;    /* returned value is 0 */
5664
        case 2: goto EXPAND_FAILED_CURLY;    /* returned value is 0 */
5531
        }
5665
        }
5532
5666
5533
      continue;
5667
      if (skipping) continue;
5668
      break;
5534
      }
5669
      }
5535
5670
5536
    /* Handle character translation for "tr" */
5671
    /* Handle character translation for "tr" */
Lines 5539-5545 Link Here
5539
      {
5674
      {
5540
      int oldptr = gstring_length(yield);
5675
      int oldptr = gstring_length(yield);
5541
      int o2m;
5676
      int o2m;
5542
      uschar *sub[3];
5677
      uschar * sub[3];
5543
5678
5544
      switch(read_subs(sub, 3, 3, &s, skipping, TRUE, name, &resetok))
5679
      switch(read_subs(sub, 3, 3, &s, skipping, TRUE, name, &resetok))
5545
        {
5680
        {
Lines 5561-5567 Link Here
5561
          }
5696
          }
5562
        }
5697
        }
5563
5698
5564
      continue;
5699
      if (skipping) continue;
5700
      break;
5565
      }
5701
      }
5566
5702
5567
    /* Handle "hash", "length", "nhash", and "substr" when they are given with
5703
    /* Handle "hash", "length", "nhash", and "substr" when they are given with
Lines 5575-5581 Link Here
5575
      int len;
5711
      int len;
5576
      uschar *ret;
5712
      uschar *ret;
5577
      int val[2] = { 0, -1 };
5713
      int val[2] = { 0, -1 };
5578
      uschar *sub[3];
5714
      uschar * sub[3];
5579
5715
5580
      /* "length" takes only 2 arguments whereas the others take 2 or 3.
5716
      /* "length" takes only 2 arguments whereas the others take 2 or 3.
5581
      Ensure that sub[2] is set in the ${length } case. */
5717
      Ensure that sub[2] is set in the ${length } case. */
Lines 5624-5630 Link Here
5624
      if (!ret)
5760
      if (!ret)
5625
	goto EXPAND_FAILED;
5761
	goto EXPAND_FAILED;
5626
      yield = string_catn(yield, ret, len);
5762
      yield = string_catn(yield, ret, len);
5627
      continue;
5763
      if (skipping) continue;
5764
      break;
5628
      }
5765
      }
5629
5766
5630
    /* Handle HMAC computation: ${hmac{<algorithm>}{<secret>}{<text>}}
5767
    /* Handle HMAC computation: ${hmac{<algorithm>}{<secret>}{<text>}}
Lines 5639-5652 Link Here
5639
5776
5640
    case EITEM_HMAC:
5777
    case EITEM_HMAC:
5641
      {
5778
      {
5642
      uschar *sub[3];
5779
      uschar * sub[3];
5643
      md5 md5_base;
5780
      md5 md5_base;
5644
      hctx sha1_ctx;
5781
      hctx sha1_ctx;
5645
      void *use_base;
5782
      void * use_base;
5646
      int type;
5783
      int type;
5647
      int hashlen;      /* Number of octets for the hash algorithm's output */
5784
      int hashlen;      /* Number of octets for the hash algorithm's output */
5648
      int hashblocklen; /* Number of octets the hash algorithm processes */
5785
      int hashblocklen; /* Number of octets the hash algorithm processes */
5649
      uschar *keyptr, *p;
5786
      uschar * keyptr, * p;
5650
      unsigned int keylen;
5787
      unsigned int keylen;
5651
5788
5652
      uschar keyhash[MAX_HASHLEN];
5789
      uschar keyhash[MAX_HASHLEN];
Lines 5663-5741 Link Here
5663
        case 3: goto EXPAND_FAILED;
5800
        case 3: goto EXPAND_FAILED;
5664
        }
5801
        }
5665
5802
5666
      if (!skipping)
5803
      if (skipping) continue;
5804
5805
      if (Ustrcmp(sub[0], "md5") == 0)
5667
	{
5806
	{
5668
	if (Ustrcmp(sub[0], "md5") == 0)
5807
	type = HMAC_MD5;
5669
	  {
5808
	use_base = &md5_base;
5670
	  type = HMAC_MD5;
5809
	hashlen = 16;
5671
	  use_base = &md5_base;
5810
	hashblocklen = 64;
5672
	  hashlen = 16;
5811
	}
5673
	  hashblocklen = 64;
5812
      else if (Ustrcmp(sub[0], "sha1") == 0)
5674
	  }
5813
	{
5675
	else if (Ustrcmp(sub[0], "sha1") == 0)
5814
	type = HMAC_SHA1;
5676
	  {
5815
	use_base = &sha1_ctx;
5677
	  type = HMAC_SHA1;
5816
	hashlen = 20;
5678
	  use_base = &sha1_ctx;
5817
	hashblocklen = 64;
5679
	  hashlen = 20;
5818
	}
5680
	  hashblocklen = 64;
5819
      else
5681
	  }
5820
	{
5682
	else
5821
	expand_string_message =
5683
	  {
5822
	  string_sprintf("hmac algorithm \"%s\" is not recognised", sub[0]);
5684
	  expand_string_message =
5823
	goto EXPAND_FAILED;
5685
	    string_sprintf("hmac algorithm \"%s\" is not recognised", sub[0]);
5824
	}
5686
	  goto EXPAND_FAILED;
5687
	  }
5688
5825
5689
	keyptr = sub[1];
5826
      keyptr = sub[1];
5690
	keylen = Ustrlen(keyptr);
5827
      keylen = Ustrlen(keyptr);
5691
5828
5692
	/* If the key is longer than the hash block length, then hash the key
5829
      /* If the key is longer than the hash block length, then hash the key
5693
	first */
5830
      first */
5694
5831
5695
	if (keylen > hashblocklen)
5832
      if (keylen > hashblocklen)
5696
	  {
5833
	{
5697
	  chash_start(type, use_base);
5834
	chash_start(type, use_base);
5698
	  chash_end(type, use_base, keyptr, keylen, keyhash);
5835
	chash_end(type, use_base, keyptr, keylen, keyhash);
5699
	  keyptr = keyhash;
5836
	keyptr = keyhash;
5700
	  keylen = hashlen;
5837
	keylen = hashlen;
5701
	  }
5838
	}
5702
5839
5703
	/* Now make the inner and outer key values */
5840
      /* Now make the inner and outer key values */
5704
5841
5705
	memset(innerkey, 0x36, hashblocklen);
5842
      memset(innerkey, 0x36, hashblocklen);
5706
	memset(outerkey, 0x5c, hashblocklen);
5843
      memset(outerkey, 0x5c, hashblocklen);
5707
5844
5708
	for (int i = 0; i < keylen; i++)
5845
      for (int i = 0; i < keylen; i++)
5709
	  {
5846
	{
5710
	  innerkey[i] ^= keyptr[i];
5847
	innerkey[i] ^= keyptr[i];
5711
	  outerkey[i] ^= keyptr[i];
5848
	outerkey[i] ^= keyptr[i];
5712
	  }
5849
	}
5713
5850
5714
	/* Now do the hashes */
5851
      /* Now do the hashes */
5715
5852
5716
	chash_start(type, use_base);
5853
      chash_start(type, use_base);
5717
	chash_mid(type, use_base, innerkey);
5854
      chash_mid(type, use_base, innerkey);
5718
	chash_end(type, use_base, sub[2], Ustrlen(sub[2]), innerhash);
5855
      chash_end(type, use_base, sub[2], Ustrlen(sub[2]), innerhash);
5719
5856
5720
	chash_start(type, use_base);
5857
      chash_start(type, use_base);
5721
	chash_mid(type, use_base, outerkey);
5858
      chash_mid(type, use_base, outerkey);
5722
	chash_end(type, use_base, innerhash, hashlen, finalhash);
5859
      chash_end(type, use_base, innerhash, hashlen, finalhash);
5723
5860
5724
	/* Encode the final hash as a hex string */
5861
      /* Encode the final hash as a hex string */
5725
5862
5726
	p = finalhash_hex;
5863
      p = finalhash_hex;
5727
	for (int i = 0; i < hashlen; i++)
5864
      for (int i = 0; i < hashlen; i++)
5728
	  {
5865
	{
5729
	  *p++ = hex_digits[(finalhash[i] & 0xf0) >> 4];
5866
	*p++ = hex_digits[(finalhash[i] & 0xf0) >> 4];
5730
	  *p++ = hex_digits[finalhash[i] & 0x0f];
5867
	*p++ = hex_digits[finalhash[i] & 0x0f];
5731
	  }
5868
	}
5732
5869
5733
	DEBUG(D_any) debug_printf("HMAC[%s](%.*s,%s)=%.*s\n",
5870
      DEBUG(D_any) debug_printf("HMAC[%s](%.*s,%s)=%.*s\n",
5734
	  sub[0], (int)keylen, keyptr, sub[2], hashlen*2, finalhash_hex);
5871
	sub[0], (int)keylen, keyptr, sub[2], hashlen*2, finalhash_hex);
5735
5872
5736
	yield = string_catn(yield, finalhash_hex, hashlen*2);
5873
      yield = string_catn(yield, finalhash_hex, hashlen*2);
5737
	}
5874
      break;
5738
      continue;
5739
      }
5875
      }
5740
5876
5741
    /* Handle global substitution for "sg" - like Perl's s/xxx/yyy/g operator.
5877
    /* Handle global substitution for "sg" - like Perl's s/xxx/yyy/g operator.
Lines 5743-5755 Link Here
5743
5879
5744
    case EITEM_SG:
5880
    case EITEM_SG:
5745
      {
5881
      {
5746
      const pcre *re;
5882
      const pcre2_code * re;
5747
      int moffset, moffsetextra, slen;
5883
      int moffset, moffsetextra, slen;
5748
      int roffset;
5884
      PCRE2_SIZE roffset;
5749
      int emptyopt;
5885
      pcre2_match_data * md;
5750
      const uschar *rerror;
5886
      int err, emptyopt;
5751
      uschar *subject;
5887
      uschar * subject, * sub[3];
5752
      uschar *sub[3];
5753
      int save_expand_nmax =
5888
      int save_expand_nmax =
5754
        save_expand_strings(save_expand_nstring, save_expand_nlength);
5889
        save_expand_strings(save_expand_nstring, save_expand_nlength);
5755
5890
Lines 5760-5774 Link Here
5760
        case 3: goto EXPAND_FAILED;
5895
        case 3: goto EXPAND_FAILED;
5761
        }
5896
        }
5762
5897
5898
      /*XXX no handling of skipping? */
5763
      /* Compile the regular expression */
5899
      /* Compile the regular expression */
5764
5900
5765
      if (!(re = pcre_compile(CS sub[1], PCRE_COPT, CCSS &rerror,
5901
      if (!(re = pcre2_compile((PCRE2_SPTR)sub[1], PCRE2_ZERO_TERMINATED,
5766
			      &roffset, NULL)))
5902
		  PCRE_COPT, &err, &roffset, pcre_cmp_ctx)))
5767
        {
5903
        {
5904
        uschar errbuf[128];
5905
	pcre2_get_error_message(err, errbuf, sizeof(errbuf));
5768
        expand_string_message = string_sprintf("regular expression error in "
5906
        expand_string_message = string_sprintf("regular expression error in "
5769
          "\"%s\": %s at offset %d", sub[1], rerror, roffset);
5907
          "\"%s\": %s at offset %ld", sub[1], errbuf, (long)roffset);
5770
        goto EXPAND_FAILED;
5908
        goto EXPAND_FAILED;
5771
        }
5909
        }
5910
      md = pcre2_match_data_create(EXPAND_MAXN + 1, pcre_gen_ctx);
5772
5911
5773
      /* Now run a loop to do the substitutions as often as necessary. It ends
5912
      /* Now run a loop to do the substitutions as often as necessary. It ends
5774
      when there are no more matches. Take care over matches of the null string;
5913
      when there are no more matches. Take care over matches of the null string;
Lines 5781-5790 Link Here
5781
5920
5782
      for (;;)
5921
      for (;;)
5783
        {
5922
        {
5784
        int ovector[3*(EXPAND_MAXN+1)];
5923
	PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md);
5785
        int n = pcre_exec(re, NULL, CS subject, slen, moffset + moffsetextra,
5924
	int n = pcre2_match(re, (PCRE2_SPTR)subject, slen, moffset + moffsetextra,
5786
          PCRE_EOPT | emptyopt, ovector, nelem(ovector));
5925
	  PCRE_EOPT | emptyopt, md, pcre_mtc_ctx);
5787
        uschar *insert;
5926
        uschar * insert;
5788
5927
5789
        /* No match - if we previously set PCRE_NOTEMPTY after a null match, this
5928
        /* No match - if we previously set PCRE_NOTEMPTY after a null match, this
5790
        is not necessarily the end. We want to repeat the match from one
5929
        is not necessarily the end. We want to repeat the match from one
Lines 5806-5829 Link Here
5806
          }
5945
          }
5807
5946
5808
        /* Match - set up for expanding the replacement. */
5947
        /* Match - set up for expanding the replacement. */
5948
	DEBUG(D_expand) debug_printf_indent("%s: match\n", name);
5809
5949
5810
        if (n == 0) n = EXPAND_MAXN + 1;
5950
        if (n == 0) n = EXPAND_MAXN + 1;
5811
        expand_nmax = 0;
5951
        expand_nmax = 0;
5812
        for (int nn = 0; nn < n*2; nn += 2)
5952
        for (int nn = 0; nn < n*2; nn += 2)
5813
          {
5953
          {
5814
          expand_nstring[expand_nmax] = subject + ovector[nn];
5954
          expand_nstring[expand_nmax] = subject + ovec[nn];
5815
          expand_nlength[expand_nmax++] = ovector[nn+1] - ovector[nn];
5955
          expand_nlength[expand_nmax++] = ovec[nn+1] - ovec[nn];
5816
          }
5956
          }
5817
        expand_nmax--;
5957
        expand_nmax--;
5818
5958
5819
        /* Copy the characters before the match, plus the expanded insertion. */
5959
        /* Copy the characters before the match, plus the expanded insertion. */
5820
5960
5821
        yield = string_catn(yield, subject + moffset, ovector[0] - moffset);
5961
	yield = string_catn(yield, subject + moffset, ovec[0] - moffset);
5962
5822
        if (!(insert = expand_string(sub[2])))
5963
        if (!(insert = expand_string(sub[2])))
5823
	  goto EXPAND_FAILED;
5964
	  goto EXPAND_FAILED;
5824
        yield = string_cat(yield, insert);
5965
        yield = string_cat(yield, insert);
5825
5966
5826
        moffset = ovector[1];
5967
        moffset = ovec[1];
5827
        moffsetextra = 0;
5968
        moffsetextra = 0;
5828
        emptyopt = 0;
5969
        emptyopt = 0;
5829
5970
Lines 5834-5843 Link Here
5834
        string at the same point. If this fails (picked up above) we advance to
5975
        string at the same point. If this fails (picked up above) we advance to
5835
        the next character. */
5976
        the next character. */
5836
5977
5837
        if (ovector[0] == ovector[1])
5978
        if (ovec[0] == ovec[1])
5838
          {
5979
          {
5839
          if (ovector[0] == slen) break;
5980
          if (ovec[0] == slen) break;
5840
          emptyopt = PCRE_NOTEMPTY | PCRE_ANCHORED;
5981
          emptyopt = PCRE2_NOTEMPTY | PCRE2_ANCHORED;
5841
          }
5982
          }
5842
        }
5983
        }
5843
5984
Lines 5845-5851 Link Here
5845
5986
5846
      restore_expand_strings(save_expand_nmax, save_expand_nstring,
5987
      restore_expand_strings(save_expand_nmax, save_expand_nstring,
5847
        save_expand_nlength);
5988
        save_expand_nlength);
5848
      continue;
5989
      if (skipping) continue;
5990
      break;
5849
      }
5991
      }
5850
5992
5851
    /* Handle keyed and numbered substring extraction. If the first argument
5993
    /* Handle keyed and numbered substring extraction. If the first argument
Lines 5855-5862 Link Here
5855
      {
5997
      {
5856
      int field_number = 1;
5998
      int field_number = 1;
5857
      BOOL field_number_set = FALSE;
5999
      BOOL field_number_set = FALSE;
5858
      uschar *save_lookup_value = lookup_value;
6000
      uschar * save_lookup_value = lookup_value, * sub[3];
5859
      uschar *sub[3];
5860
      int save_expand_nmax =
6001
      int save_expand_nmax =
5861
        save_expand_strings(save_expand_nstring, save_expand_nlength);
6002
        save_expand_strings(save_expand_nstring, save_expand_nlength);
5862
6003
Lines 5882-5888 Link Here
5882
6023
5883
      if (skipping)
6024
      if (skipping)
5884
	{
6025
	{
5885
        for (int j = 5; j > 0 && *s == '{'; j--)		/*'}'*/
6026
        for (int j = 5; j > 0 && *s == '{'; j--)			/*'}'*/
5886
	  {
6027
	  {
5887
          if (!expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok))
6028
          if (!expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok))
5888
	    goto EXPAND_FAILED;					/*'{'*/
6029
	    goto EXPAND_FAILED;					/*'{'*/
Lines 5893-5905 Link Here
5893
	    }
6034
	    }
5894
	  Uskip_whitespace(&s);
6035
	  Uskip_whitespace(&s);
5895
	  }
6036
	  }
5896
	if (  Ustrncmp(s, "fail", 4) == 0			/*'{'*/
6037
	if (  Ustrncmp(s, "fail", 4) == 0				/*'{'*/
5897
	   && (s[4] == '}' || s[4] == ' ' || s[4] == '\t' || !s[4])
6038
	   && (s[4] == '}' || s[4] == ' ' || s[4] == '\t' || !s[4])
5898
	   )
6039
	   )
5899
	  {
6040
	  {
5900
	  s += 4;
6041
	  s += 4;
5901
	  Uskip_whitespace(&s);
6042
	  Uskip_whitespace(&s);
5902
	  }							/*'{'*/
6043
	  }								/*'{'*/
5903
	if (*s != '}')
6044
	if (*s != '}')
5904
	  {
6045
	  {
5905
	  expand_string_message = US"missing '}' closing extract";
6046
	  expand_string_message = US"missing '}' closing extract";
Lines 5909-5918 Link Here
5909
6050
5910
      else for (int i = 0, j = 2; i < j; i++) /* Read the proper number of arguments */
6051
      else for (int i = 0, j = 2; i < j; i++) /* Read the proper number of arguments */
5911
        {
6052
        {
5912
	if (Uskip_whitespace(&s) == '{') 						/*'}'*/
6053
	if (Uskip_whitespace(&s) == '{') 				/*'}'*/
5913
          {
6054
          {
5914
          if (!(sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok)))
6055
          if (!(sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok)))
5915
	    goto EXPAND_FAILED;					/*'{'*/
6056
	    goto EXPAND_FAILED;						/*'{'*/
5916
          if (*s++ != '}')
6057
          if (*s++ != '}')
5917
	    {
6058
	    {
5918
	    expand_string_message = string_sprintf(
6059
	    expand_string_message = string_sprintf(
Lines 5929-5935 Link Here
5929
            {
6070
            {
5930
            int len;
6071
            int len;
5931
            int x = 0;
6072
            int x = 0;
5932
            uschar *p = sub[0];
6073
            uschar * p = sub[0];
5933
6074
5934
            Uskip_whitespace(&p);
6075
            Uskip_whitespace(&p);
5935
            sub[0] = p;
6076
            sub[0] = p;
Lines 5938-5944 Link Here
5938
            while (len > 0 && isspace(p[len-1])) len--;
6079
            while (len > 0 && isspace(p[len-1])) len--;
5939
            p[len] = 0;
6080
            p[len] = 0;
5940
6081
5941
	    if (*p == 0)
6082
	    if (!*p)
5942
	      {
6083
	      {
5943
	      expand_string_message = US"first argument of \"extract\" must "
6084
	      expand_string_message = US"first argument of \"extract\" must "
5944
		"not be empty";
6085
		"not be empty";
Lines 5950-5957 Link Here
5950
	      field_number = -1;
6091
	      field_number = -1;
5951
	      p++;
6092
	      p++;
5952
	      }
6093
	      }
5953
	    while (*p != 0 && isdigit(*p)) x = x * 10 + *p++ - '0';
6094
	    while (*p && isdigit(*p)) x = x * 10 + *p++ - '0';
5954
	    if (*p == 0)
6095
	    if (!*p)
5955
	      {
6096
	      {
5956
	      field_number *= x;
6097
	      field_number *= x;
5957
	      if (fmt == extract_basic) j = 3;               /* Need 3 args */
6098
	      if (fmt == extract_basic) j = 3;               /* Need 3 args */
Lines 6081-6087 Link Here
6081
      restore_expand_strings(save_expand_nmax, save_expand_nstring,
6222
      restore_expand_strings(save_expand_nmax, save_expand_nstring,
6082
        save_expand_nlength);
6223
        save_expand_nlength);
6083
6224
6084
      continue;
6225
      if (skipping) continue;
6226
      break;
6085
      }
6227
      }
6086
6228
6087
    /* return the Nth item from a list */
6229
    /* return the Nth item from a list */
Lines 6089-6096 Link Here
6089
    case EITEM_LISTEXTRACT:
6231
    case EITEM_LISTEXTRACT:
6090
      {
6232
      {
6091
      int field_number = 1;
6233
      int field_number = 1;
6092
      uschar *save_lookup_value = lookup_value;
6234
      uschar * save_lookup_value = lookup_value, * sub[2];
6093
      uschar *sub[2];
6094
      int save_expand_nmax =
6235
      int save_expand_nmax =
6095
        save_expand_strings(save_expand_nstring, save_expand_nlength);
6236
        save_expand_strings(save_expand_nstring, save_expand_nlength);
6096
6237
Lines 6098-6112 Link Here
6098
6239
6099
      for (int i = 0; i < 2; i++)
6240
      for (int i = 0; i < 2; i++)
6100
        {
6241
        {
6101
        if (Uskip_whitespace(&s) != '{')					/*'}'*/
6242
        if (Uskip_whitespace(&s) != '{')				/*}*/
6102
	  {
6243
	  {
6103
	  expand_string_message = string_sprintf(
6244
	  expand_string_message = string_sprintf(
6104
	    "missing '{' for arg %d of listextract", i+1);
6245
	    "missing '{' for arg %d of listextract", i+1);		/*}*/
6105
	  goto EXPAND_FAILED_CURLY;
6246
	  goto EXPAND_FAILED_CURLY;
6106
	  }
6247
	  }
6107
6248
6108
	sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
6249
	sub[i] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
6109
	if (!sub[i])     goto EXPAND_FAILED;		/*{*/
6250
	if (!sub[i])     goto EXPAND_FAILED;				/*{{*/
6110
	if (*s++ != '}')
6251
	if (*s++ != '}')
6111
	  {
6252
	  {
6112
	  expand_string_message = string_sprintf(
6253
	  expand_string_message = string_sprintf(
Lines 6179-6185 Link Here
6179
      restore_expand_strings(save_expand_nmax, save_expand_nstring,
6320
      restore_expand_strings(save_expand_nmax, save_expand_nstring,
6180
        save_expand_nlength);
6321
        save_expand_nlength);
6181
6322
6182
      continue;
6323
      if (skipping) continue;
6324
      break;
6183
      }
6325
      }
6184
6326
6185
    case EITEM_LISTQUOTE:
6327
    case EITEM_LISTQUOTE:
Lines 6197-6210 Link Here
6197
	yield = string_catn(yield, sub[1], 1);
6339
	yield = string_catn(yield, sub[1], 1);
6198
	}
6340
	}
6199
      else yield = string_catn(yield, US" ", 1);
6341
      else yield = string_catn(yield, US" ", 1);
6200
      continue;
6342
      if (skipping) continue;
6343
      break;
6201
      }
6344
      }
6202
6345
6203
#ifndef DISABLE_TLS
6346
#ifndef DISABLE_TLS
6204
    case EITEM_CERTEXTRACT:
6347
    case EITEM_CERTEXTRACT:
6205
      {
6348
      {
6206
      uschar *save_lookup_value = lookup_value;
6349
      uschar * save_lookup_value = lookup_value, * sub[2];
6207
      uschar *sub[2];
6208
      int save_expand_nmax =
6350
      int save_expand_nmax =
6209
        save_expand_strings(save_expand_nstring, save_expand_nlength);
6351
        save_expand_strings(save_expand_nstring, save_expand_nlength);
6210
6352
Lines 6212-6221 Link Here
6212
      if (Uskip_whitespace(&s) != '{')					/*}*/
6354
      if (Uskip_whitespace(&s) != '{')					/*}*/
6213
	{
6355
	{
6214
	expand_string_message = US"missing '{' for field arg of certextract";
6356
	expand_string_message = US"missing '{' for field arg of certextract";
6215
	goto EXPAND_FAILED_CURLY;
6357
	goto EXPAND_FAILED_CURLY;					/*}*/
6216
	}
6358
	}
6217
      sub[0] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
6359
      sub[0] = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
6218
      if (!sub[0])     goto EXPAND_FAILED;		/*{*/
6360
      if (!sub[0])     goto EXPAND_FAILED;				/*{{*/
6219
      if (*s++ != '}')
6361
      if (*s++ != '}')
6220
        {
6362
        {
6221
	expand_string_message = US"missing '}' closing field arg of certextract";
6363
	expand_string_message = US"missing '}' closing field arg of certextract";
Lines 6238-6244 Link Here
6238
      if (Uskip_whitespace(&s) != '{')					/*}*/
6380
      if (Uskip_whitespace(&s) != '{')					/*}*/
6239
	{
6381
	{
6240
	expand_string_message = US"missing '{' for cert variable arg of certextract";
6382
	expand_string_message = US"missing '{' for cert variable arg of certextract";
6241
	goto EXPAND_FAILED_CURLY;
6383
	goto EXPAND_FAILED_CURLY;					/*}*/
6242
	}
6384
	}
6243
      if (*++s != '$')
6385
      if (*++s != '$')
6244
        {
6386
        {
Lines 6247-6253 Link Here
6247
	goto EXPAND_FAILED;
6389
	goto EXPAND_FAILED;
6248
	}
6390
	}
6249
      sub[1] = expand_string_internal(s+1, TRUE, &s, skipping, FALSE, &resetok);
6391
      sub[1] = expand_string_internal(s+1, TRUE, &s, skipping, FALSE, &resetok);
6250
      if (!sub[1])     goto EXPAND_FAILED;		/*{*/
6392
      if (!sub[1])     goto EXPAND_FAILED;				/*{{*/
6251
      if (*s++ != '}')
6393
      if (*s++ != '}')
6252
        {
6394
        {
6253
	expand_string_message = US"missing '}' closing cert variable arg of certextract";
6395
	expand_string_message = US"missing '}' closing cert variable arg of certextract";
Lines 6276-6282 Link Here
6276
6418
6277
      restore_expand_strings(save_expand_nmax, save_expand_nstring,
6419
      restore_expand_strings(save_expand_nmax, save_expand_nstring,
6278
        save_expand_nlength);
6420
        save_expand_nlength);
6279
      continue;
6421
      if (skipping) continue;
6422
      break;
6280
      }
6423
      }
6281
#endif	/*DISABLE_TLS*/
6424
#endif	/*DISABLE_TLS*/
6282
6425
Lines 6286-6308 Link Here
6286
    case EITEM_MAP:
6429
    case EITEM_MAP:
6287
    case EITEM_REDUCE:
6430
    case EITEM_REDUCE:
6288
      {
6431
      {
6289
      int sep = 0;
6432
      int sep = 0, save_ptr = gstring_length(yield);
6290
      int save_ptr = gstring_length(yield);
6291
      uschar outsep[2] = { '\0', '\0' };
6433
      uschar outsep[2] = { '\0', '\0' };
6292
      const uschar *list, *expr, *temp;
6434
      const uschar *list, *expr, *temp;
6293
      uschar *save_iterate_item = iterate_item;
6435
      uschar * save_iterate_item = iterate_item;
6294
      uschar *save_lookup_value = lookup_value;
6436
      uschar * save_lookup_value = lookup_value;
6295
6437
6296
      Uskip_whitespace(&s);
6438
      Uskip_whitespace(&s);
6297
      if (*s++ != '{')
6439
      if (*s++ != '{')							/*}*/
6298
        {
6440
        {
6299
	expand_string_message =
6441
	expand_string_message =
6300
	  string_sprintf("missing '{' for first arg of %s", name);
6442
	  string_sprintf("missing '{' for first arg of %s", name);
6301
	goto EXPAND_FAILED_CURLY;
6443
	goto EXPAND_FAILED_CURLY;					/*}*/
6302
	}
6444
	}
6303
6445
6304
      if (!(list = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok)))
6446
      if (!(list = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok)))
6305
	goto EXPAND_FAILED;
6447
	goto EXPAND_FAILED;						/*{{*/
6306
      if (*s++ != '}')
6448
      if (*s++ != '}')
6307
        {
6449
        {
6308
	expand_string_message =
6450
	expand_string_message =
Lines 6314-6327 Link Here
6314
        {
6456
        {
6315
	uschar * t;
6457
	uschar * t;
6316
        Uskip_whitespace(&s);
6458
        Uskip_whitespace(&s);
6317
        if (*s++ != '{')
6459
        if (*s++ != '{')						/*}*/
6318
	  {
6460
	  {
6319
	  expand_string_message = US"missing '{' for second arg of reduce";
6461
	  expand_string_message = US"missing '{' for second arg of reduce";
6320
	  goto EXPAND_FAILED_CURLY;
6462
	  goto EXPAND_FAILED_CURLY;					/*}*/
6321
	  }
6463
	  }
6322
        t = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok);
6464
        t = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok);
6323
        if (!t) goto EXPAND_FAILED;
6465
        if (!t) goto EXPAND_FAILED;
6324
        lookup_value = t;
6466
        lookup_value = t;						/*{{*/
6325
        if (*s++ != '}')
6467
        if (*s++ != '}')
6326
	  {
6468
	  {
6327
	  expand_string_message = US"missing '}' closing second arg of reduce";
6469
	  expand_string_message = US"missing '}' closing second arg of reduce";
Lines 6330-6339 Link Here
6330
        }
6472
        }
6331
6473
6332
      Uskip_whitespace(&s);
6474
      Uskip_whitespace(&s);
6333
      if (*s++ != '{')
6475
      if (*s++ != '{')							/*}*/
6334
        {
6476
        {
6335
	expand_string_message =
6477
	expand_string_message =
6336
	  string_sprintf("missing '{' for last arg of %s", name);
6478
	  string_sprintf("missing '{' for last arg of %s", name);	/*}*/
6337
	goto EXPAND_FAILED_CURLY;
6479
	goto EXPAND_FAILED_CURLY;
6338
	}
6480
	}
6339
6481
Lines 6345-6357 Link Here
6345
      condition for real. For EITEM_MAP and EITEM_REDUCE, do the same, using
6487
      condition for real. For EITEM_MAP and EITEM_REDUCE, do the same, using
6346
      the normal internal expansion function. */
6488
      the normal internal expansion function. */
6347
6489
6348
      if (item_type == EITEM_FILTER)
6490
      if (item_type != EITEM_FILTER)
6349
        {
6350
        if ((temp = eval_condition(expr, &resetok, NULL)))
6351
	  s = temp;
6352
        }
6353
      else
6354
        temp = expand_string_internal(s, TRUE, &s, TRUE, TRUE, &resetok);
6491
        temp = expand_string_internal(s, TRUE, &s, TRUE, TRUE, &resetok);
6492
      else
6493
        if ((temp = eval_condition(expr, &resetok, NULL))) s = temp;
6355
6494
6356
      if (!temp)
6495
      if (!temp)
6357
        {
6496
        {
Lines 6360-6377 Link Here
6360
        goto EXPAND_FAILED;
6499
        goto EXPAND_FAILED;
6361
        }
6500
        }
6362
6501
6363
      Uskip_whitespace(&s);
6502
      Uskip_whitespace(&s);						/*{{{*/
6364
      if (*s++ != '}')
6503
      if (*s++ != '}')
6365
        {						/*{*/
6504
        {
6366
        expand_string_message = string_sprintf("missing } at end of condition "
6505
        expand_string_message = string_sprintf("missing } at end of condition "
6367
          "or expression inside \"%s\"; could be an unquoted } in the content",
6506
          "or expression inside \"%s\"; could be an unquoted } in the content",
6368
	  name);
6507
	  name);
6369
        goto EXPAND_FAILED;
6508
        goto EXPAND_FAILED;
6370
        }
6509
        }
6371
6510
6372
      Uskip_whitespace(&s);				/*{*/
6511
      Uskip_whitespace(&s);						/*{{*/
6373
      if (*s++ != '}')
6512
      if (*s++ != '}')
6374
        {						/*{*/
6513
        {
6375
        expand_string_message = string_sprintf("missing } at end of \"%s\"",
6514
        expand_string_message = string_sprintf("missing } at end of \"%s\"",
6376
          name);
6515
          name);
6377
        goto EXPAND_FAILED;
6516
        goto EXPAND_FAILED;
Lines 6434-6439 Link Here
6434
        item of the output list, add in a space if the new item begins with the
6573
        item of the output list, add in a space if the new item begins with the
6435
        separator character, or is an empty string. */
6574
        separator character, or is an empty string. */
6436
6575
6576
/*XXX is there not a standard support function for this, appending to a list? */
6577
/* yes, string_append_listele(), but it depends on lack of text before the list */
6578
6437
        if (  yield && yield->ptr != save_ptr
6579
        if (  yield && yield->ptr != save_ptr
6438
	   && (temp[0] == *outsep || temp[0] == 0))
6580
	   && (temp[0] == *outsep || temp[0] == 0))
6439
          yield = string_catn(yield, US" ", 1);
6581
          yield = string_catn(yield, US" ", 1);
Lines 6451-6457 Link Here
6451
          too many; backup and end the loop. Otherwise arrange to double the
6593
          too many; backup and end the loop. Otherwise arrange to double the
6452
          separator. */
6594
          separator. */
6453
6595
6454
          if (temp[seglen] == '\0') { yield->ptr--; break; }
6596
          if (!temp[seglen]) { yield->ptr--; break; }
6455
          yield = string_catn(yield, outsep, 1);
6597
          yield = string_catn(yield, outsep, 1);
6456
          temp += seglen + 1;
6598
          temp += seglen + 1;
6457
          }
6599
          }
Lines 6480-6507 Link Here
6480
      /* Restore preserved $item */
6622
      /* Restore preserved $item */
6481
6623
6482
      iterate_item = save_iterate_item;
6624
      iterate_item = save_iterate_item;
6483
      continue;
6625
      if (skipping) continue;
6626
      break;
6484
      }
6627
      }
6485
6628
6486
    case EITEM_SORT:
6629
    case EITEM_SORT:
6487
      {
6630
      {
6488
      int cond_type;
6631
      int sep = 0, cond_type;
6489
      int sep = 0;
6632
      const uschar * srclist, * cmp, * xtract;
6490
      const uschar *srclist, *cmp, *xtract;
6491
      uschar * opname, * srcitem;
6633
      uschar * opname, * srcitem;
6492
      const uschar *dstlist = NULL, *dstkeylist = NULL;
6634
      const uschar * dstlist = NULL, * dstkeylist = NULL;
6493
      uschar * tmp;
6635
      uschar * tmp, * save_iterate_item = iterate_item;
6494
      uschar *save_iterate_item = iterate_item;
6495
6636
6496
      Uskip_whitespace(&s);
6637
      Uskip_whitespace(&s);
6497
      if (*s++ != '{')
6638
      if (*s++ != '{')							/*}*/
6498
        {
6639
        {
6499
        expand_string_message = US"missing '{' for list arg of sort";
6640
        expand_string_message = US"missing '{' for list arg of sort";
6500
	goto EXPAND_FAILED_CURLY;
6641
	goto EXPAND_FAILED_CURLY;					/*}*/
6501
	}
6642
	}
6502
6643
6503
      srclist = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok);
6644
      srclist = expand_string_internal(s, TRUE, &s, skipping, TRUE, &resetok);
6504
      if (!srclist) goto EXPAND_FAILED;
6645
      if (!srclist) goto EXPAND_FAILED;					/*{{*/
6505
      if (*s++ != '}')
6646
      if (*s++ != '}')
6506
        {
6647
        {
6507
        expand_string_message = US"missing '}' closing list arg of sort";
6648
        expand_string_message = US"missing '}' closing list arg of sort";
Lines 6509-6522 Link Here
6509
	}
6650
	}
6510
6651
6511
      Uskip_whitespace(&s);
6652
      Uskip_whitespace(&s);
6512
      if (*s++ != '{')
6653
      if (*s++ != '{')							/*}*/
6513
        {
6654
        {
6514
        expand_string_message = US"missing '{' for comparator arg of sort";
6655
        expand_string_message = US"missing '{' for comparator arg of sort";
6515
	goto EXPAND_FAILED_CURLY;
6656
	goto EXPAND_FAILED_CURLY;					/*}*/
6516
	}
6657
	}
6517
6658
6518
      cmp = expand_string_internal(s, TRUE, &s, skipping, FALSE, &resetok);
6659
      cmp = expand_string_internal(s, TRUE, &s, skipping, FALSE, &resetok);
6519
      if (!cmp) goto EXPAND_FAILED;
6660
      if (!cmp) goto EXPAND_FAILED;					/*{{*/
6520
      if (*s++ != '}')
6661
      if (*s++ != '}')
6521
        {
6662
        {
6522
        expand_string_message = US"missing '}' closing comparator arg of sort";
6663
        expand_string_message = US"missing '}' closing comparator arg of sort";
Lines 6543-6567 Link Here
6543
	}
6684
	}
6544
6685
6545
      Uskip_whitespace(&s);
6686
      Uskip_whitespace(&s);
6546
      if (*s++ != '{')
6687
      if (*s++ != '{')							/*}*/
6547
        {
6688
        {
6548
        expand_string_message = US"missing '{' for extractor arg of sort";
6689
        expand_string_message = US"missing '{' for extractor arg of sort";
6549
	goto EXPAND_FAILED_CURLY;
6690
	goto EXPAND_FAILED_CURLY;					/*}*/
6550
	}
6691
	}
6551
6692
6552
      xtract = s;
6693
      xtract = s;
6553
      if (!(tmp = expand_string_internal(s, TRUE, &s, TRUE, TRUE, &resetok)))
6694
      if (!(tmp = expand_string_internal(s, TRUE, &s, TRUE, TRUE, &resetok)))
6554
	goto EXPAND_FAILED;
6695
	goto EXPAND_FAILED;
6555
      xtract = string_copyn(xtract, s - xtract);
6696
      xtract = string_copyn(xtract, s - xtract);
6556
6697
									/*{{*/
6557
      if (*s++ != '}')
6698
      if (*s++ != '}')
6558
        {
6699
        {
6559
        expand_string_message = US"missing '}' closing extractor arg of sort";
6700
        expand_string_message = US"missing '}' closing extractor arg of sort";
6560
	goto EXPAND_FAILED_CURLY;
6701
	goto EXPAND_FAILED_CURLY;
6561
	}
6702
	}
6562
							/*{*/
6703
									/*{{*/
6563
      if (*s++ != '}')
6704
      if (*s++ != '}')
6564
        {						/*{*/
6705
        {
6565
        expand_string_message = US"missing } at end of \"sort\"";
6706
        expand_string_message = US"missing } at end of \"sort\"";
6566
        goto EXPAND_FAILED;
6707
        goto EXPAND_FAILED;
6567
        }
6708
        }
Lines 6571-6578 Link Here
6571
      while ((srcitem = string_nextinlist(&srclist, &sep, NULL, 0)))
6712
      while ((srcitem = string_nextinlist(&srclist, &sep, NULL, 0)))
6572
	{
6713
	{
6573
	uschar * srcfield, * dstitem;
6714
	uschar * srcfield, * dstitem;
6574
	gstring * newlist = NULL;
6715
	gstring * newlist = NULL, * newkeylist = NULL;
6575
	gstring * newkeylist = NULL;
6576
6716
6577
        DEBUG(D_expand) debug_printf_indent("%s: $item = \"%s\"\n", name, srcitem);
6717
        DEBUG(D_expand) debug_printf_indent("%s: $item = \"%s\"\n", name, srcitem);
6578
6718
Lines 6596-6602 Link Here
6596
6736
6597
	  /* field for comparison */
6737
	  /* field for comparison */
6598
	  if (!(dstfield = string_nextinlist(&dstkeylist, &sep, NULL, 0)))
6738
	  if (!(dstfield = string_nextinlist(&dstkeylist, &sep, NULL, 0)))
6599
	    goto sort_mismatch;
6739
	    goto SORT_MISMATCH;
6600
6740
6601
	  /* String-comparator names start with a letter; numeric names do not */
6741
	  /* String-comparator names start with a letter; numeric names do not */
6602
6742
Lines 6617-6623 Link Here
6617
	    while ((dstitem = string_nextinlist(&dstlist, &sep, NULL, 0)))
6757
	    while ((dstitem = string_nextinlist(&dstlist, &sep, NULL, 0)))
6618
	      {
6758
	      {
6619
	      if (!(dstfield = string_nextinlist(&dstkeylist, &sep, NULL, 0)))
6759
	      if (!(dstfield = string_nextinlist(&dstkeylist, &sep, NULL, 0)))
6620
		goto sort_mismatch;
6760
		goto SORT_MISMATCH;
6621
	      newlist = string_append_listele(newlist, sep, dstitem);
6761
	      newlist = string_append_listele(newlist, sep, dstitem);
6622
	      newkeylist = string_append_listele(newkeylist, sep, dstfield);
6762
	      newkeylist = string_append_listele(newkeylist, sep, dstfield);
6623
	      }
6763
	      }
Lines 6648-6656 Link Here
6648
6788
6649
      /* Restore preserved $item */
6789
      /* Restore preserved $item */
6650
      iterate_item = save_iterate_item;
6790
      iterate_item = save_iterate_item;
6651
      continue;
6791
      break;
6652
6792
6653
      sort_mismatch:
6793
      SORT_MISMATCH:
6654
	expand_string_message = US"Internal error in sort (list mismatch)";
6794
	expand_string_message = US"Internal error in sort (list mismatch)";
6655
	goto EXPAND_FAILED;
6795
	goto EXPAND_FAILED;
6656
      }
6796
      }
Lines 6671-6683 Link Here
6671
6811
6672
#else   /* EXPAND_DLFUNC */
6812
#else   /* EXPAND_DLFUNC */
6673
      {
6813
      {
6674
      tree_node *t;
6814
      tree_node * t;
6675
      exim_dlfunc_t *func;
6815
      exim_dlfunc_t * func;
6676
      uschar *result;
6816
      uschar * result;
6677
      int status, argc;
6817
      int status, argc;
6678
      uschar *argv[EXPAND_DLFUNC_MAX_ARGS + 3];
6818
      uschar * argv[EXPAND_DLFUNC_MAX_ARGS + 3];
6679
6819
6680
      if ((expand_forbid & RDO_DLFUNC) != 0)
6820
      if (expand_forbid & RDO_DLFUNC)
6681
        {
6821
        {
6682
        expand_string_message =
6822
        expand_string_message =
6683
          US"dynamically-loaded functions are not permitted";
6823
          US"dynamically-loaded functions are not permitted";
Lines 6701-6707 Link Here
6701
6841
6702
      if (!(t = tree_search(dlobj_anchor, argv[0])))
6842
      if (!(t = tree_search(dlobj_anchor, argv[0])))
6703
        {
6843
        {
6704
        void *handle = dlopen(CS argv[0], RTLD_LAZY);
6844
        void * handle = dlopen(CS argv[0], RTLD_LAZY);
6705
        if (!handle)
6845
        if (!handle)
6706
          {
6846
          {
6707
          expand_string_message = string_sprintf("dlopen \"%s\" failed: %s",
6847
          expand_string_message = string_sprintf("dlopen \"%s\" failed: %s",
Lines 6709-6715 Link Here
6709
          log_write(0, LOG_MAIN|LOG_PANIC, "%s", expand_string_message);
6849
          log_write(0, LOG_MAIN|LOG_PANIC, "%s", expand_string_message);
6710
          goto EXPAND_FAILED;
6850
          goto EXPAND_FAILED;
6711
          }
6851
          }
6712
        t = store_get_perm(sizeof(tree_node) + Ustrlen(argv[0]), is_tainted(argv[0]));
6852
        t = store_get_perm(sizeof(tree_node) + Ustrlen(argv[0]), argv[0]);
6713
        Ustrcpy(t->name, argv[0]);
6853
        Ustrcpy(t->name, argv[0]);
6714
        t->data.ptr = handle;
6854
        t->data.ptr = handle;
6715
        (void)tree_insertnode(&dlobj_anchor, t);
6855
        (void)tree_insertnode(&dlobj_anchor, t);
Lines 6735-6749 Link Here
6735
6875
6736
      resetok = FALSE;
6876
      resetok = FALSE;
6737
      result = NULL;
6877
      result = NULL;
6738
      for (argc = 0; argv[argc]; argc++);
6878
      for (argc = 0; argv[argc]; argc++) ;
6739
      status = func(&result, argc - 2, &argv[2]);
6879
6740
      if(status == OK)
6880
      if ((status = func(&result, argc - 2, &argv[2])) != OK)
6741
        {
6742
        if (!result) result = US"";
6743
        yield = string_cat(yield, result);
6744
        continue;
6745
        }
6746
      else
6747
        {
6881
        {
6748
        expand_string_message = result ? result : US"(no message)";
6882
        expand_string_message = result ? result : US"(no message)";
6749
        if (status == FAIL_FORCED)
6883
        if (status == FAIL_FORCED)
Lines 6753-6758 Link Here
6753
              argv[0], argv[1], status, expand_string_message);
6887
              argv[0], argv[1], status, expand_string_message);
6754
        goto EXPAND_FAILED;
6888
        goto EXPAND_FAILED;
6755
        }
6889
        }
6890
6891
      if (result) yield = string_cat(yield, result);
6892
      break;
6756
      }
6893
      }
6757
#endif /* EXPAND_DLFUNC */
6894
#endif /* EXPAND_DLFUNC */
6758
6895
Lines 6765-6774 Link Here
6765
	goto EXPAND_FAILED;
6902
	goto EXPAND_FAILED;
6766
6903
6767
      key = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
6904
      key = expand_string_internal(s+1, TRUE, &s, skipping, TRUE, &resetok);
6768
      if (!key) goto EXPAND_FAILED;			/*{*/
6905
      if (!key) goto EXPAND_FAILED;					/*{{*/
6769
      if (*s++ != '}')
6906
      if (*s++ != '}')
6770
        {
6907
        {
6771
        expand_string_message = US"missing '{' for name arg of env";
6908
        expand_string_message = US"missing '}' for name arg of env";
6772
	goto EXPAND_FAILED_CURLY;
6909
	goto EXPAND_FAILED_CURLY;
6773
	}
6910
	}
6774
6911
Lines 6786-6800 Link Here
6786
        case 1: goto EXPAND_FAILED;          /* when all is well, the */
6923
        case 1: goto EXPAND_FAILED;          /* when all is well, the */
6787
        case 2: goto EXPAND_FAILED_CURLY;    /* returned value is 0 */
6924
        case 2: goto EXPAND_FAILED_CURLY;    /* returned value is 0 */
6788
        }
6925
        }
6789
      continue;
6926
      if (skipping) continue;
6927
      break;
6790
      }
6928
      }
6791
6929
6792
#ifdef EXPERIMENTAL_SRS_NATIVE
6930
#ifdef SUPPORT_SRS
6793
    case EITEM_SRS_ENCODE:
6931
    case EITEM_SRS_ENCODE:
6794
      /* ${srs_encode {secret} {return_path} {orig_domain}} */
6932
      /* ${srs_encode {secret} {return_path} {orig_domain}} */
6795
      {
6933
      {
6796
      uschar * sub[3];
6934
      uschar * sub[3];
6797
      uschar cksum[4];
6935
      uschar cksum[4];
6936
      gstring * g = NULL;
6937
      BOOL quoted = FALSE;
6798
6938
6799
      switch (read_subs(sub, 3, 3, CUSS &s, skipping, TRUE, name, &resetok))
6939
      switch (read_subs(sub, 3, 3, CUSS &s, skipping, TRUE, name, &resetok))
6800
        {
6940
        {
Lines 6802-6850 Link Here
6802
        case 2:
6942
        case 2:
6803
        case 3: goto EXPAND_FAILED;
6943
        case 3: goto EXPAND_FAILED;
6804
        }
6944
        }
6945
      if (skipping) continue;
6805
6946
6806
      yield = string_catn(yield, US"SRS0=", 5);
6947
      if (sub[1] && *(sub[1]))
6948
	{
6949
	g = string_catn(g, US"SRS0=", 5);
6807
6950
6808
      /* ${l_4:${hmac{md5}{SRS_SECRET}{${lc:$return_path}}}}= */
6951
	/* ${l_4:${hmac{md5}{SRS_SECRET}{${lc:$return_path}}}}= */
6809
      hmac_md5(sub[0], string_copylc(sub[1]), cksum, sizeof(cksum));
6952
	hmac_md5(sub[0], string_copylc(sub[1]), cksum, sizeof(cksum));
6810
      yield = string_catn(yield, cksum, sizeof(cksum));
6953
	g = string_catn(g, cksum, sizeof(cksum));
6811
      yield = string_catn(yield, US"=", 1);
6954
	g = string_catn(g, US"=", 1);
6812
6955
6813
      /* ${base32:${eval:$tod_epoch/86400&0x3ff}}= */
6956
	/* ${base32:${eval:$tod_epoch/86400&0x3ff}}= */
6814
	{
6957
	  {
6815
	struct timeval now;
6958
	  struct timeval now;
6816
	unsigned long i;
6959
	  unsigned long i;
6817
	gstring * g = NULL;
6960
	  gstring * h = NULL;
6818
6961
6819
	gettimeofday(&now, NULL);
6962
	  gettimeofday(&now, NULL);
6820
	for (unsigned long i = (now.tv_sec / 86400) & 0x3ff; i; i >>= 5)
6963
	  for (unsigned long i = (now.tv_sec / 86400) & 0x3ff; i; i >>= 5)
6821
	  g = string_catn(g, &base32_chars[i & 0x1f], 1);
6964
	    h = string_catn(h, &base32_chars[i & 0x1f], 1);
6822
	if (g) while (g->ptr > 0)
6965
	  if (h) while (h->ptr > 0)
6823
	  yield = string_catn(yield, &g->s[--g->ptr], 1);
6966
	    g = string_catn(g, &h->s[--h->ptr], 1);
6824
	}
6967
	  }
6825
      yield = string_catn(yield, US"=", 1);
6968
	g = string_catn(g, US"=", 1);
6826
6969
6827
      /* ${domain:$return_path}=${local_part:$return_path} */
6970
	/* ${domain:$return_path}=${local_part:$return_path} */
6828
	{
6971
	  {
6829
        int start, end, domain;
6972
	  int start, end, domain;
6830
        uschar * t = parse_extract_address(sub[1], &expand_string_message,
6973
	  uschar * t = parse_extract_address(sub[1], &expand_string_message,
6831
					  &start, &end, &domain, FALSE);
6974
					    &start, &end, &domain, FALSE);
6832
        if (!t)
6975
	  uschar * s;
6833
	  goto EXPAND_FAILED;
6834
6976
6835
	if (domain > 0) yield = string_cat(yield, t + domain);
6977
	  if (!t)
6836
	yield = string_catn(yield, US"=", 1);
6978
	    goto EXPAND_FAILED;
6837
	yield = domain > 0
6838
	  ? string_catn(yield, t, domain - 1) : string_cat(yield, t);
6839
        }
6840
6979
6841
      /* @$original_domain */
6980
	  if (domain > 0) g = string_cat(g, t + domain);
6842
      yield = string_catn(yield, US"@", 1);
6981
	  g = string_catn(g, US"=", 1);
6843
      yield = string_cat(yield, sub[2]);
6982
6844
      continue;
6983
	  s = domain > 0 ? string_copyn(t, domain - 1) : t;
6984
	  if ((quoted = Ustrchr(s, '"') != NULL))
6985
	    {
6986
	    gstring * h = NULL;
6987
	    DEBUG(D_expand) debug_printf_indent("auto-quoting local part\n");
6988
	    while (*s)		/* de-quote */
6989
	      {
6990
	      while (*s && *s != '"') h = string_catn(h, s++, 1);
6991
	      if (*s) s++;
6992
	      while (*s && *s != '"') h = string_catn(h, s++, 1);
6993
	      if (*s) s++;
6994
	      }
6995
	    gstring_release_unused(h);
6996
	    s = string_from_gstring(h);
6997
	    }
6998
	  g = string_cat(g, s);
6999
	  }
7000
7001
	/* Assume that if the original local_part had quotes
7002
	it was for good reason */
7003
7004
	if (quoted) yield = string_catn(yield, US"\"", 1);
7005
	yield = string_catn(yield, g->s, g->ptr);
7006
	if (quoted) yield = string_catn(yield, US"\"", 1);
7007
7008
	/* @$original_domain */
7009
	yield = string_catn(yield, US"@", 1);
7010
	yield = string_cat(yield, sub[2]);
7011
	}
7012
      else
7013
	DEBUG(D_expand) debug_printf_indent("null return_path for srs-encode\n");
7014
7015
      break;
6845
      }
7016
      }
6846
#endif /*EXPERIMENTAL_SRS_NATIVE*/
7017
#endif /*SUPPORT_SRS*/
7018
7019
    default:
7020
      goto NOT_ITEM;
6847
    }	/* EITEM_* switch */
7021
    }	/* EITEM_* switch */
7022
    /*NOTREACHED*/
7023
7024
  DEBUG(D_expand)
7025
    if (yield && (start > 0 || *s))	/* only if not the sole expansion of the line */
7026
      debug_expansion_interim(US"item-res",
7027
			      yield->s + start, yield->ptr - start, skipping);
7028
  continue;
7029
7030
NOT_ITEM: ;
7031
  }
6848
7032
6849
  /* Control reaches here if the name is not recognized as one of the more
7033
  /* Control reaches here if the name is not recognized as one of the more
6850
  complicated expansion items. Check for the "operator" syntax (name terminated
7034
  complicated expansion items. Check for the "operator" syntax (name terminated
Lines 6854-6863 Link Here
6854
  if (*s == ':')
7038
  if (*s == ':')
6855
    {
7039
    {
6856
    int c;
7040
    int c;
6857
    uschar *arg = NULL;
7041
    uschar * arg = NULL, * sub;
6858
    uschar *sub;
6859
#ifndef DISABLE_TLS
7042
#ifndef DISABLE_TLS
6860
    var_entry *vp = NULL;
7043
    var_entry * vp = NULL;
6861
#endif
7044
#endif
6862
7045
6863
    /* Owing to an historical mis-design, an underscore may be part of the
7046
    /* Owing to an historical mis-design, an underscore may be part of the
Lines 6891-6897 Link Here
6891
		  FALSE, &resetok);
7074
		  FALSE, &resetok);
6892
	  if (!sub)       goto EXPAND_FAILED;		/*{*/
7075
	  if (!sub)       goto EXPAND_FAILED;		/*{*/
6893
	  if (*s1 != '}')
7076
	  if (*s1 != '}')
6894
	    {
7077
	    {						/*{*/
6895
	    expand_string_message =
7078
	    expand_string_message =
6896
	      string_sprintf("missing '}' closing cert arg of %s", name);
7079
	      string_sprintf("missing '}' closing cert arg of %s", name);
6897
	    goto EXPAND_FAILED_CURLY;
7080
	    goto EXPAND_FAILED_CURLY;
Lines 6920-7048 Link Here
6920
7103
6921
    if (skipping && c >= 0) continue;
7104
    if (skipping && c >= 0) continue;
6922
7105
6923
    /* Otherwise, switch on the operator type */
7106
    /* Otherwise, switch on the operator type.  After handling go back
7107
    to the main loop top. */
6924
7108
6925
    switch(c)
7109
     {
7110
     int start = yield->ptr;
7111
     switch(c)
6926
      {
7112
      {
6927
      case EOP_BASE32:
7113
      case EOP_BASE32:
6928
	{
7114
	{
6929
        uschar *t;
7115
	uschar *t;
6930
        unsigned long int n = Ustrtoul(sub, &t, 10);
7116
	unsigned long int n = Ustrtoul(sub, &t, 10);
6931
	gstring * g = NULL;
7117
	gstring * g = NULL;
6932
7118
6933
        if (*t != 0)
7119
	if (*t != 0)
6934
          {
7120
	  {
6935
          expand_string_message = string_sprintf("argument for base32 "
7121
	  expand_string_message = string_sprintf("argument for base32 "
6936
            "operator is \"%s\", which is not a decimal number", sub);
7122
	    "operator is \"%s\", which is not a decimal number", sub);
6937
          goto EXPAND_FAILED;
7123
	  goto EXPAND_FAILED;
6938
          }
7124
	  }
6939
	for ( ; n; n >>= 5)
7125
	for ( ; n; n >>= 5)
6940
	  g = string_catn(g, &base32_chars[n & 0x1f], 1);
7126
	  g = string_catn(g, &base32_chars[n & 0x1f], 1);
6941
7127
6942
	if (g) while (g->ptr > 0) yield = string_catn(yield, &g->s[--g->ptr], 1);
7128
	if (g) while (g->ptr > 0) yield = string_catn(yield, &g->s[--g->ptr], 1);
6943
	continue;
7129
	break;
6944
	}
7130
	}
6945
7131
6946
      case EOP_BASE32D:
7132
      case EOP_BASE32D:
6947
        {
7133
	{
6948
        uschar *tt = sub;
7134
	uschar *tt = sub;
6949
        unsigned long int n = 0;
7135
	unsigned long int n = 0;
6950
        while (*tt)
7136
	while (*tt)
6951
          {
7137
	  {
6952
          uschar * t = Ustrchr(base32_chars, *tt++);
7138
	  uschar * t = Ustrchr(base32_chars, *tt++);
6953
          if (!t)
7139
	  if (!t)
6954
            {
7140
	    {
6955
            expand_string_message = string_sprintf("argument for base32d "
7141
	    expand_string_message = string_sprintf("argument for base32d "
6956
              "operator is \"%s\", which is not a base 32 number", sub);
7142
	      "operator is \"%s\", which is not a base 32 number", sub);
6957
            goto EXPAND_FAILED;
7143
	    goto EXPAND_FAILED;
6958
            }
7144
	    }
6959
          n = n * 32 + (t - base32_chars);
7145
	  n = n * 32 + (t - base32_chars);
6960
          }
7146
	  }
6961
        yield = string_fmt_append(yield, "%ld", n);
7147
	yield = string_fmt_append(yield, "%ld", n);
6962
        continue;
7148
	break;
6963
        }
7149
	}
6964
7150
6965
      case EOP_BASE62:
7151
      case EOP_BASE62:
6966
        {
7152
	{
6967
        uschar *t;
7153
	uschar *t;
6968
        unsigned long int n = Ustrtoul(sub, &t, 10);
7154
	unsigned long int n = Ustrtoul(sub, &t, 10);
6969
        if (*t != 0)
7155
	if (*t != 0)
6970
          {
7156
	  {
6971
          expand_string_message = string_sprintf("argument for base62 "
7157
	  expand_string_message = string_sprintf("argument for base62 "
6972
            "operator is \"%s\", which is not a decimal number", sub);
7158
	    "operator is \"%s\", which is not a decimal number", sub);
6973
          goto EXPAND_FAILED;
7159
	  goto EXPAND_FAILED;
6974
          }
7160
	  }
6975
        yield = string_cat(yield, string_base62(n));
7161
	yield = string_cat(yield, string_base62(n));
6976
        continue;
7162
	break;
6977
        }
7163
	}
6978
7164
6979
      /* Note that for Darwin and Cygwin, BASE_62 actually has the value 36 */
7165
      /* Note that for Darwin and Cygwin, BASE_62 actually has the value 36 */
6980
7166
6981
      case EOP_BASE62D:
7167
      case EOP_BASE62D:
6982
        {
7168
	{
6983
        uschar *tt = sub;
7169
	uschar *tt = sub;
6984
        unsigned long int n = 0;
7170
	unsigned long int n = 0;
6985
        while (*tt != 0)
7171
	while (*tt != 0)
6986
          {
6987
          uschar *t = Ustrchr(base62_chars, *tt++);
6988
          if (!t)
6989
            {
6990
            expand_string_message = string_sprintf("argument for base62d "
6991
              "operator is \"%s\", which is not a base %d number", sub,
6992
              BASE_62);
6993
            goto EXPAND_FAILED;
6994
            }
6995
          n = n * BASE_62 + (t - base62_chars);
6996
          }
6997
        yield = string_fmt_append(yield, "%ld", n);
6998
        continue;
6999
        }
7000
7001
      case EOP_BLESS:
7002
	/* This is purely for the convenience of the test harness.  Do not enable
7003
	it otherwise as it defeats the taint-checking security. */
7004
7005
	if (f.running_in_test_harness)
7006
	  yield = string_cat(yield, is_tainted(sub)
7007
				    ? string_copy_taint(sub, FALSE) : sub);
7008
	else
7009
	  {
7172
	  {
7010
	  DEBUG(D_expand) debug_printf_indent("bless operator not supported\n");
7173
	  uschar *t = Ustrchr(base62_chars, *tt++);
7011
	  yield = string_cat(yield, sub);
7174
	  if (!t)
7175
	    {
7176
	    expand_string_message = string_sprintf("argument for base62d "
7177
	      "operator is \"%s\", which is not a base %d number", sub,
7178
	      BASE_62);
7179
	    goto EXPAND_FAILED;
7180
	    }
7181
	  n = n * BASE_62 + (t - base62_chars);
7012
	  }
7182
	  }
7013
	continue;
7183
	yield = string_fmt_append(yield, "%ld", n);
7184
	break;
7185
	}
7014
7186
7015
      case EOP_EXPAND:
7187
      case EOP_EXPAND:
7016
        {
7188
	{
7017
        uschar *expanded = expand_string_internal(sub, FALSE, NULL, skipping, TRUE, &resetok);
7189
	uschar *expanded = expand_string_internal(sub, FALSE, NULL, skipping, TRUE, &resetok);
7018
        if (!expanded)
7190
	if (!expanded)
7019
          {
7191
	  {
7020
          expand_string_message =
7192
	  expand_string_message =
7021
            string_sprintf("internal expansion of \"%s\" failed: %s", sub,
7193
	    string_sprintf("internal expansion of \"%s\" failed: %s", sub,
7022
              expand_string_message);
7194
	      expand_string_message);
7023
          goto EXPAND_FAILED;
7195
	  goto EXPAND_FAILED;
7024
          }
7196
	  }
7025
        yield = string_cat(yield, expanded);
7197
	yield = string_cat(yield, expanded);
7026
        continue;
7198
	break;
7027
        }
7199
	}
7028
7200
7029
      case EOP_LC:
7201
      case EOP_LC:
7030
        {
7202
	{
7031
        int count = 0;
7203
	int count = 0;
7032
        uschar *t = sub - 1;
7204
	uschar *t = sub - 1;
7033
        while (*(++t) != 0) { *t = tolower(*t); count++; }
7205
	while (*(++t) != 0) { *t = tolower(*t); count++; }
7034
        yield = string_catn(yield, sub, count);
7206
	yield = string_catn(yield, sub, count);
7035
        continue;
7207
	break;
7036
        }
7208
	}
7037
7209
7038
      case EOP_UC:
7210
      case EOP_UC:
7039
        {
7211
	{
7040
        int count = 0;
7212
	int count = 0;
7041
        uschar *t = sub - 1;
7213
	uschar *t = sub - 1;
7042
        while (*(++t) != 0) { *t = toupper(*t); count++; }
7214
	while (*(++t) != 0) { *t = toupper(*t); count++; }
7043
        yield = string_catn(yield, sub, count);
7215
	yield = string_catn(yield, sub, count);
7044
        continue;
7216
	break;
7045
        }
7217
	}
7046
7218
7047
      case EOP_MD5:
7219
      case EOP_MD5:
7048
#ifndef DISABLE_TLS
7220
#ifndef DISABLE_TLS
Lines 7061-7067 Link Here
7061
	  for (int j = 0; j < 16; j++)
7233
	  for (int j = 0; j < 16; j++)
7062
	    yield = string_fmt_append(yield, "%02x", digest[j]);
7234
	    yield = string_fmt_append(yield, "%02x", digest[j]);
7063
	  }
7235
	  }
7064
        continue;
7236
	break;
7065
7237
7066
      case EOP_SHA1:
7238
      case EOP_SHA1:
7067
#ifndef DISABLE_TLS
7239
#ifndef DISABLE_TLS
Lines 7080-7086 Link Here
7080
	  for (int j = 0; j < 20; j++)
7252
	  for (int j = 0; j < 20; j++)
7081
	    yield = string_fmt_append(yield, "%02X", digest[j]);
7253
	    yield = string_fmt_append(yield, "%02X", digest[j]);
7082
	  }
7254
	  }
7083
        continue;
7255
	break;
7084
7256
7085
      case EOP_SHA2:
7257
      case EOP_SHA2:
7086
      case EOP_SHA256:
7258
      case EOP_SHA256:
Lines 7106-7112 Link Here
7106
	    goto EXPAND_FAILED;
7278
	    goto EXPAND_FAILED;
7107
	    }
7279
	    }
7108
7280
7109
	  exim_sha_update(&h, sub, Ustrlen(sub));
7281
	  exim_sha_update_string(&h, sub);
7110
	  exim_sha_finish(&h, &b);
7282
	  exim_sha_finish(&h, &b);
7111
	  while (b.len-- > 0)
7283
	  while (b.len-- > 0)
7112
	    yield = string_fmt_append(yield, "%02X", *b.data++);
7284
	    yield = string_fmt_append(yield, "%02X", *b.data++);
Lines 7114-7120 Link Here
7114
#else
7286
#else
7115
	  expand_string_message = US"sha256 only supported with TLS";
7287
	  expand_string_message = US"sha256 only supported with TLS";
7116
#endif
7288
#endif
7117
        continue;
7289
	break;
7118
7290
7119
      case EOP_SHA3:
7291
      case EOP_SHA3:
7120
#ifdef EXIM_HAVE_SHA3
7292
#ifdef EXIM_HAVE_SHA3
Lines 7134-7145 Link Here
7134
	  goto EXPAND_FAILED;
7306
	  goto EXPAND_FAILED;
7135
	  }
7307
	  }
7136
7308
7137
	exim_sha_update(&h, sub, Ustrlen(sub));
7309
	exim_sha_update_string(&h, sub);
7138
	exim_sha_finish(&h, &b);
7310
	exim_sha_finish(&h, &b);
7139
	while (b.len-- > 0)
7311
	while (b.len-- > 0)
7140
	  yield = string_fmt_append(yield, "%02X", *b.data++);
7312
	  yield = string_fmt_append(yield, "%02X", *b.data++);
7141
	}
7313
	}
7142
        continue;
7314
	break;
7143
#else
7315
#else
7144
	expand_string_message = US"sha3 only supported with GnuTLS 3.5.0 + or OpenSSL 1.1.1 +";
7316
	expand_string_message = US"sha3 only supported with GnuTLS 3.5.0 + or OpenSSL 1.1.1 +";
7145
	goto EXPAND_FAILED;
7317
	goto EXPAND_FAILED;
Lines 7148-7307 Link Here
7148
      /* Convert hex encoding to base64 encoding */
7320
      /* Convert hex encoding to base64 encoding */
7149
7321
7150
      case EOP_HEX2B64:
7322
      case EOP_HEX2B64:
7151
        {
7323
	{
7152
        int c = 0;
7324
	int c = 0;
7153
        int b = -1;
7325
	int b = -1;
7154
        uschar *in = sub;
7326
	uschar *in = sub;
7155
        uschar *out = sub;
7327
	uschar *out = sub;
7156
        uschar *enc;
7328
	uschar *enc;
7157
7329
7158
        for (enc = sub; *enc; enc++)
7330
	for (enc = sub; *enc; enc++)
7159
          {
7331
	  {
7160
          if (!isxdigit(*enc))
7332
	  if (!isxdigit(*enc))
7161
            {
7333
	    {
7162
            expand_string_message = string_sprintf("\"%s\" is not a hex "
7334
	    expand_string_message = string_sprintf("\"%s\" is not a hex "
7163
              "string", sub);
7335
	      "string", sub);
7164
            goto EXPAND_FAILED;
7336
	    goto EXPAND_FAILED;
7165
            }
7337
	    }
7166
          c++;
7338
	  c++;
7167
          }
7339
	  }
7168
7340
7169
        if ((c & 1) != 0)
7341
	if ((c & 1) != 0)
7170
          {
7342
	  {
7171
          expand_string_message = string_sprintf("\"%s\" contains an odd "
7343
	  expand_string_message = string_sprintf("\"%s\" contains an odd "
7172
            "number of characters", sub);
7344
	    "number of characters", sub);
7173
          goto EXPAND_FAILED;
7345
	  goto EXPAND_FAILED;
7174
          }
7346
	  }
7175
7347
7176
        while ((c = *in++) != 0)
7348
	while ((c = *in++) != 0)
7177
          {
7349
	  {
7178
          if (isdigit(c)) c -= '0';
7350
	  if (isdigit(c)) c -= '0';
7179
          else c = toupper(c) - 'A' + 10;
7351
	  else c = toupper(c) - 'A' + 10;
7180
          if (b == -1)
7352
	  if (b == -1)
7181
            b = c << 4;
7353
	    b = c << 4;
7182
          else
7354
	  else
7183
            {
7355
	    {
7184
            *out++ = b | c;
7356
	    *out++ = b | c;
7185
            b = -1;
7357
	    b = -1;
7186
            }
7358
	    }
7187
          }
7359
	  }
7188
7360
7189
        enc = b64encode(CUS sub, out - sub);
7361
	enc = b64encode(CUS sub, out - sub);
7190
        yield = string_cat(yield, enc);
7362
	yield = string_cat(yield, enc);
7191
        continue;
7363
	break;
7192
        }
7364
	}
7193
7365
7194
      /* Convert octets outside 0x21..0x7E to \xXX form */
7366
      /* Convert octets outside 0x21..0x7E to \xXX form */
7195
7367
7196
      case EOP_HEXQUOTE:
7368
      case EOP_HEXQUOTE:
7197
	{
7369
	{
7198
        uschar *t = sub - 1;
7370
	uschar *t = sub - 1;
7199
        while (*(++t) != 0)
7371
	while (*(++t) != 0)
7200
          {
7372
	  {
7201
          if (*t < 0x21 || 0x7E < *t)
7373
	  if (*t < 0x21 || 0x7E < *t)
7202
            yield = string_fmt_append(yield, "\\x%02x", *t);
7374
	    yield = string_fmt_append(yield, "\\x%02x", *t);
7203
	  else
7375
	  else
7204
	    yield = string_catn(yield, t, 1);
7376
	    yield = string_catn(yield, t, 1);
7205
          }
7377
	  }
7206
	continue;
7378
	break;
7207
	}
7379
	}
7208
7380
7209
      /* count the number of list elements */
7381
      /* count the number of list elements */
7210
7382
7211
      case EOP_LISTCOUNT:
7383
      case EOP_LISTCOUNT:
7212
        {
7384
	{
7213
	int cnt = 0;
7385
	int cnt = 0, sep = 0;
7214
	int sep = 0;
7386
	uschar * buf = store_get(2, sub);
7215
7387
7216
	while (string_nextinlist(CUSS &sub, &sep, NULL, 0)) cnt++;
7388
	while (string_nextinlist(CUSS &sub, &sep, buf, 1)) cnt++;
7217
	yield = string_fmt_append(yield, "%d", cnt);
7389
	yield = string_fmt_append(yield, "%d", cnt);
7218
        continue;
7390
	break;
7219
        }
7391
	}
7220
7392
7221
      /* expand a named list given the name */
7393
      /* expand a named list given the name */
7222
      /* handles nested named lists; requotes as colon-sep list */
7394
      /* handles nested named lists; requotes as colon-sep list */
7223
7395
7224
      case EOP_LISTNAMED:
7396
      case EOP_LISTNAMED:
7225
	{
7397
	expand_string_message = NULL;
7226
	tree_node *t = NULL;
7398
	yield = expand_listnamed(yield, sub, arg);
7227
	const uschar * list;
7399
	if (expand_string_message)
7228
	int sep = 0;
7229
	uschar * item;
7230
	uschar * suffix = US"";
7231
	BOOL needsep = FALSE;
7232
	uschar buffer[256];
7233
7234
	if (*sub == '+') sub++;
7235
	if (!arg)		/* no-argument version */
7236
	  {
7237
	  if (!(t = tree_search(addresslist_anchor, sub)) &&
7238
	      !(t = tree_search(domainlist_anchor,  sub)) &&
7239
	      !(t = tree_search(hostlist_anchor,    sub)))
7240
	    t = tree_search(localpartlist_anchor, sub);
7241
	  }
7242
	else switch(*arg)	/* specific list-type version */
7243
	  {
7244
	  case 'a': t = tree_search(addresslist_anchor,   sub); suffix = US"_a"; break;
7245
	  case 'd': t = tree_search(domainlist_anchor,    sub); suffix = US"_d"; break;
7246
	  case 'h': t = tree_search(hostlist_anchor,      sub); suffix = US"_h"; break;
7247
	  case 'l': t = tree_search(localpartlist_anchor, sub); suffix = US"_l"; break;
7248
	  default:
7249
            expand_string_message = US"bad suffix on \"list\" operator";
7250
	    goto EXPAND_FAILED;
7251
	  }
7252
7253
	if(!t)
7254
	  {
7255
          expand_string_message = string_sprintf("\"%s\" is not a %snamed list",
7256
            sub, !arg?""
7257
	      : *arg=='a'?"address "
7258
	      : *arg=='d'?"domain "
7259
	      : *arg=='h'?"host "
7260
	      : *arg=='l'?"localpart "
7261
	      : 0);
7262
	  goto EXPAND_FAILED;
7400
	  goto EXPAND_FAILED;
7263
	  }
7401
	break;
7264
7265
	list = ((namedlist_block *)(t->data.ptr))->string;
7266
7267
	while ((item = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
7268
	  {
7269
	  uschar * buf = US" : ";
7270
	  if (needsep)
7271
	    yield = string_catn(yield, buf, 3);
7272
	  else
7273
	    needsep = TRUE;
7274
7275
	  if (*item == '+')	/* list item is itself a named list */
7276
	    {
7277
	    uschar * sub = string_sprintf("${listnamed%s:%s}", suffix, item);
7278
	    item = expand_string_internal(sub, FALSE, NULL, FALSE, TRUE, &resetok);
7279
	    }
7280
	  else if (sep != ':')	/* item from non-colon-sep list, re-quote for colon list-separator */
7281
	    {
7282
	    char * cp;
7283
	    char tok[3];
7284
	    tok[0] = sep; tok[1] = ':'; tok[2] = 0;
7285
	    while ((cp= strpbrk(CCS item, tok)))
7286
	      {
7287
              yield = string_catn(yield, item, cp - CS item);
7288
	      if (*cp++ == ':')	/* colon in a non-colon-sep list item, needs doubling */
7289
	        {
7290
                yield = string_catn(yield, US"::", 2);
7291
	        item = US cp;
7292
		}
7293
	      else		/* sep in item; should already be doubled; emit once */
7294
	        {
7295
                yield = string_catn(yield, US tok, 1);
7296
		if (*cp == sep) cp++;
7297
	        item = US cp;
7298
		}
7299
	      }
7300
	    }
7301
          yield = string_cat(yield, item);
7302
	  }
7303
        continue;
7304
	}
7305
7402
7306
      /* quote a list-item for the given list-separator */
7403
      /* quote a list-item for the given list-separator */
7307
7404
Lines 7309-7362 Link Here
7309
      ${mask:131.111.10.206/28} is 131.111.10.192/28. */
7406
      ${mask:131.111.10.206/28} is 131.111.10.192/28. */
7310
7407
7311
      case EOP_MASK:
7408
      case EOP_MASK:
7312
        {
7409
	{
7313
        int count;
7410
	int count;
7314
        uschar *endptr;
7411
	uschar *endptr;
7315
        int binary[4];
7412
	int binary[4];
7316
        int mask, maskoffset;
7413
	int type, mask, maskoffset;
7317
        int type = string_is_ip_address(sub, &maskoffset);
7414
	BOOL normalised;
7318
        uschar buffer[64];
7415
	uschar buffer[64];
7319
7416
7320
        if (type == 0)
7417
	if ((type = string_is_ip_address(sub, &maskoffset)) == 0)
7321
          {
7418
	  {
7322
          expand_string_message = string_sprintf("\"%s\" is not an IP address",
7419
	  expand_string_message = string_sprintf("\"%s\" is not an IP address",
7323
           sub);
7420
	   sub);
7324
          goto EXPAND_FAILED;
7421
	  goto EXPAND_FAILED;
7325
          }
7422
	  }
7326
7423
7327
        if (maskoffset == 0)
7424
	if (maskoffset == 0)
7328
          {
7425
	  {
7329
          expand_string_message = string_sprintf("missing mask value in \"%s\"",
7426
	  expand_string_message = string_sprintf("missing mask value in \"%s\"",
7330
            sub);
7427
	    sub);
7331
          goto EXPAND_FAILED;
7428
	  goto EXPAND_FAILED;
7332
          }
7429
	  }
7333
7430
7334
        mask = Ustrtol(sub + maskoffset + 1, &endptr, 10);
7431
	mask = Ustrtol(sub + maskoffset + 1, &endptr, 10);
7335
7432
7336
        if (*endptr != 0 || mask < 0 || mask > ((type == 4)? 32 : 128))
7433
	if (*endptr || mask < 0 || mask > (type == 4 ? 32 : 128))
7337
          {
7434
	  {
7338
          expand_string_message = string_sprintf("mask value too big in \"%s\"",
7435
	  expand_string_message = string_sprintf("mask value too big in \"%s\"",
7339
            sub);
7436
	    sub);
7340
          goto EXPAND_FAILED;
7437
	  goto EXPAND_FAILED;
7341
          }
7438
	  }
7342
7439
7343
        /* Convert the address to binary integer(s) and apply the mask */
7440
	/* If an optional 'n' was given, ipv6 gets normalised output:
7441
	colons rather than dots, and zero-compressed. */
7344
7442
7345
        sub[maskoffset] = 0;
7443
	normalised = arg && *arg == 'n';
7346
        count = host_aton(sub, binary);
7347
        host_mask(count, binary, mask);
7348
7444
7349
        /* Convert to masked textual format and add to output. */
7445
	/* Convert the address to binary integer(s) and apply the mask */
7350
7446
7351
        yield = string_catn(yield, buffer,
7447
	sub[maskoffset] = 0;
7352
          host_nmtoa(count, binary, mask, buffer, '.'));
7448
	count = host_aton(sub, binary);
7353
        continue;
7449
	host_mask(count, binary, mask);
7354
        }
7450
7451
	/* Convert to masked textual format and add to output. */
7452
7453
	if (type == 4 || !normalised)
7454
	  yield = string_catn(yield, buffer,
7455
	    host_nmtoa(count, binary, mask, buffer, '.'));
7456
	else
7457
	  {
7458
	  ipv6_nmtoa(binary, buffer);
7459
	  yield = string_fmt_append(yield, "%s/%d", buffer, mask);
7460
	  }
7461
	break;
7462
	}
7355
7463
7356
      case EOP_IPV6NORM:
7464
      case EOP_IPV6NORM:
7357
      case EOP_IPV6DENORM:
7465
      case EOP_IPV6DENORM:
7358
	{
7466
	{
7359
        int type = string_is_ip_address(sub, NULL);
7467
	int type = string_is_ip_address(sub, NULL);
7360
	int binary[4];
7468
	int binary[4];
7361
	uschar buffer[44];
7469
	uschar buffer[44];
7362
7470
Lines 7382-7475 Link Here
7382
		    ? ipv6_nmtoa(binary, buffer)
7490
		    ? ipv6_nmtoa(binary, buffer)
7383
		    : host_nmtoa(4, binary, -1, buffer, ':')
7491
		    : host_nmtoa(4, binary, -1, buffer, ':')
7384
		  );
7492
		  );
7385
	continue;
7493
	break;
7386
	}
7494
	}
7387
7495
7388
      case EOP_ADDRESS:
7496
      case EOP_ADDRESS:
7389
      case EOP_LOCAL_PART:
7497
      case EOP_LOCAL_PART:
7390
      case EOP_DOMAIN:
7498
      case EOP_DOMAIN:
7391
        {
7499
	{
7392
        uschar * error;
7500
	uschar * error;
7393
        int start, end, domain;
7501
	int start, end, domain;
7394
        uschar * t = parse_extract_address(sub, &error, &start, &end, &domain,
7502
	uschar * t = parse_extract_address(sub, &error, &start, &end, &domain,
7395
          FALSE);
7503
	  FALSE);
7396
        if (t)
7504
	if (t)
7397
	  if (c != EOP_DOMAIN)
7505
	  if (c != EOP_DOMAIN)
7398
	    yield = c == EOP_LOCAL_PART && domain > 0
7506
	    yield = c == EOP_LOCAL_PART && domain > 0
7399
	      ? string_catn(yield, t, domain - 1)
7507
	      ? string_catn(yield, t, domain - 1)
7400
	      : string_cat(yield, t);
7508
	      : string_cat(yield, t);
7401
	  else if (domain > 0)
7509
	  else if (domain > 0)
7402
	    yield = string_cat(yield, t + domain);
7510
	    yield = string_cat(yield, t + domain);
7403
        continue;
7511
	break;
7404
        }
7512
	}
7405
7513
7406
      case EOP_ADDRESSES:
7514
      case EOP_ADDRESSES:
7407
        {
7515
	{
7408
        uschar outsep[2] = { ':', '\0' };
7516
	uschar outsep[2] = { ':', '\0' };
7409
        uschar *address, *error;
7517
	uschar *address, *error;
7410
        int save_ptr = gstring_length(yield);
7518
	int save_ptr = gstring_length(yield);
7411
        int start, end, domain;  /* Not really used */
7519
	int start, end, domain;  /* Not really used */
7412
7520
7413
	if (Uskip_whitespace(&sub) == '>')
7521
	if (Uskip_whitespace(&sub) == '>')
7414
          if (*outsep = *++sub) ++sub;
7522
	  if (*outsep = *++sub) ++sub;
7415
          else
7523
	  else
7416
	    {
7524
	    {
7417
            expand_string_message = string_sprintf("output separator "
7525
	    expand_string_message = string_sprintf("output separator "
7418
              "missing in expanding ${addresses:%s}", --sub);
7526
	      "missing in expanding ${addresses:%s}", --sub);
7419
            goto EXPAND_FAILED;
7527
	    goto EXPAND_FAILED;
7420
            }
7528
	    }
7421
        f.parse_allow_group = TRUE;
7529
	f.parse_allow_group = TRUE;
7422
7530
7423
        for (;;)
7531
	for (;;)
7424
          {
7532
	  {
7425
          uschar * p = parse_find_address_end(sub, FALSE);
7533
	  uschar * p = parse_find_address_end(sub, FALSE);
7426
          uschar saveend = *p;
7534
	  uschar saveend = *p;
7427
          *p = '\0';
7535
	  *p = '\0';
7428
          address = parse_extract_address(sub, &error, &start, &end, &domain,
7536
	  address = parse_extract_address(sub, &error, &start, &end, &domain,
7429
            FALSE);
7537
	    FALSE);
7430
          *p = saveend;
7538
	  *p = saveend;
7431
7539
7432
          /* Add the address to the output list that we are building. This is
7540
	  /* Add the address to the output list that we are building. This is
7433
          done in chunks by searching for the separator character. At the
7541
	  done in chunks by searching for the separator character. At the
7434
          start, unless we are dealing with the first address of the output
7542
	  start, unless we are dealing with the first address of the output
7435
          list, add in a space if the new address begins with the separator
7543
	  list, add in a space if the new address begins with the separator
7436
          character, or is an empty string. */
7544
	  character, or is an empty string. */
7437
7545
7438
          if (address)
7546
	  if (address)
7439
            {
7547
	    {
7440
            if (yield && yield->ptr != save_ptr && address[0] == *outsep)
7548
	    if (yield && yield->ptr != save_ptr && address[0] == *outsep)
7441
              yield = string_catn(yield, US" ", 1);
7549
	      yield = string_catn(yield, US" ", 1);
7442
7550
7443
            for (;;)
7551
	    for (;;)
7444
              {
7552
	      {
7445
              size_t seglen = Ustrcspn(address, outsep);
7553
	      size_t seglen = Ustrcspn(address, outsep);
7446
              yield = string_catn(yield, address, seglen + 1);
7554
	      yield = string_catn(yield, address, seglen + 1);
7447
7448
              /* If we got to the end of the string we output one character
7449
              too many. */
7450
7451
              if (address[seglen] == '\0') { yield->ptr--; break; }
7452
              yield = string_catn(yield, outsep, 1);
7453
              address += seglen + 1;
7454
              }
7455
7555
7456
            /* Output a separator after the string: we will remove the
7556
	      /* If we got to the end of the string we output one character
7457
            redundant final one at the end. */
7557
	      too many. */
7458
7558
7459
            yield = string_catn(yield, outsep, 1);
7559
	      if (address[seglen] == '\0') { yield->ptr--; break; }
7460
            }
7560
	      yield = string_catn(yield, outsep, 1);
7561
	      address += seglen + 1;
7562
	      }
7461
7563
7462
          if (saveend == '\0') break;
7564
	    /* Output a separator after the string: we will remove the
7463
          sub = p + 1;
7565
	    redundant final one at the end. */
7464
          }
7465
7566
7466
        /* If we have generated anything, remove the redundant final
7567
	    yield = string_catn(yield, outsep, 1);
7467
        separator. */
7568
	    }
7468
7569
7469
        if (yield && yield->ptr != save_ptr) yield->ptr--;
7570
	  if (saveend == '\0') break;
7470
        f.parse_allow_group = FALSE;
7571
	  sub = p + 1;
7471
        continue;
7572
	  }
7472
        }
7573
7574
	/* If we have generated anything, remove the redundant final
7575
	separator. */
7576
7577
	if (yield && yield->ptr != save_ptr) yield->ptr--;
7578
	f.parse_allow_group = FALSE;
7579
	break;
7580
	}
7473
7581
7474
7582
7475
      /* quote puts a string in quotes if it is empty or contains anything
7583
      /* quote puts a string in quotes if it is empty or contains anything
Lines 7483-8068 Link Here
7483
7591
7484
      case EOP_QUOTE:
7592
      case EOP_QUOTE:
7485
      case EOP_QUOTE_LOCAL_PART:
7593
      case EOP_QUOTE_LOCAL_PART:
7486
      if (!arg)
7594
	if (!arg)
7487
        {
7595
	  {
7488
        BOOL needs_quote = (!*sub);      /* TRUE for empty string */
7596
	  BOOL needs_quote = (!*sub);      /* TRUE for empty string */
7489
        uschar *t = sub - 1;
7597
	  uschar *t = sub - 1;
7490
7491
        if (c == EOP_QUOTE)
7492
          {
7493
          while (!needs_quote && *(++t) != 0)
7494
            needs_quote = !isalnum(*t) && !strchr("_-.", *t);
7495
          }
7496
        else  /* EOP_QUOTE_LOCAL_PART */
7497
          {
7498
          while (!needs_quote && *(++t) != 0)
7499
            needs_quote = !isalnum(*t) &&
7500
              strchr("!#$%&'*+-/=?^_`{|}~", *t) == NULL &&
7501
              (*t != '.' || t == sub || t[1] == 0);
7502
          }
7503
7598
7504
        if (needs_quote)
7599
	  if (c == EOP_QUOTE)
7505
          {
7600
	    while (!needs_quote && *++t)
7506
          yield = string_catn(yield, US"\"", 1);
7601
	      needs_quote = !isalnum(*t) && !strchr("_-.", *t);
7507
          t = sub - 1;
7602
7508
          while (*(++t) != 0)
7603
	  else  /* EOP_QUOTE_LOCAL_PART */
7509
            {
7604
	    while (!needs_quote && *++t)
7510
            if (*t == '\n')
7605
	      needs_quote = !isalnum(*t)
7511
              yield = string_catn(yield, US"\\n", 2);
7606
		&& strchr("!#$%&'*+-/=?^_`{|}~", *t) == NULL
7512
            else if (*t == '\r')
7607
		&& (*t != '.' || t == sub || !t[1]);
7513
              yield = string_catn(yield, US"\\r", 2);
7514
            else
7515
              {
7516
              if (*t == '\\' || *t == '"')
7517
                yield = string_catn(yield, US"\\", 1);
7518
              yield = string_catn(yield, t, 1);
7519
              }
7520
            }
7521
          yield = string_catn(yield, US"\"", 1);
7522
          }
7523
        else yield = string_cat(yield, sub);
7524
        continue;
7525
        }
7526
7608
7527
      /* quote_lookuptype does lookup-specific quoting */
7609
	  if (needs_quote)
7610
	    {
7611
	    yield = string_catn(yield, US"\"", 1);
7612
	    t = sub - 1;
7613
	    while (*++t)
7614
	      if (*t == '\n')
7615
		yield = string_catn(yield, US"\\n", 2);
7616
	      else if (*t == '\r')
7617
		yield = string_catn(yield, US"\\r", 2);
7618
	      else
7619
		{
7620
		if (*t == '\\' || *t == '"')
7621
		  yield = string_catn(yield, US"\\", 1);
7622
		yield = string_catn(yield, t, 1);
7623
		}
7624
	    yield = string_catn(yield, US"\"", 1);
7625
	    }
7626
	  else
7627
	    yield = string_cat(yield, sub);
7628
	  break;
7629
	  }
7528
7630
7529
      else
7631
	/* quote_lookuptype does lookup-specific quoting */
7530
        {
7531
        int n;
7532
        uschar *opt = Ustrchr(arg, '_');
7533
7632
7534
        if (opt) *opt++ = 0;
7633
	else
7634
	  {
7635
	  int n;
7636
	  uschar * opt = Ustrchr(arg, '_');
7535
7637
7536
        if ((n = search_findtype(arg, Ustrlen(arg))) < 0)
7638
	  if (opt) *opt++ = 0;
7537
          {
7538
          expand_string_message = search_error_message;
7539
          goto EXPAND_FAILED;
7540
          }
7541
7639
7542
        if (lookup_list[n]->quote)
7640
	  if ((n = search_findtype(arg, Ustrlen(arg))) < 0)
7543
          sub = (lookup_list[n]->quote)(sub, opt);
7641
	    {
7544
        else if (opt)
7642
	    expand_string_message = search_error_message;
7545
	  sub = NULL;
7643
	    goto EXPAND_FAILED;
7644
	    }
7546
7645
7547
        if (!sub)
7646
	  if (lookup_list[n]->quote)
7548
          {
7647
	    sub = (lookup_list[n]->quote)(sub, opt, (unsigned)n);
7549
          expand_string_message = string_sprintf(
7648
	  else if (opt)
7550
            "\"%s\" unrecognized after \"${quote_%s\"",
7649
	    sub = NULL;
7551
            opt, arg);
7552
          goto EXPAND_FAILED;
7553
          }
7554
7650
7555
        yield = string_cat(yield, sub);
7651
	  if (!sub)
7556
        continue;
7652
	    {
7557
        }
7653
	    expand_string_message = string_sprintf(
7654
	      "\"%s\" unrecognized after \"${quote_%s\"",	/*}*/
7655
	      opt, arg);
7656
	    goto EXPAND_FAILED;
7657
	    }
7558
7658
7559
      /* rx quote sticks in \ before any non-alphameric character so that
7659
	  yield = string_cat(yield, sub);
7560
      the insertion works in a regular expression. */
7660
	  break;
7661
	  }
7561
7662
7562
      case EOP_RXQUOTE:
7663
	/* rx quote sticks in \ before any non-alphameric character so that
7563
        {
7664
	the insertion works in a regular expression. */
7564
        uschar *t = sub - 1;
7565
        while (*(++t) != 0)
7566
          {
7567
          if (!isalnum(*t))
7568
            yield = string_catn(yield, US"\\", 1);
7569
          yield = string_catn(yield, t, 1);
7570
          }
7571
        continue;
7572
        }
7573
7665
7574
      /* RFC 2047 encodes, assuming headers_charset (default ISO 8859-1) as
7666
	case EOP_RXQUOTE:
7575
      prescribed by the RFC, if there are characters that need to be encoded */
7667
	  {
7668
	  uschar *t = sub - 1;
7669
	  while (*(++t) != 0)
7670
	    {
7671
	    if (!isalnum(*t))
7672
	      yield = string_catn(yield, US"\\", 1);
7673
	    yield = string_catn(yield, t, 1);
7674
	    }
7675
	  break;
7676
	  }
7576
7677
7577
      case EOP_RFC2047:
7678
	/* RFC 2047 encodes, assuming headers_charset (default ISO 8859-1) as
7578
        yield = string_cat(yield,
7679
	prescribed by the RFC, if there are characters that need to be encoded */
7579
			    parse_quote_2047(sub, Ustrlen(sub), headers_charset,
7580
			      FALSE));
7581
        continue;
7582
7680
7583
      /* RFC 2047 decode */
7681
	case EOP_RFC2047:
7682
	  yield = string_cat(yield,
7683
			      parse_quote_2047(sub, Ustrlen(sub), headers_charset,
7684
				FALSE));
7685
	  break;
7584
7686
7585
      case EOP_RFC2047D:
7687
	/* RFC 2047 decode */
7586
        {
7587
        int len;
7588
        uschar *error;
7589
        uschar *decoded = rfc2047_decode(sub, check_rfc2047_length,
7590
          headers_charset, '?', &len, &error);
7591
        if (error)
7592
          {
7593
          expand_string_message = error;
7594
          goto EXPAND_FAILED;
7595
          }
7596
        yield = string_catn(yield, decoded, len);
7597
        continue;
7598
        }
7599
7688
7600
      /* from_utf8 converts UTF-8 to 8859-1, turning non-existent chars into
7689
	case EOP_RFC2047D:
7601
      underscores */
7690
	  {
7691
	  int len;
7692
	  uschar *error;
7693
	  uschar *decoded = rfc2047_decode(sub, check_rfc2047_length,
7694
	    headers_charset, '?', &len, &error);
7695
	  if (error)
7696
	    {
7697
	    expand_string_message = error;
7698
	    goto EXPAND_FAILED;
7699
	    }
7700
	  yield = string_catn(yield, decoded, len);
7701
	  break;
7702
	  }
7602
7703
7603
      case EOP_FROM_UTF8:
7704
	/* from_utf8 converts UTF-8 to 8859-1, turning non-existent chars into
7604
        {
7705
	underscores */
7605
	uschar * buff = store_get(4, is_tainted(sub));
7606
        while (*sub)
7607
          {
7608
          int c;
7609
          GETUTF8INC(c, sub);
7610
          if (c > 255) c = '_';
7611
          buff[0] = c;
7612
          yield = string_catn(yield, buff, 1);
7613
          }
7614
        continue;
7615
        }
7616
7706
7617
      /* replace illegal UTF-8 sequences by replacement character  */
7707
	case EOP_FROM_UTF8:
7708
	  {
7709
	  uschar * buff = store_get(4, sub);
7710
	  while (*sub)
7711
	    {
7712
	    int c;
7713
	    GETUTF8INC(c, sub);
7714
	    if (c > 255) c = '_';
7715
	    buff[0] = c;
7716
	    yield = string_catn(yield, buff, 1);
7717
	    }
7718
	  break;
7719
	  }
7618
7720
7619
      #define UTF8_REPLACEMENT_CHAR US"?"
7721
	/* replace illegal UTF-8 sequences by replacement character  */
7620
7722
7621
      case EOP_UTF8CLEAN:
7723
	#define UTF8_REPLACEMENT_CHAR US"?"
7622
        {
7623
        int seq_len = 0, index = 0;
7624
        int bytes_left = 0;
7625
        long codepoint = -1;
7626
        int complete;
7627
        uschar seq_buff[4];			/* accumulate utf-8 here */
7628
7724
7629
	/* Manually track tainting, as we deal in individual chars below */
7725
	case EOP_UTF8CLEAN:
7726
	  {
7727
	  int seq_len = 0, index = 0;
7728
	  int bytes_left = 0;
7729
	  long codepoint = -1;
7730
	  int complete;
7731
	  uschar seq_buff[4];			/* accumulate utf-8 here */
7630
7732
7631
	if (is_tainted(sub))
7733
	  /* Manually track tainting, as we deal in individual chars below */
7632
	  if (yield->s && yield->ptr)
7633
	    gstring_rebuffer(yield);
7634
	  else
7635
	    yield->s = store_get(yield->size = Ustrlen(sub), TRUE);
7636
7734
7637
	/* Check the UTF-8, byte-by-byte */
7735
	  if (!yield->s || !yield->ptr)
7736
	    yield->s = store_get(yield->size = Ustrlen(sub), sub);
7737
	  else if (is_incompatible(yield->s, sub))
7738
	    gstring_rebuffer(yield, sub);
7638
7739
7639
        while (*sub)
7740
	  /* Check the UTF-8, byte-by-byte */
7640
	  {
7641
	  complete = 0;
7642
	  uschar c = *sub++;
7643
7741
7644
	  if (bytes_left)
7742
	  while (*sub)
7645
	    {
7743
	    {
7646
	    if ((c & 0xc0) != 0x80)
7744
	    complete = 0;
7647
		    /* wrong continuation byte; invalidate all bytes */
7745
	    uschar c = *sub++;
7648
	      complete = 1; /* error */
7746
7649
	    else
7747
	    if (bytes_left)
7650
	      {
7651
	      codepoint = (codepoint << 6) | (c & 0x3f);
7652
	      seq_buff[index++] = c;
7653
	      if (--bytes_left == 0)		/* codepoint complete */
7654
		if(codepoint > 0x10FFFF)	/* is it too large? */
7655
		  complete = -1;	/* error (RFC3629 limit) */
7656
		else
7657
		  {		/* finished; output utf-8 sequence */
7658
		  yield = string_catn(yield, seq_buff, seq_len);
7659
		  index = 0;
7660
		  }
7661
	      }
7662
	    }
7663
	  else	/* no bytes left: new sequence */
7664
	    {
7665
	    if(!(c & 0x80))	/* 1-byte sequence, US-ASCII, keep it */
7666
	      {
7667
	      yield = string_catn(yield, &c, 1);
7668
	      continue;
7669
	      }
7670
	    if((c & 0xe0) == 0xc0)		/* 2-byte sequence */
7671
	      {
7748
	      {
7672
	      if(c == 0xc0 || c == 0xc1)	/* 0xc0 and 0xc1 are illegal */
7749
	      if ((c & 0xc0) != 0x80)
7673
		complete = -1;
7750
		      /* wrong continuation byte; invalidate all bytes */
7751
		complete = 1; /* error */
7674
	      else
7752
	      else
7675
		{
7753
		{
7676
		  bytes_left = 1;
7754
		codepoint = (codepoint << 6) | (c & 0x3f);
7677
		  codepoint = c & 0x1f;
7755
		seq_buff[index++] = c;
7756
		if (--bytes_left == 0)		/* codepoint complete */
7757
		  if(codepoint > 0x10FFFF)	/* is it too large? */
7758
		    complete = -1;	/* error (RFC3629 limit) */
7759
		  else
7760
		    {		/* finished; output utf-8 sequence */
7761
		    yield = string_catn(yield, seq_buff, seq_len);
7762
		    index = 0;
7763
		    }
7678
		}
7764
		}
7679
	      }
7765
	      }
7680
	    else if((c & 0xf0) == 0xe0)		/* 3-byte sequence */
7766
	    else	/* no bytes left: new sequence */
7681
	      {
7767
	      {
7682
	      bytes_left = 2;
7768
	      if(!(c & 0x80))	/* 1-byte sequence, US-ASCII, keep it */
7683
	      codepoint = c & 0x0f;
7769
		{
7684
	      }
7770
		yield = string_catn(yield, &c, 1);
7685
	    else if((c & 0xf8) == 0xf0)		/* 4-byte sequence */
7771
		continue;
7772
		}
7773
	      if((c & 0xe0) == 0xc0)		/* 2-byte sequence */
7774
		{
7775
		if(c == 0xc0 || c == 0xc1)	/* 0xc0 and 0xc1 are illegal */
7776
		  complete = -1;
7777
		else
7778
		  {
7779
		    bytes_left = 1;
7780
		    codepoint = c & 0x1f;
7781
		  }
7782
		}
7783
	      else if((c & 0xf0) == 0xe0)		/* 3-byte sequence */
7784
		{
7785
		bytes_left = 2;
7786
		codepoint = c & 0x0f;
7787
		}
7788
	      else if((c & 0xf8) == 0xf0)		/* 4-byte sequence */
7789
		{
7790
		bytes_left = 3;
7791
		codepoint = c & 0x07;
7792
		}
7793
	      else	/* invalid or too long (RFC3629 allows only 4 bytes) */
7794
		complete = -1;
7795
7796
	      seq_buff[index++] = c;
7797
	      seq_len = bytes_left + 1;
7798
	      }		/* if(bytes_left) */
7799
7800
	    if (complete != 0)
7686
	      {
7801
	      {
7687
	      bytes_left = 3;
7802
	      bytes_left = index = 0;
7688
	      codepoint = c & 0x07;
7803
	      yield = string_catn(yield, UTF8_REPLACEMENT_CHAR, 1);
7689
	      }
7804
	      }
7690
	    else	/* invalid or too long (RFC3629 allows only 4 bytes) */
7805
	    if ((complete == 1) && ((c & 0x80) == 0))
7691
	      complete = -1;
7806
			  /* ASCII character follows incomplete sequence */
7692
7807
		yield = string_catn(yield, &c, 1);
7693
	    seq_buff[index++] = c;
7808
	    }
7694
	    seq_len = bytes_left + 1;
7809
	  /* If given a sequence truncated mid-character, we also want to report ?
7695
	    }		/* if(bytes_left) */
7810
	  Eg, ${length_1:フィル} is one byte, not one character, so we expect
7811
	  ${utf8clean:${length_1:フィル}} to yield '?' */
7696
7812
7697
	  if (complete != 0)
7813
	  if (bytes_left != 0)
7698
	    {
7699
	    bytes_left = index = 0;
7700
	    yield = string_catn(yield, UTF8_REPLACEMENT_CHAR, 1);
7814
	    yield = string_catn(yield, UTF8_REPLACEMENT_CHAR, 1);
7701
	    }
7702
	  if ((complete == 1) && ((c & 0x80) == 0))
7703
			/* ASCII character follows incomplete sequence */
7704
	      yield = string_catn(yield, &c, 1);
7705
	  }
7706
        /* If given a sequence truncated mid-character, we also want to report ?
7707
        * Eg, ${length_1:フィル} is one byte, not one character, so we expect
7708
        * ${utf8clean:${length_1:フィル}} to yield '?' */
7709
        if (bytes_left != 0)
7710
          yield = string_catn(yield, UTF8_REPLACEMENT_CHAR, 1);
7711
7815
7712
        continue;
7816
	  break;
7713
        }
7817
	  }
7714
7818
7715
#ifdef SUPPORT_I18N
7819
#ifdef SUPPORT_I18N
7716
      case EOP_UTF8_DOMAIN_TO_ALABEL:
7820
	case EOP_UTF8_DOMAIN_TO_ALABEL:
7717
	{
7718
        uschar * error = NULL;
7719
	uschar * s = string_domain_utf8_to_alabel(sub, &error);
7720
	if (error)
7721
	  {
7821
	  {
7722
	  expand_string_message = string_sprintf(
7822
	  uschar * error = NULL;
7723
	    "error converting utf8 (%s) to alabel: %s",
7823
	  uschar * s = string_domain_utf8_to_alabel(sub, &error);
7724
	    string_printing(sub), error);
7824
	  if (error)
7725
	  goto EXPAND_FAILED;
7825
	    {
7826
	    expand_string_message = string_sprintf(
7827
	      "error converting utf8 (%s) to alabel: %s",
7828
	      string_printing(sub), error);
7829
	    goto EXPAND_FAILED;
7830
	    }
7831
	  yield = string_cat(yield, s);
7832
	  break;
7726
	  }
7833
	  }
7727
	yield = string_cat(yield, s);
7728
        continue;
7729
	}
7730
7834
7731
      case EOP_UTF8_DOMAIN_FROM_ALABEL:
7835
	case EOP_UTF8_DOMAIN_FROM_ALABEL:
7732
	{
7733
        uschar * error = NULL;
7734
	uschar * s = string_domain_alabel_to_utf8(sub, &error);
7735
	if (error)
7736
	  {
7836
	  {
7737
	  expand_string_message = string_sprintf(
7837
	  uschar * error = NULL;
7738
	    "error converting alabel (%s) to utf8: %s",
7838
	  uschar * s = string_domain_alabel_to_utf8(sub, &error);
7739
	    string_printing(sub), error);
7839
	  if (error)
7740
	  goto EXPAND_FAILED;
7840
	    {
7841
	    expand_string_message = string_sprintf(
7842
	      "error converting alabel (%s) to utf8: %s",
7843
	      string_printing(sub), error);
7844
	    goto EXPAND_FAILED;
7845
	    }
7846
	  yield = string_cat(yield, s);
7847
	  break;
7741
	  }
7848
	  }
7742
	yield = string_cat(yield, s);
7743
        continue;
7744
	}
7745
7849
7746
      case EOP_UTF8_LOCALPART_TO_ALABEL:
7850
	case EOP_UTF8_LOCALPART_TO_ALABEL:
7747
	{
7748
        uschar * error = NULL;
7749
	uschar * s = string_localpart_utf8_to_alabel(sub, &error);
7750
	if (error)
7751
	  {
7851
	  {
7752
	  expand_string_message = string_sprintf(
7852
	  uschar * error = NULL;
7753
	    "error converting utf8 (%s) to alabel: %s",
7853
	  uschar * s = string_localpart_utf8_to_alabel(sub, &error);
7754
	    string_printing(sub), error);
7854
	  if (error)
7755
	  goto EXPAND_FAILED;
7855
	    {
7856
	    expand_string_message = string_sprintf(
7857
	      "error converting utf8 (%s) to alabel: %s",
7858
	      string_printing(sub), error);
7859
	    goto EXPAND_FAILED;
7860
	    }
7861
	  yield = string_cat(yield, s);
7862
	  DEBUG(D_expand) debug_printf_indent("yield: '%s'\n", yield->s);
7863
	  break;
7756
	  }
7864
	  }
7757
	yield = string_cat(yield, s);
7758
	DEBUG(D_expand) debug_printf_indent("yield: '%s'\n", yield->s);
7759
        continue;
7760
	}
7761
7865
7762
      case EOP_UTF8_LOCALPART_FROM_ALABEL:
7866
	case EOP_UTF8_LOCALPART_FROM_ALABEL:
7763
	{
7764
        uschar * error = NULL;
7765
	uschar * s = string_localpart_alabel_to_utf8(sub, &error);
7766
	if (error)
7767
	  {
7867
	  {
7768
	  expand_string_message = string_sprintf(
7868
	  uschar * error = NULL;
7769
	    "error converting alabel (%s) to utf8: %s",
7869
	  uschar * s = string_localpart_alabel_to_utf8(sub, &error);
7770
	    string_printing(sub), error);
7870
	  if (error)
7771
	  goto EXPAND_FAILED;
7871
	    {
7872
	    expand_string_message = string_sprintf(
7873
	      "error converting alabel (%s) to utf8: %s",
7874
	      string_printing(sub), error);
7875
	    goto EXPAND_FAILED;
7876
	    }
7877
	  yield = string_cat(yield, s);
7878
	  break;
7772
	  }
7879
	  }
7773
	yield = string_cat(yield, s);
7774
        continue;
7775
	}
7776
#endif	/* EXPERIMENTAL_INTERNATIONAL */
7880
#endif	/* EXPERIMENTAL_INTERNATIONAL */
7777
7881
7778
      /* escape turns all non-printing characters into escape sequences. */
7882
	/* escape turns all non-printing characters into escape sequences. */
7779
7883
7780
      case EOP_ESCAPE:
7884
	case EOP_ESCAPE:
7781
        {
7885
	  {
7782
        const uschar * t = string_printing(sub);
7886
	  const uschar * t = string_printing(sub);
7783
        yield = string_cat(yield, t);
7887
	  yield = string_cat(yield, t);
7784
        continue;
7888
	  break;
7785
        }
7889
	  }
7786
7890
7787
      case EOP_ESCAPE8BIT:
7891
	case EOP_ESCAPE8BIT:
7788
	{
7892
	  {
7789
	uschar c;
7893
	  uschar c;
7790
7894
7791
	for (const uschar * s = sub; (c = *s); s++)
7895
	  for (const uschar * s = sub; (c = *s); s++)
7792
	  yield = c < 127 && c != '\\'
7896
	    yield = c < 127 && c != '\\'
7793
	    ? string_catn(yield, s, 1)
7897
	      ? string_catn(yield, s, 1)
7794
	    : string_fmt_append(yield, "\\%03o", c);
7898
	      : string_fmt_append(yield, "\\%03o", c);
7795
	continue;
7899
	  break;
7796
	}
7900
	  }
7797
7901
7798
      /* Handle numeric expression evaluation */
7902
	/* Handle numeric expression evaluation */
7799
7903
7800
      case EOP_EVAL:
7904
	case EOP_EVAL:
7801
      case EOP_EVAL10:
7905
	case EOP_EVAL10:
7802
        {
7906
	  {
7803
        uschar *save_sub = sub;
7907
	  uschar *save_sub = sub;
7804
        uschar *error = NULL;
7908
	  uschar *error = NULL;
7805
        int_eximarith_t n = eval_expr(&sub, (c == EOP_EVAL10), &error, FALSE);
7909
	  int_eximarith_t n = eval_expr(&sub, (c == EOP_EVAL10), &error, FALSE);
7806
        if (error)
7910
	  if (error)
7807
          {
7911
	    {
7808
          expand_string_message = string_sprintf("error in expression "
7912
	    expand_string_message = string_sprintf("error in expression "
7809
            "evaluation: %s (after processing \"%.*s\")", error,
7913
	      "evaluation: %s (after processing \"%.*s\")", error,
7810
	    (int)(sub-save_sub), save_sub);
7914
	      (int)(sub-save_sub), save_sub);
7811
          goto EXPAND_FAILED;
7915
	    goto EXPAND_FAILED;
7812
          }
7916
	    }
7813
        yield = string_fmt_append(yield, PR_EXIM_ARITH, n);
7917
	  yield = string_fmt_append(yield, PR_EXIM_ARITH, n);
7814
        continue;
7918
	  break;
7815
        }
7919
	  }
7816
7920
7817
      /* Handle time period formatting */
7921
	/* Handle time period formatting */
7818
7922
7819
      case EOP_TIME_EVAL:
7923
	case EOP_TIME_EVAL:
7820
        {
7924
	  {
7821
        int n = readconf_readtime(sub, 0, FALSE);
7925
	  int n = readconf_readtime(sub, 0, FALSE);
7822
        if (n < 0)
7926
	  if (n < 0)
7823
          {
7927
	    {
7824
          expand_string_message = string_sprintf("string \"%s\" is not an "
7928
	    expand_string_message = string_sprintf("string \"%s\" is not an "
7825
            "Exim time interval in \"%s\" operator", sub, name);
7929
	      "Exim time interval in \"%s\" operator", sub, name);
7826
          goto EXPAND_FAILED;
7930
	    goto EXPAND_FAILED;
7827
          }
7931
	    }
7828
        yield = string_fmt_append(yield, "%d", n);
7932
	  yield = string_fmt_append(yield, "%d", n);
7829
        continue;
7933
	  break;
7830
        }
7934
	  }
7831
7935
7832
      case EOP_TIME_INTERVAL:
7936
	case EOP_TIME_INTERVAL:
7833
        {
7937
	  {
7834
        int n;
7938
	  int n;
7835
        uschar *t = read_number(&n, sub);
7939
	  uschar *t = read_number(&n, sub);
7836
        if (*t != 0) /* Not A Number*/
7940
	  if (*t != 0) /* Not A Number*/
7837
          {
7941
	    {
7838
          expand_string_message = string_sprintf("string \"%s\" is not a "
7942
	    expand_string_message = string_sprintf("string \"%s\" is not a "
7839
            "positive number in \"%s\" operator", sub, name);
7943
	      "positive number in \"%s\" operator", sub, name);
7840
          goto EXPAND_FAILED;
7944
	    goto EXPAND_FAILED;
7841
          }
7945
	    }
7842
        t = readconf_printtime(n);
7946
	  t = readconf_printtime(n);
7843
        yield = string_cat(yield, t);
7947
	  yield = string_cat(yield, t);
7844
        continue;
7948
	  break;
7845
        }
7949
	  }
7846
7950
7847
      /* Convert string to base64 encoding */
7951
	/* Convert string to base64 encoding */
7848
7952
7849
      case EOP_STR2B64:
7953
	case EOP_STR2B64:
7850
      case EOP_BASE64:
7954
	case EOP_BASE64:
7851
	{
7955
	  {
7852
#ifndef DISABLE_TLS
7956
#ifndef DISABLE_TLS
7853
	uschar * s = vp && *(void **)vp->value
7957
	  uschar * s = vp && *(void **)vp->value
7854
	  ? tls_cert_der_b64(*(void **)vp->value)
7958
	    ? tls_cert_der_b64(*(void **)vp->value)
7855
	  : b64encode(CUS sub, Ustrlen(sub));
7959
	    : b64encode(CUS sub, Ustrlen(sub));
7856
#else
7960
#else
7857
	uschar * s = b64encode(CUS sub, Ustrlen(sub));
7961
	  uschar * s = b64encode(CUS sub, Ustrlen(sub));
7858
#endif
7962
#endif
7859
	yield = string_cat(yield, s);
7963
	  yield = string_cat(yield, s);
7860
	continue;
7964
	  break;
7861
	}
7965
	  }
7862
7966
7863
      case EOP_BASE64D:
7967
	case EOP_BASE64D:
7864
        {
7968
	  {
7865
        uschar * s;
7969
	  uschar * s;
7866
        int len = b64decode(sub, &s);
7970
	  int len = b64decode(sub, &s);
7867
	if (len < 0)
7971
	  if (len < 0)
7868
          {
7972
	    {
7869
          expand_string_message = string_sprintf("string \"%s\" is not "
7973
	    expand_string_message = string_sprintf("string \"%s\" is not "
7870
            "well-formed for \"%s\" operator", sub, name);
7974
	      "well-formed for \"%s\" operator", sub, name);
7871
          goto EXPAND_FAILED;
7975
	    goto EXPAND_FAILED;
7872
          }
7976
	    }
7873
        yield = string_cat(yield, s);
7977
	  yield = string_cat(yield, s);
7874
        continue;
7978
	  break;
7875
        }
7979
	  }
7876
7980
7877
      /* strlen returns the length of the string */
7981
	/* strlen returns the length of the string */
7878
7982
7879
      case EOP_STRLEN:
7983
	case EOP_STRLEN:
7880
        yield = string_fmt_append(yield, "%d", Ustrlen(sub));
7984
	  yield = string_fmt_append(yield, "%d", Ustrlen(sub));
7881
        continue;
7985
	  break;
7882
7986
7883
      /* length_n or l_n takes just the first n characters or the whole string,
7987
	/* length_n or l_n takes just the first n characters or the whole string,
7884
      whichever is the shorter;
7988
	whichever is the shorter;
7885
7989
7886
      substr_m_n, and s_m_n take n characters from offset m; negative m take
7990
	substr_m_n, and s_m_n take n characters from offset m; negative m take
7887
      from the end; l_n is synonymous with s_0_n. If n is omitted in substr it
7991
	from the end; l_n is synonymous with s_0_n. If n is omitted in substr it
7888
      takes the rest, either to the right or to the left.
7992
	takes the rest, either to the right or to the left.
7889
7993
7890
      hash_n or h_n makes a hash of length n from the string, yielding n
7994
	hash_n or h_n makes a hash of length n from the string, yielding n
7891
      characters from the set a-z; hash_n_m makes a hash of length n, but
7995
	characters from the set a-z; hash_n_m makes a hash of length n, but
7892
      uses m characters from the set a-zA-Z0-9.
7996
	uses m characters from the set a-zA-Z0-9.
7893
7997
7894
      nhash_n returns a single number between 0 and n-1 (in text form), while
7998
	nhash_n returns a single number between 0 and n-1 (in text form), while
7895
      nhash_n_m returns a div/mod hash as two numbers "a/b". The first lies
7999
	nhash_n_m returns a div/mod hash as two numbers "a/b". The first lies
7896
      between 0 and n-1 and the second between 0 and m-1. */
8000
	between 0 and n-1 and the second between 0 and m-1. */
7897
8001
7898
      case EOP_LENGTH:
8002
	case EOP_LENGTH:
7899
      case EOP_L:
8003
	case EOP_L:
7900
      case EOP_SUBSTR:
8004
	case EOP_SUBSTR:
7901
      case EOP_S:
8005
	case EOP_S:
7902
      case EOP_HASH:
8006
	case EOP_HASH:
7903
      case EOP_H:
8007
	case EOP_H:
7904
      case EOP_NHASH:
8008
	case EOP_NHASH:
7905
      case EOP_NH:
8009
	case EOP_NH:
7906
        {
8010
	  {
7907
        int sign = 1;
8011
	  int sign = 1;
7908
        int value1 = 0;
8012
	  int value1 = 0;
7909
        int value2 = -1;
8013
	  int value2 = -1;
7910
        int *pn;
8014
	  int *pn;
7911
        int len;
8015
	  int len;
7912
        uschar *ret;
8016
	  uschar *ret;
7913
8017
7914
        if (!arg)
8018
	  if (!arg)
7915
          {
8019
	    {
7916
          expand_string_message = string_sprintf("missing values after %s",
8020
	    expand_string_message = string_sprintf("missing values after %s",
7917
            name);
8021
	      name);
7918
          goto EXPAND_FAILED;
8022
	    goto EXPAND_FAILED;
7919
          }
8023
	    }
7920
8024
7921
        /* "length" has only one argument, effectively being synonymous with
8025
	  /* "length" has only one argument, effectively being synonymous with
7922
        substr_0_n. */
8026
	  substr_0_n. */
7923
8027
7924
        if (c == EOP_LENGTH || c == EOP_L)
8028
	  if (c == EOP_LENGTH || c == EOP_L)
7925
          {
8029
	    {
7926
          pn = &value2;
8030
	    pn = &value2;
7927
          value2 = 0;
8031
	    value2 = 0;
7928
          }
8032
	    }
7929
8033
7930
        /* The others have one or two arguments; for "substr" the first may be
8034
	  /* The others have one or two arguments; for "substr" the first may be
7931
        negative. The second being negative means "not supplied". */
8035
	  negative. The second being negative means "not supplied". */
7932
8036
7933
        else
8037
	  else
7934
          {
8038
	    {
7935
          pn = &value1;
8039
	    pn = &value1;
7936
          if (name[0] == 's' && *arg == '-') { sign = -1; arg++; }
8040
	    if (name[0] == 's' && *arg == '-') { sign = -1; arg++; }
7937
          }
8041
	    }
7938
8042
7939
        /* Read up to two numbers, separated by underscores */
8043
	  /* Read up to two numbers, separated by underscores */
7940
8044
7941
        ret = arg;
8045
	  ret = arg;
7942
        while (*arg != 0)
8046
	  while (*arg != 0)
7943
          {
8047
	    {
7944
          if (arg != ret && *arg == '_' && pn == &value1)
8048
	    if (arg != ret && *arg == '_' && pn == &value1)
7945
            {
8049
	      {
7946
            pn = &value2;
8050
	      pn = &value2;
7947
            value2 = 0;
8051
	      value2 = 0;
7948
            if (arg[1] != 0) arg++;
8052
	      if (arg[1] != 0) arg++;
7949
            }
8053
	      }
7950
          else if (!isdigit(*arg))
8054
	    else if (!isdigit(*arg))
7951
            {
8055
	      {
7952
            expand_string_message =
8056
	      expand_string_message =
7953
              string_sprintf("non-digit after underscore in \"%s\"", name);
8057
		string_sprintf("non-digit after underscore in \"%s\"", name);
7954
            goto EXPAND_FAILED;
8058
	      goto EXPAND_FAILED;
7955
            }
8059
	      }
7956
          else *pn = (*pn)*10 + *arg++ - '0';
8060
	    else *pn = (*pn)*10 + *arg++ - '0';
7957
          }
8061
	    }
7958
        value1 *= sign;
8062
	  value1 *= sign;
7959
8063
7960
        /* Perform the required operation */
8064
	  /* Perform the required operation */
7961
8065
7962
        ret = c == EOP_HASH || c == EOP_H
8066
	  ret = c == EOP_HASH || c == EOP_H
7963
	  ? compute_hash(sub, value1, value2, &len)
8067
	    ? compute_hash(sub, value1, value2, &len)
7964
	  : c == EOP_NHASH || c == EOP_NH
8068
	    : c == EOP_NHASH || c == EOP_NH
7965
	  ? compute_nhash(sub, value1, value2, &len)
8069
	    ? compute_nhash(sub, value1, value2, &len)
7966
	  : extract_substr(sub, value1, value2, &len);
8070
	    : extract_substr(sub, value1, value2, &len);
7967
        if (!ret) goto EXPAND_FAILED;
8071
	  if (!ret) goto EXPAND_FAILED;
7968
8072
7969
        yield = string_catn(yield, ret, len);
8073
	  yield = string_catn(yield, ret, len);
7970
        continue;
8074
	  break;
7971
        }
8075
	  }
7972
8076
7973
      /* Stat a path */
8077
	/* Stat a path */
7974
8078
7975
      case EOP_STAT:
8079
	case EOP_STAT:
7976
        {
8080
	  {
7977
        uschar smode[12];
8081
	  uschar smode[12];
7978
        uschar **modetable[3];
8082
	  uschar **modetable[3];
7979
        mode_t mode;
8083
	  mode_t mode;
7980
        struct stat st;
8084
	  struct stat st;
7981
8085
7982
        if (expand_forbid & RDO_EXISTS)
8086
	  if (expand_forbid & RDO_EXISTS)
7983
          {
8087
	    {
7984
          expand_string_message = US"Use of the stat() expansion is not permitted";
8088
	    expand_string_message = US"Use of the stat() expansion is not permitted";
7985
          goto EXPAND_FAILED;
8089
	    goto EXPAND_FAILED;
7986
          }
8090
	    }
7987
8091
7988
        if (stat(CS sub, &st) < 0)
8092
	  if (stat(CS sub, &st) < 0)
7989
          {
8093
	    {
7990
          expand_string_message = string_sprintf("stat(%s) failed: %s",
8094
	    expand_string_message = string_sprintf("stat(%s) failed: %s",
7991
            sub, strerror(errno));
8095
	      sub, strerror(errno));
7992
          goto EXPAND_FAILED;
8096
	    goto EXPAND_FAILED;
7993
          }
8097
	    }
7994
        mode = st.st_mode;
8098
	  mode = st.st_mode;
7995
        switch (mode & S_IFMT)
8099
	  switch (mode & S_IFMT)
7996
          {
8100
	    {
7997
          case S_IFIFO: smode[0] = 'p'; break;
8101
	    case S_IFIFO: smode[0] = 'p'; break;
7998
          case S_IFCHR: smode[0] = 'c'; break;
8102
	    case S_IFCHR: smode[0] = 'c'; break;
7999
          case S_IFDIR: smode[0] = 'd'; break;
8103
	    case S_IFDIR: smode[0] = 'd'; break;
8000
          case S_IFBLK: smode[0] = 'b'; break;
8104
	    case S_IFBLK: smode[0] = 'b'; break;
8001
          case S_IFREG: smode[0] = '-'; break;
8105
	    case S_IFREG: smode[0] = '-'; break;
8002
          default: smode[0] = '?'; break;
8106
	    default: smode[0] = '?'; break;
8003
          }
8107
	    }
8004
8108
8005
        modetable[0] = ((mode & 01000) == 0)? mtable_normal : mtable_sticky;
8109
	  modetable[0] = ((mode & 01000) == 0)? mtable_normal : mtable_sticky;
8006
        modetable[1] = ((mode & 02000) == 0)? mtable_normal : mtable_setid;
8110
	  modetable[1] = ((mode & 02000) == 0)? mtable_normal : mtable_setid;
8007
        modetable[2] = ((mode & 04000) == 0)? mtable_normal : mtable_setid;
8111
	  modetable[2] = ((mode & 04000) == 0)? mtable_normal : mtable_setid;
8008
8112
8009
        for (int i = 0; i < 3; i++)
8113
	  for (int i = 0; i < 3; i++)
8010
          {
8114
	    {
8011
          memcpy(CS(smode + 7 - i*3), CS(modetable[i][mode & 7]), 3);
8115
	    memcpy(CS(smode + 7 - i*3), CS(modetable[i][mode & 7]), 3);
8012
          mode >>= 3;
8116
	    mode >>= 3;
8013
          }
8117
	    }
8014
8118
8015
        smode[10] = 0;
8119
	  smode[10] = 0;
8016
        yield = string_fmt_append(yield,
8120
	  yield = string_fmt_append(yield,
8017
	  "mode=%04lo smode=%s inode=%ld device=%ld links=%ld "
8121
	    "mode=%04lo smode=%s inode=%ld device=%ld links=%ld "
8018
          "uid=%ld gid=%ld size=" OFF_T_FMT " atime=%ld mtime=%ld ctime=%ld",
8122
	    "uid=%ld gid=%ld size=" OFF_T_FMT " atime=%ld mtime=%ld ctime=%ld",
8019
          (long)(st.st_mode & 077777), smode, (long)st.st_ino,
8123
	    (long)(st.st_mode & 077777), smode, (long)st.st_ino,
8020
          (long)st.st_dev, (long)st.st_nlink, (long)st.st_uid,
8124
	    (long)st.st_dev, (long)st.st_nlink, (long)st.st_uid,
8021
          (long)st.st_gid, st.st_size, (long)st.st_atime,
8125
	    (long)st.st_gid, st.st_size, (long)st.st_atime,
8022
          (long)st.st_mtime, (long)st.st_ctime);
8126
	    (long)st.st_mtime, (long)st.st_ctime);
8023
        continue;
8127
	  break;
8024
        }
8128
	  }
8025
8129
8026
      /* vaguely random number less than N */
8130
	/* vaguely random number less than N */
8027
8131
8028
      case EOP_RANDINT:
8132
	case EOP_RANDINT:
8029
        {
8133
	  {
8030
        int_eximarith_t max = expanded_string_integer(sub, TRUE);
8134
	  int_eximarith_t max = expanded_string_integer(sub, TRUE);
8031
8135
8032
        if (expand_string_message)
8136
	  if (expand_string_message)
8033
          goto EXPAND_FAILED;
8137
	    goto EXPAND_FAILED;
8034
        yield = string_fmt_append(yield, "%d", vaguely_random_number((int)max));
8138
	  yield = string_fmt_append(yield, "%d", vaguely_random_number((int)max));
8035
        continue;
8139
	  break;
8036
        }
8140
	  }
8037
8141
8038
      /* Reverse IP, including IPv6 to dotted-nibble */
8142
	/* Reverse IP, including IPv6 to dotted-nibble */
8039
8143
8040
      case EOP_REVERSE_IP:
8144
	case EOP_REVERSE_IP:
8041
        {
8145
	  {
8042
        int family, maskptr;
8146
	  int family, maskptr;
8043
        uschar reversed[128];
8147
	  uschar reversed[128];
8044
8148
8045
        family = string_is_ip_address(sub, &maskptr);
8149
	  family = string_is_ip_address(sub, &maskptr);
8046
        if (family == 0)
8150
	  if (family == 0)
8047
          {
8151
	    {
8048
          expand_string_message = string_sprintf(
8152
	    expand_string_message = string_sprintf(
8049
              "reverse_ip() not given an IP address [%s]", sub);
8153
		"reverse_ip() not given an IP address [%s]", sub);
8050
          goto EXPAND_FAILED;
8154
	    goto EXPAND_FAILED;
8051
          }
8155
	    }
8052
        invert_address(reversed, sub);
8156
	  invert_address(reversed, sub);
8053
        yield = string_cat(yield, reversed);
8157
	  yield = string_cat(yield, reversed);
8054
        continue;
8158
	  break;
8055
        }
8159
	  }
8056
8160
8057
      /* Unknown operator */
8161
	/* Unknown operator */
8058
8162
8059
      default:
8163
	default:
8060
	expand_string_message =
8164
	  expand_string_message =
8061
	  string_sprintf("unknown expansion operator \"%s\"", name);
8165
	    string_sprintf("unknown expansion operator \"%s\"", name);
8062
	goto EXPAND_FAILED;
8166
	  goto EXPAND_FAILED;
8063
      }
8167
	}	/* EOP_* switch */
8168
8169
       DEBUG(D_expand)
8170
	{
8171
	const uschar * s = yield->s + start;
8172
	int i = yield->ptr - start;
8173
	BOOL tainted = is_tainted(s);
8174
8175
	DEBUG(D_noutf8)
8176
	  {
8177
	  debug_printf_indent("|-----op-res: %.*s\n", i, s);
8178
	  if (tainted)
8179
	    {
8180
	    debug_printf_indent("%s     \\__", skipping ? "|     " : "      ");
8181
	    debug_print_taint(yield->s);
8182
	    }
8183
	  }
8184
	else
8185
	  {
8186
	  debug_printf_indent(UTF8_VERT_RIGHT
8187
	    UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
8188
	    "op-res: %.*s\n", i, s);
8189
	  if (tainted)
8190
	    {
8191
	    debug_printf_indent("%s",
8192
	      skipping
8193
	      ? UTF8_VERT "             " : "           " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ);
8194
	    debug_print_taint(yield->s);
8195
	    }
8196
	  }
8197
	}
8198
       continue;
8199
       }
8064
    }
8200
    }
8065
8201
8202
  /* Not an item or an operator */
8066
  /* Handle a plain name. If this is the first thing in the expansion, release
8203
  /* Handle a plain name. If this is the first thing in the expansion, release
8067
  the pre-allocated buffer. If the result data is known to be in a new buffer,
8204
  the pre-allocated buffer. If the result data is known to be in a new buffer,
8068
  newsize will be set to the size of that buffer, and we can just point at that
8205
  newsize will be set to the size of that buffer, and we can just point at that
Lines 8072-8089 Link Here
8072
						/*{*/
8209
						/*{*/
8073
  if (*s++ == '}')
8210
  if (*s++ == '}')
8074
    {
8211
    {
8212
    const uschar * value;
8075
    int len;
8213
    int len;
8076
    int newsize = 0;
8214
    int newsize = 0;
8077
    gstring * g = NULL;
8215
    gstring * g = NULL;
8078
8216
8079
    if (!yield)
8217
    if (!yield)
8080
      g = store_get(sizeof(gstring), FALSE);
8218
      g = store_get(sizeof(gstring), GET_UNTAINTED);
8081
    else if (yield->ptr == 0)
8219
    else if (yield->ptr == 0)
8082
      {
8220
      {
8083
      if (resetok) reset_point = store_reset(reset_point);
8221
      if (resetok) reset_point = store_reset(reset_point);
8084
      yield = NULL;
8222
      yield = NULL;
8085
      reset_point = store_mark();
8223
      reset_point = store_mark();
8086
      g = store_get(sizeof(gstring), FALSE);	/* alloc _before_ calling find_variable() */
8224
      g = store_get(sizeof(gstring), GET_UNTAINTED);	/* alloc _before_ calling find_variable() */
8087
      }
8225
      }
8088
    if (!(value = find_variable(name, FALSE, skipping, &newsize)))
8226
    if (!(value = find_variable(name, FALSE, skipping, &newsize)))
8089
      {
8227
      {
Lines 8098-8104 Link Here
8098
      yield = g;
8236
      yield = g;
8099
      yield->size = newsize;
8237
      yield->size = newsize;
8100
      yield->ptr = len;
8238
      yield->ptr = len;
8101
      yield->s = value;
8239
      yield->s = US value; /* known to be in new store i.e. a copy, so deconst safe */
8102
      }
8240
      }
8103
    else
8241
    else
8104
      yield = string_catn(yield, value, len);
8242
      yield = string_catn(yield, value, len);
Lines 8116-8122 Link Here
8116
/* If we hit the end of the string when ket_ends is set, there is a missing
8254
/* If we hit the end of the string when ket_ends is set, there is a missing
8117
terminating brace. */
8255
terminating brace. */
8118
8256
8119
if (ket_ends && *s == 0)
8257
if (ket_ends && !*s)
8120
  {
8258
  {
8121
  expand_string_message = malformed_header
8259
  expand_string_message = malformed_header
8122
    ? US"missing } at end of string - could be header name not terminated by colon"
8260
    ? US"missing } at end of string - could be header name not terminated by colon"
Lines 8149-8156 Link Here
8149
    debug_printf_indent("%sresult: %s\n",
8287
    debug_printf_indent("%sresult: %s\n",
8150
      skipping ? "|-----" : "\\_____", yield->s);
8288
      skipping ? "|-----" : "\\_____", yield->s);
8151
    if (tainted)
8289
    if (tainted)
8152
      debug_printf_indent("%s     \\__(tainted)\n",
8290
      {
8153
	skipping ? "|     " : "      ");
8291
      debug_printf_indent("%s     \\__", skipping ? "|     " : "      ");
8292
      debug_print_taint(yield->s);
8293
      }
8154
    if (skipping)
8294
    if (skipping)
8155
      debug_printf_indent("\\___skipping: result is not used\n");
8295
      debug_printf_indent("\\___skipping: result is not used\n");
8156
    }
8296
    }
Lines 8164-8172 Link Here
8164
      skipping ? UTF8_VERT_RIGHT : UTF8_UP_RIGHT,
8304
      skipping ? UTF8_VERT_RIGHT : UTF8_UP_RIGHT,
8165
      yield->s);
8305
      yield->s);
8166
    if (tainted)
8306
    if (tainted)
8167
      debug_printf_indent("%s(tainted)\n",
8307
      {
8308
      debug_printf_indent("%s",
8168
	skipping
8309
	skipping
8169
	? UTF8_VERT "             " : "           " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ);
8310
	? UTF8_VERT "             " : "           " UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ);
8311
      debug_print_taint(yield->s);
8312
      }
8170
    if (skipping)
8313
    if (skipping)
8171
      debug_printf_indent(UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
8314
      debug_printf_indent(UTF8_UP_RIGHT UTF8_HORIZ UTF8_HORIZ UTF8_HORIZ
8172
	"skipping: result is not used\n");
8315
	"skipping: result is not used\n");
Lines 8193-8198 Link Here
8193
EXPAND_FAILED:
8336
EXPAND_FAILED:
8194
if (left) *left = s;
8337
if (left) *left = s;
8195
DEBUG(D_expand)
8338
DEBUG(D_expand)
8339
  {
8196
  DEBUG(D_noutf8)
8340
  DEBUG(D_noutf8)
8197
    {
8341
    {
8198
    debug_printf_indent("|failed to expand: %s\n", string);
8342
    debug_printf_indent("|failed to expand: %s\n", string);
Lines 8212-8217 Link Here
8212
    if (f.expand_string_forcedfail)
8356
    if (f.expand_string_forcedfail)
8213
      debug_printf_indent(UTF8_UP_RIGHT "failure was forced\n");
8357
      debug_printf_indent(UTF8_UP_RIGHT "failure was forced\n");
8214
    }
8358
    }
8359
  }
8215
if (resetok_p && !resetok) *resetok_p = FALSE;
8360
if (resetok_p && !resetok) *resetok_p = FALSE;
8216
expand_level--;
8361
expand_level--;
8217
return NULL;
8362
return NULL;
Lines 8519-8524 Link Here
8519
  const uschar *var_data;
8664
  const uschar *var_data;
8520
} err_ctx;
8665
} err_ctx;
8521
8666
8667
/* Called via tree_walk, which allows nonconst name/data.  Our usage is const. */
8522
static void
8668
static void
8523
assert_variable_notin(uschar * var_name, uschar * var_data, void * ctx)
8669
assert_variable_notin(uschar * var_name, uschar * var_data, void * ctx)
8524
{
8670
{
Lines 8540-8552 Link Here
8540
tree_walk(acl_var_c, assert_variable_notin, &e);
8686
tree_walk(acl_var_c, assert_variable_notin, &e);
8541
tree_walk(acl_var_m, assert_variable_notin, &e);
8687
tree_walk(acl_var_m, assert_variable_notin, &e);
8542
8688
8543
/* check auth<n> variables */
8689
/* check auth<n> variables.
8690
assert_variable_notin() treats as const, so deconst is safe. */
8544
for (int i = 0; i < AUTH_VARS; i++) if (auth_vars[i])
8691
for (int i = 0; i < AUTH_VARS; i++) if (auth_vars[i])
8545
  assert_variable_notin(US"auth<n>", auth_vars[i], &e);
8692
  assert_variable_notin(US"auth<n>", US auth_vars[i], &e);
8546
8693
8547
/* check regex<n> variables */
8694
/* check regex<n> variables. assert_variable_notin() treats as const. */
8548
for (int i = 0; i < REGEX_VARS; i++) if (regex_vars[i])
8695
for (int i = 0; i < REGEX_VARS; i++) if (regex_vars[i])
8549
  assert_variable_notin(US"regex<n>", regex_vars[i], &e);
8696
  assert_variable_notin(US"regex<n>", US regex_vars[i], &e);
8550
8697
8551
/* check known-name variables */
8698
/* check known-name variables */
8552
for (var_entry * v = var_table; v < var_table + var_table_size; v++)
8699
for (var_entry * v = var_table; v < var_table + var_table_size; v++)
Lines 8577-8587 Link Here
8577
8724
8578
8725
8579
BOOL
8726
BOOL
8580
regex_match_and_setup(const pcre *re, uschar *subject, int options, int setup)
8727
regex_match_and_setup(const pcre2_code *re, uschar *subject, int options, int setup)
8581
{
8728
{
8582
int ovector[3*(EXPAND_MAXN+1)];
8729
int ovec[3*(EXPAND_MAXN+1)];
8583
int n = pcre_exec(re, NULL, subject, Ustrlen(subject), 0, PCRE_EOPT|options,
8730
int n = pcre_exec(re, NULL, subject, Ustrlen(subject), 0, PCRE_EOPT|options,
8584
  ovector, nelem(ovector));
8731
  ovec, nelem(ovec));
8585
BOOL yield = n >= 0;
8732
BOOL yield = n >= 0;
8586
if (n == 0) n = EXPAND_MAXN + 1;
8733
if (n == 0) n = EXPAND_MAXN + 1;
8587
if (yield)
8734
if (yield)
Lines 8589-8596 Link Here
8589
  expand_nmax = setup < 0 ? 0 : setup + 1;
8736
  expand_nmax = setup < 0 ? 0 : setup + 1;
8590
  for (int nn = setup < 0 ? 0 : 2; nn < n*2; nn += 2)
8737
  for (int nn = setup < 0 ? 0 : 2; nn < n*2; nn += 2)
8591
    {
8738
    {
8592
    expand_nstring[expand_nmax] = subject + ovector[nn];
8739
    expand_nstring[expand_nmax] = subject + ovec[nn];
8593
    expand_nlength[expand_nmax++] = ovector[nn+1] - ovector[nn];
8740
    expand_nlength[expand_nmax++] = ovec[nn+1] - ovec[nn];
8594
    }
8741
    }
8595
  expand_nmax--;
8742
  expand_nmax--;
8596
  }
8743
  }
Lines 8606-8611 Link Here
8606
debug_file = stderr;
8753
debug_file = stderr;
8607
debug_fd = fileno(debug_file);
8754
debug_fd = fileno(debug_file);
8608
big_buffer = malloc(big_buffer_size);
8755
big_buffer = malloc(big_buffer_size);
8756
store_init();
8609
8757
8610
for (int i = 1; i < argc; i++)
8758
for (int i = 1; i < argc; i++)
8611
  {
8759
  {
(-)exim.orig/src/filter.c (-165 / +176 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 27-33 Link Here
27
  struct condition_block *c;
27
  struct condition_block *c;
28
  struct filter_cmd      *f;
28
  struct filter_cmd      *f;
29
  int                     i;
29
  int                     i;
30
  uschar                 *u;
30
  const uschar            *u;
31
};
31
};
32
32
33
/* Local structures used in this module */
33
/* Local structures used in this module */
Lines 67-73 Link Here
67
67
68
enum { had_neither, had_else, had_elif, had_endif };
68
enum { had_neither, had_else, had_elif, had_endif };
69
69
70
static BOOL read_command_list(uschar **, filter_cmd ***, BOOL);
70
static BOOL read_command_list(const uschar **, filter_cmd ***, BOOL);
71
71
72
72
73
/* The string arguments for the mail command. The header line ones (that are
73
/* The string arguments for the mail command. The header line ones (that are
Lines 252-259 Link Here
252
Returns:           pointer to next non-whitespace character
252
Returns:           pointer to next non-whitespace character
253
*/
253
*/
254
254
255
static uschar *
255
static const uschar *
256
nextsigchar(uschar *ptr, BOOL comment_allowed)
256
nextsigchar(const uschar *ptr, BOOL comment_allowed)
257
{
257
{
258
for (;;)
258
for (;;)
259
  {
259
  {
Lines 290-297 Link Here
290
Returns:    pointer to the next significant character after the word
290
Returns:    pointer to the next significant character after the word
291
*/
291
*/
292
292
293
static uschar *
293
static const uschar *
294
nextword(uschar *ptr, uschar *buffer, int size, BOOL bracket)
294
nextword(const uschar *ptr, uschar *buffer, int size, BOOL bracket)
295
{
295
{
296
uschar *bp = buffer;
296
uschar *bp = buffer;
297
while (*ptr != 0 && !isspace(*ptr) &&
297
while (*ptr != 0 && !isspace(*ptr) &&
Lines 326-338 Link Here
326
Returns:     the next significant character after the item
326
Returns:     the next significant character after the item
327
*/
327
*/
328
328
329
static uschar *
329
static const uschar *
330
nextitem(uschar *ptr, uschar *buffer, int size, BOOL bracket)
330
nextitem(const uschar *ptr, uschar *buffer, int size, BOOL bracket)
331
{
331
{
332
uschar *bp = buffer;
332
uschar *bp = buffer;
333
if (*ptr != '\"') return nextword(ptr, buffer, size, bracket);
333
if (*ptr != '\"') return nextword(ptr, buffer, size, bracket);
334
334
335
while (*(++ptr) != 0 && *ptr != '\"' && *ptr != '\n')
335
while (*++ptr && *ptr != '\"' && *ptr != '\n')
336
  {
336
  {
337
  if (bp - buffer >= size - 1)
337
  if (bp - buffer >= size - 1)
338
    {
338
    {
Lines 345-351 Link Here
345
    {
345
    {
346
    if (isspace(ptr[1]))    /* \<whitespace>NL<whitespace> ignored */
346
    if (isspace(ptr[1]))    /* \<whitespace>NL<whitespace> ignored */
347
      {
347
      {
348
      uschar *p = ptr + 1;
348
      const uschar *p = ptr + 1;
349
      while (*p != '\n' && isspace(*p)) p++;
349
      while (*p != '\n' && isspace(*p)) p++;
350
      if (*p == '\n')
350
      if (*p == '\n')
351
        {
351
        {
Lines 385-391 Link Here
385
*/
385
*/
386
386
387
static int
387
static int
388
get_number(uschar *s, BOOL *ok)
388
get_number(const uschar *s, BOOL *ok)
389
{
389
{
390
int value, count;
390
int value, count;
391
*ok = FALSE;
391
*ok = FALSE;
Lines 416-423 Link Here
416
Returns:          points to next character after "then"
416
Returns:          points to next character after "then"
417
*/
417
*/
418
418
419
static uschar *
419
static const uschar *
420
read_condition(uschar *ptr, condition_block **cond, BOOL toplevel)
420
read_condition(const uschar *ptr, condition_block **cond, BOOL toplevel)
421
{
421
{
422
uschar buffer[1024];
422
uschar buffer[1024];
423
BOOL testfor = TRUE;
423
BOOL testfor = TRUE;
Lines 434-440 Link Here
434
434
435
  /* reaching the end of the input is an error. */
435
  /* reaching the end of the input is an error. */
436
436
437
  if (*ptr == 0)
437
  if (!*ptr)
438
    {
438
    {
439
    *error_pointer = US"\"then\" missing at end of filter file";
439
    *error_pointer = US"\"then\" missing at end of filter file";
440
    break;
440
    break;
Lines 477-483 Link Here
477
  else
477
  else
478
    {
478
    {
479
    ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
479
    ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
480
    if (*error_pointer != NULL) break;
480
    if (*error_pointer) break;
481
481
482
    /* "Then" at the start of a condition is an error */
482
    /* "Then" at the start of a condition is an error */
483
483
Lines 498-504 Link Here
498
498
499
    /* Build a condition block from the specific word. */
499
    /* Build a condition block from the specific word. */
500
500
501
    c = store_get(sizeof(condition_block), FALSE);
501
    c = store_get(sizeof(condition_block), GET_UNTAINTED);
502
    c->left.u = c->right.u = NULL;
502
    c->left.u = c->right.u = NULL;
503
    c->testfor = testfor;
503
    c->testfor = testfor;
504
    testfor = TRUE;
504
    testfor = TRUE;
Lines 518-524 Link Here
518
      for (;;)
518
      for (;;)
519
        {
519
        {
520
        string_item *aa;
520
        string_item *aa;
521
        uschar *saveptr = ptr;
521
        const uschar * saveptr = ptr;
522
        ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
522
        ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
523
        if (*error_pointer) break;
523
        if (*error_pointer) break;
524
        if (Ustrcmp(buffer, "alias") != 0)
524
        if (Ustrcmp(buffer, "alias") != 0)
Lines 528-534 Link Here
528
          }
528
          }
529
        ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
529
        ptr = nextitem(ptr, buffer, sizeof(buffer), TRUE);
530
        if (*error_pointer) break;
530
        if (*error_pointer) break;
531
        aa = store_get(sizeof(string_item), FALSE);
531
        aa = store_get(sizeof(string_item), GET_UNTAINTED);
532
        aa->text = string_copy(buffer);
532
        aa->text = string_copy(buffer);
533
        aa->next = c->left.a;
533
        aa->next = c->left.a;
534
        c->left.a = aa;
534
        c->left.a = aa;
Lines 569-575 Link Here
569
    else
569
    else
570
      {
570
      {
571
      int i;
571
      int i;
572
      uschar *isptr = NULL;
572
      const uschar *isptr = NULL;
573
573
574
      c->left.u = string_copy(buffer);
574
      c->left.u = string_copy(buffer);
575
      ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
575
      ptr = nextword(ptr, buffer, sizeof(buffer), TRUE);
Lines 655-672 Link Here
655
655
656
  else
656
  else
657
    {
657
    {
658
    uschar *saveptr = ptr;
658
//    const uschar *saveptr = ptr;
659
    ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
659
    ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
660
    if (*error_pointer) break;
660
    if (*error_pointer) break;
661
661
662
    /* "Then" terminates a toplevel condition; otherwise a closing bracket
662
    /* "Then" terminates a toplevel condition; otherwise a closing bracket
663
    has been omitted. Put a string terminator at the start of "then" so
663
    has been omitted. Put a string terminator at the start of "then" so
664
    that reflecting the condition can be done when testing. */
664
    that reflecting the condition can be done when testing. */
665
    /*XXX This stops us doing a constification job in this file, unfortunately.
666
    Comment it out and see if anything breaks.
667
    With one addition down at DEFERFREEZEFAIL it passes the testsuite. */
665
668
666
    if (Ustrcmp(buffer, "then") == 0)
669
    if (Ustrcmp(buffer, "then") == 0)
667
      {
670
      {
668
      if (toplevel) *saveptr = 0;
671
//      if (toplevel) *saveptr = 0;
669
      else *error_pointer = string_sprintf("missing \")\" at end of "
672
//      else
673
   if (!toplevel)
674
      *error_pointer = string_sprintf("missing \")\" at end of "
670
          "condition near line %d of filter file", line_number);
675
          "condition near line %d of filter file", line_number);
671
      break;
676
      break;
672
      }
677
      }
Lines 679-685 Link Here
679
684
680
    else if (Ustrcmp(buffer, "and") == 0)
685
    else if (Ustrcmp(buffer, "and") == 0)
681
      {
686
      {
682
      condition_block *andc = store_get(sizeof(condition_block), FALSE);
687
      condition_block * andc = store_get(sizeof(condition_block), GET_UNTAINTED);
683
      andc->parent = current_parent;
688
      andc->parent = current_parent;
684
      andc->type = cond_and;
689
      andc->type = cond_and;
685
      andc->testfor = TRUE;
690
      andc->testfor = TRUE;
Lines 697-704 Link Here
697
702
698
    else if (Ustrcmp(buffer, "or") == 0)
703
    else if (Ustrcmp(buffer, "or") == 0)
699
      {
704
      {
700
      condition_block *orc = store_get(sizeof(condition_block), FALSE);
705
      condition_block * orc = store_get(sizeof(condition_block), GET_UNTAINTED);
701
      condition_block *or_parent = NULL;
706
      condition_block * or_parent = NULL;
702
707
703
      if (current_parent)
708
      if (current_parent)
704
        {
709
        {
Lines 837-843 Link Here
837
*/
842
*/
838
843
839
static BOOL
844
static BOOL
840
read_command(uschar **pptr, filter_cmd ***lastcmdptr)
845
read_command(const uschar **pptr, filter_cmd ***lastcmdptr)
841
{
846
{
842
int command, i, cmd_bit;
847
int command, i, cmd_bit;
843
filter_cmd *new, **newlastcmdptr;
848
filter_cmd *new, **newlastcmdptr;
Lines 845-852 Link Here
845
BOOL was_seen_or_unseen = FALSE;
850
BOOL was_seen_or_unseen = FALSE;
846
BOOL was_noerror = FALSE;
851
BOOL was_noerror = FALSE;
847
uschar buffer[1024];
852
uschar buffer[1024];
848
uschar *ptr = *pptr;
853
const uschar *ptr = *pptr;
849
uschar *saveptr;
854
const uschar *saveptr;
850
uschar *fmsg = NULL;
855
uschar *fmsg = NULL;
851
856
852
/* Read the next word and find which command it is. Command words are normally
857
/* Read the next word and find which command it is. Command words are normally
Lines 855-860 Link Here
855
as brackets are allowed in conditions and users will expect not to require
860
as brackets are allowed in conditions and users will expect not to require
856
white space here. */
861
white space here. */
857
862
863
*buffer = '\0';	/* compiler quietening */
864
858
if (Ustrncmp(ptr, "if(", 3) == 0)
865
if (Ustrncmp(ptr, "if(", 3) == 0)
859
  {
866
  {
860
  Ustrcpy(buffer, US"if");
867
  Ustrcpy(buffer, US"if");
Lines 868-874 Link Here
868
else
875
else
869
  {
876
  {
870
  ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
877
  ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
871
  if (*error_pointer != NULL) return FALSE;
878
  if (*error_pointer) return FALSE;
872
  }
879
  }
873
880
874
for (command = 0; command < command_list_count; command++)
881
for (command = 0; command < command_list_count; command++)
Lines 907-917 Link Here
907
  case testprint_command:
914
  case testprint_command:
908
915
909
  ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
916
  ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
910
  if (*buffer == 0)
917
  if (!*buffer)
911
    *error_pointer = string_sprintf("\"%s\" requires an argument "
918
    *error_pointer = string_sprintf("\"%s\" requires an argument "
912
      "near line %d of filter file", command_list[command], line_number);
919
      "near line %d of filter file", command_list[command], line_number);
913
920
914
  if (*error_pointer != NULL) yield = FALSE; else
921
  if (*error_pointer) yield = FALSE; else
915
    {
922
    {
916
    union argtypes argument, second_argument;
923
    union argtypes argument, second_argument;
917
924
Lines 921-933 Link Here
921
      {
928
      {
922
      argument.u = string_copy(buffer);
929
      argument.u = string_copy(buffer);
923
      ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
930
      ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
924
      if (*buffer == 0 || Ustrcmp(buffer, "to") != 0)
931
      if (!*buffer || Ustrcmp(buffer, "to") != 0)
925
        *error_pointer = string_sprintf("\"to\" expected in \"add\" command "
932
        *error_pointer = string_sprintf("\"to\" expected in \"add\" command "
926
          "near line %d of filter file", line_number);
933
          "near line %d of filter file", line_number);
927
      else
934
      else
928
        {
935
        {
929
        ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
936
        ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
930
        if (*buffer == 0)
937
        if (!*buffer)
931
          *error_pointer = string_sprintf("value missing after \"to\" "
938
          *error_pointer = string_sprintf("value missing after \"to\" "
932
            "near line %d of filter file", line_number);
939
            "near line %d of filter file", line_number);
933
        else second_argument.u = string_copy(buffer);
940
        else second_argument.u = string_copy(buffer);
Lines 963-969 Link Here
963
      if (yield)
970
      if (yield)
964
        {
971
        {
965
        ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
972
        ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
966
        if (*buffer == 0)
973
        if (!*buffer)
967
          *error_pointer = string_sprintf("value missing after \"add\", "
974
          *error_pointer = string_sprintf("value missing after \"add\", "
968
            "\"remove\", or \"charset\" near line %d of filter file",
975
            "\"remove\", or \"charset\" near line %d of filter file",
969
              line_number);
976
              line_number);
Lines 999-1005 Link Here
999
1006
1000
      else if (command == deliver_command)
1007
      else if (command == deliver_command)
1001
        {
1008
        {
1002
        uschar *save_ptr = ptr;
1009
        const uschar *save_ptr = ptr;
1003
        ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1010
        ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1004
        if (Ustrcmp(buffer, "errors_to") == 0)
1011
        if (Ustrcmp(buffer, "errors_to") == 0)
1005
          {
1012
          {
Lines 1014-1022 Link Here
1014
    FALSE for logging commands, and it doesn't matter for testprint, as
1021
    FALSE for logging commands, and it doesn't matter for testprint, as
1015
    that doesn't change the "delivered" status. */
1022
    that doesn't change the "delivered" status. */
1016
1023
1017
    if (*error_pointer != NULL) yield = FALSE; else
1024
    if (*error_pointer) yield = FALSE;
1025
    else
1018
      {
1026
      {
1019
      new = store_get(sizeof(filter_cmd) + sizeof(union argtypes), FALSE);
1027
      new = store_get(sizeof(filter_cmd) + sizeof(union argtypes), GET_UNTAINTED);
1020
      new->next = NULL;
1028
      new->next = NULL;
1021
      **lastcmdptr = new;
1029
      **lastcmdptr = new;
1022
      *lastcmdptr = &(new->next);
1030
      *lastcmdptr = &(new->next);
Lines 1081-1087 Link Here
1081
1089
1082
  saveptr = ptr;
1090
  saveptr = ptr;
1083
  ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1091
  ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1084
  if (*saveptr != '\"' && (*buffer == 0 || Ustrcmp(buffer, "text") != 0))
1092
  if (*saveptr != '\"' && (!*buffer || Ustrcmp(buffer, "text") != 0))
1085
    {
1093
    {
1086
    ptr = saveptr;
1094
    ptr = saveptr;
1087
    fmsg = US"";
1095
    fmsg = US"";
Lines 1100-1111 Link Here
1100
  /* Finish has no arguments; fmsg defaults to NULL */
1108
  /* Finish has no arguments; fmsg defaults to NULL */
1101
1109
1102
  case finish_command:
1110
  case finish_command:
1103
  new = store_get(sizeof(filter_cmd), FALSE);
1111
  new = store_get(sizeof(filter_cmd), GET_UNTAINTED);
1104
  new->next = NULL;
1112
  new->next = NULL;
1105
  **lastcmdptr = new;
1113
  **lastcmdptr = new;
1106
  *lastcmdptr = &(new->next);
1114
  *lastcmdptr = &(new->next);
1107
  new->command = command;
1115
  new->command = command;
1108
  new->seen = seen_force? seen_value : FALSE;
1116
  new->seen = seen_force ? seen_value : FALSE;
1109
  new->args[0].u = fmsg;
1117
  new->args[0].u = fmsg;
1110
  break;
1118
  break;
1111
1119
Lines 1124-1133 Link Here
1124
1132
1125
  /* Set up the command block for if */
1133
  /* Set up the command block for if */
1126
1134
1127
  new = store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), FALSE);
1135
  new = store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), GET_UNTAINTED);
1128
  new->next = NULL;
1136
  new->next = NULL;
1129
  **lastcmdptr = new;
1137
  **lastcmdptr = new;
1130
  *lastcmdptr = &(new->next);
1138
  *lastcmdptr = &new->next;
1131
  new->command = command;
1139
  new->command = command;
1132
  new->seen = FALSE;
1140
  new->seen = FALSE;
1133
  new->args[0].u = NULL;
1141
  new->args[0].u = NULL;
Lines 1136-1143 Link Here
1136
1144
1137
  /* Read the condition */
1145
  /* Read the condition */
1138
1146
1139
  ptr = read_condition(ptr, &(new->args[0].c), TRUE);
1147
  ptr = read_condition(ptr, &new->args[0].c, TRUE);
1140
  if (*error_pointer != NULL) { yield = FALSE; break; }
1148
  if (*error_pointer) { yield = FALSE; break; }
1141
1149
1142
  /* Read the commands to be obeyed if the condition is true */
1150
  /* Read the commands to be obeyed if the condition is true */
1143
1151
Lines 1152-1158 Link Here
1152
    while (had_else_endif == had_elif)
1160
    while (had_else_endif == had_elif)
1153
      {
1161
      {
1154
      filter_cmd *newnew =
1162
      filter_cmd *newnew =
1155
        store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), FALSE);
1163
        store_get(sizeof(filter_cmd) + 4 * sizeof(union argtypes), GET_UNTAINTED);
1156
      new->args[2].f = newnew;
1164
      new->args[2].f = newnew;
1157
      new = newnew;
1165
      new = newnew;
1158
      new->next = NULL;
1166
      new->next = NULL;
Lines 1162-1169 Link Here
1162
      new->args[1].u = new->args[2].u = NULL;
1170
      new->args[1].u = new->args[2].u = NULL;
1163
      new->args[3].u = ptr;
1171
      new->args[3].u = ptr;
1164
1172
1165
      ptr = read_condition(ptr, &(new->args[0].c), TRUE);
1173
      ptr = read_condition(ptr, &new->args[0].c, TRUE);
1166
      if (*error_pointer != NULL) { yield = FALSE; break; }
1174
      if (*error_pointer) { yield = FALSE; break; }
1167
      newlastcmdptr = &(new->args[1].f);
1175
      newlastcmdptr = &(new->args[1].f);
1168
      if (!read_command_list(&ptr, &newlastcmdptr, TRUE))
1176
      if (!read_command_list(&ptr, &newlastcmdptr, TRUE))
1169
        yield = FALSE;
1177
        yield = FALSE;
Lines 1205-1214 Link Here
1205
1213
1206
  case mail_command:
1214
  case mail_command:
1207
  case vacation_command:
1215
  case vacation_command:
1208
  new = store_get(sizeof(filter_cmd) + mailargs_total * sizeof(union argtypes), FALSE);
1216
  new = store_get(sizeof(filter_cmd) + mailargs_total * sizeof(union argtypes), GET_UNTAINTED);
1209
  new->next = NULL;
1217
  new->next = NULL;
1210
  new->command = command;
1218
  new->command = command;
1211
  new->seen = seen_force? seen_value : FALSE;
1219
  new->seen = seen_force ? seen_value : FALSE;
1212
  new->noerror = noerror_force;
1220
  new->noerror = noerror_force;
1213
  for (i = 0; i < mailargs_total; i++) new->args[i].u = NULL;
1221
  for (i = 0; i < mailargs_total; i++) new->args[i].u = NULL;
1214
1222
Lines 1219-1231 Link Here
1219
1227
1220
  for (;;)
1228
  for (;;)
1221
    {
1229
    {
1222
    uschar *saveptr = ptr;
1230
    const uschar *saveptr = ptr;
1223
    ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1231
    ptr = nextword(ptr, buffer, sizeof(buffer), FALSE);
1224
    if (*error_pointer != NULL)
1232
    if (*error_pointer)
1225
      {
1233
      { yield = FALSE; break; }
1226
      yield = FALSE;
1227
      break;
1228
      }
1229
1234
1230
    /* Ensure "return" is followed by "message"; that's a complete option */
1235
    /* Ensure "return" is followed by "message"; that's a complete option */
1231
1236
Lines 1275-1285 Link Here
1275
    /* Found keyword, read the data item */
1280
    /* Found keyword, read the data item */
1276
1281
1277
    ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1282
    ptr = nextitem(ptr, buffer, sizeof(buffer), FALSE);
1278
    if (*error_pointer != NULL)
1283
    if (*error_pointer)
1279
      {
1284
      { yield = FALSE; break; }
1280
      yield = FALSE;
1281
      break;
1282
      }
1283
    else new->args[i].u = string_copy(buffer);
1285
    else new->args[i].u = string_copy(buffer);
1284
    }
1286
    }
1285
1287
Lines 1288-1305 Link Here
1288
1290
1289
  if (command == vacation_command)
1291
  if (command == vacation_command)
1290
    {
1292
    {
1291
    if (new->args[mailarg_index_file].u == NULL)
1293
    if (!new->args[mailarg_index_file].u)
1292
      {
1294
      {
1293
      new->args[mailarg_index_file].u = string_copy(US".vacation.msg");
1295
      new->args[mailarg_index_file].u = string_copy(US".vacation.msg");
1294
      new->args[mailarg_index_expand].u = US"";   /* not NULL => TRUE */
1296
      new->args[mailarg_index_expand].u = US"";   /* not NULL => TRUE */
1295
      }
1297
      }
1296
    if (new->args[mailarg_index_log].u == NULL)
1298
    if (!new->args[mailarg_index_log].u)
1297
      new->args[mailarg_index_log].u = string_copy(US".vacation.log");
1299
      new->args[mailarg_index_log].u = string_copy(US".vacation.log");
1298
    if (new->args[mailarg_index_once].u == NULL)
1300
    if (!new->args[mailarg_index_once].u)
1299
      new->args[mailarg_index_once].u = string_copy(US".vacation");
1301
      new->args[mailarg_index_once].u = string_copy(US".vacation");
1300
    if (new->args[mailarg_index_once_repeat].u == NULL)
1302
    if (!new->args[mailarg_index_once_repeat].u)
1301
      new->args[mailarg_index_once_repeat].u = string_copy(US"7d");
1303
      new->args[mailarg_index_once_repeat].u = string_copy(US"7d");
1302
    if (new->args[mailarg_index_subject].u == NULL)
1304
    if (!new->args[mailarg_index_subject].u)
1303
      new->args[mailarg_index_subject].u = string_copy(US"On vacation");
1305
      new->args[mailarg_index_subject].u = string_copy(US"On vacation");
1304
    }
1306
    }
1305
1307
Lines 1314-1320 Link Here
1314
1316
1315
  case seen_command:
1317
  case seen_command:
1316
  case unseen_command:
1318
  case unseen_command:
1317
  if (*ptr == 0)
1319
  if (!*ptr)
1318
    {
1320
    {
1319
    *error_pointer = string_sprintf("\"seen\" or \"unseen\" "
1321
    *error_pointer = string_sprintf("\"seen\" or \"unseen\" "
1320
      "near line %d is not followed by a command", line_number);
1322
      "near line %d is not followed by a command", line_number);
Lines 1335-1341 Link Here
1335
  /* So does noerror */
1337
  /* So does noerror */
1336
1338
1337
  case noerror_command:
1339
  case noerror_command:
1338
  if (*ptr == 0)
1340
  if (!*ptr)
1339
    {
1341
    {
1340
    *error_pointer = string_sprintf("\"noerror\" "
1342
    *error_pointer = string_sprintf("\"noerror\" "
1341
      "near line %d is not followed by a command", line_number);
1343
      "near line %d is not followed by a command", line_number);
Lines 1384-1394 Link Here
1384
*/
1386
*/
1385
1387
1386
static BOOL
1388
static BOOL
1387
read_command_list(uschar **pptr, filter_cmd ***lastcmdptr, BOOL conditional)
1389
read_command_list(const uschar **pptr, filter_cmd ***lastcmdptr, BOOL conditional)
1388
{
1390
{
1389
if (conditional) expect_endif++;
1391
if (conditional) expect_endif++;
1390
had_else_endif = had_neither;
1392
had_else_endif = had_neither;
1391
while (**pptr != 0 && had_else_endif == had_neither)
1393
while (**pptr && had_else_endif == had_neither)
1392
  {
1394
  {
1393
  if (!read_command(pptr, lastcmdptr)) return FALSE;
1395
  if (!read_command(pptr, lastcmdptr)) return FALSE;
1394
  *pptr = nextsigchar(*pptr, TRUE);
1396
  *pptr = nextsigchar(*pptr, TRUE);
Lines 1425-1434 Link Here
1425
test_condition(condition_block *c, BOOL toplevel)
1427
test_condition(condition_block *c, BOOL toplevel)
1426
{
1428
{
1427
BOOL yield = FALSE;
1429
BOOL yield = FALSE;
1428
const pcre *re;
1430
const uschar *exp[2], * p, * pp;
1429
uschar *exp[2], *p, *pp;
1430
const uschar *regcomp_error = NULL;
1431
int regcomp_error_offset;
1432
int val[2];
1431
int val[2];
1433
int i;
1432
int i;
1434
1433
Lines 1486-1493 Link Here
1486
1485
1487
  case cond_foranyaddress:
1486
  case cond_foranyaddress:
1488
  p = c->left.u;
1487
  p = c->left.u;
1489
  pp = expand_string(p);
1488
  if (!(pp = expand_cstring(p)))
1490
  if (pp == NULL)
1491
    {
1489
    {
1492
    *error_pointer = string_sprintf("failed to expand \"%s\" in "
1490
    *error_pointer = string_sprintf("failed to expand \"%s\" in "
1493
      "filter file: %s", p, expand_string_message);
1491
      "filter file: %s", p, expand_string_message);
Lines 1497-1515 Link Here
1497
  yield = FALSE;
1495
  yield = FALSE;
1498
  f.parse_allow_group = TRUE;     /* Allow group syntax */
1496
  f.parse_allow_group = TRUE;     /* Allow group syntax */
1499
1497
1500
  while (*pp != 0)
1498
  while (*pp)
1501
    {
1499
    {
1502
    uschar *error;
1500
    uschar *error;
1503
    int start, end, domain;
1501
    int start, end, domain;
1504
    int saveend;
1502
    uschar * s;
1505
1503
1506
    p = parse_find_address_end(pp, FALSE);
1504
    p = parse_find_address_end(pp, FALSE);
1507
    saveend = *p;
1505
    s = string_copyn(pp, p - pp);
1508
1506
1509
    *p = 0;
1510
    filter_thisaddress =
1507
    filter_thisaddress =
1511
      parse_extract_address(pp, &error, &start, &end, &domain, FALSE);
1508
      parse_extract_address(s, &error, &start, &end, &domain, FALSE);
1512
    *p = saveend;
1513
1509
1514
    if (filter_thisaddress)
1510
    if (filter_thisaddress)
1515
      {
1511
      {
Lines 1523-1529 Link Here
1523
      }
1519
      }
1524
1520
1525
    if (yield) break;
1521
    if (yield) break;
1526
    if (saveend == 0) break;
1522
    if (!*p) break;
1527
    pp = p + 1;
1523
    pp = p + 1;
1528
    }
1524
    }
1529
1525
Lines 1538-1545 Link Here
1538
  p = c->left.u;
1534
  p = c->left.u;
1539
  for (i = 0; i < 2; i++)
1535
  for (i = 0; i < 2; i++)
1540
    {
1536
    {
1541
    exp[i] = expand_string(p);
1537
    if (!(exp[i] = expand_cstring(p)))
1542
    if (exp[i] == NULL)
1543
      {
1538
      {
1544
      *error_pointer = string_sprintf("failed to expand \"%s\" in "
1539
      *error_pointer = string_sprintf("failed to expand \"%s\" in "
1545
        "filter file: %s", p, expand_string_message);
1540
        "filter file: %s", p, expand_string_message);
Lines 1561-1567 Link Here
1561
    break;
1556
    break;
1562
1557
1563
    case cond_contains:
1558
    case cond_contains:
1564
    yield = strstric(exp[0], exp[1], FALSE) != NULL;
1559
    yield = strstric_c(exp[0], exp[1], FALSE) != NULL;
1565
    break;
1560
    break;
1566
1561
1567
    case cond_CONTAINS:
1562
    case cond_CONTAINS:
Lines 1580-1613 Link Here
1580
    case cond_ENDS:
1575
    case cond_ENDS:
1581
      {
1576
      {
1582
      int len = Ustrlen(exp[1]);
1577
      int len = Ustrlen(exp[1]);
1583
      uschar *s = exp[0] + Ustrlen(exp[0]) - len;
1578
      const uschar *s = exp[0] + Ustrlen(exp[0]) - len;
1584
      yield = (s < exp[0])? FALSE :
1579
      yield = s < exp[0]
1585
        ((c->type == cond_ends)? strcmpic(s, exp[1]) : Ustrcmp(s, exp[1])) == 0;
1580
	? FALSE
1581
	: (c->type == cond_ends ? strcmpic(s, exp[1]) : Ustrcmp(s, exp[1])) == 0;
1586
      }
1582
      }
1587
    break;
1583
    break;
1588
1584
1589
    case cond_matches:
1585
    case cond_matches:
1590
    case cond_MATCHES:
1586
    case cond_MATCHES:
1591
    if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1592
        (debug_selector & D_filter) != 0)
1593
      {
1587
      {
1594
      debug_printf_indent("Match expanded arguments:\n");
1588
      const pcre2_code *re;
1595
      debug_printf_indent("  Subject = %s\n", exp[0]);
1589
      int err;
1596
      debug_printf_indent("  Pattern = %s\n", exp[1]);
1590
      PCRE2_SIZE offset;
1597
      }
1598
1591
1599
    if (!(re = pcre_compile(CS exp[1],
1592
      if ((filter_test != FTEST_NONE && debug_selector != 0) ||
1600
      PCRE_COPT | ((c->type == cond_matches)? PCRE_CASELESS : 0),
1593
	  (debug_selector & D_filter) != 0)
1601
      CCSS &regcomp_error, &regcomp_error_offset, NULL)))
1594
	{
1602
      {
1595
	debug_printf_indent("Match expanded arguments:\n");
1603
      *error_pointer = string_sprintf("error while compiling "
1596
	debug_printf_indent("  Subject = %s\n", exp[0]);
1604
        "regular expression \"%s\": %s at offset %d",
1597
	debug_printf_indent("  Pattern = %s\n", exp[1]);
1605
        exp[1], regcomp_error, regcomp_error_offset);
1598
	}
1606
      return FALSE;
1607
      }
1608
1599
1609
    yield = regex_match_and_setup(re, exp[0], PCRE_EOPT, -1);
1600
      if (!(re = pcre2_compile((PCRE2_SPTR)exp[1], PCRE2_ZERO_TERMINATED,
1610
    break;
1601
		  PCRE_COPT | (c->type == cond_matches ? PCRE2_CASELESS : 0),
1602
		  &err, &offset, pcre_cmp_ctx)))
1603
	{
1604
	uschar errbuf[128];
1605
	pcre2_get_error_message(err, errbuf, sizeof(errbuf));
1606
	*error_pointer = string_sprintf("error while compiling "
1607
	  "regular expression \"%s\": %s at offset %ld",
1608
	  exp[1], errbuf, (long)offset);
1609
	return FALSE;
1610
	}
1611
1612
      yield = regex_match_and_setup(re, exp[0], PCRE_EOPT, -1);
1613
      break;
1614
      }
1611
1615
1612
    /* For above and below, convert the strings to numbers */
1616
    /* For above and below, convert the strings to numbers */
1613
1617
Lines 1686-1702 Link Here
1686
1690
1687
  for (i = 0; i < (command_exparg_count[commands->command] & 15); i++)
1691
  for (i = 0; i < (command_exparg_count[commands->command] & 15); i++)
1688
    {
1692
    {
1689
    uschar *ss = commands->args[i].u;
1693
    const uschar *ss = commands->args[i].u;
1690
    if (!ss)
1694
    if (!ss)
1691
      expargs[i] = NULL;
1695
      expargs[i] = NULL;
1692
    else
1696
    else if (!(expargs[i] = expand_cstring(ss)))
1693
      if (!(expargs[i] = expand_string(ss)))
1697
      {
1694
        {
1698
      *error_pointer = string_sprintf("failed to expand \"%s\" in "
1695
        *error_pointer = string_sprintf("failed to expand \"%s\" in "
1699
	"%s command: %s", ss, command_list[commands->command],
1696
          "%s command: %s", ss, command_list[commands->command],
1700
	expand_string_message);
1697
          expand_string_message);
1701
      return FF_ERROR;
1698
        return FF_ERROR;
1702
      }
1699
        }
1700
    }
1703
    }
1701
1704
1702
  /* Now switch for each command, setting the "delivered" flag if any of them
1705
  /* Now switch for each command, setting the "delivered" flag if any of them
Lines 1892-1898 Link Here
1892
	if (expand_nmax >= 0 || filter_thisaddress != NULL)
1895
	if (expand_nmax >= 0 || filter_thisaddress != NULL)
1893
	  {
1896
	  {
1894
	  int ecount = expand_nmax >= 0 ? expand_nmax : -1;
1897
	  int ecount = expand_nmax >= 0 ? expand_nmax : -1;
1895
	  uschar **ss = store_get(sizeof(uschar *) * (ecount + 3), FALSE);
1898
	  uschar ** ss = store_get(sizeof(uschar *) * (ecount + 3), GET_UNTAINTED);
1896
1899
1897
	  addr->pipe_expandn = ss;
1900
	  addr->pipe_expandn = ss;
1898
	  if (!filter_thisaddress) filter_thisaddress = US"";
1901
	  if (!filter_thisaddress) filter_thisaddress = US"";
Lines 1951-1957 Link Here
1951
	  (long int)geteuid());
1954
	  (long int)geteuid());
1952
	if (log_fd < 0)
1955
	if (log_fd < 0)
1953
	  {
1956
	  {
1954
	  if (log_filename == NULL)
1957
	  if (!log_filename)
1955
	    {
1958
	    {
1956
	    *error_pointer = US"attempt to obey \"logwrite\" command "
1959
	    *error_pointer = US"attempt to obey \"logwrite\" command "
1957
	      "without a previous \"logfile\"";
1960
	      "without a previous \"logfile\"";
Lines 1960-1966 Link Here
1960
	  log_fd = Uopen(log_filename, O_CREAT|O_APPEND|O_WRONLY, log_mode);
1963
	  log_fd = Uopen(log_filename, O_CREAT|O_APPEND|O_WRONLY, log_mode);
1961
	  if (log_fd < 0)
1964
	  if (log_fd < 0)
1962
	    {
1965
	    {
1963
	    *error_pointer = string_open_failed(errno, "filter log file \"%s\"",
1966
	    *error_pointer = string_open_failed("filter log file \"%s\"",
1964
	      log_filename);
1967
	      log_filename);
1965
	    return FF_ERROR;
1968
	    return FF_ERROR;
1966
	    }
1969
	    }
Lines 1974-1982 Link Here
1974
	  }
1977
	  }
1975
	}
1978
	}
1976
      else
1979
      else
1977
	{
1980
	DEBUG(D_filter)
1978
	DEBUG(D_filter) debug_printf_indent("skipping logwrite (verifying or testing)\n");
1981
	  debug_printf_indent("skipping logwrite (verifying or testing)\n");
1979
	}
1980
      break;
1982
      break;
1981
1983
1982
      /* Header addition and removal is available only in the system filter. The
1984
      /* Header addition and removal is available only in the system filter. The
Lines 1989-2004 Link Here
1989
	s = expargs[0];
1991
	s = expargs[0];
1990
1992
1991
	if (filter_test != FTEST_NONE)
1993
	if (filter_test != FTEST_NONE)
1992
	  printf("Headers %s \"%s\"\n", (subtype == TRUE)? "add" :
1994
	  printf("Headers %s \"%s\"\n",
1993
	    (subtype == FALSE)? "remove" : "charset", string_printing(s));
1995
	    subtype == TRUE ? "add"
1996
	    : subtype == FALSE ? "remove"
1997
	    : "charset",
1998
	    string_printing(s));
1994
1999
1995
	if (subtype == TRUE)
2000
	if (subtype == TRUE)
1996
	  {
2001
	  {
1997
	  while (isspace(*s)) s++;
2002
	  while (isspace(*s)) s++;
1998
	  if (s[0] != 0)
2003
	  if (*s)
1999
	    {
2004
	    {
2000
	    header_add(htype_other, "%s%s", s, (s[Ustrlen(s)-1] == '\n')?
2005
	    header_add(htype_other, "%s%s", s,
2001
	      "" : "\n");
2006
	      s[Ustrlen(s)-1] == '\n' ? "" : "\n");
2002
	    header_last->type = header_checkname(header_last, FALSE);
2007
	    header_last->type = header_checkname(header_last, FALSE);
2003
	    if (header_last->type >= 'a') header_last->type = htype_other;
2008
	    if (header_last->type >= 'a') header_last->type = htype_other;
2004
	    }
2009
	    }
Lines 2007-2024 Link Here
2007
	else if (subtype == FALSE)
2012
	else if (subtype == FALSE)
2008
	  {
2013
	  {
2009
	  int sep = 0;
2014
	  int sep = 0;
2010
	  uschar *ss;
2015
	  const uschar * list = s;
2011
	  const uschar *list = s;
2016
2012
	  uschar buffer[128];
2017
	  for (uschar * ss; ss = string_nextinlist(&list, &sep, NULL, 0); )
2013
	  while ((ss = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))
2014
		 != NULL)
2015
	    header_remove(0, ss);
2018
	    header_remove(0, ss);
2016
	  }
2019
	  }
2017
2020
2018
	/* This setting lasts only while the filter is running; on exit, the
2021
	/* This setting lasts only while the filter is running; on exit, the
2019
	variable is reset to the previous value. */
2022
	variable is reset to the previous value. */
2020
2023
2021
	else headers_charset = s;	/*XXX loses track of const */
2024
	else headers_charset = s;
2022
	}
2025
	}
2023
      break;
2026
      break;
2024
2027
Lines 2041-2058 Link Here
2041
      ff_name = US"freeze";
2044
      ff_name = US"freeze";
2042
      ff_ret = FF_FREEZE;
2045
      ff_ret = FF_FREEZE;
2043
2046
2044
      DEFERFREEZEFAIL:
2047
    DEFERFREEZEFAIL:
2045
      fmsg = expargs[0];		/*XXX loses track of const */
2048
      *error_pointer = fmsg = US string_printing(Ustrlen(expargs[0]) > 1024
2046
      if (Ustrlen(fmsg) > 1024) Ustrcpy(fmsg + 1000, US" ... (truncated)");
2049
	? string_sprintf("%.1000s ... (truncated)", expargs[0])
2047
      fmsg = US string_printing(fmsg);
2050
	: string_copy(expargs[0]));
2048
      *error_pointer = fmsg;
2051
      for(uschar * s = fmsg; *s; s++)
2052
	if (!s[1] && *s == '\n') { *s = '\0'; break; }	/* drop trailing newline */
2049
2053
2050
      if (filter_test != FTEST_NONE)
2054
      if (filter_test != FTEST_NONE)
2051
	{
2055
	{
2052
	indent();
2056
	indent();
2053
	printf("%c%s text \"%s\"\n", toupper(ff_name[0]), ff_name+1, fmsg);
2057
	printf("%c%s text \"%s\"\n", toupper(ff_name[0]), ff_name+1, fmsg);
2054
	}
2058
	}
2055
      else DEBUG(D_filter) debug_printf_indent("Filter: %s \"%s\"\n", ff_name, fmsg);
2059
      else
2060
        DEBUG(D_filter) debug_printf_indent("Filter: %s \"%s\"\n", ff_name, fmsg);
2056
      return ff_ret;
2061
      return ff_ret;
2057
2062
2058
    case finish_command:
2063
    case finish_command:
Lines 2062-2080 Link Here
2062
	printf("%sinish\n", (commands->seen)? "Seen f" : "F");
2067
	printf("%sinish\n", (commands->seen)? "Seen f" : "F");
2063
	}
2068
	}
2064
      else
2069
      else
2065
	{
2066
	DEBUG(D_filter) debug_printf_indent("Filter: %sfinish\n",
2070
	DEBUG(D_filter) debug_printf_indent("Filter: %sfinish\n",
2067
	  (commands->seen)? " Seen " : "");
2071
	  commands->seen ? " Seen " : "");
2068
	}
2069
      finish_obeyed = TRUE;
2072
      finish_obeyed = TRUE;
2070
      return filter_delivered? FF_DELIVERED : FF_NOTDELIVERED;
2073
      return filter_delivered ? FF_DELIVERED : FF_NOTDELIVERED;
2071
2074
2072
    case if_command:
2075
    case if_command:
2073
	{
2076
	{
2074
	uschar *save_address = filter_thisaddress;
2077
	uschar *save_address = filter_thisaddress;
2075
	int ok = FF_DELIVERED;
2078
	int ok = FF_DELIVERED;
2076
	condition_value = test_condition(commands->args[0].c, TRUE);
2079
	condition_value = test_condition(commands->args[0].c, TRUE);
2077
	if (*error_pointer != NULL) ok = FF_ERROR; else
2080
	if (*error_pointer)
2081
	  ok = FF_ERROR;
2082
	else
2078
	  {
2083
	  {
2079
	  output_indent += 2;
2084
	  output_indent += 2;
2080
	  ok = interpret_commands(commands->args[condition_value? 1:2].f,
2085
	  ok = interpret_commands(commands->args[condition_value? 1:2].f,
Lines 2082-2088 Link Here
2082
	  output_indent -= 2;
2087
	  output_indent -= 2;
2083
	  }
2088
	  }
2084
	filter_thisaddress = save_address;
2089
	filter_thisaddress = save_address;
2085
	if (finish_obeyed || (ok != FF_DELIVERED && ok != FF_NOTDELIVERED))
2090
	if (finish_obeyed  ||  ok != FF_DELIVERED && ok != FF_NOTDELIVERED)
2086
	  return ok;
2091
	  return ok;
2087
	}
2092
	}
2088
      break;
2093
      break;
Lines 2094-2100 Link Here
2094
2099
2095
    case mail_command:
2100
    case mail_command:
2096
    case vacation_command:
2101
    case vacation_command:
2097
	if (return_path == NULL || return_path[0] == 0)
2102
	if (!return_path || !*return_path)
2098
	  {
2103
	  {
2099
	  if (filter_test != FTEST_NONE)
2104
	  if (filter_test != FTEST_NONE)
2100
	    printf("%s command ignored because return_path is empty\n",
2105
	    printf("%s command ignored because return_path is empty\n",
Lines 2124-2135 Link Here
2124
2129
2125
	for (i = 0; i < MAILARGS_STRING_COUNT; i++)
2130
	for (i = 0; i < MAILARGS_STRING_COUNT; i++)
2126
	  {
2131
	  {
2127
	  uschar *p;
2128
	  const uschar *s = expargs[i];
2132
	  const uschar *s = expargs[i];
2129
2133
2130
	  if (s == NULL) continue;
2134
	  if (!s) continue;
2131
2135
2132
	  if (i != mailarg_index_text) for (p = s; *p != 0; p++)
2136
	  if (i != mailarg_index_text) for (const uschar * p = s; *p; p++)
2133
	    {
2137
	    {
2134
	    int c = *p;
2138
	    int c = *p;
2135
	    if (i > mailarg_index_text)
2139
	    if (i > mailarg_index_text)
Lines 2159-2170 Link Here
2159
2163
2160
	      else
2164
	      else
2161
		{
2165
		{
2162
		uschar *pp;
2166
		const uschar *pp;
2163
		for (pp = p + 1;; pp++)
2167
		for (pp = p + 1;; pp++)
2164
		  {
2168
		  {
2165
		  c = *pp;
2169
		  c = *pp;
2166
		  if (c == ':' && pp != p + 1) break;
2170
		  if (c == ':' && pp != p + 1) break;
2167
		  if (c == 0 || c == ':' || isspace(*pp))
2171
		  if (!c || c == ':' || isspace(c))
2168
		    {
2172
		    {
2169
		    *error_pointer = string_sprintf("\\n not followed by space or "
2173
		    *error_pointer = string_sprintf("\\n not followed by space or "
2170
		      "valid header name in \"%.1024s\" in %s command",
2174
		      "valid header name in \"%.1024s\" in %s command",
Lines 2179-2192 Link Here
2179
2183
2180
	  /* The string is OK */
2184
	  /* The string is OK */
2181
2185
2182
	  commands->args[i].u = s;	/*XXX loses track of const */
2186
	  commands->args[i].u = s;
2183
	  }
2187
	  }
2184
2188
2185
	/* Proceed with mail or vacation command */
2189
	/* Proceed with mail or vacation command */
2186
2190
2187
	if (filter_test != FTEST_NONE)
2191
	if (filter_test != FTEST_NONE)
2188
	  {
2192
	  {
2189
	  uschar *to = commands->args[mailarg_index_to].u;
2193
	  const uschar *to = commands->args[mailarg_index_to].u;
2190
	  indent();
2194
	  indent();
2191
	  printf("%sail to: %s%s%s\n", (commands->seen)? "Seen m" : "M",
2195
	  printf("%sail to: %s%s%s\n", (commands->seen)? "Seen m" : "M",
2192
	    to ? to : US"<default>",
2196
	    to ? to : US"<default>",
Lines 2194-2200 Link Here
2194
	    commands->noerror ? " (noerror)" : "");
2198
	    commands->noerror ? " (noerror)" : "");
2195
	  for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2199
	  for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2196
	    {
2200
	    {
2197
	    uschar *arg = commands->args[i].u;
2201
	    const uschar *arg = commands->args[i].u;
2198
	    if (arg)
2202
	    if (arg)
2199
	      {
2203
	      {
2200
	      int len = Ustrlen(mailargs[i]);
2204
	      int len = Ustrlen(mailargs[i]);
Lines 2210-2224 Link Here
2210
	  }
2214
	  }
2211
	else
2215
	else
2212
	  {
2216
	  {
2213
	  uschar *tt;
2217
	  const uschar *tt;
2214
	  uschar *to = commands->args[mailarg_index_to].u;
2218
	  const uschar *to = commands->args[mailarg_index_to].u;
2215
	  gstring * log_addr = NULL;
2219
	  gstring * log_addr = NULL;
2216
2220
2217
	  if (!to) to = expand_string(US"$reply_address");
2221
	  if (!to) to = expand_string(US"$reply_address");
2218
	  while (isspace(*to)) to++;
2222
	  while (isspace(*to)) to++;
2219
2223
2220
	  for (tt = to; *tt != 0; tt++)     /* Get rid of newlines */
2224
	  for (tt = to; *tt; tt++)     /* Get rid of newlines */
2221
	    if (*tt == '\n') *tt = ' ';
2225
	    if (*tt == '\n')
2226
	      {
2227
	      uschar * s = string_copy(to);
2228
	      for (uschar * ss = s; *ss; ss++)
2229
		if (*ss == '\n') *ss = ' ';
2230
	      to = s;
2231
	      break;
2232
	      }
2222
2233
2223
	  DEBUG(D_filter)
2234
	  DEBUG(D_filter)
2224
	    {
2235
	    {
Lines 2229-2236 Link Here
2229
	      commands->noerror ? " (noerror)" : "");
2240
	      commands->noerror ? " (noerror)" : "");
2230
	    for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2241
	    for (i = 1; i < MAILARGS_STRING_COUNT; i++)
2231
	      {
2242
	      {
2232
	      uschar *arg = commands->args[i].u;
2243
	      const uschar *arg = commands->args[i].u;
2233
	      if (arg != NULL)
2244
	      if (arg)
2234
		{
2245
		{
2235
		int len = Ustrlen(mailargs[i]);
2246
		int len = Ustrlen(mailargs[i]);
2236
		while (len++ < 15) debug_printf_indent(" ");
2247
		while (len++ < 15) debug_printf_indent(" ");
Lines 2248-2254 Link Here
2248
	  string gets too long. */
2259
	  string gets too long. */
2249
2260
2250
	  tt = to;
2261
	  tt = to;
2251
	  while (*tt != 0)
2262
	  while (*tt)
2252
	    {
2263
	    {
2253
	    uschar *ss = parse_find_address_end(tt, FALSE);
2264
	    uschar *ss = parse_find_address_end(tt, FALSE);
2254
	    uschar *recipient, *errmess;
2265
	    uschar *recipient, *errmess;
Lines 2296-2302 Link Here
2296
	  addr->next = *generated;
2307
	  addr->next = *generated;
2297
	  *generated = addr;
2308
	  *generated = addr;
2298
2309
2299
	  addr->reply = store_get(sizeof(reply_item), FALSE);
2310
	  addr->reply = store_get(sizeof(reply_item), GET_UNTAINTED);
2300
	  addr->reply->from = NULL;
2311
	  addr->reply->from = NULL;
2301
	  addr->reply->to = string_copy(to);
2312
	  addr->reply->to = string_copy(to);
2302
	  addr->reply->file_expand =
2313
	  addr->reply->file_expand =
Lines 2324-2330 Link Here
2324
2335
2325
	  for (i = 1; i < mailargs_string_passed; i++)
2336
	  for (i = 1; i < mailargs_string_passed; i++)
2326
	    {
2337
	    {
2327
	    uschar *ss = commands->args[i].u;
2338
	    const uschar *ss = commands->args[i].u;
2328
	    *(USS((US addr->reply) + reply_offsets[i])) =
2339
	    *(USS((US addr->reply) + reply_offsets[i])) =
2329
	      ss ? string_copy(ss) : NULL;
2340
	      ss ? string_copy(ss) : NULL;
2330
	    }
2341
	    }
Lines 2497-2509 Link Here
2497
*/
2508
*/
2498
2509
2499
int
2510
int
2500
filter_interpret(uschar *filter, int options, address_item **generated,
2511
filter_interpret(const uschar *filter, int options, address_item **generated,
2501
  uschar **error)
2512
  uschar **error)
2502
{
2513
{
2503
int i;
2514
int i;
2504
int yield = FF_ERROR;
2515
int yield = FF_ERROR;
2505
uschar *ptr = filter;
2516
const uschar *ptr = filter;
2506
uschar *save_headers_charset = headers_charset;
2517
const uschar *save_headers_charset = headers_charset;
2507
filter_cmd *commands = NULL;
2518
filter_cmd *commands = NULL;
2508
filter_cmd **lastcmdptr = &commands;
2519
filter_cmd **lastcmdptr = &commands;
2509
2520
(-)exim.orig/src/filtertest.c (-11 / +12 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2021 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2009 */
6
/* Copyright (c) University of Cambridge 1995 - 2009 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 45-55 Link Here
45
body_linecount = 0;
46
body_linecount = 0;
46
header_size = message_size;
47
header_size = message_size;
47
48
48
if (!dot_ended && !feof(stdin))
49
if (!dot_ended && !stdin_feof())
49
  {
50
  {
50
  if (!f.dot_ends)
51
  if (!f.dot_ends)
51
    {
52
    {
52
    while ((ch = getc(stdin)) != EOF)
53
    while ((ch = stdin_getc(GETC_BUFFER_UNLIMITED)) != EOF)
53
      {
54
      {
54
      if (ch == 0) body_zerocount++;
55
      if (ch == 0) body_zerocount++;
55
      if (ch == '\n') body_linecount++;
56
      if (ch == '\n') body_linecount++;
Lines 62-68 Link Here
62
  else
63
  else
63
    {
64
    {
64
    int ch_state = 1;
65
    int ch_state = 1;
65
    while ((ch = getc(stdin)) != EOF)
66
    while ((ch = stdin_getc(GETC_BUFFER_UNLIMITED)) != EOF)
66
      {
67
      {
67
      if (ch == 0) body_zerocount++;
68
      if (ch == 0) body_zerocount++;
68
      switch (ch_state)
69
      switch (ch_state)
Lines 95-104 Link Here
95
      if (s > message_body_end + message_body_visible) s = message_body_end;
96
      if (s > message_body_end + message_body_visible) s = message_body_end;
96
      message_size++;
97
      message_size++;
97
      }
98
      }
98
    READ_END: ch = ch;  /* Some compilers don't like null statements */
99
    READ_END: ;
99
    }
100
    }
100
  if (s == message_body_end || s[-1] != '\n') body_linecount++;
101
  if (s == message_body_end || s[-1] != '\n') body_linecount++;
101
  }
102
  }
103
debug_printf("%s %d\n", __FUNCTION__, __LINE__);
102
104
103
message_body[body_len] = 0;
105
message_body[body_len] = 0;
104
message_body_size = message_size - header_size;
106
message_body_size = message_size - header_size;
Lines 112-118 Link Here
112
  int above = message_body_visible - below;
114
  int above = message_body_visible - below;
113
  if (above > 0)
115
  if (above > 0)
114
    {
116
    {
115
    uschar *temp = store_get(below, TRUE);
117
    uschar * temp = store_get(below, GET_UNTAINTED);
116
    memcpy(temp, message_body_end, below);
118
    memcpy(temp, message_body_end, below);
117
    memmove(message_body_end, s+1, above);
119
    memmove(message_body_end, s+1, above);
118
    memcpy(message_body_end + above, temp, below);
120
    memcpy(message_body_end + above, temp, below);
Lines 178-184 Link Here
178
  return FALSE;
180
  return FALSE;
179
  }
181
  }
180
182
181
filebuf = store_get(statbuf.st_size + 1, is_tainted(filename));
183
filebuf = store_get(statbuf.st_size + 1, filename);
182
rc = read(fd, filebuf, statbuf.st_size);
184
rc = read(fd, filebuf, statbuf.st_size);
183
(void)close(fd);
185
(void)close(fd);
184
186
Lines 250-256 Link Here
250
/* For a filter, set up the message_body variables and the message size if this
252
/* For a filter, set up the message_body variables and the message size if this
251
is the first time this function has been called. */
253
is the first time this function has been called. */
252
254
253
if (message_body == NULL) read_message_body(dot_ended);
255
if (!message_body) read_message_body(dot_ended);
254
256
255
/* Now pass the filter file to the function that interprets it. Because
257
/* Now pass the filter file to the function that interprets it. Because
256
filter_test is not FILTER_NONE, the interpreter will output comments about what
258
filter_test is not FILTER_NONE, the interpreter will output comments about what
Lines 269-278 Link Here
269
  }
271
  }
270
else
272
else
271
  {
273
  {
272
  yield = (filter_type == FILTER_SIEVE)?
274
  yield = filter_type == FILTER_SIEVE
273
    sieve_interpret(filebuf, RDO_REWRITE, NULL, NULL, NULL, NULL, &generated, &error)
275
    ? sieve_interpret(filebuf, RDO_REWRITE, NULL, NULL, NULL, NULL, &generated, &error)
274
    :
276
    : filter_interpret(filebuf, RDO_REWRITE, &generated, &error);
275
    filter_interpret(filebuf, RDO_REWRITE, &generated, &error);
276
  }
277
  }
277
278
278
return yield != FF_ERROR;
279
return yield != FF_ERROR;
(-)exim.orig/src/functions.h (-86 / +204 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 53-83 Link Here
53
extern void    tls_clean_env(void);
53
extern void    tls_clean_env(void);
54
extern BOOL    tls_client_start(client_conn_ctx *, smtp_connect_args *,
54
extern BOOL    tls_client_start(client_conn_ctx *, smtp_connect_args *,
55
		  void *, tls_support *, uschar **);
55
		  void *, tls_support *, uschar **);
56
extern void    tls_client_creds_reload(BOOL);
56
57
57
extern void    tls_close(void *, int);
58
extern void    tls_close(void *, int);
58
extern BOOL    tls_could_read(void);
59
extern BOOL    tls_could_getc(void);
59
extern void    tls_daemon_init(void);
60
extern void    tls_daemon_init(void);
61
extern int     tls_daemon_tick(void);
60
extern BOOL    tls_dropprivs_validate_require_cipher(BOOL);
62
extern BOOL    tls_dropprivs_validate_require_cipher(BOOL);
61
extern BOOL    tls_export_cert(uschar *, size_t, void *);
63
extern BOOL    tls_export_cert(uschar *, size_t, void *);
62
extern int     tls_feof(void);
64
extern int     tls_feof(void);
63
extern int     tls_ferror(void);
65
extern int     tls_ferror(void);
66
extern uschar *tls_field_from_dn(uschar *, const uschar *);
64
extern void    tls_free_cert(void **);
67
extern void    tls_free_cert(void **);
65
extern int     tls_getc(unsigned);
68
extern int     tls_getc(unsigned);
66
extern uschar *tls_getbuf(unsigned *);
69
extern uschar *tls_getbuf(unsigned *);
67
extern void    tls_get_cache(void);
70
extern void    tls_get_cache(unsigned);
71
extern BOOL    tls_hasc(void);
68
extern BOOL    tls_import_cert(const uschar *, void **);
72
extern BOOL    tls_import_cert(const uschar *, void **);
73
extern BOOL    tls_is_name_for_cert(const uschar *, void *);
74
# ifdef USE_OPENSSL
75
extern BOOL    tls_openssl_options_parse(uschar *, long *);
76
# endif
69
extern int     tls_read(void *, uschar *, size_t);
77
extern int     tls_read(void *, uschar *, size_t);
70
extern int     tls_server_start(const uschar *, uschar **);
78
extern int     tls_server_start(uschar **);
79
extern void    tls_shutdown_wr(void *);
71
extern BOOL    tls_smtp_buffered(void);
80
extern BOOL    tls_smtp_buffered(void);
72
extern int     tls_ungetc(int);
81
extern int     tls_ungetc(int);
82
#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
83
extern void    tls_watch_discard_event(int);
84
extern void    tls_watch_invalidate(void);
85
#endif
73
extern int     tls_write(void *, const uschar *, size_t, BOOL);
86
extern int     tls_write(void *, const uschar *, size_t, BOOL);
74
extern uschar *tls_validate_require_cipher(void);
87
extern uschar *tls_validate_require_cipher(void);
75
extern void    tls_version_report(FILE *);
88
extern gstring *tls_version_report(gstring *);
76
# ifdef USE_OPENSSL
77
extern BOOL    tls_openssl_options_parse(uschar *, long *);
78
# endif
79
extern uschar * tls_field_from_dn(uschar *, const uschar *);
80
extern BOOL    tls_is_name_for_cert(const uschar *, void *);
81
89
82
# ifdef SUPPORT_DANE
90
# ifdef SUPPORT_DANE
83
extern int     tlsa_lookup(const host_item *, dns_answer *, BOOL);
91
extern int     tlsa_lookup(const host_item *, dns_answer *, BOOL);
Lines 90-95 Link Here
90
98
91
extern acl_block *acl_read(uschar *(*)(void), uschar **);
99
extern acl_block *acl_read(uschar *(*)(void), uschar **);
92
extern int     acl_check(int, uschar *, uschar *, uschar **, uschar **);
100
extern int     acl_check(int, uschar *, uschar *, uschar **, uschar **);
101
extern uschar *acl_current_verb(void);
93
extern int     acl_eval(int, uschar *, uschar **, uschar **);
102
extern int     acl_eval(int, uschar *, uschar **, uschar **);
94
103
95
extern tree_node *acl_var_create(uschar *);
104
extern tree_node *acl_var_create(uschar *);
Lines 123-128 Link Here
123
extern gstring * auth_show_supported(gstring *);
132
extern gstring * auth_show_supported(gstring *);
124
extern uschar *auth_xtextencode(uschar *, int);
133
extern uschar *auth_xtextencode(uschar *, int);
125
extern int     auth_xtextdecode(uschar *, uschar **);
134
extern int     auth_xtextdecode(uschar *, uschar **);
135
extern uschar *authenticator_current_name(void);
126
136
127
#ifdef EXPERIMENTAL_ARC
137
#ifdef EXPERIMENTAL_ARC
128
extern gstring *authres_arc(gstring *);
138
extern gstring *authres_arc(gstring *);
Lines 139-148 Link Here
139
#endif
149
#endif
140
150
141
extern uschar *b64encode(const uschar *, int);
151
extern uschar *b64encode(const uschar *, int);
142
extern uschar *b64encode_taint(const uschar *, int, BOOL);
152
extern uschar *b64encode_taint(const uschar *, int, const void *);
143
extern int     b64decode(const uschar *, uschar **);
153
extern int     b64decode(const uschar *, uschar **);
144
extern int     bdat_getc(unsigned);
154
extern int     bdat_getc(unsigned);
145
extern uschar *bdat_getbuf(unsigned *);
155
extern uschar *bdat_getbuf(unsigned *);
156
extern BOOL    bdat_hasc(void);
146
extern int     bdat_ungetc(int);
157
extern int     bdat_ungetc(int);
147
extern void    bdat_flush_data(void);
158
extern void    bdat_flush_data(void);
148
159
Lines 176-194 Link Here
176
extern int     dcc_process(uschar **);
187
extern int     dcc_process(uschar **);
177
#endif
188
#endif
178
189
179
extern void    debug_logging_activate(uschar *, uschar *);
190
extern void    debug_logging_activate(const uschar *, const uschar *);
180
extern void    debug_logging_stop(void);
191
extern void    debug_logging_from_spool(const uschar *);
192
extern void    debug_logging_stop(BOOL);
181
extern void    debug_print_argv(const uschar **);
193
extern void    debug_print_argv(const uschar **);
182
extern void    debug_print_ids(uschar *);
194
extern void    debug_print_ids(uschar *);
183
extern void    debug_printf_indent(const char *, ...) PRINTF_FUNCTION(1,2);
195
extern void    debug_printf_indent(const char *, ...) PRINTF_FUNCTION(1,2);
184
extern void    debug_print_string(uschar *);
196
extern void    debug_print_string(uschar *);
185
extern void    debug_print_tree(tree_node *);
197
extern void    debug_print_tree(const char *, tree_node *);
186
extern void    debug_vprintf(int, const char *, va_list);
198
extern void    debug_vprintf(int, const char *, va_list);
199
extern void    debug_pretrigger_setup(const uschar *);
200
extern void    debug_pretrigger_discard(void);
187
extern void    debug_print_socket(int);
201
extern void    debug_print_socket(int);
202
extern void    debug_trigger_fire(void);
188
203
189
extern void    decode_bits(unsigned int *, size_t, int *,
204
extern void    decode_bits(unsigned int *, size_t, int *,
190
	           uschar *, bit_table *, int, uschar *, int);
205
	           const uschar *, bit_table *, int, uschar *, int);
191
extern void    delete_pid_file(void);
206
extern void    delete_pid_file(void);
207
extern void    deliver_local(address_item *, BOOL);
192
extern address_item *deliver_make_addr(uschar *, BOOL);
208
extern address_item *deliver_make_addr(uschar *, BOOL);
193
extern void    delivery_log(int, address_item *, int, uschar *);
209
extern void    delivery_log(int, address_item *, int, uschar *);
194
extern int     deliver_message(uschar *, BOOL, BOOL);
210
extern int     deliver_message(uschar *, BOOL, BOOL);
Lines 197-203 Link Here
197
extern int     deliver_split_address(address_item *);
213
extern int     deliver_split_address(address_item *);
198
extern void    deliver_succeeded(address_item *);
214
extern void    deliver_succeeded(address_item *);
199
215
200
extern uschar *deliver_get_sender_address (uschar *id);
201
extern void    delivery_re_exec(int);
216
extern void    delivery_re_exec(int);
202
217
203
extern void    die_tainted(const uschar *, const uschar *, int);
218
extern void    die_tainted(const uschar *, const uschar *, int);
Lines 227-233 Link Here
227
extern void    enq_end(uschar *);
242
extern void    enq_end(uschar *);
228
extern BOOL    enq_start(uschar *, unsigned);
243
extern BOOL    enq_start(uschar *, unsigned);
229
#ifndef DISABLE_EVENT
244
#ifndef DISABLE_EVENT
230
extern uschar *event_raise(uschar *, const uschar *, uschar *);
245
extern uschar *event_raise(uschar *, const uschar *, uschar *, int *);
231
extern void    msg_event_raise(const uschar *, const address_item *);
246
extern void    msg_event_raise(const uschar *, const address_item *);
232
#endif
247
#endif
233
248
Lines 236-242 Link Here
236
extern void    exim_exit(int) NORETURN;
251
extern void    exim_exit(int) NORETURN;
237
extern void    exim_gettime(struct timeval *);
252
extern void    exim_gettime(struct timeval *);
238
extern void    exim_nullstd(void);
253
extern void    exim_nullstd(void);
239
extern void    exim_setugid(uid_t, gid_t, BOOL, uschar *);
254
extern void    exim_setugid(uid_t, gid_t, BOOL, const uschar *);
240
extern void    exim_underbar_exit(int) NORETURN;
255
extern void    exim_underbar_exit(int) NORETURN;
241
extern void    exim_wait_tick(struct timeval *, int);
256
extern void    exim_wait_tick(struct timeval *, int);
242
extern int     exp_bool(address_item *addr,
257
extern int     exp_bool(address_item *addr,
Lines 255-266 Link Here
255
270
256
extern BOOL    fd_ready(int, time_t);
271
extern BOOL    fd_ready(int, time_t);
257
272
258
extern int     filter_interpret(uschar *, int, address_item **, uschar **);
273
extern int     filter_interpret(const uschar *, int, address_item **, uschar **);
259
extern BOOL    filter_personal(string_item *, BOOL);
274
extern BOOL    filter_personal(string_item *, BOOL);
260
extern BOOL    filter_runtest(int, uschar *, BOOL, BOOL);
275
extern BOOL    filter_runtest(int, uschar *, BOOL, BOOL);
261
extern BOOL    filter_system_interpret(address_item **, uschar **);
276
extern BOOL    filter_system_interpret(address_item **, uschar **);
262
277
263
extern uschar * fn_hdrs_added(void);
278
extern uschar * fn_hdrs_added(void);
279
extern void    force_fd(int, int);
264
280
265
extern void    header_add(int, const char *, ...);
281
extern void    header_add(int, const char *, ...);
266
extern header_line *header_add_at_position_internal(BOOL, uschar *, BOOL, int, const char *, ...);
282
extern header_line *header_add_at_position_internal(BOOL, uschar *, BOOL, int, const char *, ...);
Lines 308-314 Link Here
308
extern int     ipv6_nmtoa(int *, uschar *);
324
extern int     ipv6_nmtoa(int *, uschar *);
309
325
310
extern uschar *local_part_quote(uschar *);
326
extern uschar *local_part_quote(uschar *);
311
extern int     log_open_as_exim(uschar *);
327
extern int     log_open_as_exim(const uschar * const);
312
extern void    log_close_all(void);
328
extern void    log_close_all(void);
313
329
314
extern macro_item * macro_create(const uschar *, const uschar *, BOOL);
330
extern macro_item * macro_create(const uschar *, const uschar *, BOOL);
Lines 331-336 Link Here
331
                 unsigned int *, int, BOOL, const uschar **);
347
                 unsigned int *, int, BOOL, const uschar **);
332
extern int     match_check_string(const uschar *, const uschar *, int, BOOL, BOOL, BOOL,
348
extern int     match_check_string(const uschar *, const uschar *, int, BOOL, BOOL, BOOL,
333
                 const uschar **);
349
                 const uschar **);
350
351
extern void    message_start(void);
352
extern void    message_tidyup(void);
334
extern void    md5_end(md5 *, const uschar *, int, uschar *);
353
extern void    md5_end(md5 *, const uschar *, int, uschar *);
335
extern void    md5_mid(md5 *, const uschar *);
354
extern void    md5_mid(md5 *, const uschar *);
336
extern void    md5_start(md5 *);
355
extern void    md5_start(md5 *);
Lines 361-373 Link Here
361
380
362
extern uschar *parse_extract_address(const uschar *, uschar **, int *, int *, int *,
381
extern uschar *parse_extract_address(const uschar *, uschar **, int *, int *, int *,
363
                 BOOL);
382
                 BOOL);
364
extern int     parse_forward_list(uschar *, int, address_item **, uschar **,
383
extern int     parse_forward_list(const uschar *, int, address_item **, uschar **,
365
                 const uschar *, uschar *, error_block **);
384
                 const uschar *, const uschar *, error_block **);
366
extern uschar *parse_find_address_end(uschar *, BOOL);
385
extern uschar *parse_find_address_end(const uschar *, BOOL);
367
extern const uschar *parse_find_at(const uschar *);
386
extern const uschar *parse_find_at(const uschar *);
368
extern const uschar *parse_fix_phrase(const uschar *, int);
387
extern const uschar *parse_fix_phrase(const uschar *, int);
369
extern const uschar *parse_message_id(const uschar *, uschar **, uschar **);
388
extern const uschar *parse_message_id(const uschar *, uschar **, uschar **);
370
extern const uschar *parse_quote_2047(const uschar *, int, uschar *, BOOL);
389
extern const uschar *parse_quote_2047(const uschar *, int, const uschar *,
390
				      BOOL);
371
extern const uschar *parse_date_time(const uschar *str, time_t *t);
391
extern const uschar *parse_date_time(const uschar *str, time_t *t);
372
extern void priv_drop_temp(const uid_t, const gid_t);
392
extern void priv_drop_temp(const uid_t, const gid_t);
373
extern void priv_restore(void);
393
extern void priv_restore(void);
Lines 381-396 Link Here
381
extern unsigned queue_count(void);
401
extern unsigned queue_count(void);
382
extern unsigned queue_count_cached(void);
402
extern unsigned queue_count_cached(void);
383
extern void    queue_list(int, uschar **, int);
403
extern void    queue_list(int, uschar **, int);
384
#ifdef EXPERIMENTAL_QUEUE_RAMP
404
#ifndef DISABLE_QUEUE_RAMP
385
extern void    queue_notify_daemon(const uschar * hostname);
405
extern void    queue_notify_daemon(const uschar * hostname);
386
#endif
406
#endif
387
extern void    queue_run(uschar *, uschar *, BOOL);
407
extern void    queue_run(uschar *, uschar *, BOOL);
388
408
389
extern int     random_number(int);
409
extern int     random_number(int);
390
extern const uschar *rc_to_string(int);
410
extern const uschar *rc_to_string(int);
391
extern int     rda_interpret(redirect_block *, int, uschar *, uschar *,
411
extern int     rda_interpret(redirect_block *, int, const uschar *, const uschar *,
392
                 uschar *, uschar *, uschar *, ugid_block *, address_item **,
412
                 const uschar *, const uschar *, const uschar *, const ugid_block *, address_item **,
393
                 uschar **, error_block **, int *, uschar *);
413
                 uschar **, error_block **, int *, const uschar *);
394
extern int     rda_is_filter(const uschar *);
414
extern int     rda_is_filter(const uschar *);
395
extern BOOL    readconf_depends(driver_instance *, uschar *);
415
extern BOOL    readconf_depends(driver_instance *, uschar *);
396
extern void    readconf_driver_init(uschar *, driver_instance **,
416
extern void    readconf_driver_init(uschar *, driver_instance **,
Lines 415-422 Link Here
415
#ifdef WITH_CONTENT_SCAN
435
#ifdef WITH_CONTENT_SCAN
416
extern int     regex(const uschar **);
436
extern int     regex(const uschar **);
417
#endif
437
#endif
418
extern BOOL    regex_match_and_setup(const pcre *, const uschar *, int, int);
438
extern BOOL    regex_match(const pcre2_code *, const uschar *, int, uschar **);
419
extern const pcre *regex_must_compile(const uschar *, BOOL, BOOL);
439
extern BOOL    regex_match_and_setup(const pcre2_code *, const uschar *, int, int);
440
extern const pcre2_code *regex_must_compile(const uschar *, BOOL, BOOL);
420
extern void    retry_add_item(address_item *, uschar *, int);
441
extern void    retry_add_item(address_item *, uschar *, int);
421
extern BOOL    retry_check_address(const uschar *, host_item *, uschar *, BOOL,
442
extern BOOL    retry_check_address(const uschar *, host_item *, uschar *, BOOL,
422
                 uschar **, uschar **);
443
                 uschar **, uschar **);
Lines 432-439 Link Here
432
extern const uschar *rewrite_one(const uschar *, int, BOOL *, BOOL, uschar *,
453
extern const uschar *rewrite_one(const uschar *, int, BOOL *, BOOL, uschar *,
433
                 rewrite_rule *);
454
                 rewrite_rule *);
434
extern void    rewrite_test(const uschar *);
455
extern void    rewrite_test(const uschar *);
435
extern uschar *rfc2047_decode2(uschar *, BOOL, uschar *, int, int *, int *,
456
extern uschar *rfc2047_decode2(uschar *, BOOL, const uschar *, int, int *,
436
                 uschar **);
457
				     int *, uschar **);
437
extern int     route_address(address_item *, address_item **, address_item **,
458
extern int     route_address(address_item *, address_item **, address_item **,
438
                 address_item **, address_item **, int);
459
                 address_item **, address_item **, int);
439
extern int     route_check_prefix(const uschar *, const uschar *, unsigned *);
460
extern int     route_check_prefix(const uschar *, const uschar *, unsigned *);
Lines 447-453 Link Here
447
extern void    route_init(void);
468
extern void    route_init(void);
448
extern gstring * route_show_supported(gstring *);
469
extern gstring * route_show_supported(gstring *);
449
extern void    route_tidyup(void);
470
extern void    route_tidyup(void);
471
extern uschar *router_current_name(void);
450
472
473
extern uschar *search_args(int, uschar *, uschar *, uschar **, const uschar *);
451
extern uschar *search_find(void *, const uschar *, uschar *, int,
474
extern uschar *search_find(void *, const uschar *, uschar *, int,
452
		 const uschar *, int, int, int *, const uschar *);
475
		 const uschar *, int, int, int *, const uschar *);
453
extern int     search_findtype(const uschar *, int);
476
extern int     search_findtype(const uschar *, int);
Lines 459-468 Link Here
459
extern void    sha1_end(hctx *, const uschar *, int, uschar *);
482
extern void    sha1_end(hctx *, const uschar *, int, uschar *);
460
extern void    sha1_mid(hctx *, const uschar *);
483
extern void    sha1_mid(hctx *, const uschar *);
461
extern void    sha1_start(hctx *);
484
extern void    sha1_start(hctx *);
462
extern int     sieve_interpret(uschar *, int, uschar *, uschar *, uschar *,
485
extern int     sieve_interpret(const uschar *, int, const uschar *,
463
                 uschar *, address_item **, uschar **);
486
		 const uschar *, const uschar *, const uschar *,
487
		 address_item **, uschar **);
464
extern void    sigalrm_handler(int);
488
extern void    sigalrm_handler(int);
465
extern BOOL    smtp_buffered(void);
489
extern int     smtp_boundsock(smtp_connect_args *);
466
extern void    smtp_closedown(uschar *);
490
extern void    smtp_closedown(uschar *);
467
extern void    smtp_command_timeout_exit(void) NORETURN;
491
extern void    smtp_command_timeout_exit(void) NORETURN;
468
extern void    smtp_command_sigterm_exit(void) NORETURN;
492
extern void    smtp_command_sigterm_exit(void) NORETURN;
Lines 471-478 Link Here
471
extern void    smtp_deliver_init(void);
495
extern void    smtp_deliver_init(void);
472
extern uschar *smtp_cmd_hist(void);
496
extern uschar *smtp_cmd_hist(void);
473
extern int     smtp_connect(smtp_connect_args *, const blob *);
497
extern int     smtp_connect(smtp_connect_args *, const blob *);
474
extern int     smtp_sock_connect(host_item *, int, int, uschar *,
475
		 transport_instance * tb, int, const blob *);
476
extern int     smtp_feof(void);
498
extern int     smtp_feof(void);
477
extern int     smtp_ferror(void);
499
extern int     smtp_ferror(void);
478
extern uschar *smtp_get_connection_info(void);
500
extern uschar *smtp_get_connection_info(void);
Lines 481-491 Link Here
481
extern BOOL    smtp_get_port(uschar *, address_item *, int *, uschar *);
503
extern BOOL    smtp_get_port(uschar *, address_item *, int *, uschar *);
482
extern int     smtp_getc(unsigned);
504
extern int     smtp_getc(unsigned);
483
extern uschar *smtp_getbuf(unsigned *);
505
extern uschar *smtp_getbuf(unsigned *);
484
extern void    smtp_get_cache(void);
506
extern void    smtp_get_cache(unsigned);
507
extern BOOL    smtp_hasc(void);
485
extern int     smtp_handle_acl_fail(int, int, uschar *, uschar *);
508
extern int     smtp_handle_acl_fail(int, int, uschar *, uschar *);
486
extern void    smtp_log_no_mail(void);
509
extern void    smtp_log_no_mail(void);
487
extern void    smtp_message_code(uschar **, int *, uschar **, uschar **, BOOL);
510
extern void    smtp_message_code(uschar **, int *, uschar **, uschar **, BOOL);
488
extern void    smtp_proxy_tls(void *, uschar *, size_t, int *, int) NORETURN;
511
extern void    smtp_proxy_tls(void *, uschar *, size_t, int *, int, const uschar *) NORETURN;
489
extern BOOL    smtp_read_response(void *, uschar *, int, int, int);
512
extern BOOL    smtp_read_response(void *, uschar *, int, int, int);
490
extern void   *smtp_reset(void *);
513
extern void   *smtp_reset(void *);
491
extern void    smtp_respond(uschar *, int, BOOL, uschar *);
514
extern void    smtp_respond(uschar *, int, BOOL, uschar *);
Lines 493-498 Link Here
493
extern void    smtp_port_for_connect(host_item *, int);
516
extern void    smtp_port_for_connect(host_item *, int);
494
extern void    smtp_send_prohibition_message(int, uschar *);
517
extern void    smtp_send_prohibition_message(int, uschar *);
495
extern int     smtp_setup_msg(void);
518
extern int     smtp_setup_msg(void);
519
extern int     smtp_sock_connect(smtp_connect_args *, int, const blob *);
496
extern BOOL    smtp_start_session(void);
520
extern BOOL    smtp_start_session(void);
497
extern int     smtp_ungetc(int);
521
extern int     smtp_ungetc(int);
498
extern BOOL    smtp_verify_helo(void);
522
extern BOOL    smtp_verify_helo(void);
Lines 506-518 Link Here
506
extern int     spool_open_datafile(uschar *);
530
extern int     spool_open_datafile(uschar *);
507
extern int     spool_open_temp(uschar *);
531
extern int     spool_open_temp(uschar *);
508
extern int     spool_read_header(uschar *, BOOL, BOOL);
532
extern int     spool_read_header(uschar *, BOOL, BOOL);
533
extern uschar *spool_sender_from_msgid(const uschar *);
509
extern int     spool_write_header(uschar *, int, uschar **);
534
extern int     spool_write_header(uschar *, int, uschar **);
510
extern int     stdin_getc(unsigned);
535
extern int     stdin_getc(unsigned);
511
extern int     stdin_feof(void);
536
extern int     stdin_feof(void);
512
extern int     stdin_ferror(void);
537
extern int     stdin_ferror(void);
538
extern BOOL    stdin_hasc(void);
513
extern int     stdin_ungetc(int);
539
extern int     stdin_ungetc(int);
514
540
515
extern void    store_exit(void);
541
extern void    store_exit(void);
542
extern void    store_init(void);
543
extern void    store_writeprotect(int);
544
516
extern gstring *string_append(gstring *, int, ...) WARN_UNUSED_RESULT;
545
extern gstring *string_append(gstring *, int, ...) WARN_UNUSED_RESULT;
517
extern gstring *string_append_listele(gstring *, uschar, const uschar *) WARN_UNUSED_RESULT;
546
extern gstring *string_append_listele(gstring *, uschar, const uschar *) WARN_UNUSED_RESULT;
518
extern gstring *string_append_listele_n(gstring *, uschar, const uschar *, unsigned) WARN_UNUSED_RESULT;
547
extern gstring *string_append_listele_n(gstring *, uschar, const uschar *, unsigned) WARN_UNUSED_RESULT;
Lines 552-561 Link Here
552
extern gstring *string_vformat_trc(gstring *, const uschar *, unsigned,
581
extern gstring *string_vformat_trc(gstring *, const uschar *, unsigned,
553
			unsigned, unsigned, const char *, va_list);
582
			unsigned, unsigned, const char *, va_list);
554
583
555
#define string_open_failed(eno, fmt, ...) \
584
#define string_open_failed(fmt, ...) \
556
	string_open_failed_trc(eno, US __FUNCTION__, __LINE__, fmt, __VA_ARGS__)
585
	string_open_failed_trc(US __FUNCTION__, __LINE__, fmt, __VA_ARGS__)
557
extern uschar *string_open_failed_trc(int, const uschar *, unsigned,
586
extern uschar *string_open_failed_trc(const uschar *, unsigned,
558
			const char *, ...) PRINTF_FUNCTION(4,5);
587
			const char *, ...) PRINTF_FUNCTION(3,4);
559
588
560
#define string_nextinlist(lp, sp, b, l) \
589
#define string_nextinlist(lp, sp, b, l) \
561
	string_nextinlist_trc((lp), (sp), (b), (l), US __FUNCTION__, __LINE__)
590
	string_nextinlist_trc((lp), (sp), (b), (l), US __FUNCTION__, __LINE__)
Lines 565-570 Link Here
565
extern int     strcmpic(const uschar *, const uschar *);
594
extern int     strcmpic(const uschar *, const uschar *);
566
extern int     strncmpic(const uschar *, const uschar *, int);
595
extern int     strncmpic(const uschar *, const uschar *, int);
567
extern uschar *strstric(uschar *, uschar *, BOOL);
596
extern uschar *strstric(uschar *, uschar *, BOOL);
597
extern const uschar *strstric_c(const uschar *, const uschar *, BOOL);
568
598
569
extern int     test_harness_fudged_queue_time(int);
599
extern int     test_harness_fudged_queue_time(int);
570
extern void    tcp_init(void);
600
extern void    tcp_init(void);
Lines 575-589 Link Here
575
extern uschar *tod_stamp(int);
605
extern uschar *tod_stamp(int);
576
606
577
extern BOOL    transport_check_waiting(const uschar *, const uschar *, int, uschar *,
607
extern BOOL    transport_check_waiting(const uschar *, const uschar *, int, uschar *,
578
                 BOOL *, oicf, void*);
608
                 oicf, void*);
579
extern void    transport_init(void);
609
extern uschar *transport_current_name(void);
580
extern void    transport_do_pass_socket(const uschar *, const uschar *,
610
extern void    transport_do_pass_socket(const uschar *, const uschar *,
581
		 const uschar *, uschar *, int);
611
		 const uschar *, uschar *, int);
582
extern BOOL    transport_pass_socket(const uschar *, const uschar *, const uschar *, uschar *,
612
extern void    transport_init(void);
583
                 int);
613
extern BOOL    transport_pass_socket(const uschar *, const uschar *, const uschar *, uschar *, int
614
#ifdef EXPERIMENTAL_ESMTP_LIMITS
615
			, unsigned, unsigned, unsigned
616
#endif
617
			);
584
extern uschar *transport_rcpt_address(address_item *, BOOL);
618
extern uschar *transport_rcpt_address(address_item *, BOOL);
585
extern BOOL    transport_set_up_command(const uschar ***, uschar *,
619
extern BOOL    transport_set_up_command(const uschar ***, const uschar *,
586
		 BOOL, int, address_item *, uschar *, uschar **);
620
		 BOOL, int, address_item *, BOOL, const uschar *, uschar **);
587
extern void    transport_update_waiting(host_item *, uschar *);
621
extern void    transport_update_waiting(host_item *, uschar *);
588
extern BOOL    transport_write_block(transport_ctx *, uschar *, int, BOOL);
622
extern BOOL    transport_write_block(transport_ctx *, uschar *, int, BOOL);
589
extern void    transport_write_reset(int);
623
extern void    transport_write_reset(int);
Lines 605-611 Link Here
605
extern void    unspool_mbox(void);
639
extern void    unspool_mbox(void);
606
#endif
640
#endif
607
#ifdef SUPPORT_I18N
641
#ifdef SUPPORT_I18N
608
extern void    utf8_version_report(FILE *);
642
extern gstring *utf8_version_report(gstring *);
609
#endif
643
#endif
610
644
611
extern int     verify_address(address_item *, FILE *, int, int, int, int,
645
extern int     verify_address(address_item *, FILE *, int, int, int, int,
Lines 622-627 Link Here
622
	         const uschar*, const uschar *, const uschar **);
656
	         const uschar*, const uschar *, const uschar **);
623
extern address_item *verify_checked_sender(uschar *);
657
extern address_item *verify_checked_sender(uschar *);
624
extern void    verify_get_ident(int);
658
extern void    verify_get_ident(int);
659
extern void    verify_quota(uschar *);
660
extern int     verify_quota_call(const uschar *, int, int, uschar **);
625
extern BOOL    verify_sender(int *, uschar **);
661
extern BOOL    verify_sender(int *, uschar **);
626
extern BOOL    verify_sender_preliminary(int *, uschar **);
662
extern BOOL    verify_sender_preliminary(int *, uschar **);
627
extern void    version_init(void);
663
extern void    version_init(void);
Lines 647-652 Link Here
647
#endif
683
#endif
648
}
684
}
649
685
686
static inline BOOL
687
is_incompatible(const void * old, const void * new)
688
{
689
#if defined(COMPILE_UTILITY) || defined(MACRO_PREDEF) || defined(EM_VERSION_C)
690
return FALSE;
691
692
#else
693
extern BOOL is_incompatible_fn(const void *, const void *);
694
return is_incompatible_fn(old, new);
695
#endif
696
}
697
650
/******************************************************************************/
698
/******************************************************************************/
651
/* String functions */
699
/* String functions */
652
static inline uschar * __Ustrcat(uschar * dst, const uschar * src, const char * func, int line)
700
static inline uschar * __Ustrcat(uschar * dst, const uschar * src, const char * func, int line)
Lines 739-770 Link Here
739
787
740
static inline uschar *
788
static inline uschar *
741
string_copyn_taint_trc(const uschar * s, unsigned len,
789
string_copyn_taint_trc(const uschar * s, unsigned len,
742
	BOOL tainted, const char * func, int line)
790
	const void * proto_mem, const char * func, int line)
743
{
791
{
744
uschar * ss = store_get_3(len + 1, tainted, func, line);
792
uschar * ss;
793
unsigned slen = Ustrlen(s);
794
if (len > slen) len = slen;
795
ss = store_get_3(len + 1, proto_mem, func, line);
745
memcpy(ss, s, len);
796
memcpy(ss, s, len);
746
ss[len] = '\0';
797
ss[len] = '\0';
747
return ss;
798
return ss;
748
}
799
}
749
800
750
static inline uschar *
801
static inline uschar *
751
string_copy_taint_trc(const uschar * s, BOOL tainted, const char * func, int line)
802
string_copy_taint_trc(const uschar * s, const void * proto_mem, const char * func, int line)
752
{ return string_copyn_taint_trc(s, Ustrlen(s), tainted, func, line); }
803
{ return string_copyn_taint_trc(s, Ustrlen(s), proto_mem, func, line); }
753
804
754
static inline uschar *
805
static inline uschar *
755
string_copyn_trc(const uschar * s, unsigned len, const char * func, int line)
806
string_copyn_trc(const uschar * s, unsigned len, const char * func, int line)
756
{ return string_copyn_taint_trc(s, len, is_tainted(s), func, line); }
807
{ return string_copyn_taint_trc(s, len, s, func, line); }
757
static inline uschar *
808
static inline uschar *
758
string_copy_trc(const uschar * s, const char * func, int line)
809
string_copy_trc(const uschar * s, const char * func, int line)
759
{ return string_copy_taint_trc(s, is_tainted(s), func, line); }
810
{ return string_copy_taint_trc(s, s, func, line); }
760
811
761
812
762
/* String-copy functions explicitly setting the taint status */
813
/* String-copy functions explicitly setting the taint status */
763
814
764
#define string_copyn_taint(s, len, tainted) \
815
#define string_copyn_taint(s, len, proto_mem) \
765
	string_copyn_taint_trc((s), (len), (tainted), __FUNCTION__, __LINE__)
816
	string_copyn_taint_trc((s), (len), (proto_mem), __FUNCTION__, __LINE__)
766
#define string_copy_taint(s, tainted) \
817
#define string_copy_taint(s, proto_mem) \
767
	string_copy_taint_trc((s), (tainted), __FUNCTION__, __LINE__)
818
	string_copy_taint_trc((s), (proto_mem), __FUNCTION__, __LINE__)
768
819
769
/* Simple string-copy functions maintaining the taint */
820
/* Simple string-copy functions maintaining the taint */
770
821
Lines 784-794 Link Here
784
*/
835
*/
785
836
786
static inline uschar *
837
static inline uschar *
787
string_copylc(const uschar *s)
838
string_copylc(const uschar * s)
788
{
839
{
789
uschar *ss = store_get(Ustrlen(s) + 1, is_tainted(s));
840
uschar * ss = store_get(Ustrlen(s) + 1, s);
790
uschar *p = ss;
841
uschar * p = ss;
791
while (*s != 0) *p++ = tolower(*s++);
842
while (*s) *p++ = tolower(*s++);
792
*p = 0;
843
*p = 0;
793
return ss;
844
return ss;
794
}
845
}
Lines 810-819 Link Here
810
*/
861
*/
811
862
812
static inline uschar *
863
static inline uschar *
813
string_copynlc(uschar *s, int n)
864
string_copynlc(uschar * s, int n)
814
{
865
{
815
uschar *ss = store_get(n + 1, is_tainted(s));
866
uschar * ss = store_get(n + 1, s);
816
uschar *p = ss;
867
uschar * p = ss;
817
while (n-- > 0) *p++ = tolower(*s++);
868
while (n-- > 0) *p++ = tolower(*s++);
818
*p = 0;
869
*p = 0;
819
return ss;
870
return ss;
Lines 839-845 Link Here
839
uschar *ss;
890
uschar *ss;
840
891
841
store_pool = POOL_PERM;
892
store_pool = POOL_PERM;
842
ss = store_get(len, force_taint || is_tainted(s));
893
ss = store_get(len, force_taint ? GET_TAINTED : s);
843
memcpy(ss, s, len);
894
memcpy(ss, s, len);
844
store_pool = old_pool;
895
store_pool = old_pool;
845
return ss;
896
return ss;
Lines 867-880 Link Here
867
918
868
/* Create a growable-string with some preassigned space */
919
/* Create a growable-string with some preassigned space */
869
920
870
#define string_get_tainted(size, tainted) \
921
#define string_get_tainted(size, proto_mem) \
871
	string_get_tainted_trc((size), (tainted), __FUNCTION__, __LINE__)
922
	string_get_tainted_trc((size), (proto_mem), __FUNCTION__, __LINE__)
872
923
873
static inline gstring *
924
static inline gstring *
874
string_get_tainted_trc(unsigned size, BOOL tainted, const char * func, unsigned line)
925
string_get_tainted_trc(unsigned size, const void * proto_mem, const char * func, unsigned line)
875
{
926
{
876
gstring * g = store_get_3(sizeof(gstring) + size, tainted, func, line);
927
gstring * g = store_get_3(sizeof(gstring) + size, proto_mem, func, line);
877
g->size = size;
928
g->size = size;		/*XXX would be good if we could see the actual alloc size */
878
g->ptr = 0;
929
g->ptr = 0;
879
g->s = US(g + 1);
930
g->s = US(g + 1);
880
return g;
931
return g;
Lines 886-892 Link Here
886
static inline gstring *
937
static inline gstring *
887
string_get_trc(unsigned size, const char * func, unsigned line)
938
string_get_trc(unsigned size, const char * func, unsigned line)
888
{
939
{
889
return string_get_tainted_trc(size, FALSE, func, line);
940
return string_get_tainted_trc(size, GET_UNTAINTED, func, line);
890
}
941
}
891
942
892
/* NUL-terminate the C string in the growable-string, and return it. */
943
/* NUL-terminate the C string in the growable-string, and return it. */
Lines 939-969 Link Here
939
}
990
}
940
991
941
992
942
/* Copy the content of a string to tainted memory */
993
/* Copy the content of a string to tainted memory.  The proto_mem arg
994
will always be tainted, and suitable as a prototype. */
943
995
944
static inline void
996
static inline void
945
gstring_rebuffer(gstring * g)
997
gstring_rebuffer(gstring * g, const void * proto_mem)
946
{
998
{
947
uschar * s = store_get(g->size, TRUE);
999
uschar * s = store_get_3(g->size, proto_mem, __FUNCTION__, __LINE__);
948
memcpy(s, g->s, g->ptr);
1000
memcpy(s, g->s, g->ptr);
949
g->s = s;
1001
g->s = s;
950
}
1002
}
951
1003
952
1004
1005
# ifndef COMPILE_UTILITY
953
/******************************************************************************/
1006
/******************************************************************************/
1007
/* Use store_malloc for DNSA structs, and explicit frees. Using the same pool
1008
for them as the strings we proceed to copy from them meant they could not be
1009
released, hence blowing 64k for every DNS lookup. That mounted up. With malloc
1010
we do have to take care over marking tainted all copied strings.  A separate pool
1011
could be used and would handle that implicitly. */
954
1012
955
#define store_get_dns_answer() store_get_dns_answer_trc(CUS __FUNCTION__, __LINE__)
1013
#define store_get_dns_answer() store_get_dns_answer_trc(CUS __FUNCTION__, __LINE__)
956
1014
957
static inline dns_answer *
1015
static inline dns_answer *
958
store_get_dns_answer_trc(const uschar * func, unsigned line)
1016
store_get_dns_answer_trc(const uschar * func, unsigned line)
959
{
1017
{
960
return store_get_3(sizeof(dns_answer), TRUE, CCS func, line);  /* use tainted mem */
1018
return store_malloc_3(sizeof(dns_answer), CCS func, line);
1019
}
1020
1021
#define store_free_dns_answer(dnsa) store_free_dns_answer_trc(dnsa, CUS __FUNCTION__, __LINE__)
1022
1023
static inline void
1024
store_free_dns_answer_trc(dns_answer * dnsa, const uschar * func, unsigned line)
1025
{
1026
store_free_3(dnsa, CCS func, line);
961
}
1027
}
962
1028
963
/******************************************************************************/
1029
/******************************************************************************/
964
/* Routines with knowledge of spool layout */
1030
/* Routines with knowledge of spool layout */
965
1031
966
# ifndef COMPILE_UTILITY
967
static inline void
1032
static inline void
968
spool_pname_buf(uschar * buf, int len)
1033
spool_pname_buf(uschar * buf, int len)
969
{
1034
{
Lines 1008-1014 Link Here
1008
#ifdef COMPILE_UTILITY		/* version avoiding string-extension */
1073
#ifdef COMPILE_UTILITY		/* version avoiding string-extension */
1009
int len = Ustrlen(spool_directory) + 1 + Ustrlen(queue_name) + 1 + Ustrlen(purpose) + 1
1074
int len = Ustrlen(spool_directory) + 1 + Ustrlen(queue_name) + 1 + Ustrlen(purpose) + 1
1010
	+ Ustrlen(subdir) + 1 + Ustrlen(fname) + Ustrlen(suffix) + 1;
1075
	+ Ustrlen(subdir) + 1 + Ustrlen(fname) + Ustrlen(suffix) + 1;
1011
uschar * buf = store_get(len, FALSE);
1076
uschar * buf = store_get(len, GET_UNTAINTED);
1012
string_format(buf, len, "%s/%s/%s/%s/%s%s",
1077
string_format(buf, len, "%s/%s/%s/%s/%s%s",
1013
	spool_directory, queue_name, purpose, subdir, fname, suffix);
1078
	spool_directory, queue_name, purpose, subdir, fname, suffix);
1014
return buf;
1079
return buf;
Lines 1029-1046 Link Here
1029
/******************************************************************************/
1094
/******************************************************************************/
1030
/* Time calculations */
1095
/* Time calculations */
1031
1096
1097
/* Diff two times (later, earlier) returning diff in 1st arg */
1032
static inline void
1098
static inline void
1033
timesince(struct timeval * diff, const struct timeval * then)
1099
timediff(struct timeval * later, const struct timeval * earlier)
1034
{
1100
{
1035
gettimeofday(diff, NULL);
1101
later->tv_sec -= earlier->tv_sec;
1036
diff->tv_sec -= then->tv_sec;
1102
if ((later->tv_usec -= earlier->tv_usec) < 0)
1037
if ((diff->tv_usec -= then->tv_usec) < 0)
1038
  {
1103
  {
1039
  diff->tv_sec--;
1104
  later->tv_sec--;
1040
  diff->tv_usec += 1000*1000;
1105
  later->tv_usec += 1000*1000;
1041
  }
1106
  }
1042
}
1107
}
1043
1108
1109
static inline void
1110
timesince(struct timeval * diff, const struct timeval * then)
1111
{
1112
gettimeofday(diff, NULL);
1113
timediff(diff, then);
1114
}
1115
1044
static inline uschar *
1116
static inline uschar *
1045
string_timediff(const struct timeval * diff)
1117
string_timediff(const struct timeval * diff)
1046
{
1118
{
Lines 1101-1106 Link Here
1101
errno = EACCES;
1173
errno = EACCES;
1102
return -1;
1174
return -1;
1103
}
1175
}
1176
#ifdef EXIM_HAVE_OPENAT
1104
static inline int
1177
static inline int
1105
exim_openat(int dirfd, const char *pathname, int flags)
1178
exim_openat(int dirfd, const char *pathname, int flags)
1106
{
1179
{
Lines 1117-1122 Link Here
1117
errno = EACCES;
1190
errno = EACCES;
1118
return -1;
1191
return -1;
1119
}
1192
}
1193
#endif
1120
1194
1121
static inline FILE *
1195
static inline FILE *
1122
exim_fopen(const char *pathname, const char *mode)
1196
exim_fopen(const char *pathname, const char *mode)
Lines 1175-1180 Link Here
1175
  outfdptr, make_leader, purpose);
1249
  outfdptr, make_leader, purpose);
1176
}
1250
}
1177
1251
1252
/* Return 1 if fd is usable per pollbits, else 0 */
1253
static inline int
1254
poll_one_fd(int fd, short pollbits, int tmo_millisec)
1255
{
1256
struct pollfd p = {.fd = fd, .events = pollbits};
1257
return poll(&p, 1, tmo_millisec);
1258
}
1259
1260
/******************************************************************************/
1261
/* Client-side smtp log string, for debug */
1262
1263
static inline void
1264
smtp_debug_cmd(const uschar * buf, int mode)
1265
{
1266
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP%c> %s\n",
1267
  mode == SCMD_BUFFER ? '|' : mode == SCMD_MORE ? '+' : '>', buf);
1268
1269
#  ifndef DISABLE_CLIENT_CMD_LOG
1270
  {
1271
  int len = Ustrcspn(buf, " \n");
1272
  int old_pool = store_pool;
1273
  store_pool = POOL_PERM;	/* Main pool ACL allocations eg. callouts get released */
1274
  client_cmd_log = string_append_listele_n(client_cmd_log, ':', buf, MIN(len, 8));
1275
  if (mode == SCMD_BUFFER) 
1276
    {
1277
    client_cmd_log = string_catn(client_cmd_log, US"|", 1); 
1278
    (void) string_from_gstring(client_cmd_log);
1279
    }
1280
  store_pool = old_pool;
1281
  }
1282
#  endif
1283
}
1284
1285
1286
static inline void
1287
smtp_debug_cmd_report(void)
1288
{
1289
#  ifndef DISABLE_CLIENT_CMD_LOG
1290
debug_printf("cmdlog: '%s'\n", client_cmd_log ? client_cmd_log->s : US"(unset)");
1291
#  endif
1292
}
1293
1294
1295
1178
# endif	/* !COMPILE_UTILITY */
1296
# endif	/* !COMPILE_UTILITY */
1179
1297
1180
/******************************************************************************/
1298
/******************************************************************************/
(-)exim.orig/src/globals.c (-107 / +83 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* All the global variables are defined together in this one module, so
9
/* All the global variables are defined together in this one module, so
Lines 114-128 Link Here
114
114
115
uschar *dsn_envid              = NULL;
115
uschar *dsn_envid              = NULL;
116
int     dsn_ret                = 0;
116
int     dsn_ret                = 0;
117
const pcre  *regex_DSN         = NULL;
117
const pcre2_code  *regex_DSN         = NULL;
118
uschar *dsn_advertise_hosts    = NULL;
118
uschar *dsn_advertise_hosts    = NULL;
119
119
120
#ifndef DISABLE_TLS
120
#ifndef DISABLE_TLS
121
BOOL    gnutls_compat_mode     = FALSE;
121
BOOL    gnutls_compat_mode     = FALSE;
122
BOOL    gnutls_allow_auto_pkcs11 = FALSE;
122
BOOL    gnutls_allow_auto_pkcs11 = FALSE;
123
uschar *hosts_require_alpn     = NULL;
123
uschar *openssl_options        = NULL;
124
uschar *openssl_options        = NULL;
124
const pcre *regex_STARTTLS     = NULL;
125
const pcre2_code *regex_STARTTLS     = NULL;
125
uschar *tls_advertise_hosts    = US"*";
126
uschar *tls_advertise_hosts    = US"*";
127
uschar *tls_alpn	       = US"smtp:esmtp";
126
uschar *tls_certificate        = NULL;
128
uschar *tls_certificate        = NULL;
127
uschar *tls_crl                = NULL;
129
uschar *tls_crl                = NULL;
128
/* This default matches NSS DH_MAX_P_BITS value at current time (2012), because
130
/* This default matches NSS DH_MAX_P_BITS value at current time (2012), because
Lines 137-148 Link Here
137
uschar *tls_privatekey         = NULL;
139
uschar *tls_privatekey         = NULL;
138
BOOL    tls_remember_esmtp     = FALSE;
140
BOOL    tls_remember_esmtp     = FALSE;
139
uschar *tls_require_ciphers    = NULL;
141
uschar *tls_require_ciphers    = NULL;
140
# ifdef EXPERIMENTAL_TLS_RESUME
142
# ifndef DISABLE_TLS_RESUME
141
uschar *tls_resumption_hosts   = NULL;
143
uschar *tls_resumption_hosts   = NULL;
142
# endif
144
# endif
143
uschar *tls_try_verify_hosts   = NULL;
145
uschar *tls_try_verify_hosts   = NULL;
144
uschar *tls_verify_certificates= US"system";
146
uschar *tls_verify_certificates= US"system";
145
uschar *tls_verify_hosts       = NULL;
147
uschar *tls_verify_hosts       = NULL;
148
int     tls_watch_fd	       = -1;
149
time_t  tls_watch_trigger_time = (time_t)0;
146
#else	/*DISABLE_TLS*/
150
#else	/*DISABLE_TLS*/
147
uschar *tls_advertise_hosts    = NULL;
151
uschar *tls_advertise_hosts    = NULL;
148
#endif
152
#endif
Lines 151-161 Link Here
151
/* Per Recipient Data Response variables */
155
/* Per Recipient Data Response variables */
152
BOOL    prdr_enable            = FALSE;
156
BOOL    prdr_enable            = FALSE;
153
BOOL    prdr_requested         = FALSE;
157
BOOL    prdr_requested         = FALSE;
154
const pcre *regex_PRDR         = NULL;
158
const pcre2_code *regex_PRDR         = NULL;
155
#endif
159
#endif
156
160
157
#ifdef SUPPORT_I18N
161
#ifdef SUPPORT_I18N
158
const pcre *regex_UTF8         = NULL;
162
const pcre2_code *regex_UTF8         = NULL;
159
#endif
163
#endif
160
164
161
/* Input-reading functions for messages, so we can use special ones for
165
/* Input-reading functions for messages, so we can use special ones for
Lines 163-178 Link Here
163
stand-alone tests. */
167
stand-alone tests. */
164
168
165
#if !defined(STAND_ALONE) && !defined(MACRO_PREDEF)
169
#if !defined(STAND_ALONE) && !defined(MACRO_PREDEF)
166
int (*lwr_receive_getc)(unsigned) = stdin_getc;
170
int	(*lwr_receive_getc)(unsigned)	= stdin_getc;
167
uschar * (*lwr_receive_getbuf)(unsigned *) = NULL;
171
uschar * (*lwr_receive_getbuf)(unsigned *) = NULL;
168
int (*lwr_receive_ungetc)(int) = stdin_ungetc;
172
int	(*lwr_receive_ungetc)(int)	= stdin_ungetc;
169
int (*receive_getc)(unsigned)  = stdin_getc;
173
BOOL	(*lwr_receive_hasc)(void)	= stdin_hasc;
170
uschar * (*receive_getbuf)(unsigned *)  = NULL;
174
171
void (*receive_get_cache)(void)= NULL;
175
int	(*receive_getc)(unsigned) 	= stdin_getc;
172
int (*receive_ungetc)(int)     = stdin_ungetc;
176
uschar * (*receive_getbuf)(unsigned *) 	= NULL;
173
int (*receive_feof)(void)      = stdin_feof;
177
void	(*receive_get_cache)(unsigned)	= NULL;
174
int (*receive_ferror)(void)    = stdin_ferror;
178
BOOL	(*receive_hasc)(void)		= stdin_hasc;
175
BOOL (*receive_smtp_buffered)(void) = NULL;   /* Only used for SMTP */
179
int	(*receive_ungetc)(int)    	= stdin_ungetc;
180
int	(*receive_feof)(void)     	= stdin_feof;
181
int	(*receive_ferror)(void)   	= stdin_ferror;
176
#endif
182
#endif
177
183
178
184
Lines 308-313 Link Here
308
#endif
314
#endif
309
	.smtp_in_pipelining_advertised = FALSE,
315
	.smtp_in_pipelining_advertised = FALSE,
310
	.smtp_in_pipelining_used = FALSE,
316
	.smtp_in_pipelining_used = FALSE,
317
	.smtp_in_quit		= FALSE,
311
	.spool_file_wireformat  = FALSE,
318
	.spool_file_wireformat  = FALSE,
312
	.submission_mode        = FALSE,
319
	.submission_mode        = FALSE,
313
	.suppress_local_fixups  = FALSE,
320
	.suppress_local_fixups  = FALSE,
Lines 383-389 Link Here
383
BOOL    proxy_session          = FALSE;
390
BOOL    proxy_session          = FALSE;
384
#endif
391
#endif
385
392
386
#ifdef EXPERIMENTAL_QUEUE_RAMP
393
#ifndef DISABLE_QUEUE_RAMP
387
BOOL    queue_fast_ramp		= FALSE;
394
BOOL    queue_fast_ramp		= FALSE;
388
#endif
395
#endif
389
BOOL    queue_list_requires_admin = TRUE;
396
BOOL    queue_list_requires_admin = TRUE;
Lines 408-417 Link Here
408
#endif
415
#endif
409
BOOL    split_spool_directory  = FALSE;
416
BOOL    split_spool_directory  = FALSE;
410
BOOL    spool_wireformat       = FALSE;
417
BOOL    spool_wireformat       = FALSE;
411
#ifdef EXPERIMENTAL_SRS
412
BOOL    srs_usehash            = TRUE;
413
BOOL    srs_usetimestamp       = TRUE;
414
#endif
415
BOOL    strict_acl_vars        = FALSE;
418
BOOL    strict_acl_vars        = FALSE;
416
BOOL    strip_excess_angle_brackets = FALSE;
419
BOOL    strip_excess_angle_brackets = FALSE;
417
BOOL    strip_trailing_dot     = FALSE;
420
BOOL    strip_trailing_dot     = FALSE;
Lines 597-605 Link Here
597
    .extra_headers =	NULL,
600
    .extra_headers =	NULL,
598
    .remove_headers =	NULL,
601
    .remove_headers =	NULL,
599
    .variables =	NULL,
602
    .variables =	NULL,
600
#ifdef EXPERIMENTAL_SRS
601
    .srs_sender =	NULL,
602
#endif
603
    .ignore_error =	FALSE,
603
    .ignore_error =	FALSE,
604
#ifdef SUPPORT_I18N
604
#ifdef SUPPORT_I18N
605
    .utf8_msg =		FALSE,
605
    .utf8_msg =		FALSE,
Lines 649-655 Link Here
649
649
650
uschar *auth_defer_msg         = US"reason not recorded";
650
uschar *auth_defer_msg         = US"reason not recorded";
651
uschar *auth_defer_user_msg    = US"";
651
uschar *auth_defer_user_msg    = US"";
652
uschar *auth_vars[AUTH_VARS];
652
const uschar *auth_vars[AUTH_VARS];
653
uschar *authenticator_name     = NULL;
653
int     auto_thaw              = 0;
654
int     auto_thaw              = 0;
654
#ifdef WITH_CONTENT_SCAN
655
#ifdef WITH_CONTENT_SCAN
655
int     av_failed              = FALSE;	/* boolean but accessed as vtype_int*/
656
int     av_failed              = FALSE;	/* boolean but accessed as vtype_int*/
Lines 702-712 Link Here
702
unsigned chunking_datasize     = 0;
703
unsigned chunking_datasize     = 0;
703
unsigned chunking_data_left    = 0;
704
unsigned chunking_data_left    = 0;
704
chunking_state_t chunking_state= CHUNKING_NOT_OFFERED;
705
chunking_state_t chunking_state= CHUNKING_NOT_OFFERED;
705
const pcre *regex_CHUNKING     = NULL;
706
const pcre2_code *regex_CHUNKING     = NULL;
707
708
#ifdef EXPERIMENTAL_ESMTP_LIMITS
709
const pcre2_code *regex_LIMITS        = NULL;
710
#endif
706
711
707
uschar *client_authenticator   = NULL;
712
uschar *client_authenticator   = NULL;
708
uschar *client_authenticated_id = NULL;
713
uschar *client_authenticated_id = NULL;
709
uschar *client_authenticated_sender = NULL;
714
uschar *client_authenticated_sender = NULL;
715
#ifndef DISABLE_CLIENT_CMD_LOG
716
gstring *client_cmd_log        = NULL;
717
#endif
710
int     clmacro_count          = 0;
718
int     clmacro_count          = 0;
711
uschar *clmacros[MAX_CLMACROS];
719
uschar *clmacros[MAX_CLMACROS];
712
FILE   *config_file            = NULL;
720
FILE   *config_file            = NULL;
Lines 736-741 Link Here
736
uschar *continue_host_address  = NULL;
744
uschar *continue_host_address  = NULL;
737
int     continue_sequence      = 1;
745
int     continue_sequence      = 1;
738
uschar *continue_transport     = NULL;
746
uschar *continue_transport     = NULL;
747
#ifdef EXPERIMENTAL_ESMTP_LIMITS
748
unsigned continue_limit_mail   = 0;
749
unsigned continue_limit_rcpt   = 0;
750
unsigned continue_limit_rcptdom= 0;
751
#endif
739
752
740
uschar *csa_status             = NULL;
753
uschar *csa_status             = NULL;
741
cut_t   cutthrough = {
754
cut_t   cutthrough = {
Lines 801-809 Link Here
801
  BIT_TABLE(D, uid),
814
  BIT_TABLE(D, uid),
802
  BIT_TABLE(D, verify),
815
  BIT_TABLE(D, verify),
803
};
816
};
804
int     debug_options_count    = nelem(debug_options);
817
int      debug_options_count	= nelem(debug_options);
818
uschar   debuglog_name[LOG_NAME_SIZE] = {0};
819
unsigned debug_pretrigger_bsize	= 0;
820
uschar * debug_pretrigger_buf	= NULL;
821
unsigned int debug_selector	= 0;
805
822
806
unsigned int debug_selector    = 0;
807
int     delay_warning[DELAY_WARNING_SIZE] = { DELAY_WARNING_SIZE, 1, 24*60*60 };
823
int     delay_warning[DELAY_WARNING_SIZE] = { DELAY_WARNING_SIZE, 1, 24*60*60 };
808
uschar *delay_warning_condition=
824
uschar *delay_warning_condition=
809
  US"${if or {"
825
  US"${if or {"
Lines 883-889 Link Here
883
uschar *dnslist_value          = NULL;
899
uschar *dnslist_value          = NULL;
884
tree_node *domainlist_anchor   = NULL;
900
tree_node *domainlist_anchor   = NULL;
885
int     domainlist_count       = 0;
901
int     domainlist_count       = 0;
902
const uschar *driver_srcfile   = NULL;
903
int     driver_srcline	       = 0;
886
uschar *dsn_from               = US DEFAULT_DSN_FROM;
904
uschar *dsn_from               = US DEFAULT_DSN_FROM;
905
unsigned int dtrigger_selector = 0;
887
906
888
int     errno_quota            = ERRNO_QUOTA;
907
int     errno_quota            = ERRNO_QUOTA;
889
uschar *errors_copy            = NULL;
908
uschar *errors_copy            = NULL;
Lines 906-912 Link Here
906
int     expand_forbid          = 0;
925
int     expand_forbid          = 0;
907
int     expand_nlength[EXPAND_MAXN+1];
926
int     expand_nlength[EXPAND_MAXN+1];
908
int     expand_nmax            = -1;
927
int     expand_nmax            = -1;
909
uschar *expand_nstring[EXPAND_MAXN+1];
928
const uschar *expand_nstring[EXPAND_MAXN+1];
910
uschar *expand_string_message;
929
uschar *expand_string_message;
911
uschar *extra_local_interfaces = NULL;
930
uschar *extra_local_interfaces = NULL;
912
931
Lines 935-941 Link Here
935
volatile sig_atomic_t had_command_sigterm = 0;
954
volatile sig_atomic_t had_command_sigterm = 0;
936
volatile sig_atomic_t had_data_timeout    = 0;
955
volatile sig_atomic_t had_data_timeout    = 0;
937
volatile sig_atomic_t had_data_sigint     = 0;
956
volatile sig_atomic_t had_data_sigint     = 0;
938
uschar *headers_charset        = US HEADERS_CHARSET;
957
const uschar *headers_charset  = US HEADERS_CHARSET;
939
int     header_insert_maxlen   = 64 * 1024;
958
int     header_insert_maxlen   = 64 * 1024;
940
header_line  *header_last      = NULL;
959
header_line  *header_last      = NULL;
941
header_line  *header_list      = NULL;
960
header_line  *header_list      = NULL;
Lines 978-983 Link Here
978
tree_node *hostlist_anchor     = NULL;
997
tree_node *hostlist_anchor     = NULL;
979
int     hostlist_count         = 0;
998
int     hostlist_count         = 0;
980
uschar *hosts_treat_as_local   = NULL;
999
uschar *hosts_treat_as_local   = NULL;
1000
uschar *hosts_require_helo     = US"*";
981
uschar *hosts_connection_nolog = NULL;
1001
uschar *hosts_connection_nolog = NULL;
982
1002
983
int     ignore_bounce_errors_after = 10*7*24*60*60;  /* 10 weeks */
1003
int     ignore_bounce_errors_after = 10*7*24*60*60;  /* 10 weeks */
Lines 995-1000 Link Here
995
int     keep_malformed         = 4*24*60*60;    /* 4 days */
1015
int     keep_malformed         = 4*24*60*60;    /* 4 days */
996
1016
997
uschar *eldap_dn               = NULL;
1017
uschar *eldap_dn               = NULL;
1018
#ifdef EXPERIMENTAL_ESMTP_LIMITS
1019
uschar *limits_advertise_hosts = US"*";
1020
#endif
998
int     load_average           = -2;
1021
int     load_average           = -2;
999
uschar *local_from_prefix      = NULL;
1022
uschar *local_from_prefix      = NULL;
1000
uschar *local_from_suffix      = NULL;
1023
uschar *local_from_suffix      = NULL;
Lines 1028-1033 Link Here
1028
  Li_outgoing_interface, /* see d_log_interface in deliver.c */
1051
  Li_outgoing_interface, /* see d_log_interface in deliver.c */
1029
  Li_msg_id,
1052
  Li_msg_id,
1030
  Li_queue_run,
1053
  Li_queue_run,
1054
  Li_queue_time_exclusive,
1031
  Li_rejected_header,
1055
  Li_rejected_header,
1032
  Li_retry_defer,
1056
  Li_retry_defer,
1033
  Li_sender_verify_fail,
1057
  Li_sender_verify_fail,
Lines 1076-1086 Link Here
1076
  BIT_TABLE(L, outgoing_port),
1100
  BIT_TABLE(L, outgoing_port),
1077
  BIT_TABLE(L, pid),
1101
  BIT_TABLE(L, pid),
1078
  BIT_TABLE(L, pipelining),
1102
  BIT_TABLE(L, pipelining),
1103
  BIT_TABLE(L, protocol_detail),
1079
#if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS)
1104
#if defined(SUPPORT_PROXY) || defined(SUPPORT_SOCKS)
1080
  BIT_TABLE(L, proxy),
1105
  BIT_TABLE(L, proxy),
1081
#endif
1106
#endif
1082
  BIT_TABLE(L, queue_run),
1107
  BIT_TABLE(L, queue_run),
1083
  BIT_TABLE(L, queue_time),
1108
  BIT_TABLE(L, queue_time),
1109
  BIT_TABLE(L, queue_time_exclusive),
1084
  BIT_TABLE(L, queue_time_overall),
1110
  BIT_TABLE(L, queue_time_overall),
1085
  BIT_TABLE(L, receive_time),
1111
  BIT_TABLE(L, receive_time),
1086
  BIT_TABLE(L, received_recipients),
1112
  BIT_TABLE(L, received_recipients),
Lines 1136-1142 Link Here
1136
uschar *message_id;
1162
uschar *message_id;
1137
uschar *message_id_domain      = NULL;
1163
uschar *message_id_domain      = NULL;
1138
uschar *message_id_text        = NULL;
1164
uschar *message_id_text        = NULL;
1139
struct timeval message_id_tv   = { 0, 0 };
1140
uschar  message_id_option[MESSAGE_ID_LENGTH + 3];
1165
uschar  message_id_option[MESSAGE_ID_LENGTH + 3];
1141
uschar *message_id_external;
1166
uschar *message_id_external;
1142
int     message_linecount      = 0;
1167
int     message_linecount      = 0;
Lines 1182-1187 Link Here
1182
uschar *override_local_interfaces = NULL;
1207
uschar *override_local_interfaces = NULL;
1183
uschar *override_pid_file_path = NULL;
1208
uschar *override_pid_file_path = NULL;
1184
1209
1210
pcre2_general_context * pcre_gen_ctx = NULL;
1211
pcre2_compile_context * pcre_cmp_ctx = NULL;
1212
pcre2_match_context * pcre_mtc_ctx = NULL;
1213
1185
uschar *percent_hack_domains   = NULL;
1214
uschar *percent_hack_domains   = NULL;
1186
uschar *pid_file_path          = US PID_FILE_PATH
1215
uschar *pid_file_path          = US PID_FILE_PATH
1187
                           "\0<--------------Space to patch pid_file_path->";
1216
                           "\0<--------------Space to patch pid_file_path->";
Lines 1201-1206 Link Here
1201
int     proxy_external_port    = 0;
1230
int     proxy_external_port    = 0;
1202
uschar *proxy_local_address    = NULL;
1231
uschar *proxy_local_address    = NULL;
1203
int     proxy_local_port       = 0;
1232
int     proxy_local_port       = 0;
1233
int     proxy_protocol_timeout = 3;
1204
#endif
1234
#endif
1205
1235
1206
uschar *prvscheck_address      = NULL;
1236
uschar *prvscheck_address      = NULL;
Lines 1266-1272 Link Here
1266
int     received_headers_max   = 30;
1296
int     received_headers_max   = 30;
1267
uschar *received_protocol      = NULL;
1297
uschar *received_protocol      = NULL;
1268
struct timeval received_time   = { 0, 0 };
1298
struct timeval received_time   = { 0, 0 };
1269
struct timeval received_time_taken = { 0, 0 };
1299
struct timeval received_time_complete = { 0, 0 };
1270
uschar *recipient_data         = NULL;
1300
uschar *recipient_data         = NULL;
1271
uschar *recipient_unqualified_hosts = NULL;
1301
uschar *recipient_unqualified_hosts = NULL;
1272
uschar *recipient_verify_failure = NULL;
1302
uschar *recipient_verify_failure = NULL;
Lines 1274-1293 Link Here
1274
recipient_item  *recipients_list = NULL;
1304
recipient_item  *recipients_list = NULL;
1275
int     recipients_list_max    = 0;
1305
int     recipients_list_max    = 0;
1276
int     recipients_max         = 50000;
1306
int     recipients_max         = 50000;
1277
const pcre *regex_AUTH         = NULL;
1307
const pcre2_code *regex_AUTH         = NULL;
1278
const pcre *regex_check_dns_names = NULL;
1308
const pcre2_code *regex_check_dns_names = NULL;
1279
const pcre *regex_From         = NULL;
1309
const pcre2_code *regex_From         = NULL;
1280
const pcre *regex_IGNOREQUOTA  = NULL;
1310
const pcre2_code *regex_IGNOREQUOTA  = NULL;
1281
const pcre *regex_PIPELINING   = NULL;
1311
const pcre2_code *regex_PIPELINING   = NULL;
1282
const pcre *regex_SIZE         = NULL;
1312
const pcre2_code *regex_SIZE         = NULL;
1283
#ifndef DISABLE_PIPE_CONNECT
1313
#ifndef DISABLE_PIPE_CONNECT
1284
const pcre *regex_EARLY_PIPE   = NULL;
1314
const pcre2_code *regex_EARLY_PIPE   = NULL;
1285
#endif
1315
#endif
1286
const pcre *regex_ismsgid      = NULL;
1316
const pcre2_code *regex_ismsgid      = NULL;
1287
const pcre *regex_smtp_code    = NULL;
1317
const pcre2_code *regex_smtp_code    = NULL;
1288
uschar *regex_vars[REGEX_VARS];
1318
const uschar *regex_vars[REGEX_VARS];
1289
#ifdef WHITELIST_D_MACROS
1319
#ifdef WHITELIST_D_MACROS
1290
const pcre *regex_whitelisted_macro = NULL;
1320
const pcre2_code *regex_whitelisted_macro = NULL;
1291
#endif
1321
#endif
1292
#ifdef WITH_CONTENT_SCAN
1322
#ifdef WITH_CONTENT_SCAN
1293
uschar *regex_match_string     = NULL;
1323
uschar *regex_match_string     = NULL;
Lines 1442-1453 Link Here
1442
int     smtp_accept_max        = 20;
1472
int     smtp_accept_max        = 20;
1443
int     smtp_accept_max_nonmail= 10;
1473
int     smtp_accept_max_nonmail= 10;
1444
uschar *smtp_accept_max_nonmail_hosts = US"*";
1474
uschar *smtp_accept_max_nonmail_hosts = US"*";
1445
int     smtp_accept_max_per_connection = 1000;
1475
uschar *smtp_accept_max_per_connection = US"1000";
1446
uschar *smtp_accept_max_per_host = NULL;
1476
uschar *smtp_accept_max_per_host = NULL;
1447
int     smtp_accept_queue      = 0;
1477
int     smtp_accept_queue      = 0;
1448
int     smtp_accept_queue_per_connection = 10;
1478
int     smtp_accept_queue_per_connection = 10;
1449
int     smtp_accept_reserve    = 0;
1479
int     smtp_accept_reserve    = 0;
1450
uschar *smtp_active_hostname   = NULL;
1480
uschar *smtp_active_hostname   = NULL;
1481
int	smtp_backlog_monitor   = 0;
1451
uschar *smtp_banner            = US"$smtp_active_hostname ESMTP "
1482
uschar *smtp_banner            = US"$smtp_active_hostname ESMTP "
1452
                             "Exim $version_number $tod_full"
1483
                             "Exim $version_number $tod_full"
1453
                             "\0<---------------Space to patch smtp_banner->";
1484
                             "\0<---------------Space to patch smtp_banner->";
Lines 1460-1472 Link Here
1460
double  smtp_delay_mail        = 0.0;
1491
double  smtp_delay_mail        = 0.0;
1461
double  smtp_delay_rcpt        = 0.0;
1492
double  smtp_delay_rcpt        = 0.0;
1462
FILE   *smtp_in                = NULL;
1493
FILE   *smtp_in                = NULL;
1494
int     smtp_listen_backlog    = 0;
1463
int     smtp_load_reserve      = -1;
1495
int     smtp_load_reserve      = -1;
1464
int     smtp_mailcmd_count     = 0;
1496
int     smtp_mailcmd_count     = 0;
1497
int     smtp_mailcmd_max       = -1;
1465
FILE   *smtp_out               = NULL;
1498
FILE   *smtp_out               = NULL;
1466
uschar *smtp_etrn_command      = NULL;
1499
uschar *smtp_etrn_command      = NULL;
1467
int     smtp_max_synprot_errors= 3;
1500
int     smtp_max_synprot_errors= 3;
1468
int     smtp_max_unknown_commands = 3;
1501
int     smtp_max_unknown_commands = 3;
1469
uschar *smtp_notquit_reason    = NULL;
1502
uschar *smtp_notquit_reason    = NULL;
1503
unsigned smtp_peer_options     = 0;
1504
unsigned smtp_peer_options_wrap= 0;
1470
uschar *smtp_ratelimit_hosts   = NULL;
1505
uschar *smtp_ratelimit_hosts   = NULL;
1471
uschar *smtp_ratelimit_mail    = NULL;
1506
uschar *smtp_ratelimit_mail    = NULL;
1472
uschar *smtp_ratelimit_rcpt    = NULL;
1507
uschar *smtp_ratelimit_rcpt    = NULL;
Lines 1482-1489 Link Here
1482
double  smtp_rlr_factor        = 0.0;
1517
double  smtp_rlr_factor        = 0.0;
1483
int     smtp_rlr_limit         = 0;
1518
int     smtp_rlr_limit         = 0;
1484
int     smtp_rlr_threshold     = INT_MAX;
1519
int     smtp_rlr_threshold     = INT_MAX;
1485
unsigned smtp_peer_options     = 0;
1486
unsigned smtp_peer_options_wrap= 0;
1487
#ifdef SUPPORT_I18N
1520
#ifdef SUPPORT_I18N
1488
uschar *smtputf8_advertise_hosts = US"*";	/* overridden under test-harness */
1521
uschar *smtputf8_advertise_hosts = US"*";	/* overridden under test-harness */
1489
#endif
1522
#endif
Lines 1511-1537 Link Here
1511
FILE   *spool_data_file	       = NULL;
1544
FILE   *spool_data_file	       = NULL;
1512
uschar *spool_directory        = US SPOOL_DIRECTORY
1545
uschar *spool_directory        = US SPOOL_DIRECTORY
1513
                           "\0<--------------Space to patch spool_directory->";
1546
                           "\0<--------------Space to patch spool_directory->";
1514
#ifdef EXPERIMENTAL_SRS
1547
#ifdef SUPPORT_SRS
1515
uschar *srs_config             = NULL;
1516
uschar *srs_db_address         = NULL;
1517
uschar *srs_db_key             = NULL;
1518
int     srs_hashlength         = 6;
1519
int     srs_hashmin            = -1;
1520
int     srs_maxage             = 31;
1521
uschar *srs_orig_recipient     = NULL;
1522
uschar *srs_orig_sender        = NULL;
1523
uschar *srs_recipient          = NULL;
1524
uschar *srs_secrets            = NULL;
1525
uschar *srs_status             = NULL;
1526
#endif
1527
#ifdef EXPERIMENTAL_SRS_NATIVE
1528
uschar *srs_recipient          = NULL;
1548
uschar *srs_recipient          = NULL;
1529
#endif
1549
#endif
1530
int     string_datestamp_offset= -1;
1550
int     string_datestamp_offset= -1;
1531
int     string_datestamp_length= 0;
1551
int     string_datestamp_length= 0;
1532
int     string_datestamp_type  = -1;
1552
int     string_datestamp_type  = -1;
1533
uschar *submission_domain      = NULL;
1553
const uschar *submission_domain = NULL;
1534
uschar *submission_name        = NULL;
1554
const uschar *submission_name  = NULL;
1535
int     syslog_facility        = LOG_MAIL;
1555
int     syslog_facility        = LOG_MAIL;
1536
uschar *syslog_processname     = US"exim";
1556
uschar *syslog_processname     = US"exim";
1537
uschar *system_filter          = NULL;
1557
uschar *system_filter          = NULL;
Lines 1559-1618 Link Here
1559
transport_instance  *transports = NULL;
1579
transport_instance  *transports = NULL;
1560
1580
1561
transport_instance  transport_defaults = {
1581
transport_instance  transport_defaults = {
1562
    .next =			NULL,
1582
    /* All non-mentioned elements zero/NULL/FALSE */
1563
    .name =			NULL,
1564
    .info =			NULL,
1565
    .options_block =		NULL,
1566
    .driver_name =		NULL,
1567
    .setup =			NULL,
1568
    .batch_max =		1,
1583
    .batch_max =		1,
1569
    .batch_id =			NULL,
1570
    .home_dir =			NULL,
1571
    .current_dir =		NULL,
1572
    .expand_multi_domain =	NULL,
1573
    .multi_domain =		TRUE,
1584
    .multi_domain =		TRUE,
1574
    .overrides_hosts =		FALSE,
1575
    .max_addresses =		100,
1585
    .max_addresses =		100,
1576
    .connection_max_messages =	500,
1586
    .connection_max_messages =	500,
1577
    .deliver_as_creator =	FALSE,
1578
    .disable_logging =		FALSE,
1579
    .initgroups =		FALSE,
1580
    .uid_set =			FALSE,
1581
    .gid_set =			FALSE,
1582
    .uid =			(uid_t)(-1),
1587
    .uid =			(uid_t)(-1),
1583
    .gid =			(gid_t)(-1),
1588
    .gid =			(gid_t)(-1),
1584
    .expand_uid =		NULL,
1585
    .expand_gid =		NULL,
1586
    .warn_message =		NULL,
1587
    .shadow =			NULL,
1588
    .shadow_condition =		NULL,
1589
    .filter_command =		NULL,
1590
    .add_headers =		NULL,
1591
    .remove_headers =		NULL,
1592
    .return_path =		NULL,
1593
    .debug_string =		NULL,
1594
    .max_parallel =		NULL,
1595
    .message_size_limit =	NULL,
1596
    .headers_rewrite =		NULL,
1597
    .rewrite_rules =		NULL,
1598
    .rewrite_existflags =	0,
1599
    .filter_timeout =		300,
1589
    .filter_timeout =		300,
1600
    .body_only =		FALSE,
1601
    .delivery_date_add =	FALSE,
1602
    .envelope_to_add =		FALSE,
1603
    .headers_only =		FALSE,
1604
    .rcpt_include_affixes =	FALSE,
1605
    .return_path_add =		FALSE,
1606
    .return_output =		FALSE,
1607
    .return_fail_output =	FALSE,
1608
    .log_output =		FALSE,
1609
    .log_fail_output =		FALSE,
1610
    .log_defer_output =		FALSE,
1611
    .retry_use_local_part =	TRUE_UNSET,	/* retry_use_local_part: BOOL, but set neither
1590
    .retry_use_local_part =	TRUE_UNSET,	/* retry_use_local_part: BOOL, but set neither
1612
						 1 nor 0 so can detect unset */
1591
						 1 nor 0 so can detect unset */
1613
#ifndef DISABLE_EVENT
1614
   .event_action =		NULL
1615
#endif
1616
};
1592
};
1617
1593
1618
int     transport_count;
1594
int     transport_count;
Lines 1663-1669 Link Here
1663
uschar *verify_mode	       = NULL;
1639
uschar *verify_mode	       = NULL;
1664
uschar *version_copyright      =
1640
uschar *version_copyright      =
1665
 US"Copyright (c) University of Cambridge, 1995 - 2018\n"
1641
 US"Copyright (c) University of Cambridge, 1995 - 2018\n"
1666
   "(c) The Exim Maintainers and contributors in ACKNOWLEDGMENTS file, 2007 - 2018";
1642
   "(c) The Exim Maintainers and contributors in ACKNOWLEDGMENTS file, 2007 - 2022";
1667
uschar *version_date           = US"?";
1643
uschar *version_date           = US"?";
1668
uschar *version_cnumber        = US"????";
1644
uschar *version_cnumber        = US"????";
1669
uschar *version_string         = US"?";
1645
uschar *version_string         = US"?";
(-)exim.orig/src/globals.h (-47 / +76 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Almost all the global variables are defined together in this one header, so
9
/* Almost all the global variables are defined together in this one header, so
Lines 107-113 Link Here
107
    OCSP_FAILED,		/* verify failed */
107
    OCSP_FAILED,		/* verify failed */
108
    OCSP_VFIED			/* verified */
108
    OCSP_VFIED			/* verified */
109
    }     ocsp;		      /* Stapled OCSP status */
109
    }     ocsp;		      /* Stapled OCSP status */
110
#ifdef EXPERIMENTAL_TLS_RESUME
110
#ifndef DISABLE_TLS_RESUME
111
  hctx	  resume_hctx;		/* session lookup key accumulation */
112
  const uschar * resume_index;	/* session lookup key */
113
111
  unsigned resumption;		/* Session resumption */
114
  unsigned resumption;		/* Session resumption */
112
  BOOL	  host_resumable:1;
115
  BOOL	  host_resumable:1;
113
  BOOL	  ticket_received:1;
116
  BOOL	  ticket_received:1;
Lines 121-128 Link Here
121
#ifndef DISABLE_TLS
124
#ifndef DISABLE_TLS
122
extern BOOL    gnutls_compat_mode;     /* Less security, more compatibility */
125
extern BOOL    gnutls_compat_mode;     /* Less security, more compatibility */
123
extern BOOL    gnutls_allow_auto_pkcs11; /* Let GnuTLS autoload PKCS11 modules */
126
extern BOOL    gnutls_allow_auto_pkcs11; /* Let GnuTLS autoload PKCS11 modules */
127
extern uschar *hosts_require_alpn;     /* Mandatory ALPN successful nogitiation */
124
extern uschar *openssl_options;        /* OpenSSL compatibility options */
128
extern uschar *openssl_options;        /* OpenSSL compatibility options */
125
extern const pcre *regex_STARTTLS;     /* For recognizing STARTTLS settings */
129
extern const pcre2_code *regex_STARTTLS;     /* For recognizing STARTTLS settings */
130
extern uschar *tls_alpn;	       /* ALPN names acceptable */
126
extern uschar *tls_certificate;        /* Certificate file */
131
extern uschar *tls_certificate;        /* Certificate file */
127
extern uschar *tls_crl;                /* CRL File */
132
extern uschar *tls_crl;                /* CRL File */
128
extern int     tls_dh_max_bits;        /* don't accept higher lib suggestions */
133
extern int     tls_dh_max_bits;        /* don't accept higher lib suggestions */
Lines 134-151 Link Here
134
extern uschar *tls_privatekey;         /* Private key file */
139
extern uschar *tls_privatekey;         /* Private key file */
135
extern BOOL    tls_remember_esmtp;     /* For YAEB */
140
extern BOOL    tls_remember_esmtp;     /* For YAEB */
136
extern uschar *tls_require_ciphers;    /* So some can be avoided */
141
extern uschar *tls_require_ciphers;    /* So some can be avoided */
137
# ifdef EXPERIMENTAL_TLS_RESUME
142
# ifndef DISABLE_TLS_RESUME
138
extern uschar *tls_resumption_hosts;   /* TLS session resumption */
143
extern uschar *tls_resumption_hosts;   /* TLS session resumption */
139
# endif
144
# endif
140
extern uschar *tls_try_verify_hosts;   /* Optional client verification */
145
extern uschar *tls_try_verify_hosts;   /* Optional client verification */
141
extern uschar *tls_verify_certificates;/* Path for certificates to check */
146
extern uschar *tls_verify_certificates;/* Path for certificates to check */
142
extern uschar *tls_verify_hosts;       /* Mandatory client verification */
147
extern uschar *tls_verify_hosts;       /* Mandatory client verification */
148
extern int     tls_watch_fd;	       /* for inotify of creds files */
149
extern time_t  tls_watch_trigger_time; /* non-0: triggered */
143
#endif
150
#endif
144
extern uschar *tls_advertise_hosts;    /* host for which TLS is advertised */
151
extern uschar *tls_advertise_hosts;    /* host for which TLS is advertised */
145
152
146
extern uschar  *dsn_envid;             /* DSN envid string */
153
extern uschar  *dsn_envid;             /* DSN envid string */
147
extern int      dsn_ret;               /* DSN ret type*/
154
extern int      dsn_ret;               /* DSN ret type*/
148
extern const pcre  *regex_DSN;         /* For recognizing DSN settings */
155
extern const pcre2_code  *regex_DSN;         /* For recognizing DSN settings */
149
extern uschar  *dsn_advertise_hosts;   /* host for which TLS is advertised */
156
extern uschar  *dsn_advertise_hosts;   /* host for which TLS is advertised */
150
157
151
/* Input-reading functions for messages, so we can use special ones for
158
/* Input-reading functions for messages, so we can use special ones for
Lines 153-166 Link Here
153
160
154
extern int (*lwr_receive_getc)(unsigned);
161
extern int (*lwr_receive_getc)(unsigned);
155
extern uschar * (*lwr_receive_getbuf)(unsigned *);
162
extern uschar * (*lwr_receive_getbuf)(unsigned *);
163
extern BOOL (*lwr_receive_hasc)(void);
156
extern int (*lwr_receive_ungetc)(int);
164
extern int (*lwr_receive_ungetc)(int);
165
157
extern int (*receive_getc)(unsigned);
166
extern int (*receive_getc)(unsigned);
158
extern uschar * (*receive_getbuf)(unsigned *);
167
extern uschar * (*receive_getbuf)(unsigned *);
159
extern void (*receive_get_cache)(void);
168
extern BOOL (*receive_hasc)(void);
169
extern void (*receive_get_cache)(unsigned);
160
extern int (*receive_ungetc)(int);
170
extern int (*receive_ungetc)(int);
161
extern int (*receive_feof)(void);
171
extern int (*receive_feof)(void);
162
extern int (*receive_ferror)(void);
172
extern int (*receive_ferror)(void);
163
extern BOOL (*receive_smtp_buffered)(void);
164
173
165
174
166
/* For clearing, saving, restoring address expansion variables. We have to have
175
/* For clearing, saving, restoring address expansion variables. We have to have
Lines 264-275 Link Here
264
 BOOL   sender_set_untrusted		:1; /* Sender set by untrusted caller */
273
 BOOL   sender_set_untrusted		:1; /* Sender set by untrusted caller */
265
 BOOL   smtp_authenticated		:1; /* Sending client has authenticated */
274
 BOOL   smtp_authenticated		:1; /* Sending client has authenticated */
266
#ifndef DISABLE_PIPE_CONNECT
275
#ifndef DISABLE_PIPE_CONNECT
267
 BOOL   smtp_in_early_pipe_advertised	:1; /* server advertised PIPE_CONNECT */
276
 BOOL   smtp_in_early_pipe_advertised	:1; /* server advertised PIPECONNECT */
268
 BOOL	smtp_in_early_pipe_no_auth	:1; /* too many authenticator names */
277
 BOOL	smtp_in_early_pipe_no_auth	:1; /* too many authenticator names */
269
 BOOL   smtp_in_early_pipe_used		:1; /* client did send early data */
278
 BOOL   smtp_in_early_pipe_used		:1; /* client did send early data */
270
#endif
279
#endif
271
 BOOL   smtp_in_pipelining_advertised	:1; /* server advertised PIPELINING */
280
 BOOL   smtp_in_pipelining_advertised	:1; /* server advertised PIPELINING */
272
 BOOL   smtp_in_pipelining_used		:1; /* server noted client using PIPELINING */
281
 BOOL   smtp_in_pipelining_used		:1; /* server noted client using PIPELINING */
282
 BOOL   smtp_in_quit			:1; /* server noted QUIT command */
273
 BOOL   spool_file_wireformat		:1; /* current -D file has CRLF rather than NL */
283
 BOOL   spool_file_wireformat		:1; /* current -D file has CRLF rather than NL */
274
 BOOL   submission_mode			:1; /* Can be forced from ACL */
284
 BOOL   submission_mode			:1; /* Can be forced from ACL */
275
 BOOL   suppress_local_fixups		:1; /* Can be forced from ACL */
285
 BOOL   suppress_local_fixups		:1; /* Can be forced from ACL */
Lines 311-317 Link Here
311
extern uschar *acl_smtp_data;          /* ACL run after DATA received */
321
extern uschar *acl_smtp_data;          /* ACL run after DATA received */
312
#ifndef DISABLE_PRDR
322
#ifndef DISABLE_PRDR
313
extern uschar *acl_smtp_data_prdr;     /* ACL run after DATA received if in PRDR mode*/
323
extern uschar *acl_smtp_data_prdr;     /* ACL run after DATA received if in PRDR mode*/
314
const extern pcre *regex_PRDR;         /* For recognizing PRDR settings */
324
const extern pcre2_code *regex_PRDR;         /* For recognizing PRDR settings */
315
#endif
325
#endif
316
#ifndef DISABLE_DKIM
326
#ifndef DISABLE_DKIM
317
extern uschar *acl_smtp_dkim;          /* ACL run for DKIM signatures / domains */
327
extern uschar *acl_smtp_dkim;          /* ACL run for DKIM signatures / domains */
Lines 357-369 Link Here
357
extern uschar *authenticated_id;       /* ID that was authenticated */
367
extern uschar *authenticated_id;       /* ID that was authenticated */
358
extern uschar *authenticated_sender;   /* From AUTH on MAIL */
368
extern uschar *authenticated_sender;   /* From AUTH on MAIL */
359
extern BOOL    authentication_failed;  /* TRUE if AUTH was tried and failed */
369
extern BOOL    authentication_failed;  /* TRUE if AUTH was tried and failed */
370
extern uschar *authenticator_name;     /* for debug and error messages */
360
extern uschar *auth_advertise_hosts;   /* Only advertise to these */
371
extern uschar *auth_advertise_hosts;   /* Only advertise to these */
361
extern auth_info auths_available[];    /* Vector of available auth mechanisms */
372
extern auth_info auths_available[];    /* Vector of available auth mechanisms */
362
extern auth_instance *auths;           /* Chain of instantiated auths */
373
extern auth_instance *auths;           /* Chain of instantiated auths */
363
extern auth_instance auth_defaults;    /* Default values */
374
extern auth_instance auth_defaults;    /* Default values */
364
extern uschar *auth_defer_msg;         /* Error message for log */
375
extern uschar *auth_defer_msg;         /* Error message for log */
365
extern uschar *auth_defer_user_msg;    /* Error message for user */
376
extern uschar *auth_defer_user_msg;    /* Error message for user */
366
extern uschar *auth_vars[];            /* $authn variables */
377
extern const uschar *auth_vars[];      /* $authn variables */
367
extern int     auto_thaw;              /* Auto-thaw interval */
378
extern int     auto_thaw;              /* Auto-thaw interval */
368
#ifdef WITH_CONTENT_SCAN
379
#ifdef WITH_CONTENT_SCAN
369
extern int     av_failed;              /* TRUE if the AV process failed */
380
extern int     av_failed;              /* TRUE if the AV process failed */
Lines 413-418 Link Here
413
extern uschar *client_authenticator;        /* Authenticator name used for smtp delivery */
424
extern uschar *client_authenticator;        /* Authenticator name used for smtp delivery */
414
extern uschar *client_authenticated_id;     /* "login" name used for SMTP AUTH */
425
extern uschar *client_authenticated_id;     /* "login" name used for SMTP AUTH */
415
extern uschar *client_authenticated_sender; /* AUTH option to SMTP MAIL FROM (not yet used) */
426
extern uschar *client_authenticated_sender; /* AUTH option to SMTP MAIL FROM (not yet used) */
427
#ifndef DISABLE_CLIENT_CMD_LOG
428
extern gstring *client_cmd_log;	       /* debug log of client cmds & responses */
429
#endif
416
extern int     clmacro_count;          /* Number of command line macros */
430
extern int     clmacro_count;          /* Number of command line macros */
417
extern uschar *clmacros[];             /* Copy of them, for re-exec */
431
extern uschar *clmacros[];             /* Copy of them, for re-exec */
418
extern BOOL    commandline_checks_require_admin; /* belt and braces for insecure setups */
432
extern BOOL    commandline_checks_require_admin; /* belt and braces for insecure setups */
Lines 432-437 Link Here
432
extern uschar *continue_host_address;  /* IP address for ditto */
446
extern uschar *continue_host_address;  /* IP address for ditto */
433
extern int     continue_sequence;      /* Sequence num for continued delivery */
447
extern int     continue_sequence;      /* Sequence num for continued delivery */
434
extern uschar *continue_transport;     /* Transport for continued delivery */
448
extern uschar *continue_transport;     /* Transport for continued delivery */
449
#ifdef EXPERIMENTAL_ESMTP_LIMITS
450
extern unsigned continue_limit_mail;   /* Peer advertised limit */
451
extern unsigned continue_limit_rcpt;
452
extern unsigned continue_limit_rcptdom;
453
#endif
454
435
455
436
extern uschar *csa_status;             /* Client SMTP Authorization result */
456
extern uschar *csa_status;             /* Client SMTP Authorization result */
437
457
Lines 470-476 Link Here
470
extern int     debug_notall[];         /* Debug options excluded from +all */
490
extern int     debug_notall[];         /* Debug options excluded from +all */
471
extern bit_table debug_options[];      /* Table of debug options */
491
extern bit_table debug_options[];      /* Table of debug options */
472
extern int     debug_options_count;    /* Size of table */
492
extern int     debug_options_count;    /* Size of table */
493
extern unsigned debug_pretrigger_bsize;
494
extern uschar *debug_pretrigger_buf;   /* circular buffer for precapture */
473
extern BOOL    debug_store;	       /* Do extra checks on store_reset */
495
extern BOOL    debug_store;	       /* Do extra checks on store_reset */
496
extern uschar  debuglog_name[LOG_NAME_SIZE]; /* ACL-init debug */
497
474
extern int     delay_warning[];        /* Times between warnings */
498
extern int     delay_warning[];        /* Times between warnings */
475
extern uschar *delay_warning_condition; /* Condition string for warnings */
499
extern uschar *delay_warning_condition; /* Condition string for warnings */
476
extern BOOL    delivery_date_remove;   /* Remove delivery-date headers */
500
extern BOOL    delivery_date_remove;   /* Remove delivery-date headers */
Lines 546-551 Link Here
546
extern int     dns_retrans;            /* Retransmission time setting */
570
extern int     dns_retrans;            /* Retransmission time setting */
547
extern int     dns_retry;              /* Number of retries */
571
extern int     dns_retry;              /* Number of retries */
548
extern int     dns_dnssec_ok;          /* When constructing DNS query, set DO flag */
572
extern int     dns_dnssec_ok;          /* When constructing DNS query, set DO flag */
573
extern const uschar * dns_rc_names[];  /* Mostly for debug output */
549
extern uschar *dns_trust_aa;           /* DNSSEC trust AA as AD */
574
extern uschar *dns_trust_aa;           /* DNSSEC trust AA as AD */
550
extern int     dns_use_edns0;          /* Coerce EDNS0 support on/off in resolver. */
575
extern int     dns_use_edns0;          /* Coerce EDNS0 support on/off in resolver. */
551
extern uschar *dnslist_domain;         /* DNS (black) list domain */
576
extern uschar *dnslist_domain;         /* DNS (black) list domain */
Lines 557-562 Link Here
557
582
558
/* This option is now a no-opt, retained for compatibility */
583
/* This option is now a no-opt, retained for compatibility */
559
extern BOOL    drop_cr;                /* For broken local MUAs */
584
extern BOOL    drop_cr;                /* For broken local MUAs */
585
extern const uschar *driver_srcfile;   /* For debug & errors */
586
extern int     driver_srcline;	       /* For debug & errors */
587
588
extern unsigned int dtrigger_selector; /* when to start debug */
560
589
561
extern uschar *dsn_from;               /* From: string for DSNs */
590
extern uschar *dsn_from;               /* From: string for DSNs */
562
591
Lines 584-590 Link Here
584
extern int     expand_forbid;          /* RDO flags for forbidding things */
613
extern int     expand_forbid;          /* RDO flags for forbidding things */
585
extern int     expand_nlength[];       /* Lengths of numbered strings */
614
extern int     expand_nlength[];       /* Lengths of numbered strings */
586
extern int     expand_nmax;            /* Max numerical value */
615
extern int     expand_nmax;            /* Max numerical value */
587
extern uschar *expand_nstring[];       /* Numbered strings */
616
extern const uschar *expand_nstring[];       /* Numbered strings */
588
extern BOOL    extract_addresses_remove_arguments; /* Controls -t behaviour */
617
extern BOOL    extract_addresses_remove_arguments; /* Controls -t behaviour */
589
extern uschar *extra_local_interfaces; /* Local, non-listen interfaces */
618
extern uschar *extra_local_interfaces; /* Local, non-listen interfaces */
590
619
Lines 630-635 Link Here
630
extern uschar *host_lookup_msg;        /* Text for why it failed */
659
extern uschar *host_lookup_msg;        /* Text for why it failed */
631
extern int     host_number;            /* For sharing spools */
660
extern int     host_number;            /* For sharing spools */
632
extern uschar *host_number_string;     /* For expanding */
661
extern uschar *host_number_string;     /* For expanding */
662
extern uschar *hosts_require_helo;     /* check for HELO/EHLO before MAIL */
633
extern uschar *host_reject_connection; /* Reject these hosts */
663
extern uschar *host_reject_connection; /* Reject these hosts */
634
extern tree_node *hostlist_anchor;     /* Tree of defined host lists */
664
extern tree_node *hostlist_anchor;     /* Tree of defined host lists */
635
extern int     hostlist_count;         /* Number defined */
665
extern int     hostlist_count;         /* Number defined */
Lines 649-654 Link Here
649
extern int     keep_malformed;         /* Time to keep malformed messages */
679
extern int     keep_malformed;         /* Time to keep malformed messages */
650
680
651
extern uschar *eldap_dn;               /* Where LDAP DNs are left */
681
extern uschar *eldap_dn;               /* Where LDAP DNs are left */
682
#ifdef EXPERIMENTAL_ESMTP_LIMITS
683
extern uschar *limits_advertise_hosts; /* for banner/EHLO pipelining */
684
#endif
652
extern int     load_average;           /* Most recently read load average */
685
extern int     load_average;           /* Most recently read load average */
653
extern BOOL    local_from_check;       /* For adding Sender: (global value) */
686
extern BOOL    local_from_check;       /* For adding Sender: (global value) */
654
extern uschar *local_from_prefix;      /* Permitted prefixes */
687
extern uschar *local_from_prefix;      /* Permitted prefixes */
Lines 704-710 Link Here
704
extern uschar *message_id_external;    /* External form of following */
737
extern uschar *message_id_external;    /* External form of following */
705
extern uschar *message_id_domain;      /* Expanded to form domain-part of message_id */
738
extern uschar *message_id_domain;      /* Expanded to form domain-part of message_id */
706
extern uschar *message_id_text;        /* Expanded to form message_id */
739
extern uschar *message_id_text;        /* Expanded to form message_id */
707
extern struct timeval message_id_tv;   /* Time used to create last message_id */
708
extern int     message_linecount;      /* As it says */
740
extern int     message_linecount;      /* As it says */
709
extern BOOL    message_logs;           /* TRUE to write message logs */
741
extern BOOL    message_logs;           /* TRUE to write message logs */
710
extern int     message_size;           /* Size of message */
742
extern int     message_size;           /* Size of message */
Lines 712-718 Link Here
712
#ifdef SUPPORT_I18N
744
#ifdef SUPPORT_I18N
713
extern BOOL    message_smtputf8;       /* Internationalized mail handling */
745
extern BOOL    message_smtputf8;       /* Internationalized mail handling */
714
extern int     message_utf8_downconvert; /* convert from utf8 */
746
extern int     message_utf8_downconvert; /* convert from utf8 */
715
const extern pcre *regex_UTF8;         /* For recognizing SMTPUTF8 settings */
747
const extern pcre2_code *regex_UTF8;         /* For recognizing SMTPUTF8 settings */
716
#endif
748
#endif
717
extern uschar  message_subdir[];       /* Subdirectory for messages */
749
extern uschar  message_subdir[];       /* Subdirectory for messages */
718
extern uschar *message_reference;      /* Reference for error messages */
750
extern uschar *message_reference;      /* Reference for error messages */
Lines 760-765 Link Here
760
extern uschar *override_local_interfaces; /* Value of -oX argument */
792
extern uschar *override_local_interfaces; /* Value of -oX argument */
761
extern uschar *override_pid_file_path; /* Value of -oP argument */
793
extern uschar *override_pid_file_path; /* Value of -oP argument */
762
794
795
extern pcre2_general_context * pcre_gen_ctx;	/* pcre memory management */
796
extern pcre2_compile_context * pcre_cmp_ctx;
797
extern pcre2_match_context *   pcre_mtc_ctx;
798
763
extern uschar *percent_hack_domains;   /* Local domains for which '% operates */
799
extern uschar *percent_hack_domains;   /* Local domains for which '% operates */
764
extern uschar *pid_file_path;          /* For writing daemon pids */
800
extern uschar *pid_file_path;          /* For writing daemon pids */
765
#ifndef DISABLE_PIPE_CONNECT
801
#ifndef DISABLE_PIPE_CONNECT
Lines 785-790 Link Here
785
extern int     proxy_external_port;    /* Port on remote interface of proxy */
821
extern int     proxy_external_port;    /* Port on remote interface of proxy */
786
extern uschar *proxy_local_address;    /* IP of local interface of proxy */
822
extern uschar *proxy_local_address;    /* IP of local interface of proxy */
787
extern int     proxy_local_port;       /* Port on local interface of proxy */
823
extern int     proxy_local_port;       /* Port on local interface of proxy */
824
extern int     proxy_protocol_timeout; /* Timeout for proxy negotiation */
788
extern BOOL    proxy_session;          /* TRUE if receiving mail from valid proxy  */
825
extern BOOL    proxy_session;          /* TRUE if receiving mail from valid proxy  */
789
#endif
826
#endif
790
827
Lines 795-801 Link Here
795
extern const uschar *qualify_domain_recipient; /* Domain to qualify recipients with */
832
extern const uschar *qualify_domain_recipient; /* Domain to qualify recipients with */
796
extern uschar *qualify_domain_sender;  /* Domain to qualify senders with */
833
extern uschar *qualify_domain_sender;  /* Domain to qualify senders with */
797
extern uschar *queue_domains;          /* Queue these domains */
834
extern uschar *queue_domains;          /* Queue these domains */
798
#ifdef EXPERIMENTAL_QUEUE_RAMP
835
#ifndef DISABLE_QUEUE_RAMP
799
extern BOOL    queue_fast_ramp;        /* 2-phase queue-run overlap */
836
extern BOOL    queue_fast_ramp;        /* 2-phase queue-run overlap */
800
#endif
837
#endif
801
extern BOOL    queue_list_requires_admin; /* TRUE if -bp requires admin */
838
extern BOOL    queue_list_requires_admin; /* TRUE if -bp requires admin */
Lines 837-865 Link Here
837
extern uschar *received_for;           /* For "for" field */
874
extern uschar *received_for;           /* For "for" field */
838
extern uschar *received_header_text;   /* Definition of Received: header */
875
extern uschar *received_header_text;   /* Definition of Received: header */
839
extern int     received_headers_max;   /* Max count of Received: headers */
876
extern int     received_headers_max;   /* Max count of Received: headers */
840
extern struct timeval received_time;   /* Time the message was received */
877
extern struct timeval received_time;   /* Time the message started to be received */
841
extern struct timeval received_time_taken; /* Interval the message took to be received */
878
extern struct timeval received_time_complete; /* Time the message completed reception */
842
extern uschar *recipient_data;         /* lookup data for recipients */
879
extern uschar *recipient_data;         /* lookup data for recipients */
843
extern uschar *recipient_unqualified_hosts; /* Permitted unqualified recipients */
880
extern uschar *recipient_unqualified_hosts; /* Permitted unqualified recipients */
844
extern uschar *recipient_verify_failure; /* What went wrong */
881
extern uschar *recipient_verify_failure; /* What went wrong */
845
extern int     recipients_list_max;    /* Maximum number fitting in list */
882
extern int     recipients_list_max;    /* Maximum number fitting in list */
846
extern int     recipients_max;         /* Max permitted */
883
extern int     recipients_max;         /* Max permitted */
847
extern BOOL    recipients_max_reject;  /* If TRUE, reject whole message */
884
extern BOOL    recipients_max_reject;  /* If TRUE, reject whole message */
848
extern const pcre *regex_AUTH;         /* For recognizing AUTH settings */
885
extern const pcre2_code *regex_AUTH;         /* For recognizing AUTH settings */
849
extern const pcre  *regex_check_dns_names; /* For DNS name checking */
886
extern const pcre2_code  *regex_check_dns_names; /* For DNS name checking */
850
extern const pcre  *regex_From;        /* For recognizing "From_" lines */
887
extern const pcre2_code  *regex_From;        /* For recognizing "From_" lines */
851
extern const pcre  *regex_CHUNKING;    /* For recognizing CHUNKING (RFC 3030) */
888
extern const pcre2_code  *regex_CHUNKING;    /* For recognizing CHUNKING (RFC 3030) */
852
extern const pcre  *regex_IGNOREQUOTA; /* For recognizing IGNOREQUOTA (LMTP) */
889
extern const pcre2_code  *regex_IGNOREQUOTA; /* For recognizing IGNOREQUOTA (LMTP) */
853
extern const pcre  *regex_PIPELINING;  /* For recognizing PIPELINING */
890
#ifdef EXPERIMENTAL_ESMTP_LIMITS
854
extern const pcre  *regex_SIZE;        /* For recognizing SIZE settings */
891
extern const pcre2_code  *regex_LIMITS; /* For recognizing LIMITS */
892
#endif
893
extern const pcre2_code  *regex_PIPELINING;  /* For recognizing PIPELINING */
894
extern const pcre2_code  *regex_SIZE;        /* For recognizing SIZE settings */
855
#ifndef DISABLE_PIPE_CONNECT
895
#ifndef DISABLE_PIPE_CONNECT
856
extern const pcre  *regex_EARLY_PIPE;  /* For recognizing PIPE_CONNCT */
896
extern const pcre2_code  *regex_EARLY_PIPE;  /* For recognizing PIPE_CONNCT */
857
#endif
897
#endif
858
extern const pcre  *regex_ismsgid;     /* Compiled r.e. for message it */
898
extern const pcre2_code  *regex_ismsgid;     /* Compiled r.e. for message ID */
859
extern const pcre  *regex_smtp_code;   /* For recognizing SMTP codes */
899
extern const pcre2_code  *regex_smtp_code;   /* For recognizing SMTP codes */
860
extern uschar *regex_vars[];           /* $regexN variables */
900
extern const uschar *regex_vars[];           /* $regexN variables */
861
#ifdef WHITELIST_D_MACROS
901
#ifdef WHITELIST_D_MACROS
862
extern const pcre  *regex_whitelisted_macro; /* For -D macro values */
902
extern const pcre2_code  *regex_whitelisted_macro; /* For -D macro values */
863
#endif
903
#endif
864
#ifdef WITH_CONTENT_SCAN
904
#ifdef WITH_CONTENT_SCAN
865
extern uschar *regex_match_string;     /* regex that matched a line (regex ACL condition) */
905
extern uschar *regex_match_string;     /* regex that matched a line (regex ACL condition) */
Lines 922-933 Link Here
922
extern int     smtp_accept_max;        /* Max SMTP connections */
962
extern int     smtp_accept_max;        /* Max SMTP connections */
923
extern int     smtp_accept_max_nonmail;/* Max non-mail commands in one con */
963
extern int     smtp_accept_max_nonmail;/* Max non-mail commands in one con */
924
extern uschar *smtp_accept_max_nonmail_hosts; /* Limit non-mail cmds from these hosts */
964
extern uschar *smtp_accept_max_nonmail_hosts; /* Limit non-mail cmds from these hosts */
925
extern int     smtp_accept_max_per_connection; /* Max msgs per connection */
965
extern uschar *smtp_accept_max_per_connection; /* Max msgs per connection */
926
extern uschar *smtp_accept_max_per_host; /* Max SMTP cons from one IP addr */
966
extern uschar *smtp_accept_max_per_host; /* Max SMTP cons from one IP addr */
927
extern int     smtp_accept_queue;      /* Queue after so many connections */
967
extern int     smtp_accept_queue;      /* Queue after so many connections */
928
extern int     smtp_accept_queue_per_connection; /* Queue after so many msgs */
968
extern int     smtp_accept_queue_per_connection; /* Queue after so many msgs */
929
extern int     smtp_accept_reserve;    /* Reserve these SMTP connections */
969
extern int     smtp_accept_reserve;    /* Reserve these SMTP connections */
930
extern uschar *smtp_active_hostname;   /* Hostname for this message */
970
extern uschar *smtp_active_hostname;   /* Hostname for this message */
971
extern int     smtp_backlog_monitor;   /* listen backlog level to log */
931
extern uschar *smtp_banner;            /* Banner string (to be expanded) */
972
extern uschar *smtp_banner;            /* Banner string (to be expanded) */
932
extern BOOL    smtp_check_spool_space; /* TRUE to check SMTP SIZE value */
973
extern BOOL    smtp_check_spool_space; /* TRUE to check SMTP SIZE value */
933
extern int     smtp_ch_index;          /* Index in smtp_connection_had */
974
extern int     smtp_ch_index;          /* Index in smtp_connection_had */
Lines 942-951 Link Here
942
extern uschar *smtp_etrn_command;      /* Command to run */
983
extern uschar *smtp_etrn_command;      /* Command to run */
943
extern BOOL    smtp_etrn_serialize;    /* Only one at once */
984
extern BOOL    smtp_etrn_serialize;    /* Only one at once */
944
extern FILE   *smtp_in;                /* Incoming SMTP input file */
985
extern FILE   *smtp_in;                /* Incoming SMTP input file */
986
extern int     smtp_listen_backlog;    /* Current listener socket backlog, if monitored */
945
extern int     smtp_load_reserve;      /* Only from reserved if load > this */
987
extern int     smtp_load_reserve;      /* Only from reserved if load > this */
946
extern int     smtp_mailcmd_count;     /* Count of MAIL commands */
988
extern int     smtp_mailcmd_count;     /* Count of MAIL commands */
989
extern int     smtp_mailcmd_max;       /* Limit for MAIL commands */
947
extern int     smtp_max_synprot_errors;/* Max syntax/protocol errors */
990
extern int     smtp_max_synprot_errors;/* Max syntax/protocol errors */
948
extern int     smtp_max_unknown_commands; /* As it says */
991
extern int     smtp_max_unknown_commands; /* As it says */
992
extern uschar *smtp_names[];	       /* decode for command codes */
949
extern uschar *smtp_notquit_reason;    /* Global for disconnect reason */
993
extern uschar *smtp_notquit_reason;    /* Global for disconnect reason */
950
extern FILE   *smtp_out;               /* Incoming SMTP output file */
994
extern FILE   *smtp_out;               /* Incoming SMTP output file */
951
extern uschar *smtp_ratelimit_hosts;   /* Rate limit these hosts */
995
extern uschar *smtp_ratelimit_hosts;   /* Rate limit these hosts */
Lines 992-1013 Link Here
992
extern FILE   *spool_data_file;	       /* handle for -D file */
1036
extern FILE   *spool_data_file;	       /* handle for -D file */
993
extern uschar *spool_directory;        /* Name of spool directory */
1037
extern uschar *spool_directory;        /* Name of spool directory */
994
extern BOOL    spool_wireformat;       /* can write wireformat -D files */
1038
extern BOOL    spool_wireformat;       /* can write wireformat -D files */
995
#ifdef EXPERIMENTAL_SRS
1039
#ifdef SUPPORT_SRS
996
extern uschar *srs_config;             /* SRS config secret:max age:hash length:use timestamp:use hash */
997
extern uschar *srs_db_address;         /* SRS db address */
998
extern uschar *srs_db_key;             /* SRS db key */
999
extern int     srs_hashlength;         /* SRS hash length */
1000
extern int     srs_hashmin;            /* SRS minimum hash length */
1001
extern int     srs_maxage;             /* SRS max age */
1002
extern uschar *srs_orig_sender;        /* SRS original sender */
1003
extern uschar *srs_orig_recipient;     /* SRS original recipient */
1004
extern uschar *srs_recipient;          /* SRS recipient */
1005
extern uschar *srs_secrets;            /* SRS secrets list */
1006
extern uschar *srs_status;             /* SRS staus */
1007
extern BOOL    srs_usehash;            /* SRS use hash flag */
1008
extern BOOL    srs_usetimestamp;       /* SRS use timestamp flag */
1009
#endif
1010
#ifdef EXPERIMENTAL_SRS_NATIVE
1011
extern uschar *srs_recipient;          /* SRS recipient */
1040
extern uschar *srs_recipient;          /* SRS recipient */
1012
#endif
1041
#endif
1013
extern BOOL    strict_acl_vars;        /* ACL variables have to be set before being used */
1042
extern BOOL    strict_acl_vars;        /* ACL variables have to be set before being used */
Lines 1016-1023 Link Here
1016
extern int     string_datestamp_type;  /* After insertion by string_format */
1045
extern int     string_datestamp_type;  /* After insertion by string_format */
1017
extern BOOL    strip_excess_angle_brackets; /* Surrounding route-addrs */
1046
extern BOOL    strip_excess_angle_brackets; /* Surrounding route-addrs */
1018
extern BOOL    strip_trailing_dot;     /* Remove dots at ends of domains */
1047
extern BOOL    strip_trailing_dot;     /* Remove dots at ends of domains */
1019
extern uschar *submission_domain;      /* Domain for submission mode */
1048
extern const uschar *submission_domain;/* Domain for submission mode */
1020
extern uschar *submission_name;        /* User name set from ACL */
1049
extern const uschar *submission_name;  /* User name set from ACL */
1021
extern BOOL    syslog_duplication;     /* FALSE => no duplicate logging */
1050
extern BOOL    syslog_duplication;     /* FALSE => no duplicate logging */
1022
extern int     syslog_facility;        /* As defined by Syslog.h */
1051
extern int     syslog_facility;        /* As defined by Syslog.h */
1023
extern BOOL    syslog_pid;             /* TRUE if PID on syslogs */
1052
extern BOOL    syslog_pid;             /* TRUE if PID on syslogs */
(-)exim.orig/src/hash.c (-16 / +67 lines)
Lines 1-7 Link Here
1
/*
1
/*
2
 *  Exim - an Internet mail transport agent
2
 *  Exim - an Internet mail transport agent
3
 *
3
 *
4
 *  Copyright (C) 2010 - 2018  Exim maintainers
4
 *  Copyright (c) The Exim Maintainers 2010 - 2022
5
 *  Copyright (c) University of Cambridge 1995 - 2009
5
 *  Copyright (c) University of Cambridge 1995 - 2009
6
 *
6
 *
7
 *  Hash interface functions
7
 *  Hash interface functions
Lines 29-45 Link Here
29
29
30
/******************************************************************************/
30
/******************************************************************************/
31
#ifdef SHA_OPENSSL
31
#ifdef SHA_OPENSSL
32
# define HAVE_PARTIAL_SHA
32
33
33
BOOL
34
BOOL
34
exim_sha_init(hctx * h, hashmethod m)
35
exim_sha_init(hctx * h, hashmethod m)
35
{
36
{
37
# if OPENSSL_VERSION_NUMBER < 0x30000000L
36
switch (h->method = m)
38
switch (h->method = m)
37
  {
39
  {
38
  case HASH_SHA1:     h->hashlen = 20; SHA1_Init  (&h->u.sha1);     break;
40
  case HASH_SHA1:     h->hashlen = 20; SHA1_Init  (&h->u.sha1);     break;
39
  case HASH_SHA2_256: h->hashlen = 32; SHA256_Init(&h->u.sha2_256); break;
41
  case HASH_SHA2_256: h->hashlen = 32; SHA256_Init(&h->u.sha2_256); break;
40
  case HASH_SHA2_384: h->hashlen = 48; SHA384_Init(&h->u.sha2_512); break;
42
  case HASH_SHA2_384: h->hashlen = 48; SHA384_Init(&h->u.sha2_512); break;
41
  case HASH_SHA2_512: h->hashlen = 64; SHA512_Init(&h->u.sha2_512); break;
43
  case HASH_SHA2_512: h->hashlen = 64; SHA512_Init(&h->u.sha2_512); break;
42
#ifdef EXIM_HAVE_SHA3
44
#  ifdef EXIM_HAVE_SHA3
43
  case HASH_SHA3_224: h->hashlen = 28;
45
  case HASH_SHA3_224: h->hashlen = 28;
44
		      EVP_DigestInit(h->u.mctx = EVP_MD_CTX_new(), EVP_sha3_224());
46
		      EVP_DigestInit(h->u.mctx = EVP_MD_CTX_new(), EVP_sha3_224());
45
		      break;
47
		      break;
Lines 52-83 Link Here
52
  case HASH_SHA3_512: h->hashlen = 64;
54
  case HASH_SHA3_512: h->hashlen = 64;
53
		      EVP_DigestInit(h->u.mctx = EVP_MD_CTX_new(), EVP_sha3_512());
55
		      EVP_DigestInit(h->u.mctx = EVP_MD_CTX_new(), EVP_sha3_512());
54
		      break;
56
		      break;
55
#endif
57
#  endif
56
  default:	      h->hashlen = 0; return FALSE;
58
  default:	      h->hashlen = 0; return FALSE;
57
  }
59
  }
58
return TRUE;
60
return TRUE;
61
62
# else
63
EVP_MD * md;
64
65
h->hashlen = 0;
66
if (!(h->u.mctx = EVP_MD_CTX_new())) return FALSE;
67
switch (h->method = m)
68
  {
69
  case HASH_SHA1:     h->hashlen = 20; md = EVP_MD_fetch(NULL, "SHA1", NULL); break;
70
  case HASH_SHA2_256: h->hashlen = 32; md = EVP_MD_fetch(NULL, "SHA2-256", NULL); break;
71
  case HASH_SHA2_384: h->hashlen = 48; md = EVP_MD_fetch(NULL, "SHA2-384", NULL); break;
72
  case HASH_SHA2_512: h->hashlen = 64; md = EVP_MD_fetch(NULL, "SHA2-512", NULL); break;
73
  case HASH_SHA3_224: h->hashlen = 28; md = EVP_MD_fetch(NULL, "SHA3-224", NULL); break;
74
  case HASH_SHA3_256: h->hashlen = 32; md = EVP_MD_fetch(NULL, "SHA3-256", NULL); break;
75
  case HASH_SHA3_384: h->hashlen = 48; md = EVP_MD_fetch(NULL, "SHA3-384", NULL); break;
76
  case HASH_SHA3_512: h->hashlen = 64; md = EVP_MD_fetch(NULL, "SHA3-512", NULL); break;
77
  default:	      return FALSE;
78
  }
79
if (md && EVP_DigestInit_ex(h->u.mctx, md, NULL))
80
  return TRUE;
81
82
h->hashlen = 0;
83
return FALSE;
84
# endif
59
}
85
}
60
86
61
87
62
void
88
void
63
exim_sha_update(hctx * h, const uschar * data, int len)
89
exim_sha_update(hctx * h, const uschar * data, int len)
64
{
90
{
91
# if OPENSSL_VERSION_NUMBER < 0x30000000L
65
switch (h->method)
92
switch (h->method)
66
  {
93
  {
67
  case HASH_SHA1:     SHA1_Update  (&h->u.sha1,     data, len); break;
94
  case HASH_SHA1:     SHA1_Update  (&h->u.sha1,     data, len); break;
68
  case HASH_SHA2_256: SHA256_Update(&h->u.sha2_256, data, len); break;
95
  case HASH_SHA2_256: SHA256_Update(&h->u.sha2_256, data, len); break;
69
  case HASH_SHA2_384: SHA384_Update(&h->u.sha2_512, data, len); break;
96
  case HASH_SHA2_384: SHA384_Update(&h->u.sha2_512, data, len); break;
70
  case HASH_SHA2_512: SHA512_Update(&h->u.sha2_512, data, len); break;
97
  case HASH_SHA2_512: SHA512_Update(&h->u.sha2_512, data, len); break;
71
#ifdef EXIM_HAVE_SHA3
98
#  ifdef EXIM_HAVE_SHA3
72
  case HASH_SHA3_224:
99
  case HASH_SHA3_224:
73
  case HASH_SHA3_256:
100
  case HASH_SHA3_256:
74
  case HASH_SHA3_384:
101
  case HASH_SHA3_384:
75
  case HASH_SHA3_512: EVP_DigestUpdate(h->u.mctx, data, len); break;
102
  case HASH_SHA3_512: EVP_DigestUpdate(h->u.mctx, data, len); break;
76
#endif
103
#  endif
77
  /* should be blocked by init not handling these, but be explicit to
104
  /* should be blocked by init not handling these, but be explicit to
78
  guard against accidents later (and hush up clang -Wswitch) */
105
  guard against accidents later (and hush up clang -Wswitch) */
79
  default: assert(0);
106
  default: assert(0);
80
  }
107
  }
108
109
# else
110
111
EVP_DigestUpdate(h->u.mctx, data, len);
112
# endif
81
}
113
}
82
114
83
115
Lines 85-110 Link Here
85
exim_sha_finish(hctx * h, blob * b)
117
exim_sha_finish(hctx * h, blob * b)
86
{
118
{
87
/* Hashing is sufficient to purify any tainted input */
119
/* Hashing is sufficient to purify any tainted input */
88
b->data = store_get(b->len = h->hashlen, FALSE);
120
b->data = store_get(b->len = h->hashlen, GET_UNTAINTED);
121
122
# if OPENSSL_VERSION_NUMBER < 0x30000000L
89
switch (h->method)
123
switch (h->method)
90
  {
124
  {
91
  case HASH_SHA1:     SHA1_Final  (b->data, &h->u.sha1);     break;
125
  case HASH_SHA1:     SHA1_Final  (b->data, &h->u.sha1);     break;
92
  case HASH_SHA2_256: SHA256_Final(b->data, &h->u.sha2_256); break;
126
  case HASH_SHA2_256: SHA256_Final(b->data, &h->u.sha2_256); break;
93
  case HASH_SHA2_384: SHA384_Final(b->data, &h->u.sha2_512); break;
127
  case HASH_SHA2_384: SHA384_Final(b->data, &h->u.sha2_512); break;
94
  case HASH_SHA2_512: SHA512_Final(b->data, &h->u.sha2_512); break;
128
  case HASH_SHA2_512: SHA512_Final(b->data, &h->u.sha2_512); break;
95
#ifdef EXIM_HAVE_SHA3
129
#  ifdef EXIM_HAVE_SHA3
96
  case HASH_SHA3_224:
130
  case HASH_SHA3_224:
97
  case HASH_SHA3_256:
131
  case HASH_SHA3_256:
98
  case HASH_SHA3_384:
132
  case HASH_SHA3_384:
99
  case HASH_SHA3_512: EVP_DigestFinal(h->u.mctx, b->data, NULL); break;
133
  case HASH_SHA3_512: EVP_DigestFinal(h->u.mctx, b->data, NULL); break;
100
#endif
134
#  endif
101
  default: assert(0);
135
  default: assert(0);
102
  }
136
  }
137
138
# else
139
140
EVP_DigestFinal_ex(h->u.mctx, b->data, NULL);
141
EVP_MD_free((EVP_MD *) EVP_MD_CTX_get0_md(h->u.mctx));
142
EVP_MD_CTX_free(h->u.mctx);
143
144
# endif
103
}
145
}
104
146
105
147
106
148
107
#elif defined(SHA_GNUTLS)
149
#elif defined(SHA_GNUTLS)
150
# define HAVE_PARTIAL_SHA
108
/******************************************************************************/
151
/******************************************************************************/
109
152
110
BOOL
153
BOOL
Lines 138-150 Link Here
138
void
181
void
139
exim_sha_finish(hctx * h, blob * b)
182
exim_sha_finish(hctx * h, blob * b)
140
{
183
{
141
b->data = store_get(b->len = h->hashlen, FALSE);
184
b->data = store_get(b->len = h->hashlen, GET_UNTAINTED);
142
gnutls_hash_output(h->sha, b->data);
185
gnutls_hash_output(h->sha, b->data);
143
}
186
}
144
187
145
188
146
189
147
#elif defined(SHA_GCRYPT)
190
#elif defined(SHA_GCRYPT)
191
# define HAVE_PARTIAL_SHA
148
/******************************************************************************/
192
/******************************************************************************/
149
193
150
BOOL
194
BOOL
Lines 175-181 Link Here
175
void
219
void
176
exim_sha_finish(hctx * h, blob * b)
220
exim_sha_finish(hctx * h, blob * b)
177
{
221
{
178
b->data = store_get(b->len = h->hashlen, FALSE);
222
b->data = store_get(b->len = h->hashlen, GET_UNTAINTED);
179
memcpy(b->data, gcry_md_read(h->sha, 0), h->hashlen);
223
memcpy(b->data, gcry_md_read(h->sha, 0), h->hashlen);
180
}
224
}
181
225
Lines 183-188 Link Here
183
227
184
228
185
#elif defined(SHA_POLARSSL)
229
#elif defined(SHA_POLARSSL)
230
# define HAVE_PARTIAL_SHA
186
/******************************************************************************/
231
/******************************************************************************/
187
232
188
BOOL
233
BOOL
Lines 213-219 Link Here
213
void
258
void
214
exim_sha_finish(hctx * h, blob * b)
259
exim_sha_finish(hctx * h, blob * b)
215
{
260
{
216
b->data = store_get(b->len = h->hashlen, FALSE);
261
b->data = store_get(b->len = h->hashlen, GET_INTAINTED);
217
switch (h->method)
262
switch (h->method)
218
  {
263
  {
219
  case HASH_SHA1:   sha1_finish(h->u.sha1, b->data); break;
264
  case HASH_SHA1:   sha1_finish(h->u.sha1, b->data); break;
Lines 391-399 Link Here
391
  memset(work, 0, 56);
436
  memset(work, 0, 56);
392
  }
437
  }
393
else
438
else
394
  {
395
  memset(work+length+1, 0, 55-length);
439
  memset(work+length+1, 0, 55-length);
396
  }
397
440
398
/* The final 8 bytes of the final chunk are a 64-bit representation of the
441
/* The final 8 bytes of the final chunk are a 64-bit representation of the
399
length of the input string *bits*, before padding, high order word first, and
442
length of the input string *bits*, before padding, high order word first, and
Lines 451-457 Link Here
451
void
494
void
452
exim_sha_finish(hctx * h, blob * b)
495
exim_sha_finish(hctx * h, blob * b)
453
{
496
{
454
b->data = store_get(b->len = h->hashlen, FALSE);
497
b->data = store_get(b->len = h->hashlen, GET_UNTAINTED);
455
498
456
native_sha1_end(&h->sha1, NULL, 0, b->data);
499
native_sha1_end(&h->sha1, NULL, 0, b->data);
457
}
500
}
Lines 515-520 Link Here
515
558
516
559
517
560
561
#ifdef HAVE_PARTIAL_SHA
562
# undef HAVE_PARTIAL_SHA
563
void
564
exim_sha_update_string(hctx * h, const uschar * s)
565
{
566
if (s) exim_sha_update(h, s, Ustrlen(s));
567
}
568
#endif
518
569
519
570
520
571
Lines 524-530 Link Here
524
**************************************************
575
**************************************************
525
*************************************************/
576
*************************************************/
526
577
527
# ifdef STAND_ALONE
578
#ifdef STAND_ALONE
528
579
529
/* Test values. The first 128 may contain binary zeros and have increasing
580
/* Test values. The first 128 may contain binary zeros and have increasing
530
length. */
581
length. */
Lines 839-844 Link Here
839
if (strcmp(s, atest) != 0) printf("*** No match ***\n");
890
if (strcmp(s, atest) != 0) printf("*** No match ***\n");
840
891
841
}
892
}
842
# endif	/*STAND_ALONE*/
893
#endif	/*STAND_ALONE*/
843
894
844
/* End of File */
895
/* End of File */
(-)exim.orig/src/hash.h (-2 / +2 lines)
Lines 1-7 Link Here
1
/*
1
/*
2
 *  Exim - an Internet mail transport agent
2
 *  Exim - an Internet mail transport agent
3
 *
3
 *  Copyright (c) The Exim Maintainers 1995 - 2022
4
 *  Copyright (C) 1995 - 2018  Exim maintainers
5
 *
4
 *
6
 *  Hash interface functions
5
 *  Hash interface functions
7
 */
6
 */
Lines 77-82 Link Here
77
76
78
extern BOOL     exim_sha_init(hctx *, hashmethod);
77
extern BOOL     exim_sha_init(hctx *, hashmethod);
79
extern void     exim_sha_update(hctx *, const uschar *a, int);
78
extern void     exim_sha_update(hctx *, const uschar *a, int);
79
extern void     exim_sha_update_string(hctx *, const uschar *a);
80
extern void     exim_sha_finish(hctx *, blob *);
80
extern void     exim_sha_finish(hctx *, blob *);
81
81
82
#endif
82
#endif
(-)exim.orig/src/header.c (-14 / +15 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2016 */
6
/* Copyright (c) University of Cambridge 1995 - 2016 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 97-108 Link Here
97
header_line *h, *new = NULL;
97
header_line *h, *new = NULL;
98
header_line **hptr;
98
header_line **hptr;
99
99
100
uschar *p, *q;
100
uschar * p, * q, * buf;
101
uschar * buf = store_get(HEADER_ADD_BUFFER_SIZE, FALSE);
101
gstring gs;
102
gstring gs = { .size = HEADER_ADD_BUFFER_SIZE, .ptr = 0, .s = buf };
103
102
104
if (!header_last) return NULL;
103
if (!header_last) return NULL;
105
104
105
gs.s = buf = store_get(HEADER_ADD_BUFFER_SIZE, GET_UNTAINTED);
106
gs.size = HEADER_ADD_BUFFER_SIZE;
107
gs.ptr = 0;
108
106
if (!string_vformat(&gs, SVFMT_REBUFFER, format, ap))
109
if (!string_vformat(&gs, SVFMT_REBUFFER, format, ap))
107
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "string too long in header_add: "
110
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "string too long in header_add: "
108
    "%.100s ...", string_from_gstring(&gs));
111
    "%.100s ...", string_from_gstring(&gs));
Lines 179-185 Link Here
179
    if (*(++q) != ' ' && *q != '\t') break;
182
    if (*(++q) != ' ' && *q != '\t') break;
180
    }
183
    }
181
184
182
  new = store_get(sizeof(header_line), FALSE);
185
  new = store_get(sizeof(header_line), GET_UNTAINTED);
183
  new->text = string_copyn(p, q - p);
186
  new->text = string_copyn(p, q - p);
184
  new->slen = q - p;
187
  new->slen = q - p;
185
  new->type = type;
188
  new->type = type;
Lines 368-374 Link Here
368
one_pattern_match(uschar *name, int slen, BOOL has_addresses, uschar *pattern)
371
one_pattern_match(uschar *name, int slen, BOOL has_addresses, uschar *pattern)
369
{
372
{
370
BOOL yield = FALSE;
373
BOOL yield = FALSE;
371
const pcre *re = NULL;
374
const pcre2_code *re = NULL;
372
375
373
/* If the pattern is a regex, compile it. Bomb out if compiling fails; these
376
/* If the pattern is a regex, compile it. Bomb out if compiling fails; these
374
patterns are all constructed internally and should be valid. */
377
patterns are all constructed internally and should be valid. */
Lines 416-425 Link Here
416
419
417
      /* Otherwise, test for the pattern; a non-regex must be an exact match */
420
      /* Otherwise, test for the pattern; a non-regex must be an exact match */
418
421
419
      yield = !re
422
      yield = re
420
        ? (strcmpic(next, pattern) == 0)
423
	? regex_match(re, next, -1, NULL)
421
        : (pcre_exec(re, NULL, CS next, Ustrlen(next), 0, PCRE_EOPT, NULL, 0)
424
        : (strcmpic(next, pattern) == 0);
422
          >= 0);
423
      }
425
      }
424
    }
426
    }
425
427
Lines 428-437 Link Here
428
430
429
  else
431
  else
430
    {
432
    {
431
    yield = (re == NULL)?
433
    yield = re
432
      (strstric(h->text, pattern, FALSE) != NULL)
434
      ? regex_match(re, h->text, h->slen, NULL)
433
      :
435
      : (strstric(h->text, pattern, FALSE) != NULL);
434
      (pcre_exec(re, NULL, CS h->text, h->slen, 0, PCRE_EOPT, NULL, 0) >= 0);
435
    }
436
    }
436
  }
437
  }
437
438
(-)exim.orig/src/host.c (-81 / +93 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Functions for finding hosts, either by gethostbyname(), gethostbyaddr(), or
9
/* Functions for finding hosts, either by gethostbyname(), gethostbyaddr(), or
Lines 197-205 Link Here
197
     ||  ipa == 6 && af == AF_INET6)
197
     ||  ipa == 6 && af == AF_INET6)
198
    {
198
    {
199
    int x[4];
199
    int x[4];
200
    yield = store_get(sizeof(struct hostent), FALSE);
200
    yield = store_get(sizeof(struct hostent), GET_UNTAINTED);
201
    alist = store_get(2 * sizeof(char *), FALSE);
201
    alist = store_get(2 * sizeof(char *), GET_UNTAINTED);
202
    adds  = store_get(alen, FALSE);
202
    adds  = store_get(alen, GET_UNTAINTED);
203
    yield->h_name = CS name;
203
    yield->h_name = CS name;
204
    yield->h_aliases = NULL;
204
    yield->h_aliases = NULL;
205
    yield->h_addrtype = af;
205
    yield->h_addrtype = af;
Lines 222-228 Link Here
222
  else
222
  else
223
    {
223
    {
224
    *error_num = HOST_NOT_FOUND;
224
    *error_num = HOST_NOT_FOUND;
225
    return NULL;
225
    yield = NULL;
226
    goto out;
226
    }
227
    }
227
228
228
/* Handle a host name */
229
/* Handle a host name */
Lines 238-248 Link Here
238
  switch(rc)
239
  switch(rc)
239
    {
240
    {
240
    case DNS_SUCCEED: break;
241
    case DNS_SUCCEED: break;
241
    case DNS_NOMATCH: *error_num = HOST_NOT_FOUND; return NULL;
242
    case DNS_NOMATCH: *error_num = HOST_NOT_FOUND; yield = NULL; goto out;
242
    case DNS_NODATA:  *error_num = NO_DATA; return NULL;
243
    case DNS_NODATA:  *error_num = NO_DATA; yield = NULL; goto out;
243
    case DNS_AGAIN:   *error_num = TRY_AGAIN; return NULL;
244
    case DNS_AGAIN:   *error_num = TRY_AGAIN; yield = NULL; goto out;
244
    default:
245
    default:
245
    case DNS_FAIL:    *error_num = NO_RECOVERY; return NULL;
246
    case DNS_FAIL:    *error_num = NO_RECOVERY; yield = NULL; goto out;
246
    }
247
    }
247
248
248
  for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
249
  for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS);
Lines 250-258 Link Here
250
       rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == type)
251
       rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == type)
251
    count++;
252
    count++;
252
253
253
  yield = store_get(sizeof(struct hostent), FALSE);
254
  yield = store_get(sizeof(struct hostent), GET_UNTAINTED);
254
  alist = store_get((count + 1) * sizeof(char *), FALSE);
255
  alist = store_get((count + 1) * sizeof(char *), GET_UNTAINTED);
255
  adds  = store_get(count *alen, FALSE);
256
  adds  = store_get(count *alen, GET_UNTAINTED);
256
257
257
  yield->h_name = CS name;
258
  yield->h_name = CS name;
258
  yield->h_aliases = NULL;
259
  yield->h_aliases = NULL;
Lines 280-285 Link Here
280
  *alist = NULL;
281
  *alist = NULL;
281
  }
282
  }
282
283
284
out:
285
286
store_free_dns_answer(dnsa);
283
return yield;
287
return yield;
284
}
288
}
285
289
Lines 324-335 Link Here
324
    continue;
328
    continue;
325
    }
329
    }
326
330
327
  h = store_get(sizeof(host_item), FALSE);
331
  h = store_get(sizeof(host_item), GET_UNTAINTED);
328
  h->name = name;
332
  h->name = name;
329
  h->address = NULL;
333
  h->address = NULL;
330
  h->port = PORT_NONE;
334
  h->port = PORT_NONE;
331
  h->mx = fake_mx;
335
  h->mx = fake_mx;
332
  h->sort_key = randomize? (-fake_mx)*1000 + random_number(1000) : 0;
336
  h->sort_key = randomize ? (-fake_mx)*1000 + random_number(1000) : 0;
333
  h->status = hstatus_unknown;
337
  h->status = hstatus_unknown;
334
  h->why = hwhy_unknown;
338
  h->why = hwhy_unknown;
335
  h->last_try = 0;
339
  h->last_try = 0;
Lines 366-380 Link Here
366
*        Extract port from address string        *
370
*        Extract port from address string        *
367
*************************************************/
371
*************************************************/
368
372
369
/* In the spool file, and in the -oMa and -oMi options, a host plus port is
373
/* In the -oMa and -oMi options, a host plus port is given as an IP address
370
given as an IP address followed by a dot and a port number. This function
374
followed by a dot and a port number. This function decodes this.
371
decodes this.
372
375
373
An alternative format for the -oMa and -oMi options is [ip address]:port which
376
An alternative format for the -oMa and -oMi options is [ip address]:port which
374
is what Exim 4 uses for output, because it seems to becoming commonly used,
377
is what Exim uses for output, because it seems to becoming commonly used,
375
whereas the dot form confuses some programs/people. So we recognize that form
378
whereas the dot form confuses some programs/people. So we recognize that form
376
too.
379
too.
377
380
381
The spool file used to use the first form, but this breaks with a v4mapped ipv6
382
hybrid, because the parsing here is not clever.  So for spool we now use the
383
second form.
384
378
Argument:
385
Argument:
379
  address    points to the string; if there is a port, the '.' in the string
386
  address    points to the string; if there is a port, the '.' in the string
380
             is overwritten with zero to terminate the address; if the string
387
             is overwritten with zero to terminate the address; if the string
Lines 728-734 Link Here
728
int sep = 0;
735
int sep = 0;
729
uschar *s;
736
uschar *s;
730
ip_address_item * yield = NULL, * last = NULL, * next;
737
ip_address_item * yield = NULL, * last = NULL, * next;
731
BOOL taint = is_tainted(list);
732
738
733
while ((s = string_nextinlist(&list, &sep, NULL, 0)))
739
while ((s = string_nextinlist(&list, &sep, NULL, 0)))
734
  {
740
  {
Lines 747-753 Link Here
747
  address above. The field in the ip_address_item is large enough to hold an
753
  address above. The field in the ip_address_item is large enough to hold an
748
  IPv6 address. */
754
  IPv6 address. */
749
755
750
  next = store_get(sizeof(ip_address_item), taint);
756
  next = store_get(sizeof(ip_address_item), list);
751
  next->next = NULL;
757
  next->next = NULL;
752
  Ustrcpy(next->address, s);
758
  Ustrcpy(next->address, s);
753
  next->port = port;
759
  next->port = port;
Lines 815-821 Link Here
815
{
821
{
816
ip_address_item *running_interfaces = NULL;
822
ip_address_item *running_interfaces = NULL;
817
823
818
if (local_interface_data == NULL)
824
if (!local_interface_data)
819
  {
825
  {
820
  void *reset_item = store_mark();
826
  void *reset_item = store_mark();
821
  ip_address_item *dlist = host_build_ifacelist(CUS local_interfaces,
827
  ip_address_item *dlist = host_build_ifacelist(CUS local_interfaces,
Lines 911-924 Link Here
911
    struct sockaddr_in6 *sk = (struct sockaddr_in6 *)arg;
917
    struct sockaddr_in6 *sk = (struct sockaddr_in6 *)arg;
912
    yield = US inet_ntop(family, &(sk->sin6_addr), CS addr_buffer,
918
    yield = US inet_ntop(family, &(sk->sin6_addr), CS addr_buffer,
913
      sizeof(addr_buffer));
919
      sizeof(addr_buffer));
914
    if (portptr != NULL) *portptr = ntohs(sk->sin6_port);
920
    if (portptr) *portptr = ntohs(sk->sin6_port);
915
    }
921
    }
916
  else
922
  else
917
    {
923
    {
918
    struct sockaddr_in *sk = (struct sockaddr_in *)arg;
924
    struct sockaddr_in *sk = (struct sockaddr_in *)arg;
919
    yield = US inet_ntop(family, &(sk->sin_addr), CS addr_buffer,
925
    yield = US inet_ntop(family, &(sk->sin_addr), CS addr_buffer,
920
      sizeof(addr_buffer));
926
      sizeof(addr_buffer));
921
    if (portptr != NULL) *portptr = ntohs(sk->sin_port);
927
    if (portptr) *portptr = ntohs(sk->sin_port);
922
    }
928
    }
923
  }
929
  }
924
else
930
else
Lines 937-943 Link Here
937
if (type < 0)
943
if (type < 0)
938
  {
944
  {
939
  yield = US inet_ntoa(((struct sockaddr_in *)arg)->sin_addr);
945
  yield = US inet_ntoa(((struct sockaddr_in *)arg)->sin_addr);
940
  if (portptr != NULL) *portptr = ntohs(((struct sockaddr_in *)arg)->sin_port);
946
  if (portptr) *portptr = ntohs(((struct sockaddr_in *)arg)->sin_port);
941
  }
947
  }
942
else
948
else
943
  yield = US inet_ntoa(*((struct in_addr *)arg));
949
  yield = US inet_ntoa(*((struct in_addr *)arg));
Lines 945-951 Link Here
945
951
946
/* If there is no buffer, put the string into some new store. */
952
/* If there is no buffer, put the string into some new store. */
947
953
948
if (!buffer) buffer = store_get(46, FALSE);
954
if (!buffer) buffer = store_get(46, GET_UNTAINTED);
949
955
950
/* Callers of this function with a non-NULL buffer must ensure that it is
956
/* Callers of this function with a non-NULL buffer must ensure that it is
951
large enough to hold an IPv6 address, namely, at least 46 bytes. That's what
957
large enough to hold an IPv6 address, namely, at least 46 bytes. That's what
Lines 1197-1205 Link Here
1197
  c++;
1203
  c++;
1198
  }
1204
  }
1199
1205
1200
c[-1] = '\0';	/* drop trailing colon */
1206
*--c = '\0';	/* drop trailing colon */
1201
1207
1202
/* debug_printf("%s: D k %d <%s> <%s>\n", __FUNCTION__, k, d, d + 2*(k+1)); */
1208
/* debug_printf("%s: D k %d <%s> <%s>\n", __FUNCTION__, k, buffer, buffer + 2*(k+1)); */
1203
if (k >= 0)
1209
if (k >= 0)
1204
  {			/* collapse */
1210
  {			/* collapse */
1205
  c = d + 2*(k+1);
1211
  c = d + 2*(k+1);
Lines 1232-1245 Link Here
1232
host_is_tls_on_connect_port(int port)
1238
host_is_tls_on_connect_port(int port)
1233
{
1239
{
1234
int sep = 0;
1240
int sep = 0;
1235
uschar buffer[32];
1241
const uschar * list = tls_in.on_connect_ports;
1236
const uschar *list = tls_in.on_connect_ports;
1237
uschar *s;
1238
uschar *end;
1239
1242
1240
if (tls_in.on_connect) return TRUE;
1243
if (tls_in.on_connect) return TRUE;
1241
1244
1242
while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
1245
for (uschar * s, * end; s = string_nextinlist(&list, &sep, NULL, 0); )
1243
  if (Ustrtol(s, &end, 10) == port)
1246
  if (Ustrtol(s, &end, 10) == port)
1244
    return TRUE;
1247
    return TRUE;
1245
1248
Lines 1581-1592 Link Here
1581
1584
1582
  if (hosts->h_aliases)
1585
  if (hosts->h_aliases)
1583
    {
1586
    {
1584
    int count = 1;
1587
    int count = 1;  /* need 1 more for terminating NULL */
1585
    uschar **ptr;
1588
    uschar **ptr;
1586
1589
1587
    for (uschar ** aliases = USS hosts->h_aliases; *aliases; aliases++) count++;
1590
    for (uschar ** aliases = USS hosts->h_aliases; *aliases; aliases++) count++;
1588
    store_pool = POOL_PERM;
1591
    store_pool = POOL_PERM;
1589
    ptr = sender_host_aliases = store_get(count * sizeof(uschar *), FALSE);
1592
    ptr = sender_host_aliases = store_get(count * sizeof(uschar *), GET_UNTAINTED);
1590
    store_pool = POOL_TAINT_PERM;
1593
    store_pool = POOL_TAINT_PERM;
1591
1594
1592
    for (uschar ** aliases = USS hosts->h_aliases; *aliases; aliases++)
1595
    for (uschar ** aliases = USS hosts->h_aliases; *aliases; aliases++)
Lines 1690-1696 Link Here
1690
      {
1693
      {
1691
      uschar **aptr = NULL;
1694
      uschar **aptr = NULL;
1692
      int ssize = 264;
1695
      int ssize = 264;
1693
      int count = 0;
1696
      int count = 1;  /* need 1 more for terminating NULL */
1694
      int old_pool = store_pool;
1697
      int old_pool = store_pool;
1695
1698
1696
      sender_host_dnssec = dns_is_secure(dnsa);
1699
      sender_host_dnssec = dns_is_secure(dnsa);
Lines 1708-1714 Link Here
1708
      /* Get store for the list of aliases. For compatibility with
1711
      /* Get store for the list of aliases. For compatibility with
1709
      gethostbyaddr, we make an empty list if there are none. */
1712
      gethostbyaddr, we make an empty list if there are none. */
1710
1713
1711
      aptr = sender_host_aliases = store_get(count * sizeof(uschar *), FALSE);
1714
      aptr = sender_host_aliases = store_get(count * sizeof(uschar *), GET_UNTAINTED);
1712
1715
1713
      /* Re-scan and extract the names */
1716
      /* Re-scan and extract the names */
1714
1717
Lines 1716-1722 Link Here
1716
           rr;
1719
           rr;
1717
           rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == T_PTR)
1720
           rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == T_PTR)
1718
        {
1721
        {
1719
        uschar * s = store_get(ssize, TRUE);	/* names are tainted */
1722
        uschar * s = store_get(ssize, GET_TAINTED);	/* names are tainted */
1720
1723
1721
        /* If an overlong response was received, the data will have been
1724
        /* If an overlong response was received, the data will have been
1722
        truncated and dn_expand may fail. */
1725
        truncated and dn_expand may fail. */
Lines 1793-1799 Link Here
1793
  {
1796
  {
1794
  uschar **aliases = sender_host_aliases;
1797
  uschar **aliases = sender_host_aliases;
1795
  debug_printf("IP address lookup yielded \"%s\"\n", sender_host_name);
1798
  debug_printf("IP address lookup yielded \"%s\"\n", sender_host_name);
1796
  while (*aliases != NULL) debug_printf("  alias \"%s\"\n", *aliases++);
1799
  while (*aliases) debug_printf("  alias \"%s\"\n", *aliases++);
1797
  }
1800
  }
1798
1801
1799
/* We need to verify that a forward lookup on the name we found does indeed
1802
/* We need to verify that a forward lookup on the name we found does indeed
Lines 2041-2084 Link Here
2041
2044
2042
  if (!hostdata)
2045
  if (!hostdata)
2043
    {
2046
    {
2044
    uschar *error;
2047
    uschar * error;
2045
    switch (error_num)
2048
    switch (error_num)
2046
      {
2049
      {
2047
      case HOST_NOT_FOUND: error = US"HOST_NOT_FOUND"; break;
2050
      case HOST_NOT_FOUND: error = US"HOST_NOT_FOUND";	break;
2048
      case TRY_AGAIN:      error = US"TRY_AGAIN"; break;
2051
      case TRY_AGAIN:      error = US"TRY_AGAIN";   temp_error = TRUE; break;
2049
      case NO_RECOVERY:    error = US"NO_RECOVERY"; break;
2052
      case NO_RECOVERY:    error = US"NO_RECOVERY"; temp_error = TRUE; break;
2050
      case NO_DATA:        error = US"NO_DATA"; break;
2053
      case NO_DATA:        error = US"NO_DATA";		break;
2051
    #if NO_DATA != NO_ADDRESS
2054
    #if NO_DATA != NO_ADDRESS
2052
      case NO_ADDRESS:     error = US"NO_ADDRESS"; break;
2055
      case NO_ADDRESS:     error = US"NO_ADDRESS";	break;
2053
    #endif
2056
    #endif
2054
      default: error = US"?"; break;
2057
      default: error = US"?"; break;
2055
      }
2058
      }
2056
2059
2057
    DEBUG(D_host_lookup) debug_printf("%s returned %d (%s)\n",
2060
    DEBUG(D_host_lookup) debug_printf("%s(af=%s) returned %d (%s)\n",
2058
      f.running_in_test_harness ? "host_fake_gethostbyname" :
2061
      f.running_in_test_harness ? "host_fake_gethostbyname" :
2059
      #if HAVE_IPV6
2062
#if HAVE_IPV6
2060
        #if HAVE_GETIPNODEBYNAME
2063
# if HAVE_GETIPNODEBYNAME
2061
        af == AF_INET6 ? "getipnodebyname(af=inet6)" : "getipnodebyname(af=inet)",
2064
        "getipnodebyname",
2062
        #else
2065
# else
2063
        af == AF_INET6 ? "gethostbyname2(af=inet6)" : "gethostbyname2(af=inet)",
2066
        "gethostbyname2",
2064
        #endif
2067
# endif
2065
      #else
2068
#else
2066
      "gethostbyname",
2069
	"gethostbyname",
2067
      #endif
2070
#endif
2068
      error_num, error);
2071
      af == AF_INET ? "inet" : "inet6", error_num, error);
2069
2072
2070
    if (error_num == TRY_AGAIN || error_num == NO_RECOVERY) temp_error = TRUE;
2071
    continue;
2073
    continue;
2072
    }
2074
    }
2073
  if ((hostdata->h_addr_list)[0] == NULL) continue;
2075
  if (!(hostdata->h_addr_list)[0]) continue;
2074
2076
2075
  /* Replace the name with the fully qualified one if necessary, and fill in
2077
  /* Replace the name with the fully qualified one if necessary, and fill in
2076
  the fully_qualified_name pointer. */
2078
  the fully_qualified_name pointer. */
2077
2079
2078
  if (hostdata->h_name[0] != 0 &&
2080
  if (hostdata->h_name[0] && Ustrcmp(host->name, hostdata->h_name) != 0)
2079
      Ustrcmp(host->name, hostdata->h_name) != 0)
2080
    host->name = string_copy_dnsdomain(US hostdata->h_name);
2081
    host->name = string_copy_dnsdomain(US hostdata->h_name);
2081
  if (fully_qualified_name != NULL) *fully_qualified_name = host->name;
2082
  if (fully_qualified_name) *fully_qualified_name = host->name;
2082
2083
2083
  /* Get the list of addresses. IPv4 and IPv6 addresses can be distinguished
2084
  /* Get the list of addresses. IPv4 and IPv6 addresses can be distinguished
2084
  by their different lengths. Scan the list, ignoring any that are to be
2085
  by their different lengths. Scan the list, ignoring any that are to be
Lines 2092-2100 Link Here
2092
      host_ntoa(ipv4_addr? AF_INET:AF_INET6, *addrlist, NULL, NULL);
2093
      host_ntoa(ipv4_addr? AF_INET:AF_INET6, *addrlist, NULL, NULL);
2093
2094
2094
    #ifndef STAND_ALONE
2095
    #ifndef STAND_ALONE
2095
    if (ignore_target_hosts != NULL &&
2096
    if (  ignore_target_hosts
2096
        verify_check_this_host(&ignore_target_hosts, NULL, host->name,
2097
       && verify_check_this_host(&ignore_target_hosts, NULL, host->name,
2097
          text_address, NULL) == OK)
2098
	    text_address, NULL) == OK)
2098
      {
2099
      {
2099
      DEBUG(D_host_lookup)
2100
      DEBUG(D_host_lookup)
2100
        debug_printf("ignored host %s [%s]\n", host->name, text_address);
2101
        debug_printf("ignored host %s [%s]\n", host->name, text_address);
Lines 2102-2111 Link Here
2102
      }
2103
      }
2103
    #endif
2104
    #endif
2104
2105
2105
    /* If this is the first address, last == NULL and we put the data in the
2106
    /* If this is the first address, last is NULL and we put the data in the
2106
    original block. */
2107
    original block. */
2107
2108
2108
    if (last == NULL)
2109
    if (!last)
2109
      {
2110
      {
2110
      host->address = text_address;
2111
      host->address = text_address;
2111
      host->port = PORT_NONE;
2112
      host->port = PORT_NONE;
Lines 2120-2126 Link Here
2120
2121
2121
    else
2122
    else
2122
      {
2123
      {
2123
      host_item *next = store_get(sizeof(host_item), FALSE);
2124
      host_item *next = store_get(sizeof(host_item), GET_UNTAINTED);
2124
      next->name = host->name;
2125
      next->name = host->name;
2125
#ifndef DISABLE_TLS
2126
#ifndef DISABLE_TLS
2126
      next->certname = host->certname;
2127
      next->certname = host->certname;
Lines 2143-2154 Link Here
2143
NULL. If temp_error is set, at least one of the lookups gave a temporary error,
2144
NULL. If temp_error is set, at least one of the lookups gave a temporary error,
2144
so we pass that back. */
2145
so we pass that back. */
2145
2146
2146
if (host->address == NULL)
2147
if (!host->address)
2147
  {
2148
  {
2148
  uschar *msg =
2149
  uschar *msg =
2149
    #ifndef STAND_ALONE
2150
    #ifndef STAND_ALONE
2150
    (message_id[0] == 0 && smtp_in != NULL)?
2151
    !message_id[0] && smtp_in
2151
      string_sprintf("no IP address found for host %s (during %s)", host->name,
2152
      ? string_sprintf("no IP address found for host %s (during %s)", host->name,
2152
          smtp_get_connection_info()) :
2153
          smtp_get_connection_info()) :
2153
    #endif
2154
    #endif
2154
    string_sprintf("no IP address found for host %s", host->name);
2155
    string_sprintf("no IP address found for host %s", host->name);
Lines 2196-2202 Link Here
2196
2197
2197
RETURN_AGAIN:
2198
RETURN_AGAIN:
2198
  {
2199
  {
2199
  #ifndef STAND_ALONE
2200
#ifndef STAND_ALONE
2200
  int rc;
2201
  int rc;
2201
  const uschar *save = deliver_domain;
2202
  const uschar *save = deliver_domain;
2202
  deliver_domain = host->name;  /* set $domain */
2203
  deliver_domain = host->name;  /* set $domain */
Lines 2209-2215 Link Here
2209
      "returning HOST_FIND_FAILED\n", host->name);
2210
      "returning HOST_FIND_FAILED\n", host->name);
2210
    return HOST_FIND_FAILED;
2211
    return HOST_FIND_FAILED;
2211
    }
2212
    }
2212
  #endif
2213
#endif
2213
  return HOST_FIND_AGAIN;
2214
  return HOST_FIND_AGAIN;
2214
  }
2215
  }
2215
}
2216
}
Lines 2267-2272 Link Here
2267
BOOL v6_find_again = FALSE;
2268
BOOL v6_find_again = FALSE;
2268
BOOL dnssec_fail = FALSE;
2269
BOOL dnssec_fail = FALSE;
2269
int i;
2270
int i;
2271
dns_answer * dnsa;
2270
2272
2271
#ifndef DISABLE_TLS
2273
#ifndef DISABLE_TLS
2272
/* Copy the host name at this point to the value which is used for
2274
/* Copy the host name at this point to the value which is used for
Lines 2292-2297 Link Here
2292
  return HOST_FOUND;
2294
  return HOST_FOUND;
2293
  }
2295
  }
2294
2296
2297
dnsa = store_get_dns_answer();
2298
2295
/* On an IPv6 system, unless IPv6 is disabled, go round the loop up to twice,
2299
/* On an IPv6 system, unless IPv6 is disabled, go round the loop up to twice,
2296
looking for AAAA records the first time. However, unless doing standalone
2300
looking for AAAA records the first time. However, unless doing standalone
2297
testing, we force an IPv4 lookup if the domain matches dns_ipv4_lookup global.
2301
testing, we force an IPv4 lookup if the domain matches dns_ipv4_lookup global.
Lines 2323-2329 Link Here
2323
  int type = types[i];
2327
  int type = types[i];
2324
  int randoffset = i == (whichrrs & HOST_FIND_IPV4_FIRST ? 1 : 0)
2328
  int randoffset = i == (whichrrs & HOST_FIND_IPV4_FIRST ? 1 : 0)
2325
    ? 500 : 0;  /* Ensures v6/4 sort order */
2329
    ? 500 : 0;  /* Ensures v6/4 sort order */
2326
  dns_answer * dnsa = store_get_dns_answer();
2327
  dns_scan dnss;
2330
  dns_scan dnss;
2328
2331
2329
  int rc = dns_lookup_timerwrap(dnsa, host->name, type, fully_qualified_name);
2332
  int rc = dns_lookup_timerwrap(dnsa, host->name, type, fully_qualified_name);
Lines 2346-2355 Link Here
2346
    {
2349
    {
2347
    if (i == 0)  /* Just tried for an A record, i.e. end of loop */
2350
    if (i == 0)  /* Just tried for an A record, i.e. end of loop */
2348
      {
2351
      {
2349
      if (host->address != NULL) return HOST_FOUND;  /* AAAA was found */
2352
      if (host->address != NULL)
2350
      if (rc == DNS_AGAIN || rc == DNS_FAIL || v6_find_again)
2353
        i = HOST_FOUND;  /* AAAA was found */
2351
        return HOST_FIND_AGAIN;
2354
      else if (rc == DNS_AGAIN || rc == DNS_FAIL || v6_find_again)
2352
      return HOST_FIND_FAILED;    /* DNS_NOMATCH or DNS_NODATA */
2355
        i = HOST_FIND_AGAIN;
2356
      else
2357
	i = HOST_FIND_FAILED;    /* DNS_NOMATCH or DNS_NODATA */
2358
      goto out;
2353
      }
2359
      }
2354
2360
2355
    /* Tried for an AAAA record: remember if this was a temporary
2361
    /* Tried for an AAAA record: remember if this was a temporary
Lines 2452-2458 Link Here
2452
	/* Not a duplicate */
2458
	/* Not a duplicate */
2453
2459
2454
	new_sort_key = host->mx * 1000 + random_number(500) + randoffset;
2460
	new_sort_key = host->mx * 1000 + random_number(500) + randoffset;
2455
	next = store_get(sizeof(host_item), FALSE);
2461
	next = store_get(sizeof(host_item), GET_UNTAINTED);
2456
2462
2457
	/* New address goes first: insert the new block after the first one
2463
	/* New address goes first: insert the new block after the first one
2458
	(so as not to disturb the original pointer) but put the new address
2464
	(so as not to disturb the original pointer) but put the new address
Lines 2494-2504 Link Here
2494
/* Control gets here only if the second lookup (the A record) succeeded.
2500
/* Control gets here only if the second lookup (the A record) succeeded.
2495
However, the address may not be filled in if it was ignored. */
2501
However, the address may not be filled in if it was ignored. */
2496
2502
2497
return host->address
2503
i = host->address
2498
  ? HOST_FOUND
2504
  ? HOST_FOUND
2499
  : dnssec_fail
2505
  : dnssec_fail
2500
  ? HOST_FIND_SECURITY
2506
  ? HOST_FIND_SECURITY
2501
  : HOST_IGNORED;
2507
  : HOST_IGNORED;
2508
2509
out:
2510
  store_free_dns_answer(dnsa);
2511
  return i;
2502
}
2512
}
2503
2513
2504
2514
Lines 2637-2643 Link Here
2637
#endif
2647
#endif
2638
      { yield = HOST_FIND_AGAIN; goto out; }
2648
      { yield = HOST_FIND_AGAIN; goto out; }
2639
    DEBUG(D_host_lookup) debug_printf("DNS_%s treated as DNS_NODATA "
2649
    DEBUG(D_host_lookup) debug_printf("DNS_%s treated as DNS_NODATA "
2640
      "(domain in srv_fail_domains)\n", (rc == DNS_FAIL)? "FAIL":"AGAIN");
2650
      "(domain in srv_fail_domains)\n", rc == DNS_FAIL ? "FAIL":"AGAIN");
2641
    }
2651
    }
2642
  }
2652
  }
2643
2653
Lines 2855-2861 Link Here
2855
  /* Make a new host item and seek the correct insertion place */
2865
  /* Make a new host item and seek the correct insertion place */
2856
    {
2866
    {
2857
    int sort_key = precedence * 1000 + weight;
2867
    int sort_key = precedence * 1000 + weight;
2858
    host_item *next = store_get(sizeof(host_item), FALSE);
2868
    host_item * next = store_get(sizeof(host_item), GET_UNTAINTED);
2859
    next->name = string_copy_dnsdomain(data);
2869
    next->name = string_copy_dnsdomain(data);
2860
    next->address = NULL;
2870
    next->address = NULL;
2861
    next->port = port;
2871
    next->port = port;
Lines 3167-3172 Link Here
3167
out:
3177
out:
3168
3178
3169
dns_init(FALSE, FALSE, FALSE);	/* clear the dnssec bit for getaddrbyname */
3179
dns_init(FALSE, FALSE, FALSE);	/* clear the dnssec bit for getaddrbyname */
3180
store_free_dns_answer(dnsa);
3170
return yield;
3181
return yield;
3171
}
3182
}
3172
3183
Lines 3195-3201 Link Here
3195
rc = dns_lookup_timerwrap(dnsa, buffer, T_TLSA, &fullname);
3206
rc = dns_lookup_timerwrap(dnsa, buffer, T_TLSA, &fullname);
3196
sec = dns_is_secure(dnsa);
3207
sec = dns_is_secure(dnsa);
3197
DEBUG(D_transport)
3208
DEBUG(D_transport)
3198
  debug_printf("TLSA lookup ret %d %sDNSSEC\n", rc, sec ? "" : "not ");
3209
  debug_printf("TLSA lookup ret %s %sDNSSEC\n", dns_rc_names[rc], sec ? "" : "not ");
3199
3210
3200
switch (rc)
3211
switch (rc)
3201
  {
3212
  {
Lines 3265-3270 Link Here
3265
3276
3266
disable_ipv6 = FALSE;
3277
disable_ipv6 = FALSE;
3267
primary_hostname = US"";
3278
primary_hostname = US"";
3279
store_init();
3268
store_pool = POOL_MAIN;
3280
store_pool = POOL_MAIN;
3269
debug_selector = D_host_lookup|D_interface;
3281
debug_selector = D_host_lookup|D_interface;
3270
debug_file = stdout;
3282
debug_file = stdout;
(-)exim.orig/src/ip.c (-16 / +6 lines)
Lines 3-9 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
6
/* Copyright (c) The Exim Maintainers 2020 - 2021 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Functions for doing things with sockets. With the advent of IPv6 this has
9
/* Functions for doing things with sockets. With the advent of IPv6 this has
Lines 127-134 Link Here
127
  return sizeof(sin->v6);
127
  return sizeof(sin->v6);
128
  }
128
  }
129
else
129
else
130
#else     /* HAVE_IPv6 */
131
af = af;  /* Avoid compiler warning */
132
#endif    /* HAVE_IPV6 */
130
#endif    /* HAVE_IPV6 */
133
131
134
/* Setup code when using IPv4 socket. The wildcard address is "". */
132
/* Setup code when using IPv4 socket. The wildcard address is "". */
Lines 209-216 Link Here
209
  s_len = sizeof(s_in6);
207
  s_len = sizeof(s_in6);
210
  }
208
  }
211
else
209
else
212
#else     /* HAVE_IPV6 */
213
af = af;  /* Avoid compiler warning */
214
#endif    /* HAVE_IPV6 */
210
#endif    /* HAVE_IPV6 */
215
211
216
/* For an IPv4 address, use an IPv4 sockaddr structure, even on a system with
212
/* For an IPv4 address, use an IPv4 sockaddr structure, even on a system with
Lines 467-474 Link Here
467
  for (int port = portlo; port <= porthi; port++)
463
  for (int port = portlo; port <= porthi; port++)
468
    if (ip_connect(fd, af, h->address, port, timeout, fastopen_blob) == 0)
464
    if (ip_connect(fd, af, h->address, port, timeout, fastopen_blob) == 0)
469
      {
465
      {
470
      if (fd != fd6) close(fd6);
466
      if (fd6 >= 0 && fd != fd6) close(fd6);
471
      if (fd != fd4) close(fd4);
467
      if (fd4 >= 0 && fd != fd4) close(fd4);
472
      if (connhost)
468
      if (connhost)
473
	{
469
	{
474
	h->port = port;
470
	h->port = port;
Lines 593-601 Link Here
593
BOOL
589
BOOL
594
fd_ready(int fd, time_t timelimit)
590
fd_ready(int fd, time_t timelimit)
595
{
591
{
596
fd_set select_inset;
592
int rc, time_left = timelimit - time(NULL);
597
int time_left = timelimit - time(NULL);
598
int rc;
599
593
600
if (time_left <= 0)
594
if (time_left <= 0)
601
  {
595
  {
Lines 606-617 Link Here
606
600
607
do
601
do
608
  {
602
  {
609
  struct timeval tv = { .tv_sec = time_left, .tv_usec = 0 };
610
  FD_ZERO (&select_inset);
611
  FD_SET (fd, &select_inset);
612
613
  /*DEBUG(D_transport) debug_printf("waiting for data on fd\n");*/
603
  /*DEBUG(D_transport) debug_printf("waiting for data on fd\n");*/
614
  rc = select(fd + 1, (SELECT_ARG2_TYPE *)&select_inset, NULL, NULL, &tv);
604
  rc = poll_one_fd(fd, POLLIN, time_left * 1000);
615
605
616
  /* If some interrupt arrived, just retry. We presume this to be rare,
606
  /* If some interrupt arrived, just retry. We presume this to be rare,
617
  but it can happen (e.g. the SIGUSR1 signal sent by exiwhat causes
607
  but it can happen (e.g. the SIGUSR1 signal sent by exiwhat causes
Lines 640-646 Link Here
640
  /* Checking the FD_ISSET is not enough, if we're interrupted, the
630
  /* Checking the FD_ISSET is not enough, if we're interrupted, the
641
  select_inset may still contain the 'input'. */
631
  select_inset may still contain the 'input'. */
642
  }
632
  }
643
while (rc < 0 || !FD_ISSET(fd, &select_inset));
633
while (rc < 0);
644
return TRUE;
634
return TRUE;
645
}
635
}
646
636
(-)exim.orig/src/local_scan.c (-2 / +1 lines)
Lines 3-8 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2009 */
5
/* Copyright (c) University of Cambridge 1995 - 2009 */
6
/* Copyright (c) The Exim Maintainers 2021 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
8
9
Lines 57-64 Link Here
57
int
58
int
58
local_scan(int fd, uschar **return_text)
59
local_scan(int fd, uschar **return_text)
59
{
60
{
60
fd = fd;                      /* Keep picky compilers happy */
61
return_text = return_text;
62
return LOCAL_SCAN_ACCEPT;
61
return LOCAL_SCAN_ACCEPT;
63
}
62
}
64
63
(-)exim.orig/src/local_scan.h (-12 / +13 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2020 */
6
/* Copyright (c) University of Cambridge 1995 - 2020 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* This file is the header that is the only Exim header to be included in the
9
/* This file is the header that is the only Exim header to be included in the
Lines 40-47 Link Here
40
each time a new feature is added (in a way that doesn't break backward
40
each time a new feature is added (in a way that doesn't break backward
41
compatibility). */
41
compatibility). */
42
42
43
#define LOCAL_SCAN_ABI_VERSION_MAJOR 4
43
#define LOCAL_SCAN_ABI_VERSION_MAJOR 6
44
#define LOCAL_SCAN_ABI_VERSION_MINOR 1
44
#define LOCAL_SCAN_ABI_VERSION_MINOR 0
45
#define LOCAL_SCAN_ABI_VERSION \
45
#define LOCAL_SCAN_ABI_VERSION \
46
  LOCAL_SCAN_ABI_VERSION_MAJOR.LOCAL_SCAN_ABI_VERSION_MINOR
46
  LOCAL_SCAN_ABI_VERSION_MAJOR.LOCAL_SCAN_ABI_VERSION_MINOR
47
47
Lines 160-166 Link Here
160
extern int     body_linecount;         /* Line count in body */
160
extern int     body_linecount;         /* Line count in body */
161
extern int     body_zerocount;         /* Binary zero count in body */
161
extern int     body_zerocount;         /* Binary zero count in body */
162
extern uschar *expand_string_message;  /* Error info for failing expansion */
162
extern uschar *expand_string_message;  /* Error info for failing expansion */
163
extern uschar *headers_charset;        /* Charset for RFC 2047 decoding */
163
extern const uschar *headers_charset;  /* Charset for RFC 2047 decoding */
164
extern header_line *header_last;       /* Final header */
164
extern header_line *header_last;       /* Final header */
165
extern header_line *header_list;       /* First header */
165
extern header_line *header_list;       /* First header */
166
extern BOOL    host_checking;          /* Set when checking a host */
166
extern BOOL    host_checking;          /* Set when checking a host */
Lines 198-204 Link Here
198
extern int     lss_match_host(uschar *, uschar *, uschar *);
198
extern int     lss_match_host(uschar *, uschar *, uschar *);
199
extern void    receive_add_recipient(uschar *, int);
199
extern void    receive_add_recipient(uschar *, int);
200
extern BOOL    receive_remove_recipient(uschar *);
200
extern BOOL    receive_remove_recipient(uschar *);
201
extern uschar *rfc2047_decode(uschar *, BOOL, uschar *, int, int *, uschar **);
201
extern uschar *rfc2047_decode(uschar *, BOOL, const uschar *, int, int *,
202
			      uschar **);
202
extern int     smtp_fflush(void);
203
extern int     smtp_fflush(void);
203
extern void    smtp_printf(const char *, BOOL, ...) PRINTF_FUNCTION(1,3);
204
extern void    smtp_printf(const char *, BOOL, ...) PRINTF_FUNCTION(1,3);
204
extern void    smtp_vprintf(const char *, BOOL, va_list);
205
extern void    smtp_vprintf(const char *, BOOL, va_list);
Lines 207-218 Link Here
207
	string_sprintf_trc(fmt, US __FUNCTION__, __LINE__, __VA_ARGS__)
208
	string_sprintf_trc(fmt, US __FUNCTION__, __LINE__, __VA_ARGS__)
208
extern uschar *string_sprintf_trc(const char *, const uschar *, unsigned, ...) ALMOST_PRINTF(1,4);
209
extern uschar *string_sprintf_trc(const char *, const uschar *, unsigned, ...) ALMOST_PRINTF(1,4);
209
210
210
#define store_get(size, tainted) \
211
#define store_get(size, proto_mem) \
211
	store_get_3(size, tainted, __FUNCTION__, __LINE__)
212
	store_get_3((size), (proto_mem), __FUNCTION__, __LINE__)
212
extern void   *store_get_3(int, BOOL, const char *, int)	ALLOC ALLOC_SIZE(1) WARN_UNUSED_RESULT;
213
extern void   *store_get_3(int, const void *, const char *, int)	ALLOC ALLOC_SIZE(1) WARN_UNUSED_RESULT;
213
#define store_get_perm(size, tainted) \
214
#define store_get_perm(size, proto_mem) \
214
	store_get_perm_3(size, tainted, __FUNCTION__, __LINE__)
215
	store_get_perm_3((size), (proto_mem), __FUNCTION__, __LINE__)
215
extern void   *store_get_perm_3(int, BOOL, const char *, int)	ALLOC ALLOC_SIZE(1) WARN_UNUSED_RESULT;
216
extern void   *store_get_perm_3(int, const void *, const char *, int)	ALLOC ALLOC_SIZE(1) WARN_UNUSED_RESULT;
216
217
217
218
218
#if defined(LOCAL_SCAN) || defined(DLFUNC_IMPL)
219
#if defined(LOCAL_SCAN) || defined(DLFUNC_IMPL)
Lines 229-235 Link Here
229
230
230
extern uschar * string_copy_function(const uschar *);
231
extern uschar * string_copy_function(const uschar *);
231
extern uschar * string_copyn_function(const uschar *, int n);
232
extern uschar * string_copyn_function(const uschar *, int n);
232
extern uschar * string_copy_taint_function(const uschar *, BOOL tainted);
233
extern uschar * string_copy_taint_function(const uschar *, const void * proto_mem);
233
extern pid_t    child_open_exim_function(int *, const uschar *);
234
extern pid_t    child_open_exim_function(int *, const uschar *);
234
extern pid_t    child_open_exim2_function(int *, uschar *, uschar *, const uschar *);
235
extern pid_t    child_open_exim2_function(int *, uschar *, uschar *, const uschar *);
235
extern pid_t    child_open_function(uschar **, uschar **, int, int *, int *, BOOL, const uschar *);
236
extern pid_t    child_open_function(uschar **, uschar **, int, int *, int *, BOOL, const uschar *);
(-)exim.orig/src/log.c (-174 / +203 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Functions for writing log files. The code for maintaining datestamped
9
/* Functions for writing log files. The code for maintaining datestamped
Lines 12-18 Link Here
12
12
13
#include "exim.h"
13
#include "exim.h"
14
14
15
#define LOG_NAME_SIZE 256
16
#define MAX_SYSLOG_LEN 870
15
#define MAX_SYSLOG_LEN 870
17
16
18
#define LOG_MODE_FILE   1
17
#define LOG_MODE_FILE   1
Lines 30-36 Link Here
30
29
31
static uschar mainlog_name[LOG_NAME_SIZE];
30
static uschar mainlog_name[LOG_NAME_SIZE];
32
static uschar rejectlog_name[LOG_NAME_SIZE];
31
static uschar rejectlog_name[LOG_NAME_SIZE];
33
static uschar debuglog_name[LOG_NAME_SIZE];
34
32
35
static uschar *mainlog_datestamp = NULL;
33
static uschar *mainlog_datestamp = NULL;
36
static uschar *rejectlog_datestamp = NULL;
34
static uschar *rejectlog_datestamp = NULL;
Lines 55-119 Link Here
55
number definitions in macros.h */
53
number definitions in macros.h */
56
54
57
static const uschar * exim_errstrings[] = {
55
static const uschar * exim_errstrings[] = {
58
  US"",
56
  [0] = US"",
59
  US"unknown error",
57
  [- ERRNO_UNKNOWNERROR] =	US"unknown error",
60
  US"user slash",
58
  [- ERRNO_USERSLASH] =		US"user slash",
61
  US"exist race",
59
  [- ERRNO_EXISTRACE] =		US"exist race",
62
  US"not regular",
60
  [- ERRNO_NOTREGULAR] =	US"not regular",
63
  US"not directory",
61
  [- ERRNO_NOTDIRECTORY] =	US"not directory",
64
  US"bad ugid",
62
  [- ERRNO_BADUGID] =		US"bad ugid",
65
  US"bad mode",
63
  [- ERRNO_BADMODE] =		US"bad mode",
66
  US"inode changed",
64
  [- ERRNO_INODECHANGED] =	US"inode changed",
67
  US"lock failed",
65
  [- ERRNO_LOCKFAILED] =	US"lock failed",
68
  US"bad address2",
66
  [- ERRNO_BADADDRESS2] =	US"bad address2",
69
  US"forbid pipe",
67
  [- ERRNO_FORBIDPIPE] =	US"forbid pipe",
70
  US"forbid file",
68
  [- ERRNO_FORBIDFILE] =	US"forbid file",
71
  US"forbid reply",
69
  [- ERRNO_FORBIDREPLY] =	US"forbid reply",
72
  US"missing pipe",
70
  [- ERRNO_MISSINGPIPE] =	US"missing pipe",
73
  US"missing file",
71
  [- ERRNO_MISSINGFILE] =	US"missing file",
74
  US"missing reply",
72
  [- ERRNO_MISSINGREPLY] =	US"missing reply",
75
  US"bad redirect",
73
  [- ERRNO_BADREDIRECT] =	US"bad redirect",
76
  US"smtp closed",
74
  [- ERRNO_SMTPCLOSED] =	US"smtp closed",
77
  US"smtp format",
75
  [- ERRNO_SMTPFORMAT] =	US"smtp format",
78
  US"spool format",
76
  [- ERRNO_SPOOLFORMAT] =	US"spool format",
79
  US"not absolute",
77
  [- ERRNO_NOTABSOLUTE] =	US"not absolute",
80
  US"Exim-imposed quota",
78
  [- ERRNO_EXIMQUOTA] =		US"Exim-imposed quota",
81
  US"held",
79
  [- ERRNO_HELD] =		US"held",
82
  US"Delivery filter process failure",
80
  [- ERRNO_FILTER_FAIL] =	US"Delivery filter process failure",
83
  US"Delivery add/remove header failure",
81
  [- ERRNO_CHHEADER_FAIL] =	US"Delivery add/remove header failure",
84
  US"Delivery write incomplete error",
82
  [- ERRNO_WRITEINCOMPLETE] =	US"Delivery write incomplete error",
85
  US"Some expansion failed",
83
  [- ERRNO_EXPANDFAIL] =	US"Some expansion failed",
86
  US"Failed to get gid",
84
  [- ERRNO_GIDFAIL] =		US"Failed to get gid",
87
  US"Failed to get uid",
85
  [- ERRNO_UIDFAIL] =		US"Failed to get uid",
88
  US"Unset or non-existent transport",
86
  [- ERRNO_BADTRANSPORT] =	US"Unset or non-existent transport",
89
  US"MBX length mismatch",
87
  [- ERRNO_MBXLENGTH] =		US"MBX length mismatch",
90
  US"Lookup failed routing or in smtp tpt",
88
  [- ERRNO_UNKNOWNHOST] =	US"Lookup failed routing or in smtp tpt",
91
  US"Can't match format in appendfile",
89
  [- ERRNO_FORMATUNKNOWN] =	US"Can't match format in appendfile",
92
  US"Creation outside home in appendfile",
90
  [- ERRNO_BADCREATE] =		US"Creation outside home in appendfile",
93
  US"Can't check a list; lookup defer",
91
  [- ERRNO_LISTDEFER] =		US"Can't check a list; lookup defer",
94
  US"DNS lookup defer",
92
  [- ERRNO_DNSDEFER] =		US"DNS lookup defer",
95
  US"Failed to start TLS session",
93
  [- ERRNO_TLSFAILURE] =	US"Failed to start TLS session",
96
  US"Mandatory TLS session not started",
94
  [- ERRNO_TLSREQUIRED] =	US"Mandatory TLS session not started",
97
  US"Failed to chown a file",
95
  [- ERRNO_CHOWNFAIL] =		US"Failed to chown a file",
98
  US"Failed to create a pipe",
96
  [- ERRNO_PIPEFAIL] =		US"Failed to create a pipe",
99
  US"When verifying",
97
  [- ERRNO_CALLOUTDEFER] =	US"When verifying",
100
  US"When required by client",
98
  [- ERRNO_AUTHFAIL] =		US"When required by client",
101
  US"Used internally in smtp transport",
99
  [- ERRNO_CONNECTTIMEOUT] =	US"Used internally in smtp transport",
102
  US"RCPT gave 4xx error",
100
  [- ERRNO_RCPT4XX] =		US"RCPT gave 4xx error",
103
  US"MAIL gave 4xx error",
101
  [- ERRNO_MAIL4XX] =		US"MAIL gave 4xx error",
104
  US"DATA gave 4xx error",
102
  [- ERRNO_DATA4XX] =		US"DATA gave 4xx error",
105
  US"Negotiation failed for proxy configured host",
103
  [- ERRNO_PROXYFAIL] =		US"Negotiation failed for proxy configured host",
106
  US"Authenticator 'other' failure",
104
  [- ERRNO_AUTHPROB] =		US"Authenticator 'other' failure",
107
  US"target not supporting SMTPUTF8",
105
  [- ERRNO_UTF8_FWD] =		US"target not supporting SMTPUTF8",
108
  US"",
106
  [- ERRNO_HOST_IS_LOCAL] =	US"host is local",
109
107
  [- ERRNO_TAINT] =		US"tainted filename",
110
  US"Not time for routing",
108
111
  US"Not time for local delivery",
109
  [- ERRNO_RRETRY] =		US"Not time for routing",
112
  US"Not time for any remote host",
110
113
  US"Local-only delivery",
111
  [- ERRNO_LRETRY] =		US"Not time for local delivery",
114
  US"Domain in queue_domains",
112
  [- ERRNO_HRETRY] =		US"Not time for any remote host",
115
  US"Transport concurrency limit",
113
  [- ERRNO_LOCAL_ONLY] =	US"Local-only delivery",
116
  US"Event requests alternate response",
114
  [- ERRNO_QUEUE_DOMAIN] =	US"Domain in queue_domains",
115
  [- ERRNO_TRETRY] =		US"Transport concurrency limit",
116
117
  [- ERRNO_EVENT] =		US"Event requests alternate response",
117
};
118
};
118
119
119
120
Lines 265-271 Link Here
265
*/
266
*/
266
267
267
static int
268
static int
268
log_open_already_exim(uschar * const name)
269
log_open_already_exim(const uschar * const name)
269
{
270
{
270
int fd = -1;
271
int fd = -1;
271
const int flags = O_WRONLY | O_APPEND | O_CREAT | O_NONBLOCK;
272
const int flags = O_WRONLY | O_APPEND | O_CREAT | O_NONBLOCK;
Lines 287-294 Link Here
287
  uschar *lastslash = Ustrrchr(name, '/');
288
  uschar *lastslash = Ustrrchr(name, '/');
288
  *lastslash = 0;
289
  *lastslash = 0;
289
  created = directory_make(NULL, name, LOG_DIRECTORY_MODE, FALSE);
290
  created = directory_make(NULL, name, LOG_DIRECTORY_MODE, FALSE);
290
  DEBUG(D_any) debug_printf("%s log directory %s\n",
291
  DEBUG(D_any)
291
    created ? "created" : "failed to create", name);
292
    if (created)
293
      debug_printf("created log directory %s\n", name);
294
    else
295
      debug_printf("failed to create log directory %s: %s\n", name, strerror(errno));
292
  *lastslash = '/';
296
  *lastslash = '/';
293
  if (created) fd = Uopen(name, flags, LOG_MODE);
297
  if (created) fd = Uopen(name, flags, LOG_MODE);
294
  }
298
  }
Lines 298-306 Link Here
298
302
299
303
300
304
301
/* Inspired by OpenSSH's mm_send_fd(). Thanks! */
305
/* Inspired by OpenSSH's mm_send_fd(). Thanks!
306
Send fd over socketpair.
307
Return: true iff good.
308
*/
302
309
303
static int
310
static BOOL
304
log_send_fd(const int sock, const int fd)
311
log_send_fd(const int sock, const int fd)
305
{
312
{
306
struct msghdr msg;
313
struct msghdr msg;
Lines 309-316 Link Here
309
  char buf[CMSG_SPACE(sizeof(int))];
316
  char buf[CMSG_SPACE(sizeof(int))];
310
} cmsgbuf;
317
} cmsgbuf;
311
struct cmsghdr *cmsg;
318
struct cmsghdr *cmsg;
312
struct iovec vec;
313
char ch = 'A';
319
char ch = 'A';
320
struct iovec vec = {.iov_base = &ch, .iov_len = 1};
314
ssize_t n;
321
ssize_t n;
315
322
316
memset(&msg, 0, sizeof(msg));
323
memset(&msg, 0, sizeof(msg));
Lines 324-340 Link Here
324
cmsg->cmsg_type = SCM_RIGHTS;
331
cmsg->cmsg_type = SCM_RIGHTS;
325
*(int *)CMSG_DATA(cmsg) = fd;
332
*(int *)CMSG_DATA(cmsg) = fd;
326
333
327
vec.iov_base = &ch;
328
vec.iov_len = 1;
329
msg.msg_iov = &vec;
334
msg.msg_iov = &vec;
330
msg.msg_iovlen = 1;
335
msg.msg_iovlen = 1;
331
336
332
while ((n = sendmsg(sock, &msg, 0)) == -1 && errno == EINTR);
337
while ((n = sendmsg(sock, &msg, 0)) == -1 && errno == EINTR);
333
if (n != 1) return -1;
338
return n == 1;
334
return 0;
335
}
339
}
336
340
337
/* Inspired by OpenSSH's mm_receive_fd(). Thanks! */
341
/* Inspired by OpenSSH's mm_receive_fd(). Thanks!
342
Return fd passed over socketpair, or -1 on error.
343
*/
338
344
339
static int
345
static int
340
log_recv_fd(const int sock)
346
log_recv_fd(const int sock)
Lines 345-358 Link Here
345
  char buf[CMSG_SPACE(sizeof(int))];
351
  char buf[CMSG_SPACE(sizeof(int))];
346
} cmsgbuf;
352
} cmsgbuf;
347
struct cmsghdr *cmsg;
353
struct cmsghdr *cmsg;
348
struct iovec vec;
349
ssize_t n;
350
char ch = '\0';
354
char ch = '\0';
351
int fd = -1;
355
struct iovec vec = {.iov_base = &ch, .iov_len = 1};
356
ssize_t n;
357
int fd;
352
358
353
memset(&msg, 0, sizeof(msg));
359
memset(&msg, 0, sizeof(msg));
354
vec.iov_base = &ch;
355
vec.iov_len = 1;
356
msg.msg_iov = &vec;
360
msg.msg_iov = &vec;
357
msg.msg_iovlen = 1;
361
msg.msg_iovlen = 1;
358
362
Lines 360-373 Link Here
360
msg.msg_control = &cmsgbuf.buf;
364
msg.msg_control = &cmsgbuf.buf;
361
msg.msg_controllen = sizeof(cmsgbuf.buf);
365
msg.msg_controllen = sizeof(cmsgbuf.buf);
362
366
363
while ((n = recvmsg(sock, &msg, 0)) == -1 && errno == EINTR);
367
while ((n = recvmsg(sock, &msg, 0)) == -1 && errno == EINTR) ;
364
if (n != 1 || ch != 'A') return -1;
368
if (n != 1 || ch != 'A') return -1;
365
369
366
cmsg = CMSG_FIRSTHDR(&msg);
370
if (!(cmsg = CMSG_FIRSTHDR(&msg))) return -1;
367
if (cmsg == NULL) return -1;
368
if (cmsg->cmsg_type != SCM_RIGHTS) return -1;
371
if (cmsg->cmsg_type != SCM_RIGHTS) return -1;
369
fd = *(const int *)CMSG_DATA(cmsg);
372
if ((fd = *(const int *)CMSG_DATA(cmsg)) < 0) return -1;
370
if (fd < 0) return -1;
371
return fd;
373
return fd;
372
}
374
}
373
375
Lines 388-421 Link Here
388
*/
390
*/
389
391
390
int
392
int
391
log_open_as_exim(uschar * const name)
393
log_open_as_exim(const uschar * const name)
392
{
394
{
393
int fd = -1;
395
int fd = -1;
394
const uid_t euid = geteuid();
396
const uid_t euid = geteuid();
395
397
396
if (euid == exim_uid)
398
if (euid == exim_uid)
397
  {
398
  fd = log_open_already_exim(name);
399
  fd = log_open_already_exim(name);
399
  }
400
else if (euid == root_uid)
400
else if (euid == root_uid)
401
  {
401
  {
402
  int sock[2];
402
  int sock[2];
403
  if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock) == 0)
403
  if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock) == 0)
404
    {
404
    {
405
    const pid_t pid = exim_fork(US"logfile-open");
405
    const pid_t pid = fork();
406
    if (pid == 0)
406
    if (pid == 0)
407
      {
407
      {
408
      (void)close(sock[0]);
408
      (void)close(sock[0]);
409
      if (setgroups(1, &exim_gid) != 0) _exit(EXIT_FAILURE);
409
      if (  setgroups(1, &exim_gid) != 0
410
      if (setgid(exim_gid) != 0) _exit(EXIT_FAILURE);
410
         || setgid(exim_gid) != 0
411
      if (setuid(exim_uid) != 0) _exit(EXIT_FAILURE);
411
         || setuid(exim_uid) != 0
412
412
413
      if (getuid() != exim_uid || geteuid() != exim_uid) _exit(EXIT_FAILURE);
413
         || getuid() != exim_uid || geteuid() != exim_uid
414
      if (getgid() != exim_gid || getegid() != exim_gid) _exit(EXIT_FAILURE);
414
         || getgid() != exim_gid || getegid() != exim_gid
415
415
416
      fd = log_open_already_exim(name);
416
         || (fd = log_open_already_exim(name)) < 0
417
      if (fd < 0) _exit(EXIT_FAILURE);
417
         || !log_send_fd(sock[1], fd)
418
      if (log_send_fd(sock[1], fd) != 0) _exit(EXIT_FAILURE);
418
	 ) _exit(EXIT_FAILURE);
419
      (void)close(sock[1]);
419
      (void)close(sock[1]);
420
      _exit(EXIT_SUCCESS);
420
      _exit(EXIT_SUCCESS);
421
      }
421
      }
Lines 439-447 Link Here
439
  if (flags != -1) (void)fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
439
  if (flags != -1) (void)fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
440
  }
440
  }
441
else
441
else
442
  {
443
  errno = EACCES;
442
  errno = EACCES;
444
  }
445
443
446
return fd;
444
return fd;
447
}
445
}
Lines 457-463 Link Here
457
it does not exist. This may be called recursively on failure, in order to open
455
it does not exist. This may be called recursively on failure, in order to open
458
the panic log.
456
the panic log.
459
457
460
The directory is in the static variable file_path. This is static so that it
458
The directory is in the static variable file_path. This is static so that
461
the work of sorting out the path is done just once per Exim process.
459
the work of sorting out the path is done just once per Exim process.
462
460
463
Exim is normally configured to avoid running as root wherever possible, the log
461
Exim is normally configured to avoid running as root wherever possible, the log
Lines 475-481 Link Here
475
*/
473
*/
476
474
477
static void
475
static void
478
open_log(int *fd, int type, uschar *tag)
476
open_log(int * fd, int type, const uschar * tag)
479
{
477
{
480
uid_t euid;
478
uid_t euid;
481
BOOL ok, ok2;
479
BOOL ok, ok2;
Lines 492-551 Link Here
492
490
493
ok = string_format(buffer, sizeof(buffer), CS file_path, log_names[type]);
491
ok = string_format(buffer, sizeof(buffer), CS file_path, log_names[type]);
494
492
495
/* Save the name of the mainlog for rollover processing. Without a datestamp,
493
switch (type)
496
it gets statted to see if it has been cycled. With a datestamp, the datestamp
497
will be compared. The static slot for saving it is the same size as buffer,
498
and the text has been checked above to fit, so this use of strcpy() is OK. */
499
500
if (type == lt_main && string_datestamp_offset >= 0)
501
  {
494
  {
502
  Ustrcpy(mainlog_name, buffer);
495
  case lt_main:
503
  mainlog_datestamp = mainlog_name + string_datestamp_offset;
496
    /* Save the name of the mainlog for rollover processing. Without a datestamp,
504
  }
497
    it gets statted to see if it has been cycled. With a datestamp, the datestamp
505
498
    will be compared. The static slot for saving it is the same size as buffer,
506
/* Ditto for the reject log */
499
    and the text has been checked above to fit, so this use of strcpy() is OK. */
507
500
    Ustrcpy(mainlog_name, buffer);
508
else if (type == lt_reject && string_datestamp_offset >= 0)
501
    if (string_datestamp_offset > 0)
509
  {
502
      mainlog_datestamp = mainlog_name + string_datestamp_offset;
510
  Ustrcpy(rejectlog_name, buffer);
503
    break;
511
  rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
512
  }
513
514
/* and deal with the debug log (which keeps the datestamp, but does not
515
update it) */
516
504
517
else if (type == lt_debug)
505
  case lt_reject:
518
  {
506
    /* Ditto for the reject log */
519
  Ustrcpy(debuglog_name, buffer);
507
    Ustrcpy(rejectlog_name, buffer);
520
  if (tag)
508
    if (string_datestamp_offset > 0)
521
    {
509
      rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
522
    /* this won't change the offset of the datestamp */
510
    break;
523
    ok2 = string_format(buffer, sizeof(buffer), "%s%s",
524
      debuglog_name, tag);
525
    if (ok2)
526
      Ustrcpy(debuglog_name, buffer);
527
    }
528
  }
529
511
530
/* Remove any datestamp if this is the panic log. This is rare, so there's no
512
  case lt_debug:
531
need to optimize getting the datestamp length. We remove one non-alphanumeric
513
    /* and deal with the debug log (which keeps the datestamp, but does not
532
char afterwards if at the start, otherwise one before. */
514
    update it) */
515
    Ustrcpy(debuglog_name, buffer);
516
    if (tag)
517
      {
518
      if (is_tainted(tag))
519
      	die(US"exim: tainted tag for debug log filename",
520
      	      US"Logging failure; please try later");
521
522
      /* this won't change the offset of the datestamp */
523
      ok2 = string_format(buffer, sizeof(buffer), "%s%s",
524
        debuglog_name, tag);
525
      if (ok2)
526
        Ustrcpy(debuglog_name, buffer);
527
      }
528
    break;
533
529
534
else if (string_datestamp_offset >= 0)
530
  default:
535
  {
531
    /* Remove any datestamp if this is the panic log. This is rare, so there's no
536
  uschar * from = buffer + string_datestamp_offset;
532
    need to optimize getting the datestamp length. We remove one non-alphanumeric
537
  uschar * to = from + string_datestamp_length;
533
    char afterwards if at the start, otherwise one before. */
534
    if (string_datestamp_offset >= 0)
535
      {
536
      uschar * from = buffer + string_datestamp_offset;
537
      uschar * to = from + string_datestamp_length;
538
538
539
  if (from == buffer || from[-1] == '/')
539
      if (from == buffer || from[-1] == '/')
540
    {
540
        {
541
    if (!isalnum(*to)) to++;
541
        if (!isalnum(*to)) to++;
542
    }
542
        }
543
  else
543
      else
544
    if (!isalnum(from[-1])) from--;
544
        if (!isalnum(from[-1])) from--;
545
545
546
  /* This copy is ok, because we know that to is a substring of from. But
546
      /* This copy is ok, because we know that to is a substring of from. But
547
  due to overlap we must use memmove() not Ustrcpy(). */
547
      due to overlap we must use memmove() not Ustrcpy(). */
548
  memmove(from, to, Ustrlen(to)+1);
548
      memmove(from, to, Ustrlen(to)+1);
549
      }
550
    break;
549
  }
551
  }
550
552
551
/* If the file name is too long, it is an unrecoverable disaster */
553
/* If the file name is too long, it is an unrecoverable disaster */
Lines 556-567 Link Here
556
558
557
/* We now have the file name. After a successful open, return. */
559
/* We now have the file name. After a successful open, return. */
558
560
559
*fd = log_open_as_exim(buffer);
561
if ((*fd = log_open_as_exim(buffer)) >= 0)
560
561
if (*fd >= 0)
562
  {
563
  return;
562
  return;
564
  }
565
563
566
euid = geteuid();
564
euid = geteuid();
567
565
Lines 729-738 Link Here
729
}
727
}
730
728
731
729
730
/* Close mainlog, unless we do not see a chance to open the file mainlog later
731
again.  This will happen if we log from a transport process (which has dropped
732
privs); something we traditionally avoid, but the introduction of taint-tracking
733
and resulting detection of errors is makinng harder. */
734
732
void
735
void
733
mainlog_close(void)
736
mainlog_close(void)
734
{
737
{
735
if (mainlogfd < 0) return;
738
if (mainlogfd < 0
739
   || !(geteuid() == 0 || geteuid() == exim_uid))
740
  return;
736
(void)close(mainlogfd);
741
(void)close(mainlogfd);
737
mainlogfd = -1;
742
mainlogfd = -1;
738
mainlog_inode = 0;
743
mainlog_inode = 0;
Lines 902-907 Link Here
902
      "More than one path given in log_file_path: using %s", file_path);
907
      "More than one path given in log_file_path: using %s", file_path);
903
  }
908
  }
904
909
910
/* Optionally trigger debug */
911
912
if (flags & LOG_PANIC && dtrigger_selector & BIT(DTi_panictrigger))
913
  debug_trigger_fire();
914
905
/* If debugging, show all log entries, but don't show headers. Do it all
915
/* If debugging, show all log entries, but don't show headers. Do it all
906
in one go so that it doesn't get split when multi-processing. */
916
in one go so that it doesn't get split when multi-processing. */
907
917
Lines 1249-1258 Link Here
1249
    panic_recurseflag = FALSE;
1259
    panic_recurseflag = FALSE;
1250
1260
1251
    if (panic_save_buffer)
1261
    if (panic_save_buffer)
1252
      {
1262
      (void) write(paniclogfd, panic_save_buffer, Ustrlen(panic_save_buffer));
1253
      int i = write(paniclogfd, panic_save_buffer, Ustrlen(panic_save_buffer));
1254
      i = i;	/* compiler quietening */
1255
      }
1256
1263
1257
    written_len = write_to_fd_buf(paniclogfd, g->s, g->ptr);
1264
    written_len = write_to_fd_buf(paniclogfd, g->s, g->ptr);
1258
    if (written_len != g->ptr)
1265
    if (written_len != g->ptr)
Lines 1356-1363 Link Here
1356
*/
1363
*/
1357
1364
1358
void
1365
void
1359
decode_bits(unsigned int *selector, size_t selsize, int *notall,
1366
decode_bits(unsigned int * selector, size_t selsize, int * notall,
1360
  uschar *string, bit_table *options, int count, uschar *which, int flags)
1367
  const uschar * string, bit_table * options, int count, uschar * which,
1368
  int flags)
1361
{
1369
{
1362
uschar *errmsg;
1370
uschar *errmsg;
1363
if (!string) return;
1371
if (!string) return;
Lines 1366-1372 Link Here
1366
  {
1374
  {
1367
  char *end;    /* Not uschar */
1375
  char *end;    /* Not uschar */
1368
  memset(selector, 0, sizeof(*selector)*selsize);
1376
  memset(selector, 0, sizeof(*selector)*selsize);
1369
  *selector = strtoul(CS string+1, &end, 0);
1377
  *selector = strtoul(CCS string+1, &end, 0);
1370
  if (!*end) return;
1378
  if (!*end) return;
1371
  errmsg = string_sprintf("malformed numeric %s_selector setting: %s", which,
1379
  errmsg = string_sprintf("malformed numeric %s_selector setting: %s", which,
1372
    string);
1380
    string);
Lines 1378-1386 Link Here
1378
else for(;;)
1386
else for(;;)
1379
  {
1387
  {
1380
  BOOL adding;
1388
  BOOL adding;
1381
  uschar *s;
1389
  const uschar * s;
1382
  int len;
1390
  int len;
1383
  bit_table *start, *end;
1391
  bit_table * start, * end;
1384
1392
1385
  Uskip_whitespace(&string);
1393
  Uskip_whitespace(&string);
1386
  if (!*string) return;
1394
  if (!*string) return;
Lines 1469-1481 Link Here
1469
1477
1470
The first use of this is in ACL logic, "control = debug/tag=foo/opts=+expand"
1478
The first use of this is in ACL logic, "control = debug/tag=foo/opts=+expand"
1471
which can be combined with conditions, etc, to activate extra logging only
1479
which can be combined with conditions, etc, to activate extra logging only
1472
for certain sources. The second use is inetd wait mode debug preservation. */
1480
for certain sources. The second use is inetd wait mode debug preservation.
1481
1482
It might be nice, in ACL-initiated pretrigger mode, to not create the file
1483
immediately but only upon a trigger - but we'd need another cmdline option
1484
to pass the name through child_exxec_exim(). */
1473
1485
1474
void
1486
void
1475
debug_logging_activate(uschar *tag_name, uschar *opts)
1487
debug_logging_activate(const uschar * tag_name, const uschar * opts)
1476
{
1488
{
1477
int fd = -1;
1478
1479
if (debug_file)
1489
if (debug_file)
1480
  {
1490
  {
1481
  debug_printf("DEBUGGING ACTIVATED FROM WITHIN CONFIG.\n"
1491
  debug_printf("DEBUGGING ACTIVATED FROM WITHIN CONFIG.\n"
Lines 1483-1489 Link Here
1483
  return;
1493
  return;
1484
  }
1494
  }
1485
1495
1486
if (tag_name != NULL && (Ustrchr(tag_name, '/') != NULL))
1496
if (tag_name && (Ustrchr(tag_name, '/') != NULL))
1487
  {
1497
  {
1488
  log_write(0, LOG_MAIN|LOG_PANIC, "debug tag may not contain a '/' in: %s",
1498
  log_write(0, LOG_MAIN|LOG_PANIC, "debug tag may not contain a '/' in: %s",
1489
      tag_name);
1499
      tag_name);
Lines 1501-1524 Link Here
1501
1511
1502
if (!*file_path) set_file_path();
1512
if (!*file_path) set_file_path();
1503
1513
1504
open_log(&fd, lt_debug, tag_name);
1514
open_log(&debug_fd, lt_debug, tag_name);
1505
1515
1506
if (fd != -1)
1516
if (debug_fd != -1)
1507
  debug_file = fdopen(fd, "w");
1517
  debug_file = fdopen(debug_fd, "w");
1508
else
1518
else
1509
  log_write(0, LOG_MAIN|LOG_PANIC, "unable to open debug log");
1519
  log_write(0, LOG_MAIN|LOG_PANIC, "unable to open debug log");
1510
}
1520
}
1511
1521
1512
1522
1513
void
1523
void
1514
debug_logging_stop(void)
1524
debug_logging_from_spool(const uschar * filename)
1525
{
1526
if (debug_fd < 0)
1527
  {
1528
  Ustrncpy(debuglog_name, filename, sizeof(debuglog_name));
1529
  if ((debug_fd = log_open_as_exim(filename)) >= 0)
1530
    debug_file = fdopen(debug_fd, "w");
1531
  DEBUG(D_deliver) debug_printf("debug enabled by spoolfile\n");
1532
  }
1533
/*
1534
else DEBUG(D_deliver)
1535
  debug_printf("debug already active; ignoring spoolfile '%s'\n", filename);
1536
*/
1537
}
1538
1539
1540
void
1541
debug_logging_stop(BOOL kill)
1515
{
1542
{
1543
debug_pretrigger_discard();
1516
if (!debug_file || !debuglog_name[0]) return;
1544
if (!debug_file || !debuglog_name[0]) return;
1517
1545
1518
debug_selector = 0;
1546
debug_selector = 0;
1519
fclose(debug_file);
1547
fclose(debug_file);
1520
debug_file = NULL;
1548
debug_file = NULL;
1521
unlink_log(lt_debug);
1549
debug_fd = -1;
1550
if (kill) unlink_log(lt_debug);
1522
}
1551
}
1523
1552
1524
1553
(-)exim.orig/src/lookupapi.h (-5 / +8 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2015 */
6
/* 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. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 42-57 Link Here
42
  void (*tidy)(void);             /* tidy function */
42
  void (*tidy)(void);             /* tidy function */
43
  uschar *(*quote)(               /* quoting function */
43
  uschar *(*quote)(               /* quoting function */
44
    uschar *,                     /* string to quote */
44
    uschar *,                     /* string to quote */
45
    uschar *);                    /* additional data from quote name */
45
    uschar *,                     /* additional data from quote name */
46
  void (*version_report)(         /* diagnostic function */
46
    unsigned);			  /* lookup type index */
47
    FILE *);                      /* fh to write to */
47
  gstring * (*version_report)(    /* diagnostic function */
48
    gstring *);                   /* string to appand to */
48
} lookup_info;
49
} lookup_info;
49
50
50
/* This magic number is used by the following lookup_module_info structure
51
/* This magic number is used by the following lookup_module_info structure
51
   for checking API compatibility. It used to be equivalent to the string"LMM3" */
52
   for checking API compatibility. It used to be equivalent to the string"LMM3" */
52
#define LOOKUP_MODULE_INFO_MAGIC 0x4c4d4933
53
#define LOOKUP_MODULE_INFO_MAGIC 0x4c4d4935
53
/* Version 2 adds: version_report */
54
/* Version 2 adds: version_report */
54
/* Version 3 change: non/cache becomes TTL in seconds */
55
/* Version 3 change: non/cache becomes TTL in seconds */
56
/* Version 4 add: index on quoting function */
57
/* Version 5 change: version report now adds to a gstring */
55
58
56
typedef struct lookup_module_info {
59
typedef struct lookup_module_info {
57
  uint magic;
60
  uint magic;
(-)exim.orig/src/lookups/cdb.c (-26 / +14 lines)
Lines 6-13 Link Here
6
 * Exim - CDB database lookup module
6
 * Exim - CDB database lookup module
7
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8
 *
8
 *
9
 * Copyright (c) The Exim Maintainers 2020 - 2022
9
 * Copyright (c) 1998 Nigel Metheringham, Planet Online Ltd
10
 * Copyright (c) 1998 Nigel Metheringham, Planet Online Ltd
10
 * Copyright (c) The Exim Maintainers 2020
11
 *
11
 *
12
 * This program is free software; you can redistribute it and/or
12
 * This program is free software; you can redistribute it and/or
13
 * modify it under the terms of the GNU General Public License
13
 * modify it under the terms of the GNU General Public License
Lines 157-175 Link Here
157
157
158
if ((fileno = Uopen(filename, O_RDONLY, 0)) < 0)
158
if ((fileno = Uopen(filename, O_RDONLY, 0)) < 0)
159
  {
159
  {
160
  int save_errno = errno;
160
  *errmsg = string_open_failed("%s for cdb lookup", filename);
161
  *errmsg = string_open_failed(errno, "%s for cdb lookup", filename);
162
  errno = save_errno;
163
  return NULL;
161
  return NULL;
164
  }
162
  }
165
163
166
if (fstat(fileno, &statbuf) != 0)
164
if (fstat(fileno, &statbuf) != 0)
167
  {
165
  {
168
  int save_errno = errno;
166
  *errmsg = string_open_failed("fstat(%s) failed - cannot do cdb lookup",
169
  *errmsg = string_open_failed(errno,
170
			      "fstat(%s) failed - cannot do cdb lookup",
171
			      filename);
167
			      filename);
172
  errno = save_errno;
173
  return NULL;
168
  return NULL;
174
  }
169
  }
175
170
Lines 178-193 Link Here
178
173
179
if (statbuf.st_size < CDB_HASH_TABLE)
174
if (statbuf.st_size < CDB_HASH_TABLE)
180
  {
175
  {
181
  int save_errno = errno;
176
  *errmsg = string_open_failed("%s too short for cdb lookup", filename);
182
  *errmsg = string_open_failed(errno,
183
			      "%s too short for cdb lookup",
184
			      filename);
185
  errno = save_errno;
186
  return NULL;
177
  return NULL;
187
  }
178
  }
188
179
189
/* Having got a file open we need the structure to put things in */
180
/* Having got a file open we need the structure to put things in */
190
cdbp = store_get(sizeof(struct cdb_state), FALSE);
181
cdbp = store_get(sizeof(struct cdb_state), GET_UNTAINTED);
191
/* store_get() does not return if memory was not available... */
182
/* store_get() does not return if memory was not available... */
192
/* preload the structure.... */
183
/* preload the structure.... */
193
cdbp->fileno = fileno;
184
cdbp->fileno = fileno;
Lines 222-228 Link Here
222
/* get a buffer to stash the basic offsets in - this should speed
213
/* get a buffer to stash the basic offsets in - this should speed
223
things up a lot - especially on multiple lookups */
214
things up a lot - especially on multiple lookups */
224
215
225
cdbp->cdb_offsets = store_get(CDB_HASH_TABLE, FALSE);
216
cdbp->cdb_offsets = store_get(CDB_HASH_TABLE, GET_UNTAINTED);
226
217
227
/* now fill the buffer up... */
218
/* now fill the buffer up... */
228
219
Lines 231-238 Link Here
231
  /* read of hash table failed, oh dear, oh.....  time to give up I think....
222
  /* read of hash table failed, oh dear, oh.....  time to give up I think....
232
  call the close routine (deallocs the memory), and return NULL */
223
  call the close routine (deallocs the memory), and return NULL */
233
224
234
  *errmsg = string_open_failed(errno,
225
  *errmsg = string_open_failed("cannot read header from %s for cdb lookup",
235
			      "cannot read header from %s for cdb lookup",
236
			      filename);
226
			      filename);
237
  cdb_close(cdbp);
227
  cdb_close(cdbp);
238
  return NULL;
228
  return NULL;
Lines 281-289 Link Here
281
hash_offlen,
271
hash_offlen,
282
hash_slotnm;
272
hash_slotnm;
283
273
284
/* Keep picky compilers happy */
285
do_cache = do_cache;
286
287
key_hash = cdb_hash(keystring, key_len);
274
key_hash = cdb_hash(keystring, key_len);
288
275
289
hash_offset_entry = CDB_HASH_ENTRY * (key_hash & CDB_HASH_MASK);
276
hash_offset_entry = CDB_HASH_ENTRY * (key_hash & CDB_HASH_MASK);
Lines 356-362 Link Here
356
	   /* ... and the returned result.  Assume it is not
343
	   /* ... and the returned result.  Assume it is not
357
	   tainted, lacking any way of telling.  */
344
	   tainted, lacking any way of telling.  */
358
345
359
	   *result = store_get(item_dat_len + 1, FALSE);
346
	   *result = store_get(item_dat_len + 1, GET_UNTAINTED);
360
	   memcpy(*result, item_ptr, item_dat_len);
347
	   memcpy(*result, item_ptr, item_dat_len);
361
	   (*result)[item_dat_len] = 0;
348
	   (*result)[item_dat_len] = 0;
362
	   return OK;
349
	   return OK;
Lines 400-406 Link Here
400
    if (item_key_len == key_len)
387
    if (item_key_len == key_len)
401
      {					/* finally check if key matches */
388
      {					/* finally check if key matches */
402
      rmark reset_point = store_mark();
389
      rmark reset_point = store_mark();
403
      uschar * item_key = store_get(key_len, TRUE); /* keys liable to be tainted */
390
      uschar * item_key = store_get(key_len, GET_TAINTED); /* keys liable to be tainted */
404
391
405
      if (cdb_bread(cdbp->fileno, item_key, key_len) == -1) return DEFER;
392
      if (cdb_bread(cdbp->fileno, item_key, key_len) == -1) return DEFER;
406
      if (Ustrncmp(keystring, item_key, key_len) == 0)
393
      if (Ustrncmp(keystring, item_key, key_len) == 0)
Lines 414-420 Link Here
414
        /* then we build a new result string.  We know we have enough
401
        /* then we build a new result string.  We know we have enough
415
        memory so disable Coverity errors about the tainted item_dat_ken */
402
        memory so disable Coverity errors about the tainted item_dat_ken */
416
403
417
        *result = store_get(item_dat_len + 1, FALSE);
404
        *result = store_get(item_dat_len + 1, GET_UNTAINTED);
418
        /* coverity[tainted_data] */
405
        /* coverity[tainted_data] */
419
        if (cdb_bread(cdbp->fileno, *result, item_dat_len) == -1)
406
        if (cdb_bread(cdbp->fileno, *result, item_dat_len) == -1)
420
	  return DEFER;
407
	  return DEFER;
Lines 471-482 Link Here
471
458
472
#include "../version.h"
459
#include "../version.h"
473
460
474
void
461
gstring *
475
cdb_version_report(FILE *f)
462
cdb_version_report(gstring * g)
476
{
463
{
477
#ifdef DYNLOOKUP
464
#ifdef DYNLOOKUP
478
fprintf(f, "Library version: CDB: Exim version %s\n", EXIM_VERSION_STR);
465
g = string_fmt_append(g, "Library version: CDB: Exim version %s\n", EXIM_VERSION_STR);
479
#endif
466
#endif
467
return g;
480
}
468
}
481
469
482
470
(-)exim.orig/src/lookups/dbmdb.c (-26 / +19 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#include "../exim.h"
9
#include "../exim.h"
Lines 21-36 Link Here
21
{
21
{
22
uschar * dirname = string_copy(filename);
22
uschar * dirname = string_copy(filename);
23
uschar * s;
23
uschar * s;
24
EXIM_DB *yield = NULL;
24
EXIM_DB * yield = NULL;
25
25
26
if ((s = Ustrrchr(dirname, '/'))) *s = '\0';
26
if ((s = Ustrrchr(dirname, '/'))) *s = '\0';
27
EXIM_DBOPEN(filename, dirname, O_RDONLY, 0, &yield);
27
if (!(yield = exim_dbopen(filename, dirname, O_RDONLY, 0)))
28
if (!yield)
28
  *errmsg = string_open_failed("%s as a %s file", filename, EXIM_DBTYPE);
29
  {
30
  int save_errno = errno;
31
  *errmsg = string_open_failed(errno, "%s as a %s file", filename, EXIM_DBTYPE);
32
  errno = save_errno;
33
  }
34
return yield;
29
return yield;
35
}
30
}
36
31
Lines 52-58 Link Here
52
  gid_t *owngroups, uschar **errmsg)
47
  gid_t *owngroups, uschar **errmsg)
53
{
48
{
54
int rc;
49
int rc;
55
handle = handle;    /* Keep picky compilers happy */
56
50
57
#if defined(USE_DB) || defined(USE_TDB) || defined(USE_GDBM)
51
#if defined(USE_DB) || defined(USE_TDB) || defined(USE_GDBM)
58
rc = lf_check_file(-1, filename, S_IFREG, modemask, owners, owngroups,
52
rc = lf_check_file(-1, filename, S_IFREG, modemask, owners, owngroups,
Lines 98-116 Link Here
98
EXIM_DB *d = (EXIM_DB *)handle;
92
EXIM_DB *d = (EXIM_DB *)handle;
99
EXIM_DATUM key, data;
93
EXIM_DATUM key, data;
100
94
101
filename = filename;    /* Keep picky compilers happy */
95
exim_datum_init(&key);               /* Some DBM libraries require datums to */
102
errmsg = errmsg;
96
exim_datum_init(&data);              /* be cleared before use. */
103
do_cache = do_cache;
97
length++;
104
98
exim_datum_data_set(&key,
105
EXIM_DATUM_INIT(key);               /* Some DBM libraries require datums to */
99
  memcpy(store_get(length, keystring), keystring, length)); /* key can have embedded NUL */
106
EXIM_DATUM_INIT(data);              /* be cleared before use. */
100
exim_datum_size_set(&key, length);
107
EXIM_DATUM_DATA(key) = CS keystring;
108
EXIM_DATUM_SIZE(key) = length + 1;
109
101
110
if (EXIM_DBGET(d, key, data))
102
if (exim_dbget(d, &key, &data))
111
  {
103
  {
112
  *result = string_copyn(US EXIM_DATUM_DATA(data), EXIM_DATUM_SIZE(data));
104
  *result = string_copyn(exim_datum_data_get(&data), exim_datum_size_get(&data));
113
  EXIM_DATUM_FREE(data);            /* Some DBM libraries need a free() call */
105
  exim_datum_free(&data);            /* Some DBM libraries need a free() call */
114
  return OK;
106
  return OK;
115
  }
107
  }
116
return FAIL;
108
return FAIL;
Lines 158-164 Link Here
158
or less than, the length of the delimited list passed in + 1. */
150
or less than, the length of the delimited list passed in + 1. */
159
151
160
buflen = length + 3;
152
buflen = length + 3;
161
key_buffer = store_get(buflen, is_tainted(keystring));
153
key_buffer = store_get(buflen, keystring);
162
154
163
key_buffer[0] = '\0';
155
key_buffer[0] = '\0';
164
156
Lines 223-229 Link Here
223
void
215
void
224
static dbmdb_close(void *handle)
216
static dbmdb_close(void *handle)
225
{
217
{
226
EXIM_DBCLOSE((EXIM_DB *)handle);
218
exim_dbclose((EXIM_DB *)handle);
227
}
219
}
228
220
229
221
Lines 236-247 Link Here
236
228
237
#include "../version.h"
229
#include "../version.h"
238
230
239
void
231
gstring *
240
dbm_version_report(FILE *f)
232
dbm_version_report(gstring * g)
241
{
233
{
242
#ifdef DYNLOOKUP
234
#ifdef DYNLOOKUP
243
fprintf(f, "Library version: DBM: Exim version %s\n", EXIM_VERSION_STR);
235
g = string_fmt_append(g, "Library version: DBM: Exim version %s\n", EXIM_VERSION_STR);
244
#endif
236
#endif
237
return g;
245
}
238
}
246
239
247
240
(-)exim.orig/src/lookups/dnsdb.c (-21 / +30 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#include "../exim.h"
9
#include "../exim.h"
Lines 80-87 Link Here
80
static void *
80
static void *
81
dnsdb_open(const uschar * filename, uschar **errmsg)
81
dnsdb_open(const uschar * filename, uschar **errmsg)
82
{
82
{
83
filename = filename;   /* Keep picky compilers happy */
84
errmsg = errmsg;       /* Ditto */
85
return (void *)(-1);   /* Any non-0 value */
83
return (void *)(-1);   /* Any non-0 value */
86
}
84
}
87
85
Lines 155-165 Link Here
155
153
156
gstring * yield = string_get(256);
154
gstring * yield = string_get(256);
157
155
158
handle = handle;           /* Keep picky compilers happy */
159
filename = filename;
160
length = length;
161
do_cache = do_cache;
162
163
/* If the string starts with '>' we change the output separator.
156
/* If the string starts with '>' we change the output separator.
164
If it's followed by ';' or ',' we set the TXT output separator. */
157
If it's followed by ';' or ',' we set the TXT output separator. */
165
158
Lines 197-203 Link Here
197
    else
190
    else
198
      {
191
      {
199
      *errmsg = US"unsupported dnsdb defer behaviour";
192
      *errmsg = US"unsupported dnsdb defer behaviour";
200
      return DEFER;
193
      rc = DEFER;
194
      goto out;
201
      }
195
      }
202
    }
196
    }
203
  else if (strncmpic(keystring, US"dnssec_", 7) == 0)
197
  else if (strncmpic(keystring, US"dnssec_", 7) == 0)
Lines 212-218 Link Here
212
    else
206
    else
213
      {
207
      {
214
      *errmsg = US"unsupported dnsdb dnssec behaviour";
208
      *errmsg = US"unsupported dnsdb dnssec behaviour";
215
      return DEFER;
209
      rc = DEFER;
210
      goto out;
216
      }
211
      }
217
    }
212
    }
218
  else if (strncmpic(keystring, US"retrans_", 8) == 0)
213
  else if (strncmpic(keystring, US"retrans_", 8) == 0)
Lines 221-227 Link Here
221
    if ((timeout_sec = readconf_readtime(keystring += 8, ',', FALSE)) <= 0)
216
    if ((timeout_sec = readconf_readtime(keystring += 8, ',', FALSE)) <= 0)
222
      {
217
      {
223
      *errmsg = US"unsupported dnsdb timeout value";
218
      *errmsg = US"unsupported dnsdb timeout value";
224
      return DEFER;
219
      rc = DEFER;
220
      goto out;
225
      }
221
      }
226
    dns_retrans = timeout_sec;
222
    dns_retrans = timeout_sec;
227
    while (*keystring != ',') keystring++;
223
    while (*keystring != ',') keystring++;
Lines 232-238 Link Here
232
    if ((retries = (int)strtol(CCS keystring + 6, CSS &keystring, 0)) < 0)
228
    if ((retries = (int)strtol(CCS keystring + 6, CSS &keystring, 0)) < 0)
233
      {
229
      {
234
      *errmsg = US"unsupported dnsdb retry count";
230
      *errmsg = US"unsupported dnsdb retry count";
235
      return DEFER;
231
      rc = DEFER;
232
      goto out;
236
      }
233
      }
237
    dns_retry = retries;
234
    dns_retry = retries;
238
    }
235
    }
Lines 243-249 Link Here
243
  if (*keystring++ != ',')
240
  if (*keystring++ != ',')
244
    {
241
    {
245
    *errmsg = US"dnsdb modifier syntax error";
242
    *errmsg = US"dnsdb modifier syntax error";
246
    return DEFER;
243
    rc = DEFER;
244
    goto out;
247
    }
245
    }
248
  while (isspace(*keystring)) keystring++;
246
  while (isspace(*keystring)) keystring++;
249
  }
247
  }
Lines 271-277 Link Here
271
  if (i >= nelem(type_names))
269
  if (i >= nelem(type_names))
272
    {
270
    {
273
    *errmsg = US"unsupported DNS record type";
271
    *errmsg = US"unsupported DNS record type";
274
    return DEFER;
272
    rc = DEFER;
273
    goto out;
275
    }
274
    }
276
275
277
  keystring = equals + 1;
276
  keystring = equals + 1;
Lines 366-372 Link Here
366
	dns_retrans = save_retrans;
365
	dns_retrans = save_retrans;
367
	dns_retry = save_retry;
366
	dns_retry = save_retry;
368
	dns_init(FALSE, FALSE, FALSE);			/* clr dnssec bit */
367
	dns_init(FALSE, FALSE, FALSE);			/* clr dnssec bit */
369
	return DEFER;					/* always defer */
368
	rc = DEFER;					/* always defer */
369
	goto out;
370
	}
370
	}
371
      if (defer_mode == PASS) failrc = DEFER;         /* defer only if all do */
371
      if (defer_mode == PASS) failrc = DEFER;         /* defer only if all do */
372
      continue;                                       /* treat defer as fail */
372
      continue;                                       /* treat defer as fail */
Lines 556-565 Link Here
556
dns_retry = save_retry;
556
dns_retry = save_retry;
557
dns_init(FALSE, FALSE, FALSE);	/* clear the dnssec bit for getaddrbyname */
557
dns_init(FALSE, FALSE, FALSE);	/* clear the dnssec bit for getaddrbyname */
558
558
559
if (!yield || !yield->ptr) return failrc;
559
if (!yield || !yield->ptr)
560
  rc = failrc;
561
else
562
  {
563
  *result = string_from_gstring(yield);
564
  rc = OK;
565
  }
566
567
out:
560
568
561
*result = string_from_gstring(yield);
569
store_free_dns_answer(dnsa);
562
return OK;
570
return rc;
563
}
571
}
564
572
565
573
Lines 572-583 Link Here
572
580
573
#include "../version.h"
581
#include "../version.h"
574
582
575
void
583
gstring *
576
dnsdb_version_report(FILE *f)
584
dnsdb_version_report(gstring * g)
577
{
585
{
578
#ifdef DYNLOOKUP
586
#ifdef DYNLOOKUP
579
fprintf(f, "Library version: DNSDB: Exim version %s\n", EXIM_VERSION_STR);
587
g = string_fmt_append(g, "Library version: DNSDB: Exim version %s\n", EXIM_VERSION_STR);
580
#endif
588
#endif
589
return g;
581
}
590
}
582
591
583
592
(-)exim.orig/src/lookups/dsearch.c (-12 / +7 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2015 */
6
/* 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. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* The idea for this code came from Matthew Byng-Maddick, but his original has
9
/* The idea for this code came from Matthew Byng-Maddick, but his original has
Lines 31-39 Link Here
31
DIR * dp = exim_opendir(dirname);
31
DIR * dp = exim_opendir(dirname);
32
if (!dp)
32
if (!dp)
33
  {
33
  {
34
  int save_errno = errno;
34
  *errmsg = string_open_failed("%s for directory search", dirname);
35
  *errmsg = string_open_failed(errno, "%s for directory search", dirname);
36
  errno = save_errno;
37
  return NULL;
35
  return NULL;
38
  }
36
  }
39
closedir(dp);
37
closedir(dp);
Lines 86-95 Link Here
86
uschar * filename;
84
uschar * filename;
87
unsigned flags = 0;
85
unsigned flags = 0;
88
86
89
handle = handle;  /* Keep picky compilers happy */
90
length = length;
91
do_cache = do_cache;
92
93
if (Ustrchr(keystring, '/') != 0)
87
if (Ustrchr(keystring, '/') != 0)
94
  {
88
  {
95
  *errmsg = string_sprintf("key for dsearch lookup contains a slash: %s",
89
  *errmsg = string_sprintf("key for dsearch lookup contains a slash: %s",
Lines 130-136 Link Here
130
  {
124
  {
131
  /* Since the filename exists in the filesystem, we can return a
125
  /* Since the filename exists in the filesystem, we can return a
132
  non-tainted result. */
126
  non-tainted result. */
133
  *result = string_copy_taint(flags & RET_FULL ? filename : keystring, FALSE);
127
  *result = string_copy_taint(flags & RET_FULL ? filename : keystring, GET_UNTAINTED);
134
  return OK;
128
  return OK;
135
  }
129
  }
136
130
Lines 164-175 Link Here
164
158
165
#include "../version.h"
159
#include "../version.h"
166
160
167
void
161
gstring *
168
dsearch_version_report(FILE *f)
162
dsearch_version_report(gstring * g)
169
{
163
{
170
#ifdef DYNLOOKUP
164
#ifdef DYNLOOKUP
171
fprintf(f, "Library version: dsearch: Exim version %s\n", EXIM_VERSION_STR);
165
g = string_fmt_append(g, "Library version: dsearch: Exim version %s\n", EXIM_VERSION_STR);
172
#endif
166
#endif
167
return g;
173
}
168
}
174
169
175
170
(-)exim.orig/src/lookups/ibase.c (-63 / +41 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* The code in this module was contributed by Ard Biesheuvel. */
9
/* The code in this module was contributed by Ard Biesheuvel. */
Lines 177-183 Link Here
177
  }
177
  }
178
else
178
else
179
  {
179
  {
180
  cn = store_get(sizeof(ibase_connection), FALSE);
180
  cn = store_get(sizeof(ibase_connection), GET_UNTAINTED);
181
  cn->server = server_copy;
181
  cn->server = server_copy;
182
  cn->dbh = NULL;
182
  cn->dbh = NULL;
183
  cn->transh = NULL;
183
  cn->transh = NULL;
Lines 252-258 Link Here
252
252
253
/* Lacking any information, assume that the data is untainted */
253
/* Lacking any information, assume that the data is untainted */
254
reset_point = store_mark();
254
reset_point = store_mark();
255
out_sqlda = store_get(XSQLDA_LENGTH(1), FALSE);
255
out_sqlda = store_get(XSQLDA_LENGTH(1), GET_UNTAINTED);
256
out_sqlda->version = SQLDA_VERSION1;
256
out_sqlda->version = SQLDA_VERSION1;
257
out_sqlda->sqln = 1;
257
out_sqlda->sqln = 1;
258
258
Lines 272-278 Link Here
272
/* re-allocate the output structure if there's more than one field */
272
/* re-allocate the output structure if there's more than one field */
273
if (out_sqlda->sqln < out_sqlda->sqld)
273
if (out_sqlda->sqln < out_sqlda->sqld)
274
  {
274
  {
275
  XSQLDA *new_sqlda = store_get(XSQLDA_LENGTH(out_sqlda->sqld), FALSE);
275
  XSQLDA *new_sqlda = store_get(XSQLDA_LENGTH(out_sqlda->sqld), GET_UNTAINTED);
276
  if (isc_dsql_describe
276
  if (isc_dsql_describe
277
      (status, &stmth, out_sqlda->version, new_sqlda))
277
      (status, &stmth, out_sqlda->version, new_sqlda))
278
    {
278
    {
Lines 294-339 Link Here
294
  switch (var->sqltype & ~1)
294
  switch (var->sqltype & ~1)
295
    {
295
    {
296
    case SQL_VARYING:
296
    case SQL_VARYING:
297
	var->sqldata = CS store_get(sizeof(char) * var->sqllen + 2, FALSE);
297
	var->sqldata = CS store_get(sizeof(char) * var->sqllen + 2, GET_UNTAINTED);
298
	break;
298
	break;
299
    case SQL_TEXT:
299
    case SQL_TEXT:
300
	var->sqldata = CS store_get(sizeof(char) * var->sqllen, FALSE);
300
	var->sqldata = CS store_get(sizeof(char) * var->sqllen, GET_UNTAINTED);
301
	break;
301
	break;
302
    case SQL_SHORT:
302
    case SQL_SHORT:
303
	var->sqldata = CS  store_get(sizeof(short), FALSE);
303
	var->sqldata = CS  store_get(sizeof(short), GET_UNTAINTED);
304
	break;
304
	break;
305
    case SQL_LONG:
305
    case SQL_LONG:
306
	var->sqldata = CS  store_get(sizeof(ISC_LONG), FALSE);
306
	var->sqldata = CS  store_get(sizeof(ISC_LONG), GET_UNTAINTED);
307
	break;
307
	break;
308
#ifdef SQL_INT64
308
#ifdef SQL_INT64
309
    case SQL_INT64:
309
    case SQL_INT64:
310
	var->sqldata = CS  store_get(sizeof(ISC_INT64), FALSE);
310
	var->sqldata = CS  store_get(sizeof(ISC_INT64), GET_UNTAINTED);
311
	break;
311
	break;
312
#endif
312
#endif
313
    case SQL_FLOAT:
313
    case SQL_FLOAT:
314
	var->sqldata = CS  store_get(sizeof(float), FALSE);
314
	var->sqldata = CS  store_get(sizeof(float), GET_UNTAINTED);
315
	break;
315
	break;
316
    case SQL_DOUBLE:
316
    case SQL_DOUBLE:
317
	var->sqldata = CS  store_get(sizeof(double), FALSE);
317
	var->sqldata = CS  store_get(sizeof(double), GET_UNTAINTED);
318
	break;
318
	break;
319
#ifdef SQL_TIMESTAMP
319
#ifdef SQL_TIMESTAMP
320
    case SQL_DATE:
320
    case SQL_DATE:
321
	var->sqldata = CS  store_get(sizeof(ISC_QUAD), FALSE);
321
	var->sqldata = CS  store_get(sizeof(ISC_QUAD), GET_UNTAINTED);
322
	break;
322
	break;
323
#else
323
#else
324
    case SQL_TIMESTAMP:
324
    case SQL_TIMESTAMP:
325
	var->sqldata = CS  store_get(sizeof(ISC_TIMESTAMP), FALSE);
325
	var->sqldata = CS  store_get(sizeof(ISC_TIMESTAMP), GET_UNTAINTED);
326
	break;
326
	break;
327
    case SQL_TYPE_DATE:
327
    case SQL_TYPE_DATE:
328
	var->sqldata = CS  store_get(sizeof(ISC_DATE), FALSE);
328
	var->sqldata = CS  store_get(sizeof(ISC_DATE), GET_UNTAINTED);
329
	break;
329
	break;
330
    case SQL_TYPE_TIME:
330
    case SQL_TYPE_TIME:
331
	var->sqldata = CS  store_get(sizeof(ISC_TIME), FALSE);
331
	var->sqldata = CS  store_get(sizeof(ISC_TIME), GET_UNTAINTED);
332
	break;
332
	break;
333
  #endif
333
  #endif
334
    }
334
    }
335
  if (var->sqltype & 1)
335
  if (var->sqltype & 1)
336
    var->sqlind = (short *) store_get(sizeof(short), FALSE);
336
    var->sqlind = (short *) store_get(sizeof(short), GET_UNTAINTED);
337
  }
337
  }
338
338
339
/* finally, we're ready to execute the statement */
339
/* finally, we're ready to execute the statement */
Lines 457-470 Link Here
457
int sep = 0;
457
int sep = 0;
458
uschar *server;
458
uschar *server;
459
uschar *list = ibase_servers;
459
uschar *list = ibase_servers;
460
uschar buffer[512];
461
462
/* Keep picky compilers happy */
463
do_cache = do_cache;
464
460
465
DEBUG(D_lookup) debug_printf_indent("Interbase query: %s\n", query);
461
DEBUG(D_lookup) debug_printf_indent("Interbase query: %s\n", query);
466
462
467
while ((server = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
463
while ((server = string_nextinlist(&list, &sep, NULL, 0)))
468
  {
464
  {
469
  BOOL defer_break = FALSE;
465
  BOOL defer_break = FALSE;
470
  int rc = perform_ibase_search(query, server, result, errmsg, &defer_break);
466
  int rc = perform_ibase_search(query, server, result, errmsg, &defer_break);
Lines 496-546 Link Here
496
Arguments:
492
Arguments:
497
  s          the string to be quoted
493
  s          the string to be quoted
498
  opt        additional option text or NULL if none
494
  opt        additional option text or NULL if none
495
  idx	     lookup type index
499
496
500
Returns:     the processed string or NULL for a bad option
497
Returns:     the processed string or NULL for a bad option
501
*/
498
*/
502
499
503
static uschar *ibase_quote(uschar * s, uschar * opt)
500
static uschar *
501
ibase_quote(uschar * s, uschar * opt, unsigned idx)
504
{
502
{
505
    register int c;
503
int c;
506
    int count = 0;
504
int count = 0;
507
    uschar *t = s;
505
uschar * t = s, * quoted;
508
    uschar *quoted;
506
509
507
if (opt)
510
    if (opt != NULL)
508
  return NULL;            /* No options recognized */
511
        return NULL;            /* No options recognized */
509
512
510
while ((c = *t++))
513
    while ((c = *t++) != 0)
511
  if (c == '\'') count++;
514
        if (Ustrchr("\n\t\r\b\'\"\\", c) != NULL)
512
515
            count++;
513
t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx);
516
514
517
    if (count == 0)
515
while ((c = *s++))
518
        return s;
516
  if (c == '\'') { *t++ = '\''; *t++ = '\''; }
519
    t = quoted = store_get(Ustrlen(s) + count + 1, FALSE);
517
  else *t++ = c;
520
521
    while ((c = *s++) != 0) {
522
        if (Ustrchr("'", c) != NULL) {
523
            *t++ = '\'';
524
            *t++ = '\'';
525
/*    switch(c)
526
      {
527
      case '\n': *t++ = 'n';
528
      break;
529
      case '\t': *t++ = 't';
530
      break;
531
      case '\r': *t++ = 'r';
532
      break;
533
      case '\b': *t++ = 'b';
534
      break;
535
      default:   *t++ = c;
536
      break;
537
      }*/
538
        } else
539
            *t++ = c;
540
    }
541
518
542
    *t = 0;
519
*t = 0;
543
    return quoted;
520
return quoted;
544
}
521
}
545
522
546
523
Lines 552-563 Link Here
552
529
553
#include "../version.h"
530
#include "../version.h"
554
531
555
void
532
gstring *
556
ibase_version_report(FILE *f)
533
ibase_version_report(gstring * g)
557
{
534
{
558
#ifdef DYNLOOKUP
535
#ifdef DYNLOOKUP
559
fprintf(f, "Library version: ibase: Exim version %s\n", EXIM_VERSION_STR);
536
g = string_fmt_append(g, "Library version: ibase: Exim version %s\n", EXIM_VERSION_STR));
560
#endif
537
#endif
538
return g;
561
}
539
}
562
540
563
541
(-)exim.orig/src/lookups/json.c (-14 / +7 lines)
Lines 2-8 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) Jeremy Harris 2019-2020 */
5
/* Copyright (c) The Exim Maintainers 2021 - 2022 */
6
/* Copyright (c) Jeremy Harris 2019 - 2020 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
8
#include "../exim.h"
9
#include "../exim.h"
Lines 23-29 Link Here
23
static void *
24
static void *
24
json_malloc(size_t nbytes)
25
json_malloc(size_t nbytes)
25
{
26
{
26
void * p = store_get((int)nbytes, FALSE);
27
void * p = store_get((int)nbytes, GET_UNTAINTED);
27
/* debug_printf("%s %d: %p\n", __FUNCTION__, (int)nbytes, p); */
28
/* debug_printf("%s %d: %p\n", __FUNCTION__, (int)nbytes, p); */
28
return p;
29
return p;
29
}
30
}
Lines 47-58 Link Here
47
json_set_alloc_funcs(json_malloc, json_free);
48
json_set_alloc_funcs(json_malloc, json_free);
48
49
49
if (!(f = Ufopen(filename, "rb")))
50
if (!(f = Ufopen(filename, "rb")))
50
  {
51
  *errmsg = string_open_failed("%s for json search", filename);
51
  int save_errno = errno;
52
  *errmsg = string_open_failed(errno, "%s for json search", filename);
53
  errno = save_errno;
54
  return NULL;
55
  }
56
return f;
52
return f;
57
}
53
}
58
54
Lines 89-97 Link Here
89
uschar * key;
85
uschar * key;
90
int sep = 0;
86
int sep = 0;
91
87
92
length = length;	/* Keep picky compilers happy */
93
do_cache = do_cache;	/* Keep picky compilers happy */
94
95
rewind(f);
88
rewind(f);
96
if (!(j = json_loadf(f, 0, &jerr)))
89
if (!(j = json_loadf(f, 0, &jerr)))
97
  {
90
  {
Lines 165-174 Link Here
165
158
166
#include "../version.h"
159
#include "../version.h"
167
160
168
void
161
gstring *
169
json_version_report(FILE *f)
162
json_version_report(gstring * g)
170
{
163
{
171
fprintf(f, "Library version: json: Jansonn version %s\n", JANSSON_VERSION);
164
return string_fmt_append(g, "Library version: json: Jansonn version %s\n", JANSSON_VERSION);
172
}
165
}
173
166
174
167
(-)exim.orig/src/lookups/ldap.c (-40 / +28 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Many thanks to Stuart Lynne for contributing the original code for this
9
/* Many thanks to Stuart Lynne for contributing the original code for this
Lines 496-502 Link Here
496
496
497
  /* Now add this connection to the chain of cached connections */
497
  /* Now add this connection to the chain of cached connections */
498
498
499
  lcp = store_get(sizeof(LDAP_CONNECTION), FALSE);
499
  lcp = store_get(sizeof(LDAP_CONNECTION), GET_UNTAINTED);
500
  lcp->host = host ? string_copy(host) : NULL;
500
  lcp->host = host ? string_copy(host) : NULL;
501
  lcp->bound = FALSE;
501
  lcp->bound = FALSE;
502
  lcp->user = NULL;
502
  lcp->user = NULL;
Lines 1091-1097 Link Here
1091
uschar *user = NULL;
1091
uschar *user = NULL;
1092
uschar *password = NULL;
1092
uschar *password = NULL;
1093
uschar *local_servers = NULL;
1093
uschar *local_servers = NULL;
1094
uschar *server;
1095
const uschar *list;
1094
const uschar *list;
1096
1095
1097
while (isspace(*url)) url++;
1096
while (isspace(*url)) url++;
Lines 1250-1262 Link Here
1250
    &defer_break, user, password, sizelimit, timelimit, tcplimit, dereference,
1249
    &defer_break, user, password, sizelimit, timelimit, tcplimit, dereference,
1251
    referrals);
1250
    referrals);
1252
1251
1253
/* Loop through the default servers until OK or FAIL. Use local_servers list
1252
/* Loop through the servers until OK or FAIL. Use local_servers list
1254
 * if defined in the lookup, otherwise use the global default list */
1253
if defined in the lookup, otherwise use the global default list */
1255
list = !local_servers ? eldap_default_servers : local_servers;
1254
1256
while ((server = string_nextinlist(&list, &sep, NULL, 0)))
1255
list = local_servers ? local_servers : eldap_default_servers;
1256
for (uschar * server; server = string_nextinlist(&list, &sep, NULL, 0); )
1257
  {
1257
  {
1258
  int rc;
1258
  int rc, port = 0;
1259
  int port = 0;
1260
  uschar *colon = Ustrchr(server, ':');
1259
  uschar *colon = Ustrchr(server, ':');
1261
  if (colon)
1260
  if (colon)
1262
    {
1261
    {
Lines 1287-1294 Link Here
1287
  int length, uschar ** result, uschar ** errmsg, uint * do_cache,
1286
  int length, uschar ** result, uschar ** errmsg, uint * do_cache,
1288
  const uschar * opts)
1287
  const uschar * opts)
1289
{
1288
{
1290
/* Keep picky compilers happy */
1291
do_cache = do_cache;
1292
return(control_ldap_search(ldap_url, SEARCH_LDAP_SINGLE, result, errmsg));
1289
return(control_ldap_search(ldap_url, SEARCH_LDAP_SINGLE, result, errmsg));
1293
}
1290
}
1294
1291
Lines 1297-1304 Link Here
1297
  int length, uschar ** result, uschar ** errmsg, uint * do_cache,
1294
  int length, uschar ** result, uschar ** errmsg, uint * do_cache,
1298
  const uschar * opts)
1295
  const uschar * opts)
1299
{
1296
{
1300
/* Keep picky compilers happy */
1301
do_cache = do_cache;
1302
return(control_ldap_search(ldap_url, SEARCH_LDAP_MULTIPLE, result, errmsg));
1297
return(control_ldap_search(ldap_url, SEARCH_LDAP_MULTIPLE, result, errmsg));
1303
}
1298
}
1304
1299
Lines 1307-1314 Link Here
1307
  int length, uschar ** result, uschar ** errmsg, uint * do_cache,
1302
  int length, uschar ** result, uschar ** errmsg, uint * do_cache,
1308
  const uschar * opts)
1303
  const uschar * opts)
1309
{
1304
{
1310
/* Keep picky compilers happy */
1311
do_cache = do_cache;
1312
return(control_ldap_search(ldap_url, SEARCH_LDAP_DN, result, errmsg));
1305
return(control_ldap_search(ldap_url, SEARCH_LDAP_DN, result, errmsg));
1313
}
1306
}
1314
1307
Lines 1316-1323 Link Here
1316
eldapauth_find(void * handle, const uschar * filename, const uschar * ldap_url,
1309
eldapauth_find(void * handle, const uschar * filename, const uschar * ldap_url,
1317
  int length, uschar ** result, uschar ** errmsg, uint * do_cache)
1310
  int length, uschar ** result, uschar ** errmsg, uint * do_cache)
1318
{
1311
{
1319
/* Keep picky compilers happy */
1320
do_cache = do_cache;
1321
return(control_ldap_search(ldap_url, SEARCH_LDAP_AUTH, result, errmsg));
1312
return(control_ldap_search(ldap_url, SEARCH_LDAP_AUTH, result, errmsg));
1322
}
1313
}
1323
1314
Lines 1347-1362 Link Here
1347
static void
1338
static void
1348
eldap_tidy(void)
1339
eldap_tidy(void)
1349
{
1340
{
1350
LDAP_CONNECTION *lcp = NULL;
1351
eldap_dn = NULL;
1341
eldap_dn = NULL;
1352
1342
1353
while ((lcp = ldap_connections) != NULL)
1343
for (LDAP_CONNECTION *lcp; lcp = ldap_connections; ldap_connections = lcp->next)
1354
  {
1344
  {
1355
  DEBUG(D_lookup) debug_printf_indent("unbind LDAP connection to %s:%d\n", lcp->host,
1345
  DEBUG(D_lookup) debug_printf_indent("unbind LDAP connection to %s:%d\n",
1356
    lcp->port);
1346
    lcp->host, lcp->port);
1357
  if(lcp->bound == TRUE)
1347
  if(lcp->bound) ldap_unbind(lcp->ld);
1358
    ldap_unbind(lcp->ld);
1359
  ldap_connections = lcp->next;
1360
  }
1348
  }
1361
}
1349
}
1362
1350
Lines 1417-1422 Link Here
1417
  s          the string to be quoted
1405
  s          the string to be quoted
1418
  opt        additional option text or NULL if none
1406
  opt        additional option text or NULL if none
1419
             only "dn" is recognized
1407
             only "dn" is recognized
1408
  idx	     lookup type index
1420
1409
1421
Returns:     the processed string or NULL for a bad option
1410
Returns:     the processed string or NULL for a bad option
1422
*/
1411
*/
Lines 1442-1459 Link Here
1442
1431
1443
1432
1444
static uschar *
1433
static uschar *
1445
eldap_quote(uschar *s, uschar *opt)
1434
eldap_quote(uschar * s, uschar * opt, unsigned idx)
1446
{
1435
{
1447
register int c;
1436
int c, count = 0, len = 0;
1448
int count = 0;
1449
int len = 0;
1450
BOOL dn = FALSE;
1437
BOOL dn = FALSE;
1451
uschar *t = s;
1438
uschar * t = s, * quoted;
1452
uschar *quoted;
1453
1439
1454
/* Test for a DN quotation. */
1440
/* Test for a DN quotation. */
1455
1441
1456
if (opt != NULL)
1442
if (opt)
1457
  {
1443
  {
1458
  if (Ustrcmp(opt, "dn") != 0) return NULL;    /* No others recognized */
1444
  if (Ustrcmp(opt, "dn") != 0) return NULL;    /* No others recognized */
1459
  dn = TRUE;
1445
  dn = TRUE;
Lines 1466-1489 Link Here
1466
possibly escaped character. The really fast way would be just to test for
1452
possibly escaped character. The really fast way would be just to test for
1467
non-alphanumerics, but it is probably better to spot a few others that are
1453
non-alphanumerics, but it is probably better to spot a few others that are
1468
never escaped, because if there are no specials at all, we can avoid copying
1454
never escaped, because if there are no specials at all, we can avoid copying
1469
the string. */
1455
the string.
1456
XXX No longer true; we always copy, to support quoted-enforcement */
1470
1457
1471
while ((c = *t++) != 0)
1458
while ((c = *t++))
1472
  {
1459
  {
1473
  len++;
1460
  len++;
1474
  if (!isalnum(c) && Ustrchr(ALWAYS_LITERAL, c) == NULL) count += 5;
1461
  if (!isalnum(c) && Ustrchr(ALWAYS_LITERAL, c) == NULL) count += 5;
1475
  }
1462
  }
1476
if (count == 0) return s;
1463
/*if (count == 0) return s;*/
1477
1464
1478
/* Get sufficient store to hold the quoted string */
1465
/* Get sufficient store to hold the quoted string */
1479
1466
1480
t = quoted = store_get(len + count + 1, is_tainted(s));
1467
t = quoted = store_get_quoted(len + count + 1, s, idx);
1481
1468
1482
/* Handle plain quote_ldap */
1469
/* Handle plain quote_ldap */
1483
1470
1484
if (!dn)
1471
if (!dn)
1485
  {
1472
  {
1486
  while ((c = *s++) != 0)
1473
  while ((c = *s++))
1487
    {
1474
    {
1488
    if (!isalnum(c))
1475
    if (!isalnum(c))
1489
      {
1476
      {
Lines 1508-1514 Link Here
1508
1495
1509
else
1496
else
1510
  {
1497
  {
1511
  uschar *ss = s + len;
1498
  uschar * ss = s + len;
1512
1499
1513
  /* Find the last char before any trailing spaces */
1500
  /* Find the last char before any trailing spaces */
1514
1501
Lines 1570-1581 Link Here
1570
1557
1571
#include "../version.h"
1558
#include "../version.h"
1572
1559
1573
void
1560
gstring *
1574
ldap_version_report(FILE *f)
1561
ldap_version_report(gstring * g)
1575
{
1562
{
1576
#ifdef DYNLOOKUP
1563
#ifdef DYNLOOKUP
1577
fprintf(f, "Library version: LDAP: Exim version %s\n", EXIM_VERSION_STR);
1564
g = string_fmt_append(g, "Library version: LDAP: Exim version %s\n", EXIM_VERSION_STR);
1578
#endif
1565
#endif
1566
return g;
1579
}
1567
}
1580
1568
1581
1569
(-)exim.orig/src/lookups/lf_sqlperform.c (-1 / +1 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
(-)exim.orig/src/lookups/lmdb.c (-9 / +10 lines)
Lines 2-14 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 2016 - 2018 */
6
/* Copyright (c) University of Cambridge 2016 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#include "../exim.h"
9
#include "../exim.h"
10
10
11
#ifdef EXPERIMENTAL_LMDB
11
#ifdef LOOKUP_LMDB
12
12
13
#include <lmdb.h>
13
#include <lmdb.h>
14
14
Lines 31-37 Link Here
31
int ret, save_errno;
31
int ret, save_errno;
32
const uschar * errstr;
32
const uschar * errstr;
33
33
34
lmdb_p = store_get(sizeof(Lmdbstrct), FALSE);
34
lmdb_p = store_get(sizeof(Lmdbstrct), GET_UNTAINTED);
35
lmdb_p->txn = NULL;
35
lmdb_p->txn = NULL;
36
36
37
if ((ret = mdb_env_create(&db_env)))
37
if ((ret = mdb_env_create(&db_env)))
Lines 129-142 Link Here
129
129
130
#include "../version.h"
130
#include "../version.h"
131
131
132
void
132
gstring *
133
lmdb_version_report(FILE * f)
133
lmdb_version_report(gstring * g)
134
{
134
{
135
fprintf(f, "Library version: LMDB: Compile: %d.%d.%d\n",
135
g = string_fmt_append(g, "Library version: LMDB: Compile: %d.%d.%d\n",
136
    MDB_VERSION_MAJOR, MDB_VERSION_MINOR, MDB_VERSION_PATCH);
136
			  MDB_VERSION_MAJOR, MDB_VERSION_MINOR, MDB_VERSION_PATCH);
137
#ifdef DYNLOOKUP
137
#ifdef DYNLOOKUP
138
fprintf(f, "                        Exim version %s\n", EXIM_VERSION_STR);
138
g = string_fmt_append(g, "                        Exim version %s\n", EXIM_VERSION_STR);
139
#endif
139
#endif
140
return g;
140
}
141
}
141
142
142
static lookup_info lmdb_lookup_info = {
143
static lookup_info lmdb_lookup_info = {
Lines 158-161 Link Here
158
static lookup_info *_lookup_list[] = { &lmdb_lookup_info };
159
static lookup_info *_lookup_list[] = { &lmdb_lookup_info };
159
lookup_module_info lmdb_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 };
160
lookup_module_info lmdb_lookup_module_info = { LOOKUP_MODULE_INFO_MAGIC, _lookup_list, 1 };
160
161
161
#endif /* EXPERIMENTAL_LMDB */
162
#endif /* LOOKUP_LMDB */
(-)exim.orig/src/lookups/lsearch.c (-69 / +69 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#include "../exim.h"
9
#include "../exim.h"
Lines 29-42 Link Here
29
static void *
29
static void *
30
lsearch_open(const uschar * filename, uschar ** errmsg)
30
lsearch_open(const uschar * filename, uschar ** errmsg)
31
{
31
{
32
FILE *f = Ufopen(filename, "rb");
32
FILE * f = Ufopen(filename, "rb");
33
if (f == NULL)
33
if (!f)
34
  {
34
  *errmsg = string_open_failed("%s for linear search", filename);
35
  int save_errno = errno;
36
  *errmsg = string_open_failed(errno, "%s for linear search", filename);
37
  errno = save_errno;
38
  return NULL;
39
  }
40
return f;
35
return f;
41
}
36
}
42
37
Lines 74-105 Link Here
74
static int
69
static int
75
internal_lsearch_find(void * handle, const uschar * filename,
70
internal_lsearch_find(void * handle, const uschar * filename,
76
  const uschar * keystring, int length, uschar ** result, uschar ** errmsg,
71
  const uschar * keystring, int length, uschar ** result, uschar ** errmsg,
77
 int type)
72
  int type, const uschar * opts)
78
{
73
{
79
FILE *f = (FILE *)handle;
74
FILE *f = handle;
80
BOOL last_was_eol = TRUE;
75
BOOL ret_full = FALSE;
81
BOOL this_is_eol = TRUE;
82
int old_pool = store_pool;
76
int old_pool = store_pool;
83
rmark reset_point = NULL;
77
rmark reset_point = NULL;
84
uschar buffer[4096];
78
uschar buffer[4096];
85
79
80
if (opts)
81
  {
82
  int sep = ',';
83
  uschar * ele;
84
85
  while ((ele = string_nextinlist(&opts, &sep, NULL, 0)))
86
    if (Ustrcmp(ele, "ret=full") == 0)
87
      { ret_full = TRUE; break; }
88
  }
89
86
/* Wildcard searches may use up some store, because of expansions. We don't
90
/* Wildcard searches may use up some store, because of expansions. We don't
87
want them to fill up our search store. What we do is set the pool to the main
91
want them to fill up our search store. What we do is set the pool to the main
88
pool and get a point to reset to later. Wildcard searches could also issue
92
pool and get a point to reset to later. Wildcard searches could also issue
89
lookups, but internal_search_find will take care of that, and the cache will be
93
lookups, but internal_search_find will take care of that, and the cache will be
90
safely stored in the search pool again. */
94
safely stored in the search pool again. */
91
95
92
if(type == LSEARCH_WILD || type == LSEARCH_NWILD)
96
if (type == LSEARCH_WILD || type == LSEARCH_NWILD)
93
  {
97
  {
94
  store_pool = POOL_MAIN;
98
  store_pool = POOL_MAIN;
95
  reset_point = store_mark();
99
  reset_point = store_mark();
96
  }
100
  }
97
101
98
filename = filename;  /* Keep picky compilers happy */
99
errmsg = errmsg;
100
101
rewind(f);
102
rewind(f);
102
for (last_was_eol = TRUE;
103
for (BOOL this_is_eol, last_was_eol = TRUE;
103
     Ufgets(buffer, sizeof(buffer), f) != NULL;
104
     Ufgets(buffer, sizeof(buffer), f) != NULL;
104
     last_was_eol = this_is_eol)
105
     last_was_eol = this_is_eol)
105
  {
106
  {
Lines 145-165 Link Here
145
  if (*s == '\"')
146
  if (*s == '\"')
146
    {
147
    {
147
    uschar *t = s++;
148
    uschar *t = s++;
148
    while (*s != 0 && *s != '\"')
149
    while (*s && *s != '\"')
149
      {
150
      {
150
      if (*s == '\\') *t++ = string_interpret_escape(CUSS &s);
151
      *t++ = *s == '\\' ? string_interpret_escape(CUSS &s) : *s;
151
        else *t++ = *s;
152
      s++;
152
      s++;
153
      }
153
      }
154
    if (*s != 0) s++;               /* Past terminating " */
155
    linekeylength = t - buffer;
154
    linekeylength = t - buffer;
155
    if (*s) s++;			/* Past terminating " */
156
    if (ret_full)
157
      memmove(t, s, Ustrlen(s)+1);	/* copy the rest of line also */
156
    }
158
    }
157
159
158
  /* Otherwise it is terminated by a colon or white space */
160
  /* Otherwise it is terminated by a colon or white space */
159
161
160
  else
162
  else
161
    {
163
    {
162
    while (*s != 0 && *s != ':' && !isspace(*s)) s++;
164
    while (*s && *s != ':' && !isspace(*s)) s++;
163
    linekeylength = s - buffer;
165
    linekeylength = s - buffer;
164
    }
166
    }
165
167
Lines 170-178 Link Here
170
    /* A plain lsearch treats each key as a literal */
172
    /* A plain lsearch treats each key as a literal */
171
173
172
    case LSEARCH_PLAIN:
174
    case LSEARCH_PLAIN:
173
    if (linekeylength != length || strncmpic(buffer, keystring, length) != 0)
175
      if (linekeylength != length || strncmpic(buffer, keystring, length) != 0)
174
      continue;
176
	continue;
175
    break;      /* Key matched */
177
      break;      /* Key matched */
176
178
177
    /* A wild lsearch treats each key as a possible wildcarded string; no
179
    /* A wild lsearch treats each key as a possible wildcarded string; no
178
    expansion is done for nwildlsearch. */
180
    expansion is done for nwildlsearch. */
Lines 189-195 Link Here
189
        UCHAR_MAX+1,              /* Single-item list */
191
        UCHAR_MAX+1,              /* Single-item list */
190
        NULL,                     /* No anchor */
192
        NULL,                     /* No anchor */
191
        NULL,                     /* No caching */
193
        NULL,                     /* No caching */
192
        MCL_STRING + ((type == LSEARCH_WILD)? 0:MCL_NOEXPAND),
194
        MCL_STRING + (type == LSEARCH_WILD ? 0 : MCL_NOEXPAND),
193
        TRUE,                     /* Caseless */
195
        TRUE,                     /* Caseless */
194
        NULL);
196
        NULL);
195
      buffer[linekeylength] = save;
197
      buffer[linekeylength] = save;
Lines 197-243 Link Here
197
      if (rc == DEFER) return DEFER;
199
      if (rc == DEFER) return DEFER;
198
      }
200
      }
199
201
200
    /* The key has matched. If the search involved a regular expression, it
202
      /* The key has matched. If the search involved a regular expression, it
201
    might have caused numerical variables to be set. However, their values will
203
      might have caused numerical variables to be set. However, their values will
202
    be in the wrong storage pool for external use. Copying them to the standard
204
      be in the wrong storage pool for external use. Copying them to the standard
203
    pool is not feasible because of the caching of lookup results - a repeated
205
      pool is not feasible because of the caching of lookup results - a repeated
204
    lookup will not match the regular expression again. Therefore, we flatten
206
      lookup will not match the regular expression again. Therefore, we drop
205
    all numeric variables at this point. */
207
      all numeric variables at this point. */
206
208
207
    expand_nmax = -1;
209
      expand_nmax = -1;
208
    break;
210
      break;
209
211
210
    /* Compare an ip address against a list of network/ip addresses. We have to
212
    /* Compare an ip address against a list of network/ip addresses. We have to
211
    allow for the "*" case specially. */
213
    allow for the "*" case specially. */
212
214
213
    case LSEARCH_IP:
215
    case LSEARCH_IP:
214
    if (linekeylength == 1 && buffer[0] == '*')
216
      if (linekeylength == 1 && buffer[0] == '*')
215
      {
217
	{
216
      if (length != 1 || keystring[0] != '*') continue;
218
	if (length != 1 || keystring[0] != '*') continue;
217
      }
219
	}
218
    else if (length == 1 && keystring[0] == '*') continue;
220
      else if (length == 1 && keystring[0] == '*') continue;
219
    else
221
      else
220
      {
222
	{
221
      int maskoffset;
223
	int maskoffset;
222
      int save = buffer[linekeylength];
224
	int save = buffer[linekeylength];
223
      buffer[linekeylength] = 0;
225
	buffer[linekeylength] = 0;
224
      if (string_is_ip_address(buffer, &maskoffset) == 0 ||
226
	if (string_is_ip_address(buffer, &maskoffset) == 0 ||
225
          !host_is_in_net(keystring, buffer, maskoffset)) continue;
227
	    !host_is_in_net(keystring, buffer, maskoffset)) continue;
226
      buffer[linekeylength] = save;
228
	buffer[linekeylength] = save;
227
      }
229
	}
228
    break;      /* Key matched */
230
      break;      /* Key matched */
229
    }
231
    }
230
232
231
  /* The key has matched. Skip spaces after the key, and allow an optional
233
  /* The key has matched. Skip spaces after the key, and allow an optional
232
  colon after the spaces. This is an odd specification, but it's for
234
  colon after the spaces. This is an odd specification, but it's for
233
  compatibility. */
235
  compatibility. */
234
236
235
  while (isspace((uschar)*s)) s++;
237
  if (!ret_full)
236
  if (*s == ':')
238
    if (Uskip_whitespace(&s) == ':')
237
    {
239
      {
238
    s++;
240
      s++;
239
    while (isspace((uschar)*s)) s++;
241
      Uskip_whitespace(&s);
240
    }
242
      }
241
243
242
  /* Reset dynamic store, if we need to, and revert to the search pool */
244
  /* Reset dynamic store, if we need to, and revert to the search pool */
243
245
Lines 256-262 Link Here
256
258
257
  this_is_comment = FALSE;
259
  this_is_comment = FALSE;
258
  yield = string_get(100);
260
  yield = string_get(100);
259
  if (*s != 0)
261
  if (ret_full)
262
    yield = string_cat(yield, buffer);
263
  else if (*s)
260
    yield = string_cat(yield, s);
264
    yield = string_cat(yield, s);
261
265
262
  /* Now handle continuations */
266
  /* Now handle continuations */
Lines 324-332 Link Here
324
  int length, uschar ** result, uschar ** errmsg, uint * do_cache,
328
  int length, uschar ** result, uschar ** errmsg, uint * do_cache,
325
  const uschar * opts)
329
  const uschar * opts)
326
{
330
{
327
do_cache = do_cache;  /* Keep picky compilers happy */
328
return internal_lsearch_find(handle, filename, keystring, length, result,
331
return internal_lsearch_find(handle, filename, keystring, length, result,
329
  errmsg, LSEARCH_PLAIN);
332
  errmsg, LSEARCH_PLAIN, opts);
330
}
333
}
331
334
332
335
Lines 342-350 Link Here
342
  int length, uschar ** result, uschar ** errmsg, uint * do_cache,
345
  int length, uschar ** result, uschar ** errmsg, uint * do_cache,
343
  const uschar * opts)
346
  const uschar * opts)
344
{
347
{
345
do_cache = do_cache;  /* Keep picky compilers happy */
346
return internal_lsearch_find(handle, filename, keystring, length, result,
348
return internal_lsearch_find(handle, filename, keystring, length, result,
347
  errmsg, LSEARCH_WILD);
349
  errmsg, LSEARCH_WILD, opts);
348
}
350
}
349
351
350
352
Lines 360-368 Link Here
360
  int length, uschar ** result, uschar ** errmsg, uint * do_cache,
362
  int length, uschar ** result, uschar ** errmsg, uint * do_cache,
361
  const uschar * opts)
363
  const uschar * opts)
362
{
364
{
363
do_cache = do_cache;  /* Keep picky compilers happy */
364
return internal_lsearch_find(handle, filename, keystring, length, result,
365
return internal_lsearch_find(handle, filename, keystring, length, result,
365
  errmsg, LSEARCH_NWILD);
366
  errmsg, LSEARCH_NWILD, opts);
366
}
367
}
367
368
368
369
Lines 379-390 Link Here
379
  int length, uschar ** result, uschar ** errmsg, uint * do_cache,
380
  int length, uschar ** result, uschar ** errmsg, uint * do_cache,
380
  const uschar * opts)
381
  const uschar * opts)
381
{
382
{
382
do_cache = do_cache;  /* Keep picky compilers happy */
383
384
if ((length == 1 && keystring[0] == '*') ||
383
if ((length == 1 && keystring[0] == '*') ||
385
    string_is_ip_address(keystring, NULL) != 0)
384
    string_is_ip_address(keystring, NULL) != 0)
386
  return internal_lsearch_find(handle, filename, keystring, length, result,
385
  return internal_lsearch_find(handle, filename, keystring, length, result,
387
    errmsg, LSEARCH_IP);
386
    errmsg, LSEARCH_IP, opts);
388
387
389
*errmsg = string_sprintf("\"%s\" is not a valid iplsearch key (an IP "
388
*errmsg = string_sprintf("\"%s\" is not a valid iplsearch key (an IP "
390
"address, with optional CIDR mask, is wanted): "
389
"address, with optional CIDR mask, is wanted): "
Lines 417-428 Link Here
417
416
418
#include "../version.h"
417
#include "../version.h"
419
418
420
void
419
gstring *
421
lsearch_version_report(FILE *f)
420
lsearch_version_report(gstring * g)
422
{
421
{
423
#ifdef DYNLOOKUP
422
#ifdef DYNLOOKUP
424
fprintf(f, "Library version: lsearch: Exim version %s\n", EXIM_VERSION_STR);
423
g = string_fmt_append(g, "Library version: lsearch: Exim version %s\n", EXIM_VERSION_STR));
425
#endif
424
#endif
425
return g;
426
}
426
}
427
427
428
428
(-)exim.orig/src/lookups/Makefile (-46 / +48 lines)
Lines 1-6 Link Here
1
# Make file for building Exim's lookup modules.
1
# Make file for building Exim's lookup modules.
2
# This is called from the main make file, after cd'ing
2
# This is called from the main make file, after cd'ing
3
# to the lookups subdirectory.
3
# to the lookups subdirectory.
4
#
5
# Copyright (c) The Exim Maintainers 2021
4
6
5
# nb: at build time, the version of this file used will have had some
7
# nb: at build time, the version of this file used will have had some
6
#     extra variable definitions and prepended to it and module build rules
8
#     extra variable definitions and prepended to it and module build rules
Lines 24-74 Link Here
24
.c.so:;          @echo "$(CC) -shared $*.c"
26
.c.so:;          @echo "$(CC) -shared $*.c"
25
		 $(FE)$(CC) $(LOOKUP_$*_INCLUDE) $(LOOKUP_$*_LIBS) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) $(DLFLAGS) $*.c -o $@
27
		 $(FE)$(CC) $(LOOKUP_$*_INCLUDE) $(LOOKUP_$*_LIBS) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) $(DLFLAGS) $*.c -o $@
26
28
27
lf_check_file.o: $(PHDRS) lf_check_file.c  lf_functions.h
29
lf_check_file.o: $(HDRS) lf_check_file.c  lf_functions.h
28
lf_quote.o:      $(PHDRS) lf_quote.c       lf_functions.h
30
lf_quote.o:      $(HDRS) lf_quote.c       lf_functions.h
29
lf_sqlperform.o: $(PHDRS) lf_sqlperform.c  lf_functions.h
31
lf_sqlperform.o: $(HDRS) lf_sqlperform.c  lf_functions.h
30
32
31
cdb.o:           $(PHDRS) cdb.c
33
cdb.o:           $(HDRS) cdb.c
32
dbmdb.o:         $(PHDRS) dbmdb.c
34
dbmdb.o:         $(HDRS) dbmdb.c
33
dnsdb.o:         $(PHDRS) dnsdb.c
35
dnsdb.o:         $(HDRS) dnsdb.c
34
dsearch.o:       $(PHDRS) dsearch.c
36
dsearch.o:       $(HDRS) dsearch.c
35
ibase.o:         $(PHDRS) ibase.c
37
ibase.o:         $(HDRS) ibase.c
36
ldap.o:          $(PHDRS) ldap.c
38
ldap.o:          $(HDRS) ldap.c
37
lmdb.o:          $(PHDRS) lmdb.c
39
lmdb.o:          $(HDRS) lmdb.c
38
json.o:          $(PHDRS) json.c
40
json.o:          $(HDRS) json.c
39
lsearch.o:       $(PHDRS) lsearch.c
41
lsearch.o:       $(HDRS) lsearch.c
40
mysql.o:         $(PHDRS) mysql.c
42
mysql.o:         $(HDRS) mysql.c
41
nis.o:           $(PHDRS) nis.c
43
nis.o:           $(HDRS) nis.c
42
nisplus.o:       $(PHDRS) nisplus.c
44
nisplus.o:       $(HDRS) nisplus.c
43
oracle.o:        $(PHDRS) oracle.c
45
oracle.o:        $(HDRS) oracle.c
44
passwd.o:        $(PHDRS) passwd.c
46
passwd.o:        $(HDRS) passwd.c
45
pgsql.o:         $(PHDRS) pgsql.c
47
pgsql.o:         $(HDRS) pgsql.c
46
readsock.o:      $(PHDRS) readsock.c
48
readsock.o:      $(HDRS) readsock.c
47
redis.o:         $(PHDRS) redis.c
49
redis.o:         $(HDRS) redis.c
48
spf.o:           $(PHDRS) spf.c
50
spf.o:           $(HDRS) spf.c
49
sqlite.o:        $(PHDRS) sqlite.c
51
sqlite.o:        $(HDRS) sqlite.c
50
testdb.o:        $(PHDRS) testdb.c
52
testdb.o:        $(HDRS) testdb.c
51
whoson.o:        $(PHDRS) whoson.c
53
whoson.o:        $(HDRS) whoson.c
52
54
53
cdb.so:           $(PHDRS) cdb.c
55
cdb.so:           $(HDRS) cdb.c
54
dbmdb.so:         $(PHDRS) dbmdb.c
56
dbmdb.so:         $(HDRS) dbmdb.c
55
dnsdb.so:         $(PHDRS) dnsdb.c
57
dnsdb.so:         $(HDRS) dnsdb.c
56
dsearch.so:       $(PHDRS) dsearch.c
58
dsearch.so:       $(HDRS) dsearch.c
57
ibase.so:         $(PHDRS) ibase.c
59
ibase.so:         $(HDRS) ibase.c
58
json.so:          $(PHDRS) json.c
60
json.so:          $(HDRS) json.c
59
ldap.so:          $(PHDRS) ldap.c
61
ldap.so:          $(HDRS) ldap.c
60
lmdb.so:          $(PHDRS) lmdb.c
62
lmdb.so:          $(HDRS) lmdb.c
61
lsearch.so:       $(PHDRS) lsearch.c
63
lsearch.so:       $(HDRS) lsearch.c
62
mysql.so:         $(PHDRS) mysql.c
64
mysql.so:         $(HDRS) mysql.c
63
nis.so:           $(PHDRS) nis.c
65
nis.so:           $(HDRS) nis.c
64
nisplus.so:       $(PHDRS) nisplus.c
66
nisplus.so:       $(HDRS) nisplus.c
65
oracle.so:        $(PHDRS) oracle.c
67
oracle.so:        $(HDRS) oracle.c
66
passwd.so:        $(PHDRS) passwd.c
68
passwd.so:        $(HDRS) passwd.c
67
pgsql.so:         $(PHDRS) pgsql.c
69
pgsql.so:         $(HDRS) pgsql.c
68
redis.so:         $(PHDRS) redis.c
70
redis.so:         $(HDRS) redis.c
69
spf.so:           $(PHDRS) spf.c
71
spf.so:           $(HDRS) spf.c
70
sqlite.so:        $(PHDRS) sqlite.c
72
sqlite.so:        $(HDRS) sqlite.c
71
testdb.so:        $(PHDRS) testdb.c
73
testdb.so:        $(HDRS) testdb.c
72
whoson.so:        $(PHDRS) whoson.c
74
whoson.so:        $(HDRS) whoson.c
73
75
74
# End
76
# End
(-)exim.orig/src/lookups/mysql.c (-31 / +32 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Thanks to Paul Kelly for contributing the original code for these
9
/* Thanks to Paul Kelly for contributing the original code for these
Lines 231-237 Link Here
231
231
232
  /* Get store for a new handle, initialize it, and connect to the server */
232
  /* Get store for a new handle, initialize it, and connect to the server */
233
233
234
  mysql_handle = store_get(sizeof(MYSQL), FALSE);
234
  mysql_handle = store_get(sizeof(MYSQL), GET_UNTAINTED);
235
  mysql_init(mysql_handle);
235
  mysql_init(mysql_handle);
236
  mysql_options(mysql_handle, MYSQL_READ_DEFAULT_GROUP, CS group);
236
  mysql_options(mysql_handle, MYSQL_READ_DEFAULT_GROUP, CS group);
237
  if (mysql_real_connect(mysql_handle,
237
  if (mysql_real_connect(mysql_handle,
Lines 247-253 Link Here
247
247
248
  /* Add the connection to the cache */
248
  /* Add the connection to the cache */
249
249
250
  cn = store_get(sizeof(mysql_connection), FALSE);
250
  cn = store_get(sizeof(mysql_connection), GET_UNTAINTED);
251
  cn->server = server_copy;
251
  cn->server = server_copy;
252
  cn->handle = mysql_handle;
252
  cn->handle = mysql_handle;
253
  cn->next = mysql_connections;
253
  cn->next = mysql_connections;
Lines 286-292 Link Here
286
    {
286
    {
287
    DEBUG(D_lookup) debug_printf_indent("MYSQL: query was not one that returns data\n");
287
    DEBUG(D_lookup) debug_printf_indent("MYSQL: query was not one that returns data\n");
288
    result = string_cat(result,
288
    result = string_cat(result,
289
	       string_sprintf("%d", mysql_affected_rows(mysql_handle)));
289
	       string_sprintf("%lld", mysql_affected_rows(mysql_handle)));
290
    *do_cache = 0;
290
    *do_cache = 0;
291
    goto MYSQL_EXIT;
291
    goto MYSQL_EXIT;
292
    }
292
    }
Lines 308-314 Link Here
308
308
309
while ((mysql_row_data = mysql_fetch_row(mysql_result)))
309
while ((mysql_row_data = mysql_fetch_row(mysql_result)))
310
  {
310
  {
311
  unsigned long *lengths = mysql_fetch_lengths(mysql_result);
311
  unsigned long * lengths = mysql_fetch_lengths(mysql_result);
312
312
313
  if (result)
313
  if (result)
314
    result = string_catn(result, US"\n", 1);
314
    result = string_catn(result, US"\n", 1);
Lines 319-325 Link Here
319
			result);
319
			result);
320
320
321
  else if (mysql_row_data[0] != NULL)    /* NULL value yields nothing */
321
  else if (mysql_row_data[0] != NULL)    /* NULL value yields nothing */
322
      result = string_catn(result, US mysql_row_data[0], lengths[0]);
322
      result = lengths[0] == 0 && !result
323
	? string_get(1)		/* for 0-len string result ensure non-null gstring */
324
        : string_catn(result, US mysql_row_data[0], lengths[0]);
323
  }
325
  }
324
326
325
/* more results? -1 = no, >0 = error, 0 = yes (keep looping)
327
/* more results? -1 = no, >0 = error, 0 = yes (keep looping)
Lines 411-453 Link Here
411
Arguments:
413
Arguments:
412
  s          the string to be quoted
414
  s          the string to be quoted
413
  opt        additional option text or NULL if none
415
  opt        additional option text or NULL if none
416
  idx	     lookup type index
414
417
415
Returns:     the processed string or NULL for a bad option
418
Returns:     the processed string or NULL for a bad option
416
*/
419
*/
417
420
418
static uschar *
421
static uschar *
419
mysql_quote(uschar *s, uschar *opt)
422
mysql_quote(uschar * s, uschar * opt, unsigned idx)
420
{
423
{
421
register int c;
424
int c, count = 0;
422
int count = 0;
425
uschar * t = s, * quoted;
423
uschar *t = s;
424
uschar *quoted;
425
426
426
if (opt != NULL) return NULL;     /* No options recognized */
427
if (opt) return NULL;     /* No options recognized */
427
428
428
while ((c = *t++) != 0)
429
while ((c = *t++))
429
  if (Ustrchr("\n\t\r\b\'\"\\", c) != NULL) count++;
430
  if (Ustrchr("\n\t\r\b\'\"\\", c) != NULL) count++;
430
431
431
if (count == 0) return s;
432
/* Old code:  if (count == 0) return s;
432
t = quoted = store_get(Ustrlen(s) + count + 1, is_tainted(s));
433
Now always allocate and copy, to track the quoted status. */
433
434
434
while ((c = *s++) != 0)
435
t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx);
436
437
while ((c = *s++))
435
  {
438
  {
436
  if (Ustrchr("\n\t\r\b\'\"\\", c) != NULL)
439
  if (Ustrchr("\n\t\r\b\'\"\\", c) != NULL)
437
    {
440
    {
438
    *t++ = '\\';
441
    *t++ = '\\';
439
    switch(c)
442
    switch(c)
440
      {
443
      {
441
      case '\n': *t++ = 'n';
444
      case '\n': *t++ = 'n'; break;
442
      break;
445
      case '\t': *t++ = 't'; break;
443
      case '\t': *t++ = 't';
446
      case '\r': *t++ = 'r'; break;
444
      break;
447
      case '\b': *t++ = 'b'; break;
445
      case '\r': *t++ = 'r';
448
      default:   *t++ = c;   break;
446
      break;
447
      case '\b': *t++ = 'b';
448
      break;
449
      default:   *t++ = c;
450
      break;
451
      }
449
      }
452
    }
450
    }
453
  else *t++ = c;
451
  else *t++ = c;
Lines 466-481 Link Here
466
464
467
#include "../version.h"
465
#include "../version.h"
468
466
469
void
467
gstring *
470
mysql_version_report(FILE *f)
468
mysql_version_report(gstring * g)
471
{
469
{
472
fprintf(f, "Library version: MySQL: Compile: %lu %s [%s]\n"
470
g = string_fmt_append(g,
473
           "                        Runtime: %lu %s\n",
471
  "Library version: MySQL: Compile: %lu %s [%s]\n"
472
  "                        Runtime: %lu %s\n",
474
        (long)EXIM_MxSQL_VERSION_ID, EXIM_MxSQL_VERSION_STR, EXIM_MxSQL_BASE_STR,
473
        (long)EXIM_MxSQL_VERSION_ID, EXIM_MxSQL_VERSION_STR, EXIM_MxSQL_BASE_STR,
475
        mysql_get_client_version(), mysql_get_client_info());
474
        mysql_get_client_version(), mysql_get_client_info());
476
#ifdef DYNLOOKUP
475
#ifdef DYNLOOKUP
477
fprintf(f, "                        Exim version %s\n", EXIM_VERSION_STR);
476
g = string_fmt_append(g,
477
  "                        Exim version %s\n", EXIM_VERSION_STR);
478
#endif
478
#endif
479
return g;
479
}
480
}
480
481
481
/* These are the lookup_info blocks for this driver */
482
/* These are the lookup_info blocks for this driver */
(-)exim.orig/src/lookups/nis.c (-4 / +5 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2015 */
6
/* 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. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#include "../exim.h"
9
#include "../exim.h"
Lines 97-108 Link Here
97
97
98
#include "../version.h"
98
#include "../version.h"
99
99
100
void
100
gstring *
101
nis_version_report(FILE *f)
101
nis_version_report(gstring * g)
102
{
102
{
103
#ifdef DYNLOOKUP
103
#ifdef DYNLOOKUP
104
fprintf(f, "Library version: NIS: Exim version %s\n", EXIM_VERSION_STR);
104
g = string_fmt_append(g, "Library version: NIS: Exim version %s\n", EXIM_VERSION_STR);
105
#endif
105
#endif
106
return g;
106
}
107
}
107
108
108
109
(-)exim.orig/src/lookups/nisplus.c (-12 / +12 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#include "../exim.h"
9
#include "../exim.h"
Lines 226-250 Link Here
226
Arguments:
226
Arguments:
227
  s          the string to be quoted
227
  s          the string to be quoted
228
  opt        additional option text or NULL if none
228
  opt        additional option text or NULL if none
229
  idx	     lookup type index
229
230
230
Returns:     the processed string or NULL for a bad option
231
Returns:     the processed string or NULL for a bad option
231
*/
232
*/
232
233
233
static uschar *
234
static uschar *
234
nisplus_quote(uschar *s, uschar *opt)
235
nisplus_quote(uschar * s, uschar * opt, unsigned idx)
235
{
236
{
236
int count = 0;
237
int count = 0;
237
uschar *quoted;
238
uschar * quoted, * t = s;
238
uschar *t = s;
239
239
240
if (opt != NULL) return NULL;    /* No options recognized */
240
if (opt) return NULL;    /* No options recognized */
241
241
242
while (*t != 0) if (*t++ == '\"') count++;
242
while (*t) if (*t++ == '\"') count++;
243
if (count == 0) return s;
244
243
245
t = quoted = store_get(Ustrlen(s) + count + 1, is_tainted(s));
244
t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx);
246
245
247
while (*s != 0)
246
while (*s)
248
  {
247
  {
249
  *t++ = *s;
248
  *t++ = *s;
250
  if (*s++ == '\"') *t++ = '\"';
249
  if (*s++ == '\"') *t++ = '\"';
Lines 263-274 Link Here
263
262
264
#include "../version.h"
263
#include "../version.h"
265
264
266
void
265
gstring *
267
nisplus_version_report(FILE *f)
266
nisplus_version_report(gstring * g)
268
{
267
{
269
#ifdef DYNLOOKUP
268
#ifdef DYNLOOKUP
270
fprintf(f, "Library version: NIS+: Exim version %s\n", EXIM_VERSION_STR);
269
g = string_fmt_append(g, "Library version: NIS+: Exim version %s\n", EXIM_VERSION_STR);
271
#endif
270
#endif
271
return g;
272
}
272
}
273
273
274
274
(-)exim.orig/src/lookups/oracle.c (-22 / +20 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2015 */
6
/* 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. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Interface to an Oracle database. This code was originally supplied by
9
/* Interface to an Oracle database. This code was originally supplied by
Lines 306-313 Link Here
306
306
307
  /* Get store for a new connection, initialize it, and connect to the server */
307
  /* Get store for a new connection, initialize it, and connect to the server */
308
308
309
   oracle_handle = store_get(sizeof(struct cda_def), FALSE);
309
   oracle_handle = store_get(sizeof(struct cda_def), GET_UNTAINTED);
310
   hda = store_get(HDA_SIZE, FALSE);
310
   hda = store_get(HDA_SIZE, GET_UNTAINTED);
311
   memset(hda,'\0',HDA_SIZE);
311
   memset(hda,'\0',HDA_SIZE);
312
312
313
  /*
313
  /*
Lines 330-336 Link Here
330
330
331
  /* Add the connection to the cache */
331
  /* Add the connection to the cache */
332
332
333
  cn = store_get(sizeof(oracle_connection), FALSE);
333
  cn = store_get(sizeof(oracle_connection), GET_UNTAINTED);
334
  cn->server = server_copy;
334
  cn->server = server_copy;
335
  cn->handle = oracle_handle;
335
  cn->handle = oracle_handle;
336
  cn->next = oracle_connections;
336
  cn->next = oracle_connections;
Lines 349-355 Link Here
349
349
350
/* We have a connection. Open a cursor and run the query */
350
/* We have a connection. Open a cursor and run the query */
351
351
352
cda = store_get(sizeof(Cda_Def), FALSE);
352
cda = store_get(sizeof(Cda_Def), GET_UNTAINTED);
353
353
354
if (oopen(cda, oracle_handle, (text *)0, -1, -1, (text *)0, -1) != 0)
354
if (oopen(cda, oracle_handle, (text *)0, -1, -1, (text *)0, -1) != 0)
355
  {
355
  {
Lines 370-377 Link Here
370
/* Find the number of fields returned and sort out their types. If the number
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. */
371
is one, we don't add field names to the data. Otherwise we do. */
372
372
373
def = store_get(sizeof(Ora_Define)*MAX_SELECT_LIST_SIZE, FALSE);
373
def = store_get(sizeof(Ora_Define)*MAX_SELECT_LIST_SIZE, GET_UNTAINTED);
374
desc = store_get(sizeof(Ora_Describe)*MAX_SELECT_LIST_SIZE, FALSE);
374
desc = store_get(sizeof(Ora_Describe)*MAX_SELECT_LIST_SIZE, GET_UNTAINTED);
375
375
376
if ((num_fields = describe_define(cda,def,desc)) == -1)
376
if ((num_fields = describe_define(cda,def,desc)) == -1)
377
  {
377
  {
Lines 510-522 Link Here
510
int sep = 0;
510
int sep = 0;
511
uschar *server;
511
uschar *server;
512
uschar *list = oracle_servers;
512
uschar *list = oracle_servers;
513
uschar buffer[512];
514
513
515
do_cache = do_cache;   /* Placate picky compilers */
514
do_cache = do_cache;   /* Placate picky compilers */
516
515
517
DEBUG(D_lookup) debug_printf_indent("ORACLE query: %s\n", query);
516
DEBUG(D_lookup) debug_printf_indent("ORACLE query: %s\n", query);
518
517
519
while ((server = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
518
while ((server = string_nextinlist(&list, &sep, NULL, 0)))
520
  {
519
  {
521
  BOOL defer_break;
520
  BOOL defer_break;
522
  int rc = perform_oracle_search(query, server, result, errmsg, &defer_break);
521
  int rc = perform_oracle_search(query, server, result, errmsg, &defer_break);
Lines 544-570 Link Here
544
Arguments:
543
Arguments:
545
  s          the string to be quoted
544
  s          the string to be quoted
546
  opt        additional option text or NULL if none
545
  opt        additional option text or NULL if none
546
  idx	     lookup type index
547
547
548
Returns:     the processed string or NULL for a bad option
548
Returns:     the processed string or NULL for a bad option
549
*/
549
*/
550
550
551
static uschar *
551
static uschar *
552
oracle_quote(uschar *s, uschar *opt)
552
oracle_quote(uschar * s, uschar * opt, unsigned idx)
553
{
553
{
554
register int c;
554
int c, count = 0;
555
int count = 0;
555
uschar * t = s, * quoted;
556
uschar *t = s;
557
uschar *quoted;
558
556
559
if (opt != NULL) return NULL;    /* No options are recognized */
557
if (opt) return NULL;    /* No options are recognized */
560
558
561
while ((c = *t++) != 0)
559
while ((c = *t++))
562
  if (strchr("\n\t\r\b\'\"\\", c) != NULL) count++;
560
  if (strchr("\n\t\r\b\'\"\\", c) != NULL) count++;
563
561
564
if (count == 0) return s;
562
t = quoted = store_get_quoted((int)Ustrlen(s) + count + 1, s, idx);
565
t = quoted = store_get((int)strlen(s) + count + 1, is_tainted(s));
566
563
567
while ((c = *s++) != 0)
564
while ((c = *s++))
568
  {
565
  {
569
  if (strchr("\n\t\r\b\'\"\\", c) != NULL)
566
  if (strchr("\n\t\r\b\'\"\\", c) != NULL)
570
    {
567
    {
Lines 599-610 Link Here
599
596
600
#include "../version.h"
597
#include "../version.h"
601
598
602
void
599
gstring *
603
oracle_version_report(FILE *f)
600
oracle_version_report(gstring * g)
604
{
601
{
605
#ifdef DYNLOOKUP
602
#ifdef DYNLOOKUP
606
fprintf(f, "Library version: Oracle: Exim version %s\n", EXIM_VERSION_STR);
603
g = string_fmt_append(g, "Library version: Oracle: Exim version %s\n", EXIM_VERSION_STR);
607
#endif
604
#endif
605
return g;
608
}
606
}
609
607
610
608
(-)exim.orig/src/lookups/passwd.c (-12 / +5 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2015 */
6
/* 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. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#include "../exim.h"
9
#include "../exim.h"
Lines 19-26 Link Here
19
static void *
19
static void *
20
passwd_open(const uschar * filename, uschar ** errmsg)
20
passwd_open(const uschar * filename, uschar ** errmsg)
21
{
21
{
22
filename = filename;     /* Keep picky compilers happy */
23
errmsg = errmsg;
24
return (void *)(-1);     /* Just return something non-null */
22
return (void *)(-1);     /* Just return something non-null */
25
}
23
}
26
24
Lines 40-51 Link Here
40
{
38
{
41
struct passwd *pw;
39
struct passwd *pw;
42
40
43
handle = handle;         /* Keep picky compilers happy */
44
filename = filename;
45
length = length;
46
errmsg = errmsg;
47
do_cache = do_cache;
48
49
if (!route_finduser(keystring, &pw, NULL)) return FAIL;
41
if (!route_finduser(keystring, &pw, NULL)) return FAIL;
50
*result = string_sprintf("*:%d:%d:%s:%s:%s", (int)pw->pw_uid, (int)pw->pw_gid,
42
*result = string_sprintf("*:%d:%d:%s:%s:%s", (int)pw->pw_uid, (int)pw->pw_gid,
51
  pw->pw_gecos, pw->pw_dir, pw->pw_shell);
43
  pw->pw_gecos, pw->pw_dir, pw->pw_shell);
Lines 62-73 Link Here
62
54
63
#include "../version.h"
55
#include "../version.h"
64
56
65
void
57
gstring *
66
passwd_version_report(FILE *f)
58
passwd_version_report(gstring * g)
67
{
59
{
68
#ifdef DYNLOOKUP
60
#ifdef DYNLOOKUP
69
fprintf(f, "Library version: passwd: Exim version %s\n", EXIM_VERSION_STR);
61
g = string_fmt_append(g, "Library version: passwd: Exim version %s\n", EXIM_VERSION_STR);
70
#endif
62
#endif
63
return g;
71
}
64
}
72
65
73
static lookup_info _lookup_info = {
66
static lookup_info _lookup_info = {
(-)exim.orig/src/lookups/pgsql.c (-25 / +21 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Thanks to Petr Cech for contributing the original code for these
9
/* Thanks to Petr Cech for contributing the original code for these
Lines 262-268 Link Here
262
262
263
  /* Add the connection to the cache */
263
  /* Add the connection to the cache */
264
264
265
  cn = store_get(sizeof(pgsql_connection), FALSE);
265
  cn = store_get(sizeof(pgsql_connection), GET_UNTAINTED);
266
  cn->server = server_copy;
266
  cn->server = server_copy;
267
  cn->handle = pg_conn;
267
  cn->handle = pg_conn;
268
  cn->next = pgsql_connections;
268
  cn->next = pgsql_connections;
Lines 336-341 Link Here
336
      uschar *tmp = US PQgetvalue(pg_result, i, j);
336
      uschar *tmp = US PQgetvalue(pg_result, i, j);
337
      result = lf_quote(US PQfname(pg_result, j), tmp, Ustrlen(tmp), result);
337
      result = lf_quote(US PQfname(pg_result, j), tmp, Ustrlen(tmp), result);
338
      }
338
      }
339
  if (!result) result = string_get(1);
339
  }
340
  }
340
341
341
/* If result is NULL then no data has been found and so we return FAIL. */
342
/* If result is NULL then no data has been found and so we return FAIL. */
Lines 413-439 Link Here
413
Arguments:
414
Arguments:
414
  s          the string to be quoted
415
  s          the string to be quoted
415
  opt        additional option text or NULL if none
416
  opt        additional option text or NULL if none
417
  idx	     lookup type index
416
418
417
Returns:     the processed string or NULL for a bad option
419
Returns:     the processed string or NULL for a bad option
418
*/
420
*/
419
421
420
static uschar *
422
static uschar *
421
pgsql_quote(uschar *s, uschar *opt)
423
pgsql_quote(uschar * s, uschar * opt, unsigned idx)
422
{
424
{
423
register int c;
425
int count = 0, c;
424
int count = 0;
426
uschar * t = s, * quoted;
425
uschar *t = s;
426
uschar *quoted;
427
427
428
if (opt != NULL) return NULL;     /* No options recognized */
428
if (opt) return NULL;     /* No options recognized */
429
429
430
while ((c = *t++) != 0)
430
while ((c = *t++))
431
  if (Ustrchr("\n\t\r\b\'\"\\", c) != NULL) count++;
431
  if (Ustrchr("\n\t\r\b\'\"\\", c) != NULL) count++;
432
432
433
if (count == 0) return s;
433
t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx);
434
t = quoted = store_get(Ustrlen(s) + count + 1, is_tainted(s));
435
434
436
while ((c = *s++) != 0)
435
while ((c = *s++))
437
  {
436
  {
438
  if (c == '\'')
437
  if (c == '\'')
439
    {
438
    {
Lines 445-460 Link Here
445
    *t++ = '\\';
444
    *t++ = '\\';
446
    switch(c)
445
    switch(c)
447
      {
446
      {
448
      case '\n': *t++ = 'n';
447
      case '\n': *t++ = 'n'; break;
449
      break;
448
      case '\t': *t++ = 't'; break;
450
      case '\t': *t++ = 't';
449
      case '\r': *t++ = 'r'; break;
451
      break;
450
      case '\b': *t++ = 'b'; break;
452
      case '\r': *t++ = 'r';
451
      default:   *t++ = c;   break;
453
      break;
454
      case '\b': *t++ = 'b';
455
      break;
456
      default:   *t++ = c;
457
      break;
458
      }
452
      }
459
    }
453
    }
460
  else *t++ = c;
454
  else *t++ = c;
Lines 473-483 Link Here
473
467
474
#include "../version.h"
468
#include "../version.h"
475
469
476
void
470
gstring *
477
pgsql_version_report(FILE *f)
471
pgsql_version_report(gstring * g)
478
{
472
{
479
#ifdef DYNLOOKUP
473
#ifdef DYNLOOKUP
480
fprintf(f, "Library version: PostgreSQL: Exim version %s\n", EXIM_VERSION_STR);
474
g = string_fmt_append(g, "Library version: PostgreSQL: Exim version %s\n", EXIM_VERSION_STR);
481
#endif
475
#endif
482
476
483
/* Version reporting: there appears to be no available information about
477
/* Version reporting: there appears to be no available information about
Lines 485-490 Link Here
485
can access the server version and the chosen protocol version, but those
479
can access the server version and the chosen protocol version, but those
486
aren't really what we want.  It might make sense to debug_printf those
480
aren't really what we want.  It might make sense to debug_printf those
487
when the connection is established though? */
481
when the connection is established though? */
482
483
return g;
488
}
484
}
489
485
490
486
(-)exim.orig/src/lookups/readsock.c (-14 / +34 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2021 - 2022 */
5
/* Copyright (c) Jeremy Harris 2020 */
6
/* Copyright (c) Jeremy Harris 2020 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 13-20 Link Here
13
internal_readsock_open(client_conn_ctx * cctx, const uschar * sspec,
14
internal_readsock_open(client_conn_ctx * cctx, const uschar * sspec,
14
  int timeout, BOOL do_tls, uschar ** errmsg)
15
  int timeout, BOOL do_tls, uschar ** errmsg)
15
{
16
{
16
int sep = ',';
17
uschar * ele;
18
const uschar * server_name;
17
const uschar * server_name;
19
host_item host;
18
host_item host;
20
19
Lines 97-103 Link Here
97
96
98
  sigalrm_seen = FALSE;
97
  sigalrm_seen = FALSE;
99
  ALARM(timeout);
98
  ALARM(timeout);
100
  rc = connect(cctx->sock, (struct sockaddr *)(&sockun), sizeof(sockun));
99
  rc = connect(cctx->sock, (struct sockaddr *) &sockun, sizeof(sockun));
101
  ALARM_CLR(0);
100
  ALARM_CLR(0);
102
  if (sigalrm_seen)
101
  if (sigalrm_seen)
103
    {
102
    {
Lines 117-126 Link Here
117
#ifndef DISABLE_TLS
116
#ifndef DISABLE_TLS
118
if (do_tls)
117
if (do_tls)
119
  {
118
  {
119
  union sockaddr_46 interface_sock;
120
  EXIM_SOCKLEN_T size = sizeof(interface_sock);
120
  smtp_connect_args conn_args = {.host = &host };
121
  smtp_connect_args conn_args = {.host = &host };
121
  tls_support tls_dummy = {.sni=NULL};
122
  tls_support tls_dummy = { .sni = NULL };
122
  uschar * errstr;
123
  uschar * errstr;
123
124
125
  if (getsockname(cctx->sock, (struct sockaddr *) &interface_sock, &size) == 0)
126
    conn_args.sending_ip_address = host_ntoa(-1, &interface_sock, NULL, NULL);
127
  else
128
    {
129
    *errmsg = string_sprintf("getsockname failed: %s", strerror(errno));
130
    goto bad;
131
    }
132
124
  if (!tls_client_start(cctx, &conn_args, NULL, &tls_dummy, &errstr))
133
  if (!tls_client_start(cctx, &conn_args, NULL, &tls_dummy, &errstr))
125
    {
134
    {
126
    *errmsg = string_sprintf("TLS connect failed: %s", errstr);
135
    *errmsg = string_sprintf("TLS connect failed: %s", errstr);
Lines 151-157 Link Here
151
static void *
160
static void *
152
readsock_open(const uschar * filename, uschar ** errmsg)
161
readsock_open(const uschar * filename, uschar ** errmsg)
153
{
162
{
154
client_conn_ctx * cctx = store_get(sizeof(*cctx), FALSE);
163
client_conn_ctx * cctx = store_get(sizeof(*cctx), GET_UNTAINTED);
155
cctx->sock = -1;
164
cctx->sock = -1;
156
cctx->tls_ctx = NULL;
165
cctx->tls_ctx = NULL;
157
DEBUG(D_lookup) debug_printf_indent("readsock: allocated context\n");
166
DEBUG(D_lookup) debug_printf_indent("readsock: allocated context\n");
Lines 182-188 Link Here
182
} lf = {.do_shutdown = TRUE};
191
} lf = {.do_shutdown = TRUE};
183
uschar * eol = NULL;
192
uschar * eol = NULL;
184
int timeout = 5;
193
int timeout = 5;
185
FILE * fp;
186
gstring * yield;
194
gstring * yield;
187
int ret = DEFER;
195
int ret = DEFER;
188
196
Lines 250-265 Link Here
250
and might need later write ops on the socket, the stdio must be in
258
and might need later write ops on the socket, the stdio must be in
251
writable mode or the underlying socket goes non-writable. */
259
writable mode or the underlying socket goes non-writable. */
252
260
253
if (!cctx->tls_ctx)
254
  fp = fdopen(cctx->sock, lf.do_shutdown ? "rb" : "wb");
255
256
sigalrm_seen = FALSE;
261
sigalrm_seen = FALSE;
257
ALARM(timeout);
262
#ifdef DISABLE_TLS
258
yield =
263
if (TRUE)
259
#ifndef DISABLE_TLS
264
#else
260
  cctx->tls_ctx ? cat_file_tls(cctx->tls_ctx, NULL, eol) :
265
if (!cctx->tls_ctx)
261
#endif
266
#endif
262
		  cat_file(fp, NULL, eol);
267
  {
268
  FILE * fp = fdopen(cctx->sock, "rb");
269
  if (!fp)
270
    {
271
    log_write(0, LOG_MAIN|LOG_PANIC, "readsock fdopen: %s\n", strerror(errno));
272
    goto out;
273
    }
274
  ALARM(timeout);
275
  yield = cat_file(fp, NULL, eol);
276
  }
277
else
278
  {
279
  ALARM(timeout);
280
  yield = cat_file_tls(cctx->tls_ctx, NULL, eol);
281
  }
282
263
ALARM_CLR(0);
283
ALARM_CLR(0);
264
284
265
if (sigalrm_seen)
285
if (sigalrm_seen)
(-)exim.orig/src/lookups/redis.c (-16 / +16 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#include "../exim.h"
9
#include "../exim.h"
Lines 171-177 Link Here
171
    }
171
    }
172
172
173
  /* Add the connection to the cache */
173
  /* Add the connection to the cache */
174
  cn = store_get(sizeof(redis_connection), FALSE);
174
  cn = store_get(sizeof(redis_connection), GET_UNTAINTED);
175
  cn->server = server_copy;
175
  cn->server = server_copy;
176
  cn->handle = redis_handle;
176
  cn->handle = redis_handle;
177
  cn->next = redis_connections;
177
  cn->next = redis_connections;
Lines 399-425 Link Here
399
Arguments:
399
Arguments:
400
  s          the string to be quoted
400
  s          the string to be quoted
401
  opt        additional option text or NULL if none
401
  opt        additional option text or NULL if none
402
  idx	     lookup type index
402
403
403
Returns:     the processed string or NULL for a bad option
404
Returns:     the processed string or NULL for a bad option
404
*/
405
*/
405
406
406
static uschar *
407
static uschar *
407
redis_quote(uschar *s, uschar *opt)
408
redis_quote(uschar * s, uschar * opt, unsigned idx)
408
{
409
{
409
register int c;
410
int c, count = 0;
410
int count = 0;
411
uschar * t = s, * quoted;
411
uschar *t = s;
412
uschar *quoted;
413
412
414
if (opt) return NULL;     /* No options recognized */
413
if (opt) return NULL;     /* No options recognized */
415
414
416
while ((c = *t++) != 0)
415
while ((c = *t++))
417
  if (isspace(c) || c == '\\') count++;
416
  if (isspace(c) || c == '\\') count++;
418
417
419
if (count == 0) return s;
418
t = quoted = store_get_quoted(Ustrlen(s) + count + 1, s, idx);
420
t = quoted = store_get(Ustrlen(s) + count + 1, is_tainted(s));
421
419
422
while ((c = *s++) != 0)
420
while ((c = *s++))
423
  {
421
  {
424
  if (isspace(c) || c == '\\') *t++ = '\\';
422
  if (isspace(c) || c == '\\') *t++ = '\\';
425
  *t++ = c;
423
  *t++ = c;
Lines 435-448 Link Here
435
*************************************************/
433
*************************************************/
436
#include "../version.h"
434
#include "../version.h"
437
435
438
void
436
gstring *
439
redis_version_report(FILE *f)
437
redis_version_report(gstring * g)
440
{
438
{
441
fprintf(f, "Library version: REDIS: Compile: %d [%d]\n",
439
g = string_fmt_append(g,
442
               HIREDIS_MAJOR, HIREDIS_MINOR);
440
  "Library version: REDIS: Compile: %d [%d]\n", HIREDIS_MAJOR, HIREDIS_MINOR);
443
#ifdef DYNLOOKUP
441
#ifdef DYNLOOKUP
444
fprintf(f, "                        Exim version %s\n", EXIM_VERSION_STR);
442
g = string_fmt_append(g,
443
  "                        Exim version %s\n", EXIM_VERSION_STR);
445
#endif
444
#endif
445
return g;
446
}
446
}
447
447
448
448
(-)exim.orig/src/lookups/spf.c (-5 / +5 lines)
Lines 5-18 Link Here
5
/* Exim - SPF lookup module using libspf2
5
/* Exim - SPF lookup module using libspf2
6
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7
7
8
Copyright (c) The Exim Maintainers 2020 - 2022
8
Copyright (c) 2005 Chris Webb, Arachsys Internet Services Ltd
9
Copyright (c) 2005 Chris Webb, Arachsys Internet Services Ltd
9
10
10
This program is free software; you can redistribute it and/or
11
This program is free software; you can redistribute it and/or
11
modify it under the terms of the GNU General Public License
12
modify it under the terms of the GNU General Public License
12
as published by the Free Software Foundation; either version 2
13
as published by the Free Software Foundation; either version 2
13
of the License, or (at your option) any later version.
14
of the License, or (at your option) any later version.
14
15
Copyright (c) The Exim Maintainers 2020
16
*/
15
*/
17
16
18
#include "../exim.h"
17
#include "../exim.h"
Lines 128-139 Link Here
128
127
129
#include "../version.h"
128
#include "../version.h"
130
129
131
void
130
gstring *
132
spf_version_report(FILE *f)
131
spf_version_report(gstring * g)
133
{
132
{
134
#ifdef DYNLOOKUP
133
#ifdef DYNLOOKUP
135
fprintf(f, "Library version: SPF: Exim version %s\n", EXIM_VERSION_STR);
134
g = string_fmt_append(g, "Library version: SPF: Exim version %s\n", EXIM_VERSION_STR));
136
#endif
135
#endif
136
return g;
137
}
137
}
138
138
139
139
(-)exim.orig/src/lookups/sqlite.c (-19 / +22 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#include "../exim.h"
9
#include "../exim.h"
Lines 66-72 Link Here
66
  /* For multiple fields, include the field name too */
66
  /* For multiple fields, include the field name too */
67
  for (int i = 0; i < argc; i++)
67
  for (int i = 0; i < argc; i++)
68
    {
68
    {
69
    uschar *value = US((argv[i] != NULL)? argv[i]:"<NULL>");
69
    uschar * value = US(argv[i] ? argv[i] : "<NULL>");
70
    res = lf_quote(US azColName[i], value, Ustrlen(value), res);
70
    res = lf_quote(US azColName[i], value, Ustrlen(value), res);
71
    }
71
    }
72
  }
72
  }
Lines 74-80 Link Here
74
else
74
else
75
  res = string_cat(res, argv[0] ? US argv[0] : US "<NULL>");
75
  res = string_cat(res, argv[0] ? US argv[0] : US "<NULL>");
76
76
77
*(gstring **)arg = res;
77
/* always return a non-null gstring, even for a zero-length string result */
78
*(gstring **)arg = res ? res : string_get(1);
78
return 0;
79
return 0;
79
}
80
}
80
81
Lines 94-100 Link Here
94
  return FAIL;
95
  return FAIL;
95
  }
96
  }
96
97
97
if (!res) *do_cache = 0;
98
if (!res) *do_cache = 0;	/* on fail, wipe cache */
98
99
99
*result = string_from_gstring(res);
100
*result = string_from_gstring(res);
100
return OK;
101
return OK;
Lines 125-150 Link Here
125
Arguments:
126
Arguments:
126
  s          the string to be quoted
127
  s          the string to be quoted
127
  opt        additional option text or NULL if none
128
  opt        additional option text or NULL if none
129
  idx	     lookup type index
128
130
129
Returns:     the processed string or NULL for a bad option
131
Returns:     the processed string or NULL for a bad option
130
*/
132
*/
131
133
132
static uschar *
134
static uschar *
133
sqlite_quote(uschar *s, uschar *opt)
135
sqlite_quote(uschar * s, uschar * opt, unsigned idx)
134
{
136
{
135
register int c;
137
int c, count = 0;
136
int count = 0;
138
uschar * t = s, * quoted;
137
uschar *t = s;
138
uschar *quoted;
139
139
140
if (opt != NULL) return NULL;     /* No options recognized */
140
if (opt) return NULL;     /* No options recognized */
141
141
142
while ((c = *t++) != 0) if (c == '\'') count++;
142
while ((c = *t++)) if (c == '\'') count++;
143
count += t - s;
143
144
144
if (count == 0) return s;
145
t = quoted = store_get_quoted(count + 1, s, idx);
145
t = quoted = store_get(Ustrlen(s) + count + 1, is_tainted(s));
146
146
147
while ((c = *s++) != 0)
147
while ((c = *s++))
148
  {
148
  {
149
  if (c == '\'') *t++ = '\'';
149
  if (c == '\'') *t++ = '\'';
150
  *t++ = c;
150
  *t++ = c;
Lines 164-178 Link Here
164
164
165
#include "../version.h"
165
#include "../version.h"
166
166
167
void
167
gstring *
168
sqlite_version_report(FILE *f)
168
sqlite_version_report(gstring * g)
169
{
169
{
170
fprintf(f, "Library version: SQLite: Compile: %s\n"
170
g = string_fmt_append(g,
171
           "                         Runtime: %s\n",
171
  "Library version: SQLite: Compile: %s\n"
172
  "                         Runtime: %s\n",
172
        SQLITE_VERSION, sqlite3_libversion());
173
        SQLITE_VERSION, sqlite3_libversion());
173
#ifdef DYNLOOKUP
174
#ifdef DYNLOOKUP
174
fprintf(f, "                         Exim version %s\n", EXIM_VERSION_STR);
175
g = string_fmt_append(g,
176
  "                         Exim version %s\n", EXIM_VERSION_STR);
175
#endif
177
#endif
178
return g;
176
}
179
}
177
180
178
static lookup_info _lookup_info = {
181
static lookup_info _lookup_info = {
(-)exim.orig/src/lookups/testdb.c (-10 / +5 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2015 */
6
/* 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. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#include "../exim.h"
9
#include "../exim.h"
Lines 24-31 Link Here
24
static void *
24
static void *
25
testdb_open(const uschar * filename, uschar ** errmsg)
25
testdb_open(const uschar * filename, uschar ** errmsg)
26
{
26
{
27
filename = filename;   /* Keep picky compilers happy */
28
errmsg = errmsg;
29
return (void *)(1);    /* Just return something non-null */
27
return (void *)(1);    /* Just return something non-null */
30
}
28
}
31
29
Lines 42-51 Link Here
42
  int length, uschar ** result, uschar ** errmsg, uint * do_cache,
40
  int length, uschar ** result, uschar ** errmsg, uint * do_cache,
43
  const uschar * opts)
41
  const uschar * opts)
44
{
42
{
45
handle = handle;          /* Keep picky compilers happy */
46
filename = filename;
47
length = length;
48
49
if (Ustrcmp(query, "fail") == 0)
43
if (Ustrcmp(query, "fail") == 0)
50
  {
44
  {
51
  *errmsg = US"testdb lookup forced FAIL";
45
  *errmsg = US"testdb lookup forced FAIL";
Lines 74-85 Link Here
74
68
75
#include "../version.h"
69
#include "../version.h"
76
70
77
void
71
gstring *
78
testdb_version_report(FILE *f)
72
testdb_version_report(gstring * g)
79
{
73
{
80
#ifdef DYNLOOKUP
74
#ifdef DYNLOOKUP
81
fprintf(f, "Library version: TestDB: Exim version %s\n", EXIM_VERSION_STR);
75
g = string_fmt_append(g, "Library version: TestDB: Exim version %s\n", EXIM_VERSION_STR);
82
#endif
76
#endif
77
return g;
83
}
78
}
84
79
85
80
(-)exim.orig/src/lookups/whoson.c (-12 / +8 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2015 */
6
/* 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. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* This code originally came from Robert Wal. */
9
/* This code originally came from Robert Wal. */
Lines 23-30 Link Here
23
static void *
23
static void *
24
whoson_open(const uschar * filename, uschar ** errmsg)
24
whoson_open(const uschar * filename, uschar ** errmsg)
25
{
25
{
26
filename = filename;   /* Keep picky compilers happy */
27
errmsg = errmsg;
28
return (void *)(1);    /* Just return something non-null */
26
return (void *)(1);    /* Just return something non-null */
29
}
27
}
30
28
Lines 40-50 Link Here
40
  uschar ** result, uschar ** errmsg, uint * do_cache, const uschar * opts)
38
  uschar ** result, uschar ** errmsg, uint * do_cache, const uschar * opts)
41
{
39
{
42
uschar buffer[80];
40
uschar buffer[80];
43
handle = handle;          /* Keep picky compilers happy */
44
filename = filename;
45
length = length;
46
errmsg = errmsg;
47
do_cache = do_cache;
48
41
49
switch (wso_query(CS query, CS buffer, sizeof(buffer)))
42
switch (wso_query(CS query, CS buffer, sizeof(buffer)))
50
  {
43
  {
Lines 71-83 Link Here
71
64
72
#include "../version.h"
65
#include "../version.h"
73
66
74
void
67
gstring *
75
whoson_version_report(FILE *f)
68
whoson_version_report(gstring * g)
76
{
69
{
77
fprintf(f, "Library version: Whoson: Runtime: %s\n", wso_version());
70
g = string_fmt_append(g,
71
  "Library version: Whoson: Runtime: %s\n", wso_version());
78
#ifdef DYNLOOKUP
72
#ifdef DYNLOOKUP
79
fprintf(f, "                         Exim version %s\n", EXIM_VERSION_STR);
73
g = string_fmt_append(g,
74
  "                         Exim version %s\n", EXIM_VERSION_STR);
80
#endif
75
#endif
76
return g;
81
}
77
}
82
78
83
static lookup_info _lookup_info = {
79
static lookup_info _lookup_info = {
(-)exim.orig/src/macro_predef.c (-13 / +36 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) Jeremy Harris 1995 - 2018 */
6
/* Copyright (c) Jeremy Harris 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Create a static data structure with the predefined macros, to be
9
/* Create a static data structure with the predefined macros, to be
Lines 174-194 Link Here
174
#ifdef SUPPORT_SOCKS
174
#ifdef SUPPORT_SOCKS
175
  builtin_macro_create(US"_HAVE_SOCKS");
175
  builtin_macro_create(US"_HAVE_SOCKS");
176
#endif
176
#endif
177
#if defined(SUPPORT_SRS)
178
  builtin_macro_create(US"_HAVE_NATIVE_SRS");	/* beware clash with _HAVE_SRS */
179
#endif
177
#ifdef TCP_FASTOPEN
180
#ifdef TCP_FASTOPEN
178
  builtin_macro_create(US"_HAVE_TCP_FASTOPEN");
181
  builtin_macro_create(US"_HAVE_TCP_FASTOPEN");
179
#endif
182
#endif
180
#ifdef EXPERIMENTAL_LMDB
181
  builtin_macro_create(US"_HAVE_LMDB");
182
#endif
183
#ifdef SUPPORT_SPF
183
#ifdef SUPPORT_SPF
184
  builtin_macro_create(US"_HAVE_SPF");
184
  builtin_macro_create(US"_HAVE_SPF");
185
#endif
185
#endif
186
#if defined(EXPERIMENTAL_SRS) || defined(EXPERIMENTAL_SRS_NATIVE)
186
#ifdef SUPPORT_SRS
187
  builtin_macro_create(US"_HAVE_SRS");
187
  builtin_macro_create(US"_HAVE_SRS");
188
#endif
188
#endif
189
#if defined(EXPERIMENTAL_SRS_NATIVE)
190
  builtin_macro_create(US"_HAVE_NATIVE_SRS");	/* beware clash with _HAVE_SRS */
191
#endif
192
#ifdef EXPERIMENTAL_ARC
189
#ifdef EXPERIMENTAL_ARC
193
  builtin_macro_create(US"_HAVE_ARC");
190
  builtin_macro_create(US"_HAVE_ARC");
194
#endif
191
#endif
Lines 204-210 Link Here
204
#ifdef EXPERIMENTAL_DSN_INFO
201
#ifdef EXPERIMENTAL_DSN_INFO
205
  builtin_macro_create(US"_HAVE_DSN_INFO");
202
  builtin_macro_create(US"_HAVE_DSN_INFO");
206
#endif
203
#endif
207
#ifdef EXPERIMENTAL_TLS_RESUME
204
#ifndef DISABLE_TLS_RESUME
208
  builtin_macro_create(US"_HAVE_TLS_RESUME");
205
  builtin_macro_create(US"_HAVE_TLS_RESUME");
209
#endif
206
#endif
210
207
Lines 226-240 Link Here
226
#ifdef LOOKUP_IBASE
223
#ifdef LOOKUP_IBASE
227
  builtin_macro_create(US"_HAVE_LOOKUP_IBASE");
224
  builtin_macro_create(US"_HAVE_LOOKUP_IBASE");
228
#endif
225
#endif
226
#ifdef LOOKUP_LMDB
227
  builtin_macro_create(US"_HAVE_LMDB");
228
  builtin_macro_create(US"_HAVE_LOOKUP_LMDB");
229
#endif
229
#ifdef LOOKUP_LDAP
230
#ifdef LOOKUP_LDAP
230
  builtin_macro_create(US"_HAVE_LOOKUP_JSON");
231
  builtin_macro_create(US"_HAVE_LOOKUP_JSON");
231
#endif
232
#endif
232
#ifdef LOOKUP_LDAP
233
#ifdef LOOKUP_LDAP
233
  builtin_macro_create(US"_HAVE_LOOKUP_LDAP");
234
  builtin_macro_create(US"_HAVE_LOOKUP_LDAP");
234
#endif
235
#endif
235
#ifdef EXPERIMENTAL_LMDB
236
  builtin_macro_create(US"_HAVE_LOOKUP_LMDB");
237
#endif
238
#ifdef LOOKUP_MYSQL
236
#ifdef LOOKUP_MYSQL
239
  builtin_macro_create(US"_HAVE_LOOKUP_MYSQL");
237
  builtin_macro_create(US"_HAVE_LOOKUP_MYSQL");
240
#endif
238
#endif
Lines 278-288 Link Here
278
# endif
276
# endif
279
#endif
277
#endif
280
278
279
features_acl();
280
features_crypto();
281
281
#ifdef WITH_CONTENT_SCAN
282
#ifdef WITH_CONTENT_SCAN
282
features_malware();
283
features_malware();
283
#endif
284
#endif
285
}
284
286
285
features_crypto();
287
static void
288
exp_features(void)
289
{
290
#ifdef EXPERIMENTAL_ARC
291
  builtin_macro_create(US"_EXP_ARC");
292
#endif
293
#ifdef EXPERIMENTAL_BRIGHTMAIL
294
  builtin_macro_create(US"_EXP_BMI");
295
#endif
296
#ifdef EXPERIMENTAL_DCC
297
  builtin_macro_create(US"_EXP_DCC");
298
#endif
299
#ifdef EXPERIMENTAL_DSN_INFO
300
  builtin_macro_create(US"_EXP_DSNI");
301
#endif
302
#ifdef EXPERIMENTAL_ESMTP_LIMITS
303
  builtin_macro_create(US"_EXP_LIMITS");
304
#endif
305
#ifdef EXPERIMENTAL_QUEUEFILE
306
  builtin_macro_create(US"_EXP_QUEUEFILE");
307
#endif
286
}
308
}
287
309
288
310
Lines 313-318 Link Here
313
{
335
{
314
printf("#include \"exim.h\"\n");
336
printf("#include \"exim.h\"\n");
315
features();
337
features();
338
exp_features();
316
options();
339
options();
317
params();
340
params();
318
341
(-)exim.orig/src/macro_predef.h (+2 lines)
Lines 3-8 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) Jeremy Harris 2017 - 2018 */
5
/* Copyright (c) Jeremy Harris 2017 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2021 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
8
/* Global functions */
9
/* Global functions */
Lines 12-17 Link Here
12
extern void builtin_macro_create_var(const uschar *, const uschar *);
13
extern void builtin_macro_create_var(const uschar *, const uschar *);
13
extern void options_from_list(optionlist *, unsigned, const uschar *, uschar *);
14
extern void options_from_list(optionlist *, unsigned, const uschar *, uschar *);
14
15
16
extern void features_acl(void);
15
extern void features_malware(void);
17
extern void features_malware(void);
16
extern void features_crypto(void);
18
extern void features_crypto(void);
17
extern void options_main(void);
19
extern void options_main(void);
(-)exim.orig/src/macros.h (-46 / +52 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 79-89 Link Here
79
  ((uschar)(c) > 127 && print_topbitchars))
79
  ((uschar)(c) > 127 && print_topbitchars))
80
80
81
81
82
/* Convenience for testing strings */
83
84
#define streqic(Foo, Bar) (strcmpic(Foo, Bar) == 0)
85
86
87
/* When built with TLS support, the act of flushing SMTP output becomes
82
/* When built with TLS support, the act of flushing SMTP output becomes
88
a no-op once an SSL session is in progress. */
83
a no-op once an SSL session is in progress. */
89
84
Lines 110-117 Link Here
110
105
111
/* Debugging control */
106
/* Debugging control */
112
107
108
#define LOG_NAME_SIZE 256
113
#define DEBUG(x)      if (debug_selector & (x))
109
#define DEBUG(x)      if (debug_selector & (x))
114
#define HDEBUG(x)     if (host_checking || (debug_selector & (x)))
110
#define HDEBUG(x)     if (host_checking || debug_selector & (x))
115
111
116
/* The default From: text for DSNs */
112
/* The default From: text for DSNs */
117
113
Lines 195-208 Link Here
195
#define WAIT_NAME_MAX 50
191
#define WAIT_NAME_MAX 50
196
#define WAIT_CONT_MAX 1000
192
#define WAIT_CONT_MAX 1000
197
193
198
/* Wait this long before determining that a Proxy Protocol configured
199
host isn't speaking the protocol, and so is disallowed. Can be moved to
200
runtime configuration if per site settings become needed. */
201
#ifdef SUPPORT_PROXY
202
#define PROXY_NEGOTIATION_TIMEOUT_SEC 3
203
#define PROXY_NEGOTIATION_TIMEOUT_USEC 0
204
#endif
205
206
/* Fixed option values for all PCRE functions */
194
/* Fixed option values for all PCRE functions */
207
195
208
#define PCRE_COPT 0   /* compile */
196
#define PCRE_COPT 0   /* compile */
Lines 210-217 Link Here
210
198
211
/* Macros for trivial functions */
199
/* Macros for trivial functions */
212
200
213
#define mac_ismsgid(s) \
201
#define mac_ismsgid(s)	(regex_match(regex_ismsgid, (s), -1, NULL))
214
  (pcre_exec(regex_ismsgid,NULL,CS s,Ustrlen(s),0,PCRE_EOPT,NULL,0) >= 0)
215
202
216
203
217
/* Options for dns_next_rr */
204
/* Options for dns_next_rr */
Lines 313-319 Link Here
313
#define DELIVER_MUA_FAILED         2  /* Failure when mua_wrapper is set */
300
#define DELIVER_MUA_FAILED         2  /* Failure when mua_wrapper is set */
314
#define DELIVER_NOT_ATTEMPTED      3  /* Not tried (no msg or is locked */
301
#define DELIVER_NOT_ATTEMPTED      3  /* Not tried (no msg or is locked */
315
302
316
/* Returns from DNS lookup functions. */
303
/* Returns from DNS lookup functions. Use dns_rc_names[] for debug strings */
317
304
318
enum { DNS_SUCCEED, DNS_NOMATCH, DNS_NODATA, DNS_AGAIN, DNS_FAIL };
305
enum { DNS_SUCCEED, DNS_NOMATCH, DNS_NODATA, DNS_AGAIN, DNS_FAIL };
319
306
Lines 436-441 Link Here
436
                                         D_timestamp   | \
423
                                         D_timestamp   | \
437
                                         D_resolver))
424
                                         D_resolver))
438
425
426
/* Bits for debug triggers */
427
428
enum {
429
  DTi_panictrigger,
430
  DTi_pretrigger,
431
};
432
439
/* Options bits for logging. Those that have values < BITWORDSIZE can be used
433
/* Options bits for logging. Those that have values < BITWORDSIZE can be used
440
in calls to log_write(). The others are put into later words in log_selector
434
in calls to log_write(). The others are put into later words in log_selector
441
and are only ever tested independently, so they do not need bit mask
435
and are only ever tested independently, so they do not need bit mask
Lines 483-490 Link Here
483
  Li_outgoing_port,
477
  Li_outgoing_port,
484
  Li_pid,
478
  Li_pid,
485
  Li_pipelining,
479
  Li_pipelining,
480
  Li_protocol_detail,
486
  Li_proxy,
481
  Li_proxy,
487
  Li_queue_time,
482
  Li_queue_time,
483
  Li_queue_time_exclusive,
488
  Li_queue_time_overall,
484
  Li_queue_time_overall,
489
  Li_receive_time,
485
  Li_receive_time,
490
  Li_received_sender,
486
  Li_received_sender,
Lines 563-581 Link Here
563
#define ERRNO_AUTHPROB       (-48)   /* Authenticator "other" failure */
559
#define ERRNO_AUTHPROB       (-48)   /* Authenticator "other" failure */
564
#define ERRNO_UTF8_FWD       (-49)   /* target not supporting SMTPUTF8 */
560
#define ERRNO_UTF8_FWD       (-49)   /* target not supporting SMTPUTF8 */
565
#define ERRNO_HOST_IS_LOCAL  (-50)   /* Transport refuses to talk to localhost */
561
#define ERRNO_HOST_IS_LOCAL  (-50)   /* Transport refuses to talk to localhost */
562
#define ERRNO_TAINT          (-51)   /* Transport refuses to talk use tainted filename */
566
563
567
/* These must be last, so all retry deferments can easily be identified */
564
/* These must be last, so all retry deferments can easily be identified */
568
565
569
#define ERRNO_RETRY_BASE     (-51)   /* Base to test against */
566
#define ERRNO_RETRY_BASE     (-52)   /* Base to test against */
570
#define ERRNO_RRETRY         (-51)   /* Not time for routing */
567
#define ERRNO_RRETRY         (-52)   /* Not time for routing */
571
568
572
#define ERRNO_WARN_BASE      (-52)   /* Base to test against */
569
#define ERRNO_WARN_BASE      (-53)   /* Base to test against */
573
#define ERRNO_LRETRY         (-52)   /* Not time for local delivery */
570
#define ERRNO_LRETRY         (-53)   /* Not time for local delivery */
574
#define ERRNO_HRETRY         (-53)   /* Not time for any remote host */
571
#define ERRNO_HRETRY         (-54)   /* Not time for any remote host */
575
#define ERRNO_LOCAL_ONLY     (-54)   /* Local-only delivery */
572
#define ERRNO_LOCAL_ONLY     (-55)   /* Local-only delivery */
576
#define ERRNO_QUEUE_DOMAIN   (-55)   /* Domain in queue_domains */
573
#define ERRNO_QUEUE_DOMAIN   (-56)   /* Domain in queue_domains */
577
#define ERRNO_TRETRY         (-56)   /* Transport concurrency limit */
574
#define ERRNO_TRETRY         (-57)   /* Transport concurrency limit */
578
#define ERRNO_EVENT	     (-57)   /* Event processing request alternate response */
575
#define ERRNO_EVENT	     (-58)   /* Event processing request alternate response */
579
576
580
577
581
578
Lines 739-744 Link Here
739
#define vopt_callout_recippmaster 0x0100   /* use postmaster to verify recip */
736
#define vopt_callout_recippmaster 0x0100   /* use postmaster to verify recip */
740
#define vopt_callout_hold	  0x0200   /* lazy close connection */
737
#define vopt_callout_hold	  0x0200   /* lazy close connection */
741
#define vopt_success_on_redirect  0x0400
738
#define vopt_success_on_redirect  0x0400
739
#define vopt_quota                0x0800   /* quota check, to local/appendfile */
742
740
743
/* Values for fields in callout cache records */
741
/* Values for fields in callout cache records */
744
742
Lines 869-890 Link Here
869
867
870
/* Options for transport_write_message */
868
/* Options for transport_write_message */
871
869
872
#define topt_add_return_path    0x001
870
#define topt_add_return_path    0x0001
873
#define topt_add_delivery_date  0x002
871
#define topt_add_delivery_date  0x0002
874
#define topt_add_envelope_to    0x004
872
#define topt_add_envelope_to    0x0004
875
#define topt_use_crlf           0x008  /* Terminate lines with CRLF */
873
#define topt_escape_headers     0x0008	/* Apply escape check to headers */
876
#define topt_end_dot            0x010  /* Send terminating dot line */
874
#define topt_use_crlf           0x0010	/* Terminate lines with CRLF */
877
#define topt_no_headers         0x020  /* Omit headers */
875
#define topt_no_headers         0x0020	/* Omit headers */
878
#define topt_no_body            0x040  /* Omit body */
876
#define topt_no_body            0x0040	/* Omit body */
879
#define topt_escape_headers     0x080  /* Apply escape check to headers */
877
#define topt_end_dot            0x0080	/* Send terminating dot line */
880
#define topt_use_bdat		0x100  /* prepend chunks with RFC3030 BDAT header */
878
#define topt_no_flush		0x0100	/* more data expected after message (eg QUIT) */
881
#define topt_output_string	0x200  /* create string rather than write to fd */
879
#define topt_use_bdat		0x0200	/* prepend chunks with RFC3030 BDAT header */
882
#define topt_continuation	0x400  /* do not reset buffer */
880
#define topt_output_string	0x0400	/* create string rather than write to fd */
883
#define topt_not_socket		0x800  /* cannot do socket-only syscalls */
881
#define topt_continuation	0x0800	/* do not reset buffer */
882
#define topt_not_socket		0x1000	/* cannot do socket-only syscalls */
884
883
885
/* Options for smtp_write_command */
884
/* Options for smtp_write_command */
886
885
887
enum {	
886
enum {
888
  SCMD_FLUSH = 0,	/* write to kernel */
887
  SCMD_FLUSH = 0,	/* write to kernel */
889
  SCMD_MORE,		/* write to kernel, but likely more soon */
888
  SCMD_MORE,		/* write to kernel, but likely more soon */
890
  SCMD_BUFFER		/* stash in application cmd output buffer */
889
  SCMD_BUFFER		/* stash in application cmd output buffer */
Lines 976-982 Link Here
976
#define ACL_BIT_MIME		BIT(ACL_WHERE_MIME)
975
#define ACL_BIT_MIME		BIT(ACL_WHERE_MIME)
977
#define ACL_BIT_DKIM		BIT(ACL_WHERE_DKIM)
976
#define ACL_BIT_DKIM		BIT(ACL_WHERE_DKIM)
978
#define ACL_BIT_DATA		BIT(ACL_WHERE_DATA)
977
#define ACL_BIT_DATA		BIT(ACL_WHERE_DATA)
979
#ifndef DISABLE_PRDR
978
#ifdef DISABLE_PRDR
979
# define ACL_BIT_PRDR		0
980
#else
980
# define ACL_BIT_PRDR		BIT(ACL_WHERE_PRDR)
981
# define ACL_BIT_PRDR		BIT(ACL_WHERE_PRDR)
981
#endif
982
#endif
982
#define ACL_BIT_NOTSMTP		BIT(ACL_WHERE_NOTSMTP)
983
#define ACL_BIT_NOTSMTP		BIT(ACL_WHERE_NOTSMTP)
Lines 994-999 Link Here
994
#define ACL_BIT_DELIVERY	BIT(ACL_WHERE_DELIVERY)
995
#define ACL_BIT_DELIVERY	BIT(ACL_WHERE_DELIVERY)
995
#define ACL_BIT_UNKNOWN		BIT(ACL_WHERE_UNKNOWN)
996
#define ACL_BIT_UNKNOWN		BIT(ACL_WHERE_UNKNOWN)
996
997
998
#define ACL_BITS_HAVEDATA	(ACL_BIT_MIME | ACL_BIT_DKIM | ACL_BIT_DATA \
999
				| ACL_BIT_PRDR \
1000
				| ACL_BIT_NOTSMTP | ACL_BIT_QUIT | ACL_BIT_NOTQUIT)
1001
997
1002
998
/* Situations for spool_write_header() */
1003
/* Situations for spool_write_header() */
999
1004
Lines 1047-1055 Link Here
1047
1052
1048
1053
1049
/* Options on tls_close */
1054
/* Options on tls_close */
1050
#define TLS_NO_SHUTDOWN		0
1055
#define TLS_NO_SHUTDOWN		0	/* Just forget the context */
1051
#define TLS_SHUTDOWN_NOWAIT	1
1056
#define TLS_SHUTDOWN_NOWAIT	1	/* Send alert; do not wait */
1052
#define TLS_SHUTDOWN_WAIT	2
1057
#define TLS_SHUTDOWN_WAIT	2	/* Send alert & wait for peer's alert */
1058
#define TLS_SHUTDOWN_WONLY	3	/* only wait for peer's alert */
1053
1059
1054
1060
1055
#ifdef COMPILE_UTILITY
1061
#ifdef COMPILE_UTILITY
Lines 1070-1077 Link Here
1070
1076
1071
#define AUTHS_REGEX US"\\n250[\\s\\-]AUTH\\s+([\\-\\w \\t]+)(?:\\n|$)"
1077
#define AUTHS_REGEX US"\\n250[\\s\\-]AUTH\\s+([\\-\\w \\t]+)(?:\\n|$)"
1072
1078
1073
#define EARLY_PIPE_FEATURE_NAME "PIPE_CONNECT"
1079
#define EARLY_PIPE_FEATURE_NAME "PIPECONNECT"
1074
#define EARLY_PIPE_FEATURE_LEN  12
1080
#define EARLY_PIPE_FEATURE_LEN  11
1075
1081
1076
1082
1077
/* Flags for auth_client_item() */
1083
/* Flags for auth_client_item() */
(-)exim.orig/src/malware.c (-115 / +144 lines)
Lines 2-10 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003 - 2015
5
/*
6
 * Copyright (c) The Exim Maintainers 2015 - 2022
7
 * Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003 - 2015
6
 * License: GPL
8
 * License: GPL
7
 * Copyright (c) The Exim Maintainers 2015 - 2020
8
 */
9
 */
9
10
10
/* Code for calling virus (malware) scanners. Called from acl.c. */
11
/* Code for calling virus (malware) scanners. Called from acl.c. */
Lines 129-136 Link Here
129
#define MALWARE_TIMEOUT 120	/* default timeout, seconds */
130
#define MALWARE_TIMEOUT 120	/* default timeout, seconds */
130
131
131
static const uschar * malware_regex_default = US ".+";
132
static const uschar * malware_regex_default = US ".+";
132
static const pcre * malware_default_re = NULL;
133
static const pcre2_code * malware_default_re = NULL;
133
134
134
135
135
136
#ifndef DISABLE_MAL_CLAM
136
#ifndef DISABLE_MAL_CLAM
Lines 157-191 Link Here
157
# define DERR_BAD_CALL               (1<<15)  /* wrong command */
157
# define DERR_BAD_CALL               (1<<15)  /* wrong command */
158
158
159
static const uschar * drweb_re_str = US "infected\\swith\\s*(.+?)$";
159
static const uschar * drweb_re_str = US "infected\\swith\\s*(.+?)$";
160
static const pcre * drweb_re = NULL;
160
static const pcre2_code * drweb_re = NULL;
161
#endif
161
#endif
162
162
163
#ifndef DISABLE_MAL_FSECURE
163
#ifndef DISABLE_MAL_FSECURE
164
static const uschar * fsec_re_str = US "\\S{0,5}INFECTED\\t[^\\t]*\\t([^\\t]+)\\t\\S*$";
164
static const uschar * fsec_re_str = US "\\S{0,5}INFECTED\\t[^\\t]*\\t([^\\t]+)\\t\\S*$";
165
static const pcre * fsec_re = NULL;
165
static const pcre2_code * fsec_re = NULL;
166
#endif
166
#endif
167
167
168
#ifndef DISABLE_MAL_KAV
168
#ifndef DISABLE_MAL_KAV
169
static const uschar * kav_re_sus_str = US "suspicion:\\s*(.+?)\\s*$";
169
static const uschar * kav_re_sus_str = US "suspicion:\\s*(.+?)\\s*$";
170
static const uschar * kav_re_inf_str = US "infected:\\s*(.+?)\\s*$";
170
static const uschar * kav_re_inf_str = US "infected:\\s*(.+?)\\s*$";
171
static const pcre * kav_re_sus = NULL;
171
static const pcre2_code * kav_re_sus = NULL;
172
static const pcre * kav_re_inf = NULL;
172
static const pcre2_code * kav_re_inf = NULL;
173
#endif
173
#endif
174
174
175
#ifndef DISABLE_MAL_AVAST
175
#ifndef DISABLE_MAL_AVAST
176
static const uschar * ava_re_clean_str = US "(?!\\\\)\\t\\[\\+\\]";
176
static const uschar * ava_re_clean_str = US "(?!\\\\)\\t\\[\\+\\]";
177
static const uschar * ava_re_virus_str = US "(?!\\\\)\\t\\[L\\]\\d+\\.0\\t0\\s(.*)";
177
static const uschar * ava_re_virus_str = US "(?!\\\\)\\t\\[L\\]\\d+\\.0\\t0\\s(.*)";
178
static const uschar * ava_re_error_str = US "(?!\\\\)\\t\\[E\\]\\d+\\.0\\tError\\s\\d+\\s(.*)";
178
static const uschar * ava_re_error_str = US "(?!\\\\)\\t\\[E\\]\\d+\\.0\\tError\\s\\d+\\s(.*)";
179
static const pcre * ava_re_clean = NULL;
179
static const pcre2_code * ava_re_clean = NULL;
180
static const pcre * ava_re_virus = NULL;
180
static const pcre2_code * ava_re_virus = NULL;
181
static const pcre * ava_re_error = NULL;
181
static const pcre2_code * ava_re_error = NULL;
182
#endif
182
#endif
183
183
184
#ifndef DISABLE_MAL_FFROT6D
184
#ifndef DISABLE_MAL_FFROT6D
185
static const uschar * fprot6d_re_error_str = US "^\\d+\\s<(.+?)>$";
185
static const uschar * fprot6d_re_error_str = US "^\\d+\\s<(.+?)>$";
186
static const uschar * fprot6d_re_virus_str = US "^\\d+\\s<infected:\\s+(.+?)>\\s+.+$";
186
static const uschar * fprot6d_re_virus_str = US "^\\d+\\s<infected:\\s+(.+?)>\\s+.+$";
187
static const pcre * fprot6d_re_error = NULL;
187
static const pcre2_code * fprot6d_re_error = NULL;
188
static const pcre * fprot6d_re_virus = NULL;
188
static const pcre2_code * fprot6d_re_virus = NULL;
189
#endif
189
#endif
190
190
191
191
Lines 220-225 Link Here
220
/* Some (currently avast only) use backslash escaped whitespace,
220
/* Some (currently avast only) use backslash escaped whitespace,
221
this function undoes these escapes */
221
this function undoes these escapes */
222
222
223
#ifndef DISABLE_MAL_AVAST
223
static inline void
224
static inline void
224
unescape(uschar *p)
225
unescape(uschar *p)
225
{
226
{
Lines 228-233 Link Here
228
  if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
229
  if (*p == '\\' && (isspace(p[1]) || p[1] == '\\'))
229
    for (p0 = p; *p0; ++p0) *p0 = p0[1];
230
    for (p0 = p; *p0; ++p0) *p0 = p0[1];
230
}
231
}
232
#endif
231
233
232
/* --- malware_*_defer --- */
234
/* --- malware_*_defer --- */
233
static inline int
235
static inline int
Lines 250-262 Link Here
250
return malware_panic_defer(string_sprintf("%s %s : %s",
252
return malware_panic_defer(string_sprintf("%s %s : %s",
251
  scanent->name, hostport ? hostport : CUS"", str));
253
  scanent->name, hostport ? hostport : CUS"", str));
252
}
254
}
253
static inline int
254
m_log_defer(struct scan * scanent, const uschar * hostport,
255
  const uschar * str)
256
{
257
return malware_log_defer(string_sprintf("%s %s : %s",
258
  scanent->name, hostport ? hostport : CUS"", str));
259
}
260
/* --- m_*_defer_3 */
255
/* --- m_*_defer_3 */
261
static inline int
256
static inline int
262
m_panic_defer_3(struct scan * scanent, const uschar * hostport,
257
m_panic_defer_3(struct scan * scanent, const uschar * hostport,
Lines 277-284 Link Here
277
m_tcpsocket(const uschar * hostname, unsigned int port,
272
m_tcpsocket(const uschar * hostname, unsigned int port,
278
	host_item * host, uschar ** errstr, const blob * fastopen_blob)
273
	host_item * host, uschar ** errstr, const blob * fastopen_blob)
279
{
274
{
280
return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
275
int fd = ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
281
			  host, errstr, fastopen_blob);
276
			  host, errstr, fastopen_blob);
277
#ifdef EXIM_TFO_FREEBSD
278
/* Under some fault conditions, FreeBSD 12.2 seen to send a (non-TFO) SYN
279
and, getting no response, wait for a long time.  Impose a 5s max. */
280
if (fd >= 0)
281
  (void) poll_one_fd(fd, POLLOUT, 5 * 1000);
282
#endif
283
return fd;
282
}
284
}
283
#endif
285
#endif
284
286
Lines 296-332 Link Here
296
return sock;
298
return sock;
297
}
299
}
298
300
299
static const pcre *
301
static const pcre2_code *
300
m_pcre_compile(const uschar * re, uschar ** errstr)
302
m_pcre_compile(const uschar * re, uschar ** errstr)
301
{
303
{
302
const uschar * rerror;
304
int err;
303
int roffset;
305
PCRE2_SIZE roffset;
304
const pcre * cre;
306
const pcre2_code * cre;
305
307
306
if (!(cre = pcre_compile(CS re, PCRE_COPT, CCSS &rerror, &roffset, NULL)))
308
if (!(cre = pcre2_compile((PCRE2_SPTR)re, PCRE2_ZERO_TERMINATED,
307
  *errstr= string_sprintf("regular expression error in '%s': %s at offset %d",
309
	      PCRE_COPT, &err, &roffset, pcre_cmp_ctx)))
308
      re, rerror, roffset);
310
  {
311
  uschar errbuf[128];
312
  pcre2_get_error_message(err, errbuf, sizeof(errbuf));
313
  *errstr= string_sprintf("regular expression error in '%s': %s at offset %ld",
314
      re, errbuf, (long)roffset);
315
  }
309
return cre;
316
return cre;
310
}
317
}
311
318
312
uschar *
319
uschar *
313
m_pcre_exec(const pcre * cre, uschar * text)
320
m_pcre_exec(const pcre2_code * cre, uschar * text)
314
{
321
{
315
int ovector[10*3];
322
pcre2_match_data * md = pcre2_match_data_create(2, pcre_gen_ctx);
316
int i = pcre_exec(cre, NULL, CS text, Ustrlen(text), 0, 0,
323
int i = pcre2_match(cre, text, PCRE2_ZERO_TERMINATED, 0, 0, md, pcre_mtc_ctx);
317
	      ovector, nelem(ovector));
324
PCRE2_UCHAR * substr = NULL;
318
uschar * substr = NULL;
325
PCRE2_SIZE slen;
326
319
if (i >= 2)				/* Got it */
327
if (i >= 2)				/* Got it */
320
  pcre_get_substring(CS text, ovector, i, 1, CCSS &substr);
328
  pcre2_substring_get_bynumber(md, 1, &substr, &slen);
321
return substr;
329
return US substr;
322
}
330
}
323
331
324
static const pcre *
332
static const pcre2_code *
325
m_pcre_nextinlist(const uschar ** list, int * sep,
333
m_pcre_nextinlist(const uschar ** list, int * sep,
326
 char * listerr, uschar ** errstr)
334
 char * listerr, uschar ** errstr)
327
{
335
{
328
const uschar * list_ele;
336
const uschar * list_ele;
329
const pcre * cre = NULL;
337
const pcre2_code * cre = NULL;
330
338
331
if (!(list_ele = string_nextinlist(list, sep, NULL, 0)))
339
if (!(list_ele = string_nextinlist(list, sep, NULL, 0)))
332
  *errstr = US listerr;
340
  *errstr = US listerr;
Lines 386-391 Link Here
386
}
394
}
387
395
388
/* return TRUE iff size as requested */
396
/* return TRUE iff size as requested */
397
#ifndef DISABLE_MAL_DRWEB
389
static BOOL
398
static BOOL
390
recv_len(int sock, void * buf, int size, time_t tmo)
399
recv_len(int sock, void * buf, int size, time_t tmo)
391
{
400
{
Lines 393-398 Link Here
393
  ? recv(sock, buf, size, 0) == size
402
  ? recv(sock, buf, size, 0) == size
394
  : FALSE;
403
  : FALSE;
395
}
404
}
405
#endif
396
406
397
407
398
408
Lines 574-580 Link Here
574
uschar *scanner_name;
584
uschar *scanner_name;
575
unsigned long mbox_size;
585
unsigned long mbox_size;
576
FILE *mbox_file;
586
FILE *mbox_file;
577
const pcre *re;
587
const pcre2_code *re;
578
uschar * errstr;
588
uschar * errstr;
579
struct scan * scanent;
589
struct scan * scanent;
580
const uschar * scanner_options;
590
const uschar * scanner_options;
Lines 916-922 Link Here
916
	/* read and concatenate virus names into one string */
926
	/* read and concatenate virus names into one string */
917
	for (int i = 0; i < drweb_vnum; i++)
927
	for (int i = 0; i < drweb_vnum; i++)
918
	  {
928
	  {
919
	  int ovector[10*3];
929
	  pcre2_match_data * md = pcre2_match_data_create(2, pcre_gen_ctx);
920
930
921
	  /* read the size of report */
931
	  /* read the size of report */
922
	  if (!recv_len(malware_daemon_ctx.sock, &drweb_slen, sizeof(drweb_slen), tmo))
932
	  if (!recv_len(malware_daemon_ctx.sock, &drweb_slen, sizeof(drweb_slen), tmo))
Lines 925-931 Link Here
925
	  drweb_slen = ntohl(drweb_slen);
935
	  drweb_slen = ntohl(drweb_slen);
926
936
927
	  /* assume tainted, since it is external input */
937
	  /* assume tainted, since it is external input */
928
	  tmpbuf = store_get(drweb_slen, TRUE);
938
	  tmpbuf = store_get(drweb_slen, GET_TAINTED);
929
939
930
	  /* read report body */
940
	  /* read report body */
931
	  if (!recv_len(malware_daemon_ctx.sock, tmpbuf, drweb_slen, tmo))
941
	  if (!recv_len(malware_daemon_ctx.sock, tmpbuf, drweb_slen, tmo))
Lines 934-955 Link Here
934
	  tmpbuf[drweb_slen] = '\0';
944
	  tmpbuf[drweb_slen] = '\0';
935
945
936
	  /* try matcher on the line, grab substring */
946
	  /* try matcher on the line, grab substring */
937
	  result = pcre_exec(drweb_re, NULL, CS tmpbuf, Ustrlen(tmpbuf), 0, 0,
947
	  result = pcre2_match(drweb_re, (PCRE2_SPTR)tmpbuf, PCRE2_ZERO_TERMINATED,
938
				  ovector, nelem(ovector));
948
				0, 0, md, pcre_mtc_ctx);
939
	  if (result >= 2)
949
	  if (result >= 2)
940
	    {
950
	    {
941
	    const char * pre_malware_nb;
951
	    PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md);
942
943
	    pcre_get_substring(CS tmpbuf, ovector, result, 1, &pre_malware_nb);
944
952
945
	    if (i==0)	/* the first name we just copy to malware_name */
953
	    if (i==0)	/* the first name we just copy to malware_name */
946
	      g = string_cat(NULL, US pre_malware_nb);
954
	      g = string_catn(NULL, US ovec[2], ovec[3] - ovec[2]);
947
955
948
	    /*XXX could be string_append_listele? */
949
	    else	/* concatenate each new virus name to previous */
956
	    else	/* concatenate each new virus name to previous */
950
	      g = string_append(g, 2, "/", pre_malware_nb);
957
	      {
951
958
	      g = string_catn(g, US"/", 1);
952
	    pcre_free_substring(pre_malware_nb);
959
	      g = string_catn(g, US ovec[2], ovec[3] - ovec[2]);
960
	      }
953
	    }
961
	    }
954
	  }
962
	  }
955
	  malware_name = string_from_gstring(g);
963
	  malware_name = string_from_gstring(g);
Lines 1142-1148 Link Here
1142
      int kav_rc;
1150
      int kav_rc;
1143
      unsigned long kav_reportlen;
1151
      unsigned long kav_reportlen;
1144
      int bread;
1152
      int bread;
1145
      const pcre *kav_re;
1153
      const pcre2_code *kav_re;
1146
      uschar *p;
1154
      uschar *p;
1147
1155
1148
      /* get current date and time, build scan request */
1156
      /* get current date and time, build scan request */
Lines 1251-1258 Link Here
1251
    case M_CMDL: /* "cmdline" scanner type ---------------------------------- */
1259
    case M_CMDL: /* "cmdline" scanner type ---------------------------------- */
1252
      {
1260
      {
1253
      const uschar *cmdline_scanner = scanner_options;
1261
      const uschar *cmdline_scanner = scanner_options;
1254
      const pcre *cmdline_trigger_re;
1262
      const pcre2_code *cmdline_trigger_re;
1255
      const pcre *cmdline_regex_re;
1263
      const pcre2_code *cmdline_regex_re;
1256
      uschar * file_name;
1264
      uschar * file_name;
1257
      uschar * commandline;
1265
      uschar * commandline;
1258
      void (*eximsigchld)(int);
1266
      void (*eximsigchld)(int);
Lines 1446-1454 Link Here
1446
      uschar av_buffer[1024];
1454
      uschar av_buffer[1024];
1447
      uschar *hostname = US"";
1455
      uschar *hostname = US"";
1448
      host_item connhost;
1456
      host_item connhost;
1449
      uschar *clamav_fbuf;
1457
      int clam_fd;
1450
      int clam_fd, result;
1451
      off_t fsize;
1452
      unsigned int fsize_uint;
1458
      unsigned int fsize_uint;
1453
      BOOL use_scan_command = FALSE;
1459
      BOOL use_scan_command = FALSE;
1454
      clamd_address * cv[MAX_CLAMD_SERVERS];
1460
      clamd_address * cv[MAX_CLAMD_SERVERS];
Lines 1466-1474 Link Here
1466
	int subsep = ' ';
1472
	int subsep = ' ';
1467
1473
1468
	/* Local file; so we def want to use_scan_command and don't want to try
1474
	/* Local file; so we def want to use_scan_command and don't want to try
1469
	 * passing IP/port combinations */
1475
	passing IP/port combinations */
1470
	use_scan_command = TRUE;
1476
	use_scan_command = TRUE;
1471
	cd = (clamd_address *) store_get(sizeof(clamd_address), FALSE);
1477
	cd = (clamd_address *) store_get(sizeof(clamd_address), GET_UNTAINTED);
1472
1478
1473
	/* extract socket-path part */
1479
	/* extract socket-path part */
1474
	sublist = scanner_options;
1480
	sublist = scanner_options;
Lines 1502-1508 Link Here
1502
	    continue;
1508
	    continue;
1503
	    }
1509
	    }
1504
1510
1505
	  cd = (clamd_address *) store_get(sizeof(clamd_address), FALSE);
1511
	  cd = (clamd_address *) store_get(sizeof(clamd_address), GET_UNTAINTED);
1506
1512
1507
	  /* extract host and port part */
1513
	  /* extract host and port part */
1508
	  sublist = scanner_options;
1514
	  sublist = scanner_options;
Lines 1555-1570 Link Here
1555
	{ cmd_str.data = US"zINSTREAM"; cmd_str.len = 10; }
1561
	{ cmd_str.data = US"zINSTREAM"; cmd_str.len = 10; }
1556
      else
1562
      else
1557
	{
1563
	{
1558
	cmd_str.data = string_sprintf("SCAN %s\n", eml_filename);
1564
	int n;
1559
	cmd_str.len = Ustrlen(cmd_str.data);
1565
	cmd_str.data = string_sprintf("SCAN %s\n%n", eml_filename, &n);
1566
	cmd_str.len = n;		/* .len is a size_t */
1560
	}
1567
	}
1561
1568
1562
      /* We have some network servers specified */
1569
      /* We have some network servers specified */
1563
      if (num_servers)
1570
      if (num_servers)
1564
	{
1571
	{
1565
	/* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
1572
	/* Confirmed in ClamAV source (0.95.3) that the TCPAddr option of clamd
1566
	 * only supports AF_INET, but we should probably be looking to the
1573
	only supports AF_INET, but we should probably be looking to the
1567
	 * future and rewriting this to be protocol-independent anyway. */
1574
	future and rewriting this to be protocol-independent anyway. */
1568
1575
1569
	while (num_servers > 0)
1576
	while (num_servers > 0)
1570
	  {
1577
	  {
Lines 1575-1590 Link Here
1575
			 cd->hostspec, cd->tcp_port);
1582
			 cd->hostspec, cd->tcp_port);
1576
1583
1577
	  /* Lookup the host. This is to ensure that we connect to the same IP
1584
	  /* Lookup the host. This is to ensure that we connect to the same IP
1578
	   * on both connections (as one host could resolve to multiple ips) */
1585
	  on both connections (as one host could resolve to multiple ips) */
1579
	  for (;;)
1586
	  for (;;)
1580
	    {
1587
	    {
1581
	    /*XXX we trust that the cmd_str is ideempotent */
1588
	    /*XXX we trust that the cmd_str is idempotent */
1582
	    if ((malware_daemon_ctx.sock = m_tcpsocket(cd->hostspec, cd->tcp_port,
1589
	    if ((malware_daemon_ctx.sock = m_tcpsocket(cd->hostspec, cd->tcp_port,
1583
				    &connhost, &errstr, &cmd_str)) >= 0)
1590
				    &connhost, &errstr,
1591
				    use_scan_command ? &cmd_str : NULL)) >= 0)
1584
	      {
1592
	      {
1585
	      /* Connection successfully established with a server */
1593
	      /* Connection successfully established with a server */
1586
	      hostname = cd->hostspec;
1594
	      hostname = cd->hostspec;
1587
	      cmd_str.len = 0;
1595
	      if (use_scan_command) cmd_str.len = 0;
1588
	      break;
1596
	      break;
1589
	      }
1597
	      }
1590
	    if (cd->retry <= 0) break;
1598
	    if (cd->retry <= 0) break;
Lines 1618-1637 Link Here
1618
	  }
1626
	  }
1619
1627
1620
      /* have socket in variable "sock"; command to use is semi-independent of
1628
      /* have socket in variable "sock"; command to use is semi-independent of
1621
       * the socket protocol.  We use SCAN if is local (either Unix/local
1629
      the socket protocol.  We use SCAN if is local (either Unix/local
1622
       * domain socket, or explicitly told local) else we stream the data.
1630
      domain socket, or explicitly told local) else we stream the data.
1623
       * How we stream the data depends upon how we were built.  */
1631
      How we stream the data depends upon how we were built.  */
1624
1632
1625
      if (!use_scan_command)
1633
      if (!use_scan_command)
1626
	{
1634
	{
1635
	struct stat st;
1636
#if defined(EXIM_TCP_CORK) && !defined(OS_SENDFILE)
1637
	BOOL corked = TRUE;
1638
#endif
1627
	/* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
1639
	/* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
1628
	chunks, <n> a 4-byte number (network order), terminated by a zero-length
1640
	chunks, <n> a 4-byte number (network order), terminated by a zero-length
1629
	chunk. */
1641
	chunk. We only send one chunk. */
1630
1642
1631
	DEBUG(D_acl) debug_printf_indent(
1643
	DEBUG(D_acl) debug_printf_indent(
1632
	    "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
1644
	    "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
1633
	    scanner_name);
1645
	    scanner_name);
1634
1646
1647
#if defined(EXIM_TCP_CORK)
1648
	(void) setsockopt(malware_daemon_ctx.sock, IPPROTO_TCP, EXIM_TCP_CORK,
1649
			  US &on, sizeof(on));
1650
#endif
1635
	/* Pass the string to ClamAV (10 = "zINSTREAM\0"), if not already sent */
1651
	/* Pass the string to ClamAV (10 = "zINSTREAM\0"), if not already sent */
1636
	if (cmd_str.len)
1652
	if (cmd_str.len)
1637
	  if (send(malware_daemon_ctx.sock, cmd_str.data, cmd_str.len, 0) < 0)
1653
	  if (send(malware_daemon_ctx.sock, cmd_str.data, cmd_str.len, 0) < 0)
Lines 1640-1646 Link Here
1640
		strerror(errno)),
1656
		strerror(errno)),
1641
	      malware_daemon_ctx.sock);
1657
	      malware_daemon_ctx.sock);
1642
1658
1643
	/* calc file size */
1644
	if ((clam_fd = exim_open2(CS eml_filename, O_RDONLY)) < 0)
1659
	if ((clam_fd = exim_open2(CS eml_filename, O_RDONLY)) < 0)
1645
	  {
1660
	  {
1646
	  int err = errno;
1661
	  int err = errno;
Lines 1649-1714 Link Here
1649
	      eml_filename, strerror(err)),
1664
	      eml_filename, strerror(err)),
1650
	    malware_daemon_ctx.sock);
1665
	    malware_daemon_ctx.sock);
1651
	  }
1666
	  }
1652
	if ((fsize = lseek(clam_fd, 0, SEEK_END)) < 0)
1667
	if (fstat(clam_fd, &st) < 0)
1653
	  {
1668
	  {
1654
	  int err;
1669
	  int err = errno;
1655
b_seek:   err = errno;
1656
	  (void)close(clam_fd);
1670
	  (void)close(clam_fd);
1657
	  return m_panic_defer_3(scanent, NULL,
1671
	  return m_panic_defer_3(scanent, NULL,
1658
	    string_sprintf("can't seek spool file %s: %s",
1672
	    string_sprintf("can't stat spool file %s: %s",
1659
	      eml_filename, strerror(err)),
1673
	      eml_filename, strerror(err)),
1660
	    malware_daemon_ctx.sock);
1674
	    malware_daemon_ctx.sock);
1661
	  }
1675
	  }
1662
	fsize_uint = (unsigned int) fsize;
1676
	fsize_uint = (unsigned int) st.st_size;
1663
	if ((off_t)fsize_uint != fsize)
1677
	if ((off_t)fsize_uint != st.st_size)
1664
	  {
1678
	  {
1665
	  (void)close(clam_fd);
1679
	  (void)close(clam_fd);
1666
	  return m_panic_defer_3(scanent, NULL,
1680
	  return m_panic_defer_3(scanent, NULL,
1667
	    string_sprintf("seeking spool file %s, size overflow",
1681
	    string_sprintf("stat spool file %s, size overflow", eml_filename),
1668
	      eml_filename),
1669
	    malware_daemon_ctx.sock);
1682
	    malware_daemon_ctx.sock);
1670
	  }
1683
	  }
1671
	if (lseek(clam_fd, 0, SEEK_SET) < 0)
1672
	  goto b_seek;
1673
1684
1674
	if (!(clamav_fbuf = store_malloc(fsize_uint)))
1685
	/* send file size */
1675
	  {
1686
	send_size = htonl(fsize_uint);
1676
	  (void)close(clam_fd);
1687
	if (send(malware_daemon_ctx.sock, &send_size, sizeof(send_size), 0) < 0)
1677
	  return m_panic_defer_3(scanent, NULL,
1688
	  return m_panic_defer_3(scanent, NULL,
1678
	    string_sprintf("unable to allocate memory %u for file (%s)",
1689
	    string_sprintf("unable to send file size to socket (%s)", hostname),
1679
	      fsize_uint, eml_filename),
1680
	    malware_daemon_ctx.sock);
1690
	    malware_daemon_ctx.sock);
1681
	  }
1682
1691
1683
	if ((result = read(clam_fd, clamav_fbuf, fsize_uint)) < 0)
1692
	/* send file body */
1693
	while (fsize_uint)
1684
	  {
1694
	  {
1685
	  int err = errno;
1695
#ifdef OS_SENDFILE
1686
	  store_free(clamav_fbuf); (void)close(clam_fd);
1696
	  int n = os_sendfile(malware_daemon_ctx.sock, clam_fd, NULL, (size_t)fsize_uint);
1687
	  return m_panic_defer_3(scanent, NULL,
1697
	  if (n < 0)
1688
	    string_sprintf("can't read spool file %s: %s",
1698
	    return m_panic_defer_3(scanent, NULL,
1689
	      eml_filename, strerror(err)),
1699
	      string_sprintf("unable to send file body to socket (%s): %s", hostname, strerror(errno)),
1690
	    malware_daemon_ctx.sock);
1700
	      malware_daemon_ctx.sock);
1701
	  fsize_uint -= n;
1702
#else
1703
	  int n = MIN(fsize_uint, big_buffer_size);
1704
	  if ((n = read(clam_fd, big_buffer, n)) < 0)
1705
	    return m_panic_defer_3(scanent, NULL,
1706
	      string_sprintf("can't read spool file %s: %s",
1707
		eml_filename, strerror(errno)),
1708
	      malware_daemon_ctx.sock);
1709
	  if (send(malware_daemon_ctx.sock, big_buffer, (size_t)n, 0) < 0)
1710
	    return m_panic_defer_3(scanent, NULL,
1711
	      string_sprintf("unable to send file body to socket (%s): %s", hostname, strerror(errno)),
1712
	      malware_daemon_ctx.sock);
1713
	  fsize_uint -= n;
1714
# ifdef EXIM_TCP_CORK
1715
	  if (corked)
1716
	    {
1717
	    corked = FALSE;
1718
	    (void) setsockopt(malware_daemon_ctx.sock, IPPROTO_TCP, EXIM_TCP_CORK,
1719
			      US &off, sizeof(off));
1720
	    }
1721
# endif
1722
#endif	/*!OS_SENDFILE*/
1723
1691
	  }
1724
	  }
1692
	(void)close(clam_fd);
1693
1725
1694
	/* send file body to socket */
1695
	send_size = htonl(fsize_uint);
1696
	send_final_zeroblock = 0;
1726
	send_final_zeroblock = 0;
1697
	if ((send(malware_daemon_ctx.sock, &send_size, sizeof(send_size), 0) < 0) ||
1727
	if (send(malware_daemon_ctx.sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0)
1698
	    (send(malware_daemon_ctx.sock, clamav_fbuf, fsize_uint, 0) < 0) ||
1699
	    (send(malware_daemon_ctx.sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0))
1700
	  {
1701
	  store_free(clamav_fbuf);
1702
	  return m_panic_defer_3(scanent, NULL,
1728
	  return m_panic_defer_3(scanent, NULL,
1703
	    string_sprintf("unable to send file body to socket (%s)", hostname),
1729
	    string_sprintf("unable to send file terminator to socket (%s)", hostname),
1704
	    malware_daemon_ctx.sock);
1730
	    malware_daemon_ctx.sock);
1705
	  }
1731
#ifdef OS_SENDFILE
1706
	store_free(clamav_fbuf);
1732
	(void) setsockopt(malware_daemon_ctx.sock, IPPROTO_TCP, EXIM_TCP_CORK,
1733
			  US &off, sizeof(off));
1734
#endif
1707
	}
1735
	}
1708
      else
1736
      else
1709
	{ /* use scan command */
1737
	{ /* use scan command */
1710
	/* Send a SCAN command pointing to a filename; then in the then in the
1738
	/* Send a SCAN command pointing to a filename; then in the then in the
1711
	 * scan-method-neutral part, read the response back */
1739
	scan-method-neutral part, read the response back */
1712
1740
1713
/* ================================================================= */
1741
/* ================================================================= */
1714
1742
Lines 1733-1742 Link Here
1733
	      malware_daemon_ctx.sock);
1761
	      malware_daemon_ctx.sock);
1734
1762
1735
	/* Do not shut down the socket for writing; a user report noted that
1763
	/* Do not shut down the socket for writing; a user report noted that
1736
	 * clamd 0.70 does not react well to this. */
1764
	clamd 0.70 does not react well to this. */
1737
	}
1765
	}
1738
      /* Commands have been sent, no matter which scan method or connection
1766
      /* Commands have been sent, no matter which scan method or connection
1739
       * type we're using; now just read the result, independent of method. */
1767
      type we're using; now just read the result, independent of method. */
1740
1768
1741
      /* Read the result */
1769
      /* Read the result */
1742
      memset(av_buffer, 0, sizeof(av_buffer));
1770
      memset(av_buffer, 0, sizeof(av_buffer));
Lines 1782-1787 Link Here
1782
      /* strip newline at the end (won't be present for zINSTREAM)
1810
      /* strip newline at the end (won't be present for zINSTREAM)
1783
      (also any trailing whitespace, which shouldn't exist, but we depend upon
1811
      (also any trailing whitespace, which shouldn't exist, but we depend upon
1784
      this below, so double-check) */
1812
      this below, so double-check) */
1813
1785
      p = av_buffer + Ustrlen(av_buffer) - 1;
1814
      p = av_buffer + Ustrlen(av_buffer) - 1;
1786
      if (*p == '\n') *p = '\0';
1815
      if (*p == '\n') *p = '\0';
1787
1816
Lines 1792-1798 Link Here
1792
      if (*p) ++p;
1821
      if (*p) ++p;
1793
1822
1794
      /* colon in returned output? */
1823
      /* colon in returned output? */
1795
      if(!(p = Ustrchr(av_buffer,':')))
1824
      if (!(p = Ustrchr(av_buffer,':')))
1796
	return m_panic_defer(scanent, CUS callout_address, string_sprintf(
1825
	return m_panic_defer(scanent, CUS callout_address, string_sprintf(
1797
		  "ClamAV returned malformed result (missing colon): %s",
1826
		  "ClamAV returned malformed result (missing colon): %s",
1798
		  av_buffer));
1827
		  av_buffer));
Lines 1856-1863 Link Here
1856
      uschar * linebuffer;
1885
      uschar * linebuffer;
1857
      uschar * sockline_scanner;
1886
      uschar * sockline_scanner;
1858
      uschar sockline_scanner_default[] = "%s\n";
1887
      uschar sockline_scanner_default[] = "%s\n";
1859
      const pcre *sockline_trig_re;
1888
      const pcre2_code *sockline_trig_re;
1860
      const pcre *sockline_name_re;
1889
      const pcre2_code *sockline_name_re;
1861
1890
1862
      /* find scanner command line */
1891
      /* find scanner command line */
1863
      if (  (sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
1892
      if (  (sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
Lines 2096-2102 Link Here
2096
              if (malware_name)     /* Nothing else matters, just read on */
2125
              if (malware_name)     /* Nothing else matters, just read on */
2097
                break;
2126
                break;
2098
2127
2099
	      if (pcre_exec(ava_re_clean, NULL, CS buf, slen, 0, 0, NULL, 0) == 0)
2128
	      if (regex_match(ava_re_clean, buf, slen, NULL))
2100
		break;
2129
		break;
2101
2130
2102
              if ((malware_name = m_pcre_exec(ava_re_virus, buf)))
2131
              if ((malware_name = m_pcre_exec(ava_re_virus, buf)))
Lines 2117-2123 Link Here
2117
                  break;
2146
                  break;
2118
                  }
2147
                  }
2119
                }
2148
                }
2120
              else if (pcre_exec(ava_re_error, NULL, CS buf, slen, 0, 0, NULL, 0) == 0)
2149
              else if (regex_match(ava_re_error, buf, slen, NULL))
2121
                {
2150
                {
2122
                log_write(0, LOG_MAIN, "internal scanner error (ignored): %s", buf);
2151
                log_write(0, LOG_MAIN, "internal scanner error (ignored): %s", buf);
2123
                break;
2152
                break;
(-)exim.orig/src/match.c (-77 / +75 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Functions for matching strings */
9
/* Functions for matching strings */
Lines 104-111 Link Here
104
uschar *keyquery, *result, *semicolon;
104
uschar *keyquery, *result, *semicolon;
105
void *handle;
105
void *handle;
106
106
107
error = error;  /* Keep clever compilers from complaining */
108
109
if (valueptr) *valueptr = NULL;
107
if (valueptr) *valueptr = NULL;
110
108
111
/* For regular expressions, use cb->origsubject rather than cb->subject so that
109
/* For regular expressions, use cb->origsubject rather than cb->subject so that
Lines 130-138 Link Here
130
128
131
if (pattern[0] == '^')
129
if (pattern[0] == '^')
132
  {
130
  {
133
  const pcre * re = regex_must_compile(pattern, cb->caseless, FALSE);
131
  const pcre2_code * re = regex_must_compile(pattern, cb->caseless, FALSE);
134
  if (expand_setup < 0
132
  if (expand_setup < 0
135
      ? pcre_exec(re, NULL, CCS s, Ustrlen(s), 0, PCRE_EOPT, NULL, 0) < 0
133
      ? !regex_match(re, s, -1, NULL)
136
      : !regex_match_and_setup(re, s, 0, expand_setup)
134
      : !regex_match_and_setup(re, s, 0, expand_setup)
137
     )
135
     )
138
    return FAIL;
136
    return FAIL;
Lines 286-307 Link Here
286
284
287
/* Set the parameters for the three different kinds of lookup. */
285
/* Set the parameters for the three different kinds of lookup. */
288
286
289
keyquery = semicolon + 1;
287
keyquery = search_args(search_type, s, semicolon+1, &filename, opts);
290
Uskip_whitespace(&keyquery);
291
292
if (mac_islookup(search_type, lookup_absfilequery))
293
  {
294
  filename = keyquery;
295
  while (*keyquery && !isspace(*keyquery)) keyquery++;
296
  filename = string_copyn(filename, keyquery - filename);
297
  Uskip_whitespace(&keyquery);
298
  }
299
300
else if (!mac_islookup(search_type, lookup_querystyle))
301
  {
302
  filename = keyquery;
303
  keyquery = s;
304
  }
305
288
306
/* Now do the actual lookup; throw away the data returned unless it was asked
289
/* Now do the actual lookup; throw away the data returned unless it was asked
307
for; partial matching is all handled inside search_find(). Note that there is
290
for; partial matching is all handled inside search_find(). Note that there is
Lines 449-459 Link Here
449
  void *arg, int type, const uschar *name, const uschar **valueptr)
432
  void *arg, int type, const uschar *name, const uschar **valueptr)
450
{
433
{
451
int yield = OK;
434
int yield = OK;
452
unsigned int *original_cache_bits = *cache_ptr;
435
unsigned int * original_cache_bits = *cache_ptr;
453
BOOL include_unknown = FALSE;
436
BOOL include_unknown = FALSE, ignore_unknown = FALSE,
454
BOOL ignore_unknown = FALSE;
437
      include_defer = FALSE, ignore_defer = FALSE;
455
BOOL include_defer = FALSE;
456
BOOL ignore_defer = FALSE;
457
const uschar *list;
438
const uschar *list;
458
uschar *sss;
439
uschar *sss;
459
uschar *ot = NULL;
440
uschar *ot = NULL;
Lines 462-469 Link Here
462
443
463
HDEBUG(D_any)
444
HDEBUG(D_any)
464
  {
445
  {
465
  uschar *listname = readconf_find_option(listptr);
446
  uschar * listname = readconf_find_option(listptr);
466
  if (listname[0] != 0) ot = string_sprintf("%s in %s?", name, listname);
447
  if (*listname) ot = string_sprintf("%s in %s?", name, listname);
467
  }
448
  }
468
449
469
/* If the list is empty, the answer is no. Skip the debugging output for
450
/* If the list is empty, the answer is no. Skip the debugging output for
Lines 471-477 Link Here
471
452
472
if (!*listptr)
453
if (!*listptr)
473
  {
454
  {
474
  HDEBUG(D_lists) if (ot) debug_printf("%s no (option unset)\n", ot);
455
  HDEBUG(D_lists) if (ot) debug_printf_indent("%s no (option unset)\n", ot);
475
  return FAIL;
456
  return FAIL;
476
  }
457
  }
477
458
Lines 504-510 Link Here
504
    {
485
    {
505
    if (f.expand_string_forcedfail)
486
    if (f.expand_string_forcedfail)
506
      {
487
      {
507
      HDEBUG(D_lists) debug_printf("expansion of \"%s\" forced failure: "
488
      HDEBUG(D_lists) debug_printf_indent("expansion of \"%s\" forced failure: "
508
        "assume not in this list\n", *listptr);
489
        "assume not in this list\n", *listptr);
509
      return FAIL;
490
      return FAIL;
510
      }
491
      }
Lines 515-522 Link Here
515
  }
496
  }
516
497
517
/* For an unnamed list, use the expanded version in comments */
498
/* For an unnamed list, use the expanded version in comments */
499
#define LIST_LIMIT_PR 2048
518
500
519
HDEBUG(D_any) if (!ot) ot = string_sprintf("%s in \"%s\"?", name, list);
501
HDEBUG(D_any) if (!ot)
502
  {
503
  int n, m;
504
  gstring * g = string_fmt_append(NULL, "%s in \"%n%.*s%n\"",
505
    name, &n, LIST_LIMIT_PR, list, &m);
506
  if (m - n >= LIST_LIMIT_PR) g = string_catn(g, US"...", 3);
507
  g = string_catn(g, US"?", 1);
508
  gstring_release_unused(g);
509
  ot = string_from_gstring(g);
510
  }
520
511
521
/* Now scan the list and process each item in turn, until one of them matches,
512
/* Now scan the list and process each item in turn, until one of them matches,
522
or we hit an error. */
513
or we hit an error. */
Lines 676-682 Link Here
676
            so we use the permanent store pool */
667
            so we use the permanent store pool */
677
668
678
            store_pool = POOL_PERM;
669
            store_pool = POOL_PERM;
679
            p = store_get(sizeof(namedlist_cacheblock), FALSE);
670
            p = store_get(sizeof(namedlist_cacheblock), GET_UNTAINTED);
680
            p->key = string_copy(get_check_key(arg, type));
671
            p->key = string_copy(get_check_key(arg, type));
681
672
682
673
Lines 686-692 Link Here
686
            p->next = nb->cache_data;
677
            p->next = nb->cache_data;
687
            nb->cache_data = p;
678
            nb->cache_data = p;
688
            if (*valueptr)
679
            if (*valueptr)
689
              DEBUG(D_lists) debug_printf("data from lookup saved for "
680
              DEBUG(D_lists) debug_printf_indent("data from lookup saved for "
690
                "cache for %s: key '%s' value '%s'\n", ss, p->key, *valueptr);
681
                "cache for %s: key '%s' value '%s'\n", ss, p->key, *valueptr);
691
            }
682
            }
692
          }
683
          }
Lines 698-704 Link Here
698
689
699
      else
690
      else
700
        {
691
        {
701
        DEBUG(D_lists) debug_printf("cached %s match for %s\n",
692
        DEBUG(D_lists) debug_printf_indent("cached %s match for %s\n",
702
          (bits & (-bits)) == bits ? "yes" : "no", ss);
693
          (bits & (-bits)) == bits ? "yes" : "no", ss);
703
694
704
        cached = US" - cached";
695
        cached = US" - cached";
Lines 712-718 Link Here
712
              *valueptr = p->data;
703
              *valueptr = p->data;
713
              break;
704
              break;
714
              }
705
              }
715
          DEBUG(D_lists) debug_printf("cached lookup data = %s\n", *valueptr);
706
          DEBUG(D_lists) debug_printf_indent("cached lookup data = %s\n", *valueptr);
716
          }
707
          }
717
        }
708
        }
718
709
Lines 721-728 Link Here
721
712
722
      if ((bits & (-bits)) == bits)    /* Only one of the two bits is set */
713
      if ((bits & (-bits)) == bits)    /* Only one of the two bits is set */
723
        {
714
        {
724
        HDEBUG(D_lists) debug_printf("%s %s (matched \"%s\"%s)\n", ot,
715
        HDEBUG(D_lists) debug_printf_indent("%s %s (matched \"%s\"%s)\n", ot,
725
          (yield == OK)? "yes" : "no", sss, cached);
716
          yield == OK ? "yes" : "no", sss, cached);
726
        return yield;
717
        return yield;
727
        }
718
        }
728
      }
719
      }
Lines 735-741 Link Here
735
      switch ((func)(arg, ss, valueptr, &error))
726
      switch ((func)(arg, ss, valueptr, &error))
736
        {
727
        {
737
        case OK:
728
        case OK:
738
	  HDEBUG(D_lists) debug_printf("%s %s (matched \"%s\")\n", ot,
729
	  HDEBUG(D_lists) debug_printf_indent("%s %s (matched \"%s\")\n", ot,
739
	    (yield == OK)? "yes" : "no", sss);
730
	    (yield == OK)? "yes" : "no", sss);
740
	  return yield;
731
	  return yield;
741
732
Lines 744-750 Link Here
744
	    error = string_sprintf("DNS lookup of \"%s\" deferred", ss);
735
	    error = string_sprintf("DNS lookup of \"%s\" deferred", ss);
745
	  if (ignore_defer)
736
	  if (ignore_defer)
746
	    {
737
	    {
747
	    HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_defer\n",
738
	    HDEBUG(D_lists) debug_printf_indent("%s: item ignored by +ignore_defer\n",
748
	      error);
739
	      error);
749
	    break;
740
	    break;
750
	    }
741
	    }
Lines 764-775 Link Here
764
        case ERROR:
755
        case ERROR:
765
	  if (ignore_unknown)
756
	  if (ignore_unknown)
766
	    {
757
	    {
767
	    HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_unknown\n",
758
	    HDEBUG(D_lists) debug_printf_indent("%s: item ignored by +ignore_unknown\n",
768
	      error);
759
	      error);
769
	    }
760
	    }
770
	  else
761
	  else
771
	    {
762
	    {
772
	    HDEBUG(D_lists) debug_printf("%s %s (%s)\n", ot,
763
	    HDEBUG(D_lists) debug_printf_indent("%s %s (%s)\n", ot,
773
	      include_unknown? "yes":"no", error);
764
	      include_unknown? "yes":"no", error);
774
	    if (!include_unknown)
765
	    if (!include_unknown)
775
	      {
766
	      {
Lines 803-809 Link Here
803
      if (listname[0] == 0)
794
      if (listname[0] == 0)
804
        listname = string_sprintf("\"%s\"", *listptr);
795
        listname = string_sprintf("\"%s\"", *listptr);
805
      log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
796
      log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
806
        string_open_failed(errno, "%s when checking %s", sss, listname));
797
        string_open_failed("%s when checking %s", sss, listname));
807
      }
798
      }
808
799
809
    /* Trailing comments are introduced by #, but in an address list or local
800
    /* Trailing comments are introduced by #, but in an address list or local
Lines 826-844 Link Here
826
        sss = ss + 1;
817
        sss = ss + 1;
827
        }
818
        }
828
819
829
      ss = filebuffer + Ustrlen(filebuffer);             /* trailing space */
820
      ss = filebuffer + Ustrlen(filebuffer);		/* trailing space */
830
      while (ss > filebuffer && isspace(ss[-1])) ss--;
821
      while (ss > filebuffer && isspace(ss[-1])) ss--;
831
      *ss = 0;
822
      *ss = 0;
832
823
833
      ss = filebuffer;
824
      ss = filebuffer;
834
      while (isspace(*ss)) ss++;                         /* leading space */
825
      while (isspace(*ss)) ss++;			/* leading space */
835
826
836
      if (*ss == 0) continue;                            /* ignore empty */
827
      if (!*ss) continue;				/* ignore empty */
837
828
838
      file_yield = yield;                                /* positive yield */
829
      file_yield = yield;				/* positive yield */
839
      sss = ss;                                          /* for debugging */
830
      sss = ss;						/* for debugging */
840
831
841
      if (*ss == '!')                                    /* negation */
832
      if (*ss == '!')					/* negation */
842
        {
833
        {
843
        file_yield = (file_yield == OK)? FAIL : OK;
834
        file_yield = (file_yield == OK)? FAIL : OK;
844
        while (isspace((*(++ss))));
835
        while (isspace((*(++ss))));
Lines 848-854 Link Here
848
        {
839
        {
849
        case OK:
840
        case OK:
850
	  (void)fclose(f);
841
	  (void)fclose(f);
851
	  HDEBUG(D_lists) debug_printf("%s %s (matched \"%s\" in %s)\n", ot,
842
	  HDEBUG(D_lists) debug_printf_indent("%s %s (matched \"%s\" in %s)\n", ot,
852
	    yield == OK ? "yes" : "no", sss, filename);
843
	    yield == OK ? "yes" : "no", sss, filename);
853
844
854
	  /* The "pattern" being matched came from the file; we use a stack-local.
845
	  /* The "pattern" being matched came from the file; we use a stack-local.
Lines 862-868 Link Here
862
	    error = string_sprintf("DNS lookup of %s deferred", ss);
853
	    error = string_sprintf("DNS lookup of %s deferred", ss);
863
	  if (ignore_defer)
854
	  if (ignore_defer)
864
	    {
855
	    {
865
	    HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_defer\n",
856
	    HDEBUG(D_lists) debug_printf_indent("%s: item ignored by +ignore_defer\n",
866
	      error);
857
	      error);
867
	    break;
858
	    break;
868
	    }
859
	    }
Lines 877-888 Link Here
877
        case ERROR:		/* host name lookup failed - this can only */
868
        case ERROR:		/* host name lookup failed - this can only */
878
	  if (ignore_unknown)	/* be for an incoming host (not outgoing) */
869
	  if (ignore_unknown)	/* be for an incoming host (not outgoing) */
879
	    {
870
	    {
880
	    HDEBUG(D_lists) debug_printf("%s: item ignored by +ignore_unknown\n",
871
	    HDEBUG(D_lists) debug_printf_indent("%s: item ignored by +ignore_unknown\n",
881
	      error);
872
	      error);
882
	    }
873
	    }
883
	  else
874
	  else
884
	   {
875
	   {
885
	    HDEBUG(D_lists) debug_printf("%s %s (%s)\n", ot,
876
	    HDEBUG(D_lists) debug_printf_indent("%s %s (%s)\n", ot,
886
	      include_unknown? "yes":"no", error);
877
	      include_unknown? "yes":"no", error);
887
	    (void)fclose(f);
878
	    (void)fclose(f);
888
	    if (!include_unknown)
879
	    if (!include_unknown)
Lines 908-914 Link Here
908
/* End of list reached: if the last item was negated yield OK, else FAIL. */
899
/* End of list reached: if the last item was negated yield OK, else FAIL. */
909
900
910
HDEBUG(D_lists)
901
HDEBUG(D_lists)
911
  debug_printf("%s %s (end of list)\n", ot, yield == OK ? "no":"yes");
902
  debug_printf_indent("%s %s (end of list)\n", ot, yield == OK ? "no":"yes");
912
return yield == OK ? FAIL : OK;
903
return yield == OK ? FAIL : OK;
913
904
914
/* Something deferred */
905
/* Something deferred */
Lines 1014-1032 Link Here
1014
static int
1005
static int
1015
check_address(void *arg, const uschar *pattern, const uschar **valueptr, uschar **error)
1006
check_address(void *arg, const uschar *pattern, const uschar **valueptr, uschar **error)
1016
{
1007
{
1017
check_address_block *cb = (check_address_block *)arg;
1008
check_address_block * cb = (check_address_block *)arg;
1018
check_string_block csb;
1009
check_string_block csb;
1019
int rc;
1010
int rc;
1020
int expand_inc = 0;
1011
int expand_inc = 0;
1021
unsigned int *null = NULL;
1012
unsigned int * null = NULL;
1022
const uschar *listptr;
1013
const uschar * listptr;
1023
uschar *subject = cb->address;
1014
uschar * subject = cb->address;
1024
const uschar *s;
1015
const uschar * s;
1025
uschar *pdomain, *sdomain;
1016
uschar * pdomain, * sdomain;
1017
uschar * value = NULL;
1026
1018
1027
error = error;  /* Keep clever compilers from complaining */
1019
DEBUG(D_lists) debug_printf_indent("address match test: subject=%s pattern=%s\n",
1028
1029
DEBUG(D_lists) debug_printf("address match test: subject=%s pattern=%s\n",
1030
  subject, pattern);
1020
  subject, pattern);
1031
1021
1032
/* Find the subject's domain */
1022
/* Find the subject's domain */
Lines 1075-1081 Link Here
1075
because other patterns expect to have a local part and a domain to match
1065
because other patterns expect to have a local part and a domain to match
1076
against. */
1066
against. */
1077
1067
1078
if (*subject == 0) return (*pattern == 0)? OK : FAIL;
1068
if (!*subject) return *pattern ? FAIL : OK;
1079
1069
1080
/* If the pattern starts with "@@" we have a split lookup, where the domain is
1070
/* If the pattern starts with "@@" we have a split lookup, where the domain is
1081
looked up to obtain a list of local parts. If the subject's local part is just
1071
looked up to obtain a list of local parts. If the subject's local part is just
Lines 1085-1091 Link Here
1085
  {
1075
  {
1086
  int watchdog = 50;
1076
  int watchdog = 50;
1087
  uschar *list, *ss;
1077
  uschar *list, *ss;
1088
  uschar buffer[1024];
1089
1078
1090
  if (sdomain == subject + 1 && *subject == '*') return FAIL;
1079
  if (sdomain == subject + 1 && *subject == '*') return FAIL;
1091
1080
Lines 1116-1122 Link Here
1116
    /* Look up the local parts provided by the list; negation is permitted.
1105
    /* Look up the local parts provided by the list; negation is permitted.
1117
    If a local part has to begin with !, a regex can be used. */
1106
    If a local part has to begin with !, a regex can be used. */
1118
1107
1119
    while ((ss = string_nextinlist(CUSS &list, &sep, buffer, sizeof(buffer))))
1108
    while ((ss = string_nextinlist(CUSS &list, &sep, NULL, 0)))
1120
      {
1109
      {
1121
      int local_yield;
1110
      int local_yield;
1122
1111
Lines 1198-1203 Link Here
1198
      expand_nlength[cb->expand_setup] = sllen - cllen;
1187
      expand_nlength[cb->expand_setup] = sllen - cllen;
1199
      expand_inc = 1;
1188
      expand_inc = 1;
1200
      }
1189
      }
1190
    value = string_copyn(pattern + 1, cllen);
1201
    }
1191
    }
1202
  else
1192
  else
1203
    {
1193
    {
Lines 1206-1211 Link Here
1206
        ? strncmpic(subject, pattern, sllen) != 0
1196
        ? strncmpic(subject, pattern, sllen) != 0
1207
	: Ustrncmp(subject, pattern, sllen) != 0) return FAIL;
1197
	: Ustrncmp(subject, pattern, sllen) != 0) return FAIL;
1208
    }
1198
    }
1199
    value = string_copyn(pattern, sllen);
1209
  }
1200
  }
1210
1201
1211
/* If the local part matched, or was not being checked, check the domain using
1202
/* If the local part matched, or was not being checked, check the domain using
Lines 1230-1245 Link Here
1230
listptr = pdomain ? pdomain + 1 : pattern;
1221
listptr = pdomain ? pdomain + 1 : pattern;
1231
if (valueptr) *valueptr = NULL;
1222
if (valueptr) *valueptr = NULL;
1232
1223
1233
return match_check_list(
1224
  {
1234
  &listptr,                  /* list of one item */
1225
  const uschar * dvalue = NULL;
1235
  UCHAR_MAX+1,               /* impossible separator; single item */
1226
  rc = match_check_list(
1236
  &domainlist_anchor,        /* it's a domain list */
1227
    &listptr,                  /* list of one item */
1237
  &null,                     /* ptr to NULL means no caching */
1228
    UCHAR_MAX+1,               /* impossible separator; single item */
1238
  check_string,              /* the function to do one test */
1229
    &domainlist_anchor,        /* it's a domain list */
1239
  &csb,                      /* its data */
1230
    &null,                     /* ptr to NULL means no caching */
1240
  MCL_DOMAIN + MCL_NOEXPAND, /* domain list; don't expand */
1231
    check_string,              /* the function to do one test */
1241
  csb.subject,               /* string for messages */
1232
    &csb,                      /* its data */
1242
  valueptr);                 /* where to pass back lookup data */
1233
    MCL_DOMAIN + MCL_NOEXPAND, /* domain list; don't expand */
1234
    csb.subject,               /* string for messages */
1235
    &dvalue);                       /* where to pass back lookup data */
1236
  if (valueptr && (value || dvalue))
1237
    *valueptr = string_sprintf("%s@%s",
1238
		  value ? value : US"", dvalue ? dvalue : US"");
1239
  }
1240
return rc;
1243
}
1241
}
1244
1242
1245
1243
Lines 1294-1301 Link Here
1294
patterns.) Otherwise just the domain is lower cases. A magic item "+caseful" in
1292
patterns.) Otherwise just the domain is lower cases. A magic item "+caseful" in
1295
the list can be used to restore a caseful copy of the local part from the
1293
the list can be used to restore a caseful copy of the local part from the
1296
original address.
1294
original address.
1297
Limit the subject address size to avoid mem-exhastion attacks.  The size chosen
1295
Limit the subject address size to avoid mem-exhaustion attacks.  The size chosen
1298
is historical (we used to use big_buffer her). */
1296
is historical (we used to use big_buffer here). */
1299
1297
1300
if ((len = Ustrlen(address)) > BIG_BUFFER_SIZE) len = BIG_BUFFER_SIZE;
1298
if ((len = Ustrlen(address)) > BIG_BUFFER_SIZE) len = BIG_BUFFER_SIZE;
1301
ab.address = string_copyn(address, len);
1299
ab.address = string_copyn(address, len);
(-)exim.orig/src/mime.c (-3 / +4 lines)
Lines 2-10 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004 - 2015
5
/*
6
 * Copyright (c) The Exim Maintainers 2015 - 2022
7
 * Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004 - 2015
6
 * License: GPL
8
 * License: GPL
7
 * Copyright (c) The Exim Maintainers 2015 - 2020
8
 */
9
 */
9
10
10
#include "exim.h"
11
#include "exim.h"
Lines 501-507 Link Here
501
struct mime_boundary_context nested_context;
502
struct mime_boundary_context nested_context;
502
503
503
/* reserve a line buffer to work in.  Assume tainted data. */
504
/* reserve a line buffer to work in.  Assume tainted data. */
504
header = store_get(MIME_MAX_HEADER_SIZE+1, TRUE);
505
header = store_get(MIME_MAX_HEADER_SIZE+1, GET_TAINTED);
505
506
506
/* Not actually used at the moment, but will be vital to fixing
507
/* Not actually used at the moment, but will be vital to fixing
507
 * some RFC 2046 nonconformance later... */
508
 * some RFC 2046 nonconformance later... */
(-)exim.orig/src/moan.c (-4 / +3 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Functions for sending messages to sender or to mailmaster. */
9
/* Functions for sending messages to sender or to mailmaster. */
Lines 386-392 Link Here
386
  if (bounce_return_body && message_file)
386
  if (bounce_return_body && message_file)
387
    {
387
    {
388
    BOOL enddot = f.dot_ends && message_file == stdin;
388
    BOOL enddot = f.dot_ends && message_file == stdin;
389
    uschar * buf = store_get(bounce_return_linesize_limit+2, TRUE);
389
    uschar * buf = store_get(bounce_return_linesize_limit+2, GET_TAINTED);
390
390
391
    if (firstline) fprintf(fp, "%s", CS firstline);
391
    if (firstline) fprintf(fp, "%s", CS firstline);
392
392
Lines 719-725 Link Here
719
uschar *item, *localpart, *domain;
719
uschar *item, *localpart, *domain;
720
const uschar *listptr = errors_copy;
720
const uschar *listptr = errors_copy;
721
uschar *yield = NULL;
721
uschar *yield = NULL;
722
uschar buffer[256];
723
int sep = 0;
722
int sep = 0;
724
int llen;
723
int llen;
725
724
Lines 735-741 Link Here
735
734
736
/* Scan through the configured items */
735
/* Scan through the configured items */
737
736
738
while ((item = string_nextinlist(&listptr, &sep, buffer, sizeof(buffer))))
737
while ((item = string_nextinlist(&listptr, &sep, NULL, 0)))
739
  {
738
  {
740
  const uschar *newaddress = item;
739
  const uschar *newaddress = item;
741
  const uschar *pattern = string_dequote(&newaddress);
740
  const uschar *pattern = string_dequote(&newaddress);
(-)exim.orig/src/mytypes.h (-5 / +14 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 30-57 Link Here
30
30
31
31
32
/* If gcc is being used to compile Exim, we can use its facility for checking
32
/* If gcc is being used to compile Exim, we can use its facility for checking
33
the arguments of printf-like functions. This is done by a macro. */
33
the arguments of printf-like functions. This is done by a macro.
34
OpenBSD has unfortunately taken to objecting to use of %n in printf
35
so we have to give up on all of the available parameter checking. */
34
36
35
#if defined(__GNUC__) || defined(__clang__)
37
#if defined(__GNUC__) || defined(__clang__)
36
# define PRINTF_FUNCTION(A,B)	__attribute__((format(printf,A,B)))
38
# ifndef __OpenBSD__
39
#  define PRINTF_FUNCTION(A,B)	__attribute__((format(printf,A,B)))
40
# endif
37
# define ARG_UNUSED		__attribute__((__unused__))
41
# define ARG_UNUSED		__attribute__((__unused__))
42
# define FUNC_MAYBE_UNUSED	__attribute__((__unused__))
38
# define WARN_UNUSED_RESULT	__attribute__((__warn_unused_result__))
43
# define WARN_UNUSED_RESULT	__attribute__((__warn_unused_result__))
39
# define ALLOC			__attribute__((malloc))
44
# define ALLOC			__attribute__((malloc))
40
# define ALLOC_SIZE(A)		__attribute__((alloc_size(A)))
45
# define ALLOC_SIZE(A)		__attribute__((alloc_size(A)))
41
# define NORETURN		__attribute__((noreturn))
46
# define NORETURN		__attribute__((noreturn))
42
#else
47
#else
43
# define PRINTF_FUNCTION(A,B)
44
# define ARG_UNUSED		/**/
48
# define ARG_UNUSED		/**/
49
# define FUNC_MAYBE_UNUSED	/**/
45
# define WARN_UNUSED_RESULT	/**/
50
# define WARN_UNUSED_RESULT	/**/
46
# define ALLOC			/**/
51
# define ALLOC			/**/
47
# define ALLOC_SIZE(A)		/**/
52
# define ALLOC_SIZE(A)		/**/
48
# define NORETURN		/**/
53
# define NORETURN		/**/
49
#endif
54
#endif
50
55
56
#ifndef PRINTF_FUNCTION
57
# define PRINTF_FUNCTION(A,B)	/**/
58
#endif
59
51
#ifdef WANT_DEEPER_PRINTF_CHECKS
60
#ifdef WANT_DEEPER_PRINTF_CHECKS
52
# define ALMOST_PRINTF(A, B) PRINTF_FUNCTION(A, B)
61
# define ALMOST_PRINTF(A, B) PRINTF_FUNCTION(A, B)
53
#else
62
#else
54
# define ALMOST_PRINTF(A, B)
63
# define ALMOST_PRINTF(A, B)	/**/
55
#endif
64
#endif
56
65
57
66
(-)exim.orig/src/os.c (-8 / +11 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2021 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 495-503 Link Here
495
496
496
for (struct ifaddrs * ifa = ifalist; ifa; ifa = ifa->ifa_next)
497
for (struct ifaddrs * ifa = ifalist; ifa; ifa = ifa->ifa_next)
497
  {
498
  {
498
  if (ifa->ifa_addr->sa_family != AF_INET
499
  struct sockaddr * ifa_addr = ifa->ifa_addr;
500
  if (!ifa_addr) continue;
501
  if (ifa_addr->sa_family != AF_INET
499
#if HAVE_IPV6
502
#if HAVE_IPV6
500
    && ifa->ifa_addr->sa_family != AF_INET6
503
    && ifa_addr->sa_family != AF_INET6
501
#endif /* HAVE_IPV6 */
504
#endif /* HAVE_IPV6 */
502
    )
505
    )
503
    continue;
506
    continue;
Lines 508-519 Link Here
508
  /* Create a data block for the address, fill in the data, and put it on the
511
  /* Create a data block for the address, fill in the data, and put it on the
509
  chain. */
512
  chain. */
510
513
511
  next = store_get(sizeof(ip_address_item), FALSE);
514
  next = store_get(sizeof(ip_address_item), GET_UNTAINTED);
512
  next->next = NULL;
515
  next->next = NULL;
513
  next->port = 0;
516
  next->port = 0;
514
  (void)host_ntoa(-1, ifa->ifa_addr, next->address, NULL);
517
  (void)host_ntoa(-1, ifa_addr, next->address, NULL);
515
518
516
  if (yield == NULL)
519
  if (!yield)
517
    yield = last = next;
520
    yield = last = next;
518
  else
521
  else
519
    {
522
    {
Lines 743-749 Link Here
743
  /* Create a data block for the address, fill in the data, and put it on the
746
  /* Create a data block for the address, fill in the data, and put it on the
744
  chain. */
747
  chain. */
745
748
746
  next = store_get(sizeof(ip_address_item), FALSE);
749
  next = store_get(sizeof(ip_address_item), GET_UNTAINTED);
747
  next->next = NULL;
750
  next->next = NULL;
748
  next->port = 0;
751
  next->port = 0;
749
  (void)host_ntoa(-1, addrp, next->address, NULL);
752
  (void)host_ntoa(-1, addrp, next->address, NULL);
Lines 775-787 Link Here
775
ip_address_item *
778
ip_address_item *
776
os_common_find_running_interfaces(void)
779
os_common_find_running_interfaces(void)
777
{
780
{
778
ip_address_item *yield = store_get(sizeof(address_item), FALSE);
781
ip_address_item *yield = store_get(sizeof(address_item), GET_UNTAINTED);
779
yield->address = US"127.0.0.1";
782
yield->address = US"127.0.0.1";
780
yield->port = 0;
783
yield->port = 0;
781
yield->next = NULL;
784
yield->next = NULL;
782
785
783
#if HAVE_IPV6
786
#if HAVE_IPV6
784
yield->next = store_get(sizeof(address_item), FALSE);
787
yield->next = store_get(sizeof(address_item), GET_UNTAINTED);
785
yield->next->address = US"::1";
788
yield->next->address = US"::1";
786
yield->next->port = 0;
789
yield->next->port = 0;
787
yield->next->next = NULL;
790
yield->next->next = NULL;
(-)exim.orig/src/parse.c (-100 / +105 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Functions for parsing addresses */
9
/* Functions for parsing addresses */
Lines 22-43 Link Here
22
22
23
#ifdef STAND_ALONE
23
#ifdef STAND_ALONE
24
24
25
address_item *deliver_make_addr(uschar *address, BOOL copy)
25
address_item *
26
deliver_make_addr(uschar *address, BOOL copy)
26
{
27
{
27
address_item *addr = store_get(sizeof(address_item), FALSE);
28
address_item *addr = store_get(sizeof(address_item), GET_UNTAINTED);
28
addr->next = NULL;
29
addr->next = NULL;
29
addr->parent = NULL;
30
addr->parent = NULL;
30
addr->address = address;
31
addr->address = address;
31
return addr;
32
return addr;
32
}
33
}
33
34
34
uschar *rewrite_address(uschar *recipient, BOOL dummy1, BOOL dummy2, rewrite_rule
35
uschar *
36
rewrite_address(uschar *recipient, BOOL dummy1, BOOL dummy2, rewrite_rule
35
  *dummy3, int dummy4)
37
  *dummy3, int dummy4)
36
{
38
{
37
return recipient;
39
return recipient;
38
}
40
}
39
41
40
uschar *rewrite_address_qualify(uschar *recipient, BOOL dummy1)
42
uschar *
43
rewrite_address_qualify(uschar *recipient, BOOL dummy1)
41
{
44
{
42
return recipient;
45
return recipient;
43
}
46
}
Lines 65-71 Link Here
65
*/
68
*/
66
69
67
uschar *
70
uschar *
68
parse_find_address_end(uschar *s, BOOL nl_ends)
71
parse_find_address_end(const uschar *s, BOOL nl_ends)
69
{
72
{
70
BOOL source_routing = *s == '@';
73
BOOL source_routing = *s == '@';
71
int no_term = source_routing? 1 : 0;
74
int no_term = source_routing? 1 : 0;
Lines 121-127 Link Here
121
    }
124
    }
122
  }
125
  }
123
126
124
return s;
127
return US s;
125
}
128
}
126
129
127
130
Lines 224-239 Link Here
224
in []. Make sure the output is set to the null string if there is a syntax
227
in []. Make sure the output is set to the null string if there is a syntax
225
error as well as if there is no domain at all.
228
error as well as if there is no domain at all.
226
229
230
Optionally, msg_id domain literals ( printable-ascii enclosed in [] )
231
are permitted.
232
227
Arguments:
233
Arguments:
228
  s          current character pointer
234
  s          current character pointer
229
  t          where to put the domain
235
  t          where to put the domain
236
  msg_id_literals     flag for relaxed domain-literal processing
230
  errorptr   put error message here on failure (*t will be 0 on exit)
237
  errorptr   put error message here on failure (*t will be 0 on exit)
231
238
232
Returns:     new character pointer
239
Returns:     new character pointer
233
*/
240
*/
234
241
235
static const uschar *
242
static const uschar *
236
read_domain(const uschar *s, uschar *t, uschar **errorptr)
243
read_domain(const uschar *s, uschar *t, BOOL msg_id_literals, uschar **errorptr)
237
{
244
{
238
uschar *tt = t;
245
uschar *tt = t;
239
s = skip_comment(s);
246
s = skip_comment(s);
Lines 259-265 Link Here
259
    t += 5;
266
    t += 5;
260
    s += 5;
267
    s += 5;
261
    }
268
    }
262
  while (*s == '.' || *s == ':' || isxdigit(*s)) *t++ = *s++;
269
270
  if (msg_id_literals)
271
    while (*s >= 33 && *s <= 90 || *s >= 94 && *s <= 126) *t++ = *s++;
272
  else
273
    while (*s == '.' || *s == ':' || isxdigit(*s)) *t++ = *s++;
263
274
264
  if (*s == ']') *t++ = *s++; else
275
  if (*s == ']') *t++ = *s++; else
265
    {
276
    {
Lines 267-273 Link Here
267
    *tt = 0;
278
    *tt = 0;
268
    }
279
    }
269
280
270
  if (!allow_domain_literals)
281
  if (!allow_domain_literals && !msg_id_literals)
271
    {
282
    {
272
    *errorptr = US"domain literals not allowed";
283
    *errorptr = US"domain literals not allowed";
273
    *tt = 0;
284
    *tt = 0;
Lines 500-506 Link Here
500
while (*s == '@')
511
while (*s == '@')
501
  {
512
  {
502
  *t++ = '@';
513
  *t++ = '@';
503
  s = read_domain(s+1, t, errorptr);
514
  s = read_domain(s+1, t, FALSE, errorptr);
504
  if (*t == 0) return s;
515
  if (*t == 0) return s;
505
  t += Ustrlen((const uschar *)t);
516
  t += Ustrlen((const uschar *)t);
506
  if (*s != ',') break;
517
  if (*s != ',') break;
Lines 559-565 Link Here
559
      t += Ustrlen((const uschar *)t);
570
      t += Ustrlen((const uschar *)t);
560
      *t++ = *s++;
571
      *t++ = *s++;
561
      *domainptr = t;
572
      *domainptr = t;
562
      s = read_domain(s, t, errorptr);
573
      s = read_domain(s, t, FALSE, errorptr);
563
      }
574
      }
564
return s;
575
return s;
565
}
576
}
Lines 619-625 Link Here
619
parse_extract_address(const uschar *mailbox, uschar **errorptr, int *start, int *end,
630
parse_extract_address(const uschar *mailbox, uschar **errorptr, int *start, int *end,
620
  int *domain, BOOL allow_null)
631
  int *domain, BOOL allow_null)
621
{
632
{
622
uschar *yield = store_get(Ustrlen(mailbox) + 1, is_tainted(mailbox));
633
uschar * yield = store_get(Ustrlen(mailbox) + 1, mailbox);
623
const uschar *startptr, *endptr;
634
const uschar *startptr, *endptr;
624
const uschar *s = US mailbox;
635
const uschar *s = US mailbox;
625
uschar *t = US yield;
636
uschar *t = US yield;
Lines 647-655 Link Here
647
658
648
if (*s != '@' && *s != '<')
659
if (*s != '@' && *s != '<')
649
  {
660
  {
650
  if (*s == 0 || *s == ';')
661
  if (!*s || *s == ';')
651
    {
662
    {
652
    if (*t == 0) FAILED(US"empty address");
663
    if (!*t) FAILED(US"empty address");
653
    endptr = last_comment_position;
664
    endptr = last_comment_position;
654
    goto PARSE_SUCCEEDED;              /* Bare local part */
665
    goto PARSE_SUCCEEDED;              /* Bare local part */
655
    }
666
    }
Lines 740-746 Link Here
740
    }
751
    }
741
752
742
  endptr = s;
753
  endptr = s;
743
  if (*errorptr != NULL) goto PARSE_FAILED;
754
  if (*errorptr) goto PARSE_FAILED;
744
  while (bracket_count-- > 0) if (*s++ != '>')
755
  while (bracket_count-- > 0) if (*s++ != '>')
745
    {
756
    {
746
    *errorptr = s[-1] == 0
757
    *errorptr = s[-1] == 0
Lines 759-772 Link Here
759
not enclosed in <> as well, which is indicated by an empty first local
770
not enclosed in <> as well, which is indicated by an empty first local
760
part preceding '@'. The source routing is, however, ignored. */
771
part preceding '@'. The source routing is, however, ignored. */
761
772
762
else if (*t == 0)
773
else if (!*t)
763
  {
774
  {
764
  uschar *domainptr = yield;
775
  uschar *domainptr = yield;
765
  s = read_route(s, t, errorptr);
776
  s = read_route(s, t, errorptr);
766
  if (*errorptr != NULL) goto PARSE_FAILED;
777
  if (*errorptr) goto PARSE_FAILED;
767
  *t = 0;         /* Ensure route is ignored - probably overkill */
778
  *t = 0;         /* Ensure route is ignored - probably overkill */
768
  s = read_addr_spec(s, t, 0, errorptr, &domainptr);
779
  s = read_addr_spec(s, t, 0, errorptr, &domainptr);
769
  if (*errorptr != NULL) goto PARSE_FAILED;
780
  if (*errorptr) goto PARSE_FAILED;
770
  *domain = domainptr - yield;
781
  *domain = domainptr - yield;
771
  endptr = last_comment_position;
782
  endptr = last_comment_position;
772
  if (*domain == 0) FAILED(US"domain missing in source-routed address");
783
  if (*domain == 0) FAILED(US"domain missing in source-routed address");
Lines 779-786 Link Here
779
  t += Ustrlen((const uschar *)t);
790
  t += Ustrlen((const uschar *)t);
780
  *t++ = *s++;
791
  *t++ = *s++;
781
  *domain = t - yield;
792
  *domain = t - yield;
782
  s = read_domain(s, t, errorptr);
793
  s = read_domain(s, t, TRUE, errorptr);
783
  if (*t == 0) goto PARSE_FAILED;
794
  if (!*t) goto PARSE_FAILED;
784
  endptr = last_comment_position;
795
  endptr = last_comment_position;
785
  }
796
  }
786
797
Lines 789-795 Link Here
789
move it back past white space if necessary. */
800
move it back past white space if necessary. */
790
801
791
PARSE_SUCCEEDED:
802
PARSE_SUCCEEDED:
792
if (*s != 0)
803
if (*s)
793
  {
804
  {
794
  if (f.parse_found_group && *s == ';')
805
  if (f.parse_found_group && *s == ';')
795
    {
806
    {
Lines 863-869 Link Here
863
*/
874
*/
864
875
865
const uschar *
876
const uschar *
866
parse_quote_2047(const uschar *string, int len, uschar *charset, BOOL fold)
877
parse_quote_2047(const uschar *string, int len, const uschar *charset,
878
  BOOL fold)
867
{
879
{
868
const uschar * s = string;
880
const uschar * s = string;
869
int hlen, l;
881
int hlen, l;
Lines 904-911 Link Here
904
    { g = string_catn(g, s, 1); first_byte = FALSE; }
916
    { g = string_catn(g, s, 1); first_byte = FALSE; }
905
  }
917
  }
906
918
907
g = string_catn(g, US"?=", 2);
919
if (coded)
908
return coded ? string_from_gstring(g) : string;
920
  string = string_from_gstring(g = string_catn(g, US"?=", 2));
921
else
922
  g->ptr = -1;
923
924
gstring_release_unused(g);
925
return string;
909
}
926
}
910
927
911
928
Lines 980-990 Link Here
980
/* No non-printers; use the RFC 822 quoting rules */
997
/* No non-printers; use the RFC 822 quoting rules */
981
998
982
if (len <= 0 || len >= INT_MAX/4)
999
if (len <= 0 || len >= INT_MAX/4)
983
  {
1000
  return string_copy_taint(CUS"", phrase);
984
  return string_copy_taint(CUS"", is_tainted(phrase));
985
  }
986
1001
987
buffer = store_get((len+1)*4, is_tainted(phrase));
1002
buffer = store_get((len+1)*4, phrase);
988
1003
989
s = phrase;
1004
s = phrase;
990
end = s + len;
1005
end = s + len;
Lines 1228-1235 Link Here
1228
*/
1243
*/
1229
1244
1230
int
1245
int
1231
parse_forward_list(uschar *s, int options, address_item **anchor,
1246
parse_forward_list(const uschar *s, int options, address_item **anchor,
1232
  uschar **error, const uschar *incoming_domain, uschar *directory,
1247
  uschar **error, const uschar *incoming_domain, const uschar *directory,
1233
  error_block **syntax_errors)
1248
  error_block **syntax_errors)
1234
{
1249
{
1235
int count = 0;
1250
int count = 0;
Lines 1238-1255 Link Here
1238
1253
1239
for (;;)
1254
for (;;)
1240
  {
1255
  {
1241
  int len;
1256
  int len, special = 0, specopt = 0, specbit = 0;
1242
  int special = 0;
1257
  const uschar * ss, * nexts;
1243
  int specopt = 0;
1258
  address_item * addr;
1244
  int specbit = 0;
1245
  uschar *ss, *nexts;
1246
  address_item *addr;
1247
  BOOL inquote = FALSE;
1259
  BOOL inquote = FALSE;
1248
1260
1249
  for (;;)
1261
  for (;;)
1250
    {
1262
    {
1251
    while (isspace(*s) || *s == ',') s++;
1263
    while (isspace(*s) || *s == ',') s++;
1252
    if (*s == '#') { while (*s != 0 && *s != '\n') s++; } else break;
1264
    if (*s == '#') { while (*s && *s != '\n') s++; } else break;
1253
    }
1265
    }
1254
1266
1255
  /* When we reach the end of the list, we return FF_DELIVERED if any child
1267
  /* When we reach the end of the list, we return FF_DELIVERED if any child
Lines 1270-1287 Link Here
1270
    syntax error has been skipped. I now think it is the wrong approach, but
1282
    syntax error has been skipped. I now think it is the wrong approach, but
1271
    have left this here just in case, and for the record. */
1283
    have left this here just in case, and for the record. */
1272
1284
1273
    #ifdef NEVER
1285
#ifdef NEVER
1274
    if (count > 0) return FF_DELIVERED;   /* Something was generated */
1286
    if (count > 0) return FF_DELIVERED;   /* Something was generated */
1275
1287
1276
    if (syntax_errors == NULL ||          /* Not skipping syntax errors, or */
1288
    if (!syntax_errors ||          /* Not skipping syntax errors, or */
1277
       *syntax_errors == NULL)            /*   we didn't actually skip any */
1289
       !*syntax_errors)            /*   we didn't actually skip any */
1278
      return FF_NOTDELIVERED;
1290
      return FF_NOTDELIVERED;
1279
1291
1280
    *error = string_sprintf("no addresses generated: syntax error in %s: %s",
1292
    *error = string_sprintf("no addresses generated: syntax error in %s: %s",
1281
       (*syntax_errors)->text2, (*syntax_errors)->text1);
1293
       (*syntax_errors)->text2, (*syntax_errors)->text1);
1282
    return FF_ERROR;
1294
    return FF_ERROR;
1283
    #endif
1295
#endif
1284
1285
    }
1296
    }
1286
1297
1287
  /* Find the end of the next address. Quoted strings in addresses may contain
1298
  /* Find the end of the next address. Quoted strings in addresses may contain
Lines 1298-1304 Link Here
1298
1309
1299
  /* Remove any trailing spaces; we know there's at least one non-space. */
1310
  /* Remove any trailing spaces; we know there's at least one non-space. */
1300
1311
1301
  while (isspace((ss[-1]))) ss--;
1312
  while (isspace(ss[-1])) ss--;
1302
1313
1303
  /* We now have s->start and ss->end of the next address. Remove quotes
1314
  /* We now have s->start and ss->end of the next address. Remove quotes
1304
  if they completely enclose, remembering the address started with a quote
1315
  if they completely enclose, remembering the address started with a quote
Lines 1311-1330 Link Here
1311
    ss--;
1322
    ss--;
1312
    inquote = TRUE;
1323
    inquote = TRUE;
1313
    while (s < ss && isspace(*s)) s++;
1324
    while (s < ss && isspace(*s)) s++;
1314
    while (ss > s && isspace((ss[-1]))) ss--;
1325
    while (ss > s && isspace(ss[-1])) ss--;
1315
    }
1326
    }
1316
1327
1317
  /* Set up the length of the address. */
1328
  /* Set up the length of the address. */
1318
1329
1319
  len = ss - s;
1330
  len = ss - s;
1320
1331
1321
  DEBUG(D_route)
1332
  DEBUG(D_route) debug_printf("extract item: %.*s\n", len, s);
1322
    {
1323
    int save = s[len];
1324
    s[len] = 0;
1325
    debug_printf("extract item: %s\n", s);
1326
    s[len] = save;
1327
    }
1328
1333
1329
  /* Handle special addresses if permitted. If the address is :unknown:
1334
  /* Handle special addresses if permitted. If the address is :unknown:
1330
  ignore it - this is for backward compatibility with old alias files. You
1335
  ignore it - this is for backward compatibility with old alias files. You
Lines 1345-1362 Link Here
1345
  else if (Ustrncmp(s, ":fail:", 6) == 0)
1350
  else if (Ustrncmp(s, ":fail:", 6) == 0)
1346
    { special = FF_FAIL; specopt = RDO_FAIL; }  /* specbit is 0 */
1351
    { special = FF_FAIL; specopt = RDO_FAIL; }  /* specbit is 0 */
1347
1352
1348
  if (special != 0)
1353
  if (special)
1349
    {
1354
    {
1350
    uschar *ss = Ustrchr(s+1, ':') + 1;
1355
    uschar * ss = Ustrchr(s+1, ':') + 1; /* line after the special... */
1351
    if ((options & specopt) == specbit)
1356
    if ((options & specopt) == specbit)
1352
      {
1357
      {
1353
      *error = string_sprintf("\"%.*s\" is not permitted", len, s);
1358
      *error = string_sprintf("\"%.*s\" is not permitted", len, s);
1354
      return FF_ERROR;
1359
      return FF_ERROR;
1355
      }
1360
      }
1356
    while (*ss != 0 && isspace(*ss)) ss++;
1361
    while (*ss && isspace(*ss)) ss++;	/* skip leading whitespace */
1357
    while (s[len] != 0 && s[len] != '\n') len++;
1362
    if ((len = Ustrlen(ss)) > 0)	/* ignore trailing newlines */
1358
    s[len] = 0;
1363
      for (const uschar * t = ss + len - 1; t >= ss && *t == '\n'; t--) len--;
1359
    *error = string_copy(ss);
1364
    *error = string_copyn(ss, len);	/* becomes the error */
1360
    return special;
1365
    return special;
1361
    }
1366
    }
1362
1367
Lines 1367-1380 Link Here
1367
1372
1368
  if (Ustrncmp(s, ":include:", 9) == 0)
1373
  if (Ustrncmp(s, ":include:", 9) == 0)
1369
    {
1374
    {
1370
    uschar *filebuf;
1375
    uschar * filebuf;
1371
    uschar filename[256];
1376
    uschar filename[256];
1372
    uschar *t = s+9;
1377
    const uschar * t = s+9;
1373
    int flen = len - 9;
1378
    int flen = len - 9;
1374
    int frc;
1379
    int frc;
1375
    struct stat statbuf;
1380
    struct stat statbuf;
1376
    address_item *last;
1381
    address_item * last;
1377
    FILE *f;
1382
    FILE * f;
1378
1383
1379
    while (flen > 0 && isspace(*t)) { t++; flen--; }
1384
    while (flen > 0 && isspace(*t)) { t++; flen--; }
1380
1385
Lines 1384-1390 Link Here
1384
      return FF_ERROR;
1389
      return FF_ERROR;
1385
      }
1390
      }
1386
1391
1387
    if (flen > 255)
1392
    if (flen > sizeof(filename)-1)
1388
      {
1393
      {
1389
      *error = string_sprintf("included file name \"%s\" is too long", t);
1394
      *error = string_sprintf("included file name \"%s\" is too long", t);
1390
      return FF_ERROR;
1395
      return FF_ERROR;
Lines 1422-1429 Link Here
1422
    if (directory)
1427
    if (directory)
1423
      {
1428
      {
1424
      int len = Ustrlen(directory);
1429
      int len = Ustrlen(directory);
1425
      uschar *p = filename + len;
1430
      uschar * p;
1426
1431
1432
      while (len > 0 && directory[len-1] == '/') len--;		/* ignore trailing '/' */
1433
      p = filename + len;
1427
      if (Ustrncmp(filename, directory, len) != 0 || *p != '/')
1434
      if (Ustrncmp(filename, directory, len) != 0 || *p != '/')
1428
        {
1435
        {
1429
        *error = string_sprintf("included file %s is not in directory %s",
1436
        *error = string_sprintf("included file %s is not in directory %s",
Lines 1438-1444 Link Here
1438
      with a flag that fails symlinks. */
1445
      with a flag that fails symlinks. */
1439
1446
1440
      {
1447
      {
1441
      int fd = exim_open2(CS directory, O_RDONLY);
1448
      int fd = exim_open2(CCS directory, O_RDONLY);
1442
      if (fd < 0)
1449
      if (fd < 0)
1443
	{
1450
	{
1444
	*error = string_sprintf("failed to open directory %s", directory);
1451
	*error = string_sprintf("failed to open directory %s", directory);
Lines 1448-1456 Link Here
1448
	{
1455
	{
1449
	uschar temp;
1456
	uschar temp;
1450
	int fd2;
1457
	int fd2;
1451
	uschar * q = p;
1458
	uschar * q = p + 1;		/* skip dividing '/' */
1452
1459
1453
	while (*++p && *p != '/') ;
1460
	while (*q == '/') q++;		/* skip extra '/' */
1461
	while (*++p && *p != '/') ;	/* end of component */
1454
	temp = *p;
1462
	temp = *p;
1455
	*p = '\0';
1463
	*p = '\0';
1456
1464
Lines 1508-1514 Link Here
1508
1516
1509
    if (!f)
1517
    if (!f)
1510
      {
1518
      {
1511
      *error = string_open_failed(errno, "included file %s", filename);
1519
      *error = string_open_failed("included file %s", filename);
1512
      return FF_INCLUDEFAIL;
1520
      return FF_INCLUDEFAIL;
1513
      }
1521
      }
1514
1522
Lines 1538-1544 Link Here
1538
      return FF_ERROR;
1546
      return FF_ERROR;
1539
      }
1547
      }
1540
1548
1541
    filebuf = store_get(statbuf.st_size + 1, is_tainted(filename));
1549
    filebuf = store_get(statbuf.st_size + 1, filename);
1542
    if (fread(filebuf, 1, statbuf.st_size, f) != statbuf.st_size)
1550
    if (fread(filebuf, 1, statbuf.st_size, f) != statbuf.st_size)
1543
      {
1551
      {
1544
      *error = string_sprintf("error while reading included file %s: %s",
1552
      *error = string_sprintf("error while reading included file %s: %s",
Lines 1586-1603 Link Here
1586
    {
1594
    {
1587
    int start, end, domain;
1595
    int start, end, domain;
1588
    const uschar *recipient = NULL;
1596
    const uschar *recipient = NULL;
1589
    int save = s[len];
1597
    uschar * s_ltd = string_copyn(s, len);
1590
    s[len] = 0;
1591
1598
1592
    /* If it starts with \ and the rest of it parses as a valid mail address
1599
    /* If it starts with \ and the rest of it parses as a valid mail address
1593
    without a domain, carry on with that address, but qualify it with the
1600
    without a domain, carry on with that address, but qualify it with the
1594
    incoming domain. Otherwise arrange for the address to fall through,
1601
    incoming domain. Otherwise arrange for the address to fall through,
1595
    causing an error message on the re-parse. */
1602
    causing an error message on the re-parse. */
1596
1603
1597
    if (*s == '\\')
1604
    if (*s_ltd == '\\')
1598
      {
1605
      {
1599
      recipient =
1606
      recipient =
1600
        parse_extract_address(s+1, error, &start, &end, &domain, FALSE);
1607
        parse_extract_address(s_ltd+1, error, &start, &end, &domain, FALSE);
1601
      if (recipient)
1608
      if (recipient)
1602
        recipient = domain != 0 ? NULL :
1609
        recipient = domain != 0 ? NULL :
1603
          string_sprintf("%s@%s", recipient, incoming_domain);
1610
          string_sprintf("%s@%s", recipient, incoming_domain);
Lines 1606-1627 Link Here
1606
    /* Try parsing the item as an address. */
1613
    /* Try parsing the item as an address. */
1607
1614
1608
    if (!recipient) recipient =
1615
    if (!recipient) recipient =
1609
      parse_extract_address(s, error, &start, &end, &domain, FALSE);
1616
      parse_extract_address(s_ltd, error, &start, &end, &domain, FALSE);
1610
1617
1611
    /* If item starts with / or | and is not a valid address, or there
1618
    /* If item starts with / or | and is not a valid address, or there
1612
    is no domain, treat it as a file or pipe. If it was a quoted item,
1619
    is no domain, treat it as a file or pipe. If it was a quoted item,
1613
    remove the quoting occurrences of \ within it. */
1620
    remove the quoting occurrences of \ within it. */
1614
1621
1615
    if ((*s == '|' || *s == '/') && (recipient == NULL || domain == 0))
1622
    if ((*s_ltd == '|' || *s_ltd == '/') && (!recipient || domain == 0))
1616
      {
1623
      {
1617
      uschar *t = store_get(Ustrlen(s) + 1, is_tainted(s));
1624
      uschar * t = store_get(Ustrlen(s_ltd) + 1, s_ltd);
1618
      uschar *p = t;
1625
      uschar * p = t, * q = s_ltd;
1619
      uschar *q = s;
1626
1620
      while (*q != 0)
1627
      while (*q)
1621
        {
1628
        {
1622
        if (inquote)
1629
        if (inquote)
1623
          {
1630
          {
1624
          *p++ = (*q == '\\')? *(++q) : *q;
1631
          *p++ = *q == '\\' ? *++q : *q;
1625
          q++;
1632
          q++;
1626
          }
1633
          }
1627
        else *p++ = *q++;
1634
        else *p++ = *q++;
Lines 1629-1635 Link Here
1629
      *p = 0;
1636
      *p = 0;
1630
      addr = deliver_make_addr(t, TRUE);
1637
      addr = deliver_make_addr(t, TRUE);
1631
      setflag(addr, af_pfr);                   /* indicates pipe/file/reply */
1638
      setflag(addr, af_pfr);                   /* indicates pipe/file/reply */
1632
      if (*s != '|') setflag(addr, af_file);   /* indicates file */
1639
      if (*s_ltd != '|') setflag(addr, af_file);   /* indicates file */
1633
      }
1640
      }
1634
1641
1635
    /* Item must be an address. Complain if not, else qualify, rewrite and set
1642
    /* Item must be an address. Complain if not, else qualify, rewrite and set
Lines 1641-1676 Link Here
1641
1648
1642
    else
1649
    else
1643
      {
1650
      {
1644
      if (recipient == NULL)
1651
      if (!recipient)
1645
        {
1652
        {
1646
        if (Ustrcmp(*error, "empty address") == 0)
1653
        if (Ustrcmp(*error, "empty address") == 0)
1647
          {
1654
          {
1648
          *error = NULL;
1655
          *error = NULL;
1649
          s[len] = save;
1650
          s = nexts;
1656
          s = nexts;
1651
          continue;
1657
          continue;
1652
          }
1658
          }
1653
1659
1654
        if (syntax_errors != NULL)
1660
        if (syntax_errors)
1655
          {
1661
          {
1656
          error_block *e = store_get(sizeof(error_block), FALSE);
1662
          error_block * e = store_get(sizeof(error_block), GET_UNTAINTED);
1657
          error_block *last = *syntax_errors;
1663
          error_block * last = *syntax_errors;
1658
          if (last == NULL) *syntax_errors = e; else
1664
          if (last)
1659
            {
1665
            {
1660
            while (last->next != NULL) last = last->next;
1666
            while (last->next) last = last->next;
1661
            last->next = e;
1667
            last->next = e;
1662
            }
1668
            }
1669
          else
1670
	    *syntax_errors = e;
1663
          e->next = NULL;
1671
          e->next = NULL;
1664
          e->text1 = *error;
1672
          e->text1 = *error;
1665
          e->text2 = string_copy(s);
1673
          e->text2 = s_ltd;
1666
          s[len] = save;
1667
          s = nexts;
1674
          s = nexts;
1668
          continue;
1675
          continue;
1669
          }
1676
          }
1670
        else
1677
        else
1671
          {
1678
          {
1672
          *error = string_sprintf("%s in \"%s\"", *error, s);
1679
          *error = string_sprintf("%s in \"%s\"", *error, s_ltd);
1673
          s[len] = save;   /* _after_ using it for *error */
1674
          return FF_ERROR;
1680
          return FF_ERROR;
1675
          }
1681
          }
1676
        }
1682
        }
Lines 1678-1694 Link Here
1678
      /* Address was successfully parsed. Rewrite, and then make an address
1684
      /* Address was successfully parsed. Rewrite, and then make an address
1679
      block. */
1685
      block. */
1680
1686
1681
      recipient = ((options & RDO_REWRITE) != 0)?
1687
      recipient = options & RDO_REWRITE
1682
        rewrite_address(recipient, TRUE, FALSE, global_rewrite_rules,
1688
	? rewrite_address(recipient, TRUE, FALSE, global_rewrite_rules,
1683
          rewrite_existflags) :
1689
			  rewrite_existflags)
1684
        rewrite_address_qualify(recipient, TRUE);	/*XXX loses track of const */
1690
	: rewrite_address_qualify(recipient, TRUE);	/*XXX loses track of const */
1685
      addr = deliver_make_addr(US recipient, TRUE);  /* TRUE => copy recipient, so deconst ok */
1691
      addr = deliver_make_addr(US recipient, TRUE);  /* TRUE => copy recipient, so deconst ok */
1686
      }
1692
      }
1687
1693
1688
    /* Restore the final character in the original data, and add to the
1694
    /* Add the original data to the output chain. */
1689
    output chain. */
1690
1695
1691
    s[len] = save;
1692
    addr->next = *anchor;
1696
    addr->next = *anchor;
1693
    *anchor = addr;
1697
    *anchor = addr;
1694
    count++;
1698
    count++;
Lines 1735-1741 Link Here
1735
line. Therefore, take care to release unwanted store afterwards. */
1739
line. Therefore, take care to release unwanted store afterwards. */
1736
1740
1737
reset_point = store_mark();
1741
reset_point = store_mark();
1738
id = *yield = store_get(Ustrlen(str) + 1, is_tainted(str));
1742
id = *yield = store_get(Ustrlen(str) + 1, str);
1739
*id++ = *str++;
1743
*id++ = *str++;
1740
1744
1741
str = read_addr_spec(str, id, '>', error, &domain);
1745
str = read_addr_spec(str, id, '>', error, &domain);
Lines 2086-2091 Link Here
2086
int start, end, domain;
2090
int start, end, domain;
2087
uschar buffer[1024];
2091
uschar buffer[1024];
2088
2092
2093
store_init();
2089
big_buffer = store_malloc(big_buffer_size);
2094
big_buffer = store_malloc(big_buffer_size);
2090
2095
2091
/* strip_trailing_dot = TRUE; */
2096
/* strip_trailing_dot = TRUE; */
(-)exim.orig/src/pdkim/pdkim.c (-27 / +30 lines)
Lines 1-6 Link Here
1
/*
1
/*
2
 *  PDKIM - a RFC4871 (DKIM) implementation
2
 *  PDKIM - a RFC4871 (DKIM) implementation
3
 *
3
 *
4
 *  Copyright (c) The Exim Maintainers 2021 - 2022
4
 *  Copyright (C) 2009 - 2016  Tom Kistner <tom@duncanthrax.net>
5
 *  Copyright (C) 2009 - 2016  Tom Kistner <tom@duncanthrax.net>
5
 *  Copyright (C) 2016 - 2020  Jeremy Harris <jgh@exim.org>
6
 *  Copyright (C) 2016 - 2020  Jeremy Harris <jgh@exim.org>
6
 *
7
 *
Lines 247-253 Link Here
247
static pdkim_stringlist *
248
static pdkim_stringlist *
248
pdkim_prepend_stringlist(pdkim_stringlist * base, const uschar * str)
249
pdkim_prepend_stringlist(pdkim_stringlist * base, const uschar * str)
249
{
250
{
250
pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist), FALSE);
251
pdkim_stringlist * new_entry = store_get(sizeof(pdkim_stringlist), GET_UNTAINTED);
251
252
252
memset(new_entry, 0, sizeof(pdkim_stringlist));
253
memset(new_entry, 0, sizeof(pdkim_stringlist));
253
new_entry->value = string_copy(str);
254
new_entry->value = string_copy(str);
Lines 337-343 Link Here
337
{
338
{
338
BOOL past_field_name = FALSE;
339
BOOL past_field_name = FALSE;
339
BOOL seen_wsp = FALSE;
340
BOOL seen_wsp = FALSE;
340
uschar * relaxed = store_get(len+3, TRUE);	/* tainted */
341
uschar * relaxed = store_get(len+3, GET_TAINTED);
341
uschar * q = relaxed;
342
uschar * q = relaxed;
342
343
343
for (const uschar * p = header; p - header < len; p++)
344
for (const uschar * p = header; p - header < len; p++)
Lines 417-423 Link Here
417
int nchar = 0;
418
int nchar = 0;
418
uschar * q;
419
uschar * q;
419
const uschar * p = str;
420
const uschar * p = str;
420
uschar * n = store_get(Ustrlen(str)+1, TRUE);
421
uschar * n = store_get(Ustrlen(str)+1, GET_TAINTED);
421
422
422
*n = '\0';
423
*n = '\0';
423
q = n;
424
q = n;
Lines 474-480 Link Here
474
BOOL in_b_val = FALSE;
475
BOOL in_b_val = FALSE;
475
int where = PDKIM_HDR_LIMBO;
476
int where = PDKIM_HDR_LIMBO;
476
477
477
sig = store_get(sizeof(pdkim_signature), FALSE);
478
sig = store_get(sizeof(pdkim_signature), GET_UNTAINTED);
478
memset(sig, 0, sizeof(pdkim_signature));
479
memset(sig, 0, sizeof(pdkim_signature));
479
sig->bodylength = -1;
480
sig->bodylength = -1;
480
481
Lines 483-489 Link Here
483
sig->keytype = -1;
484
sig->keytype = -1;
484
sig->hashtype = -1;
485
sig->hashtype = -1;
485
486
486
q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1, TRUE);	/* tainted */
487
q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1, GET_TAINTED);
487
488
488
for (uschar * p = raw_hdr; ; p++)
489
for (uschar * p = raw_hdr; ; p++)
489
  {
490
  {
Lines 663-669 Link Here
663
int sep = ';';
664
int sep = ';';
664
pdkim_pubkey * pub;
665
pdkim_pubkey * pub;
665
666
666
pub = store_get(sizeof(pdkim_pubkey), TRUE);	/* tainted */
667
pub = store_get(sizeof(pdkim_pubkey), GET_TAINTED);
667
memset(pub, 0, sizeof(pdkim_pubkey));
668
memset(pub, 0, sizeof(pdkim_pubkey));
668
669
669
while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0)))
670
while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0)))
Lines 793-800 Link Here
793
{
794
{
794
for (pdkim_bodyhash * b = ctx->bodyhash; b; b = b->next)     /* Finish hashes */
795
for (pdkim_bodyhash * b = ctx->bodyhash; b; b = b->next)     /* Finish hashes */
795
  {
796
  {
796
  DEBUG(D_acl) debug_printf("DKIM: finish bodyhash %d/%d/%ld len %ld\n",
797
  DEBUG(D_acl) debug_printf("DKIM: finish bodyhash %s/%s/%ld len %ld\n",
797
	    b->hashtype, b->canon_method, b->bodylength, b->signed_body_bytes);
798
      pdkim_hashes[b->hashtype].dkim_hashname, pdkim_canons[b->canon_method],
799
      b->bodylength, b->signed_body_bytes);
798
  exim_sha_finish(&b->body_hash_ctx, &b->bh);
800
  exim_sha_finish(&b->body_hash_ctx, &b->bh);
799
  }
801
  }
800
802
Lines 805-814 Link Here
805
807
806
  DEBUG(D_acl)
808
  DEBUG(D_acl)
807
    {
809
    {
808
    debug_printf("DKIM [%s] Body bytes (%s) hashed: %lu\n"
810
    debug_printf("DKIM [%s]%s Body bytes (%s) hashed: %lu\n"
809
		 "DKIM [%s] Body %s computed: ",
811
		 "DKIM [%s]%s Body %s computed: ",
810
	sig->domain, pdkim_canons[b->canon_method], b->signed_body_bytes,
812
	sig->domain, sig->selector, pdkim_canons[b->canon_method], b->signed_body_bytes,
811
	sig->domain, pdkim_hashes[b->hashtype].dkim_hashname);
813
	sig->domain, sig->selector, pdkim_hashes[b->hashtype].dkim_hashname);
812
    pdkim_hexprint(CUS b->bh.data, b->bh.len);
814
    pdkim_hexprint(CUS b->bh.data, b->bh.len);
813
    }
815
    }
814
816
Lines 1264-1270 Link Here
1264
1266
1265
if (sig->created > 0)
1267
if (sig->created > 0)
1266
  {
1268
  {
1267
  uschar minibuf[20];
1269
  uschar minibuf[21];
1268
1270
1269
  snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->created);
1271
  snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->created);
1270
  hdr = pdkim_headcat(&col, hdr, US";", US"t=", minibuf);
1272
  hdr = pdkim_headcat(&col, hdr, US";", US"t=", minibuf);
Lines 1272-1278 Link Here
1272
1274
1273
if (sig->expires > 0)
1275
if (sig->expires > 0)
1274
  {
1276
  {
1275
  uschar minibuf[20];
1277
  uschar minibuf[21];
1276
1278
1277
  snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->expires);
1279
  snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->expires);
1278
  hdr = pdkim_headcat(&col, hdr, US";", US"x=", minibuf);
1280
  hdr = pdkim_headcat(&col, hdr, US";", US"x=", minibuf);
Lines 1280-1286 Link Here
1280
1282
1281
if (sig->bodylength >= 0)
1283
if (sig->bodylength >= 0)
1282
  {
1284
  {
1283
  uschar minibuf[20];
1285
  uschar minibuf[21];
1284
1286
1285
  snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->bodylength);
1287
  snprintf(CS minibuf, sizeof(minibuf), "%lu", sig->bodylength);
1286
  hdr = pdkim_headcat(&col, hdr, US";", US"l=", minibuf);
1288
  hdr = pdkim_headcat(&col, hdr, US";", US"l=", minibuf);
Lines 1611-1617 Link Here
1611
	  rh = pdkim_relax_header(rh, TRUE);	/* cook header for relaxed canon */
1613
	  rh = pdkim_relax_header(rh, TRUE);	/* cook header for relaxed canon */
1612
1614
1613
	/* Feed header to the hash algorithm */
1615
	/* Feed header to the hash algorithm */
1614
	exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1616
	exim_sha_update_string(&hhash_ctx, CUS rh);
1615
1617
1616
	/* Remember headers block for signing (when the library cannot do incremental)  */
1618
	/* Remember headers block for signing (when the library cannot do incremental)  */
1617
	/*XXX we could avoid doing this for all but the GnuTLS/RSA case */
1619
	/*XXX we could avoid doing this for all but the GnuTLS/RSA case */
Lines 1672-1678 Link Here
1672
	      : string_copy(CUS hdrs->value);
1674
	      : string_copy(CUS hdrs->value);
1673
1675
1674
	    /* Feed header to the hash algorithm */
1676
	    /* Feed header to the hash algorithm */
1675
	    exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
1677
	    exim_sha_update_string(&hhash_ctx, CUS rh);
1676
1678
1677
	    DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1679
	    DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
1678
	    hdrs->tag = 1;
1680
	    hdrs->tag = 1;
Lines 1713-1719 Link Here
1713
    }
1715
    }
1714
1716
1715
  /* Finalize header hash */
1717
  /* Finalize header hash */
1716
  exim_sha_update(&hhash_ctx, CUS sig_hdr, Ustrlen(sig_hdr));
1718
  exim_sha_update_string(&hhash_ctx, CUS sig_hdr);
1717
  exim_sha_finish(&hhash_ctx, &hhash);
1719
  exim_sha_finish(&hhash_ctx, &hhash);
1718
1720
1719
  DEBUG(D_acl)
1721
  DEBUG(D_acl)
Lines 1918-1930 Link Here
1918
{
1920
{
1919
pdkim_ctx * ctx;
1921
pdkim_ctx * ctx;
1920
1922
1921
ctx = store_get(sizeof(pdkim_ctx), FALSE);
1923
ctx = store_get(sizeof(pdkim_ctx), GET_UNTAINTED);
1922
memset(ctx, 0, sizeof(pdkim_ctx));
1924
memset(ctx, 0, sizeof(pdkim_ctx));
1923
1925
1924
if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM;
1926
if (dot_stuffing) ctx->flags = PDKIM_DOT_TERM;
1925
/* The line-buffer is for message data, hence tainted */
1927
/* The line-buffer is for message data, hence tainted */
1926
ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN, TRUE);
1928
ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN, GET_TAINTED);
1927
ctx->dns_txt_callback = dns_txt_callback;
1929
ctx->dns_txt_callback = dns_txt_callback;
1930
ctx->cur_header = string_get_tainted(36, GET_TAINTED);
1928
1931
1929
return ctx;
1932
return ctx;
1930
}
1933
}
Lines 1945-1951 Link Here
1945
1948
1946
/* Allocate & init one signature struct */
1949
/* Allocate & init one signature struct */
1947
1950
1948
sig = store_get(sizeof(pdkim_signature), FALSE);
1951
sig = store_get(sizeof(pdkim_signature), GET_UNTAINTED);
1949
memset(sig, 0, sizeof(pdkim_signature));
1952
memset(sig, 0, sizeof(pdkim_signature));
1950
1953
1951
sig->bodylength = -1;
1954
sig->bodylength = -1;
Lines 2026-2039 Link Here
2026
     && canon_method == b->canon_method
2029
     && canon_method == b->canon_method
2027
     && bodylength == b->bodylength)
2030
     && bodylength == b->bodylength)
2028
    {
2031
    {
2029
    DEBUG(D_receive) debug_printf("DKIM: using existing bodyhash %d/%d/%ld\n",
2032
    DEBUG(D_receive) debug_printf("DKIM: using existing bodyhash %s/%s/%ld\n",
2030
				  hashtype, canon_method, bodylength);
2033
      pdkim_hashes[hashtype].dkim_hashname, pdkim_canons[canon_method], bodylength);
2031
    return b;
2034
    return b;
2032
    }
2035
    }
2033
2036
2034
DEBUG(D_receive) debug_printf("DKIM: new bodyhash %d/%d/%ld\n",
2037
DEBUG(D_receive) debug_printf("DKIM: new bodyhash %s/%s/%ld\n",
2035
			      hashtype, canon_method, bodylength);
2038
    pdkim_hashes[hashtype].dkim_hashname, pdkim_canons[canon_method], bodylength);
2036
b = store_get(sizeof(pdkim_bodyhash), FALSE);
2039
b = store_get(sizeof(pdkim_bodyhash), GET_UNTAINTED);
2037
b->next = ctx->bodyhash;
2040
b->next = ctx->bodyhash;
2038
b->hashtype = hashtype;
2041
b->hashtype = hashtype;
2039
b->canon_method = canon_method;
2042
b->canon_method = canon_method;
Lines 2078-2084 Link Here
2078
memset(ctx, 0, sizeof(pdkim_ctx));
2081
memset(ctx, 0, sizeof(pdkim_ctx));
2079
ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
2082
ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
2080
/* The line buffer is for message data, hence tainted */
2083
/* The line buffer is for message data, hence tainted */
2081
ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN, TRUE);
2084
ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN, GET_TAINTED);
2082
DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
2085
DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
2083
}
2086
}
2084
2087
(-)exim.orig/src/pdkim/signing.c (-6 / +10 lines)
Lines 1-7 Link Here
1
/*
1
/*
2
 *  PDKIM - a RFC4871 (DKIM) implementation
2
 *  PDKIM - a RFC4871 (DKIM) implementation
3
 *
3
 *  Copyright (c) The Exim Maintainers 1995 - 2022
4
 *  Copyright (C) 1995 - 2020  Exim maintainers
5
 *
4
 *
6
 *  signing/verification interface
5
 *  signing/verification interface
7
 */
6
 */
Lines 37-42 Link Here
37
#ifdef SIGN_GNUTLS
36
#ifdef SIGN_GNUTLS
38
# define EXIM_GNUTLS_LIBRARY_LOG_LEVEL 3
37
# define EXIM_GNUTLS_LIBRARY_LOG_LEVEL 3
39
38
39
# ifndef GNUTLS_VERIFY_ALLOW_BROKEN
40
#  define GNUTLS_VERIFY_ALLOW_BROKEN 0
41
# endif
42
40
43
41
/* Logging function which can be registered with
44
/* Logging function which can be registered with
42
 *   gnutls_global_set_log_function()
45
 *   gnutls_global_set_log_function()
Lines 219-225 Link Here
219
    default:		return US"nonhandled hash type";
222
    default:		return US"nonhandled hash type";
220
    }
223
    }
221
224
222
  if ((rc = gnutls_pubkey_verify_hash2(verify_ctx->key, algo, 0, &k, &s)) < 0)
225
  if ((rc = gnutls_pubkey_verify_hash2(verify_ctx->key, algo,
226
	      GNUTLS_VERIFY_ALLOW_BROKEN, &k, &s)) < 0)
223
    ret = US gnutls_strerror(rc);
227
    ret = US gnutls_strerror(rc);
224
  }
228
  }
225
229
Lines 502-508 Link Here
502
  }
506
  }
503
507
504
#define SIGSPACE 128
508
#define SIGSPACE 128
505
sig->data = store_get(SIGSPACE, FALSE);
509
sig->data = store_get(SIGSPACE, GET_UNTAINTED);
506
510
507
if (gcry_mpi_cmp (sign_ctx->p, sign_ctx->q) > 0)
511
if (gcry_mpi_cmp (sign_ctx->p, sign_ctx->q) > 0)
508
  {
512
  {
Lines 761-767 Link Here
761
if (  (ctx = EVP_MD_CTX_new())
765
if (  (ctx = EVP_MD_CTX_new())
762
   && EVP_DigestSignInit(ctx, NULL, md, NULL, sign_ctx->key) > 0
766
   && EVP_DigestSignInit(ctx, NULL, md, NULL, sign_ctx->key) > 0
763
   && EVP_DigestSign(ctx, NULL, &siglen, NULL, 0) > 0
767
   && EVP_DigestSign(ctx, NULL, &siglen, NULL, 0) > 0
764
   && (sig->data = store_get(siglen, FALSE))
768
   && (sig->data = store_get(siglen, GET_UNTAINTED))
765
769
766
   /* Obtain the signature (slen could change here!) */
770
   /* Obtain the signature (slen could change here!) */
767
   && EVP_DigestSign(ctx, sig->data, &siglen, data->data, data->len) > 0
771
   && EVP_DigestSign(ctx, sig->data, &siglen, data->data, data->len) > 0
Lines 777-783 Link Here
777
   && EVP_DigestSignInit(ctx, NULL, md, NULL, sign_ctx->key) > 0
781
   && EVP_DigestSignInit(ctx, NULL, md, NULL, sign_ctx->key) > 0
778
   && EVP_DigestSignUpdate(ctx, data->data, data->len) > 0
782
   && EVP_DigestSignUpdate(ctx, data->data, data->len) > 0
779
   && EVP_DigestSignFinal(ctx, NULL, &siglen) > 0
783
   && EVP_DigestSignFinal(ctx, NULL, &siglen) > 0
780
   && (sig->data = store_get(siglen, FALSE))
784
   && (sig->data = store_get(siglen, GET_UNTAINTED))
781
 
785
 
782
   /* Obtain the signature (slen could change here!) */
786
   /* Obtain the signature (slen could change here!) */
783
   && EVP_DigestSignFinal(ctx, sig->data, &siglen) > 0
787
   && EVP_DigestSignFinal(ctx, sig->data, &siglen) > 0
(-)exim.orig/src/perl.c (-1 / +5 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 1999 - 2022 */
5
/* Copyright (c) 1998 Malcolm Beattie */
6
/* Copyright (c) 1998 Malcolm Beattie */
6
/* Copyright (C) 1999 - 2018  Exim maintainers */
7
7
8
/* Modified by PH to get rid of the "na" usage, March 1999.
8
/* Modified by PH to get rid of the "na" usage, March 1999.
9
   Modified further by PH for general tidying for Exim 4.
9
   Modified further by PH for general tidying for Exim 4.
Lines 15-20 Link Here
15
/* See the file NOTICE for conditions of use and distribution. */
15
/* See the file NOTICE for conditions of use and distribution. */
16
16
17
#include <assert.h>
17
#include <assert.h>
18
19
#define HINTSDB_H
20
#define DBFUNCTIONS_H
21
18
#include "exim.h"
22
#include "exim.h"
19
23
20
#define EXIM_TRUE TRUE
24
#define EXIM_TRUE TRUE
(-)exim.orig/src/queue.c (-16 / +26 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Functions that operate on the input queue. */
9
/* Functions that operate on the input queue. */
Lines 26-31 Link Here
26
#define LOG2_MAXNODES 32
26
#define LOG2_MAXNODES 32
27
27
28
28
29
#ifndef DISABLE_TLS
30
static BOOL queue_tls_init = FALSE;
31
#endif
29
32
30
/*************************************************
33
/*************************************************
31
*  Helper sort function for queue_get_spool_list *
34
*  Helper sort function for queue_get_spool_list *
Lines 211-218 Link Here
211
	(*pcount)++;
214
	(*pcount)++;
212
      else
215
      else
213
	{
216
	{
214
	queue_filename *next =
217
	queue_filename * next =
215
	  store_get(sizeof(queue_filename) + Ustrlen(name), is_tainted(name));
218
	  store_get(sizeof(queue_filename) + Ustrlen(name), name);
216
	Ustrcpy(next->text, name);
219
	Ustrcpy(next->text, name);
217
	next->dir_uschar = subdirchar;
220
	next->dir_uschar = subdirchar;
218
221
Lines 347-354 Link Here
347
{
350
{
348
BOOL force_delivery = f.queue_run_force || deliver_selectstring != NULL ||
351
BOOL force_delivery = f.queue_run_force || deliver_selectstring != NULL ||
349
  deliver_selectstring_sender != NULL;
352
  deliver_selectstring_sender != NULL;
350
const pcre *selectstring_regex = NULL;
353
const pcre2_code *selectstring_regex = NULL;
351
const pcre *selectstring_regex_sender = NULL;
354
const pcre2_code *selectstring_regex_sender = NULL;
352
uschar *log_detail = NULL;
355
uschar *log_detail = NULL;
353
int subcount = 0;
356
int subcount = 0;
354
uschar subdirs[64];
357
uschar subdirs[64];
Lines 566-574 Link Here
566
569
567
      else if (  deliver_selectstring_sender
570
      else if (  deliver_selectstring_sender
568
	      && !(f.deliver_selectstring_sender_regex
571
	      && !(f.deliver_selectstring_sender_regex
569
		  ? (pcre_exec(selectstring_regex_sender, NULL,
572
		  ? regex_match(selectstring_regex_sender, sender_address, -1, NULL)
570
		      CS sender_address, Ustrlen(sender_address), 0, PCRE_EOPT,
571
		      NULL, 0) >= 0)
572
		  : (strstric(sender_address, deliver_selectstring_sender, FALSE)
573
		  : (strstric(sender_address, deliver_selectstring_sender, FALSE)
573
		      != NULL)
574
		      != NULL)
574
	      )   )
575
	      )   )
Lines 587-594 Link Here
587
          {
588
          {
588
          uschar *address = recipients_list[i].address;
589
          uschar *address = recipients_list[i].address;
589
          if (  (f.deliver_selectstring_regex
590
          if (  (f.deliver_selectstring_regex
590
		? (pcre_exec(selectstring_regex, NULL, CS address,
591
		? regex_match(selectstring_regex, address, -1, NULL)
591
		     Ustrlen(address), 0, PCRE_EOPT, NULL, 0) >= 0)
592
                : (strstric(address, deliver_selectstring, FALSE) != NULL)
592
                : (strstric(address, deliver_selectstring, FALSE) != NULL)
593
		)
593
		)
594
             && tree_search(tree_nonrecipients, address) == NULL
594
             && tree_search(tree_nonrecipients, address) == NULL
Lines 654-659 Link Here
654
    report_time_since(&timestamp_startup, US"queue msg selected");
654
    report_time_since(&timestamp_startup, US"queue msg selected");
655
#endif
655
#endif
656
656
657
#ifndef DISABLE_TLS
658
    if (!queue_tls_init)
659
      {
660
      queue_tls_init = TRUE;
661
      /* Preload TLS library info for smtp transports.  Once, and only if we
662
      have a delivery to do. */
663
      tls_client_creds_reload(FALSE);
664
      }
665
#endif
666
657
single_item_retry:
667
single_item_retry:
658
    if ((pid = exim_fork(US"qrun-delivery")) == 0)
668
    if ((pid = exim_fork(US"qrun-delivery")) == 0)
659
      {
669
      {
Lines 891-898 Link Here
891
  queue_filename *last = NULL;
901
  queue_filename *last = NULL;
892
  for (int i = 0; i < count; i++)
902
  for (int i = 0; i < count; i++)
893
    {
903
    {
894
    queue_filename *next =
904
    queue_filename * next =
895
      store_get(sizeof(queue_filename) + Ustrlen(list[i]) + 2, is_tainted(list[i]));
905
      store_get(sizeof(queue_filename) + Ustrlen(list[i]) + 2, list[i]);
896
    sprintf(CS next->text, "%s-H", list[i]);
906
    sprintf(CS next->text, "%s-H", list[i]);
897
    next->dir_uschar = '*';
907
    next->dir_uschar = '*';
898
    next->next = NULL;
908
    next->next = NULL;
Lines 1338-1352 Link Here
1338
	    deliver_domain = dom
1348
	    deliver_domain = dom
1339
	      ? CUS string_copyn(addr+dom, end - dom) : CUS"";
1349
	      ? CUS string_copyn(addr+dom, end - dom) : CUS"";
1340
1350
1341
	    event_raise(event_action, US"msg:fail:internal",
1351
	    (void) event_raise(event_action, US"msg:fail:internal",
1342
	      string_sprintf("message removed by %s", username));
1352
	      string_sprintf("message removed by %s", username), NULL);
1343
1353
1344
	    deliver_localpart = save_local;
1354
	    deliver_localpart = save_local;
1345
	    deliver_domain = save_domain;
1355
	    deliver_domain = save_domain;
1346
	    }
1356
	    }
1347
	  }
1357
	  }
1348
	}
1358
	}
1349
      (void) event_raise(event_action, US"msg:complete", NULL);
1359
      (void) event_raise(event_action, US"msg:complete", NULL, NULL);
1350
#endif
1360
#endif
1351
      log_write(0, LOG_MAIN, "removed by %s", username);
1361
      log_write(0, LOG_MAIN, "removed by %s", username);
1352
      log_write(0, LOG_MAIN, "Completed");
1362
      log_write(0, LOG_MAIN, "Completed");
Lines 1537-1543 Link Here
1537
/******************************************************************************/
1547
/******************************************************************************/
1538
/******************************************************************************/
1548
/******************************************************************************/
1539
1549
1540
#ifdef EXPERIMENTAL_QUEUE_RAMP
1550
#ifndef DISABLE_QUEUE_RAMP
1541
void
1551
void
1542
queue_notify_daemon(const uschar * msgid)
1552
queue_notify_daemon(const uschar * msgid)
1543
{
1553
{
(-)exim.orig/src/rda.c (-25 / +23 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* This module contains code for extracting addresses from a forwarding list
9
/* This module contains code for extracting addresses from a forwarding list
Lines 166-172 Link Here
166
*/
166
*/
167
167
168
static uschar *
168
static uschar *
169
rda_get_file_contents(redirect_block *rdata, int options, uschar **error,
169
rda_get_file_contents(const redirect_block *rdata, int options, uschar **error,
170
  int *yield)
170
  int *yield)
171
{
171
{
172
FILE *fwd;
172
FILE *fwd;
Lines 222-228 Link Here
222
222
223
DEFAULT_ERROR:
223
DEFAULT_ERROR:
224
  default:
224
  default:
225
    *error = string_open_failed(errno, "%s", filename);
225
    *error = string_open_failed("%s", filename);
226
    *yield = FF_ERROR;
226
    *yield = FF_ERROR;
227
    return NULL;
227
    return NULL;
228
  }
228
  }
Lines 284-290 Link Here
284
284
285
/* Read the file in one go in order to minimize the time we have it open. */
285
/* Read the file in one go in order to minimize the time we have it open. */
286
286
287
filebuf = store_get(statbuf.st_size + 1, is_tainted(filename));
287
filebuf = store_get(statbuf.st_size + 1, filename);
288
288
289
if (fread(filebuf, 1, statbuf.st_size, fwd) != statbuf.st_size)
289
if (fread(filebuf, 1, statbuf.st_size, fwd) != statbuf.st_size)
290
  {
290
  {
Lines 339-351 Link Here
339
*/
339
*/
340
340
341
static int
341
static int
342
rda_extract(redirect_block *rdata, int options, uschar *include_directory,
342
rda_extract(const redirect_block * rdata, int options,
343
  uschar *sieve_vacation_directory, uschar *sieve_enotify_mailto_owner,
343
  const uschar * include_directory, const uschar * sieve_vacation_directory,
344
  uschar *sieve_useraddress, uschar *sieve_subaddress,
344
  const uschar * sieve_enotify_mailto_owner, const uschar * sieve_useraddress,
345
  address_item **generated, uschar **error, error_block **eblockp,
345
  const uschar * sieve_subaddress, address_item ** generated, uschar ** error,
346
  int *filtertype)
346
  error_block ** eblockp, int * filtertype)
347
{
347
{
348
uschar *data;
348
const uschar * data;
349
349
350
if (rdata->isfile)
350
if (rdata->isfile)
351
  {
351
  {
Lines 442-450 Link Here
442
static int
442
static int
443
rda_write_string(int fd, const uschar *s)
443
rda_write_string(int fd, const uschar *s)
444
{
444
{
445
int len = (s == NULL)? 0 : Ustrlen(s) + 1;
445
int len = s ? Ustrlen(s) + 1 : 0;
446
return (  write(fd, &len, sizeof(int)) != sizeof(int)
446
return (  write(fd, &len, sizeof(int)) != sizeof(int)
447
       || (s != NULL  &&  write(fd, s, len) != len)
447
       || (s   &&  write(fd, s, len) != len)
448
       )
448
       )
449
       ? -1 : 0;
449
       ? -1 : 0;
450
}
450
}
Lines 476-482 Link Here
476
  /* We know we have enough memory so disable the error on "len" */
476
  /* We know we have enough memory so disable the error on "len" */
477
  /* coverity[tainted_data] */
477
  /* coverity[tainted_data] */
478
  /* We trust the data source, so untainted */
478
  /* We trust the data source, so untainted */
479
  if (read(fd, *sp = store_get(len, FALSE), len) != len) return FALSE;
479
  if (read(fd, *sp = store_get(len, GET_UNTAINTED), len) != len) return FALSE;
480
return TRUE;
480
return TRUE;
481
}
481
}
482
482
Lines 541-551 Link Here
541
*/
541
*/
542
542
543
int
543
int
544
rda_interpret(redirect_block *rdata, int options, uschar *include_directory,
544
rda_interpret(redirect_block * rdata, int options,
545
  uschar *sieve_vacation_directory, uschar *sieve_enotify_mailto_owner,
545
  const uschar * include_directory, const uschar * sieve_vacation_directory,
546
  uschar *sieve_useraddress, uschar *sieve_subaddress, ugid_block *ugid,
546
  const uschar * sieve_enotify_mailto_owner, const uschar * sieve_useraddress,
547
  address_item **generated, uschar **error, error_block **eblockp,
547
  const uschar * sieve_subaddress, const ugid_block * ugid, address_item ** generated,
548
  int *filtertype, uschar *rname)
548
  uschar ** error, error_block ** eblockp, int * filtertype, const uschar * rname)
549
{
549
{
550
int fd, rc, pfd[2];
550
int fd, rc, pfd[2];
551
int yield, status;
551
int yield, status;
Lines 808-814 Link Here
808
    uschar *s;
808
    uschar *s;
809
    if (!rda_read_string(fd, &s)) goto DISASTER;
809
    if (!rda_read_string(fd, &s)) goto DISASTER;
810
    if (!s) break;
810
    if (!s) break;
811
    e = store_get(sizeof(error_block), FALSE);
811
    e = store_get(sizeof(error_block), GET_UNTAINTED);
812
    e->next = NULL;
812
    e->next = NULL;
813
    e->text1 = s;
813
    e->text1 = s;
814
    if (!rda_read_string(fd, &s)) goto DISASTER;
814
    if (!rda_read_string(fd, &s)) goto DISASTER;
Lines 907-913 Link Here
907
907
908
    if (i > 0)
908
    if (i > 0)
909
      {
909
      {
910
      addr->pipe_expandn = store_get((i+1) * sizeof(uschar *), FALSE);
910
      addr->pipe_expandn = store_get((i+1) * sizeof(uschar *), GET_UNTAINTED);
911
      addr->pipe_expandn[i] = NULL;
911
      addr->pipe_expandn[i] = NULL;
912
      while (--i >= 0) addr->pipe_expandn[i] = expandn[i];
912
      while (--i >= 0) addr->pipe_expandn[i] = expandn[i];
913
      }
913
      }
Lines 917-923 Link Here
917
    if (read(fd, &reply_options, sizeof(int)) != sizeof(int)) goto DISASTER;
917
    if (read(fd, &reply_options, sizeof(int)) != sizeof(int)) goto DISASTER;
918
    if ((reply_options & REPLY_EXISTS) != 0)
918
    if ((reply_options & REPLY_EXISTS) != 0)
919
      {
919
      {
920
      addr->reply = store_get(sizeof(reply_item), FALSE);
920
      addr->reply = store_get(sizeof(reply_item), GET_UNTAINTED);
921
921
922
      addr->reply->file_expand = (reply_options & REPLY_EXPAND) != 0;
922
      addr->reply->file_expand = (reply_options & REPLY_EXPAND) != 0;
923
      addr->reply->return_message = (reply_options & REPLY_RETURN) != 0;
923
      addr->reply->return_message = (reply_options & REPLY_RETURN) != 0;
Lines 961-976 Link Here
961
  *error = string_sprintf("internal problem in %s: failure to transfer "
961
  *error = string_sprintf("internal problem in %s: failure to transfer "
962
    "data from subprocess: status=%04x%s%s%s", rname,
962
    "data from subprocess: status=%04x%s%s%s", rname,
963
    status, readerror,
963
    status, readerror,
964
    (*error == NULL)? US"" : US": error=",
964
    *error ? US": error=" : US"",
965
    (*error == NULL)? US"" : *error);
965
    *error ? *error : US"");
966
  log_write(0, LOG_MAIN|LOG_PANIC, "%s", *error);
966
  log_write(0, LOG_MAIN|LOG_PANIC, "%s", *error);
967
  }
967
  }
968
else if (status != 0)
968
else if (status != 0)
969
  {
970
  log_write(0, LOG_MAIN|LOG_PANIC, "internal problem in %s: unexpected status "
969
  log_write(0, LOG_MAIN|LOG_PANIC, "internal problem in %s: unexpected status "
971
    "%04x from redirect subprocess (but data correctly received)", rname,
970
    "%04x from redirect subprocess (but data correctly received)", rname,
972
    status);
971
    status);
973
  }
974
972
975
FINAL_EXIT:
973
FINAL_EXIT:
976
(void)close(fd);
974
(void)close(fd);
(-)exim.orig/src/readconf.c (-127 / +144 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Functions for reading the configuration file, and for displaying
9
/* Functions for reading the configuration file, and for displaying
Lines 181-186 Link Here
181
#ifdef SUPPORT_PROXY
181
#ifdef SUPPORT_PROXY
182
  { "hosts_proxy",              opt_stringptr,   {&hosts_proxy} },
182
  { "hosts_proxy",              opt_stringptr,   {&hosts_proxy} },
183
#endif
183
#endif
184
#ifndef DISABLE_TLS
185
  { "hosts_require_alpn",       opt_stringptr,   {&hosts_require_alpn} },
186
#endif
187
  { "hosts_require_helo",       opt_stringptr,   {&hosts_require_helo} },
184
  { "hosts_treat_as_local",     opt_stringptr,   {&hosts_treat_as_local} },
188
  { "hosts_treat_as_local",     opt_stringptr,   {&hosts_treat_as_local} },
185
#ifdef LOOKUP_IBASE
189
#ifdef LOOKUP_IBASE
186
  { "ibase_servers",            opt_stringptr,   {&ibase_servers} },
190
  { "ibase_servers",            opt_stringptr,   {&ibase_servers} },
Lines 201-206 Link Here
201
  { "ldap_start_tls",           opt_bool,        {&eldap_start_tls} },
205
  { "ldap_start_tls",           opt_bool,        {&eldap_start_tls} },
202
  { "ldap_version",             opt_int,         {&eldap_version} },
206
  { "ldap_version",             opt_int,         {&eldap_version} },
203
#endif
207
#endif
208
#ifdef EXPERIMENTAL_ESMTP_LIMITS
209
  { "limits_advertise_hosts", opt_stringptr, {&limits_advertise_hosts} },
210
#endif
204
  { "local_from_check",         opt_bool,        {&local_from_check} },
211
  { "local_from_check",         opt_bool,        {&local_from_check} },
205
  { "local_from_prefix",        opt_stringptr,   {&local_from_prefix} },
212
  { "local_from_prefix",        opt_stringptr,   {&local_from_prefix} },
206
  { "local_from_suffix",        opt_stringptr,   {&local_from_suffix} },
213
  { "local_from_suffix",        opt_stringptr,   {&local_from_suffix} },
Lines 259-268 Link Here
259
  { "print_topbitchars",        opt_bool,        {&print_topbitchars} },
266
  { "print_topbitchars",        opt_bool,        {&print_topbitchars} },
260
  { "process_log_path",         opt_stringptr,   {&process_log_path} },
267
  { "process_log_path",         opt_stringptr,   {&process_log_path} },
261
  { "prod_requires_admin",      opt_bool,        {&prod_requires_admin} },
268
  { "prod_requires_admin",      opt_bool,        {&prod_requires_admin} },
269
#ifdef SUPPORT_PROXY
270
  { "proxy_protocol_timeout",   opt_time,        {&proxy_protocol_timeout} },
271
#endif
262
  { "qualify_domain",           opt_stringptr,   {&qualify_domain_sender} },
272
  { "qualify_domain",           opt_stringptr,   {&qualify_domain_sender} },
263
  { "qualify_recipient",        opt_stringptr,   {&qualify_domain_recipient} },
273
  { "qualify_recipient",        opt_stringptr,   {&qualify_domain_recipient} },
264
  { "queue_domains",            opt_stringptr,   {&queue_domains} },
274
  { "queue_domains",            opt_stringptr,   {&queue_domains} },
265
#ifdef EXPERIMENTAL_QUEUE_RAMP
275
#ifndef DISABLE_QUEUE_RAMP
266
  { "queue_fast_ramp",          opt_bool,        {&queue_fast_ramp} },
276
  { "queue_fast_ramp",          opt_bool,        {&queue_fast_ramp} },
267
#endif
277
#endif
268
  { "queue_list_requires_admin",opt_bool,        {&queue_list_requires_admin} },
278
  { "queue_list_requires_admin",opt_bool,        {&queue_list_requires_admin} },
Lines 297-308 Link Here
297
  { "smtp_accept_max",          opt_int,         {&smtp_accept_max} },
307
  { "smtp_accept_max",          opt_int,         {&smtp_accept_max} },
298
  { "smtp_accept_max_nonmail",  opt_int,         {&smtp_accept_max_nonmail} },
308
  { "smtp_accept_max_nonmail",  opt_int,         {&smtp_accept_max_nonmail} },
299
  { "smtp_accept_max_nonmail_hosts", opt_stringptr, {&smtp_accept_max_nonmail_hosts} },
309
  { "smtp_accept_max_nonmail_hosts", opt_stringptr, {&smtp_accept_max_nonmail_hosts} },
300
  { "smtp_accept_max_per_connection", opt_int,   {&smtp_accept_max_per_connection} },
310
  { "smtp_accept_max_per_connection", opt_stringptr,   {&smtp_accept_max_per_connection} },
301
  { "smtp_accept_max_per_host", opt_stringptr,   {&smtp_accept_max_per_host} },
311
  { "smtp_accept_max_per_host", opt_stringptr,   {&smtp_accept_max_per_host} },
302
  { "smtp_accept_queue",        opt_int,         {&smtp_accept_queue} },
312
  { "smtp_accept_queue",        opt_int,         {&smtp_accept_queue} },
303
  { "smtp_accept_queue_per_connection", opt_int, {&smtp_accept_queue_per_connection} },
313
  { "smtp_accept_queue_per_connection", opt_int, {&smtp_accept_queue_per_connection} },
304
  { "smtp_accept_reserve",      opt_int,         {&smtp_accept_reserve} },
314
  { "smtp_accept_reserve",      opt_int,         {&smtp_accept_reserve} },
305
  { "smtp_active_hostname",     opt_stringptr,   {&raw_active_hostname} },
315
  { "smtp_active_hostname",     opt_stringptr,   {&raw_active_hostname} },
316
  { "smtp_backlog_monitor",     opt_int,         {&smtp_backlog_monitor} },
306
  { "smtp_banner",              opt_stringptr,   {&smtp_banner} },
317
  { "smtp_banner",              opt_stringptr,   {&smtp_banner} },
307
  { "smtp_check_spool_space",   opt_bool,        {&smtp_check_spool_space} },
318
  { "smtp_check_spool_space",   opt_bool,        {&smtp_check_spool_space} },
308
  { "smtp_connect_backlog",     opt_int,         {&smtp_connect_backlog} },
319
  { "smtp_connect_backlog",     opt_int,         {&smtp_connect_backlog} },
Lines 335-349 Link Here
335
  { "sqlite_dbfile",            opt_stringptr,   {&sqlite_dbfile} },
346
  { "sqlite_dbfile",            opt_stringptr,   {&sqlite_dbfile} },
336
  { "sqlite_lock_timeout",      opt_int,         {&sqlite_lock_timeout} },
347
  { "sqlite_lock_timeout",      opt_int,         {&sqlite_lock_timeout} },
337
#endif
348
#endif
338
#ifdef EXPERIMENTAL_SRS
339
  { "srs_config",               opt_stringptr,   {&srs_config} },
340
  { "srs_hashlength",           opt_int,         {&srs_hashlength} },
341
  { "srs_hashmin",              opt_int,         {&srs_hashmin} },
342
  { "srs_maxage",               opt_int,         {&srs_maxage} },
343
  { "srs_secrets",              opt_stringptr,   {&srs_secrets} },
344
  { "srs_usehash",              opt_bool,        {&srs_usehash} },
345
  { "srs_usetimestamp",         opt_bool,        {&srs_usetimestamp} },
346
#endif
347
  { "strict_acl_vars",          opt_bool,        {&strict_acl_vars} },
349
  { "strict_acl_vars",          opt_bool,        {&strict_acl_vars} },
348
  { "strip_excess_angle_brackets", opt_bool,     {&strip_excess_angle_brackets} },
350
  { "strip_excess_angle_brackets", opt_bool,     {&strip_excess_angle_brackets} },
349
  { "strip_trailing_dot",       opt_bool,        {&strip_trailing_dot} },
351
  { "strip_trailing_dot",       opt_bool,        {&strip_trailing_dot} },
Lines 367-372 Link Here
367
  { "timezone",                 opt_stringptr,   {&timezone_string} },
369
  { "timezone",                 opt_stringptr,   {&timezone_string} },
368
  { "tls_advertise_hosts",      opt_stringptr,   {&tls_advertise_hosts} },
370
  { "tls_advertise_hosts",      opt_stringptr,   {&tls_advertise_hosts} },
369
#ifndef DISABLE_TLS
371
#ifndef DISABLE_TLS
372
  { "tls_alpn",		        opt_stringptr,   {&tls_alpn} },
370
  { "tls_certificate",          opt_stringptr,   {&tls_certificate} },
373
  { "tls_certificate",          opt_stringptr,   {&tls_certificate} },
371
  { "tls_crl",                  opt_stringptr,   {&tls_crl} },
374
  { "tls_crl",                  opt_stringptr,   {&tls_crl} },
372
  { "tls_dh_max_bits",          opt_int,         {&tls_dh_max_bits} },
375
  { "tls_dh_max_bits",          opt_int,         {&tls_dh_max_bits} },
Lines 379-385 Link Here
379
  { "tls_privatekey",           opt_stringptr,   {&tls_privatekey} },
382
  { "tls_privatekey",           opt_stringptr,   {&tls_privatekey} },
380
  { "tls_remember_esmtp",       opt_bool,        {&tls_remember_esmtp} },
383
  { "tls_remember_esmtp",       opt_bool,        {&tls_remember_esmtp} },
381
  { "tls_require_ciphers",      opt_stringptr,   {&tls_require_ciphers} },
384
  { "tls_require_ciphers",      opt_stringptr,   {&tls_require_ciphers} },
382
# ifdef EXPERIMENTAL_TLS_RESUME
385
# ifndef DISABLE_TLS_RESUME
383
  { "tls_resumption_hosts",     opt_stringptr,   {&tls_resumption_hosts} },
386
  { "tls_resumption_hosts",     opt_stringptr,   {&tls_resumption_hosts} },
384
# endif
387
# endif
385
  { "tls_try_verify_hosts",     opt_stringptr,   {&tls_try_verify_hosts} },
388
  { "tls_try_verify_hosts",     opt_stringptr,   {&tls_try_verify_hosts} },
Lines 643-649 Link Here
643
macro_item *
646
macro_item *
644
macro_create(const uschar * name, const uschar * val, BOOL command_line)
647
macro_create(const uschar * name, const uschar * val, BOOL command_line)
645
{
648
{
646
macro_item * m = store_get(sizeof(macro_item), FALSE);
649
macro_item * m = store_get(sizeof(macro_item), GET_UNTAINTED);
647
650
648
READCONF_DEBUG fprintf(stderr, "%s: '%s' '%s'\n", __FUNCTION__, name, val);
651
READCONF_DEBUG fprintf(stderr, "%s: '%s' '%s'\n", __FUNCTION__, name, val);
649
m->next = NULL;
652
m->next = NULL;
Lines 1073-1079 Link Here
1073
1076
1074
    if (config_lines)
1077
    if (config_lines)
1075
      save_config_position(config_filename, config_lineno);
1078
      save_config_position(config_filename, config_lineno);
1076
    save = store_get(sizeof(config_file_item), FALSE);
1079
    save = store_get(sizeof(config_file_item), GET_UNTAINTED);
1077
    save->next = config_file_stack;
1080
    save->next = config_file_stack;
1078
    config_file_stack = save;
1081
    config_file_stack = save;
1079
    save->file = config_file;
1082
    save->file = config_file;
Lines 1422-1428 Link Here
1422
static rewrite_rule *
1425
static rewrite_rule *
1423
readconf_one_rewrite(const uschar *p, int *existflags, BOOL isglobal)
1426
readconf_one_rewrite(const uschar *p, int *existflags, BOOL isglobal)
1424
{
1427
{
1425
rewrite_rule *next = store_get(sizeof(rewrite_rule), FALSE);
1428
rewrite_rule * next = store_get(sizeof(rewrite_rule), GET_UNTAINTED);
1426
1429
1427
next->next = NULL;
1430
next->next = NULL;
1428
next->key = string_dequote(&p);
1431
next->key = string_dequote(&p);
Lines 1855-1860 Link Here
1855
        flagptr = (int *)ol3->v.value;
1858
        flagptr = (int *)ol3->v.value;
1856
        }
1859
        }
1857
1860
1861
      /* This will trap if sptr is tainted. Not sure if that can happen */
1858
      while ((p = string_nextinlist(CUSS &sptr, &sep, big_buffer, BIG_BUFFER_SIZE)))
1862
      while ((p = string_nextinlist(CUSS &sptr, &sep, big_buffer, BIG_BUFFER_SIZE)))
1859
        {
1863
        {
1860
        rewrite_rule *next = readconf_one_rewrite(p, flagptr, FALSE);
1864
        rewrite_rule *next = readconf_one_rewrite(p, flagptr, FALSE);
Lines 1999-2004 Link Here
1999
      while (count-- > 1)
2003
      while (count-- > 1)
2000
        {
2004
        {
2001
        int sep = 0;
2005
        int sep = 0;
2006
	/* If p is tainted we trap.  Not sure that can happen */
2002
        (void)string_nextinlist(&p, &sep, big_buffer, BIG_BUFFER_SIZE);
2007
        (void)string_nextinlist(&p, &sep, big_buffer, BIG_BUFFER_SIZE);
2003
        if (!route_finduser(big_buffer, NULL, &uid))
2008
        if (!route_finduser(big_buffer, NULL, &uid))
2004
          log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "user %s was not found",
2009
          log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "user %s was not found",
Lines 2040-2045 Link Here
2040
      while (count-- > 1)
2045
      while (count-- > 1)
2041
        {
2046
        {
2042
        int sep = 0;
2047
        int sep = 0;
2048
	/* If p is tainted we trap.  Not sure that can happen */
2043
        (void)string_nextinlist(&p, &sep, big_buffer, BIG_BUFFER_SIZE);
2049
        (void)string_nextinlist(&p, &sep, big_buffer, BIG_BUFFER_SIZE);
2044
        if (!route_findgroup(big_buffer, &gid))
2050
        if (!route_findgroup(big_buffer, &gid))
2045
          log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "group %s was not found",
2051
          log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "group %s was not found",
Lines 2997-3003 Link Here
2997
BOOL forcecache = FALSE;
3003
BOOL forcecache = FALSE;
2998
uschar *ss;
3004
uschar *ss;
2999
tree_node *t;
3005
tree_node *t;
3000
namedlist_block * nb = store_get(sizeof(namedlist_block), FALSE);
3006
namedlist_block * nb = store_get_perm(sizeof(namedlist_block), FALSE);
3001
3007
3002
if (Ustrncmp(s, "_cache", 6) == 0)
3008
if (Ustrncmp(s, "_cache", 6) == 0)
3003
  {
3009
  {
Lines 3015-3021 Link Here
3015
Uskip_whitespace(&s);
3021
Uskip_whitespace(&s);
3016
ss = s;
3022
ss = s;
3017
while (isalnum(*s) || *s == '_') s++;
3023
while (isalnum(*s) || *s == '_') s++;
3018
t = store_get(sizeof(tree_node) + s-ss, is_tainted(ss));
3024
t = store_get(sizeof(tree_node) + s-ss, ss);
3019
Ustrncpy(t->name, ss, s-ss);
3025
Ustrncpy(t->name, ss, s-ss);
3020
t->name[s-ss] = 0;
3026
t->name[s-ss] = 0;
3021
Uskip_whitespace(&s);
3027
Uskip_whitespace(&s);
Lines 3122-3181 Link Here
3122
3128
3123
/* Loop through the possible file names */
3129
/* Loop through the possible file names */
3124
3130
3131
/* Should never be a tainted list */
3125
while((filename = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
3132
while((filename = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
3126
  {
3133
  {
3127
3134
3128
  /* Cut out all the fancy processing unless specifically wanted */
3135
  /* Cut out all the fancy processing unless specifically wanted */
3129
3136
3130
  #if defined(CONFIGURE_FILE_USE_NODE) || defined(CONFIGURE_FILE_USE_EUID)
3137
#if defined(CONFIGURE_FILE_USE_NODE) || defined(CONFIGURE_FILE_USE_EUID)
3131
  uschar *suffix = filename + Ustrlen(filename);
3138
  uschar *suffix = filename + Ustrlen(filename);
3132
3139
3133
  /* Try for the node-specific file if a node name exists */
3140
  /* Try for the node-specific file if a node name exists */
3134
3141
3135
  #ifdef CONFIGURE_FILE_USE_NODE
3142
# ifdef CONFIGURE_FILE_USE_NODE
3136
  struct utsname uts;
3143
  struct utsname uts;
3137
  if (uname(&uts) >= 0)
3144
  if (uname(&uts) >= 0)
3138
    {
3145
    {
3139
    #ifdef CONFIGURE_FILE_USE_EUID
3146
#  ifdef CONFIGURE_FILE_USE_EUID
3140
    sprintf(CS suffix, ".%ld.%.256s", (long int)original_euid, uts.nodename);
3147
    sprintf(CS suffix, ".%ld.%.256s", (long int)original_euid, uts.nodename);
3141
    config_file = Ufopen(filename, "rb");
3148
    if (!(config_file = Ufopen(filename, "rb")))
3142
    if (config_file == NULL)
3149
#  endif  /* CONFIGURE_FILE_USE_EUID */
3143
    #endif  /* CONFIGURE_FILE_USE_EUID */
3144
      {
3150
      {
3145
      sprintf(CS suffix, ".%.256s", uts.nodename);
3151
      sprintf(CS suffix, ".%.256s", uts.nodename);
3146
      config_file = Ufopen(filename, "rb");
3152
      config_file = Ufopen(filename, "rb");
3147
      }
3153
      }
3148
    }
3154
    }
3149
  #endif  /* CONFIGURE_FILE_USE_NODE */
3155
# endif  /* CONFIGURE_FILE_USE_NODE */
3150
3156
3151
  /* Otherwise, try the generic name, possibly with the euid added */
3157
  /* Otherwise, try the generic name, possibly with the euid added */
3152
3158
3153
  #ifdef CONFIGURE_FILE_USE_EUID
3159
# ifdef CONFIGURE_FILE_USE_EUID
3154
  if (config_file == NULL)
3160
  if (!config_file)
3155
    {
3161
    {
3156
    sprintf(CS suffix, ".%ld", (long int)original_euid);
3162
    sprintf(CS suffix, ".%ld", (long int)original_euid);
3157
    config_file = Ufopen(filename, "rb");
3163
    config_file = Ufopen(filename, "rb");
3158
    }
3164
    }
3159
  #endif  /* CONFIGURE_FILE_USE_EUID */
3165
# endif  /* CONFIGURE_FILE_USE_EUID */
3160
3166
3161
  /* Finally, try the unadorned name */
3167
  /* Finally, try the unadorned name */
3162
3168
3163
  if (config_file == NULL)
3169
  if (!config_file)
3164
    {
3170
    {
3165
    *suffix = 0;
3171
    *suffix = 0;
3166
    config_file = Ufopen(filename, "rb");
3172
    config_file = Ufopen(filename, "rb");
3167
    }
3173
    }
3168
  #else  /* if neither defined */
3174
#else  /* if neither defined */
3169
3175
3170
  /* This is the common case when the fancy processing is not included. */
3176
  /* This is the common case when the fancy processing is not included. */
3171
3177
3172
  config_file = Ufopen(filename, "rb");
3178
  config_file = Ufopen(filename, "rb");
3173
  #endif
3179
#endif
3174
3180
3175
  /* If the file does not exist, continue to try any others. For any other
3181
  /* If the file does not exist, continue to try any others. For any other
3176
  error, break out (and die). */
3182
  error, break out (and die). */
3177
3183
3178
  if (config_file != NULL || errno != ENOENT) break;
3184
  if (config_file || errno != ENOENT) break;
3179
  }
3185
  }
3180
3186
3181
/* On success, save the name for verification; config_filename is used when
3187
/* On success, save the name for verification; config_filename is used when
Lines 3198-3236 Link Here
3198
    config_main_directory = last_slash == filename ? US"/" : string_copyn(filename, last_slash - filename);
3204
    config_main_directory = last_slash == filename ? US"/" : string_copyn(filename, last_slash - filename);
3199
  else
3205
  else
3200
    {
3206
    {
3201
      /* relative configuration file name: working dir + / + basename(filename) */
3207
    /* relative configuration file name: working dir + / + basename(filename) */
3202
3208
3203
      uschar buf[PATH_MAX];
3209
    uschar buf[PATH_MAX];
3204
      gstring * g;
3210
    gstring * g;
3205
3211
3206
      if (os_getcwd(buf, PATH_MAX) == NULL)
3212
    if (os_getcwd(buf, PATH_MAX) == NULL)
3207
        {
3213
      {
3208
        perror("exim: getcwd");
3214
      perror("exim: getcwd");
3209
        exit(EXIT_FAILURE);
3215
      exit(EXIT_FAILURE);
3210
        }
3216
      }
3211
      g = string_cat(NULL, buf);
3217
    g = string_cat(NULL, buf);
3212
3218
3213
      /* If the dir does not end with a "/", append one */
3219
    /* If the dir does not end with a "/", append one */
3214
      if (g->s[g->ptr-1] != '/')
3220
    if (g->s[g->ptr-1] != '/')
3215
        g = string_catn(g, US"/", 1);
3221
      g = string_catn(g, US"/", 1);
3216
3222
3217
      /* If the config file contains a "/", extract the directory part */
3223
    /* If the config file contains a "/", extract the directory part */
3218
      if (last_slash)
3224
    if (last_slash)
3219
        g = string_catn(g, filename, last_slash - filename);
3225
      g = string_catn(g, filename, last_slash - filename);
3220
3226
3221
      config_main_directory = string_from_gstring(g);
3227
    config_main_directory = string_from_gstring(g);
3222
    }
3228
    }
3223
  config_directory = config_main_directory;
3229
  config_directory = config_main_directory;
3224
  }
3230
  }
3225
else
3231
else
3226
  {
3232
  if (!filename)
3227
  if (filename == NULL)
3228
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "non-existent configuration file(s): "
3233
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "non-existent configuration file(s): "
3229
      "%s", config_main_filelist);
3234
      "%s", config_main_filelist);
3230
  else
3235
  else
3231
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", string_open_failed(errno,
3236
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
3232
      "configuration file %s", filename));
3237
      string_open_failed("configuration file %s", filename));
3233
  }
3234
3238
3235
/* Now, once we found and opened our configuration file, we change the directory
3239
/* Now, once we found and opened our configuration file, we change the directory
3236
to a safe place. Later we change to $spool_directory. */
3240
to a safe place. Later we change to $spool_directory. */
Lines 3250-3268 Link Here
3250
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to stat configuration file %s",
3254
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to stat configuration file %s",
3251
      big_buffer);
3255
      big_buffer);
3252
3256
3253
  if ((statbuf.st_uid != root_uid                /* owner not root */
3257
  if (    statbuf.st_uid != root_uid		/* owner not root */
3254
       #ifdef CONFIGURE_OWNER
3258
#ifdef CONFIGURE_OWNER
3255
       && statbuf.st_uid != config_uid           /* owner not the special one */
3259
       && statbuf.st_uid != config_uid		/* owner not the special one */
3256
       #endif
3260
#endif
3257
         ) ||                                    /* or */
3261
     ||						/* or */
3258
      (statbuf.st_gid != root_gid                /* group not root & */
3262
	  statbuf.st_gid != root_gid		/* group not root & */
3259
       #ifdef CONFIGURE_GROUP
3263
#ifdef CONFIGURE_GROUP
3260
       && statbuf.st_gid != config_gid           /* group not the special one */
3264
       && statbuf.st_gid != config_gid		/* group not the special one */
3261
       #endif
3265
#endif
3262
       && (statbuf.st_mode & 020) != 0) ||       /* group writeable  */
3266
       && (statbuf.st_mode & 020) != 0		/* group writeable  */
3263
                                                 /* or */
3267
     ||						/* or */
3264
      ((statbuf.st_mode & 2) != 0))              /* world writeable  */
3268
       (statbuf.st_mode & 2) != 0		/* world writeable  */
3265
3269
     )
3266
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Exim configuration file %s has the "
3270
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Exim configuration file %s has the "
3267
      "wrong owner, group, or mode", big_buffer);
3271
      "wrong owner, group, or mode", big_buffer);
3268
3272
Lines 3275-3281 Link Here
3275
  if (statbuf.st_size > 8192)
3279
  if (statbuf.st_size > 8192)
3276
    {
3280
    {
3277
    rmark r = store_mark();
3281
    rmark r = store_mark();
3278
    void * dummy = store_get((int)statbuf.st_size, FALSE);
3282
    void * dummy = store_get((int)statbuf.st_size, GET_UNTAINTED);
3279
    store_reset(r);
3283
    store_reset(r);
3280
    }
3284
    }
3281
  }
3285
  }
Lines 3309-3319 Link Here
3309
    read_named_list(&hostlist_anchor, &hostlist_count,
3313
    read_named_list(&hostlist_anchor, &hostlist_count,
3310
      MAX_NAMED_LIST, t+8, US"host list", hide);
3314
      MAX_NAMED_LIST, t+8, US"host list", hide);
3311
3315
3312
  else if (Ustrncmp(t, US"addresslist", 11) == 0)
3316
  else if (Ustrncmp(t, "addresslist", 11) == 0)
3313
    read_named_list(&addresslist_anchor, &addresslist_count,
3317
    read_named_list(&addresslist_anchor, &addresslist_count,
3314
      MAX_NAMED_LIST, t+11, US"address list", hide);
3318
      MAX_NAMED_LIST, t+11, US"address list", hide);
3315
3319
3316
  else if (Ustrncmp(t, US"localpartlist", 13) == 0)
3320
  else if (Ustrncmp(t, "localpartlist", 13) == 0)
3317
    read_named_list(&localpartlist_anchor, &localpartlist_count,
3321
    read_named_list(&localpartlist_anchor, &localpartlist_count,
3318
      MAX_NAMED_LIST, t+13, US"local part list", hide);
3322
      MAX_NAMED_LIST, t+13, US"local part list", hide);
3319
3323
Lines 3332-3338 Link Here
3332
/* If the timezone string is empty, set it to NULL, implying no TZ variable
3336
/* If the timezone string is empty, set it to NULL, implying no TZ variable
3333
wanted. */
3337
wanted. */
3334
3338
3335
if (timezone_string != NULL && *timezone_string == 0) timezone_string = NULL;
3339
if (timezone_string && !*timezone_string) timezone_string = NULL;
3336
3340
3337
/* The max retry interval must not be greater than 24 hours. */
3341
/* The max retry interval must not be greater than 24 hours. */
3338
3342
Lines 3353-3362 Link Here
3353
canonize it. Some people like upper case letters in their host names, so we
3357
canonize it. Some people like upper case letters in their host names, so we
3354
don't force the case. */
3358
don't force the case. */
3355
3359
3356
if (primary_hostname == NULL)
3360
if (!primary_hostname)
3357
  {
3361
  {
3358
  const uschar *hostname;
3362
  const uschar * hostname;
3359
  struct utsname uts;
3363
  struct utsname uts;
3364
3360
  if (uname(&uts) < 0)
3365
  if (uname(&uts) < 0)
3361
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "uname() failed to yield host name");
3366
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "uname() failed to yield host name");
3362
  hostname = US uts.nodename;
3367
  hostname = US uts.nodename;
Lines 3366-3398 Link Here
3366
    int af = AF_INET;
3371
    int af = AF_INET;
3367
    struct hostent *hostdata;
3372
    struct hostent *hostdata;
3368
3373
3369
    #if HAVE_IPV6
3374
#if HAVE_IPV6
3370
    if (!disable_ipv6 && (dns_ipv4_lookup == NULL ||
3375
    if (  !disable_ipv6
3371
         match_isinlist(hostname, CUSS &dns_ipv4_lookup, 0, NULL, NULL,
3376
       && (  !dns_ipv4_lookup
3377
	  || match_isinlist(hostname, CUSS &dns_ipv4_lookup, 0, NULL, NULL,
3372
	    MCL_DOMAIN, TRUE, NULL) != OK))
3378
	    MCL_DOMAIN, TRUE, NULL) != OK))
3373
      af = AF_INET6;
3379
      af = AF_INET6;
3374
    #else
3380
#endif
3375
    af = AF_INET;
3376
    #endif
3377
3381
3378
    for (;;)
3382
    for (;;)
3379
      {
3383
      {
3380
      #if HAVE_IPV6
3384
#if HAVE_IPV6
3381
        #if HAVE_GETIPNODEBYNAME
3385
# if HAVE_GETIPNODEBYNAME
3382
        int error_num;
3386
        int error_num;
3383
        hostdata = getipnodebyname(CS hostname, af, 0, &error_num);
3387
        hostdata = getipnodebyname(CS hostname, af, 0, &error_num);
3384
        #else
3388
        #else
3385
        hostdata = gethostbyname2(CS hostname, af);
3389
        hostdata = gethostbyname2(CS hostname, af);
3386
        #endif
3390
# endif
3387
      #else
3391
#else
3388
      hostdata = gethostbyname(CS hostname);
3392
      hostdata = gethostbyname(CS hostname);
3389
      #endif
3393
#endif
3390
3394
3391
      if (hostdata != NULL)
3395
      if (hostdata)
3392
        {
3396
        { hostname = US hostdata->h_name; break; }
3393
        hostname = US hostdata->h_name;
3394
        break;
3395
        }
3396
3397
3397
      if (af == AF_INET) break;
3398
      if (af == AF_INET) break;
3398
      af = AF_INET;
3399
      af = AF_INET;
Lines 3435-3440 Link Here
3435
      "\"%s\": %s", log_file_path, expand_string_message);
3436
      "\"%s\": %s", log_file_path, expand_string_message);
3436
3437
3437
  ss = s;
3438
  ss = s;
3439
  /* should never be a tainted list */
3438
  while ((sss = string_nextinlist(&ss, &sep, big_buffer, big_buffer_size)))
3440
  while ((sss = string_nextinlist(&ss, &sep, big_buffer, big_buffer_size)))
3439
    {
3441
    {
3440
    uschar *t;
3442
    uschar *t;
Lines 3479-3485 Link Here
3479
3481
3480
/* Expand pid_file_path */
3482
/* Expand pid_file_path */
3481
3483
3482
if (*pid_file_path != 0)
3484
if (*pid_file_path)
3483
  {
3485
  {
3484
  if (!(s = expand_string(pid_file_path)))
3486
  if (!(s = expand_string(pid_file_path)))
3485
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand pid_file_path "
3487
    log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand pid_file_path "
Lines 3489-3495 Link Here
3489
3491
3490
/* Set default value of process_log_path */
3492
/* Set default value of process_log_path */
3491
3493
3492
if (!process_log_path || *process_log_path =='\0')
3494
if (!process_log_path || !*process_log_path)
3493
  process_log_path = string_sprintf("%s/exim-process.info", spool_directory);
3495
  process_log_path = string_sprintf("%s/exim-process.info", spool_directory);
3494
3496
3495
/* Compile the regex for matching a UUCP-style "From_" line in an incoming
3497
/* Compile the regex for matching a UUCP-style "From_" line in an incoming
Lines 3541-3547 Link Here
3541
    log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
3543
    log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
3542
      "error in errors_reply_to (%s): %s", errors_reply_to, errmess);
3544
      "error in errors_reply_to (%s): %s", errors_reply_to, errmess);
3543
3545
3544
  if (domain == 0)
3546
  if (!domain)
3545
    log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
3547
    log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
3546
      "errors_reply_to (%s) does not contain a domain", errors_reply_to);
3548
      "errors_reply_to (%s) does not contain a domain", errors_reply_to);
3547
  }
3549
  }
Lines 3549-3556 Link Here
3549
/* If smtp_accept_queue or smtp_accept_max_per_host is set, then
3551
/* If smtp_accept_queue or smtp_accept_max_per_host is set, then
3550
smtp_accept_max must also be set. */
3552
smtp_accept_max must also be set. */
3551
3553
3552
if (smtp_accept_max == 0 &&
3554
if (smtp_accept_max == 0 && (smtp_accept_queue > 0 || smtp_accept_max_per_host))
3553
    (smtp_accept_queue > 0 || smtp_accept_max_per_host != NULL))
3554
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
3555
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
3555
    "smtp_accept_max must be set if smtp_accept_queue or "
3556
    "smtp_accept_max must be set if smtp_accept_queue or "
3556
    "smtp_accept_max_per_host is set");
3557
    "smtp_accept_max_per_host is set");
Lines 3571-3577 Link Here
3571
        host_number_string, expand_string_message);
3572
        host_number_string, expand_string_message);
3572
  n = Ustrtol(s, &end, 0);
3573
  n = Ustrtol(s, &end, 0);
3573
  while (isspace(*end)) end++;
3574
  while (isspace(*end)) end++;
3574
  if (*end != 0)
3575
  if (*end)
3575
    log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
3576
    log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
3576
      "localhost_number value is not a number: %s", s);
3577
      "localhost_number value is not a number: %s", s);
3577
  if (n > LOCALHOST_MAX)
3578
  if (n > LOCALHOST_MAX)
Lines 3648-3654 Link Here
3648
    {
3649
    {
3649
    int len = dd->options_len;
3650
    int len = dd->options_len;
3650
    d->info = dd;
3651
    d->info = dd;
3651
    d->options_block = store_get(len, FALSE);
3652
    d->options_block = store_get_perm(len, FALSE);
3652
    memcpy(d->options_block, dd->options_block, len);
3653
    memcpy(d->options_block, dd->options_block, len);
3653
    for (int i = 0; i < *(dd->options_count); i++)
3654
    for (int i = 0; i < *(dd->options_count); i++)
3654
      dd->options[i].type &= ~opt_set;
3655
      dd->options[i].type &= ~opt_set;
Lines 3664-3669 Link Here
3664
3665
3665
3666
3666
3667
3668
static void
3669
driver_init_fini(driver_instance * d, const uschar * class)
3670
{
3671
if (!d->driver_name)
3672
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
3673
    "no driver defined for %s \"%s\"", class, d->name);
3674
(d->info->init)(d);
3675
}
3676
3677
3667
/*************************************************
3678
/*************************************************
3668
*             Initialize driver list             *
3679
*             Initialize driver list             *
3669
*************************************************/
3680
*************************************************/
Lines 3724-3734 Link Here
3724
    {
3735
    {
3725
    if (d)
3736
    if (d)
3726
      {
3737
      {
3727
      if (!d->driver_name)
3728
        log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
3729
          "no driver defined for %s \"%s\"", class, d->name);
3730
      /* s is using big_buffer, so this call had better not */
3738
      /* s is using big_buffer, so this call had better not */
3731
      (d->info->init)(d);
3739
      driver_init_fini(d, class);
3732
      d = NULL;
3740
      d = NULL;
3733
      }
3741
      }
3734
    if (!macro_read_assignment(buffer)) exim_exit(EXIT_FAILURE);
3742
    if (!macro_read_assignment(buffer)) exim_exit(EXIT_FAILURE);
Lines 3744-3755 Link Here
3744
    /* Finish off initializing the previous driver. */
3752
    /* Finish off initializing the previous driver. */
3745
3753
3746
    if (d)
3754
    if (d)
3747
      {
3755
      driver_init_fini(d, class);
3748
      if (!d->driver_name)
3749
        log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
3750
          "no driver defined for %s \"%s\"", class, d->name);
3751
      (d->info->init)(d);
3752
      }
3753
3756
3754
    /* Check that we haven't already got a driver of this name */
3757
    /* Check that we haven't already got a driver of this name */
3755
3758
Lines 3761-3771 Link Here
3761
    /* Set up a new driver instance data block on the chain, with
3764
    /* Set up a new driver instance data block on the chain, with
3762
    its default values installed. */
3765
    its default values installed. */
3763
3766
3764
    d = store_get(instance_size, FALSE);
3767
    d = store_get_perm(instance_size, FALSE);
3765
    memcpy(d, instance_default, instance_size);
3768
    memcpy(d, instance_default, instance_size);
3766
    *p = d;
3769
    *p = d;
3767
    p = &d->next;
3770
    p = &d->next;
3768
    d->name = string_copy(name);
3771
    d->name = string_copy(name);
3772
    d->srcfile = config_filename;
3773
    d->srcline = config_lineno; 
3769
3774
3770
    /* Clear out the "set" bits in the generic options */
3775
    /* Clear out the "set" bits in the generic options */
3771
3776
Lines 3813-3824 Link Here
3813
/* Run the initialization function for the final driver. */
3818
/* Run the initialization function for the final driver. */
3814
3819
3815
if (d)
3820
if (d)
3816
  {
3821
  driver_init_fini(d, class);
3817
  if (!d->driver_name)
3818
    log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
3819
      "no driver defined for %s \"%s\"", class, d->name);
3820
  (d->info->init)(d);
3821
  }
3822
}
3822
}
3823
3823
3824
3824
Lines 4058-4064 Link Here
4058
  const uschar *pp;
4058
  const uschar *pp;
4059
  uschar *error;
4059
  uschar *error;
4060
4060
4061
  next = store_get(sizeof(retry_config), FALSE);
4061
  next = store_get(sizeof(retry_config), GET_UNTAINTED);
4062
  next->next = NULL;
4062
  next->next = NULL;
4063
  *chain = next;
4063
  *chain = next;
4064
  chain = &(next->next);
4064
  chain = &(next->next);
Lines 4102-4108 Link Here
4102
4102
4103
  while (*p)
4103
  while (*p)
4104
    {
4104
    {
4105
    retry_rule *rule = store_get(sizeof(retry_rule), FALSE);
4105
    retry_rule * rule = store_get(sizeof(retry_rule), GET_UNTAINTED);
4106
    *rchain = rule;
4106
    *rchain = rule;
4107
    rchain = &(rule->next);
4107
    rchain = &(rule->next);
4108
    rule->next = NULL;
4108
    rule->next = NULL;
Lines 4180-4190 Link Here
4180
4180
4181
  for (auth_instance * bu = au->next; bu; bu = bu->next)
4181
  for (auth_instance * bu = au->next; bu; bu = bu->next)
4182
    if (strcmpic(au->public_name, bu->public_name) == 0)
4182
    if (strcmpic(au->public_name, bu->public_name) == 0)
4183
      if ((au->client && bu->client) || (au->server && bu->server))
4183
      if (  au->client && bu->client
4184
	 || au->server && bu->server)
4184
        log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "two %s authenticators "
4185
        log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "two %s authenticators "
4185
          "(%s and %s) have the same public name (%s)",
4186
          "(%s and %s) have the same public name (%s)",
4186
          au->client ? US"client" : US"server", au->name, bu->name,
4187
          au->client && bu->client ? US"client" : US"server",
4187
          au->public_name);
4188
	  au->name, bu->name, au->public_name);
4188
#ifndef DISABLE_PIPE_CONNECT
4189
#ifndef DISABLE_PIPE_CONNECT
4189
  nauths++;
4190
  nauths++;
4190
#endif
4191
#endif
Lines 4195-4200 Link Here
4195
}
4196
}
4196
4197
4197
4198
4199
/* For error messages, a string describing the config location associated
4200
with current processing.  NULL if we are not in an authenticator. */
4201
4202
uschar *
4203
authenticator_current_name(void)
4204
{
4205
if (!authenticator_name) return NULL;
4206
return string_sprintf(" (authenticator %s, %s %d)", authenticator_name, driver_srcfile, driver_srcline);
4207
}
4208
4209
4210
4198
4211
4199
4212
4200
/*************************************************
4213
/*************************************************
Lines 4251-4257 Link Here
4251
  if (*p != ':' || name[0] == 0)
4264
  if (*p != ':' || name[0] == 0)
4252
    log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "missing or malformed ACL name");
4265
    log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "missing or malformed ACL name");
4253
4266
4254
  node = store_get(sizeof(tree_node) + Ustrlen(name), is_tainted(name));
4267
  node = store_get_perm(sizeof(tree_node) + Ustrlen(name), name);
4255
  Ustrcpy(node->name, name);
4268
  Ustrcpy(node->name, name);
4256
  if (!tree_insertnode(&acl_anchor, node))
4269
  if (!tree_insertnode(&acl_anchor, node))
4257
    log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
4270
    log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
Lines 4396-4402 Link Here
4396
static config_line_item *current;
4409
static config_line_item *current;
4397
config_line_item *next;
4410
config_line_item *next;
4398
4411
4399
next = (config_line_item*) store_get(sizeof(config_line_item), FALSE);
4412
next = (config_line_item*) store_get(sizeof(config_line_item), GET_UNTAINTED);
4400
next->line = string_copy(line);
4413
next->line = string_copy(line);
4401
next->next = NULL;
4414
next->next = NULL;
4402
4415
Lines 4413-4437 Link Here
4413
{
4426
{
4414
const int TS = terse ? 0 : 2;
4427
const int TS = terse ? 0 : 2;
4415
int indent = 0;
4428
int indent = 0;
4429
rmark r = NULL;
4416
4430
4417
for (config_line_item * i = config_lines; i; i = i->next)
4431
for (const config_line_item * i = config_lines; i; i = i->next)
4418
  {
4432
  {
4419
  uschar *current;
4433
  uschar * current, * p;
4420
  uschar *p;
4434
4435
  if (r) store_reset(r);
4436
  r = store_mark();
4421
4437
4422
  /* skip over to the first non-space */
4438
  /* skip over to the first non-space */
4423
  for (current = i->line; *current && isspace(*current); ++current)
4439
  for (current = string_copy(i->line); *current && isspace(*current); ++current)
4424
    ;
4440
    ;
4425
4441
4426
  if (*current == '\0')
4442
  if (!*current)
4427
    continue;
4443
    continue;
4428
4444
4429
  /* Collapse runs of spaces. We stop this if we encounter one of the
4445
  /* Collapse runs of spaces. We stop this if we encounter one of the
4430
   * following characters: "'$, as this may indicate careful formatting */
4446
  following characters: "'$, as this may indicate careful formatting */
4431
  for (p = current; *p; ++p)
4447
4448
  for (p = current; *p; p++) if (isspace(*p))
4432
    {
4449
    {
4433
    uschar *next;
4450
    uschar *next;
4434
    if (!isspace(*p)) continue;
4435
    if (*p != ' ') *p = ' ';
4451
    if (*p != ' ') *p = ' ';
4436
4452
4437
    for (next = p; isspace(*next); ++next)
4453
    for (next = p; isspace(*next); ++next)
Lines 4485-4490 Link Here
4485
    /* rest is public */
4501
    /* rest is public */
4486
    printf("%*s%s\n", indent, "", current);
4502
    printf("%*s%s\n", indent, "", current);
4487
  }
4503
  }
4504
if (r) store_reset(r);
4488
}
4505
}
4489
4506
4490
#endif	/*!MACRO_PREDEF*/
4507
#endif	/*!MACRO_PREDEF*/
(-)exim.orig/src/receive.c (-138 / +186 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Code for receiving a message and setting up spool files. */
9
/* Code for receiving a message and setting up spool files. */
Lines 44-85 Link Here
44
the file. (When SMTP input is occurring, different functions are used by
44
the file. (When SMTP input is occurring, different functions are used by
45
changing the pointer variables.) */
45
changing the pointer variables.) */
46
46
47
int
47
uschar stdin_buf[4096];
48
stdin_getc(unsigned lim)
48
uschar * stdin_inptr = stdin_buf;
49
{
49
uschar * stdin_inend = stdin_buf;
50
int c = getc(stdin);
51
50
52
if (had_data_timeout)
51
static BOOL
53
  {
52
stdin_refill(void)
54
  fprintf(stderr, "exim: timed out while reading - message abandoned\n");
53
{
55
  log_write(L_lost_incoming_connection,
54
size_t rc = fread(stdin_buf, 1, sizeof(stdin_buf), stdin);
56
            LOG_MAIN, "timed out while reading local message");
55
if (rc <= 0)
57
  receive_bomb_out(US"data-timeout", NULL);   /* Does not return */
58
  }
59
if (had_data_sigint)
60
  {
56
  {
61
  if (filter_test == FTEST_NONE)
57
  if (had_data_timeout)
58
    {
59
    fprintf(stderr, "exim: timed out while reading - message abandoned\n");
60
    log_write(L_lost_incoming_connection,
61
	      LOG_MAIN, "timed out while reading local message");
62
    receive_bomb_out(US"data-timeout", NULL);   /* Does not return */
63
    }
64
  if (had_data_sigint)
62
    {
65
    {
63
    fprintf(stderr, "\nexim: %s received - message abandoned\n",
66
    if (filter_test == FTEST_NONE)
64
      had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT");
67
      {
65
    log_write(0, LOG_MAIN, "%s received while reading local message",
68
      fprintf(stderr, "\nexim: %s received - message abandoned\n",
66
      had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT");
69
	had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT");
70
      log_write(0, LOG_MAIN, "%s received while reading local message",
71
	had_data_sigint == SIGTERM ? "SIGTERM" : "SIGINT");
72
      }
73
    receive_bomb_out(US"signal-exit", NULL);    /* Does not return */
67
    }
74
    }
68
  receive_bomb_out(US"signal-exit", NULL);    /* Does not return */
75
  return FALSE;
69
  }
76
  }
70
return c;
77
stdin_inend = stdin_buf + rc;
78
stdin_inptr = stdin_buf;
79
return TRUE;
80
}
81
82
int
83
stdin_getc(unsigned lim)
84
{
85
if (stdin_inptr >= stdin_inend)
86
  if (!stdin_refill())
87
      return EOF;
88
return *stdin_inptr++;
89
}
90
91
92
BOOL
93
stdin_hasc(void)
94
{
95
return stdin_inptr < stdin_inend;
71
}
96
}
72
97
73
int
98
int
74
stdin_ungetc(int c)
99
stdin_ungetc(int c)
75
{
100
{
76
return ungetc(c, stdin);
101
if (stdin_inptr <= stdin_buf)
102
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "buffer underflow in stdin_ungetc");
103
104
*--stdin_inptr = c;
105
return c;
77
}
106
}
78
107
79
int
108
int
80
stdin_feof(void)
109
stdin_feof(void)
81
{
110
{
82
return feof(stdin);
111
return stdin_hasc() ? FALSE : feof(stdin);
83
}
112
}
84
113
85
int
114
int
Lines 176-181 Link Here
176
  empty item in a list. */
205
  empty item in a list. */
177
206
178
  if (*p == 0) p = US":";
207
  if (*p == 0) p = US":";
208
  /* should never be a tainted list */
179
  while ((path = string_nextinlist(&p, &sep, buffer, sizeof(buffer))))
209
  while ((path = string_nextinlist(&p, &sep, buffer, sizeof(buffer))))
180
    if (Ustrcmp(path, "syslog") != 0)
210
    if (Ustrcmp(path, "syslog") != 0)
181
      break;
211
      break;
Lines 497-504 Link Here
497
    }
527
    }
498
528
499
  recipients_list_max = recipients_list_max ? 2*recipients_list_max : 50;
529
  recipients_list_max = recipients_list_max ? 2*recipients_list_max : 50;
500
  recipients_list = store_get(recipients_list_max * sizeof(recipient_item), FALSE);
530
  recipients_list = store_get(recipients_list_max * sizeof(recipient_item), GET_UNTAINTED);
501
  if (oldlist != NULL)
531
  if (oldlist)
502
    memcpy(recipients_list, oldlist, oldmax * sizeof(recipient_item));
532
    memcpy(recipients_list, oldlist, oldmax * sizeof(recipient_item));
503
  }
533
  }
504
534
Lines 587-605 Link Here
587
static void
617
static void
588
log_close_chk(void)
618
log_close_chk(void)
589
{
619
{
590
if (!receive_timeout)
620
if (!receive_timeout && !receive_hasc())
591
  {
621
  {
592
  struct timeval t;
622
  struct timeval t;
593
  timesince(&t, &received_time);
623
  timesince(&t, &received_time);
594
  if (t.tv_sec > 30*60)
624
  if (t.tv_sec > 30*60)
595
    mainlog_close();
625
    mainlog_close();
596
  else
626
  else
597
    {
627
    if (poll_one_fd(0, POLLIN, (30*60 - t.tv_sec) * 1000) == 0)
598
    fd_set r;
628
      mainlog_close();
599
    FD_ZERO(&r); FD_SET(0, &r);
600
    t.tv_sec = 30*60 - t.tv_sec; t.tv_usec = 0;
601
    if (select(1, &r, NULL, NULL, &t) == 0) mainlog_close();
602
    }
603
  }
629
  }
604
}
630
}
605
631
Lines 653-663 Link Here
653
  {
679
  {
654
  int last_ch = '\n';
680
  int last_ch = '\n';
655
681
656
/*XXX we do a gettimeofday before checking for every received char,
657
which is hardly clever.  The function-indirection doesn't help, but
658
an additional function to check for nonempty read buffer would help.
659
See stdin_getc() / smtp_getc() / tls_getc() / bdat_getc(). */
660
661
  for ( ;
682
  for ( ;
662
       log_close_chk(), (ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF;
683
       log_close_chk(), (ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF;
663
       last_ch = ch)
684
       last_ch = ch)
Lines 946-952 Link Here
946
*/
967
*/
947
968
948
static int
969
static int
949
read_message_bdat_smtp(FILE *fout)
970
read_message_bdat_smtp(FILE * fout)
950
{
971
{
951
int linelength = 0, ch;
972
int linelength = 0, ch;
952
enum CH_STATE ch_state = LF_SEEN;
973
enum CH_STATE ch_state = LF_SEEN;
Lines 1052-1058 Link Here
1052
}
1073
}
1053
1074
1054
static int
1075
static int
1055
read_message_bdat_smtp_wire(FILE *fout)
1076
read_message_bdat_smtp_wire(FILE * fout)
1056
{
1077
{
1057
int ch;
1078
int ch;
1058
1079
Lines 1235-1243 Link Here
1235
    const uschar * list = acl_removed_headers;
1256
    const uschar * list = acl_removed_headers;
1236
    int sep = ':';         /* This is specified as a colon-separated list */
1257
    int sep = ':';         /* This is specified as a colon-separated list */
1237
    uschar *s;
1258
    uschar *s;
1238
    uschar buffer[128];
1239
1259
1240
    while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
1260
    while ((s = string_nextinlist(&list, &sep, NULL, 0)))
1241
      if (header_testname(h, s, Ustrlen(s), FALSE))
1261
      if (header_testname(h, s, Ustrlen(s), FALSE))
1242
	{
1262
	{
1243
	h->type = htype_old;
1263
	h->type = htype_old;
Lines 1523-1533 Link Here
1523
void
1543
void
1524
received_header_gen(void)
1544
received_header_gen(void)
1525
{
1545
{
1526
uschar *received;
1546
uschar * received;
1527
uschar *timestamp;
1547
uschar * timestamp = expand_string(US"${tod_full}");
1528
header_line *received_header= header_list;
1548
header_line * received_header= header_list;
1529
1549
1530
timestamp = expand_string(US"${tod_full}");
1531
if (recipients_count == 1) received_for = recipients_list[0].address;
1550
if (recipients_count == 1) received_for = recipients_list[0].address;
1532
received = expand_string(received_header_text);
1551
received = expand_string(received_header_text);
1533
received_for = NULL;
1552
received_for = NULL;
Lines 1546-1559 Link Here
1546
the result of the expansion is an empty string, we leave the header marked as
1565
the result of the expansion is an empty string, we leave the header marked as
1547
"old" so as to refrain from adding a Received header. */
1566
"old" so as to refrain from adding a Received header. */
1548
1567
1549
if (received[0] == 0)
1568
if (!received[0])
1550
  {
1569
  {
1551
  received_header->text = string_sprintf("Received: ; %s\n", timestamp);
1570
  received_header->text = string_sprintf("Received: ; %s\n", timestamp);
1552
  received_header->type = htype_old;
1571
  received_header->type = htype_old;
1553
  }
1572
  }
1554
else
1573
else
1555
  {
1574
  {
1556
  received_header->text = string_sprintf("%s; %s\n", received, timestamp);
1575
  received_header->text = string_sprintf("%s;\n\t%s\n", received, timestamp);
1557
  received_header->type = htype_received;
1576
  received_header->type = htype_received;
1558
  }
1577
  }
1559
1578
Lines 1664-1673 Link Here
1664
int  error_rc = error_handling == ERRORS_SENDER
1683
int  error_rc = error_handling == ERRORS_SENDER
1665
	? errors_sender_rc : EXIT_FAILURE;
1684
	? errors_sender_rc : EXIT_FAILURE;
1666
int  header_size = 256;
1685
int  header_size = 256;
1667
int  start, end, domain;
1668
int  id_resolution = 0;
1669
int  had_zero = 0;
1686
int  had_zero = 0;
1670
int  prevlines_length = 0;
1687
int  prevlines_length = 0;
1688
const int id_resolution = BASE_62 == 62 ? 5000 : 10000;
1671
1689
1672
int ptr = 0;
1690
int ptr = 0;
1673
1691
Lines 1721-1726 Link Here
1721
uschar *timestamp;
1739
uschar *timestamp;
1722
int tslen;
1740
int tslen;
1723
1741
1742
/* Time of creation of message_id */
1743
1744
static struct timeval message_id_tv = { 0, 0 };
1745
1724
1746
1725
/* Release any open files that might have been cached while preparing to
1747
/* Release any open files that might have been cached while preparing to
1726
accept the message - e.g. by verifying addresses - because reading a message
1748
accept the message - e.g. by verifying addresses - because reading a message
Lines 1738-1754 Link Here
1738
header. Temporarily mark it as "old", i.e. not to be used. We keep header_last
1760
header. Temporarily mark it as "old", i.e. not to be used. We keep header_last
1739
pointing to the end of the chain to make adding headers simple. */
1761
pointing to the end of the chain to make adding headers simple. */
1740
1762
1741
received_header = header_list = header_last = store_get(sizeof(header_line), FALSE);
1763
received_header = header_list = header_last = store_get(sizeof(header_line), GET_UNTAINTED);
1742
header_list->next = NULL;
1764
header_list->next = NULL;
1743
header_list->type = htype_old;
1765
header_list->type = htype_old;
1744
header_list->text = NULL;
1766
header_list->text = NULL;
1745
header_list->slen = 0;
1767
header_list->slen = 0;
1746
1768
1747
/* Control block for the next header to be read. */
1769
/* Control block for the next header to be read.
1770
The data comes from the message, so is tainted. */
1748
1771
1749
reset_point = store_mark();
1772
reset_point = store_mark();
1750
next = store_get(sizeof(header_line), FALSE);	/* not tainted */
1773
next = store_get(sizeof(header_line), GET_UNTAINTED);
1751
next->text = store_get(header_size, TRUE);	/* tainted */
1774
next->text = store_get(header_size, GET_TAINTED);
1752
1775
1753
/* Initialize message id to be null (indicating no message read), and the
1776
/* Initialize message id to be null (indicating no message read), and the
1754
header names list to be the normal list. Indicate there is no data file open
1777
header names list to be the normal list. Indicate there is no data file open
Lines 1787-1803 Link Here
1787
if (sender_host_address) dmarc_init();	/* initialize libopendmarc */
1810
if (sender_host_address) dmarc_init();	/* initialize libopendmarc */
1788
#endif
1811
#endif
1789
1812
1813
/* In SMTP sessions we may receive several messages in one connection. Before
1814
each subsequent one, we wait for the clock to tick at the level of message-id
1815
granularity.
1816
This is so that the combination of time+pid is unique, even on systems where the
1817
pid can be re-used within our time interval. We can't shorten the interval
1818
without re-designing the message-id. See comments above where the message id is
1819
created. This is Something For The Future.
1820
Do this wait any time we have previously created a message-id, even if we
1821
rejected the message.  This gives unique IDs for logging done by ACLs.
1822
The initial timestamp must have been obtained via exim_gettime() to avoid
1823
issues on Linux with suspend/resume. */
1824
1825
if (message_id_tv.tv_sec)
1826
  {
1827
  message_id_tv.tv_usec = (message_id_tv.tv_usec/id_resolution) * id_resolution;
1828
  exim_wait_tick(&message_id_tv, id_resolution);
1829
  }
1830
1790
/* Remember the time of reception. Exim uses time+pid for uniqueness of message
1831
/* Remember the time of reception. Exim uses time+pid for uniqueness of message
1791
ids, and fractions of a second are required. See the comments that precede the
1832
ids, and fractions of a second are required. See the comments that precede the
1792
message id creation below. */
1833
message id creation below.
1834
We use a routine that if possible uses a monotonic clock, and can be used again
1835
after reception for the tick-wait even under the Linux non-Posix behaviour. */
1793
1836
1794
exim_gettime(&message_id_tv);
1837
else
1838
  exim_gettime(&message_id_tv);
1795
1839
1796
/* For other uses of the received time we can operate with granularity of one
1840
/* For other uses of the received time we can operate with granularity of one
1797
second, and for that we use the global variable received_time. This is for
1841
second, and for that we use the global variable received_time. This is for
1798
things like ultimate message timeouts. */
1842
things like ultimate message timeouts.
1843
For this we do not care about the Linux suspend/resume problem, so rather than
1844
use exim_gettime() everywhere we use a plain gettimeofday() here. */
1799
1845
1800
received_time = message_id_tv;
1846
gettimeofday(&received_time, NULL);
1801
1847
1802
/* If SMTP input, set the special handler for timeouts. The alarm() calls
1848
/* If SMTP input, set the special handler for timeouts. The alarm() calls
1803
happen in the smtp_getc() function when it refills its buffer. */
1849
happen in the smtp_getc() function when it refills its buffer. */
Lines 1843-1854 Link Here
1843
  /* If we hit EOF on a SMTP connection, it's an error, since incoming
1889
  /* If we hit EOF on a SMTP connection, it's an error, since incoming
1844
  SMTP must have a correct "." terminator. */
1890
  SMTP must have a correct "." terminator. */
1845
1891
1846
  if (ch == EOF && smtp_input /* && !smtp_batched_input */)
1892
  if (smtp_input /* && !smtp_batched_input */)
1847
    {
1893
    if (ch == EOF)
1848
    smtp_reply = handle_lost_connection(US" (header)");
1894
      {
1849
    smtp_yield = FALSE;
1895
      smtp_reply = handle_lost_connection(US" (header)");
1850
    goto TIDYUP;                       /* Skip to end of function */
1896
      smtp_yield = FALSE;
1851
    }
1897
      goto TIDYUP;                       /* Skip to end of function */
1898
      }
1899
    else if (ch == ERR)
1900
      goto TIDYUP;
1852
1901
1853
  /* See if we are at the current header's size limit - there must be at least
1902
  /* See if we are at the current header's size limit - there must be at least
1854
  four bytes left. This allows for the new character plus a zero, plus two for
1903
  four bytes left. This allows for the new character plus a zero, plus two for
Lines 1872-1881 Link Here
1872
      goto OVERSIZE;
1921
      goto OVERSIZE;
1873
    header_size *= 2;
1922
    header_size *= 2;
1874
1923
1875
    /* The data came from the message, so is tainted. */
1924
    if (!store_extend(next->text, oldsize, header_size))
1876
1925
      next->text = store_newblock(next->text, header_size, ptr);
1877
    if (!store_extend(next->text, TRUE, oldsize, header_size))
1878
      next->text = store_newblock(next->text, TRUE, header_size, ptr);
1879
    }
1926
    }
1880
1927
1881
  /* Cope with receiving a binary zero. There is dispute about whether
1928
  /* Cope with receiving a binary zero. There is dispute about whether
Lines 1890-1896 Link Here
1890
  those from data files use just LF. Treat LF in local SMTP input as a
1937
  those from data files use just LF. Treat LF in local SMTP input as a
1891
  terminator too. Treat EOF as a line terminator always. */
1938
  terminator too. Treat EOF as a line terminator always. */
1892
1939
1893
  if (ch == EOF) goto EOL;
1940
  if (ch < 0) goto EOL;
1894
1941
1895
  /* FUDGE: There are sites out there that don't send CRs before their LFs, and
1942
  /* FUDGE: There are sites out there that don't send CRs before their LFs, and
1896
  other MTAs accept this. We are therefore forced into this "liberalisation"
1943
  other MTAs accept this. We are therefore forced into this "liberalisation"
Lines 1915-1921 Link Here
1915
  prevent further reading), and break out of the loop, having freed the
1962
  prevent further reading), and break out of the loop, having freed the
1916
  empty header, and set next = NULL to indicate no data line. */
1963
  empty header, and set next = NULL to indicate no data line. */
1917
1964
1918
  if (ptr == 0 && ch == '.' && f.dot_ends)
1965
  if (f.dot_ends && ptr == 0 && ch == '.')
1919
    {
1966
    {
1920
    ch = (receive_getc)(GETC_BUFFER_UNLIMITED);
1967
    ch = (receive_getc)(GETC_BUFFER_UNLIMITED);
1921
    if (ch == '\r')
1968
    if (ch == '\r')
Lines 1923-1929 Link Here
1923
      ch = (receive_getc)(GETC_BUFFER_UNLIMITED);
1970
      ch = (receive_getc)(GETC_BUFFER_UNLIMITED);
1924
      if (ch != '\n')
1971
      if (ch != '\n')
1925
        {
1972
        {
1926
        receive_ungetc(ch);
1973
	if (ch >= 0) receive_ungetc(ch);
1927
        ch = '\r';              /* Revert to CR */
1974
        ch = '\r';              /* Revert to CR */
1928
        }
1975
        }
1929
      }
1976
      }
Lines 1961-1967 Link Here
1961
    /* Otherwise, put back the character after CR, and turn the bare CR
2008
    /* Otherwise, put back the character after CR, and turn the bare CR
1962
    into LF SP. */
2009
    into LF SP. */
1963
2010
1964
    ch = (receive_ungetc)(ch);
2011
    if (ch >= 0) (receive_ungetc)(ch);
1965
    next->text[ptr++] = '\n';
2012
    next->text[ptr++] = '\n';
1966
    message_size++;
2013
    message_size++;
1967
    ch = ' ';
2014
    ch = ' ';
Lines 2045-2051 Link Here
2045
  whitespace character. If it is, we have a continuation of this header line.
2092
  whitespace character. If it is, we have a continuation of this header line.
2046
  There is always space for at least one character at this point. */
2093
  There is always space for at least one character at this point. */
2047
2094
2048
  if (ch != EOF)
2095
  if (ch >= 0)
2049
    {
2096
    {
2050
    int nextch = (receive_getc)(GETC_BUFFER_UNLIMITED);
2097
    int nextch = (receive_getc)(GETC_BUFFER_UNLIMITED);
2051
    if (nextch == ' ' || nextch == '\t')
2098
    if (nextch == ' ' || nextch == '\t')
Lines 2055-2062 Link Here
2055
	goto OVERSIZE;
2102
	goto OVERSIZE;
2056
      continue;                      /* Iterate the loop */
2103
      continue;                      /* Iterate the loop */
2057
      }
2104
      }
2058
    else if (nextch != EOF) (receive_ungetc)(nextch);   /* For next time */
2105
    else if (nextch >= 0)	/* not EOF, ERR etc */
2059
    else ch = EOF;                   /* Cause main loop to exit at end */
2106
      (receive_ungetc)(nextch);   /* For next time */
2107
    else ch = nextch;                   /* Cause main loop to exit at end */
2060
    }
2108
    }
2061
2109
2062
  /* We have got to the real line end. Terminate the string and release store
2110
  /* We have got to the real line end. Terminate the string and release store
Lines 2158-2164 Link Here
2158
2206
2159
  else
2207
  else
2160
    {
2208
    {
2161
    uschar *p = next->text;
2209
    uschar * p = next->text;
2162
2210
2163
    /* If not a valid header line, break from the header reading loop, leaving
2211
    /* If not a valid header line, break from the header reading loop, leaving
2164
    next != NULL, indicating that it holds the first line of the body. */
2212
    next != NULL, indicating that it holds the first line of the body. */
Lines 2256-2271 Link Here
2256
    }
2304
    }
2257
2305
2258
  /* The line has been handled. If we have hit EOF, break out of the loop,
2306
  /* The line has been handled. If we have hit EOF, break out of the loop,
2259
  indicating no pending data line. */
2307
  indicating no pending data line and no more data for the message */
2260
2308
2261
  if (ch == EOF) { next = NULL; break; }
2309
  if (ch < 0)
2310
    {
2311
    next = NULL;
2312
    if (ch == EOF)	message_ended = END_DOT;
2313
    else if (ch == ERR) message_ended = END_PROTOCOL;
2314
    break;
2315
    }
2262
2316
2263
  /* Set up for the next header */
2317
  /* Set up for the next header */
2264
2318
2265
  reset_point = store_mark();
2319
  reset_point = store_mark();
2266
  header_size = 256;
2320
  header_size = 256;
2267
  next = store_get(sizeof(header_line), FALSE);
2321
  next = store_get(sizeof(header_line), GET_UNTAINTED);
2268
  next->text = store_get(header_size, TRUE);
2322
  next->text = store_get(header_size, GET_TAINTED);
2269
  ptr = 0;
2323
  ptr = 0;
2270
  had_zero = 0;
2324
  had_zero = 0;
2271
  prevlines_length = 0;
2325
  prevlines_length = 0;
Lines 2288-2301 Link Here
2288
/* End of file on any SMTP connection is an error. If an incoming SMTP call
2342
/* End of file on any SMTP connection is an error. If an incoming SMTP call
2289
is dropped immediately after valid headers, the next thing we will see is EOF.
2343
is dropped immediately after valid headers, the next thing we will see is EOF.
2290
We must test for this specially, as further down the reading of the data is
2344
We must test for this specially, as further down the reading of the data is
2291
skipped if already at EOF. */
2345
skipped if already at EOF.
2346
In CHUNKING mode, a protocol error makes us give up on the message. */
2292
2347
2293
if (smtp_input && (receive_feof)())
2348
if (smtp_input)
2294
  {
2349
  if ((receive_feof)())
2295
  smtp_reply = handle_lost_connection(US" (after header)");
2350
    {
2296
  smtp_yield = FALSE;
2351
    smtp_reply = handle_lost_connection(US" (after header)");
2297
  goto TIDYUP;                       /* Skip to end of function */
2352
    smtp_yield = FALSE;
2298
  }
2353
    goto TIDYUP;			/* Skip to end of function */
2354
    }
2355
  else if (message_ended == END_PROTOCOL)
2356
    {
2357
    smtp_reply = US"";			/* no reply needed */
2358
    goto TIDYUP;
2359
    }
2299
2360
2300
/* If this is a filter test run and no headers were read, output a warning
2361
/* If this is a filter test run and no headers were read, output a warning
2301
in case there is a mistake in the test message. */
2362
in case there is a mistake in the test message. */
Lines 2549-2555 Link Here
2549
        white space that follows the newline must not be removed - it is part
2610
        white space that follows the newline must not be removed - it is part
2550
        of the header. */
2611
        of the header. */
2551
2612
2552
        pp = recipient = store_get(ss - s + 1, is_tainted(s));
2613
        pp = recipient = store_get(ss - s + 1, s);
2553
        for (uschar * p = s; p < ss; p++) if (*p != '\n') *pp++ = *p;
2614
        for (uschar * p = s; p < ss; p++) if (*p != '\n') *pp++ = *p;
2554
        *pp = 0;
2615
        *pp = 0;
2555
2616
Lines 2581-2587 Link Here
2581
        if (!recipient && Ustrcmp(errmess, "empty address") != 0)
2642
        if (!recipient && Ustrcmp(errmess, "empty address") != 0)
2582
          {
2643
          {
2583
          int len = Ustrlen(s);
2644
          int len = Ustrlen(s);
2584
          error_block *b = store_get(sizeof(error_block), FALSE);
2645
          error_block * b = store_get(sizeof(error_block), GET_UNTAINTED);
2585
          while (len > 0 && isspace(s[len-1])) len--;
2646
          while (len > 0 && isspace(s[len-1])) len--;
2586
          b->next = NULL;
2647
          b->next = NULL;
2587
          b->text1 = string_printing(string_copyn(s, len));
2648
          b->text1 = string_printing(string_copyn(s, len));
Lines 2678-2705 Link Here
2678
Ustrncpy(message_id + 7, string_base62((long int)getpid()), 6);
2739
Ustrncpy(message_id + 7, string_base62((long int)getpid()), 6);
2679
2740
2680
/* Deal with the case where the host number is set. The value of the number was
2741
/* Deal with the case where the host number is set. The value of the number was
2681
checked when it was read, to ensure it isn't too big. The timing granularity is
2742
checked when it was read, to ensure it isn't too big. */
2682
left in id_resolution so that an appropriate wait can be done after receiving
2683
the message, if necessary (we hope it won't be). */
2684
2743
2685
if (host_number_string)
2744
if (host_number_string)
2686
  {
2687
  id_resolution = BASE_62 == 62 ? 5000 : 10000;
2688
  sprintf(CS(message_id + MESSAGE_ID_LENGTH - 3), "-%2s",
2745
  sprintf(CS(message_id + MESSAGE_ID_LENGTH - 3), "-%2s",
2689
    string_base62((long int)(
2746
    string_base62((long int)(
2690
      host_number * (1000000/id_resolution) +
2747
      host_number * (1000000/id_resolution) +
2691
        message_id_tv.tv_usec/id_resolution)) + 4);
2748
        message_id_tv.tv_usec/id_resolution)) + 4);
2692
  }
2693
2749
2694
/* Host number not set: final field is just the fractional time at an
2750
/* Host number not set: final field is just the fractional time at an
2695
appropriate resolution. */
2751
appropriate resolution. */
2696
2752
2697
else
2753
else
2698
  {
2699
  id_resolution = BASE_62 == 62 ? 500 : 1000;
2700
  sprintf(CS(message_id + MESSAGE_ID_LENGTH - 3), "-%2s",
2754
  sprintf(CS(message_id + MESSAGE_ID_LENGTH - 3), "-%2s",
2701
    string_base62((long int)(message_id_tv.tv_usec/id_resolution)) + 4);
2755
    string_base62((long int)(message_id_tv.tv_usec/id_resolution)) + 4);
2702
  }
2703
2756
2704
/* Add the current message id onto the current process info string if
2757
/* Add the current message id onto the current process info string if
2705
it will fit. */
2758
it will fit. */
Lines 2788-2794 Link Here
2788
2841
2789
if (LOGGING(received_recipients))
2842
if (LOGGING(received_recipients))
2790
  {
2843
  {
2791
  raw_recipients = store_get(recipients_count * sizeof(uschar *), FALSE);
2844
  raw_recipients = store_get(recipients_count * sizeof(uschar *), GET_UNTAINTED);
2792
  for (int i = 0; i < recipients_count; i++)
2845
  for (int i = 0; i < recipients_count; i++)
2793
    raw_recipients[i] = string_copy(recipients_list[i].address);
2846
    raw_recipients[i] = string_copy(recipients_list[i].address);
2794
  raw_recipients_count = recipients_count;
2847
  raw_recipients_count = recipients_count;
Lines 2798-2807 Link Here
2798
recipients will get here only if the conditions were right (allow_unqualified_
2851
recipients will get here only if the conditions were right (allow_unqualified_
2799
recipient is TRUE). */
2852
recipient is TRUE). */
2800
2853
2854
DEBUG(D_rewrite)
2855
  { debug_printf_indent("qualify & rewrite recipients list\n"); acl_level++; }
2801
for (int i = 0; i < recipients_count; i++)
2856
for (int i = 0; i < recipients_count; i++)
2802
  recipients_list[i].address =	/* deconst ok as src was not cont */
2857
  recipients_list[i].address =	/* deconst ok as src was not cont */
2803
    US rewrite_address(recipients_list[i].address, TRUE, TRUE,
2858
    US rewrite_address(recipients_list[i].address, TRUE, TRUE,
2804
      global_rewrite_rules, rewrite_existflags);
2859
      global_rewrite_rules, rewrite_existflags);
2860
DEBUG(D_rewrite) acl_level--;
2805
2861
2806
/* If there is no From: header, generate one for local (without
2862
/* If there is no From: header, generate one for local (without
2807
suppress_local_fixups) or submission_mode messages. If there is no sender
2863
suppress_local_fixups) or submission_mode messages. If there is no sender
Lines 2815-2821 Link Here
2815
if (  !from_header
2871
if (  !from_header
2816
   && ((!sender_host_address && !f.suppress_local_fixups) || f.submission_mode))
2872
   && ((!sender_host_address && !f.suppress_local_fixups) || f.submission_mode))
2817
  {
2873
  {
2818
  uschar *oname = US"";
2874
  const uschar * oname = US"";
2819
2875
2820
  /* Use the originator_name if this is a locally submitted message and the
2876
  /* Use the originator_name if this is a locally submitted message and the
2821
  caller is not trusted. For trusted callers, use it only if -F was used to
2877
  caller is not trusted. For trusted callers, use it only if -F was used to
Lines 2973-2978 Link Here
2973
/* If there are any rewriting rules, apply them to the sender address, unless
3029
/* If there are any rewriting rules, apply them to the sender address, unless
2974
it has already been rewritten as part of verification for SMTP input. */
3030
it has already been rewritten as part of verification for SMTP input. */
2975
3031
3032
DEBUG(D_rewrite)
3033
  { debug_printf("global rewrite rules\n"); acl_level++; }
2976
if (global_rewrite_rules && !sender_address_unrewritten && *sender_address)
3034
if (global_rewrite_rules && !sender_address_unrewritten && *sender_address)
2977
  {
3035
  {
2978
  /* deconst ok as src was not const */
3036
  /* deconst ok as src was not const */
Lines 2981-2986 Link Here
2981
  DEBUG(D_receive|D_rewrite)
3039
  DEBUG(D_receive|D_rewrite)
2982
    debug_printf("rewritten sender = %s\n", sender_address);
3040
    debug_printf("rewritten sender = %s\n", sender_address);
2983
  }
3041
  }
3042
DEBUG(D_rewrite) acl_level--;
2984
3043
2985
3044
2986
/* The headers must be run through rewrite_header(), because it ensures that
3045
/* The headers must be run through rewrite_header(), because it ensures that
Lines 2997-3008 Link Here
2997
documented as happening *after* recipient addresses are taken from the headers
3056
documented as happening *after* recipient addresses are taken from the headers
2998
by the -t command line option. An added Sender: gets rewritten here. */
3057
by the -t command line option. An added Sender: gets rewritten here. */
2999
3058
3000
for (header_line * h = header_list->next; h; h = h->next)
3059
DEBUG(D_rewrite)
3001
  {
3060
  { debug_printf("rewrite headers\n"); acl_level++; }
3002
  header_line *newh = rewrite_header(h, NULL, NULL, global_rewrite_rules,
3061
for (header_line * h = header_list->next, * newh; h; h = h->next)
3003
    rewrite_existflags, TRUE);
3062
  if ((newh = rewrite_header(h, NULL, NULL, global_rewrite_rules,
3004
  if (newh) h = newh;
3063
			      rewrite_existflags, TRUE)))
3005
  }
3064
    h = newh;
3065
DEBUG(D_rewrite) acl_level--;
3006
3066
3007
3067
3008
/* An RFC 822 (sic) message is not legal unless it has at least one of "to",
3068
/* An RFC 822 (sic) message is not legal unless it has at least one of "to",
Lines 3282-3288 Link Here
3282
/* No I/O errors were encountered while writing the data file. */
3342
/* No I/O errors were encountered while writing the data file. */
3283
3343
3284
DEBUG(D_receive) debug_printf("Data file written for message %s\n", message_id);
3344
DEBUG(D_receive) debug_printf("Data file written for message %s\n", message_id);
3285
if (LOGGING(receive_time)) timesince(&received_time_taken, &received_time);
3345
gettimeofday(&received_time_complete, NULL);
3286
3346
3287
3347
3288
/* If there were any bad addresses extracted by -t, or there were no recipients
3348
/* If there were any bad addresses extracted by -t, or there were no recipients
Lines 4004-4010 Link Here
4004
if (LOGGING(tls_cipher) && tls_in.cipher)
4064
if (LOGGING(tls_cipher) && tls_in.cipher)
4005
  {
4065
  {
4006
  g = string_append(g, 2, US" X=", tls_in.cipher);
4066
  g = string_append(g, 2, US" X=", tls_in.cipher);
4007
# ifdef EXPERIMENTAL_TLS_RESUME
4067
# ifndef DISABLE_TLS_RESUME
4008
  if (LOGGING(tls_resumption) && tls_in.resumption & RESUME_USED)
4068
  if (LOGGING(tls_resumption) && tls_in.resumption & RESUME_USED)
4009
    g = string_catn(g, US"*", 1);
4069
    g = string_catn(g, US"*", 1);
4010
# endif
4070
# endif
Lines 4060-4066 Link Here
4060
#endif
4120
#endif
4061
4121
4062
if (LOGGING(receive_time))
4122
if (LOGGING(receive_time))
4063
  g = string_append(g, 2, US" RT=", string_timediff(&received_time_taken));
4123
  {
4124
  struct timeval diff = received_time_complete;
4125
  timediff(&diff, &received_time);
4126
  g = string_append(g, 2, US" RT=", string_timediff(&diff));
4127
  }
4064
4128
4065
if (*queue_name)
4129
if (*queue_name)
4066
  g = string_append(g, 2, US" Q=", queue_name);
4130
  g = string_append(g, 2, US" Q=", queue_name);
Lines 4077-4082 Link Here
4077
  uschar * old_id;
4141
  uschar * old_id;
4078
  BOOL save_allow_domain_literals = allow_domain_literals;
4142
  BOOL save_allow_domain_literals = allow_domain_literals;
4079
  allow_domain_literals = TRUE;
4143
  allow_domain_literals = TRUE;
4144
  int start, end, domain;
4145
4080
  old_id = parse_extract_address(Ustrchr(msgid_header->text, ':') + 1,
4146
  old_id = parse_extract_address(Ustrchr(msgid_header->text, ':') + 1,
4081
    &errmsg, &start, &end, &domain, FALSE);
4147
    &errmsg, &start, &end, &domain, FALSE);
4082
  allow_domain_literals = save_allow_domain_literals;
4148
  allow_domain_literals = save_allow_domain_literals;
Lines 4169-4175 Link Here
4169
/* Before sending an SMTP response in a TCP/IP session, we check to see if the
4235
/* Before sending an SMTP response in a TCP/IP session, we check to see if the
4170
connection has gone away. This can only be done if there is no unconsumed input
4236
connection has gone away. This can only be done if there is no unconsumed input
4171
waiting in the local input buffer. We can test for this by calling
4237
waiting in the local input buffer. We can test for this by calling
4172
receive_smtp_buffered(). RFC 2920 (pipelining) explicitly allows for additional
4238
receive_hasc(). RFC 2920 (pipelining) explicitly allows for additional
4173
input to be sent following the final dot, so the presence of following input is
4239
input to be sent following the final dot, so the presence of following input is
4174
not an error.
4240
not an error.
4175
4241
Lines 4184-4203 Link Here
4184
connection will vanish between the time of this test and the sending of the
4250
connection will vanish between the time of this test and the sending of the
4185
response, but the chance of this happening should be small. */
4251
response, but the chance of this happening should be small. */
4186
4252
4187
if (smtp_input && sender_host_address && !f.sender_host_notsocket &&
4253
if (  smtp_input && sender_host_address && !f.sender_host_notsocket
4188
    !receive_smtp_buffered())
4254
   && !receive_hasc())
4189
  {
4255
  {
4190
  struct timeval tv;
4256
  if (poll_one_fd(fileno(smtp_in), POLLIN, 0) != 0)
4191
  fd_set select_check;
4192
  FD_ZERO(&select_check);
4193
  FD_SET(fileno(smtp_in), &select_check);
4194
  tv.tv_sec = 0;
4195
  tv.tv_usec = 0;
4196
4197
  if (select(fileno(smtp_in) + 1, &select_check, NULL, NULL, &tv) != 0)
4198
    {
4257
    {
4199
    int c = (receive_getc)(GETC_BUFFER_UNLIMITED);
4258
    int c = (receive_getc)(GETC_BUFFER_UNLIMITED);
4200
    if (c != EOF) (receive_ungetc)(c); else
4259
    if (c != EOF) (receive_ungetc)(c);
4260
    else
4201
      {
4261
      {
4202
      smtp_notquit_exit(US"connection-lost", NULL, NULL);
4262
      smtp_notquit_exit(US"connection-lost", NULL, NULL);
4203
      smtp_reply = US"";    /* No attempt to send a response */
4263
      smtp_reply = US"";    /* No attempt to send a response */
Lines 4318-4340 Link Here
4318
4378
4319
4379
4320
TIDYUP:
4380
TIDYUP:
4321
/* In SMTP sessions we may receive several messages in one connection. After
4322
each one, we wait for the clock to tick at the level of message-id granularity.
4323
This is so that the combination of time+pid is unique, even on systems where the
4324
pid can be re-used within our time interval. We can't shorten the interval
4325
without re-designing the message-id. See comments above where the message id is
4326
created. This is Something For The Future.
4327
Do this wait any time we have created a message-id, even if we rejected the
4328
message.  This gives unique IDs for logging done by ACLs. */
4329
4330
if (id_resolution != 0)
4331
  {
4332
  message_id_tv.tv_usec = (message_id_tv.tv_usec/id_resolution) * id_resolution;
4333
  exim_wait_tick(&message_id_tv, id_resolution);
4334
  id_resolution = 0;
4335
  }
4336
4337
4338
process_info[process_info_len] = 0;			/* Remove message id */
4381
process_info[process_info_len] = 0;			/* Remove message id */
4339
if (spool_data_file && cutthrough_done == NOT_TRIED)
4382
if (spool_data_file && cutthrough_done == NOT_TRIED)
4340
  {
4383
  {
Lines 4385-4396 Link Here
4385
4428
4386
      else if (chunking_state > CHUNKING_OFFERED)
4429
      else if (chunking_state > CHUNKING_OFFERED)
4387
	{
4430
	{
4388
        smtp_printf("250- %u byte chunk, total %d\r\n250 OK id=%s\r\n", FALSE,
4431
	/* If there is more input waiting, no need to flush (probably the client
4432
	pipelined QUIT after data).  We check only the in-process buffer, not
4433
	the socket. */
4434
4435
        smtp_printf("250- %u byte chunk, total %d\r\n250 OK id=%s\r\n",
4436
	    receive_hasc(),
4389
	    chunking_datasize, message_size+message_linecount, message_id);
4437
	    chunking_datasize, message_size+message_linecount, message_id);
4390
	chunking_state = CHUNKING_OFFERED;
4438
	chunking_state = CHUNKING_OFFERED;
4391
	}
4439
	}
4392
      else
4440
      else
4393
        smtp_printf("250 OK id=%s\r\n", FALSE, message_id);
4441
        smtp_printf("250 OK id=%s\r\n", receive_hasc(), message_id);
4394
4442
4395
      if (host_checking)
4443
      if (host_checking)
4396
        fprintf(stdout,
4444
        fprintf(stdout,
(-)exim.orig/src/regex.c (-18 / +27 lines)
Lines 2-10 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-2015
5
/*
6
 * Copyright (c) The Exim Maintainers 2016 - 2022
7
 * Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003-2015
6
 * License: GPL
8
 * License: GPL
7
 * Copyright (c) The Exim Maintainers 2016 - 2018
8
 */
9
 */
9
10
10
/* Code for matching regular expressions against headers and body.
11
/* Code for matching regular expressions against headers and body.
Lines 17-23 Link Here
17
18
18
/* Structure to hold a list of Regular expressions */
19
/* Structure to hold a list of Regular expressions */
19
typedef struct pcre_list {
20
typedef struct pcre_list {
20
  pcre *re;
21
  pcre2_code *re;
21
  uschar *pcre_text;
22
  uschar *pcre_text;
22
  struct pcre_list *next;
23
  struct pcre_list *next;
23
} pcre_list;
24
} pcre_list;
Lines 32-39 Link Here
32
{
33
{
33
int sep = 0;
34
int sep = 0;
34
uschar *regex_string;
35
uschar *regex_string;
35
const char *pcre_error;
36
int pcre_erroffset;
37
pcre_list *re_list_head = NULL;
36
pcre_list *re_list_head = NULL;
38
pcre_list *ri;
37
pcre_list *ri;
39
38
Lines 41-59 Link Here
41
while ((regex_string = string_nextinlist(&list, &sep, NULL, 0)))
40
while ((regex_string = string_nextinlist(&list, &sep, NULL, 0)))
42
  if (strcmpic(regex_string, US"false") != 0 && Ustrcmp(regex_string, "0") != 0)
41
  if (strcmpic(regex_string, US"false") != 0 && Ustrcmp(regex_string, "0") != 0)
43
    {
42
    {
44
    pcre *re;
43
    pcre2_code * re;
44
    int err;
45
    PCRE2_SIZE pcre_erroffset;
45
46
46
    /* compile our regular expression */
47
    /* compile our regular expression */
47
    if (!(re = pcre_compile( CS regex_string,
48
    if (!(re = pcre2_compile( (PCRE2_SPTR) regex_string, PCRE2_ZERO_TERMINATED,
48
		       0, &pcre_error, &pcre_erroffset, NULL )))
49
		  0, &err, &pcre_erroffset, pcre_cmp_ctx)))
49
      {
50
      {
51
      uschar errbuf[128];
52
      pcre2_get_error_message(err, errbuf, sizeof(errbuf));
50
      log_write(0, LOG_MAIN,
53
      log_write(0, LOG_MAIN,
51
	   "regex acl condition warning - error in regex '%s': %s at offset %d, skipped.",
54
	   "regex acl condition warning - error in regex '%s': %s at offset %ld, skipped.",
52
	   regex_string, pcre_error, pcre_erroffset);
55
	   regex_string, errbuf, (long)pcre_erroffset);
53
      continue;
56
      continue;
54
      }
57
      }
55
58
56
    ri = store_get(sizeof(pcre_list), FALSE);
59
    ri = store_get(sizeof(pcre_list), GET_UNTAINTED);
57
    ri->re = re;
60
    ri->re = re;
58
    ri->pcre_text = regex_string;
61
    ri->pcre_text = regex_string;
59
    ri->next = re_list_head;
62
    ri->next = re_list_head;
Lines 65-89 Link Here
65
static int
68
static int
66
matcher(pcre_list * re_list_head, uschar * linebuffer, int len)
69
matcher(pcre_list * re_list_head, uschar * linebuffer, int len)
67
{
70
{
68
for(pcre_list * ri = re_list_head; ri; ri = ri->next)
71
pcre2_match_data * md = pcre2_match_data_create(REGEX_VARS + 1, pcre_gen_ctx);
72
73
for (pcre_list * ri = re_list_head; ri; ri = ri->next)
69
  {
74
  {
70
  int ovec[3*(REGEX_VARS+1)];
71
  int n;
75
  int n;
72
76
73
  /* try matcher on the line */
77
  /* try matcher on the line */
74
  if ((n = pcre_exec(ri->re, NULL, CS linebuffer, len, 0, 0, ovec, nelem(ovec))) > 0)
78
  if ((n = pcre2_match(ri->re, (PCRE2_SPTR)linebuffer, len, 0, 0, md, pcre_mtc_ctx)) > 0)
75
    {
79
    {
76
    Ustrncpy(regex_match_string_buffer, ri->pcre_text,
80
    Ustrncpy(regex_match_string_buffer, ri->pcre_text,
77
	      sizeof(regex_match_string_buffer)-1);
81
	      sizeof(regex_match_string_buffer)-1);
78
    regex_match_string = regex_match_string_buffer;
82
    regex_match_string = regex_match_string_buffer;
79
83
80
    for (int nn = 1; nn < n; nn++)
84
    for (int nn = 1; nn < n; nn++)
81
      regex_vars[nn-1] =
85
      {
82
	string_copyn(linebuffer + ovec[nn*2], ovec[nn*2+1] - ovec[nn*2]);
86
      PCRE2_UCHAR * cstr;
87
      PCRE2_SIZE cslen;
88
      pcre2_substring_get_bynumber(md, nn, &cstr, &cslen);
89
      regex_vars[nn-1] = CUS cstr;
90
      }
83
91
84
    return OK;
92
    return OK;
85
    }
93
    }
86
  }
94
  }
95
pcre2_match_data_free(md);
87
return FAIL;
96
return FAIL;
88
}
97
}
89
98
Lines 125-131 Link Here
125
  return FAIL;			/* no regexes -> nothing to do */
134
  return FAIL;			/* no regexes -> nothing to do */
126
135
127
/* match each line against all regexes */
136
/* match each line against all regexes */
128
linebuffer = store_get(32767, TRUE);	/* tainted */
137
linebuffer = store_get(32767, GET_TAINTED);
129
while (fgets(CS linebuffer, 32767, mbox_file))
138
while (fgets(CS linebuffer, 32767, mbox_file))
130
  {
139
  {
131
  if (  mime_stream && mime_current_boundary		/* check boundary */
140
  if (  mime_stream && mime_current_boundary		/* check boundary */
Lines 196-202 Link Here
196
  }
205
  }
197
206
198
/* get 32k memory, tainted */
207
/* get 32k memory, tainted */
199
mime_subject = store_get(32767, TRUE);
208
mime_subject = store_get(32767, GET_TAINTED);
200
209
201
mime_subject_len = fread(mime_subject, 1, 32766, f);
210
mime_subject_len = fread(mime_subject, 1, 32766, f);
202
211
(-)exim.orig/src/retry.c (-13 / +12 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Functions concerned with retrying unsuccessful deliveries. */
9
/* Functions concerned with retrying unsuccessful deliveries. */
Lines 127-137 Link Here
127
{
127
{
128
BOOL yield = FALSE;
128
BOOL yield = FALSE;
129
time_t now = time(NULL);
129
time_t now = time(NULL);
130
uschar *host_key, *message_key;
130
uschar * host_key, * message_key;
131
open_db dbblock;
131
open_db dbblock, * dbm_file;
132
open_db *dbm_file;
132
tree_node * node;
133
tree_node *node;
133
dbdata_retry * host_retry_record, * message_retry_record;
134
dbdata_retry *host_retry_record, *message_retry_record;
135
134
136
*retry_host_key = *retry_message_key = NULL;
135
*retry_host_key = *retry_message_key = NULL;
137
136
Lines 145-153 Link Here
145
/* Generate the host key for the unusable tree and the retry database. Ensure
144
/* Generate the host key for the unusable tree and the retry database. Ensure
146
host names are lower cased (that's what %S does). */
145
host names are lower cased (that's what %S does). */
147
146
148
host_key = include_ip_address?
147
host_key = include_ip_address
149
  string_sprintf("T:%S:%s%s", host->name, host->address, portstring) :
148
  ? string_sprintf("T:%S:%s%s", host->name, host->address, portstring)
150
  string_sprintf("T:%S%s", host->name, portstring);
149
  : string_sprintf("T:%S%s", host->name, portstring);
151
150
152
/* Generate the message-specific key */
151
/* Generate the message-specific key */
153
152
Lines 292-298 Link Here
292
void
291
void
293
retry_add_item(address_item *addr, uschar *key, int flags)
292
retry_add_item(address_item *addr, uschar *key, int flags)
294
{
293
{
295
retry_item *rti = store_get(sizeof(retry_item), FALSE);
294
retry_item * rti = store_get(sizeof(retry_item), GET_UNTAINTED);
296
host_item * host = addr->host_used;
295
host_item * host = addr->host_used;
297
296
298
rti->next = addr->retries;
297
rti->next = addr->retries;
Lines 655-661 Link Here
655
	  ? US string_printing(rti->message)
654
	  ? US string_printing(rti->message)
656
	  : US"unknown error";
655
	  : US"unknown error";
657
        message_length = Ustrlen(message);
656
        message_length = Ustrlen(message);
658
        if (message_length > 150) message_length = 150;
657
        if (message_length > EXIM_DB_RLIMIT) message_length = EXIM_DB_RLIMIT;
659
658
660
        /* Read a retry record from the database or construct a new one.
659
        /* Read a retry record from the database or construct a new one.
661
        Ignore an old one if it is too old since it was last updated. */
660
        Ignore an old one if it is too old since it was last updated. */
Lines 669-675 Link Here
669
        if (!retry_record)
668
        if (!retry_record)
670
          {
669
          {
671
          retry_record = store_get(sizeof(dbdata_retry) + message_length,
670
          retry_record = store_get(sizeof(dbdata_retry) + message_length,
672
				   is_tainted(message));
671
				   message);
673
          message_space = message_length;
672
          message_space = message_length;
674
          retry_record->first_failed = now;
673
          retry_record->first_failed = now;
675
          retry_record->last_try = now;
674
          retry_record->last_try = now;
Lines 815-821 Link Here
815
	if (message_length > message_space)
814
	if (message_length > message_space)
816
	  {
815
	  {
817
	  dbdata_retry * newr =
816
	  dbdata_retry * newr =
818
	    store_get(sizeof(dbdata_retry) + message_length, is_tainted(message));
817
	    store_get(sizeof(dbdata_retry) + message_length, message);
819
	  memcpy(newr, retry_record, sizeof(dbdata_retry));
818
	  memcpy(newr, retry_record, sizeof(dbdata_retry));
820
	  retry_record = newr;
819
	  retry_record = newr;
821
	  }
820
	  }
(-)exim.orig/src/rewrite.c (-34 / +18 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2021 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 109-119 Link Here
109
110
110
if (whole) *whole = FALSE;
111
if (whole) *whole = FALSE;
111
112
112
/* Scan the rewriting rules */
113
/* Scan the rewriting rules, ignoring any without matching flag */
113
114
114
for (rewrite_rule * rule = rewrite_rules;
115
for (rewrite_rule * rule = rewrite_rules;
115
     rule && !done;
116
     rule && !done;
116
     rule_number++, rule = rule->next)
117
     rule_number++, rule = rule->next) if (rule->flags & flag)
117
  {
118
  {
118
  int start, end, pdomain;
119
  int start, end, pdomain;
119
  int count = 0;
120
  int count = 0;
Lines 122-131 Link Here
122
  uschar *error, *new;
123
  uschar *error, *new;
123
  const uschar * newparsed;
124
  const uschar * newparsed;
124
125
125
  /* Ensure that the flag matches the flags in the rule. */
126
127
  if (!(rule->flags & flag)) continue;
128
129
  /* Come back here for a repeat after a successful rewrite. We do this
126
  /* Come back here for a repeat after a successful rewrite. We do this
130
  only so many times. */
127
  only so many times. */
131
128
Lines 453-462 Link Here
453
header_line *newh = NULL;
450
header_line *newh = NULL;
454
rmark function_reset_point = store_mark();
451
rmark function_reset_point = store_mark();
455
uschar *s = Ustrchr(h->text, ':') + 1;
452
uschar *s = Ustrchr(h->text, ':') + 1;
453
456
while (isspace(*s)) s++;
454
while (isspace(*s)) s++;
457
455
458
DEBUG(D_rewrite)
456
DEBUG(D_rewrite)
459
  debug_printf("rewrite_one_header: type=%c:\n  %s", h->type, h->text);
457
  debug_printf_indent("rewrite_one_header: type=%c:\n  %s", h->type, h->text);
460
458
461
f.parse_allow_group = TRUE;     /* Allow group syntax */
459
f.parse_allow_group = TRUE;     /* Allow group syntax */
462
460
Lines 483-493 Link Here
483
  the next address, saving the start of the old one. */
481
  the next address, saving the start of the old one. */
484
482
485
  *ss = 0;
483
  *ss = 0;
486
  recipient = parse_extract_address(s,&errmess,&start,&end,&domain,FALSE);
484
  recipient = parse_extract_address(s, &errmess, &start, &end, &domain, FALSE);
487
488
  *ss = terminator;
485
  *ss = terminator;
489
  sprev = s;
486
  sprev = s;
490
  s = ss + (terminator? 1:0);
487
  s = ss + (terminator ? 1 : 0);
491
  while (isspace(*s)) s++;
488
  while (isspace(*s)) s++;
492
489
493
  /* There isn't much we can do for syntactic disasters at this stage.
490
  /* There isn't much we can do for syntactic disasters at this stage.
Lines 496-525 Link Here
496
  empty address, overlong addres. Sometimes the result matters, sometimes not.
493
  empty address, overlong addres. Sometimes the result matters, sometimes not.
497
  It seems this function is called for *any* header we see. */
494
  It seems this function is called for *any* header we see. */
498
495
499
500
  if (!recipient)
496
  if (!recipient)
501
    {
497
    {
502
#if 0
498
    /* Handle unparesable addresses in the header. Slightly ugly because a
503
    /* FIXME:
499
    null output from the extract can also result from a header without an
504
    This was(!) an attempt tho handle empty rewrits, but seemingly it
500
    address, "To: undisclosed recpients:;" being the classic case. */
505
    needs more effort to decide if the returned empty address matters.
506
    Now this will now break test 471 again.
507
508
    471 fails now because it uses an overlong address, for wich parse_extract_address()
509
    returns an empty address (which was not expected).
510
511
    Checking the output and exit if rewrite_rules or routed_old are present
512
    isn't a good idea either: It's enough to have *any* rewrite rule
513
    in the configuration plus "To: undisclosed recpients:;" to exit(), which
514
    is not what we want.
515
    */
516
501
517
    if (rewrite_rules || routed_old)
502
    if ((rewrite_rules || routed_old) && Ustrcmp(errmess, "empty address") != 0)
518
      {
503
      {
519
      log_write(0, LOG_MAIN, "rewrite: %s", errmess);
504
      log_write(0, LOG_MAIN, "rewrite: %s", errmess);
520
      exim_exit(EXIT_FAILURE);
505
      exim_exit(EXIT_FAILURE);
521
      }
506
      }
522
#endif
523
    loop_reset_point = store_reset(loop_reset_point);
507
    loop_reset_point = store_reset(loop_reset_point);
524
    continue;
508
    continue;
525
    }
509
    }
Lines 534-540 Link Here
534
  as abc@xyz, which the DNS lookup turns into abc@xyz.foo.com). However, if no
518
  as abc@xyz, which the DNS lookup turns into abc@xyz.foo.com). However, if no
535
  change is made here, don't bother carrying on. */
519
  change is made here, don't bother carrying on. */
536
520
537
  if (routed_old != NULL)
521
  if (routed_old)
538
    {
522
    {
539
    if (domain <= 0 || strcmpic(recipient+domain, routed_old) != 0) continue;
523
    if (domain <= 0 || strcmpic(recipient+domain, routed_old) != 0) continue;
540
    recipient[domain-1] = 0;
524
    recipient[domain-1] = 0;
Lines 579-585 Link Here
579
  "whole" flag set, adjust the pointers so that the whole address gets
563
  "whole" flag set, adjust the pointers so that the whole address gets
580
  replaced, except possibly a final \n. */
564
  replaced, except possibly a final \n. */
581
565
582
  if ((existflags & flag) != 0)
566
  if (existflags & flag)
583
    {
567
    {
584
    BOOL whole;
568
    BOOL whole;
585
    /* deconst ok as recipient was notconst */
569
    /* deconst ok as recipient was notconst */
Lines 619-625 Link Here
619
    int oldlen = end - start;
603
    int oldlen = end - start;
620
604
621
    header_line * prev = newh ? newh : h;
605
    header_line * prev = newh ? newh : h;
622
    uschar * newt = store_get_perm(prev->slen - oldlen + newlen + 4, TRUE);
606
    uschar * newt = store_get_perm(prev->slen - oldlen + newlen + 4, GET_TAINTED);
623
    uschar * newtstart = newt;
607
    uschar * newtstart = newt;
624
608
625
    int type = prev->type;
609
    int type = prev->type;
Lines 683-689 Link Here
683
667
684
    store_reset(function_reset_point);
668
    store_reset(function_reset_point);
685
    function_reset_point = store_mark();
669
    function_reset_point = store_mark();
686
    newh = store_get(sizeof(header_line), FALSE);
670
    newh = store_get(sizeof(header_line), GET_UNTAINTED);
687
    newh->type = type;
671
    newh->type = type;
688
    newh->slen = slen;
672
    newh->slen = slen;
689
    newh->text = string_copyn(newtstart, slen);
673
    newh->text = string_copyn(newtstart, slen);
Lines 691-697 Link Here
691
    /* Set up for scanning the rest of the header */
675
    /* Set up for scanning the rest of the header */
692
676
693
    s = newh->text + remlen;
677
    s = newh->text + remlen;
694
    DEBUG(D_rewrite) debug_printf("remainder: %s", (*s == 0)? US"\n" : s);
678
    DEBUG(D_rewrite) debug_printf("remainder: %s", *s ? s : US"\n");
695
    }
679
    }
696
  }
680
  }
697
681
Lines 701-710 Link Here
701
/* If a rewrite happened and "replace" is true, put the new header into the
685
/* If a rewrite happened and "replace" is true, put the new header into the
702
chain following the old one, and mark the old one as replaced. */
686
chain following the old one, and mark the old one as replaced. */
703
687
704
if (newh != NULL && replace)
688
if (newh && replace)
705
  {
689
  {
706
  newh->next = h->next;
690
  newh->next = h->next;
707
  if (newh->next == NULL) header_last = newh;
691
  if (!newh->next) header_last = newh;
708
  h->type = htype_old;
692
  h->type = htype_old;
709
  h->next = newh;
693
  h->next = newh;
710
  }
694
  }
(-)exim.orig/src/rfc2047.c (-6 / +6 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* This file contains a function for decoding message header lines that may
9
/* This file contains a function for decoding message header lines that may
Lines 47-53 Link Here
47
int len = 0;
47
int len = 0;
48
uschar *ptr;
48
uschar *ptr;
49
49
50
ptr = *ptrptr = store_get(Ustrlen(string) + 1, is_tainted(string));  /* No longer than this */
50
ptr = *ptrptr = store_get(Ustrlen(string) + 1, string);  /* No longer than this */
51
51
52
while (*string != 0)
52
while (*string != 0)
53
  {
53
  {
Lines 186-193 Link Here
186
*/
186
*/
187
187
188
uschar *
188
uschar *
189
rfc2047_decode2(uschar *string, BOOL lencheck, uschar *target, int zeroval,
189
rfc2047_decode2(uschar *string, BOOL lencheck, const uschar *target,
190
  int *lenptr, int *sizeptr, uschar **error)
190
  int zeroval, int *lenptr, int *sizeptr, uschar **error)
191
{
191
{
192
int size = Ustrlen(string);
192
int size = Ustrlen(string);
193
size_t dlen;
193
size_t dlen;
Lines 209-215 Link Here
209
translated into a multibyte code such as UTF-8. That's why we use the dynamic
209
translated into a multibyte code such as UTF-8. That's why we use the dynamic
210
string building code. */
210
string building code. */
211
211
212
yield = store_get(sizeof(gstring) + ++size, is_tainted(string));
212
yield = store_get(sizeof(gstring) + ++size, string);
213
yield->size = size;
213
yield->size = size;
214
yield->ptr = 0;
214
yield->ptr = 0;
215
yield->s = US(yield + 1);
215
yield->s = US(yield + 1);
Lines 336-342 Link Here
336
argument. */
336
argument. */
337
337
338
uschar *
338
uschar *
339
rfc2047_decode(uschar *string, BOOL lencheck, uschar *target, int zeroval,
339
rfc2047_decode(uschar *string, BOOL lencheck, const uschar *target, int zeroval,
340
  int *lenptr, uschar **error)
340
  int *lenptr, uschar **error)
341
{
341
{
342
return rfc2047_decode2(string, lencheck, target, zeroval, lenptr, NULL, error);
342
return rfc2047_decode2(string, lencheck, target, zeroval, lenptr, NULL, error);
(-)exim.orig/src/route.c (-11 / +30 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Functions concerned with routing, and the list of generic router options. */
9
/* Functions concerned with routing, and the list of generic router options. */
Lines 288-294 Link Here
288
288
289
  /* Build a host list if fallback hosts is set. */
289
  /* Build a host list if fallback hosts is set. */
290
290
291
  host_build_hostlist(&(r->fallback_hostlist), r->fallback_hosts, FALSE);
291
    {
292
    int old_pool = store_pool;
293
    store_pool = POOL_PERM;
294
    host_build_hostlist(&r->fallback_hostlist, r->fallback_hosts, FALSE);
295
    store_pool = old_pool;
296
    }
292
297
293
  /* Check redirect_router and pass_router are valid */
298
  /* Check redirect_router and pass_router are valid */
294
299
Lines 607-620 Link Here
607
BOOL ugid_set = FALSE;
612
BOOL ugid_set = FALSE;
608
const uschar *listptr;
613
const uschar *listptr;
609
uschar *check;
614
uschar *check;
610
uschar buffer[1024];
611
615
612
if (!s) return OK;
616
if (!s) return OK;
613
617
614
DEBUG(D_route) debug_printf("checking require_files\n");
618
DEBUG(D_route) debug_printf("checking require_files\n");
615
619
616
listptr = s;
620
listptr = s;
617
while ((check = string_nextinlist(&listptr, &sep, buffer, sizeof(buffer))))
621
while ((check = string_nextinlist(&listptr, &sep, NULL, 0)))
618
  {
622
  {
619
  int rc;
623
  int rc;
620
  int eacces_code = 0;
624
  int eacces_code = 0;
Lines 1495-1501 Link Here
1495
1499
1496
  if (!(node = tree_search(*root, name)))
1500
  if (!(node = tree_search(*root, name)))
1497
    {				/* name should never be tainted */
1501
    {				/* name should never be tainted */
1498
    node = store_get(sizeof(tree_node) + Ustrlen(name), FALSE);
1502
    node = store_get(sizeof(tree_node) + Ustrlen(name), GET_UNTAINTED);
1499
    Ustrcpy(node->name, name);
1503
    Ustrcpy(node->name, name);
1500
    (void)tree_insertnode(root, node);
1504
    (void)tree_insertnode(root, node);
1501
    }
1505
    }
Lines 1666-1672 Link Here
1666
	addr->prefix_v = string_copyn(addr->local_part, vlen);
1670
	addr->prefix_v = string_copyn(addr->local_part, vlen);
1667
	}
1671
	}
1668
      else
1672
      else
1669
	addr->prefix = string_copyn_taint(addr->local_part, plen, FALSE);
1673
	addr->prefix = string_copyn_taint(addr->local_part, plen, GET_UNTAINTED);
1670
      addr->local_part += plen;
1674
      addr->local_part += plen;
1671
      DEBUG(D_route) debug_printf("stripped prefix %s\n", addr->prefix);
1675
      DEBUG(D_route) debug_printf("stripped prefix %s\n", addr->prefix);
1672
      }
1676
      }
Lines 1689-1695 Link Here
1689
      int lplen = Ustrlen(addr->local_part) - slen;
1693
      int lplen = Ustrlen(addr->local_part) - slen;
1690
      addr->suffix = vlen
1694
      addr->suffix = vlen
1691
	? addr->local_part + lplen
1695
	? addr->local_part + lplen
1692
	: string_copy_taint(addr->local_part + lplen, slen);
1696
	: string_copy_taint(addr->local_part + lplen, GET_UNTAINTED);
1693
      addr->suffix_v = addr->suffix + Ustrlen(addr->suffix) - vlen;
1697
      addr->suffix_v = addr->suffix + Ustrlen(addr->suffix) - vlen;
1694
      addr->local_part = string_copyn(addr->local_part, lplen);
1698
      addr->local_part = string_copyn(addr->local_part, lplen);
1695
      DEBUG(D_route) debug_printf("stripped suffix %s\n", addr->suffix);
1699
      DEBUG(D_route) debug_printf("stripped suffix %s\n", addr->suffix);
Lines 1706-1711 Link Here
1706
  the local part sorted. */
1710
  the local part sorted. */
1707
1711
1708
  router_name = r->name;
1712
  router_name = r->name;
1713
  driver_srcfile = r->srcfile;
1714
  driver_srcline = r->srcline;
1709
  deliver_set_expansions(addr);
1715
  deliver_set_expansions(addr);
1710
1716
1711
  /* For convenience, the pre-router checks are in a separate function, which
1717
  /* For convenience, the pre-router checks are in a separate function, which
Lines 1713-1719 Link Here
1713
1719
1714
  if ((rc = check_router_conditions(r, addr, verify, &pw, &error)) != OK)
1720
  if ((rc = check_router_conditions(r, addr, verify, &pw, &error)) != OK)
1715
    {
1721
    {
1716
    router_name = NULL;
1722
    driver_srcfile = router_name = NULL; driver_srcline = 0;
1717
    if (rc == SKIP) continue;
1723
    if (rc == SKIP) continue;
1718
    addr->message = error;
1724
    addr->message = error;
1719
    yield = rc;
1725
    yield = rc;
Lines 1764-1770 Link Here
1764
          {
1770
          {
1765
          DEBUG(D_route)
1771
          DEBUG(D_route)
1766
            debug_printf("\"more\"=false: skipping remaining routers\n");
1772
            debug_printf("\"more\"=false: skipping remaining routers\n");
1767
	  router_name = NULL;
1773
	  driver_srcfile = router_name = NULL; driver_srcline = 0;
1768
          r = NULL;
1774
          r = NULL;
1769
          break;
1775
          break;
1770
          }
1776
          }
Lines 1816-1822 Link Here
1816
  yield = (r->info->code)(r, addr, pw, verify, paddr_local, paddr_remote,
1822
  yield = (r->info->code)(r, addr, pw, verify, paddr_local, paddr_remote,
1817
    addr_new, addr_succeed);
1823
    addr_new, addr_succeed);
1818
1824
1819
  router_name = NULL;
1825
  driver_srcfile = router_name = NULL; driver_srcline = 0;
1820
1826
1821
  if (yield == FAIL)
1827
  if (yield == FAIL)
1822
    {
1828
    {
Lines 2044-2053 Link Here
2044
  addr->message = expand_hide_passwords(addr->message);
2050
  addr->message = expand_hide_passwords(addr->message);
2045
2051
2046
deliver_set_expansions(NULL);
2052
deliver_set_expansions(NULL);
2047
router_name = NULL;
2053
driver_srcfile = router_name = NULL; driver_srcline = 0;
2048
f.disable_logging = FALSE;
2054
f.disable_logging = FALSE;
2049
return yield;
2055
return yield;
2050
}
2056
}
2051
2057
2058
2059
2060
/* For error messages, a string describing the config location associated
2061
with current processing.  NULL if we are not in a router. */
2062
/* Name only, for now */
2063
2064
uschar *
2065
router_current_name(void)
2066
{
2067
if (!router_name) return NULL;
2068
return string_sprintf(" (router %s, %s %d)", router_name, driver_srcfile, driver_srcline);
2069
}
2070
2052
#endif	/*!MACRO_PREDEF*/
2071
#endif	/*!MACRO_PREDEF*/
2053
/* End of route.c */
2072
/* End of route.c */
(-)exim.orig/src/routers/accept.c (-4 / +1 lines)
Lines 3-9 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
6
/* Copyright (c) The Exim Maintainers 2020 - 2021 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 107-115 Link Here
107
uschar *remove_headers;
107
uschar *remove_headers;
108
header_line *extra_headers;
108
header_line *extra_headers;
109
109
110
addr_new = addr_new;  /* Keep picky compilers happy */
111
addr_succeed = addr_succeed;
112
113
DEBUG(D_route) debug_printf("%s router called for %s\n  domain = %s\n",
110
DEBUG(D_route) debug_printf("%s router called for %s\n  domain = %s\n",
114
  rblock->name, addr->address, addr->domain);
111
  rblock->name, addr->address, addr->domain);
115
112
(-)exim.orig/src/routers/dnslookup.c (-5 / +4 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#include "../exim.h"
9
#include "../exim.h"
Lines 160-168 Link Here
160
const uschar *listptr;
160
const uschar *listptr;
161
uschar widen_buffer[256];
161
uschar widen_buffer[256];
162
162
163
addr_new = addr_new;          /* Keep picky compilers happy */
164
addr_succeed = addr_succeed;
165
166
DEBUG(D_route)
163
DEBUG(D_route)
167
  debug_printf("%s router called for %s\n  domain = %s\n",
164
  debug_printf("%s router called for %s\n  domain = %s\n",
168
    rblock->name, addr->address, addr->domain);
165
    rblock->name, addr->address, addr->domain);
Lines 207-212 Link Here
207
   && (verify != v_sender || !ob->rewrite_headers || addr->parent))
204
   && (verify != v_sender || !ob->rewrite_headers || addr->parent))
208
  {
205
  {
209
  listptr = ob->widen_domains;
206
  listptr = ob->widen_domains;
207
  /* not expanded so should never be tainted */
210
  widen = string_nextinlist(&listptr, &widen_sep, widen_buffer,
208
  widen = string_nextinlist(&listptr, &widen_sep, widen_buffer,
211
    sizeof(widen_buffer));
209
    sizeof(widen_buffer));
212
210
Lines 236-241 Link Here
236
  else if (widen)
234
  else if (widen)
237
    {
235
    {
238
    h.name = string_sprintf("%s.%s", addr->domain, widen);
236
    h.name = string_sprintf("%s.%s", addr->domain, widen);
237
    /* not expanded so should never be tainted */
239
    widen = string_nextinlist(&listptr, &widen_sep, widen_buffer,
238
    widen = string_nextinlist(&listptr, &widen_sep, widen_buffer,
240
      sizeof(widen_buffer));
239
      sizeof(widen_buffer));
241
    DEBUG(D_route) debug_printf("%s router widened %s to %s\n", rblock->name,
240
    DEBUG(D_route) debug_printf("%s router widened %s to %s\n", rblock->name,
Lines 457-463 Link Here
457
/* Get store in which to preserve the original host item, chained on
456
/* Get store in which to preserve the original host item, chained on
458
to the address. */
457
to the address. */
459
458
460
addr->host_list = store_get(sizeof(host_item), FALSE);
459
addr->host_list = store_get(sizeof(host_item), GET_UNTAINTED);
461
addr->host_list[0] = h;
460
addr->host_list[0] = h;
462
461
463
/* Fill in the transport and queue the address for delivery. */
462
/* Fill in the transport and queue the address for delivery. */
(-)exim.orig/src/routers/ipliteral.c (-6 / +2 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 57-63 Link Here
57
ipliteral_router_options_block *ob =
57
ipliteral_router_options_block *ob =
58
  (ipliteral_router_options_block *)(rblock->options_block);
58
  (ipliteral_router_options_block *)(rblock->options_block);
59
*/
59
*/
60
rblock = rblock;
61
}
60
}
62
61
63
62
Lines 116-124 Link Here
116
int len = Ustrlen(domain);
115
int len = Ustrlen(domain);
117
int rc, ipv;
116
int rc, ipv;
118
117
119
addr_new = addr_new;         /* Keep picky compilers happy */
120
addr_succeed = addr_succeed;
121
122
DEBUG(D_route) debug_printf("%s router called for %s: domain = %s\n",
118
DEBUG(D_route) debug_printf("%s router called for %s: domain = %s\n",
123
  rblock->name, addr->address, addr->domain);
119
  rblock->name, addr->address, addr->domain);
124
120
Lines 150-156 Link Here
150
146
151
/* Set up a host item */
147
/* Set up a host item */
152
148
153
h = store_get(sizeof(host_item), FALSE);
149
h = store_get(sizeof(host_item), GET_UNTAINTED);
154
150
155
h->next = NULL;
151
h->next = NULL;
156
h->address = string_copy(ip);
152
h->address = string_copy(ip);
(-)exim.orig/src/routers/iplookup.c (-9 / +5 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 161-183 Link Here
161
uschar *hostname, *reroute, *domain;
161
uschar *hostname, *reroute, *domain;
162
const uschar *listptr;
162
const uschar *listptr;
163
uschar host_buffer[256];
163
uschar host_buffer[256];
164
host_item *host = store_get(sizeof(host_item), FALSE);
164
host_item *host = store_get(sizeof(host_item), GET_UNTAINTED);
165
address_item *new_addr;
165
address_item *new_addr;
166
iplookup_router_options_block *ob =
166
iplookup_router_options_block *ob =
167
  (iplookup_router_options_block *)(rblock->options_block);
167
  (iplookup_router_options_block *)(rblock->options_block);
168
const pcre *re = ob->re_response_pattern;
168
const pcre2_code *re = ob->re_response_pattern;
169
int count, query_len, rc;
169
int count, query_len, rc;
170
int sep = 0;
170
int sep = 0;
171
171
172
addr_local = addr_local;    /* Keep picky compilers happy */
173
addr_remote = addr_remote;
174
addr_succeed = addr_succeed;
175
pw = pw;
176
177
DEBUG(D_route) debug_printf("%s router called for %s: domain = %s\n",
172
DEBUG(D_route) debug_printf("%s router called for %s: domain = %s\n",
178
  rblock->name, addr->address, addr->domain);
173
  rblock->name, addr->address, addr->domain);
179
174
180
reply = store_get(256, TRUE);	/* tainted data */
175
reply = store_get(256, GET_TAINTED);
181
176
182
/* Build the query string to send. If not explicitly given, a default of
177
/* Build the query string to send. If not explicitly given, a default of
183
"user@domain user@domain" is used. */
178
"user@domain user@domain" is used. */
Lines 205-210 Link Here
205
being a host list. */
200
being a host list. */
206
201
207
listptr = ob->hosts;
202
listptr = ob->hosts;
203
/* not expanded so should never be tainted */
208
while ((hostname = string_nextinlist(&listptr, &sep, host_buffer,
204
while ((hostname = string_nextinlist(&listptr, &sep, host_buffer,
209
       sizeof(host_buffer))))
205
       sizeof(host_buffer))))
210
  {
206
  {
(-)exim.orig/src/routers/iplookup.h (-1 / +2 lines)
Lines 3-8 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2009 */
5
/* Copyright (c) University of Cambridge 1995 - 2009 */
6
/* Copyright (c) The Exim Maintainers 2021 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
8
9
Lines 17-23 Link Here
17
  uschar *query;
18
  uschar *query;
18
  uschar *response_pattern;
19
  uschar *response_pattern;
19
  uschar *reroute;
20
  uschar *reroute;
20
  const pcre *re_response_pattern;
21
  const pcre2_code *re_response_pattern;
21
  BOOL  optional;
22
  BOOL  optional;
22
} iplookup_router_options_block;
23
} iplookup_router_options_block;
23
24
(-)exim.orig/src/routers/manualroute.c (-7 / +4 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 248-256 Link Here
248
BOOL individual_transport_set = FALSE;
248
BOOL individual_transport_set = FALSE;
249
BOOL randomize = ob->hosts_randomize;
249
BOOL randomize = ob->hosts_randomize;
250
250
251
addr_new = addr_new;           /* Keep picky compilers happy */
252
addr_succeed = addr_succeed;
253
254
DEBUG(D_route) debug_printf("%s router called for %s\n  domain = %s\n",
251
DEBUG(D_route) debug_printf("%s router called for %s\n  domain = %s\n",
255
  rblock->name, addr->address, addr->domain);
252
  rblock->name, addr->address, addr->domain);
256
253
Lines 262-268 Link Here
262
  int sep = -(';');             /* Default is semicolon */
259
  int sep = -(';');             /* Default is semicolon */
263
  listptr = ob->route_list;
260
  listptr = ob->route_list;
264
261
265
  while ((route_item = string_nextinlist(&listptr, &sep, NULL, 0)) != NULL)
262
  while ((route_item = string_nextinlist(&listptr, &sep, NULL, 0)))
266
    {
263
    {
267
    int rc;
264
    int rc;
268
265
Lines 402-408 Link Here
402
  if (hostlist[0])
399
  if (hostlist[0])
403
    {
400
    {
404
    host_item *h;
401
    host_item *h;
405
    addr->host_list = h = store_get(sizeof(host_item), FALSE);
402
    addr->host_list = h = store_get(sizeof(host_item), GET_UNTAINTED);
406
    h->name = string_copy(hostlist);
403
    h->name = string_copy(hostlist);
407
    h->address = NULL;
404
    h->address = NULL;
408
    h->port = PORT_NONE;
405
    h->port = PORT_NONE;
Lines 471-477 Link Here
471
defined for these hosts. It will be a remote one, as a local transport is
468
defined for these hosts. It will be a remote one, as a local transport is
472
dealt with above. However, we don't need one if verifying only. */
469
dealt with above. However, we don't need one if verifying only. */
473
470
474
if (transport == NULL && verify == v_none)
471
if (!transport && verify == v_none)
475
    {
472
    {
476
    log_write(0, LOG_MAIN, "Error in %s router: no transport defined",
473
    log_write(0, LOG_MAIN, "Error in %s router: no transport defined",
477
      rblock->name);
474
      rblock->name);
(-)exim.orig/src/routers/queryprogram.c (-54 / +33 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#include "../exim.h"
9
#include "../exim.h"
Lines 86-98 Link Here
86
86
87
/* A command must be given */
87
/* A command must be given */
88
88
89
if (ob->command == NULL)
89
if (!ob->command)
90
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n  "
90
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n  "
91
    "a command specification is required", rblock->name);
91
    "a command specification is required", rblock->name);
92
92
93
/* A uid/gid must be supplied */
93
/* A uid/gid must be supplied */
94
94
95
if (!ob->cmd_uid_set && ob->expand_cmd_uid == NULL)
95
if (!ob->cmd_uid_set && !ob->expand_cmd_uid)
96
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n  "
96
  log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n  "
97
    "command_user must be specified", rblock->name);
97
    "command_user must be specified", rblock->name);
98
}
98
}
Lines 242-282 Link Here
242
  &addr_prop.remove_headers);
242
  &addr_prop.remove_headers);
243
if (rc != OK) return rc;
243
if (rc != OK) return rc;
244
244
245
#ifdef EXPERIMENTAL_SRS
246
addr_prop.srs_sender = NULL;
247
#endif
248
249
/* Get the fixed or expanded uid under which the command is to run
245
/* Get the fixed or expanded uid under which the command is to run
250
(initialization ensures that one or the other is set). */
246
(initialization ensures that one or the other is set). */
251
247
252
if (!ob->cmd_uid_set)
248
if (  !ob->cmd_uid_set
253
  {
249
   && !route_find_expanded_user(ob->expand_cmd_uid, rblock->name, US"router",
254
  if (!route_find_expanded_user(ob->expand_cmd_uid, rblock->name, US"router",
250
	&upw, &uid, &(addr->message)))
255
      &upw, &uid, &(addr->message)))
256
    return DEFER;
251
    return DEFER;
257
  }
258
252
259
/* Get the fixed or expanded gid, or take the gid from the passwd entry. */
253
/* Get the fixed or expanded gid, or take the gid from the passwd entry. */
260
254
261
if (!ob->cmd_gid_set)
255
if (!ob->cmd_gid_set)
262
  {
256
  if (ob->expand_cmd_gid)
263
  if (ob->expand_cmd_gid != NULL)
264
    {
257
    {
265
    if (route_find_expanded_group(ob->expand_cmd_gid, rblock->name,
258
    if (route_find_expanded_group(ob->expand_cmd_gid, rblock->name,
266
        US"router", &gid, &(addr->message)))
259
        US"router", &gid, &(addr->message)))
267
      return DEFER;
260
      return DEFER;
268
    }
261
    }
269
  else if (upw != NULL)
262
  else if (upw)
270
    {
271
    gid = upw->pw_gid;
263
    gid = upw->pw_gid;
272
    }
273
  else
264
  else
274
    {
265
    {
275
    addr->message = string_sprintf("command_user set without command_group "
266
    addr->message = string_sprintf("command_user set without command_group "
276
      "for %s router", rblock->name);
267
      "for %s router", rblock->name);
277
    return DEFER;
268
    return DEFER;
278
    }
269
    }
279
  }
280
270
281
DEBUG(D_route) debug_printf("requires uid=%ld gid=%ld current_directory=%s\n",
271
DEBUG(D_route) debug_printf("requires uid=%ld gid=%ld current_directory=%s\n",
282
  (long int)uid, (long int)gid, current_directory);
272
  (long int)uid, (long int)gid, current_directory);
Lines 301-311 Link Here
301
    TRUE,                               /* expand the arguments */
291
    TRUE,                               /* expand the arguments */
302
    0,                                  /* not relevant when... */
292
    0,                                  /* not relevant when... */
303
    NULL,                               /* no transporting address */
293
    NULL,                               /* no transporting address */
294
    FALSE,				/* args must be untainted */
304
    US"queryprogram router",            /* for error messages */
295
    US"queryprogram router",            /* for error messages */
305
    &(addr->message)))                  /* where to put error message */
296
    &addr->message))                    /* where to put error message */
306
  {
307
  return DEFER;
297
  return DEFER;
308
  }
309
298
310
/* Create the child process, making it a group leader. */
299
/* Create the child process, making it a group leader. */
311
300
Lines 373-380 Link Here
373
rword = buffer;
362
rword = buffer;
374
while (isspace(*rword)) rword++;
363
while (isspace(*rword)) rword++;
375
rdata = rword;
364
rdata = rword;
376
while (*rdata != 0 && !isspace(*rdata)) rdata++;
365
while (*rdata && !isspace(*rdata)) rdata++;
377
if (*rdata != 0) *rdata++ = 0;
366
if (*rdata) *rdata++ = 0;
378
367
379
/* The word must be a known yield name. If it is "REDIRECT", the rest of the
368
/* The word must be a known yield name. If it is "REDIRECT", the rest of the
380
line is redirection data, as for a .forward file. It may not contain filter
369
line is redirection data, as for a .forward file. It may not contain filter
Lines 402-408 Link Here
402
    NULL,                        /* sieve subaddress not relevant */
391
    NULL,                        /* sieve subaddress not relevant */
403
    &ugid,                       /* uid/gid (but not set) */
392
    &ugid,                       /* uid/gid (but not set) */
404
    &generated,                  /* where to hang the results */
393
    &generated,                  /* where to hang the results */
405
    &(addr->message),            /* where to put messages */
394
    &addr->message,              /* where to put messages */
406
    NULL,                        /* don't skip syntax errors */
395
    NULL,                        /* don't skip syntax errors */
407
    &filtertype,                 /* not used; will always be FILTER_FORWARD */
396
    &filtertype,                 /* not used; will always be FILTER_FORWARD */
408
    string_sprintf("%s router", rblock->name));
397
    string_sprintf("%s router", rblock->name));
Lines 414-441 Link Here
414
    response after verifying. */
403
    response after verifying. */
415
404
416
    case FF_DEFER:
405
    case FF_DEFER:
417
    if (addr->message == NULL) addr->message = US"forced defer";
406
      if (!addr->message) addr->message = US"forced defer";
418
      else addr->user_message = addr->message;
407
      else addr->user_message = addr->message;
419
    return DEFER;
408
      return DEFER;
420
409
421
    case FF_FAIL:
410
    case FF_FAIL:
422
    add_generated(rblock, addr_new, addr, generated, &addr_prop);
411
      add_generated(rblock, addr_new, addr, generated, &addr_prop);
423
    if (addr->message == NULL) addr->message = US"forced rejection";
412
      if (!addr->message) addr->message = US"forced rejection";
424
      else addr->user_message = addr->message;
413
      else addr->user_message = addr->message;
425
    return FAIL;
414
      return FAIL;
426
415
427
    case FF_DELIVERED:
416
    case FF_DELIVERED:
428
    break;
417
      break;
429
418
430
    case FF_NOTDELIVERED:    /* an empty redirection list is bad */
419
    case FF_NOTDELIVERED:    /* an empty redirection list is bad */
431
    addr->message = US"no addresses supplied";
420
      addr->message = US"no addresses supplied";
432
    /* Fall through */
421
    /* Fall through */
433
422
434
    case FF_ERROR:
423
    case FF_ERROR:
435
    default:
424
    default:
436
    addr->basic_errno = ERRNO_BADREDIRECT;
425
      addr->basic_errno = ERRNO_BADREDIRECT;
437
    addr->message = string_sprintf("error in redirect data: %s", addr->message);
426
      addr->message = string_sprintf("error in redirect data: %s", addr->message);
438
    return DEFER;
427
      return DEFER;
439
    }
428
    }
440
429
441
  /* Handle the generated addresses, if any. */
430
  /* Handle the generated addresses, if any. */
Lines 473-492 Link Here
473
  }
462
  }
474
463
475
/* The command yielded "ACCEPT". The rest of the string is a number of keyed
464
/* The command yielded "ACCEPT". The rest of the string is a number of keyed
476
fields from which we can fish out values using the "extract" expansion
465
fields from which we can fish out values using the equivalent of the "extract"
477
function. To use this feature, we must put the string into the $value variable,
466
expansion function. */
478
i.e. set lookup_value. */
479
480
lookup_value = rdata;
481
s = expand_string(US"${extract{data}{$value}}");
482
if (*s != 0) addr_prop.address_data = string_copy(s);
483
467
484
s = expand_string(US"${extract{transport}{$value}}");
468
if ((s = expand_getkeyed(US"data", rdata)) && *s)
485
lookup_value = NULL;
469
  addr_prop.address_data = string_copy(s);
486
470
487
/* If we found a transport name, find the actual transport */
471
/* If we found a transport name, find the actual transport */
488
472
489
if (*s != 0)
473
if ((s = expand_getkeyed(US"transport", rdata)) && *s)
490
  {
474
  {
491
  transport_instance *transport;
475
  transport_instance *transport;
492
  for (transport = transports; transport; transport = transport->next)
476
  for (transport = transports; transport; transport = transport->next)
Lines 507-513 Link Here
507
491
508
else
492
else
509
  {
493
  {
510
  if (!rf_get_transport(rblock->transport_name, &(rblock->transport), addr,
494
  if (!rf_get_transport(rblock->transport_name, &rblock->transport, addr,
511
       rblock->name, US"transport"))
495
       rblock->name, US"transport"))
512
    return DEFER;
496
    return DEFER;
513
  addr->transport = rblock->transport;
497
  addr->transport = rblock->transport;
Lines 515-530 Link Here
515
499
516
/* See if a host list is given, and if so, look up the addresses. */
500
/* See if a host list is given, and if so, look up the addresses. */
517
501
518
lookup_value = rdata;
502
if ((s = expand_getkeyed(US"hosts", rdata)) && *s)
519
s = expand_string(US"${extract{hosts}{$value}}");
520
521
if (*s != 0)
522
  {
503
  {
523
  int lookup_type = LK_DEFAULT;
504
  int lookup_type = LK_DEFAULT;
524
  uschar *ss = expand_string(US"${extract{lookup}{$value}}");
505
  uschar * ss = expand_getkeyed(US"lookup", rdata);
525
  lookup_value = NULL;
526
506
527
  if (*ss != 0)
507
  if (ss && *ss)
528
    {
508
    {
529
    if (Ustrcmp(ss, "byname") == 0) lookup_type = LK_BYNAME;
509
    if (Ustrcmp(ss, "byname") == 0) lookup_type = LK_BYNAME;
530
    else if (Ustrcmp(ss, "bydns") == 0) lookup_type = LK_BYDNS;
510
    else if (Ustrcmp(ss, "bydns") == 0) lookup_type = LK_BYDNS;
Lines 551-558 Link Here
551
531
552
/* Queue the address for local or remote delivery. */
532
/* Queue the address for local or remote delivery. */
553
533
554
return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)?
534
return rf_queue_add(addr, addr_local, addr_remote, rblock, pw) ? OK : DEFER;
555
  OK : DEFER;
556
}
535
}
557
536
558
#endif   /*!MACRO_PREDEF*/
537
#endif   /*!MACRO_PREDEF*/
(-)exim.orig/src/routers/redirect.c (-123 / +11 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 93-105 Link Here
93
  { "sieve_useraddress", opt_stringptr,		LOFF(sieve_useraddress) },
93
  { "sieve_useraddress", opt_stringptr,		LOFF(sieve_useraddress) },
94
  { "sieve_vacation_directory", opt_stringptr,	LOFF(sieve_vacation_directory) },
94
  { "sieve_vacation_directory", opt_stringptr,	LOFF(sieve_vacation_directory) },
95
  { "skip_syntax_errors", opt_bool,		LOFF(skip_syntax_errors) },
95
  { "skip_syntax_errors", opt_bool,		LOFF(skip_syntax_errors) },
96
#ifdef EXPERIMENTAL_SRS
97
  { "srs",                opt_stringptr,	LOFF(srs) },
98
  { "srs_alias",          opt_stringptr,	LOFF(srs_alias) },
99
  { "srs_condition",      opt_stringptr,	LOFF(srs_condition) },
100
  { "srs_dbinsert",       opt_stringptr,	LOFF(srs_dbinsert) },
101
  { "srs_dbselect",       opt_stringptr,	LOFF(srs_dbselect) },
102
#endif
103
  { "syntax_errors_text", opt_stringptr,	LOFF(syntax_errors_text) },
96
  { "syntax_errors_text", opt_stringptr,	LOFF(syntax_errors_text) },
104
  { "syntax_errors_to",   opt_stringptr,	LOFF(syntax_errors_to) }
97
  { "syntax_errors_to",   opt_stringptr,	LOFF(syntax_errors_to) }
105
};
98
};
Lines 149-161 Link Here
149
  NULL,        /* qualify_domain */
142
  NULL,        /* qualify_domain */
150
  NULL,        /* owners */
143
  NULL,        /* owners */
151
  NULL,        /* owngroups */
144
  NULL,        /* owngroups */
152
#ifdef EXPERIMENTAL_SRS
153
  NULL,        /* srs */
154
  NULL,        /* srs_alias */
155
  NULL,        /* srs_condition */
156
  NULL,        /* srs_dbinsert */
157
  NULL,        /* srs_dbselect */
158
#endif
159
  022,         /* modemask */
145
  022,         /* modemask */
160
  RDO_REWRITE | RDO_PREPEND_HOME, /* bit_options */
146
  RDO_REWRITE | RDO_PREPEND_HOME, /* bit_options */
161
  FALSE,       /* check_ancestor */
147
  FALSE,       /* check_ancestor */
Lines 409-422 Link Here
409
    if (next->address[0] == '|')
395
    if (next->address[0] == '|')
410
      {
396
      {
411
      address_pipe = next->address;
397
      address_pipe = next->address;
412
      if (rf_get_transport(ob->pipe_transport_name, &(ob->pipe_transport),
398
      if (rf_get_transport(ob->pipe_transport_name, &ob->pipe_transport,
413
          next, rblock->name, US"pipe_transport"))
399
          next, rblock->name, US"pipe_transport"))
414
        next->transport = ob->pipe_transport;
400
        next->transport = ob->pipe_transport;
415
      address_pipe = NULL;
401
      address_pipe = NULL;
416
      }
402
      }
417
    else if (next->address[0] == '>')
403
    else if (next->address[0] == '>')
418
      {
404
      {
419
      if (rf_get_transport(ob->reply_transport_name, &(ob->reply_transport),
405
      if (rf_get_transport(ob->reply_transport_name, &ob->reply_transport,
420
          next, rblock->name, US"reply_transport"))
406
          next, rblock->name, US"reply_transport"))
421
        next->transport = ob->reply_transport;
407
        next->transport = ob->reply_transport;
422
      }
408
      }
Lines 432-442 Link Here
432
          next->transport = ob->directory_transport;
418
          next->transport = ob->directory_transport;
433
        }
419
        }
434
      else
420
      else
435
        {
421
        if (rf_get_transport(ob->file_transport_name, &ob->file_transport,
436
        if (rf_get_transport(ob->file_transport_name, &(ob->file_transport),
437
            next, rblock->name, US"file_transport"))
422
            next, rblock->name, US"file_transport"))
438
          next->transport = ob->file_transport;
423
          next->transport = ob->file_transport;
439
        }
424
440
      address_file = NULL;
425
      address_file = NULL;
441
      }
426
      }
442
    }
427
    }
Lines 529-537 Link Here
529
int frc = 0;
514
int frc = 0;
530
int xrc = 0;
515
int xrc = 0;
531
516
532
addr_local = addr_local;     /* Keep picky compilers happy */
533
addr_remote = addr_remote;
534
535
/* Initialize the data to be propagated to the children */
517
/* Initialize the data to be propagated to the children */
536
518
537
addr_prop.address_data = deliver_address_data;
519
addr_prop.address_data = deliver_address_data;
Lines 543-551 Link Here
543
addr_prop.variables = NULL;
525
addr_prop.variables = NULL;
544
tree_dup((tree_node **)&addr_prop.variables, addr->prop.variables);
526
tree_dup((tree_node **)&addr_prop.variables, addr->prop.variables);
545
527
546
#ifdef EXPERIMENTAL_SRS
547
addr_prop.srs_sender = NULL;
548
#endif
549
#ifdef SUPPORT_I18N
528
#ifdef SUPPORT_I18N
550
addr_prop.utf8_msg = addr->prop.utf8_msg;
529
addr_prop.utf8_msg = addr->prop.utf8_msg;
551
addr_prop.utf8_downcvt = addr->prop.utf8_downcvt;
530
addr_prop.utf8_downcvt = addr->prop.utf8_downcvt;
Lines 578-672 Link Here
578
  ugid.gid_set = TRUE;
557
  ugid.gid_set = TRUE;
579
  }
558
  }
580
559
581
#ifdef EXPERIMENTAL_SRS
582
  /* Perform SRS on recipient/return-path as required  */
583
584
  if(ob->srs != NULL)
585
  {
586
    BOOL usesrs = TRUE;
587
588
    if(ob->srs_condition != NULL)
589
      usesrs = expand_check_condition(ob->srs_condition, "srs_condition expansion failed", NULL);
590
591
    if(usesrs)
592
    {
593
      int srs_action = 0, n_srs;
594
      uschar *res;
595
      uschar *usedomain;
596
597
      /* What are we doing? */
598
      if(Ustrcmp(ob->srs, "forward") == 0)
599
        srs_action = 1;
600
      else if(Ustrcmp(ob->srs, "reverseandforward") == 0)
601
      {
602
        srs_action = 3;
603
604
        if((ob->srs_dbinsert == NULL) ^ (ob->srs_dbselect == NULL))
605
          return DEFER;
606
      }
607
      else if(Ustrcmp(ob->srs, "reverse") == 0)
608
        srs_action = 2;
609
610
      /* Reverse SRS */
611
      if(srs_action & 2)
612
      {
613
        srs_orig_recipient = addr->address;
614
615
        eximsrs_init();
616
        if(ob->srs_dbselect)
617
          eximsrs_db_set(TRUE, ob->srs_dbselect);
618
/* Comment this out for now...
619
//        else
620
//          eximsrs_db_set(TRUE, NULL);
621
*/
622
623
        if((n_srs = eximsrs_reverse(&res, addr->address)) == OK)
624
        {
625
          srs_recipient = res;
626
          DEBUG(D_any)
627
            debug_printf("SRS (reverse): Recipient '%s' rewritten to '%s'\n", srs_orig_recipient, srs_recipient);
628
        }
629
630
        eximsrs_done();
631
632
        if(n_srs != OK)
633
          return n_srs;
634
      }
635
636
      /* Forward SRS */
637
      /* No point in actually performing SRS if we are just verifying a recipient */
638
      if((srs_action & 1) && verify == v_none &&
639
         (sender_address ? sender_address[0] != 0 : FALSE))
640
      {
641
642
        srs_orig_sender = sender_address;
643
        eximsrs_init();
644
        if(ob->srs_dbinsert)
645
          eximsrs_db_set(FALSE, ob->srs_dbinsert);
646
/* Comment this out for now...
647
//        else
648
//          eximsrs_db_set(FALSE, NULL);
649
*/
650
651
        if (!(usedomain = ob->srs_alias ? expand_string(ob->srs_alias) : NULL))
652
          usedomain = string_copy(deliver_domain);
653
654
        if((n_srs = eximsrs_forward(&res, sender_address, usedomain)) == OK)
655
        {
656
          addr_prop.srs_sender = res;
657
          DEBUG(D_any)
658
            debug_printf("SRS (forward): Sender '%s' rewritten to '%s'\n", srs_orig_sender, res);
659
        }
660
661
        eximsrs_done();
662
663
        if(n_srs != OK)
664
          return n_srs;
665
      }
666
    }
667
  }
668
#endif
669
670
/* Call the function that interprets redirection data, either inline or from a
560
/* Call the function that interprets redirection data, either inline or from a
671
file. This is a separate function so that the system filter can use it. It will
561
file. This is a separate function so that the system filter can use it. It will
672
run the function in a subprocess if necessary. If qualify_preserve_domain is
562
run the function in a subprocess if necessary. If qualify_preserve_domain is
Lines 696-702 Link Here
696
frc = rda_interpret(&redirect, options, ob->include_directory,
586
frc = rda_interpret(&redirect, options, ob->include_directory,
697
  ob->sieve_vacation_directory, ob->sieve_enotify_mailto_owner,
587
  ob->sieve_vacation_directory, ob->sieve_enotify_mailto_owner,
698
  ob->sieve_useraddress, ob->sieve_subaddress, &ugid, &generated,
588
  ob->sieve_useraddress, ob->sieve_subaddress, &ugid, &generated,
699
  &(addr->message), ob->skip_syntax_errors? &eblock : NULL, &filtertype,
589
  &addr->message, ob->skip_syntax_errors? &eblock : NULL, &filtertype,
700
  string_sprintf("%s router (recipient is %s)", rblock->name, addr->address));
590
  string_sprintf("%s router (recipient is %s)", rblock->name, addr->address));
701
591
702
qualify_domain_recipient = save_qualify_domain_recipient;
592
qualify_domain_recipient = save_qualify_domain_recipient;
Lines 737-751 Link Here
737
      addr->message = yield == FAIL ? US"forced rejection" : US"forced defer";
627
      addr->message = yield == FAIL ? US"forced rejection" : US"forced defer";
738
    else
628
    else
739
      {
629
      {
740
      int ovector[3];
630
      uschar * matched;
741
      if (ob->forbid_smtp_code &&
631
      if (  ob->forbid_smtp_code
742
	  pcre_exec(regex_smtp_code, NULL, CS addr->message,
632
	 && regex_match(regex_smtp_code, addr->message, -1, &matched))
743
	    Ustrlen(addr->message), 0, PCRE_EOPT,
744
	    ovector, sizeof(ovector)/sizeof(int)) >= 0)
745
	{
633
	{
746
	DEBUG(D_route) debug_printf("SMTP code at start of error message "
634
	DEBUG(D_route) debug_printf("SMTP code at start of error message "
747
	  "is ignored because forbid_smtp_code is set\n");
635
	  "is ignored because forbid_smtp_code is set\n");
748
	addr->message += ovector[1];
636
	addr->message += Ustrlen(matched);
749
	}
637
	}
750
      addr->user_message = addr->message;
638
      addr->user_message = addr->message;
751
      setflag(addr, af_pass_message);
639
      setflag(addr, af_pass_message);
Lines 787-793 Link Here
787
675
788
    if (filtertype != FILTER_FORWARD && ob->skip_syntax_errors)
676
    if (filtertype != FILTER_FORWARD && ob->skip_syntax_errors)
789
      {
677
      {
790
      eblock = store_get(sizeof(error_block), FALSE);
678
      eblock = store_get(sizeof(error_block), GET_UNTAINTED);
791
      eblock->next = NULL;
679
      eblock->next = NULL;
792
      eblock->text1 = addr->message;
680
      eblock->text1 = addr->message;
793
      eblock->text2 = NULL;
681
      eblock->text2 = NULL;
(-)exim.orig/src/routers/redirect.h (-8 / +1 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2021 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2009 */
6
/* Copyright (c) University of Cambridge 1995 - 2009 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 34-47 Link Here
34
  uid_t  *owners;
35
  uid_t  *owners;
35
  gid_t  *owngroups;
36
  gid_t  *owngroups;
36
37
37
#ifdef EXPERIMENTAL_SRS
38
  uschar *srs;
39
  uschar *srs_alias;
40
  uschar *srs_condition;
41
  uschar *srs_dbinsert;
42
  uschar *srs_dbselect;
43
#endif
44
45
  int   modemask;
38
  int   modemask;
46
  int   bit_options;
39
  int   bit_options;
47
  BOOL  check_ancestor;
40
  BOOL  check_ancestor;
(-)exim.orig/src/routers/rf_change_domain.c (-3 / +4 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 35-43 Link Here
35
rf_change_domain(address_item *addr, const uschar *domain, BOOL rewrite,
36
rf_change_domain(address_item *addr, const uschar *domain, BOOL rewrite,
36
  address_item **addr_new)
37
  address_item **addr_new)
37
{
38
{
38
address_item *parent = store_get(sizeof(address_item), FALSE);
39
address_item * parent = store_get(sizeof(address_item), GET_UNTAINTED);
39
uschar *at = Ustrrchr(addr->address, '@');
40
uschar * at = Ustrrchr(addr->address, '@');
40
uschar *address = string_sprintf("%.*s@%s",
41
uschar * address = string_sprintf("%.*s@%s",
41
  (int)(at - addr->address), addr->address, domain);
42
  (int)(at - addr->address), addr->address, domain);
42
43
43
DEBUG(D_route) debug_printf("domain changed to %s\n", domain);
44
DEBUG(D_route) debug_printf("domain changed to %s\n", domain);
(-)exim.orig/src/routers/rf_get_munge_headers.c (-8 / +9 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2021 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 38-54 Link Here
38
  {
39
  {
39
  const uschar * list = rblock->extra_headers;
40
  const uschar * list = rblock->extra_headers;
40
  int sep = '\n';
41
  int sep = '\n';
41
  uschar * s;
42
  uschar * s, * t;
42
  int slen;
43
  int slen;
43
44
44
  while ((s = string_nextinlist(&list, &sep, NULL, 0)))
45
  while ((s = string_nextinlist(&list, &sep, NULL, 0)))
45
    if (!(s = expand_string(s)))
46
    if (!(s = expand_string(t = s)))
46
      {
47
      {
47
      if (!f.expand_string_forcedfail)
48
      if (!f.expand_string_forcedfail)
48
	{
49
	{
49
	addr->message = string_sprintf(
50
	addr->message = string_sprintf(
50
	  "%s router failed to expand add_headers item \"%s\": %s",
51
	  "%s router failed to expand add_headers item \"%s\": %s",
51
	  rblock->name, s, expand_string_message);
52
	  rblock->name, t, expand_string_message);
52
	return DEFER;
53
	return DEFER;
53
	}
54
	}
54
      }
55
      }
Lines 59-65 Link Here
59
      shared with other addresses. The output function outputs them in reverse
60
      shared with other addresses. The output function outputs them in reverse
60
      order. */
61
      order. */
61
62
62
      header_line *  h = store_get(sizeof(header_line), FALSE);
63
      header_line *  h = store_get(sizeof(header_line), GET_UNTAINTED);
63
64
64
      /* We used to use string_sprintf() to add the newline if needed, but that
65
      /* We used to use string_sprintf() to add the newline if needed, but that
65
      causes problems if the header line is exceedingly long (e.g. adding
66
      causes problems if the header line is exceedingly long (e.g. adding
Lines 69-75 Link Here
69
	h->text = s;
70
	h->text = s;
70
      else
71
      else
71
	{
72
	{
72
	h->text = store_get(slen+2, is_tainted(s));
73
	h->text = store_get(slen+2, s);
73
	memcpy(h->text, s, slen);
74
	memcpy(h->text, s, slen);
74
	h->text[slen++] = '\n';
75
	h->text[slen++] = '\n';
75
	h->text[slen] = 0;
76
	h->text[slen] = 0;
Lines 90-109 Link Here
90
  {
91
  {
91
  const uschar * list = rblock->remove_headers;
92
  const uschar * list = rblock->remove_headers;
92
  int sep = ':';
93
  int sep = ':';
93
  uschar * s;
94
  uschar * s, * t;
94
  gstring * g = NULL;
95
  gstring * g = NULL;
95
96
96
  if (*remove_headers)
97
  if (*remove_headers)
97
    g = string_cat(NULL, *remove_headers);
98
    g = string_cat(NULL, *remove_headers);
98
99
99
  while ((s = string_nextinlist(&list, &sep, NULL, 0)))
100
  while ((s = string_nextinlist(&list, &sep, NULL, 0)))
100
    if (!(s = expand_string(s)))
101
    if (!(s = expand_string(t = s)))
101
      {
102
      {
102
      if (!f.expand_string_forcedfail)
103
      if (!f.expand_string_forcedfail)
103
	{
104
	{
104
	addr->message = string_sprintf(
105
	addr->message = string_sprintf(
105
	  "%s router failed to expand remove_headers item \"%s\": %s",
106
	  "%s router failed to expand remove_headers item \"%s\": %s",
106
	  rblock->name, s, expand_string_message);
107
	  rblock->name, t, expand_string_message);
107
	return DEFER;
108
	return DEFER;
108
	}
109
	}
109
      }
110
      }
(-)exim.orig/src/routers/rf_get_transport.c (+1 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2021 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2009 */
6
/* Copyright (c) University of Cambridge 1995 - 2009 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
(-)exim.orig/src/routers/rf_queue_add.c (+1 lines)
Lines 3-8 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2021 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
8
#include "../exim.h"
9
#include "../exim.h"
(-)exim.orig/src/search.c (-36 / +142 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2015 */
6
/* 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. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* A set of functions to search databases in various formats. An open
9
/* A set of functions to search databases in various formats. An open
Lines 63-73 Link Here
63
*/
63
*/
64
64
65
int
65
int
66
search_findtype(const uschar *name, int len)
66
search_findtype(const uschar * name, int len)
67
{
67
{
68
int bot = 0;
68
for (int bot = 0, top = lookup_list_count; top > bot; )
69
int top = lookup_list_count;
70
while (top > bot)
71
  {
69
  {
72
  int mid = (top + bot)/2;
70
  int mid = (top + bot)/2;
73
  int c = Ustrncmp(name, lookup_list[mid]->name, len);
71
  int c = Ustrncmp(name, lookup_list[mid]->name, len);
Lines 92-98 Link Here
92
  if (c > 0) bot = mid + 1; else top = mid;
90
  if (c > 0) bot = mid + 1; else top = mid;
93
  }
91
  }
94
92
95
search_error_message = string_sprintf("unknown lookup type \"%.*s\"",len,name);
93
search_error_message = string_sprintf("unknown lookup type \"%.*s\"", len, name);
96
return -1;
94
return -1;
97
}
95
}
98
96
Lines 217-222 Link Here
217
}
215
}
218
216
219
217
218
/* Set the parameters for the three different kinds of lookup.
219
Arguments:
220
 search_type	the search-type code
221
 search		the search-type string
222
 query		argument for the search; filename or query
223
 fnamep		pointer to return filename
224
 opts		options
225
226
Return:	keyquery	the search-type (for single-key) or query (for query-type)
227
 */
228
uschar *
229
search_args(int search_type, uschar * search, uschar * query, uschar ** fnamep,
230
  const uschar * opts)
231
{
232
Uskip_whitespace(&query);
233
if (mac_islookup(search_type, lookup_absfilequery))
234
  {					/* query-style but with file (sqlite) */
235
  int sep = ',';
236
237
  /* Check options first for new-style file spec */
238
  if (opts) for (uschar * s; s = string_nextinlist(&opts, &sep, NULL, 0); )
239
    if (Ustrncmp(s, "file=", 5) == 0)
240
      {
241
      *fnamep = s+5;
242
      return query;
243
      }
244
245
  /* If no filename from options, use old-tyle space-sep prefix on query */
246
  if (*query == '/')
247
    {
248
    uschar * s = query;
249
    while (*query && !isspace(*query)) query++;
250
    *fnamep = string_copyn(s, query - s);
251
    Uskip_whitespace(&query);
252
    }
253
  else
254
    *fnamep = NULL;
255
  return query;		/* remainder after file skipped */
256
  }
257
if (!mac_islookup(search_type, lookup_querystyle))
258
  {					/* single-key */
259
  *fnamep = query;
260
  return search;	/* modifiers important so use "keyquery" for them */
261
  }
262
*fnamep = NULL;				/* else query-style */
263
return query;
264
}
265
266
220
267
221
/*************************************************
268
/*************************************************
222
*               Release cached resources         *
269
*               Release cached resources         *
Lines 429-436 Link Here
429
476
430
if (!t)
477
if (!t)
431
  {
478
  {
432
  t = store_get(sizeof(tree_node) + Ustrlen(keybuffer), FALSE);
479
  t = store_get(sizeof(tree_node) + Ustrlen(keybuffer), GET_UNTAINTED);
433
  t->data.ptr = c = store_get(sizeof(search_cache), FALSE);
480
  t->data.ptr = c = store_get(sizeof(search_cache), GET_UNTAINTED);
434
  c->item_cache = NULL;
481
  c->item_cache = NULL;
435
  Ustrcpy(t->name, keybuffer);
482
  Ustrcpy(t->name, keybuffer);
436
  tree_insertnode(&search_tree, t);
483
  tree_insertnode(&search_tree, t);
Lines 462-467 Link Here
462
               NULL for query-style searches
509
               NULL for query-style searches
463
  keystring    the keystring for single-key+file lookups, or
510
  keystring    the keystring for single-key+file lookups, or
464
               the querystring for query-style lookups
511
               the querystring for query-style lookups
512
  cache_rd     FALSE to avoid lookup in cache layer
465
  opts	       type-specific options
513
  opts	       type-specific options
466
514
467
Returns:       a pointer to a dynamic string containing the answer,
515
Returns:       a pointer to a dynamic string containing the answer,
Lines 472-478 Link Here
472
520
473
static uschar *
521
static uschar *
474
internal_search_find(void * handle, const uschar * filename, uschar * keystring,
522
internal_search_find(void * handle, const uschar * filename, uschar * keystring,
475
  const uschar * opts)
523
  BOOL cache_rd, const uschar * opts)
476
{
524
{
477
tree_node * t = (tree_node *)handle;
525
tree_node * t = (tree_node *)handle;
478
search_cache * c = (search_cache *)(t->data.ptr);
526
search_cache * c = (search_cache *)(t->data.ptr);
Lines 501-511 Link Here
501
store_pool = POOL_SEARCH;
549
store_pool = POOL_SEARCH;
502
550
503
/* Look up the data for the key, unless it is already in the cache for this
551
/* Look up the data for the key, unless it is already in the cache for this
504
file. No need to check c->item_cache for NULL, tree_search will do so. */
552
file. No need to check c->item_cache for NULL, tree_search will do so. Check
553
whether we want to use the cache entry last so that we can always replace it. */
505
554
506
if (  (t = tree_search(c->item_cache, keystring))
555
if (  (t = tree_search(c->item_cache, keystring))
507
   && (!(e = t->data.ptr)->expiry || e->expiry > time(NULL))
556
   && (!(e = t->data.ptr)->expiry || e->expiry > time(NULL))
508
   && (!opts && !e->opts  ||  opts && e->opts && Ustrcmp(opts, e->opts) == 0)
557
   && (!opts && !e->opts  ||  opts && e->opts && Ustrcmp(opts, e->opts) == 0)
558
   && cache_rd
509
   )
559
   )
510
  { /* Data was in the cache already; set the pointer from the tree node */
560
  { /* Data was in the cache already; set the pointer from the tree node */
511
  data = e->data.ptr;
561
  data = e->data.ptr;
Lines 522-532 Link Here
522
    {
572
    {
523
    if (t)
573
    if (t)
524
      debug_printf_indent("cached data found but %s; ",
574
      debug_printf_indent("cached data found but %s; ",
525
	e->expiry && e->expiry <= time(NULL) ? "out-of-date" : "wrong opts");
575
	e->expiry && e->expiry <= time(NULL) ? "out-of-date"
576
	: cache_rd ? "wrong opts" : "no_rd option set");
526
    debug_printf_indent("%s lookup required for %s%s%s\n",
577
    debug_printf_indent("%s lookup required for %s%s%s\n",
527
      filename ? US"file" : US"database",
578
      filename ? US"file" : US"database",
528
      keystring,
579
      keystring,
529
      filename ? US"\n  in " : US"", filename ? filename : US"");
580
      filename ? US"\n  in " : US"", filename ? filename : US"");
581
    if (!filename && is_tainted(keystring))
582
      {
583
      debug_printf_indent("                             ");
584
      debug_print_taint(keystring);
585
      }
586
    }
587
588
  /* Check that the query, for query-style lookups,
589
  is either untainted or properly quoted for the lookup type.
590
591
  XXX Should we this move into lf_sqlperform() ?  The server-taint check is there.
592
  */
593
594
  if (  !filename && lookup_list[search_type]->quote
595
     && is_tainted(keystring) && !is_quoted_like(keystring, search_type))
596
    {
597
    uschar * s = acl_current_verb();
598
    if (!s) s = authenticator_current_name();	/* must be before transport */
599
    if (!s) s = transport_current_name();	/* must be before router */
600
    if (!s) s = router_current_name();	/* GCC ?: would be good, but not in clang */
601
    if (!s) s = US"";
602
#ifdef enforce_quote_protection_notyet
603
    search_error_message = string_sprintf(
604
      "tainted search query is not properly quoted%s: %s%s",
605
      s, keystring);
606
    f.search_find_defer = TRUE;
607
#else
608
     {
609
      int q = quoter_for_address(keystring);
610
      /* If we're called from a transport, no privs to open the paniclog;
611
      the logging punts to using stderr - and that seems to stop the debug
612
      stream. */
613
      log_write(0,
614
	transport_name ? LOG_MAIN : LOG_MAIN|LOG_PANIC,
615
	"tainted search query is not properly quoted%s: %s", s, keystring);
616
617
      DEBUG(D_lookup) debug_printf_indent("search_type %d (%s) quoting %d (%s)\n",
618
	search_type, lookup_list[search_type]->name,
619
	q, is_real_quoter(q) ? lookup_list[q]->name : US"none");
620
     }
621
#endif
530
    }
622
    }
531
623
532
  /* Call the code for the different kinds of search. DEFER is handled
624
  /* Call the code for the different kinds of search. DEFER is handled
Lines 534-554 Link Here
534
  distinguish if necessary. */
626
  distinguish if necessary. */
535
627
536
  if (lookup_list[search_type]->find(c->handle, filename, keystring, keylength,
628
  if (lookup_list[search_type]->find(c->handle, filename, keystring, keylength,
537
      &data, &search_error_message, &do_cache, opts) == DEFER)
629
	  &data, &search_error_message, &do_cache, opts) == DEFER)
538
    f.search_find_defer = TRUE;
630
    f.search_find_defer = TRUE;
539
631
540
  /* A record that has been found is now in data, which is either NULL
632
  /* A record that has been found is now in data, which is either NULL
541
  or points to a bit of dynamic store. Cache the result of the lookup if
633
  or points to a bit of dynamic store. Cache the result of the lookup if
542
  caching is permitted. Lookups can disable caching, when they did something
634
  caching is permitted. Lookups can disable caching, when they did something
543
  that changes their data. The mysql and pgsql lookups do this when an
635
  that changes their data. The mysql and pgsql lookups do this when an
544
  UPDATE/INSERT query was executed. */
636
  UPDATE/INSERT query was executed.  Lookups can also set a TTL for the
637
  cache entry; the dnsdb lookup does.
638
  Finally, the caller can request no caching by setting an option. */
545
639
546
  else if (do_cache)
640
  else if (do_cache)
547
    {
641
    {
642
    DEBUG(D_lookup) debug_printf_indent("%s cache entry\n",
643
      t ? "replacing old" : "creating new");
548
    if (!t)	/* No existing entry.  Create new one. */
644
    if (!t)	/* No existing entry.  Create new one. */
549
      {
645
      {
550
      int len = keylength + 1;
646
      int len = keylength + 1;
551
      e = store_get(sizeof(expiring_data) + sizeof(tree_node) + len, is_tainted(keystring));
647
      /* The cache node value should never be expanded so use tainted mem */
648
      e = store_get(sizeof(expiring_data) + sizeof(tree_node) + len, GET_TAINTED);
552
      t = (tree_node *)(e+1);
649
      t = (tree_node *)(e+1);
553
      memcpy(t->name, keystring, len);
650
      memcpy(t->name, keystring, len);
554
      t->data.ptr = e;
651
      t->data.ptr = e;
Lines 561-568 Link Here
561
    e->data.ptr = data;
658
    e->data.ptr = data;
562
    }
659
    }
563
660
564
  /* If caching was disabled, empty the cache tree. We just set the cache
661
/* If caching was disabled, empty the cache tree. We just set the cache
565
  pointer to NULL here, because we cannot release the store at this stage. */
662
pointer to NULL here, because we cannot release the store at this stage. */
566
663
567
  else
664
  else
568
    {
665
    {
Lines 621-629 Link Here
621
  int partial, const uschar * affix, int affixlen, int starflags,
718
  int partial, const uschar * affix, int affixlen, int starflags,
622
  int * expand_setup, const uschar * opts)
719
  int * expand_setup, const uschar * opts)
623
{
720
{
624
tree_node *t = (tree_node *)handle;
721
tree_node * t = (tree_node *)handle;
625
BOOL set_null_wild = FALSE;
722
BOOL set_null_wild = FALSE, cache_rd = TRUE, ret_key = FALSE;
626
uschar *yield;
723
uschar * yield;
627
724
628
DEBUG(D_lookup)
725
DEBUG(D_lookup)
629
  {
726
  {
Lines 636-641 Link Here
636
733
637
  }
734
  }
638
735
736
/* Parse global lookup options. Also, create a new options list with
737
the global options dropped so that the cache-modifiers are not
738
used in the cache key. */
739
740
if (opts)
741
  {
742
  int sep = ',';
743
  gstring * g = NULL;
744
745
  for (uschar * ele; ele = string_nextinlist(&opts, &sep, NULL, 0); )
746
    if (Ustrcmp(ele, "ret=key") == 0) ret_key = TRUE;
747
    else if (Ustrcmp(ele, "cache=no_rd") == 0) cache_rd = FALSE;
748
    else g = string_append_listele(g, ',', ele);
749
750
  opts = string_from_gstring(g);
751
  }
752
639
/* Arrange to put this database at the top of the LRU chain if it is a type
753
/* Arrange to put this database at the top of the LRU chain if it is a type
640
that opens real files. */
754
that opens real files. */
641
755
Lines 683-689 Link Here
683
/* First of all, try to match the key string verbatim. If matched a complete
797
/* First of all, try to match the key string verbatim. If matched a complete
684
entry but could have been partial, flag to set up variables. */
798
entry but could have been partial, flag to set up variables. */
685
799
686
yield = internal_search_find(handle, filename, keystring, opts);
800
yield = internal_search_find(handle, filename, keystring, cache_rd, opts);
687
if (f.search_find_defer) return NULL;
801
if (f.search_find_defer) return NULL;
688
802
689
if (yield) { if (partial >= 0) set_null_wild = TRUE; }
803
if (yield) { if (partial >= 0) set_null_wild = TRUE; }
Lines 704-714 Link Here
704
  if (affixlen == 0) keystring2 = keystring; else
818
  if (affixlen == 0) keystring2 = keystring; else
705
    {
819
    {
706
    keystring2 = store_get(len + affixlen + 1,
820
    keystring2 = store_get(len + affixlen + 1,
707
			is_tainted(keystring) || is_tainted(affix));
821
	  is_tainted(keystring) || is_tainted(affix) ? GET_TAINTED : GET_UNTAINTED);
708
    Ustrncpy(keystring2, affix, affixlen);
822
    Ustrncpy(keystring2, affix, affixlen);
709
    Ustrcpy(keystring2 + affixlen, keystring);
823
    Ustrcpy(keystring2 + affixlen, keystring);
710
    DEBUG(D_lookup) debug_printf_indent("trying partial match %s\n", keystring2);
824
    DEBUG(D_lookup) debug_printf_indent("trying partial match %s\n", keystring2);
711
    yield = internal_search_find(handle, filename, keystring2, opts);
825
    yield = internal_search_find(handle, filename, keystring2, cache_rd, opts);
712
    if (f.search_find_defer) return NULL;
826
    if (f.search_find_defer) return NULL;
713
    }
827
    }
714
828
Lines 746-752 Link Here
746
        }
860
        }
747
861
748
      DEBUG(D_lookup) debug_printf_indent("trying partial match %s\n", keystring3);
862
      DEBUG(D_lookup) debug_printf_indent("trying partial match %s\n", keystring3);
749
      yield = internal_search_find(handle, filename, keystring3, opts);
863
      yield = internal_search_find(handle, filename, keystring3,
864
		cache_rd, opts);
750
      if (f.search_find_defer) return NULL;
865
      if (f.search_find_defer) return NULL;
751
      if (yield)
866
      if (yield)
752
        {
867
        {
Lines 787-793 Link Here
787
    *atat = '*';
902
    *atat = '*';
788
903
789
    DEBUG(D_lookup) debug_printf_indent("trying default match %s\n", atat);
904
    DEBUG(D_lookup) debug_printf_indent("trying default match %s\n", atat);
790
    yield = internal_search_find(handle, filename, atat, opts);
905
    yield = internal_search_find(handle, filename, atat, cache_rd, opts);
791
    *atat = savechar;
906
    *atat = savechar;
792
    if (f.search_find_defer) return NULL;
907
    if (f.search_find_defer) return NULL;
793
908
Lines 810-816 Link Here
810
if (!yield  &&  starflags & (SEARCH_STAR|SEARCH_STARAT))
925
if (!yield  &&  starflags & (SEARCH_STAR|SEARCH_STARAT))
811
  {
926
  {
812
  DEBUG(D_lookup) debug_printf_indent("trying to match *\n");
927
  DEBUG(D_lookup) debug_printf_indent("trying to match *\n");
813
  yield = internal_search_find(handle, filename, US"*", opts);
928
  yield = internal_search_find(handle, filename, US"*", cache_rd, opts);
814
  if (yield && expand_setup && *expand_setup >= 0)
929
  if (yield && expand_setup && *expand_setup >= 0)
815
    {
930
    {
816
    *expand_setup += 1;
931
    *expand_setup += 1;
Lines 843-859 Link Here
843
than the result.  Return a de-tainted version of the key on the grounds that
958
than the result.  Return a de-tainted version of the key on the grounds that
844
it have been validated by the lookup. */
959
it have been validated by the lookup. */
845
960
846
if (yield && opts)
961
if (yield && ret_key)
847
  {
962
  yield = string_copy_taint(keystring, GET_UNTAINTED);
848
  int sep = ',';
849
  for (uschar * ele; ele = string_nextinlist(&opts, &sep, NULL, 0); )
850
    if (Ustrcmp(ele, "ret=key") == 0)
851
      {
852
      DEBUG(D_lookup) debug_printf_indent("lookup ret=key: %s\n", keystring);
853
      yield = string_copy_taint(keystring, FALSE);
854
      break;
855
      }
856
  }
857
963
858
return yield;
964
return yield;
859
}
965
}
(-)exim.orig/src/sieve.c (-57 / +48 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) Michael Haardt 2003 - 2015
5
/*
6
 * Copyright (c) The Exim Maintainers 2016 - 2020
6
 * Copyright (c) The Exim Maintainers 2016 - 2022
7
 * Copyright (c) Michael Haardt 2003 - 2015
7
 * See the file NOTICE for conditions of use and distribution.
8
 * See the file NOTICE for conditions of use and distribution.
8
 */
9
 */
9
10
Lines 54-60 Link Here
54
55
55
struct Sieve
56
struct Sieve
56
  {
57
  {
57
  uschar *filter;
58
  const uschar *filter;
58
  const uschar *pc;
59
  const uschar *pc;
59
  int line;
60
  int line;
60
  const uschar *errmsg;
61
  const uschar *errmsg;
Lines 71-77 Link Here
71
  int require_enotify;
72
  int require_enotify;
72
  struct Notification *notified;
73
  struct Notification *notified;
73
#endif
74
#endif
74
  uschar *enotify_mailto_owner;
75
  const uschar *enotify_mailto_owner;
75
#ifdef SUBADDRESS
76
#ifdef SUBADDRESS
76
  int require_subaddress;
77
  int require_subaddress;
77
#endif
78
#endif
Lines 79-85 Link Here
79
  int require_vacation;
80
  int require_vacation;
80
  int vacation_ran;
81
  int vacation_ran;
81
#endif
82
#endif
82
  uschar *vacation_directory;
83
  const uschar *vacation_directory;
83
  const uschar *subaddress;
84
  const uschar *subaddress;
84
  const uschar *useraddress;
85
  const uschar *useraddress;
85
  int require_copy;
86
  int require_copy;
Lines 245-251 Link Here
245
    dst->length=0;
246
    dst->length=0;
246
  else
247
  else
247
    {
248
    {
248
    dst->character = store_get(dst->length+1, is_tainted(src->character)); /* plus one for \0 */
249
    dst->character = store_get(dst->length+1, src->character); /* plus one for \0 */
249
    new=dst->character;
250
    new=dst->character;
250
    }
251
    }
251
  for (const uschar * start = src->character, * end = start + src->length;
252
  for (const uschar * start = src->character, * end = start + src->length;
Lines 444-459 Link Here
444
        filter->errmsg=US"Invalid URI encoding";
445
        filter->errmsg=US"Invalid URI encoding";
445
        return -1;
446
        return -1;
446
        }
447
        }
447
      new=store_get(sizeof(string_item), FALSE);
448
      new = store_get(sizeof(string_item), GET_UNTAINTED);
448
      new->text = store_get(to.length+1, is_tainted(to.character));
449
      new->text = store_get(to.length+1, to.character);
449
      if (to.length) memcpy(new->text, to.character, to.length);
450
      if (to.length) memcpy(new->text, to.character, to.length);
450
      new->text[to.length]='\0';
451
      new->text[to.length] = '\0';
451
      new->next=*recipient;
452
      new->next = *recipient;
452
      *recipient=new;
453
      *recipient = new;
453
      }
454
      }
454
    else
455
    else
455
      {
456
      {
456
      filter->errmsg=US"Missing addr-spec in URI";
457
      filter->errmsg = US"Missing addr-spec in URI";
457
      return -1;
458
      return -1;
458
      }
459
      }
459
    if (*uri=='%') uri+=3;
460
    if (*uri=='%') uri+=3;
Lines 502-509 Link Here
502
      }
503
      }
503
    if (hname.length==2 && strcmpic(hname.character, US"to")==0)
504
    if (hname.length==2 && strcmpic(hname.character, US"to")==0)
504
      {
505
      {
505
      new=store_get(sizeof(string_item), FALSE);
506
      new=store_get(sizeof(string_item), GET_UNTAINTED);
506
      new->text = store_get(hvalue.length+1, is_tainted(hvalue.character));
507
      new->text = store_get(hvalue.length+1, hvalue.character);
507
      if (hvalue.length) memcpy(new->text, hvalue.character, hvalue.length);
508
      if (hvalue.length) memcpy(new->text, hvalue.character, hvalue.length);
508
      new->text[hvalue.length]='\0';
509
      new->text[hvalue.length]='\0';
509
      new->next=*recipient;
510
      new->next=*recipient;
Lines 1729-1735 Link Here
1729
      struct String *new;
1730
      struct String *new;
1730
1731
1731
      dataCapacity = dataCapacity ? dataCapacity * 2 : 4;
1732
      dataCapacity = dataCapacity ? dataCapacity * 2 : 4;
1732
      new = store_get(sizeof(struct String) * dataCapacity, FALSE);
1733
      new = store_get(sizeof(struct String) * dataCapacity, GET_UNTAINTED);
1733
1734
1734
      if (d) memcpy(new,d,sizeof(struct String)*dataLength);
1735
      if (d) memcpy(new,d,sizeof(struct String)*dataLength);
1735
      d = new;
1736
      d = new;
Lines 1767-1773 Link Here
1767
  }
1768
  }
1768
else /* single string */
1769
else /* single string */
1769
  {
1770
  {
1770
  if (!(d=store_get(sizeof(struct String)*2, FALSE)))
1771
  if (!(d=store_get(sizeof(struct String)*2, GET_UNTAINTED)))
1771
    return -1;
1772
    return -1;
1772
1773
1773
  m=parse_string(filter,&d[0]);
1774
  m=parse_string(filter,&d[0]);
Lines 3073-3079 Link Here
3073
        if (!already)
3074
        if (!already)
3074
          /* New notification, process it */
3075
          /* New notification, process it */
3075
          {
3076
          {
3076
          struct Notification * sent = store_get(sizeof(struct Notification), FALSE);
3077
          struct Notification * sent = store_get(sizeof(struct Notification), GET_UNTAINTED);
3077
          sent->method=method;
3078
          sent->method=method;
3078
          sent->importance=importance;
3079
          sent->importance=importance;
3079
          sent->message=message;
3080
          sent->message=message;
Lines 3093-3101 Link Here
3093
		? expand_string(US"$local_part_prefix$local_part$local_part_suffix@$domain")
3094
		? expand_string(US"$local_part_prefix$local_part$local_part_suffix@$domain")
3094
		: from.character);
3095
		: from.character);
3095
              for (string_item * p = recipient; p; p=p->next)
3096
              for (string_item * p = recipient; p; p=p->next)
3096
	       	fprintf(f,"To: %s\n",p->text);
3097
	       	fprintf(f, "To: %s\n",p->text);
3097
              fprintf(f,"Auto-Submitted: auto-notified; %s\n",filter->enotify_mailto_owner);
3098
              fprintf(f, "Auto-Submitted: auto-notified; %s\n", filter->enotify_mailto_owner);
3098
              if (header.length>0) fprintf(f,"%s",header.character);
3099
              if (header.length > 0) fprintf(f, "%s", header.character);
3099
              if (message.length==-1)
3100
              if (message.length==-1)
3100
                {
3101
                {
3101
                message.character=US"Notification";
3102
                message.character=US"Notification";
Lines 3105-3111 Link Here
3105
		fprintf(f, "Subject: %s\n", parse_quote_2047(message.character,
3106
		fprintf(f, "Subject: %s\n", parse_quote_2047(message.character,
3106
		  message.length, US"utf-8", TRUE));
3107
		  message.length, US"utf-8", TRUE));
3107
              fprintf(f,"\n");
3108
              fprintf(f,"\n");
3108
              if (body.length>0) fprintf(f,"%s\n",body.character);
3109
              if (body.length > 0) fprintf(f, "%s\n", body.character);
3109
              fflush(f);
3110
              fflush(f);
3110
              (void)fclose(f);
3111
              (void)fclose(f);
3111
              (void)child_close(pid, 0);
3112
              (void)child_close(pid, 0);
Lines 3212-3220 Link Here
3212
          }
3213
          }
3213
        for (struct String * a = addresses; a->length != -1; ++a)
3214
        for (struct String * a = addresses; a->length != -1; ++a)
3214
          {
3215
          {
3215
          string_item * new = store_get(sizeof(string_item), FALSE);
3216
          string_item * new = store_get(sizeof(string_item), GET_UNTAINTED);
3216
3217
3217
          new->text = store_get(a->length+1, is_tainted(a->character));
3218
          new->text = store_get(a->length+1, a->character);
3218
          if (a->length) memcpy(new->text,a->character,a->length);
3219
          if (a->length) memcpy(new->text,a->character,a->length);
3219
          new->text[a->length]='\0';
3220
          new->text[a->length]='\0';
3220
          new->next=aliases;
3221
          new->next=aliases;
Lines 3327-3333 Link Here
3327
          addr->prop.ignore_error = TRUE;
3328
          addr->prop.ignore_error = TRUE;
3328
          addr->next = *generated;
3329
          addr->next = *generated;
3329
          *generated = addr;
3330
          *generated = addr;
3330
          addr->reply = store_get(sizeof(reply_item), FALSE);
3331
          addr->reply = store_get(sizeof(reply_item), GET_UNTAINTED);
3331
          memset(addr->reply,0,sizeof(reply_item)); /* XXX */
3332
          memset(addr->reply,0,sizeof(reply_item)); /* XXX */
3332
          addr->reply->to = string_copy(sender_address);
3333
          addr->reply->to = string_copy(sender_address);
3333
          if (from.length==-1)
3334
          if (from.length==-1)
Lines 3425-3431 Link Here
3425
3426
3426
if (parse_white(filter)==-1) return -1;
3427
if (parse_white(filter)==-1) return -1;
3427
3428
3428
if (exec && filter->vacation_directory != NULL && filter_test == FTEST_NONE)
3429
if (exec && filter->vacation_directory && filter_test == FTEST_NONE)
3429
  {
3430
  {
3430
  DIR *oncelogdir;
3431
  DIR *oncelogdir;
3431
  struct dirent *oncelog;
3432
  struct dirent *oncelog;
Lines 3448-3455 Link Here
3448
    while ((oncelog = readdir(oncelogdir)))
3449
    while ((oncelog = readdir(oncelogdir)))
3449
      if (strlen(oncelog->d_name)==32)
3450
      if (strlen(oncelog->d_name)==32)
3450
        {
3451
        {
3451
        uschar *s = string_sprintf("%s/%s",filter->vacation_directory,oncelog->d_name);
3452
        uschar *s = string_sprintf("%s/%s", filter->vacation_directory, oncelog->d_name);
3452
        if (Ustat(s,&properties)==0 && (properties.st_mtime+VACATION_MAX_DAYS*86400)<now)
3453
        if (Ustat(s,&properties) == 0 && properties.st_mtime+VACATION_MAX_DAYS*86400 < now)
3453
          Uunlink(s);
3454
          Uunlink(s);
3454
        }
3455
        }
3455
    closedir(oncelogdir);
3456
    closedir(oncelogdir);
Lines 3484-3490 Link Here
3484
#ifdef ENOTIFY
3485
#ifdef ENOTIFY
3485
    else if (eq_octet(check,&str_enotify,0))
3486
    else if (eq_octet(check,&str_enotify,0))
3486
      {
3487
      {
3487
      if (filter->enotify_mailto_owner == NULL)
3488
      if (!filter->enotify_mailto_owner)
3488
        {
3489
        {
3489
        filter->errmsg=CUS "enotify disabled";
3490
        filter->errmsg=CUS "enotify disabled";
3490
        return -1;
3491
        return -1;
Lines 3498-3504 Link Here
3498
#ifdef VACATION
3499
#ifdef VACATION
3499
    else if (eq_octet(check,&str_vacation,0))
3500
    else if (eq_octet(check,&str_vacation,0))
3500
      {
3501
      {
3501
      if (filter_test == FTEST_NONE && filter->vacation_directory == NULL)
3502
      if (filter_test == FTEST_NONE && !filter->vacation_directory)
3502
        {
3503
        {
3503
        filter->errmsg=CUS "vacation disabled";
3504
        filter->errmsg=CUS "vacation disabled";
3504
        return -1;
3505
        return -1;
Lines 3554-3597 Link Here
3554
*/
3555
*/
3555
3556
3556
int
3557
int
3557
sieve_interpret(uschar *filter, int options, uschar *vacation_directory,
3558
sieve_interpret(const uschar * filter, int options,
3558
  uschar *enotify_mailto_owner, uschar *useraddress, uschar *subaddress,
3559
  const uschar * vacation_directory, const uschar * enotify_mailto_owner,
3559
  address_item **generated, uschar **error)
3560
  const uschar * useraddress, const uschar * subaddress,
3561
  address_item ** generated, uschar ** error)
3560
{
3562
{
3561
struct Sieve sieve;
3563
struct Sieve sieve;
3562
int r;
3564
int r;
3563
uschar *msg;
3565
uschar * msg;
3564
3565
options = options; /* Keep picky compilers happy */
3566
error = error;
3567
3566
3568
DEBUG(D_route) debug_printf("Sieve: start of processing\n");
3567
DEBUG(D_route) debug_printf("Sieve: start of processing\n");
3569
sieve.filter = filter;
3568
sieve.filter = filter;
3570
3569
3571
if (!vacation_directory)
3570
if (!vacation_directory)
3572
  sieve.vacation_directory = NULL;
3571
  sieve.vacation_directory = NULL;
3573
else
3572
else if (!(sieve.vacation_directory = expand_cstring(vacation_directory)))
3574
  {
3573
  {
3575
  if (!(sieve.vacation_directory = expand_string(vacation_directory)))
3574
  *error = string_sprintf("failed to expand \"%s\" "
3576
    {
3575
    "(sieve_vacation_directory): %s", vacation_directory,
3577
    *error = string_sprintf("failed to expand \"%s\" "
3576
    expand_string_message);
3578
      "(sieve_vacation_directory): %s", vacation_directory,
3577
  return FF_ERROR;
3579
      expand_string_message);
3580
    return FF_ERROR;
3581
    }
3582
  }
3578
  }
3583
3579
3584
if (!enotify_mailto_owner)
3580
if (!enotify_mailto_owner)
3585
  sieve.enotify_mailto_owner = NULL;
3581
  sieve.enotify_mailto_owner = NULL;
3586
else
3582
else if (!(sieve.enotify_mailto_owner = expand_cstring(enotify_mailto_owner)))
3587
  {
3583
  {
3588
  if (!(sieve.enotify_mailto_owner = expand_string(enotify_mailto_owner)))
3584
  *error = string_sprintf("failed to expand \"%s\" "
3589
    {
3585
    "(sieve_enotify_mailto_owner): %s", enotify_mailto_owner,
3590
    *error = string_sprintf("failed to expand \"%s\" "
3586
    expand_string_message);
3591
      "(sieve_enotify_mailto_owner): %s", enotify_mailto_owner,
3587
  return FF_ERROR;
3592
      expand_string_message);
3593
    return FF_ERROR;
3594
    }
3595
  }
3588
  }
3596
3589
3597
sieve.useraddress = useraddress
3590
sieve.useraddress = useraddress
Lines 3599-3612 Link Here
3599
sieve.subaddress = subaddress;
3592
sieve.subaddress = subaddress;
3600
3593
3601
#ifdef COMPILE_SYNTAX_CHECKER
3594
#ifdef COMPILE_SYNTAX_CHECKER
3602
if (parse_start(&sieve,0,generated)==1)
3595
if (parse_start(&sieve, 0, generated) == 1)
3603
#else
3596
#else
3604
if (parse_start(&sieve,1,generated)==1)
3597
if (parse_start(&sieve, 1, generated) == 1)
3605
#endif
3598
#endif
3606
  {
3607
  if (sieve.keep)
3599
  if (sieve.keep)
3608
    {
3600
    {
3609
    add_addr(generated,US"inbox",1,0,0,0);
3601
    add_addr(generated, US"inbox", 1, 0, 0, 0);
3610
    msg = US"Implicit keep";
3602
    msg = US"Implicit keep";
3611
    r = FF_DELIVERED;
3603
    r = FF_DELIVERED;
3612
    }
3604
    }
Lines 3615-3621 Link Here
3615
    msg = US"No implicit keep";
3607
    msg = US"No implicit keep";
3616
    r = FF_DELIVERED;
3608
    r = FF_DELIVERED;
3617
    }
3609
    }
3618
  }
3619
else
3610
else
3620
  {
3611
  {
3621
  msg = string_sprintf("Sieve error: %s in line %d",sieve.errmsg,sieve.line);
3612
  msg = string_sprintf("Sieve error: %s in line %d",sieve.errmsg,sieve.line);
(-)exim.orig/src/smtp_in.c (-398 / +436 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Functions for handling an incoming SMTP call. */
9
/* Functions for handling an incoming SMTP call. */
Lines 139-145 Link Here
139
#endif
139
#endif
140
  BOOL dsn_advertised			:1;
140
  BOOL dsn_advertised			:1;
141
  BOOL esmtp				:1;
141
  BOOL esmtp				:1;
142
  BOOL helo_required			:1;
142
  BOOL helo_verify_required		:1;
143
  BOOL helo_verify			:1;
143
  BOOL helo_verify			:1;
144
  BOOL helo_seen			:1;
144
  BOOL helo_seen			:1;
145
  BOOL helo_accept_junk			:1;
145
  BOOL helo_accept_junk			:1;
Lines 153-159 Link Here
153
  BOOL smtputf8_advertised		:1;
153
  BOOL smtputf8_advertised		:1;
154
#endif
154
#endif
155
} fl = {
155
} fl = {
156
  .helo_required = FALSE,
156
  .helo_verify_required = FALSE,
157
  .helo_verify = FALSE,
157
  .helo_verify = FALSE,
158
  .smtp_exit_function_called = FALSE,
158
  .smtp_exit_function_called = FALSE,
159
};
159
};
Lines 227-233 Link Here
227
/* This list of names is used for performing the smtp_no_mail logging action.
227
/* This list of names is used for performing the smtp_no_mail logging action.
228
It must be kept in step with the SCH_xxx enumerations. */
228
It must be kept in step with the SCH_xxx enumerations. */
229
229
230
static uschar *smtp_names[] =
230
uschar * smtp_names[] =
231
  {
231
  {
232
  US"NONE", US"AUTH", US"DATA", US"BDAT", US"EHLO", US"ETRN", US"EXPN",
232
  US"NONE", US"AUTH", US"DATA", US"BDAT", US"EHLO", US"ETRN", US"EXPN",
233
  US"HELO", US"HELP", US"MAIL", US"NOOP", US"QUIT", US"RCPT", US"RSET",
233
  US"HELO", US"HELP", US"MAIL", US"NOOP", US"QUIT", US"RCPT", US"RSET",
Lines 320-417 Link Here
320
static void smtp_rset_handler(void);
320
static void smtp_rset_handler(void);
321
321
322
/*************************************************
322
/*************************************************
323
*          Recheck synchronization               *
324
*************************************************/
325
326
/* Synchronization checks can never be perfect because a packet may be on its
327
way but not arrived when the check is done.  Normally, the checks happen when
328
commands are read: Exim ensures that there is no more input in the input buffer.
329
In normal cases, the response to the command will be fast, and there is no
330
further check.
331
332
However, for some commands an ACL is run, and that can include delays. In those
333
cases, it is useful to do another check on the input just before sending the
334
response. This also applies at the start of a connection. This function does
335
that check by means of the select() function, as long as the facility is not
336
disabled or inappropriate. A failure of select() is ignored.
337
338
When there is unwanted input, we read it so that it appears in the log of the
339
error.
340
341
Arguments: none
342
Returns:   TRUE if all is well; FALSE if there is input pending
343
*/
344
345
static BOOL
346
wouldblock_reading(void)
347
{
348
int fd, rc;
349
fd_set fds;
350
struct timeval tzero;
351
352
#ifndef DISABLE_TLS
353
if (tls_in.active.sock >= 0)
354
 return !tls_could_read();
355
#endif
356
357
if (smtp_inptr < smtp_inend)
358
  return FALSE;
359
360
fd = fileno(smtp_in);
361
FD_ZERO(&fds);
362
FD_SET(fd, &fds);
363
tzero.tv_sec = 0;
364
tzero.tv_usec = 0;
365
rc = select(fd + 1, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &tzero);
366
367
if (rc <= 0) return TRUE;     /* Not ready to read */
368
rc = smtp_getc(GETC_BUFFER_UNLIMITED);
369
if (rc < 0) return TRUE;      /* End of file or error */
370
371
smtp_ungetc(rc);
372
return FALSE;
373
}
374
375
static BOOL
376
check_sync(void)
377
{
378
if (!smtp_enforce_sync || !sender_host_address || f.sender_host_notsocket)
379
  return TRUE;
380
381
return wouldblock_reading();
382
}
383
384
385
/* If there's input waiting (and we're doing pipelineing) then we can pipeline
386
a reponse with the one following. */
387
388
static BOOL
389
pipeline_response(void)
390
{
391
if (  !smtp_enforce_sync || !sender_host_address
392
   || f.sender_host_notsocket || !f.smtp_in_pipelining_advertised)
393
  return FALSE;
394
395
if (wouldblock_reading()) return FALSE;
396
f.smtp_in_pipelining_used = TRUE;
397
return TRUE;
398
}
399
400
401
#ifndef DISABLE_PIPE_CONNECT
402
static BOOL
403
pipeline_connect_sends(void)
404
{
405
if (!sender_host_address || f.sender_host_notsocket || !fl.pipe_connect_acceptable)
406
  return FALSE;
407
408
if (wouldblock_reading()) return FALSE;
409
f.smtp_in_early_pipe_used = TRUE;
410
return TRUE;
411
}
412
#endif
413
414
/*************************************************
415
*          Log incomplete transactions           *
323
*          Log incomplete transactions           *
416
*************************************************/
324
*************************************************/
417
325
Lines 434-440 Link Here
434
342
435
if (recipients_count > 0)
343
if (recipients_count > 0)
436
  {
344
  {
437
  raw_recipients = store_get(recipients_count * sizeof(uschar *), FALSE);
345
  raw_recipients = store_get(recipients_count * sizeof(uschar *), GET_UNTAINTED);
438
  for (int i = 0; i < recipients_count; i++)
346
  for (int i = 0; i < recipients_count; i++)
439
    raw_recipients[i] = recipients_list[i].address;
347
    raw_recipients[i] = recipients_list[i].address;
440
  raw_recipients_count = recipients_count;
348
  raw_recipients_count = recipients_count;
Lines 493-498 Link Here
493
}
401
}
494
402
495
403
404
/******************************************************************************/
405
/* SMTP input buffer handling.  Most of these are similar to stdio routines.  */
406
407
static void
408
smtp_buf_init(void)
409
{
410
/* Set up the buffer for inputting using direct read() calls, and arrange to
411
call the local functions instead of the standard C ones.  Place a NUL at the
412
end of the buffer to safety-stop C-string reads from it. */
413
414
if (!(smtp_inbuffer = US malloc(IN_BUFFER_SIZE)))
415
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "malloc() failed for SMTP input buffer");
416
smtp_inbuffer[IN_BUFFER_SIZE-1] = '\0';
417
418
smtp_inptr = smtp_inend = smtp_inbuffer;
419
smtp_had_eof = smtp_had_error = 0;
420
}
421
422
496
423
497
/* Refill the buffer, and notify DKIM verification code.
424
/* Refill the buffer, and notify DKIM verification code.
498
Return false for error or EOF.
425
Return false for error or EOF.
Lines 502-507 Link Here
502
smtp_refill(unsigned lim)
429
smtp_refill(unsigned lim)
503
{
430
{
504
int rc, save_errno;
431
int rc, save_errno;
432
505
if (!smtp_out) return FALSE;
433
if (!smtp_out) return FALSE;
506
fflush(smtp_out);
434
fflush(smtp_out);
507
if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout);
435
if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout);
Lines 543-553 Link Here
543
return TRUE;
471
return TRUE;
544
}
472
}
545
473
546
/*************************************************
547
*          SMTP version of getc()                *
548
*************************************************/
549
474
550
/* This gets the next byte from the SMTP input buffer. If the buffer is empty,
475
/* Check if there is buffered data */
476
477
BOOL
478
smtp_hasc(void)
479
{
480
return smtp_inptr < smtp_inend;
481
}
482
483
/* SMTP version of getc()
484
485
This gets the next byte from the SMTP input buffer. If the buffer is empty,
551
it flushes the output, and refills the buffer, with a timeout. The signal
486
it flushes the output, and refills the buffer, with a timeout. The signal
552
handler is set appropriately by the calling function. This function is not used
487
handler is set appropriately by the calling function. This function is not used
553
after a connection has negotiated itself into an TLS/SSL state.
488
after a connection has negotiated itself into an TLS/SSL state.
Lines 559-579 Link Here
559
int
494
int
560
smtp_getc(unsigned lim)
495
smtp_getc(unsigned lim)
561
{
496
{
562
if (smtp_inptr >= smtp_inend)
497
if (!smtp_hasc() && !smtp_refill(lim)) return EOF;
563
  if (!smtp_refill(lim))
564
    return EOF;
565
return *smtp_inptr++;
498
return *smtp_inptr++;
566
}
499
}
567
500
501
/* Get many bytes, refilling buffer if needed */
502
568
uschar *
503
uschar *
569
smtp_getbuf(unsigned * len)
504
smtp_getbuf(unsigned * len)
570
{
505
{
571
unsigned size;
506
unsigned size;
572
uschar * buf;
507
uschar * buf;
573
508
574
if (smtp_inptr >= smtp_inend)
509
if (!smtp_hasc() && !smtp_refill(*len))
575
  if (!smtp_refill(*len))
510
  { *len = 0; return NULL; }
576
    { *len = 0; return NULL; }
577
511
578
if ((size = smtp_inend - smtp_inptr) > *len) size = *len;
512
if ((size = smtp_inend - smtp_inptr) > *len) size = *len;
579
buf = smtp_inptr;
513
buf = smtp_inptr;
Lines 582-598 Link Here
582
return buf;
516
return buf;
583
}
517
}
584
518
519
/* Copy buffered data to the dkim feed.
520
Called, unless TLS, just before starting to read message headers. */
521
585
void
522
void
586
smtp_get_cache(void)
523
smtp_get_cache(unsigned lim)
587
{
524
{
588
#ifndef DISABLE_DKIM
525
#ifndef DISABLE_DKIM
589
int n = smtp_inend - smtp_inptr;
526
int n = smtp_inend - smtp_inptr;
527
if (n > lim)
528
  n = lim;
590
if (n > 0)
529
if (n > 0)
591
  dkim_exim_verify_feed(smtp_inptr, n);
530
  dkim_exim_verify_feed(smtp_inptr, n);
592
#endif
531
#endif
593
}
532
}
594
533
595
534
535
/* SMTP version of ungetc()
536
Puts a character back in the input buffer. Only ever called once.
537
538
Arguments:
539
  ch           the character
540
541
Returns:       the character
542
*/
543
544
int
545
smtp_ungetc(int ch)
546
{
547
if (smtp_inptr <= smtp_inbuffer)	/* NB: NOT smtp_hasc() ! */
548
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "buffer underflow in smtp_ungetc");
549
550
*--smtp_inptr = ch;
551
return ch;
552
}
553
554
555
/* SMTP version of feof()
556
Tests for a previous EOF
557
558
Arguments:     none
559
Returns:       non-zero if the eof flag is set
560
*/
561
562
int
563
smtp_feof(void)
564
{
565
return smtp_had_eof;
566
}
567
568
569
/* SMTP version of ferror()
570
Tests for a previous read error, and returns with errno
571
restored to what it was when the error was detected.
572
573
Arguments:     none
574
Returns:       non-zero if the error flag is set
575
*/
576
577
int
578
smtp_ferror(void)
579
{
580
errno = smtp_had_error;
581
return smtp_had_error;
582
}
583
584
585
/* Check if a getc will block or not */
586
587
static BOOL
588
smtp_could_getc(void)
589
{
590
int fd, rc;
591
fd_set fds;
592
struct timeval tzero = {.tv_sec = 0, .tv_usec = 0};
593
594
if (smtp_inptr < smtp_inend)
595
  return TRUE;
596
597
fd = fileno(smtp_in);
598
FD_ZERO(&fds);
599
FD_SET(fd, &fds);
600
rc = select(fd + 1, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &tzero);
601
602
if (rc <= 0) return FALSE;     /* Not ready to read */
603
rc = smtp_getc(GETC_BUFFER_UNLIMITED);
604
if (rc < 0) return FALSE;      /* End of file or error */
605
606
smtp_ungetc(rc);
607
return TRUE;
608
}
609
610
611
/******************************************************************************/
612
/*************************************************
613
*          Recheck synchronization               *
614
*************************************************/
615
616
/* Synchronization checks can never be perfect because a packet may be on its
617
way but not arrived when the check is done.  Normally, the checks happen when
618
commands are read: Exim ensures that there is no more input in the input buffer.
619
In normal cases, the response to the command will be fast, and there is no
620
further check.
621
622
However, for some commands an ACL is run, and that can include delays. In those
623
cases, it is useful to do another check on the input just before sending the
624
response. This also applies at the start of a connection. This function does
625
that check by means of the select() function, as long as the facility is not
626
disabled or inappropriate. A failure of select() is ignored.
627
628
When there is unwanted input, we read it so that it appears in the log of the
629
error.
630
631
Arguments: none
632
Returns:   TRUE if all is well; FALSE if there is input pending
633
*/
634
635
static BOOL
636
wouldblock_reading(void)
637
{
638
#ifndef DISABLE_TLS
639
if (tls_in.active.sock >= 0)
640
 return !tls_could_getc();
641
#endif
642
643
return !smtp_could_getc();
644
}
645
646
static BOOL
647
check_sync(void)
648
{
649
if (!smtp_enforce_sync || !sender_host_address || f.sender_host_notsocket)
650
  return TRUE;
651
652
return wouldblock_reading();
653
}
654
655
656
/******************************************************************************/
657
/* Variants of the smtp_* input handling functions for use in CHUNKING mode */
658
596
/* Forward declarations */
659
/* Forward declarations */
597
static inline void bdat_push_receive_functions(void);
660
static inline void bdat_push_receive_functions(void);
598
static inline void bdat_pop_receive_functions(void);
661
static inline void bdat_pop_receive_functions(void);
Lines 661-667 Link Here
661
  if (chunking_state == CHUNKING_LAST)
724
  if (chunking_state == CHUNKING_LAST)
662
    {
725
    {
663
#ifndef DISABLE_DKIM
726
#ifndef DISABLE_DKIM
727
    dkim_collect_input = dkim_save;
664
    dkim_exim_verify_feed(NULL, 0);	/* notify EOD */
728
    dkim_exim_verify_feed(NULL, 0);	/* notify EOD */
729
    dkim_collect_input = 0;
665
#endif
730
#endif
666
    return EOD;
731
    return EOD;
667
    }
732
    }
Lines 743-748 Link Here
743
  }
808
  }
744
}
809
}
745
810
811
BOOL
812
bdat_hasc(void)
813
{
814
if (chunking_data_left > 0)
815
  return lwr_receive_hasc();
816
return TRUE;
817
}
818
746
uschar *
819
uschar *
747
bdat_getbuf(unsigned * len)
820
bdat_getbuf(unsigned * len)
748
{
821
{
Lines 767-778 Link Here
767
  }
840
  }
768
841
769
bdat_pop_receive_functions();
842
bdat_pop_receive_functions();
770
843
chunking_state = CHUNKING_OFFERED;
771
if (chunking_state != CHUNKING_LAST)
844
DEBUG(D_receive) debug_printf("chunking state %d\n", (int)chunking_state);
772
  {
773
  chunking_state = CHUNKING_OFFERED;
774
  DEBUG(D_receive) debug_printf("chunking state %d\n", (int)chunking_state);
775
  }
776
}
845
}
777
846
778
847
Lines 782-791 Link Here
782
/* push the current receive_* function on the "stack", and
851
/* push the current receive_* function on the "stack", and
783
replace them by bdat_getc(), which in turn will use the lwr_receive_*
852
replace them by bdat_getc(), which in turn will use the lwr_receive_*
784
functions to do the dirty work. */
853
functions to do the dirty work. */
785
if (lwr_receive_getc == NULL)
854
if (!lwr_receive_getc)
786
  {
855
  {
787
  lwr_receive_getc = receive_getc;
856
  lwr_receive_getc = receive_getc;
788
  lwr_receive_getbuf = receive_getbuf;
857
  lwr_receive_getbuf = receive_getbuf;
858
  lwr_receive_hasc = receive_hasc;
789
  lwr_receive_ungetc = receive_ungetc;
859
  lwr_receive_ungetc = receive_ungetc;
790
  }
860
  }
791
else
861
else
Lines 795-844 Link Here
795
865
796
receive_getc = bdat_getc;
866
receive_getc = bdat_getc;
797
receive_getbuf = bdat_getbuf;
867
receive_getbuf = bdat_getbuf;
868
receive_hasc = bdat_hasc;
798
receive_ungetc = bdat_ungetc;
869
receive_ungetc = bdat_ungetc;
799
}
870
}
800
871
801
static inline void
872
static inline void
802
bdat_pop_receive_functions(void)
873
bdat_pop_receive_functions(void)
803
{
874
{
804
if (lwr_receive_getc == NULL)
875
if (!lwr_receive_getc)
805
  {
876
  {
806
  DEBUG(D_receive) debug_printf("chunking double-pop receive functions\n");
877
  DEBUG(D_receive) debug_printf("chunking double-pop receive functions\n");
807
  return;
878
  return;
808
  }
879
  }
809
receive_getc = lwr_receive_getc;
880
receive_getc = lwr_receive_getc;
810
receive_getbuf = lwr_receive_getbuf;
881
receive_getbuf = lwr_receive_getbuf;
882
receive_hasc = lwr_receive_hasc;
811
receive_ungetc = lwr_receive_ungetc;
883
receive_ungetc = lwr_receive_ungetc;
812
884
813
lwr_receive_getc = NULL;
885
lwr_receive_getc = NULL;
814
lwr_receive_getbuf = NULL;
886
lwr_receive_getbuf = NULL;
887
lwr_receive_hasc = NULL;
815
lwr_receive_ungetc = NULL;
888
lwr_receive_ungetc = NULL;
816
}
889
}
817
890
818
/*************************************************
819
*          SMTP version of ungetc()              *
820
*************************************************/
821
822
/* Puts a character back in the input buffer. Only ever
823
called once.
824
825
Arguments:
826
  ch           the character
827
828
Returns:       the character
829
*/
830
831
int
832
smtp_ungetc(int ch)
833
{
834
if (smtp_inptr <= smtp_inbuffer)
835
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "buffer underflow in smtp_ungetc");
836
837
*--smtp_inptr = ch;
838
return ch;
839
}
840
841
842
int
891
int
843
bdat_ungetc(int ch)
892
bdat_ungetc(int ch)
844
{
893
{
Lines 849-910 Link Here
849
898
850
899
851
900
852
/*************************************************
901
/******************************************************************************/
853
*          SMTP version of feof()                *
854
*************************************************/
855
856
/* Tests for a previous EOF
857
858
Arguments:     none
859
Returns:       non-zero if the eof flag is set
860
*/
861
862
int
863
smtp_feof(void)
864
{
865
return smtp_had_eof;
866
}
867
868
869
870
871
/*************************************************
872
*          SMTP version of ferror()              *
873
*************************************************/
874
875
/* Tests for a previous read error, and returns with errno
876
restored to what it was when the error was detected.
877
878
Arguments:     none
879
Returns:       non-zero if the error flag is set
880
*/
881
882
int
883
smtp_ferror(void)
884
{
885
errno = smtp_had_error;
886
return smtp_had_error;
887
}
888
889
890
891
/*************************************************
892
*      Test for characters in the SMTP buffer    *
893
*************************************************/
894
895
/* Used at the end of a message
896
897
Arguments:     none
898
Returns:       TRUE/FALSE
899
*/
900
901
BOOL
902
smtp_buffered(void)
903
{
904
return smtp_inptr < smtp_inend;
905
}
906
907
908
902
909
/*************************************************
903
/*************************************************
910
*     Write formatted string to SMTP channel     *
904
*     Write formatted string to SMTP channel     *
Lines 958-972 Link Here
958
yield = !! string_vformat(&gs, SVFMT_TAINT_NOCHK, format, ap);
952
yield = !! string_vformat(&gs, SVFMT_TAINT_NOCHK, format, ap);
959
string_from_gstring(&gs);
953
string_from_gstring(&gs);
960
954
961
DEBUG(D_receive)
955
DEBUG(D_receive) for (const uschar * t, * s = gs.s;
962
  {
956
		      s && (t = Ustrchr(s, '\r'));
963
  uschar *msg_copy, *cr, *end;
957
		      s = t + 2)				/* \r\n */
964
  msg_copy = string_copy(gs.s);
958
    debug_printf("%s %.*s\n",
965
  end = msg_copy + gs.ptr;
959
		  s == gs.s ? "SMTP>>" : "      ",
966
  while ((cr = Ustrchr(msg_copy, '\r')) != NULL)   /* lose CRs */
960
		  (int)(t - s), s);
967
    memmove(cr, cr + 1, (end--) - cr);
968
  debug_printf("SMTP>> %s", msg_copy);
969
  }
970
961
971
if (!yield)
962
if (!yield)
972
  {
963
  {
Lines 983-989 Link Here
983
974
984
if (fl.rcpt_in_progress)
975
if (fl.rcpt_in_progress)
985
  {
976
  {
986
  if (rcpt_smtp_response == NULL)
977
  if (!rcpt_smtp_response)
987
    rcpt_smtp_response = string_copy(big_buffer);
978
    rcpt_smtp_response = string_copy(big_buffer);
988
  else if (fl.rcpt_smtp_response_same &&
979
  else if (fl.rcpt_smtp_response_same &&
989
           Ustrcmp(rcpt_smtp_response, big_buffer) != 0)
980
           Ustrcmp(rcpt_smtp_response, big_buffer) != 0)
Lines 1034-1039 Link Here
1034
1025
1035
1026
1036
1027
1028
/* If there's input waiting (and we're doing pipelineing) then we can pipeline
1029
a reponse with the one following. */
1030
1031
static BOOL
1032
pipeline_response(void)
1033
{
1034
if (  !smtp_enforce_sync || !sender_host_address
1035
   || f.sender_host_notsocket || !f.smtp_in_pipelining_advertised)
1036
  return FALSE;
1037
1038
if (wouldblock_reading()) return FALSE;
1039
f.smtp_in_pipelining_used = TRUE;
1040
return TRUE;
1041
}
1042
1043
1044
#ifndef DISABLE_PIPE_CONNECT
1045
static BOOL
1046
pipeline_connect_sends(void)
1047
{
1048
if (!sender_host_address || f.sender_host_notsocket || !fl.pipe_connect_acceptable)
1049
  return FALSE;
1050
1051
if (wouldblock_reading()) return FALSE;
1052
f.smtp_in_early_pipe_used = TRUE;
1053
return TRUE;
1054
}
1055
#endif
1056
1037
/*************************************************
1057
/*************************************************
1038
*          SMTP command read timeout             *
1058
*          SMTP command read timeout             *
1039
*************************************************/
1059
*************************************************/
Lines 1074-1098 Link Here
1074
1094
1075
#ifdef SUPPORT_PROXY
1095
#ifdef SUPPORT_PROXY
1076
/*************************************************
1096
/*************************************************
1077
*     Restore socket timeout to previous value   *
1078
*************************************************/
1079
/* If the previous value was successfully retrieved, restore
1080
it before returning control to the non-proxy routines
1081
1082
Arguments: fd     - File descriptor for input
1083
           get_ok - Successfully retrieved previous values
1084
           tvtmp  - Time struct with previous values
1085
           vslen  - Length of time struct
1086
Returns:   none
1087
*/
1088
static void
1089
restore_socket_timeout(int fd, int get_ok, struct timeval * tvtmp, socklen_t vslen)
1090
{
1091
if (get_ok == 0)
1092
  (void) setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CS tvtmp, vslen);
1093
}
1094
1095
/*************************************************
1096
*       Check if host is required proxy host     *
1097
*       Check if host is required proxy host     *
1097
*************************************************/
1098
*************************************************/
1098
/* The function determines if inbound host will be a regular smtp host
1099
/* The function determines if inbound host will be a regular smtp host
Lines 1168-1174 Link Here
1168
1169
1169
while (capacity > 0)
1170
while (capacity > 0)
1170
  {
1171
  {
1171
  do { ret = recv(fd, to, 1, 0); } while (ret == -1 && errno == EINTR);
1172
  do { ret = read(fd, to, 1); } while (ret == -1 && errno == EINTR && !had_command_timeout);
1172
  if (ret == -1)
1173
  if (ret == -1)
1173
    return -1;
1174
    return -1;
1174
  have++;
1175
  have++;
Lines 1272-1291 Link Here
1272
int fd = fileno(smtp_in);
1273
int fd = fileno(smtp_in);
1273
const char v2sig[12] = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A";
1274
const char v2sig[12] = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A";
1274
uschar * iptype;  /* To display debug info */
1275
uschar * iptype;  /* To display debug info */
1275
struct timeval tv;
1276
struct timeval tvtmp;
1277
socklen_t vslen = sizeof(struct timeval);
1276
socklen_t vslen = sizeof(struct timeval);
1278
BOOL yield = FALSE;
1277
BOOL yield = FALSE;
1279
1278
1280
/* Save current socket timeout values */
1279
os_non_restarting_signal(SIGALRM, command_timeout_handler);
1281
get_ok = getsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CS &tvtmp, &vslen);
1280
ALARM(proxy_protocol_timeout);
1282
1283
/* Proxy Protocol host must send header within a short time
1284
(default 3 seconds) or it's considered invalid */
1285
tv.tv_sec  = PROXY_NEGOTIATION_TIMEOUT_SEC;
1286
tv.tv_usec = PROXY_NEGOTIATION_TIMEOUT_USEC;
1287
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, CS &tv, sizeof(tv)) < 0)
1288
  goto bad;
1289
1281
1290
do
1282
do
1291
  {
1283
  {
Lines 1293-1301 Link Here
1293
  don't do a PEEK into the data, actually slurp up enough to be
1285
  don't do a PEEK into the data, actually slurp up enough to be
1294
  "safe". Can't take it all because TLS-on-connect clients follow
1286
  "safe". Can't take it all because TLS-on-connect clients follow
1295
  immediately with TLS handshake. */
1287
  immediately with TLS handshake. */
1296
  ret = recv(fd, &hdr, PROXY_INITIAL_READ, 0);
1288
  ret = read(fd, &hdr, PROXY_INITIAL_READ);
1297
  }
1289
  }
1298
  while (ret == -1 && errno == EINTR);
1290
  while (ret == -1 && errno == EINTR && !had_command_timeout);
1299
1291
1300
if (ret == -1)
1292
if (ret == -1)
1301
  goto proxyfail;
1293
  goto proxyfail;
Lines 1309-1316 Link Here
1309
  /* First get the length fields. */
1301
  /* First get the length fields. */
1310
  do
1302
  do
1311
    {
1303
    {
1312
    retmore = recv(fd, (uschar*)&hdr + ret, PROXY_V2_HEADER_SIZE - PROXY_INITIAL_READ, 0);
1304
    retmore = read(fd, (uschar*)&hdr + ret, PROXY_V2_HEADER_SIZE - PROXY_INITIAL_READ);
1313
    } while (retmore == -1 && errno == EINTR);
1305
    } while (retmore == -1 && errno == EINTR && !had_command_timeout);
1314
  if (retmore == -1)
1306
  if (retmore == -1)
1315
    goto proxyfail;
1307
    goto proxyfail;
1316
  ret += retmore;
1308
  ret += retmore;
Lines 1346-1353 Link Here
1346
    {
1338
    {
1347
    do
1339
    do
1348
      {
1340
      {
1349
      retmore = recv(fd, (uschar*)&hdr + ret, size-ret, 0);
1341
      retmore = read(fd, (uschar*)&hdr + ret, size-ret);
1350
      } while (retmore == -1 && errno == EINTR);
1342
      } while (retmore == -1 && errno == EINTR && !had_command_timeout);
1351
    if (retmore == -1)
1343
    if (retmore == -1)
1352
      goto proxyfail;
1344
      goto proxyfail;
1353
    ret += retmore;
1345
    ret += retmore;
Lines 1575-1581 Link Here
1575
should cause a synchronization failure */
1567
should cause a synchronization failure */
1576
1568
1577
proxyfail:
1569
proxyfail:
1578
  restore_socket_timeout(fd, get_ok, &tvtmp, vslen);
1570
  DEBUG(D_receive) if (had_command_timeout)
1571
    debug_printf("Timeout while reading proxy header\n");
1579
1572
1580
bad:
1573
bad:
1581
  if (yield)
1574
  if (yield)
Lines 1591-1596 Link Here
1591
      debug_printf("Failure to extract proxied host, only QUIT allowed\n");
1584
      debug_printf("Failure to extract proxied host, only QUIT allowed\n");
1592
    }
1585
    }
1593
1586
1587
ALARM(0);
1594
return;
1588
return;
1595
}
1589
}
1596
#endif
1590
#endif
Lines 1681-1692 Link Here
1681
	|| smtp_cmd_buffer[p->len] == ' '
1675
	|| smtp_cmd_buffer[p->len] == ' '
1682
     )  )
1676
     )  )
1683
    {
1677
    {
1684
    if (smtp_inptr < smtp_inend &&                     /* Outstanding input */
1678
    if (   smtp_inptr < smtp_inend		/* Outstanding input */
1685
        p->cmd < sync_cmd_limit &&                     /* Command should sync */
1679
       &&  p->cmd < sync_cmd_limit		/* Command should sync */
1686
        check_sync &&                                  /* Local flag set */
1680
       &&  check_sync				/* Local flag set */
1687
        smtp_enforce_sync &&                           /* Global flag set */
1681
       &&  smtp_enforce_sync			/* Global flag set */
1688
        sender_host_address != NULL &&                 /* Not local input */
1682
       &&  sender_host_address != NULL		/* Not local input */
1689
        !f.sender_host_notsocket)                        /* Really is a socket */
1683
       &&  !f.sender_host_notsocket		/* Really is a socket */
1684
       )
1690
      return BADSYN_CMD;
1685
      return BADSYN_CMD;
1691
1686
1692
    /* The variables $smtp_command and $smtp_command_argument point into the
1687
    /* The variables $smtp_command and $smtp_command_argument point into the
Lines 1735-1741 Link Here
1735
   && check_sync			/* Local flag set */
1730
   && check_sync			/* Local flag set */
1736
   && smtp_enforce_sync			/* Global flag set */
1731
   && smtp_enforce_sync			/* Global flag set */
1737
   && sender_host_address		/* Not local input */
1732
   && sender_host_address		/* Not local input */
1738
   && !f.sender_host_notsocket)		/* Really is a socket */
1733
   && !f.sender_host_notsocket		/* Really is a socket */
1734
   )
1739
  return BADSYN_CMD;
1735
  return BADSYN_CMD;
1740
1736
1741
return OTHER_CMD;
1737
return OTHER_CMD;
Lines 1761-1767 Link Here
1761
*/
1757
*/
1762
1758
1763
void
1759
void
1764
smtp_closedown(uschar *message)
1760
smtp_closedown(uschar * message)
1765
{
1761
{
1766
if (!smtp_in || smtp_batched_input) return;
1762
if (!smtp_in || smtp_batched_input) return;
1767
receive_swallow_smtp();
1763
receive_swallow_smtp();
Lines 1773-1778 Link Here
1773
    return;
1769
    return;
1774
1770
1775
  case QUIT_CMD:
1771
  case QUIT_CMD:
1772
    f.smtp_in_quit = TRUE;
1776
    smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname);
1773
    smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname);
1777
    mac_smtp_fflush();
1774
    mac_smtp_fflush();
1778
    return;
1775
    return;
Lines 1841-1847 Link Here
1841
if (LOGGING(tls_cipher) && tls_in.cipher)
1838
if (LOGGING(tls_cipher) && tls_in.cipher)
1842
  {
1839
  {
1843
  g = string_append(g, 2, US" X=", tls_in.cipher);
1840
  g = string_append(g, 2, US" X=", tls_in.cipher);
1844
#ifdef EXPERIMENTAL_TLS_RESUME
1841
#ifndef DISABLE_TLS_RESUME
1845
  if (LOGGING(tls_resumption) && tls_in.resumption & RESUME_USED)
1842
  if (LOGGING(tls_resumption) && tls_in.resumption & RESUME_USED)
1846
    g = string_catn(g, US"*", 1);
1843
    g = string_catn(g, US"*", 1);
1847
#endif
1844
#endif
Lines 1861-1867 Link Here
1861
static gstring *
1858
static gstring *
1862
s_connhad_log(gstring * g)
1859
s_connhad_log(gstring * g)
1863
{
1860
{
1864
uschar * sep = smtp_connection_had[SMTP_HBUFF_SIZE-1] != SCH_NONE
1861
const uschar * sep = smtp_connection_had[SMTP_HBUFF_SIZE-1] != SCH_NONE
1865
  ? US" C=..." : US" C=";
1862
  ? US" C=..." : US" C=";
1866
1863
1867
for (int i = smtp_ch_index; i < SMTP_HBUFF_SIZE; i++)
1864
for (int i = smtp_ch_index; i < SMTP_HBUFF_SIZE; i++)
Lines 1870-1880 Link Here
1870
    g = string_append(g, 2, sep, smtp_names[smtp_connection_had[i]]);
1867
    g = string_append(g, 2, sep, smtp_names[smtp_connection_had[i]]);
1871
    sep = US",";
1868
    sep = US",";
1872
    }
1869
    }
1873
for (int i = 0; i < smtp_ch_index; i++)
1870
for (int i = 0; i < smtp_ch_index; i++, sep = US",")
1874
  {
1875
  g = string_append(g, 2, sep, smtp_names[smtp_connection_had[i]]);
1871
  g = string_append(g, 2, sep, smtp_names[smtp_connection_had[i]]);
1876
  sep = US",";
1877
  }
1878
return g;
1872
return g;
1879
}
1873
}
1880
1874
Lines 2094-2123 Link Here
2094
  raw_recipients_count = recipients_count = recipients_list_max = 0;
2088
  raw_recipients_count = recipients_count = recipients_list_max = 0;
2095
message_linecount = 0;
2089
message_linecount = 0;
2096
message_size = -1;
2090
message_size = -1;
2091
message_body = message_body_end = NULL;
2097
acl_added_headers = NULL;
2092
acl_added_headers = NULL;
2098
acl_removed_headers = NULL;
2093
acl_removed_headers = NULL;
2099
f.queue_only_policy = FALSE;
2094
f.queue_only_policy = FALSE;
2100
rcpt_smtp_response = NULL;
2095
rcpt_smtp_response = NULL;
2101
fl.rcpt_smtp_response_same = TRUE;
2096
fl.rcpt_smtp_response_same = TRUE;
2102
fl.rcpt_in_progress = FALSE;
2097
fl.rcpt_in_progress = FALSE;
2103
f.deliver_freeze = FALSE;                              /* Can be set by ACL */
2098
f.deliver_freeze = FALSE;				/* Can be set by ACL */
2104
freeze_tell = freeze_tell_config;                    /* Can be set by ACL */
2099
freeze_tell = freeze_tell_config;			/* Can be set by ACL */
2105
fake_response = OK;                                  /* Can be set by ACL */
2100
fake_response = OK;					/* Can be set by ACL */
2106
#ifdef WITH_CONTENT_SCAN
2101
#ifdef WITH_CONTENT_SCAN
2107
f.no_mbox_unspool = FALSE;                             /* Can be set by ACL */
2102
f.no_mbox_unspool = FALSE;				/* Can be set by ACL */
2108
#endif
2103
#endif
2109
f.submission_mode = FALSE;                             /* Can be set by ACL */
2104
f.submission_mode = FALSE;				/* Can be set by ACL */
2110
f.suppress_local_fixups = f.suppress_local_fixups_default; /* Can be set by ACL */
2105
f.suppress_local_fixups = f.suppress_local_fixups_default; /* Can be set by ACL */
2111
f.active_local_from_check = local_from_check;          /* Can be set by ACL */
2106
f.active_local_from_check = local_from_check;		/* Can be set by ACL */
2112
f.active_local_sender_retain = local_sender_retain;    /* Can be set by ACL */
2107
f.active_local_sender_retain = local_sender_retain;	/* Can be set by ACL */
2113
sending_ip_address = NULL;
2108
sending_ip_address = NULL;
2114
return_path = sender_address = NULL;
2109
return_path = sender_address = NULL;
2115
deliver_localpart_data = deliver_domain_data =
2110
deliver_localpart_data = deliver_domain_data =
2116
recipient_data = sender_data = NULL;			/* Can be set by ACL */
2111
recipient_data = sender_data = NULL;			/* Can be set by ACL */
2112
recipient_verify_failure = NULL;
2117
deliver_localpart_parent = deliver_localpart_orig = NULL;
2113
deliver_localpart_parent = deliver_localpart_orig = NULL;
2118
deliver_domain_parent = deliver_domain_orig = NULL;
2114
deliver_domain_parent = deliver_domain_orig = NULL;
2119
callout_address = NULL;
2115
callout_address = NULL;
2120
submission_name = NULL;                              /* Can be set by ACL */
2116
submission_name = NULL;					/* Can be set by ACL */
2121
raw_sender = NULL;                  /* After SMTP rewrite, before qualifying */
2117
raw_sender = NULL;                  /* After SMTP rewrite, before qualifying */
2122
sender_address_unrewritten = NULL;  /* Set only after verify rewrite */
2118
sender_address_unrewritten = NULL;  /* Set only after verify rewrite */
2123
sender_verified_list = NULL;        /* No senders verified */
2119
sender_verified_list = NULL;        /* No senders verified */
Lines 2171-2193 Link Here
2171
2167
2172
acl_var_m = NULL;
2168
acl_var_m = NULL;
2173
2169
2174
/* The message body variables use malloc store. They may be set if this is
2170
/* Warning log messages are saved in malloc store. They are saved to avoid
2175
not the first message in an SMTP session and the previous message caused them
2176
to be referenced in an ACL. */
2177
2178
if (message_body)
2179
  {
2180
  store_free(message_body);
2181
  message_body = NULL;
2182
  }
2183
2184
if (message_body_end)
2185
  {
2186
  store_free(message_body_end);
2187
  message_body_end = NULL;
2188
  }
2189
2190
/* Warning log messages are also saved in malloc store. They are saved to avoid
2191
repetition in the same message, but it seems right to repeat them for different
2171
repetition in the same message, but it seems right to repeat them for different
2192
messages. */
2172
messages. */
2193
2173
Lines 2197-2203 Link Here
2197
  acl_warn_logged = acl_warn_logged->next;
2177
  acl_warn_logged = acl_warn_logged->next;
2198
  store_free(this);
2178
  store_free(this);
2199
  }
2179
  }
2180
2181
message_tidyup();
2200
store_reset(reset_point);
2182
store_reset(reset_point);
2183
2184
message_start();
2201
return store_mark();
2185
return store_mark();
2202
}
2186
}
2203
2187
Lines 2274-2280 Link Here
2274
2258
2275
    case MAIL_CMD:
2259
    case MAIL_CMD:
2276
      smtp_mailcmd_count++;              /* Count for no-mail log */
2260
      smtp_mailcmd_count++;              /* Count for no-mail log */
2277
      if (sender_address != NULL)
2261
      if (sender_address)
2278
	/* The function moan_smtp_batch() does not return. */
2262
	/* The function moan_smtp_batch() does not return. */
2279
	moan_smtp_batch(smtp_cmd_buffer, "503 Sender already given");
2263
	moan_smtp_batch(smtp_cmd_buffer, "503 Sender already given");
2280
2264
Lines 2417-2424 Link Here
2417
      break;
2401
      break;
2418
2402
2419
2403
2420
    case EOF_CMD:
2421
    case QUIT_CMD:
2404
    case QUIT_CMD:
2405
      f.smtp_in_quit = TRUE;
2406
    case EOF_CMD:
2422
      done = 2;
2407
      done = 2;
2423
      break;
2408
      break;
2424
2409
Lines 2450-2458 Link Here
2450
2435
2451
#ifndef DISABLE_TLS
2436
#ifndef DISABLE_TLS
2452
static BOOL
2437
static BOOL
2453
smtp_log_tls_fail(uschar * errstr)
2438
smtp_log_tls_fail(const uschar * errstr)
2454
{
2439
{
2455
uschar * conn_info = smtp_get_connection_info();
2440
const uschar * conn_info = smtp_get_connection_info();
2456
2441
2457
if (Ustrncmp(conn_info, US"SMTP ", 5) == 0) conn_info += 5;
2442
if (Ustrncmp(conn_info, US"SMTP ", 5) == 0) conn_info += 5;
2458
/* I'd like to get separated H= here, but too hard for now */
2443
/* I'd like to get separated H= here, but too hard for now */
Lines 2580-2586 Link Here
2580
2565
2581
/* Allow for trailing 0 in the command and data buffers.  Tainted. */
2566
/* Allow for trailing 0 in the command and data buffers.  Tainted. */
2582
2567
2583
smtp_cmd_buffer = store_get_perm(2*SMTP_CMD_BUFFER_SIZE + 2, TRUE);
2568
smtp_cmd_buffer = store_get_perm(2*SMTP_CMD_BUFFER_SIZE + 2, GET_TAINTED);
2584
2569
2585
smtp_cmd_buffer[0] = 0;
2570
smtp_cmd_buffer[0] = 0;
2586
smtp_data_buffer = smtp_cmd_buffer + SMTP_CMD_BUFFER_SIZE + 1;
2571
smtp_data_buffer = smtp_cmd_buffer + SMTP_CMD_BUFFER_SIZE + 1;
Lines 2601-2625 Link Here
2601
    (sender_host_address ? protocols : protocols_local) [pnormal];
2586
    (sender_host_address ? protocols : protocols_local) [pnormal];
2602
2587
2603
/* Set up the buffer for inputting using direct read() calls, and arrange to
2588
/* Set up the buffer for inputting using direct read() calls, and arrange to
2604
call the local functions instead of the standard C ones.  Place a NUL at the
2589
call the local functions instead of the standard C ones. */
2605
end of the buffer to safety-stop C-string reads from it. */
2606
2590
2607
if (!(smtp_inbuffer = US malloc(IN_BUFFER_SIZE)))
2591
smtp_buf_init();
2608
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "malloc() failed for SMTP input buffer");
2609
smtp_inbuffer[IN_BUFFER_SIZE-1] = '\0';
2610
2592
2611
receive_getc = smtp_getc;
2593
receive_getc = smtp_getc;
2612
receive_getbuf = smtp_getbuf;
2594
receive_getbuf = smtp_getbuf;
2613
receive_get_cache = smtp_get_cache;
2595
receive_get_cache = smtp_get_cache;
2596
receive_hasc = smtp_hasc;
2614
receive_ungetc = smtp_ungetc;
2597
receive_ungetc = smtp_ungetc;
2615
receive_feof = smtp_feof;
2598
receive_feof = smtp_feof;
2616
receive_ferror = smtp_ferror;
2599
receive_ferror = smtp_ferror;
2617
receive_smtp_buffered = smtp_buffered;
2618
lwr_receive_getc = NULL;
2600
lwr_receive_getc = NULL;
2619
lwr_receive_getbuf = NULL;
2601
lwr_receive_getbuf = NULL;
2602
lwr_receive_hasc = NULL;
2620
lwr_receive_ungetc = NULL;
2603
lwr_receive_ungetc = NULL;
2621
smtp_inptr = smtp_inend = smtp_inbuffer;
2622
smtp_had_eof = smtp_had_error = 0;
2623
2604
2624
/* Set up the message size limit; this may be host-specific */
2605
/* Set up the message size limit; this may be host-specific */
2625
2606
Lines 2694-2700 Link Here
2694
    {
2675
    {
2695
    #if OPTSTYLE == 1
2676
    #if OPTSTYLE == 1
2696
    EXIM_SOCKLEN_T optlen = sizeof(struct ip_options) + MAX_IPOPTLEN;
2677
    EXIM_SOCKLEN_T optlen = sizeof(struct ip_options) + MAX_IPOPTLEN;
2697
    struct ip_options *ipopt = store_get(optlen, FALSE);
2678
    struct ip_options *ipopt = store_get(optlen, GET_UNTAINTED);
2698
    #elif OPTSTYLE == 2
2679
    #elif OPTSTYLE == 2
2699
    struct ip_opts ipoptblock;
2680
    struct ip_opts ipoptblock;
2700
    struct ip_opts *ipopt = &ipoptblock;
2681
    struct ip_opts *ipopt = &ipoptblock;
Lines 2973-2980 Link Here
2973
  /* Determine whether HELO/EHLO is required for this host. The requirement
2954
  /* Determine whether HELO/EHLO is required for this host. The requirement
2974
  can be hard or soft. */
2955
  can be hard or soft. */
2975
2956
2976
  fl.helo_required = verify_check_host(&helo_verify_hosts) == OK;
2957
  fl.helo_verify_required = verify_check_host(&helo_verify_hosts) == OK;
2977
  if (!fl.helo_required)
2958
  if (!fl.helo_verify_required)
2978
    fl.helo_verify = verify_check_host(&helo_try_verify_hosts) == OK;
2959
    fl.helo_verify = verify_check_host(&helo_try_verify_hosts) == OK;
2979
2960
2980
  /* Determine whether this hosts is permitted to send syntactic junk
2961
  /* Determine whether this hosts is permitted to send syntactic junk
Lines 2988-2994 Link Here
2988
if (smtp_batched_input) return TRUE;
2969
if (smtp_batched_input) return TRUE;
2989
2970
2990
/* If valid Proxy Protocol source is connecting, set up session.
2971
/* If valid Proxy Protocol source is connecting, set up session.
2991
 * Failure will not allow any SMTP function other than QUIT. */
2972
Failure will not allow any SMTP function other than QUIT. */
2992
2973
2993
#ifdef SUPPORT_PROXY
2974
#ifdef SUPPORT_PROXY
2994
proxy_session = FALSE;
2975
proxy_session = FALSE;
Lines 2997-3012 Link Here
2997
  setup_proxy_protocol_host();
2978
  setup_proxy_protocol_host();
2998
#endif
2979
#endif
2999
2980
3000
  /* Start up TLS if tls_on_connect is set. This is for supporting the legacy
2981
/* Start up TLS if tls_on_connect is set. This is for supporting the legacy
3001
  smtps port for use with older style SSL MTAs. */
2982
smtps port for use with older style SSL MTAs. */
3002
2983
3003
#ifndef DISABLE_TLS
2984
#ifndef DISABLE_TLS
3004
  if (tls_in.on_connect)
2985
if (tls_in.on_connect)
3005
    {
2986
  {
3006
    if (tls_server_start(tls_require_ciphers, &user_msg) != OK)
2987
  if (tls_server_start(&user_msg) != OK)
3007
      return smtp_log_tls_fail(user_msg);
2988
    return smtp_log_tls_fail(user_msg);
3008
    cmd_list[CMD_LIST_TLS_AUTH].is_mail_cmd = TRUE;
2989
  cmd_list[CMD_LIST_TLS_AUTH].is_mail_cmd = TRUE;
3009
    }
2990
  }
3010
#endif
2991
#endif
3011
2992
3012
/* Run the connect ACL if it exists */
2993
/* Run the connect ACL if it exists */
Lines 3052-3058 Link Here
3052
3033
3053
p = s + Ustrlen(s);
3034
p = s + Ustrlen(s);
3054
while (p > s && isspace(p[-1])) p--;
3035
while (p > s && isspace(p[-1])) p--;
3055
*p = 0;
3036
s = string_copyn(s, p-s);
3056
3037
3057
/* It seems that CC:Mail is braindead, and assumes that the greeting message
3038
/* It seems that CC:Mail is braindead, and assumes that the greeting message
3058
is all contained in a single IP packet. The original code wrote out the
3039
is all contained in a single IP packet. The original code wrote out the
Lines 3232-3238 Link Here
3232
3213
3233
if (fl.rcpt_in_progress)
3214
if (fl.rcpt_in_progress)
3234
  {
3215
  {
3235
  if (rcpt_smtp_response == NULL)
3216
  if (!rcpt_smtp_response)
3236
    rcpt_smtp_response = string_copy(msg);
3217
    rcpt_smtp_response = string_copy(msg);
3237
  else if (fl.rcpt_smtp_response_same &&
3218
  else if (fl.rcpt_smtp_response_same &&
3238
           Ustrcmp(rcpt_smtp_response, msg) != 0)
3219
           Ustrcmp(rcpt_smtp_response, msg) != 0)
Lines 3247-3253 Link Here
3247
for (;;)
3228
for (;;)
3248
  {
3229
  {
3249
  uschar *nl = Ustrchr(msg, '\n');
3230
  uschar *nl = Ustrchr(msg, '\n');
3250
  if (nl == NULL)
3231
  if (!nl)
3251
    {
3232
    {
3252
    smtp_printf("%.3s%c%.*s%s\r\n", !final, code, final ? ' ':'-', esclen, esc, msg);
3233
    smtp_printf("%.3s%c%.*s%s\r\n", !final, code, final ? ' ':'-', esclen, esc, msg);
3253
    return;
3234
    return;
Lines 3303-3329 Link Here
3303
smtp_message_code(uschar **code, int *codelen, uschar **msg, uschar **log_msg,
3284
smtp_message_code(uschar **code, int *codelen, uschar **msg, uschar **log_msg,
3304
  BOOL check_valid)
3285
  BOOL check_valid)
3305
{
3286
{
3306
int n;
3287
uschar * match;
3307
int ovector[3];
3288
int len;
3308
3289
3309
if (!msg || !*msg) return;
3290
if (!msg || !*msg || !regex_match(regex_smtp_code, *msg, -1, &match))
3310
3291
  return;
3311
if ((n = pcre_exec(regex_smtp_code, NULL, CS *msg, Ustrlen(*msg), 0,
3312
  PCRE_EOPT, ovector, sizeof(ovector)/sizeof(int))) < 0) return;
3313
3292
3293
len = Ustrlen(match);
3314
if (check_valid && (*msg)[0] != (*code)[0])
3294
if (check_valid && (*msg)[0] != (*code)[0])
3315
  {
3295
  {
3316
  log_write(0, LOG_MAIN|LOG_PANIC, "configured error code starts with "
3296
  log_write(0, LOG_MAIN|LOG_PANIC, "configured error code starts with "
3317
    "incorrect digit (expected %c) in \"%s\"", (*code)[0], *msg);
3297
    "incorrect digit (expected %c) in \"%s\"", (*code)[0], *msg);
3318
  if (log_msg != NULL && *log_msg == *msg)
3298
  if (log_msg && *log_msg == *msg)
3319
    *log_msg = string_sprintf("%s %s", *code, *log_msg + ovector[1]);
3299
    *log_msg = string_sprintf("%s %s", *code, *log_msg + len);
3320
  }
3300
  }
3321
else
3301
else
3322
  {
3302
  {
3323
  *code = *msg;
3303
  *code = *msg;
3324
  *codelen = ovector[1];    /* Includes final space */
3304
  *codelen = len;    /* Includes final space */
3325
  }
3305
  }
3326
*msg += ovector[1];         /* Chop the code off the message */
3306
*msg += len;         /* Chop the code off the message */
3327
return;
3307
return;
3328
}
3308
}
3329
3309
Lines 3374-3391 Link Here
3374
uschar *smtp_code;
3354
uschar *smtp_code;
3375
uschar *lognl;
3355
uschar *lognl;
3376
uschar *sender_info = US"";
3356
uschar *sender_info = US"";
3377
uschar *what =
3357
uschar *what;
3378
#ifdef WITH_CONTENT_SCAN
3379
  where == ACL_WHERE_MIME ? US"during MIME ACL checks" :
3380
#endif
3381
  where == ACL_WHERE_PREDATA ? US"DATA" :
3382
  where == ACL_WHERE_DATA ? US"after DATA" :
3383
#ifndef DISABLE_PRDR
3384
  where == ACL_WHERE_PRDR ? US"after DATA PRDR" :
3385
#endif
3386
  smtp_cmd_data ?
3387
    string_sprintf("%s %s", acl_wherenames[where], smtp_cmd_data) :
3388
    string_sprintf("%s in \"connect\" ACL", acl_wherenames[where]);
3389
3358
3390
if (drop) rc = FAIL;
3359
if (drop) rc = FAIL;
3391
3360
Lines 3401-3419 Link Here
3401
this is what should be logged, so I've changed to logging the unrewritten
3370
this is what should be logged, so I've changed to logging the unrewritten
3402
address to retain backward compatibility. */
3371
address to retain backward compatibility. */
3403
3372
3404
#ifndef WITH_CONTENT_SCAN
3373
switch (where)
3405
if (where == ACL_WHERE_RCPT || where == ACL_WHERE_DATA)
3374
  {
3406
#else
3375
#ifdef WITH_CONTENT_SCAN
3407
if (where == ACL_WHERE_RCPT || where == ACL_WHERE_DATA || where == ACL_WHERE_MIME)
3376
  case ACL_WHERE_MIME:		what = US"during MIME ACL checks";	break;
3377
#endif
3378
  case ACL_WHERE_PREDATA:	what = US"DATA";			break;
3379
  case ACL_WHERE_DATA:		what = US"after DATA";			break;
3380
#ifndef DISABLE_PRDR
3381
  case ACL_WHERE_PRDR:		what = US"after DATA PRDR";		break;
3408
#endif
3382
#endif
3383
  default:
3384
    {
3385
    uschar * place = smtp_cmd_data ? smtp_cmd_data : US"in \"connect\" ACL";
3386
    int lim = 100;
3387
3388
    if (where == ACL_WHERE_AUTH)	/* avoid logging auth creds */
3389
      {
3390
      uschar * s;
3391
      for (s = smtp_cmd_data; *s && !isspace(*s); ) s++;
3392
      lim = s - smtp_cmd_data;	/* atop after method */
3393
      }
3394
    what = string_sprintf("%s %.*s", acl_wherenames[where], lim, place);
3395
    }
3396
  }
3397
switch (where)
3409
  {
3398
  {
3410
  sender_info = string_sprintf("F=<%s>%s%s%s%s ",
3399
  case ACL_WHERE_RCPT:
3411
    sender_address_unrewritten ? sender_address_unrewritten : sender_address,
3400
  case ACL_WHERE_DATA:
3412
    sender_host_authenticated ? US" A="                                    : US"",
3401
#ifdef WITH_CONTENT_SCAN
3413
    sender_host_authenticated ? sender_host_authenticated                  : US"",
3402
  case ACL_WHERE_MIME:
3414
    sender_host_authenticated && authenticated_id ? US":"                  : US"",
3403
#endif
3415
    sender_host_authenticated && authenticated_id ? authenticated_id       : US""
3404
    sender_info = string_sprintf("F=<%s>%s%s%s%s ",
3416
    );
3405
      sender_address_unrewritten ? sender_address_unrewritten : sender_address,
3406
      sender_host_authenticated ? US" A="                                    : US"",
3407
      sender_host_authenticated ? sender_host_authenticated                  : US"",
3408
      sender_host_authenticated && authenticated_id ? US":"                  : US"",
3409
      sender_host_authenticated && authenticated_id ? authenticated_id       : US""
3410
      );
3411
  break;
3417
  }
3412
  }
3418
3413
3419
/* If there's been a sender verification failure with a specific message, and
3414
/* If there's been a sender verification failure with a specific message, and
Lines 3775-3780 Link Here
3775
const uschar *set_id = NULL;
3770
const uschar *set_id = NULL;
3776
int rc;
3771
int rc;
3777
3772
3773
/* Set up globals for error messages */
3774
3775
authenticator_name = au->name;
3776
driver_srcfile = au->srcfile;
3777
driver_srcline = au->srcline;
3778
3778
/* Run the checking code, passing the remainder of the command line as
3779
/* Run the checking code, passing the remainder of the command line as
3779
data. Initials the $auth<n> variables as empty. Initialize $0 empty and set
3780
data. Initials the $auth<n> variables as empty. Initialize $0 empty and set
3780
it as the only set numerical variable. The authenticator may set $auth<n>
3781
it as the only set numerical variable. The authenticator may set $auth<n>
Lines 3795-3800 Link Here
3795
if (au->set_id) set_id = expand_string(au->set_id);
3796
if (au->set_id) set_id = expand_string(au->set_id);
3796
expand_nmax = -1;        /* Reset numeric variables */
3797
expand_nmax = -1;        /* Reset numeric variables */
3797
for (int i = 0; i < AUTH_VARS; i++) auth_vars[i] = NULL;   /* Reset $auth<n> */
3798
for (int i = 0; i < AUTH_VARS; i++) auth_vars[i] = NULL;   /* Reset $auth<n> */
3799
driver_srcfile = authenticator_name = NULL; driver_srcline = 0;
3798
3800
3799
/* The value of authenticated_id is stored in the spool file and printed in
3801
/* The value of authenticated_id is stored in the spool file and printed in
3800
log lines. It must not contain binary zeros or newline characters. In
3802
log lines. It must not contain binary zeros or newline characters. In
Lines 3907-3923 Link Here
3907
smtp_quit_handler(uschar ** user_msgp, uschar ** log_msgp)
3909
smtp_quit_handler(uschar ** user_msgp, uschar ** log_msgp)
3908
{
3910
{
3909
HAD(SCH_QUIT);
3911
HAD(SCH_QUIT);
3912
f.smtp_in_quit = TRUE;
3910
incomplete_transaction_log(US"QUIT");
3913
incomplete_transaction_log(US"QUIT");
3911
if (acl_smtp_quit)
3914
if (  acl_smtp_quit
3912
  {
3915
   && acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, user_msgp, log_msgp)
3913
  int rc = acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, user_msgp, log_msgp);
3916
	== ERROR)
3914
  if (rc == ERROR)
3915
    log_write(0, LOG_MAIN|LOG_PANIC, "ACL for QUIT returned ERROR: %s",
3917
    log_write(0, LOG_MAIN|LOG_PANIC, "ACL for QUIT returned ERROR: %s",
3916
      *log_msgp);
3918
      *log_msgp);
3917
  }
3918
3919
3919
#ifdef TCP_CORK
3920
#ifdef EXIM_TCP_CORK
3920
(void) setsockopt(fileno(smtp_out), IPPROTO_TCP, TCP_CORK, US &on, sizeof(on));
3921
(void) setsockopt(fileno(smtp_out), IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on));
3921
#endif
3922
#endif
3922
3923
3923
if (*user_msgp)
3924
if (*user_msgp)
Lines 3925-3936 Link Here
3925
else
3926
else
3926
  smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname);
3927
  smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname);
3927
3928
3928
#ifndef DISABLE_TLS
3929
#ifdef SERVERSIDE_CLOSE_NOWAIT
3930
# ifndef DISABLE_TLS
3929
tls_close(NULL, TLS_SHUTDOWN_NOWAIT);
3931
tls_close(NULL, TLS_SHUTDOWN_NOWAIT);
3930
#endif
3932
# endif
3931
3933
3932
log_write(L_smtp_connection, LOG_MAIN, "%s closed by QUIT",
3934
log_write(L_smtp_connection, LOG_MAIN, "%s closed by QUIT",
3933
  smtp_get_connection_info());
3935
  smtp_get_connection_info());
3936
#else
3937
3938
# ifndef DISABLE_TLS
3939
tls_close(NULL, TLS_SHUTDOWN_WAIT);
3940
# endif
3941
3942
log_write(L_smtp_connection, LOG_MAIN, "%s closed by QUIT",
3943
  smtp_get_connection_info());
3944
3945
/* Pause, hoping client will FIN first so that they get the TIME_WAIT.
3946
The socket should become readble (though with no data) */
3947
3948
(void) poll_one_fd(fileno(smtp_in), POLLIN, 200);
3949
#endif	/*!SERVERSIDE_CLOSE_NOWAIT*/
3934
}
3950
}
3935
3951
3936
3952
Lines 3941-3949 Link Here
3941
incomplete_transaction_log(US"RSET");
3957
incomplete_transaction_log(US"RSET");
3942
smtp_printf("250 Reset OK\r\n", FALSE);
3958
smtp_printf("250 Reset OK\r\n", FALSE);
3943
cmd_list[CMD_LIST_RSET].is_mail_cmd = FALSE;
3959
cmd_list[CMD_LIST_RSET].is_mail_cmd = FALSE;
3960
if (chunking_state > CHUNKING_OFFERED)
3961
  chunking_state = CHUNKING_OFFERED;
3944
}
3962
}
3945
3963
3946
3964
3965
static int
3966
expand_mailmax(const uschar * s)
3967
{
3968
if (!(s = expand_cstring(s)))
3969
  log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand smtp_accept_max_per_connection");
3970
return *s ? Uatoi(s) : 0;
3971
}
3947
3972
3948
/*************************************************
3973
/*************************************************
3949
*       Initialize for SMTP incoming message     *
3974
*       Initialize for SMTP incoming message     *
Lines 4017-4022 Link Here
4017
4042
4018
if (smtp_batched_input) return smtp_setup_batch_msg();
4043
if (smtp_batched_input) return smtp_setup_batch_msg();
4019
4044
4045
#ifdef TCP_QUICKACK
4046
if (smtp_in)		/* Avoid pure-ACKs while in cmd pingpong phase */
4047
  (void) setsockopt(fileno(smtp_in), IPPROTO_TCP, TCP_QUICKACK,
4048
	  US &off, sizeof(off));
4049
#endif
4050
4020
/* Deal with SMTP commands. This loop is exited by setting done to a POSITIVE
4051
/* Deal with SMTP commands. This loop is exited by setting done to a POSITIVE
4021
value. The values are 2 larger than the required yield of the function. */
4052
value. The values are 2 larger than the required yield of the function. */
4022
4053
Lines 4074-4085 Link Here
4074
    }
4105
    }
4075
#endif
4106
#endif
4076
4107
4077
#ifdef TCP_QUICKACK
4078
  if (smtp_in)		/* Avoid pure-ACKs while in cmd pingpong phase */
4079
    (void) setsockopt(fileno(smtp_in), IPPROTO_TCP, TCP_QUICKACK,
4080
	    US &off, sizeof(off));
4081
#endif
4082
4083
  switch(smtp_read_command(
4108
  switch(smtp_read_command(
4084
#ifndef DISABLE_PIPE_CONNECT
4109
#ifndef DISABLE_PIPE_CONNECT
4085
	  !fl.pipe_connect_acceptable,
4110
	  !fl.pipe_connect_acceptable,
Lines 4140-4160 Link Here
4140
      /* Find the name of the requested authentication mechanism. */
4165
      /* Find the name of the requested authentication mechanism. */
4141
4166
4142
      s = smtp_cmd_data;
4167
      s = smtp_cmd_data;
4143
      while ((c = *smtp_cmd_data) != 0 && !isspace(c))
4168
      for (; (c = *smtp_cmd_data) && !isspace(c); smtp_cmd_data++)
4144
	{
4145
	if (!isalnum(c) && c != '-' && c != '_')
4169
	if (!isalnum(c) && c != '-' && c != '_')
4146
	  {
4170
	  {
4147
	  done = synprot_error(L_smtp_syntax_error, 501, NULL,
4171
	  done = synprot_error(L_smtp_syntax_error, 501, NULL,
4148
	    US"invalid character in authentication mechanism name");
4172
	    US"invalid character in authentication mechanism name");
4149
	  goto COMMAND_LOOP;
4173
	  goto COMMAND_LOOP;
4150
	  }
4174
	  }
4151
	smtp_cmd_data++;
4152
	}
4153
4175
4154
      /* If not at the end of the line, we must be at white space. Terminate the
4176
      /* If not at the end of the line, we must be at white space. Terminate the
4155
      name and move the pointer on to any data that may be present. */
4177
      name and move the pointer on to any data that may be present. */
4156
4178
4157
      if (*smtp_cmd_data != 0)
4179
      if (*smtp_cmd_data)
4158
	{
4180
	{
4159
	*smtp_cmd_data++ = 0;
4181
	*smtp_cmd_data++ = 0;
4160
	while (isspace(*smtp_cmd_data)) smtp_cmd_data++;
4182
	while (isspace(*smtp_cmd_data)) smtp_cmd_data++;
Lines 4246-4252 Link Here
4246
      /* If sender_host_unknown is true, we have got here via the -bs interface,
4268
      /* If sender_host_unknown is true, we have got here via the -bs interface,
4247
      not called from inetd. Otherwise, we are running an IP connection and the
4269
      not called from inetd. Otherwise, we are running an IP connection and the
4248
      host address will be set. If the helo name is the primary name of this
4270
      host address will be set. If the helo name is the primary name of this
4249
      host and we haven't done a reverse lookup, force one now. If helo_required
4271
      host and we haven't done a reverse lookup, force one now. If helo_verify_required
4250
      is set, ensure that the HELO name matches the actual host. If helo_verify
4272
      is set, ensure that the HELO name matches the actual host. If helo_verify
4251
      is set, do the same check, but softly. */
4273
      is set, do the same check, but softly. */
4252
4274
Lines 4274-4292 Link Here
4274
	  tls_in.active.sock >= 0 ? " TLS" : "", host_and_ident(FALSE));
4296
	  tls_in.active.sock >= 0 ? " TLS" : "", host_and_ident(FALSE));
4275
4297
4276
	/* Verify if configured. This doesn't give much security, but it does
4298
	/* Verify if configured. This doesn't give much security, but it does
4277
	make some people happy to be able to do it. If helo_required is set,
4299
	make some people happy to be able to do it. If helo_verify_required is set,
4278
	(host matches helo_verify_hosts) failure forces rejection. If helo_verify
4300
	(host matches helo_verify_hosts) failure forces rejection. If helo_verify
4279
	is set (host matches helo_try_verify_hosts), it does not. This is perhaps
4301
	is set (host matches helo_try_verify_hosts), it does not. This is perhaps
4280
	now obsolescent, since the verification can now be requested selectively
4302
	now obsolescent, since the verification can now be requested selectively
4281
	at ACL time. */
4303
	at ACL time. */
4282
4304
4283
	f.helo_verified = f.helo_verify_failed = sender_helo_dnssec = FALSE;
4305
	f.helo_verified = f.helo_verify_failed = sender_helo_dnssec = FALSE;
4284
	if (fl.helo_required || fl.helo_verify)
4306
	if (fl.helo_verify_required || fl.helo_verify)
4285
	  {
4307
	  {
4286
	  BOOL tempfail = !smtp_verify_helo();
4308
	  BOOL tempfail = !smtp_verify_helo();
4287
	  if (!f.helo_verified)
4309
	  if (!f.helo_verified)
4288
	    {
4310
	    {
4289
	    if (fl.helo_required)
4311
	    if (fl.helo_verify_required)
4290
	      {
4312
	      {
4291
	      smtp_printf("%d %s argument does not match calling host\r\n", FALSE,
4313
	      smtp_printf("%d %s argument does not match calling host\r\n", FALSE,
4292
		tempfail? 451 : 550, hello);
4314
		tempfail? 451 : 550, hello);
Lines 4342-4352 Link Here
4342
      fl.smtputf8_advertised = FALSE;
4364
      fl.smtputf8_advertised = FALSE;
4343
#endif
4365
#endif
4344
4366
4367
      /* Expand the per-connection message count limit option */
4368
      smtp_mailcmd_max = expand_mailmax(smtp_accept_max_per_connection);
4369
4345
      smtp_code = US"250 ";        /* Default response code plus space*/
4370
      smtp_code = US"250 ";        /* Default response code plus space*/
4346
      if (!user_msg)
4371
      if (!user_msg)
4347
	{
4372
	{
4348
	/* sender_host_name below will be tainted, so save on copy when we hit it */
4373
	/* sender_host_name below will be tainted, so save on copy when we hit it */
4349
	g = string_get_tainted(24, TRUE);
4374
	g = string_get_tainted(24, GET_TAINTED);
4350
	g = string_fmt_append(g, "%.3s %s Hello %s%s%s",
4375
	g = string_fmt_append(g, "%.3s %s Hello %s%s%s",
4351
	  smtp_code,
4376
	  smtp_code,
4352
	  smtp_active_hostname,
4377
	  smtp_active_hostname,
Lines 4401-4406 Link Here
4401
	  g = string_catn(g, US"-SIZE\r\n", 7);
4426
	  g = string_catn(g, US"-SIZE\r\n", 7);
4402
	  }
4427
	  }
4403
4428
4429
#ifdef EXPERIMENTAL_ESMTP_LIMITS
4430
	if (  (smtp_mailcmd_max > 0 || recipients_max)
4431
	   && verify_check_host(&limits_advertise_hosts) == OK)
4432
	  {
4433
	  g = string_fmt_append(g, "%.3s-LIMITS", smtp_code);
4434
	  if (smtp_mailcmd_max > 0)
4435
	    g = string_fmt_append(g, " MAILMAX=%d", smtp_mailcmd_max);
4436
	  if (recipients_max)
4437
	    g = string_fmt_append(g, " RCPTMAX=%d", recipients_max);
4438
	  g = string_catn(g, US"\r\n", 2);
4439
	  }
4440
#endif
4441
4404
	/* Exim does not do protocol conversion or data conversion. It is 8-bit
4442
	/* Exim does not do protocol conversion or data conversion. It is 8-bit
4405
	clean; if it has an 8-bit character in its hand, it just sends it. It
4443
	clean; if it has an 8-bit character in its hand, it just sends it. It
4406
	cannot therefore specify 8BITMIME and remain consistent with the RFCs.
4444
	cannot therefore specify 8BITMIME and remain consistent with the RFCs.
Lines 4577-4595 Link Here
4577
# endif
4615
# endif
4578
      else
4616
      else
4579
#endif
4617
#endif
4618
	(void) fwrite(g->s, 1, g->ptr, smtp_out);
4580
4619
4581
	{
4620
      DEBUG(D_receive) for (const uschar * t, * s = string_from_gstring(g);
4582
	int i = fwrite(g->s, 1, g->ptr, smtp_out); i = i; /* compiler quietening */
4621
			    s && (t = Ustrchr(s, '\r'));
4583
	}
4622
			    s = t + 2)				/* \r\n */
4584
      DEBUG(D_receive)
4623
	  debug_printf("%s %.*s\n",
4585
	{
4624
			s == g->s ? "SMTP>>" : "      ",
4586
	uschar *cr;
4625
			(int)(t - s), s);
4587
4588
	(void) string_from_gstring(g);
4589
	while ((cr = Ustrchr(g->s, '\r')) != NULL)   /* lose CRs */
4590
	  memmove(cr, cr + 1, (g->ptr--) - (cr - g->s));
4591
	debug_printf("SMTP>> %s", g->s);
4592
	}
4593
      fl.helo_seen = TRUE;
4626
      fl.helo_seen = TRUE;
4594
4627
4595
      /* Reset the protocol and the state, abandoning any previous message. */
4628
      /* Reset the protocol and the state, abandoning any previous message. */
Lines 4615-4630 Link Here
4615
    case MAIL_CMD:
4648
    case MAIL_CMD:
4616
      HAD(SCH_MAIL);
4649
      HAD(SCH_MAIL);
4617
      smtp_mailcmd_count++;              /* Count for limit and ratelimit */
4650
      smtp_mailcmd_count++;              /* Count for limit and ratelimit */
4651
      message_start();
4618
      was_rej_mail = TRUE;               /* Reset if accepted */
4652
      was_rej_mail = TRUE;               /* Reset if accepted */
4619
      env_mail_type_t * mail_args;       /* Sanity check & validate args */
4653
      env_mail_type_t * mail_args;       /* Sanity check & validate args */
4620
4654
4621
      if (fl.helo_required && !fl.helo_seen)
4655
      if (!fl.helo_seen)
4622
	{
4656
	if (  fl.helo_verify_required
4623
	smtp_printf("503 HELO or EHLO required\r\n", FALSE);
4657
	   || verify_check_host(&hosts_require_helo) == OK)
4624
	log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL from %s: no "
4658
	  {
4625
	  "HELO/EHLO given", host_and_ident(FALSE));
4659
	  smtp_printf("503 HELO or EHLO required\r\n", FALSE);
4626
	break;
4660
	  log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL from %s: no "
4627
	}
4661
	    "HELO/EHLO given", host_and_ident(FALSE));
4662
	  break;
4663
	  }
4664
	else if (smtp_mailcmd_max < 0)
4665
	  smtp_mailcmd_max = expand_mailmax(smtp_accept_max_per_connection);
4628
4666
4629
      if (sender_address)
4667
      if (sender_address)
4630
	{
4668
	{
Lines 4643-4650 Link Here
4643
      /* Check to see if the limit for messages per connection would be
4681
      /* Check to see if the limit for messages per connection would be
4644
      exceeded by accepting further messages. */
4682
      exceeded by accepting further messages. */
4645
4683
4646
      if (smtp_accept_max_per_connection > 0 &&
4684
      if (smtp_mailcmd_max > 0 && smtp_mailcmd_count > smtp_mailcmd_max)
4647
	  smtp_mailcmd_count > smtp_accept_max_per_connection)
4648
	{
4685
	{
4649
	smtp_printf("421 too many messages in this connection\r\n", FALSE);
4686
	smtp_printf("421 too many messages in this connection\r\n", FALSE);
4650
	log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL command %s: too many "
4687
	log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL command %s: too many "
Lines 5042-5048 Link Here
5042
      count this as a protocol error. Reset was_rej_mail so that further RCPTs
5079
      count this as a protocol error. Reset was_rej_mail so that further RCPTs
5043
      get the same treatment. */
5080
      get the same treatment. */
5044
5081
5045
      if (sender_address == NULL)
5082
      if (!sender_address)
5046
	{
5083
	{
5047
	if (f.smtp_in_pipelining_advertised && last_was_rej_mail)
5084
	if (f.smtp_in_pipelining_advertised && last_was_rej_mail)
5048
	  {
5085
	  {
Lines 5061-5067 Link Here
5061
5098
5062
      /* Check for an operand */
5099
      /* Check for an operand */
5063
5100
5064
      if (smtp_cmd_data[0] == 0)
5101
      if (!smtp_cmd_data[0])
5065
	{
5102
	{
5066
	done = synprot_error(L_smtp_syntax_error, 501, NULL,
5103
	done = synprot_error(L_smtp_syntax_error, 501, NULL,
5067
	  US"RCPT must have an address operand");
5104
	  US"RCPT must have an address operand");
Lines 5352-5358 Link Here
5352
#endif
5389
#endif
5353
      if (!discarded && recipients_count <= 0)
5390
      if (!discarded && recipients_count <= 0)
5354
	{
5391
	{
5355
	if (fl.rcpt_smtp_response_same && rcpt_smtp_response != NULL)
5392
	if (fl.rcpt_smtp_response_same && rcpt_smtp_response)
5356
	  {
5393
	  {
5357
	  uschar *code = US"503";
5394
	  uschar *code = US"503";
5358
	  int len = Ustrlen(rcpt_smtp_response);
5395
	  int len = Ustrlen(rcpt_smtp_response);
Lines 5402-5408 Link Here
5402
	ACL may have delayed.  To handle cutthrough delivery enforce a dummy call
5439
	ACL may have delayed.  To handle cutthrough delivery enforce a dummy call
5403
	to get the DATA command sent. */
5440
	to get the DATA command sent. */
5404
5441
5405
	if (acl_smtp_predata == NULL && cutthrough.cctx.sock < 0)
5442
	if (!acl_smtp_predata && cutthrough.cctx.sock < 0)
5406
	  rc = OK;
5443
	  rc = OK;
5407
	else
5444
	else
5408
	  {
5445
	  {
Lines 5555-5561 Link Here
5555
      Pipelining sync checks will normally have protected us too, unless disabled
5592
      Pipelining sync checks will normally have protected us too, unless disabled
5556
      by configuration. */
5593
      by configuration. */
5557
5594
5558
      if (receive_smtp_buffered())
5595
      if (receive_hasc())
5559
	{
5596
	{
5560
	DEBUG(D_any)
5597
	DEBUG(D_any)
5561
	  debug_printf("Non-empty input buffer after STARTTLS; naive attack?\n");
5598
	  debug_printf("Non-empty input buffer after STARTTLS; naive attack?\n");
Lines 5582-5588 Link Here
5582
      STARTTLS that don't add to the nonmail command count. */
5619
      STARTTLS that don't add to the nonmail command count. */
5583
5620
5584
      s = NULL;
5621
      s = NULL;
5585
      if ((rc = tls_server_start(tls_require_ciphers, &s)) == OK)
5622
      if ((rc = tls_server_start(&s)) == OK)
5586
	{
5623
	{
5587
	if (!tls_remember_esmtp)
5624
	if (!tls_remember_esmtp)
5588
	  fl.helo_seen = fl.esmtp = fl.auth_advertised = f.smtp_in_pipelining_advertised = FALSE;
5625
	  fl.helo_seen = fl.esmtp = fl.auth_advertised = f.smtp_in_pipelining_advertised = FALSE;
Lines 5644-5649 Link Here
5644
	some sense is perhaps "right". */
5681
	some sense is perhaps "right". */
5645
5682
5646
	case QUIT_CMD:
5683
	case QUIT_CMD:
5684
	  f.smtp_in_quit = TRUE;
5647
	  user_msg = NULL;
5685
	  user_msg = NULL;
5648
	  if (  acl_smtp_quit
5686
	  if (  acl_smtp_quit
5649
	     && ((rc = acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, &user_msg,
5687
	     && ((rc = acl_check(ACL_WHERE_QUIT, NULL, acl_smtp_quit, &user_msg,
Lines 5788-5794 Link Here
5788
	etrn_command = smtp_etrn_command;
5826
	etrn_command = smtp_etrn_command;
5789
	deliver_domain = smtp_cmd_data;
5827
	deliver_domain = smtp_cmd_data;
5790
	rc = transport_set_up_command(&argv, smtp_etrn_command, TRUE, 0, NULL,
5828
	rc = transport_set_up_command(&argv, smtp_etrn_command, TRUE, 0, NULL,
5791
	  US"ETRN processing", &error);
5829
	  FALSE, US"ETRN processing", &error);
5792
	deliver_domain = NULL;
5830
	deliver_domain = NULL;
5793
	if (!rc)
5831
	if (!rc)
5794
	  {
5832
	  {
Lines 5865-5870 Link Here
5865
	  {
5903
	  {
5866
	  DEBUG(D_exec) debug_print_argv(argv);
5904
	  DEBUG(D_exec) debug_print_argv(argv);
5867
	  exim_nullstd();                   /* Ensure std{in,out,err} exist */
5905
	  exim_nullstd();                   /* Ensure std{in,out,err} exist */
5906
	  /* argv[0] should be untainted, from child_exec_exim() */
5868
	  execv(CS argv[0], (char *const *)argv);
5907
	  execv(CS argv[0], (char *const *)argv);
5869
	  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "exec of \"%s\" (ETRN) failed: %s",
5908
	  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "exec of \"%s\" (ETRN) failed: %s",
5870
	    etrn_command, strerror(errno));
5909
	    etrn_command, strerror(errno));
Lines 5993-5999 Link Here
5993
  COMMAND_LOOP:
6032
  COMMAND_LOOP:
5994
  last_was_rej_mail = was_rej_mail;     /* Remember some last commands for */
6033
  last_was_rej_mail = was_rej_mail;     /* Remember some last commands for */
5995
  last_was_rcpt = was_rcpt;             /* protocol error handling */
6034
  last_was_rcpt = was_rcpt;             /* protocol error handling */
5996
  continue;
5997
  }
6035
  }
5998
6036
5999
return done - 2;  /* Convert yield values */
6037
return done - 2;  /* Convert yield values */
(-)exim.orig/src/smtp_out.c (-86 / +193 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* A number of functions for driving outgoing SMTP calls. */
9
/* A number of functions for driving outgoing SMTP calls. */
Lines 27-33 Link Here
27
               which case the function does nothing
27
               which case the function does nothing
28
  host_af    AF_INET or AF_INET6 for the outgoing IP address
28
  host_af    AF_INET or AF_INET6 for the outgoing IP address
29
  addr       the mail address being handled (for setting errors)
29
  addr       the mail address being handled (for setting errors)
30
  interface  point this to the interface
30
  interface  point this to the interface if there is one defined
31
  msg        to add to any error message
31
  msg        to add to any error message
32
32
33
Returns:     TRUE on success, FALSE on failure, with error message
33
Returns:     TRUE on success, FALSE on failure, with error message
Lines 67-76 Link Here
67
Uskip_whitespace(&expint);
67
Uskip_whitespace(&expint);
68
if (!*expint) return TRUE;
68
if (!*expint) return TRUE;
69
69
70
while ((iface = string_nextinlist(&expint, &sep, big_buffer,
70
while ((iface = string_nextinlist(&expint, &sep, NULL, 0)))
71
          big_buffer_size)))
72
  {
71
  {
73
  if (string_is_ip_address(iface, NULL) == 0)
72
  int if_af = string_is_ip_address(iface, NULL);
73
  if (if_af == 0)
74
    {
74
    {
75
    addr->transport_return = PANIC;
75
    addr->transport_return = PANIC;
76
    addr->message = string_sprintf("\"%s\" is not a valid IP "
76
    addr->message = string_sprintf("\"%s\" is not a valid IP "
Lines 79-89 Link Here
79
    return FALSE;
79
    return FALSE;
80
    }
80
    }
81
81
82
  if (((Ustrchr(iface, ':') == NULL)? AF_INET:AF_INET6) == host_af)
82
  if ((if_af == 4 ? AF_INET : AF_INET6) == host_af)
83
    break;
83
    break;
84
  }
84
  }
85
85
86
if (iface) *interface = string_copy(iface);
86
*interface = iface;
87
return TRUE;
87
return TRUE;
88
}
88
}
89
89
Lines 153-177 Link Here
153
153
154
154
155
#ifdef TCP_FASTOPEN
155
#ifdef TCP_FASTOPEN
156
/* Try to record if TFO was attmepted and if it was successfully used.  */
157
156
static void
158
static void
157
tfo_out_check(int sock)
159
tfo_out_check(int sock)
158
{
160
{
161
static BOOL done_once = FALSE;
162
163
if (done_once) return;
164
done_once = TRUE;
165
159
# ifdef __FreeBSD__
166
# ifdef __FreeBSD__
160
struct tcp_info tinfo;
167
struct tcp_info tinfo;
161
int val;
168
socklen_t len = sizeof(tinfo);
162
socklen_t len = sizeof(val);
169
170
/* A getsockopt TCP_FASTOPEN unfortunately returns "was-used" for a TFO/R as
171
well as a TFO/C.  Use what we can of the Linux hack below; reliability issues ditto. */
172
switch (tcp_out_fastopen)
173
  {
174
  case TFO_ATTEMPTED_NODATA:
175
    if (  getsockopt(sock, IPPROTO_TCP, TCP_INFO, &tinfo, &len) == 0
176
       && tinfo.tcpi_state == TCPS_SYN_SENT
177
       && tinfo.__tcpi_unacked > 0
178
       )
179
      {
180
      DEBUG(D_transport|D_v)
181
       debug_printf("TCP_FASTOPEN tcpi_unacked %d\n", tinfo.__tcpi_unacked);
182
      tcp_out_fastopen = TFO_USED_NODATA;
183
      }
184
    break;
185
  /*
186
  case TFO_ATTEMPTED_DATA:
187
  case TFO_ATTEMPTED_DATA:
188
       if (tinfo.tcpi_options & TCPI_OPT_SYN_DATA)   XXX no equvalent as of 12.2
189
  */
190
  }
163
191
164
/* The observability as of 12.1 is not useful as a client, only telling us that
165
a TFO option was used on SYN.  It could have been a TFO-R, or ignored by the
166
server. */
167
168
/*
169
if (tcp_out_fastopen == TFO_ATTEMPTED_NODATA || tcp_out_fastopen == TFO_ATTEMPTED_DATA)
170
  if (getsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN, &val, &len) == 0 && val != 0) {}
171
*/
172
switch (tcp_out_fastopen)
192
switch (tcp_out_fastopen)
173
  {
193
  {
174
  case TFO_ATTEMPTED_NODATA:	tcp_out_fastopen = TFO_USED_NODATA; break;
175
  case TFO_ATTEMPTED_DATA:	tcp_out_fastopen = TFO_USED_DATA; break;
194
  case TFO_ATTEMPTED_DATA:	tcp_out_fastopen = TFO_USED_DATA; break;
176
  default: break; /* compiler quietening */
195
  default: break; /* compiler quietening */
177
  }
196
  }
Lines 233-267 Link Here
233
#endif
252
#endif
234
253
235
254
236
/* Arguments as for smtp_connect(), plus
255
/* Create and bind a socket, given the connect-args.
237
  early_data	if non-NULL, idenmpotent data to be sent -
256
Update those with the state.  Return the fd, or -1 with errno set.
238
		preferably in the TCP SYN segment
239
240
Returns:      connected socket number, or -1 with errno set
241
*/
257
*/
242
258
243
int
259
int
244
smtp_sock_connect(host_item * host, int host_af, int port, uschar * interface,
260
smtp_boundsock(smtp_connect_args * sc)
245
  transport_instance * tb, int timeout, const blob * early_data)
246
{
261
{
262
transport_instance * tb = sc->tblock;
247
smtp_transport_options_block * ob =
263
smtp_transport_options_block * ob =
248
  (smtp_transport_options_block *)tb->options_block;
264
  (smtp_transport_options_block *)tb->options_block;
249
const uschar * dscp = ob->dscp;
265
const uschar * dscp = ob->dscp;
250
int dscp_value;
266
int sock, dscp_value, dscp_level, dscp_option;
251
int dscp_level;
252
int dscp_option;
253
int sock;
254
int save_errno = 0;
255
const blob * fastopen_blob = NULL;
256
267
257
268
if ((sock = ip_socket(SOCK_STREAM, sc->host_af)) < 0)
258
#ifndef DISABLE_EVENT
269
  return -1;
259
deliver_host_address = host->address;
260
deliver_host_port = port;
261
if (event_raise(tb->event_action, US"tcp:connect", NULL)) return -1;
262
#endif
263
264
if ((sock = ip_socket(SOCK_STREAM, host_af)) < 0) return -1;
265
270
266
/* Set TCP_NODELAY; Exim does its own buffering. */
271
/* Set TCP_NODELAY; Exim does its own buffering. */
267
272
Lines 272-278 Link Here
272
/* Set DSCP value, if we can. For now, if we fail to set the value, we don't
277
/* Set DSCP value, if we can. For now, if we fail to set the value, we don't
273
bomb out, just log it and continue in default traffic class. */
278
bomb out, just log it and continue in default traffic class. */
274
279
275
if (dscp && dscp_lookup(dscp, host_af, &dscp_level, &dscp_option, &dscp_value))
280
if (dscp && dscp_lookup(dscp, sc->host_af, &dscp_level, &dscp_option, &dscp_value))
276
  {
281
  {
277
  HDEBUG(D_transport|D_acl|D_v)
282
  HDEBUG(D_transport|D_acl|D_v)
278
    debug_printf_indent("DSCP \"%s\"=%x ", dscp, dscp_value);
283
    debug_printf_indent("DSCP \"%s\"=%x ", dscp, dscp_value);
Lines 281-287 Link Here
281
      debug_printf_indent("failed to set DSCP: %s ", strerror(errno));
286
      debug_printf_indent("failed to set DSCP: %s ", strerror(errno));
282
  /* If the kernel supports IPv4 and IPv6 on an IPv6 socket, we need to set the
287
  /* If the kernel supports IPv4 and IPv6 on an IPv6 socket, we need to set the
283
  option for both; ignore failures here */
288
  option for both; ignore failures here */
284
  if (host_af == AF_INET6 &&
289
  if (sc->host_af == AF_INET6 &&
285
      dscp_lookup(dscp, AF_INET, &dscp_level, &dscp_option, &dscp_value))
290
      dscp_lookup(dscp, AF_INET, &dscp_level, &dscp_option, &dscp_value))
286
    (void) setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value));
291
    (void) setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value));
287
  }
292
  }
Lines 289-352 Link Here
289
/* Bind to a specific interface if requested. Caller must ensure the interface
294
/* Bind to a specific interface if requested. Caller must ensure the interface
290
is the same type (IPv4 or IPv6) as the outgoing address. */
295
is the same type (IPv4 or IPv6) as the outgoing address. */
291
296
292
if (interface && ip_bind(sock, host_af, interface, 0) < 0)
297
if (sc->interface)
293
  {
298
  {
294
  save_errno = errno;
299
  union sockaddr_46 interface_sock;
295
  HDEBUG(D_transport|D_acl|D_v)
300
  EXIM_SOCKLEN_T size = sizeof(interface_sock);
296
    debug_printf_indent("unable to bind outgoing SMTP call to %s: %s", interface,
301
297
    strerror(errno));
302
  if (  ip_bind(sock, sc->host_af, sc->interface, 0) < 0
303
     || getsockname(sock, (struct sockaddr *) &interface_sock, &size) < 0
304
     )
305
    {
306
    HDEBUG(D_transport|D_acl|D_v)
307
      debug_printf_indent("unable to bind outgoing SMTP call to %s: %s", sc->interface,
308
	strerror(errno));
309
    close(sock);
310
    return -1;
311
    }
312
  sending_ip_address = host_ntoa(-1, &interface_sock, NULL, &sending_port);
298
  }
313
  }
299
314
315
sc->sock = sock;
316
return sock;
317
}
318
319
320
/* Arguments:
321
  host        host item containing name and address and port
322
  host_af     AF_INET or AF_INET6
323
  port	      TCP port number
324
  interface   outgoing interface address or NULL
325
  tb          transport
326
  timeout     timeout value or 0
327
  early_data	if non-NULL, idempotent data to be sent -
328
		preferably in the TCP SYN segment
329
	      Special case: non-NULL but with NULL blob.data - caller is
330
	      client-data-first (eg. TLS-on-connect) and a lazy-TCP-connect is
331
	      acceptable.
332
333
Returns:      connected socket number, or -1 with errno set
334
*/
335
336
int
337
smtp_sock_connect(smtp_connect_args * sc, int timeout, const blob * early_data)
338
{
339
smtp_transport_options_block * ob =
340
  (smtp_transport_options_block *)sc->tblock->options_block;
341
int sock;
342
int save_errno = 0;
343
const blob * fastopen_blob = NULL;
344
345
346
#ifndef DISABLE_EVENT
347
deliver_host_address = sc->host->address;
348
deliver_host_port = sc->host->port;
349
if (event_raise(sc->tblock->event_action, US"tcp:connect", NULL, &errno)) return -1;
350
#endif
351
352
if (  (sock = sc->sock) < 0
353
   && (sock = smtp_boundsock(sc)) < 0)
354
  save_errno = errno;
355
sc->sock = -1;
356
300
/* Connect to the remote host, and add keepalive to the socket before returning
357
/* Connect to the remote host, and add keepalive to the socket before returning
301
it, if requested.  If the build supports TFO, request it - and if the caller
358
it, if requested.  If the build supports TFO, request it - and if the caller
302
requested some early-data then include that in the TFO request.  If there is
359
requested some early-data then include that in the TFO request.  If there is
303
early-data but no TFO support, send it after connecting. */
360
early-data but no TFO support, send it after connecting. */
304
361
305
else
362
if (!save_errno)
306
  {
363
  {
307
#ifdef TCP_FASTOPEN
364
#ifdef TCP_FASTOPEN
308
  if (verify_check_given_host(CUSS &ob->hosts_try_fastopen, host) == OK)
365
  /* See if TCP Fast Open usable.  Default is a traditional 3WHS connect */
309
    fastopen_blob = early_data ? early_data : &tcp_fastopen_nodata;
366
  if (verify_check_given_host(CUSS &ob->hosts_try_fastopen, sc->host) == OK)
367
    {
368
    if (!early_data)
369
      fastopen_blob = &tcp_fastopen_nodata;	/* TFO, with no data */
370
    else if (early_data->data)
371
      fastopen_blob = early_data;		/* TFO, with data */
372
# ifdef TCP_FASTOPEN_CONNECT
373
    else
374
      {						/* expecting client data */
375
      debug_printf(" set up lazy-connect\n");
376
      setsockopt(sock, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, US &on, sizeof(on));
377
      /* fastopen_blob = NULL;		 lazy TFO, triggered by data write */
378
      }
379
# endif
380
    }
310
#endif
381
#endif
311
382
312
  if (ip_connect(sock, host_af, host->address, port, timeout, fastopen_blob) < 0)
383
  if (ip_connect(sock, sc->host_af, sc->host->address, sc->host->port, timeout, fastopen_blob) < 0)
313
    save_errno = errno;
384
    save_errno = errno;
314
  else if (early_data && !fastopen_blob && early_data->data && early_data->len)
385
  else if (early_data && !fastopen_blob && early_data->data && early_data->len)
315
    {
386
    {
387
    /* We had some early-data to send, but couldn't do TFO */
316
    HDEBUG(D_transport|D_acl|D_v)
388
    HDEBUG(D_transport|D_acl|D_v)
317
      debug_printf("sending %ld nonTFO early-data\n", (long)early_data->len);
389
      debug_printf("sending %ld nonTFO early-data\n", (long)early_data->len);
318
390
319
#ifdef TCP_QUICKACK
391
#ifdef TCP_QUICKACK_notdef
320
    (void) setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, US &off, sizeof(off));
392
    (void) setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, US &off, sizeof(off));
321
#endif
393
#endif
322
    if (send(sock, early_data->data, early_data->len, 0) < 0)
394
    if (send(sock, early_data->data, early_data->len, 0) < 0)
323
      save_errno = errno;
395
      save_errno = errno;
324
    }
396
    }
397
#ifdef TCP_QUICKACK_notdef
398
  /* Under TFO (with openssl & pipe-conn; testcase 4069, as of
399
  5.10.8-100.fc32.x86_64) this seems to be inop.
400
  Perhaps overwritten when we (client) go -> ESTABLISHED on seeing the 3rd-ACK?
401
  For that case, added at smtp_reap_banner(). */
402
  (void) setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, US &off, sizeof(off));
403
#endif
325
  }
404
  }
326
405
327
/* Either bind() or connect() failed */
406
if (!save_errno)
328
329
if (save_errno != 0)
330
  {
331
  HDEBUG(D_transport|D_acl|D_v)
332
    {
333
    debug_printf_indent(" failed: %s", CUstrerror(save_errno));
334
    if (save_errno == ETIMEDOUT)
335
      debug_printf(" (timeout=%s)", readconf_printtime(timeout));
336
    debug_printf("\n");
337
    }
338
  (void)close(sock);
339
  errno = save_errno;
340
  return -1;
341
  }
342
343
/* Both bind() and connect() succeeded, and any early-data */
344
345
else
346
  {
407
  {
347
  union sockaddr_46 interface_sock;
408
  union sockaddr_46 interface_sock;
348
  EXIM_SOCKLEN_T size = sizeof(interface_sock);
409
  EXIM_SOCKLEN_T size = sizeof(interface_sock);
349
410
411
  /* Both bind() and connect() succeeded, and any early-data */
412
350
  HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" connected\n");
413
  HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" connected\n");
351
  if (getsockname(sock, (struct sockaddr *)(&interface_sock), &size) == 0)
414
  if (getsockname(sock, (struct sockaddr *)(&interface_sock), &size) == 0)
352
    sending_ip_address = host_ntoa(-1, &interface_sock, NULL, &sending_port);
415
    sending_ip_address = host_ntoa(-1, &interface_sock, NULL, &sending_port);
Lines 358-369 Link Here
358
    return -1;
421
    return -1;
359
    }
422
    }
360
423
361
  if (ob->keepalive) ip_keepalive(sock, host->address, TRUE);
424
  if (ob->keepalive) ip_keepalive(sock, sc->host->address, TRUE);
362
#ifdef TCP_FASTOPEN
425
#ifdef TCP_FASTOPEN
363
  tfo_out_check(sock);
426
  tfo_out_check(sock);
364
#endif
427
#endif
365
  return sock;
428
  return sock;
366
  }
429
  }
430
431
/* Either bind() or connect() failed */
432
433
HDEBUG(D_transport|D_acl|D_v)
434
  {
435
  debug_printf_indent(" failed: %s", CUstrerror(save_errno));
436
  if (save_errno == ETIMEDOUT)
437
    debug_printf(" (timeout=%s)", readconf_printtime(timeout));
438
  debug_printf("\n");
439
  }
440
(void)close(sock);
441
errno = save_errno;
442
return -1;
367
}
443
}
368
444
369
445
Lines 396-401 Link Here
396
Arguments:
472
Arguments:
397
  sc	      details for making connection: host, af, interface, transport
473
  sc	      details for making connection: host, af, interface, transport
398
  early_data  if non-NULL, data to be sent - preferably in the TCP SYN segment
474
  early_data  if non-NULL, data to be sent - preferably in the TCP SYN segment
475
	      Special case: non-NULL but with NULL blob.data - caller is
476
	      client-data-first (eg. TLS-on-connect) and a lazy-TCP-connect is
477
	      acceptable.
399
478
400
Returns:      connected socket number, or -1 with errno set
479
Returns:      connected socket number, or -1 with errno set
401
*/
480
*/
Lines 448-455 Link Here
448
  }
527
  }
449
#endif
528
#endif
450
529
451
return smtp_sock_connect(sc->host, sc->host_af, port, sc->interface,
530
return smtp_sock_connect(sc, ob->connect_timeout, early_data);
452
			  sc->tblock, ob->connect_timeout, early_data);
453
}
531
}
454
532
455
533
Lines 474-486 Link Here
474
int rc;
552
int rc;
475
int n = outblock->ptr - outblock->buffer;
553
int n = outblock->ptr - outblock->buffer;
476
BOOL more = mode == SCMD_MORE;
554
BOOL more = mode == SCMD_MORE;
555
client_conn_ctx * cctx;
477
556
478
HDEBUG(D_transport|D_acl) debug_printf_indent("cmd buf flush %d bytes%s\n", n,
557
HDEBUG(D_transport|D_acl) debug_printf_indent("cmd buf flush %d bytes%s\n", n,
479
  more ? " (more expected)" : "");
558
  more ? " (more expected)" : "");
480
559
560
if (!(cctx = outblock->cctx))
561
  {
562
  log_write(0, LOG_MAIN|LOG_PANIC, "null conn-context pointer");
563
  errno = 0;
564
  return FALSE;
565
  }
566
481
#ifndef DISABLE_TLS
567
#ifndef DISABLE_TLS
482
if (outblock->cctx->tls_ctx)
568
if (cctx->tls_ctx)		/*XXX have seen a null cctx here, rvfy sending QUIT, hence check above */
483
  rc = tls_write(outblock->cctx->tls_ctx, outblock->buffer, n, more);
569
  rc = tls_write(cctx->tls_ctx, outblock->buffer, n, more);
484
else
570
else
485
#endif
571
#endif
486
572
Lines 494-500 Link Here
494
    requirement: TFO with data can, in rare cases, replay the data to the
580
    requirement: TFO with data can, in rare cases, replay the data to the
495
    receiver. */
581
    receiver. */
496
582
497
    if (  (outblock->cctx->sock = smtp_connect(outblock->conn_args, &early_data))
583
    if (  (cctx->sock = smtp_connect(outblock->conn_args, &early_data))
498
       < 0)
584
       < 0)
499
      return FALSE;
585
      return FALSE;
500
    outblock->conn_args = NULL;
586
    outblock->conn_args = NULL;
Lines 502-508 Link Here
502
    }
588
    }
503
  else
589
  else
504
    {
590
    {
505
    rc = send(outblock->cctx->sock, outblock->buffer, n,
591
    rc = send(cctx->sock, outblock->buffer, n,
506
#ifdef MSG_MORE
592
#ifdef MSG_MORE
507
	      more ? MSG_MORE : 0
593
	      more ? MSG_MORE : 0
508
#else
594
#else
Lines 517-523 Link Here
517
    https://bugzilla.redhat.com/show_bug.cgi?id=1803806 */
603
    https://bugzilla.redhat.com/show_bug.cgi?id=1803806 */
518
604
519
    if (!more)
605
    if (!more)
520
      setsockopt(outblock->cctx->sock, IPPROTO_TCP, TCP_CORK, &off, sizeof(off));
606
      setsockopt(cctx->sock, IPPROTO_TCP, TCP_CORK, &off, sizeof(off));
521
#endif
607
#endif
522
    }
608
    }
523
  }
609
  }
Lines 535-540 Link Here
535
621
536
622
537
623
624
/* This might be called both due to callout and then from delivery.
625
Use memory that will not be released between those phases.
626
*/
627
static void
628
smtp_debug_resp(const uschar * buf)
629
{
630
#ifndef DISABLE_CLIENT_CMD_LOG
631
int old_pool = store_pool;
632
store_pool = POOL_PERM;
633
client_cmd_log = string_append_listele_n(client_cmd_log, ':', buf,
634
  buf[3] == ' ' ? 3 : 4);
635
store_pool = old_pool;
636
#endif
637
}
638
639
538
/*************************************************
640
/*************************************************
539
*             Write SMTP command                 *
641
*             Write SMTP command                 *
540
*************************************************/
642
*************************************************/
Lines 556-562 Link Here
556
*/
658
*/
557
659
558
int
660
int
559
smtp_write_command(void * sx, int mode, const char *format, ...)
661
smtp_write_command(void * sx, int mode, const char * format, ...)
560
{
662
{
561
smtp_outblock * outblock = &((smtp_context *)sx)->outblock;
663
smtp_outblock * outblock = &((smtp_context *)sx)->outblock;
562
int rc = 0;
664
int rc = 0;
Lines 609-618 Link Here
609
      while (!isspace(*p)) p++;
711
      while (!isspace(*p)) p++;
610
      while (isspace(*p)) p++;
712
      while (isspace(*p)) p++;
611
      }
713
      }
612
    while (*p != 0) *p++ = '*';
714
    while (*p) *p++ = '*';
613
    }
715
    }
614
716
615
  HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP>> %s\n", big_buffer);
717
  smtp_debug_cmd(big_buffer, mode);
616
  }
718
  }
617
719
618
if (mode != SCMD_BUFFER)
720
if (mode != SCMD_BUFFER)
Lines 750-757 Link Here
750
uschar * ptr = buffer;
852
uschar * ptr = buffer;
751
int count = 0;
853
int count = 0;
752
time_t timelimit = time(NULL) + timeout;
854
time_t timelimit = time(NULL) + timeout;
855
BOOL yield = FALSE;
753
856
754
errno = 0;  /* Ensure errno starts out zero */
857
errno = 0;  /* Ensure errno starts out zero */
858
buffer[0] = '\0';
755
859
756
#ifndef DISABLE_PIPE_CONNECT
860
#ifndef DISABLE_PIPE_CONNECT
757
if (sx->pending_BANNER || sx->pending_EHLO)
861
if (sx->pending_BANNER || sx->pending_EHLO)
Lines 760-768 Link Here
760
  if ((rc = smtp_reap_early_pipe(sx, &count)) != OK)
864
  if ((rc = smtp_reap_early_pipe(sx, &count)) != OK)
761
    {
865
    {
762
    DEBUG(D_transport) debug_printf("failed reaping pipelined cmd responsess\n");
866
    DEBUG(D_transport) debug_printf("failed reaping pipelined cmd responsess\n");
763
    buffer[0] = '\0';
764
    if (rc == DEFER) errno = ERRNO_TLSFAILURE;
867
    if (rc == DEFER) errno = ERRNO_TLSFAILURE;
765
    return FALSE;
868
    goto out;
766
    }
869
    }
767
  }
870
  }
768
#endif
871
#endif
Lines 793-799 Link Here
793
     (ptr[3] != '-' && ptr[3] != ' ' && ptr[3] != 0))
896
     (ptr[3] != '-' && ptr[3] != ' ' && ptr[3] != 0))
794
    {
897
    {
795
    errno = ERRNO_SMTPFORMAT;    /* format error */
898
    errno = ERRNO_SMTPFORMAT;    /* format error */
796
    return FALSE;
899
    goto out;
797
    }
900
    }
798
901
799
  /* If the line we have just read is a terminal line, line, we are done.
902
  /* If the line we have just read is a terminal line, line, we are done.
Lines 811-817 Link Here
811
  }
914
  }
812
915
813
#ifdef TCP_FASTOPEN
916
#ifdef TCP_FASTOPEN
814
  tfo_out_check(sx->cctx.sock);
917
tfo_out_check(sx->cctx.sock);
815
#endif
918
#endif
816
919
817
/* Return a value that depends on the SMTP return code. On some systems a
920
/* Return a value that depends on the SMTP return code. On some systems a
Lines 821-827 Link Here
821
timeouts, lost connections, etc. */
924
timeouts, lost connections, etc. */
822
925
823
errno = 0;
926
errno = 0;
824
return buffer[0] == okdigit;
927
yield = buffer[0] == okdigit;
928
929
out:
930
  smtp_debug_resp(buffer);
931
  return yield;
825
}
932
}
826
933
827
/* End of smtp_out.c */
934
/* End of smtp_out.c */
(-)exim.orig/src/spam.c (-58 / +26 lines)
Lines 2-10 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003 - 2015
5
/*
6
 * Copyright (c) The Exim Maintainers 2016 - 2022
7
 * Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003 - 2015
6
 * License: GPL
8
 * License: GPL
7
 * Copyright (c) The Exim Maintainers 2016 - 2020
8
 */
9
 */
9
10
10
/* Code for calling spamassassin's spamd. Called from acl.c. */
11
/* Code for calling spamassassin's spamd. Called from acl.c. */
Lines 35-41 Link Here
35
spamd->weight = SPAMD_WEIGHT;
36
spamd->weight = SPAMD_WEIGHT;
36
spamd->timeout = SPAMD_TIMEOUT;
37
spamd->timeout = SPAMD_TIMEOUT;
37
spamd->retry = 0;
38
spamd->retry = 0;
38
spamd->priority = 1;
39
spamd->priority = SPAMD_PRIORITY;
39
return 0;
40
return 0;
40
}
41
}
41
42
Lines 139-159 Link Here
139
spamd_address_container * sd;
140
spamd_address_container * sd;
140
long weights;
141
long weights;
141
unsigned pri;
142
unsigned pri;
142
static BOOL srandomed = FALSE;
143
143
144
/* speedup, if we have only 1 server */
144
/* speedup, if we have only 1 server */
145
if (num_servers == 1)
145
if (num_servers == 1)
146
  return (spamds[0]->is_failed ? -1 : 0);
146
  return (spamds[0]->is_failed ? -1 : 0);
147
147
148
/* init ranmod */
149
if (!srandomed)
150
  {
151
  struct timeval tv;
152
  gettimeofday(&tv, NULL);
153
  srandom((unsigned int)(tv.tv_usec/1000));
154
  srandomed = TRUE;
155
  }
156
157
/* scan for highest pri */
148
/* scan for highest pri */
158
for (pri = 0, i = 0; i < num_servers; i++)
149
for (pri = 0, i = 0; i < num_servers; i++)
159
  {
150
  {
Lines 170-176 Link Here
170
if (weights == 0)	/* all servers failed */
161
if (weights == 0)	/* all servers failed */
171
  return -1;
162
  return -1;
172
163
173
for (long rnd = random() % weights, i = 0; i < num_servers; i++)
164
for (long rnd = random_number(weights), i = 0; i < num_servers; i++)
174
  {
165
  {
175
  sd = spamds[i];
166
  sd = spamds[i];
176
  if (!sd->is_failed && sd->priority == pri)
167
  if (!sd->is_failed && sd->priority == pri)
Lines 204-215 Link Here
204
int override = 0;
195
int override = 0;
205
time_t start;
196
time_t start;
206
size_t read, wrote;
197
size_t read, wrote;
207
#ifndef NO_POLL_H
208
struct pollfd pollfd;
209
#else                               /* Patch posted by Erik ? for OS X */
210
struct timeval select_tv;         /* and applied by PH */
211
fd_set select_fd;
212
#endif
213
uschar *spamd_address_work;
198
uschar *spamd_address_work;
214
spamd_address_container * sd;
199
spamd_address_container * sd;
215
200
Lines 224-231 Link Here
224
  }
209
  }
225
210
226
/* if username is "0" or "false", do not scan */
211
/* if username is "0" or "false", do not scan */
227
if ( (Ustrcmp(user_name,"0") == 0) ||
212
if (Ustrcmp(user_name, "0") == 0 || strcmpic(user_name, US"false") == 0)
228
     (strcmpic(user_name,US"false") == 0) )
229
  return FAIL;
213
  return FAIL;
230
214
231
/* if there is an additional option, check if it is "true" */
215
/* if there is an additional option, check if it is "true" */
Lines 234-252 Link Here
234
  override = 1;
218
  override = 1;
235
219
236
/* expand spamd_address if needed */
220
/* expand spamd_address if needed */
237
if (*spamd_address == '$')
221
if (*spamd_address != '$')
222
  spamd_address_work = spamd_address;
223
else if (!(spamd_address_work = expand_string(spamd_address)))
238
  {
224
  {
239
  spamd_address_work = expand_string(spamd_address);
225
  log_write(0, LOG_MAIN|LOG_PANIC,
240
  if (spamd_address_work == NULL)
226
    "%s spamd_address starts with $, but expansion failed: %s",
241
    {
227
    loglabel, expand_string_message);
242
    log_write(0, LOG_MAIN|LOG_PANIC,
228
  return DEFER;
243
      "%s spamd_address starts with $, but expansion failed: %s",
244
      loglabel, expand_string_message);
245
    return DEFER;
246
    }
247
  }
229
  }
248
else
249
  spamd_address_work = spamd_address;
250
230
251
DEBUG(D_acl) debug_printf_indent("spamd: addrlist '%s'\n", spamd_address_work);
231
DEBUG(D_acl) debug_printf_indent("spamd: addrlist '%s'\n", spamd_address_work);
252
232
Lines 290-296 Link Here
290
    uschar * s;
270
    uschar * s;
291
271
292
    DEBUG(D_acl) debug_printf_indent("spamd: addr entry '%s'\n", address);
272
    DEBUG(D_acl) debug_printf_indent("spamd: addr entry '%s'\n", address);
293
    sd = store_get(sizeof(spamd_address_container), FALSE);
273
    sd = store_get(sizeof(spamd_address_container), GET_UNTAINTED);
294
274
295
    for (sublist = address, args = 0, spamd_param_init(sd);
275
    for (sublist = address, args = 0, spamd_param_init(sd);
296
	 (s = string_nextinlist(&sublist, &sublist_sep, NULL, 0));
276
	 (s = string_nextinlist(&sublist, &sublist_sep, NULL, 0));
Lines 410-428 Link Here
410
  }
390
  }
411
391
412
/* now send the file */
392
/* now send the file */
413
/* spamd sometimes accepts connections but doesn't read data off
393
/* spamd sometimes accepts connections but doesn't read data off the connection.
414
 * the connection.  We make the file descriptor non-blocking so
394
We make the file descriptor non-blocking so that the write will only write
415
 * that the write will only write sufficient data without blocking
395
sufficient data without blocking and we poll the descriptor to make sure that we
416
 * and we poll the descriptor to make sure that we can write without
396
can write without blocking.  Short writes are gracefully handled and if the
417
 * blocking.  Short writes are gracefully handled and if the whole
397
whole transaction takes too long it is aborted.
418
 * transaction takes too long it is aborted.
398
419
 * Note: poll() is not supported in OSX 10.2 and is reported to be
399
Note: poll() is not supported in OSX 10.2 and is reported to be broken in more
420
 *       broken in more recent versions (up to 10.4).
400
      recent versions (up to 10.4). Workaround using select() removed 2021/11 (jgh).
421
 */
401
 */
422
#ifndef NO_POLL_H
402
#ifdef NO_POLL_H
423
pollfd.fd = spamd_cctx.sock;
403
# error Need poll(2) support
424
pollfd.events = POLLOUT;
425
#endif
404
#endif
405
426
(void)fcntl(spamd_cctx.sock, F_SETFL, O_NONBLOCK);
406
(void)fcntl(spamd_cctx.sock, F_SETFL, O_NONBLOCK);
427
do
407
do
428
  {
408
  {
Lines 431-449 Link Here
431
    {
411
    {
432
    offset = 0;
412
    offset = 0;
433
again:
413
again:
434
#ifndef NO_POLL_H
414
    result = poll_one_fd(spamd_cctx.sock, POLLOUT, 1000);
435
    result = poll(&pollfd, 1, 1000);
436
437
/* Patch posted by Erik ? for OS X and applied by PH */
438
#else
439
    select_tv.tv_sec = 1;
440
    select_tv.tv_usec = 0;
441
    FD_ZERO(&select_fd);
442
    FD_SET(spamd_cctx.sock, &select_fd);
443
    result = select(spamd_cctx.sock+1, NULL, &select_fd, NULL, &select_tv);
444
#endif
445
/* End Erik's patch */
446
447
    if (result == -1 && errno == EINTR)
415
    if (result == -1 && errno == EINTR)
448
      goto again;
416
      goto again;
449
    else if (result < 1)
417
    else if (result < 1)
(-)exim.orig/src/spam.h (-1 / +3 lines)
Lines 3-8 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003 - 2015 */
5
/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003 - 2015 */
6
/* Copyright (c) The Exim Maintainers 2021 */
6
/* License: GPL */
7
/* License: GPL */
7
8
8
/* spam defines */
9
/* spam defines */
Lines 21-28 Link Here
21
# define SHUT_WR 1
22
# define SHUT_WR 1
22
#endif
23
#endif
23
24
24
/* default weight */
25
/* Defaults */
25
#define SPAMD_WEIGHT 1
26
#define SPAMD_WEIGHT 1
27
#define SPAMD_PRIORITY 1
26
28
27
typedef struct spamd_address_container
29
typedef struct spamd_address_container
28
{
30
{
(-)exim.orig/src/spf.c (-7 / +16 lines)
Lines 3-11 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* SPF support.
5
/* SPF support.
6
   Copyright (c) The Exim Maintainers 2015 - 2022
6
   Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004 - 2014
7
   Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004 - 2014
7
   License: GPL
8
   License: GPL
8
   Copyright (c) The Exim Maintainers 2015 - 2020
9
*/
9
*/
10
10
11
/* Code for calling spf checks via libspf-alt. Called from acl.c. */
11
/* Code for calling spf checks via libspf-alt. Called from acl.c. */
Lines 34-48 Link Here
34
SPF_dns_rr_t  * spf_nxdomain = NULL;
34
SPF_dns_rr_t  * spf_nxdomain = NULL;
35
35
36
36
37
void
37
gstring *
38
spf_lib_version_report(FILE * fp)
38
spf_lib_version_report(gstring * g)
39
{
39
{
40
int maj, min, patch;
40
int maj, min, patch;
41
41
SPF_get_lib_version(&maj, &min, &patch);
42
SPF_get_lib_version(&maj, &min, &patch);
42
fprintf(fp, "Library version: spf2: Compile: %d.%d.%d\n",
43
g = string_fmt_append(g, "Library version: spf2: Compile: %d.%d.%d\n",
43
	SPF_LIB_VERSION_MAJOR, SPF_LIB_VERSION_MINOR, SPF_LIB_VERSION_PATCH);
44
	SPF_LIB_VERSION_MAJOR, SPF_LIB_VERSION_MINOR, SPF_LIB_VERSION_PATCH);
44
fprintf(fp, "                       Runtime: %d.%d.%d\n",
45
g = string_fmt_append(g,    "                       Runtime: %d.%d.%d\n",
45
	 maj, min, patch);
46
	 maj, min, patch);
47
return g;
46
}
48
}
47
49
48
50
Lines 80-85 Link Here
80
  HDEBUG(D_host_lookup) debug_printf("faking NO_DATA for SPF RR(99) lookup\n");
82
  HDEBUG(D_host_lookup) debug_printf("faking NO_DATA for SPF RR(99) lookup\n");
81
  srr.herrno = NO_DATA;
83
  srr.herrno = NO_DATA;
82
  SPF_dns_rr_dup(&spfrr, &srr);
84
  SPF_dns_rr_dup(&spfrr, &srr);
85
  store_free_dns_answer(dnsa);
83
  return spfrr;
86
  return spfrr;
84
  }
87
  }
85
88
Lines 100-105 Link Here
100
if (found == 0)
103
if (found == 0)
101
  {
104
  {
102
  SPF_dns_rr_dup(&spfrr, &srr);
105
  SPF_dns_rr_dup(&spfrr, &srr);
106
  store_free_dns_answer(dnsa);
103
  return spfrr;
107
  return spfrr;
104
  }
108
  }
105
109
Lines 171-176 Link Here
171
175
172
/* spfrr->rr must have been malloc()d for this */
176
/* spfrr->rr must have been malloc()d for this */
173
SPF_dns_rr_dup(&spfrr, &srr);
177
SPF_dns_rr_dup(&spfrr, &srr);
178
store_free_dns_answer(dnsa);
174
return spfrr;
179
return spfrr;
175
}
180
}
176
181
Lines 248-254 Link Here
248
if (!(s = expand_string(spf_smtp_comment_template)))
253
if (!(s = expand_string(spf_smtp_comment_template)))
249
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "expansion of spf_smtp_comment_template failed");
254
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "expansion of spf_smtp_comment_template failed");
250
255
251
SPF_server_set_explanation(spf_server, s, &spf_response);
256
SPF_server_set_explanation(spf_server, CCS s, &spf_response);
252
if (SPF_response_errcode(spf_response) != SPF_E_SUCCESS)
257
if (SPF_response_errcode(spf_response) != SPF_E_SUCCESS)
253
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", SPF_strerror(SPF_response_errcode(spf_response)));
258
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", SPF_strerror(SPF_response_errcode(spf_response)));
254
259
Lines 402-409 Link Here
402
  g = string_cat(g, US" (best guess record for domain)");
407
  g = string_cat(g, US" (best guess record for domain)");
403
408
404
s = expand_string(US"$sender_address_domain");
409
s = expand_string(US"$sender_address_domain");
410
if (s && *s)
411
  return string_append(g, 2, US" smtp.mailfrom=", s);
412
413
s = sender_helo_name;
405
return s && *s
414
return s && *s
406
  ? string_append(g, 2, US" smtp.mailfrom=", s)
415
  ? string_append(g, 2, US" smtp.helo=", s)
407
  : string_cat(g, US" smtp.mailfrom=<>");
416
  : string_cat(g, US" smtp.mailfrom=<>");
408
}
417
}
409
418
(-)exim.orig/src/spf.h (-2 / +2 lines)
Lines 3-11 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Experimental SPF support.
5
/* Experimental SPF support.
6
   Copyright (c) The Exim Maintainers 2016 - 2022
6
   Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004
7
   Copyright (c) Tom Kistner <tom@duncanthrax.net> 2004
7
   License: GPL
8
   License: GPL
8
   Copyright (c) The Exim Maintainers 2016 - 2020
9
*/
9
*/
10
10
11
#ifdef SUPPORT_SPF
11
#ifdef SUPPORT_SPF
Lines 25-31 Link Here
25
} spf_result_id;
25
} spf_result_id;
26
26
27
/* prototypes */
27
/* prototypes */
28
void spf_lib_version_report(FILE *);
28
gstring * spf_lib_version_report(gstring *);
29
BOOL spf_init(void);
29
BOOL spf_init(void);
30
BOOL spf_conn_init(uschar *, uschar *);
30
BOOL spf_conn_init(uschar *, uschar *);
31
int  spf_process(const uschar **, uschar *, int);
31
int  spf_process(const uschar **, uschar *, int);
(-)exim.orig/src/spool_in.c (-47 / +123 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Functions for reading spool files. When compiling for a utility (eximon),
9
/* Functions for reading spool files. When compiling for a utility (eximon),
Lines 186-192 Link Here
186
186
187
if (n < 5) return FALSE;    /* malformed line */
187
if (n < 5) return FALSE;    /* malformed line */
188
buffer[n-1] = 0;            /* Remove \n */
188
buffer[n-1] = 0;            /* Remove \n */
189
node = store_get(sizeof(tree_node) + n - 3, TRUE);	/* rcpt names tainted */
189
node = store_get(sizeof(tree_node) + n - 3, GET_TAINTED);	/* rcpt names tainted */
190
*connect = node;
190
*connect = node;
191
Ustrcpy(node->name, buffer + 3);
191
Ustrcpy(node->name, buffer + 3);
192
node->data.ptr = NULL;
192
node->data.ptr = NULL;
Lines 300-305 Link Here
300
message_utf8_downconvert = 0;
300
message_utf8_downconvert = 0;
301
#endif
301
#endif
302
302
303
#ifndef COMPILE_UTILITY
304
debuglog_name[0] = '\0';
305
#endif
303
dsn_ret = 0;
306
dsn_ret = 0;
304
dsn_envid = NULL;
307
dsn_envid = NULL;
305
}
308
}
Lines 442-448 Link Here
442
if (n < 3 || big_buffer[0] != '<' || big_buffer[n-2] != '>')
445
if (n < 3 || big_buffer[0] != '<' || big_buffer[n-2] != '>')
443
  goto SPOOL_FORMAT_ERROR;
446
  goto SPOOL_FORMAT_ERROR;
444
447
445
sender_address = store_get(n-2, TRUE);	/* tainted */
448
sender_address = store_get(n-2, GET_TAINTED);
446
Ustrncpy(sender_address, big_buffer+1, n-3);
449
Ustrncpy(sender_address, big_buffer+1, n-3);
447
sender_address[n-3] = 0;
450
sender_address[n-3] = 0;
448
451
Lines 451-456 Link Here
451
if (sscanf(CS big_buffer, TIME_T_FMT " %d", &received_time.tv_sec, &warning_count) != 2)
454
if (sscanf(CS big_buffer, TIME_T_FMT " %d", &received_time.tv_sec, &warning_count) != 2)
452
  goto SPOOL_FORMAT_ERROR;
455
  goto SPOOL_FORMAT_ERROR;
453
received_time.tv_usec = 0;
456
received_time.tv_usec = 0;
457
received_time_complete = received_time;
458
454
459
455
message_age = time(NULL) - received_time.tv_sec;
460
message_age = time(NULL) - received_time.tv_sec;
456
#ifndef COMPILE_UTILITY
461
#ifndef COMPILE_UTILITY
Lines 477-487 Link Here
477
that we don't recognize. Otherwise it wouldn't be possible to back off a new
482
that we don't recognize. Otherwise it wouldn't be possible to back off a new
478
version that left new-style flags written on the spool.
483
version that left new-style flags written on the spool.
479
484
480
If the line starts with "--" the content of the variable is tainted.  */
485
If the line starts with "--" the content of the variable is tainted.
486
If the line start "--(<lookuptype>)" it is also quoted for the given <lookuptype>.
487
*/
481
488
482
for (;;)
489
for (;;)
483
  {
490
  {
484
  BOOL tainted;
491
  const void * proto_mem;
485
  uschar * var;
492
  uschar * var;
486
  const uschar * p;
493
  const uschar * p;
487
494
Lines 489-496 Link Here
489
  if (big_buffer[0] != '-') break;
496
  if (big_buffer[0] != '-') break;
490
  big_buffer[Ustrlen(big_buffer)-1] = 0;
497
  big_buffer[Ustrlen(big_buffer)-1] = 0;
491
498
492
  tainted = big_buffer[1] == '-';
499
  proto_mem = big_buffer[1] == '-' ? GET_TAINTED : GET_UNTAINTED;
493
  var =  big_buffer + (tainted ? 2 : 1);
500
  var =  big_buffer + (proto_mem == GET_UNTAINTED ? 1 : 2);
501
  if (*var == '(')				/* marker for quoted value */
502
    {
503
    uschar * s;
504
    int idx;
505
    for (s = ++var; *s != ')'; ) s++;
506
#ifndef COMPILE_UTILITY
507
    if ((idx = search_findtype(var, s - var)) < 0)
508
      {
509
      DEBUG(D_any) debug_printf("Unrecognised quoter %.*s\n", (int)(s - var), var+1);
510
      goto SPOOL_FORMAT_ERROR;
511
      }
512
    proto_mem = store_get_quoted(1, GET_TAINTED, idx);
513
#endif  /* COMPILE_UTILITY */
514
    var = s + 1;
515
    }
494
  p = var + 1;
516
  p = var + 1;
495
517
496
  switch(*var)
518
  switch(*var)
Lines 514-520 Link Here
514
        (int)(endptr - var - 5), var + 5);
536
        (int)(endptr - var - 5), var + 5);
515
      if (sscanf(CS endptr, " %d", &count) != 1) goto SPOOL_FORMAT_ERROR;
537
      if (sscanf(CS endptr, " %d", &count) != 1) goto SPOOL_FORMAT_ERROR;
516
      node = acl_var_create(name);
538
      node = acl_var_create(name);
517
      node->data.ptr = store_get(count + 1, tainted);
539
      node->data.ptr = store_get(count + 1, proto_mem);
518
      if (fread(node->data.ptr, 1, count+1, fp) < count) goto SPOOL_READ_ERROR;
540
      if (fread(node->data.ptr, 1, count+1, fp) < count) goto SPOOL_READ_ERROR;
519
      ((uschar*)node->data.ptr)[count] = 0;
541
      ((uschar*)node->data.ptr)[count] = 0;
520
      }
542
      }
Lines 525-535 Link Here
525
      f.allow_unqualified_sender = TRUE;
547
      f.allow_unqualified_sender = TRUE;
526
548
527
    else if (Ustrncmp(p, "uth_id", 6) == 0)
549
    else if (Ustrncmp(p, "uth_id", 6) == 0)
528
      authenticated_id = string_copy_taint(var + 8, tainted);
550
      authenticated_id = string_copy_taint(var + 8, proto_mem);
529
    else if (Ustrncmp(p, "uth_sender", 10) == 0)
551
    else if (Ustrncmp(p, "uth_sender", 10) == 0)
530
      authenticated_sender = string_copy_taint(var + 12, tainted);
552
      authenticated_sender = string_copy_taint(var + 12, proto_mem);
531
    else if (Ustrncmp(p, "ctive_hostname", 14) == 0)
553
    else if (Ustrncmp(p, "ctive_hostname", 14) == 0)
532
      smtp_active_hostname = string_copy_taint(var + 16, tainted);
554
      smtp_active_hostname = string_copy_taint(var + 16, proto_mem);
533
555
534
    /* For long-term backward compatibility, we recognize "-acl", which was
556
    /* For long-term backward compatibility, we recognize "-acl", which was
535
    used before the number of ACL variables changed from 10 to 20. This was
557
    used before the number of ACL variables changed from 10 to 20. This was
Lines 553-559 Link Here
553
      else
575
      else
554
        (void) string_format(name, sizeof(name), "%c%u", 'm', index - 10);
576
        (void) string_format(name, sizeof(name), "%c%u", 'm', index - 10);
555
      node = acl_var_create(name);
577
      node = acl_var_create(name);
556
      node->data.ptr = store_get(count + 1, tainted);
578
      node->data.ptr = store_get(count + 1, proto_mem);
557
      /* We sanity-checked the count, so disable the Coverity error */
579
      /* We sanity-checked the count, so disable the Coverity error */
558
      /* coverity[tainted_data] */
580
      /* coverity[tainted_data] */
559
      if (fread(node->data.ptr, 1, count+1, fp) < count) goto SPOOL_READ_ERROR;
581
      if (fread(node->data.ptr, 1, count+1, fp) < count) goto SPOOL_READ_ERROR;
Lines 568-585 Link Here
568
      body_zerocount = Uatoi(var + 14);
590
      body_zerocount = Uatoi(var + 14);
569
#ifdef EXPERIMENTAL_BRIGHTMAIL
591
#ifdef EXPERIMENTAL_BRIGHTMAIL
570
    else if (Ustrncmp(p, "mi_verdicts ", 12) == 0)
592
    else if (Ustrncmp(p, "mi_verdicts ", 12) == 0)
571
      bmi_verdicts = string_copy_taint(var + 13, tainted);
593
      bmi_verdicts = string_copy_taint(var + 13, proto_mem);
572
#endif
594
#endif
573
    break;
595
    break;
574
596
575
    case 'd':
597
    case 'd':
576
    if (Ustrcmp(p, "eliver_firsttime") == 0)
598
    if (Ustrcmp(p, "eliver_firsttime") == 0)
577
      f.deliver_firsttime = TRUE;
599
      f.deliver_firsttime = TRUE;
578
    /* Check if the dsn flags have been set in the header file */
579
    else if (Ustrncmp(p, "sn_ret", 6) == 0)
600
    else if (Ustrncmp(p, "sn_ret", 6) == 0)
580
      dsn_ret= atoi(CS var + 7);
601
      dsn_ret= atoi(CS var + 7);
581
    else if (Ustrncmp(p, "sn_envid", 8) == 0)
602
    else if (Ustrncmp(p, "sn_envid", 8) == 0)
582
      dsn_envid = string_copy_taint(var + 10, tainted);
603
      dsn_envid = string_copy_taint(var + 10, proto_mem);
604
#ifndef COMPILE_UTILITY
605
    else if (Ustrncmp(p, "ebug_selector ", 14) == 0)
606
      debug_selector = strtol(CS var + 15, NULL, 0);
607
    else if (Ustrncmp(p, "ebuglog_name ", 13) == 0)
608
      debug_logging_from_spool(var + 14);
609
#endif
583
    break;
610
    break;
584
611
585
    case 'f':
612
    case 'f':
Lines 597-609 Link Here
597
    else if (Ustrcmp(p, "ost_lookup_failed") == 0)
624
    else if (Ustrcmp(p, "ost_lookup_failed") == 0)
598
      host_lookup_failed = TRUE;
625
      host_lookup_failed = TRUE;
599
    else if (Ustrncmp(p, "ost_auth_pubname", 16) == 0)
626
    else if (Ustrncmp(p, "ost_auth_pubname", 16) == 0)
600
      sender_host_auth_pubname = string_copy_taint(var + 18, tainted);
627
      sender_host_auth_pubname = string_copy_taint(var + 18, proto_mem);
601
    else if (Ustrncmp(p, "ost_auth", 8) == 0)
628
    else if (Ustrncmp(p, "ost_auth", 8) == 0)
602
      sender_host_authenticated = string_copy_taint(var + 10, tainted);
629
      sender_host_authenticated = string_copy_taint(var + 10, proto_mem);
603
    else if (Ustrncmp(p, "ost_name", 8) == 0)
630
    else if (Ustrncmp(p, "ost_name", 8) == 0)
604
      sender_host_name = string_copy_taint(var + 10, tainted);
631
      sender_host_name = string_copy_taint(var + 10, proto_mem);
605
    else if (Ustrncmp(p, "elo_name", 8) == 0)
632
    else if (Ustrncmp(p, "elo_name", 8) == 0)
606
      sender_helo_name = string_copy_taint(var + 10, tainted);
633
      sender_helo_name = string_copy_taint(var + 10, proto_mem);
607
634
608
    /* We now record the port number after the address, separated by a
635
    /* We now record the port number after the address, separated by a
609
    dot. For compatibility during upgrading, do nothing if there
636
    dot. For compatibility during upgrading, do nothing if there
Lines 612-618 Link Here
612
    else if (Ustrncmp(p, "ost_address", 11) == 0)
639
    else if (Ustrncmp(p, "ost_address", 11) == 0)
613
      {
640
      {
614
      sender_host_port = host_address_extract_port(var + 13);
641
      sender_host_port = host_address_extract_port(var + 13);
615
      sender_host_address = string_copy_taint(var + 13, tainted);
642
      sender_host_address = string_copy_taint(var + 13, proto_mem);
616
      }
643
      }
617
    break;
644
    break;
618
645
Lines 620-629 Link Here
620
    if (Ustrncmp(p, "nterface_address", 16) == 0)
647
    if (Ustrncmp(p, "nterface_address", 16) == 0)
621
      {
648
      {
622
      interface_port = host_address_extract_port(var + 18);
649
      interface_port = host_address_extract_port(var + 18);
623
      interface_address = string_copy_taint(var + 18, tainted);
650
      interface_address = string_copy_taint(var + 18, proto_mem);
624
      }
651
      }
625
    else if (Ustrncmp(p, "dent", 4) == 0)
652
    else if (Ustrncmp(p, "dent", 4) == 0)
626
      sender_ident = string_copy_taint(var + 6, tainted);
653
      sender_ident = string_copy_taint(var + 6, proto_mem);
627
    break;
654
    break;
628
655
629
    case 'l':
656
    case 'l':
Lines 633-639 Link Here
633
      f.local_error_message = TRUE;
660
      f.local_error_message = TRUE;
634
#ifdef HAVE_LOCAL_SCAN
661
#ifdef HAVE_LOCAL_SCAN
635
    else if (Ustrncmp(p, "ocal_scan ", 10) == 0)
662
    else if (Ustrncmp(p, "ocal_scan ", 10) == 0)
636
      local_scan_data = string_copy_taint(var + 11, tainted);
663
      local_scan_data = string_copy_taint(var + 11, proto_mem);
637
#endif
664
#endif
638
    break;
665
    break;
639
666
Lines 650-661 Link Here
650
677
651
    case 'r':
678
    case 'r':
652
    if (Ustrncmp(p, "eceived_protocol", 16) == 0)
679
    if (Ustrncmp(p, "eceived_protocol", 16) == 0)
653
      received_protocol = string_copy_taint(var + 18, tainted);
680
      received_protocol = string_copy_taint(var + 18, proto_mem);
654
    else if (Ustrncmp(p, "eceived_time_usec", 17) == 0)
681
    else if (Ustrncmp(p, "eceived_time_usec", 17) == 0)
655
      {
682
      {
656
      unsigned usec;
683
      unsigned usec;
657
      if (sscanf(CS var + 20, "%u", &usec) == 1)
684
      if (sscanf(CS var + 20, "%u", &usec) == 1)
685
	{
658
	received_time.tv_usec = usec;
686
	received_time.tv_usec = usec;
687
	if (!received_time_complete.tv_sec) received_time_complete.tv_usec = usec;
688
	}
689
      }
690
    else if (Ustrncmp(p, "eceived_time_complete", 21) == 0)
691
      {
692
      unsigned sec, usec;
693
      if (sscanf(CS var + 23, "%u.%u", &sec, &usec) == 2)
694
	{
695
	received_time_complete.tv_sec = sec;
696
	received_time_complete.tv_usec = usec;
697
	}
659
      }
698
      }
660
    break;
699
    break;
661
700
Lines 664-674 Link Here
664
      f.sender_set_untrusted = TRUE;
703
      f.sender_set_untrusted = TRUE;
665
#ifdef WITH_CONTENT_SCAN
704
#ifdef WITH_CONTENT_SCAN
666
    else if (Ustrncmp(p, "pam_bar ", 8) == 0)
705
    else if (Ustrncmp(p, "pam_bar ", 8) == 0)
667
      spam_bar = string_copy_taint(var + 9, tainted);
706
      spam_bar = string_copy_taint(var + 9, proto_mem);
668
    else if (Ustrncmp(p, "pam_score ", 10) == 0)
707
    else if (Ustrncmp(p, "pam_score ", 10) == 0)
669
      spam_score = string_copy_taint(var + 11, tainted);
708
      spam_score = string_copy_taint(var + 11, proto_mem);
670
    else if (Ustrncmp(p, "pam_score_int ", 14) == 0)
709
    else if (Ustrncmp(p, "pam_score_int ", 14) == 0)
671
      spam_score_int = string_copy_taint(var + 15, tainted);
710
      spam_score_int = string_copy_taint(var + 15, proto_mem);
672
#endif
711
#endif
673
#ifndef COMPILE_UTILITY
712
#ifndef COMPILE_UTILITY
674
    else if (Ustrncmp(p, "pool_file_wireformat", 20) == 0)
713
    else if (Ustrncmp(p, "pool_file_wireformat", 20) == 0)
Lines 688-694 Link Here
688
      if (Ustrncmp(q, "certificate_verified", 20) == 0)
727
      if (Ustrncmp(q, "certificate_verified", 20) == 0)
689
	tls_in.certificate_verified = TRUE;
728
	tls_in.certificate_verified = TRUE;
690
      else if (Ustrncmp(q, "cipher", 6) == 0)
729
      else if (Ustrncmp(q, "cipher", 6) == 0)
691
	tls_in.cipher = string_copy_taint(q+7, tainted);
730
	tls_in.cipher = string_copy_taint(q+7, proto_mem);
692
# ifndef COMPILE_UTILITY	/* tls support fns not built in */
731
# ifndef COMPILE_UTILITY	/* tls support fns not built in */
693
      else if (Ustrncmp(q, "ourcert", 7) == 0)
732
      else if (Ustrncmp(q, "ourcert", 7) == 0)
694
	(void) tls_import_cert(q+8, &tls_in.ourcert);
733
	(void) tls_import_cert(q+8, &tls_in.ourcert);
Lines 696-712 Link Here
696
	(void) tls_import_cert(q+9, &tls_in.peercert);
735
	(void) tls_import_cert(q+9, &tls_in.peercert);
697
# endif
736
# endif
698
      else if (Ustrncmp(q, "peerdn", 6) == 0)
737
      else if (Ustrncmp(q, "peerdn", 6) == 0)
699
	tls_in.peerdn = string_unprinting(string_copy_taint(q+7, tainted));
738
	tls_in.peerdn = string_unprinting(string_copy_taint(q+7, proto_mem));
700
      else if (Ustrncmp(q, "sni", 3) == 0)
739
      else if (Ustrncmp(q, "sni", 3) == 0)
701
	tls_in.sni = string_unprinting(string_copy_taint(q+4, tainted));
740
	tls_in.sni = string_unprinting(string_copy_taint(q+4, proto_mem));
702
      else if (Ustrncmp(q, "ocsp", 4) == 0)
741
      else if (Ustrncmp(q, "ocsp", 4) == 0)
703
	tls_in.ocsp = q[5] - '0';
742
	tls_in.ocsp = q[5] - '0';
704
# ifdef EXPERIMENTAL_TLS_RESUME
743
# ifndef DISABLE_TLS_RESUME
705
      else if (Ustrncmp(q, "resumption", 10) == 0)
744
      else if (Ustrncmp(q, "resumption", 10) == 0)
706
	tls_in.resumption = q[11] - 'A';
745
	tls_in.resumption = q[11] - 'A';
707
# endif
746
# endif
708
      else if (Ustrncmp(q, "ver", 3) == 0)
747
      else if (Ustrncmp(q, "ver", 3) == 0)
709
	tls_in.ver = string_copy_taint(q+4, tainted);
748
	tls_in.ver = string_copy_taint(q+4, proto_mem);
710
      }
749
      }
711
    break;
750
    break;
712
#endif
751
#endif
Lines 745-755 Link Here
745
    goto SPOOL_FORMAT_ERROR;
784
    goto SPOOL_FORMAT_ERROR;
746
785
747
#ifndef COMPILE_UTILITY
786
#ifndef COMPILE_UTILITY
748
DEBUG(D_deliver)
787
DEBUG(D_deliver) debug_print_tree("Non-recipients", tree_nonrecipients);
749
  {
750
  debug_printf("Non-recipients:\n");
751
  debug_print_tree(tree_nonrecipients);
752
  }
753
#endif  /* COMPILE_UTILITY */
788
#endif  /* COMPILE_UTILITY */
754
789
755
/* After reading the tree, the next line has not yet been read into the
790
/* After reading the tree, the next line has not yet been read into the
Lines 765-771 Link Here
765
#endif  /* COMPILE_UTILITY */
800
#endif  /* COMPILE_UTILITY */
766
801
767
recipients_list_max = rcount;
802
recipients_list_max = rcount;
768
recipients_list = store_get(rcount * sizeof(recipient_item), FALSE);
803
recipients_list = store_get(rcount * sizeof(recipient_item), GET_UNTAINTED);
769
804
770
/* We sanitised the count and know we have enough memory, so disable
805
/* We sanitised the count and know we have enough memory, so disable
771
the Coverity error on recipients_count */
806
the Coverity error on recipients_count */
Lines 865-871 Link Here
865
900
866
    (void)sscanf(CS p+1, "%d", &flags);
901
    (void)sscanf(CS p+1, "%d", &flags);
867
902
868
    if ((flags & 0x01) != 0)      /* one_time data exists */
903
    if (flags & 0x01)      /* one_time data exists */
869
      {
904
      {
870
      int len;
905
      int len;
871
      while (isdigit(*(--p)) || *p == ',' || *p == '-');
906
      while (isdigit(*(--p)) || *p == ',' || *p == '-');
Lines 874-885 Link Here
874
      if (len > 0)
909
      if (len > 0)
875
        {
910
        {
876
        p -= len;
911
        p -= len;
877
        errors_to = string_copy_taint(p, TRUE);
912
        errors_to = string_copy_taint(p, GET_TAINTED);
878
        }
913
        }
879
      }
914
      }
880
915
881
    *(--p) = 0;   /* Terminate address */
916
    *--p = 0;   /* Terminate address */
882
    if ((flags & 0x02) != 0)      /* one_time data exists */
917
    if (flags & 0x02)      /* one_time data exists */
883
      {
918
      {
884
      int len;
919
      int len;
885
      while (isdigit(*(--p)) || *p == ',' || *p == '-');
920
      while (isdigit(*(--p)) || *p == ',' || *p == '-');
Lines 888-898 Link Here
888
      if (len > 0)
923
      if (len > 0)
889
        {
924
        {
890
        p -= len;
925
        p -= len;
891
        orcpt = string_copy_taint(p, TRUE);
926
        orcpt = string_copy_taint(p, GET_TAINTED);
892
        }
927
        }
893
      }
928
      }
894
929
895
    *(--p) = 0;   /* Terminate address */
930
    *--p = 0;   /* Terminate address */
896
    }
931
    }
897
#if !defined(COMPILE_UTILITY)
932
#if !defined(COMPILE_UTILITY)
898
  else
933
  else
Lines 906-912 Link Here
906
      big_buffer, errors_to);
941
      big_buffer, errors_to);
907
#endif
942
#endif
908
943
909
  recipients_list[recipients_count].address = string_copy_taint(big_buffer, TRUE);
944
  recipients_list[recipients_count].address = string_copy_taint(big_buffer, GET_TAINTED);
910
  recipients_list[recipients_count].pno = pno;
945
  recipients_list[recipients_count].pno = pno;
911
  recipients_list[recipients_count].errors_to = errors_to;
946
  recipients_list[recipients_count].errors_to = errors_to;
912
  recipients_list[recipients_count].orcpt = orcpt;
947
  recipients_list[recipients_count].orcpt = orcpt;
Lines 938-948 Link Here
938
973
939
  if (read_headers)
974
  if (read_headers)
940
    {
975
    {
941
    h = store_get(sizeof(header_line), FALSE);
976
    h = store_get(sizeof(header_line), GET_UNTAINTED);
942
    h->next = NULL;
977
    h->next = NULL;
943
    h->type = flag[0];
978
    h->type = flag[0];
944
    h->slen = n;
979
    h->slen = n;
945
    h->text = store_get(n+1, TRUE);	/* tainted */
980
    h->text = store_get(n+1, GET_TAINTED);
946
981
947
    if (h->type == htype_received) received_count++;
982
    if (h->type == htype_received) received_count++;
948
983
Lines 1013-1018 Link Here
1013
return inheader? spool_read_hdrerror : spool_read_enverror;
1048
return inheader? spool_read_hdrerror : spool_read_enverror;
1014
}
1049
}
1015
1050
1051
1052
#ifndef COMPILE_UTILITY
1053
/* Read out just the (envelope) sender string from the spool -H file.
1054
Remove the <> wrap and return it in allocated store.  Return NULL on error.
1055
1056
We assume that message_subdir is already set.
1057
*/
1058
1059
uschar *
1060
spool_sender_from_msgid(const uschar * id)
1061
{
1062
uschar * name = string_sprintf("%s-H", id);
1063
FILE * fp;
1064
int n;
1065
uschar * yield = NULL;
1066
1067
if (!(fp = Ufopen(spool_fname(US"input", message_subdir, name, US""), "rb")))
1068
  return NULL;
1069
1070
DEBUG(D_deliver) debug_printf_indent("reading spool file %s\n", name);
1071
1072
/* Skip the line with the copy of the filename, then the line with login/uid/gid.
1073
Read the next line, which should be the envelope sender.
1074
Do basic validation on that. */
1075
1076
if (  Ufgets(big_buffer, big_buffer_size, fp) != NULL
1077
   && Ufgets(big_buffer, big_buffer_size, fp) != NULL
1078
   && Ufgets(big_buffer, big_buffer_size, fp) != NULL
1079
   && (n = Ustrlen(big_buffer)) >= 3
1080
   && big_buffer[0] == '<' && big_buffer[n-2] == '>'
1081
   )
1082
  {
1083
  yield = store_get(n-2, GET_TAINTED);
1084
  Ustrncpy(yield, big_buffer+1, n-3);
1085
  yield[n-3] = 0;
1086
  }
1087
fclose(fp);
1088
return yield;
1089
}
1090
#endif  /* COMPILE_UTILITY */
1091
1016
/* vi: aw ai sw=2
1092
/* vi: aw ai sw=2
1017
*/
1093
*/
1018
/* End of spool_in.c */
1094
/* End of spool_in.c */
(-)exim.orig/src/spool_mbox.c (-11 / +12 lines)
Lines 4-10 Link Here
4
4
5
/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003 - 2015
5
/* Copyright (c) Tom Kistner <tom@duncanthrax.net> 2003 - 2015
6
 * License: GPL
6
 * License: GPL
7
 * Copyright (c) The Exim Maintainers 2016 - 2020
7
 * Copyright (c) The Exim Maintainers 2016 - 2021
8
 */
8
 */
9
9
10
/* Code for setting up a MBOX style spool file inside a /scan/<msgid>
10
/* Code for setting up a MBOX style spool file inside a /scan/<msgid>
Lines 53-60 Link Here
53
  temp_string = string_sprintf("scan/%s", message_id);
53
  temp_string = string_sprintf("scan/%s", message_id);
54
  if (!directory_make(spool_directory, temp_string, 0750, FALSE))
54
  if (!directory_make(spool_directory, temp_string, 0750, FALSE))
55
    {
55
    {
56
    log_write(0, LOG_MAIN|LOG_PANIC, "%s", string_open_failed(errno,
56
    log_write(0, LOG_MAIN|LOG_PANIC, "%s",
57
      "scan directory %s/scan/%s", spool_directory, temp_string));
57
      string_open_failed("scan directory %s/scan/%s", spool_directory, temp_string));
58
    goto OUT;
58
    goto OUT;
59
    }
59
    }
60
60
Lines 62-69 Link Here
62
62
63
  if (!(mbox_file = modefopen(mbox_path, "wb", SPOOL_MODE)))
63
  if (!(mbox_file = modefopen(mbox_path, "wb", SPOOL_MODE)))
64
    {
64
    {
65
    log_write(0, LOG_MAIN|LOG_PANIC, "%s", string_open_failed(errno,
65
    log_write(0, LOG_MAIN|LOG_PANIC, "%s",
66
      "scan file %s", mbox_path));
66
      string_open_failed("scan file %s", mbox_path));
67
    goto OUT;
67
    goto OUT;
68
    }
68
    }
69
69
Lines 185-192 Link Here
185
if (  !(yield = Ufopen(mbox_path,"rb"))
185
if (  !(yield = Ufopen(mbox_path,"rb"))
186
   || fstat(fileno(yield), &statbuf) != 0
186
   || fstat(fileno(yield), &statbuf) != 0
187
   )
187
   )
188
  log_write(0, LOG_MAIN|LOG_PANIC, "%s", string_open_failed(errno,
188
  log_write(0, LOG_MAIN|LOG_PANIC, "%s",
189
    "scan file %s", mbox_path));
189
    string_open_failed( "scan file %s", mbox_path));
190
else
190
else
191
  *mbox_file_size = statbuf.st_size;
191
  *mbox_file_size = statbuf.st_size;
192
192
Lines 219-243 Link Here
219
    {
219
    {
220
    debug_printf("Unable to opendir(%s): %s\n", mbox_path, strerror(errno));
220
    debug_printf("Unable to opendir(%s): %s\n", mbox_path, strerror(errno));
221
    /* Just in case we still can: */
221
    /* Just in case we still can: */
222
    rmdir(CS mbox_path);
222
    (void) rmdir(CS mbox_path);
223
    return;
223
    return;
224
    }
224
    }
225
  /* loop thru dir & delete entries */
225
  /* loop thru dir & delete entries */
226
  for (struct dirent *entry; entry = readdir(tempdir); )
226
  for (struct dirent *entry; entry = readdir(tempdir); )
227
    {
227
    {
228
    uschar *name = US entry->d_name;
228
    uschar *name = US entry->d_name;
229
    int dummy;
230
    if (Ustrcmp(name, US".") == 0 || Ustrcmp(name, US"..") == 0) continue;
229
    if (Ustrcmp(name, US".") == 0 || Ustrcmp(name, US"..") == 0) continue;
231
230
232
    file_path = string_sprintf("%s/%s", mbox_path, name);
231
    file_path = string_sprintf("%s/%s", mbox_path, name);
233
    debug_printf("unspool_mbox(): unlinking '%s'\n", file_path);
232
    debug_printf("unspool_mbox(): unlinking '%s'\n", file_path);
234
    dummy = unlink(CS file_path); dummy = dummy;	/* compiler quietening */
233
    if (unlink(CS file_path) != 0)
234
      log_write(0, LOG_MAIN|LOG_PANIC, "unlink(%s): %s", file_path, strerror(errno));
235
    }
235
    }
236
236
237
  closedir(tempdir);
237
  closedir(tempdir);
238
238
239
  /* remove directory */
239
  /* remove directory */
240
  rmdir(CS mbox_path);
240
  if (rmdir(CS mbox_path) != 0)
241
    log_write(0, LOG_MAIN|LOG_PANIC, "rmdir(%s): %s", mbox_path, strerror(errno));
241
  store_reset(reset_point);
242
  store_reset(reset_point);
242
  }
243
  }
243
spool_mbox_ok = 0;
244
spool_mbox_ok = 0;
(-)exim.orig/src/spool_out.c (-6 / +23 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Functions for writing spool files, and moving them about. */
9
/* Functions for writing spool files, and moving them about. */
Lines 120-127 Link Here
120
static void
120
static void
121
spool_var_write(FILE * fp, const uschar * name, const uschar * val)
121
spool_var_write(FILE * fp, const uschar * name, const uschar * val)
122
{
122
{
123
if (is_tainted(val)) putc('-', fp);
123
putc('-', fp);
124
fprintf(fp, "-%s %s\n", name, val);
124
if (is_tainted(val))
125
  {
126
  int q = quoter_for_address(val);
127
  putc('-', fp);
128
  if (is_real_quoter(q)) fprintf(fp, "(%s)", lookup_list[q]->name);
129
  }
130
fprintf(fp, "%s %s\n", name, val);
125
}
131
}
126
132
127
/*************************************************
133
/*************************************************
Lines 174-179 Link Here
174
fprintf(fp, "%d %d\n", (int)received_time.tv_sec, warning_count);
180
fprintf(fp, "%d %d\n", (int)received_time.tv_sec, warning_count);
175
181
176
fprintf(fp, "-received_time_usec .%06d\n", (int)received_time.tv_usec);
182
fprintf(fp, "-received_time_usec .%06d\n", (int)received_time.tv_usec);
183
fprintf(fp, "-received_time_complete %d.%06d\n",
184
  (int)received_time_complete.tv_sec, (int)received_time_complete.tv_usec);
177
185
178
/* If there is information about a sending host, remember it. The HELO
186
/* If there is information about a sending host, remember it. The HELO
179
data can be set for local SMTP as well as remote. */
187
data can be set for local SMTP as well as remote. */
Lines 183-189 Link Here
183
if (sender_host_address)
191
if (sender_host_address)
184
  {
192
  {
185
  if (is_tainted(sender_host_address)) putc('-', fp);
193
  if (is_tainted(sender_host_address)) putc('-', fp);
186
  fprintf(fp, "-host_address %s.%d\n", sender_host_address, sender_host_port);
194
  fprintf(fp, "-host_address [%s]:%d\n", sender_host_address, sender_host_port);
187
  if (sender_host_name)
195
  if (sender_host_name)
188
    spool_var_write(fp, US"host_name", sender_host_name);
196
    spool_var_write(fp, US"host_name", sender_host_name);
189
  }
197
  }
Lines 197-203 Link Here
197
if (interface_address)
205
if (interface_address)
198
  {
206
  {
199
  if (is_tainted(interface_address)) putc('-', fp);
207
  if (is_tainted(interface_address)) putc('-', fp);
200
  fprintf(fp, "-interface_address %s.%d\n", interface_address, interface_port);
208
  fprintf(fp, "-interface_address [%s]:%d\n", interface_address, interface_port);
201
  }
209
  }
202
210
203
if (smtp_active_hostname != primary_hostname)
211
if (smtp_active_hostname != primary_hostname)
Lines 222-227 Link Here
222
230
223
/* Now any other data that needs to be remembered. */
231
/* Now any other data that needs to be remembered. */
224
232
233
if (*debuglog_name)
234
  {
235
  fprintf(fp, "-debug_selector 0x%x\n", debug_selector);
236
  fprintf(fp, "-debuglog_name %s\n", debuglog_name);
237
  }
238
225
if (f.spool_file_wireformat)
239
if (f.spool_file_wireformat)
226
  fprintf(fp, "-spool_file_wireformat\n");
240
  fprintf(fp, "-spool_file_wireformat\n");
227
else
241
else
Lines 275-281 Link Here
275
    fprintf(fp, "-tls_ourcert %s\n", CS big_buffer);
289
    fprintf(fp, "-tls_ourcert %s\n", CS big_buffer);
276
  }
290
  }
277
if (tls_in.ocsp)	 fprintf(fp, "-tls_ocsp %d\n",   tls_in.ocsp);
291
if (tls_in.ocsp)	 fprintf(fp, "-tls_ocsp %d\n",   tls_in.ocsp);
278
# ifdef EXPERIMENTAL_TLS_RESUME
292
# ifndef DISABLE_TLS_RESUME
279
fprintf(fp, "-tls_resumption %c\n", 'A' + tls_in.resumption);
293
fprintf(fp, "-tls_resumption %c\n", 'A' + tls_in.resumption);
280
# endif
294
# endif
281
if (tls_in.ver) spool_var_write(fp, US"tls_ver", tls_in.ver);
295
if (tls_in.ver) spool_var_write(fp, US"tls_ver", tls_in.ver);
Lines 520-525 Link Here
520
{
534
{
521
uschar * dest_qname = queue_name_dest ? queue_name_dest : queue_name;
535
uschar * dest_qname = queue_name_dest ? queue_name_dest : queue_name;
522
536
537
/* Since we are working within the spool, de-taint the dest queue name */
538
dest_qname = string_copy_taint(dest_qname, GET_UNTAINTED);
539
523
/* Create any output directories that do not exist. */
540
/* Create any output directories that do not exist. */
524
541
525
(void) directory_make(spool_directory,
542
(void) directory_make(spool_directory,
(-)exim.orig/src/std-crypto.c (-50 / +57 lines)
Lines 3-9 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) Phil Pennock 2012, 2016
5
/* Copyright (c) Phil Pennock 2012, 2016
6
 * Copyright (c) The Exim Maintainers 2017 - 2018
6
 * Copyright (c) The Exim Maintainers 2017 - 2021
7
 * But almost everything here is fixed published constants from RFCs, so also:
7
 * But almost everything here is fixed published constants from RFCs, so also:
8
 * Copyright (C) The Internet Society (2003)
8
 * Copyright (C) The Internet Society (2003)
9
 * Copyright (C) The IETF Trust (2008)
9
 * Copyright (C) The IETF Trust (2008)
Lines 914-925 Link Here
914
914
915
/* ========================================================================= */
915
/* ========================================================================= */
916
916
917
/*
917
/* Generated by Phil as a non-standard option.
918
 * Generated by Phil as a non-standard option.
918
openssl dhparam -2 2048
919
 * openssl dhparam -2 2048
919
No provenance to prove non-tampering available, beyond trusting that this
920
 * No provenance to prove non-tampering available, beyond trusting that this
920
developer generated this as stated above. */
921
 * developer generated this as stated above.
921
922
 */
923
922
924
/* MacOSX 10.10.5 invoking system OpenSSL 0.9.8zg */
923
/* MacOSX 10.10.5 invoking system OpenSSL 0.9.8zg */
925
static const char dh_exim_20160529_1[] =
924
static const char dh_exim_20160529_1[] =
Lines 957-1023 Link Here
957
/* ========================================================================= */
956
/* ========================================================================= */
958
957
959
struct dh_constant {
958
struct dh_constant {
960
  const char *label;
959
  const char *	label;
961
  const char *pem;
960
  const char *	pem;
961
  int		logging;
962
};
962
};
963
963
964
#define EXIM_DH_PRIME_DEFAULT dh_exim_20160529_3
965
964
/* KEEP SORTED ALPHABETICALLY;
966
/* KEEP SORTED ALPHABETICALLY;
965
 * duplicate PEM are okay, if we want aliases, but names must be alphabetical */
967
duplicate PEM are okay, if we want aliases, but names must be alphabetical */
968
966
static struct dh_constant dh_constants[] = {
969
static struct dh_constant dh_constants[] = {
967
    /*  label			pem */
970
    /*  label			pem */
968
    { "default",		dh_exim_20160529_3 },
971
    { "default",		EXIM_DH_PRIME_DEFAULT,	0 },
969
    { "exim.dev.20160529.1",	dh_exim_20160529_1 },
972
    { "exim.dev.20160529.1",	dh_exim_20160529_1,	0 },
970
    { "exim.dev.20160529.2",	dh_exim_20160529_2 },
973
    { "exim.dev.20160529.2",	dh_exim_20160529_2,	0 },
971
    { "exim.dev.20160529.3",	dh_exim_20160529_3 },
974
    { "exim.dev.20160529.3",	dh_exim_20160529_3,	0 },
972
    { "ffdhe2048",		dh_ffdhe2048_pem },
975
    { "ffdhe2048",		dh_ffdhe2048_pem,	0 },
973
    { "ffdhe3072",		dh_ffdhe3072_pem },
976
    { "ffdhe3072",		dh_ffdhe3072_pem,	0 },
974
    { "ffdhe4096",		dh_ffdhe4096_pem },
977
    { "ffdhe4096",		dh_ffdhe4096_pem,	0 },
975
    { "ffdhe6144",		dh_ffdhe6144_pem },
978
    { "ffdhe6144",		dh_ffdhe6144_pem,	0 },
976
    { "ffdhe8192",		dh_ffdhe8192_pem },
979
    { "ffdhe8192",		dh_ffdhe8192_pem,	0 },
977
    { "ike1",			dh_ike_1_pem },
980
    { "ike1",			dh_ike_1_pem,		LOG_MAIN | LOG_PANIC },
978
    { "ike14",			dh_ike_14_pem },
981
    { "ike14",			dh_ike_14_pem,		0 },
979
    { "ike15",			dh_ike_15_pem },
982
    { "ike15",			dh_ike_15_pem,		0 },
980
    { "ike16",			dh_ike_16_pem },
983
    { "ike16",			dh_ike_16_pem,		0 },
981
    { "ike17",			dh_ike_17_pem },
984
    { "ike17",			dh_ike_17_pem,		0 },
982
    { "ike18",			dh_ike_18_pem },
985
    { "ike18",			dh_ike_18_pem,		0 },
983
    { "ike2",			dh_ike_2_pem },
986
    { "ike2",			dh_ike_2_pem,		LOG_MAIN },
984
    { "ike22",			dh_ike_22_pem },
987
    { "ike22",			dh_ike_22_pem,		LOG_MAIN | LOG_PANIC },
985
    { "ike23",			dh_ike_23_pem },
988
    { "ike23",			dh_ike_23_pem,		LOG_MAIN },
986
    { "ike24",			dh_ike_24_pem },
989
    { "ike24",			dh_ike_24_pem,		LOG_MAIN },
987
    { "ike5",			dh_ike_5_pem },
990
    { "ike5",			dh_ike_5_pem,		0 },
988
};
991
};
989
static const int dh_constants_count =
992
static const int dh_constants_count = nelem(dh_constants);
990
  sizeof(dh_constants) / sizeof(struct dh_constant);
991
993
992
994
993
/* A policy decision; in absence of any other data, use a 2048 bit prime,
995
/* A policy decision; in absence of any other data, use a 2048 bit prime,
994
 * pick the first one from the latest RFC providing such. */
996
pick the first one from the latest RFC providing such. */
997
995
const char *
998
const char *
996
std_dh_prime_default(void)
999
std_dh_prime_default(void)
997
{
1000
{
998
  return dh_ike_23_pem;
1001
return EXIM_DH_PRIME_DEFAULT;
999
}
1002
}
1000
1003
1001
1004
1005
/* Return PEM string for given name */
1006
1002
const char *
1007
const char *
1003
std_dh_prime_named(const uschar *name)
1008
std_dh_prime_named(const uschar * name)
1004
{
1009
{
1005
  int first, last;
1010
for (int first = 0, last = dh_constants_count; last > first; )
1006
  char *search_name = CS string_copylc(US name);
1011
  {
1007
1012
  int middle = (first + last)/2;
1008
  first = 0;
1013
  struct dh_constant * dp = &dh_constants[middle];
1009
  last = dh_constants_count;
1014
  int c = Ustrcmp(name, dp->label);
1010
  while (last > first) {
1015
  if (c == 0)
1011
    int middle = (first + last)/2;
1016
    {
1012
    int c = strcmp(search_name, dh_constants[middle].label);
1017
    if (dp->logging)
1013
    if (c == 0)
1018
      log_write(0, dp->logging,
1014
      return dh_constants[middle].pem;
1019
	"WARNING: deprecated Diffie-Hellman parameter '%s' used", dp->label);
1015
    else if (c > 0)
1020
    return dp->pem;
1016
      first = middle + 1;
1021
    }
1017
    else
1022
  else if (c > 0)
1018
      last = middle;
1023
    first = middle + 1;
1024
  else
1025
    last = middle;
1019
  }
1026
  }
1020
  return NULL;
1027
return NULL;
1021
}
1028
}
1022
1029
1023
#endif /*DISABLE_TLS*/
1030
#endif /*DISABLE_TLS*/
(-)exim.orig/src/store.c (-215 / +629 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim maintainers 2019 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim maintainers 2019 - 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Exim gets and frees all its store through these functions. In the original
9
/* Exim gets and frees all its store through these functions. In the original
Lines 37-47 Link Here
37
  This means it can be freed when search_tidyup() is called to close down all
37
  This means it can be freed when search_tidyup() is called to close down all
38
  the lookup caching.
38
  the lookup caching.
39
39
40
. Orthogonal to the three pool types, there are two classes of memory: untainted
40
- There is another pool (POOL_MESSAGE) used for medium-lifetime objects; within
41
  a single message transaction but needed for longer than the use of the main
42
  pool permits.  Currently this means only receive-time DKIM information.
43
44
- There is a dedicated pool for configuration data read from the config file(s).
45
  Once complete, it is made readonly.
46
47
- There are pools for each active combination of lookup-quoting, dynamically created.
48
49
. Orthogonal to the four main pool types, there are two classes of memory: untainted
41
  and tainted.  The latter is used for values derived from untrusted input, and
50
  and tainted.  The latter is used for values derived from untrusted input, and
42
  the string-expansion mechanism refuses to operate on such values (obviously,
51
  the string-expansion mechanism refuses to operate on such values (obviously,
43
  it can expand an untainted value to return a tainted result).  The classes
52
  it can expand an untainted value to return a tainted result).  The classes
44
  are implemented by duplicating the three pool types.  Pool resets are requested
53
  are implemented by duplicating the four pool types.  Pool resets are requested
45
  against the nontainted sibling and apply to both siblings.
54
  against the nontainted sibling and apply to both siblings.
46
55
47
  Only memory blocks requested for tainted use are regarded as tainted; anything
56
  Only memory blocks requested for tainted use are regarded as tainted; anything
Lines 93-98 Link Here
93
  size_t length;
102
  size_t length;
94
} storeblock;
103
} storeblock;
95
104
105
/* Pool descriptor struct */
106
107
typedef struct pooldesc {
108
  storeblock *	chainbase;		/* list of blocks in pool */
109
  storeblock *	current_block;		/* top block, still with free space */
110
  void *	next_yield;		/* next allocation point */
111
  int		yield_length;		/* remaining space in current block */
112
  unsigned	store_block_order;	/* log2(size) block allocation size */
113
114
  /* This variable is set by store_get() to its yield, and by store_reset() to
115
  NULL. This enables string_cat() to optimize its store handling for very long
116
  strings. That's why the variable is global. */
117
118
  void *	store_last_get;
119
120
  /* These are purely for stats-gathering */
121
122
  int		nbytes;
123
  int		maxbytes;
124
  int		nblocks;
125
  int		maxblocks;
126
  unsigned	maxorder;
127
} pooldesc;
128
129
/* Enhanced pool descriptor for quoted pools */
130
131
typedef struct quoted_pooldesc {
132
  pooldesc			pool;
133
  unsigned			quoter;
134
  struct quoted_pooldesc *	next;
135
} quoted_pooldesc;
136
96
/* Just in case we find ourselves on a system where the structure above has a
137
/* Just in case we find ourselves on a system where the structure above has a
97
length that is not a multiple of the alignment, set up a macro for the padded
138
length that is not a multiple of the alignment, set up a macro for the padded
98
length. */
139
length. */
Lines 101-110 Link Here
101
  (((sizeof(storeblock) + alignment - 1) / alignment) * alignment)
142
  (((sizeof(storeblock) + alignment - 1) / alignment) * alignment)
102
143
103
/* Size of block to get from malloc to carve up into smaller ones. This
144
/* Size of block to get from malloc to carve up into smaller ones. This
104
must be a multiple of the alignment. We assume that 8192 is going to be
145
must be a multiple of the alignment. We assume that 4096 is going to be
105
suitably aligned. */
146
suitably aligned.  Double the size per-pool for every malloc, to mitigate
147
certain denial-of-service attacks.  Don't bother to decrease on block frees.
148
We waste average half the current alloc size per pool.  This could be several
149
hundred kB now, vs. 4kB with a constant-size block size.  But the search time
150
for is_tainted(), linear in the number of blocks for the pool, is O(n log n)
151
rather than O(n^2).
152
A test of 2000 RCPTs and just accept ACL had 370kB in 21 blocks before,
153
504kB in 6 blocks now, for the untainted-main (largest) pool.
154
Builds for restricted-memory system can disable the expansion by
155
defining RESTRICTED_MEMORY */
156
/*XXX should we allow any for malloc's own overhead?  But how much? */
106
157
107
#define STORE_BLOCK_SIZE (8192 - ALIGNED_SIZEOF_STOREBLOCK)
158
/* #define RESTRICTED_MEMORY */
159
#define STORE_BLOCK_SIZE(order) ((1U << (order)) - ALIGNED_SIZEOF_STOREBLOCK)
108
160
109
/* Variables holding data for the local pools of store. The current pool number
161
/* Variables holding data for the local pools of store. The current pool number
110
is held in store_pool, which is global so that it can be changed from outside.
162
is held in store_pool, which is global so that it can be changed from outside.
Lines 113-123 Link Here
113
165
114
int store_pool = POOL_MAIN;
166
int store_pool = POOL_MAIN;
115
167
116
#define NPOOLS 6
168
pooldesc paired_pools[N_PAIRED_POOLS];
117
static storeblock *chainbase[NPOOLS];
169
quoted_pooldesc * quoted_pools = NULL;
118
static storeblock *current_block[NPOOLS];
170
119
static void *next_yield[NPOOLS];
171
static int n_nonpool_blocks;	/* current number of direct store_malloc() blocks */
120
static int yield_length[NPOOLS] = { -1, -1, -1,  -1, -1, -1 };
172
static int max_nonpool_blocks;
173
static int max_pool_malloc;	/* max value for pool_malloc */
174
static int max_nonpool_malloc;	/* max value for nonpool_malloc */
121
175
122
/* pool_malloc holds the amount of memory used by the store pools; this goes up
176
/* pool_malloc holds the amount of memory used by the store pools; this goes up
123
and down as store is reset or released. nonpool_malloc is the total got by
177
and down as store is reset or released. nonpool_malloc is the total got by
Lines 127-175 Link Here
127
static int pool_malloc;
181
static int pool_malloc;
128
static int nonpool_malloc;
182
static int nonpool_malloc;
129
183
130
/* This variable is set by store_get() to its yield, and by store_reset() to
131
NULL. This enables string_cat() to optimize its store handling for very long
132
strings. That's why the variable is global. */
133
134
void *store_last_get[NPOOLS];
135
136
/* These are purely for stats-gathering */
137
138
static int nbytes[NPOOLS];	/* current bytes allocated */
139
static int maxbytes[NPOOLS];	/* max number reached */
140
static int nblocks[NPOOLS];	/* current number of blocks allocated */
141
static int maxblocks[NPOOLS];
142
static int n_nonpool_blocks;	/* current number of direct store_malloc() blocks */
143
static int max_nonpool_blocks;
144
static int max_pool_malloc;	/* max value for pool_malloc */
145
static int max_nonpool_malloc;	/* max value for nonpool_malloc */
146
147
184
148
#ifndef COMPILE_UTILITY
185
#ifndef COMPILE_UTILITY
149
static const uschar * pooluse[NPOOLS] = {
186
static const uschar * pooluse[N_PAIRED_POOLS] = {
150
[POOL_MAIN] =		US"main",
187
[POOL_MAIN] =		US"main",
151
[POOL_PERM] =		US"perm",
188
[POOL_PERM] =		US"perm",
189
[POOL_CONFIG] =		US"config",
152
[POOL_SEARCH] =		US"search",
190
[POOL_SEARCH] =		US"search",
191
[POOL_MESSAGE] =	US"message",
153
[POOL_TAINT_MAIN] =	US"main",
192
[POOL_TAINT_MAIN] =	US"main",
154
[POOL_TAINT_PERM] =	US"perm",
193
[POOL_TAINT_PERM] =	US"perm",
194
[POOL_TAINT_CONFIG] =	US"config",
155
[POOL_TAINT_SEARCH] =	US"search",
195
[POOL_TAINT_SEARCH] =	US"search",
196
[POOL_TAINT_MESSAGE] =	US"message",
156
};
197
};
157
static const uschar * poolclass[NPOOLS] = {
198
static const uschar * poolclass[N_PAIRED_POOLS] = {
158
[POOL_MAIN] =		US"untainted",
199
[POOL_MAIN] =		US"untainted",
159
[POOL_PERM] =		US"untainted",
200
[POOL_PERM] =		US"untainted",
201
[POOL_CONFIG] =		US"untainted",
160
[POOL_SEARCH] =		US"untainted",
202
[POOL_SEARCH] =		US"untainted",
203
[POOL_MESSAGE] =	US"untainted",
161
[POOL_TAINT_MAIN] =	US"tainted",
204
[POOL_TAINT_MAIN] =	US"tainted",
162
[POOL_TAINT_PERM] =	US"tainted",
205
[POOL_TAINT_PERM] =	US"tainted",
206
[POOL_TAINT_CONFIG] =	US"tainted",
163
[POOL_TAINT_SEARCH] =	US"tainted",
207
[POOL_TAINT_SEARCH] =	US"tainted",
208
[POOL_TAINT_MESSAGE] =	US"tainted",
164
};
209
};
165
#endif
210
#endif
166
211
167
212
168
static void * internal_store_malloc(int, const char *, int);
213
static void * internal_store_malloc(size_t, const char *, int);
169
static void   internal_store_free(void *, const char *, int linenumber);
214
static void   internal_store_free(void *, const char *, int linenumber);
170
215
171
/******************************************************************************/
216
/******************************************************************************/
172
217
218
static void
219
pool_init(pooldesc * pp)
220
{
221
memset(pp, 0, sizeof(*pp));
222
pp->yield_length = -1;
223
pp->store_block_order = 12; /* log2(allocation_size) ie. 4kB */
224
}
225
226
/* Initialisation, for things fragile with parameter channges when using
227
static initialisers. */
228
229
void
230
store_init(void)
231
{
232
for (pooldesc * pp = paired_pools; pp < paired_pools + N_PAIRED_POOLS; pp++)
233
  pool_init(pp);
234
}
235
236
/******************************************************************************/
237
/* Locating elements given memory pointer */
238
239
static BOOL
240
is_pointer_in_block(const storeblock * b, const void * p)
241
{
242
uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK;
243
return US p >= bc && US p < bc + b->length;
244
}
245
246
static pooldesc *
247
pool_current_for_pointer(const void * p)
248
{
249
storeblock * b;
250
251
for (quoted_pooldesc * qp = quoted_pools; qp; qp = qp->next)
252
  if ((b = qp->pool.current_block) && is_pointer_in_block(b, p))
253
    return &qp->pool;
254
255
for (pooldesc * pp = paired_pools; pp < paired_pools + N_PAIRED_POOLS; pp++)
256
  if ((b = pp->current_block) && is_pointer_in_block(b, p))
257
    return pp;
258
return NULL;
259
}
260
261
static pooldesc *
262
pool_for_pointer(const void * p, const char * func, int linenumber)
263
{
264
pooldesc * pp;
265
storeblock * b;
266
267
if ((pp = pool_current_for_pointer(p))) return pp;
268
269
for (quoted_pooldesc * qp = quoted_pools; qp; qp = qp->next)
270
  for (b = qp->pool.chainbase; b; b = b->next)
271
    if (is_pointer_in_block(b, p)) return &qp->pool;
272
273
for (pp = paired_pools; pp < paired_pools + N_PAIRED_POOLS; pp++)
274
  for (b = pp->chainbase; b; b = b->next)
275
    if (is_pointer_in_block(b, p)) return pp;
276
277
log_write(0, LOG_MAIN|LOG_PANIC_DIE,
278
  "bad memory reference; pool not found, at %s %d", func, linenumber);
279
return NULL;
280
}
281
282
/******************************************************************************/
173
/* Test if a pointer refers to tainted memory.
283
/* Test if a pointer refers to tainted memory.
174
284
175
Slower version check, for use when platform intermixes malloc and mmap area
285
Slower version check, for use when platform intermixes malloc and mmap area
Lines 184-202 Link Here
184
{
294
{
185
storeblock * b;
295
storeblock * b;
186
296
187
for (int pool = POOL_TAINT_BASE; pool < nelem(chainbase); pool++)
297
if (p == GET_UNTAINTED) return FALSE;
188
  if ((b = current_block[pool]))
298
if (p == GET_TAINTED) return TRUE;
189
    {
299
190
    uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK;
300
for (pooldesc * pp = paired_pools + POOL_TAINT_BASE;
191
    if (US p >= bc && US p < bc + b->length) return TRUE;
301
     pp < paired_pools + N_PAIRED_POOLS; pp++)
192
    }
302
  if ((b = pp->current_block))
303
    if (is_pointer_in_block(b, p)) return TRUE;
304
305
for (quoted_pooldesc * qp = quoted_pools; qp; qp = qp->next)
306
  if (b = qp->pool.current_block)
307
    if (is_pointer_in_block(b, p)) return TRUE;
308
309
for (pooldesc * pp = paired_pools + POOL_TAINT_BASE;
310
     pp < paired_pools + N_PAIRED_POOLS; pp++)
311
  for (b = pp->chainbase; b; b = b->next)
312
    if (is_pointer_in_block(b, p)) return TRUE;
313
314
for (quoted_pooldesc * qp = quoted_pools; qp; qp = qp->next)
315
  for (b = qp->pool.chainbase; b; b = b->next)
316
    if (is_pointer_in_block(b, p)) return TRUE;
193
317
194
for (int pool = POOL_TAINT_BASE; pool < nelem(chainbase); pool++)
195
  for (b = chainbase[pool]; b; b = b->next)
196
    {
197
    uschar * bc = US b + ALIGNED_SIZEOF_STOREBLOCK;
198
    if (US p >= bc && US p < bc + b->length) return TRUE;
199
    }
200
return FALSE;
318
return FALSE;
201
}
319
}
202
320
Lines 209-238 Link Here
209
}
327
}
210
328
211
329
330
#ifndef COMPILE_UTILITY
331
/* Return the pool for the given quoter, or null */
212
332
213
/*************************************************
333
static pooldesc *
214
*       Get a block from the current pool        *
334
pool_for_quoter(unsigned quoter)
215
*************************************************/
335
{
336
for (quoted_pooldesc * qp = quoted_pools; qp; qp = qp->next)
337
  if (qp->quoter == quoter)
338
    return &qp->pool;
339
return NULL;
340
}
216
341
217
/* Running out of store is a total disaster. This function is called via the
342
/* Allocate/init a new quoted-pool and return the pool */
218
macro store_get(). It passes back a block of store within the current big
219
block, getting a new one if necessary. The address is saved in
220
store_last_was_get.
221
343
222
Arguments:
344
static pooldesc *
223
  size        amount wanted, bytes
345
quoted_pool_new(unsigned quoter)
224
  tainted     class: set to true for untrusted data (eg. from smtp input)
346
{
225
  func        function from which called
347
// debug_printf("allocating quoted-pool\n");
226
  linenumber  line number in source file
348
quoted_pooldesc * qp = store_get_perm(sizeof(quoted_pooldesc), GET_UNTAINTED);
227
349
228
Returns:      pointer to store (panic on malloc failure)
350
pool_init(&qp->pool);
229
*/
351
qp->quoter = quoter;
352
qp->next = quoted_pools;
353
quoted_pools = qp;
354
return &qp->pool;
355
}
356
#endif
230
357
231
void *
358
232
store_get_3(int size, BOOL tainted, const char *func, int linenumber)
359
/******************************************************************************/
360
void
361
store_writeprotect(int pool)
233
{
362
{
234
int pool = tainted ? store_pool + POOL_TAINT_BASE : store_pool;
363
#if !defined(COMPILE_UTILITY) && !defined(MISSING_POSIX_MEMALIGN)
364
for (storeblock * b =  paired_pools[pool].chainbase; b; b = b->next)
365
  if (mprotect(b, ALIGNED_SIZEOF_STOREBLOCK + b->length, PROT_READ) != 0)
366
    DEBUG(D_any) debug_printf("config block mprotect: (%d) %s\n", errno, strerror(errno));
367
#endif
368
}
235
369
370
/******************************************************************************/
371
372
static void *
373
pool_get(pooldesc * pp, int size, BOOL align_mem, const char * func, int linenumber)
374
{
236
/* Ensure we've been asked to allocate memory.
375
/* Ensure we've been asked to allocate memory.
237
A negative size is a sign of a security problem.
376
A negative size is a sign of a security problem.
238
A zero size might be also suspect, but our internal usage deliberately
377
A zero size might be also suspect, but our internal usage deliberately
Lines 241-247 Link Here
241
380
242
if (size < 0 || size >= INT_MAX/2)
381
if (size < 0 || size >= INT_MAX/2)
243
  log_write(0, LOG_MAIN|LOG_PANIC_DIE,
382
  log_write(0, LOG_MAIN|LOG_PANIC_DIE,
244
            "bad memory allocation requested (%d bytes) at %s %d",
383
            "bad memory allocation requested (%d bytes) from %s %d",
245
            size, func, linenumber);
384
            size, func, linenumber);
246
385
247
/* Round up the size to a multiple of the alignment. Although this looks a
386
/* Round up the size to a multiple of the alignment. Although this looks a
Lines 256-276 Link Here
256
size is STORE_BLOCK_SIZE, and we would expect this to be the norm, since
395
size is STORE_BLOCK_SIZE, and we would expect this to be the norm, since
257
these functions are mostly called for small amounts of store. */
396
these functions are mostly called for small amounts of store. */
258
397
259
if (size > yield_length[pool])
398
if (size > pp->yield_length)
260
  {
399
  {
261
  int length = size <= STORE_BLOCK_SIZE ? STORE_BLOCK_SIZE : size;
400
  int length = MAX(
401
	  STORE_BLOCK_SIZE(pp->store_block_order) - ALIGNED_SIZEOF_STOREBLOCK,
402
	  size);
262
  int mlength = length + ALIGNED_SIZEOF_STOREBLOCK;
403
  int mlength = length + ALIGNED_SIZEOF_STOREBLOCK;
263
  storeblock * newblock;
404
  storeblock * newblock;
264
405
265
  /* Sometimes store_reset() may leave a block for us; check if we can use it */
406
  /* Sometimes store_reset() may leave a block for us; check if we can use it */
266
407
267
  if (  (newblock = current_block[pool])
408
  if (  (newblock = pp->current_block)
268
     && (newblock = newblock->next)
409
     && (newblock = newblock->next)
269
     && newblock->length < length
410
     && newblock->length < length
270
     )
411
     )
271
    {
412
    {
272
    /* Give up on this block, because it's too small */
413
    /* Give up on this block, because it's too small */
273
    nblocks[pool]--;
414
    pp->nblocks--;
274
    internal_store_free(newblock, func, linenumber);
415
    internal_store_free(newblock, func, linenumber);
275
    newblock = NULL;
416
    newblock = NULL;
276
    }
417
    }
Lines 279-332 Link Here
279
420
280
  if (!newblock)
421
  if (!newblock)
281
    {
422
    {
282
    if ((nbytes[pool] += mlength) > maxbytes[pool])
423
    if ((pp->nbytes += mlength) > pp->maxbytes)
283
      maxbytes[pool] = nbytes[pool];
424
      pp->maxbytes = pp->nbytes;
284
    if ((pool_malloc += mlength) > max_pool_malloc)	/* Used in pools */
425
    if ((pool_malloc += mlength) > max_pool_malloc)	/* Used in pools */
285
      max_pool_malloc = pool_malloc;
426
      max_pool_malloc = pool_malloc;
286
    nonpool_malloc -= mlength;			/* Exclude from overall total */
427
    nonpool_malloc -= mlength;			/* Exclude from overall total */
287
    if (++nblocks[pool] > maxblocks[pool])
428
    if (++pp->nblocks > pp->maxblocks)
288
      maxblocks[pool] = nblocks[pool];
429
      pp->maxblocks = pp->nblocks;
289
430
290
    newblock = internal_store_malloc(mlength, func, linenumber);
431
#ifndef MISSING_POSIX_MEMALIGN
432
    if (align_mem)
433
      {
434
      long pgsize = sysconf(_SC_PAGESIZE);
435
      int err = posix_memalign((void **)&newblock,
436
				pgsize, (mlength + pgsize - 1) & ~(pgsize - 1));
437
      if (err)
438
	log_write(0, LOG_MAIN|LOG_PANIC_DIE,
439
	  "failed to alloc (using posix_memalign) %d bytes of memory: '%s'"
440
	  "called from line %d in %s",
441
	  size, strerror(err), linenumber, func);
442
      }
443
    else
444
#endif
445
      newblock = internal_store_malloc(mlength, func, linenumber);
291
    newblock->next = NULL;
446
    newblock->next = NULL;
292
    newblock->length = length;
447
    newblock->length = length;
448
#ifndef RESTRICTED_MEMORY
449
    if (pp->store_block_order++ > pp->maxorder)
450
      pp->maxorder = pp->store_block_order;
451
#endif
293
452
294
    if (!chainbase[pool])
453
    if (! pp->chainbase)
295
      chainbase[pool] = newblock;
454
       pp->chainbase = newblock;
296
    else
455
    else
297
      current_block[pool]->next = newblock;
456
      pp->current_block->next = newblock;
298
    }
457
    }
299
458
300
  current_block[pool] = newblock;
459
  pp->current_block = newblock;
301
  yield_length[pool] = newblock->length;
460
  pp->yield_length = newblock->length;
302
  next_yield[pool] =
461
  pp->next_yield =
303
    (void *)(CS current_block[pool] + ALIGNED_SIZEOF_STOREBLOCK);
462
    (void *)(CS pp->current_block + ALIGNED_SIZEOF_STOREBLOCK);
304
  (void) VALGRIND_MAKE_MEM_NOACCESS(next_yield[pool], yield_length[pool]);
463
  (void) VALGRIND_MAKE_MEM_NOACCESS(pp->next_yield, pp->yield_length);
305
  }
464
  }
306
465
307
/* There's (now) enough room in the current block; the yield is the next
466
/* There's (now) enough room in the current block; the yield is the next
308
pointer. */
467
pointer. */
309
468
310
store_last_get[pool] = next_yield[pool];
469
pp->store_last_get = pp->next_yield;
311
470
312
/* Cut out the debugging stuff for utilities, but stop picky compilers from
471
(void) VALGRIND_MAKE_MEM_UNDEFINED(pp->store_last_get, size);
313
giving warnings. */
472
/* Update next pointer and number of bytes left in the current block. */
314
473
315
#ifdef COMPILE_UTILITY
474
pp->next_yield = (void *)(CS pp->next_yield + size);
316
func = func;
475
pp->yield_length -= size;
317
linenumber = linenumber;
476
return pp->store_last_get;
318
#else
477
}
319
DEBUG(D_memory)
320
  debug_printf("---%d Get %6p %5d %-14s %4d\n", pool,
321
    store_last_get[pool], size, func, linenumber);
322
#endif  /* COMPILE_UTILITY */
323
478
324
(void) VALGRIND_MAKE_MEM_UNDEFINED(store_last_get[pool], size);
479
/*************************************************
325
/* Update next pointer and number of bytes left in the current block. */
480
*       Get a block from the current pool        *
481
*************************************************/
326
482
327
next_yield[pool] = (void *)(CS next_yield[pool] + size);
483
/* Running out of store is a total disaster. This function is called via the
328
yield_length[pool] -= size;
484
macro store_get(). The current store_pool is used, adjusting for taint.
329
return store_last_get[pool];
485
If the protoype is quoted, use a quoted-pool.
486
Return a block of store within the current big block of the pool, getting a new
487
one if necessary. The address is saved in store_last_get for the pool.
488
489
Arguments:
490
  size        amount wanted, bytes
491
  proto_mem   class: get store conformant to this
492
		Special values: 0 forces untainted, 1 forces tainted
493
  func        function from which called
494
  linenumber  line number in source file
495
496
Returns:      pointer to store (panic on malloc failure)
497
*/
498
499
void *
500
store_get_3(int size, const void * proto_mem, const char * func, int linenumber)
501
{
502
#ifndef COMPILE_UTILITY
503
int quoter = quoter_for_address(proto_mem);
504
#endif
505
pooldesc * pp;
506
void * yield;
507
508
#ifndef COMPILE_UTILITY
509
if (!is_real_quoter(quoter))
510
#endif
511
  {
512
  BOOL tainted = is_tainted(proto_mem);
513
  int pool = tainted ? store_pool + POOL_TAINT_BASE : store_pool;
514
  pp = paired_pools + pool;
515
  yield = pool_get(pp, size, (pool == POOL_CONFIG), func, linenumber);
516
517
  /* Cut out the debugging stuff for utilities, but stop picky compilers from
518
  giving warnings. */
519
520
#ifndef COMPILE_UTILITY
521
  DEBUG(D_memory)
522
    debug_printf("---%d Get %6p %5d %-14s %4d\n", pool,
523
      pp->store_last_get, size, func, linenumber);
524
#endif
525
  }
526
#ifndef COMPILE_UTILITY
527
else
528
  {
529
  DEBUG(D_memory)
530
    debug_printf("allocating quoted-block for quoter %u (from %s %d)\n",
531
      quoter, func, linenumber);
532
  if (!(pp = pool_for_quoter(quoter))) pp = quoted_pool_new(quoter);
533
  yield = pool_get(pp, size, FALSE, func, linenumber);
534
  DEBUG(D_memory)
535
    debug_printf("---QQ Get %6p %5d %-14s %4d\n",
536
      pp->store_last_get, size, func, linenumber);
537
  }
538
#endif
539
return yield;
330
}
540
}
331
541
332
542
Lines 340-345 Link Here
340
550
341
Arguments:
551
Arguments:
342
  size        amount wanted
552
  size        amount wanted
553
  proto_mem   class: get store conformant to this
343
  func        function from which called
554
  func        function from which called
344
  linenumber  line number in source file
555
  linenumber  line number in source file
345
556
Lines 347-363 Link Here
347
*/
558
*/
348
559
349
void *
560
void *
350
store_get_perm_3(int size, BOOL tainted, const char *func, int linenumber)
561
store_get_perm_3(int size, const void * proto_mem, const char * func, int linenumber)
351
{
562
{
352
void *yield;
563
void * yield;
353
int old_pool = store_pool;
564
int old_pool = store_pool;
354
store_pool = POOL_PERM;
565
store_pool = POOL_PERM;
355
yield = store_get_3(size, tainted, func, linenumber);
566
yield = store_get_3(size, proto_mem, func, linenumber);
356
store_pool = old_pool;
567
store_pool = old_pool;
357
return yield;
568
return yield;
358
}
569
}
359
570
360
571
572
#ifndef COMPILE_UTILITY
573
/*************************************************
574
*  Get a block annotated as being lookup-quoted  *
575
*************************************************/
576
577
/* Allocate from pool a pool consistent with the proto_mem augmented by the
578
requested quoter type.
579
580
XXX currently not handling mark/release
581
582
Args:	size		number of bytes to allocate
583
	quoter		id for the quoting type
584
	func		caller, for debug
585
	linenumber	caller, for debug
586
587
Return:	allocated memory block
588
*/
589
590
static void *
591
store_force_get_quoted(int size, unsigned quoter,
592
  const char * func, int linenumber)
593
{
594
pooldesc * pp = pool_for_quoter(quoter);
595
void * yield;
596
597
DEBUG(D_memory)
598
  debug_printf("allocating quoted-block for quoter %u (from %s %d)\n", quoter, func, linenumber);
599
600
if (!pp) pp = quoted_pool_new(quoter);
601
yield = pool_get(pp, size, FALSE, func, linenumber);
602
603
DEBUG(D_memory)
604
  debug_printf("---QQ Get %6p %5d %-14s %4d\n",
605
    pp->store_last_get, size, func, linenumber);
606
607
return yield;
608
}
609
610
/* Maybe get memory for the specified quoter, but only if the
611
prototype memory is tainted. Otherwise, get plain memory.
612
*/
613
void *
614
store_get_quoted_3(int size, const void * proto_mem, unsigned quoter,
615
  const char * func, int linenumber)
616
{
617
// debug_printf("store_get_quoted_3: quoter %u\n", quoter);
618
return is_tainted(proto_mem)
619
  ? store_force_get_quoted(size, quoter, func, linenumber)
620
  : store_get_3(size, proto_mem, func, linenumber);
621
}
622
623
/* Return quoter for given address, or -1 if not in a quoted-pool. */
624
int
625
quoter_for_address(const void * p)
626
{
627
for (quoted_pooldesc * qp = quoted_pools; qp; qp = qp->next)
628
  {
629
  pooldesc * pp = &qp->pool;
630
  storeblock * b;
631
632
  if (b = pp->current_block)
633
    if (is_pointer_in_block(b, p))
634
      return qp->quoter;
635
636
  for (b = pp->chainbase; b; b = b->next)
637
    if (is_pointer_in_block(b, p))
638
      return qp->quoter;
639
  }
640
return -1;
641
}
642
643
/* Return TRUE iff the given address is quoted for the given type.
644
There is extra complexity to handle lookup providers with multiple
645
find variants but shared quote functions. */
646
BOOL
647
is_quoted_like(const void * p, unsigned quoter)
648
{
649
int pq = quoter_for_address(p);
650
BOOL y =
651
  is_real_quoter(pq) && lookup_list[pq]->quote == lookup_list[quoter]->quote;
652
/* debug_printf("is_quoted(%p, %u): %c\n", p, quoter, y?'T':'F'); */
653
return y;
654
}
655
656
/* Return TRUE if the quoter value indicates an actual quoter */
657
BOOL
658
is_real_quoter(int quoter)
659
{
660
return quoter >= 0;
661
}
662
663
/* Return TRUE if the "new" data requires that the "old" data
664
be recopied to new-class memory.  We order the classes as
665
666
  2: tainted, not quoted
667
  1: quoted (which is also tainted)
668
  0: untainted
669
670
If the "new" is higher-order than the "old", they are not compatible
671
and a copy is needed.  If both are quoted, but the quoters differ,
672
not compatible.  Otherwise they are compatible.
673
*/
674
BOOL
675
is_incompatible_fn(const void * old, const void * new)
676
{
677
int oq, nq;
678
unsigned oi, ni;
679
680
ni = is_real_quoter(nq = quoter_for_address(new)) ? 1 : is_tainted(new) ? 2 : 0;
681
oi = is_real_quoter(oq = quoter_for_address(old)) ? 1 : is_tainted(old) ? 2 : 0;
682
return ni > oi || ni == oi && nq != oq;
683
}
684
685
#endif	/*!COMPILE_UTILITY*/
361
686
362
/*************************************************
687
/*************************************************
363
*      Extend a block if it is at the top        *
688
*      Extend a block if it is at the top        *
Lines 380-392 Link Here
380
Returns:     TRUE if the block is at the top of the stack and has been
705
Returns:     TRUE if the block is at the top of the stack and has been
381
             extended; FALSE if it isn't at the top of the stack, or cannot
706
             extended; FALSE if it isn't at the top of the stack, or cannot
382
             be extended
707
             be extended
708
709
XXX needs extension for quoted-tracking.  This assumes that the global store_pool
710
is the one to alloc from, which breaks with separated pools.
383
*/
711
*/
384
712
385
BOOL
713
BOOL
386
store_extend_3(void *ptr, BOOL tainted, int oldsize, int newsize,
714
store_extend_3(void * ptr, int oldsize, int newsize,
387
   const char *func, int linenumber)
715
   const char * func, int linenumber)
388
{
716
{
389
int pool = tainted ? store_pool + POOL_TAINT_BASE : store_pool;
717
pooldesc * pp = pool_for_pointer(ptr, func, linenumber);
390
int inc = newsize - oldsize;
718
int inc = newsize - oldsize;
391
int rounded_oldsize = oldsize;
719
int rounded_oldsize = oldsize;
392
720
Lines 395-428 Link Here
395
            "bad memory extension requested (%d -> %d bytes) at %s %d",
723
            "bad memory extension requested (%d -> %d bytes) at %s %d",
396
            oldsize, newsize, func, linenumber);
724
            oldsize, newsize, func, linenumber);
397
725
398
/* Check that the block being extended was already of the required taint status;
399
refuse to extend if not. */
400
401
if (is_tainted(ptr) != tainted)
402
  return FALSE;
403
404
if (rounded_oldsize % alignment != 0)
726
if (rounded_oldsize % alignment != 0)
405
  rounded_oldsize += alignment - (rounded_oldsize % alignment);
727
  rounded_oldsize += alignment - (rounded_oldsize % alignment);
406
728
407
if (CS ptr + rounded_oldsize != CS (next_yield[pool]) ||
729
if (CS ptr + rounded_oldsize != CS (pp->next_yield) ||
408
    inc > yield_length[pool] + rounded_oldsize - oldsize)
730
    inc > pp->yield_length + rounded_oldsize - oldsize)
409
  return FALSE;
731
  return FALSE;
410
732
411
/* Cut out the debugging stuff for utilities, but stop picky compilers from
733
/* Cut out the debugging stuff for utilities, but stop picky compilers from
412
giving warnings. */
734
giving warnings. */
413
735
414
#ifdef COMPILE_UTILITY
736
#ifndef COMPILE_UTILITY
415
func = func;
416
linenumber = linenumber;
417
#else
418
DEBUG(D_memory)
737
DEBUG(D_memory)
419
  debug_printf("---%d Ext %6p %5d %-14s %4d\n", pool, ptr, newsize,
738
  {
420
    func, linenumber);
739
  quoted_pooldesc * qp;
740
  for (qp = quoted_pools; qp; qp = qp->next)
741
    if (pp == &qp->pool)
742
      {
743
      debug_printf("---Q%d Ext %6p %5d %-14s %4d\n",
744
	(int)(qp - quoted_pools),
745
	ptr, newsize, func, linenumber);
746
      break;
747
      }
748
  if (!qp)
749
    debug_printf("---%d Ext %6p %5d %-14s %4d\n",
750
      (int)(pp - paired_pools),
751
      ptr, newsize, func, linenumber);
752
  }
421
#endif  /* COMPILE_UTILITY */
753
#endif  /* COMPILE_UTILITY */
422
754
423
if (newsize % alignment != 0) newsize += alignment - (newsize % alignment);
755
if (newsize % alignment != 0) newsize += alignment - (newsize % alignment);
424
next_yield[pool] = CS ptr + newsize;
756
pp->next_yield = CS ptr + newsize;
425
yield_length[pool] -= newsize - rounded_oldsize;
757
pp->yield_length -= newsize - rounded_oldsize;
426
(void) VALGRIND_MAKE_MEM_UNDEFINED(ptr + oldsize, inc);
758
(void) VALGRIND_MAKE_MEM_UNDEFINED(ptr + oldsize, inc);
427
return TRUE;
759
return TRUE;
428
}
760
}
Lines 430-435 Link Here
430
762
431
763
432
764
765
static BOOL
766
is_pwr2_size(int len)
767
{
768
unsigned x = len;
769
return (x & (x - 1)) == 0;
770
}
771
772
433
/*************************************************
773
/*************************************************
434
*    Back up to a previous point on the stack    *
774
*    Back up to a previous point on the stack    *
435
*************************************************/
775
*************************************************/
Lines 439-446 Link Here
439
not call with a pointer returned by store_get().  Both the untainted and tainted
779
not call with a pointer returned by store_get().  Both the untainted and tainted
440
pools corresposding to store_pool are reset.
780
pools corresposding to store_pool are reset.
441
781
782
Quoted pools are not handled.
783
442
Arguments:
784
Arguments:
443
  r           place to back up to
785
  ptr         place to back up to
786
  pool	      pool holding the pointer
444
  func        function from which called
787
  func        function from which called
445
  linenumber  line number in source file
788
  linenumber  line number in source file
446
789
Lines 451-473 Link Here
451
internal_store_reset(void * ptr, int pool, const char *func, int linenumber)
794
internal_store_reset(void * ptr, int pool, const char *func, int linenumber)
452
{
795
{
453
storeblock * bb;
796
storeblock * bb;
454
storeblock * b = current_block[pool];
797
pooldesc * pp = paired_pools + pool;
798
storeblock * b = pp->current_block;
455
char * bc = CS b + ALIGNED_SIZEOF_STOREBLOCK;
799
char * bc = CS b + ALIGNED_SIZEOF_STOREBLOCK;
456
int newlength, count;
800
int newlength, count;
457
#ifndef COMPILE_UTILITY
801
#ifndef COMPILE_UTILITY
458
int oldmalloc = pool_malloc;
802
int oldmalloc = pool_malloc;
459
#endif
803
#endif
460
804
805
if (!b) return;	/* exim_dumpdb gets this, becuse it has never used tainted mem */
806
461
/* Last store operation was not a get */
807
/* Last store operation was not a get */
462
808
463
store_last_get[pool] = NULL;
809
pp->store_last_get = NULL;
464
810
465
/* See if the place is in the current block - as it often will be. Otherwise,
811
/* See if the place is in the current block - as it often will be. Otherwise,
466
search for the block in which it lies. */
812
search for the block in which it lies. */
467
813
468
if (CS ptr < bc || CS ptr > bc + b->length)
814
if (CS ptr < bc || CS ptr > bc + b->length)
469
  {
815
  {
470
  for (b = chainbase[pool]; b; b = b->next)
816
  for (b =  pp->chainbase; b; b = b->next)
471
    {
817
    {
472
    bc = CS b + ALIGNED_SIZEOF_STOREBLOCK;
818
    bc = CS b + ALIGNED_SIZEOF_STOREBLOCK;
473
    if (CS ptr >= bc && CS ptr <= bc + b->length) break;
819
    if (CS ptr >= bc && CS ptr <= bc + b->length) break;
Lines 493-511 Link Here
493
  }
839
  }
494
#endif
840
#endif
495
(void) VALGRIND_MAKE_MEM_NOACCESS(ptr, newlength);
841
(void) VALGRIND_MAKE_MEM_NOACCESS(ptr, newlength);
496
next_yield[pool] = CS ptr + (newlength % alignment);
842
pp->next_yield = CS ptr + (newlength % alignment);
497
count = yield_length[pool];
843
count = pp->yield_length;
498
count = (yield_length[pool] = newlength - (newlength % alignment)) - count;
844
count = (pp->yield_length = newlength - (newlength % alignment)) - count;
499
current_block[pool] = b;
845
pp->current_block = b;
500
846
501
/* Free any subsequent block. Do NOT free the first
847
/* Free any subsequent block. Do NOT free the first
502
successor, if our current block has less than 256 bytes left. This should
848
successor, if our current block has less than 256 bytes left. This should
503
prevent us from flapping memory. However, keep this block only when it has
849
prevent us from flapping memory. However, keep this block only when it has
504
the default size. */
850
a power-of-two size so probably is not a custom inflated one. */
505
851
506
if (  yield_length[pool] < STOREPOOL_MIN_SIZE
852
if (  pp->yield_length < STOREPOOL_MIN_SIZE
507
   && b->next
853
   && b->next
508
   && b->next->length == STORE_BLOCK_SIZE)
854
   && is_pwr2_size(b->next->length + ALIGNED_SIZEOF_STOREBLOCK))
509
  {
855
  {
510
  b = b->next;
856
  b = b->next;
511
#ifndef COMPILE_UTILITY
857
#ifndef COMPILE_UTILITY
Lines 518-573 Link Here
518
  }
864
  }
519
865
520
bb = b->next;
866
bb = b->next;
521
b->next = NULL;
867
if (pool != POOL_CONFIG)
868
  b->next = NULL;
522
869
523
while ((b = bb))
870
while ((b = bb))
524
  {
871
  {
525
  int siz = b->length + ALIGNED_SIZEOF_STOREBLOCK;
872
  int siz = b->length + ALIGNED_SIZEOF_STOREBLOCK;
873
526
#ifndef COMPILE_UTILITY
874
#ifndef COMPILE_UTILITY
527
  if (debug_store)
875
  if (debug_store)
528
    assert_no_variables(b, b->length + ALIGNED_SIZEOF_STOREBLOCK,
876
    assert_no_variables(b, b->length + ALIGNED_SIZEOF_STOREBLOCK,
529
			func, linenumber);
877
			func, linenumber);
530
#endif
878
#endif
531
  bb = bb->next;
879
  bb = bb->next;
532
  nbytes[pool] -= siz;
880
  pp->nbytes -= siz;
533
  pool_malloc -= siz;
881
  pool_malloc -= siz;
534
  nblocks[pool]--;
882
  pp->nblocks--;
535
  internal_store_free(b, func, linenumber);
883
  if (pool != POOL_CONFIG)
884
    internal_store_free(b, func, linenumber);
885
886
#ifndef RESTRICTED_MEMORY
887
  if (pp->store_block_order > 13) pp->store_block_order--;
888
#endif
536
  }
889
  }
537
890
538
/* Cut out the debugging stuff for utilities, but stop picky compilers from
891
/* Cut out the debugging stuff for utilities, but stop picky compilers from
539
giving warnings. */
892
giving warnings. */
540
893
541
#ifdef COMPILE_UTILITY
894
#ifndef COMPILE_UTILITY
542
func = func;
543
linenumber = linenumber;
544
#else
545
DEBUG(D_memory)
895
DEBUG(D_memory)
546
  debug_printf("---%d Rst %6p %5d %-14s %4d %d\n", pool, ptr,
896
  debug_printf("---%d Rst %6p %5d %-14s %4d\tpool %d\n", pool, ptr,
547
    count + oldmalloc - pool_malloc,
897
    count + oldmalloc - pool_malloc,
548
    func, linenumber, pool_malloc);
898
    func, linenumber, pool_malloc);
549
#endif  /* COMPILE_UTILITY */
899
#endif  /* COMPILE_UTILITY */
550
}
900
}
551
901
552
902
903
/* Back up the pool pair, untainted and tainted, of the store_pool setting.
904
Quoted pools are not handled.
905
*/
906
553
rmark
907
rmark
554
store_reset_3(rmark r, int pool, const char *func, int linenumber)
908
store_reset_3(rmark r, const char * func, int linenumber)
555
{
909
{
556
void ** ptr = r;
910
void ** ptr = r;
557
911
558
if (pool >= POOL_TAINT_BASE)
912
if (store_pool >= POOL_TAINT_BASE)
559
  log_write(0, LOG_MAIN|LOG_PANIC_DIE,
913
  log_write(0, LOG_MAIN|LOG_PANIC_DIE,
560
    "store_reset called for pool %d: %s %d\n", pool, func, linenumber);
914
    "store_reset called for pool %d: %s %d\n", store_pool, func, linenumber);
561
if (!r)
915
if (!r)
562
  log_write(0, LOG_MAIN|LOG_PANIC_DIE,
916
  log_write(0, LOG_MAIN|LOG_PANIC_DIE,
563
    "store_reset called with bad mark: %s %d\n", func, linenumber);
917
    "store_reset called with bad mark: %s %d\n", func, linenumber);
564
918
565
internal_store_reset(*ptr, pool + POOL_TAINT_BASE, func, linenumber);
919
internal_store_reset(*ptr, store_pool + POOL_TAINT_BASE, func, linenumber);
566
internal_store_reset(ptr,  pool,		   func, linenumber);
920
internal_store_reset(ptr,  store_pool,		   func, linenumber);
567
return NULL;
921
return NULL;
568
}
922
}
569
923
570
924
925
/**************/
571
926
572
/* Free tail-end unused allocation.  This lets us allocate a big chunk
927
/* Free tail-end unused allocation.  This lets us allocate a big chunk
573
early, for cases when we only discover later how much was really needed.
928
early, for cases when we only discover later how much was really needed.
Lines 580-611 Link Here
580
*/
935
*/
581
936
582
void
937
void
583
store_release_above_3(void *ptr, const char *func, int linenumber)
938
store_release_above_3(void * ptr, const char * func, int linenumber)
584
{
939
{
940
pooldesc * pp;
941
585
/* Search all pools' "current" blocks.  If it isn't one of those,
942
/* Search all pools' "current" blocks.  If it isn't one of those,
586
ignore it (it usually will be). */
943
ignore it (it usually will be). */
587
944
588
for (int pool = 0; pool < nelem(current_block); pool++)
945
if ((pp = pool_current_for_pointer(ptr)))
589
  {
946
  {
590
  storeblock * b = current_block[pool];
947
  storeblock * b = pp->current_block;
591
  char * bc;
592
  int count, newlength;
948
  int count, newlength;
593
949
594
  if (!b)
595
    continue;
596
597
  bc = CS b + ALIGNED_SIZEOF_STOREBLOCK;
598
  if (CS ptr < bc || CS ptr > bc + b->length)
599
    continue;
600
601
  /* Last store operation was not a get */
950
  /* Last store operation was not a get */
602
951
603
  store_last_get[pool] = NULL;
952
  pp->store_last_get = NULL;
604
953
605
  /* Back up, rounding to the alignment if necessary. When testing, flatten
954
  /* Back up, rounding to the alignment if necessary. When testing, flatten
606
  the released memory. */
955
  the released memory. */
607
956
608
  newlength = bc + b->length - CS ptr;
957
  newlength = (CS b + ALIGNED_SIZEOF_STOREBLOCK) + b->length - CS ptr;
609
#ifndef COMPILE_UTILITY
958
#ifndef COMPILE_UTILITY
610
  if (debug_store)
959
  if (debug_store)
611
    {
960
    {
Lines 618-637 Link Here
618
    }
967
    }
619
#endif
968
#endif
620
  (void) VALGRIND_MAKE_MEM_NOACCESS(ptr, newlength);
969
  (void) VALGRIND_MAKE_MEM_NOACCESS(ptr, newlength);
621
  next_yield[pool] = CS ptr + (newlength % alignment);
970
  pp->next_yield = CS ptr + (newlength % alignment);
622
  count = yield_length[pool];
971
  count = pp->yield_length;
623
  count = (yield_length[pool] = newlength - (newlength % alignment)) - count;
972
  count = (pp->yield_length = newlength - (newlength % alignment)) - count;
624
973
625
  /* Cut out the debugging stuff for utilities, but stop picky compilers from
974
  /* Cut out the debugging stuff for utilities, but stop picky compilers from
626
  giving warnings. */
975
  giving warnings. */
627
976
628
#ifdef COMPILE_UTILITY
977
#ifndef COMPILE_UTILITY
629
  func = func;
630
  linenumber = linenumber;
631
#else
632
  DEBUG(D_memory)
978
  DEBUG(D_memory)
633
    debug_printf("---%d Rel %6p %5d %-14s %4d %d\n", pool, ptr, count,
979
    {
634
      func, linenumber, pool_malloc);
980
    quoted_pooldesc * qp;
981
    for (qp = quoted_pools; qp; qp = qp->next)
982
      if (pp == &qp->pool)
983
	debug_printf("---Q%d Rel %6p %5d %-14s %4d\tpool %d\n",
984
	  (int)(qp - quoted_pools),
985
	  ptr, count, func, linenumber, pool_malloc);
986
    if (!qp)
987
      debug_printf("---%d Rel %6p %5d %-14s %4d\tpool %d\n",
988
	(int)(pp - paired_pools), ptr, count,
989
	func, linenumber, pool_malloc);
990
    }
635
#endif
991
#endif
636
  return;
992
  return;
637
  }
993
  }
Lines 644-653 Link Here
644
1000
645
1001
646
rmark
1002
rmark
647
store_mark_3(const char *func, int linenumber)
1003
store_mark_3(const char * func, int linenumber)
648
{
1004
{
649
void ** p;
1005
void ** p;
650
1006
1007
#ifndef COMPILE_UTILITY
1008
DEBUG(D_memory)
1009
  debug_printf("---%d Mrk                    %-14s %4d\tpool %d\n",
1010
    store_pool, func, linenumber, pool_malloc);
1011
#endif  /* COMPILE_UTILITY */
1012
651
if (store_pool >= POOL_TAINT_BASE)
1013
if (store_pool >= POOL_TAINT_BASE)
652
  log_write(0, LOG_MAIN|LOG_PANIC_DIE,
1014
  log_write(0, LOG_MAIN|LOG_PANIC_DIE,
653
    "store_mark called for pool %d: %s %d\n", store_pool, func, linenumber);
1015
    "store_mark called for pool %d: %s %d\n", store_pool, func, linenumber);
Lines 657-664 Link Here
657
Reset uses the cookie to recover the t-mark, winds back the tainted pool with it
1019
Reset uses the cookie to recover the t-mark, winds back the tainted pool with it
658
and winds back the untainted pool with the cookie. */
1020
and winds back the untainted pool with the cookie. */
659
1021
660
p = store_get_3(sizeof(void *), FALSE, func, linenumber);
1022
p = store_get_3(sizeof(void *), GET_UNTAINTED, func, linenumber);
661
*p = store_get_3(0, TRUE, func, linenumber);
1023
*p = store_get_3(0, GET_TAINTED, func, linenumber);
662
return p;
1024
return p;
663
}
1025
}
664
1026
Lines 674-679 Link Here
674
1036
675
Arguments:
1037
Arguments:
676
  block       block of store to consider
1038
  block       block of store to consider
1039
  pp	      pool containing the block
677
  func        function from which called
1040
  func        function from which called
678
  linenumber  line number in source file
1041
  linenumber  line number in source file
679
1042
Lines 681-708 Link Here
681
*/
1044
*/
682
1045
683
static void
1046
static void
684
store_release_3(void * block, int pool, const char * func, int linenumber)
1047
store_release_3(void * block, pooldesc * pp, const char * func, int linenumber)
685
{
1048
{
686
/* It will never be the first block, so no need to check that. */
1049
/* It will never be the first block, so no need to check that. */
687
1050
688
for (storeblock * b = chainbase[pool]; b; b = b->next)
1051
for (storeblock * b =  pp->chainbase; b; b = b->next)
689
  {
1052
  {
690
  storeblock * bb = b->next;
1053
  storeblock * bb = b->next;
691
  if (bb && CS block == CS bb + ALIGNED_SIZEOF_STOREBLOCK)
1054
  if (bb && CS block == CS bb + ALIGNED_SIZEOF_STOREBLOCK)
692
    {
1055
    {
693
    int siz = bb->length + ALIGNED_SIZEOF_STOREBLOCK;
1056
    int siz = bb->length + ALIGNED_SIZEOF_STOREBLOCK;
694
    b->next = bb->next;
1057
    b->next = bb->next;
695
    nbytes[pool] -= siz;
1058
    pp->nbytes -= siz;
696
    pool_malloc -= siz;
1059
    pool_malloc -= siz;
697
    nblocks[pool]--;
1060
    pp->nblocks--;
698
1061
699
    /* Cut out the debugging stuff for utilities, but stop picky compilers
1062
    /* Cut out the debugging stuff for utilities, but stop picky compilers
700
    from giving warnings. */
1063
    from giving warnings. */
701
1064
702
#ifdef COMPILE_UTILITY
1065
#ifndef COMPILE_UTILITY
703
    func = func;
704
    linenumber = linenumber;
705
#else
706
    DEBUG(D_memory)
1066
    DEBUG(D_memory)
707
      debug_printf("-Release %6p %-20s %4d %d\n", (void *)bb, func,
1067
      debug_printf("-Release %6p %-20s %4d %d\n", (void *)bb, func,
708
	linenumber, pool_malloc);
1068
	linenumber, pool_malloc);
Lines 711-717 Link Here
711
      memset(bb, 0xF0, bb->length+ALIGNED_SIZEOF_STOREBLOCK);
1071
      memset(bb, 0xF0, bb->length+ALIGNED_SIZEOF_STOREBLOCK);
712
#endif  /* COMPILE_UTILITY */
1072
#endif  /* COMPILE_UTILITY */
713
1073
714
    free(bb);
1074
    internal_store_free(bb, func, linenumber);
715
    return;
1075
    return;
716
    }
1076
    }
717
  }
1077
  }
Lines 735-769 Link Here
735
has been allocated since. If so, releases that block.
1095
has been allocated since. If so, releases that block.
736
1096
737
Arguments:
1097
Arguments:
738
  block
1098
  oldblock
739
  newsize
1099
  newsize	requested size
740
  len
1100
  len		current size
741
1101
742
Returns:	new location of data
1102
Returns:	new location of data
743
*/
1103
*/
744
1104
745
void *
1105
void *
746
store_newblock_3(void * block, BOOL tainted, int newsize, int len,
1106
store_newblock_3(void * oldblock, int newsize, int len,
747
  const char * func, int linenumber)
1107
  const char * func, int linenumber)
748
{
1108
{
749
int pool = tainted ? store_pool + POOL_TAINT_BASE : store_pool;
1109
pooldesc * pp = pool_for_pointer(oldblock, func, linenumber);
750
BOOL release_ok = !tainted && store_last_get[pool] == block;
1110
BOOL release_ok = !is_tainted(oldblock) && pp->store_last_get == oldblock;		/*XXX why tainted not handled? */
751
uschar * newtext;
1111
uschar * newblock;
752
753
#if !defined(MACRO_PREDEF) && !defined(COMPILE_UTILITY)
754
if (is_tainted(block) != tainted)
755
  die_tainted(US"store_newblock", CUS func, linenumber);
756
#endif
757
1112
758
if (len < 0 || len > newsize)
1113
if (len < 0 || len > newsize)
759
  log_write(0, LOG_MAIN|LOG_PANIC_DIE,
1114
  log_write(0, LOG_MAIN|LOG_PANIC_DIE,
760
            "bad memory extension requested (%d -> %d bytes) at %s %d",
1115
            "bad memory extension requested (%d -> %d bytes) at %s %d",
761
            len, newsize, func, linenumber);
1116
            len, newsize, func, linenumber);
762
1117
763
newtext = store_get(newsize, tainted);
1118
newblock = store_get(newsize, oldblock);
764
memcpy(newtext, block, len);
1119
memcpy(newblock, oldblock, len);
765
if (release_ok) store_release_3(block, pool, func, linenumber);
1120
if (release_ok) store_release_3(oldblock, pp, func, linenumber);
766
return (void *)newtext;
1121
return (void *)newblock;
767
}
1122
}
768
1123
769
1124
Lines 786-822 Link Here
786
*/
1141
*/
787
1142
788
static void *
1143
static void *
789
internal_store_malloc(int size, const char *func, int line)
1144
internal_store_malloc(size_t size, const char *func, int line)
790
{
1145
{
791
void * yield;
1146
void * yield;
792
1147
793
if (size < 0 || size >= INT_MAX/2)
1148
/* Check specifically for a possibly result of conversion from
1149
a negative int, to the (unsigned, wider) size_t */
1150
1151
if (size >= INT_MAX/2)
794
  log_write(0, LOG_MAIN|LOG_PANIC_DIE,
1152
  log_write(0, LOG_MAIN|LOG_PANIC_DIE,
795
            "bad memory allocation requested (%d bytes) at %s %d",
1153
    "bad internal_store_malloc request (" SIZE_T_FMT " bytes) from %s %d",
796
            size, func, line);
1154
    size, func, line);
797
1155
1156
size += sizeof(size_t);	/* space to store the size, used under debug */
798
if (size < 16) size = 16;
1157
if (size < 16) size = 16;
799
1158
800
if (!(yield = malloc((size_t)size)))
1159
if (!(yield = malloc(size)))
801
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to malloc %d bytes of memory: "
1160
  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to malloc " SIZE_T_FMT " bytes of memory: "
802
    "called from line %d in %s", size, line, func);
1161
    "called from line %d in %s", size, line, func);
803
1162
1163
#ifndef COMPILE_UTILITY
1164
DEBUG(D_any) *(size_t *)yield = size;
1165
#endif
1166
yield = US yield + sizeof(size_t);
1167
804
if ((nonpool_malloc += size) > max_nonpool_malloc)
1168
if ((nonpool_malloc += size) > max_nonpool_malloc)
805
  max_nonpool_malloc = nonpool_malloc;
1169
  max_nonpool_malloc = nonpool_malloc;
806
1170
807
/* Cut out the debugging stuff for utilities, but stop picky compilers from
1171
/* Cut out the debugging stuff for utilities, but stop picky compilers from
808
giving warnings. */
1172
giving warnings. */
809
1173
810
#ifdef COMPILE_UTILITY
1174
#ifndef COMPILE_UTILITY
811
func = func; line = line;
812
#else
813
814
/* If running in test harness, spend time making sure all the new store
1175
/* If running in test harness, spend time making sure all the new store
815
is not filled with zeros so as to catch problems. */
1176
is not filled with zeros so as to catch problems. */
816
1177
817
if (f.running_in_test_harness)
1178
if (f.running_in_test_harness)
818
  memset(yield, 0xF0, (size_t)size);
1179
  memset(yield, 0xF0, size - sizeof(size_t));
819
DEBUG(D_memory) debug_printf("--Malloc %6p %5d bytes\t%-14s %4d\tpool %5d  nonpool %5d\n",
1180
DEBUG(D_memory) debug_printf("--Malloc %6p %5lu bytes\t%-20s %4d\tpool %5d  nonpool %5d\n",
820
  yield, size, func, line, pool_malloc, nonpool_malloc);
1181
  yield, size, func, line, pool_malloc, nonpool_malloc);
821
#endif  /* COMPILE_UTILITY */
1182
#endif  /* COMPILE_UTILITY */
822
1183
Lines 824-830 Link Here
824
}
1185
}
825
1186
826
void *
1187
void *
827
store_malloc_3(int size, const char *func, int linenumber)
1188
store_malloc_3(size_t size, const char *func, int linenumber)
828
{
1189
{
829
if (n_nonpool_blocks++ > max_nonpool_blocks)
1190
if (n_nonpool_blocks++ > max_nonpool_blocks)
830
  max_nonpool_blocks = n_nonpool_blocks;
1191
  max_nonpool_blocks = n_nonpool_blocks;
Lines 849-862 Link Here
849
static void
1210
static void
850
internal_store_free(void * block, const char * func, int linenumber)
1211
internal_store_free(void * block, const char * func, int linenumber)
851
{
1212
{
852
#ifdef COMPILE_UTILITY
1213
uschar * p = US block - sizeof(size_t);
853
func = func;
1214
#ifndef COMPILE_UTILITY
854
linenumber = linenumber;
1215
DEBUG(D_any) nonpool_malloc -= *(size_t *)p;
855
#else
1216
DEBUG(D_memory) debug_printf("----Free %6p %5ld bytes\t%-20s %4d\n",
856
DEBUG(D_memory)
1217
		    block, *(size_t *)p, func, linenumber);
857
  debug_printf("----Free %6p %-20s %4d\n", block, func, linenumber);
1218
#endif
858
#endif  /* COMPILE_UTILITY */
1219
free(p);
859
free(block);
860
}
1220
}
861
1221
862
void
1222
void
Lines 874-887 Link Here
874
#ifndef COMPILE_UTILITY
1234
#ifndef COMPILE_UTILITY
875
DEBUG(D_memory)
1235
DEBUG(D_memory)
876
 {
1236
 {
1237
 int i;
877
 debug_printf("----Exit nonpool max: %3d kB in %d blocks\n",
1238
 debug_printf("----Exit nonpool max: %3d kB in %d blocks\n",
878
  (max_nonpool_malloc+1023)/1024, max_nonpool_blocks);
1239
  (max_nonpool_malloc+1023)/1024, max_nonpool_blocks);
879
 debug_printf("----Exit npools  max: %3d kB\n", max_pool_malloc/1024);
1240
 debug_printf("----Exit npools  max: %3d kB\n", max_pool_malloc/1024);
880
 for (int i = 0; i < NPOOLS; i++)
1241
881
  debug_printf("----Exit  pool %d max: %3d kB in %d blocks\t%s %s\n",
1242
 for (i = 0; i < N_PAIRED_POOLS; i++)
882
    i, maxbytes[i]/1024, maxblocks[i], poolclass[i], pooluse[i]);
1243
   {
1244
   pooldesc * pp = paired_pools + i;
1245
   debug_printf("----Exit  pool %2d max: %3d kB in %d blocks at order %u\t%s %s\n",
1246
    i, (pp->maxbytes+1023)/1024, pp->maxblocks, pp->maxorder,
1247
    poolclass[i], pooluse[i]);
1248
   }
1249
 i = 0;
1250
 for (quoted_pooldesc * qp = quoted_pools; qp; i++, qp = qp->next)
1251
   {
1252
   pooldesc * pp = &qp->pool;
1253
   debug_printf("----Exit  pool Q%d max: %3d kB in %d blocks at order %u\ttainted quoted:%s\n",
1254
    i, (pp->maxbytes+1023)/1024, pp->maxblocks, pp->maxorder, lookup_list[qp->quoter]->name);
1255
   }
883
 }
1256
 }
884
#endif
1257
#endif
885
}
1258
}
886
1259
1260
1261
/******************************************************************************/
1262
/* Per-message pool management */
1263
1264
static rmark   message_reset_point    = NULL;
1265
1266
void
1267
message_start(void)
1268
{
1269
int oldpool = store_pool;
1270
store_pool = POOL_MESSAGE;
1271
if (!message_reset_point) message_reset_point = store_mark();
1272
store_pool = oldpool;
1273
}
1274
1275
void
1276
message_tidyup(void)
1277
{
1278
int oldpool;
1279
if (!message_reset_point) return;
1280
oldpool = store_pool;
1281
store_pool = POOL_MESSAGE;
1282
message_reset_point = store_reset(message_reset_point);
1283
store_pool = oldpool;
1284
}
1285
1286
/******************************************************************************/
1287
/* Debug analysis of address */
1288
1289
#ifndef COMPILE_UTILITY
1290
void
1291
debug_print_taint(const void * p)
1292
{
1293
int q = quoter_for_address(p);
1294
if (!is_tainted(p)) return;
1295
debug_printf("(tainted");
1296
if (is_real_quoter(q)) debug_printf(", quoted:%s", lookup_list[q]->name);
1297
debug_printf(")\n");
1298
}
1299
#endif
1300
887
/* End of store.c */
1301
/* End of store.c */
(-)exim.orig/src/store.h (-13 / +37 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2009 */
6
/* Copyright (c) University of Cambridge 1995 - 2009 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Header for Exim's memory allocation functions */
9
/* Header for Exim's memory allocation functions */
Lines 13-27 Link Here
13
13
14
/* Define symbols for identifying the store pools. */
14
/* Define symbols for identifying the store pools. */
15
15
16
enum { POOL_MAIN,       POOL_PERM,       POOL_SEARCH,
16
enum { POOL_MAIN,
17
       POOL_PERM,
18
       POOL_CONFIG,
19
       POOL_SEARCH,
20
       POOL_MESSAGE,
21
17
       POOL_TAINT_BASE,
22
       POOL_TAINT_BASE,
18
       POOL_TAINT_MAIN = POOL_TAINT_BASE, POOL_TAINT_PERM, POOL_TAINT_SEARCH };
23
24
       POOL_TAINT_MAIN = POOL_TAINT_BASE,
25
       POOL_TAINT_PERM,
26
       POOL_TAINT_CONFIG,
27
       POOL_TAINT_SEARCH,
28
       POOL_TAINT_MESSAGE,
29
30
       N_PAIRED_POOLS
31
};
19
32
20
/* This variable (the one for the current pool) is set by store_get() to its
33
/* This variable (the one for the current pool) is set by store_get() to its
21
yield, and by store_reset() to NULL. This allows string_cat() to optimize its
34
yield, and by store_reset() to NULL. This allows string_cat() to optimize its
22
store handling. */
35
store handling. */
23
36
24
extern void *store_last_get[6];
37
extern void * store_last_get[];
25
38
26
/* This variable contains the current store pool number. */
39
/* This variable contains the current store pool number. */
27
40
Lines 30-64 Link Here
30
/* Macros for calling the memory allocation routines with
43
/* Macros for calling the memory allocation routines with
31
tracing information for debugging. */
44
tracing information for debugging. */
32
45
33
#define store_extend(addr, tainted, old, new) \
46
#define store_extend(addr, old, new) \
34
  store_extend_3(addr, tainted, old, new, __FUNCTION__, __LINE__)
47
  store_extend_3(addr, old, new, __FUNCTION__, __LINE__)
35
48
36
#define store_free(addr) \
49
#define store_free(addr) \
37
	store_free_3(addr, __FUNCTION__, __LINE__)
50
	store_free_3(addr, __FUNCTION__, __LINE__)
38
/* store_get & store_get_perm are in local_scan.h */
51
/* store_get & store_get_perm are in local_scan.h */
52
#define store_get_quoted(size, proto_mem, quoter) \
53
	store_get_quoted_3((size), (proto_mem), (quoter), __FUNCTION__, __LINE__)
39
#define store_malloc(size) \
54
#define store_malloc(size) \
40
	store_malloc_3(size, __FUNCTION__, __LINE__)
55
	store_malloc_3(size, __FUNCTION__, __LINE__)
41
#define store_mark(void) \
56
#define store_mark(void) \
42
	store_mark_3(__FUNCTION__, __LINE__)
57
	store_mark_3(__FUNCTION__, __LINE__)
43
#define store_newblock(addr, tainted, newsize, datalen) \
58
#define store_newblock(oldblock, newsize, datalen) \
44
	store_newblock_3(addr, tainted, newsize, datalen, __FUNCTION__, __LINE__)
59
	store_newblock_3(oldblock, newsize, datalen, __FUNCTION__, __LINE__)
45
#define store_release_above(addr) \
60
#define store_release_above(addr) \
46
	store_release_above_3(addr, __FUNCTION__, __LINE__)
61
	store_release_above_3(addr, __FUNCTION__, __LINE__)
47
#define store_reset(mark) \
62
#define store_reset(mark) \
48
	store_reset_3(mark, store_pool, __FUNCTION__, __LINE__)
63
	store_reset_3(mark, __FUNCTION__, __LINE__)
49
64
50
65
51
/* The real functions */
66
/* The real functions */
52
typedef void ** rmark;
67
typedef void ** rmark;
53
68
54
extern BOOL    store_extend_3(void *, BOOL, int, int, const char *, int);
69
extern BOOL    store_extend_3(void *, int, int, const char *, int);
55
extern void    store_free_3(void *, const char *, int);
70
extern void    store_free_3(void *, const char *, int);
56
/* store_get_3 & store_get_perm_3 are in local_scan.h */
71
/* store_get_3 & store_get_perm_3 are in local_scan.h */
57
extern void   *store_malloc_3(int, const char *, int)		ALLOC ALLOC_SIZE(1) WARN_UNUSED_RESULT;
72
extern void *  store_get_quoted_3(int, const void *, unsigned, const char *, int);
73
extern void *  store_malloc_3(size_t, const char *, int)		ALLOC ALLOC_SIZE(1) WARN_UNUSED_RESULT;
58
extern rmark   store_mark_3(const char *, int);
74
extern rmark   store_mark_3(const char *, int);
59
extern void   *store_newblock_3(void *, BOOL, int, int, const char *, int);
75
extern void *  store_newblock_3(void *, int, int, const char *, int);
60
extern void    store_release_above_3(void *, const char *, int);
76
extern void    store_release_above_3(void *, const char *, int);
61
extern rmark   store_reset_3(rmark, int, const char *, int);
77
extern rmark   store_reset_3(rmark, const char *, int);
78
79
#define GET_UNTAINTED	(const void *)0
80
#define GET_TAINTED	(const void *)1
81
82
extern int	quoter_for_address(const void *);
83
extern BOOL	is_quoted_like(const void *, unsigned);
84
extern BOOL	is_real_quoter(int);
85
extern void	debug_print_taint(const void * p);
62
86
63
#endif  /* STORE_H */
87
#endif  /* STORE_H */
64
88
(-)exim.orig/src/string.c (-104 / +124 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Miscellaneous string-handling functions. Some are not required for
9
/* Miscellaneous string-handling functions. Some are not required for
Lines 298-304 Link Here
298
const uschar *t = s;
298
const uschar *t = s;
299
uschar *ss, *tt;
299
uschar *ss, *tt;
300
300
301
while (*t != 0)
301
while (*t)
302
  {
302
  {
303
  int c = *t++;
303
  int c = *t++;
304
  if (  !mac_isprint(c)
304
  if (  !mac_isprint(c)
Lines 313-319 Link Here
313
/* Get a new block of store guaranteed big enough to hold the
313
/* Get a new block of store guaranteed big enough to hold the
314
expanded string. */
314
expanded string. */
315
315
316
tt = ss = store_get(length + nonprintcount * 3 + 1, is_tainted(s));
316
tt = ss = store_get(length + nonprintcount * 3 + 1, s);
317
317
318
/* Copy everything, escaping non printers. */
318
/* Copy everything, escaping non printers. */
319
319
Lines 371-377 Link Here
371
if (!p) return s;
371
if (!p) return s;
372
372
373
len = Ustrlen(s) + 1;
373
len = Ustrlen(s) + 1;
374
ss = store_get(len, is_tainted(s));
374
ss = store_get(len, s);
375
375
376
q = ss;
376
q = ss;
377
off = p - s;
377
off = p - s;
Lines 428-449 Link Here
428
*/
428
*/
429
429
430
uschar *
430
uschar *
431
string_copy_function(const uschar *s)
431
string_copy_function(const uschar * s)
432
{
432
{
433
return string_copy_taint(s, is_tainted(s));
433
return string_copy_taint(s, s);
434
}
434
}
435
435
436
/* This function assumes that memcpy() is faster than strcpy().
436
/* As above, but explicitly specifying the result taint status
437
As above, but explicitly specifying the result taint status
438
*/
437
*/
439
438
440
uschar *
439
uschar *
441
string_copy_taint_function(const uschar * s, BOOL tainted)
440
string_copy_taint_function(const uschar * s, const void * proto_mem)
442
{
441
{
443
int len = Ustrlen(s) + 1;
442
return string_copy_taint(s, proto_mem);
444
uschar *ss = store_get(len, tainted);
445
memcpy(ss, s, len);
446
return ss;
447
}
443
}
448
444
449
445
Lines 463-474 Link Here
463
*/
459
*/
464
460
465
uschar *
461
uschar *
466
string_copyn_function(const uschar *s, int n)
462
string_copyn_function(const uschar * s, int n)
467
{
463
{
468
uschar *ss = store_get(n + 1, is_tainted(s));
464
return string_copyn(s, n);
469
Ustrncpy(ss, s, n);
470
ss[n] = 0;
471
return ss;
472
}
465
}
473
#endif
466
#endif
474
467
Lines 484-493 Link Here
484
*/
477
*/
485
478
486
uschar *
479
uschar *
487
string_copy_malloc(const uschar *s)
480
string_copy_malloc(const uschar * s)
488
{
481
{
489
int len = Ustrlen(s) + 1;
482
int len = Ustrlen(s) + 1;
490
uschar *ss = store_malloc(len);
483
uschar * ss = store_malloc(len);
491
memcpy(ss, s, len);
484
memcpy(ss, s, len);
492
return ss;
485
return ss;
493
}
486
}
Lines 506-542 Link Here
506
*/
499
*/
507
500
508
uschar *
501
uschar *
509
string_split_message(uschar *msg)
502
string_split_message(uschar * msg)
510
{
503
{
511
uschar *s, *ss;
504
uschar *s, *ss;
512
505
513
if (msg == NULL || Ustrlen(msg) <= 75) return msg;
506
if (!msg || Ustrlen(msg) <= 75) return msg;
514
s = ss = msg = string_copy(msg);
507
s = ss = msg = string_copy(msg);
515
508
516
for (;;)
509
for (;;)
517
  {
510
  {
518
  int i = 0;
511
  int i = 0;
519
  while (i < 75 && *ss != 0 && *ss != '\n') ss++, i++;
512
  while (i < 75 && *ss && *ss != '\n') ss++, i++;
520
  if (*ss == 0) break;
513
  if (!*ss) break;
521
  if (*ss == '\n')
514
  if (*ss == '\n')
522
    s = ++ss;
515
    s = ++ss;
523
  else
516
  else
524
    {
517
    {
525
    uschar *t = ss + 1;
518
    uschar * t = ss + 1;
526
    uschar *tt = NULL;
519
    uschar * tt = NULL;
527
    while (--t > s + 35)
520
    while (--t > s + 35)
528
      {
521
      {
529
      if (*t == ' ')
522
      if (*t == ' ')
530
        {
523
        {
531
        if (t[-1] == ':') { tt = t; break; }
524
        if (t[-1] == ':') { tt = t; break; }
532
        if (tt == NULL) tt = t;
525
        if (!tt) tt = t;
533
        }
526
        }
534
      }
527
      }
535
528
536
    if (tt == NULL)          /* Can't split behind - try ahead */
529
    if (!tt)          /* Can't split behind - try ahead */
537
      {
530
      {
538
      t = ss + 1;
531
      t = ss + 1;
539
      while (*t != 0)
532
      while (*t)
540
        {
533
        {
541
        if (*t == ' ' || *t == '\n')
534
        if (*t == ' ' || *t == '\n')
542
          { tt = t; break; }
535
          { tt = t; break; }
Lines 544-550 Link Here
544
        }
537
        }
545
      }
538
      }
546
539
547
    if (tt == NULL) break;   /* Can't find anywhere to split */
540
    if (!tt) break;   /* Can't find anywhere to split */
548
    *tt = '\n';
541
    *tt = '\n';
549
    s = ss = tt+1;
542
    s = ss = tt+1;
550
    }
543
    }
Lines 572-583 Link Here
572
*/
565
*/
573
566
574
uschar *
567
uschar *
575
string_copy_dnsdomain(uschar *s)
568
string_copy_dnsdomain(uschar * s)
576
{
569
{
577
uschar *yield;
570
uschar * yield;
578
uschar *ss = yield = store_get(Ustrlen(s) + 1, is_tainted(s));
571
uschar * ss = yield = store_get(Ustrlen(s) + 1, GET_TAINTED);	/* always treat as tainted */
579
572
580
while (*s != 0)
573
while (*s)
581
  {
574
  {
582
  if (*s != '\\')
575
  if (*s != '\\')
583
    *ss++ = *s++;
576
    *ss++ = *s++;
Lines 586-592 Link Here
586
    *ss++ = (s[1] - '0')*100 + (s[2] - '0')*10 + s[3] - '0';
579
    *ss++ = (s[1] - '0')*100 + (s[2] - '0')*10 + s[3] - '0';
587
    s += 4;
580
    s += 4;
588
    }
581
    }
589
  else if (*(++s) != 0)
582
  else if (*++s)
590
    *ss++ = *s++;
583
    *ss++ = *s++;
591
  }
584
  }
592
585
Lines 611-625 Link Here
611
*/
604
*/
612
605
613
uschar *
606
uschar *
614
string_dequote(const uschar **sptr)
607
string_dequote(const uschar ** sptr)
615
{
608
{
616
const uschar *s = *sptr;
609
const uschar * s = * sptr;
617
uschar *t, *yield;
610
uschar * t, * yield;
618
611
619
/* First find the end of the string */
612
/* First find the end of the string */
620
613
621
if (*s != '\"')
614
if (*s != '\"')
622
  while (*s != 0 && !isspace(*s)) s++;
615
  while (*s && !isspace(*s)) s++;
623
else
616
else
624
  {
617
  {
625
  s++;
618
  s++;
Lines 633-649 Link Here
633
626
634
/* Get enough store to copy into */
627
/* Get enough store to copy into */
635
628
636
t = yield = store_get(s - *sptr + 1, is_tainted(*sptr));
629
t = yield = store_get(s - *sptr + 1, *sptr);
637
s = *sptr;
630
s = *sptr;
638
631
639
/* Do the copy */
632
/* Do the copy */
640
633
641
if (*s != '\"')
634
if (*s != '\"')
642
  while (*s != 0 && !isspace(*s)) *t++ = *s++;
635
  while (*s && !isspace(*s)) *t++ = *s++;
643
else
636
else
644
  {
637
  {
645
  s++;
638
  s++;
646
  while (*s != 0 && *s != '\"')
639
  while (*s && *s != '\"')
647
    {
640
    {
648
    *t++ = *s == '\\' ? string_interpret_escape(&s) : *s;
641
    *t++ = *s == '\\' ? string_interpret_escape(&s) : *s;
649
    s++;
642
    s++;
Lines 671-683 Link Here
671
Arguments:
664
Arguments:
672
  format    a printf() format - deliberately char * rather than uschar *
665
  format    a printf() format - deliberately char * rather than uschar *
673
              because it will most usually be a literal string
666
              because it will most usually be a literal string
667
  func	    caller, for debug
668
  line	    caller, for debug
674
  ...       arguments for format
669
  ...       arguments for format
675
670
676
Returns:    pointer to fresh piece of store containing sprintf'ed string
671
Returns:    pointer to fresh piece of store containing sprintf'ed string
677
*/
672
*/
678
673
679
uschar *
674
uschar *
680
string_sprintf_trc(const char *format, const uschar * func, unsigned line, ...)
675
string_sprintf_trc(const char * format, const uschar * func, unsigned line, ...)
681
{
676
{
682
#ifdef COMPILE_UTILITY
677
#ifdef COMPILE_UTILITY
683
uschar buffer[STRING_SPRINTF_BUFFER_SIZE];
678
uschar buffer[STRING_SPRINTF_BUFFER_SIZE];
Lines 725-731 Link Here
725
*/
720
*/
726
721
727
int
722
int
728
strncmpic(const uschar *s, const uschar *t, int n)
723
strncmpic(const uschar * s, const uschar * t, int n)
729
{
724
{
730
while (n--)
725
while (n--)
731
  {
726
  {
Lines 749-757 Link Here
749
*/
744
*/
750
745
751
int
746
int
752
strcmpic(const uschar *s, const uschar *t)
747
strcmpic(const uschar * s, const uschar * t)
753
{
748
{
754
while (*s != 0)
749
while (*s)
755
  {
750
  {
756
  int c = tolower(*s++) - tolower(*t++);
751
  int c = tolower(*s++) - tolower(*t++);
757
  if (c != 0) return c;
752
  if (c != 0) return c;
Lines 775-785 Link Here
775
Returns:         pointer to substring in string, or NULL if not found
770
Returns:         pointer to substring in string, or NULL if not found
776
*/
771
*/
777
772
778
uschar *
773
const uschar *
779
strstric(uschar *s, uschar *t, BOOL space_follows)
774
strstric_c(const uschar * s, const uschar * t, BOOL space_follows)
780
{
775
{
781
uschar *p = t;
776
const uschar * p = t;
782
uschar *yield = NULL;
777
const uschar * yield = NULL;
783
int cl = tolower(*p);
778
int cl = tolower(*p);
784
int cu = toupper(*p);
779
int cu = toupper(*p);
785
780
Lines 787-794 Link Here
787
  {
782
  {
788
  if (*s == cl || *s == cu)
783
  if (*s == cl || *s == cu)
789
    {
784
    {
790
    if (yield == NULL) yield = s;
785
    if (!yield) yield = s;
791
    if (*(++p) == 0)
786
    if (!*++p)
792
      {
787
      {
793
      if (!space_follows || s[1] == ' ' || s[1] == '\n' ) return yield;
788
      if (!space_follows || s[1] == ' ' || s[1] == '\n' ) return yield;
794
      yield = NULL;
789
      yield = NULL;
Lines 798-804 Link Here
798
    cu = toupper(*p);
793
    cu = toupper(*p);
799
    s++;
794
    s++;
800
    }
795
    }
801
  else if (yield != NULL)
796
  else if (yield)
802
    {
797
    {
803
    yield = NULL;
798
    yield = NULL;
804
    p = t;
799
    p = t;
Lines 810-815 Link Here
810
return NULL;
805
return NULL;
811
}
806
}
812
807
808
uschar *
809
strstric(uschar * s, uschar * t, BOOL space_follows)
810
{
811
return US strstric_c(s, t, space_follows);
812
}
813
813
814
814
815
#ifdef COMPILE_UTILITY
815
#ifdef COMPILE_UTILITY
Lines 858-875 Link Here
858
  separator  a pointer to the separator character in an int (see above)
858
  separator  a pointer to the separator character in an int (see above)
859
  buffer     where to put a copy of the next string in the list; or
859
  buffer     where to put a copy of the next string in the list; or
860
               NULL if the next string is returned in new memory
860
               NULL if the next string is returned in new memory
861
	     Note that if the list is tainted then a provided buffer must be
862
	     also (else we trap, with a message referencing the callsite).
863
	     If we do the allocation, taint is handled there.
861
  buflen     when buffer is not NULL, the size of buffer; otherwise ignored
864
  buflen     when buffer is not NULL, the size of buffer; otherwise ignored
862
865
866
  func	     caller, for debug
867
  line	     caller, for debug
868
863
Returns:     pointer to buffer, containing the next substring,
869
Returns:     pointer to buffer, containing the next substring,
864
             or NULL if no more substrings
870
             or NULL if no more substrings
865
*/
871
*/
866
872
867
uschar *
873
uschar *
868
string_nextinlist_trc(const uschar **listptr, int *separator, uschar *buffer, int buflen,
874
string_nextinlist_trc(const uschar ** listptr, int * separator, uschar * buffer,
869
 const uschar * func, int line)
875
  int buflen, const uschar * func, int line)
870
{
876
{
871
int sep = *separator;
877
int sep = *separator;
872
const uschar *s = *listptr;
878
const uschar * s = *listptr;
873
BOOL sep_is_special;
879
BOOL sep_is_special;
874
880
875
if (!s) return NULL;
881
if (!s) return NULL;
Lines 905-910 Link Here
905
sep_is_special = iscntrl(sep);
911
sep_is_special = iscntrl(sep);
906
912
907
/* Handle the case when a buffer is provided. */
913
/* Handle the case when a buffer is provided. */
914
/*XXX need to also deal with qouted-requirements mismatch */
908
915
909
if (buffer)
916
if (buffer)
910
  {
917
  {
Lines 932-945 Link Here
932
  start of a string. Avoid getting working memory for an empty item. */
939
  start of a string. Avoid getting working memory for an empty item. */
933
940
934
  if (*s == sep)
941
  if (*s == sep)
935
    {
942
    if (*++s != sep || sep_is_special)
936
    s++;
937
    if (*s != sep || sep_is_special)
938
      {
943
      {
939
      *listptr = s;
944
      *listptr = s;
940
      return string_copy(US"");
945
      return string_copy(US"");
941
      }
946
      }
942
    }
943
947
944
  /* Not an empty string; the first character is guaranteed to be a data
948
  /* Not an empty string; the first character is guaranteed to be a data
945
  character. */
949
  character. */
Lines 952-963 Link Here
952
    s = ss;
956
    s = ss;
953
    if (!*s || *++s != sep || sep_is_special) break;
957
    if (!*s || *++s != sep || sep_is_special) break;
954
    }
958
    }
959
960
  /* Trim trailing spaces from the returned string */
961
955
  /* while (g->ptr > 0 && isspace(g->s[g->ptr-1])) g->ptr--; */
962
  /* while (g->ptr > 0 && isspace(g->s[g->ptr-1])) g->ptr--; */
956
  while (  g->ptr > 0 && isspace(g->s[g->ptr-1])
963
  while (  g->ptr > 0 && isspace(g->s[g->ptr-1])
957
	&& (g->ptr == 1 || g->s[g->ptr-2] != '\\') )
964
	&& (g->ptr == 1 || g->s[g->ptr-2] != '\\') )
958
    g->ptr--;
965
    g->ptr--;
959
  buffer = string_from_gstring(g);
966
  buffer = string_from_gstring(g);
960
  gstring_release_unused(g);
967
  gstring_release_unused_trc(g, CCS func, line);
961
  }
968
  }
962
969
963
/* Update the current pointer and return the new string */
970
/* Update the current pointer and return the new string */
Lines 1081-1087 Link Here
1081
{
1088
{
1082
int p = g->ptr;
1089
int p = g->ptr;
1083
int oldsize = g->size;
1090
int oldsize = g->size;
1084
BOOL tainted = is_tainted(g->s);
1085
1091
1086
/* Mostly, string_cat() is used to build small strings of a few hundred
1092
/* Mostly, string_cat() is used to build small strings of a few hundred
1087
characters at most. There are times, however, when the strings are very much
1093
characters at most. There are times, however, when the strings are very much
Lines 1113-1120 Link Here
1113
was the last item on the dynamic memory stack. This is the case if it matches
1119
was the last item on the dynamic memory stack. This is the case if it matches
1114
store_last_get. */
1120
store_last_get. */
1115
1121
1116
if (!store_extend(g->s, tainted, oldsize, g->size))
1122
if (!store_extend(g->s, oldsize, g->size))
1117
  g->s = store_newblock(g->s, tainted, g->size, p);
1123
  g->s = store_newblock(g->s, g->size, p);
1118
}
1124
}
1119
1125
1120
1126
Lines 1129-1166 Link Here
1129
sometimes called to extract parts of other strings.
1135
sometimes called to extract parts of other strings.
1130
1136
1131
Arguments:
1137
Arguments:
1132
  string   points to the start of the string that is being built, or NULL
1138
  g	   growable-string that is being built, or NULL if not assigned yet
1133
             if this is a new string that has no contents yet
1134
  s        points to characters to add
1139
  s        points to characters to add
1135
  count    count of characters to add; must not exceed the length of s, if s
1140
  count    count of characters to add; must not exceed the length of s, if s
1136
             is a C string.
1141
             is a C string.
1137
1142
1138
Returns:   pointer to the start of the string, changed if copied for expansion.
1143
Returns:   growable string, changed if copied for expansion.
1139
           Note that a NUL is not added, though space is left for one. This is
1144
           Note that a NUL is not added, though space is left for one. This is
1140
           because string_cat() is often called multiple times to build up a
1145
           because string_cat() is often called multiple times to build up a
1141
           string - there's no point adding the NUL till the end.
1146
           string - there's no point adding the NUL till the end.
1147
	   NULL is a possible return.
1142
1148
1143
*/
1149
*/
1144
/* coverity[+alloc] */
1150
/* coverity[+alloc] */
1145
1151
1146
gstring *
1152
gstring *
1147
string_catn(gstring * g, const uschar *s, int count)
1153
string_catn(gstring * g, const uschar * s, int count)
1148
{
1154
{
1149
int p;
1155
int p;
1150
BOOL srctaint = is_tainted(s);
1151
1156
1152
if (count < 0)
1157
if (count < 0)
1153
  log_write(0, LOG_MAIN|LOG_PANIC_DIE,
1158
  log_write(0, LOG_MAIN|LOG_PANIC_DIE,
1154
    "internal error in string_catn (count %d)", count);
1159
    "internal error in string_catn (count %d)", count);
1160
if (count == 0) return g;
1155
1161
1162
/*debug_printf("string_catn '%.*s'\n", count, s);*/
1156
if (!g)
1163
if (!g)
1157
  {
1164
  {
1158
  unsigned inc = count < 4096 ? 127 : 1023;
1165
  unsigned inc = count < 4096 ? 127 : 1023;
1159
  unsigned size = ((count + inc) &  ~inc) + 1;
1166
  unsigned size = ((count + inc) &  ~inc) + 1;	/* round up requested count */
1160
  g = string_get_tainted(size, srctaint);
1167
  g = string_get_tainted(size, s);
1168
  }
1169
else if (!g->s)			/* should not happen */
1170
  {
1171
  g->s = string_copyn(s, count);
1172
  g->ptr = count;
1173
  g->size = count;	/*XXX suboptimal*/
1174
  return g;
1175
  }
1176
else if (is_incompatible(g->s, s))
1177
  {
1178
/* debug_printf("rebuf A\n"); */
1179
  gstring_rebuffer(g, s);
1161
  }
1180
  }
1162
else if (srctaint && !is_tainted(g->s))
1163
  gstring_rebuffer(g);
1164
1181
1165
if (g->ptr < 0 || g->ptr > g->size)
1182
if (g->ptr < 0 || g->ptr > g->size)
1166
  log_write(0, LOG_MAIN|LOG_PANIC_DIE,
1183
  log_write(0, LOG_MAIN|LOG_PANIC_DIE,
Lines 1181-1189 Link Here
1181
1198
1182
1199
1183
gstring *
1200
gstring *
1184
string_cat(gstring *string, const uschar *s)
1201
string_cat(gstring * g, const uschar * s)
1185
{
1202
{
1186
return string_catn(string, s, Ustrlen(s));
1203
return string_catn(g, s, Ustrlen(s));
1187
}
1204
}
1188
1205
1189
1206
Lines 1196-1225 Link Here
1196
It calls string_cat() to do the dirty work.
1213
It calls string_cat() to do the dirty work.
1197
1214
1198
Arguments:
1215
Arguments:
1199
  string   expanding-string that is being built, or NULL
1216
  g	   growable-string that is being built, or NULL if not yet assigned
1200
             if this is a new string that has no contents yet
1201
  count    the number of strings to append
1217
  count    the number of strings to append
1202
  ...      "count" uschar* arguments, which must be valid zero-terminated
1218
  ...      "count" uschar* arguments, which must be valid zero-terminated
1203
             C strings
1219
             C strings
1204
1220
1205
Returns:   pointer to the start of the string, changed if copied for expansion.
1221
Returns:   growable string, changed if copied for expansion.
1206
           The string is not zero-terminated - see string_cat() above.
1222
           The string is not zero-terminated - see string_cat() above.
1207
*/
1223
*/
1208
1224
1209
__inline__ gstring *
1225
__inline__ gstring *
1210
string_append(gstring *string, int count, ...)
1226
string_append(gstring * g, int count, ...)
1211
{
1227
{
1212
va_list ap;
1228
va_list ap;
1213
1229
1214
va_start(ap, count);
1230
va_start(ap, count);
1215
while (count-- > 0)
1231
while (count-- > 0)
1216
  {
1232
  {
1217
  uschar *t = va_arg(ap, uschar *);
1233
  uschar * t = va_arg(ap, uschar *);
1218
  string = string_cat(string, t);
1234
  g = string_cat(g, t);
1219
  }
1235
  }
1220
va_end(ap);
1236
va_end(ap);
1221
1237
1222
return string;
1238
return g;
1223
}
1239
}
1224
#endif
1240
#endif
1225
1241
Lines 1255-1261 Link Here
1255
string_format_trc(uschar * buffer, int buflen,
1271
string_format_trc(uschar * buffer, int buflen,
1256
  const uschar * func, unsigned line, const char * format, ...)
1272
  const uschar * func, unsigned line, const char * format, ...)
1257
{
1273
{
1258
gstring g = { .size = buflen, .ptr = 0, .s = buffer }, *gp;
1274
gstring g = { .size = buflen, .ptr = 0, .s = buffer }, * gp;
1259
va_list ap;
1275
va_list ap;
1260
va_start(ap, format);
1276
va_start(ap, format);
1261
gp = string_vformat_trc(&g, func, line, STRING_SPRINTF_BUFFER_SIZE,
1277
gp = string_vformat_trc(&g, func, line, STRING_SPRINTF_BUFFER_SIZE,
Lines 1298-1310 Link Here
1298
1314
1299
gstring *
1315
gstring *
1300
string_vformat_trc(gstring * g, const uschar * func, unsigned line,
1316
string_vformat_trc(gstring * g, const uschar * func, unsigned line,
1301
  unsigned size_limit, unsigned flags, const char *format, va_list ap)
1317
  unsigned size_limit, unsigned flags, const char * format, va_list ap)
1302
{
1318
{
1303
enum ltypes { L_NORMAL=1, L_SHORT=2, L_LONG=3, L_LONGLONG=4, L_LONGDOUBLE=5, L_SIZE=6 };
1319
enum ltypes { L_NORMAL=1, L_SHORT=2, L_LONG=3, L_LONGLONG=4, L_LONGDOUBLE=5, L_SIZE=6 };
1304
1320
1305
int width, precision, off, lim, need;
1321
int width, precision, off, lim, need;
1306
const char * fp = format;	/* Deliberately not unsigned */
1322
const char * fp = format;	/* Deliberately not unsigned */
1307
BOOL dest_tainted = FALSE;
1308
1323
1309
string_datestamp_offset = -1;	/* Datestamp not inserted */
1324
string_datestamp_offset = -1;	/* Datestamp not inserted */
1310
string_datestamp_length = 0;	/* Datestamp not inserted */
1325
string_datestamp_length = 0;	/* Datestamp not inserted */
Lines 1317-1332 Link Here
1317
1332
1318
/* Ensure we have a string, to save on checking later */
1333
/* Ensure we have a string, to save on checking later */
1319
if (!g) g = string_get(16);
1334
if (!g) g = string_get(16);
1320
else if (!(flags & SVFMT_TAINT_NOCHK)) dest_tainted = is_tainted(g->s);
1321
1335
1322
if (!(flags & SVFMT_TAINT_NOCHK) && !dest_tainted && is_tainted(format))
1336
if (!(flags & SVFMT_TAINT_NOCHK) && is_incompatible(g->s, format))
1323
  {
1337
  {
1324
#ifndef MACRO_PREDEF
1338
#ifndef MACRO_PREDEF
1325
  if (!(flags & SVFMT_REBUFFER))
1339
  if (!(flags & SVFMT_REBUFFER))
1326
    die_tainted(US"string_vformat", func, line);
1340
    die_tainted(US"string_vformat", func, line);
1327
#endif
1341
#endif
1328
  gstring_rebuffer(g);
1342
/* debug_printf("rebuf B\n"); */
1329
  dest_tainted = TRUE;
1343
  gstring_rebuffer(g, format);
1330
  }
1344
  }
1331
#endif	/*!COMPILE_UTILITY*/
1345
#endif	/*!COMPILE_UTILITY*/
1332
1346
Lines 1338-1344 Link Here
1338
while (*fp)
1352
while (*fp)
1339
  {
1353
  {
1340
  int length = L_NORMAL;
1354
  int length = L_NORMAL;
1341
  int *nptr;
1355
  int * nptr;
1342
  int slen;
1356
  int slen;
1343
  const char *null = "NULL";		/* ) These variables */
1357
  const char *null = "NULL";		/* ) These variables */
1344
  const char *item_start, *s;		/* ) are deliberately */
1358
  const char *item_start, *s;		/* ) are deliberately */
Lines 1546-1557 Link Here
1546
      if (!s) s = null;
1560
      if (!s) s = null;
1547
      slen = Ustrlen(s);
1561
      slen = Ustrlen(s);
1548
1562
1549
      if (!(flags & SVFMT_TAINT_NOCHK) && !dest_tainted && is_tainted(s))
1563
      if (!(flags & SVFMT_TAINT_NOCHK) && is_incompatible(g->s, s))
1550
	if (flags & SVFMT_REBUFFER)
1564
	if (flags & SVFMT_REBUFFER)
1551
	  {
1565
	  {
1552
	  gstring_rebuffer(g);
1566
/* debug_printf("%s %d: untainted workarea, tainted %%s :- rebuffer\n", __FUNCTION__, __LINE__); */
1567
	  gstring_rebuffer(g, s);
1553
	  gp = CS g->s + g->ptr;
1568
	  gp = CS g->s + g->ptr;
1554
	  dest_tainted = TRUE;
1555
	  }
1569
	  }
1556
#ifndef MACRO_PREDEF
1570
#ifndef MACRO_PREDEF
1557
	else
1571
	else
Lines 1640-1655 Link Here
1640
"Permission denied", reads and includes the euid and egid.
1654
"Permission denied", reads and includes the euid and egid.
1641
1655
1642
Arguments:
1656
Arguments:
1643
  eno           the value of errno after the failure
1644
  format        a text format string - deliberately not uschar *
1657
  format        a text format string - deliberately not uschar *
1658
  func		caller, for debug
1659
  line		caller, for debug
1645
  ...           arguments for the format string
1660
  ...           arguments for the format string
1646
1661
1647
Returns:        a message, in dynamic store
1662
Returns:        a message, in dynamic store
1648
*/
1663
*/
1649
1664
1650
uschar *
1665
uschar *
1651
string_open_failed_trc(int eno, const uschar * func, unsigned line,
1666
string_open_failed_trc(const uschar * func, unsigned line,
1652
  const char *format, ...)
1667
  const char * format, ...)
1653
{
1668
{
1654
va_list ap;
1669
va_list ap;
1655
gstring * g = string_get(1024);
1670
gstring * g = string_get(1024);
Lines 1664-1685 Link Here
1664
va_start(ap, format);
1679
va_start(ap, format);
1665
(void) string_vformat_trc(g, func, line, STRING_SPRINTF_BUFFER_SIZE,
1680
(void) string_vformat_trc(g, func, line, STRING_SPRINTF_BUFFER_SIZE,
1666
	SVFMT_REBUFFER, format, ap);
1681
	SVFMT_REBUFFER, format, ap);
1667
string_from_gstring(g);
1668
gstring_release_unused(g);
1669
va_end(ap);
1682
va_end(ap);
1670
1683
1671
return eno == EACCES
1684
g = string_catn(g, US": ", 2);
1672
  ? string_sprintf("%s: %s (euid=%ld egid=%ld)", g->s, strerror(eno),
1685
g = string_cat(g, US strerror(errno));
1673
    (long int)geteuid(), (long int)getegid())
1686
1674
  : string_sprintf("%s: %s", g->s, strerror(eno));
1687
if (errno == EACCES)
1688
  {
1689
  int save_errno = errno;
1690
  g = string_fmt_append(g, " (euid=%ld egid=%ld)",
1691
    (long int)geteuid(), (long int)getegid());
1692
  errno = save_errno;
1693
  }
1694
gstring_release_unused(g);
1695
return string_from_gstring(g);
1675
}
1696
}
1676
#endif  /* COMPILE_UTILITY */
1677
1697
1678
1698
1679
1699
1680
1700
1681
1701
1682
#ifndef COMPILE_UTILITY
1683
/* qsort(3), currently used to sort the environment variables
1702
/* qsort(3), currently used to sort the environment variables
1684
for -bP environment output, needs a function to compare two pointers to string
1703
for -bP environment output, needs a function to compare two pointers to string
1685
pointers. Here it is. */
1704
pointers. Here it is. */
Lines 1706-1711 Link Here
1706
uschar buffer[256];
1725
uschar buffer[256];
1707
1726
1708
printf("Testing is_ip_address\n");
1727
printf("Testing is_ip_address\n");
1728
store_init();
1709
1729
1710
while (fgets(CS buffer, sizeof(buffer), stdin) != NULL)
1730
while (fgets(CS buffer, sizeof(buffer), stdin) != NULL)
1711
  {
1731
  {
(-)exim.orig/src/structs.h (-7 / +23 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 133-143 Link Here
133
  uschar *name;                   /* Instance name */
133
  uschar *name;                   /* Instance name */
134
  struct driver_info *info;       /* Points to info for this driver */
134
  struct driver_info *info;       /* Points to info for this driver */
135
  void   *options_block;          /* Pointer to private options */
135
  void   *options_block;          /* Pointer to private options */
136
136
  uschar *driver_name;            /* All start with this generic option */
137
  uschar *driver_name;            /* All start with this generic option */
138
  const uschar *srcfile;	  /* and config source info for errors */
139
  int	  srcline;
137
} driver_instance;
140
} driver_instance;
138
141
139
typedef struct driver_info {
142
typedef struct driver_info {
140
  uschar *driver_name;            /* Name of driver */
143
  uschar *driver_name;            /* Name of driver */
144
141
  optionlist *options;            /* Table of private options names */
145
  optionlist *options;            /* Table of private options names */
142
  int    *options_count;          /* -> Number of entries in table */
146
  int    *options_count;          /* -> Number of entries in table */
143
  void   *options_block;          /* Points to default private block */
147
  void   *options_block;          /* Points to default private block */
Lines 159-164 Link Here
159
  struct transport_info *info;    /* Info for this driver */
163
  struct transport_info *info;    /* Info for this driver */
160
  void *options_block;            /* Pointer to private options */
164
  void *options_block;            /* Pointer to private options */
161
  uschar *driver_name;            /* Must be first */
165
  uschar *driver_name;            /* Must be first */
166
  const uschar *srcfile;
167
  int	  srcline;
168
162
  int   (*setup)(                 /* Setup entry point */
169
  int   (*setup)(                 /* Setup entry point */
163
    struct transport_instance *,
170
    struct transport_instance *,
164
    struct address_item *,
171
    struct address_item *,
Lines 283-288 Link Here
283
  struct router_info *info;
290
  struct router_info *info;
284
  void   *options_block;          /* Pointer to private options */
291
  void   *options_block;          /* Pointer to private options */
285
  uschar *driver_name;            /* Must be first */
292
  uschar *driver_name;            /* Must be first */
293
  const uschar *srcfile;
294
  int	  srcline;
286
295
287
  uschar *address_data;           /* Arbitrary data */
296
  uschar *address_data;           /* Arbitrary data */
288
#ifdef EXPERIMENTAL_BRIGHTMAIL
297
#ifdef EXPERIMENTAL_BRIGHTMAIL
Lines 400-405 Link Here
400
  struct auth_info *info;         /* Pointer to driver info block */
409
  struct auth_info *info;         /* Pointer to driver info block */
401
  void   *options_block;          /* Pointer to private options */
410
  void   *options_block;          /* Pointer to private options */
402
  uschar *driver_name;            /* Must be first */
411
  uschar *driver_name;            /* Must be first */
412
  const uschar *srcfile;
413
  int	  srcline;
414
403
  uschar *advertise_condition;    /* Are we going to advertise this?*/
415
  uschar *advertise_condition;    /* Are we going to advertise this?*/
404
  uschar *client_condition;       /* Should the client try this? */
416
  uschar *client_condition;       /* Should the client try this? */
405
  uschar *public_name;            /* Advertised name */
417
  uschar *public_name;            /* Advertised name */
Lines 435-442 Link Here
435
    int,                          /* command timeout */
447
    int,                          /* command timeout */
436
    uschar *,                     /* buffer for reading response */
448
    uschar *,                     /* buffer for reading response */
437
    int);                         /* sizeof buffer */
449
    int);                         /* sizeof buffer */
438
  void (*version_report)(         /* diagnostic version reporting */
450
  gstring * (*version_report)(    /* diagnostic version reporting */
439
    FILE *);                      /* I/O stream to print to */
451
    gstring *);                   /* string to append to */
440
  void (*macros_create)(void);	  /* feature-macro creation */
452
  void (*macros_create)(void);	  /* feature-macro creation */
441
} auth_info;
453
} auth_info;
442
454
Lines 518-526 Link Here
518
  uschar *remove_headers;         /* list of those to remove */
530
  uschar *remove_headers;         /* list of those to remove */
519
  void   *variables;		  /* router-vasriables */
531
  void   *variables;		  /* router-vasriables */
520
532
521
#ifdef EXPERIMENTAL_SRS
522
  uschar *srs_sender;             /* Change return path when delivering */
523
#endif
524
  BOOL    ignore_error:1;	  /* ignore delivery error */
533
  BOOL    ignore_error:1;	  /* ignore delivery error */
525
#ifdef SUPPORT_I18N
534
#ifdef SUPPORT_I18N
526
  BOOL    utf8_msg:1;		  /* requires SMTPUTF8 processing */
535
  BOOL    utf8_msg:1;		  /* requires SMTPUTF8 processing */
Lines 626-631 Link Here
626
    BOOL af_verify_routed:1;		/* for cached sender verify: routed OK */
635
    BOOL af_verify_routed:1;		/* for cached sender verify: routed OK */
627
    BOOL af_verify_callout:1;		/* for cached sender verify: callout was specified */
636
    BOOL af_verify_callout:1;		/* for cached sender verify: callout was specified */
628
    BOOL af_include_affixes:1;		/* delivered with affixes in RCPT */
637
    BOOL af_include_affixes:1;		/* delivered with affixes in RCPT */
638
    BOOL af_new_conn:1;			/* delivered on an fresh TCP conn */
639
    BOOL af_cont_conn:1;		/* delivered (with new MAIL cmd) on an existing TCP conn */
629
    BOOL af_cert_verified:1;		/* delivered with verified TLS cert */
640
    BOOL af_cert_verified:1;		/* delivered with verified TLS cert */
630
    BOOL af_pass_message:1;		/* pass message in bounces */
641
    BOOL af_pass_message:1;		/* pass message in bounces */
631
    BOOL af_bad_reply:1;		/* filter could not generate autoreply */
642
    BOOL af_bad_reply:1;		/* filter could not generate autoreply */
Lines 647-653 Link Here
647
#ifdef SUPPORT_I18N
658
#ifdef SUPPORT_I18N
648
    BOOL af_utf8_downcvt:1;		/* downconvert was done for delivery */
659
    BOOL af_utf8_downcvt:1;		/* downconvert was done for delivery */
649
#endif
660
#endif
650
#ifdef EXPERIMENTAL_TLS_RESUME
661
#ifndef DISABLE_TLS_RESUME
651
    BOOL af_tls_resume:1;		/* TLS used a resumed session */
662
    BOOL af_tls_resume:1;		/* TLS used a resumed session */
652
#endif
663
#endif
653
  } flags;
664
  } flags;
Lines 820-825 Link Here
820
  int                   host_af;
831
  int                   host_af;
821
  uschar *              interface;
832
  uschar *              interface;
822
833
834
  int			sock;	/* used for a bound but not connected socket */
835
  uschar *		sending_ip_address;	/* used for TLS resumption */
836
  const uschar *	host_lbserver;		/* ditto, for server-behind LB */
837
  BOOL			have_lbserver:1;	/* host_lbserver is valid */
838
823
#ifdef SUPPORT_DANE
839
#ifdef SUPPORT_DANE
824
  BOOL dane:1;			/* connection must do dane */
840
  BOOL dane:1;			/* connection must do dane */
825
  dns_answer		tlsa_dnsa;	/* strictly, this should use tainted mem */
841
  dns_answer		tlsa_dnsa;	/* strictly, this should use tainted mem */
(-)exim.orig/src/tls.c (-3 / +360 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* This module provides TLS (aka SSL) support for Exim. The code for OpenSSL is
9
/* This module provides TLS (aka SSL) support for Exim. The code for OpenSSL is
Lines 25-30 Link Here
25
#endif
25
#endif
26
26
27
27
28
/* Forward decl. */
29
static void tls_client_resmption_key(tls_support *, smtp_connect_args *,
30
  smtp_transport_options_block *);
31
32
28
#if defined(MACRO_PREDEF) && !defined(DISABLE_TLS)
33
#if defined(MACRO_PREDEF) && !defined(DISABLE_TLS)
29
# include "macro_predef.h"
34
# include "macro_predef.h"
30
# ifdef USE_GNUTLS
35
# ifdef USE_GNUTLS
Lines 36-41 Link Here
36
41
37
#ifndef MACRO_PREDEF
42
#ifndef MACRO_PREDEF
38
43
44
static void tls_per_lib_daemon_init(void);
45
static void tls_per_lib_daemon_tick(void);
46
static unsigned  tls_server_creds_init(void);
47
static void tls_server_creds_invalidate(void);
48
static void tls_client_creds_init(transport_instance *, BOOL);
49
static void tls_client_creds_invalidate(transport_instance *);
50
static void tls_daemon_creds_reload(void);
51
static BOOL opt_set_and_noexpand(const uschar *);
52
static BOOL opt_unset_or_noexpand(const uschar *);
53
54
55
39
/* This module is compiled only when it is specifically requested in the
56
/* This module is compiled only when it is specifically requested in the
40
build-time configuration. However, some compilers don't like compiling empty
57
build-time configuration. However, some compilers don't like compiling empty
41
modules, so keep them happy with a dummy when skipping the rest. Make it
58
modules, so keep them happy with a dummy when skipping the rest. Make it
Lines 45-51 Link Here
45
62
46
#ifdef DISABLE_TLS
63
#ifdef DISABLE_TLS
47
static void dummy(int x) { dummy(x-1); }
64
static void dummy(int x) { dummy(x-1); }
48
#else
65
#else	/* most of the rest of the file */
66
67
const exim_tlslib_state	null_tls_preload = {0};
49
68
50
/* Static variables that are used for buffering data by both sets of
69
/* Static variables that are used for buffering data by both sets of
51
functions and the common functions below.
70
functions and the common functions below.
Lines 62-67 Link Here
62
static BOOL ssl_xfer_error = FALSE;
81
static BOOL ssl_xfer_error = FALSE;
63
#endif
82
#endif
64
83
84
#ifdef EXIM_HAVE_KEVENT
85
# define KEV_SIZE 16	/* Eight file,dir pairs */
86
static struct kevent kev[KEV_SIZE];
87
static int kev_used = 0;
88
#endif
89
90
static unsigned tls_creds_expire = 0;
65
91
66
/*************************************************
92
/*************************************************
67
*       Expand string; give error on failure     *
93
*       Expand string; give error on failure     *
Lines 96-101 Link Here
96
}
122
}
97
123
98
124
125
#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
126
/* Add the directory for a filename to the inotify handle, creating that if
127
needed.  This is enough to see changes to files in that dir.
128
Return boolean success.
129
130
The word "system" fails, which is on the safe side as we don't know what
131
directory it implies nor if the TLS library handles a watch for us.
132
133
The string "system,cache" is recognised and explicitly accepted without
134
setting a watch.  This permits the system CA bundle to be cached even though
135
we have no way to tell when it gets modified by an update.
136
The call chain for OpenSSL uses a (undocumented) call into the library
137
to discover the actual file.  We don't know what GnuTLS uses.
138
139
A full set of caching including the CAs takes 35ms output off of the
140
server tls_init() (GnuTLS, Fedora 32, 2018-class x86_64 laptop hardware).
141
*/
142
static BOOL
143
tls_set_one_watch(const uschar * filename)
144
# ifdef EXIM_HAVE_INOTIFY
145
{
146
uschar * s;
147
148
if (Ustrcmp(filename, "system,cache") == 0) return TRUE;
149
150
if (!(s = Ustrrchr(filename, '/'))) return FALSE;
151
s = string_copyn(filename, s - filename);	/* mem released by tls_set_watch */
152
DEBUG(D_tls) debug_printf("watch dir '%s'\n", s);
153
154
/*XXX unclear what effect symlinked files will have for inotify */
155
156
if (inotify_add_watch(tls_watch_fd, CCS s,
157
      IN_ONESHOT | IN_CLOSE_WRITE | IN_DELETE | IN_DELETE_SELF
158
      | IN_MOVED_FROM | IN_MOVED_TO | IN_MOVE_SELF) >= 0)
159
  return TRUE;
160
DEBUG(D_tls) debug_printf("notify_add_watch: %s\n", strerror(errno));
161
return FALSE;
162
}
163
# endif
164
# ifdef EXIM_HAVE_KEVENT
165
{
166
uschar * s, * t;
167
int fd1, fd2, i, j, cnt = 0;
168
struct stat sb;
169
#ifdef OpenBSD
170
struct kevent k_dummy;
171
struct timespec ts = {0};
172
#endif
173
174
errno = 0;
175
if (Ustrcmp(filename, "system,cache") == 0) return TRUE;
176
177
for (;;)
178
  {
179
  if (kev_used > KEV_SIZE-2) { s = US"out of kev space"; goto bad; }
180
  if (!(s = Ustrrchr(filename, '/'))) return FALSE;
181
  s = string_copyn(filename, s - filename);	/* mem released by tls_set_watch */
182
183
  /* The dir open will fail if there is a symlink on the path. Fine; it's too
184
  much effort to handle all possible cases; just refuse the preload. */
185
186
  if ((fd2 = open(CCS s, O_RDONLY | O_NOFOLLOW)) < 0) { s = US"open dir"; goto bad; }
187
188
  if ((lstat(CCS filename, &sb)) < 0) { s = US"lstat"; goto bad; }
189
  if (!S_ISLNK(sb.st_mode))
190
    {
191
    if ((fd1 = open(CCS filename, O_RDONLY | O_NOFOLLOW)) < 0)
192
      { s = US"open file"; goto bad; }
193
    DEBUG(D_tls) debug_printf("watch file '%s':\t%d\n", filename, fd1);
194
    EV_SET(&kev[kev_used++],
195
	(uintptr_t)fd1,
196
	EVFILT_VNODE,
197
	EV_ADD | EV_ENABLE | EV_ONESHOT,
198
	NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND
199
	| NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE,
200
	0,
201
	NULL);
202
    cnt++;
203
    }
204
  DEBUG(D_tls) debug_printf("watch dir  '%s':\t%d\n", s, fd2);
205
  EV_SET(&kev[kev_used++],
206
	(uintptr_t)fd2,
207
	EVFILT_VNODE,
208
	EV_ADD | EV_ENABLE | EV_ONESHOT,
209
	NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND
210
	| NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE,
211
	0,
212
	NULL);
213
  cnt++;
214
215
  if (!(S_ISLNK(sb.st_mode))) break;
216
217
  t = store_get(1024, GET_UNTAINTED);
218
  Ustrncpy(t, s, 1022);
219
  j = Ustrlen(s);
220
  t[j++] = '/';
221
  if ((i = readlink(CCS filename, (void *)(t+j), 1023-j)) < 0) { s = US"readlink"; goto bad; }
222
  filename = t;
223
  *(t += i+j) = '\0';
224
  store_release_above(t+1);
225
  }
226
227
#ifdef OpenBSD
228
if (kevent(tls_watch_fd, &kev[kev_used-cnt], cnt, &k_dummy, 1, &ts) >= 0)
229
  return TRUE;
230
#else
231
if (kevent(tls_watch_fd, &kev[kev_used-cnt], cnt, NULL, 0, NULL) >= 0)
232
  return TRUE;
233
#endif
234
s = US"kevent";
235
236
bad:
237
DEBUG(D_tls)
238
  if (errno)
239
    debug_printf("%s: %s: %s\n", __FUNCTION__, s, strerror(errno));
240
  else
241
    debug_printf("%s: %s\n", __FUNCTION__, s);
242
return FALSE;
243
}
244
# endif	/*EXIM_HAVE_KEVENT*/
245
246
247
/* Create an inotify facility if needed.
248
Then set watches on the dir containing the given file or (optionally)
249
list of files.  Return boolean success. */
250
251
static BOOL
252
tls_set_watch(const uschar * filename, BOOL list)
253
{
254
rmark r;
255
BOOL rc = FALSE;
256
257
if (!filename || !*filename) return TRUE;
258
if (Ustrncmp(filename, "system", 6) == 0) return TRUE;
259
260
DEBUG(D_tls) debug_printf("tls_set_watch: '%s'\n", filename);
261
262
if (  tls_watch_fd < 0
263
# ifdef EXIM_HAVE_INOTIFY
264
   && (tls_watch_fd = inotify_init1(O_CLOEXEC)) < 0
265
# endif
266
# ifdef EXIM_HAVE_KEVENT
267
   && (tls_watch_fd = kqueue()) < 0
268
# endif
269
   )
270
    {
271
    DEBUG(D_tls) debug_printf("inotify_init: %s\n", strerror(errno));
272
    return FALSE;
273
    }
274
275
r = store_mark();
276
277
if (list)
278
  {
279
  int sep = 0;
280
  for (uschar * s; s = string_nextinlist(&filename, &sep, NULL, 0); )
281
    if (!(rc = tls_set_one_watch(s))) break;
282
  }
283
else
284
  rc = tls_set_one_watch(filename);
285
286
store_reset(r);
287
if (!rc) DEBUG(D_tls) debug_printf("tls_set_watch() fail on '%s': %s\n", filename, strerror(errno));
288
return rc;
289
}
290
291
292
void
293
tls_watch_discard_event(int fd)
294
{
295
#ifdef EXIM_HAVE_INOTIFY
296
(void) read(fd, big_buffer, big_buffer_size);
297
#endif
298
#ifdef EXIM_HAVE_KEVENT
299
struct kevent kev;
300
struct timespec t = {0};
301
(void) kevent(fd, NULL, 0, &kev, 1, &t);
302
#endif
303
}
304
#endif	/*EXIM_HAVE_INOTIFY*/
305
306
307
void
308
tls_client_creds_reload(BOOL watch)
309
{
310
for(transport_instance * t = transports; t; t = t->next)
311
  if (Ustrcmp(t->driver_name, "smtp") == 0)
312
    {
313
    tls_client_creds_invalidate(t);
314
    tls_client_creds_init(t, watch);
315
    }
316
}
317
318
319
void
320
tls_watch_invalidate(void)
321
{
322
if (tls_watch_fd < 0) return;
323
324
#ifdef EXIM_HAVE_KEVENT
325
/* Close the files we had open for kevent */
326
for (int i = 0; i < kev_used; i++)
327
  {
328
  DEBUG(D_tls) debug_printf("closing watch fd: %d\n", (int) kev[i].ident);
329
  (void) close((int) kev[i].ident);
330
  kev[i].ident = (uintptr_t)-1;
331
  }
332
kev_used = 0;
333
#endif
334
335
close(tls_watch_fd);
336
tls_watch_fd = -1;
337
}
338
339
340
static void
341
tls_daemon_creds_reload(void)
342
{
343
unsigned lifetime;
344
345
#ifdef EXIM_HAVE_KEVENT
346
tls_watch_invalidate();
347
#endif
348
349
tls_server_creds_invalidate();
350
tls_creds_expire = (lifetime = tls_server_creds_init())
351
  ? time(NULL) + lifetime : 0;
352
353
tls_client_creds_reload(TRUE);
354
}
355
356
357
/* Utility predicates for use by the per-library code */
358
static BOOL
359
opt_set_and_noexpand(const uschar * opt)
360
{ return opt && *opt && Ustrchr(opt, '$') == NULL; }
361
362
static BOOL
363
opt_unset_or_noexpand(const uschar * opt)
364
{ return !opt || Ustrchr(opt, '$') == NULL; }
365
366
367
368
/* Called every time round the daemon loop.
369
370
If we reloaded fd-watcher, return the old watch fd
371
having modified the global for the new one. Otherwise
372
return -1.
373
*/
374
375
int
376
tls_daemon_tick(void)
377
{
378
int old_watch_fd = tls_watch_fd;
379
380
tls_per_lib_daemon_tick();
381
#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
382
if (tls_creds_expire && time(NULL) >= tls_creds_expire)
383
  {
384
  /* The server cert is a selfsign, with limited lifetime.  Dump it and
385
  generate a new one.  Reload the rest of the creds also as the machinery
386
  is all there. */
387
388
  DEBUG(D_tls) debug_printf("selfsign cert rotate\n");
389
  tls_creds_expire = 0;
390
  tls_daemon_creds_reload();
391
  return old_watch_fd;
392
  }
393
else if (tls_watch_trigger_time && time(NULL) >= tls_watch_trigger_time + 5)
394
  {
395
  /* Called, after a delay for multiple file ops to get done, from
396
  the daemon when any of the watches added (above) fire.
397
  Dump the set of watches and arrange to reload cached creds (which
398
  will set up new watches). */
399
400
  DEBUG(D_tls) debug_printf("watch triggered\n");
401
  tls_watch_trigger_time = tls_creds_expire = 0;
402
  tls_daemon_creds_reload();
403
  return old_watch_fd;
404
  }
405
#endif
406
return -1;
407
}
408
409
/* Called once at daemon startup */
410
411
void
412
tls_daemon_init(void)
413
{
414
tls_per_lib_daemon_init();
415
}
416
417
99
/*************************************************
418
/*************************************************
100
*        Timezone environment flipping           *
419
*        Timezone environment flipping           *
101
*************************************************/
420
*************************************************/
Lines 372-378 Link Here
372
return FALSE;
691
return FALSE;
373
}
692
}
374
693
375
376
/* Environment cleanup: The GnuTLS library uses SSLKEYLOGFILE in the environment
694
/* Environment cleanup: The GnuTLS library uses SSLKEYLOGFILE in the environment
377
and writes a file by that name.  Our OpenSSL code does the same, using keying
695
and writes a file by that name.  Our OpenSSL code does the same, using keying
378
info from the library API.
696
info from the library API.
Lines 478-483 Link Here
478
796
479
797
480
798
799
static void
800
tls_client_resmption_key(tls_support * tlsp, smtp_connect_args * conn_args,
801
  smtp_transport_options_block * ob)
802
{
803
#ifndef DISABLE_TLS_RESUME
804
hctx * h = &tlsp->resume_hctx;
805
blob b;
806
gstring * g;
807
808
DEBUG(D_tls) if (conn_args->host_lbserver)
809
  debug_printf("TLS: lbserver '%s'\n", conn_args->host_lbserver);
810
811
# ifdef EXIM_HAVE_SHA2
812
exim_sha_init(h, HASH_SHA2_256);
813
# else
814
exim_sha_init(h, HASH_SHA1);
815
# endif
816
exim_sha_update_string(h, conn_args->host_lbserver);
817
# ifdef SUPPORT_DANE
818
if (conn_args->dane)
819
  exim_sha_update(h,  CUS &conn_args->tlsa_dnsa, sizeof(dns_answer));
820
# endif
821
exim_sha_update_string(h, conn_args->host->address);
822
exim_sha_update(h,   CUS &conn_args->host->port, sizeof(conn_args->host->port));
823
exim_sha_update_string(h, conn_args->sending_ip_address);
824
exim_sha_update_string(h, openssl_options);
825
exim_sha_update_string(h, ob->tls_require_ciphers);
826
exim_sha_update_string(h, tlsp->sni);
827
# ifdef EXIM_HAVE_ALPN
828
exim_sha_update_string(h, ob->tls_alpn);
829
# endif
830
exim_sha_finish(h, &b);
831
for (g = string_get(b.len*2+1); b.len-- > 0; )
832
  g = string_fmt_append(g, "%02x", *b.data++);
833
tlsp->resume_index = string_from_gstring(g);
834
DEBUG(D_tls) debug_printf("TLS: resume session index %s\n", tlsp->resume_index);
835
#endif
836
}
837
481
#endif	/*!DISABLE_TLS*/
838
#endif	/*!DISABLE_TLS*/
482
#endif	/*!MACRO_PREDEF*/
839
#endif	/*!MACRO_PREDEF*/
483
840
(-)exim.orig/src/tlscert-gnu.c (-14 / +15 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2021 - 2022 */
5
/* Copyright (c) Jeremy Harris 2014 - 2018 */
6
/* Copyright (c) Jeremy Harris 2014 - 2018 */
6
7
7
/* This file provides TLS/SSL support for Exim using the GnuTLS library,
8
/* This file provides TLS/SSL support for Exim using the GnuTLS library,
Lines 114-120 Link Here
114
if (mod && Ustrcmp(mod, "int") == 0)
115
if (mod && Ustrcmp(mod, "int") == 0)
115
  return string_sprintf("%u", (unsigned)t);
116
  return string_sprintf("%u", (unsigned)t);
116
117
117
cp = store_get(len, FALSE);
118
cp = store_get(len, GET_UNTAINTED);
118
if (f.timestamps_utc)
119
if (f.timestamps_utc)
119
  {
120
  {
120
  uschar * tz = to_tz(US"GMT0");
121
  uschar * tz = to_tz(US"GMT0");
Lines 148-154 Link Here
148
    != GNUTLS_E_SHORT_MEMORY_BUFFER)
149
    != GNUTLS_E_SHORT_MEMORY_BUFFER)
149
  return g_err("gi0", __FUNCTION__, ret);
150
  return g_err("gi0", __FUNCTION__, ret);
150
151
151
cp = store_get(siz, TRUE);
152
cp = store_get(siz, GET_TAINTED);
152
if ((ret = gnutls_x509_crt_get_issuer_dn(cert, CS cp, &siz)) < 0)
153
if ((ret = gnutls_x509_crt_get_issuer_dn(cert, CS cp, &siz)) < 0)
153
  return g_err("gi1", __FUNCTION__, ret);
154
  return g_err("gi1", __FUNCTION__, ret);
154
155
Lines 202-208 Link Here
202
    != GNUTLS_E_SHORT_MEMORY_BUFFER)
203
    != GNUTLS_E_SHORT_MEMORY_BUFFER)
203
  return g_err("gs0", __FUNCTION__, ret);
204
  return g_err("gs0", __FUNCTION__, ret);
204
205
205
cp1 = store_get(len*4+1, TRUE);
206
cp1 = store_get(len*4+1, GET_TAINTED);
206
if (gnutls_x509_crt_get_signature((gnutls_x509_crt_t)cert, CS cp1, &len) != 0)
207
if (gnutls_x509_crt_get_signature((gnutls_x509_crt_t)cert, CS cp1, &len) != 0)
207
  return g_err("gs1", __FUNCTION__, ret);
208
  return g_err("gs1", __FUNCTION__, ret);
208
209
Lines 232-238 Link Here
232
    != GNUTLS_E_SHORT_MEMORY_BUFFER)
233
    != GNUTLS_E_SHORT_MEMORY_BUFFER)
233
  return g_err("gs0", __FUNCTION__, ret);
234
  return g_err("gs0", __FUNCTION__, ret);
234
235
235
cp = store_get(siz, TRUE);
236
cp = store_get(siz, GET_TAINTED);
236
if ((ret = gnutls_x509_crt_get_dn(cert, CS cp, &siz)) < 0)
237
if ((ret = gnutls_x509_crt_get_dn(cert, CS cp, &siz)) < 0)
237
  return g_err("gs1", __FUNCTION__, ret);
238
  return g_err("gs1", __FUNCTION__, ret);
238
239
Lines 260-266 Link Here
260
if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
261
if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
261
  return g_err("ge0", __FUNCTION__, ret);
262
  return g_err("ge0", __FUNCTION__, ret);
262
263
263
cp1 = store_get(siz*4 + 1, TRUE);
264
cp1 = store_get(siz*4 + 1, GET_TAINTED);
264
265
265
ret = gnutls_x509_crt_get_extension_by_oid ((gnutls_x509_crt_t)cert,
266
ret = gnutls_x509_crt_get_extension_by_oid ((gnutls_x509_crt_t)cert,
266
  CS oid, idx, CS cp1, &siz, &crit);
267
  CS oid, idx, CS cp1, &siz, &crit);
Lines 288-300 Link Here
288
uschar * ele;
289
uschar * ele;
289
int match = -1;
290
int match = -1;
290
291
291
while (mod)
292
if (mod) while (*mod)
292
  {
293
  {
293
  if (*mod == '>' && *++mod) sep = *mod++;
294
  if (*mod == '>' && *++mod) sep = *mod++;
294
  else if (Ustrcmp(mod, "dns")==0) { match = GNUTLS_SAN_DNSNAME; mod += 3; }
295
  else if (Ustrncmp(mod, "dns", 3)==0) { match = GNUTLS_SAN_DNSNAME; mod += 3; }
295
  else if (Ustrcmp(mod, "uri")==0) { match = GNUTLS_SAN_URI; mod += 3; }
296
  else if (Ustrncmp(mod, "uri", 3)==0) { match = GNUTLS_SAN_URI; mod += 3; }
296
  else if (Ustrcmp(mod, "mail")==0) { match = GNUTLS_SAN_RFC822NAME; mod += 4; }
297
  else if (Ustrncmp(mod, "mail", 4)==0) { match = GNUTLS_SAN_RFC822NAME; mod += 4; }
297
  else continue;
298
  else break;
298
299
299
  if (*mod++ != ',')
300
  if (*mod++ != ',')
300
    break;
301
    break;
Lines 316-322 Link Here
316
      return g_err("gs0", __FUNCTION__, ret);
317
      return g_err("gs0", __FUNCTION__, ret);
317
    }
318
    }
318
319
319
  ele = store_get(siz+1, TRUE);
320
  ele = store_get(siz+1, GET_TAINTED);
320
  if ((ret = gnutls_x509_crt_get_subject_alt_name(
321
  if ((ret = gnutls_x509_crt_get_subject_alt_name(
321
    (gnutls_x509_crt_t)cert, index, ele, &siz, NULL)) < 0)
322
    (gnutls_x509_crt_t)cert, index, ele, &siz, NULL)) < 0)
322
    return g_err("gs1", __FUNCTION__, ret);
323
    return g_err("gs1", __FUNCTION__, ret);
Lines 399-405 Link Here
399
      return g_err("gc0", __FUNCTION__, ret);
400
      return g_err("gc0", __FUNCTION__, ret);
400
    }
401
    }
401
402
402
  ele = store_get(siz, TRUE);
403
  ele = store_get(siz, GET_TAINTED);
403
  if ((ret = gnutls_x509_crt_get_crl_dist_points(
404
  if ((ret = gnutls_x509_crt_get_crl_dist_points(
404
      (gnutls_x509_crt_t)cert, index, ele, &siz, NULL, NULL)) < 0)
405
      (gnutls_x509_crt_t)cert, index, ele, &siz, NULL, NULL)) < 0)
405
    return g_err("gc1", __FUNCTION__, ret);
406
    return g_err("gc1", __FUNCTION__, ret);
Lines 422-428 Link Here
422
423
423
if (  (fail = gnutls_x509_crt_export((gnutls_x509_crt_t)cert,
424
if (  (fail = gnutls_x509_crt_export((gnutls_x509_crt_t)cert,
424
	GNUTLS_X509_FMT_DER, cp, &len)) != GNUTLS_E_SHORT_MEMORY_BUFFER
425
	GNUTLS_X509_FMT_DER, cp, &len)) != GNUTLS_E_SHORT_MEMORY_BUFFER
425
   || !(cp = store_get((int)len, TRUE), TRUE)	/* tainted */
426
   || !(cp = store_get((int)len, GET_TAINTED), TRUE)	/* tainted */
426
   || (fail = gnutls_x509_crt_export((gnutls_x509_crt_t)cert,
427
   || (fail = gnutls_x509_crt_export((gnutls_x509_crt_t)cert,
427
        GNUTLS_X509_FMT_DER, cp, &len))
428
        GNUTLS_X509_FMT_DER, cp, &len))
428
   )
429
   )
Lines 447-453 Link Here
447
    != GNUTLS_E_SHORT_MEMORY_BUFFER)
448
    != GNUTLS_E_SHORT_MEMORY_BUFFER)
448
  return g_err("gf0", __FUNCTION__, ret);
449
  return g_err("gf0", __FUNCTION__, ret);
449
450
450
cp = store_get(siz*3+1, TRUE);
451
cp = store_get(siz*3+1, GET_TAINTED);
451
if ((ret = gnutls_x509_crt_get_fingerprint(cert, algo, cp, &siz)) < 0)
452
if ((ret = gnutls_x509_crt_get_fingerprint(cert, algo, cp, &siz)) < 0)
452
  return g_err("gf1", __FUNCTION__, ret);
453
  return g_err("gf1", __FUNCTION__, ret);
453
454
(-)exim.orig/src/tlscert-openssl.c (-3 / +4 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2022 */
5
/* Copyright (c) Jeremy Harris 2014 - 2019 */
6
/* Copyright (c) Jeremy Harris 2014 - 2019 */
6
7
7
/* This module provides TLS (aka SSL) support for Exim using the OpenSSL
8
/* This module provides TLS (aka SSL) support for Exim using the OpenSSL
Lines 171-177 Link Here
171
172
172
      /* convert to string in our format */
173
      /* convert to string in our format */
173
      len = 32;
174
      len = 32;
174
      s = store_get(len, FALSE);
175
      s = store_get(len, GET_UNTAINTED);
175
      strftime(CS s, (size_t)len, "%b %e %T %Y %z", tm_p);
176
      strftime(CS s, (size_t)len, "%b %e %T %Y %z", tm_p);
176
      }
177
      }
177
    }
178
    }
Lines 335-341 Link Here
335
/* binary data, DER encoded */
336
/* binary data, DER encoded */
336
/* just dump for now */
337
/* just dump for now */
337
len = BIO_get_mem_data(bp, &cp1);
338
len = BIO_get_mem_data(bp, &cp1);
338
cp3 = cp2 = store_get(len*3+1, TRUE);
339
cp3 = cp2 = store_get(len*3+1, GET_TAINTED);
339
340
340
while(len)
341
while(len)
341
  {
342
  {
Lines 502-508 Link Here
502
  expand_string_message = US"tls_cert_fprt: out of mem\n";
503
  expand_string_message = US"tls_cert_fprt: out of mem\n";
503
  return NULL;
504
  return NULL;
504
  }
505
  }
505
cp = store_get(n*2+1, TRUE);
506
cp = store_get(n*2+1, GET_TAINTED);
506
for (int j = 0; j < (int)n; j++) sprintf(CS cp+2*j, "%02X", md[j]);
507
for (int j = 0; j < (int)n; j++) sprintf(CS cp+2*j, "%02X", md[j]);
507
return(cp);
508
return(cp);
508
}
509
}
(-)exim.orig/src/tls-gnu.c (-567 / +1236 lines)
Lines 2-12 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
8
9
/* Copyright (c) Phil Pennock 2012 */
7
/* Copyright (c) Phil Pennock 2012 */
8
/* See the file NOTICE for conditions of use and distribution. */
10
9
11
/* This file provides TLS/SSL support for Exim using the GnuTLS library,
10
/* This file provides TLS/SSL support for Exim using the GnuTLS library,
12
one of the available supported implementations.  This file is #included into
11
one of the available supported implementations.  This file is #included into
Lines 90-98 Link Here
90
#if GNUTLS_VERSION_NUMBER >= 0x030506 && !defined(DISABLE_OCSP)
89
#if GNUTLS_VERSION_NUMBER >= 0x030506 && !defined(DISABLE_OCSP)
91
# define SUPPORT_SRV_OCSP_STACK
90
# define SUPPORT_SRV_OCSP_STACK
92
#endif
91
#endif
93
#if GNUTLS_VERSION_NUMBER >= 0x030600
94
# define GNUTLS_AUTO_DHPARAMS
95
#endif
96
#if GNUTLS_VERSION_NUMBER >= 0x030603
92
#if GNUTLS_VERSION_NUMBER >= 0x030603
97
# define EXIM_HAVE_TLS1_3
93
# define EXIM_HAVE_TLS1_3
98
# define SUPPORT_GNUTLS_EXT_RAW_PARSE
94
# define SUPPORT_GNUTLS_EXT_RAW_PARSE
Lines 111-119 Link Here
111
# endif
107
# endif
112
#endif
108
#endif
113
109
114
#ifdef EXPERIMENTAL_TLS_RESUME
110
#ifndef DISABLE_TLS_RESUME
115
# if GNUTLS_VERSION_NUMBER < 0x030603
111
# if GNUTLS_VERSION_NUMBER >= 0x030603
116
#  error GNUTLS version too early for session-resumption
112
#  define EXIM_HAVE_TLS_RESUME
113
# else
114
#  warning "GnuTLS library version too old; resumption unsupported"
115
# endif
116
#endif
117
118
#if GNUTLS_VERSION_NUMBER >= 0x030200
119
# ifdef SUPPORT_GNUTLS_EXT_RAW_PARSE
120
#  define EXIM_HAVE_ALPN
117
# endif
121
# endif
118
#endif
122
#endif
119
123
Lines 131-137 Link Here
131
void
135
void
132
options_tls(void)
136
options_tls(void)
133
{
137
{
134
# ifdef EXPERIMENTAL_TLS_RESUME
138
# ifndef DISABLE_TLS_RESUME
135
builtin_macro_create_var(US"_RESUME_DECODE", RESUME_DECODE_STRING );
139
builtin_macro_create_var(US"_RESUME_DECODE", RESUME_DECODE_STRING );
136
# endif
140
# endif
137
# ifdef EXIM_HAVE_TLS1_3
141
# ifdef EXIM_HAVE_TLS1_3
Lines 143-148 Link Here
143
# ifdef SUPPORT_SRV_OCSP_STACK
147
# ifdef SUPPORT_SRV_OCSP_STACK
144
builtin_macro_create(US"_HAVE_TLS_OCSP_LIST");
148
builtin_macro_create(US"_HAVE_TLS_OCSP_LIST");
145
# endif
149
# endif
150
#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
151
builtin_macro_create(US"_HAVE_TLS_CA_CACHE");
152
# endif
153
# ifdef EXIM_HAVE_ALPN
154
builtin_macro_create(US"_HAVE_TLS_ALPN");
155
# endif
146
}
156
}
147
#else
157
#else
148
158
Lines 176-183 Link Here
176
186
177
typedef struct exim_gnutls_state {
187
typedef struct exim_gnutls_state {
178
  gnutls_session_t	session;
188
  gnutls_session_t	session;
179
  gnutls_certificate_credentials_t x509_cred;
189
180
  gnutls_priority_t	priority_cache;
190
  exim_tlslib_state	lib_state;
191
#define x509_cred		libdata0
192
#define pri_cache		libdata1
193
181
  enum peer_verify_requirement verify_requirement;
194
  enum peer_verify_requirement verify_requirement;
182
  int			fd_in;
195
  int			fd_in;
183
  int			fd_out;
196
  int			fd_out;
Lines 243-257 Link Here
243
XXX But see gnutls_session_get_ptr()
256
XXX But see gnutls_session_get_ptr()
244
*/
257
*/
245
258
246
static exim_gnutls_state_st state_server;
259
static exim_gnutls_state_st state_server = {
260
  /* all elements not explicitly intialised here get 0/NULL/FALSE */
261
  .fd_in =		-1,
262
  .fd_out =		-1,
263
};
247
264
248
#ifndef GNUTLS_AUTO_DHPARAMS
249
/* dh_params are initialised once within the lifetime of a process using TLS;
265
/* dh_params are initialised once within the lifetime of a process using TLS;
250
if we used TLS in a long-lived daemon, we'd have to reconsider this.  But we
266
if we used TLS in a long-lived daemon, we'd have to reconsider this.  But we
251
don't want to repeat this. */
267
don't want to repeat this. */
252
268
253
static gnutls_dh_params_t dh_server_params = NULL;
269
static gnutls_dh_params_t dh_server_params = NULL;
254
#endif
255
270
256
static int ssl_session_timeout = 7200;	/* Two hours */
271
static int ssl_session_timeout = 7200;	/* Two hours */
257
272
Lines 266-275 Link Here
266
static BOOL exim_testharness_disable_ocsp_validity_check = FALSE;
281
static BOOL exim_testharness_disable_ocsp_validity_check = FALSE;
267
#endif
282
#endif
268
283
269
#ifdef EXPERIMENTAL_TLS_RESUME
284
#ifdef EXIM_HAVE_ALPN
285
static int server_seen_alpn = -1;	/* count of names */
286
#endif
287
#ifdef EXIM_HAVE_TLS_RESUME
270
static gnutls_datum_t server_sessticket_key;
288
static gnutls_datum_t server_sessticket_key;
271
#endif
289
#endif
272
290
291
273
/* ------------------------------------------------------------------------ */
292
/* ------------------------------------------------------------------------ */
274
/* macros */
293
/* macros */
275
294
Lines 296-302 Link Here
296
# define EXIM_SERVER_DH_BITS_PRE2_12 1024
315
# define EXIM_SERVER_DH_BITS_PRE2_12 1024
297
#endif
316
#endif
298
317
299
#define expand_check_tlsvar(Varname, errstr) \
318
#define Expand_check_tlsvar(Varname, errstr) \
300
  expand_check(state->Varname, US #Varname, &state->exp_##Varname, errstr)
319
  expand_check(state->Varname, US #Varname, &state->exp_##Varname, errstr)
301
320
302
#if GNUTLS_VERSION_NUMBER >= 0x020c00
321
#if GNUTLS_VERSION_NUMBER >= 0x020c00
Lines 314-319 Link Here
314
# endif /* AVOID_GNUTLS_PKCS11 */
333
# endif /* AVOID_GNUTLS_PKCS11 */
315
#endif
334
#endif
316
335
336
#if GNUTLS_VERSION_NUMBER >= 0x030404
337
# define HAVE_GNUTLS_PRF_RFC5705
338
#endif
317
339
318
340
319
341
Lines 326-359 Link Here
326
348
327
static int exim_sni_handling_cb(gnutls_session_t session);
349
static int exim_sni_handling_cb(gnutls_session_t session);
328
350
329
#ifdef EXPERIMENTAL_TLS_RESUME
351
#ifdef EXIM_HAVE_TLS_RESUME
330
static int
352
static int
331
tls_server_ticket_cb(gnutls_session_t sess, u_int htype, unsigned when,
353
tls_server_ticket_cb(gnutls_session_t sess, u_int htype, unsigned when,
332
  unsigned incoming, const gnutls_datum_t * msg);
354
  unsigned incoming, const gnutls_datum_t * msg);
333
#endif
355
#endif
334
356
335
357
336
/* Daemon one-time initialisation */
337
void
338
tls_daemon_init(void)
339
{
340
#ifdef EXPERIMENTAL_TLS_RESUME
341
/* We are dependent on the GnuTLS implementation of the Session Ticket
342
encryption; both the strength and the key rotation period.  We hope that
343
the strength at least matches that of the ciphersuite (but GnuTLS does not
344
document this). */
345
346
static BOOL once = FALSE;
347
if (once) return;
348
once = TRUE;
349
gnutls_session_ticket_key_generate(&server_sessticket_key);	/* >= 2.10.0 */
350
if (f.running_in_test_harness) ssl_session_timeout = 6;
351
#endif
352
}
353
354
/* ------------------------------------------------------------------------ */
355
/* Static functions */
356
357
/*************************************************
358
/*************************************************
358
*               Handle TLS error                 *
359
*               Handle TLS error                 *
359
*************************************************/
360
*************************************************/
Lines 387-396 Link Here
387
388
388
389
389
static int
390
static int
390
tls_error_gnu(const uschar *prefix, int err, const host_item *host,
391
tls_error_gnu(exim_gnutls_state_st * state, const uschar *prefix, int err,
391
  uschar ** errstr)
392
  uschar ** errstr)
392
{
393
{
393
return tls_error(prefix, US gnutls_strerror(err), host, errstr);
394
return tls_error(prefix,
395
  state && err == GNUTLS_E_FATAL_ALERT_RECEIVED
396
  ? US gnutls_alert_get_name(gnutls_alert_get(state->session))
397
  : US gnutls_strerror(err),
398
  state ? state->host : NULL,
399
  errstr);
394
}
400
}
395
401
396
static int
402
static int
Lines 401-406 Link Here
401
}
407
}
402
408
403
409
410
/* ------------------------------------------------------------------------ */
411
/* Initialisation */
412
413
#ifndef DISABLE_OCSP
414
415
static BOOL
416
tls_is_buggy_ocsp(void)
417
{
418
const uschar * s;
419
uschar maj, mid, mic;
420
421
s = CUS gnutls_check_version(NULL);
422
maj = atoi(CCS s);
423
if (maj == 3)
424
  {
425
  while (*s && *s != '.') s++;
426
  mid = atoi(CCS ++s);
427
  if (mid <= 2)
428
    return TRUE;
429
  else if (mid >= 5)
430
    return FALSE;
431
  else
432
    {
433
    while (*s && *s != '.') s++;
434
    mic = atoi(CCS ++s);
435
    return mic <= (mid == 3 ? 16 : 3);
436
    }
437
  }
438
return FALSE;
439
}
440
441
#endif
442
443
444
static int
445
tls_g_init(uschar ** errstr)
446
{
447
int rc;
448
DEBUG(D_tls) debug_printf("GnuTLS global init required\n");
449
450
#if defined(HAVE_GNUTLS_PKCS11) && !defined(GNUTLS_AUTO_PKCS11_MANUAL)
451
/* By default, gnutls_global_init will init PKCS11 support in auto mode,
452
which loads modules from a config file, which sounds good and may be wanted
453
by some sysadmin, but also means in common configurations that GNOME keyring
454
environment variables are used and so breaks for users calling mailq.
455
To prevent this, we init PKCS11 first, which is the documented approach. */
456
457
if (!gnutls_allow_auto_pkcs11)
458
  if ((rc = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL)))
459
    return tls_error_gnu(NULL, US"gnutls_pkcs11_init", rc, errstr);
460
#endif
461
462
#ifndef GNUTLS_AUTO_GLOBAL_INIT
463
if ((rc = gnutls_global_init()))
464
  return tls_error_gnu(NULL, US"gnutls_global_init", rc, errstr);
465
#endif
466
467
#if EXIM_GNUTLS_LIBRARY_LOG_LEVEL >= 0
468
DEBUG(D_tls)
469
  {
470
  gnutls_global_set_log_function(exim_gnutls_logger_cb);
471
  /* arbitrarily chosen level; bump up to 9 for more */
472
  gnutls_global_set_log_level(EXIM_GNUTLS_LIBRARY_LOG_LEVEL);
473
  }
474
#endif
475
476
#ifndef DISABLE_OCSP
477
if (tls_ocsp_file && (gnutls_buggy_ocsp = tls_is_buggy_ocsp()))
478
  log_write(0, LOG_MAIN, "OCSP unusable with this GnuTLS library version");
479
#endif
480
481
exim_gnutls_base_init_done = TRUE;
482
return OK;
483
}
484
485
486
487
/* Daemon-call before each connection.  Nothing to do for GnuTLS. */
488
489
static void
490
tls_per_lib_daemon_tick(void)
491
{
492
}
493
494
/* Daemon one-time initialisation */
495
496
static void
497
tls_per_lib_daemon_init(void)
498
{
499
uschar * dummy_errstr;
500
static BOOL once = FALSE;
501
502
if (!exim_gnutls_base_init_done)
503
  tls_g_init(&dummy_errstr);
504
505
if (!once)
506
  {
507
  once = TRUE;
508
509
#ifdef EXIM_HAVE_TLS_RESUME
510
  /* We are dependent on the GnuTLS implementation of the Session Ticket
511
  encryption; both the strength and the key rotation period.  We hope that
512
  the strength at least matches that of the ciphersuite (but GnuTLS does not
513
  document this). */
514
515
  gnutls_session_ticket_key_generate(&server_sessticket_key);	/* >= 2.10.0 */
516
  if (f.running_in_test_harness) ssl_session_timeout = 6;
517
#endif
518
519
  tls_daemon_creds_reload();
520
  }
521
}
522
523
/* ------------------------------------------------------------------------ */
524
404
/*************************************************
525
/*************************************************
405
*    Deal with logging errors during I/O         *
526
*    Deal with logging errors during I/O         *
406
*************************************************/
527
*************************************************/
Lines 422-432 Link Here
422
const uschar * msg;
543
const uschar * msg;
423
uschar * errstr;
544
uschar * errstr;
424
545
425
if (rc == GNUTLS_E_FATAL_ALERT_RECEIVED)
546
msg = rc == GNUTLS_E_FATAL_ALERT_RECEIVED
426
  msg = string_sprintf("A TLS fatal alert has been received: %s",
547
  ? string_sprintf("A TLS fatal alert has been received: %s",
427
    US gnutls_alert_get_name(gnutls_alert_get(state->session)));
548
      US gnutls_alert_get_name(gnutls_alert_get(state->session)))
428
else
549
#ifdef GNUTLS_E_PREMATURE_TERMINATION
429
  msg = US gnutls_strerror(rc);
550
  : rc == GNUTLS_E_PREMATURE_TERMINATION && errno
551
  ? string_sprintf("%s: syscall: %s", US gnutls_strerror(rc), strerror(errno))
552
#endif
553
  : US gnutls_strerror(rc);
430
554
431
(void) tls_error(when, msg, state->host, &errstr);
555
(void) tls_error(when, msg, state->host, &errstr);
432
556
Lines 503-513 Link Here
503
static void
627
static void
504
extract_exim_vars_from_tls_state(exim_gnutls_state_st * state)
628
extract_exim_vars_from_tls_state(exim_gnutls_state_st * state)
505
{
629
{
506
#ifdef HAVE_GNUTLS_SESSION_CHANNEL_BINDING
507
int old_pool;
508
int rc;
509
gnutls_datum_t channel;
510
#endif
511
tls_support * tlsp = state->tlsp;
630
tls_support * tlsp = state->tlsp;
512
631
513
tlsp->active.sock = state->fd_out;
632
tlsp->active.sock = state->fd_out;
Lines 525-545 Link Here
525
644
526
tlsp->channelbinding = NULL;
645
tlsp->channelbinding = NULL;
527
#ifdef HAVE_GNUTLS_SESSION_CHANNEL_BINDING
646
#ifdef HAVE_GNUTLS_SESSION_CHANNEL_BINDING
528
channel.data = NULL;
529
channel.size = 0;
530
if ((rc = gnutls_session_channel_binding(state->session, GNUTLS_CB_TLS_UNIQUE, &channel)))
531
  { DEBUG(D_tls) debug_printf("Channel binding error: %s\n", gnutls_strerror(rc)); }
532
else
533
  {
647
  {
534
  /* Declare the taintedness of the binding info.  On server, untainted; on
648
  gnutls_datum_t channel = {.data = NULL, .size = 0};
535
  client, tainted - being the Finish msg from the server. */
649
  uschar * buf;
650
  int rc;
536
651
537
  old_pool = store_pool;
652
# ifdef HAVE_GNUTLS_PRF_RFC5705
538
  store_pool = POOL_PERM;
653
  /* Older libraries may not have GNUTLS_TLS1_3 defined! */
539
  tlsp->channelbinding = b64encode_taint(CUS channel.data, (int)channel.size,
654
  if (gnutls_protocol_get_version(state->session) > GNUTLS_TLS1_2)
540
					  !!state->host);
655
    {
541
  store_pool = old_pool;
656
    buf = store_get(32, state->host ? GET_TAINTED : GET_UNTAINTED);
542
  DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage\n");
657
    rc = gnutls_prf_rfc5705(state->session,
658
				(size_t)24,  "EXPORTER-Channel-Binding", (size_t)0, "",
659
				32, CS buf);
660
    channel.data = buf;
661
    channel.size = 32;
662
    }
663
  else
664
# endif
665
    rc = gnutls_session_channel_binding(state->session, GNUTLS_CB_TLS_UNIQUE, &channel);
666
667
  if (rc)
668
    { DEBUG(D_tls) debug_printf("extracting channel binding: %s\n", gnutls_strerror(rc)); }
669
  else
670
    {
671
    int old_pool = store_pool;
672
    /* Declare the taintedness of the binding info.  On server, untainted; on
673
    client, tainted - being the Finish msg from the server. */
674
675
    store_pool = POOL_PERM;
676
    tlsp->channelbinding = b64encode_taint(CUS channel.data, (int)channel.size,
677
					    state->host ? GET_TAINTED : GET_UNTAINTED);
678
    store_pool = old_pool;
679
    DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage\n");
680
    }
543
  }
681
  }
544
#endif
682
#endif
545
683
Lines 562-568 Link Here
562
700
563
701
564
702
565
#ifndef GNUTLS_AUTO_DHPARAMS
566
/*************************************************
703
/*************************************************
567
*            Setup up DH parameters              *
704
*            Setup up DH parameters              *
568
*************************************************/
705
*************************************************/
Lines 585-591 Link Here
585
{
722
{
586
int fd, rc;
723
int fd, rc;
587
unsigned int dh_bits;
724
unsigned int dh_bits;
588
gnutls_datum_t m = {.data = NULL, .size = 0};
725
gnutls_datum_t m;
589
uschar filename_buf[PATH_MAX];
726
uschar filename_buf[PATH_MAX];
590
uschar *filename = NULL;
727
uschar *filename = NULL;
591
size_t sz;
728
size_t sz;
Lines 593-602 Link Here
593
BOOL use_file_in_spool = FALSE;
730
BOOL use_file_in_spool = FALSE;
594
host_item *host = NULL; /* dummy for macros */
731
host_item *host = NULL; /* dummy for macros */
595
732
596
DEBUG(D_tls) debug_printf("Initialising GnuTLS server params.\n");
733
DEBUG(D_tls) debug_printf("Initialising GnuTLS server params\n");
597
734
598
if ((rc = gnutls_dh_params_init(&dh_server_params)))
735
if ((rc = gnutls_dh_params_init(&dh_server_params)))
599
  return tls_error_gnu(US"gnutls_dh_params_init", rc, host, errstr);
736
  return tls_error_gnu(NULL, US"gnutls_dh_params_init", rc, errstr);
737
738
m.data = NULL;
739
m.size = 0;
600
740
601
if (!expand_check(tls_dhparam, US"tls_dhparam", &exp_tls_dhparam, errstr))
741
if (!expand_check(tls_dhparam, US"tls_dhparam", &exp_tls_dhparam, errstr))
602
  return DEFER;
742
  return DEFER;
Lines 611-617 Link Here
611
  use_file_in_spool = TRUE;
751
  use_file_in_spool = TRUE;
612
else if (Ustrcmp(exp_tls_dhparam, "none") == 0)
752
else if (Ustrcmp(exp_tls_dhparam, "none") == 0)
613
  {
753
  {
614
  DEBUG(D_tls) debug_printf("Requested no DH parameters.\n");
754
  DEBUG(D_tls) debug_printf("Requested no DH parameters\n");
615
  return OK;
755
  return OK;
616
  }
756
  }
617
else if (exp_tls_dhparam[0] != '/')
757
else if (exp_tls_dhparam[0] != '/')
Lines 626-632 Link Here
626
if (m.data)
766
if (m.data)
627
  {
767
  {
628
  if ((rc = gnutls_dh_params_import_pkcs3(dh_server_params, &m, GNUTLS_X509_FMT_PEM)))
768
  if ((rc = gnutls_dh_params_import_pkcs3(dh_server_params, &m, GNUTLS_X509_FMT_PEM)))
629
    return tls_error_gnu(US"gnutls_dh_params_import_pkcs3", rc, host, errstr);
769
    return tls_error_gnu(NULL, US"gnutls_dh_params_import_pkcs3", rc, errstr);
630
  DEBUG(D_tls) debug_printf("Loaded fixed standard D-H parameters\n");
770
  DEBUG(D_tls) debug_printf("Loaded fixed standard D-H parameters\n");
631
  return OK;
771
  return OK;
632
  }
772
  }
Lines 638-649 Link Here
638
if (!(dh_bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_NORMAL)))
778
if (!(dh_bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_NORMAL)))
639
  return tls_error(US"gnutls_sec_param_to_pk_bits() failed", NULL, NULL, errstr);
779
  return tls_error(US"gnutls_sec_param_to_pk_bits() failed", NULL, NULL, errstr);
640
DEBUG(D_tls)
780
DEBUG(D_tls)
641
  debug_printf("GnuTLS tells us that for D-H PK, NORMAL is %d bits.\n",
781
  debug_printf("GnuTLS tells us that for D-H PK, NORMAL is %d bits\n",
642
      dh_bits);
782
      dh_bits);
643
#else
783
#else
644
dh_bits = EXIM_SERVER_DH_BITS_PRE2_12;
784
dh_bits = EXIM_SERVER_DH_BITS_PRE2_12;
645
DEBUG(D_tls)
785
DEBUG(D_tls)
646
  debug_printf("GnuTLS lacks gnutls_sec_param_to_pk_bits(), using %d bits.\n",
786
  debug_printf("GnuTLS lacks gnutls_sec_param_to_pk_bits(), using %d bits\n",
647
      dh_bits);
787
      dh_bits);
648
#endif
788
#endif
649
789
Lines 651-657 Link Here
651
if (dh_bits > tls_dh_max_bits)
791
if (dh_bits > tls_dh_max_bits)
652
  {
792
  {
653
  DEBUG(D_tls)
793
  DEBUG(D_tls)
654
    debug_printf("tls_dh_max_bits clamping override, using %d bits instead.\n",
794
    debug_printf("tls_dh_max_bits clamping override, using %d bits instead\n",
655
        tls_dh_max_bits);
795
        tls_dh_max_bits);
656
  dh_bits = tls_dh_max_bits;
796
  dh_bits = tls_dh_max_bits;
657
  }
797
  }
Lines 710-716 Link Here
710
  rc = gnutls_dh_params_import_pkcs3(dh_server_params, &m, GNUTLS_X509_FMT_PEM);
850
  rc = gnutls_dh_params_import_pkcs3(dh_server_params, &m, GNUTLS_X509_FMT_PEM);
711
  store_free(m.data);
851
  store_free(m.data);
712
  if (rc)
852
  if (rc)
713
    return tls_error_gnu(US"gnutls_dh_params_import_pkcs3", rc, host, errstr);
853
    return tls_error_gnu(NULL, US"gnutls_dh_params_import_pkcs3", rc, errstr);
714
  DEBUG(D_tls) debug_printf("read D-H parameters from file \"%s\"\n", filename);
854
  DEBUG(D_tls) debug_printf("read D-H parameters from file \"%s\"\n", filename);
715
  }
855
  }
716
856
Lines 724-730 Link Here
724
    debug_printf("D-H parameter cache file \"%s\" does not exist\n", filename);
864
    debug_printf("D-H parameter cache file \"%s\" does not exist\n", filename);
725
  }
865
  }
726
else
866
else
727
  return tls_error(string_open_failed(errno, "\"%s\" for reading", filename),
867
  return tls_error(string_open_failed("\"%s\" for reading", filename),
728
      NULL, NULL, errstr);
868
      NULL, NULL, errstr);
729
869
730
/* If ret < 0, either the cache file does not exist, or the data it contains
870
/* If ret < 0, either the cache file does not exist, or the data it contains
Lines 742-758 Link Here
742
    return tls_error(US"Filename too long to generate replacement",
882
    return tls_error(US"Filename too long to generate replacement",
743
        filename, NULL, errstr);
883
        filename, NULL, errstr);
744
884
745
  temp_fn = string_copy(US"%s.XXXXXXX");
885
  temp_fn = string_copy(US"exim-dh.XXXXXXX");
746
  if ((fd = mkstemp(CS temp_fn)) < 0)	/* modifies temp_fn */
886
  if ((fd = mkstemp(CS temp_fn)) < 0)	/* modifies temp_fn */
747
    return tls_error_sys(US"Unable to open temp file", errno, NULL, errstr);
887
    return tls_error_sys(US"Unable to open temp file", errno, NULL, errstr);
748
  (void)exim_chown(temp_fn, exim_uid, exim_gid);   /* Probably not necessary */
888
  (void)exim_chown(temp_fn, exim_uid, exim_gid);   /* Probably not necessary */
749
889
750
  /* GnuTLS overshoots!  If we ask for 2236, we might get 2237 or more.  But
890
  /* GnuTLS overshoots!
751
  there's no way to ask GnuTLS how many bits there really are.  We can ask
891
   * If we ask for 2236, we might get 2237 or more.
752
  how many bits were used in a TLS session, but that's it!  The prime itself
892
   * But there's no way to ask GnuTLS how many bits there really are.
753
  is hidden behind too much abstraction.  So we ask for less, and proceed on
893
   * We can ask how many bits were used in a TLS session, but that's it!
754
  a wing and a prayer.  First attempt, subtracted 3 for 2233 and got 2240.  */
894
   * The prime itself is hidden behind too much abstraction.
755
895
   * So we ask for less, and proceed on a wing and a prayer.
896
   * First attempt, subtracted 3 for 2233 and got 2240.
897
   */
756
  if (dh_bits >= EXIM_CLIENT_DH_MIN_BITS + 10)
898
  if (dh_bits >= EXIM_CLIENT_DH_MIN_BITS + 10)
757
    {
899
    {
758
    dh_bits_gen = dh_bits - 10;
900
    dh_bits_gen = dh_bits - 10;
Lines 765-771 Link Here
765
    debug_printf("requesting generation of %d bit Diffie-Hellman prime ...\n",
907
    debug_printf("requesting generation of %d bit Diffie-Hellman prime ...\n",
766
        dh_bits_gen);
908
        dh_bits_gen);
767
  if ((rc = gnutls_dh_params_generate2(dh_server_params, dh_bits_gen)))
909
  if ((rc = gnutls_dh_params_generate2(dh_server_params, dh_bits_gen)))
768
    return tls_error_gnu(US"gnutls_dh_params_generate2", rc, host, errstr);
910
    return tls_error_gnu(NULL, US"gnutls_dh_params_generate2", rc, errstr);
769
911
770
  /* gnutls_dh_params_export_pkcs3() will tell us the exact size, every time,
912
  /* gnutls_dh_params_export_pkcs3() will tell us the exact size, every time,
771
  and I confirmed that a NULL call to get the size first is how the GnuTLS
913
  and I confirmed that a NULL call to get the size first is how the GnuTLS
Lines 776-783 Link Here
776
  if (  (rc = gnutls_dh_params_export_pkcs3(dh_server_params,
918
  if (  (rc = gnutls_dh_params_export_pkcs3(dh_server_params,
777
		GNUTLS_X509_FMT_PEM, m.data, &sz))
919
		GNUTLS_X509_FMT_PEM, m.data, &sz))
778
     && rc != GNUTLS_E_SHORT_MEMORY_BUFFER)
920
     && rc != GNUTLS_E_SHORT_MEMORY_BUFFER)
779
    return tls_error_gnu(US"gnutls_dh_params_export_pkcs3(NULL) sizing",
921
    return tls_error_gnu(NULL, US"gnutls_dh_params_export_pkcs3(NULL) sizing",
780
	      rc, host, errstr);
922
	      rc, errstr);
781
  m.size = sz;
923
  m.size = sz;
782
  if (!(m.data = store_malloc(m.size)))
924
  if (!(m.data = store_malloc(m.size)))
783
    return tls_error_sys(US"memory allocation failed", errno, NULL, errstr);
925
    return tls_error_sys(US"memory allocation failed", errno, NULL, errstr);
Lines 787-793 Link Here
787
      m.data, &sz)))
929
      m.data, &sz)))
788
    {
930
    {
789
    store_free(m.data);
931
    store_free(m.data);
790
    return tls_error_gnu(US"gnutls_dh_params_export_pkcs3() real", rc, host, errstr);
932
    return tls_error_gnu(NULL, US"gnutls_dh_params_export_pkcs3() real", rc, errstr);
791
    }
933
    }
792
  m.size = sz; /* shrink by 1, probably */
934
  m.size = sz; /* shrink by 1, probably */
793
935
Lines 815-826 Link Here
815
DEBUG(D_tls) debug_printf("initialized server D-H parameters\n");
957
DEBUG(D_tls) debug_printf("initialized server D-H parameters\n");
816
return OK;
958
return OK;
817
}
959
}
818
#endif
819
960
820
961
821
962
822
963
823
/* Create and install a selfsigned certificate, for use in server mode */
964
/* Create and install a selfsigned certificate, for use in server mode. */
824
965
825
static int
966
static int
826
tls_install_selfsign(exim_gnutls_state_st * state, uschar ** errstr)
967
tls_install_selfsign(exim_gnutls_state_st * state, uschar ** errstr)
Lines 837-842 Link Here
837
if (TRUE) goto err;
978
if (TRUE) goto err;
838
#endif
979
#endif
839
980
981
DEBUG(D_tls) debug_printf("TLS: generating selfsigned server cert\n");
840
where = US"initialising pkey";
982
where = US"initialising pkey";
841
if ((rc = gnutls_x509_privkey_init(&pkey))) goto err;
983
if ((rc = gnutls_x509_privkey_init(&pkey))) goto err;
842
984
Lines 861-867 Link Here
861
if (  (rc = gnutls_x509_crt_set_version(cert, 3))
1003
if (  (rc = gnutls_x509_crt_set_version(cert, 3))
862
   || (rc = gnutls_x509_crt_set_serial(cert, &now, sizeof(now)))
1004
   || (rc = gnutls_x509_crt_set_serial(cert, &now, sizeof(now)))
863
   || (rc = gnutls_x509_crt_set_activation_time(cert, now = time(NULL)))
1005
   || (rc = gnutls_x509_crt_set_activation_time(cert, now = time(NULL)))
864
   || (rc = gnutls_x509_crt_set_expiration_time(cert, now + 60 * 60)) /* 1 hr */
1006
   || (rc = gnutls_x509_crt_set_expiration_time(cert, (long)2 * 60 * 60))	/* 2 hour */
865
   || (rc = gnutls_x509_crt_set_key(cert, pkey))
1007
   || (rc = gnutls_x509_crt_set_key(cert, pkey))
866
1008
867
   || (rc = gnutls_x509_crt_set_dn_by_oid(cert,
1009
   || (rc = gnutls_x509_crt_set_dn_by_oid(cert,
Lines 879-885 Link Here
879
1021
880
where = US"installing selfsign cert";
1022
where = US"installing selfsign cert";
881
					/* Since: 2.4.0 */
1023
					/* Since: 2.4.0 */
882
if ((rc = gnutls_certificate_set_x509_key(state->x509_cred, &cert, 1, pkey)))
1024
if ((rc = gnutls_certificate_set_x509_key(state->lib_state.x509_cred,
1025
    &cert, 1, pkey)))
883
  goto err;
1026
  goto err;
884
1027
885
rc = OK;
1028
rc = OK;
Lines 890-896 Link Here
890
  return rc;
1033
  return rc;
891
1034
892
err:
1035
err:
893
  rc = tls_error_gnu(where, rc, NULL, errstr);
1036
  rc = tls_error_gnu(state, where, rc, errstr);
894
  goto out;
1037
  goto out;
895
}
1038
}
896
1039
Lines 906-919 Link Here
906
1049
907
static int
1050
static int
908
tls_add_certfile(exim_gnutls_state_st * state, const host_item * host,
1051
tls_add_certfile(exim_gnutls_state_st * state, const host_item * host,
909
  uschar * certfile, uschar * keyfile, uschar ** errstr)
1052
  const uschar * certfile, const uschar * keyfile, uschar ** errstr)
910
{
1053
{
911
int rc = gnutls_certificate_set_x509_key_file(state->x509_cred,
1054
int rc = gnutls_certificate_set_x509_key_file(state->lib_state.x509_cred,
912
    CS certfile, CS keyfile, GNUTLS_X509_FMT_PEM);
1055
    CCS certfile, CCS keyfile, GNUTLS_X509_FMT_PEM);
913
if (rc < 0)
1056
if (rc < 0)
914
  return tls_error_gnu(
1057
  return tls_error_gnu(state,
915
    string_sprintf("cert/key setup: cert=%s key=%s", certfile, keyfile),
1058
    string_sprintf("cert/key setup: cert=%s key=%s", certfile, keyfile),
916
    rc, host, errstr);
1059
    rc, errstr);
917
return -rc;
1060
return -rc;
918
}
1061
}
919
1062
Lines 948-960 Link Here
948
/* Make a note that we saw a status-request */
1091
/* Make a note that we saw a status-request */
949
static int
1092
static int
950
tls_server_clienthello_ext(void * ctx, unsigned tls_id,
1093
tls_server_clienthello_ext(void * ctx, unsigned tls_id,
951
  const unsigned char *data, unsigned size)
1094
  const uschar * data, unsigned size)
952
{
1095
{
953
/* https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml */
1096
/* The values for tls_id are documented here:
954
if (tls_id == 5)	/* status_request */
1097
https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml */
955
  {
1098
switch (tls_id)
956
  DEBUG(D_tls) debug_printf("Seen status_request extension from client\n");
1099
  {
957
  tls_in.ocsp = OCSP_NOT_RESP;
1100
  case 5:	/* Status Request */
1101
    DEBUG(D_tls) debug_printf("Seen status_request extension from client\n");
1102
    tls_in.ocsp = OCSP_NOT_RESP;
1103
    break;
1104
#ifdef EXIM_HAVE_ALPN
1105
  case 16:	/* Application Layer Protocol Notification */
1106
    /* The format of "data" here doesn't seem to be documented, but appears
1107
    to be a 2-byte field with a (redundant, given the "size" arg) total length
1108
    then a sequence of one-byte size then string (not nul-term) names.  The
1109
    latter is as described in OpenSSL documentation. */
1110
1111
    DEBUG(D_tls) debug_printf("Seen ALPN extension from client (s=%u):", size);
1112
    for (const uschar * s = data+2; s-data < size-1; s += *s + 1)
1113
      {
1114
      server_seen_alpn++;
1115
      DEBUG(D_tls) debug_printf(" '%.*s'", (int)*s, s+1);
1116
      }
1117
    DEBUG(D_tls) debug_printf("\n");
1118
    if (server_seen_alpn > 1)
1119
      {
1120
      DEBUG(D_tls) debug_printf("TLS: too many ALPNs presented in handshake\n");
1121
      return GNUTLS_E_NO_APPLICATION_PROTOCOL;
1122
      }
1123
    break;
1124
#endif
958
  }
1125
  }
959
return 0;
1126
return 0;
960
}
1127
}
Lines 970-975 Link Here
970
}
1137
}
971
1138
972
1139
1140
# ifdef notdef_crashes
973
/* Make a note that we saw a status-response */
1141
/* Make a note that we saw a status-response */
974
static int
1142
static int
975
tls_server_servercerts_ext(void * ctx, unsigned tls_id,
1143
tls_server_servercerts_ext(void * ctx, unsigned tls_id,
Lines 985-990 Link Here
985
  }
1153
  }
986
return 0;
1154
return 0;
987
}
1155
}
1156
# endif
988
1157
989
/* Callback for certificates packet, on server, if we think we might serve stapled-OCSP */
1158
/* Callback for certificates packet, on server, if we think we might serve stapled-OCSP */
990
static int
1159
static int
Lines 992-1024 Link Here
992
  unsigned when, unsigned int incoming, const gnutls_datum_t * msg)
1161
  unsigned when, unsigned int incoming, const gnutls_datum_t * msg)
993
{
1162
{
994
/* Call fn for each extension seen.  3.6.3 onwards */
1163
/* Call fn for each extension seen.  3.6.3 onwards */
995
#ifdef notdef
1164
# ifdef notdef_crashes
996
/*XXX crashes */
1165
				/*XXX crashes */
997
return gnutls_ext_raw_parse(NULL, tls_server_servercerts_ext, msg, 0);
1166
return gnutls_ext_raw_parse(NULL, tls_server_servercerts_ext, msg, 0);
998
#endif
1167
# endif
999
}
1168
}
1000
#endif
1169
#endif /*SUPPORT_GNUTLS_EXT_RAW_PARSE*/
1001
1170
1002
/*XXX in tls1.3 the cert-status travel as an extension next to the cert, in the
1171
/*XXX in tls1.3 the cert-status travel as an extension next to the cert, in the
1003
 "Handshake Protocol: Certificate" record.
1172
 "Handshake Protocol: Certificate" record.
1004
So we need to spot the Certificate handshake message, parse it and spot any status_request extension(s)
1173
So we need to spot the Certificate handshake message, parse it and spot any status_request extension(s)
1005
1174
1006
This is different to tls1.2 - where it is a separate record (wireshake term) / handshake message (gnutls term).
1175
This is different to tls1.2 - where it is a separate record (wireshark term) / handshake message (gnutls term).
1007
*/
1176
*/
1008
1177
1009
#if defined(EXPERIMENTAL_TLS_RESUME) || defined(SUPPORT_GNUTLS_EXT_RAW_PARSE)
1178
#if defined(EXIM_HAVE_TLS_RESUME) || defined(SUPPORT_GNUTLS_EXT_RAW_PARSE)
1010
/* Callback for certificate-status, on server. We sent stapled OCSP. */
1179
/* Callback for certificate-status, on server. We sent stapled OCSP. */
1011
static int
1180
static int
1012
tls_server_certstatus_cb(gnutls_session_t session, unsigned int htype,
1181
tls_server_certstatus_cb(gnutls_session_t session, unsigned int htype,
1013
  unsigned when, unsigned int incoming, const gnutls_datum_t * msg)
1182
  unsigned when, unsigned int incoming, const gnutls_datum_t * msg)
1014
{
1183
{
1015
DEBUG(D_tls) debug_printf("Sending certificate-status\n");		/*XXX we get this for tls1.2 but not for 1.3 */
1184
DEBUG(D_tls) debug_printf("Sending certificate-status\n");		/*XXX we get this for tls1.2 but not for 1.3 */
1016
#ifdef SUPPORT_SRV_OCSP_STACK
1185
# ifdef SUPPORT_SRV_OCSP_STACK
1017
tls_in.ocsp = exim_testharness_disable_ocsp_validity_check
1186
tls_in.ocsp = exim_testharness_disable_ocsp_validity_check
1018
  ? OCSP_VFY_NOT_TRIED : OCSP_VFIED;	/* We know that GnuTLS verifies responses */
1187
  ? OCSP_VFY_NOT_TRIED : OCSP_VFIED;	/* We know that GnuTLS verifies responses */
1019
#else
1188
# else
1020
tls_in.ocsp = OCSP_VFY_NOT_TRIED;
1189
tls_in.ocsp = OCSP_VFY_NOT_TRIED;
1021
#endif
1190
# endif
1022
return 0;
1191
return 0;
1023
}
1192
}
1024
1193
Lines 1038-1044 Link Here
1038
# endif
1207
# endif
1039
  case GNUTLS_HANDSHAKE_CERTIFICATE_STATUS:
1208
  case GNUTLS_HANDSHAKE_CERTIFICATE_STATUS:
1040
    return tls_server_certstatus_cb(sess, htype, when, incoming, msg);
1209
    return tls_server_certstatus_cb(sess, htype, when, incoming, msg);
1041
# ifdef EXPERIMENTAL_TLS_RESUME
1210
# ifdef EXIM_HAVE_TLS_RESUME
1042
  case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET:
1211
  case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET:
1043
    return tls_server_ticket_cb(sess, htype, when, incoming, msg);
1212
    return tls_server_ticket_cb(sess, htype, when, incoming, msg);
1044
# endif
1213
# endif
Lines 1063-1068 Link Here
1063
}
1232
}
1064
#endif
1233
#endif
1065
1234
1235
/**************************************************
1236
* One-time init credentials for server and client *
1237
**************************************************/
1238
1239
static void
1240
creds_basic_init(gnutls_certificate_credentials_t x509_cred, BOOL server)
1241
{
1242
#ifdef SUPPORT_SRV_OCSP_STACK
1243
gnutls_certificate_set_flags(x509_cred, GNUTLS_CERTIFICATE_API_V2);
1244
1245
# if !defined(DISABLE_OCSP) && defined(SUPPORT_GNUTLS_EXT_RAW_PARSE)
1246
if (server && tls_ocsp_file)
1247
  {
1248
  if (f.running_in_test_harness)
1249
    tls_server_testharness_ocsp_fiddle();
1250
1251
  if (exim_testharness_disable_ocsp_validity_check)
1252
    gnutls_certificate_set_flags(x509_cred,
1253
      GNUTLS_CERTIFICATE_API_V2 | GNUTLS_CERTIFICATE_SKIP_OCSP_RESPONSE_CHECK);
1254
  }
1255
# endif
1256
#endif
1257
DEBUG(D_tls)
1258
  debug_printf("TLS: basic cred init, %s\n", server ? "server" : "client");
1259
}
1260
1261
static int
1262
creds_load_server_certs(exim_gnutls_state_st * state, const uschar * cert,
1263
  const uschar * pkey, const uschar * ocsp, uschar ** errstr)
1264
{
1265
const uschar * clist = cert;
1266
const uschar * klist = pkey;
1267
const uschar * olist;
1268
int csep = 0, ksep = 0, osep = 0, cnt = 0, rc;
1269
uschar * cfile, * kfile, * ofile;
1270
#ifndef DISABLE_OCSP
1271
# ifdef SUPPORT_GNUTLS_EXT_RAW_PARSE
1272
gnutls_x509_crt_fmt_t ocsp_fmt = GNUTLS_X509_FMT_DER;
1273
# endif
1274
1275
if (!expand_check(ocsp, US"tls_ocsp_file", &ofile, errstr))
1276
  return DEFER;
1277
olist = ofile;
1278
#endif
1279
1280
while (cfile = string_nextinlist(&clist, &csep, NULL, 0))
1281
1282
  if (!(kfile = string_nextinlist(&klist, &ksep, NULL, 0)))
1283
    return tls_error(US"cert/key setup: out of keys", NULL, NULL, errstr);
1284
  else if ((rc = tls_add_certfile(state, NULL, cfile, kfile, errstr)) > 0)
1285
    return rc;
1286
  else
1287
    {
1288
    int gnutls_cert_index = -rc;
1289
    DEBUG(D_tls) debug_printf("TLS: cert/key %d %s registered\n",
1290
			      gnutls_cert_index, cfile);
1291
1292
#ifndef DISABLE_OCSP
1293
    if (ocsp)
1294
      {
1295
      /* Set the OCSP stapling server info */
1296
      if (gnutls_buggy_ocsp)
1297
	{
1298
	DEBUG(D_tls)
1299
	  debug_printf("GnuTLS library is buggy for OCSP; avoiding\n");
1300
	}
1301
      else if ((ofile = string_nextinlist(&olist, &osep, NULL, 0)))
1302
	{
1303
	DEBUG(D_tls) debug_printf("OCSP response file %d  = %s\n",
1304
				  gnutls_cert_index, ofile);
1305
# ifdef SUPPORT_GNUTLS_EXT_RAW_PARSE
1306
	if (Ustrncmp(ofile, US"PEM ", 4) == 0)
1307
	  {
1308
	  ocsp_fmt = GNUTLS_X509_FMT_PEM;
1309
	  ofile += 4;
1310
	  }
1311
	else if (Ustrncmp(ofile, US"DER ", 4) == 0)
1312
	  {
1313
	  ocsp_fmt = GNUTLS_X509_FMT_DER;
1314
	  ofile += 4;
1315
	  }
1316
1317
	if  ((rc = gnutls_certificate_set_ocsp_status_request_file2(
1318
		  state->lib_state.x509_cred, CCS ofile, gnutls_cert_index,
1319
		  ocsp_fmt)) < 0)
1320
	  return tls_error_gnu(state,
1321
		  US"gnutls_certificate_set_ocsp_status_request_file2",
1322
		  rc, errstr);
1323
	DEBUG(D_tls)
1324
	  debug_printf(" %d response%s loaded\n", rc, rc>1 ? "s":"");
1325
1326
	/* Arrange callbacks for OCSP request observability */
1327
1328
	if (state->session)
1329
	  gnutls_handshake_set_hook_function(state->session,
1330
	    GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST, tls_server_hook_cb);
1331
	else
1332
	  state->lib_state.ocsp_hook = TRUE;
1333
1334
1335
# else
1336
#  if defined(SUPPORT_SRV_OCSP_STACK)
1337
	if ((rc = gnutls_certificate_set_ocsp_status_request_function2(
1338
		     state->lib_state.x509_cred, gnutls_cert_index,
1339
		     server_ocsp_stapling_cb, ofile)))
1340
	    return tls_error_gnu(state,
1341
		  US"gnutls_certificate_set_ocsp_status_request_function2",
1342
		  rc, errstr);
1343
	else
1344
#  endif
1345
	  {
1346
	  if (cnt++ > 0)
1347
	    {
1348
	    DEBUG(D_tls)
1349
	      debug_printf("oops; multiple OCSP files not supported\n");
1350
	    break;
1351
	    }
1352
	  gnutls_certificate_set_ocsp_status_request_function(
1353
	    state->lib_state.x509_cred, server_ocsp_stapling_cb, ofile);
1354
	  }
1355
# endif	/* SUPPORT_GNUTLS_EXT_RAW_PARSE */
1356
	}
1357
      else
1358
	DEBUG(D_tls) debug_printf("ran out of OCSP response files in list\n");
1359
      }
1360
#endif /* DISABLE_OCSP */
1361
    }
1362
return 0;
1363
}
1364
1365
static int
1366
creds_load_client_certs(exim_gnutls_state_st * state, const host_item * host,
1367
  const uschar * cert, const uschar * pkey, uschar ** errstr)
1368
{
1369
int rc = tls_add_certfile(state, host, cert, pkey, errstr);
1370
if (rc > 0) return rc;
1371
DEBUG(D_tls) debug_printf("TLS: cert/key registered\n");
1372
return 0;
1373
}
1374
1375
static int
1376
creds_load_cabundle(exim_gnutls_state_st * state, const uschar * bundle,
1377
  const host_item * host, uschar ** errstr)
1378
{
1379
int cert_count;
1380
struct stat statbuf;
1381
1382
#ifdef SUPPORT_SYSDEFAULT_CABUNDLE
1383
if (Ustrcmp(bundle, "system") == 0 || Ustrncmp(bundle, "system,", 7) == 0)
1384
  cert_count = gnutls_certificate_set_x509_system_trust(state->lib_state.x509_cred);
1385
else
1386
#endif
1387
  {
1388
  if (Ustat(bundle, &statbuf) < 0)
1389
    {
1390
    log_write(0, LOG_MAIN|LOG_PANIC, "could not stat '%s' "
1391
	"(tls_verify_certificates): %s", bundle, strerror(errno));
1392
    return DEFER;
1393
    }
1394
1395
#ifndef SUPPORT_CA_DIR
1396
  /* The test suite passes in /dev/null; we could check for that path explicitly,
1397
  but who knows if someone has some weird FIFO which always dumps some certs, or
1398
  other weirdness.  The thing we really want to check is that it's not a
1399
  directory, since while OpenSSL supports that, GnuTLS does not.
1400
  So s/!S_ISREG/S_ISDIR/ and change some messaging ... */
1401
  if (S_ISDIR(statbuf.st_mode))
1402
    {
1403
    log_write(0, LOG_MAIN|LOG_PANIC,
1404
	"tls_verify_certificates \"%s\" is a directory", bundle);
1405
    return DEFER;
1406
    }
1407
#endif
1408
1409
  DEBUG(D_tls) debug_printf("verify certificates = %s size=" OFF_T_FMT "\n",
1410
	  bundle, statbuf.st_size);
1411
1412
  if (statbuf.st_size == 0)
1413
    {
1414
    DEBUG(D_tls)
1415
      debug_printf("cert file empty, no certs, no verification, ignoring any CRL\n");
1416
    return OK;
1417
    }
1418
1419
  cert_count =
1420
1421
#ifdef SUPPORT_CA_DIR
1422
    (statbuf.st_mode & S_IFMT) == S_IFDIR
1423
    ?
1424
    gnutls_certificate_set_x509_trust_dir(state->lib_state.x509_cred,
1425
      CS bundle, GNUTLS_X509_FMT_PEM)
1426
    :
1427
#endif
1428
    gnutls_certificate_set_x509_trust_file(state->lib_state.x509_cred,
1429
      CS bundle, GNUTLS_X509_FMT_PEM);
1430
1431
#ifdef SUPPORT_CA_DIR
1432
  /* Mimic the behaviour with OpenSSL of not advertising a usable-cert list
1433
  when using the directory-of-certs config model. */
1434
1435
  if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
1436
    if (state->session)
1437
      gnutls_certificate_send_x509_rdn_sequence(state->session, 1);
1438
    else
1439
      state->lib_state.ca_rdn_emulate = TRUE;
1440
#endif
1441
  }
1442
1443
if (cert_count < 0)
1444
  return tls_error_gnu(state, US"setting certificate trust", cert_count, errstr);
1445
DEBUG(D_tls)
1446
  debug_printf("Added %d certificate authorities\n", cert_count);
1447
1448
return OK;
1449
}
1450
1451
1452
static int
1453
creds_load_crl(exim_gnutls_state_st * state, const uschar * crl, uschar ** errstr)
1454
{
1455
int cert_count;
1456
DEBUG(D_tls) debug_printf("loading CRL file = %s\n", crl);
1457
if ((cert_count = gnutls_certificate_set_x509_crl_file(state->lib_state.x509_cred,
1458
    CS crl, GNUTLS_X509_FMT_PEM)) < 0)
1459
  return tls_error_gnu(state, US"gnutls_certificate_set_x509_crl_file",
1460
	    cert_count, errstr);
1461
1462
DEBUG(D_tls) debug_printf("Processed %d CRLs\n", cert_count);
1463
return OK;
1464
}
1465
1466
1467
static int
1468
creds_load_pristring(exim_gnutls_state_st * state, const uschar * p,
1469
  const char ** errpos)
1470
{
1471
if (!p)
1472
  {
1473
  p = exim_default_gnutls_priority;
1474
  DEBUG(D_tls)
1475
    debug_printf("GnuTLS using default session cipher/priority \"%s\"\n", p);
1476
  }
1477
return gnutls_priority_init( (gnutls_priority_t *) &state->lib_state.pri_cache,
1478
  CCS p, errpos);
1479
}
1480
1481
static unsigned
1482
tls_server_creds_init(void)
1483
{
1484
uschar * dummy_errstr;
1485
unsigned lifetime = 0;
1486
1487
state_server.lib_state = null_tls_preload;
1488
if (gnutls_certificate_allocate_credentials(
1489
      (gnutls_certificate_credentials_t *) &state_server.lib_state.x509_cred))
1490
  {
1491
  state_server.lib_state.x509_cred = NULL;
1492
  return lifetime;
1493
  }
1494
creds_basic_init(state_server.lib_state.x509_cred, TRUE);
1495
1496
#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
1497
/* If tls_certificate has any $ indicating expansions, it is not good.
1498
If tls_privatekey is set but has $, not good.  Likewise for tls_ocsp_file.
1499
If all good (and tls_certificate set), load the cert(s). */
1500
1501
if (  opt_set_and_noexpand(tls_certificate)
1502
# ifndef DISABLE_OCSP
1503
   && opt_unset_or_noexpand(tls_ocsp_file)
1504
# endif
1505
   && opt_unset_or_noexpand(tls_privatekey))
1506
  {
1507
  /* Set watches on the filenames.  The implementation does de-duplication
1508
  so we can just blindly do them all.
1509
  */
1510
1511
  if (  tls_set_watch(tls_certificate, TRUE)
1512
# ifndef DISABLE_OCSP
1513
     && tls_set_watch(tls_ocsp_file, TRUE)
1514
# endif
1515
     && tls_set_watch(tls_privatekey, TRUE))
1516
    {
1517
    DEBUG(D_tls) debug_printf("TLS: preloading server certs\n");
1518
    if (creds_load_server_certs(&state_server, tls_certificate,
1519
	  tls_privatekey && *tls_privatekey ? tls_privatekey : tls_certificate,
1520
# ifdef DISABLE_OCSP
1521
	  NULL,
1522
# else
1523
	  tls_ocsp_file,
1524
# endif
1525
	  &dummy_errstr) == 0)
1526
      state_server.lib_state.conn_certs = TRUE;
1527
    }
1528
  }
1529
else if (  !tls_certificate && !tls_privatekey
1530
# ifndef DISABLE_OCSP
1531
	&& !tls_ocsp_file
1532
# endif
1533
	)
1534
  {		/* Generate & preload a selfsigned cert. No files to watch. */
1535
  if ((tls_install_selfsign(&state_server, &dummy_errstr)) == OK)
1536
    {
1537
    state_server.lib_state.conn_certs = TRUE;
1538
    lifetime = f.running_in_test_harness ? 2 : 60 * 60;		/* 1 hour */
1539
    }
1540
  }
1541
else
1542
  DEBUG(D_tls) debug_printf("TLS: not preloading server certs\n");
1543
1544
/* If tls_verify_certificates is non-empty and has no $, load CAs.
1545
If none was configured and we can't handle "system", treat as empty. */
1546
1547
if (  opt_set_and_noexpand(tls_verify_certificates)
1548
#ifndef SUPPORT_SYSDEFAULT_CABUNDLE
1549
   && Ustrcmp(tls_verify_certificates, "system") != 0
1550
#endif
1551
   )
1552
  {
1553
  if (tls_set_watch(tls_verify_certificates, FALSE))
1554
    {
1555
    DEBUG(D_tls) debug_printf("TLS: preloading CA bundle for server\n");
1556
    if (creds_load_cabundle(&state_server, tls_verify_certificates,
1557
			    NULL, &dummy_errstr) != OK)
1558
      return lifetime;
1559
    state_server.lib_state.cabundle = TRUE;
1560
1561
    /* If CAs loaded and tls_crl is non-empty and has no $, load it */
1562
1563
    if (opt_set_and_noexpand(tls_crl))
1564
      {
1565
      if (tls_set_watch(tls_crl, FALSE))
1566
	{
1567
	DEBUG(D_tls) debug_printf("TLS: preloading CRL for server\n");
1568
	if (creds_load_crl(&state_server, tls_crl, &dummy_errstr) != OK)
1569
	  return lifetime;
1570
	state_server.lib_state.crl = TRUE;
1571
	}
1572
      }
1573
    else
1574
      DEBUG(D_tls) debug_printf("TLS: not preloading CRL for server\n");
1575
    }
1576
  }
1577
else
1578
  DEBUG(D_tls) debug_printf("TLS: not preloading CA bundle for server\n");
1579
#endif	/* EXIM_HAVE_INOTIFY */
1580
1581
/* If tls_require_ciphers is non-empty and has no $, load the
1582
ciphers priority cache.  If unset, load with the default.
1583
(server-only as the client one depends on non/DANE) */
1584
1585
if (!tls_require_ciphers || opt_set_and_noexpand(tls_require_ciphers))
1586
  {
1587
  const char * dummy_errpos;
1588
  DEBUG(D_tls) debug_printf("TLS: preloading cipher list for server: %s\n",
1589
		  tls_require_ciphers);
1590
  if (  creds_load_pristring(&state_server, tls_require_ciphers, &dummy_errpos)
1591
     == OK)
1592
    state_server.lib_state.pri_string = TRUE;
1593
  }
1594
else
1595
  DEBUG(D_tls) debug_printf("TLS: not preloading cipher list for server\n");
1596
return lifetime;
1597
}
1598
1599
1600
/* Preload whatever creds are static, onto a transport.  The client can then
1601
just copy the pointer as it starts up. */
1602
1603
/*XXX this is not called for a cmdline send. But one needing to use >1 conn would benefit,
1604
and there seems little downside. */
1605
1606
static void
1607
tls_client_creds_init(transport_instance * t, BOOL watch)
1608
{
1609
smtp_transport_options_block * ob = t->options_block;
1610
exim_gnutls_state_st tpt_dummy_state;
1611
host_item * dummy_host = (host_item *)1;
1612
uschar * dummy_errstr;
1613
1614
if (  !exim_gnutls_base_init_done
1615
   && tls_g_init(&dummy_errstr) != OK)
1616
  return;
1617
1618
ob->tls_preload = null_tls_preload;
1619
if (gnutls_certificate_allocate_credentials(
1620
  (struct gnutls_certificate_credentials_st **)&ob->tls_preload.x509_cred))
1621
  {
1622
  ob->tls_preload.x509_cred = NULL;
1623
  return;
1624
  }
1625
creds_basic_init(ob->tls_preload.x509_cred, FALSE);
1626
1627
tpt_dummy_state.session = NULL;
1628
tpt_dummy_state.lib_state = ob->tls_preload;
1629
1630
#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
1631
if (  opt_set_and_noexpand(ob->tls_certificate)
1632
   && opt_unset_or_noexpand(ob->tls_privatekey))
1633
  {
1634
  if (  !watch
1635
     || (  tls_set_watch(ob->tls_certificate, FALSE)
1636
	&& tls_set_watch(ob->tls_privatekey, FALSE)
1637
     )  )
1638
    {
1639
    const uschar * pkey = ob->tls_privatekey;
1640
1641
    DEBUG(D_tls)
1642
      debug_printf("TLS: preloading client certs for transport '%s'\n", t->name);
1643
1644
    /* The state->lib_state.x509_cred is used for the certs load, and is the sole
1645
    structure element used.  So we can set up a dummy.  The hoat arg only
1646
    selects a retcode in case of fail, so any value */
1647
1648
    if (creds_load_client_certs(&tpt_dummy_state, dummy_host,
1649
	  ob->tls_certificate, pkey ? pkey : ob->tls_certificate,
1650
	  &dummy_errstr) == OK)
1651
      ob->tls_preload.conn_certs = TRUE;
1652
    }
1653
  }
1654
else
1655
  DEBUG(D_tls)
1656
    debug_printf("TLS: not preloading client certs, for transport '%s'\n", t->name);
1657
1658
/* If tls_verify_certificates is non-empty and has no $, load CAs.
1659
If none was configured and we can't handle "system", treat as empty. */
1660
1661
if (  opt_set_and_noexpand(ob->tls_verify_certificates)
1662
#ifndef SUPPORT_SYSDEFAULT_CABUNDLE
1663
   && Ustrcmp(ob->tls_verify_certificates, "system") != 0
1664
#endif
1665
   )
1666
  {
1667
  if (!watch || tls_set_watch(ob->tls_verify_certificates, FALSE))
1668
    {
1669
    DEBUG(D_tls)
1670
      debug_printf("TLS: preloading CA bundle for transport '%s'\n", t->name);
1671
    if (creds_load_cabundle(&tpt_dummy_state, ob->tls_verify_certificates,
1672
			    dummy_host, &dummy_errstr) != OK)
1673
      return;
1674
    ob->tls_preload.cabundle = TRUE;
1675
1676
    if (opt_set_and_noexpand(ob->tls_crl))
1677
      {
1678
      if (!watch || tls_set_watch(ob->tls_crl, FALSE))
1679
	{
1680
	DEBUG(D_tls) debug_printf("TLS: preloading CRL for transport '%s'\n", t->name);
1681
	if (creds_load_crl(&tpt_dummy_state, ob->tls_crl, &dummy_errstr) != OK)
1682
	  return;
1683
	ob->tls_preload.crl = TRUE;
1684
	}
1685
      }
1686
    else
1687
      DEBUG(D_tls) debug_printf("TLS: not preloading CRL, for transport '%s'\n", t->name);
1688
    }
1689
  }
1690
else
1691
  DEBUG(D_tls)
1692
      debug_printf("TLS: not preloading CA bundle, for transport '%s'\n", t->name);
1693
1694
/* We do not preload tls_require_ciphers to to the transport as it implicitly
1695
depends on DANE or plain usage. */
1696
1697
#endif
1698
}
1699
1700
1701
#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
1702
/* Invalidate the creds cached, by dropping the current ones.
1703
Call when we notice one of the source files has changed. */
1704
 
1705
static void
1706
tls_server_creds_invalidate(void)
1707
{
1708
if (state_server.lib_state.pri_cache)
1709
  gnutls_priority_deinit(state_server.lib_state.pri_cache);
1710
state_server.lib_state.pri_cache = NULL;
1711
1712
if (state_server.lib_state.x509_cred)
1713
  gnutls_certificate_free_credentials(state_server.lib_state.x509_cred);
1714
state_server.lib_state = null_tls_preload;
1715
}
1716
1717
1718
static void
1719
tls_client_creds_invalidate(transport_instance * t)
1720
{
1721
smtp_transport_options_block * ob = t->options_block;
1722
if (ob->tls_preload.x509_cred)
1723
  gnutls_certificate_free_credentials(ob->tls_preload.x509_cred);
1724
ob->tls_preload = null_tls_preload;
1725
}
1726
#endif
1727
1728
1066
/*************************************************
1729
/*************************************************
1067
*       Variables re-expanded post-SNI           *
1730
*       Variables re-expanded post-SNI           *
1068
*************************************************/
1731
*************************************************/
Lines 1085-1097 Link Here
1085
static int
1748
static int
1086
tls_expand_session_files(exim_gnutls_state_st * state, uschar ** errstr)
1749
tls_expand_session_files(exim_gnutls_state_st * state, uschar ** errstr)
1087
{
1750
{
1088
struct stat statbuf;
1089
int rc;
1751
int rc;
1090
const host_item *host = state->host;  /* macro should be reconsidered? */
1752
const host_item *host = state->host;  /* macro should be reconsidered? */
1091
uschar *saved_tls_certificate = NULL;
1753
const uschar *saved_tls_certificate = NULL;
1092
uschar *saved_tls_privatekey = NULL;
1754
const uschar *saved_tls_privatekey = NULL;
1093
uschar *saved_tls_verify_certificates = NULL;
1755
const uschar *saved_tls_verify_certificates = NULL;
1094
uschar *saved_tls_crl = NULL;
1756
const uschar *saved_tls_crl = NULL;
1095
int cert_count;
1757
int cert_count;
1096
1758
1097
/* We check for tls_sni *before* expansion. */
1759
/* We check for tls_sni *before* expansion. */
Lines 1104-1114 Link Here
1104
	  || Ustrstr(state->tls_certificate, US"tls_out_sni")
1766
	  || Ustrstr(state->tls_certificate, US"tls_out_sni")
1105
       )  )
1767
       )  )
1106
      {
1768
      {
1107
      DEBUG(D_tls) debug_printf("We will re-expand TLS session files if we receive SNI.\n");
1769
      DEBUG(D_tls) debug_printf("We will re-expand TLS session files if we receive SNI\n");
1108
      state->trigger_sni_changes = TRUE;
1770
      state->trigger_sni_changes = TRUE;
1109
      }
1771
      }
1110
    }
1772
    }
1111
  else
1773
  else	/* SNI callback case */
1112
    {
1774
    {
1113
    /* useful for debugging */
1775
    /* useful for debugging */
1114
    saved_tls_certificate = state->exp_tls_certificate;
1776
    saved_tls_certificate = state->exp_tls_certificate;
Lines 1117-1410 Link Here
1117
    saved_tls_crl = state->exp_tls_crl;
1779
    saved_tls_crl = state->exp_tls_crl;
1118
    }
1780
    }
1119
1781
1120
if ((rc = gnutls_certificate_allocate_credentials(&state->x509_cred)))
1782
if (!state->lib_state.x509_cred)
1121
  return tls_error_gnu(US"gnutls_certificate_allocate_credentials",
1122
	    rc, host, errstr);
1123
1124
#ifdef SUPPORT_SRV_OCSP_STACK
1125
gnutls_certificate_set_flags(state->x509_cred, GNUTLS_CERTIFICATE_API_V2);
1126
1127
# if !defined(DISABLE_OCSP) && defined(SUPPORT_GNUTLS_EXT_RAW_PARSE)
1128
if (!host && tls_ocsp_file)
1129
  {
1783
  {
1130
  if (f.running_in_test_harness)
1784
  if ((rc = gnutls_certificate_allocate_credentials(
1131
    tls_server_testharness_ocsp_fiddle();
1785
	(gnutls_certificate_credentials_t *) &state->lib_state.x509_cred)))
1132
1786
    return tls_error_gnu(state, US"gnutls_certificate_allocate_credentials",
1133
  if (exim_testharness_disable_ocsp_validity_check)
1787
	    rc, errstr);
1134
    gnutls_certificate_set_flags(state->x509_cred,
1788
  creds_basic_init(state->lib_state.x509_cred, !host);
1135
      GNUTLS_CERTIFICATE_API_V2 | GNUTLS_CERTIFICATE_SKIP_OCSP_RESPONSE_CHECK);
1136
  }
1789
  }
1137
# endif
1138
#endif
1139
1790
1140
/* remember: expand_check_tlsvar() is expand_check() but fiddling with
1791
1792
/* remember: Expand_check_tlsvar() is expand_check() but fiddling with
1141
state members, assuming consistent naming; and expand_check() returns
1793
state members, assuming consistent naming; and expand_check() returns
1142
false if expansion failed, unless expansion was forced to fail. */
1794
false if expansion failed, unless expansion was forced to fail. */
1143
1795
1144
/* check if we at least have a certificate, before doing expensive
1796
/* check if we at least have a certificate, before doing expensive
1145
D-H generation. */
1797
D-H generation. */
1146
1798
1147
if (!expand_check_tlsvar(tls_certificate, errstr))
1799
if (!state->lib_state.conn_certs)
1148
  return DEFER;
1149
1150
/* certificate is mandatory in server, optional in client */
1151
1152
if (  !state->exp_tls_certificate
1153
   || !*state->exp_tls_certificate
1154
   )
1155
  if (!host)
1156
    return tls_install_selfsign(state, errstr);
1157
  else
1158
    DEBUG(D_tls) debug_printf("TLS: no client certificate specified; okay\n");
1159
1160
if (state->tls_privatekey && !expand_check_tlsvar(tls_privatekey, errstr))
1161
  return DEFER;
1162
1163
/* tls_privatekey is optional, defaulting to same file as certificate */
1164
1165
if (!state->tls_privatekey || !*state->tls_privatekey)
1166
  {
1800
  {
1167
  state->tls_privatekey = state->tls_certificate;
1801
  if (!Expand_check_tlsvar(tls_certificate, errstr))
1168
  state->exp_tls_privatekey = state->exp_tls_certificate;
1802
    return DEFER;
1169
  }
1170
1171
1803
1172
if (state->exp_tls_certificate && *state->exp_tls_certificate)
1804
  /* certificate is mandatory in server, optional in client */
1173
  {
1174
  DEBUG(D_tls) debug_printf("certificate file = %s\nkey file = %s\n",
1175
      state->exp_tls_certificate, state->exp_tls_privatekey);
1176
1805
1177
  if (state->received_sni)
1806
  if (  !state->exp_tls_certificate
1178
    if (  Ustrcmp(state->exp_tls_certificate, saved_tls_certificate) == 0
1807
     || !*state->exp_tls_certificate
1179
       && Ustrcmp(state->exp_tls_privatekey,  saved_tls_privatekey)  == 0
1808
     )
1180
       )
1809
    if (!host)
1181
      {
1810
      return tls_install_selfsign(state, errstr);
1182
      DEBUG(D_tls) debug_printf("TLS SNI: cert and key unchanged\n");
1183
      }
1184
    else
1811
    else
1185
      {
1812
      DEBUG(D_tls) debug_printf("TLS: no client certificate specified; okay\n");
1186
      DEBUG(D_tls) debug_printf("TLS SNI: have a changed cert/key pair.\n");
1187
      }
1188
1189
  if (!host)	/* server */
1190
    {
1191
    const uschar * clist = state->exp_tls_certificate;
1192
    const uschar * klist = state->exp_tls_privatekey;
1193
    const uschar * olist;
1194
    int csep = 0, ksep = 0, osep = 0, cnt = 0;
1195
    uschar * cfile, * kfile, * ofile;
1196
#ifndef DISABLE_OCSP
1197
# ifdef SUPPORT_GNUTLS_EXT_RAW_PARSE
1198
    gnutls_x509_crt_fmt_t ocsp_fmt = GNUTLS_X509_FMT_DER;
1199
# endif
1200
1813
1201
    if (!expand_check(tls_ocsp_file, US"tls_ocsp_file", &ofile, errstr))
1814
  if (state->tls_privatekey && !Expand_check_tlsvar(tls_privatekey, errstr))
1202
      return DEFER;
1815
    return DEFER;
1203
    olist = ofile;
1204
#endif
1205
1206
    while (cfile = string_nextinlist(&clist, &csep, NULL, 0))
1207
1816
1208
      if (!(kfile = string_nextinlist(&klist, &ksep, NULL, 0)))
1817
  /* tls_privatekey is optional, defaulting to same file as certificate */
1209
	return tls_error(US"cert/key setup: out of keys", NULL, host, errstr);
1210
      else if (0 < (rc = tls_add_certfile(state, host, cfile, kfile, errstr)))
1211
	return rc;
1212
      else
1213
	{
1214
	int gnutls_cert_index = -rc;
1215
	DEBUG(D_tls) debug_printf("TLS: cert/key %d %s registered\n",
1216
				  gnutls_cert_index, cfile);
1217
1818
1218
#ifndef DISABLE_OCSP
1819
  if (!state->tls_privatekey || !*state->tls_privatekey)
1219
	if (tls_ocsp_file)
1820
    {
1220
	  {
1821
    state->tls_privatekey = state->tls_certificate;
1221
	  /* Set the OCSP stapling server info */
1822
    state->exp_tls_privatekey = state->exp_tls_certificate;
1222
	  if (gnutls_buggy_ocsp)
1823
    }
1223
	    {
1224
	    DEBUG(D_tls)
1225
	      debug_printf("GnuTLS library is buggy for OCSP; avoiding\n");
1226
	    }
1227
	  else if ((ofile = string_nextinlist(&olist, &osep, NULL, 0)))
1228
	    {
1229
	    DEBUG(D_tls) debug_printf("OCSP response file %d  = %s\n",
1230
				      gnutls_cert_index, ofile);
1231
# ifdef SUPPORT_GNUTLS_EXT_RAW_PARSE
1232
	    if (Ustrncmp(ofile, US"PEM ", 4) == 0)
1233
	      {
1234
	      ocsp_fmt = GNUTLS_X509_FMT_PEM;
1235
	      ofile += 4;
1236
	      }
1237
	    else if (Ustrncmp(ofile, US"DER ", 4) == 0)
1238
	      {
1239
	      ocsp_fmt = GNUTLS_X509_FMT_DER;
1240
	      ofile += 4;
1241
	      }
1242
1243
	    if  ((rc = gnutls_certificate_set_ocsp_status_request_file2(
1244
		      state->x509_cred, CCS ofile, gnutls_cert_index,
1245
		      ocsp_fmt)) < 0)
1246
	      return tls_error_gnu(
1247
		      US"gnutls_certificate_set_ocsp_status_request_file2",
1248
		      rc, host, errstr);
1249
	    DEBUG(D_tls)
1250
	      debug_printf(" %d response%s loaded\n", rc, rc>1 ? "s":"");
1251
1252
	    /* Arrange callbacks for OCSP request observability */
1253
1824
1254
	    gnutls_handshake_set_hook_function(state->session,
1825
  if (state->exp_tls_certificate && *state->exp_tls_certificate)
1255
	      GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST, tls_server_hook_cb);
1826
    {
1827
    BOOL load = TRUE;
1828
    DEBUG(D_tls) debug_printf("certificate file = %s\nkey file = %s\n",
1829
	state->exp_tls_certificate, state->exp_tls_privatekey);
1256
1830
1257
# else
1831
    if (state->received_sni)
1258
#  if defined(SUPPORT_SRV_OCSP_STACK)
1832
      if (  Ustrcmp(state->exp_tls_certificate, saved_tls_certificate) == 0
1259
	    if ((rc = gnutls_certificate_set_ocsp_status_request_function2(
1833
	 && Ustrcmp(state->exp_tls_privatekey,  saved_tls_privatekey)  == 0
1260
			 state->x509_cred, gnutls_cert_index,
1834
	 )
1261
			 server_ocsp_stapling_cb, ofile)))
1835
	{
1262
		return tls_error_gnu(
1836
	DEBUG(D_tls) debug_printf("TLS SNI: cert and key unchanged\n");
1263
		      US"gnutls_certificate_set_ocsp_status_request_function2",
1837
	load = FALSE;	/* avoid re-loading the same certs */
1264
		      rc, host, errstr);
1265
	    else
1266
#  endif
1267
	      {
1268
	      if (cnt++ > 0)
1269
		{
1270
		DEBUG(D_tls)
1271
		  debug_printf("oops; multiple OCSP files not supported\n");
1272
		break;
1273
		}
1274
	      gnutls_certificate_set_ocsp_status_request_function(
1275
		state->x509_cred, server_ocsp_stapling_cb, ofile);
1276
	      }
1277
# endif	/* SUPPORT_GNUTLS_EXT_RAW_PARSE */
1278
	    }
1279
	  else
1280
	    DEBUG(D_tls) debug_printf("ran out of OCSP response files in list\n");
1281
	  }
1282
#endif /* DISABLE_OCSP */
1283
	}
1838
	}
1839
      else		/* unload the pre-SNI certs before loading new ones */
1840
	{
1841
	DEBUG(D_tls) debug_printf("TLS SNI: have a changed cert/key pair\n");
1842
	gnutls_certificate_free_keys(state->lib_state.x509_cred);
1843
	}
1844
1845
    if (  load
1846
       && (rc = host
1847
	  ? creds_load_client_certs(state, host, state->exp_tls_certificate,
1848
			      state->exp_tls_privatekey, errstr)
1849
	  : creds_load_server_certs(state, state->exp_tls_certificate,
1850
			      state->exp_tls_privatekey,
1851
#ifdef DISABLE_OCSP
1852
			      NULL,
1853
#else
1854
			      tls_ocsp_file,
1855
#endif
1856
			      errstr)
1857
       )  ) return rc;
1284
    }
1858
    }
1285
  else	/* client */
1859
  }
1286
    {
1860
else
1287
    if (0 < (rc = tls_add_certfile(state, host,
1861
  {
1288
		state->exp_tls_certificate, state->exp_tls_privatekey, errstr)))
1862
  DEBUG(D_tls)
1289
      return rc;
1863
    debug_printf("%s certs were preloaded\n", host ? "client" : "server");
1290
    DEBUG(D_tls) debug_printf("TLS: cert/key registered\n");
1864
1291
    }
1865
  if (!state->tls_privatekey) state->tls_privatekey = state->tls_certificate;
1866
  state->exp_tls_certificate = US state->tls_certificate;
1867
  state->exp_tls_privatekey = US state->tls_privatekey;
1292
1868
1293
  } /* tls_certificate */
1869
#ifdef SUPPORT_GNUTLS_EXT_RAW_PARSE
1870
  if (state->lib_state.ocsp_hook)
1871
     gnutls_handshake_set_hook_function(state->session,
1872
       GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST, tls_server_hook_cb);
1873
#endif
1874
  }
1294
1875
1295
1876
1296
/* Set the trusted CAs file if one is provided, and then add the CRL if one is
1877
/* Set the trusted CAs file if one is provided, and then add the CRL if one is
1297
provided. Experiment shows that, if the certificate file is empty, an unhelpful
1878
provided. Experiment shows that, if the certificate file is empty, an unhelpful
1298
error message is provided. However, if we just refrain from setting anything up
1879
error message is provided. However, if we just refrain from setting anything up
1299
in that case, certificate verification fails, which seems to be the correct
1880
in that case, certificate verification fails, which seems to be the correct
1300
behaviour. */
1881
behaviour.
1882
If none was configured and we can't handle "system", treat as empty. */
1301
1883
1302
if (state->tls_verify_certificates && *state->tls_verify_certificates)
1884
if (!state->lib_state.cabundle)
1303
  {
1885
  {
1304
  if (!expand_check_tlsvar(tls_verify_certificates, errstr))
1886
  if (state->tls_verify_certificates && *state->tls_verify_certificates)
1305
    return DEFER;
1887
    {
1888
    if (!Expand_check_tlsvar(tls_verify_certificates, errstr))
1889
      return DEFER;
1306
#ifndef SUPPORT_SYSDEFAULT_CABUNDLE
1890
#ifndef SUPPORT_SYSDEFAULT_CABUNDLE
1307
  if (Ustrcmp(state->exp_tls_verify_certificates, "system") == 0)
1891
    if (Ustrcmp(state->exp_tls_verify_certificates, "system") == 0)
1308
    state->exp_tls_verify_certificates = NULL;
1892
      state->exp_tls_verify_certificates = NULL;
1309
#endif
1893
#endif
1310
  if (state->tls_crl && *state->tls_crl)
1894
    if (state->tls_crl && *state->tls_crl)
1311
    if (!expand_check_tlsvar(tls_crl, errstr))
1895
      if (!Expand_check_tlsvar(tls_crl, errstr))
1312
      return DEFER;
1896
	return DEFER;
1313
1897
1314
  if (!(state->exp_tls_verify_certificates &&
1898
    if (!(state->exp_tls_verify_certificates &&
1315
        *state->exp_tls_verify_certificates))
1899
	  *state->exp_tls_verify_certificates))
1900
      {
1901
      DEBUG(D_tls)
1902
	debug_printf("TLS: tls_verify_certificates expanded empty, ignoring\n");
1903
      /* With no tls_verify_certificates, we ignore tls_crl too */
1904
      return OK;
1905
      }
1906
    }
1907
  else
1316
    {
1908
    {
1317
    DEBUG(D_tls)
1909
    DEBUG(D_tls)
1318
      debug_printf("TLS: tls_verify_certificates expanded empty, ignoring\n");
1910
      debug_printf("TLS: tls_verify_certificates not set or empty, ignoring\n");
1319
    /* With no tls_verify_certificates, we ignore tls_crl too */
1320
    return OK;
1911
    return OK;
1321
    }
1912
    }
1913
  rc = creds_load_cabundle(state, state->exp_tls_verify_certificates, host, errstr);
1914
  if (rc != OK) return rc;
1322
  }
1915
  }
1323
else
1916
else
1324
  {
1917
  {
1325
  DEBUG(D_tls)
1918
  DEBUG(D_tls)
1326
    debug_printf("TLS: tls_verify_certificates not set or empty, ignoring\n");
1919
    debug_printf("%s CA bundle was preloaded\n", host ? "client" : "server");
1327
  return OK;
1920
  state->exp_tls_verify_certificates = US state->tls_verify_certificates;
1328
  }
1329
1330
#ifdef SUPPORT_SYSDEFAULT_CABUNDLE
1331
if (Ustrcmp(state->exp_tls_verify_certificates, "system") == 0)
1332
  cert_count = gnutls_certificate_set_x509_system_trust(state->x509_cred);
1333
else
1334
#endif
1335
  {
1336
  if (Ustat(state->exp_tls_verify_certificates, &statbuf) < 0)
1337
    {
1338
    log_write(0, LOG_MAIN|LOG_PANIC, "could not stat '%s' "
1339
	"(tls_verify_certificates): %s", state->exp_tls_verify_certificates,
1340
	strerror(errno));
1341
    return DEFER;
1342
    }
1343
1344
#ifndef SUPPORT_CA_DIR
1345
  /* The test suite passes in /dev/null; we could check for that path explicitly,
1346
  but who knows if someone has some weird FIFO which always dumps some certs, or
1347
  other weirdness.  The thing we really want to check is that it's not a
1348
  directory, since while OpenSSL supports that, GnuTLS does not.
1349
  So s/!S_ISREG/S_ISDIR/ and change some messaging ... */
1350
  if (S_ISDIR(statbuf.st_mode))
1351
    {
1352
    DEBUG(D_tls)
1353
      debug_printf("verify certificates path is a dir: \"%s\"\n",
1354
	  state->exp_tls_verify_certificates);
1355
    log_write(0, LOG_MAIN|LOG_PANIC,
1356
	"tls_verify_certificates \"%s\" is a directory",
1357
	state->exp_tls_verify_certificates);
1358
    return DEFER;
1359
    }
1360
#endif
1361
1362
  DEBUG(D_tls) debug_printf("verify certificates = %s size=" OFF_T_FMT "\n",
1363
	  state->exp_tls_verify_certificates, statbuf.st_size);
1364
1365
  if (statbuf.st_size == 0)
1366
    {
1367
    DEBUG(D_tls)
1368
      debug_printf("cert file empty, no certs, no verification, ignoring any CRL\n");
1369
    return OK;
1370
    }
1371
1372
  cert_count =
1373
1374
#ifdef SUPPORT_CA_DIR
1375
    (statbuf.st_mode & S_IFMT) == S_IFDIR
1376
    ?
1377
    gnutls_certificate_set_x509_trust_dir(state->x509_cred,
1378
      CS state->exp_tls_verify_certificates, GNUTLS_X509_FMT_PEM)
1379
    :
1380
#endif
1381
    gnutls_certificate_set_x509_trust_file(state->x509_cred,
1382
      CS state->exp_tls_verify_certificates, GNUTLS_X509_FMT_PEM);
1383
1921
1384
#ifdef SUPPORT_CA_DIR
1922
#ifdef SUPPORT_CA_DIR
1385
  /* Mimic the behaviour with OpenSSL of not advertising a usable-cert list
1923
/* Mimic the behaviour with OpenSSL of not advertising a usable-cert list
1386
  when using the directory-of-certs config model. */
1924
when using the directory-of-certs config model. */
1387
1925
    if (state->lib_state.ca_rdn_emulate)
1388
  if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
1926
      gnutls_certificate_send_x509_rdn_sequence(state->session, 1);
1389
    gnutls_certificate_send_x509_rdn_sequence(state->session, 1);
1390
#endif
1927
#endif
1391
  }
1928
  }
1392
1929
1393
if (cert_count < 0)
1394
  return tls_error_gnu(US"setting certificate trust", cert_count, host, errstr);
1395
DEBUG(D_tls)
1396
  debug_printf("Added %d certificate authorities.\n", cert_count);
1397
1930
1398
if (state->tls_crl && *state->tls_crl &&
1931
if (!state->lib_state.crl)
1399
    state->exp_tls_crl && *state->exp_tls_crl)
1400
  {
1932
  {
1401
  DEBUG(D_tls) debug_printf("loading CRL file = %s\n", state->exp_tls_crl);
1933
  if (  state->tls_crl && *state->tls_crl
1402
  if ((cert_count = gnutls_certificate_set_x509_crl_file(state->x509_cred,
1934
     && state->exp_tls_crl && *state->exp_tls_crl)
1403
      CS state->exp_tls_crl, GNUTLS_X509_FMT_PEM)) < 0)
1935
    return creds_load_crl(state, state->exp_tls_crl, errstr);
1404
    return tls_error_gnu(US"gnutls_certificate_set_x509_crl_file",
1936
  }
1405
	      cert_count, host, errstr);
1937
else
1406
1938
  {
1407
  DEBUG(D_tls) debug_printf("Processed %d CRLs.\n", cert_count);
1939
  DEBUG(D_tls)
1940
      debug_printf("%s CRL was preloaded\n", host ? "client" : "server");
1941
  state->exp_tls_crl = US state->tls_crl;
1408
  }
1942
  }
1409
1943
1410
return OK;
1944
return OK;
Lines 1436-1442 Link Here
1436
int rc;
1970
int rc;
1437
const host_item *host = state->host;  /* macro should be reconsidered? */
1971
const host_item *host = state->host;  /* macro should be reconsidered? */
1438
1972
1439
#ifndef GNUTLS_AUTO_DHPARAMS
1440
/* Create D-H parameters, or read them from the cache file. This function does
1973
/* Create D-H parameters, or read them from the cache file. This function does
1441
its own SMTP error messaging. This only happens for the server, TLS D-H ignores
1974
its own SMTP error messaging. This only happens for the server, TLS D-H ignores
1442
client-side params. */
1975
client-side params. */
Lines 1446-1461 Link Here
1446
  if (!dh_server_params)
1979
  if (!dh_server_params)
1447
    if ((rc = init_server_dh(errstr)) != OK) return rc;
1980
    if ((rc = init_server_dh(errstr)) != OK) return rc;
1448
1981
1449
  /* Unnecessary & discouraged with 3.6.0 or later */
1982
  /* Unnecessary & discouraged with 3.6.0 or later, according to docs.  But without it,
1450
  gnutls_certificate_set_dh_params(state->x509_cred, dh_server_params);
1983
  no DHE- ciphers are advertised. */
1984
  gnutls_certificate_set_dh_params(state->lib_state.x509_cred, dh_server_params);
1451
  }
1985
  }
1452
#endif
1453
1986
1454
/* Link the credentials to the session. */
1987
/* Link the credentials to the session. */
1455
1988
1456
if ((rc = gnutls_credentials_set(state->session,
1989
if ((rc = gnutls_credentials_set(state->session,
1457
	    GNUTLS_CRD_CERTIFICATE, state->x509_cred)))
1990
	    GNUTLS_CRD_CERTIFICATE, state->lib_state.x509_cred)))
1458
  return tls_error_gnu(US"gnutls_credentials_set", rc, host, errstr);
1991
  return tls_error_gnu(state, US"gnutls_credentials_set", rc, errstr);
1459
1992
1460
return OK;
1993
return OK;
1461
}
1994
}
Lines 1465-1511 Link Here
1465
*************************************************/
1998
*************************************************/
1466
1999
1467
2000
1468
#ifndef DISABLE_OCSP
1469
1470
static BOOL
1471
tls_is_buggy_ocsp(void)
1472
{
1473
const uschar * s;
1474
uschar maj, mid, mic;
1475
1476
s = CUS gnutls_check_version(NULL);
1477
maj = atoi(CCS s);
1478
if (maj == 3)
1479
  {
1480
  while (*s && *s != '.') s++;
1481
  mid = atoi(CCS ++s);
1482
  if (mid <= 2)
1483
    return TRUE;
1484
  else if (mid >= 5)
1485
    return FALSE;
1486
  else
1487
    {
1488
    while (*s && *s != '.') s++;
1489
    mic = atoi(CCS ++s);
1490
    return mic <= (mid == 3 ? 16 : 3);
1491
    }
1492
  }
1493
return FALSE;
1494
}
1495
1496
#endif
1497
1498
1499
/* Called from both server and client code. In the case of a server, errors
2001
/* Called from both server and client code. In the case of a server, errors
1500
before actual TLS negotiation return DEFER.
2002
before actual TLS negotiation return DEFER.
1501
2003
1502
Arguments:
2004
Arguments:
1503
  host            connected host, if client; NULL if server
2005
  host            connected host, if client; NULL if server
1504
  certificate     certificate file
2006
  ob		  tranport options block, if client; NULL if server
1505
  privatekey      private key file
1506
  sni             TLS SNI to send, sometimes when client; else NULL
1507
  cas             CA certs file
1508
  crl             CRL file
1509
  require_ciphers tls_require_ciphers setting
2007
  require_ciphers tls_require_ciphers setting
1510
  caller_state    returned state-info structure
2008
  caller_state    returned state-info structure
1511
  errstr	  error string pointer
2009
  errstr	  error string pointer
Lines 1516-1527 Link Here
1516
static int
2014
static int
1517
tls_init(
2015
tls_init(
1518
    const host_item *host,
2016
    const host_item *host,
1519
    const uschar *certificate,
2017
    smtp_transport_options_block * ob,
1520
    const uschar *privatekey,
2018
    const uschar * require_ciphers,
1521
    const uschar *sni,
1522
    const uschar *cas,
1523
    const uschar *crl,
1524
    const uschar *require_ciphers,
1525
    exim_gnutls_state_st **caller_state,
2019
    exim_gnutls_state_st **caller_state,
1526
    tls_support * tlsp,
2020
    tls_support * tlsp,
1527
    uschar ** errstr)
2021
    uschar ** errstr)
Lines 1529-1613 Link Here
1529
exim_gnutls_state_st * state;
2023
exim_gnutls_state_st * state;
1530
int rc;
2024
int rc;
1531
size_t sz;
2025
size_t sz;
1532
const char * errpos;
1533
const uschar * p;
1534
2026
1535
if (!exim_gnutls_base_init_done)
2027
if (  !exim_gnutls_base_init_done
1536
  {
2028
   && (rc = tls_g_init(errstr)) != OK)
1537
  DEBUG(D_tls) debug_printf("GnuTLS global init required.\n");
2029
  return rc;
1538
1539
#if defined(HAVE_GNUTLS_PKCS11) && !defined(GNUTLS_AUTO_PKCS11_MANUAL)
1540
  /* By default, gnutls_global_init will init PKCS11 support in auto mode,
1541
  which loads modules from a config file, which sounds good and may be wanted
1542
  by some sysadmin, but also means in common configurations that GNOME keyring
1543
  environment variables are used and so breaks for users calling mailq.
1544
  To prevent this, we init PKCS11 first, which is the documented approach. */
1545
  if (!gnutls_allow_auto_pkcs11)
1546
    if ((rc = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL)))
1547
      return tls_error_gnu(US"gnutls_pkcs11_init", rc, host, errstr);
1548
#endif
1549
1550
#ifndef GNUTLS_AUTO_GLOBAL_INIT
1551
  if ((rc = gnutls_global_init()))
1552
    return tls_error_gnu(US"gnutls_global_init", rc, host, errstr);
1553
#endif
1554
1555
#if EXIM_GNUTLS_LIBRARY_LOG_LEVEL >= 0
1556
  DEBUG(D_tls)
1557
    {
1558
    gnutls_global_set_log_function(exim_gnutls_logger_cb);
1559
    /* arbitrarily chosen level; bump up to 9 for more */
1560
    gnutls_global_set_log_level(EXIM_GNUTLS_LIBRARY_LOG_LEVEL);
1561
    }
1562
#endif
1563
1564
#ifndef DISABLE_OCSP
1565
  if (tls_ocsp_file && (gnutls_buggy_ocsp = tls_is_buggy_ocsp()))
1566
    log_write(0, LOG_MAIN, "OCSP unusable with this GnuTLS library version");
1567
#endif
1568
1569
  exim_gnutls_base_init_done = TRUE;
1570
  }
1571
2030
1572
if (host)
2031
if (host)
1573
  {
2032
  {
1574
  /* For client-side sessions we allocate a context. This lets us run
2033
  /* For client-side sessions we allocate a context. This lets us run
1575
  several in parallel. */
2034
  several in parallel. */
2035
1576
  int old_pool = store_pool;
2036
  int old_pool = store_pool;
1577
  store_pool = POOL_PERM;
2037
  store_pool = POOL_PERM;
1578
  state = store_get(sizeof(exim_gnutls_state_st), FALSE);
2038
  state = store_get(sizeof(exim_gnutls_state_st), GET_UNTAINTED);
1579
  store_pool = old_pool;
2039
  store_pool = old_pool;
1580
2040
1581
  memcpy(state, &exim_gnutls_state_init, sizeof(exim_gnutls_state_init));
2041
  memcpy(state, &exim_gnutls_state_init, sizeof(exim_gnutls_state_init));
2042
  state->lib_state = ob->tls_preload;
1582
  state->tlsp = tlsp;
2043
  state->tlsp = tlsp;
1583
  DEBUG(D_tls) debug_printf("initialising GnuTLS client session\n");
2044
  DEBUG(D_tls) debug_printf("initialising GnuTLS client session\n");
1584
  rc = gnutls_init(&state->session, GNUTLS_CLIENT);
2045
  rc = gnutls_init(&state->session, GNUTLS_CLIENT);
2046
2047
  state->tls_certificate =	ob->tls_certificate;
2048
  state->tls_privatekey =	ob->tls_privatekey;
2049
  state->tls_sni =		ob->tls_sni;
2050
  state->tls_verify_certificates = ob->tls_verify_certificates;
2051
  state->tls_crl =		ob->tls_crl;
1585
  }
2052
  }
1586
else
2053
else
1587
  {
2054
  {
2055
  /* Server operations always use the one state_server context.  It is not
2056
  shared because we have forked a fresh process for every receive.  However it
2057
  can get re-used for successive TLS sessions on a single TCP connection. */
2058
1588
  state = &state_server;
2059
  state = &state_server;
1589
  memcpy(state, &exim_gnutls_state_init, sizeof(exim_gnutls_state_init));
1590
  state->tlsp = tlsp;
2060
  state->tlsp = tlsp;
1591
  DEBUG(D_tls) debug_printf("initialising GnuTLS server session\n");
2061
  DEBUG(D_tls) debug_printf("initialising GnuTLS server session\n");
1592
  rc = gnutls_init(&state->session, GNUTLS_SERVER);
2062
  rc = gnutls_init(&state->session, GNUTLS_SERVER);
2063
2064
  state->tls_certificate =	tls_certificate;
2065
  state->tls_privatekey =	tls_privatekey;
2066
  state->tls_sni =		NULL;
2067
  state->tls_verify_certificates = tls_verify_certificates;
2068
  state->tls_crl =		tls_crl;
1593
  }
2069
  }
1594
if (rc)
2070
if (rc)
1595
  return tls_error_gnu(US"gnutls_init", rc, host, errstr);
2071
  return tls_error_gnu(state, US"gnutls_init", rc, errstr);
1596
2072
2073
state->tls_require_ciphers =	require_ciphers;
1597
state->host = host;
2074
state->host = host;
1598
2075
1599
state->tls_certificate = certificate;
1600
state->tls_privatekey = privatekey;
1601
state->tls_require_ciphers = require_ciphers;
1602
state->tls_sni = sni;
1603
state->tls_verify_certificates = cas;
1604
state->tls_crl = crl;
1605
1606
/* This handles the variables that might get re-expanded after TLS SNI;
2076
/* This handles the variables that might get re-expanded after TLS SNI;
1607
that's tls_certificate, tls_privatekey, tls_verify_certificates, tls_crl */
2077
tls_certificate, tls_privatekey, tls_verify_certificates, tls_crl */
1608
2078
1609
DEBUG(D_tls)
2079
DEBUG(D_tls)
1610
  debug_printf("Expanding various TLS configuration options for session credentials.\n");
2080
  debug_printf("Expanding various TLS configuration options for session credentials\n");
1611
if ((rc = tls_expand_session_files(state, errstr)) != OK) return rc;
2081
if ((rc = tls_expand_session_files(state, errstr)) != OK) return rc;
1612
2082
1613
/* These are all other parts of the x509_cred handling, since SNI in GnuTLS
2083
/* These are all other parts of the x509_cred handling, since SNI in GnuTLS
Lines 1618-1624 Link Here
1618
/* set SNI in client, only */
2088
/* set SNI in client, only */
1619
if (host)
2089
if (host)
1620
  {
2090
  {
1621
  if (!expand_check(sni, US"tls_out_sni", &state->tlsp->sni, errstr))
2091
  if (!expand_check(state->tls_sni, US"tls_out_sni", &state->tlsp->sni, errstr))
1622
    return DEFER;
2092
    return DEFER;
1623
  if (state->tlsp->sni && *state->tlsp->sni)
2093
  if (state->tlsp->sni && *state->tlsp->sni)
1624
    {
2094
    {
Lines 1627-1671 Link Here
1627
    sz = Ustrlen(state->tlsp->sni);
2097
    sz = Ustrlen(state->tlsp->sni);
1628
    if ((rc = gnutls_server_name_set(state->session,
2098
    if ((rc = gnutls_server_name_set(state->session,
1629
	  GNUTLS_NAME_DNS, state->tlsp->sni, sz)))
2099
	  GNUTLS_NAME_DNS, state->tlsp->sni, sz)))
1630
      return tls_error_gnu(US"gnutls_server_name_set", rc, host, errstr);
2100
      return tls_error_gnu(state, US"gnutls_server_name_set", rc, errstr);
1631
    }
2101
    }
1632
  }
2102
  }
1633
else if (state->tls_sni)
2103
else if (state->tls_sni)
1634
  DEBUG(D_tls) debug_printf("*** PROBABLY A BUG *** " \
2104
  DEBUG(D_tls) debug_printf("*** PROBABLY A BUG *** " \
1635
      "have an SNI set for a server [%s]\n", state->tls_sni);
2105
      "have an SNI set for a server [%s]\n", state->tls_sni);
1636
2106
1637
/* This is the priority string support,
2107
if (!state->lib_state.pri_string)
1638
http://www.gnutls.org/manual/html_node/Priority-Strings.html
1639
and replaces gnutls_require_kx, gnutls_require_mac & gnutls_require_protocols.
1640
This was backwards incompatible, but means Exim no longer needs to track
1641
all algorithms and provide string forms for them. */
1642
1643
p = NULL;
1644
if (state->tls_require_ciphers && *state->tls_require_ciphers)
1645
  {
2108
  {
1646
  if (!expand_check_tlsvar(tls_require_ciphers, errstr))
2109
  const uschar * p = NULL;
1647
    return DEFER;
2110
  const char * errpos;
1648
  if (state->exp_tls_require_ciphers && *state->exp_tls_require_ciphers)
2111
2112
  /* This is the priority string support,
2113
  http://www.gnutls.org/manual/html_node/Priority-Strings.html
2114
  and replaces gnutls_require_kx, gnutls_require_mac & gnutls_require_protocols.
2115
  This was backwards incompatible, but means Exim no longer needs to track
2116
  all algorithms and provide string forms for them. */
2117
2118
  if (state->tls_require_ciphers && *state->tls_require_ciphers)
1649
    {
2119
    {
1650
    p = state->exp_tls_require_ciphers;
2120
    if (!Expand_check_tlsvar(tls_require_ciphers, errstr))
1651
    DEBUG(D_tls) debug_printf("GnuTLS session cipher/priority \"%s\"\n", p);
2121
      return DEFER;
2122
    if (state->exp_tls_require_ciphers && *state->exp_tls_require_ciphers)
2123
      {
2124
      p = state->exp_tls_require_ciphers;
2125
      DEBUG(D_tls) debug_printf("GnuTLS session cipher/priority \"%s\"\n", p);
2126
      }
1652
    }
2127
    }
2128
2129
  if ((rc = creds_load_pristring(state, p, &errpos)))
2130
    return tls_error_gnu(state, string_sprintf(
2131
			"gnutls_priority_init(%s) failed at offset %ld, \"%.6s..\"",
2132
			p, (long)(errpos - CS p), errpos),
2133
		    rc, errstr);
1653
  }
2134
  }
1654
if (!p)
2135
else
1655
  {
2136
  {
1656
  p = exim_default_gnutls_priority;
2137
  DEBUG(D_tls) debug_printf("cipher list preloaded\n");
1657
  DEBUG(D_tls)
2138
  state->exp_tls_require_ciphers = US state->tls_require_ciphers;
1658
    debug_printf("GnuTLS using default session cipher/priority \"%s\"\n", p);
1659
  }
2139
  }
1660
2140
1661
if ((rc = gnutls_priority_init(&state->priority_cache, CCS p, &errpos)))
1662
  return tls_error_gnu(string_sprintf(
1663
		      "gnutls_priority_init(%s) failed at offset %ld, \"%.6s..\"",
1664
		      p, errpos - CS p, errpos),
1665
		  rc, host, errstr);
1666
2141
1667
if ((rc = gnutls_priority_set(state->session, state->priority_cache)))
2142
if ((rc = gnutls_priority_set(state->session, state->lib_state.pri_cache)))
1668
  return tls_error_gnu(US"gnutls_priority_set", rc, host, errstr);
2143
  return tls_error_gnu(state, US"gnutls_priority_set", rc, errstr);
1669
2144
1670
/* This also sets the server ticket expiration time to the same, and
2145
/* This also sets the server ticket expiration time to the same, and
1671
the STEK rotation time to 3x. */
2146
the STEK rotation time to 3x. */
Lines 1863-1869 Link Here
1863
      DEBUG(D_tls) debug_printf("TLS: peer cert problem: %s: %s\n", \
2338
      DEBUG(D_tls) debug_printf("TLS: peer cert problem: %s: %s\n", \
1864
	(Label), gnutls_strerror(rc)); \
2339
	(Label), gnutls_strerror(rc)); \
1865
      if (state->verify_requirement >= VERIFY_REQUIRED) \
2340
      if (state->verify_requirement >= VERIFY_REQUIRED) \
1866
	return tls_error_gnu((Label), rc, state->host, errstr); \
2341
	return tls_error_gnu(state, (Label), rc, errstr); \
1867
      return OK; \
2342
      return OK; \
1868
      } \
2343
      } \
1869
    } while (0)
2344
    } while (0)
Lines 1880-1886 Link Here
1880
  exim_gnutls_peer_err(US"getting size for cert DN failed");
2355
  exim_gnutls_peer_err(US"getting size for cert DN failed");
1881
  return FAIL; /* should not happen */
2356
  return FAIL; /* should not happen */
1882
  }
2357
  }
1883
dn_buf = store_get_perm(sz, TRUE);	/* tainted */
2358
dn_buf = store_get_perm(sz, GET_TAINTED);
1884
rc = gnutls_x509_crt_get_dn(crt, CS dn_buf, &sz);
2359
rc = gnutls_x509_crt_get_dn(crt, CS dn_buf, &sz);
1885
exim_gnutls_peer_err(US"failed to extract certificate DN [gnutls_x509_crt_get_dn(cert 0)]");
2360
exim_gnutls_peer_err(US"failed to extract certificate DN [gnutls_x509_crt_get_dn(cert 0)]");
1886
2361
Lines 1960-1967 Link Here
1960
      for (nrec = 0; state->dane_data_len[nrec]; ) nrec++;
2435
      for (nrec = 0; state->dane_data_len[nrec]; ) nrec++;
1961
      nrec++;
2436
      nrec++;
1962
2437
1963
      dd = store_get(nrec * sizeof(uschar *), FALSE);
2438
      dd = store_get(nrec * sizeof(uschar *), GET_UNTAINTED);
1964
      ddl = store_get(nrec * sizeof(int), FALSE);
2439
      ddl = store_get(nrec * sizeof(int), GET_UNTAINTED);
1965
      nrec--;
2440
      nrec--;
1966
2441
1967
      if ((rc = dane_state_init(&s, 0)))
2442
      if ((rc = dane_state_init(&s, 0)))
Lines 2191-2197 Link Here
2191
  {
2666
  {
2192
  DEBUG(D_tls)
2667
  DEBUG(D_tls)
2193
    if (rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
2668
    if (rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
2194
      debug_printf("TLS: no SNI presented in handshake.\n");
2669
      debug_printf("TLS: no SNI presented in handshake\n");
2195
    else
2670
    else
2196
      debug_printf("TLS failure: gnutls_server_name_get(): %s [%d]\n",
2671
      debug_printf("TLS failure: gnutls_server_name_get(): %s [%d]\n",
2197
        gnutls_strerror(rc), rc);
2672
        gnutls_strerror(rc), rc);
Lines 2207-2213 Link Here
2207
/* We now have a UTF-8 string in sni_name */
2682
/* We now have a UTF-8 string in sni_name */
2208
old_pool = store_pool;
2683
old_pool = store_pool;
2209
store_pool = POOL_PERM;
2684
store_pool = POOL_PERM;
2210
state->received_sni = string_copy_taint(US sni_name, TRUE);
2685
state->received_sni = string_copy_taint(US sni_name, GET_TAINTED);
2211
store_pool = old_pool;
2686
store_pool = old_pool;
2212
2687
2213
/* We set this one now so that variable expansions below will work */
2688
/* We set this one now so that variable expansions below will work */
Lines 2266-2272 Link Here
2266
2741
2267
  state->tlsp->peercert = crt;
2742
  state->tlsp->peercert = crt;
2268
  if ((yield = event_raise(state->event_action,
2743
  if ((yield = event_raise(state->event_action,
2269
	      US"tls:cert", string_sprintf("%d", cert_list_size))))
2744
	      US"tls:cert", string_sprintf("%d", cert_list_size), &errno)))
2270
    {
2745
    {
2271
    log_write(0, LOG_MAIN,
2746
    log_write(0, LOG_MAIN,
2272
	      "SSL verify denied by event-action: depth=%d: %s",
2747
	      "SSL verify denied by event-action: depth=%d: %s",
Lines 2331-2337 Link Here
2331
}
2806
}
2332
2807
2333
2808
2334
#ifdef EXPERIMENTAL_TLS_RESUME
2809
#ifdef EXIM_HAVE_TLS_RESUME
2335
static int
2810
static int
2336
tls_server_ticket_cb(gnutls_session_t sess, u_int htype, unsigned when,
2811
tls_server_ticket_cb(gnutls_session_t sess, u_int htype, unsigned when,
2337
  unsigned incoming, const gnutls_datum_t * msg)
2812
  unsigned incoming, const gnutls_datum_t * msg)
Lines 2386-2392 Link Here
2386
  DEBUG(D_tls) debug_printf("Session resumed\n");
2861
  DEBUG(D_tls) debug_printf("Session resumed\n");
2387
  }
2862
  }
2388
}
2863
}
2389
#endif
2864
#endif	/* EXIM_HAVE_TLS_RESUME */
2865
2866
2867
#ifdef EXIM_HAVE_ALPN
2868
/* Expand and convert an Exim list to a gnutls_datum list.  False return for fail.
2869
NULL plist return for silent no-ALPN.
2870
*/
2871
2872
static BOOL
2873
tls_alpn_plist(uschar ** tls_alpn, const gnutls_datum_t ** plist, unsigned * plen,
2874
  uschar ** errstr)
2875
{
2876
uschar * exp_alpn;
2877
2878
if (!expand_check(*tls_alpn, US"tls_alpn", &exp_alpn, errstr))
2879
  return FALSE;
2880
2881
if (!exp_alpn)
2882
  {
2883
  DEBUG(D_tls) debug_printf("Setting TLS ALPN forced to fail, not sending\n");
2884
  *plist = NULL;
2885
  }
2886
else
2887
  {
2888
  const uschar * list = exp_alpn;
2889
  int sep = 0;
2890
  unsigned cnt = 0;
2891
  gnutls_datum_t * p;
2892
  uschar * s;
2893
2894
  while (string_nextinlist(&list, &sep, NULL, 0)) cnt++;
2895
2896
  p = store_get(sizeof(gnutls_datum_t) * cnt, exp_alpn);
2897
  list = exp_alpn;
2898
  for (int i = 0; s = string_nextinlist(&list, &sep, NULL, 0); i++)
2899
    { p[i].data = s; p[i].size = Ustrlen(s); }
2900
  *plist = (*plen = cnt) ? p : NULL;
2901
  }
2902
return TRUE;
2903
}
2904
2905
static void
2906
tls_server_set_acceptable_alpns(exim_gnutls_state_st * state, uschar ** errstr)
2907
{
2908
uschar * local_alpn = string_copy(tls_alpn);
2909
int rc;
2910
const gnutls_datum_t * plist;
2911
unsigned plen;
2912
2913
if (tls_alpn_plist(&local_alpn, &plist, &plen, errstr) && plist)
2914
  {
2915
  /* This seems to be only mandatory if the client sends an ALPN extension;
2916
  not trying ALPN is ok. Need to decide how to support server-side must-alpn. */
2917
2918
  server_seen_alpn = 0;
2919
  if (!(rc = gnutls_alpn_set_protocols(state->session, plist, plen,
2920
					GNUTLS_ALPN_MANDATORY)))
2921
    gnutls_handshake_set_hook_function(state->session,
2922
      GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST, tls_server_hook_cb);
2923
  else
2924
    DEBUG(D_tls)
2925
      debug_printf("setting alpn protocols: %s\n", US gnutls_strerror(rc));
2926
  }
2927
}
2928
#endif	/* EXIM_HAVE_ALPN */
2929
2390
/* ------------------------------------------------------------------------ */
2930
/* ------------------------------------------------------------------------ */
2391
/* Exported functions */
2931
/* Exported functions */
2392
2932
Lines 2402-2408 Link Here
2402
a TLS session.
2942
a TLS session.
2403
2943
2404
Arguments:
2944
Arguments:
2405
  require_ciphers  list of allowed ciphers or NULL
2406
  errstr	   pointer to error string
2945
  errstr	   pointer to error string
2407
2946
2408
Returns:           OK on success
2947
Returns:           OK on success
Lines 2412-2418 Link Here
2412
*/
2951
*/
2413
2952
2414
int
2953
int
2415
tls_server_start(const uschar * require_ciphers, uschar ** errstr)
2954
tls_server_start(uschar ** errstr)
2416
{
2955
{
2417
int rc;
2956
int rc;
2418
exim_gnutls_state_st * state = NULL;
2957
exim_gnutls_state_st * state = NULL;
Lines 2436-2451 Link Here
2436
  gettimeofday(&t0, NULL);
2975
  gettimeofday(&t0, NULL);
2437
#endif
2976
#endif
2438
2977
2439
  if ((rc = tls_init(NULL, tls_certificate, tls_privatekey,
2978
  if ((rc = tls_init(NULL, NULL,
2440
      NULL, tls_verify_certificates, tls_crl,
2979
      tls_require_ciphers, &state, &tls_in, errstr)) != OK) return rc;
2441
      require_ciphers, &state, &tls_in, errstr)) != OK) return rc;
2442
2980
2443
#ifdef MEASURE_TIMING
2981
#ifdef MEASURE_TIMING
2444
  report_time_since(&t0, US"server tls_init (delta)");
2982
  report_time_since(&t0, US"server tls_init (delta)");
2445
#endif
2983
#endif
2446
  }
2984
  }
2447
2985
2448
#ifdef EXPERIMENTAL_TLS_RESUME
2986
#ifdef EXIM_HAVE_ALPN
2987
tls_server_set_acceptable_alpns(state, errstr);
2988
#endif
2989
2990
#ifdef EXIM_HAVE_TLS_RESUME
2449
tls_server_resume_prehandshake(state);
2991
tls_server_resume_prehandshake(state);
2450
#endif
2992
#endif
2451
2993
Lines 2455-2475 Link Here
2455
if (verify_check_host(&tls_verify_hosts) == OK)
2997
if (verify_check_host(&tls_verify_hosts) == OK)
2456
  {
2998
  {
2457
  DEBUG(D_tls)
2999
  DEBUG(D_tls)
2458
    debug_printf("TLS: a client certificate will be required.\n");
3000
    debug_printf("TLS: a client certificate will be required\n");
2459
  state->verify_requirement = VERIFY_REQUIRED;
3001
  state->verify_requirement = VERIFY_REQUIRED;
2460
  gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUIRE);
3002
  gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUIRE);
2461
  }
3003
  }
2462
else if (verify_check_host(&tls_try_verify_hosts) == OK)
3004
else if (verify_check_host(&tls_try_verify_hosts) == OK)
2463
  {
3005
  {
2464
  DEBUG(D_tls)
3006
  DEBUG(D_tls)
2465
    debug_printf("TLS: a client certificate will be requested but not required.\n");
3007
    debug_printf("TLS: a client certificate will be requested but not required\n");
2466
  state->verify_requirement = VERIFY_OPTIONAL;
3008
  state->verify_requirement = VERIFY_OPTIONAL;
2467
  gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUEST);
3009
  gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUEST);
2468
  }
3010
  }
2469
else
3011
else
2470
  {
3012
  {
2471
  DEBUG(D_tls)
3013
  DEBUG(D_tls)
2472
    debug_printf("TLS: a client certificate will not be requested.\n");
3014
    debug_printf("TLS: a client certificate will not be requested\n");
2473
  state->verify_requirement = VERIFY_NONE;
3015
  state->verify_requirement = VERIFY_NONE;
2474
  gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_IGNORE);
3016
  gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_IGNORE);
2475
  }
3017
  }
Lines 2479-2485 Link Here
2479
  {
3021
  {
2480
  state->event_action = event_action;
3022
  state->event_action = event_action;
2481
  gnutls_session_set_ptr(state->session, state);
3023
  gnutls_session_set_ptr(state->session, state);
2482
  gnutls_certificate_set_verify_function(state->x509_cred, verify_cb);
3024
  gnutls_certificate_set_verify_function(state->lib_state.x509_cred, verify_cb);
2483
  }
3025
  }
2484
#endif
3026
#endif
2485
3027
Lines 2522-2527 Link Here
2522
3064
2523
if (rc != GNUTLS_E_SUCCESS)
3065
if (rc != GNUTLS_E_SUCCESS)
2524
  {
3066
  {
3067
  DEBUG(D_tls) debug_printf(" error %d from gnutls_handshake: %s\n",
3068
    rc, gnutls_strerror(rc));
3069
2525
  /* It seems that, except in the case of a timeout, we have to close the
3070
  /* It seems that, except in the case of a timeout, we have to close the
2526
  connection right here; otherwise if the other end is running OpenSSL it hangs
3071
  connection right here; otherwise if the other end is running OpenSSL it hangs
2527
  until the server times out. */
3072
  until the server times out. */
Lines 2529-2542 Link Here
2529
  if (sigalrm_seen)
3074
  if (sigalrm_seen)
2530
    {
3075
    {
2531
    tls_error(US"gnutls_handshake", US"timed out", NULL, errstr);
3076
    tls_error(US"gnutls_handshake", US"timed out", NULL, errstr);
3077
#ifndef DISABLE_EVENT
3078
    (void) event_raise(event_action, US"tls:fail:connect", *errstr, NULL);
3079
#endif
2532
    gnutls_db_remove_session(state->session);
3080
    gnutls_db_remove_session(state->session);
2533
    }
3081
    }
2534
  else
3082
  else
2535
    {
3083
    {
2536
    tls_error_gnu(US"gnutls_handshake", rc, NULL, errstr);
3084
    tls_error_gnu(state, US"gnutls_handshake", rc, errstr);
3085
#ifndef DISABLE_EVENT
3086
    (void) event_raise(event_action, US"tls:fail:connect", *errstr, NULL);
3087
#endif
2537
    (void) gnutls_alert_send_appropriate(state->session, rc);
3088
    (void) gnutls_alert_send_appropriate(state->session, rc);
2538
    gnutls_deinit(state->session);
3089
    gnutls_deinit(state->session);
2539
    gnutls_certificate_free_credentials(state->x509_cred);
2540
    millisleep(500);
3090
    millisleep(500);
2541
    shutdown(state->fd_out, SHUT_WR);
3091
    shutdown(state->fd_out, SHUT_WR);
2542
    for (int i = 1024; fgetc(smtp_in) != EOF && i > 0; ) i--;	/* drain skt */
3092
    for (int i = 1024; fgetc(smtp_in) != EOF && i > 0; ) i--;	/* drain skt */
Lines 2553-2564 Link Here
2553
  tls_in.ext_master_secret = TRUE;
3103
  tls_in.ext_master_secret = TRUE;
2554
#endif
3104
#endif
2555
3105
2556
#ifdef EXPERIMENTAL_TLS_RESUME
3106
#ifdef EXIM_HAVE_TLS_RESUME
2557
tls_server_resume_posthandshake(state);
3107
tls_server_resume_posthandshake(state);
2558
#endif
3108
#endif
2559
3109
2560
DEBUG(D_tls) post_handshake_debug(state);
3110
DEBUG(D_tls) post_handshake_debug(state);
2561
3111
3112
#ifdef EXIM_HAVE_ALPN
3113
if (server_seen_alpn > 0)
3114
  {
3115
  DEBUG(D_tls)
3116
    {		/* The client offered ALPN.  See what was negotiated. */
3117
    gnutls_datum_t p = {.size = 0};
3118
    int rc = gnutls_alpn_get_selected_protocol(state->session, &p);
3119
    if (!rc)
3120
	debug_printf("ALPN negotiated: %.*s\n", (int)p.size, p.data);
3121
    else
3122
	debug_printf("getting alpn protocol: %s\n", US gnutls_strerror(rc));
3123
3124
    }
3125
  }
3126
else if (server_seen_alpn == 0)
3127
  if (verify_check_host(&hosts_require_alpn) == OK)
3128
    {
3129
    gnutls_alert_send(state->session, GNUTLS_AL_FATAL, GNUTLS_A_NO_APPLICATION_PROTOCOL);
3130
    tls_error(US"handshake", US"ALPN required but not negotiated", NULL, errstr);
3131
    return FAIL;
3132
    }
3133
  else
3134
    DEBUG(D_tls) debug_printf("TLS: no ALPN presented in handshake\n");
3135
else
3136
  DEBUG(D_tls) debug_printf("TLS: was not watching for ALPN\n");
3137
#endif
3138
2562
/* Verify after the fact */
3139
/* Verify after the fact */
2563
3140
2564
if (!verify_certificate(state, errstr))
3141
if (!verify_certificate(state, errstr))
Lines 2585-2594 Link Here
2585
receive_getc = tls_getc;
3162
receive_getc = tls_getc;
2586
receive_getbuf = tls_getbuf;
3163
receive_getbuf = tls_getbuf;
2587
receive_get_cache = tls_get_cache;
3164
receive_get_cache = tls_get_cache;
3165
receive_hasc = tls_hasc;
2588
receive_ungetc = tls_ungetc;
3166
receive_ungetc = tls_ungetc;
2589
receive_feof = tls_feof;
3167
receive_feof = tls_feof;
2590
receive_ferror = tls_ferror;
3168
receive_ferror = tls_ferror;
2591
receive_smtp_buffered = tls_smtp_buffered;
2592
3169
2593
return OK;
3170
return OK;
2594
}
3171
}
Lines 2609-2615 Link Here
2609
    host->certname;
3186
    host->certname;
2610
#endif
3187
#endif
2611
  DEBUG(D_tls)
3188
  DEBUG(D_tls)
2612
    debug_printf("TLS: server cert verification includes hostname: \"%s\".\n",
3189
    debug_printf("TLS: server cert verification includes hostname: \"%s\"\n",
2613
		    state->exp_tls_verify_cert_hostnames);
3190
		    state->exp_tls_verify_cert_hostnames);
2614
  }
3191
  }
2615
}
3192
}
Lines 2638-2645 Link Here
2638
     rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)
3215
     rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)
2639
    ) if (rr->type == T_TLSA) i++;
3216
    ) if (rr->type == T_TLSA) i++;
2640
3217
2641
dane_data = store_get(i * sizeof(uschar *), FALSE);
3218
dane_data = store_get(i * sizeof(uschar *), GET_UNTAINTED);
2642
dane_data_len = store_get(i * sizeof(int), FALSE);
3219
dane_data_len = store_get(i * sizeof(int), GET_UNTAINTED);
2643
3220
2644
i = 0;
3221
i = 0;
2645
for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr;
3222
for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr;
Lines 2686-2692 Link Here
2686
3263
2687
3264
2688
3265
2689
#ifdef EXPERIMENTAL_TLS_RESUME
3266
#ifdef EXIM_HAVE_TLS_RESUME
2690
/* On the client, get any stashed session for the given IP from hints db
3267
/* On the client, get any stashed session for the given IP from hints db
2691
and apply it to the ssl-connection for attempted resumption.  Although
3268
and apply it to the ssl-connection for attempted resumption.  Although
2692
there is a gnutls_session_ticket_enable_client() interface it is
3269
there is a gnutls_session_ticket_enable_client() interface it is
Lines 2697-2721 Link Here
2697
3274
2698
static void
3275
static void
2699
tls_retrieve_session(tls_support * tlsp, gnutls_session_t session,
3276
tls_retrieve_session(tls_support * tlsp, gnutls_session_t session,
2700
  host_item * host, smtp_transport_options_block * ob)
3277
  smtp_connect_args * conn_args, smtp_transport_options_block * ob)
2701
{
3278
{
2702
tlsp->resumption = RESUME_SUPPORTED;
3279
tlsp->resumption = RESUME_SUPPORTED;
2703
if (verify_check_given_host(CUSS &ob->tls_resumption_hosts, host) == OK)
3280
3281
if (!conn_args->have_lbserver)
3282
  { DEBUG(D_tls) debug_printf("resumption not supported on continued-connection\n"); }
3283
else if (verify_check_given_host(CUSS &ob->tls_resumption_hosts, conn_args->host) == OK)
2704
  {
3284
  {
2705
  dbdata_tls_session * dt;
3285
  dbdata_tls_session * dt;
2706
  int len, rc;
3286
  int len, rc;
2707
  open_db dbblock, * dbm_file;
3287
  open_db dbblock, * dbm_file;
2708
3288
2709
  DEBUG(D_tls)
2710
    debug_printf("check for resumable session for %s\n", host->address);
2711
  tlsp->host_resumable = TRUE;
3289
  tlsp->host_resumable = TRUE;
3290
  tls_client_resmption_key(tlsp, conn_args, ob);
3291
2712
  tlsp->resumption |= RESUME_CLIENT_REQUESTED;
3292
  tlsp->resumption |= RESUME_CLIENT_REQUESTED;
2713
  if ((dbm_file = dbfn_open(US"tls", O_RDONLY, &dbblock, FALSE, FALSE)))
3293
  if ((dbm_file = dbfn_open(US"tls", O_RDONLY, &dbblock, FALSE, FALSE)))
2714
    {
3294
    {
2715
    /* Key for the db is the IP.  We'd like to filter the retrieved session
3295
    /* We'd like to filter the retrieved session for ticket advisory expiry,
2716
    for ticket advisory expiry, but 3.6.1 seems to give no access to that */
3296
    but 3.6.1 seems to give no access to that */
2717
3297
2718
    if ((dt = dbfn_read_with_length(dbm_file, host->address, &len)))
3298
    if ((dt = dbfn_read_with_length(dbm_file, tlsp->resume_index, &len)))
2719
      if (!(rc = gnutls_session_set_data(session,
3299
      if (!(rc = gnutls_session_set_data(session,
2720
		    CUS dt->session, (size_t)len - sizeof(dbdata_tls_session))))
3300
		    CUS dt->session, (size_t)len - sizeof(dbdata_tls_session))))
2721
	{
3301
	{
Lines 2752-2758 Link Here
2752
      {
3332
      {
2753
      open_db dbblock, * dbm_file;
3333
      open_db dbblock, * dbm_file;
2754
      int dlen = sizeof(dbdata_tls_session) + tkt.size;
3334
      int dlen = sizeof(dbdata_tls_session) + tkt.size;
2755
      dbdata_tls_session * dt = store_get(dlen, TRUE);
3335
      dbdata_tls_session * dt = store_get(dlen, GET_TAINTED);
2756
3336
2757
      DEBUG(D_tls) debug_printf("session data size %u\n", (unsigned)tkt.size);
3337
      DEBUG(D_tls) debug_printf("session data size %u\n", (unsigned)tkt.size);
2758
      memcpy(dt->session, tkt.data, tkt.size);
3338
      memcpy(dt->session, tkt.data, tkt.size);
Lines 2761-2768 Link Here
2761
      if ((dbm_file = dbfn_open(US"tls", O_RDWR, &dbblock, FALSE, FALSE)))
3341
      if ((dbm_file = dbfn_open(US"tls", O_RDWR, &dbblock, FALSE, FALSE)))
2762
	{
3342
	{
2763
	/* key for the db is the IP */
3343
	/* key for the db is the IP */
2764
	dbfn_delete(dbm_file, host->address);
3344
	dbfn_write(dbm_file, tlsp->resume_index, dt, dlen);
2765
	dbfn_write(dbm_file, host->address, dt, dlen);
2766
	dbfn_close(dbm_file);
3345
	dbfn_close(dbm_file);
2767
3346
2768
	DEBUG(D_tls)
3347
	DEBUG(D_tls)
Lines 2797-2810 Link Here
2797
3376
2798
static void
3377
static void
2799
tls_client_resume_prehandshake(exim_gnutls_state_st * state,
3378
tls_client_resume_prehandshake(exim_gnutls_state_st * state,
2800
  tls_support * tlsp, host_item * host,
3379
  tls_support * tlsp, smtp_connect_args * conn_args,
2801
  smtp_transport_options_block * ob)
3380
  smtp_transport_options_block * ob)
2802
{
3381
{
2803
gnutls_session_set_ptr(state->session, state);
3382
gnutls_session_set_ptr(state->session, state);
2804
gnutls_handshake_set_hook_function(state->session,
3383
gnutls_handshake_set_hook_function(state->session,
2805
  GNUTLS_HANDSHAKE_NEW_SESSION_TICKET, GNUTLS_HOOK_POST, tls_client_ticket_cb);
3384
  GNUTLS_HANDSHAKE_NEW_SESSION_TICKET, GNUTLS_HOOK_POST, tls_client_ticket_cb);
2806
3385
2807
tls_retrieve_session(tlsp, state->session, host, ob);
3386
tls_retrieve_session(tlsp, state->session, conn_args, ob);
2808
}
3387
}
2809
3388
2810
static void
3389
static void
Lines 2819-2825 Link Here
2819
3398
2820
tls_save_session(tlsp, state->session, host);
3399
tls_save_session(tlsp, state->session, host);
2821
}
3400
}
2822
#endif	/* EXPERIMENTAL_TLS_RESUME */
3401
#endif	/* !DISABLE_TLS_RESUME */
2823
3402
2824
3403
2825
/*************************************************
3404
/*************************************************
Lines 2870-2876 Link Here
2870
3449
2871
if (conn_args->dane && ob->dane_require_tls_ciphers)
3450
if (conn_args->dane && ob->dane_require_tls_ciphers)
2872
  {
3451
  {
2873
  /* not using expand_check_tlsvar because not yet in state */
3452
  /* not using Expand_check_tlsvar because not yet in state */
2874
  if (!expand_check(ob->dane_require_tls_ciphers, US"dane_require_tls_ciphers",
3453
  if (!expand_check(ob->dane_require_tls_ciphers, US"dane_require_tls_ciphers",
2875
      &cipher_list, errstr))
3454
      &cipher_list, errstr))
2876
    return FALSE;
3455
    return FALSE;
Lines 2888-2904 Link Here
2888
  gettimeofday(&t0, NULL);
3467
  gettimeofday(&t0, NULL);
2889
#endif
3468
#endif
2890
3469
2891
  if (tls_init(host, ob->tls_certificate, ob->tls_privatekey,
3470
  if (tls_init(host, ob, cipher_list, &state, tlsp, errstr) != OK)
2892
      ob->tls_sni, ob->tls_verify_certificates, ob->tls_crl,
2893
      cipher_list, &state, tlsp, errstr) != OK)
2894
    return FALSE;
3471
    return FALSE;
2895
3472
2896
2897
#ifdef MEASURE_TIMING
3473
#ifdef MEASURE_TIMING
2898
  report_time_since(&t0, US"client tls_init (delta)");
3474
  report_time_since(&t0, US"client tls_init (delta)");
2899
#endif
3475
#endif
2900
  }
3476
  }
2901
3477
3478
if (ob->tls_alpn)
3479
#ifdef EXIM_HAVE_ALPN
3480
  {
3481
  const gnutls_datum_t * plist;
3482
  unsigned plen;
3483
3484
  if (!tls_alpn_plist(&ob->tls_alpn, &plist, &plen, errstr))
3485
    return FALSE;
3486
  if (plist)
3487
    if (gnutls_alpn_set_protocols(state->session, plist, plen, 0) != 0)
3488
      {
3489
      tls_error(US"alpn init", NULL, state->host, errstr);
3490
      return FALSE;
3491
      }
3492
    else
3493
      DEBUG(D_tls) debug_printf("Setting TLS ALPN '%s'\n", ob->tls_alpn);
3494
  }
3495
#else
3496
  log_write(0, LOG_MAIN, "ALPN unusable with this GnuTLS library version; ignoring \"%s\"\n",
3497
          ob->tls_alpn);
3498
#endif
3499
2902
  {
3500
  {
2903
  int dh_min_bits = ob->tls_dh_min_bits;
3501
  int dh_min_bits = ob->tls_dh_min_bits;
2904
  if (dh_min_bits < EXIM_CLIENT_DH_MIN_MIN_BITS)
3502
  if (dh_min_bits < EXIM_CLIENT_DH_MIN_MIN_BITS)
Lines 2924-2930 Link Here
2924
if (conn_args->dane && dane_tlsa_load(state, &conn_args->tlsa_dnsa))
3522
if (conn_args->dane && dane_tlsa_load(state, &conn_args->tlsa_dnsa))
2925
  {
3523
  {
2926
  DEBUG(D_tls)
3524
  DEBUG(D_tls)
2927
    debug_printf("TLS: server certificate DANE required.\n");
3525
    debug_printf("TLS: server certificate DANE required\n");
2928
  state->verify_requirement = VERIFY_DANE;
3526
  state->verify_requirement = VERIFY_DANE;
2929
  gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUIRE);
3527
  gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUIRE);
2930
  }
3528
  }
Lines 2939-2945 Link Here
2939
  {
3537
  {
2940
  tls_client_setup_hostname_checks(host, state, ob);
3538
  tls_client_setup_hostname_checks(host, state, ob);
2941
  DEBUG(D_tls)
3539
  DEBUG(D_tls)
2942
    debug_printf("TLS: server certificate verification required.\n");
3540
    debug_printf("TLS: server certificate verification required\n");
2943
  state->verify_requirement = VERIFY_REQUIRED;
3541
  state->verify_requirement = VERIFY_REQUIRED;
2944
  gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUIRE);
3542
  gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUIRE);
2945
  }
3543
  }
Lines 2947-2960 Link Here
2947
  {
3545
  {
2948
  tls_client_setup_hostname_checks(host, state, ob);
3546
  tls_client_setup_hostname_checks(host, state, ob);
2949
  DEBUG(D_tls)
3547
  DEBUG(D_tls)
2950
    debug_printf("TLS: server certificate verification optional.\n");
3548
    debug_printf("TLS: server certificate verification optional\n");
2951
  state->verify_requirement = VERIFY_OPTIONAL;
3549
  state->verify_requirement = VERIFY_OPTIONAL;
2952
  gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUEST);
3550
  gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_REQUEST);
2953
  }
3551
  }
2954
else
3552
else
2955
  {
3553
  {
2956
  DEBUG(D_tls)
3554
  DEBUG(D_tls)
2957
    debug_printf("TLS: server certificate verification not required.\n");
3555
    debug_printf("TLS: server certificate verification not required\n");
2958
  state->verify_requirement = VERIFY_NONE;
3556
  state->verify_requirement = VERIFY_NONE;
2959
  gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_IGNORE);
3557
  gnutls_certificate_server_set_request(state->session, GNUTLS_CERT_IGNORE);
2960
  }
3558
  }
Lines 2967-2981 Link Here
2967
  if ((rc = gnutls_ocsp_status_request_enable_client(state->session,
3565
  if ((rc = gnutls_ocsp_status_request_enable_client(state->session,
2968
		    NULL, 0, NULL)) != OK)
3566
		    NULL, 0, NULL)) != OK)
2969
    {
3567
    {
2970
    tls_error_gnu(US"cert-status-req", rc, state->host, errstr);
3568
    tls_error_gnu(state, US"cert-status-req", rc, errstr);
2971
    return FALSE;
3569
    return FALSE;
2972
    }
3570
    }
2973
  tlsp->ocsp = OCSP_NOT_RESP;
3571
  tlsp->ocsp = OCSP_NOT_RESP;
2974
  }
3572
  }
2975
#endif
3573
#endif
2976
3574
2977
#ifdef EXPERIMENTAL_TLS_RESUME
3575
#ifdef EXIM_HAVE_TLS_RESUME
2978
tls_client_resume_prehandshake(state, tlsp, host, ob);
3576
tls_client_resume_prehandshake(state, tlsp, conn_args, ob);
2979
#endif
3577
#endif
2980
3578
2981
#ifndef DISABLE_EVENT
3579
#ifndef DISABLE_EVENT
Lines 2983-2989 Link Here
2983
  {
3581
  {
2984
  state->event_action = tb->event_action;
3582
  state->event_action = tb->event_action;
2985
  gnutls_session_set_ptr(state->session, state);
3583
  gnutls_session_set_ptr(state->session, state);
2986
  gnutls_certificate_set_verify_function(state->x509_cred, verify_cb);
3584
  gnutls_certificate_set_verify_function(state->lib_state.x509_cred, verify_cb);
2987
  }
3585
  }
2988
#endif
3586
#endif
2989
3587
Lines 3009-3015 Link Here
3009
    tls_error(US"gnutls_handshake", US"timed out", state->host, errstr);
3607
    tls_error(US"gnutls_handshake", US"timed out", state->host, errstr);
3010
    }
3608
    }
3011
  else
3609
  else
3012
    tls_error_gnu(US"gnutls_handshake", rc, state->host, errstr);
3610
    tls_error_gnu(state, US"gnutls_handshake", rc, errstr);
3013
  return FALSE;
3611
  return FALSE;
3014
  }
3612
  }
3015
3613
Lines 3054-3062 Link Here
3054
	gnutls_free(printed.data);
3652
	gnutls_free(printed.data);
3055
	}
3653
	}
3056
      else
3654
      else
3057
	(void) tls_error_gnu(US"ocsp decode", rc, state->host, errstr);
3655
	(void) tls_error_gnu(state, US"ocsp decode", rc, errstr);
3058
    if (idx == 0 && rc)
3656
    if (idx == 0 && rc)
3059
      (void) tls_error_gnu(US"ocsp decode", rc, state->host, errstr);
3657
      (void) tls_error_gnu(state, US"ocsp decode", rc, errstr);
3060
    }
3658
    }
3061
3659
3062
  if (gnutls_ocsp_status_request_is_checked(state->session, 0) == 0)
3660
  if (gnutls_ocsp_status_request_is_checked(state->session, 0) == 0)
Lines 3074-3083 Link Here
3074
  }
3672
  }
3075
#endif
3673
#endif
3076
3674
3077
#ifdef EXPERIMENTAL_TLS_RESUME
3675
#ifdef EXIM_HAVE_TLS_RESUME
3078
tls_client_resume_posthandshake(state, tlsp, host);
3676
tls_client_resume_posthandshake(state, tlsp, host);
3079
#endif
3677
#endif
3080
3678
3679
#ifdef EXIM_HAVE_ALPN
3680
if (ob->tls_alpn)	/* We requested. See what was negotiated. */
3681
  {
3682
  gnutls_datum_t p = {.size = 0};
3683
3684
  if (gnutls_alpn_get_selected_protocol(state->session, &p) == 0)
3685
    { DEBUG(D_tls) debug_printf("ALPN negotiated: '%.*s'\n", (int)p.size, p.data); }
3686
  else if (verify_check_given_host(CUSS &ob->hosts_require_alpn, host) == OK)
3687
    {
3688
    gnutls_alert_send(state->session, GNUTLS_AL_FATAL, GNUTLS_A_NO_APPLICATION_PROTOCOL);
3689
    tls_error(US"handshake", US"ALPN required but not negotiated", state->host, errstr);
3690
    return FALSE;
3691
    }
3692
  else
3693
    DEBUG(D_tls) debug_printf("No ALPN negotiated");
3694
  }
3695
#endif
3696
3081
/* Sets various Exim expansion variables; may need to adjust for ACL callouts */
3697
/* Sets various Exim expansion variables; may need to adjust for ACL callouts */
3082
3698
3083
extract_exim_vars_from_tls_state(state);
3699
extract_exim_vars_from_tls_state(state);
Lines 3089-3094 Link Here
3089
3705
3090
3706
3091
3707
3708
/*
3709
Arguments:
3710
  ct_ctx	client TLS context pointer, or NULL for the one global server context
3711
*/
3712
3713
void
3714
tls_shutdown_wr(void * ct_ctx)
3715
{
3716
exim_gnutls_state_st * state = ct_ctx ? ct_ctx : &state_server;
3717
tls_support * tlsp = state->tlsp;
3718
3719
if (!tlsp || tlsp->active.sock < 0) return;  /* TLS was not active */
3720
3721
tls_write(ct_ctx, NULL, 0, FALSE);	/* flush write buffer */
3722
3723
HDEBUG(D_transport|D_tls|D_acl|D_v) debug_printf_indent("  SMTP(TLS shutdown)>>\n");
3724
gnutls_bye(state->session, GNUTLS_SHUT_WR);
3725
}
3726
3092
/*************************************************
3727
/*************************************************
3093
*         Close down a TLS session               *
3728
*         Close down a TLS session               *
3094
*************************************************/
3729
*************************************************/
Lines 3099-3125 Link Here
3099
3734
3100
Arguments:
3735
Arguments:
3101
  ct_ctx	client context pointer, or NULL for the one global server context
3736
  ct_ctx	client context pointer, or NULL for the one global server context
3102
  shutdown	1 if TLS close-alert is to be sent,
3737
  do_shutdown	0 no data-flush or TLS close-alert
3103
		2 if also response to be waited for
3738
		1 if TLS close-alert is to be sent,
3739
		2 if also response to be waited for (2s timeout)
3104
3740
3105
Returns:     nothing
3741
Returns:     nothing
3106
*/
3742
*/
3107
3743
3108
void
3744
void
3109
tls_close(void * ct_ctx, int shutdown)
3745
tls_close(void * ct_ctx, int do_shutdown)
3110
{
3746
{
3111
exim_gnutls_state_st * state = ct_ctx ? ct_ctx : &state_server;
3747
exim_gnutls_state_st * state = ct_ctx ? ct_ctx : &state_server;
3112
tls_support * tlsp = state->tlsp;
3748
tls_support * tlsp = state->tlsp;
3113
3749
3114
if (!tlsp || tlsp->active.sock < 0) return;  /* TLS was not active */
3750
if (!tlsp || tlsp->active.sock < 0) return;  /* TLS was not active */
3115
3751
3116
if (shutdown)
3752
if (do_shutdown)
3117
  {
3753
  {
3118
  DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n",
3754
  DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n",
3119
    shutdown > 1 ? " (with response-wait)" : "");
3755
    do_shutdown > TLS_SHUTDOWN_NOWAIT ? " (with response-wait)" : "");
3756
3757
  tls_write(ct_ctx, NULL, 0, FALSE);	/* flush write buffer */
3758
3759
#ifdef EXIM_TCP_CORK
3760
  if (do_shutdown == TLS_SHUTDOWN_WAIT)
3761
    (void) setsockopt(tlsp->active.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &off, sizeof(off));
3762
#endif
3763
3764
  /* The library seems to have no way to only wait for a peer's
3765
  shutdown, so handle the same as TLS_SHUTDOWN_WAIT */
3120
3766
3121
  ALARM(2);
3767
  ALARM(2);
3122
  gnutls_bye(state->session, shutdown > 1 ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
3768
  gnutls_bye(state->session,
3769
      do_shutdown > TLS_SHUTDOWN_NOWAIT ? GNUTLS_SHUT_RDWR : GNUTLS_SHUT_WR);
3123
  ALARM_CLR(0);
3770
  ALARM_CLR(0);
3124
  }
3771
  }
3125
3772
Lines 3128-3142 Link Here
3128
  receive_getc =	smtp_getc;
3775
  receive_getc =	smtp_getc;
3129
  receive_getbuf =	smtp_getbuf;
3776
  receive_getbuf =	smtp_getbuf;
3130
  receive_get_cache =	smtp_get_cache;
3777
  receive_get_cache =	smtp_get_cache;
3778
  receive_hasc =	smtp_hasc;
3131
  receive_ungetc =	smtp_ungetc;
3779
  receive_ungetc =	smtp_ungetc;
3132
  receive_feof =	smtp_feof;
3780
  receive_feof =	smtp_feof;
3133
  receive_ferror =	smtp_ferror;
3781
  receive_ferror =	smtp_ferror;
3134
  receive_smtp_buffered = smtp_buffered;
3135
  }
3782
  }
3136
3783
3137
gnutls_deinit(state->session);
3784
gnutls_deinit(state->session);
3138
gnutls_certificate_free_credentials(state->x509_cred);
3139
3140
tlsp->active.sock = -1;
3785
tlsp->active.sock = -1;
3141
tlsp->active.tls_ctx = NULL;
3786
tlsp->active.tls_ctx = NULL;
3142
/* Leave bits, peercert, cipher, peerdn, certificate_verified set, for logging */
3787
/* Leave bits, peercert, cipher, peerdn, certificate_verified set, for logging */
Lines 3144-3150 Link Here
3144
3789
3145
3790
3146
if (state->xfer_buffer) store_free(state->xfer_buffer);
3791
if (state->xfer_buffer) store_free(state->xfer_buffer);
3147
memcpy(state, &exim_gnutls_state_init, sizeof(exim_gnutls_state_init));
3148
}
3792
}
3149
3793
3150
3794
Lines 3242-3247 Link Here
3242
return state->xfer_buffer[state->xfer_buffer_lwm++];
3886
return state->xfer_buffer[state->xfer_buffer_lwm++];
3243
}
3887
}
3244
3888
3889
BOOL
3890
tls_hasc(void)
3891
{
3892
exim_gnutls_state_st * state = &state_server;
3893
return state->xfer_buffer_lwm < state->xfer_buffer_hwm;
3894
}
3895
3245
uschar *
3896
uschar *
3246
tls_getbuf(unsigned * len)
3897
tls_getbuf(unsigned * len)
3247
{
3898
{
Lines 3266-3277 Link Here
3266
}
3917
}
3267
3918
3268
3919
3920
/* Get up to the given number of bytes from any cached data, and feed to dkim. */
3269
void
3921
void
3270
tls_get_cache()
3922
tls_get_cache(unsigned lim)
3271
{
3923
{
3272
#ifndef DISABLE_DKIM
3924
#ifndef DISABLE_DKIM
3273
exim_gnutls_state_st * state = &state_server;
3925
exim_gnutls_state_st * state = &state_server;
3274
int n = state->xfer_buffer_hwm - state->xfer_buffer_lwm;
3926
int n = state->xfer_buffer_hwm - state->xfer_buffer_lwm;
3927
if (n > lim)
3928
  n = lim;
3275
if (n > 0)
3929
if (n > 0)
3276
  dkim_exim_verify_feed(state->xfer_buffer+state->xfer_buffer_lwm, n);
3930
  dkim_exim_verify_feed(state->xfer_buffer+state->xfer_buffer_lwm, n);
3277
#endif
3931
#endif
Lines 3279-3293 Link Here
3279
3933
3280
3934
3281
BOOL
3935
BOOL
3282
tls_could_read(void)
3936
tls_could_getc(void)
3283
{
3937
{
3284
return state_server.xfer_buffer_lwm < state_server.xfer_buffer_hwm
3938
return state_server.xfer_buffer_lwm < state_server.xfer_buffer_hwm
3285
 || gnutls_record_check_pending(state_server.session) > 0;
3939
 || gnutls_record_check_pending(state_server.session) > 0;
3286
}
3940
}
3287
3941
3288
3942
3289
3290
3291
/*************************************************
3943
/*************************************************
3292
*          Read bytes from TLS channel           *
3944
*          Read bytes from TLS channel           *
3293
*************************************************/
3945
*************************************************/
Lines 3396-3403 Link Here
3396
4048
3397
  if (outbytes < 0)
4049
  if (outbytes < 0)
3398
    {
4050
    {
3399
    DEBUG(D_tls) debug_printf("%s: gnutls_record_send err\n", __FUNCTION__);
4051
#ifdef GNUTLS_E_PREMATURE_TERMINATION
3400
    record_io_error(state, outbytes, US"send", NULL);
4052
    if (  outbytes == GNUTLS_E_PREMATURE_TERMINATION && errno == ECONNRESET
4053
       && !ct_ctx && f.smtp_in_quit
4054
       )
4055
      {					/* Outlook, dammit */
4056
      if (LOGGING(protocol_detail))
4057
	log_write(0, LOG_MAIN, "[%s] after QUIT, client reset TCP before"
4058
	  " SMTP response and TLS close\n", sender_host_address);
4059
      else
4060
	DEBUG(D_tls) debug_printf("[%s] SSL_write: after QUIT,"
4061
	  " client reset TCP before TLS close\n", sender_host_address);
4062
      }
4063
    else
4064
#endif
4065
      {
4066
      DEBUG(D_tls) debug_printf("%s: gnutls_record_send err\n", __FUNCTION__);
4067
      record_io_error(state, outbytes, US"send", NULL);
4068
      }
3401
    return -1;
4069
    return -1;
3402
    }
4070
    }
3403
  if (outbytes == 0)
4071
  if (outbytes == 0)
Lines 3486-3492 Link Here
3486
i = gnutls_rnd(GNUTLS_RND_NONCE, smallbuf, needed_len);
4154
i = gnutls_rnd(GNUTLS_RND_NONCE, smallbuf, needed_len);
3487
if (i < 0)
4155
if (i < 0)
3488
  {
4156
  {
3489
  DEBUG(D_all) debug_printf("gnutls_rnd() failed, using fallback.\n");
4157
  DEBUG(D_all) debug_printf("gnutls_rnd() failed, using fallback\n");
3490
  return vaguely_random_number_fallback(max);
4158
  return vaguely_random_number_fallback(max);
3491
  }
4159
  }
3492
r = 0;
4160
r = 0;
Lines 3572-3578 Link Here
3572
rc = gnutls_priority_init(&priority_cache, CS expciphers, &errpos);
4240
rc = gnutls_priority_init(&priority_cache, CS expciphers, &errpos);
3573
validate_check_rc(string_sprintf(
4241
validate_check_rc(string_sprintf(
3574
      "gnutls_priority_init(%s) failed at offset %ld, \"%.8s..\"",
4242
      "gnutls_priority_init(%s) failed at offset %ld, \"%.8s..\"",
3575
      expciphers, errpos - CS expciphers, errpos));
4243
      expciphers, (long)(errpos - CS expciphers), errpos));
3576
4244
3577
#undef return_deinit
4245
#undef return_deinit
3578
#undef validate_check_rc
4246
#undef validate_check_rc
Lines 3592-3608 Link Here
3592
4260
3593
/* See a description in tls-openssl.c for an explanation of why this exists.
4261
/* See a description in tls-openssl.c for an explanation of why this exists.
3594
4262
3595
Arguments:   a FILE* to print the results to
4263
Arguments:   string to append to
3596
Returns:     nothing
4264
Returns:     string
3597
*/
4265
*/
3598
4266
3599
void
4267
gstring *
3600
tls_version_report(FILE *f)
4268
tls_version_report(gstring * g)
3601
{
4269
{
3602
fprintf(f, "Library version: GnuTLS: Compile: %s\n"
4270
return string_fmt_append(g,
3603
           "                         Runtime: %s\n",
4271
    "Library version: GnuTLS: Compile: %s\n"
3604
           LIBGNUTLS_VERSION,
4272
    "                         Runtime: %s\n",
3605
           gnutls_check_version(NULL));
4273
	     LIBGNUTLS_VERSION,
4274
	     gnutls_check_version(NULL));
3606
}
4275
}
3607
4276
3608
#endif	/*!MACRO_PREDEF*/
4277
#endif	/*!MACRO_PREDEF*/
(-)exim.orig/src/tls-openssl.c (-982 / +1751 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2019 */
6
/* Copyright (c) University of Cambridge 1995 - 2019 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Portions Copyright (c) The OpenSSL Project 1999 */
9
/* Portions Copyright (c) The OpenSSL Project 1999 */
Lines 80-85 Link Here
80
#  ifndef DISABLE_OCSP
80
#  ifndef DISABLE_OCSP
81
#   define EXIM_HAVE_OCSP
81
#   define EXIM_HAVE_OCSP
82
#  endif
82
#  endif
83
#  define EXIM_HAVE_ALPN /* fail ret from hshake-cb is ignored by LibreSSL */
83
# else
84
# else
84
#  define EXIM_NEED_OPENSSL_INIT
85
#  define EXIM_NEED_OPENSSL_INIT
85
# endif
86
# endif
Lines 89-94 Link Here
89
# endif
90
# endif
90
#endif
91
#endif
91
92
93
#if LIBRESSL_VERSION_NUMBER >= 0x3040000fL
94
# define EXIM_HAVE_OPENSSL_CIPHER_GET_ID
95
#endif
96
92
#if !defined(LIBRESSL_VERSION_NUMBER) \
97
#if !defined(LIBRESSL_VERSION_NUMBER) \
93
    || LIBRESSL_VERSION_NUMBER >= 0x20010000L
98
    || LIBRESSL_VERSION_NUMBER >= 0x20010000L
94
# if !defined(OPENSSL_NO_ECDH)
99
# if !defined(OPENSSL_NO_ECDH)
Lines 116-122 Link Here
116
# define DISABLE_OCSP
121
# define DISABLE_OCSP
117
#endif
122
#endif
118
123
119
#ifdef EXPERIMENTAL_TLS_RESUME
124
#ifndef DISABLE_TLS_RESUME
120
# if OPENSSL_VERSION_NUMBER < 0x0101010L
125
# if OPENSSL_VERSION_NUMBER < 0x0101010L
121
#  error OpenSSL version too old for session-resumption
126
#  error OpenSSL version too old for session-resumption
122
# endif
127
# endif
Lines 227-238 Link Here
227
  { US"no_tlsv1", SSL_OP_NO_TLSv1 },
232
  { US"no_tlsv1", SSL_OP_NO_TLSv1 },
228
#endif
233
#endif
229
#ifdef SSL_OP_NO_TLSv1_1
234
#ifdef SSL_OP_NO_TLSv1_1
230
#if SSL_OP_NO_TLSv1_1 == 0x00000400L
235
# if OPENSSL_VERSION_NUMBER < 0x30000000L
236
#  if SSL_OP_NO_TLSv1_1 == 0x00000400L
231
  /* Error in chosen value in 1.0.1a; see first item in CHANGES for 1.0.1b */
237
  /* Error in chosen value in 1.0.1a; see first item in CHANGES for 1.0.1b */
232
#warning OpenSSL 1.0.1a uses a bad value for SSL_OP_NO_TLSv1_1, ignoring
238
#   warning OpenSSL 1.0.1a uses a bad value for SSL_OP_NO_TLSv1_1, ignoring
233
#else
239
#   define NO_SSL_OP_NO_TLSv1_1
240
#  endif
241
# endif
242
# ifndef NO_SSL_OP_NO_TLSv1_1
234
  { US"no_tlsv1_1", SSL_OP_NO_TLSv1_1 },
243
  { US"no_tlsv1_1", SSL_OP_NO_TLSv1_1 },
235
#endif
244
# endif
236
#endif
245
#endif
237
#ifdef SSL_OP_NO_TLSv1_2
246
#ifdef SSL_OP_NO_TLSv1_2
238
  { US"no_tlsv1_2", SSL_OP_NO_TLSv1_2 },
247
  { US"no_tlsv1_2", SSL_OP_NO_TLSv1_2 },
Lines 274-279 Link Here
274
283
275
#ifndef MACRO_PREDEF
284
#ifndef MACRO_PREDEF
276
static int exim_openssl_options_size = nelem(exim_openssl_options);
285
static int exim_openssl_options_size = nelem(exim_openssl_options);
286
static long init_options = 0;
277
#endif
287
#endif
278
288
279
#ifdef MACRO_PREDEF
289
#ifdef MACRO_PREDEF
Lines 292-298 Link Here
292
  builtin_macro_create(buf);
302
  builtin_macro_create(buf);
293
  }
303
  }
294
304
295
# ifdef EXPERIMENTAL_TLS_RESUME
305
# ifndef DISABLE_TLS_RESUME
296
builtin_macro_create_var(US"_RESUME_DECODE", RESUME_DECODE_STRING );
306
builtin_macro_create_var(US"_RESUME_DECODE", RESUME_DECODE_STRING );
297
# endif
307
# endif
298
# ifdef SSL_OP_NO_TLSv1_3
308
# ifdef SSL_OP_NO_TLSv1_3
Lines 305-310 Link Here
305
builtin_macro_create(US"_HAVE_TLS_OCSP");
315
builtin_macro_create(US"_HAVE_TLS_OCSP");
306
builtin_macro_create(US"_HAVE_TLS_OCSP_LIST");
316
builtin_macro_create(US"_HAVE_TLS_OCSP_LIST");
307
# endif
317
# endif
318
# ifdef EXIM_HAVE_ALPN
319
builtin_macro_create(US"_HAVE_TLS_ALPN");
320
# endif
308
}
321
}
309
#else
322
#else
310
323
Lines 350-361 Link Here
350
  gstring *	corked;
363
  gstring *	corked;
351
} exim_openssl_client_tls_ctx;
364
} exim_openssl_client_tls_ctx;
352
365
353
static SSL_CTX *server_ctx = NULL;
366
354
static SSL     *server_ssl = NULL;
367
/* static SSL_CTX *server_ctx = NULL; */
368
/* static SSL     *server_ssl = NULL; */
355
369
356
#ifdef EXIM_HAVE_OPENSSL_TLSEXT
370
#ifdef EXIM_HAVE_OPENSSL_TLSEXT
357
static SSL_CTX *server_sni = NULL;
371
static SSL_CTX *server_sni = NULL;
358
#endif
372
#endif
373
#ifdef EXIM_HAVE_ALPN
374
static BOOL server_seen_alpn = FALSE;
375
#endif
359
376
360
static char ssl_errstring[256];
377
static char ssl_errstring[256];
361
378
Lines 371-377 Link Here
371
  OCSP_RESPONSE *	resp;
388
  OCSP_RESPONSE *	resp;
372
} ocsp_resplist;
389
} ocsp_resplist;
373
390
374
typedef struct tls_ext_ctx_cb {
391
typedef struct exim_openssl_state {
392
  exim_tlslib_state	lib_state;
393
#define lib_ctx			libdata0
394
#define lib_ssl			libdata1
395
375
  tls_support *	tlsp;
396
  tls_support *	tlsp;
376
  uschar *	certificate;
397
  uschar *	certificate;
377
  uschar *	privatekey;
398
  uschar *	privatekey;
Lines 399-420 Link Here
399
#ifndef DISABLE_EVENT
420
#ifndef DISABLE_EVENT
400
  uschar *	event_action;
421
  uschar *	event_action;
401
#endif
422
#endif
402
} tls_ext_ctx_cb;
423
} exim_openssl_state_st;
403
424
404
/* should figure out a cleanup of API to handle state preserved per
425
/* should figure out a cleanup of API to handle state preserved per
405
implementation, for various reasons, which can be void * in the APIs.
426
implementation, for various reasons, which can be void * in the APIs.
406
For now, we hack around it. */
427
For now, we hack around it. */
407
tls_ext_ctx_cb *client_static_cbinfo = NULL;	/*XXX should not use static; multiple concurrent clients! */
428
exim_openssl_state_st *client_static_state = NULL;	/*XXX should not use static; multiple concurrent clients! */
408
tls_ext_ctx_cb *server_static_cbinfo = NULL;
429
exim_openssl_state_st state_server = {.is_server = TRUE};
409
430
410
static int
431
static int
411
setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host, BOOL optional,
432
setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host,
412
    int (*cert_vfy_cb)(int, X509_STORE_CTX *), uschar ** errstr );
433
    uschar ** errstr );
413
434
414
/* Callbacks */
435
/* Callbacks */
415
#ifdef EXIM_HAVE_OPENSSL_TLSEXT
416
static int tls_servername_cb(SSL *s, int *ad ARG_UNUSED, void *arg);
417
#endif
418
#ifndef DISABLE_OCSP
436
#ifndef DISABLE_OCSP
419
static int tls_server_stapling_cb(SSL *s, void *arg);
437
static int tls_server_stapling_cb(SSL *s, void *arg);
420
#endif
438
#endif
Lines 422-439 Link Here
422
440
423
441
424
/* Daemon-called, before every connection, key create/rotate */
442
/* Daemon-called, before every connection, key create/rotate */
425
#ifdef EXPERIMENTAL_TLS_RESUME
443
#ifndef DISABLE_TLS_RESUME
426
static void tk_init(void);
444
static void tk_init(void);
427
static int tls_exdata_idx = -1;
445
static int tls_exdata_idx = -1;
428
#endif
446
#endif
429
447
430
void
448
static void
431
tls_daemon_init(void)
449
tls_per_lib_daemon_tick(void)
432
{
450
{
433
#ifdef EXPERIMENTAL_TLS_RESUME
451
#ifndef DISABLE_TLS_RESUME
434
tk_init();
452
tk_init();
435
#endif
453
#endif
436
return;
454
}
455
456
/* Called once at daemon startup */
457
458
static void
459
tls_per_lib_daemon_init(void)
460
{
461
tls_daemon_creds_reload();
437
}
462
}
438
463
439
464
Lines 475-484 Link Here
475
500
476
501
477
502
503
/**************************************************
504
* General library initalisation                   *
505
**************************************************/
506
507
static BOOL
508
lib_rand_init(void * addr)
509
{
510
randstuff r;
511
if (!RAND_status()) return TRUE;
512
513
gettimeofday(&r.tv, NULL);
514
r.p = getpid();
515
RAND_seed(US (&r), sizeof(r));
516
RAND_seed(US big_buffer, big_buffer_size);
517
if (addr) RAND_seed(US addr, sizeof(addr));
518
519
return RAND_status();
520
}
521
522
523
static void
524
tls_openssl_init(void)
525
{
526
static BOOL once = FALSE;
527
if (once) return;
528
once = TRUE;
529
530
#ifdef EXIM_NEED_OPENSSL_INIT
531
SSL_load_error_strings();          /* basic set up */
532
OpenSSL_add_ssl_algorithms();
533
#endif
534
535
#if defined(EXIM_HAVE_SHA256) && !defined(OPENSSL_AUTO_SHA256)
536
/* SHA256 is becoming ever more popular. This makes sure it gets added to the
537
list of available digests. */
538
EVP_add_digest(EVP_sha256());
539
#endif
540
541
(void) lib_rand_init(NULL);
542
(void) tls_openssl_options_parse(openssl_options, &init_options);
543
}
544
545
546
547
/*************************************************
548
*                Initialize for DH               *
549
*************************************************/
550
551
/* If dhparam is set, expand it, and load up the parameters for DH encryption.
552
Server only.
553
554
Arguments:
555
  sctx      The current SSL CTX (inbound or outbound)
556
  dhparam   DH parameter file or fixed parameter identity string
557
  errstr    error string pointer
558
559
Returns:    TRUE if OK (nothing to set up, or setup worked)
560
*/
561
562
static BOOL
563
init_dh(SSL_CTX * sctx, uschar * dhparam, uschar ** errstr)
564
{
565
BIO * bio;
566
#if OPENSSL_VERSION_NUMBER < 0x30000000L
567
DH * dh;
568
#else
569
EVP_PKEY * pkey;
570
#endif
571
uschar * dhexpanded;
572
const char * pem;
573
int dh_bitsize;
574
575
if (!expand_check(dhparam, US"tls_dhparam", &dhexpanded, errstr))
576
  return FALSE;
577
578
if (!dhexpanded || !*dhexpanded)
579
  bio = BIO_new_mem_buf(CS std_dh_prime_default(), -1);
580
else if (dhexpanded[0] == '/')
581
  {
582
  if (!(bio = BIO_new_file(CS dhexpanded, "r")))
583
    {
584
    tls_error(string_sprintf("could not read dhparams file %s", dhexpanded),
585
          NULL, US strerror(errno), errstr);
586
    return FALSE;
587
    }
588
  }
589
else
590
  {
591
  if (Ustrcmp(dhexpanded, "none") == 0)
592
    {
593
    DEBUG(D_tls) debug_printf("Requested no DH parameters.\n");
594
    return TRUE;
595
    }
596
597
  if (!(pem = std_dh_prime_named(dhexpanded)))
598
    {
599
    tls_error(string_sprintf("Unknown standard DH prime \"%s\"", dhexpanded),
600
        NULL, US strerror(errno), errstr);
601
    return FALSE;
602
    }
603
  bio = BIO_new_mem_buf(CS pem, -1);
604
  }
605
606
if (!(
607
#if OPENSSL_VERSION_NUMBER < 0x30000000L
608
      dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL)
609
#else
610
      pkey = PEM_read_bio_Parameters_ex(bio, NULL, NULL, NULL)
611
#endif
612
   ) )
613
  {
614
  BIO_free(bio);
615
  tls_error(string_sprintf("Could not read tls_dhparams \"%s\"", dhexpanded),
616
      NULL, NULL, errstr);
617
  return FALSE;
618
  }
619
620
/* note: our default limit of 2236 is not a multiple of 8; the limit comes from
621
an NSS limit, and the GnuTLS APIs handle bit-sizes fine, so we went with 2236.
622
But older OpenSSL can only report in bytes (octets), not bits.  If someone wants
623
to dance at the edge, then they can raise the limit or use current libraries. */
624
625
#if OPENSSL_VERSION_NUMBER < 0x30000000L
626
# ifdef EXIM_HAVE_OPENSSL_DH_BITS
627
/* Added in commit 26c79d5641d; `git describe --contains` says OpenSSL_1_1_0-pre1~1022
628
This predates OpenSSL_1_1_0 (before a, b, ...) so is in all 1.1.0 */
629
dh_bitsize = DH_bits(dh);
630
# else
631
dh_bitsize = 8 * DH_size(dh);
632
# endif
633
#else	/* 3.0.0 + */
634
dh_bitsize = EVP_PKEY_get_bits(pkey);
635
#endif
636
637
/* Even if it is larger, we silently return success rather than cause things to
638
fail out, so that a too-large DH will not knock out all TLS; it's a debatable
639
choice.  Likewise for a failing attempt to set one. */
640
641
if (dh_bitsize <= tls_dh_max_bits)
642
  {
643
  if (
644
#if OPENSSL_VERSION_NUMBER < 0x30000000L
645
      SSL_CTX_set_tmp_dh(sctx, dh)
646
#else
647
      SSL_CTX_set0_tmp_dh_pkey(sctx, pkey)
648
#endif
649
      == 0)
650
    {
651
    ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
652
    log_write(0, LOG_MAIN|LOG_PANIC, "TLS error (D-H param setting '%s'): %s",
653
	dhexpanded ? dhexpanded : US"default", ssl_errstring);
654
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
655
    /* EVP_PKEY_free(pkey);  crashes */
656
#endif
657
    }
658
  else
659
    DEBUG(D_tls)
660
      debug_printf("Diffie-Hellman initialized from %s with %d-bit prime\n",
661
	dhexpanded ? dhexpanded : US"default", dh_bitsize);
662
  }
663
else
664
  DEBUG(D_tls)
665
    debug_printf("dhparams '%s' %d bits, is > tls_dh_max_bits limit of %d\n",
666
	dhexpanded ? dhexpanded : US"default", dh_bitsize, tls_dh_max_bits);
667
668
#if OPENSSL_VERSION_NUMBER < 0x30000000L
669
DH_free(dh);
670
#endif
671
/* The EVP_PKEY ownership stays with the ctx; do not free it */
672
673
BIO_free(bio);
674
return TRUE;
675
}
676
677
678
679
680
/*************************************************
681
*               Initialize for ECDH              *
682
*************************************************/
683
684
/* Load parameters for ECDH encryption.  Server only.
685
686
For now, we stick to NIST P-256 because: it's simple and easy to configure;
687
it avoids any patent issues that might bite redistributors; despite events in
688
the news and concerns over curve choices, we're not cryptographers, we're not
689
pretending to be, and this is "good enough" to be better than no support,
690
protecting against most adversaries.  Given another year or two, there might
691
be sufficient clarity about a "right" way forward to let us make an informed
692
decision, instead of a knee-jerk reaction.
693
694
Longer-term, we should look at supporting both various named curves and
695
external files generated with "openssl ecparam", much as we do for init_dh().
696
We should also support "none" as a value, to explicitly avoid initialisation.
697
698
Patches welcome.
699
700
Arguments:
701
  sctx      The current SSL CTX (inbound or outbound)
702
  errstr    error string pointer
703
704
Returns:    TRUE if OK (nothing to set up, or setup worked)
705
*/
706
707
static BOOL
708
init_ecdh(SSL_CTX * sctx, uschar ** errstr)
709
{
710
#ifdef OPENSSL_NO_ECDH
711
return TRUE;
712
#else
713
714
uschar * exp_curve;
715
int nid;
716
BOOL rv;
717
718
# ifndef EXIM_HAVE_ECDH
719
DEBUG(D_tls)
720
  debug_printf("No OpenSSL API to define ECDH parameters, skipping\n");
721
return TRUE;
722
# else
723
724
if (!expand_check(tls_eccurve, US"tls_eccurve", &exp_curve, errstr))
725
  return FALSE;
726
if (!exp_curve || !*exp_curve)
727
  return TRUE;
728
729
/* "auto" needs to be handled carefully.
730
 * OpenSSL <  1.0.2: we do not select anything, but fallback to prime256v1
731
 * OpenSSL <  1.1.0: we have to call SSL_CTX_set_ecdh_auto
732
 *                   (openssl/ssl.h defines SSL_CTRL_SET_ECDH_AUTO)
733
 * OpenSSL >= 1.1.0: we do not set anything, the libray does autoselection
734
 *                   https://github.com/openssl/openssl/commit/fe6ef2472db933f01b59cad82aa925736935984b
735
 */
736
if (Ustrcmp(exp_curve, "auto") == 0)
737
  {
738
#if OPENSSL_VERSION_NUMBER < 0x10002000L
739
  DEBUG(D_tls) debug_printf(
740
    "ECDH OpenSSL < 1.0.2: temp key parameter settings: overriding \"auto\" with \"prime256v1\"\n");
741
  exp_curve = US"prime256v1";
742
#else
743
# if defined SSL_CTRL_SET_ECDH_AUTO
744
  DEBUG(D_tls) debug_printf(
745
    "ECDH OpenSSL 1.0.2+: temp key parameter settings: autoselection\n");
746
  SSL_CTX_set_ecdh_auto(sctx, 1);
747
  return TRUE;
748
# else
749
  DEBUG(D_tls) debug_printf(
750
    "ECDH OpenSSL 1.1.0+: temp key parameter settings: default selection\n");
751
  return TRUE;
752
# endif
753
#endif
754
  }
755
756
DEBUG(D_tls) debug_printf("ECDH: curve '%s'\n", exp_curve);
757
if (  (nid = OBJ_sn2nid       (CCS exp_curve)) == NID_undef
758
#   ifdef EXIM_HAVE_OPENSSL_EC_NIST2NID
759
   && (nid = EC_curve_nist2nid(CCS exp_curve)) == NID_undef
760
#   endif
761
   )
762
  {
763
  tls_error(string_sprintf("Unknown curve name tls_eccurve '%s'", exp_curve),
764
    NULL, NULL, errstr);
765
  return FALSE;
766
  }
767
768
# if OPENSSL_VERSION_NUMBER < 0x30000000L
769
 {
770
  EC_KEY * ecdh;
771
  if (!(ecdh = EC_KEY_new_by_curve_name(nid)))
772
    {
773
    tls_error(US"Unable to create ec curve", NULL, NULL, errstr);
774
    return FALSE;
775
    }
776
777
  /* The "tmp" in the name here refers to setting a temporary key
778
  not to the stability of the interface. */
779
780
  if ((rv = SSL_CTX_set_tmp_ecdh(sctx, ecdh) == 0))
781
    tls_error(string_sprintf("Error enabling '%s' curve", exp_curve), NULL, NULL, errstr);
782
  else
783
    DEBUG(D_tls) debug_printf("ECDH: enabled '%s' curve\n", exp_curve);
784
  EC_KEY_free(ecdh);
785
 }
786
787
#else	/* v 3.0.0 + */
788
789
if ((rv = SSL_CTX_set1_groups(sctx, &nid, 1)) == 0)
790
  tls_error(string_sprintf("Error enabling '%s' group", exp_curve), NULL, NULL, errstr);
791
else
792
  DEBUG(D_tls) debug_printf("ECDH: enabled '%s' group\n", exp_curve);
793
794
#endif
795
796
return !rv;
797
798
# endif	/*EXIM_HAVE_ECDH*/
799
#endif /*OPENSSL_NO_ECDH*/
800
}
801
802
803
478
/*************************************************
804
/*************************************************
479
*        Callback to generate RSA key            *
805
*        Expand key and cert file specs          *
480
*************************************************/
806
*************************************************/
481
807
808
#if OPENSSL_VERSION_NUMBER < 0x30000000L
482
/*
809
/*
483
Arguments:
810
Arguments:
484
  s          SSL connection (not used)
811
  s          SSL connection (not used)
Lines 496-512 Link Here
496
BIGNUM *bn = BN_new();
823
BIGNUM *bn = BN_new();
497
#endif
824
#endif
498
825
499
export = export;     /* Shut picky compilers up */
500
DEBUG(D_tls) debug_printf("Generating %d bit RSA key...\n", keylength);
826
DEBUG(D_tls) debug_printf("Generating %d bit RSA key...\n", keylength);
501
827
502
#ifdef EXIM_HAVE_RSA_GENKEY_EX
828
# ifdef EXIM_HAVE_RSA_GENKEY_EX
503
if (  !BN_set_word(bn, (unsigned long)RSA_F4)
829
if (  !BN_set_word(bn, (unsigned long)RSA_F4)
504
   || !(rsa_key = RSA_new())
830
   || !(rsa_key = RSA_new())
505
   || !RSA_generate_key_ex(rsa_key, keylength, bn, NULL)
831
   || !RSA_generate_key_ex(rsa_key, keylength, bn, NULL)
506
   )
832
   )
507
#else
833
# else
508
if (!(rsa_key = RSA_generate_key(keylength, RSA_F4, NULL, NULL)))
834
if (!(rsa_key = RSA_generate_key(keylength, RSA_F4, NULL, NULL)))
509
#endif
835
# endif
510
836
511
  {
837
  {
512
  ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
838
  ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
Lines 516-548 Link Here
516
  }
842
  }
517
return rsa_key;
843
return rsa_key;
518
}
844
}
845
#endif	/* pre-3.0.0 */
519
846
520
847
521
848
522
/* Extreme debug
849
/* Create and install a selfsigned certificate, for use in server mode */
523
#ifndef DISABLE_OCSP
850
/*XXX we could arrange to call this during prelo for a null tls_certificate option.
524
void
851
The normal cache inval + relo will suffice.
525
x509_store_dump_cert_s_names(X509_STORE * store)
852
Just need a timer for inval. */
853
854
static int
855
tls_install_selfsign(SSL_CTX * sctx, uschar ** errstr)
526
{
856
{
527
STACK_OF(X509_OBJECT) * roots= store->objs;
857
X509 * x509 = NULL;
528
static uschar name[256];
858
EVP_PKEY * pkey;
859
X509_NAME * name;
860
uschar * where;
529
861
530
for (int i= 0; i < sk_X509_OBJECT_num(roots); i++)
862
DEBUG(D_tls) debug_printf("TLS: generating selfsigned server cert\n");
863
where = US"allocating pkey";
864
if (!(pkey = EVP_PKEY_new()))
865
  goto err;
866
867
where = US"allocating cert";
868
if (!(x509 = X509_new()))
869
  goto err;
870
871
where = US"generating pkey";
872
#if OPENSSL_VERSION_NUMBER < 0x30000000L
873
 {
874
  RSA * rsa;
875
  if (!(rsa = rsa_callback(NULL, 0, 2048)))
876
    goto err;
877
878
  where = US"assigning pkey";
879
  if (!EVP_PKEY_assign_RSA(pkey, rsa))
880
    goto err;
881
 }
882
#else
883
pkey = EVP_RSA_gen(2048);
884
#endif
885
886
X509_set_version(x509, 2);				/* N+1 - version 3 */
887
ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
888
X509_gmtime_adj(X509_get_notBefore(x509), 0);
889
X509_gmtime_adj(X509_get_notAfter(x509), (long)2 * 60 * 60);	/* 2 hour */
890
X509_set_pubkey(x509, pkey);
891
892
name = X509_get_subject_name(x509);
893
X509_NAME_add_entry_by_txt(name, "C",
894
			  MBSTRING_ASC, CUS "UK", -1, -1, 0);
895
X509_NAME_add_entry_by_txt(name, "O",
896
			  MBSTRING_ASC, CUS "Exim Developers", -1, -1, 0);
897
X509_NAME_add_entry_by_txt(name, "CN",
898
			  MBSTRING_ASC, CUS smtp_active_hostname, -1, -1, 0);
899
X509_set_issuer_name(x509, name);
900
901
where = US"signing cert";
902
if (!X509_sign(x509, pkey, EVP_md5()))
903
  goto err;
904
905
where = US"installing selfsign cert";
906
if (!SSL_CTX_use_certificate(sctx, x509))
907
  goto err;
908
909
where = US"installing selfsign key";
910
if (!SSL_CTX_use_PrivateKey(sctx, pkey))
911
  goto err;
912
913
return OK;
914
915
err:
916
  (void) tls_error(where, NULL, NULL, errstr);
917
  if (x509) X509_free(x509);
918
  if (pkey) EVP_PKEY_free(pkey);
919
  return DEFER;
920
}
921
922
923
924
925
926
927
928
/*************************************************
929
*           Information callback                 *
930
*************************************************/
931
932
/* The SSL library functions call this from time to time to indicate what they
933
are doing. We copy the string to the debugging output when TLS debugging has
934
been requested.
935
936
Arguments:
937
  s         the SSL connection
938
  where
939
  ret
940
941
Returns:    nothing
942
*/
943
944
static void
945
info_callback(SSL *s, int where, int ret)
946
{
947
DEBUG(D_tls)
531
  {
948
  {
532
  X509_OBJECT * tmp_obj= sk_X509_OBJECT_value(roots, i);
949
  const uschar * str;
533
  if(tmp_obj->type == X509_LU_X509)
950
951
  if (where & SSL_ST_CONNECT)
952
     str = US"SSL_connect";
953
  else if (where & SSL_ST_ACCEPT)
954
     str = US"SSL_accept";
955
  else
956
     str = US"SSL info (undefined)";
957
958
  if (where & SSL_CB_LOOP)
959
     debug_printf("%s: %s\n", str, SSL_state_string_long(s));
960
  else if (where & SSL_CB_ALERT)
961
    debug_printf("SSL3 alert %s:%s:%s\n",
962
	  str = where & SSL_CB_READ ? US"read" : US"write",
963
	  SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret));
964
  else if (where & SSL_CB_EXIT)
534
    {
965
    {
535
    X509_NAME * sn = X509_get_subject_name(tmp_obj->data.x509);
966
    if (ret == 0)
536
    if (X509_NAME_oneline(sn, CS name, sizeof(name)))
967
      debug_printf("%s: failed in %s\n", str, SSL_state_string_long(s));
537
      {
968
    else if (ret < 0)
538
      name[sizeof(name)-1] = '\0';
969
      debug_printf("%s: error in %s\n", str, SSL_state_string_long(s));
539
      debug_printf(" %s\n", name);
540
      }
541
    }
970
    }
971
  else if (where & SSL_CB_HANDSHAKE_START)
972
     debug_printf("%s: hshake start: %s\n", str, SSL_state_string_long(s));
973
  else if (where & SSL_CB_HANDSHAKE_DONE)
974
     debug_printf("%s: hshake done: %s\n", str, SSL_state_string_long(s));
542
  }
975
  }
543
}
976
}
977
978
#ifdef OPENSSL_HAVE_KEYLOG_CB
979
static void
980
keylog_callback(const SSL *ssl, const char *line)
981
{
982
char * filename;
983
FILE * fp;
984
DEBUG(D_tls) debug_printf("%.200s\n", line);
985
if (!(filename = getenv("SSLKEYLOGFILE"))) return;
986
if (!(fp = fopen(filename, "a"))) return;
987
fprintf(fp, "%s\n", line);
988
fclose(fp);
989
}
544
#endif
990
#endif
545
*/
991
992
993
546
994
547
995
548
#ifndef DISABLE_EVENT
996
#ifndef DISABLE_EVENT
Lines 554-567 Link Here
554
uschar * yield;
1002
uschar * yield;
555
X509 * old_cert;
1003
X509 * old_cert;
556
1004
557
ev = tlsp == &tls_out ? client_static_cbinfo->event_action : event_action;
1005
ev = tlsp == &tls_out ? client_static_state->event_action : event_action;
558
if (ev)
1006
if (ev)
559
  {
1007
  {
560
  DEBUG(D_tls) debug_printf("verify_event: %s %d\n", what, depth);
1008
  DEBUG(D_tls) debug_printf("verify_event: %s %d\n", what, depth);
561
  old_cert = tlsp->peercert;
1009
  old_cert = tlsp->peercert;
562
  tlsp->peercert = X509_dup(cert);
1010
  tlsp->peercert = X509_dup(cert);
563
  /* NB we do not bother setting peerdn */
1011
  /* NB we do not bother setting peerdn */
564
  if ((yield = event_raise(ev, US"tls:cert", string_sprintf("%d", depth))))
1012
  if ((yield = event_raise(ev, US"tls:cert", string_sprintf("%d", depth), &errno)))
565
    {
1013
    {
566
    log_write(0, LOG_MAIN, "[%s] %s verify denied by event-action: "
1014
    log_write(0, LOG_MAIN, "[%s] %s verify denied by event-action: "
567
		"depth=%d cert=%s: %s",
1015
		"depth=%d cert=%s: %s",
Lines 661-675 Link Here
661
  {
1109
  {
662
  DEBUG(D_tls) debug_printf("SSL verify ok: depth=%d SN=%s\n", depth, dn);
1110
  DEBUG(D_tls) debug_printf("SSL verify ok: depth=%d SN=%s\n", depth, dn);
663
#ifndef DISABLE_OCSP
1111
#ifndef DISABLE_OCSP
664
  if (tlsp == &tls_out && client_static_cbinfo->u_ocsp.client.verify_store)
1112
  if (tlsp == &tls_out && client_static_state->u_ocsp.client.verify_store)
665
    {	/* client, wanting stapling  */
1113
    {	/* client, wanting stapling  */
666
    /* Add the server cert's signing chain as the one
1114
    /* Add the server cert's signing chain as the one
667
    for the verification of the OCSP stapled information. */
1115
    for the verification of the OCSP stapled information. */
668
1116
669
    if (!X509_STORE_add_cert(client_static_cbinfo->u_ocsp.client.verify_store,
1117
    if (!X509_STORE_add_cert(client_static_state->u_ocsp.client.verify_store,
670
                             cert))
1118
                             cert))
671
      ERR_clear_error();
1119
      ERR_clear_error();
672
    sk_X509_push(client_static_cbinfo->verify_stack, cert);
1120
    sk_X509_push(client_static_state->verify_stack, cert);
673
    }
1121
    }
674
#endif
1122
#endif
675
#ifndef DISABLE_EVENT
1123
#ifndef DISABLE_EVENT
Lines 682-688 Link Here
682
  const uschar * verify_cert_hostnames;
1130
  const uschar * verify_cert_hostnames;
683
1131
684
  if (  tlsp == &tls_out
1132
  if (  tlsp == &tls_out
685
     && ((verify_cert_hostnames = client_static_cbinfo->verify_cert_hostnames)))
1133
     && ((verify_cert_hostnames = client_static_state->verify_cert_hostnames)))
686
	/* client, wanting hostname check */
1134
	/* client, wanting hostname check */
687
    {
1135
    {
688
1136
Lines 802-816 Link Here
802
  {
1250
  {
803
  tls_out.dane_verified = TRUE;
1251
  tls_out.dane_verified = TRUE;
804
#ifndef DISABLE_OCSP
1252
#ifndef DISABLE_OCSP
805
  if (client_static_cbinfo->u_ocsp.client.verify_store)
1253
  if (client_static_state->u_ocsp.client.verify_store)
806
    {	/* client, wanting stapling  */
1254
    {	/* client, wanting stapling  */
807
    /* Add the server cert's signing chain as the one
1255
    /* Add the server cert's signing chain as the one
808
    for the verification of the OCSP stapled information. */
1256
    for the verification of the OCSP stapled information. */
809
1257
810
    if (!X509_STORE_add_cert(client_static_cbinfo->u_ocsp.client.verify_store,
1258
    if (!X509_STORE_add_cert(client_static_state->u_ocsp.client.verify_store,
811
                             cert))
1259
                             cert))
812
      ERR_clear_error();
1260
      ERR_clear_error();
813
    sk_X509_push(client_static_cbinfo->verify_stack, cert);
1261
    sk_X509_push(client_static_state->verify_stack, cert);
814
    }
1262
    }
815
#endif
1263
#endif
816
  }
1264
  }
Lines 828-1236 Link Here
828
#endif	/*SUPPORT_DANE*/
1276
#endif	/*SUPPORT_DANE*/
829
1277
830
1278
831
/*************************************************
832
*           Information callback                 *
833
*************************************************/
834
835
/* The SSL library functions call this from time to time to indicate what they
836
are doing. We copy the string to the debugging output when TLS debugging has
837
been requested.
838
839
Arguments:
840
  s         the SSL connection
841
  where
842
  ret
843
844
Returns:    nothing
845
*/
846
847
static void
848
info_callback(SSL *s, int where, int ret)
849
{
850
DEBUG(D_tls)
851
  {
852
  const uschar * str;
853
854
  if (where & SSL_ST_CONNECT)
855
     str = US"SSL_connect";
856
  else if (where & SSL_ST_ACCEPT)
857
     str = US"SSL_accept";
858
  else
859
     str = US"SSL info (undefined)";
860
861
  if (where & SSL_CB_LOOP)
862
     debug_printf("%s: %s\n", str, SSL_state_string_long(s));
863
  else if (where & SSL_CB_ALERT)
864
    debug_printf("SSL3 alert %s:%s:%s\n",
865
	  str = where & SSL_CB_READ ? US"read" : US"write",
866
	  SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret));
867
  else if (where & SSL_CB_EXIT)
868
     if (ret == 0)
869
	debug_printf("%s: failed in %s\n", str, SSL_state_string_long(s));
870
     else if (ret < 0)
871
	debug_printf("%s: error in %s\n", str, SSL_state_string_long(s));
872
  else if (where & SSL_CB_HANDSHAKE_START)
873
     debug_printf("%s: hshake start: %s\n", str, SSL_state_string_long(s));
874
  else if (where & SSL_CB_HANDSHAKE_DONE)
875
     debug_printf("%s: hshake done: %s\n", str, SSL_state_string_long(s));
876
  }
877
}
878
879
#ifdef OPENSSL_HAVE_KEYLOG_CB
880
static void
881
keylog_callback(const SSL *ssl, const char *line)
882
{
883
char * filename;
884
FILE * fp;
885
DEBUG(D_tls) debug_printf("%.200s\n", line);
886
if (!(filename = getenv("SSLKEYLOGFILE"))) return;
887
if (!(fp = fopen(filename, "a"))) return;
888
fprintf(fp, "%s\n", line);
889
fclose(fp);
890
}
891
#endif
892
893
894
#ifdef EXPERIMENTAL_TLS_RESUME
895
/* Manage the keysets used for encrypting the session tickets, on the server. */
896
897
typedef struct {			/* Session ticket encryption key */
898
  uschar 	name[16];
899
900
  const EVP_CIPHER *	aes_cipher;
901
  uschar		aes_key[32];	/* size needed depends on cipher. aes_128 implies 128/8 = 16? */
902
  const EVP_MD *	hmac_hash;
903
  uschar		hmac_key[16];
904
  time_t		renew;
905
  time_t		expire;
906
} exim_stek;
907
908
static exim_stek exim_tk;	/* current key */
909
static exim_stek exim_tk_old;	/* previous key */
910
911
static void
912
tk_init(void)
913
{
914
time_t t = time(NULL);
915
916
if (exim_tk.name[0])
917
  {
918
  if (exim_tk.renew >= t) return;
919
  exim_tk_old = exim_tk;
920
  }
921
922
if (f.running_in_test_harness) ssl_session_timeout = 6;
923
924
DEBUG(D_tls) debug_printf("OpenSSL: %s STEK\n", exim_tk.name[0] ? "rotating" : "creating");
925
if (RAND_bytes(exim_tk.aes_key, sizeof(exim_tk.aes_key)) <= 0) return;
926
if (RAND_bytes(exim_tk.hmac_key, sizeof(exim_tk.hmac_key)) <= 0) return;
927
if (RAND_bytes(exim_tk.name+1, sizeof(exim_tk.name)-1) <= 0) return;
928
929
exim_tk.name[0] = 'E';
930
exim_tk.aes_cipher = EVP_aes_256_cbc();
931
exim_tk.hmac_hash = EVP_sha256();
932
exim_tk.expire = t + ssl_session_timeout;
933
exim_tk.renew = t + ssl_session_timeout/2;
934
}
935
936
static exim_stek *
937
tk_current(void)
938
{
939
if (!exim_tk.name[0]) return NULL;
940
return &exim_tk;
941
}
942
943
static exim_stek *
944
tk_find(const uschar * name)
945
{
946
return memcmp(name, exim_tk.name, sizeof(exim_tk.name)) == 0 ? &exim_tk
947
  : memcmp(name, exim_tk_old.name, sizeof(exim_tk_old.name)) == 0 ? &exim_tk_old
948
  : NULL;
949
}
950
951
/* Callback for session tickets, on server */
952
static int
953
ticket_key_callback(SSL * ssl, uschar key_name[16],
954
  uschar * iv, EVP_CIPHER_CTX * ctx, HMAC_CTX * hctx, int enc)
955
{
956
tls_support * tlsp = server_static_cbinfo->tlsp;
957
exim_stek * key;
958
959
if (enc)
960
  {
961
  DEBUG(D_tls) debug_printf("ticket_key_callback: create new session\n");
962
  tlsp->resumption |= RESUME_CLIENT_REQUESTED;
963
964
  if (RAND_bytes(iv, EVP_MAX_IV_LENGTH) <= 0)
965
    return -1; /* insufficient random */
966
967
  if (!(key = tk_current()))	/* current key doesn't exist or isn't valid */
968
     return 0;			/* key couldn't be created */
969
  memcpy(key_name, key->name, 16);
970
  DEBUG(D_tls) debug_printf("STEK expire " TIME_T_FMT "\n", key->expire - time(NULL));
971
972
  /*XXX will want these dependent on the ssl session strength */
973
  HMAC_Init_ex(hctx, key->hmac_key, sizeof(key->hmac_key),
974
		key->hmac_hash, NULL);
975
  EVP_EncryptInit_ex(ctx, key->aes_cipher, NULL, key->aes_key, iv);
976
977
  DEBUG(D_tls) debug_printf("ticket created\n");
978
  return 1;
979
  }
980
else
981
  {
982
  time_t now = time(NULL);
983
984
  DEBUG(D_tls) debug_printf("ticket_key_callback: retrieve session\n");
985
  tlsp->resumption |= RESUME_CLIENT_SUGGESTED;
986
987
  if (!(key = tk_find(key_name)) || key->expire < now)
988
    {
989
    DEBUG(D_tls)
990
      {
991
      debug_printf("ticket not usable (%s)\n", key ? "expired" : "not found");
992
      if (key) debug_printf("STEK expire " TIME_T_FMT "\n", key->expire - now);
993
      }
994
    return 0;
995
    }
996
997
  HMAC_Init_ex(hctx, key->hmac_key, sizeof(key->hmac_key),
998
		key->hmac_hash, NULL);
999
  EVP_DecryptInit_ex(ctx, key->aes_cipher, NULL, key->aes_key, iv);
1000
1001
  DEBUG(D_tls) debug_printf("ticket usable, STEK expire " TIME_T_FMT "\n", key->expire - now);
1002
1003
  /* The ticket lifetime and renewal are the same as the STEK lifetime and
1004
  renewal, which is overenthusiastic.  A factor of, say, 3x longer STEK would
1005
  be better.  To do that we'd have to encode ticket lifetime in the name as
1006
  we don't yet see the restored session.  Could check posthandshake for TLS1.3
1007
  and trigger a new ticket then, but cannot do that for TLS1.2 */
1008
  return key->renew < now ? 2 : 1;
1009
  }
1010
}
1011
#endif
1012
1013
1014
1015
/*************************************************
1016
*                Initialize for DH               *
1017
*************************************************/
1018
1019
/* If dhparam is set, expand it, and load up the parameters for DH encryption.
1020
1021
Arguments:
1022
  sctx      The current SSL CTX (inbound or outbound)
1023
  dhparam   DH parameter file or fixed parameter identity string
1024
  host      connected host, if client; NULL if server
1025
  errstr    error string pointer
1026
1027
Returns:    TRUE if OK (nothing to set up, or setup worked)
1028
*/
1029
1030
static BOOL
1031
init_dh(SSL_CTX *sctx, uschar *dhparam, const host_item *host, uschar ** errstr)
1032
{
1033
BIO *bio;
1034
DH *dh;
1035
uschar *dhexpanded;
1036
const char *pem;
1037
int dh_bitsize;
1038
1039
if (!expand_check(dhparam, US"tls_dhparam", &dhexpanded, errstr))
1040
  return FALSE;
1041
1042
if (!dhexpanded || !*dhexpanded)
1043
  bio = BIO_new_mem_buf(CS std_dh_prime_default(), -1);
1044
else if (dhexpanded[0] == '/')
1045
  {
1046
  if (!(bio = BIO_new_file(CS dhexpanded, "r")))
1047
    {
1048
    tls_error(string_sprintf("could not read dhparams file %s", dhexpanded),
1049
          host, US strerror(errno), errstr);
1050
    return FALSE;
1051
    }
1052
  }
1053
else
1054
  {
1055
  if (Ustrcmp(dhexpanded, "none") == 0)
1056
    {
1057
    DEBUG(D_tls) debug_printf("Requested no DH parameters.\n");
1058
    return TRUE;
1059
    }
1060
1061
  if (!(pem = std_dh_prime_named(dhexpanded)))
1062
    {
1063
    tls_error(string_sprintf("Unknown standard DH prime \"%s\"", dhexpanded),
1064
        host, US strerror(errno), errstr);
1065
    return FALSE;
1066
    }
1067
  bio = BIO_new_mem_buf(CS pem, -1);
1068
  }
1069
1070
if (!(dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL)))
1071
  {
1072
  BIO_free(bio);
1073
  tls_error(string_sprintf("Could not read tls_dhparams \"%s\"", dhexpanded),
1074
      host, NULL, errstr);
1075
  return FALSE;
1076
  }
1077
1078
/* note: our default limit of 2236 is not a multiple of 8; the limit comes from
1079
 * an NSS limit, and the GnuTLS APIs handle bit-sizes fine, so we went with
1080
 * 2236.  But older OpenSSL can only report in bytes (octets), not bits.
1081
 * If someone wants to dance at the edge, then they can raise the limit or use
1082
 * current libraries. */
1083
#ifdef EXIM_HAVE_OPENSSL_DH_BITS
1084
/* Added in commit 26c79d5641d; `git describe --contains` says OpenSSL_1_1_0-pre1~1022
1085
 * This predates OpenSSL_1_1_0 (before a, b, ...) so is in all 1.1.0 */
1086
dh_bitsize = DH_bits(dh);
1087
#else
1088
dh_bitsize = 8 * DH_size(dh);
1089
#endif
1090
1091
/* Even if it is larger, we silently return success rather than cause things
1092
 * to fail out, so that a too-large DH will not knock out all TLS; it's a
1093
 * debatable choice. */
1094
if (dh_bitsize > tls_dh_max_bits)
1095
  {
1096
  DEBUG(D_tls)
1097
    debug_printf("dhparams file %d bits, is > tls_dh_max_bits limit of %d\n",
1098
        dh_bitsize, tls_dh_max_bits);
1099
  }
1100
else
1101
  {
1102
  SSL_CTX_set_tmp_dh(sctx, dh);
1103
  DEBUG(D_tls)
1104
    debug_printf("Diffie-Hellman initialized from %s with %d-bit prime\n",
1105
      dhexpanded ? dhexpanded : US"default", dh_bitsize);
1106
  }
1107
1108
DH_free(dh);
1109
BIO_free(bio);
1110
1111
return TRUE;
1112
}
1113
1114
1115
1116
1117
/*************************************************
1118
*               Initialize for ECDH              *
1119
*************************************************/
1120
1121
/* Load parameters for ECDH encryption.
1122
1123
For now, we stick to NIST P-256 because: it's simple and easy to configure;
1124
it avoids any patent issues that might bite redistributors; despite events in
1125
the news and concerns over curve choices, we're not cryptographers, we're not
1126
pretending to be, and this is "good enough" to be better than no support,
1127
protecting against most adversaries.  Given another year or two, there might
1128
be sufficient clarity about a "right" way forward to let us make an informed
1129
decision, instead of a knee-jerk reaction.
1130
1131
Longer-term, we should look at supporting both various named curves and
1132
external files generated with "openssl ecparam", much as we do for init_dh().
1133
We should also support "none" as a value, to explicitly avoid initialisation.
1134
1135
Patches welcome.
1136
1137
Arguments:
1138
  sctx      The current SSL CTX (inbound or outbound)
1139
  host      connected host, if client; NULL if server
1140
  errstr    error string pointer
1141
1142
Returns:    TRUE if OK (nothing to set up, or setup worked)
1143
*/
1144
1145
static BOOL
1146
init_ecdh(SSL_CTX * sctx, host_item * host, uschar ** errstr)
1147
{
1148
#ifdef OPENSSL_NO_ECDH
1149
return TRUE;
1150
#else
1151
1152
EC_KEY * ecdh;
1153
uschar * exp_curve;
1154
int nid;
1155
BOOL rv;
1156
1157
if (host)	/* No ECDH setup for clients, only for servers */
1158
  return TRUE;
1159
1160
# ifndef EXIM_HAVE_ECDH
1161
DEBUG(D_tls)
1162
  debug_printf("No OpenSSL API to define ECDH parameters, skipping\n");
1163
return TRUE;
1164
# else
1165
1166
if (!expand_check(tls_eccurve, US"tls_eccurve", &exp_curve, errstr))
1167
  return FALSE;
1168
if (!exp_curve || !*exp_curve)
1169
  return TRUE;
1170
1171
/* "auto" needs to be handled carefully.
1172
 * OpenSSL <  1.0.2: we do not select anything, but fallback to prime256v1
1173
 * OpenSSL <  1.1.0: we have to call SSL_CTX_set_ecdh_auto
1174
 *                   (openssl/ssl.h defines SSL_CTRL_SET_ECDH_AUTO)
1175
 * OpenSSL >= 1.1.0: we do not set anything, the libray does autoselection
1176
 *                   https://github.com/openssl/openssl/commit/fe6ef2472db933f01b59cad82aa925736935984b
1177
 */
1178
if (Ustrcmp(exp_curve, "auto") == 0)
1179
  {
1180
#if OPENSSL_VERSION_NUMBER < 0x10002000L
1181
  DEBUG(D_tls) debug_printf(
1182
    "ECDH OpenSSL < 1.0.2: temp key parameter settings: overriding \"auto\" with \"prime256v1\"\n");
1183
  exp_curve = US"prime256v1";
1184
#else
1185
# if defined SSL_CTRL_SET_ECDH_AUTO
1186
  DEBUG(D_tls) debug_printf(
1187
    "ECDH OpenSSL 1.0.2+ temp key parameter settings: autoselection\n");
1188
  SSL_CTX_set_ecdh_auto(sctx, 1);
1189
  return TRUE;
1190
# else
1191
  DEBUG(D_tls) debug_printf(
1192
    "ECDH OpenSSL 1.1.0+ temp key parameter settings: default selection\n");
1193
  return TRUE;
1194
# endif
1195
#endif
1196
  }
1197
1198
DEBUG(D_tls) debug_printf("ECDH: curve '%s'\n", exp_curve);
1199
if (  (nid = OBJ_sn2nid       (CCS exp_curve)) == NID_undef
1200
#   ifdef EXIM_HAVE_OPENSSL_EC_NIST2NID
1201
   && (nid = EC_curve_nist2nid(CCS exp_curve)) == NID_undef
1202
#   endif
1203
   )
1204
  {
1205
  tls_error(string_sprintf("Unknown curve name tls_eccurve '%s'", exp_curve),
1206
    host, NULL, errstr);
1207
  return FALSE;
1208
  }
1209
1210
if (!(ecdh = EC_KEY_new_by_curve_name(nid)))
1211
  {
1212
  tls_error(US"Unable to create ec curve", host, NULL, errstr);
1213
  return FALSE;
1214
  }
1215
1216
/* The "tmp" in the name here refers to setting a temporary key
1217
not to the stability of the interface. */
1218
1219
if ((rv = SSL_CTX_set_tmp_ecdh(sctx, ecdh) == 0))
1220
  tls_error(string_sprintf("Error enabling '%s' curve", exp_curve), host, NULL, errstr);
1221
else
1222
  DEBUG(D_tls) debug_printf("ECDH: enabled '%s' curve\n", exp_curve);
1223
1224
EC_KEY_free(ecdh);
1225
return !rv;
1226
1227
# endif	/*EXIM_HAVE_ECDH*/
1228
#endif /*OPENSSL_NO_ECDH*/
1229
}
1230
1231
1232
1233
1234
#ifndef DISABLE_OCSP
1279
#ifndef DISABLE_OCSP
1235
/*************************************************
1280
/*************************************************
1236
*       Load OCSP information into state         *
1281
*       Load OCSP information into state         *
Lines 1242-1257 Link Here
1242
ASSUMES: single response, for single cert.
1287
ASSUMES: single response, for single cert.
1243
1288
1244
Arguments:
1289
Arguments:
1245
  sctx            the SSL_CTX* to update
1290
  state           various parts of session state
1246
  cbinfo          various parts of session state
1247
  filename        the filename putatively holding an OCSP response
1291
  filename        the filename putatively holding an OCSP response
1248
  is_pem	  file is PEM format; otherwise is DER
1292
  is_pem	  file is PEM format; otherwise is DER
1249
1250
*/
1293
*/
1251
1294
1252
static void
1295
static void
1253
ocsp_load_response(SSL_CTX * sctx, tls_ext_ctx_cb * cbinfo,
1296
ocsp_load_response(exim_openssl_state_st * state, const uschar * filename,
1254
  const uschar * filename, BOOL is_pem)
1297
  BOOL is_pem)
1255
{
1298
{
1256
BIO * bio;
1299
BIO * bio;
1257
OCSP_RESPONSE * resp;
1300
OCSP_RESPONSE * resp;
Lines 1265-1274 Link Here
1265
DEBUG(D_tls)
1308
DEBUG(D_tls)
1266
  debug_printf("tls_ocsp_file (%s)  '%s'\n", is_pem ? "PEM" : "DER", filename);
1309
  debug_printf("tls_ocsp_file (%s)  '%s'\n", is_pem ? "PEM" : "DER", filename);
1267
1310
1311
if (!filename || !*filename) return;
1312
1313
ERR_clear_error();
1268
if (!(bio = BIO_new_file(CS filename, "rb")))
1314
if (!(bio = BIO_new_file(CS filename, "rb")))
1269
  {
1315
  {
1270
  DEBUG(D_tls) debug_printf("Failed to open OCSP response file \"%s\"\n",
1316
  log_write(0, LOG_MAIN|LOG_PANIC,
1271
      filename);
1317
    "Failed to open OCSP response file \"%s\": %.100s",
1318
    filename, ERR_reason_error_string(ERR_get_error()));
1272
  return;
1319
  return;
1273
  }
1320
  }
1274
1321
Lines 1279-1289 Link Here
1279
  long len;
1326
  long len;
1280
  if (!PEM_read_bio(bio, &dummy, &dummy, &data, &len))
1327
  if (!PEM_read_bio(bio, &dummy, &dummy, &data, &len))
1281
    {
1328
    {
1282
    DEBUG(D_tls) debug_printf("Failed to read PEM file \"%s\"\n",
1329
    log_write(0, LOG_MAIN|LOG_PANIC, "Failed to read PEM file \"%s\": %.100s",
1283
	filename);
1330
      filename, ERR_reason_error_string(ERR_get_error()));
1284
    return;
1331
    return;
1285
    }
1332
    }
1286
debug_printf("read pem file\n");
1287
  freep = data;
1333
  freep = data;
1288
  resp = d2i_OCSP_RESPONSE(NULL, CUSS &data, len);
1334
  resp = d2i_OCSP_RESPONSE(NULL, CUSS &data, len);
1289
  OPENSSL_free(freep);
1335
  OPENSSL_free(freep);
Lines 1294-1300 Link Here
1294
1340
1295
if (!resp)
1341
if (!resp)
1296
  {
1342
  {
1297
  DEBUG(D_tls) debug_printf("Error reading OCSP response.\n");
1343
  log_write(0, LOG_MAIN|LOG_PANIC, "Error reading OCSP response from \"%s\": %s",
1344
      filename, ERR_reason_error_string(ERR_get_error()));
1298
  return;
1345
  return;
1299
  }
1346
  }
1300
1347
Lines 1320-1326 Link Here
1320
  goto bad;
1367
  goto bad;
1321
  }
1368
  }
1322
1369
1323
sk = cbinfo->verify_stack;
1370
sk = state->verify_stack;
1324
verify_flags = OCSP_NOVERIFY; /* check sigs, but not purpose */
1371
verify_flags = OCSP_NOVERIFY; /* check sigs, but not purpose */
1325
1372
1326
/* May need to expose ability to adjust those flags?
1373
/* May need to expose ability to adjust those flags?
Lines 1396-1405 Link Here
1396
supply_response:
1443
supply_response:
1397
  /* Add the resp to the list used by tls_server_stapling_cb() */
1444
  /* Add the resp to the list used by tls_server_stapling_cb() */
1398
  {
1445
  {
1399
  ocsp_resplist ** op = &cbinfo->u_ocsp.server.olist, * oentry;
1446
  ocsp_resplist ** op = &state->u_ocsp.server.olist, * oentry;
1400
  while (oentry = *op)
1447
  while (oentry = *op)
1401
    op = &oentry->next;
1448
    op = &oentry->next;
1402
  *op = oentry = store_get(sizeof(ocsp_resplist), FALSE);
1449
  *op = oentry = store_get(sizeof(ocsp_resplist), GET_UNTAINTED);
1403
  oentry->next = NULL;
1450
  oentry->next = NULL;
1404
  oentry->resp = resp;
1451
  oentry->resp = resp;
1405
  }
1452
  }
Lines 1421-1427 Link Here
1421
1468
1422
1469
1423
static void
1470
static void
1424
ocsp_free_response_list(tls_ext_ctx_cb * cbinfo)
1471
ocsp_free_response_list(exim_openssl_state_st * cbinfo)
1425
{
1472
{
1426
for (ocsp_resplist * olist = cbinfo->u_ocsp.server.olist; olist;
1473
for (ocsp_resplist * olist = cbinfo->u_ocsp.server.olist; olist;
1427
     olist = olist->next)
1474
     olist = olist->next)
Lines 1433-1506 Link Here
1433
1480
1434
1481
1435
1482
1436
/* Create and install a selfsigned certificate, for use in server mode */
1437
1438
static int
1439
tls_install_selfsign(SSL_CTX * sctx, uschar ** errstr)
1440
{
1441
X509 * x509 = NULL;
1442
EVP_PKEY * pkey;
1443
RSA * rsa;
1444
X509_NAME * name;
1445
uschar * where;
1446
1447
where = US"allocating pkey";
1448
if (!(pkey = EVP_PKEY_new()))
1449
  goto err;
1450
1451
where = US"allocating cert";
1452
if (!(x509 = X509_new()))
1453
  goto err;
1454
1455
where = US"generating pkey";
1456
if (!(rsa = rsa_callback(NULL, 0, 2048)))
1457
  goto err;
1458
1459
where = US"assigning pkey";
1460
if (!EVP_PKEY_assign_RSA(pkey, rsa))
1461
  goto err;
1462
1463
X509_set_version(x509, 2);				/* N+1 - version 3 */
1464
ASN1_INTEGER_set(X509_get_serialNumber(x509), 1);
1465
X509_gmtime_adj(X509_get_notBefore(x509), 0);
1466
X509_gmtime_adj(X509_get_notAfter(x509), (long)60 * 60);	/* 1 hour */
1467
X509_set_pubkey(x509, pkey);
1468
1469
name = X509_get_subject_name(x509);
1470
X509_NAME_add_entry_by_txt(name, "C",
1471
			  MBSTRING_ASC, CUS "UK", -1, -1, 0);
1472
X509_NAME_add_entry_by_txt(name, "O",
1473
			  MBSTRING_ASC, CUS "Exim Developers", -1, -1, 0);
1474
X509_NAME_add_entry_by_txt(name, "CN",
1475
			  MBSTRING_ASC, CUS smtp_active_hostname, -1, -1, 0);
1476
X509_set_issuer_name(x509, name);
1477
1478
where = US"signing cert";
1479
if (!X509_sign(x509, pkey, EVP_md5()))
1480
  goto err;
1481
1482
where = US"installing selfsign cert";
1483
if (!SSL_CTX_use_certificate(sctx, x509))
1484
  goto err;
1485
1486
where = US"installing selfsign key";
1487
if (!SSL_CTX_use_PrivateKey(sctx, pkey))
1488
  goto err;
1489
1490
return OK;
1491
1492
err:
1493
  (void) tls_error(where, NULL, NULL, errstr);
1494
  if (x509) X509_free(x509);
1495
  if (pkey) EVP_PKEY_free(pkey);
1496
  return DEFER;
1497
}
1498
1499
1500
1501
1483
1502
static int
1484
static int
1503
tls_add_certfile(SSL_CTX * sctx, tls_ext_ctx_cb * cbinfo, uschar * file,
1485
tls_add_certfile(SSL_CTX * sctx, exim_openssl_state_st * cbinfo, uschar * file,
1504
  uschar ** errstr)
1486
  uschar ** errstr)
1505
{
1487
{
1506
DEBUG(D_tls) debug_printf("tls_certificate file '%s'\n", file);
1488
DEBUG(D_tls) debug_printf("tls_certificate file '%s'\n", file);
Lines 1512-1518 Link Here
1512
}
1494
}
1513
1495
1514
static int
1496
static int
1515
tls_add_pkeyfile(SSL_CTX * sctx, tls_ext_ctx_cb * cbinfo, uschar * file,
1497
tls_add_pkeyfile(SSL_CTX * sctx, exim_openssl_state_st * cbinfo, uschar * file,
1516
  uschar ** errstr)
1498
  uschar ** errstr)
1517
{
1499
{
1518
DEBUG(D_tls) debug_printf("tls_privatekey file  '%s'\n", file);
1500
DEBUG(D_tls) debug_printf("tls_privatekey file  '%s'\n", file);
Lines 1523-1531 Link Here
1523
}
1505
}
1524
1506
1525
1507
1526
/*************************************************
1508
1527
*        Expand key and cert file specs          *
1528
*************************************************/
1529
1509
1530
/* Called once during tls_init and possibly again during TLS setup, for a
1510
/* Called once during tls_init and possibly again during TLS setup, for a
1531
new context, if Server Name Indication was used and tls_sni was seen in
1511
new context, if Server Name Indication was used and tls_sni was seen in
Lines 1533-1553 Link Here
1533
1513
1534
Arguments:
1514
Arguments:
1535
  sctx            the SSL_CTX* to update
1515
  sctx            the SSL_CTX* to update
1536
  cbinfo          various parts of session state
1516
  state           various parts of session state
1537
  errstr	  error string pointer
1517
  errstr	  error string pointer
1538
1518
1539
Returns:          OK/DEFER/FAIL
1519
Returns:          OK/DEFER/FAIL
1540
*/
1520
*/
1541
1521
1542
static int
1522
static int
1543
tls_expand_session_files(SSL_CTX * sctx, tls_ext_ctx_cb * cbinfo,
1523
tls_expand_session_files(SSL_CTX * sctx, exim_openssl_state_st * state,
1544
  uschar ** errstr)
1524
  uschar ** errstr)
1545
{
1525
{
1546
uschar * expanded;
1526
uschar * expanded;
1547
1527
1548
if (!cbinfo->certificate)
1528
if (!state->certificate)
1549
  {
1529
  {
1550
  if (!cbinfo->is_server)		/* client */
1530
  if (!state->is_server)		/* client */
1551
    return OK;
1531
    return OK;
1552
					/* server */
1532
					/* server */
1553
  if (tls_install_selfsign(sctx, errstr) != OK)
1533
  if (tls_install_selfsign(sctx, errstr) != OK)
Lines 1558-1580 Link Here
1558
  int err;
1538
  int err;
1559
1539
1560
  if ( !reexpand_tls_files_for_sni
1540
  if ( !reexpand_tls_files_for_sni
1561
     && (  Ustrstr(cbinfo->certificate, US"tls_sni")
1541
     && (  Ustrstr(state->certificate, US"tls_sni")
1562
	|| Ustrstr(cbinfo->certificate, US"tls_in_sni")
1542
	|| Ustrstr(state->certificate, US"tls_in_sni")
1563
	|| Ustrstr(cbinfo->certificate, US"tls_out_sni")
1543
	|| Ustrstr(state->certificate, US"tls_out_sni")
1564
     )  )
1544
     )  )
1565
    reexpand_tls_files_for_sni = TRUE;
1545
    reexpand_tls_files_for_sni = TRUE;
1566
1546
1567
  if (!expand_check(cbinfo->certificate, US"tls_certificate", &expanded, errstr))
1547
  if (!expand_check(state->certificate, US"tls_certificate", &expanded, errstr))
1568
    return DEFER;
1548
    return DEFER;
1569
1549
1570
  if (expanded)
1550
  if (expanded)
1571
    if (cbinfo->is_server)
1551
    if (state->is_server)
1572
      {
1552
      {
1573
      const uschar * file_list = expanded;
1553
      const uschar * file_list = expanded;
1574
      int sep = 0;
1554
      int sep = 0;
1575
      uschar * file;
1555
      uschar * file;
1576
#ifndef DISABLE_OCSP
1556
#ifndef DISABLE_OCSP
1577
      const uschar * olist = cbinfo->u_ocsp.server.file;
1557
      const uschar * olist = state->u_ocsp.server.file;
1578
      int osep = 0;
1558
      int osep = 0;
1579
      uschar * ofile;
1559
      uschar * ofile;
1580
      BOOL fmt_pem = FALSE;
1560
      BOOL fmt_pem = FALSE;
Lines 1585-1606 Link Here
1585
      if (olist && !*olist)
1565
      if (olist && !*olist)
1586
	olist = NULL;
1566
	olist = NULL;
1587
1567
1588
      if (  cbinfo->u_ocsp.server.file_expanded && olist
1568
      if (  state->u_ocsp.server.file_expanded && olist
1589
	 && (Ustrcmp(olist, cbinfo->u_ocsp.server.file_expanded) == 0))
1569
	 && (Ustrcmp(olist, state->u_ocsp.server.file_expanded) == 0))
1590
	{
1570
	{
1591
	DEBUG(D_tls) debug_printf(" - value unchanged, using existing values\n");
1571
	DEBUG(D_tls) debug_printf(" - value unchanged, using existing values\n");
1592
	olist = NULL;
1572
	olist = NULL;
1593
	}
1573
	}
1594
      else
1574
      else
1595
	{
1575
	{
1596
	ocsp_free_response_list(cbinfo);
1576
	ocsp_free_response_list(state);
1597
	cbinfo->u_ocsp.server.file_expanded = olist;
1577
	state->u_ocsp.server.file_expanded = olist;
1598
	}
1578
	}
1599
#endif
1579
#endif
1600
1580
1601
      while (file = string_nextinlist(&file_list, &sep, NULL, 0))
1581
      while (file = string_nextinlist(&file_list, &sep, NULL, 0))
1602
	{
1582
	{
1603
	if ((err = tls_add_certfile(sctx, cbinfo, file, errstr)))
1583
	if ((err = tls_add_certfile(sctx, state, file, errstr)))
1604
	  return err;
1584
	  return err;
1605
1585
1606
#ifndef DISABLE_OCSP
1586
#ifndef DISABLE_OCSP
Lines 1617-1623 Link Here
1617
	      fmt_pem = FALSE;
1597
	      fmt_pem = FALSE;
1618
	      ofile += 4;
1598
	      ofile += 4;
1619
	      }
1599
	      }
1620
	    ocsp_load_response(sctx, cbinfo, ofile, fmt_pem);
1600
	    ocsp_load_response(state, ofile, fmt_pem);
1621
	    }
1601
	    }
1622
	  else
1602
	  else
1623
	    DEBUG(D_tls) debug_printf("ran out of ocsp file list\n");
1603
	    DEBUG(D_tls) debug_printf("ran out of ocsp file list\n");
Lines 1625-1635 Link Here
1625
	}
1605
	}
1626
      }
1606
      }
1627
    else	/* would there ever be a need for multiple client certs? */
1607
    else	/* would there ever be a need for multiple client certs? */
1628
      if ((err = tls_add_certfile(sctx, cbinfo, expanded, errstr)))
1608
      if ((err = tls_add_certfile(sctx, state, expanded, errstr)))
1629
	return err;
1609
	return err;
1630
1610
1631
  if (  cbinfo->privatekey
1611
  if (  state->privatekey
1632
     && !expand_check(cbinfo->privatekey, US"tls_privatekey", &expanded, errstr))
1612
     && !expand_check(state->privatekey, US"tls_privatekey", &expanded, errstr))
1633
    return DEFER;
1613
    return DEFER;
1634
1614
1635
  /* If expansion was forced to fail, key_expanded will be NULL. If the result
1615
  /* If expansion was forced to fail, key_expanded will be NULL. If the result
Lines 1637-1654 Link Here
1637
  key is in the same file as the certificate. */
1617
  key is in the same file as the certificate. */
1638
1618
1639
  if (expanded && *expanded)
1619
  if (expanded && *expanded)
1640
    if (cbinfo->is_server)
1620
    if (state->is_server)
1641
      {
1621
      {
1642
      const uschar * file_list = expanded;
1622
      const uschar * file_list = expanded;
1643
      int sep = 0;
1623
      int sep = 0;
1644
      uschar * file;
1624
      uschar * file;
1645
1625
1646
      while (file = string_nextinlist(&file_list, &sep, NULL, 0))
1626
      while (file = string_nextinlist(&file_list, &sep, NULL, 0))
1647
	if ((err = tls_add_pkeyfile(sctx, cbinfo, file, errstr)))
1627
	if ((err = tls_add_pkeyfile(sctx, state, file, errstr)))
1648
	  return err;
1628
	  return err;
1649
      }
1629
      }
1650
    else	/* would there ever be a need for multiple client certs? */
1630
    else	/* would there ever be a need for multiple client certs? */
1651
      if ((err = tls_add_pkeyfile(sctx, cbinfo, expanded, errstr)))
1631
      if ((err = tls_add_pkeyfile(sctx, state, expanded, errstr)))
1652
	return err;
1632
	return err;
1653
  }
1633
  }
1654
1634
Lines 1658-1663 Link Here
1658
1638
1659
1639
1660
1640
1641
/**************************************************
1642
* One-time init credentials for server and client *
1643
**************************************************/
1644
1645
static void
1646
normalise_ciphers(uschar ** ciphers, const uschar * pre_expansion_ciphers)
1647
{
1648
uschar * s = *ciphers;
1649
1650
if (!s || !Ustrchr(s, '_')) return;	/* no change needed */
1651
1652
if (s == pre_expansion_ciphers)
1653
  s = string_copy(s);			/* get writable copy */
1654
1655
for (uschar * t = s; *t; t++) if (*t == '_') *t = '-';
1656
*ciphers = s;
1657
}
1658
1659
static int
1660
server_load_ciphers(SSL_CTX * ctx, exim_openssl_state_st * state,
1661
  uschar * ciphers, uschar ** errstr)
1662
{
1663
DEBUG(D_tls) debug_printf("required ciphers: %s\n", ciphers);
1664
if (!SSL_CTX_set_cipher_list(ctx, CS ciphers))
1665
  return tls_error(US"SSL_CTX_set_cipher_list", NULL, NULL, errstr);
1666
state->server_cipher_list = ciphers;
1667
return OK;
1668
}
1669
1670
1671
1672
static int
1673
lib_ctx_new(SSL_CTX ** ctxp, host_item * host, uschar ** errstr)
1674
{
1675
SSL_CTX * ctx;
1676
#ifdef EXIM_HAVE_OPENSSL_TLS_METHOD
1677
if (!(ctx = SSL_CTX_new(host ? TLS_client_method() : TLS_server_method())))
1678
#else
1679
if (!(ctx = SSL_CTX_new(host ? SSLv23_client_method() : SSLv23_server_method())))
1680
#endif
1681
  return tls_error(US"SSL_CTX_new", host, NULL, errstr);
1682
1683
/* Set up the information callback, which outputs if debugging is at a suitable
1684
level. */
1685
1686
DEBUG(D_tls)
1687
  {
1688
  SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
1689
#if defined(EXIM_HAVE_OPESSL_TRACE) && !defined(OPENSSL_NO_SSL_TRACE)
1690
  /* this needs a debug build of OpenSSL */
1691
  SSL_CTX_set_msg_callback(ctx, (void (*)())SSL_trace);
1692
#endif
1693
#ifdef OPENSSL_HAVE_KEYLOG_CB
1694
  SSL_CTX_set_keylog_callback(ctx, (void (*)())keylog_callback);
1695
#endif
1696
  }
1697
1698
/* Automatically re-try reads/writes after renegotiation. */
1699
(void) SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
1700
*ctxp = ctx;
1701
return OK;
1702
}
1703
1704
1705
static unsigned
1706
tls_server_creds_init(void)
1707
{
1708
SSL_CTX * ctx;
1709
uschar * dummy_errstr;
1710
unsigned lifetime = 0;
1711
1712
tls_openssl_init();
1713
1714
state_server.lib_state = null_tls_preload;
1715
1716
if (lib_ctx_new(&ctx, NULL, &dummy_errstr) != OK)
1717
  return 0;
1718
state_server.lib_state.lib_ctx = ctx;
1719
1720
/* Preload DH params and EC curve */
1721
1722
if (opt_unset_or_noexpand(tls_dhparam))
1723
  {
1724
  DEBUG(D_tls) debug_printf("TLS: preloading DH params for server\n");
1725
  if (init_dh(ctx, tls_dhparam, &dummy_errstr))
1726
    state_server.lib_state.dh = TRUE;
1727
  }
1728
else
1729
  DEBUG(D_tls) debug_printf("TLS: not preloading DH params for server\n");
1730
if (opt_unset_or_noexpand(tls_eccurve))
1731
  {
1732
  DEBUG(D_tls) debug_printf("TLS: preloading ECDH curve for server\n");
1733
  if (init_ecdh(ctx, &dummy_errstr))
1734
    state_server.lib_state.ecdh = TRUE;
1735
  }
1736
else
1737
  DEBUG(D_tls) debug_printf("TLS: not preloading ECDH curve for server\n");
1738
1739
#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
1740
/* If we can, preload the server-side cert, key and ocsp */
1741
1742
if (  opt_set_and_noexpand(tls_certificate)
1743
# ifndef DISABLE_OCSP
1744
   && opt_unset_or_noexpand(tls_ocsp_file)
1745
#endif
1746
   && opt_unset_or_noexpand(tls_privatekey))
1747
  {
1748
  /* Set watches on the filenames.  The implementation does de-duplication
1749
  so we can just blindly do them all.  */
1750
1751
  if (  tls_set_watch(tls_certificate, TRUE)
1752
# ifndef DISABLE_OCSP
1753
     && tls_set_watch(tls_ocsp_file, TRUE)
1754
#endif
1755
     && tls_set_watch(tls_privatekey, TRUE))
1756
    {
1757
    state_server.certificate = tls_certificate;
1758
    state_server.privatekey = tls_privatekey;
1759
#ifndef DISABLE_OCSP
1760
    state_server.u_ocsp.server.file = tls_ocsp_file;
1761
#endif
1762
1763
    DEBUG(D_tls) debug_printf("TLS: preloading server certs\n");
1764
    if (tls_expand_session_files(ctx, &state_server, &dummy_errstr) == OK)
1765
      state_server.lib_state.conn_certs = TRUE;
1766
    }
1767
  }
1768
else if (  !tls_certificate && !tls_privatekey
1769
# ifndef DISABLE_OCSP
1770
	&& !tls_ocsp_file
1771
#endif
1772
   )
1773
  {		/* Generate & preload a selfsigned cert. No files to watch. */
1774
  if (tls_expand_session_files(ctx, &state_server, &dummy_errstr) == OK)
1775
    {
1776
    state_server.lib_state.conn_certs = TRUE;
1777
    lifetime = f.running_in_test_harness ? 2 : 60 * 60;		/* 1 hour */
1778
    }
1779
  }
1780
else
1781
  DEBUG(D_tls) debug_printf("TLS: not preloading server certs\n");
1782
1783
1784
/* If we can, preload the Authorities for checking client certs against.
1785
Actual choice to do verify is made (tls_{,try_}verify_hosts)
1786
at TLS conn startup */
1787
1788
if (  opt_set_and_noexpand(tls_verify_certificates)
1789
   && opt_unset_or_noexpand(tls_crl))
1790
  {
1791
  /* Watch the default dir also as they are always included */
1792
1793
  if (  tls_set_watch(CUS X509_get_default_cert_file(), FALSE)
1794
     && tls_set_watch(tls_verify_certificates, FALSE)
1795
     && tls_set_watch(tls_crl, FALSE))
1796
    {
1797
    DEBUG(D_tls) debug_printf("TLS: preloading CA bundle for server\n");
1798
1799
    if (setup_certs(ctx, tls_verify_certificates, tls_crl, NULL, &dummy_errstr)
1800
	== OK)
1801
      state_server.lib_state.cabundle = TRUE;
1802
    }
1803
  }
1804
else
1805
  DEBUG(D_tls) debug_printf("TLS: not preloading CA bundle for server\n");
1806
#endif	/* EXIM_HAVE_INOTIFY */
1807
1808
1809
/* If we can, preload the ciphers control string */
1810
1811
if (opt_set_and_noexpand(tls_require_ciphers))
1812
  {
1813
  DEBUG(D_tls) debug_printf("TLS: preloading cipher list for server\n");
1814
  normalise_ciphers(&tls_require_ciphers, tls_require_ciphers);
1815
  if (server_load_ciphers(ctx, &state_server, tls_require_ciphers,
1816
			  &dummy_errstr) == OK)
1817
    state_server.lib_state.pri_string = TRUE;
1818
  }
1819
else
1820
  DEBUG(D_tls) debug_printf("TLS: not preloading cipher list for server\n");
1821
return lifetime;
1822
}
1823
1824
1825
1826
1827
/* Preload whatever creds are static, onto a transport.  The client can then
1828
just copy the pointer as it starts up.
1829
Called from the daemon after a cache-invalidate with watch set; called from
1830
a queue-run startup with watch clear. */
1831
1832
static void
1833
tls_client_creds_init(transport_instance * t, BOOL watch)
1834
{
1835
smtp_transport_options_block * ob = t->options_block;
1836
exim_openssl_state_st tpt_dummy_state;
1837
host_item * dummy_host = (host_item *)1;
1838
uschar * dummy_errstr;
1839
SSL_CTX * ctx;
1840
1841
tls_openssl_init();
1842
1843
ob->tls_preload = null_tls_preload;
1844
if (lib_ctx_new(&ctx, dummy_host, &dummy_errstr) != OK)
1845
  return;
1846
ob->tls_preload.lib_ctx = ctx;
1847
1848
tpt_dummy_state.lib_state = ob->tls_preload;
1849
1850
#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
1851
if (  opt_set_and_noexpand(ob->tls_certificate)
1852
   && opt_unset_or_noexpand(ob->tls_privatekey))
1853
  {
1854
  if (  !watch
1855
     || (  tls_set_watch(ob->tls_certificate, FALSE)
1856
	&& tls_set_watch(ob->tls_privatekey, FALSE)
1857
     )  )
1858
    {
1859
    uschar * pkey = ob->tls_privatekey;
1860
1861
    DEBUG(D_tls)
1862
      debug_printf("TLS: preloading client certs for transport '%s'\n",t->name);
1863
1864
    if (  tls_add_certfile(ctx, &tpt_dummy_state, ob->tls_certificate,
1865
				    &dummy_errstr) == 0
1866
       && tls_add_pkeyfile(ctx, &tpt_dummy_state,
1867
				    pkey ? pkey : ob->tls_certificate,
1868
				    &dummy_errstr) == 0
1869
       )
1870
      ob->tls_preload.conn_certs = TRUE;
1871
    }
1872
  }
1873
else
1874
  DEBUG(D_tls)
1875
    debug_printf("TLS: not preloading client certs, for transport '%s'\n", t->name);
1876
1877
1878
if (  opt_set_and_noexpand(ob->tls_verify_certificates)
1879
   && opt_unset_or_noexpand(ob->tls_crl))
1880
  {
1881
  if (  !watch
1882
     ||    tls_set_watch(CUS X509_get_default_cert_file(), FALSE)
1883
        && tls_set_watch(ob->tls_verify_certificates, FALSE)
1884
	&& tls_set_watch(ob->tls_crl, FALSE)
1885
     )
1886
    {
1887
    DEBUG(D_tls)
1888
      debug_printf("TLS: preloading CA bundle for transport '%s'\n", t->name);
1889
1890
    if (setup_certs(ctx, ob->tls_verify_certificates,
1891
	  ob->tls_crl, dummy_host, &dummy_errstr) == OK)
1892
      ob->tls_preload.cabundle = TRUE;
1893
    }
1894
  }
1895
else
1896
  DEBUG(D_tls)
1897
      debug_printf("TLS: not preloading CA bundle, for transport '%s'\n", t->name);
1898
1899
#endif /*EXIM_HAVE_INOTIFY*/
1900
}
1901
1902
1903
#if defined(EXIM_HAVE_INOTIFY) || defined(EXIM_HAVE_KEVENT)
1904
/* Invalidate the creds cached, by dropping the current ones.
1905
Call when we notice one of the source files has changed. */
1906
 
1907
static void
1908
tls_server_creds_invalidate(void)
1909
{
1910
SSL_CTX_free(state_server.lib_state.lib_ctx);
1911
state_server.lib_state = null_tls_preload;
1912
}
1913
1914
1915
static void
1916
tls_client_creds_invalidate(transport_instance * t)
1917
{
1918
smtp_transport_options_block * ob = t->options_block;
1919
SSL_CTX_free(ob->tls_preload.lib_ctx);
1920
ob->tls_preload = null_tls_preload;
1921
}
1922
1923
#else
1924
1925
static void
1926
tls_server_creds_invalidate(void)
1927
{ return; }
1928
1929
static void
1930
tls_client_creds_invalidate(transport_instance * t)
1931
{ return; }
1932
1933
#endif	/*EXIM_HAVE_INOTIFY*/
1934
1935
1936
/* Extreme debug
1937
#ifndef DISABLE_OCSP
1938
void
1939
x509_store_dump_cert_s_names(X509_STORE * store)
1940
{
1941
STACK_OF(X509_OBJECT) * roots= store->objs;
1942
static uschar name[256];
1943
1944
for (int i= 0; i < sk_X509_OBJECT_num(roots); i++)
1945
  {
1946
  X509_OBJECT * tmp_obj= sk_X509_OBJECT_value(roots, i);
1947
  if(tmp_obj->type == X509_LU_X509)
1948
    {
1949
    X509_NAME * sn = X509_get_subject_name(tmp_obj->data.x509);
1950
    if (X509_NAME_oneline(sn, CS name, sizeof(name)))
1951
      {
1952
      name[sizeof(name)-1] = '\0';
1953
      debug_printf(" %s\n", name);
1954
      }
1955
    }
1956
  }
1957
}
1958
#endif
1959
*/
1960
1961
1962
#ifndef DISABLE_TLS_RESUME
1963
/* Manage the keysets used for encrypting the session tickets, on the server. */
1964
1965
typedef struct {			/* Session ticket encryption key */
1966
  uschar 	name[16];
1967
1968
  const EVP_CIPHER *	aes_cipher;
1969
  uschar		aes_key[32];	/* size needed depends on cipher. aes_128 implies 128/8 = 16? */
1970
# if OPENSSL_VERSION_NUMBER < 0x30000000L
1971
  const EVP_MD *	hmac_hash;
1972
# else
1973
  const uschar *	hmac_hashname;
1974
# endif
1975
  uschar		hmac_key[16];
1976
  time_t		renew;
1977
  time_t		expire;
1978
} exim_stek;
1979
1980
static exim_stek exim_tk;	/* current key */
1981
static exim_stek exim_tk_old;	/* previous key */
1982
1983
static void
1984
tk_init(void)
1985
{
1986
time_t t = time(NULL);
1987
1988
if (exim_tk.name[0])
1989
  {
1990
  if (exim_tk.renew >= t) return;
1991
  exim_tk_old = exim_tk;
1992
  }
1993
1994
if (f.running_in_test_harness) ssl_session_timeout = 6;
1995
1996
DEBUG(D_tls) debug_printf("OpenSSL: %s STEK\n", exim_tk.name[0] ? "rotating" : "creating");
1997
if (RAND_bytes(exim_tk.aes_key, sizeof(exim_tk.aes_key)) <= 0) return;
1998
if (RAND_bytes(exim_tk.hmac_key, sizeof(exim_tk.hmac_key)) <= 0) return;
1999
if (RAND_bytes(exim_tk.name+1, sizeof(exim_tk.name)-1) <= 0) return;
2000
2001
exim_tk.name[0] = 'E';
2002
exim_tk.aes_cipher = EVP_aes_256_cbc();
2003
# if OPENSSL_VERSION_NUMBER < 0x30000000L
2004
exim_tk.hmac_hash = EVP_sha256();
2005
# else
2006
exim_tk.hmac_hashname = US "sha256";
2007
# endif
2008
exim_tk.expire = t + ssl_session_timeout;
2009
exim_tk.renew = t + ssl_session_timeout/2;
2010
}
2011
2012
static exim_stek *
2013
tk_current(void)
2014
{
2015
if (!exim_tk.name[0]) return NULL;
2016
return &exim_tk;
2017
}
2018
2019
static exim_stek *
2020
tk_find(const uschar * name)
2021
{
2022
return memcmp(name, exim_tk.name, sizeof(exim_tk.name)) == 0 ? &exim_tk
2023
  : memcmp(name, exim_tk_old.name, sizeof(exim_tk_old.name)) == 0 ? &exim_tk_old
2024
  : NULL;
2025
}
2026
2027
2028
static int
2029
tk_hmac_init(
2030
# if OPENSSL_VERSION_NUMBER < 0x30000000L
2031
  HMAC_CTX * hctx,
2032
#else
2033
  EVP_MAC_CTX * hctx,
2034
#endif
2035
  exim_stek * key
2036
  )
2037
{
2038
/*XXX will want these dependent on the ssl session strength */
2039
# if OPENSSL_VERSION_NUMBER < 0x30000000L
2040
  HMAC_Init_ex(hctx, key->hmac_key, sizeof(key->hmac_key),
2041
		key->hmac_hash, NULL);
2042
#else
2043
 {
2044
  OSSL_PARAM params[3];
2045
  uschar * hk = string_copy(key->hmac_hashname);	/* need nonconst */
2046
  params[0] = OSSL_PARAM_construct_octet_string("key", key->hmac_key, sizeof(key->hmac_key));
2047
  params[1] = OSSL_PARAM_construct_utf8_string("digest", CS hk, 0);
2048
  params[2] = OSSL_PARAM_construct_end();
2049
  if (EVP_MAC_CTX_set_params(hctx, params) == 0)
2050
    {
2051
    DEBUG(D_tls) debug_printf("EVP_MAC_CTX_set_params: %s\n",
2052
      ERR_reason_error_string(ERR_get_error()));
2053
    return 0; /* error in mac initialisation */
2054
    }
2055
}
2056
#endif
2057
return 1;
2058
}
2059
2060
/* Callback for session tickets, on server */
2061
static int
2062
ticket_key_callback(SSL * ssl, uschar key_name[16],
2063
  uschar * iv, EVP_CIPHER_CTX * c_ctx,
2064
# if OPENSSL_VERSION_NUMBER < 0x30000000L
2065
  HMAC_CTX * hctx,
2066
#else
2067
  EVP_MAC_CTX * hctx,
2068
#endif
2069
  int enc)
2070
{
2071
tls_support * tlsp = state_server.tlsp;
2072
exim_stek * key;
2073
2074
if (enc)
2075
  {
2076
  DEBUG(D_tls) debug_printf("ticket_key_callback: create new session\n");
2077
  tlsp->resumption |= RESUME_CLIENT_REQUESTED;
2078
2079
  if (RAND_bytes(iv, EVP_MAX_IV_LENGTH) <= 0)
2080
    return -1; /* insufficient random */
2081
2082
  if (!(key = tk_current()))	/* current key doesn't exist or isn't valid */
2083
     return 0;			/* key couldn't be created */
2084
  memcpy(key_name, key->name, 16);
2085
  DEBUG(D_tls) debug_printf("STEK expire " TIME_T_FMT "\n", key->expire - time(NULL));
2086
2087
  if (tk_hmac_init(hctx, key) == 0) return 0;
2088
  EVP_EncryptInit_ex(c_ctx, key->aes_cipher, NULL, key->aes_key, iv);
2089
2090
  DEBUG(D_tls) debug_printf("ticket created\n");
2091
  return 1;
2092
  }
2093
else
2094
  {
2095
  time_t now = time(NULL);
2096
2097
  DEBUG(D_tls) debug_printf("ticket_key_callback: retrieve session\n");
2098
  tlsp->resumption |= RESUME_CLIENT_SUGGESTED;
2099
2100
  if (!(key = tk_find(key_name)) || key->expire < now)
2101
    {
2102
    DEBUG(D_tls)
2103
      {
2104
      debug_printf("ticket not usable (%s)\n", key ? "expired" : "not found");
2105
      if (key) debug_printf("STEK expire " TIME_T_FMT "\n", key->expire - now);
2106
      }
2107
    return 0;
2108
    }
2109
2110
  if (tk_hmac_init(hctx, key) == 0) return 0;
2111
  EVP_DecryptInit_ex(c_ctx, key->aes_cipher, NULL, key->aes_key, iv);
2112
2113
  DEBUG(D_tls) debug_printf("ticket usable, STEK expire " TIME_T_FMT "\n", key->expire - now);
2114
2115
  /* The ticket lifetime and renewal are the same as the STEK lifetime and
2116
  renewal, which is overenthusiastic.  A factor of, say, 3x longer STEK would
2117
  be better.  To do that we'd have to encode ticket lifetime in the name as
2118
  we don't yet see the restored session.  Could check posthandshake for TLS1.3
2119
  and trigger a new ticket then, but cannot do that for TLS1.2 */
2120
  return key->renew < now ? 2 : 1;
2121
  }
2122
}
2123
#endif	/* !DISABLE_TLS_RESUME */
2124
2125
2126
2127
static void
2128
setup_cert_verify(SSL_CTX * ctx, BOOL optional,
2129
    int (*cert_vfy_cb)(int, X509_STORE_CTX *))
2130
{
2131
/* If verification is optional, don't fail if no certificate */
2132
2133
SSL_CTX_set_verify(ctx,
2134
    SSL_VERIFY_PEER | (optional ? 0 : SSL_VERIFY_FAIL_IF_NO_PEER_CERT),
2135
    cert_vfy_cb);
2136
}
2137
2138
1661
/*************************************************
2139
/*************************************************
1662
*            Callback to handle SNI              *
2140
*            Callback to handle SNI              *
1663
*************************************************/
2141
*************************************************/
Lines 1683-1689 Link Here
1683
tls_servername_cb(SSL *s, int *ad ARG_UNUSED, void *arg)
2161
tls_servername_cb(SSL *s, int *ad ARG_UNUSED, void *arg)
1684
{
2162
{
1685
const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
2163
const char *servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
1686
tls_ext_ctx_cb *cbinfo = (tls_ext_ctx_cb *) arg;
2164
exim_openssl_state_st *state = (exim_openssl_state_st *) arg;
1687
int rc;
2165
int rc;
1688
int old_pool = store_pool;
2166
int old_pool = store_pool;
1689
uschar * dummy_errstr;
2167
uschar * dummy_errstr;
Lines 1696-1702 Link Here
1696
2174
1697
/* Make the extension value available for expansion */
2175
/* Make the extension value available for expansion */
1698
store_pool = POOL_PERM;
2176
store_pool = POOL_PERM;
1699
tls_in.sni = string_copy_taint(US servername, TRUE);
2177
tls_in.sni = string_copy_taint(US servername, GET_TAINTED);
1700
store_pool = old_pool;
2178
store_pool = old_pool;
1701
2179
1702
if (!reexpand_tls_files_for_sni)
2180
if (!reexpand_tls_files_for_sni)
Lines 1706-1756 Link Here
1706
not confident that memcpy wouldn't break some internal reference counting.
2184
not confident that memcpy wouldn't break some internal reference counting.
1707
Especially since there's a references struct member, which would be off. */
2185
Especially since there's a references struct member, which would be off. */
1708
2186
1709
#ifdef EXIM_HAVE_OPENSSL_TLS_METHOD
2187
if (lib_ctx_new(&server_sni, NULL, &dummy_errstr) != OK)
1710
if (!(server_sni = SSL_CTX_new(TLS_server_method())))
1711
#else
1712
if (!(server_sni = SSL_CTX_new(SSLv23_server_method())))
1713
#endif
1714
  {
1715
  ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
1716
  DEBUG(D_tls) debug_printf("SSL_CTX_new() failed: %s\n", ssl_errstring);
1717
  goto bad;
2188
  goto bad;
1718
  }
1719
2189
1720
/* Not sure how many of these are actually needed, since SSL object
2190
/* Not sure how many of these are actually needed, since SSL object
1721
already exists.  Might even need this selfsame callback, for reneg? */
2191
already exists.  Might even need this selfsame callback, for reneg? */
1722
2192
1723
SSL_CTX_set_info_callback(server_sni, SSL_CTX_get_info_callback(server_ctx));
2193
  {
1724
SSL_CTX_set_mode(server_sni, SSL_CTX_get_mode(server_ctx));
2194
  SSL_CTX * ctx = state_server.lib_state.lib_ctx;
1725
SSL_CTX_set_options(server_sni, SSL_CTX_get_options(server_ctx));
2195
  SSL_CTX_set_info_callback(server_sni, SSL_CTX_get_info_callback(ctx));
1726
SSL_CTX_set_timeout(server_sni, SSL_CTX_get_timeout(server_ctx));
2196
  SSL_CTX_set_mode(server_sni, SSL_CTX_get_mode(ctx));
1727
SSL_CTX_set_tlsext_servername_callback(server_sni, tls_servername_cb);
2197
  SSL_CTX_set_options(server_sni, SSL_CTX_get_options(ctx));
1728
SSL_CTX_set_tlsext_servername_arg(server_sni, cbinfo);
2198
  SSL_CTX_set_timeout(server_sni, SSL_CTX_get_timeout(ctx));
2199
  SSL_CTX_set_tlsext_servername_callback(server_sni, tls_servername_cb);
2200
  SSL_CTX_set_tlsext_servername_arg(server_sni, state);
2201
  }
1729
2202
1730
if (  !init_dh(server_sni, cbinfo->dhparam, NULL, &dummy_errstr)
2203
if (  !init_dh(server_sni, state->dhparam, &dummy_errstr)
1731
   || !init_ecdh(server_sni, NULL, &dummy_errstr)
2204
   || !init_ecdh(server_sni, &dummy_errstr)
1732
   )
2205
   )
1733
  goto bad;
2206
  goto bad;
1734
2207
1735
if (  cbinfo->server_cipher_list
2208
if (  state->server_cipher_list
1736
   && !SSL_CTX_set_cipher_list(server_sni, CS cbinfo->server_cipher_list))
2209
   && !SSL_CTX_set_cipher_list(server_sni, CS state->server_cipher_list))
1737
  goto bad;
2210
  goto bad;
1738
2211
1739
#ifndef DISABLE_OCSP
2212
#ifndef DISABLE_OCSP
1740
if (cbinfo->u_ocsp.server.file)
2213
if (state->u_ocsp.server.file)
1741
  {
2214
  {
1742
  SSL_CTX_set_tlsext_status_cb(server_sni, tls_server_stapling_cb);
2215
  SSL_CTX_set_tlsext_status_cb(server_sni, tls_server_stapling_cb);
1743
  SSL_CTX_set_tlsext_status_arg(server_sni, cbinfo);
2216
  SSL_CTX_set_tlsext_status_arg(server_sni, state);
1744
  }
2217
  }
1745
#endif
2218
#endif
1746
2219
1747
if ((rc = setup_certs(server_sni, tls_verify_certificates, tls_crl, NULL, FALSE,
2220
  {
1748
		      verify_callback_server, &dummy_errstr)) != OK)
2221
  uschar * expcerts;
1749
  goto bad;
2222
  if (  !expand_check(tls_verify_certificates, US"tls_verify_certificates",
2223
		  &expcerts, &dummy_errstr)
2224
     || (rc = setup_certs(server_sni, expcerts, tls_crl, NULL,
2225
			&dummy_errstr)) != OK)
2226
    goto bad;
2227
2228
  if (expcerts && *expcerts)
2229
    setup_cert_verify(server_sni, FALSE, verify_callback_server);
2230
  }
1750
2231
1751
/* do this after setup_certs, because this can require the certs for verifying
2232
/* do this after setup_certs, because this can require the certs for verifying
1752
OCSP information. */
2233
OCSP information. */
1753
if ((rc = tls_expand_session_files(server_sni, cbinfo, &dummy_errstr)) != OK)
2234
if ((rc = tls_expand_session_files(server_sni, state, &dummy_errstr)) != OK)
1754
  goto bad;
2235
  goto bad;
1755
2236
1756
DEBUG(D_tls) debug_printf("Switching SSL context.\n");
2237
DEBUG(D_tls) debug_printf("Switching SSL context.\n");
Lines 1764-1769 Link Here
1764
2245
1765
2246
1766
2247
2248
#ifdef EXIM_HAVE_ALPN
2249
/*************************************************
2250
*        Callback to handle ALPN                 *
2251
*************************************************/
2252
2253
/* Called on server if tls_alpn nonblank after expansion,
2254
when client offers ALPN, after the SNI callback.
2255
If set and not matching the list then we dump the connection */
2256
2257
static int
2258
tls_server_alpn_cb(SSL *ssl, const uschar ** out, uschar * outlen,
2259
  const uschar * in, unsigned int inlen, void * arg)
2260
{
2261
server_seen_alpn = TRUE;
2262
DEBUG(D_tls)
2263
  {
2264
  debug_printf("Received TLS ALPN offer:");
2265
  for (int pos = 0, siz; pos < inlen; pos += siz+1)
2266
    {
2267
    siz = in[pos];
2268
    if (pos + 1 + siz > inlen) siz = inlen - pos - 1;
2269
    debug_printf(" '%.*s'", siz, in + pos + 1);
2270
    }
2271
  debug_printf(".  Our list: '%s'\n", tls_alpn);
2272
  }
2273
2274
/* Look for an acceptable ALPN */
2275
2276
if (  inlen > 1		/* at least one name */
2277
   && in[0]+1 == inlen	/* filling the vector, so exactly one name */
2278
   )
2279
  {
2280
  const uschar * list = tls_alpn;
2281
  int sep = 0;
2282
  for (uschar * name; name = string_nextinlist(&list, &sep, NULL, 0); )
2283
    if (Ustrncmp(in+1, name, in[0]) == 0)
2284
      {
2285
      *out = in+1;			/* we checked for exactly one, so can just point to it */
2286
      *outlen = inlen;
2287
      return SSL_TLSEXT_ERR_OK;		/* use ALPN */
2288
      }
2289
  }
2290
2291
/* More than one name from clilent, or name did not match our list. */
2292
2293
/* This will be fatal to the TLS conn; would be nice to kill TCP also.
2294
Maybe as an option in future; for now leave control to the config (must-tls). */
2295
2296
DEBUG(D_tls) debug_printf("TLS ALPN rejected\n");
2297
return SSL_TLSEXT_ERR_ALERT_FATAL;
2298
}
2299
#endif	/* EXIM_HAVE_ALPN */
2300
2301
2302
1767
#ifndef DISABLE_OCSP
2303
#ifndef DISABLE_OCSP
1768
2304
1769
/*************************************************
2305
/*************************************************
Lines 1781-1788 Link Here
1781
static int
2317
static int
1782
tls_server_stapling_cb(SSL *s, void *arg)
2318
tls_server_stapling_cb(SSL *s, void *arg)
1783
{
2319
{
1784
const tls_ext_ctx_cb * cbinfo = (tls_ext_ctx_cb *) arg;
2320
const exim_openssl_state_st * state = arg;
1785
ocsp_resplist * olist = cbinfo->u_ocsp.server.olist;
2321
ocsp_resplist * olist = state->u_ocsp.server.olist;
1786
uschar * response_der;	/*XXX blob */
2322
uschar * response_der;	/*XXX blob */
1787
int response_der_len;
2323
int response_der_len;
1788
2324
Lines 1799-1807 Link Here
1799
  const X509 * cert_sent = SSL_get_certificate(s);
2335
  const X509 * cert_sent = SSL_get_certificate(s);
1800
  const ASN1_INTEGER * cert_serial = X509_get0_serialNumber(cert_sent);
2336
  const ASN1_INTEGER * cert_serial = X509_get0_serialNumber(cert_sent);
1801
  const BIGNUM * cert_bn = ASN1_INTEGER_to_BN(cert_serial, NULL);
2337
  const BIGNUM * cert_bn = ASN1_INTEGER_to_BN(cert_serial, NULL);
1802
  const X509_NAME * cert_issuer = X509_get_issuer_name(cert_sent);
1803
  uschar * chash;
1804
  uint chash_len;
1805
2338
1806
  for (; olist; olist = olist->next)
2339
  for (; olist; olist = olist->next)
1807
    {
2340
    {
Lines 1856-1862 Link Here
1856
if (response_der_len <= 0)
2389
if (response_der_len <= 0)
1857
  return SSL_TLSEXT_ERR_NOACK;
2390
  return SSL_TLSEXT_ERR_NOACK;
1858
2391
1859
SSL_set_tlsext_status_ocsp_resp(server_ssl, response_der, response_der_len);
2392
SSL_set_tlsext_status_ocsp_resp(state_server.lib_state.lib_ssl,
2393
				response_der, response_der_len);
1860
tls_in.ocsp = OCSP_VFIED;
2394
tls_in.ocsp = OCSP_VFIED;
1861
return SSL_TLSEXT_ERR_OK;
2395
return SSL_TLSEXT_ERR_OK;
1862
}
2396
}
Lines 1873-1879 Link Here
1873
static int
2407
static int
1874
tls_client_stapling_cb(SSL *s, void *arg)
2408
tls_client_stapling_cb(SSL *s, void *arg)
1875
{
2409
{
1876
tls_ext_ctx_cb * cbinfo = arg;
2410
exim_openssl_state_st * cbinfo = arg;
1877
const unsigned char * p;
2411
const unsigned char * p;
1878
int len;
2412
int len;
1879
OCSP_RESPONSE * rsp;
2413
OCSP_RESPONSE * rsp;
Lines 1883-1890 Link Here
1883
DEBUG(D_tls) debug_printf("Received TLS status callback (OCSP stapling):\n");
2417
DEBUG(D_tls) debug_printf("Received TLS status callback (OCSP stapling):\n");
1884
len = SSL_get_tlsext_status_ocsp_resp(s, &p);
2418
len = SSL_get_tlsext_status_ocsp_resp(s, &p);
1885
if(!p)
2419
if(!p)
1886
 {
2420
 {				/* Expect this when we requested ocsp but got none */
1887
  /* Expect this when we requested ocsp but got none */
2421
  if (SSL_session_reused(s) && tls_out.ocsp == OCSP_VFIED)
2422
    {
2423
    DEBUG(D_tls) debug_printf(" null, but resumed; ocsp vfy stored with session is good\n");
2424
    return 1;
2425
    }
1888
  if (cbinfo->u_ocsp.client.verify_required && LOGGING(tls_cipher))
2426
  if (cbinfo->u_ocsp.client.verify_required && LOGGING(tls_cipher))
1889
    log_write(0, LOG_MAIN, "Required TLS certificate status not received");
2427
    log_write(0, LOG_MAIN, "Required TLS certificate status not received");
1890
  else
2428
  else
Lines 1926-1932 Link Here
1926
    STACK_OF(OCSP_SINGLERESP) * sresp = bs->tbsResponseData->responses;
2464
    STACK_OF(OCSP_SINGLERESP) * sresp = bs->tbsResponseData->responses;
1927
#endif
2465
#endif
1928
2466
1929
    DEBUG(D_tls) bp = BIO_new_fp(debug_file, BIO_NOCLOSE);
2467
    DEBUG(D_tls) bp = BIO_new(BIO_s_mem());
1930
2468
1931
    /*OCSP_RESPONSE_print(bp, rsp, 0);   extreme debug: stapling content */
2469
    /*OCSP_RESPONSE_print(bp, rsp, 0);   extreme debug: stapling content */
1932
2470
Lines 1941-1949 Link Here
1941
	if (LOGGING(tls_cipher)) log_write(0, LOG_MAIN,
2479
	if (LOGGING(tls_cipher)) log_write(0, LOG_MAIN,
1942
		"Received TLS cert status response, itself unverifiable: %s",
2480
		"Received TLS cert status response, itself unverifiable: %s",
1943
		ERR_reason_error_string(ERR_peek_error()));
2481
		ERR_reason_error_string(ERR_peek_error()));
1944
	BIO_printf(bp, "OCSP response verify failure\n");
2482
	DEBUG(D_tls)
1945
	ERR_print_errors(bp);
2483
	  {
1946
	OCSP_RESPONSE_print(bp, rsp, 0);
2484
	  BIO_printf(bp, "OCSP response verify failure\n");
2485
	  ERR_print_errors(bp);
2486
	  OCSP_RESPONSE_print(bp, rsp, 0);
2487
	  }
1947
	goto failed;
2488
	goto failed;
1948
	}
2489
	}
1949
      else
2490
      else
Lines 1981-1994 Link Here
1981
      status = OCSP_single_get0_status(single, &reason, &rev,
2522
      status = OCSP_single_get0_status(single, &reason, &rev,
1982
		  &thisupd, &nextupd);
2523
		  &thisupd, &nextupd);
1983
2524
1984
      DEBUG(D_tls) time_print(bp, "This OCSP Update", thisupd);
2525
      DEBUG(D_tls)
1985
      DEBUG(D_tls) if(nextupd) time_print(bp, "Next OCSP Update", nextupd);
2526
	{
2527
	time_print(bp, "This OCSP Update", thisupd);
2528
	if (nextupd) time_print(bp, "Next OCSP Update", nextupd);
2529
	}
1986
      if (!OCSP_check_validity(thisupd, nextupd,
2530
      if (!OCSP_check_validity(thisupd, nextupd,
1987
	    EXIM_OCSP_SKEW_SECONDS, EXIM_OCSP_MAX_AGE))
2531
	    EXIM_OCSP_SKEW_SECONDS, EXIM_OCSP_MAX_AGE))
1988
	{
2532
	{
1989
	tls_out.ocsp = OCSP_FAILED;
2533
	tls_out.ocsp = OCSP_FAILED;
1990
	DEBUG(D_tls) ERR_print_errors(bp);
2534
	DEBUG(D_tls) ERR_print_errors(bp);
1991
	log_write(0, LOG_MAIN, "Server OSCP dates invalid");
2535
	log_write(0, LOG_MAIN, "OCSP dates invalid");
1992
	goto failed;
2536
	goto failed;
1993
	}
2537
	}
1994
2538
Lines 2021-2026 Link Here
2021
    tls_out.ocsp = OCSP_FAILED;
2565
    tls_out.ocsp = OCSP_FAILED;
2022
    i = cbinfo->u_ocsp.client.verify_required ? 0 : 1;
2566
    i = cbinfo->u_ocsp.client.verify_required ? 0 : 1;
2023
  good:
2567
  good:
2568
    {
2569
    uschar * s = NULL;
2570
    int len = (int) BIO_get_mem_data(bp, CSS &s);
2571
    if (len > 0) debug_printf("%.*s", len, s);
2572
    }
2024
    BIO_free(bp);
2573
    BIO_free(bp);
2025
  }
2574
  }
2026
2575
Lines 2033-2127 Link Here
2033
/*************************************************
2582
/*************************************************
2034
*            Initialize for TLS                  *
2583
*            Initialize for TLS                  *
2035
*************************************************/
2584
*************************************************/
2036
2037
static void
2038
tls_openssl_init(void)
2039
{
2040
#ifdef EXIM_NEED_OPENSSL_INIT
2041
SSL_load_error_strings();          /* basic set up */
2042
OpenSSL_add_ssl_algorithms();
2043
#endif
2044
2045
#if defined(EXIM_HAVE_SHA256) && !defined(OPENSSL_AUTO_SHA256)
2046
/* SHA256 is becoming ever more popular. This makes sure it gets added to the
2047
list of available digests. */
2048
EVP_add_digest(EVP_sha256());
2049
#endif
2050
}
2051
2052
2053
2054
/* Called from both server and client code, to do preliminary initialization
2585
/* Called from both server and client code, to do preliminary initialization
2055
of the library.  We allocate and return a context structure.
2586
of the library.  We allocate and return a context structure.
2056
2587
2057
Arguments:
2588
Arguments:
2058
  ctxp            returned SSL context
2059
  host            connected host, if client; NULL if server
2589
  host            connected host, if client; NULL if server
2060
  dhparam         DH parameter file
2590
  ob		  transport options block, if client; NULL if server
2061
  certificate     certificate file
2062
  privatekey      private key
2063
  ocsp_file       file of stapling info (server); flag for require ocsp (client)
2591
  ocsp_file       file of stapling info (server); flag for require ocsp (client)
2064
  addr            address if client; NULL if server (for some randomness)
2592
  addr            address if client; NULL if server (for some randomness)
2065
  cbp             place to put allocated callback context
2593
  caller_state    place to put pointer to allocated state-struct
2066
  errstr	  error string pointer
2594
  errstr	  error string pointer
2067
2595
2068
Returns:          OK/DEFER/FAIL
2596
Returns:          OK/DEFER/FAIL
2069
*/
2597
*/
2070
2598
2071
static int
2599
static int
2072
tls_init(SSL_CTX **ctxp, host_item *host, uschar *dhparam, uschar *certificate,
2600
tls_init(host_item * host, smtp_transport_options_block * ob,
2073
  uschar *privatekey,
2074
#ifndef DISABLE_OCSP
2601
#ifndef DISABLE_OCSP
2075
  uschar *ocsp_file,
2602
  uschar *ocsp_file,
2076
#endif
2603
#endif
2077
  address_item *addr, tls_ext_ctx_cb ** cbp,
2604
  address_item *addr, exim_openssl_state_st ** caller_state,
2078
  tls_support * tlsp,
2605
  tls_support * tlsp,
2079
  uschar ** errstr)
2606
  uschar ** errstr)
2080
{
2607
{
2081
SSL_CTX * ctx;
2608
SSL_CTX * ctx;
2082
long init_options;
2609
exim_openssl_state_st * state;
2083
int rc;
2610
int rc;
2084
tls_ext_ctx_cb * cbinfo;
2085
2611
2086
cbinfo = store_malloc(sizeof(tls_ext_ctx_cb));
2612
if (host)			/* client */
2087
cbinfo->tlsp = tlsp;
2088
cbinfo->certificate = certificate;
2089
cbinfo->privatekey = privatekey;
2090
cbinfo->is_server = host==NULL;
2091
#ifndef DISABLE_OCSP
2092
cbinfo->verify_stack = NULL;
2093
if (!host)
2094
  {
2613
  {
2095
  cbinfo->u_ocsp.server.file = ocsp_file;
2614
  state = store_malloc(sizeof(exim_openssl_state_st));
2096
  cbinfo->u_ocsp.server.file_expanded = NULL;
2615
  memset(state, 0, sizeof(*state));
2097
  cbinfo->u_ocsp.server.olist = NULL;
2616
  state->certificate = ob->tls_certificate;
2617
  state->privatekey =  ob->tls_privatekey;
2618
  state->is_server = FALSE;
2619
  state->dhparam = NULL;
2620
  state->lib_state = ob->tls_preload;
2621
  }
2622
else				/* server */
2623
  {
2624
  state = &state_server;
2625
  state->certificate = tls_certificate;
2626
  state->privatekey =  tls_privatekey;
2627
  state->is_server = TRUE;
2628
  state->dhparam = tls_dhparam;
2629
  state->lib_state = state_server.lib_state;
2098
  }
2630
  }
2099
else
2100
  cbinfo->u_ocsp.client.verify_store = NULL;
2101
#endif
2102
cbinfo->dhparam = dhparam;
2103
cbinfo->server_cipher_list = NULL;
2104
cbinfo->host = host;
2105
#ifndef DISABLE_EVENT
2106
cbinfo->event_action = NULL;
2107
#endif
2108
2631
2109
tls_openssl_init();
2632
state->tlsp = tlsp;
2633
state->host = host;
2110
2634
2111
/* Create a context.
2635
if (!state->lib_state.pri_string)
2112
The OpenSSL docs in 1.0.1b have not been updated to clarify TLS variant
2636
  state->server_cipher_list = NULL;
2113
negotiation in the different methods; as far as I can tell, the only
2114
*_{server,client}_method which allows negotiation is SSLv23, which exists even
2115
when OpenSSL is built without SSLv2 support.
2116
By disabling with openssl_options, we can let admins re-enable with the
2117
existing knob. */
2118
2637
2119
#ifdef EXIM_HAVE_OPENSSL_TLS_METHOD
2638
#ifndef DISABLE_EVENT
2120
if (!(ctx = SSL_CTX_new(host ? TLS_client_method() : TLS_server_method())))
2639
state->event_action = NULL;
2121
#else
2122
if (!(ctx = SSL_CTX_new(host ? SSLv23_client_method() : SSLv23_server_method())))
2123
#endif
2640
#endif
2124
  return tls_error(US"SSL_CTX_new", host, NULL, errstr);
2641
2642
tls_openssl_init();
2125
2643
2126
/* It turns out that we need to seed the random number generator this early in
2644
/* It turns out that we need to seed the random number generator this early in
2127
order to get the full complement of ciphers to work. It took me roughly a day
2645
order to get the full complement of ciphers to work. It took me roughly a day
Lines 2129-2168 Link Here
2129
2647
2130
On systems that have /dev/urandom, SSL may automatically seed itself from
2648
On systems that have /dev/urandom, SSL may automatically seed itself from
2131
there. Otherwise, we have to make something up as best we can. Double check
2649
there. Otherwise, we have to make something up as best we can. Double check
2132
afterwards. */
2650
afterwards.
2133
2651
2134
if (!RAND_status())
2652
Although we likely called this before, at daemon startup, this is a chance
2135
  {
2653
to mix in further variable info (time, pid) if needed. */
2136
  randstuff r;
2137
  gettimeofday(&r.tv, NULL);
2138
  r.p = getpid();
2139
2654
2140
  RAND_seed(US (&r), sizeof(r));
2655
if (!lib_rand_init(addr))
2141
  RAND_seed(US big_buffer, big_buffer_size);
2656
  return tls_error(US"RAND_status", host,
2142
  if (addr != NULL) RAND_seed(US addr, sizeof(addr));
2657
    US"unable to seed random number generator", errstr);
2143
2144
  if (!RAND_status())
2145
    return tls_error(US"RAND_status", host,
2146
      US"unable to seed random number generator", errstr);
2147
  }
2148
2149
/* Set up the information callback, which outputs if debugging is at a suitable
2150
level. */
2151
2152
DEBUG(D_tls)
2153
  {
2154
  SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
2155
#if defined(EXIM_HAVE_OPESSL_TRACE) && !defined(OPENSSL_NO_SSL_TRACE)
2156
  /* this needs a debug build of OpenSSL */
2157
  SSL_CTX_set_msg_callback(ctx, (void (*)())SSL_trace);
2158
#endif
2159
#ifdef OPENSSL_HAVE_KEYLOG_CB
2160
  SSL_CTX_set_keylog_callback(ctx, (void (*)())keylog_callback);
2161
#endif
2162
  }
2163
2164
/* Automatically re-try reads/writes after renegotiation. */
2165
(void) SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
2166
2658
2167
/* Apply administrator-supplied work-arounds.
2659
/* Apply administrator-supplied work-arounds.
2168
Historically we applied just one requested option,
2660
Historically we applied just one requested option,
Lines 2173-2187 Link Here
2173
No OpenSSL version number checks: the options we accept depend upon the
2665
No OpenSSL version number checks: the options we accept depend upon the
2174
availability of the option value macros from OpenSSL.  */
2666
availability of the option value macros from OpenSSL.  */
2175
2667
2176
if (!tls_openssl_options_parse(openssl_options, &init_options))
2668
if (!init_options)
2177
  return tls_error(US"openssl_options parsing failed", host, NULL, errstr);
2669
  if (!tls_openssl_options_parse(openssl_options, &init_options))
2670
    return tls_error(US"openssl_options parsing failed", host, NULL, errstr);
2671
2672
/* Create a context.
2673
The OpenSSL docs in 1.0.1b have not been updated to clarify TLS variant
2674
negotiation in the different methods; as far as I can tell, the only
2675
*_{server,client}_method which allows negotiation is SSLv23, which exists even
2676
when OpenSSL is built without SSLv2 support.
2677
By disabling with openssl_options, we can let admins re-enable with the
2678
existing knob. */
2178
2679
2179
#ifdef EXPERIMENTAL_TLS_RESUME
2680
if (!(ctx = state->lib_state.lib_ctx))
2681
  {
2682
  if ((rc = lib_ctx_new(&ctx, host, errstr)) != OK)
2683
    return rc;
2684
  state->lib_state.lib_ctx = ctx;
2685
  }
2686
2687
#ifndef DISABLE_TLS_RESUME
2180
tlsp->resumption = RESUME_SUPPORTED;
2688
tlsp->resumption = RESUME_SUPPORTED;
2181
#endif
2689
#endif
2182
if (init_options)
2690
if (init_options)
2183
  {
2691
  {
2184
#ifdef EXPERIMENTAL_TLS_RESUME
2692
#ifndef DISABLE_TLS_RESUME
2185
  /* Should the server offer session resumption? */
2693
  /* Should the server offer session resumption? */
2186
  if (!host && verify_check_host(&tls_resumption_hosts) == OK)
2694
  if (!host && verify_check_host(&tls_resumption_hosts) == OK)
2187
    {
2695
    {
Lines 2213-2233 Link Here
2213
/* Initialize with DH parameters if supplied */
2721
/* Initialize with DH parameters if supplied */
2214
/* Initialize ECDH temp key parameter selection */
2722
/* Initialize ECDH temp key parameter selection */
2215
2723
2216
if (  !init_dh(ctx, dhparam, host, errstr)
2724
if (!host)
2217
   || !init_ecdh(ctx, host, errstr)
2725
  {
2218
   )
2726
  if (state->lib_state.dh)
2219
  return DEFER;
2727
    { DEBUG(D_tls) debug_printf("TLS: DH params were preloaded\n"); }
2728
  else
2729
    if (!init_dh(ctx, state->dhparam, errstr)) return DEFER;
2730
2731
  if (state->lib_state.ecdh)
2732
    { DEBUG(D_tls) debug_printf("TLS: ECDH curve was preloaded\n"); }
2733
  else
2734
    if (!init_ecdh(ctx, errstr)) return DEFER;
2735
  }
2220
2736
2221
/* Set up certificate and key (and perhaps OCSP info) */
2737
/* Set up certificate and key (and perhaps OCSP info) */
2222
2738
2223
if ((rc = tls_expand_session_files(ctx, cbinfo, errstr)) != OK)
2739
if (state->lib_state.conn_certs)
2224
  return rc;
2740
  {
2741
  DEBUG(D_tls)
2742
    debug_printf("TLS: %s certs were preloaded\n", host ? "client":"server");
2743
  }
2744
else
2745
  {
2746
#ifndef DISABLE_OCSP
2747
  if (!host)
2748
    {
2749
    state->u_ocsp.server.file = ocsp_file;
2750
    state->u_ocsp.server.file_expanded = NULL;
2751
    state->u_ocsp.server.olist = NULL;
2752
    }
2753
#endif
2754
  if ((rc = tls_expand_session_files(ctx, state, errstr)) != OK) return rc;
2755
  }
2225
2756
2226
/* If we need to handle SNI or OCSP, do so */
2757
/* If we need to handle SNI or OCSP, do so */
2227
2758
2228
#ifdef EXIM_HAVE_OPENSSL_TLSEXT
2759
#ifdef EXIM_HAVE_OPENSSL_TLSEXT
2229
# ifndef DISABLE_OCSP
2760
# ifndef DISABLE_OCSP
2230
  if (!(cbinfo->verify_stack = sk_X509_new_null()))
2761
  if (!(state->verify_stack = sk_X509_new_null()))
2231
    {
2762
    {
2232
    DEBUG(D_tls) debug_printf("failed to create stack for stapling verify\n");
2763
    DEBUG(D_tls) debug_printf("failed to create stack for stapling verify\n");
2233
    return FAIL;
2764
    return FAIL;
Lines 2241-2273 Link Here
2241
  the option exists, not what the current expansion might be, as SNI might
2772
  the option exists, not what the current expansion might be, as SNI might
2242
  change the certificate and OCSP file in use between now and the time the
2773
  change the certificate and OCSP file in use between now and the time the
2243
  callback is invoked. */
2774
  callback is invoked. */
2244
  if (cbinfo->u_ocsp.server.file)
2775
  if (state->u_ocsp.server.file)
2245
    {
2776
    {
2246
    SSL_CTX_set_tlsext_status_cb(ctx, tls_server_stapling_cb);
2777
    SSL_CTX_set_tlsext_status_cb(ctx, tls_server_stapling_cb);
2247
    SSL_CTX_set_tlsext_status_arg(ctx, cbinfo);
2778
    SSL_CTX_set_tlsext_status_arg(ctx, state);
2248
    }
2779
    }
2249
# endif
2780
# endif
2250
  /* We always do this, so that $tls_sni is available even if not used in
2781
  /* We always do this, so that $tls_sni is available even if not used in
2251
  tls_certificate */
2782
  tls_certificate */
2252
  SSL_CTX_set_tlsext_servername_callback(ctx, tls_servername_cb);
2783
  SSL_CTX_set_tlsext_servername_callback(ctx, tls_servername_cb);
2253
  SSL_CTX_set_tlsext_servername_arg(ctx, cbinfo);
2784
  SSL_CTX_set_tlsext_servername_arg(ctx, state);
2785
2786
# ifdef EXIM_HAVE_ALPN
2787
  if (tls_alpn && *tls_alpn)
2788
    {
2789
    uschar * exp_alpn;
2790
    if (  expand_check(tls_alpn, US"tls_alpn", &exp_alpn, errstr)
2791
       && *exp_alpn && !isblank(*exp_alpn))
2792
      {
2793
      tls_alpn = exp_alpn;	/* subprocess so ok to overwrite */
2794
      SSL_CTX_set_alpn_select_cb(ctx, tls_server_alpn_cb, state);
2795
      }
2796
    else
2797
      tls_alpn = NULL;
2798
    }
2799
# endif
2254
  }
2800
  }
2255
# ifndef DISABLE_OCSP
2801
# ifndef DISABLE_OCSP
2256
else			/* client */
2802
else			/* client */
2257
  if(ocsp_file)		/* wanting stapling */
2803
  if(ocsp_file)		/* wanting stapling */
2258
    {
2804
    {
2259
    if (!(cbinfo->u_ocsp.client.verify_store = X509_STORE_new()))
2805
    if (!(state->u_ocsp.client.verify_store = X509_STORE_new()))
2260
      {
2806
      {
2261
      DEBUG(D_tls) debug_printf("failed to create store for stapling verify\n");
2807
      DEBUG(D_tls) debug_printf("failed to create store for stapling verify\n");
2262
      return FAIL;
2808
      return FAIL;
2263
      }
2809
      }
2264
    SSL_CTX_set_tlsext_status_cb(ctx, tls_client_stapling_cb);
2810
    SSL_CTX_set_tlsext_status_cb(ctx, tls_client_stapling_cb);
2265
    SSL_CTX_set_tlsext_status_arg(ctx, cbinfo);
2811
    SSL_CTX_set_tlsext_status_arg(ctx, state);
2266
    }
2812
    }
2267
# endif
2813
# endif
2268
#endif
2814
#endif
2269
2815
2270
cbinfo->verify_cert_hostnames = NULL;
2816
state->verify_cert_hostnames = NULL;
2271
2817
2272
#ifdef EXIM_HAVE_EPHEM_RSA_KEX
2818
#ifdef EXIM_HAVE_EPHEM_RSA_KEX
2273
/* Set up the RSA callback */
2819
/* Set up the RSA callback */
Lines 2280-2287 Link Here
2280
SSL_CTX_set_timeout(ctx, ssl_session_timeout);
2826
SSL_CTX_set_timeout(ctx, ssl_session_timeout);
2281
DEBUG(D_tls) debug_printf("Initialized TLS\n");
2827
DEBUG(D_tls) debug_printf("Initialized TLS\n");
2282
2828
2283
*cbp = cbinfo;
2829
*caller_state = state;
2284
*ctxp = ctx;
2285
2830
2286
return OK;
2831
return OK;
2287
}
2832
}
Lines 2408-2425 Link Here
2408
/* Load certs from file, return TRUE on success */
2953
/* Load certs from file, return TRUE on success */
2409
2954
2410
static BOOL
2955
static BOOL
2411
chain_from_pem_file(const uschar * file, STACK_OF(X509) * verify_stack)
2956
chain_from_pem_file(const uschar * file, STACK_OF(X509) ** vp)
2412
{
2957
{
2413
BIO * bp;
2958
BIO * bp;
2414
X509 * x;
2959
STACK_OF(X509) * verify_stack = *vp;
2415
2960
2416
while (sk_X509_num(verify_stack) > 0)
2961
if (verify_stack)
2417
  X509_free(sk_X509_pop(verify_stack));
2962
  while (sk_X509_num(verify_stack) > 0)
2963
    X509_free(sk_X509_pop(verify_stack));
2964
else
2965
  verify_stack = sk_X509_new_null();
2418
2966
2419
if (!(bp = BIO_new_file(CS file, "r"))) return FALSE;
2967
if (!(bp = BIO_new_file(CS file, "r"))) return FALSE;
2420
while ((x = PEM_read_bio_X509(bp, NULL, 0, NULL)))
2968
for (X509 * x; x = PEM_read_bio_X509(bp, NULL, 0, NULL); )
2421
  sk_X509_push(verify_stack, x);
2969
  sk_X509_push(verify_stack, x);
2422
BIO_free(bp);
2970
BIO_free(bp);
2971
*vp = verify_stack;
2423
return TRUE;
2972
return TRUE;
2424
}
2973
}
2425
#endif
2974
#endif
Lines 2431-2450 Link Here
2431
2980
2432
Arguments:
2981
Arguments:
2433
  sctx          SSL_CTX* to initialise
2982
  sctx          SSL_CTX* to initialise
2434
  certs         certs file or NULL
2983
  certs         certs file, expanded
2435
  crl           CRL file or NULL
2984
  crl           CRL file or NULL
2436
  host          NULL in a server; the remote host in a client
2985
  host          NULL in a server; the remote host in a client
2437
  optional      TRUE if called from a server for a host in tls_try_verify_hosts;
2438
                otherwise passed as FALSE
2439
  cert_vfy_cb	Callback function for certificate verification
2440
  errstr	error string pointer
2986
  errstr	error string pointer
2441
2987
2442
Returns:        OK/DEFER/FAIL
2988
Returns:        OK/DEFER/FAIL
2443
*/
2989
*/
2444
2990
2445
static int
2991
static int
2446
setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host, BOOL optional,
2992
setup_certs(SSL_CTX *sctx, uschar *certs, uschar *crl, host_item *host,
2447
    int (*cert_vfy_cb)(int, X509_STORE_CTX *), uschar ** errstr)
2993
    uschar ** errstr)
2448
{
2994
{
2449
uschar *expcerts, *expcrl;
2995
uschar *expcerts, *expcrl;
2450
2996
Lines 2460-2466 Link Here
2460
  if (!SSL_CTX_set_default_verify_paths(sctx))
3006
  if (!SSL_CTX_set_default_verify_paths(sctx))
2461
    return tls_error(US"SSL_CTX_set_default_verify_paths", host, NULL, errstr);
3007
    return tls_error(US"SSL_CTX_set_default_verify_paths", host, NULL, errstr);
2462
3008
2463
  if (Ustrcmp(expcerts, "system") != 0)
3009
  if (Ustrcmp(expcerts, "system") != 0 && Ustrncmp(expcerts, "system,", 7) != 0)
2464
    {
3010
    {
2465
    struct stat statbuf;
3011
    struct stat statbuf;
2466
3012
Lines 2477-2482 Link Here
2477
	{ file = NULL; dir = expcerts; }
3023
	{ file = NULL; dir = expcerts; }
2478
      else
3024
      else
2479
	{
3025
	{
3026
	STACK_OF(X509) * verify_stack =
3027
#ifndef DISABLE_OCSP
3028
	  !host ? state_server.verify_stack :
3029
#endif
3030
	  NULL;
3031
	STACK_OF(X509) ** vp = &verify_stack;
3032
2480
	file = expcerts; dir = NULL;
3033
	file = expcerts; dir = NULL;
2481
#ifndef DISABLE_OCSP
3034
#ifndef DISABLE_OCSP
2482
	/* In the server if we will be offering an OCSP proof, load chain from
3035
	/* In the server if we will be offering an OCSP proof, load chain from
Lines 2485-2495 Link Here
2485
/*XXX Glitch!   The file here is tls_verify_certs: the chain for verifying the client cert.
3038
/*XXX Glitch!   The file here is tls_verify_certs: the chain for verifying the client cert.
2486
This is inconsistent with the need to verify the OCSP proof of the server cert.
3039
This is inconsistent with the need to verify the OCSP proof of the server cert.
2487
*/
3040
*/
2488
2489
	if (  !host
3041
	if (  !host
2490
	   && statbuf.st_size > 0
3042
	   && statbuf.st_size > 0
2491
	   && server_static_cbinfo->u_ocsp.server.file
3043
	   && state_server.u_ocsp.server.file
2492
	   && !chain_from_pem_file(file, server_static_cbinfo->verify_stack)
3044
	   && !chain_from_pem_file(file, vp)
2493
	   )
3045
	   )
2494
	  {
3046
	  {
2495
	  log_write(0, LOG_MAIN|LOG_PANIC,
3047
	  log_write(0, LOG_MAIN|LOG_PANIC,
Lines 2506-2512 Link Here
2506
3058
2507
      if (  (!file || statbuf.st_size > 0)
3059
      if (  (!file || statbuf.st_size > 0)
2508
         && !SSL_CTX_load_verify_locations(sctx, CS file, CS dir))
3060
         && !SSL_CTX_load_verify_locations(sctx, CS file, CS dir))
2509
	return tls_error(US"SSL_CTX_load_verify_locations", host, NULL, errstr);
3061
	  return tls_error(US"SSL_CTX_load_verify_locations",
3062
			    host, NULL, errstr);
2510
3063
2511
      /* On the server load the list of CAs for which we will accept certs, for
3064
      /* On the server load the list of CAs for which we will accept certs, for
2512
      sending to the client.  This is only for the one-file
3065
      sending to the client.  This is only for the one-file
Lines 2521-2531 Link Here
2521
      if (file)
3074
      if (file)
2522
	{
3075
	{
2523
	STACK_OF(X509_NAME) * names = SSL_load_client_CA_file(CS file);
3076
	STACK_OF(X509_NAME) * names = SSL_load_client_CA_file(CS file);
3077
	int i = sk_X509_NAME_num(names);
2524
3078
2525
	if (!host) SSL_CTX_set_client_CA_list(sctx, names);
3079
	if (!host) SSL_CTX_set_client_CA_list(sctx, names);
2526
	DEBUG(D_tls) debug_printf("Added %d certificate authorities.\n",
3080
	DEBUG(D_tls) debug_printf("Added %d additional certificate authorit%s\n",
2527
				    sk_X509_NAME_num(names));
3081
				    i, i>1 ? "ies":"y");
2528
	}
3082
	}
3083
      else
3084
	DEBUG(D_tls)
3085
	  debug_printf("Added dir for additional certificate authorities\n");
2529
      }
3086
      }
2530
    }
3087
    }
2531
3088
Lines 2581-2592 Link Here
2581
    }
3138
    }
2582
3139
2583
#endif  /* OPENSSL_VERSION_NUMBER > 0x00907000L */
3140
#endif  /* OPENSSL_VERSION_NUMBER > 0x00907000L */
2584
2585
  /* If verification is optional, don't fail if no certificate */
2586
2587
  SSL_CTX_set_verify(sctx,
2588
    SSL_VERIFY_PEER | (optional ? 0 : SSL_VERIFY_FAIL_IF_NO_PEER_CERT),
2589
    cert_vfy_cb);
2590
  }
3141
  }
2591
3142
2592
return OK;
3143
return OK;
Lines 2594-2609 Link Here
2594
3145
2595
3146
2596
3147
3148
static void
3149
tls_dump_keylog(SSL * ssl)
3150
{
3151
#ifdef EXIM_HAVE_OPENSSL_KEYLOG
3152
  BIO * bp = BIO_new(BIO_s_mem());
3153
  uschar * s = NULL;
3154
  int len;
3155
  SSL_SESSION_print_keylog(bp, SSL_get_session(ssl));
3156
  len = (int) BIO_get_mem_data(bp, CSS &s);
3157
  if (len > 0) debug_printf("%.*s", len, s);
3158
  BIO_free(bp);
3159
#endif
3160
}
3161
3162
2597
/*************************************************
3163
/*************************************************
2598
*       Start a TLS session in a server          *
3164
*       Start a TLS session in a server          *
2599
*************************************************/
3165
*************************************************/
2600
2601
/* This is called when Exim is running as a server, after having received
3166
/* This is called when Exim is running as a server, after having received
2602
the STARTTLS command. It must respond to that command, and then negotiate
3167
the STARTTLS command. It must respond to that command, and then negotiate
2603
a TLS session.
3168
a TLS session.
2604
3169
2605
Arguments:
3170
Arguments:
2606
  require_ciphers   allowed ciphers
2607
  errstr	    pointer to error message
3171
  errstr	    pointer to error message
2608
3172
2609
Returns:            OK on success
3173
Returns:            OK on success
Lines 2613-2623 Link Here
2613
*/
3177
*/
2614
3178
2615
int
3179
int
2616
tls_server_start(const uschar * require_ciphers, uschar ** errstr)
3180
tls_server_start(uschar ** errstr)
2617
{
3181
{
2618
int rc;
3182
int rc;
2619
uschar * expciphers;
3183
uschar * expciphers;
2620
tls_ext_ctx_cb * cbinfo;
3184
exim_openssl_state_st * dummy_statep;
3185
SSL_CTX * ctx;
3186
SSL * ssl;
2621
static uschar peerdn[256];
3187
static uschar peerdn[256];
2622
3188
2623
/* Check for previous activation */
3189
/* Check for previous activation */
Lines 2632-2647 Link Here
2632
/* Initialize the SSL library. If it fails, it will already have logged
3198
/* Initialize the SSL library. If it fails, it will already have logged
2633
the error. */
3199
the error. */
2634
3200
2635
rc = tls_init(&server_ctx, NULL, tls_dhparam, tls_certificate, tls_privatekey,
3201
rc = tls_init(NULL, NULL,
2636
#ifndef DISABLE_OCSP
3202
#ifndef DISABLE_OCSP
2637
    tls_ocsp_file,
3203
    tls_ocsp_file,
2638
#endif
3204
#endif
2639
    NULL, &server_static_cbinfo, &tls_in, errstr);
3205
    NULL, &dummy_statep, &tls_in, errstr);
2640
if (rc != OK) return rc;
3206
if (rc != OK) return rc;
2641
cbinfo = server_static_cbinfo;
3207
ctx = state_server.lib_state.lib_ctx;
2642
2643
if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers, errstr))
2644
  return FAIL;
2645
3208
2646
/* In OpenSSL, cipher components are separated by hyphens. In GnuTLS, they
3209
/* In OpenSSL, cipher components are separated by hyphens. In GnuTLS, they
2647
were historically separated by underscores. So that I can use either form in my
3210
were historically separated by underscores. So that I can use either form in my
Lines 2652-2664 Link Here
2652
TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
3215
TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256
2653
*/
3216
*/
2654
3217
2655
if (expciphers)
3218
if (state_server.lib_state.pri_string)
3219
  { DEBUG(D_tls) debug_printf("TLS: cipher list was preloaded\n"); }
3220
else 
2656
  {
3221
  {
2657
  for (uschar * s = expciphers; *s; s++ ) if (*s == '_') *s = '-';
3222
  if (!expand_check(tls_require_ciphers, US"tls_require_ciphers", &expciphers, errstr))
2658
  DEBUG(D_tls) debug_printf("required ciphers: %s\n", expciphers);
3223
    return FAIL;
2659
  if (!SSL_CTX_set_cipher_list(server_ctx, CS expciphers))
3224
2660
    return tls_error(US"SSL_CTX_set_cipher_list", NULL, NULL, errstr);
3225
  if (expciphers)
2661
  cbinfo->server_cipher_list = expciphers;
3226
    {
3227
    normalise_ciphers(&expciphers, tls_require_ciphers);
3228
    if ((rc = server_load_ciphers(ctx, &state_server, expciphers, errstr)) != OK)
3229
      return rc;
3230
    }
2662
  }
3231
  }
2663
3232
2664
/* If this is a host for which certificate verification is mandatory or
3233
/* If this is a host for which certificate verification is mandatory or
Lines 2671-2707 Link Here
2671
server_verify_callback_called = FALSE;
3240
server_verify_callback_called = FALSE;
2672
3241
2673
if (verify_check_host(&tls_verify_hosts) == OK)
3242
if (verify_check_host(&tls_verify_hosts) == OK)
2674
  {
2675
  rc = setup_certs(server_ctx, tls_verify_certificates, tls_crl, NULL,
2676
			FALSE, verify_callback_server, errstr);
2677
  if (rc != OK) return rc;
2678
  server_verify_optional = FALSE;
3243
  server_verify_optional = FALSE;
2679
  }
2680
else if (verify_check_host(&tls_try_verify_hosts) == OK)
3244
else if (verify_check_host(&tls_try_verify_hosts) == OK)
2681
  {
2682
  rc = setup_certs(server_ctx, tls_verify_certificates, tls_crl, NULL,
2683
			TRUE, verify_callback_server, errstr);
2684
  if (rc != OK) return rc;
2685
  server_verify_optional = TRUE;
3245
  server_verify_optional = TRUE;
2686
  }
3246
else
3247
  goto skip_certs;
3248
3249
 {
3250
  uschar * expcerts;
3251
  if (!expand_check(tls_verify_certificates, US"tls_verify_certificates",
3252
		    &expcerts, errstr))
3253
    return DEFER;
3254
  DEBUG(D_tls) debug_printf("tls_verify_certificates: %s\n", expcerts);
3255
3256
  if (state_server.lib_state.cabundle)
3257
    { DEBUG(D_tls) debug_printf("TLS: CA bundle for server was preloaded\n"); }
3258
  else
3259
    if ((rc = setup_certs(ctx, expcerts, tls_crl, NULL, errstr)) != OK)
3260
      return rc;
3261
3262
  if (expcerts && *expcerts)
3263
    setup_cert_verify(ctx, server_verify_optional, verify_callback_server);
3264
 }
3265
skip_certs: ;
2687
3266
2688
#ifdef EXPERIMENTAL_TLS_RESUME
3267
#ifndef DISABLE_TLS_RESUME
2689
SSL_CTX_set_tlsext_ticket_key_cb(server_ctx, ticket_key_callback);
3268
# if OPENSSL_VERSION_NUMBER < 0x30000000L
3269
SSL_CTX_set_tlsext_ticket_key_cb(ctx, ticket_key_callback);
2690
/* despite working, appears to always return failure, so ignoring */
3270
/* despite working, appears to always return failure, so ignoring */
3271
# else
3272
SSL_CTX_set_tlsext_ticket_key_evp_cb(ctx, ticket_key_callback);
3273
/* despite working, appears to always return failure, so ignoring */
3274
# endif
2691
#endif
3275
#endif
3276
2692
#ifdef OPENSSL_HAVE_NUM_TICKETS
3277
#ifdef OPENSSL_HAVE_NUM_TICKETS
2693
# ifdef EXPERIMENTAL_TLS_RESUME
3278
# ifndef DISABLE_TLS_RESUME
2694
SSL_CTX_set_num_tickets(server_ctx, tls_in.host_resumable ? 1 : 0);
3279
SSL_CTX_set_num_tickets(ctx, tls_in.host_resumable ? 1 : 0);
2695
# else
3280
# else
2696
SSL_CTX_set_num_tickets(server_ctx, 0);	/* send no TLS1.3 stateful-tickets */
3281
SSL_CTX_set_num_tickets(ctx, 0);	/* send no TLS1.3 stateful-tickets */
2697
# endif
3282
# endif
2698
#endif
3283
#endif
2699
3284
2700
3285
2701
/* Prepare for new connection */
3286
/* Prepare for new connection */
2702
3287
2703
if (!(server_ssl = SSL_new(server_ctx)))
3288
if (!(ssl = SSL_new(ctx)))
2704
  return tls_error(US"SSL_new", NULL, NULL, errstr);
3289
  return tls_error(US"SSL_new", NULL, NULL, errstr);
3290
state_server.lib_state.lib_ssl = ssl;
2705
3291
2706
/* Warning: we used to SSL_clear(ssl) here, it was removed.
3292
/* Warning: we used to SSL_clear(ssl) here, it was removed.
2707
 *
3293
 *
Lines 2722-2728 Link Here
2722
the response. Other smtp_printf() calls do not need it, because in non-TLS
3308
the response. Other smtp_printf() calls do not need it, because in non-TLS
2723
mode, the fflush() happens when smtp_getc() is called. */
3309
mode, the fflush() happens when smtp_getc() is called. */
2724
3310
2725
SSL_set_session_id_context(server_ssl, sid_ctx, Ustrlen(sid_ctx));
3311
SSL_set_session_id_context(ssl, sid_ctx, Ustrlen(sid_ctx));
2726
if (!tls_in.on_connect)
3312
if (!tls_in.on_connect)
2727
  {
3313
  {
2728
  smtp_printf("220 TLS go ahead\r\n", FALSE);
3314
  smtp_printf("220 TLS go ahead\r\n", FALSE);
Lines 2732-2751 Link Here
2732
/* Now negotiate the TLS session. We put our own timer on it, since it seems
3318
/* Now negotiate the TLS session. We put our own timer on it, since it seems
2733
that the OpenSSL library doesn't. */
3319
that the OpenSSL library doesn't. */
2734
3320
2735
SSL_set_wfd(server_ssl, fileno(smtp_out));
3321
SSL_set_wfd(ssl, fileno(smtp_out));
2736
SSL_set_rfd(server_ssl, fileno(smtp_in));
3322
SSL_set_rfd(ssl, fileno(smtp_in));
2737
SSL_set_accept_state(server_ssl);
3323
SSL_set_accept_state(ssl);
2738
3324
2739
DEBUG(D_tls) debug_printf("Calling SSL_accept\n");
3325
DEBUG(D_tls) debug_printf("Calling SSL_accept\n");
2740
3326
3327
ERR_clear_error();
2741
sigalrm_seen = FALSE;
3328
sigalrm_seen = FALSE;
2742
if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout);
3329
if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout);
2743
rc = SSL_accept(server_ssl);
3330
rc = SSL_accept(ssl);
2744
ALARM_CLR(0);
3331
ALARM_CLR(0);
2745
3332
2746
if (rc <= 0)
3333
if (rc <= 0)
2747
  {
3334
  {
2748
  int error = SSL_get_error(server_ssl, rc);
3335
  int error = SSL_get_error(ssl, rc);
2749
  switch(error)
3336
  switch(error)
2750
    {
3337
    {
2751
    case SSL_ERROR_NONE:
3338
    case SSL_ERROR_NONE:
Lines 2754-2762 Link Here
2754
    case SSL_ERROR_ZERO_RETURN:
3341
    case SSL_ERROR_ZERO_RETURN:
2755
      DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n");
3342
      DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n");
2756
      (void) tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : NULL, errstr);
3343
      (void) tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : NULL, errstr);
2757
3344
#ifndef DISABLE_EVENT
2758
      if (SSL_get_shutdown(server_ssl) == SSL_RECEIVED_SHUTDOWN)
3345
      (void) event_raise(event_action, US"tls:fail:connect", *errstr, NULL);
2759
	    SSL_shutdown(server_ssl);
3346
#endif
3347
      if (SSL_get_shutdown(ssl) == SSL_RECEIVED_SHUTDOWN)
3348
	SSL_shutdown(ssl);
2760
3349
2761
      tls_close(NULL, TLS_NO_SHUTDOWN);
3350
      tls_close(NULL, TLS_NO_SHUTDOWN);
2762
      return FAIL;
3351
      return FAIL;
Lines 2764-2778 Link Here
2764
    /* Handle genuine errors */
3353
    /* Handle genuine errors */
2765
    case SSL_ERROR_SSL:
3354
    case SSL_ERROR_SSL:
2766
      {
3355
      {
2767
      uschar * s = US"SSL_accept";
3356
      uschar * s = NULL;
2768
      int r = ERR_GET_REASON(ERR_peek_error());
3357
      int r = ERR_GET_REASON(ERR_peek_error());
2769
      if (  r == SSL_R_WRONG_VERSION_NUMBER
3358
      if (  r == SSL_R_WRONG_VERSION_NUMBER
2770
#ifdef SSL_R_VERSION_TOO_LOW
3359
#ifdef SSL_R_VERSION_TOO_LOW
2771
         || r == SSL_R_VERSION_TOO_LOW
3360
         || r == SSL_R_VERSION_TOO_LOW
2772
#endif
3361
#endif
2773
         || r == SSL_R_UNKNOWN_PROTOCOL || r == SSL_R_UNSUPPORTED_PROTOCOL)
3362
         || r == SSL_R_UNKNOWN_PROTOCOL || r == SSL_R_UNSUPPORTED_PROTOCOL)
2774
	s = string_sprintf("%s (%s)", s, SSL_get_version(server_ssl));
3363
	s = string_sprintf("(%s)", SSL_get_version(ssl));
2775
      (void) tls_error(s, NULL, sigalrm_seen ? US"timed out" : NULL, errstr);
3364
      (void) tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : s, errstr);
3365
#ifndef DISABLE_EVENT
3366
      (void) event_raise(event_action, US"tls:fail:connect", *errstr, NULL);
3367
#endif
2776
      return FAIL;
3368
      return FAIL;
2777
      }
3369
      }
2778
3370
Lines 2783-2793 Link Here
2783
	if (!errno)
3375
	if (!errno)
2784
	  {
3376
	  {
2785
	  *errstr = US"SSL_accept: TCP connection closed by peer";
3377
	  *errstr = US"SSL_accept: TCP connection closed by peer";
3378
#ifndef DISABLE_EVENT
3379
	  (void) event_raise(event_action, US"tls:fail:connect", *errstr, NULL);
3380
#endif
2786
	  return FAIL;
3381
	  return FAIL;
2787
	  }
3382
	  }
2788
	DEBUG(D_tls) debug_printf(" - syscall %s\n", strerror(errno));
3383
	DEBUG(D_tls) debug_printf(" - syscall %s\n", strerror(errno));
2789
	}
3384
	}
2790
      (void) tls_error(US"SSL_accept", NULL, sigalrm_seen ? US"timed out" : NULL, errstr);
3385
      (void) tls_error(US"SSL_accept", NULL,
3386
		      sigalrm_seen ? US"timed out"
3387
		      : ERR_peek_error() ? NULL : string_sprintf("ret %d", error),
3388
		      errstr);
3389
#ifndef DISABLE_EVENT
3390
      (void) event_raise(event_action, US"tls:fail:connect", *errstr, NULL);
3391
#endif
2791
      return FAIL;
3392
      return FAIL;
2792
    }
3393
    }
2793
  }
3394
  }
Lines 2796-2838 Link Here
2796
ERR_clear_error();	/* Even success can leave errors in the stack. Seen with
3397
ERR_clear_error();	/* Even success can leave errors in the stack. Seen with
2797
			anon-authentication ciphersuite negotiated. */
3398
			anon-authentication ciphersuite negotiated. */
2798
3399
2799
#ifdef EXPERIMENTAL_TLS_RESUME
3400
#ifndef DISABLE_TLS_RESUME
2800
if (SSL_session_reused(server_ssl))
3401
if (SSL_session_reused(ssl))
2801
  {
3402
  {
2802
  tls_in.resumption |= RESUME_USED;
3403
  tls_in.resumption |= RESUME_USED;
2803
  DEBUG(D_tls) debug_printf("Session reused\n");
3404
  DEBUG(D_tls) debug_printf("Session reused\n");
2804
  }
3405
  }
2805
#endif
3406
#endif
2806
3407
3408
#ifdef EXIM_HAVE_ALPN
3409
/* If require-alpn, check server_seen_alpn here.  Else abort TLS */
3410
if (!tls_alpn || !*tls_alpn)
3411
  { DEBUG(D_tls) debug_printf("TLS: was not watching for ALPN\n"); }
3412
else if (!server_seen_alpn)
3413
  if (verify_check_host(&hosts_require_alpn) == OK)
3414
    {
3415
    /* We'd like to send a definitive Alert but OpenSSL provides no facility */
3416
    SSL_shutdown(ssl);
3417
    tls_error(US"handshake", NULL, US"ALPN required but not negotiated", errstr);
3418
    return FAIL;
3419
    }
3420
  else
3421
    { DEBUG(D_tls) debug_printf("TLS: no ALPN presented in handshake\n"); }
3422
else DEBUG(D_tls)
3423
  {
3424
  const uschar * name;
3425
  unsigned len;
3426
  SSL_get0_alpn_selected(ssl, &name, &len);
3427
  if (len && name)
3428
    debug_printf("ALPN negotiated: '%.*s'\n", (int)*name, name+1);
3429
  else
3430
    debug_printf("ALPN: no protocol negotiated\n");
3431
  }
3432
#endif
3433
3434
2807
/* TLS has been set up. Record data for the connection,
3435
/* TLS has been set up. Record data for the connection,
2808
adjust the input functions to read via TLS, and initialize things. */
3436
adjust the input functions to read via TLS, and initialize things. */
2809
3437
2810
#ifdef SSL_get_extms_support
3438
#ifdef SSL_get_extms_support
2811
tls_in.ext_master_secret = SSL_get_extms_support(server_ssl) == 1;
3439
tls_in.ext_master_secret = SSL_get_extms_support(ssl) == 1;
2812
#endif
3440
#endif
2813
peer_cert(server_ssl, &tls_in, peerdn, sizeof(peerdn));
3441
peer_cert(ssl, &tls_in, peerdn, sizeof(peerdn));
2814
3442
2815
tls_in.ver = tlsver_name(server_ssl);
3443
tls_in.ver = tlsver_name(ssl);
2816
tls_in.cipher = construct_cipher_name(server_ssl, tls_in.ver, &tls_in.bits);
3444
tls_in.cipher = construct_cipher_name(ssl, tls_in.ver, &tls_in.bits);
2817
tls_in.cipher_stdname = cipher_stdname_ssl(server_ssl);
3445
tls_in.cipher_stdname = cipher_stdname_ssl(ssl);
2818
3446
2819
DEBUG(D_tls)
3447
DEBUG(D_tls)
2820
  {
3448
  {
2821
  uschar buf[2048];
3449
  uschar buf[2048];
2822
  if (SSL_get_shared_ciphers(server_ssl, CS buf, sizeof(buf)))
3450
  if (SSL_get_shared_ciphers(ssl, CS buf, sizeof(buf)))
2823
    debug_printf("Shared ciphers: %s\n", buf);
3451
    debug_printf("Shared ciphers: %s\n", buf);
2824
3452
2825
#ifdef EXIM_HAVE_OPENSSL_KEYLOG
3453
  tls_dump_keylog(ssl);
2826
  {
2827
  BIO * bp = BIO_new_fp(debug_file, BIO_NOCLOSE);
2828
  SSL_SESSION_print_keylog(bp, SSL_get_session(server_ssl));
2829
  BIO_free(bp);
2830
  }
2831
#endif
2832
3454
2833
#ifdef EXIM_HAVE_SESSION_TICKET
3455
#ifdef EXIM_HAVE_SESSION_TICKET
2834
  {
3456
  {
2835
  SSL_SESSION * ss = SSL_get_session(server_ssl);
3457
  SSL_SESSION * ss = SSL_get_session(ssl);
2836
  if (SSL_SESSION_has_ticket(ss))	/* 1.1.0 */
3458
  if (SSL_SESSION_has_ticket(ss))	/* 1.1.0 */
2837
    debug_printf("The session has a ticket, life %lu seconds\n",
3459
    debug_printf("The session has a ticket, life %lu seconds\n",
2838
      SSL_SESSION_get_ticket_lifetime_hint(ss));
3460
      SSL_SESSION_get_ticket_lifetime_hint(ss));
Lines 2842-2848 Link Here
2842
3464
2843
/* Record the certificate we presented */
3465
/* Record the certificate we presented */
2844
  {
3466
  {
2845
  X509 * crt = SSL_get_certificate(server_ssl);
3467
  X509 * crt = SSL_get_certificate(ssl);
2846
  tls_in.ourcert = crt ? X509_dup(crt) : NULL;
3468
  tls_in.ourcert = crt ? X509_dup(crt) : NULL;
2847
  }
3469
  }
2848
3470
Lines 2850-2861 Link Here
2850
See description in https://paquier.xyz/postgresql-2/channel-binding-openssl/ */
3472
See description in https://paquier.xyz/postgresql-2/channel-binding-openssl/ */
2851
  {
3473
  {
2852
  uschar c, * s;
3474
  uschar c, * s;
2853
  size_t len = SSL_get_peer_finished(server_ssl, &c, 0);
3475
  size_t len = SSL_get_peer_finished(ssl, &c, 0);
2854
  int old_pool = store_pool;
3476
  int old_pool = store_pool;
2855
3477
2856
  SSL_get_peer_finished(server_ssl, s = store_get((int)len, FALSE), len);
3478
  SSL_get_peer_finished(ssl, s = store_get((int)len, GET_UNTAINTED), len);
2857
  store_pool = POOL_PERM;
3479
  store_pool = POOL_PERM;
2858
    tls_in.channelbinding = b64encode_taint(CUS s, (int)len, FALSE);
3480
    tls_in.channelbinding = b64encode_taint(CUS s, (int)len, GET_UNTAINTED);
2859
  store_pool = old_pool;
3481
  store_pool = old_pool;
2860
  DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage %p\n", tls_in.channelbinding);
3482
  DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage %p\n", tls_in.channelbinding);
2861
  }
3483
  }
Lines 2872-2881 Link Here
2872
receive_getc = tls_getc;
3494
receive_getc = tls_getc;
2873
receive_getbuf = tls_getbuf;
3495
receive_getbuf = tls_getbuf;
2874
receive_get_cache = tls_get_cache;
3496
receive_get_cache = tls_get_cache;
3497
receive_hasc = tls_hasc;
2875
receive_ungetc = tls_ungetc;
3498
receive_ungetc = tls_ungetc;
2876
receive_feof = tls_feof;
3499
receive_feof = tls_feof;
2877
receive_ferror = tls_ferror;
3500
receive_ferror = tls_ferror;
2878
receive_smtp_buffered = tls_smtp_buffered;
2879
3501
2880
tls_in.active.sock = fileno(smtp_out);
3502
tls_in.active.sock = fileno(smtp_out);
2881
tls_in.active.tls_ctx = NULL;	/* not using explicit ctx for server-side */
3503
tls_in.active.tls_ctx = NULL;	/* not using explicit ctx for server-side */
Lines 2887-2902 Link Here
2887
3509
2888
static int
3510
static int
2889
tls_client_basic_ctx_init(SSL_CTX * ctx,
3511
tls_client_basic_ctx_init(SSL_CTX * ctx,
2890
    host_item * host, smtp_transport_options_block * ob, tls_ext_ctx_cb * cbinfo,
3512
    host_item * host, smtp_transport_options_block * ob, exim_openssl_state_st * state,
2891
    uschar ** errstr)
3513
    uschar ** errstr)
2892
{
3514
{
2893
int rc;
3515
int rc;
2894
/* stick to the old behaviour for compatibility if tls_verify_certificates is
2895
   set but both tls_verify_hosts and tls_try_verify_hosts is not set. Check only
2896
   the specified host patterns if one of them is defined */
2897
3516
2898
if (  (  !ob->tls_verify_hosts
3517
/* Back-compatible old behaviour if tls_verify_certificates is set but both
2899
      && (!ob->tls_try_verify_hosts || !*ob->tls_try_verify_hosts)
3518
tls_verify_hosts and tls_try_verify_hosts are not set. Check only the specified
3519
host patterns if one of them is set with content. */
3520
3521
if (  (  (  !ob->tls_verify_hosts || !ob->tls_verify_hosts
3522
	 || Ustrcmp(ob->tls_try_verify_hosts, ":") == 0
3523
	 )
3524
      && (  !ob->tls_try_verify_hosts || !*ob->tls_try_verify_hosts
3525
	 || Ustrcmp(ob->tls_try_verify_hosts, ":") == 0
3526
         )
2900
      )
3527
      )
2901
   || verify_check_given_host(CUSS &ob->tls_verify_hosts, host) == OK
3528
   || verify_check_given_host(CUSS &ob->tls_verify_hosts, host) == OK
2902
   )
3529
   )
Lines 2906-2926 Link Here
2906
else
3533
else
2907
  return OK;
3534
  return OK;
2908
3535
2909
if ((rc = setup_certs(ctx, ob->tls_verify_certificates,
3536
 {
2910
      ob->tls_crl, host, client_verify_optional, verify_callback_client,
3537
  uschar * expcerts;
2911
      errstr)) != OK)
3538
  if (!expand_check(ob->tls_verify_certificates, US"tls_verify_certificates",
2912
  return rc;
3539
		    &expcerts, errstr))
3540
    return DEFER;
3541
  DEBUG(D_tls) debug_printf("tls_verify_certificates: %s\n", expcerts);
3542
3543
  if (state->lib_state.cabundle)
3544
    { DEBUG(D_tls) debug_printf("TLS: CA bundle was preloaded\n"); }
3545
  else
3546
    if ((rc = setup_certs(ctx, expcerts, ob->tls_crl, host, errstr)) != OK)
3547
      return rc;
3548
3549
  if (expcerts && *expcerts)
3550
    setup_cert_verify(ctx, client_verify_optional, verify_callback_client);
3551
 }
2913
3552
2914
if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK)
3553
if (verify_check_given_host(CUSS &ob->tls_verify_cert_hostnames, host) == OK)
2915
  {
3554
  {
2916
  cbinfo->verify_cert_hostnames =
3555
  state->verify_cert_hostnames =
2917
#ifdef SUPPORT_I18N
3556
#ifdef SUPPORT_I18N
2918
    string_domain_utf8_to_alabel(host->certname, NULL);
3557
    string_domain_utf8_to_alabel(host->certname, NULL);
2919
#else
3558
#else
2920
    host->certname;
3559
    host->certname;
2921
#endif
3560
#endif
2922
  DEBUG(D_tls) debug_printf("Cert hostname to check: \"%s\"\n",
3561
  DEBUG(D_tls) debug_printf("Cert hostname to check: \"%s\"\n",
2923
		    cbinfo->verify_cert_hostnames);
3562
		    state->verify_cert_hostnames);
2924
  }
3563
  }
2925
return OK;
3564
return OK;
2926
}
3565
}
Lines 2983-3008 Link Here
2983
3622
2984
3623
2985
3624
2986
#ifdef EXPERIMENTAL_TLS_RESUME
3625
#ifndef DISABLE_TLS_RESUME
2987
/* On the client, get any stashed session for the given IP from hints db
3626
/* On the client, get any stashed session for the given IP from hints db
2988
and apply it to the ssl-connection for attempted resumption. */
3627
and apply it to the ssl-connection for attempted resumption. */
2989
3628
2990
static void
3629
static void
2991
tls_retrieve_session(tls_support * tlsp, SSL * ssl, const uschar * key)
3630
tls_retrieve_session(tls_support * tlsp, SSL * ssl)
2992
{
3631
{
2993
tlsp->resumption |= RESUME_SUPPORTED;
2994
if (tlsp->host_resumable)
3632
if (tlsp->host_resumable)
2995
  {
3633
  {
3634
  const uschar * key = tlsp->resume_index;
2996
  dbdata_tls_session * dt;
3635
  dbdata_tls_session * dt;
2997
  int len;
3636
  int len;
2998
  open_db dbblock, * dbm_file;
3637
  open_db dbblock, * dbm_file;
2999
3638
3000
  tlsp->resumption |= RESUME_CLIENT_REQUESTED;
3639
  tlsp->resumption |= RESUME_CLIENT_REQUESTED;
3001
  DEBUG(D_tls) debug_printf("checking for resumable session for %s\n", key);
3640
  DEBUG(D_tls)
3641
    debug_printf("checking for resumable session for %s\n", tlsp->resume_index);
3002
  if ((dbm_file = dbfn_open(US"tls", O_RDWR, &dbblock, FALSE, FALSE)))
3642
  if ((dbm_file = dbfn_open(US"tls", O_RDWR, &dbblock, FALSE, FALSE)))
3003
    {
3643
    {
3004
    /* key for the db is the IP */
3644
    if ((dt = dbfn_read_with_length(dbm_file, tlsp->resume_index, &len)))
3005
    if ((dt = dbfn_read_with_length(dbm_file, key, &len)))
3006
      {
3645
      {
3007
      SSL_SESSION * ss = NULL;
3646
      SSL_SESSION * ss = NULL;
3008
      const uschar * sess_asn1 = dt->session;
3647
      const uschar * sess_asn1 = dt->session;
Lines 3017-3046 Link Here
3017
	  debug_printf("decoding session: %s\n", ssl_errstring);
3656
	  debug_printf("decoding session: %s\n", ssl_errstring);
3018
	  }
3657
	  }
3019
	}
3658
	}
3020
#ifdef EXIM_HAVE_SESSION_TICKET
3659
      else
3021
      else if ( SSL_SESSION_get_ticket_lifetime_hint(ss) + dt->time_stamp
3022
	       < time(NULL))
3023
	{
3660
	{
3024
	DEBUG(D_tls) debug_printf("session expired\n");
3661
	unsigned long lifetime =
3025
	dbfn_delete(dbm_file, key);
3662
#ifdef EXIM_HAVE_SESSION_TICKET
3026
	}
3663
	  SSL_SESSION_get_ticket_lifetime_hint(ss);
3664
#else			/* Use, fairly arbitrilarily, what we as server would */
3665
	  f.running_in_test_harness ? 6 : ssl_session_timeout;
3027
#endif
3666
#endif
3028
      else if (!SSL_set_session(ssl, ss))
3667
	if (lifetime + dt->time_stamp < time(NULL))
3029
	{
3668
	  {
3030
	DEBUG(D_tls)
3669
	  DEBUG(D_tls) debug_printf("session expired\n");
3670
	  dbfn_delete(dbm_file, tlsp->resume_index);
3671
	  }
3672
	else if (SSL_set_session(ssl, ss))
3673
	  {
3674
	  DEBUG(D_tls) debug_printf("good session\n");
3675
	  tlsp->resumption |= RESUME_CLIENT_SUGGESTED;
3676
	  tlsp->verify_override = dt->verify_override;
3677
	  tlsp->ocsp = dt->ocsp;
3678
	  }
3679
	else DEBUG(D_tls)
3031
	  {
3680
	  {
3032
	  ERR_error_string_n(ERR_get_error(),
3681
	  ERR_error_string_n(ERR_get_error(),
3033
	    ssl_errstring, sizeof(ssl_errstring));
3682
	    ssl_errstring, sizeof(ssl_errstring));
3034
	  debug_printf("applying session to ssl: %s\n", ssl_errstring);
3683
	  debug_printf("applying session to ssl: %s\n", ssl_errstring);
3035
	  }
3684
	  }
3036
	}
3685
	}
3037
      else
3038
	{
3039
	DEBUG(D_tls) debug_printf("good session\n");
3040
	tlsp->resumption |= RESUME_CLIENT_SUGGESTED;
3041
	tlsp->verify_override = dt->verify_override;
3042
	tlsp->ocsp = dt->ocsp;
3043
	}
3044
      }
3686
      }
3045
    else
3687
    else
3046
      DEBUG(D_tls) debug_printf("no session record\n");
3688
      DEBUG(D_tls) debug_printf("no session record\n");
Lines 3055-3061 Link Here
3055
static int
3697
static int
3056
tls_save_session_cb(SSL * ssl, SSL_SESSION * ss)
3698
tls_save_session_cb(SSL * ssl, SSL_SESSION * ss)
3057
{
3699
{
3058
tls_ext_ctx_cb * cbinfo = SSL_get_ex_data(ssl, tls_exdata_idx);
3700
exim_openssl_state_st * cbinfo = SSL_get_ex_data(ssl, tls_exdata_idx);
3059
tls_support * tlsp;
3701
tls_support * tlsp;
3060
3702
3061
DEBUG(D_tls) debug_printf("tls_save_session_cb\n");
3703
DEBUG(D_tls) debug_printf("tls_save_session_cb\n");
Lines 3068-3074 Link Here
3068
  {
3710
  {
3069
  int len = i2d_SSL_SESSION(ss, NULL);
3711
  int len = i2d_SSL_SESSION(ss, NULL);
3070
  int dlen = sizeof(dbdata_tls_session) + len;
3712
  int dlen = sizeof(dbdata_tls_session) + len;
3071
  dbdata_tls_session * dt = store_get(dlen, TRUE);
3713
  dbdata_tls_session * dt = store_get(dlen, GET_TAINTED);
3072
  uschar * s = dt->session;
3714
  uschar * s = dt->session;
3073
  open_db dbblock, * dbm_file;
3715
  open_db dbblock, * dbm_file;
3074
3716
Lines 3081-3089 Link Here
3081
3723
3082
  if ((dbm_file = dbfn_open(US"tls", O_RDWR, &dbblock, FALSE, FALSE)))
3724
  if ((dbm_file = dbfn_open(US"tls", O_RDWR, &dbblock, FALSE, FALSE)))
3083
    {
3725
    {
3084
    const uschar * key = cbinfo->host->address;
3726
    dbfn_write(dbm_file, tlsp->resume_index, dt, dlen);
3085
    dbfn_delete(dbm_file, key);
3086
    dbfn_write(dbm_file, key, dt, dlen);
3087
    dbfn_close(dbm_file);
3727
    dbfn_close(dbm_file);
3088
    DEBUG(D_tls) debug_printf("wrote session (len %u) to db\n",
3728
    DEBUG(D_tls) debug_printf("wrote session (len %u) to db\n",
3089
		  (unsigned)dlen);
3729
		  (unsigned)dlen);
Lines 3093-3113 Link Here
3093
}
3733
}
3094
3734
3095
3735
3736
/* Construct a key for session DB lookup, and setup the SSL_CTX for resumption */
3737
3096
static void
3738
static void
3097
tls_client_ctx_resume_prehandshake(
3739
tls_client_ctx_resume_prehandshake(
3098
  exim_openssl_client_tls_ctx * exim_client_ctx, tls_support * tlsp,
3740
  exim_openssl_client_tls_ctx * exim_client_ctx, smtp_connect_args * conn_args,
3099
  smtp_transport_options_block * ob, host_item * host)
3741
  tls_support * tlsp, smtp_transport_options_block * ob)
3100
{
3742
{
3101
/* Should the client request a session resumption ticket? */
3743
tlsp->host_resumable = TRUE;
3102
if (verify_check_given_host(CUSS &ob->tls_resumption_hosts, host) == OK)
3744
tls_client_resmption_key(tlsp, conn_args, ob);
3103
  {
3104
  tlsp->host_resumable = TRUE;
3105
3745
3106
  SSL_CTX_set_session_cache_mode(exim_client_ctx->ctx,
3746
SSL_CTX_set_session_cache_mode(exim_client_ctx->ctx,
3107
	SSL_SESS_CACHE_CLIENT
3747
      SSL_SESS_CACHE_CLIENT
3108
	| SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_NO_AUTO_CLEAR);
3748
      | SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_NO_AUTO_CLEAR);
3109
  SSL_CTX_sess_set_new_cb(exim_client_ctx->ctx, tls_save_session_cb);
3749
SSL_CTX_sess_set_new_cb(exim_client_ctx->ctx, tls_save_session_cb);
3110
  }
3111
}
3750
}
3112
3751
3113
static BOOL
3752
static BOOL
Lines 3121-3137 Link Here
3121
  SSL_clear_options(ssl, SSL_OP_NO_TICKET);
3760
  SSL_clear_options(ssl, SSL_OP_NO_TICKET);
3122
3761
3123
  tls_exdata_idx = SSL_get_ex_new_index(0, 0, 0, 0, 0);
3762
  tls_exdata_idx = SSL_get_ex_new_index(0, 0, 0, 0, 0);
3124
  if (!SSL_set_ex_data(ssl, tls_exdata_idx, client_static_cbinfo))
3763
  if (!SSL_set_ex_data(ssl, tls_exdata_idx, client_static_state))
3125
    {
3764
    {
3126
    tls_error(US"set ex_data", host, NULL, errstr);
3765
    tls_error(US"set ex_data", host, NULL, errstr);
3127
    return FALSE;
3766
    return FALSE;
3128
    }
3767
    }
3129
  debug_printf("tls_exdata_idx %d cbinfo %p\n", tls_exdata_idx, client_static_cbinfo);
3768
  debug_printf("tls_exdata_idx %d cbinfo %p\n", tls_exdata_idx, client_static_state);
3130
  }
3769
  }
3131
3770
3132
tlsp->resumption = RESUME_SUPPORTED;
3771
tlsp->resumption = RESUME_SUPPORTED;
3133
/* Pick up a previous session, saved on an old ticket */
3772
/* Pick up a previous session, saved on an old ticket */
3134
tls_retrieve_session(tlsp, ssl, host->address);
3773
tls_retrieve_session(tlsp, ssl);
3135
return TRUE;
3774
return TRUE;
3136
}
3775
}
3137
3776
Lines 3145-3151 Link Here
3145
  tlsp->resumption |= RESUME_USED;
3784
  tlsp->resumption |= RESUME_USED;
3146
  }
3785
  }
3147
}
3786
}
3148
#endif	/* EXPERIMENTAL_TLS_RESUME */
3787
#endif	/* !DISABLE_TLS_RESUME */
3788
3789
3790
#ifdef EXIM_HAVE_ALPN
3791
/* Expand and convert an Exim list to an ALPN list.  False return for fail.
3792
NULL plist return for silent no-ALPN.
3793
3794
Overwite the passed-in list with the expanded version.
3795
*/
3796
3797
static BOOL
3798
tls_alpn_plist(uschar ** tls_alpn, const uschar ** plist, unsigned * plen,
3799
  uschar ** errstr)
3800
{
3801
uschar * exp_alpn;
3802
3803
if (!expand_check(*tls_alpn, US"tls_alpn", &exp_alpn, errstr))
3804
  return FALSE;
3805
*tls_alpn = exp_alpn;
3806
3807
if (!exp_alpn)
3808
  {
3809
  DEBUG(D_tls) debug_printf("Setting TLS ALPN forced to fail, not sending\n");
3810
  *plist = NULL;
3811
  }
3812
else
3813
  {
3814
  /* The server implementation only accepts exactly one protocol name
3815
  but it's little extra code complexity in the client. */
3816
3817
  const uschar * list = exp_alpn;
3818
  uschar * p = store_get(Ustrlen(exp_alpn), exp_alpn), * s, * t;
3819
  int sep = 0;
3820
  uschar len;
3821
3822
  for (t = p; s = string_nextinlist(&list, &sep, NULL, 0); t += len)
3823
    {
3824
    *t++ = len = (uschar) Ustrlen(s);
3825
    memcpy(t, s, len);
3826
    }
3827
  *plist = (*plen = t - p) ? p : NULL;
3828
  }
3829
return TRUE;
3830
}
3831
#endif	/* EXIM_HAVE_ALPN */
3149
3832
3150
3833
3151
/*************************************************
3834
/*************************************************
Lines 3186-3192 Link Here
3186
3869
3187
rc = store_pool;
3870
rc = store_pool;
3188
store_pool = POOL_PERM;
3871
store_pool = POOL_PERM;
3189
exim_client_ctx = store_get(sizeof(exim_openssl_client_tls_ctx), FALSE);
3872
exim_client_ctx = store_get(sizeof(exim_openssl_client_tls_ctx), GET_UNTAINTED);
3190
exim_client_ctx->corked = NULL;
3873
exim_client_ctx->corked = NULL;
3191
store_pool = rc;
3874
store_pool = rc;
3192
3875
Lines 3223-3236 Link Here
3223
  }
3906
  }
3224
#endif
3907
#endif
3225
3908
3226
rc = tls_init(&exim_client_ctx->ctx, host, NULL,
3909
rc = tls_init(host, ob,
3227
    ob->tls_certificate, ob->tls_privatekey,
3228
#ifndef DISABLE_OCSP
3910
#ifndef DISABLE_OCSP
3229
    (void *)(long)request_ocsp,
3911
    (void *)(long)request_ocsp,
3230
#endif
3912
#endif
3231
    cookie, &client_static_cbinfo, tlsp, errstr);
3913
    cookie, &client_static_state, tlsp, errstr);
3232
if (rc != OK) return FALSE;
3914
if (rc != OK) return FALSE;
3233
3915
3916
exim_client_ctx->ctx = client_static_state->lib_state.lib_ctx;
3917
3234
tlsp->certificate_verified = FALSE;
3918
tlsp->certificate_verified = FALSE;
3235
client_verify_callback_called = FALSE;
3919
client_verify_callback_called = FALSE;
3236
3920
Lines 3246-3266 Link Here
3246
    return FALSE;
3930
    return FALSE;
3247
  if (expciphers && *expciphers == '\0')
3931
  if (expciphers && *expciphers == '\0')
3248
    expciphers = NULL;
3932
    expciphers = NULL;
3933
3934
  normalise_ciphers(&expciphers, ob->dane_require_tls_ciphers);
3249
  }
3935
  }
3250
#endif
3936
#endif
3251
if (!expciphers &&
3937
if (!expciphers)
3252
    !expand_check(ob->tls_require_ciphers, US"tls_require_ciphers",
3938
  {
3939
  if (!expand_check(ob->tls_require_ciphers, US"tls_require_ciphers",
3253
      &expciphers, errstr))
3940
      &expciphers, errstr))
3254
  return FALSE;
3941
    return FALSE;
3255
3942
3256
/* In OpenSSL, cipher components are separated by hyphens. In GnuTLS, they
3943
  /* In OpenSSL, cipher components are separated by hyphens. In GnuTLS, they
3257
are separated by underscores. So that I can use either form in my tests, and
3944
  are separated by underscores. So that I can use either form in my tests, and
3258
also for general convenience, we turn underscores into hyphens here. */
3945
  also for general convenience, we turn underscores into hyphens here. */
3946
3947
  normalise_ciphers(&expciphers, ob->tls_require_ciphers);
3948
  }
3259
3949
3260
if (expciphers)
3950
if (expciphers)
3261
  {
3951
  {
3262
  uschar *s = expciphers;
3263
  while (*s) { if (*s == '_') *s = '-'; s++; }
3264
  DEBUG(D_tls) debug_printf("required ciphers: %s\n", expciphers);
3952
  DEBUG(D_tls) debug_printf("required ciphers: %s\n", expciphers);
3265
  if (!SSL_CTX_set_cipher_list(exim_client_ctx->ctx, CS expciphers))
3953
  if (!SSL_CTX_set_cipher_list(exim_client_ctx->ctx, CS expciphers))
3266
    {
3954
    {
Lines 3291-3337 Link Here
3291
3979
3292
#endif
3980
#endif
3293
3981
3294
  if (tls_client_basic_ctx_init(exim_client_ctx->ctx, host, ob,
3982
if (tls_client_basic_ctx_init(exim_client_ctx->ctx, host, ob,
3295
	client_static_cbinfo, errstr) != OK)
3983
      client_static_state, errstr) != OK)
3296
    return FALSE;
3297
3298
#ifdef EXPERIMENTAL_TLS_RESUME
3299
tls_client_ctx_resume_prehandshake(exim_client_ctx, tlsp, ob, host);
3300
#endif
3301
3302
3303
if (!(exim_client_ctx->ssl = SSL_new(exim_client_ctx->ctx)))
3304
  {
3305
  tls_error(US"SSL_new", host, NULL, errstr);
3306
  return FALSE;
3984
  return FALSE;
3307
  }
3308
SSL_set_session_id_context(exim_client_ctx->ssl, sid_ctx, Ustrlen(sid_ctx));
3309
3310
SSL_set_fd(exim_client_ctx->ssl, cctx->sock);
3311
SSL_set_connect_state(exim_client_ctx->ssl);
3312
3985
3313
if (ob->tls_sni)
3986
if (ob->tls_sni)
3314
  {
3987
  {
3315
  if (!expand_check(ob->tls_sni, US"tls_sni", &tlsp->sni, errstr))
3988
  if (!expand_check(ob->tls_sni, US"tls_sni", &tlsp->sni, errstr))
3316
    return FALSE;
3989
    return FALSE;
3317
  if (!tlsp->sni)
3990
  if (!tlsp->sni)
3318
    {
3991
    { DEBUG(D_tls) debug_printf("Setting TLS SNI forced to fail, not sending\n"); }
3319
    DEBUG(D_tls) debug_printf("Setting TLS SNI forced to fail, not sending\n");
3320
    }
3321
  else if (!Ustrlen(tlsp->sni))
3992
  else if (!Ustrlen(tlsp->sni))
3322
    tlsp->sni = NULL;
3993
    tlsp->sni = NULL;
3323
  else
3994
  else
3324
    {
3995
    {
3325
#ifdef EXIM_HAVE_OPENSSL_TLSEXT
3996
#ifndef EXIM_HAVE_OPENSSL_TLSEXT
3326
    DEBUG(D_tls) debug_printf("Setting TLS SNI \"%s\"\n", tlsp->sni);
3327
    SSL_set_tlsext_host_name(exim_client_ctx->ssl, tlsp->sni);
3328
#else
3329
    log_write(0, LOG_MAIN, "SNI unusable with this OpenSSL library version; ignoring \"%s\"\n",
3997
    log_write(0, LOG_MAIN, "SNI unusable with this OpenSSL library version; ignoring \"%s\"\n",
3330
          tlsp->sni);
3998
          tlsp->sni);
3999
    tlsp->sni = NULL;
3331
#endif
4000
#endif
3332
    }
4001
    }
3333
  }
4002
  }
3334
4003
4004
if (ob->tls_alpn)
4005
#ifdef EXIM_HAVE_ALPN
4006
  {
4007
  const uschar * plist;
4008
  unsigned plen;
4009
4010
  if (!tls_alpn_plist(&ob->tls_alpn, &plist, &plen, errstr))
4011
    return FALSE;
4012
  if (plist)
4013
    if (SSL_CTX_set_alpn_protos(exim_client_ctx->ctx, plist, plen) != 0)
4014
      {
4015
      tls_error(US"alpn init", host, NULL, errstr);
4016
      return FALSE;
4017
      }
4018
    else
4019
      DEBUG(D_tls) debug_printf("Setting TLS ALPN '%s'\n", ob->tls_alpn);
4020
  }
4021
#else
4022
  log_write(0, LOG_MAIN, "ALPN unusable with this OpenSSL library version; ignoring \"%s\"\n",
4023
          ob->tls_alpn);
4024
#endif
4025
4026
#ifndef DISABLE_TLS_RESUME
4027
/*XXX have_lbserver: another cmdline arg possibly, for continued-conn, but use
4028
will be very low. */
4029
4030
if (!conn_args->have_lbserver)	/* wanted for tls_client_resmption_key() */
4031
  { DEBUG(D_tls) debug_printf("resumption not supported on continued-connection\n"); }
4032
else if (verify_check_given_host(CUSS &ob->tls_resumption_hosts, host) == OK)
4033
  tls_client_ctx_resume_prehandshake(exim_client_ctx, conn_args, tlsp, ob);
4034
#endif
4035
4036
4037
if (!(exim_client_ctx->ssl = SSL_new(exim_client_ctx->ctx)))
4038
  {
4039
  tls_error(US"SSL_new", host, NULL, errstr);
4040
  return FALSE;
4041
  }
4042
SSL_set_session_id_context(exim_client_ctx->ssl, sid_ctx, Ustrlen(sid_ctx));
4043
SSL_set_fd(exim_client_ctx->ssl, cctx->sock);
4044
SSL_set_connect_state(exim_client_ctx->ssl);
4045
4046
#ifdef EXIM_HAVE_OPENSSL_TLSEXT
4047
if (tlsp->sni)
4048
  {
4049
  DEBUG(D_tls) debug_printf("Setting TLS SNI \"%s\"\n", tlsp->sni);
4050
  SSL_set_tlsext_host_name(exim_client_ctx->ssl, tlsp->sni);
4051
  }
4052
#endif
4053
3335
#ifdef SUPPORT_DANE
4054
#ifdef SUPPORT_DANE
3336
if (conn_args->dane)
4055
if (conn_args->dane)
3337
  if (dane_tlsa_load(exim_client_ctx->ssl, host, &conn_args->tlsa_dnsa, errstr) != OK)
4056
  if (dane_tlsa_load(exim_client_ctx->ssl, host, &conn_args->tlsa_dnsa, errstr) != OK)
Lines 3361-3379 Link Here
3361
if (request_ocsp)
4080
if (request_ocsp)
3362
  {
4081
  {
3363
  SSL_set_tlsext_status_type(exim_client_ctx->ssl, TLSEXT_STATUSTYPE_ocsp);
4082
  SSL_set_tlsext_status_type(exim_client_ctx->ssl, TLSEXT_STATUSTYPE_ocsp);
3364
  client_static_cbinfo->u_ocsp.client.verify_required = require_ocsp;
4083
  client_static_state->u_ocsp.client.verify_required = require_ocsp;
3365
  tlsp->ocsp = OCSP_NOT_RESP;
4084
  tlsp->ocsp = OCSP_NOT_RESP;
3366
  }
4085
  }
3367
#endif
4086
#endif
3368
4087
3369
#ifdef EXPERIMENTAL_TLS_RESUME
4088
#ifndef DISABLE_TLS_RESUME
3370
if (!tls_client_ssl_resume_prehandshake(exim_client_ctx->ssl, tlsp, host,
4089
if (!tls_client_ssl_resume_prehandshake(exim_client_ctx->ssl, tlsp, host,
3371
      errstr))
4090
      errstr))
3372
  return FALSE;
4091
  return FALSE;
3373
#endif
4092
#endif
3374
4093
3375
#ifndef DISABLE_EVENT
4094
#ifndef DISABLE_EVENT
3376
client_static_cbinfo->event_action = tb ? tb->event_action : NULL;
4095
client_static_state->event_action = tb ? tb->event_action : NULL;
3377
#endif
4096
#endif
3378
4097
3379
/* There doesn't seem to be a built-in timeout on connection. */
4098
/* There doesn't seem to be a built-in timeout on connection. */
Lines 3398-3416 Link Here
3398
DEBUG(D_tls)
4117
DEBUG(D_tls)
3399
  {
4118
  {
3400
  debug_printf("SSL_connect succeeded\n");
4119
  debug_printf("SSL_connect succeeded\n");
3401
#ifdef EXIM_HAVE_OPENSSL_KEYLOG
4120
  tls_dump_keylog(exim_client_ctx->ssl);
3402
  {
3403
  BIO * bp = BIO_new_fp(debug_file, BIO_NOCLOSE);
3404
  SSL_SESSION_print_keylog(bp, SSL_get_session(exim_client_ctx->ssl));
3405
  BIO_free(bp);
3406
  }
3407
#endif
3408
  }
4121
  }
3409
4122
3410
#ifdef EXPERIMENTAL_TLS_RESUME
4123
#ifndef DISABLE_TLS_RESUME
3411
tls_client_resume_posthandshake(exim_client_ctx, tlsp);
4124
tls_client_resume_posthandshake(exim_client_ctx, tlsp);
3412
#endif
4125
#endif
3413
4126
4127
#ifdef EXIM_HAVE_ALPN
4128
if (ob->tls_alpn)	/* We requested. See what was negotiated. */
4129
  {
4130
  const uschar * name;
4131
  unsigned len;
4132
4133
  SSL_get0_alpn_selected(exim_client_ctx->ssl, &name, &len);
4134
  if (len > 0)
4135
    { DEBUG(D_tls) debug_printf("ALPN negotiated %u: '%.*s'\n", len, (int)*name, name+1); }
4136
  else if (verify_check_given_host(CUSS &ob->hosts_require_alpn, host) == OK)
4137
    {
4138
    /* Would like to send a relevant fatal Alert, but OpenSSL has no API */
4139
    tls_error(US"handshake", host, US"ALPN required but not negotiated", errstr);
4140
    return FALSE;
4141
    }
4142
  }
4143
#endif
4144
3414
#ifdef SSL_get_extms_support
4145
#ifdef SSL_get_extms_support
3415
tlsp->ext_master_secret = SSL_get_extms_support(exim_client_ctx->ssl) == 1;
4146
tlsp->ext_master_secret = SSL_get_extms_support(exim_client_ctx->ssl) == 1;
3416
#endif
4147
#endif
Lines 3433-3441 Link Here
3433
  size_t len = SSL_get_finished(exim_client_ctx->ssl, &c, 0);
4164
  size_t len = SSL_get_finished(exim_client_ctx->ssl, &c, 0);
3434
  int old_pool = store_pool;
4165
  int old_pool = store_pool;
3435
4166
3436
  SSL_get_finished(exim_client_ctx->ssl, s = store_get((int)len, TRUE), len);
4167
  SSL_get_finished(exim_client_ctx->ssl, s = store_get((int)len, GET_TAINTED), len);
3437
  store_pool = POOL_PERM;
4168
  store_pool = POOL_PERM;
3438
    tlsp->channelbinding = b64encode_taint(CUS s, (int)len, TRUE);
4169
    tlsp->channelbinding = b64encode_taint(CUS s, (int)len, GET_TAINTED);
3439
  store_pool = old_pool;
4170
  store_pool = old_pool;
3440
  DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage %p %p\n", tlsp->channelbinding, tlsp);
4171
  DEBUG(D_tls) debug_printf("Have channel bindings cached for possible auth usage %p %p\n", tlsp->channelbinding, tlsp);
3441
  }
4172
  }
Lines 3453-3469 Link Here
3453
static BOOL
4184
static BOOL
3454
tls_refill(unsigned lim)
4185
tls_refill(unsigned lim)
3455
{
4186
{
4187
SSL * ssl = state_server.lib_state.lib_ssl;
3456
int error;
4188
int error;
3457
int inbytes;
4189
int inbytes;
3458
4190
3459
DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", server_ssl,
4191
DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", ssl,
3460
  ssl_xfer_buffer, ssl_xfer_buffer_size);
4192
  ssl_xfer_buffer, ssl_xfer_buffer_size);
3461
4193
3462
ERR_clear_error();
4194
ERR_clear_error();
3463
if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout);
4195
if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout);
3464
inbytes = SSL_read(server_ssl, CS ssl_xfer_buffer,
4196
inbytes = SSL_read(ssl, CS ssl_xfer_buffer,
3465
		  MIN(ssl_xfer_buffer_size, lim));
4197
		  MIN(ssl_xfer_buffer_size, lim));
3466
error = SSL_get_error(server_ssl, inbytes);
4198
error = SSL_get_error(ssl, inbytes);
3467
if (smtp_receive_timeout > 0) ALARM_CLR(0);
4199
if (smtp_receive_timeout > 0) ALARM_CLR(0);
3468
4200
3469
if (had_command_timeout)		/* set by signal handler */
4201
if (had_command_timeout)		/* set by signal handler */
Lines 3487-3494 Link Here
3487
  case SSL_ERROR_ZERO_RETURN:
4219
  case SSL_ERROR_ZERO_RETURN:
3488
    DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n");
4220
    DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n");
3489
4221
3490
    if (SSL_get_shutdown(server_ssl) == SSL_RECEIVED_SHUTDOWN)
4222
    if (SSL_get_shutdown(ssl) == SSL_RECEIVED_SHUTDOWN)
3491
	  SSL_shutdown(server_ssl);
4223
	  SSL_shutdown(ssl);
3492
4224
3493
    tls_close(NULL, TLS_NO_SHUTDOWN);
4225
    tls_close(NULL, TLS_NO_SHUTDOWN);
3494
    return FALSE;
4226
    return FALSE;
Lines 3542-3547 Link Here
3542
return ssl_xfer_buffer[ssl_xfer_buffer_lwm++];
4274
return ssl_xfer_buffer[ssl_xfer_buffer_lwm++];
3543
}
4275
}
3544
4276
4277
BOOL
4278
tls_hasc(void)
4279
{
4280
return ssl_xfer_buffer_lwm < ssl_xfer_buffer_hwm;
4281
}
4282
3545
uschar *
4283
uschar *
3546
tls_getbuf(unsigned * len)
4284
tls_getbuf(unsigned * len)
3547
{
4285
{
Lines 3566-3575 Link Here
3566
4304
3567
4305
3568
void
4306
void
3569
tls_get_cache()
4307
tls_get_cache(unsigned lim)
3570
{
4308
{
3571
#ifndef DISABLE_DKIM
4309
#ifndef DISABLE_DKIM
3572
int n = ssl_xfer_buffer_hwm - ssl_xfer_buffer_lwm;
4310
int n = ssl_xfer_buffer_hwm - ssl_xfer_buffer_lwm;
4311
debug_printf("tls_get_cache\n");
4312
if (n > lim)
4313
  n = lim;
3573
if (n > 0)
4314
if (n > 0)
3574
  dkim_exim_verify_feed(ssl_xfer_buffer+ssl_xfer_buffer_lwm, n);
4315
  dkim_exim_verify_feed(ssl_xfer_buffer+ssl_xfer_buffer_lwm, n);
3575
#endif
4316
#endif
Lines 3577-3585 Link Here
3577
4318
3578
4319
3579
BOOL
4320
BOOL
3580
tls_could_read(void)
4321
tls_could_getc(void)
3581
{
4322
{
3582
return ssl_xfer_buffer_lwm < ssl_xfer_buffer_hwm || SSL_pending(server_ssl) > 0;
4323
return ssl_xfer_buffer_lwm < ssl_xfer_buffer_hwm
4324
    || SSL_pending(state_server.lib_state.lib_ssl) > 0;
3583
}
4325
}
3584
4326
3585
4327
Lines 3602-3608 Link Here
3602
int
4344
int
3603
tls_read(void * ct_ctx, uschar *buff, size_t len)
4345
tls_read(void * ct_ctx, uschar *buff, size_t len)
3604
{
4346
{
3605
SSL * ssl = ct_ctx ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl : server_ssl;
4347
SSL * ssl = ct_ctx ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl
4348
		  : state_server.lib_state.lib_ssl;
3606
int inbytes;
4349
int inbytes;
3607
int error;
4350
int error;
3608
4351
Lines 3652-3658 Link Here
3652
size_t olen = len;
4395
size_t olen = len;
3653
int outbytes, error;
4396
int outbytes, error;
3654
SSL * ssl = ct_ctx
4397
SSL * ssl = ct_ctx
3655
  ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl : server_ssl;
4398
  ? ((exim_openssl_client_tls_ctx *)ct_ctx)->ssl
4399
  : state_server.lib_state.lib_ssl;
3656
static gstring * server_corked = NULL;
4400
static gstring * server_corked = NULL;
3657
gstring ** corkedp = ct_ctx
4401
gstring ** corkedp = ct_ctx
3658
  ? &((exim_openssl_client_tls_ctx *)ct_ctx)->corked : &server_corked;
4402
  ? &((exim_openssl_client_tls_ctx *)ct_ctx)->corked : &server_corked;
Lines 3671-3677 Link Here
3671
a store reset there, so use POOL_PERM. */
4415
a store reset there, so use POOL_PERM. */
3672
/* + if CHUNKING, cmds EHLO,MAIL,RCPT(s),BDAT */
4416
/* + if CHUNKING, cmds EHLO,MAIL,RCPT(s),BDAT */
3673
4417
3674
if ((more || corked))
4418
if (more || corked)
3675
  {
4419
  {
3676
  if (!len) buff = US &error;	/* dummy just so that string_catn is ok */
4420
  if (!len) buff = US &error;	/* dummy just so that string_catn is ok */
3677
4421
Lines 3716-3724 Link Here
3716
      return -1;
4460
      return -1;
3717
4461
3718
    case SSL_ERROR_SYSCALL:
4462
    case SSL_ERROR_SYSCALL:
3719
      log_write(0, LOG_MAIN, "SSL_write: (from %s) syscall: %s",
4463
      if (ct_ctx || errno != ECONNRESET || !f.smtp_in_quit)
3720
	sender_fullhost ? sender_fullhost : US"<unknown>",
4464
	log_write(0, LOG_MAIN, "SSL_write: (from %s) syscall: %s",
3721
	strerror(errno));
4465
	  sender_fullhost ? sender_fullhost : US"<unknown>",
4466
	  strerror(errno));
4467
      else if (LOGGING(protocol_detail))
4468
	log_write(0, LOG_MAIN, "[%s] after QUIT, client reset TCP before"
4469
	  " SMTP response and TLS close\n", sender_host_address);
4470
      else
4471
	DEBUG(D_tls) debug_printf("[%s] SSL_write: after QUIT,"
4472
	  " client reset TCP before TLS close\n", sender_host_address);
3722
      return -1;
4473
      return -1;
3723
4474
3724
    default:
4475
    default:
Lines 3731-3736 Link Here
3731
4482
3732
4483
3733
4484
4485
/*
4486
Arguments:
4487
  ct_ctx	client TLS context pointer, or NULL for the one global server context
4488
*/
4489
4490
void
4491
tls_shutdown_wr(void * ct_ctx)
4492
{
4493
exim_openssl_client_tls_ctx * o_ctx = ct_ctx;
4494
SSL ** sslp = o_ctx ? &o_ctx->ssl : (SSL **) &state_server.lib_state.lib_ssl;
4495
int * fdp = o_ctx ? &tls_out.active.sock : &tls_in.active.sock;
4496
int rc;
4497
4498
if (*fdp < 0) return;  /* TLS was not active */
4499
4500
tls_write(ct_ctx, NULL, 0, FALSE);	/* flush write buffer */
4501
4502
HDEBUG(D_transport|D_tls|D_acl|D_v) debug_printf_indent("  SMTP(TLS shutdown)>>\n");
4503
rc = SSL_shutdown(*sslp);
4504
if (rc < 0) DEBUG(D_tls)
4505
  {
4506
  ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
4507
  debug_printf("SSL_shutdown: %s\n", ssl_errstring);
4508
  }
4509
}
4510
3734
/*************************************************
4511
/*************************************************
3735
*         Close down a TLS session               *
4512
*         Close down a TLS session               *
3736
*************************************************/
4513
*************************************************/
Lines 3741-3747 Link Here
3741
4518
3742
Arguments:
4519
Arguments:
3743
  ct_ctx	client TLS context pointer, or NULL for the one global server context
4520
  ct_ctx	client TLS context pointer, or NULL for the one global server context
3744
  shutdown	1 if TLS close-alert is to be sent,
4521
  do_shutdown	0 no data-flush or TLS close-alert
4522
		1 if TLS close-alert is to be sent,
3745
 		2 if also response to be waited for
4523
 		2 if also response to be waited for
3746
4524
3747
Returns:     nothing
4525
Returns:     nothing
Lines 3750-3775 Link Here
3750
*/
4528
*/
3751
4529
3752
void
4530
void
3753
tls_close(void * ct_ctx, int shutdown)
4531
tls_close(void * ct_ctx, int do_shutdown)
3754
{
4532
{
3755
exim_openssl_client_tls_ctx * o_ctx = ct_ctx;
4533
exim_openssl_client_tls_ctx * o_ctx = ct_ctx;
3756
SSL_CTX **ctxp = o_ctx ? &o_ctx->ctx : &server_ctx;
4534
SSL ** sslp = o_ctx ? &o_ctx->ssl : (SSL **) &state_server.lib_state.lib_ssl;
3757
SSL **sslp =     o_ctx ? &o_ctx->ssl : &server_ssl;
4535
int * fdp = o_ctx ? &tls_out.active.sock : &tls_in.active.sock;
3758
int *fdp = o_ctx ? &tls_out.active.sock : &tls_in.active.sock;
3759
4536
3760
if (*fdp < 0) return;  /* TLS was not active */
4537
if (*fdp < 0) return;  /* TLS was not active */
3761
4538
3762
if (shutdown)
4539
if (do_shutdown > TLS_NO_SHUTDOWN)
3763
  {
4540
  {
3764
  int rc;
4541
  int rc;
3765
  DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n",
4542
  DEBUG(D_tls) debug_printf("tls_close(): shutting down TLS%s\n",
3766
    shutdown > 1 ? " (with response-wait)" : "");
4543
    do_shutdown > TLS_SHUTDOWN_NOWAIT ? " (with response-wait)" : "");
4544
4545
  tls_write(ct_ctx, NULL, 0, FALSE);	/* flush write buffer */
3767
4546
3768
  if (  (rc = SSL_shutdown(*sslp)) == 0	/* send "close notify" alert */
4547
  if (  (  do_shutdown >= TLS_SHUTDOWN_WONLY
3769
     && shutdown > 1)
4548
	|| (rc = SSL_shutdown(*sslp)) == 0	/* send "close notify" alert */
4549
	)
4550
     && do_shutdown > TLS_SHUTDOWN_NOWAIT
4551
     )
3770
    {
4552
    {
4553
#ifdef EXIM_TCP_CORK
4554
    (void) setsockopt(*fdp, IPPROTO_TCP, EXIM_TCP_CORK, US &off, sizeof(off));
4555
#endif
3771
    ALARM(2);
4556
    ALARM(2);
3772
    rc = SSL_shutdown(*sslp);		/* wait for response */
4557
    rc = SSL_shutdown(*sslp);			/* wait for response */
3773
    ALARM_CLR(0);
4558
    ALARM_CLR(0);
3774
    }
4559
    }
3775
4560
Lines 3783-3807 Link Here
3783
if (!o_ctx)		/* server side */
4568
if (!o_ctx)		/* server side */
3784
  {
4569
  {
3785
#ifndef DISABLE_OCSP
4570
#ifndef DISABLE_OCSP
3786
  sk_X509_pop_free(server_static_cbinfo->verify_stack, X509_free);
4571
  sk_X509_pop_free(state_server.verify_stack, X509_free);
3787
  server_static_cbinfo->verify_stack = NULL;
4572
  state_server.verify_stack = NULL;
3788
#endif
4573
#endif
3789
4574
3790
  receive_getc =	smtp_getc;
4575
  receive_getc =	smtp_getc;
3791
  receive_getbuf =	smtp_getbuf;
4576
  receive_getbuf =	smtp_getbuf;
3792
  receive_get_cache =	smtp_get_cache;
4577
  receive_get_cache =	smtp_get_cache;
4578
  receive_hasc =	smtp_hasc;
3793
  receive_ungetc =	smtp_ungetc;
4579
  receive_ungetc =	smtp_ungetc;
3794
  receive_feof =	smtp_feof;
4580
  receive_feof =	smtp_feof;
3795
  receive_ferror =	smtp_ferror;
4581
  receive_ferror =	smtp_ferror;
3796
  receive_smtp_buffered = smtp_buffered;
3797
  tls_in.active.tls_ctx = NULL;
4582
  tls_in.active.tls_ctx = NULL;
3798
  tls_in.sni = NULL;
4583
  tls_in.sni = NULL;
3799
  /* Leave bits, peercert, cipher, peerdn, certificate_verified set, for logging */
4584
  /* Leave bits, peercert, cipher, peerdn, certificate_verified set, for logging */
3800
  }
4585
  }
3801
4586
3802
SSL_CTX_free(*ctxp);
3803
SSL_free(*sslp);
4587
SSL_free(*sslp);
3804
*ctxp = NULL;
3805
*sslp = NULL;
4588
*sslp = NULL;
3806
*fdp = -1;
4589
*fdp = -1;
3807
}
4590
}
Lines 3822-3829 Link Here
3822
uschar *
4605
uschar *
3823
tls_validate_require_cipher(void)
4606
tls_validate_require_cipher(void)
3824
{
4607
{
3825
SSL_CTX *ctx;
4608
SSL_CTX * ctx;
3826
uschar *s, *expciphers, *err;
4609
uschar * expciphers, * err;
3827
4610
3828
tls_openssl_init();
4611
tls_openssl_init();
3829
4612
Lines 3837-3870 Link Here
3837
if (!(expciphers && *expciphers))
4620
if (!(expciphers && *expciphers))
3838
  return NULL;
4621
  return NULL;
3839
4622
3840
/* normalisation ripped from above */
4623
normalise_ciphers(&expciphers, tls_require_ciphers);
3841
s = expciphers;
3842
while (*s != 0) { if (*s == '_') *s = '-'; s++; }
3843
4624
3844
err = NULL;
4625
err = NULL;
3845
4626
if (lib_ctx_new(&ctx, NULL, &err) == OK)
3846
#ifdef EXIM_HAVE_OPENSSL_TLS_METHOD
3847
if (!(ctx = SSL_CTX_new(TLS_server_method())))
3848
#else
3849
if (!(ctx = SSL_CTX_new(SSLv23_server_method())))
3850
#endif
3851
  {
4627
  {
3852
  ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
4628
  DEBUG(D_tls)
3853
  return string_sprintf("SSL_CTX_new() failed: %s", ssl_errstring);
4629
    debug_printf("tls_require_ciphers expands to \"%s\"\n", expciphers);
3854
  }
3855
4630
3856
DEBUG(D_tls)
4631
  if (!SSL_CTX_set_cipher_list(ctx, CS expciphers))
3857
  debug_printf("tls_require_ciphers expands to \"%s\"\n", expciphers);
4632
    {
4633
    ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
4634
    err = string_sprintf("SSL_CTX_set_cipher_list(%s) failed: %s",
4635
			expciphers, ssl_errstring);
4636
    }
3858
4637
3859
if (!SSL_CTX_set_cipher_list(ctx, CS expciphers))
4638
  SSL_CTX_free(ctx);
3860
  {
3861
  ERR_error_string_n(ERR_get_error(), ssl_errstring, sizeof(ssl_errstring));
3862
  err = string_sprintf("SSL_CTX_set_cipher_list(%s) failed: %s",
3863
		      expciphers, ssl_errstring);
3864
  }
4639
  }
3865
3866
SSL_CTX_free(ctx);
3867
3868
return err;
4640
return err;
3869
}
4641
}
3870
4642
Lines 3886-3906 Link Here
3886
will change, so we can more usefully assist with version diagnosis by also
4658
will change, so we can more usefully assist with version diagnosis by also
3887
reporting the build date.
4659
reporting the build date.
3888
4660
3889
Arguments:   a FILE* to print the results to
4661
Arguments:   string to append to
3890
Returns:     nothing
4662
Returns:     string
3891
*/
4663
*/
3892
4664
3893
void
4665
gstring *
3894
tls_version_report(FILE *f)
4666
tls_version_report(gstring * g)
3895
{
4667
{
3896
fprintf(f, "Library version: OpenSSL: Compile: %s\n"
4668
return string_fmt_append(g,
3897
           "                          Runtime: %s\n"
4669
    "Library version: OpenSSL: Compile: %s\n"
3898
           "                                 : %s\n",
4670
    "                          Runtime: %s\n"
3899
           OPENSSL_VERSION_TEXT,
4671
    "                                 : %s\n",
3900
           SSLeay_version(SSLEAY_VERSION),
4672
	     OPENSSL_VERSION_TEXT,
3901
           SSLeay_version(SSLEAY_BUILT_ON));
4673
	     SSLeay_version(SSLEAY_VERSION),
3902
/* third line is 38 characters for the %s and the line is 73 chars long;
4674
	     SSLeay_version(SSLEAY_BUILT_ON));
3903
the OpenSSL output includes a "built on: " prefix already. */
4675
  /* third line is 38 characters for the %s and the line is 73 chars long;
4676
  the OpenSSL output includes a "built on: " prefix already. */
3904
}
4677
}
3905
4678
3906
4679
Lines 4054-4060 Link Here
4054
{
4827
{
4055
long result, item;
4828
long result, item;
4056
uschar * exp, * end;
4829
uschar * exp, * end;
4057
uschar keep_c;
4058
BOOL adding, item_parsed;
4830
BOOL adding, item_parsed;
4059
4831
4060
/* Server: send no (<= TLS1.2) session tickets */
4832
/* Server: send no (<= TLS1.2) session tickets */
Lines 4096-4106 Link Here
4096
    return FALSE;
4868
    return FALSE;
4097
    }
4869
    }
4098
  adding = *s++ == '+';
4870
  adding = *s++ == '+';
4099
  for (end = s; (*end != '\0') && !isspace(*end); ++end) /**/ ;
4871
  for (end = s; *end && !isspace(*end); ) end++;
4100
  keep_c = *end;
4872
  item_parsed = tls_openssl_one_option_parse(string_copyn(s, end-s), &item);
4101
  *end = '\0';
4102
  item_parsed = tls_openssl_one_option_parse(s, &item);
4103
  *end = keep_c;
4104
  if (!item_parsed)
4873
  if (!item_parsed)
4105
    {
4874
    {
4106
    DEBUG(D_tls) debug_printf("openssl option setting unrecognised: \"%s\"\n", s);
4875
    DEBUG(D_tls) debug_printf("openssl option setting unrecognised: \"%s\"\n", s);
(-)exim.orig/src/transport.c (-99 / +194 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* General functions concerned with transportation, and generic options for all
9
/* General functions concerned with transportation, and generic options for all
Lines 253-259 Link Here
253
253
254
  for(;;)
254
  for(;;)
255
    {
255
    {
256
    fd_set fds;
257
    /* This code makes use of alarm() in order to implement the timeout. This
256
    /* This code makes use of alarm() in order to implement the timeout. This
258
    isn't a very tidy way of doing things. Using non-blocking I/O with select()
257
    isn't a very tidy way of doing things. Using non-blocking I/O with select()
259
    provides a neater approach. However, I don't know how to do this when TLS is
258
    provides a neater approach. However, I don't know how to do this when TLS is
Lines 281-288 Link Here
281
    if (rc >= 0 || errno != ENOTCONN || connretry <= 0)
280
    if (rc >= 0 || errno != ENOTCONN || connretry <= 0)
282
      break;
281
      break;
283
282
284
    FD_ZERO(&fds); FD_SET(fd, &fds);
283
    poll_one_fd(fd, POLLOUT, -1);		/* could set timeout? retval check? */
285
    select(fd+1, NULL, &fds, NULL, NULL);	/* could set timout? */
286
    connretry--;
284
    connretry--;
287
    }
285
    }
288
286
Lines 653-659 Link Here
653
651
654
for (ppp = *pdlist; ppp; ppp = ppp->next) if (p == ppp->ptr) return TRUE;
652
for (ppp = *pdlist; ppp; ppp = ppp->next) if (p == ppp->ptr) return TRUE;
655
653
656
ppp = store_get(sizeof(struct aci), FALSE);
654
ppp = store_get(sizeof(struct aci), GET_UNTAINTED);
657
ppp->next = *pdlist;
655
ppp->next = *pdlist;
658
*pdlist = ppp;
656
*pdlist = ppp;
659
ppp->ptr = p;
657
ppp->ptr = p;
Lines 677-683 Link Here
677
675
678
/* Remember what we have output, and output it. */
676
/* Remember what we have output, and output it. */
679
677
680
ppp = store_get(sizeof(struct aci), FALSE);
678
ppp = store_get(sizeof(struct aci), GET_UNTAINTED);
681
ppp->next = *pplist;
679
ppp->next = *pplist;
682
*pplist = ppp;
680
*pplist = ppp;
683
ppp->ptr = pp;
681
ppp->ptr = pp;
Lines 784-790 Link Here
784
  /* Header removed */
782
  /* Header removed */
785
783
786
  else
784
  else
787
    DEBUG(D_transport) debug_printf("removed header line:\n%s---\n", h->text);
785
    DEBUG(D_transport) debug_printf("removed header line:\n %s---\n", h->text);
788
  }
786
  }
789
787
790
/* Add on any address-specific headers. If there are multiple addresses,
788
/* Add on any address-specific headers. If there are multiple addresses,
Lines 800-807 Link Here
800
798
801
if (addr)
799
if (addr)
802
  {
800
  {
803
  header_line *hprev = addr->prop.extra_headers;
801
  header_line * hprev = addr->prop.extra_headers, * hnext, * h;
804
  header_line *hnext, * h;
802
805
  for (int i = 0; i < 2; i++)
803
  for (int i = 0; i < 2; i++)
806
    for (h = hprev, hprev = NULL; h; h = hnext)
804
    for (h = hprev, hprev = NULL; h; h = hnext)
807
      {
805
      {
Lines 812-818 Link Here
812
	{
810
	{
813
	if (!sendfn(tctx, h->text, h->slen)) return FALSE;
811
	if (!sendfn(tctx, h->text, h->slen)) return FALSE;
814
	DEBUG(D_transport)
812
	DEBUG(D_transport)
815
	  debug_printf("added header line(s):\n%s---\n", h->text);
813
	  debug_printf("added header line(s):\n %s---\n", h->text);
816
	}
814
	}
817
      }
815
      }
818
  }
816
  }
Lines 840-846 Link Here
840
	  return FALSE;
838
	  return FALSE;
841
	DEBUG(D_transport)
839
	DEBUG(D_transport)
842
	  {
840
	  {
843
	  debug_printf("added header line:\n%s", s);
841
	  debug_printf("added header line:\n %s", s);
844
	  if (s[len-1] != '\n') debug_printf("\n");
842
	  if (s[len-1] != '\n') debug_printf("\n");
845
	  debug_printf("---\n");
843
	  debug_printf("---\n");
846
	  }
844
	  }
Lines 886-892 Link Here
886
884
887
Arguments:
885
Arguments:
888
  tctx
886
  tctx
889
    (fd, msg)		Either and fd, to write the message to,
887
    (fd, msg)		Either an fd, to write the message to,
890
			or a string: if null write message to allocated space
888
			or a string: if null write message to allocated space
891
			otherwire take content as headers.
889
			otherwire take content as headers.
892
    addr                (chain of) addresses (for extra headers), or NULL;
890
    addr                (chain of) addresses (for extra headers), or NULL;
Lines 905-910 Link Here
905
      add_delivery_date     if TRUE, add a "delivery-date" header
903
      add_delivery_date     if TRUE, add a "delivery-date" header
906
      use_crlf              if TRUE, turn NL into CR LF
904
      use_crlf              if TRUE, turn NL into CR LF
907
      end_dot               if TRUE, send a terminating "." line at the end
905
      end_dot               if TRUE, send a terminating "." line at the end
906
      no_flush		    if TRUE, do not flush at end
908
      no_headers            if TRUE, omit the headers
907
      no_headers            if TRUE, omit the headers
909
      no_body               if TRUE, omit the body
908
      no_body               if TRUE, omit the body
910
    check_string          a string to check for at the start of lines, or NULL
909
    check_string          a string to check for at the start of lines, or NULL
Lines 1156-1168 Link Here
1156
1155
1157
/* If requested, add a terminating "." line (SMTP output). */
1156
/* If requested, add a terminating "." line (SMTP output). */
1158
1157
1159
if (tctx->options & topt_end_dot && !write_chunk(tctx, US".\n", 2))
1158
if (tctx->options & topt_end_dot)
1160
  return FALSE;
1159
  {
1160
  smtp_debug_cmd(US".", 0);
1161
  if (!write_chunk(tctx, US".\n", 2))
1162
    return FALSE;
1163
  }
1161
1164
1162
/* Write out any remaining data in the buffer before returning. */
1165
/* Write out any remaining data in the buffer before returning. */
1163
1166
1164
return (len = chunk_ptr - deliver_out_buffer) <= 0 ||
1167
return (len = chunk_ptr - deliver_out_buffer) <= 0
1165
  transport_write_block(tctx, deliver_out_buffer, len, FALSE);
1168
  || transport_write_block(tctx, deliver_out_buffer, len,
1169
			    !!(tctx->options & topt_no_flush));
1166
}
1170
}
1167
1171
1168
1172
Lines 1260-1266 Link Here
1260
1264
1261
  tctx->u.fd = fd_write;
1265
  tctx->u.fd = fd_write;
1262
  tctx->check_string = tctx->escape_string = NULL;
1266
  tctx->check_string = tctx->escape_string = NULL;
1263
  tctx->options &= ~(topt_use_crlf | topt_end_dot | topt_use_bdat);
1267
  tctx->options &= ~(topt_use_crlf | topt_end_dot | topt_use_bdat | topt_no_flush);
1264
1268
1265
  rc = internal_transport_write_message(tctx, size_limit);
1269
  rc = internal_transport_write_message(tctx, size_limit);
1266
1270
Lines 1396-1406 Link Here
1396
        yield = FALSE;
1400
        yield = FALSE;
1397
	}
1401
	}
1398
      else if (!ok)
1402
      else if (!ok)
1399
        {
1403
        {		/* Try to drain the pipe; read fails are don't care */
1400
	int dummy = read(pfd[pipe_read], (void *)&save_errno, sizeof(int));
1404
	int dummy = read(pfd[pipe_read], (void *)&save_errno, sizeof(int));
1401
        dummy = read(pfd[pipe_read], (void *)&tctx->addr->more_errno, sizeof(int));
1405
        dummy = read(pfd[pipe_read], (void *)&tctx->addr->more_errno, sizeof(int));
1402
        dummy = read(pfd[pipe_read], (void *)&tctx->addr->delivery_time, sizeof(struct timeval));
1406
        dummy = read(pfd[pipe_read], (void *)&tctx->addr->delivery_time, sizeof(struct timeval));
1403
	dummy = dummy;		/* compiler quietening */
1404
        yield = FALSE;
1407
        yield = FALSE;
1405
        }
1408
        }
1406
      }
1409
      }
Lines 1427-1433 Link Here
1427
        ? !write_chunk(tctx, US".\n", 2)
1430
        ? !write_chunk(tctx, US".\n", 2)
1428
	: !write_chunk(tctx, US"\n.\n", 3)
1431
	: !write_chunk(tctx, US"\n.\n", 3)
1429
     )  )
1432
     )  )
1430
    yield = FALSE;
1433
    { smtp_debug_cmd(US".", 0); yield = FALSE; }
1431
1434
1432
  /* Write out any remaining data in the buffer. */
1435
  /* Write out any remaining data in the buffer. */
1433
1436
Lines 1522-1528 Link Here
1522
1525
1523
  if (!(host_record = dbfn_read(dbm_file, host->name)))
1526
  if (!(host_record = dbfn_read(dbm_file, host->name)))
1524
    {
1527
    {
1525
    host_record = store_get(sizeof(dbdata_wait) + MESSAGE_ID_LENGTH, FALSE);
1528
    host_record = store_get(sizeof(dbdata_wait) + MESSAGE_ID_LENGTH, GET_UNTAINTED);
1526
    host_record->count = host_record->sequence = 0;
1529
    host_record->count = host_record->sequence = 0;
1527
    }
1530
    }
1528
1531
Lines 1571-1577 Link Here
1571
    {
1574
    {
1572
    sprintf(CS buffer, "%.200s:%d", host->name, host_record->sequence);
1575
    sprintf(CS buffer, "%.200s:%d", host->name, host_record->sequence);
1573
    dbfn_write(dbm_file, buffer, host_record, sizeof(dbdata_wait) + host_length);
1576
    dbfn_write(dbm_file, buffer, host_record, sizeof(dbdata_wait) + host_length);
1574
#ifdef EXPERIMENTAL_QUEUE_RAMP
1577
#ifndef DISABLE_QUEUE_RAMP
1575
    if (f.queue_2stage && queue_fast_ramp && !queue_run_in_order)
1578
    if (f.queue_2stage && queue_fast_ramp && !queue_run_in_order)
1576
      queue_notify_daemon(message_id);
1579
      queue_notify_daemon(message_id);
1577
#endif
1580
#endif
Lines 1586-1592 Link Here
1586
  else
1589
  else
1587
    {
1590
    {
1588
    dbdata_wait *newr =
1591
    dbdata_wait *newr =
1589
      store_get(sizeof(dbdata_wait) + host_length + MESSAGE_ID_LENGTH, FALSE);
1592
      store_get(sizeof(dbdata_wait) + host_length + MESSAGE_ID_LENGTH, GET_UNTAINTED);
1590
    memcpy(newr, host_record, sizeof(dbdata_wait) + host_length);
1593
    memcpy(newr, host_record, sizeof(dbdata_wait) + host_length);
1591
    host_record = newr;
1594
    host_record = newr;
1592
    }
1595
    }
Lines 1600-1606 Link Here
1600
  /* Update the database */
1603
  /* Update the database */
1601
1604
1602
  dbfn_write(dbm_file, host->name, host_record, sizeof(dbdata_wait) + host_length);
1605
  dbfn_write(dbm_file, host->name, host_record, sizeof(dbdata_wait) + host_length);
1603
  DEBUG(D_transport) debug_printf("added to list for %s\n", host->name);
1606
  DEBUG(D_transport) debug_printf("added %.*s to queue for %s\n",
1607
				  MESSAGE_ID_LENGTH, message_id, host->name);
1604
  }
1608
  }
1605
1609
1606
/* All now done */
1610
/* All now done */
Lines 1628-1634 Link Here
1628
  local_message_max  maximum number of messages down one connection
1632
  local_message_max  maximum number of messages down one connection
1629
                       as set by the caller transport
1633
                       as set by the caller transport
1630
  new_message_id     set to the message id of a waiting message
1634
  new_message_id     set to the message id of a waiting message
1631
  more               set TRUE if there are yet more messages waiting
1632
  oicf_func          function to call to validate if it is ok to send
1635
  oicf_func          function to call to validate if it is ok to send
1633
                     to this message_id from the current instance.
1636
                     to this message_id from the current instance.
1634
  oicf_data          opaque data for oicf_func
1637
  oicf_data          opaque data for oicf_func
Lines 1644-1650 Link Here
1644
1647
1645
BOOL
1648
BOOL
1646
transport_check_waiting(const uschar *transport_name, const uschar *hostname,
1649
transport_check_waiting(const uschar *transport_name, const uschar *hostname,
1647
  int local_message_max, uschar *new_message_id, BOOL *more, oicf oicf_func, void *oicf_data)
1650
  int local_message_max, uschar *new_message_id, oicf oicf_func, void *oicf_data)
1648
{
1651
{
1649
dbdata_wait *host_record;
1652
dbdata_wait *host_record;
1650
int host_length;
1653
int host_length;
Lines 1654-1661 Link Here
1654
int         i;
1657
int         i;
1655
struct stat statbuf;
1658
struct stat statbuf;
1656
1659
1657
*more = FALSE;
1658
1659
DEBUG(D_transport)
1660
DEBUG(D_transport)
1660
  {
1661
  {
1661
  debug_printf("transport_check_waiting entered\n");
1662
  debug_printf("transport_check_waiting entered\n");
Lines 1722-1728 Link Here
1722
1723
1723
  /* create an array to read entire message queue into memory for processing  */
1724
  /* create an array to read entire message queue into memory for processing  */
1724
1725
1725
  msgq = store_get(sizeof(msgq_t) * host_record->count, FALSE);
1726
  msgq = store_get(sizeof(msgq_t) * host_record->count, GET_UNTAINTED);
1726
  msgq_count = host_record->count;
1727
  msgq_count = host_record->count;
1727
  msgq_actual = msgq_count;
1728
  msgq_actual = msgq_count;
1728
1729
Lines 1860-1868 Link Here
1860
if (host_length > 0)
1861
if (host_length > 0)
1861
  {
1862
  {
1862
  host_record->count = host_length/MESSAGE_ID_LENGTH;
1863
  host_record->count = host_length/MESSAGE_ID_LENGTH;
1863
1864
  dbfn_write(dbm_file, hostname, host_record, (int)sizeof(dbdata_wait) + host_length);
1864
  dbfn_write(dbm_file, hostname, host_record, (int)sizeof(dbdata_wait) + host_length);
1865
  *more = TRUE;
1866
  }
1865
  }
1867
1866
1868
dbfn_close(dbm_file);
1867
dbfn_close(dbm_file);
Lines 1883-1891 Link Here
1883
transport_do_pass_socket(const uschar *transport_name, const uschar *hostname,
1882
transport_do_pass_socket(const uschar *transport_name, const uschar *hostname,
1884
  const uschar *hostaddress, uschar *id, int socket_fd)
1883
  const uschar *hostaddress, uschar *id, int socket_fd)
1885
{
1884
{
1886
int i = 22;
1885
int i = 13;
1887
const uschar **argv;
1886
const uschar **argv;
1888
1887
1888
#ifndef DISABLE_TLS
1889
if (smtp_peer_options & OPTION_TLS) i += 6;
1890
#endif
1891
#ifdef EXPERIMENTAL_ESMTP_LIMITS
1892
if (continue_limit_mail || continue_limit_rcpt || continue_limit_rcptdom)
1893
				    i += 4;
1894
#endif
1895
if (queue_run_pid != (pid_t)0)	    i += 3;
1896
#ifdef SUPPORT_SOCKS
1897
if (proxy_session)		    i += 5;
1898
#endif
1899
1889
/* Set up the calling arguments; use the standard function for the basics,
1900
/* Set up the calling arguments; use the standard function for the basics,
1890
but we have a number of extras that may be added. */
1901
but we have a number of extras that may be added. */
1891
1902
Lines 1919-1924 Link Here
1919
    argv[i++] = US"-MCT";
1930
    argv[i++] = US"-MCT";
1920
#endif
1931
#endif
1921
1932
1933
#ifdef EXPERIMENTAL_ESMTP_LIMITS
1934
if (continue_limit_rcpt || continue_limit_rcptdom)
1935
  {
1936
  argv[i++] = US"-MCL";
1937
  argv[i++] = string_sprintf("%u", continue_limit_mail);
1938
  argv[i++] = string_sprintf("%u", continue_limit_rcpt);
1939
  argv[i++] = string_sprintf("%u", continue_limit_rcptdom);
1940
  }
1941
#endif
1942
1922
if (queue_run_pid != (pid_t)0)
1943
if (queue_run_pid != (pid_t)0)
1923
  {
1944
  {
1924
  argv[i++] = US"-MCQ";
1945
  argv[i++] = US"-MCQ";
Lines 1926-1931 Link Here
1926
  argv[i++] = string_sprintf("%d", queue_run_pipe);
1947
  argv[i++] = string_sprintf("%d", queue_run_pipe);
1927
  }
1948
  }
1928
1949
1950
#ifdef SUPPORT_SOCKS
1951
if (proxy_session)
1952
  {
1953
  argv[i++] = US"-MCp";
1954
  argv[i++] = proxy_local_address;
1955
  argv[i++] = string_sprintf("%d", proxy_local_port);
1956
  argv[i++] = proxy_external_address;
1957
  argv[i++] = string_sprintf("%d", proxy_external_port);
1958
  }
1959
#endif
1960
1929
argv[i++] = US"-MC";
1961
argv[i++] = US"-MC";
1930
argv[i++] = US transport_name;
1962
argv[i++] = US transport_name;
1931
argv[i++] = US hostname;
1963
argv[i++] = US hostname;
Lines 1944-1949 Link Here
1944
1976
1945
DEBUG(D_exec) debug_print_argv(argv);
1977
DEBUG(D_exec) debug_print_argv(argv);
1946
exim_nullstd();                          /* Ensure std{out,err} exist */
1978
exim_nullstd();                          /* Ensure std{out,err} exist */
1979
/* argv[0] should be untainted, from child_exec_exim() */
1947
execv(CS argv[0], (char *const *)argv);
1980
execv(CS argv[0], (char *const *)argv);
1948
1981
1949
DEBUG(D_any) debug_printf("execv failed: %s\n", strerror(errno));
1982
DEBUG(D_any) debug_printf("execv failed: %s\n", strerror(errno));
Lines 1968-1980 Link Here
1968
2001
1969
BOOL
2002
BOOL
1970
transport_pass_socket(const uschar *transport_name, const uschar *hostname,
2003
transport_pass_socket(const uschar *transport_name, const uschar *hostname,
1971
  const uschar *hostaddress, uschar *id, int socket_fd)
2004
  const uschar *hostaddress, uschar *id, int socket_fd
2005
#ifdef EXPERIMENTAL_ESMTP_LIMITS
2006
  , unsigned peer_limit_mail, unsigned peer_limit_rcpt, unsigned peer_limit_rcptdom
2007
#endif
2008
  )
1972
{
2009
{
1973
pid_t pid;
2010
pid_t pid;
1974
int status;
2011
int status;
1975
2012
1976
DEBUG(D_transport) debug_printf("transport_pass_socket entered\n");
2013
DEBUG(D_transport) debug_printf("transport_pass_socket entered\n");
1977
2014
2015
#ifdef EXPERIMENTAL_ESMTP_LIMITS
2016
continue_limit_mail = peer_limit_mail;
2017
continue_limit_rcpt = peer_limit_rcpt;
2018
continue_limit_rcptdom = peer_limit_rcptdom;
2019
#endif
2020
1978
if ((pid = exim_fork(US"continued-transport-interproc")) == 0)
2021
if ((pid = exim_fork(US"continued-transport-interproc")) == 0)
1979
  {
2022
  {
1980
  /* Disconnect entirely from the parent process. If we are running in the
2023
  /* Disconnect entirely from the parent process. If we are running in the
Lines 2010-2015 Link Here
2010
2053
2011
2054
2012
2055
2056
/* Enforce all args untainted, for consistency with a router-sourced pipe
2057
command, where (because the whole line is passed as one to the tpt) a
2058
tainted arg taints the executable name.  It's unclear also that letting an
2059
attacker supply command arguments is wise. */
2060
2061
static BOOL
2062
arg_is_tainted(const uschar * s, int argn, address_item * addr,
2063
  const uschar * etext, uschar ** errptr)
2064
{
2065
if (is_tainted(s))
2066
  {
2067
  uschar * msg = string_sprintf("Tainted arg %d for %s command: '%s'",
2068
				argn, etext, s);
2069
  if (addr)
2070
    {
2071
    addr->transport_return = FAIL;
2072
    addr->message = msg;
2073
    }
2074
  else *errptr = msg;
2075
  return TRUE;
2076
  }
2077
return FALSE;
2078
}
2079
2080
2013
/*************************************************
2081
/*************************************************
2014
*          Set up direct (non-shell) command     *
2082
*          Set up direct (non-shell) command     *
2015
*************************************************/
2083
*************************************************/
Lines 2027-2032 Link Here
2027
  expand_failed      error value to set if expansion fails; not relevant if
2095
  expand_failed      error value to set if expansion fails; not relevant if
2028
                     addr == NULL
2096
                     addr == NULL
2029
  addr               chain of addresses, or NULL
2097
  addr               chain of addresses, or NULL
2098
  allow_tainted_args as it says; used for ${run}
2030
  etext              text for use in error messages
2099
  etext              text for use in error messages
2031
  errptr             where to put error message if addr is NULL;
2100
  errptr             where to put error message if addr is NULL;
2032
                     otherwise it is put in the first address
2101
                     otherwise it is put in the first address
Lines 2036-2050 Link Here
2036
*/
2105
*/
2037
2106
2038
BOOL
2107
BOOL
2039
transport_set_up_command(const uschar ***argvptr, uschar *cmd,
2108
transport_set_up_command(const uschar *** argvptr, const uschar * cmd,
2040
  BOOL expand_arguments, int expand_failed, address_item *addr,
2109
  BOOL expand_arguments, int expand_failed, address_item * addr,
2041
  uschar *etext, uschar **errptr)
2110
  BOOL allow_tainted_args, const uschar * etext, uschar ** errptr)
2042
{
2111
{
2043
const uschar **argv;
2112
const uschar ** argv, * s;
2044
uschar *s, *ss;
2113
int address_count = 0, argcount = 0, max_args;
2045
int address_count = 0;
2046
int argcount = 0;
2047
int max_args;
2048
2114
2049
/* Get store in which to build an argument list. Count the number of addresses
2115
/* Get store in which to build an argument list. Count the number of addresses
2050
supplied, and allow for that many arguments, plus an additional 60, which
2116
supplied, and allow for that many arguments, plus an additional 60, which
Lines 2053-2059 Link Here
2053
2119
2054
for (address_item * ad = addr; ad; ad = ad->next) address_count++;
2120
for (address_item * ad = addr; ad; ad = ad->next) address_count++;
2055
max_args = address_count + 60;
2121
max_args = address_count + 60;
2056
*argvptr = argv = store_get((max_args+1)*sizeof(uschar *), FALSE);
2122
*argvptr = argv = store_get((max_args+1)*sizeof(uschar *), GET_UNTAINTED);
2057
2123
2058
/* Split the command up into arguments terminated by white space. Lose
2124
/* Split the command up into arguments terminated by white space. Lose
2059
trailing space at the start and end. Double-quoted arguments can contain \\ and
2125
trailing space at the start and end. Double-quoted arguments can contain \\ and
Lines 2061-2093 Link Here
2061
arguments are verbatim. Copy each argument into a new string. */
2127
arguments are verbatim. Copy each argument into a new string. */
2062
2128
2063
s = cmd;
2129
s = cmd;
2064
while (isspace(*s)) s++;
2130
Uskip_whitespace(&s);
2065
2131
2066
for (; *s != 0 && argcount < max_args; argcount++)
2132
for (; *s && argcount < max_args; argcount++)
2067
  {
2133
  {
2068
  if (*s == '\'')
2134
  if (*s == '\'')
2069
    {
2135
    {
2070
    ss = s + 1;
2136
    int n = Ustrcspn(++s, "'");
2071
    while (*ss != 0 && *ss != '\'') ss++;
2137
    argv[argcount] = string_copyn(s, n);
2072
    argv[argcount] = ss = store_get(ss - s++, is_tainted(cmd));
2138
    if (*(s += n) == '\'') s++;
2073
    while (*s != 0 && *s != '\'') *ss++ = *s++;
2074
    if (*s != 0) s++;
2075
    *ss++ = 0;
2076
    }
2139
    }
2077
  else
2140
  else
2078
    argv[argcount] = string_dequote(CUSS &s);
2141
    argv[argcount] = string_dequote(CUSS &s);
2079
  while (isspace(*s)) s++;
2142
  Uskip_whitespace(&s);
2080
  }
2143
  }
2081
2144
2082
argv[argcount] = US 0;
2145
argv[argcount] = NULL;
2083
2146
2084
/* If *s != 0 we have run out of argument slots. */
2147
/* If *s != 0 we have run out of argument slots. */
2085
2148
2086
if (*s != 0)
2149
if (*s)
2087
  {
2150
  {
2088
  uschar *msg = string_sprintf("Too many arguments in command \"%s\" in "
2151
  uschar *msg = string_sprintf("Too many arguments in command \"%s\" in "
2089
    "%s", cmd, etext);
2152
    "%s", cmd, etext);
2090
  if (addr != NULL)
2153
  if (addr)
2091
    {
2154
    {
2092
    addr->transport_return = FAIL;
2155
    addr->transport_return = FAIL;
2093
    addr->message = msg;
2156
    addr->message = msg;
Lines 2121-2136 Link Here
2121
2184
2122
if (expand_arguments)
2185
if (expand_arguments)
2123
  {
2186
  {
2124
  BOOL allow_dollar_recipients = addr != NULL &&
2187
  BOOL allow_dollar_recipients = addr && addr->parent
2125
    addr->parent != NULL &&
2188
    && Ustrcmp(addr->parent->address, "system-filter") == 0;
2126
    Ustrcmp(addr->parent->address, "system-filter") == 0;
2127
2189
2128
  for (int i = 0; argv[i] != US 0; i++)
2190
  for (int i = 0; argv[i]; i++)
2129
    {
2191
    {
2130
2131
    /* Handle special fudge for passing an address list */
2192
    /* Handle special fudge for passing an address list */
2132
2193
2133
    if (addr != NULL &&
2194
    if (addr &&
2134
        (Ustrcmp(argv[i], "$pipe_addresses") == 0 ||
2195
        (Ustrcmp(argv[i], "$pipe_addresses") == 0 ||
2135
         Ustrcmp(argv[i], "${pipe_addresses}") == 0))
2196
         Ustrcmp(argv[i], "${pipe_addresses}") == 0))
2136
      {
2197
      {
Lines 2151-2156 Link Here
2151
2212
2152
      for (address_item * ad = addr; ad; ad = ad->next)
2213
      for (address_item * ad = addr; ad; ad = ad->next)
2153
        {
2214
        {
2215
	/* $pipe_addresses is spefically not checked for taint, because there is
2216
	a testcase (321) depending on it.  It's unclear if the exact thing being
2217
	done really needs to be legitimate, though I suspect it reflects an
2218
	actual use-case that showed up a bug.
2219
	This is a hole in the taint-pretection, mitigated only in that
2220
	shell-syntax metachars cannot be injected via this route. */
2221
2222
	DEBUG(D_transport) if (is_tainted(ad->address))
2223
	  debug_printf("tainted element '%s' from $pipe_addresses\n", ad->address);
2224
2154
	argv[i++] = ad->address;
2225
	argv[i++] = ad->address;
2155
	argcount++;
2226
	argcount++;
2156
	}
2227
	}
Lines 2162-2175 Link Here
2162
2233
2163
      /* Handle special case of $address_pipe when af_force_command is set */
2234
      /* Handle special case of $address_pipe when af_force_command is set */
2164
2235
2165
    else if (addr != NULL && testflag(addr,af_force_command) &&
2236
    else if (addr && testflag(addr,af_force_command) &&
2166
        (Ustrcmp(argv[i], "$address_pipe") == 0 ||
2237
        (Ustrcmp(argv[i], "$address_pipe") == 0 ||
2167
         Ustrcmp(argv[i], "${address_pipe}") == 0))
2238
         Ustrcmp(argv[i], "${address_pipe}") == 0))
2168
      {
2239
      {
2169
      int address_pipe_argcount = 0;
2240
      int address_pipe_argcount = 0;
2170
      int address_pipe_max_args;
2241
      int address_pipe_max_args;
2171
      uschar **address_pipe_argv;
2242
      uschar **address_pipe_argv;
2172
      BOOL tainted;
2173
2243
2174
      /* We can never have more then the argv we will be loading into */
2244
      /* We can never have more then the argv we will be loading into */
2175
      address_pipe_max_args = max_args - argcount + 1;
2245
      address_pipe_max_args = max_args - argcount + 1;
Lines 2178-2190 Link Here
2178
        debug_printf("address_pipe_max_args=%d\n", address_pipe_max_args);
2248
        debug_printf("address_pipe_max_args=%d\n", address_pipe_max_args);
2179
2249
2180
      /* We allocate an additional for (uschar *)0 */
2250
      /* We allocate an additional for (uschar *)0 */
2181
      address_pipe_argv = store_get((address_pipe_max_args+1)*sizeof(uschar *), FALSE);
2251
      address_pipe_argv = store_get((address_pipe_max_args+1)*sizeof(uschar *), GET_UNTAINTED);
2182
2252
2183
      /* +1 because addr->local_part[0] == '|' since af_force_command is set */
2253
      /* +1 because addr->local_part[0] == '|' since af_force_command is set */
2184
      s = expand_string(addr->local_part + 1);
2254
      s = expand_string(addr->local_part + 1);
2185
      tainted = is_tainted(s);
2186
2255
2187
      if (s == NULL || *s == '\0')
2256
      if (!s || !*s)
2188
        {
2257
        {
2189
        addr->transport_return = FAIL;
2258
        addr->transport_return = FAIL;
2190
        addr->message = string_sprintf("Expansion of \"%s\" "
2259
        addr->message = string_sprintf("Expansion of \"%s\" "
Lines 2193-2224 Link Here
2193
        return FALSE;
2262
        return FALSE;
2194
        }
2263
        }
2195
2264
2196
      while (isspace(*s)) s++; /* strip leading space */
2265
      Uskip_whitespace(&s);			/* strip leading space */
2197
2266
2198
      while (*s != 0 && address_pipe_argcount < address_pipe_max_args)
2267
      while (*s && address_pipe_argcount < address_pipe_max_args)
2199
        {
2268
        {
2200
        if (*s == '\'')
2269
        if (*s == '\'')
2201
          {
2270
	  {
2202
          ss = s + 1;
2271
	  int n = Ustrcspn(++s, "'");
2203
          while (*ss != 0 && *ss != '\'') ss++;
2272
	  argv[argcount] = string_copyn(s, n);
2204
          address_pipe_argv[address_pipe_argcount++] = ss = store_get(ss - s++, tainted);
2273
	  if (*(s += n) == '\'') s++;
2205
          while (*s != 0 && *s != '\'') *ss++ = *s++;
2274
	  }
2206
          if (*s != 0) s++;
2275
        else
2207
          *ss++ = 0;
2276
	  address_pipe_argv[address_pipe_argcount++] = string_dequote(CUSS &s);
2208
          }
2277
	Uskip_whitespace(&s);			/* strip space after arg */
2209
        else address_pipe_argv[address_pipe_argcount++] =
2210
	      string_copy(string_dequote(CUSS &s));
2211
        while (isspace(*s)) s++; /* strip space after arg */
2212
        }
2278
        }
2213
2279
2214
      address_pipe_argv[address_pipe_argcount] = US 0;
2280
      address_pipe_argv[address_pipe_argcount] = NULL;
2215
2281
2216
      /* If *s != 0 we have run out of argument slots. */
2282
      /* If *s != 0 we have run out of argument slots. */
2217
      if (*s != 0)
2283
      if (*s)
2218
        {
2284
        {
2219
        uschar *msg = string_sprintf("Too many arguments in $address_pipe "
2285
        uschar *msg = string_sprintf("Too many arguments in $address_pipe "
2220
          "\"%s\" in %s", addr->local_part + 1, etext);
2286
          "\"%s\" in %s", addr->local_part + 1, etext);
2221
        if (addr != NULL)
2287
        if (addr)
2222
          {
2288
          {
2223
          addr->transport_return = FAIL;
2289
          addr->transport_return = FAIL;
2224
          addr->message = msg;
2290
          addr->message = msg;
Lines 2228-2235 Link Here
2228
        }
2294
        }
2229
2295
2230
      /* address_pipe_argcount - 1
2296
      /* address_pipe_argcount - 1
2231
       * because we are replacing $address_pipe in the argument list
2297
      because we are replacing $address_pipe in the argument list
2232
       * with the first thing it expands to */
2298
      with the first thing it expands to */
2299
2233
      if (argcount + address_pipe_argcount - 1 > max_args)
2300
      if (argcount + address_pipe_argcount - 1 > max_args)
2234
        {
2301
        {
2235
        addr->transport_return = FAIL;
2302
        addr->transport_return = FAIL;
Lines 2239-2250 Link Here
2239
        }
2306
        }
2240
2307
2241
      /* If we are not just able to replace the slot that contained
2308
      /* If we are not just able to replace the slot that contained
2242
       * $address_pipe (address_pipe_argcount == 1)
2309
      $address_pipe (address_pipe_argcount == 1)
2243
       * We have to move the existing argv by address_pipe_argcount - 1
2310
      We have to move the existing argv by address_pipe_argcount - 1
2244
       * Visually if address_pipe_argcount == 2:
2311
      Visually if address_pipe_argcount == 2:
2245
       * [argv 0][argv 1][argv 2($address_pipe)][argv 3][0]
2312
      [argv 0][argv 1][argv 2($address_pipe)][argv 3][0]
2246
       * [argv 0][argv 1][ap_arg0][ap_arg1][old argv 3][0]
2313
      [argv 0][argv 1][ap_arg0][ap_arg1][old argv 3][0] */
2247
       */
2314
2248
      if (address_pipe_argcount > 1)
2315
      if (address_pipe_argcount > 1)
2249
        memmove(
2316
        memmove(
2250
          /* current position + additional args */
2317
          /* current position + additional args */
Lines 2256-2270 Link Here
2256
        );
2323
        );
2257
2324
2258
      /* Now we fill in the slots we just moved argv out of
2325
      /* Now we fill in the slots we just moved argv out of
2259
       * [argv 0][argv 1][argv 2=pipeargv[0]][argv 3=pipeargv[1]][old argv 3][0]
2326
      [argv 0][argv 1][argv 2=pipeargv[0]][argv 3=pipeargv[1]][old argv 3][0] */
2260
       */
2327
2261
      for (int address_pipe_i = 0;
2328
      for (int address_pipe_i = 0;
2262
           address_pipe_argv[address_pipe_i] != US 0;
2329
           address_pipe_argv[address_pipe_i];
2263
           address_pipe_i++)
2330
           address_pipe_i++, argcount++)
2264
        {
2331
	{
2265
        argv[i++] = address_pipe_argv[address_pipe_i];
2332
        uschar * s = address_pipe_argv[address_pipe_i];
2266
        argcount++;
2333
	if (arg_is_tainted(s, i, addr, etext, errptr)) return FALSE;
2267
        }
2334
        argv[i++] = s;
2335
	}
2268
2336
2269
      /* Subtract one since we replace $address_pipe */
2337
      /* Subtract one since we replace $address_pipe */
2270
      argcount--;
2338
      argcount--;
Lines 2293-2298 Link Here
2293
        else *errptr = msg;
2361
        else *errptr = msg;
2294
        return FALSE;
2362
        return FALSE;
2295
        }
2363
        }
2364
2365
      if ( f.running_in_test_harness && is_tainted(expanded_arg)
2366
	 && Ustrcmp(etext, "queryprogram router") == 0)
2367
	{			/* hack, would be good to not need it */
2368
	DEBUG(D_transport)
2369
	  debug_printf("SPECIFIC TESTSUITE EXEMPTION: tainted arg '%s'\n",
2370
		      expanded_arg);
2371
	}
2372
      else if (  !allow_tainted_args
2373
	      && arg_is_tainted(expanded_arg, i, addr, etext, errptr))
2374
	return FALSE;
2296
      argv[i] = expanded_arg;
2375
      argv[i] = expanded_arg;
2297
      }
2376
      }
2298
    }
2377
    }
Lines 2300-2313 Link Here
2300
  DEBUG(D_transport)
2379
  DEBUG(D_transport)
2301
    {
2380
    {
2302
    debug_printf("direct command after expansion:\n");
2381
    debug_printf("direct command after expansion:\n");
2303
    for (int i = 0; argv[i] != US 0; i++)
2382
    for (int i = 0; argv[i]; i++)
2304
      debug_printf("  argv[%d] = %s\n", i, string_printing(argv[i]));
2383
      {
2384
      debug_printf("  argv[%d] = '%s'\n", i, string_printing(argv[i]));
2385
      debug_print_taint(argv[i]);
2386
      }
2305
    }
2387
    }
2306
  }
2388
  }
2307
2389
2308
return TRUE;
2390
return TRUE;
2309
}
2391
}
2310
2392
2393
2394
2395
/* For error messages, a string describing the config location associated
2396
with current processing.  NULL if we are not in a transport. */
2397
/* Name only, for now */
2398
2399
uschar *
2400
transport_current_name(void)
2401
{
2402
if (!transport_name) return NULL;
2403
return string_sprintf(" (transport %s, %s %d)", transport_name, driver_srcfile, driver_srcline);
2404
}
2405
2311
#endif	/*!MACRO_PREDEF*/
2406
#endif	/*!MACRO_PREDEF*/
2312
/* vi: aw ai sw=2
2407
/* vi: aw ai sw=2
2313
*/
2408
*/
(-)exim.orig/src/transports/appendfile.c (-157 / +156 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
5
/* Copyright (c) The Exim maintainers 2020 - 2022 */
6
/* Copyright (c) The Exim maintainers 2020 */
6
/* Copyright (c) University of Cambridge 1995 - 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 112-181 Link Here
112
/* Default private options block for the appendfile transport. */
112
/* Default private options block for the appendfile transport. */
113
113
114
appendfile_transport_options_block appendfile_transport_option_defaults = {
114
appendfile_transport_options_block appendfile_transport_option_defaults = {
115
  NULL,           /* filename */
115
  /* all non-mentioned members zero/null/false */
116
  NULL,           /* dirname */
116
  .dirfilename = US"q${base62:$tod_epoch}-$inode",
117
  US"q${base62:$tod_epoch}-$inode", /* dirfilename */
117
  .create_file_string = US"anywhere",
118
  NULL,           /* message_prefix (default reset in init if not bsmtp) */
118
  .maildir_dir_regex = US"^(?:cur|new|\\..*)$",
119
  NULL,           /* message_suffix (ditto) */
119
  .mailbox_size_value = -1,
120
  US"anywhere",   /* create_file_string (string value for create_file) */
120
  .mailbox_filecount_value = -1,
121
  NULL,           /* quota */
121
  .mode = APPENDFILE_MODE,
122
  NULL,           /* quota_directory */
122
  .dirmode = APPENDFILE_DIRECTORY_MODE,
123
  NULL,           /* quota_filecount */
123
  .lockfile_mode = APPENDFILE_LOCKFILE_MODE,
124
  NULL,           /* quota_size_regex */
124
  .lockfile_timeout = 30*60,
125
  NULL,           /* quota_warn_threshold */
125
  .lock_retries = 10,
126
  NULL,           /* mailbox_size_string */
126
   .lock_interval = 3,
127
  NULL,           /* mailbox_filecount_string */
127
  .maildir_retries = 10,
128
  NULL,           /* expand_maildir_use_size_file */
128
  .create_file = create_anywhere,
129
  US"^(?:cur|new|\\..*)$",  /* maildir_dir_regex */
129
  .check_owner = TRUE,
130
  NULL,           /* maildir_tag */
130
  .create_directory = TRUE,
131
  NULL,           /* maildirfolder_create_regex */
131
  .notify_comsat = FALSE,
132
  NULL,           /* mailstore_prefix */
132
  .use_lockfile = TRUE,
133
  NULL,           /* mailstore_suffix */
133
  .use_fcntl = TRUE,
134
  NULL,           /* check_string (default changed for non-bsmtp file)*/
134
  .mode_fail_narrower = TRUE,
135
  NULL,           /* escape_string (ditto) */
135
  .quota_is_inclusive = TRUE,
136
  NULL,           /* file_format */
137
  0,              /* quota_value */
138
  0,              /* quota_warn_threshold_value */
139
  -1,             /* mailbox_size_value */
140
  -1,             /* mailbox_filecount_value */
141
  0,              /* quota_filecount_value */
142
  APPENDFILE_MODE,           /* mode */
143
  APPENDFILE_DIRECTORY_MODE, /* dirmode */
144
  APPENDFILE_LOCKFILE_MODE,  /* lockfile_mode */
145
  30*60,          /* lockfile_timeout */
146
  0,              /* lock_fcntl_timeout */
147
  0,              /* lock_flock_timeout */
148
  10,             /* lock_retries */
149
   3,             /* lock_interval */
150
  10,             /* maildir_retries */
151
  create_anywhere,/* create_file */
152
  0,              /* options */
153
  FALSE,          /* allow_fifo */
154
  FALSE,          /* allow_symlink */
155
  FALSE,          /* check_group */
156
  TRUE,           /* check_owner */
157
  TRUE,           /* create_directory */
158
  FALSE,          /* notify_comsat */
159
  TRUE,           /* use_lockfile */
160
  FALSE,          /* set_use_lockfile */
161
  TRUE,           /* use_fcntl */
162
  FALSE,          /* set_use_fcntl */
163
  FALSE,          /* use_flock */
164
  FALSE,          /* set_use_flock */
165
  FALSE,          /* use_mbx_lock */
166
  FALSE,          /* set_use_mbx_lock */
167
  FALSE,          /* use_bsmtp */
168
  FALSE,          /* use_crlf */
169
  FALSE,          /* file_must_exist */
170
  TRUE,           /* mode_fail_narrower */
171
  FALSE,          /* maildir_format */
172
  FALSE,          /* maildir_use_size_file */
173
  FALSE,          /* mailstore_format */
174
  FALSE,          /* mbx_format */
175
  FALSE,          /* quota_warn_threshold_is_percent */
176
  TRUE,           /* quota_is_inclusive */
177
  FALSE,          /* quota_no_check */
178
  FALSE           /* quota_filecount_no_check */
179
};
136
};
180
137
181
138
Lines 226-236 Link Here
226
uschar *q = ob->quota;
183
uschar *q = ob->quota;
227
double default_value = 0.0;
184
double default_value = 0.0;
228
185
229
addrlist = addrlist;    /* Keep picky compilers happy */
230
dummy = dummy;
231
uid = uid;
232
gid = gid;
233
234
if (ob->expand_maildir_use_size_file)
186
if (ob->expand_maildir_use_size_file)
235
	ob->maildir_use_size_file = expand_check_condition(ob->expand_maildir_use_size_file,
187
	ob->maildir_use_size_file = expand_check_condition(ob->expand_maildir_use_size_file,
236
		US"`maildir_use_size_file` in transport", tblock->name);
188
		US"`maildir_use_size_file` in transport", tblock->name);
Lines 240-256 Link Here
240
192
241
for (int i = 0; i < 5; i++)
193
for (int i = 0; i < 5; i++)
242
  {
194
  {
243
  double d;
195
  double d = default_value;
244
  int no_check = 0;
196
  int no_check = 0;
245
  uschar *which = NULL;
197
  uschar *which = NULL;
246
198
247
  if (q == NULL) d = default_value;
199
  if (q)
248
  else
249
    {
200
    {
250
    uschar *rest;
201
    uschar * rest, * s;
251
    uschar *s = expand_string(q);
252
202
253
    if (!s)
203
    if (!(s =  expand_string(q)))
254
      {
204
      {
255
      *errmsg = string_sprintf("Expansion of \"%s\" in %s transport failed: "
205
      *errmsg = string_sprintf("Expansion of \"%s\" in %s transport failed: "
256
        "%s", q, tblock->name, expand_string_message);
206
        "%s", q, tblock->name, expand_string_message);
Lines 320-327 Link Here
320
      break;
270
      break;
321
271
322
    case 2:
272
    case 2:
323
    if (d >= 2.0*1024.0*1024.0*1024.0 && sizeof(off_t) <= 4)
273
      if (d >= 2.0*1024.0*1024.0*1024.0 && sizeof(off_t) <= 4)
324
	which = US"quota_warn_threshold";
274
	  which = US"quota_warn_threshold";
325
      ob->quota_warn_threshold_value = (off_t)d;
275
      ob->quota_warn_threshold_value = (off_t)d;
326
      q = ob->mailbox_size_string;
276
      q = ob->mailbox_size_string;
327
      default_value = -1.0;
277
      default_value = -1.0;
Lines 367-372 Link Here
367
{
317
{
368
appendfile_transport_options_block *ob =
318
appendfile_transport_options_block *ob =
369
  (appendfile_transport_options_block *)(tblock->options_block);
319
  (appendfile_transport_options_block *)(tblock->options_block);
320
uschar * s;
370
321
371
/* Set up the setup entry point, to be called in the privileged state */
322
/* Set up the setup entry point, to be called in the privileged state */
372
323
Lines 465-484 Link Here
465
/* If "create_file" is set, check that a valid option is given, and set the
416
/* If "create_file" is set, check that a valid option is given, and set the
466
integer variable. */
417
integer variable. */
467
418
468
if (ob->create_file_string)
419
if ((s = ob->create_file_string ) && *s)
469
  {
420
  {
470
  int value = 0;
421
  int val = 0;
471
  if (Ustrcmp(ob->create_file_string, "anywhere") == 0)
422
  if (Ustrcmp(s, "anywhere") == 0)			val = create_anywhere;
472
    value = create_anywhere;
423
  else if (*s == '/' || Ustrcmp(s, "belowhome") == 0)	val = create_belowhome;
473
  else if (Ustrcmp(ob->create_file_string, "belowhome") == 0)
424
  else if (Ustrcmp(s, "inhome") == 0)			val = create_inhome;
474
    value = create_belowhome;
475
  else if (Ustrcmp(ob->create_file_string, "inhome") == 0)
476
    value = create_inhome;
477
  else
425
  else
478
    log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
426
    log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
479
      "invalid value given for \"file_create\" for the %s transport: %s",
427
      "invalid value given for \"create_file\" for the %s transport: '%s'",
480
        tblock->name, ob->create_file_string);
428
      tblock->name, s);
481
  ob->create_file = value;
429
  ob->create_file = val;
482
  }
430
  }
483
431
484
/* If quota_warn_threshold is set, set up default for warn_message. It may
432
/* If quota_warn_threshold is set, set up default for warn_message. It may
Lines 649-655 Link Here
649
597
650
/* Search the formats for a match */
598
/* Search the formats for a match */
651
599
652
while ((s = string_nextinlist(&format,&sep,big_buffer,big_buffer_size)))
600
/* not expanded so cannot be tainted */
601
while ((s = string_nextinlist(&format, &sep, big_buffer, big_buffer_size)))
653
  {
602
  {
654
  int slen = Ustrlen(s);
603
  int slen = Ustrlen(s);
655
  BOOL match = len >= slen && Ustrncmp(data, s, slen) == 0;
604
  BOOL match = len >= slen && Ustrncmp(data, s, slen) == 0;
Lines 702-715 Link Here
702
Arguments:
651
Arguments:
703
  dirname       the name of the directory
652
  dirname       the name of the directory
704
  countptr      where to add the file count (because this function recurses)
653
  countptr      where to add the file count (because this function recurses)
705
  regex         a compiled regex to get the size from a name
654
  re            a compiled regex to get the size from a name
706
655
707
Returns:        the sum of the sizes of the stattable files
656
Returns:        the sum of the sizes of the stattable files
708
                zero if the directory cannot be opened
657
                zero if the directory cannot be opened
709
*/
658
*/
710
659
711
off_t
660
off_t
712
check_dir_size(const uschar * dirname, int *countptr, const pcre *regex)
661
check_dir_size(const uschar * dirname, int * countptr, const pcre2_code * re)
713
{
662
{
714
DIR *dir;
663
DIR *dir;
715
off_t sum = 0;
664
off_t sum = 0;
Lines 728-741 Link Here
728
677
729
  /* If there's a regex, try to find the size using it */
678
  /* If there's a regex, try to find the size using it */
730
679
731
  if (regex)
680
  if (re)
732
    {
681
    {
733
    int ovector[6];
682
    pcre2_match_data * md = pcre2_match_data_create(2, pcre_gen_ctx);
734
    if (pcre_exec(regex, NULL, CS name, Ustrlen(name), 0, 0, ovector,6) >= 2)
683
    int rc = pcre2_match(re, (PCRE2_SPTR)name, PCRE2_ZERO_TERMINATED,
684
			  0, 0, md, pcre_mtc_ctx);
685
    PCRE2_SIZE * ovec = pcre2_get_ovector_pointer(md);
686
    if (  rc >= 0
687
       && (rc = pcre2_get_ovector_count(md)) >= 2)
735
      {
688
      {
736
      uschar *endptr;
689
      uschar *endptr;
737
      off_t size = (off_t)Ustrtod(name + ovector[2], &endptr);
690
      off_t size = (off_t)Ustrtod(name + ovec[2], &endptr);
738
      if (endptr == name + ovector[3])
691
      if (endptr == name + ovec[3])
739
        {
692
        {
740
        sum += size;
693
        sum += size;
741
        DEBUG(D_transport)
694
        DEBUG(D_transport)
Lines 762-768 Link Here
762
    if ((statbuf.st_mode & S_IFMT) == S_IFREG)
715
    if ((statbuf.st_mode & S_IFMT) == S_IFREG)
763
      sum += statbuf.st_size / statbuf.st_nlink;
716
      sum += statbuf.st_size / statbuf.st_nlink;
764
    else if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
717
    else if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
765
      sum += check_dir_size(path, &count, regex);
718
      sum += check_dir_size(path, &count, re);
766
  }
719
  }
767
720
768
closedir(dir);
721
closedir(dir);
Lines 940-967 Link Here
940
Arguments:
893
Arguments:
941
  filename     the file name
894
  filename     the file name
942
  create_file  the ob->create_file option
895
  create_file  the ob->create_file option
896
  deliver_dir  the delivery directory
943
897
944
Returns:       TRUE if creation is permitted
898
Returns:       TRUE if creation is permitted
945
*/
899
*/
946
900
947
static BOOL
901
static BOOL
948
check_creation(uschar *filename, int create_file)
902
check_creation(uschar *filename, int create_file, const uschar * deliver_dir)
949
{
903
{
950
BOOL yield = TRUE;
904
BOOL yield = TRUE;
951
905
952
if (deliver_home  &&  create_file != create_anywhere)
906
if (deliver_dir  &&  create_file != create_anywhere)
953
  {
907
  {
954
  int len = Ustrlen(deliver_home);
908
  int len = Ustrlen(deliver_dir);
955
  uschar *file = filename;
909
  uschar *file = filename;
956
910
957
  while (file[0] == '/' && file[1] == '/') file++;
911
  while (file[0] == '/' && file[1] == '/') file++;
958
  if (Ustrncmp(file, deliver_home, len) != 0 || file[len] != '/' ||
912
  if (  Ustrncmp(file, deliver_dir, len) != 0
959
       ( Ustrchr(file+len+2, '/') != NULL &&
913
     || file[len] != '/'
960
         (
914
     ||    Ustrchr(file+len+2, '/') != NULL
961
         create_file != create_belowhome ||
915
	&& (  create_file != create_belowhome
962
         Ustrstr(file+len, "/../") != NULL
916
	   || Ustrstr(file+len, "/../") != NULL
963
         )
917
	   )
964
       )
965
     ) yield = FALSE;
918
     ) yield = FALSE;
966
919
967
  /* If yield is TRUE, the file name starts with the home directory, and does
920
  /* If yield is TRUE, the file name starts with the home directory, and does
Lines 999-1008 Link Here
999
    if (rp)
952
    if (rp)
1000
      {
953
      {
1001
      uschar hdbuffer[PATH_MAX+1];
954
      uschar hdbuffer[PATH_MAX+1];
1002
      uschar *rph = deliver_home;
955
      const uschar * rph = deliver_dir;
1003
      int rlen = Ustrlen(big_buffer);
956
      int rlen = Ustrlen(big_buffer);
1004
957
1005
      if ((rp = US realpath(CS deliver_home, CS hdbuffer)))
958
      if ((rp = US realpath(CS deliver_dir, CS hdbuffer)))
1006
        {
959
        {
1007
        rph = hdbuffer;
960
        rph = hdbuffer;
1008
        len = Ustrlen(rph);
961
        len = Ustrlen(rph);
Lines 1013-1019 Link Here
1013
        {
966
        {
1014
        yield = FALSE;
967
        yield = FALSE;
1015
        DEBUG(D_transport) debug_printf("Real path \"%s\" does not match \"%s\"\n",
968
        DEBUG(D_transport) debug_printf("Real path \"%s\" does not match \"%s\"\n",
1016
          big_buffer, deliver_home);
969
          big_buffer, deliver_dir);
1017
        }
970
        }
1018
      }
971
      }
1019
    }
972
    }
Lines 1183-1188 Link Here
1183
appendfile_transport_options_block *ob =
1136
appendfile_transport_options_block *ob =
1184
  (appendfile_transport_options_block *)(tblock->options_block);
1137
  (appendfile_transport_options_block *)(tblock->options_block);
1185
struct stat statbuf;
1138
struct stat statbuf;
1139
const uschar * deliver_dir;
1186
uschar *fdname = NULL;
1140
uschar *fdname = NULL;
1187
uschar *filename = NULL;
1141
uschar *filename = NULL;
1188
uschar *hitchname = NULL;
1142
uschar *hitchname = NULL;
Lines 1286-1297 Link Here
1286
    expand_string_message);
1240
    expand_string_message);
1287
  goto ret_panic;
1241
  goto ret_panic;
1288
  }
1242
  }
1289
if (is_tainted(path))
1290
  {
1291
  addr->message = string_sprintf("Tainted '%s' (file or directory "
1292
    "name for %s transport) not permitted", path, tblock->name);
1293
  goto ret_panic;
1294
  }
1295
1243
1296
if (path[0] != '/')
1244
if (path[0] != '/')
1297
  {
1245
  {
Lines 1368-1373 Link Here
1368
  return FALSE;
1316
  return FALSE;
1369
  }
1317
  }
1370
1318
1319
/* If an absolute path was given for create_file the it overrides deliver_home
1320
(here) and de-taints the filename (below, after check_creation() */
1321
1322
deliver_dir = *ob->create_file_string == '/'
1323
  ? ob->create_file_string : deliver_home;
1324
1371
/* Handle the case of a file name. If the file name is /dev/null, we can save
1325
/* Handle the case of a file name. If the file name is /dev/null, we can save
1372
ourselves some effort and just give a success return right away. */
1326
ourselves some effort and just give a success return right away. */
1373
1327
Lines 1384-1393 Link Here
1384
    }
1338
    }
1385
1339
1386
  /* Set the name of the file to be opened, and the file to which the data
1340
  /* Set the name of the file to be opened, and the file to which the data
1387
  is written, and find out if we are permitted to create a non-existent file. */
1341
  is written, and find out if we are permitted to create a non-existent file.
1342
  If the create_file option is an absolute path and the file was within it,
1343
  de-taint.  Chaeck for a tainted path. */
1344
1345
  if (  (allow_creation_here = check_creation(path, ob->create_file, deliver_dir))
1346
     && ob->create_file == create_belowhome)
1347
    if (is_tainted(path))
1348
      {
1349
      DEBUG(D_transport) debug_printf("de-tainting path '%s'\n", path);
1350
      path = string_copy_taint(path, GET_UNTAINTED);
1351
      }
1388
1352
1353
  if (is_tainted(path)) goto tainted_ret_panic;
1389
  dataname = filename = path;
1354
  dataname = filename = path;
1390
  allow_creation_here = check_creation(filename, ob->create_file);
1391
1355
1392
  /* If ob->create_directory is set, attempt to create the directories in
1356
  /* If ob->create_directory is set, attempt to create the directories in
1393
  which this mailbox lives, but only if we are permitted to create the file
1357
  which this mailbox lives, but only if we are permitted to create the file
Lines 1397-1413 Link Here
1397
  if (ob->create_directory && allow_creation_here)
1361
  if (ob->create_directory && allow_creation_here)
1398
    {
1362
    {
1399
    uschar *p = Ustrrchr(path, '/');
1363
    uschar *p = Ustrrchr(path, '/');
1400
    *p = '\0';
1364
    p = string_copyn(path, p - path);
1401
    if (!directory_make(NULL, path, ob->dirmode, FALSE))
1365
    if (!directory_make(NULL, p, ob->dirmode, FALSE))
1402
      {
1366
      {
1403
      addr->basic_errno = errno;
1367
      addr->basic_errno = errno;
1404
      addr->message =
1368
      addr->message =
1405
        string_sprintf("failed to create directories for %s: %s", path,
1369
        string_sprintf("failed to create directories for %s: %s", path,
1406
          strerror(errno));
1370
          exim_errstr(errno));
1407
      DEBUG(D_transport) debug_printf("%s transport: %s\n", tblock->name, path);
1371
      DEBUG(D_transport) debug_printf("%s transport: %s\n", tblock->name, path);
1408
      return FALSE;
1372
      return FALSE;
1409
      }
1373
      }
1410
    *p = '/';
1411
    }
1374
    }
1412
1375
1413
  /* If file_format is set we must check that any existing file matches one of
1376
  /* If file_format is set we must check that any existing file matches one of
Lines 2204-2213 Link Here
2204
2167
2205
else
2168
else
2206
  {
2169
  {
2207
  uschar *check_path = path;    /* Default quota check path */
2170
  uschar *check_path;		/* Default quota check path */
2208
  const pcre *regex = NULL;     /* Regex for file size from file name */
2171
  const pcre2_code * re = NULL;     /* Regex for file size from file name */
2209
2172
2210
  if (!check_creation(string_sprintf("%s/any", path), ob->create_file))
2173
  if (!check_creation(string_sprintf("%s/any", path),
2174
		      ob->create_file, deliver_dir))
2211
    {
2175
    {
2212
    addr->basic_errno = ERRNO_BADCREATE;
2176
    addr->basic_errno = ERRNO_BADCREATE;
2213
    addr->message = string_sprintf("tried to create file in %s, but "
2177
    addr->message = string_sprintf("tried to create file in %s, but "
Lines 2215-2220 Link Here
2215
    goto RETURN;
2179
    goto RETURN;
2216
    }
2180
    }
2217
2181
2182
  /* If the create_file option is an absolute path and the file was within
2183
  it, de-taint. Otherwise check for taint. */
2184
2185
  if (is_tainted(path))
2186
    if (ob->create_file == create_belowhome)
2187
      {
2188
      DEBUG(D_transport) debug_printf("de-tainting path '%s'\n", path);
2189
      path = string_copy_taint(path, GET_UNTAINTED);
2190
      }
2191
    else
2192
      goto tainted_ret_panic;
2193
2194
  check_path = path;
2195
2218
  #ifdef SUPPORT_MAILDIR
2196
  #ifdef SUPPORT_MAILDIR
2219
  /* For a maildir delivery, ensure that all the relevant directories exist,
2197
  /* For a maildir delivery, ensure that all the relevant directories exist,
2220
  and a maildirfolder file if necessary. */
2198
  and a maildirfolder file if necessary. */
Lines 2233-2250 Link Here
2233
2211
2234
  if (ob->quota_value > 0 || THRESHOLD_CHECK || ob->maildir_use_size_file)
2212
  if (ob->quota_value > 0 || THRESHOLD_CHECK || ob->maildir_use_size_file)
2235
    {
2213
    {
2236
    const uschar *error;
2214
    PCRE2_SIZE offset;
2237
    int offset;
2215
    int err;
2238
2216
2239
    /* Compile the regex if there is one. */
2217
    /* Compile the regex if there is one. */
2240
2218
2241
    if (ob->quota_size_regex)
2219
    if (ob->quota_size_regex)
2242
      {
2220
      {
2243
      if (!(regex = pcre_compile(CS ob->quota_size_regex, PCRE_COPT,
2221
      if (!(re = pcre2_compile((PCRE2_SPTR)ob->quota_size_regex,
2244
	  CCSS &error, &offset, NULL)))
2222
		  PCRE2_ZERO_TERMINATED, PCRE_COPT, &err, &offset, pcre_cmp_ctx)))
2245
        {
2223
        {
2224
	uschar errbuf[128];
2225
	pcre2_get_error_message(err, errbuf, sizeof(errbuf));
2246
        addr->message = string_sprintf("appendfile: regular expression "
2226
        addr->message = string_sprintf("appendfile: regular expression "
2247
          "error: %s at offset %d while compiling %s", error, offset,
2227
          "error: %s at offset %ld while compiling %s", errbuf, (long)offset,
2248
          ob->quota_size_regex);
2228
          ob->quota_size_regex);
2249
        return FALSE;
2229
        return FALSE;
2250
        }
2230
        }
Lines 2287-2300 Link Here
2287
        {
2267
        {
2288
        uschar *new_check_path = string_copy(check_path);
2268
        uschar *new_check_path = string_copy(check_path);
2289
        uschar *slash = Ustrrchr(new_check_path, '/');
2269
        uschar *slash = Ustrrchr(new_check_path, '/');
2290
        if (slash != NULL)
2270
        if (slash)
2291
          {
2271
          {
2292
          if (slash[1] == 0)
2272
          if (!slash[1])
2293
            {
2273
            {
2294
            *slash = 0;
2274
            *slash = 0;
2295
            slash = Ustrrchr(new_check_path, '/');
2275
            slash = Ustrrchr(new_check_path, '/');
2296
            }
2276
            }
2297
          if (slash != NULL)
2277
          if (slash)
2298
            {
2278
            {
2299
            *slash = 0;
2279
            *slash = 0;
2300
            check_path = new_check_path;
2280
            check_path = new_check_path;
Lines 2319-2337 Link Here
2319
  #ifdef SUPPORT_MAILDIR
2299
  #ifdef SUPPORT_MAILDIR
2320
  if (ob->maildir_use_size_file)
2300
  if (ob->maildir_use_size_file)
2321
    {
2301
    {
2322
    const pcre *dir_regex = NULL;
2302
    const pcre2_code * dir_regex = NULL;
2323
    const uschar *error;
2303
    PCRE2_SIZE offset;
2324
    int offset;
2304
    int err;
2325
2305
2326
    if (ob->maildir_dir_regex)
2306
    if (ob->maildir_dir_regex)
2327
      {
2307
      {
2328
      int check_path_len = Ustrlen(check_path);
2308
      int check_path_len = Ustrlen(check_path);
2329
2309
2330
      if (!(dir_regex = pcre_compile(CS ob->maildir_dir_regex, PCRE_COPT,
2310
      if (!(dir_regex = pcre2_compile((PCRE2_SPTR)ob->maildir_dir_regex,
2331
	  CCSS &error, &offset, NULL)))
2311
	    PCRE2_ZERO_TERMINATED, PCRE_COPT, &err, &offset, pcre_cmp_ctx)))
2332
        {
2312
        {
2313
	uschar errbuf[128];
2314
	pcre2_get_error_message(err, errbuf, sizeof(errbuf));
2333
        addr->message = string_sprintf("appendfile: regular expression "
2315
        addr->message = string_sprintf("appendfile: regular expression "
2334
          "error: %s at offset %d while compiling %s", error, offset,
2316
          "error: %s at offset %ld while compiling %s", errbuf, (long)offset,
2335
          ob->maildir_dir_regex);
2317
          ob->maildir_dir_regex);
2336
        return FALSE;
2318
        return FALSE;
2337
        }
2319
        }
Lines 2349-2356 Link Here
2349
        {
2331
        {
2350
        uschar *s = path + check_path_len;
2332
        uschar *s = path + check_path_len;
2351
        while (*s == '/') s++;
2333
        while (*s == '/') s++;
2352
        s = (*s == 0) ? US "new" : string_sprintf("%s/new", s);
2334
        s = *s ? string_sprintf("%s/new", s) : US"new";
2353
        if (pcre_exec(dir_regex, NULL, CS s, Ustrlen(s), 0, 0, NULL, 0) < 0)
2335
	if (!regex_match(dir_regex, s, -1, NULL))
2354
          {
2336
          {
2355
          disable_quota = TRUE;
2337
          disable_quota = TRUE;
2356
          DEBUG(D_transport) debug_printf("delivery directory does not match "
2338
          DEBUG(D_transport) debug_printf("delivery directory does not match "
Lines 2371-2377 Link Here
2371
      off_t size;
2353
      off_t size;
2372
      int filecount;
2354
      int filecount;
2373
2355
2374
      if ((maildirsize_fd = maildir_ensure_sizefile(check_path, ob, regex, dir_regex,
2356
      if ((maildirsize_fd = maildir_ensure_sizefile(check_path, ob,  re, dir_regex,
2375
	  &size, &filecount)) == -1)
2357
	  &size, &filecount)) == -1)
2376
        {
2358
        {
2377
        addr->basic_errno = errno;
2359
        addr->basic_errno = errno;
Lines 2396-2402 Link Here
2396
 *    (void)unlink(CS string_sprintf("%s/maildirsize", check_path));
2378
 *    (void)unlink(CS string_sprintf("%s/maildirsize", check_path));
2397
 *    if (THRESHOLD_CHECK)
2379
 *    if (THRESHOLD_CHECK)
2398
 *      mailbox_size = maildir_compute_size(check_path, &mailbox_filecount, &old_latest,
2380
 *      mailbox_size = maildir_compute_size(check_path, &mailbox_filecount, &old_latest,
2399
 *        regex, dir_regex, FALSE);
2381
 *         re, dir_regex, FALSE);
2400
 *    }
2382
 *    }
2401
*/
2383
*/
2402
2384
Lines 2408-2423 Link Here
2408
  count. Note that ob->quota_filecount_value cannot be set without
2390
  count. Note that ob->quota_filecount_value cannot be set without
2409
  ob->quota_value being set. */
2391
  ob->quota_value being set. */
2410
2392
2411
  if (!disable_quota &&
2393
  if (  !disable_quota
2412
      (ob->quota_value > 0 || THRESHOLD_CHECK) &&
2394
     && (ob->quota_value > 0 || THRESHOLD_CHECK)
2413
      (mailbox_size < 0 ||
2395
     && (  mailbox_size < 0
2414
        (mailbox_filecount < 0 && ob->quota_filecount_value > 0)))
2396
	|| mailbox_filecount < 0 && ob->quota_filecount_value > 0
2397
    )   )
2415
    {
2398
    {
2416
    off_t size;
2399
    off_t size;
2417
    int filecount = 0;
2400
    int filecount = 0;
2418
    DEBUG(D_transport)
2401
    DEBUG(D_transport)
2419
      debug_printf("quota checks on directory %s\n", check_path);
2402
      debug_printf("quota checks on directory %s\n", check_path);
2420
    size = check_dir_size(check_path, &filecount, regex);
2403
    size = check_dir_size(check_path, &filecount,  re);
2421
    if (mailbox_size < 0) mailbox_size = size;
2404
    if (mailbox_size < 0) mailbox_size = size;
2422
    if (mailbox_filecount < 0) mailbox_filecount = filecount;
2405
    if (mailbox_filecount < 0) mailbox_filecount = filecount;
2423
    }
2406
    }
Lines 2484-2490 Link Here
2484
      uschar *basename;
2467
      uschar *basename;
2485
2468
2486
      (void)gettimeofday(&msg_tv, NULL);
2469
      (void)gettimeofday(&msg_tv, NULL);
2487
      basename = string_sprintf(TIME_T_FMT ".H%luP" PID_T_FMT ".%s",
2470
      basename = string_sprintf(TIME_T_FMT ".M%luP" PID_T_FMT ".%s",
2488
       	msg_tv.tv_sec, msg_tv.tv_usec, getpid(), primary_hostname);
2471
       	msg_tv.tv_sec, msg_tv.tv_usec, getpid(), primary_hostname);
2489
2472
2490
      filename = dataname = string_sprintf("tmp/%s", basename);
2473
      filename = dataname = string_sprintf("tmp/%s", basename);
Lines 2556-2566 Link Here
2556
    dataname = string_sprintf("%s.msg", mailstore_basename);
2539
    dataname = string_sprintf("%s.msg", mailstore_basename);
2557
2540
2558
    fd = Uopen(filename, O_WRONLY|O_CREAT|O_EXCL, mode);
2541
    fd = Uopen(filename, O_WRONLY|O_CREAT|O_EXCL, mode);
2559
    if (fd < 0 &&                                 /* failed to open, and */
2542
    if (  fd < 0				/* failed to open, and */
2560
        (errno != ENOENT ||                       /* either not non-exist */
2543
       && (   errno != ENOENT			/* either not non-exist */
2561
         !ob->create_directory ||                 /* or not allowed to make */
2544
	  || !ob->create_directory		/* or not allowed to make */
2562
         !directory_make(NULL, path, ob->dirmode, FALSE) ||  /* or failed to create dir */
2545
	  || !directory_make(NULL, path, ob->dirmode, FALSE)  /* or failed to create dir */
2563
         (fd = Uopen(filename, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0)) /* or then failed to open */
2546
	  || (fd = Uopen(filename, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0 /* or then failed to open */
2547
       )  )
2564
      {
2548
      {
2565
      addr->basic_errno = errno;
2549
      addr->basic_errno = errno;
2566
      addr->message = string_sprintf("while creating file %s", filename);
2550
      addr->message = string_sprintf("while creating file %s", filename);
Lines 2739-2744 Link Here
2739
2723
2740
  }
2724
  }
2741
2725
2726
if (verify_mode)
2727
  {
2728
  addr->basic_errno = errno;
2729
  addr->message = US"Over quota";
2730
  addr->transport_return = yield;
2731
  DEBUG(D_transport)
2732
    debug_printf("appendfile (verify) yields %d with errno=%d more_errno=%d\n",
2733
      yield, addr->basic_errno, addr->more_errno);
2734
2735
  goto RETURN;
2736
  }
2737
2742
/* If we are writing in MBX format, what we actually do is to write the message
2738
/* If we are writing in MBX format, what we actually do is to write the message
2743
to a temporary file, and then copy it to the real file once we know its size.
2739
to a temporary file, and then copy it to the real file once we know its size.
2744
This is the most straightforward way of getting the correct length in the
2740
This is the most straightforward way of getting the correct length in the
Lines 3195-3201 Link Here
3195
          uschar *iptr = expand_string(nametag);
3191
          uschar *iptr = expand_string(nametag);
3196
          if (iptr)
3192
          if (iptr)
3197
            {
3193
            {
3198
            uschar *etag = store_get(Ustrlen(iptr) + 2, is_tainted(iptr));
3194
            uschar *etag = store_get(Ustrlen(iptr) + 2, iptr);
3199
            uschar *optr = etag;
3195
            uschar *optr = etag;
3200
            for ( ; *iptr; iptr++)
3196
            for ( ; *iptr; iptr++)
3201
              if (mac_isgraph(*iptr) && *iptr != '/')
3197
              if (mac_isgraph(*iptr) && *iptr != '/')
Lines 3309-3314 Link Here
3309
3305
3310
return FALSE;
3306
return FALSE;
3311
3307
3308
tainted_ret_panic:
3309
  addr->message = string_sprintf("Tainted '%s' (file or directory "
3310
      "name for %s transport) not permitted", path, tblock->name);
3312
ret_panic:
3311
ret_panic:
3313
  addr->transport_return = PANIC;
3312
  addr->transport_return = PANIC;
3314
  return FALSE;
3313
  return FALSE;
(-)exim.orig/src/transports/appendfile.h (-1 / +2 lines)
Lines 3-8 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2021 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
8
/* Private structure for the private options. */
9
/* Private structure for the private options. */
Lines 94-99 Link Here
94
95
95
/* Function that is shared with tf_maildir.c */
96
/* Function that is shared with tf_maildir.c */
96
97
97
extern off_t  check_dir_size(const uschar *, int *, const pcre *);
98
extern off_t  check_dir_size(const uschar *, int *, const pcre2_code *);
98
99
99
/* End of transports/appendfile.h */
100
/* End of transports/appendfile.h */
(-)exim.orig/src/transports/autoreply.c (-65 / +61 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 57-83 Link Here
57
#else   /*!MACRO_PREDEF*/
57
#else   /*!MACRO_PREDEF*/
58
58
59
59
60
/* Default private options block for the autoreply transport. */
60
/* Default private options block for the autoreply transport.
61
All non-mentioned lements zero/null/false. */
61
62
62
autoreply_transport_options_block autoreply_transport_option_defaults = {
63
autoreply_transport_options_block autoreply_transport_option_defaults = {
63
  NULL,           /* from */
64
  .mode = 0600,
64
  NULL,           /* reply_to */
65
  NULL,           /* to */
66
  NULL,           /* cc */
67
  NULL,           /* bcc */
68
  NULL,           /* subject */
69
  NULL,           /* headers */
70
  NULL,           /* text */
71
  NULL,           /* file */
72
  NULL,           /* logfile */
73
  NULL,           /* oncelog */
74
  NULL,           /* once_repeat */
75
  NULL,           /* never_mail */
76
  0600,           /* mode */
77
  0,              /* once_file_size */
78
  FALSE,          /* file_expand */
79
  FALSE,          /* file_optional */
80
  FALSE           /* return message */
81
};
65
};
82
66
83
67
Lines 175-192 Link Here
175
list. Any that are found are removed.
159
list. Any that are found are removed.
176
160
177
Arguments:
161
Arguments:
178
  listptr     points to the list of addresses
162
  list        list of addresses to be checked
179
  never_mail  an address list, already expanded
163
  never_mail  an address list, already expanded
180
164
181
Returns:      nothing
165
Returns:      edited replacement address list, or NULL, or original
182
*/
166
*/
183
167
184
static void
168
static uschar *
185
check_never_mail(uschar **listptr, const uschar *never_mail)
169
check_never_mail(uschar * list, const uschar * never_mail)
186
{
170
{
187
uschar *s = *listptr;
171
rmark reset_point = store_mark();
172
uschar * newlist = string_copy(list);
173
uschar * s = newlist;
174
BOOL hit = FALSE;
188
175
189
while (*s != 0)
176
while (*s)
190
  {
177
  {
191
  uschar *error, *next;
178
  uschar *error, *next;
192
  uschar *e = parse_find_address_end(s, FALSE);
179
  uschar *e = parse_find_address_end(s, FALSE);
Lines 220-225 Link Here
220
    {
207
    {
221
    DEBUG(D_transport)
208
    DEBUG(D_transport)
222
      debug_printf("discarding recipient %s (matched never_mail)\n", next);
209
      debug_printf("discarding recipient %s (matched never_mail)\n", next);
210
    hit = TRUE;
223
    if (terminator == ',') e++;
211
    if (terminator == ',') e++;
224
    memmove(s, e, Ustrlen(e) + 1);
212
    memmove(s, e, Ustrlen(e) + 1);
225
    }
213
    }
Lines 230-247 Link Here
230
    }
218
    }
231
  }
219
  }
232
220
221
/* If no addresses were removed, retrieve the memory used and return
222
the original. */
223
224
if (!hit)
225
  {
226
  store_reset(reset_point);
227
  return list;
228
  }
229
233
/* Check to see if we removed the last address, leaving a terminating comma
230
/* Check to see if we removed the last address, leaving a terminating comma
234
that needs to be removed */
231
that needs to be removed */
235
232
236
s = *listptr + Ustrlen(*listptr);
233
s = newlist + Ustrlen(newlist);
237
while (s > *listptr && (isspace(s[-1]) || s[-1] == ',')) s--;
234
while (s > newlist && (isspace(s[-1]) || s[-1] == ',')) s--;
238
*s = 0;
235
*s = 0;
239
236
240
/* Check to see if there any addresses left; if not, set NULL */
237
/* Check to see if there any addresses left; if not, return NULL */
238
239
s = newlist;
240
while (s && isspace(*s)) s++;
241
if (*s)
242
  return newlist;
241
243
242
s = *listptr;
244
store_reset(reset_point);
243
while (s != 0 && isspace(*s)) s++;
245
return NULL;
244
if (*s == 0) *listptr = NULL;
245
}
246
}
246
247
247
248
Lines 263-269 Link Here
263
int cache_fd = -1;
264
int cache_fd = -1;
264
int cache_size = 0;
265
int cache_size = 0;
265
int add_size = 0;
266
int add_size = 0;
266
EXIM_DB *dbm_file = NULL;
267
EXIM_DB * dbm_file = NULL;
267
BOOL file_expand, return_message;
268
BOOL file_expand, return_message;
268
uschar *from, *reply_to, *to, *cc, *bcc, *subject, *headers, *text, *file;
269
uschar *from, *reply_to, *to, *cc, *bcc, *subject, *headers, *text, *file;
269
uschar *logfile, *oncelog;
270
uschar *logfile, *oncelog;
Lines 345-360 Link Here
345
    return FALSE;
346
    return FALSE;
346
347
347
  if (oncerepeat)
348
  if (oncerepeat)
348
    {
349
    if ((once_repeat_sec = readconf_readtime(oncerepeat, 0, FALSE)) < 0)
349
    once_repeat_sec = readconf_readtime(oncerepeat, 0, FALSE);
350
    if (once_repeat_sec < 0)
351
      {
350
      {
352
      addr->transport_return = FAIL;
351
      addr->transport_return = FAIL;
353
      addr->message = string_sprintf("Invalid time value \"%s\" for "
352
      addr->message = string_sprintf("Invalid time value \"%s\" for "
354
        "\"once_repeat\" in %s transport", oncerepeat, tblock->name);
353
        "\"once_repeat\" in %s transport", oncerepeat, tblock->name);
355
      return FALSE;
354
      return FALSE;
356
      }
355
      }
357
    }
358
  }
356
  }
359
357
360
/* If the never_mail option is set, we have to scan all the recipients and
358
/* If the never_mail option is set, we have to scan all the recipients and
Lines 372-380 Link Here
372
    return FALSE;
370
    return FALSE;
373
    }
371
    }
374
372
375
  if (to) check_never_mail(&to, never_mail);
373
  if (to) to = check_never_mail(to, never_mail);
376
  if (cc) check_never_mail(&cc, never_mail);
374
  if (cc) cc = check_never_mail(cc, never_mail);
377
  if (bcc) check_never_mail(&bcc, never_mail);
375
  if (bcc) bcc = check_never_mail(bcc, never_mail);
378
376
379
  if (!to && !cc && !bcc)
377
  if (!to && !cc && !bcc)
380
    {
378
    {
Lines 439-445 Link Here
439
437
440
    cache_size = statbuf.st_size;
438
    cache_size = statbuf.st_size;
441
    add_size = sizeof(time_t) + Ustrlen(to) + 1;
439
    add_size = sizeof(time_t) + Ustrlen(to) + 1;
442
    cache_buff = store_get(cache_size + add_size, is_tainted(oncelog));
440
    cache_buff = store_get(cache_size + add_size, oncelog);
443
441
444
    if (read(cache_fd, cache_buff, cache_size) != cache_size)
442
    if (read(cache_fd, cache_buff, cache_size) != cache_size)
445
      {
443
      {
Lines 478-485 Link Here
478
476
479
    dirname = (s = Ustrrchr(oncelog, '/'))
477
    dirname = (s = Ustrrchr(oncelog, '/'))
480
      ? string_copyn(oncelog, s - oncelog) : NULL;
478
      ? string_copyn(oncelog, s - oncelog) : NULL;
481
    EXIM_DBOPEN(oncelog, dirname, O_RDWR|O_CREAT, ob->mode, &dbm_file);
479
    if (!(dbm_file = exim_dbopen(oncelog, dirname, O_RDWR|O_CREAT, ob->mode)))
482
    if (!dbm_file)
483
      {
480
      {
484
      addr->transport_return = DEFER;
481
      addr->transport_return = DEFER;
485
      addr->basic_errno = errno;
482
      addr->basic_errno = errno;
Lines 489-500 Link Here
489
      goto END_OFF;
486
      goto END_OFF;
490
      }
487
      }
491
488
492
    EXIM_DATUM_INIT(key_datum);        /* Some DBM libraries need datums */
489
    exim_datum_init(&key_datum);        /* Some DBM libraries need datums */
493
    EXIM_DATUM_INIT(result_datum);     /* to be cleared */
490
    exim_datum_init(&result_datum);     /* to be cleared */
494
    EXIM_DATUM_DATA(key_datum) = CS to;
491
    exim_datum_data_set(&key_datum, (void *) to);
495
    EXIM_DATUM_SIZE(key_datum) = Ustrlen(to) + 1;
492
    exim_datum_size_set(&key_datum, Ustrlen(to) + 1);
496
493
497
    if (EXIM_DBGET(dbm_file, key_datum, result_datum))
494
    if (exim_dbget(dbm_file, &key_datum, &result_datum))
498
      {
495
      {
499
      /* If the datum size is that of a binary time, we are in the new world
496
      /* If the datum size is that of a binary time, we are in the new world
500
      where messages are sent periodically. Otherwise the file is an old one,
497
      where messages are sent periodically. Otherwise the file is an old one,
Lines 503-510 Link Here
503
      introduced at Exim 3.00. In a couple of years' time the test on the size
500
      introduced at Exim 3.00. In a couple of years' time the test on the size
504
      can be abolished. */
501
      can be abolished. */
505
502
506
      if (EXIM_DATUM_SIZE(result_datum) == sizeof(time_t))
503
      if (exim_datum_size_get(&result_datum) == sizeof(time_t))
507
        memcpy(&then, EXIM_DATUM_DATA(result_datum), sizeof(time_t));
504
        memcpy(&then, exim_datum_data_get(&result_datum), sizeof(time_t));
508
      else
505
      else
509
        then = now;
506
        then = now;
510
      }
507
      }
Lines 577-583 Link Here
577
  addr->message = string_sprintf("Failed to create child process to send "
574
  addr->message = string_sprintf("Failed to create child process to send "
578
    "message from %s transport: %s", tblock->name, strerror(errno));
575
    "message from %s transport: %s", tblock->name, strerror(errno));
579
  DEBUG(D_transport) debug_printf("%s\n", addr->message);
576
  DEBUG(D_transport) debug_printf("%s\n", addr->message);
580
  if (dbm_file) EXIM_DBCLOSE(dbm_file);
577
  if (dbm_file) exim_dbclose(dbm_file);
581
  return FALSE;
578
  return FALSE;
582
  }
579
  }
583
580
Lines 649-660 Link Here
649
646
650
if (return_message)
647
if (return_message)
651
  {
648
  {
652
  uschar *rubric = (tblock->headers_only)?
649
  uschar *rubric = tblock->headers_only
653
    US"------ This is a copy of the message's header lines.\n"
650
    ? US"------ This is a copy of the message's header lines.\n"
654
    : (tblock->body_only)?
651
    : tblock->body_only
655
    US"------ This is a copy of the body of the message, without the headers.\n"
652
    ? US"------ This is a copy of the body of the message, without the headers.\n"
656
    :
653
    : US"------ This is a copy of the message, including all the headers.\n";
657
    US"------ This is a copy of the message, including all the headers.\n";
658
  transport_ctx tctx = {
654
  transport_ctx tctx = {
659
    .u = {.fd = fileno(fp)},
655
    .u = {.fd = fileno(fp)},
660
    .tblock = tblock,
656
    .tblock = tblock,
Lines 739-756 Link Here
739
else if (dbm_file)
735
else if (dbm_file)
740
  {
736
  {
741
  EXIM_DATUM key_datum, value_datum;
737
  EXIM_DATUM key_datum, value_datum;
742
  EXIM_DATUM_INIT(key_datum);          /* Some DBM libraries need to have */
738
  exim_datum_init(&key_datum);          /* Some DBM libraries need to have */
743
  EXIM_DATUM_INIT(value_datum);        /* cleared datums. */
739
  exim_datum_init(&value_datum);        /* cleared datums. */
744
  EXIM_DATUM_DATA(key_datum) = CS to;
740
  exim_datum_data_set(&key_datum, to);
745
  EXIM_DATUM_SIZE(key_datum) = Ustrlen(to) + 1;
741
  exim_datum_size_set(&key_datum, Ustrlen(to) + 1);
746
742
747
  /* Many OS define the datum value, sensibly, as a void *. However, there
743
  /* Many OS define the datum value, sensibly, as a void *. However, there
748
  are some which still have char *. By casting this address to a char * we
744
  are some which still have char *. By casting this address to a char * we
749
  can avoid warning messages from the char * systems. */
745
  can avoid warning messages from the char * systems. */
750
746
751
  EXIM_DATUM_DATA(value_datum) = CS (&now);
747
  exim_datum_data_set(&value_datum, &now);
752
  EXIM_DATUM_SIZE(value_datum) = (int)sizeof(time_t);
748
  exim_datum_size_set(&value_datum, sizeof(time_t));
753
  EXIM_DBPUT(dbm_file, key_datum, value_datum);
749
  exim_dbput(dbm_file, &key_datum, &value_datum);
754
  }
750
  }
755
751
756
/* If sending failed, defer to try again - but if once is set the next
752
/* If sending failed, defer to try again - but if once is set the next
Lines 813-819 Link Here
813
  }
809
  }
814
810
815
END_OFF:
811
END_OFF:
816
if (dbm_file) EXIM_DBCLOSE(dbm_file);
812
if (dbm_file) exim_dbclose(dbm_file);
817
if (cache_fd > 0) (void)close(cache_fd);
813
if (cache_fd > 0) (void)close(cache_fd);
818
814
819
DEBUG(D_transport) debug_printf("%s transport succeeded\n", tblock->name);
815
DEBUG(D_transport) debug_printf("%s transport succeeded\n", tblock->name);
(-)exim.orig/src/transports/lmtp.c (-11 / +11 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 489-496 Link Here
489
  {
489
  {
490
  DEBUG(D_transport) debug_printf("using command %s\n", ob->cmd);
490
  DEBUG(D_transport) debug_printf("using command %s\n", ob->cmd);
491
  sprintf(CS buffer, "%.50s transport", tblock->name);
491
  sprintf(CS buffer, "%.50s transport", tblock->name);
492
  if (!transport_set_up_command(&argv, ob->cmd, TRUE, PANIC, addrlist, buffer,
492
  if (!transport_set_up_command(&argv, ob->cmd, TRUE, PANIC, addrlist, FALSE,
493
       NULL))
493
	buffer, NULL))
494
    return FALSE;
494
    return FALSE;
495
495
496
  /* If the -N option is set, can't do any more. Presume all has gone well. */
496
  /* If the -N option is set, can't do any more. Presume all has gone well. */
Lines 558-580 Link Here
558
/* First thing is to wait for an initial greeting. */
558
/* First thing is to wait for an initial greeting. */
559
559
560
Ustrcpy(big_buffer, US"initial connection");
560
Ustrcpy(big_buffer, US"initial connection");
561
if (!lmtp_read_response(out, buffer, sizeof(buffer), '2',
561
if (!lmtp_read_response(out, buffer, sizeof(buffer), '2', timeout))
562
  timeout)) goto RESPONSE_FAILED;
562
  goto RESPONSE_FAILED;
563
563
564
/* Next, we send a LHLO command, and expect a positive response */
564
/* Next, we send a LHLO command, and expect a positive response */
565
565
566
if (!lmtp_write_command(fd_in, "%s %s\r\n", "LHLO",
566
if (!lmtp_write_command(fd_in, "%s %s\r\n", "LHLO", primary_hostname))
567
  primary_hostname)) goto WRITE_FAILED;
567
  goto WRITE_FAILED;
568
568
569
if (!lmtp_read_response(out, buffer, sizeof(buffer), '2',
569
if (!lmtp_read_response(out, buffer, sizeof(buffer), '2', timeout))
570
     timeout)) goto RESPONSE_FAILED;
570
  goto RESPONSE_FAILED;
571
571
572
/* If the ignore_quota option is set, note whether the server supports the
572
/* If the ignore_quota option is set, note whether the server supports the
573
IGNOREQUOTA option, and if so, set an appropriate addition for RCPT. */
573
IGNOREQUOTA option, and if so, set an appropriate addition for RCPT. */
574
574
575
if (ob->ignore_quota)
575
if (ob->ignore_quota)
576
  igquotstr = (pcre_exec(regex_IGNOREQUOTA, NULL, CS buffer,
576
  igquotstr = regex_match(regex_IGNOREQUOTA, buffer, -1, NULL)
577
    Ustrlen(CS buffer), 0, PCRE_EOPT, NULL, 0) >= 0)? US" IGNOREQUOTA" : US"";
577
    ? US" IGNOREQUOTA" : US"";
578
578
579
/* Now the envelope sender */
579
/* Now the envelope sender */
580
580
(-)exim.orig/src/transports/pipe.c (-47 / +26 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
9
Lines 88-118 Link Here
88
/* Default private options block for the pipe transport. */
88
/* Default private options block for the pipe transport. */
89
89
90
pipe_transport_options_block pipe_transport_option_defaults = {
90
pipe_transport_options_block pipe_transport_option_defaults = {
91
  NULL,           /* cmd */
91
  .path =	US"/bin:/usr/bin",
92
  NULL,           /* allow_commands */
92
  .temp_errors = US mac_expanded_string(EX_TEMPFAIL) ":"
93
  NULL,           /* environment */
93
		   mac_expanded_string(EX_CANTCREAT),
94
  US"/bin:/usr/bin",  /* path */
94
  .umask =	022,
95
  NULL,           /* message_prefix (reset in init if not bsmtp) */
95
  .max_output = 20480,
96
  NULL,           /* message_suffix (ditto) */
96
  .timeout =	60*60,
97
  US mac_expanded_string(EX_TEMPFAIL) ":"    /* temp_errors */
97
  /* all others null/zero/false */
98
     mac_expanded_string(EX_CANTCREAT),
99
  NULL,           /* check_string */
100
  NULL,           /* escape_string */
101
  022,            /* umask */
102
  20480,          /* max_output */
103
  60*60,          /* timeout */
104
  0,              /* options */
105
  FALSE,          /* force_command */
106
  FALSE,          /* freeze_exec_fail */
107
  FALSE,          /* freeze_signal */
108
  FALSE,          /* ignore_status */
109
  FALSE,          /* permit_coredump */
110
  FALSE,          /* restrict_to_path */
111
  FALSE,          /* timeout_defer */
112
  FALSE,          /* use_shell */
113
  FALSE,          /* use_bsmtp */
114
  FALSE,          /* use_classresources */
115
  FALSE           /* use_crlf */
116
};
98
};
117
99
118
100
Lines 144-156 Link Here
144
pipe_transport_options_block *ob =
126
pipe_transport_options_block *ob =
145
  (pipe_transport_options_block *)(tblock->options_block);
127
  (pipe_transport_options_block *)(tblock->options_block);
146
128
147
addrlist = addrlist;  /* Keep compiler happy */
148
dummy = dummy;
149
uid = uid;
150
gid = gid;
151
errmsg = errmsg;
152
ob = ob;
153
154
#ifdef HAVE_SETCLASSRESOURCES
129
#ifdef HAVE_SETCLASSRESOURCES
155
if (ob->use_classresources)
130
if (ob->use_classresources)
156
  {
131
  {
Lines 285-296 Link Here
285
driver options. Only one of body_only and headers_only can be set. */
260
driver options. Only one of body_only and headers_only can be set. */
286
261
287
ob->options |=
262
ob->options |=
288
  (tblock->body_only? topt_no_headers : 0) |
263
    (tblock->body_only ? topt_no_headers : 0)
289
  (tblock->headers_only? topt_no_body : 0) |
264
  | (tblock->headers_only ? topt_no_body : 0)
290
  (tblock->return_path_add? topt_add_return_path : 0) |
265
  | (tblock->return_path_add ? topt_add_return_path : 0)
291
  (tblock->delivery_date_add? topt_add_delivery_date : 0) |
266
  | (tblock->delivery_date_add ? topt_add_delivery_date : 0)
292
  (tblock->envelope_to_add? topt_add_envelope_to : 0) |
267
  | (tblock->envelope_to_add ? topt_add_envelope_to : 0)
293
  (ob->use_crlf? topt_use_crlf : 0);
268
  | (ob->use_crlf ? topt_use_crlf : 0);
294
}
269
}
295
270
296
271
Lines 329-335 Link Here
329
is in the addresses). */
304
is in the addresses). */
330
305
331
if (!transport_set_up_command(argvptr, cmd, expand_arguments, expand_fail,
306
if (!transport_set_up_command(argvptr, cmd, expand_arguments, expand_fail,
332
      addr, string_sprintf("%.50s transport", tname), NULL))
307
      addr, FALSE, string_sprintf("%.50s transport", tname), NULL))
333
  return FALSE;
308
  return FALSE;
334
309
335
/* Point to the set-up arguments. */
310
/* Point to the set-up arguments. */
Lines 442-448 Link Here
442
{
417
{
443
const uschar **argv;
418
const uschar **argv;
444
419
445
*argvptr = argv = store_get((4)*sizeof(uschar *), FALSE);
420
*argvptr = argv = store_get((4)*sizeof(uschar *), GET_UNTAINTED);
446
421
447
argv[0] = US"/bin/sh";
422
argv[0] = US"/bin/sh";
448
argv[1] = US"-c";
423
argv[1] = US"-c";
Lines 476-481 Link Here
476
451
477
    for (address_item * ad = addr; ad; ad = ad->next)
452
    for (address_item * ad = addr; ad; ad = ad->next)
478
      {
453
      {
454
      DEBUG(D_transport) if (is_tainted(ad->address))
455
	debug_printf("tainted element '%s' from $pipe_addresses\n", ad->address);
456
479
      /*XXX string_append_listele() ? */
457
      /*XXX string_append_listele() ? */
480
      if (ad != addr) g = string_catn(g, US" ", 1);
458
      if (ad != addr) g = string_catn(g, US" ", 1);
481
      g = string_cat(g, ad->address);
459
      g = string_cat(g, ad->address);
Lines 588-596 Link Here
588
  }
566
  }
589
567
590
/* If no command has been supplied, we are in trouble.
568
/* If no command has been supplied, we are in trouble.
591
 * We also check for an empty string since it may be
569
We also check for an empty string since it may be
592
 * coming from addr->local_part[0] == '|'
570
coming from addr->local_part[0] == '|' */
593
 */
594
571
595
if (!cmd || !*cmd)
572
if (!cmd || !*cmd)
596
  {
573
  {
Lines 601-606 Link Here
601
  }
578
  }
602
if (is_tainted(cmd))
579
if (is_tainted(cmd))
603
  {
580
  {
581
  DEBUG(D_transport) debug_printf("cmd '%s' is tainted\n", cmd);
604
  addr->message = string_sprintf("Tainted '%s' (command "
582
  addr->message = string_sprintf("Tainted '%s' (command "
605
    "for %s transport) not permitted", cmd, tblock->name);
583
    "for %s transport) not permitted", cmd, tblock->name);
606
  addr->transport_return = PANIC;
584
  addr->transport_return = PANIC;
Lines 659-669 Link Here
659
envp[envcount++] = string_sprintf("SENDER=%s", sender_address);
637
envp[envcount++] = string_sprintf("SENDER=%s", sender_address);
660
envp[envcount++] = US"SHELL=/bin/sh";
638
envp[envcount++] = US"SHELL=/bin/sh";
661
639
662
if (addr->host_list != NULL)
640
if (addr->host_list)
663
  envp[envcount++] = string_sprintf("HOST=%s", addr->host_list->name);
641
  envp[envcount++] = string_sprintf("HOST=%s", addr->host_list->name);
664
642
665
if (f.timestamps_utc) envp[envcount++] = US"TZ=UTC";
643
if (f.timestamps_utc)
666
else if (timezone_string != NULL && timezone_string[0] != 0)
644
  envp[envcount++] = US"TZ=UTC";
645
else if (timezone_string && timezone_string[0])
667
  envp[envcount++] = string_sprintf("TZ=%s", timezone_string);
646
  envp[envcount++] = string_sprintf("TZ=%s", timezone_string);
668
647
669
/* Add any requested items */
648
/* Add any requested items */
(-)exim.orig/src/transports/queuefile.c (-1 / +5 lines)
Lines 4-10 Link Here
4
4
5
/* Copyright (c) Andrew Colin Kissa <andrew@topdog.za.net> 2016 */
5
/* Copyright (c) Andrew Colin Kissa <andrew@topdog.za.net> 2016 */
6
/* Copyright (c) University of Cambridge 2016 */
6
/* Copyright (c) University of Cambridge 2016 */
7
/* Copyright (c) The Exim Maintainers 1995 - 2020 */
7
/* Copyright (c) The Exim Maintainers 1995 - 2021 */
8
/* See the file NOTICE for conditions of use and distribution. */
8
/* See the file NOTICE for conditions of use and distribution. */
9
9
10
10
Lines 14-19 Link Here
14
#ifdef EXPERIMENTAL_QUEUEFILE	/* whole file */
14
#ifdef EXPERIMENTAL_QUEUEFILE	/* whole file */
15
#include "queuefile.h"
15
#include "queuefile.h"
16
16
17
#ifndef EXIM_HAVE_OPENAT
18
# error queuefile transport reqires openat() support
19
#endif
20
17
/* Options specific to the appendfile transport. They must be in alphabetic
21
/* Options specific to the appendfile transport. They must be in alphabetic
18
order (note that "_" comes before the lower case letters). Some of them are
22
order (note that "_" comes before the lower case letters). Some of them are
19
stored in the publicly visible instance block - these are flagged with the
23
stored in the publicly visible instance block - these are flagged with the
(-)exim.orig/src/transports/smtp.c (-468 / +899 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#include "../exim.h"
9
#include "../exim.h"
Lines 43-49 Link Here
43
  { "dane_require_tls_ciphers", opt_stringptr, LOFF(dane_require_tls_ciphers) },
43
  { "dane_require_tls_ciphers", opt_stringptr, LOFF(dane_require_tls_ciphers) },
44
# endif
44
# endif
45
  { "data_timeout",         opt_time,	   LOFF(data_timeout) },
45
  { "data_timeout",         opt_time,	   LOFF(data_timeout) },
46
  { "delay_after_cutoff", opt_bool,	   LOFF(delay_after_cutoff) },
46
  { "delay_after_cutoff",   opt_bool,	   LOFF(delay_after_cutoff) },
47
#ifndef DISABLE_DKIM
47
#ifndef DISABLE_DKIM
48
  { "dkim_canon", opt_stringptr,	   LOFF(dkim.dkim_canon) },
48
  { "dkim_canon", opt_stringptr,	   LOFF(dkim.dkim_canon) },
49
  { "dkim_domain", opt_stringptr,	   LOFF(dkim.dkim_domain) },
49
  { "dkim_domain", opt_stringptr,	   LOFF(dkim.dkim_domain) },
Lines 64-69 Link Here
64
  { "final_timeout",        opt_time,	   LOFF(final_timeout) },
64
  { "final_timeout",        opt_time,	   LOFF(final_timeout) },
65
  { "gethostbyname",        opt_bool,	   LOFF(gethostbyname) },
65
  { "gethostbyname",        opt_bool,	   LOFF(gethostbyname) },
66
  { "helo_data",            opt_stringptr, LOFF(helo_data) },
66
  { "helo_data",            opt_stringptr, LOFF(helo_data) },
67
#if !defined(DISABLE_TLS) && !defined(DISABLE_TLS_RESUME)
68
  { "host_name_extract",    opt_stringptr, LOFF(host_name_extract) },
69
# endif
67
  { "hosts",                opt_stringptr, LOFF(hosts) },
70
  { "hosts",                opt_stringptr, LOFF(hosts) },
68
  { "hosts_avoid_esmtp",    opt_stringptr, LOFF(hosts_avoid_esmtp) },
71
  { "hosts_avoid_esmtp",    opt_stringptr, LOFF(hosts_avoid_esmtp) },
69
  { "hosts_avoid_pipelining", opt_stringptr, LOFF(hosts_avoid_pipelining) },
72
  { "hosts_avoid_pipelining", opt_stringptr, LOFF(hosts_avoid_pipelining) },
Lines 84-89 Link Here
84
#if !defined(DISABLE_TLS) && !defined(DISABLE_OCSP)
87
#if !defined(DISABLE_TLS) && !defined(DISABLE_OCSP)
85
  { "hosts_request_ocsp",   opt_stringptr, LOFF(hosts_request_ocsp) },
88
  { "hosts_request_ocsp",   opt_stringptr, LOFF(hosts_request_ocsp) },
86
#endif
89
#endif
90
  { "hosts_require_alpn",   opt_stringptr, LOFF(hosts_require_alpn) },
87
  { "hosts_require_auth",   opt_stringptr, LOFF(hosts_require_auth) },
91
  { "hosts_require_auth",   opt_stringptr, LOFF(hosts_require_auth) },
88
#ifndef DISABLE_TLS
92
#ifndef DISABLE_TLS
89
# ifdef SUPPORT_DANE
93
# ifdef SUPPORT_DANE
Lines 111-116 Link Here
111
  { "lmtp_ignore_quota",    opt_bool,	   LOFF(lmtp_ignore_quota) },
115
  { "lmtp_ignore_quota",    opt_bool,	   LOFF(lmtp_ignore_quota) },
112
  { "max_rcpt",             opt_int | opt_public,
116
  { "max_rcpt",             opt_int | opt_public,
113
      OPT_OFF(transport_instance, max_addresses) },
117
      OPT_OFF(transport_instance, max_addresses) },
118
  { "message_linelength_limit", opt_int,   LOFF(message_linelength_limit) },
114
  { "multi_domain",         opt_expand_bool | opt_public,
119
  { "multi_domain",         opt_expand_bool | opt_public,
115
      OPT_OFF(transport_instance, multi_domain) },
120
      OPT_OFF(transport_instance, multi_domain) },
116
  { "port",                 opt_stringptr, LOFF(port) },
121
  { "port",                 opt_stringptr, LOFF(port) },
Lines 122-133 Link Here
122
  { "socks_proxy",          opt_stringptr, LOFF(socks_proxy) },
127
  { "socks_proxy",          opt_stringptr, LOFF(socks_proxy) },
123
#endif
128
#endif
124
#ifndef DISABLE_TLS
129
#ifndef DISABLE_TLS
130
  { "tls_alpn",             opt_stringptr, LOFF(tls_alpn) },
125
  { "tls_certificate",      opt_stringptr, LOFF(tls_certificate) },
131
  { "tls_certificate",      opt_stringptr, LOFF(tls_certificate) },
126
  { "tls_crl",              opt_stringptr, LOFF(tls_crl) },
132
  { "tls_crl",              opt_stringptr, LOFF(tls_crl) },
127
  { "tls_dh_min_bits",      opt_int,	   LOFF(tls_dh_min_bits) },
133
  { "tls_dh_min_bits",      opt_int,	   LOFF(tls_dh_min_bits) },
128
  { "tls_privatekey",       opt_stringptr, LOFF(tls_privatekey) },
134
  { "tls_privatekey",       opt_stringptr, LOFF(tls_privatekey) },
129
  { "tls_require_ciphers",  opt_stringptr, LOFF(tls_require_ciphers) },
135
  { "tls_require_ciphers",  opt_stringptr, LOFF(tls_require_ciphers) },
130
# ifdef EXPERIMENTAL_TLS_RESUME
136
# ifndef DISABLE_TLS_RESUME
131
  { "tls_resumption_hosts", opt_stringptr, LOFF(tls_resumption_hosts) },
137
  { "tls_resumption_hosts", opt_stringptr, LOFF(tls_resumption_hosts) },
132
# endif
138
# endif
133
  { "tls_sni",              opt_stringptr, LOFF(tls_sni) },
139
  { "tls_sni",              opt_stringptr, LOFF(tls_sni) },
Lines 162-184 Link Here
162
/* Default private options block for the smtp transport. */
168
/* Default private options block for the smtp transport. */
163
169
164
smtp_transport_options_block smtp_transport_option_defaults = {
170
smtp_transport_options_block smtp_transport_option_defaults = {
165
  .hosts =			NULL,
171
  /* All non-mentioned elements 0/NULL/FALSE */
166
  .fallback_hosts =		NULL,
167
  .hostlist =			NULL,
168
  .fallback_hostlist =		NULL,
169
  .helo_data =			US"$primary_hostname",
172
  .helo_data =			US"$primary_hostname",
170
  .interface =			NULL,
171
  .port =			NULL,
172
  .protocol =			US"smtp",
173
  .protocol =			US"smtp",
173
  .dscp =			NULL,
174
  .serialize_hosts =		NULL,
175
  .hosts_try_auth =		NULL,
176
  .hosts_require_auth =		NULL,
177
  .hosts_try_chunking =		US"*",
174
  .hosts_try_chunking =		US"*",
178
#ifdef SUPPORT_DANE
175
#ifdef SUPPORT_DANE
179
  .hosts_try_dane =		US"*",
176
  .hosts_try_dane =		US"*",
180
  .hosts_require_dane =		NULL,
181
  .dane_require_tls_ciphers =	NULL,
182
#endif
177
#endif
183
  .hosts_try_fastopen =		US"*",
178
  .hosts_try_fastopen =		US"*",
184
#ifndef DISABLE_PRDR
179
#ifndef DISABLE_PRDR
Lines 186-204 Link Here
186
#endif
181
#endif
187
#ifndef DISABLE_OCSP
182
#ifndef DISABLE_OCSP
188
  .hosts_request_ocsp =		US"*",               /* hosts_request_ocsp (except under DANE; tls_client_start()) */
183
  .hosts_request_ocsp =		US"*",               /* hosts_request_ocsp (except under DANE; tls_client_start()) */
189
  .hosts_require_ocsp =		NULL,
190
#endif
191
  .hosts_require_tls =		NULL,
192
  .hosts_avoid_tls =		NULL,
193
  .hosts_verify_avoid_tls =	NULL,
194
  .hosts_avoid_pipelining =	NULL,
195
#ifndef DISABLE_PIPE_CONNECT
196
  .hosts_pipe_connect =		NULL,
197
#endif
198
  .hosts_avoid_esmtp =		NULL,
199
#ifndef DISABLE_TLS
200
  .hosts_nopass_tls =		NULL,
201
  .hosts_noproxy_tls =		NULL,
202
#endif
184
#endif
203
  .command_timeout =		5*60,
185
  .command_timeout =		5*60,
204
  .connect_timeout =		5*60,
186
  .connect_timeout =		5*60,
Lines 207-268 Link Here
207
  .size_addition =		1024,
189
  .size_addition =		1024,
208
  .hosts_max_try =		5,
190
  .hosts_max_try =		5,
209
  .hosts_max_try_hardlimit =	50,
191
  .hosts_max_try_hardlimit =	50,
192
  .message_linelength_limit =	998,
210
  .address_retry_include_sender = TRUE,
193
  .address_retry_include_sender = TRUE,
211
  .allow_localhost =		FALSE,
212
  .authenticated_sender_force =	FALSE,
213
  .gethostbyname =		FALSE,
214
  .dns_qualify_single =		TRUE,
194
  .dns_qualify_single =		TRUE,
215
  .dns_search_parents =		FALSE,
216
  .dnssec = { .request= US"*", .require=NULL },
195
  .dnssec = { .request= US"*", .require=NULL },
217
  .delay_after_cutoff =		TRUE,
196
  .delay_after_cutoff =		TRUE,
218
  .hosts_override =		FALSE,
219
  .hosts_randomize =		FALSE,
220
  .keepalive =			TRUE,
197
  .keepalive =			TRUE,
221
  .lmtp_ignore_quota =		FALSE,
222
  .expand_retry_include_ip_address =	NULL,
223
  .retry_include_ip_address =	TRUE,
198
  .retry_include_ip_address =	TRUE,
224
#ifdef SUPPORT_SOCKS
225
  .socks_proxy =		NULL,
226
#endif
227
#ifndef DISABLE_TLS
199
#ifndef DISABLE_TLS
228
  .tls_certificate =		NULL,
229
  .tls_crl =			NULL,
230
  .tls_privatekey =		NULL,
231
  .tls_require_ciphers =	NULL,
232
  .tls_sni =			NULL,
233
  .tls_verify_certificates =	US"system",
200
  .tls_verify_certificates =	US"system",
234
  .tls_dh_min_bits =		EXIM_CLIENT_DH_DEFAULT_MIN_BITS,
201
  .tls_dh_min_bits =		EXIM_CLIENT_DH_DEFAULT_MIN_BITS,
235
  .tls_tempfail_tryclear =	TRUE,
202
  .tls_tempfail_tryclear =	TRUE,
236
# ifdef EXPERIMENTAL_TLS_RESUME
237
  .tls_resumption_hosts =	NULL,
238
# endif
239
  .tls_verify_hosts =		NULL,
240
  .tls_try_verify_hosts =	US"*",
203
  .tls_try_verify_hosts =	US"*",
241
  .tls_verify_cert_hostnames =	US"*",
204
  .tls_verify_cert_hostnames =	US"*",
205
# ifndef DISABLE_TLS_RESUME
206
  .host_name_extract =		US"${if and {{match{$host}{.outlook.com\\$}} {match{$item}{\\N^250-([\\w.]+)\\s\\N}}} {$1}}",
207
# endif
242
#endif
208
#endif
243
#ifdef SUPPORT_I18N
209
#ifdef SUPPORT_I18N
244
  .utf8_downconvert =		US"-1",
210
  .utf8_downconvert =		US"-1",
245
#endif
211
#endif
246
#ifndef DISABLE_DKIM
212
#ifndef DISABLE_DKIM
247
 .dkim =
213
 .dkim =
248
   {.dkim_domain =		NULL,
214
   { .dkim_hash =		US"sha256", },
249
    .dkim_identity =		NULL,
250
    .dkim_private_key =		NULL,
251
    .dkim_selector =		NULL,
252
    .dkim_canon =		NULL,
253
    .dkim_sign_headers =	NULL,
254
    .dkim_strict =		NULL,
255
    .dkim_hash =		US"sha256",
256
    .dkim_timestamps =		NULL,
257
    .dot_stuffed =		FALSE,
258
    .force_bodyhash =		FALSE,
259
# ifdef EXPERIMENTAL_ARC
260
    .arc_signspec =		NULL,
261
# endif
262
    },
263
# ifdef EXPERIMENTAL_ARC
264
  .arc_sign =			NULL,
265
# endif
266
#endif
215
#endif
267
};
216
};
268
217
Lines 294-336 Link Here
294
void
243
void
295
smtp_deliver_init(void)
244
smtp_deliver_init(void)
296
{
245
{
297
if (!regex_PIPELINING) regex_PIPELINING =
246
struct list
298
  regex_must_compile(US"\\n250[\\s\\-]PIPELINING(\\s|\\n|$)", FALSE, TRUE);
247
  {
299
248
  const pcre2_code **	re;
300
if (!regex_SIZE) regex_SIZE =
249
  const uschar *	string;
301
  regex_must_compile(US"\\n250[\\s\\-]SIZE(\\s|\\n|$)", FALSE, TRUE);
250
  } list[] =
302
251
  {
303
if (!regex_AUTH) regex_AUTH =
252
    { &regex_AUTH,		AUTHS_REGEX },
304
  regex_must_compile(AUTHS_REGEX, FALSE, TRUE);
253
    { &regex_CHUNKING,		US"\\n250[\\s\\-]CHUNKING(\\s|\\n|$)" },
254
    { &regex_DSN,		US"\\n250[\\s\\-]DSN(\\s|\\n|$)" },
255
    { &regex_IGNOREQUOTA,	US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)" },
256
    { &regex_PIPELINING,	US"\\n250[\\s\\-]PIPELINING(\\s|\\n|$)" },
257
    { &regex_SIZE,		US"\\n250[\\s\\-]SIZE(\\s|\\n|$)" },
305
258
306
#ifndef DISABLE_TLS
259
#ifndef DISABLE_TLS
307
if (!regex_STARTTLS) regex_STARTTLS =
260
    { &regex_STARTTLS,		US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)" },
308
  regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE);
309
#endif
261
#endif
310
311
if (!regex_CHUNKING) regex_CHUNKING =
312
  regex_must_compile(US"\\n250[\\s\\-]CHUNKING(\\s|\\n|$)", FALSE, TRUE);
313
314
#ifndef DISABLE_PRDR
262
#ifndef DISABLE_PRDR
315
if (!regex_PRDR) regex_PRDR =
263
    { &regex_PRDR,		US"\\n250[\\s\\-]PRDR(\\s|\\n|$)" },
316
  regex_must_compile(US"\\n250[\\s\\-]PRDR(\\s|\\n|$)", FALSE, TRUE);
317
#endif
264
#endif
318
319
#ifdef SUPPORT_I18N
265
#ifdef SUPPORT_I18N
320
if (!regex_UTF8) regex_UTF8 =
266
    { &regex_UTF8,		US"\\n250[\\s\\-]SMTPUTF8(\\s|\\n|$)" },
321
  regex_must_compile(US"\\n250[\\s\\-]SMTPUTF8(\\s|\\n|$)", FALSE, TRUE);
322
#endif
267
#endif
323
324
if (!regex_DSN) regex_DSN  =
325
  regex_must_compile(US"\\n250[\\s\\-]DSN(\\s|\\n|$)", FALSE, TRUE);
326
327
if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA =
328
  regex_must_compile(US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)", FALSE, TRUE);
329
330
#ifndef DISABLE_PIPE_CONNECT
268
#ifndef DISABLE_PIPE_CONNECT
331
if (!regex_EARLY_PIPE) regex_EARLY_PIPE =
269
    { &regex_EARLY_PIPE,  	US"\\n250[\\s\\-]" EARLY_PIPE_FEATURE_NAME "(\\s|\\n|$)" },
332
  regex_must_compile(US"\\n250[\\s\\-]" EARLY_PIPE_FEATURE_NAME "(\\s|\\n|$)", FALSE, TRUE);
270
#endif
271
#ifdef EXPERIMENTAL_ESMTP_LIMITS
272
    { &regex_LIMITS,		US"\\n250[\\s\\-]LIMITS\\s" },
333
#endif
273
#endif
274
  };
275
276
for (struct list * l = list; l < list + nelem(list); l++)
277
  if (!*l->re)
278
    *l->re = regex_must_compile(l->string, FALSE, TRUE);
334
}
279
}
335
280
336
281
Lines 362-371 Link Here
362
{
307
{
363
smtp_transport_options_block *ob = SOB tblock->options_block;
308
smtp_transport_options_block *ob = SOB tblock->options_block;
364
309
365
errmsg = errmsg;    /* Keep picky compilers happy */
366
uid = uid;
367
gid = gid;
368
369
/* Pass back options if required. This interface is getting very messy. */
310
/* Pass back options if required. This interface is getting very messy. */
370
311
371
if (tf)
312
if (tf)
Lines 411-416 Link Here
411
smtp_transport_init(transport_instance *tblock)
352
smtp_transport_init(transport_instance *tblock)
412
{
353
{
413
smtp_transport_options_block *ob = SOB tblock->options_block;
354
smtp_transport_options_block *ob = SOB tblock->options_block;
355
int old_pool = store_pool;
414
356
415
/* Retry_use_local_part defaults FALSE if unset */
357
/* Retry_use_local_part defaults FALSE if unset */
416
358
Lines 441-452 Link Here
441
/* If hosts_override is set and there are local hosts, set the global
383
/* If hosts_override is set and there are local hosts, set the global
442
flag that stops verify from showing router hosts. */
384
flag that stops verify from showing router hosts. */
443
385
444
if (ob->hosts_override && ob->hosts != NULL) tblock->overrides_hosts = TRUE;
386
if (ob->hosts_override && ob->hosts) tblock->overrides_hosts = TRUE;
445
387
446
/* If there are any fallback hosts listed, build a chain of host items
388
/* If there are any fallback hosts listed, build a chain of host items
447
for them, but do not do any lookups at this time. */
389
for them, but do not do any lookups at this time. */
448
390
449
host_build_hostlist(&(ob->fallback_hostlist), ob->fallback_hosts, FALSE);
391
store_pool = POOL_PERM;
392
host_build_hostlist(&ob->fallback_hostlist, ob->fallback_hosts, FALSE);
393
store_pool = old_pool;
450
}
394
}
451
395
452
396
Lines 740-746 Link Here
740
	: string_copy(addr->message)
684
	: string_copy(addr->message)
741
      : addr->basic_errno > 0
685
      : addr->basic_errno > 0
742
	? string_copy(US strerror(addr->basic_errno))
686
	? string_copy(US strerror(addr->basic_errno))
743
	: NULL);
687
	: NULL,
688
      NULL);
744
689
745
deliver_localpart = save_local;
690
deliver_localpart = save_local;
746
deliver_domain =    save_domain;
691
deliver_domain =    save_domain;
Lines 773-779 Link Here
773
static BOOL
718
static BOOL
774
smtp_reap_banner(smtp_context * sx)
719
smtp_reap_banner(smtp_context * sx)
775
{
720
{
776
BOOL good_response = smtp_read_response(sx, sx->buffer, sizeof(sx->buffer),
721
BOOL good_response;
722
#if defined(__linux__) && defined(TCP_QUICKACK)
723
  {	/* Hack to get QUICKACK disabled; has to be right after 3whs, and has to on->off */
724
  int sock = sx->cctx.sock;
725
  struct pollfd p = {.fd = sock, .events = POLLOUT};
726
  if (poll(&p, 1, 1000) >= 0)	/* retval test solely for compiler quitening */
727
    {
728
    (void) setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, US &on, sizeof(on));
729
    (void) setsockopt(sock, IPPROTO_TCP, TCP_QUICKACK, US &off, sizeof(off));
730
    }
731
  }
732
#endif
733
good_response = smtp_read_response(sx, sx->buffer, sizeof(sx->buffer),
777
  '2', (SOB sx->conn_args.ob)->command_timeout);
734
  '2', (SOB sx->conn_args.ob)->command_timeout);
778
#ifdef EXPERIMENTAL_DSN_INFO
735
#ifdef EXPERIMENTAL_DSN_INFO
779
sx->smtp_greeting = string_copy(sx->buffer);
736
sx->smtp_greeting = string_copy(sx->buffer);
Lines 801-812 Link Here
801
#endif
758
#endif
802
#ifndef DISABLE_EVENT
759
#ifndef DISABLE_EVENT
803
(void) event_raise(sx->conn_args.tblock->event_action,
760
(void) event_raise(sx->conn_args.tblock->event_action,
804
  US"smtp:ehlo", sx->buffer);
761
  US"smtp:ehlo", sx->buffer, NULL);
805
#endif
762
#endif
806
return TRUE;
763
return TRUE;
807
}
764
}
808
765
809
766
767
/* Grab a string differentiating server behind a loadbalancer, for TLS
768
resumption when such servers do not share a session-cache */
769
770
static void
771
ehlo_response_lbserver(smtp_context * sx, smtp_transport_options_block * ob)
772
{
773
#if !defined(DISABLE_TLS) && !defined(DISABLE_TLS_RESUME)
774
const uschar * s;
775
uschar * save_item = iterate_item;
776
777
if (sx->conn_args.have_lbserver)
778
  return;
779
iterate_item = sx->buffer;
780
s = expand_cstring(ob->host_name_extract);
781
iterate_item = save_item;
782
sx->conn_args.host_lbserver = s && !*s ? NULL : s;
783
sx->conn_args.have_lbserver = TRUE;
784
#endif
785
}
786
787
788
789
/******************************************************************************/
790
791
#ifdef EXPERIMENTAL_ESMTP_LIMITS
792
/* If TLS, or TLS not offered, called with the EHLO response in the buffer.
793
Check it for a LIMITS keyword and parse values into the smtp context structure.
794
795
We don't bother with peers that we won't talk TLS to, even though they can,
796
just ignore their LIMITS advice (if any) and treat them as if they do not.
797
This saves us dealing with a duplicate set of values. */
798
799
static void
800
ehlo_response_limits_read(smtp_context * sx)
801
{
802
uschar * match;
803
804
/* matches up to just after the first space after the keyword */
805
806
if (regex_match(regex_LIMITS, sx->buffer, -1, &match))
807
  for (const uschar * s = sx->buffer + Ustrlen(match); *s; )
808
    {
809
    while (isspace(*s)) s++;
810
    if (*s == '\n') break;
811
812
    if (strncmpic(s, US"MAILMAX=", 8) == 0)
813
      {
814
      sx->peer_limit_mail = atoi(CS (s += 8));
815
      while (isdigit(*s)) s++;
816
      }
817
    else if (strncmpic(s, US"RCPTMAX=", 8) == 0)
818
      {
819
      sx->peer_limit_rcpt = atoi(CS (s += 8));
820
      while (isdigit(*s)) s++;
821
      }
822
    else if (strncmpic(s, US"RCPTDOMAINMAX=", 14) == 0)
823
      {
824
      sx->peer_limit_rcptdom = atoi(CS (s += 14));
825
      while (isdigit(*s)) s++;
826
      }
827
    else
828
      while (*s && !isspace(*s)) s++;
829
    }
830
}
831
832
/* Apply given values to the current connection */
833
static void
834
ehlo_limits_apply(smtp_context * sx,
835
  unsigned limit_mail, unsigned limit_rcpt, unsigned limit_rcptdom)
836
{
837
if (limit_mail && limit_mail < sx->max_mail) sx->max_mail = limit_mail;
838
if (limit_rcpt && limit_rcpt < sx->max_rcpt) sx->max_rcpt = limit_rcpt;
839
if (limit_rcptdom)
840
  {
841
  DEBUG(D_transport) debug_printf("will treat as !multi_domain\n");
842
  sx->single_rcpt_domain = TRUE;
843
  }
844
}
845
846
/* Apply values from EHLO-resp to the current connection */
847
static void
848
ehlo_response_limits_apply(smtp_context * sx)
849
{
850
ehlo_limits_apply(sx, sx->peer_limit_mail, sx->peer_limit_rcpt,
851
  sx->peer_limit_rcptdom);
852
}
853
854
/* Apply values read from cache to the current connection */
855
static void
856
ehlo_cache_limits_apply(smtp_context * sx)
857
{
858
# ifndef DISABLE_PIPE_CONNECT
859
ehlo_limits_apply(sx, sx->ehlo_resp.limit_mail, sx->ehlo_resp.limit_rcpt,
860
  sx->ehlo_resp.limit_rcptdom);
861
# endif
862
}
863
#endif	/*EXPERIMENTAL_ESMTP_LIMITS*/
864
865
/******************************************************************************/
810
866
811
#ifndef DISABLE_PIPE_CONNECT
867
#ifndef DISABLE_PIPE_CONNECT
812
static uschar *
868
static uschar *
Lines 820-838 Link Here
820
    host->port == PORT_NONE ? sx->port : host->port);
876
    host->port == PORT_NONE ? sx->port : host->port);
821
}
877
}
822
878
879
/* Cache EHLO-response info for use by early-pipe.
880
Called
881
- During a normal flow on EHLO response (either cleartext or under TLS),
882
  when we are willing to do PIPECONNECT and it is offered
883
- During an early-pipe flow on receiving the actual EHLO response and noting
884
  disparity versus the cached info used, when PIPECONNECT is still being offered
885
886
We assume that suitable values have been set in the sx.ehlo_resp structure for
887
features and auths; we handle the copy of limits. */
888
823
static void
889
static void
824
write_ehlo_cache_entry(const smtp_context * sx)
890
write_ehlo_cache_entry(smtp_context * sx)
825
{
891
{
826
open_db dbblock, * dbm_file;
892
open_db dbblock, * dbm_file;
827
893
894
# ifdef EXPERIMENTAL_ESMTP_LIMITS
895
sx->ehlo_resp.limit_mail = sx->peer_limit_mail;
896
sx->ehlo_resp.limit_rcpt = sx->peer_limit_rcpt;
897
sx->ehlo_resp.limit_rcptdom = sx->peer_limit_rcptdom;
898
# endif
899
828
if ((dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE)))
900
if ((dbm_file = dbfn_open(US"misc", O_RDWR, &dbblock, TRUE, TRUE)))
829
  {
901
  {
830
  uschar * ehlo_resp_key = ehlo_cache_key(sx);
902
  uschar * ehlo_resp_key = ehlo_cache_key(sx);
831
  dbdata_ehlo_resp er = { .data = sx->ehlo_resp };
903
  dbdata_ehlo_resp er = { .data = sx->ehlo_resp };
832
904
833
  HDEBUG(D_transport) debug_printf("writing clr %04x/%04x cry %04x/%04x\n",
905
  HDEBUG(D_transport)
834
    sx->ehlo_resp.cleartext_features, sx->ehlo_resp.cleartext_auths,
906
# ifdef EXPERIMENTAL_ESMTP_LIMITS
835
    sx->ehlo_resp.crypted_features, sx->ehlo_resp.crypted_auths);
907
    if (sx->ehlo_resp.limit_mail || sx->ehlo_resp.limit_rcpt || sx->ehlo_resp.limit_rcptdom)
908
      debug_printf("writing clr %04x/%04x cry %04x/%04x lim %05d/%05d/%05d\n",
909
	sx->ehlo_resp.cleartext_features, sx->ehlo_resp.cleartext_auths,
910
	sx->ehlo_resp.crypted_features, sx->ehlo_resp.crypted_auths,
911
	sx->ehlo_resp.limit_mail, sx->ehlo_resp.limit_rcpt,
912
	sx->ehlo_resp.limit_rcptdom);
913
    else
914
# endif
915
      debug_printf("writing clr %04x/%04x cry %04x/%04x\n",
916
	sx->ehlo_resp.cleartext_features, sx->ehlo_resp.cleartext_auths,
917
	sx->ehlo_resp.crypted_features, sx->ehlo_resp.crypted_auths);
836
918
837
  dbfn_write(dbm_file, ehlo_resp_key, &er, (int)sizeof(er));
919
  dbfn_write(dbm_file, ehlo_resp_key, &er, (int)sizeof(er));
838
  dbfn_close(dbm_file);
920
  dbfn_close(dbm_file);
Lines 866-872 Link Here
866
  uschar * ehlo_resp_key = ehlo_cache_key(sx);
948
  uschar * ehlo_resp_key = ehlo_cache_key(sx);
867
  dbdata_ehlo_resp * er;
949
  dbdata_ehlo_resp * er;
868
950
869
  if (!(er = dbfn_read(dbm_file, ehlo_resp_key)))
951
  if (!(er = dbfn_read_enforce_length(dbm_file, ehlo_resp_key, sizeof(dbdata_ehlo_resp))))
870
    { DEBUG(D_transport) debug_printf("no ehlo-resp record\n"); }
952
    { DEBUG(D_transport) debug_printf("no ehlo-resp record\n"); }
871
  else if (time(NULL) - er->time_stamp > retry_data_expire)
953
  else if (time(NULL) - er->time_stamp > retry_data_expire)
872
    {
954
    {
Lines 877-888 Link Here
877
    }
959
    }
878
  else
960
  else
879
    {
961
    {
962
    DEBUG(D_transport)
963
# ifdef EXPERIMENTAL_ESMTP_LIMITS
964
      if (er->data.limit_mail || er->data.limit_rcpt || er->data.limit_rcptdom)
965
	debug_printf("EHLO response bits from cache:"
966
	  " cleartext 0x%04x/0x%04x crypted 0x%04x/0x%04x lim %05d/%05d/%05d\n",
967
	  er->data.cleartext_features, er->data.cleartext_auths,
968
	  er->data.crypted_features, er->data.crypted_auths,
969
	  er->data.limit_mail, er->data.limit_rcpt, er->data.limit_rcptdom);
970
      else
971
# endif
972
	debug_printf("EHLO response bits from cache:"
973
	  " cleartext 0x%04x/0x%04x crypted 0x%04x/0x%04x\n",
974
	  er->data.cleartext_features, er->data.cleartext_auths,
975
	  er->data.crypted_features, er->data.crypted_auths);
976
880
    sx->ehlo_resp = er->data;
977
    sx->ehlo_resp = er->data;
978
# ifdef EXPERIMENTAL_ESMTP_LIMITS
979
    ehlo_cache_limits_apply(sx);
980
# endif
881
    dbfn_close(dbm_file);
981
    dbfn_close(dbm_file);
882
    DEBUG(D_transport) debug_printf(
883
	"EHLO response bits from cache: cleartext 0x%04x/0x%04x crypted 0x%04x/0x%04x\n",
884
	er->data.cleartext_features, er->data.cleartext_auths,
885
	er->data.crypted_features, er->data.crypted_auths);
886
    return TRUE;
982
    return TRUE;
887
    }
983
    }
888
  dbfn_close(dbm_file);
984
  dbfn_close(dbm_file);
Lines 968-973 Link Here
968
    if (tls_out.active.sock >= 0) rc = DEFER;
1064
    if (tls_out.active.sock >= 0) rc = DEFER;
969
    goto fail;
1065
    goto fail;
970
    }
1066
    }
1067
  /*XXX EXPERIMENTAL_ESMTP_LIMITS ? */
1068
  ehlo_response_lbserver(sx, sx->conn_args.ob);
971
  }
1069
  }
972
1070
973
if (pending_EHLO)
1071
if (pending_EHLO)
Lines 984-991 Link Here
984
    goto fail;
1082
    goto fail;
985
    }
1083
    }
986
1084
987
  /* Compare the actual EHLO response to the cached value we assumed;
1085
  /* Compare the actual EHLO response extensions and AUTH methods to the cached
988
  on difference, dump or rewrite the cache and arrange for a retry. */
1086
  value we assumed; on difference, dump or rewrite the cache and arrange for a
1087
  retry. */
989
1088
990
  ap = tls_out.active.sock < 0
1089
  ap = tls_out.active.sock < 0
991
      ? &sx->ehlo_resp.cleartext_auths : &sx->ehlo_resp.crypted_auths;
1090
      ? &sx->ehlo_resp.cleartext_auths : &sx->ehlo_resp.crypted_auths;
Lines 995-1000 Link Here
995
	| OPTION_CHUNKING | OPTION_PRDR | OPTION_DSN | OPTION_PIPE | OPTION_SIZE
1094
	| OPTION_CHUNKING | OPTION_PRDR | OPTION_DSN | OPTION_PIPE | OPTION_SIZE
996
	| OPTION_UTF8 | OPTION_EARLY_PIPE
1095
	| OPTION_UTF8 | OPTION_EARLY_PIPE
997
	);
1096
	);
1097
# ifdef EXPERIMENTAL_ESMTP_LIMITS
1098
  if (tls_out.active.sock >= 0 || !(peer_offered & OPTION_TLS))
1099
    ehlo_response_limits_read(sx);
1100
# endif
998
  if (  peer_offered != sx->peer_offered
1101
  if (  peer_offered != sx->peer_offered
999
     || (authbits = study_ehlo_auths(sx)) != *ap)
1102
     || (authbits = study_ehlo_auths(sx)) != *ap)
1000
    {
1103
    {
Lines 1002-1017 Link Here
1002
      debug_printf("EHLO %s extensions changed, 0x%04x/0x%04x -> 0x%04x/0x%04x\n",
1105
      debug_printf("EHLO %s extensions changed, 0x%04x/0x%04x -> 0x%04x/0x%04x\n",
1003
		    tls_out.active.sock < 0 ? "cleartext" : "crypted",
1106
		    tls_out.active.sock < 0 ? "cleartext" : "crypted",
1004
		    sx->peer_offered, *ap, peer_offered, authbits);
1107
		    sx->peer_offered, *ap, peer_offered, authbits);
1005
    *(tls_out.active.sock < 0
1006
      ? &sx->ehlo_resp.cleartext_features : &sx->ehlo_resp.crypted_features) = peer_offered;
1007
    *ap = authbits;
1008
    if (peer_offered & OPTION_EARLY_PIPE)
1108
    if (peer_offered & OPTION_EARLY_PIPE)
1109
      {
1110
      *(tls_out.active.sock < 0
1111
	? &sx->ehlo_resp.cleartext_features : &sx->ehlo_resp.crypted_features) =
1112
	  peer_offered;
1113
      *ap = authbits;
1009
      write_ehlo_cache_entry(sx);
1114
      write_ehlo_cache_entry(sx);
1115
      }
1010
    else
1116
    else
1011
      invalidate_ehlo_cache_entry(sx);
1117
      invalidate_ehlo_cache_entry(sx);
1012
1118
1013
    return OK;		/* just carry on */
1119
    return OK;		/* just carry on */
1014
    }
1120
    }
1121
# ifdef EXPERIMENTAL_ESMTP_LIMITS
1122
    /* If we are handling LIMITS, compare the actual EHLO LIMITS values with the
1123
    cached values and invalidate cache if different.  OK to carry on with
1124
    connect since values are advisory. */
1125
    {
1126
    if (  (tls_out.active.sock >= 0 || !(peer_offered & OPTION_TLS))
1127
       && (  sx->peer_limit_mail != sx->ehlo_resp.limit_mail
1128
          || sx->peer_limit_rcpt != sx->ehlo_resp.limit_rcpt
1129
          || sx->peer_limit_rcptdom != sx->ehlo_resp.limit_rcptdom
1130
       )  )
1131
      {
1132
      HDEBUG(D_transport)
1133
	{
1134
	debug_printf("EHLO LIMITS changed:");
1135
	if (sx->peer_limit_mail != sx->ehlo_resp.limit_mail)
1136
	  debug_printf(" MAILMAX %u -> %u\n", sx->ehlo_resp.limit_mail, sx->peer_limit_mail);
1137
	else if (sx->peer_limit_rcpt != sx->ehlo_resp.limit_rcpt)
1138
	  debug_printf(" RCPTMAX %u -> %u\n", sx->ehlo_resp.limit_rcpt, sx->peer_limit_rcpt);
1139
	else
1140
	  debug_printf(" RCPTDOMAINMAX %u -> %u\n", sx->ehlo_resp.limit_rcptdom, sx->peer_limit_rcptdom);
1141
	}
1142
      invalidate_ehlo_cache_entry(sx);
1143
      }
1144
    }
1145
# endif
1015
  }
1146
  }
1016
return OK;
1147
return OK;
1017
1148
Lines 1133-1139 Link Here
1133
  /* The address was accepted */
1264
  /* The address was accepted */
1134
  addr->host_used = sx->conn_args.host;
1265
  addr->host_used = sx->conn_args.host;
1135
1266
1136
  DEBUG(D_transport) debug_printf("%s expect rcpt\n", __FUNCTION__);
1267
  DEBUG(D_transport) debug_printf("%s expect rcpt for %s\n", __FUNCTION__, addr->address);
1137
  if (smtp_read_response(sx, sx->buffer, sizeof(sx->buffer),
1268
  if (smtp_read_response(sx, sx->buffer, sizeof(sx->buffer),
1138
			  '2', ob->command_timeout))
1269
			  '2', ob->command_timeout))
1139
    {
1270
    {
Lines 1334-1343 Link Here
1334
host_item * host = sx->conn_args.host;			/* host to deliver to */
1465
host_item * host = sx->conn_args.host;			/* host to deliver to */
1335
int rc;
1466
int rc;
1336
1467
1468
/* Set up globals for error messages */
1469
1470
authenticator_name = au->name;
1471
driver_srcfile = au->srcfile;
1472
driver_srcline = au->srcline;
1473
1337
sx->outblock.authenticating = TRUE;
1474
sx->outblock.authenticating = TRUE;
1338
rc = (au->info->clientcode)(au, sx, ob->command_timeout,
1475
rc = (au->info->clientcode)(au, sx, ob->command_timeout,
1339
			    sx->buffer, sizeof(sx->buffer));
1476
			    sx->buffer, sizeof(sx->buffer));
1340
sx->outblock.authenticating = FALSE;
1477
sx->outblock.authenticating = FALSE;
1478
driver_srcfile = authenticator_name = NULL; driver_srcline = 0;
1341
DEBUG(D_transport) debug_printf("%s authenticator yielded %d\n", au->name, rc);
1479
DEBUG(D_transport) debug_printf("%s authenticator yielded %d\n", au->name, rc);
1342
1480
1343
/* A temporary authentication failure must hold up delivery to
1481
/* A temporary authentication failure must hold up delivery to
Lines 1688-1695 Link Here
1688
current_local_identity =
1826
current_local_identity =
1689
  smtp_local_identity(s_compare->current_sender_address, s_compare->tblock);
1827
  smtp_local_identity(s_compare->current_sender_address, s_compare->tblock);
1690
1828
1691
if (!(new_sender_address = deliver_get_sender_address(message_id)))
1829
if (!(new_sender_address = spool_sender_from_msgid(message_id)))
1692
    return FALSE;
1830
  return FALSE;
1831
1693
1832
1694
message_local_identity =
1833
message_local_identity =
1695
  smtp_local_identity(new_sender_address, s_compare->tblock);
1834
  smtp_local_identity(new_sender_address, s_compare->tblock);
Lines 1702-1758 Link Here
1702
static unsigned
1841
static unsigned
1703
ehlo_response(uschar * buf, unsigned checks)
1842
ehlo_response(uschar * buf, unsigned checks)
1704
{
1843
{
1705
size_t bsize = Ustrlen(buf);
1844
PCRE2_SIZE bsize = Ustrlen(buf);
1845
pcre2_match_data * md = pcre2_match_data_create(1, pcre_gen_ctx);
1706
1846
1707
/* debug_printf("%s: check for 0x%04x\n", __FUNCTION__, checks); */
1847
/* debug_printf("%s: check for 0x%04x\n", __FUNCTION__, checks); */
1708
1848
1709
#ifndef DISABLE_TLS
1849
#ifndef DISABLE_TLS
1710
if (  checks & OPTION_TLS
1850
if (  checks & OPTION_TLS
1711
   && pcre_exec(regex_STARTTLS, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
1851
   && pcre2_match(regex_STARTTLS,
1852
		  (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_mtc_ctx) < 0)
1712
#endif
1853
#endif
1713
  checks &= ~OPTION_TLS;
1854
  checks &= ~OPTION_TLS;
1714
1855
1715
if (  checks & OPTION_IGNQ
1856
if (  checks & OPTION_IGNQ
1716
   && pcre_exec(regex_IGNOREQUOTA, NULL, CS buf, bsize, 0,
1857
   && pcre2_match(regex_IGNOREQUOTA,
1717
		PCRE_EOPT, NULL, 0) < 0)
1858
		  (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_mtc_ctx) < 0)
1718
  checks &= ~OPTION_IGNQ;
1859
  checks &= ~OPTION_IGNQ;
1719
1860
1720
if (  checks & OPTION_CHUNKING
1861
if (  checks & OPTION_CHUNKING
1721
   && pcre_exec(regex_CHUNKING, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
1862
   && pcre2_match(regex_CHUNKING,
1863
		  (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_mtc_ctx) < 0)
1722
  checks &= ~OPTION_CHUNKING;
1864
  checks &= ~OPTION_CHUNKING;
1723
1865
1724
#ifndef DISABLE_PRDR
1866
#ifndef DISABLE_PRDR
1725
if (  checks & OPTION_PRDR
1867
if (  checks & OPTION_PRDR
1726
   && pcre_exec(regex_PRDR, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
1868
   && pcre2_match(regex_PRDR,
1869
		  (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_mtc_ctx) < 0)
1727
#endif
1870
#endif
1728
  checks &= ~OPTION_PRDR;
1871
  checks &= ~OPTION_PRDR;
1729
1872
1730
#ifdef SUPPORT_I18N
1873
#ifdef SUPPORT_I18N
1731
if (  checks & OPTION_UTF8
1874
if (  checks & OPTION_UTF8
1732
   && pcre_exec(regex_UTF8, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
1875
   && pcre2_match(regex_UTF8,
1876
		  (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_mtc_ctx) < 0)
1733
#endif
1877
#endif
1734
  checks &= ~OPTION_UTF8;
1878
  checks &= ~OPTION_UTF8;
1735
1879
1736
if (  checks & OPTION_DSN
1880
if (  checks & OPTION_DSN
1737
   && pcre_exec(regex_DSN, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
1881
   && pcre2_match(regex_DSN,
1882
		  (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_mtc_ctx) < 0)
1738
  checks &= ~OPTION_DSN;
1883
  checks &= ~OPTION_DSN;
1739
1884
1740
if (  checks & OPTION_PIPE
1885
if (  checks & OPTION_PIPE
1741
   && pcre_exec(regex_PIPELINING, NULL, CS buf, bsize, 0,
1886
   && pcre2_match(regex_PIPELINING,
1742
		PCRE_EOPT, NULL, 0) < 0)
1887
		  (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_mtc_ctx) < 0)
1743
  checks &= ~OPTION_PIPE;
1888
  checks &= ~OPTION_PIPE;
1744
1889
1745
if (  checks & OPTION_SIZE
1890
if (  checks & OPTION_SIZE
1746
   && pcre_exec(regex_SIZE, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
1891
   && pcre2_match(regex_SIZE,
1892
		  (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_mtc_ctx) < 0)
1747
  checks &= ~OPTION_SIZE;
1893
  checks &= ~OPTION_SIZE;
1748
1894
1749
#ifndef DISABLE_PIPE_CONNECT
1895
#ifndef DISABLE_PIPE_CONNECT
1750
if (  checks & OPTION_EARLY_PIPE
1896
if (  checks & OPTION_EARLY_PIPE
1751
   && pcre_exec(regex_EARLY_PIPE, NULL, CS buf, bsize, 0,
1897
   && pcre2_match(regex_EARLY_PIPE,
1752
		PCRE_EOPT, NULL, 0) < 0)
1898
		  (PCRE2_SPTR)buf, bsize, 0, PCRE_EOPT, md, pcre_mtc_ctx) < 0)
1753
#endif
1899
#endif
1754
  checks &= ~OPTION_EARLY_PIPE;
1900
  checks &= ~OPTION_EARLY_PIPE;
1755
1901
1902
pcre2_match_data_free(md);
1756
/* debug_printf("%s: found     0x%04x\n", __FUNCTION__, checks); */
1903
/* debug_printf("%s: found     0x%04x\n", __FUNCTION__, checks); */
1757
return checks;
1904
return checks;
1758
}
1905
}
Lines 1877-1882 Link Here
1877
2024
1878
2025
1879
2026
2027
#ifdef SUPPORT_DANE
2028
static int
2029
check_force_dane_conn(smtp_context * sx, smtp_transport_options_block * ob)
2030
{
2031
int rc;
2032
if(  sx->dane_required
2033
  || verify_check_given_host(CUSS &ob->hosts_try_dane, sx->conn_args.host) == OK
2034
  )
2035
  switch (rc = tlsa_lookup(sx->conn_args.host, &sx->conn_args.tlsa_dnsa, sx->dane_required))
2036
    {
2037
    case OK:		sx->conn_args.dane = TRUE;
2038
			ob->tls_tempfail_tryclear = FALSE;	/* force TLS */
2039
			ob->tls_sni = sx->conn_args.host->name; /* force SNI */
2040
			break;
2041
    case FAIL_FORCED:	break;
2042
    default:		set_errno_nohost(sx->addrlist, ERRNO_DNSDEFER,
2043
			    string_sprintf("DANE error: tlsa lookup %s",
2044
			      rc_to_string(rc)),
2045
			    rc, FALSE, &sx->delivery_start);
2046
# ifndef DISABLE_EVENT
2047
			(void) event_raise(sx->conn_args.tblock->event_action,
2048
			  US"dane:fail", sx->dane_required
2049
			    ?  US"dane-required" : US"dnssec-invalid",
2050
			  NULL);
2051
# endif
2052
			return rc;
2053
    }
2054
return OK;
2055
}
2056
#endif
1880
2057
1881
2058
1882
/*************************************************
2059
/*************************************************
Lines 1885-1891 Link Here
1885
2062
1886
/*
2063
/*
1887
Arguments:
2064
Arguments:
1888
  ctx		  connection context
2065
  sx		  connection context
1889
  suppress_tls    if TRUE, don't attempt a TLS connection - this is set for
2066
  suppress_tls    if TRUE, don't attempt a TLS connection - this is set for
1890
                    a second attempt after TLS initialization fails
2067
                    a second attempt after TLS initialization fails
1891
2068
Lines 1909-1951 Link Here
1909
uschar * tls_errstr;
2086
uschar * tls_errstr;
1910
#endif
2087
#endif
1911
2088
2089
/* Many lines of clearing individual elements of *sx that used to
2090
be here have been replaced by a full memset to zero (de41aff051).
2091
There are two callers, this file and verify.c .  Now we only set
2092
up nonzero elements. */
2093
1912
sx->conn_args.ob = ob;
2094
sx->conn_args.ob = ob;
1913
2095
1914
sx->lmtp = strcmpic(ob->protocol, US"lmtp") == 0;
2096
sx->lmtp = strcmpic(ob->protocol, US"lmtp") == 0;
1915
sx->smtps = strcmpic(ob->protocol, US"smtps") == 0;
2097
sx->smtps = strcmpic(ob->protocol, US"smtps") == 0;
1916
/* sx->ok = FALSE; */
1917
sx->send_rset = TRUE;
2098
sx->send_rset = TRUE;
1918
sx->send_quit = TRUE;
2099
sx->send_quit = TRUE;
1919
sx->setting_up = TRUE;
2100
sx->setting_up = TRUE;
1920
sx->esmtp = TRUE;
2101
sx->esmtp = TRUE;
1921
/* sx->esmtp_sent = FALSE; */
1922
#ifdef SUPPORT_I18N
1923
/* sx->utf8_needed = FALSE; */
1924
#endif
1925
sx->dsn_all_lasthop = TRUE;
2102
sx->dsn_all_lasthop = TRUE;
1926
#ifdef SUPPORT_DANE
2103
#ifdef SUPPORT_DANE
1927
/* sx->conn_args.dane = FALSE; */
1928
sx->dane_required =
2104
sx->dane_required =
1929
  verify_check_given_host(CUSS &ob->hosts_require_dane, sx->conn_args.host) == OK;
2105
  verify_check_given_host(CUSS &ob->hosts_require_dane, sx->conn_args.host) == OK;
1930
#endif
2106
#endif
1931
#ifndef DISABLE_PIPE_CONNECT
1932
/* sx->early_pipe_active = sx->early_pipe_ok = FALSE; */
1933
/* sx->ehlo_resp.cleartext_features = sx->ehlo_resp.crypted_features = 0; */
1934
/* sx->pending_BANNER = sx->pending_EHLO = sx->pending_MAIL = FALSE; */
1935
#endif
1936
2107
1937
if ((sx->max_rcpt = sx->conn_args.tblock->max_addresses) == 0) sx->max_rcpt = 999999;
2108
if ((sx->max_mail = sx->conn_args.tblock->connection_max_messages) == 0) sx->max_mail = 999999;
1938
/* sx->peer_offered = 0; */
2109
if ((sx->max_rcpt = sx->conn_args.tblock->max_addresses) == 0)           sx->max_rcpt = 999999;
1939
/* sx->avoid_option = 0; */
1940
sx->igquotstr = US"";
2110
sx->igquotstr = US"";
1941
if (!sx->helo_data) sx->helo_data = ob->helo_data;
2111
if (!sx->helo_data) sx->helo_data = ob->helo_data;
1942
#ifdef EXPERIMENTAL_DSN_INFO
1943
/* sx->smtp_greeting = NULL; */
1944
/* sx->helo_response = NULL; */
1945
#endif
1946
2112
1947
smtp_command = US"initial connection";
2113
smtp_command = US"initial connection";
1948
/* sx->buffer[0] = '\0'; */
1949
2114
1950
/* Set up the buffer for reading SMTP response packets. */
2115
/* Set up the buffer for reading SMTP response packets. */
1951
2116
Lines 1959-1967 Link Here
1959
sx->outblock.buffer = sx->outbuffer;
2124
sx->outblock.buffer = sx->outbuffer;
1960
sx->outblock.buffersize = sizeof(sx->outbuffer);
2125
sx->outblock.buffersize = sizeof(sx->outbuffer);
1961
sx->outblock.ptr = sx->outbuffer;
2126
sx->outblock.ptr = sx->outbuffer;
1962
/* sx->outblock.cmd_count = 0; */
1963
/* sx->outblock.authenticating = FALSE; */
1964
/* sx->outblock.conn_args = NULL; */
1965
2127
1966
/* Reset the parameters of a TLS session. */
2128
/* Reset the parameters of a TLS session. */
1967
2129
Lines 1974-1980 Link Here
1974
tls_out.sni = NULL;
2136
tls_out.sni = NULL;
1975
#endif
2137
#endif
1976
tls_out.ocsp = OCSP_NOT_REQ;
2138
tls_out.ocsp = OCSP_NOT_REQ;
1977
#ifdef EXPERIMENTAL_TLS_RESUME
2139
#ifndef DISABLE_TLS_RESUME
1978
tls_out.resumption = 0;
2140
tls_out.resumption = 0;
1979
#endif
2141
#endif
1980
tls_out.ver = NULL;
2142
tls_out.ver = NULL;
Lines 2003-2034 Link Here
2003
  const uschar * sni = US"";
2165
  const uschar * sni = US"";
2004
2166
2005
# ifdef SUPPORT_DANE
2167
# ifdef SUPPORT_DANE
2006
  /* Check if the message will be DANE-verified; if so force its SNI */
2168
  /* Check if the message will be DANE-verified; if so force TLS and its SNI */
2007
2169
2008
  tls_out.dane_verified = FALSE;
2170
  tls_out.dane_verified = FALSE;
2009
  smtp_port_for_connect(sx->conn_args.host, sx->port);
2171
  smtp_port_for_connect(sx->conn_args.host, sx->port);
2010
  if (  sx->conn_args.host->dnssec == DS_YES
2172
  if (  sx->conn_args.host->dnssec == DS_YES
2011
     && (  sx->dane_required
2173
     && (rc = check_force_dane_conn(sx, ob)) != OK
2012
	|| verify_check_given_host(CUSS &ob->hosts_try_dane, sx->conn_args.host) == OK
2174
     )
2013
     )  )
2175
    return rc;
2014
    switch (rc = tlsa_lookup(sx->conn_args.host, &sx->conn_args.tlsa_dnsa, sx->dane_required))
2015
      {
2016
      case OK:		sx->conn_args.dane = TRUE;
2017
			ob->tls_tempfail_tryclear = FALSE;	/* force TLS */
2018
			ob->tls_sni = sx->first_addr->domain;	/* force SNI */
2019
			break;
2020
      case FAIL_FORCED:	break;
2021
      default:		set_errno_nohost(sx->addrlist, ERRNO_DNSDEFER,
2022
			      string_sprintf("DANE error: tlsa lookup %s",
2023
				rc_to_string(rc)),
2024
			      rc, FALSE, &sx->delivery_start);
2025
#  ifndef DISABLE_EVENT
2026
			    (void) event_raise(sx->conn_args.tblock->event_action,
2027
			      US"dane:fail", sx->dane_required
2028
				?  US"dane-required" : US"dnssec-invalid");
2029
#  endif
2030
			    return rc;
2031
      }
2032
# endif
2176
# endif
2033
2177
2034
  /* If the SNI or the DANE status required for the new message differs from the
2178
  /* If the SNI or the DANE status required for the new message differs from the
Lines 2056-2062 Link Here
2056
    DEBUG(D_transport)
2200
    DEBUG(D_transport)
2057
      debug_printf("Closing proxied-TLS connection due to SNI mismatch\n");
2201
      debug_printf("Closing proxied-TLS connection due to SNI mismatch\n");
2058
2202
2059
    HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP>> QUIT\n");
2203
    smtp_debug_cmd(US"QUIT", 0);
2060
    write(0, "QUIT\r\n", 6);
2204
    write(0, "QUIT\r\n", 6);
2061
    close(0);
2205
    close(0);
2062
    continue_hostname = continue_proxy_cipher = NULL;
2206
    continue_hostname = continue_proxy_cipher = NULL;
Lines 2077-2082 Link Here
2077
  if (sx->verify)
2221
  if (sx->verify)
2078
    HDEBUG(D_verify) debug_printf("interface=%s port=%d\n", sx->conn_args.interface, sx->port);
2222
    HDEBUG(D_verify) debug_printf("interface=%s port=%d\n", sx->conn_args.interface, sx->port);
2079
2223
2224
  /* Arrange to report to calling process this is a new connection */
2225
2226
  clearflag(sx->first_addr, af_cont_conn);
2227
  setflag(sx->first_addr, af_new_conn);
2228
2080
  /* Get the actual port the connection will use, into sx->conn_args.host */
2229
  /* Get the actual port the connection will use, into sx->conn_args.host */
2081
2230
2082
  smtp_port_for_connect(sx->conn_args.host, sx->port);
2231
  smtp_port_for_connect(sx->conn_args.host, sx->port);
Lines 2090-2116 Link Here
2090
    if (sx->conn_args.host->dnssec == DS_YES)
2239
    if (sx->conn_args.host->dnssec == DS_YES)
2091
      {
2240
      {
2092
      int rc;
2241
      int rc;
2093
      if(  sx->dane_required
2242
      if ((rc = check_force_dane_conn(sx, ob)) != OK)
2094
	|| verify_check_given_host(CUSS &ob->hosts_try_dane, sx->conn_args.host) == OK
2243
	return rc;
2095
	)
2096
	switch (rc = tlsa_lookup(sx->conn_args.host, &sx->conn_args.tlsa_dnsa, sx->dane_required))
2097
	  {
2098
	  case OK:		sx->conn_args.dane = TRUE;
2099
				ob->tls_tempfail_tryclear = FALSE;	/* force TLS */
2100
				ob->tls_sni = sx->first_addr->domain;	/* force SNI */
2101
				break;
2102
	  case FAIL_FORCED:	break;
2103
	  default:		set_errno_nohost(sx->addrlist, ERRNO_DNSDEFER,
2104
				  string_sprintf("DANE error: tlsa lookup %s",
2105
				    rc_to_string(rc)),
2106
				  rc, FALSE, &sx->delivery_start);
2107
# ifndef DISABLE_EVENT
2108
				(void) event_raise(sx->conn_args.tblock->event_action,
2109
				  US"dane:fail", sx->dane_required
2110
				    ?  US"dane-required" : US"dnssec-invalid");
2111
# endif
2112
				return rc;
2113
	  }
2114
      }
2244
      }
2115
    else if (sx->dane_required)
2245
    else if (sx->dane_required)
2116
      {
2246
      {
Lines 2119-2125 Link Here
2119
	FAIL, FALSE, &sx->delivery_start);
2249
	FAIL, FALSE, &sx->delivery_start);
2120
# ifndef DISABLE_EVENT
2250
# ifndef DISABLE_EVENT
2121
      (void) event_raise(sx->conn_args.tblock->event_action,
2251
      (void) event_raise(sx->conn_args.tblock->event_action,
2122
	US"dane:fail", US"dane-required");
2252
	US"dane:fail", US"dane-required", NULL);
2123
# endif
2253
# endif
2124
      return FAIL;
2254
      return FAIL;
2125
      }
2255
      }
Lines 2130-2136 Link Here
2130
2260
2131
  sx->cctx.tls_ctx = NULL;
2261
  sx->cctx.tls_ctx = NULL;
2132
  sx->inblock.cctx = sx->outblock.cctx = &sx->cctx;
2262
  sx->inblock.cctx = sx->outblock.cctx = &sx->cctx;
2263
#ifdef EXPERIMENTAL_ESMTP_LIMITS
2264
  sx->peer_limit_mail = sx->peer_limit_rcpt = sx->peer_limit_rcptdom =
2265
#endif
2133
  sx->avoid_option = sx->peer_offered = smtp_peer_options = 0;
2266
  sx->avoid_option = sx->peer_offered = smtp_peer_options = 0;
2267
#ifndef DISABLE_CLIENT_CMD_LOG
2268
  client_cmd_log = NULL;
2269
#endif
2134
2270
2135
#ifndef DISABLE_PIPE_CONNECT
2271
#ifndef DISABLE_PIPE_CONNECT
2136
  if (  verify_check_given_host(CUSS &ob->hosts_pipe_connect,
2272
  if (  verify_check_given_host(CUSS &ob->hosts_pipe_connect,
Lines 2140-2145 Link Here
2140
    the helo string might use it avoid doing early-pipelining. */
2276
    the helo string might use it avoid doing early-pipelining. */
2141
2277
2142
    if (  !sx->helo_data
2278
    if (  !sx->helo_data
2279
       || sx->conn_args.interface
2143
       || !Ustrstr(sx->helo_data, "$sending_ip_address")
2280
       || !Ustrstr(sx->helo_data, "$sending_ip_address")
2144
       || Ustrstr(sx->helo_data, "def:sending_ip_address")
2281
       || Ustrstr(sx->helo_data, "def:sending_ip_address")
2145
       )
2282
       )
Lines 2149-2169 Link Here
2149
	 && sx->ehlo_resp.cleartext_features & OPTION_EARLY_PIPE)
2286
	 && sx->ehlo_resp.cleartext_features & OPTION_EARLY_PIPE)
2150
	{
2287
	{
2151
	DEBUG(D_transport)
2288
	DEBUG(D_transport)
2152
	  debug_printf("Using cached cleartext PIPE_CONNECT\n");
2289
	  debug_printf("Using cached cleartext PIPECONNECT\n");
2153
	sx->early_pipe_active = TRUE;
2290
	sx->early_pipe_active = TRUE;
2154
	sx->peer_offered = sx->ehlo_resp.cleartext_features;
2291
	sx->peer_offered = sx->ehlo_resp.cleartext_features;
2155
	}
2292
	}
2156
      }
2293
      }
2157
    else DEBUG(D_transport)
2294
    else DEBUG(D_transport)
2158
      debug_printf("helo needs $sending_ip_address\n");
2295
      debug_printf("helo needs $sending_ip_address; avoid early-pipelining\n");
2159
2296
2160
PIPE_CONNECT_RETRY:
2297
PIPE_CONNECT_RETRY:
2161
  if (sx->early_pipe_active)
2298
  if (sx->early_pipe_active)
2299
    {
2162
    sx->outblock.conn_args = &sx->conn_args;
2300
    sx->outblock.conn_args = &sx->conn_args;
2301
    (void) smtp_boundsock(&sx->conn_args);
2302
    }
2163
  else
2303
  else
2164
#endif
2304
#endif
2165
    {
2305
    {
2166
    if ((sx->cctx.sock = smtp_connect(&sx->conn_args, NULL)) < 0)
2306
    blob lazy_conn = {.data = NULL};
2307
    /* For TLS-connect, a TFO lazy-connect is useful since the Client Hello
2308
    can go on the TCP SYN. */
2309
2310
    if ((sx->cctx.sock = smtp_connect(&sx->conn_args,
2311
			    sx->smtps ? &lazy_conn : NULL)) < 0)
2167
      {
2312
      {
2168
      set_errno_nohost(sx->addrlist,
2313
      set_errno_nohost(sx->addrlist,
2169
	errno == ETIMEDOUT ? ERRNO_CONNECTTIMEOUT : errno,
2314
	errno == ETIMEDOUT ? ERRNO_CONNECTTIMEOUT : errno,
Lines 2172-2183 Link Here
2172
      sx->send_quit = FALSE;
2317
      sx->send_quit = FALSE;
2173
      return DEFER;
2318
      return DEFER;
2174
      }
2319
      }
2320
#ifdef TCP_QUICKACK
2321
    (void) setsockopt(sx->cctx.sock, IPPROTO_TCP, TCP_QUICKACK, US &off,
2322
			sizeof(off));
2323
#endif
2175
    }
2324
    }
2176
  /* Expand the greeting message while waiting for the initial response. (Makes
2325
  /* Expand the greeting message while waiting for the initial response. (Makes
2177
  sense if helo_data contains ${lookup dnsdb ...} stuff). The expansion is
2326
  sense if helo_data contains ${lookup dnsdb ...} stuff). The expansion is
2178
  delayed till here so that $sending_interface and $sending_port are set. */
2327
  delayed till here so that $sending_ip_address and $sending_port are set.
2179
/*XXX early-pipe: they still will not be. Is there any way to find out what they
2328
  Those will be known even for a TFO lazy-connect, having been set by the bind().
2180
will be?  Somehow I doubt it. */
2329
  For early-pipe, we are ok if binding to a local interface; otherwise (if
2330
  $sending_ip_address is seen in helo_data) we disabled early-pipe above. */
2181
2331
2182
  if (sx->helo_data)
2332
  if (sx->helo_data)
2183
    if (!(sx->helo_data = expand_string(sx->helo_data)))
2333
    if (!(sx->helo_data = expand_string(sx->helo_data)))
Lines 2217-2226 Link Here
2217
    else
2367
    else
2218
#endif
2368
#endif
2219
      {
2369
      {
2220
#ifdef TCP_QUICKACK
2221
      (void) setsockopt(sx->cctx.sock, IPPROTO_TCP, TCP_QUICKACK, US &off,
2222
			sizeof(off));
2223
#endif
2224
      if (!smtp_reap_banner(sx))
2370
      if (!smtp_reap_banner(sx))
2225
	goto RESPONSE_FAILED;
2371
	goto RESPONSE_FAILED;
2226
      }
2372
      }
Lines 2230-2236 Link Here
2230
      uschar * s;
2376
      uschar * s;
2231
      lookup_dnssec_authenticated = sx->conn_args.host->dnssec==DS_YES ? US"yes"
2377
      lookup_dnssec_authenticated = sx->conn_args.host->dnssec==DS_YES ? US"yes"
2232
	: sx->conn_args.host->dnssec==DS_NO ? US"no" : NULL;
2378
	: sx->conn_args.host->dnssec==DS_NO ? US"no" : NULL;
2233
      s = event_raise(sx->conn_args.tblock->event_action, US"smtp:connect", sx->buffer);
2379
      s = event_raise(sx->conn_args.tblock->event_action, US"smtp:connect", sx->buffer, NULL);
2234
      if (s)
2380
      if (s)
2235
	{
2381
	{
2236
	set_errno_nohost(sx->addrlist, ERRNO_EXPANDFAIL,
2382
	set_errno_nohost(sx->addrlist, ERRNO_EXPANDFAIL,
Lines 2403-2408 Link Here
2403
	  )
2549
	  )
2404
#endif
2550
#endif
2405
	);
2551
	);
2552
#ifdef EXPERIMENTAL_ESMTP_LIMITS
2553
      if (tls_out.active.sock >= 0 || !(sx->peer_offered & OPTION_TLS))
2554
	{
2555
	ehlo_response_limits_read(sx);
2556
	ehlo_response_limits_apply(sx);
2557
	}
2558
#endif
2406
#ifndef DISABLE_PIPE_CONNECT
2559
#ifndef DISABLE_PIPE_CONNECT
2407
      if (sx->early_pipe_ok)
2560
      if (sx->early_pipe_ok)
2408
	{
2561
	{
Lines 2411-2422 Link Here
2411
	if (  (sx->peer_offered & (OPTION_PIPE | OPTION_EARLY_PIPE))
2564
	if (  (sx->peer_offered & (OPTION_PIPE | OPTION_EARLY_PIPE))
2412
	   == (OPTION_PIPE | OPTION_EARLY_PIPE))
2565
	   == (OPTION_PIPE | OPTION_EARLY_PIPE))
2413
	  {
2566
	  {
2414
	  DEBUG(D_transport) debug_printf("PIPE_CONNECT usable in future for this IP\n");
2567
	  DEBUG(D_transport) debug_printf("PIPECONNECT usable in future for this IP\n");
2415
	  sx->ehlo_resp.cleartext_auths = study_ehlo_auths(sx);
2568
	  sx->ehlo_resp.cleartext_auths = study_ehlo_auths(sx);
2416
	  write_ehlo_cache_entry(sx);
2569
	  write_ehlo_cache_entry(sx);
2417
	  }
2570
	  }
2418
	}
2571
	}
2419
#endif
2572
#endif
2573
      ehlo_response_lbserver(sx, ob);
2420
      }
2574
      }
2421
2575
2422
  /* Set tls_offered if the response to EHLO specifies support for STARTTLS. */
2576
  /* Set tls_offered if the response to EHLO specifies support for STARTTLS. */
Lines 2457-2462 Link Here
2457
  sx->inblock.cctx = sx->outblock.cctx = &sx->cctx;
2611
  sx->inblock.cctx = sx->outblock.cctx = &sx->cctx;
2458
  smtp_command = big_buffer;
2612
  smtp_command = big_buffer;
2459
  sx->peer_offered = smtp_peer_options;
2613
  sx->peer_offered = smtp_peer_options;
2614
#ifdef EXPERIMENTAL_ESMTP_LIMITS
2615
  /* Limits passed by cmdline over exec. */
2616
  ehlo_limits_apply(sx,
2617
		    sx->peer_limit_mail = continue_limit_mail,
2618
		    sx->peer_limit_rcpt = continue_limit_rcpt,
2619
		    sx->peer_limit_rcptdom = continue_limit_rcptdom);
2620
#endif
2460
  sx->helo_data = NULL;		/* ensure we re-expand ob->helo_data */
2621
  sx->helo_data = NULL;		/* ensure we re-expand ob->helo_data */
2461
2622
2462
  /* For a continued connection with TLS being proxied for us, or a
2623
  /* For a continued connection with TLS being proxied for us, or a
Lines 2498-2513 Link Here
2498
2659
2499
#ifndef DISABLE_PIPE_CONNECT
2660
#ifndef DISABLE_PIPE_CONNECT
2500
  /* If doing early-pipelining reap the banner and EHLO-response but leave
2661
  /* If doing early-pipelining reap the banner and EHLO-response but leave
2501
  the response for the STARTTLS we just sent alone. */
2662
  the response for the STARTTLS we just sent alone.  On fail, assume wrong
2663
  cached capability and retry with the pipelining disabled. */
2502
2664
2503
  if (sx->early_pipe_active && sync_responses(sx, 2, 0) != 0)
2665
  if (sx->early_pipe_active)
2504
    {
2666
    {
2505
    HDEBUG(D_transport)
2667
    if (sync_responses(sx, 2, 0) != 0)
2506
      debug_printf("failed reaping pipelined cmd responses\n");
2668
      {
2507
    close(sx->cctx.sock);
2669
      HDEBUG(D_transport)
2508
    sx->cctx.sock = -1;
2670
	debug_printf("failed reaping pipelined cmd responses\n");
2509
    sx->early_pipe_active = FALSE;
2671
      close(sx->cctx.sock);
2510
    goto PIPE_CONNECT_RETRY;
2672
      sx->cctx.sock = -1;
2673
      sx->early_pipe_active = FALSE;
2674
      goto PIPE_CONNECT_RETRY;
2675
      }
2511
    }
2676
    }
2512
#endif
2677
#endif
2513
2678
Lines 2536-2549 Link Here
2536
  else
2701
  else
2537
  TLS_NEGOTIATE:
2702
  TLS_NEGOTIATE:
2538
    {
2703
    {
2704
    sx->conn_args.sending_ip_address = sending_ip_address;
2539
    if (!tls_client_start(&sx->cctx, &sx->conn_args, sx->addrlist, &tls_out, &tls_errstr))
2705
    if (!tls_client_start(&sx->cctx, &sx->conn_args, sx->addrlist, &tls_out, &tls_errstr))
2540
      {
2706
      {
2541
      /* TLS negotiation failed; give an error. From outside, this function may
2707
      /* TLS negotiation failed; give an error. From outside, this function may
2542
      be called again to try in clear on a new connection, if the options permit
2708
      be called again to try in clear on a new connection, if the options permit
2543
      it for this host. */
2709
      it for this host. */
2544
#ifdef USE_GNUTLS
2710
  TLS_CONN_FAILED:
2545
  GNUTLS_CONN_FAILED:
2546
#endif
2547
      DEBUG(D_tls) debug_printf("TLS session fail: %s\n", tls_errstr);
2711
      DEBUG(D_tls) debug_printf("TLS session fail: %s\n", tls_errstr);
2548
2712
2549
# ifdef SUPPORT_DANE
2713
# ifdef SUPPORT_DANE
Lines 2554-2560 Link Here
2554
	  sx->conn_args.host->name, sx->conn_args.host->address, tls_errstr);
2718
	  sx->conn_args.host->name, sx->conn_args.host->address, tls_errstr);
2555
#  ifndef DISABLE_EVENT
2719
#  ifndef DISABLE_EVENT
2556
	(void) event_raise(sx->conn_args.tblock->event_action,
2720
	(void) event_raise(sx->conn_args.tblock->event_action,
2557
	  US"dane:fail", US"validation-failure");	/* could do with better detail */
2721
	  US"dane:fail", US"validation-failure", NULL);	/* could do with better detail */
2558
#  endif
2722
#  endif
2559
	}
2723
	}
2560
# endif
2724
# endif
Lines 2564-2571 Link Here
2564
      sx->send_quit = FALSE;
2728
      sx->send_quit = FALSE;
2565
      goto TLS_FAILED;
2729
      goto TLS_FAILED;
2566
      }
2730
      }
2731
    sx->send_tlsclose = TRUE;
2732
2733
    /* TLS session is set up.  Check the inblock fill level.  If there is
2734
    content then as we have not yet done a tls read it must have arrived before
2735
    the TLS handshake, in-clear.  That violates the sync requirement of the
2736
    STARTTLS RFC, so fail. */
2567
2737
2568
    /* TLS session is set up */
2738
    if (sx->inblock.ptr != sx->inblock.ptrend)
2739
      {
2740
      DEBUG(D_tls)
2741
	{
2742
	int i = sx->inblock.ptrend - sx->inblock.ptr;
2743
	debug_printf("unused data in input buffer after ack for STARTTLS:\n"
2744
	  "'%.*s'%s\n",
2745
	  i > 100 ? 100 : i, sx->inblock.ptr, i > 100 ? "..." : "");
2746
	}
2747
      tls_errstr = US"synch error before connect";
2748
      goto TLS_CONN_FAILED;
2749
      }
2569
2750
2570
    smtp_peer_options_wrap = smtp_peer_options;
2751
    smtp_peer_options_wrap = smtp_peer_options;
2571
    for (address_item * addr = sx->addrlist; addr; addr = addr->next)
2752
    for (address_item * addr = sx->addrlist; addr; addr = addr->next)
Lines 2616-2624 Link Here
2616
    sx->peer_offered = sx->ehlo_resp.crypted_features;
2797
    sx->peer_offered = sx->ehlo_resp.crypted_features;
2617
    if ((sx->early_pipe_active =
2798
    if ((sx->early_pipe_active =
2618
	 !!(sx->ehlo_resp.crypted_features & OPTION_EARLY_PIPE)))
2799
	 !!(sx->ehlo_resp.crypted_features & OPTION_EARLY_PIPE)))
2619
      DEBUG(D_transport) debug_printf("Using cached crypted PIPE_CONNECT\n");
2800
      DEBUG(D_transport) debug_printf("Using cached crypted PIPECONNECT\n");
2620
    }
2801
    }
2621
#endif
2802
#endif
2803
#ifdef EXPERIMMENTAL_ESMTP_LIMITS
2804
  /* As we are about to send another EHLO, forget any LIMITS received so far. */
2805
  sx->peer_limit_mail = sx->peer_limit_rcpt = sx->peer_limit_rcptdom = 0;
2806
  if ((sx->max_mail = sx->conn_args.tblock->connection_max_message) == 0) sx->max_mail = 999999;
2807
  if ((sx->max_rcpt = sx->conn_args.tblock->max_addresses) == 0)          sx->max_rcpt = 999999;
2808
  sx->single_rcpt_domain = FALSE;
2809
#endif
2622
2810
2623
  /* For SMTPS we need to wait for the initial OK response. */
2811
  /* For SMTPS we need to wait for the initial OK response. */
2624
  if (sx->smtps)
2812
  if (sx->smtps)
Lines 2670-2676 Link Here
2670
      Can it do that, with all the flexibility we need? */
2858
      Can it do that, with all the flexibility we need? */
2671
2859
2672
      tls_errstr = US"error on first read";
2860
      tls_errstr = US"error on first read";
2673
      goto GNUTLS_CONN_FAILED;
2861
      goto TLS_CONN_FAILED;
2674
      }
2862
      }
2675
#else
2863
#else
2676
      goto RESPONSE_FAILED;
2864
      goto RESPONSE_FAILED;
Lines 2698-2704 Link Here
2698
    (void) event_raise(sx->conn_args.tblock->event_action, US"dane:fail",
2886
    (void) event_raise(sx->conn_args.tblock->event_action, US"dane:fail",
2699
      smtp_peer_options & OPTION_TLS
2887
      smtp_peer_options & OPTION_TLS
2700
      ? US"validation-failure"		/* could do with better detail */
2888
      ? US"validation-failure"		/* could do with better detail */
2701
      : US"starttls-not-supported");
2889
      : US"starttls-not-supported",
2890
      NULL);
2702
# endif
2891
# endif
2703
  goto TLS_FAILED;
2892
  goto TLS_FAILED;
2704
  }
2893
  }
Lines 2709-2715 Link Here
2709
continued session down a previously-used socket, we haven't just done EHLO, so
2898
continued session down a previously-used socket, we haven't just done EHLO, so
2710
we skip this. */
2899
we skip this. */
2711
2900
2712
if (continue_hostname == NULL
2901
if (   !continue_hostname
2713
#ifndef DISABLE_TLS
2902
#ifndef DISABLE_TLS
2714
    || tls_out.active.sock >= 0
2903
    || tls_out.active.sock >= 0
2715
#endif
2904
#endif
Lines 2748-2753 Link Here
2748
    if (tls_out.active.sock >= 0)
2937
    if (tls_out.active.sock >= 0)
2749
      sx->ehlo_resp.crypted_features = sx->peer_offered;
2938
      sx->ehlo_resp.crypted_features = sx->peer_offered;
2750
#endif
2939
#endif
2940
2941
#ifdef EXPERIMENTAL_ESMTP_LIMITS
2942
    if (tls_out.active.sock >= 0 || !(sx->peer_offered & OPTION_TLS))
2943
      {
2944
      ehlo_response_limits_read(sx);
2945
      ehlo_response_limits_apply(sx);
2946
      }
2947
#endif
2751
    }
2948
    }
2752
2949
2753
    /* Set for IGNOREQUOTA if the response to LHLO specifies support and the
2950
    /* Set for IGNOREQUOTA if the response to LHLO specifies support and the
Lines 2772-2789 Link Here
2772
      smtp_peer_options & OPTION_PIPE ? "" : "not ");
2969
      smtp_peer_options & OPTION_PIPE ? "" : "not ");
2773
2970
2774
    if (  sx->peer_offered & OPTION_CHUNKING
2971
    if (  sx->peer_offered & OPTION_CHUNKING
2775
       && verify_check_given_host(CUSS &ob->hosts_try_chunking, sx->conn_args.host) != OK)
2972
       && verify_check_given_host(CUSS &ob->hosts_try_chunking, sx->conn_args.host) == OK)
2776
      sx->peer_offered &= ~OPTION_CHUNKING;
2973
      smtp_peer_options |= OPTION_CHUNKING;
2777
2974
2778
    if (sx->peer_offered & OPTION_CHUNKING)
2975
    if (smtp_peer_options & OPTION_CHUNKING)
2779
      DEBUG(D_transport) debug_printf("CHUNKING usable\n");
2976
      DEBUG(D_transport) debug_printf("CHUNKING usable\n");
2780
2977
2781
#ifndef DISABLE_PRDR
2978
#ifndef DISABLE_PRDR
2782
    if (  sx->peer_offered & OPTION_PRDR
2979
    if (  sx->peer_offered & OPTION_PRDR
2783
       && verify_check_given_host(CUSS &ob->hosts_try_prdr, sx->conn_args.host) != OK)
2980
       && verify_check_given_host(CUSS &ob->hosts_try_prdr, sx->conn_args.host) == OK)
2784
      sx->peer_offered &= ~OPTION_PRDR;
2981
      smtp_peer_options |= OPTION_PRDR;
2785
2982
2786
    if (sx->peer_offered & OPTION_PRDR)
2983
    if (smtp_peer_options & OPTION_PRDR)
2787
      DEBUG(D_transport) debug_printf("PRDR usable\n");
2984
      DEBUG(D_transport) debug_printf("PRDR usable\n");
2788
#endif
2985
#endif
2789
2986
Lines 2800-2806 Link Here
2800
       && ( sx->ehlo_resp.cleartext_features | sx->ehlo_resp.crypted_features)
2997
       && ( sx->ehlo_resp.cleartext_features | sx->ehlo_resp.crypted_features)
2801
	  & OPTION_EARLY_PIPE)
2998
	  & OPTION_EARLY_PIPE)
2802
      {
2999
      {
2803
      DEBUG(D_transport) debug_printf("PIPE_CONNECT usable in future for this IP\n");
3000
      DEBUG(D_transport) debug_printf("PIPECONNECT usable in future for this IP\n");
2804
      sx->ehlo_resp.crypted_auths = study_ehlo_auths(sx);
3001
      sx->ehlo_resp.crypted_auths = study_ehlo_auths(sx);
2805
      write_ehlo_cache_entry(sx);
3002
      write_ehlo_cache_entry(sx);
2806
      }
3003
      }
Lines 2915-2921 Link Here
2915
3112
2916
  SEND_FAILED:
3113
  SEND_FAILED:
2917
    code = '4';
3114
    code = '4';
2918
    message = US string_sprintf("send() to %s [%s] failed: %s",
3115
    message = US string_sprintf("smtp send to %s [%s] failed: %s",
2919
      sx->conn_args.host->name, sx->conn_args.host->address, strerror(errno));
3116
      sx->conn_args.host->name, sx->conn_args.host->address, strerror(errno));
2920
    sx->send_quit = FALSE;
3117
    sx->send_quit = FALSE;
2921
    yield = DEFER;
3118
    yield = DEFER;
Lines 2981-2987 Link Here
2981
#ifndef DISABLE_TLS
3178
#ifndef DISABLE_TLS
2982
if (sx->cctx.tls_ctx)
3179
if (sx->cctx.tls_ctx)
2983
  {
3180
  {
2984
  tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_NOWAIT);
3181
  if (sx->send_tlsclose)
3182
    {
3183
    tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_NOWAIT);
3184
    sx->send_tlsclose = FALSE;
3185
    }
2985
  sx->cctx.tls_ctx = NULL;
3186
  sx->cctx.tls_ctx = NULL;
2986
  }
3187
  }
2987
#endif
3188
#endif
Lines 3004-3012 Link Here
3004
sx->cctx.sock = -1;
3205
sx->cctx.sock = -1;
3005
3206
3006
#ifndef DISABLE_EVENT
3207
#ifndef DISABLE_EVENT
3007
(void) event_raise(sx->conn_args.tblock->event_action, US"tcp:close", NULL);
3208
(void) event_raise(sx->conn_args.tblock->event_action, US"tcp:close", NULL, NULL);
3008
#endif
3209
#endif
3009
3210
3211
smtp_debug_cmd_report();
3010
continue_transport = NULL;
3212
continue_transport = NULL;
3011
continue_hostname = NULL;
3213
continue_hostname = NULL;
3012
return yield;
3214
return yield;
Lines 3049-3055 Link Here
3049
request that */
3251
request that */
3050
3252
3051
sx->prdr_active = FALSE;
3253
sx->prdr_active = FALSE;
3052
if (sx->peer_offered & OPTION_PRDR)
3254
if (smtp_peer_options & OPTION_PRDR)
3053
  for (address_item * addr = addrlist; addr; addr = addr->next)
3255
  for (address_item * addr = addrlist; addr; addr = addr->next)
3054
    if (addr->transport_return == PENDING_DEFER)
3256
    if (addr->transport_return == PENDING_DEFER)
3055
      {
3257
      {
Lines 3077-3083 Link Here
3077
3279
3078
/* check if all addresses have DSN-lasthop flag; do not send RET and ENVID if so */
3280
/* check if all addresses have DSN-lasthop flag; do not send RET and ENVID if so */
3079
for (sx->dsn_all_lasthop = TRUE, addr = addrlist, address_count = 0;
3281
for (sx->dsn_all_lasthop = TRUE, addr = addrlist, address_count = 0;
3080
     addr && address_count < sx->max_rcpt;
3282
     addr && address_count < sx->max_rcpt;	/*XXX maybe also || sx->single_rcpt_domain ? */
3081
     addr = addr->next) if (addr->transport_return == PENDING_DEFER)
3283
     addr = addr->next) if (addr->transport_return == PENDING_DEFER)
3082
  {
3284
  {
3083
  address_count++;
3285
  address_count++;
Lines 3165-3170 Link Here
3165
smtp_write_mail_and_rcpt_cmds(smtp_context * sx, int * yield)
3367
smtp_write_mail_and_rcpt_cmds(smtp_context * sx, int * yield)
3166
{
3368
{
3167
address_item * addr;
3369
address_item * addr;
3370
#ifdef EXPERIMENTAL_ESMTP_LIMITS
3371
address_item * restart_addr = NULL;
3372
#endif
3168
int address_count, pipe_limit;
3373
int address_count, pipe_limit;
3169
int rc;
3374
int rc;
3170
3375
Lines 3249-3261 Link Here
3249
For verify we flush the pipeline after any (the only) rcpt address. */
3454
For verify we flush the pipeline after any (the only) rcpt address. */
3250
3455
3251
for (addr = sx->first_addr, address_count = 0, pipe_limit = 100;
3456
for (addr = sx->first_addr, address_count = 0, pipe_limit = 100;
3252
     addr  &&  address_count < sx->max_rcpt;
3457
     addr &&  address_count < sx->max_rcpt;
3253
     addr = addr->next) if (addr->transport_return == PENDING_DEFER)
3458
     addr = addr->next) if (addr->transport_return == PENDING_DEFER)
3254
  {
3459
  {
3255
  int cmds_sent;
3460
  int cmds_sent;
3256
  BOOL no_flush;
3461
  BOOL no_flush;
3257
  uschar * rcpt_addr;
3462
  uschar * rcpt_addr;
3258
3463
3464
#ifdef EXPERIMENTAL_ESMTP_LIMITS
3465
  if (  sx->single_rcpt_domain					/* restriction on domains */
3466
     && address_count > 0					/* not first being sent */
3467
     && Ustrcmp(addr->domain, sx->first_addr->domain) != 0	/* dom diff from first */
3468
     )
3469
    {
3470
    DEBUG(D_transport) debug_printf("skipping different domain %s\n", addr->domain);
3471
3472
    /* Ensure the smtp-response reaper does not think the address had a RCPT
3473
    command sent for it.  Reset to PENDING_DEFER in smtp_deliver(), where we
3474
    goto SEND_MESSAGE.  */
3475
3476
    addr->transport_return = SKIP;
3477
    if (!restart_addr) restart_addr = addr;	/* note restart point */
3478
    continue;					/* skip this one */
3479
    }
3480
#endif
3481
3259
  addr->dsn_aware = sx->peer_offered & OPTION_DSN
3482
  addr->dsn_aware = sx->peer_offered & OPTION_DSN
3260
    ? dsn_support_yes : dsn_support_no;
3483
    ? dsn_support_yes : dsn_support_no;
3261
3484
Lines 3327-3333 Link Here
3327
    }
3550
    }
3328
  }      /* Loop for next address */
3551
  }      /* Loop for next address */
3329
3552
3553
#ifdef EXPERIMENTAL_ESMTP_LIMITS
3554
sx->next_addr = restart_addr ? restart_addr : addr;
3555
#else
3330
sx->next_addr = addr;
3556
sx->next_addr = addr;
3557
#endif
3331
return 0;
3558
return 0;
3332
}
3559
}
3333
3560
Lines 3349-3388 Link Here
3349
  bufsiz	size of buffer
3576
  bufsiz	size of buffer
3350
  pfd		pipe filedescriptor array; [0] is comms to proxied process
3577
  pfd		pipe filedescriptor array; [0] is comms to proxied process
3351
  timeout	per-read timeout, seconds
3578
  timeout	per-read timeout, seconds
3579
  host		hostname of remote
3352
3580
3353
Does not return.
3581
Does not return.
3354
*/
3582
*/
3355
3583
3356
void
3584
void
3357
smtp_proxy_tls(void * ct_ctx, uschar * buf, size_t bsize, int * pfd,
3585
smtp_proxy_tls(void * ct_ctx, uschar * buf, size_t bsize, int * pfd,
3358
  int timeout)
3586
  int timeout, const uschar * host)
3359
{
3587
{
3360
fd_set rfds, efds;
3588
struct pollfd p[2] = {{.fd = tls_out.active.sock, .events = POLLIN},
3361
int max_fd = MAX(pfd[0], tls_out.active.sock) + 1;
3589
		      {.fd = pfd[0], .events = POLLIN}};
3362
int rc, i;
3590
int rc, i;
3591
BOOL send_tls_shutdown = TRUE;
3363
3592
3364
close(pfd[1]);
3593
close(pfd[1]);
3365
if ((rc = exim_fork(US"tls-proxy")))
3594
if ((rc = exim_fork(US"tls-proxy")))
3366
  _exit(rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
3595
  _exit(rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
3367
3596
3368
set_process_info("proxying TLS connection for continued transport");
3597
set_process_info("proxying TLS connection for continued transport to %s\n", host);
3369
FD_ZERO(&rfds);
3370
FD_SET(tls_out.active.sock, &rfds);
3371
FD_SET(pfd[0], &rfds);
3372
3598
3373
for (int fd_bits = 3; fd_bits; )
3599
do
3374
  {
3600
  {
3375
  time_t time_left = timeout;
3601
  time_t time_left = timeout;
3376
  time_t time_start = time(NULL);
3602
  time_t time_start = time(NULL);
3377
3603
3378
  /* wait for data */
3604
  /* wait for data */
3379
  efds = rfds;
3380
  do
3605
  do
3381
    {
3606
    {
3382
    struct timeval tv = { time_left, 0 };
3607
    rc = poll(p, 2, time_left * 1000);
3383
3384
    rc = select(max_fd,
3385
      (SELECT_ARG2_TYPE *)&rfds, NULL, (SELECT_ARG2_TYPE *)&efds, &tv);
3386
3608
3387
    if (rc < 0 && errno == EINTR)
3609
    if (rc < 0 && errno == EINTR)
3388
      if ((time_left -= time(NULL) - time_start) > 0) continue;
3610
      if ((time_left -= time(NULL) - time_start) > 0) continue;
Lines 3393-3443 Link Here
3393
      goto done;
3615
      goto done;
3394
      }
3616
      }
3395
3617
3396
    if (FD_ISSET(tls_out.active.sock, &efds) || FD_ISSET(pfd[0], &efds))
3618
    /* For errors where not readable, bomb out */
3619
3620
    if (p[0].revents & POLLERR || p[1].revents & POLLERR)
3397
      {
3621
      {
3398
      DEBUG(D_transport) debug_printf("select: exceptional cond on %s fd\n",
3622
      DEBUG(D_transport) debug_printf("select: exceptional cond on %s fd\n",
3399
	FD_ISSET(pfd[0], &efds) ? "proxy" : "tls");
3623
	p[0].revents & POLLERR ? "tls" : "proxy");
3400
      goto done;
3624
      if (!(p[0].revents & POLLIN || p[1].events & POLLIN))
3625
	goto done;
3626
      DEBUG(D_transport) debug_printf("- but also readable; no exit yet\n");
3401
      }
3627
      }
3402
    }
3628
    }
3403
  while (rc < 0 || !(FD_ISSET(tls_out.active.sock, &rfds) || FD_ISSET(pfd[0], &rfds)));
3629
  while (rc < 0 || !(p[0].revents & POLLIN || p[1].revents & POLLIN));
3404
3630
3405
  /* handle inbound data */
3631
  /* handle inbound data */
3406
  if (FD_ISSET(tls_out.active.sock, &rfds))
3632
  if (p[0].revents & POLLIN)
3407
    if ((rc = tls_read(ct_ctx, buf, bsize)) <= 0)
3633
    if ((rc = tls_read(ct_ctx, buf, bsize)) <= 0)	/* Expect -1 for EOF; */
3408
      {
3634
    {				    /* that reaps the TLS Close Notify record */
3409
      fd_bits &= ~1;
3635
      p[0].fd = -1;
3410
      FD_CLR(tls_out.active.sock, &rfds);
3411
      shutdown(pfd[0], SHUT_WR);
3636
      shutdown(pfd[0], SHUT_WR);
3412
      timeout = 5;
3637
      timeout = 5;
3413
      }
3638
      }
3414
    else
3639
    else
3415
      {
3416
      for (int nbytes = 0; rc - nbytes > 0; nbytes += i)
3640
      for (int nbytes = 0; rc - nbytes > 0; nbytes += i)
3417
	if ((i = write(pfd[0], buf + nbytes, rc - nbytes)) < 0) goto done;
3641
	if ((i = write(pfd[0], buf + nbytes, rc - nbytes)) < 0) goto done;
3418
      }
3419
  else if (fd_bits & 1)
3420
    FD_SET(tls_out.active.sock, &rfds);
3421
3642
3422
  /* handle outbound data */
3643
  /* Handle outbound data.  We cannot combine payload and the TLS-close
3423
  if (FD_ISSET(pfd[0], &rfds))
3644
  due to the limitations of the (pipe) channel feeding us.  Maybe use a unix-domain
3645
  socket? */
3646
  if (p[1].revents & POLLIN)
3424
    if ((rc = read(pfd[0], buf, bsize)) <= 0)
3647
    if ((rc = read(pfd[0], buf, bsize)) <= 0)
3425
      {
3648
      {
3426
      fd_bits = 0;
3649
      p[1].fd = -1;
3427
      tls_close(ct_ctx, TLS_SHUTDOWN_NOWAIT);
3650
3428
      ct_ctx = NULL;
3651
# ifdef EXIM_TCP_CORK  /* Use _CORK to get TLS Close Notify in FIN segment */
3652
      (void) setsockopt(tls_out.active.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on));
3653
# endif
3654
      tls_shutdown_wr(ct_ctx);
3655
      send_tls_shutdown = FALSE;
3656
      shutdown(tls_out.active.sock, SHUT_WR);
3429
      }
3657
      }
3430
    else
3658
    else
3431
      {
3432
      for (int nbytes = 0; rc - nbytes > 0; nbytes += i)
3659
      for (int nbytes = 0; rc - nbytes > 0; nbytes += i)
3433
	if ((i = tls_write(ct_ctx, buf + nbytes, rc - nbytes, FALSE)) < 0)
3660
	if ((i = tls_write(ct_ctx, buf + nbytes, rc - nbytes, FALSE)) < 0)
3434
	  goto done;
3661
	  goto done;
3435
      }
3436
  else if (fd_bits & 2)
3437
    FD_SET(pfd[0], &rfds);
3438
  }
3662
  }
3663
while (p[0].fd >= 0 || p[1].fd >= 0);
3439
3664
3440
done:
3665
done:
3666
  if (send_tls_shutdown) tls_close(ct_ctx, TLS_SHUTDOWN_NOWAIT);
3667
  ct_ctx = NULL;
3441
  testharness_pause_ms(100);	/* let logging complete */
3668
  testharness_pause_ms(100);	/* let logging complete */
3442
  exim_exit(EXIT_SUCCESS);
3669
  exim_exit(EXIT_SUCCESS);
3443
}
3670
}
Lines 3503-3533 Link Here
3503
int save_errno;
3730
int save_errno;
3504
int rc;
3731
int rc;
3505
3732
3506
BOOL pass_message = FALSE;
3507
uschar *message = NULL;
3733
uschar *message = NULL;
3508
uschar new_message_id[MESSAGE_ID_LENGTH + 1];
3734
uschar new_message_id[MESSAGE_ID_LENGTH + 1];
3509
smtp_context * sx = store_get(sizeof(*sx), TRUE);	/* tainted, for the data buffers */
3735
smtp_context * sx = store_get(sizeof(*sx), GET_TAINTED);	/* tainted, for the data buffers */
3736
BOOL pass_message = FALSE;
3737
#ifdef EXPERIMENTAL_ESMTP_LIMITS
3738
BOOL mail_limit = FALSE;
3739
#endif
3510
#ifdef SUPPORT_DANE
3740
#ifdef SUPPORT_DANE
3511
BOOL dane_held;
3741
BOOL dane_held;
3512
#endif
3742
#endif
3743
BOOL tcw_done = FALSE, tcw = FALSE;
3513
3744
3514
suppress_tls = suppress_tls;  /* stop compiler warning when no TLS support */
3515
*message_defer = FALSE;
3745
*message_defer = FALSE;
3516
3746
3517
memset(sx, 0, sizeof(*sx));
3747
memset(sx, 0, sizeof(*sx));
3518
sx->addrlist = addrlist;
3748
sx->addrlist = addrlist;
3519
sx->conn_args.host = host;
3749
sx->conn_args.host = host;
3520
sx->conn_args.host_af = host_af,
3750
sx->conn_args.host_af = host_af;
3521
sx->port = defport;
3751
sx->port = defport;
3522
sx->conn_args.interface = interface;
3752
sx->conn_args.interface = interface;
3523
sx->helo_data = NULL;
3753
sx->helo_data = NULL;
3524
sx->conn_args.tblock = tblock;
3754
sx->conn_args.tblock = tblock;
3525
/* sx->verify = FALSE; */
3755
sx->conn_args.sock = -1;
3526
gettimeofday(&sx->delivery_start, NULL);
3756
gettimeofday(&sx->delivery_start, NULL);
3527
sx->sync_addr = sx->first_addr = addrlist;
3757
sx->sync_addr = sx->first_addr = addrlist;
3528
3758
3759
REPEAT_CONN:
3529
#ifdef SUPPORT_DANE
3760
#ifdef SUPPORT_DANE
3530
DANE_DOMAINS:
3531
dane_held = FALSE;
3761
dane_held = FALSE;
3532
#endif
3762
#endif
3533
3763
Lines 3572-3579 Link Here
3572
  yield ERROR. */
3802
  yield ERROR. */
3573
3803
3574
  if (!transport_set_up_command(&transport_filter_argv,
3804
  if (!transport_set_up_command(&transport_filter_argv,
3575
	tblock->filter_command, TRUE, DEFER, addrlist,
3805
	tblock->filter_command, TRUE, DEFER, addrlist, FALSE,
3576
	string_sprintf("%.50s transport", tblock->name), NULL))
3806
	string_sprintf("%.50s transport filter", tblock->name), NULL))
3577
    {
3807
    {
3578
    set_errno_nohost(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER,
3808
    set_errno_nohost(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER,
3579
      FALSE, &sx->delivery_start);
3809
      FALSE, &sx->delivery_start);
Lines 3584-3590 Link Here
3584
  if (  transport_filter_argv
3814
  if (  transport_filter_argv
3585
     && *transport_filter_argv
3815
     && *transport_filter_argv
3586
     && **transport_filter_argv
3816
     && **transport_filter_argv
3587
     && sx->peer_offered & OPTION_CHUNKING
3817
     && smtp_peer_options & OPTION_CHUNKING
3588
#ifndef DISABLE_DKIM
3818
#ifndef DISABLE_DKIM
3589
    /* When dkim signing, chunking is handled even with a transport-filter */
3819
    /* When dkim signing, chunking is handled even with a transport-filter */
3590
     && !(ob->dkim.dkim_private_key && ob->dkim.dkim_domain && ob->dkim.dkim_selector)
3820
     && !(ob->dkim.dkim_private_key && ob->dkim.dkim_domain && ob->dkim.dkim_selector)
Lines 3592-3598 Link Here
3592
#endif
3822
#endif
3593
     )
3823
     )
3594
    {
3824
    {
3595
    sx->peer_offered &= ~OPTION_CHUNKING;
3825
    smtp_peer_options &= ~OPTION_CHUNKING;
3596
    DEBUG(D_transport) debug_printf("CHUNKING not usable due to transport filter\n");
3826
    DEBUG(D_transport) debug_printf("CHUNKING not usable due to transport filter\n");
3597
    }
3827
    }
3598
  }
3828
  }
Lines 3669-3675 Link Here
3669
If using CHUNKING, do not send a BDAT until we know how big a chunk we want
3899
If using CHUNKING, do not send a BDAT until we know how big a chunk we want
3670
to send is. */
3900
to send is. */
3671
3901
3672
if (  !(sx->peer_offered & OPTION_CHUNKING)
3902
if (  !(smtp_peer_options & OPTION_CHUNKING)
3673
   && (sx->ok || (pipelining_active && !mua_wrapper)))
3903
   && (sx->ok || (pipelining_active && !mua_wrapper)))
3674
  {
3904
  {
3675
  int count = smtp_write_command(sx, SCMD_FLUSH, "DATA\r\n");
3905
  int count = smtp_write_command(sx, SCMD_FLUSH, "DATA\r\n");
Lines 3706-3712 Link Here
3706
(Haven't been able to make it work using select() for writing yet.) */
3936
(Haven't been able to make it work using select() for writing yet.) */
3707
3937
3708
if (  !sx->ok
3938
if (  !sx->ok
3709
   && (!(sx->peer_offered & OPTION_CHUNKING) || !pipelining_active))
3939
   && (!(smtp_peer_options & OPTION_CHUNKING) || !pipelining_active))
3710
  {
3940
  {
3711
  /* Save the first address of the next batch. */
3941
  /* Save the first address of the next batch. */
3712
  sx->first_addr = sx->next_addr;
3942
  sx->first_addr = sx->next_addr;
Lines 3735-3741 Link Here
3735
  of responses.  The callback needs a whole bunch of state so set up
3965
  of responses.  The callback needs a whole bunch of state so set up
3736
  a transport-context structure to be passed around. */
3966
  a transport-context structure to be passed around. */
3737
3967
3738
  if (sx->peer_offered & OPTION_CHUNKING)
3968
  if (smtp_peer_options & OPTION_CHUNKING)
3739
    {
3969
    {
3740
    tctx.check_string = tctx.escape_string = NULL;
3970
    tctx.check_string = tctx.escape_string = NULL;
3741
    tctx.options |= topt_use_bdat;
3971
    tctx.options |= topt_use_bdat;
Lines 3760-3769 Link Here
3760
  transport_write_timeout = ob->data_timeout;
3990
  transport_write_timeout = ob->data_timeout;
3761
  smtp_command = US"sending data block";   /* For error messages */
3991
  smtp_command = US"sending data block";   /* For error messages */
3762
  DEBUG(D_transport|D_v)
3992
  DEBUG(D_transport|D_v)
3763
    if (sx->peer_offered & OPTION_CHUNKING)
3993
    if (smtp_peer_options & OPTION_CHUNKING)
3764
      debug_printf("         will write message using CHUNKING\n");
3994
      debug_printf("         will write message using CHUNKING\n");
3765
    else
3995
    else
3766
      debug_printf("  SMTP>> writing message and terminating \".\"\n");
3996
      debug_printf("  SMTP>> (writing message)\n");
3767
  transport_count = 0;
3997
  transport_count = 0;
3768
3998
3769
#ifndef DISABLE_DKIM
3999
#ifndef DISABLE_DKIM
Lines 3800-3805 Link Here
3800
  report_time_since(&t0, US"dkim_exim_sign_init (delta)");
4030
  report_time_since(&t0, US"dkim_exim_sign_init (delta)");
3801
# endif
4031
# endif
3802
  }
4032
  }
4033
#endif
4034
4035
  /* See if we can pipeline QUIT.  Reasons not to are
4036
  - pipelining not active
4037
  - not ok to send quit
4038
  - errors in amtp transation responses
4039
  - more addrs to send for this message or this host
4040
  - this message was being retried
4041
  - more messages for this host
4042
  If we can, we want the message-write to not flush (the tail end of) its data out.  */
4043
4044
  if (  sx->pipelining_used
4045
     && (sx->ok && sx->completed_addr || smtp_peer_options & OPTION_CHUNKING)
4046
     && sx->send_quit
4047
     && !(sx->first_addr || f.continue_more)
4048
     && f.deliver_firsttime
4049
     )
4050
    {
4051
    smtp_compare_t t_compare =
4052
      {.tblock = tblock, .current_sender_address = sender_address};
4053
4054
    tcw_done = TRUE;
4055
    tcw =
4056
#ifndef DISABLE_TLS
4057
	   (  tls_out.active.sock < 0  &&  !continue_proxy_cipher
4058
           || verify_check_given_host(CUSS &ob->hosts_nopass_tls, host) != OK
4059
	   )
4060
        &&
4061
#endif
4062
           transport_check_waiting(tblock->name, host->name,
4063
             tblock->connection_max_messages, new_message_id,
4064
	     (oicf)smtp_are_same_identities, (void*)&t_compare);
4065
    if (!tcw)
4066
      {
4067
      HDEBUG(D_transport) debug_printf("will pipeline QUIT\n");
4068
      tctx.options |= topt_no_flush;
4069
      }
4070
    }
4071
4072
#ifndef DISABLE_DKIM
3803
  sx->ok = dkim_transport_write_message(&tctx, &ob->dkim, CUSS &message);
4073
  sx->ok = dkim_transport_write_message(&tctx, &ob->dkim, CUSS &message);
3804
#else
4074
#else
3805
  sx->ok = transport_write_message(&tctx, 0);
4075
  sx->ok = transport_write_message(&tctx, 0);
Lines 3828-3834 Link Here
3828
4098
3829
  smtp_command = US"end of data";
4099
  smtp_command = US"end of data";
3830
4100
3831
  if (sx->peer_offered & OPTION_CHUNKING && sx->cmd_count > 1)
4101
  /* If we can pipeline a QUIT with the data them send it now.  If a new message
4102
  for this host appeared in the queue while data was being sent, we will not see
4103
  it and it will have to wait for a queue run.  If there was one but another
4104
  thread took it, we might attempt to send it - but locking of spoolfiles will
4105
  detect that. Use _MORE to get QUIT in FIN segment. */
4106
4107
  if (tcw_done && !tcw)
4108
    {
4109
    /*XXX jgh 2021/03/10 google et. al screwup.  G, at least, sends TCP FIN in response to TLS
4110
    close-notify.  Under TLS 1.3, violating RFC.
4111
    However, TLS 1.2 does not have half-close semantics. */
4112
4113
    if (     sx->cctx.tls_ctx
4114
#if 0 && !defined(DISABLE_TLS)
4115
          && Ustrcmp(tls_out.ver, "TLS1.3") != 0
4116
#endif
4117
       || !f.deliver_firsttime
4118
       )
4119
      {				/* Send QUIT now and not later */
4120
      (void)smtp_write_command(sx, SCMD_FLUSH, "QUIT\r\n");
4121
      sx->send_quit = FALSE;
4122
      }
4123
    else
4124
      {				/* add QUIT to the output buffer */
4125
      (void)smtp_write_command(sx, SCMD_MORE, "QUIT\r\n");
4126
      sx->send_quit = FALSE;	/* avoid sending it later */
4127
4128
#ifndef DISABLE_TLS
4129
      if (sx->cctx.tls_ctx && sx->send_tlsclose)	/* need to send TLS Close Notify */
4130
	{
4131
# ifdef EXIM_TCP_CORK		/* Use _CORK to get Close Notify in FIN segment */
4132
	(void) setsockopt(sx->cctx.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on));
4133
# endif
4134
	tls_shutdown_wr(sx->cctx.tls_ctx);
4135
	sx->send_tlsclose = FALSE;	/* avoid later repeat */
4136
	}
4137
#endif
4138
      HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP(shutdown)>>\n");
4139
      shutdown(sx->cctx.sock, SHUT_WR);	/* flush output buffer, with TCP FIN */
4140
      }
4141
    }
4142
4143
  if (smtp_peer_options & OPTION_CHUNKING && sx->cmd_count > 1)
3832
    {
4144
    {
3833
    /* Reap any outstanding MAIL & RCPT commands, but not a DATA-go-ahead */
4145
    /* Reap any outstanding MAIL & RCPT commands, but not a DATA-go-ahead */
3834
    switch(sync_responses(sx, sx->cmd_count-1, 0))
4146
    switch(sync_responses(sx, sx->cmd_count-1, 0))
Lines 3920-3928 Link Here
3920
          !sx->lmtp
4232
          !sx->lmtp
3921
       )
4233
       )
3922
      {
4234
      {
3923
      const uschar *s = string_printing(sx->buffer);
4235
      const uschar * s = string_printing(sx->buffer);
3924
      /* deconst cast ok here as string_printing was checked to have alloc'n'copied */
4236
      /* deconst cast ok here as string_printing was checked to have alloc'n'copied */
3925
      conf = (s == sx->buffer)? US string_copy(s) : US s;
4237
      conf = s == sx->buffer ? US string_copy(s) : US s;
3926
      }
4238
      }
3927
4239
3928
    /* Process all transported addresses - for LMTP or PRDR, read a status for
4240
    /* Process all transported addresses - for LMTP or PRDR, read a status for
Lines 4001-4007 Link Here
4001
#ifndef DISABLE_PRDR
4313
#ifndef DISABLE_PRDR
4002
      if (sx->prdr_active) setflag(addr, af_prdr_used);
4314
      if (sx->prdr_active) setflag(addr, af_prdr_used);
4003
#endif
4315
#endif
4004
      if (sx->peer_offered & OPTION_CHUNKING) setflag(addr, af_chunking_used);
4316
      if (smtp_peer_options & OPTION_CHUNKING) setflag(addr, af_chunking_used);
4005
      flag = '-';
4317
      flag = '-';
4006
4318
4007
#ifndef DISABLE_PRDR
4319
#ifndef DISABLE_PRDR
Lines 4018-4024 Link Here
4018
        else
4330
        else
4019
          sprintf(CS sx->buffer, "%.500s\n", addr->unique);
4331
          sprintf(CS sx->buffer, "%.500s\n", addr->unique);
4020
4332
4021
        DEBUG(D_deliver) debug_printf("S:journalling %s\n", sx->buffer);
4333
        DEBUG(D_deliver) debug_printf("S:journalling %s", sx->buffer);
4022
        len = Ustrlen(CS sx->buffer);
4334
        len = Ustrlen(CS sx->buffer);
4023
        if (write(journal_fd, sx->buffer, len) != len)
4335
        if (write(journal_fd, sx->buffer, len) != len)
4024
          log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for "
4336
          log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for "
Lines 4072-4077 Link Here
4072
	      "%s: %s", sx->buffer, strerror(errno));
4384
	      "%s: %s", sx->buffer, strerror(errno));
4073
	  }
4385
	  }
4074
	else if (addr->transport_return == DEFER)
4386
	else if (addr->transport_return == DEFER)
4387
	  /*XXX magic value -2 ? maybe host+message ? */
4075
	  retry_add_item(addr, addr->address_retry_key, -2);
4388
	  retry_add_item(addr, addr->address_retry_key, -2);
4076
      }
4389
      }
4077
#endif
4390
#endif
Lines 4102-4108 Link Here
4102
    {
4415
    {
4103
    save_errno = errno;
4416
    save_errno = errno;
4104
    message = NULL;
4417
    message = NULL;
4105
    sx->send_quit = check_response(host, &save_errno, addrlist->more_errno,
4418
    /* Clear send_quit flag if needed.  Do not set. */
4419
    sx->send_quit &= check_response(host, &save_errno, addrlist->more_errno,
4106
      sx->buffer, &code, &message, &pass_message);
4420
      sx->buffer, &code, &message, &pass_message);
4107
    goto FAILED;
4421
    goto FAILED;
4108
    }
4422
    }
Lines 4111-4117 Link Here
4111
    {
4425
    {
4112
    save_errno = errno;
4426
    save_errno = errno;
4113
    code = '4';
4427
    code = '4';
4114
    message = string_sprintf("send() to %s [%s] failed: %s",
4428
    message = string_sprintf("smtp send to %s [%s] failed: %s",
4115
      host->name, host->address, message ? message : US strerror(save_errno));
4429
      host->name, host->address, message ? message : US strerror(save_errno));
4116
    sx->send_quit = FALSE;
4430
    sx->send_quit = FALSE;
4117
    goto FAILED;
4431
    goto FAILED;
Lines 4147-4152 Link Here
4147
	message_error = Ustrncmp(smtp_command,"end ",4) == 0;
4461
	message_error = Ustrncmp(smtp_command,"end ",4) == 0;
4148
	break;
4462
	break;
4149
4463
4464
#ifndef DISABLE_DKIM
4465
      case EACCES:
4466
	/* DKIM signing failure: avoid thinking we pipelined quit,
4467
	just abandon the message and close the socket. */
4468
4469
	message_error = FALSE;
4470
# ifndef DISABLE_TLS
4471
	if (sx->cctx.tls_ctx)
4472
	  {
4473
	  tls_close(sx->cctx.tls_ctx,
4474
		    sx->send_tlsclose ? TLS_SHUTDOWN_WAIT : TLS_SHUTDOWN_WONLY);
4475
	  sx->cctx.tls_ctx = NULL;
4476
	  }
4477
# endif
4478
	break;
4479
#endif
4150
      default:
4480
      default:
4151
	message_error = FALSE;
4481
	message_error = FALSE;
4152
	break;
4482
	break;
Lines 4187-4194 Link Here
4187
4517
4188
        *message_defer = TRUE;
4518
        *message_defer = TRUE;
4189
        }
4519
        }
4520
#ifdef TIOCOUTQ
4521
      DEBUG(D_transport) if (sx->cctx.sock >= 0)
4522
	{
4523
	int n;
4524
	if (ioctl(sx->cctx.sock, TIOCOUTQ, &n) == 0)
4525
	  debug_printf("%d bytes remain in socket output buffer\n", n);
4526
	}
4527
#endif
4190
      }
4528
      }
4191
4192
    /* Otherwise, we have an I/O error or a timeout other than after MAIL or
4529
    /* Otherwise, we have an I/O error or a timeout other than after MAIL or
4193
    ".", or some other transportation error. We defer all addresses and yield
4530
    ".", or some other transportation error. We defer all addresses and yield
4194
    DEFER, except for the case of failed add_headers expansion, or a transport
4531
    DEFER, except for the case of failed add_headers expansion, or a transport
Lines 4255-4338 Link Here
4255
    sx->send_rset, f.continue_more, yield, sx->first_addr ? "not " : "");
4592
    sx->send_rset, f.continue_more, yield, sx->first_addr ? "not " : "");
4256
4593
4257
if (sx->completed_addr && sx->ok && sx->send_quit)
4594
if (sx->completed_addr && sx->ok && sx->send_quit)
4258
  {
4595
#ifdef EXPERIMENTAL_ESMTP_LIMITS
4259
  BOOL more;
4596
  if (mail_limit = continue_sequence >= sx->max_mail)
4260
  smtp_compare_t t_compare;
4597
    {
4261
4598
    DEBUG(D_transport)
4262
  t_compare.tblock = tblock;
4599
      debug_printf("reached limit %u for MAILs per conn\n", sx->max_mail);
4263
  t_compare.current_sender_address = sender_address;
4600
    }
4264
4601
  else
4265
  if (  sx->first_addr != NULL		/* more addrs for this message */
4266
     || f.continue_more			/* more addrs for coninued-host */
4267
     || (
4268
#ifndef DISABLE_TLS
4269
	   (  tls_out.active.sock < 0  &&  !continue_proxy_cipher
4270
           || verify_check_given_host(CUSS &ob->hosts_nopass_tls, host) != OK
4271
	   )
4272
        &&
4273
#endif
4602
#endif
4274
           transport_check_waiting(tblock->name, host->name,
4275
             tblock->connection_max_messages, new_message_id, &more,
4276
	     (oicf)smtp_are_same_identities, (void*)&t_compare)
4277
     )  )
4278
    {
4603
    {
4279
    uschar *msg;
4604
    smtp_compare_t t_compare =
4280
    BOOL pass_message;
4605
      {.tblock = tblock, .current_sender_address = sender_address};
4281
4606
4282
    if (sx->send_rset)
4607
    if (  sx->first_addr			/* more addrs for this message */
4283
      if (! (sx->ok = smtp_write_command(sx, SCMD_FLUSH, "RSET\r\n") >= 0))
4608
       || f.continue_more			/* more addrs for continued-host */
4284
        {
4609
       || tcw_done && tcw			/* more messages for host */
4285
        msg = US string_sprintf("send() to %s [%s] failed: %s", host->name,
4610
       || (
4286
          host->address, strerror(errno));
4611
#ifndef DISABLE_TLS
4287
        sx->send_quit = FALSE;
4612
	     (  tls_out.active.sock < 0  &&  !continue_proxy_cipher
4288
        }
4613
	     || verify_check_given_host(CUSS &ob->hosts_nopass_tls, host) != OK
4289
      else if (! (sx->ok = smtp_read_response(sx, sx->buffer, sizeof(sx->buffer),
4614
	     )
4290
		  '2', ob->command_timeout)))
4615
	  &&
4291
        {
4616
#endif
4292
        int code;
4617
	     transport_check_waiting(tblock->name, host->name,
4293
        sx->send_quit = check_response(host, &errno, 0, sx->buffer, &code, &msg,
4618
	       sx->max_mail, new_message_id,
4294
          &pass_message);
4619
	       (oicf)smtp_are_same_identities, (void*)&t_compare)
4295
        if (!sx->send_quit)
4620
       )  )
4296
          {
4621
      {
4297
          DEBUG(D_transport) debug_printf("H=%s [%s] %s\n",
4622
      uschar *msg;
4298
	    host->name, host->address, msg);
4623
      BOOL pass_message;
4299
          }
4300
        }
4301
4624
4302
    /* Either RSET was not needed, or it succeeded */
4625
      if (sx->send_rset)
4626
	if (! (sx->ok = smtp_write_command(sx, SCMD_FLUSH, "RSET\r\n") >= 0))
4627
	  {
4628
	  msg = US string_sprintf("smtp send to %s [%s] failed: %s", host->name,
4629
	    host->address, strerror(errno));
4630
	  sx->send_quit = FALSE;
4631
	  }
4632
	else if (! (sx->ok = smtp_read_response(sx, sx->buffer, sizeof(sx->buffer),
4633
		    '2', ob->command_timeout)))
4634
	  {
4635
	  int code;
4636
	  sx->send_quit = check_response(host, &errno, 0, sx->buffer, &code, &msg,
4637
	    &pass_message);
4638
	  if (!sx->send_quit)
4639
	    {
4640
	    DEBUG(D_transport) debug_printf("H=%s [%s] %s\n",
4641
	      host->name, host->address, msg);
4642
	    }
4643
	  }
4303
4644
4304
    if (sx->ok)
4645
      /* Either RSET was not needed, or it succeeded */
4305
      {
4646
4647
      if (sx->ok)
4648
	{
4306
#ifndef DISABLE_TLS
4649
#ifndef DISABLE_TLS
4307
      int pfd[2];
4650
	int pfd[2];
4308
#endif
4651
#endif
4309
      int socket_fd = sx->cctx.sock;
4652
	int socket_fd = sx->cctx.sock;
4310
4311
4653
4312
      if (sx->first_addr != NULL)	/* More addresses still to be sent */
4654
	if (sx->first_addr)		/* More addresses still to be sent */
4313
        {				/*   for this message              */
4655
	  {				/*   for this message              */
4314
        continue_sequence++;		/* Causes * in logging */
4656
#ifdef EXPERIMENTAL_ESMTP_LIMITS
4315
	pipelining_active = sx->pipelining_used;    /* was cleared at DATA */
4657
	  /* Any that we marked as skipped, reset to do now */
4316
        goto SEND_MESSAGE;
4658
	  for (address_item * a = sx->first_addr; a; a = a->next)
4317
        }
4659
	    if (a->transport_return == SKIP)
4660
	      a->transport_return = PENDING_DEFER;
4661
#endif
4662
	  continue_sequence++;				/* for consistency */
4663
	  clearflag(sx->first_addr, af_new_conn);
4664
	  setflag(sx->first_addr, af_cont_conn);	/* Causes * in logging */
4665
	  pipelining_active = sx->pipelining_used;	/* was cleared at DATA */
4666
	  goto SEND_MESSAGE;
4667
	  }
4318
4668
4319
      /* Unless caller said it already has more messages listed for this host,
4669
	/* Unless caller said it already has more messages listed for this host,
4320
      pass the connection on to a new Exim process (below, the call to
4670
	pass the connection on to a new Exim process (below, the call to
4321
      transport_pass_socket).  If the caller has more ready, just return with
4671
	transport_pass_socket).  If the caller has more ready, just return with
4322
      the connection still open. */
4672
	the connection still open. */
4323
4673
4324
#ifndef DISABLE_TLS
4674
#ifndef DISABLE_TLS
4325
      if (tls_out.active.sock >= 0)
4675
	if (tls_out.active.sock >= 0)
4326
	if (  f.continue_more
4676
	  if (  f.continue_more
4327
	   || verify_check_given_host(CUSS &ob->hosts_noproxy_tls, host) == OK)
4677
	     || verify_check_given_host(CUSS &ob->hosts_noproxy_tls, host) == OK)
4328
	  {
4678
	    {
4329
	  /* Before passing the socket on, or returning to caller with it still
4679
	    /* Before passing the socket on, or returning to caller with it still
4330
	  open, we must shut down TLS.  Not all MTAs allow for the continuation
4680
	    open, we must shut down TLS.  Not all MTAs allow for the continuation
4331
	  of the SMTP session when TLS is shut down. We test for this by sending
4681
	    of the SMTP session when TLS is shut down. We test for this by sending
4332
	  a new EHLO. If we don't get a good response, we don't attempt to pass
4682
	    a new EHLO. If we don't get a good response, we don't attempt to pass
4333
	  the socket on. */
4683
	    the socket on. */
4334
4684
4335
	  tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WAIT);
4685
	  tls_close(sx->cctx.tls_ctx,
4686
	    sx->send_tlsclose ? TLS_SHUTDOWN_WAIT : TLS_SHUTDOWN_WONLY);
4687
	  sx->send_tlsclose = FALSE;
4336
	  sx->cctx.tls_ctx = NULL;
4688
	  sx->cctx.tls_ctx = NULL;
4337
	  tls_out.active.sock = -1;
4689
	  tls_out.active.sock = -1;
4338
	  smtp_peer_options = smtp_peer_options_wrap;
4690
	  smtp_peer_options = smtp_peer_options_wrap;
Lines 4342-4457 Link Here
4342
	    && smtp_read_response(sx, sx->buffer, sizeof(sx->buffer),
4694
	    && smtp_read_response(sx, sx->buffer, sizeof(sx->buffer),
4343
				      '2', ob->command_timeout);
4695
				      '2', ob->command_timeout);
4344
4696
4345
	  if (sx->ok && f.continue_more)
4697
	    if (sx->ok && f.continue_more)
4346
	    goto TIDYUP;		/* More addresses for another run */
4698
	      goto TIDYUP;		/* More addresses for another run */
4347
	  }
4699
	    }
4348
	else
4349
	  {
4350
	  /* Set up a pipe for proxying TLS for the new transport process */
4351
4352
	  smtp_peer_options |= OPTION_TLS;
4353
	  if ((sx->ok = socketpair(AF_UNIX, SOCK_STREAM, 0, pfd) == 0))
4354
	    socket_fd = pfd[1];
4355
	  else
4700
	  else
4356
	    set_errno(sx->first_addr, errno, US"internal allocation problem",
4701
	    {
4357
		    DEFER, FALSE, host,
4702
	    /* Set up a pipe for proxying TLS for the new transport process */
4703
4704
	    smtp_peer_options |= OPTION_TLS;
4705
	    if ((sx->ok = socketpair(AF_UNIX, SOCK_STREAM, 0, pfd) == 0))
4706
	      socket_fd = pfd[1];
4707
	    else
4708
	      set_errno(sx->first_addr, errno, US"internal allocation problem",
4709
		      DEFER, FALSE, host,
4358
# ifdef EXPERIMENTAL_DSN_INFO
4710
# ifdef EXPERIMENTAL_DSN_INFO
4359
		    sx->smtp_greeting, sx->helo_response,
4711
		      sx->smtp_greeting, sx->helo_response,
4360
# endif
4712
# endif
4361
		    &sx->delivery_start);
4713
		      &sx->delivery_start);
4362
	  }
4714
	    }
4363
      else
4715
	else
4364
#endif
4716
#endif
4365
	if (f.continue_more)
4717
	  if (f.continue_more)
4366
	  goto TIDYUP;			/* More addresses for another run */
4718
	    goto TIDYUP;			/* More addresses for another run */
4367
4368
      /* If the socket is successfully passed, we mustn't send QUIT (or
4369
      indeed anything!) from here. */
4370
4719
4371
/*XXX DSN_INFO: assume likely to do new HELO; but for greet we'll want to
4720
	/* If the socket is successfully passed, we mustn't send QUIT (or
4372
propagate it from the initial
4721
	indeed anything!) from here. */
4373
*/
4374
      if (sx->ok && transport_pass_socket(tblock->name, host->name,
4375
	    host->address, new_message_id, socket_fd))
4376
	{
4377
        sx->send_quit = FALSE;
4378
4722
4379
	/* We have passed the client socket to a fresh transport process.
4723
  /*XXX DSN_INFO: assume likely to do new HELO; but for greet we'll want to
4380
	If TLS is still active, we need to proxy it for the transport we
4724
  propagate it from the initial
4381
	just passed the baton to.  Fork a child to to do it, and return to
4725
  */
4382
	get logging done asap.  Which way to place the work makes assumptions
4726
	if (sx->ok && transport_pass_socket(tblock->name, host->name,
4383
	about post-fork prioritisation which may not hold on all platforms. */
4727
	      host->address, new_message_id, socket_fd
4384
#ifndef DISABLE_TLS
4728
#ifdef EXPERIMENTAL_ESMTP_LIMITS
4385
	if (tls_out.active.sock >= 0)
4729
	      , sx->peer_limit_mail, sx->peer_limit_rcpt, sx->peer_limit_rcptdom
4730
#endif
4731
	      ))
4386
	  {
4732
	  {
4387
	  int pid = exim_fork(US"tls-proxy-interproc");
4733
	  sx->send_quit = FALSE;
4388
	  if (pid == 0)		/* child; fork again to disconnect totally */
4389
	    {
4390
	    /* does not return */
4391
	    smtp_proxy_tls(sx->cctx.tls_ctx, sx->buffer, sizeof(sx->buffer), pfd,
4392
			    ob->command_timeout);
4393
	    }
4394
4734
4395
	  if (pid > 0)		/* parent */
4735
	  /* We have passed the client socket to a fresh transport process.
4736
	  If TLS is still active, we need to proxy it for the transport we
4737
	  just passed the baton to.  Fork a child to to do it, and return to
4738
	  get logging done asap.  Which way to place the work makes assumptions
4739
	  about post-fork prioritisation which may not hold on all platforms. */
4740
#ifndef DISABLE_TLS
4741
	  if (tls_out.active.sock >= 0)
4396
	    {
4742
	    {
4397
	    close(pfd[0]);
4743
	    int pid = exim_fork(US"tls-proxy-interproc");
4398
	    /* tidy the inter-proc to disconn the proxy proc */
4744
	    if (pid == 0)		/* child; fork again to disconnect totally */
4399
	    waitpid(pid, NULL, 0);
4745
	      {
4400
	    tls_close(sx->cctx.tls_ctx, TLS_NO_SHUTDOWN);
4746
	      /* does not return */
4401
	    sx->cctx.tls_ctx = NULL;
4747
	      smtp_proxy_tls(sx->cctx.tls_ctx, sx->buffer, sizeof(sx->buffer), pfd,
4402
	    (void)close(sx->cctx.sock);
4748
			      ob->command_timeout, host->name);
4403
	    sx->cctx.sock = -1;
4749
	      }
4404
	    continue_transport = NULL;
4750
4405
	    continue_hostname = NULL;
4751
	    if (pid > 0)		/* parent */
4406
	    goto TIDYUP;
4752
	      {
4753
	      close(pfd[0]);
4754
	      /* tidy the inter-proc to disconn the proxy proc */
4755
	      waitpid(pid, NULL, 0);
4756
	      tls_close(sx->cctx.tls_ctx, TLS_NO_SHUTDOWN);
4757
	      sx->cctx.tls_ctx = NULL;
4758
	      (void)close(sx->cctx.sock);
4759
	      sx->cctx.sock = -1;
4760
	      continue_transport = NULL;
4761
	      continue_hostname = NULL;
4762
	      goto TIDYUP;
4763
	      }
4764
	    log_write(0, LOG_PANIC_DIE, "fork failed");
4407
	    }
4765
	    }
4408
	  log_write(0, LOG_PANIC_DIE, "fork failed");
4409
	  }
4410
#endif
4766
#endif
4767
	  }
4411
	}
4768
	}
4412
      }
4413
4769
4414
    /* If RSET failed and there are addresses left, they get deferred. */
4770
      /* If RSET failed and there are addresses left, they get deferred. */
4415
    else
4771
      else
4416
      set_errno(sx->first_addr, errno, msg, DEFER, FALSE, host,
4772
	set_errno(sx->first_addr, errno, msg, DEFER, FALSE, host,
4417
#ifdef EXPERIMENTAL_DSN_INFO
4773
#ifdef EXPERIMENTAL_DSN_INFO
4418
		  sx->smtp_greeting, sx->helo_response,
4774
		    sx->smtp_greeting, sx->helo_response,
4419
#endif
4775
#endif
4420
		  &sx->delivery_start);
4776
		    &sx->delivery_start);
4777
      }
4421
    }
4778
    }
4422
  }
4423
4779
4424
/* End off tidily with QUIT unless the connection has died or the socket has
4780
/* End off tidily with QUIT unless the connection has died or the socket has
4425
been passed to another process. There has been discussion on the net about what
4781
been passed to another process. */
4426
to do after sending QUIT. The wording of the RFC suggests that it is necessary
4427
to wait for a response, but on the other hand, there isn't anything one can do
4428
with an error response, other than log it. Exim used to do that. However,
4429
further discussion suggested that it is positively advantageous not to wait for
4430
the response, but to close the session immediately. This is supposed to move
4431
the TCP/IP TIME_WAIT state from the server to the client, thereby removing some
4432
load from the server. (Hosts that are both servers and clients may not see much
4433
difference, of course.) Further discussion indicated that this was safe to do
4434
on Unix systems which have decent implementations of TCP/IP that leave the
4435
connection around for a while (TIME_WAIT) after the application has gone away.
4436
This enables the response sent by the server to be properly ACKed rather than
4437
timed out, as can happen on broken TCP/IP implementations on other OS.
4438
4439
This change is being made on 31-Jul-98. After over a year of trouble-free
4440
operation, the old commented-out code was removed on 17-Sep-99. */
4441
4782
4442
SEND_QUIT:
4783
SEND_QUIT:
4443
#ifdef TCP_CORK
4784
if (sx->send_quit)
4444
(void) setsockopt(sx->cctx.sock, IPPROTO_TCP, TCP_CORK, US &on, sizeof(on));
4785
  {			/* Use _MORE to get QUIT in FIN segment */
4786
  (void)smtp_write_command(sx, SCMD_MORE, "QUIT\r\n");
4787
#ifndef DISABLE_TLS
4788
  if (sx->cctx.tls_ctx && sx->send_tlsclose)
4789
    {
4790
# ifdef EXIM_TCP_CORK	/* Use _CORK to get TLS Close Notify in FIN segment */
4791
    (void) setsockopt(sx->cctx.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on));
4792
# endif
4793
    tls_shutdown_wr(sx->cctx.tls_ctx);
4794
    sx->send_tlsclose = FALSE;
4795
    }
4445
#endif
4796
#endif
4446
if (sx->send_quit) (void)smtp_write_command(sx, SCMD_FLUSH, "QUIT\r\n");
4797
  }
4447
4798
4448
END_OFF:
4799
END_OFF:
4449
4800
4450
#ifndef DISABLE_TLS
4451
tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_NOWAIT);
4452
sx->cctx.tls_ctx = NULL;
4453
#endif
4454
4455
/* Close the socket, and return the appropriate value, first setting
4801
/* Close the socket, and return the appropriate value, first setting
4456
works because the NULL setting is passed back to the calling process, and
4802
works because the NULL setting is passed back to the calling process, and
4457
remote_max_parallel is forced to 1 when delivering over an existing connection,
4803
remote_max_parallel is forced to 1 when delivering over an existing connection,
Lines 4462-4481 Link Here
4462
specified in the transports, and therefore not visible at top level, in which
4808
specified in the transports, and therefore not visible at top level, in which
4463
case continue_more won't get set. */
4809
case continue_more won't get set. */
4464
4810
4465
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP(close)>>\n");
4466
if (sx->send_quit)
4811
if (sx->send_quit)
4467
  {
4812
  {
4813
  /* This flushes data queued in the socket, being the QUIT and any TLS Close,
4814
  sending them along with the client FIN flag.  Us (we hope) sending FIN first
4815
  means we (client) take the TIME_WAIT state, so the server (which likely has a
4816
  higher connection rate) does not have to. */
4817
4818
  HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP(shutdown)>>\n");
4468
  shutdown(sx->cctx.sock, SHUT_WR);
4819
  shutdown(sx->cctx.sock, SHUT_WR);
4469
  millisleep(20);
4470
  testharness_pause_ms(200);
4471
  if (fcntl(sx->cctx.sock, F_SETFL, O_NONBLOCK) == 0)
4472
    for (int i = 16; read(sx->cctx.sock, sx->inbuffer, sizeof(sx->inbuffer)) > 0 && i > 0;)
4473
      i--;				/* drain socket */
4474
  }
4820
  }
4821
4822
if (sx->send_quit || tcw_done && !tcw)
4823
  {
4824
  /* Wait for (we hope) ack of our QUIT, and a server FIN.  Discard any data
4825
  received, then discard the socket.  Any packet received after then, or receive
4826
  data still in the socket, will get a RST - hence the pause/drain. */
4827
4828
  /* Reap the response to QUIT, timing out after one second */
4829
  (void) smtp_read_response(sx, sx->buffer, sizeof(sx->buffer), '2', 1);
4830
#ifndef DISABLE_TLS
4831
  if (sx->cctx.tls_ctx)
4832
    {
4833
    int n;
4834
4835
    /* Reap the TLS Close Notify from the server, timing out after one second */
4836
    sigalrm_seen = FALSE;
4837
    ALARM(1);
4838
    do
4839
      n = tls_read(sx->cctx.tls_ctx, sx->inbuffer, sizeof(sx->inbuffer));
4840
    while (!sigalrm_seen && n > 0);
4841
    ALARM_CLR(0);
4842
4843
    if (sx->send_tlsclose)
4844
      {
4845
# ifdef EXIM_TCP_CORK
4846
      (void) setsockopt(sx->cctx.sock, IPPROTO_TCP, EXIM_TCP_CORK, US &on, sizeof(on));
4847
# endif
4848
      tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WAIT);
4849
      }
4850
    else
4851
      tls_close(sx->cctx.tls_ctx, TLS_SHUTDOWN_WONLY);
4852
    sx->cctx.tls_ctx = NULL;
4853
    }
4854
#endif
4855
4856
  /* Drain any trailing data from the socket before close, to avoid sending a RST */
4857
4858
  if (  poll_one_fd(sx->cctx.sock, POLLIN, 20) != 0		/* 20ms */
4859
     && fcntl(sx->cctx.sock, F_SETFL, O_NONBLOCK) == 0)
4860
    for (int i = 16, n;						/* drain socket */
4861
	 (n = read(sx->cctx.sock, sx->inbuffer, sizeof(sx->inbuffer))) > 0 && i > 0;
4862
	 i--) HDEBUG(D_transport|D_acl|D_v)
4863
      {
4864
      int m = MIN(n, 64);
4865
      debug_printf_indent("  SMTP(drain %d bytes)<< %.*s\n", n, m, sx->inbuffer);
4866
      for (m = 0; m < n; m++)
4867
	debug_printf("0x%02x\n", sx->inbuffer[m]);
4868
      }
4869
  }
4870
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP(close)>>\n");
4475
(void)close(sx->cctx.sock);
4871
(void)close(sx->cctx.sock);
4872
sx->cctx.sock = -1;
4873
continue_transport = NULL;
4874
continue_hostname = NULL;
4875
smtp_debug_cmd_report();
4476
4876
4477
#ifndef DISABLE_EVENT
4877
#ifndef DISABLE_EVENT
4478
(void) event_raise(tblock->event_action, US"tcp:close", NULL);
4878
(void) event_raise(tblock->event_action, US"tcp:close", NULL, NULL);
4479
#endif
4879
#endif
4480
4880
4481
#ifdef SUPPORT_DANE
4881
#ifdef SUPPORT_DANE
Lines 4492-4506 Link Here
4492
	to get the domain string for SNI */
4892
	to get the domain string for SNI */
4493
4893
4494
	sx->first_addr = a;
4894
	sx->first_addr = a;
4895
	clearflag(a, af_cont_conn);
4896
	setflag(a, af_new_conn);		/* clear * from logging */
4495
	DEBUG(D_transport) debug_printf("DANE: go-around for %s\n", a->domain);
4897
	DEBUG(D_transport) debug_printf("DANE: go-around for %s\n", a->domain);
4496
	}
4898
	}
4497
      }
4899
      }
4498
  goto DANE_DOMAINS;
4900
  continue_sequence = 1;			/* for consistency */
4901
  goto REPEAT_CONN;
4902
  }
4903
#endif
4904
4905
#ifdef EXPERIMENTAL_ESMTP_LIMITS
4906
if (mail_limit && sx->first_addr)
4907
  {
4908
  /* Reset the sequence count since we closed the connection.  This is flagged
4909
  on the pipe back to the delivery process so that a non-continued-conn delivery
4910
  is logged. */
4911
4912
  continue_sequence = 1;			/* for consistency */
4913
  clearflag(sx->first_addr, af_cont_conn);
4914
  setflag(sx->first_addr, af_new_conn);		/* clear  * from logging */
4915
  goto REPEAT_CONN;
4499
  }
4916
  }
4500
#endif
4917
#endif
4501
4918
4502
continue_transport = NULL;
4503
continue_hostname = NULL;
4504
return yield;
4919
return yield;
4505
4920
4506
TIDYUP:
4921
TIDYUP:
Lines 4662-4667 Link Here
4662
      cutthrough.cctx.sock >= 0 ? cutthrough.cctx.sock : 0);
5077
      cutthrough.cctx.sock >= 0 ? cutthrough.cctx.sock : 0);
4663
  }
5078
  }
4664
5079
5080
/* Check the restrictions on line length */
5081
5082
if (max_received_linelength > ob->message_linelength_limit)
5083
  {
5084
  struct timeval now;
5085
  gettimeofday(&now, NULL);
5086
5087
  for (address_item * addr = addrlist; addr; addr = addr->next)
5088
    if (addr->transport_return == DEFER)
5089
      addr->transport_return = PENDING_DEFER;
5090
5091
  set_errno_nohost(addrlist, ERRNO_SMTPFORMAT,
5092
    US"message has lines too long for transport", FAIL, TRUE, &now);
5093
  goto END_TRANSPORT;
5094
  }
5095
4665
/* Set the flag requesting that these hosts be added to the waiting
5096
/* Set the flag requesting that these hosts be added to the waiting
4666
database if the delivery fails temporarily or if we are running with
5097
database if the delivery fails temporarily or if we are running with
4667
queue_smtp or a 2-stage queue run. This gets unset for certain
5098
queue_smtp or a 2-stage queue run. This gets unset for certain
Lines 4699-4705 Link Here
4699
    {
5130
    {
4700
    uschar *s = ob->hosts;
5131
    uschar *s = ob->hosts;
4701
5132
4702
    if (Ustrchr(s, '$') != NULL)
5133
    if (Ustrchr(s, '$'))
4703
      {
5134
      {
4704
      if (!(expanded_hosts = expand_string(s)))
5135
      if (!(expanded_hosts = expand_string(s)))
4705
        {
5136
        {
Lines 5047-5053 Link Here
5047
    because connections to the same host from a different interface should be
5478
    because connections to the same host from a different interface should be
5048
    treated separately. */
5479
    treated separately. */
5049
5480
5050
    host_af = Ustrchr(host->address, ':') == NULL ? AF_INET : AF_INET6;
5481
    host_af = Ustrchr(host->address, ':') ? AF_INET6 : AF_INET;
5051
      {
5482
      {
5052
      uschar * s = ob->interface;
5483
      uschar * s = ob->interface;
5053
      if (s && *s)
5484
      if (s && *s)
Lines 5216-5222 Link Here
5216
5647
5217
      if (expanded_hosts)
5648
      if (expanded_hosts)
5218
	{
5649
	{
5219
	thost = store_get(sizeof(host_item), FALSE);
5650
	thost = store_get(sizeof(host_item), GET_UNTAINTED);
5220
	*thost = *host;
5651
	*thost = *host;
5221
	thost->name = string_copy(host->name);
5652
	thost->name = string_copy(host->name);
5222
	thost->address = string_copy(host->address);
5653
	thost->address = string_copy(host->address);
(-)exim.orig/src/transports/smtp.h (-67 / +110 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
#define DELIVER_BUFFER_SIZE 4096
9
#define DELIVER_BUFFER_SIZE 4096
Lines 13-108 Link Here
13
#define PENDING_OK      (PENDING + OK)
13
#define PENDING_OK      (PENDING + OK)
14
14
15
15
16
#ifndef DISABLE_TLS
17
/* Flags structure for validity of TLS configuration */
18
19
typedef struct {
20
  BOOL conn_certs:1;		/* certificates etc. loaded */
21
  BOOL cabundle:1;		/* CA certificates loaded */
22
  BOOL crl:1;			/* CRL loaded */
23
  BOOL pri_string:1;		/* cipher priority-string cache loaded */
24
  BOOL dh:1;			/* Diffie-Helman params loaded */
25
  BOOL ecdh:1;			/* EC Diffie-Helman params loaded */
26
27
  BOOL ca_rdn_emulate:1;	/* do not advertise usable-cert list */
28
  BOOL ocsp_hook:1;		/* need hshake callback on session */
29
30
  void * libdata0;		/* library-dependent preloaded data */
31
  void * libdata1;		/* library-dependent preloaded data */
32
} exim_tlslib_state;
33
#endif
34
35
16
/* Private structure for the private options and other private data. */
36
/* Private structure for the private options and other private data. */
17
37
18
typedef struct {
38
typedef struct {
19
  uschar *hosts;
39
  uschar	*hosts;
20
  uschar *fallback_hosts;
40
  uschar	*fallback_hosts;
21
  host_item *hostlist;
41
  host_item	*hostlist;
22
  host_item *fallback_hostlist;
42
  host_item	*fallback_hostlist;
23
  uschar *authenticated_sender;
43
  uschar	*authenticated_sender;
24
  uschar *helo_data;
44
  uschar	*helo_data;
25
  uschar *interface;
45
  uschar	*interface;
26
  uschar *port;
46
  uschar	*port;
27
  uschar *protocol;
47
  uschar	*protocol;
28
  uschar *dscp;
48
  uschar	*dscp;
29
  uschar *serialize_hosts;
49
  uschar	*serialize_hosts;
30
  uschar *hosts_try_auth;
50
  uschar	*hosts_try_auth;
31
  uschar *hosts_require_auth;
51
  uschar	*hosts_require_alpn;
32
  uschar *hosts_try_chunking;
52
  uschar	*hosts_require_auth;
53
  uschar	*hosts_try_chunking;
33
#ifdef SUPPORT_DANE
54
#ifdef SUPPORT_DANE
34
  uschar *hosts_try_dane;
55
  uschar	*hosts_try_dane;
35
  uschar *hosts_require_dane;
56
  uschar	*hosts_require_dane;
36
  uschar *dane_require_tls_ciphers;
57
  uschar	*dane_require_tls_ciphers;
37
#endif
58
#endif
38
  uschar *hosts_try_fastopen;
59
  uschar	*hosts_try_fastopen;
39
#ifndef DISABLE_PRDR
60
#ifndef DISABLE_PRDR
40
  uschar *hosts_try_prdr;
61
  uschar	*hosts_try_prdr;
41
#endif
62
#endif
42
#ifndef DISABLE_OCSP
63
#ifndef DISABLE_OCSP
43
  uschar *hosts_request_ocsp;
64
  uschar	*hosts_request_ocsp;
44
  uschar *hosts_require_ocsp;
65
  uschar	*hosts_require_ocsp;
45
#endif
66
#endif
46
  uschar *hosts_require_tls;
67
  uschar	*hosts_require_tls;
47
  uschar *hosts_avoid_tls;
68
  uschar	*hosts_avoid_tls;
48
  uschar *hosts_verify_avoid_tls;
69
  uschar	*hosts_verify_avoid_tls;
49
  uschar *hosts_avoid_pipelining;
70
  uschar	*hosts_avoid_pipelining;
50
#ifndef DISABLE_PIPE_CONNECT
71
#ifndef DISABLE_PIPE_CONNECT
51
  uschar *hosts_pipe_connect;
72
  uschar	*hosts_pipe_connect;
52
#endif
73
#endif
53
  uschar *hosts_avoid_esmtp;
74
  uschar	*hosts_avoid_esmtp;
54
#ifndef DISABLE_TLS
75
#ifndef DISABLE_TLS
55
  uschar *hosts_nopass_tls;
76
  uschar	*hosts_nopass_tls;
56
  uschar *hosts_noproxy_tls;
77
  uschar	*hosts_noproxy_tls;
57
#endif
78
#endif
58
  int     command_timeout;
79
  int		command_timeout;
59
  int     connect_timeout;
80
  int		connect_timeout;
60
  int     data_timeout;
81
  int		data_timeout;
61
  int     final_timeout;
82
  int		final_timeout;
62
  int     size_addition;
83
  int		size_addition;
63
  int     hosts_max_try;
84
  int		hosts_max_try;
64
  int     hosts_max_try_hardlimit;
85
  int		hosts_max_try_hardlimit;
65
  BOOL    address_retry_include_sender;
86
  int		message_linelength_limit;
66
  BOOL    allow_localhost;
87
  BOOL		address_retry_include_sender;
67
  BOOL    authenticated_sender_force;
88
  BOOL		allow_localhost;
68
  BOOL    gethostbyname;
89
  BOOL		authenticated_sender_force;
69
  BOOL    dns_qualify_single;
90
  BOOL		gethostbyname;
70
  BOOL    dns_search_parents;
91
  BOOL		dns_qualify_single;
92
  BOOL		dns_search_parents;
71
  dnssec_domains dnssec;
93
  dnssec_domains dnssec;
72
  BOOL    delay_after_cutoff;
94
  BOOL		delay_after_cutoff;
73
  BOOL    hosts_override;
95
  BOOL		hosts_override;
74
  BOOL    hosts_randomize;
96
  BOOL		hosts_randomize;
75
  BOOL    keepalive;
97
  BOOL		keepalive;
76
  BOOL    lmtp_ignore_quota;
98
  BOOL		lmtp_ignore_quota;
77
  uschar *expand_retry_include_ip_address;
99
  uschar	*expand_retry_include_ip_address;
78
  BOOL    retry_include_ip_address;
100
  BOOL		retry_include_ip_address;
79
#ifdef SUPPORT_SOCKS
101
#ifdef SUPPORT_SOCKS
80
  uschar *socks_proxy;
102
  uschar	*socks_proxy;
81
#endif
103
#endif
82
#ifndef DISABLE_TLS
104
#ifndef DISABLE_TLS
83
  uschar *tls_certificate;
105
  uschar	*tls_alpn;
84
  uschar *tls_crl;
106
  uschar	*tls_certificate;
85
  uschar *tls_privatekey;
107
  uschar	*tls_crl;
86
  uschar *tls_require_ciphers;
108
  uschar	*tls_privatekey;
87
# ifdef EXPERIMENTAL_TLS_RESUME
109
  uschar	*tls_require_ciphers;
88
  uschar *tls_resumption_hosts;
110
# ifndef DISABLE_TLS_RESUME
111
  uschar	*host_name_extract;
112
  uschar	*tls_resumption_hosts;
89
# endif
113
# endif
90
  const uschar *tls_sni;
114
  const uschar	*tls_sni;
91
  uschar *tls_verify_certificates;
115
  uschar	*tls_verify_certificates;
92
  int     tls_dh_min_bits;
116
  int		tls_dh_min_bits;
93
  BOOL    tls_tempfail_tryclear;
117
  BOOL		tls_tempfail_tryclear;
94
  uschar *tls_verify_hosts;
118
  uschar	*tls_verify_hosts;
95
  uschar *tls_try_verify_hosts;
119
  uschar	*tls_try_verify_hosts;
96
  uschar *tls_verify_cert_hostnames;
120
  uschar	*tls_verify_cert_hostnames;
97
#endif
121
#endif
98
#ifdef SUPPORT_I18N
122
#ifdef SUPPORT_I18N
99
  uschar *utf8_downconvert;
123
  uschar	*utf8_downconvert;
100
#endif
124
#endif
101
#ifndef DISABLE_DKIM
125
#ifndef DISABLE_DKIM
102
  struct ob_dkim dkim;
126
  struct ob_dkim dkim;
103
#endif
127
#endif
104
#ifdef EXPERIMENTAL_ARC
128
#ifdef EXPERIMENTAL_ARC
105
  uschar *arc_sign;
129
  uschar	*arc_sign;
130
#endif
131
#ifndef DISABLE_TLS
132
  exim_tlslib_state tls_preload;
106
#endif
133
#endif
107
} smtp_transport_options_block;
134
} smtp_transport_options_block;
108
135
Lines 147-160 Link Here
147
  BOOL pending_BDAT:1;
174
  BOOL pending_BDAT:1;
148
  BOOL RCPT_452:1;
175
  BOOL RCPT_452:1;
149
  BOOL good_RCPT:1;
176
  BOOL good_RCPT:1;
177
#ifdef EXPERIMENTAL_ESMTP_LIMITS
178
  BOOL single_rcpt_domain:1;
179
#endif
150
  BOOL completed_addr:1;
180
  BOOL completed_addr:1;
151
  BOOL send_rset:1;
181
  BOOL send_rset:1;
152
  BOOL send_quit:1;
182
  BOOL send_quit:1;
183
  BOOL send_tlsclose:1;
184
185
  unsigned	peer_offered;
186
#ifdef EXPERIMENTAL_ESMTP_LIMITS
187
  unsigned	peer_limit_mail;
188
  unsigned	peer_limit_rcpt;
189
  unsigned	peer_limit_rcptdom;
190
#endif
153
191
192
  unsigned	max_mail;
154
  int		max_rcpt;
193
  int		max_rcpt;
155
  int		cmd_count;
194
  int		cmd_count;
156
195
157
  unsigned	peer_offered;
158
  unsigned	avoid_option;
196
  unsigned	avoid_option;
159
  uschar *	igquotstr;
197
  uschar *	igquotstr;
160
  uschar *	helo_data;
198
  uschar *	helo_data;
Lines 163-168 Link Here
163
  uschar *	helo_response;
201
  uschar *	helo_response;
164
#endif
202
#endif
165
#ifndef DISABLE_PIPE_CONNECT
203
#ifndef DISABLE_PIPE_CONNECT
204
  /* Info about the EHLO response stored to / retrieved from cache.  When
205
  operating early-pipe, we use the cached values.  For each of plaintext and
206
  crypted we store bitmaps for ESMTP features and AUTH methods.  If the LIMITS
207
  extension is built and usable them at least one of the limits values cached
208
  is nonzero, and we use the values to constrain the connection. */
166
  ehlo_resp_precis	ehlo_resp;
209
  ehlo_resp_precis	ehlo_resp;
167
#endif
210
#endif
168
211
(-)exim.orig/src/transports/smtp_socks.c (-18 / +15 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2021 - 2022 */
5
/* Copyright (c) Jeremy Harris 2015 - 2018 */
6
/* Copyright (c) Jeremy Harris 2015 - 2018 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 160-179 Link Here
160
socks_opts * lim = &proxies[nproxies];
161
socks_opts * lim = &proxies[nproxies];
161
long rnd, weights;
162
long rnd, weights;
162
unsigned pri;
163
unsigned pri;
163
static BOOL srandomed = FALSE;
164
164
165
if (nproxies == 1)		/* shortcut, if we have only 1 server */
165
if (nproxies == 1)		/* shortcut, if we have only 1 server */
166
  return (proxies[0].is_failed ? -1 : 0);
166
  return (proxies[0].is_failed ? -1 : 0);
167
167
168
/* init random */
169
if (!srandomed)
170
  {
171
  struct timeval tv;
172
  gettimeofday(&tv, NULL);
173
  srandom((unsigned int)(tv.tv_usec/1000));
174
  srandomed = TRUE;
175
  }
176
177
/* scan for highest pri */
168
/* scan for highest pri */
178
for (pri = 0, sd = proxies; sd < lim; sd++)
169
for (pri = 0, sd = proxies; sd < lim; sd++)
179
  if (!sd->is_failed && sd->priority > pri)
170
  if (!sd->is_failed && sd->priority > pri)
Lines 186-192 Link Here
186
if (weights == 0)       /* all servers failed */
177
if (weights == 0)       /* all servers failed */
187
  return -1;
178
  return -1;
188
179
189
for (rnd = random() % weights, i = 0; i < nproxies; i++)
180
for (rnd = random_number(weights), i = 0; i < nproxies; i++)
190
  {
181
  {
191
  sd = &proxies[i];
182
  sd = &proxies[i];
192
  if (!sd->is_failed && sd->priority == pri)
183
  if (!sd->is_failed && sd->priority == pri)
Lines 230-236 Link Here
230
uschar buf[24];
221
uschar buf[24];
231
socks_opts proxies[32];			/* max #proxies handled */
222
socks_opts proxies[32];			/* max #proxies handled */
232
unsigned nproxies;
223
unsigned nproxies;
233
socks_opts * sob;
224
socks_opts * sob = NULL;
234
unsigned size;
225
unsigned size;
235
blob early_data;
226
blob early_data;
236
227
Lines 267-272 Link Here
267
  while ((option = string_nextinlist(&proxy_spec, &subsep, NULL, 0)))
258
  while ((option = string_nextinlist(&proxy_spec, &subsep, NULL, 0)))
268
    socks_option(sob, option);
259
    socks_option(sob, option);
269
  }
260
  }
261
if (!sob) return -1;
270
262
271
/* Set up the socks protocol method-selection message,
263
/* Set up the socks protocol method-selection message,
272
for sending on connection */
264
for sending on connection */
Lines 282-288 Link Here
282
  {
274
  {
283
  int idx;
275
  int idx;
284
  host_item proxy;
276
  host_item proxy;
285
  int proxy_af;
277
  smtp_connect_args sc = {.sock = -1};
286
278
287
  if ((idx = socks_get_proxy(proxies, nproxies)) < 0)
279
  if ((idx = socks_get_proxy(proxies, nproxies)) < 0)
288
    {
280
    {
Lines 294-304 Link Here
294
286
295
  /* bodge up a host struct for the proxy */
287
  /* bodge up a host struct for the proxy */
296
  proxy.address = proxy.name = sob->proxy_host;
288
  proxy.address = proxy.name = sob->proxy_host;
297
  proxy_af = Ustrchr(sob->proxy_host, ':') ? AF_INET6 : AF_INET;
289
  proxy.port = sob->port;
290
291
  sc.tblock = tb;
292
  sc.ob = ob;
293
  sc.host = &proxy;
294
  sc.host_af = Ustrchr(sob->proxy_host, ':') ? AF_INET6 : AF_INET;
295
  sc.interface = interface;
298
296
299
  /*XXX we trust that the method-select command is idempotent */
297
  /*XXX we trust that the method-select command is idempotent */
300
  if ((fd = smtp_sock_connect(&proxy, proxy_af, sob->port,
298
  if ((fd = smtp_sock_connect(&sc, sob->timeout, &early_data)) >= 0)
301
	      interface, tb, sob->timeout, &early_data)) >= 0)
302
    {
299
    {
303
    proxy_local_address = string_copy(proxy.address);
300
    proxy_local_address = string_copy(proxy.address);
304
    proxy_local_port = sob->port;
301
    proxy_local_port = sob->port;
Lines 330-336 Link Here
330
   )
327
   )
331
  goto proxy_err;
328
  goto proxy_err;
332
329
333
  {
330
 {
334
  union sockaddr_46 sin;
331
  union sockaddr_46 sin;
335
  (void) ip_addr(&sin, host_af, host->address, port);
332
  (void) ip_addr(&sin, host_af, host->address, port);
336
333
Lines 353-359 Link Here
353
      &sin.v4.sin_port, sizeof(sin.v4.sin_port));
350
      &sin.v4.sin_port, sizeof(sin.v4.sin_port));
354
    size = 4+sizeof(sin.v4.sin_addr.s_addr)+sizeof(sin.v4.sin_port);
351
    size = 4+sizeof(sin.v4.sin_addr.s_addr)+sizeof(sin.v4.sin_port);
355
    }
352
    }
356
  }
353
 }
357
354
358
state = US"connect";
355
state = US"connect";
359
HDEBUG(D_transport|D_acl|D_v)
356
HDEBUG(D_transport|D_acl|D_v)
(-)exim.orig/src/transports/tf_maildir.c (-13 / +14 lines)
Lines 3-9 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
6
/* Copyright (c) The Exim Maintainers 2020 - 2021 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Functions in support of the use of maildirsize files for handling quotas in
9
/* Functions in support of the use of maildirsize files for handling quotas in
Lines 140-163 Link Here
140
/* If the basic path matches maildirfolder_create_regex, we are dealing with
140
/* If the basic path matches maildirfolder_create_regex, we are dealing with
141
a subfolder, and should ensure that a maildirfolder file exists. */
141
a subfolder, and should ensure that a maildirfolder file exists. */
142
142
143
if (maildirfolder_create_regex != NULL)
143
if (maildirfolder_create_regex)
144
  {
144
  {
145
  const uschar *error;
145
  int err;
146
  int offset;
146
  PCRE2_SIZE offset;
147
  const pcre *regex;
147
  const pcre2_code * re;
148
148
149
  DEBUG(D_transport) debug_printf("checking for maildirfolder requirement\n");
149
  DEBUG(D_transport) debug_printf("checking for maildirfolder requirement\n");
150
150
151
  if (!(regex = pcre_compile(CS maildirfolder_create_regex, PCRE_COPT,
151
  if (!(re = pcre2_compile((PCRE2_SPTR)maildirfolder_create_regex,
152
    CCSS &error, &offset, NULL)))
152
	      PCRE2_ZERO_TERMINATED, PCRE_COPT, &err, &offset, pcre_cmp_ctx)))
153
    {
153
    {
154
    uschar errbuf[128];
155
    pcre2_get_error_message(err, errbuf, sizeof(errbuf));
154
    addr->message = string_sprintf("appendfile: regular expression "
156
    addr->message = string_sprintf("appendfile: regular expression "
155
      "error: %s at offset %d while compiling %s", error, offset,
157
      "error: %s at offset %ld while compiling %s", errbuf, (long)offset,
156
      maildirfolder_create_regex);
158
      maildirfolder_create_regex);
157
    return FALSE;
159
    return FALSE;
158
    }
160
    }
159
161
160
  if (pcre_exec(regex, NULL, CS path, Ustrlen(path), 0, 0, NULL, 0) >= 0)
162
  if (regex_match(re, path, -1, NULL))
161
    {
163
    {
162
    uschar *fname = string_sprintf("%s/maildirfolder", path);
164
    uschar *fname = string_sprintf("%s/maildirfolder", path);
163
    if (Ustat(fname, &statbuf) == 0)
165
    if (Ustat(fname, &statbuf) == 0)
Lines 250-256 Link Here
250
252
251
off_t
253
off_t
252
maildir_compute_size(uschar *path, int *filecount, time_t *latest,
254
maildir_compute_size(uschar *path, int *filecount, time_t *latest,
253
  const pcre *regex, const pcre *dir_regex, BOOL timestamp_only)
255
  const pcre2_code *regex, const pcre2_code *dir_regex, BOOL timestamp_only)
254
{
256
{
255
DIR *dir;
257
DIR *dir;
256
off_t sum = 0;
258
off_t sum = 0;
Lines 269-276 Link Here
269
  scan. We do the regex match first, because that avoids a stat() for names
271
  scan. We do the regex match first, because that avoids a stat() for names
270
  we aren't interested in. */
272
  we aren't interested in. */
271
273
272
  if (dir_regex != NULL &&
274
  if (dir_regex && !regex_match(dir_regex, name, -1, NULL))
273
      pcre_exec(dir_regex, NULL, CS name, Ustrlen(name), 0, 0, NULL, 0) < 0)
274
    {
275
    {
275
    DEBUG(D_transport)
276
    DEBUG(D_transport)
276
      debug_printf("skipping %s/%s: dir_regex does not match\n", path, name);
277
      debug_printf("skipping %s/%s: dir_regex does not match\n", path, name);
Lines 358-364 Link Here
358
359
359
int
360
int
360
maildir_ensure_sizefile(uschar *path, appendfile_transport_options_block *ob,
361
maildir_ensure_sizefile(uschar *path, appendfile_transport_options_block *ob,
361
  const pcre *regex, const pcre *dir_regex, off_t *returned_size,
362
  const pcre2_code *regex, const pcre2_code *dir_regex, off_t *returned_size,
362
  int *returned_filecount)
363
  int *returned_filecount)
363
{
364
{
364
int count, fd;
365
int count, fd;
(-)exim.orig/src/transports/tf_maildir.h (-4 / +5 lines)
Lines 3-20 Link Here
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) University of Cambridge 1995 - 2009 */
5
/* Copyright (c) University of Cambridge 1995 - 2009 */
6
/* Copyright (c) The Exim Maintainers 2021 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
8
/* Header file for the functions that are used to support the use of
9
/* Header file for the functions that are used to support the use of
9
maildirsize files for quota handling in maildir directories. */
10
maildirsize files for quota handling in maildir directories. */
10
11
11
extern off_t  maildir_compute_size(uschar *, int *, time_t *, const pcre *,
12
extern off_t  maildir_compute_size(uschar *, int *, time_t *, const pcre2_code *,
12
                const pcre *, BOOL);
13
                const pcre2_code *, BOOL);
13
extern BOOL   maildir_ensure_directories(uschar *, address_item *, BOOL, int,
14
extern BOOL   maildir_ensure_directories(uschar *, address_item *, BOOL, int,
14
                uschar *);
15
                uschar *);
15
extern int    maildir_ensure_sizefile(uschar *,
16
extern int    maildir_ensure_sizefile(uschar *,
16
                appendfile_transport_options_block *, const pcre *,
17
                appendfile_transport_options_block *, const pcre2_code *,
17
                const pcre *, off_t *, int *);
18
                const pcre2_code *, off_t *, int *);
18
extern void   maildir_record_length(int, int);
19
extern void   maildir_record_length(int, int);
19
20
20
/* End of tf_maildir.h */
21
/* End of tf_maildir.h */
(-)exim.orig/src/tree.c (-4 / +5 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2021 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2015 */
6
/* Copyright (c) University of Cambridge 1995 - 2015 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 30-36 Link Here
30
tree_add_nonrecipient(const uschar *s)
31
tree_add_nonrecipient(const uschar *s)
31
{
32
{
32
rmark rpoint = store_mark();
33
rmark rpoint = store_mark();
33
tree_node *node = store_get(sizeof(tree_node) + Ustrlen(s), is_tainted(s));
34
tree_node * node = store_get(sizeof(tree_node) + Ustrlen(s), s);
34
Ustrcpy(node->name, s);
35
Ustrcpy(node->name, s);
35
node->data.ptr = NULL;
36
node->data.ptr = NULL;
36
if (!tree_insertnode(&tree_nonrecipients, node)) store_reset(rpoint);
37
if (!tree_insertnode(&tree_nonrecipients, node)) store_reset(rpoint);
Lines 55-61 Link Here
55
tree_add_duplicate(const uschar *s, address_item *addr)
56
tree_add_duplicate(const uschar *s, address_item *addr)
56
{
57
{
57
rmark rpoint = store_mark();
58
rmark rpoint = store_mark();
58
tree_node *node = store_get(sizeof(tree_node) + Ustrlen(s), is_tainted(s));
59
tree_node * node = store_get(sizeof(tree_node) + Ustrlen(s), s);
59
Ustrcpy(node->name, s);
60
Ustrcpy(node->name, s);
60
node->data.ptr = addr;
61
node->data.ptr = addr;
61
if (!tree_insertnode(&tree_duplicates, node)) store_reset(rpoint);
62
if (!tree_insertnode(&tree_duplicates, node)) store_reset(rpoint);
Lines 81-87 Link Here
81
uschar s[256];
82
uschar s[256];
82
sprintf(CS s, "T:%.200s:%s", h->name, h->address);
83
sprintf(CS s, "T:%.200s:%s", h->name, h->address);
83
node = store_get(sizeof(tree_node) + Ustrlen(s),
84
node = store_get(sizeof(tree_node) + Ustrlen(s),
84
			is_tainted(h->name) || is_tainted(h->address));
85
	    is_tainted(h->name) || is_tainted(h->address) ? GET_TAINTED : GET_UNTAINTED);
85
Ustrcpy(node->name, s);
86
Ustrcpy(node->name, s);
86
node->data.val = h->why;
87
node->data.val = h->why;
87
if (h->status == hstatus_unusable_expired) node->data.val += 256;
88
if (h->status == hstatus_unusable_expired) node->data.val += 256;
Lines 373-379 Link Here
373
tree_add_var(uschar * name, uschar * val, void * ctx)
374
tree_add_var(uschar * name, uschar * val, void * ctx)
374
{
375
{
375
tree_node ** root = ctx;
376
tree_node ** root = ctx;
376
tree_node * node = store_get(sizeof(tree_node) + Ustrlen(name), is_tainted(name));
377
tree_node * node = store_get(sizeof(tree_node) + Ustrlen(name), name);
377
Ustrcpy(node->name, name);
378
Ustrcpy(node->name, name);
378
node->data.ptr = val;
379
node->data.ptr = val;
379
(void) tree_insertnode(root, node);
380
(void) tree_insertnode(root, node);
(-)exim.orig/src/utf8.c (-10 / +17 lines)
Lines 2-7 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2022 */
5
/* Copyright (c) Jeremy Harris 2015 - 2018 */
6
/* Copyright (c) Jeremy Harris 2015 - 2018 */
6
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
7
8
Lines 133-139 Link Here
133
uschar *
134
uschar *
134
string_localpart_utf8_to_alabel(const uschar * utf8, uschar ** err)
135
string_localpart_utf8_to_alabel(const uschar * utf8, uschar ** err)
135
{
136
{
136
size_t ucs4_len;
137
size_t ucs4_len = 0;
137
punycode_uint * p;
138
punycode_uint * p;
138
size_t p_len;
139
size_t p_len;
139
uschar * res;
140
uschar * res;
Lines 142-149 Link Here
142
if (!string_is_utf8(utf8)) return string_copy(utf8);
143
if (!string_is_utf8(utf8)) return string_copy(utf8);
143
144
144
p = (punycode_uint *) stringprep_utf8_to_ucs4(CCS utf8, -1, &ucs4_len);
145
p = (punycode_uint *) stringprep_utf8_to_ucs4(CCS utf8, -1, &ucs4_len);
146
if (!p || !ucs4_len)
147
  {
148
  if (err) *err = US"l_u2a: bad UTF-8 input";
149
  return NULL;
150
  }
145
p_len = ucs4_len*4;	/* this multiplier is pure guesswork */
151
p_len = ucs4_len*4;	/* this multiplier is pure guesswork */
146
res = store_get(p_len+5, is_tainted(utf8));
152
res = store_get(p_len+5, utf8);
147
153
148
res[0] = 'x'; res[1] = 'n'; res[2] = res[3] = '-';
154
res[0] = 'x'; res[1] = 'n'; res[2] = res[3] = '-';
149
155
Lines 172-178 Link Here
172
DEBUG(D_expand) debug_printf("l_a2u: '%s'\n", alabel);
178
DEBUG(D_expand) debug_printf("l_a2u: '%s'\n", alabel);
173
alabel += 4;
179
alabel += 4;
174
p_len = Ustrlen(alabel);
180
p_len = Ustrlen(alabel);
175
p = store_get((p_len+1) * sizeof(*p), is_tainted(alabel));
181
p = store_get((p_len+1) * sizeof(*p), alabel);
176
182
177
if ((rc = punycode_decode(p_len, CCS alabel, &p_len, p, NULL)) != PUNYCODE_SUCCESS)
183
if ((rc = punycode_decode(p_len, CCS alabel, &p_len, p, NULL)) != PUNYCODE_SUCCESS)
178
  {
184
  {
Lines 240-267 Link Here
240
246
241
/* See a description in tls-openssl.c for an explanation of why this exists.
247
/* See a description in tls-openssl.c for an explanation of why this exists.
242
248
243
Arguments:   a FILE* to print the results to
249
Arguments:   string to append to
244
Returns:     nothing
250
Returns:     string
245
*/
251
*/
246
252
247
void
253
gstring *
248
utf8_version_report(FILE *f)
254
utf8_version_report(gstring * g)
249
{
255
{
250
#ifdef SUPPORT_I18N_2008
256
#ifdef SUPPORT_I18N_2008
251
fprintf(f, "Library version: IDN2: Compile: %s\n"
257
g = string_fmt_append(g, "Library version: IDN2: Compile: %s\n"
252
           "                       Runtime: %s\n",
258
           "                       Runtime: %s\n",
253
	IDN2_VERSION,
259
	IDN2_VERSION,
254
	idn2_check_version(NULL));
260
	idn2_check_version(NULL));
255
fprintf(f, "Library version: Stringprep: Compile: %s\n"
261
g = string_fmt_append(g, "Library version: Stringprep: Compile: %s\n"
256
           "                             Runtime: %s\n",
262
           "                             Runtime: %s\n",
257
	STRINGPREP_VERSION,
263
	STRINGPREP_VERSION,
258
	stringprep_check_version(NULL));
264
	stringprep_check_version(NULL));
259
#else
265
#else
260
fprintf(f, "Library version: IDN: Compile: %s\n"
266
g = string_fmt_append(g, "Library version: IDN: Compile: %s\n"
261
           "                      Runtime: %s\n",
267
           "                      Runtime: %s\n",
262
	STRINGPREP_VERSION,
268
	STRINGPREP_VERSION,
263
	stringprep_check_version(NULL));
269
	stringprep_check_version(NULL));
264
#endif
270
#endif
271
return g;
265
}
272
}
266
273
267
#endif	/* whole file */
274
#endif	/* whole file */
(-)exim.orig/src/verify.c (-645 / +329 lines)
Lines 2-9 Link Here
2
*     Exim - an Internet mail transport agent    *
2
*     Exim - an Internet mail transport agent    *
3
*************************************************/
3
*************************************************/
4
4
5
/* Copyright (c) The Exim Maintainers 2020 - 2022 */
5
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) University of Cambridge 1995 - 2018 */
6
/* Copyright (c) The Exim Maintainers 2020 */
7
/* See the file NOTICE for conditions of use and distribution. */
7
/* See the file NOTICE for conditions of use and distribution. */
8
8
9
/* Functions concerned with verifying things. The original code for callout
9
/* Functions concerned with verifying things. The original code for callout
Lines 19-45 Link Here
19
uschar ctbuffer[8192];
19
uschar ctbuffer[8192];
20
20
21
21
22
/* Structure for caching DNSBL lookups */
23
24
typedef struct dnsbl_cache_block {
25
  time_t expiry;
26
  dns_address *rhs;
27
  uschar *text;
28
  int rc;
29
  BOOL text_set;
30
} dnsbl_cache_block;
31
32
33
/* Anchor for DNSBL cache */
34
35
static tree_node *dnsbl_cache = NULL;
36
37
38
/* Bits for match_type in one_check_dnsbl() */
39
40
#define MT_NOT 1
41
#define MT_ALL 2
42
43
static uschar cutthrough_response(client_conn_ctx *, char, uschar **, int);
22
static uschar cutthrough_response(client_conn_ctx *, char, uschar **, int);
44
23
45
24
Lines 71-77 Link Here
71
50
72
if (!(cache_record = dbfn_read_with_length(dbm_file, key, &length)))
51
if (!(cache_record = dbfn_read_with_length(dbm_file, key, &length)))
73
  {
52
  {
74
  HDEBUG(D_verify) debug_printf("callout cache: no %s record found for %s\n", type, key);
53
  HDEBUG(D_verify) debug_printf_indent("callout cache: no %s record found for %s\n", type, key);
75
  return NULL;
54
  return NULL;
76
  }
55
  }
77
56
Lines 85-91 Link Here
85
64
86
if (now - cache_record->time_stamp > expire)
65
if (now - cache_record->time_stamp > expire)
87
  {
66
  {
88
  HDEBUG(D_verify) debug_printf("callout cache: %s record expired for %s\n", type, key);
67
  HDEBUG(D_verify) debug_printf_indent("callout cache: %s record expired for %s\n", type, key);
89
  return NULL;
68
  return NULL;
90
  }
69
  }
91
70
Lines 99-105 Link Here
99
  {
78
  {
100
  if (length == sizeof(dbdata_callout_cache_obs))
79
  if (length == sizeof(dbdata_callout_cache_obs))
101
    {
80
    {
102
    dbdata_callout_cache *new = store_get(sizeof(dbdata_callout_cache), FALSE);
81
    dbdata_callout_cache * new = store_get(sizeof(dbdata_callout_cache), GET_UNTAINTED);
103
    memcpy(new, cache_record, length);
82
    memcpy(new, cache_record, length);
104
    new->postmaster_stamp = new->random_stamp = new->time_stamp;
83
    new->postmaster_stamp = new->random_stamp = new->time_stamp;
105
    cache_record = new;
84
    cache_record = new;
Lines 112-118 Link Here
112
    cache_record->random_result = ccache_unknown;
91
    cache_record->random_result = ccache_unknown;
113
  }
92
  }
114
93
115
HDEBUG(D_verify) debug_printf("callout cache: found %s record for %s\n", type, key);
94
HDEBUG(D_verify) debug_printf_indent("callout cache: found %s record for %s\n", type, key);
116
return cache_record;
95
return cache_record;
117
}
96
}
118
97
Lines 134-149 Link Here
134
open_db dbblock;
113
open_db dbblock;
135
open_db *dbm_file = NULL;
114
open_db *dbm_file = NULL;
136
115
137
/* Open the callout cache database, it it exists, for reading only at this
116
/* Open the callout cache database, if it exists, for reading only at this
138
stage, unless caching has been disabled. */
117
stage, unless caching has been disabled. */
139
118
140
if (options & vopt_callout_no_cache)
119
if (options & vopt_callout_no_cache)
141
  {
120
  {
142
  HDEBUG(D_verify) debug_printf("callout cache: disabled by no_cache\n");
121
  HDEBUG(D_verify) debug_printf_indent("callout cache: disabled by no_cache\n");
143
  }
122
  }
144
else if (!(dbm_file = dbfn_open(US"callout", O_RDWR, &dbblock, FALSE, TRUE)))
123
else if (!(dbm_file = dbfn_open(US"callout", O_RDWR, &dbblock, FALSE, TRUE)))
145
  {
124
  {
146
  HDEBUG(D_verify) debug_printf("callout cache: not available\n");
125
  HDEBUG(D_verify) debug_printf_indent("callout cache: not available\n");
147
  }
126
  }
148
else
127
else
149
  {
128
  {
Lines 174-180 Link Here
174
       || *from_address == 0 && cache_record->result == ccache_reject_mfnull)
153
       || *from_address == 0 && cache_record->result == ccache_reject_mfnull)
175
      {
154
      {
176
      HDEBUG(D_verify)
155
      HDEBUG(D_verify)
177
	debug_printf("callout cache: domain gave initial rejection, or "
156
	debug_printf_indent("callout cache: domain gave initial rejection, or "
178
	  "does not accept HELO or MAIL FROM:<>\n");
157
	  "does not accept HELO or MAIL FROM:<>\n");
179
      setflag(addr, af_verify_nsfail);
158
      setflag(addr, af_verify_nsfail);
180
      addr->user_message = US"(result of an earlier callout reused).";
159
      addr->user_message = US"(result of an earlier callout reused).";
Lines 195-208 Link Here
195
      {
174
      {
196
      case ccache_accept:
175
      case ccache_accept:
197
	HDEBUG(D_verify)
176
	HDEBUG(D_verify)
198
	  debug_printf("callout cache: domain accepts random addresses\n");
177
	  debug_printf_indent("callout cache: domain accepts random addresses\n");
199
	*failure_ptr = US"random";
178
	*failure_ptr = US"random";
200
	dbfn_close(dbm_file);
179
	dbfn_close(dbm_file);
201
	return TRUE;     /* Default yield is OK */
180
	return TRUE;     /* Default yield is OK */
202
181
203
      case ccache_reject:
182
      case ccache_reject:
204
	HDEBUG(D_verify)
183
	HDEBUG(D_verify)
205
	  debug_printf("callout cache: domain rejects random addresses\n");
184
	  debug_printf_indent("callout cache: domain rejects random addresses\n");
206
	*opt_ptr = options & ~vopt_callout_random;
185
	*opt_ptr = options & ~vopt_callout_random;
207
	new_domain_record->random_result = ccache_reject;
186
	new_domain_record->random_result = ccache_reject;
208
	new_domain_record->random_stamp = cache_record->random_stamp;
187
	new_domain_record->random_stamp = cache_record->random_stamp;
Lines 210-216 Link Here
210
189
211
      default:
190
      default:
212
	HDEBUG(D_verify)
191
	HDEBUG(D_verify)
213
	  debug_printf("callout cache: need to check random address handling "
192
	  debug_printf_indent("callout cache: need to check random address handling "
214
	    "(not cached or cache expired)\n");
193
	    "(not cached or cache expired)\n");
215
	dbfn_close(dbm_file);
194
	dbfn_close(dbm_file);
216
	return FALSE;
195
	return FALSE;
Lines 227-233 Link Here
227
	{
206
	{
228
	setflag(addr, af_verify_pmfail);
207
	setflag(addr, af_verify_pmfail);
229
	HDEBUG(D_verify)
208
	HDEBUG(D_verify)
230
	  debug_printf("callout cache: domain does not accept "
209
	  debug_printf_indent("callout cache: domain does not accept "
231
	    "RCPT TO:<postmaster@domain>\n");
210
	    "RCPT TO:<postmaster@domain>\n");
232
	*yield = FAIL;
211
	*yield = FAIL;
233
	*failure_ptr = US"postmaster";
212
	*failure_ptr = US"postmaster";
Lines 239-245 Link Here
239
      if (cache_record->postmaster_result == ccache_unknown)
218
      if (cache_record->postmaster_result == ccache_unknown)
240
	{
219
	{
241
	HDEBUG(D_verify)
220
	HDEBUG(D_verify)
242
	  debug_printf("callout cache: need to check RCPT "
221
	  debug_printf_indent("callout cache: need to check RCPT "
243
	    "TO:<postmaster@domain> (not cached or cache expired)\n");
222
	    "TO:<postmaster@domain> (not cached or cache expired)\n");
244
	dbfn_close(dbm_file);
223
	dbfn_close(dbm_file);
245
	return FALSE;
224
	return FALSE;
Lines 250-256 Link Here
250
      that the value in the cache record is preserved (with its old timestamp).
229
      that the value in the cache record is preserved (with its old timestamp).
251
      */
230
      */
252
231
253
      HDEBUG(D_verify) debug_printf("callout cache: domain accepts RCPT "
232
      HDEBUG(D_verify) debug_printf_indent("callout cache: domain accepts RCPT "
254
	"TO:<postmaster@domain>\n");
233
	"TO:<postmaster@domain>\n");
255
      *pm_ptr = NULL;
234
      *pm_ptr = NULL;
256
      new_domain_record->postmaster_result = ccache_accept;
235
      new_domain_record->postmaster_result = ccache_accept;
Lines 274-285 Link Here
274
  if (cache_address_record->result == ccache_accept)
253
  if (cache_address_record->result == ccache_accept)
275
    {
254
    {
276
    HDEBUG(D_verify)
255
    HDEBUG(D_verify)
277
      debug_printf("callout cache: address record is positive\n");
256
      debug_printf_indent("callout cache: address record is positive\n");
278
    }
257
    }
279
  else
258
  else
280
    {
259
    {
281
    HDEBUG(D_verify)
260
    HDEBUG(D_verify)
282
      debug_printf("callout cache: address record is negative\n");
261
      debug_printf_indent("callout cache: address record is negative\n");
283
    addr->user_message = US"Previous (cached) callout verification failure";
262
    addr->user_message = US"Previous (cached) callout verification failure";
284
    *failure_ptr = US"recipient";
263
    *failure_ptr = US"recipient";
285
    *yield = FAIL;
264
    *yield = FAIL;
Lines 316-328 Link Here
316
if (dom_rec->result != ccache_unknown)
295
if (dom_rec->result != ccache_unknown)
317
  if (!(dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE, TRUE)))
296
  if (!(dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE, TRUE)))
318
    {
297
    {
319
    HDEBUG(D_verify) debug_printf("callout cache: not available\n");
298
    HDEBUG(D_verify) debug_printf_indent("callout cache: not available\n");
320
    }
299
    }
321
  else
300
  else
322
    {
301
    {
323
    (void)dbfn_write(dbm_file, domain, dom_rec,
302
    (void)dbfn_write(dbm_file, domain, dom_rec,
324
      (int)sizeof(dbdata_callout_cache));
303
      (int)sizeof(dbdata_callout_cache));
325
    HDEBUG(D_verify) debug_printf("wrote callout cache domain record for %s:\n"
304
    HDEBUG(D_verify) debug_printf_indent("wrote callout cache domain record for %s:\n"
326
      "  result=%d postmaster=%d random=%d\n",
305
      "  result=%d postmaster=%d random=%d\n",
327
      domain,
306
      domain,
328
      dom_rec->result,
307
      dom_rec->result,
Lines 339-351 Link Here
339
    dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE, TRUE);
318
    dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE, TRUE);
340
  if (!dbm_file)
319
  if (!dbm_file)
341
    {
320
    {
342
    HDEBUG(D_verify) debug_printf("no callout cache available\n");
321
    HDEBUG(D_verify) debug_printf_indent("no callout cache available\n");
343
    }
322
    }
344
  else
323
  else
345
    {
324
    {
346
    (void)dbfn_write(dbm_file, address_key, addr_rec,
325
    (void)dbfn_write(dbm_file, address_key, addr_rec,
347
      (int)sizeof(dbdata_callout_cache_address));
326
      (int)sizeof(dbdata_callout_cache_address));
348
    HDEBUG(D_verify) debug_printf("wrote %s callout cache address record for %s\n",
327
    HDEBUG(D_verify) debug_printf_indent("wrote %s callout cache address record for %s\n",
349
      addr_rec->result == ccache_accept ? "positive" : "negative",
328
      addr_rec->result == ccache_accept ? "positive" : "negative",
350
      address_key);
329
      address_key);
351
    }
330
    }
Lines 421-427 Link Here
421
400
422
	if (done)
401
	if (done)
423
	  {
402
	  {
424
	  address_item * na = store_get(sizeof(address_item), FALSE);
403
	  address_item * na = store_get(sizeof(address_item), GET_UNTAINTED);
425
	  *na = cutthrough.addr;
404
	  *na = cutthrough.addr;
426
	  cutthrough.addr = *addr;
405
	  cutthrough.addr = *addr;
427
	  cutthrough.addr.host_used = &cutthrough.host;
406
	  cutthrough.addr.host_used = &cutthrough.host;
Lines 466-471 Link Here
466
}
445
}
467
446
468
447
448
449
450
/* A rcpt callout, or cached record of one, verified the address.
451
Set $domain_data and $local_part_data to detainted versions.
452
*/
453
static void
454
callout_verified_rcpt(const address_item * addr)
455
{
456
address_item a = {.address = addr->address};
457
if (deliver_split_address(&a) != OK) return;
458
deliver_localpart_data = string_copy_taint(a.local_part, GET_UNTAINTED);
459
deliver_domain_data =    string_copy_taint(a.domain,     GET_UNTAINTED);
460
}
461
462
469
/*************************************************
463
/*************************************************
470
*      Do callout verification for an address    *
464
*      Do callout verification for an address    *
471
*************************************************/
465
*************************************************/
Lines 568-573 Link Here
568
  {
562
  {
569
  HDEBUG(D_verify) debug_printf("cannot callout via null transport\n");
563
  HDEBUG(D_verify) debug_printf("cannot callout via null transport\n");
570
  }
564
  }
565
571
else if (Ustrcmp(addr->transport->driver_name, "smtp") != 0)
566
else if (Ustrcmp(addr->transport->driver_name, "smtp") != 0)
572
  log_write(0, LOG_MAIN|LOG_PANIC|LOG_CONFIG_FOR, "callout transport '%s': %s is non-smtp",
567
  log_write(0, LOG_MAIN|LOG_PANIC|LOG_CONFIG_FOR, "callout transport '%s': %s is non-smtp",
573
    addr->transport->name, addr->transport->driver_name);
568
    addr->transport->name, addr->transport->driver_name);
Lines 671-677 Link Here
671
      log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address,
666
      log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address,
672
        addr->message);
667
        addr->message);
673
668
674
    if (!sx) sx = store_get(sizeof(*sx), TRUE);	/* tainted buffers */
669
    if (!sx) sx = store_get(sizeof(*sx), GET_TAINTED);	/* tainted buffers */
675
    memset(sx, 0, sizeof(*sx));
670
    memset(sx, 0, sizeof(*sx));
676
671
677
    sx->addrlist = sx->first_addr = addr;
672
    sx->addrlist = sx->first_addr = addr;
Lines 681-686 Link Here
681
    sx->conn_args.interface = interface;
676
    sx->conn_args.interface = interface;
682
    sx->helo_data = tf->helo_data;
677
    sx->helo_data = tf->helo_data;
683
    sx->conn_args.tblock = addr->transport;
678
    sx->conn_args.tblock = addr->transport;
679
    sx->conn_args.sock = -1;
684
    sx->verify = TRUE;
680
    sx->verify = TRUE;
685
681
686
tls_retry_connection:
682
tls_retry_connection:
Lines 835-841 Link Here
835
	    sx->cctx.sock = -1;
831
	    sx->cctx.sock = -1;
836
#ifndef DISABLE_EVENT
832
#ifndef DISABLE_EVENT
837
	    (void) event_raise(addr->transport->event_action,
833
	    (void) event_raise(addr->transport->event_action,
838
			      US"tcp:close", NULL);
834
			      US"tcp:close", NULL, NULL);
839
#endif
835
#endif
840
	    addr->address = main_address;
836
	    addr->address = main_address;
841
	    addr->transport_return = PENDING_DEFER;
837
	    addr->transport_return = PENDING_DEFER;
Lines 1116-1122 Link Here
1116
      for (address_item * caddr = &cutthrough.addr, * parent = addr->parent;
1112
      for (address_item * caddr = &cutthrough.addr, * parent = addr->parent;
1117
	   parent;
1113
	   parent;
1118
	   caddr = caddr->parent, parent = parent->parent)
1114
	   caddr = caddr->parent, parent = parent->parent)
1119
        *(caddr->parent = store_get(sizeof(address_item), FALSE)) = *parent;
1115
        *(caddr->parent = store_get(sizeof(address_item), GET_UNTAINTED)) = *parent;
1120
1116
1121
      ctctx.outblock.buffer = ctbuffer;
1117
      ctctx.outblock.buffer = ctbuffer;
1122
      ctctx.outblock.buffersize = sizeof(ctbuffer);
1118
      ctctx.outblock.buffersize = sizeof(ctbuffer);
Lines 1146-1153 Link Here
1146
	HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP(close)>>\n");
1142
	HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP(close)>>\n");
1147
	(void)close(sx->cctx.sock);
1143
	(void)close(sx->cctx.sock);
1148
	sx->cctx.sock = -1;
1144
	sx->cctx.sock = -1;
1145
	smtp_debug_cmd_report();
1149
#ifndef DISABLE_EVENT
1146
#ifndef DISABLE_EVENT
1150
	(void) event_raise(addr->transport->event_action, US"tcp:close", NULL);
1147
	(void) event_raise(addr->transport->event_action, US"tcp:close", NULL, NULL);
1151
#endif
1148
#endif
1152
	}
1149
	}
1153
      }
1150
      }
Lines 1366-1372 Link Here
1366
if(cutthrough.cctx.sock < 0 || cutthrough.callout_hold_only)
1363
if(cutthrough.cctx.sock < 0 || cutthrough.callout_hold_only)
1367
  return FALSE;
1364
  return FALSE;
1368
1365
1369
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP>> DATA\n");
1366
smtp_debug_cmd(US"DATA", 0);
1370
cutthrough_puts(US"DATA\r\n", 6);
1367
cutthrough_puts(US"DATA\r\n", 6);
1371
cutthrough_flush_send();
1368
cutthrough_flush_send();
1372
1369
Lines 1434-1440 Link Here
1434
  */
1431
  */
1435
  client_conn_ctx tmp_ctx = cutthrough.cctx;
1432
  client_conn_ctx tmp_ctx = cutthrough.cctx;
1436
  ctctx.outblock.ptr = ctbuffer;
1433
  ctctx.outblock.ptr = ctbuffer;
1437
  HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP>> QUIT\n");
1434
  smtp_debug_cmd(US"QUIT", 0);
1438
  _cutthrough_puts(US"QUIT\r\n", 6);	/* avoid recursion */
1435
  _cutthrough_puts(US"QUIT\r\n", 6);	/* avoid recursion */
1439
  _cutthrough_flush_send();
1436
  _cutthrough_flush_send();
1440
  cutthrough.cctx.sock = -1;		/* avoid recursion via read timeout */
1437
  cutthrough.cctx.sock = -1;		/* avoid recursion via read timeout */
Lines 1453-1458 Link Here
1453
#endif
1450
#endif
1454
  HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP(close)>>\n");
1451
  HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP(close)>>\n");
1455
  (void)close(fd);
1452
  (void)close(fd);
1453
  smtp_debug_cmd_report();
1456
  HDEBUG(D_acl) debug_printf_indent("----------- cutthrough shutdown (%s) ------------\n", why);
1454
  HDEBUG(D_acl) debug_printf_indent("----------- cutthrough shutdown (%s) ------------\n", why);
1457
  }
1455
  }
1458
ctctx.outblock.ptr = ctbuffer;
1456
ctctx.outblock.ptr = ctbuffer;
Lines 1612-1618 Link Here
1612
Arguments:
1610
Arguments:
1613
  vaddr            contains the address to verify; the next field in this block
1611
  vaddr            contains the address to verify; the next field in this block
1614
                     must be NULL
1612
                     must be NULL
1615
  f                if not NULL, write the result to this file
1613
  fp               if not NULL, write the result to this file
1616
  options          various option bits:
1614
  options          various option bits:
1617
                     vopt_fake_sender => this sender verify is not for the real
1615
                     vopt_fake_sender => this sender verify is not for the real
1618
                       sender (it was verify=sender=xxxx or an address from a
1616
                       sender (it was verify=sender=xxxx or an address from a
Lines 1663-1671 Link Here
1663
BOOL success_on_redirect = (options & vopt_success_on_redirect) != 0;
1661
BOOL success_on_redirect = (options & vopt_success_on_redirect) != 0;
1664
int i;
1662
int i;
1665
int yield = OK;
1663
int yield = OK;
1666
int verify_type = expn? v_expn :
1664
int verify_type = expn ? v_expn :
1667
   f.address_test_mode? v_none :
1665
   f.address_test_mode ? v_none :
1668
          options & vopt_is_recipient? v_recipient : v_sender;
1666
          options & vopt_is_recipient ? v_recipient : v_sender;
1669
address_item *addr_list;
1667
address_item *addr_list;
1670
address_item *addr_new = NULL;
1668
address_item *addr_new = NULL;
1671
address_item *addr_remote = NULL;
1669
address_item *addr_remote = NULL;
Lines 1848-1853 Link Here
1848
1846
1849
  if (rc == OK)
1847
  if (rc == OK)
1850
    {
1848
    {
1849
    BOOL local_verify = FALSE;
1850
1851
    if (routed) *routed = TRUE;
1851
    if (routed) *routed = TRUE;
1852
    if (callout > 0)
1852
    if (callout > 0)
1853
      {
1853
      {
Lines 1874-1945 Link Here
1874
      transport's options, so as to mimic what would happen if we were really
1874
      transport's options, so as to mimic what would happen if we were really
1875
      sending a message to this address. */
1875
      sending a message to this address. */
1876
1876
1877
      if ((tp = addr->transport) && !tp->info->local)
1877
      if ((tp = addr->transport))
1878
        {
1878
	if (!tp->info->local)
1879
        (void)(tp->setup)(tp, addr, &tf, 0, 0, NULL);
1879
	  {
1880
	  (void)(tp->setup)(tp, addr, &tf, 0, 0, NULL);
1880
1881
1881
        /* If the transport has hosts and the router does not, or if the
1882
	  /* If the transport has hosts and the router does not, or if the
1882
        transport is configured to override the router's hosts, we must build a
1883
	  transport is configured to override the router's hosts, we must build a
1883
        host list of the transport's hosts, and find the IP addresses */
1884
	  host list of the transport's hosts, and find the IP addresses */
1884
1885
1885
        if (tf.hosts && (!host_list || tf.hosts_override))
1886
	  if (tf.hosts && (!host_list || tf.hosts_override))
1886
          {
1887
	    {
1887
          uschar *s;
1888
	    uschar *s;
1888
          const uschar *save_deliver_domain = deliver_domain;
1889
	    const uschar *save_deliver_domain = deliver_domain;
1889
          uschar *save_deliver_localpart = deliver_localpart;
1890
	    uschar *save_deliver_localpart = deliver_localpart;
1890
1891
1891
          host_list = NULL;    /* Ignore the router's hosts */
1892
	    host_list = NULL;    /* Ignore the router's hosts */
1892
1893
1893
          deliver_domain = addr->domain;
1894
	    deliver_domain = addr->domain;
1894
          deliver_localpart = addr->local_part;
1895
	    deliver_localpart = addr->local_part;
1895
          s = expand_string(tf.hosts);
1896
	    s = expand_string(tf.hosts);
1896
          deliver_domain = save_deliver_domain;
1897
	    deliver_domain = save_deliver_domain;
1897
          deliver_localpart = save_deliver_localpart;
1898
	    deliver_localpart = save_deliver_localpart;
1898
1899
1899
          if (!s)
1900
	    if (!s)
1900
            {
1901
	      {
1901
            log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand list of hosts "
1902
	      log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand list of hosts "
1902
              "\"%s\" in %s transport for callout: %s", tf.hosts,
1903
		"\"%s\" in %s transport for callout: %s", tf.hosts,
1903
              tp->name, expand_string_message);
1904
		tp->name, expand_string_message);
1904
            }
1905
	      }
1905
          else
1906
	    else
1906
            {
1907
	      {
1907
            int flags;
1908
	      int flags;
1908
            host_build_hostlist(&host_list, s, tf.hosts_randomize);
1909
	      host_build_hostlist(&host_list, s, tf.hosts_randomize);
1909
1910
1910
            /* Just ignore failures to find a host address. If we don't manage
1911
	      /* Just ignore failures to find a host address. If we don't manage
1911
            to find any addresses, the callout will defer. Note that more than
1912
	      to find any addresses, the callout will defer. Note that more than
1912
            one address may be found for a single host, which will result in
1913
	      one address may be found for a single host, which will result in
1913
            additional host items being inserted into the chain. Hence we must
1914
	      additional host items being inserted into the chain. Hence we must
1914
            save the next host first. */
1915
	      save the next host first. */
1915
1916
1916
            flags = HOST_FIND_BY_A | HOST_FIND_BY_AAAA;
1917
	      flags = HOST_FIND_BY_A | HOST_FIND_BY_AAAA;
1917
            if (tf.qualify_single) flags |= HOST_FIND_QUALIFY_SINGLE;
1918
	      if (tf.qualify_single) flags |= HOST_FIND_QUALIFY_SINGLE;
1918
            if (tf.search_parents) flags |= HOST_FIND_SEARCH_PARENTS;
1919
	      if (tf.search_parents) flags |= HOST_FIND_SEARCH_PARENTS;
1919
1920
1920
            for (host_item * host = host_list, * nexthost; host; host = nexthost)
1921
	      for (host_item * host = host_list, * nexthost; host; host = nexthost)
1921
              {
1922
              nexthost = host->next;
1923
              if (tf.gethostbyname ||
1924
                  string_is_ip_address(host->name, NULL) != 0)
1925
                (void)host_find_byname(host, NULL, flags, NULL, TRUE);
1926
              else
1927
		{
1922
		{
1928
		const dnssec_domains * dsp = NULL;
1923
		nexthost = host->next;
1929
		if (Ustrcmp(tp->driver_name, "smtp") == 0)
1924
		if (tf.gethostbyname ||
1925
		    string_is_ip_address(host->name, NULL) != 0)
1926
		  (void)host_find_byname(host, NULL, flags, NULL, TRUE);
1927
		else
1930
		  {
1928
		  {
1931
		  smtp_transport_options_block * ob =
1929
		  const dnssec_domains * dsp = NULL;
1932
		      (smtp_transport_options_block *) tp->options_block;
1930
		  if (Ustrcmp(tp->driver_name, "smtp") == 0)
1933
		  dsp = &ob->dnssec;
1931
		    {
1934
		  }
1932
		    smtp_transport_options_block * ob =
1933
			(smtp_transport_options_block *) tp->options_block;
1934
		    dsp = &ob->dnssec;
1935
		    }
1935
1936
1936
                (void) host_find_bydns(host, NULL, flags, NULL, NULL, NULL,
1937
		  (void) host_find_bydns(host, NULL, flags, NULL, NULL, NULL,
1937
		  dsp, NULL, NULL);
1938
		    dsp, NULL, NULL);
1939
		  }
1938
		}
1940
		}
1939
              }
1941
	      }
1940
            }
1942
	    }
1941
          }
1943
	  }
1942
        }
1944
	else if (  options & vopt_quota
1945
		&& Ustrcmp(tp->driver_name, "appendfile") == 0)
1946
	  local_verify = TRUE;
1943
1947
1944
      /* Can only do a callout if we have at least one host! If the callout
1948
      /* Can only do a callout if we have at least one host! If the callout
1945
      fails, it will have set ${sender,recipient}_verify_failure. */
1949
      fails, it will have set ${sender,recipient}_verify_failure. */
Lines 1963-1975 Link Here
1963
#ifndef DISABLE_TLS
1967
#ifndef DISABLE_TLS
1964
	  deliver_set_expansions(NULL);
1968
	  deliver_set_expansions(NULL);
1965
#endif
1969
#endif
1970
	  if (  options & vopt_is_recipient
1971
	     && rc == OK
1972
			 /* set to "random", with OK, for an accepted random */
1973
	     && !recipient_verify_failure
1974
	     )
1975
	    callout_verified_rcpt(addr);
1966
          }
1976
          }
1967
        }
1977
        }
1978
      else if (local_verify)
1979
	{
1980
        HDEBUG(D_verify) debug_printf("Attempting quota verification\n");
1981
1982
	deliver_set_expansions(addr);
1983
	deliver_local(addr, TRUE);
1984
	rc = addr->transport_return;
1985
	}
1968
      else
1986
      else
1969
        {
1970
        HDEBUG(D_verify) debug_printf("Cannot do callout: neither router nor "
1987
        HDEBUG(D_verify) debug_printf("Cannot do callout: neither router nor "
1971
          "transport provided a host list, or transport is not smtp\n");
1988
          "transport provided a host list, or transport is not smtp\n");
1972
        }
1973
      }
1989
      }
1974
    }
1990
    }
1975
1991
Lines 2158-2167 Link Here
2158
    addr_list = addr->next;
2174
    addr_list = addr->next;
2159
2175
2160
    fprintf(fp, "%s", CS addr->address);
2176
    fprintf(fp, "%s", CS addr->address);
2161
#ifdef EXPERIMENTAL_SRS
2162
    if(addr->prop.srs_sender)
2163
      fprintf(fp, "    [srs = %s]", addr->prop.srs_sender);
2164
#endif
2165
2177
2166
    /* If the address is a duplicate, show something about it. */
2178
    /* If the address is a duplicate, show something about it. */
2167
2179
Lines 2884-2911 Link Here
2884
*/
2896
*/
2885
2897
2886
int
2898
int
2887
check_host(void *arg, const uschar *ss, const uschar **valueptr, uschar **error)
2899
check_host(void * arg, const uschar * ss, const uschar ** valueptr, uschar ** error)
2888
{
2900
{
2889
check_host_block *cb = (check_host_block *)arg;
2901
check_host_block * cb = (check_host_block *)arg;
2890
int mlen = -1;
2902
int mlen = -1;
2891
int maskoffset;
2903
int maskoffset;
2892
BOOL iplookup = FALSE;
2904
BOOL iplookup = FALSE, isquery = FALSE;
2893
BOOL isquery = FALSE;
2905
BOOL isiponly = cb->host_name && !cb->host_name[0];
2894
BOOL isiponly = cb->host_name != NULL && cb->host_name[0] == 0;
2906
const uschar * t;
2895
const uschar *t;
2896
uschar * semicolon, * endname, * opts;
2907
uschar * semicolon, * endname, * opts;
2897
uschar **aliases;
2908
uschar ** aliases;
2898
2909
2899
/* Optimize for the special case when the pattern is "*". */
2910
/* Optimize for the special case when the pattern is "*". */
2900
2911
2901
if (*ss == '*' && ss[1] == 0) return OK;
2912
if (*ss == '*' && !ss[1]) return OK;
2902
2913
2903
/* If the pattern is empty, it matches only in the case when there is no host -
2914
/* If the pattern is empty, it matches only in the case when there is no host -
2904
this can occur in ACL checking for SMTP input using the -bs option. In this
2915
this can occur in ACL checking for SMTP input using the -bs option. In this
2905
situation, the host address is the empty string. */
2916
situation, the host address is the empty string. */
2906
2917
2907
if (cb->host_address[0] == 0) return (*ss == 0)? OK : FAIL;
2918
if (!cb->host_address[0]) return *ss ? FAIL : OK;
2908
if (*ss == 0) return FAIL;
2919
if (!*ss) return FAIL;
2909
2920
2910
/* If the pattern is precisely "@" then match against the primary host name,
2921
/* If the pattern is precisely "@" then match against the primary host name,
2911
provided that host name matching is permitted; if it's "@[]" match against the
2922
provided that host name matching is permitted; if it's "@[]" match against the
Lines 2942-2948 Link Here
2942
dots). */
2953
dots). */
2943
2954
2944
for (t = ss; isdigit(*t) || *t == '.'; ) t++;
2955
for (t = ss; isdigit(*t) || *t == '.'; ) t++;
2945
if (*t == 0 || (*t == '/' && t != ss))
2956
if (!*t  || (*t == '/' && t != ss))
2946
  {
2957
  {
2947
  *error = US"malformed IPv4 address or address mask";
2958
  *error = US"malformed IPv4 address or address mask";
2948
  return ERROR;
2959
  return ERROR;
Lines 3354-3926 Link Here
3354
3365
3355
3366
3356
3367
3357
/*************************************************
3368
/****************************************************
3358
*          Perform a single dnsbl lookup         *
3369
  Verify a local user account for quota sufficiency
3359
*************************************************/
3370
****************************************************/
3360
3371
3361
/* This function is called from verify_check_dnsbl() below. It is also called
3372
/* The real work, done via a re-exec for privs, calls
3362
recursively from within itself when domain and domain_txt are different
3373
down to the transport for the quota check.
3363
pointers, in order to get the TXT record from the alternate domain.
3374
3364
3375
Route and transport (in recipient-verify mode) the
3365
Arguments:
3376
given recipient. 
3366
  domain         the outer dnsbl domain
3377
3367
  domain_txt     alternate domain to lookup TXT record on success; when the
3378
A routing result indicating any transport type other than appendfile
3368
                   same domain is to be used, domain_txt == domain (that is,
3379
results in a fail.
3369
                   the pointers must be identical, not just the text)
3380
3370
  keydomain      the current keydomain (for debug message)
3381
Return, on stdout, a result string containing:
3371
  prepend        subdomain to lookup (like keydomain, but
3382
- highlevel result code (OK, DEFER, FAIL)
3372
                   reversed if IP address)
3383
- errno
3373
  iplist         the list of matching IP addresses, or NULL for "any"
3384
- where string
3374
  bitmask        true if bitmask matching is wanted
3385
- message string
3375
  match_type     condition for 'succeed' result
3376
                   0 => Any RR in iplist     (=)
3377
                   1 => No RR in iplist      (!=)
3378
                   2 => All RRs in iplist    (==)
3379
                   3 => Some RRs not in iplist (!==)
3380
                   the two bits are defined as MT_NOT and MT_ALL
3381
  defer_return   what to return for a defer
3382
3383
Returns:         OK if lookup succeeded
3384
                 FAIL if not
3385
*/
3386
*/
3386
3387
3387
static int
3388
void
3388
one_check_dnsbl(uschar *domain, uschar *domain_txt, uschar *keydomain,
3389
verify_quota(uschar * address)
3389
  uschar *prepend, uschar *iplist, BOOL bitmask, int match_type,
3390
  int defer_return)
3391
{
3390
{
3392
dns_answer * dnsa = store_get_dns_answer();
3391
address_item vaddr = {.address = address};
3393
dns_scan dnss;
3392
BOOL routed;
3394
tree_node *t;
3393
uschar * msg = US"\0";
3395
dnsbl_cache_block *cb;
3394
int rc, len = 1;
3396
int old_pool = store_pool;
3397
uschar * query;
3398
int qlen;
3399
3400
/* Construct the specific query domainname */
3401
3402
query = string_sprintf("%s.%s", prepend, domain);
3403
if ((qlen = Ustrlen(query)) >= 256)
3404
  {
3405
  log_write(0, LOG_MAIN|LOG_PANIC, "dnslist query is too long "
3406
    "(ignored): %s...", query);
3407
  return FAIL;
3408
  }
3409
3395
3410
/* Look for this query in the cache. */
3396
if ((rc = verify_address(&vaddr, NULL, vopt_is_recipient | vopt_quota,
3411
3397
    1, 0, 0, NULL, NULL, &routed)) != OK)
3412
if (  (t = tree_search(dnsbl_cache, query))
3413
   && (cb = t->data.ptr)->expiry > time(NULL)
3414
   )
3415
3416
/* Previous lookup was cached */
3417
3418
  {
3419
  HDEBUG(D_dnsbl) debug_printf("dnslists: using result of previous lookup\n");
3420
  }
3421
3422
/* If not cached from a previous lookup, we must do a DNS lookup, and
3423
cache the result in permanent memory. */
3424
3425
else
3426
  {
3398
  {
3427
  uint ttl = 3600;	/* max TTL for positive cache entries */
3399
  uschar * where = recipient_verify_failure;
3428
3400
  msg = acl_verify_message ? acl_verify_message : vaddr.message;
3429
  store_pool = POOL_PERM;
3401
  if (!msg) msg = US"";
3430
3402
  if (rc == DEFER && vaddr.basic_errno == ERRNO_EXIMQUOTA)
3431
  if (t)
3432
    {
3403
    {
3433
    HDEBUG(D_dnsbl) debug_printf("cached data found but past valid time; ");
3404
    rc = FAIL;					/* DEFER -> FAIL */
3434
    }
3405
    where = US"quota";
3435
3406
    vaddr.basic_errno = 0;
3436
  else
3437
    {	/* Set up a tree entry to cache the lookup */
3438
    t = store_get(sizeof(tree_node) + qlen + 1 + 1, is_tainted(query));
3439
    Ustrcpy(t->name, query);
3440
    t->data.ptr = cb = store_get(sizeof(dnsbl_cache_block), FALSE);
3441
    (void)tree_insertnode(&dnsbl_cache, t);
3442
    }
3443
3444
  /* Do the DNS lookup . */
3445
3446
  HDEBUG(D_dnsbl) debug_printf("new DNS lookup for %s\n", query);
3447
  cb->rc = dns_basic_lookup(dnsa, query, T_A);
3448
  cb->text_set = FALSE;
3449
  cb->text = NULL;
3450
  cb->rhs = NULL;
3451
3452
  /* If the lookup succeeded, cache the RHS address. The code allows for
3453
  more than one address - this was for complete generality and the possible
3454
  use of A6 records. However, A6 records are no longer supported. Leave the code
3455
  here, just in case.
3456
3457
  Quite apart from one A6 RR generating multiple addresses, there are DNS
3458
  lists that return more than one A record, so we must handle multiple
3459
  addresses generated in that way as well.
3460
3461
  Mark the cache entry with the "now" plus the minimum of the address TTLs,
3462
  or the RFC 2308 negative-cache value from the SOA if none were found. */
3463
3464
  switch (cb->rc)
3465
    {
3466
    case DNS_SUCCEED:
3467
      {
3468
      dns_address ** addrp = &cb->rhs;
3469
      dns_address * da;
3470
      for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr;
3471
	   rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
3472
	if (rr->type == T_A && (da = dns_address_from_rr(dnsa, rr)))
3473
	  {
3474
	  *addrp = da;
3475
	  while (da->next) da = da->next;
3476
	  addrp = &da->next;
3477
	  if (ttl > rr->ttl) ttl = rr->ttl;
3478
	  }
3479
3480
      if (cb->rhs)
3481
	{
3482
	cb->expiry = time(NULL) + ttl;
3483
	break;
3484
	}
3485
3486
      /* If we didn't find any A records, change the return code. This can
3487
      happen when there is a CNAME record but there are no A records for what
3488
      it points to. */
3489
3490
      cb->rc = DNS_NODATA;
3491
      }
3492
      /*FALLTHROUGH*/
3493
3494
    case DNS_NOMATCH:
3495
    case DNS_NODATA:
3496
      {
3497
      /* Although there already is a neg-cache layer maintained by
3498
      dns_basic_lookup(), we have a dnslist cache entry allocated and
3499
      tree-inserted. So we may as well use it. */
3500
3501
      time_t soa_negttl = dns_expire_from_soa(dnsa, T_A);
3502
      cb->expiry = soa_negttl ? soa_negttl : time(NULL) + ttl;
3503
      break;
3504
      }
3505
3506
    default:
3507
      cb->expiry = time(NULL) + ttl;
3508
      break;
3509
    }
3407
    }
3408
  else if (!where) where = US"";
3510
3409
3511
  store_pool = old_pool;
3410
  len = 5 + Ustrlen(msg) + 1 + Ustrlen(where);
3512
  HDEBUG(D_dnsbl) debug_printf("dnslists: wrote cache entry, ttl=%d\n",
3411
  msg = string_sprintf("%c%c%c%c%c%s%c%s", (uschar)rc,
3513
    (int)(cb->expiry - time(NULL)));
3412
    (vaddr.basic_errno >> 24) & 0xff, (vaddr.basic_errno >> 16) & 0xff,
3413
    (vaddr.basic_errno >> 8) & 0xff, vaddr.basic_errno & 0xff,
3414
    where, '\0', msg);
3514
  }
3415
  }
3515
3416
3516
/* We now have the result of the DNS lookup, either newly done, or cached
3417
DEBUG(D_verify) debug_printf_indent("verify_quota: len %d\n", len);
3517
from a previous call. If the lookup succeeded, check against the address
3418
write(1, msg, len);
3518
list if there is one. This may be a positive equality list (introduced by
3419
return;
3519
"="), a negative equality list (introduced by "!="), a positive bitmask
3420
}
3520
list (introduced by "&"), or a negative bitmask list (introduced by "!&").*/
3521
3522
if (cb->rc == DNS_SUCCEED)
3523
  {
3524
  dns_address * da = NULL;
3525
  uschar *addlist = cb->rhs->address;
3526
3527
  /* For A and AAAA records, there may be multiple addresses from multiple
3528
  records. For A6 records (currently not expected to be used) there may be
3529
  multiple addresses from a single record. */
3530
3531
  for (da = cb->rhs->next; da; da = da->next)
3532
    addlist = string_sprintf("%s, %s", addlist, da->address);
3533
3534
  HDEBUG(D_dnsbl) debug_printf("DNS lookup for %s succeeded (yielding %s)\n",
3535
    query, addlist);
3536
3537
  /* Address list check; this can be either for equality, or via a bitmask.
3538
  In the latter case, all the bits must match. */
3539
3540
  if (iplist)
3541
    {
3542
    for (da = cb->rhs; da; da = da->next)
3543
      {
3544
      int ipsep = ',';
3545
      const uschar *ptr = iplist;
3546
      uschar *res;
3547
3548
      /* Handle exact matching */
3549
3550
      if (!bitmask)
3551
	{
3552
        while ((res = string_nextinlist(&ptr, &ipsep, NULL, 0)))
3553
          if (Ustrcmp(CS da->address, res) == 0)
3554
	    break;
3555
	}
3556
3557
      /* Handle bitmask matching */
3558
3559
      else
3560
        {
3561
        int address[4];
3562
        int mask = 0;
3563
3564
        /* At present, all known DNS blocking lists use A records, with
3565
        IPv4 addresses on the RHS encoding the information they return. I
3566
        wonder if this will linger on as the last vestige of IPv4 when IPv6
3567
        is ubiquitous? Anyway, for now we use paranoia code to completely
3568
        ignore IPv6 addresses. The default mask is 0, which always matches.
3569
        We change this only for IPv4 addresses in the list. */
3570
3571
        if (host_aton(da->address, address) == 1) mask = address[0];
3572
3573
        /* Scan the returned addresses, skipping any that are IPv6 */
3574
3575
        while ((res = string_nextinlist(&ptr, &ipsep, NULL, 0)))
3576
          {
3577
          if (host_aton(res, address) != 1) continue;
3578
          if ((address[0] & mask) == address[0]) break;
3579
          }
3580
        }
3581
3582
      /* If either
3583
3584
         (a) An IP address in an any ('=') list matched, or
3585
         (b) No IP address in an all ('==') list matched
3586
3587
      then we're done searching. */
3588
3589
      if (((match_type & MT_ALL) != 0) == (res == NULL)) break;
3590
      }
3591
3592
    /* If da == NULL, either
3593
3421
3594
       (a) No IP address in an any ('=') list matched, or
3595
       (b) An IP address in an all ('==') list didn't match
3596
3422
3597
    so behave as if the DNSBL lookup had not succeeded, i.e. the host is not on
3423
/******************************************************************************/
3598
    the list. */
3599
3424
3600
    if ((match_type == MT_NOT || match_type == MT_ALL) != (da == NULL))
3425
/* Quota cache lookup.  We use the callout hints db also for the quota cache.
3601
      {
3426
Return TRUE if a nonexpired record was found, having filled in the yield
3602
      HDEBUG(D_dnsbl)
3427
argument.
3603
        {
3428
*/
3604
        uschar *res = NULL;
3605
        switch(match_type)
3606
          {
3607
          case 0:
3608
	    res = US"was no match"; break;
3609
          case MT_NOT:
3610
	    res = US"was an exclude match"; break;
3611
          case MT_ALL:
3612
	    res = US"was an IP address that did not match"; break;
3613
          case MT_NOT|MT_ALL:
3614
	    res = US"were no IP addresses that did not match"; break;
3615
          }
3616
        debug_printf("=> but we are not accepting this block class because\n");
3617
        debug_printf("=> there %s for %s%c%s\n",
3618
          res,
3619
          ((match_type & MT_ALL) == 0)? "" : "=",
3620
          bitmask? '&' : '=', iplist);
3621
        }
3622
      return FAIL;
3623
      }
3624
    }
3625
3626
  /* Either there was no IP list, or the record matched, implying that the
3627
  domain is on the list. We now want to find a corresponding TXT record. If an
3628
  alternate domain is specified for the TXT record, call this function
3629
  recursively to look that up; this has the side effect of re-checking that
3630
  there is indeed an A record at the alternate domain. */
3631
3632
  if (domain_txt != domain)
3633
    return one_check_dnsbl(domain_txt, domain_txt, keydomain, prepend, NULL,
3634
      FALSE, match_type, defer_return);
3635
3636
  /* If there is no alternate domain, look up a TXT record in the main domain
3637
  if it has not previously been cached. */
3638
3639
  if (!cb->text_set)
3640
    {
3641
    cb->text_set = TRUE;
3642
    if (dns_basic_lookup(dnsa, query, T_TXT) == DNS_SUCCEED)
3643
      for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr;
3644
           rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
3645
        if (rr->type == T_TXT)
3646
	  {
3647
	  int len = (rr->data)[0];
3648
	  if (len > 511) len = 127;
3649
	  store_pool = POOL_PERM;
3650
	  cb->text = string_sprintf("%.*s", len, CUS (rr->data+1));
3651
	  store_pool = old_pool;
3652
	  break;
3653
	  }
3654
    }
3655
3656
  dnslist_value = addlist;
3657
  dnslist_text = cb->text;
3658
  return OK;
3659
  }
3660
3429
3661
/* There was a problem with the DNS lookup */
3430
static BOOL
3431
cached_quota_lookup(const uschar * rcpt, int * yield,
3432
  int pos_cache, int neg_cache)
3433
{
3434
open_db dbblock, *dbm_file = NULL;
3435
dbdata_callout_cache_address * cache_address_record;
3662
3436
3663
if (cb->rc != DNS_NOMATCH && cb->rc != DNS_NODATA)
3437
if (!pos_cache && !neg_cache)
3438
  return FALSE;
3439
if (!(dbm_file = dbfn_open(US"callout", O_RDWR, &dbblock, FALSE, TRUE)))
3664
  {
3440
  {
3665
  log_write(L_dnslist_defer, LOG_MAIN,
3441
  HDEBUG(D_verify) debug_printf_indent("quota cache: not available\n");
3666
    "DNS list lookup defer (probably timeout) for %s: %s", query,
3442
  return FALSE;
3667
    (defer_return == OK)?   US"assumed in list" :
3668
    (defer_return == FAIL)? US"assumed not in list" :
3669
                            US"returned DEFER");
3670
  return defer_return;
3671
  }
3443
  }
3672
3444
if (!(cache_address_record = (dbdata_callout_cache_address *)
3673
/* No entry was found in the DNS; continue for next domain */
3445
    get_callout_cache_record(dbm_file, rcpt, US"address",
3674
3446
      pos_cache, neg_cache)))
3675
HDEBUG(D_dnsbl)
3676
  {
3447
  {
3677
  debug_printf("DNS lookup for %s failed\n", query);
3448
  dbfn_close(dbm_file);
3678
  debug_printf("=> that means %s is not listed at %s\n",
3449
  return FALSE;
3679
     keydomain, domain);
3680
  }
3450
  }
3681
3451
if (cache_address_record->result == ccache_accept)
3682
return FAIL;
3452
  *yield = OK;
3453
dbfn_close(dbm_file);
3454
return TRUE;
3683
}
3455
}
3684
3456
3457
/* Quota cache write */
3685
3458
3459
static void
3460
cache_quota_write(const uschar * rcpt, int yield, int pos_cache, int neg_cache)
3461
{
3462
open_db dbblock, *dbm_file = NULL;
3463
dbdata_callout_cache_address cache_address_record;
3686
3464
3465
if (!pos_cache && !neg_cache)
3466
  return;
3467
if (!(dbm_file = dbfn_open(US"callout", O_RDWR|O_CREAT, &dbblock, FALSE, TRUE)))
3468
  {
3469
  HDEBUG(D_verify) debug_printf_indent("quota cache: not available\n");
3470
  return;
3471
  }
3687
3472
3688
/*************************************************
3473
cache_address_record.result = yield == OK ? ccache_accept : ccache_reject;
3689
*        Check host against DNS black lists      *
3690
*************************************************/
3691
3692
/* This function runs checks against a list of DNS black lists, until one
3693
matches. Each item on the list can be of the form
3694
3695
  domain=ip-address/key
3696
3697
The domain is the right-most domain that is used for the query, for example,
3698
blackholes.mail-abuse.org. If the IP address is present, there is a match only
3699
if the DNS lookup returns a matching IP address. Several addresses may be
3700
given, comma-separated, for example: x.y.z=127.0.0.1,127.0.0.2.
3701
3702
If no key is given, what is looked up in the domain is the inverted IP address
3703
of the current client host. If a key is given, it is used to construct the
3704
domain for the lookup. For example:
3705
3706
  dsn.rfc-ignorant.org/$sender_address_domain
3707
3708
After finding a match in the DNS, the domain is placed in $dnslist_domain, and
3709
then we check for a TXT record for an error message, and if found, save its
3710
value in $dnslist_text. We also cache everything in a tree, to optimize
3711
multiple lookups.
3712
3474
3713
The TXT record is normally looked up in the same domain as the A record, but
3475
(void)dbfn_write(dbm_file, rcpt, &cache_address_record,
3714
when many lists are combined in a single DNS domain, this will not be a very
3476
	(int)sizeof(dbdata_callout_cache_address));
3715
specific message. It is possible to specify a different domain for looking up
3477
HDEBUG(D_verify) debug_printf_indent("wrote %s quota cache record for %s\n",
3716
TXT records; this is given before the main domain, comma-separated. For
3478
      yield == OK ? "positive" : "negative", rcpt);
3717
example:
3718
3479
3719
  dnslists = http.dnsbl.sorbs.net,dnsbl.sorbs.net=127.0.0.2 : \
3480
dbfn_close(dbm_file);
3720
             socks.dnsbl.sorbs.net,dnsbl.sorbs.net=127.0.0.3
3481
return;
3482
}
3721
3483
3722
The caching ensures that only one lookup in dnsbl.sorbs.net is done.
3723
3484
3724
Note: an address for testing RBL is 192.203.178.39
3485
/* To evaluate a local user's quota, starting in ACL, we need to
3725
Note: an address for testing DUL is 192.203.178.4
3486
fork & exec to regain privileges, to that we can change to the user's
3726
Note: a domain for testing RFCI is example.tld.dsn.rfc-ignorant.org
3487
identity for access to their files.
3727
3488
3728
Arguments:
3489
Arguments:
3729
  where        the acl type
3490
 rcpt		Recipient account
3730
  listptr      the domain/address/data list
3491
 pos_cache	Number of seconds to cache a positive result (delivery
3731
  log_msgptr   log message on error
3492
 		to be accepted).  Zero to disable caching.
3732
3493
 neg_cache	Number of seconds to cache a negative result.  Zero to disable.
3733
Returns:    OK      successful lookup (i.e. the address is on the list), or
3494
 msg		Pointer to result string pointer
3734
                      lookup deferred after +include_unknown
3495
3735
            FAIL    name not found, or no data found for the given type, or
3496
Return:		OK/DEFER/FAIL code
3736
                      lookup deferred after +exclude_unknown (default)
3737
            DEFER   lookup failure, if +defer_unknown was set
3738
*/
3497
*/
3739
3498
3740
int
3499
int
3741
verify_check_dnsbl(int where, const uschar ** listptr, uschar ** log_msgptr)
3500
verify_quota_call(const uschar * rcpt, int pos_cache, int neg_cache,
3501
  uschar ** msg)
3742
{
3502
{
3743
int sep = 0;
3503
int pfd[2], pid, save_errno, yield = FAIL;
3744
int defer_return = FAIL;
3504
void (*oldsignal)(int);
3745
const uschar *list = *listptr;
3505
const uschar * where = US"socketpair";
3746
uschar *domain;
3747
uschar revadd[128];        /* Long enough for IPv6 address */
3748
3749
/* Indicate that the inverted IP address is not yet set up */
3750
3751
revadd[0] = 0;
3752
3506
3753
/* In case this is the first time the DNS resolver is being used. */
3507
*msg = NULL;
3754
3508
3755
dns_init(FALSE, FALSE, FALSE);	/*XXX dnssec? */
3509
if (cached_quota_lookup(rcpt, &yield, pos_cache, neg_cache))
3756
3757
/* Loop through all the domains supplied, until something matches */
3758
3759
while ((domain = string_nextinlist(&list, &sep, NULL, 0)))
3760
  {
3510
  {
3761
  int rc;
3511
  HDEBUG(D_verify) debug_printf_indent("quota cache: address record is %s\n",
3762
  BOOL bitmask = FALSE;
3512
    yield == OK ? "positive" : "negative");
3763
  int match_type = 0;
3513
  if (yield != OK)
3764
  uschar *domain_txt;
3765
  uschar *comma;
3766
  uschar *iplist;
3767
  uschar *key;
3768
3769
  HDEBUG(D_dnsbl) debug_printf("dnslists check: %s\n", domain);
3770
3771
  /* Deal with special values that change the behaviour on defer */
3772
3773
  if (domain[0] == '+')
3774
    {
3775
    if      (strcmpic(domain, US"+include_unknown") == 0) defer_return = OK;
3776
    else if (strcmpic(domain, US"+exclude_unknown") == 0) defer_return = FAIL;
3777
    else if (strcmpic(domain, US"+defer_unknown") == 0)   defer_return = DEFER;
3778
    else
3779
      log_write(0, LOG_MAIN|LOG_PANIC, "unknown item in dnslist (ignored): %s",
3780
        domain);
3781
    continue;
3782
    }
3783
3784
  /* See if there's explicit data to be looked up */
3785
3786
  if ((key = Ustrchr(domain, '/'))) *key++ = 0;
3787
3788
  /* See if there's a list of addresses supplied after the domain name. This is
3789
  introduced by an = or a & character; if preceded by = we require all matches
3790
  and if preceded by ! we invert the result. */
3791
3792
  if (!(iplist = Ustrchr(domain, '=')))
3793
    {
3514
    {
3794
    bitmask = TRUE;
3515
    recipient_verify_failure = US"quota";
3795
    iplist = Ustrchr(domain, '&');
3516
    acl_verify_message = *msg =
3796
    }
3517
      US"Previous (cached) quota verification failure";
3797
3798
  if (iplist)				       /* Found either = or & */
3799
    {
3800
    if (iplist > domain && iplist[-1] == '!')  /* Handle preceding ! */
3801
      {
3802
      match_type |= MT_NOT;
3803
      iplist[-1] = 0;
3804
      }
3805
3806
    *iplist++ = 0;                             /* Terminate domain, move on */
3807
3808
    /* If we found = (bitmask == FALSE), check for == or =& */
3809
3810
    if (!bitmask && (*iplist == '=' || *iplist == '&'))
3811
      {
3812
      bitmask = *iplist++ == '&';
3813
      match_type |= MT_ALL;
3814
      }
3815
    }
3816
3817
3818
  /* If there is a comma in the domain, it indicates that a second domain for
3819
  looking up TXT records is provided, before the main domain. Otherwise we must
3820
  set domain_txt == domain. */
3821
3822
  domain_txt = domain;
3823
  if ((comma = Ustrchr(domain, ',')))
3824
    {
3825
    *comma++ = 0;
3826
    domain = comma;
3827
    }
3518
    }
3519
  return yield;
3520
  }
3828
3521
3829
  /* Check that what we have left is a sensible domain name. There is no reason
3522
if (pipe(pfd) != 0)
3830
  why these domains should in fact use the same syntax as hosts and email
3523
  goto fail;
3831
  domains, but in practice they seem to. However, there is little point in
3832
  actually causing an error here, because that would no doubt hold up incoming
3833
  mail. Instead, I'll just log it. */
3834
3524
3835
  for (uschar * s = domain; *s; s++)
3525
where = US"fork";
3836
    if (!isalnum(*s) && *s != '-' && *s != '.' && *s != '_')
3526
oldsignal = signal(SIGCHLD, SIG_DFL);
3837
      {
3527
if ((pid = exim_fork(US"quota-verify")) < 0)
3838
      log_write(0, LOG_MAIN, "dnslists domain \"%s\" contains "
3528
  {
3839
        "strange characters - is this right?", domain);
3529
  save_errno = errno;
3840
      break;
3530
  close(pfd[pipe_write]);
3841
      }
3531
  close(pfd[pipe_read]);
3532
  errno = save_errno;
3533
  goto fail;
3534
  }
3842
3535
3843
  /* Check the alternate domain if present */
3536
if (pid == 0)		/* child */
3537
  {
3538
  close(pfd[pipe_read]);
3539
  force_fd(pfd[pipe_write], 1);		/* stdout to pipe */
3540
  close(pfd[pipe_write]);
3541
  dup2(1, 0);
3542
  if (debug_fd > 0) force_fd(debug_fd, 2);
3844
3543
3845
  if (domain_txt != domain) for (uschar * s = domain_txt; *s; s++)
3544
  child_exec_exim(CEE_EXEC_EXIT, FALSE, NULL, FALSE, 3,
3846
    if (!isalnum(*s) && *s != '-' && *s != '.' && *s != '_')
3545
    US"-MCq", string_sprintf("%d", message_size), rcpt);
3847
      {
3546
  /*NOTREACHED*/
3848
      log_write(0, LOG_MAIN, "dnslists domain \"%s\" contains "
3547
  }
3849
        "strange characters - is this right?", domain_txt);
3850
      break;
3851
      }
3852
3548
3853
  /* If there is no key string, construct the query by adding the domain name
3549
save_errno = errno;
3854
  onto the inverted host address, and perform a single DNS lookup. */
3550
close(pfd[pipe_write]);
3855
3551
3856
  if (!key)
3552
if (pid < 0)
3857
    {
3553
  {
3858
    if (where == ACL_WHERE_NOTSMTP_START || where == ACL_WHERE_NOTSMTP)
3554
  DEBUG(D_verify) debug_printf_indent(" fork: %s\n", strerror(save_errno));
3859
      {
3555
  }
3860
      *log_msgptr = string_sprintf
3556
else
3861
	("cannot test auto-keyed dnslists condition in %s ACL",
3557
  {
3862
	  acl_wherenames[where]);
3558
  uschar buf[128];
3863
      return ERROR;
3559
  int n = read(pfd[pipe_read], buf, sizeof(buf));
3864
      }
3560
  int status;
3865
    if (!sender_host_address) return FAIL;    /* can never match */
3561
3866
    if (revadd[0] == 0) invert_address(revadd, sender_host_address);
3562
  waitpid(pid, &status, 0);
3867
    rc = one_check_dnsbl(domain, domain_txt, sender_host_address, revadd,
3563
  if (status == 0)
3868
      iplist, bitmask, match_type, defer_return);
3564
    {
3869
    if (rc == OK)
3565
    uschar * s;
3870
      {
3566
3871
      dnslist_domain = string_copy(domain_txt);
3567
    if (n > 0) yield = buf[0];
3872
      dnslist_matched = string_copy(sender_host_address);
3568
    if (n > 4)
3873
      HDEBUG(D_dnsbl) debug_printf("=> that means %s is listed at %s\n",
3569
      save_errno = (buf[1] << 24) | (buf[2] << 16) | (buf[3] << 8) | buf[4];
3874
        sender_host_address, dnslist_domain);
3570
    if ((recipient_verify_failure = n > 5
3875
      }
3571
	? string_copyn_taint(buf+5, n-5, GET_UNTAINTED) : NULL))
3876
    if (rc != FAIL) return rc;     /* OK or DEFER */
3572
      {
3573
      int m;
3574
      s = buf + 5 + Ustrlen(recipient_verify_failure) + 1;
3575
      m = n - (s - buf);
3576
      acl_verify_message = *msg =
3577
	m > 0 ? string_copyn_taint(s, m, GET_UNTAINTED) : NULL;
3578
      }
3579
3580
    DEBUG(D_verify) debug_printf_indent("verify call response:"
3581
      " len %d yield %s errno '%s' where '%s' msg '%s'\n",
3582
      n, rc_names[yield], strerror(save_errno), recipient_verify_failure, *msg);
3583
3584
    if (  yield == OK
3585
       || save_errno == 0 && Ustrcmp(recipient_verify_failure, "quota") == 0)
3586
      cache_quota_write(rcpt, yield, pos_cache, neg_cache);
3587
    else DEBUG(D_verify)
3588
      debug_printf_indent("result not cacheable\n");
3877
    }
3589
    }
3878
3879
  /* If there is a key string, it can be a list of domains or IP addresses to
3880
  be concatenated with the main domain. */
3881
3882
  else
3590
  else
3883
    {
3591
    {
3884
    int keysep = 0;
3592
    DEBUG(D_verify)
3885
    BOOL defer = FALSE;
3593
      debug_printf_indent("verify call response: waitpid status 0x%04x\n", status);
3886
    uschar *keydomain;
3887
    uschar keyrevadd[128];
3888
3889
    while ((keydomain = string_nextinlist(CUSS &key, &keysep, NULL, 0)))
3890
      {
3891
      uschar *prepend = keydomain;
3892
3893
      if (string_is_ip_address(keydomain, NULL) != 0)
3894
        {
3895
        invert_address(keyrevadd, keydomain);
3896
        prepend = keyrevadd;
3897
        }
3898
3899
      rc = one_check_dnsbl(domain, domain_txt, keydomain, prepend, iplist,
3900
        bitmask, match_type, defer_return);
3901
      if (rc == OK)
3902
        {
3903
        dnslist_domain = string_copy(domain_txt);
3904
        dnslist_matched = string_copy(keydomain);
3905
        HDEBUG(D_dnsbl) debug_printf("=> that means %s is listed at %s\n",
3906
          keydomain, dnslist_domain);
3907
        return OK;
3908
        }
3909
3910
      /* If the lookup deferred, remember this fact. We keep trying the rest
3911
      of the list to see if we get a useful result, and if we don't, we return
3912
      DEFER at the end. */
3913
3914
      if (rc == DEFER) defer = TRUE;
3915
      }    /* continue with next keystring domain/address */
3916
3917
    if (defer) return DEFER;
3918
    }
3594
    }
3919
  }        /* continue with next dnsdb outer domain */
3595
  }
3920
3596
3921
return FAIL;
3597
close(pfd[pipe_read]);
3598
signal(SIGCHLD, oldsignal);
3599
errno = save_errno;
3600
return yield;
3601
3602
fail:
3603
DEBUG(D_verify) debug_printf_indent("verify_quota_call fail in %s\n", where);
3604
return yield;
3922
}
3605
}
3923
3606
3607
3924
/* vi: aw ai sw=2
3608
/* vi: aw ai sw=2
3925
*/
3609
*/
3926
/* End of verify.c */
3610
/* End of verify.c */
(-)exim.orig/util/gen_pkcs3.c (+1 lines)
Lines 1-4 Link Here
1
/* Copyright (C) 2012,2016 Phil Pennock.
1
/* Copyright (C) 2012,2016 Phil Pennock.
2
 * Copyright (c) The Exim Maintainers 2021
2
 * This is distributed as part of Exim and licensed under the GPL.
3
 * This is distributed as part of Exim and licensed under the GPL.
3
 * See the file "NOTICE" for more details.
4
 * See the file "NOTICE" for more details.
4
 */
5
 */

Return to bug 46381