Accessing Windows Services

来源:互联网 发布:程序员玩什么游戏 编辑:程序博客网 时间:2024/05/01 14:15

Windows Q&A
January 22, 2005


Accessing Windows Services

How can I programmatically 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 our process ID and they query Windows for a handle to this process. This sets us up to ask more detailed information about the process:

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 GetTokenInformation with a null buffer, which tells the function we only want the size that is needed:

DWORD tokenUserLength = 0;DWORD returnLength = 0;::GetTokenInformation( tokenHandle, TokenUser, NULL, tokenUserLength, &returnLength);

Now that we have the proper size, we can allocate some memory for the buffer and request that the information be copied into it:

TOKEN_USER* pUserToken = static_cast<TOKEN_USER*>(new char[returnLength]);tokenUserLength = returnLength;::GetTokenInformation( tokenHandle, TokenUser, pUserToken, tokenUserLength, &returnLength);

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抣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, D.C.
Do you have a Windows development question? Send it to markbaker-winqa8364@mailblocks.com.

原创粉丝点击