Solved

Changing System Process Using ImpresonateLoggedOnUser

Posted on 2009-05-14
22
398 Views
Last Modified: 2012-05-07
First post, so be kind.

Here is the situation.  I have a service running as "SYSTEM" in the task manager.  At some point I need to check the DCOM connection to a server.  If the Client-Server have both the same user name and password, everything is find.  When either of them change the password, (passwords are not the same between the client-server) things go south with the DCOM.  Note:  This is running under Windows XP SP2 in a Workgroup.

I have created two classes that when called will check the connection to see if using the default credentials will make a valid connection.  If one cannot be made, then it request the server credentials and tried again.  If it is successful, then the entered credentials are saved within the registry.  The password is encrypted first before saving.  There is a limit on the number of tries before failure.

When this runs in a process that is created by the logged on user, it works like a champ.  But, in the SYSTEM run process the connection passes when the password on the server is different from the client.  This should fail and then request the credentials.

I have done the following:
1.  Got ID for the current user that is logged on by calling GetWindowThreadProcessId and find the Icon Tray to get a process ID logged on user process.
2.  Get the handle to this process (OpenProcess).
3.  Get the token for that process using OpenProcessToken.
4. Call ImpersonateLoggedOnUser to impersonate the logged on user inside of the process running under SYSTEM.

I make a call to GetUserName before and after the ImpersonateLoggedOnUser call.  It is SYSTEM before the Impersonation and "UserA" after.  This gives me a warm fuzzy that the impersonation took, but when I make the call to check the DCOM connections it again is fat dumb and happy when it should request the credentials.

How do I get the current SYSTEM process to actually be UserA?

If a CreateProcessAsUser and start Notepad, it says it is running as UserA, but if I call Notepad with CreateProcess it says it is running as "SYSTEM".
HANDLE hToken;

HANDLE hProc;
 

DWORD dwProcID;
 

GetWindowThreadProcessId( FindWindow( "Shell_TrayWnd", NULL ),  dwProcID );

hProc - OpenProcess( PROCESS_ALL_ACCESS, dwProcID );

OpenProcessToken( hProc, TOKEN_ALL_ACCESS, &hToken );
 

char szName[100];

unsigned long nSize = 99;
 

GetUserName( szName, &nSize );  //  Returns SYSTEM here.
 

ImpersonateLoggedOnUser( hToken );
 

nSize = 99;

GetUserName( szName, &nSize ); //  Returns UserA here.
 

//  Want to do stuff...
 

RevertToSelf();
 

nSize = 99;

GetUserName( szName, &nSize );  //  Returns SYSTEM here.
 

CloseHandle( hToken );

CloseHandle( hProc );

Open in new window

0
Comment
Question by:WrongwayF16
  • 13
  • 9
22 Comments
 
LVL 86

Assisted Solution

by:jkr
jkr earned 180 total points
ID: 24389802
What failure exactly (in terms of an error code) is it that you encounter after 'LogonUser()'?
0
 
LVL 1

Author Comment

by:WrongwayF16
ID: 24389888
There is not error code that is the problem.  The HRESULT is S_OK for the call to the proxy.  This should return S_ACCESSDENIED when run in the SYSTEM process like it does in the UserA created process.  That is why I'm trying to impersonate UserA in the SYSTEM process so it will fail.
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 180 total points
ID: 24390021
Which interface/API exactly is returning that?
0
 
LVL 1

Author Comment

by:WrongwayF16
ID: 24390041
One of our DCOM services.
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 180 total points
ID: 24390085
Is the password for 'UserA' set to what it should be?
0
 
LVL 1

Author Comment

by:WrongwayF16
ID: 24390144
An example of it would be:

ITestPtr ptrTest = //The Interface from the CreateInstanceEx call.

hResult = ptrTest->TestMethod();

I expect the hResult to be S_ACCESSDENIED instead of S_OK.

I make the same test/call in another process that is started by the user and it DOES return S_ACCESSDENIED when the passwords for the same user (client-server) different and is fine for when they are the same.  Also, the COSERVERINFO::pAuthInfo is NULL.


COSERVERINFO coServer;

ZeroMemory( &coServer, sizeof( coServer ));
 

coServer.pwszName = _bstr_t( "192.168.15.100" );  //  IP of server
 

MULTI_QI qiServer = { &IID_ITest, NULL, S_OK };
 

hResult = CoCreateInstanceEx( CLSID_Test, CLSCTX_REMOTE_SERVER, &coServer, 1, &qiServer );
 

if( SUCCEEDED( hResult )) {

    ITestPtr ptrTest;

    ptrTest.Attach( reinterpret_cast< ITest* >( qiServer.pItf ));

    

    try {

        hResult = ptrTest->TestMethod();

        

        if( SUCCEEDED( hResult )) {

            //  Good connection

        }

        else {

            // Bad Connection => Should be S_ACCESSDENIED

        }

    }

    catch( _com_error& e ) {

    }

}

else {

    _com_issue_error( hResult );

}

Open in new window

0
 
LVL 1

Author Comment

by:WrongwayF16
ID: 24390230
The user account exists on both client-server.  When the password for both are the same it is find.  I don't need to pass any credentials.  This came about when the user on the server changed his password to something else and didn't change it on the client.

We have deployed S/W and this could happen in the field.

This is why I created the classes to test and if the call to the proxy fails, then it requests the credentials for the server.  Then, these values are passed into the COAUTHINFO and COAUTHIDENTITY.

It works great when the process is listed as "UserA" in the task manager and the credentials are requested and the communication works fine.

I need to impersonate "UserA" when the process is running under the "SYSTEM" since the call which I would expect to be under the logged on user credentials now is not.  When it is under the "SYSTEM", return from the call through the proxy is returning S_OK even though the passwords are different.
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 180 total points
ID: 24390245
Well, you wrote "When either of them change the password, [...] things go south with the DCOM" - thus my question if the password for the user that you are impersonating is the correct one in that case.
0
 
LVL 1

Author Comment

by:WrongwayF16
ID: 24390318
Short answer, Yes it works like a champ.

The problem is when the test is being done under the service.  Here, when the call with the default credentials (trying to use the client's credentials) it is passing when it should fail.  The only thing that we can think of is that it is being run with the "SYSTEM" security instead of the logged on user.
0
 
LVL 1

Author Comment

by:WrongwayF16
ID: 24390745
JKR, you asked what it the failure coming back from LogonUser, we are not using that, but open process token to get the credentials of the current logged on user.  Sorry for any confusion if any.

This is the last part that we need to solve.  The test for the DCOM works in other places in our application and with the given credentials (if the password is different) makes the call to the DCOM and the proxy is not failing.  This is the last part.  We are trying test the DCOM connections  when the user starts up the system (from this service that we created) and if it fails, query for the proper credentials.  It appears that when creating the DCOM interface pointer and then making the call through the proxy is stating that it is fine, even though the passwords are different (this is where I would expect an access denied error code).  This is why it seems to be using the SYSTEM security credentials instead of the logged on user's; and hence why we are trying to impersonate the logged on user for the test.

One solution that has been tossed around is after the impersonation start a new process to make the test, but we think that is a band-aid to the problem.  At least the call to create the DCOM interface correctly uses the logged on user's credentials.  According to the MSDN from one of the other developers is that the impersonation for the current process should have the credentials of UserA instead of SYSTEM.  If this was read incorrectly, then...
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 180 total points
ID: 24391613
Soory, that was just a mistake on my side...
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 1

Author Comment

by:WrongwayF16
ID: 24391747
Hey, no problem.  I may not have made myself clear.

Any ideas?

0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 180 total points
ID: 24399880
Hm, just out of curiosity - does it work when yo uuse 'LogonUser()' instead (just for testing purpioses)?
0
 
LVL 1

Author Comment

by:WrongwayF16
ID: 24400048
This is running in a service, so I don't have the username and password.  I can get the username by calling GetUserName, but I cannot find a way to get the logged on user's password.  That seems to be encrypted somewhere and from what I have read a real pain to get too.

The DCOM test works great (this test is actully part of our solution) but when it runs under the SYSTEM as the user name it is always saying there is no problem no matter what.

0
 
LVL 1

Author Comment

by:WrongwayF16
ID: 24400069
And...

That really isn't a good thing.  Since how I am testing it right now, the client has UserA and the user name and Password as his password, while the server has user name UserA and Passw0rd as its password.  This test should be returning an E_ACCESSDENIED instead of S_OK when I try to call a method on the proxy.

0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 180 total points
ID: 24400079
Well, I thought of hard-coding one for testing purpoese ;o)
0
 
LVL 1

Author Comment

by:WrongwayF16
ID: 24400113

HANDLE hTokenImpersonate;
 

// Got the token for the current logged on user
 

if( !ImpersonateLoggedOnUser( hTokenImpersonate )) {

    //  Output some error message or log it or just ignore...

}
 

//  Does any classed created here have the impersonated users identity?
 

CClassBiteMe biteMe;  //  Does the variable biteMe (LOL I like using this...) have the

                      //  identity of the impersonated user?
 

RevertToSelf();

Open in new window

0
 
LVL 1

Author Comment

by:WrongwayF16
ID: 24400119
This fricken fracken keyboard!!!!!

The question I guess I really have is if during a running process (or thread) you impersonate another user does that current running process (or thread) take on the impersonated identity?

Thank god it is Friday!
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 180 total points
ID: 24400150
Well, it should - I wanted to check if you get any further with a token provided by 'LogonUser()'.
0
 
LVL 1

Author Comment

by:WrongwayF16
ID: 24400266
The impersonation did not take.  See code below...

I even tried to use the DuplicateToken call to set the SecurityImpersonation and it still didn't not impersonate.

L

HANDLE hLogonUser;

LogonUser( "UserA"

         , "WORKGROUP"

         , "Password"

         , LOGON32_LOGON_NEW_CREDENTIALS

         , LOGON32_PROVIDER_WINNT50

         , &hLogonUser

         );
 

ImpersonateLoggedOnUser( hLogonUser );
 

char szName[100];

unsigned long nSize = 99;

GetUserName( szName, &nSize ); //  Returns "SYSTEM"

Open in new window

0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 180 total points
ID: 24400419
Strange - the last time I did something like that from a service it worked... wicll try to see if I can find more...
0
 
LVL 1

Accepted Solution

by:
WrongwayF16 earned 0 total points
ID: 24426498
The solution that we decided to use is:

Impersonate the logged on user then create a new process with this user and do what we needed in that.

Thanks for the help folks.

0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

In days of old, returning something by value from a function in C++ was necessarily avoided because it would, invariably, involve one or even two copies of the object being created and potentially costly calls to a copy-constructor and destructor. A…
Templates For Beginners Or How To Encourage The Compiler To Work For You Introduction This tutorial is targeted at the reader who is, perhaps, familiar with the basics of C++ but would prefer a little slower introduction to the more ad…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now