From 4f405b77ce9cf27bca7384ad539f0ec93dbb085c Mon Sep 17 00:00:00 2001 From: Michael Meyer Date: Fri, 20 Oct 2023 13:26:54 -0400 Subject: [PATCH 1/4] Remove pw check in authorize_wizard_mode Now that CHECK_PLNAME is a sysconf option, it can be possible to authorize wizard mode even if get_unix_pw() fails to return the user's login name, so I think the call to check_user_string() should go out either way in case that's what's happening. --- sys/libnh/libnhmain.c | 4 +--- sys/unix/unixmain.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/sys/libnh/libnhmain.c b/sys/libnh/libnhmain.c index 40be3b467..41669033b 100644 --- a/sys/libnh/libnhmain.c +++ b/sys/libnh/libnhmain.c @@ -597,9 +597,7 @@ port_help(void) boolean authorize_wizard_mode(void) { - struct passwd *pw = get_unix_pw(); - - if (pw && sysopt.wizards && sysopt.wizards[0]) { + if (sysopt.wizards && sysopt.wizards[0]) { if (check_user_string(sysopt.wizards)) return TRUE; } diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index 2b041d0e8..56f567a46 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -956,9 +956,7 @@ port_help(void) boolean authorize_wizard_mode(void) { - struct passwd *pw = get_unix_pw(); - - if (pw && sysopt.wizards && sysopt.wizards[0]) { + if (sysopt.wizards && sysopt.wizards[0]) { if (check_user_string(sysopt.wizards)) return TRUE; } From 85b727c92cd730de0fc3ed108b1ef46e7d770345 Mon Sep 17 00:00:00 2001 From: Michael Meyer Date: Fri, 20 Oct 2023 13:48:15 -0400 Subject: [PATCH 2/4] Apply sysconf EXPLORERS restriction on startup The sysconf EXPLORERS list restricting access to explore mode was being evaluated and used when a player used the #exploremode command in-game, or when specifying -X or OPTIONS=playmode:explore on the command line when resuming a normal game, but not when starting an entirely new game. When SYSCF is avilable, check for authorization early, similar to debug mode authorization, to restrict access to explore mode to EXPLORERS under (hopefully) all circumstances. --- include/extern.h | 3 +++ src/cmd.c | 7 +------ src/options.c | 7 +++++-- src/restore.c | 4 ++-- sys/libnh/libnhmain.c | 30 +++++++++++++++++++++++++++--- sys/share/pcmain.c | 7 +++++++ sys/unix/unixmain.c | 30 +++++++++++++++++++++++++++--- sys/vms/vmsmain.c | 7 +++++++ sys/windows/windmain.c | 7 +++++++ 9 files changed, 86 insertions(+), 16 deletions(-) diff --git a/include/extern.h b/include/extern.h index 02d7f3b31..604b341c9 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2123,6 +2123,7 @@ extern int dohistory(void); extern void chdirx(char *, boolean); #endif /* CHDIR */ extern boolean authorize_wizard_mode(void); +extern boolean authorize_explore_mode(void); #endif #if defined(WIN32) extern int getlock(void); @@ -3100,6 +3101,7 @@ extern void port_help(void); #endif extern void sethanguphandler(void(*)(int)); extern boolean authorize_wizard_mode(void); +extern boolean authorize_explore_mode(void); extern void append_slash(char *); extern boolean check_user_string(const char *); extern char *get_login_name(void); @@ -3264,6 +3266,7 @@ extern void chdirx(const char *, boolean); #endif /* CHDIR */ extern void sethanguphandler(void(*)(int)); extern boolean authorize_wizard_mode(void); +extern boolean authorize_explore_mode(void); /* ### vmsmisc.c ### */ diff --git a/src/cmd.c b/src/cmd.c index a823b7486..941d71822 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -965,10 +965,7 @@ enter_explore_mode(void) } else { const char *oldmode = !wizard ? "normal game" : "debug mode"; -#ifdef SYSCF -#if defined(UNIX) - if (!sysopt.explorers || !sysopt.explorers[0] - || !check_user_string(sysopt.explorers)) { + if (!authorize_explore_mode()) { if (!wizard) { You("cannot access explore mode."); return ECMD_OK; @@ -978,8 +975,6 @@ enter_explore_mode(void) /* keep going */ } } -#endif -#endif pline("Beware! From explore mode there will be no return to %s,", oldmode); if (paranoid_query(ParanoidQuit, diff --git a/src/options.c b/src/options.c index 7354481f3..e8ffe174b 100644 --- a/src/options.c +++ b/src/options.c @@ -10257,11 +10257,14 @@ set_playmode(void) gp.plnamelen = (int) strlen(strcpy(gp.plname, "wizard")); else wizard = FALSE; /* not allowed or not available */ - /* force explore mode if we didn't make it into wizard mode */ + /* try explore mode if we didn't make it into wizard mode */ discover = !wizard; iflags.deferred_X = FALSE; } - /* don't need to do anything special for explore mode or normal play */ + if (discover && !authorize_explore_mode()) { + discover = iflags.deferred_X = FALSE; + } + /* don't need to do anything special for normal play */ } static void diff --git a/src/restore.c b/src/restore.c index fc475f9d3..d154a99b6 100644 --- a/src/restore.c +++ b/src/restore.c @@ -560,8 +560,8 @@ restgamestate(NHFILE *nhfp) if (newgameflags.debug) { /* authorized by startup code; wizard mode exists and is allowed */ wizard = TRUE, discover = iflags.deferred_X = FALSE; - } else if (wizard) { - /* specified by save file; check authorization now */ + } else if (wizard || discover) { + /* specified by save file; check authorization now. */ set_playmode(); } role_init(); /* Reset the initial role, race, gender, and alignment */ diff --git a/sys/libnh/libnhmain.c b/sys/libnh/libnhmain.c index 41669033b..5770c5c4e 100644 --- a/sys/libnh/libnhmain.c +++ b/sys/libnh/libnhmain.c @@ -50,7 +50,7 @@ extern void init_linux_cons(void); #endif static void wd_message(void); -static boolean wiz_error_flag = FALSE; +static boolean wiz_error_flag = FALSE, explore_error_flag = FALSE; static struct passwd *get_unix_pw(void); #ifdef __EMSCRIPTEN__ @@ -605,6 +605,22 @@ authorize_wizard_mode(void) return FALSE; } +/* similar to above, validate explore mode access */ +boolean +authorize_explore_mode(void) +{ +#ifdef SYSCF + if (sysopt.explorers && sysopt.explorers[0]) { + if (check_user_string(sysopt.explorers)) + return TRUE; + } + explore_error_flag = TRUE; /* not being allowed into explore mode */ + return FALSE; +#else + return TRUE; /* if sysconf disabled, no restrictions on explore mode */ +#endif +} + static void wd_message(void) { @@ -614,9 +630,17 @@ wd_message(void) pline("Only user%s %s may access debug (wizard) mode.", strchr(sysopt.wizards, ' ') ? "s" : "", tmp); free(tmp); - } else + } else { + You("cannot access debug (wizard) mode."); + } + wizard = 0; /* (paranoia) */ + if (!explore_error_flag) { pline("Entering explore/discovery mode instead."); - wizard = 0, discover = 1; /* (paranoia) */ + discover = 1; + } + } else if (explore_error_flag) { + You("cannot access explore mode."); /* same as enter_explore_mode */ + discover = 0; /* (more paranoia) */ } else if (discover) You("are in non-scoring explore/discovery mode."); } diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index 5706651be..3744ee490 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -720,6 +720,13 @@ authorize_wizard_mode(void) return FALSE; } +/* similar to above, validate explore mode access */ +boolean +authorize_explore_mode(void) +{ + return TRUE; /* no restrictions on explore mode */ +} + #ifdef EXEPATH #ifdef __DJGPP__ #define PATH_SEPARATOR '/' diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index 56f567a46..2da764cae 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -53,7 +53,7 @@ extern void init_linux_cons(void); #endif static void wd_message(void); -static boolean wiz_error_flag = FALSE; +static boolean wiz_error_flag = FALSE, explore_error_flag = FALSE; static struct passwd *get_unix_pw(void); int @@ -964,6 +964,22 @@ authorize_wizard_mode(void) return FALSE; } +/* similar to above, validate explore mode access */ +boolean +authorize_explore_mode(void) +{ +#ifdef SYSCF + if (sysopt.explorers && sysopt.explorers[0]) { + if (check_user_string(sysopt.explorers)) + return TRUE; + } + explore_error_flag = TRUE; /* not being allowed into explore mode */ + return FALSE; +#else + return TRUE; /* if sysconf disabled, no restrictions on explore mode */ +#endif +} + static void wd_message(void) { @@ -973,9 +989,17 @@ wd_message(void) pline("Only user%s %s may access debug (wizard) mode.", strchr(sysopt.wizards, ' ') ? "s" : "", tmp); free(tmp); - } else + } else { + You("cannot access debug (wizard) mode."); + } + wizard = 0; /* (paranoia) */ + if (!explore_error_flag) { pline("Entering explore/discovery mode instead."); - wizard = 0, discover = 1; /* (paranoia) */ + discover = 1; + } + } else if (explore_error_flag) { + You("cannot access explore mode."); /* same as enter_explore_mode */ + discover = 0; /* (more paranoia) */ } else if (discover) You("are in non-scoring explore/discovery mode."); } diff --git a/sys/vms/vmsmain.c b/sys/vms/vmsmain.c index 7dd2536f9..4e7c6ab89 100644 --- a/sys/vms/vmsmain.c +++ b/sys/vms/vmsmain.c @@ -484,6 +484,13 @@ authorize_wizard_mode(void) return FALSE; } +/* similar to above, validate explore mode access */ +boolean +authorize_explore_mode(void) +{ + return TRUE; /* no restrictions on explore mode */ +} + static void wd_message(void) { diff --git a/sys/windows/windmain.c b/sys/windows/windmain.c index 5966615b4..0be7ef9cd 100644 --- a/sys/windows/windmain.c +++ b/sys/windows/windmain.c @@ -1021,6 +1021,13 @@ authorize_wizard_mode(void) return FALSE; } +/* similar to above, validate explore mode access */ +boolean +authorize_explore_mode(void) +{ + return TRUE; /* no restrictions on explore mode */ +} + #define PATH_SEPARATOR '\\' #if defined(WIN32) && !defined(WIN32CON) From 1e237e4b8f576aba2dda56db7992dd19b535a6e8 Mon Sep 17 00:00:00 2001 From: Michael Meyer Date: Fri, 20 Oct 2023 14:37:58 -0400 Subject: [PATCH 3/4] Fix: shunt to explore mode after wizmode auth fail If an unauthorized player requests the game launch in wizard mode, it will try to put her in explore mode instead. If this happened during restoration of a previous (normal) saved game, the setting of discover in wd_message() would bypass iflags.deferred_X, allowing the player to select to keep the non-explore-mode save file. [Actually, when I tested it I always got an error when answering yes to the "keep the save file?" prompt, but that's a problem too...] Because deferred_X was still 1 after this, the pline "You are already in explore mode" would also be printed following the prompt (when moveloop_preamble() attempted to set explore mode). Fix this so that loading a normal game with -D, then failing the authorization, boots into explore mode via iflags.deferred_X and the "really enter explore mode?" prompt, as it would have if -X were specified on the command line to begin with. --- src/options.c | 4 +++- sys/libnh/libnhmain.c | 8 +++----- sys/unix/unixmain.c | 8 +++----- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/options.c b/src/options.c index e8ffe174b..d23a1a01d 100644 --- a/src/options.c +++ b/src/options.c @@ -10258,8 +10258,10 @@ set_playmode(void) else wizard = FALSE; /* not allowed or not available */ /* try explore mode if we didn't make it into wizard mode */ + /* if requesting wizard mode when restoring a normal game, this will + set iflags.deferred_X and prompt to activate explore mode after the + save file has already been deleted */ discover = !wizard; - iflags.deferred_X = FALSE; } if (discover && !authorize_explore_mode()) { discover = iflags.deferred_X = FALSE; diff --git a/sys/libnh/libnhmain.c b/sys/libnh/libnhmain.c index 5770c5c4e..d7d757cd3 100644 --- a/sys/libnh/libnhmain.c +++ b/sys/libnh/libnhmain.c @@ -633,14 +633,12 @@ wd_message(void) } else { You("cannot access debug (wizard) mode."); } - wizard = 0; /* (paranoia) */ - if (!explore_error_flag) { + wizard = FALSE; /* (paranoia) */ + if (!explore_error_flag) pline("Entering explore/discovery mode instead."); - discover = 1; - } } else if (explore_error_flag) { You("cannot access explore mode."); /* same as enter_explore_mode */ - discover = 0; /* (more paranoia) */ + discover = iflags.deferred_X = FALSE; /* (more paranoia) */ } else if (discover) You("are in non-scoring explore/discovery mode."); } diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index 2da764cae..ec039ddf7 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -992,14 +992,12 @@ wd_message(void) } else { You("cannot access debug (wizard) mode."); } - wizard = 0; /* (paranoia) */ - if (!explore_error_flag) { + wizard = FALSE; /* (paranoia) */ + if (!explore_error_flag) pline("Entering explore/discovery mode instead."); - discover = 1; - } } else if (explore_error_flag) { You("cannot access explore mode."); /* same as enter_explore_mode */ - discover = 0; /* (more paranoia) */ + discover = iflags.deferred_X = FALSE; /* (more paranoia) */ } else if (discover) You("are in non-scoring explore/discovery mode."); } From b993edca74d850965cdd0aa1ab8a5e25b6152266 Mon Sep 17 00:00:00 2001 From: Michael Meyer Date: Mon, 23 Oct 2023 21:44:41 -0400 Subject: [PATCH 4/4] Follow-ups on EXPLORERS authorization I realized that failed explore-mode authorization on a special-mode saved game cannot downgrade the game mode further down to a normal game, because this would dump the player back into a state where she has completed some part of the game in explore mode but is eligible for the topten list. This is even more true when the game was formerly a wizard-mode game. Unforunately, that was the state my previous commits left the game in. Instead, if restoring an explore-mode or wizard-mode savegame, and the player is authorized via sysconf for neither of those modes, fail restoration entirely and start a new game instead. That's sort of clunky and there could probably be more explanation provided, but it should be an exceedingly rare occurance and I'm not sure what alternative exists that would still honor the EXPLORERS and WIZARDS restrictions. This shouldn't affect the way they default 'down a mode' in other circumstances, i.e. the overwhelming majority of situations in which EXPLORERS authorization is needed/checked. For the same reason, I realized that the player can't be prompted whether or not to enter explore mode, if being downgraded from a no-longer-authorized wizmode save while explore mode is authorized. The change from wizard mode to explore mode must be mandatory. I have also switched that up so that it will force the change -- unfortunately, this has the side effect of allowing the preservation of the save, but it's more important to make sure a wizard mode game doesn't get reverted to normal mode. They won't be able to load the save into wizard mode anyway. --- include/flag.h | 2 ++ src/options.c | 1 + src/restore.c | 12 ++++++++++-- sys/libnh/libnhmain.c | 11 +++++------ sys/unix/unixmain.c | 11 +++++------ 5 files changed, 23 insertions(+), 14 deletions(-) diff --git a/include/flag.h b/include/flag.h index 7338f027e..4b8557793 100644 --- a/include/flag.h +++ b/include/flag.h @@ -412,6 +412,8 @@ struct instance_flags { chosen_windowport[], but do not switch to it in the midst of options processing */ genericptr_t returning_missile; /* 'struct obj *'; Mjollnir or aklys */ + boolean wiz_error_flag; /* flag for tracking failed wizmode auth */ + boolean explore_error_flag; /* ditto for explore mode */ boolean obsolete; /* obsolete options can point at this, it isn't used */ }; diff --git a/src/options.c b/src/options.c index d23a1a01d..d939b3dd4 100644 --- a/src/options.c +++ b/src/options.c @@ -10262,6 +10262,7 @@ set_playmode(void) set iflags.deferred_X and prompt to activate explore mode after the save file has already been deleted */ discover = !wizard; + iflags.deferred_X = FALSE; } if (discover && !authorize_explore_mode()) { discover = iflags.deferred_X = FALSE; diff --git a/src/restore.c b/src/restore.c index d154a99b6..6570ddbfc 100644 --- a/src/restore.c +++ b/src/restore.c @@ -512,7 +512,7 @@ restgamestate(NHFILE *nhfp) struct obj *bc_obj; char timebuf[15]; unsigned long uid = 0; - boolean defer_perm_invent; + boolean defer_perm_invent, restoring_special; if (nhfp->structlevel) Mread(nhfp->fd, &uid, sizeof uid); @@ -557,10 +557,11 @@ restgamestate(NHFILE *nhfp) in the discover case, we don't want to set that for a normal game until after the save file has been removed */ iflags.deferred_X = (newgameflags.explore && !discover); + restoring_special = (wizard || discover); if (newgameflags.debug) { /* authorized by startup code; wizard mode exists and is allowed */ wizard = TRUE, discover = iflags.deferred_X = FALSE; - } else if (wizard || discover) { + } else if (restoring_special) { /* specified by save file; check authorization now. */ set_playmode(); } @@ -572,6 +573,13 @@ restgamestate(NHFILE *nhfp) Mread(nhfp->fd, &u, sizeof u); gy.youmonst.cham = u.mcham; + if (restoring_special && iflags.explore_error_flag) { + /* savefile has wizard or explore mode, but player is no longer + authorized to access either; can't downgrade mode any further, so + fail restoration. */ + u.uhp = 0; + } + if (nhfp->structlevel) Mread(nhfp->fd, timebuf, 14); timebuf[14] = '\0'; diff --git a/sys/libnh/libnhmain.c b/sys/libnh/libnhmain.c index d7d757cd3..631b9152c 100644 --- a/sys/libnh/libnhmain.c +++ b/sys/libnh/libnhmain.c @@ -50,7 +50,6 @@ extern void init_linux_cons(void); #endif static void wd_message(void); -static boolean wiz_error_flag = FALSE, explore_error_flag = FALSE; static struct passwd *get_unix_pw(void); #ifdef __EMSCRIPTEN__ @@ -601,7 +600,7 @@ authorize_wizard_mode(void) if (check_user_string(sysopt.wizards)) return TRUE; } - wiz_error_flag = TRUE; /* not being allowed into wizard mode */ + iflags.wiz_error_flag = TRUE; /* not being allowed into wizard mode */ return FALSE; } @@ -614,7 +613,7 @@ authorize_explore_mode(void) if (check_user_string(sysopt.explorers)) return TRUE; } - explore_error_flag = TRUE; /* not being allowed into explore mode */ + iflags.explore_error_flag = TRUE; /* not allowed into explore mode */ return FALSE; #else return TRUE; /* if sysconf disabled, no restrictions on explore mode */ @@ -624,7 +623,7 @@ authorize_explore_mode(void) static void wd_message(void) { - if (wiz_error_flag) { + if (iflags.wiz_error_flag) { if (sysopt.wizards && sysopt.wizards[0]) { char *tmp = build_english_list(sysopt.wizards); pline("Only user%s %s may access debug (wizard) mode.", @@ -634,9 +633,9 @@ wd_message(void) You("cannot access debug (wizard) mode."); } wizard = FALSE; /* (paranoia) */ - if (!explore_error_flag) + if (!iflags.explore_error_flag) pline("Entering explore/discovery mode instead."); - } else if (explore_error_flag) { + } else if (iflags.explore_error_flag) { You("cannot access explore mode."); /* same as enter_explore_mode */ discover = iflags.deferred_X = FALSE; /* (more paranoia) */ } else if (discover) diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index ec039ddf7..122c2a96d 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -53,7 +53,6 @@ extern void init_linux_cons(void); #endif static void wd_message(void); -static boolean wiz_error_flag = FALSE, explore_error_flag = FALSE; static struct passwd *get_unix_pw(void); int @@ -960,7 +959,7 @@ authorize_wizard_mode(void) if (check_user_string(sysopt.wizards)) return TRUE; } - wiz_error_flag = TRUE; /* not being allowed into wizard mode */ + iflags.wiz_error_flag = TRUE; /* not being allowed into wizard mode */ return FALSE; } @@ -973,7 +972,7 @@ authorize_explore_mode(void) if (check_user_string(sysopt.explorers)) return TRUE; } - explore_error_flag = TRUE; /* not being allowed into explore mode */ + iflags.explore_error_flag = TRUE; /* not allowed into explore mode */ return FALSE; #else return TRUE; /* if sysconf disabled, no restrictions on explore mode */ @@ -983,7 +982,7 @@ authorize_explore_mode(void) static void wd_message(void) { - if (wiz_error_flag) { + if (iflags.wiz_error_flag) { if (sysopt.wizards && sysopt.wizards[0]) { char *tmp = build_english_list(sysopt.wizards); pline("Only user%s %s may access debug (wizard) mode.", @@ -993,9 +992,9 @@ wd_message(void) You("cannot access debug (wizard) mode."); } wizard = FALSE; /* (paranoia) */ - if (!explore_error_flag) + if (!iflags.explore_error_flag) pline("Entering explore/discovery mode instead."); - } else if (explore_error_flag) { + } else if (iflags.explore_error_flag) { You("cannot access explore mode."); /* same as enter_explore_mode */ discover = iflags.deferred_X = FALSE; /* (more paranoia) */ } else if (discover)