ECSecurity.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470
  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. #include <kopano/platform.h>
  17. #include <memory>
  18. #include <utility>
  19. #include <kopano/tie.hpp>
  20. #include "ECDatabaseUtils.h"
  21. #include "ECDatabase.h"
  22. #include "ECSessionManager.h"
  23. #include "ECSession.h"
  24. #include <kopano/ECDefs.h>
  25. #include "ECSecurity.h"
  26. #include <kopano/stringutil.h>
  27. #include <kopano/Trace.h>
  28. #include "kcore.hpp"
  29. #include <mapidefs.h>
  30. #include <mapicode.h>
  31. #include <mapitags.h>
  32. #include <kopano/mapiext.h>
  33. #include <openssl/ssl.h>
  34. #include <openssl/evp.h>
  35. #include <openssl/x509.h>
  36. #include <openssl/bio.h>
  37. #include <algorithm>
  38. #include "ECUserManagement.h"
  39. #include "SOAPUtils.h"
  40. #include "SOAPDebug.h"
  41. #include <edkmdb.h>
  42. #include "ECDBDef.h"
  43. #include "cmdutil.hpp"
  44. using namespace KCHL;
  45. namespace KC {
  46. #define MAX_PARENT_LIMIT 64
  47. /**
  48. * @param[in] lpSession user session
  49. * @param[in] lpConfig config object
  50. * @param[in] lpLogger log object for normal logging
  51. * @param[in] lpAudit optional log object for auditing
  52. */
  53. ECSecurity::ECSecurity(ECSession *lpSession, ECConfig *lpConfig,
  54. ECLogger *lpAudit) :
  55. m_lpSession(lpSession), m_lpAudit(lpAudit), m_lpConfig(lpConfig)
  56. {
  57. if (m_lpAudit != NULL)
  58. m_lpAudit->AddRef();
  59. m_bRestrictedAdmin = parseBool(lpConfig->GetSetting("restrict_admin_permissions"));
  60. m_bOwnerAutoFullAccess = parseBool(lpConfig->GetSetting("owner_auto_full_access"));
  61. }
  62. ECSecurity::~ECSecurity()
  63. {
  64. delete m_lpGroups;
  65. delete m_lpViewCompanies;
  66. delete m_lpAdminCompanies;
  67. if (m_lpAudit != NULL)
  68. m_lpAudit->Release();
  69. }
  70. /**
  71. * Called once for each login after the object was constructed. Since
  72. * this function can return errors, this is not done in the
  73. * constructor.
  74. *
  75. * @param[in] ulUserId current logged in user
  76. *
  77. * @return Kopano error code
  78. */
  79. ECRESULT ECSecurity::SetUserContext(unsigned int ulUserId, unsigned int ulImpersonatorID)
  80. {
  81. ECRESULT er;
  82. ECUserManagement *lpUserManagement = m_lpSession->GetUserManagement();
  83. m_ulUserID = ulUserId;
  84. m_ulImpersonatorID = ulImpersonatorID;
  85. er = lpUserManagement->GetObjectDetails(m_ulUserID, &m_details);
  86. if(er != erSuccess)
  87. return er;
  88. // Get the company we're assigned to
  89. if (m_lpSession->GetSessionManager()->IsHostedSupported())
  90. m_ulCompanyID = m_details.GetPropInt(OB_PROP_I_COMPANYID);
  91. else
  92. m_ulCompanyID = 0;
  93. if (m_ulImpersonatorID != EC_NO_IMPERSONATOR) {
  94. unsigned int ulAdminLevel = 0;
  95. er = lpUserManagement->GetObjectDetails(m_ulImpersonatorID, &m_impersonatorDetails);
  96. if (er != erSuccess)
  97. return er;
  98. ulAdminLevel = m_impersonatorDetails.GetPropInt(OB_PROP_I_ADMINLEVEL);
  99. if (ulAdminLevel == 0) {
  100. return KCERR_NO_ACCESS;
  101. } else if (m_lpSession->GetSessionManager()->IsHostedSupported() == true && ulAdminLevel < ADMIN_LEVEL_SYSADMIN) {
  102. unsigned int ulCompanyID = m_impersonatorDetails.GetPropInt(OB_PROP_I_COMPANYID);
  103. if (ulCompanyID != m_ulCompanyID)
  104. return KCERR_NO_ACCESS;
  105. }
  106. }
  107. /*
  108. * Don't initialize m_lpGroups, m_lpViewCompanies and m_lpAdminCompanies
  109. * We should wait with that until the first time we actually use it,
  110. * this will save quite a lot of LDAP queries since often we don't
  111. * even need the list at all.
  112. */
  113. return erSuccess;
  114. }
  115. // helper class to remember groups we've seen to break endless loops
  116. class cUniqueGroup {
  117. public:
  118. bool operator()(const localobjectdetails_t &obj) const
  119. {
  120. return m_seen.find(obj) != m_seen.end();
  121. }
  122. std::set<localobjectdetails_t> m_seen;
  123. };
  124. /**
  125. * This function returns a list of security groups the user is a
  126. * member of. If a group contains a group, it will be appended to the
  127. * list. The list will be a unique list of groups in the end.
  128. *
  129. * @param[in] ulUserId A user or group to query the grouplist for.
  130. * @param[out] lppGroups The unique list of group ids
  131. *
  132. * @return Kopano error code
  133. */
  134. ECRESULT ECSecurity::GetGroupsForUser(unsigned int ulUserId, std::list<localobjectdetails_t> **lppGroups)
  135. {
  136. ECRESULT er;
  137. std::list<localobjectdetails_t> *lpGroups = NULL;
  138. cUniqueGroup cSeenGroups;
  139. /* Gets the current user's membership information.
  140. * This means you will be in the same groups until you login again */
  141. er = m_lpSession->GetUserManagement()->GetParentObjectsOfObjectAndSync(OBJECTRELATION_GROUP_MEMBER,
  142. ulUserId, &lpGroups, USERMANAGEMENT_IDS_ONLY);
  143. if (er != erSuccess)
  144. return er;
  145. /* A user is only member of a group when he can also view the group */
  146. for (auto iterGroups = lpGroups->begin(); iterGroups != lpGroups->cend(); ) {
  147. /*
  148. * Since this function is only used by ECSecurity, we can only
  149. * test for security groups here. However, normal groups were
  150. * used to be security enabled, so only check for dynamic
  151. * groups here to exclude.
  152. */
  153. if (IsUserObjectVisible(iterGroups->ulId) != erSuccess || iterGroups->GetClass() == DISTLIST_DYNAMIC) {
  154. lpGroups->erase(iterGroups++);
  155. continue;
  156. }
  157. cSeenGroups.m_seen.insert(*iterGroups);
  158. std::list<localobjectdetails_t> *lpGroupInGroups = NULL;
  159. er = m_lpSession->GetUserManagement()->GetParentObjectsOfObjectAndSync(OBJECTRELATION_GROUP_MEMBER,
  160. iterGroups->ulId, &lpGroupInGroups, USERMANAGEMENT_IDS_ONLY);
  161. if (er == erSuccess) {
  162. // Adds all groups from lpGroupInGroups to the main lpGroups list, except when already in cSeenGroups
  163. remove_copy_if(lpGroupInGroups->begin(), lpGroupInGroups->end(), back_inserter(*lpGroups), cSeenGroups);
  164. delete lpGroupInGroups;
  165. }
  166. // Ignore error (eg. cannot use that function on group Everyone)
  167. ++iterGroups;
  168. }
  169. *lppGroups = lpGroups;
  170. return erSuccess;
  171. }
  172. /**
  173. * Return the bitmask of permissions for an object
  174. *
  175. * @param[in] ulObjId hierarchy object to get permission mask for
  176. * @param[out] lpulRights permission mask
  177. *
  178. * @return always erSuccess
  179. */
  180. ECRESULT ECSecurity::GetObjectPermission(unsigned int ulObjId, unsigned int* lpulRights)
  181. {
  182. ECRESULT er = erSuccess;
  183. struct rightsArray *lpRights = NULL;
  184. unsigned ulCurObj = ulObjId;
  185. bool bFoundACL = false;
  186. unsigned int ulDepth = 0;
  187. *lpulRights = 0;
  188. // Get the deepest GRANT ACL that applies to this user or groups that this user is in
  189. // WARNING we totally ignore DENY ACL's here. This means that the deepest GRANT counts. In practice
  190. // this doesn't matter because GRANTmask = ~DENYmask.
  191. while(true)
  192. {
  193. if(m_lpSession->GetSessionManager()->GetCacheManager()->GetACLs(ulCurObj, &lpRights) == erSuccess) {
  194. // This object has ACL's, check if any of them are for this user
  195. for (gsoap_size_t i = 0; i < lpRights->__size; ++i)
  196. if(lpRights->__ptr[i].ulType == ACCESS_TYPE_GRANT && lpRights->__ptr[i].ulUserid == m_ulUserID) {
  197. *lpulRights |= lpRights->__ptr[i].ulRights;
  198. bFoundACL = true;
  199. }
  200. // Check for the company we are in and add the permissions
  201. for (gsoap_size_t i = 0; i < lpRights->__size; ++i)
  202. if (lpRights->__ptr[i].ulType == ACCESS_TYPE_GRANT && lpRights->__ptr[i].ulUserid == m_ulCompanyID) {
  203. *lpulRights |= lpRights->__ptr[i].ulRights;
  204. bFoundACL = true;
  205. }
  206. // Also check for groups that we are in, and add those permissions
  207. if(m_lpGroups || GetGroupsForUser(m_ulUserID, &m_lpGroups) == erSuccess)
  208. for (const auto &grp : *m_lpGroups)
  209. for (gsoap_size_t i = 0; i < lpRights->__size; ++i)
  210. if (lpRights->__ptr[i].ulType == ACCESS_TYPE_GRANT &&
  211. lpRights->__ptr[i].ulUserid == grp.ulId) {
  212. *lpulRights |= lpRights->__ptr[i].ulRights;
  213. bFoundACL = true;
  214. }
  215. }
  216. if(lpRights)
  217. {
  218. FreeRightsArray(lpRights);
  219. lpRights = NULL;
  220. }
  221. if (bFoundACL)
  222. // If any of the ACLs at this level were for us, then use these ACLs.
  223. break;
  224. // There were no ACLs or no ACLs for us, go to the parent and try there
  225. er = m_lpSession->GetSessionManager()->GetCacheManager()->GetParent(ulCurObj, &ulCurObj);
  226. if (er != erSuccess)
  227. // No more parents, break (with ulRights = 0)
  228. return erSuccess;
  229. // This can really only happen if you have a broken tree in the database, eg a record which has
  230. // parent == id. To break out of the loop we limit the depth to 64 which is very deep in practice. This means
  231. // that you never have any rights for folders that are more than 64 levels of folders away from their ACL ..
  232. if (++ulDepth > MAX_PARENT_LIMIT) {
  233. ec_log_err("Maximum depth reached for object %d, deepest object: %d", ulObjId, ulCurObj);
  234. return erSuccess;
  235. }
  236. }
  237. return er;
  238. }
  239. /**
  240. * Check permission for a certain object id
  241. *
  242. * This function checks if ANY of the passed permissions are granted on the passed object
  243. * for the currently logged-in user.
  244. *
  245. * @param[in] ulObjId Object ID for which the permission should be checked
  246. * @param[in] ulACLMask Mask of permissions to be checked
  247. * @return Kopano error code
  248. * @retval erSuccess if permission is granted
  249. * @retval KCERR_NO_ACCESS if permission is denied
  250. */
  251. ECRESULT ECSecurity::HaveObjectPermission(unsigned int ulObjId, unsigned int ulACLMask)
  252. {
  253. unsigned int ulRights = 0;
  254. GetObjectPermission(ulObjId, &ulRights);
  255. return (ulRights & ulACLMask) ? erSuccess : KCERR_NO_ACCESS;
  256. }
  257. /**
  258. * Checks if you are the owner of the given object id. This can return
  259. * no access, since other people may have created an object in the
  260. * owner's store (or true if you're that someone).
  261. *
  262. * @param[in] ulObjId hierarchy object to check ownership of
  263. *
  264. * @return Kopano error code
  265. */
  266. ECRESULT ECSecurity::IsOwner(unsigned int ulObjId) const
  267. {
  268. unsigned int ulOwner = 0;
  269. auto er = GetOwner(ulObjId, &ulOwner);
  270. return er != erSuccess || ulOwner != m_ulUserID ? KCERR_NO_ACCESS : erSuccess;
  271. }
  272. /**
  273. * Get the original creator of an object
  274. *
  275. * @param[in] ulObjId hierarchy object to get ownership of
  276. * @param[out] lpulOwnerId owner userid (may not even exist anymore)
  277. *
  278. * @return Kopano error code
  279. */
  280. ECRESULT ECSecurity::GetOwner(unsigned int ulObjId,
  281. unsigned int *lpulOwnerId) const
  282. {
  283. // Default setting
  284. *lpulOwnerId = 0;
  285. auto er = m_lpSession->GetSessionManager()->GetCacheManager()->GetOwner(ulObjId, lpulOwnerId);
  286. return er != erSuccess ? KCERR_NOT_FOUND : er;
  287. }
  288. /**
  289. * Check for a deleted folder as parent of ulId, max folder depth as
  290. * defined (64).
  291. *
  292. * @param[in] ulId object id to start checking from
  293. *
  294. * @return KCERR_NOT_FOUND Error if a parent has the delete flag
  295. */
  296. ECRESULT ECSecurity::CheckDeletedParent(unsigned int ulId) const
  297. {
  298. ECRESULT er = erSuccess;
  299. unsigned int ulParentObjId = 0;
  300. unsigned int ulObjFlags = 0;
  301. unsigned int ulObjType = 0;
  302. unsigned int ulDepth = 0;
  303. ECCacheManager *lpCache = m_lpSession->GetSessionManager()->GetCacheManager();
  304. do {
  305. er = lpCache->GetObject(ulId, &ulParentObjId, NULL, &ulObjFlags, &ulObjType);
  306. if (er != erSuccess)
  307. return er;
  308. if (ulObjFlags & MSGFLAG_DELETED)
  309. return KCERR_NOT_FOUND;
  310. ulId = ulParentObjId;
  311. ++ulDepth;
  312. } while (ulObjType != MAPI_STORE && ulParentObjId != CACHE_NO_PARENT && ulDepth <= MAX_PARENT_LIMIT);
  313. // return error when max depth is reached, so we don't create folders and messages deeper than the limit
  314. if (ulDepth == MAX_PARENT_LIMIT)
  315. er = KCERR_NOT_FOUND;
  316. return er;
  317. }
  318. /**
  319. * For the current user context, check the permissions on a given object
  320. *
  321. * @param[in] ulObjId hierarchy object to check permissions on
  322. * @param[in] ulecRights minimal permission required on object to succeed
  323. *
  324. * @return Kopano error code
  325. * @retval erSuccess requested access on object allowed
  326. * @retval KCERR_NO_ACCESS requested access on object denied
  327. */
  328. ECRESULT ECSecurity::CheckPermission(unsigned int ulObjId, unsigned int ulecRights)
  329. {
  330. ECRESULT er = KCERR_NO_ACCESS;
  331. bool bOwnerFound = false;
  332. unsigned int ulStoreOwnerId = 0;
  333. unsigned int ulStoreType = 0;
  334. unsigned int ulObjectOwnerId = 0;
  335. unsigned int ulACL = 0;
  336. int nCheckType = 0;
  337. unsigned int ulObjType;
  338. unsigned int ulParentId;
  339. unsigned int ulParentType;
  340. if(m_ulUserID == KOPANO_UID_SYSTEM) {
  341. // SYSTEM is always allowed everything
  342. er = erSuccess;
  343. goto exit;
  344. }
  345. // special case: stores and root containers are always allowed to be opened
  346. if (ulecRights == ecSecurityFolderVisible || ulecRights == ecSecurityRead) {
  347. er = m_lpSession->GetSessionManager()->GetCacheManager()->GetObject(ulObjId, &ulParentId, NULL, NULL, &ulObjType);
  348. if (er != erSuccess)
  349. goto exit;
  350. if (ulObjType == MAPI_STORE)
  351. goto exit;
  352. er = m_lpSession->GetSessionManager()->GetCacheManager()->GetObject(ulParentId, NULL, NULL, NULL, &ulParentType);
  353. if (er != erSuccess)
  354. goto exit;
  355. if (ulObjType == MAPI_FOLDER && ulParentType == MAPI_STORE)
  356. goto exit;
  357. }
  358. // Is the current user the owner of the store
  359. if (GetStoreOwnerAndType(ulObjId, &ulStoreOwnerId, &ulStoreType) == erSuccess && ulStoreOwnerId == m_ulUserID) {
  360. if (ulStoreType != ECSTORE_TYPE_ARCHIVE) {
  361. er = erSuccess;
  362. goto exit;
  363. } else if (ulecRights == ecSecurityFolderVisible || ulecRights == ecSecurityRead) {
  364. er = erSuccess;
  365. goto exit;
  366. }
  367. }
  368. // is current user the owner of the object
  369. if (GetOwner(ulObjId, &ulObjectOwnerId) == erSuccess && ulObjectOwnerId == m_ulUserID && m_bOwnerAutoFullAccess)
  370. {
  371. bOwnerFound = true;
  372. if (ulStoreType == ECSTORE_TYPE_ARCHIVE) {
  373. if(ulecRights == ecSecurityFolderVisible || ulecRights == ecSecurityRead) {
  374. er = erSuccess;
  375. goto exit;
  376. }
  377. } else if(ulecRights == ecSecurityFolderVisible || ulecRights == ecSecurityRead || ulecRights == ecSecurityCreate) {
  378. er = erSuccess;
  379. goto exit;
  380. }
  381. }
  382. // Since this is the most complicated check, do this one last
  383. if(IsAdminOverOwnerOfObject(ulObjId) == erSuccess) {
  384. if(!m_bRestrictedAdmin) {
  385. er = erSuccess;
  386. goto exit;
  387. }
  388. // If restricted admin mode is set, admins only receive folder permissions.
  389. if(ulecRights == ecSecurityFolderVisible || ulecRights == ecSecurityFolderAccess || ulecRights == ecSecurityCreateFolder) {
  390. er = erSuccess;
  391. goto exit;
  392. }
  393. }
  394. ulACL = 0;
  395. switch(ulecRights){
  396. case ecSecurityRead: // 1
  397. ulACL |= ecRightsReadAny;
  398. nCheckType = 1;
  399. break;
  400. case ecSecurityCreate: // 2
  401. ulACL |= ecRightsCreate;
  402. nCheckType = 1;
  403. break;
  404. case ecSecurityEdit: // 3
  405. ulACL |= ecRightsEditAny;
  406. if(bOwnerFound)
  407. ulACL |= ecRightsEditOwned;
  408. nCheckType = 1;
  409. break;
  410. case ecSecurityDelete: // 4
  411. ulACL |= ecRightsDeleteAny;
  412. if(bOwnerFound)
  413. ulACL |= ecRightsDeleteOwned;
  414. nCheckType = 1;
  415. break;
  416. case ecSecurityCreateFolder: // 5
  417. ulACL |= ecRightsCreateSubfolder;
  418. nCheckType = 1;
  419. break;
  420. case ecSecurityFolderVisible: // 6
  421. ulACL |= ecRightsFolderVisible;
  422. nCheckType = 1;
  423. break;
  424. case ecSecurityFolderAccess: // 7
  425. if (bOwnerFound == false || ulStoreType == ECSTORE_TYPE_ARCHIVE)
  426. ulACL |= ecRightsFolderAccess;
  427. nCheckType = 1;
  428. break;
  429. case ecSecurityOwner: // 8
  430. nCheckType = 2;
  431. break;
  432. case ecSecurityAdmin: // 9
  433. nCheckType = 3;
  434. break;
  435. default:
  436. nCheckType = 0; // No rights
  437. break;
  438. }
  439. if(nCheckType == 1) { //Get the acl of the object
  440. if(ulACL == 0) {
  441. // No ACLs required, so grant access
  442. er = erSuccess;
  443. goto exit;
  444. }
  445. er = HaveObjectPermission(ulObjId, ulACL);
  446. } else if(nCheckType == 2) {// Is owner ?
  447. if (bOwnerFound)
  448. er = erSuccess;
  449. } else if(nCheckType == 3) { // Is admin?
  450. // We already checked IsAdminOverOwnerOfObject() above, so we'll never get here.
  451. er = erSuccess;
  452. }
  453. exit:
  454. if (er == erSuccess && (ulecRights == ecSecurityCreate || ulecRights == ecSecurityEdit || ulecRights == ecSecurityCreateFolder))
  455. // writing in a deleted parent is not allowed
  456. er = CheckDeletedParent(ulObjId);
  457. if(er != erSuccess)
  458. TRACE_INTERNAL(TRACE_ENTRY,"Security","ECSecurity::CheckPermission","object=%d, rights=%d", ulObjId, ulecRights);
  459. if (m_lpAudit && m_ulUserID != KOPANO_UID_SYSTEM) {
  460. unsigned int ulType = 0;
  461. objectdetails_t sStoreDetails;
  462. std::string strStoreOwner;
  463. std::string strUsername;
  464. m_lpSession->GetSessionManager()->GetCacheManager()->GetObject(ulObjId, NULL, NULL, NULL, &ulType);
  465. if (er == KCERR_NO_ACCESS || ulStoreOwnerId != m_ulUserID) {
  466. GetUsername(&strUsername);
  467. if (ulStoreOwnerId == m_ulUserID)
  468. strStoreOwner = strUsername;
  469. else if (m_lpSession->GetUserManagement()->GetObjectDetails(ulStoreOwnerId, &sStoreDetails) != erSuccess)
  470. // should not really happen on store owners?
  471. strStoreOwner = "<non-existing>";
  472. else
  473. strStoreOwner = sStoreDetails.GetPropString(OB_PROP_S_LOGIN);
  474. }
  475. if (er == KCERR_NO_ACCESS)
  476. m_lpAudit->Log(EC_LOGLEVEL_FATAL, "access denied objectid=%d type=%d ownername='%s' username='%s' rights='%s'",
  477. ulObjId, ulType, strStoreOwner.c_str(), strUsername.c_str(), RightsToString(ulecRights));
  478. else if (ulStoreOwnerId != m_ulUserID)
  479. m_lpAudit->Log(EC_LOGLEVEL_FATAL, "access allowed objectid=%d type=%d ownername='%s' username='%s' rights='%s'",
  480. ulObjId, ulType, strStoreOwner.c_str(), strUsername.c_str(), RightsToString(ulecRights));
  481. else
  482. // you probably do not want to log all what a user does in their own store, do you?
  483. m_lpAudit->Log(EC_LOGLEVEL_INFO, "access allowed objectid=%d type=%d userid=%d", ulObjId, ulType, m_ulUserID);
  484. }
  485. return er;
  486. }
  487. /**
  488. * Get the ACLs on a given object in a protocol struct to send to the client
  489. *
  490. * @param[in] objid hierarchy object to get the ACLs for
  491. * @param[in] ulType rights access type, denied or grant
  492. * @param[out] lpsRightsArray structure with the current rights on objid
  493. *
  494. * @return Kopano error code
  495. */
  496. ECRESULT ECSecurity::GetRights(unsigned int objid, int ulType,
  497. struct rightsArray *lpsRightsArray) const
  498. {
  499. ECRESULT er = KCERR_NO_ACCESS;
  500. DB_RESULT lpDBResult;
  501. DB_ROW lpDBRow = NULL;
  502. ECDatabase *lpDatabase = NULL;
  503. std::string strQuery;
  504. unsigned int ulCount = 0;
  505. unsigned int i=0;
  506. objectid_t sExternId;
  507. er = m_lpSession->GetDatabase(&lpDatabase);
  508. if (er != erSuccess)
  509. return er;
  510. if (lpsRightsArray == nullptr)
  511. return KCERR_INVALID_PARAMETER;
  512. strQuery = "SELECT a.id, a.type, a.rights FROM acl AS a WHERE a.hierarchy_id="+stringify(objid);
  513. if(ulType == ACCESS_TYPE_DENIED)
  514. strQuery += " AND a.type="+stringify(ACCESS_TYPE_DENIED);
  515. else if(ulType == ACCESS_TYPE_GRANT)
  516. strQuery += " AND a.type="+stringify(ACCESS_TYPE_GRANT);
  517. // else ACCESS_TYPE_DENIED and ACCESS_TYPE_GRANT
  518. er = lpDatabase->DoSelect(strQuery, &lpDBResult);
  519. if(er != erSuccess)
  520. return er;
  521. ulCount = lpDatabase->GetNumRows(lpDBResult);
  522. if(ulCount > 0)
  523. {
  524. lpsRightsArray->__ptr = s_alloc<rights>(nullptr, ulCount);
  525. lpsRightsArray->__size = ulCount;
  526. memset(lpsRightsArray->__ptr, 0, sizeof(struct rights) * ulCount);
  527. for (i = 0; i < ulCount; ++i) {
  528. lpDBRow = lpDatabase->FetchRow(lpDBResult);
  529. if(lpDBRow == NULL) {
  530. ec_log_err("ECSecurity::GetRights(): row is null");
  531. return KCERR_DATABASE_ERROR;
  532. }
  533. lpsRightsArray->__ptr[i].ulUserid = atoi(lpDBRow[0]);
  534. lpsRightsArray->__ptr[i].ulType = atoi(lpDBRow[1]);
  535. lpsRightsArray->__ptr[i].ulRights = atoi(lpDBRow[2]);
  536. lpsRightsArray->__ptr[i].ulState = RIGHT_NORMAL;
  537. // do not use internal IDs with the cache
  538. if (lpsRightsArray->__ptr[i].ulUserid == KOPANO_UID_SYSTEM) {
  539. sExternId = objectid_t(ACTIVE_USER);
  540. } else if (lpsRightsArray->__ptr[i].ulUserid == KOPANO_UID_EVERYONE) {
  541. sExternId = objectid_t(DISTLIST_GROUP);
  542. } else {
  543. er = m_lpSession->GetUserManagement()->GetExternalId(lpsRightsArray->__ptr[i].ulUserid, &sExternId);
  544. if (er != erSuccess)
  545. return er;
  546. }
  547. er = ABIDToEntryID(NULL, lpsRightsArray->__ptr[i].ulUserid, sExternId, &lpsRightsArray->__ptr[i].sUserId);
  548. if (er != erSuccess)
  549. return er;
  550. }
  551. }else{
  552. lpsRightsArray->__ptr = NULL;
  553. lpsRightsArray->__size = 0;
  554. }
  555. return erSuccess;
  556. }
  557. /**
  558. * Update the rights on a given object
  559. *
  560. * @param[in] objid hierarchy object id to set rights on
  561. * @param[in] lpsRightsArray protocol struct containing new rights for this object
  562. *
  563. * @return Kopano error code
  564. */
  565. ECRESULT ECSecurity::SetRights(unsigned int objid, struct rightsArray *lpsRightsArray)
  566. {
  567. ECRESULT er;
  568. std::string strQueryNew, strQueryDelete;
  569. unsigned int ulDeniedRights=0;
  570. ECDatabase *lpDatabase = NULL;
  571. unsigned int ulUserId = 0;
  572. objectid_t sExternId;
  573. objectdetails_t sDetails;
  574. size_t ulErrors = 0;
  575. er = m_lpSession->GetDatabase(&lpDatabase);
  576. if (er != erSuccess)
  577. return er;
  578. if (lpsRightsArray == NULL)
  579. return KCERR_INVALID_PARAMETER;
  580. // Invalidate cache for this object
  581. m_lpSession->GetSessionManager()->GetCacheManager()->Update(fnevObjectModified, objid);
  582. for (gsoap_size_t i = 0; i < lpsRightsArray->__size; ++i) {
  583. // FIXME: check for each object if it belongs to the store we're logged into (except for admin)
  584. // Get the correct local id
  585. if (lpsRightsArray->__ptr[i].sUserId.__size > 0 && lpsRightsArray->__ptr[i].sUserId.__ptr != NULL)
  586. {
  587. er = ABEntryIDToID(&lpsRightsArray->__ptr[i].sUserId, &ulUserId, &sExternId, NULL);
  588. if (er != erSuccess)
  589. return er;
  590. // internal user/group doesn't have an externid
  591. if (!sExternId.id.empty())
  592. {
  593. // Get real ulUserId on this server
  594. er = m_lpSession->GetUserManagement()->GetLocalId(sExternId, &ulUserId, NULL);
  595. if (er != erSuccess)
  596. return er;
  597. }
  598. }
  599. else
  600. ulUserId = lpsRightsArray->__ptr[i].ulUserid;
  601. er = m_lpSession->GetUserManagement()->GetObjectDetails(ulUserId, &sDetails);
  602. if (er != erSuccess)
  603. return er;
  604. // You can only set (delete is ok) permissions on active users, and security groups
  605. // Outlook 2007 blocks this client side, other clients get this error.
  606. if ((lpsRightsArray->__ptr[i].ulState & ~(RIGHT_DELETED | RIGHT_AUTOUPDATE_DENIED)) != 0 &&
  607. sDetails.GetClass() != ACTIVE_USER &&
  608. sDetails.GetClass() != DISTLIST_SECURITY &&
  609. sDetails.GetClass() != CONTAINER_COMPANY) {
  610. ++ulErrors;
  611. continue;
  612. }
  613. // Auto create denied rules
  614. ulDeniedRights = lpsRightsArray->__ptr[i].ulRights^ecRightsAllMask;
  615. if(lpsRightsArray->__ptr[i].ulRights & ecRightsEditAny)
  616. ulDeniedRights&=~ecRightsEditOwned;
  617. else if(lpsRightsArray->__ptr[i].ulRights & ecRightsEditOwned){
  618. ulDeniedRights&=~ecRightsEditOwned;
  619. ulDeniedRights|=ecRightsEditAny;
  620. }
  621. if(lpsRightsArray->__ptr[i].ulRights & ecRightsDeleteAny)
  622. ulDeniedRights&=~ecRightsDeleteOwned;
  623. else if(lpsRightsArray->__ptr[i].ulRights & ecRightsDeleteOwned)
  624. {
  625. ulDeniedRights&=~ecRightsDeleteOwned;
  626. ulDeniedRights|=ecRightsDeleteAny;
  627. }
  628. if(lpsRightsArray->__ptr[i].ulState == RIGHT_NORMAL)
  629. {
  630. // Do nothing...
  631. }
  632. else if((lpsRightsArray->__ptr[i].ulState & RIGHT_NEW) || (lpsRightsArray->__ptr[i].ulState & RIGHT_MODIFY))
  633. {
  634. strQueryNew = "REPLACE INTO acl (id, hierarchy_id, type, rights) VALUES ";
  635. strQueryNew+="("+stringify(ulUserId)+","+stringify(objid)+","+stringify(lpsRightsArray->__ptr[i].ulType)+","+stringify(lpsRightsArray->__ptr[i].ulRights)+")";
  636. er = lpDatabase->DoInsert(strQueryNew);
  637. if(er != erSuccess)
  638. return er;
  639. if(lpsRightsArray->__ptr[i].ulState & RIGHT_AUTOUPDATE_DENIED){
  640. strQueryNew = "REPLACE INTO acl (id, hierarchy_id, type, rights) VALUES ";
  641. strQueryNew+=" ("+stringify(ulUserId)+","+stringify(objid)+","+stringify(ACCESS_TYPE_DENIED)+","+stringify(ulDeniedRights)+")";
  642. er = lpDatabase->DoInsert(strQueryNew);
  643. if(er != erSuccess)
  644. return er;
  645. }
  646. }
  647. else if(lpsRightsArray->__ptr[i].ulState & RIGHT_DELETED)
  648. {
  649. strQueryDelete = "DELETE FROM acl WHERE ";
  650. strQueryDelete+="(hierarchy_id="+stringify(objid)+" AND id="+stringify(ulUserId)+" AND type="+stringify(lpsRightsArray->__ptr[i].ulType)+")";
  651. er = lpDatabase->DoDelete(strQueryDelete);
  652. if(er != erSuccess)
  653. return er;
  654. if(lpsRightsArray->__ptr[i].ulState & RIGHT_AUTOUPDATE_DENIED) {
  655. strQueryDelete = "DELETE FROM acl WHERE ";
  656. strQueryDelete+="(hierarchy_id="+stringify(objid)+" AND id="+stringify(ulUserId)+" AND type="+stringify(ACCESS_TYPE_DENIED)+")";
  657. er = lpDatabase->DoDelete(strQueryDelete);
  658. if(er != erSuccess)
  659. return er;
  660. }
  661. }else{
  662. // a Hacker ?
  663. }
  664. }
  665. if (lpsRightsArray->__size >= 0 && ulErrors == static_cast<size_t>(lpsRightsArray->__size))
  666. er = KCERR_INVALID_PARAMETER; // all acl's failed
  667. else if (ulErrors != 0)
  668. er = KCWARN_PARTIAL_COMPLETION; // some acl's failed
  669. else
  670. er = erSuccess;
  671. return er;
  672. }
  673. /**
  674. * Return the company id of the current user context
  675. *
  676. * @param[out] lpulCompanyId company id of user
  677. *
  678. * @return always erSuccess
  679. */
  680. ECRESULT ECSecurity::GetUserCompany(unsigned int *lpulCompanyId) const
  681. {
  682. *lpulCompanyId = m_ulCompanyID;
  683. return erSuccess;
  684. }
  685. /**
  686. * Get a list of company ids that may be viewed by the current user
  687. *
  688. * @param[in] ulFlags Usermanagemnt flags
  689. * @param[out] lppObjects New allocated list of company details
  690. *
  691. * @return Kopano error code
  692. */
  693. ECRESULT ECSecurity::GetViewableCompanyIds(unsigned int ulFlags, list<localobjectdetails_t> **lppObjects)
  694. {
  695. ECRESULT er;
  696. /*
  697. * We have the viewable companies stored in our cache,
  698. * if it is present use that, otherwise just create a
  699. * new one.
  700. * NOTE: We always request GetViewableCompanies with 0 as ulFlags,
  701. * this because we are caching the list here and some callers might
  702. * want all details while others will only want the IDs.
  703. */
  704. if (!m_lpViewCompanies) {
  705. er = GetViewableCompanies(0, &m_lpViewCompanies);
  706. if (er != erSuccess)
  707. return er;
  708. }
  709. /*
  710. * Because of the difference in flags it is possible we have
  711. * too many entries in the list. We need to filter those out now.
  712. */
  713. *lppObjects = new list<localobjectdetails_t>();
  714. for (const auto &i : *m_lpViewCompanies) {
  715. if (m_ulUserID != 0 && (ulFlags & USERMANAGEMENT_ADDRESSBOOK) &&
  716. i.GetPropBool(OB_PROP_B_AB_HIDDEN))
  717. continue;
  718. if (ulFlags & USERMANAGEMENT_IDS_ONLY)
  719. (*lppObjects)->push_back(localobjectdetails_t(i.ulId, i.GetClass()));
  720. else
  721. (*lppObjects)->push_back(localobjectdetails_t(i.ulId, i));
  722. }
  723. return erSuccess;
  724. }
  725. /**
  726. * Check if the given user id is readable by the current user
  727. *
  728. * @param[in] ulUserObjectId internal user id
  729. *
  730. * @return Kopano error code
  731. * @retval erSuccess viewable
  732. * @retval KCERR_NOT_FOUND not viewable
  733. */
  734. ECRESULT ECSecurity::IsUserObjectVisible(unsigned int ulUserObjectId)
  735. {
  736. ECRESULT er;
  737. objectid_t sExternId;
  738. unsigned int ulCompanyId;
  739. if (ulUserObjectId == 0 ||
  740. ulUserObjectId == m_ulUserID ||
  741. ulUserObjectId == m_ulCompanyID ||
  742. ulUserObjectId == KOPANO_UID_SYSTEM ||
  743. ulUserObjectId == KOPANO_UID_EVERYONE ||
  744. m_details.GetPropInt(OB_PROP_I_ADMINLEVEL) == ADMIN_LEVEL_SYSADMIN ||
  745. !m_lpSession->GetSessionManager()->IsHostedSupported())
  746. return erSuccess;
  747. er = m_lpSession->GetUserManagement()->GetExternalId(ulUserObjectId, &sExternId, &ulCompanyId);
  748. if (er != erSuccess)
  749. return er;
  750. // still needed?
  751. if (sExternId.objclass == CONTAINER_COMPANY)
  752. ulCompanyId = ulUserObjectId;
  753. if (!m_lpViewCompanies) {
  754. er = GetViewableCompanies(0, &m_lpViewCompanies);
  755. if (er != erSuccess)
  756. return er;
  757. }
  758. for (const auto &company : *m_lpViewCompanies)
  759. if (company.ulId == ulCompanyId)
  760. return erSuccess;
  761. /* Item was not found */
  762. return KCERR_NOT_FOUND;
  763. }
  764. /**
  765. * Internal helper function to get a list of viewable company details
  766. *
  767. * @todo won't this bug when we cache only the IDs in a first call,
  768. * and then when we need the full details, the m_lpViewCompanies will
  769. * only contain the IDs?
  770. *
  771. * @param[in] ulFlags usermanagement flags
  772. * @param[in] lppObjects new allocated list with company details
  773. *
  774. * @return
  775. */
  776. ECRESULT ECSecurity::GetViewableCompanies(unsigned int ulFlags,
  777. std::list<localobjectdetails_t> **lppObjects) const
  778. {
  779. ECRESULT er = erSuccess;
  780. std::unique_ptr<std::list<localobjectdetails_t> > lpObjects;
  781. objectdetails_t details;
  782. if (m_details.GetPropInt(OB_PROP_I_ADMINLEVEL) == ADMIN_LEVEL_SYSADMIN)
  783. er = m_lpSession->GetUserManagement()->GetCompanyObjectListAndSync(CONTAINER_COMPANY, 0, &unique_tie(lpObjects), ulFlags);
  784. else
  785. er = m_lpSession->GetUserManagement()->GetParentObjectsOfObjectAndSync(OBJECTRELATION_COMPANY_VIEW,
  786. m_ulCompanyID, &unique_tie(lpObjects), ulFlags);
  787. if (er != erSuccess)
  788. /* Whatever the error might be, it only indicates we
  789. * are not allowed to view _other_ companyspaces.
  790. * It doesn't restrict us from viewing our own... */
  791. lpObjects.reset(new std::list<localobjectdetails_t>);
  792. /* We are going to insert the requested companyID to the list as well,
  793. * this way we guarentee that _all_ viewable companies are in the list.
  794. * And we can use sort() and unique() to prevent duplicate entries while
  795. * making sure the we can savely handle things when the current company
  796. * is either added or not present in the RemoteViewableCompanies. */
  797. if (m_ulCompanyID != 0) {
  798. if (!(ulFlags & USERMANAGEMENT_IDS_ONLY)) {
  799. er = m_lpSession->GetUserManagement()->GetObjectDetails(m_ulCompanyID, &details);
  800. if (er != erSuccess)
  801. return er;
  802. } else {
  803. details = objectdetails_t(CONTAINER_COMPANY);
  804. }
  805. lpObjects->push_back(localobjectdetails_t(m_ulCompanyID, details));
  806. }
  807. lpObjects->sort();
  808. lpObjects->unique();
  809. *lppObjects = lpObjects.release();
  810. return erSuccess;
  811. }
  812. /**
  813. * Get a list of company details which the current user is admin over
  814. *
  815. * @param[in] ulFlags usermanagement flags
  816. * @param[out] lppObjects company list
  817. *
  818. * @return Kopano error code
  819. */
  820. ECRESULT ECSecurity::GetAdminCompanies(unsigned int ulFlags, list<localobjectdetails_t> **lppObjects)
  821. {
  822. ECRESULT er = erSuccess;
  823. std::unique_ptr<std::list<localobjectdetails_t> > lpObjects;
  824. if (m_details.GetPropInt(OB_PROP_I_ADMINLEVEL) == ADMIN_LEVEL_SYSADMIN)
  825. er = m_lpSession->GetUserManagement()->GetCompanyObjectListAndSync(CONTAINER_COMPANY,
  826. 0, &unique_tie(lpObjects), ulFlags);
  827. else
  828. er = m_lpSession->GetUserManagement()->GetParentObjectsOfObjectAndSync(OBJECTRELATION_COMPANY_ADMIN,
  829. m_ulUserID, &unique_tie(lpObjects), ulFlags);
  830. if (er != erSuccess)
  831. return er;
  832. /* A user is only admin over a company when he has privileges to view the company */
  833. for (auto iterObjects = lpObjects->begin(); iterObjects != lpObjects->cend(); ) {
  834. if (IsUserObjectVisible(iterObjects->ulId) != erSuccess) {
  835. auto iterObjectsRemove = iterObjects;
  836. ++iterObjects;
  837. lpObjects->erase(iterObjectsRemove);
  838. } else {
  839. ++iterObjects;
  840. }
  841. }
  842. *lppObjects = lpObjects.release();
  843. return erSuccess;
  844. }
  845. /**
  846. * Return the current logged in UserID _OR_ if you're an administrator
  847. * over user that is set as owner of the given object, return the
  848. * owner of the object.
  849. *
  850. * @param[in] ulObjId object to get ownership of if admin, defaults to 0 to get the current UserID
  851. *
  852. * @return user id of object
  853. */
  854. unsigned int ECSecurity::GetUserId(unsigned int ulObjId)
  855. {
  856. ECRESULT er = erSuccess;
  857. unsigned int ulUserId = this->m_ulUserID;
  858. if (ulObjId != 0 && IsAdminOverOwnerOfObject(ulObjId) == erSuccess) {
  859. er = GetOwner(ulObjId, &ulUserId);
  860. if (er != erSuccess)
  861. ulUserId = this->m_ulUserID;
  862. }
  863. return ulUserId;
  864. }
  865. /**
  866. * Check if the given object id is in your own store
  867. *
  868. * @param[in] ulObjId hierarchy object id of object to check
  869. *
  870. * @return Kopano error code
  871. * @retval erSuccess object is in current user's store
  872. */
  873. ECRESULT ECSecurity::IsStoreOwner(unsigned int ulObjId) const
  874. {
  875. ECRESULT er;
  876. unsigned int ulStoreId = 0;
  877. er = m_lpSession->GetSessionManager()->GetCacheManager()->GetStore(ulObjId, &ulStoreId, NULL);
  878. if(er != erSuccess)
  879. return er;
  880. er = IsOwner(ulStoreId);
  881. if(er != erSuccess)
  882. return er;
  883. return erSuccess;
  884. }
  885. /**
  886. * Return the current user's admin level
  887. *
  888. * @return admin level of user
  889. */
  890. int ECSecurity::GetAdminLevel(void) const
  891. {
  892. return m_details.GetPropInt(OB_PROP_I_ADMINLEVEL);
  893. }
  894. /**
  895. * Get the owner of the store in which the given objectid resides in
  896. *
  897. * @param[in] ulObjId hierarchy object id to get store owner of
  898. * @param[in] lpulOwnerId user id of store in which ulObjId resides
  899. *
  900. * @return Kopano error code
  901. */
  902. ECRESULT ECSecurity::GetStoreOwner(unsigned int ulObjId,
  903. unsigned int *lpulOwnerId) const
  904. {
  905. return GetStoreOwnerAndType(ulObjId, lpulOwnerId, NULL);
  906. }
  907. /**
  908. * Get the owner and type of the store in which the given objectid resides in
  909. *
  910. * @param[in] ulObjId hierarchy object id to get store owner of
  911. * @param[out] lpulOwnerId user id of store in which ulObjId resides
  912. * @param[out] lpulStoreType type of store in which ulObjId resides
  913. *
  914. * @return Kopano error code
  915. */
  916. ECRESULT ECSecurity::GetStoreOwnerAndType(unsigned int ulObjId,
  917. unsigned int *lpulOwnerId, unsigned int *lpulStoreType) const
  918. {
  919. ECRESULT er;
  920. unsigned int ulStoreId = 0;
  921. if (lpulOwnerId || lpulStoreType) {
  922. er = m_lpSession->GetSessionManager()->GetCacheManager()->GetStoreAndType(ulObjId, &ulStoreId, NULL, lpulStoreType);
  923. if (er != erSuccess)
  924. return er;
  925. }
  926. if (lpulOwnerId) {
  927. er = GetOwner(ulStoreId, lpulOwnerId);
  928. if (er != erSuccess)
  929. return er;
  930. }
  931. return erSuccess;
  932. }
  933. /**
  934. * Check if the current user is admin over a given user id (user/group/company/...)
  935. *
  936. * @todo this function should be renamed to IsAdminOfUserObject(id) or something like that
  937. *
  938. * @param[in] ulUserObjectId id of user
  939. *
  940. * @return Kopano error code
  941. * @retval erSuccess Yes, admin
  942. * @retval KCERR_NO_ACCESS No, not admin
  943. */
  944. ECRESULT ECSecurity::IsAdminOverUserObject(unsigned int ulUserObjectId)
  945. {
  946. ECRESULT er = KCERR_NO_ACCESS;
  947. unsigned int ulCompanyId;
  948. objectdetails_t objectdetails;
  949. objectid_t sExternId;
  950. /* Hosted disabled: When admin level is not zero, then the user
  951. * is the administrator, otherwise the user isn't and we don't need
  952. * to look any further. */
  953. if (!m_lpSession->GetSessionManager()->IsHostedSupported()) {
  954. if (m_details.GetPropInt(OB_PROP_I_ADMINLEVEL) != 0)
  955. er = erSuccess;
  956. return er;
  957. }
  958. /* If hosted is enabled, system administrators are administrator over all users. */
  959. if (m_details.GetPropInt(OB_PROP_I_ADMINLEVEL) == ADMIN_LEVEL_SYSADMIN)
  960. return erSuccess;
  961. /*
  962. * Determine to which company the user belongs
  963. */
  964. er = m_lpSession->GetUserManagement()->GetExternalId(ulUserObjectId, &sExternId, &ulCompanyId);
  965. if (er != erSuccess)
  966. return er;
  967. // still needed?
  968. if (sExternId.objclass == CONTAINER_COMPANY)
  969. ulCompanyId = ulUserObjectId;
  970. /*
  971. * If ulCompanyId is the company where the logged in user belongs to,
  972. * then the only thing we need to check is the "isadmin" boolean.
  973. */
  974. if (m_ulCompanyID == ulCompanyId) {
  975. if (m_details.GetPropInt(OB_PROP_I_ADMINLEVEL) != 0)
  976. er = erSuccess;
  977. else
  978. er = KCERR_NO_ACCESS;
  979. return er;
  980. }
  981. if (!m_lpAdminCompanies) {
  982. er = GetAdminCompanies(USERMANAGEMENT_IDS_ONLY, &m_lpAdminCompanies);
  983. if (er != erSuccess)
  984. return er;
  985. }
  986. for (const auto &obj : *m_lpAdminCompanies)
  987. if (obj.ulId == ulCompanyId)
  988. return erSuccess;
  989. /* Item was not found, so no access */
  990. return KCERR_NO_ACCESS;
  991. }
  992. /**
  993. * Check if we're admin over the user who owns the given object id
  994. *
  995. * @param ulObjectId hierarchy object id
  996. *
  997. * @return Kopano error code
  998. * @retval erSuccess Yes
  999. * @retval KCERR_NO_ACCESS No
  1000. */
  1001. ECRESULT ECSecurity::IsAdminOverOwnerOfObject(unsigned int ulObjectId)
  1002. {
  1003. ECRESULT er;
  1004. unsigned int ulOwner;
  1005. /*
  1006. * Request the ownership if the object.
  1007. */
  1008. er = GetStoreOwner(ulObjectId, &ulOwner);
  1009. if (er != erSuccess)
  1010. return er;
  1011. return IsAdminOverUserObject(ulOwner);
  1012. }
  1013. /**
  1014. * Get the size of the store in which the given ulObjId resides in
  1015. *
  1016. * @param[in] ulObjId hierarchy object id
  1017. * @param[out] lpllStoreSize size of store
  1018. *
  1019. * @return Kopano error code
  1020. */
  1021. ECRESULT ECSecurity::GetStoreSize(unsigned int ulObjId,
  1022. long long *lpllStoreSize) const
  1023. {
  1024. ECRESULT er = erSuccess;
  1025. ECDatabase *lpDatabase = NULL;
  1026. DB_RESULT lpDBResult;
  1027. DB_ROW lpDBRow = NULL;
  1028. std::string strQuery;
  1029. unsigned int ulStore;
  1030. er = m_lpSession->GetDatabase(&lpDatabase);
  1031. if (er != erSuccess)
  1032. return er;
  1033. er = m_lpSession->GetSessionManager()->GetCacheManager()->GetStore(ulObjId, &ulStore, NULL);
  1034. if(er != erSuccess)
  1035. return er;
  1036. strQuery = "SELECT val_longint FROM properties WHERE tag="+stringify(PROP_ID(PR_MESSAGE_SIZE_EXTENDED))+" AND type="+stringify(PROP_TYPE(PR_MESSAGE_SIZE_EXTENDED)) + " AND hierarchyid="+stringify(ulStore);
  1037. er = lpDatabase->DoSelect(strQuery, &lpDBResult);
  1038. if(er != erSuccess)
  1039. return er;
  1040. if(lpDatabase->GetNumRows(lpDBResult) != 1) {
  1041. // This mostly happens when we're creating a new store, so return 0 sized store
  1042. *lpllStoreSize = 0;
  1043. return erSuccess;
  1044. }
  1045. lpDBRow = lpDatabase->FetchRow(lpDBResult);
  1046. if(lpDBRow == NULL || lpDBRow[0] == NULL) {
  1047. ec_log_err("ECSecurity::GetStoreSize(): row is null");
  1048. return KCERR_DATABASE_ERROR;
  1049. }
  1050. *lpllStoreSize = atoll(lpDBRow[0]);
  1051. return erSuccess;
  1052. }
  1053. /**
  1054. * Get the store size of a given user
  1055. *
  1056. * @param[in] ulUserId internal user id
  1057. * @param[out] lpllUserSize store size of user
  1058. *
  1059. * @return Kopano error code
  1060. */
  1061. ECRESULT ECSecurity::GetUserSize(unsigned int ulUserId,
  1062. long long *lpllUserSize) const
  1063. {
  1064. ECRESULT er = erSuccess;
  1065. ECDatabase *lpDatabase = NULL;
  1066. DB_RESULT lpDBResult;
  1067. DB_ROW lpDBRow = NULL;
  1068. std::string strQuery;
  1069. long long llUserSize = 0;
  1070. er = m_lpSession->GetDatabase(&lpDatabase);
  1071. if (er != erSuccess)
  1072. return er;
  1073. strQuery =
  1074. "SELECT p.val_longint "
  1075. "FROM properties AS p "
  1076. "JOIN stores AS s "
  1077. "ON s.hierarchy_id = p.hierarchyid "
  1078. "WHERE "
  1079. "s.user_id = " + stringify(ulUserId) + " " +
  1080. "AND p.tag = " + stringify(PROP_ID(PR_MESSAGE_SIZE_EXTENDED)) + " "
  1081. "AND p.type = " + stringify(PROP_TYPE(PR_MESSAGE_SIZE_EXTENDED));
  1082. er = lpDatabase->DoSelect(strQuery, &lpDBResult);
  1083. if(er != erSuccess)
  1084. return er;
  1085. if (lpDatabase->GetNumRows(lpDBResult) != 1) {
  1086. *lpllUserSize = 0;
  1087. return erSuccess;
  1088. }
  1089. lpDBRow = lpDatabase->FetchRow(lpDBResult);
  1090. if (lpDBRow == NULL) {
  1091. ec_log_err("ECSecurity::GetUserSize(): row is null");
  1092. return KCERR_DATABASE_ERROR;
  1093. }
  1094. if (lpDBRow[0] == NULL)
  1095. llUserSize = 0;
  1096. else
  1097. llUserSize = atoll(lpDBRow[0]);
  1098. *lpllUserSize = llUserSize;
  1099. return erSuccess;
  1100. }
  1101. /**
  1102. * Gets the quota status value (ok, warn, soft, hard) for a given
  1103. * store and store size
  1104. *
  1105. * @note if you already know the owner of the store, it's better to
  1106. * call ECSecurity::CheckUserQuota
  1107. *
  1108. * @param[in] ulStoreId store to check quota for
  1109. * @param[in] llStoreSize current store size of the store
  1110. * @param[out] lpQuotaStatus quota status value
  1111. *
  1112. * @return Kopano error code
  1113. */
  1114. ECRESULT ECSecurity::CheckQuota(unsigned int ulStoreId, long long llStoreSize,
  1115. eQuotaStatus *lpQuotaStatus) const
  1116. {
  1117. ECRESULT er;
  1118. unsigned int ulOwnerId = 0;
  1119. unsigned int ulStoreType = 0;
  1120. er = m_lpSession->GetSessionManager()->GetCacheManager()->GetStoreAndType(ulStoreId, NULL, NULL, &ulStoreType);
  1121. if (er != erSuccess)
  1122. return er;
  1123. if(ulStoreType != ECSTORE_TYPE_PRIVATE) {
  1124. *lpQuotaStatus = QUOTA_OK;
  1125. return er; // all is good, no quota on non-private stores.
  1126. }
  1127. // Get the store owner
  1128. er = GetStoreOwner(ulStoreId, &ulOwnerId);
  1129. if(er != erSuccess)
  1130. return er;
  1131. return CheckUserQuota(ulOwnerId, llStoreSize, lpQuotaStatus);
  1132. }
  1133. /**
  1134. * Gets the quota status value (ok, warn, soft, hard) for a given
  1135. * store and store size
  1136. *
  1137. * @param[in] ulUserId user to check quota for
  1138. * @param[in] llStoreSize current store size of the store
  1139. * @param[out] lpQuotaStatus quota status
  1140. *
  1141. * @return Kopano error code
  1142. */
  1143. ECRESULT ECSecurity::CheckUserQuota(unsigned int ulUserId,
  1144. long long llStoreSize, eQuotaStatus *lpQuotaStatus) const
  1145. {
  1146. ECRESULT er;
  1147. quotadetails_t quotadetails;
  1148. if (ulUserId == KOPANO_UID_EVERYONE) {
  1149. /* Publicly owned stores are never over quota.
  1150. * But do publicly owned stores actually exist since the owner is either a user or company */
  1151. *lpQuotaStatus = QUOTA_OK;
  1152. return erSuccess;
  1153. }
  1154. er = GetUserQuota(ulUserId, false, &quotadetails);
  1155. if (er != erSuccess)
  1156. return er;
  1157. // check the options
  1158. if(quotadetails.llHardSize > 0 && llStoreSize >= quotadetails.llHardSize)
  1159. *lpQuotaStatus = QUOTA_HARDLIMIT;
  1160. else if(quotadetails.llSoftSize > 0 && llStoreSize >= quotadetails.llSoftSize)
  1161. *lpQuotaStatus = QUOTA_SOFTLIMIT;
  1162. else if(quotadetails.llWarnSize > 0 && llStoreSize >= quotadetails.llWarnSize)
  1163. *lpQuotaStatus = QUOTA_WARN;
  1164. else
  1165. *lpQuotaStatus = QUOTA_OK;
  1166. return erSuccess;
  1167. }
  1168. /**
  1169. * Get the quota details of a user
  1170. *
  1171. * @param[in] ulUserId internal user id
  1172. * @param[out] lpDetails quota details
  1173. *
  1174. * @return Kopano error code
  1175. */
  1176. ECRESULT ECSecurity::GetUserQuota(unsigned int ulUserId, bool bGetUserDefault,
  1177. quotadetails_t *lpDetails) const
  1178. {
  1179. ECRESULT er = erSuccess;
  1180. const char *lpszWarnQuota = NULL;
  1181. const char *lpszSoftQuota = NULL;
  1182. const char *lpszHardQuota = NULL;
  1183. quotadetails_t quotadetails;
  1184. objectid_t sExternId;
  1185. unsigned int ulCompanyId;
  1186. if (!lpDetails) {
  1187. er = KCERR_INVALID_PARAMETER;
  1188. goto exit;
  1189. }
  1190. er = m_lpSession->GetUserManagement()->GetExternalId(ulUserId, &sExternId, &ulCompanyId);
  1191. if (er != erSuccess)
  1192. goto exit;
  1193. assert(!bGetUserDefault || sExternId.objclass == CONTAINER_COMPANY);
  1194. /* Not all objectclasses support quota */
  1195. if ((sExternId.objclass == NONACTIVE_CONTACT) ||
  1196. (OBJECTCLASS_TYPE(sExternId.objclass) == OBJECTTYPE_DISTLIST) ||
  1197. (sExternId.objclass == CONTAINER_ADDRESSLIST))
  1198. goto exit;
  1199. er = m_lpSession->GetUserManagement()->GetQuotaDetailsAndSync(ulUserId, &quotadetails, bGetUserDefault);
  1200. if (er != erSuccess)
  1201. goto exit;
  1202. /* When the default quota boolean is set, we need to look at the next quota level */
  1203. if (!quotadetails.bUseDefaultQuota)
  1204. goto exit;
  1205. /* Request default quota values from company level if enabled */
  1206. if ((OBJECTCLASS_TYPE(sExternId.objclass) == OBJECTTYPE_MAILUSER) && ulCompanyId) {
  1207. er = m_lpSession->GetUserManagement()->GetQuotaDetailsAndSync(ulCompanyId, &quotadetails, true);
  1208. if (er == erSuccess && !quotadetails.bUseDefaultQuota)
  1209. goto exit; /* On failure, or when we should use the default, we're done */
  1210. er = erSuccess;
  1211. }
  1212. /* No information from company, the last level we can check is the configuration file */
  1213. if (OBJECTCLASS_TYPE(sExternId.objclass) == OBJECTTYPE_MAILUSER) {
  1214. lpszWarnQuota = m_lpSession->GetSessionManager()->GetConfig()->GetSetting("quota_warn");
  1215. lpszSoftQuota = m_lpSession->GetSessionManager()->GetConfig()->GetSetting("quota_soft");
  1216. lpszHardQuota = m_lpSession->GetSessionManager()->GetConfig()->GetSetting("quota_hard");
  1217. } else if (sExternId.objclass == CONTAINER_COMPANY) {
  1218. lpszWarnQuota = m_lpSession->GetSessionManager()->GetConfig()->GetSetting("companyquota_warn");
  1219. }
  1220. quotadetails.bUseDefaultQuota = true;
  1221. quotadetails.bIsUserDefaultQuota = false;
  1222. if (lpszWarnQuota)
  1223. quotadetails.llWarnSize = atoll(lpszWarnQuota) * 1024 * 1024;
  1224. if (lpszSoftQuota)
  1225. quotadetails.llSoftSize = atoll(lpszSoftQuota) * 1024 * 1024;
  1226. if (lpszHardQuota)
  1227. quotadetails.llHardSize = atoll(lpszHardQuota) * 1024 * 1024;
  1228. exit:
  1229. if (er == erSuccess)
  1230. *lpDetails = std::move(quotadetails);
  1231. return er;
  1232. }
  1233. /**
  1234. * Get the username of the current user context
  1235. *
  1236. * @param[out] lpstrUsername login name of the user
  1237. *
  1238. * @return always erSuccess
  1239. */
  1240. ECRESULT ECSecurity::GetUsername(std::string *lpstrUsername) const
  1241. {
  1242. if (m_ulUserID)
  1243. *lpstrUsername = m_details.GetPropString(OB_PROP_S_LOGIN);
  1244. else
  1245. *lpstrUsername = KOPANO_SYSTEM_USER;
  1246. return erSuccess;
  1247. }
  1248. /**
  1249. * Get the username of the user impersonating the current user
  1250. *
  1251. * @param[out] lpstrImpersonator login name of the impersonator
  1252. *
  1253. * @return always erSuccess
  1254. */
  1255. ECRESULT ECSecurity::GetImpersonator(std::string *lpstrImpersonator) const
  1256. {
  1257. ECRESULT er = erSuccess;
  1258. if (m_ulImpersonatorID == EC_NO_IMPERSONATOR)
  1259. er = KCERR_NOT_FOUND;
  1260. else if (m_ulImpersonatorID)
  1261. *lpstrImpersonator = m_impersonatorDetails.GetPropString(OB_PROP_S_LOGIN);
  1262. else
  1263. *lpstrImpersonator = KOPANO_SYSTEM_USER;
  1264. return er;
  1265. }
  1266. /**
  1267. * Get memory size of this object
  1268. *
  1269. * @return Object size in bytes
  1270. */
  1271. size_t ECSecurity::GetObjectSize(void) const
  1272. {
  1273. size_t ulSize = sizeof(*this);
  1274. ulSize += m_details.GetObjectSize();
  1275. ulSize += m_impersonatorDetails.GetObjectSize();
  1276. if (m_lpGroups) {
  1277. size_t ulItems = 0;
  1278. for (const auto &i : *m_lpGroups) {
  1279. ++ulItems;
  1280. ulSize += i.GetObjectSize();
  1281. }
  1282. ulSize += MEMORY_USAGE_LIST(ulItems, list<localobjectdetails_t>);
  1283. }
  1284. if (m_lpViewCompanies)
  1285. {
  1286. size_t ulItems = 0;
  1287. for (const auto &i : *m_lpViewCompanies) {
  1288. ++ulItems;
  1289. ulSize += i.GetObjectSize();
  1290. }
  1291. ulSize += MEMORY_USAGE_LIST(ulItems, list<localobjectdetails_t>);
  1292. }
  1293. if (m_lpAdminCompanies)
  1294. {
  1295. size_t ulItems = 0;
  1296. for (const auto &i : *m_lpAdminCompanies) {
  1297. ++ulItems;
  1298. ulSize += i.GetObjectSize();
  1299. }
  1300. ulSize += MEMORY_USAGE_LIST(ulItems, list<localobjectdetails_t>);
  1301. }
  1302. return ulSize;
  1303. }
  1304. } /* namespace */