file descriptors in Perl-----I need to use gpg's "--passphrase-fd n" option
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
file descriptors in Perl-----I need to use gpg's "--passphrase-fd n" option
Hi:
I would like to use gpg to encrypt something from the standard input
inside a perl program:
system( <<stuff>> | gpg -c -o $OutputFilename - )
This works fine interactively.
I also need to run this in a cron job. How can I read a password
from a file (yes, I understand there are security risks in doing
this)? gpg's help file tells me that I can use a "file descriptor n"
to do this:
--passphrase-fd n
Read the passphrase from file descriptor n. If you
use 0 for n, the passphrase will be read from stdin.
This can only be used if only one passphrase is
supplied. Don't use this option if you can avoid it.
I've seen this simple example:
system( cat $HOME/.BadPassword | gpg -c -passphrase-fd 0 -o $OutputFilename - )
However, this will not work for me because my input comes from the
standard input. So it looks like I need to set up another file
descriptor (say, "3") for my password file:
system( <<stuff>> | gpg -c -passphrase-fd 3 -o $OutputFilename - )
How about something like the (untested) code fragment:
Code:
my $password = SomeObfuscationFunction();
open( ENCRYPTOR, "|gpg -c -o $OutputFilename -" ) || die "Cannot launch gpg : $!\n";
print ENCRYPTOR $password;
close ENCRYPTOR;
This launches the gpg program, with it's stdin piped to a perl file descriptor. You can then write to the file desciptor to send data to the child process's standard input.
Thanks for the suggestion, but it will not work for me because
some other process is using the standard input. Let me start
from scratch, filling in some of the details I left off the
first time:
For backup purposes, I tar certain files, burn to a DVD, and move
offsite. I would like to encrypt these files as well. Because these
tar'ed files are large (they fill a DVD), I would like to do both
operations simultaneously.
Suppose I have a directory called "cv". This command will tar and encrypt the directory:
tar cvvjf - cv 2>> cv.tar.log | gpg -ca -o cv.tar.bz2.asc -
This will decrypt and untar:
gpg -o - cv.tar.bz2.asc | tar xjvf -
This works great if I run them interactively---I am prompted for the
password each time. How do I get it to work in a (perl) script (so I can
have a cron job do this automatically when I am sleeping)? What
I cannot figure out is how to send a password (that resides in, say,
/password.txt) to gpg.
Here is a small Perl script that does not work:
open(PW, "/password.txt");
$filedescriptor=fileno(PW);
print ("filedescriptor=$filedescriptor\n");
print ("tar cvvjf - cv 2>> cv.tar.log | gpg -ca --passphrase-fd $filedescriptor -o cv.tar.bz2.asc -\n");
system("tar cvvjf - cv 2>> cv.tar.log | gpg -ca --passphrase-fd $filedescriptor -o cv.tar.bz2.asc -");
Here is the output from this program:
filedescriptor=3
tar cvvjf - cv 2>> cv.tar.log | gpg -ca --passphrase-fd 3 -o cv.tar.bz2.asc -
Reading passphrase from file descriptor 3 ...
The program just hangs there. If I type something ("foo"), then that
is used as the password! Why does gpg report that it is reading from
file descriptor 3 when in fact it reads from the standard input (#=0)?
The password file is just one word ("foo"). I've tried ending
(and not ending) the line with a newline.
Any thoughts on this?
Is there a better way to solve my problem (tar and encrypt in a script)?
Is there no way to have the gpg program read from a file (I scanned the manpage quickly, but didn't see a definitive answer)? If yes, then you would have file descriptor 0 available to pipe your passphrase to gpg, while reading the encryption data from the specified file. This is inherently unsecure, so perhaps it isn't possible.
By inspection, it looks like your approach should work. I guess I would start by writing some short code stub in C which reads from a specified file descriptor, and echoes everything it reads to standard out. Use that to replace the gpg tool, for diagnostic puposes. This lets you test whether the problem is with the perl or the gpg side of the issue. If you aren't C literate enough to do this, I can probably help you out there.
The perl system() function can be replaced with discrete components: fork(), exec(), wait...
Perhaps using these separately will either solve the problem, or reveal a solution.
I had the same problem. That perl was closing my file descriptor when calling system. Perl set close-on-open flag on all file descriptors or uses $SYSTEM_FD_MAX.
I used the following code to get it to work.
Code:
use POSIX;
use Fcntl qw/ :mode /;
....
fcntl (PWFILE,F_SETFD,0);
my $fd=fileno PWFILE;
my $cmd="sshpass -d$fd ssh thansen ls";
#system($cmd);
open (CMD,"$cmd|") or die "failed cmd:$cmd";
while(<CMD>) {
print $_;
}
If exec is specified without command or arguments, and any file descriptors with numbers greater than 2 are opened with associated redirection statements, it is unspecified whether those file descriptors remain open when the shell invokes another utility. Scripts concerned that child shells could misuse open file descriptors can always close them explicitly, as shown in one of the following examples.
why don't you just put the pipeline you
gave in a shell script for the cron job.
try:
Code:
exec 7<passwd
gpg -c -passphrase-fd 7
oops, didn't see the previous post, fcntl may work
but why use perl to call a shell pipeline?
Last edited by bigearsbilly; 02-25-2011 at 09:58 AM.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.