Calling all Perl gurus
Results 1 to 4 of 4

Thread: Calling all Perl gurus

  1. #1
    Senior Member roswell1329's Avatar
    Join Date
    Jan 2002
    Posts
    670

    Calling all Perl gurus

    I'm writing a comprehensive security audit script for my own use that I want to use remotely from my workstation to various systems I administer. I'm writing the script in Perl and it runs several ssh commands against the remote system and then formats the results. To facilitate all the ssh authentication, I have copied my public key out to my accounts on all these systems and I'm running this script under an ssh-agent with my private key added to the sessions, therefore I never have to enter a password for all these ssh connections.

    Okay, with the background out of the way it's down to brass tacks. I'm trying to limit my bandwidth usage as much as possible, so the less screwing around on the remote system, the better. One of the commands I created, however, is really giving me some real problems. It's obviously a shell / syntax incompatibility due to much of the punctuation, but I don't know how to get around it. This particular routine is a slick command-line one-liner to yank all the UID 0 accounts out of the password file and return them. On a standard command-line, it would look like this:

    perl -F: -ane 'print if !$F[2];' /etc/passwd

    Using any non-C style shell (i.e. ksh, sh, or bash), this will work fine. If you're using a C-style shell (i.e. csh, or tcsh), you'll need to make one modification:

    perl -F: -ane 'print if not $F[2];' /etc/passwd

    I'm trying to use some variation of this line in my script to avoid multiple command steps of breaking apart the passwd file, searching for UID 0 users and returning the results using a more conventional method. All myattempts, however, have failed. Here's what I have tried:

    my $response = system("/usr/bin/ssh system.name.domain.com /usr/bin/perl -F: -ane 'print if not $F[2];' /etc/passwd");

    This gives me the error:


    Name "main::F" used only once: possible typo at ./audit line 17.
    Use of uninitialized value in concatenation (.) or string at ./audit line 17.
    Can't open if: No such file or directory
    Can't open not: No such file or directory
    ksh: /etc/passwd: cannot execute


    I also tried this:

    my $response = `/usr/bin/ssh $system \"/usr/bin/perl -F: -ane 'print if not @F[2];' /etc/passwd\"`;

    Thinking that the punctuation was causing most of the problems, you'll notice I tried to use escaped quotes to enclose the entire statement without success. I also had to replace the dollar sign with the @ sign to get around the F being treated as a shell variable. This didn't work either. In fact, the error I got was:


    Scalar value @F[2] better written as $F[2] at ./audit line 16.
    Possible unintended interpolation of @F in string at ./audit line 16.
    Name "main::F" used only once: possible typo at ./audit line 16.
    Use of uninitialized value in join or string at ./audit line 16.
    syntax error at -e line 1, near "not ;"
    Execution of -e aborted due to compilation errors.


    I know this is a pretty specific problem, but does anyone have any suggestions on how I can better format that statement so that it will work?
    /* You are not expected to understand this. */

  2. #2
    Jaded Network Admin nebulus200's Avatar
    Join Date
    Jun 2002
    Posts
    1,356
    One thing you might consider is maybe using 'expect'. Rather than trying to remote run all of those ssh commands...at least that is what I do and it works fairly smoothly. Another thing I have done is written a series of information gathering scripts that run daily out of cron and then use a scp -B to grab them all and parse locally...

    As to your problems, I am going to mess around for it a while and see if I can figure it out, but wanted to through 'expect' out there first...

    /nebulus

    Code:
    $system = "testhost";
    $ssh = "/bin/ssh";
    $perl = "/bin/perl";
    
    $cmd  = "perl -F: -ane 'print if \! \@F[2];' /etc/passwd";
    $response = `$ssh $system \"$cmd\"`;
    Worked...think you just needed to escape out the special characters (! and @).

    /nebulus
    There is only one constant, one universal, it is the only real truth: causality. Action. Reaction. Cause and effect...There is no escape from it, we are forever slaves to it. Our only hope, our only peace is to understand it, to understand the 'why'. 'Why' is what separates us from them, you from me. 'Why' is the only real social power, without it you are powerless.

    (Merovingian - Matrix Reloaded)

  3. #3
    Senior Member roswell1329's Avatar
    Join Date
    Jan 2002
    Posts
    670
    Holy smokes, nebulus200! That worked great! I should learn to break things up a bit more instead of one long continuous command, eh? I would have tried expect, but I really hate the idea of hard coding passwords into my code -- then again, if I'm running my ssh-agent, I suppose that wouldn't really be a problem.

    No worries, I was hoping to do it this way, anyway. Thanks a bundle! A shower of greenies for your efforts!
    /* You are not expected to understand this. */

  4. #4
    Jaded Network Admin nebulus200's Avatar
    Join Date
    Jun 2002
    Posts
    1,356
    Originally posted here by roswell1329
    Holy smokes, nebulus200! That worked great! I should learn to break things up a bit more instead of one long continuous command, eh? I would have tried expect, but I really hate the idea of hard coding passwords into my code -- then again, if I'm running my ssh-agent, I suppose that wouldn't really be a problem.

    No worries, I was hoping to do it this way, anyway. Thanks a bundle! A shower of greenies for your efforts!
    The breaking it up thing is just a personal preference of mine, especially when debugging something because then I can make a simple change one place and try it again and not have to worry about it. And if you are going to be running the command with multiple arguments multiple times, it makes it easier to just dump it in a loop if everything is substitutable.

    Just for SNG, here is what I do. This script lives on every box and is run from cron:

    Code:
    # gather.sun.sh
    # specifically for SUN Solaris
    HOST=`/bin/hostname`
    FILE='/var/adm/info'                                    # where to put info
    NET='/var/adm/netinfo'
    ECHO='/bin/echo'
    DF='/bin/df'
    GREP='/bin/grep'
    CUT='/bin/cut'
    LS='/bin/ls'
    IFCONFIG='/sbin/ifconfig'
    NETSTAT='/bin/netstat'
    
    # grab /var usage
    a=`$DF -k | $GREP var`                                  # assign to var to strip extra whitespace
    b=`$ECHO $a | $CUT -f5 -d' ' | $CUT -f1 -d'%'`          # b now has percent usage
    
    if [ $b -gt 60 ]; then
            $ECHO "WARNING: /var filesystem on $HOST at $b % usage." >> $FILE
            if [ $b -gt 90 ]; then
                    $ECHO "WARNING: File system nearly full on $HOST, info not gathered." >> $FILE
                    $ECHO >> $FILE
                    exit 1
            fi
            $ECHO >> $FILE
    else
            $ECHO "/var filesystem on $HOST at $b %usage." >> $FILE
    fi
    
    $ECHO "__SOLARIS_PATCH_INFO_START__" >> $FILE
    a=`$LS '/var/sadm/patch'`
    $ECHO $a >> $FILE
    $ECHO "__SOLARIS_PATCH_INFO_STOP__" >> $FILE
    $ECHO >> $FILE
    
    $ECHO "__IFCONFIG_START__" >> $NET
    $IFCONFIG -a >> $NET
    $ECHO "__IFCONFIG_STOP__" >> $NET
    $ECHO >> $FILE
    
    $ECHO "__ROUTING_START__" >> $NET
    $NETSTAT -nr >> $NET
    $ECHO "__ROUTING_END__" >> $NET
    $ECHO >> $FILE
    
    
    $ECHO "__STAT_START__" >> $NET
    $NETSTAT -f inet -P tcp -s >> $NET
    $NETSTAT -f inet -P udp -s >> $NET
    $NETSTAT -f inet -P icmp -s >> $NET
    $NETSTAT -f inet -P ip -s >> $NET
    $ECHO "__STAT_STOP__" >> $NET
    $ECHO >> $NET
    
    $ECHO "__NONACTIVE_CONNECTIONS_START__" >> $NET
    $NETSTAT -an -f inet -P tcp | $GREP -v BOUND | $GREP -v LISTEN | $GREP -v ESTABLISHED | $GREP -v IDLE >> $NET
    $ECHO "__NONACTIVE_CONNECTIONS_STOP__" >> $NET
    $ECHO >> $NET
    I then have another script that gathers all the info/netinfo files to a central place, since you have done the keys, it should work. The script, after setting the values, then issues:

    $scp="/bin/scp";
    $dst_port="2222";
    #ip and ipn are grabbed from a db that lists all the machines (this part is in a big foreach)
    #$fi is the file being grabbed
    #dbd is the directory to store the file (likewise set earlier by the while)
    system("$scp -p -q -P $dst_port -B $user\@$ip:$fi $dbd/$ipn/ > /dev/null 2>&1 ");

    I then of couse have another script that parses all the downloaded results and prints out a nice report (that is why the gather.sh script has all those _START and _STOP's). Dunno, there are pro's and con's to each, but wanted to through out a different way of doing things. I don't use expect much, usually only if I need a little bit more interactivity/decision making that a simple script can provide.


    /nebulus
    There is only one constant, one universal, it is the only real truth: causality. Action. Reaction. Cause and effect...There is no escape from it, we are forever slaves to it. Our only hope, our only peace is to understand it, to understand the 'why'. 'Why' is what separates us from them, you from me. 'Why' is the only real social power, without it you are powerless.

    (Merovingian - Matrix Reloaded)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •