X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=tools%2Fdebianqueued-0.9%2Fdebianqueued;h=4fe899a03432b578e081802460a96c732e2b26d1;hb=d3b91e7ec18eda0646d19c81228997b2adfa31f2;hp=f9974366950bf075937946fed73117c0c15ad55b;hpb=40908ec831933a46339b740e0371f4fccbf7adb9;p=dak.git diff --git a/tools/debianqueued-0.9/debianqueued b/tools/debianqueued-0.9/debianqueued index f9974366..4fe899a0 100755 --- a/tools/debianqueued-0.9/debianqueued +++ b/tools/debianqueued-0.9/debianqueued @@ -22,6 +22,10 @@ use Net::FTP; use Socket qw( PF_INET AF_INET SOCK_STREAM ); use Config; use Sys::Hostname; +use File::Copy; +use Digest::MD5; + +setlocale(&POSIX::LC_ALL, "C"); # --------------------------------------------------------------------------- # configuration @@ -56,6 +60,7 @@ $junk = @conf::test_binaries; $junk = @conf::maintainer_mail; $junk = @conf::targetdir_delayed; $junk = $conf::mail ||= '/usr/sbin/sendmail'; +$junk = $conf::overridemail; $conf::target = "localhost" if $conf::upload_method eq "copy"; package main; @@ -65,6 +70,8 @@ package main; ($main::hostname, undef, undef, undef, undef) = gethostbyname(hostname()); my %packages = (); +my $re_file_safe_prefix = qr/\A([a-zA-Z0-9][a-zA-Z0-9_.:~+-]*)/s; +my $re_file_safe = qr/$re_file_safe_prefix\z/s; # extract -r and -k args $main::arg = ""; @@ -233,7 +240,6 @@ sub check_incoming_writable(); sub rm(@); sub md5sum($); sub is_debian_file($); -sub get_maintainer($); sub debian_file_stem($); sub msg($@); sub debug(@); @@ -383,7 +389,7 @@ while (1) { # ping target only if there is the possibility that we'll contact it (but # also don't wait too long). - my @have_changes = <*.changes *.commands>; + my @have_changes = <*.changes *.commands *.dak-commands>; for ( my $delayed_dirs = 0 ; $delayed_dirs <= $conf::max_delayed ; $delayed_dirs++ ) @@ -483,7 +489,7 @@ sub check_dir() { return ); - # look for *.commands files but not in delayed queues + # look for *.commands and *.dak-commands files but not in delayed queues if ( $adelay == -1 ) { foreach $file (<*.commands>) { init_mail($file); @@ -494,6 +500,15 @@ sub check_dir() { write_status_file() if $conf::statusdelay; finish_mail(); } ## end foreach $file (<*.commands>) + foreach $file (<*.dak-commands>) { + init_mail($file); + block_signals(); + process_dak_commands($file); + unblock_signals(); + $main::dstat = "c"; + write_status_file() if $conf::statusdelay; + finish_mail(); + } } ## end if ( $adelay == -1 ) opendir( INC, "." ) or ( @@ -554,86 +569,6 @@ sub check_dir() { msg( "log", "Deleted stray file ${main::current_incoming_short}/$file\n" ) if rm($file); - } elsif ( - $age > $conf::no_changes_timeout - && is_debian_file($file) - && - - # not already reported - !( $stats[ST_MODE] & S_ISGID ) - && ( $pattern = debian_file_stem($file) ) - && ( @job_files = glob($pattern) ) - && - - # If a .changes is in the list, it has the same stem as the - # found file (probably a .orig.tar.gz). Don't report in this - # case. - !( grep( /\.changes$/, @job_files ) ) - ) - { - $maint = get_maintainer($file); - - # Don't send a mail if this looks like the recompilation of a - # package for a non-i386 arch. For those, the maintainer field is - # useless :-( - if ( !grep( /(\.dsc|_(i386|all)\.deb)$/, @job_files ) ) { - msg( "log", "Found an upload without .changes and with no ", - ".dsc file\n" ); - msg( "log", - "Not sending a report, because probably ", - "recompilation job\n" ); - } elsif ($maint) { - init_mail(); - $main::mail_addr = $maint; - $main::mail_addr = $1 if $main::mail_addr =~ /<([^>]*)>/; - $main::mail_subject = - "Incomplete upload found in " . "Debian upload queue"; - msg( - "mail", - "Probably you are the uploader of the following " - . "file(s) in\n" - ); - msg( "mail", "the Debian upload queue directory:\n " ); - msg( "mail", join( "\n ", @job_files ), "\n" ); - msg( - "mail", - "This looks like an upload, but a .changes file " - . "is missing, so the job\n" - ); - msg( "mail", "cannot be processed.\n\n" ); - msg( - "mail", - "If no .changes file arrives within ", - print_time( $conf::stray_remove_timeout - $age ), - ", the files will be deleted.\n\n" - ); - msg( - "mail", - "If you didn't upload those files, please just " - . "ignore this message.\n" - ); - finish_mail(); - msg( - "log", - "Sending problem report for an upload without a " - . ".changes\n" - ); - msg( "log", "Maintainer: $maint\n" ); - } else { - msg( - "log", - "Found an upload without .changes, but can't " - . "find a maintainer address\n" - ); - } ## end else [ if ( !grep( /(\.dsc|_(i386|all)\.deb)$/... - msg( "log", "Files: @job_files\n" ); - - # remember we already have sent a mail regarding this file - foreach (@job_files) { - my @st = stat($_); - next if !@st; # file may have disappeared in the meantime - chmod +( $st[ST_MODE] |= S_ISGID ), $_; - } } else { debug( "found stray file ${main::current_incoming_short}/$file, deleting in ", @@ -667,7 +602,7 @@ outer_loop: while () { # forbid shell meta chars in the name, we pass it to a # subshell several times... - $field[5] =~ /^([a-zA-Z0-9.+_:@=%-][~a-zA-Z0-9.+_:@=%-]*)/; + $field[5] =~ /$re_file_safe/; if ( $1 ne $field[5] ) { msg( "log", "found suspicious filename $field[5]\n" ); next; @@ -690,7 +625,7 @@ sub process_changes($\@) { $pgplines, @files, @filenames, @changes_stats, $failure_file, $retries, $last_retry, $upload_time, $file, $do_report, $ls_l, $problems_reported, - $errs, $pkgname, $signator + $errs, $pkgname, $signator, $extralines ); local (*CHANGES); local (*FAILS); @@ -707,12 +642,19 @@ sub process_changes($\@) { open( CHANGES, "<$changes" ) or die "Cannot open ${main::current_incoming_short}/$changes: $!\n"; $pgplines = 0; + $extralines = 0; $main::mail_addr = ""; @files = (); outer_loop: while () { if (/^---+(BEGIN|END) PGP .*---+$/) { ++$pgplines; - } elsif (/^Maintainer:\s*/i) { + next; + } + if ( $pgplines < 1 or $pgplines >= 3 ) { + $extralines++ if length $_ > 1; + next; + } + if (/^Maintainer:\s*/i) { chomp( $main::mail_addr = $' ); $main::mail_addr = $1 if $main::mail_addr =~ /<([^>]*)>/; } elsif (/^Source:\s*/i) { @@ -727,7 +669,7 @@ outer_loop: while () { # forbid shell meta chars in the name, we pass it to a # subshell several times... - $field[5] =~ /^([a-zA-Z0-9.+_:@=%-][~a-zA-Z0-9.+_:@=%-]*)/; + $field[5] =~ /$re_file_safe/; if ( $1 ne $field[5] ) { msg( "log", "found suspicious filename $field[5]\n" ); msg( @@ -758,6 +700,12 @@ outer_loop: while () { @$keep_list = @filenames; # some consistency checks + if ( $extralines ) { + msg( "log,mail", +"$main::current_incoming_short/$changes contained lines outside the pgp signed " +."part, cannot process\n" ); + goto remove_only_changes; + } ## end if ( $extralines ) if ( !$main::mail_addr ) { msg( "log,mail", "$main::current_incoming_short/$changes doesn't contain a Maintainer: field; " @@ -1100,6 +1048,55 @@ outer_loop: while () { #} } ## end sub process_changes($\@) +# +# process one .dak-commands file +# +sub process_dak_commands { + my $commands = shift; + + msg("log", "processing ${main::current_incoming_short}/$commands\n"); + + # TODO: get mail address from signed contents + # and NOT implement a third parser for armored PGP... + $main::mail_addr = undef; + + # check signature + my $signator = pgp_check($commands); + if (!$signator) { + msg("log,mail", + "$main::current_incoming_short/$commands has bad PGP/GnuPG signature!\n"); + msg("log,mail", + "Removing $main::current_incoming_short/$commands\n"); + rm($commands); + return; + } + elsif ($signator eq 'LOCAL ERROR') { + debug("Can't check signature for $main::current_incoming_short/$commands -- don't process it for now"); + return; + } + msg("log,mail", "(PGP/GnuPG signature by $signator)\n"); + + # check target + my @filenames = ($commands); + if (my $ls_l = is_on_target($commands, @filenames)) { + msg("log,mail", "$main::current_incoming_short/$commands is already present on target host:\n"); + msg("log,mail", "$ls_l\n"); + msg("log,mail", "Job $commands removed.\n"); + rm($commands); + return; + } + + if (!copy_to_target($commands)) { + msg("log,mail", "$commands couldn't be uploaded to target.\n"); + msg("log,mail", "Giving up and removing it.\n"); + rm($commands); + return; + } + + rm($commands); + msg("mail", "$commands uploaded successfully to $conf::target\n"); +} + # # process one .commands file # @@ -1209,7 +1206,9 @@ outer_loop: while () { $selecteddelayed = $1; s,^DELAYED/[0-9]+-day/,,; } - if ( $origword eq "--searchdirs" ) { + if (m,(^|/)\*,) { + msg("mail,log", "$_: filename component cannot start with a wildcard\n"); + } elsif ( $origword eq "--searchdirs" ) { $selecteddelayed = -2; } elsif (m,/,) { msg( @@ -1316,8 +1315,8 @@ outer_loop: while () { if ( $afile =~ m/\.changes$/ ) { utime undef, undef, ("$dir/$afile"); } - if ( !rename "$dir/$afile", "$target_dir/$afile" ) { - msg( "mail,log", "rename: $!\n" ); + if ( !move("$dir/$afile", "$target_dir/$afile") ) { + msg( "mail,log", "move: $!\n" ); } else { msg( "mail,log", "$afile moved to $target_delay-day\n" ); } @@ -1330,7 +1329,7 @@ outer_loop: while () { } elsif ( $conf::upload_method ne "copy" ) { msg( "mail,log", "cancel not available\n" ); } elsif ( - $word[1] !~ m,^[a-zA-Z0-9.+_:@=%-][~a-zA-Z0-9.+_:@=%-]*\.changes$, ) + $word[1] !~ m,$re_file_safe_prefix.changes\z, ) { msg( "mail,log", "argument to cancel must be one .changes filename without path\n" ); @@ -1387,8 +1386,8 @@ sub age_delayed_queues() { my @thesefiles = ( $achanges =~ m,.*/([^/]*), ); push( @thesefiles, get_filelist_from_known_good_changes($achanges) ); for my $afile (@thesefiles) { - if ( !rename "$dir/$afile", "$target_dir/$afile" ) { - msg( "log", "rename: $!\n" ); + if ( !move("$dir/$afile", "$target_dir/$afile") ) { + msg( "log", "move: $!\n" ); } else { msg( "log", "$afile moved to $target_dir\n" ); } @@ -1631,6 +1630,13 @@ sub pgp_check($) { my $stat; local (*PIPE); + if ($file =~ /$re_file_safe/) { + $file = $1; + } else { + msg( "log", "Tainted filename, skipping: $file\n" ); + return "LOCAL ERROR"; + } + $stat = 1; if ( -x $conf::gpg ) { debug( "executing $conf::gpg --no-options --batch " @@ -2126,14 +2132,12 @@ sub rm(@) { # sub md5sum($) { my $file = shift; - my $line; - - chomp( $line = `$conf::md5sum $file` ); - debug( "md5sum($file): ", - $? ? "exit status $?" - : $line =~ /^(\S+)/ ? $1 - : "match failed" ); - return $? ? "" : $line =~ /^(\S+)/ ? $1 : ""; + + open my $fh, "<", $file or return ""; + my $md5 = $md5->addfile($fh); + close $fh; + + return $md5->hexdigest; } ## end sub md5sum($) # @@ -2145,67 +2149,6 @@ sub is_debian_file($) { && $file !~ /\.orig\.tar\.gz/; } -# -# try to extract maintainer email address from some a non-.changes file -# return "" if not possible -# -sub get_maintainer($) { - my $file = shift; - my $maintainer = ""; - local (*F); - - if ( $file =~ /\.diff\.gz$/ ) { - - # parse a diff - open( F, "$conf::gzip -dc '$file' 2>/dev/null |" ) or return ""; - while () { - - # look for header line of a file */debian/control - last if m,^\+\+\+\s+[^/]+/debian/control(\s+|$),; - } - while () { - last if /^---/; # end of control file patch, no Maintainer: found - # inside control file patch look for Maintainer: field - $maintainer = $1, last if /^\+Maintainer:\s*(.*)$/i; - } - while () { } # read to end of file to avoid broken pipe - close(F) or return ""; - } elsif ( $file =~ /\.(deb|dsc|tar\.gz)$/ ) { - if ( $file =~ /\.deb$/ && $conf::ar ) { - - # extract control.tar.gz from .deb with ar, then let tar extract - # the control file itself - open( F, - "($conf::ar p '$file' control.tar.gz | " - . "$conf::tar -xOf - " - . "--use-compress-program $conf::gzip " - . "control) 2>/dev/null |" - ) or return ""; - } elsif ( $file =~ /\.dsc$/ ) { - - # just do a plain grep - debug("get_maint: .dsc, no cmd"); - open( F, "<$file" ) or return ""; - } elsif ( $file =~ /\.tar\.gz$/ ) { - - # let tar extract a file */debian/control - open( F, - "$conf::tar -xOf '$file' " - . "--use-compress-program $conf::gzip " - . "\\*/debian/control 2>&1 |" - ) or return ""; - } else { - return ""; - } - while () { - $maintainer = $1, last if /^Maintainer:\s*(.*)$/i; - } - close(F) or return ""; - } ## end elsif ( $file =~ /\.(deb|dsc|tar\.gz)$/) - - return $maintainer; -} ## end sub get_maintainer($) - # # return a pattern that matches all files that probably belong to one job # @@ -2325,14 +2268,19 @@ sub send_mail($$$) { $Email::Send::Sendmail::SENDMAIL = $conf::mail; } + if ($conf::overridemail) { + $addr = $conf::overridemail; + } + my $date = sprintf "%s", strftime( "%a, %d %b %Y %T %z", ( localtime(time) ) ); my $message = <<__MESSAGE__; To: $addr -From: Archive Administrator +From: Debian FTP Masters Subject: $subject Date: $date X-Debian: DAK +X-DAK: DAK __MESSAGE__ if ( length $package ) {