"Fossies" - the Fresh Open Source Software Archive

Member "html-trap.procmail.nomacroscan" (20 Jan 2006, 64750 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 	    }	#\
 1117 	    unlink($destf);	#\
 1118 	    if ($lastline =~ /^--${mimebdry}(--)?$/) {	#\
 1119 	      $mend = $1;	#\
 1120 	      $lastline =~ s/${mimebdry}/${newbdry}/ if $bdrytoolong;	#\
 1121 	      s/^--/--${newbdry}${mend}/ if $nullbdry;	#\
 1122 	      if ($mend) {	#\
 1123 		if ($mimebdrs[0]) {	#\
 1124 		  $mimebdry = pop @mimebdrs;	#\
 1125 		  $newbdry = pop @newbdrs;	#\
 1126 		  $rawbdry = pop @rawbdrs;	#\
 1127 		  $bdrytoolong = pop @bdrstoolong;	#\
 1128 		  $gotbdry = pop @gotbdrs;	#\
 1129 		  $nullbdry = pop @nullbdrs;	#\
 1130 		}	#\
 1131 	      } else {	#\
 1132 	        $inmimehdr = 1;	#\
 1133 	      }	#\
 1134 	    }	#\
 1135 	    print $lastline; $_ = "";	#\
 1136 	  }	#\
 1137 	  $check_att = 0;	#\
 1138 	}	#\
 1139 	if ($inmimehdr || $hdrcnt) {	#\
 1140 	  if (/^(\s+\S|(file)?name)/) {	#\
 1141 	    s/^\s*/ /;	#\
 1142 	    s/^\s*// if $hdrtxt =~ /"[^"]*[^;]$/;	#\
 1143 	    s/\s*\n$//;	#\
 1144 	    $hdrtxt .= $_;	#\
 1145 	    $_ = "";	#\
 1146 	  } else {	#\
 1147 	    if ($hdrtxt) {	#\
 1148 	      $hdrtxt =~ s/([^\\])\\"/\1\\ÿ/g;	#\
 1149 	      if ($hdrtxt =~ /`\s*`/) {	#\
 1150 		warn " Fixing double backquotes.\n";	#\
 1151 		$hdrtxt =~ s/`\s*`/\\"/g;	#\
 1152 	      }	#\
 1153 	      if ($hdrtxt =~ /^[-\w]+\s*:.*name\s*=\s*"[^"]+$/i) {	#\
 1154 		warn " Fixing missing close quote on filename.\n";	#\
 1155 		$hdrtxt .= "\"";	#\
 1156 	      }	#\
 1157 	      while (($hdr, $val) = $hdrtxt =~ /^([-\w]+)\s*:.*\s(\S+)\s*=\s*""/i) {	#\
 1158 		warn " Null $val in $hdr header.\n";	#\
 1159 		$sval = quotemeta($val);	#\
 1160 		$hdrtxt =~ s/\s$sval\s*=\s*""/ X-$val="{null value sanitized}"/;	#\
 1161 	      }	#\
 1162 	      unless ($ENV{"SECURITY_DISABLE_OUTLOOK_HACKS"}) {	#\
 1163 		while (($hdr,$filen) = $hdrtxt =~ /^(Content-Description)\s*:\s*text\s+from\s+file\s+\047([^\047]+)\047/i) {	#\
 1164 		  warn " Fixing file name \"$filen\" in ${hdr}:\n";	#\
 1165 		  $newfilen = $filen; $filen = quotemeta($filen);	#\
 1166 		  $hdrtxt =~ s/\s+\047${filen}\047/, filename="${newfilen}"/ig;	#\
 1167 		}	#\
 1168 	      }	#\
 1169 	      while (($junk,$filen,$junk) = $hdrtxt =~ /^Content-[-\w]+\s*:[^"]*("[^"]*"[^"]+)*name\s*=\s*([^"\s]([^;]|;(?!\s))+)/i) {	#\
 1170 		warn " Fixing unquoted filename \"$filen\".\n";	#\
 1171 		$newfilen = $filen; $filen = quotemeta($filen);	#\
 1172 		if ($newfilen =~ /\.[a-z0-9]+"[a-z0-9"]+[\.\s]*$/i) {	#\
 1173 		  warn " Defanging quotes-in-extension attack.\n";	#\
 1174 		  while ($newfilen =~ /\.[a-z0-9]+"[a-z0-9"]+[\.\s]*$/i) {	#\
 1175 		    $newfilen =~ s/\.([a-z0-9]+)"([a-z0-9"]+)[\.\s]*$/.$1$2/i;	#\
 1176 		  }	#\
 1177 		}	#\
 1178 		$newfilen =~ s/\"/\\"/g;	#\
 1179 		if ($newfilen =~ /\([^)]*\)/) {	#\
 1180 		  warn " Removing embedded RFC822 comments.\n";	#\
 1181 		  $newfilen =~ s/\([^)]*\)//g;	#\
 1182 		}	#\
 1183 		$hdrtxt =~ s/name\s*=\s*${filen}/name="$newfilen"/ig;	#\
 1184 	      }	#\
 1185 	      while (($filen) = $hdrtxt =~ /^Content-[-\w]+\s*:.*name\s*=\s*"(=\?[^"]+\?Q\?[^"]+=(2e|3[0-9]|[46][1-9a-f]|[57][0-9a])[^"]+\?=)"/i) {	#\
 1186 		warn " Fixing encoded plain characters in \"$filen\".\n";	#\
 1187 		$newfilen = $filen; $filen = quotemeta($filen);	#\
 1188 		while ($newfilen =~ /=(2e|3[0-9]|[46][1-9a-f]|[57][0-9a])/i) {	#\
 1189 		  $char = chr(hex("0x$1"));	#\
 1190 		  $newfilen =~ s/=$1/$char/gi;	#\
 1191 		}	#\
 1192 		$hdrtxt =~ s/name\s*=\s*"${filen}"/name="$newfilen"/ig;	#\
 1193 	      }	#\
 1194 	      while (($filen) = $hdrtxt =~ /^Content-[-\w]+\s*:.*name\s*=\s*"([^"]+)[\.\s]+"/i) {	#\
 1195 		warn " Fixing trailing spaces/periods in filename.\n";	#\
 1196 		$newfilen = $filen; $filen = quotemeta($filen);	#\
 1197 		$hdrtxt =~ s/name\s*=\s*"${filen}[\.\s]+"/name="$newfilen"/ig;	#\
 1198 	      }	#\
 1199 	      while (($filen) = $hdrtxt =~ /^Content-[-\w]+\s*:.*name\s*=\s*"([^"]{128,})"/i) {	#\
 1200 		warn " Shortening long filename \"$filen\".\n";	#\
 1201 		$filen =~ s/\s+/ /g;	#\
 1202 		substr ($filen,64,32) = "..." while (length($filen) > 120);	#\
 1203 		$hdrtxt =~ s/name\s*=\s*"[^"]{120,}"/name="$filen"/i;	#\
 1204 		$mangle_mime_type = 1;	#\
 1205 		warn " Filename now \"$filen\".\n";	#\
 1206 	      }	#\
 1207 	      if (($mtype) = $hdrtxt =~ /^Content-Type:\s+([a-z0-9-_]+\/[a-z0-9-_]+)/i) {	#\
 1208 		warn " MIME body part type \"$mtype\".\n" if $ENV{"DEBUG"};	#\
 1209 		unless ($mtype =~ /^(multipart|text|message)\//i) {	#\
 1210 		  unless ($hdrtxt =~ /name\s*=\s*"/i) {	#\
 1211 		    $dfrhdr .= "$hdrtxt\n"; $hdrtxt = "";	#\
 1212 		  }	#\
 1213 		}	#\
 1214 		if ($mtype =~ /^application\/x-ms-?download/i && ! ($ENV{"SECURITY_TRUST_MS_DOWNLOAD"} || $poisoned)) {	#\
 1215 			warn " Trapped poisoned $mtype\n";	#\
 1216 			$poisoned = 1; $check_att = 0;	#\
 1217 			print "Content-Type: TEXT/PLAIN;\n";	#\
 1218 			print "$XCS NOTIFY\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1219 			print "$XCS REPORT: Trapped poisoned $mtype attachment\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1220 			print "$XCS QUARANTINE\n" if $ENV{"SECURITY_QUARANTINE"};	#\
 1221 			print "Content-Description: SECURITY WARNING\n\n";	#\
 1222 			print $ENV{"POISONED_WARNING"};	#\
 1223 			print "Scanner score: 0 (poisoned by MIME type, scan skipped)\n\n";	#\
 1224 		}	#\
 1225 		if ($mtype =~ /^application\/x(-zip)?-compress(ed)?/i) {	#\
 1226 		  $check_att = 2 unless $ENV{"DISABLE_ZIP_SCAN"} || $poisoned;	#\
 1227 	        }	#\
 1228 		if ($mtype =~ /^image\//i) {	#\
 1229 		  $check_att = 3 unless $ENV{"DISABLE_JPEG_SCAN"} || $poisoned;	#\
 1230 	        }	#\
 1231 	      }	#\
 1232 	      if ($hdrtxt =~ /^Content-Transfer-Encoding\s*:/i) {	#\
 1233 		$base64 = ($hdrtxt =~ /:\s+base64/i);	#\
 1234 		$dfrhdr .= "$hdrtxt\n"; $hdrtxt = "";	#\
 1235 	      }	#\
 1236 	      if ($hdrtxt =~ /^Content-[-\w]+\s*:.*name\s*=\s*"([^"]*\.(p?jp[eg]+|bmp|gif|png|wmf)(\?=)?)"/i) {	#\
 1237 		  $check_att = 3 unless $ENV{"DISABLE_JPEG_SCAN"} || $poisoned;	#\
 1238 	      }	#\
 1239 	      if (($filen) = $hdrtxt =~ /^Content-[-\w]+\s*:.*name\s*=\s*"([^"]*\.(do[ct]|xl[swt]|p[po]t|rtf|pps|zip|rar)(\?=)?)"/i) {	#\
 1240 		$fn = $filen; $fn =~ s/\s{10,}/ (many spaces) /;	#\
 1241 		$stripped = 0;	#\
 1242 		if ($filen =~ /\.rar(\?=)?$/i) {	#\
 1243 			$typ = "RAR archive";	#\
 1244 			$check_att = 4 unless $ENV{"DISABLE_RAR_SCAN"} || $poisoned;	#\
 1245 			$zfilen = $filen;	#\
 1246 		} elsif ($filen =~ /\.zip(\?=)?$/i) {	#\
 1247 			$typ = "ZIP archive";	#\
 1248 			$check_att = 2 unless $ENV{"DISABLE_ZIP_SCAN"} || $poisoned;	#\
 1249 			$zfilen = $filen;	#\
 1250 		} else {	#\
 1251 			$typ = "Office document";	#\
 1252 			$check_att = 1 unless $ENV{"DISABLE_MACRO_CHECK"} || $poisoned;	#\
 1253 		}	#\
 1254 		if (!$poisoned && ($specf = $ENV{"STRIPPED_EXECUTABLES"})) {	#\
 1255 		  if (open(STRIPPED,$specf)) {	#\
 1256 		    warn " Checking $typ \"$fn\" for stripping.\n";	#\
 1257 		    while (chomp($stp_spec = <STRIPPED>)) {	#\
 1258 		      $stp_spec =~ s/^\s+//g;	#\
 1259 		      $stp_spec =~ s/\s.*$//g;	#\
 1260 		      next unless $stp_spec;	#\
 1261 		      $stp_spec =~ s/([^\\])\./$1\\./g;	#\
 1262 		      $stp_spec =~ s/\*/.*/g;	#\
 1263 		      $stp_spec =~ s/\?\?/?./g;	#\
 1264 		      $stp_spec =~ s/([^\(]|^)\?/$1./g;	#\
 1265 		      $stp_spec .= "(\\?=)?\$" unless $stp_spec =~ /\$/;	#\
 1266 		      warn "  Checking against \"$stp_spec\"\n" if $ENV{"DEBUG"};	#\
 1267 		      if ($filen =~ /^${stp_spec}/i) {	#\
 1268 			warn " Stripped $typ \"$fn\".\n";	#\
 1269 			print "Content-Type: TEXT/PLAIN;\n";	#\
 1270 			print "$XCS REPORT: $typ attachment \"$fn\" stripped\n";	#\
 1271 			print "Content-Description: SECURITY NOTICE\n\n";	#\
 1272 			print $ENV{"STRIPPED_WARNING"};	#\
 1273 			print "Filename: $fn\n\n";	#\
 1274 			print "More headers follow:\n\n" unless $pastmsghdr;	#\
 1275 			$_ = $dfrhdr = $hdrtxt = "";	#\
 1276 			$stripped = $strip_att = 1;	#\
 1277 			$check_att = $inmimehdr = 0;	#\
 1278 			last;	#\
 1279 		      }	#\
 1280 		    }	#\
 1281 		    close(STRIPPED);	#\
 1282 		  } else {	#\
 1283 		    warn " ERR: Unable to open strip list \"$specf\".\n";	#\
 1284 		  }	#\
 1285 		}	#\
 1286 		if (!$poisoned && !$stripped && ($specf = $ENV{"POISONED_EXECUTABLES"})) {	#\
 1287 		  if (open(POISONED,$specf)) {	#\
 1288 		    warn " Checking $typ \"$fn\" for poisoning.\n";	#\
 1289 		    while (chomp($psn_spec = <POISONED>)) {	#\
 1290 		      $psn_spec =~ s/^\s+//g;	#\
 1291 		      $psn_spec =~ s/\s.*$//g;	#\
 1292 		      next unless $psn_spec;	#\
 1293 		      $psn_spec =~ s/([^\\])\./$1\\./g;	#\
 1294 		      $psn_spec =~ s/\*/.*/g;	#\
 1295 		      $psn_spec =~ s/\?\?/?./g;	#\
 1296 		      $psn_spec =~ s/([^\(]|^)\?/$1./g;	#\
 1297 		      $psn_spec .= "(\\?=)?\$" unless $psn_spec =~ /\$/;	#\
 1298 		      warn "  Checking against \"$psn_spec\"\n" if $ENV{"DEBUG"};	#\
 1299 		      if ($filen =~ /^${psn_spec}/i) {	#\
 1300 			warn " Trapped poisoned $typ \"$fn\".\n";	#\
 1301 			$poisoned = 1; $check_att = 0;	#\
 1302 			print "Content-Type: TEXT/PLAIN;\n";	#\
 1303 			print "$XCS NOTIFY\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1304 			print "$XCS REPORT: Trapped poisoned $typ attachment \"$fn\"\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1305 			print "$XCS QUARANTINE\n" if $ENV{"SECURITY_QUARANTINE"};	#\
 1306 			print "Content-Description: SECURITY WARNING\n\n";	#\
 1307 			print $ENV{"POISONED_WARNING"};	#\
 1308 			print "Scanner score: 0 (poisoned by name, scan skipped)\n\n";	#\
 1309 			last;	#\
 1310 		      }	#\
 1311 		    }	#\
 1312 		    close(POISONED);	#\
 1313 		  } else {	#\
 1314 		    warn " ERR: Unable to open poison list \"$specf\".\n";	#\
 1315 		  }	#\
 1316 		}	#\
 1317 	      }	#\
 1318 	      if (($bndry) = $hdrtxt =~ /^Content-Type:\s+multipart\/.*\s+boundary\s*=\s*"?([^"]+)"?/i) {	#\
 1319 		push @mimebdrs, $mimebdry;	#\
 1320 		push @newbdrs, $newbdry;	#\
 1321 		push @rawbdrs, $rawbdry;	#\
 1322 		push @bdrstoolong, $bdrytoolong;	#\
 1323 		push @gotbdrs, $gotbdry;	#\
 1324 		push @nullbdrs, $nullbdry;	#\
 1325 		$mimebdry = $newbdry = $bndry;	#\
 1326 		$mimebdry = quotemeta($mimebdry);	#\
 1327 		$rcrsmsg = $bdrytoolong = $gotbdry = 0;	#\
 1328 	      }	#\
 1329 	      if ($hdrtxt =~ /^Content-Type:\s+message\/rfc822/i) {	#\
 1330 		if (!$inmimehdr) {	#\
 1331 		  push @mimebdrs, $mimebdry;	#\
 1332 		  push @newbdrs, $newbdry;	#\
 1333 		  push @rawbdrs, $rawbdry;	#\
 1334 		  push @bdrstoolong, $bdrytoolong;	#\
 1335 		  push @gotbdrs, $gotbdry;	#\
 1336 		  push @nullbdrs, $nullbdry;	#\
 1337 		  $mimebdry = $newbdry = "";	#\
 1338 		  $rcrsmsg = $pastmsghdr = $bdrytoolong = $gotbdry = 0;	#\
 1339 		} else {	#\
 1340 		  $rcrsmsg = 1;	#\
 1341 		}	#\
 1342 	      }	#\
 1343 	      if ($ENV{"SECURITY_STRIP_MSTNEF"} && $hdrtxt =~ /^Content-Type:\s+application\/MS-TNEF/i) {	#\
 1344 		print "Content-Type: TEXT/PLAIN;\n";	#\
 1345 		print "$XCS REPORT: Stripped MS-TNEF attachment\n";	#\
 1346 		print "Content-Description: SECURITY NOTICE\n\n";	#\
 1347 		print $ENV{"TNEF_WARNING"};	#\
 1348 		$_ = $dfrhdr = $hdrtxt = "";	#\
 1349 		$strip_att = 1;	#\
 1350 		$inmimehdr = 0;	#\
 1351 	      }	#\
 1352 	      while (($filen) = $hdrtxt =~ /^Content-[-\w]+\s*:.*name\s*=\s*"([^"]*\.($ENV{"MANGLE_EXTENSIONS"})(\?=)?)"/io) {	#\
 1353 		$fn = $filen; $fn =~ s/\s{10,}/ (many spaces) /;	#\
 1354 		$stripped = 0;	#\
 1355 		if (!$poisoned && ($specf = $ENV{"STRIPPED_EXECUTABLES"})) {	#\
 1356 		  if (open(STRIPPED,$specf)) {	#\
 1357 		    warn " Checking \"$fn\" for stripping.\n";	#\
 1358 		    while (chomp($stp_spec = <STRIPPED>)) {	#\
 1359 		      $stp_spec =~ s/^\s+//g;	#\
 1360 		      $stp_spec =~ s/\s.*$//g;	#\
 1361 		      next unless $stp_spec;	#\
 1362 		      $stp_spec =~ s/([^\\])\./$1\\./g;	#\
 1363 		      $stp_spec =~ s/\*/.*/g;	#\
 1364 		      $stp_spec =~ s/\?\?/?./g;	#\
 1365 		      $stp_spec =~ s/([^\(]|^)\?/$1./g;	#\
 1366 		      $stp_spec .= "(\\?=)?\$" unless $stp_spec =~ /\$/;	#\
 1367 		      warn "  Checking against \"$stp_spec\"\n" if $ENV{"DEBUG"};	#\
 1368 		      if ($filen =~ /^${stp_spec}/i) {	#\
 1369 			warn " Stripped executable \"$fn\".\n";	#\
 1370 			print "Content-Type: TEXT/PLAIN;\n";	#\
 1371 			print "$XCS REPORT: Attachment \"$fn\" stripped\n";	#\
 1372 			print "Content-Description: SECURITY NOTICE\n\n";	#\
 1373 			print $ENV{"STRIPPED_WARNING"};	#\
 1374 			print "Filename: $fn\n\n";	#\
 1375 			print "More headers follow:\n\n" unless $pastmsghdr;	#\
 1376 			$_ = $dfrhdr = $hdrtxt = "";	#\
 1377 			$strip_att = $stripped = 1;	#\
 1378 			$inmimehdr = $check_att = 0;	#\
 1379 			last;	#\
 1380 		      }	#\
 1381 		    }	#\
 1382 		    close(STRIPPED);	#\
 1383 		  } else {	#\
 1384 		    warn " ERR: Unable to open stripped-executables file \"$specf\".\n";	#\
 1385 		  }	#\
 1386 		}	#\
 1387 		if (!$poisoned && !$stripped && ($specf = $ENV{"POISONED_EXECUTABLES"})) {	#\
 1388 		  if (open(POISONED,$specf)) {	#\
 1389 		    warn " Checking \"$fn\" for poisoning.\n";	#\
 1390 		    while (chomp($psn_spec = <POISONED>)) {	#\
 1391 		      $psn_spec =~ s/^\s+//g;	#\
 1392 		      $psn_spec =~ s/\s.*$//g;	#\
 1393 		      next unless $psn_spec;	#\
 1394 		      $psn_spec =~ s/([^\\])\./$1\\./g;	#\
 1395 		      $psn_spec =~ s/\*/.*/g;	#\
 1396 		      $psn_spec =~ s/\?\?/?./g;	#\
 1397 		      $psn_spec =~ s/([^\(]|^)\?/$1./g;	#\
 1398 		      $psn_spec .= "(\\?=)?\$" unless $psn_spec =~ /\$/;	#\
 1399 		      warn "  Checking against \"$psn_spec\"\n" if $ENV{"DEBUG"};	#\
 1400 		      if ($filen =~ /^${psn_spec}/i) {	#\
 1401 			warn " Trapped poisoned executable \"$fn\".\n";	#\
 1402 			$poisoned = 1; $check_att = 0; 	#\
 1403 			print "Content-Type: TEXT/PLAIN;\n";	#\
 1404 			print "$XCS NOTIFY\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1405 			print "$XCS REPORT: Trapped poisoned executable \"$fn\"\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"};	#\
 1406 			print "$XCS QUARANTINE\n" if $ENV{"SECURITY_QUARANTINE"};	#\
 1407 			print "Content-Description: SECURITY WARNING\n\n";	#\
 1408 			print $ENV{"POISONED_WARNING"};	#\
 1409 			last;	#\
 1410 		      }	#\
 1411 		    }	#\
 1412 		    close(POISONED);	#\
 1413 		  } else {	#\
 1414 		    warn " ERR: Unable to open poisoned-executables file \"$specf\".\n";	#\
 1415 		  }	#\
 1416 		}	#\
 1417 		unless ($stripped) {	#\
 1418 		  warn " Mangling executable filename \"$fn\".\n";	#\
 1419 		  $newfilen = $filen; $filen = quotemeta($filen);	#\
 1420 		  $newfilen =~ s/\.([-a-z0-9{}]+(\?=)?)$/.${$}DEFANGED-$1/i;	#\
 1421 		  $hdrtxt =~ s/name\s*=\s*"?${filen}"?/name="$newfilen"/ig;	#\
 1422 		  $mangle_mime_type = 1;	#\
 1423 		}	#\
 1424 	      }	#\
 1425 	      if ($mangle_mime_type && $hdrtxt =~ /^Content-Type:\s/i) {	#\
 1426 		($oct) = $hdrtxt =~ /^Content-Type:.*\s(\S+\/\S+;?)/i;	#\
 1427 		warn " Mangling MIME type \"$oct\".\n";	#\
 1428 		unless ($oct =~ /text\/plain;/i) {	#\
 1429 		  print "$XCS original Content-Type was $oct\n";	#\
 1430 		  $oct = quotemeta($oct);	#\
 1431 		  $hdrtxt =~ s/${oct}/APPLICATION\/DEFANGED;/i;	#\
 1432 		}	#\
 1433 	      }	#\
 1434 	      if ($mangle_mime_type && $hdrtxt =~ /\sx-mac-\S+/i) {	#\
 1435 		$eudora = "";	#\
 1436 		while (($eh) = $hdrtxt =~ /(\sx-mac-\S+\s*=\s*\S+;?)/i) {	#\
 1437 		  $eudora .= $eh;	#\
 1438 		  $eh = quotemeta($eh);	#\
 1439 		  $hdrtxt =~ s/${eh}//i;	#\
 1440 		}	#\
 1441 		print "$XCS removed$eudora\n";	#\
 1442 	      }	#\
 1443 	      if (($junk) = $hdrtxt =~ /^Content-Type\s*:\s+(.{128}).{100,}$/i) {	#\
 1444 		warn " Truncating long Content-Type header.\n";	#\
 1445 		$junk =~ s/"/\\"/g;	#\
 1446 		$hdrtxt = "Content-Type: X-BOGUS\/X-BOGUS; originally=\"$junk...\"";	#\
 1447 	      } elsif (($junk) = $hdrtxt =~ /^Content-Description\s*:\s+(.{128}).{100,}$/i) {	#\
 1448 		warn " Truncating long Content-Description header.\n";	#\
 1449 		$hdrtxt = "Content-Description: $junk...";	#\
 1450 	      } elsif (($junk) = $hdrtxt =~ /^Content-[-\w]+\s*:\s+(.{128}).{100,}$/i) {	#\
 1451 		warn " Truncating long MIME header.\n";	#\
 1452 		$junk =~ s/"/\\"/g;	#\
 1453 		$hdrtxt =~ s/^Content-([-\w]+)\s*:.*$/X-Overflow: Content-$1; originally="$junk..."/i;	#\
 1454 	      }	#\
 1455 	      $hdrtxt =~ s/\\ÿ/\\"/g;	#\
 1456 	      print "$hdrtxt\n" if $hdrtxt;	#\
 1457 	      $hdrtxt = "";	#\
 1458 	      if (!$inmimehdr) {	#\
 1459 		if ($dfrhdr) {	#\
 1460 		  if ($mangle_mime_type && $dfrhdr =~ /^Content-Type:\s/i) {	#\
 1461 		    ($oct) = $dfrhdr =~ /^Content-Type:[^\n]*\s(\S+\/\S+;?)/i;	#\
 1462 		    warn " Mangling MIME type \"$oct\".\n";	#\
 1463 		    unless ($oct =~ /text\/plain;/i) {	#\
 1464 		      print "$XCS original Content-Type was $oct\n";	#\
 1465 		      $oct = quotemeta($oct);	#\
 1466 		      $dfrhdr =~ s/${oct}/APPLICATION\/DEFANGED;/i;	#\
 1467 		    }	#\
 1468 		  }	#\
 1469 		  print $dfrhdr; $dfrhdr = "";	#\
 1470 		}	#\
 1471 		$poisoned = $mangle_mime_type = 0;	#\
 1472 	      }	#\
 1473 	    }	#\
 1474 	    if (/^\S/) {	#\
 1475 	      s/\s*\n$//;	#\
 1476 	      $hdrtxt = $_;	#\
 1477 	      $_ = "";	#\
 1478 	      $hdrcnt++;	#\
 1479 	    } else {	#\
 1480 	      $hdrcnt = 0;	#\
 1481 	      $hdrtxt = "";	#\
 1482 	    }	#\
 1483 	  }	#\
 1484 	}	#\
 1485       }	#\
 1486     ' 2>> $LOGFILE
 1487 }
 1488 
 1489 }  # ---- END OF SIGNED/ENCRYPTED SKIP
 1490 
 1491 :0 HB
 1492 * SECURITY_POISON_WINEXE ?? [^ ]
 1493 * !$ ^X-Content-Security: \[${HOST}\] (QUARANTINE|DISCARD)
 1494 * ^Content-Transfer-Encoding[	]*:.*base64
 1495 * 9876543210^0 ^Content-Type[ 	]*:.*(application|multipart)/[^ ]*[ 	]*;
 1496 * 9876543210^0 ^Content-Disposition[ 	]*:.*attachment
 1497 {
 1498     # not already quarantined
 1499     # check for Windows executable attachments that were not blocked by name
 1500     # rules for postfix from <hobbit@avian.org>, adapted to sanitizer
 1501     # http://archives.neohapsis.com/archives/postfix/2002-04/1841.html
 1502     # NOT 100% reliable, but will catch the simple case of using
 1503     # a benign filename and a bogus MIME type, and letting Windows figure out
 1504     # to execute the attachment directly (vs. opening in a viewer) by its magic
 1505 
 1506     :0 B D hf
 1507     * 9876543210^0 ^TV[nopqr]....[AB]..A.A....*AAAA...*AAAA
 1508     * 9876543210^0 ^[^ 	]*LnJkYXRhAA
 1509     * 9876543210^0 ^[^ 	]*cmRhdGEAA
 1510     * 9876543210^0 ^[^ 	]*5yZGF0YQAA
 1511     * 9876543210^0 ^[^ 	]*LnJlbG9JAA
 1512     * 9876543210^0 ^[^ 	]*cmVsb2MAA
 1513     * 9876543210^0 ^[^ 	]*5yZWxvYwAA
 1514     | formail -A "X-Content-Security: [$HOST] NOTIFY" \
 1515               -A "X-Content-Security: [$HOST] QUARANTINE" \
 1516               -A "X-Content-Security: [$HOST] REPORT: Trapped Windows executable attachment"
 1517 }
 1518 
 1519 :0 HB
 1520 * $ ^X-Content-Security: \[${HOST}\] (NOTIFY|QUARANTINE|DISCARD)
 1521 {
 1522   :0
 1523   * SECURITY_MSGID_LOG ?? [^ ]
 1524   { JUNK=`echo "$MSGID" >> $SECURITY_MSGID_LOG` }
 1525 
 1526   :0 HB
 1527   * $ ^X-Content-Security: \[${HOST}\] DISCARD
 1528   {
 1529     SECURITY_QUARANTINE=/dev/null
 1530   }
 1531 
 1532   :0 HB
 1533   * $ ^X-Content-Security: \[${HOST}\] SPOOFED_SENDER
 1534   {
 1535     # don't bother the sender, it's probably forged
 1536     SECURITY_NOTIFY_SENDER=
 1537   }
 1538 
 1539   :0
 1540   * 9876543210^0 SECURITY_NOTIFY ?? [^ ]
 1541   * 9876543210^0 SECURITY_NOTIFY_VERBOSE ?? [^ ]
 1542   {
 1543     # Notify administration and sender of the attack
 1544 
 1545     STATUS="STATUS: Message delivered to $TO"
 1546     STATUS_PUBLIC="STATUS: Message delivered."
 1547     REPORT="REPORT: No details available."
 1548     SCORE="REPORT: Not a document, or already poisoned by filename. Not scanned for macros."
 1549 
 1550     :0
 1551     * SECURITY_QUARANTINE ?? [^ ]
 1552     {
 1553       STATUS="STATUS: Message quarantined in $SECURITY_QUARANTINE, not delivered to recipient."
 1554       STATUS_PUBLIC="STATUS: Message quarantined, not delivered to recipient."
 1555     }
 1556 
 1557     :0 HB
 1558     * $ ^X-Content-Security: \[${HOST}\] DISCARD
 1559     {
 1560       STATUS="STATUS: Message discarded, not delivered to recipient."
 1561       STATUS_PUBLIC="$STATUS"
 1562     }
 1563 
 1564     :0 HB
 1565     * ^\/Macro Scanner score: [1-9][0-9]+
 1566     {
 1567       SCORE="REPORT: $MATCH"
 1568     }
 1569 
 1570     :0 HB
 1571     * $ ^X-Content-Security: \[${HOST}\] REPORT:
 1572     { REPORT=`grep "^X-Content-Security: \[${HOST}\] REPORT: " | sed -e 's/^.* REPORT:/REPORT:/g'` }
 1573 
 1574 
 1575     #---------------------------------------------------------------------------
 1576     # Smart Sender Notify Suppression
 1577     # If the Return-Path: domain is not supported by any of the Received: domains
 1578     # then the envelope sender address is probably forged. Don't waste time notifying.
 1579     #
 1580     
 1581     :0
 1582     *   SECURITY_NOTIFY_SENDER ?? [^ ]
 1583     *   FROMDOM ?? [^ ]
 1584     * ! SECURITY_DISABLE_SMART_REPLY ?? [^ ]
 1585     {
 1586       FROMDOM2="_"
 1587       FROMDOM3="_"
 1588     
 1589       :0
 1590       * FROMDOM ?? ^.+\.\/[^.]+\.[^.]+$
 1591       {
 1592         FROMDOM2="$MATCH"
 1593         # ignore some domains (e.g. ac.uk, com.ar, etc.)
 1594         :0
 1595         * FROMDOM2 ?? ^(co|ac|com|net|org)\.[a-z][a-z]$
 1596         {
 1597           FROMDOM2="_"
 1598         }
 1599       }
 1600     
 1601       :0
 1602       * FROMDOM ?? ^.+\.\/[^.]+\.[^.]+\.[^.]+$
 1603       {
 1604         FROMDOM3="$MATCH"
 1605       }
 1606     
 1607       # Look for Received: headers that support the sender's claimed domain
 1608       # Line 1: sendmail, postfix
 1609       # Line 2: qmail
 1610       :0 H
 1611       * $! ^Received: from [^ ]+ \(([^ .]+\.)*($FROMDOM|$FROMDOM3|$FROMDOM2) [^)]+\)+[ 	]+by (${SECURITY_TRUSTED_MTAS:-${HOST}})
 1612       * $! ^Received: from ([^ .]+\.)*($FROMDOM|$FROMDOM3|$FROMDOM2)[ 	]+\(HELO .*[ 	]+by (${SECURITY_TRUSTED_MTAS:-${HOST}})
 1613       {
 1614         REPLY_SUPPRESSED="NOTICE: Envelope sender domain $FROMDOM not supported by trusted Received: path. Suppressing sender notification.${NL}"
 1615         LOG=" $REPLY_SUPPRESSED"
 1616         SECURITY_NOTIFY_SENDER=
 1617       }
 1618     
 1619       # Did a mailing list rewrite the Return-Path header?
 1620       :0E
 1621       * -1^0
 1622       * 1^0 ^Precedence: (bulk|junk|list)
 1623       * 1^0 ^(List-Id|X-Mailing-List):
 1624       * 9876543210^0 FROM ?? \<owner-
 1625       * 9876543210^0 FROM ?? \<[^@ >]+-l-admin@
 1626       {
 1627         REPLY_SUPPRESSED="NOTICE: Message from mailing list. Suppressing sender notification.${NL}"
 1628         LOG=" $REPLY_SUPPRESSED"
 1629         SECURITY_NOTIFY_SENDER=
 1630       }
 1631     }
 1632     #---------------------------------------------------------------------------
 1633 
 1634     :0 HB
 1635     * !$ ^X-Content-Security: \[${HOST}\] NONOTIFY
 1636     {
 1637        :0
 1638        * SECURITY_NOTIFY ?? [^ ]
 1639        * !$ ^X-Loop: EMAIL SECURITY WARNING $HOST $SECRET
 1640        {
 1641 	 LOG="${NL} NOTIFY ADMIN ($SECURITY_NOTIFY)${NL}"
 1642    
 1643 	 :0 h ci
 1644 	 | ( \
 1645 	     echo "To: $SECURITY_NOTIFY";\
 1646              echo 'From: "Procmail Security daemon"' "<${SECURITY_LOCAL_POSTMASTER}>";\
 1647 	     echo 'Subject: SECURITY WARNING - possible email attack';\
 1648 	     echo "X-Loop: EMAIL SECURITY WARNING $HOST $SECRET"; \
 1649 	     echo ;\
 1650 	     echo "\$Revision: 1.151 $";\
 1651 	     echo ;\
 1652 	     echo "$REPORT";\
 1653 	     echo "$SCORE";\
 1654 	     echo "$STATUS";\
 1655 	     echo "$REPLY_SUPPRESSED";\
 1656 	     echo ;\
 1657 	     echo 'Headers from message:';\
 1658 	     echo ;\
 1659 	     sed -e 's/^/> /' ;\
 1660 	   ) | $SENDMAIL $MTA_FLAGS_CMDLN $SECURITY_NOTIFY
 1661        }
 1662    
 1663        :0
 1664        * SECURITY_NOTIFY_VERBOSE ?? [^ ]
 1665        * !$ ^X-Loop: EMAIL SECURITY WARNING $HOST $SECRET
 1666        {
 1667 	 LOG="${NL} NOTIFY ADMIN VERBOSE ($SECURITY_NOTIFY_VERBOSE)${NL}"
 1668    
 1669 	 :0 hb ci
 1670 	 | ( \
 1671 	     echo "To: $SECURITY_NOTIFY_VERBOSE";\
 1672              echo 'From: "Procmail Security daemon"' "<${SECURITY_LOCAL_POSTMASTER}>";\
 1673 	     echo 'Subject: SECURITY WARNING - possible email attack';\
 1674 	     echo "X-Loop: EMAIL SECURITY WARNING $HOST $SECRET"; \
 1675 	     echo ;\
 1676 	     echo "$REPORT";\
 1677 	     echo "$SCORE";\
 1678 	     echo "$STATUS";\
 1679 	     echo "$REPLY_SUPPRESSED";\
 1680 	     echo ;\
 1681 	     echo 'Message:';\
 1682 	     echo ;\
 1683 	     sed -e 's/^/> /' ;\
 1684 	   ) | $SENDMAIL $MTA_FLAGS_CMDLN $SECURITY_NOTIFY_VERBOSE
 1685        }
 1686     }
 1687    
 1688     :0 H
 1689     * SECURITY_NOTIFY_SENDER ?? [^ ]
 1690     * !  ^FROM_DAEMON
 1691     * !$ ^X-Loop: EMAIL SECURITY WARNING $HOST $SECRET
 1692     {
 1693       LOG="${NL} NOTIFY SENDER${NL}"
 1694       PM_BCC="X-Placeholder:"
 1695       PM_CC="X-Placeholder:"
 1696 
 1697       :0 HB
 1698       * !$ ^X-Content-Security: \[${HOST}\] NONOTIFY
 1699       {
 1700           PM_BCC="Bcc: $SECURITY_NOTIFY"
 1701       }
 1702 
 1703       :0
 1704       * SECURITY_NOTIFY_SENDER_POSTMASTER ?? [^ ]
 1705       * FROMDOM ?? [^ ]
 1706       {
 1707           PM_CC="postmaster@$FROMDOM"
 1708           
 1709 	  :0
 1710 	  * SECURITY_NOTIFY_SENDER_ABUSE ?? [^ ]
 1711 	  {
 1712 	    PM_CC="$PM_CC>, <abuse@$FROMDOM"
 1713 	  }
 1714 
 1715           PM_CC="Cc: <$PM_CC>"
 1716       }
 1717 
 1718       MSG_HEADERS=`sed -e '/^$/q; s/^/> /'`
 1719 
 1720       :0 h ci
 1721       | ( \
 1722           formail -r \
 1723                   -I "From: \"Procmail Security daemon\" <${SECURITY_LOCAL_POSTMASTER}>"\
 1724                   -I "$PM_BCC" -I "$PM_CC" -I "References: $MSGID" \
 1725 		  -I "Sender: <${SECURITY_LOCAL_POSTMASTER}>" \
 1726 		  -I "Errors-To: <${SECURITY_LOCAL_POSTMASTER}>" \
 1727                   -I "X-Loop: EMAIL SECURITY WARNING $HOST $SECRET" \
 1728 		  -I "$OVERRIDEFORMAIL" \
 1729           ;\
 1730           echo ;\
 1731           if [ -f "$SECURITY_NOTIFY_SENDER" -a -s "$SECURITY_NOTIFY_SENDER" -a -r "$SECURITY_NOTIFY_SENDER" ] ;\
 1732           then \
 1733                 echo 'Regarding your message to';\
 1734                 echo "$TO";\
 1735                 echo ;\
 1736                 cat $SECURITY_NOTIFY_SENDER; \
 1737           else \
 1738                 echo '*** SECURITY WARNING ***';\
 1739                 echo 'Our email gateway has detected that your message to';\
 1740                 echo "$TO";\
 1741                 echo 'MAY contain hazardous embedded scripting or attachments,';\
 1742                 echo 'or has been rejected by our site security policy for some other reason.';\
 1743                 echo 'If you have a question, please reply to this notification message.';\
 1744                 echo ;\
 1745                 echo 'It is POSSIBLE that your message was infected by a virus.';\
 1746                 echo 'You should make sure your virus signature file';\
 1747                 echo 'is up-to-date and then rescan your computer,';\
 1748                 echo 'especially if you do not remember sending this message.';\
 1749                 echo ;\
 1750                 echo 'If the macro scanner score is large yet your virus scanner reports';\
 1751                 echo 'that the document is not infected, try saving it using a different';\
 1752                 echo 'format (such as Rich Text - "RTF") that will remove all macros.';\
 1753           fi ;\
 1754           echo ;\
 1755           echo "$REPORT";\
 1756           echo "$SCORE";\
 1757           echo "$STATUS_PUBLIC";\
 1758           echo ;\
 1759           echo 'Headers from message:';\
 1760           echo ;\
 1761           echo "$MSG_HEADERS";\
 1762           echo ;\
 1763           echo ;\
 1764           echo '--';\
 1765           echo 'Message sanitized on' $HOST;\
 1766           echo 'See http://www.impsec.org/email-tools/sanitizer-intro.html for details.';\
 1767           echo ;\
 1768         ) | $SENDMAIL $MTA_FLAGS_HDRS
 1769 
 1770     }
 1771   }
 1772 
 1773   :0
 1774   * SECURITY_QUARANTINE ?? [^ ]
 1775   {
 1776     :0
 1777     * SECURITY_NOTIFY_RECIPIENT ?? [^ ]
 1778     {
 1779       LOG="${NL} NOTIFY RECIPIENT${NL}"
 1780 
 1781       # We could stuff this directly into $DEFAULT but then
 1782       # we'd have to worry about generating Message-ID and Date headers
 1783       # and it wouldn't work on a relay...
 1784       :0 h ci
 1785       | ( \
 1786           echo "To: $TO";\
 1787           echo 'From: "Procmail Security daemon"' "<${SECURITY_LOCAL_POSTMASTER}>";\
 1788 	  if [ "$SECURITY_QUARANTINE" = "/dev/null" ] ;\
 1789           then \
 1790 		  echo 'Subject: SECURITY WARNING - email discarded';\
 1791           else \
 1792 		  echo 'Subject: SECURITY WARNING - email quarantined';\
 1793           fi ;\
 1794           echo ;\
 1795           if [ -f "$SECURITY_NOTIFY_RECIPIENT" -a -s "$SECURITY_NOTIFY_RECIPIENT" -a -r "$SECURITY_NOTIFY_RECIPIENT" ] ;\
 1796           then \
 1797                 cat $SECURITY_NOTIFY_RECIPIENT; \
 1798           else \
 1799                 echo '*** SECURITY WARNING ***';\
 1800                 echo 'Our email gateway has detected that a message sent to you';\
 1801                 echo 'MAY contain hazardous embedded scripting or attachments.';\
 1802                 echo 'The message has been quarantined or discarded per our site security policy.';\
 1803                 echo 'Please contact your system administrator for further details.';\
 1804                 echo ;\
 1805           fi ;\
 1806           echo ;\
 1807           echo "$REPORT";\
 1808           echo "$SCORE";\
 1809           echo "$STATUS_PUBLIC";\
 1810           echo ;\
 1811           echo 'Headers from message:';\
 1812           echo ;\
 1813           sed -e 's/^/> /' ;\
 1814           echo ;\
 1815           echo '--';\
 1816           echo 'Message sanitized on' $HOST;\
 1817           echo 'See http://www.impsec.org/email-tools/sanitizer-intro.html for details.';\
 1818           echo ;\
 1819         ) | $SENDMAIL $MTA_FLAGS_HDRS
 1820 
 1821     }
 1822 
 1823     :0 :${SECURITY_QUARANTINE_LOCKFILE}
 1824     $SECURITY_QUARANTINE
 1825 
 1826     :0 e
 1827     * ! SECURITY_QUARANTINE_OPTIONAL ?? [^ ]
 1828     {
 1829       # Argh! Quarantine failed, and not explicitly marked as optional!
 1830       # Bounce message, and notify administrator
 1831       LOG="${NL} ERR: QUARANTINE FAILED!${NL}"
 1832       EXITCODE=65
 1833 
 1834       :0 h
 1835       * SECURITY_NOTIFY ?? [^ ]
 1836       * !$ ^X-Loop: EMAIL SECURITY WARNING $HOST $SECRET
 1837       | ( \
 1838           echo "To: $SECURITY_NOTIFY";\
 1839           echo 'From: "Procmail Security daemon"' "<${SECURITY_LOCAL_POSTMASTER}>";\
 1840           echo 'Subject: SECURITY WARNING - quarantine failed!';\
 1841           echo "X-Loop: EMAIL SECURITY WARNING $HOST $SECRET"; \
 1842           echo ;\
 1843           echo 'Attempt to quarantine the following message in $SECURITY_QUARANTINE failed.';\
 1844           echo 'Message has been bounced.';\
 1845           echo 'Verify file access permissions (file must be writable):';\
 1846           ls -l $SECURITY_QUARANTINE ;\
 1847           echo ;\
 1848           echo "$REPORT";\
 1849           echo "$SCORE";\
 1850           echo ;\
 1851           echo 'Headers from message:';\
 1852           echo ;\
 1853           sed -e 's/^/> /' ;\
 1854         ) | $SENDMAIL $MTA_FLAGS_CMDLN $SECURITY_NOTIFY
 1855 
 1856       # zap it, just in case
 1857       :0
 1858       /dev/null
 1859     }
 1860   }
 1861 }
 1862 
 1863 #eof