diff options
Diffstat (limited to 'lib-src/update-game-score.c')
-rw-r--r-- | lib-src/update-game-score.c | 33 |
1 files changed, 19 insertions, 14 deletions
diff --git a/lib-src/update-game-score.c b/lib-src/update-game-score.c index d3354af2783..4f154832c81 100644 --- a/lib-src/update-game-score.c +++ b/lib-src/update-game-score.c @@ -21,8 +21,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ /* This program allows a game to securely and atomically update a - score file. It should be installed setuid, owned by an appropriate - user like `games'. + score file. It should be installed either setuid or setgid, owned + by an appropriate user or group like `games'. Alternatively, it can be compiled without HAVE_SHARED_GAME_DIR defined, and in that case it will store scores in the user's home @@ -88,7 +88,7 @@ static int push_score (struct score_entry **scores, ptrdiff_t *count, ptrdiff_t *size, struct score_entry const *newscore); static void sort_scores (struct score_entry *scores, ptrdiff_t count, bool reverse); -static int write_scores (const char *filename, +static int write_scores (const char *filename, mode_t mode, const struct score_entry *scores, ptrdiff_t count); static _Noreturn void @@ -122,18 +122,19 @@ get_user_id (void) } static const char * -get_prefix (bool running_suid, const char *user_prefix) +get_prefix (bool privileged, const char *user_prefix) { - if (!running_suid && user_prefix == NULL) - lose ("Not using a shared game directory, and no prefix given."); - if (running_suid) + if (privileged) { #ifdef HAVE_SHARED_GAME_DIR return HAVE_SHARED_GAME_DIR; #else - lose ("This program was compiled without HAVE_SHARED_GAME_DIR,\n and should not be suid."); + lose ("This program was compiled without HAVE_SHARED_GAME_DIR,\n" + "and should not run with elevated privileges."); #endif } + if (user_prefix == NULL) + lose ("Not using a shared game directory, and no prefix given."); return user_prefix; } @@ -173,7 +174,7 @@ int main (int argc, char **argv) { int c; - bool running_suid; + bool running_suid, running_sgid; void *lockstate; char *scorefile; char *end, *nl, *user, *data; @@ -214,8 +215,11 @@ main (int argc, char **argv) usage (EXIT_FAILURE); running_suid = (getuid () != geteuid ()); + running_sgid = (getgid () != getegid ()); + if (running_suid && running_sgid) + lose ("This program can run either suid or sgid, but not both."); - prefix = get_prefix (running_suid, user_prefix); + prefix = get_prefix (running_suid || running_sgid, user_prefix); scorefile = malloc (strlen (prefix) + strlen (argv[optind]) + 2); if (!scorefile) @@ -270,7 +274,8 @@ main (int argc, char **argv) scores += scorecount - max_scores; scorecount = max_scores; } - if (write_scores (scorefile, scores, scorecount) < 0) + if (write_scores (scorefile, running_sgid ? 0664 : 0644, + scores, scorecount) < 0) { unlock_file (scorefile, lockstate); lose_syserr ("Failed to write scores file"); @@ -421,8 +426,8 @@ sort_scores (struct score_entry *scores, ptrdiff_t count, bool reverse) } static int -write_scores (const char *filename, const struct score_entry *scores, - ptrdiff_t count) +write_scores (const char *filename, mode_t mode, + const struct score_entry *scores, ptrdiff_t count) { int fd; FILE *f; @@ -435,7 +440,7 @@ write_scores (const char *filename, const struct score_entry *scores, if (fd < 0) return -1; #ifndef DOS_NT - if (fchmod (fd, 0644) != 0) + if (fchmod (fd, mode) != 0) return -1; #endif f = fdopen (fd, "w"); |