/* #Specification: mailconf / masquerading / strategy The masquerading allows filtering of the "from:" of outgoing messages. It allows transformation of the sender. Different variations are possible. One incoming domain may be replace by another, or all email from one domain may be hidden as originating from one user from another domain. */ #include #include #include #include "mailconf.h" #include "internal.h" #include "mailconf.m" #include static MAILCONF_HELP_FILE help_masq ("masquerade"); PUBLIC MASQ::MASQ( const char *buf) { SSTRING act; buf = str_extract (buf,act); active = act.getval(); buf = str_extract (buf,from); buf = str_extract (buf,new_from); buf = str_extract (buf,comment); } PUBLIC MASQ::MASQ() { active = 1; } /* Edit one rule, return 0 if the edit was successful return 1 if this record should be deleted. */ PUBLIC int MASQ::edit() { int ret = -1; DIALOG dia; dia.newf_chk ("",active,MSG_U(F_MASQACTIVE,"This rule is active")); dia.newf_str (MSG_U(F_FROM,"from"),from); dia.newf_str (MSG_U(F_NEWFROM,"new from"),new_from); dia.newf_str (MSG_R(F_COMMENT),comment); dia.delwhat (MSG_R(F_DELCPLX)); int nof = 0; while (1){ char buf[100]; if (from.is_empty()){ strcpy (buf,MSG_U(T_NEWMASQ,"New masquerading rule")); }else{ sprintf (buf,MSG_U(T_MASQ,"Masquerading rule for %s") ,from.get()); } MENU_STATUS code = dia.edit (buf ,MSG_U(I_MASQUERADING ,"You are allowed to intercept email originating from a\n" "domain or a user of a domain and transform it so it now\n" "originate from another domain or another user of another domain\n") ,help_masq ,nof ,MENUBUT_DEL|MENUBUT_ACCEPT|MENUBUT_CANCEL); if (code == MENU_CANCEL || code == MENU_ESCAPE){ dia.restore(); break; }else if (code == MENU_DEL){ ret = 1; break; }else{ char status[2000]; SSTREAM_NUL out; if (rule1(out,status)==-1){ xconf_error ("%s",status); }else{ ret = 0; break; } } } return ret; } static const char MASQMAIL[]="masqmail"; static const char CASES[]="cases"; PUBLIC MASQS::MASQS() { SSTRINGS strs; int nb = linuxconf_getall (MASQMAIL,CASES,strs,0); for (int i=0; iget())); } rstmodified(); } PUBLIC MASQ *MASQS::getitem(int no) { return (MASQ*)ARRAY::getitem(no); } PUBLIC int MASQS::write() { linuxconf_setcursys (subsys_mail); linuxconf_removeall (MASQMAIL,CASES); int n = getnb(); for (int i=0; iactive ,c->from.get(),c->new_from.get() ,c->comment.get()); linuxconf_add (MASQMAIL,CASES,buf); } int ret = linuxconf_save(); if (ret!=-1){ rstmodified(); } return ret; } static int cmp_by_from (const ARRAY_OBJ *p1, const ARRAY_OBJ *p2) { MASQ *r1 = (MASQ*)p1; MASQ *r2 = (MASQ*)p2; int ret = r1->from.cmp(r2->from); if (ret == 0) ret = r1->new_from.cmp(r2->new_from); return ret; } PUBLIC int MASQS::edit() { int ret = 0; int nof = 0; while (1){ sort(cmp_by_from); DIALOG dia; int n = getnb(); for (int i=0; ifrom,cp->new_from); } dia.addwhat (MSG_U(T_ADDMASQ,"Select [Add] to define a new masquerading rule")); MENU_STATUS code = dia.editmenu (MSG_U(T_MASQRULES,"Masquerading rules") ,MSG_U(I_MASQRULES ,"You can setup multiple masquerading rules.\n" "The key is the origin of the message, including the user name\n") ,help_masq ,nof ,MENUBUT_ADD); if (code == MENU_QUIT || code == MENU_ESCAPE){ break; }else if (code == MENU_OK){ if (editone (nof)!=-1) ret = 1; }else if (code == MENU_ADD){ MASQ *cp = new MASQ; if (manage_edit (cp,cp->edit())==0) ret = 1; } } return ret; } /* Return != 0 if some entry were modified */ int masq_edit () { MASQS cpl; return cpl.edit(); } /* Generate the rules to be insert in the ruleset 0 of sendmail.cf. Sometime out is a SSTREAM_NUL, called this way to validate the rule. */ PUBLIC int MASQ::rule1( SSTREAM &out, char *status) { /* #Specification: mailconf / masquerading / inactive An inactive rule is not validated. This means the user may left a rules half finished. */ int ret = 0; status[0] = '\0'; if (active){ ret = 0; char userfrom[200],sitefrom[200]; userfrom[0] = sitefrom[0] = '\0'; if (from.is_empty()){ status += sprintf (status,MSG_R(F_NOEMPTY),MSG_R(F_FROM)); ret = -1; }else if (complex_parse (from,userfrom,sitefrom) == -1){ ret = -1; status += sprintf (status,MSG_R(F_IVLDTO),MSG_R(F_FROM)); } char new_userfrom[200],new_sitefrom[200]; new_userfrom[0] = new_sitefrom[0] = '\0'; if (new_from.is_empty()){ status += sprintf (status ,MSG_R(F_NOEMPTY) ,MSG_R(F_NEWFROM)); ret = -1; }else if (complex_parse (new_from,new_userfrom,new_sitefrom)==-1){ ret = -1; status += sprintf (status,MSG_R(F_IVLDTO),MSG_R(F_NEWFROM)); } if (strcmp(new_userfrom,"$*")==0){ if (strcmp(userfrom,"$*")==0){ strcpy (new_userfrom,"$1"); }else{ strcpy (new_userfrom,userfrom); } } if (ret == 0){ char *pt = ""; // Another rule in case the domain is qualified by the dns // and a . has been added. for (int i=0; i<2; i++, pt = "."){ out.printf ("R%s<@%s%s>\t$@ %s < @ %s%s>\n" ,userfrom,sitefrom,pt ,new_userfrom,new_sitefrom,pt); } } } return ret; } /* Generate the required parts of ruleset 1. Return -1 if any errors. */ PUBLIC int MASQS::rule1( SSTREAM &out) { int ret = 0; int n = getnb(); if (n > 0){ out.puts ("# Masquerading rules\nS1\n"); for (int i=0; irule1(out,status); } } return ret; }