Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I'm trying to write a Perl program that runs a PGP command (using NAI's e-business server) to add a key to my keyring. If the key already exists on the keyring, then the PGP command will fail with an error message. Otherwise it is added, but I need to confirm this with a carriage return (I can't seem to override this with PGP settings despite instructions in the manual...)

So basically I need to write (a carriage return) to STDIN and capture STDOUT or STDERR of the command.

I'm using Open3 and so far I can read from STOUT and STDERR but can't write to STDIN, so everytime I run my program I have to press return myself - but I eventually want to run this as a CGI script...

Here's my code:
#/usr/bin/perl # program to test open3() # module imports use strict; use warnings; use diagnostics; use IPC::Open3; use IO::Handle; use FileHandle (); # variable declarations my $pid; my $pid2; my @errors; my @output; my $pgp_command = "pgp --key-add temp_pgp_key.asc --with-private"; open (OUTPUT, ">&STDOUT") # output sent directly or die "Can't dup STDOUT to OUTPUT: $!\n"; open (ERROR, ">&STDERR") # error sent directly or die "Can't dup STDERR to ERROR: $!\n"; eval { $pid = open3(\*INPUT, \*OUTPUT, \*ERROR, $pgp_command) or die "could not run pgp command : $pgp_command : $!"; print INPUT "\n"; # wait for child to terminate with PID -1 but not in non-blocking m +ode? $pid2 = waitpid(-1,0); }; $@ && die "ERROR: $@\n"; # EVAL_ERROR print "process id : " . $pid . "\n"; print "exit value \$? : " . $? . "\n"; print "pid2 : " . $pid2 . "\n"; @output = <OUTPUT> or @errors = <ERROR> or die "Could not get response from PGP command : $pgp_command : +$!"; foreach (@output) { print "output " . $_ . "\n"}; foreach (@errors) { print "error " . $_ . "\n"}; close INPUT; close OUTPUT; close ERROR;
Can you help? Thanks,
Andrew

Replies are listed 'Best First'.
Re: Open3 with STDIN STDOUT and STDERR
by BrowserUk (Patriarch) on Sep 12, 2002 at 10:26 UTC

    PGP is probably using direct access to the keyboard buffer, thereby bypassing STDIN.

    The easiest way to verify this would be to create a file with nothing but a few (2-3) newlines in it and the pipe the file to the program on the command line. eg.

    pgp --key-add temp_pgp_key.asc --with-private < nl.dat

    If the program still pauses and waits for you to press return, it is bypassing STDIN (using getc() or similar) and your attempts to feed it a newline from within Perl are destined to fail.

    Maybe one of the other monks knows a way around this.

    If this is the case, it is quite possibly done deliberately so as to prevent your keyring being compromised by malicious software. If true, unless the program has an override for this feature, you may not be able to achieve your aim.


    Well It's better than the Abottoire, but Yorkshire!
      You're right - that command doesn't work either.

      Does anyone have any idea how to get round this?

      Andrew
Re: Open3 with STDIN STDOUT and STDERR
by fglock (Vicar) on Sep 12, 2002 at 13:28 UTC

    You could try using GPG. It doesn't have this problem AFAIK (I use it with open3). You must set appropriate cipher, etc for PGP compatibility. See also open3 + mod_perl.

      Unfortunately using GPG isn't an option - I've looked into GPG/PGP compatibility issues and we don't really have enough time to work them out.

      Anyone any other suggestions or is this a security measure that can't be overcome?

      Thanks,
      Andrew
Re: Open3 with STDIN STDOUT and STDERR
by greenFox (Vicar) on Sep 13, 2002 at 02:39 UTC
    This probably won't solve your problem but I don't think you need to explicitly open STDOUT & STDERR with IPC::Open3, I haven't used pgp but aside from a problem with pgp accepting the input (as BrowserUk showed) this should also work and is a bit simpler-
    # example open3() code only my $pgp_command = "pgp --key-add temp_pgp_key.asc --with-private"; open3(*PGP_IN, *PGP_OUT, *ERROR, $pgp_command); print PGP_IN "\n"; close(PGP_IN); my @return = <PGP_OUT>; close(PGP_OUT); my @error=<ERROR>; close(ERROR);

    --
    Until you've lost your reputation, you never realize what a burden it was or what freedom really is. -Margaret Mitchell