#------------------------------------------------------------------------------ # Who: # Richard Nelson # What: # 1) New macro ${client_helo} containing the EHLO/HELO text (or null) # 2) New ruleset check_helo called after the EHLO/HELO and before the # milter callout. This ruleset invocation and handling are modeled # after the existing check_* rulesets # Why: # 0) $s is transient, and not set until MAIL FROM: is seen - I want the # ability to check the EHLO/HELO string elsewere (like check_vrfy). # ${client_helo} is set upon seeing the EHLO/HELO command and # remains valid forever. # 1) There is an IBM internal system check routine for AIX and Linux that # I'm thinking will soon be a requirement to pass its audit... Like # all such tools, it is limited - it requires that vrfy,expn are # disabled... well, I don't do that... if you can relay through the # box, then you can query it. If you can't relay, you get 5.7.1 ! # using the new macro - I can specifically deny the scanner - even # though other traffic is unaffected. # 2) It can provide the same function as -DPICKY_HELO_CHECK, dynamically # by making those checks in the new check_helo ruleset - as outlined # below (NOT RECOMMENDED) # 3) It can be passed to the milters, if they choose (like mimedefang) # to apparently not support the helo callout # 4) I was bored stiff being in the bowels of a COBOL compiler and # needed a sanity break :) # Design questions: # Testing: # 1) Running on three boxes, two of which make use of the macro and # ruleset to block. The new function works great - and no ill # affects seen on any of the boxes. # Documentation: # See below for the new macro and ruleset # TODO: # add to milter macro specifications # Changes: # 1) deliver.c -- remove client_helo from the envelope like all the # other client_* macros # 2) srvrsmtp.c # A) A new boolean variable indicating that the helo string is valid # gothelo is not sufficient here... the new scope is very small... # B) A new character pointer holding the helo string address # C) After obtaining a valid helo string, or accepting an invalid # one, create a copy of the string for permanence # D) Update the client_helo macro variable with the helo string #------------------------------------------------------------------------------ #5.2. D -- Define Macro # ... # ${client_helo} # The string specified by the SMTP client on the EHLO/HELO # command, or null if no EHLO/HELO was seen. Defined in the # SMTP server only. Unlike the $s macro, which is transient # and not available in all rulesets, the {client_helo} macro # is available to all rulesets after the EHLO/HELO greeting. # ... #------------------------------------------------------------------------------ #5.1.4.?. check_helo # # The check_helo ruleset is passed the address # or name parameter of the SMTP EHLO/HELO command. It can # accept or reject the address. Note that rejecting mail # based upon this check is a violation of the standards! # # One could impliment an improved -PICKY_HELO_CHECK test # here by checking the values of {client_name}, {client_addr}, # against {client_helo} and {daemon_addr}. #------------------------------------------------------------------------------ diff -c 'deliver.orig' 'deliver.c' Index: ./deliver.orig Prereq: 8.986 *** ./sendmail-8.13.4/sendmail/deliver.c Tue Aug 10 17:50:11 2004 --- ./deliver.c Tue Aug 10 17:44:04 2004 *************** *** 1363,1368 **** --- 1363,1369 ---- macdefine(&e->e_macro, A_PERM, macid("{client_addr}"), ""); macdefine(&e->e_macro, A_PERM, macid("{client_port}"), ""); macdefine(&e->e_macro, A_PERM, macid("{client_resolve}"), ""); + macdefine(&e->e_macro, A_PERM, macid("{client_helo}"), ""); } SM_TRY diff -c 'srvrsmtp.orig' 'srvrsmtp.c' Index: ./srvrsmtp.orig Prereq: 8.906 *** ./sendmail-8.13.4/sendmail/srvrsmtp.c Tue Aug 10 17:50:23 2004 --- ./srvrsmtp.c Tue Aug 10 17:42:54 2004 *************** *** 444,449 **** --- 444,451 ---- char *volatile protocol; /* sending protocol */ char *volatile sendinghost; /* sending hostname */ char *volatile peerhostname; /* name of SMTP peer or "localhost" */ + char *volatile helo_name; /* client_helo string */ + bool helo_accept = false; /* helo/ehlo command accepted */ auto char *delimptr; char *id; volatile unsigned int n_badcmds = 0; /* count of bad commands */ *************** *** 1976,1981 **** --- 1978,1987 ---- { q = "pleased to meet you"; sendinghost = sm_strdup_x(p); + helo_accept = true; + helo_name = sm_strdup_x(p); + macdefine(&e->e_macro, A_PERM, macid("{client_helo}"), + helo_name); } else if (!AllowBogusHELO) { *************** *** 1989,1994 **** --- 1995,2004 ---- else { q = "accepting invalid domain name"; + helo_accept = true; + helo_name = sm_strdup_x(p); + macdefine(&e->e_macro, A_PERM, macid("{client_helo}"), + helo_name); } if (gothelo) *************** *** 1996,2001 **** --- 2006,2028 ---- CLEAR_STATE(cmdbuf); } + if (helo_accept) { + if (rscheck("check_helo", helo_name, + NULL, e, RSF_RMCOMM|RSF_COUNT, 3, + NULL, e->e_id) != EX_OK || + Errors > 0) + sm_exc_raisenew_x(&EtypeQuickAbort, 1); + + if (MaxMessageSize > 0 && + (e->e_msgsize > MaxMessageSize || + e->e_msgsize < 0)) + { + usrerr("552 5.2.3 Message size exceeds fixed maximum message size (%ld)", + MaxMessageSize); + sm_exc_raisenew_x(&EtypeQuickAbort, 1); + } + } + #if MILTER if (smtp.sm_milterlist && smtp.sm_milterize && !bitset(EF_DISCARD, e->e_flags))