Windows Q & A January 22, 2005
Accessing Windows Services
How can I Programmatical DETERMINE THE User Account of a Service?
(Part 1 of 2) Windows Services (also known as "NT Services" because they first appeared in the Windows NT operating system) are an extremely handy way to package an executable that needs to [1] run automatically at system startup, [2 ] run in the background, and [3] run under a specific user account. Although it's possible to partially simulate each of these behaviors by adding an application to the Startup folder and using the RUNAS.EXE application to run under an alternative account (except for the slight problem of the inability to specify a password on the command-line for security reasons), it's a lot more straightforward to use a service. Although the topic of Windows Services could easily run to book-length, we'll take a Closer Look At Determining The User Account in this Column.
At first glance, determining the user account of a running process (actually, by the code in that process) would seem to be one of those single API calls you make into the dark recesses of the Windows operating system. Unfortunately (and known only to Microsoft), this is one of those areas where you have to make a series of cascading calls into various functions, but also be aware of some gotchas that may not be apparent. Interestingly enough, the newer Microsoft .NET framework that provides a more modern abstraction of the Windows SDK still requires knowledge of dependencies between calls and various situations that can trip up an intrepid programmer. Basically, this is one of those areas that you code, debug, test, and put away into your toolchest.
THE FIRST Step Is To Determine Who We Are At The Process Level. Let's Look At Some Code: DWORD Processid = getCurrentProcessId ();
Handle processhandle =
OpenProcess (Process_Query_Information, False,
Processid);
We fetch out and.
Handle tokenhandle = NULL;
:: OpenProcessToken (ProcessHandle, Token_Query, & Tokenhandle);
The function OpenProcessToken is one of those massively over-designed functions scattered around the Win32 SDK-depending upon the value of the second parameter (in this case, TOKEN_QUERY), we receive a handle to a block of information that can be further queried. However First WE NEED TO Determine The Size of The Buffer That Will Receive The Information. We do this by calling gettokenformation with a null buffer, Which Tells The Function We online
DWORD tokenUserlength = 0;
DWORD RETURNLENGTH = 0;
:: GetTokenInformation (Tokenhandle, Tokenuser, Null, Tokenuserlength,
& returngength);
Now That We since:
Token_User * Pusertoken =
Static_cast
TokenUserlength = RETURNLENGTH;
:: GetTokenInformation (Tokenhandle, Tokenuser, Pusertoken,
TokenUserlength; & returngength;
OK, SO At this Point We Have a Pointer To a token_user Structure, Which Contains Information We need to call yet another function to get the actual user account for this process.
We Yun l continue in the next column with the final steps to move from this information to the actual account name and some potential gotchas. Everyone loves a cliffhanger, right? Mark M. Baker is the Chief of Research & Development at BNA Software located in Washington, DCDO you have a windows development Question? Send it to markbaker-winqa8364@mailblocks.com.