|
|
//---------------------------------------------------------
// Copyright (c) 1999-2000 Microsoft Corporation
//
// utilfunctions.cpp
//
// vikram K.R.C. ([email protected])
//
// Some generic functions to do command line administration
// (May-2000)
//---------------------------------------------------------
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntlsa.h>
#include "resource.h" //resource.h should be before any other .h file that has resource ids.
#include "admutils.h"
#include "common.h"
#include <stdio.h>
#include <stdarg.h>
#include <shlwapi.h>
#include <tchar.h>
#include <assert.h>
#include <conio.h>
#include <winsock.h>
#include <windns.h> //for #define DNS_MAX_NAME_BUFFER_LENGTH 256
#include <Lmuse.h>
#include <Lm.h>
#include "sfucom.h"
#include <lm.h>
#include <commctrl.h>
#include <OleAuto.h >
#include <string.h>
#include <stdlib.h>
#include "atlbase.h"
#define WINLOGONNT_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon")
#define NETLOGONPARAMETERS_KEY TEXT("System\\CurrentControlSet\\Services\\Netlogon\\Parameters")
#define TRUSTEDDOMAINLIST_VALUE TEXT("TrustedDomainList")
#define CACHEPRIMARYDOMAIN_VALUE TEXT("CachePrimaryDomain")
#define CACHETRUSTEDDOMAINS_VALUE TEXT("CacheTrustedDomains")
#define DOMAINCACHE_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\DomainCache")
#define DCACHE_VALUE TEXT("DCache")
#define WINLOGONNT_DCACHE_KEY TEXT("DCache")
//FOR USING THE CLIGRPENUM INTERFACE...(it is used in the function
//IsValidDomain)
//the following are hash defined in the CligrpEnum.cpp file.
#define GROUP 1
#define MEMBER 2
#define NTDOMAIN 3
#define MACHINE 4
//Globals
BSTR bstrLogin=NULL; BSTR bstrPasswd=NULL; BSTR bstrNameSpc= NULL;
SC_HANDLE g_hServiceManager=NULL; SC_HANDLE g_hServiceHandle=NULL; SERVICE_STATUS g_hServiceStatus;
WCHAR *local_host = L"\\\\localhost";
BOOL g_fNetConnectionExists = FALSE;
STRING_LIST g_slNTDomains;
//externs
//from tnadmutl.cpp
extern wchar_t* g_arCLASSname[_MAX_CLASS_NAMES_]; //the hive names....
extern int g_arNUM_PROPNAME[_MAX_PROPS_]; //Number of properties in the registry each one corresponds to.
extern HKEY g_hkeyHKLM; //to store the handle to the registry.
extern HKEY g_arCLASShkey[_MAX_CLASS_NAMES_]; //array to hold the handles to the keys of the class hives.
extern WCHAR g_szMsg[MAX_BUFFER_SIZE] ; //array to store the string loaded.
extern HMODULE g_hResource; //handle to the strings library.
HMODULE g_hXPResource; //handle to the XPSP1 strings library.
extern HANDLE g_stdout;
StrList* g_pStrList=NULL;
#ifdef __cplusplus
extern "C" { #endif
//Global Variables...
//externs from nfsadmin.y file.
extern int g_nError; // the error flag, 1 error, 0 no error.
extern int g_nPrimaryOption; //_tSERVER, _tCLIENT, _tGW or _tHELP
extern int g_nSecondaryOption; //Start,Stop,Config,etc kind of things.
extern int g_nTertiaryOption; extern int g_nConfigOptions; //the Config Options.
extern ConfigProperty g_arPROP[_MAX_PROPS_][_MAX_NUMOF_PROPNAMES_]; extern wchar_t* g_arVALOF[_MAX_PROPS_]; //the given values of properties in the command line
#ifdef __cplusplus
} #endif
BOOL g_fCoInitSuccess = FALSE;
/*
* wzName should not be NULL. (Caller's responsibility) */ HRESULT DoNetUseGetInfo(WCHAR *wzName, BOOL *fConnectionExists) { HRESULT hRes=S_OK;
WCHAR wzResource[DNS_MAX_NAME_BUFFER_LENGTH+1];
USE_INFO_0 *pUseInfo0; API_RET_TYPE uReturnCode; // API return code
*fConnectionExists = FALSE;
if (NULL == wzName) { return E_FAIL; }
_snwprintf(wzResource,DNS_MAX_NAME_BUFFER_LENGTH, L"%s\\ipc$", wzName);
wzResource[DNS_MAX_NAME_BUFFER_LENGTH] = L'\0'; // Ensure NULL termination
uReturnCode=NetUseGetInfo(NULL, wzResource, 0, (LPBYTE *)&pUseInfo0);
if(NERR_Success != uReturnCode) { // If no network connection exists, return S_OK as it
// is not an error for us.
if(ERROR_NOT_CONNECTED == uReturnCode) goto End; PrintFormattedErrorMessage(uReturnCode); hRes=E_FAIL; } else { // Debug Messages
/*
wprintf(L" Local device : %s\n", pUseInfo0->ui0_local); wprintf(L" Remote device : %Fs\n", pUseInfo0->ui0_remote); */
// NetUseGetInfo function allocates memory for the buffer
// Hence need to free the same.
NetApiBufferFree(pUseInfo0); *fConnectionExists = TRUE; } End: return hRes; }
HRESULT DoNetUseAdd(WCHAR* wzLoginname, WCHAR* wzPassword,WCHAR* wzCname) { HRESULT hRes=S_OK; USE_INFO_2 ui2Info; DWORD dw=-1; WCHAR* wzName=NULL; int fValid=0; int retVal=0; char szHostName[DNS_MAX_NAME_BUFFER_LENGTH]; int count; WCHAR* wzTemp=NULL; WCHAR szTemp[MAX_BUFFER_SIZE];
ui2Info.ui2_local=NULL; ui2Info.ui2_remote=NULL;
if(wzCname!=NULL && _wcsicmp(wzCname, L"localhost") && _wcsicmp(wzCname, local_host) ) { //Validate the MACHINE
if(FAILED(hRes=IsValidMachine(wzCname, &fValid))) return hRes; else if(!fValid) { if(0==LoadString(g_hResource,IDR_MACHINE_NOT_AVAILABLE,szTemp,MAX_BUFFER_SIZE)) return GetLastError(); _snwprintf(g_szMsg, MAX_BUFFER_SIZE -1, szTemp,wzCname); MyWriteConsole(g_stdout, g_szMsg, wcslen(g_szMsg)); hRes= E_FAIL; goto End; }
//format properly
if((wzName=(wchar_t*)malloc((3+wcslen(wzCname))*sizeof(wchar_t)))==NULL) return E_OUTOFMEMORY; if(NULL==StrStrI(wzCname,L"\\\\")) { wcscpy(wzName,L"\\\\"); wcscat(wzName,wzCname); } else if(wzCname==StrStrI(wzCname,L"\\\\")) wcscpy(wzName,wzCname); else { hRes=E_INVALIDARG; goto End; } // See whether a network connection already exists for
// resource ipc$.
if(FAILED(hRes = DoNetUseGetInfo(wzName, &g_fNetConnectionExists))) goto End;
// Network Connection already exists.
if(g_fNetConnectionExists) goto End;
} else if(NULL==wzLoginname) goto End; else //We should send the localhost's name in absolute terms ...otherwise it gives error "duplicate name exists"
{ WORD wVersionRequested; //INGR
WSADATA wsaData; //INGR
// Start up winsock
wVersionRequested = MAKEWORD( 1, 1 ); //INGR
if (0==WSAStartup(wVersionRequested, &wsaData)) { //INGR
if(SOCKET_ERROR!=(gethostname(szHostName,DNS_MAX_NAME_BUFFER_LENGTH))) { if((wzName=(WCHAR *)malloc((3+strlen(szHostName))*sizeof(WCHAR)))==NULL) return E_OUTOFMEMORY; wcscpy(wzName,L"\\\\"); if(NULL==(wzTemp=DupWStr(szHostName))) { free(wzName); return E_OUTOFMEMORY; } wzName=wcscat(wzName,wzTemp); free(wzTemp); } else { hRes = GetLastError(); g_nError = hRes; PrintFormattedErrorMessage(hRes); goto End; } WSACleanup(); //INGR
} else wzName=local_host; } count = (7 + wcslen(wzName)); // name + \ipc$
ui2Info.ui2_remote=(wchar_t*)malloc(count * sizeof(wchar_t)); if(NULL==ui2Info.ui2_remote) { hRes=E_OUTOFMEMORY; goto End; }
_snwprintf(ui2Info.ui2_remote, count, L"%s\\ipc$", wzName); // calculated size, no risks
ui2Info.ui2_password=wzPassword; ui2Info.ui2_asg_type=USE_IPC;
if(NULL==wzLoginname) { ui2Info.ui2_username=NULL; ui2Info.ui2_domainname=NULL; } else if(NULL==StrStrI(wzLoginname,L"\\")) { ui2Info.ui2_username=wzLoginname; ui2Info.ui2_domainname=NULL; } else { wzTemp=ui2Info.ui2_username=_wcsdup(wzLoginname); if(NULL==wzTemp) { hRes=E_OUTOFMEMORY; goto End; } ui2Info.ui2_domainname=wcstok(wzTemp,L"\\"); ui2Info.ui2_username=wcstok(NULL,L"\\"); }
NET_API_STATUS nError; nError = NetUseAdd(NULL, 2, (LPBYTE) &ui2Info, &dw); if (NERR_Success != nError) { LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, nError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),// Default language
(LPTSTR) &lpMsgBuf, 0, NULL);
_tprintf(L"\n%s\n",(LPCTSTR)lpMsgBuf); LocalFree( lpMsgBuf ); hRes=E_FAIL; // To return E_FAIL from the function
goto End; }
End: if(wzName && (wzName != local_host)) free(wzName); if(ui2Info.ui2_remote) free(ui2Info.ui2_remote);
return hRes; }
HRESULT DoNetUseDel(WCHAR* wzCname) { HRESULT hRes=S_OK; int retVal=-1; WCHAR wzName[DNS_MAX_NAME_BUFFER_LENGTH+1] = { 0 }; int nWritten = 0;
// The network connection was there before invoking the admin tool
// So, don't delete it
if(g_fNetConnectionExists) goto End; if(NULL!=wzCname && _wcsicmp(wzCname, L"localhost") && _wcsicmp(wzCname, local_host) ) { if(NULL==StrStrI(wzCname,L"\\\\")) { nWritten = _snwprintf(wzName, ARRAYSIZE(wzName) - 1, L"\\\\%s", wzCname); if (nWritten < 0) { hRes=E_INVALIDARG; goto End; } } else if(wzCname==StrStrI(g_arVALOF[_p_CNAME_],L"\\\\")) { wcsncpy(wzName, wzCname, (ARRAYSIZE(wzName) - 1)); wzName[(ARRAYSIZE(wzName) - 1)] = 0; nWritten = wcslen(wzName); } else { hRes=E_INVALIDARG; goto End; }
wcsncpy(wzName+nWritten, L"\\ipc$", (ARRAYSIZE(wzName) - 1 - nWritten)); wzName[ARRAYSIZE(wzName)-1] = L'\0'; retVal=NetUseDel( NULL, wzName, USE_LOTS_OF_FORCE ); if(retVal!=NERR_Success) { hRes=retVal; goto End; } }
End: return hRes; } /*--
This function gets a handle to Registry. --*/
HRESULT GetConnection(WCHAR* wzCname) { int fValid=0; HRESULT hRes=S_OK;
wchar_t* wzName=NULL; LONG apiReturn=0L;
//probably already got the key
if(g_hkeyHKLM!=NULL) return S_OK;
if(wzCname!=NULL) { if((wzName=(wchar_t*)malloc((3+wcslen(wzCname))*sizeof(wchar_t)))==NULL) { ShowError(IDS_E_OUTOFMEMORY); hRes = E_OUTOFMEMORY; goto End; } if(NULL==StrStrI(wzCname,L"\\\\")) { wcscpy(wzName,L"\\\\"); wcscat(wzName,wzCname); } else if(wzCname==StrStrI(wzCname,L"\\\\")) wcscpy(wzName,wzCname); else { hRes = E_INVALIDARG; goto End; } } //connecting to the registry.
apiReturn = ERROR_SUCCESS; apiReturn = RegConnectRegistry( wzName, HKEY_LOCAL_MACHINE, &g_hkeyHKLM );
if (ERROR_SUCCESS != apiReturn) { PrintFormattedErrorMessage(apiReturn); hRes = E_FAIL; }
End: if(wzName) free(wzName);
return hRes; }
/*--
the GetSerHandle() function gets the service handle to the admin --*/
HRESULT GetSerHandle(LPCTSTR lpServiceName,DWORD dwScmDesiredAccess, DWORD dwRegDesiredAccess,BOOL fSuppressMsg) {
wchar_t* wzCname; HRESULT hRes=S_OK; WCHAR szTemp[MAX_BUFFER_SIZE];
if(g_arVALOF[_p_CNAME_]!=NULL && StrStrI(g_arVALOF[_p_CNAME_],L"\\")!=g_arVALOF[_p_CNAME_]) { if((wzCname=(wchar_t *)malloc((3+wcslen(g_arVALOF[_p_CNAME_]))*sizeof(wchar_t)))==NULL) { ShowError(IDS_E_OUTOFMEMORY); return E_FAIL; } wcscpy(wzCname,L"\\\\"); wcscat(wzCname,g_arVALOF[_p_CNAME_]); } else wzCname=g_arVALOF[_p_CNAME_];
if (g_hServiceManager) CloseServiceHandle(g_hServiceManager); if ((g_hServiceManager = OpenSCManager(wzCname,SERVICES_ACTIVE_DATABASE,dwScmDesiredAccess))==NULL) { DWORD dwErrorCode=0; dwErrorCode = GetLastError(); if(ERROR_ACCESS_DENIED == dwErrorCode) { hRes = ERROR_ACCESS_DENIED; // Need to return this error
ShowError(IDR_NOT_PRIVILEGED); fwprintf(stdout,L" %s\n",(g_arVALOF[_p_CNAME_] ? g_arVALOF[_p_CNAME_] : L"localhost")); } else PrintFormattedErrorMessage(dwErrorCode); } else if ((g_hServiceHandle= OpenService(g_hServiceManager,lpServiceName,dwRegDesiredAccess))==NULL) if((hRes=GetLastError())==ERROR_SERVICE_DOES_NOT_EXIST && (FALSE==fSuppressMsg)) { ShowError(IDR_SERVICE_NOT_INSTALLED); fwprintf(stdout,L" %s.\n", lpServiceName); if (0 == LoadString(g_hResource, IDR_VERIFY_SERVICE_INSTALLED, szTemp, MAX_BUFFER_SIZE)) { return GetLastError(); } _snwprintf(g_szMsg, MAX_BUFFER_SIZE -1, szTemp,(g_arVALOF[_p_CNAME_] ? g_arVALOF[_p_CNAME_] : L"localhost")); MyWriteConsole(g_stdout, g_szMsg, wcslen(g_szMsg));
} return hRes; }
/*--
to close the service handles --*/ HRESULT CloseHandles() { BOOL bRet = FALSE; HRESULT hRes = S_OK; if(g_hServiceHandle ) { bRet = CloseServiceHandle(g_hServiceHandle); g_hServiceHandle = NULL; if(!bRet) hRes = GetLastError(); } if(g_hServiceManager) { bRet = CloseServiceHandle(g_hServiceManager); g_hServiceManager= NULL; if(!bRet) hRes = GetLastError(); } return hRes; }
/*-- StartSer Starts the Service after getting its handle by using
GetSerHandle function --*/ HRESULT StartSfuService(LPCTSTR lpServiceName) { HRESULT hRes=S_OK; SERVICE_STATUS serStatus; DWORD dwOldCheckPoint; DWORD dwStartTickCount; DWORD dwWaitTime; DWORD dwStatus; if(FAILED(hRes=GetSerHandle(lpServiceName,SC_MANAGER_ALL_ACCESS,SERVICE_ALL_ACCESS,FALSE))) goto End;
if(hRes == ERROR_ACCESS_DENIED) { // Don't know why ERROR_ACCESS_DENIED escaped FAILED() macro. Anyway,
// returning that error here.
goto End; } else if(StartService(g_hServiceHandle, NULL, NULL)) { if (!QueryServiceStatus( g_hServiceHandle, // handle to service
&serStatus) ) // address of status information structure
{ hRes = GetLastError(); ShowErrorFallback(IDS_E_SERVICE_NOT_STARTED, _T("\nError occured while starting the service.")); if(hRes != ERROR_IO_PENDING) //not an interesting error to print
PrintFormattedErrorMessage(hRes); goto End; } dwStartTickCount = GetTickCount(); dwOldCheckPoint = serStatus.dwCheckPoint;
while (serStatus.dwCurrentState == SERVICE_START_PENDING) { // Do not wait longer than the wait hint. A good interval is
// one tenth the wait hint, but no less than 1 second and no
// more than 10 seconds.
dwWaitTime = serStatus.dwWaitHint / 10;
if( dwWaitTime < 1000 ) dwWaitTime = 1000; else if ( dwWaitTime > 10000 ) dwWaitTime = 10000;
Sleep( dwWaitTime );
// Check the status again.
if (!QueryServiceStatus( g_hServiceHandle, // handle to service
&serStatus) ) // address of structure
break; if ( serStatus.dwCheckPoint > dwOldCheckPoint ) { // The service is making progress.
dwStartTickCount = GetTickCount(); dwOldCheckPoint = serStatus.dwCheckPoint; } else { if(GetTickCount()-dwStartTickCount > serStatus.dwWaitHint) { // No progress made within the wait hint
break; } } }
if (serStatus.dwCurrentState == SERVICE_RUNNING) { PrintMessageEx(g_stdout,IDS_SERVICE_STARTED, _T("\nThe service was started successfully.\n")); goto End; } }
if((hRes=GetLastError())==ERROR_SERVICE_ALREADY_RUNNING) { /* StartService returns SERVICE_ALREADY_RUNNING even when the
service is in wierd state. For instance, when the service is in the state STOP_PENDING, we print - The service was controlled successfully To avoid this, we issue a control to the service and see if it can respond. If it can't appropriate error message is printed */ if (ControlService(g_hServiceHandle, SERVICE_CONTROL_INTERROGATE, &serStatus)) { PrintMessageEx(g_stdout,IDR_ALREADY_STARTED, _T("\nThe service is already started.\n")); hRes = S_OK; } else { hRes = GetLastError(); ShowErrorFallback(IDS_E_SERVICE_NOT_STARTED, _T("\nError occured while starting the service.")); if(hRes != ERROR_IO_PENDING) //not an interesting error to print
PrintFormattedErrorMessage(hRes); } } else if(hRes==ERROR_ACCESS_DENIED) ShowError(IDR_NOT_PRIVILEGED); else { ShowErrorFallback(IDS_E_SERVICE_NOT_STARTED, _T("\nError occured while starting the service.")); if(hRes != ERROR_IO_PENDING) //not an interesting error to print
PrintFormattedErrorMessage(hRes); }
End: CloseHandles(); return hRes; }
/*--
QuerySfuService function queries the service for its status.
--*/ HRESULT QuerySfuService(LPCTSTR lpServiceName) { HRESULT hRes; if(FAILED(hRes=GetSerHandle(lpServiceName,SC_MANAGER_CONNECT,SERVICE_QUERY_STATUS,FALSE))) return hRes;
if(hRes == ERROR_ACCESS_DENIED) { // Don't know why ERROR_ACCESS_DENIED escaped FAILED() macro. Anyway,
// returning that error here.
return hRes; }
else if(QueryServiceStatus(g_hServiceHandle,&g_hServiceStatus)) return CloseHandles(); else return GetLastError(); } /*--
ControlSfuService Stops Pauses Continues the Service after getting its handle by using GetSerHandle function.
--*/
HRESULT ControlSfuService(LPCTSTR lpServiceName,DWORD dwControl) { LPSERVICE_STATUS lpStatus = (SERVICE_STATUS *) malloc (sizeof(SERVICE_STATUS));
if(lpStatus==NULL) { ;//bugbug print an error
return E_OUTOFMEMORY; }
HRESULT hr = S_FALSE; int queryCounter =0; DWORD dwState = 0;
if(FAILED(dwState= GetSerHandle(lpServiceName,SC_MANAGER_ALL_ACCESS,SERVICE_ALL_ACCESS,FALSE))) {free(lpStatus);return dwState;}
if(dwState == ERROR_ACCESS_DENIED) { // Don't know why ERROR_ACCESS_DENIED escaped FAILED() macro. Anyway,
// returning that error here.
free(lpStatus); return dwState; }
//Check the return value of ControlService. If not null, then loop
//with QueryServiceStatus
if (ControlService(g_hServiceHandle,dwControl,lpStatus)) { switch(dwControl) { case(SERVICE_CONTROL_PAUSE) : dwState = SERVICE_PAUSED; break; case(SERVICE_CONTROL_CONTINUE) : dwState = SERVICE_RUNNING; break; case(SERVICE_CONTROL_STOP): dwState = SERVICE_STOPPED; break; } for (;queryCounter <= _MAX_QUERY_CONTROL_; queryCounter++) { if( QueryServiceStatus( g_hServiceHandle, lpStatus ) ) { //Check if state required is attained
if ( lpStatus->dwCurrentState != dwState ) { if ( lpStatus->dwWaitHint ) { Sleep(lpStatus->dwWaitHint); } else Sleep(500); } else { switch(dwControl) { case SERVICE_CONTROL_PAUSE: PrintMessageEx(g_stdout,IDR_SERVICE_PAUSED,_T("\nThe service has been paused.\n")); break; case SERVICE_CONTROL_CONTINUE: PrintMessageEx(g_stdout,IDR_SERVICE_CONTINUED,_T("\nThe service has been resumed.\n")); break; case SERVICE_CONTROL_STOP: PrintMessage(g_stdout,IDR_SERVICE_CONTROLLED); break; } hr = S_OK; break; } } else { hr = GetLastError(); PrintFormattedErrorMessage(hr); break; } } if (queryCounter > _MAX_QUERY_CONTROL_) { // We couldn't get to the state which we wanted to
// within the no. of iterations. So print that the
// service was not controlled successfully.
switch(dwControl) { case SERVICE_CONTROL_PAUSE: PrintMessageEx(g_stdout,IDR_SERVICE_NOT_PAUSED,_T("\nThe service could not be paused.\n")); break; case SERVICE_CONTROL_CONTINUE: PrintMessageEx(g_stdout,IDR_SERVICE_NOT_CONTINUED,_T("\nThe service could not be resumed.\n")); break; case SERVICE_CONTROL_STOP: PrintMessage(g_stdout,IDR_SERVICE_NOT_CONTROLLED); break; } hr = S_OK; } } else { hr = GetLastError(); PrintFormattedErrorMessage(hr); }
free (lpStatus); if(FAILED(hr)) return hr;
return CloseHandles(); }
/* --
GetBit(int Options,int bit) function returns the BIT in the position bit in the Options{it acts as a bit array} --*/
int GetBit(int Options,int nbit) { int ni=0x01,nj=0; ni=ni<<nbit;
if(ni&Options) return 1; else return 0; }
/* --
SetBit(int Options,int bit) function Sets the BIT in the position bit in the Options{it acts as a bit array}. --*/ int SetBit(int Options,int nbit) { int ni=1,nj=0; ni=ni<<nbit; Options=ni|Options; return Options; }
/*--
this function prints out the help message for the command --*/ HRESULT PrintMessage(HANDLE fp,int nMessageid) { HRESULT hRes = S_OK; HANDLE hOut = fp; int nRet = 0; DWORD dwWritten = 0; if( hOut == NULL ) hOut = g_stdout; if(LoadString(g_hResource, nMessageid, g_szMsg, MAX_BUFFER_SIZE)==0) return GetLastError(); MyWriteConsole(hOut,g_szMsg,_tcslen(g_szMsg)); return hRes; }
/*--
this function prints out the help message for the command and falls back to english string if loadstring fails --*/ HRESULT PrintMessageEx(HANDLE fp,int nMessageid, LPCTSTR szEng) { HRESULT hRes = S_OK; int nRet = 0; HANDLE hOut = fp; DWORD dwWritten = 0; if( hOut == NULL ) hOut = g_stdout;
TnLoadString(nMessageid, g_szMsg, MAX_BUFFER_SIZE,szEng); MyWriteConsole(hOut,g_szMsg,_tcslen(g_szMsg)); return hRes; }
/*--This function takes the parameter corresponding to the error code,
prints it out and puts back all the classes and quits the program. --*/
BOOL FileIsConsole( HANDLE fp ) { unsigned htype;
htype = GetFileType(fp); htype &= ~FILE_TYPE_REMOTE; return htype == FILE_TYPE_CHAR; }
void MyWriteConsole( HANDLE fp, LPWSTR lpBuffer, DWORD cchBuffer ) { //
// Jump through hoops for output because:
//
// 1. printf() family chokes on international output (stops
// printing when it hits an unrecognized character)
//
// 2. WriteConsole() works great on international output but
// fails if the handle has been redirected (i.e., when the
// output is piped to a file)
//
// 3. WriteFile() works great when output is piped to a file
// but only knows about bytes, so Unicode characters are
// printed as two Ansi characters.
//
if (FileIsConsole(fp)) { WriteConsole(fp, lpBuffer, cchBuffer, &cchBuffer, NULL); } else { LPSTR lpAnsiBuffer = (LPSTR) LocalAlloc(LMEM_FIXED, cchBuffer * sizeof(WCHAR));
if (lpAnsiBuffer != NULL) { cchBuffer = WideCharToMultiByte(CP_OEMCP, 0, lpBuffer, cchBuffer, lpAnsiBuffer, cchBuffer * sizeof(WCHAR), NULL, NULL);
if (cchBuffer != 0) { WriteFile(fp, lpAnsiBuffer, cchBuffer, &cchBuffer, NULL); }
LocalFree(lpAnsiBuffer); } } }
int ShowError(int nError) {
g_nError=nError;
if(LoadString(g_hResource, nError, g_szMsg, MAX_BUFFER_SIZE)==0) return 1; //failed to loadString
MyWriteConsole(g_stdout,g_szMsg, wcslen(g_szMsg));
return 0; //successfully shown error
}
/*--This function takes the parameter corresponding to the error code
and it's English String, prints it out and puts back all the classes and quits the program. --*/
int ShowErrorFallback(int nError, LPCTSTR szEng) {
g_nError=nError;
TnLoadString(nError,g_szMsg,MAX_BUFFER_SIZE,szEng); MyWriteConsole(g_stdout,g_szMsg, wcslen(g_szMsg));
return 0; //successfully shown error
}
// This function takes the input string for g_szMsg which is expected to
// contain a "%s" init. We have several usage of such string across the
// admintools and hence this function. Incase we have more that one %s
// then we can not use this function.
int ShowErrorEx(int nError,WCHAR *wzFormatString) { g_nError=nError;
if(LoadString(g_hResource, nError, g_szMsg, MAX_BUFFER_SIZE)==0) return 1; //failed to loadString
wprintf(g_szMsg,wzFormatString); fflush (stdout); return 0; //successfully shown error
}
/*--
GetClass function gets handles to all the class hives, into the array g_arCLASShkey, using the handle to the HKLM we have from GetConnection --*/
HRESULT GetClassEx(int nProperty, int nNumProp, BOOL bPrintErrorMessages, REGSAM samDesired) { int i=g_arPROP[nProperty][nNumProp].classname; LONG retVal;
if(g_arCLASShkey[i]!=NULL) return S_OK; retVal=RegOpenKeyEx( g_hkeyHKLM,// handle to open key
g_arCLASSname[i], // subkey name
0, // reserved
samDesired, // security access mask
g_arCLASShkey+i // handle to open key
); if(retVal!=ERROR_SUCCESS) { if (bPrintErrorMessages) { PrintFormattedErrorMessage(retVal); } return E_FAIL; }
return S_OK; }
/*--
PutClasses() function closes the keys to the hives. --*/
HRESULT PutClasses() { int ni=0; SCODE sc=S_OK; for(ni=0;ni<_MAX_CLASS_NAMES_;ni++) { if(g_arCLASShkey[ni]==NULL) continue; // this class was not got, so no need to put.
if(RegCloseKey(g_arCLASShkey[ni])!=ERROR_SUCCESS) sc=GetLastError(); g_arCLASShkey[ni]=NULL; }
if(g_hkeyHKLM!=NULL) { if (RegCloseKey(g_hkeyHKLM)!=ERROR_SUCCESS) return GetLastError(); g_hkeyHKLM=NULL; } return sc; }
/*--
GetProperty() function gets value of the required property from the hive.
//NOTE:
// In case of REG_MULTI_SZ type
//we are storing linked list of strings and not returning anything in variant
//the linked list 'g_pStrList' needs to be freed by the caller
//the caller needs to remember this
--*/ HRESULT GetProperty(int nProperty, int nNumofprop, VARIANT *pvarVal) { if(g_arPROP[nProperty][nNumofprop].propname==NULL) return E_FAIL;
LONG retVal=ERROR_SUCCESS; DWORD size; DWORD dType;
UINT uVar; wchar_t szString[MAX_BUFFER_SIZE]={0}; wchar_t* szMultiStr=NULL;
StrList * pHeadList=NULL; StrList * pTailList=NULL; StrList * pTemp= NULL ;
if(g_arCLASShkey[g_arPROP[nProperty][nNumofprop].classname]==NULL) { retVal=E_ABORT; goto End; } switch (V_VT(&g_arPROP[nProperty][nNumofprop].var)) { case VT_I4: size=sizeof(UINT); retVal=RegQueryValueEx(g_arCLASShkey[g_arPROP[nProperty][nNumofprop].classname], g_arPROP[nProperty][nNumofprop].propname, NULL, &dType, (LPBYTE)&uVar, (LPDWORD)&size ); if(retVal!=ERROR_SUCCESS) { // If this was because of the registry value not found
// display a proper error message instead of "the system
// can not find the file specified"
if(ERROR_FILE_NOT_FOUND==retVal) PrintMissingRegValueMsg(nProperty,nNumofprop); else PrintFormattedErrorMessage(retVal); goto End; }
V_I4(pvarVal)=uVar; break;
case VT_BSTR: size=MAX_BUFFER_SIZE*sizeof(wchar_t);
retVal=RegQueryValueEx(g_arCLASShkey[g_arPROP[nProperty][nNumofprop].classname], g_arPROP[nProperty][nNumofprop].propname, NULL, &dType, (LPBYTE)szString, (LPDWORD)&size ); if(retVal!=ERROR_SUCCESS) { // If this was because of the registry value not found
// display a proper error message instead of "the system
// can not find the file specified"
if(ERROR_FILE_NOT_FOUND==retVal) PrintMissingRegValueMsg(nProperty,nNumofprop); else PrintFormattedErrorMessage(retVal);
goto End; } V_BSTR(pvarVal)=SysAllocString(szString); if(NULL==V_BSTR(pvarVal)) { ShowError(IDS_E_OUTOFMEMORY); retVal=E_OUTOFMEMORY; goto End; }
break; case VT_ARRAY: pvarVal=NULL; retVal=RegQueryValueEx(g_arCLASShkey[g_arPROP[nProperty][nNumofprop].classname], g_arPROP[nProperty][nNumofprop].propname, NULL, &dType, NULL, (LPDWORD)&size ); if(retVal==ERROR_SUCCESS) { szMultiStr=(wchar_t*)malloc(size * sizeof(char)); if(szMultiStr==NULL) { retVal = E_OUTOFMEMORY; goto End; } //since the size returned is in bytes we use sizeof(char)
retVal=RegQueryValueEx(g_arCLASShkey[g_arPROP[nProperty][nNumofprop].classname], g_arPROP[nProperty][nNumofprop].propname, NULL, &dType, (LPBYTE)szMultiStr, (LPDWORD)&size );
}
if (retVal!=ERROR_SUCCESS) { if(ERROR_FILE_NOT_FOUND==retVal) PrintMissingRegValueMsg(nProperty,nNumofprop); else PrintFormattedErrorMessage(retVal); goto End; } else { //form a linked list containing the strings
//get all the strings into a linked list
// and their count into 'count'
int count = 0 ; DWORD length = 0 ; WCHAR* wzTemp = szMultiStr;
if (size >= 2) { // take away the last two zeroes of a reg_multi_sz
size -= 2; while( wzTemp && *wzTemp && (length < size/sizeof(WCHAR))) { pTemp= (StrList *) malloc( sizeof( StrList ) ); if(pTemp==NULL) { retVal=E_OUTOFMEMORY; goto End; }
count++; // add 1 so that you go past the null.
length+=wcslen(wzTemp ) + 1; if((pTemp->Str=_wcsdup(wzTemp))==NULL) { retVal=E_OUTOFMEMORY; goto End; } // insertion logic is being changed.
// insert at the tail.
if (NULL == pTailList) { // first insertion
pHeadList = pTemp; pTailList = pTemp; pTemp->next = NULL; pTemp = NULL; // the memory pointed by pTemp will be taken care by the linked list.
} else { // normal insertion
pTailList->next = pTemp; pTemp->next = NULL; pTailList = pTemp; pTemp = NULL; // the memory pointed by pTemp will be taken care by the linked list.
} wzTemp = szMultiStr + length; } } //NOTE:
// We are doing a trick here....in case of multi_reg_sz
//we are storing strings in a linked list pointed by g_pStrList
//they need to be freed by the caller
g_pStrList=pHeadList; //including 1 wide char '\0' for multi_sz end
} break;
default: ; }
End:
StrList* temp=NULL; if(retVal==E_OUTOFMEMORY) while(pHeadList!=NULL) { temp=pHeadList; if(pHeadList->Str) free(pHeadList->Str); pHeadList=pHeadList->next; free(temp); }
if(pTemp) { SAFE_FREE(pTemp->Str); free(pTemp); } if(szMultiStr) free(szMultiStr);
if(retVal!=ERROR_SUCCESS) return E_FAIL; else return ERROR_SUCCESS; }
/*--
PutProperty puts the property by using its classObject's handle. Incase you pass NULL in place of pvarVal, it does not put the property.
//NOTE:
// In case of MULTI_REG_SZ type
// caller stores linked list of strings and does not pass anything in variant
//the linked list 'g_pStrList' needs to be freed by the callee (here)
//the caller needs to remember this
--*/ HRESULT PutProperty(int nProperty, int nNumofprop, VARIANT* pvarVal) { HRESULT retVal=S_OK; CONST BYTE *lpData=NULL; DWORD cbData=0; DWORD dType; wchar_t* wzTemp=NULL; StrList* pTempList=NULL; int len=0;
if(g_arPROP[nProperty][nNumofprop].fDontput==1) goto End;
switch(V_VT(&g_arPROP[nProperty][nNumofprop].var)) { case VT_I4: lpData=(CONST BYTE *) &V_I4(pvarVal); cbData=sizeof(DWORD); dType=REG_DWORD; break; case VT_BSTR: if(V_BSTR(pvarVal)) { lpData=(CONST BYTE *)(wchar_t*)V_BSTR(pvarVal); cbData=(wcslen((wchar_t*)V_BSTR(pvarVal))+1)*sizeof(wchar_t); } else { lpData = NULL; cbData=0; } dType=REG_SZ; break;
case VT_ARRAY: //package passed in array into lpData well
dType=REG_MULTI_SZ;
//calculate the no. of bytes reqd.
pTempList = g_pStrList; while(pTempList!=NULL) { cbData += ((wcslen(pTempList->Str)+1)*sizeof(wchar_t)); pTempList = pTempList->next; } cbData += sizeof(wchar_t); //for extra '\0' in MULTI_SZ; Note: for blank entries, only one '\0' is reqd. so this is also OK.
if(NULL==(wzTemp=(wchar_t*)malloc(cbData))) { retVal=E_OUTOFMEMORY; goto End; }
while(g_pStrList!=NULL) { wcscpy(wzTemp+len,g_pStrList->Str); len+=wcslen(g_pStrList->Str)+1; pTempList=g_pStrList; g_pStrList=g_pStrList->next;
if(pTempList->Str) free(pTempList->Str); free(pTempList); }
// fill the last two bytes NULL , as required to terminate a MULTI_SZ
*(wzTemp+len) = L'\0'; lpData=(CONST BYTE*)wzTemp;
break;
default : { if(0==LoadString(g_hResource,IDS_E_UNEXPECTED,g_szMsg,MAX_BUFFER_SIZE)) return GetLastError(); MyWriteConsole(g_stdout,g_szMsg, wcslen(g_szMsg)); retVal= E_FAIL; goto End; } ; } if(lpData) { retVal=RegSetValueEx( g_arCLASShkey[g_arPROP[nProperty][nNumofprop].classname], // handle to key
g_arPROP[nProperty][nNumofprop].propname, // value name
0, // reserved
dType,// value type
lpData, // value data
cbData // size of value data
); if(FAILED(retVal)) { WCHAR *lpMsgBuf;
if (0 != FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, retVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPWSTR)&lpMsgBuf, 0, NULL )) { MyWriteConsole(g_stdout,lpMsgBuf, wcslen(lpMsgBuf)); LocalFree( lpMsgBuf ); } } goto End; }
End: if(wzTemp) free(wzTemp); return retVal; }
/*--
DupWStr takes a char string, and returns a wchar string. Note that it allocates the memory required for the wchar string, So we need to free it explicitly if after use.
if it has quotes surrounding it, then it is snipped off
--*/ wchar_t* DupWStr(char *szStr) { wchar_t* wzStr=NULL; char* szString=NULL;
if(szStr==NULL) return NULL;
int nLen=strlen(szStr); if(NULL==(szString=(char*)malloc((nLen+1)*sizeof(char)))) return NULL; if(szStr[0]!='"') strcpy(szString,szStr); else { int nPos; if(szStr[nLen-1]!='"') //ending double quotes not there.
nPos=1;//then no need to skip the last two. One is enough
else nPos=2; strcpy(szString,szStr+1); szString[nLen-nPos]='\0'; } nLen=MultiByteToWideChar(GetConsoleCP(),0,szString,-1,NULL,NULL); if (0 == nLen) { free(szString); return NULL; } wzStr=(wchar_t *) malloc(nLen*sizeof(wchar_t)); if(wzStr==NULL) { free(szString); return NULL; }
if (!MultiByteToWideChar(GetConsoleCP(), 0, szString, -1, wzStr, nLen )) { free(szString); free(wzStr); return NULL; }
if(szString) free(szString); return wzStr; }
/*--
DupCStr takes a wchar string, and returns a char string. Note that it allocates the memory required for the char string, So we need to free it explicitly if after use.
If memory allocation fails (or if input is NULL), it returns a NULL pointer. --*/ char* DupCStr(wchar_t *wzStr) { char* szStr=NULL;
if(wzStr==NULL) return NULL; int cbMultiByte = WideCharToMultiByte( GetACP(),NULL,wzStr,-1,szStr,0,NULL,NULL);
if (0 == cbMultiByte) { return NULL; } szStr = (char *) malloc(cbMultiByte);
if (NULL == szStr) { return NULL; }
cbMultiByte = WideCharToMultiByte( GetConsoleCP(),NULL,wzStr,-1,szStr, cbMultiByte,NULL,NULL);
if (0 == cbMultiByte) { free(szStr); szStr = NULL; }
return szStr; }
/*--
function(s) to resolve and check if the given machine is valid or not --*/
HRESULT IsValidMachine(wchar_t* wzCname , int *fValid) {
HRESULT hRes=S_OK; struct sockaddr_in addr; char * nodeName=NULL; int cbMultiByte; *fValid= 0;
wchar_t* wzName=NULL; if(wzCname==NULL) { *fValid=1; goto End; } else { if(NULL==(wzName=(wchar_t*)malloc((wcslen(wzCname)+1)*sizeof(wchar_t)))) { hRes=E_OUTOFMEMORY; goto End; } if(StrStrI(wzCname,L"\\")!=NULL) { wcscpy(wzName,wzCname+2); } else wcscpy(wzName,wzCname); }
cbMultiByte = WideCharToMultiByte( GetACP(),NULL,wzName,-1,nodeName, 0,NULL,NULL);
nodeName = (char *) malloc(cbMultiByte*sizeof(char)); if(!nodeName) { hRes=E_OUTOFMEMORY; goto End; } WideCharToMultiByte( GetConsoleCP(),NULL,wzName,-1,nodeName, cbMultiByte,NULL,NULL); if (Get_Inet_Address (&addr, nodeName)) *fValid = 1;
End: if(nodeName) free(nodeName); if(wzName) free(wzName); return hRes; }
BOOL Get_Inet_Address(struct sockaddr_in *addr, char *host) { register struct hostent *hp; WORD wVersionRequested; //INGR
WSADATA wsaData; //INGR
// Start up winsock
wVersionRequested = MAKEWORD( 1, 1 ); //INGR
if (WSAStartup(wVersionRequested, &wsaData) != 0) { //INGR
return (FALSE); }
// Get the address
memset(addr, 0, sizeof(*addr)); //bzero((TCHAR *)addr, sizeof *addr);
addr->sin_addr.s_addr = (u_long) inet_addr(host); if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) { if ((hp = gethostbyname(host)) == NULL) { return (FALSE); } memcpy(&addr->sin_addr,hp->h_addr, hp->h_length ); //bcopy(hp->h_addr, (TCHAR *)&addr->sin_addr, hp->h_length);
} addr->sin_family = AF_INET;
WSACleanup(); //INGR
return (TRUE); }
/*--
Function to get the Trusted Domains and then check if the given domain is one among them --*/
HRESULT IsValidDomain(wchar_t* wzDomainName, int *fValid) { HRESULT hRes = E_FAIL; TCHAR szName[MAX_PATH]; DWORD dwLen = sizeof(szName);
ZeroMemory(szName,sizeof(szName));
*fValid = 0; if(_wcsicmp(wzDomainName,L".")==0||_wcsicmp(wzDomainName,L"localhost")==0||_wcsicmp(wzDomainName,local_host)==0) { *fValid=1; return S_OK; } //If it's a local machine, g_arVALOF[_p_CNAME_] will be NULL. So pass "localhost".
if(FAILED(hRes=LoadNTDomainList(g_arVALOF[_p_CNAME_] ?g_arVALOF[_p_CNAME_] : SZLOCALMACHINE))) return hRes;
//compare given domain with all the domains in the list.
if(g_slNTDomains.count != 0) { DWORD i; for(i=0;i<g_slNTDomains.count;i++) { if(_wcsicmp(g_slNTDomains.strings[i],wzDomainName)==0) { *fValid=1; break; } } } return S_OK; }
/* This Function CheckForPassword() takes the password from the stdout after prompting for the same;
This function is called if the user name (Login name) is specified with out password */ HRESULT CheckForPassword(void) { HRESULT hRes=S_OK; HANDLE hStdin; DWORD fdwMode, fdwOldMode; if(g_arVALOF[_p_USER_]!=NULL&&NULL==g_arVALOF[_p_PASSWD_]) { //Password is not specified and hence go get it.
if(NULL==(g_arVALOF[_p_PASSWD_]=(wchar_t*)malloc(MAX_BUFFER_SIZE*sizeof(wchar_t)))) { hRes=E_OUTOFMEMORY; return hRes; }
int i; PrintMessage(g_stdout, IDR_PASSWD_PROMPT);
hStdin = GetStdHandle(STD_INPUT_HANDLE);
if (hStdin == INVALID_HANDLE_VALUE) goto ElsePart; if (GetConsoleMode(hStdin, &fdwOldMode)) { fdwMode = fdwOldMode & ~(ENABLE_ECHO_INPUT); if (! SetConsoleMode(hStdin, fdwMode)) goto ElsePart; if(NULL==fgetws(g_arVALOF[_p_PASSWD_],MAX_BUFFER_SIZE,stdin)) { hRes = E_FAIL; return hRes; } wchar_t *szLast = wcsrchr(g_arVALOF[_p_PASSWD_],L'\n'); if(szLast) { *szLast = L'\0'; } SetConsoleMode(hStdin, fdwOldMode); } else { // Here we get the password char by char(with echo off)
// and we can't support backspace and del chars here.
// this code will be executed only if we could not get/set
// the console of the user to ECHO_OFF
ElsePart: for(i=0;i<MAX_BUFFER_SIZE-1;i++) { g_arVALOF[_p_PASSWD_][i]=(wchar_t)_getch(); if(g_arVALOF[_p_PASSWD_][i]==L'\r'||g_arVALOF[_p_PASSWD_][i]==L'\n') break; } puts("\n\n"); g_arVALOF[_p_PASSWD_][i]=L'\0'; } } else if (NULL==g_arVALOF[_p_USER_]&&g_arVALOF[_p_PASSWD_]!=NULL) //Only password is specified hence error
{ hRes=E_FAIL; ShowError(IDS_E_LOGINNOTSPECIFIED); } return hRes; } void ConvertintoSeconds(int nProperty,int *nSeconds) {
int FirstTok=_wtoi(wcstok(g_arVALOF[nProperty],L":")); wchar_t* mins=wcstok(NULL,L":"); wchar_t* secs=wcstok(NULL,L":"); if(NULL == secs) { if(NULL == mins) { *nSeconds=FirstTok; return; } else { FirstTok*=60; FirstTok+=_wtoi(mins); *nSeconds=FirstTok; return; } } else { FirstTok*=60; FirstTok+=_wtoi(mins); FirstTok*=60; FirstTok+=_wtoi(secs); *nSeconds=FirstTok; return; } } void PrintFormattedErrorMessage(LONG LErrorCode) { WCHAR *lpMsgBuf;
if (0 != FormatMessageW( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, LErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPWSTR)&lpMsgBuf, 0, NULL )) { MyWriteConsole(g_stdout,lpMsgBuf, wcslen(lpMsgBuf)); LocalFree( lpMsgBuf ); } }
HRESULT getHostNameFromIP(char *szCname, WCHAR** wzCname) { struct hostent *hostinfo; WSADATA wsaData; u_long res; HRESULT hRes=S_OK; if (WSAStartup(MAKEWORD (1,1),&wsaData) != 0) { return E_FAIL; } if ((res = inet_addr ( szCname )) != INADDR_NONE ) { if ((hostinfo = gethostbyaddr ((char*) &res, sizeof(res),AF_INET)) == NULL) { // Handle error here
hRes=E_FAIL; goto End; } // At this point hostinfo->h_name contains host name in ASCII
// convert it to UNICODE before returning.
if(NULL == (*wzCname=DupWStr(hostinfo->h_name))) { hRes=E_OUTOFMEMORY; goto End; } } else { if(NULL == (*wzCname=DupWStr(szCname))) { hRes=E_OUTOFMEMORY; goto End; } } End: WSACleanup(); return hRes; }
HRESULT GetDomainHostedByThisMc( LPWSTR szDomain ) { OBJECT_ATTRIBUTES obj_attr = { 0 }; LSA_HANDLE policy; NTSTATUS nStatus = STATUS_SUCCESS; LSA_UNICODE_STRING szSystemName ; LSA_UNICODE_STRING *machine_to_open = NULL; WCHAR szName[MAX_PATH] = L""; USHORT dwLen = 0; WCHAR *wzCName=NULL; char *szCName=NULL; HRESULT hRes=S_OK; szSystemName.Buffer = NULL; int count; if( !szDomain ) { hRes=E_FAIL; goto GetDomainHostedByThisMcAbort; }
obj_attr.Length = sizeof(obj_attr); szDomain[0] = L'\0'; if(g_arVALOF[_p_CNAME_]) { // Whistler : LsaOpenPolicy fails due to build environment in whistler if the
// computer name is given in IP address format. Hence, we get the host name from
// the IP address, incase it is a Whistler build.
// This works fine for Garuda. In Future, make sure you remove this unnecessary
// work around.
#ifdef WHISTLER_BUILD
if(NULL == (szCName=DupCStr(g_arVALOF[_p_CNAME_]))) { hRes=E_OUTOFMEMORY; goto GetDomainHostedByThisMcAbort; }
if(S_OK != (hRes=getHostNameFromIP(szCName,&wzCName))) { goto GetDomainHostedByThisMcAbort; } #else
if(NULL==(wzCName=_wcsdup(g_arVALOF[_p_CNAME_]))) { hRes=E_OUTOFMEMORY; goto GetDomainHostedByThisMcAbort; } #endif
// dwLen is used to allocate memory to szSystemName.Buffer
dwLen = (USHORT)wcslen(g_arVALOF[_p_CNAME_]) + 1;
count = wcslen(wzCName);
//count CANNOT be zero- Grammar will not allow empty computer names!!
if(0==count) { hRes=IDS_E_INVALIDARG; goto GetDomainHostedByThisMcAbort; } if (((count > 1) && (wzCName[0] != L'\\' ) && (wzCName[1] != L'\\')) || (count==1)) { dwLen += (USHORT)wcslen(SLASH_SLASH); }
szSystemName.Buffer = (WCHAR *) malloc(dwLen*sizeof(WCHAR)); if(szSystemName.Buffer==NULL) { hRes=E_OUTOFMEMORY; goto GetDomainHostedByThisMcAbort; }
if (((count > 1) && (wzCName[0] != L'\\' ) && (wzCName[1] != L'\\'))|| (count==1)) { wcscpy(szSystemName.Buffer, SLASH_SLASH); //no overflow. Fixed length.
} else { szSystemName.Buffer[0]=L'\0'; }
szSystemName.MaximumLength = dwLen * sizeof(WCHAR); szSystemName.Length= szSystemName.MaximumLength - sizeof(WCHAR);
wcsncat(szSystemName.Buffer, wzCName, dwLen - 1 - wcslen(szSystemName.Buffer));
machine_to_open = &szSystemName; }
nStatus = LsaOpenPolicy( machine_to_open, &obj_attr, POLICY_VIEW_LOCAL_INFORMATION, &policy );
if (NT_SUCCESS(nStatus)) { POLICY_ACCOUNT_DOMAIN_INFO *info = NULL;
nStatus = LsaQueryInformationPolicy( policy, PolicyAccountDomainInformation, (PVOID *)&info );
if (NT_SUCCESS(nStatus)) { hRes = S_OK; wcscpy( szDomain, info->DomainName.Buffer ); LsaFreeMemory(info); }
LsaClose(policy); }
GetDomainHostedByThisMcAbort: if(wzCName) free(wzCName); if(szCName) free(szCName); if(szSystemName.Buffer) free(szSystemName.Buffer);
return hRes; }
BOOL CheckForInt(int nProperty) { char *szVal=NULL; BOOL fRet=FALSE; szVal = DupCStr(g_arVALOF[nProperty]); if(szVal) { if( atof(szVal) - _wtoi(g_arVALOF[nProperty]) ) fRet = FALSE; else fRet = TRUE; }
SAFE_FREE(szVal); return fRet; }
// This function changes the user specified Computer name into the IP address
// format and returns that. It also stores the specified name in the global
// variable g_szCName for future reference(in Printsettings()).
// This is needed if we want to convert the etc\hosts alias name into the IP
// address as they themselves will not get resolve in NetUseAdd().
// This function is called in this way in <fooadmin.y>
// g_arVALOF[_p_CNAME_]=CopyHostName(yytext)
// The above line replaces the call to DupWStr directly(FYI).
//
// WE HAVE DECIDED NOT TO FIX THIS (WINDOWS BUG 153111) AS IT SLOWS
// DOWN THE PERFORMANCE OF THE UTILS(It takes time to resolve--call
// to gethostbyname()
/*
// This will create the memory required and they need to be freed explicitly.
// Please free the memory allocated to g_szCName as well.
WCHAR *CopyHostName(CHAR *szCName) { // Inorder to print the name of the computer in the same way as the user specified
// we store that in a global variable and use the same in PrintSettings()
struct sockaddr_in addr; WCHAR *wzIPAddress=NULL;
g_szCName=DupWStr(szCName); if(Get_Inet_Address(&addr,szCName)) { wzIPAddress=DupWStr(inet_ntoa(addr.sin_addr)); }
return wzIPAddress; }
*/
// This function checks for the maximum integer and even
// pops up the appropriate error message
// This function takes the integer value in g_arVALOF[]
// char array and compares with TEXT_MAX_INTEGER_VALUE
// if exceeds bails out with the error
HRESULT CheckForMaxInt(WCHAR *wzValue,DWORD ErrorCode) { HRESULT hRes=S_OK;
UINT SpecIntLen = wcslen(wzValue); UINT MaxIntLen = wcslen(TEXT_MAX_INTEGER_VALUE);
// If the length of the value exceeds the max integer length =>
// clearly error
// else
// if same length, then strcmp will help in determining whether the value
// exceeds the max limit.
if(SpecIntLen > MaxIntLen) goto Error; else if ((SpecIntLen == MaxIntLen) && (wcscmp(wzValue,TEXT_MAX_INTEGER_VALUE)>0)) goto Error; else goto End; Error: hRes=E_FAIL; ShowError(ErrorCode); goto End; End: return hRes; }
// This function does a pre-analysis of the command line and copies the appropriate
// values into the global variable. This is for handling two cases.
// (1) To take care of DBCS chars that may appear in the command line. Since the
// actual lexical analyser can not handle DBCS and the we couldn't make use
// of the multi-byte conversion aptly (will result in two many special cases
// in lex specification), hence we are preprocessing the command line and
// eliminating the processing of DBCS in lex.
// (2) Some admintools, they take so complicated parameters that we can not put
// them into specification. The actual problem is that there are several such
// parameters and they can take any character theoritically.:(
// Arguments:
//
// (1) argc: Number of arguments in the command line.
// To make sure that we are exceeding the limits
// (2) argv: The actual command line parameters
// (3) nProperty: This is the index to where the "value" of the option
// is tobe stored.
// (4) option: This is the actual option (text string), we are trying to
// analyze and this guyz value should be store appropriately.
// (5) currentOp: This is an index to the current argument that is being
// analyzed.
// (6) nextOp: <OUT> This is an index to the next command line argument
// that needs to be taken care.
// (7) Success: <OUT> Flag which indicates whether we have done something
// to the command line parameters (did the option match)
// (8) IsSpaceAllowed: This is a flag to indicate whether the case (5)
// below as a valid scenario.
// This function returns ERROR_SUCCESS on Success
// else error is returned
DWORD PreAnalyzer(int argc, WCHAR *argv[], int nProperty, WCHAR *wzOption, int nCurrentOp, int *nNextOp, BOOL *fSuccess, BOOL IsSpaceAllowed ) { // *******************************************************************//
// These are the five ways in which the actual command line
// arguments can be specified.
//
// Case (1) : <option>=<value>
// Case (2) : <option>=space<value>
// Case (3) : <option>space=space<value>
// Case (4) : <option>space=<value>
// Case (5) : <option>space<value>
//
// We need to take care of all the five case while analyzing
// *******************************************************************//
DWORD nOptionStrLen = wcslen(wzOption); // buffer: This buffer stores the argv[i] and argv[i+1] (if exists)
// and used for processing the argument.
WCHAR wzBuffer[_MAX_PATH + 1];
DWORD nStartIndex,nRunIndex;
BOOL fEqualToFound = FALSE;
DWORD nRetVal = ERROR_SUCCESS;
DWORD nBufferLength;
DWORD dwSize;
*fSuccess = FALSE; // Initializing the next op to current op
*nNextOp=nCurrentOp;
// Check whether wzOption is the current op.
// if not return.
if(_wcsnicmp(wzOption,argv[nCurrentOp],nOptionStrLen)) goto End;
// Buffer is framed
wzBuffer[_MAX_PATH] = L'\0'; // Ensure NULL termination
wcsncpy(wzBuffer, argv[nCurrentOp], _MAX_PATH);
if(argc>nCurrentOp+1) { // We have one more command line argument (i+1)
// so concat it to the buffer
INT used_up_length = wcslen(wzBuffer);
_snwprintf( wzBuffer + used_up_length, _MAX_PATH - used_up_length, L" %s", argv[nCurrentOp+1] ); }
nBufferLength = wcslen(wzBuffer); nStartIndex = nOptionStrLen;
nRunIndex = nStartIndex;
// Skip space and any "=" sign inbetween
while((nRunIndex < nStartIndex + 3 ) && (nRunIndex < nBufferLength)) { if(L'=' == wzBuffer[nRunIndex]) { if(fEqualToFound) break; else { fEqualToFound = TRUE; nRunIndex++; continue; } } else if(L' ' == wzBuffer[nRunIndex]) { nRunIndex++; continue; } else break; }
// Filter missing value for the option
if(nRunIndex>=nBufferLength) { if(nRunIndex == nOptionStrLen + 2) { // Case (3)
// Check whether the option is missing.
if(NULL == argv[nCurrentOp+2]) { nRetVal=E_FAIL; goto End; } else // Increment nRunIndex to point to next valid input
nRunIndex++; } else { // Missing value for (1),(2),(4) and (5)
nRetVal = E_FAIL; goto End; } }
// If no "=" is present and also space is not allowed
// as a valid scenario, then invalid according to usage
if((!fEqualToFound)&&(!IsSpaceAllowed)) { nRetVal = IDR_TELNET_CONTROL_VALUES; goto End; }
// Now we expect the actual value of the option at the nRunIndex.
// So, based on the value of nRunIndex, we can say which argv[]
// has the value and can take any actions if required.
switch(nRunIndex - nStartIndex) { case 1: // Falls under Cases (1) or (5) as stated above
if(L'=' == wzBuffer[nOptionStrLen]) { // Clearly case (1)
if(NULL == (g_arVALOF[nProperty] = _wcsdup(argv[nCurrentOp]+nOptionStrLen+1))) { nRetVal = IDS_E_OUTOFMEMORY;// Error
ShowError(IDS_E_OUTOFMEMORY); goto End; } *nNextOp = nCurrentOp ; *fSuccess = TRUE; } else { // case (5)
if(NULL == (g_arVALOF[nProperty] = _wcsdup(argv[nCurrentOp+1]))) { nRetVal = IDS_E_OUTOFMEMORY;// Error
ShowError(IDS_E_OUTOFMEMORY); goto End; } *nNextOp = nCurrentOp + 1; *fSuccess = TRUE; } break; case 2: // Falls under Cases (2) and (4)
if(L'=' == argv[nCurrentOp+1][0]) { // Case (4)
// Skip the "=" and then copy.
if(NULL == (g_arVALOF[nProperty] = _wcsdup(argv[nCurrentOp+1]+1))) { nRetVal = IDS_E_OUTOFMEMORY;// Error
ShowError(IDS_E_OUTOFMEMORY); goto End; } *nNextOp = nCurrentOp + 1; *fSuccess = TRUE; } else { // Case (2)
if(NULL == (g_arVALOF[nProperty] = _wcsdup(argv[nCurrentOp+1]))) { nRetVal = IDS_E_OUTOFMEMORY;// Error
ShowError(IDS_E_OUTOFMEMORY); goto End; } *nNextOp = nCurrentOp + 1; *fSuccess = TRUE; } break; case 3: // Falls under case (3)
if (NULL == (g_arVALOF[nProperty] = _wcsdup(argv[nCurrentOp+2]))) { nRetVal = IDS_E_OUTOFMEMORY;// Error
ShowError(IDS_E_OUTOFMEMORY); goto End; } *nNextOp = nCurrentOp + 2; *fSuccess = TRUE; break;
case 0: // Something unexpected encountered
// Give it to the actual analyzer for analyzis.
*nNextOp = nCurrentOp; break; }
if(ERROR_SUCCESS == nRetVal) { if(NULL==g_arVALOF[nProperty]) { nRetVal = E_FAIL; goto End; } } End: return nRetVal; }
// This function will print the missing registry value information
// Why didn't we add the following string to Cladmin.rc? The reasons are
// (1) We don't want to get Whistler and Garuda Telnet out of sync
// (2) This code should NEVER get executed and it is only for the
// the instrumentation. We can remove this before shipping.
#define IDS_E_MISSING_REGVALUE L"The registry value '%s' is missing.\n"
DWORD PrintMissingRegValueMsg(int nProperty, int nNumofprop) { WCHAR szRegValue[_MAX_PATH + 1];
wcsncpy(g_szMsg, IDS_E_MISSING_REGVALUE, ARRAYSIZE(g_szMsg)-1); g_szMsg[ARRAYSIZE(g_szMsg)-1]=L'\0';
_snwprintf( szRegValue, _MAX_PATH, L"%s\\%s", g_arCLASSname[g_arPROP[nProperty][nNumofprop].classname], g_arPROP[nProperty][nNumofprop].propname);
szRegValue[_MAX_PATH] = L'\0'; // ensure NULL termination
fwprintf(stdout, g_szMsg, szRegValue );
return S_OK; } void HelperFreeStringList(PSTRING_LIST pList) { if(pList && pList->count && pList->strings) { DWORD i;
for(i=0; i < pList->count; ++i) { if(pList->strings[i]) delete [] pList->strings[i]; }
delete pList->strings;
pList->count = 0; pList->strings = NULL; } }
HRESULT LoadNTDomainList(LPTSTR szMachine) { HRESULT hRes = S_OK; int dwSize=0, dwType=0; DWORD nIndex = 0; LPTSTR lpComputer = NULL, lpDomains = NULL, lpPrimary = NULL; LPBYTE lpBuffer = NULL;
//MessageBoxW(NULL, (LPWSTR)L"LoadNTDomainList", L"LoadNTDomainList1", MB_OK);
//
// Add all trusted domains to the list
//
dwSize = GetTrustedDomainList(szMachine,&lpDomains, &lpPrimary);
//
// free previous values
//
HelperFreeStringList(&g_slNTDomains); //
// initialize list again
//
g_slNTDomains.count = 0; //
// two for primary domain
// and this computer
// one more in case dwSize is -1
// hence total is 3
//
g_slNTDomains.strings = new LPTSTR[dwSize + 3]; ATLASSERT(g_slNTDomains.strings != NULL); if(NULL==g_slNTDomains.strings) { ShowError(IDS_E_OUTOFMEMORY); hRes = E_OUTOFMEMORY; goto Done; } ZeroMemory(g_slNTDomains.strings, (dwSize + 3)*sizeof(LPTSTR));
if((dwSize > 0) && lpDomains) { LPTSTR ptr = lpDomains; //
// add domains to our list
//
while(*ptr) { ptr = _tcsupr(ptr); g_slNTDomains.strings[g_slNTDomains.count] = new TCHAR[_tcslen(ptr) + 1]; ATLASSERT(g_slNTDomains.strings[g_slNTDomains.count] != NULL); ZeroMemory(g_slNTDomains.strings[g_slNTDomains.count], (_tcslen(ptr) + 1)*sizeof(TCHAR)); _tcscpy(g_slNTDomains.strings[g_slNTDomains.count], ptr); ptr += _tcslen(ptr) + 1; g_slNTDomains.count++; } delete [] lpDomains; lpDomains = NULL; }
if(lpPrimary && *lpPrimary) { lpPrimary = _tcsupr(lpPrimary);
for(nIndex=0;nIndex<g_slNTDomains.count;nIndex++) { if(!_tcsicmp(lpPrimary, g_slNTDomains.strings[nIndex])) break; }
if(nIndex == g_slNTDomains.count) { //
// lpPrimary was not in the list of domains that we
// got. add it.
//
g_slNTDomains.strings[g_slNTDomains.count] = new TCHAR[_tcslen(lpPrimary) + 1]; ATLASSERT(g_slNTDomains.strings[g_slNTDomains.count] != NULL); ZeroMemory(g_slNTDomains.strings[g_slNTDomains.count], (_tcslen(lpPrimary) + 1)*sizeof(TCHAR)); _tcscpy(g_slNTDomains.strings[g_slNTDomains.count], lpPrimary); g_slNTDomains.count++; } }
//
// Add our computer to be selected if this machine is not the
// domain controler (which should already be in the list)
//
//Pass NULL if local machine. Else machine name.
NetServerGetInfo(_wcsicmp(szMachine,SZLOCALMACHINE) ? szMachine : NULL, 101, &lpBuffer); if(lpBuffer && ((LPSERVER_INFO_101)lpBuffer)->sv101_type & ((DWORD)SV_TYPE_DOMAIN_CTRL | (DWORD)SV_TYPE_DOMAIN_BAKCTRL)) { /*
we got this computer as one of the domains. no need to add it to the list again. just do nothing. */ ; } else { TCHAR szName[MAX_PATH + 2]; ZeroMemory(szName, sizeof(szName)); DWORD dwLen = sizeof(szName); //if it's not a local machine, keep it as it is. Else make it \\localhost.
if (_tcsicmp(szMachine,SZLOCALMACHINE)) { if( _tcslen(szMachine) > (MAX_PATH - 2) ) goto Done;
if (_tcsncmp(szMachine,L"\\\\",2)) _tcscpy(szName,L"\\\\"); _tcscat(szName,szMachine); _tcsupr(szName); } else if(GetComputerName(szName + 2, &dwLen)) { szName[0] = TEXT('\\'); szName[1] = TEXT('\\'); } else goto Done;
//
// add this also to our list of domains
//
g_slNTDomains.strings[g_slNTDomains.count] = new TCHAR[_tcslen(szName) + 1]; ATLASSERT(g_slNTDomains.strings[g_slNTDomains.count] != NULL); ZeroMemory(g_slNTDomains.strings[g_slNTDomains.count], (_tcslen(szName) + 1)*sizeof(TCHAR)); _tcscpy(g_slNTDomains.strings[g_slNTDomains.count], szName); g_slNTDomains.count++; }
Done: if(lpBuffer) { NetApiBufferFree(lpBuffer); }
if(lpPrimary) { delete [] lpPrimary; }
return hRes; }
int GetTrustedDomainList(LPTSTR szMachine, LPTSTR * list, LPTSTR * primary) { //BOOL stat = TRUE;
DWORD ret=0, size=0, type=0; LPTSTR cache = NULL, trusted = NULL; HKEY hKey=NULL; CRegKey key; HKEY hKeyRemoteRegistry = NULL;
STRING_LIST slValues = {0, NULL}; *list = NULL;
if (FAILED(RegConnectRegistry(_wcsicmp(szMachine,SZLOCALMACHINE) ? szMachine : NULL, HKEY_LOCAL_MACHINE, &hKeyRemoteRegistry))) { goto ABORT; }
if(key.Open(hKeyRemoteRegistry, WINLOGONNT_KEY) == ERROR_SUCCESS) { size = 0; if(key.QueryValue(*primary, CACHEPRIMARYDOMAIN_VALUE, &size) == ERROR_SUCCESS) { *primary = new TCHAR[size+1]; ATLASSERT(primary != NULL);
if(*primary) { ZeroMemory(*primary, (size+1)*sizeof(TCHAR));
if(key.QueryValue(*primary, CACHEPRIMARYDOMAIN_VALUE, &size) != ERROR_SUCCESS) { goto ABORT; } else { key.Close(); // don't quit. we have to get the list of trusted domains also.
} } } else { key.Close(); goto ABORT; } } else { goto ABORT; }
//
// Get trusted domains. In NT40 the CacheTrustedDomains
// under winlogon doesn't exist. I did find that Netlogon has a field
// called TrustedDomainList which seems to be there in both NT351 and NT40.
// Winlogon has a field called DCache which seem to cache the trusted
// domains. I'm going to check Netlogon:TrustedDomainList first. If it
// fails: Check for Winlogon:CacheTrustedDomains then Winlogon:DCache.
// Warning -- Winlogon:CacheTrustedDomains is a REG_SZ and
// Netlogon:TrustedDomainList and Winlogon:DCache are REG_MULTI_SZ.
// Note -- see 4.0 Resource Kit documentation regarding some of these
// values
//
if(key.Open(hKeyRemoteRegistry, NETLOGONPARAMETERS_KEY) == ERROR_SUCCESS) { size = 0;
if(key.QueryValue(trusted, TRUSTEDDOMAINLIST_VALUE, &size) == ERROR_SUCCESS) { trusted = new TCHAR[size + 1]; ATLASSERT(trusted != NULL);
if(trusted) { ZeroMemory(trusted, (size+1)*sizeof(TCHAR)); if(key.QueryValue(trusted, TRUSTEDDOMAINLIST_VALUE, &size) != ERROR_SUCCESS) { key.Close(); delete [] trusted; trusted = NULL; *list = NULL; //goto ABORT;
} else { *list = trusted; key.Close(); } } else { key.Close(); goto ABORT; } } else { key.Close(); *list = NULL; } } if(!(*list) && (key.Open(hKeyRemoteRegistry, WINLOGONNT_KEY) == ERROR_SUCCESS)) { size = 0;
if(key.QueryValue(cache, CACHETRUSTEDDOMAINS_VALUE, &size) == ERROR_SUCCESS) { cache = new TCHAR[size + 1]; ATLASSERT(cache != NULL);
if(cache) { ZeroMemory(cache, size);
if(key.QueryValue(cache, CACHETRUSTEDDOMAINS_VALUE, &size) == ERROR_SUCCESS) { //
// comma separated list
//
LPTSTR lpComma = NULL; LPTSTR lpDelim = TEXT(",");
lpComma = _tcstok(cache, lpDelim);
while(lpComma) { lpComma = _tcstok(NULL, lpDelim); } *list = cache; } else { key.Close(); delete [] cache; cache = NULL; *list = NULL; } } else { key.Close(); goto ABORT; } } else { *list = NULL; key.Close(); } } if(!(*list) && (key.Open(hKeyRemoteRegistry, WINLOGONNT_KEY) == ERROR_SUCCESS)) { size = 0;
if(key.QueryValue(trusted, DCACHE_VALUE, &size) == ERROR_SUCCESS) { trusted = new TCHAR[size + 1]; ATLASSERT(trusted != NULL);
if(trusted) { if(key.QueryValue(trusted, DCACHE_VALUE, &size) == ERROR_SUCCESS) { *list = trusted; } else { key.Close(); delete [] trusted; trusted = NULL; *list = NULL; } } else { key.Close(); goto ABORT; } } else { key.Close(); *list = NULL; } }
// VikasT
// Apparantely, on NT5 DCache doesn't exist. I found that there is a key
// under Winlogon named DomainCache that has all the cached domains.
// So, lets get that
//
//if(!(*list) && (RegOpenkeyEx(hKeyRemoteRegistry, DOMAINCACHE_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS))
//if(!(*list) && (RegOpenkey(hKeyRemoteRegistry, DOMAINCACHE_KEY, &hKey) == ERROR_SUCCESS))
if(!(*list) && (key.Open(hKeyRemoteRegistry, DOMAINCACHE_KEY) == ERROR_SUCCESS)) { size = 0; TCHAR * pszTemp = NULL; TCHAR szTemp[MAX_PATH]; DWORD dwNumberOfValues = 0; DWORD dwIndex = 0; DWORD dwCharCount = MAX_PATH; HRESULT hrResult = ERROR_SUCCESS;
hKey = HKEY(key); //
// first find out how many values are present
//
hrResult = RegQueryInfoKey( hKey, //handle of key to query
NULL, // address of buffer for class string
NULL, // address of size of class string buffer
NULL, // reserved
NULL, // address of buffer for number of subkeys
NULL, // address of buffer for longest subkey name length
NULL, // address of buffer for longest class string length
&dwNumberOfValues, // address of buffer for number of value entries
NULL, // address of buffer for longest value name length
NULL, // address of buffer for longest value data length
NULL, // address of buffer for security descriptor length
NULL // address of buffer for last write time
); if(hrResult != ERROR_SUCCESS) goto ABORT;
slValues.count = dwNumberOfValues; slValues.strings = new LPTSTR[slValues.count]; ATLASSERT(slValues.strings != NULL); if(slValues.strings == NULL) goto ABORT;
ZeroMemory(slValues.strings, slValues.count * sizeof(LPTSTR));
for(dwIndex = 0;dwIndex<dwNumberOfValues;dwIndex++) { dwCharCount = MAX_PATH;
if(RegEnumValue(hKey, dwIndex, szTemp, &dwCharCount, NULL, NULL, NULL, NULL) == ERROR_NO_MORE_ITEMS) break; slValues.strings[dwIndex] = new TCHAR[dwCharCount+1]; ATLASSERT(slValues.strings[dwIndex] != NULL); if(slValues.strings[dwIndex] == NULL) goto ABORT; ZeroMemory(slValues.strings[dwIndex], (dwCharCount+1) * sizeof(TCHAR)); _tcscpy(slValues.strings[dwIndex], szTemp); // add up the return buffer size
size += dwCharCount+1; }
if(dwNumberOfValues > 0) { trusted = new TCHAR[size + 1]; ATLASSERT(trusted != NULL); if( trusted == NULL ) { goto ABORT; }
ZeroMemory(trusted, (size+1)*sizeof(TCHAR)); pszTemp = trusted; for(dwIndex = 0;dwIndex<slValues.count;dwIndex++) { _tcscpy(pszTemp, slValues.strings[dwIndex]); pszTemp += _tcslen(slValues.strings[dwIndex]) + 1; } } *list = trusted; size = dwNumberOfValues; }
goto Done;
ABORT: // set the return value;
size = (DWORD)-1; if(*primary != NULL) { delete [] *primary; *primary = NULL; }
if(trusted != NULL) { delete [] trusted; trusted = NULL; }
if(cache != NULL) { delete [] cache; cache = NULL; }
Done: if (hKeyRemoteRegistry != NULL) { RegCloseKey(hKeyRemoteRegistry); hKeyRemoteRegistry = NULL; }
if(hKey != NULL) { RegCloseKey(hKey); hKey = NULL; key.m_hKey = NULL; }
HelperFreeStringList(&slValues);
return size; }
/*
Description: This function will try to load the string from XPSP1RES.DLL if the dll is present. Else it will try to load from the normal resource dll. If that fails, it will copy the English string into the destination buffer Parameters: [in] Message ID of the resource string to be loaded. [out] Destination string. [in] Maximum size of destination buffer. [in] English string to be copied if everything else fails Return value: Number of TCHARs. */ int TnLoadString(int msg_id, LPTSTR string, int max_size_of_buffer, LPCTSTR english_string) { int retval = 0;
//try loading from cladmin.dll or the image itself
if(g_hResource) { retval = LoadString(g_hResource,msg_id,string,max_size_of_buffer); if(retval != 0) goto Done; //Resource string loaded from the cladmin.dll or image.
} //Try loading from XP Res dll only if the OS version is XP
if(g_hXPResource) { retval = LoadString(g_hXPResource,msg_id,string,max_size_of_buffer); if(retval != 0) goto Done; //Resource string loaded from xpsp1res.dll
} //Everything failed. Copy the English string and set retval to number of characters
//in English string
_tcsncpy(string,english_string,max_size_of_buffer-1); string[max_size_of_buffer-1] = _T('\0'); retval = _tcslen(english_string); Done: return retval; }
|