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 must change the password periodically to maintain security. When you change the password on a service account, update the password stored by the SCM. The following code example shows how to do both.
The code examples use IADsUser::SetPassword to set the account password. 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 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. For more information, and a code example, see 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 szServiceName, // Name of the service LPTSTR szOldPassword, // Old password 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; if(!szServerDNS || !szAccountDN || !szServiceName || !szOldPassword || !szNewPassword) { _tprintf(TEXT("Invalid parameter")); goto cleanup; } // Set the password on the account. // Use the distinguished name to bind to the account object. _tcsncpy(szAccountPath, TEXT("LDAP://"), MAX_PATH); _tcscat(szAccountPath, szAccountDN, MAX_PATH - _tcslen(szAccountPath)); 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->ChangePassword(CComBSTR(szOldPassword), CComBSTR(szNewPassword)); if (FAILED(hr)) { _tprintf(TEXT("ChangePassword failed - 0x%x\n"), dwStatus = hr); goto cleanup; } // 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, szServiceName, SERVICE_ALL_ACCESS); if (! schService) { _tprintf(TEXT("OpenService failed - %s\n"), dwStatus = GetLastError()); goto cleanup; } // Get the SCM database lock before changing the password. sclLock = LockServiceDatabase(schSCManager); if (sclLock == NULL) { _tprintf(TEXT("LockServiceDatabase failed - %d\n"), dwStatus = GetLastError()); goto cleanup; } // 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 NULL, // 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; }