//+---------------------------------------------------------------------------- // // Copyright (C) 1998, Microsoft Corporation // // File: account.cxx // // Contents: Code to read and set the passwords for services. Adopted from // the code used by the service control manager to do the same. // // Classes: // // Functions: SCMgrGetPassword // ScGetPassword // ScOpenPolicy // ScFormSecretName // MapNTStatus // // History: January 16, 1998 Milans Created // //----------------------------------------------------------------------------- #include "smtpinc.h" #include "ntrtl.h" #include "nturtl.h" #include "ntlsa.h" #include "account.h" DWORD ScGetPassword( LPSTR szServiceName, LPSTR *pszPassword); DWORD ScOpenPolicy( ACCESS_MASK DesiredAccess, LSA_HANDLE *PolicyHandle); DWORD ScFormSecretName( LPSTR szServiceName, LPWSTR *pwszSecretName); DWORD MapNTStatus( NTSTATUS ntstatus); //+---------------------------------------------------------------------------- // // Function: SCMgrGetPassword // // Synopsis: Reads the password configured for a given service. // // Arguments: [szServiceName] -- Name of service. // [cbPassword] -- Size in bytes of pszPassword buffer. // [pszPassword] -- The buffer in which to return the password. // // Returns: [ERROR_SUCCESS] -- Successfully returning password. // [ERROR_MORE_DATA] -- Password too big for passed in buffer. // [ERROR_INVALID_SREVICE_ACCOUNT] -- Unable to find password for // specified service. // [ERROR_ACCESS_DENIED] -- Priviledge violation reading password // //----------------------------------------------------------------------------- DWORD SCMgrGetPassword( LPSTR szServiceName, DWORD cbPassword, LPSTR pszPassword) { DWORD dwErr = ERROR_SUCCESS; LPSTR pszAllocatedPassword; pszAllocatedPassword = NULL; dwErr = ScGetPassword(szServiceName, &pszAllocatedPassword); if (dwErr == ERROR_SUCCESS) { if (strlen(pszAllocatedPassword) < cbPassword) strcpy(pszPassword, pszAllocatedPassword); else dwErr = ERROR_MORE_DATA; delete [] pszAllocatedPassword; } return( dwErr ); } //+---------------------------------------------------------------------------- // // Function: ScGetPassword // // Synopsis: Retrieves the configured password for a given service // // Arguments: [szServiceName] -- Name of service for which the configured // password is to be retrieved. // [pszPassword] -- On successful return, a string is allocated // using new and the password returned in it. Caller should // free using delete. // // Returns: [ERROR_SUCCESS] -- Successfully returning password. // [ERROR_INVALID_SERVICE_ACCOUNT] -- Service name not found. // [ERROR_ACCESS_DENIED] -- No access to password registry // //----------------------------------------------------------------------------- DWORD ScGetPassword( LPSTR szServiceName, LPSTR *pszPassword) { DWORD dwErr; NTSTATUS ntstatus; LSA_HANDLE PolicyHandle; LPWSTR LsaSecretName; UNICODE_STRING SecretNameString; PUNICODE_STRING NewPasswordString; // // Open a handle to the local security policy. // if (ScOpenPolicy( POLICY_CREATE_SECRET, &PolicyHandle ) != NO_ERROR) { return ERROR_INVALID_SERVICE_ACCOUNT; } // // Form the secret name under which the service password is stored // if ((dwErr = ScFormSecretName( szServiceName, &LsaSecretName )) != ERROR_SUCCESS) { (void) LsaClose(PolicyHandle); return dwErr; } RtlInitUnicodeString(&SecretNameString, LsaSecretName); ntstatus = LsaRetrievePrivateData( PolicyHandle, &SecretNameString, &NewPasswordString ); if (NT_SUCCESS(ntstatus)) { *pszPassword = new CHAR[ NewPasswordString->Length + 1 ]; if (*pszPassword != NULL) { wcstombs( *pszPassword, NewPasswordString->Buffer, NewPasswordString->Length/sizeof(WCHAR)); (*pszPassword)[NewPasswordString->Length/sizeof(WCHAR)] = 0; dwErr = ERROR_SUCCESS; } else { dwErr = E_OUTOFMEMORY; } } else { dwErr = MapNTStatus( ntstatus ); } delete [] LsaSecretName; (void) LsaClose(PolicyHandle); return dwErr; } //+---------------------------------------------------------------------------- // // Function: ScOpenPolicy // // Synopsis: Opens the local security policy by calling LsaOpenPolicy. // // Arguments: [DesiredAccess] -- Desired access to Policy. // [PolicyHandle] -- The policy handle is returned here. // // Returns: [ERROR_SUCCESS] -- Successful return. // [ERROR_ACCESS_DENIED] -- No access to lsa policy. // //----------------------------------------------------------------------------- DWORD ScOpenPolicy( ACCESS_MASK DesiredAccess, LSA_HANDLE *PolicyHandle) { NTSTATUS ntstatus; OBJECT_ATTRIBUTES ObjAttributes; // // Open a handle to the local security policy. Initialize the // objects attributes structure first. // InitializeObjectAttributes( &ObjAttributes, NULL, 0L, NULL, NULL ); ntstatus = LsaOpenPolicy( NULL, &ObjAttributes, DesiredAccess, PolicyHandle ); return( MapNTStatus( ntstatus ) ); } //+---------------------------------------------------------------------------- // // Function: ScFormSecretName // // Synopsis: Forms the secret name used to store the password for the // service. // // Arguments: [szServiceName] -- The service name for which the // corresponding secret name is required. // [pwszSecretName] -- On successful return, a newly allocated // buffer, containing the UNICODE secret name, is returned // here. Caller should free using delete. // // Returns: [ERROR_SUCCESS] -- If successful // [E_OUTOFMEMORY] -- If unable to allocate space for // pwszSecretName. // //----------------------------------------------------------------------------- #define SC_SECRET_PREFIX "_SC_" #define SC_SECRET_PREFIX_W L"_SC_" DWORD ScFormSecretName( LPSTR szServiceName, LPWSTR *pwszSecretName) { DWORD cLen, cServiceNameLen; cServiceNameLen = strlen(szServiceName); cLen = sizeof( SC_SECRET_PREFIX ) + cServiceNameLen + 1; *pwszSecretName = new WCHAR[ cLen ]; if (*pwszSecretName != NULL) { wcscpy( *pwszSecretName, SC_SECRET_PREFIX_W ); mbstowcs( &(*pwszSecretName)[sizeof(SC_SECRET_PREFIX) - 1], szServiceName, cServiceNameLen + 1); return( ERROR_SUCCESS ); } else { return( E_OUTOFMEMORY ); } } //+---------------------------------------------------------------------------- // // Function: MapNTStatus // // Synopsis: Simple function to map some registry related NT statuses to // Win32 errors. // // Arguments: [ntstatus] -- The NT Status to map // // Returns: Win32 error corresponding to ntstatus // //----------------------------------------------------------------------------- DWORD MapNTStatus( NTSTATUS ntstatus) { DWORD dwErr; switch (ntstatus) { case STATUS_SUCCESS: dwErr = ERROR_SUCCESS; break; case STATUS_ACCESS_DENIED: dwErr = ERROR_ACCESS_DENIED; break; default: dwErr = ERROR_INVALID_SERVICE_ACCOUNT; break; } return( dwErr ); }