Platform SDK: Active Directory, ADSI, and Directory Services

Changing the Password on a Service's User Account

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;
 
}