//--------------------------------------------------------- // Copyright (c) 1999-2000 Microsoft Corporation // // utilfunctions.cpp // // vikram K.R.C. (vikram_krc@bigfoot.com) // // Some generic functions to do command line administration // (May-2000) //--------------------------------------------------------- #include #include #include #include #include "resource.h" //resource.h should be before any other .h file that has resource ids. #include "admutils.h" #include "common.h" #include #include #include #include #include #include #include #include //for #define DNS_MAX_NAME_BUFFER_LENGTH 256 #include #include #include "sfucom.h" #include #include #include #include #include #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<= 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;ih_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 // 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: This is an index to the next command line argument // that needs to be taken care. // (7) Success: 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) :