diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index fc871f064f..d699102ffc 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Net; using System.Reflection; +using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -197,6 +198,13 @@ namespace Jellyfin.Server try { await webHost.StartAsync(_tokenSource.Token).ConfigureAwait(false); + + if (startupConfig.UseUnixSocket() && Environment.OSVersion.Platform == PlatformID.Unix) + { + var socketPath = GetUnixSocketPath(startupConfig, appPaths); + + SetUnixSocketPermissions(startupConfig, socketPath); + } } catch (Exception ex) when (ex is not TaskCanceledException) { @@ -326,20 +334,7 @@ namespace Jellyfin.Server // Bind to unix socket (only on unix systems) if (startupConfig.UseUnixSocket() && Environment.OSVersion.Platform == PlatformID.Unix) { - var socketPath = startupConfig.GetUnixSocketPath(); - if (string.IsNullOrEmpty(socketPath)) - { - var xdgRuntimeDir = Environment.GetEnvironmentVariable("XDG_RUNTIME_DIR"); - if (xdgRuntimeDir == null) - { - // Fall back to config dir - socketPath = Path.Join(appPaths.ConfigurationDirectoryPath, "socket.sock"); - } - else - { - socketPath = Path.Join(xdgRuntimeDir, "jellyfin-socket"); - } - } + var socketPath = GetUnixSocketPath(startupConfig, appPaths); // Workaround for https://github.com/aspnet/AspNetCore/issues/14134 if (File.Exists(socketPath)) @@ -663,5 +658,49 @@ namespace Jellyfin.Server return "\"" + arg + "\""; } + + private static string GetUnixSocketPath(IConfiguration startupConfig, IApplicationPaths appPaths) + { + var socketPath = startupConfig.GetUnixSocketPath(); + + if (string.IsNullOrEmpty(socketPath)) + { + var xdgRuntimeDir = Environment.GetEnvironmentVariable("XDG_RUNTIME_DIR"); + var socketFile = "jellyfin.sock"; + if (xdgRuntimeDir == null) + { + // Fall back to config dir + socketPath = Path.Join(appPaths.ConfigurationDirectoryPath, socketFile); + } + else + { + socketPath = Path.Join(xdgRuntimeDir, socketFile); + } + } + + return socketPath; + } + + private static void SetUnixSocketPermissions(IConfiguration startupConfig, string socketPath) + { + var socketPerms = startupConfig.GetUnixSocketPermissions(); + + if (!string.IsNullOrEmpty(socketPerms)) + { + [DllImport("libc")] + static extern int Chmod(string pathname, int mode); + + var exitCode = Chmod(socketPath, Convert.ToInt32(socketPerms, 8)); + + if (exitCode < 0) + { + _logger.LogError("Failed to set Kestrel unix socket permissions to {SocketPerms}, return code: {ExitCode}", socketPerms, exitCode); + } + else + { + _logger.LogInformation("Kestrel unix socket permissions set to {SocketPerms}", socketPerms); + } + } + } } } diff --git a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs index 957ce67443..5a71102617 100644 --- a/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs +++ b/MediaBrowser.Controller/Extensions/ConfigurationExtensions.cs @@ -54,6 +54,11 @@ namespace MediaBrowser.Controller.Extensions /// public const string UnixSocketPathKey = "kestrel:socketPath"; + /// + /// The permissions for the unix socket. + /// + public const string UnixSocketPermissionsKey = "kestrel:socketPermissions"; + /// /// Gets a value indicating whether the application should host static web content from the . /// @@ -102,5 +107,13 @@ namespace MediaBrowser.Controller.Extensions /// The unix socket path. public static string GetUnixSocketPath(this IConfiguration configuration) => configuration[UnixSocketPathKey]; + + /// + /// Gets the permissions for the unix socket from the . + /// + /// The configuration to read the setting from. + /// The unix socket permissions. + public static string GetUnixSocketPermissions(this IConfiguration configuration) + => configuration[UnixSocketPermissionsKey]; } }