Many other excellent answers here, but if you're still confused as I was, here's another approach. Please note that I am only a student of this stuff, not a master, so this answer is a work in progress, and not to be considered a solid answer, at least not yet. Consider this answer v0.2.
Groups are simple and complex at the same time.
Key to IDs used below:
KEY Full name -------- Description---------------------------------------------
u User uID = User ID (a unique # associated with each user)
g Group gID = Group ID (a unique # associated with each group)
While each /etc/passwd entry has one uID and one gID,
additional gIDs can be associated with a users via
/etc/group.
L Login IDs - uID and gID produced from the Login process.
('L' is not exactly standard Linux terminology, but
useful for explanations below.)
F File IDs - uID and gID retrieved from a file's ownership.
('F' is not exactly standard Linux terminology, but
useful for explanations below.)
R Real IDs - Who actually runs a process
E Effective IDs - Who spoofed via setuid or setgid, runs a process
O Original Eff. IDs - Place to save the original Effective ID when changing
it (e.g. temporarily downgrading it) so can later
restore it. Also called "Saved ID"; (but 'S' was not
used for here to help avoid confusion with the 'S' in
'SetUserID' & SetGroupID.)
+ Supplimentary gIDs - Optional, additional groups (none or more) running
this process which can be used to test for permissions.
User and Group ID names:
Category USER GROUP Notes
----------------- ---- ----- -------------------------------------------
From login: LuID LgID From /etc/passwd lookup
From files: FuID FgID Each file has these. Set by creator process.
For each running process:
Real RuID RgID Actual user starting the program
Effective EuID EgID Assigned user starting the program*
Saved OuID OgID Saves original effective ID.
Supplementary +gID1 (optional, additional groups)
+gID2
...
How processes acquire IDs:
1) Login authenticates username and returns LuID
and LgID
from /etc/passwd
.
2) The first process sets up effective=real=login, i.e.
EuID=RuID=LuID
EgID=RgID=LgID
3) Forked children inherit RuID
, EuID
, RgID
, and EgID
, (& possibly saved & supp), however,
If the suid bit (s) is set on the file of the new program to execute, then set effective from file:
EuID=FuID
If the sgid bit (s) is set on the file of the new program to execute, then set effective from file:
EgID=FgID
Note: The underlying filesystem's suid and nosuid mount options also apply.
4a) If suid was used to set EuID
, then EuID
can be temporarily changed (e.g. downgraded from root), but first it's original value is saved in OuID
so it can be restored later if desired.
4b) If sgid was used to set EgID
, then EgID
can be temporarily changed (e.g. downgraded from root), but first it's original value is saved in OgID
so it can be restored later if desired.
When a file is to be created:
File's new id's are set from effective id's: FuID=EuID and FgID=EgID
(Permissions are set from umask.)
To open for reading:
If FuID = EuID and user-read bit is set, or
If FgID = EgID and group-read bit is set, or
If FgID = +gID1 and group-read bit is set, or
If FgID = +gID2 and group-read bit is set, ...
then allow reading.
To open for writing:
(Same as above but write bit set to allow writing.)
To open for execution:
(Same as above but execute bit set to allow execution.)
When a message needs to be sent:
Use RuID and RgID. (Not EuID or EgID). *(Not sure where I read this.)*
References: man credentials
Extra: Here is a utility to pretty print your /etc/group file:
cat /etc/group | sort -t: -k3n | awk -F ':' \
'BEGIN{printf "\n%-20s %-3s %-8s %s", \
"Group name","pw", "Group ID ", "User list"}\
BEGIN{printf "\n%-20s %-3s %-8s %s\n", \
"----------","--", "---------", "---------"} \
{ printf "%-20s %-3s %8d %s\n", $1, $2, $3, $4 }'