Hello,

I thread hijacked earlier today... probably shouldn't have, sorry if that annoyed anyone.

Anyway I have an issue using LookupAccountSid in a visual studio 2013 project running on Windows 7 Pro x64.

First of all, it works perfectly in debug, but doesn't work when built for release. What I think is happening is somewhere along the lines a variable is being assigned a NULL reference so when it is accessed an ACCESS_VIOLATION (c00....05) occurs in ntdll.dll.

When running in debug mode, the debug runtime uses a different memory location for NULL pointers so even though a NULL pointer is being referenced, I don't get the general protection fault.

Now the fact that this NULL pointer is being accessed does not seem to have any bearing on the actual functionality of the application as running in debug not only compiles and runs but actually outputs exactly the right data.

SO

Here's where I'm at. I think I need to either prevent the program from attempting to access a NULL pointer OR (this may well be completely retarded) somehow set a default memory location for NULL pointers that will not cause a GPF?! (a la run the application in a closer environment to 'debug mode') as mentioned, this is possibly a completely stupid idea...

What I've determined so far...

The exception occurs when calling LookupAccountSidW().

This is part of the Win32 API and takes a pointer to a SID (PSID) then from this looks up a string value for the domain name and user name. There are some caveats to running this function, firstly you need to tell it how long (in characters) the user and domain name are. Naturally you don't know this. So you create DWORDs of 0 and send in a pointer to it and give it a NULL for the output string (LPWSTR). The function on the first call will update your DWORDs to the actual values you need.

Then you reallocate the LPWSTRs so that they are 'big enough' to hold the strings that are being generated.

You finally make a second call to the LookupAccountSidW() function with the resized LPWSTRs and the updated DWORDs.

Our LPWSTRs are now populated with the domain name and username! (yippee)

Now for the issue... The first time we make this attempt this process; it works perfectly end-to-end and we get our user name and domain name.

The second time we attempt this process it fails immediately with an ACCESS_VIOLATION.

So my thought was, I've got some parameter that is not being re-set on the second run. So I went so far as to put the entire lookup into a function that takes a string SID - so even the conversion to a PSID is done within the function - NO VARIABLES used in the lookup come from outside the function yet the issue remains!

here's my function:

bool GetStringFromSid(wstring* myOutString){
    LPWSTR myTrusteeName = _T(""), myDomainName = _T("");
    DWORD myDwordNameLength = 0, myDwordDomLength = 0;
    SID_NAME_USE myNameUse = SidTypeUnknown;
    PSID getSid = new PSID;
    wstring stringSid = *myOutString;
    ConvertStringSidToSidW(&stringSid[0], &getSid);


    //Make an initial lookup to find out how big the names are
    LookupAccountSidW(
        NULL
        , getSid
        , NULL
        , (LPDWORD)&myDwordNameLength
        , NULL
        , (LPDWORD)&myDwordDomLength
        , &myNameUse
        ); //at this point error 122 is thrown as the length of myTrusteeName is too short.

    wcout << "got this far" << endl;
    //alter the size of these variables rather than just getting the 1st letter and some gibberish
    myTrusteeName = (LPWSTR)GlobalAlloc(GMEM_FIXED, myDwordNameLength);
    myDomainName = (LPWSTR)GlobalAlloc(GMEM_FIXED, myDwordDomLength);

    //do the lookup again this time with genuine sizes
    BOOL it_dun_gud_ya = LookupAccountSidW(
        NULL
        , getSid
        , myTrusteeName
        , (LPDWORD)&myDwordNameLength
        , myDomainName
        , (LPDWORD)&myDwordDomLength
        , &myNameUse
        );

    //find out if we got a valid SID
    if (it_dun_gud_ya){


        //convert from LPW to string using wstringstream
        wstringstream LPWConverter;

        if ((_tcslen(myTrusteeName) == 0) && (_tcslen(myDomainName) > 0)){
            LPWConverter << myDomainName;
        }
        else if ((_tcslen(myTrusteeName) > 0) && (_tcslen(myDomainName) == 0)){
            LPWConverter << myTrusteeName;
        }
        else if ((_tcslen(myTrusteeName) > 0) && (_tcslen(myDomainName) > 0)){
            LPWConverter << myDomainName << "\\" << myTrusteeName;
        }

        *myOutString = LPWConverter.str();

        return true;
    }
    else {
        return false;
    }


}

You'll notice a wcout of 'got this far' I put this in to prove that error was occuring in the lookup that is done to get the string lengths.

I cannot understand why my function would work the first time I call it but not on the second? I'm even calling it with the same string value both times!

Have I stumbled accross a Microsoft bug or am I being a retard? I'm guessing that when you list the NTFS permissions using windows explorer, this API is being called by explorer in the background so I know that ntdll.dll works in some environments??!?

I am now completely out of ideas and I believe I may have exhausted the google on this one too!

Really hoping someone will be able to help me...

Thanks for reading thus far :)
Ben

AFAIK, the first call to LookupAccountSidW will return the buffer sizes needed in TCHARS. So you will need to allocate bufsize * sizeof(wchar_t)
You also need to free the memory.

Thanks, I thought that is effectively what lines 23 and 24 are doing? Or are you refering to the variables that I currently have as DWORDs and am passing as references?

Because you are calling LookupAccountSidW(...), myDwordNameLength and myDwordDomLength will contain the buffer size needed in wide chars. Thus on lines 23 and 24 you are only allocating half the required size for each buffer.
Change those lines to:

myTrusteeName = (LPWSTR)GlobalAlloc(GMEM_FIXED, myDwordNameLength * sizeof(wchar_t));
myDomainName = (LPWSTR)GlobalAlloc(GMEM_FIXED, myDwordDomLength * sizeof(wchar_t));
commented: Saved my ass! +1

...

good lord I could kiss you right now and I don't even care if you're a dude.

I hadn't previously been using LookupAccountSidW() but the issue was still there before because the compiler was defaulting to wide chars anyway.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.