1#!perl -w 2 3=head1 NAME 4 5postfix-queue 6 7=head1 DESCRIPTION 8 9This plugin passes mails on to the postfix cleanup daemon. 10 11=head1 CONFIG 12 13The first optional parameter is the location of the cleanup socket. If it does 14not start with a ``/'', it is treated as a flag for cleanup (see below). 15The 'postfix_queue' plugin can also contain a list of cleanup socket paths 16and/or remote postfix cleanup service hosts specified in the form of 17'address:port'. If set, the environment variable POSTFIXQUEUE overrides both 18of these settings. 19 20All other parameters are flags for cleanup, no flags are enabled by default. 21See below in ``POSTFIX COMPATIBILITY'' for flags understood by your postfix 22version. Supported by all postfix versions E<gt>= 2.1 are: 23 24=over 4 25 26=item FLAG_FILTER 27 28Set the CLEANUP_FLAG_FILTER for cleanup. This enables the use of 29I<header_filter>, I<body_filter> or I<content_filter> in postfix' main.cf. 30 31=item FLAG_BCC_OK 32 33Setting this flag enables (for example) the I<recipient_bcc_maps> parameter 34 35=item FLAG_MAP_OK 36 37This flag enables the use of other recipient mappings (e.g. 38I<virtual_alias_maps>) in postfix' cleanup. 39 40=item FLAG_MASK_EXTERNAL 41 42This flag mask combines FLAG_FILTER, FLAG_MILTER (only in postfix >= 2.3) 43FLAG_BCC_OK and FLAG_MAP_OK and is used by postfix for external messages. 44This is probably what you want to use. 45 46=back 47 48For more flags see below in ``POSTFIX COMPATIBILITY'', your postfix version 49(grep _FLAG_ src/global/cleanup_user.h) and/or lib/Qpsmtpd/Postfix/Constants.pm 50 51=head1 POSTFIX COMPATIBILITY 52 53The first version of this plugin was written for postfix 1.x. 54 55The next step for Postfix 2.1 (and later) was to add the FLAG_FILTER, 56FLAG_BCC_OK and FLAG_MAP_OK flags for submission to the cleanup deamon. 57 58This version can use all flags found in Postfix 2.x (up to 2.4 currently). 59Unknown flags are ignored by the cleanup daemon (just tested with postfix 602.1), so it should be safe to set flags just understood by later versions 61of postfix/cleanup. 62 63Even if all known flags can be set, some are not that useful when feeding 64the message from qpsmtpd, e.g. 65 66=head2 FLAG_NONE 67 68no effect 69 70=head2 FLAG_DISCARD 71 72DON'T USE, use another plugin which hooks the I<hook_queue()> and returns 73B<OK> just for the messages you want to drop. As long as this plugin does 74not support setting queue flags on the fly from other modules, this flag 75would drop ALL messages. Don't use! 76 77=head2 FLAG_BOUNCE 78 79Qpsmtpd should be configured not to accept bad messages... 80 81=head2 FLAG_HOLD 82 83Not useful in production setup, maybe in testing environment (untested, what 84real effects this has). 85 86=over 4 87 88=item Flags known by postfix 1.1: 89 90 FLAG_NONE - No special features 91 FLAG_BOUNCE - Bounce bad messages 92 FLAG_FILTER - Enable content filter 93 94=item Flags known by postfix 2.1, 2.2 95 96all flags from postfix 1.1, plus the following: 97 FLAG_HOLD - Place message on hold 98 FLAG_DISCARD - Discard message silently 99 FLAG_BCC_OK - Ok to add auto-BCC addresses 100 FLAG_MAP_OK - Ok to map addresses 101 FLAG_MASK_INTERNAL - alias for FLAG_MAP_OK 102 FLAG_MASK_EXTERNAL - FILTER, BCC_OK and MAP_OK 103 104=item Flags known by postfix 2.3 105 106all flags from postfix 2.1, up to FLAG_MASK_INTERNAL. New or changed: 107 FLAG_MILTER - Enable Milter applications 108 FLAG_FILTER_ALL - FILTER and MILTER 109 FLAG_MASK_EXTERNAL - FILTER_ALL, BCC_OK, MAP_OK 110 111=item Flags known by postfix 2.4 112 113currently (postfix-2.4-20061019) the same as 2.3 114 115=back 116 117=head1 MAYBE IN FUTURE 118 119Settings the (additional) queue flags from another plugin. Currently at the 120beginning of I<hook_queue()> all flags are reset to the flags given as plugin 121parameters. 122 123=cut 124 125use Qpsmtpd::Postfix; 126use Qpsmtpd::Postfix::Constants; 127 128sub register { 129 my ($self, $qp, @args) = @_; 130 131 $self->log(LOGDEBUG, 132 "using constants generated from Postfix" . "v$postfix_version"); 133 $self->{_queue_flags} = 0; 134 if (@args > 0) { 135 if ($args[0] =~ m#^(/.+)#) { 136 137 # untaint socket path 138 $self->{_queue_socket} = $1; 139 shift @args; 140 } 141 142 foreach (@args) { 143 if ($self->can("CLEANUP_" . $_) and /^(FLAG_[A-Z0-9_]+)$/) { 144 $_ = $1; 145 $self->{_queue_flags} |= (eval "CLEANUP_$_;" || 0); 146 147 #print STDERR "queue flag: $_: ".$self->{_queue_flags}."\n"; 148 } 149 else { 150 $self->log(LOGWARN, "Ignoring unkown cleanup flag $_"); 151 } 152 } 153 } 154 else { 155 $self->{_queue_socket} = "/var/spool/postfix/public/cleanup"; 156 } 157 158 $self->{_queue_socket_env} = $ENV{POSTFIXQUEUE} if $ENV{POSTFIXQUEUE}; 159 160} 161 162sub hook_queue { 163 my ($self, $transaction) = @_; 164 $transaction->notes('postfix-queue-flags', $self->{_queue_flags}); 165 my @queue; 166 @queue = ($self->{_queue_socket_env}) if $self->{_queue_socket_env}; 167 @queue = $self->qp->config('cleanup_sockets') unless @queue; 168 @queue = ($self->{_queue_socket} // ()) unless @queue; 169 $transaction->notes('postfix-queue-sockets', \@queue) if @queue; 170 171# $self->log(LOGDEBUG, "queue-flags=".$transaction->notes('postfix-queue-flags')); 172 my ($status, $qid, $reason) = Qpsmtpd::Postfix->inject_mail($transaction); 173 if ($status) { 174 175 # this split is needed, because if cleanup returns 176 # CLEANUP_STAT_MASK_INCOMPLETE we might return DENY (CLEANUP_STAT_SIZE) 177 # instead of DENYSOFT (CLEANUP_STAT_WRITE, CLEANUP_STAT_BAD, 178 # CLEANUP_STAT_DEFER) ... n.b. this is the behaviour of 667. 179 foreach my $key (keys %cleanup_soft) { 180 my $stat = eval $key # keys have the same names as the constants 181 or next; 182 if ($status & $stat) { 183 return (DENYSOFT, $reason || $cleanup_soft{$key}); 184 } 185 } 186 foreach my $key (keys %cleanup_hard) { 187 my $stat = eval $key # keys have the same names as the constants 188 or next; 189 if ($status & $stat) { 190 return (DENY, $reason || $cleanup_hard{$key}); 191 } 192 } 193 194 # we have no idea why we're here. 195 return (DECLINED, 196 $reason || "Unable to queue message ($status, $reason)"); 197 } 198 199 my $msg_id = $transaction->header->get('Message-Id') || ''; 200 $msg_id =~ s/[\r\n].*//s; # don't allow newlines in the Message-Id here 201 return (OK, "Queued! $msg_id (Queue-Id: $qid)"); 202} 203 204