2

I'm trying to cycle through /etc/passwd with a single-line command in order to find those users who have a home directory which is not owned by the user.

The following has syntax errors in it, but hopefully illustrates the concept.

awk -F: 'BEGIN{nores=1;} {if(system( "[ -d " $6 " ]") == 0 && $7 != "/sbin/nologin" && $(system( "ls -ld $6 | awk \'{print $3}\')" ) != $1 ) {print "The directory " $6 " exists for user " $1 " but is not owned by that user"; nores=0 }} END{if (nores) print "No results";}' /etc/passwd

This is associated with writing checks for the CIS RHEL6 Benchmark item 9.1.13 for some internal testing.

Solution I will likely use, which helped fix what I did wrong:

awk -F: 'BEGIN { FS = ":"; nores = 1; } { if ((system("[ -d " $6 " ]") == 0) && ($7 != "/sbin/nologin")) { "stat -c \"%U\" " $6 | getline s; if (s != $1) { print "The directory " $6 " exists for user " $1 " but is not owned by that user"; nores = 0 } } } END { if (nores) print "No results"; }' /etc/passwd

Other solution, but making it fit the requirements by putting it on one line::

flag=0; testuser=$(stat "/home/testuser" -c %U); while IFS=':' read -r myuser a b c d mydir e; do if [ -d "$mydir" -a "$e" != "/sbin/nologin" ]; then if [ "$myuser" != "$testuser" -a "$myuser" != $(stat "$mydir" -c %U) ]; then echo "The directory $mydir exists for user $myuser but is not owned by that user"; flag=1; fi fi done </etc/passwd; if [ $flag -eq 0 ]; then echo "No results"; fi
  • 1
    One liners quickly become hard to read. That is why you place them is a shell script with proper indentation. As an adding bonus you call the shell script by name instead of typing hundreds of characters. – fd0 Apr 9 '15 at 18:16
  • 1
    You should use getent instead of parsing /etc/password. – Dennis Williamson Apr 9 '15 at 20:28
  • @fd0 You're assuming this is being called by a person at the command-line. In actuality this is being called by a tool that requires it all be on one-line, hence the requirement. No would would argue that properly indented code is easier to maintain. – Doug Apr 17 '15 at 17:01
2

Or your awk could be:

awk -F: 'BEGIN { FS = ":"; nores = 1; } { if ((system("[ -d " $6 " ]") == 0) && ($7 != "/sbin/nologin")) { "stat -c \"%U\" " $6 | getline s; if (s != $1) { print "The directory " $6 " exists for user " $1 " but is not owned by that user"; nores = 0 } } } END { if (nores) print "No results"; }' /etc/passwd
  • Man, I tried something along that syntax before and couldn't get it to work, but your code definitely works. This is technically much closer to what I was trying to, so going to accept. – Doug Apr 9 '15 at 16:40
  • Don't hurry to accept, Costas solutions is very good, consider it. I just tried doing it as per your awk. – taliezin Apr 9 '15 at 16:41
3
flag=0
testuser=$(stat "/home/testuser" -c %U)
while IFS=':' read -r myuser a b c d mydir e
do
    if [ -d "$mydir" -a "$e" != "/sbin/nologin" ]
    then
        if [ "$myuser" != "$testuser" -a \
             "$myuser" != $(stat "$mydir" -c %U) ] 
        then
            echo "The directory $mydir exists for user $myuser" \
                 "but is not owned by that user"
            flag=1
        fi
    fi
done </etc/passwd
if [ $flag -eq 0 ]
then
    echo "No results"
fi
  • Thank-you. This is very different to what I was doing, but it works! In case someone else needs it on oneline, here is the same thing: flag=0; testuser=$(stat "/home/testuser" -c %U); while IFS=':' read -r myuser a b c d mydir e; do if [ -d "$mydir" -a "$e" != "/sbin/nologin" ]; then if [ "$myuser" != "$testuser" -a "$myuser" != $(stat "$mydir" -c %U) ]; then echo "The directory $mydir exists for user $myuser but is not owned by that user"; flag=1; fi fi done </etc/passwd; if [ $flag -eq 0 ]; then echo "No results"; fi – Doug Apr 9 '15 at 16:36
2

With

perl -F: -anE 'if( (stat $F[5])[4] != $F[2] )
                   { say "$F[0]($F[2]) not own $F[5]" }' /etc/passwd 

you get almost what you wanted. In /etc/passwd:

  • F0 = username
  • F5 = home
  • F2 = uid
  • stat FileOrDir [4] is the uid of FileOrDir

Add some more condition to tune it. Example:

perl -F: -anE 'if( -d $F[5]  and               # F5 is a directory and
                   (stat $F[5])[4] != $F[2]    # owner(home) isNot uid
                 ) { say ...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.