1 /* $NetBSD: dsn_filter.c,v 1.2 2017/02/14 01:16:45 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* dsn_filter 3 6 /* SUMMARY 7 /* filter delivery status code or text 8 /* SYNOPSIS 9 /* #include <dsn_filter.h> 10 /* 11 /* DSN_FILTER *dsn_filter_create( 12 /* const char *title, 13 /* const char *map_names) 14 /* 15 /* DSN *dsn_filter_lookup( 16 /* DSN_FILTER *fp, 17 /* DSN *dsn) 18 /* 19 /* void dsn_filter_free( 20 /* DSN_FILTER *fp) 21 /* DESCRIPTION 22 /* This module maps (bounce or defer non-delivery status code 23 /* and text) into replacement (bounce or defer non-delivery 24 /* status code and text), or maps (success status code and 25 /* text) into replacement (success status code and text). Other 26 /* DSN attributes are passed through without modification. 27 /* 28 /* dsn_filter_create() instantiates a delivery status filter. 29 /* 30 /* dsn_filter_lookup() queries the specified filter. The input 31 /* DSN must be a success, bounce or defer DSN. If a match is 32 /* found a non-delivery status must map to a non-delivery 33 /* status, a success status must map to a success status, and 34 /* the text must be non-empty. The result is a null pointer 35 /* when no valid match is found. Otherwise, the result is 36 /* overwritten upon each call. This function must not be 37 /* called with the result from a dsn_filter_lookup() call. 38 /* 39 /* dsn_filter_free() destroys the specified delivery status 40 /* filter. 41 /* 42 /* Arguments: 43 /* .IP title 44 /* Origin of the mapnames argument, typically a configuration 45 /* parameter name. This is reported in diagnostics. 46 /* .IP mapnames 47 /* List of lookup tables, separated by whitespace or comma. 48 /* .IP fp 49 /* filter created with dsn_filter_create() 50 /* .IP dsn 51 /* A success, bounce or defer DSN data structure. The 52 /* dsn_filter_lookup() result value is in part a shallow copy 53 /* of this argument. 54 /* SEE ALSO 55 /* maps(3) multi-table search 56 /* DIAGNOSTICS 57 /* Panic: invalid dsn argument; recursive call. Fatal error: 58 /* memory allocation problem. Warning: invalid DSN lookup 59 /* result. 60 /* LICENSE 61 /* .ad 62 /* .fi 63 /* The Secure Mailer license must be distributed with this software. 64 /* AUTHOR(S) 65 /* Wietse Venema 66 /* IBM T.J. Watson Research 67 /* P.O. Box 704 68 /* Yorktown Heights, NY 10598, USA 69 /*--*/ 70 71 /* 72 * System libraries. 73 */ 74 #include <sys_defs.h> 75 76 /* 77 * Utility library. 78 */ 79 #include <msg.h> 80 #include <mymalloc.h> 81 #include <vstring.h> 82 83 /* 84 * Global library. 85 */ 86 #include <maps.h> 87 #include <dsn.h> 88 #include <dsn_util.h> 89 #include <maps.h> 90 #include <dsn_filter.h> 91 92 /* 93 * Private data structure. 94 */ 95 struct DSN_FILTER { 96 MAPS *maps; /* Replacement (status, text) */ 97 VSTRING *buffer; /* Status code and text */ 98 DSN_SPLIT dp; /* Parsing aid */ 99 DSN dsn; /* Shallow copy */ 100 }; 101 102 /* 103 * SLMs. 104 */ 105 #define STR(x) vstring_str(x) 106 107 /* dsn_filter_create - create delivery status filter */ 108 109 DSN_FILTER *dsn_filter_create(const char *title, const char *map_names) 110 { 111 static const char myname[] = "dsn_filter_create"; 112 DSN_FILTER *fp; 113 114 if (msg_verbose) 115 msg_info("%s: %s %s", myname, title, map_names); 116 117 fp = (DSN_FILTER *) mymalloc(sizeof(*fp)); 118 fp->buffer = vstring_alloc(100); 119 fp->maps = maps_create(title, map_names, DICT_FLAG_LOCK); 120 return (fp); 121 } 122 123 /* dsn_filter_lookup - apply delivery status filter */ 124 125 DSN *dsn_filter_lookup(DSN_FILTER *fp, DSN *dsn) 126 { 127 static const char myname[] = "dsn_filter_lookup"; 128 const char *result; 129 int ndr_dsn = 0; 130 131 if (msg_verbose) 132 msg_info("%s: %s %s", myname, dsn->status, dsn->reason); 133 134 /* 135 * XXX Instead of hard-coded '4' etc., use some form of encapsulation 136 * when reading or updating the status class field. 137 */ 138 #define IS_SUCCESS_DSN(s) (dsn_valid(s) && (s)[0] == '2') 139 #define IS_NDR_DSN(s) (dsn_valid(s) && ((s)[0] == '4' || (s)[0] == '5')) 140 141 /* 142 * Sanity check. We filter only success/bounce/defer DSNs. 143 */ 144 if (IS_SUCCESS_DSN(dsn->status)) 145 ndr_dsn = 0; 146 else if (IS_NDR_DSN(dsn->status)) 147 ndr_dsn = 1; 148 else 149 msg_panic("%s: dsn argument with bad status code: %s", 150 myname, dsn->status); 151 152 /* 153 * Sanity check. A delivery status filter must not be invoked with its 154 * own result. 155 */ 156 if (dsn->reason == fp->dsn.reason) 157 msg_panic("%s: recursive call is not allowed", myname); 158 159 /* 160 * Look up replacement status and text. 161 */ 162 vstring_sprintf(fp->buffer, "%s %s", dsn->status, dsn->reason); 163 if ((result = maps_find(fp->maps, STR(fp->buffer), 0)) != 0) { 164 /* Sanity check. Do not allow success<=>error mappings. */ 165 if ((ndr_dsn == 0 && !IS_SUCCESS_DSN(result)) 166 || (ndr_dsn != 0 && !IS_NDR_DSN(result))) { 167 msg_warn("%s: bad status code: %s", fp->maps->title, result); 168 return (0); 169 } else { 170 vstring_strcpy(fp->buffer, result); 171 dsn_split(&fp->dp, "can't happen", STR(fp->buffer)); 172 (void) DSN_ASSIGN(&fp->dsn, DSN_STATUS(fp->dp.dsn), 173 (result[0] == '4' ? "delayed" : 174 result[0] == '5' ? "failed" : 175 dsn->action), 176 fp->dp.text, dsn->dtype, dsn->dtext, 177 dsn->mtype, dsn->mname); 178 return (&fp->dsn); 179 } 180 } 181 return (0); 182 } 183 184 /* dsn_filter_free - destroy delivery status filter */ 185 186 void dsn_filter_free(DSN_FILTER *fp) 187 { 188 static const char myname[] = "dsn_filter_free"; 189 190 if (msg_verbose) 191 msg_info("%s: %s", myname, fp->maps->title); 192 193 maps_free(fp->maps); 194 vstring_free(fp->buffer); 195 myfree((void *) fp); 196 } 197