Add initial shared directive-reading functions
authorJacob Bachmeyer <jcb@gnu.org>
Sat, 8 Oct 2022 03:45:23 +0000 (22:45 -0500)
committerJacob Bachmeyer <jcb@gnu.org>
Sat, 8 Oct 2022 03:45:23 +0000 (22:45 -0500)
gatekeeper.pl

index ae078e226bfbb878d32ac50f2ad29e016a12247c..69e00812e0d92d5c3e5b80e1873b2dfa5e2cbbc5 100755 (executable)
@@ -731,6 +731,81 @@ sub fatal {
   ftp_die("(in $cwd) $msg",$exit_code);
 }
 
+\f
+#
+# - Directive reader
+#
+
+=item $directive = read_directive ( $handle )
+
+Read a PGP-clearsigned directive from the provided handle, which must be
+open for reading.  The handle is assumed to be positioned at the start of
+the file.  This function will search for the PGP header and stop reading at
+the signature.
+
+The return value is an arrayref of key/value arrayrefs representing the
+directive elements in the first PGP-clearsigned message found while reading
+from HANDLE.  The values in the returned structure are tainted.
+
+=cut
+
+sub read_directive {
+  my $directive = shift;
+
+  local *_;
+  my @records = ();
+
+  # First, we find the PGP signature header.
+  while (<$directive>) {
+    chomp; s/\r+$//;   # remove line ending, including DOS type
+    last if m/^-----BEGIN PGP SIGNED MESSAGE-----$/;
+  }
+  # We are now in the armor headers.
+  while (<$directive>) {
+    chomp; s/\r+$//;   # remove line ending, including DOS type
+    # According to RFC4880, there must be exactly one empty line to
+    # separate the signed message from the armor headers.
+    last if m/^$/;
+  }
+  # We are now looking at the signed message text.
+  while (<$directive>) {
+    chomp; s/\r+$//;   # remove line ending, including DOS type
+    s/^\s+//; s/\s+$//;        # trim leading and trailing whitespace
+
+    last if m/^-----BEGIN PGP SIGNATURE-----$/;
+
+    unless (/^$/) {    # ignore blank lines
+      push @records, [split /\s+/,$_,2];
+      $records[-1][0] =~ s/\s*:$//; # trim trailing colon on key
+    }
+  }
+  # That is all:  we have reached the signature and are done.
+  return \@records;
+}
+
+=item $directive = read_directive_from_file ( $filename )
+
+Read a PGP-clearsigned directive file and return an arrayref of key/value
+pair arrayrefs representing the directive elements in the signed portion of
+the file FILENAME.  Any text in the file not within the first clearsigned
+message is ignored.
+
+The values returned from this procedure are tainted.
+
+=cut
+
+sub read_directive_from_file {
+  my $filename = shift;
+
+  open my $handle, '<', $filename
+    or die "open($filename) failed: $!";
+  my $records = read_directive($handle);
+  close $handle
+    or die "close($filename) failed: $!";
+
+  return $records;
+}
+
 \f
 #
 # - [SC] Scan for incoming packets