diff --git a/Cargo.lock b/Cargo.lock index 207d6cb36..7cfbfaf10 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1525,6 +1525,7 @@ dependencies = [ "ironrdp", "ironrdp-cliprdr-native", "ironrdp-core", + "ironrdp-rdcleanpath", "sspi", "thiserror 1.0.69", "tracing", diff --git a/ffi/Cargo.toml b/ffi/Cargo.toml index b265a4f48..9c6b902b3 100644 --- a/ffi/Cargo.toml +++ b/ffi/Cargo.toml @@ -17,6 +17,7 @@ diplomat-runtime = "0.7" ironrdp = { path = "../crates/ironrdp", features = ["session", "connector", "dvc", "svc", "rdpdr", "rdpsnd", "graphics", "input", "cliprdr", "displaycontrol"] } ironrdp-cliprdr-native.path = "../crates/ironrdp-cliprdr-native" ironrdp-core = { path = "../crates/ironrdp-core", features = ["alloc"] } +ironrdp-rdcleanpath = { path = "../crates/ironrdp-rdcleanpath" } sspi = { version = "0.16", features = ["network_client"] } thiserror = "1" tracing = { version = "0.1", features = ["log"] } diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdCleanPathPdu.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdCleanPathPdu.cs new file mode 100644 index 000000000..3455481a5 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdCleanPathPdu.cs @@ -0,0 +1,39 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct RdCleanPathPdu +{ + private const string NativeLib = "DevolutionsIronRdp"; + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RdCleanPathPdu_to_der", ExactSpelling = true)] + public static unsafe extern RdcleanpathFfiResultBoxVecU8BoxIronRdpError ToDer(RdCleanPathPdu* self); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RdCleanPathPdu_get_hint", ExactSpelling = true)] + public static unsafe extern PduHint* GetHint(); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RdCleanPathPdu_from_der", ExactSpelling = true)] + public static unsafe extern RdcleanpathFfiResultBoxRdCleanPathPduBoxIronRdpError FromDer(byte* der, nuint derSz); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RdCleanPathPdu_get_x224_connection_pdu", ExactSpelling = true)] + public static unsafe extern RdcleanpathFfiResultBoxVecU8BoxIronRdpError GetX224ConnectionPdu(RdCleanPathPdu* self); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RdCleanPathPdu_get_server_cert_chain", ExactSpelling = true)] + public static unsafe extern RdcleanpathFfiResultBoxServerCertChainBoxIronRdpError GetServerCertChain(RdCleanPathPdu* self); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RdCleanPathPdu_get_server_addr", ExactSpelling = true)] + public static unsafe extern RdcleanpathFfiResultVoidBoxIronRdpError GetServerAddr(RdCleanPathPdu* self, DiplomatWriteable* serverAddr); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RdCleanPathPdu_destroy", ExactSpelling = true)] + public static unsafe extern void Destroy(RdCleanPathPdu* self); +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdCleanPathRequestBuilder.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdCleanPathRequestBuilder.cs new file mode 100644 index 000000000..d1f3f5f2a --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdCleanPathRequestBuilder.cs @@ -0,0 +1,39 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct RdCleanPathRequestBuilder +{ + private const string NativeLib = "DevolutionsIronRdp"; + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RdCleanPathRequestBuilder_new", ExactSpelling = true)] + public static unsafe extern RdCleanPathRequestBuilder* New(); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RdCleanPathRequestBuilder_with_x224_pdu", ExactSpelling = true)] + public static unsafe extern void WithX224Pdu(RdCleanPathRequestBuilder* self, VecU8* x224Pdu); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RdCleanPathRequestBuilder_with_destination", ExactSpelling = true)] + public static unsafe extern void WithDestination(RdCleanPathRequestBuilder* self, byte* destination, nuint destinationSz); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RdCleanPathRequestBuilder_with_proxy_auth", ExactSpelling = true)] + public static unsafe extern void WithProxyAuth(RdCleanPathRequestBuilder* self, byte* proxyAuth, nuint proxyAuthSz); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RdCleanPathRequestBuilder_with_pcb", ExactSpelling = true)] + public static unsafe extern void WithPcb(RdCleanPathRequestBuilder* self, byte* pcb, nuint pcbSz); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RdCleanPathRequestBuilder_build", ExactSpelling = true)] + public static unsafe extern RdcleanpathFfiResultBoxRdCleanPathPduBoxIronRdpError Build(RdCleanPathRequestBuilder* self); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "RdCleanPathRequestBuilder_destroy", ExactSpelling = true)] + public static unsafe extern void Destroy(RdCleanPathRequestBuilder* self); +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultBoxRdCleanPathPduBoxIronRdpError.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultBoxRdCleanPathPduBoxIronRdpError.cs new file mode 100644 index 000000000..74bf82a09 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultBoxRdCleanPathPduBoxIronRdpError.cs @@ -0,0 +1,46 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct RdcleanpathFfiResultBoxRdCleanPathPduBoxIronRdpError +{ + [StructLayout(LayoutKind.Explicit)] + private unsafe struct InnerUnion + { + [FieldOffset(0)] + internal RdCleanPathPdu* ok; + [FieldOffset(0)] + internal IronRdpError* err; + } + + private InnerUnion _inner; + + [MarshalAs(UnmanagedType.U1)] + public bool isOk; + + public unsafe RdCleanPathPdu* Ok + { + get + { + return _inner.ok; + } + } + + public unsafe IronRdpError* Err + { + get + { + return _inner.err; + } + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultBoxServerCertChainBoxIronRdpError.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultBoxServerCertChainBoxIronRdpError.cs new file mode 100644 index 000000000..c78b2d558 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultBoxServerCertChainBoxIronRdpError.cs @@ -0,0 +1,46 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct RdcleanpathFfiResultBoxServerCertChainBoxIronRdpError +{ + [StructLayout(LayoutKind.Explicit)] + private unsafe struct InnerUnion + { + [FieldOffset(0)] + internal ServerCertChain* ok; + [FieldOffset(0)] + internal IronRdpError* err; + } + + private InnerUnion _inner; + + [MarshalAs(UnmanagedType.U1)] + public bool isOk; + + public unsafe ServerCertChain* Ok + { + get + { + return _inner.ok; + } + } + + public unsafe IronRdpError* Err + { + get + { + return _inner.err; + } + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultBoxVecU8BoxIronRdpError.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultBoxVecU8BoxIronRdpError.cs new file mode 100644 index 000000000..7cce2e6ad --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultBoxVecU8BoxIronRdpError.cs @@ -0,0 +1,46 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct RdcleanpathFfiResultBoxVecU8BoxIronRdpError +{ + [StructLayout(LayoutKind.Explicit)] + private unsafe struct InnerUnion + { + [FieldOffset(0)] + internal VecU8* ok; + [FieldOffset(0)] + internal IronRdpError* err; + } + + private InnerUnion _inner; + + [MarshalAs(UnmanagedType.U1)] + public bool isOk; + + public unsafe VecU8* Ok + { + get + { + return _inner.ok; + } + } + + public unsafe IronRdpError* Err + { + get + { + return _inner.err; + } + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultVoidBoxIronRdpError.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultVoidBoxIronRdpError.cs new file mode 100644 index 000000000..c1e085512 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawRdcleanpathFfiResultVoidBoxIronRdpError.cs @@ -0,0 +1,36 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct RdcleanpathFfiResultVoidBoxIronRdpError +{ + [StructLayout(LayoutKind.Explicit)] + private unsafe struct InnerUnion + { + [FieldOffset(0)] + internal IronRdpError* err; + } + + private InnerUnion _inner; + + [MarshalAs(UnmanagedType.U1)] + public bool isOk; + + public unsafe IronRdpError* Err + { + get + { + return _inner.err; + } + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawServerCertChain.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawServerCertChain.cs new file mode 100644 index 000000000..bd3bf3913 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawServerCertChain.cs @@ -0,0 +1,30 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct ServerCertChain +{ + private const string NativeLib = "DevolutionsIronRdp"; + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ServerCertChain_get_len", ExactSpelling = true)] + public static unsafe extern nuint GetLen(ServerCertChain* self); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ServerCertChain_get_vecu8", ExactSpelling = true)] + public static unsafe extern UtilsFfiResultBoxVecU8BoxIronRdpError GetVecu8(ServerCertChain* self, nuint index); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ServerCertChain_get_slice", ExactSpelling = true)] + public static unsafe extern UtilsFfiResultBoxBytesSliceBoxIronRdpError GetSlice(ServerCertChain* self, nuint index); + + [DllImport(NativeLib, CallingConvention = CallingConvention.Cdecl, EntryPoint = "ServerCertChain_destroy", ExactSpelling = true)] + public static unsafe extern void Destroy(ServerCertChain* self); +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawUtilsFfiResultBoxBytesSliceBoxIronRdpError.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawUtilsFfiResultBoxBytesSliceBoxIronRdpError.cs new file mode 100644 index 000000000..5527183b6 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawUtilsFfiResultBoxBytesSliceBoxIronRdpError.cs @@ -0,0 +1,46 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct UtilsFfiResultBoxBytesSliceBoxIronRdpError +{ + [StructLayout(LayoutKind.Explicit)] + private unsafe struct InnerUnion + { + [FieldOffset(0)] + internal BytesSlice* ok; + [FieldOffset(0)] + internal IronRdpError* err; + } + + private InnerUnion _inner; + + [MarshalAs(UnmanagedType.U1)] + public bool isOk; + + public unsafe BytesSlice* Ok + { + get + { + return _inner.ok; + } + } + + public unsafe IronRdpError* Err + { + get + { + return _inner.err; + } + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RawUtilsFfiResultBoxVecU8BoxIronRdpError.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RawUtilsFfiResultBoxVecU8BoxIronRdpError.cs new file mode 100644 index 000000000..823dd2517 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RawUtilsFfiResultBoxVecU8BoxIronRdpError.cs @@ -0,0 +1,46 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp.Raw; + +#nullable enable + +[StructLayout(LayoutKind.Sequential)] +public partial struct UtilsFfiResultBoxVecU8BoxIronRdpError +{ + [StructLayout(LayoutKind.Explicit)] + private unsafe struct InnerUnion + { + [FieldOffset(0)] + internal VecU8* ok; + [FieldOffset(0)] + internal IronRdpError* err; + } + + private InnerUnion _inner; + + [MarshalAs(UnmanagedType.U1)] + public bool isOk; + + public unsafe VecU8* Ok + { + get + { + return _inner.ok; + } + } + + public unsafe IronRdpError* Err + { + get + { + return _inner.err; + } + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RdCleanPathPdu.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RdCleanPathPdu.cs new file mode 100644 index 000000000..7b4f816b6 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RdCleanPathPdu.cs @@ -0,0 +1,225 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp; + +#nullable enable + +public partial class RdCleanPathPdu: IDisposable +{ + private unsafe Raw.RdCleanPathPdu* _inner; + + public string ServerAddr + { + get + { + return GetServerAddr(); + } + } + + public ServerCertChain ServerCertChain + { + get + { + return GetServerCertChain(); + } + } + + public VecU8 X224ConnectionPdu + { + get + { + return GetX224ConnectionPdu(); + } + } + + /// + /// Creates a managed RdCleanPathPdu from a raw handle. + /// + /// + /// Safety: you should not build two managed objects using the same raw handle (may causes use-after-free and double-free). + ///
+ /// This constructor assumes the raw struct is allocated on Rust side. + /// If implemented, the custom Drop implementation on Rust side WILL run on destruction. + ///
+ public unsafe RdCleanPathPdu(Raw.RdCleanPathPdu* handle) + { + _inner = handle; + } + + /// + /// + /// A VecU8 allocated on Rust side. + /// + public VecU8 ToDer() + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("RdCleanPathPdu"); + } + Raw.RdcleanpathFfiResultBoxVecU8BoxIronRdpError result = Raw.RdCleanPathPdu.ToDer(_inner); + if (!result.isOk) + { + throw new IronRdpException(new IronRdpError(result.Err)); + } + Raw.VecU8* retVal = result.Ok; + return new VecU8(retVal); + } + } + + /// + /// A PduHint allocated on Rust side. + /// + public static PduHint GetHint() + { + unsafe + { + Raw.PduHint* retVal = Raw.RdCleanPathPdu.GetHint(); + return new PduHint(retVal); + } + } + + /// + /// + /// A RdCleanPathPdu allocated on Rust side. + /// + public static RdCleanPathPdu FromDer(byte[] der) + { + unsafe + { + nuint derLength = (nuint)der.Length; + fixed (byte* derPtr = der) + { + Raw.RdcleanpathFfiResultBoxRdCleanPathPduBoxIronRdpError result = Raw.RdCleanPathPdu.FromDer(derPtr, derLength); + if (!result.isOk) + { + throw new IronRdpException(new IronRdpError(result.Err)); + } + Raw.RdCleanPathPdu* retVal = result.Ok; + return new RdCleanPathPdu(retVal); + } + } + } + + /// + /// + /// A VecU8 allocated on Rust side. + /// + public VecU8 GetX224ConnectionPdu() + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("RdCleanPathPdu"); + } + Raw.RdcleanpathFfiResultBoxVecU8BoxIronRdpError result = Raw.RdCleanPathPdu.GetX224ConnectionPdu(_inner); + if (!result.isOk) + { + throw new IronRdpException(new IronRdpError(result.Err)); + } + Raw.VecU8* retVal = result.Ok; + return new VecU8(retVal); + } + } + + /// + /// + /// A ServerCertChain allocated on Rust side. + /// + public ServerCertChain GetServerCertChain() + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("RdCleanPathPdu"); + } + Raw.RdcleanpathFfiResultBoxServerCertChainBoxIronRdpError result = Raw.RdCleanPathPdu.GetServerCertChain(_inner); + if (!result.isOk) + { + throw new IronRdpException(new IronRdpError(result.Err)); + } + Raw.ServerCertChain* retVal = result.Ok; + return new ServerCertChain(retVal); + } + } + + /// + public void GetServerAddr(DiplomatWriteable serverAddr) + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("RdCleanPathPdu"); + } + Raw.RdcleanpathFfiResultVoidBoxIronRdpError result = Raw.RdCleanPathPdu.GetServerAddr(_inner, &serverAddr); + if (!result.isOk) + { + throw new IronRdpException(new IronRdpError(result.Err)); + } + } + } + + /// + public string GetServerAddr() + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("RdCleanPathPdu"); + } + DiplomatWriteable writeable = new DiplomatWriteable(); + Raw.RdcleanpathFfiResultVoidBoxIronRdpError result = Raw.RdCleanPathPdu.GetServerAddr(_inner, &writeable); + if (!result.isOk) + { + throw new IronRdpException(new IronRdpError(result.Err)); + } + string retVal = writeable.ToUnicode(); + writeable.Dispose(); + return retVal; + } + } + + /// + /// Returns the underlying raw handle. + /// + public unsafe Raw.RdCleanPathPdu* AsFFI() + { + return _inner; + } + + /// + /// Destroys the underlying object immediately. + /// + public void Dispose() + { + unsafe + { + if (_inner == null) + { + return; + } + + Raw.RdCleanPathPdu.Destroy(_inner); + _inner = null; + + GC.SuppressFinalize(this); + } + } + + ~RdCleanPathPdu() + { + Dispose(); + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/RdCleanPathRequestBuilder.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/RdCleanPathRequestBuilder.cs new file mode 100644 index 000000000..cb0df5499 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/RdCleanPathRequestBuilder.cs @@ -0,0 +1,166 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp; + +#nullable enable + +public partial class RdCleanPathRequestBuilder: IDisposable +{ + private unsafe Raw.RdCleanPathRequestBuilder* _inner; + + /// + /// Creates a managed RdCleanPathRequestBuilder from a raw handle. + /// + /// + /// Safety: you should not build two managed objects using the same raw handle (may causes use-after-free and double-free). + ///
+ /// This constructor assumes the raw struct is allocated on Rust side. + /// If implemented, the custom Drop implementation on Rust side WILL run on destruction. + ///
+ public unsafe RdCleanPathRequestBuilder(Raw.RdCleanPathRequestBuilder* handle) + { + _inner = handle; + } + + /// + /// A RdCleanPathRequestBuilder allocated on Rust side. + /// + public static RdCleanPathRequestBuilder New() + { + unsafe + { + Raw.RdCleanPathRequestBuilder* retVal = Raw.RdCleanPathRequestBuilder.New(); + return new RdCleanPathRequestBuilder(retVal); + } + } + + public void WithX224Pdu(VecU8 x224Pdu) + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("RdCleanPathRequestBuilder"); + } + Raw.VecU8* x224PduRaw; + x224PduRaw = x224Pdu.AsFFI(); + if (x224PduRaw == null) + { + throw new ObjectDisposedException("VecU8"); + } + Raw.RdCleanPathRequestBuilder.WithX224Pdu(_inner, x224PduRaw); + } + } + + public void WithDestination(string destination) + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("RdCleanPathRequestBuilder"); + } + byte[] destinationBuf = DiplomatUtils.StringToUtf8(destination); + nuint destinationBufLength = (nuint)destinationBuf.Length; + fixed (byte* destinationBufPtr = destinationBuf) + { + Raw.RdCleanPathRequestBuilder.WithDestination(_inner, destinationBufPtr, destinationBufLength); + } + } + } + + public void WithProxyAuth(string proxyAuth) + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("RdCleanPathRequestBuilder"); + } + byte[] proxyAuthBuf = DiplomatUtils.StringToUtf8(proxyAuth); + nuint proxyAuthBufLength = (nuint)proxyAuthBuf.Length; + fixed (byte* proxyAuthBufPtr = proxyAuthBuf) + { + Raw.RdCleanPathRequestBuilder.WithProxyAuth(_inner, proxyAuthBufPtr, proxyAuthBufLength); + } + } + } + + public void WithPcb(string pcb) + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("RdCleanPathRequestBuilder"); + } + byte[] pcbBuf = DiplomatUtils.StringToUtf8(pcb); + nuint pcbBufLength = (nuint)pcbBuf.Length; + fixed (byte* pcbBufPtr = pcbBuf) + { + Raw.RdCleanPathRequestBuilder.WithPcb(_inner, pcbBufPtr, pcbBufLength); + } + } + } + + /// + /// + /// A RdCleanPathPdu allocated on Rust side. + /// + public RdCleanPathPdu Build() + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("RdCleanPathRequestBuilder"); + } + Raw.RdcleanpathFfiResultBoxRdCleanPathPduBoxIronRdpError result = Raw.RdCleanPathRequestBuilder.Build(_inner); + if (!result.isOk) + { + throw new IronRdpException(new IronRdpError(result.Err)); + } + Raw.RdCleanPathPdu* retVal = result.Ok; + return new RdCleanPathPdu(retVal); + } + } + + /// + /// Returns the underlying raw handle. + /// + public unsafe Raw.RdCleanPathRequestBuilder* AsFFI() + { + return _inner; + } + + /// + /// Destroys the underlying object immediately. + /// + public void Dispose() + { + unsafe + { + if (_inner == null) + { + return; + } + + Raw.RdCleanPathRequestBuilder.Destroy(_inner); + _inner = null; + + GC.SuppressFinalize(this); + } + } + + ~RdCleanPathRequestBuilder() + { + Dispose(); + } +} diff --git a/ffi/dotnet/Devolutions.IronRdp/Generated/ServerCertChain.cs b/ffi/dotnet/Devolutions.IronRdp/Generated/ServerCertChain.cs new file mode 100644 index 000000000..835bf2341 --- /dev/null +++ b/ffi/dotnet/Devolutions.IronRdp/Generated/ServerCertChain.cs @@ -0,0 +1,128 @@ +// by Diplomat + +#pragma warning disable 0105 +using System; +using System.Runtime.InteropServices; + +using Devolutions.IronRdp.Diplomat; +#pragma warning restore 0105 + +namespace Devolutions.IronRdp; + +#nullable enable + +public partial class ServerCertChain: IDisposable +{ + private unsafe Raw.ServerCertChain* _inner; + + public nuint Len + { + get + { + return GetLen(); + } + } + + /// + /// Creates a managed ServerCertChain from a raw handle. + /// + /// + /// Safety: you should not build two managed objects using the same raw handle (may causes use-after-free and double-free). + ///
+ /// This constructor assumes the raw struct is allocated on Rust side. + /// If implemented, the custom Drop implementation on Rust side WILL run on destruction. + ///
+ public unsafe ServerCertChain(Raw.ServerCertChain* handle) + { + _inner = handle; + } + + public nuint GetLen() + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("ServerCertChain"); + } + nuint retVal = Raw.ServerCertChain.GetLen(_inner); + return retVal; + } + } + + /// + /// + /// A VecU8 allocated on Rust side. + /// + public VecU8 GetVecu8(nuint index) + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("ServerCertChain"); + } + Raw.UtilsFfiResultBoxVecU8BoxIronRdpError result = Raw.ServerCertChain.GetVecu8(_inner, index); + if (!result.isOk) + { + throw new IronRdpException(new IronRdpError(result.Err)); + } + Raw.VecU8* retVal = result.Ok; + return new VecU8(retVal); + } + } + + /// + /// + /// A BytesSlice allocated on Rust side. + /// + public BytesSlice GetSlice(nuint index) + { + unsafe + { + if (_inner == null) + { + throw new ObjectDisposedException("ServerCertChain"); + } + Raw.UtilsFfiResultBoxBytesSliceBoxIronRdpError result = Raw.ServerCertChain.GetSlice(_inner, index); + if (!result.isOk) + { + throw new IronRdpException(new IronRdpError(result.Err)); + } + Raw.BytesSlice* retVal = result.Ok; + return new BytesSlice(retVal); + } + } + + /// + /// Returns the underlying raw handle. + /// + public unsafe Raw.ServerCertChain* AsFFI() + { + return _inner; + } + + /// + /// Destroys the underlying object immediately. + /// + public void Dispose() + { + unsafe + { + if (_inner == null) + { + return; + } + + Raw.ServerCertChain.Destroy(_inner); + _inner = null; + + GC.SuppressFinalize(this); + } + } + + ~ServerCertChain() + { + Dispose(); + } +} diff --git a/ffi/src/error.rs b/ffi/src/error.rs index 9312ba45f..ffdc6c41f 100644 --- a/ffi/src/error.rs +++ b/ffi/src/error.rs @@ -139,6 +139,8 @@ pub mod ffi { Clipboard, #[error("wrong platform error")] WrongOS, + #[error("Missing required field")] + MissingRequiredField, } /// Stringified Picky error along with an error kind. diff --git a/ffi/src/lib.rs b/ffi/src/lib.rs index 407847ce4..44009cd5a 100644 --- a/ffi/src/lib.rs +++ b/ffi/src/lib.rs @@ -11,6 +11,7 @@ pub mod graphics; pub mod input; pub mod log; pub mod pdu; +pub mod rdcleanpath; pub mod session; pub mod svc; pub mod utils; diff --git a/ffi/src/rdcleanpath.rs b/ffi/src/rdcleanpath.rs new file mode 100644 index 000000000..34bedc11b --- /dev/null +++ b/ffi/src/rdcleanpath.rs @@ -0,0 +1,135 @@ +#[derive(Clone, Copy, Debug)] +struct RDCleanPathHint; + +const RDCLEANPATH_HINT: RDCleanPathHint = RDCleanPathHint; + +impl ironrdp::pdu::PduHint for RDCleanPathHint { + fn find_size(&self, bytes: &[u8]) -> ironrdp::core::DecodeResult> { + match ironrdp_rdcleanpath::RDCleanPathPdu::detect(bytes) { + ironrdp_rdcleanpath::DetectionResult::Detected { total_length, .. } => Ok(Some((true, total_length))), + ironrdp_rdcleanpath::DetectionResult::NotEnoughBytes => Ok(None), + ironrdp_rdcleanpath::DetectionResult::Failed => Err(ironrdp::core::other_err!( + "RDCleanPathHint", + "detection failed (invalid PDU)" + )), + } + } +} + +#[diplomat::bridge] +pub mod ffi { + + use crate::error::ffi::{IronRdpError, IronRdpErrorKind}; + use crate::error::ValueConsumedError; + use crate::utils::ffi::{ServerCertChain, VecU8}; + use core::fmt::Write; + + #[diplomat::opaque] + pub struct RdCleanPathPdu(pub ironrdp_rdcleanpath::RDCleanPathPdu); + + #[diplomat::opaque] + pub struct RdCleanPathRequestBuilder { + x224_pdu: Option>, + destination: Option, + proxy_auth: Option, + pcb: Option, + } + + impl RdCleanPathRequestBuilder { + pub fn new() -> Box { + Box::new(RdCleanPathRequestBuilder { + x224_pdu: None, + destination: None, + proxy_auth: None, + pcb: None, + }) + } + + pub fn with_x224_pdu(&mut self, x224_pdu: &VecU8) { + self.x224_pdu = Some(x224_pdu.0.clone()); + } + + pub fn with_destination(&mut self, destination: &str) { + self.destination = Some(destination.to_owned()); + } + + pub fn with_proxy_auth(&mut self, proxy_auth: &str) { + self.proxy_auth = Some(proxy_auth.to_owned()); + } + + pub fn with_pcb(&mut self, pcb: &str) { + self.pcb = Some(pcb.to_owned()); + } + + pub fn build(&self) -> Result, Box> { + let RdCleanPathRequestBuilder { + x224_pdu, + destination, + proxy_auth, + pcb, + } = self; + + let request = ironrdp_rdcleanpath::RDCleanPathPdu::new_request( + x224_pdu.to_owned().ok_or(IronRdpErrorKind::MissingRequiredField)?, + destination.to_owned().ok_or(IronRdpErrorKind::MissingRequiredField)?, + proxy_auth.to_owned().ok_or(IronRdpErrorKind::MissingRequiredField)?, + pcb.to_owned(), + ) + .map_err(|_| IronRdpErrorKind::EncodeError)?; + + Ok(Box::new(RdCleanPathPdu(request))) + } + } + + impl RdCleanPathPdu { + pub fn to_der(&self) -> Result, Box> { + let der = self.0.to_der().map_err(|_| IronRdpErrorKind::EncodeError)?; + Ok(Box::new(VecU8(der))) + } + + pub fn get_hint<'a>() -> Box> { + Box::new(crate::connector::ffi::PduHint(&super::RDCLEANPATH_HINT)) + } + + pub fn from_der(der: &[u8]) -> Result, Box> { + let pdu = ironrdp_rdcleanpath::RDCleanPathPdu::from_der(der).map_err(|_| IronRdpErrorKind::DecodeError)?; + Ok(Box::new(RdCleanPathPdu(pdu))) + } + + pub fn get_x224_connection_pdu(&self) -> Result, Box> { + let Some(x224_pdu_response) = self.0.x224_connection_pdu.as_ref() else { + return Err(ValueConsumedError::for_item("RdCleanPathPdu").into()); + }; + + let result = x224_pdu_response.as_bytes().to_vec(); + + Ok(Box::new(VecU8(result))) + } + + pub fn get_server_cert_chain(&self) -> Result, Box> { + let Some(server_cert_chain) = self.0.server_cert_chain.as_ref() else { + return Err(ValueConsumedError::for_item("ServerCertChain").into()); + }; + + let vecs = server_cert_chain + .iter() + .map(|cert| cert.as_bytes().to_vec()) + .collect::>(); + + Ok(Box::new(ServerCertChain(vecs))) + } + + pub fn get_server_addr( + &self, + server_addr: &mut diplomat_runtime::DiplomatWriteable, + ) -> Result<(), Box> { + let Some(server_addr_str) = self.0.server_addr.as_ref() else { + return Err(ValueConsumedError::for_item("server_addr").into()); + }; + + write!(server_addr, "{server_addr_str}").map_err(|_| IronRdpErrorKind::IO)?; + + Ok(()) + } + } +} diff --git a/ffi/src/utils/mod.rs b/ffi/src/utils/mod.rs index 672c5653e..b60e40284 100644 --- a/ffi/src/utils/mod.rs +++ b/ffi/src/utils/mod.rs @@ -3,6 +3,29 @@ pub mod ffi { use crate::error::ffi::IronRdpError; + #[diplomat::opaque] + pub struct ServerCertChain(pub Vec>); + + impl ServerCertChain { + pub fn get_len(&self) -> usize { + self.0.len() + } + + pub fn get_vecu8(&self, index: usize) -> Result, Box> { + if index >= self.0.len() { + return Err("index out of bounds".into()); + } + Ok(Box::new(VecU8(self.0[index].clone()))) + } + + pub fn get_slice<'a>(&'a self, index: usize) -> Result>, Box> { + if index >= self.0.len() { + return Err("index out of bounds".into()); + } + Ok(Box::new(BytesSlice(&self.0[index]))) + } + } + #[diplomat::opaque] pub struct VecU8(pub Vec);