14 use Time
::HiRes qw
(gettimeofday
);
25 my $msg = shift || '';
33 return $dbh->last_insert_id(
34 undef, undef, undef, undef, { sequence
=> $seq});
38 my ($filename, $lasttime) = @_;
40 my $st = stat($filename);
42 return 0 if !defined($st);
44 return ($lasttime >= $st->ctime);
47 sub extract_filename
{
50 if (my $value = $head->recommended_filename()) {
52 if (my $decvalue = MIME
::Words
::decode_mimewords
($value)) {
53 $decvalue =~ s/\0/ /g;
54 $decvalue = PVE
::Tools
::trim
($decvalue);
63 my ($entity, $add_id, $id) = @_;
67 foreach my $tag (grep {/^x-proxmox-tmp/i} $entity->head->tags) {
68 $entity->head->delete ($tag);
71 $entity->head->replace('X-Proxmox-tmp-AID', $id) if $add_id;
73 foreach my $part ($entity->parts) {
74 $id = remove_marks
($part, $add_id, $id + 1);
85 foreach my $k (keys %$dh) {
88 $body =~ s/__${k}__/$v/gs;
96 my ($entity, $sender, $targets, $xforward, $me, $nodsn) = @_;
104 my $smtp = Net
::SMTP-
>new('127.0.0.1', Port
=> 10025, Hello
=> $me) ||
105 die "unable to connect to localhost at port 10025";
107 if (defined($xforward)) {
110 foreach my $attr (keys %{$xforward}) {
111 $xfwd .= " $attr=$xforward->{$attr}";
114 if ($xfwd && $smtp->command("XFORWARD", $xfwd)->response() != CMD_OK
) {
115 syslog
('err', "xforward error - got: %s %s", $smtp->code, scalar($smtp->message));
119 if (!$smtp->mail($sender)) {
120 syslog
('err', "smtp error - got: %s %s", $smtp->code, scalar ($smtp->message));
121 die "smtp from: ERROR";
124 my $dsnopts = $nodsn ?
{Notify
=> ['NEVER']} : {};
126 if (!$smtp->to (@$targets, $dsnopts)) {
127 syslog
('err', "smtp error - got: %s %s", $smtp->code, scalar($smtp->message));
128 die "smtp to: ERROR";
132 #$entity->sync_headers ();
135 my $out = PMG
::SMTPPrinter-
>new($smtp);
136 $entity->print($out);
138 # make sure we always have a newline at the end of the mail
139 # else dataend() fails
140 $smtp->datasend("\n");
142 if ($smtp->dataend()) {
143 my @msgs = $smtp->message;
144 $resmess = $msgs[$#msgs];
145 ($resid) = $resmess =~ m/Ok: queued as ([0-9A-Z]+)/;
146 $rescode = $smtp->code;
148 die sprintf("unexpected SMTP result - got: %s %s : WARNING", $smtp->code, $resmess);
151 my @msgs = $smtp->message;
152 $resmess = $msgs[$#msgs];
153 $rescode = $smtp->code;
154 die sprintf("sending data failed - got: %s %s : ERROR", $smtp->code, $resmess);
159 $smtp->quit if $smtp;
162 syslog
('err', $err);
165 return wantarray ?
($resid, $rescode, $resmess) : $resid;
168 sub analyze_virus_clam
{
169 my ($queue, $dname, $pmg_cfg) = @_;
174 my $clamdscan_opts = "--stdout";
176 my ($csec, $usec) = gettimeofday
();
182 $previous_alarm = alarm($timeout);
185 die "$queue->{logid}: Maximum time ($timeout sec) exceeded. " .
186 "virus analyze (clamav) failed: ERROR";
189 open(CMD
, "/usr/bin/clamdscan $clamdscan_opts '$dname'|") ||
190 die "$queue->{logid}: can't exec clamdscan: $! : ERROR";
196 if (m/^$dname.*:\s+([^ :]*)\s+FOUND$/) {
197 # we just use the first detected virus name
198 $vinfo = $1 if !$vinfo;
200 if (m/^Infected files:\s(\d*)$/i) {
209 alarm(0); # avoid race conditions
211 if (!defined($ifiles)) {
212 die "$queue->{logid}: got undefined output from " .
213 "virus detector: $res : ERROR";
217 syslog
('info', "$queue->{logid}: virus detected: $vinfo (clamav)");
222 alarm($previous_alarm);
224 my ($csec_end, $usec_end) = gettimeofday
();
225 $queue->{ptime_clam
} =
226 int (($csec_end-$csec)*1000 + ($usec_end - $usec)/1000);
229 syslog
('err', $err);
231 $queue->{errors
} = 1;
234 $queue->{vinfo_clam
} = $vinfo;
236 return $vinfo ?
"$vinfo (clamav)" : undef;
240 my ($queue, $filename, $pmg_cfg, $testmode) = @_;
242 # TODO: support other virus scanners?
244 # always scan with clamav
245 return analyze_virus_clam
($queue, $filename, $pmg_cfg);
248 sub magic_mime_type_for_file
{
251 # we do not use get_mime_type_for_file, because that considers
252 # filename extensions - we only want magic type detection
254 my $bufsize = Xdgmime
::xdg_mime_get_max_buffer_extents
();
255 die "got strange value for max_buffer_extents" if $bufsize > 4096*10;
257 my $ct = "application/octet-stream";
259 my $fh = IO
::File-
>new("<$filename") ||
260 die "unable to open file '$filename' - $!";
263 if (($len = $fh->read($buf, $bufsize)) > 0) {
264 $ct = xdg_mime_get_mime_type_for_data
($buf, $len);
268 die "unable to read file '$filename' - $!" if ($len < 0);
276 if (my $path = $entity->{PMX_decoded_path
}) {
278 # set a reasonable default if magic does not give a result
279 $entity->{PMX_magic_ct
} = $entity->head->mime_attr('content-type');
281 if (my $ct = magic_mime_type_for_file
($path)) {
282 if ($ct ne 'application/octet-stream' || !$entity->{PMX_magic_ct
}) {
283 $entity->{PMX_magic_ct
} = $ct;
287 my $filename = $entity->head->recommended_filename;
288 $filename = basename
($path) if !defined($filename) || $filename eq '';
290 if (my $ct = xdg_mime_get_mime_type_from_file_name
($filename)) {
291 $entity->{PMX_glob_ct
} = $ct;
295 foreach my $part ($entity->parts) {
296 add_ct_marks
($part);
300 sub rewrite_config_file
{
301 my ($pmg_cfg, $tmplname, $dstfn) = @_;
303 my $demo = $pmg_cfg->get('administration', 'demo');
305 my $srcfn = ($tmplname =~ m
|^.?
/|) ? $tmplname : "/var
/lib/pmg/templates/$tmplname";
309 my $demosrc = "$srcfn.demo
";
310 $srcfn = $demosrc if -f $demosrc;
314 my $srcfd = IO::File->new ($srcfn, "r
")
315 || die "cant
read template
'$srcfn' - $!: ERROR
";
316 my $dstfd = PMG::AtomicFile->open ($dstfn, "w
")
317 || die "cant
open config file
'$dstfn' - $!: ERROR
";
319 if ($dstfn eq '/etc/fetchmailrc') {
320 my ($login, $pass, $uid, $gid) = getpwnam('fetchmail');
322 chown($uid, $gid, ${*$dstfd}{'io_atomicfile_temp'});
324 chmod (0600, ${*$dstfd}{'io_atomicfile_temp'});
325 } elsif ($dstfn eq '/etc/clamav/freshclam.conf') {
326 # needed if file contains a HTTPProxyPasswort
328 my $uid = getpwnam('clamav');
329 my $gid = getgrnam('adm');
332 chown ($uid, $gid, ${*$dstfd}{'io_atomicfile_temp'});
334 chmod (0600, ${*$dstfd}{'io_atomicfile_temp'});
337 my $template = Template->new({});
339 my $vars = { pmg => $pmg_cfg->get_config() };
341 $template->process($srcfd, $vars, $dstfd) ||
342 die $template->error();
348 sub rewrite_config_script {
349 my ($pmg_cfg, $tmplname, $dstfn) = @_;
351 rewrite_config_file($pmg_cfg, $tmplname, $dstfn);
352 system("chmod +x
$dstfn");