Announcement

Collapse
No announcement yet.

System Plugin and netapi32

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • System Plugin and netapi32

    I have created a small tool that provides a GUI for gathering information in order to create a user account in Windows. I figured it would be a good idea to make direct API calls and get to understand how the system plugin works ... After going over the source of the UserManager plugin as well as several MSDN pages I am having trouble getting this to work.

    In the first part of my code I am using InstallOptionsEx in order to create the GUI then I gather all the info into variables (working part, not shown here). The second part however that is handling the user creation is not working:

    code:

    ; I am using some default definitions straight out of Lmaccess.h
    !define UF_SCRIPT 0x000001
    !define UF_NORMAL_ACCOUNT 0x000200
    !define UF_DONT_EXPIRE_PASSWD 0x010000
    !define USER_PRIV_USER 0x000001

    ; First I get the computername as ComputerNamePhysicalNetBIOS:
    System::Call 'kernel32.dll::GetComputerNameExW(i 4, w .r0, *i ${NSIS_MAX_STRLEN} r1) i.r2'
    StrCpy $TargetServerName "\\$0"

    ; Then I am constructing the USER_INFO_1 structure
    StrCpy $1 "$TargetServerName"
    StrCpy $2 1
    StrCpy $R1 "$UserName"
    StrCpy $R2 "$Password"
    StrCpy $R3 ${USER_PRIV_USER}
    StrCpy $R4 "$UserDescription"
    System::Int64Op ${UF_SCRIPT} + ${UF_NORMAL_ACCOUNT}
    Pop $R5
    System::Int64Op $R5 + ${UF_DONT_EXPIRE_PASSWD}
    Pop $R5
    System::Call '*(w R1, w R2, i 0, i R3, n, w R4, i R5, n)i.s'
    Pop $R6

    ; Then I call the NetAddUser function from netapi32.dll
    System::Call 'netapi32.dll::NetUserAdd(w r1, i 1, i R6, i.r3) i.r4 ?e'

    The above gives me error 997 (ERROR_IO_PENDING) and $4 gives me error 87 (INVALID_PARAMETER)
    If I make the call like this:
    code:

    System::Call 'netapi32.dll::NetUserAdd(w r1, i 1, *i R6, i.r3) i.r4 ?e'

    then I get error 997 (ERROR_IO_PENDING) and $4 gives me error 2202 (ERROR_BAD_USERNAME)

    Note that all the variables used have been declared. Also I am using some error checking to make sure that the username and password have correct lengths.

    Any help will be much appreciated

    CF

    More info about the USER_INFO_1 structure can be found here
    The NetUserAdd function is described here
    Last edited by CancerFace; 12 April 2006, 22:05.

  • #2
    Right ...
    Although I am allocating space for the structure I am not putting any data into it, silly me. However I am still getting the same error (997 - ERROR_IO_PENDING) when I use this code:
    code:

    !define UF_SCRIPT 0x000001
    !define UF_NORMAL_ACCOUNT 0x000200
    !define UF_DONT_EXPIRE_PASSWD 0x010000
    !define USER_PRIV_USER 0x000001
    System::Call 'kernel32.dll::GetComputerNameExW(i 4, w .r0, *i ${NSIS_MAX_STRLEN} r1) i.r2'
    StrCpy $TargetServerName "\\$0"
    StrCpy $1 "$TargetServerName"
    StrCpy $2 1
    StrCpy $R1 "$UserName"
    StrCpy $R2 "$Password"
    StrCpy $R3 ${USER_PRIV_USER}
    StrCpy $R4 "$UserDescription"
    System::Int64Op ${UF_SCRIPT} + ${UF_NORMAL_ACCOUNT}
    Pop $R5
    System::Int64Op $R5 + ${UF_DONT_EXPIRE_PASSWD}
    Pop $R5
    System::Call '*(w R1, w R2, n, i R3, n, w R4, i R5, n) i.s'
    Pop $R6
    System::Call '*$R6(w R1, w R2, n, i R3, n, w R4, i R5, n)'

    System::Call 'netapi32.dll::NetUserAdd(w r1, i 1, *i R6, i.r3) i.r4 ?e'

    As for the string values in the structure, they have to be unicode and I am not sure if setting them as 'w Rx' is the way to go ...

    Any ideas?
    Thanks in advance

    CF
    Last edited by CancerFace; 13 April 2006, 14:29.

    Comment


    • #3
      $R6 already contains the pointer to your buffer. You shouldn't pass it as a pointer or you'll get a pointer to the pointer. Use just `i` instead of `*i`. On the same issue, in the fourth parameter, you should use `*i` instead of `i`.
      NSIS FAQ | NSIS Home Page | Donate $
      "I hear and I forget. I see and I remember. I do and I understand." -- Confucius

      Comment


      • #4
        Thanks for the info kichik

        Is it sufficient to pass the LPWSTR values to the structure as 'w Rx' since they should be unicode?
        code:
        StrCpy R1 "$UserName"
        ; ... and so on for R2,3,...
        !define strUSERINFO '(w, w, n, i, n, w, i, n) i'
        System::Call '*${strUSERINFO}(R1,R2,,R3,,R4,R5,).s'

        or should I create a buffer for each parameter, then feed the value in and then point to that buffer from within the structure?
        code:
        StrLen $9 "$UserName"
        IntOp $9 $9 + 1
        System::Call '*(&w$9 "$UserName")i.R1'
        ;... and so on for R2,3,...
        !define strUSERINFO '(i, i, n, i, n, i, i, n) i'
        System::Call '*${strUSERINFO}(R1,R2,,R3,,R4,R5,).s'

        Thanks in advance

        CF

        Comment


        • #5
          'w' should be good enough.
          NSIS FAQ | NSIS Home Page | Donate $
          "I hear and I forget. I see and I remember. I do and I understand." -- Confucius

          Comment


          • #6
            Hmmm ... Still error 997.
            Here is the part of the code that I am running:
            code:
            SetCompressor /SOLID lzma
            !include "MUI.nsh"
            !include "LogicLib.nsh"

            OutFile "Test.exe"
            InstallDir "$TEMP"

            Var "UserFirstName"
            Var "UserLastName"
            Var "UserDescription"
            Var "UserName"
            Var "Password"
            Var "UnlimitedPass"
            Var "TargetServerName"

            !define UF_SCRIPT 0x000001
            !define UF_NORMAL_ACCOUNT 0x000200
            !define UF_DONT_EXPIRE_PASSWD 0x010000

            !define USER_PRIV_GUEST 0x000000
            !define USER_PRIV_USER 0x000001
            !define USER_PRIV_ADMIN 0x000002

            Section -Boo
            SectionEnd

            Function .onInit
            StrCpy $UserFirstName "First Name"
            StrCpy $UserLastName "Last Name"
            StrCpy $UserDescription "Long user description"
            StrCpy $UserName "TemplateUser"
            StrCpy $Password "123tgfdds"
            StrCpy $UnlimitedPass 1
            Call GetServerName
            Call CreateNewUser
            MessageBox MB_OK|MB_ICONINFORMATION 'The Error Code from the NetAPI command was "$0" and got "$3" and "$4"'
            Quit
            FunctionEnd

            Function GetServerName
            System::Call 'kernel32.dll::GetComputerNameExW(i 4, w .r0, *i ${NSIS_MAX_STRLEN} r1) i.r2'
            ${If} $2 = 1
            StrCpy $TargetServerName "\\$0"
            ${Else}
            MessageBox MB_OK|MB_ICONSTOP 'Could not determine the computer name!$\nAborting...'
            Quit
            ${EndIf}
            System::Free $0
            FunctionEnd

            Function CreateNewUser
            StrCpy $1 "$TargetServerName"
            StrCpy $2 1
            !define strUSERINFO '(w, w, n, i, n, w, i, n) i'
            StrCpy $R1 "$UserName"
            StrCpy $R2 "$Password"
            StrCpy $R3 ${USER_PRIV_USER}
            StrCpy $R4 "$UserDescription"
            System::Int64Op ${UF_SCRIPT} + ${UF_NORMAL_ACCOUNT}
            Pop $R5
            ${If} $UnlimitedPass = 1
            System::Int64Op $R5 + ${UF_DONT_EXPIRE_PASSWD}
            Pop $R5
            ${EndIf}
            System::Call '*${strUSERINFO}(R1,R2,,R3,,R4,R5,) i.s'
            Pop $R6
            System::Call '*$R6${strUSERINFO}(R1,R2,,R3,,R4,R5,)'
            System::Call 'netapi32.dll::NetUserAdd(w r1, i 1, i R6, *i.r3) i.r4 ?e'
            Pop $0
            FunctionEnd

            ?
            CF

            Comment


            • #7
              According to MSDN, NetUserAdd doesn't set the last error. The documentation doesn't mention GetLastError. 997 means nothing. The real error is returned by the function itself and set to $4 in your script. 87, which is the real error code, is ERROR_INVALID_PARAMETER.

              The real problems is with the `n` in the structure definition. `n` is not a valid type, it's only a valid value. Replace it with `i` and it'll work.
              NSIS FAQ | NSIS Home Page | Donate $
              "I hear and I forget. I see and I remember. I do and I understand." -- Confucius

              Comment


              • #8
                It works!
                Thanks a lot kichik!
                Please add me to the (long) list of people that you made happy in this forum

                CF

                Comment


                • #9
                  Hmmm ...
                  Adding the user and changing some data works but I am stuck when I try to add the user to a group.
                  Here is the part that works:
                  code:
                  SetCompressor /SOLID lzma
                  !include "MUI.nsh"
                  !include "LogicLib.nsh"

                  OutFile "Test.exe"
                  InstallDir "$TEMP"

                  Var "UserFirstName"
                  Var "UserLastName"
                  Var "UserDescription"
                  Var "UserName"
                  Var "Password"
                  Var "UnlimitedPass"
                  Var "TargetServerName"

                  !define UF_SCRIPT 0x000001
                  !define UF_NORMAL_ACCOUNT 0x000200
                  !define UF_DONT_EXPIRE_PASSWD 0x010000
                  !define USER_PRIV_USER 0x000001
                  !define USER_TYPE_1 1
                  !define USER_INFO_23 23
                  !define USER_TYPE_1011 1011

                  !define strUSER_TYPE_1 '(w,w,i,i,i,w,i,i)i'
                  !define strUSER_TYPE_1011 '(w)i'

                  Section -Boo
                  SectionEnd

                  Function .onInit
                  StrCpy $UserFirstName "First Name"
                  StrCpy $UserLastName "Last Name"
                  StrCpy $UserDescription "Long user description"
                  StrCpy $UserName "TemplateUser"
                  StrCpy $Password "123tgfdds"
                  StrCpy $UnlimitedPass 1
                  Call GetServerName
                  Call CreateNewUser
                  Call SetUserFullName
                  Quit
                  FunctionEnd

                  Function GetServerName
                  System::Call 'kernel32.dll::GetComputerNameExW(i 4, w .r0, *i ${NSIS_MAX_STRLEN} r1) i.r2'
                  ${If} $2 = 1
                  StrCpy $TargetServerName "\\$0"
                  ${Else}
                  MessageBox MB_OK|MB_ICONSTOP 'Could not determine the computer name!$\nAborting...'
                  Quit
                  ${EndIf}
                  System::Free $0
                  FunctionEnd

                  Function CreateNewUser
                  StrCpy $1 "$TargetServerName"
                  StrCpy $2 ${USER_TYPE_1}
                  StrCpy $R1 "$UserName"
                  StrCpy $R2 "$Password"
                  StrCpy $R3 ${USER_PRIV_USER}
                  StrCpy $R4 "$UserDescription"
                  System::Int64Op ${UF_SCRIPT} + ${UF_NORMAL_ACCOUNT}
                  Pop $R5
                  ${If} $UnlimitedPass = 1
                  System::Int64Op $R5 + ${UF_DONT_EXPIRE_PASSWD}
                  Pop $R5
                  ${EndIf}
                  System::Call '*${strUSER_TYPE_1}(R1,R2,n,R3,n,R4,R5,n) i.s'
                  Pop $R6
                  System::Call '*$R6${strUSER_TYPE_1}(R1,R2,,R3,,R4,R5,)'
                  System::Call 'netapi32.dll::NetUserAdd(w r1, i r2, i R6, *i.r3) i.r4'
                  FunctionEnd

                  Function SetUserFullName
                  StrCpy $1 "$TargetServerName"
                  StrCpy $2 "$UserName"
                  StrCpy $3 ${USER_TYPE_1011}
                  StrCpy $R1 "$UserFirstName $UserLastName"
                  System::Call '*${strUSER_INFO_1011}(R1)i.s'
                  Pop $R2
                  System::Call '*$R2${strUSER_INFO_1011}(R1)'
                  System::Call 'netapi32.dll::NetUserSetInfo(w r1, w r2, i r3, i R2, *i.r4) i.r5'
                  FunctionEnd

                  I tried using the NetGroupAddUser function I get error 2220 on $4 (Group Name Cannot be found) and I suspect that this function is only for domain groups (although you would expect a fancier name like AddUserToDomainGroup or something )
                  code:
                  Function AddUserToGroup
                  StrCpy $1 "$TargetServerName"
                  StrCpy $2 "USERS"
                  StrCpy $3 "$UserName"
                  System::Call 'netapi32.dll::NetGroupAddUser(w r1, w r2, w r3)i.r4'
                  FunctionEnd

                  Then I tried to use the NetLocalGroupAddMembers function. If I understand correctly, I need to allocate a buffer that will contain the LOCALGROUP_MEMBERS_INFO_0 structure, which in turn should contain the SID structure of the user-account ... To get the SID I would have to call the NetUserGetInfo function and allocate a buffer for the User_Info_23 structure which in turn contains a pointer to the SID structure (and this should have been pre-allocated)
                  Something like this:
                  code:
                  System::Call 'netapi32.dll::NetApiBufferAllocate(&w${NSIS_MAX_STRLEN}, *i.R9)'
                  System::Call '*(&w${NSIS_MAX_STRLEN},&w${NSIS_MAX_STRLEN},\
                  &w${NSIS_MAX_STRLEN},&i${NSIS_MAX_STRLEN},&i${NSIS_MAX_STRLEN})i.R8'
                  StrCpy $1 "$TargetServerName"
                  StrCpy $2 "$UserName"
                  StrCpy $3 ${USER_INFO_23}
                  System::Call 'netapi32.dll::NetUserGetInfo(w r1, w r2, i r3, i R8)i.r4'
                  System::Call '*$R8(w.R1,w.R2,w.R3,i.R4,i.R5)'
                  System::Call '*$R9(w.R6)'
                  MessageBox MB_OK|MB_ICONINFORMATION 'Got the following Information:$\n\
                  Username: "$R1"$\nFull Name: "$R2"$\n\
                  User Comment: "$R3"$\nUser Flags: "$R4"$\n\
                  User SID: "$R5"$\nStored SID "$R6"'
                  System::Call 'netapi32.dll::NetApiBufferFree(i R9)'

                  However R1-6 are filled with gibberish after running the above code...


                  Any ideas?
                  CF

                  Comment


                  • #10
                    Your call to NetApiBufferAllocate is invalid. The ampersand prefix is only available on structures and should it be an integer anyway and not a wide string. The allocation of the USER_INFO_23 structure is redundant. NetUserGetInfo allocates it for you. For this, its last parameter must be a pointer and not just a simple integer pointing to your allocated structure.
                    code:
                    StrCpy $1 "$TargetServerName"
                    StrCpy $2 "$UserName"

                    System::Call 'netapi32::NetUserGetInfo(w r1, w r2, i 23, *i .R8) i.r4'
                    System::Call '*$R8(w.R1,w.R2,w.R3,i.R4,i.R5)'

                    System::Call 'netapi32::NetApiBufferFree(i R8)'

                    DetailPrint $R1
                    DetailPrint $R2
                    DetailPrint $R3
                    DetailPrint $R4
                    DetailPrint $R5

                    BTW, according to MSDN, USER_INFO_23 is only available on XP and above. You might want to use LOCALGROUP_MEMBERS_INFO_3 instead.
                    NSIS FAQ | NSIS Home Page | Donate $
                    "I hear and I forget. I see and I remember. I do and I understand." -- Confucius

                    Comment


                    • #11
                      Makes sense
                      However I am still a bit confused.
                      The reason I am using the USER_INFO_23 structure for the NetUserGetInfo is that this one points to an SID. The other option would be the USER_INFO_20 structure which points to an RID. In both cases your code gives me in R5 the buffer where the SID/RID is stored so I have to call
                      code:
                      System::Call '*$R5(i .R7)'
                      to get the actual SID/RID out to $R7. In the case of the RIDs, I get the 4 last digits of a user's SID, and this number is different for different users.
                      In the case of the SIDs, if I make the call as an 'i' the output is always the same for any user (1281). If I make the call as an 'l' then the output is different for different users. Which brings me to the real question (which explains in part why I was trying to allocate buffers with NetApiBufferAllocate as w) what is the format of the SID that I should expect? Does it matter, since I will feed it to the NetLocalGroupAddMembers function or should I first transform it somehow to a readable quantity?

                      Isn't LOCAL_GROUPMEMBERS_INFO_3 supposed to be available only to XP etc clients? The only reason I was not going to use it is that it contains the information in the format
                      <DomainName>\<AccountName>
                      and I assumed that it is used only in a domain and not on a single workstation ...

                      Thanks for all the help by the way, without your comments I would have spent way much more time in this, probably to no good end

                      CF

                      Comment


                      • #12
                        $R5 is a pointer to the SID, it's what you need. You don't want to dereference it. LOCALGROUP_MEMBERS_INFO_0 has only one member which is a pointer to a SID. You don't need to mess with the internals of the SID. All you need is the pointer.

                        LOCAL_GROUPMEMBERS_INFO_3 is available on NT and 2000 as well as XP. It does seem to require a domain name, so it's probably not good enough. You find another way to get the user's SID. You can get the RID using USER_INFO_20 and assemble the SID on your own with GetSidIdentifierAuthority, AllocateAndInitializeSid, GetSidSubAuthority and GetSidSubAuthorityCount. Count the sub-authorities using GetSidSubAuthorityCount, get all of them using GetSidSubAuthority, get the authority identifier using GetSidIdentifierAuthority and allocate your new SID with the those authorities and the RID using AllocateAndInitializeSid.
                        NSIS FAQ | NSIS Home Page | Donate $
                        "I hear and I forget. I see and I remember. I do and I understand." -- Confucius

                        Comment


                        • #13
                          I just saw your reply while I was going to write that I finally figured it out
                          I'll get the code shaped up a bit and I'll post it here.

                          kichik I appreciate all your help
                          Thank you very very very much
                          CF

                          Comment


                          • #14
                            After a lot of messing around with those netapi32 functions I managed to get them to work.
                            Needless to say that without kichik's comments I would probably be still trying ...

                            So here is the full story if anyone wants to use those in the future.

                            Some background:
                            I wanted to be able to create a user and specify parameters that were not used in the UserMgr plugin like making the password to not expire or prevent the user from changing it. In order to achieve this I had to use netapi32.dll and its functions (You can get all the info needed for the netapi32 functions through this MSDN page).

                            Step 0 - define constants and variables
                            Here are the constants that are used by the NetAPI functions that I am calling, along with some variables that you may or may not want to use:
                            code:

                            ;Possible user flags
                            !define UF_SCRIPT 0x000001
                            !define UF_ACCOUNTDISABLE 0x000002
                            !define UF_HOMEDIR_REQUIRED 0x000008
                            !define UF_LOCKOUT 0x000010
                            !define UF_PASSWD_NOTREQD 0x000020
                            !define UF_PASSWD_CANT_CHANGE 0x000040
                            !define UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED 0x000080
                            !define UF_TEMP_DUPLICATE_ACCOUNT 0x000100
                            !define UF_NORMAL_ACCOUNT 0x000200
                            !define UF_INTERDOMAIN_TRUST_ACCOUNT 0x000800
                            !define UF_WORKSTATION_TRUST_ACCOUNT 0x001000
                            !define UF_SERVER_TRUST_ACCOUNT 0x002000
                            !define UF_DONT_EXPIRE_PASSWD 0x010000
                            !define UF_MNS_LOGON_ACCOUNT 0x020000
                            !define UF_SMARTCARD_REQUIRED 0x040000
                            !define UF_TRUSTED_FOR_DELEGATION 0x080000
                            !define UF_NOT_DELEGATED 0x100000
                            !define UF_USE_DES_KEY_ONLY 0x200000
                            !define UF_DONT_REQUIRE_PREAUTH 0x400000
                            !define UF_PASSWORD_EXPIRED 0x800000

                            ; User Types
                            !define USER_TYPE_1 1
                            !define USER_TYPE_1011 1011

                            ; USER_INFO Types
                            !define USER_INFO_23 23

                            ; Local Group levels
                            !define LOCALGROUP_MEMBERS_INFO_0 0

                            ; User level of privilege
                            !define USER_PRIV_GUEST 0x000000
                            !define USER_PRIV_USER 0x000001
                            !define USER_PRIV_ADMIN 0x000002

                            ; Structure Definitions
                            !define strUSER_INFO_1 '(w,w,i,i,w,w,i,w)i'
                            !define strUSER_INFO_1011 '(w)i'

                            ;Variables
                            Var "TargetServerName"
                            Var "UserName"
                            Var "UserPassword"
                            Var "UserFirstName"
                            Var "UserLastName"
                            Var "UserComment"
                            Var "MakeAdmin"
                            Var "UnlimitedPass"

                            Step 1 - Get the computer name
                            This step may be redundant since you can use a null name and then the local machine will be the target system. Here is a function that will get the computer name and will place it on the $TargetServerName variable (you need to include LogicLib.nsh for this):
                            code:
                            Function GetComputerNameAPI
                            System::Call 'kernel32.dll::GetComputerNameExW(i 4, w .r0, *i ${NSIS_MAX_STRLEN} r1) i.r2'
                            ${If} $2 = 1
                            StrCpy $TargetServerName "\\$0"
                            ${Else}
                            System::Call "kernel32.dll::GetComputerNameW(t .r0, *i ${NSIS_MAX_STRLEN} r1) i.r2"
                            ${If} $2 = 1
                            StrCpy $TargetServerName "\\$0"
                            ${Else}
                            MessageBox MB_OK|MB_ICONSTOP 'Could not determine the computer name!$\nAborting...'
                            Quit
                            ${EndIf}
                            ${EndIf}
                            System::Free $0
                            FunctionEnd

                            Step 2 - Create the user
                            In order to create the user we need to call the NetUserAdd function which requires to generate at least a USER_INFO_1 structure which will hold the user's information (Note that we could use the USER_INFO_3 structure instead which contains a lot more information for the user). Here is the relevant code:
                            code:
                            Function CreateUserAPI
                            StrCpy $1 "$TargetServerName"
                            StrCpy $2 ${USER_TYPE_1}
                            StrCpy $R1 "$UserName"
                            StrCpy $R2 "$UserPassword"
                            StrCpy $R3 ${USER_PRIV_USER}
                            StrCpy $R4 "$UserComment"
                            System::Int64Op ${UF_SCRIPT} + ${UF_NORMAL_ACCOUNT}
                            Pop $R5
                            ${If} $UnlimitedPass = 1
                            System::Int64Op $R5 + ${UF_DONT_EXPIRE_PASSWD}
                            Pop $R5
                            ${EndIf}
                            System::Call '*${strUSER_INFO_1}(R1,R2,n,R3,n,R4,R5,n) i.s'
                            Pop $R6
                            System::Call '*$R6${strUSER_INFO_1}(R1,R2,n,R3,n,R4,R5,n)'
                            System::Call 'netapi32.dll::NetUserAdd(w r1, i r2, i R6, *i.r3) i.r4'
                            System::Free $R6
                            FunctionEnd

                            Note that we can add more user flags (see Step 0) by adding them incrementally to $R5

                            Step 3 - Set the user's first and last name
                            To do this I will be using the NetUserSetInfo function. There are quite a few things we can change with this function, but I will only alter the first and last name of the user (structure USER_TYPE_1011). Here is the function:
                            code:
                            Function SetUserInfoAPI
                            StrCpy $1 "$TargetServerName"
                            StrCpy $2 "$UserName"
                            StrCpy $3 ${USER_TYPE_1011}
                            StrCpy $R1 "$UserFirstName $UserLastName"
                            System::Call '*${strUSER_INFO_1011}(R1)i.s'
                            Pop $R2
                            System::Call '*$R2${strUSER_INFO_1011}(R1)'
                            System::Call 'netapi32.dll::NetUserSetInfo(w r1, w r2, i r3, i R2, *i.r4) i.r5'
                            System::Free $R2
                            FunctionEnd

                            Step 4 - Get the user's SID
                            We need this in order to use it in Step 5 (see bellow)
                            I will use the NetUserGetInfo function to get the SID of the user that was just created in Step 3. The data will be fed to a USER_INFO_23 structure. The SID will be kept at a buffer pointed to by R9 in the next function:
                            code:
                            Function GetUserInfoAPI
                            StrCpy $1 "$TargetServerName"
                            StrCpy $2 "$UserName"
                            StrCpy $3 ${USER_INFO_23}
                            System::Call 'netapi32::NetUserGetInfo(w r1, w r2, i r3, *i .R8) i.r4'
                            System::Call '*$R8(w .R1, w .R2, w .R3, i .R4, i .R9)'
                            System::Free $R8
                            FunctionEnd

                            Step 5 - Add the user to a group
                            This will be done using the NetLocalGroupAddMembers function using the SID from the previous step. I am using the $MakeAdmin variable (you have to set it to 1 in order to add the user to the admin group) to determine the group I will be adding the user to.
                            code:
                            Function AddUserToGroupAPI
                            StrCpy $1 "$TargetServerName"
                            ${If} $MakeAdmin = 1
                            StrCpy $2 "Administrators"
                            ${Else}
                            StrCpy $2 "Users"
                            ${EndIf}
                            StrCpy $3 ${LOCALGROUP_MEMBERS_INFO_0}
                            System::Int64Op 1 * 0x000001
                            Pop $4
                            System::Call 'netapi32.dll::NetLocalGroupAddMembers(w r1, w r2, i r3, *i R9, i r4) i.r6'
                            FunctionEnd

                            That's it!
                            You can call the functions from inside your code or make a continuous block of all the commands and get the user created.
                            Also you can add some error checking for each function. In general if the NetAPIs succeed they return 0 to the relevant variable.

                            I have to say this was a an excellent chance for me to dive into the system plugin and I really enjoyed the process

                            Again a big 'thank you' to kichik for the directions ...
                            CF

                            Comment


                            • #15
                              This is very handy info, would be great if you added a page in the wiki.
                              One question; is it ok to use the strings "Administrators" and "Users" on non english systems?
                              IntOp $PostCount $PostCount + 1

                              Comment

                              Working...
                              X