#ifndef UNICODE
#define UNICODE
#endif
#include "stdafx.h"
#include <windows.h>
#include <lm.h>
#include <ntsecapi.h>
#include <isc/ntgroups.h>
#include <isc/result.h>
#include "AccountInfo.h"
#define MAX_NAME_LENGTH 256
NTSTATUS
OpenPolicy(
LPWSTR ServerName,
DWORD DesiredAccess,
PLSA_HANDLE PolicyHandle
);
BOOL
GetAccountSid(
LPTSTR SystemName,
LPTSTR AccountName,
PSID *Sid
);
NTSTATUS
SetPrivilegeOnAccount(
LSA_HANDLE PolicyHandle,
PSID AccountSid,
LPWSTR PrivilegeName,
BOOL bEnable
);
NTSTATUS
GetPrivilegesOnAccount(
LSA_HANDLE PolicyHandle,
PSID AccountSid,
wchar_t **PrivList,
unsigned int *PrivCount
);
NTSTATUS
AddPrivilegeToAcccount(
LPTSTR AccountName,
LPWSTR PrivilegeName
);
void
InitLsaString(
PLSA_UNICODE_STRING LsaString,
LPWSTR String
);
void
DisplayNtStatus(
LPSTR szAPI,
NTSTATUS Status
);
void
DisplayWinError(
LPSTR szAPI,
DWORD WinError
);
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif
int
GetAccountPrivileges(char *name, wchar_t **PrivList, unsigned int *PrivCount,
char **Accounts, unsigned int *totalAccounts,
int maxAccounts)
{
LSA_HANDLE PolicyHandle;
TCHAR AccountName[256];
PSID pSid;
unsigned int i;
NTSTATUS Status;
isc_result_t istatus;
int iRetVal = RTN_ERROR;
if ((Status = OpenPolicy(NULL,
POLICY_LOOKUP_NAMES,
&PolicyHandle)) != STATUS_SUCCESS)
return (RTN_ERROR);
wsprintf(AccountName, TEXT("%hS"), name);
if (!GetAccountSid(NULL, AccountName, &pSid))
return (RTN_NOACCOUNT);
istatus = isc_ntsecurity_getaccountgroups(name, Accounts, maxAccounts,
totalAccounts);
if (istatus == ISC_R_NOMEMORY)
return (RTN_NOMEMORY);
else if (istatus != ISC_R_SUCCESS)
return (RTN_ERROR);
Accounts[*totalAccounts] = name;
(*totalAccounts)++;
for (i = 0; i < *totalAccounts; i++) {
wsprintf(AccountName, TEXT("%hS"), Accounts[i]);
if (!GetAccountSid(NULL, AccountName, &pSid))
continue;
if ((Status = GetPrivilegesOnAccount(PolicyHandle, pSid,
PrivList, PrivCount)) == STATUS_SUCCESS)
{
iRetVal=RTN_OK;
if (pSid != NULL)
HeapFree(GetProcessHeap(), 0, pSid);
} else {
if (pSid != NULL)
HeapFree(GetProcessHeap(), 0, pSid);
continue;
}
}
LsaClose(PolicyHandle);
(*totalAccounts)--;
return iRetVal;
}
BOOL
CreateServiceAccount(char *name, char *password) {
NTSTATUS retstat;
USER_INFO_1 ui;
DWORD dwLevel = 1;
DWORD dwError = 0;
NET_API_STATUS nStatus;
size_t namelen = strlen(name);
size_t passwdlen = strlen(password);
wchar_t AccountName[MAX_NAME_LENGTH];
wchar_t AccountPassword[MAX_NAME_LENGTH];
mbstowcs(AccountName, name, namelen + 1);
mbstowcs(AccountPassword, password, passwdlen + 1);
ui.usri1_name = (LPWSTR) &AccountName;
ui.usri1_password = (LPWSTR) &AccountPassword;
ui.usri1_priv = USER_PRIV_USER;
ui.usri1_home_dir = NULL;
ui.usri1_comment = L"ISC BIND Service Account";
ui.usri1_flags = UF_PASSWD_CANT_CHANGE | UF_DONT_EXPIRE_PASSWD |
UF_SCRIPT;
ui.usri1_script_path = NULL;
nStatus = NetUserAdd(NULL, dwLevel, (LPBYTE)&ui, &dwError);
if (nStatus != NERR_Success)
return (FALSE);
retstat = AddPrivilegeToAcccount(name, SE_SERVICE_LOGON_PRIV);
return (TRUE);
}
NTSTATUS
AddPrivilegeToAcccount(LPTSTR name, LPWSTR PrivilegeName) {
LSA_HANDLE PolicyHandle;
TCHAR AccountName[256];
PSID pSid;
NTSTATUS Status;
unsigned long err;
if ((Status = OpenPolicy(NULL, POLICY_ALL_ACCESS, &PolicyHandle))
!= STATUS_SUCCESS)
return (RTN_ERROR);
wsprintf(AccountName, TEXT("%hS"), name);
if (!GetAccountSid(NULL, AccountName, &pSid))
return (RTN_NOACCOUNT);
err = LsaNtStatusToWinError(SetPrivilegeOnAccount(PolicyHandle,
pSid, PrivilegeName, TRUE));
LsaClose(PolicyHandle);
if (err == ERROR_SUCCESS)
return (RTN_OK);
else
return (err);
}
void
InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String){
size_t StringLength;
if (String == NULL) {
LsaString->Buffer = NULL;
LsaString->Length = 0;
LsaString->MaximumLength = 0;
return;
}
StringLength = wcslen(String);
LsaString->Buffer = String;
LsaString->Length = (USHORT) StringLength * sizeof(WCHAR);
LsaString->MaximumLength = (USHORT)(StringLength+1) * sizeof(WCHAR);
}
NTSTATUS
OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle){
LSA_OBJECT_ATTRIBUTES ObjectAttributes;
LSA_UNICODE_STRING ServerString;
PLSA_UNICODE_STRING Server = NULL;
ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
if (ServerName != NULL) {
InitLsaString(&ServerString, ServerName);
Server = &ServerString;
}
return (LsaOpenPolicy(Server, &ObjectAttributes, DesiredAccess,
PolicyHandle));
}
BOOL
GetAccountSid(LPTSTR SystemName, LPTSTR AccountName, PSID *Sid) {
LPTSTR ReferencedDomain = NULL;
DWORD cbSid = 128;
DWORD cbReferencedDomain = 16;
SID_NAME_USE peUse;
BOOL bSuccess = FALSE;
__try {
if ((*Sid = HeapAlloc(GetProcessHeap(), 0, cbSid)) == NULL)
__leave;
if ((ReferencedDomain = (LPTSTR) HeapAlloc(GetProcessHeap(), 0,
cbReferencedDomain)) == NULL) __leave;
while (!LookupAccountName(SystemName, AccountName, *Sid, &cbSid,
ReferencedDomain, &cbReferencedDomain,
&peUse))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
if ((*Sid = HeapReAlloc(GetProcessHeap(), 0,
*Sid, cbSid)) == NULL) __leave;
if ((ReferencedDomain= (LPTSTR) HeapReAlloc(
GetProcessHeap(), 0, ReferencedDomain,
cbReferencedDomain)) == NULL)
__leave;
}
else
__leave;
}
bSuccess = TRUE;
}
__finally {
HeapFree(GetProcessHeap(), 0, ReferencedDomain);
if (!bSuccess) {
if (*Sid != NULL) {
HeapFree(GetProcessHeap(), 0, *Sid);
*Sid = NULL;
}
}
}
return (bSuccess);
}
NTSTATUS
SetPrivilegeOnAccount(LSA_HANDLE PolicyHandle, PSID AccountSid,
LPWSTR PrivilegeName, BOOL bEnable)
{
LSA_UNICODE_STRING PrivilegeString;
InitLsaString(&PrivilegeString, PrivilegeName);
if (bEnable)
return (LsaAddAccountRights(PolicyHandle, AccountSid,
&PrivilegeString, 1));
else
return (LsaRemoveAccountRights(PolicyHandle, AccountSid,
FALSE, &PrivilegeString, 1));
}
NTSTATUS
GetPrivilegesOnAccount(LSA_HANDLE PolicyHandle, PSID AccountSid,
wchar_t **PrivList, unsigned int *PrivCount)
{
NTSTATUS Status;
LSA_UNICODE_STRING *UserRights;
ULONG CountOfRights;
unsigned int retlen = 0;
DWORD i, j;
int found;
Status = LsaEnumerateAccountRights(PolicyHandle, AccountSid,
&UserRights, &CountOfRights);
if (UserRights == NULL || Status != STATUS_SUCCESS)
return (Status);
for (i = 0; i < CountOfRights; i++) {
found = -1;
retlen = UserRights[i].Length/sizeof(wchar_t);
for (j = 0; j < *PrivCount; j++) {
found = wcsncmp(PrivList[j], UserRights[i].Buffer,
retlen);
if (found == 0)
break;
}
if (found != 0) {
PrivList[*PrivCount] =
(wchar_t *)malloc(UserRights[i].MaximumLength);
if (PrivList[*PrivCount] == NULL)
return (RTN_NOMEMORY);
wcsncpy(PrivList[*PrivCount], UserRights[i].Buffer,
retlen);
PrivList[*PrivCount][retlen] = L'\0';
(*PrivCount)++;
}
}
return (Status);
}
void
DisplayNtStatus(LPSTR szAPI, NTSTATUS Status) {
DisplayWinError(szAPI, LsaNtStatusToWinError(Status));
}
void
DisplayWinError(LPSTR szAPI, DWORD WinError) {
LPSTR MessageBuffer;
DWORD dwBufferLength;
if (dwBufferLength=FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, WinError, GetUserDefaultLangID(),
(LPSTR) &MessageBuffer, 0, NULL)){
DWORD dwBytesWritten;
WriteFile(GetStdHandle(STD_ERROR_HANDLE), MessageBuffer,
dwBufferLength, &dwBytesWritten, NULL);
LocalFree(MessageBuffer);
}
}