using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Remotely.Agent.Interfaces; using Remotely.Agent.Services; using Remotely.Shared.Enums; using Remotely.Shared.Utilities; using Remotely.Shared.Services; using System; using System.Diagnostics; using System.IO; using System.ServiceProcess; using System.Threading.Tasks; using System.Runtime.Versioning; using Remotely.Agent.Services.Linux; using Remotely.Agent.Services.MacOS; using Remotely.Agent.Services.Windows; using Microsoft.Extensions.Hosting; using System.Linq; using Microsoft.Win32; using System.Reflection; namespace Remotely.Agent; public class Program { [Obsolete("Remove this when all services are in DI behind interfaces.")] public static IServiceProvider? Services { get; set; } public static async Task Main(string[] args) { try { var host = Host .CreateDefaultBuilder(args) .UseWindowsService() .UseSystemd() .ConfigureServices(RegisterServices) .Build(); await host.StartAsync(); Services = host.Services; await Init(host.Services); await host.WaitForShutdownAsync(); } catch (Exception ex) { var version = AppVersionHelper.GetAppVersion(); var componentName = Assembly.GetExecutingAssembly().GetName().Name; var logger = new FileLogger($"{componentName}", version, "Main"); logger.LogError(ex, "Error during agent startup."); throw; } } private static async Task Init(IServiceProvider services) { var logger = services.GetRequiredService>(); AppDomain.CurrentDomain.UnhandledException += (sender, ex) => { if (ex.ExceptionObject is Exception exception) { logger.LogError(exception, "Unhandled exception in AppDomain."); } else { logger.LogError("Unhandled exception in AppDomain."); } }; SetWorkingDirectory(); if (OperatingSystem.IsWindows()) { SetSas(services, logger); } await services.GetRequiredService().BeginChecking(); await services.GetRequiredService().Connect(); } private static void RegisterServices(IServiceCollection services) { services.AddHttpClient(); services.AddLogging(builder => { builder.AddConsole().AddDebug(); var version = AppVersionHelper.GetAppVersion(); var componentName = Assembly.GetExecutingAssembly().GetName().Name; builder.AddProvider(new FileLoggerProvider($"{componentName}", version)); }); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddHostedService(services => services.GetRequiredService()); services.AddScoped(); services.AddTransient(); services.AddTransient(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddSingleton(); if (OperatingSystem.IsWindows()) { services.AddScoped(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); } else if (OperatingSystem.IsLinux()) { services.AddScoped(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); } else if (OperatingSystem.IsMacOS()) { services.AddScoped(); services.AddSingleton(); services.AddSingleton(); } else { throw new NotSupportedException("Operating system not supported."); } } [SupportedOSPlatform("windows")] private static void SetSas(IServiceProvider services, ILogger logger) { try { var elevationDetector = services.GetRequiredService(); if (elevationDetector.IsElevated()) { // Set Secure Attention Sequence policy to allow app to simulate Ctrl + Alt + Del. var subkey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System", true); subkey?.SetValue("SoftwareSASGeneration", "3", RegistryValueKind.DWord); } } catch (Exception ex) { logger.LogError(ex, "Error while setting Secure Attention Sequence in the registry."); } } private static void SetWorkingDirectory() { var exePath = Environment.ProcessPath ?? Environment.GetCommandLineArgs().First(); var exeDir = Path.GetDirectoryName(exePath) ?? AppDomain.CurrentDomain.BaseDirectory; Directory.SetCurrentDirectory(exeDir); } }