[VB.net] Elevated Privileges / Adminrechte für bestimmte Buttons

02/17/2012 16:29 tolio#1
So ich wollte mal Fragen ob mir jemanden erklären kann das ich für bestimmte Aktionen in meinem Programm admin rechte anfordern kann. In meinem Fall brauche ich das, um wenn gewünscht, in den Autostart (via Registry) zu kommen.
Immer das programm als Admin starten will ich nicht weil das ziemlich nervt und außerdem müssen die Autostart einstellungen ja nicht oft geändert werden. Nach einem Tag googlen hab ich es lediglich geschafft dieses wunderbare admin schild auf die entsprechenden Buttons zu zaubern jedoch nicht, dass dann eine admin abfrage kommt:
[Only registered and activated users can see links. Click Here To Register...]
Ich hoffe mir kann da irgendjemand irgendwie weiterhelfen, ich nehmen auch gerne nur links oder sonst was an was weiterhelfen könnte
MfG
tolio
02/25/2012 23:44 nkkk#2
hm das geht glaube ich garnicht so einfach, was spricht denn dagegen das prog. einfach mit adminrechten auszuführen ? also einfach einstellen das das prog immer mit adminrechten ausgefügt wird.

wenn du es unbedingt so machen willst, musst du sobald er auf den knpf dückt ein anderes prog mit adminrechten starten, das dan macht was du willst, da die adminrechte immer bei prozessstart vergeben werden.
02/26/2012 11:11 tolio#3
nur die autostart funktion benötigt halt admin rechte und der rest nicht, da finde ich es blöd immer die adminrechte bestätigen zu müssen
Ich habe mittlerweile ein workaround gebastet wie du es auch beschrieben hast, hier mein code falls jemand anders irgenwann man ähnliche probleme hat;)

Code:
        Dim windir As String = Environment.GetEnvironmentVariable("WINDIR")
        Dim prog As Process = New Process
        prog.StartInfo.FileName = windir & "\system32\cmd.exe"
        prog.StartInfo.Arguments = "/c REG DELETE HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run /v " & Application.ProductName & " /f"
        prog.StartInfo.Verb = "runas"
        prog.Start()
        prog.WaitForExit()
01/09/2013 06:17 »jD«#4
I know this is an old thread but I have a piece of code that I needed once that will do just what you need!

Code:
Public Class Impersonator
	Implements IDisposable
	Private Context As WindowsImpersonationContext = Nothing

	Public Sub New(userName As String, password As String, domainName As String)
		Impersonate(userName, password, domainName)
	End Sub

	Public Sub Dispose()
		UndoImpersonation()
	End Sub

	<DllImport("advapi32.dll", SetLastError := True)> _
	Private Shared Function LogonUser(lpszUserName As String, lpszDomain As String, lpszPassword As String, dwLogonType As Integer, dwLogonProvider As Integer, ByRef phToken As IntPtr) As Integer
	End Function

	<DllImport("advapi32.dll", CharSet := CharSet.Auto, SetLastError := True)> _
	Private Shared Function DuplicateToken(hToken As IntPtr, impersonationLevel As Integer, ByRef hNewToken As IntPtr) As Integer
	End Function

	<DllImport("advapi32.dll", CharSet := CharSet.Auto, SetLastError := True)> _
	Private Shared Function RevertToSelf() As Boolean
	End Function

	<DllImport("kernel32.dll", CharSet := CharSet.Auto)> _
	Private Shared Function CloseHandle(handle As IntPtr) As Boolean
	End Function

	Private Const LOGON32_LOGON_INTERACTIVE As Integer = 2
	Private Const LOGON32_PROVIDER_DEFAULT As Integer = 0

	Private Sub Impersonate(userName As String, password As String, domain As String)
		Dim tempoaryIdentity As WindowsIdentity = Nothing
		Dim token As IntPtr = IntPtr.Zero
		Dim tokenDup As IntPtr = IntPtr.Zero

		Try
			If RevertToSelf() Then
				If LogonUser(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, token) <> 0 Then
					If DuplicateToken(token, 2, tokenDup) <> 0 Then
						tempoaryIdentity = New WindowsIdentity(tokenDup)
						impersonationContext = tempoaryIdentity.Impersonate()
					Else
						Throw New Win32Exception(Marshal.GetLastWin32Error())
					End If
				Else
					Throw New Win32Exception(Marshal.GetLastWin32Error())
				End If
			Else
				Throw New Win32Exception(Marshal.GetLastWin32Error())
			End If
		Finally
			If token <> IntPtr.Zero Then
				CloseHandle(token)
			End If
			If tokenDuplicate <> IntPtr.Zero Then
				CloseHandle(tokenDuplicate)
			End If
		End Try
	End Sub

	Private Sub UndoImpersonation()
		If Context IsNot Nothing Then
			Context.Undo()
		End If
	End Sub
End Class
You can then use it like this:
Code:
Using New Impersonator("Username", "Password", "DomainName")
    [ Code here runs as the above user ]
End Using
To obtain the Username, Password and Domain name of a certain user you can use the CredUI API of windows and call the appropriate [Only registered and activated users can see links. Click Here To Register...] or the [Only registered and activated users can see links. Click Here To Register...] functions.

Some example code I grabbed from StackOverflow follows:
Code:
''' <summary>
''' Leverages the windows UI to prompt for a password
''' </summary>
Friend NotInheritable Class Authentication
	Private Sub New()
	End Sub
	Public Structure CREDUI_INFO
		Public cbSize As Integer
		Public hwndParent As IntPtr
		Public pszMessageText As String
		Public pszCaptionText As String
		Public hbmBanner As IntPtr
	End Structure

	<DllImport("credui")> _
	Private Shared Function CredUIPromptForCredentials(ByRef creditUR As CREDUI_INFO, targetName As String, reserved1 As IntPtr, iError As Integer, userName As StringBuilder, maxUserName As Integer, _
		password As StringBuilder, maxPassword As Integer, <MarshalAs(UnmanagedType.Bool)> ByRef pfSave As Boolean, flags As CREDUI_FLAGS) As CredUIReturnCodes
	End Function

	<Flags> _
	Private Enum CREDUI_FLAGS
		INCORRECT_PASSWORD = &H1
		DO_NOT_PERSIST = &H2
		REQUEST_ADMINISTRATOR = &H4
		EXCLUDE_CERTIFICATES = &H8
		REQUIRE_CERTIFICATE = &H10
		SHOW_SAVE_CHECK_BOX = &H40
		ALWAYS_SHOW_UI = &H80
		REQUIRE_SMARTCARD = &H100
		PASSWORD_ONLY_OK = &H200
		VALIDATE_USERNAME = &H400
		COMPLETE_USERNAME = &H800
		PERSIST = &H1000
		SERVER_CREDENTIAL = &H4000
		EXPECT_CONFIRMATION = &H20000
		GENERIC_CREDENTIALS = &H40000
		USERNAME_TARGET_CREDENTIALS = &H80000
		KEEP_USERNAME = &H100000
	End Enum

	Public Enum CredUIReturnCodes
		NO_ERROR = 0
		ERROR_CANCELLED = 1223
		ERROR_NO_SUCH_LOGON_SESSION = 1312
		ERROR_NOT_FOUND = 1168
		ERROR_INVALID_ACCOUNT_NAME = 1315
		ERROR_INSUFFICIENT_BUFFER = 122
		ERROR_INVALID_PARAMETER = 87
		ERROR_INVALID_FLAGS = 1004
	End Enum

	''' <summary>
	''' Prompts for password.
	''' </summary>
	''' <param name="user">The user.</param>
	''' <param name="password">The password.</param>
	''' <returns>True if no errors.</returns>
	Friend Shared Function PromptForPassword(user As String, password As String) As Boolean
		' Setup the flags and variables
		Dim userPassword As New StringBuilder(), userID As New StringBuilder()
		Dim credUI As New CREDUI_INFO()
		credUI.cbSize = Marshal.SizeOf(credUI)
		Dim save As Boolean = False
		Dim flags As CREDUI_FLAGS = CREDUI_FLAGS.ALWAYS_SHOW_UI Or CREDUI_FLAGS.GENERIC_CREDENTIALS

		' Prompt the user
		Dim returnCode As CredUIReturnCodes = CredUIPromptForCredentials(credUI, Application.ProductName, IntPtr.Zero, 0, userID, 100, _
			userPassword, 100, save, flags)

		user = userID.ToString()
		password = userPassword.ToString()

		Return (returnCode = CredUIReturnCodes.NO_ERROR)
	End Function
End Class
Hope its what you need! -jD