#!/usr/bin/perl #Расширенный хелп if ($ARGV[0]=~/^help$/i) { print "This script helps to manage rulesets for \"Sendmail ACL\" (с)linux.ufaras.ru\n"; print "Dirty code was written by Askon, using Google(c) Perl :)\n"; print "Don't forget to set correct path for \$allow_file, \$deny_file and \$tmp\n\n"; print "Example: $0 add deny from \@mail.ru to root in\n"; print "Will deny all mail from \@mail.ru to local user root\n\n"; print "Example: $0 add deny from root to test\@mail.ru out\n"; print "Will deny all mail from user root to test\@mail.ru\n\n"; print "Example: $0 del 5 {allow|deny}\n"; print "Will delete rule number 5 from allow or deny file\n\n"; print "Example: $0 del-many 1,2,5,6,10 {allow|deny}\n"; print "Will delete specified rule numbers from allow or deny file\n\n"; print "Example: $0 del-many 1-10 {allow|deny}\n"; print "Will delete all rules from 1 to 10, from allow or deny file\n\n"; print "Example: $0 like test_tv root {allow|deny}\n"; print "Will create same rulesets in allow or deny file(or in both if empty) for user root as for user test_tv.\n\n"; exit; } #Выводим хелп по комманде, если даны не все аргументы. if((@ARGV<7)&&($ARGV[0]!~/^list$/i)&&($ARGV[1] !~ /^\d+$/)&&($ARGV[0]!~/^del\-many$/i)&&($ARGV[0]!~/^like$/i)) { print "Usage:\t$0 {add|del} {allow|deny} from {username|email} to {username|email} {in|out}\n"; print "\t$0 list {allow|deny|all} {keyword}\n"; print "\t$0 del {number} {allow|deny}\n"; print "\t$0 del-many {rule1,rule2...ruleN} {allow|deny}\n"; print "\t$0 like {existing username} {new username} {allow|deny}\n"; print "\t$0 help\n"; exit; } my $direction = $ARGV[6]; my $action = $ARGV[0]; my $rule = $ARGV[1]; my $from_word = $ARGV[2]; my $from_user = $ARGV[3]; my $to_word = $ARGV[4]; my $to_user = $ARGV[5]; my $allow_file = "/etc/mail/allow"; my $deny_file = "/etc/mail/deny"; my $tmp_path = "/tmp"; #Выполняем list if ($action =~ /^list$/i) { if (($rule !~ /^allow$/i)&&($rule !~ /^deny$/i)&&($rule !~ /^all$/i)) {$rule = "all";} if ($rule =~ /^allow$/i) { if ($ARGV[2] eq "") {exec("cat -n $allow_file");} else {exec("cat -n $allow_file\|grep $ARGV[2]");} } elsif ($rule =~ /^deny$/i) { if ($ARGV[2] eq "") {exec("cat -n $deny_file");} else {exec("cat -n $deny_file\|grep $ARGV[2]");} } elsif ($rule =~ /^all$/i) { print "----ALLOW FILE----\n"; if ($ARGV[2] eq "") {system("cat -n $allow_file");} else {system("cat -n $allow_file\|grep $ARGV[2]");} print "\n----DENY FILE----\n"; if ($ARGV[2] eq "") {exec("cat -n $deny_file");} else {exec("cat -n $deny_file\| grep $ARGV[2]");} } } #Делаем like if ($action =~ /^like$/i) { if (($ARGV[1] eq "")||($ARGV[2] eq "")) {print "Wrong syntax, see example.\n";exit;} $return1 = system("cat $allow_file\|grep \":$ARGV[1]:\""); $return = system("cat $deny_file\|grep \":$ARGV[1]:\""); if (($return !=0) && ($return1 !=0)) {print "Can't find any $ARGV[1] in allow or deny file.\n";exit; } else { if (($return1 == 0) && ($ARGV[3] !~ /^deny$/i)) { system ("cat $allow_file|grep \":$ARGV[1]:\"|sed 's/:$ARGV[1]:/:$ARGV[2]:/'>>$allow_file"); make_clean($allow_file); print "New rules for $ARGV[2] were successfully created at $allow_file:\n"; system ("$0 list allow :$ARGV[2]:"); } if (($return == 0) && ($ARGV[3] !~ /^allow$/i)) { system ("cat $deny_file|grep \":$ARGV[1]:\"|sed 's/:$ARGV[1]:/:$ARGV[2]:/'>>$deny_file"); make_clean($deny_file); print "New rules for $ARGV[2] were successfully created at $deny_file:\n"; system ("$0 list deny :$ARGV[2]:"); } } exit; } #Делаем del-many if ($action =~ /^del-many$/i) { if (($ARGV[1] =~ /\-/)&&($ARGV[2] ne "")) { @rules = split(/\-/,$ARGV[1]); @rules = sort {$b <=> $a} @rules; $i=@rules[0]; if ($ARGV[2] =~ /^allow$/i) {$file = $allow_file;} elsif ($ARGV[2] =~ /^deny$/i) {$file = $deny_file;} else {print "Unknown rule file type.\n";exit;} print "Will delete many rules from @rules[1] to @rules[0]:\n"; while ($i>=@rules[1]) { system("cat -n $file\|grep \" $i\""); del_line($i,$file); $i--; } make_clean($deny_file); exit; } #Преобразовуем параметр коммандной строки $ARGV[1] в массив элементов (разделитель элементов - ",") @rules = split(/,/,$ARGV[1]); #сортируем массив по убыванию @rules = sort { $b <=> $a } @rules; #Следующие две строки удаляют из массива @rules дубликаты %seen = (); @rules = grep { ! $seen{$_} ++ } @rules; if ($ARGV[2] =~ /^deny$/i) {print "Followed line(s) will be deleted from $deny_file:\n"; for (@rules) { $return = system("cat -n $deny_file\|grep \" @rules[$j]\""); if ($return != 0) {print "No such rule number(@rules[$j]) in $deny_file\n";} else {del_line(@rules[$j],$deny_file); make_clean($deny_file);} $j++; } exit; } elsif ($ARGV[2] =~ /^allow$/i) {print "Followed line(s) will be deleted from $allow_file:\n"; for (@rules) { $return = system("cat -n $allow_file\|grep \" @rules[$j]\""); if ($return != 0) {print "No such rule number(@rules[$j]) in $allow_file\n";} else {del_line(@rules[$j],$allow_file); make_clean($allow_file);} $j++; } exit; } else {print "From what file?\n";} exit; } #Удаляем строку с заданным номером из allow или deny файла if (($action =~ /^del$/i)&&($rule =~ /^\d+$/)) { if ($from_word =~ /^allow$/i) {$file = $allow_file; print "Will delete line \#$rule from $file.\n"; $return = system("cat -n $file\|grep \" $rule\""); if ($return != 0) {print "No such rule number($rule) in $file\n";exit;} else { print "Do you really want remove this entry? [y/n]"; $read_user = ; if ($read_user =~ /^y/i) {print "Deleting line \#$rule from $file...\n"; # print "Rule numbers has been changed, check \"$ARGV[0] list\" before any future \"del\"!\n"; del_line($rule,$file); make_clean($file);exit; } else {print "Don't fuck my mind!\n"; exit;} } } elsif ($from_word =~ /^deny$/i) {$file = $deny_file; print "Will delete line \#$rule from $file.\n"; $return = system("cat -n $file\|grep \" $rule\""); if ($return != 0) {print "No such rule number($rule) in $file\n";exit;} else { print "Do you really want remove this entry? [y/n]"; $read_user = ; if ($read_user =~ /^y/i) {print "Deleting line \#$rule from $file...\n"; # print "Rule numbers has been changed, check \"$ARGV[0] list\" before any future \"del\"!\n"; del_line($rule,$file); make_clean($file);exit; } else {print "Don't fuck my mind!\n"; exit;} } } else {print "Delete rule number $rule from what file?\n";} exit; } #Проверяем значения неизменяемых аргументов if (($from_word !~ /^from$/i)||($to_word !~ /^to$/i) ||(($action !~ /^add$/i)&&($action !~ /^del$/i)) ||(($direction !~ /^in$/i)&&($direction !~ /^out$/i)) ||(($rule !~ /^allow$/i)&&($rule !~ /^deny$/i)) ) { print "Wrong syntax, see example.\n"; exit; } #Проверям синтаксис вводимых пар From: To: if (($direction =~ /^in$/i)&&($to_user =~ /\@/) ||(($direction =~ /^out$/i)&&(($from_user =~ /\@/)&&($from_user !~ /^all$/))) ) { print "Error: Local user name shouldn't have \"\@\".\n"; exit; } if (($direction =~ /^out$/i)&&(($to_user !~ /\@/)&&($to_user !~ /^all$/)) ||(($direction =~ /^in$/i)&&($from_user !~ /\@/)) ) { print "Error: Remote user name should contain domain part with \@.\n"; exit; } #Выбираем с каким файлом будем работать в зависимости от выбранного правила allow/deny if ($rule =~ /^allow$/i) {$file = $allow_file;} else {$file = $deny_file;} #Преобразовуем правило allow/deny в верхний регистр $rule =~ tr/a-z/A-Z/; if ($direction =~ /^in$/i) { $from_user = addr_converter ($from_user); print "To:$to_user:$from_user\t\t$rule\n"; if ($action =~ /^add$/i) { print "We will write it to $file\n"; open(CONFIG,">> $file")|| die("Cannot Open File"); print (CONFIG "To:$to_user:$from_user\t\t$rule\n"); close(CONFIG);make_clean($file); } if ($action =~ /^del$/i) { print "We will try delete \"To:$to_user:$from_user\t\t$rule\" from $file\n"; # open(CONFIG, "$file")|| die("Cannot Open File"); @f=; close CONFIG; @f=read_file($file); open(CONFIG, "> $file"); $from_user =~ s/\/\\\>/; foreach $str (@f) { if ($str !~ /To:$to_user:$from_user\t\t$rule/) {print (CONFIG "$str"); } } close(CONFIG);make_clean($file); } } if ($direction =~ /^out$/i) { $to_user = addr_converter ($to_user); print "From:$from_user:$to_user\t\t$rule\n"; if ($action =~ /^add$/i) { print "We will write it to $file\n"; open(CONFIG,">> $file")|| die("Cannot Open File"); print (CONFIG "From:$from_user:$to_user\t\t$rule\n"); close(CONFIG);make_clean($file); } if ($action =~ /^del$/i) { print "We will try to delete \"From:$from_user:$to_user\t\t$rule\" from $file\n"; # open(CONFIG, "$file")|| die("Cannot Open File"); @f=; close CONFIG; @f=read_file($file); open(CONFIG, "> $file"); $to_user =~ s/\/\\\>/; foreach $str (@f) { if ($str !~ /From:$from_user:$to_user\t\t$rule/) {print (CONFIG "$str"); } } close(CONFIG);make_clean($file); } } #Проверяем синтаксис введенного email адреса или почтового домена #Преобразовуем email адрес в к виду user<@domain.ru> sub addr_converter { my ($email) = @_; if ($email =~ /^all$/) {return $email;} if ($email !~/\@(\w+)\.(\w+)/) { print "Wrong email syntax\n"; exit; } $email =~ s/\@/\<\@/; $email =~ s/$/\.\>/; return $email; } #Считываем файл в массив sub read_file { my ($f_name) = @_; open(FFF,"$f_name")|| die("Cannot Open File");@f = ;close(FFF); return @f; } #Удаляем строку с заданным номером из файла sub del_line { my ($line_num, $f_name) = @_; open(FFF,"$f_name")|| die("Cannot Open File");@f = ;close(FFF); splice(@f,$line_num-1,1); open(FFF,">$f_name") || die("Cannot Open File"); print FFF @f; close(FFF); } #Сортируем созданные файлы перед выходом, создаем hash для sendmail sub make_clean { my ($f_name) = @_; $tmp_name = "mailfw.tmp"; system("cat $f_name\|sort -t \: --key=2 -u\>$tmp_path\/$tmp_name\&\&cp $f_name $f_name.bak\;cat $tmp_path\/$tmp_name \> $f_name\&\&rm $tmp_path\/$tmp_name"); system("makemap hash $allow_file\<$allow_file\;makemap hash $deny_file\<$deny_file"); #print "Rule numbers has been CHANGED, check \"$0 list\" before any future \"del\"!\n"; }