To change ownership of a file
/bin/chown user:group file # Must be superuser.
/bin/chgrp group file      # Must be su or own file.


/bin/chmod SUGO /path/file


  • S= Special (SUID, SGID, sticky directory) 4=SUID, 2=SGID, 1=directory sticky bit

  • U= User/owner permissions 4=owner read, 2=owner write, 1=owner execute

  • G= Group permissions 4=group read, 2=group write, 1=group execute

  • O= Others - everybody’s permissions 4=all read, 2=all write, 1=all execute

One unusual "mode" you may come across when using the symbolic mode of the chmod command is an upper case X. Here is an example.

sudo chmod -Rc ug=rwX,o=rX pocketome/pdbder/

This is not actually a mode per se; it does not imply different metadata. It is a hint to the chmod program about how to selectively change the mode. It makes the file(s) executable or searchable only if the file is a directory or already has execute permission for some user. In other words, if the file is not a directory or an executable program, chmod does not set the x permission. This allows for setting access to things without causing other trouble.

A complete symbolic mode regular expression looks like this.


What is a "Sticky Bit"?

For directories

Allows users to conservatively share a directory. Normally a user can delete anything in a directory or nothing depending on if he has write permission for the directory. With the sticky bit set on the directory, a user can delete his own files in that directory, but not the files of others. An exception is if he is the owner of the directory and has write permission (or superuser). The classic example is a /tmp directory where all users can do what they want with only their own files.

chmod 1777 /tmp  # Sets up the normal temporary directory.
$ stat /tmp | grep Uid # /tmp directory permissions ls like this.
Access: (1777/drwxrwxrwt)  Uid: (    0/    root)   Gid: (    0/ root)

For normal files

Obsolete in 2005. The sticky bit used to signal that the OS cache executables in memory after execution (stick), but today that is automatic and setting the sticky bit on non directories is either pointless or will cause system dependent behavior.

That said, the XDG Base Directory Specification seems to revive functionality in 2010 with this note about forcing files to "stick" around in $XDG_RUNTIME_DIR when they otherwise might be culled.

To ensure that your files are not removed, they should have their access time timestamp modified at least once every 6 hours of monotonic time or the sticky bit should be set on the file.


What is "SUID"?

This stands for "set user id".

Applied to directories


What does it mean? No idea. Probably nothing. Couldn’t notice any features.

However, after a Gentoo update, I once got this:

* Messages for package net-mail/mailbase-1.1:

* Your /var/spool/mail/ directory permissions differ from
*   those which mailbase wants to set it to (03775).
*   If you did not change them on purpose, consider running:
*     chown root:mail /var/spool/mail/
*     chmod 03775 /var/spool/mail/

Which does produce this:

drwxrwsr-t 2 root mail 4.0K May 11 22:18 /var/spool/mail/

Could this be a clue to some secret functionality?

Applied to executable files


For files, it affects whom the file is executed as. When a SUID executable is run, the process is treated as if it were started by the owner of the file, not the user who actually executed it. Keep in mind that if a script (such as a bash, Perl, or Python program) is executable, the SUID (and SGID) bits don’t have any real effect. This is because a script is not actually executable code that’s sent to the processor. The actual code that is really being executed is the interpreter and that does not run with the expected SUID permissions. It’s shell trickery that causes Perl programs to "execute". In reality, the shell has a quick look at the file and realizes it needs to fire off the real executable, the interpreter, with the script as an argument. If you want to see the SUID bit in action, here’s a real executable (a simple clone of the id system utility) that demonstrates it.

#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
int main() {
    int realuid= getuid(); int effectiveuid= geteuid();
    int realgid= getgid(); int effectivegid= getegid();
    printf( "RealUser=%d EffectiveUser=%d RealGroup=%d EffectiveGroup=%d\n",
            realuid, effectiveuid, realgid, effectivegid );
    return 0; }
Results of identitycrisis test
$ ls -ln identitycrisis
-rwsrwsr-x  1 1000 502 7615 Dec  9 14:12 identitycrisis
$ id
uid=500(xed) gid=501(jcsg) groups=10(wheel),18(audio),85(usb),501(jcsg)
$ ./identitycrisis
RealUser=500 EffectiveUser=1000 RealGroup=501 EffectiveGroup=502

What is "SGID"?

This stands for "set group id".

Applied to directories:


Normally when a user creates a file, it is owned by that user and it’s primary group is the user’s primary group. If SGID is on a directory, then any file created in that directory will have a group of the directory. This is true even if the creator isn’t a member of that group.

Applied to executable files:

-rw-rwSr-- (2664)

The same as with SUID except the effective group during execution is the owning group of the executable and not the executor’s primary group as would normally be the case.

Applied to nonexecutable files: Apparently this can affect "mandatory record locking" for System V style Unixes. What that means and how it’s used - no idea.

How To Interpret Strange ls Permission Strings

The permission string is 10 characters.

drwxr-x---   <=== Something like this.
0123456789   <=== Numbered like this (by me, not officially).
  • The 0 position is the directory flag d or a normal file -.

  • 1-3 are the user’s (file owner’s) permissions.

  • 4-6 are the permissions of the memebers of the file’s group.

  • 7-9 are the permissions of others, i.e. anybody at all.

In each triplet, the first two (1,2,4,5,7,8) are binary flags either on or off. If off, it is a dash. If on, it is either read or write depending on position- 1,4,7 r for readable, and 2,5,8 w for writable.

The last position of the triplet is more complicated as it is not binary. There are 2 binary flags stuffed into one character. Many people don’t realize this since in normal usage, this field looks binary like the others with a - for not executable and a x for execute permission. The two states described by this character are executable (or not) and something fancy (or not). Fancy is my word and it’s a helpful step when tackling the full complexity. Ideally there could be 4 characters to describe all this:

  • - = neither executable nor fancy

  • x = executable but not fancy, i.e. normal executable

  • F = fancy but not executable

  • f = both fancy and executable

This is very similar to how it really works, but instead of F for fancy, there are 2 letters, s/S for SUID and SGID, and t/T for the sticky bit. The following 10 sets of parentheses show all the options.

Another way to visualize it.
    --x------ + SUID       = --s------
    --------- + SUID       = --S------
    -----x--- + SGID       = -----s---
    --------- + SGID       = -----S---
    --------x + sticky bit = --------t
    --------- + sticky bit = --------T

Note that the octal number values for the permissions look like this.

  • S - (special) setuid=4, setgid=2, sticky=1

  • U - (user) read=4, write=2, execute=1

  • G - (group) read=4, write=2, execute=1

  • O - (other) read=4, write=2, execute=1

To see what a file has now use something like this.

$ stat -c%a /usr/bin/passwd

Making A File Immutable

To set a file so that it can not be changed or deleted by anyone, its immutable attribute can be set. Generally, only root can do this.

chattr +i filename

To clear the setting:

chattr -i filename

A similar trick is to make a file "append only". This could be useful for log files to detect tampering.

chattr +a filename

The attributes for a file can be checked by:

lsattr filename

useradd/usermod Options

In my opinion the correct command for user management is /usr/sbin/useradd. It is not adduser which is a symlink on many systems. I get the feeling that adduser is an ancient Debian thing (by Ian Murdock himself) which might be fine there, but useradd is the universal classic way available everywhere, even Debian, and perfectly functional now.

See /etc/default/useradd for defaults (or useradd -D).

  • -d /specialhome/user = default home directory.

  • -m [-k /specific/skeleton] = use /etc/skel to populate user account.

  • -c "Chris X Edwards" = GECOS or real name, comment field.

  • -s /bin/tsch = users shell, use /bin/false or /bin/nologin for deamons.

  • -g users = initial primary group (can be name or number).

  • -u 600 = a special user ID number, maybe to match a NFS.

  • -e 2005-12-08 = Expiration date of this account.

  • -f 0 = days after password expires that account is disabled. -1 default, off.

The same options for useradd apply to usermod plus:

  • -l cxe = A new login name. Watch the user’s scripts break!

  • -G audio,wheel = COMPLETE list of groups user is in. Missing=deleted!!

  • -L = Lock the password with a ! disabling it.

  • -U = Unlock a user’s password.

# Add a new user "tech".
useradd -m -g users -c "Visiting personnel" -s /bin/bash tech

# Rename a user from "tech" to "bob".
usermod -l bob tech; mv -i /home/tech /home/bob

# Add group "temps" to /etc/group.
groupadd temps

# Add user "xed" to group "temps" and remove from all other groups.
usermod -G temps xed

# Add user "xed" to group "temps".
gpasswd -a xed temps
### When adding groups, any of the user's currently logged in sessions
### will not know about the new group memberships! It is wise for the user
### in question to log out of everything completely and re-login again to
### notice the effects of the new group membership status.

# Check groups that xed is in (when logged in as xed).
# Note that new groups show up only after re-login!!!
   $ whoami
   $ groups
        wheel audio jcsg
   $ groups xed             # So specify an explicit user.
        wheel audio usb jcsg temps
   $ su xed -
   $ groups
        wheel audio usb jcsg temps

# Oh this is nice.... :-p
tech@mindnoise $ groups
    jcsg temps
tech@mindnoise $ groups tech
    temps jcsg

# Delete user "xed" from group "temps".
gpasswd -d xed temps

# Delete group "temps".
groupdel temps

# Delete user "tech" and remove "tech" from all group membership.
userdel tech                                    # Saves files!

# Delete user "tech" and remove from groups, delete home dir tree.
userdel -r tech                                 # Deletes files!

# Delete files of user already gone from /etc/passwd.
useradd tech; userdel -r tech

# These commands help run things with different "real group ID".

Other handy user/group commands to be aware of

  • /usr/sbin/groupmod - Can change names or ids of groups.

  • /usr/sbin/grpck - Checks the /etc/group for sanity.

  • /usr/sbin/pwck - Checks the /etc/passwd file for sanity.

  • /usr/sbin/grpunconv - Unconvert from group shadow passwords.

  • /usr/sbin/grpconv - Convert to group shadow passwords.

  • /usr/sbin/pwconv - Convert to shadaw passwords.

  • /usr/sbin/pwunconv - Unconvert from shadow passwords.

Fixing Corrupted Permissions

Did a chmod command go awry? Did you just mess up a lot of permissions and need a way to carefully put them back. The basic strategy is to use the find command to look for a certain specific signature of permissions that are wrong and the exec sub directive to chmod them back. Here’s how to fix an example where g+rwx was mistakenly applied to a directory tree. First we cure the case where the group can write and execute but the owner can’t which is generally a mistake:

find /xed -perm /g+w -and \! -perm /u+w -exec chmod g-w '{}' ';'
find /xed -perm /g+x -and \! -perm /u+x -exec chmod g-x '{}' ';'

The harder problem here is which private files can the group now read or write that the owner didn’t want to make so public. Those have to be addressed specifically. But here’s how you find them:

find /xed -perm /g+r -and \! -perm /o+r -exec ls -l '{}' ';'
find /xed -perm /g+w -and \! -perm /o+w -exec ls -l '{}' ';'

ACL And The Mystery Dot

From CentOS 5 to CentOS 6 a strange thing happened. When listing files, the permission string seems to have picked up a trailing dot. This looks like this:

-rw-r--r--. 1 root root 53 Jul  2 19:16 /etc/issue

Notice the dot in the 11th column. What is it? Why wasn’t it there in CentOS 5 (or any other distribution I have been using)? Turns out that it’s an explicit declaration of the status of how the ACL (access control list) is set. Here’s a good explanation of it. Also you can look at man getfacl and man setfacl. There are rumors that this is also an artifact of SELinux voodoo.

This is related to the mystery @ found in the same place when using the Mac OSX ls command. There it means that the file has "extended attributes". These can be checked with ls -@. If the file has "extended security information" (ACL) it will have a + in that location of the ls output.

i.F.A.Q. (inFrequently Asked Questions)

What permissions allow a file be deleted??

When the user who wants to do the deleting has write permission on the directory where the file to be deleted lives. The permissions of the file itself do not matter (though you might get a warning confirmation request if the file has no write permissions).

What happens if a group is deleted that is a user’s primary group??

Good question. Don’t know the answer.

Can anyone besides the superuser do a chown??

Not exactly. Effectively, however, it is possible if a user wants to change a file’s owner from someone else to himself. For this, the user must have read access to the file and write access in the directory the file lives in. Here is a little bash script that does this trick.

    /bin/cp -a $1 $1.NEW; /bin/mv $1.NEW $1
Can anyone besides the superuser allow membership into a group??

(Unconfirmed guess - dependent on the perms of /etc/group???)

What permissions are required to "chmod" a file??

If you own it, then 0000 is ok (if it’s a directory and you’re in it, you can block yourself from further meddling - just cd out of it and you can do what needs to be done).

What permissions are required to "touch" a file??

If you own it, then 0000 is ok. If you don’t own it and are NOT in its group, then 0002 is sufficient. 0020 works if you’re in the group, but 0002 does not. Looks like the same is true for directories.

Can being a member of the file’s group block access??


-------rw-  1 notme nonmember  438 Dec 12 08:34 IamNOTinitsgroup
-------rw-  1 notme member     292 Dec 12 08:32 Iaminitsgroup
$ echo >> IamNOTinitsgroup      # This is ok!
$ echo >> Iaminitsgroup         # Permission denied!
What happens to hard linked files when the permission of one is changed??

The other one is changed too. The same is true for "touch".

What does a plus mean at the end of a permission string??

Here’s what that looks like.

-rw-r--r--+  1 xed   alab 4.9M Apr 25 11:51 j27k_CAT_ms.icb

It seems that this is related to security issues. From the ls man page: "If the file or directory has extended security information, the permissions field printed by the -l option is followed by a + character." Note however, that I have seen this with NFS where it spontaneously just went away.

What if the permissions are scrupulously correct but the system still refuses to honor them?

I have had the situation where the executable permission look like this but it will produce a "Permission denied" error when executed.

-rwxr-xr-x.  1 root root 3.0M Sep 29 12:01 theprogram*

There are two places to look. If the file command shows the program to be an ASCII script, the error may be produced within the script. If that is not the case and there is no reason this should not run, check carefully that your mount options are correct for execution. In /etc/fstab, the options word defaults is the same as rw,suid,dev,exec,auto,nouser,async. Make sure you didn’t remove both the defaults and the exec. There is also a permissions option to consider.