Add system database - managed by service (uid<5000) users, accessible by priviledged... 97/39297/4
authorMaciej J. Karpiuk <m.karpiuk2@samsung.com>
Thu, 16 Apr 2015 06:55:58 +0000 (08:55 +0200)
committerBartlomiej Grzelewski <b.grzelewski@samsung.com>
Fri, 15 May 2015 10:14:03 +0000 (03:14 -0700)
Change-Id: I08b6c4718ff4219bebfd85ab942cfe22570ed0a5

src/include/ckmc/ckmc-type.h
src/manager/client-capi/ckmc-type.cpp
src/manager/common/protocols.cpp
src/manager/common/protocols.h
src/manager/main/generic-socket-manager.h
src/manager/main/socket-manager.cpp
src/manager/service/access-control.cpp
src/manager/service/access-control.h
src/manager/service/ckm-logic.cpp
src/manager/service/ckm-logic.h
src/manager/service/ckm-service.cpp

index 197a02c..fbb30ab 100644 (file)
@@ -45,6 +45,15 @@ extern "C" {
 KEY_MANAGER_CAPI extern char const * const ckmc_label_name_separator;
 
 /**
+ * shared database label - user may be given permission to access shared
+ * database items. In such case, the alias should contain shared database
+ * label.
+ * @see ckmc_label_name_separator
+ * @see key-manager_doc.h
+ */
+KEY_MANAGER_CAPI extern char const * const ckmc_label_shared_owner;
+
+/**
  * @brief Enumeration for key types of key manager.
  * @since_tizen 2.3
  */
index 3553b02..7048333 100644 (file)
@@ -35,7 +35,8 @@
 #include <openssl/pem.h>
 
 
-const char * const ckmc_label_name_separator = CKM::LABEL_NAME_SEPARATOR;
+const char * const ckmc_label_name_separator    = CKM::LABEL_NAME_SEPARATOR;
+const char * const ckmc_label_shared_owner      = CKM::LABEL_SYSTEM_DB;
 
 
 int _ckmc_load_cert_from_x509(X509 *xCert, ckmc_cert_s **cert);
index 128f28f..92c24b0 100644 (file)
@@ -34,6 +34,7 @@ char const * const SERVICE_SOCKET_CKM_CONTROL = "/tmp/.central-key-manager-api-c
 char const * const SERVICE_SOCKET_CKM_STORAGE = "/tmp/.central-key-manager-api-storage.sock";
 char const * const SERVICE_SOCKET_OCSP = "/tmp/.central-key-manager-api-ocsp.sock";
 char const * const LABEL_NAME_SEPARATOR = " ";
+char const * const LABEL_SYSTEM_DB = "/";
 
 
 PKCS12Serializable::PKCS12Serializable() {}
index 3739f12..607192e 100644 (file)
@@ -240,6 +240,7 @@ private:
 
 // (client side) Alias = (service side) Label::Name
 COMMON_API extern char const * const LABEL_NAME_SEPARATOR;
+COMMON_API extern char const * const LABEL_SYSTEM_DB;
 typedef std::string Name;
 typedef std::vector<std::pair<Label, Name> > LabelNameVector;
 
index 5d1521e..5018c4a 100644 (file)
@@ -45,7 +45,10 @@ namespace CKM {
 typedef int InterfaceID;
 
 struct Credentials {
-    uid_t uid;
+    Credentials() : clientUid(0) {}
+    Credentials(uid_t socketUid, const Label & socketLabel)
+        : clientUid(socketUid), smackLabel(socketLabel) {}
+    uid_t clientUid;
     Label smackLabel;
 };
 
index 405add5..bde932f 100644 (file)
@@ -52,7 +52,6 @@ namespace {
 const time_t SOCKET_TIMEOUT = 1000;
 
 int getCredentialsFromSocket(int sock, CKM::Credentials &cred) {
-    CKM::Credentials credentials;
     std::vector<char> result(1);
     socklen_t length = 1;
     ucred peerCred;
@@ -79,8 +78,7 @@ int getCredentialsFromSocket(int sock, CKM::Credentials &cred) {
     }
 
     result.push_back('\0');
-    cred.smackLabel = result.data();
-    cred.uid = peerCred.uid;
+    cred = CKM::Credentials(peerCred.uid, result.data());
     return 0;
 }
 
index a1b0755..decd92c 100644 (file)
@@ -37,6 +37,7 @@ namespace {
 const char* const MDPP_MODE_ENFORCING = "Enforcing";
 const char* const MDPP_MODE_ENABLED = "Enabled";
 const char* const MDPP_MODE_DISABLED = "Disabled";
+const uid_t       SYSTEM_SVC_MAX_UID = (5000 - 1);
 } // anonymous namespace
 
 namespace CKM {
@@ -83,26 +84,42 @@ bool AccessControl::isCCMode() const
     return m_ccMode;
 }
 
+bool AccessControl::isSystemService(const uid_t uid) const
+{
+    return uid <= SYSTEM_SVC_MAX_UID;
+}
+
+bool AccessControl::isSystemService(const CKM::Credentials &cred) const
+{
+    return isSystemService(cred.clientUid);
+}
+
+
 int AccessControl::canSave(
-        const Label & ownerLabel,
-        const Label & accessorLabel) const
+        const CKM::Credentials &accessorCred,
+        const Label & ownerLabel) const
 {
-    if(ownerLabel != accessorLabel)
+    if(isSystemService(accessorCred))
+        return CKM_API_SUCCESS;
+    if(ownerLabel != accessorCred.smackLabel)
         return CKM_API_ERROR_ACCESS_DENIED;
 
     return CKM_API_SUCCESS;
 }
 
 int AccessControl::canModify(
-        const Label & ownerLabel,
-        const Label & accessorLabel) const
+        const CKM::Credentials &accessorCred,
+        const Label & ownerLabel) const
 {
-    return canSave(ownerLabel, accessorLabel);
+    return canSave(accessorCred, ownerLabel);
 }
 
 int AccessControl::canRead(
+        const CKM::Credentials &accessorCred,
         const PermissionForLabel & permissionLabel) const
 {
+    if(isSystemService(accessorCred))
+        return CKM_API_SUCCESS;
     if(permissionLabel & Permission::READ)
         return CKM_API_SUCCESS;
 
@@ -110,11 +127,12 @@ int AccessControl::canRead(
 }
 
 int AccessControl::canExport(
+        const CKM::Credentials &accessorCred,
         const DB::Row & row,
         const PermissionForLabel & permissionLabel) const
 {
     int ec;
-    if(CKM_API_SUCCESS != (ec = canRead(permissionLabel)))
+    if(CKM_API_SUCCESS != (ec = canRead(accessorCred, permissionLabel)))
         return ec;
 
     // check if can export
@@ -129,8 +147,11 @@ int AccessControl::canExport(
 }
 
 int AccessControl::canDelete(
+        const CKM::Credentials &accessorCred,
         const PermissionForLabel & permissionLabel) const
 {
+    if(isSystemService(accessorCred))
+        return CKM_API_SUCCESS;
     if(permissionLabel & Permission::REMOVE)
         return CKM_API_SUCCESS;
     if(permissionLabel & Permission::READ)
index 63adea3..32bfb66 100644 (file)
@@ -27,6 +27,7 @@
 #include <protocols.h>
 #include <db-row.h>
 #include <permission.h>
+#include <generic-socket-manager.h>
 
 namespace CKM {
 
@@ -34,37 +35,46 @@ class AccessControl
 {
 public:
     /**
-     * check if given data can be saved under given label by accessorLabel
+     * return true if client uid is from the system services uid space
+     */
+    bool isSystemService(const uid_t uid) const;
+    bool isSystemService(const CKM::Credentials &cred) const;
+
+    /**
+     * check if given data can be saved by current accessor
      * @return CKM_API_SUCCESS if access is allowed, otherwise negative error code
      */
-    int canSave(const Label & ownerLabel,
-                const Label & accessorLabel) const;
+    int canSave(const CKM::Credentials &accessorCred,
+                const Label & ownerLabel) const;
 
     /**
-     * check if given label can be modified by accessorLabel
+     * check if given label can be modified by accessor
      * @return CKM_API_SUCCESS if access is allowed, otherwise negative error code
      */
-    int canModify(const Label & ownerLabel,
-                  const Label & accessorLabel) const;
+    int canModify(const CKM::Credentials &accessorCred,
+                  const Label & ownerLabel) const;
 
     /**
      * check if given row can be read (for internal use)
      * @return CKM_API_SUCCESS if access is allowed, otherwise negative error code
      */
-    int canRead(const PermissionForLabel & permissionLabel) const;
+    int canRead(const CKM::Credentials &accessorCred,
+                const PermissionForLabel & permissionLabel) const;
 
     /**
      * check if given row can be exported (data provided to the client)
      * @return CKM_API_SUCCESS if access is allowed, otherwise negative error code
      */
-    int canExport(const DB::Row & row,
-                const PermissionForLabel & permissionLabel) const;
+    int canExport(const CKM::Credentials &accessorCred,
+                  const DB::Row & row,
+                  const PermissionForLabel & permissionLabel) const;
 
     /**
      * check if given accessor can delete ownerLabel's items.
      * @return CKM_API_SUCCESS if access is allowed, otherwise negative error code
      */
-    int canDelete(const PermissionForLabel & permissionLabel) const;
+    int canDelete(const CKM::Credentials &accessorCred,
+                  const PermissionForLabel & permissionLabel) const;
 
     void updateCCMode();
     bool isCCMode() const;
index e8e7f0c..89fa59c 100644 (file)
@@ -33,7 +33,9 @@
 #include <sw-backend/crypto-service.h>
 
 namespace {
-const char * const CERT_SYSTEM_DIR = "/etc/ssl/certs";
+const char * const CERT_SYSTEM_DIR  = "/etc/ssl/certs";
+const uid_t        SYSTEM_DB_UID    = 0;
+const char * const SYSTEM_DB_PASSWD = "cAtRugU7";
 
 bool isLabelValid(const CKM::Label &label) {
     // TODO: copy code from libprivilege control (for check smack label)
@@ -47,7 +49,6 @@ bool isNameValid(const CKM::Name &name) {
         return false;
     return true;
 }
-
 } // anonymous namespace
 
 namespace CKM {
@@ -83,27 +84,32 @@ void CKMLogic::saveDKEKFile(uid_t user, const Password &password) {
     fs.saveDKEK(handle.keyProvider.getWrappedDomainKEK(password));
 }
 
-RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password) {
-    int retCode = CKM_API_SUCCESS;
+int CKMLogic::unlockDatabase(uid_t user, const Password & password)
+{
+    if (0<m_userDataMap.count(user) && m_userDataMap[user].keyProvider.isInitialized())
+        return CKM_API_SUCCESS;
 
-    try {
-        if (0 == m_userDataMap.count(user) || !(m_userDataMap[user].keyProvider.isInitialized())) {
-            auto &handle = m_userDataMap[user];
-            FileSystem fs(user);
+    int retCode = CKM_API_SUCCESS;
+    try
+    {
+        auto &handle = m_userDataMap[user];
 
-            loadDKEKFile(user, password);
+        FileSystem fs(user);
+        loadDKEKFile(user, password);
 
-            auto wrappedDatabaseDEK = fs.getDBDEK();
+        auto wrappedDatabaseDEK = fs.getDBDEK();
+        if (wrappedDatabaseDEK.empty()) {
+            wrappedDatabaseDEK = handle.keyProvider.generateDEK(std::to_string(user));
+            fs.saveDBDEK(wrappedDatabaseDEK);
+        }
 
-            if (wrappedDatabaseDEK.empty()) {
-                wrappedDatabaseDEK = handle.keyProvider.generateDEK(std::to_string(user));
-                fs.saveDBDEK(wrappedDatabaseDEK);
-            }
+        RawBuffer key = handle.keyProvider.getPureDEK(wrappedDatabaseDEK);
 
-            RawBuffer key = handle.keyProvider.getPureDEK(wrappedDatabaseDEK);
-            handle.database = DB::Crypto(fs.getDBPath(), key);
-            handle.crypto = CryptoLogic();
+        handle.database = DB::Crypto(fs.getDBPath(), key);
+        handle.crypto = CryptoLogic();
 
+        if ( !m_accessControl.isSystemService(user) )
+        {
             // remove data of removed apps during locked state
             AppLabelVector removedApps = fs.clearRemovedsApps();
             for(auto& appSmackLabel : removedApps) {
@@ -127,10 +133,50 @@ RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password) {
         retCode = CKM_API_ERROR_SERVER_ERROR;
     }
 
-    if(retCode != CKM_API_SUCCESS) {
-        // When not successful, UserData in m_userDataMap should be erased.
-        // Because other operations make decision based on the existence of UserData in m_userDataMap.
+    if (CKM_API_SUCCESS != retCode)
         m_userDataMap.erase(user);
+
+    return retCode;
+}
+
+int CKMLogic::unlockSystemDB()
+{
+    return unlockDatabase(SYSTEM_DB_UID, SYSTEM_DB_PASSWD);
+}
+
+UserData & CKMLogic::selectDatabase(const Credentials &cred, const Label &incoming_label)
+{
+    // if user trying to access system service - check:
+    //    * if user database is unlocked [mandatory]
+    //    * if not - proceed with regular user database
+    //    * if explicit system database label given -> switch to system DB
+    if ( !m_accessControl.isSystemService(cred) )
+    {
+        if (0 == m_userDataMap.count(cred.clientUid))
+            ThrowMsg(Exception::DatabaseLocked, "database with UID: " << cred.clientUid << " locked");
+
+        if (0 != incoming_label.compare(LABEL_SYSTEM_DB))
+            return m_userDataMap[cred.clientUid];
+    }
+
+    // system database selected, modify the label
+    if (CKM_API_SUCCESS != unlockSystemDB() )
+        ThrowMsg(Exception::DatabaseLocked, "can not unlock system database");
+    return m_userDataMap[SYSTEM_DB_UID];
+}
+
+RawBuffer CKMLogic::unlockUserKey(uid_t user, const Password &password)
+{
+    int retCode = CKM_API_SUCCESS;
+
+    if( !m_accessControl.isSystemService(user) )
+    {
+        retCode = unlockDatabase(user, password);
+    }
+    else
+    {
+        // do not allow lock/unlock operations for system users
+        retCode = CKM_API_ERROR_INPUT_PARAM;
     }
 
     return MessageBuffer::Serialize(retCode).Pop();
@@ -141,10 +187,18 @@ RawBuffer CKMLogic::updateCCMode() {
     return MessageBuffer::Serialize(CKM_API_SUCCESS).Pop();
 }
 
-RawBuffer CKMLogic::lockUserKey(uid_t user) {
+RawBuffer CKMLogic::lockUserKey(uid_t user)
+{
     int retCode = CKM_API_SUCCESS;
-    // TODO try catch for all errors that should be supported by error code
-    m_userDataMap.erase(user);
+    if( !m_accessControl.isSystemService(user) )
+    {
+        m_userDataMap.erase(user);
+    }
+    else
+    {
+        // do not allow lock/unlock operations for system users
+        retCode = CKM_API_ERROR_INPUT_PARAM;
+    }
 
     return MessageBuffer::Serialize(retCode).Pop();
 
@@ -152,7 +206,10 @@ RawBuffer CKMLogic::lockUserKey(uid_t user) {
 
 RawBuffer CKMLogic::removeUserData(uid_t user) {
     int retCode = CKM_API_SUCCESS;
-    // TODO try catch for all errors that should be supported by error code
+
+    if (m_accessControl.isSystemService(user))
+        user = SYSTEM_DB_UID;
+
     m_userDataMap.erase(user);
 
     FileSystem fs(user);
@@ -161,15 +218,29 @@ RawBuffer CKMLogic::removeUserData(uid_t user) {
     return MessageBuffer::Serialize(retCode).Pop();
 }
 
+int CKMLogic::changeUserPasswordHelper(uid_t user,
+                                       const Password &oldPassword,
+                                       const Password &newPassword)
+{
+    // do not allow to change system database password
+    if( m_accessControl.isSystemService(user) )
+        return CKM_API_ERROR_INPUT_PARAM;
+
+    loadDKEKFile(user, oldPassword);
+    saveDKEKFile(user, newPassword);
+
+    return CKM_API_SUCCESS;
+}
+
 RawBuffer CKMLogic::changeUserPassword(
     uid_t user,
     const Password &oldPassword,
     const Password &newPassword)
 {
     int retCode = CKM_API_SUCCESS;
-    try {
-        loadDKEKFile(user, oldPassword);
-        saveDKEKFile(user, newPassword);
+    try
+    {
+        retCode = changeUserPasswordHelper(user, oldPassword, newPassword);
     } catch (const KeyProvider::Exception::PassWordError &e) {
         LogError("Incorrect Password " << e.GetMessage());
         retCode = CKM_API_ERROR_AUTHENTICATION_FAILED;
@@ -187,22 +258,36 @@ RawBuffer CKMLogic::changeUserPassword(
     return MessageBuffer::Serialize(retCode).Pop();
 }
 
-RawBuffer CKMLogic::resetUserPassword(
+int CKMLogic::resetUserPasswordHelper(
     uid_t user,
     const Password &newPassword)
 {
+    // do not allow to reset system database password
+    if( m_accessControl.isSystemService(user) )
+        return CKM_API_ERROR_INPUT_PARAM;
+
     int retCode = CKM_API_SUCCESS;
+    if (0 == m_userDataMap.count(user))
+    {
+        // Check if key exists. If exists we must return error
+        FileSystem fs(user);
+        auto wrappedDKEKMain = fs.getDKEK();
+        if (!wrappedDKEKMain.empty())
+            retCode = CKM_API_ERROR_BAD_REQUEST;
+    } else {
+        saveDKEKFile(user, newPassword);
+    }
 
+    return retCode;
+}
+
+RawBuffer CKMLogic::resetUserPassword(
+    uid_t user,
+    const Password &newPassword)
+{
+    int retCode = CKM_API_SUCCESS;
     try {
-        if (0 == m_userDataMap.count(user)) {
-            // Check if key exists. If exists we must return error
-            FileSystem fs(user);
-            auto wrappedDKEKMain = fs.getDKEK();
-            if (!wrappedDKEKMain.empty())
-                retCode = CKM_API_ERROR_BAD_REQUEST;
-        } else {
-            saveDKEKFile(user, newPassword);
-        }
+        retCode = resetUserPasswordHelper(user, newPassword);
     } catch (const FileSystem::Exception::Base &e) {
         LogError("Error in FileSystem " << e.GetMessage());
         retCode = CKM_API_ERROR_FILE_SYSTEM;
@@ -264,33 +349,33 @@ int CKMLogic::checkSaveConditions(
     }
 
     // check if allowed to save using ownerLabel
-    int access_ec = m_accessControl.canSave(ownerLabel, cred.smackLabel);
-    if(access_ec != CKM_API_SUCCESS)
+    int access_ec = m_accessControl.canSave(cred, ownerLabel);
+    if( access_ec != CKM_API_SUCCESS)
     {
         LogWarning("label " << cred.smackLabel << " can not save rows using label " << ownerLabel);
         return access_ec;
     }
 
     // check if not a duplicate
-    if( handler.database.isNameLabelPresent(name, cred.smackLabel) )
+    if( handler.database.isNameLabelPresent(name, ownerLabel))
         return CKM_API_ERROR_DB_ALIAS_EXISTS;
 
     // encryption section
-    if (!handler.crypto.haveKey(cred.smackLabel)) {
+    if (!handler.crypto.haveKey(ownerLabel))
+    {
         RawBuffer got_key;
-        auto key_optional = handler.database.getKey(cred.smackLabel);
+        auto key_optional = handler.database.getKey(ownerLabel);
         if(!key_optional) {
-            LogDebug("No Key in database found. Generating new one for label: "
-                    << cred.smackLabel);
-            got_key = handler.keyProvider.generateDEK(cred.smackLabel);
-            handler.database.saveKey(cred.smackLabel, got_key);
+            LogDebug("No Key in database found. Generating new one for label: " << ownerLabel);
+            got_key = handler.keyProvider.generateDEK(ownerLabel);
+            handler.database.saveKey(ownerLabel, got_key);
         } else {
             LogDebug("Key from DB");
             got_key = *key_optional;
         }
 
         got_key = handler.keyProvider.getPureDEK(got_key);
-        handler.crypto.pushKey(cred.smackLabel, got_key);
+        handler.crypto.pushKey(ownerLabel, got_key);
     }
 
     return CKM_API_SUCCESS;
@@ -350,37 +435,36 @@ RawBuffer CKMLogic::saveData(
     DataType dataType,
     const PolicySerializable &policy)
 {
-    int retCode;
-    if (0 == m_userDataMap.count(cred.uid))
-        retCode = CKM_API_ERROR_DB_LOCKED;
-    else
-    {
-        try {
-            // check if data is correct
-            retCode = verifyBinaryData(dataType, data);
-            if(retCode == CKM_API_SUCCESS)
-            {
-                retCode = saveDataHelper(cred, name, label, dataType, data, policy);
-            }
-        } catch (const KeyProvider::Exception::Base &e) {
-            LogError("KeyProvider failed with message: " << e.GetMessage());
-            retCode = CKM_API_ERROR_SERVER_ERROR;
-        } catch (const CryptoLogic::Exception::Base &e) {
-            LogError("CryptoLogic failed with message: " << e.GetMessage());
-            retCode = CKM_API_ERROR_SERVER_ERROR;
-        } catch (const DB::Crypto::Exception::InternalError &e) {
-            LogError("DB::Crypto failed with message: " << e.GetMessage());
-            retCode = CKM_API_ERROR_DB_ERROR;
-        } catch (const DB::Crypto::Exception::TransactionError &e) {
-            LogError("DB::Crypto transaction failed with message " << e.GetMessage());
-            retCode = CKM_API_ERROR_DB_ERROR;
-        } catch (const FileSystem::Exception::Base &e) {
-            LogError("Error in FileSystem " << e.GetMessage());
-            retCode = CKM_API_ERROR_FILE_SYSTEM;
-        } catch (const CKM::Exception &e) {
-            LogError("CKM::Exception: " << e.GetMessage());
-            retCode = CKM_API_ERROR_SERVER_ERROR;
+    int retCode = CKM_API_ERROR_UNKNOWN;
+
+    try {
+        // check if data is correct
+        retCode = verifyBinaryData(dataType, data);
+        if(retCode == CKM_API_SUCCESS)
+        {
+            retCode = saveDataHelper(cred, name, label, dataType, data, policy);
         }
+    } catch (const KeyProvider::Exception::Base &e) {
+        LogError("KeyProvider failed with message: " << e.GetMessage());
+        retCode = CKM_API_ERROR_SERVER_ERROR;
+    } catch (const CryptoLogic::Exception::Base &e) {
+        LogError("CryptoLogic failed with message: " << e.GetMessage());
+        retCode = CKM_API_ERROR_SERVER_ERROR;
+    } catch (const DB::Crypto::Exception::InternalError &e) {
+        LogError("DB::Crypto failed with message: " << e.GetMessage());
+        retCode = CKM_API_ERROR_DB_ERROR;
+    } catch (const DB::Crypto::Exception::TransactionError &e) {
+        LogError("DB::Crypto transaction failed with message " << e.GetMessage());
+        retCode = CKM_API_ERROR_DB_ERROR;
+    } catch (const FileSystem::Exception::Base &e) {
+        LogError("Error in FileSystem " << e.GetMessage());
+        retCode = CKM_API_ERROR_FILE_SYSTEM;
+    } catch (const CKMLogic::Exception::DatabaseLocked &e) {
+        LogError("Error " << e.GetMessage());
+        retCode = CKM_API_ERROR_DB_LOCKED;
+    } catch (const CKM::Exception &e) {
+        LogError("CKM::Exception: " << e.GetMessage());
+        retCode = CKM_API_ERROR_SERVER_ERROR;
     }
 
     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::SAVE),
@@ -444,29 +528,24 @@ RawBuffer CKMLogic::savePKCS12(
     const PolicySerializable &keyPolicy,
     const PolicySerializable &certPolicy)
 {
-    int retCode;
-    if (0 == m_userDataMap.count(cred.uid))
-        retCode = CKM_API_ERROR_DB_LOCKED;
-    else
-    {
-        try {
-            retCode = saveDataHelper(cred, name, label, pkcs, keyPolicy, certPolicy);
-        } catch (const KeyProvider::Exception::Base &e) {
-            LogError("KeyProvider failed with message: " << e.GetMessage());
-            retCode = CKM_API_ERROR_SERVER_ERROR;
-        } catch (const CryptoLogic::Exception::Base &e) {
-            LogError("CryptoLogic failed with message: " << e.GetMessage());
-            retCode = CKM_API_ERROR_SERVER_ERROR;
-        } catch (const DB::Crypto::Exception::InternalError &e) {
-            LogError("DB::Crypto failed with message: " << e.GetMessage());
-            retCode = CKM_API_ERROR_DB_ERROR;
-        } catch (const DB::Crypto::Exception::TransactionError &e) {
-            LogError("DB::Crypto transaction failed with message " << e.GetMessage());
-            retCode = CKM_API_ERROR_DB_ERROR;
-        } catch (const CKM::Exception &e) {
-            LogError("CKM::Exception: " << e.GetMessage());
-            retCode = CKM_API_ERROR_SERVER_ERROR;
-        }
+    int retCode = CKM_API_ERROR_UNKNOWN;
+    try {
+        retCode = saveDataHelper(cred, name, label, pkcs, keyPolicy, certPolicy);
+    } catch (const KeyProvider::Exception::Base &e) {
+        LogError("KeyProvider failed with message: " << e.GetMessage());
+        retCode = CKM_API_ERROR_SERVER_ERROR;
+    } catch (const CryptoLogic::Exception::Base &e) {
+        LogError("CryptoLogic failed with message: " << e.GetMessage());
+        retCode = CKM_API_ERROR_SERVER_ERROR;
+    } catch (const DB::Crypto::Exception::InternalError &e) {
+        LogError("DB::Crypto failed with message: " << e.GetMessage());
+        retCode = CKM_API_ERROR_DB_ERROR;
+    } catch (const DB::Crypto::Exception::TransactionError &e) {
+        LogError("DB::Crypto transaction failed with message " << e.GetMessage());
+        retCode = CKM_API_ERROR_DB_ERROR;
+    } catch (const CKM::Exception &e) {
+        LogError("CKM::Exception: " << e.GetMessage());
+        retCode = CKM_API_ERROR_SERVER_ERROR;
     }
 
     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::SAVE_PKCS12),
@@ -479,30 +558,31 @@ RawBuffer CKMLogic::savePKCS12(
 int CKMLogic::removeDataHelper(
         const Credentials &cred,
         const Name &name,
-        const Label &ownerLabel)
+        const Label &label)
 {
-    if (0 == m_userDataMap.count(cred.uid))
-        return CKM_API_ERROR_DB_LOCKED;
+    auto &handler = selectDatabase(cred, label);
 
+    // use client label if not explicitly provided
+    const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
     if (!isNameValid(name) || !isLabelValid(ownerLabel)) {
         LogError("Invalid label or name format");
         return CKM_API_ERROR_INPUT_PARAM;
     }
 
-    auto &database = m_userDataMap[cred.uid].database;
-    DB::Crypto::Transaction transaction(&database);
+    DB::Crypto::Transaction transaction(&handler.database);
 
     // read and check permissions
     PermissionMaskOptional permissionRowOpt =
-            database.getPermissionRow(name, ownerLabel, cred.smackLabel);
-    int access_ec = m_accessControl.canDelete(PermissionForLabel(cred.smackLabel, permissionRowOpt));
-    if(access_ec != CKM_API_SUCCESS)
+            handler.database.getPermissionRow(name, ownerLabel, cred.smackLabel);
+    int retCode = m_accessControl.canDelete(cred,
+                        PermissionForLabel(cred.smackLabel, permissionRowOpt));
+    if(retCode != CKM_API_SUCCESS)
     {
-        LogWarning("access control check result: " << access_ec);
-        return access_ec;
+        LogWarning("access control check result: " << retCode);
+        return retCode;
     }
 
-    auto erased = database.deleteRow(name, ownerLabel);
+    auto erased = handler.database.deleteRow(name, ownerLabel);
     // check if the data existed or not
     if(erased)
         transaction.commit();
@@ -520,13 +600,19 @@ RawBuffer CKMLogic::removeData(
     const Name &name,
     const Label &label)
 {
-    int retCode;
-    Try {
-        // use client label if not explicitly provided
-        const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
+    int retCode = CKM_API_ERROR_UNKNOWN;
 
-        retCode = removeDataHelper(cred, name, ownerLabel);
-    } Catch (CKM::Exception) {
+    try
+    {
+        retCode = removeDataHelper(cred, name, label);
+    }
+    catch (const CKMLogic::Exception::DatabaseLocked &e)
+    {
+        LogError("Error " << e.GetMessage());
+        retCode = CKM_API_ERROR_DB_LOCKED;
+    }
+    catch (const CKM::Exception &)
+    {
         LogError("Error in deleting row!");
         retCode = CKM_API_ERROR_DB_ERROR;
     }
@@ -588,18 +674,18 @@ int CKMLogic::readMultiRow(const Name &name,
     {
         // read all key types
         database.getRows(name,
-                          ownerLabel,
-                          DataType::DB_CHAIN_FIRST,
-                          DataType::DB_CHAIN_LAST,
-                          output);
+                         ownerLabel,
+                         DataType::DB_CHAIN_FIRST,
+                         DataType::DB_CHAIN_LAST,
+                         output);
     }
     else
     {
         // read anything else
         database.getRows(name,
-                          ownerLabel,
-                          dataType,
-                          output);
+                         ownerLabel,
+                         dataType,
+                         output);
     }
 
     if(!output.size()) {
@@ -610,7 +696,8 @@ int CKMLogic::readMultiRow(const Name &name,
     return CKM_API_SUCCESS;
 }
 
-int CKMLogic::checkDataPermissionsHelper(const Name &name,
+int CKMLogic::checkDataPermissionsHelper(const Credentials &cred,
+                                         const Name &name,
                                          const Label &ownerLabel,
                                          const Label &accessorLabel,
                                          const DB::Row &row,
@@ -621,8 +708,8 @@ int CKMLogic::checkDataPermissionsHelper(const Name &name,
             database.getPermissionRow(name, ownerLabel, accessorLabel);
 
     if(exportFlag)
-        return m_accessControl.canExport(row, PermissionForLabel(accessorLabel, permissionRowOpt));
-    return m_accessControl.canRead(PermissionForLabel(accessorLabel, permissionRowOpt));
+        return m_accessControl.canExport(cred, row, PermissionForLabel(accessorLabel, permissionRowOpt));
+    return m_accessControl.canRead(cred, PermissionForLabel(accessorLabel, permissionRowOpt));
 }
 
 int CKMLogic::readDataHelper(
@@ -634,8 +721,7 @@ int CKMLogic::readDataHelper(
     const Password &password,
     DB::RowVector &rows)
 {
-    if (0 == m_userDataMap.count(cred.uid))
-        return CKM_API_ERROR_DB_LOCKED;
+    auto &handler = selectDatabase(cred, label);
 
     // use client label if not explicitly provided
     const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
@@ -643,21 +729,19 @@ int CKMLogic::readDataHelper(
     if (!isNameValid(name) || !isLabelValid(ownerLabel))
         return CKM_API_ERROR_INPUT_PARAM;
 
-    auto &handler = m_userDataMap[cred.uid];
-
     // read rows
     DB::Crypto::Transaction transaction(&handler.database);
-    int ec = readMultiRow(name, ownerLabel, dataType, handler.database, rows);
-    if(CKM_API_SUCCESS != ec)
-        return ec;
+    int retCode = readMultiRow(name, ownerLabel, dataType, handler.database, rows);
+    if(CKM_API_SUCCESS != retCode)
+        return retCode;
 
     // all read rows belong to the same owner
     DB::Row & firstRow = rows.at(0);
 
     // check access rights
-    ec = checkDataPermissionsHelper(name, ownerLabel, cred.smackLabel, firstRow, exportFlag, handler.database);
-    if(CKM_API_SUCCESS != ec)
-        return ec;
+    retCode = checkDataPermissionsHelper(cred, name, ownerLabel, cred.smackLabel, firstRow, exportFlag, handler.database);
+    if(CKM_API_SUCCESS != retCode)
+        return retCode;
 
     // decrypt row
     if (!handler.crypto.haveKey(firstRow.ownerLabel)) {
@@ -686,8 +770,7 @@ int CKMLogic::readDataHelper(
     const Password &password,
     DB::Row &row)
 {
-    if (0 == m_userDataMap.count(cred.uid))
-        return CKM_API_ERROR_DB_LOCKED;
+    auto &handler = selectDatabase(cred, label);
 
     // use client label if not explicitly provided
     const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
@@ -695,19 +778,16 @@ int CKMLogic::readDataHelper(
     if (!isNameValid(name) || !isLabelValid(ownerLabel))
         return CKM_API_ERROR_INPUT_PARAM;
 
-    auto &handler = m_userDataMap[cred.uid];
-
     // read row
     DB::Crypto::Transaction transaction(&handler.database);
-    int ec = readSingleRow(name, ownerLabel, dataType, handler.database, row);
-    if(CKM_API_SUCCESS != ec)
-        return ec;
-
+    int retCode = readSingleRow(name, ownerLabel, dataType, handler.database, row);
+    if(CKM_API_SUCCESS != retCode)
+        return retCode;
 
     // check access rights
-    ec = checkDataPermissionsHelper(name, ownerLabel, cred.smackLabel, row, exportFlag, handler.database);
-    if(CKM_API_SUCCESS != ec)
-        return ec;
+    retCode = checkDataPermissionsHelper(cred, name, ownerLabel, cred.smackLabel, row, exportFlag, handler.database);
+    if(CKM_API_SUCCESS != retCode)
+        return retCode;
 
     // decrypt row
     if (!handler.crypto.haveKey(row.ownerLabel)) {
@@ -751,6 +831,9 @@ RawBuffer CKMLogic::getData(
     } catch (const DB::Crypto::Exception::Base &e) {
         LogError("DB::Crypto failed with message: " << e.GetMessage());
         retCode = CKM_API_ERROR_DB_ERROR;
+    } catch (const CKMLogic::Exception::DatabaseLocked &e) {
+        LogError("Error " << e.GetMessage());
+        retCode = CKM_API_ERROR_DB_LOCKED;
     } catch (const CKM::Exception &e) {
         LogError("CKM::Exception: " << e.GetMessage());
         retCode = CKM_API_ERROR_SERVER_ERROR;
@@ -819,9 +902,9 @@ RawBuffer CKMLogic::getPKCS12(
         const Password &keyPassword,
         const Password &certPassword)
 {
-    int retCode;
-    PKCS12Serializable output;
+    int retCode = CKM_API_ERROR_UNKNOWN;
 
+    PKCS12Serializable output;
     try {
         KeyShPtr privKey;
         CertificateShPtr cert;
@@ -844,6 +927,9 @@ RawBuffer CKMLogic::getPKCS12(
     } catch (const DB::Crypto::Exception::Base &e) {
         LogError("DB::Crypto failed with message: " << e.GetMessage());
         retCode = CKM_API_ERROR_DB_ERROR;
+    } catch (const CKMLogic::Exception::DatabaseLocked &e) {
+        LogError("Error " << e.GetMessage());
+        retCode = CKM_API_ERROR_DB_LOCKED;
     } catch (const CKM::Exception &e) {
         LogError("CKM::Exception: " << e.GetMessage());
         retCode = CKM_API_ERROR_SERVER_ERROR;
@@ -856,39 +942,84 @@ RawBuffer CKMLogic::getPKCS12(
     return response.Pop();
 }
 
-RawBuffer CKMLogic::getDataList(
-    const Credentials &cred,
-    int commandId,
-    DataType dataType)
+int CKMLogic::getDataListHelper(const Credentials &cred,
+                                const DataType dataType,
+                                LabelNameVector &labelNameVector)
 {
-    int retCode = CKM_API_SUCCESS;
-    LabelNameVector labelNameVector;
-
-    if (0 < m_userDataMap.count(cred.uid)) {
-        auto &database = m_userDataMap[cred.uid].database;
+    int retCode = CKM_API_ERROR_DB_LOCKED;
+    if (0 < m_userDataMap.count(cred.clientUid))
+    {
+        auto &database = m_userDataMap[cred.clientUid].database;
 
         Try {
+            LabelNameVector tmpVector;
             if (dataType.isKey()) {
                 // list all key types
                 database.listNames(cred.smackLabel,
-                                   labelNameVector,
+                                   tmpVector,
                                    DataType::DB_KEY_FIRST,
                                    DataType::DB_KEY_LAST);
             } else {
                 // list anything else
                 database.listNames(cred.smackLabel,
-                                   labelNameVector,
+                                   tmpVector,
                                    dataType);
             }
+            labelNameVector.insert(labelNameVector.end(), tmpVector.begin(), tmpVector.end());
+            retCode = CKM_API_SUCCESS;
         }
         Catch (CKM::Exception) {
             LogError("Failed to get names");
             retCode = CKM_API_ERROR_DB_ERROR;
         }
-    } else {
-        retCode = CKM_API_ERROR_DB_LOCKED;
+    }
+    return retCode;
+}
+
+RawBuffer CKMLogic::getDataList(
+    const Credentials &cred,
+    int commandId,
+    DataType dataType)
+{
+    LabelNameVector systemVector;
+    LabelNameVector userVector;
+    LabelNameVector labelNameVector;
+
+    int retCode = unlockSystemDB();
+    if (CKM_API_SUCCESS == retCode)
+    {
+        // system database
+        if (m_accessControl.isSystemService(cred))
+        {
+            // lookup system DB
+            retCode = getDataListHelper(Credentials(SYSTEM_DB_UID,
+                                                    LABEL_SYSTEM_DB),
+                                        dataType,
+                                        systemVector);
+        }
+        else
+        {
+            // user - lookup system, then client DB
+            retCode = getDataListHelper(Credentials(SYSTEM_DB_UID,
+                                                    cred.smackLabel),
+                                        dataType,
+                                        systemVector);
+
+            // private database
+            if(retCode == CKM_API_SUCCESS)
+            {
+                retCode = getDataListHelper(cred,
+                                            dataType,
+                                            userVector);
+            }
+        }
     }
 
+    if(retCode == CKM_API_SUCCESS)
+    {
+        labelNameVector.insert(labelNameVector.end(), systemVector.begin(), systemVector.end());
+        labelNameVector.insert(labelNameVector.end(), userVector.begin(), userVector.end());
+    }
     auto response = MessageBuffer::Serialize(static_cast<int>(LogicCommand::GET_LIST),
                                              commandId,
                                              retCode,
@@ -905,10 +1036,12 @@ int CKMLogic::saveDataHelper(
     const RawBuffer &data,
     const PolicySerializable &policy)
 {
-    auto &handler = m_userDataMap[cred.uid];
+    auto &handler = selectDatabase(cred, label);
 
     // use client label if not explicitly provided
     const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
+    if( m_accessControl.isSystemService(cred) && ownerLabel.compare(LABEL_SYSTEM_DB)!=0)
+        return CKM_API_ERROR_INPUT_PARAM;
 
     // check if save is possible
     DB::Crypto::Transaction transaction(&handler.database);
@@ -932,10 +1065,12 @@ int CKMLogic::saveDataHelper(
     const PolicySerializable &keyPolicy,
     const PolicySerializable &certPolicy)
 {
-    auto &handler = m_userDataMap[cred.uid];
+    auto &handler = selectDatabase(cred, label);
 
     // use client label if not explicitly provided
     const Label &ownerLabel = label.empty() ? cred.smackLabel : label;
+    if( m_accessControl.isSystemService(cred) && ownerLabel.compare(LABEL_SYSTEM_DB)!=0)
+        return CKM_API_ERROR_INPUT_PARAM;
 
     // check if save is possible
     DB::Crypto::Transaction transaction(&handler.database);
@@ -968,11 +1103,12 @@ int CKMLogic::createKeyPairHelper(
     const PolicySerializable &policyPrivate,
     const PolicySerializable &policyPublic)
 {
-    if (0 == m_userDataMap.count(cred.uid))
-        return CKM_API_ERROR_DB_LOCKED;
+    auto &handlerPriv = selectDatabase(cred, labelPrivate);
+    auto &handlerPub = selectDatabase(cred, labelPublic);
+
 
-    KeyImpl prv, pub;
     int retCode;
+    KeyImpl prv, pub;
     switch(key_type)
     {
         case KeyType::KEY_RSA_PUBLIC:
@@ -1000,8 +1136,10 @@ int CKMLogic::createKeyPairHelper(
         return CKM_API_ERROR_SERVER_ERROR; // TODO error code
     }
 
-    auto &database = m_userDataMap[cred.uid].database;
-    DB::Crypto::Transaction transaction(&database);
+    DB::Crypto::Transaction transactionPriv(&handlerPriv.database);
+    // in case the same database is used for private and public - the second
+    // transaction will not be executed
+    DB::Crypto::Transaction transactionPub(&handlerPub.database);
 
     retCode = saveDataHelper(cred,
                              namePrivate,
@@ -1021,7 +1159,8 @@ int CKMLogic::createKeyPairHelper(
     if (CKM_API_SUCCESS != retCode)
         return retCode;
 
-    transaction.commit();
+    transactionPub.commit();
+    transactionPriv.commit();
 
     return retCode;
 }
@@ -1076,6 +1215,9 @@ RawBuffer CKMLogic::createKeyPair(
     } catch (DB::Crypto::Exception::InternalError &e) {
         LogDebug("DB::Crypto internal error: " << e.GetMessage());
         retCode = CKM_API_ERROR_DB_ERROR;
+    } catch (const CKMLogic::Exception::DatabaseLocked &e) {
+        LogError("Error " << e.GetMessage());
+        retCode = CKM_API_ERROR_DB_LOCKED;
     } catch (const CKM::Exception &e) {
         LogError("CKM::Exception: " << e.GetMessage());
         retCode = CKM_API_ERROR_SERVER_ERROR;
@@ -1244,6 +1386,9 @@ RawBuffer CKMLogic::getCertificateChain(
     } catch (const DB::Crypto::Exception::Base &e) {
         LogError("DB::Crypto failed with message: " << e.GetMessage());
         retCode = CKM_API_ERROR_DB_ERROR;
+    } catch (const CKMLogic::Exception::DatabaseLocked &e) {
+        LogError("Error " << e.GetMessage());
+        retCode = CKM_API_ERROR_DB_LOCKED;
     } catch (const std::exception& e) {
         LogError("STD exception " << e.what());
         retCode = CKM_API_ERROR_SERVER_ERROR;
@@ -1296,6 +1441,9 @@ RawBuffer CKMLogic::createSignature(
     } catch (const DB::Crypto::Exception::Base &e) {
         LogError("DB::Crypto failed with message: " << e.GetMessage());
         retCode = CKM_API_ERROR_DB_ERROR;
+    } catch (const CKMLogic::Exception::DatabaseLocked &e) {
+        LogError("Error " << e.GetMessage());
+        retCode = CKM_API_ERROR_DB_LOCKED;
     } catch (const CKM::Exception &e) {
         LogError("Unknown CKM::Exception: " << e.GetMessage());
         retCode = CKM_API_ERROR_SERVER_ERROR;
@@ -1368,6 +1516,9 @@ RawBuffer CKMLogic::verifySignature(
     } catch (const DB::Crypto::Exception::Base &e) {
         LogError("DB::Crypto failed with message: " << e.GetMessage());
         retCode = CKM_API_ERROR_DB_ERROR;
+    } catch (const CKMLogic::Exception::DatabaseLocked &e) {
+        LogError("Error " << e.GetMessage());
+        retCode = CKM_API_ERROR_DB_LOCKED;
     } catch (const CKM::Exception &e) {
         LogError("Unknown CKM::Exception: " << e.GetMessage());
         retCode = CKM_API_ERROR_SERVER_ERROR;
@@ -1386,6 +1537,8 @@ int CKMLogic::setPermissionHelper(
         const Label &accessorLabel,             // who will get the access
         const PermissionMask permissionMask)
 {
+    auto &handler = selectDatabase(cred, label);
+
     // we don't know the client
     if (cred.smackLabel.empty() || !isLabelValid(cred.smackLabel))
         return CKM_API_ERROR_INPUT_PARAM;
@@ -1401,29 +1554,30 @@ int CKMLogic::setPermissionHelper(
     if (ownerLabel==accessorLabel)
         return CKM_API_ERROR_INPUT_PARAM;
 
-    // can the client modify permissions to owner's row?
-    int access_ec = m_accessControl.canModify(ownerLabel, cred.smackLabel);
-    if(access_ec != CKM_API_SUCCESS)
-        return access_ec;
+    // system database does not support write/remove permissions
+    if ((0 == ownerLabel.compare(LABEL_SYSTEM_DB)) &&
+        (permissionMask & Permission::REMOVE))
+        return CKM_API_ERROR_INPUT_PARAM;
 
-    if (0 == m_userDataMap.count(cred.uid))
-        return CKM_API_ERROR_DB_LOCKED;
+    // can the client modify permissions to owner's row?
+    int retCode = m_accessControl.canModify(cred, ownerLabel);
+    if(retCode != CKM_API_SUCCESS)
+        return retCode;
 
-    auto &database = m_userDataMap[cred.uid].database;
-    DB::Crypto::Transaction transaction(&database);
+    DB::Crypto::Transaction transaction(&handler.database);
 
-    if( !database.isNameLabelPresent(name, ownerLabel) )
+    if( !handler.database.isNameLabelPresent(name, ownerLabel) )
         return CKM_API_ERROR_DB_ALIAS_UNKNOWN;
 
     // removing non-existing permissions: fail
     if(permissionMask == Permission::NONE)
     {
-        if(!database.getPermissionRow(name, ownerLabel, accessorLabel))
+        if(!handler.database.getPermissionRow(name, ownerLabel, accessorLabel))
             return CKM_API_ERROR_INPUT_PARAM;
     }
 
     // set permissions to the row owned by ownerLabel for accessorLabel
-    database.setPermission(name, ownerLabel, accessorLabel, permissionMask);
+    handler.database.setPermission(name, ownerLabel, accessorLabel, permissionMask);
     transaction.commit();
 
     return CKM_API_SUCCESS;
@@ -1441,6 +1595,9 @@ RawBuffer CKMLogic::setPermission(
     int retCode;
     Try {
         retCode = setPermissionHelper(cred, name, label, accessorLabel, permissionMask);
+    } catch (const CKMLogic::Exception::DatabaseLocked &e) {
+        LogError("Error " << e.GetMessage());
+        retCode = CKM_API_ERROR_DB_LOCKED;
     } Catch (CKM::Exception) {
         LogError("Error in set row!");
         retCode = CKM_API_ERROR_DB_ERROR;
index ab43124..eb5e948 100644 (file)
@@ -34,6 +34,7 @@
 #include <file-lock.h>
 #include <access-control.h>
 #include <certificate-impl.h>
+#include <sys/types.h>
 
 namespace CKM {
 
@@ -45,6 +46,13 @@ struct UserData {
 
 class CKMLogic {
 public:
+    class Exception
+    {
+    public:
+        DECLARE_EXCEPTION_TYPE(CKM::Exception, Base)
+        DECLARE_EXCEPTION_TYPE(Base, DatabaseLocked)
+    };
+
     CKMLogic();
     CKMLogic(const CKMLogic &) = delete;
     CKMLogic(CKMLogic &&) = delete;
@@ -176,6 +184,15 @@ public:
 
 private:
 
+    // select private/system database depending on asking uid and owner label.
+    // output: database handler and effective label
+    UserData & selectDatabase(const Credentials &incoming_cred,
+                              const Label       &incoming_label);
+
+    int unlockSystemDB();
+    int unlockDatabase(uid_t            user,
+                       const Password & password);
+
     void loadDKEKFile(
         uid_t user,
         const Password &password);
@@ -256,6 +273,7 @@ private:
         DB::RowVector &output);
 
     int checkDataPermissionsHelper(
+        const Credentials &cred,
         const Name &name,
         const Label &ownerLabel,
         const Label &accessorLabel,
@@ -319,6 +337,16 @@ private:
         const Label &accessorLabel,
         const PermissionMask permissionMask);
 
+    int getDataListHelper(
+        const Credentials &cred,
+        const DataType dataType,
+        LabelNameVector &labelNameVector);
+
+    int changeUserPasswordHelper(uid_t user,
+                                 const Password &oldPassword,
+                                 const Password &newPassword);
+
+    int resetUserPasswordHelper(uid_t user, const Password &newPassword);
 
     std::map<uid_t, UserData> m_userDataMap;
     AccessControl m_accessControl;
index 28a10b5..de4e624 100644 (file)
@@ -130,7 +130,8 @@ RawBuffer CKMService::ProcessControl(MessageBuffer &buffer) {
         PermissionMask permissionMask = 0;
 
         buffer.Deserialize(user, name, label, accessorLabel, permissionMask);
-        Credentials cred = { user, label };
+
+        Credentials cred(user, label);
         return m_logic->setPermission(
             cred,
             command,