pcutil.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. #include <kopano/platform.h>
  18. #include <utility>
  19. #include "pcutil.hpp"
  20. #include <mapicode.h>
  21. #include <kopano/stringutil.h>
  22. #include <mapidefs.h>
  23. #include <kopano/ECGuid.h>
  24. #include "versions.h"
  25. namespace KC {
  26. bool IsKopanoEntryId(ULONG cb, LPBYTE lpEntryId)
  27. {
  28. EID* peid = NULL;
  29. if(lpEntryId == NULL)
  30. return false;
  31. peid = (PEID)lpEntryId;
  32. /* TODO: maybe also a check on objType */
  33. if( (cb == sizeof(EID) && peid->ulVersion == 1) ||
  34. (cb == sizeof(EID_V0) && peid->ulVersion == 0 ) )
  35. return true;
  36. return false;
  37. }
  38. bool ValidateZEntryId(ULONG cb, LPBYTE lpEntryId, unsigned int ulCheckType)
  39. {
  40. EID* peid = NULL;
  41. if(lpEntryId == NULL)
  42. return false;
  43. peid = (PEID)lpEntryId;
  44. if( ((cb == sizeof(EID) && peid->ulVersion == 1) ||
  45. (cb == sizeof(EID_V0) && peid->ulVersion == 0 ) ) &&
  46. peid->usType == ulCheckType)
  47. return true;
  48. return false;
  49. }
  50. /**
  51. * Validate a kopano entryid list on a specific mapi object type
  52. *
  53. * @param lpMsgList Pointer to an ENTRYLIST structure that contains the number
  54. * of items to validate and an array of ENTRYID structures identifying the items.
  55. * @param ulCheckType Contains the type of the objects in the lpMsgList.
  56. *
  57. * @return bool true if all the items in the lpMsgList matches with the object type
  58. */
  59. bool ValidateZEntryList(LPENTRYLIST lpMsgList, unsigned int ulCheckType)
  60. {
  61. EID* peid = NULL;
  62. if (lpMsgList == NULL)
  63. return false;
  64. for (ULONG i = 0; i < lpMsgList->cValues; ++i) {
  65. peid = (PEID)lpMsgList->lpbin[i].lpb;
  66. if( !(((lpMsgList->lpbin[i].cb == sizeof(EID) && peid->ulVersion == 1) ||
  67. (lpMsgList->lpbin[i].cb == sizeof(EID_V0) && peid->ulVersion == 0 ) ) &&
  68. peid->usType == ulCheckType))
  69. return false;
  70. }
  71. return true;
  72. }
  73. ECRESULT GetStoreGuidFromEntryId(ULONG cb, LPBYTE lpEntryId, LPGUID lpguidStore)
  74. {
  75. EID* peid = NULL;
  76. if(lpEntryId == NULL || lpguidStore == NULL)
  77. return KCERR_INVALID_PARAMETER;
  78. peid = (PEID)lpEntryId;
  79. if(!((cb == sizeof(EID) && peid->ulVersion == 1) ||
  80. (cb == sizeof(EID_V0) && peid->ulVersion == 0 )) )
  81. return KCERR_INVALID_ENTRYID;
  82. memcpy(lpguidStore, &peid->guid, sizeof(GUID));
  83. return erSuccess;
  84. }
  85. ECRESULT GetObjTypeFromEntryId(ULONG cb, LPBYTE lpEntryId, unsigned int* lpulObjType)
  86. {
  87. EID* peid = NULL;
  88. if (lpEntryId == NULL || lpulObjType == NULL)
  89. return KCERR_INVALID_PARAMETER;
  90. peid = (PEID)lpEntryId;
  91. if(!((cb == sizeof(EID) && peid->ulVersion == 1) ||
  92. (cb == sizeof(EID_V0) && peid->ulVersion == 0 )) )
  93. return KCERR_INVALID_ENTRYID;
  94. *lpulObjType = peid->usType;
  95. return erSuccess;
  96. }
  97. ECRESULT GetObjTypeFromEntryId(entryId sEntryId, unsigned int* lpulObjType) {
  98. return GetObjTypeFromEntryId(sEntryId.__size, sEntryId.__ptr, lpulObjType);
  99. }
  100. ECRESULT GetStoreGuidFromEntryId(entryId sEntryId, LPGUID lpguidStore) {
  101. return GetStoreGuidFromEntryId(sEntryId.__size, sEntryId.__ptr, lpguidStore);
  102. }
  103. HRESULT HrGetStoreGuidFromEntryId(ULONG cb, LPBYTE lpEntryId, LPGUID lpguidStore)
  104. {
  105. return kcerr_to_mapierr(GetStoreGuidFromEntryId(cb, lpEntryId, lpguidStore));
  106. }
  107. HRESULT HrGetObjTypeFromEntryId(ULONG cb, LPBYTE lpEntryId, unsigned int* lpulObjType)
  108. {
  109. return kcerr_to_mapierr(GetObjTypeFromEntryId(cb, lpEntryId, lpulObjType));
  110. }
  111. ECRESULT ABEntryIDToID(ULONG cb, LPBYTE lpEntryId, unsigned int* lpulID, objectid_t* lpsExternId, unsigned int* lpulMapiType)
  112. {
  113. unsigned int ulID = 0;
  114. objectid_t sExternId;
  115. objectclass_t sClass = ACTIVE_USER;
  116. if (lpEntryId == NULL || lpulID == NULL || cb < CbNewABEID(""))
  117. return KCERR_INVALID_PARAMETER;
  118. auto lpABEID = reinterpret_cast<const ABEID *>(lpEntryId);
  119. if (memcmp(&lpABEID->guid, &MUIDECSAB, sizeof(GUID)) != 0)
  120. return KCERR_INVALID_ENTRYID;
  121. ulID = lpABEID->ulId;
  122. MAPITypeToType(lpABEID->ulType, &sClass);
  123. if (lpABEID->ulVersion == 1)
  124. sExternId = objectid_t(base64_decode(reinterpret_cast<const char *>(lpABEID->szExId)), sClass);
  125. *lpulID = ulID;
  126. if (lpsExternId)
  127. *lpsExternId = std::move(sExternId);
  128. if (lpulMapiType)
  129. *lpulMapiType = lpABEID->ulType;
  130. return erSuccess;
  131. }
  132. ECRESULT ABEntryIDToID(entryId* lpsEntryId, unsigned int* lpulID, objectid_t* lpsExternId, unsigned int *lpulMapiType)
  133. {
  134. if (lpsEntryId == NULL)
  135. return KCERR_INVALID_PARAMETER;
  136. return ABEntryIDToID(lpsEntryId->__size, lpsEntryId->__ptr, lpulID, lpsExternId, lpulMapiType);
  137. }
  138. ECRESULT SIEntryIDToID(ULONG cb, LPBYTE lpInstanceId, LPGUID guidServer, unsigned int *lpulInstanceId, unsigned int *lpulPropId)
  139. {
  140. LPSIEID lpInstanceEid;
  141. if (lpInstanceId == NULL)
  142. return KCERR_INVALID_PARAMETER;
  143. lpInstanceEid = (LPSIEID)lpInstanceId;
  144. if (guidServer)
  145. memcpy(guidServer, (LPBYTE)lpInstanceEid + sizeof(SIEID), sizeof(GUID));
  146. if (lpulInstanceId)
  147. *lpulInstanceId = lpInstanceEid->ulId;
  148. if (lpulPropId)
  149. *lpulPropId = lpInstanceEid->ulType;
  150. return erSuccess;
  151. }
  152. template<typename T> static int twcmp(T a, T b)
  153. {
  154. /* see elsewhere for raison d'être */
  155. return (a < b) ? -1 : (a == b) ? 0 : 1;
  156. }
  157. /**
  158. * Compares ab entryids and returns an int, can be used for sorting algorithms.
  159. * <0 left first
  160. * 0 same, or invalid
  161. * >0 right first
  162. */
  163. int SortCompareABEID(ULONG cbEntryID1, LPENTRYID lpEntryID1, ULONG cbEntryID2, LPENTRYID lpEntryID2)
  164. {
  165. int rv = 0;
  166. auto peid1 = reinterpret_cast<const ABEID *>(lpEntryID1);
  167. auto peid2 = reinterpret_cast<const ABEID *>(lpEntryID2);
  168. if (lpEntryID1 == NULL || lpEntryID2 == NULL)
  169. return 0;
  170. if (peid1->ulVersion != peid2->ulVersion)
  171. return twcmp(peid1->ulVersion, peid2->ulVersion);
  172. // sort: user(6), group(8), company(4)
  173. if (peid1->ulType != peid2->ulType) {
  174. if (peid1->ulType == MAPI_ABCONT)
  175. return -1;
  176. else if (peid2->ulType == MAPI_ABCONT)
  177. return 1;
  178. else
  179. rv = twcmp(peid1->ulType, peid2->ulType);
  180. if (rv != 0)
  181. return rv;
  182. }
  183. if (peid1->ulVersion == 0) {
  184. rv = twcmp(peid1->ulId, peid2->ulId);
  185. } else {
  186. rv = strcmp((char*)peid1->szExId, (char*)peid2->szExId);
  187. }
  188. if (rv != 0)
  189. return rv;
  190. rv = memcmp(&peid1->guid, &peid2->guid, sizeof(GUID));
  191. if (rv != 0)
  192. return rv;
  193. return 0;
  194. }
  195. bool CompareABEID(ULONG cbEntryID1, LPENTRYID lpEntryID1, ULONG cbEntryID2, LPENTRYID lpEntryID2)
  196. {
  197. auto peid1 = reinterpret_cast<const ABEID *>(lpEntryID1);
  198. auto peid2 = reinterpret_cast<const ABEID *>(lpEntryID2);
  199. if (lpEntryID1 == NULL || lpEntryID2 == NULL)
  200. return false;
  201. if (peid1->ulVersion == peid2->ulVersion)
  202. {
  203. if(cbEntryID1 != cbEntryID2)
  204. return false;
  205. if(cbEntryID1 < CbNewABEID(""))
  206. return false;
  207. if (peid1->ulVersion == 0) {
  208. if(peid1->ulId != peid2->ulId)
  209. return false;
  210. } else {
  211. if (strcmp((char*)peid1->szExId, (char*)peid2->szExId))
  212. return false;
  213. }
  214. }
  215. else
  216. {
  217. if (cbEntryID1 < CbNewABEID("") || cbEntryID2 < CbNewABEID(""))
  218. return false;
  219. if(peid1->ulId != peid2->ulId)
  220. return false;
  221. }
  222. if(peid1->guid != peid2->guid)
  223. return false;
  224. if(peid1->ulType != peid2->ulType)
  225. return false;
  226. return true;
  227. }
  228. HRESULT HrSIEntryIDToID(ULONG cb, LPBYTE lpInstanceId, LPGUID guidServer, unsigned int *lpulInstanceId, unsigned int *lpulPropId)
  229. {
  230. if(lpInstanceId == NULL)
  231. return MAPI_E_INVALID_PARAMETER;
  232. return kcerr_to_mapierr(SIEntryIDToID(cb, lpInstanceId, guidServer, lpulInstanceId, lpulPropId));
  233. }
  234. ECRESULT ABIDToEntryID(struct soap *soap, unsigned int ulID, const objectid_t& sExternId, entryId *lpsEntryId)
  235. {
  236. ECRESULT er;
  237. std::string strEncExId = base64_encode((unsigned char*)sExternId.id.c_str(), sExternId.id.size());
  238. unsigned int ulLen = 0;
  239. if (lpsEntryId == NULL)
  240. return KCERR_INVALID_PARAMETER;
  241. ulLen = CbNewABEID(strEncExId.c_str());
  242. auto lpUserEid = reinterpret_cast<ABEID *>(s_alloc<char>(soap, ulLen));
  243. memset(lpUserEid, 0, ulLen);
  244. lpUserEid->ulId = ulID;
  245. er = TypeToMAPIType(sExternId.objclass, &lpUserEid->ulType);
  246. if (er != erSuccess) {
  247. s_free(soap, lpUserEid);
  248. return er; /* or make default type user? */
  249. }
  250. memcpy(&lpUserEid->guid, &MUIDECSAB, sizeof(GUID));
  251. // If the externid is non-empty, we'll create a V1 entry id.
  252. if (!sExternId.id.empty())
  253. {
  254. lpUserEid->ulVersion = 1;
  255. // avoid FORTIFY_SOURCE checks in strcpy to an address that the compiler thinks is 1 size large
  256. memcpy(lpUserEid->szExId, strEncExId.c_str(), strEncExId.length()+1);
  257. }
  258. lpsEntryId->__size = ulLen;
  259. lpsEntryId->__ptr = (unsigned char*)lpUserEid;
  260. return erSuccess;
  261. }
  262. ECRESULT SIIDToEntryID(struct soap *soap, LPGUID guidServer, unsigned int ulInstanceId, unsigned int ulPropId, entryId *lpsInstanceId)
  263. {
  264. LPSIEID lpInstanceEid = NULL;
  265. ULONG ulSize = 0;
  266. assert(ulPropId < 0x0000FFFF);
  267. if (lpsInstanceId == NULL)
  268. return KCERR_INVALID_PARAMETER;
  269. ulSize = sizeof(SIEID) + sizeof(GUID);
  270. lpInstanceEid = (LPSIEID)s_alloc<char>(soap, ulSize);
  271. memset(lpInstanceEid, 0, ulSize);
  272. lpInstanceEid->ulId = ulInstanceId;
  273. lpInstanceEid->ulType = ulPropId;
  274. memcpy(&lpInstanceEid->guid, MUIDECSI_SERVER, sizeof(GUID));
  275. memcpy((char *)lpInstanceEid + sizeof(SIEID), guidServer, sizeof(GUID));
  276. lpsInstanceId->__size = ulSize;
  277. lpsInstanceId->__ptr = (unsigned char *)lpInstanceEid;
  278. return erSuccess;
  279. }
  280. ECRESULT SIEntryIDToID(entryId* sInstanceId, LPGUID guidServer, unsigned int *lpulInstanceId, unsigned int *lpulPropId)
  281. {
  282. if (sInstanceId == NULL)
  283. return KCERR_INVALID_PARAMETER;
  284. return SIEntryIDToID(sInstanceId->__size, sInstanceId->__ptr, guidServer, lpulInstanceId, lpulPropId);
  285. }
  286. // NOTE: when using this function, we can never be sure that we return the actual objectclass_t.
  287. // MAPI_MAILUSER can also be any type of nonactive user, groups can be security groups etc...
  288. // This can only be used as a hint. You should really look the user up since you should either know the
  289. // users table id, or extern id of the user too!
  290. ECRESULT MAPITypeToType(ULONG ulMAPIType, objectclass_t *lpsUserObjClass)
  291. {
  292. objectclass_t sUserObjClass = OBJECTCLASS_UNKNOWN;
  293. if (lpsUserObjClass == NULL)
  294. return KCERR_INVALID_PARAMETER;
  295. switch (ulMAPIType) {
  296. case MAPI_MAILUSER:
  297. sUserObjClass = OBJECTCLASS_USER;
  298. break;
  299. case MAPI_DISTLIST:
  300. sUserObjClass = OBJECTCLASS_DISTLIST;
  301. break;
  302. case MAPI_ABCONT:
  303. sUserObjClass = OBJECTCLASS_CONTAINER;
  304. break;
  305. default:
  306. return KCERR_INVALID_TYPE;
  307. }
  308. *lpsUserObjClass = std::move(sUserObjClass);
  309. return erSuccess;
  310. }
  311. ECRESULT TypeToMAPIType(objectclass_t sUserObjClass, ULONG *lpulMAPIType)
  312. {
  313. ULONG ulMAPIType = MAPI_MAILUSER;
  314. if (lpulMAPIType == NULL)
  315. return KCERR_INVALID_PARAMETER;
  316. // Check for correctness of mapping!
  317. switch (OBJECTCLASS_TYPE(sUserObjClass))
  318. {
  319. case OBJECTTYPE_MAILUSER:
  320. ulMAPIType = MAPI_MAILUSER;
  321. break;
  322. case OBJECTTYPE_DISTLIST:
  323. ulMAPIType = MAPI_DISTLIST;
  324. break;
  325. case OBJECTTYPE_CONTAINER:
  326. ulMAPIType = MAPI_ABCONT;
  327. break;
  328. default:
  329. return KCERR_INVALID_TYPE;
  330. }
  331. *lpulMAPIType = ulMAPIType;
  332. return erSuccess;
  333. }
  334. /**
  335. * Parse a Kopano version string in the form [0,]<general>,<major>,<minor>[,<svn_revision>] and
  336. * place the result in a 32 bit unsigned integer.
  337. * The format of the result is 1 byte general, 1 bytes major and 2 bytes minor.
  338. * The svn_revision is optional and ignored in any case.
  339. *
  340. * @param[in] strVersion The version string to parse
  341. * @param[out] lpulVersion Pointer to the unsigned integer in which the result is stored.
  342. *
  343. * @retval KCERR_INVALID_PARAMETER The version string could not be parsed.
  344. */
  345. ECRESULT ParseKopanoVersion(const std::string &strVersion, unsigned int *lpulVersion)
  346. {
  347. const char *lpszStart = strVersion.c_str();
  348. char *lpszEnd = NULL;
  349. unsigned int ulGeneral, ulMajor, ulMinor;
  350. // For some reason the server returns its version prefixed with "0,". We'll
  351. // just ignore that.
  352. // We assume that there's no actual live server running 0,x,y,z
  353. if (strncmp(lpszStart, "0,", 2) == 0)
  354. lpszStart += 2;
  355. ulGeneral = strtoul(lpszStart, &lpszEnd, 10);
  356. if (lpszEnd == NULL || lpszEnd == lpszStart || *lpszEnd != ',')
  357. return KCERR_INVALID_PARAMETER;
  358. lpszStart = lpszEnd + 1;
  359. ulMajor = strtoul(lpszStart, &lpszEnd, 10);
  360. if (lpszEnd == NULL || lpszEnd == lpszStart || *lpszEnd != ',')
  361. return KCERR_INVALID_PARAMETER;
  362. lpszStart = lpszEnd + 1;
  363. ulMinor = strtoul(lpszStart, &lpszEnd, 10);
  364. if (lpszEnd == NULL || lpszEnd == lpszStart || (*lpszEnd != ',' && *lpszEnd != '\0'))
  365. return KCERR_INVALID_PARAMETER;
  366. if (lpulVersion)
  367. *lpulVersion = MAKE_KOPANO_VERSION(ulGeneral, ulMajor, ulMinor);
  368. return erSuccess;
  369. }
  370. } /* namespace */