Skip site navigation (1)Skip section navigation (2)
Date:      21 Apr 2009 16:17:17 +0400
From:      "Alexey V.Degtyarev" <alexey@renatasystems.org>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   ports/133891: [PATCH] mail/exim: add support for XCLIENT command
Message-ID:  <20090421121717.94962.qmail@hs-9.renatasystems.org>
Resent-Message-ID: <200904211220.n3LCK1uM022623@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         133891
>Category:       ports
>Synopsis:       [PATCH] mail/exim: add support for XCLIENT command
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-ports-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Tue Apr 21 12:20:01 UTC 2009
>Closed-Date:
>Last-Modified:
>Originator:     Alexey V. Degtyarev
>Release:        FreeBSD 7.1-RELEASE amd64
>Organization:
>Environment:
System: FreeBSD renatasystems.org 7.1-RELEASE FreeBSD 7.1-RELEASE #0: Thu Jan 1 08:58:24 UTC 2009 root@driscoll.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC amd64


	
>Description:
This patch adds support for XCLIENT[1] SMTP command in exim. It has been
successfully tested in production mail service for a months.

[1] http://www.postfix.org/XCLIENT_README.html
[2] http://cebka.pp.ru/blog/2009/01/-eximxclient.html

>How-To-Repeat:
	
>Fix:

	

--- exim-xclient.patch begins here ---
diff -u -rN exim.orig/Makefile exim/Makefile
--- exim.orig/Makefile	2009-01-23 19:27:44.000000000 +0300
+++ exim/Makefile	2009-04-21 15:50:16.000000000 +0400
@@ -7,7 +7,7 @@
 
 PORTNAME=	exim
 PORTVERSION?=	${EXIM_VERSION}
-PORTREVISION=	3
+PORTREVISION=	4
 CATEGORIES=	mail ipv6
 MASTER_SITES=	${MASTER_SITE_EXIM:S/$/:exim/}
 MASTER_SITE_SUBDIR=	exim4/:exim
@@ -250,7 +250,10 @@
 # Don't install scripts to run exim as a daemon
 # (for example when using option mua_wrapper)
 #WITHOUT_DAEMON=	yes
-
+#
+# Enable XCLIENT command in exim
+#WITH_XCLIENT=		yes
+#
 # You should not need to fiddle with anything below this point.
 
 .if defined(WITH_WISHLIST)
@@ -559,6 +562,10 @@
 PLIST_SUB+=	DAEMON="@comment "
 .endif
 
+.if defined(WITH_XCLIENT)
+EXTRA_PATCHES+=	${FILESDIR}/extra-patch-xclient
+.endif
+
 .include <bsd.port.pre.mk>
 
 .if defined(EXIMON_ONLY) && ${MASTERDIR} == ${PKGDIR}
diff -u -rN exim.orig/files/extra-patch-xclient exim/files/extra-patch-xclient
--- exim.orig/files/extra-patch-xclient	1970-01-01 03:00:00.000000000 +0300
+++ exim/files/extra-patch-xclient	2009-02-03 17:32:18.000000000 +0300
@@ -0,0 +1,347 @@
+
+--- src/globals.c.orig	2007-12-10 18:59:58.297661332 +0300
++++ src/globals.c	2007-12-10 19:00:22.299029091 +0300
+@@ -621,6 +621,7 @@
+ BOOL    helo_verified          = FALSE;
+ BOOL    helo_verify_failed     = FALSE;
+ uschar *helo_verify_hosts      = NULL;
++uschar *xclient_allow_hosts    = NULL;
+ uschar *hex_digits             = US"0123456789abcdef";
+ uschar *hold_domains           = NULL;
+ BOOL    host_checking          = FALSE;
+--- src/globals.h.orig	2007-12-10 19:11:45.337953260 +0300
++++ src/globals.h	2007-12-10 19:12:42.341201691 +0300
+@@ -367,6 +367,7 @@
+ extern BOOL    helo_verified;          /* True if HELO verified */
+ extern BOOL    helo_verify_failed;     /* True if attempt failed */
+ extern uschar *helo_verify_hosts;      /* Hard check HELO argument for these */
++extern uschar *xclient_allow_hosts;    /* Allow XCLIENT command for specified hosts */
+ extern uschar *hex_digits;             /* Used in several places */
+ extern uschar *hold_domains;           /* Hold up deliveries to these */
+ extern BOOL    host_find_failed_syntax;/* DNS syntax check failure */
+--- src/macros.h.orig	2007-08-30 18:31:06.000000000 +0400
++++ src/macros.h	2007-12-10 17:36:29.512226916 +0300
+@@ -714,7 +714,7 @@
+ 
+ enum { SCH_NONE, SCH_AUTH, SCH_DATA, SCH_EHLO, SCH_ETRN, SCH_EXPN, SCH_HELO,
+        SCH_HELP, SCH_MAIL, SCH_NOOP, SCH_QUIT, SCH_RCPT, SCH_RSET, SCH_STARTTLS,
+-       SCH_VRFY };
++       SCH_VRFY, SCH_XCLIENT };
+ 
+ /* Returns from host_find_by{name,dns}() */
+ 
+--- src/readconf.c.orig	2007-12-10 19:03:32.809885687 +0300
++++ src/readconf.c	2007-12-10 19:13:37.344336141 +0300
+@@ -404,7 +404,8 @@
+   { "uucp_from_pattern",        opt_stringptr,   &uucp_from_pattern },
+   { "uucp_from_sender",         opt_stringptr,   &uucp_from_sender },
+   { "warn_message_file",        opt_stringptr,   &warn_message_file },
+-  { "write_rejectlog",          opt_bool,        &write_rejectlog }
++  { "write_rejectlog",          opt_bool,        &write_rejectlog },
++  { "xclient_allow_hosts",      opt_stringptr,   &xclient_allow_hosts },
+ };
+ 
+ static int optionlist_config_size =
+--- src/smtp_in.c.orig	2007-12-10 15:54:30.000000000 +0300
++++ src/smtp_in.c	2009-02-03 17:29:33.181798456 +0300
+@@ -63,10 +63,10 @@
+   /* These commands are required to be synchronized, i.e. to be the last in a
+   block of commands when pipelining. */
+ 
+-  HELO_CMD, EHLO_CMD, DATA_CMD, /* These are listed in the pipelining */
+-  VRFY_CMD, EXPN_CMD, NOOP_CMD, /* RFC as requiring synchronization */
+-  ETRN_CMD,                     /* This by analogy with TURN from the RFC */
+-  STARTTLS_CMD,                 /* Required by the STARTTLS RFC */
++  HELO_CMD, EHLO_CMD, XCLIENT_CMD, DATA_CMD, /* These are listed in the pipelining */
++  VRFY_CMD, EXPN_CMD, NOOP_CMD,              /* RFC as requiring synchronization */
++  ETRN_CMD,                                  /* This by analogy with TURN from the RFC */
++  STARTTLS_CMD,                              /* Required by the STARTTLS RFC */
+ 
+   /* This is a dummy to identify the non-sync commands when pipelining */
+ 
+@@ -152,6 +152,7 @@
+   { "rset",       sizeof("rset")-1,       RSET_CMD, FALSE, FALSE },  /* First */
+   { "helo",       sizeof("helo")-1,       HELO_CMD, TRUE,  FALSE },
+   { "ehlo",       sizeof("ehlo")-1,       EHLO_CMD, TRUE,  FALSE },
++  { "xclient",    sizeof("xclient")-1,    XCLIENT_CMD, TRUE, FALSE },
+   { "auth",       sizeof("auth")-1,       AUTH_CMD, TRUE,  TRUE  },
+   #ifdef SUPPORT_TLS
+   { "starttls",   sizeof("starttls")-1,   STARTTLS_CMD, FALSE, FALSE },
+@@ -184,7 +185,7 @@
+ 
+ static uschar *smtp_names[] =
+   {
+-  US"NONE", US"AUTH", US"DATA", US"EHLO", US"ETRN", US"EXPN", US"HELO",
++  US"NONE", US"AUTH", US"DATA", US"EHLO", US"ETRN", US"EXPN", US"HELO", US"XCLIENT",
+   US"HELP", US"MAIL", US"NOOP", US"QUIT", US"RCPT", US"RSET", US"STARTTLS",
+   US"VRFY" };
+ 
+@@ -847,6 +848,205 @@
+ }
+ 
+ 
++/*************************************************
++*   Check XCLIENT line and set sender_address    *
++*************************************************/
++
++/* Check the format of a XCLIENT line. 
++ * XCLIENT Command syntax
++ *
++ * An example client-server conversation is given at the end of this document.
++ *
++ * In SMTP server EHLO replies, the keyword associated with this extension is XCLIENT. It is followed by the names of the attributes that the XCLIENT implementation supports.
++ *
++ * The XCLIENT command may be sent at any time, except in the middle of a mail delivery transaction (i.e. between MAIL and DOT, or MAIL and RSET). 
++ * The XCLIENT command may be pipelined when the server supports ESMTP command pipelining. 
++ * To avoid triggering spamware detectors, the command should be sent at the end of a command group.
++ *
++ * The syntax of XCLIENT requests is described below. 
++ * Upper case and quoted strings specify terminals, lowercase strings specify meta terminals, and SP is whitespace. 
++ * Although command and attribute names are shown in upper case, they are in fact case insensitive.
++ *
++ *   xclient-command = XCLIENT 1*( SP attribute-name"="attribute-value )
++ *
++ *   attribute-name = ( NAME | ADDR | PORT | HELO | PROTO | LOGIN)
++ *
++ *   attribute-value = xtext
++ *
++ * Attribute values are xtext encoded as per RFC 1891.
++ * The NAME attribute specifies an SMTP client hostname (not an SMTP client address), [UNAVAILABLE] when client hostname lookup failed due to a permanent error, or [TEMPUNAVAIL] when the lookup error condition was transient.
++ *
++ * The ADDR attribute specifies an SMTP client numerical IPv4 network address, an IPv6 address prefixed with IPV6:, or [UNAVAILABLE] when the address information is unavailable. Address information is not enclosed with [].
++ *
++ * The PORT attribute specifies the SMTP client TCP port number as a decimal number, or [UNAVAILABLE] when the information is unavailable.
++ * The HELO attribute specifies an SMTP HELO parameter value, or the value [UNAVAILABLE] when the information is unavailable.
++ * The PROTO attribute specifies either SMTP or ESMTP.
++ * 
++ * Note 1: syntactically valid NAME and HELO attribute-value elements can be up to 255 characters long. 
++ * The client must not send XCLIENT commands that exceed the 512 character limit for SMTP commands. 
++ * To avoid exceeding the limit the client should send the information in multiple XCLIENT commands; for example, send NAME and ADDR first, then HELO and PROTO.
++ *
++ * Note 2: [UNAVAILABLE], [TEMPUNAVAIL] and IPV6: may be specified in upper case, lower case or mixed case.
++Argument:
++  s       the data portion of the line (already past any white space)
++
++Returns: TRUE
++         FALSE
++*/
++
++/* XCLIENT MACROS */
++#define XCLIENT_UNAVAIL US"[UNAVAILABLE]"
++#define XCLIENT_TEMPUNAVAIL US"[TEMPUNAVAIL]"
++
++static BOOL
++smtp_handle_xclient(uschar *s)
++{
++  uschar *p, *end, *arg;
++  int len;
++  p = s;
++  end = s + Ustrlen(s);
++
++  while (p <= end) {
++    /* Addr */
++    if (strncmpic(p, US"ADDR=", 5) == 0) {
++      p += 5;
++      arg = p;
++      while (*p++ != ' ' && p <= end );
++      len = p - arg;
++      /* Strip whitespace */
++      if(*(p - 1) == ' ') {
++        len --;
++      }
++      if (len > 0) {
++        sender_host_address = string_copy_malloc(string_copyn(arg, len));
++      }
++      else {
++        return FALSE;
++      }
++    }
++    /* Name */
++    else if (strncmpic(p, US"NAME=", 5) == 0) {
++      p += 5;
++      arg = p;
++      while (*p++ != ' ' && p <= end );
++      len = p - arg;
++      /* Strip whitespace */
++      if(*(p - 1) == ' ') {
++        len --;
++      }
++      if (len > 0) {
++        if ((len == sizeof(XCLIENT_UNAVAIL) - 1 && strncmpic(arg, XCLIENT_UNAVAIL, sizeof (XCLIENT_UNAVAIL) -1) == 0) ||
++            (len == sizeof(XCLIENT_TEMPUNAVAIL) - 1 && strncmpic(arg, XCLIENT_TEMPUNAVAIL, sizeof (XCLIENT_UNAVAIL) -1) == 0)) {
++          sender_host_name = NULL;
++        }
++        else {
++          sender_host_name = string_copy_malloc(string_copyn(arg, len));
++        }
++      }
++      else {
++        return FALSE;
++      }
++    }
++    /* Helo */
++    else if (strncmpic(p, US"HELO=", 5) == 0) {
++      p += 5;
++      arg = p;
++      while (*p++ != ' ' && p <= end );
++      len = p - arg;
++      /* Strip whitespace */
++      if(*(p - 1) == ' ') {
++        len --;
++      }
++        
++      if (len > 0) {
++        if ((len == sizeof(XCLIENT_UNAVAIL) - 1 && strncmpic(arg, XCLIENT_UNAVAIL, sizeof (XCLIENT_UNAVAIL) -1) == 0) ||
++            (len == sizeof(XCLIENT_TEMPUNAVAIL) - 1 && strncmpic(arg, XCLIENT_TEMPUNAVAIL, sizeof (XCLIENT_UNAVAIL) -1) == 0)) {
++          sender_helo_name = NULL;
++        }
++        else {
++          sender_helo_name = string_copy_malloc(string_copyn(arg, len));
++        }
++      }
++      else {
++        return FALSE;
++      }
++    }
++    /* Port */
++    else if (strncmpic(p, US"PORT=", 5) == 0) {
++      p += 5;
++      arg = p;
++      while (*p++ != ' ' && p <= end);
++      len = p - arg;
++      if(*(p - 1) == ' ') {
++        len --;
++      }
++      if (len > 0) {
++        if ((len == sizeof(XCLIENT_UNAVAIL) - 1 && strncmpic(arg, XCLIENT_UNAVAIL, sizeof (XCLIENT_UNAVAIL) -1) == 0) ||
++            (len == sizeof(XCLIENT_TEMPUNAVAIL) - 1 && strncmpic(arg, XCLIENT_TEMPUNAVAIL, sizeof (XCLIENT_UNAVAIL) -1) == 0)) {
++          sender_host_port = 0;
++        }
++        else {
++          sender_host_port = Uatoi(arg);
++        }
++      }
++      else {
++        return FALSE;
++      }
++    }
++    /* Login */
++    else if (strncmpic(p, US"LOGIN=", 6) == 0) {
++      p += 6;
++      arg = p;
++      while (*p++ != ' ' && p <= end);
++      len = p - arg;
++      if(*(p - 1) == ' ') {
++        len --;
++      }
++      if (len > 0) {
++        if ((len == sizeof(XCLIENT_UNAVAIL) - 1 && strncmpic(arg, XCLIENT_UNAVAIL, sizeof (XCLIENT_UNAVAIL) -1) == 0) ||
++            (len == sizeof(XCLIENT_TEMPUNAVAIL) - 1 && strncmpic(arg, XCLIENT_TEMPUNAVAIL, sizeof (XCLIENT_UNAVAIL) -1) == 0)) {
++          authenticated_id = NULL;
++          sender_host_authenticated = NULL;
++        }
++        else {
++          authenticated_id = string_copy_malloc(string_copyn(arg, len));
++          sender_host_authenticated = "xclient";
++          authentication_failed = FALSE;
++        }
++      }
++      else {
++        return FALSE;
++      }
++    }
++    /* Proto */
++    else if (strncmpic(p, US"PROTO=", 6) == 0) {
++      p += 6;
++      arg = p;
++      while (*p++ != ' ' && p <= end);
++      len = p - arg;
++      if(*(p - 1) == ' ') {
++        len --;
++      }
++      if (len > 0) {
++        if (len == 4 && (strncmpic(arg, US"SMTP", 4) == 0)) {
++          esmtp = FALSE;
++        }
++        else if (len == 5 && (strncmpic(arg, US"ESMTP", 5) == 0)) {
++          esmtp = TRUE;
++        }
++      }
++    }
++    else {
++      return FALSE;
++    }
++  }
++
++  host_build_sender_fullhost();
++  return TRUE;
++}
++
++#undef XCLIENT_UNAVAIL
++#undef XCLIENT_TEMPUNAVAIL
+ 
+ /*************************************************
+ *   Check HELO line and set sender_helo_name     *
+@@ -1131,6 +1331,11 @@
+     bsmtp_transaction_linecount = receive_linecount;
+     break;
+ 
++    /* Handle XCLIENT command */
++    case XCLIENT_CMD:
++    smtp_handle_xclient(smtp_cmd_data);
++    break;
++
+ 
+     /* The MAIL FROM command requires an address as an operand. All we
+     do here is to parse it for syntactic correctness. The form "<>" is
+@@ -3158,7 +3363,50 @@
+     toomany = FALSE;
+     break;   /* HELO/EHLO */
+ 
++    case XCLIENT_CMD:
++    HAD(SCH_XCLIENT);
++    smtp_mailcmd_count++;
++    if (helo_required && !helo_seen)
++      {
++      smtp_printf("503 HELO or EHLO required\r\n");
++      log_write(0, LOG_MAIN|LOG_REJECT, "rejected XCLIENT from %s: no "
++        "HELO/EHLO given", host_and_ident(FALSE));
++      break;
++      }
++
++    /* Check for an operand */
++    if (smtp_cmd_data[0] == 0)
++      {
++      done = synprot_error(L_smtp_syntax_error, 501, NULL,
++        US"XCLIENT must have at least one operand");
++      break;
++      }
++    if(xclient_allow_hosts != NULL) 
++      {
++        if (match_isinlist (sender_host_address, &xclient_allow_hosts, ':', NULL, NULL, MCL_NOEXPAND, FALSE, NULL) != OK) 
++          {
++            done = synprot_error(L_smtp_syntax_error, 550, NULL,
++                  US"XCLIENT is not allowed");
++            break;
++          }
++      }
++    else
++      {
++      done = synprot_error(L_smtp_syntax_error, 550, NULL,
++        US"XCLIENT is not allowed");
++      break;
++      }
++    if(smtp_handle_xclient(smtp_cmd_data) == FALSE) 
++      {
++      done = synprot_error(L_smtp_syntax_error, 501, NULL,
++        US"bad command parameter syntax");
++      break;
++      }
++    smtp_code = US"220";   /* Default status code */
++
++    smtp_printf("%s XCLIENT success\r\n", smtp_code);
+ 
++    break; /* XCLIENT */
+     /* The MAIL command requires an address as an operand. All we do
+     here is to parse it for syntactic correctness. The form "<>" is
+     a special case which converts into an empty string. The start/end
diff -u -rN exim.orig/options exim/options
--- exim.orig/options	2008-10-04 20:04:22.000000000 +0400
+++ exim/options	2009-04-21 16:03:04.000000000 +0400
@@ -172,6 +172,9 @@
 #WITH_ICONV
 # Link with libiconv to enable header charset conversion
 
+#WITH_XCLIENT
+# Enable XCLIENT command in exim: http://www.postfix.org/XCLIENT_README.html
+
 ## AUTOMATICALLY GENERATED FILE - DO NOT CHANGE ANYTHING BELOW THIS LINE ##
 # use `make config' to edit the local configuration
 # use `make makeconfig' to edit the defaults (MAINTAINER only)
--- exim-xclient.patch ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20090421121717.94962.qmail>