private static extern uint SNIWriteSyncOverAsync(SNIHandle pConn, [In] SNIPacket pPacket);
private static extern uint SNIWriteAsyncWrapper(SNIHandle pConn, [In] SNIPacket pPacket);
private static extern unsafe void SNIPacketSetData(SNIPacket pPacket, [In] byte *pbBuf, uint cbBuf);
internal static extern void SNIPacketReset([In] SNIHandle pConn, IOType IOType, SNIPacket pPacket, ConsumerNumber ConsNum);
//[ResourceExposure(ResourceScope::None)] // // Notes on SecureString: Writing out security sensitive information to managed buffer should be avoid as these can be moved // around by GC. There are two set of information which falls into this category: passwords and new changed password which // are passed in as SecureString by a user. Writing out clear passwords information is delayed until this layer to ensure that // the information is written out to buffer which is pinned in this method already. This also ensures that processing a clear password // is done right before it is written out to SNI_Packet where gets encrypted properly. // TdsParserStaticMethods.EncryptPassword operation is also done here to minimize the time the clear password is held in memory. Any changes // to loose encryption algorithm is changed it should be done in both in this method as well as TdsParserStaticMethods.EncryptPassword. // Up to current release, it is also guaranteed that both password and new change password will fit into a single login packet whose size is fixed to 4096 // So, there is no splitting logic is needed. internal static void SNIPacketSetData(SNIPacket packet, Byte[] data, Int32 length, SecureString[] passwords, // pointer to the passwords which need to be written out to SNI Packet Int32[] passwordOffsets // Offset into data buffer where the password to be written out to ) { Debug.Assert(passwords == null || (passwordOffsets != null && passwords.Length == passwordOffsets.Length), "The number of passwords does not match the number of password offsets"); bool mustRelease = false; bool mustClearBuffer = false; IntPtr clearPassword = IntPtr.Zero; // provides a guaranteed finally block – without this it isn’t guaranteed – non interruptable by fatal exceptions RuntimeHelpers.PrepareConstrainedRegions(); try { unsafe { fixed(byte *pin_data = &data[0]) { } if (passwords != null) { // Process SecureString for (int i = 0; i < passwords.Length; ++i) { // SecureString is used if (passwords[i] != null) { // provides a guaranteed finally block – without this it isn’t guaranteed – non interruptable by fatal exceptions RuntimeHelpers.PrepareConstrainedRegions(); try { // ========================================================================== // Get the clear text of secure string without converting it to String type // ========================================================================== clearPassword = Marshal.SecureStringToCoTaskMemUnicode(passwords[i]); // ========================================================================================================================== // Losely encrypt the clear text - The encryption algorithm should exactly match the TdsParserStaticMethods.EncryptPassword // ========================================================================================================================== unsafe { char *pwChar = (char *)clearPassword.ToPointer(); byte *pByte = (byte *)(clearPassword.ToPointer()); int s; byte bLo; byte bHi; int passwordsLength = passwords[i].Length; for (int j = 0; j < passwordsLength; ++j) { s = (int)*pwChar; bLo = (byte)(s & 0xff); bHi = (byte)((s >> 8) & 0xff); *(pByte++) = (Byte)((((bLo & 0x0f) << 4) | (bLo >> 4)) ^ 0xa5); *(pByte++) = (Byte)((((bHi & 0x0f) << 4) | (bHi >> 4)) ^ 0xa5); ++pwChar; } // =========================================================== // Write out the losely encrypted passwords to data buffer // =========================================================== mustClearBuffer = true; Marshal.Copy(clearPassword, data, passwordOffsets[i], passwordsLength * 2); } } finally { // Make sure that we clear the security sensitive information if (clearPassword != IntPtr.Zero) { Marshal.ZeroFreeCoTaskMemUnicode(clearPassword); } } } } } packet.DangerousAddRef(ref mustRelease); Debug.Assert(mustRelease, "AddRef Failed!"); fixed(byte *pin_data = &data[0]) { SNIPacketSetData(packet, pin_data, (uint)length); } } } finally { if (mustRelease) { packet.DangerousRelease(); } // Make sure that we clear the security sensitive information // data->Initialize() is not safe to call under CER if (mustClearBuffer) { for (int i = 0; i < data.Length; ++i) { data[i] = 0; } } } }
private static uint SNIWriteSyncOverAsync(SNIHandle pConn, [In] SNIPacket pPacket) { return(s_is64bitProcess ? SNINativeManagedWrapperX64.SNIWriteSyncOverAsync(pConn, pPacket) : SNINativeManagedWrapperX86.SNIWriteSyncOverAsync(pConn, pPacket)); }