Refactor Ext4 Engine 21/115321/8
authorSungbae Yoo <sungbae.yoo@samsung.com>
Fri, 17 Feb 2017 09:31:14 +0000 (18:31 +0900)
committerSungbae Yoo <sungbae.yoo@samsung.com>
Wed, 22 Feb 2017 11:57:48 +0000 (20:57 +0900)
Signed-off-by: Sungbae Yoo <sungbae.yoo@samsung.com>
Change-Id: Ida2ae91ac3f86b131fda3d06d6ad7d964b2b4a2f

server/engine/encryption/ext4-engine.cpp [changed mode: 0755->0644]
server/engine/encryption/ext4-engine.h
server/kernel-keyring.cpp
server/kernel-keyring.h

old mode 100755 (executable)
new mode 100644 (file)
index 212f396..41e029d
  *  See the License for the specific language governing permissions and
  *  limitations under the License
  */
-#include <iostream>
+
 #include <string>
-#include <string.h>
-#include <dirent.h>
+#include <iomanip>
+#include <iostream>
+
 #include <fcntl.h>
 #include <unistd.h>
-#include <stdlib.h>
-#include <linux/keyctl.h>
+#include <sys/vfs.h>
+#include <sys/stat.h>
 #include <sys/mount.h>
-#include <sys/xattr.h>
-#include <sys/syscall.h>
 #include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/sendfile.h>
+#include <sys/types.h>
+#include <sys/xattr.h>
 
-#include <klay/filesystem.h>
-#include <klay/audit/logger.h>
 #include <klay/error.h>
 #include <klay/exception.h>
+#include <klay/filesystem.h>
+#include <klay/audit/logger.h>
 
+#include "../../kernel-keyring.h"
 #include "../../file-footer.h"
 #include "../../key-manager/key-generator.h"
 
 #include "ext4-engine.h"
 
-namespace ode {
+#define ENCRYPTION_DIR ".encrypted"
+
+#define SMACK_LABEL_LEN_MAX 255
 
 #define EXT4_MAX_KEY_SIZE 64
 #define EXT4_KEY_DESCRIPTOR_SIZE 8
-#define EXT4_KEY_DESC_PREFIX_SIZE 5
-#define EXT4_KEY_REF_STR_BUF_SIZE ((EXT4_KEY_DESCRIPTOR_SIZE * 2) + 1)
 #define EXT4_IOC_SET_ENCRYPTION_POLICY  _IOR('f', 19, struct ext4_encryption_policy)
 #define EXT4_IOC_GET_ENCRYPTION_POLICY  _IOW('f', 21, struct ext4_encryption_policy)
 
-/* special process keyring shortcut IDs */
-#define KEY_SPEC_THREAD_KEYRING                -1
-#define KEY_SPEC_PROCESS_KEYRING       -2
-#define KEY_SPEC_SESSION_KEYRING       -3
-#define KEY_SPEC_USER_KEYRING          -4
-#define KEY_SPEC_USER_SESSION_KEYRING  -5
-#define KEY_SPEC_GROUP_KEYRING         -6
-
-#define KEYCTL_GET_KEYRING_ID          0
-#define KEYCTL_SEARCH 10
+#define EXT4_KEYRING_TYPE      "logon"
 
  /* Encryption algorithms */
 #define EXT4_ENCRYPTION_MODE_INVALID            0
@@ -65,7 +56,6 @@ namespace ode {
 #define EXT4_ENCRYPTION_MODE_AES_256_CBC        3
 #define EXT4_ENCRYPTION_MODE_AES_256_CTS        4
 
-#define SMACK_LABEL_LEN_MAX 255
 struct ext4_encryption_policy {
        char version;
        char contents_encryption_mode;
@@ -80,338 +70,226 @@ struct ext4_encryption_key {
        unsigned int size;
 } __attribute__((__packed__));
 
-/* for now, It only suits for "/opt/usr" */
+namespace ode {
+
 namespace {
-       std::string secondMountPoint("/opt/usr_encrypt");
-       std::string bindMountPoint("/opt/usr_encrypt/secure");
-       std::string ext4KeyringType("logon");
-       std::string smackAccessLabel("security.SMACK64");
-       long long totalSize = 0;
-       long long curSize = 0;
-}
 
-const Ext4Engine::data generateKeyDesc(const ode::Ext4Engine::data& key)
+const Ext4Engine::data generateKeyDescriptor(const Ext4Engine::data& key)
 {
-       Ext4Engine::data keyRef1 = ode::KeyGenerator::SHA512(key);
-       Ext4Engine::data keyRef2 = ode::KeyGenerator::SHA512(keyRef1);
-       Ext4Engine::data ret(keyRef2.begin(), keyRef2.begin()+EXT4_KEY_DESCRIPTOR_SIZE);
-
-       return ret;
+       auto hash = KeyGenerator::SHA512(KeyGenerator::SHA512(key));
+       hash.resize(EXT4_KEY_DESCRIPTOR_SIZE);
+       return hash;
 }
 
-const Ext4Engine::data generateKeyRefStr(const Ext4Engine::data& key)
+const std::string convertToHex(const Ext4Engine::data &binary)
 {
-       Ext4Engine::data ret(EXT4_KEY_REF_STR_BUF_SIZE);
-       Ext4Engine::data keyDesc = generateKeyDesc(key);
-
-       int i, a;
-       unsigned char nibble;
-       for (i=0, a=0; i < EXT4_KEY_DESCRIPTOR_SIZE; i++, a+=2) {
-               nibble = (keyDesc[i] >> 4) & 0xf;
-               if (nibble <= 9) ret[a] = '0' + nibble;
-               else                     ret[a] = 'a' + nibble - 10;
-               nibble = keyDesc[i] & 0xf;
-               if (nibble <= 9) ret[a+1] = '0' + nibble;
-               else                     ret[a+1] = 'a' + nibble - 10;
-       }
+       std::stringstream hex;
 
-       ret[a] = '\0';
+       hex << std::hex << std::setfill('0');
+       for (unsigned int byte : binary) {
+               hex << std::setw(2) << byte;
+       }
+       return hex.str();
+}
 
-       return ret;
+Ext4Engine::data sanitizeKey(const Ext4Engine::data &key)
+{
+       Ext4Engine::data sanitized(key);
+       sanitized.resize(EXT4_MAX_KEY_SIZE);
+       return sanitized;
 }
 
 void addKeyToKeyring(const Ext4Engine::data& key)
 {
-       struct ext4_encryption_key ext4Key;
-       Ext4Engine::data keyRefStr(EXT4_KEY_REF_STR_BUF_SIZE);
-       keyRefStr = generateKeyRefStr(key);
-       std::string keyRef(keyRefStr.begin(), keyRefStr.end()), keyRefFull;
-       int keyringId, ret;
-
-       keyringId = ::syscall(__NR_keyctl, KEYCTL_GET_KEYRING_ID, KEY_SPEC_SESSION_KEYRING, 0);
-       if (keyringId == -1)
-               throw runtime::Exception(runtime::GetSystemErrorMessage());
+       struct ext4_encryption_key payload;
+       std::string keyDescriptor;
+       int keyringId;
+
+       keyringId = KernelKeyRing::getKeyringId(KEY_SPEC_SESSION_KEYRING, 0);
+       if (keyringId == -1) {
+               throw runtime::Exception("Unable to get keyring id");
+       }
 
-       keyRefFull = "ext4:" + keyRef;
-       ret = ::syscall(__NR_keyctl, KEYCTL_SEARCH, keyringId, ext4KeyringType.c_str(), keyRefFull.c_str(), 0);
-       if (ret != -1) {
+       keyDescriptor = "ext4:" + convertToHex(generateKeyDescriptor(key));
+       if (KernelKeyRing::search(keyringId, EXT4_KEYRING_TYPE,
+                                                               keyDescriptor, 0) >= 0) {
                INFO("Key with descriptor already exist");
                return;
        }
-       ext4Key.mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
-       ::memset(ext4Key.raw, 0, EXT4_MAX_KEY_SIZE);
-       ::memcpy(ext4Key.raw, key.data(), key.size());
-       ext4Key.size = EXT4_MAX_KEY_SIZE;
 
-       ret = ::syscall(__NR_add_key, ext4KeyringType.c_str(), keyRefFull.c_str(),
-                            (void *)&ext4Key, sizeof(ext4Key), keyringId);
+       payload.mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
+       payload.size = EXT4_MAX_KEY_SIZE;
+       ::memcpy(payload.raw, key.data(), key.size());
 
-       if (ret == -1) {
-               throw runtime::Exception(runtime::GetSystemErrorMessage());
+       if (KernelKeyRing::add(EXT4_KEYRING_TYPE, keyDescriptor,
+                                                       (void *)&payload, sizeof(payload),
+                                                       KEY_SPEC_USER_KEYRING) < 0) {
+               throw runtime::Exception("Unable to add key to keyring");
        }
 }
 
-static void copySmackLabel(std::string& srcPath, std::string& destPath)
+int intLog2(int arg)
 {
-       Ext4Engine::data smackLabel(SMACK_LABEL_LEN_MAX + 1);
+       int l = 0;
 
-       if (::getxattr(srcPath.c_str(), smackAccessLabel.c_str(), (unsigned char*)smackLabel.data(), SMACK_LABEL_LEN_MAX + 1) == -1)
-               throw runtime::Exception(runtime::GetSystemErrorMessage());
+       arg >>= 1;
+       while(arg) {
+               l++;
+               arg >>= 1;
+       }
 
-       if (::setxattr(destPath.c_str(), smackAccessLabel.c_str(), smackLabel.data(), smackLabel.size(), 0) == -1)
-               throw runtime::Exception(runtime::GetSystemErrorMessage());
+       return l;
 }
 
-int Ext4Engine::copy(std::string& src, std::string& dest)
+void setPolicy(const std::string& path, const Ext4Engine::data& key)
 {
-       int readFd, writeFd, ret;
-       struct stat st;
+       struct ext4_encryption_policy policy;
+       int pad = 4;
+       int fd, rc;
 
-       ret = ::stat(src.c_str(), &st);
-       if (ret != 0) {
-               throw runtime::Exception(src + runtime::GetSystemErrorMessage());
+       fd = ::open(path.c_str(), O_DIRECTORY);
+       if (fd == -1) {
+               throw runtime::Exception("invalid path");
        }
 
-       readFd = ::open(src.c_str(), O_RDONLY);
-       if (readFd < 0)
-               throw runtime::Exception(src + runtime::GetSystemErrorMessage());
-
-       writeFd = ::open(dest.c_str(), O_WRONLY | O_CREAT, st.st_mode);
-       if (writeFd < 0)
-               throw runtime::Exception(dest + runtime::GetSystemErrorMessage());
-       copySmackLabel(src, dest);
-       if (::chown(dest.c_str(), st.st_uid, st.st_gid) == -1)
-               throw runtime::Exception(dest + runtime::GetSystemErrorMessage());
-       if (::sendfile(writeFd, readFd, 0, st.st_size) == -1)
-               throw runtime::Exception(runtime::GetSystemErrorMessage());
+       Ext4Engine::data descriptor = generateKeyDescriptor(key);
 
-       /* progress bar update */
-       curSize += st.st_size;
-       INFO("curSize is " + std::to_string(curSize));
-       progressBar.update(curSize, totalSize, 1);
-
-       if (::fsync(writeFd) != 0)
-               throw runtime::Exception(dest + runtime::GetSystemErrorMessage());
+       policy.version = 0;
+       policy.contents_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
+       policy.filenames_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_CTS;
+       policy.flags = intLog2(pad >> 2);
+       ::memcpy(policy.master_key_descriptor, descriptor.data(), descriptor.size());
 
-       if (::posix_fadvise(writeFd, 0, st.st_size, POSIX_FADV_DONTNEED) < 0)
-               throw runtime::Exception(dest + runtime::GetSystemErrorMessage());
+       rc = ::ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &policy);
+       ::close(fd);
 
-       ::close(readFd);
-       ::close(writeFd);
-       return 0;
+       if (rc) {
+               throw runtime::Exception("set policy failed :" + runtime::GetSystemErrorMessage());
+       }
 }
 
-static void preScanDir(std::string& dir)
+bool hasPolicy(const std::string& dir)
 {
-       DIR* d;
-
-       d = ::opendir(dir.c_str());
-
-       if (!d)
-               throw runtime::Exception(dir + runtime::GetSystemErrorMessage());
-
-       while(1) {
-               struct dirent* entry;
-               std::string dName;
-
-               entry = ::readdir(d);
-               if (!entry) {
-                       break;
-               }
-               dName = entry->d_name;
-               if (!(entry->d_type & DT_DIR)) {
-                       std::string file = dir + "/" + dName;
-                       struct stat st;
-                       int statRet;
-
-                       statRet = ::stat(file.c_str(), &st);
-                       if (statRet != 0)
-                               throw runtime::Exception(file + runtime::GetSystemErrorMessage());
-                       INFO("[preListDir] " + file + " totalSize = " + std::to_string(totalSize) + " " +std::to_string(st.st_size));
-                       totalSize += st.st_size;
-               }
-
-               if (entry->d_type & DT_DIR) {
-                       if (dName.compare(".") != 0 && dName.compare("..") != 0) {
-                               std::string path;
-
-                               path = dir + "/" + dName;
+       struct ext4_encryption_policy policy;
+       int fd, rc;
 
+       fd = ::open(dir.c_str(), O_DIRECTORY);
+       if (fd == -1) {
+               return false;
+       }
 
-                               if (path.size() >= PATH_MAX)
-                                       throw runtime::Exception(path + " :path length has got too long");
+       rc = ::ioctl(fd, EXT4_IOC_GET_ENCRYPTION_POLICY, &policy);
+       close(fd);
 
-                               preScanDir(path);
-                       }
-               }
+       if (rc) {
+               return false;
        }
 
-       if (::closedir(d))
-               throw runtime::Exception(runtime::GetSystemErrorMessage());
-
+       return true;
 }
 
-void Ext4Engine::listDir(std::string& source, std::string& dest, bool excludeFlag)
+unsigned long long getUsedSpace(const std::string& mountPoint)
 {
-       DIR* d;
-
-       if (excludeFlag && source.compare(0, bindMountPoint.size(), bindMountPoint) == 0)
-               return;
-
-       d = ::opendir(source.c_str());
-
-       if (!d)
-               throw runtime::Exception(source + runtime::GetSystemErrorMessage());
-
-       while(1) {
-               struct dirent* entry;
-               std::string dName;
-
-               entry = ::readdir(d);
-               if (!entry) {
-                       break;
-               }
-               dName = entry->d_name;
-               if (!(entry->d_type & DT_DIR)) {
-                       std::string srcFile = source + "/" + dName;
-                       std::string destFile = dest + "/" +dName;
-                       copy(srcFile, destFile);
-
-                       if (::remove(srcFile.c_str()) != 0)
-                               ERROR("file remove failed");
-               }
-
-               if (entry->d_type & DT_DIR) {
-                       if (dName.compare(".") != 0 && dName.compare("..") != 0) {
-                               std::string pathS, pathD;
-
-                               pathS = source + "/" + dName;
-                               pathD = dest + "/" +dName;
-
-                               /* make new directory */
-                               int mkdirRet, statRet;
-                               struct stat st;
-                               statRet = ::stat(pathS.c_str(), &st);
-                               if (statRet != 0)
-                                       throw runtime::Exception(pathS + runtime::GetSystemErrorMessage());
-
-                               if (excludeFlag) {
-                                       if (pathS.compare(bindMountPoint) != 0) {
-                                               mkdirRet = ::mkdir(pathD.c_str(), st.st_mode);
-                                               if (mkdirRet != 0)
-                                                       throw runtime::Exception(pathS + runtime::GetSystemErrorMessage());
-                                               copySmackLabel(pathS, pathD);
-                                               if (::chown(pathD.c_str(), st.st_uid, st.st_gid) == -1)
-                                                       throw runtime::Exception(runtime::GetSystemErrorMessage());
-                                       }
-                               } else {
-                                       mkdirRet = ::mkdir(pathD.c_str(), st.st_mode);
-                                       if (mkdirRet != 0)
-                                               throw runtime::Exception(pathD + runtime::GetSystemErrorMessage());
-                                       copySmackLabel(pathS, pathD);
-                                               if (::chown(pathD.c_str(), st.st_uid, st.st_gid) == -1)
-                                                       throw runtime::Exception(pathD + runtime::GetSystemErrorMessage());
-                               }
-                               if (pathS.size() >= PATH_MAX)
-                                       throw runtime::Exception(pathS + " :path length has got too long");
-
-                               listDir(pathS, pathD, excludeFlag);
-                       }
-               }
+       struct statfs statbuf;
+       if (::statfs(mountPoint.c_str(), &statbuf)) {
+               throw runtime::Exception("Failed to access " + mountPoint);
        }
 
-       if (::closedir(d))
-               throw runtime::Exception(runtime::GetSystemErrorMessage());
-
-       if (source.compare(secondMountPoint) != 0) {
-               if (::remove(source.c_str()) != 0)
-                       throw runtime::Exception(source + runtime::GetSystemErrorMessage());
-       }
+       return (unsigned long long)(statbuf.f_blocks - statbuf.f_bfree) * statbuf.f_bsize;
 }
 
-static int intLog2(int arg)
+unsigned long long getAvailableSpace(const std::string& mountPoint)
 {
-       int l = 0;
-
-       arg >>= 1;
-       while(arg) {
-               l++;
-               arg >>= 1;
+       struct statfs statbuf;
+       if (::statfs(mountPoint.c_str(), &statbuf)) {
+               throw runtime::Exception("Failed to access " + mountPoint);
        }
 
-       return l;
+       return (unsigned long long)statbuf.f_bfree * statbuf.f_bsize;
 }
 
-static void setPolicy(const std::string& source, const Ext4Engine::data& key)
+static void copyDac(const std::string& srcPath, const std::string& destPath)
 {
-       struct ext4_encryption_policy policy;
-       int pad = 4;
-       int fd, rc;
-       Ext4Engine::data descriptor(EXT4_KEY_DESCRIPTOR_SIZE);
+       runtime::File src(srcPath), dest(destPath);
 
-       descriptor = generateKeyDesc(key);
-       std::string descStr(descriptor.begin(), descriptor.end());
+       try {
+               mode_t mode = src.getMode();
+               uid_t uid = src.getUid();
+               gid_t gid = src.getGid();
 
-       fd = ::open(source.c_str(), O_DIRECTORY);
-       if (fd == -1)
-               throw runtime::Exception("invalid path");
-
-       policy.version = 0;
-       policy.contents_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_XTS;
-       policy.filenames_encryption_mode = EXT4_ENCRYPTION_MODE_AES_256_CTS;
-       policy.flags = intLog2(pad >> 2);
-       ::memcpy(policy.master_key_descriptor, descriptor.data(), EXT4_KEY_DESCRIPTOR_SIZE);
+               try {
+                       dest.chown(uid, gid);
+               } catch (runtime::Exception &e) {}
 
-       rc = ::ioctl(fd, EXT4_IOC_SET_ENCRYPTION_POLICY, &policy);
-       ::close(fd);
-
-       if (rc)
-               throw runtime::Exception("set policy failed :" + runtime::GetSystemErrorMessage());
+               try {
+                       dest.chmod(mode);
+               } catch (runtime::Exception &e) {}
+       } catch (runtime::Exception &e) {}
 }
 
-static bool prepareEncryptDir(std::string& sourceName, std::string& destName)
+static void copyMac(const std::string& srcPath, const std::string& destPath)
 {
-       struct stat dirStat;
-       ::stat(destName.c_str(), &dirStat);
+       char smackLabel[SMACK_LABEL_LEN_MAX + 1];
+       ssize_t labelSize;
 
-       if (::mkdir(secondMountPoint.c_str(), dirStat.st_mode) != 0)
-               throw runtime::Exception(runtime::GetSystemErrorMessage());
-       copySmackLabel(destName, secondMountPoint);
-       if (::chown(secondMountPoint.c_str(), dirStat.st_uid, dirStat.st_gid) == -1)
-               throw runtime::Exception(runtime::GetSystemErrorMessage());
-       if (::mount(sourceName.c_str(), secondMountPoint.c_str(), "ext4", 0, 0) < 0) {
-               ::remove(secondMountPoint.c_str());
-               throw runtime::Exception(runtime::GetSystemErrorMessage());
+       labelSize = ::getxattr(srcPath.c_str(), "security.SMACK64", smackLabel, SMACK_LABEL_LEN_MAX + 1);
+
+       if (labelSize == -1) {
+               return;
        }
 
-       if (::mkdir(bindMountPoint.c_str(), dirStat.st_mode) != 0)
-               throw runtime::Exception(runtime::GetSystemErrorMessage());
-       copySmackLabel(secondMountPoint, bindMountPoint);
-       if (::chown(bindMountPoint.c_str(), dirStat.st_uid, dirStat.st_gid) == -1)
-               throw runtime::Exception(runtime::GetSystemErrorMessage());
-       return true;
+       ::setxattr(destPath.c_str(), "security.SMACK64", smackLabel, labelSize, 0);
 }
 
-static int getPolicy(const std::string& dirName)
+bool isEnoughToCopyInPlace(const std::string& path)
 {
-       struct ext4_encryption_policy policy;
-       int fd, rc;
+       unsigned long long availableSpace = getAvailableSpace(path);
+
+       std::function<bool(const std::string &path)> check;
+       check = [&check, availableSpace](const std::string &path) {
+               for (runtime::DirectoryIterator iter(path), end;
+                               iter != end; ++iter) {
+                       if (iter->isDirectory()) {
+                               if (!check(iter->getPath())) {
+                                       return false;
+                               }
+                       } else if (iter->size() > availableSpace) {
+                               return false;
+                       }
+               }
+               return true;
+       };
 
-       fd = ::open(dirName.c_str(), O_DIRECTORY);
-       if (fd == -1)
-               return 0;
+       return check(path);
+}
 
-       rc = ::ioctl(fd, EXT4_IOC_GET_ENCRYPTION_POLICY, &policy);
-       close(fd);
-       if (rc) {
-               ERROR("ioctl error");
-               return 0;
+void copyInPlace(const std::string& source, const std::string& destination,
+                                       const std::function<void(unsigned long long)> &addProgress)
+{
+       for (runtime::DirectoryIterator iter(source), end; iter != end; ++iter) {
+               if (iter->getPath() == destination) {
+                       continue;
+               }
+
+               runtime::File destFile(destination + "/" + iter->getName());
+               if (iter->isDirectory()) {
+                       destFile.makeDirectory();
+                       copyInPlace(iter->getPath(), destFile.getPath(), addProgress);
+               } else {
+                       iter->copyTo(destFile.getPath());
+                       addProgress(iter->size());
+               }
+               copyDac(iter->getPath(), destFile.getPath());
+               copyMac(iter->getPath(), destFile.getPath());
+
+               iter->remove();
        }
-       return 1;
 }
 
+} // namespace
+
 Ext4Engine::Ext4Engine(const std::string& src, const std::string& dest, const ProgressBar &prgsBar) :
-       source(src), destination(dest), progressBar(prgsBar)
+       source(src), destination(dest), progress(prgsBar)
 {
 }
 
@@ -421,77 +299,92 @@ Ext4Engine::~Ext4Engine()
 
 void Ext4Engine::mount(const Ext4Engine::data& key, unsigned int options)
 {
-       addKey(key);
-       /* mount : /dev/mmcblk0p21 /opt/usr_encrypt */
-       if (::mount(source.c_str(), secondMountPoint.c_str(), "ext4", 0, 0) < 0)
-               throw runtime::Exception(runtime::GetSystemErrorMessage());
-       /* bind mount :/opt/usr_encrypt/secure /opt/usr */
-       if (::mount(bindMountPoint.c_str(), destination.c_str(), "ext4", MS_BIND, 0) < 0)
-               throw runtime::Exception(runtime::GetSystemErrorMessage());
+       std::string encryptedPath(destination + "/" ENCRYPTION_DIR);
+
+       addKeyToKeyring(sanitizeKey(key));
+
+       if (::mount(source.c_str(), destination.c_str(), "ext4", 0, 0) < 0) {
+               throw runtime::Exception("Mount error - " + runtime::GetSystemErrorMessage());
+       }
+
+       if (::mount(encryptedPath.c_str(), destination.c_str(), NULL, MS_BIND, 0) < 0) {
+               throw runtime::Exception("Mount error - " + runtime::GetSystemErrorMessage());
+       }
 }
 
 void Ext4Engine::umount()
 {
-       /* for decrypt, umount /opt/usr */
-       if (::umount(destination.c_str()))
-               throw runtime::Exception(runtime::GetSystemErrorMessage());
-}
+       //TODO : remove Key
 
-void Ext4Engine::addKey(const Ext4Engine::data& key)
-{
-       addKeyToKeyring(key);
+       if (::umount(destination.c_str())) {
+               throw runtime::Exception(runtime::GetSystemErrorMessage());
+       }
 }
 
 void Ext4Engine::encrypt(const Ext4Engine::data& key, unsigned int options)
 {
-       std::string sourceDir = getSource();
-       std::string destDir = getDestination();
-       bool copyFlag = false;
+       if (!isEnoughToCopyInPlace(destination)) {
+               throw runtime::Exception("No space to encryption");
+       }
 
-       if (!(copyFlag = prepareEncryptDir(sourceDir, destDir)))
-               throw runtime::Exception("prepareEncryptDir failed");
+       if (::mount(source.c_str(), destination.c_str(), "ext4", 0, 0) < 0) {
+               throw runtime::Exception("Mount error - " + runtime::GetSystemErrorMessage());
+       }
 
-       preScanDir(secondMountPoint);
-       /* key add to keyring */
-       addKeyToKeyring(key);
-       /* set policy */
-       setPolicy(bindMountPoint, key);
+       Ext4Engine::data sanitizedKey = sanitizeKey(key);
+       addKeyToKeyring(sanitizedKey);
 
-       if (copyFlag)
-               listDir(secondMountPoint, bindMountPoint, true);
-       INFO("[ext4 encrypt] copy done");
+       runtime::File encrypted(destination + "/" ENCRYPTION_DIR);
+       if (encrypted.exists()) {
+               encrypted.remove(true);
+       }
+       encrypted.makeDirectory();
+       setPolicy(encrypted.getPath(), sanitizedKey);
+
+       unsigned long long totalSize = getUsedSpace(source), current = 0;
+       copyInPlace(destination, encrypted.getPath(),
+                               [&current, &totalSize, this](unsigned long long size) {
+                                       current += size;
+                                       this->progress.update(current, totalSize, 1);
+                               });
+
+       if (::mount(encrypted.getPath().c_str(), destination.c_str(), NULL, MS_BIND, 0) < 0) {
+               throw runtime::Exception("Mount error - " + runtime::GetSystemErrorMessage());
+       }
 
-       progressBar.done();
-       if (::mount(bindMountPoint.c_str(), destDir.c_str(), "ext4", MS_BIND, 0) < 0)
-               throw runtime::Exception(runtime::GetSystemErrorMessage());
+       sync();
+
+       progress.done();
 }
 
 void Ext4Engine::decrypt(const Ext4Engine::data& key, unsigned int options)
 {
-       std::string destDir = getDestination();
+       if (!isEnoughToCopyInPlace(destination)) {
+               throw runtime::Exception("No space to encryption");
+       }
 
-       if (getPolicy(bindMountPoint) != 1)
+       if (!hasPolicy(destination)) {
                throw runtime::Exception("failed get policy");
-       addKeyToKeyring(key);
+       }
 
-       preScanDir(bindMountPoint);
+       if (::umount(destination.c_str())) {
+               throw runtime::Exception(runtime::GetSystemErrorMessage());
+       }
 
-       listDir(bindMountPoint, secondMountPoint, false);
-       INFO("[ext4 decrypt] copy done");
-       progressBar.done();
+       runtime::File encrypted(destination + "/" ENCRYPTION_DIR);
 
-       if (::open(bindMountPoint.c_str(), O_RDONLY) != -1)
-               ::remove(bindMountPoint.c_str());
+       unsigned long long totalSize = getUsedSpace(source), current = 0;
+       copyInPlace(encrypted.getPath(), destination,
+                               [&current, &totalSize, this](unsigned long long size) {
+                                       current += size;
+                                       this->progress.update(current, totalSize, 1);
+                               });
 
-       /* umount /opt/usr_encrypt */
-       if (::umount(secondMountPoint.c_str()))
-               throw runtime::Exception(runtime::GetSystemErrorMessage());
-       /* mount /dev/mmcblk0p21 /opt/usr */
-       if (::mount(source.c_str(), destination.c_str(), "ext4", 0, 0) < 0)
-               throw runtime::Exception(runtime::GetSystemErrorMessage());
+       encrypted.remove(true);
+
+       sync();
 
-       if (::open(secondMountPoint.c_str(), O_RDONLY) != -1)
-               ::remove(secondMountPoint.c_str());
+       progress.done();
 }
 
 bool Ext4Engine::isKeyMetaSet()
index eb233f4..dd69b70 100644 (file)
@@ -49,7 +49,6 @@ public:
        void mount(const data &key, unsigned int options);
        void umount();
 
-       void addKey(const data &key);
        void encrypt(const data &key, unsigned int options);
        void decrypt(const data &key, unsigned int options);
 
@@ -60,12 +59,9 @@ public:
 
        unsigned int getSupportedOptions();
 
-       int copy(std::string& src, std::string& dest);
-       void listDir(std::string& source, std::string& dest, bool excludeFlag);
-
 private:
        std::string source, destination;
-       ProgressBar progressBar;
+       ProgressBar progress;
 };
 
 } // namespace ode
index 98f1e8e..ac7d857 100644 (file)
@@ -44,3 +44,8 @@ long KernelKeyRing::unlink(int32_t keyid, int32_t ringid)
 {
        return ::syscall(__NR_keyctl, KEYCTL_UNLINK, keyid, ringid);
 }
+
+int32_t KernelKeyRing::getKeyringId(int32_t keyid, bool create)
+{
+       return ::syscall(__NR_keyctl, KEYCTL_GET_KEYRING_ID, KEY_SPEC_SESSION_KEYRING, create);
+}
index 786b069..9dbfdd4 100644 (file)
@@ -45,6 +45,8 @@ public:
 
        static long link(int32_t keyid, int32_t ringid);
        static long unlink(int32_t keyid, int32_t ringid);
+
+       static int32_t getKeyringId(int32_t keyid, bool create);
 };
 
 #endif //!__KERNEL_KEY_RING_H__