123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470 |
- /*
- * Copyright 2005 - 2016 Zarafa and its licensors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <kopano/platform.h>
- #include <memory>
- #include <utility>
- #include <kopano/tie.hpp>
- #include "ECDatabaseUtils.h"
- #include "ECDatabase.h"
- #include "ECSessionManager.h"
- #include "ECSession.h"
- #include <kopano/ECDefs.h>
- #include "ECSecurity.h"
- #include <kopano/stringutil.h>
- #include <kopano/Trace.h>
- #include "kcore.hpp"
- #include <mapidefs.h>
- #include <mapicode.h>
- #include <mapitags.h>
- #include <kopano/mapiext.h>
- #include <openssl/ssl.h>
- #include <openssl/evp.h>
- #include <openssl/x509.h>
- #include <openssl/bio.h>
- #include <algorithm>
- #include "ECUserManagement.h"
- #include "SOAPUtils.h"
- #include "SOAPDebug.h"
- #include <edkmdb.h>
- #include "ECDBDef.h"
- #include "cmdutil.hpp"
- using namespace KCHL;
- namespace KC {
- #define MAX_PARENT_LIMIT 64
- /**
- * @param[in] lpSession user session
- * @param[in] lpConfig config object
- * @param[in] lpLogger log object for normal logging
- * @param[in] lpAudit optional log object for auditing
- */
- ECSecurity::ECSecurity(ECSession *lpSession, ECConfig *lpConfig,
- ECLogger *lpAudit) :
- m_lpSession(lpSession), m_lpAudit(lpAudit), m_lpConfig(lpConfig)
- {
- if (m_lpAudit != NULL)
- m_lpAudit->AddRef();
- m_bRestrictedAdmin = parseBool(lpConfig->GetSetting("restrict_admin_permissions"));
- m_bOwnerAutoFullAccess = parseBool(lpConfig->GetSetting("owner_auto_full_access"));
- }
- ECSecurity::~ECSecurity()
- {
- delete m_lpGroups;
- delete m_lpViewCompanies;
- delete m_lpAdminCompanies;
- if (m_lpAudit != NULL)
- m_lpAudit->Release();
- }
- /**
- * Called once for each login after the object was constructed. Since
- * this function can return errors, this is not done in the
- * constructor.
- *
- * @param[in] ulUserId current logged in user
- *
- * @return Kopano error code
- */
- ECRESULT ECSecurity::SetUserContext(unsigned int ulUserId, unsigned int ulImpersonatorID)
- {
- ECRESULT er;
- ECUserManagement *lpUserManagement = m_lpSession->GetUserManagement();
- m_ulUserID = ulUserId;
- m_ulImpersonatorID = ulImpersonatorID;
- er = lpUserManagement->GetObjectDetails(m_ulUserID, &m_details);
- if(er != erSuccess)
- return er;
- // Get the company we're assigned to
- if (m_lpSession->GetSessionManager()->IsHostedSupported())
- m_ulCompanyID = m_details.GetPropInt(OB_PROP_I_COMPANYID);
- else
- m_ulCompanyID = 0;
- if (m_ulImpersonatorID != EC_NO_IMPERSONATOR) {
- unsigned int ulAdminLevel = 0;
- er = lpUserManagement->GetObjectDetails(m_ulImpersonatorID, &m_impersonatorDetails);
- if (er != erSuccess)
- return er;
- ulAdminLevel = m_impersonatorDetails.GetPropInt(OB_PROP_I_ADMINLEVEL);
- if (ulAdminLevel == 0) {
- return KCERR_NO_ACCESS;
- } else if (m_lpSession->GetSessionManager()->IsHostedSupported() == true && ulAdminLevel < ADMIN_LEVEL_SYSADMIN) {
- unsigned int ulCompanyID = m_impersonatorDetails.GetPropInt(OB_PROP_I_COMPANYID);
- if (ulCompanyID != m_ulCompanyID)
- return KCERR_NO_ACCESS;
- }
- }
- /*
- * Don't initialize m_lpGroups, m_lpViewCompanies and m_lpAdminCompanies
- * We should wait with that until the first time we actually use it,
- * this will save quite a lot of LDAP queries since often we don't
- * even need the list at all.
- */
- return erSuccess;
- }
- // helper class to remember groups we've seen to break endless loops
- class cUniqueGroup {
- public:
- bool operator()(const localobjectdetails_t &obj) const
- {
- return m_seen.find(obj) != m_seen.end();
- }
- std::set<localobjectdetails_t> m_seen;
- };
- /**
- * This function returns a list of security groups the user is a
- * member of. If a group contains a group, it will be appended to the
- * list. The list will be a unique list of groups in the end.
- *
- * @param[in] ulUserId A user or group to query the grouplist for.
- * @param[out] lppGroups The unique list of group ids
- *
- * @return Kopano error code
- */
- ECRESULT ECSecurity::GetGroupsForUser(unsigned int ulUserId, std::list<localobjectdetails_t> **lppGroups)
- {
- ECRESULT er;
- std::list<localobjectdetails_t> *lpGroups = NULL;
- cUniqueGroup cSeenGroups;
- /* Gets the current user's membership information.
- * This means you will be in the same groups until you login again */
- er = m_lpSession->GetUserManagement()->GetParentObjectsOfObjectAndSync(OBJECTRELATION_GROUP_MEMBER,
- ulUserId, &lpGroups, USERMANAGEMENT_IDS_ONLY);
- if (er != erSuccess)
- return er;
- /* A user is only member of a group when he can also view the group */
- for (auto iterGroups = lpGroups->begin(); iterGroups != lpGroups->cend(); ) {
- /*
- * Since this function is only used by ECSecurity, we can only
- * test for security groups here. However, normal groups were
- * used to be security enabled, so only check for dynamic
- * groups here to exclude.
- */
- if (IsUserObjectVisible(iterGroups->ulId) != erSuccess || iterGroups->GetClass() == DISTLIST_DYNAMIC) {
- lpGroups->erase(iterGroups++);
- continue;
- }
- cSeenGroups.m_seen.insert(*iterGroups);
- std::list<localobjectdetails_t> *lpGroupInGroups = NULL;
- er = m_lpSession->GetUserManagement()->GetParentObjectsOfObjectAndSync(OBJECTRELATION_GROUP_MEMBER,
- iterGroups->ulId, &lpGroupInGroups, USERMANAGEMENT_IDS_ONLY);
- if (er == erSuccess) {
- // Adds all groups from lpGroupInGroups to the main lpGroups list, except when already in cSeenGroups
- remove_copy_if(lpGroupInGroups->begin(), lpGroupInGroups->end(), back_inserter(*lpGroups), cSeenGroups);
- delete lpGroupInGroups;
- }
- // Ignore error (eg. cannot use that function on group Everyone)
- ++iterGroups;
- }
- *lppGroups = lpGroups;
- return erSuccess;
- }
- /**
- * Return the bitmask of permissions for an object
- *
- * @param[in] ulObjId hierarchy object to get permission mask for
- * @param[out] lpulRights permission mask
- *
- * @return always erSuccess
- */
- ECRESULT ECSecurity::GetObjectPermission(unsigned int ulObjId, unsigned int* lpulRights)
- {
- ECRESULT er = erSuccess;
- struct rightsArray *lpRights = NULL;
- unsigned ulCurObj = ulObjId;
- bool bFoundACL = false;
- unsigned int ulDepth = 0;
- *lpulRights = 0;
- // Get the deepest GRANT ACL that applies to this user or groups that this user is in
- // WARNING we totally ignore DENY ACL's here. This means that the deepest GRANT counts. In practice
- // this doesn't matter because GRANTmask = ~DENYmask.
- while(true)
- {
- if(m_lpSession->GetSessionManager()->GetCacheManager()->GetACLs(ulCurObj, &lpRights) == erSuccess) {
- // This object has ACL's, check if any of them are for this user
- for (gsoap_size_t i = 0; i < lpRights->__size; ++i)
- if(lpRights->__ptr[i].ulType == ACCESS_TYPE_GRANT && lpRights->__ptr[i].ulUserid == m_ulUserID) {
- *lpulRights |= lpRights->__ptr[i].ulRights;
- bFoundACL = true;
- }
- // Check for the company we are in and add the permissions
- for (gsoap_size_t i = 0; i < lpRights->__size; ++i)
- if (lpRights->__ptr[i].ulType == ACCESS_TYPE_GRANT && lpRights->__ptr[i].ulUserid == m_ulCompanyID) {
- *lpulRights |= lpRights->__ptr[i].ulRights;
- bFoundACL = true;
- }
- // Also check for groups that we are in, and add those permissions
- if(m_lpGroups || GetGroupsForUser(m_ulUserID, &m_lpGroups) == erSuccess)
- for (const auto &grp : *m_lpGroups)
- for (gsoap_size_t i = 0; i < lpRights->__size; ++i)
- if (lpRights->__ptr[i].ulType == ACCESS_TYPE_GRANT &&
- lpRights->__ptr[i].ulUserid == grp.ulId) {
- *lpulRights |= lpRights->__ptr[i].ulRights;
- bFoundACL = true;
- }
- }
- if(lpRights)
- {
- FreeRightsArray(lpRights);
- lpRights = NULL;
- }
- if (bFoundACL)
- // If any of the ACLs at this level were for us, then use these ACLs.
- break;
- // There were no ACLs or no ACLs for us, go to the parent and try there
- er = m_lpSession->GetSessionManager()->GetCacheManager()->GetParent(ulCurObj, &ulCurObj);
- if (er != erSuccess)
- // No more parents, break (with ulRights = 0)
- return erSuccess;
-
- // This can really only happen if you have a broken tree in the database, eg a record which has
- // parent == id. To break out of the loop we limit the depth to 64 which is very deep in practice. This means
- // that you never have any rights for folders that are more than 64 levels of folders away from their ACL ..
- if (++ulDepth > MAX_PARENT_LIMIT) {
- ec_log_err("Maximum depth reached for object %d, deepest object: %d", ulObjId, ulCurObj);
- return erSuccess;
- }
- }
- return er;
- }
- /**
- * Check permission for a certain object id
- *
- * This function checks if ANY of the passed permissions are granted on the passed object
- * for the currently logged-in user.
- *
- * @param[in] ulObjId Object ID for which the permission should be checked
- * @param[in] ulACLMask Mask of permissions to be checked
- * @return Kopano error code
- * @retval erSuccess if permission is granted
- * @retval KCERR_NO_ACCESS if permission is denied
- */
- ECRESULT ECSecurity::HaveObjectPermission(unsigned int ulObjId, unsigned int ulACLMask)
- {
- unsigned int ulRights = 0;
- GetObjectPermission(ulObjId, &ulRights);
- return (ulRights & ulACLMask) ? erSuccess : KCERR_NO_ACCESS;
- }
- /**
- * Checks if you are the owner of the given object id. This can return
- * no access, since other people may have created an object in the
- * owner's store (or true if you're that someone).
- *
- * @param[in] ulObjId hierarchy object to check ownership of
- *
- * @return Kopano error code
- */
- ECRESULT ECSecurity::IsOwner(unsigned int ulObjId) const
- {
- unsigned int ulOwner = 0;
- auto er = GetOwner(ulObjId, &ulOwner);
- return er != erSuccess || ulOwner != m_ulUserID ? KCERR_NO_ACCESS : erSuccess;
- }
- /**
- * Get the original creator of an object
- *
- * @param[in] ulObjId hierarchy object to get ownership of
- * @param[out] lpulOwnerId owner userid (may not even exist anymore)
- *
- * @return Kopano error code
- */
- ECRESULT ECSecurity::GetOwner(unsigned int ulObjId,
- unsigned int *lpulOwnerId) const
- {
- // Default setting
- *lpulOwnerId = 0;
- auto er = m_lpSession->GetSessionManager()->GetCacheManager()->GetOwner(ulObjId, lpulOwnerId);
- return er != erSuccess ? KCERR_NOT_FOUND : er;
- }
- /**
- * Check for a deleted folder as parent of ulId, max folder depth as
- * defined (64).
- *
- * @param[in] ulId object id to start checking from
- *
- * @return KCERR_NOT_FOUND Error if a parent has the delete flag
- */
- ECRESULT ECSecurity::CheckDeletedParent(unsigned int ulId) const
- {
- ECRESULT er = erSuccess;
- unsigned int ulParentObjId = 0;
- unsigned int ulObjFlags = 0;
- unsigned int ulObjType = 0;
- unsigned int ulDepth = 0;
- ECCacheManager *lpCache = m_lpSession->GetSessionManager()->GetCacheManager();
- do {
- er = lpCache->GetObject(ulId, &ulParentObjId, NULL, &ulObjFlags, &ulObjType);
- if (er != erSuccess)
- return er;
- if (ulObjFlags & MSGFLAG_DELETED)
- return KCERR_NOT_FOUND;
- ulId = ulParentObjId;
- ++ulDepth;
- } while (ulObjType != MAPI_STORE && ulParentObjId != CACHE_NO_PARENT && ulDepth <= MAX_PARENT_LIMIT);
- // return error when max depth is reached, so we don't create folders and messages deeper than the limit
- if (ulDepth == MAX_PARENT_LIMIT)
- er = KCERR_NOT_FOUND;
- return er;
- }
- /**
- * For the current user context, check the permissions on a given object
- *
- * @param[in] ulObjId hierarchy object to check permissions on
- * @param[in] ulecRights minimal permission required on object to succeed
- *
- * @return Kopano error code
- * @retval erSuccess requested access on object allowed
- * @retval KCERR_NO_ACCESS requested access on object denied
- */
- ECRESULT ECSecurity::CheckPermission(unsigned int ulObjId, unsigned int ulecRights)
- {
- ECRESULT er = KCERR_NO_ACCESS;
- bool bOwnerFound = false;
- unsigned int ulStoreOwnerId = 0;
- unsigned int ulStoreType = 0;
- unsigned int ulObjectOwnerId = 0;
- unsigned int ulACL = 0;
- int nCheckType = 0;
- unsigned int ulObjType;
- unsigned int ulParentId;
- unsigned int ulParentType;
- if(m_ulUserID == KOPANO_UID_SYSTEM) {
- // SYSTEM is always allowed everything
- er = erSuccess;
- goto exit;
- }
- // special case: stores and root containers are always allowed to be opened
- if (ulecRights == ecSecurityFolderVisible || ulecRights == ecSecurityRead) {
- er = m_lpSession->GetSessionManager()->GetCacheManager()->GetObject(ulObjId, &ulParentId, NULL, NULL, &ulObjType);
- if (er != erSuccess)
- goto exit;
- if (ulObjType == MAPI_STORE)
- goto exit;
- er = m_lpSession->GetSessionManager()->GetCacheManager()->GetObject(ulParentId, NULL, NULL, NULL, &ulParentType);
- if (er != erSuccess)
- goto exit;
- if (ulObjType == MAPI_FOLDER && ulParentType == MAPI_STORE)
- goto exit;
- }
- // Is the current user the owner of the store
- if (GetStoreOwnerAndType(ulObjId, &ulStoreOwnerId, &ulStoreType) == erSuccess && ulStoreOwnerId == m_ulUserID) {
- if (ulStoreType != ECSTORE_TYPE_ARCHIVE) {
- er = erSuccess;
- goto exit;
- } else if (ulecRights == ecSecurityFolderVisible || ulecRights == ecSecurityRead) {
- er = erSuccess;
- goto exit;
- }
- }
- // is current user the owner of the object
- if (GetOwner(ulObjId, &ulObjectOwnerId) == erSuccess && ulObjectOwnerId == m_ulUserID && m_bOwnerAutoFullAccess)
- {
- bOwnerFound = true;
- if (ulStoreType == ECSTORE_TYPE_ARCHIVE) {
- if(ulecRights == ecSecurityFolderVisible || ulecRights == ecSecurityRead) {
- er = erSuccess;
- goto exit;
- }
- } else if(ulecRights == ecSecurityFolderVisible || ulecRights == ecSecurityRead || ulecRights == ecSecurityCreate) {
- er = erSuccess;
- goto exit;
- }
- }
- // Since this is the most complicated check, do this one last
- if(IsAdminOverOwnerOfObject(ulObjId) == erSuccess) {
- if(!m_bRestrictedAdmin) {
- er = erSuccess;
- goto exit;
- }
- // If restricted admin mode is set, admins only receive folder permissions.
- if(ulecRights == ecSecurityFolderVisible || ulecRights == ecSecurityFolderAccess || ulecRights == ecSecurityCreateFolder) {
- er = erSuccess;
- goto exit;
- }
- }
- ulACL = 0;
- switch(ulecRights){
- case ecSecurityRead: // 1
- ulACL |= ecRightsReadAny;
- nCheckType = 1;
- break;
- case ecSecurityCreate: // 2
- ulACL |= ecRightsCreate;
- nCheckType = 1;
- break;
- case ecSecurityEdit: // 3
- ulACL |= ecRightsEditAny;
- if(bOwnerFound)
- ulACL |= ecRightsEditOwned;
- nCheckType = 1;
- break;
- case ecSecurityDelete: // 4
- ulACL |= ecRightsDeleteAny;
- if(bOwnerFound)
- ulACL |= ecRightsDeleteOwned;
- nCheckType = 1;
- break;
- case ecSecurityCreateFolder: // 5
- ulACL |= ecRightsCreateSubfolder;
- nCheckType = 1;
- break;
- case ecSecurityFolderVisible: // 6
- ulACL |= ecRightsFolderVisible;
- nCheckType = 1;
- break;
- case ecSecurityFolderAccess: // 7
- if (bOwnerFound == false || ulStoreType == ECSTORE_TYPE_ARCHIVE)
- ulACL |= ecRightsFolderAccess;
- nCheckType = 1;
- break;
- case ecSecurityOwner: // 8
- nCheckType = 2;
- break;
- case ecSecurityAdmin: // 9
- nCheckType = 3;
- break;
- default:
- nCheckType = 0; // No rights
- break;
- }
- if(nCheckType == 1) { //Get the acl of the object
- if(ulACL == 0) {
- // No ACLs required, so grant access
- er = erSuccess;
- goto exit;
- }
- er = HaveObjectPermission(ulObjId, ulACL);
- } else if(nCheckType == 2) {// Is owner ?
- if (bOwnerFound)
- er = erSuccess;
- } else if(nCheckType == 3) { // Is admin?
- // We already checked IsAdminOverOwnerOfObject() above, so we'll never get here.
- er = erSuccess;
- }
- exit:
- if (er == erSuccess && (ulecRights == ecSecurityCreate || ulecRights == ecSecurityEdit || ulecRights == ecSecurityCreateFolder))
- // writing in a deleted parent is not allowed
- er = CheckDeletedParent(ulObjId);
- if(er != erSuccess)
- TRACE_INTERNAL(TRACE_ENTRY,"Security","ECSecurity::CheckPermission","object=%d, rights=%d", ulObjId, ulecRights);
- if (m_lpAudit && m_ulUserID != KOPANO_UID_SYSTEM) {
- unsigned int ulType = 0;
- objectdetails_t sStoreDetails;
- std::string strStoreOwner;
- std::string strUsername;
- m_lpSession->GetSessionManager()->GetCacheManager()->GetObject(ulObjId, NULL, NULL, NULL, &ulType);
- if (er == KCERR_NO_ACCESS || ulStoreOwnerId != m_ulUserID) {
- GetUsername(&strUsername);
- if (ulStoreOwnerId == m_ulUserID)
- strStoreOwner = strUsername;
- else if (m_lpSession->GetUserManagement()->GetObjectDetails(ulStoreOwnerId, &sStoreDetails) != erSuccess)
- // should not really happen on store owners?
- strStoreOwner = "<non-existing>";
- else
- strStoreOwner = sStoreDetails.GetPropString(OB_PROP_S_LOGIN);
- }
- if (er == KCERR_NO_ACCESS)
- m_lpAudit->Log(EC_LOGLEVEL_FATAL, "access denied objectid=%d type=%d ownername='%s' username='%s' rights='%s'",
- ulObjId, ulType, strStoreOwner.c_str(), strUsername.c_str(), RightsToString(ulecRights));
- else if (ulStoreOwnerId != m_ulUserID)
- m_lpAudit->Log(EC_LOGLEVEL_FATAL, "access allowed objectid=%d type=%d ownername='%s' username='%s' rights='%s'",
- ulObjId, ulType, strStoreOwner.c_str(), strUsername.c_str(), RightsToString(ulecRights));
- else
- // you probably do not want to log all what a user does in their own store, do you?
- m_lpAudit->Log(EC_LOGLEVEL_INFO, "access allowed objectid=%d type=%d userid=%d", ulObjId, ulType, m_ulUserID);
- }
- return er;
- }
- /**
- * Get the ACLs on a given object in a protocol struct to send to the client
- *
- * @param[in] objid hierarchy object to get the ACLs for
- * @param[in] ulType rights access type, denied or grant
- * @param[out] lpsRightsArray structure with the current rights on objid
- *
- * @return Kopano error code
- */
- ECRESULT ECSecurity::GetRights(unsigned int objid, int ulType,
- struct rightsArray *lpsRightsArray) const
- {
- ECRESULT er = KCERR_NO_ACCESS;
- DB_RESULT lpDBResult;
- DB_ROW lpDBRow = NULL;
- ECDatabase *lpDatabase = NULL;
- std::string strQuery;
- unsigned int ulCount = 0;
- unsigned int i=0;
- objectid_t sExternId;
- er = m_lpSession->GetDatabase(&lpDatabase);
- if (er != erSuccess)
- return er;
- if (lpsRightsArray == nullptr)
- return KCERR_INVALID_PARAMETER;
- strQuery = "SELECT a.id, a.type, a.rights FROM acl AS a WHERE a.hierarchy_id="+stringify(objid);
- if(ulType == ACCESS_TYPE_DENIED)
- strQuery += " AND a.type="+stringify(ACCESS_TYPE_DENIED);
- else if(ulType == ACCESS_TYPE_GRANT)
- strQuery += " AND a.type="+stringify(ACCESS_TYPE_GRANT);
- // else ACCESS_TYPE_DENIED and ACCESS_TYPE_GRANT
- er = lpDatabase->DoSelect(strQuery, &lpDBResult);
- if(er != erSuccess)
- return er;
- ulCount = lpDatabase->GetNumRows(lpDBResult);
- if(ulCount > 0)
- {
- lpsRightsArray->__ptr = s_alloc<rights>(nullptr, ulCount);
- lpsRightsArray->__size = ulCount;
- memset(lpsRightsArray->__ptr, 0, sizeof(struct rights) * ulCount);
- for (i = 0; i < ulCount; ++i) {
- lpDBRow = lpDatabase->FetchRow(lpDBResult);
- if(lpDBRow == NULL) {
- ec_log_err("ECSecurity::GetRights(): row is null");
- return KCERR_DATABASE_ERROR;
- }
- lpsRightsArray->__ptr[i].ulUserid = atoi(lpDBRow[0]);
- lpsRightsArray->__ptr[i].ulType = atoi(lpDBRow[1]);
- lpsRightsArray->__ptr[i].ulRights = atoi(lpDBRow[2]);
- lpsRightsArray->__ptr[i].ulState = RIGHT_NORMAL;
- // do not use internal IDs with the cache
- if (lpsRightsArray->__ptr[i].ulUserid == KOPANO_UID_SYSTEM) {
- sExternId = objectid_t(ACTIVE_USER);
- } else if (lpsRightsArray->__ptr[i].ulUserid == KOPANO_UID_EVERYONE) {
- sExternId = objectid_t(DISTLIST_GROUP);
- } else {
- er = m_lpSession->GetUserManagement()->GetExternalId(lpsRightsArray->__ptr[i].ulUserid, &sExternId);
- if (er != erSuccess)
- return er;
- }
- er = ABIDToEntryID(NULL, lpsRightsArray->__ptr[i].ulUserid, sExternId, &lpsRightsArray->__ptr[i].sUserId);
- if (er != erSuccess)
- return er;
- }
- }else{
- lpsRightsArray->__ptr = NULL;
- lpsRightsArray->__size = 0;
- }
- return erSuccess;
- }
- /**
- * Update the rights on a given object
- *
- * @param[in] objid hierarchy object id to set rights on
- * @param[in] lpsRightsArray protocol struct containing new rights for this object
- *
- * @return Kopano error code
- */
- ECRESULT ECSecurity::SetRights(unsigned int objid, struct rightsArray *lpsRightsArray)
- {
- ECRESULT er;
- std::string strQueryNew, strQueryDelete;
- unsigned int ulDeniedRights=0;
- ECDatabase *lpDatabase = NULL;
- unsigned int ulUserId = 0;
- objectid_t sExternId;
- objectdetails_t sDetails;
- size_t ulErrors = 0;
- er = m_lpSession->GetDatabase(&lpDatabase);
- if (er != erSuccess)
- return er;
- if (lpsRightsArray == NULL)
- return KCERR_INVALID_PARAMETER;
- // Invalidate cache for this object
- m_lpSession->GetSessionManager()->GetCacheManager()->Update(fnevObjectModified, objid);
- for (gsoap_size_t i = 0; i < lpsRightsArray->__size; ++i) {
- // FIXME: check for each object if it belongs to the store we're logged into (except for admin)
- // Get the correct local id
- if (lpsRightsArray->__ptr[i].sUserId.__size > 0 && lpsRightsArray->__ptr[i].sUserId.__ptr != NULL)
- {
- er = ABEntryIDToID(&lpsRightsArray->__ptr[i].sUserId, &ulUserId, &sExternId, NULL);
- if (er != erSuccess)
- return er;
- // internal user/group doesn't have an externid
- if (!sExternId.id.empty())
- {
- // Get real ulUserId on this server
- er = m_lpSession->GetUserManagement()->GetLocalId(sExternId, &ulUserId, NULL);
- if (er != erSuccess)
- return er;
- }
- }
- else
- ulUserId = lpsRightsArray->__ptr[i].ulUserid;
- er = m_lpSession->GetUserManagement()->GetObjectDetails(ulUserId, &sDetails);
- if (er != erSuccess)
- return er;
- // You can only set (delete is ok) permissions on active users, and security groups
- // Outlook 2007 blocks this client side, other clients get this error.
- if ((lpsRightsArray->__ptr[i].ulState & ~(RIGHT_DELETED | RIGHT_AUTOUPDATE_DENIED)) != 0 &&
- sDetails.GetClass() != ACTIVE_USER &&
- sDetails.GetClass() != DISTLIST_SECURITY &&
- sDetails.GetClass() != CONTAINER_COMPANY) {
- ++ulErrors;
- continue;
- }
- // Auto create denied rules
- ulDeniedRights = lpsRightsArray->__ptr[i].ulRights^ecRightsAllMask;
- if(lpsRightsArray->__ptr[i].ulRights & ecRightsEditAny)
- ulDeniedRights&=~ecRightsEditOwned;
- else if(lpsRightsArray->__ptr[i].ulRights & ecRightsEditOwned){
- ulDeniedRights&=~ecRightsEditOwned;
- ulDeniedRights|=ecRightsEditAny;
- }
- if(lpsRightsArray->__ptr[i].ulRights & ecRightsDeleteAny)
- ulDeniedRights&=~ecRightsDeleteOwned;
- else if(lpsRightsArray->__ptr[i].ulRights & ecRightsDeleteOwned)
- {
- ulDeniedRights&=~ecRightsDeleteOwned;
- ulDeniedRights|=ecRightsDeleteAny;
- }
- if(lpsRightsArray->__ptr[i].ulState == RIGHT_NORMAL)
- {
- // Do nothing...
- }
- else if((lpsRightsArray->__ptr[i].ulState & RIGHT_NEW) || (lpsRightsArray->__ptr[i].ulState & RIGHT_MODIFY))
- {
- strQueryNew = "REPLACE INTO acl (id, hierarchy_id, type, rights) VALUES ";
- strQueryNew+="("+stringify(ulUserId)+","+stringify(objid)+","+stringify(lpsRightsArray->__ptr[i].ulType)+","+stringify(lpsRightsArray->__ptr[i].ulRights)+")";
- er = lpDatabase->DoInsert(strQueryNew);
- if(er != erSuccess)
- return er;
- if(lpsRightsArray->__ptr[i].ulState & RIGHT_AUTOUPDATE_DENIED){
- strQueryNew = "REPLACE INTO acl (id, hierarchy_id, type, rights) VALUES ";
- strQueryNew+=" ("+stringify(ulUserId)+","+stringify(objid)+","+stringify(ACCESS_TYPE_DENIED)+","+stringify(ulDeniedRights)+")";
- er = lpDatabase->DoInsert(strQueryNew);
- if(er != erSuccess)
- return er;
- }
- }
- else if(lpsRightsArray->__ptr[i].ulState & RIGHT_DELETED)
- {
- strQueryDelete = "DELETE FROM acl WHERE ";
- strQueryDelete+="(hierarchy_id="+stringify(objid)+" AND id="+stringify(ulUserId)+" AND type="+stringify(lpsRightsArray->__ptr[i].ulType)+")";
- er = lpDatabase->DoDelete(strQueryDelete);
- if(er != erSuccess)
- return er;
- if(lpsRightsArray->__ptr[i].ulState & RIGHT_AUTOUPDATE_DENIED) {
- strQueryDelete = "DELETE FROM acl WHERE ";
- strQueryDelete+="(hierarchy_id="+stringify(objid)+" AND id="+stringify(ulUserId)+" AND type="+stringify(ACCESS_TYPE_DENIED)+")";
- er = lpDatabase->DoDelete(strQueryDelete);
- if(er != erSuccess)
- return er;
- }
- }else{
- // a Hacker ?
- }
- }
- if (lpsRightsArray->__size >= 0 && ulErrors == static_cast<size_t>(lpsRightsArray->__size))
- er = KCERR_INVALID_PARAMETER; // all acl's failed
- else if (ulErrors != 0)
- er = KCWARN_PARTIAL_COMPLETION; // some acl's failed
- else
- er = erSuccess;
- return er;
- }
- /**
- * Return the company id of the current user context
- *
- * @param[out] lpulCompanyId company id of user
- *
- * @return always erSuccess
- */
- ECRESULT ECSecurity::GetUserCompany(unsigned int *lpulCompanyId) const
- {
- *lpulCompanyId = m_ulCompanyID;
- return erSuccess;
- }
- /**
- * Get a list of company ids that may be viewed by the current user
- *
- * @param[in] ulFlags Usermanagemnt flags
- * @param[out] lppObjects New allocated list of company details
- *
- * @return Kopano error code
- */
- ECRESULT ECSecurity::GetViewableCompanyIds(unsigned int ulFlags, list<localobjectdetails_t> **lppObjects)
- {
- ECRESULT er;
- /*
- * We have the viewable companies stored in our cache,
- * if it is present use that, otherwise just create a
- * new one.
- * NOTE: We always request GetViewableCompanies with 0 as ulFlags,
- * this because we are caching the list here and some callers might
- * want all details while others will only want the IDs.
- */
- if (!m_lpViewCompanies) {
- er = GetViewableCompanies(0, &m_lpViewCompanies);
- if (er != erSuccess)
- return er;
- }
- /*
- * Because of the difference in flags it is possible we have
- * too many entries in the list. We need to filter those out now.
- */
- *lppObjects = new list<localobjectdetails_t>();
- for (const auto &i : *m_lpViewCompanies) {
- if (m_ulUserID != 0 && (ulFlags & USERMANAGEMENT_ADDRESSBOOK) &&
- i.GetPropBool(OB_PROP_B_AB_HIDDEN))
- continue;
- if (ulFlags & USERMANAGEMENT_IDS_ONLY)
- (*lppObjects)->push_back(localobjectdetails_t(i.ulId, i.GetClass()));
- else
- (*lppObjects)->push_back(localobjectdetails_t(i.ulId, i));
- }
- return erSuccess;
- }
- /**
- * Check if the given user id is readable by the current user
- *
- * @param[in] ulUserObjectId internal user id
- *
- * @return Kopano error code
- * @retval erSuccess viewable
- * @retval KCERR_NOT_FOUND not viewable
- */
- ECRESULT ECSecurity::IsUserObjectVisible(unsigned int ulUserObjectId)
- {
- ECRESULT er;
- objectid_t sExternId;
- unsigned int ulCompanyId;
- if (ulUserObjectId == 0 ||
- ulUserObjectId == m_ulUserID ||
- ulUserObjectId == m_ulCompanyID ||
- ulUserObjectId == KOPANO_UID_SYSTEM ||
- ulUserObjectId == KOPANO_UID_EVERYONE ||
- m_details.GetPropInt(OB_PROP_I_ADMINLEVEL) == ADMIN_LEVEL_SYSADMIN ||
- !m_lpSession->GetSessionManager()->IsHostedSupported())
- return erSuccess;
- er = m_lpSession->GetUserManagement()->GetExternalId(ulUserObjectId, &sExternId, &ulCompanyId);
- if (er != erSuccess)
- return er;
- // still needed?
- if (sExternId.objclass == CONTAINER_COMPANY)
- ulCompanyId = ulUserObjectId;
- if (!m_lpViewCompanies) {
- er = GetViewableCompanies(0, &m_lpViewCompanies);
- if (er != erSuccess)
- return er;
- }
- for (const auto &company : *m_lpViewCompanies)
- if (company.ulId == ulCompanyId)
- return erSuccess;
- /* Item was not found */
- return KCERR_NOT_FOUND;
- }
- /**
- * Internal helper function to get a list of viewable company details
- *
- * @todo won't this bug when we cache only the IDs in a first call,
- * and then when we need the full details, the m_lpViewCompanies will
- * only contain the IDs?
- *
- * @param[in] ulFlags usermanagement flags
- * @param[in] lppObjects new allocated list with company details
- *
- * @return
- */
- ECRESULT ECSecurity::GetViewableCompanies(unsigned int ulFlags,
- std::list<localobjectdetails_t> **lppObjects) const
- {
- ECRESULT er = erSuccess;
- std::unique_ptr<std::list<localobjectdetails_t> > lpObjects;
- objectdetails_t details;
- if (m_details.GetPropInt(OB_PROP_I_ADMINLEVEL) == ADMIN_LEVEL_SYSADMIN)
- er = m_lpSession->GetUserManagement()->GetCompanyObjectListAndSync(CONTAINER_COMPANY, 0, &unique_tie(lpObjects), ulFlags);
- else
- er = m_lpSession->GetUserManagement()->GetParentObjectsOfObjectAndSync(OBJECTRELATION_COMPANY_VIEW,
- m_ulCompanyID, &unique_tie(lpObjects), ulFlags);
- if (er != erSuccess)
- /* Whatever the error might be, it only indicates we
- * are not allowed to view _other_ companyspaces.
- * It doesn't restrict us from viewing our own... */
- lpObjects.reset(new std::list<localobjectdetails_t>);
- /* We are going to insert the requested companyID to the list as well,
- * this way we guarentee that _all_ viewable companies are in the list.
- * And we can use sort() and unique() to prevent duplicate entries while
- * making sure the we can savely handle things when the current company
- * is either added or not present in the RemoteViewableCompanies. */
- if (m_ulCompanyID != 0) {
- if (!(ulFlags & USERMANAGEMENT_IDS_ONLY)) {
- er = m_lpSession->GetUserManagement()->GetObjectDetails(m_ulCompanyID, &details);
- if (er != erSuccess)
- return er;
- } else {
- details = objectdetails_t(CONTAINER_COMPANY);
- }
- lpObjects->push_back(localobjectdetails_t(m_ulCompanyID, details));
- }
- lpObjects->sort();
- lpObjects->unique();
- *lppObjects = lpObjects.release();
- return erSuccess;
- }
- /**
- * Get a list of company details which the current user is admin over
- *
- * @param[in] ulFlags usermanagement flags
- * @param[out] lppObjects company list
- *
- * @return Kopano error code
- */
- ECRESULT ECSecurity::GetAdminCompanies(unsigned int ulFlags, list<localobjectdetails_t> **lppObjects)
- {
- ECRESULT er = erSuccess;
- std::unique_ptr<std::list<localobjectdetails_t> > lpObjects;
- if (m_details.GetPropInt(OB_PROP_I_ADMINLEVEL) == ADMIN_LEVEL_SYSADMIN)
- er = m_lpSession->GetUserManagement()->GetCompanyObjectListAndSync(CONTAINER_COMPANY,
- 0, &unique_tie(lpObjects), ulFlags);
- else
- er = m_lpSession->GetUserManagement()->GetParentObjectsOfObjectAndSync(OBJECTRELATION_COMPANY_ADMIN,
- m_ulUserID, &unique_tie(lpObjects), ulFlags);
- if (er != erSuccess)
- return er;
- /* A user is only admin over a company when he has privileges to view the company */
- for (auto iterObjects = lpObjects->begin(); iterObjects != lpObjects->cend(); ) {
- if (IsUserObjectVisible(iterObjects->ulId) != erSuccess) {
- auto iterObjectsRemove = iterObjects;
- ++iterObjects;
- lpObjects->erase(iterObjectsRemove);
- } else {
- ++iterObjects;
- }
- }
- *lppObjects = lpObjects.release();
- return erSuccess;
- }
- /**
- * Return the current logged in UserID _OR_ if you're an administrator
- * over user that is set as owner of the given object, return the
- * owner of the object.
- *
- * @param[in] ulObjId object to get ownership of if admin, defaults to 0 to get the current UserID
- *
- * @return user id of object
- */
- unsigned int ECSecurity::GetUserId(unsigned int ulObjId)
- {
- ECRESULT er = erSuccess;
- unsigned int ulUserId = this->m_ulUserID;
- if (ulObjId != 0 && IsAdminOverOwnerOfObject(ulObjId) == erSuccess) {
- er = GetOwner(ulObjId, &ulUserId);
- if (er != erSuccess)
- ulUserId = this->m_ulUserID;
- }
- return ulUserId;
- }
- /**
- * Check if the given object id is in your own store
- *
- * @param[in] ulObjId hierarchy object id of object to check
- *
- * @return Kopano error code
- * @retval erSuccess object is in current user's store
- */
- ECRESULT ECSecurity::IsStoreOwner(unsigned int ulObjId) const
- {
- ECRESULT er;
- unsigned int ulStoreId = 0;
- er = m_lpSession->GetSessionManager()->GetCacheManager()->GetStore(ulObjId, &ulStoreId, NULL);
- if(er != erSuccess)
- return er;
- er = IsOwner(ulStoreId);
- if(er != erSuccess)
- return er;
- return erSuccess;
- }
- /**
- * Return the current user's admin level
- *
- * @return admin level of user
- */
- int ECSecurity::GetAdminLevel(void) const
- {
- return m_details.GetPropInt(OB_PROP_I_ADMINLEVEL);
- }
- /**
- * Get the owner of the store in which the given objectid resides in
- *
- * @param[in] ulObjId hierarchy object id to get store owner of
- * @param[in] lpulOwnerId user id of store in which ulObjId resides
- *
- * @return Kopano error code
- */
- ECRESULT ECSecurity::GetStoreOwner(unsigned int ulObjId,
- unsigned int *lpulOwnerId) const
- {
- return GetStoreOwnerAndType(ulObjId, lpulOwnerId, NULL);
- }
- /**
- * Get the owner and type of the store in which the given objectid resides in
- *
- * @param[in] ulObjId hierarchy object id to get store owner of
- * @param[out] lpulOwnerId user id of store in which ulObjId resides
- * @param[out] lpulStoreType type of store in which ulObjId resides
- *
- * @return Kopano error code
- */
- ECRESULT ECSecurity::GetStoreOwnerAndType(unsigned int ulObjId,
- unsigned int *lpulOwnerId, unsigned int *lpulStoreType) const
- {
- ECRESULT er;
- unsigned int ulStoreId = 0;
- if (lpulOwnerId || lpulStoreType) {
- er = m_lpSession->GetSessionManager()->GetCacheManager()->GetStoreAndType(ulObjId, &ulStoreId, NULL, lpulStoreType);
- if (er != erSuccess)
- return er;
- }
- if (lpulOwnerId) {
- er = GetOwner(ulStoreId, lpulOwnerId);
- if (er != erSuccess)
- return er;
- }
- return erSuccess;
- }
- /**
- * Check if the current user is admin over a given user id (user/group/company/...)
- *
- * @todo this function should be renamed to IsAdminOfUserObject(id) or something like that
- *
- * @param[in] ulUserObjectId id of user
- *
- * @return Kopano error code
- * @retval erSuccess Yes, admin
- * @retval KCERR_NO_ACCESS No, not admin
- */
- ECRESULT ECSecurity::IsAdminOverUserObject(unsigned int ulUserObjectId)
- {
- ECRESULT er = KCERR_NO_ACCESS;
- unsigned int ulCompanyId;
- objectdetails_t objectdetails;
- objectid_t sExternId;
- /* Hosted disabled: When admin level is not zero, then the user
- * is the administrator, otherwise the user isn't and we don't need
- * to look any further. */
- if (!m_lpSession->GetSessionManager()->IsHostedSupported()) {
- if (m_details.GetPropInt(OB_PROP_I_ADMINLEVEL) != 0)
- er = erSuccess;
- return er;
- }
- /* If hosted is enabled, system administrators are administrator over all users. */
- if (m_details.GetPropInt(OB_PROP_I_ADMINLEVEL) == ADMIN_LEVEL_SYSADMIN)
- return erSuccess;
- /*
- * Determine to which company the user belongs
- */
- er = m_lpSession->GetUserManagement()->GetExternalId(ulUserObjectId, &sExternId, &ulCompanyId);
- if (er != erSuccess)
- return er;
- // still needed?
- if (sExternId.objclass == CONTAINER_COMPANY)
- ulCompanyId = ulUserObjectId;
- /*
- * If ulCompanyId is the company where the logged in user belongs to,
- * then the only thing we need to check is the "isadmin" boolean.
- */
- if (m_ulCompanyID == ulCompanyId) {
- if (m_details.GetPropInt(OB_PROP_I_ADMINLEVEL) != 0)
- er = erSuccess;
- else
- er = KCERR_NO_ACCESS;
- return er;
- }
- if (!m_lpAdminCompanies) {
- er = GetAdminCompanies(USERMANAGEMENT_IDS_ONLY, &m_lpAdminCompanies);
- if (er != erSuccess)
- return er;
- }
- for (const auto &obj : *m_lpAdminCompanies)
- if (obj.ulId == ulCompanyId)
- return erSuccess;
- /* Item was not found, so no access */
- return KCERR_NO_ACCESS;
- }
- /**
- * Check if we're admin over the user who owns the given object id
- *
- * @param ulObjectId hierarchy object id
- *
- * @return Kopano error code
- * @retval erSuccess Yes
- * @retval KCERR_NO_ACCESS No
- */
- ECRESULT ECSecurity::IsAdminOverOwnerOfObject(unsigned int ulObjectId)
- {
- ECRESULT er;
- unsigned int ulOwner;
- /*
- * Request the ownership if the object.
- */
- er = GetStoreOwner(ulObjectId, &ulOwner);
- if (er != erSuccess)
- return er;
- return IsAdminOverUserObject(ulOwner);
- }
- /**
- * Get the size of the store in which the given ulObjId resides in
- *
- * @param[in] ulObjId hierarchy object id
- * @param[out] lpllStoreSize size of store
- *
- * @return Kopano error code
- */
- ECRESULT ECSecurity::GetStoreSize(unsigned int ulObjId,
- long long *lpllStoreSize) const
- {
- ECRESULT er = erSuccess;
- ECDatabase *lpDatabase = NULL;
- DB_RESULT lpDBResult;
- DB_ROW lpDBRow = NULL;
- std::string strQuery;
- unsigned int ulStore;
- er = m_lpSession->GetDatabase(&lpDatabase);
- if (er != erSuccess)
- return er;
- er = m_lpSession->GetSessionManager()->GetCacheManager()->GetStore(ulObjId, &ulStore, NULL);
- if(er != erSuccess)
- return er;
- 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);
- er = lpDatabase->DoSelect(strQuery, &lpDBResult);
- if(er != erSuccess)
- return er;
- if(lpDatabase->GetNumRows(lpDBResult) != 1) {
- // This mostly happens when we're creating a new store, so return 0 sized store
- *lpllStoreSize = 0;
- return erSuccess;
- }
- lpDBRow = lpDatabase->FetchRow(lpDBResult);
- if(lpDBRow == NULL || lpDBRow[0] == NULL) {
- ec_log_err("ECSecurity::GetStoreSize(): row is null");
- return KCERR_DATABASE_ERROR;
- }
- *lpllStoreSize = atoll(lpDBRow[0]);
- return erSuccess;
- }
- /**
- * Get the store size of a given user
- *
- * @param[in] ulUserId internal user id
- * @param[out] lpllUserSize store size of user
- *
- * @return Kopano error code
- */
- ECRESULT ECSecurity::GetUserSize(unsigned int ulUserId,
- long long *lpllUserSize) const
- {
- ECRESULT er = erSuccess;
- ECDatabase *lpDatabase = NULL;
- DB_RESULT lpDBResult;
- DB_ROW lpDBRow = NULL;
- std::string strQuery;
- long long llUserSize = 0;
- er = m_lpSession->GetDatabase(&lpDatabase);
- if (er != erSuccess)
- return er;
- strQuery =
- "SELECT p.val_longint "
- "FROM properties AS p "
- "JOIN stores AS s "
- "ON s.hierarchy_id = p.hierarchyid "
- "WHERE "
- "s.user_id = " + stringify(ulUserId) + " " +
- "AND p.tag = " + stringify(PROP_ID(PR_MESSAGE_SIZE_EXTENDED)) + " "
- "AND p.type = " + stringify(PROP_TYPE(PR_MESSAGE_SIZE_EXTENDED));
- er = lpDatabase->DoSelect(strQuery, &lpDBResult);
- if(er != erSuccess)
- return er;
- if (lpDatabase->GetNumRows(lpDBResult) != 1) {
- *lpllUserSize = 0;
- return erSuccess;
- }
- lpDBRow = lpDatabase->FetchRow(lpDBResult);
- if (lpDBRow == NULL) {
- ec_log_err("ECSecurity::GetUserSize(): row is null");
- return KCERR_DATABASE_ERROR;
- }
- if (lpDBRow[0] == NULL)
- llUserSize = 0;
- else
- llUserSize = atoll(lpDBRow[0]);
- *lpllUserSize = llUserSize;
- return erSuccess;
- }
- /**
- * Gets the quota status value (ok, warn, soft, hard) for a given
- * store and store size
- *
- * @note if you already know the owner of the store, it's better to
- * call ECSecurity::CheckUserQuota
- *
- * @param[in] ulStoreId store to check quota for
- * @param[in] llStoreSize current store size of the store
- * @param[out] lpQuotaStatus quota status value
- *
- * @return Kopano error code
- */
- ECRESULT ECSecurity::CheckQuota(unsigned int ulStoreId, long long llStoreSize,
- eQuotaStatus *lpQuotaStatus) const
- {
- ECRESULT er;
- unsigned int ulOwnerId = 0;
- unsigned int ulStoreType = 0;
- er = m_lpSession->GetSessionManager()->GetCacheManager()->GetStoreAndType(ulStoreId, NULL, NULL, &ulStoreType);
- if (er != erSuccess)
- return er;
-
- if(ulStoreType != ECSTORE_TYPE_PRIVATE) {
- *lpQuotaStatus = QUOTA_OK;
- return er; // all is good, no quota on non-private stores.
- }
- // Get the store owner
- er = GetStoreOwner(ulStoreId, &ulOwnerId);
- if(er != erSuccess)
- return er;
- return CheckUserQuota(ulOwnerId, llStoreSize, lpQuotaStatus);
- }
- /**
- * Gets the quota status value (ok, warn, soft, hard) for a given
- * store and store size
- *
- * @param[in] ulUserId user to check quota for
- * @param[in] llStoreSize current store size of the store
- * @param[out] lpQuotaStatus quota status
- *
- * @return Kopano error code
- */
- ECRESULT ECSecurity::CheckUserQuota(unsigned int ulUserId,
- long long llStoreSize, eQuotaStatus *lpQuotaStatus) const
- {
- ECRESULT er;
- quotadetails_t quotadetails;
- if (ulUserId == KOPANO_UID_EVERYONE) {
- /* Publicly owned stores are never over quota.
- * But do publicly owned stores actually exist since the owner is either a user or company */
- *lpQuotaStatus = QUOTA_OK;
- return erSuccess;
- }
- er = GetUserQuota(ulUserId, false, "adetails);
- if (er != erSuccess)
- return er;
- // check the options
- if(quotadetails.llHardSize > 0 && llStoreSize >= quotadetails.llHardSize)
- *lpQuotaStatus = QUOTA_HARDLIMIT;
- else if(quotadetails.llSoftSize > 0 && llStoreSize >= quotadetails.llSoftSize)
- *lpQuotaStatus = QUOTA_SOFTLIMIT;
- else if(quotadetails.llWarnSize > 0 && llStoreSize >= quotadetails.llWarnSize)
- *lpQuotaStatus = QUOTA_WARN;
- else
- *lpQuotaStatus = QUOTA_OK;
- return erSuccess;
- }
- /**
- * Get the quota details of a user
- *
- * @param[in] ulUserId internal user id
- * @param[out] lpDetails quota details
- *
- * @return Kopano error code
- */
- ECRESULT ECSecurity::GetUserQuota(unsigned int ulUserId, bool bGetUserDefault,
- quotadetails_t *lpDetails) const
- {
- ECRESULT er = erSuccess;
- const char *lpszWarnQuota = NULL;
- const char *lpszSoftQuota = NULL;
- const char *lpszHardQuota = NULL;
- quotadetails_t quotadetails;
- objectid_t sExternId;
- unsigned int ulCompanyId;
- if (!lpDetails) {
- er = KCERR_INVALID_PARAMETER;
- goto exit;
- }
- er = m_lpSession->GetUserManagement()->GetExternalId(ulUserId, &sExternId, &ulCompanyId);
- if (er != erSuccess)
- goto exit;
- assert(!bGetUserDefault || sExternId.objclass == CONTAINER_COMPANY);
- /* Not all objectclasses support quota */
- if ((sExternId.objclass == NONACTIVE_CONTACT) ||
- (OBJECTCLASS_TYPE(sExternId.objclass) == OBJECTTYPE_DISTLIST) ||
- (sExternId.objclass == CONTAINER_ADDRESSLIST))
- goto exit;
- er = m_lpSession->GetUserManagement()->GetQuotaDetailsAndSync(ulUserId, "adetails, bGetUserDefault);
- if (er != erSuccess)
- goto exit;
- /* When the default quota boolean is set, we need to look at the next quota level */
- if (!quotadetails.bUseDefaultQuota)
- goto exit;
- /* Request default quota values from company level if enabled */
- if ((OBJECTCLASS_TYPE(sExternId.objclass) == OBJECTTYPE_MAILUSER) && ulCompanyId) {
- er = m_lpSession->GetUserManagement()->GetQuotaDetailsAndSync(ulCompanyId, "adetails, true);
- if (er == erSuccess && !quotadetails.bUseDefaultQuota)
- goto exit; /* On failure, or when we should use the default, we're done */
- er = erSuccess;
- }
- /* No information from company, the last level we can check is the configuration file */
- if (OBJECTCLASS_TYPE(sExternId.objclass) == OBJECTTYPE_MAILUSER) {
- lpszWarnQuota = m_lpSession->GetSessionManager()->GetConfig()->GetSetting("quota_warn");
- lpszSoftQuota = m_lpSession->GetSessionManager()->GetConfig()->GetSetting("quota_soft");
- lpszHardQuota = m_lpSession->GetSessionManager()->GetConfig()->GetSetting("quota_hard");
- } else if (sExternId.objclass == CONTAINER_COMPANY) {
- lpszWarnQuota = m_lpSession->GetSessionManager()->GetConfig()->GetSetting("companyquota_warn");
- }
- quotadetails.bUseDefaultQuota = true;
- quotadetails.bIsUserDefaultQuota = false;
- if (lpszWarnQuota)
- quotadetails.llWarnSize = atoll(lpszWarnQuota) * 1024 * 1024;
- if (lpszSoftQuota)
- quotadetails.llSoftSize = atoll(lpszSoftQuota) * 1024 * 1024;
- if (lpszHardQuota)
- quotadetails.llHardSize = atoll(lpszHardQuota) * 1024 * 1024;
- exit:
- if (er == erSuccess)
- *lpDetails = std::move(quotadetails);
- return er;
- }
- /**
- * Get the username of the current user context
- *
- * @param[out] lpstrUsername login name of the user
- *
- * @return always erSuccess
- */
- ECRESULT ECSecurity::GetUsername(std::string *lpstrUsername) const
- {
- if (m_ulUserID)
- *lpstrUsername = m_details.GetPropString(OB_PROP_S_LOGIN);
- else
- *lpstrUsername = KOPANO_SYSTEM_USER;
- return erSuccess;
- }
- /**
- * Get the username of the user impersonating the current user
- *
- * @param[out] lpstrImpersonator login name of the impersonator
- *
- * @return always erSuccess
- */
- ECRESULT ECSecurity::GetImpersonator(std::string *lpstrImpersonator) const
- {
- ECRESULT er = erSuccess;
- if (m_ulImpersonatorID == EC_NO_IMPERSONATOR)
- er = KCERR_NOT_FOUND;
- else if (m_ulImpersonatorID)
- *lpstrImpersonator = m_impersonatorDetails.GetPropString(OB_PROP_S_LOGIN);
- else
- *lpstrImpersonator = KOPANO_SYSTEM_USER;
- return er;
- }
- /**
- * Get memory size of this object
- *
- * @return Object size in bytes
- */
- size_t ECSecurity::GetObjectSize(void) const
- {
- size_t ulSize = sizeof(*this);
- ulSize += m_details.GetObjectSize();
- ulSize += m_impersonatorDetails.GetObjectSize();
-
- if (m_lpGroups) {
- size_t ulItems = 0;
- for (const auto &i : *m_lpGroups) {
- ++ulItems;
- ulSize += i.GetObjectSize();
- }
- ulSize += MEMORY_USAGE_LIST(ulItems, list<localobjectdetails_t>);
- }
- if (m_lpViewCompanies)
- {
- size_t ulItems = 0;
- for (const auto &i : *m_lpViewCompanies) {
- ++ulItems;
- ulSize += i.GetObjectSize();
- }
- ulSize += MEMORY_USAGE_LIST(ulItems, list<localobjectdetails_t>);
- }
- if (m_lpAdminCompanies)
- {
- size_t ulItems = 0;
- for (const auto &i : *m_lpAdminCompanies) {
- ++ulItems;
- ulSize += i.GetObjectSize();
- }
- ulSize += MEMORY_USAGE_LIST(ulItems, list<localobjectdetails_t>);
- }
- return ulSize;
- }
- } /* namespace */
|