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.

553 lines
13 KiB

  1. //+-----------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (c) Microsoft Corporation
  6. //
  7. // File: kpkdc.h
  8. //
  9. // Contents: routines for communicating with the kdc
  10. //
  11. // History: 10-Jul-2001 t-ryanj Created
  12. //
  13. //------------------------------------------------------------------------
  14. #include <nt.h>
  15. #include <ntrtl.h>
  16. #include <nturtl.h>
  17. #include <windows.h>
  18. #ifndef SECURITY_WIN32
  19. #define SECURITY_WIN32
  20. #endif
  21. #include <kerbcomm.h>
  22. #include <dsgetdc.h>
  23. #include <lm.h> /* for NetApiBufferFree */
  24. #include "kpkdc.h"
  25. #include "kpcontext.h"
  26. #include "kpcore.h"
  27. #define KDC_SERVICE_NAME "kerberos"
  28. #define KDC_FALLBACK_PORT 88
  29. SHORT KpDefaultKdcPort;
  30. BOOL KpWSAStarted = FALSE;
  31. ULONG
  32. KpGetPduValue(
  33. PKPCONTEXT pContext
  34. );
  35. VOID
  36. KpInitDefaultKdcPort(
  37. VOID
  38. );
  39. //+-------------------------------------------------------------------------
  40. //
  41. // Function: KpInitWinsock
  42. //
  43. // Synopsis: Starts winsock
  44. //
  45. // Effects:
  46. //
  47. // Arguments:
  48. //
  49. // Requires:
  50. //
  51. // Returns: Success value. If FALSE, GetLastError() for details.
  52. //
  53. // Notes:
  54. //
  55. //
  56. //--------------------------------------------------------------------------
  57. BOOL
  58. KpInitWinsock(
  59. VOID
  60. )
  61. {
  62. WORD wWinsockVersionRequested = MAKEWORD( 2,2 );
  63. WSADATA wsaData;
  64. DWORD WSAStartError;
  65. DsysAssert(!KpWSAStarted);
  66. WSAStartError = WSAStartup( wWinsockVersionRequested, &wsaData );
  67. if( WSAStartError == SOCKET_ERROR )
  68. {
  69. DebugLog( DEB_ERROR, "%s(%d): Error starting winsock: 0x%x.\n", __FILE__, __LINE__, WSAGetLastError() );
  70. SetLastError(WSAGetLastError());
  71. goto Cleanup;
  72. }
  73. KpWSAStarted = TRUE;
  74. KpInitDefaultKdcPort();
  75. Cleanup:
  76. return KpWSAStarted;
  77. }
  78. //+-------------------------------------------------------------------------
  79. //
  80. // Function: KpCleanupWinsock
  81. //
  82. // Synopsis: Cleans up winsock.
  83. //
  84. // Effects:
  85. //
  86. // Arguments:
  87. //
  88. // Requires:
  89. //
  90. // Returns:
  91. //
  92. // Notes:
  93. //
  94. //
  95. //--------------------------------------------------------------------------
  96. VOID
  97. KpCleanupWinsock(
  98. VOID
  99. )
  100. {
  101. if( KpWSAStarted )
  102. {
  103. WSACleanup();
  104. KpWSAStarted = FALSE;
  105. }
  106. }
  107. //+-------------------------------------------------------------------------
  108. //
  109. // Function: KpInitDefaultKdcPort
  110. //
  111. // Synopsis: Finds the appropriate port for talking to kdcs.
  112. //
  113. // Effects:
  114. //
  115. // Arguments:
  116. //
  117. // Requires:
  118. //
  119. // Returns:
  120. //
  121. // Notes:
  122. //
  123. //
  124. //--------------------------------------------------------------------------
  125. VOID
  126. KpInitDefaultKdcPort(
  127. VOID
  128. )
  129. {
  130. PSERVENT krb5;
  131. /* TODO: Read from registry. */
  132. //
  133. // Ask winsock what port kerberos works on. This should be defined in
  134. // %systemroot%\system32\drivers\etc\services
  135. // Note that winsock manages the servent struct, we don't need to free it.
  136. //
  137. if( krb5 = getservbyname( KDC_SERVICE_NAME, NULL ) )
  138. {
  139. KpDefaultKdcPort = krb5->s_port;
  140. }
  141. else
  142. {
  143. DebugLog( DEB_WARN, "%s(%d): Could not determine kerberos port; falling back to port %d.\n", __FILE__, __LINE__, KDC_FALLBACK_PORT );
  144. KpDefaultKdcPort = htons( KDC_FALLBACK_PORT );
  145. }
  146. }
  147. //+-------------------------------------------------------------------------
  148. //
  149. // Function: KpKdcWrite
  150. //
  151. // Synopsis: Writes the response to the KDC.
  152. //
  153. // Effects:
  154. //
  155. // Arguments: pContext - the context
  156. //
  157. // Requires:
  158. //
  159. // Returns:
  160. //
  161. // Notes:
  162. //
  163. //
  164. //--------------------------------------------------------------------------
  165. VOID
  166. KpKdcWrite(
  167. PKPCONTEXT pContext
  168. )
  169. {
  170. PKERB_KDC_REQUEST pKdcReq = NULL;
  171. KERBERR KerbErr;
  172. ULONG PduValue = 0; /* compiler stupid, insists on =0 */
  173. PDOMAIN_CONTROLLER_INFOA pKdcInfo = NULL;
  174. DWORD DsError;
  175. sockaddr_in KdcAddr;
  176. int connecterr;
  177. BOOL WriteSuccess;
  178. DebugLog( DEB_TRACE, "%s(%d): %d bytes read from http.\n", __FILE__, __LINE__, pContext->pECB->cbTotalBytes );
  179. //
  180. // First we need to find the PduValue for the request so we can unpack.
  181. //
  182. PduValue = KpGetPduValue(pContext);
  183. if( !PduValue )
  184. goto Error;
  185. //
  186. // Unpack the request.
  187. //
  188. KerbErr = KerbUnpackData( pContext->databuf + sizeof(DWORD),
  189. pContext->buflen - sizeof(DWORD),
  190. PduValue,
  191. (PVOID*)&pKdcReq );
  192. if( !KERB_SUCCESS(KerbErr) )
  193. {
  194. DebugLog( DEB_ERROR, "%s(%d): Kerberos Error: 0x%x\n", __FILE__, __LINE__, KerbErr );
  195. goto Error;
  196. }
  197. //
  198. // Now we need to look for a KDC for the realm specified in the request.
  199. //
  200. DebugLog( DEB_TRACE, "%s(%d): Realm found to be %s.\n", __FILE__, __LINE__, pKdcReq->request_body.realm );
  201. DsError = DsGetDcNameA( NULL, /* Computer Name */
  202. pKdcReq->request_body.realm,
  203. NULL, /* Domain GUID */
  204. NULL, /* Site Name */
  205. DS_IP_REQUIRED | DS_KDC_REQUIRED,
  206. &pKdcInfo );
  207. if( DsError != NO_ERROR )
  208. {
  209. DebugLog( DEB_ERROR, "%s(%d): Error from DsGetDcName: 0x%x\n", __FILE__, __LINE__, DsError );
  210. goto Error;
  211. }
  212. DebugLog( DEB_TRACE, "%s(%d): DC found. %s\n", __FILE__, __LINE__, pKdcInfo->DomainControllerAddress );
  213. //
  214. // Construct the SOCKADDR_IN to connect to the kdc.
  215. //
  216. KdcAddr.sin_family = AF_INET;
  217. KdcAddr.sin_port = KpDefaultKdcPort;
  218. KdcAddr.sin_addr.s_addr = inet_addr(pKdcInfo->DomainControllerAddress+2 /* past the \\ */ );
  219. //
  220. // Create the socket.
  221. //
  222. pContext->KdcSock = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
  223. if( !pContext->KdcSock )
  224. {
  225. DebugLog( DEB_ERROR, "%s(%d): Error creating socket: 0x%x\n", __FILE__, __LINE__, WSAGetLastError() );
  226. goto Error;
  227. }
  228. //
  229. // Connect the socket.
  230. //
  231. connecterr = connect( pContext->KdcSock, (sockaddr*)&KdcAddr, sizeof(sockaddr_in) );
  232. if( connecterr )
  233. {
  234. DebugLog( DEB_ERROR, "%s(%d): Error connecting to Kdc: 0x%x\n", __FILE__, __LINE__, WSAGetLastError() );
  235. goto Error;
  236. }
  237. //
  238. // Associate the socket with the iocp.
  239. //
  240. /* if( KpGlobalIocp != CreateIoCompletionPort( (HANDLE)pContext->KdcSock,
  241. KpGlobalIocp,
  242. KPCK_CHECK_CONTEXT,
  243. 0 ) ) */
  244. if( !BindIoCompletionCallback( (HANDLE)pContext->KdcSock,
  245. KpIoCompletionRoutine,
  246. 0 ) )
  247. {
  248. DebugLog( DEB_ERROR, "%s(%d): Error associating Iocp with Kdc socket: 0x%x.\n", __FILE__, __LINE__, GetLastError() );
  249. goto Error;
  250. }
  251. //
  252. // Write the request asynchronously.
  253. //
  254. ZeroMemory( &(pContext->ol), sizeof(OVERLAPPED) );
  255. pContext->dwStatus = KP_KDC_WRITE;
  256. WriteSuccess = WriteFile( (HANDLE)pContext->KdcSock,
  257. pContext->databuf,
  258. pContext->buflen,
  259. NULL, /* bytes written - not used in async */
  260. &(pContext->ol) );
  261. if( !WriteSuccess )
  262. {
  263. if( GetLastError() != ERROR_IO_PENDING )
  264. {
  265. DebugLog( DEB_ERROR, "%s(%d): Error issuing socket write: 0x%x\n", __FILE__, __LINE__, GetLastError() );
  266. goto Error;
  267. }
  268. }
  269. Cleanup:
  270. if( pKdcInfo )
  271. NetApiBufferFree( pKdcInfo );
  272. if( pKdcReq )
  273. KerbFreeData( PduValue, pKdcReq );
  274. return;
  275. Error:
  276. KpReleaseContext(pContext);
  277. goto Cleanup;
  278. }
  279. //+-------------------------------------------------------------------------
  280. //
  281. // Function: KpKdcRead
  282. //
  283. // Synopsis: Reads the response from the KDC.
  284. //
  285. // Effects:
  286. //
  287. // Arguments: pContext
  288. //
  289. // Requires:
  290. //
  291. // Returns:
  292. //
  293. // Notes: Just a stub now.
  294. //
  295. //
  296. //--------------------------------------------------------------------------
  297. VOID
  298. KpKdcRead(
  299. PKPCONTEXT pContext
  300. )
  301. {
  302. BOOL ReadSuccess;
  303. //
  304. // Read as much data as possible from the socket asynchronously.
  305. //
  306. ZeroMemory( &(pContext->ol), sizeof(OVERLAPPED) );
  307. pContext->dwStatus = KP_KDC_READ;
  308. DebugLog( DEB_PEDANTIC, "%s(%d): Reading up to %d bytes from Kdc socket.\n", __FILE__, __LINE__, pContext->buflen - pContext->bytesReceived );
  309. ReadSuccess = ReadFile( (HANDLE)pContext->KdcSock,
  310. pContext->databuf + pContext->bytesReceived,
  311. pContext->buflen - pContext->bytesReceived,
  312. NULL, /* bytes read - not used in async */
  313. &(pContext->ol) );
  314. if( !ReadSuccess )
  315. {
  316. if( GetLastError() != ERROR_IO_PENDING )
  317. {
  318. DebugLog( DEB_ERROR, "%s(%d): Error issuing read: 0x%x\n", __FILE__, __LINE__, GetLastError() );
  319. goto Error;
  320. }
  321. }
  322. Cleanup:
  323. return;
  324. Error:
  325. KpReleaseContext(pContext);
  326. goto Cleanup;
  327. }
  328. //+-------------------------------------------------------------------------
  329. //
  330. // Function: KpKdcReadDone
  331. //
  332. // Synopsis: Checks to see if enough data has been read.
  333. //
  334. // Effects:
  335. //
  336. // Arguments: pContext
  337. //
  338. // Requires:
  339. //
  340. // Returns: TRUE of reading is complete.
  341. //
  342. // Notes:
  343. //
  344. //--------------------------------------------------------------------------
  345. BOOL
  346. KpKdcReadDone(
  347. PKPCONTEXT pContext
  348. )
  349. {
  350. InterlockedExchangeAdd( (LONG*)&(pContext->bytesReceived), (LONG)pContext->ol.InternalHigh );
  351. return pContext->bytesReceived == pContext->buflen;
  352. }
  353. //+-------------------------------------------------------------------------
  354. //
  355. // Function: KpCalcLength
  356. //
  357. // Synopsis: Calculates the length of the incoming request.
  358. //
  359. // Effects:
  360. //
  361. // Arguments: pContext
  362. //
  363. // Requires:
  364. //
  365. // Returns: Success value.
  366. //
  367. // Notes:
  368. //
  369. //--------------------------------------------------------------------------
  370. BOOL
  371. KpCalcLength(
  372. PKPCONTEXT pContext
  373. )
  374. {
  375. BOOL fRet = TRUE;
  376. DWORD cbContent;
  377. LPBYTE newbuf = NULL;
  378. //
  379. // Spec says that all requests that we recieve should be in TCP form,
  380. // meaning they are preceeded by at least 4 bytes in network byte order
  381. // indicating the length of the message. So if we don't have at least
  382. // four bytes of data, we're toast.
  383. //
  384. if( pContext->ol.InternalHigh < sizeof(DWORD) )
  385. {
  386. DebugLog( DEB_TRACE, "%s(%d): Less than sizeof(DWORD) bytes received. CalcLength failed.\n", __FILE__, __LINE__ );
  387. goto Error;
  388. }
  389. //
  390. // Convert the four bytes to host byte order.
  391. //
  392. cbContent = ntohl(*(u_long*)pContext->databuf);
  393. //
  394. // If the sign bit is set, that means that another four bytes are
  395. // needed for the length of the message. That's too long, so
  396. // we'll just punt.
  397. //
  398. if( cbContent & 0x80000000 ) /* high bit set */
  399. {
  400. DebugLog( DEB_TRACE, "%s(%d): Length won't fit in DWORD.\n", __FILE__, __LINE__ );
  401. goto Error;
  402. }
  403. //
  404. // So we're expecting as a total length, the length of the length
  405. // plus the length of the content.
  406. //
  407. pContext->bytesExpected = sizeof(DWORD) + cbContent;
  408. //
  409. // Realloc our buffer to be large enough to hold the whole message.
  410. //
  411. pContext->buflen = sizeof(DWORD) + cbContent;
  412. newbuf = (LPBYTE)KpReAlloc( pContext->databuf, pContext->buflen );
  413. if( !newbuf )
  414. {
  415. DebugLog( DEB_TRACE, "%s(%d): Realloc failed. CalcLength failed.\n", __FILE__, __LINE__ );
  416. goto Error;
  417. }
  418. pContext->databuf = newbuf;
  419. DebugLog( DEB_TRACE, "%s(%d): Looking for reply of length %d.\n", __FILE__, __LINE__, pContext->bytesExpected );
  420. Cleanup:
  421. return fRet;
  422. Error:
  423. fRet = FALSE;
  424. goto Cleanup;
  425. }
  426. //+-------------------------------------------------------------------------
  427. //
  428. // Function: KpGetPduValue
  429. //
  430. // Synopsis: Looks at the first byte of the request to determine the
  431. // message type, and returns the appropriate PduValue for
  432. // unpacking.
  433. //
  434. // Effects:
  435. //
  436. // Arguments: pContext
  437. //
  438. // Requires:
  439. //
  440. // Returns: The appropriate PduValue, or 0 on failure. Note that 0
  441. // is a valid PduValue, but since we're only concerned with
  442. // AS-REQ and TGS-REQ, we can ignore it.
  443. //
  444. // Notes:
  445. //
  446. //--------------------------------------------------------------------------
  447. ULONG
  448. KpGetPduValue(
  449. PKPCONTEXT pContext
  450. )
  451. {
  452. ULONG PduValue = 0;
  453. //
  454. // If we don't have the first byte, we can't exactly parse it.
  455. //
  456. if( pContext->buflen < 1 + sizeof(DWORD) )
  457. goto Cleanup;
  458. //
  459. // The last five bits of the first byte signify the message type.
  460. //
  461. switch( pContext->databuf[sizeof(DWORD)] & 0x1f ) /* last 5 bits */
  462. {
  463. case 0xa: /* AS-REQUEST */
  464. DebugLog( DEB_TRACE, "%s(%d): Processing AS-REQUEST.\n", __FILE__, __LINE__ );
  465. PduValue = KERB_AS_REQUEST_PDU;
  466. break;
  467. case 0xc: /* TGS-REQUEST */
  468. DebugLog( DEB_TRACE, "%s(%d): Processing TGS-REQUEST.\n", __FILE__, __LINE__ );
  469. PduValue = KERB_TGS_REQUEST_PDU;
  470. break;
  471. default:
  472. DebugLog( DEB_ERROR, "%s(%d): Not an AS or TGS request.\n", __FILE__, __LINE__ );
  473. goto Cleanup;
  474. }
  475. Cleanup:
  476. return PduValue;
  477. }