Calling system commands from Perl

Posted by Dan J on Stack Overflow See other posts from Stack Overflow or by Dan J
Published on 2010-12-10T21:08:38Z Indexed on 2010/12/31 21:54 UTC
Read the original article Hit count: 320

Filed under:
|
|

In an older version of our code, we called out from Perl to do an LDAP search as follows:

# Pass the base DN in via the ldapsearch-specific environment variable 
# (rather than as the "-b" paramater) to avoid problems of shell 
# interpretation of special characters in the DN.
$ENV{LDAP_BASEDN} = $ldn;

$lcmd = "ldapsearch -x -T -1 -h $gLdapServer" .
        <snip>
        " > $lworkfile 2>&1";
system($lcmd);

if (($? != 0) || (! -e "$lworkfile"))
{
  # Handle the error
}

The code above would result in a successful LDAP search, and the output of that search would be in the file $lworkfile.

Unfortunately, we recently reconfigured openldap on this server so that a "BASE DC=" is specified in /etc/openldap/ldap.conf and /etc/ldap.conf. That change seems to mean ldapsearch ignores the LDAP_BASEDN environment variable, and so my ldapsearch fails.

I've tried a couple of different fixes but without success so far:

(1) I tried going back to using the "-b" argument to ldapsearch, but escaping the shell metacharacters. I started writing the escaping code:

my $ldn_escaped = $ldn;
$ldn_escaped =~ s/\/\\/g;
$ldn_escaped =~ s/`/\`/g;
$ldn_escaped =~ s/$/\$/g;
$ldn_escaped =~ s/"/\"/g;

That threw up some Perl errors because I haven't escaped those regexes properly in Perl (the line number matches the regex with the backticks in).

Backticks found where operator expected at /tmp/mycommand line 404, at end of line

At the same time I started to doubt this approach and looked for a better one.

(2) I then saw some Stackoverflow questions (here and here) that suggested a better solution.

Here's the code:

print("Processing...");

# Pass the arguments to ldapsearch by invoking open() with an array.
# This ensures the shell does NOT interpret shell metacharacters.
my(@cmd_args) = ("-x", "-T", "-1", "-h", "$gLdapPool",
                 "-b", "$ldn",
                 <snip>
                );

$lcmd = "ldapsearch";

open my $lldap_output, "-|", $lcmd, @cmd_args;

while (my $lline = <$lldap_output>)
{
  # I can parse the contents of my file fine
}

$lldap_output->close;

The two problems I am having with approach (2) are:

a) Calling open or system with an array of arguments does not let me pass > $lworkfile 2>&1 to the command, so I can't stop the ldapsearch output being sent to screen, which makes my output look ugly:

Processing...ldap_bind: Success (0)
        additional info: Success

b) I can't figure out how to choose which location (i.e. path and file name) to the file handle passed to open, i.e. I don't know where $lldap_output is. Can I move/rename it, or inspect it to find out where it is (or is it not actually saved to disk)?

Based on the problems with (2), this makes me think I should return back to approach (1), but I'm not quite sure how to

© Stack Overflow or respective owner

Related posts about perl

Related posts about ldap