Platform SDK: Active Directory, ADSI, and Directory Services |
For a service instance that logs on with a user account (rather than the LocalSystem account), the Service Control Manager (SCM) on the host computer stores the account password, which it uses to log on the service when the service starts up. As with any user account, you need to change the password periodically to maintain security. So when you change the password on a service's account, you also need to update the password stored by the SCM. The following code sample shows how to do both.
The samples uses IADsUser::SetPassword to set the password on the account. This method uses the distinguished name of the account. Then the sample opens a handle to the installed service on the specified host computer, and uses the ChangeServiceConfig function to update the password cached by the SCM. This function uses the SAM name (domain\username) of the account.
Note that this code must be executed by a domain administrator.
For a replicable service in which each replica uses a different logon account, you could update the passwords for all of the replicas by enumerating the service instances as shown in the sample code at Enumerating the Replicas of a Service.
DWORD UpdateAccountPassword( LPTSTR szServerDNS, // DNS name of host computer LPTSTR szAccountDN, // Distinguished name of service's logon account LPTSTR szAccountSAM, // SAM name of service's logon account LPTSTR szNewPassword // New password ) { SC_HANDLE schService = NULL; SC_HANDLE schSCManager = NULL; DWORD dwLen = MAX_PATH; TCHAR szAccountPath[MAX_PATH]; IADsUser *pUser = NULL; HRESULT hr; DWORD dwStatus=0; SC_LOCK sclLock = NULL; // First, set the password on the account. // Use the distinguished name to bind to the account object. _tcscpy(szAccountPath, TEXT("LDAP://") ); _tcscat(szAccountPath, szAccountDN); hr = ADsGetObject(szAccountPath, IID_IADsUser, (void**)&pUser); if (FAILED(hr)) { _tprintf(TEXT("Get IADsUser failed - 0x%x\n"), dwStatus = hr); goto cleanup; } // Set the password on the account. hr = pUser->SetPassword(szNewPassword); if (FAILED(hr)) { _tprintf(TEXT("SetPassword failed - 0x%x\n"), dwStatus = hr); goto cleanup; } // Now update the account and password in the SCM database. // Open the Service Control Manager on the specified computer. schSCManager = OpenSCManager( szServerDNS, // DNS name of host computer NULL, // database (NULL == default) SC_MANAGER_ALL_ACCESS // access required ); if (! schSCManager) { _tprintf(TEXT("OpenSCManager failed - %d\n"), dwStatus = GetLastError()); goto cleanup; } // Open a handle to the service instance. schService = OpenService(schSCManager, TEXT(SZSERVICENAME), SERVICE_ALL_ACCESS); if (! schService) { _tprintf(TEXT("OpenService failed - %s\n"), dwStatus = GetLastError()); goto cleanup; } // Need to acquire the SCM database lock before changing the password. sclLock = LockServiceDatabase(schSCManager); if (sclLock == NULL) { _tprintf(TEXT("LockServiceDatabase failed - %d\n"), dwStatus = GetLastError()); goto cleanup; } // Now set the account and password that the service uses at startup. if (! ChangeServiceConfig( schService, // Handle of service SERVICE_NO_CHANGE, // Service type: no change SERVICE_NO_CHANGE, // Change service start type SERVICE_NO_CHANGE, // Error control: no change NULL, // Binary path: no change NULL, // Load order group: no change NULL, // Tag ID: no change NULL, // Dependencies: no change szAccountSAM, // Account name: no change szNewPassword, // New password NULL) ) { // Display name: no change _tprintf(TEXT("ChangeServiceConfig failed - %s\n"), dwStatus = GetLastError()); goto cleanup; } _tprintf(TEXT("Password changed for service instance on: %s\n"), szServerDNS); cleanup: if (sclLock) UnlockServiceDatabase(sclLock); if (schService) CloseServiceHandle(schService); if (schSCManager) CloseServiceHandle(schSCManager); if (pUser) pUser->Release(); return dwStatus; }