Home | History | Annotate | Line # | Download | only in smtpd
      1 /*	$NetBSD: smtpd_dsn_fix.c,v 1.1.1.1 2009/06/23 10:08:56 tron Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	smtpd_dsn_fix 3
      6 /* SUMMARY
      7 /*	fix DSN status
      8 /* SYNOPSIS
      9 /*	#include <smtpd_dsn_fix.h>
     10 /*
     11 /*	const char *smtpd_dsn_fix(status, reply_class)
     12 /*	const char *status;
     13 /*	const char *reply_class;
     14 /* DESCRIPTION
     15 /*	smtpd_dsn_fix() transforms DSN status codes according to the
     16 /*	status information that is actually being reported. The
     17 /*	following transformations are implemented:
     18 /* .IP \(bu
     19 /*	Transform a recipient address DSN into a sender address DSN
     20 /*	when reporting sender address status information, and vice
     21 /*	versa. This transformation may be needed because some Postfix
     22 /*	access control features don't know whether the address being
     23 /*	rejected is a sender or recipient. Examples are smtpd access
     24 /*	tables, rbl reply templates, and the error mailer.
     25 /* .IP \(bu
     26 /*	Transform a sender or recipient address DSN into a non-address
     27 /*	DSN when reporting non-address status information. For
     28 /*	example, if something rejects HELO with DSN status 4.1.1
     29 /*	(unknown recipient address), then we send the more neutral
     30 /*	4.0.0 DSN instead. This transformation is needed when the
     31 /*	same smtpd access map entry or rbl reply template is used
     32 /*	for both address and non-address information.
     33 /* .PP
     34 /*	A non-address DSN is not transformed
     35 /*	when reporting sender or recipient address status information,
     36 /*	as there are many legitimate instances of such usage.
     37 /*
     38 /*	It is left up to the caller to update the initial DSN digit
     39 /*	appropriately; in Postfix this is done as late as possible,
     40 /*	because hard rejects may be changed into soft rejects for
     41 /*	all kinds of reasons.
     42 /*
     43 /*	Arguments:
     44 /* .IP status
     45 /*	A DSN status as per RFC 3463.
     46 /* .IP reply_class
     47 /*	SMTPD_NAME_SENDER, SMTPD_NAME_RECIPIENT or some other
     48 /*	null-terminated string.
     49 /* LICENSE
     50 /* .ad
     51 /* .fi
     52 /*	The Secure Mailer license must be distributed with this software.
     53 /* AUTHOR(S)
     54 /*	Wietse Venema
     55 /*	IBM T.J. Watson Research
     56 /*	P.O. Box 704
     57 /*	Yorktown Heights, NY 10598, USA
     58 /*--*/
     59 /* System library. */
     60 
     61 #include <sys_defs.h>
     62 #include <ctype.h>
     63 #include <string.h>
     64 
     65 /* Utility library. */
     66 
     67 #include <msg.h>
     68 
     69 /* Global library. */
     70 
     71 /* Application-specific. */
     72 
     73 #include <smtpd_dsn_fix.h>
     74 
     75 struct dsn_map {
     76     const char *micro_code;		/* Final digits in mailbox D.S.N. */
     77     const char *sender_dsn;		/* Replacement sender D.S.N. */
     78     const char *rcpt_dsn;		/* Replacement recipient D.S.N. */
     79 };
     80 
     81 static struct dsn_map dsn_map[] = {
     82     /* - Sender - Recipient */
     83     "1", SND_DSN, "4.1.1",		/* 4.1.1: Bad dest mbox addr */
     84     "2", "4.1.8", "4.1.2",		/* 4.1.2: Bad dest system addr */
     85     "3", "4.1.7", "4.1.3",		/* 4.1.3: Bad dest mbox addr syntax */
     86     "4", SND_DSN, "4.1.4",		/* 4.1.4: Dest mbox addr ambiguous */
     87     "5", "4.1.0", "4.1.5",		/* 4.1.5: Dest mbox addr valid */
     88     "6", SND_DSN, "4.1.6",		/* 4.1.6: Mailbox has moved */
     89     "7", "4.1.7", "4.1.3",		/* 4.1.7: Bad sender mbox addr syntax */
     90     "8", "4.1.8", "4.1.2",		/* 4.1.8: Bad sender system addr */
     91     0, "4.1.0", "4.1.0",		/* Default mapping */
     92 };
     93 
     94 /* smtpd_dsn_fix - fix DSN status */
     95 
     96 const char *smtpd_dsn_fix(const char *status, const char *reply_class)
     97 {
     98     struct dsn_map *dp;
     99     const char *result = status;
    100 
    101     /*
    102      * Update an address-specific DSN according to what is being rejected.
    103      */
    104     if (ISDIGIT(status[0]) && strncmp(status + 1, ".1.", 3) == 0) {
    105 
    106 	/*
    107 	 * Fix recipient address DSN while rejecting a sender address. Don't
    108 	 * let future recipient-specific DSN codes slip past us.
    109 	 */
    110 	if (strcmp(reply_class, SMTPD_NAME_SENDER) == 0) {
    111 	    for (dp = dsn_map; dp->micro_code != 0; dp++)
    112 		if (strcmp(status + 4, dp->micro_code) == 0)
    113 		    break;
    114 	    result = dp->sender_dsn;
    115 	}
    116 
    117 	/*
    118 	 * Fix sender address DSN while rejecting a recipient address. Don't
    119 	 * let future sender-specific DSN codes slip past us.
    120 	 */
    121 	else if (strcmp(reply_class, SMTPD_NAME_RECIPIENT) == 0) {
    122 	    for (dp = dsn_map; dp->micro_code != 0; dp++)
    123 		if (strcmp(status + 4, dp->micro_code) == 0)
    124 		    break;
    125 	    result = dp->rcpt_dsn;
    126 	}
    127 
    128 	/*
    129 	 * Fix address-specific DSN while rejecting a non-address.
    130 	 */
    131 	else {
    132 	    result = "4.0.0";
    133 	}
    134 
    135 	/*
    136 	 * Give them a clue of what is going on.
    137 	 */
    138 	if (strcmp(status + 2, result + 2) != 0)
    139 	    msg_info("mapping DSN status %s into %s status %c%s",
    140 		     status, reply_class, status[0], result + 1);
    141 	return (result);
    142     }
    143 
    144     /*
    145      * Don't update a non-address DSN. There are many legitimate uses for
    146      * these while rejecting address or non-address information.
    147      */
    148     else {
    149 	return (status);
    150     }
    151 }
    152