"Fossies" - the Fresh Open Source Software Archive

Member "html-trap.procmail" (20 Jan 2006, 69446 Bytes) of package /linux/privat/old/procmail-sanitizer.tar.gz:


As a special service "Fossies" has tried to format the requested text file into HTML format (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

A hint: This file contains one or more very long lines, so maybe it is better readable using the pure text view mode that shows the contents as wrapped lines within the browser window.


    1 ### Copyright (C) 1997-2004 John D. Hardin
    2 ### This program is free software; you can redistribute it and/or modify
    3 ### it under the terms of the GNU General Public License as published by
    4 ### the Free Software Foundation; either version 2 of the License, or
    5 ### (at your option) any later version.
    6 ###
    7 ### This program is distributed in the hope that it will be useful,
    8 ### but WITHOUT ANY WARRANTY; without even the implied warranty of
    9 ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   10 ### GNU General Public License for more details.
   11 ###
   12 ### Contact the copyright holder for commercial licensing terms
   13 ### if you wish to incorporate this code or portions of it into
   14 ### non-GPL software.
   15 ###
   16 #
   17 # <jhardin@impsec.org>
   18 # $Id: html-trap.procmail,v 1.151 2006-01-20 07:29:24-08 jhardin Exp jhardin $
   19 #
   20 # Baroquely complex Procmail and Perl recipe to defang active-content HTML tags
   21 # to protect those people foolish enough to read their mail from a web browser
   22 # or HTML-enabled mail client. Also mangles the attachment name on executable
   23 # attachments to prevent attacks, at the cost of not being able to run
   24 # programs from within your mail client - which you shouldn't do anyway.
   25 # Also protects against excessively long filenames in attachments, which
   26 # can cause nasty things to happen in some clients, and excessively long
   27 # MIME headers, which may crash or allow exploits of some clients.
   28 #
   29 # All of the configuration options discussed below must be set in the
   30 # procmail script that calls this filter, before this filter is called.
   31 # Please see http://www.impsec.org/email-tools/sanitizer-configuration.html
   32 # for complete documentation of all configuration options.
   33 #
   34 # If you wish to override the default list of executable extensions,
   35 # set MANGLE_EXTENSIONS to a regexp (see where it is defined below for
   36 # the proper syntax). DO NOT start or end it with a vertical bar or have
   37 # two adjacent vertical bars!
   38 #
   39 # If you wish to block specific executable or document filenames from
   40 # attachments, define $POISONED_EXECUTABLES to point at a filename
   41 # containing one filename per line, with no leading spaces. Trailing spaces
   42 # and comments (beginning with "#") are permitted.
   43 # Case is ignored. Wildcards are allowed, using a mishmash of filename
   44 # globbing and regular expression syntax.
   45 #
   46 # Site policy for trapped messages can be specified within limited bounds.
   47 # To redirect poisoned messages to a file or directory, set
   48 # $SECURITY_QUARANTINE to the name of the file or directory. To notify
   49 # administrator(s), set $SECURITY_NOTIFY and/or $SECURITY_NOTIFY_VERBOSE to a
   50 # comma-delimited address list. The _VERBOSE recipients will get the whole
   51 # message.
   52 #
   53 # If the trapped message cannot be saved in $SECURITY_QUARANTINE for any
   54 # reason, the message will be bounced unless $SECURITY_QUARANTINE_OPTIONAL is
   55 # set to any value.
   56 #
   57 # This performs limited scanning of attachments for M$ macros which contain
   58 # possibly dangerous code (as opposed to specific strings from specific
   59 # variants of specific exploits). To disable this scanning, set
   60 # $DISABLE_MACRO_CHECK to anything. To adjust the score an attachment is
   61 # considered "poisoned" at, set $POISONED_SCORE. The default is 25, which
   62 # should be okay unless you see valid attachments with complex macros. Set
   63 # $SCORE_HISTORY to a filename to track the scores on scanned documents.
   64 # If you wish to do profiling before implementing poisoning, set
   65 # $SCORE_ONLY to anything to scan and possibly record scores but not
   66 # poison. This could also be accomplished by setting $POISONED_SCORE to a
   67 # very high value (200?), which would trap attacks while still allowing
   68 # profiling.
   69 #
   70 # This performs scanning of .ZIP archive attachments for filenames. .ZIP
   71 # attachments will be handled by the POISON and STRIP lists, and
   72 # $ZIPPED_EXECUTABLES lists filespecs that will cause the message to be
   73 # quarantined if found in the .ZIP attachment
   74 #
   75 # If you wish to send a message to the author of a trapped message, set
   76 # $SECURITY_NOTIFY_SENDER to any value. To replace the canned message that
   77 # is sent to the author of a trapped message, set $SECURITY_NOTIFY_SENDER
   78 # to point at a text file for the message body. No variable expansion is
   79 # performed on the body of this message. If you want to notify the
   80 # sender's postmaster as well, set $SECURITY_NOTIFY_SENDER_POSTMASTER
   81 # to any value. If you are not running this on a mail relay, you can use
   82 # $SECURITY_NOTIFY_RECIPIENT in the same manner as $SECURITY_NOTIFY_SENDER.
   83 #
   84 # This could also be extended fairly easily to allow virus-checking of
   85 # attachments, assuming you have a virus-checker that will run under *nix.
   86 #
   87 # NOTES
   88 #   Requires perl.
   89 #   Attachment scanning requires the "mktemp" and "mimencode" programs OR
   90 #   the installation of the CPAN Perl modules MIME::Base64 and File::MkTemp.
   91 #   Set $USE_CPAN if you want to use CPAN modules. If you can't put those
   92 #   modules in their system directories (e.g. you're running this on your
   93 #   ISP's computer), put them somewhere accessible and set $PVT_CPAN to that
   94 #   directory.
   95 #   Scanning of ZIP attachments requires the "unzip" program.
   96 #
   97 #   This is a non-delivering filter recipe unless $SECURITY_QUARANTINE is
   98 #   set.
   99 #
  100 # INVOCATION
  101 #   Insert
  102 #     CONFIG_VARIABLE=some_value
  103 #     {repeat as needed}
  104 #     INCLUDERC=html-trap.procmail
  105 #   into your .procmailrc at the beginning or end.
  106 #
  107 #   For further details, particularly how to set up site-wide and mail hub
  108 #   or relay filtering, visit:
  109 #   http://www.impsec.org/email-tools/procmail-security.html
  110 #
  111 
  112 # possible bug workaround?
  113 LINEBUF=8192
  114 
  115 # Size LINEBUF dynamically to deal with excessively large headers
  116 :0 H
  117 * 32000^0
  118 * 1^1 .
  119 {
  120   LINEBUF="$="
  121 }
  122 
  123 # override csh and cousins
  124 :0
  125 * SHELL ?? csh$
  126 {
  127   SHELL="/bin/sh"
  128 }
  129 
  130 # Make sure $LOGFILE exists so the shells don't barf
  131 LOGFILE=${LOGFILE:-"/dev/null"}
  132 
  133 #---------------------------------------------------------------------------
  134 # Grab some info for logging
  135 #
  136 NL="
  137 "
  138 SUBJ=""
  139 FROM="unknown"
  140 FROMDOM=""
  141 REPLY_SUPPRESSED=""
  142 
  143 :0
  144 * ^Subject[ 	]*:[ 	]+\/[^ ].+
  145 {
  146   SUBJ=" in \"$MATCH\""
  147 }
  148 
  149 OVERRIDEFORMAIL="Xx:"
  150 
  151 # AOL mail servers look up who is dialled in and
  152 # add that user's ID as the X-Apparently-From: header
  153 # This is pretty spoof-proof
  154 
  155 :0
  156 * ^Received: from .*\.aol\.com .* by .*\.aol\.com
  157 * ^X-Apparently-From:.*\/[^ ]+@aol\.com
  158 {
  159   FROM="$MATCH"
  160   OVERRIDEFORMAIL="To: $FROM"
  161   
  162   SUBJ="$SUBJ from $FROM"
  163   FROMDOM="aol.com"
  164 }
  165 
  166 # otherwise, try Return-Path: (the envelope sender)
  167 # which is still subject to spoofing but may be
  168 # overlooked
  169 
  170 :0 E
  171 * ^Return-Path:.*\/<[^>]+@[^>]+>
  172 {
  173   FROM="$MATCH"
  174   
  175   # Did a mailing list rewrite the Return-Path header?
  176   :0
  177   * -1^0
  178   * 1^0 ^Precedence: (bulk|junk|list)
  179   * 1^0 ^(List-Id|X-Mailing-List):
  180   * 9876543210^0 FROM ?? \<owner-
  181   * 9876543210^0 FROM ?? \<[^@ >]+-l-admin@
  182   {
  183     :0
  184     * ^From:.*\/<[^>]+>
  185     {
  186       FROM="$MATCH"
  187     }
  188   }
  189 
  190   SUBJ="$SUBJ from $FROM"
  191   :0
  192   * ^Return-Path:.*<[^@]+@\/[^>]+
  193   {
  194     FROMDOM="$MATCH"
  195   }
  196 }
  197 
  198 # The following runs if Return-Path: header not found
  199 # MAKE SURE your MTA puts in a Return-Path: header!
  200 :0 E
  201 * ^From:.*\/<[^>]+>
  202 {
  203   FROM="$MATCH"
  204   SUBJ="$SUBJ from $FROM"
  205   LOG=" WARN: No usable Return-Path: header found in message.${NL}"
  206 
  207   :0
  208   *   SECURITY_NOTIFY_SENDER ?? [^ ]
  209   * ! SECURITY_DISABLE_SMART_REPLY ?? [^ ]
  210   {
  211     REPLY_SUPPRESSED="NOTICE: No Return-Path: header. Suppressing sender notification.${NL}"
  212     LOG=" $REPLY_SUPPRESSED"
  213     SECURITY_NOTIFY_SENDER=
  214   }
  215 }
  216 
  217 TO=<$LOGNAME>
  218 
  219 :0
  220 * LOGNAME ?? ^root$
  221 {
  222   # If $LOGNAME is root, we're probably running as a gateway filter:
  223   # get the "real" to name(s) out of the message headers.
  224   :0
  225   * ^To: +\/.*
  226   {
  227     TO="$MATCH"
  228   }
  229 }
  230 
  231 # try to get the full recipient address from a Received: header
  232 # this overrides LOGNAME and the To: header
  233 :0
  234 * ^Received: .*for \/<?[^> ]+@[^> ]+\.[^> ;]+>?
  235 {
  236   TO="$MATCH"
  237 }
  238 
  239 :0
  240 * ^Received: .*for \/<[^> ]+@[^> ]+\.[a-z][a-z][a-z]?[a-z]?[a-z]?[a-z]?>
  241 {
  242   TO="$MATCH"
  243 }
  244 
  245 SUBJ="$SUBJ to $TO"
  246 
  247 :0
  248 * ^Message-ID:.*\/<[^>]+>
  249 {
  250   MSGID="$MATCH"
  251   SUBJ="$SUBJ msgid=$MSGID"
  252 }
  253 
  254 SUBJ="$SUBJ
  255 "
  256 
  257 #---------------------------------------------------------------------------
  258 # Override these in /etc/procmailrc as needed
  259 #
  260 
  261 STRIPPED_WARNING=${STRIPPED_WARNING:-"
  262 SECURITY NOTICE:
  263 
  264 The mail system has removed a file attachment from this message.
  265 The attachment has been discarded.
  266 
  267 Please contact your system administrator for details.
  268 
  269 "}
  270 
  271 POISONED_WARNING=${POISONED_WARNING:-"
  272 SECURITY WARNING!
  273 
  274 The mail system has detected that the following
  275 attachment may contain hazardous program code, is
  276 a suspicious file type, or has a suspicious file name.
  277 Do not trust it. Contact your system administrator immediately.
  278 
  279 "}
  280 
  281 MACRO_WARNING=${MACRO_WARNING:-"
  282 SECURITY WARNING!
  283 
  284 The mail delivery system has detected that the preceding
  285 document attachment appears to contain hazardous macro code.
  286 Macro Scanner score: "}
  287 
  288 MACRO_DETAILS=${MACRO_DETAILS:-"Macro Scanner score details:
  289 "
  290 
  291 ZIP_MAGIC_WARNING=${ZIP_MAGIC_WARNING:-"
  292 SECURITY WARNING!
  293 
  294 The mail system has detected that the preceding attachment
  295 claims to be a ZIP archive, but it does not have a valid ZIP
  296 archive signature.
  297 Do not trust it. Contact your system administrator immediately.
  298 
  299 "}
  300 
  301 ZIPPED_WARNING=${ZIPPED_WARNING:-"
  302 SECURITY WARNING!
  303 
  304 The mail system has detected that the preceding ZIP archive
  305 attachment contains suspicious files.
  306 Do not trust it. Contact your system administrator immediately.
  307 
  308 The suspicious files in the archive are:
  309 
  310 "}
  311 
  312 :0
  313 * ! DISABLE_RAR_SCAN ?? [^ ]
  314 * ! ? type unrar >/dev/null 2>&1
  315 {
  316   # unrar not on $PATH
  317   LOG=" unrar not found, disabling RAR scan - either install unrar or define DISABLE_RAR_SCAN${NL}"
  318   DISABLE_RAR_SCAN=Y
  319 }
  320 
  321 
  322 RAR_MAGIC_WARNING=${RAR_MAGIC_WARNING:-"
  323 SECURITY WARNING!
  324 
  325 The mail system has detected that the preceding attachment
  326 claims to be a RAR archive, but it does not have a valid RAR
  327 archive signature.
  328 Do not trust it. Contact your system administrator immediately.
  329 
  330 "}
  331 
  332 RARRED_WARNING=${RARRED_WARNING:-"
  333 SECURITY WARNING!
  334 
  335 The mail system has detected that the preceding RAR archive
  336 attachment contains suspicious files.
  337 Do not trust it. Contact your system administrator immediately.
  338 
  339 The suspicious files in the archive are:
  340 
  341 "}
  342 
  343 BAD_BASE64_WARNING=${BAD_BASE64_WARNING:-"
  344 SECURITY WARNING!
  345 
  346 The mail system has detected that the preceding attachment
  347 was encoded in a manner intended to bypass security filtering.
  348 Do not trust it. Contact your system administrator immediately.
  349 
  350 "}
  351 
  352 BAD_JPEG_WARNING=${BAD_JPEG_WARNING:-"
  353 SECURITY WARNING!
  354 
  355 The mail system has detected that the preceding attachment
  356 appears to be a JPEG image containing a Microsoft buffer overflow attack.
  357 Do not trust it. Contact your system administrator immediately.
  358 
  359 "}
  360 
  361 WMF_WARNING=${WMF_WARNING:-"
  362 SECURITY WARNING!
  363 
  364 The mail system has detected that the preceding attachment
  365 appears to be a WMF image. It has been blocked for security reasons.
  366 Contact your system administrator immediately.
  367 
  368 "}
  369 
  370 TNEF_WARNING=${TNEF_WARNING:-"
  371 SECURITY NOTICE:
  372 
  373 The mail system has removed a Microsoft attachment for security reasons.
  374 The sender should disable sending Rich Text format in Outlook and
  375 disable sending TNEF to the Internet from their Microsoft Exchange gateway.
  376 
  377 See http://support.microsoft.com/support/kb/articles/Q241/5/38.ASP
  378 and http://www.microsoft.com/TechNet/exchange/2505ch10.asp
  379 for more information.
  380 
  381 "}
  382 
  383 
  384 # FROM address for notifications
  385 SECURITY_LOCAL_POSTMASTER=${SECURITY_LOCAL_POSTMASTER:-"postmaster"}
  386 
  387 # MTA command line options when generating messages
  388 # get recipient(s) from command line
  389 MTA_FLAGS_CMDLN=${MTA_FLAGS_CMDLN:-"-U"}
  390 # get recipient(s) from message headers
  391 MTA_FLAGS_HDRS=${MTA_FLAGS_HDRS:-"-oi -t -f$SECURITY_LOCAL_POSTMASTER"}
  392 
  393 # How paranoid to be about stuff embedded in documents
  394 # default: very
  395 SC_MBD=${SECURITY_OFFICE_EMBED_SCORE:-99}
  396 
  397 
  398 #---------------------------------------------------------------------------
  399 # trap some excessively long RFC-822 headers
  400 #
  401 
  402 :0
  403 * ^\/Subject: ..................................................................................................................................................................................................................................................*
  404 {
  405   LOG=" Trapped excessively long header$SUBJ"
  406   STATUS="STATUS: Header truncated."
  407   HDR="$MATCH"
  408 
  409   # truncate the header
  410   :0 fw h
  411   * ^\/Subject: .................................................................................................................................................................................................................................................
  412   | formail -i "$MATCH"
  413 
  414   SECURITY_NOTIFY=${SECURITY_NOTIFY:-"postmaster"}
  415 
  416   :0
  417   * ! SECURITY_NONOTIFY_LONGSUBJECT ?? [^ ]
  418   * SECURITY_NOTIFY ?? [^ ]
  419   * !$ ^X-Loop: EMAIL SECURITY WARNING $HOST $SECRET
  420   {
  421     LOG="${NL} NOTIFY $SECURITY_NOTIFY${NL}"
  422 
  423     :0 h ci
  424     | ( \
  425         echo "To: $SECURITY_NOTIFY";\
  426         echo 'From: "Procmail Security daemon"' "<${SECURITY_LOCAL_POSTMASTER}>";\
  427         echo 'Subject: SECURITY WARNING - possible email attack';\
  428         echo "X-Loop: EMAIL SECURITY WARNING $HOST $SECRET"; \
  429         echo ;\
  430         echo 'Trapped excessively long header:' ;\
  431         echo "$HDR";\
  432         echo ;\
  433         echo "$STATUS";\
  434         echo ;\
  435         echo 'Headers from message:';\
  436         echo ;\
  437         sed -e 's/^/> /' ;\
  438       ) | $SENDMAIL $MTA_FLAGS_CMDLN $SECURITY_NOTIFY
  439   }
  440 }
  441 
  442 
  443 :0
  444 * \/^((resent-)?(sender|from|(reply-)?to|cc|bcc)|(errors|disposition-notification|apparently)-to|Return-Path): .*<>.*<>.*<>.*<>.*<>.*<>.*
  445 {
  446   HDR=$MATCH
  447   LOG=" Trapped multiple null addresses (possible sendmail attack)"
  448   STATUS="STATUS: Header cleaned."
  449 
  450   # truncate the header
  451   :0 fw h
  452   | sed -e 's/<>.*<>.*<>.*<>.*<>.*<>/<>/g'
  453 
  454   SECURITY_NOTIFY=${SECURITY_NOTIFY:-"postmaster"}
  455 
  456   :0
  457   * SECURITY_NOTIFY ?? [^ ]
  458   * !$ ^X-Loop: EMAIL SECURITY WARNING $HOST $SECRET
  459   {
  460     LOG="${NL} NOTIFY $SECURITY_NOTIFY${NL}"
  461 
  462     :0 h ci
  463     | ( \
  464         echo "To: $SECURITY_NOTIFY";\
  465         echo 'From: "Procmail Security daemon"' "<${SECURITY_LOCAL_POSTMASTER}>";\
  466         echo 'Subject: SECURITY WARNING - possible email attack';\
  467         echo "X-Loop: EMAIL SECURITY WARNING $HOST $SECRET"; \
  468         echo ;\
  469         echo 'Trapped multiple null addresses (possible sendmail exploit):' ;\
  470         echo "$HDR";\
  471         echo ;\
  472         echo "$STATUS";\
  473         echo ;\
  474         echo 'Headers from message:';\
  475         echo ;\
  476         sed -e 's/^/> /' ;\
  477       ) | $SENDMAIL $MTA_FLAGS_CMDLN $SECURITY_NOTIFY
  478   }
  479 }
  480 
  481 
  482 :0
  483 * ^\/(Mime-Version|(Resent-)?(Date|Sender|From|Reply-To)|(errors|disposition-notification|apparently)-to|Message-ID|Return-Path|Status|X-Status|X-Keywords|Content-(Class|Type|Disposition|Transfer-Encoding)): ......................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................*
  484 {
  485   LOG=" Trapped excessively long header$SUBJ"
  486   STATUS="STATUS: Message bounced."
  487   HDR="$MATCH"
  488 
  489   :0
  490   * SECURITY_QUARANTINE ?? [^ ]
  491   {
  492     STATUS="STATUS: Message quarantined in $SECURITY_QUARANTINE, not delivered to recipient."
  493   }
  494 
  495   SECURITY_NOTIFY=${SECURITY_NOTIFY:-"postmaster"}
  496 
  497   :0
  498   * SECURITY_NOTIFY ?? [^ ]
  499   * !$ ^X-Loop: EMAIL SECURITY WARNING $HOST $SECRET
  500   {
  501     LOG="${NL} NOTIFY $SECURITY_NOTIFY${NL}"
  502 
  503     :0 h ci
  504     | ( \
  505         echo "To: $SECURITY_NOTIFY";\
  506         echo 'From: "Procmail Security daemon"' "<${SECURITY_LOCAL_POSTMASTER}>";\
  507         echo 'Subject: SECURITY WARNING - possible email attack';\
  508         echo "X-Loop: EMAIL SECURITY WARNING $HOST $SECRET"; \
  509         echo ;\
  510         echo 'Trapped excessively long header:' ;\
  511         echo "$HDR";\
  512         echo ;\
  513         echo "$STATUS";\
  514         echo ;\
  515         echo 'Headers from message:';\
  516         echo ;\
  517         sed -e 's/^/> /' ;\
  518       ) | $SENDMAIL $MTA_FLAGS_CMDLN $SECURITY_NOTIFY
  519   }
  520 
  521   :0
  522   * SECURITY_QUARANTINE ?? [^ ]
  523   {
  524     :0 :${SECURITY_QUARANTINE_LOCKFILE}
  525     $SECURITY_QUARANTINE
  526 
  527     :0 e
  528     {
  529       # Argh! Quarantine failed!
  530       # notify administrator
  531       LOG="${NL} ERR: QUARANTINE FAILED!${NL}"
  532 
  533       # bounce it.
  534       EXITCODE=65
  535 
  536       :0 h
  537       * SECURITY_NOTIFY ?? [^ ]
  538       * !$ ^X-Loop: EMAIL SECURITY WARNING $HOST $SECRET
  539       | ( \
  540           echo "To: $SECURITY_NOTIFY";\
  541           echo 'From: "Procmail Security daemon"' "<${SECURITY_LOCAL_POSTMASTER}>";\
  542           echo 'Subject: SECURITY WARNING - quarantine failed!';\
  543           echo "X-Loop: EMAIL SECURITY WARNING $HOST $SECRET"; \
  544           echo ;\
  545           echo 'Attempt to quarantine the following message in $SECURITY_QUARANTINE failed.';\
  546           echo 'Message has been bounced.';\
  547           echo 'Verify file access permissions:';\
  548           ls -l $SECURITY_QUARANTINE 2>&1 ;\
  549           echo ;\
  550           echo 'Headers from message:';\
  551           echo ;\
  552           sed -e 's/^/> /' ;\
  553         ) | $SENDMAIL $MTA_FLAGS_CMDLN $SECURITY_NOTIFY
  554 
  555     }
  556   }
  557 
  558   # bounce it.
  559   EXITCODE=65
  560 
  561   # zap it.
  562   :0
  563   /dev/null
  564 
  565 }
  566 
  567 #---------------------------------------------------------------------------
  568 # Not all MIME can be sanitized...
  569 #
  570 :0
  571 * ^Content-Type[ 	]*:.*multipart/((signed)|(encrypted));
  572 * ! SECURITY_DEFANG_SIGNED ?? [^ ]
  573 {
  574   LOG=" WARN: Cannot sanitize message due to signing or encryption$SUBJ"
  575 }
  576 
  577 #---------------------------------------------------------------------------
  578 # Defang HTML active-content tags
  579 #
  580 # NB: In case you think the regexes should be /<[ 	]*TAG/, I suggest
  581 # you *try* such tags in your browser first...
  582 #
  583 # Unfortunately the "on*" (e.g. "onload=") syntax is such that we can't
  584 # reliably look for /onload="/ - there may be whitespace around the =.
  585 # This isn't intended to be a full HTML parser, so we'll err on the side of
  586 # safety by defanging everything, even though it may be outside of an HTML
  587 # context.
  588 #
  589 # This keeps getting uglier as more and more holes are discovered.
  590 #
  591 # This will be folded into a better sanitizer Real Soon Now...
  592 #
  593 
  594 :0
  595 * 9876543210^1 ! ^Content-Type[ 	]*:.*multipart/((signed)|(encrypted));
  596 * 9876543210^1 SECURITY_DEFANG_SIGNED ?? [^ ]
  597 {
  598 #----------- ALL OF THIS IS SKIPPED FOR SIGNED/ENCRYPTED MESSAGES
  599 
  600 # "perl -e" has problems when run as root...
  601 DROPPRIVS=YES
  602 
  603 :0
  604 * DEBUG_VERBOSE ?? [^ ]
  605 {
  606   VERBOSE=YES
  607 }
  608 
  609 :0 H
  610 * [\015][^\012]
  611 {
  612   # this apparently happens a lot, so stop logging it
  613   #LOG="Defanging bare CR in headers$SUBJ"
  614 
  615   :0 fw h
  616   | perl -p -e 's/\015/\012/g'
  617 }
  618 
  619 :0 B
  620 * ! SECURITY_TRUST_HTML ?? [^ ]
  621 * 9876543210^1 \<(html|title|body|meta|app|script|object|embed|i?frame|style|img|bgsound|i?layer|link|form|input|table|th|td|xml)
  622 * 9876543210^1 =(3d)?[ 	]*["'](&{|([a-z]+script|mocha):)
  623 {
  624 
  625   LOG="Defanging active HTML content$SUBJ"
  626 
  627   HAVE_UUE=
  628 
  629   :0 B
  630   * ^begin[ 	]+([0-9]+)?[ 	]+[^ 	]+
  631   {
  632     HAVE_UUE=YES
  633     LOG=" UUE content, HTML defang suppression enabled.$NL"
  634   }
  635 
  636   :0 fw b
  637   | perl -p -e '	#\
  638 	unless ($ENV{"HAVE_UUE"} && /^M.{60}$/ ) {	#\
  639 		if (/ / && /["\047][^"\047\s]*&#x?[1-9][0-9a-f]/i) {	#\
  640 			while (/["\047][^"\047\s]*&#((4[6-9]|5[0-8]|6[4-9]|[78][0-9]|9[07-9]|1[0-1][0-9]|12[0-2])(?![0-9]))/) {	#\
  641 				$char = chr($1);	#\
  642 				s/&#$1;?/$char/g;	#\
  643 			}	#\
  644 			while (/["\047][^"\047\s]*&#(x(2[ef]|3[0-9a]|4[0-9a-f]|5[0-9a]|6[1-9a-f]|7[0-9a]))/i) {	#\
  645 				$char = chr(hex("0$1"));	#\
  646 				s/&#$1;?/$char/gi;	#\
  647 			}	#\
  648 		}	#\
  649 		if (/ / && /["\047][^"\047\s]*%[2-7][0-9a-f]/i) {	#\
  650 			while (/["\047][^"\047\s]*%((2[ef]|3[0-9a]|4[0-9a-f]|5[0-9a]|6[1-9a-f]|7[0-9a]))/i) {	#\
  651 				$char = chr(hex("0x$1"));	#\
  652 				s/%$1/$char/gi;	#\
  653 			}	#\
  654 		}	#\
  655 		if (/<|%3c/) {	#\
  656 			s/(<|%3c)(META|APP|SCRIPT|OBJECT|EMBED|FRAME|IFRAME|LAYER|ILAYER|LINK|FORM|INPUT|XML)/$1DEFANGED_$2/gi;	#\
  657 			unless ($ENV{"SECURITY_TRUST_STYLE_TAGS"}) {	#\
  658 				s/<STYLE/ <!-- <DEFANGED_STYLE/gi;	#\
  659 				s/<\/STYLE/ --> <\/DEFANGED_STYLE/gi;	#\
  660 				s/\sSTYLE\s*=/ DEFANGED_STYLE=/gi;	#\
  661 			}	#\
  662 			if ($ENV{"DEFANG_WEBBUGS"}) {	#\
  663 				s/<IMG/<DEFANGED_IMG/gi;	#\
  664 				s/<BGSOUND/<DEFANGED_BGSOUND/gi;	#\
  665 				if (/<(BODY|TABLE|TH|TD)\s/i) {	#\
  666 					s/\sBACKGROUND\s*=\s*/ DEFANGED_BACKGROUND=/gi;	#\
  667 				}	#\
  668 			}	#\
  669 			s/\sOn(Abort|Blur|Change|Click|DblClick|DragDrop|Error|Focus|KeyDown|KeyPress|KeyUp|Load|MouseDown|MouseMove|MouseOut|MouseOver|MouseUp|Move|Reset|Resize|Select|Submit|Unload|ContextMenu|DragStart)/ DEFANGED_On$1/gi;	#\
  670 		}	#\
  671 		s/^\s*On(Abort|Blur|Change|Click|DblClick|DragDrop|Error|Focus|KeyDown|KeyPress|KeyUp|Load|MouseDown|MouseMove|MouseOut|MouseOver|MouseUp|Move|Reset|Resize|Select|Submit|Unload|ContextMenu|DragStart)/DEFANGED_On$1/gi;	#\
  672 		s/(["\047\075]|url\()([a-z]+script|mocha):/${1}DEFANGED_$2:/gi;	#\
  673 		s/(["\047\075])&{/${1}DEFANGED_&_{/g;	#\
  674 	}	#\
  675         '
  676 }
  677 
  678 #---------------------------------------------------------------------------
  679 # Mangle HTML and executable attachment filenames enough that they won't
  680 # automatically execute, and limit the length of extremely long attachment
  681 # filenames and MIME headers to prevent buffer overflows and client
  682 # crashes (sigh). Adding ${$} to the mangling inserts a bit of randomness
  683 # so that an active-HTML or BO exploit can't just look for an attachment
  684 # named EXPLOIT.DEFANGED-EXE to get around the defanging.
  685 #
  686 # NOTE: the [ 	] has a tab embedded in it - DO NOT remove it...
  687 #
  688 
  689 :0
  690 * ! MANGLE_EXTENSIONS ?? [^ ]
  691 {
  692   MANGLE_EXTENSIONS='html?|exe|com|cmd|bat|pif|sc[rt]|lnk|dll|ocx|do[ct]|xl[swt]|p[po]t|rtf|vb[se]?|hta|p[lm]|sh[bs]|hlp|chm|eml|ws[cfh]|ad[ep]|jse?|md[abew]|ms[ip]|reg|as[dfx]|c[ip]l|pps|wm[avszdf]|vcf|nws|wsz|\{[-0-9a-f]+\}'
  693 }
  694 
  695 
  696 # UUE attachments
  697 :0 B
  698 * ^begin[ 	]+([0-9]+)?[ 	]+[^ 	]+
  699 {
  700   :0 B
  701   * ^begin[ 	]+([0-9]+)?[ 	]+\/[^ 	]....................................................................................................+$
  702   {
  703     LOG="Truncating extremely long attachment filename $MATCH$SUBJ"
  704 
  705     :0 fw b
  706     | perl -p -e 'if (/^begin\s+[0-9]*\s/i) {	#\
  707             ($mode, $filen) = /^begin\s+([0-9]*)\s+(.{64}).*$/i;	#\
  708             $mode = "644" unless $mode;	#\
  709             s/^.*$/begin $mode $filen.../ if $filen;	#\
  710           }'
  711   }
  712 
  713   :0 B
  714   * $ ^begin[ 	]+([0-9]+)?[ 	]+.+\.(${MANGLE_EXTENSIONS})[ 	]*$
  715   {
  716     LOG="Sanitizing executable UUE attachments$SUBJ"
  717 
  718     :0 fw b
  719     | perl -p -e '	#\
  720       if ($stripped) {	#\
  721 	chomp;	#\
  722 	if (/^end$/i || /^\s*$/) {	#\
  723 	  $stripped = 0;	#\
  724 	}	#\
  725 	$_ = ""; next;	#\
  726       }	#\
  727       if (($junk,$filen) = /^begin\s+([0-9]+\s+)?((\\.|[^"])+\.($ENV{"MANGLE_EXTENSIONS"}|\{[-0-9a-f]+\}))[\.\s]*$/io) {	#\
  728 	if ($specf = $ENV{"STRIPPED_EXECUTABLES"}) {	#\
  729 	  if (open(STRIPPED,$specf)) {	#\
  730 	    warn " Checking UUE \"$filen\" for stripping.\n";	#\
  731 	    while (chomp($stp_spec = <STRIPPED>)) {	#\
  732 	      $stp_spec =~ s/^\s+//g;	#\
  733 	      $stp_spec =~ s/\s.*$//g;	#\
  734 	      next unless $stp_spec;	#\
  735 	      $stp_spec =~ s/([^\\])\./$1\\./g;	#\
  736 	      $stp_spec =~ s/\*/.*/g;	#\
  737 	      $stp_spec =~ s/\?\?/?./g;	#\
  738 	      $stp_spec =~ s/([^\(]|^)\?/$1./g;	#\
  739 	      $stp_spec .= "\$" unless $stp_spec =~ /\$/;	#\
  740               warn "  Checking against \"$stp_spec\"\n" if $ENV{"DEBUG"};	#\
  741 	      if ($filen =~ /^${stp_spec}/i) {	#\
  742 	      warn " Stripped UUE attachment \"$filen\".\n";	#\
  743 		$stripped = 1;	#\
  744 		print "\n";	#\
  745 		print "X-Content-Security: [" . $ENV{"HOST"} . "] REPORT: UUE attachment \"$filen\" stripped\n";	#\
  746 		print "\n";	#\
  747 		print $ENV{"STRIPPED_WARNING"};	#\
  748 		print "Filename: $filen\n\n";	#\
  749 		last;	#\
  750 	      }	#\
  751 	    }	#\
  752 	    close(STRIPPED);	#\
  753 	    if ($stripped) {	#\
  754 		$_ = <>;	#\
  755 		$_ = ""; next;	#\
  756 	    }	#\
  757 	  } else {	#\
  758 	    warn " ERR: Unable to open stripped-executables file \"$specf\".\n";	#\
  759 	  }	#\
  760 	}	#\
  761 	if ($specf = $ENV{"POISONED_EXECUTABLES"}) {	#\
  762 	  if (open(POISONED,$specf)) {	#\
  763 	    warn " Checking UUE \"$filen\" for poisoning.\n";	#\
  764 	    while (chomp($psn_spec = <POISONED>)) {	#\
  765               $psn_spec =~ s/^\s+//g;	#\
  766               $psn_spec =~ s/\s.*$//g;	#\
  767               next unless $psn_spec;	#\
  768               $psn_spec =~ s/([^\\])\./$1\\./g;	#\
  769               $psn_spec =~ s/\*/.*/g;	#\
  770               $psn_spec =~ s/\?\?/?./g;	#\
  771 	      $psn_spec =~ s/([^\(]|^)\?/$1./g;	#\
  772 	      $psn_spec .= "\$" unless $psn_spec =~ /\$/;	#\
  773               warn "  Checking against \"$psn_spec\"\n" if $ENV{"DEBUG"};	#\
  774               if ($filen =~ /^${psn_spec}/i) {	#\
  775                 warn " Trapped poisoned attachment \"$filen\".\n";	#\
  776                 print "X-Content-Security: [", $ENV{"HOST"}, "] NOTIFY\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
  777                 print "X-Content-Security: [", $ENV{"HOST"}, "] REPORT: Trapped poisoned attachment \"$filen\"\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
  778                 print "X-Content-Security: [", $ENV{"HOST"}, "] QUARANTINE\n" if $ENV{"SECURITY_QUARANTINE"};	#\
  779                 print "\n";	#\
  780 		print $ENV{"POISONED_WARNING"};	#\
  781                 print "SUSPICIOUS ATTACHMENT: ";	#\
  782                 last;	#\
  783               }	#\
  784             }	#\
  785             close(POISONED);	#\
  786           } else {	#\
  787             warn " ERR: Unable to open poisoned-executables file \"$specf\".\n";	#\
  788           }	#\
  789         }	#\
  790         warn " Mangling executable UUE filename \"$filen\".\n";	#\
  791         $filen =~ s/\.([-a-z0-9{}]+)$/.${$}DEFANGED-$1/i;	#\
  792         print "begin 666 $filen\n";	#\
  793         $_ = "";	#\
  794       }	#\
  795     ' 2>> $LOGFILE
  796   }
  797 }
  798 
  799 # MIME attachments and general header sanitizing
  800 :0
  801 * !$ ^X-Content-Security: \[${HOST}\] (QUARANTINE|DISCARD)
  802 * 9876543210^0 ^Content-Type[ 	]*:.*(application|multipart)/[^ ]*[ 	]*;
  803 * 9876543210^0 ^Content-Type[ 	]*:.*message/rfc822
  804 * 9876543210^0 ^Content-Disposition[ 	]*:.*attachment
  805 {
  806   LOG="Sanitizing MIME & attachments$SUBJ"
  807 
  808   # Due to procmail not unwrapping MIME attachment headers,
  809   # (they're in the message body) this perl script has to run against
  810   # *every* message with MIME attachments to ensure security. Sorry.
  811 
  812   # If you get "Out of memory" errors in your procmail log, try changing to
  813   # the following:
  814   # :0 fw
  815   # | ulimit -d 15000; perl -p -e '	#\
  816 
  817   POISONED_SCORE=${POISONED_SCORE:-25}
  818   ZIPPED_EXECUTABLES=${ZIPPED_EXECUTABLES:-"$POISONED_EXECUTABLES"}
  819 
  820   :0 fw
  821   | perl -p -e '	#\
  822       $pastmsghdr = 1 if /^\s*$/;	#\
  823       $XCS = "X-Content-Security: [" . $ENV{"HOST"} . "]" unless $XCS;	#\
  824       if ($pastmsghdr) {	#\
  825 	if (!$mimebdry && $mimebdrs[0]) {	#\
  826 	  warn " Found no MIME boundary in msg attachment.\n" if $ENV{"DEBUG"};	#\
  827 	  $mimebdry = pop @mimebdrs;	#\
  828 	  $newbdry = pop @newbdrs;	#\
  829 	  $rawbdry = pop @rawbdrs;	#\
  830 	  $bdrytoolong = pop @bdrstoolong;	#\
  831 	  $gotbdry = pop @gotbdrs;	#\
  832 	  $nullbdry = pop @nullbdrs;	#\
  833 	}	#\
  834 	$_ = "" if $strip_att && !$gotbdry;	#\
  835       } else {	#\
  836 	if (($type,$format,$junk) = /^Content-Type\s*:\s.*(application|multipart|message)\/(\S+)\s*(;.*)?$/i) {	#\
  837 	  $wanthdr = 1;	#\
  838 	  print "X-Security: message sanitized on ", $ENV{"HOST"}, "\n";	#\
  839 	  print "\tSee http://www.impsec.org/email-tools/sanitizer-intro.html\n";	#\
  840 	  print "\tfor details. \$Revision: 1.151 $x\$Date: 2006-01-20 07:29:24-08 $x\n";	#\
  841 	  print "X-Security: The postmaster has not enabled quarantine of poisoned messages.\n" unless $ENV{"SECURITY_QUARANTINE"};	#\
  842 	  if ($type =~ /application/i) {	#\
  843 	    $inmimehdr = 1;	#\
  844 	  } elsif ($type =~ /message/i && $format =~ /rfc822/i) {	#\
  845 	    $rcrsmsg = $inmimehdr = 1;	#\
  846 	  }	#\
  847 	} elsif (/^\S/) {	#\
  848 	  $wanthdr = 0;	#\
  849 	}	#\
  850 	if ($wanthdr) {	#\
  851 	  if (($mimebdry) = /boundary\s*=\s*(("")|("[^"]+")|([^"]\S+)|$)/i) {	#\
  852 	    $mimebdry =~ s/(^"|"$)//g;	#\
  853 	    $rawbdry = $mimebdry;	#\
  854 	    $gotbdry = 1;	#\
  855 	    $wanthdr = 0;	#\
  856 	    $bdrytoolong = $nullbdry = 0;	#\
  857 	    if ($bdrytoolong = (length($mimebdry) > 80)) {	#\
  858 	      warn " Truncating long MIME boundary string.\n";	#\
  859 	      $newbdry = substr($mimebdry,0,64);	#\
  860 	      $mimebdry = quotemeta($mimebdry);	#\
  861 	      s/${mimebdry}/${newbdry}/;	#\
  862 	      $rawbdry =~ s/${mimebdry}/${newbdry}/;	#\
  863 	    } elsif ($nullbdry = (length($mimebdry) < 1)) {	#\
  864 	      warn " Replacing null MIME boundary string.\n";	#\
  865 	      $newbdry = "==NULL_MIME_BOUNDARY_ATTACK_SANITIZED-${$}==";	#\
  866 	      s/boundary\s*=\s*(""|$)/boundary="${newbdry}"/i;	#\
  867 	    } else {	#\
  868 	      $newbdry = $mimebdry;	#\
  869 	      $mimebdry = quotemeta($mimebdry);	#\
  870 	    }	#\
  871 	  }	#\
  872 	}	#\
  873       }	#\
  874       if ($mimebdry || ($gotbdry && $nullbdry) || $inmimehdr) {	#\
  875 	if (/^\s*$/) {	#\
  876 	  $inmimehdr = 0;	#\
  877 	  if ($rcrsmsg) {	#\
  878 	    push @mimebdrs, $mimebdry;	#\
  879 	    push @newbdrs, $newbdry;	#\
  880 	    push @rawbdrs, $rawbdry;	#\
  881 	    push @bdrstoolong, $bdrytoolong;	#\
  882 	    push @gotbdrs, $gotbdry;	#\
  883 	    push @nullbdrs, $nullbdry;	#\
  884 	    $mimebdry = $newbdry = "";	#\
  885 	    $rcrsmsg = $pastmsghdr = $bdrytoolong = $gotbdry = 0;	#\
  886 	  }	#\
  887 	} elsif (/^--${mimebdry}(--)?$/) {	#\
  888 	  $mend = $1;	#\
  889 	  s/${mimebdry}/${newbdry}/ if $bdrytoolong;	#\
  890 	  s/^--/--${newbdry}${mend}/ if $nullbdry;	#\
  891 	  if ($mend) {	#\
  892 	    if ($mimebdrs[0]) {	#\
  893 	      $mimebdry = pop @mimebdrs;	#\
  894 	      $newbdry = pop @newbdrs;	#\
  895 	      $rawbdry = pop @rawbdrs;	#\
  896 	      $bdrytoolong = pop @bdrstoolong;	#\
  897 	      $gotbdry = pop @gotbdrs;	#\
  898 	      $nullbdry = pop @nullbdrs;	#\
  899 	    }	#\
  900 	  } else {	#\
  901 	    $inmimehdr = 1;	#\
  902 	    $rcrsmsg = $strip_att = $check_att = 0;	#\
  903 	  }	#\
  904 	} elsif (!$inmimehdr && $strip_att) {	#\
  905 	  $_ = "";	#\
  906 	} elsif (!$inmimehdr && $check_att && !$base64) {	#\
  907 	  warn "  Not base64, not scanning\n";	#\
  908 	  $base64 = $check_att = 0;	#\
  909 	} elsif (!$inmimehdr && $check_att) {	#\
  910 	  $ATTCH = $destf = $rarh = $ziph = "";	#\
  911 	  $SIG{PIPE} = 'IGNORE';	#\
  912 	  if ($ENV{"USE_CPAN"}) {	#\
  913 	    push @INC, $ENV{"PVT_CPAN"} if $ENV{"PVT_CPAN"};	#\
  914 	    eval "use MIME::Base64; use File::MkTemp;"; die $@ if $@;	#\
  915 	    if (($ATTCH,$destf) = mkstempt("mailchk.XXXXXX","/tmp")) {	#\
  916 	      $destf = "/tmp/$destf";	#\
  917 	    } else {	#\
  918 	      warn " ERR: mkstempt failed\n";	#\
  919 	      $ATTCH = $destf = "";	#\
  920 	    }	#\
  921 	  } else {	#\
  922 	    if (!chomp($destf = `mktemp /tmp/mailchk.XXXXXX`)) {	#\
  923 	      warn " ERR: mktemp failed\n";	#\
  924 	      $ATTCH = $destf = "";	#\
  925 	    } else {	#\
  926 	      if (open(ATTCH,"|mimencode -u -o $destf")) {	#\
  927 		$ATTCH = ATTCH;	#\
  928 	      } else {	#\
  929 		warn " ERR: mimencode failed: $@\n";	#\
  930 		unlink($destf);	#\
  931 		$ATTCH = $destf = "";	#\
  932 	      }	#\
  933 	    }	#\
  934 	  }	#\
  935 	  if ($ATTCH && $destf) {	#\
  936 	    warn "  Decoding to \"$destf\"\n";	#\
  937 	    do {	#\
  938 	      print $_;	#\
  939 	      if (length($_) > 3) {	#\
  940 	        if ($ENV{"USE_CPAN"}) {	#\
  941 		  $de = decode_base64($_);	#\
  942 		  print $ATTCH $de || die $@;	#\
  943 		  $rarh = $ziph = $de unless $ziph;	#\
  944 	        } else {	#\
  945 	      	  print $ATTCH $_ || die $@;	#\
  946 	        } #\
  947 	      } else {	#\
  948 		$rarh = $ziph = "XXX" if length($_) > 1;	#\
  949 	      }	#\
  950 	      $_ = <>;	#\
  951 	      $lastline = $_;	#\
  952 	    } until (/^--${mimebdry}(--)?$/ || ($mimebdrs[0] && /^--${mimebdrs[0]}(--)?$/) || !$_ );	#\
  953 	    if (close($ATTCH)) {	#\
  954 	      # Run virus-checker against $destf here.	#\
  955 	    } else {	#\
  956 	      warn "  ERR: decode failed! mimencode?\n";	#\
  957 	      $check_att = 0;	#\
  958 	    }	#\
  959 	    if ($check_att == 3) {	#\
  960 	      warn "  Scanning image\n";	#\
  961 	      $wmf = $jpegbo = 0; #\
  962 	      if ($ENV{"SECURITY_POISON_WMF"} && (`/usr/bin/od -N 4 -t x $destf` =~ /9ac6cdd7/i)) {	#\
  963 	        $wmf = 1;	#\
  964 		warn "   Poisoned WMF\n";	#\
  965 	      } elsif (open(JPEGI,"rdjpgcom $destf 2>&1 |")) {	#\
  966 	        while (<JPEGI>) {	#\
  967 		  warn "djpeg: $_" if $ENV{"DEBUG_VERBOSE"};	#\
  968 	          if (/Erroneous JPEG marker length/i) {	#\
  969 	            $jpegbo = $_; last;	#\
  970 	          }	#\
  971 	        }	#\
  972 	        close(JPEGI);	#\
  973 	      }	#\
  974 	      if ($jpegbo || $wmf) {	#\
  975 		print "\n\n--$newbdry\n";	#\
  976 		print "Content-Type: TEXT/PLAIN;\n";	#\
  977 		print "Content-Description: SECURITY WARNING\n";	#\
  978 		print "$XCS NOTIFY\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
  979 		print "$XCS QUARANTINE\n" if $ENV{"SECURITY_QUARANTINE"};	#\
  980 	      }	#\
  981 	      if ($jpegbo) {	#\
  982 		warn "   JPEG BO?\n";	#\
  983 		print "$XCS REPORT: Trapped possible JPEG attack: $jpegbo" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
  984 		print "\n";	#\
  985 		print $ENV{"BAD_JPEG_WARNING"};	#\
  986 	      }	#\
  987 	      if ($wmf) {	#\
  988 		print "$XCS REPORT: Trapped possible WMF attack." if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
  989 		print "\n";	#\
  990 		print $ENV{"WMF_WARNING"};	#\
  991 	      }	#\
  992 	    } elsif (($check_att == 2 || $check_att == 4) && ($specf = $ENV{"ZIPPED_EXECUTABLES"})) {	#\
  993 	      if ($check_att == 2) {	#\
  994 		$rarh = "Rar";	#\
  995 	        warn "  Scanning ZIP\n" if $ENV{"DEBUG"};	#\
  996 	        unless ($ENV{"USE_CPAN"} || $ziph) {	#\
  997 		  if (open(ATTCH,"<$destf")) {	#\
  998 		    $ziph = <ATTCH>;	#\
  999 		    close(ATTCH);	#\
 1000 		  } else {	#\
 1001 		    warn " ERR: decode failed\n";	#\
 1002 		    $ziph = "PK\003\004";	#\
 1003 		  }	#\
 1004 	        }	#\
 1005 	      }	elsif ($check_att == 4) {	#\
 1006 		$ziph = "PK\003\004";	#\
 1007 	        warn "  Scanning RAR\n" if $ENV{"DEBUG"};	#\
 1008 	        unless ($rarh) {	#\
 1009 		  if (open(ATTCH,"<$destf")) {	#\
 1010 		    $rarh = <ATTCH>;	#\
 1011 		    close(ATTCH);	#\
 1012 		  } else {	#\
 1013 		    warn " ERR: decode failed\n";	#\
 1014 		    $rarh = "Rar";	#\
 1015 		  }	#\
 1016 	        }	#\
 1017 	      }	#\
 1018 	      if ($ziph !~ /^(?:PK00)?PK\003\004/ || $rarh !~ /^Rar/) {	#\
 1019 		if ($ziph eq "XXX") {	#\
 1020 		  warn "   Hostile BASE64\n";	#\
 1021 		} else {	#\
 1022 		  warn "   ZIP/RAR magic not found\n";	#\
 1023 		} #\
 1024 		print "\n\n--$newbdry\n";	#\
 1025 		print "Content-Type: TEXT/PLAIN;\n";	#\
 1026 		print "$XCS NOTIFY\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1027 		if ($ziph eq "XXX") {	#\
 1028 		  print "$XCS REPORT: Trapped ZIP/RAR file \"$zfilen\" with hostile base64 encoding\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1029 		} else {	#\
 1030 		  print "$XCS REPORT: Trapped bogus ZIP/RAR file \"$zfilen\"\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1031 		} #\
 1032 		print "$XCS QUARANTINE\n" if $ENV{"SECURITY_QUARANTINE"};	#\
 1033 		print "Content-Description: SECURITY WARNING\n\n";	#\
 1034 		if ($ziph eq "XXX") {	#\
 1035 		  print $ENV{"BAD_BASE64_WARNING"};	#\
 1036 		} else {	#\
 1037 	          if ($check_att == 2) {	#\
 1038 		    print $ENV{"ZIP_MAGIC_WARNING"};	#\
 1039 	          } elsif ($check_att == 4) {	#\
 1040 		    print $ENV{"RAR_MAGIC_WARNING"};	#\
 1041 		  } #\
 1042 		} #\
 1043 	      } elsif (open(ZIPPOL,$specf)) {	#\
 1044 		%zipf = ();	#\
 1045 	        if ($check_att == 2) {	#\
 1046 		  if (open(ZIPL,"unzip -l $destf |")) {	#\
 1047 		    while (<ZIPL>) {	#\
 1048 		      if (($filen) = /^\s+\d+\s+\S+\s+\S+\s+(.+)$/) {	#\
 1049 			warn "$filen\n" if $ENV{"DEBUG"};	#\
 1050 		        $zipf{$filen} = 1;	#\
 1051 		      }	#\
 1052 		    }	#\
 1053 		    warn "  ERR: scan failed! unzip?\n" unless close(ZIPL);	#\
 1054 		    if (open(ZIPL,"unzip -t -P _virus_$$ $destf 2>&1 |")) {	#\
 1055 		      while (<ZIPL>) {	#\
 1056 		        if (($junk,$filen) = /(skipp|test)ing:\s+(\S.+\.\w+)\W*\s+($|incorrect)/i) {	#\
 1057 		          $zipf{$filen} = 1;	#\
 1058 		        }	#\
 1059 		      }	#\
 1060 		      close(ZIPL);	#\
 1061 		    }	#\
 1062 		  }	#\
 1063 		} elsif ($check_att == 4) {	#\
 1064 		  if (open(RARL,"unrar v $destf |")) {	#\
 1065 		    while (<RARL>) {	#\
 1066 		      if (($filen) = /^[\s*](?:[^\/]+\/)*(\S.*\..+)$/) {	#\
 1067 			warn "$filen\n" if $ENV{"DEBUG"};	#\
 1068 			$zipf{$filen} = 1;	#\
 1069 		      }	#\
 1070 		    }	#\
 1071 		    warn "  ERR: scan failed! unrar?\n" unless close(RARL);	#\
 1072 		  }	#\
 1073 		}	#\
 1074 		$filel = "";	#\
 1075 		foreach $filen (keys %zipf) {	#\
 1076 		$fn = $filen; $fn =~ s/\s{10,}/ (many spaces) /;	#\
 1077 		  warn "  Checking archived \"$fn\"\n";	#\
 1078 		  seek(ZIPPOL,0,0);	#\
 1079 		  while (chomp($pol_spec = <ZIPPOL>)) {	#\
 1080 		    $pol_spec =~ s/^\s+//g;	#\
 1081 		    $pol_spec =~ s/\s.*$//g;	#\
 1082 		    next unless $pol_spec;	#\
 1083 		    $pol_spec =~ s/([^\\])\./$1\\./g;	#\
 1084 		    $pol_spec =~ s/\*/.*/g;	#\
 1085 		    $pol_spec =~ s/\?\?/?./g;	#\
 1086 		    $pol_spec =~ s/([^\(]|^)\?/$1./g;	#\
 1087 		    warn "   Checking against \"$pol_spec\"\n" if $ENV{"DEBUG"};	#\
 1088 		    if ($filen =~ /^${pol_spec}$/i) {	#\
 1089 		      warn "   Trapped archived \"$fn\".\n";	#\
 1090 		      if (!$poisoned) {	#\
 1091 		        print "\n\n--$newbdry\n";	#\
 1092 		        print "Content-Type: TEXT/PLAIN;\n";	#\
 1093 		        print "$XCS NOTIFY\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1094 		        print "$XCS REPORT: Scanned attachment \"$zfilen\"\n$XCS REPORT: Trapped suspicious archived files:\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1095 		        $poisoned = 1;	#\
 1096 		      }	#\
 1097 		      print "$XCS REPORT:  $fn\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1098 		      $filel .= "  $fn\n";	#\
 1099 		      last;	#\
 1100 		    }	#\
 1101 		  }	#\
 1102 		}	#\
 1103 		if ($poisoned) {	#\
 1104 		  print "$XCS QUARANTINE\n" if $ENV{"SECURITY_QUARANTINE"};	#\
 1105 		  print "Content-Description: SECURITY WARNING\n\n";	#\
 1106 	          if ($check_att == 2) {	#\
 1107 		    print $ENV{"ZIPPED_WARNING"};	#\
 1108 	          } elsif ($check_att == 4) {	#\
 1109 		    print $ENV{"RARRED_WARNING"};	#\
 1110 		  }	#\
 1111 		  print "$filel\n";	#\
 1112 		}	#\
 1113 	      } else { 	#\
 1114 		warn " ERR: Unable to open ZIP/RAR list \"$specf\".\n";	#\
 1115 	      }	#\
 1116 	    } elsif ($check_att == 1) {	# CUT \
 1117 	      warn "  Scanning MSOffice file\n";	#\
 1118 	      $msapp = $score = 0;	#\
 1119 	      @scores = ();	#\
 1120 	      $why = "";	#\
 1121 	      if (open(ATTCH,"<$destf")) {	#\
 1122 		while (<ATTCH>) {	#\
 1123 		  if (/\023 (INCLUDE(PICTURE|TEXT)[^\000-\037]+)/i) {	#\
 1124 		    $why .= "    " . $ENV{"SC_MBD"} . " for $1\n";	#\
 1125 		    $score+= $ENV{"SC_MBD"};	#\
 1126 		  }	#\
 1127 		  if (/(\000|\001|\004)(VirusProtection)/i) {	#\
 1128 		    $why .= "    99 for $&\n";	#\
 1129 		    $score+= 99;	#\
 1130 		  }	#\
 1131 		  if (/\000(select\s[^\000]*shell\s*\(\s*["\047])/i) {	#\
 1132 		    $why .= "    99 for $1\n";	#\
 1133 		    $score+= 99;	#\
 1134 		  }	#\
 1135 		  if (/\000(ID="{.{36}[^}][^\000\012\015]{5,})/i) {	#\
 1136 		    $why .= "     99 for $1\n";	#\
 1137 		    $score+= 99;	#\
 1138 		  }	#\
 1139 		  if (/\000(regedit)/i) {	#\
 1140 		    $why .= "     9 for $1\n";	#\
 1141 		    $score+= 9;	#\
 1142 		  }	#\
 1143 		  if (/\000(Shell\s*\()/i) {	#\
 1144 		    $why .= "     9 for $1\n";	#\
 1145 		    $score+= 9;	#\
 1146 		  }	#\
 1147 		  if (/\000(Save(Normal|Properties)Prompt)/i) {	#\
 1148 		    $why .= "     9 for $1\n";	#\
 1149 		    $score+= 9;	#\
 1150 		  }	#\
 1151 		  if (/\000(Outlook\.Application)\000/i) {	#\
 1152 		    $why .= "     9 for $1\n";	#\
 1153 		    $score+= 9;	#\
 1154 		  }	#\
 1155 		  if (/\000(CountOfLines)/i) {	#\
 1156 		    $why .= "     9 for $1\n";	#\
 1157 		    $score+= 9;	#\
 1158 		  }	#\
 1159 		  if (/\000(AddFromString)/i) {	#\
 1160 		    $why .= "     9 for $1\n";	#\
 1161 		    $score+= 9;	#\
 1162 		  }	#\
 1163 		  if (/\000(StartupPath)/i) {	#\
 1164 		    $why .= "     9 for $1\n";	#\
 1165 		    $score+= 9;	#\
 1166 		  }	#\
 1167 		  if (/\000(CreateObject)/i) {	#\
 1168 		    $why .= "     4 for $1\n";	#\
 1169 		    $score+= 4;	#\
 1170 		  }	#\
 1171 		  if (/(\000|\004)([a-z0-9_]\.)*(Autoexec|Workbook_(Open|BeforeClose|Window(De)?activate)|Document_(Open|New|Close))/i) {	#\
 1172 		    $why .= "     4 for $&\n";	#\
 1173 		    $score+= 4;	#\
 1174 		  }	#\
 1175 		  if (/(\000|\004)(Logon|AddressLists|AddressEntries|Recipients|Attachments|Logoff)/i) {	#\
 1176 		    $why .= "     4 for $&\n";	#\
 1177 		    $score+= 4;	#\
 1178 		  }	#\
 1179 		  if (/(\000|\004)(Subject|Body)/i) {	#\
 1180 		    $why .= "     4 for $&\n" unless $scores[0];	#\
 1181 		    $scores[0] = 4;	#\
 1182 		  }	#\
 1183 		  if (/\000(Options[^\w\s])/i) {	#\
 1184 		    $why .= "     2 for $1\n";	#\
 1185 		    $score+= 2;	#\
 1186 		  }	#\
 1187 		  if (/\000(CodeModule)/i) {	#\
 1188 		    $why .= "     2 for $1\n";	#\
 1189 		    $score+= 2;	#\
 1190 		  }	#\
 1191 		  if (/\000(([a-z]+\.)?Application)\000/i) {	#\
 1192 		    $why .= "     2 for $1\n";	#\
 1193 		    $score+= 2;	#\
 1194 		  }	#\
 1195 		  if (/(\000|\004)stdole/i) {	#\
 1196 		    $why .= "     2 for $&\n";	#\
 1197 		    $score+= 2;	#\
 1198 		  }	#\
 1199 		  if (/(\000|\004)NormalTemplate/i) {	#\
 1200 		    $why .= "     2 for $&\n";	#\
 1201 		    $score+= 2;	#\
 1202 		  }	#\
 1203 		  if (/\000(ID="{[-0-9A-F]{36}}")/i) {	#\
 1204 		    $why .= "     4 for $1\n";	#\
 1205 		    $score+= 4;	#\
 1206 		  }	#\
 1207 		  if (/\000(ThisWorkbook)\000/i) {	#\
 1208 		    $why .= "     1 for $1\n";	#\
 1209 		    $score+= 1;	#\
 1210 		  }	#\
 1211 		  if (/\000(PrivateProfileString)/i) {	#\
 1212 		    $why .= "     1 for $1\n";	#\
 1213 		    $score+= 1;	#\
 1214 		  }	#\
 1215 		  if (/(\000|\004)(ActiveDocument|ThisDocument|ThisWorkbook)/i) {	#\
 1216 		    $why .= "     1 for $&\n";	#\
 1217 		    $score+= 1;	#\
 1218 		  }	#\
 1219 		  if (/\000(\[?HKEY_(CLASSES_ROOT|CURRENT_USER|LOCAL_MACHINE))/) {	#\
 1220 		    $why .= "     1 for $1\n";	#\
 1221 		    $score+= 1;	#\
 1222 		  }	#\
 1223 		  $msapp++ if /\000(Microsoft (Word Document|Excel Worksheet|Excel|PowerPoint)|MSWordDoc|Word\.Document\.[0-9]+|Excel\.Sheet\.[0-9]+)\000/;	#\
 1224 		}	#\
 1225 		close(ATTCH);	#\
 1226 	      } else { 	#\
 1227 		warn " ERR: Scan failed\n";	#\
 1228 	      }	#\
 1229 	      if ($msapp) {	#\
 1230 		for (@scores) {	#\
 1231 		  $score += $_;	#\
 1232 		}	#\
 1233 		if ($histfile = $ENV{"SCORE_HISTORY"}) {	#\
 1234 		  if (open(HIST,">>$histfile")) {	#\
 1235 		    print HIST "score=$score to=".$ENV{"TO"}." from=".$ENV{"FROM"}."\n";	#\
 1236 		    close HIST;	#\
 1237 		  }	#\
 1238 		}	#\
 1239 		$poison_score = $ENV{"POISONED_SCORE"};	#\
 1240 		$poison_score = 5 if $poison_score < 5;	#\
 1241 		if ($score > $poison_score && !$ENV{"SCORE_ONLY"}) {	#\
 1242 		  $why =~ s/[\000-\011\013-\037]//g;	#\
 1243 		  warn "   POSSIBLE MACRO EXPLOIT: Score=$score\n";	#\
 1244 		  print "\n\n--$newbdry\n";	#\
 1245 		  print "Content-Type: TEXT/PLAIN;\n";	#\
 1246 		  print "$XCS NOTIFY\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1247 		  print "$XCS REPORT: Trapped poisoned Microsoft Office attachment\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1248 		  if ($ENV{"SCORE_DETAILS"}) {	#\
 1249 		    $why2 = $why;	#\
 1250 		    $why2 =~ s/^/$XCS REPORT:/gm;	#\
 1251 		    print $why2;	#\
 1252 		  }	#\
 1253 		  print "$XCS QUARANTINE\n" if $ENV{"SECURITY_QUARANTINE"};	#\
 1254 		  print "Content-Description: SECURITY WARNING\n\n";	#\
 1255 		  print $ENV{"MACRO_WARNING"}, "$score\n";	#\
 1256 		  if ($ENV{"SCORE_DETAILS"}) {	#\
 1257 		    print $ENV{"MACRO_DETAILS"};	#\
 1258 		    print $why;	#\
 1259 		  }	#\
 1260 		}	#\
 1261 	      }	# CUT \
 1262 	    }	#\
 1263 	    unlink($destf);	#\
 1264 	    if ($lastline =~ /^--${mimebdry}(--)?$/) {	#\
 1265 	      $mend = $1;	#\
 1266 	      $lastline =~ s/${mimebdry}/${newbdry}/ if $bdrytoolong;	#\
 1267 	      s/^--/--${newbdry}${mend}/ if $nullbdry;	#\
 1268 	      if ($mend) {	#\
 1269 		if ($mimebdrs[0]) {	#\
 1270 		  $mimebdry = pop @mimebdrs;	#\
 1271 		  $newbdry = pop @newbdrs;	#\
 1272 		  $rawbdry = pop @rawbdrs;	#\
 1273 		  $bdrytoolong = pop @bdrstoolong;	#\
 1274 		  $gotbdry = pop @gotbdrs;	#\
 1275 		  $nullbdry = pop @nullbdrs;	#\
 1276 		}	#\
 1277 	      } else {	#\
 1278 	        $inmimehdr = 1;	#\
 1279 	      }	#\
 1280 	    }	#\
 1281 	    print $lastline; $_ = "";	#\
 1282 	  }	#\
 1283 	  $check_att = 0;	#\
 1284 	}	#\
 1285 	if ($inmimehdr || $hdrcnt) {	#\
 1286 	  if (/^(\s+\S|(file)?name)/) {	#\
 1287 	    s/^\s*/ /;	#\
 1288 	    s/^\s*// if $hdrtxt =~ /"[^"]*[^;]$/;	#\
 1289 	    s/\s*\n$//;	#\
 1290 	    $hdrtxt .= $_;	#\
 1291 	    $_ = "";	#\
 1292 	  } else {	#\
 1293 	    if ($hdrtxt) {	#\
 1294 	      $hdrtxt =~ s/([^\\])\\"/\1\\/g;	#\
 1295 	      if ($hdrtxt =~ /`\s*`/) {	#\
 1296 		warn " Fixing double backquotes.\n";	#\
 1297 		$hdrtxt =~ s/`\s*`/\\"/g;	#\
 1298 	      }	#\
 1299 	      if ($hdrtxt =~ /^[-\w]+\s*:.*name\s*=\s*"[^"]+$/i) {	#\
 1300 		warn " Fixing missing close quote on filename.\n";	#\
 1301 		$hdrtxt .= "\"";	#\
 1302 	      }	#\
 1303 	      while (($hdr, $val) = $hdrtxt =~ /^([-\w]+)\s*:.*\s(\S+)\s*=\s*""/i) {	#\
 1304 		warn " Null $val in $hdr header.\n";	#\
 1305 		$sval = quotemeta($val);	#\
 1306 		$hdrtxt =~ s/\s$sval\s*=\s*""/ X-$val="{null value sanitized}"/;	#\
 1307 	      }	#\
 1308 	      unless ($ENV{"SECURITY_DISABLE_OUTLOOK_HACKS"}) {	#\
 1309 		while (($hdr,$filen) = $hdrtxt =~ /^(Content-Description)\s*:\s*text\s+from\s+file\s+\047([^\047]+)\047/i) {	#\
 1310 		  warn " Fixing file name \"$filen\" in ${hdr}:\n";	#\
 1311 		  $newfilen = $filen; $filen = quotemeta($filen);	#\
 1312 		  $hdrtxt =~ s/\s+\047${filen}\047/, filename="${newfilen}"/ig;	#\
 1313 		}	#\
 1314 	      }	#\
 1315 	      while (($junk,$filen,$junk) = $hdrtxt =~ /^Content-[-\w]+\s*:[^"]*("[^"]*"[^"]+)*name\s*=\s*([^"\s]([^;]|;(?!\s))+)/i) {	#\
 1316 		warn " Fixing unquoted filename \"$filen\".\n";	#\
 1317 		$newfilen = $filen; $filen = quotemeta($filen);	#\
 1318 		if ($newfilen =~ /\.[a-z0-9]+"[a-z0-9"]+[\.\s]*$/i) {	#\
 1319 		  warn " Defanging quotes-in-extension attack.\n";	#\
 1320 		  while ($newfilen =~ /\.[a-z0-9]+"[a-z0-9"]+[\.\s]*$/i) {	#\
 1321 		    $newfilen =~ s/\.([a-z0-9]+)"([a-z0-9"]+)[\.\s]*$/.$1$2/i;	#\
 1322 		  }	#\
 1323 		}	#\
 1324 		$newfilen =~ s/\"/\\"/g;	#\
 1325 		if ($newfilen =~ /\([^)]*\)/) {	#\
 1326 		  warn " Removing embedded RFC822 comments.\n";	#\
 1327 		  $newfilen =~ s/\([^)]*\)//g;	#\
 1328 		}	#\
 1329 		$hdrtxt =~ s/name\s*=\s*${filen}/name="$newfilen"/ig;	#\
 1330 	      }	#\
 1331 	      while (($filen) = $hdrtxt =~ /^Content-[-\w]+\s*:.*name\s*=\s*"(=\?[^"]+\?Q\?[^"]+=(2e|3[0-9]|[46][1-9a-f]|[57][0-9a])[^"]+\?=)"/i) {	#\
 1332 		warn " Fixing encoded plain characters in \"$filen\".\n";	#\
 1333 		$newfilen = $filen; $filen = quotemeta($filen);	#\
 1334 		while ($newfilen =~ /=(2e|3[0-9]|[46][1-9a-f]|[57][0-9a])/i) {	#\
 1335 		  $char = chr(hex("0x$1"));	#\
 1336 		  $newfilen =~ s/=$1/$char/gi;	#\
 1337 		}	#\
 1338 		$hdrtxt =~ s/name\s*=\s*"${filen}"/name="$newfilen"/ig;	#\
 1339 	      }	#\
 1340 	      while (($filen) = $hdrtxt =~ /^Content-[-\w]+\s*:.*name\s*=\s*"([^"]+)[\.\s]+"/i) {	#\
 1341 		warn " Fixing trailing spaces/periods in filename.\n";	#\
 1342 		$newfilen = $filen; $filen = quotemeta($filen);	#\
 1343 		$hdrtxt =~ s/name\s*=\s*"${filen}[\.\s]+"/name="$newfilen"/ig;	#\
 1344 	      }	#\
 1345 	      while (($filen) = $hdrtxt =~ /^Content-[-\w]+\s*:.*name\s*=\s*"([^"]{128,})"/i) {	#\
 1346 		warn " Shortening long filename \"$filen\".\n";	#\
 1347 		$filen =~ s/\s+/ /g;	#\
 1348 		substr ($filen,64,32) = "..." while (length($filen) > 120);	#\
 1349 		$hdrtxt =~ s/name\s*=\s*"[^"]{120,}"/name="$filen"/i;	#\
 1350 		$mangle_mime_type = 1;	#\
 1351 		warn " Filename now \"$filen\".\n";	#\
 1352 	      }	#\
 1353 	      if (($mtype) = $hdrtxt =~ /^Content-Type:\s+([a-z0-9-_]+\/[a-z0-9-_]+)/i) {	#\
 1354 		warn " MIME body part type \"$mtype\".\n" if $ENV{"DEBUG"};	#\
 1355 		unless ($mtype =~ /^(multipart|text|message)\//i) {	#\
 1356 		  unless ($hdrtxt =~ /name\s*=\s*"/i) {	#\
 1357 		    $dfrhdr .= "$hdrtxt\n"; $hdrtxt = "";	#\
 1358 		  }	#\
 1359 		}	#\
 1360 		if ($mtype =~ /^application\/x-ms-?download/i && ! ($ENV{"SECURITY_TRUST_MS_DOWNLOAD"} || $poisoned)) {	#\
 1361 			warn " Trapped poisoned $mtype\n";	#\
 1362 			$poisoned = 1; $check_att = 0;	#\
 1363 			print "Content-Type: TEXT/PLAIN;\n";	#\
 1364 			print "$XCS NOTIFY\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1365 			print "$XCS REPORT: Trapped poisoned $mtype attachment\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1366 			print "$XCS QUARANTINE\n" if $ENV{"SECURITY_QUARANTINE"};	#\
 1367 			print "Content-Description: SECURITY WARNING\n\n";	#\
 1368 			print $ENV{"POISONED_WARNING"};	#\
 1369 			print "Scanner score: 0 (poisoned by MIME type, scan skipped)\n\n";	#\
 1370 		}	#\
 1371 		if ($mtype =~ /^application\/x(-zip)?-compress(ed)?/i) {	#\
 1372 		  $check_att = 2 unless $ENV{"DISABLE_ZIP_SCAN"} || $poisoned;	#\
 1373 	        }	#\
 1374 		if ($mtype =~ /^image\//i) {	#\
 1375 		  $check_att = 3 unless $ENV{"DISABLE_JPEG_SCAN"} || $poisoned;	#\
 1376 	        }	#\
 1377 	      }	#\
 1378 	      if ($hdrtxt =~ /^Content-Transfer-Encoding\s*:/i) {	#\
 1379 		$base64 = ($hdrtxt =~ /:\s+base64/i);	#\
 1380 		$dfrhdr .= "$hdrtxt\n"; $hdrtxt = "";	#\
 1381 	      }	#\
 1382 	      if ($hdrtxt =~ /^Content-[-\w]+\s*:.*name\s*=\s*"([^"]*\.(p?jp[eg]+|bmp|gif|png|wmf)(\?=)?)"/i) {	#\
 1383 		  $check_att = 3 unless $ENV{"DISABLE_JPEG_SCAN"} || $poisoned;	#\
 1384 	      }	#\
 1385 	      if (($filen) = $hdrtxt =~ /^Content-[-\w]+\s*:.*name\s*=\s*"([^"]*\.(do[ct]|xl[swt]|p[po]t|rtf|pps|zip|rar)(\?=)?)"/i) {	#\
 1386 		$fn = $filen; $fn =~ s/\s{10,}/ (many spaces) /;	#\
 1387 		$stripped = 0;	#\
 1388 		if ($filen =~ /\.rar(\?=)?$/i) {	#\
 1389 			$typ = "RAR archive";	#\
 1390 			$check_att = 4 unless $ENV{"DISABLE_RAR_SCAN"} || $poisoned;	#\
 1391 			$zfilen = $filen;	#\
 1392 		} elsif ($filen =~ /\.zip(\?=)?$/i) {	#\
 1393 			$typ = "ZIP archive";	#\
 1394 			$check_att = 2 unless $ENV{"DISABLE_ZIP_SCAN"} || $poisoned;	#\
 1395 			$zfilen = $filen;	#\
 1396 		} else {	#\
 1397 			$typ = "Office document";	#\
 1398 			$check_att = 1 unless $ENV{"DISABLE_MACRO_CHECK"} || $poisoned;	#\
 1399 		}	#\
 1400 		if (!$poisoned && ($specf = $ENV{"STRIPPED_EXECUTABLES"})) {	#\
 1401 		  if (open(STRIPPED,$specf)) {	#\
 1402 		    warn " Checking $typ \"$fn\" for stripping.\n";	#\
 1403 		    while (chomp($stp_spec = <STRIPPED>)) {	#\
 1404 		      $stp_spec =~ s/^\s+//g;	#\
 1405 		      $stp_spec =~ s/\s.*$//g;	#\
 1406 		      next unless $stp_spec;	#\
 1407 		      $stp_spec =~ s/([^\\])\./$1\\./g;	#\
 1408 		      $stp_spec =~ s/\*/.*/g;	#\
 1409 		      $stp_spec =~ s/\?\?/?./g;	#\
 1410 		      $stp_spec =~ s/([^\(]|^)\?/$1./g;	#\
 1411 		      $stp_spec .= "(\\?=)?\$" unless $stp_spec =~ /\$/;	#\
 1412 		      warn "  Checking against \"$stp_spec\"\n" if $ENV{"DEBUG"};	#\
 1413 		      if ($filen =~ /^${stp_spec}/i) {	#\
 1414 			warn " Stripped $typ \"$fn\".\n";	#\
 1415 			print "Content-Type: TEXT/PLAIN;\n";	#\
 1416 			print "$XCS REPORT: $typ attachment \"$fn\" stripped\n";	#\
 1417 			print "Content-Description: SECURITY NOTICE\n\n";	#\
 1418 			print $ENV{"STRIPPED_WARNING"};	#\
 1419 			print "Filename: $fn\n\n";	#\
 1420 			print "More headers follow:\n\n" unless $pastmsghdr;	#\
 1421 			$_ = $dfrhdr = $hdrtxt = "";	#\
 1422 			$stripped = $strip_att = 1;	#\
 1423 			$check_att = $inmimehdr = 0;	#\
 1424 			last;	#\
 1425 		      }	#\
 1426 		    }	#\
 1427 		    close(STRIPPED);	#\
 1428 		  } else {	#\
 1429 		    warn " ERR: Unable to open strip list \"$specf\".\n";	#\
 1430 		  }	#\
 1431 		}	#\
 1432 		if (!$poisoned && !$stripped && ($specf = $ENV{"POISONED_EXECUTABLES"})) {	#\
 1433 		  if (open(POISONED,$specf)) {	#\
 1434 		    warn " Checking $typ \"$fn\" for poisoning.\n";	#\
 1435 		    while (chomp($psn_spec = <POISONED>)) {	#\
 1436 		      $psn_spec =~ s/^\s+//g;	#\
 1437 		      $psn_spec =~ s/\s.*$//g;	#\
 1438 		      next unless $psn_spec;	#\
 1439 		      $psn_spec =~ s/([^\\])\./$1\\./g;	#\
 1440 		      $psn_spec =~ s/\*/.*/g;	#\
 1441 		      $psn_spec =~ s/\?\?/?./g;	#\
 1442 		      $psn_spec =~ s/([^\(]|^)\?/$1./g;	#\
 1443 		      $psn_spec .= "(\\?=)?\$" unless $psn_spec =~ /\$/;	#\
 1444 		      warn "  Checking against \"$psn_spec\"\n" if $ENV{"DEBUG"};	#\
 1445 		      if ($filen =~ /^${psn_spec}/i) {	#\
 1446 			warn " Trapped poisoned $typ \"$fn\".\n";	#\
 1447 			$poisoned = 1; $check_att = 0;	#\
 1448 			print "Content-Type: TEXT/PLAIN;\n";	#\
 1449 			print "$XCS NOTIFY\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1450 			print "$XCS REPORT: Trapped poisoned $typ attachment \"$fn\"\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1451 			print "$XCS QUARANTINE\n" if $ENV{"SECURITY_QUARANTINE"};	#\
 1452 			print "Content-Description: SECURITY WARNING\n\n";	#\
 1453 			print $ENV{"POISONED_WARNING"};	#\
 1454 			print "Scanner score: 0 (poisoned by name, scan skipped)\n\n";	#\
 1455 			last;	#\
 1456 		      }	#\
 1457 		    }	#\
 1458 		    close(POISONED);	#\
 1459 		  } else {	#\
 1460 		    warn " ERR: Unable to open poison list \"$specf\".\n";	#\
 1461 		  }	#\
 1462 		}	#\
 1463 	      }	#\
 1464 	      if (($bndry) = $hdrtxt =~ /^Content-Type:\s+multipart\/.*\s+boundary\s*=\s*"?([^"]+)"?/i) {	#\
 1465 		push @mimebdrs, $mimebdry;	#\
 1466 		push @newbdrs, $newbdry;	#\
 1467 		push @rawbdrs, $rawbdry;	#\
 1468 		push @bdrstoolong, $bdrytoolong;	#\
 1469 		push @gotbdrs, $gotbdry;	#\
 1470 		push @nullbdrs, $nullbdry;	#\
 1471 		$mimebdry = $newbdry = $bndry;	#\
 1472 		$mimebdry = quotemeta($mimebdry);	#\
 1473 		$rcrsmsg = $bdrytoolong = $gotbdry = 0;	#\
 1474 	      }	#\
 1475 	      if ($hdrtxt =~ /^Content-Type:\s+message\/rfc822/i) {	#\
 1476 		if (!$inmimehdr) {	#\
 1477 		  push @mimebdrs, $mimebdry;	#\
 1478 		  push @newbdrs, $newbdry;	#\
 1479 		  push @rawbdrs, $rawbdry;	#\
 1480 		  push @bdrstoolong, $bdrytoolong;	#\
 1481 		  push @gotbdrs, $gotbdry;	#\
 1482 		  push @nullbdrs, $nullbdry;	#\
 1483 		  $mimebdry = $newbdry = "";	#\
 1484 		  $rcrsmsg = $pastmsghdr = $bdrytoolong = $gotbdry = 0;	#\
 1485 		} else {	#\
 1486 		  $rcrsmsg = 1;	#\
 1487 		}	#\
 1488 	      }	#\
 1489 	      if ($ENV{"SECURITY_STRIP_MSTNEF"} && $hdrtxt =~ /^Content-Type:\s+application\/MS-TNEF/i) {	#\
 1490 		print "Content-Type: TEXT/PLAIN;\n";	#\
 1491 		print "$XCS REPORT: Stripped MS-TNEF attachment\n";	#\
 1492 		print "Content-Description: SECURITY NOTICE\n\n";	#\
 1493 		print $ENV{"TNEF_WARNING"};	#\
 1494 		$_ = $dfrhdr = $hdrtxt = "";	#\
 1495 		$strip_att = 1;	#\
 1496 		$inmimehdr = 0;	#\
 1497 	      }	#\
 1498 	      while (($filen) = $hdrtxt =~ /^Content-[-\w]+\s*:.*name\s*=\s*"([^"]*\.($ENV{"MANGLE_EXTENSIONS"})(\?=)?)"/io) {	#\
 1499 		$fn = $filen; $fn =~ s/\s{10,}/ (many spaces) /;	#\
 1500 		$stripped = 0;	#\
 1501 		if (!$poisoned && ($specf = $ENV{"STRIPPED_EXECUTABLES"})) {	#\
 1502 		  if (open(STRIPPED,$specf)) {	#\
 1503 		    warn " Checking \"$fn\" for stripping.\n";	#\
 1504 		    while (chomp($stp_spec = <STRIPPED>)) {	#\
 1505 		      $stp_spec =~ s/^\s+//g;	#\
 1506 		      $stp_spec =~ s/\s.*$//g;	#\
 1507 		      next unless $stp_spec;	#\
 1508 		      $stp_spec =~ s/([^\\])\./$1\\./g;	#\
 1509 		      $stp_spec =~ s/\*/.*/g;	#\
 1510 		      $stp_spec =~ s/\?\?/?./g;	#\
 1511 		      $stp_spec =~ s/([^\(]|^)\?/$1./g;	#\
 1512 		      $stp_spec .= "(\\?=)?\$" unless $stp_spec =~ /\$/;	#\
 1513 		      warn "  Checking against \"$stp_spec\"\n" if $ENV{"DEBUG"};	#\
 1514 		      if ($filen =~ /^${stp_spec}/i) {	#\
 1515 			warn " Stripped executable \"$fn\".\n";	#\
 1516 			print "Content-Type: TEXT/PLAIN;\n";	#\
 1517 			print "$XCS REPORT: Attachment \"$fn\" stripped\n";	#\
 1518 			print "Content-Description: SECURITY NOTICE\n\n";	#\
 1519 			print $ENV{"STRIPPED_WARNING"};	#\
 1520 			print "Filename: $fn\n\n";	#\
 1521 			print "More headers follow:\n\n" unless $pastmsghdr;	#\
 1522 			$_ = $dfrhdr = $hdrtxt = "";	#\
 1523 			$strip_att = $stripped = 1;	#\
 1524 			$inmimehdr = $check_att = 0;	#\
 1525 			last;	#\
 1526 		      }	#\
 1527 		    }	#\
 1528 		    close(STRIPPED);	#\
 1529 		  } else {	#\
 1530 		    warn " ERR: Unable to open stripped-executables file \"$specf\".\n";	#\
 1531 		  }	#\
 1532 		}	#\
 1533 		if (!$poisoned && !$stripped && ($specf = $ENV{"POISONED_EXECUTABLES"})) {	#\
 1534 		  if (open(POISONED,$specf)) {	#\
 1535 		    warn " Checking \"$fn\" for poisoning.\n";	#\
 1536 		    while (chomp($psn_spec = <POISONED>)) {	#\
 1537 		      $psn_spec =~ s/^\s+//g;	#\
 1538 		      $psn_spec =~ s/\s.*$//g;	#\
 1539 		      next unless $psn_spec;	#\
 1540 		      $psn_spec =~ s/([^\\])\./$1\\./g;	#\
 1541 		      $psn_spec =~ s/\*/.*/g;	#\
 1542 		      $psn_spec =~ s/\?\?/?./g;	#\
 1543 		      $psn_spec =~ s/([^\(]|^)\?/$1./g;	#\
 1544 		      $psn_spec .= "(\\?=)?\$" unless $psn_spec =~ /\$/;	#\
 1545 		      warn "  Checking against \"$psn_spec\"\n" if $ENV{"DEBUG"};	#\
 1546 		      if ($filen =~ /^${psn_spec}/i) {	#\
 1547 			warn " Trapped poisoned executable \"$fn\".\n";	#\
 1548 			$poisoned = 1; $check_att = 0; 	#\
 1549 			print "Content-Type: TEXT/PLAIN;\n";	#\
 1550 			print "$XCS NOTIFY\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1551 			print "$XCS REPORT: Trapped poisoned executable \"$fn\"\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1552 			print "$XCS QUARANTINE\n" if $ENV{"SECURITY_QUARANTINE"};	#\
 1553 			print "Content-Description: SECURITY WARNING\n\n";	#\
 1554 			print $ENV{"POISONED_WARNING"};	#\
 1555 			last;	#\
 1556 		      }	#\
 1557 		    }	#\
 1558 		    close(POISONED);	#\
 1559 		  } else {	#\
 1560 		    warn " ERR: Unable to open poisoned-executables file \"$specf\".\n";	#\
 1561 		  }	#\
 1562 		}	#\
 1563 		unless ($stripped) {	#\
 1564 		  warn " Mangling executable filename \"$fn\".\n";	#\
 1565 		  $newfilen = $filen; $filen = quotemeta($filen);	#\
 1566 		  $newfilen =~ s/\.([-a-z0-9{}]+(\?=)?)$/.${$}DEFANGED-$1/i;	#\
 1567 		  $hdrtxt =~ s/name\s*=\s*"?${filen}"?/name="$newfilen"/ig;	#\
 1568 		  $mangle_mime_type = 1;	#\
 1569 		}	#\
 1570 	      }	#\
 1571 	      if ($mangle_mime_type && $hdrtxt =~ /^Content-Type:\s/i) {	#\
 1572 		($oct) = $hdrtxt =~ /^Content-Type:.*\s(\S+\/\S+;?)/i;	#\
 1573 		warn " Mangling MIME type \"$oct\".\n";	#\
 1574 		unless ($oct =~ /text\/plain;/i) {	#\
 1575 		  print "$XCS original Content-Type was $oct\n";	#\
 1576 		  $oct = quotemeta($oct);	#\
 1577 		  $hdrtxt =~ s/${oct}/APPLICATION\/DEFANGED;/i;	#\
 1578 		}	#\
 1579 	      }	#\
 1580 	      if ($mangle_mime_type && $hdrtxt =~ /\sx-mac-\S+/i) {	#\
 1581 		$eudora = "";	#\
 1582 		while (($eh) = $hdrtxt =~ /(\sx-mac-\S+\s*=\s*\S+;?)/i) {	#\
 1583 		  $eudora .= $eh;	#\
 1584 		  $eh = quotemeta($eh);	#\
 1585 		  $hdrtxt =~ s/${eh}//i;	#\
 1586 		}	#\
 1587 		print "$XCS removed$eudora\n";	#\
 1588 	      }	#\
 1589 	      if (($junk) = $hdrtxt =~ /^Content-Type\s*:\s+(.{128}).{100,}$/i) {	#\
 1590 		warn " Truncating long Content-Type header.\n";	#\
 1591 		$junk =~ s/"/\\"/g;	#\
 1592 		$hdrtxt = "Content-Type: X-BOGUS\/X-BOGUS; originally=\"$junk...\"";	#\
 1593 	      } elsif (($junk) = $hdrtxt =~ /^Content-Description\s*:\s+(.{128}).{100,}$/i) {	#\
 1594 		warn " Truncating long Content-Description header.\n";	#\
 1595 		$hdrtxt = "Content-Description: $junk...";	#\
 1596 	      } elsif (($junk) = $hdrtxt =~ /^Content-[-\w]+\s*:\s+(.{128}).{100,}$/i) {	#\
 1597 		warn " Truncating long MIME header.\n";	#\
 1598 		$junk =~ s/"/\\"/g;	#\
 1599 		$hdrtxt =~ s/^Content-([-\w]+)\s*:.*$/X-Overflow: Content-$1; originally="$junk..."/i;	#\
 1600 	      }	#\
 1601 	      $hdrtxt =~ s/\\/\\"/g;	#\
 1602 	      print "$hdrtxt\n" if $hdrtxt;	#\
 1603 	      $hdrtxt = "";	#\
 1604 	      if (!$inmimehdr) {	#\
 1605 		if ($dfrhdr) {	#\
 1606 		  if ($mangle_mime_type && $dfrhdr =~ /^Content-Type:\s/i) {	#\
 1607 		    ($oct) = $dfrhdr =~ /^Content-Type:[^\n]*\s(\S+\/\S+;?)/i;	#\
 1608 		    warn " Mangling MIME type \"$oct\".\n";	#\
 1609 		    unless ($oct =~ /text\/plain;/i) {	#\
 1610 		      print "$XCS original Content-Type was $oct\n";	#\
 1611 		      $oct = quotemeta($oct);	#\
 1612 		      $dfrhdr =~ s/${oct}/APPLICATION\/DEFANGED;/i;	#\
 1613 		    }	#\
 1614 		  }	#\
 1615 		  print $dfrhdr; $dfrhdr = "";	#\
 1616 		}	#\
 1617 		$poisoned = $mangle_mime_type = 0;	#\
 1618 	      }	#\
 1619 	    }	#\
 1620 	    if (/^\S/) {	#\
 1621 	      s/\s*\n$//;	#\
 1622 	      $hdrtxt = $_;	#\
 1623 	      $_ = "";	#\
 1624 	      $hdrcnt++;	#\
 1625 	    } else {	#\
 1626 	      $hdrcnt = 0;	#\
 1627 	      $hdrtxt = "";	#\
 1628 	    }	#\
 1629 	  }	#\
 1630 	}	#\
 1631       }	#\
 1632     ' 2>> $LOGFILE
 1633 }
 1634 
 1635 }  # ---- END OF SIGNED/ENCRYPTED SKIP
 1636 
 1637 :0 HB
 1638 * SECURITY_POISON_WINEXE ?? [^ ]
 1639 * !$ ^X-Content-Security: \[${HOST}\] (QUARANTINE|DISCARD)
 1640 * ^Content-Transfer-Encoding[	]*:.*base64
 1641 * 9876543210^0 ^Content-Type[ 	]*:.*(application|multipart)/[^ ]*[ 	]*;
 1642 * 9876543210^0 ^Content-Disposition[ 	]*:.*attachment
 1643 {
 1644     # not already quarantined
 1645     # check for Windows executable attachments that were not blocked by name
 1646     # rules for postfix from <hobbit@avian.org>, adapted to sanitizer
 1647     # http://archives.neohapsis.com/archives/postfix/2002-04/1841.html
 1648     # NOT 100% reliable, but will catch the simple case of using
 1649     # a benign filename and a bogus MIME type, and letting Windows figure out
 1650     # to execute the attachment directly (vs. opening in a viewer) by its magic
 1651 
 1652     :0 B D hf
 1653     * 9876543210^0 ^TV[nopqr]....[AB]..A.A....*AAAA...*AAAA
 1654     * 9876543210^0 ^[^ 	]*LnJkYXRhAA
 1655     * 9876543210^0 ^[^ 	]*cmRhdGEAA
 1656     * 9876543210^0 ^[^ 	]*5yZGF0YQAA
 1657     * 9876543210^0 ^[^ 	]*LnJlbG9JAA
 1658     * 9876543210^0 ^[^ 	]*cmVsb2MAA
 1659     * 9876543210^0 ^[^ 	]*5yZWxvYwAA
 1660     | formail -A "X-Content-Security: [$HOST] NOTIFY" \
 1661               -A "X-Content-Security: [$HOST] QUARANTINE" \
 1662               -A "X-Content-Security: [$HOST] REPORT: Trapped Windows executable attachment"
 1663 }
 1664 
 1665 :0 HB
 1666 * $ ^X-Content-Security: \[${HOST}\] (NOTIFY|QUARANTINE|DISCARD)
 1667 {
 1668   :0
 1669   * SECURITY_MSGID_LOG ?? [^ ]
 1670   { JUNK=`echo "$MSGID" >> $SECURITY_MSGID_LOG` }
 1671 
 1672   :0 HB
 1673   * $ ^X-Content-Security: \[${HOST}\] DISCARD
 1674   {
 1675     SECURITY_QUARANTINE=/dev/null
 1676   }
 1677 
 1678   :0 HB
 1679   * $ ^X-Content-Security: \[${HOST}\] SPOOFED_SENDER
 1680   {
 1681     # don't bother the sender, it's probably forged
 1682     SECURITY_NOTIFY_SENDER=
 1683   }
 1684 
 1685   :0
 1686   * 9876543210^0 SECURITY_NOTIFY ?? [^ ]
 1687   * 9876543210^0 SECURITY_NOTIFY_VERBOSE ?? [^ ]
 1688   {
 1689     # Notify administration and sender of the attack
 1690 
 1691     STATUS="STATUS: Message delivered to $TO"
 1692     STATUS_PUBLIC="STATUS: Message delivered."
 1693     REPORT="REPORT: No details available."
 1694     SCORE="REPORT: Not a document, or already poisoned by filename. Not scanned for macros."
 1695 
 1696     :0
 1697     * SECURITY_QUARANTINE ?? [^ ]
 1698     {
 1699       STATUS="STATUS: Message quarantined in $SECURITY_QUARANTINE, not delivered to recipient."
 1700       STATUS_PUBLIC="STATUS: Message quarantined, not delivered to recipient."
 1701     }
 1702 
 1703     :0 HB
 1704     * $ ^X-Content-Security: \[${HOST}\] DISCARD
 1705     {
 1706       STATUS="STATUS: Message discarded, not delivered to recipient."
 1707       STATUS_PUBLIC="$STATUS"
 1708     }
 1709 
 1710     :0 HB
 1711     * ^\/Macro Scanner score: [1-9][0-9]+
 1712     {
 1713       SCORE="REPORT: $MATCH"
 1714     }
 1715 
 1716     :0 HB
 1717     * $ ^X-Content-Security: \[${HOST}\] REPORT:
 1718     { REPORT=`grep "^X-Content-Security: \[${HOST}\] REPORT: " | sed -e 's/^.* REPORT:/REPORT:/g'` }
 1719 
 1720 
 1721     #---------------------------------------------------------------------------
 1722     # Smart Sender Notify Suppression
 1723     # If the Return-Path: domain is not supported by any of the Received: domains
 1724     # then the envelope sender address is probably forged. Don't waste time notifying.
 1725     #
 1726     
 1727     :0
 1728     *   SECURITY_NOTIFY_SENDER ?? [^ ]
 1729     *   FROMDOM ?? [^ ]
 1730     * ! SECURITY_DISABLE_SMART_REPLY ?? [^ ]
 1731     {
 1732       FROMDOM2="_"
 1733       FROMDOM3="_"
 1734     
 1735       :0
 1736       * FROMDOM ?? ^.+\.\/[^.]+\.[^.]+$
 1737       {
 1738         FROMDOM2="$MATCH"
 1739         # ignore some domains (e.g. ac.uk, com.ar, etc.)
 1740         :0
 1741         * FROMDOM2 ?? ^(co|ac|com|net|org)\.[a-z][a-z]$
 1742         {
 1743           FROMDOM2="_"
 1744         }
 1745       }
 1746     
 1747       :0
 1748       * FROMDOM ?? ^.+\.\/[^.]+\.[^.]+\.[^.]+$
 1749       {
 1750         FROMDOM3="$MATCH"
 1751       }
 1752     
 1753       # Look for Received: headers that support the sender's claimed domain
 1754       # Line 1: sendmail, postfix
 1755       # Line 2: qmail
 1756       :0 H
 1757       * $! ^Received: from [^ ]+ \(([^ .]+\.)*($FROMDOM|$FROMDOM3|$FROMDOM2) [^)]+\)+[ 	]+by (${SECURITY_TRUSTED_MTAS:-${HOST}})
 1758       * $! ^Received: from ([^ .]+\.)*($FROMDOM|$FROMDOM3|$FROMDOM2)[ 	]+\(HELO .*[ 	]+by (${SECURITY_TRUSTED_MTAS:-${HOST}})
 1759       {
 1760         REPLY_SUPPRESSED="NOTICE: Envelope sender domain $FROMDOM not supported by trusted Received: path. Suppressing sender notification.${NL}"
 1761         LOG=" $REPLY_SUPPRESSED"
 1762         SECURITY_NOTIFY_SENDER=
 1763       }
 1764     
 1765       # Did a mailing list rewrite the Return-Path header?
 1766       :0E
 1767       * -1^0
 1768       * 1^0 ^Precedence: (bulk|junk|list)
 1769       * 1^0 ^(List-Id|X-Mailing-List):
 1770       * 9876543210^0 FROM ?? \<owner-
 1771       * 9876543210^0 FROM ?? \<[^@ >]+-l-admin@
 1772       {
 1773         REPLY_SUPPRESSED="NOTICE: Message from mailing list. Suppressing sender notification.${NL}"
 1774         LOG=" $REPLY_SUPPRESSED"
 1775         SECURITY_NOTIFY_SENDER=
 1776       }
 1777     }
 1778     #---------------------------------------------------------------------------
 1779 
 1780     :0 HB
 1781     * !$ ^X-Content-Security: \[${HOST}\] NONOTIFY
 1782     {
 1783        :0
 1784        * SECURITY_NOTIFY ?? [^ ]
 1785        * !$ ^X-Loop: EMAIL SECURITY WARNING $HOST $SECRET
 1786        {
 1787 	 LOG="${NL} NOTIFY ADMIN ($SECURITY_NOTIFY)${NL}"
 1788    
 1789 	 :0 h ci
 1790 	 | ( \
 1791 	     echo "To: $SECURITY_NOTIFY";\
 1792              echo 'From: "Procmail Security daemon"' "<${SECURITY_LOCAL_POSTMASTER}>";\
 1793 	     echo 'Subject: SECURITY WARNING - possible email attack';\
 1794 	     echo "X-Loop: EMAIL SECURITY WARNING $HOST $SECRET"; \
 1795 	     echo ;\
 1796 	     echo "\$Revision: 1.151 $";\
 1797 	     echo ;\
 1798 	     echo "$REPORT";\
 1799 	     echo "$SCORE";\
 1800 	     echo "$STATUS";\
 1801 	     echo "$REPLY_SUPPRESSED";\
 1802 	     echo ;\
 1803 	     echo 'Headers from message:';\
 1804 	     echo ;\
 1805 	     sed -e 's/^/> /' ;\
 1806 	   ) | $SENDMAIL $MTA_FLAGS_CMDLN $SECURITY_NOTIFY
 1807        }
 1808    
 1809        :0
 1810        * SECURITY_NOTIFY_VERBOSE ?? [^ ]
 1811        * !$ ^X-Loop: EMAIL SECURITY WARNING $HOST $SECRET
 1812        {
 1813 	 LOG="${NL} NOTIFY ADMIN VERBOSE ($SECURITY_NOTIFY_VERBOSE)${NL}"
 1814    
 1815 	 :0 hb ci
 1816 	 | ( \
 1817 	     echo "To: $SECURITY_NOTIFY_VERBOSE";\
 1818              echo 'From: "Procmail Security daemon"' "<${SECURITY_LOCAL_POSTMASTER}>";\
 1819 	     echo 'Subject: SECURITY WARNING - possible email attack';\
 1820 	     echo "X-Loop: EMAIL SECURITY WARNING $HOST $SECRET"; \
 1821 	     echo ;\
 1822 	     echo "$REPORT";\
 1823 	     echo "$SCORE";\
 1824 	     echo "$STATUS";\
 1825 	     echo "$REPLY_SUPPRESSED";\
 1826 	     echo ;\
 1827 	     echo 'Message:';\
 1828 	     echo ;\
 1829 	     sed -e 's/^/> /' ;\
 1830 	   ) | $SENDMAIL $MTA_FLAGS_CMDLN $SECURITY_NOTIFY_VERBOSE
 1831        }
 1832     }
 1833    
 1834     :0 H
 1835     * SECURITY_NOTIFY_SENDER ?? [^ ]
 1836     * !  ^FROM_DAEMON
 1837     * !$ ^X-Loop: EMAIL SECURITY WARNING $HOST $SECRET
 1838     {
 1839       LOG="${NL} NOTIFY SENDER${NL}"
 1840       PM_BCC="X-Placeholder:"
 1841       PM_CC="X-Placeholder:"
 1842 
 1843       :0 HB
 1844       * !$ ^X-Content-Security: \[${HOST}\] NONOTIFY
 1845       {
 1846           PM_BCC="Bcc: $SECURITY_NOTIFY"
 1847       }
 1848 
 1849       :0
 1850       * SECURITY_NOTIFY_SENDER_POSTMASTER ?? [^ ]
 1851       * FROMDOM ?? [^ ]
 1852       {
 1853           PM_CC="postmaster@$FROMDOM"
 1854           
 1855 	  :0
 1856 	  * SECURITY_NOTIFY_SENDER_ABUSE ?? [^ ]
 1857 	  {
 1858 	    PM_CC="$PM_CC>, <abuse@$FROMDOM"
 1859 	  }
 1860 
 1861           PM_CC="Cc: <$PM_CC>"
 1862       }
 1863 
 1864       MSG_HEADERS=`sed -e '/^$/q; s/^/> /'`
 1865 
 1866       :0 h ci
 1867       | ( \
 1868           formail -r \
 1869                   -I "From: \"Procmail Security daemon\" <${SECURITY_LOCAL_POSTMASTER}>"\
 1870                   -I "$PM_BCC" -I "$PM_CC" -I "References: $MSGID" \
 1871 		  -I "Sender: <${SECURITY_LOCAL_POSTMASTER}>" \
 1872 		  -I "Errors-To: <${SECURITY_LOCAL_POSTMASTER}>" \
 1873                   -I "X-Loop: EMAIL SECURITY WARNING $HOST $SECRET" \
 1874 		  -I "$OVERRIDEFORMAIL" \
 1875           ;\
 1876           echo ;\
 1877           if [ -f "$SECURITY_NOTIFY_SENDER" -a -s "$SECURITY_NOTIFY_SENDER" -a -r "$SECURITY_NOTIFY_SENDER" ] ;\
 1878           then \
 1879                 echo 'Regarding your message to';\
 1880                 echo "$TO";\
 1881                 echo ;\
 1882                 cat $SECURITY_NOTIFY_SENDER; \
 1883           else \
 1884                 echo '*** SECURITY WARNING ***';\
 1885                 echo 'Our email gateway has detected that your message to';\
 1886                 echo "$TO";\
 1887                 echo 'MAY contain hazardous embedded scripting or attachments,';\
 1888                 echo 'or has been rejected by our site security policy for some other reason.';\
 1889                 echo 'If you have a question, please reply to this notification message.';\
 1890                 echo ;\
 1891                 echo 'It is POSSIBLE that your message was infected by a virus.';\
 1892                 echo 'You should make sure your virus signature file';\
 1893                 echo 'is up-to-date and then rescan your computer,';\
 1894                 echo 'especially if you do not remember sending this message.';\
 1895                 echo ;\
 1896                 echo 'If the macro scanner score is large yet your virus scanner reports';\
 1897                 echo 'that the document is not infected, try saving it using a different';\
 1898                 echo 'format (such as Rich Text - "RTF") that will remove all macros.';\
 1899           fi ;\
 1900           echo ;\
 1901           echo "$REPORT";\
 1902           echo "$SCORE";\
 1903           echo "$STATUS_PUBLIC";\
 1904           echo ;\
 1905           echo 'Headers from message:';\
 1906           echo ;\
 1907           echo "$MSG_HEADERS";\
 1908           echo ;\
 1909           echo ;\
 1910           echo '--';\
 1911           echo 'Message sanitized on' $HOST;\
 1912           echo 'See http://www.impsec.org/email-tools/sanitizer-intro.html for details.';\
 1913           echo ;\
 1914         ) | $SENDMAIL $MTA_FLAGS_HDRS
 1915 
 1916     }
 1917   }
 1918 
 1919   :0
 1920   * SECURITY_QUARANTINE ?? [^ ]
 1921   {
 1922     :0
 1923     * SECURITY_NOTIFY_RECIPIENT ?? [^ ]
 1924     {
 1925       LOG="${NL} NOTIFY RECIPIENT${NL}"
 1926 
 1927       # We could stuff this directly into $DEFAULT but then
 1928       # we'd have to worry about generating Message-ID and Date headers
 1929       # and it wouldn't work on a relay...
 1930       :0 h ci
 1931       | ( \
 1932           echo "To: $TO";\
 1933           echo 'From: "Procmail Security daemon"' "<${SECURITY_LOCAL_POSTMASTER}>";\
 1934 	  if [ "$SECURITY_QUARANTINE" = "/dev/null" ] ;\
 1935           then \
 1936 		  echo 'Subject: SECURITY WARNING - email discarded';\
 1937           else \
 1938 		  echo 'Subject: SECURITY WARNING - email quarantined';\
 1939           fi ;\
 1940           echo ;\
 1941           if [ -f "$SECURITY_NOTIFY_RECIPIENT" -a -s "$SECURITY_NOTIFY_RECIPIENT" -a -r "$SECURITY_NOTIFY_RECIPIENT" ] ;\
 1942           then \
 1943                 cat $SECURITY_NOTIFY_RECIPIENT; \
 1944           else \
 1945                 echo '*** SECURITY WARNING ***';\
 1946                 echo 'Our email gateway has detected that a message sent to you';\
 1947                 echo 'MAY contain hazardous embedded scripting or attachments.';\
 1948                 echo 'The message has been quarantined or discarded per our site security policy.';\
 1949                 echo 'Please contact your system administrator for further details.';\
 1950                 echo ;\
 1951           fi ;\
 1952           echo ;\
 1953           echo "$REPORT";\
 1954           echo "$SCORE";\
 1955           echo "$STATUS_PUBLIC";\
 1956           echo ;\
 1957           echo 'Headers from message:';\
 1958           echo ;\
 1959           sed -e 's/^/> /' ;\
 1960           echo ;\
 1961           echo '--';\
 1962           echo 'Message sanitized on' $HOST;\
 1963           echo 'See http://www.impsec.org/email-tools/sanitizer-intro.html for details.';\
 1964           echo ;\
 1965         ) | $SENDMAIL $MTA_FLAGS_HDRS
 1966 
 1967     }
 1968 
 1969     :0 :${SECURITY_QUARANTINE_LOCKFILE}
 1970     $SECURITY_QUARANTINE
 1971 
 1972     :0 e
 1973     * ! SECURITY_QUARANTINE_OPTIONAL ?? [^ ]
 1974     {
 1975       # Argh! Quarantine failed, and not explicitly marked as optional!
 1976       # Bounce message, and notify administrator
 1977       LOG="${NL} ERR: QUARANTINE FAILED!${NL}"
 1978       EXITCODE=65
 1979 
 1980       :0 h
 1981       * SECURITY_NOTIFY ?? [^ ]
 1982       * !$ ^X-Loop: EMAIL SECURITY WARNING $HOST $SECRET
 1983       | ( \
 1984           echo "To: $SECURITY_NOTIFY";\
 1985           echo 'From: "Procmail Security daemon"' "<${SECURITY_LOCAL_POSTMASTER}>";\
 1986           echo 'Subject: SECURITY WARNING - quarantine failed!';\
 1987           echo "X-Loop: EMAIL SECURITY WARNING $HOST $SECRET"; \
 1988           echo ;\
 1989           echo 'Attempt to quarantine the following message in $SECURITY_QUARANTINE failed.';\
 1990           echo 'Message has been bounced.';\
 1991           echo 'Verify file access permissions (file must be writable):';\
 1992           ls -l $SECURITY_QUARANTINE ;\
 1993           echo ;\
 1994           echo "$REPORT";\
 1995           echo "$SCORE";\
 1996           echo ;\
 1997           echo 'Headers from message:';\
 1998           echo ;\
 1999           sed -e 's/^/> /' ;\
 2000         ) | $SENDMAIL $MTA_FLAGS_CMDLN $SECURITY_NOTIFY
 2001 
 2002       # zap it, just in case
 2003       :0
 2004       /dev/null
 2005     }
 2006   }
 2007 }
 2008 
 2009 #eof