Skip to content

Commit c48bbe2

Browse files
committed
Added QueryServicePrincipalName
1 parent d059914 commit c48bbe2

3 files changed

Lines changed: 104 additions & 54 deletions

File tree

NtApiDotNet/Win32/Rpc/Transport/RpcTransportSecurity.cs

Lines changed: 96 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
using NtApiDotNet.Win32.SafeHandles;
1516
using NtApiDotNet.Win32.Security.Authentication;
1617
using System;
1718

@@ -22,9 +23,68 @@ namespace NtApiDotNet.Win32.Rpc.Transport
2223
/// </summary>
2324
public struct RpcTransportSecurity
2425
{
26+
#region Private Members
2527
private readonly Func<RpcTransportSecurity, IClientAuthenticationContext> _auth_factory;
2628
private RpcAuthenticationType _auth_type;
2729

30+
private string GetAuthPackageName()
31+
{
32+
switch (_auth_type)
33+
{
34+
case RpcAuthenticationType.Negotiate:
35+
return AuthenticationPackage.NEGOSSP_NAME;
36+
case RpcAuthenticationType.Kerberos:
37+
return AuthenticationPackage.KERBEROS_NAME;
38+
case RpcAuthenticationType.WinNT:
39+
return AuthenticationPackage.NTLM_NAME;
40+
case RpcAuthenticationType.None:
41+
throw new ArgumentException("Must specify an authentication type to authenticate an RPC connection.");
42+
default:
43+
throw new ArgumentException($"Unknown authentication type: {_auth_type}");
44+
}
45+
}
46+
47+
private InitializeContextReqFlags GetContextRequestFlags()
48+
{
49+
InitializeContextReqFlags flags = InitializeContextReqFlags.Connection | InitializeContextReqFlags.UseDCEStyle;
50+
if (SecurityQualityOfService != null)
51+
{
52+
switch (SecurityQualityOfService.ImpersonationLevel)
53+
{
54+
case SecurityImpersonationLevel.Identification:
55+
flags |= InitializeContextReqFlags.Identify;
56+
break;
57+
case SecurityImpersonationLevel.Delegation:
58+
flags |= InitializeContextReqFlags.Delegate | InitializeContextReqFlags.MutualAuth;
59+
break;
60+
}
61+
}
62+
63+
switch (AuthenticationLevel)
64+
{
65+
case RpcAuthenticationLevel.PacketIntegrity:
66+
flags |= InitializeContextReqFlags.Integrity | InitializeContextReqFlags.ReplayDetect | InitializeContextReqFlags.SequenceDetect;
67+
break;
68+
case RpcAuthenticationLevel.PacketPrivacy:
69+
flags |= InitializeContextReqFlags.Confidentiality | InitializeContextReqFlags.Integrity | InitializeContextReqFlags.ReplayDetect | InitializeContextReqFlags.SequenceDetect;
70+
break;
71+
}
72+
73+
if (AuthenticationCapabilities.HasFlagSet(RpcAuthenticationCapabilities.MutualAuthentication))
74+
{
75+
flags |= InitializeContextReqFlags.MutualAuth;
76+
}
77+
if (AuthenticationCapabilities.HasFlagSet(RpcAuthenticationCapabilities.NullSession))
78+
{
79+
flags |= InitializeContextReqFlags.NullSession;
80+
}
81+
82+
return flags;
83+
}
84+
85+
#endregion
86+
87+
#region Public Properties
2888
/// <summary>
2989
/// Security quality of service.
3090
/// </summary>
@@ -58,7 +118,9 @@ public RpcAuthenticationType AuthenticationType
58118
/// Authentication capabilities.
59119
/// </summary>
60120
public RpcAuthenticationCapabilities AuthenticationCapabilities { get; set; }
121+
#endregion
61122

123+
#region Constructors
62124
/// <summary>
63125
/// Constructor.
64126
/// </summary>
@@ -77,62 +139,49 @@ public RpcTransportSecurity(SecurityQualityOfService security_quality_of_service
77139
{
78140
SecurityQualityOfService = security_quality_of_service;
79141
}
142+
#endregion
80143

81-
private string GetAuthPackageName()
82-
{
83-
switch (_auth_type)
84-
{
85-
case RpcAuthenticationType.Negotiate:
86-
return AuthenticationPackage.NEGOSSP_NAME;
87-
case RpcAuthenticationType.Kerberos:
88-
return AuthenticationPackage.KERBEROS_NAME;
89-
case RpcAuthenticationType.WinNT:
90-
return AuthenticationPackage.NTLM_NAME;
91-
case RpcAuthenticationType.None:
92-
throw new ArgumentException("Must specify an authentication type to authenticate an RPC connection.");
93-
default:
94-
throw new ArgumentException($"Unknown authentication type: {_auth_type}");
95-
}
96-
}
97-
98-
private InitializeContextReqFlags GetContextRequestFlags()
144+
#region Static Members
145+
/// <summary>
146+
/// Query the service principal name for the server.
147+
/// </summary>
148+
/// <param name="string_binding">The binding string for the server.</param>
149+
/// <param name="authn_svc">The authentication service to query.</param>
150+
/// <param name="throw_on_error">True to throw on error.</param>
151+
/// <returns>The service principal name.</returns>
152+
public static NtResult<string> QueryServicePrincipalName(string string_binding, RpcAuthenticationType authn_svc, bool throw_on_error)
99153
{
100-
InitializeContextReqFlags flags = InitializeContextReqFlags.Connection | InitializeContextReqFlags.UseDCEStyle;
101-
if (SecurityQualityOfService != null)
154+
using (var binding = SafeRpcBindingHandle.Create(string_binding, false))
102155
{
103-
switch (SecurityQualityOfService.ImpersonationLevel)
156+
if (!binding.IsSuccess)
104157
{
105-
case SecurityImpersonationLevel.Identification:
106-
flags |= InitializeContextReqFlags.Identify;
107-
break;
108-
case SecurityImpersonationLevel.Delegation:
109-
flags |= InitializeContextReqFlags.Delegate | InitializeContextReqFlags.MutualAuth;
110-
break;
158+
return binding.Cast<string>();
111159
}
112-
}
113160

114-
switch (AuthenticationLevel)
115-
{
116-
case RpcAuthenticationLevel.PacketIntegrity:
117-
flags |= InitializeContextReqFlags.Integrity | InitializeContextReqFlags.ReplayDetect | InitializeContextReqFlags.SequenceDetect;
118-
break;
119-
case RpcAuthenticationLevel.PacketPrivacy:
120-
flags |= InitializeContextReqFlags.Confidentiality | InitializeContextReqFlags.Integrity | InitializeContextReqFlags.ReplayDetect | InitializeContextReqFlags.SequenceDetect;
121-
break;
122-
}
123-
124-
if (AuthenticationCapabilities.HasFlagSet(RpcAuthenticationCapabilities.MutualAuthentication))
125-
{
126-
flags |= InitializeContextReqFlags.MutualAuth;
127-
}
128-
if (AuthenticationCapabilities.HasFlagSet(RpcAuthenticationCapabilities.NullSession))
129-
{
130-
flags |= InitializeContextReqFlags.NullSession;
161+
return Win32NativeMethods.RpcMgmtInqServerPrincName(binding.Result, authn_svc,
162+
out SafeRpcStringHandle spn).CreateWin32Result(throw_on_error, () => {
163+
using (spn)
164+
{
165+
return spn.ToString();
166+
}
167+
}
168+
);
131169
}
170+
}
132171

133-
return flags;
172+
/// <summary>
173+
/// Query the service principal name for the server.
174+
/// </summary>
175+
/// <param name="string_binding">The binding string for the server.</param>
176+
/// <param name="authn_svc">The authentication service to query.</param>
177+
/// <returns>The service principal name.</returns>
178+
public static string QueryServicePrincipalName(string string_binding, RpcAuthenticationType authn_svc)
179+
{
180+
return QueryServicePrincipalName(string_binding, authn_svc, true).Result;
134181
}
182+
#endregion
135183

184+
#region Internal Members
136185
internal IClientAuthenticationContext CreateClientContext()
137186
{
138187
if (_auth_factory != null)
@@ -157,5 +206,6 @@ internal IClientAuthenticationContext CreateClientContext()
157206
ServicePrincipalName, SecDataRep.Native);
158207
}
159208
}
209+
#endregion
160210
}
161211
}

NtApiDotNet/Win32/RpcEndpointMapper.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -140,14 +140,6 @@ private static IEnumerable<RpcEndpoint> QueryEndpointsForBinding(SafeRpcBindingH
140140
}
141141
}
142142

143-
/// <summary>
144-
/// Resolve the binding string for this service from the local Endpoint Mapper.
145-
/// </summary>
146-
/// <param name="binding">The binding handle.</param>
147-
/// <param name="interface_id">Interface UUID to lookup.</param>
148-
/// <param name="interface_version">Interface version lookup.</param>
149-
/// <remarks>This only will return a valid value if the service is running and registered with the Endpoint Mapper. It can also hang.</remarks>
150-
/// <returns>The RPC binding string. Empty string if it doesn't exist or the lookup failed.</returns>
151143
private static string MapBindingToBindingString(NtResult<SafeRpcBindingHandle> binding, Guid interface_id, Version interface_version)
152144
{
153145
if (!binding.IsSuccess)

NtApiDotNet/Win32/Win32NativeMethods.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
using NtApiDotNet.Ndr;
1616
using NtApiDotNet.Win32.Debugger;
17+
using NtApiDotNet.Win32.Rpc.Transport;
1718
using NtApiDotNet.Win32.SafeHandles;
1819
using NtApiDotNet.Win32.Security.Native;
1920
using System;
@@ -627,6 +628,13 @@ internal static extern int RpcMgmtInqIfIds(
627628
out SafeRpcIfIdVectorHandle IfIdVector
628629
);
629630

631+
[DllImport("rpcrt4.dll", CharSet = CharSet.Unicode)]
632+
internal static extern Win32Error RpcMgmtInqServerPrincName(
633+
SafeRpcBindingHandle Binding,
634+
RpcAuthenticationType AuthnSvc,
635+
out SafeRpcStringHandle ServerPrincName
636+
);
637+
630638
[DllImport("rpcrt4.dll", CharSet = CharSet.Unicode)]
631639
internal static extern int RpcBindingFree(ref IntPtr Binding);
632640

0 commit comments

Comments
 (0)