Search code examples
c++stringprintfntfssid

Issue in c++ with _tprintf printing question marks


I'm having some trouble with C++, don't often use this language!

I'm attempting to process ACLs in an NTFS directory in order to output a complete list of all allow and deny permissions that exist on a directory.

I've got the ACLs from the directory fine and I've got the Domain\Account name fine for most records. There are some cases however where outputting this just gives me ????????\????????.

I have identified 2 reasons for this.

1) the user account has been deleted from the machine so the SID is an orphan. I can determine this with GetLastError() = 1332.

2) it's a 'Well-known SID' ie some kind of built in SID so there is no username to map to - LookupAccountSid does not report an error at this point. I have no way (so far as I can see) of identifying these cases without mapping all the well-known SIDs into a file and doing a cross-reference (slow). What I want to do is simply output the SID instead of the ????????. the LPTSTR myTrusteeName is the string returned from LookupAccountSid() which is rendering as ????????. I don't know what its actual value is, if I knew that I could easily do an IF statement to print the SID instead.

        //this is part of a loop.
        if (IsValidSid(mySid)){
            //cout << "SID supplied is valid\n";
            //cout << GetLengthSid(mySid) << "\n";

            LPWSTR mySidName = NULL;
            ConvertSidToStringSid((PSID)mySid, &mySidName);




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

            //alter the size of these variables rather than just getting the 1st letter and some gibberish
            myTrusteeName = (LPTSTR)GlobalAlloc(GMEM_FIXED, myDwordNameLength);
            myDomainName = (LPTSTR)GlobalAlloc(GMEM_FIXED, myDwordDomLength);

            //do the lookup again this time with genuine sizes
            LookupAccountSid(
                NULL
                , (PSID)mySid
                , myTrusteeName
                , (LPDWORD)&myDwordNameLength
                , myDomainName
                , (LPDWORD)&myDwordDomLength
                , &myNameUse
                );

            wcout << GetLastError() << "\n"; //this will output "122" even when successful because of the first attempt.

            _tprintf(TEXT("%s\n"), myTrusteeName); //when there is no name this outputs ????????

            wcout << myTrusteeName << "\n"; //when there is no name this completely screws myTrusteeName so that it fails to print for the rest of the loop


            //if we only have ???? then it's wrong
            if (myTrusteeName == NULL){ /// WHAT IN HELL DO I PUT IN THIS COMPARISON TO IDENTIFY myTrusteeName VALUES THAT PRINT ????????
                wcout << "we are changing trustee because it's blank\n";
                myTrusteeName = _T("");//maybe change this to the value of mySidName
                wcout << "length of trustee is now " << _tcslen(myTrusteeName) << "\n";
            }
            wcout << "\n";



        }

Now... whilst writing this I realise that there is a function called IsWellKnownSid() facepalm

This outputs an item from the WELL_KNOWN_SID_TYPE enumeration

I should be able to use this.... I'm not sure how I can get the string representation of the well known sid type (ie "Users") like you would see in the ACL editor as yet.... If anyone has any advice on that I'd be most grateful.

I'm not done with this little project yet so I thought I'd post this anyway in case it proves useful to someone else in the future!

I'm still curious too -- if there was no IsWellKnownSid() function, how would I go about detecting a string value that refuses to print BEFORE I try to print it?

Many thanks for reading and best regards Ben


Solution

  • You should check that ConvertSidToStringSid and LookupAccountSid return TRUE. If they do, then LookupAccountSid will have written a string to myTrusteeName. If LookupAccountSid returns FALSE, then LookupAccountSid will not have changed the content of myTrusteeName, so it will be as uninitialized as GlobalAlloc returned it.