Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
SynVisions
Jun 29, 2003

I'm writing a perl CGI script, and I'm attempting to have it run in taint mode because there is form input that will eventually end up in a database query.

However, it doesn't appear that my -T flag on the parent script is propagating to modules that are loaded -- this is a problem because I have all of the database interaction broken off into a module.

When attempting to do $dbh->TaintIn = 1; in the module I get a Can't locate object method "TaintIn" via package "DBI::db" -- however if I setup a dbh in the parent script and set TaintIn it works fine.

I'm sure I'm missing something dumb here so any help is appreciated.

Also, for what it's worth this is for an internal website, so I doubt there will be any malicious intent, but I think it's worth going through all the motions regardless for many other reasons.

Adbot
ADBOT LOVES YOU

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
Why not use a parameterized query instead of relying on taint checking?

code:
$dbh->do('insert into users (name) values (?);', {}, $name);
This is impervious to SQL injection attacks because parameters are properly quoted for you.

SynVisions
Jun 29, 2003

I'm doing that anyway, but with taint checking it will force me to validate the data going into the database for general correctness... not just for malicious intent.

Also just using bind variables may protect my scripts from SQL injection, but if I willingly insert tainted data, and someone else's script pulls from the database and queries off that data without bind variables (which will in fact be the case) then they will just end up hitting it there.

It would seem to be best practice to do some sanity checking on what is being tossed into the DB.

Mithaldu
Sep 25, 2007

Let's cuddle. :3:

SynVisions posted:

Also just using bind variables may protect my scripts from SQL injection, but if I willingly insert tainted data, and someone else's script pulls from the database and queries off that data without bind variables (which will in fact be the case) then they will just end up hitting it there.
In that case you can basically do no amount of sanity checking that will be able to protect them, unless you completely reimplement DBI's binding checks.

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip

Filburt Shellbach posted:

Why not use a parameterized query instead of relying on taint checking?

code:
$dbh->do('insert into users (name) values (?);', {}, $name);
This is impervious to SQL injection attacks because parameters are properly quoted for you.

It is but that's not why and you know that!

Nevergirls
Jul 4, 2004

It's not right living this way, not letting others know what's true and what's false.

JawnV6 posted:

The pattern I always use is this:
code:
if( $string =~ /regexp/i ) {
  $name = $1;
  $plate = $2;
}
You're not checking if the regular expression matched, you're just indenting after the =~ with no handling if it doesnt match :psyduck:. So when you would see $1 and $2 defined and not $3, it means the regular expression failed and $1/$2/$3 are the results from one of the regexes further down in the program.

I prefer abusing list context:
code:
my ($name, $plate) = ($string =~ /$regexp/i);
Since the variables are lexical you don't have to worry about pollution from other matches.

Dinty Moore
Apr 26, 2007
Hey guys, Perl question (duh). I have a mess of Perl code which, just for the hell of it, I've been trying to get going on Windows. If you must know, it's an AFP (yes, that's Apple Filing Protocol) stack implementation in pure Perl. It works great on Linux, FreeBSD, NetBSD, and even MacOS X (faster than Apple's client, even - I poo poo you not). However, on Windows, it gets really cranky.

The network socket, for some reason, doesn't behave right. I'm using IO::Poll, in a thread, for receiving responses back from the server and dispatching the parsed response data. When I do the poll() call, though, it seems like the network socket doesn't return immediately when data hits the socket (like on every UNIX-like platform), but instead waits the whole poll() period. This slows things down a lot, making all requests take way longer than they reasonably ought to. It works eventually, just slowed way down.

It doesn't make any sense to me. I've tried this with both ActiveState Perl and Strawberry Perl, with no apparent difference in the socket behavior. It's almost like Perl's somehow operating on the sockets wrong in its Winsock calls. Is this normal, or is there something special I need to do with sockets on Windows Perl to make it behave like I expect?

Edit: After poking at it more, it isn't what I thought; every request I send is taking 3-10 seconds to get a response. Even simple ones that should turn around almost immediately. This makes no sense to me.

Edit 2: And using Wireshark to dump packets shows that sending them out on the socket isn't actually sending the data. I'm setting the TCP_NODELAY option, so there should be no reason for the TCP stack to hold the data, and yet I can see that the packet is going out well after I send the data on the socket. Once it actually goes out, the response is almost immediate, but the question is, why is that data not going out when it should? It does everywhere else.

Edit 3: Okay, looked more into it. syswrite() calls are blocking for an inordinate period of time. I don't know why, this only happens on Windows. I feel like I must be missing something terribly obvious, yet the fact that this code works perfectly on several other (not Windows) OSes would seem to indicate the problem isn't mine. What. The. Hell.

Dinty Moore fucked around with this message at 17:35 on Jul 10, 2010

S133460
Mar 17, 2008
hello

demonbleh posted:

Edit 3: Okay, looked more into it. syswrite() calls are blocking for an inordinate period of time. I don't know why, this only happens on Windows. I feel like I must be missing something terribly obvious, yet the fact that this code works perfectly on several other (not Windows) OSes would seem to indicate the problem isn't mine. What. The. Hell.

Hard to say without seeing code, but it sounds like a buffering-related issue on the filehandle. Are you mixing buffered and non-buffered operations on the same handle? Beware of stuff like <FH> (which is buffered).

On win32, syswrite on a socket does have a different implementation than other platforms. See PERL_SOCK_SYSWRITE_IS_SEND and pp_send in the perl source.

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip

satest3 posted:

Beware of stuff like <FH> (which is buffered).

Also beware of using a non-lexical filehandle :v:

Dinty Moore
Apr 26, 2007

satest3 posted:

Hard to say without seeing code, but it sounds like a buffering-related issue on the filehandle. Are you mixing buffered and non-buffered operations on the same handle? Beware of stuff like <FH> (which is buffered).

Definitely not, I am only using sysread() and syswrite() (and of course the poll() method on the IO::Poll object, and one setsockopt() call to set TCP_NODELAY). If you want to see the actual code, you can check it out at:

http://svn.now.ai/filedetails.php?repname=afp-perl&path=/trunk/Net/DSI.pm

That implements the actual socket access methods, so you can see what I mean.

satest3 posted:

On win32, syswrite on a socket does have a different implementation than other platforms. See PERL_SOCK_SYSWRITE_IS_SEND and pp_send in the perl source.

I'll have to pull the source and check it out. I haven't messed with digging around in the interpreter itself, since I didn't really know what I'd be looking for anyway.

Ninja Rope
Oct 22, 2005

Wee.
You may want to try replacing calls to sysread with recv and see if that makes a difference.

Dinty Moore
Apr 26, 2007

Otto Skorzeny posted:

Also beware of using a non-lexical filehandle :v:

If by "lexical filehandle", you mean an autovivifying filehandle in a variable... well, I'm not. It's an IO::Socket::INET object (which I guess is basically a generated filehandle glob blessed into a package). Guess I don't see why that should be a problem.

Mithaldu
Sep 25, 2007

Let's cuddle. :3:

demonbleh posted:

If by "lexical filehandle", you mean an autovivifying filehandle in a variable... well, I'm not. It's an IO::Socket::INET object (which I guess is basically a generated filehandle glob blessed into a package). Guess I don't see why that should be a problem.

They're talking about "FH" vs. "$FH".

The former is like a function name, a globally accessible thing from the moment when it's first used/defined, which can be used ANYWHERE in your code, completely regardless of scope. This means you can have very interesting magic behavior if you, for example, use the same file handle name in different places with different things and an open or close action fails silently.

The latter is only accessible within its scope and gets destroyed at the end of it. It's completely secure.

Dinty Moore
Apr 26, 2007

Mithaldu posted:

They're talking about "FH" vs. "$FH".

Okay, that's what I thought. Since I'm using IO::Socket::INET, and not just naming globs in my code, that's definitely not what's up.

S133460
Mar 17, 2008
hello

demonbleh posted:

Definitely not, I am only using sysread() and syswrite() (and of course the poll() method on the IO::Poll object, and one setsockopt() call to set TCP_NODELAY). If you want to see the actual code, you can check it out at:

http://svn.now.ai/filedetails.php?repname=afp-perl&path=/trunk/Net/DSI.pm

That implements the actual socket access methods, so you can see what I mean.

Only had time to skim it briefly...

Could you try adding binmode($conn) after your socket is created? Just a wild guess. I think sockets are O_BINARY by default in recent perls though.

Also remember that sysread can return a number different than the length you supplied it. And sysread/syswrite could return undef. Maybe check the return value of setsockopt too?

code:
# }}}1
I like you.

S133460
Mar 17, 2008
hello

Mithaldu posted:

They're talking about "FH" vs. "$FH".

The former is like a function name, a globally accessible thing from the moment when it's first used/defined, which can be used ANYWHERE in your code, completely regardless of scope.

That's kind of true. It is a package global. It references the IO slot of the typeglob stored in the symbol table of the current package. Try this...

code:
#!/usr/bin/perl

{
    package A;
    use strict;
    no strict 'refs';

    sub A::FH { qq/abc\n/ }

    $A::FH = qq/hello2\n/;     # same as $FH = ...
    ${*{q/A::FH/}{SCALAR}} = qq/hello2\n/; # same as above

    my $FH = qq/momma\n/;     # oh no...

    # explicit version of open(*FH, ...)
    open(*{q/A::FH/}{IO}, '<', '/etc/passwd') or die $!;

    print $FH;              # prints "momma"
    print $A::FH;           # prints "hello2"
    print ${*A::FH{SCALAR}};# prints "hello2"
}

print $FH;     # looks in $main::FH!

use strict;
no strict 'refs';
use warnings;

print $A::FH;               # prints "hello2"
print ${*A::FH{SCALAR}};    # prints "hello2"

print A::FH();  # prints "abc"
my $cb;
$cb = *{q/A::FH/}{CODE};
print $cb->();  # prints "abc"

$cb = \&A::FH;
print $cb->();  # prints "abc"

The syntax is ghastly, but internally it is very simple.

quote:

This means you can have very interesting magic behavior if you, for example, use the same file handle name in different places with different things and an open or close action fails silently.

This is also true of lexicals, no?

quote:

The latter is only accessible within its scope and gets destroyed at the end of it. It's completely secure.

That's kind of true. A lexical scalar can be passed out of its scope and exist after perl leaves the scope in which it was defined. Leaving a scope only decrements the reference count of SVs that were declared in that frame. Perl will only destroy a scalar whose reference count is zero, be it lexical or dynamic.

Also, be aware that lexicals are scoped to the current file....

code:
#!/usr/bin/perl

package A;
my $lex = 'red';
$dyn = 'blue';

package B;
print "lexical: $lex\n";
print "dynamic: $dyn\n";
In this case, the package global is "more secure" than the lexical. :)

Dinty Moore
Apr 26, 2007

satest3 posted:

Could you try adding binmode($conn) after your socket is created? Just a wild guess. I think sockets are O_BINARY by default in recent perls though.

Actually tried that in a local copy, thinking it might make a difference (right after I call setsockopt(), for reference). Didn't change the behavior, still got the same delays during syswrite()s. Also the packets do go out correctly (based on wireshark's captures), and the responses are correct; it's just the delay that's messing things up.

satest3 posted:

Also remember that sysread can return a number different than the length you supplied it. And sysread/syswrite could return undef. Maybe check the return value of setsockopt too?

Yeah, after reading more recently about them, I realized that that's something to consider. Hasn't affected me thus far, but definitely could. I'll have to work that in; fortunately there are only a handful of places where I'm calling sysread() and syswrite().

Mithaldu
Sep 25, 2007

Let's cuddle. :3:
satest3, you're basically right with everything in there, but let me just say I was thinking about lexical variables in sub routines. Global lexical variables are nasty and should be avoided, or only used for very specific purposes.

Hughmoris
Apr 21, 2007
Let's go to the abyss!
I'm trying to follow an online tutorial for learning Perl (no programming experience) and I'm hitting a hurdle while doing an example.
code:
#!/usr/bin/perl
#examples
use warnings;
use strict;


my @questions = qw(Java Python Perl C);
my @punchlines = {
	"None. Change it once, and its the same everywhere...",
	"One, he just stands below...",
	"A millon, one to change it...",
	'CHANGE?!!"'
};

print "Please enter a number between 1 and 4: ";
my $selection = <STDIN>;
$selection -= 1;
print "How many $questions[$selection] ";
print "programmers does it take to change a lightbulb?\n\n";
sleep 2;
print $punchlines[$selection], "\n";
That gives me an error of:
code:
Use of uninitialized value in print at helloworld.pl line 21, <STDIN> line 1.
Could someone point out what I'm missing?

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!

Hughmoris posted:

code:
my @punchlines = {
	"None. Change it once, and its the same everywhere...",
	"One, he just stands below...",
	"A millon, one to change it...",
	'CHANGE?!!"'
};

You want parentheses not braces.

Hughmoris
Apr 21, 2007
Let's go to the abyss!

Filburt Shellbach posted:

You want parentheses not braces.

That did it, thank you.

Triple Tech
Jul 28, 2006

So what, are you quitting to join Homo Explosion?

satest3 posted:

I like you.

What are the braces referring to?

Dinty Moore
Apr 26, 2007

Triple Tech posted:

What are the braces referring to?

They're vim fold markers.

Fenderbender
Oct 10, 2003

You have the right to remain silent.

demonbleh posted:

They're vim fold markers.

why not just enable perl_fold in vim? :confused:

satest2
Sep 19, 2007
bar

Fenderbender posted:

why not just enable perl_fold in vim? :confused:

I'm not crazy about syntax-based folding. I use foldmethod=marker foldlevel=1. I mostly use folding for PHP though, and really only to wrap functions/methods.

Mithaldu
Sep 25, 2007

Let's cuddle. :3:

satest2 posted:

I'm not crazy about syntax-based folding.
I couldn't imagine why that would be. Care to satisfy my curiosity? :)

Megaman
May 8, 2004
I didn't read the thread BUT...
I'm a complete noob when it comes to languages, I'm just starting perl.

Can someone break down this if line character by character from a loop that determines whether or not STDIN is a numeric value:

if ( $input =~ /^[\+-]*[0-9]*\.*[0-9]*$/ && $input !~ /^[\. ]*$/ ) {

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
You should really just read up on regular expressions. Anyway.

^ means "start of line", [] surround sets of characters, * means "arbitrarily many of what comes before", $ means "end of line". So it matches if the line is arbitrarily many +/- characters (probably a mistake), followed by arbitrarily many digits ('-' inside [] means a range of characters), followed by arbitrarily many '.'s, followed by arbitrarily many digits, *and* if the the line doesn't just contain arbitrarily many '.'s or spaces.

So the lines '++-+....9321' and '--9019.' are okay, but '.' isn't.

Pweller
Jan 25, 2006

Whatever whateva.
I need some help, I'm calling a program from a perl script using backticks, and this secondary program needs to read data from STDIN...

I'm sure I read somewhere that the parent program's STDOUT is essentially the same as the 2nd program's STDIN, but I can't get it to work.

here's essentially what my code is, I want to capture the output of the command in result:

code:
$result = `$cmd`;
# $cmd needs some data from STDIN
print "data for cmd to process";
everything seems to just stall unless I manually type in something.

Erasmus Darwin
Mar 6, 2001
I think you need to use 'open' to do that:

code:
open($fh, '|/bin/cat -tve');
print $fh "Hello,\tworld.\n";
close($fh);
If you need the result, check $? after calling close on the file handle.

Pweller
Jan 25, 2006

Whatever whateva.
Thank you that helped immensely.

I'm finding Perl syntax to be very strange.... and frustrating.

Dinty Moore
Apr 26, 2007

Ninja Rope posted:

You may want to try replacing calls to sysread with recv and see if that makes a difference.

Sorry, tried this. This didn't help, if anything it amplified the problem.

Mithaldu
Sep 25, 2007

Let's cuddle. :3:

Pweller posted:

I need some help, I'm calling a program from a perl script using backticks, and this secondary program needs to read data from STDIN...

I'm sure I read somewhere that the parent program's STDOUT is essentially the same as the 2nd program's STDIN, but I can't get it to work.

You could give IPC::Run3 a try.

mdxi
Mar 13, 2006

to JERK OFF is to be close to GOD... only with SPURTING

Pweller posted:

I'm finding Perl syntax to be very strange.... and frustrating.

This is less about Perl's syntax and more about how non-shared-memory IPC works.

Backticks aren't "real" bi-di IPC at all. Like in the shell, backticks do not open a channel to the subordinate process. They simply launch the command, wait for it to exit, then store whatever output there was in the variable you specify.

Things like IPC::Run3 and IPC::Open2 create bidirectional channels, which is what you want, but they do still have pitfalls (especially IPC::Open2, which is a recipe for deadlock unless you have control over what BOTH sides are sending, and know that every filehandle is autoflushing). They're pretty simple to use, though.

Probably the safest and most flexible (but definitely the most complex) answer is using IO::Select and IO::Socket to do IPC via the networking stack instead of pipes.

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip
The Perl 6 project turned 10 today; the Rakudo (parrot) implementation turned negative 2 weeks old.

Filburt Shellbach
Nov 6, 2007

Apni tackat say tujay aaj mitta juu gaa!
Pretty good post describing the project's history http://use.perl.org/~masak/journal/40451

Rohaq
Aug 11, 2006
So a quick question.

I've got the following code to get the location of gzcat and remove the trailing linebreak:

code:
my $GZCAT = `which gzcat`;
chomp $GZCAT;
After which $! will return 'Illegal seek'. I'm not sure what's gone wrong here, but it's causing problems later on in my code when I'm checking the value of $!, when it should be undefined when no error occurs. I could just undef $! after the chomp command is run, but that seems sloppy to me.

Any clues?

EDIT:- Further checking shows that this is due to the backticks returning an error, despite the command running successfully, I'll check further...

Rohaq fucked around with this message at 18:01 on Jul 21, 2010

Mithaldu
Sep 25, 2007

Let's cuddle. :3:

Rohaq posted:

backticks

I'd suggest you use Capture::Tiny like so:

code:
    my $res;
    my ($stdout, $stderr) = capture {
        $res = system( $cmd );
    };
That way you won't pollute your environment and know exactly the three important returns you can get from a program.

Rohaq
Aug 11, 2006

Mithaldu posted:

I'd suggest you use Capture::Tiny like so:

That way you won't pollute your environment and know exactly the three important returns you can get from a program.
This will be running on a server where it can be a pain to get new modules installed.

I've taken to using the system command for now, but I need to redirect the output of STDOUT temporarily to my variable to make it work - Any ideas on how to do this?

Adbot
ADBOT LOVES YOU

Mithaldu
Sep 25, 2007

Let's cuddle. :3:

Rohaq posted:

This will be running on a server where it can be a pain to get new modules installed.

I've taken to using the system command for now, but I need to redirect the output of STDOUT temporarily to my variable to make it work - Any ideas on how to do this?

Try and see if you can just upload this module and use it directly:
http://cpansearch.perl.org/src/DAGOLDEN/Capture-Tiny-0.08/lib/Capture/Tiny.pm

Alternatively, this will allow you to privately install modules: http://search.cpan.org/~getty/local-lib-1.006005/lib/local/lib.pm

  • Locked thread