Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2906 lines
80 KiB

  1. //---------------------------------------------------------
  2. // Copyright (c) 1999-2000 Microsoft Corporation
  3. //
  4. // utilfunctions.cpp
  5. //
  6. // vikram K.R.C. ([email protected])
  7. //
  8. // Some generic functions to do command line administration
  9. // (May-2000)
  10. //---------------------------------------------------------
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <ntlsa.h>
  15. #include "resource.h" //resource.h should be before any other .h file that has resource ids.
  16. #include "admutils.h"
  17. #include "common.h"
  18. #include <stdio.h>
  19. #include <stdarg.h>
  20. #include <shlwapi.h>
  21. #include <tchar.h>
  22. #include <assert.h>
  23. #include <conio.h>
  24. #include <winsock.h>
  25. #include <windns.h> //for #define DNS_MAX_NAME_BUFFER_LENGTH 256
  26. #include <Lmuse.h>
  27. #include <Lm.h>
  28. #include "sfucom.h"
  29. #include <lm.h>
  30. #include <commctrl.h>
  31. #include <OleAuto.h >
  32. #include <string.h>
  33. #include <stdlib.h>
  34. #include "atlbase.h"
  35. #define WINLOGONNT_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon")
  36. #define NETLOGONPARAMETERS_KEY TEXT("System\\CurrentControlSet\\Services\\Netlogon\\Parameters")
  37. #define TRUSTEDDOMAINLIST_VALUE TEXT("TrustedDomainList")
  38. #define CACHEPRIMARYDOMAIN_VALUE TEXT("CachePrimaryDomain")
  39. #define CACHETRUSTEDDOMAINS_VALUE TEXT("CacheTrustedDomains")
  40. #define DOMAINCACHE_KEY TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\DomainCache")
  41. #define DCACHE_VALUE TEXT("DCache")
  42. #define WINLOGONNT_DCACHE_KEY TEXT("DCache")
  43. //FOR USING THE CLIGRPENUM INTERFACE...(it is used in the function
  44. //IsValidDomain)
  45. //the following are hash defined in the CligrpEnum.cpp file.
  46. #define GROUP 1
  47. #define MEMBER 2
  48. #define NTDOMAIN 3
  49. #define MACHINE 4
  50. //Globals
  51. BSTR bstrLogin=NULL;
  52. BSTR bstrPasswd=NULL;
  53. BSTR bstrNameSpc= NULL;
  54. SC_HANDLE g_hServiceManager=NULL;
  55. SC_HANDLE g_hServiceHandle=NULL;
  56. SERVICE_STATUS g_hServiceStatus;
  57. WCHAR *local_host = L"\\\\localhost";
  58. BOOL g_fNetConnectionExists = FALSE;
  59. STRING_LIST g_slNTDomains;
  60. //externs
  61. //from tnadmutl.cpp
  62. extern wchar_t* g_arCLASSname[_MAX_CLASS_NAMES_];
  63. //the hive names....
  64. extern int g_arNUM_PROPNAME[_MAX_PROPS_];
  65. //Number of properties in the registry each one corresponds to.
  66. extern HKEY g_hkeyHKLM;
  67. //to store the handle to the registry.
  68. extern HKEY g_arCLASShkey[_MAX_CLASS_NAMES_];
  69. //array to hold the handles to the keys of the class hives.
  70. extern WCHAR g_szMsg[MAX_BUFFER_SIZE] ;
  71. //array to store the string loaded.
  72. extern HMODULE g_hResource;
  73. //handle to the strings library.
  74. HMODULE g_hXPResource;
  75. //handle to the XPSP1 strings library.
  76. extern HANDLE g_stdout;
  77. StrList* g_pStrList=NULL;
  78. #ifdef __cplusplus
  79. extern "C" {
  80. #endif
  81. //Global Variables...
  82. //externs from nfsadmin.y file.
  83. extern int g_nError;
  84. // the error flag, 1 error, 0 no error.
  85. extern int g_nPrimaryOption;
  86. //_tSERVER, _tCLIENT, _tGW or _tHELP
  87. extern int g_nSecondaryOption;
  88. //Start,Stop,Config,etc kind of things.
  89. extern int g_nTertiaryOption;
  90. extern int g_nConfigOptions;
  91. //the Config Options.
  92. extern ConfigProperty g_arPROP[_MAX_PROPS_][_MAX_NUMOF_PROPNAMES_];
  93. extern wchar_t* g_arVALOF[_MAX_PROPS_];
  94. //the given values of properties in the command line
  95. #ifdef __cplusplus
  96. }
  97. #endif
  98. BOOL g_fCoInitSuccess = FALSE;
  99. /*
  100. * wzName should not be NULL. (Caller's responsibility)
  101. */
  102. HRESULT DoNetUseGetInfo(WCHAR *wzName, BOOL *fConnectionExists)
  103. {
  104. HRESULT hRes=S_OK;
  105. WCHAR wzResource[DNS_MAX_NAME_BUFFER_LENGTH+1];
  106. USE_INFO_0 *pUseInfo0;
  107. API_RET_TYPE uReturnCode; // API return code
  108. *fConnectionExists = FALSE;
  109. if (NULL == wzName)
  110. {
  111. return E_FAIL;
  112. }
  113. _snwprintf(wzResource,DNS_MAX_NAME_BUFFER_LENGTH, L"%s\\ipc$", wzName);
  114. wzResource[DNS_MAX_NAME_BUFFER_LENGTH] = L'\0'; // Ensure NULL termination
  115. uReturnCode=NetUseGetInfo(NULL,
  116. wzResource,
  117. 0,
  118. (LPBYTE *)&pUseInfo0);
  119. if(NERR_Success != uReturnCode)
  120. {
  121. // If no network connection exists, return S_OK as it
  122. // is not an error for us.
  123. if(ERROR_NOT_CONNECTED == uReturnCode)
  124. goto End;
  125. PrintFormattedErrorMessage(uReturnCode);
  126. hRes=E_FAIL;
  127. }
  128. else
  129. {
  130. // Debug Messages
  131. /*
  132. wprintf(L" Local device : %s\n", pUseInfo0->ui0_local);
  133. wprintf(L" Remote device : %Fs\n", pUseInfo0->ui0_remote);
  134. */
  135. // NetUseGetInfo function allocates memory for the buffer
  136. // Hence need to free the same.
  137. NetApiBufferFree(pUseInfo0);
  138. *fConnectionExists = TRUE;
  139. }
  140. End:
  141. return hRes;
  142. }
  143. HRESULT DoNetUseAdd(WCHAR* wzLoginname, WCHAR* wzPassword,WCHAR* wzCname)
  144. {
  145. HRESULT hRes=S_OK;
  146. USE_INFO_2 ui2Info;
  147. DWORD dw=-1;
  148. WCHAR* wzName=NULL;
  149. int fValid=0;
  150. int retVal=0;
  151. char szHostName[DNS_MAX_NAME_BUFFER_LENGTH];
  152. int count;
  153. WCHAR* wzTemp=NULL;
  154. WCHAR szTemp[MAX_BUFFER_SIZE];
  155. ui2Info.ui2_local=NULL;
  156. ui2Info.ui2_remote=NULL;
  157. if(wzCname!=NULL &&
  158. _wcsicmp(wzCname, L"localhost") &&
  159. _wcsicmp(wzCname, local_host)
  160. )
  161. {
  162. //Validate the MACHINE
  163. if(FAILED(hRes=IsValidMachine(wzCname, &fValid)))
  164. return hRes;
  165. else if(!fValid)
  166. {
  167. if(0==LoadString(g_hResource,IDR_MACHINE_NOT_AVAILABLE,szTemp,MAX_BUFFER_SIZE))
  168. return GetLastError();
  169. _snwprintf(g_szMsg, MAX_BUFFER_SIZE -1, szTemp,wzCname);
  170. MyWriteConsole(g_stdout, g_szMsg, wcslen(g_szMsg));
  171. hRes= E_FAIL;
  172. goto End;
  173. }
  174. //format properly
  175. if((wzName=(wchar_t*)malloc((3+wcslen(wzCname))*sizeof(wchar_t)))==NULL)
  176. return E_OUTOFMEMORY;
  177. if(NULL==StrStrI(wzCname,L"\\\\"))
  178. {
  179. wcscpy(wzName,L"\\\\");
  180. wcscat(wzName,wzCname);
  181. }
  182. else if(wzCname==StrStrI(wzCname,L"\\\\"))
  183. wcscpy(wzName,wzCname);
  184. else
  185. {
  186. hRes=E_INVALIDARG;
  187. goto End;
  188. }
  189. // See whether a network connection already exists for
  190. // resource ipc$.
  191. if(FAILED(hRes = DoNetUseGetInfo(wzName, &g_fNetConnectionExists)))
  192. goto End;
  193. // Network Connection already exists.
  194. if(g_fNetConnectionExists)
  195. goto End;
  196. }
  197. else if(NULL==wzLoginname)
  198. goto End;
  199. else //We should send the localhost's name in absolute terms ...otherwise it gives error "duplicate name exists"
  200. {
  201. WORD wVersionRequested; //INGR
  202. WSADATA wsaData; //INGR
  203. // Start up winsock
  204. wVersionRequested = MAKEWORD( 1, 1 ); //INGR
  205. if (0==WSAStartup(wVersionRequested, &wsaData))
  206. { //INGR
  207. if(SOCKET_ERROR!=(gethostname(szHostName,DNS_MAX_NAME_BUFFER_LENGTH)))
  208. {
  209. if((wzName=(WCHAR *)malloc((3+strlen(szHostName))*sizeof(WCHAR)))==NULL)
  210. return E_OUTOFMEMORY;
  211. wcscpy(wzName,L"\\\\");
  212. if(NULL==(wzTemp=DupWStr(szHostName)))
  213. {
  214. free(wzName);
  215. return E_OUTOFMEMORY;
  216. }
  217. wzName=wcscat(wzName,wzTemp);
  218. free(wzTemp);
  219. }
  220. else
  221. {
  222. hRes = GetLastError();
  223. g_nError = hRes;
  224. PrintFormattedErrorMessage(hRes);
  225. goto End;
  226. }
  227. WSACleanup(); //INGR
  228. }
  229. else
  230. wzName=local_host;
  231. }
  232. count = (7 + wcslen(wzName)); // name + \ipc$
  233. ui2Info.ui2_remote=(wchar_t*)malloc(count * sizeof(wchar_t));
  234. if(NULL==ui2Info.ui2_remote)
  235. {
  236. hRes=E_OUTOFMEMORY;
  237. goto End;
  238. }
  239. _snwprintf(ui2Info.ui2_remote, count, L"%s\\ipc$", wzName); // calculated size, no risks
  240. ui2Info.ui2_password=wzPassword;
  241. ui2Info.ui2_asg_type=USE_IPC;
  242. if(NULL==wzLoginname)
  243. {
  244. ui2Info.ui2_username=NULL;
  245. ui2Info.ui2_domainname=NULL;
  246. }
  247. else if(NULL==StrStrI(wzLoginname,L"\\"))
  248. {
  249. ui2Info.ui2_username=wzLoginname;
  250. ui2Info.ui2_domainname=NULL;
  251. }
  252. else
  253. {
  254. wzTemp=ui2Info.ui2_username=_wcsdup(wzLoginname);
  255. if(NULL==wzTemp)
  256. {
  257. hRes=E_OUTOFMEMORY;
  258. goto End;
  259. }
  260. ui2Info.ui2_domainname=wcstok(wzTemp,L"\\");
  261. ui2Info.ui2_username=wcstok(NULL,L"\\");
  262. }
  263. NET_API_STATUS nError;
  264. nError = NetUseAdd(NULL, 2, (LPBYTE) &ui2Info, &dw);
  265. if (NERR_Success != nError)
  266. {
  267. LPVOID lpMsgBuf;
  268. FormatMessage(
  269. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  270. FORMAT_MESSAGE_FROM_SYSTEM |
  271. FORMAT_MESSAGE_IGNORE_INSERTS,
  272. NULL,
  273. nError,
  274. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),// Default language
  275. (LPTSTR) &lpMsgBuf,
  276. 0,
  277. NULL);
  278. _tprintf(L"\n%s\n",(LPCTSTR)lpMsgBuf);
  279. LocalFree( lpMsgBuf );
  280. hRes=E_FAIL; // To return E_FAIL from the function
  281. goto End;
  282. }
  283. End:
  284. if(wzName && (wzName != local_host))
  285. free(wzName);
  286. if(ui2Info.ui2_remote)
  287. free(ui2Info.ui2_remote);
  288. return hRes;
  289. }
  290. HRESULT DoNetUseDel(WCHAR* wzCname)
  291. {
  292. HRESULT hRes=S_OK;
  293. int retVal=-1;
  294. WCHAR wzName[DNS_MAX_NAME_BUFFER_LENGTH+1] = { 0 };
  295. int nWritten = 0;
  296. // The network connection was there before invoking the admin tool
  297. // So, don't delete it
  298. if(g_fNetConnectionExists)
  299. goto End;
  300. if(NULL!=wzCname &&
  301. _wcsicmp(wzCname, L"localhost") &&
  302. _wcsicmp(wzCname, local_host)
  303. )
  304. {
  305. if(NULL==StrStrI(wzCname,L"\\\\"))
  306. {
  307. nWritten = _snwprintf(wzName, ARRAYSIZE(wzName) - 1, L"\\\\%s", wzCname);
  308. if (nWritten < 0)
  309. {
  310. hRes=E_INVALIDARG;
  311. goto End;
  312. }
  313. }
  314. else if(wzCname==StrStrI(g_arVALOF[_p_CNAME_],L"\\\\"))
  315. {
  316. wcsncpy(wzName, wzCname, (ARRAYSIZE(wzName) - 1));
  317. wzName[(ARRAYSIZE(wzName) - 1)] = 0;
  318. nWritten = wcslen(wzName);
  319. }
  320. else
  321. {
  322. hRes=E_INVALIDARG;
  323. goto End;
  324. }
  325. wcsncpy(wzName+nWritten, L"\\ipc$", (ARRAYSIZE(wzName) - 1 - nWritten));
  326. wzName[ARRAYSIZE(wzName)-1] = L'\0';
  327. retVal=NetUseDel( NULL,
  328. wzName,
  329. USE_LOTS_OF_FORCE
  330. );
  331. if(retVal!=NERR_Success)
  332. {
  333. hRes=retVal;
  334. goto End;
  335. }
  336. }
  337. End:
  338. return hRes;
  339. }
  340. /*--
  341. This function gets a handle to Registry.
  342. --*/
  343. HRESULT GetConnection(WCHAR* wzCname)
  344. {
  345. int fValid=0;
  346. HRESULT hRes=S_OK;
  347. wchar_t* wzName=NULL;
  348. LONG apiReturn=0L;
  349. //probably already got the key
  350. if(g_hkeyHKLM!=NULL)
  351. return S_OK;
  352. if(wzCname!=NULL)
  353. {
  354. if((wzName=(wchar_t*)malloc((3+wcslen(wzCname))*sizeof(wchar_t)))==NULL)
  355. {
  356. ShowError(IDS_E_OUTOFMEMORY);
  357. hRes = E_OUTOFMEMORY;
  358. goto End;
  359. }
  360. if(NULL==StrStrI(wzCname,L"\\\\"))
  361. {
  362. wcscpy(wzName,L"\\\\");
  363. wcscat(wzName,wzCname);
  364. }
  365. else if(wzCname==StrStrI(wzCname,L"\\\\"))
  366. wcscpy(wzName,wzCname);
  367. else
  368. {
  369. hRes = E_INVALIDARG;
  370. goto End;
  371. }
  372. }
  373. //connecting to the registry.
  374. apiReturn = ERROR_SUCCESS;
  375. apiReturn = RegConnectRegistry( wzName,
  376. HKEY_LOCAL_MACHINE,
  377. &g_hkeyHKLM
  378. );
  379. if (ERROR_SUCCESS != apiReturn)
  380. {
  381. PrintFormattedErrorMessage(apiReturn);
  382. hRes = E_FAIL;
  383. }
  384. End:
  385. if(wzName) free(wzName);
  386. return hRes;
  387. }
  388. /*--
  389. the GetSerHandle() function gets the service handle to the admin
  390. --*/
  391. HRESULT GetSerHandle(LPCTSTR lpServiceName,DWORD dwScmDesiredAccess, DWORD dwRegDesiredAccess,BOOL fSuppressMsg)
  392. {
  393. wchar_t* wzCname;
  394. HRESULT hRes=S_OK;
  395. WCHAR szTemp[MAX_BUFFER_SIZE];
  396. if(g_arVALOF[_p_CNAME_]!=NULL && StrStrI(g_arVALOF[_p_CNAME_],L"\\")!=g_arVALOF[_p_CNAME_])
  397. {
  398. if((wzCname=(wchar_t *)malloc((3+wcslen(g_arVALOF[_p_CNAME_]))*sizeof(wchar_t)))==NULL)
  399. {
  400. ShowError(IDS_E_OUTOFMEMORY);
  401. return E_FAIL;
  402. }
  403. wcscpy(wzCname,L"\\\\");
  404. wcscat(wzCname,g_arVALOF[_p_CNAME_]);
  405. }
  406. else
  407. wzCname=g_arVALOF[_p_CNAME_];
  408. if (g_hServiceManager)
  409. CloseServiceHandle(g_hServiceManager);
  410. if ((g_hServiceManager = OpenSCManager(wzCname,SERVICES_ACTIVE_DATABASE,dwScmDesiredAccess))==NULL)
  411. {
  412. DWORD dwErrorCode=0;
  413. dwErrorCode = GetLastError();
  414. if(ERROR_ACCESS_DENIED == dwErrorCode)
  415. {
  416. hRes = ERROR_ACCESS_DENIED; // Need to return this error
  417. ShowError(IDR_NOT_PRIVILEGED);
  418. fwprintf(stdout,L" %s\n",(g_arVALOF[_p_CNAME_] ? g_arVALOF[_p_CNAME_] : L"localhost"));
  419. }
  420. else
  421. PrintFormattedErrorMessage(dwErrorCode);
  422. }
  423. else if ((g_hServiceHandle= OpenService(g_hServiceManager,lpServiceName,dwRegDesiredAccess))==NULL)
  424. if((hRes=GetLastError())==ERROR_SERVICE_DOES_NOT_EXIST && (FALSE==fSuppressMsg))
  425. {
  426. ShowError(IDR_SERVICE_NOT_INSTALLED);
  427. fwprintf(stdout,L" %s.\n", lpServiceName);
  428. if (0 == LoadString(g_hResource, IDR_VERIFY_SERVICE_INSTALLED, szTemp, MAX_BUFFER_SIZE))
  429. {
  430. return GetLastError();
  431. }
  432. _snwprintf(g_szMsg, MAX_BUFFER_SIZE -1, szTemp,(g_arVALOF[_p_CNAME_] ? g_arVALOF[_p_CNAME_] : L"localhost"));
  433. MyWriteConsole(g_stdout, g_szMsg, wcslen(g_szMsg));
  434. }
  435. return hRes;
  436. }
  437. /*--
  438. to close the service handles
  439. --*/
  440. HRESULT CloseHandles()
  441. {
  442. BOOL bRet = FALSE;
  443. HRESULT hRes = S_OK;
  444. if(g_hServiceHandle )
  445. {
  446. bRet = CloseServiceHandle(g_hServiceHandle);
  447. g_hServiceHandle = NULL;
  448. if(!bRet)
  449. hRes = GetLastError();
  450. }
  451. if(g_hServiceManager)
  452. {
  453. bRet = CloseServiceHandle(g_hServiceManager);
  454. g_hServiceManager= NULL;
  455. if(!bRet)
  456. hRes = GetLastError();
  457. }
  458. return hRes;
  459. }
  460. /*-- StartSer Starts the Service after getting its handle by using
  461. GetSerHandle function
  462. --*/
  463. HRESULT StartSfuService(LPCTSTR lpServiceName)
  464. {
  465. HRESULT hRes=S_OK;
  466. SERVICE_STATUS serStatus;
  467. DWORD dwOldCheckPoint;
  468. DWORD dwStartTickCount;
  469. DWORD dwWaitTime;
  470. DWORD dwStatus;
  471. if(FAILED(hRes=GetSerHandle(lpServiceName,SC_MANAGER_ALL_ACCESS,SERVICE_ALL_ACCESS,FALSE)))
  472. goto End;
  473. if(hRes == ERROR_ACCESS_DENIED)
  474. {
  475. // Don't know why ERROR_ACCESS_DENIED escaped FAILED() macro. Anyway,
  476. // returning that error here.
  477. goto End;
  478. }
  479. else if(StartService(g_hServiceHandle, NULL, NULL))
  480. {
  481. if (!QueryServiceStatus(
  482. g_hServiceHandle, // handle to service
  483. &serStatus) ) // address of status information structure
  484. {
  485. hRes = GetLastError();
  486. ShowErrorFallback(IDS_E_SERVICE_NOT_STARTED, _T("\nError occured while starting the service."));
  487. if(hRes != ERROR_IO_PENDING) //not an interesting error to print
  488. PrintFormattedErrorMessage(hRes);
  489. goto End;
  490. }
  491. dwStartTickCount = GetTickCount();
  492. dwOldCheckPoint = serStatus.dwCheckPoint;
  493. while (serStatus.dwCurrentState == SERVICE_START_PENDING)
  494. {
  495. // Do not wait longer than the wait hint. A good interval is
  496. // one tenth the wait hint, but no less than 1 second and no
  497. // more than 10 seconds.
  498. dwWaitTime = serStatus.dwWaitHint / 10;
  499. if( dwWaitTime < 1000 )
  500. dwWaitTime = 1000;
  501. else if ( dwWaitTime > 10000 )
  502. dwWaitTime = 10000;
  503. Sleep( dwWaitTime );
  504. // Check the status again.
  505. if (!QueryServiceStatus(
  506. g_hServiceHandle, // handle to service
  507. &serStatus) ) // address of structure
  508. break;
  509. if ( serStatus.dwCheckPoint > dwOldCheckPoint )
  510. {
  511. // The service is making progress.
  512. dwStartTickCount = GetTickCount();
  513. dwOldCheckPoint = serStatus.dwCheckPoint;
  514. }
  515. else
  516. {
  517. if(GetTickCount()-dwStartTickCount > serStatus.dwWaitHint)
  518. {
  519. // No progress made within the wait hint
  520. break;
  521. }
  522. }
  523. }
  524. if (serStatus.dwCurrentState == SERVICE_RUNNING)
  525. {
  526. PrintMessageEx(g_stdout,IDS_SERVICE_STARTED, _T("\nThe service was started successfully.\n"));
  527. goto End;
  528. }
  529. }
  530. if((hRes=GetLastError())==ERROR_SERVICE_ALREADY_RUNNING)
  531. {
  532. /* StartService returns SERVICE_ALREADY_RUNNING even when the
  533. service is in wierd state. For instance, when the service is in the
  534. state STOP_PENDING, we print - The service was controlled successfully
  535. To avoid this, we issue a control to the service and see if it can respond. If
  536. it can't appropriate error message is printed
  537. */
  538. if (ControlService(g_hServiceHandle, SERVICE_CONTROL_INTERROGATE, &serStatus))
  539. {
  540. PrintMessageEx(g_stdout,IDR_ALREADY_STARTED, _T("\nThe service is already started.\n"));
  541. hRes = S_OK;
  542. }
  543. else
  544. {
  545. hRes = GetLastError();
  546. ShowErrorFallback(IDS_E_SERVICE_NOT_STARTED, _T("\nError occured while starting the service."));
  547. if(hRes != ERROR_IO_PENDING) //not an interesting error to print
  548. PrintFormattedErrorMessage(hRes);
  549. }
  550. }
  551. else if(hRes==ERROR_ACCESS_DENIED)
  552. ShowError(IDR_NOT_PRIVILEGED);
  553. else
  554. {
  555. ShowErrorFallback(IDS_E_SERVICE_NOT_STARTED, _T("\nError occured while starting the service."));
  556. if(hRes != ERROR_IO_PENDING) //not an interesting error to print
  557. PrintFormattedErrorMessage(hRes);
  558. }
  559. End:
  560. CloseHandles();
  561. return hRes;
  562. }
  563. /*--
  564. QuerySfuService function queries the service for its status.
  565. --*/
  566. HRESULT QuerySfuService(LPCTSTR lpServiceName)
  567. {
  568. HRESULT hRes;
  569. if(FAILED(hRes=GetSerHandle(lpServiceName,SC_MANAGER_CONNECT,SERVICE_QUERY_STATUS,FALSE)))
  570. return hRes;
  571. if(hRes == ERROR_ACCESS_DENIED)
  572. {
  573. // Don't know why ERROR_ACCESS_DENIED escaped FAILED() macro. Anyway,
  574. // returning that error here.
  575. return hRes;
  576. }
  577. else if(QueryServiceStatus(g_hServiceHandle,&g_hServiceStatus))
  578. return CloseHandles();
  579. else
  580. return GetLastError();
  581. }
  582. /*--
  583. ControlSfuService Stops Pauses Continues the Service after
  584. getting its handle by using GetSerHandle function.
  585. --*/
  586. HRESULT ControlSfuService(LPCTSTR lpServiceName,DWORD dwControl)
  587. {
  588. LPSERVICE_STATUS lpStatus = (SERVICE_STATUS *) malloc (sizeof(SERVICE_STATUS));
  589. if(lpStatus==NULL)
  590. {
  591. ;//bugbug print an error
  592. return E_OUTOFMEMORY;
  593. }
  594. HRESULT hr = S_FALSE;
  595. int queryCounter =0;
  596. DWORD dwState = 0;
  597. if(FAILED(dwState= GetSerHandle(lpServiceName,SC_MANAGER_ALL_ACCESS,SERVICE_ALL_ACCESS,FALSE)))
  598. {free(lpStatus);return dwState;}
  599. if(dwState == ERROR_ACCESS_DENIED)
  600. {
  601. // Don't know why ERROR_ACCESS_DENIED escaped FAILED() macro. Anyway,
  602. // returning that error here.
  603. free(lpStatus);
  604. return dwState;
  605. }
  606. //Check the return value of ControlService. If not null, then loop
  607. //with QueryServiceStatus
  608. if (ControlService(g_hServiceHandle,dwControl,lpStatus))
  609. {
  610. switch(dwControl)
  611. {
  612. case(SERVICE_CONTROL_PAUSE) :
  613. dwState = SERVICE_PAUSED;
  614. break;
  615. case(SERVICE_CONTROL_CONTINUE) :
  616. dwState = SERVICE_RUNNING;
  617. break;
  618. case(SERVICE_CONTROL_STOP):
  619. dwState = SERVICE_STOPPED;
  620. break;
  621. }
  622. for (;queryCounter <= _MAX_QUERY_CONTROL_; queryCounter++)
  623. {
  624. if( QueryServiceStatus( g_hServiceHandle, lpStatus ) )
  625. {
  626. //Check if state required is attained
  627. if ( lpStatus->dwCurrentState != dwState )
  628. {
  629. if ( lpStatus->dwWaitHint )
  630. {
  631. Sleep(lpStatus->dwWaitHint);
  632. }
  633. else
  634. Sleep(500);
  635. }
  636. else
  637. {
  638. switch(dwControl)
  639. {
  640. case SERVICE_CONTROL_PAUSE:
  641. PrintMessageEx(g_stdout,IDR_SERVICE_PAUSED,_T("\nThe service has been paused.\n"));
  642. break;
  643. case SERVICE_CONTROL_CONTINUE:
  644. PrintMessageEx(g_stdout,IDR_SERVICE_CONTINUED,_T("\nThe service has been resumed.\n"));
  645. break;
  646. case SERVICE_CONTROL_STOP:
  647. PrintMessage(g_stdout,IDR_SERVICE_CONTROLLED);
  648. break;
  649. }
  650. hr = S_OK;
  651. break;
  652. }
  653. }
  654. else
  655. {
  656. hr = GetLastError();
  657. PrintFormattedErrorMessage(hr);
  658. break;
  659. }
  660. }
  661. if (queryCounter > _MAX_QUERY_CONTROL_)
  662. {
  663. // We couldn't get to the state which we wanted to
  664. // within the no. of iterations. So print that the
  665. // service was not controlled successfully.
  666. switch(dwControl)
  667. {
  668. case SERVICE_CONTROL_PAUSE:
  669. PrintMessageEx(g_stdout,IDR_SERVICE_NOT_PAUSED,_T("\nThe service could not be paused.\n"));
  670. break;
  671. case SERVICE_CONTROL_CONTINUE:
  672. PrintMessageEx(g_stdout,IDR_SERVICE_NOT_CONTINUED,_T("\nThe service could not be resumed.\n"));
  673. break;
  674. case SERVICE_CONTROL_STOP:
  675. PrintMessage(g_stdout,IDR_SERVICE_NOT_CONTROLLED);
  676. break;
  677. }
  678. hr = S_OK;
  679. }
  680. }
  681. else
  682. {
  683. hr = GetLastError();
  684. PrintFormattedErrorMessage(hr);
  685. }
  686. free (lpStatus);
  687. if(FAILED(hr))
  688. return hr;
  689. return CloseHandles();
  690. }
  691. /* --
  692. GetBit(int Options,int bit) function returns the BIT in the position
  693. bit in the Options{it acts as a bit array}
  694. --*/
  695. int GetBit(int Options,int nbit)
  696. {
  697. int ni=0x01,nj=0;
  698. ni=ni<<nbit;
  699. if(ni&Options)
  700. return 1;
  701. else
  702. return 0;
  703. }
  704. /* --
  705. SetBit(int Options,int bit) function Sets the BIT in the position
  706. bit in the Options{it acts as a bit array}.
  707. --*/
  708. int SetBit(int Options,int nbit)
  709. {
  710. int ni=1,nj=0;
  711. ni=ni<<nbit;
  712. Options=ni|Options;
  713. return Options;
  714. }
  715. /*--
  716. this function prints out the help message for the command
  717. --*/
  718. HRESULT PrintMessage(HANDLE fp,int nMessageid)
  719. {
  720. HRESULT hRes = S_OK;
  721. HANDLE hOut = fp;
  722. int nRet = 0;
  723. DWORD dwWritten = 0;
  724. if( hOut == NULL )
  725. hOut = g_stdout;
  726. if(LoadString(g_hResource, nMessageid, g_szMsg, MAX_BUFFER_SIZE)==0)
  727. return GetLastError();
  728. MyWriteConsole(hOut,g_szMsg,_tcslen(g_szMsg));
  729. return hRes;
  730. }
  731. /*--
  732. this function prints out the help message for the command and falls
  733. back to english string if loadstring fails
  734. --*/
  735. HRESULT PrintMessageEx(HANDLE fp,int nMessageid, LPCTSTR szEng)
  736. {
  737. HRESULT hRes = S_OK;
  738. int nRet = 0;
  739. HANDLE hOut = fp;
  740. DWORD dwWritten = 0;
  741. if( hOut == NULL )
  742. hOut = g_stdout;
  743. TnLoadString(nMessageid, g_szMsg, MAX_BUFFER_SIZE,szEng);
  744. MyWriteConsole(hOut,g_szMsg,_tcslen(g_szMsg));
  745. return hRes;
  746. }
  747. /*--This function takes the parameter corresponding to the error code,
  748. prints it out and puts back all the classes
  749. and quits the program.
  750. --*/
  751. BOOL
  752. FileIsConsole(
  753. HANDLE fp
  754. )
  755. {
  756. unsigned htype;
  757. htype = GetFileType(fp);
  758. htype &= ~FILE_TYPE_REMOTE;
  759. return htype == FILE_TYPE_CHAR;
  760. }
  761. void
  762. MyWriteConsole(
  763. HANDLE fp,
  764. LPWSTR lpBuffer,
  765. DWORD cchBuffer
  766. )
  767. {
  768. //
  769. // Jump through hoops for output because:
  770. //
  771. // 1. printf() family chokes on international output (stops
  772. // printing when it hits an unrecognized character)
  773. //
  774. // 2. WriteConsole() works great on international output but
  775. // fails if the handle has been redirected (i.e., when the
  776. // output is piped to a file)
  777. //
  778. // 3. WriteFile() works great when output is piped to a file
  779. // but only knows about bytes, so Unicode characters are
  780. // printed as two Ansi characters.
  781. //
  782. if (FileIsConsole(fp))
  783. {
  784. WriteConsole(fp, lpBuffer, cchBuffer, &cchBuffer, NULL);
  785. }
  786. else
  787. {
  788. LPSTR lpAnsiBuffer = (LPSTR) LocalAlloc(LMEM_FIXED, cchBuffer * sizeof(WCHAR));
  789. if (lpAnsiBuffer != NULL)
  790. {
  791. cchBuffer = WideCharToMultiByte(CP_OEMCP,
  792. 0,
  793. lpBuffer,
  794. cchBuffer,
  795. lpAnsiBuffer,
  796. cchBuffer * sizeof(WCHAR),
  797. NULL,
  798. NULL);
  799. if (cchBuffer != 0)
  800. {
  801. WriteFile(fp, lpAnsiBuffer, cchBuffer, &cchBuffer, NULL);
  802. }
  803. LocalFree(lpAnsiBuffer);
  804. }
  805. }
  806. }
  807. int ShowError(int nError)
  808. {
  809. g_nError=nError;
  810. if(LoadString(g_hResource, nError, g_szMsg, MAX_BUFFER_SIZE)==0)
  811. return 1; //failed to loadString
  812. MyWriteConsole(g_stdout,g_szMsg, wcslen(g_szMsg));
  813. return 0; //successfully shown error
  814. }
  815. /*--This function takes the parameter corresponding to the error code
  816. and it's English String, prints it out and puts back all the classes
  817. and quits the program.
  818. --*/
  819. int ShowErrorFallback(int nError, LPCTSTR szEng)
  820. {
  821. g_nError=nError;
  822. TnLoadString(nError,g_szMsg,MAX_BUFFER_SIZE,szEng);
  823. MyWriteConsole(g_stdout,g_szMsg, wcslen(g_szMsg));
  824. return 0; //successfully shown error
  825. }
  826. // This function takes the input string for g_szMsg which is expected to
  827. // contain a "%s" init. We have several usage of such string across the
  828. // admintools and hence this function. Incase we have more that one %s
  829. // then we can not use this function.
  830. int ShowErrorEx(int nError,WCHAR *wzFormatString)
  831. {
  832. g_nError=nError;
  833. if(LoadString(g_hResource, nError, g_szMsg, MAX_BUFFER_SIZE)==0)
  834. return 1; //failed to loadString
  835. wprintf(g_szMsg,wzFormatString);
  836. fflush (stdout);
  837. return 0; //successfully shown error
  838. }
  839. /*--
  840. GetClass function gets handles to all the class hives, into the array
  841. g_arCLASShkey, using the handle to the HKLM we have from
  842. GetConnection
  843. --*/
  844. HRESULT GetClassEx(int nProperty, int nNumProp, BOOL bPrintErrorMessages, REGSAM samDesired)
  845. {
  846. int i=g_arPROP[nProperty][nNumProp].classname;
  847. LONG retVal;
  848. if(g_arCLASShkey[i]!=NULL)
  849. return S_OK;
  850. retVal=RegOpenKeyEx(
  851. g_hkeyHKLM,// handle to open key
  852. g_arCLASSname[i], // subkey name
  853. 0, // reserved
  854. samDesired, // security access mask
  855. g_arCLASShkey+i // handle to open key
  856. );
  857. if(retVal!=ERROR_SUCCESS)
  858. {
  859. if (bPrintErrorMessages)
  860. {
  861. PrintFormattedErrorMessage(retVal);
  862. }
  863. return E_FAIL;
  864. }
  865. return S_OK;
  866. }
  867. /*--
  868. PutClasses() function closes the keys to the hives.
  869. --*/
  870. HRESULT PutClasses()
  871. {
  872. int ni=0;
  873. SCODE sc=S_OK;
  874. for(ni=0;ni<_MAX_CLASS_NAMES_;ni++)
  875. {
  876. if(g_arCLASShkey[ni]==NULL)
  877. continue; // this class was not got, so no need to put.
  878. if(RegCloseKey(g_arCLASShkey[ni])!=ERROR_SUCCESS)
  879. sc=GetLastError();
  880. g_arCLASShkey[ni]=NULL;
  881. }
  882. if(g_hkeyHKLM!=NULL)
  883. {
  884. if (RegCloseKey(g_hkeyHKLM)!=ERROR_SUCCESS)
  885. return GetLastError();
  886. g_hkeyHKLM=NULL;
  887. }
  888. return sc;
  889. }
  890. /*--
  891. GetProperty() function gets value of the required property from the
  892. hive.
  893. //NOTE:
  894. // In case of REG_MULTI_SZ type
  895. //we are storing linked list of strings and not returning anything in variant
  896. //the linked list 'g_pStrList' needs to be freed by the caller
  897. //the caller needs to remember this
  898. --*/
  899. HRESULT GetProperty(int nProperty, int nNumofprop, VARIANT *pvarVal)
  900. {
  901. if(g_arPROP[nProperty][nNumofprop].propname==NULL)
  902. return E_FAIL;
  903. LONG retVal=ERROR_SUCCESS;
  904. DWORD size;
  905. DWORD dType;
  906. UINT uVar;
  907. wchar_t szString[MAX_BUFFER_SIZE]={0};
  908. wchar_t* szMultiStr=NULL;
  909. StrList * pHeadList=NULL;
  910. StrList * pTailList=NULL;
  911. StrList * pTemp= NULL ;
  912. if(g_arCLASShkey[g_arPROP[nProperty][nNumofprop].classname]==NULL)
  913. {
  914. retVal=E_ABORT;
  915. goto End;
  916. }
  917. switch (V_VT(&g_arPROP[nProperty][nNumofprop].var))
  918. {
  919. case VT_I4:
  920. size=sizeof(UINT);
  921. retVal=RegQueryValueEx(g_arCLASShkey[g_arPROP[nProperty][nNumofprop].classname],
  922. g_arPROP[nProperty][nNumofprop].propname,
  923. NULL,
  924. &dType,
  925. (LPBYTE)&uVar,
  926. (LPDWORD)&size
  927. );
  928. if(retVal!=ERROR_SUCCESS)
  929. {
  930. // If this was because of the registry value not found
  931. // display a proper error message instead of "the system
  932. // can not find the file specified"
  933. if(ERROR_FILE_NOT_FOUND==retVal)
  934. PrintMissingRegValueMsg(nProperty,nNumofprop);
  935. else
  936. PrintFormattedErrorMessage(retVal);
  937. goto End;
  938. }
  939. V_I4(pvarVal)=uVar;
  940. break;
  941. case VT_BSTR:
  942. size=MAX_BUFFER_SIZE*sizeof(wchar_t);
  943. retVal=RegQueryValueEx(g_arCLASShkey[g_arPROP[nProperty][nNumofprop].classname],
  944. g_arPROP[nProperty][nNumofprop].propname,
  945. NULL,
  946. &dType,
  947. (LPBYTE)szString,
  948. (LPDWORD)&size
  949. );
  950. if(retVal!=ERROR_SUCCESS)
  951. {
  952. // If this was because of the registry value not found
  953. // display a proper error message instead of "the system
  954. // can not find the file specified"
  955. if(ERROR_FILE_NOT_FOUND==retVal)
  956. PrintMissingRegValueMsg(nProperty,nNumofprop);
  957. else
  958. PrintFormattedErrorMessage(retVal);
  959. goto End;
  960. }
  961. V_BSTR(pvarVal)=SysAllocString(szString);
  962. if(NULL==V_BSTR(pvarVal))
  963. {
  964. ShowError(IDS_E_OUTOFMEMORY);
  965. retVal=E_OUTOFMEMORY;
  966. goto End;
  967. }
  968. break;
  969. case VT_ARRAY:
  970. pvarVal=NULL;
  971. retVal=RegQueryValueEx(g_arCLASShkey[g_arPROP[nProperty][nNumofprop].classname],
  972. g_arPROP[nProperty][nNumofprop].propname,
  973. NULL,
  974. &dType,
  975. NULL,
  976. (LPDWORD)&size
  977. );
  978. if(retVal==ERROR_SUCCESS)
  979. {
  980. szMultiStr=(wchar_t*)malloc(size * sizeof(char));
  981. if(szMultiStr==NULL)
  982. {
  983. retVal = E_OUTOFMEMORY;
  984. goto End;
  985. }
  986. //since the size returned is in bytes we use sizeof(char)
  987. retVal=RegQueryValueEx(g_arCLASShkey[g_arPROP[nProperty][nNumofprop].classname],
  988. g_arPROP[nProperty][nNumofprop].propname,
  989. NULL,
  990. &dType,
  991. (LPBYTE)szMultiStr,
  992. (LPDWORD)&size
  993. );
  994. }
  995. if (retVal!=ERROR_SUCCESS)
  996. {
  997. if(ERROR_FILE_NOT_FOUND==retVal)
  998. PrintMissingRegValueMsg(nProperty,nNumofprop);
  999. else
  1000. PrintFormattedErrorMessage(retVal);
  1001. goto End;
  1002. }
  1003. else
  1004. { //form a linked list containing the strings
  1005. //get all the strings into a linked list
  1006. // and their count into 'count'
  1007. int count = 0 ;
  1008. DWORD length = 0 ;
  1009. WCHAR* wzTemp = szMultiStr;
  1010. if (size >= 2)
  1011. {
  1012. // take away the last two zeroes of a reg_multi_sz
  1013. size -= 2;
  1014. while( wzTemp && *wzTemp && (length < size/sizeof(WCHAR)))
  1015. {
  1016. pTemp= (StrList *) malloc( sizeof( StrList ) );
  1017. if(pTemp==NULL)
  1018. {
  1019. retVal=E_OUTOFMEMORY;
  1020. goto End;
  1021. }
  1022. count++;
  1023. // add 1 so that you go past the null.
  1024. length+=wcslen(wzTemp ) + 1;
  1025. if((pTemp->Str=_wcsdup(wzTemp))==NULL)
  1026. {
  1027. retVal=E_OUTOFMEMORY;
  1028. goto End;
  1029. }
  1030. // insertion logic is being changed.
  1031. // insert at the tail.
  1032. if (NULL == pTailList)
  1033. {
  1034. // first insertion
  1035. pHeadList = pTemp;
  1036. pTailList = pTemp;
  1037. pTemp->next = NULL;
  1038. pTemp = NULL; // the memory pointed by pTemp will be taken care by the linked list.
  1039. }
  1040. else
  1041. {
  1042. // normal insertion
  1043. pTailList->next = pTemp;
  1044. pTemp->next = NULL;
  1045. pTailList = pTemp;
  1046. pTemp = NULL; // the memory pointed by pTemp will be taken care by the linked list.
  1047. }
  1048. wzTemp = szMultiStr + length;
  1049. }
  1050. }
  1051. //NOTE:
  1052. // We are doing a trick here....in case of multi_reg_sz
  1053. //we are storing strings in a linked list pointed by g_pStrList
  1054. //they need to be freed by the caller
  1055. g_pStrList=pHeadList;
  1056. //including 1 wide char '\0' for multi_sz end
  1057. }
  1058. break;
  1059. default:
  1060. ;
  1061. }
  1062. End:
  1063. StrList* temp=NULL;
  1064. if(retVal==E_OUTOFMEMORY)
  1065. while(pHeadList!=NULL)
  1066. {
  1067. temp=pHeadList;
  1068. if(pHeadList->Str)
  1069. free(pHeadList->Str);
  1070. pHeadList=pHeadList->next;
  1071. free(temp);
  1072. }
  1073. if(pTemp)
  1074. {
  1075. SAFE_FREE(pTemp->Str);
  1076. free(pTemp);
  1077. }
  1078. if(szMultiStr)
  1079. free(szMultiStr);
  1080. if(retVal!=ERROR_SUCCESS)
  1081. return E_FAIL;
  1082. else
  1083. return ERROR_SUCCESS;
  1084. }
  1085. /*--
  1086. PutProperty puts the property by using its classObject's handle.
  1087. Incase you pass NULL in place of pvarVal, it does not put the property.
  1088. //NOTE:
  1089. // In case of MULTI_REG_SZ type
  1090. // caller stores linked list of strings and does not pass anything in variant
  1091. //the linked list 'g_pStrList' needs to be freed by the callee (here)
  1092. //the caller needs to remember this
  1093. --*/
  1094. HRESULT PutProperty(int nProperty, int nNumofprop, VARIANT* pvarVal)
  1095. {
  1096. HRESULT retVal=S_OK;
  1097. CONST BYTE *lpData=NULL;
  1098. DWORD cbData=0;
  1099. DWORD dType;
  1100. wchar_t* wzTemp=NULL;
  1101. StrList* pTempList=NULL;
  1102. int len=0;
  1103. if(g_arPROP[nProperty][nNumofprop].fDontput==1)
  1104. goto End;
  1105. switch(V_VT(&g_arPROP[nProperty][nNumofprop].var))
  1106. {
  1107. case VT_I4:
  1108. lpData=(CONST BYTE *) &V_I4(pvarVal);
  1109. cbData=sizeof(DWORD);
  1110. dType=REG_DWORD;
  1111. break;
  1112. case VT_BSTR:
  1113. if(V_BSTR(pvarVal))
  1114. {
  1115. lpData=(CONST BYTE *)(wchar_t*)V_BSTR(pvarVal);
  1116. cbData=(wcslen((wchar_t*)V_BSTR(pvarVal))+1)*sizeof(wchar_t);
  1117. }
  1118. else
  1119. {
  1120. lpData = NULL;
  1121. cbData=0;
  1122. }
  1123. dType=REG_SZ;
  1124. break;
  1125. case VT_ARRAY:
  1126. //package passed in array into lpData well
  1127. dType=REG_MULTI_SZ;
  1128. //calculate the no. of bytes reqd.
  1129. pTempList = g_pStrList;
  1130. while(pTempList!=NULL)
  1131. {
  1132. cbData += ((wcslen(pTempList->Str)+1)*sizeof(wchar_t));
  1133. pTempList = pTempList->next;
  1134. }
  1135. cbData += sizeof(wchar_t); //for extra '\0' in MULTI_SZ; Note: for blank entries, only one '\0' is reqd. so this is also OK.
  1136. if(NULL==(wzTemp=(wchar_t*)malloc(cbData)))
  1137. {
  1138. retVal=E_OUTOFMEMORY;
  1139. goto End;
  1140. }
  1141. while(g_pStrList!=NULL)
  1142. {
  1143. wcscpy(wzTemp+len,g_pStrList->Str);
  1144. len+=wcslen(g_pStrList->Str)+1;
  1145. pTempList=g_pStrList;
  1146. g_pStrList=g_pStrList->next;
  1147. if(pTempList->Str)
  1148. free(pTempList->Str);
  1149. free(pTempList);
  1150. }
  1151. // fill the last two bytes NULL , as required to terminate a MULTI_SZ
  1152. *(wzTemp+len) = L'\0';
  1153. lpData=(CONST BYTE*)wzTemp;
  1154. break;
  1155. default :
  1156. {
  1157. if(0==LoadString(g_hResource,IDS_E_UNEXPECTED,g_szMsg,MAX_BUFFER_SIZE))
  1158. return GetLastError();
  1159. MyWriteConsole(g_stdout,g_szMsg, wcslen(g_szMsg));
  1160. retVal= E_FAIL;
  1161. goto End;
  1162. }
  1163. ;
  1164. }
  1165. if(lpData)
  1166. {
  1167. retVal=RegSetValueEx(
  1168. g_arCLASShkey[g_arPROP[nProperty][nNumofprop].classname], // handle to key
  1169. g_arPROP[nProperty][nNumofprop].propname, // value name
  1170. 0, // reserved
  1171. dType,// value type
  1172. lpData, // value data
  1173. cbData // size of value data
  1174. );
  1175. if(FAILED(retVal))
  1176. {
  1177. WCHAR *lpMsgBuf;
  1178. if (0 != FormatMessageW(
  1179. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1180. FORMAT_MESSAGE_FROM_SYSTEM |
  1181. FORMAT_MESSAGE_IGNORE_INSERTS,
  1182. NULL,
  1183. retVal,
  1184. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  1185. // Default language
  1186. (LPWSTR)&lpMsgBuf,
  1187. 0,
  1188. NULL
  1189. ))
  1190. {
  1191. MyWriteConsole(g_stdout,lpMsgBuf, wcslen(lpMsgBuf));
  1192. LocalFree( lpMsgBuf );
  1193. }
  1194. }
  1195. goto End;
  1196. }
  1197. End:
  1198. if(wzTemp)
  1199. free(wzTemp);
  1200. return retVal;
  1201. }
  1202. /*--
  1203. DupWStr takes a char string, and returns a wchar string.
  1204. Note that it allocates the memory required for the wchar string, So we
  1205. need to free it explicitly if after use.
  1206. if it has quotes surrounding it, then it is snipped off
  1207. --*/
  1208. wchar_t* DupWStr(char *szStr)
  1209. {
  1210. wchar_t* wzStr=NULL;
  1211. char* szString=NULL;
  1212. if(szStr==NULL)
  1213. return NULL;
  1214. int nLen=strlen(szStr);
  1215. if(NULL==(szString=(char*)malloc((nLen+1)*sizeof(char))))
  1216. return NULL;
  1217. if(szStr[0]!='"')
  1218. strcpy(szString,szStr);
  1219. else
  1220. {
  1221. int nPos;
  1222. if(szStr[nLen-1]!='"') //ending double quotes not there.
  1223. nPos=1;//then no need to skip the last two. One is enough
  1224. else
  1225. nPos=2;
  1226. strcpy(szString,szStr+1);
  1227. szString[nLen-nPos]='\0';
  1228. }
  1229. nLen=MultiByteToWideChar(GetConsoleCP(),0,szString,-1,NULL,NULL);
  1230. if (0 == nLen)
  1231. {
  1232. free(szString);
  1233. return NULL;
  1234. }
  1235. wzStr=(wchar_t *) malloc(nLen*sizeof(wchar_t));
  1236. if(wzStr==NULL)
  1237. {
  1238. free(szString);
  1239. return NULL;
  1240. }
  1241. if (!MultiByteToWideChar(GetConsoleCP(), 0, szString, -1, wzStr, nLen ))
  1242. {
  1243. free(szString);
  1244. free(wzStr);
  1245. return NULL;
  1246. }
  1247. if(szString)
  1248. free(szString);
  1249. return wzStr;
  1250. }
  1251. /*--
  1252. DupCStr takes a wchar string, and returns a char string.
  1253. Note that it allocates the memory required for the char string, So we
  1254. need to free it explicitly if after use.
  1255. If memory allocation fails (or if input is NULL), it returns a NULL pointer.
  1256. --*/
  1257. char* DupCStr(wchar_t *wzStr)
  1258. {
  1259. char* szStr=NULL;
  1260. if(wzStr==NULL)
  1261. return NULL;
  1262. int cbMultiByte = WideCharToMultiByte( GetACP(),NULL,wzStr,-1,szStr,0,NULL,NULL);
  1263. if (0 == cbMultiByte)
  1264. {
  1265. return NULL;
  1266. }
  1267. szStr = (char *) malloc(cbMultiByte);
  1268. if (NULL == szStr)
  1269. {
  1270. return NULL;
  1271. }
  1272. cbMultiByte = WideCharToMultiByte( GetConsoleCP(),NULL,wzStr,-1,szStr,
  1273. cbMultiByte,NULL,NULL);
  1274. if (0 == cbMultiByte)
  1275. {
  1276. free(szStr);
  1277. szStr = NULL;
  1278. }
  1279. return szStr;
  1280. }
  1281. /*--
  1282. function(s) to resolve and check if the given machine is
  1283. valid or not
  1284. --*/
  1285. HRESULT IsValidMachine(wchar_t* wzCname , int *fValid)
  1286. {
  1287. HRESULT hRes=S_OK;
  1288. struct sockaddr_in addr;
  1289. char * nodeName=NULL;
  1290. int cbMultiByte;
  1291. *fValid= 0;
  1292. wchar_t* wzName=NULL;
  1293. if(wzCname==NULL)
  1294. {
  1295. *fValid=1;
  1296. goto End;
  1297. }
  1298. else
  1299. {
  1300. if(NULL==(wzName=(wchar_t*)malloc((wcslen(wzCname)+1)*sizeof(wchar_t))))
  1301. {
  1302. hRes=E_OUTOFMEMORY;
  1303. goto End;
  1304. }
  1305. if(StrStrI(wzCname,L"\\")!=NULL)
  1306. {
  1307. wcscpy(wzName,wzCname+2);
  1308. }
  1309. else
  1310. wcscpy(wzName,wzCname);
  1311. }
  1312. cbMultiByte = WideCharToMultiByte( GetACP(),NULL,wzName,-1,nodeName,
  1313. 0,NULL,NULL);
  1314. nodeName = (char *) malloc(cbMultiByte*sizeof(char));
  1315. if(!nodeName)
  1316. {
  1317. hRes=E_OUTOFMEMORY;
  1318. goto End;
  1319. }
  1320. WideCharToMultiByte( GetConsoleCP(),NULL,wzName,-1,nodeName,
  1321. cbMultiByte,NULL,NULL);
  1322. if (Get_Inet_Address (&addr, nodeName))
  1323. *fValid = 1;
  1324. End:
  1325. if(nodeName)
  1326. free(nodeName);
  1327. if(wzName)
  1328. free(wzName);
  1329. return hRes;
  1330. }
  1331. BOOL Get_Inet_Address(struct sockaddr_in *addr, char *host)
  1332. {
  1333. register struct hostent *hp;
  1334. WORD wVersionRequested; //INGR
  1335. WSADATA wsaData; //INGR
  1336. // Start up winsock
  1337. wVersionRequested = MAKEWORD( 1, 1 ); //INGR
  1338. if (WSAStartup(wVersionRequested, &wsaData) != 0) { //INGR
  1339. return (FALSE);
  1340. }
  1341. // Get the address
  1342. memset(addr, 0, sizeof(*addr));
  1343. //bzero((TCHAR *)addr, sizeof *addr);
  1344. addr->sin_addr.s_addr = (u_long) inet_addr(host);
  1345. if (addr->sin_addr.s_addr == -1 || addr->sin_addr.s_addr == 0) {
  1346. if ((hp = gethostbyname(host)) == NULL) {
  1347. return (FALSE);
  1348. }
  1349. memcpy(&addr->sin_addr,hp->h_addr, hp->h_length );
  1350. //bcopy(hp->h_addr, (TCHAR *)&addr->sin_addr, hp->h_length);
  1351. }
  1352. addr->sin_family = AF_INET;
  1353. WSACleanup(); //INGR
  1354. return (TRUE);
  1355. }
  1356. /*--
  1357. Function to get the Trusted Domains and then check if the given
  1358. domain is one among them
  1359. --*/
  1360. HRESULT IsValidDomain(wchar_t* wzDomainName, int *fValid)
  1361. {
  1362. HRESULT hRes = E_FAIL;
  1363. TCHAR szName[MAX_PATH];
  1364. DWORD dwLen = sizeof(szName);
  1365. ZeroMemory(szName,sizeof(szName));
  1366. *fValid = 0;
  1367. if(_wcsicmp(wzDomainName,L".")==0||_wcsicmp(wzDomainName,L"localhost")==0||_wcsicmp(wzDomainName,local_host)==0)
  1368. {
  1369. *fValid=1;
  1370. return S_OK;
  1371. }
  1372. //If it's a local machine, g_arVALOF[_p_CNAME_] will be NULL. So pass "localhost".
  1373. if(FAILED(hRes=LoadNTDomainList(g_arVALOF[_p_CNAME_] ?g_arVALOF[_p_CNAME_] : SZLOCALMACHINE)))
  1374. return hRes;
  1375. //compare given domain with all the domains in the list.
  1376. if(g_slNTDomains.count != 0)
  1377. {
  1378. DWORD i;
  1379. for(i=0;i<g_slNTDomains.count;i++)
  1380. {
  1381. if(_wcsicmp(g_slNTDomains.strings[i],wzDomainName)==0)
  1382. {
  1383. *fValid=1;
  1384. break;
  1385. }
  1386. }
  1387. }
  1388. return S_OK;
  1389. }
  1390. /* This Function CheckForPassword() takes the password from the stdout after prompting for the same;
  1391. This function is called if the user name (Login name) is specified with out password */
  1392. HRESULT CheckForPassword(void)
  1393. {
  1394. HRESULT hRes=S_OK;
  1395. HANDLE hStdin;
  1396. DWORD fdwMode, fdwOldMode;
  1397. if(g_arVALOF[_p_USER_]!=NULL&&NULL==g_arVALOF[_p_PASSWD_])
  1398. { //Password is not specified and hence go get it.
  1399. if(NULL==(g_arVALOF[_p_PASSWD_]=(wchar_t*)malloc(MAX_BUFFER_SIZE*sizeof(wchar_t))))
  1400. {
  1401. hRes=E_OUTOFMEMORY;
  1402. return hRes;
  1403. }
  1404. int i;
  1405. PrintMessage(g_stdout, IDR_PASSWD_PROMPT);
  1406. hStdin = GetStdHandle(STD_INPUT_HANDLE);
  1407. if (hStdin == INVALID_HANDLE_VALUE)
  1408. goto ElsePart;
  1409. if (GetConsoleMode(hStdin, &fdwOldMode))
  1410. {
  1411. fdwMode = fdwOldMode &
  1412. ~(ENABLE_ECHO_INPUT);
  1413. if (! SetConsoleMode(hStdin, fdwMode))
  1414. goto ElsePart;
  1415. if(NULL==fgetws(g_arVALOF[_p_PASSWD_],MAX_BUFFER_SIZE,stdin))
  1416. {
  1417. hRes = E_FAIL;
  1418. return hRes;
  1419. }
  1420. wchar_t *szLast = wcsrchr(g_arVALOF[_p_PASSWD_],L'\n');
  1421. if(szLast)
  1422. {
  1423. *szLast = L'\0';
  1424. }
  1425. SetConsoleMode(hStdin, fdwOldMode);
  1426. }
  1427. else
  1428. {
  1429. // Here we get the password char by char(with echo off)
  1430. // and we can't support backspace and del chars here.
  1431. // this code will be executed only if we could not get/set
  1432. // the console of the user to ECHO_OFF
  1433. ElsePart:
  1434. for(i=0;i<MAX_BUFFER_SIZE-1;i++)
  1435. {
  1436. g_arVALOF[_p_PASSWD_][i]=(wchar_t)_getch();
  1437. if(g_arVALOF[_p_PASSWD_][i]==L'\r'||g_arVALOF[_p_PASSWD_][i]==L'\n')
  1438. break;
  1439. }
  1440. puts("\n\n");
  1441. g_arVALOF[_p_PASSWD_][i]=L'\0';
  1442. }
  1443. }
  1444. else if (NULL==g_arVALOF[_p_USER_]&&g_arVALOF[_p_PASSWD_]!=NULL) //Only password is specified hence error
  1445. {
  1446. hRes=E_FAIL;
  1447. ShowError(IDS_E_LOGINNOTSPECIFIED);
  1448. }
  1449. return hRes;
  1450. }
  1451. void ConvertintoSeconds(int nProperty,int *nSeconds)
  1452. {
  1453. int FirstTok=_wtoi(wcstok(g_arVALOF[nProperty],L":"));
  1454. wchar_t* mins=wcstok(NULL,L":");
  1455. wchar_t* secs=wcstok(NULL,L":");
  1456. if(NULL == secs)
  1457. {
  1458. if(NULL == mins)
  1459. {
  1460. *nSeconds=FirstTok;
  1461. return;
  1462. }
  1463. else
  1464. {
  1465. FirstTok*=60;
  1466. FirstTok+=_wtoi(mins);
  1467. *nSeconds=FirstTok;
  1468. return;
  1469. }
  1470. }
  1471. else
  1472. {
  1473. FirstTok*=60;
  1474. FirstTok+=_wtoi(mins);
  1475. FirstTok*=60;
  1476. FirstTok+=_wtoi(secs);
  1477. *nSeconds=FirstTok;
  1478. return;
  1479. }
  1480. }
  1481. void PrintFormattedErrorMessage(LONG LErrorCode)
  1482. {
  1483. WCHAR *lpMsgBuf;
  1484. if (0 != FormatMessageW(
  1485. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1486. FORMAT_MESSAGE_FROM_SYSTEM |
  1487. FORMAT_MESSAGE_IGNORE_INSERTS,
  1488. NULL,
  1489. LErrorCode,
  1490. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  1491. // Default language
  1492. (LPWSTR)&lpMsgBuf,
  1493. 0,
  1494. NULL
  1495. ))
  1496. {
  1497. MyWriteConsole(g_stdout,lpMsgBuf, wcslen(lpMsgBuf));
  1498. LocalFree( lpMsgBuf );
  1499. }
  1500. }
  1501. HRESULT getHostNameFromIP(char *szCname, WCHAR** wzCname)
  1502. {
  1503. struct hostent *hostinfo;
  1504. WSADATA wsaData;
  1505. u_long res;
  1506. HRESULT hRes=S_OK;
  1507. if (WSAStartup(MAKEWORD (1,1),&wsaData) != 0)
  1508. {
  1509. return E_FAIL;
  1510. }
  1511. if ((res = inet_addr ( szCname )) != INADDR_NONE )
  1512. {
  1513. if ((hostinfo = gethostbyaddr ((char*) &res, sizeof(res),AF_INET))
  1514. == NULL)
  1515. {
  1516. // Handle error here
  1517. hRes=E_FAIL;
  1518. goto End;
  1519. }
  1520. // At this point hostinfo->h_name contains host name in ASCII
  1521. // convert it to UNICODE before returning.
  1522. if(NULL == (*wzCname=DupWStr(hostinfo->h_name)))
  1523. {
  1524. hRes=E_OUTOFMEMORY;
  1525. goto End;
  1526. }
  1527. }
  1528. else
  1529. {
  1530. if(NULL == (*wzCname=DupWStr(szCname)))
  1531. {
  1532. hRes=E_OUTOFMEMORY;
  1533. goto End;
  1534. }
  1535. }
  1536. End:
  1537. WSACleanup();
  1538. return hRes;
  1539. }
  1540. HRESULT GetDomainHostedByThisMc( LPWSTR szDomain )
  1541. {
  1542. OBJECT_ATTRIBUTES obj_attr = { 0 };
  1543. LSA_HANDLE policy;
  1544. NTSTATUS nStatus = STATUS_SUCCESS;
  1545. LSA_UNICODE_STRING szSystemName ;
  1546. LSA_UNICODE_STRING *machine_to_open = NULL;
  1547. WCHAR szName[MAX_PATH] = L"";
  1548. USHORT dwLen = 0;
  1549. WCHAR *wzCName=NULL;
  1550. char *szCName=NULL;
  1551. HRESULT hRes=S_OK;
  1552. szSystemName.Buffer = NULL;
  1553. int count;
  1554. if( !szDomain )
  1555. {
  1556. hRes=E_FAIL;
  1557. goto GetDomainHostedByThisMcAbort;
  1558. }
  1559. obj_attr.Length = sizeof(obj_attr);
  1560. szDomain[0] = L'\0';
  1561. if(g_arVALOF[_p_CNAME_])
  1562. {
  1563. // Whistler : LsaOpenPolicy fails due to build environment in whistler if the
  1564. // computer name is given in IP address format. Hence, we get the host name from
  1565. // the IP address, incase it is a Whistler build.
  1566. // This works fine for Garuda. In Future, make sure you remove this unnecessary
  1567. // work around.
  1568. #ifdef WHISTLER_BUILD
  1569. if(NULL == (szCName=DupCStr(g_arVALOF[_p_CNAME_])))
  1570. {
  1571. hRes=E_OUTOFMEMORY;
  1572. goto GetDomainHostedByThisMcAbort;
  1573. }
  1574. if(S_OK != (hRes=getHostNameFromIP(szCName,&wzCName)))
  1575. {
  1576. goto GetDomainHostedByThisMcAbort;
  1577. }
  1578. #else
  1579. if(NULL==(wzCName=_wcsdup(g_arVALOF[_p_CNAME_])))
  1580. {
  1581. hRes=E_OUTOFMEMORY;
  1582. goto GetDomainHostedByThisMcAbort;
  1583. }
  1584. #endif
  1585. // dwLen is used to allocate memory to szSystemName.Buffer
  1586. dwLen = (USHORT)wcslen(g_arVALOF[_p_CNAME_]) + 1;
  1587. count = wcslen(wzCName);
  1588. //count CANNOT be zero- Grammar will not allow empty computer names!!
  1589. if(0==count)
  1590. {
  1591. hRes=IDS_E_INVALIDARG;
  1592. goto GetDomainHostedByThisMcAbort;
  1593. }
  1594. if (((count > 1) && (wzCName[0] != L'\\' ) && (wzCName[1] != L'\\')) || (count==1))
  1595. {
  1596. dwLen += (USHORT)wcslen(SLASH_SLASH);
  1597. }
  1598. szSystemName.Buffer = (WCHAR *) malloc(dwLen*sizeof(WCHAR));
  1599. if(szSystemName.Buffer==NULL)
  1600. {
  1601. hRes=E_OUTOFMEMORY;
  1602. goto GetDomainHostedByThisMcAbort;
  1603. }
  1604. if (((count > 1) && (wzCName[0] != L'\\' ) && (wzCName[1] != L'\\'))|| (count==1))
  1605. {
  1606. wcscpy(szSystemName.Buffer, SLASH_SLASH); //no overflow. Fixed length.
  1607. }
  1608. else
  1609. {
  1610. szSystemName.Buffer[0]=L'\0';
  1611. }
  1612. szSystemName.MaximumLength = dwLen * sizeof(WCHAR);
  1613. szSystemName.Length= szSystemName.MaximumLength - sizeof(WCHAR);
  1614. wcsncat(szSystemName.Buffer, wzCName, dwLen - 1 - wcslen(szSystemName.Buffer));
  1615. machine_to_open = &szSystemName;
  1616. }
  1617. nStatus = LsaOpenPolicy(
  1618. machine_to_open,
  1619. &obj_attr,
  1620. POLICY_VIEW_LOCAL_INFORMATION,
  1621. &policy
  1622. );
  1623. if (NT_SUCCESS(nStatus))
  1624. {
  1625. POLICY_ACCOUNT_DOMAIN_INFO *info = NULL;
  1626. nStatus = LsaQueryInformationPolicy(
  1627. policy,
  1628. PolicyAccountDomainInformation,
  1629. (PVOID *)&info
  1630. );
  1631. if (NT_SUCCESS(nStatus))
  1632. {
  1633. hRes = S_OK;
  1634. wcscpy( szDomain, info->DomainName.Buffer );
  1635. LsaFreeMemory(info);
  1636. }
  1637. LsaClose(policy);
  1638. }
  1639. GetDomainHostedByThisMcAbort:
  1640. if(wzCName)
  1641. free(wzCName);
  1642. if(szCName)
  1643. free(szCName);
  1644. if(szSystemName.Buffer)
  1645. free(szSystemName.Buffer);
  1646. return hRes;
  1647. }
  1648. BOOL CheckForInt(int nProperty)
  1649. {
  1650. char *szVal=NULL;
  1651. BOOL fRet=FALSE;
  1652. szVal = DupCStr(g_arVALOF[nProperty]);
  1653. if(szVal)
  1654. {
  1655. if( atof(szVal) - _wtoi(g_arVALOF[nProperty]) )
  1656. fRet = FALSE;
  1657. else
  1658. fRet = TRUE;
  1659. }
  1660. SAFE_FREE(szVal);
  1661. return fRet;
  1662. }
  1663. // This function changes the user specified Computer name into the IP address
  1664. // format and returns that. It also stores the specified name in the global
  1665. // variable g_szCName for future reference(in Printsettings()).
  1666. // This is needed if we want to convert the etc\hosts alias name into the IP
  1667. // address as they themselves will not get resolve in NetUseAdd().
  1668. // This function is called in this way in <fooadmin.y>
  1669. // g_arVALOF[_p_CNAME_]=CopyHostName(yytext)
  1670. // The above line replaces the call to DupWStr directly(FYI).
  1671. //
  1672. // WE HAVE DECIDED NOT TO FIX THIS (WINDOWS BUG 153111) AS IT SLOWS
  1673. // DOWN THE PERFORMANCE OF THE UTILS(It takes time to resolve--call
  1674. // to gethostbyname()
  1675. /*
  1676. // This will create the memory required and they need to be freed explicitly.
  1677. // Please free the memory allocated to g_szCName as well.
  1678. WCHAR *CopyHostName(CHAR *szCName)
  1679. {
  1680. // Inorder to print the name of the computer in the same way as the user specified
  1681. // we store that in a global variable and use the same in PrintSettings()
  1682. struct sockaddr_in addr;
  1683. WCHAR *wzIPAddress=NULL;
  1684. g_szCName=DupWStr(szCName);
  1685. if(Get_Inet_Address(&addr,szCName))
  1686. {
  1687. wzIPAddress=DupWStr(inet_ntoa(addr.sin_addr));
  1688. }
  1689. return wzIPAddress;
  1690. }
  1691. */
  1692. // This function checks for the maximum integer and even
  1693. // pops up the appropriate error message
  1694. // This function takes the integer value in g_arVALOF[]
  1695. // char array and compares with TEXT_MAX_INTEGER_VALUE
  1696. // if exceeds bails out with the error
  1697. HRESULT CheckForMaxInt(WCHAR *wzValue,DWORD ErrorCode)
  1698. {
  1699. HRESULT hRes=S_OK;
  1700. UINT SpecIntLen = wcslen(wzValue);
  1701. UINT MaxIntLen = wcslen(TEXT_MAX_INTEGER_VALUE);
  1702. // If the length of the value exceeds the max integer length =>
  1703. // clearly error
  1704. // else
  1705. // if same length, then strcmp will help in determining whether the value
  1706. // exceeds the max limit.
  1707. if(SpecIntLen > MaxIntLen)
  1708. goto Error;
  1709. else if ((SpecIntLen == MaxIntLen) && (wcscmp(wzValue,TEXT_MAX_INTEGER_VALUE)>0))
  1710. goto Error;
  1711. else goto End;
  1712. Error:
  1713. hRes=E_FAIL;
  1714. ShowError(ErrorCode);
  1715. goto End;
  1716. End:
  1717. return hRes;
  1718. }
  1719. // This function does a pre-analysis of the command line and copies the appropriate
  1720. // values into the global variable. This is for handling two cases.
  1721. // (1) To take care of DBCS chars that may appear in the command line. Since the
  1722. // actual lexical analyser can not handle DBCS and the we couldn't make use
  1723. // of the multi-byte conversion aptly (will result in two many special cases
  1724. // in lex specification), hence we are preprocessing the command line and
  1725. // eliminating the processing of DBCS in lex.
  1726. // (2) Some admintools, they take so complicated parameters that we can not put
  1727. // them into specification. The actual problem is that there are several such
  1728. // parameters and they can take any character theoritically.:(
  1729. // Arguments:
  1730. //
  1731. // (1) argc: Number of arguments in the command line.
  1732. // To make sure that we are exceeding the limits
  1733. // (2) argv: The actual command line parameters
  1734. // (3) nProperty: This is the index to where the "value" of the option
  1735. // is tobe stored.
  1736. // (4) option: This is the actual option (text string), we are trying to
  1737. // analyze and this guyz value should be store appropriately.
  1738. // (5) currentOp: This is an index to the current argument that is being
  1739. // analyzed.
  1740. // (6) nextOp: <OUT> This is an index to the next command line argument
  1741. // that needs to be taken care.
  1742. // (7) Success: <OUT> Flag which indicates whether we have done something
  1743. // to the command line parameters (did the option match)
  1744. // (8) IsSpaceAllowed: This is a flag to indicate whether the case (5)
  1745. // below as a valid scenario.
  1746. // This function returns ERROR_SUCCESS on Success
  1747. // else error is returned
  1748. DWORD PreAnalyzer(int argc,
  1749. WCHAR *argv[],
  1750. int nProperty,
  1751. WCHAR *wzOption,
  1752. int nCurrentOp,
  1753. int *nNextOp,
  1754. BOOL *fSuccess,
  1755. BOOL IsSpaceAllowed
  1756. )
  1757. {
  1758. // *******************************************************************//
  1759. // These are the five ways in which the actual command line
  1760. // arguments can be specified.
  1761. //
  1762. // Case (1) : <option>=<value>
  1763. // Case (2) : <option>=space<value>
  1764. // Case (3) : <option>space=space<value>
  1765. // Case (4) : <option>space=<value>
  1766. // Case (5) : <option>space<value>
  1767. //
  1768. // We need to take care of all the five case while analyzing
  1769. // *******************************************************************//
  1770. DWORD nOptionStrLen = wcslen(wzOption);
  1771. // buffer: This buffer stores the argv[i] and argv[i+1] (if exists)
  1772. // and used for processing the argument.
  1773. WCHAR wzBuffer[_MAX_PATH + 1];
  1774. DWORD nStartIndex,nRunIndex;
  1775. BOOL fEqualToFound = FALSE;
  1776. DWORD nRetVal = ERROR_SUCCESS;
  1777. DWORD nBufferLength;
  1778. DWORD dwSize;
  1779. *fSuccess = FALSE;
  1780. // Initializing the next op to current op
  1781. *nNextOp=nCurrentOp;
  1782. // Check whether wzOption is the current op.
  1783. // if not return.
  1784. if(_wcsnicmp(wzOption,argv[nCurrentOp],nOptionStrLen))
  1785. goto End;
  1786. // Buffer is framed
  1787. wzBuffer[_MAX_PATH] = L'\0'; // Ensure NULL termination
  1788. wcsncpy(wzBuffer, argv[nCurrentOp], _MAX_PATH);
  1789. if(argc>nCurrentOp+1)
  1790. {
  1791. // We have one more command line argument (i+1)
  1792. // so concat it to the buffer
  1793. INT used_up_length = wcslen(wzBuffer);
  1794. _snwprintf(
  1795. wzBuffer + used_up_length,
  1796. _MAX_PATH - used_up_length,
  1797. L" %s",
  1798. argv[nCurrentOp+1]
  1799. );
  1800. }
  1801. nBufferLength = wcslen(wzBuffer);
  1802. nStartIndex = nOptionStrLen;
  1803. nRunIndex = nStartIndex;
  1804. // Skip space and any "=" sign inbetween
  1805. while((nRunIndex < nStartIndex + 3 ) && (nRunIndex < nBufferLength))
  1806. {
  1807. if(L'=' == wzBuffer[nRunIndex])
  1808. {
  1809. if(fEqualToFound)
  1810. break;
  1811. else
  1812. {
  1813. fEqualToFound = TRUE;
  1814. nRunIndex++;
  1815. continue;
  1816. }
  1817. }
  1818. else
  1819. if(L' ' == wzBuffer[nRunIndex])
  1820. {
  1821. nRunIndex++;
  1822. continue;
  1823. }
  1824. else
  1825. break;
  1826. }
  1827. // Filter missing value for the option
  1828. if(nRunIndex>=nBufferLength)
  1829. {
  1830. if(nRunIndex == nOptionStrLen + 2)
  1831. {
  1832. // Case (3)
  1833. // Check whether the option is missing.
  1834. if(NULL == argv[nCurrentOp+2])
  1835. {
  1836. nRetVal=E_FAIL;
  1837. goto End;
  1838. }
  1839. else
  1840. // Increment nRunIndex to point to next valid input
  1841. nRunIndex++;
  1842. }
  1843. else
  1844. { // Missing value for (1),(2),(4) and (5)
  1845. nRetVal = E_FAIL;
  1846. goto End;
  1847. }
  1848. }
  1849. // If no "=" is present and also space is not allowed
  1850. // as a valid scenario, then invalid according to usage
  1851. if((!fEqualToFound)&&(!IsSpaceAllowed))
  1852. {
  1853. nRetVal = IDR_TELNET_CONTROL_VALUES;
  1854. goto End;
  1855. }
  1856. // Now we expect the actual value of the option at the nRunIndex.
  1857. // So, based on the value of nRunIndex, we can say which argv[]
  1858. // has the value and can take any actions if required.
  1859. switch(nRunIndex - nStartIndex)
  1860. {
  1861. case 1:
  1862. // Falls under Cases (1) or (5) as stated above
  1863. if(L'=' == wzBuffer[nOptionStrLen])
  1864. {
  1865. // Clearly case (1)
  1866. if(NULL == (g_arVALOF[nProperty] = _wcsdup(argv[nCurrentOp]+nOptionStrLen+1)))
  1867. {
  1868. nRetVal = IDS_E_OUTOFMEMORY;// Error
  1869. ShowError(IDS_E_OUTOFMEMORY);
  1870. goto End;
  1871. }
  1872. *nNextOp = nCurrentOp ;
  1873. *fSuccess = TRUE;
  1874. }
  1875. else
  1876. { // case (5)
  1877. if(NULL == (g_arVALOF[nProperty] = _wcsdup(argv[nCurrentOp+1])))
  1878. {
  1879. nRetVal = IDS_E_OUTOFMEMORY;// Error
  1880. ShowError(IDS_E_OUTOFMEMORY);
  1881. goto End;
  1882. }
  1883. *nNextOp = nCurrentOp + 1;
  1884. *fSuccess = TRUE;
  1885. }
  1886. break;
  1887. case 2:
  1888. // Falls under Cases (2) and (4)
  1889. if(L'=' == argv[nCurrentOp+1][0])
  1890. {
  1891. // Case (4)
  1892. // Skip the "=" and then copy.
  1893. if(NULL == (g_arVALOF[nProperty] = _wcsdup(argv[nCurrentOp+1]+1)))
  1894. {
  1895. nRetVal = IDS_E_OUTOFMEMORY;// Error
  1896. ShowError(IDS_E_OUTOFMEMORY);
  1897. goto End;
  1898. }
  1899. *nNextOp = nCurrentOp + 1;
  1900. *fSuccess = TRUE;
  1901. }
  1902. else
  1903. {
  1904. // Case (2)
  1905. if(NULL == (g_arVALOF[nProperty] = _wcsdup(argv[nCurrentOp+1])))
  1906. {
  1907. nRetVal = IDS_E_OUTOFMEMORY;// Error
  1908. ShowError(IDS_E_OUTOFMEMORY);
  1909. goto End;
  1910. }
  1911. *nNextOp = nCurrentOp + 1;
  1912. *fSuccess = TRUE;
  1913. }
  1914. break;
  1915. case 3:
  1916. // Falls under case (3)
  1917. if (NULL == (g_arVALOF[nProperty] = _wcsdup(argv[nCurrentOp+2])))
  1918. {
  1919. nRetVal = IDS_E_OUTOFMEMORY;// Error
  1920. ShowError(IDS_E_OUTOFMEMORY);
  1921. goto End;
  1922. }
  1923. *nNextOp = nCurrentOp + 2;
  1924. *fSuccess = TRUE;
  1925. break;
  1926. case 0:
  1927. // Something unexpected encountered
  1928. // Give it to the actual analyzer for analyzis.
  1929. *nNextOp = nCurrentOp;
  1930. break;
  1931. }
  1932. if(ERROR_SUCCESS == nRetVal)
  1933. {
  1934. if(NULL==g_arVALOF[nProperty])
  1935. {
  1936. nRetVal = E_FAIL;
  1937. goto End;
  1938. }
  1939. }
  1940. End:
  1941. return nRetVal;
  1942. }
  1943. // This function will print the missing registry value information
  1944. // Why didn't we add the following string to Cladmin.rc? The reasons are
  1945. // (1) We don't want to get Whistler and Garuda Telnet out of sync
  1946. // (2) This code should NEVER get executed and it is only for the
  1947. // the instrumentation. We can remove this before shipping.
  1948. #define IDS_E_MISSING_REGVALUE L"The registry value '%s' is missing.\n"
  1949. DWORD PrintMissingRegValueMsg(int nProperty, int nNumofprop)
  1950. {
  1951. WCHAR szRegValue[_MAX_PATH + 1];
  1952. wcsncpy(g_szMsg, IDS_E_MISSING_REGVALUE, ARRAYSIZE(g_szMsg)-1);
  1953. g_szMsg[ARRAYSIZE(g_szMsg)-1]=L'\0';
  1954. _snwprintf(
  1955. szRegValue,
  1956. _MAX_PATH,
  1957. L"%s\\%s",
  1958. g_arCLASSname[g_arPROP[nProperty][nNumofprop].classname],
  1959. g_arPROP[nProperty][nNumofprop].propname);
  1960. szRegValue[_MAX_PATH] = L'\0'; // ensure NULL termination
  1961. fwprintf(stdout, g_szMsg, szRegValue );
  1962. return S_OK;
  1963. }
  1964. void HelperFreeStringList(PSTRING_LIST pList)
  1965. {
  1966. if(pList && pList->count && pList->strings)
  1967. {
  1968. DWORD i;
  1969. for(i=0; i < pList->count; ++i)
  1970. {
  1971. if(pList->strings[i])
  1972. delete [] pList->strings[i];
  1973. }
  1974. delete pList->strings;
  1975. pList->count = 0;
  1976. pList->strings = NULL;
  1977. }
  1978. }
  1979. HRESULT LoadNTDomainList(LPTSTR szMachine)
  1980. {
  1981. HRESULT hRes = S_OK;
  1982. int dwSize=0, dwType=0;
  1983. DWORD nIndex = 0;
  1984. LPTSTR lpComputer = NULL, lpDomains = NULL, lpPrimary = NULL;
  1985. LPBYTE lpBuffer = NULL;
  1986. //MessageBoxW(NULL, (LPWSTR)L"LoadNTDomainList", L"LoadNTDomainList1", MB_OK);
  1987. //
  1988. // Add all trusted domains to the list
  1989. //
  1990. dwSize = GetTrustedDomainList(szMachine,&lpDomains, &lpPrimary);
  1991. //
  1992. // free previous values
  1993. //
  1994. HelperFreeStringList(&g_slNTDomains);
  1995. //
  1996. // initialize list again
  1997. //
  1998. g_slNTDomains.count = 0;
  1999. //
  2000. // two for primary domain
  2001. // and this computer
  2002. // one more in case dwSize is -1
  2003. // hence total is 3
  2004. //
  2005. g_slNTDomains.strings = new LPTSTR[dwSize + 3];
  2006. ATLASSERT(g_slNTDomains.strings != NULL);
  2007. if(NULL==g_slNTDomains.strings)
  2008. {
  2009. ShowError(IDS_E_OUTOFMEMORY);
  2010. hRes = E_OUTOFMEMORY;
  2011. goto Done;
  2012. }
  2013. ZeroMemory(g_slNTDomains.strings, (dwSize + 3)*sizeof(LPTSTR));
  2014. if((dwSize > 0) && lpDomains)
  2015. {
  2016. LPTSTR ptr = lpDomains;
  2017. //
  2018. // add domains to our list
  2019. //
  2020. while(*ptr)
  2021. {
  2022. ptr = _tcsupr(ptr);
  2023. g_slNTDomains.strings[g_slNTDomains.count] = new TCHAR[_tcslen(ptr) + 1];
  2024. ATLASSERT(g_slNTDomains.strings[g_slNTDomains.count] != NULL);
  2025. ZeroMemory(g_slNTDomains.strings[g_slNTDomains.count], (_tcslen(ptr) + 1)*sizeof(TCHAR));
  2026. _tcscpy(g_slNTDomains.strings[g_slNTDomains.count], ptr);
  2027. ptr += _tcslen(ptr) + 1;
  2028. g_slNTDomains.count++;
  2029. }
  2030. delete [] lpDomains;
  2031. lpDomains = NULL;
  2032. }
  2033. if(lpPrimary && *lpPrimary)
  2034. {
  2035. lpPrimary = _tcsupr(lpPrimary);
  2036. for(nIndex=0;nIndex<g_slNTDomains.count;nIndex++)
  2037. {
  2038. if(!_tcsicmp(lpPrimary, g_slNTDomains.strings[nIndex]))
  2039. break;
  2040. }
  2041. if(nIndex == g_slNTDomains.count)
  2042. {
  2043. //
  2044. // lpPrimary was not in the list of domains that we
  2045. // got. add it.
  2046. //
  2047. g_slNTDomains.strings[g_slNTDomains.count] = new TCHAR[_tcslen(lpPrimary) + 1];
  2048. ATLASSERT(g_slNTDomains.strings[g_slNTDomains.count] != NULL);
  2049. ZeroMemory(g_slNTDomains.strings[g_slNTDomains.count], (_tcslen(lpPrimary) + 1)*sizeof(TCHAR));
  2050. _tcscpy(g_slNTDomains.strings[g_slNTDomains.count], lpPrimary);
  2051. g_slNTDomains.count++;
  2052. }
  2053. }
  2054. //
  2055. // Add our computer to be selected if this machine is not the
  2056. // domain controler (which should already be in the list)
  2057. //
  2058. //Pass NULL if local machine. Else machine name.
  2059. NetServerGetInfo(_wcsicmp(szMachine,SZLOCALMACHINE) ? szMachine : NULL, 101, &lpBuffer);
  2060. if(lpBuffer && ((LPSERVER_INFO_101)lpBuffer)->sv101_type &
  2061. ((DWORD)SV_TYPE_DOMAIN_CTRL | (DWORD)SV_TYPE_DOMAIN_BAKCTRL))
  2062. {
  2063. /*
  2064. we got this computer as one of the domains. no need to add it to the
  2065. list again. just do nothing.
  2066. */
  2067. ;
  2068. }
  2069. else
  2070. {
  2071. TCHAR szName[MAX_PATH + 2];
  2072. ZeroMemory(szName, sizeof(szName));
  2073. DWORD dwLen = sizeof(szName);
  2074. //if it's not a local machine, keep it as it is. Else make it \\localhost.
  2075. if (_tcsicmp(szMachine,SZLOCALMACHINE))
  2076. {
  2077. if( _tcslen(szMachine) > (MAX_PATH - 2) )
  2078. goto Done;
  2079. if (_tcsncmp(szMachine,L"\\\\",2))
  2080. _tcscpy(szName,L"\\\\");
  2081. _tcscat(szName,szMachine);
  2082. _tcsupr(szName);
  2083. }
  2084. else if(GetComputerName(szName + 2, &dwLen))
  2085. {
  2086. szName[0] = TEXT('\\');
  2087. szName[1] = TEXT('\\');
  2088. }
  2089. else
  2090. goto Done;
  2091. //
  2092. // add this also to our list of domains
  2093. //
  2094. g_slNTDomains.strings[g_slNTDomains.count] = new TCHAR[_tcslen(szName) + 1];
  2095. ATLASSERT(g_slNTDomains.strings[g_slNTDomains.count] != NULL);
  2096. ZeroMemory(g_slNTDomains.strings[g_slNTDomains.count], (_tcslen(szName) + 1)*sizeof(TCHAR));
  2097. _tcscpy(g_slNTDomains.strings[g_slNTDomains.count], szName);
  2098. g_slNTDomains.count++;
  2099. }
  2100. Done:
  2101. if(lpBuffer)
  2102. {
  2103. NetApiBufferFree(lpBuffer);
  2104. }
  2105. if(lpPrimary)
  2106. {
  2107. delete [] lpPrimary;
  2108. }
  2109. return hRes;
  2110. }
  2111. int GetTrustedDomainList(LPTSTR szMachine, LPTSTR * list, LPTSTR * primary)
  2112. {
  2113. //BOOL stat = TRUE;
  2114. DWORD ret=0, size=0, type=0;
  2115. LPTSTR cache = NULL, trusted = NULL;
  2116. HKEY hKey=NULL;
  2117. CRegKey key;
  2118. HKEY hKeyRemoteRegistry = NULL;
  2119. STRING_LIST slValues = {0, NULL};
  2120. *list = NULL;
  2121. if (FAILED(RegConnectRegistry(_wcsicmp(szMachine,SZLOCALMACHINE) ? szMachine : NULL,
  2122. HKEY_LOCAL_MACHINE,
  2123. &hKeyRemoteRegistry)))
  2124. {
  2125. goto ABORT;
  2126. }
  2127. if(key.Open(hKeyRemoteRegistry, WINLOGONNT_KEY) == ERROR_SUCCESS)
  2128. {
  2129. size = 0;
  2130. if(key.QueryValue(*primary, CACHEPRIMARYDOMAIN_VALUE, &size) == ERROR_SUCCESS)
  2131. {
  2132. *primary = new TCHAR[size+1];
  2133. ATLASSERT(primary != NULL);
  2134. if(*primary)
  2135. {
  2136. ZeroMemory(*primary, (size+1)*sizeof(TCHAR));
  2137. if(key.QueryValue(*primary, CACHEPRIMARYDOMAIN_VALUE, &size) != ERROR_SUCCESS)
  2138. {
  2139. goto ABORT;
  2140. }
  2141. else
  2142. {
  2143. key.Close();
  2144. // don't quit. we have to get the list of trusted domains also.
  2145. }
  2146. }
  2147. }
  2148. else
  2149. {
  2150. key.Close();
  2151. goto ABORT;
  2152. }
  2153. }
  2154. else
  2155. {
  2156. goto ABORT;
  2157. }
  2158. //
  2159. // Get trusted domains. In NT40 the CacheTrustedDomains
  2160. // under winlogon doesn't exist. I did find that Netlogon has a field
  2161. // called TrustedDomainList which seems to be there in both NT351 and NT40.
  2162. // Winlogon has a field called DCache which seem to cache the trusted
  2163. // domains. I'm going to check Netlogon:TrustedDomainList first. If it
  2164. // fails: Check for Winlogon:CacheTrustedDomains then Winlogon:DCache.
  2165. // Warning -- Winlogon:CacheTrustedDomains is a REG_SZ and
  2166. // Netlogon:TrustedDomainList and Winlogon:DCache are REG_MULTI_SZ.
  2167. // Note -- see 4.0 Resource Kit documentation regarding some of these
  2168. // values
  2169. //
  2170. if(key.Open(hKeyRemoteRegistry, NETLOGONPARAMETERS_KEY) == ERROR_SUCCESS)
  2171. {
  2172. size = 0;
  2173. if(key.QueryValue(trusted, TRUSTEDDOMAINLIST_VALUE, &size) == ERROR_SUCCESS)
  2174. {
  2175. trusted = new TCHAR[size + 1];
  2176. ATLASSERT(trusted != NULL);
  2177. if(trusted)
  2178. {
  2179. ZeroMemory(trusted, (size+1)*sizeof(TCHAR));
  2180. if(key.QueryValue(trusted, TRUSTEDDOMAINLIST_VALUE, &size) != ERROR_SUCCESS)
  2181. {
  2182. key.Close();
  2183. delete [] trusted;
  2184. trusted = NULL;
  2185. *list = NULL;
  2186. //goto ABORT;
  2187. }
  2188. else
  2189. {
  2190. *list = trusted;
  2191. key.Close();
  2192. }
  2193. }
  2194. else
  2195. {
  2196. key.Close();
  2197. goto ABORT;
  2198. }
  2199. }
  2200. else
  2201. {
  2202. key.Close();
  2203. *list = NULL;
  2204. }
  2205. }
  2206. if(!(*list) && (key.Open(hKeyRemoteRegistry, WINLOGONNT_KEY) == ERROR_SUCCESS))
  2207. {
  2208. size = 0;
  2209. if(key.QueryValue(cache, CACHETRUSTEDDOMAINS_VALUE, &size) == ERROR_SUCCESS)
  2210. {
  2211. cache = new TCHAR[size + 1];
  2212. ATLASSERT(cache != NULL);
  2213. if(cache)
  2214. {
  2215. ZeroMemory(cache, size);
  2216. if(key.QueryValue(cache, CACHETRUSTEDDOMAINS_VALUE, &size) == ERROR_SUCCESS)
  2217. {
  2218. //
  2219. // comma separated list
  2220. //
  2221. LPTSTR lpComma = NULL;
  2222. LPTSTR lpDelim = TEXT(",");
  2223. lpComma = _tcstok(cache, lpDelim);
  2224. while(lpComma)
  2225. {
  2226. lpComma = _tcstok(NULL, lpDelim);
  2227. }
  2228. *list = cache;
  2229. }
  2230. else
  2231. {
  2232. key.Close();
  2233. delete [] cache;
  2234. cache = NULL;
  2235. *list = NULL;
  2236. }
  2237. }
  2238. else
  2239. {
  2240. key.Close();
  2241. goto ABORT;
  2242. }
  2243. }
  2244. else
  2245. {
  2246. *list = NULL;
  2247. key.Close();
  2248. }
  2249. }
  2250. if(!(*list) && (key.Open(hKeyRemoteRegistry, WINLOGONNT_KEY) == ERROR_SUCCESS))
  2251. {
  2252. size = 0;
  2253. if(key.QueryValue(trusted, DCACHE_VALUE, &size) == ERROR_SUCCESS)
  2254. {
  2255. trusted = new TCHAR[size + 1];
  2256. ATLASSERT(trusted != NULL);
  2257. if(trusted)
  2258. {
  2259. if(key.QueryValue(trusted, DCACHE_VALUE, &size) == ERROR_SUCCESS)
  2260. {
  2261. *list = trusted;
  2262. }
  2263. else
  2264. {
  2265. key.Close();
  2266. delete [] trusted;
  2267. trusted = NULL;
  2268. *list = NULL;
  2269. }
  2270. }
  2271. else
  2272. {
  2273. key.Close();
  2274. goto ABORT;
  2275. }
  2276. }
  2277. else
  2278. {
  2279. key.Close();
  2280. *list = NULL;
  2281. }
  2282. }
  2283. // VikasT
  2284. // Apparantely, on NT5 DCache doesn't exist. I found that there is a key
  2285. // under Winlogon named DomainCache that has all the cached domains.
  2286. // So, lets get that
  2287. //
  2288. //if(!(*list) && (RegOpenkeyEx(hKeyRemoteRegistry, DOMAINCACHE_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS))
  2289. //if(!(*list) && (RegOpenkey(hKeyRemoteRegistry, DOMAINCACHE_KEY, &hKey) == ERROR_SUCCESS))
  2290. if(!(*list) && (key.Open(hKeyRemoteRegistry, DOMAINCACHE_KEY) == ERROR_SUCCESS))
  2291. {
  2292. size = 0;
  2293. TCHAR * pszTemp = NULL;
  2294. TCHAR szTemp[MAX_PATH];
  2295. DWORD dwNumberOfValues = 0;
  2296. DWORD dwIndex = 0;
  2297. DWORD dwCharCount = MAX_PATH;
  2298. HRESULT hrResult = ERROR_SUCCESS;
  2299. hKey = HKEY(key);
  2300. //
  2301. // first find out how many values are present
  2302. //
  2303. hrResult = RegQueryInfoKey(
  2304. hKey, //handle of key to query
  2305. NULL, // address of buffer for class string
  2306. NULL, // address of size of class string buffer
  2307. NULL, // reserved
  2308. NULL, // address of buffer for number of subkeys
  2309. NULL, // address of buffer for longest subkey name length
  2310. NULL, // address of buffer for longest class string length
  2311. &dwNumberOfValues, // address of buffer for number of value entries
  2312. NULL, // address of buffer for longest value name length
  2313. NULL, // address of buffer for longest value data length
  2314. NULL, // address of buffer for security descriptor length
  2315. NULL // address of buffer for last write time
  2316. );
  2317. if(hrResult != ERROR_SUCCESS)
  2318. goto ABORT;
  2319. slValues.count = dwNumberOfValues;
  2320. slValues.strings = new LPTSTR[slValues.count];
  2321. ATLASSERT(slValues.strings != NULL);
  2322. if(slValues.strings == NULL)
  2323. goto ABORT;
  2324. ZeroMemory(slValues.strings, slValues.count * sizeof(LPTSTR));
  2325. for(dwIndex = 0;dwIndex<dwNumberOfValues;dwIndex++)
  2326. {
  2327. dwCharCount = MAX_PATH;
  2328. if(RegEnumValue(hKey, dwIndex, szTemp, &dwCharCount, NULL, NULL, NULL, NULL) == ERROR_NO_MORE_ITEMS)
  2329. break;
  2330. slValues.strings[dwIndex] = new TCHAR[dwCharCount+1];
  2331. ATLASSERT(slValues.strings[dwIndex] != NULL);
  2332. if(slValues.strings[dwIndex] == NULL)
  2333. goto ABORT;
  2334. ZeroMemory(slValues.strings[dwIndex], (dwCharCount+1) * sizeof(TCHAR));
  2335. _tcscpy(slValues.strings[dwIndex], szTemp);
  2336. // add up the return buffer size
  2337. size += dwCharCount+1;
  2338. }
  2339. if(dwNumberOfValues > 0)
  2340. {
  2341. trusted = new TCHAR[size + 1];
  2342. ATLASSERT(trusted != NULL);
  2343. if( trusted == NULL )
  2344. {
  2345. goto ABORT;
  2346. }
  2347. ZeroMemory(trusted, (size+1)*sizeof(TCHAR));
  2348. pszTemp = trusted;
  2349. for(dwIndex = 0;dwIndex<slValues.count;dwIndex++)
  2350. {
  2351. _tcscpy(pszTemp, slValues.strings[dwIndex]);
  2352. pszTemp += _tcslen(slValues.strings[dwIndex]) + 1;
  2353. }
  2354. }
  2355. *list = trusted;
  2356. size = dwNumberOfValues;
  2357. }
  2358. goto Done;
  2359. ABORT:
  2360. // set the return value;
  2361. size = (DWORD)-1;
  2362. if(*primary != NULL)
  2363. {
  2364. delete [] *primary;
  2365. *primary = NULL;
  2366. }
  2367. if(trusted != NULL)
  2368. {
  2369. delete [] trusted;
  2370. trusted = NULL;
  2371. }
  2372. if(cache != NULL)
  2373. {
  2374. delete [] cache;
  2375. cache = NULL;
  2376. }
  2377. Done:
  2378. if (hKeyRemoteRegistry != NULL)
  2379. {
  2380. RegCloseKey(hKeyRemoteRegistry);
  2381. hKeyRemoteRegistry = NULL;
  2382. }
  2383. if(hKey != NULL)
  2384. {
  2385. RegCloseKey(hKey);
  2386. hKey = NULL;
  2387. key.m_hKey = NULL;
  2388. }
  2389. HelperFreeStringList(&slValues);
  2390. return size;
  2391. }
  2392. /*
  2393. Description:
  2394. This function will try to load the string from XPSP1RES.DLL if the dll is present. Else
  2395. it will try to load from the normal resource dll. If that fails, it will copy the English string
  2396. into the destination buffer
  2397. Parameters:
  2398. [in] Message ID of the resource string to be loaded.
  2399. [out] Destination string.
  2400. [in] Maximum size of destination buffer.
  2401. [in] English string to be copied if everything else fails
  2402. Return value:
  2403. Number of TCHARs.
  2404. */
  2405. int TnLoadString(int msg_id, LPTSTR string, int max_size_of_buffer, LPCTSTR english_string)
  2406. {
  2407. int retval = 0;
  2408. //try loading from cladmin.dll or the image itself
  2409. if(g_hResource)
  2410. {
  2411. retval = LoadString(g_hResource,msg_id,string,max_size_of_buffer);
  2412. if(retval != 0)
  2413. goto Done; //Resource string loaded from the cladmin.dll or image.
  2414. }
  2415. //Try loading from XP Res dll only if the OS version is XP
  2416. if(g_hXPResource)
  2417. {
  2418. retval = LoadString(g_hXPResource,msg_id,string,max_size_of_buffer);
  2419. if(retval != 0)
  2420. goto Done; //Resource string loaded from xpsp1res.dll
  2421. }
  2422. //Everything failed. Copy the English string and set retval to number of characters
  2423. //in English string
  2424. _tcsncpy(string,english_string,max_size_of_buffer-1);
  2425. string[max_size_of_buffer-1] = _T('\0');
  2426. retval = _tcslen(english_string);
  2427. Done:
  2428. return retval;
  2429. }