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.

510 lines
11 KiB

  1. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. //
  3. // METHOD.CPP
  4. //
  5. // Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
  6. //
  7. #include "_davprs.h"
  8. #include <statcode.h>
  9. #include "ecb.h"
  10. #include "instdata.h"
  11. // ------------------------------------------------------------------------
  12. //
  13. // DAVUnsupported()
  14. //
  15. // Execute an unsupported method --> Return "501 Not Supported" to client
  16. //
  17. void
  18. DAVUnsupported( LPMETHUTIL pmu )
  19. {
  20. // Get our access perms
  21. //
  22. SCODE sc = S_OK;
  23. // Do ISAPI application and IIS access bits checking
  24. //
  25. sc = pmu->ScIISCheck (pmu->LpwszRequestUrl());
  26. if (FAILED(sc))
  27. {
  28. // Either the request has been forwarded, or some bad error occurred.
  29. // In either case, quit here and map the error!
  30. //
  31. goto ret;
  32. }
  33. ret:
  34. pmu->SetResponseCode( FAILED(sc)
  35. ? HscFromHresult(sc)
  36. : HSC_NOT_IMPLEMENTED,
  37. NULL,
  38. 0 );
  39. }
  40. // ========================================================================
  41. //
  42. // STRUCT SMethod
  43. //
  44. // Encapsulates DAV method execution information.
  45. //
  46. // This is represented as a structure rather than a class since the method
  47. // objects are all const globals and MSVC won't initialize global objects
  48. // in a DLL to anything but 0-filled memory without an explicit call to
  49. // _CRT_INIT at process attach. _CRT_INIT is too expensive to call just
  50. // to initialize globals with constant data values which are known
  51. // at compile time.
  52. //
  53. typedef struct SMethod
  54. {
  55. //
  56. // Verb ("GET", "PUT", etc.)
  57. //
  58. //
  59. LPCSTR lpszVerb;
  60. LPCWSTR pwszVerb;
  61. //
  62. // Method ID
  63. //
  64. METHOD_ID mid;
  65. //
  66. // Implementation execution function
  67. //
  68. DAVMETHOD * Execute;
  69. } SMethod;
  70. const SMethod g_rgMethods[] =
  71. {
  72. //
  73. // For best performance, entries in this array should be
  74. // ordered by relative frequency.
  75. //
  76. //$OPT Right now, they obviously are not.
  77. //
  78. {
  79. "OPTIONS",
  80. L"OPTIONS",
  81. MID_OPTIONS,
  82. DAVOptions
  83. },
  84. {
  85. "GET",
  86. L"GET",
  87. MID_GET,
  88. DAVGet
  89. },
  90. {
  91. "HEAD",
  92. L"HEAD",
  93. MID_HEAD,
  94. DAVHead
  95. },
  96. {
  97. "PUT",
  98. L"PUT",
  99. MID_PUT,
  100. DAVPut
  101. },
  102. {
  103. "POST",
  104. L"POST",
  105. MID_POST,
  106. DAVPost
  107. },
  108. {
  109. "MOVE",
  110. L"MOVE",
  111. MID_MOVE,
  112. DAVMove
  113. },
  114. {
  115. "COPY",
  116. L"COPY",
  117. MID_COPY,
  118. DAVCopy
  119. },
  120. {
  121. "DELETE",
  122. L"DELETE",
  123. MID_DELETE,
  124. DAVDelete
  125. },
  126. {
  127. "MKCOL",
  128. L"MKCOL",
  129. MID_MKCOL,
  130. DAVMkCol
  131. },
  132. {
  133. "PROPFIND",
  134. L"PROPFIND",
  135. MID_PROPFIND,
  136. DAVPropFind
  137. },
  138. {
  139. "PROPPATCH",
  140. L"PROPPATCH",
  141. MID_PROPPATCH,
  142. DAVPropPatch
  143. },
  144. {
  145. "SEARCH",
  146. L"SEARCH",
  147. MID_SEARCH,
  148. DAVSearch
  149. },
  150. {
  151. "LOCK",
  152. L"LOCK",
  153. MID_LOCK,
  154. DAVLock
  155. },
  156. {
  157. "UNLOCK",
  158. L"UNLOCK",
  159. MID_UNLOCK,
  160. DAVUnlock
  161. },
  162. {
  163. NULL,
  164. NULL,
  165. MID_UNKNOWN,
  166. DAVUnsupported
  167. }
  168. };
  169. METHOD_ID
  170. MidMethod (LPCSTR pszMethod)
  171. {
  172. const SMethod * pMethod;
  173. for ( pMethod = g_rgMethods; pMethod->lpszVerb != NULL; pMethod++ )
  174. if ( !strcmp( pszMethod, pMethod->lpszVerb ) )
  175. break;
  176. return pMethod->mid;
  177. }
  178. METHOD_ID
  179. MidMethod (LPCWSTR pwszMethod)
  180. {
  181. const SMethod * pMethod;
  182. for ( pMethod = g_rgMethods; pMethod->pwszVerb != NULL; pMethod++ )
  183. if ( !wcscmp( pwszMethod, pMethod->pwszVerb ) )
  184. break;
  185. return pMethod->mid;
  186. }
  187. // Debug SID vs Name ---------------------------------------------------------
  188. //
  189. #ifdef DBG
  190. VOID
  191. SpitUserNameAndSID (CHAR * rgch)
  192. {
  193. enum { TOKENBUFFSIZE = (256*6) + sizeof(TOKEN_USER)};
  194. auto_handle<HANDLE> hTok;
  195. BYTE tokenbuff[TOKENBUFFSIZE];
  196. TOKEN_USER *ptu = reinterpret_cast<TOKEN_USER *>(tokenbuff);
  197. ULONG ulcbTok = sizeof(tokenbuff);
  198. *rgch = '\0';
  199. // Open the process and the process token, and get out the
  200. // security ID.
  201. //
  202. if (!OpenThreadToken (GetCurrentThread(),
  203. TOKEN_QUERY,
  204. TRUE, //$ TRUE for Process security!
  205. hTok.load()))
  206. {
  207. if (ERROR_NO_TOKEN != GetLastError())
  208. {
  209. DebugTrace( "OpenThreadToken() failed %d\n", GetLastError() );
  210. return;
  211. }
  212. if (!OpenProcessToken (GetCurrentProcess(),
  213. TOKEN_QUERY,
  214. hTok.load()))
  215. {
  216. DebugTrace( "OpenProcessToken() failed %d\n", GetLastError() );
  217. return;
  218. }
  219. }
  220. if (GetTokenInformation (hTok,
  221. TokenUser,
  222. ptu,
  223. ulcbTok,
  224. &ulcbTok))
  225. {
  226. ULONG IdentifierAuthority;
  227. BYTE * pb = (BYTE*)&IdentifierAuthority;
  228. SID * psid = reinterpret_cast<SID *>(ptu->User.Sid);
  229. for (INT i = 0; i < sizeof(ULONG); i++)
  230. {
  231. *pb++ = psid->IdentifierAuthority.Value[5-i];
  232. }
  233. wsprintfA (rgch, "S-%d-%d",
  234. psid->Revision,
  235. IdentifierAuthority);
  236. for (i = 0; i < psid->SubAuthorityCount; i++)
  237. {
  238. // The SubAuthority is a PDWORD which can be 64 bits
  239. // at the most in the forseable future, 2^64 = 10^20,
  240. // so we should use 23 (20 for the SubAuthority, a terminating
  241. // NULL plus the "- ". If snprintf
  242. // is not able to print the NULL, we will add it ourselves.
  243. //
  244. CHAR rgchT[23];
  245. _snprintf (rgchT, sizeof(rgchT), "-%d", psid->SubAuthority[i]);
  246. rgchT[CElems(rgchT) - 1] = '\0';
  247. lstrcatA (rgch, rgchT);
  248. }
  249. if (1 == psid->Revision)
  250. {
  251. if (0 == IdentifierAuthority)
  252. lstrcatA (rgch, " (Null)");
  253. if (1 == IdentifierAuthority)
  254. lstrcatA (rgch, " (World)");
  255. if (2 == IdentifierAuthority)
  256. lstrcatA (rgch, " (Local)");
  257. if (3 == IdentifierAuthority)
  258. lstrcatA (rgch, " (Creator)");
  259. if (4 == IdentifierAuthority)
  260. lstrcatA (rgch, " (Non-Unique)");
  261. if (5 == IdentifierAuthority)
  262. lstrcatA (rgch, " (NT)");
  263. }
  264. CHAR rgchAccount[MAX_PATH];
  265. CHAR rgchDomain[MAX_PATH];
  266. DWORD cbAccount = sizeof(rgchAccount) - 1;
  267. DWORD cbDomain = sizeof(rgchDomain) - 1;
  268. SID_NAME_USE snu;
  269. LookupAccountSidA (NULL,
  270. psid,
  271. rgchAccount,
  272. &cbAccount,
  273. rgchDomain,
  274. &cbDomain,
  275. &snu);
  276. lstrcatA (rgch, " ");
  277. lstrcatA (rgch, rgchDomain);
  278. lstrcatA (rgch, "\\");
  279. lstrcatA (rgch, rgchAccount);
  280. DavprsDbgHeadersTrace ("Dav: header: x-Dav-Debug-SID: %hs\n", rgch);
  281. }
  282. }
  283. VOID DebugAddSIDHeader( IMethUtil& mu )
  284. {
  285. CHAR rgch[4096];
  286. if (!DEBUG_TRACE_TEST(DavprsDbgHeaders))
  287. return;
  288. SpitUserNameAndSID (rgch);
  289. mu.SetResponseHeader ("x-Dav-Debug-SID", rgch);
  290. }
  291. #else
  292. #define DebugAddSIDHeader(_mu)
  293. #endif // DBG
  294. // ----------------------------------------------------------------------------
  295. //
  296. // CDAVExt::DwMain()
  297. //
  298. // Invokes a DAV method. This is THE function called by our IIS entrypoint
  299. // DwDavXXExtensionProc() to start processing a request.
  300. //
  301. // If MINIMAL_ISAPI is defined, this function is implemented in another
  302. // file (.\appmain.cpp). See the implementation there for what MINIMAL_ISAPI
  303. // does.
  304. //
  305. #ifndef MINIMAL_ISAPI
  306. DWORD
  307. CDAVExt::DwMain( LPEXTENSION_CONTROL_BLOCK pecbRaw,
  308. BOOL fUseRawUrlMappings /* = FALSE */ )
  309. {
  310. #ifdef DBG
  311. CHAR rgch[1024];
  312. DWORD cch;
  313. cch = sizeof(rgch);
  314. if (pecbRaw->GetServerVariable (pecbRaw->ConnID, "REQUEST_METHOD", rgch, &cch))
  315. EcbTrace ("CDAVExt::DwMain() called via method: %hs\n", rgch);
  316. cch = sizeof(rgch);
  317. if (pecbRaw->GetServerVariable (pecbRaw->ConnID, "ALL_RAW", rgch, &cch))
  318. EcbTrace ("CDAVExt::DwMain() called with RAW:\n%hs\n", rgch);
  319. cch = sizeof(rgch);
  320. if (pecbRaw->GetServerVariable (pecbRaw->ConnID, "ALL_HTTP", rgch, &cch))
  321. EcbTrace ("CDAVExt::DwMain() called with HTTP:\n%hs\n", rgch);
  322. #endif // DBG
  323. auto_ref_ptr<IEcb> pecb;
  324. DWORD dwHSEStatusRet = 0;
  325. BOOL fCaughtException = FALSE;
  326. HANDLE hitUser = INVALID_HANDLE_VALUE;
  327. try
  328. {
  329. //
  330. // Don't let hardware exceptions (AVs, etc.)
  331. // leave this try block
  332. //
  333. CWin32ExceptionHandler win32ExceptionHandler;
  334. pecb.take_ownership(NewEcb(*pecbRaw, fUseRawUrlMappings, &dwHSEStatusRet));
  335. //
  336. // If for whatever reason we failed to create a CEcb then bail
  337. // and return whatever status we were told to return.
  338. //
  339. // Note: return HSE_STATUS_SUCCESS here, not HSE_STATUS_ERROR.
  340. // We have sent back a 500 Server Error response to the client
  341. // so we don't need to send back any kind of error to IIS.
  342. //
  343. if ( !pecb.get() )
  344. {
  345. // All valid HSE status codes are non-zero (how convenient!)
  346. // so we can make sure that we are returning a valid HSE
  347. // status code here.
  348. //
  349. Assert( dwHSEStatusRet != 0 );
  350. return dwHSEStatusRet;
  351. }
  352. const SMethod * pMethod;
  353. //
  354. // Lookup the method object for this verb
  355. //
  356. for ( pMethod = g_rgMethods; pMethod->lpszVerb != NULL; pMethod++ )
  357. if ( !strcmp( pecb->LpszMethod(), pMethod->lpszVerb ) )
  358. break;
  359. //
  360. // Build request and response objects.
  361. //
  362. auto_ref_ptr<IRequest> prequest( NewRequest( *pecb ) );
  363. auto_ref_ptr<IResponse> presponse( NewResponse( *pecb ) );
  364. //
  365. // If impersonation is required, do it here
  366. //
  367. hitUser = pecb->HitUser();
  368. if ((NULL == hitUser) || (INVALID_HANDLE_VALUE == hitUser))
  369. {
  370. //$ REVIEW: SECURITY: If HitUser() returns any
  371. // value of NULL or INVALID_HANDLE_VALUE, then a call
  372. // to augment the user's token to include USG
  373. // group membership failed. Since this token
  374. // is not augmented with the additional group
  375. // that may be included in any/all deny ACL's
  376. // we want to fail this request immediately.
  377. //
  378. // We treat the failure as a 500 level error.
  379. //
  380. pecb->SendAsyncErrorResponse (500,
  381. gc_szDefErrStatusLine,
  382. gc_cchszDefErrStatusLine,
  383. gc_szUsgErrBody,
  384. gc_cchszUsgErrBody);
  385. //
  386. // Return HSE_STATUS_PENDING on success. We will call
  387. // HSE_REQ_DONE_WITH_SESSION when the CEcb is destroyed.
  388. //
  389. dwHSEStatusRet = HSE_STATUS_PENDING;
  390. //
  391. //$ REVIEW: SECURITY: end.
  392. }
  393. else
  394. {
  395. safe_impersonation si( hitUser );
  396. // If we failed to impersonate, we should not process any
  397. // portion of the the request.
  398. //
  399. if (!si.FImpersonated())
  400. throw CHresultException(E_FAIL);
  401. // Let the implementation handle the request.
  402. //
  403. {
  404. auto_ref_ptr<CMethUtil> pmu( CMethUtil::NewMethUtil( *pecb,
  405. *prequest,
  406. *presponse,
  407. pMethod->mid ) );
  408. DebugAddSIDHeader( *pmu );
  409. //
  410. // Execute the method
  411. //
  412. pMethod->Execute( pmu.get() );
  413. }
  414. //
  415. // Call the method completion function on the response.
  416. // This does all work necessary to finish handling the
  417. // response as far as the method is concerned, including
  418. // sending the response if it was not deferred by the impl.
  419. //
  420. presponse->FinishMethod();
  421. //
  422. // Return HSE_STATUS_PENDING on success. We will call
  423. // HSE_REQ_DONE_WITH_SESSION when the CEcb is destroyed.
  424. //
  425. dwHSEStatusRet = HSE_STATUS_PENDING;
  426. }
  427. }
  428. catch ( CDAVException& )
  429. {
  430. fCaughtException = TRUE;
  431. }
  432. //
  433. // If we caught an exception then handle it as best we can
  434. //
  435. if ( fCaughtException )
  436. {
  437. //
  438. // If we have a CEcb then use it to handle the server error.
  439. // If we don't have one (i.e. we threw an exception trying
  440. // to allocate/build one) then return an error to IIS
  441. // and let it handle it.
  442. //
  443. dwHSEStatusRet =
  444. pecb.get() ? pecb->HSEHandleException() :
  445. HSE_STATUS_ERROR;
  446. }
  447. //
  448. // All valid HSE status codes are non-zero (how convenient!)
  449. // so we can make sure that we are returning a valid HSE
  450. // status code here.
  451. //
  452. Assert( dwHSEStatusRet != 0 );
  453. return dwHSEStatusRet;
  454. }
  455. #endif // !defined(MINIMAL_ISAPI)