I have to find out if the local machine is still joined to a domain, or if another computer has used the computer account or, if the computer account has been reset.
In other words, i need to verify the trust relationship between the local machine and the domain
NLTest /SC_VERIFY:{Domain} does the job pretty well.
Are there any API functions that i can use to detect whether the local machine has lost the trust relationship to a domain? I don't like to call external executables from my program.
What i tried so far:
NetGetJoinInformation(): It doesn't realize it.
DsBind*(): It doesn't realize it. Also tried to call it under the local system account.
Any ideas?
Okay. After a lot of digging, i finally found a solution: I_NetLogonControl2
NETLOGON_INFO_2* buffer=NULL;
LPBYTE domainName = (LPBYTE) L"eng";
int ret = I_NetLogonControl2(NULL, NETLOGON_CONTROL_TC_VERIFY, 2, (LPBYTE) &domainName, (LPBYTE*)&buffer);
wprintf( L"I_NetLogonControl2() returned %i\n", ret);
if (ret==0)
{
wprintf( L"PdcConenctionStatus: %i\n", buffer->netlog2_pdc_connection_status);
if (buffer->netlog2_pdc_connection_status==0)
wprintf(L"Trust relationship verified.\n");
else
wprintf(L"Trust relationship FAILED.\n");
wprintf( L"TcConenctionStatus: %i\n", buffer->netlog2_tc_connection_status);
wprintf( L"Flags: %i\n", buffer->netlog2_flags);
}
return 0;
So the magic thing is hidden in NETLOGON_INFO_2::netlog2_pdc_connection_status.If this value is 86 (ERROR_INVALID_PASSWORD) or 5 (ERROR_ACCESS_DENIED) the computer account has been changed (or reset).
If the computer account has been deleted, the value is 1787 (ERROR_NO_TRUST_SAM_ACCOUNT)
Hope this helps others!
Unfortunately, the MSDN documentation is not precise. When you are specifying "NETLOGON_CONTROL_TC_VERIFY", the data argument (LPBYTE) must point to (LPWSTR*)!
you can try LogonUser function to perform network login (LOGON32_LOGON_NETWORK).
If workstation has broken trust with domain, it will not be able to verify your credentials.
You will need some domain credentials which can perform network logon of course, not local.
Your other option is to use local account which has granted network service logon and try to access other domain workstation resource.You can receive access denied error or trust relation failed depends on which resource on which server.
Finally, you can still search system event log for event ID signaling trust failure.
but we don't have any well known accounts that we can use for this
You can not check for workstation account status on domain site (in AD) until you authenticate somehow, just local status.
NetLogon_Control2 is for BDC to PDC communications; does not work for my tests in Win 7
Microsoft page --
Remarks
This function can be used to request that a BDC ensure that its copy of the SAM database is brought up-to-date. It can also be used to determine if a BDC currently has a secure channel open to the PDC.
Related
A customer is running one of our programs, usually run as a service, as an application. The customer is getting the following error on CoRegisterClassObject():
The class is configured to run as a security id different from the caller.
It looks like some type of session 0 error, but why should CoRegisterClassObject() care about session 0? COM should allow both services (session 0) and apps (session > 0) and not care what registers what, shouldn't it?
Also, I don't like the fact that it's not in the list of errors returnable by CoRegisterClassObject(), as per the Microsoft doc webpage.
The error code in question is CO_E_WRONG_SERVER_IDENTITY (0x80004015).
Per this page:
COM security frequently asked questions
Q6 Why does CoRegisterClassObject return CO_E_WRONG_SERVER_IDENTITY? When launching my ATL 1.1 server service as an .exe file, I receive CO_E_WRONG_SERVER_IDENTITY from CoRegisterClassObject. (The class is configured to run as a security ID different from the caller.) This seems to occur whether I skip the CoInitializeSecurity or not. It fails running as a service or as an .exe file.
A. Many services are debugged by running them as console applications in the interactive user identity. Because the service is already registered to run in a different identity (configurable by the Services control panel applet), OLE fails the CoRegisterClassObject and RunningObjectTable::Register(ROTFLAGS_ALLOWANYCLIENT) calls by returning CO_E_WRONG_SERVER_IDENTITY to enforce security and to prevent malicious servers from spoofing the server. To debug by running in the interactive user's identity, make the following changes in the server's registry entries to prevent these failures:
• To prevent CoRegisterClassObject failure, remove the following named value:
[HKEY_CLASSES_ROOT\APPID\{0bf52b15-8cab-11cf-8572-00aa00c006cf}]
"LocalService"="HelloOleServerService"
• To prevent a IRunningObjectTable::Register(ROTFLAGS_ALLOWANYCLIENT) failure, follow these steps:
Remove the following named value:
[HKEY_CLASSES_ROOT\APPID\{0bf52b15-8cab-11cf-8572-00aa00c006cf}]
"LocalService"="HelloOleServerService"
Then add the following named value:
[HKEY_CLASSES_ROOT\APPID\{0bf52b15-8cab-11cf-8572-00aa00c006cf}]
"RunAs"="Interactive User"
You muist restore the modified registry entries after debugging.
I am assuming you would have to replace {0bf52b15-8cab-11cf-8572-00aa00c006cf} with your COM object's actual CLSID instead.
Overview
The Process
exe/dll compiled in C++ to be run
Scenario
Log in (win 7) to a standard user account (no admin)
run The Process as admin
The Process opens some app (exe) using ShellExecute
Problem
The app is opened in the scope of the admin user
Expecting
The app is opened in the scope of the standard user
Solutions
1. CreateProcessAsUser
Use CreateProcessAsUser (Assuming I managed to get hToken right that should have solved the issue).
However, I get the call failed with error code 1314 - ERROR_PRIVILEGE_NOT_HELD. Going back to the documentation tells me:
If this function fails with ERROR_PRIVILEGE_NOT_HELD (1314), use the
CreateProcessWithLogonW function instead
So I digged in and found this CreateProcessAsUser Error 1314 which wasn't very helpful.
2. ImpersonateLoggedOnUser
using ImpersonateLoggedOnUser generated the same error code: 1314 - ERROR_PRIVILEGE_NOT_HELD.
3. CreateProcessWithLogonW
CreateProcessWithLogonW requires lpPassword which naturally I don't have
The Question
How can an admin process open an application in the logged in user?
Have you tried using CreateProcessWithTokenW which is mentioned in the CreateProcessWithLogonW documentation? It seems to require a much weaker privilege than CreateProcessAsUser, one you should posses (SE_IMPERSONATE_NAME rather than SE_ASSIGNPRIMARYTOKEN_NAME).
You said you already have a token for the interactive user so I won't go into it.
(Note: Strange bugs have been reported with all of this, including CreateProcessWithTokenW. Don't give up on the first attempt. A bug and a fix for example: why is CreateProcessWithTokenW failing with ERROR_ACCESS_DENIED )
hToken is not a "right". It's a token. What the error says is that you lack a privilege.
Holding a privilege is not a fundamental right! Some privileges are given to certain users by default. Others need to be given through the Local Security Policy (in the "User Right Assignment" node in the MMC snap-in or with LsaAddAccountRights - all of which is documented in the page Assigning Privileges to an Account).
Besides that you sometimes have to enable privileges using AdjustTokenPrivileges. This is documented in the sibling page Changing Privileges in a Token.
Some APIs enable them if you hold them. Others don't and require you to do so yourself. The obvious way to go is to enable a privilege before calling and API that's documented to require it.
The MS Forum link may not have been but the error message is quite clear. MSDN says about the function:
Typically, the process that calls the CreateProcessAsUser
function must have the SE_INCREASE_QUOTA_NAME privilege
and may require the SE_ASSIGNPRIMARYTOKEN_NAME privilege
if the token is not assignable.
and the error is (from the page you linked to!):
ERROR_PRIVILEGE_NOT_HELD
1314 (0x522)
A required privilege is not held by the client.
This is actually a very tricky Task you want to accomplish. There are very strict security policies which make it very difficult.
As far as I know you can do it with psexec. It has a commandline Switch which enables user interaction but running the process as admin. I think your command should look like the following:
psexec \\target-computer -i -s [your command]
Another way to do it is using WMI. But for this you Need to Change the security Settings of the target machine (probably using GPO's). You Need to connect to the target machine using impersonation Level deletgate see here. Additionally as said before, you Need to Change the security Settings. See here
i am using c++ win32 API.
i tried to get user details using GetUserNameExA();
i have use this function into system logondialog source(GINA).
in my logfile,it gives
CN=ComputerName,CN=Computers,DC=JEGAN,DC=COM".
But it's used after logon on to system,at that time it gives user details like "CN=sanju,CN=USERS,DC=JEGAN,DC=COM" in my other solution.
i want user details only,but it gives system details at the logon time,how can i achieve user details at logontime?
note: i have already tried ADSI,LDAP functions & directoryservices cant able to use.so suggest any other system functions.
David is correct - the GINA DLL is loaded by the WinLogon.exe process. Check Task Manager and you'll see that WinLogon.exe runs as Local System. The GetUserName and GetUserNameEx functions provide information about the identity for the current thread:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724435.aspx
From a 20,000 foot view, after a user's credentials have been validated, the GINA notifies all Network Providers of the successful login. After this, it loads the user's profile and creates the user's shell (Explorer.exe) which is then displayed.
You might try using a Network Provider instead. They are fully supported up through Windows 8 and multiple NPs can be defined for the system so you won't run into the 'chaining' issues that GINAs have.
http://msdn.microsoft.com/en-us/library/windows/desktop/aa378775.aspx
The NPLogonNotify function will receive the user's cleartext name, domain and password (sometimes you'll receive a UPN as username in which case the domain is blank). You can use this information as is, perform LDAP-based lookups to AD or use LogonUser & ImpersonateLoggedOnUser before calling GetUserNameEx. Be extremely careful with this last approach since network providers run as Local system within the WinLogon.exe process. Always call RevertToSelf and CloseHandle to undo/clean up the previous calls.
The only (quite quirky) workaround for what you are trying to do is to log on some other user account on the side which has access to the domain and can thus query user details (don't remember the permissions needed in detail, though). Otherwise I'd suggest you go with Gregg's answer.
With a thread impersonated as such user you should then be able to query the information for the user that you are going to log on (how do you even know by that time?) via NetUserGetInfo() and friends. Choose the USER_INFO_* struct that best suits your needs and simply ask the domain server for the information. This should also work on earlier and later systems (the functionality, not the GINA itself).
If I call the following API from a local service running on Windows 7:
WTS_SESSION_INFO* pWSI;
DWORD nCntWSI;
WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, NULL, 1, &pWSI, &nCntWSI);
and then go through all returned WTS_SESSION_INFO structs in pWSI and check WTS_CONNECTSTATE_CLASS State members, can someone explain what is the difference between WTSActive and WTSConnected?
Connected means the user has connected and has been (or soon will be) presented with a login screen but hasn't completed it and been verified yet. He might be typing his password, for example.
If the user has locked the workstation, it's been locked by a screensaver, or he has switched to another user account, it doesn't end his session. The user remains logged in and his session would remain marked active. So being connected but not active means there are no processes running under that user's account. (The one caveat being there could be a service or other process running in a separate session under that user's credentials, but that's a different matter.)
I need to remotely install windows service on number of computers, so I use CreateService() and other service functions from winapi. I know admin password and user name for machines that I need access to. In order to gain access to remote machine I impersonate calling process with help of LogonUser like this:
//all variables are initialized correctly
int status = 0;
status = LogonUser(lpwUsername,
lpwDomain,
lpwPassword,
LOGON32_LOGON_NEW_CREDENTIALS,
LOGON32_PROVIDER_DEFAULT,
&hToken);
if (status == 0)
{
//here comes a error
}
status = ImpersonateLoggedOnUser(hToken);
if (status == 0)
{
//once again a error
}
//ok, now we are impersonated, do all service work there
So, I gain access to machine in a domain, but some of computers are out of domain. On machines that are out of domain this code doesn't work. Is there any way to access service manager on machine out of domain?
You can do it , the account needs to exist on the remote machine and you need to use the machine name for the domain name in the LogonUser call.
Rather than rolling your own, why not just use the SC built-in command?
OK, problem resolved (not really very good, but rather OK). I used WNetAddConnection() to ipc$ on remote machine.