How do I properly impersonate another user in CoCreateInstanceEx using COAUTHIDENTITY?

StackOverflow https://stackoverflow.com/questions/10987142

  •  13-06-2021
  •  | 
  •  

Domanda

I am currently working on a MFC application which needs to retrieve data from a COM object running on another system. We already have this same data exchange mechanism working and fully supported when both systems are running Windows XP and the same manually set up user account (i.e. same username and password on both systems, no domain). The trouble is that I am trying to set it up such that I can access this same DCOM system from another computer which has the same user account set up, but is logged in under a corporate Domain user account.

Right now, it works if I manually run my application using Run As and specify the alternate user, but I am looking for a better solution. When I set up the COAUTHIDENTITY for the COSERVERINFO in CoCreateInstanceEx, I specify the username and password for the alternate account, and that doesn't seem to work. I've tried various things in the Domain entry - the computer name of the local computer, of the remote computer, and leaving it blank - but none seem to help.

I tried editing the DCOM permissions for the object on the server computer to allow full access to the Everyone account, but that doesn't seem to help, and I haven't been able to find any meaningful error messages about what's really wrong. It would probably help if I could get some kind of log message on the server computer to see exactly what credentials are coming across when I run it using Run As. Does anybody have any ideas? Or maybe know what the system uses for Domain when you make a DCOM connection from a non-Domain account (a few things imply that the computer name is used, but that doesn't work when I try it).

Code follows:

COAUTHINFO      AuthInfo;
COAUTHIDENTITY  AuthIdentity;
COSERVERINFO    ServerInfo;
MULTI_QI        Results;    

AuthIdentity.Domain             = (unsigned short *) w_domain;
AuthIdentity.DomainLength       = wcslen( w_domain);
AuthIdentity.Flags              = SEC_WINNT_AUTH_IDENTITY_UNICODE;
AuthIdentity.Password           = (unsigned short *) w_password;
AuthIdentity.PasswordLength     = wcslen(w_password);
AuthIdentity.User               = (unsigned short *) w_username;
AuthIdentity.UserLength         = wcslen(w_username);

AuthInfo.dwAuthnLevel           = RPC_C_AUTHN_LEVEL_CALL; 
AuthInfo.dwAuthnSvc             = RPC_C_AUTHN_WINNT; 
AuthInfo.dwAuthzSvc             = RPC_C_AUTHZ_NONE;
AuthInfo.dwCapabilities         = EOAC_NONE;
AuthInfo.dwImpersonationLevel   = RPC_C_IMP_LEVEL_IMPERSONATE;
AuthInfo.pAuthIdentityData      = &AuthIdentity;
AuthInfo.pwszServerPrincName    = NULL;

ServerInfo.dwReserved1  = 0;
ServerInfo.dwReserved2  = 0;
ServerInfo.pAuthInfo    = &AuthInfo;
ServerInfo.pwszName     = w_nodename;

Results.pIID = &_uuidof(_DS_SessionContext);
Results.pItf = NULL;
Results.hr   = 0;

hr = CoCreateInstanceEx(clsid, NULL, CLSCTX_ALL, &ServerInfo, (ULONG) 1, &Results);                             
if(FAILED(hr))
{
    m_Error.Format("(0x%x) CoCreateInstanceEx for _DS_DataFrame failed.",hr);
    m_Error2.Format("Make sure computer IP address is correct and connected.");
    CoUninitialize();
    UpdateData(false);
    UpdateWindow();
    return false;           
}

pSession = (_DS_SessionContext *)Results.pItf;

hr = pSession->raw_DS_GetVersion(&DSStatus, &version);
if(FAILED(hr))
{
    m_Error.Format("(0x%x)GetVersion",hr);
    CoUninitialize();
    UpdateData(false);
    UpdateWindow();
    return false;           
}
È stato utile?

Soluzione

Ah, I figured it out. Turns out that in DCOM, creating the instance and calling functions on it do not automatically use the same security blanket. The authentication info in the COSERVERINFO passed to CoCreateInstanceEx only applies towards creating the instance, and when I call functions on that instance later, then it fails because I am calling those functions using the credentials of the application.

To do it properly, before calling functions on the instance, I must first call (error handling omitted for clarity):

    hr = CoSetProxyBlanket(Results.pItf, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, 
    RPC_C_IMP_LEVEL_IMPERSONATE, &AuthIdentity, EOAC_NONE);

This sets the security blanket used to call the instance to the same one that was used to create it, and thus everything works.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top