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.

380 lines
11 KiB

  1. //++
  2. //
  3. // Copyright (C) Microsoft Corporation, 1987 - 1999
  4. //
  5. // Module Name:
  6. //
  7. // kerberos.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. HRESULT KerberosTest( NETDIAG_PARAMS* pParams, NETDIAG_RESULT* pResults)
  27. {
  28. HRESULT hr = S_OK;
  29. PTESTED_DOMAIN Context = pParams->pDomain;
  30. NET_API_STATUS NetStatus;
  31. NTSTATUS Status;
  32. BOOL RetVal = TRUE;
  33. HANDLE LogonHandle = NULL;
  34. STRING Name;
  35. ULONG PackageId;
  36. KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;
  37. PKERB_QUERY_TKT_CACHE_RESPONSE CacheResponse = NULL;
  38. ULONG ResponseSize;
  39. NTSTATUS SubStatus;
  40. ULONG Index;
  41. WCHAR KrbtgtOldTicketName[MAX_PATH+1];
  42. UNICODE_STRING KrbtgtOldTicketNameString;
  43. WCHAR KrbtgtTicketName[MAX_PATH+1];
  44. UNICODE_STRING KrbtgtTicketNameString;
  45. BOOLEAN KrbtgtTicketFound = FALSE;
  46. WCHAR OurMachineOldTicketName[MAX_PATH+1];
  47. UNICODE_STRING OurMachineOldTicketNameString;
  48. WCHAR OurMachineTicketName[MAX_PATH+1];
  49. UNICODE_STRING OurMachineTicketNameString;
  50. BOOLEAN OurMachineTicketFound = FALSE;
  51. TCHAR endTime[MAX_PATH]; // though MAX_PATH is not directly related to time, it's sufficient
  52. TCHAR renewTime[MAX_PATH];
  53. PTESTED_DOMAIN TestedDomain;
  54. LPWSTR pwszDnsHostName;
  55. InitializeListHead(&pResults->Kerberos.lmsgOutput);
  56. PrintStatusMessage(pParams, 4, IDS_KERBEROS_STATUS_MSG);
  57. //
  58. // Only Members and Domain controllers use Kerberos.
  59. //
  60. if (!( pResults->Global.pPrimaryDomainInfo->MachineRole == DsRole_RoleMemberWorkstation ||
  61. pResults->Global.pPrimaryDomainInfo->MachineRole == DsRole_RoleMemberServer ||
  62. pResults->Global.pPrimaryDomainInfo->MachineRole == DsRole_RoleBackupDomainController ||
  63. pResults->Global.pPrimaryDomainInfo->MachineRole == DsRole_RolePrimaryDomainController ))
  64. {
  65. PrintStatusMessage(pParams, 0, IDS_GLOBAL_SKIP_NL);
  66. pResults->Kerberos.fPerformed = FALSE;
  67. return hr;
  68. }
  69. //if there is no GUID for the primary domain, then it is NOT W2k domain
  70. if (! (pResults->Global.pPrimaryDomainInfo->Flags & DSROLE_PRIMARY_DOMAIN_GUID_PRESENT))
  71. {
  72. AddIMessageToList(&pResults->Kerberos.lmsgOutput, Nd_Quiet, 0, IDS_KERBEROS_NOT_W2K_PRIMARY_DOMAIN);
  73. goto L_ERR;
  74. }
  75. //
  76. // If we're logged onto a local account,
  77. // we can't test kerberos.
  78. //
  79. if ( pResults->Global.pLogonDomain == NULL )
  80. {
  81. AddIMessageToList(&pResults->Kerberos.lmsgOutput, Nd_Quiet, 0, IDS_KERBEROS_LOCALUSER);
  82. goto L_ERR;
  83. }
  84. TestedDomain = pResults->Global.pLogonDomain;
  85. //
  86. // If we're logged with cached credentials,
  87. // we can't test kerberos.
  88. //
  89. if ( pResults->Global.fLogonWithCachedCredentials )
  90. {
  91. AddIMessageToList(&pResults->Kerberos.lmsgOutput, Nd_Quiet, 0, IDS_KERBEROS_CACHED);
  92. goto L_ERR;
  93. }
  94. //
  95. // If a DC hasn't been discovered yet,
  96. // find one.
  97. //
  98. if ( TestedDomain->DcInfo == NULL )
  99. {
  100. LPTSTR pszDcType;
  101. if ( TestedDomain->fTriedToFindDcInfo ) {
  102. RetVal = FALSE;
  103. //IDS_DCLIST_NO_DC " '%ws': Cannot find DC to get DC list from (Test skipped).\n"
  104. AddMessageToList(&pResults->Kerberos.lmsgOutput, Nd_Quiet,
  105. IDS_DCLIST_NO_DC, TestedDomain->PrintableDomainName);
  106. goto L_ERR;
  107. }
  108. pszDcType = LoadAndAllocString(IDS_DCTYPE_DC);
  109. NetStatus = DoDsGetDcName( pParams,
  110. pResults,
  111. &pResults->Kerberos.lmsgOutput,
  112. TestedDomain,
  113. DS_DIRECTORY_SERVICE_PREFERRED,
  114. pszDcType, //"DC",
  115. FALSE,
  116. &TestedDomain->DcInfo );
  117. Free(pszDcType);
  118. TestedDomain->fTriedToFindDcInfo = TRUE;
  119. if ( NetStatus != NO_ERROR )
  120. {
  121. RetVal = FALSE;
  122. AddIMessageToList(&pResults->Kerberos.lmsgOutput, Nd_Quiet, 0, IDS_KERBEROS_NODC);
  123. CHK_HR_CONTEXT(pResults->Kerberos, hr = HRESULT_FROM_WIN32(NetStatus), 0);
  124. }
  125. }
  126. //
  127. // If we're logged onto an account in an NT 4 domain,
  128. // we can't test kerberos.
  129. //
  130. if ( (TestedDomain->DcInfo->Flags & DS_KDC_FLAG) == 0 )
  131. {
  132. AddIMessageToList(&pResults->Kerberos.lmsgOutput, Nd_Quiet, 0, IDS_KERBEROS_NOKDC, pResults->Global.pLogonDomainName, pResults->Global.pLogonUser );
  133. goto L_ERR;
  134. }
  135. pResults->Kerberos.fPerformed = TRUE;
  136. //
  137. // Connect to the LSA.
  138. //
  139. Status = LsaConnectUntrusted( &LogonHandle );
  140. if (!NT_SUCCESS(Status)) {
  141. RetVal = FALSE;
  142. CHK_HR_CONTEXT(pResults->Kerberos, hr = HRESULT_FROM_WIN32(Status), IDS_KERBEROS_NOLSA);
  143. }
  144. RtlInitString( &Name, MICROSOFT_KERBEROS_NAME_A );
  145. Status = LsaLookupAuthenticationPackage(
  146. LogonHandle,
  147. &Name,
  148. &PackageId );
  149. if (!NT_SUCCESS(Status)) {
  150. RetVal = FALSE;
  151. //IDS_KERBEROS_NOPACKAGE " [FATAL] Cannot lookup package %Z.\n"
  152. AddIMessageToList(&pResults->Kerberos.lmsgOutput, Nd_Quiet, 0, IDS_KERBEROS_NOPACKAGE, &Name);
  153. CHK_HR_CONTEXT(pResults->Kerberos, hr = HRESULT_FROM_WIN32(Status), IDS_KERBEROS_HRERROR);
  154. }
  155. //
  156. // Get the ticket cache from Kerberos.
  157. //
  158. CacheRequest.MessageType = KerbQueryTicketCacheMessage;
  159. CacheRequest.LogonId.LowPart = 0;
  160. CacheRequest.LogonId.HighPart = 0;
  161. Status = LsaCallAuthenticationPackage(
  162. LogonHandle,
  163. PackageId,
  164. &CacheRequest,
  165. sizeof(CacheRequest),
  166. (PVOID *) &CacheResponse,
  167. &ResponseSize,
  168. &SubStatus
  169. );
  170. if (!NT_SUCCESS(Status) || !NT_SUCCESS(SubStatus)) {
  171. AddIMessageToList(&pResults->Kerberos.lmsgOutput, Nd_Quiet, 0, IDS_KERBEROS_NOCACHE, &Name);
  172. RetVal = FALSE;
  173. if(!NT_SUCCESS(Status))
  174. {
  175. CHK_HR_CONTEXT(pResults->Kerberos, hr = HRESULT_FROM_WIN32(Status), IDS_KERBEROS_HRERROR);
  176. }
  177. else
  178. {
  179. CHK_HR_CONTEXT(pResults->Kerberos, hr = HRESULT_FROM_WIN32(SubStatus), IDS_KERBEROS_HRERROR);
  180. }
  181. }
  182. //
  183. // Build the names of some mandatory tickets.
  184. //
  185. wcscpy( KrbtgtOldTicketName, GetSafeStringW(pResults->Global.pPrimaryDomainInfo->DomainNameFlat) );
  186. wcscat( KrbtgtOldTicketName, L"\\krbtgt" );
  187. RtlInitUnicodeString( &KrbtgtOldTicketNameString, KrbtgtOldTicketName );
  188. wcscpy(KrbtgtTicketName, L"krbtgt" );
  189. wcscat(KrbtgtTicketName, L"/" );
  190. wcscat(KrbtgtTicketName, GetSafeStringW(pResults->Global.pPrimaryDomainInfo->DomainNameDns) );
  191. RtlInitUnicodeString( &KrbtgtTicketNameString, KrbtgtTicketName );
  192. wcscpy( OurMachineOldTicketName, GetSafeStringW(pResults->Global.pPrimaryDomainInfo->DomainNameFlat) );
  193. wcscat( OurMachineOldTicketName, L"\\" );
  194. wcscat( OurMachineOldTicketName, GetSafeStringW(pResults->Global.swzNetBiosName) );
  195. wcscat( OurMachineOldTicketName, L"$" );
  196. RtlInitUnicodeString( &OurMachineOldTicketNameString, OurMachineOldTicketName );
  197. // russw
  198. // Need to convert szDnsHostName from TCHAR to WCHAR
  199. pwszDnsHostName = StrDupWFromT(pResults->Global.szDnsHostName);
  200. wcscpy( OurMachineTicketName, L"host/");
  201. wcscat( OurMachineTicketName, GetSafeStringW(pwszDnsHostName));
  202. RtlInitUnicodeString( &OurMachineTicketNameString, OurMachineTicketName );
  203. Free (pwszDnsHostName);
  204. // old
  205. //wcscpy( OurMachineTicketName, GetSafeStringW(pResults->Global.szDnsHostName) );
  206. // wcscat( OurMachineTicketName, L"$" )
  207. //
  208. // Ensure those tickets are defined.
  209. //
  210. AddIMessageToList(&pResults->Kerberos.lmsgOutput, Nd_ReallyVerbose, 0, IDS_KERBEROS_CACHEDTICKER);
  211. for (Index = 0; Index < CacheResponse->CountOfTickets ; Index++ )
  212. {
  213. if ( RtlEqualUnicodeString( &CacheResponse->Tickets[Index].ServerName,
  214. &KrbtgtOldTicketNameString, TRUE )
  215. || RtlEqualUnicodeString( &CacheResponse->Tickets[Index].ServerName,
  216. &KrbtgtTicketNameString, TRUE ))
  217. {
  218. KrbtgtTicketFound = TRUE;
  219. }
  220. if ( RtlEqualUnicodeString( &CacheResponse->Tickets[Index].ServerName,
  221. &OurMachineOldTicketNameString, TRUE )
  222. || RtlEqualUnicodeString( &CacheResponse->Tickets[Index].ServerName,
  223. &OurMachineTicketNameString, TRUE ))
  224. {
  225. OurMachineTicketFound = TRUE;
  226. }
  227. AddIMessageToList(&pResults->Kerberos.lmsgOutput, Nd_ReallyVerbose, 0, IDS_KERBEROS_SERVER, &CacheResponse->Tickets[Index].ServerName);
  228. sPrintTime(endTime, CacheResponse->Tickets[Index].EndTime);
  229. sPrintTime(renewTime, CacheResponse->Tickets[Index].RenewTime);
  230. AddIMessageToList(&pResults->Kerberos.lmsgOutput, Nd_ReallyVerbose, 0, IDS_KERBEROS_ENDTIME, endTime);
  231. AddIMessageToList(&pResults->Kerberos.lmsgOutput, Nd_ReallyVerbose, 0, IDS_KERBEROS_RENEWTIME, renewTime);
  232. //
  233. // Complain if required tickets were not found.
  234. //
  235. }
  236. if ( !KrbtgtTicketFound )
  237. {
  238. AddIMessageToList(&pResults->Kerberos.lmsgOutput, Nd_Quiet, 0, IDS_KERBEROS_NOTICKET, KrbtgtTicketName);
  239. RetVal = FALSE;
  240. }
  241. if ( !OurMachineTicketFound )
  242. {
  243. AddIMessageToList(&pResults->Kerberos.lmsgOutput, Nd_Quiet, 0, IDS_KERBEROS_NOTICKET, OurMachineTicketName);
  244. RetVal = FALSE;
  245. }
  246. //
  247. // Let subsequent tests know that kerberos is working.
  248. //
  249. if ( RetVal )
  250. {
  251. pResults->Global.fKerberosIsWorking = TRUE;
  252. }
  253. L_ERR:
  254. if (LogonHandle != NULL)
  255. {
  256. LsaDeregisterLogonProcess(LogonHandle);
  257. }
  258. if (CacheResponse != NULL)
  259. {
  260. LsaFreeReturnBuffer(CacheResponse);
  261. }
  262. if (!RetVal && hr == S_OK)
  263. {
  264. pResults->Kerberos.hr = hr = E_FAIL;
  265. PrintStatusMessage(pParams, 0, IDS_GLOBAL_FAIL_NL);
  266. }
  267. else
  268. {
  269. PrintStatusMessage(pParams, 0, IDS_GLOBAL_PASS_NL);
  270. }
  271. return S_OK;
  272. }
  273. void KerberosGlobalPrint(IN NETDIAG_PARAMS *pParams, IN OUT NETDIAG_RESULT *pResults)
  274. {
  275. if (pParams->fVerbose || !FHrOK(pResults->Kerberos.hr))
  276. {
  277. PrintNewLine(pParams, 2);
  278. PrintTestTitleResult(pParams, IDS_KERBEROS_LONG, IDS_KERBEROS_SHORT, pResults->Kerberos.fPerformed,
  279. pResults->Kerberos.hr, 0);
  280. if (pParams->fReallyVerbose || !FHrOK(pResults->Kerberos.hr))
  281. PrintMessageList(pParams, &pResults->Kerberos.lmsgOutput);
  282. if (!FHrOK(pResults->Kerberos.hr))
  283. {
  284. if(pResults->Kerberos.idsContext)
  285. PrintError(pParams, pResults->Kerberos.idsContext, pResults->Kerberos.hr);
  286. }
  287. }
  288. }
  289. void KerberosPerInterfacePrint(IN NETDIAG_PARAMS *pParams,
  290. IN OUT NETDIAG_RESULT *pResults,
  291. IN INTERFACE_RESULT *pIfResult)
  292. {
  293. // no perinterface information
  294. }
  295. void KerberosCleanup(IN NETDIAG_PARAMS *pParams,
  296. IN OUT NETDIAG_RESULT *pResults)
  297. {
  298. MessageListCleanUp(&pResults->Kerberos.lmsgOutput);
  299. }