Leaked source code of windows server 2003
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.

841 lines
21 KiB

  1. //++
  2. //
  3. // Copyright (C) Microsoft Corporation, 1987 - 1999
  4. //
  5. // Module Name:
  6. //
  7. // ndutils.c
  8. //
  9. // Abstract:
  10. //
  11. // Queries into network drivers
  12. //
  13. // Author:
  14. //
  15. // Anilth - 4-20-1998
  16. //
  17. // Environment:
  18. //
  19. // User mode only.
  20. // Contains NT-specific code.
  21. //
  22. // Revision History:
  23. //
  24. //--
  25. #include "precomp.h"
  26. #include "global.h"
  27. #include <ntstatus.dbg>
  28. #include <winerror.dbg>
  29. #include "ipcfg.h"
  30. #define MAX_NET_STATUS_LENGTH 80
  31. #define MAX_WINERR_SIZE 80
  32. const TCHAR c_szSectionName[] = _T("NetDiagContact");
  33. const TCHAR c_szFileName[] = _T("NdContact.ini");
  34. HRESULT HResultFromWin32(DWORD dwErr)
  35. {
  36. return HRESULT_FROM_WIN32(dwErr);
  37. }
  38. LPTSTR Win32ErrorToString(DWORD Id)
  39. {
  40. int i = 0;
  41. static TCHAR s_szWinerr[MAX_WINERR_SIZE + 1];
  42. while (winerrorSymbolicNames[ i ].SymbolicName)
  43. {
  44. if (winerrorSymbolicNames[ i ].MessageId == Id)
  45. {
  46. _tcsncpy( s_szWinerr, A2T(winerrorSymbolicNames[ i ].SymbolicName),
  47. MAX_WINERR_SIZE);
  48. return s_szWinerr;
  49. }
  50. else
  51. {
  52. i ++;
  53. }
  54. }
  55. //if we reach here, then we cannot find the Win32 Error string
  56. _stprintf(s_szWinerr, _T("%X"), (DWORD)Id);
  57. return s_szWinerr;
  58. }
  59. LPSTR
  60. FindSymbolicNameForStatus(
  61. DWORD Id
  62. )
  63. {
  64. ULONG i;
  65. i = 0;
  66. if (Id == 0) {
  67. return "STATUS_SUCCESS";
  68. }
  69. if (Id & 0xC0000000) {
  70. while (ntstatusSymbolicNames[ i ].SymbolicName) {
  71. if (ntstatusSymbolicNames[ i ].MessageId == (NTSTATUS)Id) {
  72. return ntstatusSymbolicNames[ i ].SymbolicName;
  73. } else {
  74. i += 1;
  75. }
  76. }
  77. }
  78. i = 0;
  79. while (winerrorSymbolicNames[ i ].SymbolicName) {
  80. if (winerrorSymbolicNames[ i ].MessageId == Id) {
  81. return winerrorSymbolicNames[ i ].SymbolicName;
  82. } else {
  83. i += 1;
  84. }
  85. }
  86. #ifdef notdef
  87. while (neteventSymbolicNames[ i ].SymbolicName) {
  88. if (neteventSymbolicNames[ i ].MessageId == Id) {
  89. return neteventSymbolicNames[ i ].SymbolicName
  90. } else {
  91. i += 1;
  92. }
  93. }
  94. #endif // notdef
  95. return NULL;
  96. }
  97. VOID
  98. PrintSid(
  99. IN NETDIAG_PARAMS *pParams,
  100. IN PSID Sid OPTIONAL
  101. )
  102. /*++
  103. Routine Description:
  104. Prints a SID
  105. Arguments:
  106. Sid - SID to output
  107. Return Value:
  108. none
  109. --*/
  110. {
  111. if ( Sid == NULL )
  112. {
  113. //IDS_UTIL_SID_NULL "(null)\n"
  114. PrintMessage(pParams, IDS_UTIL_SID_NULL);
  115. }
  116. else
  117. {
  118. UNICODE_STRING SidString;
  119. NTSTATUS Status;
  120. Status = RtlConvertSidToUnicodeString( &SidString, Sid, TRUE );
  121. if ( !NT_SUCCESS(Status) )
  122. {
  123. //IDS_UTIL_SID_INVALID "Invalid 0x%lX\n"
  124. PrintMessage(pParams, IDS_UTIL_SID_INVALID, Status);
  125. }
  126. else
  127. {
  128. //IDS_GLOBAL_UNICODE_STRING "%wZ"
  129. PrintMessage(pParams, IDS_GLOBAL_UNICODE_STRING, &SidString);
  130. PrintNewLine(pParams, 1);
  131. RtlFreeUnicodeString( &SidString );
  132. }
  133. }
  134. }
  135. NET_API_STATUS
  136. IsServiceStarted(
  137. IN LPTSTR pszServiceName
  138. )
  139. /*++
  140. Routine Description:
  141. This routine queries the Service Controller to find out if the
  142. specified service has been started.
  143. Arguments:
  144. pszServiceName - Supplies the name of the service.
  145. Return Value:
  146. NO_ERROR: if the specified service has been started
  147. -1: the service was stopped normally
  148. Otherwise returns the reason the service isn't running.
  149. --*/
  150. {
  151. NET_API_STATUS NetStatus;
  152. SC_HANDLE hScManager;
  153. SC_HANDLE hService;
  154. SERVICE_STATUS ServiceStatus;
  155. if ((hScManager = OpenSCManager(
  156. NULL,
  157. NULL,
  158. SC_MANAGER_CONNECT
  159. )) == (SC_HANDLE) NULL) {
  160. NetStatus = GetLastError();
  161. DebugMessage2(" IsServiceStarted(): OpenSCManager failed. [%s]\n", NetStatusToString(NetStatus));
  162. return NetStatus;
  163. }
  164. if ((hService = OpenService(
  165. hScManager,
  166. pszServiceName,
  167. SERVICE_QUERY_STATUS
  168. )) == (SC_HANDLE) NULL)
  169. {
  170. NetStatus = GetLastError();
  171. DebugMessage3(" IsServiceStarted(): OpenService '%s' failed. [%s]\n",
  172. pszServiceName, NetStatusToString(NetStatus) );
  173. (void) CloseServiceHandle(hScManager);
  174. return NetStatus;
  175. }
  176. if (! QueryServiceStatus(
  177. hService,
  178. &ServiceStatus
  179. )) {
  180. NetStatus = GetLastError();
  181. DebugMessage3(" IsServiceStarted(): QueryServiceStatus '%s' failed. [%s]\n",
  182. pszServiceName, NetStatusToString(NetStatus) );
  183. (void) CloseServiceHandle(hScManager);
  184. (void) CloseServiceHandle(hService);
  185. return NetStatus;
  186. }
  187. (void) CloseServiceHandle(hScManager);
  188. (void) CloseServiceHandle(hService);
  189. switch ( ServiceStatus.dwCurrentState )
  190. {
  191. case SERVICE_RUNNING:
  192. case SERVICE_CONTINUE_PENDING:
  193. case SERVICE_PAUSE_PENDING:
  194. case SERVICE_PAUSED:
  195. NetStatus = NO_ERROR;
  196. break;
  197. case SERVICE_STOPPED:
  198. case SERVICE_START_PENDING:
  199. case SERVICE_STOP_PENDING:
  200. if ( ServiceStatus.dwWin32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR )
  201. {
  202. NetStatus = ServiceStatus.dwServiceSpecificExitCode;
  203. if ( NetStatus == NO_ERROR )
  204. {
  205. NetStatus = ServiceStatus.dwWin32ExitCode;
  206. }
  207. }
  208. else
  209. {
  210. NetStatus = ServiceStatus.dwWin32ExitCode;
  211. if ( NetStatus == NO_ERROR )
  212. {
  213. NetStatus = -1;
  214. }
  215. }
  216. break;
  217. default:
  218. NetStatus = ERROR_INTERNAL_ERROR;
  219. break;
  220. }
  221. return NetStatus;
  222. } // IsServiceStarted
  223. LPSTR MapTime(DWORD_PTR TimeVal)
  224. //++
  225. //
  226. // Description:
  227. // Converts IP lease time to more human-sensible string
  228. //
  229. // ENTRY TimeVal - DWORD (time_t) time value (number of milliseconds since
  230. // virtual year dot)
  231. //
  232. //
  233. // RETURNS pointer to string
  234. //
  235. // ASSUMES 1. The caller realizes this function returns a pointer to a static
  236. // buffer, hence calling this function a second time, but before
  237. // the results from the previous call have been used, will destroy
  238. // the previous results
  239. //--
  240. {
  241. struct tm* pTime;
  242. static char timeBuf[128];
  243. static char oemTimeBuf[256];
  244. if (pTime = localtime(&TimeVal)) {
  245. SYSTEMTIME systemTime;
  246. char* pTimeBuf = timeBuf;
  247. int n;
  248. systemTime.wYear = pTime->tm_year + 1900;
  249. systemTime.wMonth = pTime->tm_mon + 1;
  250. systemTime.wDayOfWeek = (WORD)pTime->tm_wday;
  251. systemTime.wDay = (WORD)pTime->tm_mday;
  252. systemTime.wHour = (WORD)pTime->tm_hour;
  253. systemTime.wMinute = (WORD)pTime->tm_min;
  254. systemTime.wSecond = (WORD)pTime->tm_sec;
  255. systemTime.wMilliseconds = 0;
  256. n = GetDateFormat(0, DATE_LONGDATE, &systemTime, NULL, timeBuf, sizeof(timeBuf));
  257. timeBuf[n - 1] = ' ';
  258. GetTimeFormat(0, 0, &systemTime, NULL, &timeBuf[n], sizeof(timeBuf) - n);
  259. //
  260. // we have to convert the returned ANSI string to the OEM charset
  261. //
  262. //
  263. if (CharToOem(timeBuf, oemTimeBuf)) {
  264. return oemTimeBuf;
  265. }
  266. return timeBuf;
  267. }
  268. return "";
  269. }
  270. //used in DCListTest and TrustTest
  271. NTSTATUS
  272. NettestSamConnect(
  273. IN NETDIAG_PARAMS *pParams,
  274. IN LPWSTR DcName,
  275. OUT PSAM_HANDLE SamServerHandle
  276. )
  277. /*++
  278. Routine Description:
  279. Determine if the DomainSid field of the TestDomain matches the DomainSid
  280. of the domain.
  281. Arguments:
  282. DcName - Dc to connect to
  283. SamServerHandle - Returns a Sam server handle
  284. Return Value:
  285. TRUE: Test suceeded.
  286. FALSE: Test failed
  287. --*/
  288. {
  289. NET_API_STATUS NetStatus;
  290. NTSTATUS Status;
  291. UNICODE_STRING ServerNameString;
  292. SAM_HANDLE LocalSamHandle = NULL;
  293. BOOL fImpersonatingAnonymous = FALSE;
  294. HANDLE hCurrentToken;
  295. //
  296. // Connect to the SAM server
  297. //
  298. RtlInitUnicodeString( &ServerNameString, DcName );
  299. Status = SamConnect(
  300. &ServerNameString,
  301. &LocalSamHandle,
  302. SAM_SERVER_LOOKUP_DOMAIN,
  303. NULL);
  304. //
  305. // Consider the case where we don't have access to the DC.
  306. // We might be logged on locally due to the domain sid being wrong.
  307. //
  308. if ( Status == STATUS_ACCESS_DENIED ) {
  309. //
  310. // Try impersonating the anonymous token.
  311. //
  312. //
  313. // Check to see if we're already impsonating
  314. //
  315. Status = NtOpenThreadToken(
  316. NtCurrentThread(),
  317. TOKEN_IMPERSONATE,
  318. TRUE, // as self to ensure we never fail
  319. &hCurrentToken );
  320. if ( Status == STATUS_NO_TOKEN ) {
  321. //
  322. // We're not already impersonating
  323. hCurrentToken = NULL;
  324. } else if ( !NT_SUCCESS( Status) ) {
  325. PrintGuruMessage(" [WARNING] Cannot NtOpenThreadToken" );
  326. PrintGuru( NetpNtStatusToApiStatus( Status ), SAM_GURU );
  327. goto Cleanup;
  328. }
  329. //
  330. // Impersonate the anonymous token
  331. //
  332. Status = NtImpersonateAnonymousToken( NtCurrentThread() );
  333. if ( !NT_SUCCESS( Status)) {
  334. PrintGuruMessage(" [WARNING] Cannot NtOpenThreadToken" );
  335. PrintGuru( NetpNtStatusToApiStatus( Status ), SAM_GURU );
  336. goto Cleanup;
  337. }
  338. fImpersonatingAnonymous = TRUE;
  339. //
  340. // Try the SamConnect again
  341. //
  342. Status = SamConnect(
  343. &ServerNameString,
  344. &LocalSamHandle,
  345. SAM_SERVER_LOOKUP_DOMAIN,
  346. NULL);
  347. if ( Status == STATUS_ACCESS_DENIED ) {
  348. // One can configure SAM this way so it isn't fatal
  349. DebugMessage2(" [WARNING] Cannot connect to SAM on '%ws' using a NULL session.", DcName );
  350. goto Cleanup;
  351. }
  352. }
  353. if ( !NT_SUCCESS(Status)) {
  354. LocalSamHandle = NULL;
  355. DebugMessage2(" [FATAL] Cannot connect to SAM on '%ws'.", DcName );
  356. goto Cleanup;
  357. }
  358. //
  359. // Success
  360. //
  361. *SamServerHandle = LocalSamHandle;
  362. Status = STATUS_SUCCESS;
  363. //
  364. // Cleanup locally used resources
  365. //
  366. Cleanup:
  367. if ( fImpersonatingAnonymous ) {
  368. NTSTATUS TempStatus;
  369. TempStatus = NtSetInformationThread(
  370. NtCurrentThread(),
  371. ThreadImpersonationToken,
  372. &hCurrentToken,
  373. sizeof(HANDLE) );
  374. if (!NT_SUCCESS( TempStatus)) {
  375. DebugMessage2( "SamConnect: Unexpected error reverting to self: 0x%lx\n",
  376. TempStatus );
  377. }
  378. }
  379. return Status;
  380. }
  381. //only used in Kerberos test so far
  382. VOID
  383. sPrintTime(
  384. LPSTR str,
  385. LARGE_INTEGER ConvertTime
  386. )
  387. /*++
  388. Routine Description:
  389. Print the specified time
  390. Arguments:
  391. Comment - Comment to print in front of the time
  392. Time - GMT time to print (Nothing is printed if this is zero)
  393. Return Value:
  394. None
  395. --*/
  396. {
  397. //
  398. // If we've been asked to convert an NT GMT time to ascii,
  399. // Do so
  400. //
  401. if ( ConvertTime.QuadPart != 0 ) {
  402. LARGE_INTEGER LocalTime;
  403. TIME_FIELDS TimeFields;
  404. NTSTATUS Status;
  405. Status = RtlSystemTimeToLocalTime( &ConvertTime, &LocalTime );
  406. if ( !NT_SUCCESS( Status )) {
  407. sprintf(str, "Can't convert time from GMT to Local time" );
  408. LocalTime = ConvertTime;
  409. }
  410. RtlTimeToTimeFields( &LocalTime, &TimeFields );
  411. sprintf(str, "%ld/%ld/%ld %ld:%2.2ld:%2.2ld",
  412. TimeFields.Month,
  413. TimeFields.Day,
  414. TimeFields.Year,
  415. TimeFields.Hour,
  416. TimeFields.Minute,
  417. TimeFields.Second );
  418. }
  419. }
  420. /*!--------------------------------------------------------------------------
  421. GetComputerNameInfo
  422. -
  423. Author: KennT
  424. ---------------------------------------------------------------------------*/
  425. HRESULT GetComputerNameInfo(NETDIAG_PARAMS *pParams, NETDIAG_RESULT *pResults)
  426. {
  427. DWORD cchSize;
  428. WCHAR swzNetBiosName[MAX_COMPUTERNAME_LENGTH+1];
  429. cchSize = DimensionOf(swzNetBiosName);
  430. if ( !GetComputerNameW( swzNetBiosName, &cchSize ) )
  431. {
  432. PrintMessage(pParams, IDS_GLOBAL_NoComputerName);
  433. return HResultFromWin32(GetLastError());
  434. }
  435. lstrcpynW(pResults->Global.swzNetBiosName, swzNetBiosName,
  436. MAX_COMPUTERNAME_LENGTH+1);
  437. return hrOK;
  438. }
  439. /*!--------------------------------------------------------------------------
  440. GetDNSInfo
  441. -
  442. Author: KennT
  443. ---------------------------------------------------------------------------*/
  444. HRESULT GetDNSInfo(NETDIAG_PARAMS *pParams, NETDIAG_RESULT *pResults)
  445. {
  446. UINT cchSize;
  447. TCHAR szDnsName[DNS_MAX_NAME_LENGTH+1];
  448. HRESULT hr = hrOK;
  449. //
  450. // Get the DNS host name.
  451. //
  452. memset(szDnsName,0,sizeof(TCHAR)*(DNS_MAX_NAME_LENGTH+1));
  453. cchSize = DimensionOf(szDnsName);
  454. if (!GetComputerNameExA( ComputerNameDnsFullyQualified,
  455. szDnsName,
  456. &cchSize))
  457. {
  458. PrintMessage(pParams, IDS_GLOBAL_ERR_NoDnsName);
  459. }
  460. else
  461. {
  462. lstrcpyn(pResults->Global.szDnsHostName, szDnsName, DNS_MAX_NAME_LENGTH+1);
  463. // Look for the first '.' in the name
  464. pResults->Global.pszDnsDomainName = strchr(pResults->Global.szDnsHostName,
  465. _T('.'));
  466. if (pResults->Global.pszDnsDomainName != NULL)
  467. {
  468. pResults->Global.pszDnsDomainName++;
  469. }
  470. }
  471. return hr;
  472. }
  473. /*!--------------------------------------------------------------------------
  474. GetNetBTParameters
  475. -
  476. Author: KennT
  477. ---------------------------------------------------------------------------*/
  478. HRESULT GetNetBTParameters(IN NETDIAG_PARAMS *pParams,
  479. IN OUT NETDIAG_RESULT *pResults)
  480. {
  481. LONG err;
  482. HRESULT hr = hrOK;
  483. HKEY hkeyServices;
  484. HKEY hkeyNetBT;
  485. DWORD dwLMHostsEnabled;
  486. DWORD dwDnsForWINS;
  487. DWORD dwType;
  488. DWORD dwLength;
  489. if (!pParams->fVerbose)
  490. return hrOK;
  491. // set defaults
  492. pResults->Global.dwLMHostsEnabled = E_FAIL;
  493. pResults->Global.dwDnsForWINS = E_FAIL;
  494. err = RegOpenKey(HKEY_LOCAL_MACHINE,
  495. _T("SYSTEM\\CurrentControlSet\\Services"),
  496. &hkeyServices
  497. );
  498. if (err != ERROR_SUCCESS)
  499. {
  500. pResults->Global.dwLMHostsEnabled = HResultFromWin32(err);
  501. pResults->Global.dwDnsForWINS = HResultFromWin32(err);
  502. PrintDebugSz(pParams, 0, _T("Services opening failed\n"));
  503. }
  504. else
  505. {
  506. err = RegOpenKey(hkeyServices,
  507. _T("NetBT\\Parameters"),
  508. &hkeyNetBT
  509. );
  510. if (err != ERROR_SUCCESS)
  511. {
  512. pResults->Global.dwLMHostsEnabled = HResultFromWin32(err);
  513. pResults->Global.dwDnsForWINS = HResultFromWin32(err);
  514. PrintDebugSz(pParams, 0, _T("Parameters opening failed\n"));
  515. }
  516. else
  517. {
  518. dwLength = sizeof(DWORD);
  519. err = RegQueryValueEx(hkeyNetBT,
  520. _T("EnableLMHOSTS"),
  521. NULL,
  522. &dwType,
  523. (LPBYTE)&dwLMHostsEnabled,
  524. &dwLength
  525. );
  526. if (err != ERROR_SUCCESS)
  527. {
  528. pResults->Global.dwLMHostsEnabled = HResultFromWin32(err);
  529. DebugMessage("Quering EnableLMHOSTS failed !\n");
  530. }
  531. else
  532. {
  533. pResults->Global.dwLMHostsEnabled = dwLMHostsEnabled;
  534. }
  535. //
  536. // In NT 5.0 - Dns for wins resolution is enabled by
  537. // default and the "EnableDNS" key will not be found.
  538. // If it is not found, we will assume its enabled.
  539. // In NT 4.0 - the key will be there and its value
  540. // should let us know whether the option is enabled
  541. // or disabled
  542. //
  543. dwLength = sizeof(DWORD);
  544. err = RegQueryValueEx(hkeyNetBT,
  545. "EnableDNS",
  546. NULL,
  547. &dwType,
  548. (LPBYTE)&dwDnsForWINS,
  549. &dwLength
  550. );
  551. if (err == ERROR_SUCCESS)
  552. {
  553. pResults->Global.dwDnsForWINS = dwDnsForWINS;
  554. }
  555. else
  556. {
  557. pResults->Global.dwDnsForWINS = TRUE;
  558. }
  559. }
  560. }
  561. return hrOK;
  562. }
  563. ULONG inet_addrW(LPCWSTR pswz)
  564. {
  565. ULONG ulReturn;
  566. CHAR * psaz;
  567. psaz = StrDupAFromW(pswz);
  568. if (psaz == NULL)
  569. return 0;
  570. ulReturn = inet_addrA(psaz);
  571. Free(psaz);
  572. return ulReturn;
  573. }
  574. LPTSTR
  575. NetStatusToString(
  576. NET_API_STATUS NetStatus
  577. )
  578. /*++
  579. Routine Description:
  580. Conver a net status code or a Windows error code to the description string.
  581. NOTE: The string is garuanteed to be valid only right after NetStatusToString is called.
  582. Arguments:
  583. NetStatus - The net status code to print.
  584. Return Value:
  585. The status description string
  586. --*/
  587. {
  588. static TCHAR s_szSymbolicName[MAX_NET_STATUS_LENGTH + 1];
  589. ZeroMemory(s_szSymbolicName, sizeof(s_szSymbolicName));
  590. switch (NetStatus)
  591. {
  592. case NERR_Success:
  593. _tcscpy( s_szSymbolicName, _T("NERR_Success") );
  594. break;
  595. case NERR_DCNotFound:
  596. _tcscpy( s_szSymbolicName, _T("NERR_DCNotFound") );
  597. break;
  598. case NERR_UserNotFound:
  599. _tcscpy( s_szSymbolicName, _T("NERR_UserNotFound") );
  600. break;
  601. case NERR_NetNotStarted:
  602. _tcscpy( s_szSymbolicName, _T("NERR_NetNotStarted") );
  603. break;
  604. case NERR_WkstaNotStarted:
  605. _tcscpy( s_szSymbolicName, _T("NERR_WkstaNotStarted") );
  606. break;
  607. case NERR_ServerNotStarted:
  608. _tcscpy( s_szSymbolicName, _T("NERR_ServerNotStarted") );
  609. break;
  610. case NERR_BrowserNotStarted:
  611. _tcscpy( s_szSymbolicName, _T("NERR_BrowserNotStarted") );
  612. break;
  613. case NERR_ServiceNotInstalled:
  614. _tcscpy( s_szSymbolicName, _T("NERR_ServiceNotInstalled") );
  615. break;
  616. case NERR_BadTransactConfig:
  617. _tcscpy( s_szSymbolicName, _T("NERR_BadTransactConfig") );
  618. break;
  619. default:
  620. {
  621. LPSTR paszName = FindSymbolicNameForStatus( NetStatus );
  622. USES_CONVERSION;
  623. if (NULL == paszName)
  624. {
  625. _stprintf(s_szSymbolicName, _T("%X"), (DWORD)NetStatus);
  626. }
  627. else
  628. {
  629. _tcsncpy( s_szSymbolicName, A2T(paszName), MAX_NET_STATUS_LENGTH);
  630. }
  631. }
  632. break;
  633. }
  634. return s_szSymbolicName;
  635. }
  636. //Load contact info from the [NetDiagContact] section of the ini file.
  637. // pszTestName [in] short name of the test, which is also the key name in the ini file
  638. // pszContactInfo [out] the string of contact info. It will be empty string of the key cannot be found.
  639. // cChSize [in] the buffer size, in characters, of pszContactInfo
  640. //
  641. // return: the number of characters copied to the buffer.
  642. DWORD LoadContact(LPCTSTR pszTestName, LPTSTR pszContactInfo, DWORD cChSize)
  643. {
  644. return GetPrivateProfileString(c_szSectionName,
  645. pszTestName,
  646. _T(""),
  647. pszContactInfo,
  648. cChSize,
  649. c_szFileName);
  650. }