Home | History | Annotate | Line # | Download | only in local
      1 /*	$NetBSD: bounce_workaround.c,v 1.2 2017/02/14 01:16:45 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	bounce_workaround 3
      6 /* SUMMARY
      7 /*	Send non-delivery notification with sender override
      8 /* SYNOPSIS
      9 /*	#include "local.h"
     10 /*
     11 /*	int	bounce_workaround(state)
     12 /*	LOCAL_STATE state;
     13 /* DESCRIPTION
     14 /*	This module works around a limitation in the bounce daemon
     15 /*	protocol, namely, the assumption that the envelope sender
     16 /*	address in a queue file is the delivery status notification
     17 /*	address for all recipients in that queue file. The assumption
     18 /*	is not valid when the local(8) delivery agent overrides the
     19 /*	envelope sender address by an owner- alias, for one or more
     20 /*	recipients in the queue file.
     21 /*
     22 /*	Sender address override is a problem only when delivering
     23 /*	to command or file, or when breaking a Delivered-To loop.
     24 /*	The local(8) delivery agent saves normal recipients to a
     25 /*	new queue file, together with the replacement envelope
     26 /*	sender address; delivery then proceeds from that new queue
     27 /*	file, and no workaround is needed.
     28 /*
     29 /*	The workaround sends one non-delivery notification for each
     30 /*	failed delivery that has a replacement sender address.  The
     31 /*	notifications are not aggregated, unlike notifications to
     32 /*	non-replaced sender addresses. In practice, a local alias
     33 /*	rarely has more than one file or command destination (if
     34 /*	only because soft error handling is problematic).
     35 /*
     36 /*	Arguments:
     37 /* .IP state
     38 /*	The attributes that specify the message, recipient and more.
     39 /*	Attributes describing alias, include or forward expansion.
     40 /*	A table with the results from expanding aliases or lists.
     41 /*	A table with delivered-to: addresses taken from the message.
     42 /* 	The non-delivery status must be either 4.X.X or 5.X.X.
     43 /* DIAGNOSTICS
     44 /*	Fatal errors: out of memory. The result is non-zero when
     45 /*	the operation should be tried again. Warnings: malformed
     46 /*	address.
     47 /* BUGS
     48 /*	The proper fix is to record in the bounce logfile an error
     49 /*	return address for each individual recipient. This would
     50 /*	eliminate the need for VERP-specific bounce protocol code,
     51 /*	and would move complexity from the bounce client side to
     52 /*	the bounce server side where it more likely belongs.
     53 /* LICENSE
     54 /* .ad
     55 /* .fi
     56 /*	The Secure Mailer license must be distributed with this
     57 /*	software.
     58 /* AUTHOR(S)
     59 /*	Wietse Venema
     60 /*	IBM T.J. Watson Research
     61 /*	P.O. Box 704
     62 /*	Yorktown Heights, NY 10598, USA
     63 /*--*/
     64 
     65 /* System library. */
     66 
     67 #include <sys_defs.h>
     68 #include <strings.h>
     69 
     70 /* Utility library. */
     71 
     72 #include <msg.h>
     73 #include <mymalloc.h>
     74 #include <vstring.h>
     75 #include <split_at.h>
     76 
     77 /* Global library. */
     78 
     79 #include <mail_params.h>
     80 #include <strip_addr.h>
     81 #include <stringops.h>
     82 #include <bounce.h>
     83 #include <defer.h>
     84 #include <split_addr.h>
     85 #include <canon_addr.h>
     86 
     87 /* Application-specific. */
     88 
     89 #include "local.h"
     90 
     91 int     bounce_workaround(LOCAL_STATE state)
     92 {
     93     const char *myname = "bounce_workaround";
     94     VSTRING *canon_owner = 0;
     95     int     rcpt_stat;
     96 
     97     /*
     98      * Look up the substitute sender address.
     99      */
    100     if (var_ownreq_special) {
    101 	char   *stripped_recipient;
    102 	char   *owner_alias;
    103 	const char *owner_expansion;
    104 
    105 #define FIND_OWNER(lhs, rhs, addr) { \
    106 	lhs = concatenate("owner-", addr, (char *) 0); \
    107 	(void) split_at_right(lhs, '@'); \
    108 	rhs = maps_find(alias_maps, lhs, DICT_FLAG_NONE); \
    109     }
    110 
    111 	FIND_OWNER(owner_alias, owner_expansion, state.msg_attr.rcpt.address);
    112 	if (alias_maps->error == 0 && owner_expansion == 0
    113 	    && (stripped_recipient = strip_addr(state.msg_attr.rcpt.address,
    114 						(char **) 0,
    115 						var_rcpt_delim)) != 0) {
    116 	    myfree(owner_alias);
    117 	    FIND_OWNER(owner_alias, owner_expansion, stripped_recipient);
    118 	    myfree(stripped_recipient);
    119 	}
    120 	if (alias_maps->error == 0 && owner_expansion != 0) {
    121 	    canon_owner = canon_addr_internal(vstring_alloc(10),
    122 					      var_exp_own_alias ?
    123 					      owner_expansion : owner_alias);
    124 	    SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level);
    125 	}
    126 	myfree(owner_alias);
    127 	if (alias_maps->error != 0) {
    128 	    /* At this point, canon_owner == 0. */
    129 	    dsb_simple(state.msg_attr.why, "4.3.0",
    130 		       "alias database unavailable");
    131 	    return (defer_append(BOUNCE_FLAGS(state.request),
    132 				 BOUNCE_ATTR(state.msg_attr)));
    133 	}
    134     }
    135 
    136     /*
    137      * Send a delivery status notification with a single recipient to the
    138      * substitute sender address, before completion of the delivery request.
    139      */
    140     if (canon_owner) {
    141 	rcpt_stat =
    142 	    (STR(state.msg_attr.why->status)[0] == '4' ?
    143 	     defer_one : bounce_one)
    144 	    (BOUNCE_FLAGS(state.request),
    145 	     BOUNCE_ONE_ATTR(state.msg_attr));
    146 	vstring_free(canon_owner);
    147     }
    148 
    149     /*
    150      * Send a regular delivery status notification, after completion of the
    151      * delivery request.
    152      */
    153     else {
    154 	rcpt_stat =
    155 	    (STR(state.msg_attr.why->status)[0] == '4' ?
    156 	     defer_append : bounce_append)
    157 	    (BOUNCE_FLAGS(state.request),
    158 	     BOUNCE_ATTR(state.msg_attr));
    159     }
    160     return (rcpt_stat);
    161 }
    162