Как удалить общие учетные данные c при удалении? - PullRequest
0 голосов
/ 01 апреля 2020

Я хочу удалить учетные данные после удаления.

    internal class CredentialManager
    {
        public class AutoPinner : IDisposable
        {
            GCHandle _pinnerArray;

            public AutoPinner(byte[] bytePtr)
            {
                _pinnerArray = GCHandle.Alloc(bytePtr, GCHandleType.Pinned);
            }

            public static implicit operator IntPtr(AutoPinner ap)
            {
                return ap._pinnerArray.AddrOfPinnedObject();
            }

            public void Dispose()
            {
                _pinnerArray.Free();
            }
        }

        [DllImport("Advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)]
        static extern bool CredRead(string target, CRED_TYPE type, int reservedFlag, out IntPtr CredentialPtr);

        [DllImport("Advapi32.dll", EntryPoint = "CredWriteW", CharSet = CharSet.Unicode, SetLastError = true)]
        static extern bool CredWrite([In] ref NativeCredential userCredential, [In] UInt32 flags);

        [DllImport("Advapi32.dll", EntryPoint = "CredFree", SetLastError = true)]
        static extern bool CredFree([In] IntPtr cred);

        [DllImport("Advapi32.dll", EntryPoint = "CredDeleteW", CharSet = CharSet.Unicode, SetLastError = true)]
        static extern bool CredDelete(string target, CRED_TYPE type, int flag);

        public enum CRED_TYPE : uint
        {
            GENERIC = 1,
            DOMAIN_PASSWORD = 2,
            DOMAIN_CERTIFICATE = 3,
            DOMAIN_VISIBLE_PASSWORD = 4,
            GENERIC_CERTIFICATE = 5,
            DOMAIN_EXTENDED = 6,
            MAXIMUM = 7,      // Maximum supported cred type
            MAXIMUM_EX = (MAXIMUM + 1000),  // Allow new applications to run on old OSes
        }
        public enum CRED_PERSIST : uint
        {
            SESSION = 1,
            LOCAL_MACHINE = 2,
            ENTERPRISE = 3,
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        private struct NativeCredential
        {
            public UInt32 Flags;
            public CRED_TYPE Type;
            public IntPtr TargetName;
            public IntPtr Comment;
            public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
            public UInt32 CredentialBlobSize;
            public IntPtr CredentialBlob;
            public UInt32 Persist;
            public UInt32 AttributeCount;
            public IntPtr Attributes;
            public IntPtr TargetAlias;
            public IntPtr UserName;

            /// <summary>
            /// This method derives a NativeCredential instance from a given Credential instance.
            /// </summary>
            /// <param name="cred">The managed Credential counterpart containing data to be stored.</param>
            /// <returns>A NativeCredential instance that is derived from the given Credential
            /// instance.</returns>
            internal static NativeCredential GetNativeCredential(Credential cred)
            {
                NativeCredential ncred = new NativeCredential();
                ncred.AttributeCount = 0;
                ncred.Attributes = IntPtr.Zero;
                ncred.Comment = IntPtr.Zero;
                ncred.TargetAlias = IntPtr.Zero;
                ncred.Type = (CRED_TYPE)cred.Type;
                ncred.Persist = (UInt32)cred.Persist;
                ncred.CredentialBlobSize = (UInt32)cred.CredentialBlobSize;
                ncred.TargetName = Marshal.StringToCoTaskMemUni(cred.TargetName);
                ncred.CredentialBlob = Marshal.StringToCoTaskMemUni(cred.CredentialBlob);
                ncred.UserName = Marshal.StringToCoTaskMemUni(cred.UserName);
                return ncred;
            }
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        private struct Credential
        {
            public UInt32 Flags;
            public CRED_TYPE Type;
            public string TargetName;
            public string Comment;
            public System.Runtime.InteropServices.ComTypes.FILETIME LastWritten;
            public UInt32 CredentialBlobSize;
            public string CredentialBlob;
            public CRED_PERSIST Persist;
            public UInt32 AttributeCount;
            public IntPtr Attributes;
            public string TargetAlias;
            public string UserName;
        }

        #region Critical Handle Type definition
        sealed class CriticalCredentialHandle : CriticalHandleZeroOrMinusOneIsInvalid
        {
            // Set the handle.
            internal CriticalCredentialHandle(IntPtr preexistingHandle)
            {
                SetHandle(preexistingHandle);
            }

            internal Credential GetCredential()
            {
                if (!IsInvalid)
                {
                    // Get the Credential from the mem location
                    NativeCredential ncred = (NativeCredential)Marshal.PtrToStructure(handle,
                          typeof(NativeCredential));

                    // Create a managed Credential type and fill it with data from the native counterpart.
                    Credential cred = new Credential();
                    cred.CredentialBlobSize = ncred.CredentialBlobSize;
                    cred.CredentialBlob = Marshal.PtrToStringUni(ncred.CredentialBlob,
                          (int)ncred.CredentialBlobSize / 2);
                    cred.UserName = Marshal.PtrToStringUni(ncred.UserName);
                    cred.TargetName = Marshal.PtrToStringUni(ncred.TargetName);
                    cred.TargetAlias = Marshal.PtrToStringUni(ncred.TargetAlias);
                    cred.Type = ncred.Type;
                    cred.Flags = ncred.Flags;
                    cred.Persist = (CRED_PERSIST)ncred.Persist;
                    return cred;
                }
                else
                {
                    throw new InvalidOperationException("Invalid CriticalHandle!");
                }
            }

            internal NativeCredential GetNativeCredential()
            {
                if (!IsInvalid)
                {
                    return (NativeCredential)Marshal.PtrToStructure(handle, typeof(NativeCredential));
                }
                else
                {
                    throw new InvalidOperationException("Invalid CriticalHandle!");
                }
            }

            // Perform any specific actions to release the handle in the ReleaseHandle method.
            // Often, you need to use Pinvoke to make a call into the Win32 API to release the 
            // handle. In this case, however, we can use the Marshal class to release the unmanaged memory.

            override protected bool ReleaseHandle()
            {
                // If the handle was set, free it. Return success.
                if (!IsInvalid)
                {
                    // NOTE: We should also ZERO out the memory allocated to the handle, before free'ing it
                    // so there are no traces of the sensitive data left in memory.
                    CredFree(handle);
                    // Mark the handle as invalid for future users.
                    SetHandleAsInvalid();
                    return true;
                }
                // Return false. 
                return false;
            }
        }
        #endregion

        public static bool WriteByteCred(string appName, string user, byte[] password)
        {
            bool result = false;
            using (AutoPinner ap = new AutoPinner(password))
            {
                NativeCredential ncred = new NativeCredential();
                ncred.AttributeCount = 0;
                ncred.Attributes = IntPtr.Zero;
                ncred.Comment = IntPtr.Zero;
                ncred.TargetAlias = IntPtr.Zero;
                ncred.Type = (CRED_TYPE)CRED_TYPE.GENERIC;
                ncred.Persist = (UInt32)CRED_PERSIST.LOCAL_MACHINE;
                ncred.CredentialBlobSize = (UInt32)password.Length;
                ncred.CredentialBlob = ap;
                ncred.TargetName = Marshal.StringToCoTaskMemUni(appName);
                ncred.UserName = Marshal.StringToCoTaskMemUni(user);

                // Write the info into the CredMan storage.
                bool written = CredWrite(ref ncred, 0);
                int lastError = Marshal.GetLastWin32Error();
                if (written)
                {
                    result = true;
                }
                else
                {
                    string message = string.Format("CredWrite failed with the error code {0}.", lastError);
                }
            }
            return result;
        }

        public static bool WriteCred(string appName, string user, string pasword)
        {
            // Validations.

            byte[] byteArray = Encoding.Unicode.GetBytes(pasword);
            if (byteArray.Length > 512)
                throw new ArgumentOutOfRangeException("The password has exceeded 512 bytes.");

            // Go ahead with what we have are stuff it into the CredMan structures.
            Credential cred = new Credential();
            cred.TargetName = appName;
            cred.UserName = user;
            cred.CredentialBlob = pasword;
            cred.CredentialBlobSize = (UInt32)Encoding.Unicode.GetBytes(pasword).Length;
            cred.AttributeCount = 0;
            cred.Attributes = IntPtr.Zero;
            cred.Comment = null;
            cred.TargetAlias = null;
            cred.Type = CRED_TYPE.GENERIC;
            cred.Persist = CRED_PERSIST.LOCAL_MACHINE;
            NativeCredential ncred = NativeCredential.GetNativeCredential(cred);
            // Write the info into the CredMan storage.
            bool written = CredWrite(ref ncred, 0);
            int lastError = Marshal.GetLastWin32Error();
            if (written)
            {
                return true;
            }
            else
            {
                string message = string.Format("CredWrite failed with the error code {0}.", lastError);
                //throw new Exception(message);
                //Log message in error log
                return false;
            }
        }

        public static byte[] ReadByteCred(string appName)
        {
            // Validations.
            IntPtr nCredPtr;

            // Make the API call using the P/Invoke signature
            bool read = CredRead(appName, CRED_TYPE.GENERIC, 0, out nCredPtr);
            int lastError = Marshal.GetLastWin32Error();

            byte[] result = null;
            // If the API was successful then...
            if (read)
            {
                using (CriticalCredentialHandle critCred = new CriticalCredentialHandle(nCredPtr))
                {
                    NativeCredential nativeCred = critCred.GetNativeCredential();
                    int blobSize = (int)nativeCred.CredentialBlobSize;

                    result = new byte[blobSize];
                    Marshal.Copy(nativeCred.CredentialBlob, result, 0, blobSize);
                }
            }
            else
            {
                //1168 is "element not found" -- ignore that one and return empty string:
                if (lastError != 1168)
                {
                    string message = string.Format("ReadCred failed with the error code {0}.", lastError);
                    //Log meaasage here
                    //return readPasswordText;
                }
            }
            return result;
        }

        public static string ReadCred(string appName)
        {
            // Validations.
            IntPtr nCredPtr;
            string readPasswordText = null;

            // Make the API call using the P/Invoke signature
            bool read = CredRead(appName, CRED_TYPE.GENERIC, 0, out nCredPtr);
            int lastError = Marshal.GetLastWin32Error();

            // If the API was successful then...
            if (read)
            {
                using (CriticalCredentialHandle critCred = new CriticalCredentialHandle(nCredPtr))
                {
                    Credential cred = critCred.GetCredential();
                    readPasswordText = cred.CredentialBlob;                   
                }
            }
            else
            {
                readPasswordText = string.Empty;

                //1168 is "element not found" -- ignore that one and return empty string:
                if (lastError != 1168)
                {
                    string message = string.Format("ReadCred failed with the error code {0}.", lastError);
                    //Log meaasage here
                    //return readPasswordText;
                }
            }
            return readPasswordText;
        }


        public static void DeleteCredential(string appName)
        {
            CredDelete(appName, CRED_TYPE.GENERIC, 0);
        }
    }

Я создал класс установщика.

private void SetupManager_AfterUninstall(object sender, InstallEventArgs e)
{

      try
      {
            if (CredentialManager.ReadByteCred(@"locahost/Guest") == null)
            {
                MessageBox.Show("NULL");

            }
            else
            {
                MessageBox.Show("NOT NULL");
                CredentialManager.DeleteCredential(@"locahost/Guest");
            }
      }
      catch(Exception ex)
      {
            writeException(ex, ex.StackTrace);
      }
}

Он не работает. учетные данные не удаляются в диспетчере учетных данных.
Однако, это работает в приложении c#.

Я пытаюсь запустить командный файл для удаления учетных данных в классе установщика, но это тоже не работает.

cmdkey /delete:"locahost/Guest"

Однако, если я извиняюсь за этот пакетный файл, он работает.

System.Security.Principal.WindowsIdentity.GetCurrent().Name

Результатом этого является NT AUTHORITY \ SYSTEM.
Я думаю, что это может быть связано с NT AUTHORITY \ SYSTEM, что учетные данные не удалены.

Универсальные c учетные данные добавляются из установленной программы в качестве учетной записи пользователя.
Установщик выполняется как системная учетная запись.
Установщик удаляет учетные данные в системная учетная запись, а не учетная запись пользователя.

Как удалить общие учетные данные c, добавленные в качестве учетной записи пользователя во время или после удаления?

...