Today I was able to write a simple C++ program that granted a user the "Log on as a service" privilege. Part of this involved converting between a LPCWSTR
and an LSA_UNICODE_STRING
. The code to do that is here:
LSA_UNICODE_STRING StringToLsaUnicodeString(LPCWSTR string) {
LSA_UNICODE_STRING lsaString;
DWORD dwLen = 0;
dwLen = wcslen(string);
lsaString.Buffer = (LPWSTR) string;
lsaString.Length = (USHORT)((dwLen) * sizeof(WCHAR));
lsaString.MaximumLength = (USHORT)((dwLen + 1) * sizeof(WCHAR));
return lsaString;
}
When I had some small errors in this function, my call to LsaLookupNames2()
failed with a code 87(hex 0x57) "The parameter is incorrect." I am trying to make this call in a C++ app that uses std::wstring
and it is failing. My current function there is as follows:
#if defined(_UNICODE)
LSA_UNICODE_STRING toLsaUnicodeString (std::wstring str) {
LSA_UNICODE_STRING lsaWStr;
DWORD len = 0;
LPWSTR cstr = (LPWSTR)str.c_str();
len = wcslen(cstr);
lsaWStr.Buffer = cstr;
lsaWStr.Length = (USHORT)((len) * sizeof(WCHAR));
lsaWStr.MaximumLength = (USHORT)((len + 1) * sizeof(WCHAR));
return lsaWStr;
}
#endif
What am I doing wrong?
You're likely encountering a lifetime issue with the
wchar_t*
returned fromstr.c_str()
.str.c_str()
will return a pointer to an underlying string whose lifetime is governed bystr
. Sincestr
is passed by-value, it will be destroyed at the end of thetoLsaUnicodeString
function, resulting in the returnedLSA_UNICODE_STRING
pointing at memory that has been deallocated. In order to avoid this, you'll need to make a copy of the underlying string in thetoLsaUnicodeString
function, and associate the copy with the returnedLSA_UNICODE_STRING
, something like:Since the memory is now allocated on the heap, you are responsible for making sure it is deallocated. You can use a function like the following to take care of this.
Even better would be to use RAII to manage the memory and guarantee that it is released when the variable is no longer in use. See Mr_C64's answer for details on this approach.