raggmopp has asked for the wisdom of the Perl Monks concerning the following question:

Hi all:

Working with per 5.8.8 on RH5.5. I am building a cgi app that will allow users to add accounts to a remote system that is behind a firewall. There are no interactive accounts except for us admins.

When users put in a name for the account, a check is done to ensure that the account does not already exists. If account does not exist a sub is called to add the new account.

If the account does exist the a message appears on user's screen and a sub is started to change the passwd. However I only want users to be able to change the passwd if the account has a specific gid. If the gid does not match, exit out. (See snippet below.)

So the first test to verify the existence of the account works fine. Now that I have verified that the account exists I want to be able to verify the gid, if it matches '5612' then the users can change the passwd. If the gid does not equal '5612' then the users are presented a message saying they cannot change the passwd. The root account is specifically stated and if they try to change the root passwd via the cgi they are kicked out of the script and the message says "NO" (in much more stern langauge).

So users enter the account name on the first form page, The second page is a verification page for user - "Is this correct?" The third page is the activity.

Does this account exist? YES. Does this account have the /5612/ pattern in the 4th field of the pass file? If YES, change it. If NO, message the user and kick them out. (Prevent users from changing the passwd on any other account that is not gid=5612)

I am copying the passwd file from the remote system so that is why you see 'passwd.$$'. So I am wanting to check the line that contains the account name and verify the 4th field, 3rd field in array.

Any ideas or hints? Many thanks!

if (!$test) { print "<br>$sr exists on the system<br>\n"; open(PASS, '/tmp/passwd.$$'); while(<PASS>) { chomp; my @fields=split(':', $_); if (grep {$fields[3] !~ /5612/} @fields) { print "You cannot change the passwd on system accounts. +<br>\n"; print "This is being logged and will be reported.<br>\n +"; } close(PASS); } }

Replies are listed 'Best First'.
Re: test value of a field for 1 line in passwd
by jwkrahn (Abbot) on Mar 19, 2012 at 13:22 UTC
    I am copying the passwd file from the remote system

    Which means that you are transmitting a plain text file, containing user names and passwords, over the internet?



    if (grep {$fields[3] !~ /5612/} @fields) {

    Without anchors your regular expression will also match numbers like 15612, 25612, etc.    It would be better to look for an exact match.    And you don't need grep because you are only testing $fields[3] and not all the elements of @fields.    (For example, if @fields contains ten elements then you are testing $fields[3] !~ /5612/ ten times, and each time will produce the same result.)

    if ( $fields[ 3 ] ne '5612' ) {

    Or:

    if ( $fields[ 3 ] != 5612 ) {

    Or:

    if ( $fields[ 3 ] !~ /\A5612\z/ ) {
Re: test value of a field for 1 line in passwd
by Anonymous Monk on Mar 19, 2012 at 13:19 UTC
    1. close(PASS); is inside of while loop, so only the first line is verified;
    2. $fields[3] !~ /5612/ should be enough.
Re: test value of a field for 1 line in passwd
by Anonymous Monk on Mar 19, 2012 at 15:15 UTC

    No, I am not transmitting the passwd file over the internet. Both systems are located in the same physical location. The system outside the firewall can only be accessed from an internal system inside our firewall or via FTP which are chroot jailed. Plus hosts.deny is installed so the system can only be accessed by another system with the correct keys. There is no X or apache or ... installed on the system outside the firewall.

    The passwd file is being transferred to an internal system using scp. Part of the reason I am doing this script is to enhance security, with an updated OpenSSH I am configuring chroot jailed SFTP.

      Many thanks!