PageRenderTime 55ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/bin/src/artica-send/filter.pas

https://github.com/rsd/artica-1.5
Pascal | 420 lines | 338 code | 64 blank | 18 comment | 40 complexity | 983089b3bdc0d03ea413bfb3cb908975 MD5 | raw file
  1. unit filter;
  2. {$MODE DELPHI}
  3. //{$mode objfpc}{$H+}
  4. {$LONGSTRINGS ON}
  5. interface
  6. uses
  7. Classes, SysUtils,variants, Process,IniFiles,oldlinux,md5,RegExpr in 'RegExpr.pas',logs,smtpsend,ldap,mimemess, mimepart,strutils,synautil,dnssend,synamisc;
  8. type
  9. TStringDynArray = array of string;
  10. type
  11. TTMailInfo = record
  12. client_address:string;
  13. client_name:string;
  14. reverse_client_name:string;
  15. sender:string;
  16. recipient:string;
  17. size:string;
  18. ldap_uid:string;
  19. ldap_ou:string;
  20. senderdomain:string;
  21. Filter_result:string;
  22. mx_record:string;
  23. md:string;
  24. end;
  25. type
  26. Tfilter=class
  27. private
  28. function Explode(const Separator, S: string; Limit: Integer = 0):TStringDynArray;
  29. function COMMANDLINE_PARAMETERS(FoundWhatPattern:string):boolean;
  30. GLOBAL_INI:TIniFile;
  31. function get_ARTICA_PHP_PATH():string;
  32. function BlackList(Email:TTMailInfo):TTMailInfo;
  33. function ArticaFilterQueuePath():string;
  34. function MYSQL_ACTION_QUERY(sql:string):boolean;
  35. procedure SendSqlQuery(email:TTmailInfo);
  36. function DNSMX(Email:TTMailInfo):TTMailInfo;
  37. infos:TTMailInfo;
  38. public
  39. constructor Create;
  40. destructor Destroy; override;
  41. MESSAGE_IDA:string;
  42. function ParseLines(receive:string):string;
  43. function MD5FromString(values:string):string;
  44. end;
  45. implementation
  46. //-------------------------------------------------------------------------------------------------------
  47. //##############################################################################
  48. constructor Tfilter.Create;
  49. begin
  50. forcedirectories('/etc/artica-postfix');
  51. end;
  52. //##############################################################################
  53. destructor Tfilter.Destroy;
  54. begin
  55. inherited Destroy;
  56. end;
  57. //##############################################################################
  58. function Tfilter.ParseLines(receive:string):string;
  59. const
  60. CR = #$0d;
  61. LF = #$0a;
  62. //CRLF = CR + LF;
  63. CRLF = #$0D + #$0A;
  64. var
  65. RegExpr:TRegExpr;
  66. response:string;
  67. LOGS:Tlogs;
  68. Table:TStringDynArray;
  69. S:TStringList;
  70. i:integer;
  71. BEGIN
  72. LOGS:=Tlogs.create;
  73. RegExpr:=TRegExpr.Create;
  74. RegExpr.Expression:='(.+?)=(.+)';
  75. Table:=Explode(#10,receive);
  76. for i:=0 to length(Table)-1 do begin
  77. if RegExpr.Exec(Table[i]) then begin
  78. if LowerCase(RegExpr.Match[1])='client_address' then infos.client_address:=RegExpr.Match[2];
  79. if LowerCase(RegExpr.Match[1])='client_name' then infos.client_name:=RegExpr.Match[2];
  80. if LowerCase(RegExpr.Match[1])='recipient' then infos.recipient:=RegExpr.Match[2];
  81. if LowerCase(RegExpr.Match[1])='sender' then infos.sender:=RegExpr.Match[2];
  82. if LowerCase(RegExpr.Match[1])='size' then infos.size:=RegExpr.Match[2];
  83. end;
  84. end;
  85. RegExpr.free;
  86. infos.md:=MD5FromString(receive);
  87. infos.Filter_result:='send';
  88. infos:=BlackList(infos);
  89. if infos.Filter_result='send' then infos:=DNSMX(infos);
  90. logs.logs('artica-policy:: ' + infos.md+' :: From <' + infos.sender + '> To <'+infos.recipient + '> (' + infos.client_address + ' [' + infos.client_name + '])=' + infos.Filter_result);
  91. s:=TStringList.Create;
  92. if infos.Filter_result='blacklist' then begin
  93. SendSqlQuery(infos);
  94. s.Add('action=REJECT 571 Delivery not authorized, message refused');
  95. s.Add('');
  96. s.Add('');
  97. result:=s.Text;
  98. s.free;
  99. LOGS.Free;
  100. exit;
  101. end;
  102. if infos.Filter_result='DNS' then begin
  103. SendSqlQuery(infos);
  104. s.Add('action=REJECT 571 Delivery not authorized, message refused');
  105. s.Add('');
  106. s.Add('');
  107. result:=s.Text;
  108. s.free;
  109. LOGS.Free;
  110. exit;
  111. end;
  112. s.Add('action=DUNNO');
  113. s.Add('');
  114. s.Add('');
  115. result:=s.Text;
  116. s.free;
  117. LOGS.Free;
  118. exit;
  119. end;
  120. //##############################################################################
  121. function Tfilter.DNSMX(Email:TTMailInfo):TTMailInfo;
  122. var
  123. l:TstringList;
  124. LOGS:Tlogs;
  125. s:string;
  126. RegExpr:TRegExpr;
  127. I:Integer;
  128. ldap:Tldap;
  129. parameters:string;
  130. begin
  131. ldap:=Tldap.Create;
  132. if ldap.IsLocalDomain(Email.senderdomain) then begin
  133. ldap.Free;
  134. exit(Email);
  135. end;
  136. if length(Email.senderdomain)=0 then begin
  137. RegExpr:=TRegExpr.Create;
  138. RegExpr.Expression:='(.+?)@(.+)';
  139. if RegExpr.Exec(Email.sender) then begin
  140. Email.senderdomain:=RegExpr.Match[2];
  141. end;
  142. RegExpr.Free;
  143. end;
  144. if length(trim(email.ldap_ou))=0 then email.ldap_ou:=ldap.OU_From_eMail(Email.recipient);
  145. if length(trim(email.ldap_ou))=0 then begin
  146. ldap.Free;
  147. exit(Email);
  148. end;
  149. parameters:=Ldap.ArticaDenyNoMXRecordsOu(email.ldap_ou);
  150. ldap.free;
  151. if parameters='pass' then exit(email);
  152. LOGS:=Tlogs.create;
  153. l := TStringList.create;
  154. try
  155. s := GetDNS;
  156. LOGS.LOGS('artica-policy:: DNSMX:: servers="' +s + '"');
  157. l.commatext := s;
  158. if l.count > 0 then
  159. begin
  160. s := l[0];
  161. LOGS.LOGS('artica-policy:: DNSMX:: request for="' +s + '" =>' + Email.senderdomain);
  162. GetMailServers(s, Email.senderdomain, l);
  163. end;
  164. finally
  165. end;
  166. if l.count>0 then begin
  167. for i:=0 to l.Count -1 do begin
  168. LOGS.LOGS('artica-policy:: DNSMX::(' + InttoStr(i) + ') "' +l.Strings[i] + '"');
  169. end;
  170. end else begin
  171. LOGS.LOGS('artica-policy:: No mx for ' + Email.senderdomain);
  172. Email.Filter_result:='DNS';
  173. end;
  174. l.free;
  175. result:=Email;
  176. end;
  177. //##############################################################################
  178. function Tfilter.BlackList(Email:TTMailInfo):TTMailInfo;
  179. var
  180. LDAP:Tldap;
  181. trouve:boolean;
  182. i:integer;
  183. ou,uid:string;
  184. RegExpr:TRegExpr;
  185. Sender_domain:string;
  186. LOGS:TLogs;
  187. begin
  188. LDAP:=TLdap.Create();
  189. LOGS:=TLOGS.Create;
  190. Email.ldap_uid:=ldap.EmailFromAliase(Email.recipient);
  191. if length(trim(email.ldap_ou))=0 then begin
  192. ou:=ldap.OU_From_eMail(Email.recipient);
  193. email.ldap_ou:=ou;
  194. end else begin
  195. ou:=Email.ldap_ou;
  196. end;
  197. RegExpr:=TRegExpr.Create;
  198. RegExpr.Expression:='(.+?)@(.+)';
  199. if RegExpr.Exec(Email.sender) then begin
  200. Sender_domain:=RegExpr.Match[2];
  201. Email.senderdomain:=Sender_domain;
  202. end;
  203. RegExpr.Free;
  204. if length(ou)>0 then begin
  205. if ldap.IsOuDomainBlackListed(ou,Email.senderdomain) then begin
  206. LOGS.Logs('artica-send::Global BlackList::' +ou + ' as black listed '+Sender_domain);
  207. LDAP.Free;
  208. LOGS.FREE;
  209. email.Filter_result:='blacklist';
  210. exit(email);
  211. end;
  212. RegExpr.Free;
  213. end;
  214. if LDAP.IsBlackListed(Email.sender,Email.recipient) then begin
  215. LOGS.Logs('artica-send:: BlackList::' +email.recipient + ' as black listed '+Email.sender);
  216. LDAP.Free;
  217. LOGS.FREE;
  218. email.Filter_result:='blacklist';
  219. exit(email);
  220. end;
  221. if LDAP.IsBlackListed(Email.sender,Email.recipient) then begin
  222. LOGS.Logs('artica-send:: BlackList::' + email.recipient+ ' as black listed '+Email.sender);
  223. LDAP.Free;
  224. LOGS.FREE;
  225. email.Filter_result:='blacklist';
  226. exit(email);
  227. end;
  228. LDAP.Free;
  229. LOGS.FREE;
  230. exit(email);
  231. end;
  232. //#########################################################################################
  233. procedure Tfilter.SendSqlQuery(email:TTmailInfo);
  234. var sql,Subject:string;
  235. begin
  236. Subject:='No Subject';
  237. sql:='INSERT INTO messages (MessageID,mail_from,mailfrom_domain,mail_to,subject,zDate,received_date,SpamRate,message_path,filter_action,ou,MailSize,SpamInfos,quarantine) ';
  238. sql:=sql + 'VALUES("'+ email.md+'","' + email.sender+'","' + email.senderdomain+'","' + email.recipient +'","'+Subject+'",';
  239. sql:=sql + 'DATE_FORMAT(NOW(),''%Y-%m-%d %H:%I:%S''),DATE_FORMAT(NOW(),''%Y-%m-%d %H:%I:%S''),"0","'+email.md+'","' +email.Filter_result+'","' +email.ldap_ou+'","' + email.size + '","NONE","0")';
  240. MYSQL_ACTION_QUERY(sql);
  241. end;
  242. //#########################################################################################
  243. function Tfilter.Explode(const Separator, S: string; Limit: Integer = 0):TStringDynArray;
  244. var
  245. SepLen : Integer;
  246. F, P : PChar;
  247. ALen, Index : Integer;
  248. begin
  249. SetLength(Result, 0);
  250. if (S = '') or (Limit < 0) then
  251. Exit;
  252. if Separator = '' then
  253. begin
  254. SetLength(Result, 1);
  255. Result[0] := S;
  256. Exit;
  257. end;
  258. SepLen := Length(Separator);
  259. ALen := Limit;
  260. SetLength(Result, ALen);
  261. Index := 0;
  262. P := PChar(S);
  263. while P^ <> #0 do
  264. begin
  265. F := P;
  266. P := StrPos(P, PChar(Separator));
  267. if (P = nil) or ((Limit > 0) and (Index = Limit - 1)) then
  268. P := StrEnd(F);
  269. if Index >= ALen then
  270. begin
  271. Inc(ALen, 5); // mehrere auf einmal um schneller arbeiten zu können
  272. SetLength(Result, ALen);
  273. end;
  274. SetString(Result[Index], F, P - F);
  275. Inc(Index);
  276. if P^ <> #0 then
  277. Inc(P, SepLen);
  278. end;
  279. if Index < ALen then
  280. SetLength(Result, Index); // wirkliche Länge festlegen
  281. end;
  282. //####################################################################################
  283. function Tfilter.MD5FromString(values:string):string;
  284. var StACrypt,StCrypt:String;
  285. Digest:TMD5Digest;
  286. begin
  287. Digest:=MD5String(values);
  288. exit(MD5Print(Digest));
  289. end;
  290. //####################################################################################
  291. function Tfilter.COMMANDLINE_PARAMETERS(FoundWhatPattern:string):boolean;
  292. var
  293. i:integer;
  294. s:string;
  295. RegExpr:TRegExpr;
  296. begin
  297. result:=false;
  298. if ParamCount>0 then begin
  299. for i:=0 to ParamCount do begin
  300. s:=s + ' ' +ParamStr(i);
  301. end;
  302. end;
  303. RegExpr:=TRegExpr.Create;
  304. RegExpr.Expression:=FoundWhatPattern;
  305. if RegExpr.Exec(s) then begin
  306. RegExpr.Free;
  307. result:=True;
  308. end;
  309. end;
  310. //####################################################################################
  311. function Tfilter.get_ARTICA_PHP_PATH():string;
  312. var path:string;
  313. begin
  314. if not DirectoryExists('/usr/share/artica-postfix') then begin
  315. path:=ParamStr(0);
  316. path:=ExtractFilePath(path);
  317. path:=AnsiReplaceText(path,'/bin/','');
  318. exit(path);
  319. end else begin
  320. exit('/usr/share/artica-postfix');
  321. end;
  322. end;
  323. //##############################################################################
  324. function Tfilter.MYSQL_ACTION_QUERY(sql:string):boolean;
  325. var root,commandline,password,cmd_result,pass:string;
  326. i:integer;
  327. D:boolean;
  328. RegExpr:TRegExpr;
  329. found:boolean;
  330. logs:Tlogs;
  331. MyRes:TstringList;
  332. QueuePath:string;
  333. FileTemp:string;
  334. database:string;
  335. begin
  336. database:='artica_filter';
  337. D:=COMMANDLINE_PARAMETERS('debug');
  338. FileTemp:=MD5FromString(sql+database)+'.sql';
  339. QueuePath:=ArticaFilterQueuePath() +'/sql_queue';
  340. ForceDirectories(QueuePath);
  341. MyRes:=TstringList.Create;
  342. MyRes.Add('<database>'+database + '</database>');
  343. MyRes.Add('<sqlquery>'+ sql + '</sqlquery>');
  344. MyRes.SaveToFile(QueuePath + '/'+FileTemp );
  345. myRes.Free;
  346. end;
  347. //##############################################################################
  348. function Tfilter.ArticaFilterQueuePath():string;
  349. var ini:TIniFile;
  350. begin
  351. ini:=TIniFile.Create('/etc/artica-postfix/artica-filter.conf');
  352. result:=ini.ReadString('INFOS','QueuePath','');
  353. if length(trim(result))=0 then result:='/usr/share/artica-filter';
  354. end;
  355. //##############################################################################
  356. end.