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.

464 lines
16 KiB

  1. #include <windows.h>
  2. #define SECURITY_WIN32
  3. #include <sspi.h>
  4. #include <issperr.h>
  5. #include <security.h>
  6. #define SSP_SPM_NT_DLL "security.dll"
  7. #define SSP_SPM_WIN95_DLL "secur32.dll"
  8. #define MAX_OUTPUT_BUFFER 4096
  9. SEC_WINNT_AUTH_IDENTITY SecId;
  10. HINSTANCE hSecLib;
  11. PSecurityFunctionTable pFuncTbl = NULL;
  12. // Preliminary func calls.
  13. VOID InitializeSecurityInterface(BOOL fDirect);
  14. BOOL HaveDigest();
  15. // 3 Main SSPI calls.
  16. // AcquireCredentialsHandle
  17. SECURITY_STATUS ACH(PCredHandle phCred);
  18. // InitializeSecurityContext
  19. SECURITY_STATUS ISC(PCredHandle phCred,
  20. PCtxtHandle phCtxt,
  21. PCtxtHandle phNewCtxt,
  22. DWORD fContextReq,
  23. LPSTR szChallenge,
  24. LPSTR szResponse,
  25. LPSTR szUser,
  26. LPSTR szPass);
  27. // FreeCredentialsHandle
  28. SECURITY_STATUS FCH(PCredHandle phCred);
  29. //--------------------------------------
  30. // main
  31. //--------------------------------------
  32. INT main()
  33. {
  34. DWORD dwReturn = 0;
  35. SECURITY_STATUS ssResult;
  36. // Get (global) dispatch table.
  37. InitializeSecurityInterface(FALSE);
  38. // Check to see if we have digest.
  39. if (!HaveDigest())
  40. {
  41. dwReturn = 1;
  42. goto exit;
  43. }
  44. // Credential handle and pointer.
  45. CredHandle hCred;
  46. CtxtHandle hCtxt;
  47. // **** Call AcquireCredentialsHandle with no credential ***
  48. ACH(&hCred);
  49. // Challenge and response buffers. As usual, we dump into an
  50. // output buffer allocated on the stack.
  51. LPSTR szChallenge;
  52. CHAR szResponse[MAX_OUTPUT_BUFFER];
  53. // First call to ISC is with zero input, expecting a 0 DWORD output buffer, as
  54. // we expect with POP clients
  55. szChallenge = NULL;
  56. // Make first call to ISC with null input - expect DWORD 0 output.
  57. ssResult = ISC( &hCred, // Cred from logging on.
  58. NULL, // Ctxt not specified first time.
  59. &hCtxt, // Output context.
  60. 0, // flags auth from cache, but not meaningful here.
  61. szChallenge, // NULL Server challenge header.
  62. szResponse, // Response buffer.
  63. NULL, // No user needed.
  64. NULL); // No pass needed.
  65. // Expect 0 DWORD output and SEC_I_CONTINUE_NEEDED.
  66. if (ssResult != SEC_I_CONTINUE_NEEDED)
  67. {
  68. DebugBreak();
  69. }
  70. // Free cred handle.
  71. FCH(&hCred);
  72. // Re-acquire cred handle.
  73. ACH(&hCred);
  74. // Now setup challenge from server for realm "Microsoft Passport" which will use the
  75. // credentials user="[email protected]", pass = "jpoley"
  76. szChallenge = "realm=\"Microsoft Passport\", algorithm = \"MD5-sess\", qop=\"auth\", nonce=\"0123456789abcdef\"";
  77. // Authenticate using user = "[email protected]", pass = "jpoley"
  78. ssResult = ISC( &hCred, // Cred from logging on.
  79. NULL, // Ctxt not specified first time.
  80. &hCtxt, // Output context.
  81. ISC_REQ_USE_SUPPLIED_CREDS, // Use the credentials supplied.
  82. szChallenge, // Server challenge header.
  83. szResponse, // Response buffer,
  84. "[email protected]", // user
  85. "jpoley" // pass
  86. );
  87. // We have just successfully authenticated for [email protected]. In doing so,
  88. // we have created a credential for [email protected] in the digest cred cache.
  89. if (ssResult != SEC_E_OK)
  90. {
  91. DebugBreak();
  92. }
  93. // Free cred handle.
  94. FCH(&hCred);
  95. // Re-acquire cred handle.
  96. ACH(&hCred);
  97. // Quick confirmation that we have a credential for "[email protected],
  98. // we'll attempt to auth to a "Microsoft Passport" challenge without supplying
  99. // any creds - this should pull jpoley creds from
  100. // the cache and authomatically generate an auth header.
  101. ssResult = ISC( &hCred, // Cred from logging on.
  102. NULL, // Ctxt not specified first time.
  103. &hCtxt, // Output context.
  104. 0, // auth from cache
  105. szChallenge, // Server challenge header.
  106. szResponse, // Response buffer,
  107. NULL, // Not passing user
  108. NULL // Not passing in pass
  109. );
  110. // Should have authed successfully.
  111. if (ssResult != SEC_E_OK)
  112. {
  113. DebugBreak();
  114. }
  115. // Free cred handle.
  116. FCH(&hCred);
  117. // Re-acquire cred handle.
  118. ACH(&hCred);
  119. // Now setup a challange from server for realm "Microsoft Passport (we'll use
  120. // the previouse one but this time we wish to authyenticate on behalf of a new
  121. // user "[email protected]" and we DON'T HAVE A PASSWORD.
  122. szChallenge = "realm=\"Microsoft Passport\", algorithm = \"MD5-sess\", qop=\"auth\", nonce=\"0123456789abcdef\"";
  123. // Authenticate
  124. ssResult = ISC( &hCred, // Cred from logging on.
  125. NULL, // Ctxt not specified first time.
  126. &hCtxt, // Output context.
  127. 0, // Auth from cache.
  128. szChallenge, // Server challenge header.
  129. szResponse, // Response buffer,
  130. "[email protected]", // user
  131. NULL // No password!
  132. );
  133. // We didn't have any credentials, so we better not have succeeded.
  134. if (ssResult != SEC_E_NO_CREDENTIALS)
  135. {
  136. DebugBreak();
  137. }
  138. // Free cred handle.
  139. FCH(&hCred);
  140. // Re-acquire cred handle.
  141. ACH(&hCred);
  142. // Prompt for credentials for [email protected]. Since the challenge contains the
  143. // realm "Microsoft Passport", the credential created here will overwrite the
  144. // credential created for [email protected], and generate the authorization string.
  145. ssResult = ISC( &hCred, // Cred from logging on.
  146. NULL, // Ctxt not specified first time.
  147. &hCtxt, // Output context.
  148. ISC_REQ_PROMPT_FOR_CREDS, // prompt for creds for [email protected]
  149. szChallenge, // Server challenge header.
  150. szResponse, // Response buffer.
  151. "[email protected]", // user to prompt for.
  152. NULL // Again, no password, we're prompting.
  153. );
  154. // We should have succeeded in collecting creds for [email protected] and
  155. // generating the authorization string.
  156. if (ssResult != SEC_E_OK)
  157. {
  158. DebugBreak();
  159. }
  160. // Free cred handle.
  161. FCH(&hCred);
  162. // Re-acquire cred handle.
  163. ACH(&hCred);
  164. // Quick confirmation that we have a credential for "[email protected]"
  165. // we'll attempt to auth to a "Microsoft Passport" challenge without supplying
  166. // any creds - this should pull alex creds from
  167. // the cache and authomatically generate an auth header.
  168. ssResult = ISC( &hCred, // Cred from logging on.
  169. NULL, // Ctxt not specified first time.
  170. &hCtxt, // Output context.
  171. 0, // auth from cache
  172. szChallenge, // Server challenge header.
  173. szResponse, // Response buffer,
  174. NULL, // Not passing user
  175. NULL // Not passing in pass
  176. );
  177. // Should have authed successfully.
  178. if (ssResult != SEC_E_OK)
  179. {
  180. DebugBreak();
  181. }
  182. // Free cred handle.
  183. FCH(&hCred);
  184. if (hSecLib)
  185. FreeLibrary(hSecLib);
  186. exit:
  187. return dwReturn;
  188. }
  189. // Main SSPI calls.
  190. //--------------------------------------
  191. // ACH
  192. //--------------------------------------
  193. SECURITY_STATUS ACH(PCredHandle phCred)
  194. {
  195. SECURITY_STATUS ssResult;
  196. // ***** SSPI CALL *****
  197. ssResult = (*(pFuncTbl->AcquireCredentialsHandleA))
  198. (NULL, // pszPrinciple NULL
  199. "Digest", // pszPackageName (Package name)
  200. SECPKG_CRED_OUTBOUND, // dwCredentialUse (client call)
  201. NULL, // pvLogonID (not used)
  202. NULL, // pAuthData (not used)
  203. NULL, // pGetKeyFn (not used)
  204. 0, // pvGetKeyArgument (not used)
  205. phCred, // phCredential (credential returned)
  206. NULL); // PTimeStamp (not used)
  207. return ssResult;
  208. }
  209. //--------------------------------------
  210. // ISC
  211. //--------------------------------------
  212. SECURITY_STATUS ISC(PCredHandle phCred,
  213. PCtxtHandle phCtxt,
  214. PCtxtHandle phNewCtxt,
  215. DWORD fContextReq,
  216. LPSTR szChallenge,
  217. LPSTR szResponse,
  218. LPSTR szUser,
  219. LPSTR szPass)
  220. {
  221. // If the client is not passing in user/pass
  222. // (ie, normal operation) then the count of
  223. // buffers passed in is always 1.
  224. #define SEC_BUFFER_NUM_NORMAL_BUFFERS 1
  225. // These are the indicese specifically expected
  226. // by the digest package
  227. #define SEC_BUFFER_CHALLENGE_INDEX 0
  228. #define SEC_BUFFER_USERNAME_INDEX 1
  229. #define SEC_BUFFER_PASSWORD_INDEX 2
  230. #define SEC_BUFFER_NUM_EXTENDED_BUFFERS 3
  231. SECURITY_STATUS ssResult;
  232. // Input buffers and descriptor.
  233. SecBuffer sbIn[SEC_BUFFER_NUM_EXTENDED_BUFFERS];
  234. SecBufferDesc sbdIn;
  235. PSecBufferDesc psbdIn;
  236. // Calling with challenge; expect SEC_E_OK or SEC_E_NO_CREDENTIALS
  237. if (szChallenge)
  238. {
  239. // Setup the challenge input buffer always (0th buffer)
  240. sbIn[SEC_BUFFER_CHALLENGE_INDEX].pvBuffer = szChallenge;
  241. sbIn[SEC_BUFFER_CHALLENGE_INDEX].cbBuffer = strlen(szChallenge);
  242. sbIn[SEC_BUFFER_CHALLENGE_INDEX].BufferType = SECBUFFER_TOKEN;
  243. // If we have a user, setup the user buffer (1st buffer)
  244. sbIn[SEC_BUFFER_USERNAME_INDEX].pvBuffer = szUser ? szUser : NULL;
  245. sbIn[SEC_BUFFER_USERNAME_INDEX].cbBuffer = szUser ? strlen(szUser) : NULL;
  246. sbIn[SEC_BUFFER_USERNAME_INDEX].BufferType = SECBUFFER_TOKEN;
  247. // If we have a password, setup the password buffer (2nd buffer for
  248. // a total of 3 buffers passed in (challenge + user + pass)
  249. sbIn[SEC_BUFFER_PASSWORD_INDEX].pvBuffer = szPass ? szPass : NULL;
  250. sbIn[SEC_BUFFER_PASSWORD_INDEX].cbBuffer = szPass ? strlen(szPass) : NULL;
  251. sbIn[SEC_BUFFER_PASSWORD_INDEX].BufferType = SECBUFFER_TOKEN;
  252. sbdIn.pBuffers = sbIn;
  253. // If either or both user and pass passed in, set num input buffers to 3
  254. // (SEC_BUFFER_NUM_EXTENDED_BUFFERS)
  255. if (szUser || szPass)
  256. sbdIn.cBuffers = SEC_BUFFER_NUM_EXTENDED_BUFFERS;
  257. // else we're just passing in the one challenge buffer (0th buffer as usual)
  258. else
  259. sbdIn.cBuffers = SEC_BUFFER_NUM_NORMAL_BUFFERS;
  260. psbdIn = &sbdIn;
  261. }
  262. else
  263. {
  264. // Calling withOUT challenge; expect SEC_I_CONTINUE_NEEDED;
  265. psbdIn = NULL;
  266. }
  267. // Output buffer and descriptor.
  268. SecBuffer sbOut[1];
  269. SecBufferDesc sbdOut;
  270. sbOut[0].pvBuffer = szResponse;
  271. sbOut[0].cbBuffer = MAX_OUTPUT_BUFFER;
  272. sbOut[0].BufferType = SECBUFFER_TOKEN;
  273. sbdOut.pBuffers = sbOut;
  274. sbdOut.cBuffers = 1;
  275. // ***** SSPI CALL *****
  276. ssResult = (*(pFuncTbl->InitializeSecurityContextA))
  277. (phCred, // phCredential (from AcquireCredentialsHandle)
  278. phCtxt, // phContext (NULL on first call, phNewCtxt on subsequent calls).
  279. NULL, // pszTargetName (not used)
  280. fContextReq, // fContextReq (auth from cache, prompt or auth using supplied creds)
  281. 0, // Reserved1 (not used)
  282. 0, // TargetDataRep (not used)
  283. psbdIn, // PSecBufDesc (input buffer descriptor)
  284. 0, // Reserved2 (not used)
  285. phNewCtxt, // phNewContext (should be passed back as phCtxt on subsequent calls)
  286. &sbdOut, // pOutput (output buffer descriptor)
  287. NULL, // pfContextAttr (pfContextAttr, not used)
  288. NULL); // ptsExpiry (not used)
  289. return ssResult;
  290. }
  291. //--------------------------------------
  292. // FCH
  293. //--------------------------------------
  294. SECURITY_STATUS FCH(PCredHandle phCred)
  295. {
  296. SECURITY_STATUS ssResult;
  297. // ***** SSPI CALL *****
  298. ssResult = (*(pFuncTbl->FreeCredentialsHandle))(phCred);
  299. return ssResult;
  300. }
  301. // Utility calls.
  302. //--------------------------------------
  303. // InitializeSecurityInterface
  304. //--------------------------------------
  305. VOID InitializeSecurityInterface(BOOL fDirect)
  306. {
  307. INIT_SECURITY_INTERFACE addrProcISI = NULL;
  308. OSVERSIONINFO VerInfo;
  309. CHAR szDLL[MAX_PATH];
  310. if (!fDirect)
  311. {
  312. VerInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
  313. GetVersionEx (&VerInfo);
  314. if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
  315. {
  316. lstrcpy (szDLL, SSP_SPM_NT_DLL);
  317. }
  318. else if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
  319. {
  320. lstrcpy (szDLL, SSP_SPM_WIN95_DLL);
  321. }
  322. }
  323. else
  324. {
  325. strcpy(szDLL, "d:\\nt\\private\\inet\\digest\\objd\\i386\\digest.dll");
  326. }
  327. hSecLib = LoadLibrary (szDLL);
  328. addrProcISI = (INIT_SECURITY_INTERFACE) GetProcAddress( hSecLib,
  329. SECURITY_ENTRYPOINT_ANSI);
  330. pFuncTbl = (*addrProcISI)();
  331. }
  332. //--------------------------------------
  333. // HaveDigest
  334. //--------------------------------------
  335. BOOL HaveDigest()
  336. {
  337. SECURITY_STATUS ssResult;
  338. DWORD cPackages;
  339. PSecPkgInfoA pSecPkgInfo;
  340. BOOL fHaveDigest;
  341. // ***** SSPI call *****
  342. ssResult = (*(pFuncTbl->EnumerateSecurityPackagesA))(&cPackages, &pSecPkgInfo);
  343. // Check if we have digest.
  344. fHaveDigest = FALSE;
  345. if (ssResult == SEC_E_OK)
  346. {
  347. for (DWORD i = 0; i < cPackages; i++)
  348. {
  349. if (strcmp(pSecPkgInfo[i].Name, "Digest") == 0)
  350. {
  351. fHaveDigest = TRUE;
  352. break;
  353. }
  354. }
  355. }
  356. return fHaveDigest;
  357. }