Geoff Chappell, Software Analyst
The RtlFormatCurrentUserKeyPath function creates a path to the registry key that represents the current user.
NTSTATUS RtlFormatCurrentUserKeyPath (UNICODE_STRING *CurrentUserKeyPath);
The CurrentUserKeyPath argument is the address of a structure that is to describe the newly allocated registry path. The contents of this structure on input are immaterial.
The function returns STATUS_SUCCESS if successful, else a negative error code.
The RtlFormatCurrentUserKeyPath function is exported by name from both the kernel and NTDLL in version 3.51 and higher.
The RtlFormatCurrentUserKeyPath function is not documented. Neither is any C-language declaration known to have been published in any Windows Driver Kit (WDK) or Software Development Kit (SDK).
Or so say my notes from 2016. Yet today, 1st June 2020, I see online a page of Previous Versions Documentation titled RtlFormatCurrentUserKeyPath function. It is dated to 2018 but is surely older. Downloadable packages of Windows documentation for Visual Studio 2015 (but not as long ago as Visual Studio 2013) have a page titled Nano Server APIs whose long list of functions include this one but with a broken link. That it’s on Microsoft’s website now may be an oversight. Notably, it directs readers to a header named “ntrtl.h” which Microsoft has not published with any known in any WDK or SDK. It also has not been prepared with Microsoft’s usual care: it mis-describes the function as “Initializes the supplied buffer with a string representation of the SID for the current user”, and presents the one argument as a UNICODE_STRING, not as a pointer to one. Still, published it is, and this note now uses Microsoft’s known name for the function’s one argument.
The registry path that this function prepares is \REGISTRY\USER\sid, where sid is the current user’s SID in the conventional string form.
As far as concerns this function, the current user is that of the current thread’s effective token, i.e., of the thread token, if the thread has one, else of the process token. Failure to query this token for its user is failure for the function.
The function composes the desired path in memory that is newly allocated from the paged pool (with tag 'GrtS') or the process heap in kernel and user modes, respectively. Given that the successful ZwQueryTokenInformation does not produce an invalid SID, the function can fail only for lack of memory, returning STATUS_NO_MEMORY.
The successful function sets the Length, MaximumLength and Buffer members at CurrentUserKeyPath to describe the composed path in its newly allocated memory. The caller should feed CurrentUserKeyPath to RtlFreeUnicodeString when done.
Historically, the function explicitly opens and closes the token for the query. It tries first to open the thread token and proceeds to the token only if the error is STATUS_NO_TOKEN. Any other failure to open the thread token is failure for the function. Starting with version 6.2, the function avoids the opening and closing of either token and instead queries the pseudo-handle -6.
Even for the earlier versions, querying the thread token is an avoidable expense unless the thread is impersonating. The kernel has this status readily available as ActivImpersonationInfo in the ETHREAD, first as a BOOLEAN and then as a bit in the CrossThreadFlags, since version 4.0, and NTDLL has it as IsImpersonating in the TEB since version 5.0. This function, however, does not take advantage of either until version 5.2 in the kernel and 6.0 in NTDLL.
For completeness, it may as well be noted that even this relatively simple function suffers before version 5.0 from a resource leakage that is all too easy even for careful programmers. If the function opens the token but fails at the query, which is unlikely, then it does not close the token.