ze-filter  (ze-filter-0.8.0-develop-180218)
mlfi_envto.c
Go to the documentation of this file.
1 
2 /*
3  *
4  * ze-filter - Mail Server Filter for sendmail
5  *
6  * Copyright (c) 2001-2018 - Jose-Marcio Martins da Cruz
7  *
8  * Auteur : Jose Marcio Martins da Cruz
9  * jose.marcio.mc@gmail.org
10  *
11  * Historique :
12  * Creation : janvier 2002
13  *
14  * This program is free software, but with restricted license :
15  *
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20  *
21  * More details about ze-filter license can be found at ze-filter
22  * web site : http://foss.jose-marcio.org
23  */
24 
25 /* ****************************************************************************
26  * *
27  * *
28  ******************************************************************************/
29 
30 sfsistat
31 mlfi_envto(ctx, envto)
32  SMFICTX *ctx;
33  char **envto;
34 {
35  CTXPRIV_T *priv = MLFIPRIV(ctx);
36  int result = SMFIS_CONTINUE;
37 
38  int ip_class;
39 
40  char *rcpt_to = NULL;
41  char *rcpt_email = NULL;
42  int access = RCPT_OK;
43 
44  rcpt_addr_T *rcpt_rec = NULL;
45 
47 
49 
50  if (priv == NULL) {
51  result = SMFIS_TEMPFAIL;
52  return result;
53  }
54 
56 
57  ip_class = priv->netclass.class;
58  priv->env_nb_rcpt++;
59  sm_macro_update(ctx, priv->sm);
60 
61  if (envto == NULL) {
62  ZE_LogMsgWarning(0, "%s : envto = NULL", CONNID_STR(priv->id));
63  result = SMFIS_TEMPFAIL;
64 
65  goto fin;
66  }
67  rcpt_to = envto[0];
68  if (rcpt_to == NULL) {
69  ZE_LogMsgWarning(0, "%s : envto[0] = NULL", CONNID_STR(priv->id));
70  result = SMFIS_TEMPFAIL;
71  return result;
72  }
73 
75  priv->peer_name, 1, CONNID_INT(priv->id));
76 
77  {
78  bool addrPlusEmail = FALSE;
79  char *s = NULL;
80 
81  if ((s = getenv("FROMRATEFULL")) != NULL) {
82  if (zeStrRegex(s, "yes|oui|true", NULL, NULL, TRUE))
83  addrPlusEmail = TRUE;
84  }
85 
86  if (addrPlusEmail) {
87  char cbuf[256];
88 
89  snprintf(cbuf, sizeof (cbuf), "%s-%s", priv->peer_addr, priv->env_from);
91  NULL, 1, CONNID_INT(priv->id));
92  } else {
94  NULL, 1, CONNID_INT(priv->id));
95  }
96  }
97 
98  {
99  char *auth_authen = NULL;
100 
101  auth_authen = sm_macro_get_str(priv->sm, "{auth_authen}");
102  if (auth_authen != NULL && strlen(auth_authen) > 0) {
103  (void) smtprate_add_entry(RATE_AUTH_RCPT, auth_authen, NULL, 1,
104  CONNID_INT(priv->id));
105  }
106  }
107 
108  FREE(priv->env_to);
109  priv->env_to = NULL;
110  /*
111  * ???
112  */
113  if ((rcpt_to != NULL) && (strlen(rcpt_to) > 0)) {
114  if ((priv->env_to = strdup(rcpt_to)) == NULL) {
115  ZE_LogSysError("%-12s : strdup mlfi_envto", CONNID_STR(priv->id));
116  result = SMFIS_TEMPFAIL;
117 
118  goto fin;
119  }
120  }
121 
122  /*
123  ** Validate connection
124  */
125  result = validate_connection(ctx);
126  if (result != SMFIS_CONTINUE)
127  goto fin;
128 
129  /*
130  * XXX
131  */
132  {
133  char *rcpt_mailer = NULL;
134 
135  rcpt_mailer = sm_macro_get_str(priv->sm, "{rcpt_mailer}");
136  ZE_MessageInfo(11, "rcpt_mailer = %s", STRNULL(rcpt_mailer, "NULL"));
137  if ((rcpt_mailer != NULL) && STRCASEEQUAL(rcpt_mailer, "error")) {
138  char why[256];
139 
140 
141  ZE_MessageInfo(12, "%s : SM BAD RECIPIENT : %s", CONNID_STR(priv->id),
142  rcpt_to);
143 
145  priv->dbrcpt_msg_unknown++;
146  priv->dbrcpt_conn_unknown++;
147  (void) jsmfi_setreply(ctx, "550", "5.1.1", "User unknown");
148  snprintf(why, sizeof (why), "Bad Recipient : sendmail says");
149  log_msg_context(ctx, why);
150  result = SMFIS_REJECT;
151  }
152  if (result != SMFIS_CONTINUE)
153  goto fin;
154  }
155 
156  /*
157  ** check recipient rate
158  */
159  result = check_rcptrate(ctx);
160  if (result != SMFIS_CONTINUE)
161  goto fin;
162 
163  /*
164  ** Check # of recipients for this session
165  */
167  result = check_rcptcount(ctx);
168 
169  if (result != SMFIS_CONTINUE)
170  goto fin;
171  }
172 
173 
174  /*
175  ** prepare to check recipient
176  */
177  if ((rcpt_email = strdup(rcpt_to)) == NULL) {
178  ZE_LogSysError("Error strdup(%s)", rcpt_to);
179  result = SMFIS_TEMPFAIL;
180  goto fin;
181  }
182  (void) extract_email_address(rcpt_email, rcpt_to, strlen(rcpt_email) + 1);
183 
184  /*
185  * Check if email address is enclosed within <> and conforms to RFC2822
186  */
187  if (!zeStrRegex(rcpt_to, "<.*>", NULL, NULL, TRUE)) {
188  ZE_MessageInfo(9, "%-12s : ENV TO Syntax Error : %s",
189  CONNID_STR(priv->id), priv->env_to);
190  }
191  /*
192  * more to came...
193  */
194 
195  /*
196  * add recipient to the list of recipients
197  */
198  rcpt_rec = rcpt_list_add(&priv->env_rcpt, rcpt_to, access);
199  if (rcpt_rec == NULL) {
200  ZE_MessageWarning(9, "%-12s mlfi_envto : can't add %s to rcpt_list",
201  CONNID_STR(priv->id), rcpt_to);
202  result = SMFIS_TEMPFAIL;
203  goto fin;
204  }
205  ZE_MessageInfo(11,
206  "RCPT LIST : ARG=(%s) TO=(%s) EMAIL=(%s) USER=(%s) HOST=(%s)",
207  envto[0], rcpt_rec->rcpt, rcpt_rec->email, rcpt_rec->user,
208  rcpt_rec->host);
209 
210 
211 #if _FFR_MODULES
212  /*
213  ** ze-filter modules
214  **
215  */
216  if (do_module_callback(ctx, 0, &result))
217  goto fin;
218  if (result != SMFIS_CONTINUE)
219  goto fin;
220 #endif /* _FFR_MODULES */
221 
222  /*
223  * Check recipient access
224  */
225  if (IS_UNKNOWN(ip_class) && cf_get_int(CF_CHECK_RCPT_ACCESS) == OPT_YES) {
226  access = check_rcpt(rcpt_email, priv->peer_addr, priv->peer_name, ip_class);
227 
228  if (access != RCPT_OK) {
229  char *rstr = "???";
230  char why[512];
231 
232  rstr = rcpt_code_string(access);
233  rstr = STRNULL(rstr, "???");
234 
235  ZE_MessageInfo(11, "%s : RCPT ACCESS : %-16s %02X %-16s %s : %s %2d %s",
236  CONNID_STR(priv->id), priv->peer_addr, ip_class,
237  CTX_NETCLASS_LABEL(priv),
238  priv->peer_name, priv->env_to, access, rstr);
239 
240  strlcpy(why, "", sizeof (why));
241  switch (access) {
242  case RCPT_OK:
243  break;
244  case RCPT_REJECT:
246  priv->dbrcpt_reject++;
247  (void) jsmfi_setreply(ctx, "550", "5.7.1", "Access denied");
248  snprintf(why, sizeof (why), "Recipient Check : %s", rstr);
249  log_msg_context(ctx, why);
250  result = SMFIS_REJECT;
251  break;
252  case RCPT_ACCESS_DENIED:
254  priv->dbrcpt_access++;
255  (void) jsmfi_setreply(ctx, "550", "5.7.1", "Access denied");
256  snprintf(why, sizeof (why), "Recipient Check : %s", rstr);
257  log_msg_context(ctx, why);
258  result = SMFIS_REJECT;
259  break;
260  case RCPT_TEMPFAIL:
262  priv->dbrcpt_reject++;
263  (void) jsmfi_setreply(ctx, "450", "4.7.1", "Temporary error");
264  snprintf(why, sizeof (why), "Recipient Check : %s", rstr);
265  log_msg_context(ctx, why);
266  result = SMFIS_TEMPFAIL;
267  break;
268  case RCPT_BAD_NETWORK:
270  priv->dbrcpt_bad_network++;
271  (void) jsmfi_setreply(ctx, "550", "5.7.1", "Access denied");
272  snprintf(why, sizeof (why), "Recipient Check : %s", rstr);
273  log_msg_context(ctx, why);
274  result = SMFIS_REJECT;
275  break;
276  case RCPT_USER_UNKNOWN:
278  priv->dbrcpt_msg_unknown++;
279  priv->dbrcpt_conn_unknown++;
280  (void) jsmfi_setreply(ctx, "550", "5.1.1", "User unknown");
281  snprintf(why, sizeof (why), "Recipient Check : %s", rstr);
282  log_msg_context(ctx, why);
283  result = SMFIS_REJECT;
284  break;
285  case RCPT_SPAMTRAP:
287  priv->dbrcpt_msg_spamtrap++;
288  priv->dbrcpt_conn_spamtrap++;
289  (void) jsmfi_setreply(ctx, "550", "5.7.1", "Access denied");
290  snprintf(why, sizeof (why), "Recipient Check : %s", rstr);
291  log_msg_context(ctx, why);
292  result = SMFIS_REJECT;
293  break;
294  case RCPT_IGNORE:
295  break;
296  default:
297  break;
298  }
299  }
300  if (rcpt_rec != NULL)
301  rcpt_rec->access = access;
302  }
303  if (result != SMFIS_CONTINUE || access == RCPT_IGNORE)
304  goto fin;
305 
306  /*
307  * Greylisting
308  */
309  if (IS_UNKNOWN(ip_class) && cf_get_int(CF_GREY_CHECK) == OPT_YES) {
310  bool doit = FALSE;
311  int rgrey = GREY_WAIT;
312 
313  doit = check_policy_tuple("GreyCheck", priv->peer_addr, priv->peer_name,
314  CTX_NETCLASS_LABEL(priv),
315  priv->env_from, priv->env_to, TRUE);
316 
317  if (doit) {
318  bool new = FALSE;
319  bool can_validate = TRUE;
320 
321  rgrey = grey_check(priv->peer_addr, priv->env_from, priv->env_to,
322  priv->peer_name, &new, can_validate);
323  switch (rgrey) {
324  case GREY_OK:
325  /*
326  * If just validated, and working in GREY_CLIENT mode,
327  * ** shall inform greyd server
328  */
329  if (new && cf_get_int(CF_GREY_MODE) == OPT_CLIENT) {
330  rgrey = remote_grey_validate(priv->peer_addr, priv->env_from,
331  priv->env_to, priv->peer_name);
332  }
333  break;
334  case GREY_WAIT:
335  /*
336  * If just created new entry, and working in GREY_CLIENT mode
337  * ** shall check greyd server
338  */
339  if (new && cf_get_int(CF_GREY_MODE) == OPT_CLIENT) {
340  /*
341  * Check with greyd server
342  * ** If greyd server has this entry already validated
343  * ** shall validate it again locally
344  */
345  rgrey = remote_grey_check(priv->peer_addr, priv->env_from,
346  priv->env_to, priv->peer_name);
347 
348  if (rgrey == GREY_OK) {
349  (void) grey_validate(priv->peer_addr, priv->env_from,
350  priv->env_to, priv->peer_name);
351  }
352  if (rgrey == GREY_DUNNO)
353  rgrey = GREY_WAIT;
354  if (rgrey == GREY_ERROR)
355  rgrey = GREY_WAIT;
356  }
357  if (rgrey == GREY_WAIT)
358  result = SMFIS_TEMPFAIL;
359  break;
360  case GREY_ERROR:
361  break;
362  }
363  if (result != SMFIS_CONTINUE) {
364 #define REPLY_REGEX "4[0-9][0-9]:4.[0-9].[0-9]:.*"
365 
366  static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
367  static bool ok = FALSE;
368  static char *rcode = "451";
369  static char *xcode = "4.3.2";
370  static char *msg = "Tempfail : Try again later, please";
371  static char rbuf[256];
372 
373  if (!ok) {
374  MUTEX_LOCK(&mutex);
375  if (!ok) {
376  char *rstr = NULL;
377  long pi;
378 
379  snprintf(rbuf, sizeof (rbuf), "%s:%s:%s", rcode, xcode, msg);
380  memset(rbuf, 0, sizeof (rbuf));
381  rstr = getenv("GREY_REPLY");
382  if (rstr != NULL) {
383  if (zeStrRegex(rstr, REPLY_REGEX, &pi, NULL, FALSE))
384  strlcpy(rbuf, rstr + pi, sizeof (rbuf));
385  else
386  rstr = NULL;
387  }
388  if (rstr == NULL) {
389  rstr = cf_get_str(CF_GREY_REPLY);
390  if (zeStrRegex(rstr, REPLY_REGEX, &pi, NULL, FALSE))
391  strlcpy(rbuf, rstr + pi, sizeof (rbuf));
392  else
393  rstr = NULL;
394  }
395  if (rstr != NULL) {
396  int argc;
397  char *argv[4];
398 
399  argc = zeStr2Tokens(rbuf, 4, argv, ":");
400  if (argc > 2) {
401  rcode = argv[0];
402  xcode = argv[1];
403  msg = argv[2];
404  }
405  }
406  ZE_MessageInfo(10, "GREY REPLY : rcode=%s xcode=%s msg=%s",
407  rcode, xcode, msg);
408  ok = TRUE;
409  }
410  MUTEX_UNLOCK(&mutex);
411  }
412 
413  (void) jsmfi_setreply(ctx, rcode, xcode, msg);
414 
415  log_msg_context(ctx, "Message delayed by greylisting");
416 
417  priv->rej_greyrcpt++;
418  priv->rej_greyreply++;
420  }
421  }
422  }
423 
424  if (result != SMFIS_CONTINUE)
425  goto fin;
426 
428  if (check_policy_tuple("Archive", priv->peer_addr, priv->peer_name,
429  CTX_NETCLASS_LABEL(priv),
430  priv->env_from, priv->env_to, FALSE)) {
431  ZE_MessageInfo(10, "%-12s Archiving message : %s %s %s %s",
432  CONNID_STR(priv->id), priv->peer_addr, priv->peer_name,
433  priv->env_from, priv->env_to);
434 
435  DO_QUARANTINE_MESSAGE(priv, WHY_ARCHIVE, NULL);
436 
437  log_msg_context(ctx, "Message Archived");
438  }
439  }
440 #if _FFR_PASS_PARTOUT
441  if (passport_ok(priv->env_to, NULL))
442  priv->pass_ok = TRUE;
443 #endif
444 
445  /*
446  * end...
447  */
448 fin:
449  if (rcpt_rec != NULL && rcpt_rec->access == RCPT_OK) {
450  switch (result) {
451  case SMFIS_TEMPFAIL:
452  rcpt_rec->access = RCPT_TEMPFAIL;
453  break;
454  case SMFIS_REJECT:
455  rcpt_rec->access = RCPT_REJECT;
456  break;
457  default:
458  break;
459  }
460  }
461  FREE(rcpt_email);
462 
464 
465  /*
466  * continue processing
467  */
468  return result;
469 }
char * host
Definition: ze-rcpt-list.h:33
int smtprate_add_entry(int, char *, char *, int, time_t)
Definition: ze-smtprate.c:363
#define RCPT_REJECT
Definition: ze-rcpt.h:39
rcpt_addr_T * env_rcpt
char * rcpt
Definition: ze-rcpt-list.h:31
#define STAT_RCPT_REJECT
Definition: ze-stats.h:83
void stats_inc(int, long)
Definition: ze-stats.c:401
#define CF_ARCHIVE
Definition: cfh-defs.h:75
int dbrcpt_conn_unknown
#define STAT_RCPT_ACCESS
Definition: ze-stats.h:84
#define CF_CHECK_NB_RCPT
Definition: cfh-defs.h:157
#define SMFIS_TEMPFAIL
#define CF_CHECK_RCPT_ACCESS
Definition: cfh-defs.h:151
int jsmfi_setreply(SMFICTX *, char *, char *, char *)
Definition: ze-libmilter.c:99
#define STAT_ENVTO
Definition: ze-stats.h:32
#define CONNID_INT(connid)
Definition: ze-filter.h:114
#define FREE(x)
Definition: macros.h:37
int remote_grey_check(char *ip, char *from, char *to, char *hostname)
#define MUTEX_UNLOCK(mutex)
Definition: macros.h:101
#define RATE_AUTH_RCPT
Definition: ze-smtprate.h:68
#define STAT_RCPT_TEMPFAIL
Definition: ze-stats.h:82
char * peer_addr
#define STRNULL(x, r)
Definition: macros.h:81
bool ok
Definition: ze-connopen.c:59
#define CALLBACK_RCPT
Definition: ze-callback.h:31
#define MUTEX_LOCK(mutex)
Definition: macros.h:93
pthread_mutex_t mutex
Definition: ze-connopen.c:63
int dbrcpt_bad_network
#define FALSE
Definition: macros.h:160
#define SMFIS_CONTINUE
#define SMFIS_REJECT
#define strlcpy
Definition: zeString.h:32
bool zeStrRegex(char *, char *, long *, long *, bool)
Definition: zeStrings.c:544
#define GREY_ERROR
Definition: ze-grey.h:38
char * extract_email_address(char *, char *, size_t)
#define OPT_YES
Definition: ze-cf.h:45
char * user
Definition: ze-rcpt-list.h:34
int remote_grey_validate(char *ip, char *from, char *to, char *hostname)
char * env_to
int grey_check(char *, char *, char *, char *, bool *, bool)
Definition: ze-grey.c:491
int cf_get_int(int id)
Definition: ze-cf.c:803
#define MLFIPRIV(ctx)
int zeStr2Tokens(char *, int, char **, char *)
Definition: zeStrings.c:610
#define INIT_CALLBACK(p, which)
Definition: ze-filter.c:125
#define DO_QUARANTINE_MESSAGE(priv, why, suffix)
int dbrcpt_msg_spamtrap
void sm_macro_update(SMFICTX *, sm_mac_T *)
Definition: ze-smmacros.c:150
char * email
Definition: ze-rcpt-list.h:32
CONNID_T id
int grey_validate(char *, char *, char *, char *)
Definition: ze-grey.c:825
#define RCPT_SPAMTRAP
Definition: ze-rcpt.h:44
int check_rcpt(char *rcpt, char *ip, char *name, int netclass)
Definition: ze-rcpt.c:89
#define RCPT_USER_UNKNOWN
Definition: ze-rcpt.h:43
#define RCPT_TEMPFAIL
Definition: ze-rcpt.h:40
#define INIT_CALLBACK_DELAY()
Definition: ze-filter.c:135
#define RCPT_ACCESS_DENIED
Definition: ze-rcpt.h:41
#define GREY_DUNNO
Definition: ze-grey.h:39
#define CF_GREY_CHECK
Definition: cfh-defs.h:190
#define GREY_OK
Definition: ze-grey.h:35
#define RCPT_OK
Definition: ze-rcpt.h:38
#define IS_UNKNOWN(class)
Definition: ze-netclass.h:51
char * rcpt_code_string(int)
Definition: ze-rcpt.c:530
#define ZE_MessageInfo(level,...)
Definition: zeSyslog.h:90
#define OPT_NO
Definition: ze-cf.h:44
sfsistat check_rcptrate(SMFICTX *)
int dbrcpt_conn_spamtrap
#define TRUE
Definition: macros.h:157
#define STAT_RCPT_UNKNOWN
Definition: ze-stats.h:86
#define ZE_MessageWarning(level,...)
Definition: zeSyslog.h:92
#define RCPT_IGNORE
Definition: ze-rcpt.h:45
int dbrcpt_msg_unknown
OPT_REC_T cf_opt
Definition: ze-config.c:40
#define ZE_LogSysError(...)
Definition: zeSyslog.h:129
char * cf_get_str(int id)
Definition: ze-cf.c:854
#define RATE_RCPT
Definition: ze-smtprate.h:52
sfsistat validate_connection(SMFICTX *)
char * peer_name
#define ZE_LogMsgWarning(level,...)
Definition: zeSyslog.h:112
#define CTX_NETCLASS_LABEL(priv)
char * env_from
#define GREY_WAIT
Definition: ze-grey.h:36
bool do_module_callback(SMFICTX *ctx, int step, int *result)
Definition: ze-mod-tools.c:84
bool passport_ok(char *to, char *key)
#define OPT_CLIENT
Definition: ze-cf.h:77
#define REPLY_REGEX
sm_mac_T * sm
rcpt_addr_T * rcpt_list_add(rcpt_addr_T **, char *, int)
Definition: ze-rcpt-list.c:62
#define STAT_GREY_RCPT
Definition: ze-stats.h:79
#define CF_GREY_MODE
Definition: cfh-defs.h:191
#define CONNID_STR(connid)
Definition: ze-filter.h:113
#define CHECK_CALLBACK_DELAY()
Definition: ze-filter.c:146
#define STAT_RCPT_BAD_NETWORK
Definition: ze-stats.h:85
#define STRCASEEQUAL(a, b)
Definition: macros.h:72
#define RCPT_BAD_NETWORK
Definition: ze-rcpt.h:42
#define WHY_ARCHIVE
Definition: ze-spool.h:32
netclass_T netclass
char arg_q
Definition: ze-config.h:49
char * sm_macro_get_str(sm_mac_T *, char *)
Definition: ze-smmacros.c:191
#define CF_GREY_REPLY
Definition: cfh-defs.h:207
void log_msg_context(SMFICTX *ctx, char *why)
#define RATE_FROM_RCPT
Definition: ze-smtprate.h:64
sfsistat mlfi_envto(SMFICTX *ctx, char **envto)
Definition: mlfi_envto.c:31
bool check_policy_tuple(char *prefix, char *ip, char *name, char *netclass, char *from, char *to, bool result)
Definition: ze-policy.c:277
int msg[MAX_SCORE+2]
Definition: ze-stats.c:41
#define STAT_RCPT_SPAMTRAP
Definition: ze-stats.h:87
sfsistat check_rcptcount(SMFICTX *)