Jump to content

Setting ACLs using alternate credentials


Surf243
 Share

Recommended Posts

Hello,

I've been using this UDF to set ACL permissions to some network folders, everything works great (no issues). However, I want to apply these permissions using elevated domain credentials supplied by the user and not the user that's currently running the script. As a temporary solution, I've implemented a RunAs function, but that's not the solution I'm looking for. I'm not fluent with using Dlls, but I have been trying out different methods.

My RunAs Function:

Func _RunAs($sUser, $sPass)
    If @Compiled Then
        RunAs($sUser, @LogonDomain, $sPass, 4, FileGetShortName(@ScriptFullPath), "", @SW_MAXIMIZE)
    Else
        RunAs($sUser, @LogonDomain, $sPass, 4, FileGetShortName(@AutoItExe) & " " & FileGetShortName(@ScriptFullPath), "", @SW_MAXIMIZE)
    EndIf
EndFunc   ;==>_RunAs

I tried LogonUser and I know that I can take that token to ImpersonateLoggedOnUser, but I'm not sure how to implement that or if that's even the right method. I also need to RevertToSelf once completed.

Func _LogonUser($sUsername, $sPassword, $sServer = @LogonDomain) ; Returns True if user exists
    Local $stToken

    $stToken = DllStructCreate("int")
    Local $aRet = DllCall("advapi32.dll", "int", "LogonUser", _
            "str", $sUsername, "str", $sServer, "str", $sPassword, "dword", 3, "dword", 0, "ptr", DllStructGetPtr($stToken))
    ;$hToken = DllStructGetData($stToken, 1)
    If Not @error And $aRet[0] <> 0 Then
        Return True
    EndIf
    Return False
EndFunc   ;==>_LogonUser

Any assistance, suggestions or idea's would be helpful.

Thanks!

Link to comment
Share on other sites

 RunAs or RunAsWait does not give you full admin rights (Admin Token), even if the user has admin right on the PC.  One workaround you have is to use re-execution.  Have a look at this thread for an example.  You could also create another script that uses #RequireAdmin, but I prefer re-execution.  

Here is a more customized script for what I think you are trying to do,  it uses RunAsWait and ShellExecuteWait.  

Global $sAdminUser = "USERNAME"
Global $sAdminPassword = "PASSWORD"
Global $sDomain = @LogonDomain
Global $iLogOnFlag = 0
Global $sParameters = ""

;Run as the Admin account.
If @UserName <> $sAdminUser And Not IsAdmin() Then
    $sParameters = ""
    If Not @Compiled Then
        $sParameters = ' "' & @ScriptFullPath & '"'
    EndIf
    
    ;Use RunAsWait to run as AdminUser, to continue the script as the user that started it, and to wait for the Admin part to Finish.
    RunAsWait($sAdminUser, $sDomain, $sAdminPassword, $iLogOnFlag, @AutoItExe & $sParameters)
    If @error Then Exit MsgBox(16 + 262144, "ERROR!", "Unable to run under administrator account.")
EndIf

;Request the Admin Token for the Admin account in Windows Vista and Higher.
If @UserName = $sAdminUser And Not IsAdmin() And Not StringRegExp(@OSVersion, "_(XP|200(0|3))") Then
    $sParameters = ""
    If Not @Compiled Then
        $sParameters = '"' & @ScriptFullPath & '"'
    EndIf
    
    ;Use ShellExecuteWait to run as AdminUser with Admin Token, to wait for the Admin part of the script to finish, and then to exit.
    ShellExecuteWait(@AutoItExe, $sParameters, "", "runas")
    If @error Then Exit MsgBox(16 + 262144, "ERROR!", "Unable to elevate to Admin due to UAC.")
    Exit
EndIf

MsgBox(16, @UserName, "Is " & (IsAdmin() ? "" : "Not " ) & "Admin") ;Example

;Admin part of script.
If IsAdmin() Then 
    MsgBox (0, "Admin Run Test", "Run Admin part of script and then exit to run as user who started the script.") ;Example
    
    
    ;Exit to finish Admin part of script.
    Exit
EndIf

;Put rest of the non Admin part of script here.

If you have any questions, please let me know.  

 

Adam

Link to comment
Share on other sites

Hey @AdamUL, I really appreciate your response and customized script. I read through your posts and it helped me a lot to understand the process. However, with my script I'm already using #RequireAdmin and my goal was to not to use re-execution (if possible). Luckily, after days of researching I was able to find the solution I was looking for.

I copied and modified an already existing function from this post: 

 

Hopefully, I've done this correctly but please correct me if needed.

Func _LogonOnUser($sUsername, $sPassword, $sServer = @LogonDomain)
    Local $aRet
    Local $stToken
    Local $phToken
    Local $nError = -1

    $stToken = DllStructCreate("int")
    $aRet = DllCall("advapi32.dll", "int", "LogonUser", _
            "str", $sUsername, _
            "str", $sServer, _
            "str", $sPassword, _
            "dword", 8, _ ; LOGON32_LOGON_NETWORK_CLEARTEXT
            "dword", 0, _
            "ptr", DllStructGetPtr($stToken))
            
    $phToken = DllStructGetData($stToken, 1)
    
    If Not @error And $aRet[0] <> 0 Then
        ;Return True ; Return True if user exists
        $aRet = DllCall("advapi32.dll", "int", "ImpersonateLoggedOnUser", "ptr", $phToken)
        If Not @error And $aRet[0] <> 0 Then
            ConsoleWrite("Impersonated User = " & @UserName & @CRLF)
            ; Do Impersonation Stuff Here
            _InitiatePermissionResources() ; Requires Permissions UDF
        Else
            $aet = DllCall("kernel32.dll", "int", "GetLastError")
            If Not @error Then $nError = $aRet[0]
        EndIf
        DllCall("kernel32.dll", "int", "CloseHandle", "ptr", $phToken)
    Else
        $aRet = DllCall("kernel32.dll", "int", "GetLastError")
        If Not @error Then $nError = $aRet[0]
    EndIf
    If $nError > -1 Then
        SetError($nError)
        Return 0
    EndIf
    Return 1
EndFunc   ;==>_LogOnUser

Once the process is completed I then _LogOffUser and RevertToSelf

Func _LogOffUser()
    _ClosePermissionResources() ; Requires Permissions UDF
    DllCall("advapi32.dll", "int", "RevertToSelf")
    ConsoleWrite("RevertToSelf User = " & @UserName & @CRLF)
EndFunc

Permissions Applied Successfully!

If I don't use the _LogonOnUser function it errors out and I lose access to my network folders and it disappears! Luckily, I am able to recover it when I use this function.

Link to comment
Share on other sites

@Surf243  Your welcome.  A very nice find, and nicely created functions.  I couldn't tell if the user that you were trying to run under was an admin user or not.  My script is used mostly with non admin users.  I'm glad your functions work for what you wanted to do.  I have added them to my script library.  The only issue, and it's really not an issue, is some of the DLL calls could be replaced by _WinAPI_* functions, such as _WinAPI_GetLastError and _WinAPI_CloseHandle.  

I'm also working with the Permissions UDF.  I have found a few issues with it, and have added comments to that thread.  

 

Adam

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...