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.

595 lines
16 KiB

  1. /*++
  2. Copyright (c) 2002 - 2002 Microsoft Corporation. All Rights Reserved.
  3. THIS CODE AND INFORMATION IS PROVIDED "AS-IS" WITHOUT WARRANTY OF
  4. ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  5. THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  6. PARTICULAR PURPOSE.
  7. THIS CODE IS NOT SUPPORTED BY MICROSOFT.
  8. --*/
  9. #include "precomp.h"
  10. #pragma hdrstop
  11. //
  12. // Macros
  13. //
  14. #define MAX_HASH 20
  15. #define CONVERT_WCHAR(ch, n) \
  16. if(iswdigit((ch))) \
  17. { \
  18. (n) = (UCHAR)((ch) - L'0'); \
  19. } \
  20. else if(iswxdigit((ch))) \
  21. { \
  22. (n) = (UCHAR) ((ch) + 10 - (iswlower((ch))?L'a':L'A')); \
  23. } \
  24. else \
  25. { \
  26. NlsPutMsg(HTTPCFG_INVALID_HASH, pHash); \
  27. return ERROR_INVALID_PARAMETER; \
  28. }
  29. //
  30. // Private functions.
  31. //
  32. /***************************************************************************++
  33. Routine Description:
  34. Prints a record in the SSL store.
  35. Arguments:
  36. pOutput - A pointer to HTTP_SERVICE_CONFIG_SSL_SET
  37. Return Value:
  38. None.
  39. --***************************************************************************/
  40. void
  41. PrintSslRecord(
  42. IN PUCHAR pOutput
  43. )
  44. {
  45. DWORD i;
  46. UNICODE_STRING GuidString;
  47. WCHAR IpAddr[INET6_ADDRSTRLEN];
  48. DWORD dwIpAddrLen = INET6_ADDRSTRLEN;
  49. DWORD dwSockAddrLength;
  50. PUCHAR pStr;
  51. PSOCKADDR_IN pSockAddrIn;
  52. PHTTP_SERVICE_CONFIG_SSL_SET pSsl;
  53. DWORD Status;
  54. pSsl = (PHTTP_SERVICE_CONFIG_SSL_SET) pOutput;
  55. // Convert address to string.
  56. //
  57. pSockAddrIn = (PSOCKADDR_IN) pSsl->KeyDesc.pIpPort;
  58. if(pSockAddrIn->sin_family == AF_INET)
  59. {
  60. dwSockAddrLength = sizeof(SOCKADDR_IN);
  61. }
  62. else if(pSockAddrIn->sin_family == AF_INET6)
  63. {
  64. dwSockAddrLength = sizeof(SOCKADDR_IN6);
  65. }
  66. else
  67. {
  68. // Status = ERROR_REGISTRY_CORRUPT;
  69. return;
  70. }
  71. Status = WSAAddressToString(pSsl->KeyDesc.pIpPort,
  72. dwSockAddrLength,
  73. NULL,
  74. IpAddr,
  75. &dwIpAddrLen
  76. );
  77. if(NO_ERROR != Status)
  78. {
  79. return;
  80. }
  81. // Print the Key.
  82. NlsPutMsg(HTTPCFG_SSL_IP, IpAddr);
  83. NlsPutMsg(HTTPCFG_SSL_HASH);
  84. pStr = (PUCHAR) pSsl->ParamDesc.pSslHash;
  85. for(i=0; i<pSsl->ParamDesc.SslHashLength; i++)
  86. {
  87. NlsPutMsg(HTTPCFG_CHAR, pStr[i]);
  88. }
  89. NlsPutMsg(HTTPCFG_NEWLINE);
  90. Status = RtlStringFromGUID(&pSsl->ParamDesc.AppId, &GuidString);
  91. if(NO_ERROR != Status)
  92. {
  93. return;
  94. }
  95. NlsPutMsg(HTTPCFG_SSL_GUID, GuidString.Buffer);
  96. RtlFreeUnicodeString(&GuidString);
  97. NlsPutMsg(HTTPCFG_SSL_CERTSTORENAME,
  98. pSsl->ParamDesc.pSslCertStoreName
  99. );
  100. NlsPutMsg(
  101. HTTPCFG_SSL_CERTCHECKMODE,
  102. pSsl->ParamDesc.DefaultCertCheckMode
  103. );
  104. NlsPutMsg(
  105. HTTPCFG_SSL_REVOCATIONFRESHNESSTIME,
  106. pSsl->ParamDesc.DefaultRevocationFreshnessTime
  107. );
  108. NlsPutMsg(
  109. HTTPCFG_SSL_REVOCATIONURLRETRIEVAL_TIMEOUT,
  110. pSsl->ParamDesc.DefaultRevocationUrlRetrievalTimeout
  111. );
  112. NlsPutMsg(
  113. HTTPCFG_SSL_SSLCTLIDENTIFIER,
  114. pSsl->ParamDesc.pDefaultSslCtlIdentifier
  115. );
  116. NlsPutMsg(
  117. HTTPCFG_SSL_SSLCTLSTORENAME,
  118. pSsl->ParamDesc.pDefaultSslCtlStoreName
  119. );
  120. NlsPutMsg(
  121. HTTPCFG_SSL_FLAGS,
  122. pSsl->ParamDesc.DefaultFlags
  123. );
  124. NlsPutMsg(
  125. HTTPCFG_RECORD_SEPARATOR
  126. );
  127. }
  128. /***************************************************************************++
  129. Routine Description:
  130. Sets a SSL entry.
  131. Arguments:
  132. pIP - The IP address.
  133. pGuid - The GUID
  134. pHash - Hash of the certificate.
  135. CertCheckMode - CertCheckMode (Bit Field).
  136. Freshness - DefaultRevocationFreshnessTime (seconds)
  137. Timeout - DefaultRevocationUrlRetrievalTimeout
  138. Flags - DefaultFlags.
  139. pCtlIdentifier - List of issuers that we want to trust.
  140. pCtlStoreName - Store name under LOCAL_MACHINE where pCtlIdentifier
  141. can be found.
  142. pCertStoreName - Store name under LOCAL_MACHINE where certificate
  143. can be found.
  144. Return Value:
  145. Success/Failure.
  146. --***************************************************************************/
  147. int
  148. DoSslSet(
  149. IN PWCHAR pIp,
  150. IN PWCHAR pGuid,
  151. IN PWCHAR pHash,
  152. IN DWORD CertCheckMode,
  153. IN DWORD Freshness,
  154. IN DWORD Timeout,
  155. IN DWORD Flags,
  156. IN PWCHAR pCtlIdentifier,
  157. IN PWCHAR pCtlStoreName,
  158. IN PWCHAR pCertStoreName
  159. )
  160. {
  161. HTTP_SERVICE_CONFIG_SSL_SET SetParam;
  162. UNICODE_STRING GuidString;
  163. DWORD Status;
  164. SOCKADDR_STORAGE TempSockAddr;
  165. USHORT HashLength;
  166. UCHAR BinaryHash[MAX_HASH];
  167. DWORD i, j;
  168. UCHAR n1, n2;
  169. ZeroMemory(&SetParam, sizeof(SetParam));
  170. SetParam.KeyDesc.pIpPort = (LPSOCKADDR)&TempSockAddr;
  171. //
  172. // Convert the string based IP into a SOCKADDR
  173. //
  174. if((Status = GetAddress(pIp,
  175. SetParam.KeyDesc.pIpPort,
  176. sizeof(TempSockAddr)
  177. )) != NO_ERROR)
  178. {
  179. NlsPutMsg(HTTPCFG_INVALID_IP, pIp);
  180. return Status;
  181. }
  182. //
  183. // Convert the string to a GUID.
  184. //
  185. if(pGuid)
  186. {
  187. GuidString.Length = (USHORT)wcslen(pGuid) * sizeof(WCHAR);
  188. GuidString.MaximumLength = (USHORT)GuidString.Length+1;
  189. GuidString.Buffer = pGuid;
  190. Status = RtlGUIDFromString(&GuidString, &SetParam.ParamDesc.AppId);
  191. if(Status != NO_ERROR)
  192. {
  193. NlsPutMsg(HTTPCFG_INVALID_GUID, pGuid);
  194. return Status;
  195. }
  196. }
  197. if(pHash)
  198. {
  199. HashLength = (USHORT) wcslen(pHash);
  200. for(i=0, j=0; i<MAX_HASH && HashLength >= 2; )
  201. {
  202. CONVERT_WCHAR(pHash[j], n1);
  203. CONVERT_WCHAR(pHash[j+1], n2);
  204. BinaryHash[i] = ((n1<<4) & 0xF0) | (n2 & 0x0F);
  205. // We've consumed 2 WCHARs
  206. HashLength -= 2;
  207. j += 2;
  208. // and used up one byte in BinaryHash
  209. i ++;
  210. }
  211. if(HashLength != 0 || i != MAX_HASH)
  212. {
  213. NlsPutMsg(HTTPCFG_INVALID_HASH, pHash);
  214. return ERROR_INVALID_PARAMETER;
  215. }
  216. SetParam.ParamDesc.SslHashLength = i;
  217. SetParam.ParamDesc.pSslHash = BinaryHash;
  218. }
  219. SetParam.ParamDesc.pSslCertStoreName = pCertStoreName;
  220. SetParam.ParamDesc.pDefaultSslCtlIdentifier = pCtlIdentifier;
  221. SetParam.ParamDesc.pDefaultSslCtlStoreName = pCtlStoreName;
  222. SetParam.ParamDesc.DefaultCertCheckMode = CertCheckMode;
  223. SetParam.ParamDesc.DefaultRevocationFreshnessTime = Freshness;
  224. SetParam.ParamDesc.DefaultRevocationUrlRetrievalTimeout = Timeout;
  225. SetParam.ParamDesc.DefaultFlags = Flags;
  226. Status = HttpSetServiceConfiguration(
  227. NULL,
  228. HttpServiceConfigSSLCertInfo,
  229. &SetParam,
  230. sizeof(SetParam),
  231. NULL
  232. );
  233. NlsPutMsg(HTTPCFG_SETSERVICE_STATUS, Status);
  234. return Status;
  235. }
  236. /***************************************************************************++
  237. Routine Description:
  238. Queries for a SSL entry.
  239. Arguments:
  240. pIp - The IP address (if NULL, then enumerate the store).
  241. Return Value:
  242. Success/Failure.
  243. --***************************************************************************/
  244. int DoSslQuery(
  245. IN PWCHAR pIp
  246. )
  247. {
  248. DWORD Status;
  249. PUCHAR pOutput = NULL;
  250. DWORD OutputLength = 0;
  251. DWORD ReturnLength = 0;
  252. HTTP_SERVICE_CONFIG_SSL_QUERY QueryParam;
  253. SOCKADDR_STORAGE TempSockAddr;
  254. ZeroMemory(&QueryParam, sizeof(QueryParam));
  255. if(pIp)
  256. {
  257. // if an IP address is specified, we'll covert it to a SOCKADDR
  258. // and do an exact query.
  259. QueryParam.QueryDesc = HttpServiceConfigQueryExact;
  260. QueryParam.KeyDesc.pIpPort = (LPSOCKADDR)&TempSockAddr;
  261. if((Status = GetAddress(pIp,
  262. QueryParam.KeyDesc.pIpPort,
  263. sizeof(TempSockAddr)
  264. )) != NO_ERROR)
  265. {
  266. NlsPutMsg(HTTPCFG_INVALID_IP, pIp);
  267. return Status;
  268. }
  269. }
  270. else
  271. {
  272. // We are enumerating all the records in the SSL store.
  273. QueryParam.QueryDesc = HttpServiceConfigQueryNext;
  274. }
  275. for(;;)
  276. {
  277. //
  278. // First, compute the bytes required to enumerate an entry.
  279. //
  280. Status = HttpQueryServiceConfiguration(
  281. NULL,
  282. HttpServiceConfigSSLCertInfo,
  283. &QueryParam,
  284. sizeof(QueryParam),
  285. pOutput,
  286. OutputLength,
  287. &ReturnLength,
  288. NULL
  289. );
  290. if(Status == ERROR_INSUFFICIENT_BUFFER)
  291. {
  292. // If the API completes with ERROR_INSUFFICIENT_BUFFER, we'll
  293. // allocate memory for it & continue with the loop where we'll
  294. // call it again.
  295. if(pOutput)
  296. {
  297. // If there was an existing buffer, free it.
  298. LocalFree(pOutput);
  299. }
  300. // Allocate a new buffer
  301. pOutput = LocalAlloc(LMEM_FIXED, ReturnLength);
  302. if(!pOutput)
  303. {
  304. return ERROR_NOT_ENOUGH_MEMORY;
  305. }
  306. OutputLength = ReturnLength;
  307. }
  308. else if(Status == NO_ERROR)
  309. {
  310. // The query succeeded! We'll print the record that we just
  311. // queried.
  312. //
  313. PrintSslRecord(pOutput);
  314. if(pIp != NULL)
  315. {
  316. //
  317. // If we are not enumerating, we are done.
  318. //
  319. break;
  320. }
  321. else
  322. {
  323. //
  324. // Since we are enumerating, we'll move on to the next
  325. // record. This is done by incrementing the cursor, till
  326. // we get ERROR_NO_MORE_ITEMS.
  327. //
  328. QueryParam.dwToken ++;
  329. }
  330. }
  331. else if(ERROR_NO_MORE_ITEMS == Status && !pIp)
  332. {
  333. // We are enumerating and we have reached the end. This is
  334. // indicated by a ERROR_NO_MORE_ITEMS error code.
  335. // This is not a real error, since it is used to indicate that
  336. // we've finished enumeration.
  337. Status = NO_ERROR;
  338. break;
  339. }
  340. else
  341. {
  342. //
  343. // Some other error, so we are done
  344. //
  345. NlsPutMsg(HTTPCFG_QUERYSERVICE_STATUS, Status);
  346. break;
  347. }
  348. }
  349. if(pOutput)
  350. {
  351. LocalFree(pOutput);
  352. }
  353. return Status;
  354. }
  355. /***************************************************************************++
  356. Routine Description:
  357. Deletes a SSL entry.
  358. Arguments:
  359. pIP - The IP address of entry to be deleted.
  360. Return Value:
  361. Success/Failure.
  362. --***************************************************************************/
  363. int DoSslDelete(
  364. IN PWCHAR pIp
  365. )
  366. {
  367. HTTP_SERVICE_CONFIG_SSL_SET SetParam;
  368. DWORD Status;
  369. SOCKADDR_STORAGE TempSockAddr;
  370. SetParam.KeyDesc.pIpPort = (LPSOCKADDR)&TempSockAddr;
  371. // Convert string IP address to a SOCKADDR structure
  372. Status = GetAddress(pIp,
  373. SetParam.KeyDesc.pIpPort,
  374. sizeof(TempSockAddr)
  375. );
  376. if(Status != NO_ERROR)
  377. {
  378. NlsPutMsg(HTTPCFG_INVALID_IP, pIp);
  379. return Status;
  380. }
  381. // Call the API.
  382. Status = HttpDeleteServiceConfiguration(
  383. NULL,
  384. HttpServiceConfigSSLCertInfo,
  385. &SetParam,
  386. sizeof(SetParam),
  387. NULL
  388. );
  389. NlsPutMsg(HTTPCFG_DELETESERVICE_STATUS, Status);
  390. return Status;
  391. }
  392. //
  393. // Public functions.
  394. //
  395. /***************************************************************************++
  396. Routine Description:
  397. The function that parses parameters specific to SSL
  398. calls Set, Query or Delete.
  399. Arguments:
  400. argc - Count of arguments.
  401. argv - Pointer to command line arguments.
  402. Type - Type of operation to be performed.
  403. Return Value:
  404. Success/Failure.
  405. --***************************************************************************/
  406. int DoSsl(
  407. int argc,
  408. WCHAR **argv,
  409. HTTPCFG_TYPE type
  410. )
  411. {
  412. PWCHAR pGuid = NULL;
  413. PWCHAR pHash = NULL;
  414. PWCHAR pCertStoreName = NULL;
  415. PWCHAR pCtlIdentifier = NULL;
  416. PWCHAR pCtlStoreName = NULL;
  417. DWORD CertCheckMode = 0;
  418. DWORD Freshness = 0;
  419. DWORD Timeout = 0;
  420. DWORD Flags = 0;
  421. PWCHAR pIp = NULL;
  422. while(argc >= 2 && (argv[0][0] == L'-' || argv[0][0] == L'/'))
  423. {
  424. switch(toupper(argv[0][1]))
  425. {
  426. case 'I':
  427. pIp = argv[1];
  428. break;
  429. case 'C':
  430. pCertStoreName = argv[1];
  431. break;
  432. case 'N':
  433. pCtlStoreName = argv[1];
  434. break;
  435. case 'T':
  436. pCtlIdentifier = argv[1];
  437. break;
  438. case 'M':
  439. CertCheckMode = _wtoi(argv[1]);
  440. break;
  441. case 'R':
  442. Freshness = _wtoi(argv[1]);
  443. break;
  444. case 'X':
  445. Timeout = _wtoi(argv[1]);
  446. break;
  447. case 'F':
  448. Flags = _wtoi(argv[1]);
  449. break;
  450. case 'G':
  451. pGuid = argv[1];
  452. break;
  453. case 'H':
  454. pHash = argv[1];
  455. break;
  456. default:
  457. NlsPutMsg(HTTPCFG_INVALID_SWITCH, argv[0]);
  458. return ERROR_INVALID_PARAMETER;
  459. }
  460. argc -=2;
  461. argv +=2;
  462. }
  463. switch(type)
  464. {
  465. case HttpCfgTypeSet:
  466. return DoSslSet(
  467. pIp,
  468. pGuid,
  469. pHash,
  470. CertCheckMode,
  471. Freshness,
  472. Timeout,
  473. Flags,
  474. pCtlIdentifier,
  475. pCtlStoreName,
  476. pCertStoreName
  477. );
  478. case HttpCfgTypeQuery:
  479. return DoSslQuery(pIp);
  480. case HttpCfgTypeDelete:
  481. return DoSslDelete(pIp);
  482. default:
  483. NlsPutMsg(HTTPCFG_INVALID_SWITCH, argv[0]);
  484. return ERROR_INVALID_PARAMETER;
  485. break;
  486. }
  487. }