Skip to content

Commit

Permalink
Merge #3933 Modernize administrator and Mono version checks
Browse files Browse the repository at this point in the history
  • Loading branch information
HebaruSan committed Dec 1, 2023
2 parents 7996256 + d268bf0 commit d6ecc87
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 81 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file.
- [GUI] Shorten toolbar button labels (#3903 by: HebaruSan; reviewed: techman83)
- [Multiple] Refactor repository and available module handling (#3904, #3907, #3908 by: HebaruSan; reviewed: techman83)
- [Multiple] Parallelize for performance, relationship resolver improvements (#3917 by: HebaruSan; reviewed: techman83)
- [Multiple] Modernize administrator and Mono version checks (#3933 by: HebaruSan; reviewed: techman83)

### Bugfixes

Expand Down
10 changes: 0 additions & 10 deletions Cmdline/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
using System.Net;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
#if NET5_0_OR_GREATER
using System.Runtime.Versioning;
#endif
Expand Down Expand Up @@ -369,13 +368,4 @@ public class NoGameInstanceKraken : Kraken
{
public NoGameInstanceKraken() { }
}

public class CmdLineUtil
{
public static uint GetUID()
=> Platform.IsUnix || Platform.IsMac ? getuid() : 1;

[DllImport("libc")]
private static extern uint getuid();
}
}
51 changes: 10 additions & 41 deletions Cmdline/Options.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using System.Text.RegularExpressions;

using log4net;
using log4net.Core;
Expand Down Expand Up @@ -219,23 +216,21 @@ public class CommonOptions
[Option("headless", DefaultValue = false, HelpText = "Set to disable all prompts")]
public bool Headless { get; set; }

[Option("asroot", DefaultValue = false, HelpText = "Allows CKAN to run as root on Linux-based systems")]
[Option("asroot", DefaultValue = false, HelpText = "Allow CKAN to run as administrator")]
public bool AsRoot { get; set; }

[HelpVerbOption]
public string GetUsage(string verb)
{
return HelpText.AutoBuild(this, verb);
}
=> HelpText.AutoBuild(this, verb);

public virtual int Handle(GameInstanceManager manager, IUser user)
{
CheckMonoVersion(user, 3, 1, 0);
CheckMonoVersion(user);

// Processes in Docker containers normally run as root.
// If we are running in a Docker container, do not require --asroot.
// Docker creates a .dockerenv file in the root of each container.
if ((Platform.IsUnix || Platform.IsMac) && CmdLineUtil.GetUID() == 0 && !File.Exists("/.dockerenv"))
if (Platform.IsAdministrator())
{
if (!AsRoot)
{
Expand Down Expand Up @@ -286,40 +281,14 @@ public void Merge(CommonOptions otherOpts)
}
}

private static void CheckMonoVersion(IUser user, int rec_major, int rec_minor, int rec_patch)
private static void CheckMonoVersion(IUser user)
{
try
{
Type type = Type.GetType("Mono.Runtime");
if (type == null)
{
return;
}

MethodInfo display_name = type.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
if (display_name != null)
{
var version_string = (string) display_name.Invoke(null, null);
var match = Regex.Match(version_string, @"^\D*(?<major>[\d]+)\.(?<minor>\d+)\.(?<revision>\d+).*$");

if (match.Success)
{
int major = int.Parse(match.Groups["major"].Value);
int minor = int.Parse(match.Groups["minor"].Value);
int patch = int.Parse(match.Groups["revision"].Value);

if (major < rec_major || (major == rec_major && minor < rec_minor))
{
user.RaiseMessage(Properties.Resources.OptionsMonoWarning,
string.Join(".", major, minor, patch),
string.Join(".", rec_major, rec_minor, rec_patch));
}
}
}
}
catch (Exception)
if (Platform.MonoVersion != null
&& Platform.MonoVersion < Platform.RecommendedMonoVersion)
{
// Ignored. This may be fragile and is just a warning method
user.RaiseMessage(Properties.Resources.OptionsMonoWarning,
Platform.MonoVersion.ToString(),
Platform.RecommendedMonoVersion.ToString());
}
}

Expand Down
7 changes: 3 additions & 4 deletions Cmdline/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,10 @@
<data name="MainUnknownCommand" xml:space="preserve"><value>Unknown command, try --help</value></data>
<data name="MainMissingInstance" xml:space="preserve"><value>I don't know where a game instance is installed.
Use 'ckan instance help' for assistance in setting this.</value></data>
<data name="OptionsRootError" xml:space="preserve"><value>You are trying to run CKAN as root.
<data name="OptionsRootError" xml:space="preserve"><value>You are trying to run CKAN as an administrator user.
This is a bad idea and there is absolutely no good reason to do it. Please run CKAN from a user account (or use --asroot if you are feeling brave).</value></data>
<data name="OptionsRootWarning" xml:space="preserve"><value>Warning: Running CKAN as root!</value></data>
<data name="OptionsMonoWarning" xml:space="preserve"><value>Warning. Detected mono runtime of {0} is less than the recommended version of {1}.
Update recommended!</value></data>
<data name="OptionsRootWarning" xml:space="preserve"><value>Warning: CKAN is running as an administrator user!</value></data>
<data name="OptionsMonoWarning" xml:space="preserve"><value>Warning: Detected Mono {0}, recommended version is {1} or later!</value></data>
<data name="OptionsInstanceAndGameDir" xml:space="preserve"><value>--instance and --gamedir can't be specified at the same time</value></data>
<data name="OptionsInvalidInstance" xml:space="preserve"><value>Invalid game instance specified "{0}", use '--gamedir' to specify by path, or 'instance list' to see known game instances</value></data>
<data name="InstanceNotInstance" xml:space="preserve"><value>Sorry, {0} does not appear to be a game instance</value></data>
Expand Down
26 changes: 26 additions & 0 deletions Core/Extensions/RegexExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Text.RegularExpressions;

namespace CKAN.Extensions
{
public static class RegexExtensions
{
/// <summary>
/// Functional-friendly wrapper around Regex.Match
/// </summary>
/// <param name="regex">The regex to match</param>
/// <param name="value">The string to check</param>
/// <param name="match">Object representing the match, if any</param>
/// <returns>True if the regex matched the value, false otherwise</returns>
public static bool TryMatch(this Regex regex, string value, out Match match)
{
if (value == null)
{
// Nothing matches null
match = null;
return false;
}
match = regex.Match(value);
return match.Success;
}
}
}
62 changes: 37 additions & 25 deletions Core/Platform.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
using System;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
#if NET6_0_OR_GREATER
using System.Runtime.Versioning;
#endif
using System.Text.RegularExpressions;
using System.Security.Principal;

using CKAN.Extensions;

namespace CKAN
{
Expand All @@ -17,12 +21,6 @@ namespace CKAN
/// </summary>
public static class Platform
{
static Platform()
{
// This call throws if we try to do it as a static initializer.
IsMonoFourOrLater = IsOnMonoFourOrLater();
}

/// <summary>
/// Are we on a Mac?
/// </summary>
Expand Down Expand Up @@ -56,39 +54,53 @@ static Platform()
/// </summary>
public static readonly bool IsMono = Type.GetType("Mono.Runtime") != null;

/// <summary>
/// Are we running on a Mono with major version 4 or later?
/// </summary>
public static readonly bool IsMonoFourOrLater;

/// <summary>
/// Are we running in an X11 environment?
/// </summary>
public static readonly bool IsX11 =
IsUnix
&& !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("DISPLAY"));

private static bool IsOnMonoFourOrLater()
public static bool IsAdministrator()
{
if (!IsMono)
if (File.Exists("/.dockerenv"))
{
// Treat as non-admin in a docker container, regardless of platform
return false;
}

// Get Mono's display name and parse the version
string display_name =
(string)Type.GetType("Mono.Runtime")
.GetMethod("GetDisplayName",
BindingFlags.NonPublic | BindingFlags.Static)
.Invoke(null, null);

var match = versionMatcher.Match(display_name);
return match.Success
&& int.Parse(match.Groups["majorVersion"].Value) >= 4;
if (IsWindows)
{
// On Windows, check if we have administrator or system roles
using (var identity = WindowsIdentity.GetCurrent())
{
var principal = new WindowsPrincipal(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator)
|| principal.IsInRole(WindowsBuiltInRole.SystemOperator);
}
}
// Otherwise Unix-like; are we root?
return getuid() == 0;
}

[DllImport("libc")]
private static extern uint getuid();

private static readonly Regex versionMatcher =
new Regex("^\\s*(?<majorVersion>\\d+)\\.\\d+\\.\\d+\\s*\\(",
new Regex("^\\s*(?<major>\\d+)\\.(?<minor>\\d+)\\.(?<patch>\\d+)\\s*\\(",
RegexOptions.Compiled);

public static readonly Version MonoVersion
= versionMatcher.TryMatch((string)Type.GetType("Mono.Runtime")
?.GetMethod("GetDisplayName",
BindingFlags.NonPublic
| BindingFlags.Static)
?.Invoke(null, null),
out Match match)
? new Version(int.Parse(match.Groups["major"].Value),
int.Parse(match.Groups["minor"].Value),
int.Parse(match.Groups["patch"].Value))
: null;

public static readonly Version RecommendedMonoVersion = new Version(5, 0, 0);
}
}
1 change: 0 additions & 1 deletion Core/Relationships/RelationshipResolver.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

using log4net;
Expand Down

0 comments on commit d6ecc87

Please sign in to comment.