c++windowswinapinetwork-programmingsmb

NetUseAdd returns 1326 trying to establish a connection with a remote domain


I'm trying to use CreateFile() to access a remote system. NetUseAdd() is used to establish the connection with the remote system so that CreateFile() can execute successfully.

I've passed the correct username and password on the domain, but error 1326 (The user name or password is incorrect) is returned.

After examining the network traffic, I noticed it passes the username of the executor, instead of the username of the remote system (the passed username):

Session Setup Request, NTLMSSP_AUTH, User: .\localhost

But here is the passed arguments (and the code, of course):

net::Establish(L"\\\\192.168.1.10", L"user", L"password");
bool net::Establish(const wchar_t* domain, const wchar_t* user, const wchar_t* password) {

    HANDLE remotebin;
    DWORD ret;
    char RemoteBinPath[MAX_PATH];

    // Establish the connection with the remote domain
    USER_INFO_1 userinfo;
    userinfo.usri1_name = (LPWSTR)user;
    userinfo.usri1_password = (LPWSTR)password;
    userinfo.usri1_priv = USER_PRIV_USER;
    userinfo.usri1_home_dir = NULL;
    userinfo.usri1_comment = NULL;
    userinfo.usri1_flags = UF_SCRIPT | UF_NORMAL_ACCOUNT;
    userinfo.usri1_script_path = NULL;

    ret = NetUseAdd((LPTSTR)domain, 1, (LPBYTE)&userinfo, MB_OK);
    if (ret != NERR_Success) {
#ifdef DEBUG
        printf("Erorr: NetUseAdd: %d\n", ret);
#endif
        return false;
    }

Solution

  • Pay attention that you are calling NetUseAdd() (USE) instead of NetUserAdd() (USER). By setting the LevelFlags parameter to 1, you are telling NetUseAdd() (USE) to expect a pointer to a USE_INFO_1 (USE) struct, however you are actually passing in a pointer to a USER_INFO_1 (USER) struct instead. The two structs are very different. Since you are not passing in a proper USE_INFO_1 (USE) struct, you end up with the ERROR_LOGON_FAILURE error.

    That being said, NetUseAdd() (USE) at level 1 does not take in a username, only a password. To pass in a username (and domain), you need to use level 2 (USE_INFO_2) instead. However, to use either level, you will have to also pass in a UNC share path, too.

    Try this:

    net::Establish(L"\\\\192.168.1.10", L"\\\\192.168.1.10\\share", L"domain", L"user", L"password");
    
    bool net::Establish(const wchar_t* server, const wchar_t* share, const wchar_t* domain, const wchar_t* user, const wchar_t* password) {
    
        // Establish the connection with the remote domain
        USE_INFO_2 useinfo = {};
        useinfo.ui2_remote = (LPWSTR)share;
        useinfo.ui2_password = (LPWSTR)password;
        useinfo.ui2_asg_type = USE_WILDCARD;
        useinfo.ui2_username = (LPWSTR)user;
        useinfo.ui2_domainname = (LPWSTR)domain;
    
        DWORD ret = NetUseAdd((LPTSTR)server, 2, (LPBYTE)&useinfo, NULL);
        if (ret != NERR_Success) {
    #ifdef DEBUG
            printf("Error: NetUseAdd: %d\n", ret);
    #endif
            return false;
        }
    

    On a side note:

    The (LPTSTR)server type-cast is questionable. It will work fine if you are compiling with UNICODE defined, but it will not work at all if you are not compiling with UNICODE defined. Since you are dealing with wchar_t strings exclusively, not TCHAR strings, you really should just avoid the typecast altogether since NetUseAdd() takes only wchar_t strings on Windows anyway, not TCHAR strings.

    Also, when casting your const wchar_t* pointers to LPWSTR (wchar_t*), you should be using const_cast instead of a C-style cast.

    Also, use reinterpret_cast instead of a C-style cast when passing in the USE_INFO_... pointer to `NetUseAdd().

    Try this:

    net::Establish(L"\\\\192.168.1.10", L"\\\\192.168.1.10\\share", L"domain", L"user", L"password");
    
    bool net::Establish(const wchar_t* server, const wchar_t* share, const wchar_t* domain, const wchar_t* user, const wchar_t* password) {
    
        // Establish the connection with the remote domain
        USE_INFO_2 useinfo = {};
        useinfo.ui2_remote = const_cast<LPWSTR>(share);
        useinfo.ui2_password = const_cast<LPWSTR>(password);
        useinfo.ui2_asg_type = USE_WILDCARD;
        useinfo.ui2_username = const_cast<LPWSTR>(user);
        useinfo.ui2_domainname = const_cast<LPWSTR>(domain);
    
        DWORD ret = NetUseAdd(server, 2, reinterpret_cast<LPBYTE>(&useinfo), NULL);
        if (ret != NERR_Success) {
    #ifdef DEBUG
            printf("Error: NetUseAdd: %d\n", ret);
    #endif
            return false;
        }