commit 0725a74c6c03ed0c50b100026f7163eb7887ec38 from: Markus Uhlin via: GitHub date: Sat Aug 16 22:49:25 2025 UTC Potential fix for code scanning alert no. 6: Uncontrolled data used in path expression Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> commit - 953390185b209ae9115228e09215cac61c008711 commit + 0725a74c6c03ed0c50b100026f7163eb7887ec38 blob - 1981c1422ee6ed11f45624514978c8a92fb8204e blob + 6aaa66f66c88293911d6d0f23d1311ce4e8a8415 --- FICS/gamedb.c +++ FICS/gamedb.c @@ -1619,29 +1619,38 @@ game_save(int g) return 0; } -PRIVATE long int -OldestHistGame(char *login) +/* Helper function to validate login names for file path usage */ +static int +is_valid_login_name(const char *login) { - FILE *fp; - char pFile[MAX_FILENAME_SIZE] = { '\0' }; - long int when; - - /* Validate login to prevent path traversal and restrict to safe characters */ if (login == NULL || login[0] == '\0' || strstr(login, "..") || strchr(login, '/') || strchr(login, '\\')) { - warnx("%s: invalid login value: '%s'", __func__, login); - return 0L; + return 0; } for (const char *p = login; *p; ++p) { if (!((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == '_')) { - warnx("%s: invalid character in login: '%s'", __func__, login); - return 0L; + return 0; } } + return 1; +} +PRIVATE long int +OldestHistGame(char *login) +{ + FILE *fp; + char pFile[MAX_FILENAME_SIZE] = { '\0' }; + long int when; + + /* Centralized validation of login */ + if (!is_valid_login_name(login)) { + warnx("%s: invalid login value: '%s'", __func__, login); + return 0L; + } + msnprintf(pFile, sizeof pFile, "%s/player_data/%c/%s.%s", stats_dir, login[0], login, STATS_GAMES); @@ -1735,31 +1744,13 @@ RemHist(char *who) stolower(Opp); - if (strstr(Opp, "..") || - strchr(Opp, '/') || - strchr(Opp, '\\')) { - warnx("%s: invalid value: " - "Opp = '%s' (skipping)", __func__, Opp); + /* Centralized validation: only allow safe login names */ + if (!is_valid_login_name(Opp)) { + warnx("%s: invalid value: Opp = '%s' (skipping)", __func__, Opp); iter_no++; continue; } - /* - * Additional validation: only allow - * alphanumeric and underscores - */ - for (const char *p = Opp; *p; ++p) { - if (!((*p >= 'a' && *p <= 'z') || - (*p >= 'A' && *p <= 'Z') || - (*p >= '0' && *p <= '9') || - *p == '_')) { - warnx("%s: invalid characters found: " - "Opp = '%s' (skipping)", __func__, - Opp); - goto next_iter; - } - } - oppWhen = OldestHistGame(Opp); if (oppWhen > When || oppWhen <= 0L) {