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.

459 lines
13 KiB

  1. /*
  2. * S T A T E T O K. H
  3. *
  4. * Sources implementation of DAV-Lock common definitions.
  5. *
  6. * Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
  7. */
  8. /*
  9. * This file contains the definitions used for parsing state token
  10. * relared headers.
  11. *
  12. */
  13. #ifndef __STATETOK_H__
  14. #define __STATETOK_H__
  15. // Current max seconds = 1 day.
  16. //
  17. DEC_CONST INT gc_cSecondsMaxLock = 60 * 60 * 24;
  18. // Current default lock time out is 3 minutes
  19. //
  20. DEC_CONST INT gc_cSecondsDefaultLock = 60 * 3;
  21. //$REVIEW These flags are duplicated in lockmgr.h and statetok.h. before
  22. //$REVIEW this is addressed, to be safe, we make sure they match
  23. //$REVIEW Also inherit the excellent comments from the lockmgr.h regarding
  24. //$REVIEW how the flags should be defined when we merge.
  25. #define DAV_LOCKTYPE_ROLLBACK 0x08000000
  26. #define DAV_LOCKTYPE_CHECKOUT 0x04000000
  27. #define DAV_LOCKTYPE_TRANSACTION_GOP 0x00100000
  28. #define DAV_LOCKTYPE_READWRITE (GENERIC_READ | GENERIC_WRITE)
  29. #define DAV_LOCKTYPE_FLAGS (GENERIC_READ | GENERIC_WRITE | DAV_LOCKTYPE_ROLLBACK | DAV_LOCKTYPE_CHECKOUT | DAV_LOCKTYPE_TRANSACTION_GOP)
  30. #define DAV_EXCLUSIVE_LOCK 0x01000000
  31. #define DAV_SHARED_LOCK 0x02000000
  32. #define DAV_LOCKSCOPE_LOCAL 0x04000000
  33. #define DAV_LOCKSCOPE_FLAGS (DAV_EXCLUSIVE_LOCK | DAV_SHARED_LOCK | DAV_LOCKSCOPE_LOCAL)
  34. #define DAV_RECURSIVE_LOCK 0x00800000
  35. #define DAV_LOCK_FLAGS (DAV_LOCKTYPE_FLAGS | DAV_RECURSIVE_LOCK | DAV_LOCKSCOPE_FLAGS)
  36. /*
  37. - IFITER
  38. -
  39. *
  40. * This is the parser copied from the original IF header processor
  41. * used in lockutil.cpp. Eventually lockutil.cpp shall use this
  42. * file since this file shall have only the common stuff sharable
  43. * between davex and davfs lock code.
  44. *
  45. * Comment format change to the style used in this file otherwise.
  46. *
  47. *
  48. */
  49. // ========================================================================
  50. //
  51. // class IFITER
  52. //
  53. // Built to parse the new If header.
  54. //
  55. // Format of the If header
  56. // If = "If" ":" ( 1*No-tag-list | 1*Tagged-list)
  57. // No-tag-list = List
  58. // Tagged-list = Resource 1*List
  59. // Resource = Coded-url
  60. // List = "(" 1*(["Not"](State-token | "[" entity-tag "]")) ")"
  61. // State-token = Coded-url
  62. // Coded-url = "<" URI ">"
  63. //
  64. //
  65. // NOTE: We are going to be lax about tagged/untagged lists.
  66. // If the first list is not tagged, but we find tagged lists later,
  67. // that's cool by me.
  68. // (Realize that there no problem switching from tagged to untagged --
  69. // because that case cannot be detected & distinguished from another
  70. // list for the same URI! The only problem is if the first list is
  71. // untagged, and later there are tagged lists. That is a case that
  72. // *should*, by a perfectly tight reading of the spec, be a bad request.
  73. // I am treating it as perfectly valid until someone tells me that I have
  74. // to do the extra 1 bit of bookkeeping.)
  75. //
  76. // State machine for this class
  77. // It's a really simple state machine.
  78. // (NOTE that I'm calling statetokens and etags "tokens", and the
  79. // contents of a single set of parentheses a "list", just like above.)
  80. //
  81. // Three possible states: NONE, NAME, and LIST.
  82. // Starts in state NONE -- can accept a tag (URI) or a start of a list.
  83. // Moves to NAME if a tag (URI) is encountered.
  84. // Only a list can follow a tag (URI).
  85. // Moves to LIST when a list start (left paren) is encountered.
  86. // Moves back to NONE when a list end (right paren) is encountered.
  87. //
  88. // ------------------------------------------------------------------------
  89. // enum FETCH_TOKEN_TYPE
  90. // These are the flags used in IFITER::PszNextToken.
  91. // There are two basic types of fetching:
  92. // o advance to next item of this type (xxx_NEW_xxx)
  93. // o fetch the next item & fail if the type does not match.
  94. //
  95. enum FETCH_TOKEN_TYPE
  96. {
  97. TOKEN_URI, // Fetch a URI, don't skip anything.
  98. TOKEN_NEW_URI, // Advance to the next URI, skipping stuff in between.
  99. TOKEN_START_LIST, // Fetch the next list item. Must be the starting list item.
  100. TOKEN_SAME_LIST, // Fetch the next internal item in this list.
  101. TOKEN_NEW_LIST, // Advance to the next start of a list, skipping past the
  102. // end of the current list if necessary. Don't skip uris.
  103. TOKEN_ANY_LIST, // NTRaid#244243 -- special for looking up locktokens
  104. // Fetch the next item for this same uri -- can cross lists,
  105. // but not uris.
  106. TOKEN_NONE, // Empty marker.
  107. };
  108. class IFITER
  109. {
  110. private:
  111. enum STATE_TYPE
  112. {
  113. STATE_NONE,
  114. STATE_NAME,
  115. STATE_LIST,
  116. };
  117. const LPCWSTR m_pwszHdr;
  118. LPCWSTR m_pwch;
  119. StringBuffer<WCHAR> m_buf;
  120. // State bits
  121. STATE_TYPE m_state;
  122. BOOL m_fCurrentNot;
  123. // NOT IMPLEMENTED
  124. //
  125. IFITER& operator=( const IFITER& );
  126. IFITER( const IFITER& );
  127. public:
  128. IFITER (LPCWSTR pwsz=0) :
  129. m_pwszHdr(pwsz),
  130. m_pwch(pwsz),
  131. m_state(STATE_NONE),
  132. m_fCurrentNot(FALSE)
  133. {
  134. }
  135. ~IFITER() {}
  136. LPCWSTR PszNextToken (FETCH_TOKEN_TYPE type);
  137. BOOL FCurrentNot() const
  138. {
  139. return m_fCurrentNot;
  140. }
  141. void Restart()
  142. {
  143. m_pwch = m_pwszHdr; m_state = STATE_NONE;
  144. }
  145. };
  146. /*
  147. - PwszSkipCodes
  148. -
  149. * Remove <> or [] tags around stuff. Useful for if: header
  150. * tags. also eliminates the LWS near to the delimiters.
  151. *
  152. * *pdwLen may be zero or the length of the string. If zero
  153. * the routine calculate the length using strlen. Wasteful,
  154. * if you already know the length.
  155. *
  156. * Returns the pointer to the first non-lws, non-delimiter.
  157. * dwLen shall be set to the actual number of chars, from the
  158. * first to the last char which is non-lws, non-delimiter when
  159. * we start looking from the end. Does not stick the null char
  160. * at the end. Do it yourself, if you need to, using dwLen.
  161. *
  162. */
  163. LPCWSTR PwszSkipCodes(IN LPCWSTR pwszTagged, IN OUT DWORD *pdwLen);
  164. /*
  165. - CStateToken
  166. -
  167. * The state token is the lean string that we use to communicate
  168. * with the client. It is the external representation of a DAV lock
  169. * or any other kind of state information.
  170. *
  171. * State token is a quoted uri which is <uri> for the external world.
  172. * So we provide facilities to deal with this in this class. The < and
  173. * > are not useful for internal processing - so we hide this to our
  174. * customers - this will avoid copying to prepend the <.
  175. *
  176. * E-TAGs are special beasts and are just plain quoted strings surrounded
  177. * by [ and ].
  178. *
  179. */
  180. class CStateToken
  181. {
  182. public:
  183. // Common defintions which are public, also used privately!
  184. //
  185. typedef enum StateTokenType
  186. {
  187. TOKEN_NONE = 0,
  188. TOKEN_LOCK,
  189. TOKEN_TRANS,
  190. TOKEN_ETAG,
  191. TOKEN_RESTAG,
  192. } STATE_TOKEN_TYPE;
  193. // normally state tokens are about of this size
  194. // ie lock tokens.
  195. //
  196. enum { NORMAL_STATE_TOKEN_SIZE = 128 };
  197. private:
  198. // Token buffer
  199. //
  200. LPWSTR m_pwszToken;
  201. // Allocated size of the current buffer.
  202. //
  203. DWORD m_cchBuf;
  204. // type of the token
  205. //
  206. STATE_TOKEN_TYPE m_tType;
  207. // Never implemented
  208. //
  209. CStateToken( const CStateToken& );
  210. CStateToken& operator=( const CStateToken& );
  211. public:
  212. CStateToken() : m_pwszToken(NULL), m_cchBuf(0), m_tType(TOKEN_NONE)
  213. {
  214. };
  215. ~CStateToken()
  216. {
  217. if (NULL != m_pwszToken)
  218. ExFree(m_pwszToken);
  219. }
  220. // Plain token accepted here.
  221. // If the dwLen is zero, NULL terminated pszToken
  222. // is the token. If non zero, it gives actual
  223. // number of chars in the token.
  224. // Useful when we parse the if: header.
  225. //
  226. BOOL FSetToken(LPCWSTR pwszToken, BOOL fEtag, DWORD dwLen = 0);
  227. // Accessors to the token info
  228. //
  229. inline STATE_TOKEN_TYPE GetTokenType() const { return m_tType; }
  230. // TRUE if the lock tokens are equal.
  231. //
  232. BOOL FIsEqual(CStateToken *pstokRhs);
  233. // get a pointer to the token string
  234. //
  235. inline LPCWSTR WszGetToken() const { return m_pwszToken; }
  236. // Parses the state token as a lock token and
  237. // get the lock token information.. Note that our lock
  238. // tokens consist of a GUIID and a long long(int64).
  239. // The guid string must be long enough to hold a GUID
  240. // string (37 chars).
  241. //
  242. BOOL FGetLockTokenInfo(unsigned __int64 *pi64SeqNum, LPWSTR pwszGuid);
  243. };
  244. /*
  245. - CStateMatchOp
  246. -
  247. * This class is used as the base class for doing
  248. * state match operations including e-tag
  249. * checks. Each implementation shall derive its own
  250. * ways to check the state of the resource. This way
  251. * the core parse code is shared between subsystems.
  252. *
  253. * Not multi-thread safe - create,use and delete in a
  254. * single thread.
  255. *
  256. */
  257. class CStateMatchOp
  258. {
  259. private:
  260. // NOT IMPLEMENTED
  261. //
  262. CStateMatchOp( const CStateMatchOp& );
  263. CStateMatchOp& operator=( const CStateMatchOp& );
  264. protected:
  265. // Current token under investigation.
  266. // All derived classes can access it.
  267. // We do not pass this as the parameter.
  268. //
  269. CStateToken m_tokCurrent;
  270. friend class CIfHeadParser;
  271. // ---------------------------------------------------------
  272. // support API for the ifheader parser
  273. // set the current token
  274. //
  275. inline BOOL FSetToken(LPCWSTR pwszToken, BOOL fEtag)
  276. {
  277. return m_tokCurrent.FSetToken(pwszToken, fEtag);
  278. }
  279. // get the current token type
  280. //
  281. inline CStateToken::STATE_TOKEN_TYPE GetTokenType() const
  282. {
  283. return m_tokCurrent.GetTokenType();
  284. }
  285. // return the storage path of the uri. Note that davex and davfs
  286. // has different implementations of this.
  287. //
  288. virtual SCODE ScGetResourcePath(LPCWSTR pwszUri, LPCWSTR * ppwszStoragePath) = 0;
  289. // check if the resource is locked by the lock specified
  290. // by the current lock token above. fRecusrive says if the
  291. // condition is to be applied to all the resources under the
  292. // given path. Believe me, lpwszPath can be NULL. And it is
  293. // NULL when the match condition is to be applied on the
  294. // first path given to HrApplyIf!. Why we do this: normally
  295. // we do lotsa processing on the method's resource before
  296. // we call the if-header parser. This processing generates
  297. // info like e-tags which can be used to do the state match
  298. // check here. So the parser needs to tell the match checker
  299. // that this is for the original uri and NULL is the indication
  300. // of that.
  301. //
  302. virtual SCODE ScMatchLockToken(LPCWSTR pwszPath, BOOL fRecursive) = 0;
  303. virtual SCODE ScMatchResTag(LPCWSTR pwszPath) = 0;
  304. virtual SCODE ScMatchTransactionToken(LPCWSTR pwszPath) = 0;
  305. // Checks if the resource is in the state specified by the
  306. // (e-tag) state token above. Parameters have same meaning as above.
  307. //
  308. virtual SCODE ScMatchETag(LPCWSTR pwszPath, BOOL fRecursive) = 0;
  309. // -----------------------------------------------------------
  310. public:
  311. // Usual suspects of CTOR and DTOR
  312. //
  313. CStateMatchOp() { };
  314. ~CStateMatchOp() { };
  315. // Using this object as the match operator parse an if header.
  316. // This is used by all method impls.
  317. //
  318. SCODE ScParseIf(LPCWSTR pwszIfHeader, LPCWSTR rgpwszPaths[], DWORD cPaths, BOOL fRecur, SCODE * pSC);
  319. };
  320. /*
  321. - FCompareSids
  322. -
  323. * compare two sids
  324. *
  325. */
  326. inline BOOL FCompareSids(PSID pSidLeft, PSID pSidRight)
  327. {
  328. if ((NULL == pSidLeft) || (NULL == pSidRight))
  329. return FALSE;
  330. // Assert the SID validity.
  331. //
  332. Assert(IsValidSid(pSidLeft));
  333. Assert(IsValidSid(pSidRight));
  334. return EqualSid(pSidLeft, pSidRight);
  335. }
  336. /*
  337. - FSeparator
  338. -
  339. * returns true if input is a path separator - used below
  340. *
  341. */
  342. inline BOOL FSeparator(WCHAR wch)
  343. {
  344. return ((wch == L'\\') || (wch == L'/'));
  345. }
  346. /*
  347. - FIsChildPath
  348. -
  349. * compare two paths to check if the child is within the scope
  350. * of the parent.
  351. *
  352. * For non recursive match, the two paths must match exactly for
  353. * TRUE return. This is useful when tagged URIs within the IF header
  354. * is processed and we have a deep operation going on. The other place
  355. * this function is used is when we have a recursive lock and need to
  356. * find out if a path is locked by this lock.
  357. *
  358. */
  359. inline BOOL FIsChildPath(LPCWSTR pwszPathParent, LPCWSTR pwszPathChild, BOOL fRecursive)
  360. {
  361. UINT cchParentLen;
  362. if ((NULL == pwszPathParent) || (NULL == pwszPathChild))
  363. return FALSE;
  364. cchParentLen = static_cast<UINT>(wcslen(pwszPathParent));
  365. // If the parent path is not an initial substring
  366. // of child return fail immediately.
  367. //
  368. if ( 0 != _wcsnicmp(pwszPathChild, pwszPathParent, cchParentLen) )
  369. {
  370. return FALSE;
  371. }
  372. // Parent indeed is the initial substring.
  373. // Check the next char of child (for NULL) to see
  374. // if they match exactly. This is an instand good condition.
  375. //
  376. if (L'\0' == pwszPathChild[cchParentLen])
  377. {
  378. return TRUE;
  379. }
  380. // We still have hope for a match ONLY for recursive checks.
  381. //
  382. if (! fRecursive)
  383. {
  384. return FALSE;
  385. }
  386. else
  387. {
  388. // either parent or child need to have a separator
  389. //
  390. if ( FSeparator(pwszPathParent[cchParentLen-1]) ||
  391. FSeparator(pwszPathChild[cchParentLen]) )
  392. return TRUE;
  393. else
  394. return FALSE;
  395. }
  396. }
  397. #endif