Networker

Re: [Networker] Still can't do this in Perl

2004-11-26 17:16:48
Subject: Re: [Networker] Still can't do this in Perl
From: George Sinclair <George.Sinclair AT NOAA DOT GOV>
To: NETWORKER AT LISTMAIL.TEMPLE DOT EDU
Date: Fri, 26 Nov 2004 17:19:32 -0500
Okay, I tried suggested code, but with taint mode turned on as shown
below and invoked as: 'script.pl name client'.
I have a question, though, about how to NOT invoke shell (security) as
discussed further down, but I may be confused on this issue.

#!/usr/bin/perl -wT
use strict;

$ENV{PATH} = '/usr/sbin';
my $name=$ARGV[0];
my $type=$ARGV[1];

use IPC::Open2;
my $pid = open2(\*RDRFH, \*WTRFH, "nsradmin -s orion -i -");

# send some commands to nsradmin.
print WTRFH "show $name\n";
print WTRFH "print type:NSR $type\n";
close WTRFH;

# get the results.
my @output = <RDRFH>;

print @output;

This code works fine, BUT as the values that will be passed to the
nsradmin program will come from outside the script, I was nervous about
leaving it this way. If this is okay, then it's really more on principle
as I like to get in the habit of safely coding wherever possible,
although some assumptions are always made. Typically, in past I have
built a list variable (@args) that would contain the command and
necessary arguments, maybe something like: @args = ("$command", "$arg1",
"$arg2") or whatever

and then used 'exec' on the list so as to avoid shell, something like:

$result = open(CHILD, "-|");
die "Couldn't open pipe to subprocess" unless defined($result);
exec(@args) or die "Can't exec @args: $!" if ($result == 0);
while(<CHILD>)
{
   # Process stuff here.
}
close(CHILD);

Again, the reason I'm doing this is that running 'exec' with arguments
as a list safely bypasses shell so it's safer? Could use 'system' but
then can't capture output. But, 'exec' with fork (CHILD) allows me to
read the output. Anyway, not sure how to use this technique with 'open2'
in this case as I need to read and write? How can I do this safely? Can
or should 'exec' even be implemented here? Maybe something else?

I just haven't had a need before to BOTH write and read to same file
handle wherein variables passed to command were defined from outside
script, so this is a little unique and just wanted to be as cautious as
I can reasonably be. I don't want to invoke the shell.

Appreciate any feedback or suggestions.

Thanks.

George

Darren Dunham wrote:
>
> > #!/usr/bin/perl
> >
> > # Begin fix
> > $result = open(CHILD, "-|");
> > # End fix
>
> > die "Couldn't open pipe to subprocess" unless defined($result);
> > open (ADM, "|/usr/sbin/nsradmin -s server") or
> >    die "Couldn't open pipe to nsradmin.\n";
>
> Umm, that is *NOT* the way I would write that.  You're forking off a
> child, but you give no indication that you're running multiple threads
> in here.  Becuase you don't run a conditional on the $result, you're
> running nsradmin twice!  Once in the parent, and again in the child.
>
> Why are you doing this?
>
> When you run this program, don't you get warnings and errors?  I do when
> I try it...
>
> $ perl -w /tmp/perl2
> Use of uninitialized value at /tmp/perl2 line 11.
> Use of uninitialized value at /tmp/perl2 line 11.
> Read on closed filehandle <CHILD> at /tmp/perl2 line 15.
> Use of uninitialized value at /tmp/perl2 line 11.
> Use of uninitialized value at /tmp/perl2 line 11.
>                         type: NSR;
>                         [....]
>
> > print ADM "print type: NSR $ARGV[0]; name: $ARGV[1]\n";
> > close ADM;
> >
> > # Begin fix
> > while(<CHILD>)
> > {
> >   push @list, $_;
> > }
> > close(CHILD);
> >
> > foreach (@list)
> > {
> >    print $_;
> > }
> > # End fix
> >
> > NOTES: A couple of things here. What was throwing me off was the fact
> > that I had "|/usr/sbin/nsradmin -s server -i")
> > and as a result, it was expecting a file to be passed in.
>
> I think all of our examples use '-i -'.  By specifying the file as "-",
> it reads from stdin.
>
> > Apparently,
> > you can get away with that in the Bourne shell, but not in Perl. So, by
> > removing the '-i', that solved that. However, the next problem I ran
> > into was that while the output of the script was getting dumped to the
> > console, I was not able to capture that output or save it so I could
> > then process it -- something I'd like to be able to do. I resolved that
> > by adding the lines listed between the "Begin fix" and "End fix"
> > remarks. At the end, I'm not doing anything but just dumping the same
> > output, but I could parse it, process it, whatever I want since I now
> > have the output captured in @list. HOWEVER, the one thing I'd like to be
> > able to do is to turn off the output to the console that gets created
> > from the line:
> >
> > print ADM "print type: NSR $ARGV[0]; name: $ARGV[1]\n";
>
> That's because you're running it *twice*.  You're running it once in the
> child (which is later read by the parent), and you're running it again
> in the parent (which is printed to STDOUT).
>
> You need to understand that the special open you're doing there is the
> same as calling fork() in your program.  That generally requires
> conditionals so that you do some work in the parent and some in the
> child.
>
> Can I ask why you're opposed to using Open2 or Open3?  They make work
> like this much simpler...
>
> #!/usr/bin/perl -w
> use strict;
>
> use IPC::Open2;
> my $pid = open2(\*RDRFH, \*WTRFH, "nsradmin -i -");
>
> # send some commands to nsradmin.
> print WTRFH "show name\n";
> print WTRFH "print type:NSR client\n";
> close WTRFH;
>
> # get the results.
> my @output = <RDRFH>;
>
> print @output;
>
> --
> Darren Dunham                                           ddunham AT taos DOT 
> com
> Senior Technical Consultant         TAOS            http://www.taos.com/
> Got some Dr Pepper?                           San Francisco, CA bay area
>          < This line left intentionally blank to confuse you. >
>
> --
> Note: To sign off this list, send a "signoff networker" command via email
> to listserv AT listmail.temple DOT edu or visit the list's Web site at
> http://listmail.temple.edu/archives/networker.html where you can
> also view and post messages to the list. Questions regarding this list
> should be sent to stan AT temple DOT edu
> =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=

--
Note: To sign off this list, send a "signoff networker" command via email
to listserv AT listmail.temple DOT edu or visit the list's Web site at
http://listmail.temple.edu/archives/networker.html where you can
also view and post messages to the list. Questions regarding this list
should be sent to stan AT temple DOT edu
=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=