Skip to content

Commit

Permalink
Protect Settings pages from being accessed remotely
Browse files Browse the repository at this point in the history
Only allow access to the Settings pages to clients connecting from the local network, and not from the network's gateway.

# Conflicts:
#	Slim/Utils/OS/Linux.pm
  • Loading branch information
mherger committed Jan 6, 2018
2 parents 3625c6d + fa6f097 commit b3228c3
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 3 deletions.
1 change: 1 addition & 0 deletions Changelog7.html
Expand Up @@ -18,6 +18,7 @@ <h2><a name="v7.9.1" id="v7.9.1"></a>Version 7.9.1</h2>

<li>Other:</li>
<ul>
<li>Block access to settings pages from outside the local network.</li>
<li>Make Playlists menu available to the SB Classic/Boom/Transporter's Home menu</li>
<li>Updated faad2 to latest code. Includes patches to increase maximum path length and fix some transcoding issues on Windows. Thanks <a href="https://github.com/ralph-irving/faad2">ralphy</a> and utgg.</li>
<li>Limit growth of the write-ahead log files for caches.</li>
Expand Down
5 changes: 5 additions & 0 deletions Slim/Utils/OS.pm
Expand Up @@ -295,6 +295,11 @@ sub getProxy {
return $proxy;
}

=head2 getDefaultGateway()
Get the network's default gateway address
=cut
sub getDefaultGateway { '' }

sub ignoredItems {
return (
# Items we should ignore on a linux volume
Expand Down
17 changes: 17 additions & 0 deletions Slim/Utils/OS/Linux.pm
Expand Up @@ -81,4 +81,21 @@ sub signalUpdateReady {
}
}

my $gateway;
sub getDefaultGateway {
if (!defined $gateway) {
$gateway = '';

my $route = `/sbin/route -n`;
while ( $route =~ /^(?:0\.0\.0\.0)\s*(\d+\.\d+\.\d+\.\d+)/mg ) {
if ( Slim::Utils::Network::ip_is_private($1) ) {
$gateway = $1;
last;
}
}
}

return $gateway;
}

1;
14 changes: 14 additions & 0 deletions Slim/Utils/OS/OSX.pm
Expand Up @@ -345,6 +345,20 @@ sub pathFromMacAlias {
return $path;
}

my $gateway;
sub getDefaultGateway {
if (!defined $gateway) {
$gateway = '';

my $route = `route -n get default`;
if ($route =~ /gateway:\s*(\d+\.\d+\.\d+\.\d+)/s ) {
$gateway = $1 if Slim::Utils::Network::ip_is_private($1);
}
}

return $gateway;
}

my $updateCheckInitialized;
my $plistLabel = "com.slimdevices.updatecheck";

Expand Down
17 changes: 17 additions & 0 deletions Slim/Utils/OS/Win32.pm
Expand Up @@ -396,6 +396,23 @@ sub getProxy {
return $proxy || $class->SUPER::getProxy();
}

my $gateway;
sub getDefaultGateway {
if (!defined $gateway) {
$gateway = '';

my $route = `route print -4`;
while ( $route =~ /^\s*0\.0\.0\.0\s+\d+\.\d+\.\d+\.\d+\s+(\d+\.\d+\.\d+\.\d+)/mg ) {
if ( Slim::Utils::Network::ip_is_private($1) ) {
$gateway = $1;
last;
}
}
}

return $gateway;
}

sub ignoredItems {
return (
# Items we should ignore on a Windows volume
Expand Down
1 change: 1 addition & 0 deletions Slim/Utils/Prefs.pm
Expand Up @@ -221,6 +221,7 @@ sub init {
return join(',', Slim::Utils::Network::hostAddr());
},
'csrfProtectionLevel' => 0,
'protectSettings' => 1,
'authorize' => 0,
'username' => '',
'password' => '',
Expand Down
33 changes: 30 additions & 3 deletions Slim/Web/HTTP.pm
Expand Up @@ -963,11 +963,38 @@ sub generateHTTPResponse {
);
}

main::INFOLOG && $log->is_info && $log->info("Generating response for ($type, $contentType) $path");

# some generally useful form details...
my $classOrCode = Slim::Web::Pages->getPageFunction($path);

# protect access to settings pages: only allow from local network
if ( main::WEBUI
&& $peeraddr{$httpClient} ne '127.0.0.1'
&& $prefs->get('protectSettings')
&& $classOrCode && !ref $classOrCode && $classOrCode->isa('Slim::Web::Settings')
) {
my $gateway = Slim::Utils::OSDetect->getOS()->getDefaultGateway();

if (
( $gateway && Slim::Utils::Network::intip($peeraddr{$httpClient}) == Slim::Utils::Network::intip($gateway) )
|| !Slim::Utils::Network::ip_is_private($peeraddr{$httpClient} )
) {
$log->warn("Access to settings pages is restricted to the local network or localhost: $peeraddr{$httpClient}");

$response->code(RC_FORBIDDEN);

$body = filltemplatefile('html/errors/403.html', $params);

return prepareResponseForSending(
$client,
$params,
$body,
$httpClient,
$response,
);
}
}

main::INFOLOG && $log->is_info && $log->info("Generating response for ($type, $contentType) $path");

if (defined($client) && $classOrCode) {
$params->{'player'} = $client->id();
$params->{'myClientState'} = $client;
Expand Down

0 comments on commit b3228c3

Please sign in to comment.