Revise handling of "filename" directive element
authorJacob Bachmeyer <jcb@gnu.org>
Fri, 21 Oct 2022 02:29:20 +0000 (21:29 -0500)
committerJacob Bachmeyer <jcb@gnu.org>
Fri, 21 Oct 2022 02:29:20 +0000 (21:29 -0500)
All protocol versions so far imply an "install" command when a directive
is uploaded as part of a triplet.  This commit also adds infrastructure
to support a possible future explicit "install" command, removes a useless
validation of the packet stem against the directive file name, and cleans
up a now-unneeded variable that had been left as scaffolding.

gatekeeper.pl

index 3ac55860f196c8cc74f31f0fca430af4922be5d2..97e4b8edb8068beaa1d34f2ff6db9f2eff2558a9 100755 (executable)
@@ -1373,10 +1373,12 @@ sub interpret_directive {
 
   my %options = ( replace => undef );
   my %header = ( version => undef, options => \%options,
-                package => undef, directory => undef );
+                package => undef, directory => undef, filename => undef );
   my @ops = ([header => \%header]);
-  my $have_install = 0;        # can only install one file per directive
-  my $filename;
+  my $install = undef; # can only install one file per directive
+  # The 'install' op carries the name of the file to install, while the
+  # 'filename' element binds the directive signature to its intended
+  # upload.  These are assumed to be the same in protocol 1.2 and earlier.
   my $cnt = 0; # TODO: remove this
 
   {    # Extract version first, since directive elements may be in any order.
@@ -1417,9 +1419,9 @@ sub interpret_directive {
       # Only let them specify one filename directive.
       fatal("Only one filename directive is allowed per directive file. "
            ."Error at filename directive: $val.",1,$directive_file_contents)
-       if exists $info{"filename"};
+       if defined $header{filename};
 
-      $filename = $val;
+      $header{filename} = $val;
       $info{"filename"} = {"value" => $val, "order" => $cnt++};  # ok.
     } elsif ($tainted_cmd eq 'version') {
       # already handled above
@@ -1460,8 +1462,9 @@ sub interpret_directive {
            1,$directive_file_contents);
     }
 
-    if (!$have_install && $filename && defined $header{directory})
-      { push @ops, [install => $filename]; $have_install = 1 }
+    if (!defined($install)
+       && defined $header{filename} && defined $header{directory})
+      { push @ops, ($install = [install => $header{filename}]) }
   }
 
   return \@ops;
@@ -1619,12 +1622,8 @@ sub read_directive_file {
     }
   }
 
-  # The above check that the directive contains at least one command
-  # ensures that we either have a filename or do not need one before we
-  # reach this point.  This is temporarily kept as scaffolding.
-  my $filename_required = exists($info{filename});
-
-  if ($filename_required) {
+  # Check if this directive carries a file/validate stem if needed
+  if (defined $op_header->{filename}) {
     # Ben Pfaff <blp@cs.stanford.edu> wrote:
     # First, "gpg -b" doesn't verify that the filename of the signed
     # data is correct. This means that I can rename gcc-1.2.3.tar.gz
@@ -1632,20 +1631,15 @@ sub read_directive_file {
     # correctly. This opens up the possibility for confusion, but in
     # itself it's not a huge deal.
     #
-    # To fix this, we require a 'filename:' line in the directive file
-    # that needs to match the name of the uploaded file.
-
-    # Filename has to match the name of the uploaded file
+    # To fix this, we require a 'filename:' line in the directive file that
+    # needs to match the name of the uploaded file and serves to bind the
+    # directive signature and the uploaded packet.  We already know that
+    # the name of the uploaded file must match the stem of the directive
+    # file name; this is how it was recognized as part of the packet.
     fatal("The filename directive does not match name of the uploaded file."
-         ."\n\n  Filename directive: $info{filename}{value}"
-         ."\n  Uploaded file: $uploaded_file\n",1)
-      if ($uploaded_file ne $info{filename}{value});
-
-    # Filename has to match the name of this directive file (a bit
-    # paranoid, but hey...)
-    fatal("filename $info{filename}{value} does not match name of directive "
-         ."file $directive_file",1)
-      if ($directive_file ne "$info{filename}{value}.directive.asc");
+         ."\n\n  Filename directive: $op_header->{filename}"
+         ."\n  Uploaded file: $stem\n",1)
+      unless $stem eq $op_header->{filename};
   }
 
   my $retval = verify_keyring($directive_file,$directive_file_contents,
@@ -1655,7 +1649,7 @@ sub read_directive_file {
   # than the one for the last file that was uploaded
   # This is only relevant when a 'filename' directive is present, hence the
   # test of the $filename_required variable.
-  if (($retval =~ /Signature made (.*)/) && ($filename_required)) {
+  if (($retval =~ /Signature made (.*)/) && (exists($info{filename}))) {
     my $timestr = $1;
 
     ftp_syslog('debug', "DEBUG: Signature made $1") if DEBUG;
@@ -1692,7 +1686,7 @@ sub read_directive_file {
     $full_filename =~ s/\/\//\//g; # Just in case...
 
     advance_timestamp_ratchet($full_filename, $epoch);
-  } elsif ($filename_required) {
+  } elsif (exists($info{filename})) {
     fatal("gpg verification problem: could not extract timestamp",1);
   }