Jump to content

Proper null-character usage in AutoIt?


Recommended Posts

I'm trying to use the DllCall function to call NetJoinDomain within Netapi32.dll. While I seem to have the Types identified properly, I am getting a return error of 1326, Logon failure: unknown user name or bad password. While I have replaced the proper credentials in the the below sample, I have confirmed that the actual credentials are correct by using them manually, so the only conclusion I can come to is that the values that I am using are not being passed properly. The MSDN documentation stipulates that some of the values either need to be null-character terminated or values that aren't used need to be a null-character. Here is the best I could come up with for that:

$netapi = DllOpen('Netapi32.dll')
$rtn = DllCall($netapi,'int','NetJoinDomain','wstr','HOSTNAME','wstr','DOMAIN' & Chr('NUL'),'wstr',Chr('NUL'),'wstr','DOMAIN\username' & Chr('NUL'),'wstr','password' & Chr('NUL'),'int',0X00000001,'int',0X00000002)
DllClose($netapi)

I've tried several permutations of the above, including using 0 instead of Chr('NUL'). A zero length string, or "", does not work. Is the above the proper representation of both the usage of a null-character and/or a null-terminated string? Or am I off in my usage? Any help that could be provided would be appreciated.

By the way, I realize that I can use NETDOM.EXE to automate a process to join a computer to a domain, but I'm trying to minimize the usage of external executables within my scripts.

Here is a link to the MSDN documentation for the NetJoinDomain function:

http://msdn.microsoft.com/library/default....tjoindomain.asp

Fully automatic, comes in any sizeMakes me wonder what I did before I got synchronized...

Link to comment
Share on other sites

have you tried Chr(0)

<{POST_SNAPBACK}>

w0uter:

I tried Chr(0), but it gives me the same result. I do appreciate the recommendation, it was somthing I hadn't tried.

Fully automatic, comes in any sizeMakes me wonder what I did before I got synchronized...

Link to comment
Share on other sites

are you doing this right?

DWORD fJoinOptions

Do you want to BitOR(0X00000001,0X00000002) ?

<{POST_SNAPBACK}>

Larry:

Sorry, but it doesn't have any affect on the issue I had referenced. It may help if I get past that point, so I appreciate the response.

Fully automatic, comes in any sizeMakes me wonder what I did before I got synchronized...

Link to comment
Share on other sites

Larry:

As it turns out, the issue was one of too much usage of the id10t.dll on my part. The above code is actually fine, my problem was that I was told that the domain in question was being run from a Windows 2000 PDC but that the domain was being run as a legacy Windows NT, not an AD, domain. After trying other functions of NETAPI32.DLL and having them work just fine, I started to think that there was something other than my code that might be the problem. Much to my horror, I discovered that the PDC and the two BDCs for our domain are Windows NT 4 boxes, which most of you probably know are no longer supported by Microsoft. In the MSDN documentation for the NetJoinDomain function, it very clearly states that this function is only available if the server you applying the function against is either Windows 2000 or Windows 2003. Yesterday I created a Windows 2000 PDC in my VMWare environment and was able to join workstations to the domain without any problem. After I get it properly documented, I'll post an example in Scripts and Scraps. Sadly, until the domain controllers are upgraded, I will have to use NETDOM.EXE in my script to accomplish what I need to do.

I appreciate the example you provided and apologize if it took much of you time to do so. Aside from a difference in the string and pointer types, the code is nearly identical to what is presented as examples in the MSDN references. Would you see any value in developing an include for AU3 to set constants for the values, like $NETSETUP_JOIN_DOMAIN = 0X00000001, much as they have done for the build environment for the Platform SDK? I wouldn't mind taking that on, at least for NETAPI32.DLL, if there was any value in doing so.

i don't have a domain... but try to follow this path... (needs latest beta)

$netapi = DllOpen('Netapi32.dll')
$kernel = DllOpen('Kernel32.dll')

$Server = 'HOSTNAME'
$Domain = 'DOMAIN'
$Account = 'DOMAIN\username'
$Password = 'password'

$CP_ACP = 0
$MB_PRECOMPOSED = 0x00000001

$n = DLLCall($kernel,"int","MultiByteToWideChar",_
                    "int",$CP_ACP,_
                    "int",$MB_PRECOMPOSED,_
                    "str",$Server,_
                    "int",-1,_
                    "ptr",0,_
                    "int",0)

$lpServer = DLLStructCreate("byte[" & $n[0] & "]")

DLLCall($kernel,"int","MultiByteToWideChar",_
                    "int",$CP_ACP,_
                    "int",$MB_PRECOMPOSED,_
                    "str",$Server,_
                    "int",-1,_
                    "ptr",DllStructGetPtr($lpServer),_
                    "int",$n[0])

$n = DLLCall($kernel,"int","MultiByteToWideChar",_
                    "int",$CP_ACP,_
                    "int",$MB_PRECOMPOSED,_
                    "str",$Domain,_
                    "int",-1,_
                    "ptr",0,_
                    "int",0)

$lpDomain = DLLStructCreate("byte[" & $n[0] & "]")

DLLCall($kernel,"int","MultiByteToWideChar",_
                    "int",$CP_ACP,_
                    "int",$MB_PRECOMPOSED,_
                    "str",$Domain,_
                    "int",-1,_
                    "ptr",DllStructGetPtr($lpDomain),_
                    "int",$n[0])

$n = DLLCall($kernel,"int","MultiByteToWideChar",_
                    "int",$CP_ACP,_
                    "int",$MB_PRECOMPOSED,_
                    "str",$Account,_
                    "int",-1,_
                    "ptr",0,_
                    "int",0)

$lpAccount = DLLStructCreate("byte[" & $n[0] & "]")

DLLCall($kernel,"int","MultiByteToWideChar",_
                    "int",$CP_ACP,_
                    "int",$MB_PRECOMPOSED,_
                    "str",$Account,_
                    "int",-1,_
                    "ptr",DllStructGetPtr($lpAccount),_
                    "int",$n[0])

$n = DLLCall($kernel,"int","MultiByteToWideChar",_
                    "int",$CP_ACP,_
                    "int",$MB_PRECOMPOSED,_
                    "str",$Password,_
                    "int",-1,_
                    "ptr",0,_
                    "int",0)

$lpPassword = DLLStructCreate("byte[" & $n[0] & "]")

DLLCall($kernel,"int","MultiByteToWideChar",_
                    "int",$CP_ACP,_
                    "int",$MB_PRECOMPOSED,_
                    "str",$Password,_
                    "int",-1,_
                    "ptr",DllStructGetPtr($lpPassword),_
                    "int",$n[0])
$rtn = DllCall($netapi,'int','NetJoinDomain',_
                        'ptr',DllStructGetPtr($lpServer),_
                        'ptr',DllStructGetPtr($lpDomain),_
                        'ptr',0,_
                        'ptr',DllStructGetPtr($lpAccount),_
                        'ptr',DllStructGetPtr($lpPassword),_
                        'int',BitOR(0x00000001,0x00000002))

DLLStructDelete($lpServer)
DLLStructDelete($lpDomain)
DLLStructDelete($lpAccount)
DLLStructDelete($lpPassword)

DllClose($netapi)
DllClose($Kernel)

<{POST_SNAPBACK}>

Fully automatic, comes in any sizeMakes me wonder what I did before I got synchronized...

Link to comment
Share on other sites

SPTech

I think in these situations may help call GetLastError and get error message:

This code is from this forum ...

_GetLastErrorMessage("After DLLCall")


;===============================================
;   _GetLastErrorMessage($DisplayMsgBox="")
;   Format the last windows error as a string and return it
;   if $DisplayMsgBox <> "" Then it will display a message box w/ the error
;   Return      Window's error as a string
;===============================================
Func _GetLastErrorMessage($DisplayMsgBox="")
    Local $ret,$s
    Local $p    = DllStructCreate("char[4096]")
    Local Const $FORMAT_MESSAGE_FROM_SYSTEM     = 0x00001000

    If @error Then Return ""

    $ret    = DllCall("Kernel32.dll","int","GetLastError")

    $ret    = DllCall("kernel32.dll","int","FormatMessage",_
                        "int",$FORMAT_MESSAGE_FROM_SYSTEM,_
                        "ptr",0,_
                        "int",$ret[0],_
                        "int",0,_
                        "ptr",DllStructGetPtr($p),_
                        "int",4096,_
                        "ptr",0)
    $s  = DllStructGetData($p,1)
    DllStructDelete($p)
    If $DisplayMsgBox <> "" Then MsgBox(0,"_GetLastErrorMessage",$DisplayMsgBox & @CRLF & $s)
    return $s
EndFunc
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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...