Test if a directory is writable by a given UID? Test if a directory is writable by a given UID? bash bash

Test if a directory is writable by a given UID?


Here's a long, roundabout way of checking.

USER=johndoeDIR=/path/to/somewhere# Use -L to get information about the target of a symlink,# not the link itself, as pointed out in the commentsINFO=( $(stat -L -c "%a %G %U" "$DIR") )PERM=${INFO[0]}GROUP=${INFO[1]}OWNER=${INFO[2]}ACCESS=noif (( ($PERM & 0002) != 0 )); then    # Everyone has write access    ACCESS=yeselif (( ($PERM & 0020) != 0 )); then    # Some group has write access.    # Is user in that group?    gs=( $(groups $USER) )    for g in "${gs[@]}"; do        if [[ $GROUP == $g ]]; then            ACCESS=yes            break        fi    doneelif (( ($PERM & 0200) != 0 )); then    # The owner has write access.    # Does the user own the file?    [[ $USER == $OWNER ]] && ACCESS=yesfi


That could do the test:

if read -a dirVals < <(stat -Lc "%U %G %A" $directory) && (    ( [ "$dirVals" == "$wantedUser" ] && [ "${dirVals[2]:2:1}" == "w" ] ) ||    ( [ "${dirVals[2]:8:1}" == "w" ] ) ||    ( [ "${dirVals[2]:5:1}" == "w" ] && (        gMember=($(groups $wantedUser)) &&        [[ "${gMember[*]:2}" =~ ^(.* |)${dirVals[1]}( .*|)$ ]]    ) ) )  then    echo 'Happy new year!!!'  fi

Explanations:

There is only one test (if), no loop and no fork.

+ Nota: as I'v used stat -Lc instead of stat -c, this will work for symlinks too!

So condition is if,

  • I could successfully read stats of $directory and assign them to dirVals,
  • And (
    • ( Owner match And Flag UserWriteable is present )
    • or flag Other Writeable is present
    • or ( Flag GroupWriteabe is present AND
      • I could successfully assing member list of $wantedUser to gMember AND
      • A string built by merging fields 2 to last of $gMember will match beginOfSting-Or-something-followed-by-a-space, immediately followed by target's group (${dirVals[1]}), immediately followed by a-space-followed-by-something-Or-endOfString. )

then echo Happy new year!

As the group's test implie a second fork (And I love to reduce as possible such calls), this is the last test to be done.

Old:

Simply:

su - mysql -c "test -w '$directory'" && echo yesyes

or:

if su - mysql -s /bin/sh -c "test -w '$directory'" ; then     echo 'Eureka!'  fi

Nota: Warn to enclose first with double-quotes for having $directory developped!


You can use sudo to execute the test in your script. For instance:

sudo -u mysql -H sh -c "if [ -w $directory ] ; then echo 'Eureka' ; fi"

To do this, the user executing the script will need sudo privileges of course.

If you explicitly need the uid instead of the username, you can also use:

sudo -u \#42 -H sh -c "if [ -w $directory ] ; then echo 'Eureka' ; fi"

In this case, 42 is the uid of the mysql user. Substitute your own value if needed.

UPDATE (to support non-sudo-priviledged users)
To get a bash script to change-users without sudu would be to require the ability to suid ("switch user id"). This, as pointed out by this answer, is a security restriction that requires a hack to work around. Check this blog for an example of "how to" work around it (I haven't tested/tried it, so I can't confirm it's success).

My recommendation, if possible, would be to write a script in C that is given permission to suid (try chmod 4755 file-name). Then, you can call setuid(#) from the C script to set the current user's id and either continue code-execution from the C application, or have it execute a separate bash script that runs whatever commands you need/want. This is also a pretty hacky method, but as far as non-sudo alternatives it's probably one of the easiest (in my opinion).