Files
IT-Nexus/agent-cs/AgentWorker.cs
Simon Grüssing 7449b64398 Fix: RDP Consent-Dialog via WTSQueryUserToken+CreateProcessAsUser (v2.4.0)
- SessionSpawner.cs: Neuer Helper — WTSQueryUserToken + CreateProcessAsUser
  ersetzt fragilen schtasks-Ansatz für UI-Spawn aus SYSTEM-Service
- RtcService: SpawnConsentHelper + SpawnCaptureHelper nutzen jetzt SessionSpawner
- Findet aktive Console-Session automatisch, Fallback auf alle Sessions
- Version: 2.3.0 → 2.4.0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 09:51:40 +02:00

208 lines
8.1 KiB
C#

using ITNexusAgent.Models;
using ITNexusAgent.Services;
using Newtonsoft.Json;
namespace ITNexusAgent;
public class AgentWorker
{
private const string Version = "2.4.0";
private const string DataDir = @"C:\ProgramData\IT Nexus Agent";
private const string ConfigPath = @"C:\ProgramData\IT Nexus Agent\config.json";
private const string StatusPath = @"C:\ProgramData\IT Nexus Agent\status.json";
private const string LogPath = @"C:\ProgramData\IT Nexus Agent\agent.log";
private readonly CancellationToken _ct;
private AgentConfig? _config;
private ApiService? _api;
private NotificationService? _notifier;
private string _exePath = "";
public AgentWorker(CancellationToken ct) => _ct = ct;
public async Task RunAsync()
{
_exePath = System.Diagnostics.Process.GetCurrentProcess().MainModule!.FileName;
Directory.CreateDirectory(DataDir);
if (!File.Exists(ConfigPath))
{
Log("ERROR: config.json nicht gefunden");
return;
}
SecureConfigFile(ConfigPath);
_config = AgentConfig.Load(ConfigPath);
_api = new ApiService(_config.ServerUrl, _config.AgentKey);
_notifier = new NotificationService(_exePath, DataDir);
Log($"Agent v{Version} gestartet");
// WebSocket Shell-Service im Hintergrund starten
var shellService = new ShellService(_config.ServerUrl, _config.AgentKey, SystemInfoService.GetHostname());
_ = shellService.RunAsync(_ct);
// WebRTC Remote Desktop Service im Hintergrund starten
var rtcService = new RtcService(_config.ServerUrl, _config.AgentKey, SystemInfoService.GetHostname());
_ = rtcService.RunAsync(_ct);
while (!_ct.IsCancellationRequested)
{
await RunCycleAsync();
await Task.Delay(TimeSpan.FromMinutes(1), _ct).ContinueWith(_ => { });
}
}
private async Task RunCycleAsync()
{
try
{
Log("Sammle Systemdaten...");
var payload = CollectData();
var response = await _api!.CheckinAsync(payload);
Log($"OK: Checkin erfolgreich (Hostname: {payload.Hostname})");
// Status-Cache für Dashboard schreiben
WriteStatusCache(payload, response, true);
// Auto-Update prüfen
if (!string.IsNullOrEmpty(response.AgentVersion) &&
System.Version.TryParse(response.AgentVersion, out var serverVer) &&
System.Version.TryParse(Version, out var localVer) &&
serverVer > localVer)
{
Log($"UPDATE: Neue Agent-Version verfügbar: {response.AgentVersion} (aktuell: {Version})");
await new CommandExecutor(_api, payload.Hostname, DataDir, _exePath)
.ExecuteAsync(new PatchCommand { Id = 0, Command = "update_agent" });
return;
}
// Patch-Commands ausführen
var executor = new CommandExecutor(_api, payload.Hostname, DataDir, _exePath);
foreach (var cmd in response.Commands)
{
Log($"PATCH: Command empfangen: {cmd.Command}");
await executor.ExecuteAsync(cmd);
}
// Ankündigungen anzeigen + sofort ACKen damit Server sie nicht mehr schickt
if (response.Announcements.Count > 0)
{
_notifier!.ShowAnnouncements(response.Announcements);
foreach (var ann in response.Announcements)
{
Log($"ANNOUNCEMENT: Dialog für {SystemInfoService.GetLastUser()} gestartet - ID {ann.Id}");
try { await _api!.AckAnnouncementAsync(ann.Id, payload.Hostname); }
catch (Exception ex) { Log($"ANNOUNCEMENT ACK Fehler: {ex.Message}"); }
}
}
}
catch (Exception ex)
{
Log($"ERROR: {ex.Message}");
WriteStatusCache(null, null, false);
}
}
private CheckinPayload CollectData()
{
var (cpuModel, cpuCores) = SystemInfoService.GetCpuInfo();
var (ramTotal, ramUsed) = SystemInfoService.GetRamInfo();
var (diskTotal, diskFree) = SystemInfoService.GetDiskInfo();
var (tpmPresent, tpmVersion, tpmV2) = SystemInfoService.GetTpmInfo();
var (defEnabled, defSigAge, _) = SecurityInfoService.GetDefenderStatus();
return new CheckinPayload
{
Hostname = SystemInfoService.GetHostname(),
AgentVersion = Version,
Os = SystemInfoService.GetOs(),
OsVersion = SystemInfoService.GetOsVersion(),
Domain = SystemInfoService.GetDomain(),
IpAddress = SystemInfoService.GetIpAddress(),
MacAddress = SystemInfoService.GetMacAddress(),
LastUser = SystemInfoService.GetLastUser(),
CpuModel = cpuModel,
CpuCores = cpuCores,
CpuUsage = SystemInfoService.GetCpuUsage(),
RamTotal = ramTotal,
RamUsed = ramUsed,
DiskTotal = diskTotal,
DiskFree = diskFree,
UptimeHours = SystemInfoService.GetUptimeHours(),
PendingUpdates = SystemInfoService.GetPendingUpdates(),
TpmPresent = tpmPresent,
TpmVersion = tpmVersion,
TpmV2 = tpmV2,
SecureBoot = SystemInfoService.GetSecureBoot(),
Win11Ready = SystemInfoService.GetWin11Readiness(tpmV2, SystemInfoService.GetSecureBoot(), cpuCores, ramTotal),
BitlockerStatus = SecurityInfoService.GetBitlockerStatus(),
DefenderEnabled = defEnabled,
DefenderSignaturesAge = defSigAge >= 0 ? defSigAge : null,
HardwareSerial = SystemInfoService.GetHardwareSerial(),
InstalledSoftware = SystemInfoService.GetInstalledSoftware(),
};
}
private void WriteStatusCache(CheckinPayload? p, CheckinResponse? r, bool online)
{
try
{
var status = new StatusCache
{
Hostname = p?.Hostname ?? SystemInfoService.GetHostname(),
LastCheckin = DateTime.Now,
AgentVersion = Version,
ServerUrl = _config?.ServerUrl ?? "",
Online = online,
CpuUsage = p?.CpuUsage,
RamTotal = p?.RamTotal,
RamUsed = p?.RamUsed,
DiskTotal = p?.DiskTotal,
DiskFree = p?.DiskFree,
PendingUpdates = p?.PendingUpdates ?? 0,
BitlockerStatus = p?.BitlockerStatus ?? "",
DefenderEnabled = p?.DefenderEnabled ?? false,
DefenderSignaturesAge = p?.DefenderSignaturesAge,
HardwareSerial = p?.HardwareSerial ?? "",
Os = p?.Os ?? "",
LastUser = p?.LastUser ?? "",
InstalledSoftware = p?.InstalledSoftware ?? [],
};
File.WriteAllText(StatusPath, JsonConvert.SerializeObject(status, Formatting.Indented));
}
catch { }
}
private static void SecureConfigFile(string path)
{
try
{
var fi = new System.IO.FileInfo(path);
var acl = fi.GetAccessControl();
acl.SetAccessRuleProtection(true, false); // Vererbung entfernen
// Nur SYSTEM und Administratoren
acl.AddAccessRule(new System.Security.AccessControl.FileSystemAccessRule(
"SYSTEM", System.Security.AccessControl.FileSystemRights.FullControl,
System.Security.AccessControl.AccessControlType.Allow));
acl.AddAccessRule(new System.Security.AccessControl.FileSystemAccessRule(
"Administrators", System.Security.AccessControl.FileSystemRights.FullControl,
System.Security.AccessControl.AccessControlType.Allow));
fi.SetAccessControl(acl);
}
catch { }
}
public static void Log(string msg)
{
try
{
var line = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} {msg}";
File.AppendAllText(LogPath, line + Environment.NewLine, System.Text.Encoding.UTF8);
}
catch { }
}
}