disable broken tests on net_4_0
[mcs.git] / class / Npgsql / Npgsql / SSPIHandler.cs
blob6215a747bed637e8ae2ca88030a981c2fe5f418f
1 #if WINDOWS && UNMANAGED
3 using System;
4 using System.IO;
5 using System.Runtime.InteropServices;
6 using System.ComponentModel;
8 namespace Npgsql
10 /// <summary>
11 /// A class to handle everything associated with SSPI authentication
12 /// </summary>
13 internal class SSPIHandler : IDisposable
15 #region constants and structs
17 private const int SECBUFFER_VERSION = 0;
18 private const int SECBUFFER_TOKEN = 2;
19 private const int SEC_E_OK = 0x00000000;
20 private const int SEC_I_CONTINUE_NEEDED = 0x00090312;
21 private const int ISC_REQ_ALLOCATE_MEMORY=0x00000100;
22 private const int SECURITY_NETWORK_DREP=0x00000000;
23 private const int SECPKG_CRED_OUTBOUND=0x00000002;
25 [StructLayout(LayoutKind.Sequential)]
26 private struct SecHandle
28 public int dwLower;
29 public int dwUpper;
32 [StructLayout(LayoutKind.Sequential)]
33 private struct SecBuffer
35 public int cbBuffer;
36 public int BufferType;
37 public IntPtr pvBuffer;
40 /// <summary>
41 /// Simplified SecBufferDesc struct with only one SecBuffer
42 /// </summary>
43 [StructLayout(LayoutKind.Sequential)]
44 private struct SecBufferDesc
46 public int ulVersion;
47 public int cBuffers;
48 public IntPtr pBuffer;
51 #endregion
53 #region p/invoke methods
55 [DllImport("Secur32.dll")]
56 private extern static int AcquireCredentialsHandle(
57 string pszPrincipal,
58 string pszPackage,
59 int fCredentialUse,
60 IntPtr pvLogonID,
61 IntPtr pAuthData,
62 IntPtr pGetKeyFn,
63 IntPtr pvGetKeyArgument,
64 ref SecHandle phCredential,
65 out SecHandle ptsExpiry
68 [DllImport("secur32", CharSet=CharSet.Auto, SetLastError=true)]
69 static extern int InitializeSecurityContext(
70 ref SecHandle phCredential,
71 ref SecHandle phContext,
72 string pszTargetName,
73 int fContextReq,
74 int Reserved1,
75 int TargetDataRep,
76 ref SecBufferDesc pInput,
77 int Reserved2,
78 out SecHandle phNewContext,
79 out SecBufferDesc pOutput,
80 out int pfContextAttr,
81 out SecHandle ptsExpiry);
83 [DllImport("secur32", CharSet=CharSet.Auto, SetLastError=true)]
84 static extern int InitializeSecurityContext(
85 ref SecHandle phCredential,
86 IntPtr phContext,
87 string pszTargetName,
88 int fContextReq,
89 int Reserved1,
90 int TargetDataRep,
91 IntPtr pInput,
92 int Reserved2,
93 out SecHandle phNewContext,
94 out SecBufferDesc pOutput,
95 out int pfContextAttr,
96 out SecHandle ptsExpiry);
98 [DllImport("Secur32.dll")]
99 private extern static int FreeContextBuffer(
100 IntPtr pvContextBuffer
103 [DllImport("Secur32.dll")]
104 private extern static int FreeCredentialsHandle(
105 ref SecHandle phCredential
108 [DllImport("Secur32.dll")]
109 private extern static int DeleteSecurityContext(
110 ref SecHandle phContext
113 #endregion
115 private bool disposed;
116 private string sspitarget;
117 private SecHandle sspicred;
118 private SecHandle sspictx;
119 private bool sspictx_set;
121 public SSPIHandler(string pghost, string krbsrvname)
123 if (pghost == null)
124 throw new ArgumentNullException("pghost");
125 if (krbsrvname == null)
126 krbsrvname = String.Empty;
127 sspitarget = String.Format("{0}/{1}", krbsrvname, pghost);
129 SecHandle expire;
130 int status = AcquireCredentialsHandle(
132 "negotiate",
133 SECPKG_CRED_OUTBOUND,
134 IntPtr.Zero,
135 IntPtr.Zero,
136 IntPtr.Zero,
137 IntPtr.Zero,
138 ref sspicred,
139 out expire
141 if (status != SEC_E_OK)
143 // This will automaticcaly fill in the message of the last Win32 error
144 throw new Win32Exception();
148 public string Continue(byte[] authData)
150 if (authData == null && sspictx_set)
151 throw new InvalidOperationException("The authData parameter con only be null at the first call to continue!");
154 int status;
156 SecBuffer OutBuffer;
157 SecBuffer InBuffer;
158 SecBufferDesc inbuf;
159 SecBufferDesc outbuf;
160 SecHandle newContext;
161 SecHandle expire;
162 int contextAttr;
164 OutBuffer.pvBuffer = IntPtr.Zero;
165 OutBuffer.BufferType = SECBUFFER_TOKEN;
166 OutBuffer.cbBuffer = 0;
167 outbuf.cBuffers = 1;
168 outbuf.ulVersion = SECBUFFER_VERSION;
169 outbuf.pBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(OutBuffer));
173 Marshal.StructureToPtr(OutBuffer, outbuf.pBuffer, false);
174 if (sspictx_set)
176 inbuf.pBuffer = IntPtr.Zero;
177 InBuffer.pvBuffer = Marshal.AllocHGlobal(authData.Length);
180 Marshal.Copy(authData, 0, InBuffer.pvBuffer, authData.Length);
181 InBuffer.cbBuffer = authData.Length;
182 InBuffer.BufferType = SECBUFFER_TOKEN;
183 inbuf.ulVersion = SECBUFFER_VERSION;
184 inbuf.cBuffers = 1;
185 inbuf.pBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(InBuffer));
186 Marshal.StructureToPtr(InBuffer, inbuf.pBuffer, false);
187 status = InitializeSecurityContext(
188 ref sspicred,
189 ref sspictx,
190 sspitarget,
191 ISC_REQ_ALLOCATE_MEMORY,
193 SECURITY_NETWORK_DREP,
194 ref inbuf,
196 out newContext,
197 out outbuf,
198 out contextAttr,
199 out expire
202 finally
204 if (InBuffer.pvBuffer != IntPtr.Zero)
205 Marshal.FreeHGlobal(InBuffer.pvBuffer);
206 if (inbuf.pBuffer != IntPtr.Zero)
207 Marshal.FreeHGlobal(inbuf.pBuffer);
210 else
212 status = InitializeSecurityContext(
213 ref sspicred,
214 IntPtr.Zero,
215 sspitarget,
216 ISC_REQ_ALLOCATE_MEMORY,
218 SECURITY_NETWORK_DREP,
219 IntPtr.Zero,
221 out newContext,
222 out outbuf,
223 out contextAttr,
224 out expire
228 if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED)
230 // This will automaticcaly fill in the message of the last Win32 error
231 throw new Win32Exception();
233 if (!sspictx_set)
235 sspictx.dwUpper = newContext.dwUpper;
236 sspictx.dwLower = newContext.dwLower;
237 sspictx_set = true;
241 if (outbuf.cBuffers > 0)
243 if (outbuf.cBuffers != 1)
245 throw new InvalidOperationException("SSPI returned invalid number of output buffers");
247 // attention: OutBuffer is still our initially created struct but outbuf.pBuffer doesn't point to
248 // it but to the copy of it we created on the unmanaged heap and passed to InitializeSecurityContext()
249 // we have to marshal it back to see the content change
250 OutBuffer = (SecBuffer)Marshal.PtrToStructure(outbuf.pBuffer, typeof(SecBuffer));
251 if (OutBuffer.cbBuffer > 0)
253 // we need the buffer with a terminating 0 so we
254 // make it one byte bigger
255 byte[] buffer = new byte[OutBuffer.cbBuffer];
256 Marshal.Copy(OutBuffer.pvBuffer, buffer, 0, buffer.Length);
257 // The SSPI authentication data must be sent as password message
259 return System.Text.Encoding.ASCII.GetString(buffer);
260 //stream.WriteByte((byte)'p');
261 //PGUtil.WriteInt32(stream, buffer.Length + 5);
262 //stream.Write(buffer, 0, buffer.Length);
263 //stream.Flush();
266 return String.Empty;
268 finally
270 if (OutBuffer.pvBuffer != IntPtr.Zero)
271 FreeContextBuffer(OutBuffer.pvBuffer);
272 if (outbuf.pBuffer != IntPtr.Zero)
273 Marshal.FreeHGlobal(outbuf.pBuffer);
278 #region resource cleanup
280 private void FreeHandles()
282 if (sspictx_set)
284 FreeCredentialsHandle(ref sspicred);
285 DeleteSecurityContext(ref sspictx);
289 ~SSPIHandler()
291 FreeHandles();
294 public void Dispose()
296 Dispose(true);
297 GC.SuppressFinalize(this);
300 protected virtual void Dispose(bool disposing)
302 if (!disposed)
304 if (disposing)
306 FreeHandles();
308 disposed = true;
312 #endregion
316 #endif