A typical setuid program does not need its special access all of the
time. It's a good idea to turn off this access when it isn't needed,
so it can't possibly give unintended access.
If the system supports the _POSIX_SAVED_IDS feature, you can
accomplish this with seteuid. When the game program starts, its
real user ID is jdoe, its effective user ID is games, and
its saved user ID is also games. The program should record both
user ID values once at the beginning, like this:
Throughout this process, the real user ID remains jdoe and the
file user ID remains games, so the program can always set its
effective user ID to either one.
On other systems that don't support file user IDs, you can
turn setuid access on and off by using setreuid to swap the real
and effective user IDs of the process, as follows:
setreuid (geteuid (), getuid ());
This special case is always allowed—it cannot fail.
Why does this have the effect of toggling the setuid access? Suppose a
game program has just started, and its real user ID is jdoe while
its effective user ID is games. In this state, the game can
write the scores file. If it swaps the two uids, the real becomes
games and the effective becomes jdoe; now the program has
only jdoe access. Another swap brings games back to
the effective user ID and restores access to the scores file.
In order to handle both kinds of systems, test for the saved user ID
feature with a preprocessor conditional, like this: