* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2017 */
+/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions concerned with verifying things. The original code for callout
#define MT_NOT 1
#define MT_ALL 2
-static uschar cutthrough_response(int, char, uschar **, int);
+static uschar cutthrough_response(client_conn_ctx *, char, uschar **, int);
case ccache_accept:
HDEBUG(D_verify)
debug_printf("callout cache: domain accepts random addresses\n");
+ *failure_ptr = US"random";
dbfn_close(dbm_file);
return TRUE; /* Default yield is OK */
host_af = Ustrchr(host->address, ':') ? AF_INET6 : AF_INET;
- if (!smtp_get_interface(tf->interface, host_af, addr, &interface,
- US"callout") ||
- !smtp_get_port(tf->port, addr, &port, US"callout"))
+ if ( !smtp_get_interface(tf->interface, host_af, addr, &interface,
+ US"callout")
+ || !smtp_get_port(tf->port, addr, &port, US"callout")
+ )
log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address,
addr->message);
+ smtp_port_for_connect(host, port);
+
if ( ( interface == cutthrough.interface
|| ( interface
&& cutthrough.interface
&& Ustrcmp(interface, cutthrough.interface) == 0
) )
- && port == cutthrough.host.port
+ && host->port == cutthrough.host.port
)
{
uschar * resp = NULL;
/* Match! Send the RCPT TO, set done from the response */
done =
- smtp_write_command(&ctblock, SCMD_FLUSH, "RCPT TO:<%.1000s>\r\n",
- transport_rcpt_address(addr,
- addr->transport->rcpt_include_affixes)) >= 0 &&
- cutthrough_response(cutthrough.fd, '2', &resp, CUTTHROUGH_DATA_TIMEOUT) == '2';
+ smtp_write_command(&ctblock, SCMD_FLUSH, "RCPT TO:<%.1000s>\r\n",
+ transport_rcpt_address(addr,
+ addr->transport->rcpt_include_affixes)) >= 0
+ && cutthrough_response(&cutthrough.cctx, '2', &resp,
+ CUTTHROUGH_DATA_TIMEOUT) == '2';
/* This would go horribly wrong if a callout fail was ignored by ACL.
We punt by abandoning cutthrough on a reject, like the
coding means skipping this whole loop and doing the append separately. */
/* Can we re-use an open cutthrough connection? */
- if ( cutthrough.fd >= 0
+ if ( cutthrough.cctx.sock >= 0
&& (options & (vopt_callout_recipsender | vopt_callout_recippmaster))
== vopt_callout_recipsender
&& !random_local_part
The sync_responses() would need to be taught about it and we'd
need another return code filtering out to here.
- Avoid using a SIZE option on the MAIL for all randon-rcpt checks.
+ Avoid using a SIZE option on the MAIL for all random-rcpt checks.
*/
sx.avoid_option = OPTION_SIZE;
new_domain_record.random_result = ccache_accept;
yield = OK; /* Only usable verify result we can return */
done = TRUE;
+ *failure_ptr = US"random";
goto no_conn;
case FAIL: /* rejected: the preferred result */
new_domain_record.random_result = ccache_reject;
debug_printf_indent("problem after random/rset/mfrom; reopen conn\n");
random_local_part = NULL;
#ifdef SUPPORT_TLS
- tls_close(FALSE, TRUE);
+ tls_close(sx.cctx.tls_ctx, TLS_SHUTDOWN_NOWAIT);
#endif
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n");
- (void)close(sx.inblock.sock);
- sx.inblock.sock = sx.outblock.sock = -1;
+ (void)close(sx.cctx.sock);
+ sx.cctx.sock = -1;
#ifndef DISABLE_EVENT
(void) event_raise(addr->transport->event_action,
US"tcp:close", NULL);
here is where we want to leave the conn open. Ditto for a lazy-close
verify. */
+ if (cutthrough.delivery)
+ {
+ if (addr->transport->filter_command)
+ {
+ cutthrough.delivery= FALSE;
+ HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of transport filter\n");
+ }
+#ifndef DISABLE_DKIM
+ if (ob->dkim.dkim_domain)
+ {
+ cutthrough.delivery= FALSE;
+ HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of DKIM signing\n");
+ }
+#endif
+#ifdef EXPERIMENTAL_ARC
+ if (ob->arc_sign)
+ {
+ cutthrough.delivery= FALSE;
+ HDEBUG(D_acl|D_v) debug_printf("Cutthrough cancelled by presence of ARC signing\n");
+ }
+#endif
+ }
+
if ( (cutthrough.delivery || options & vopt_callout_hold)
&& rcpt_count == 1
&& done
== vopt_callout_recipsender
&& !random_local_part
&& !pm_mailfrom
- && cutthrough.fd < 0
+ && cutthrough.cctx.sock < 0
&& !sx.lmtp
)
{
? "cutthrough delivery" : "potential further verifies and delivery");
cutthrough.callout_hold_only = !cutthrough.delivery;
- cutthrough.is_tls = tls_out.active >= 0;
- cutthrough.fd = sx.outblock.sock; /* We assume no buffer in use in the outblock */
+ cutthrough.is_tls = tls_out.active.sock >= 0;
+ /* We assume no buffer in use in the outblock */
+ cutthrough.cctx = sx.cctx;
cutthrough.nrcpt = 1;
cutthrough.transport = addr->transport->name;
cutthrough.interface = interface;
ctblock.buffersize = sizeof(ctbuffer);
ctblock.ptr = ctbuffer;
/* ctblock.cmd_count = 0; ctblock.authenticating = FALSE; */
- ctblock.sock = cutthrough.fd;
+ ctblock.cctx = &cutthrough.cctx;
}
else
{
'2', 1);
}
- if (sx.inblock.sock >= 0)
+ if (sx.cctx.sock >= 0)
{
#ifdef SUPPORT_TLS
- tls_close(FALSE, TRUE);
+ if (sx.cctx.tls_ctx)
+ {
+ tls_close(sx.cctx.tls_ctx, TLS_SHUTDOWN_NOWAIT);
+ sx.cctx.tls_ctx = NULL;
+ }
#endif
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n");
- (void)close(sx.inblock.sock);
- sx.inblock.sock = sx.outblock.sock = -1;
+ (void)close(sx.cctx.sock);
+ sx.cctx.sock = -1;
#ifndef DISABLE_EVENT
(void) event_raise(addr->transport->event_action, US"tcp:close", NULL);
#endif
static BOOL
cutthrough_send(int n)
{
-if(cutthrough.fd < 0)
+if(cutthrough.cctx.sock < 0)
return TRUE;
if(
#ifdef SUPPORT_TLS
- tls_out.active == cutthrough.fd ? tls_write(FALSE, ctblock.buffer, n, FALSE) :
+ cutthrough.is_tls
+ ? tls_write(cutthrough.cctx.tls_ctx, ctblock.buffer, n, FALSE)
+ :
#endif
- send(cutthrough.fd, ctblock.buffer, n, 0) > 0
+ send(cutthrough.cctx.sock, ctblock.buffer, n, 0) > 0
)
{
transport_count += n;
static BOOL
cutthrough_puts(uschar * cp, int n)
{
-if (cutthrough.fd < 0) return TRUE;
-if (_cutthrough_puts(cp, n)) return TRUE;
+if (cutthrough.cctx.sock < 0) return TRUE;
+if (_cutthrough_puts(cp, n)) return TRUE;
cancel_cutthrough_connection(TRUE, US"transmit failed");
return FALSE;
}
/* Get and check response from cutthrough target */
static uschar
-cutthrough_response(int fd, char expect, uschar ** copy, int timeout)
+cutthrough_response(client_conn_ctx * cctx, char expect, uschar ** copy, int timeout)
{
smtp_inblock inblock;
uschar inbuffer[4096];
inblock.buffersize = sizeof(inbuffer);
inblock.ptr = inbuffer;
inblock.ptrend = inbuffer;
-inblock.sock = fd;
-/* this relies on (inblock.sock == tls_out.active) */
+inblock.cctx = cctx;
if(!smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer), expect, timeout))
cancel_cutthrough_connection(TRUE, US"target timeout on read");
BOOL
cutthrough_predata(void)
{
-if(cutthrough.fd < 0 || cutthrough.callout_hold_only)
+if(cutthrough.cctx.sock < 0 || cutthrough.callout_hold_only)
return FALSE;
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP>> DATA\n");
cutthrough_flush_send();
/* Assume nothing buffered. If it was it gets ignored. */
-return cutthrough_response(cutthrough.fd, '3', NULL, CUTTHROUGH_DATA_TIMEOUT) == '3';
+return cutthrough_response(&cutthrough.cctx, '3', NULL, CUTTHROUGH_DATA_TIMEOUT) == '3';
}
{
transport_ctx tctx;
-if(cutthrough.fd < 0 || cutthrough.callout_hold_only)
+if(cutthrough.cctx.sock < 0 || cutthrough.callout_hold_only)
return FALSE;
/* We share a routine with the mainline transport to handle header add/remove/rewrites,
*/
HDEBUG(D_acl) debug_printf_indent("----------- start cutthrough headers send -----------\n");
-tctx.u.fd = cutthrough.fd;
+tctx.u.fd = cutthrough.cctx.sock;
tctx.tblock = cutthrough.addr.transport;
tctx.addr = &cutthrough.addr;
tctx.check_string = US".";
static void
close_cutthrough_connection(const uschar * why)
{
-int fd = cutthrough.fd;
+int fd = cutthrough.cctx.sock;
if(fd >= 0)
{
/* We could be sending this after a bunch of data, but that is ok as
the only way to cancel the transfer in dataphase is to drop the tcp
conn before the final dot.
*/
+ client_conn_ctx tmp_ctx = cutthrough.cctx;
ctblock.ptr = ctbuffer;
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP>> QUIT\n");
_cutthrough_puts(US"QUIT\r\n", 6); /* avoid recursion */
_cutthrough_flush_send();
- cutthrough.fd = -1; /* avoid recursion via read timeout */
+ cutthrough.cctx.sock = -1; /* avoid recursion via read timeout */
+ cutthrough.nrcpt = 0; /* permit re-cutthrough on subsequent message */
/* Wait a short time for response, and discard it */
- cutthrough_response(fd, '2', NULL, 1);
+ cutthrough_response(&tmp_ctx, '2', NULL, 1);
#ifdef SUPPORT_TLS
- tls_close(FALSE, TRUE);
+ if (cutthrough.is_tls)
+ {
+ tls_close(cutthrough.cctx.tls_ctx, TLS_SHUTDOWN_NOWAIT);
+ cutthrough.cctx.tls_ctx = NULL;
+ cutthrough.is_tls = FALSE;
+ }
#endif
HDEBUG(D_transport|D_acl|D_v) debug_printf_indent(" SMTP(close)>>\n");
(void)close(fd);
void
release_cutthrough_connection(const uschar * why)
{
-if (cutthrough.fd < 0) return;
+if (cutthrough.cctx.sock < 0) return;
HDEBUG(D_acl) debug_printf_indent("release cutthrough conn: %s\n", why);
-cutthrough.fd = -1;
+cutthrough.cctx.sock = -1;
+cutthrough.cctx.tls_ctx = NULL;
cutthrough.delivery = cutthrough.callout_hold_only = FALSE;
}
)
return cutthrough.addr.message;
-res = cutthrough_response(cutthrough.fd, '2', &cutthrough.addr.message, CUTTHROUGH_DATA_TIMEOUT);
+res = cutthrough_response(&cutthrough.cctx, '2', &cutthrough.addr.message,
+ CUTTHROUGH_DATA_TIMEOUT);
for (addr = &cutthrough.addr; addr; addr = addr->next)
{
addr->message = cutthrough.addr.message;
if (parse_find_at(address) == NULL)
{
- if ((options & vopt_qualify) == 0)
+ if (!(options & vopt_qualify))
{
- if (f != NULL)
+ if (f)
respond_printf(f, "%sA domain is required for \"%s\"%s\n",
ko_prefix, address, cr);
*failure_ptr = US"qualify";
/* Rewrite and report on it. Clear the domain and local part caches - these
may have been set by domains and local part tests during an ACL. */
-if (global_rewrite_rules != NULL)
+if (global_rewrite_rules)
{
uschar *old = address;
address = rewrite_address(address, options & vopt_is_recipient, FALSE,
{
for (i = 0; i < (MAX_NAMED_LIST * 2)/32; i++) vaddr->localpart_cache[i] = 0;
for (i = 0; i < (MAX_NAMED_LIST * 2)/32; i++) vaddr->domain_cache[i] = 0;
- if (f != NULL && !expn) fprintf(f, "Address rewritten as: %s\n", address);
+ if (f && !expn) fprintf(f, "Address rewritten as: %s\n", address);
}
}
/* If this is the real sender address, we must update sender_address at
this point, because it may be referred to in the routers. */
-if ((options & (vopt_fake_sender|vopt_is_recipient)) == 0)
+if (!(options & (vopt_fake_sender|vopt_is_recipient)))
sender_address = address;
/* If the address was rewritten to <> no verification can be done, and we have
to return OK. This rewriting is permitted only for sender addresses; for other
addresses, such rewriting fails. */
-if (address[0] == 0) return OK;
+if (!address[0]) return OK;
/* Flip the legacy TLS-related variables over to the outbound set in case
they're used in the context of a transport used by verification. Reset them
if (testflag(addr, af_pfr))
{
allok = FALSE;
- if (f != NULL)
+ if (f)
{
BOOL allow;
}
else
{
- allow = (addr->address[0] == '|')?
- testflag(addr, af_allow_pipe) : testflag(addr, af_allow_file);
+ allow = addr->address[0] == '|'
+ ? testflag(addr, af_allow_pipe) : testflag(addr, af_allow_file);
fprintf(f, "%s -> %s", addr->parent->address, addr->address);
}
additional host items being inserted into the chain. Hence we must
save the next host first. */
- flags = HOST_FIND_BY_A;
+ flags = HOST_FIND_BY_A | HOST_FIND_BY_AAAA;
if (tf.qualify_single) flags |= HOST_FIND_QUALIFY_SINGLE;
if (tf.search_parents) flags |= HOST_FIND_SEARCH_PARENTS;
else
{
HDEBUG(D_verify) debug_printf("Cannot do callout: neither router nor "
- "transport provided a host list\n");
+ "transport provided a host list, or transport is not smtp\n");
}
}
}
*************************************************/
/* This function checks those header lines that contain addresses, and verifies
-that all the addresses therein are syntactially correct.
+that all the addresses therein are 5322-syntactially correct.
Arguments:
msgptr where to put an error message
uschar *colon, *s;
int yield = OK;
-for (h = header_list; h != NULL && yield == OK; h = h->next)
+for (h = header_list; h && yield == OK; h = h->next)
{
if (h->type != htype_from &&
h->type != htype_reply_to &&
parse_allow_group = TRUE;
- while (*s != 0)
+ while (*s)
{
uschar *ss = parse_find_address_end(s, FALSE);
uschar *recipient, *errmess;
/* Permit an unqualified address only if the message is local, or if the
sending host is configured to be permitted to send them. */
- if (recipient != NULL && domain == 0)
+ if (recipient && !domain)
{
if (h->type == htype_from || h->type == htype_sender)
{
/* It's an error if no address could be extracted, except for the special
case of an empty address. */
- if (recipient == NULL && Ustrcmp(errmess, "empty address") != 0)
+ if (!recipient && Ustrcmp(errmess, "empty address") != 0)
{
uschar *verb = US"is";
uschar *t = ss;
/* deconst cast ok as we're passing a non-const to string_printing() */
*msgptr = US string_printing(
string_sprintf("%s: failing address in \"%.*s:\" header %s: %.*s",
- errmess, tt - h->text, h->text, verb, len, s));
+ errmess, (int)(tt - h->text), h->text, verb, len, s));
yield = FAIL;
break; /* Out of address loop */
/* Advance to the next address */
- s = ss + (terminator? 1:0);
+ s = ss + (terminator ? 1 : 0);
while (isspace(*s)) s++;
} /* Next address */
while (ss > s && isspace(ss[-1])) ss--;
*log_msgptr = string_sprintf("syntax error in '%.*s' header when "
"scanning for sender: %s in \"%.*s\"",
- endname - h->text, h->text, *log_msgptr, ss - s, s);
+ (int)(endname - h->text), h->text, *log_msgptr, (int)(ss - s), s);
yield = FAIL;
done = TRUE;
break;
{
*verrno = vaddr->basic_errno;
if (smtp_return_error_details)
- {
*user_msgptr = string_sprintf("Rejected after DATA: "
"could not verify \"%.*s\" header address\n%s: %s",
- endname - h->text, h->text, vaddr->address, vaddr->message);
- }
+ (int)(endname - h->text), h->text, vaddr->address, vaddr->message);
}
/* Success or defer */
void
verify_get_ident(int port)
{
-int sock, host_af, qlen;
+client_conn_ctx ident_conn_ctx = {0};
+int host_af, qlen;
int received_sender_port, received_interface_port, n;
uschar *p;
+blob early_data;
uschar buffer[2048];
/* Default is no ident. Check whether we want to do an ident check for this
address, the incoming interface address will also be IPv6. */
host_af = Ustrchr(sender_host_address, ':') == NULL ? AF_INET : AF_INET6;
-if ((sock = ip_socket(SOCK_STREAM, host_af)) < 0) return;
+if ((ident_conn_ctx.sock = ip_socket(SOCK_STREAM, host_af)) < 0) return;
-if (ip_bind(sock, host_af, interface_address, 0) < 0)
+if (ip_bind(ident_conn_ctx.sock, host_af, interface_address, 0) < 0)
{
DEBUG(D_ident) debug_printf("bind socket for ident failed: %s\n",
strerror(errno));
goto END_OFF;
}
-/*XXX could take advantage of TFO early-data. Hmm, what are the
-error returns; can we differentiate connect from data fails?
-Do we need to? */
-if (ip_connect(sock, host_af, sender_host_address, port,
- rfc1413_query_timeout, &tcp_fastopen_nodata) < 0)
+/* Construct and send the query. */
+
+qlen = snprintf(CS buffer, sizeof(buffer), "%d , %d\r\n",
+ sender_host_port, interface_port);
+early_data.data = buffer;
+early_data.len = qlen;
+
+if (ip_connect(ident_conn_ctx.sock, host_af, sender_host_address, port,
+ rfc1413_query_timeout, &early_data) < 0)
{
if (errno == ETIMEDOUT && LOGGING(ident_timeout))
log_write(0, LOG_MAIN, "ident connection to %s timed out",
goto END_OFF;
}
-/* Construct and send the query. */
-
-sprintf(CS buffer, "%d , %d\r\n", sender_host_port, interface_port);
-qlen = Ustrlen(buffer);
-if (send(sock, buffer, qlen, 0) < 0)
- {
- DEBUG(D_ident) debug_printf("ident send failed: %s\n", strerror(errno));
- goto END_OFF;
- }
-
/* Read a response line. We put it into the rest of the buffer, using several
recv() calls if necessary. */
int size = sizeof(buffer) - (p - buffer);
if (size <= 0) goto END_OFF; /* Buffer filled without seeing \n. */
- count = ip_recv(sock, p, size, rfc1413_query_timeout);
+ count = ip_recv(&ident_conn_ctx, p, size, rfc1413_query_timeout);
if (count <= 0) goto END_OFF; /* Read error or EOF */
/* Scan what we just read, to see if we have reached the terminating \r\n. Be
DEBUG(D_ident) debug_printf("sender_ident = %s\n", sender_ident);
END_OFF:
-(void)close(sock);
+(void)close(ident_conn_ctx.sock);
return;
}
/* Not a query-style lookup; must ensure the host name is present, and then we
do a check on the name and all its aliases. */
-if (sender_host_name == NULL)
+if (!sender_host_name)
{
HDEBUG(D_host_lookup)
debug_printf("sender host name required, to match against %s\n", ss);
/* Match on the sender host name, using the general matching function */
-switch(match_check_string(sender_host_name, ss, -1, TRUE, TRUE, TRUE,
- valueptr))
+switch(match_check_string(sender_host_name, ss, -1, TRUE, TRUE, TRUE, valueptr))
{
case OK: return OK;
case DEFER: return DEFER;
/* If there are aliases, try matching on them. */
aliases = sender_host_aliases;
-while (*aliases != NULL)
- {
+while (*aliases)
switch(match_check_string(*aliases++, ss, -1, TRUE, TRUE, TRUE, valueptr))
{
case OK: return OK;
case DEFER: return DEFER;
}
- }
return FAIL;
}
/* If the lookup succeeded, cache the RHS address. The code allows for
more than one address - this was for complete generality and the possible
- use of A6 records. However, A6 records have been reduced to experimental
- status (August 2001) and may die out. So they may never get used at all,
- let alone in dnsbl records. However, leave the code here, just in case.
+ use of A6 records. However, A6 records are no longer supported. Leave the code
+ here, just in case.
Quite apart from one A6 RR generating multiple addresses, there are DNS
lists that return more than one A record, so we must handle multiple
for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
rr;
rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
- {
if (rr->type == T_A)
{
dns_address *da = dns_address_from_rr(&dnsa, rr);
if (da)
{
*addrp = da;
- while (da->next != NULL) da = da->next;
- addrp = &(da->next);
+ while (da->next) da = da->next;
+ addrp = &da->next;
if (ttl > rr->ttl) ttl = rr->ttl;
}
}
- }
/* If we didn't find any A records, change the return code. This can
happen when there is a CNAME record but there are no A records for what
it points to. */
- if (cb->rhs == NULL) cb->rc = DNS_NODATA;
+ if (!cb->rhs) cb->rc = DNS_NODATA;
}
cb->expiry = time(NULL)+ttl;
records. For A6 records (currently not expected to be used) there may be
multiple addresses from a single record. */
- for (da = cb->rhs->next; da != NULL; da = da->next)
+ for (da = cb->rhs->next; da; da = da->next)
addlist = string_sprintf("%s, %s", addlist, da->address);
HDEBUG(D_dnsbl) debug_printf("DNS lookup for %s succeeded (yielding %s)\n",
/* Address list check; this can be either for equality, or via a bitmask.
In the latter case, all the bits must match. */
- if (iplist != NULL)
+ if (iplist)
{
- for (da = cb->rhs; da != NULL; da = da->next)
+ for (da = cb->rhs; da; da = da->next)
{
int ipsep = ',';
uschar ip[46];
/* Handle exact matching */
if (!bitmask)
- {
- while ((res = string_nextinlist(&ptr, &ipsep, ip, sizeof(ip))) != NULL)
- {
- if (Ustrcmp(CS da->address, ip) == 0) break;
- }
- }
+ {
+ while ((res = string_nextinlist(&ptr, &ipsep, ip, sizeof(ip))))
+ if (Ustrcmp(CS da->address, ip) == 0)
+ break;
+ }
/* Handle bitmask matching */
/* Scan the returned addresses, skipping any that are IPv6 */
- while ((res = string_nextinlist(&ptr, &ipsep, ip, sizeof(ip))) != NULL)
+ while ((res = string_nextinlist(&ptr, &ipsep, ip, sizeof(ip))))
{
if (host_aton(ip, address) != 1) continue;
if ((address[0] & mask) == address[0]) break;
switch(match_type)
{
case 0:
- res = US"was no match";
- break;
+ res = US"was no match"; break;
case MT_NOT:
- res = US"was an exclude match";
- break;
+ res = US"was an exclude match"; break;
case MT_ALL:
- res = US"was an IP address that did not match";
- break;
+ res = US"was an IP address that did not match"; break;
case MT_NOT|MT_ALL:
- res = US"were no IP addresses that did not match";
- break;
+ res = US"were no IP addresses that did not match"; break;
}
debug_printf("=> but we are not accepting this block class because\n");
debug_printf("=> there %s for %s%c%s\n",
{
dns_record *rr;
for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
- rr != NULL;
+ rr;
rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
if (rr->type == T_TXT) break;
- if (rr != NULL)
+ if (rr)
{
int len = (rr->data)[0];
if (len > 511) len = 127;
store_pool = POOL_PERM;
- cb->text = string_sprintf("%.*s", len, (const uschar *)(rr->data+1));
+ cb->text = string_sprintf("%.*s", len, CUS (rr->data+1));
store_pool = old_pool;
}
}