/* cvsnt su test program
Copyright (C) 2004-5 Tony Hoyle and March-Hare Software Ltd
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License version 2.1 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// suidtest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
/*
IsDomainMember patch from John Anderson <panic@semiosix.com>
Find out whether the machine is a member of a domain or not
*/
// build LSA UNICODE strings.
void InitLsaString( PLSA_UNICODE_STRING LsaString, LPWSTR String )
{
DWORD StringLength;
if ( String == NULL )
{
LsaString->Buffer = NULL;
LsaString->Length = 0;
LsaString->MaximumLength = 0;
return;
}
StringLength = (DWORD)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;
// Always initialize the object attributes to all zeroes.
ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
if ( ServerName != NULL )
{
// Make a LSA_UNICODE_STRING out of the LPWSTR passed in.
InitLsaString(&ServerString, ServerName);
Server = &ServerString;
}
// Attempt to open the policy.
return LsaOpenPolicy( Server, &ObjectAttributes, DesiredAccess, PolicyHandle );
}
int isDomainMember(wchar_t *wszDomain)
{
PPOLICY_PRIMARY_DOMAIN_INFO ppdiDomainInfo=NULL;
PPOLICY_DNS_DOMAIN_INFO pddiDomainInfo=NULL;
LSA_HANDLE PolicyHandle;
NTSTATUS status;
BOOL retval = FALSE;
// open the policy object for the local system
status = OpenPolicy(
NULL
, GENERIC_READ | POLICY_VIEW_LOCAL_INFORMATION
, &PolicyHandle
);
// You have a handle to the policy object. Now, get the
// domain information using LsaQueryInformationPolicy.
if ( !status )
{
/* Based on patch by Valdas Sevelis. Call PolicyDnsDomainInformation first
as Win2K Advanced server is broken w/PolicyPrimaryDomainInformation */
status = LsaQueryInformationPolicy(
PolicyHandle,
PolicyDnsDomainInformation,
(void**)&pddiDomainInfo);
if(!status)
{
retval = pddiDomainInfo->Sid != 0;
if(wszDomain && retval)
{
wcsncpy(wszDomain,pddiDomainInfo->Name.Buffer,pddiDomainInfo->Name.Length);
wszDomain[pddiDomainInfo->Name.Length]='\0';
}
LsaFreeMemory( (LPVOID)pddiDomainInfo );
}
else
{
status = LsaQueryInformationPolicy(
PolicyHandle,
PolicyPrimaryDomainInformation,
(void**)&ppdiDomainInfo);
if(!status)
{
retval = ppdiDomainInfo->Sid != 0;
if(wszDomain && retval)
{
wcsncpy(wszDomain,ppdiDomainInfo->Name.Buffer,ppdiDomainInfo->Name.Length);
wszDomain[ppdiDomainInfo->Name.Length]='\0';
}
LsaFreeMemory( (LPVOID)ppdiDomainInfo );
}
}
}
// Clean up all the memory buffers created by the LSA calls
LsaClose(PolicyHandle);
return retval;
}
DWORD BreakNameIntoParts(LPCTSTR name, LPWSTR w_name, LPWSTR w_domain, LPWSTR w_pdc)
{
static wchar_t *pw_pdc;
TCHAR *ptr;
wchar_t w_defaultdomain[DNLEN+1]={0};
int is_domain = isDomainMember(w_defaultdomain);
#ifdef TRACE
if(is_domain)
TRACE(3,"Machine is domain member");
else
TRACE(3,"Machine is standalone");
#endif
ptr=_tcschr(name, '\\');
if (ptr)
{
#ifdef _UNICODE
_tcscpy(w_name,ptr+1);
_tcsncpy(w_domain,name,ptr-name);
w_domain[ptr-name]='\0';
#else
w_name[MultiByteToWideChar(CP_ACP,0,ptr+1,-1,w_name,UNLEN+1)]='\0';
w_domain[MultiByteToWideChar(CP_ACP,0,name,ptr-name,w_domain,DNLEN)]='\0';
#endif
}
else
{
#ifdef _UNICODE
_tcscpy(w_name,name);
#else
w_name[MultiByteToWideChar(CP_ACP,0,name,-1,w_name,UNLEN+1)]='\0';
#endif
if(is_domain)
wcscpy(w_domain,w_defaultdomain);
else
*w_domain='\0';
}
if(w_pdc)
{
typedef DWORD (WINAPI *DsGetDcNameW_t)(LPCWSTR ComputerName,LPCWSTR DomainName,GUID *DomainGuid,LPCWSTR SiteName,ULONG Flags,PDOMAIN_CONTROLLER_INFOW *DomainControllerInfo);
DsGetDcNameW_t pDsGetDcNameW;
pDsGetDcNameW=(DsGetDcNameW_t)GetProcAddress(GetModuleHandle(_T("netapi32")),"DsGetDcNameW");
w_pdc[0]='\0';
if(w_domain[0] && pDsGetDcNameW)
{
PDOMAIN_CONTROLLER_INFOW pdi;
if(!pDsGetDcNameW(NULL,w_domain,NULL,NULL,DS_IS_FLAT_NAME,&pdi) || !pDsGetDcNameW(NULL,w_domain,NULL,NULL,DS_IS_DNS_NAME,&pdi))
{
wcscpy(w_pdc,pdi->DomainControllerName);
NetApiBufferFree(pdi);
}
}
else if(w_domain[0])
{
if(!NetGetAnyDCName(NULL,w_domain,(LPBYTE*)&pw_pdc) || !NetGetDCName(NULL,w_domain,(LPBYTE*)&pw_pdc))
{
wcscpy(w_pdc,pw_pdc);
NetApiBufferFree(pw_pdc);
}
}
#ifdef TRACE
TRACE(3,"Authenticating server: %S",w_pdc[0]?w_pdc:L"(local)");
#endif
}
return ERROR_SUCCESS;
}
/* Quick and dirty window station security fix */
BOOL SetWinstaDesktopSecurity(void)
{
HWINSTA hWinsta;
HDESK hDesk;
SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
SECURITY_DESCRIPTOR sd;
// Get the current window station and desktop
hWinsta = GetProcessWindowStation();
if(hWinsta == NULL)
return FALSE;
hDesk = GetThreadDesktop(GetCurrentThreadId());
if (hDesk == NULL)
return FALSE;
// Create a NULL DACL
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, (PACL) NULL, FALSE);
// Set the NULL DACL
if (!SetUserObjectSecurity(hWinsta, &si, &sd))
{
printf("SetUserObjectSecurity on the window station failed: %d",GetLastError());
return FALSE;
}
if (!SetUserObjectSecurity(hDesk, &si, &sd))
{
printf("SetUserObjectSecurity on the desktop failed: %d",GetLastError());
return FALSE;
}
// Return indicating success
return TRUE;
}
TCHAR read_key()
{
INPUT_RECORD buffer;
DWORD EventsRead;
TCHAR ch;
HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
BOOL CharRead = FALSE;
/* loop until we find a valid keystroke (a KeyDown event, and NOT a
SHIFT, ALT, or CONTROL keypress by itself) */
while(!CharRead)
{
while( !CharRead && ReadConsoleInput(hInput, &buffer, 1, &EventsRead ) &&
EventsRead > 0 )
{
if( buffer.EventType == KEY_EVENT &&
buffer.Event.KeyEvent.bKeyDown )
{
#ifdef _UNICODE
ch = buffer.Event.KeyEvent.uChar.UnicodeChar;
#else
ch = buffer.Event.KeyEvent.uChar.AsciiChar;
#endif
if(ch)
CharRead = TRUE;
}
}
}
return ch;
}
TCHAR *getpass (const char *prompt)
{
static TCHAR password[128];
static const int max_length = sizeof(password);
int i;
TCHAR c;
HANDLE hInput=GetStdHandle(STD_INPUT_HANDLE);
DWORD dwMode;
fputs (prompt, stderr);
fflush (stderr);
fflush (stdout);
FlushConsoleInputBuffer(hInput);
GetConsoleMode(hInput,&dwMode);
SetConsoleMode(hInput,ENABLE_PROCESSED_INPUT);
for (i = 0; i < max_length - 1; ++i)
{
c=0;
c = read_key();
if(c==27 || c=='\r' || c=='\n')
break;
password[i]=c;
fputc('*',stdout);
fflush (stderr);
fflush (stdout);
}
SetConsoleMode(hInput,dwMode);
FlushConsoleInputBuffer(hInput);
password[i] = '\0';
fputs ("\n", stderr);
return c==27?NULL:password;
}
char *ErrorToString(DWORD dwError)
{
static char Buffer[1024];
FormatMessageA(
FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_MAX_WIDTH_MASK,
NULL,
dwError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
Buffer,
sizeof(Buffer),
NULL);
return Buffer;
}
int _tmain(int argc, TCHAR* argv[])
{
HANDLE hToken;
wchar_t wszName[256];
wchar_t wszDomain[256];
STARTUPINFO si = { sizeof(STARTUPINFO) };
PROCESS_INFORMATION pi = {0};
wchar_t wszTitle[256];
DWORD dwLen,dwErr;
if(argc!=2)
{
fprintf(stderr,"Usage: %S <username>",argv[0]);
return -1;
}
dwLen=sizeof(wszName);
GetUserName(wszName,&dwLen);
_snwprintf(wszTitle,sizeof(wszTitle),L"%s impersonating %s",wszName,argv[1]);
si.lpTitle=wszTitle;
si.wShowWindow=SW_SHOW;
if(BreakNameIntoParts(argv[1],wszName,wszDomain,NULL))
return -1;
switch((dwErr=SuidGetImpersonationTokenW(wszName,wszDomain,LOGON32_LOGON_INTERACTIVE,&hToken)))
{
case ERROR_SUCCESS:
break;
case ERROR_PRIVILEGE_NOT_HELD:
case ERROR_ACCESS_DENIED:
{
wchar_t *pw = getpass("Password: ");
if(!LogonUser(wszName,wszDomain,pw,LOGON32_LOGON_INTERACTIVE,0,&hToken))
{
switch((dwErr=GetLastError()))
{
case ERROR_SUCCESS:
break;
default:
fprintf(stderr,"%s\n",ErrorToString(dwErr));
return -1;
}
}
}
break;
default:
fprintf(stderr,"%s\n",ErrorToString(dwErr));
return -1;
}
SetWinstaDesktopSecurity();
wchar_t wszCommand[]=L"cmd.exe";
/* Unicode version of CreateProcess modifies its command parameter... Ansi doesn't.
Apparently this is not classed as a bug ???? */
if(!CreateProcessAsUser(hToken,NULL,wszCommand,NULL,NULL,FALSE,CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi))
{
CloseHandle(hToken);
fprintf(stderr,"CreateProcess returned error %d\n",GetLastError());
return -1;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hToken);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1