mirror of
https://github.com/libretro/RetroArch.git
synced 2026-11-07 17:31:11 -10:00
smb2: publish loaded settings to the SMB backend, harden the pool paths
Commit e9f9dd443b moved retroarch_smb_init() to the top of rarch_main()
so the SMB backend has a registered configuration before anything can
touch an smb:// path. That intent is kept, but the move exposed an
asymmetry in the published struct: the string fields alias
settings->arrays and therefore follow every configuration load on their
own, while timeout, num_contexts and auth_mode are copied by value.
Since configuration loading happens later, inside retroarch_main_init(),
the numeric fields froze at the calloc-zero settings struct: the user's
configured values were never applied, the zero-fallbacks in smb_init()
always fired, and auth_mode always resolved to SEC_UNDEFINED, forcing
the KRB5/NTLMSSP probe on every first connection regardless of the
configured mode.
Reading the settings from inside the backend is not an option -
vfs_implementation_smb.c lives in libretro-common and must not depend
on RetroArch's configuration - so the fix is on the publisher side:
config_load_file() now re-publishes at its single success return, which
covers the main configuration, the salamander pass, appends and
per-core overrides alike, and keeps working if startup ordering changes
again. retroarch_smb_init() gains a declaration in retroarch.h (it had
none; configuration.c needs one) and comments documenting the
alias-vs-snapshot contract at both the definition and the declaration.
The early registration call stays. The SMB backend initializes lazily
on first smb:// access, which in every startup path happens after the
configuration has been loaded and re-published, so the correct values
are in place by the time the context pool is built.
Two hardenings in the backend paths this touches:
- reset() was a non-static function in a file that griffin.c includes
into the unity translation unit, i.e. a global symbol named 'reset'
waiting to collide at link time. Now static as smb_reset_pool(), with
the loop lowered to C89.
- smb_create_context(), used when healing a dead connection, applied
smb_cfg->timeout raw, without the zero fallback smb_init() applies,
so a healed context could be configured with timeout 0 where the
original pool got the default. Both paths now agree.
Verified offline before commit:
- Full Makefile build with --enable-builtinsmbclient (compiles the
backend, the vendored libsmb2 and the new hook), clean link, no new
warnings outside vendored deps; 'reset' no longer an exported symbol.
- Sanitizer sweep of the backend lifecycle: the translation unit linked
against scripted libsmb2 stubs (real vendored headers supply
prototypes and struct layouts, so signature drift is a compile
error), driven through nine scenarios via its public entry points:
unregistered config, empty server, normal init with explicit values
respected and round-robin use, zero num_contexts/timeout fallbacks,
the auth-probe path, context-creation failure mid-loop, connect
failure mid-loop, retry after failure, and re-publish with changed
values between init/shutdown cycles (the config_load_file refresh
this commit adds). ASan+UBSan+LSan clean, TSan clean, no leaks on
any failure path.
- Settings table drift check and griffin-order unity compile both
clean; the emitted configuration tables are unchanged.
Known limitations, unchanged by this commit: values only take effect
for contexts created after publication - the pool is not rebuilt when
settings change at runtime - and get_smb_context()'s round-robin index
is not synchronized, so concurrent VFS access from multiple threads can
hand the same non-thread-safe smb2_context to two callers. Both are
follow-up material.
This commit is contained in:
1 parent
558b24a685
commit
36766173e8
4 files changed
+50
-8
No files matched your search
@@ -7104,6 +7104,14 @@ static bool config_load_file(global_t *global,
|
||||
free(path_settings);
|
||||
if (size_settings)
|
||||
free(size_settings);
|
||||
#ifdef HAVE_SMBCLIENT
|
||||
/* Re-publish the SMB client settings: the numeric fields are
|
||||
* copied by value at publish time, so the values this load just
|
||||
* applied are not visible to the SMB backend until re-published.
|
||||
* Covers the main configuration, appends and per-core overrides
|
||||
* alike, since they all pass through here. */
|
||||
retroarch_smb_init();
|
||||
#endif
|
||||
first_load = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -89,7 +89,9 @@ static struct smb2_context *smb_create_context(void)
|
||||
smb2_set_password(ctx, smb_cfg->password);
|
||||
if (smb_cfg->workgroup && *smb_cfg->workgroup)
|
||||
smb2_set_domain(ctx, smb_cfg->workgroup);
|
||||
smb2_set_timeout(ctx, smb_cfg->timeout);
|
||||
/* Same fallback as smb_init(): 0 is not a valid timeout */
|
||||
smb2_set_timeout(ctx, (smb_cfg->timeout == 0)
|
||||
? RETRO_SMB2_DEFAULT_CLIENT_TIMEOUT : smb_cfg->timeout);
|
||||
smb2_set_security_mode(ctx, resolved_auth_mode);
|
||||
smb2_set_authentication(ctx, resolved_auth_mode);
|
||||
|
||||
@@ -131,11 +133,15 @@ static struct smb2_context *smb_heal_if_dead(struct smb2_context *ctx)
|
||||
return smb_heal_context(ctx);
|
||||
}
|
||||
|
||||
void reset(unsigned num_contexts)
|
||||
/* Static: this file is compiled into the griffin unity translation
|
||||
* unit, where a global named 'reset' is a link-time collision waiting
|
||||
* to happen. */
|
||||
static void smb_reset_pool(unsigned num_contexts)
|
||||
{
|
||||
for (unsigned i = 0; i < num_contexts; i++)
|
||||
unsigned i;
|
||||
for (i = 0; i < num_contexts; i++)
|
||||
{
|
||||
if(smb_context_pool[i])
|
||||
if (smb_context_pool[i])
|
||||
smb2_destroy_context(smb_context_pool[i]);
|
||||
}
|
||||
|
||||
@@ -197,7 +203,7 @@ static bool smb_init(void)
|
||||
if (!smb_context)
|
||||
{
|
||||
fprintf(stderr, "smb_init: error - no smb_context for %d\n", i);
|
||||
reset(max_context_configured);
|
||||
smb_reset_pool(max_context_configured);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -264,7 +270,7 @@ static bool smb_init(void)
|
||||
if (!smb_context)
|
||||
{
|
||||
fprintf(stderr, "smb_init - error - no context\n");
|
||||
reset(max_context_configured);
|
||||
smb_reset_pool(max_context_configured);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -303,7 +309,7 @@ static bool smb_init(void)
|
||||
{
|
||||
fprintf(stderr, "smb_init: error - failed to connect - error_no: %d\n", error_no);
|
||||
smb2_destroy_context(smb_context);
|
||||
reset(max_context_configured);
|
||||
smb_reset_pool(max_context_configured);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -340,7 +346,7 @@ void smb_shutdown(void)
|
||||
for (i = 0; i < max_context_configured; i++)
|
||||
smb_close_context(i);
|
||||
|
||||
reset(max_context_configured);
|
||||
smb_reset_pool(max_context_configured);
|
||||
}
|
||||
|
||||
/* Build full SMB path from settings */
|
||||
|
||||
+13
@@ -385,6 +385,19 @@ void retro_input_poll_null(void) { }
|
||||
#ifdef HAVE_SMBCLIENT
|
||||
static struct smb_settings smb_global_cfg;
|
||||
|
||||
/* Publishes the SMB client settings to the VFS SMB backend.
|
||||
*
|
||||
* Called once early in rarch_main() so the backend has a registered
|
||||
* configuration before anything can touch an smb:// path, and again at
|
||||
* the end of every successful config_load_file(). The second call is
|
||||
* what makes the numeric fields correct: the string fields below alias
|
||||
* settings->arrays and therefore follow every config load on their
|
||||
* own, but timeout, num_contexts and auth_mode are copied by value and
|
||||
* would otherwise keep whatever the settings struct held at the early
|
||||
* call, which is zero - config loading happens later, inside
|
||||
* retroarch_main_init(). The SMB backend reads the configuration
|
||||
* lazily on first smb:// access, which in every startup path is after
|
||||
* the configuration has been loaded and re-published. */
|
||||
void retroarch_smb_init(void)
|
||||
{
|
||||
settings_t *settings = config_get_ptr();
|
||||
|
||||
+15
@@ -158,6 +158,21 @@ void retroarch_favorites_init(void);
|
||||
|
||||
void retroarch_favorites_deinit(void);
|
||||
|
||||
#ifdef HAVE_SMBCLIENT
|
||||
/**
|
||||
* retroarch_smb_init:
|
||||
*
|
||||
* Publishes the SMB client settings to the VFS SMB backend. The string
|
||||
* fields alias settings->arrays and therefore always read current
|
||||
* values, but the numeric fields (timeout, num_contexts, auth_mode)
|
||||
* are copied by value, so this must be called again whenever a
|
||||
* configuration is loaded; config_load_file() does so. Safe to call
|
||||
* repeatedly. Values only take effect for SMB contexts created after
|
||||
* the call - the existing pool is not rebuilt.
|
||||
**/
|
||||
void retroarch_smb_init(void);
|
||||
#endif
|
||||
|
||||
/* Audio */
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user