diff --git a/DiscImageChef.Devices/Device/Variables.cs b/DiscImageChef.Devices/Device/Variables.cs index c8b72c572..42d6b6ebe 100644 --- a/DiscImageChef.Devices/Device/Variables.cs +++ b/DiscImageChef.Devices/Device/Variables.cs @@ -219,6 +219,17 @@ namespace DiscImageChef.Devices public byte[] Cis { get; } private readonly Remote.Remote _remote; + private bool? _isRemoteAdmin; + + public bool IsRemoteAdmin + { + get + { + if (_isRemoteAdmin is null) _isRemoteAdmin = _remote.IsRoot; + + return _isRemoteAdmin == true; + } + } public bool IsRemote => _remote != null; public string RemoteApplication => _remote?.ServerApplication; diff --git a/DiscImageChef.Devices/Remote/Enums.cs b/DiscImageChef.Devices/Remote/Enums.cs index 9dad26433..fe6e2d862 100644 --- a/DiscImageChef.Devices/Remote/Enums.cs +++ b/DiscImageChef.Devices/Remote/Enums.cs @@ -27,7 +27,9 @@ namespace DiscImageChef.Devices.Remote ResponseGetFireWireData = 22, CommandGetPcmciaData = 23, ResponseGetPcmciaData = 24, - CommandCloseDevice = 25 + CommandCloseDevice = 25, + CommandAmIRoot = 26, + ResponseAmIRoot = 27 } public enum DicNopReason : byte diff --git a/DiscImageChef.Devices/Remote/Remote.cs b/DiscImageChef.Devices/Remote/Remote.cs index 03ac78715..153458eb9 100644 --- a/DiscImageChef.Devices/Remote/Remote.cs +++ b/DiscImageChef.Devices/Remote/Remote.cs @@ -140,6 +140,71 @@ namespace DiscImageChef.Devices.Remote public string ServerArchitecture { get; } public int ServerProtocolVersion { get; } + public bool IsRoot + { + get + { + var cmdPkt = new DicPacketCmdAmIRoot + { + hdr = new DicPacketHeader + { + remote_id = Consts.RemoteId, packet_id = Consts.PacketId, + len = (uint) Marshal.SizeOf(), + version = Consts.PacketVersion, + packetType = DicPacketType.CommandAmIRoot + } + }; + + var buf = Marshal.StructureToByteArrayLittleEndian(cmdPkt); + + var len = _socket.Send(buf, SocketFlags.None); + + if (len != buf.Length) + { + DicConsole.ErrorWriteLine("Could not write to the network..."); + return false; + } + + var hdrBuf = new byte[Marshal.SizeOf()]; + + len = Receive(_socket, hdrBuf, hdrBuf.Length, SocketFlags.Peek); + + if (len < hdrBuf.Length) + { + DicConsole.ErrorWriteLine("Could not read from the network..."); + return false; + } + + var hdr = Marshal.ByteArrayToStructureLittleEndian(hdrBuf); + + if (hdr.remote_id != Consts.RemoteId || hdr.packet_id != Consts.PacketId) + { + DicConsole.ErrorWriteLine("Received data is not a DIC Remote Packet..."); + return false; + } + + if (hdr.packetType != DicPacketType.ResponseAmIRoot) + { + DicConsole.ErrorWriteLine("Expected Am I Root? Response Packet, got packet type {0}...", + hdr.packetType); + return false; + } + + buf = new byte[hdr.len]; + len = Receive(_socket, buf, buf.Length, SocketFlags.None); + + if (len < buf.Length) + { + DicConsole.ErrorWriteLine("Could not read from the network..."); + return false; + } + + var res = Marshal.ByteArrayToStructureLittleEndian(buf); + + return res.am_i_root; + } + } + public void Dispose() { Disconnect(); diff --git a/DiscImageChef.Devices/Remote/Structs.cs b/DiscImageChef.Devices/Remote/Structs.cs index 06eafcd82..d1822bb30 100644 --- a/DiscImageChef.Devices/Remote/Structs.cs +++ b/DiscImageChef.Devices/Remote/Structs.cs @@ -320,4 +320,17 @@ namespace DiscImageChef.Devices.Remote { public DicPacketHeader hdr; } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] + public struct DicPacketCmdAmIRoot + { + public DicPacketHeader hdr; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] + public struct DicPacketResAmIRoot + { + public DicPacketHeader hdr; + [MarshalAs(UnmanagedType.U4)] public bool am_i_root; + } } \ No newline at end of file diff --git a/DiscImageChef/Commands/DeviceReport.cs b/DiscImageChef/Commands/DeviceReport.cs index 5463957cb..882d8aac7 100644 --- a/DiscImageChef/Commands/DeviceReport.cs +++ b/DiscImageChef/Commands/DeviceReport.cs @@ -74,7 +74,7 @@ namespace DiscImageChef.Commands public override int Invoke(IEnumerable arguments) { - List extra = Options.Parse(arguments); + var extra = Options.Parse(arguments); if (showHelp) { @@ -105,15 +105,6 @@ namespace DiscImageChef.Commands DicConsole.DebugWriteLine("Device-Report command", "--device={0}", devicePath); DicConsole.DebugWriteLine("Device-Report command", "--verbose={0}", MainClass.Verbose); - if (!DetectOS.IsAdmin) - { - DicConsole - .ErrorWriteLine( - "Because of the commands sent to a device, device report must be run with administrative privileges."); - DicConsole.ErrorWriteLine("Not continuing."); - return (int) ErrorNumber.NotEnoughPermissions; - } - if (devicePath.Length == 2 && devicePath[1] == ':' && devicePath[0] != '/' && char.IsLetter(devicePath[0])) devicePath = "\\\\.\\" + char.ToUpper(devicePath[0]) + ':'; @@ -127,11 +118,27 @@ namespace DiscImageChef.Commands Statistics.AddDevice(dev); + bool isAdmin; + + if (dev.IsRemote) + isAdmin = dev.IsRemoteAdmin; + else isAdmin = DetectOS.IsAdmin; + + if (!isAdmin) + { + DicConsole + .ErrorWriteLine( + "Because of the commands sent to a device, device report must be run with administrative privileges."); + DicConsole.ErrorWriteLine("Not continuing."); + return (int) ErrorNumber.NotEnoughPermissions; + } + + var report = new DeviceReportV2 { Manufacturer = dev.Manufacturer, Model = dev.Model, Revision = dev.Revision, Type = dev.Type }; - bool removable = false; + var removable = false; string jsonFile; if (!string.IsNullOrWhiteSpace(dev.Manufacturer) && !string.IsNullOrWhiteSpace(dev.Revision)) @@ -249,7 +256,7 @@ namespace DiscImageChef.Commands DicConsole.WriteLine("Querying ATA IDENTIFY..."); dev.AtaIdentify(out buffer, out _, dev.Timeout, out _); report.ATA.Identify = DeviceReport.ClearIdentify(buffer); - List mediaTests = new List(); + var mediaTests = new List(); pressedKey = new ConsoleKeyInfo(); while (pressedKey.Key != ConsoleKey.N) @@ -349,7 +356,7 @@ namespace DiscImageChef.Commands .CToString(report.SCSI.Inquiry?.VendorIdentification)?.Trim() .ToLowerInvariant()); - reporter.ReportScsiModes(ref report, out byte[] cdromMode); + reporter.ReportScsiModes(ref report, out var cdromMode); string mediumManufacturer; byte[] senseBuffer; @@ -359,10 +366,10 @@ namespace DiscImageChef.Commands { case PeripheralDeviceTypes.MultiMediaDevice: { - bool iomegaRev = dev.Manufacturer.ToLowerInvariant() == "iomega" && - dev.Model.ToLowerInvariant().StartsWith("rrd"); + var iomegaRev = dev.Manufacturer.ToLowerInvariant() == "iomega" && + dev.Model.ToLowerInvariant().StartsWith("rrd"); - List mediaTypes = new List(); + var mediaTypes = new List(); report.SCSI.MultiMediaDevice = new Mmc { @@ -584,8 +591,8 @@ namespace DiscImageChef.Commands if (dev.Model.StartsWith("PD-", StringComparison.Ordinal)) mediaTypes.Add("PD-650"); - List mediaTests = new List(); - foreach (string mediaType in mediaTypes) + var mediaTests = new List(); + foreach (var mediaType in mediaTypes) { pressedKey = new ConsoleKeyInfo(); while (pressedKey.Key != ConsoleKey.Y && pressedKey.Key != ConsoleKey.N) @@ -604,17 +611,17 @@ namespace DiscImageChef.Commands .WriteLine("Please insert it in the drive and press any key when it is ready."); System.Console.ReadKey(true); - bool mediaIsRecognized = true; + var mediaIsRecognized = true; sense = dev.ScsiTestUnitReady(out senseBuffer, dev.Timeout, out _); if (sense) { - FixedSense? decSense = Sense.DecodeFixed(senseBuffer); + var decSense = Sense.DecodeFixed(senseBuffer); if (decSense.HasValue) { if (decSense.Value.ASC == 0x3A) { - int leftRetries = 50; + var leftRetries = 50; while (leftRetries > 0) { DicConsole.Write("\rWaiting for drive to become ready"); @@ -629,7 +636,7 @@ namespace DiscImageChef.Commands } else if (decSense.Value.ASC == 0x04 && decSense.Value.ASCQ == 0x01) { - int leftRetries = 50; + var leftRetries = 50; while (leftRetries > 0) { DicConsole.Write("\rWaiting for drive to become ready"); @@ -645,7 +652,7 @@ namespace DiscImageChef.Commands // These should be trapped by the OS but seems in some cases they're not else if (decSense.Value.ASC == 0x28) { - int leftRetries = 50; + var leftRetries = 50; while (leftRetries > 0) { DicConsole.Write("\rWaiting for drive to become ready"); @@ -698,7 +705,7 @@ namespace DiscImageChef.Commands if (pressedKey.Key == ConsoleKey.Y) { - for (ushort i = (ushort) mediaTest.BlockSize;; i++) + for (var i = (ushort) mediaTest.BlockSize;; i++) { DicConsole.Write("\rTrying to READ LONG with a size of {0} bytes...", i); @@ -745,7 +752,7 @@ namespace DiscImageChef.Commands { report.SCSI.SequentialDevice = reporter.ReportScsiSsc(); - List seqTests = new List(); + var seqTests = new List(); pressedKey = new ConsoleKeyInfo(); while (pressedKey.Key != ConsoleKey.N) @@ -771,18 +778,18 @@ namespace DiscImageChef.Commands DicConsole.Write("Please write the media model and press enter: "); mediumModel = System.Console.ReadLine(); - bool mediaIsRecognized = true; + var mediaIsRecognized = true; sense = dev.ScsiTestUnitReady(out senseBuffer, dev.Timeout, out _); DicConsole.DebugWriteLine("Device reporting", "sense = {0}", sense); if (sense) { - FixedSense? decSense = Sense.DecodeFixed(senseBuffer); + var decSense = Sense.DecodeFixed(senseBuffer); if (decSense.HasValue) { if (decSense.Value.ASC == 0x3A) { - int leftRetries = 50; + var leftRetries = 50; while (leftRetries > 0) { DicConsole.Write("\rWaiting for drive to become ready"); @@ -797,7 +804,7 @@ namespace DiscImageChef.Commands } else if (decSense.Value.ASC == 0x04 && decSense.Value.ASCQ == 0x01) { - int leftRetries = 50; + var leftRetries = 50; while (leftRetries > 0) { DicConsole.Write("\rWaiting for drive to become ready"); @@ -813,7 +820,7 @@ namespace DiscImageChef.Commands // These should be trapped by the OS but seems in some cases they're not else if (decSense.Value.ASC == 0x28) { - int leftRetries = 50; + var leftRetries = 50; while (leftRetries > 0) { DicConsole.Write("\rWaiting for drive to become ready"); @@ -867,7 +874,7 @@ namespace DiscImageChef.Commands { if (removable) { - List mediaTests = new List(); + var mediaTests = new List(); pressedKey = new ConsoleKeyInfo(); while (pressedKey.Key != ConsoleKey.N) @@ -893,16 +900,16 @@ namespace DiscImageChef.Commands DicConsole.Write("Please write the media model and press enter: "); mediumModel = System.Console.ReadLine(); - bool mediaIsRecognized = true; + var mediaIsRecognized = true; sense = dev.ScsiTestUnitReady(out senseBuffer, dev.Timeout, out _); if (sense) { - FixedSense? decSense = Sense.DecodeFixed(senseBuffer); + var decSense = Sense.DecodeFixed(senseBuffer); if (decSense.HasValue) if (decSense.Value.ASC == 0x3A) { - int leftRetries = 20; + var leftRetries = 20; while (leftRetries > 0) { DicConsole.Write("\rWaiting for drive to become ready"); @@ -917,7 +924,7 @@ namespace DiscImageChef.Commands } else if (decSense.Value.ASC == 0x04 && decSense.Value.ASCQ == 0x01) { - int leftRetries = 20; + var leftRetries = 20; while (leftRetries > 0) { DicConsole.Write("\rWaiting for drive to become ready"); @@ -958,7 +965,7 @@ namespace DiscImageChef.Commands if (pressedKey.Key == ConsoleKey.Y) { - for (ushort i = (ushort) mediaTest.BlockSize;; i++) + for (var i = (ushort) mediaTest.BlockSize;; i++) { DicConsole .Write("\rTrying to READ LONG with a size of {0} bytes...", i); @@ -1016,7 +1023,7 @@ namespace DiscImageChef.Commands if (pressedKey.Key == ConsoleKey.Y) { - for (ushort i = (ushort) report.SCSI.ReadCapabilities.BlockSize;; i++) + for (var i = (ushort) report.SCSI.ReadCapabilities.BlockSize;; i++) { DicConsole.Write("\rTrying to READ LONG with a size of {0} bytes...", i); sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, i, @@ -1056,8 +1063,8 @@ namespace DiscImageChef.Commands default: throw new NotSupportedException("Unknown device type."); } - FileStream jsonFs = new FileStream(jsonFile, FileMode.Create); - StreamWriter jsonSw = new StreamWriter(jsonFs); + var jsonFs = new FileStream(jsonFile, FileMode.Create); + var jsonSw = new StreamWriter(jsonFs); jsonSw.Write(JsonConvert.SerializeObject(report, Formatting.Indented, new JsonSerializerSettings {