Search code examples
linuxbashdirectorypermissionsfile-permissions

Correct Linux user home directory file ownership


I would like to programmatically repair the ownership on Linux systems for files within each users home directory which reside under /home. From https://serverfault.com/a/146709/75044 the script below seems ideal except, some of the users are not in the /etc/passwd as they are externally authenticated.

The users which are externally authenticated, do have a uid and gid associated with their home directories though. The externally authenticated users uid and gid produced from the id command do not match the ls -ln respective group and user id. I did not catch this originally due to sanitizing the output. A mapping is being performed so the only way to correctly perform this in my opinion is to leverage the uid and gid from the directory listing.

Instead of depending on the /etc/passwd, how can we obtain and use the uid and gid from each users home directory to then recursively apply the same uid and gid ownership to the objects within their respective home directories?

#!/bin/bash

while IFS=':' read -r login pass uid gid uname homedir comment; do
    if [[ "$homedir" = **/home/** ]]; then
        if [ -d "$homedir" ]; then
            echo chown -R $uid:$gid "$homedir";
        fi
    fi
done < /etc/passwd

An example user that's external authenticated would have a home directory that lives user /home

drwx------+  3 DOMAIN\user        DOMAIN\DOMAIN USERS  4096 Jan  1  1969 user

but in it's uid/gid format would look like:

drwx------+  3 12345        01234  4096 Jan  1  1969 user

Output from id (the uid/gid does not match the directory listing):

$ id DOMAIN\\user
uid=2000234(DOMAIN) gid=2000349(DOMAIN\domain users) groups=2056789(DOMAIN\domain users) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
$ stat -c "%n %u:%g" /home/user/
/home/user/ 12345:01234

I assume it would be easier to obtain and apply using the uid and gid verse parsing the user and group names.

An example of a local user is as follows:

drwx------.  4  1000  1000  4096 Jul 21 02:04 user2

drwx------.  4 user2           user2          4096 Jul 21 02:04 user2
$ id user2
uid=1000(user2) gid=1000(user2) groups=1000(user2),4(adm),190(systemd-journal)

edit

Another option would be to list the file in /home, feed through stat and apply the permissions to those files that do not match. An example to just change the group would be

find /home -maxdepth 1 but we do not want to include /home in the listing stat -c %g against home directory and set to variable $GID find \! -gid $GID -exec chown :$GID {} \; if $GID for a child file or folder of the home directory does not match, fix it

Something like the following which does not work would suffice

find . -exec sh -c '
  for f do
    GID=$(stat -c %g)
    chown :$GID $f
' find-sh {} \;    

Solution

  • Assuming that the owner and group of all home directories match the corresponding user, you can set the ownership for all contained subdirectories and files to the same values.

    Note that there might be files or directories that deliberately have a different owner or group. Blindly changing the owner or group might break access for other users or applications.

    This (untested) command will show the commands to recursively change the owner and group IDs to the values taken from the home directory:

    for i in /home/*/
    do
        echo chown -Rh $(stat -c "%u:%g" "$i") "$i"
    done
    

    You can also use chown --reference=RFILE to copy the ownership data from a reference, but this will not show the actual uid and gid values.

    for i in /home/*/
    do
        echo chown -Rh --reference="$i" "$i"
    done
    

    When you have manually checked that everything is correct, remove the echo to actually run the commands.