am d9f2082f: Merge "VolumeManager: don\'t use faccessat(AT_SYMLINK_NOFOLLOW)"
* commit 'd9f2082fd798e77cc15735bc582507abb64c8ed4':
VolumeManager: don't use faccessat(AT_SYMLINK_NOFOLLOW)
diff --git a/Android.mk b/Android.mk
index 20072b1..cf2b291 100644
--- a/Android.mk
+++ b/Android.mk
@@ -80,6 +80,13 @@
LOCAL_C_INCLUDES := $(common_c_includes)
LOCAL_CFLAGS := $(vold_cflags)
LOCAL_CONLYFLAGS := $(vold_conlyflags)
+
+ifeq ($(TARGET_HW_DISK_ENCRYPTION),true)
+LOCAL_C_INCLUDES += $(TARGET_CRYPTFS_HW_PATH)
+common_shared_libraries += libcryptfs_hw
+LOCAL_CFLAGS += -DCONFIG_HW_DISK_ENCRYPTION
+endif
+
LOCAL_SHARED_LIBRARIES := $(common_shared_libraries)
LOCAL_STATIC_LIBRARIES := $(common_static_libraries)
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 2e90ecb..8c732ce 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -654,17 +654,33 @@
SLOGD("cryptfs verifypw {}");
rc = cryptfs_verify_passwd(argv[2]);
} else if (!strcmp(argv[1], "getfield")) {
- char valbuf[PROPERTY_VALUE_MAX];
+ char *valbuf;
+ int valbuf_len = PROPERTY_VALUE_MAX;
if (argc != 3) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs getfield <fieldname>", false);
return 0;
}
dumpArgs(argc, argv, -1);
- rc = cryptfs_getfield(argv[2], valbuf, sizeof(valbuf));
- if (rc == 0) {
+
+ // Increase the buffer size until it is big enough for the field value stored.
+ while (1) {
+ valbuf = (char*)malloc(valbuf_len);
+ if (valbuf == NULL) {
+ cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false);
+ return 0;
+ }
+ rc = cryptfs_getfield(argv[2], valbuf, valbuf_len);
+ if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) {
+ break;
+ }
+ free(valbuf);
+ valbuf_len *= 2;
+ }
+ if (rc == CRYPTO_GETFIELD_OK) {
cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
}
+ free(valbuf);
} else if (!strcmp(argv[1], "setfield")) {
if (argc != 4) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs setfield <fieldname> <value>", false);
@@ -702,8 +718,14 @@
dumpArgs(argc, argv, -1);
char* password = cryptfs_get_password();
if (password) {
- cli->sendMsg(ResponseCode::CommandOkay, password, false);
- return 0;
+ char* message = 0;
+ int size = asprintf(&message, "{{sensitive}} %s", password);
+ if (size != -1) {
+ cli->sendMsg(ResponseCode::CommandOkay, message, false);
+ memset(message, 0, size);
+ free (message);
+ return 0;
+ }
}
rc = -1;
} else if (!strcmp(argv[1], "clearpw")) {
diff --git a/cryptfs.c b/cryptfs.c
index dee6bac..916bd6c 100644
--- a/cryptfs.c
+++ b/cryptfs.c
@@ -42,6 +42,7 @@
#include <linux/kdev_t.h>
#include <fs_mgr.h>
#include <time.h>
+#include <math.h>
#include "cryptfs.h"
#define LOG_TAG "Cryptfs"
#include "cutils/log.h"
@@ -63,6 +64,10 @@
#define UNUSED __attribute__((unused))
+#ifdef CONFIG_HW_DISK_ENCRYPTION
+#include "cryptfs_hw.h"
+#endif
+
#define DM_CRYPT_BUF_SIZE 4096
#define HASH_COUNT 2000
@@ -138,7 +143,8 @@
goto out;
}
- if (keymaster_dev->flags & KEYMASTER_BLOBS_ARE_STANDALONE) {
+ if (!(keymaster_dev->flags & KEYMASTER_SOFTWARE_ONLY) &&
+ (keymaster_dev->flags & KEYMASTER_BLOBS_ARE_STANDALONE)) {
rc = 1;
}
@@ -992,7 +998,16 @@
tgt->status = 0;
tgt->sector_start = 0;
tgt->length = crypt_ftr->fs_size;
- strcpy(tgt->target_type, "crypt");
+#ifdef CONFIG_HW_DISK_ENCRYPTION
+ if (!strcmp((char *)crypt_ftr->crypto_type_name, "aes-xts")) {
+ strlcpy(tgt->target_type, "req-crypt", DM_MAX_TYPE_NAME);
+ }
+ else {
+ strlcpy(tgt->target_type, "crypt", DM_MAX_TYPE_NAME);
+ }
+#else
+ strlcpy(tgt->target_type, "crypt", DM_MAX_TYPE_NAME);
+#endif
crypt_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
convert_key_to_hex_ascii(master_key, crypt_ftr->keysize, master_key_ascii);
@@ -1037,7 +1052,11 @@
*/
v = (struct dm_target_versions *) &buffer[sizeof(struct dm_ioctl)];
while (v->next) {
+#ifdef CONFIG_HW_DISK_ENCRYPTION
+ if (! strcmp(v->name, "crypt") || ! strcmp(v->name, "req-crypt")) {
+#else
if (! strcmp(v->name, "crypt")) {
+#endif
/* We found the crypt driver, return the version, and get out */
version[0] = v->version[0];
version[1] = v->version[1];
@@ -1056,7 +1075,7 @@
char buffer[DM_CRYPT_BUF_SIZE];
struct dm_ioctl *io;
unsigned int minor;
- int fd;
+ int fd=0;
int retval = -1;
int version[3];
char *extra_params;
@@ -1739,6 +1758,14 @@
fs_mgr_get_crypt_info(fstab, 0, real_blkdev, sizeof(real_blkdev));
+#ifdef CONFIG_HW_DISK_ENCRYPTION
+ if (!strcmp((char *)crypt_ftr->crypto_type_name, "aes-xts")) {
+ if(!set_hw_device_encryption_key(passwd, (char*) crypt_ftr->crypto_type_name)) {
+ SLOGE("Hardware encryption key does not match");
+ }
+ }
+#endif
+
// Create crypto block device - all (non fatal) code paths
// need it
if (create_crypto_blk_dev(crypt_ftr, decrypted_master_key,
@@ -1885,7 +1912,10 @@
create_crypto_blk_dev(&sd_crypt_ftr, saved_master_key, real_blkdev,
crypto_blkdev, label);
- stat(crypto_blkdev, &statbuf);
+ if (stat(crypto_blkdev, &statbuf) < 0) {
+ SLOGE("Error get stat for crypto_blkdev %s. err=%d(%s)\n",
+ crypto_blkdev, errno, strerror(errno));
+ }
*new_major = MAJOR(statbuf.st_rdev);
*new_minor = MINOR(statbuf.st_rdev);
@@ -2185,7 +2215,11 @@
/* aligned 32K writes tends to make flash happy.
* SD card association recommends it.
*/
+#ifndef CONFIG_HW_DISK_ENCRYPTION
#define BLOCKS_AT_A_TIME 8
+#else
+#define BLOCKS_AT_A_TIME 1024
+#endif
struct encryptGroupsData
{
@@ -3043,16 +3077,6 @@
* restart the graphics services.
*/
sleep(2);
-
- /* startup service classes main and late_start */
- property_set("vold.decrypt", "trigger_restart_min_framework");
- SLOGD("Just triggered restart_min_framework\n");
-
- /* OK, the framework is restarted and will soon be showing a
- * progress bar. Time to setup an encrypted mapping, and
- * either write a new filesystem, or encrypt in place updating
- * the progress bar as we work.
- */
}
/* Start the actual work of making an encrypted filesystem */
@@ -3074,7 +3098,23 @@
On successfully completing encryption, remove this flag */
crypt_ftr.flags |= CRYPT_INCONSISTENT_STATE;
crypt_ftr.crypt_type = crypt_type;
- strcpy((char *)crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256");
+#ifndef CONFIG_HW_DISK_ENCRYPTION
+ strlcpy((char *)crypt_ftr.crypto_type_name, "aes-cbc-essiv:sha256", MAX_CRYPTO_TYPE_NAME_LEN);
+#else
+ strlcpy((char *)crypt_ftr.crypto_type_name, "aes-xts", MAX_CRYPTO_TYPE_NAME_LEN);
+
+ rc = clear_hw_device_encryption_key();
+ if (!rc) {
+ SLOGE("Error clearing device encryption hardware key. rc = %d", rc);
+ }
+
+ rc = set_hw_device_encryption_key(passwd,
+ (char*) crypt_ftr.crypto_type_name);
+ if (!rc) {
+ SLOGE("Error initializing device encryption hardware key. rc = %d", rc);
+ goto error_shutting_down;
+ }
+#endif
/* Make an encrypted master key */
if (create_encrypted_random_key(passwd, crypt_ftr.master_key, crypt_ftr.salt, &crypt_ftr)) {
@@ -3100,6 +3140,18 @@
}
}
+ if (how == CRYPTO_ENABLE_INPLACE) {
+ /* startup service classes main and late_start */
+ property_set("vold.decrypt", "trigger_restart_min_framework");
+ SLOGD("Just triggered restart_min_framework\n");
+
+ /* OK, the framework is restarted and will soon be showing a
+ * progress bar. Time to setup an encrypted mapping, and
+ * either write a new filesystem, or encrypt in place updating
+ * the progress bar as we work.
+ */
+ }
+
decrypt_master_key(passwd, decrypted_master_key, &crypt_ftr, 0, 0);
create_crypto_blk_dev(&crypt_ftr, decrypted_master_key, real_blkdev, crypto_blkdev,
"userdata");
@@ -3124,7 +3176,8 @@
}
/* Calculate checksum if we are not finished */
- if (!rc && crypt_ftr.encrypted_upto != crypt_ftr.fs_size) {
+ if (!rc && how == CRYPTO_ENABLE_INPLACE
+ && crypt_ftr.encrypted_upto != crypt_ftr.fs_size) {
rc = cryptfs_SHA256_fileblock(crypto_blkdev,
crypt_ftr.hash_first_block);
if (rc) {
@@ -3142,7 +3195,8 @@
/* Success */
crypt_ftr.flags &= ~CRYPT_INCONSISTENT_STATE;
- if (crypt_ftr.encrypted_upto != crypt_ftr.fs_size) {
+ if (how == CRYPTO_ENABLE_INPLACE
+ && crypt_ftr.encrypted_upto != crypt_ftr.fs_size) {
SLOGD("Encrypted up to sector %lld - will continue after reboot",
crypt_ftr.encrypted_upto);
crypt_ftr.flags |= CRYPT_ENCRYPTION_IN_PROGRESS;
@@ -3150,7 +3204,8 @@
put_crypt_ftr_and_key(&crypt_ftr);
- if (crypt_ftr.encrypted_upto == crypt_ftr.fs_size) {
+ if (how == CRYPTO_ENABLE_WIPE
+ || crypt_ftr.encrypted_upto == crypt_ftr.fs_size) {
char value[PROPERTY_VALUE_MAX];
property_get("ro.crypto.state", value, "");
if (!strcmp(value, "")) {
@@ -3327,10 +3382,49 @@
put_crypt_ftr_and_key(&crypt_ftr);
free(adjusted_passwd);
+
+#ifdef CONFIG_HW_DISK_ENCRYPTION
+ if (!strcmp((char *)crypt_ftr.crypto_type_name, "aes-xts")) {
+ if (crypt_type == CRYPT_TYPE_DEFAULT) {
+ int rc = update_hw_device_encryption_key(DEFAULT_PASSWORD, (char*) crypt_ftr.crypto_type_name);
+ SLOGD("Update hardware encryption key to default for crypt_type: %d. rc = %d", crypt_type, rc);
+ if (!rc)
+ return -1;
+ } else {
+ int rc = update_hw_device_encryption_key(newpw, (char*) crypt_ftr.crypto_type_name);
+ SLOGD("Update hardware encryption key for crypt_type: %d. rc = %d", crypt_type, rc);
+ if (!rc)
+ return -1;
+ }
+ }
+#endif
return 0;
}
-static int persist_get_key(char *fieldname, char *value)
+static unsigned int persist_get_max_entries(int encrypted) {
+ struct crypt_mnt_ftr crypt_ftr;
+ unsigned int dsize;
+ unsigned int max_persistent_entries;
+
+ /* If encrypted, use the values from the crypt_ftr, otherwise
+ * use the values for the current spec.
+ */
+ if (encrypted) {
+ if (get_crypt_ftr_and_key(&crypt_ftr)) {
+ return -1;
+ }
+ dsize = crypt_ftr.persist_data_size;
+ } else {
+ dsize = CRYPT_PERSIST_DATA_SIZE;
+ }
+
+ max_persistent_entries = (dsize - sizeof(struct crypt_persist_data)) /
+ sizeof(struct crypt_persist_entry);
+
+ return max_persistent_entries;
+}
+
+static int persist_get_key(const char *fieldname, char *value)
{
unsigned int i;
@@ -3348,31 +3442,17 @@
return -1;
}
-static int persist_set_key(char *fieldname, char *value, int encrypted)
+static int persist_set_key(const char *fieldname, const char *value, int encrypted)
{
unsigned int i;
unsigned int num;
- struct crypt_mnt_ftr crypt_ftr;
unsigned int max_persistent_entries;
- unsigned int dsize;
if (persist_data == NULL) {
return -1;
}
- /* If encrypted, use the values from the crypt_ftr, otherwise
- * use the values for the current spec.
- */
- if (encrypted) {
- if(get_crypt_ftr_and_key(&crypt_ftr)) {
- return -1;
- }
- dsize = crypt_ftr.persist_data_size;
- } else {
- dsize = CRYPT_PERSIST_DATA_SIZE;
- }
- max_persistent_entries = (dsize - sizeof(struct crypt_persist_data)) /
- sizeof(struct crypt_persist_entry);
+ max_persistent_entries = persist_get_max_entries(encrypted);
num = persist_data->persist_valid_entries;
@@ -3397,14 +3477,107 @@
return -1;
}
+/**
+ * Test if key is part of the multi-entry (field, index) sequence. Return non-zero if key is in the
+ * sequence and its index is greater than or equal to index. Return 0 otherwise.
+ */
+static int match_multi_entry(const char *key, const char *field, unsigned index) {
+ unsigned int field_len;
+ unsigned int key_index;
+ field_len = strlen(field);
+
+ if (index == 0) {
+ // The first key in a multi-entry field is just the filedname itself.
+ if (!strcmp(key, field)) {
+ return 1;
+ }
+ }
+ // Match key against "%s_%d" % (field, index)
+ if (strlen(key) < field_len + 1 + 1) {
+ // Need at least a '_' and a digit.
+ return 0;
+ }
+ if (strncmp(key, field, field_len)) {
+ // If the key does not begin with field, it's not a match.
+ return 0;
+ }
+ if (1 != sscanf(&key[field_len],"_%d", &key_index)) {
+ return 0;
+ }
+ return key_index >= index;
+}
+
+/*
+ * Delete entry/entries from persist_data. If the entries are part of a multi-segment field, all
+ * remaining entries starting from index will be deleted.
+ * returns PERSIST_DEL_KEY_OK if deletion succeeds,
+ * PERSIST_DEL_KEY_ERROR_NO_FIELD if the field does not exist,
+ * and PERSIST_DEL_KEY_ERROR_OTHER if error occurs.
+ *
+ */
+static int persist_del_keys(const char *fieldname, unsigned index)
+{
+ unsigned int i;
+ unsigned int j;
+ unsigned int num;
+
+ if (persist_data == NULL) {
+ return PERSIST_DEL_KEY_ERROR_OTHER;
+ }
+
+ num = persist_data->persist_valid_entries;
+
+ j = 0; // points to the end of non-deleted entries.
+ // Filter out to-be-deleted entries in place.
+ for (i = 0; i < num; i++) {
+ if (!match_multi_entry(persist_data->persist_entry[i].key, fieldname, index)) {
+ persist_data->persist_entry[j] = persist_data->persist_entry[i];
+ j++;
+ }
+ }
+
+ if (j < num) {
+ persist_data->persist_valid_entries = j;
+ // Zeroise the remaining entries
+ memset(&persist_data->persist_entry[j], 0, (num - j) * sizeof(struct crypt_persist_entry));
+ return PERSIST_DEL_KEY_OK;
+ } else {
+ // Did not find an entry matching the given fieldname
+ return PERSIST_DEL_KEY_ERROR_NO_FIELD;
+ }
+}
+
+static int persist_count_keys(const char *fieldname)
+{
+ unsigned int i;
+ unsigned int count;
+
+ if (persist_data == NULL) {
+ return -1;
+ }
+
+ count = 0;
+ for (i = 0; i < persist_data->persist_valid_entries; i++) {
+ if (match_multi_entry(persist_data->persist_entry[i].key, fieldname, 0)) {
+ count++;
+ }
+ }
+
+ return count;
+}
+
/* Return the value of the specified field. */
-int cryptfs_getfield(char *fieldname, char *value, int len)
+int cryptfs_getfield(const char *fieldname, char *value, int len)
{
char temp_value[PROPERTY_VALUE_MAX];
- /* 0 is success, 1 is not encrypted,
- * -1 is value not set, -2 is any other error
+ /* CRYPTO_GETFIELD_OK is success,
+ * CRYPTO_GETFIELD_ERROR_NO_FIELD is value not set,
+ * CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL is buffer (as given by len) too small,
+ * CRYPTO_GETFIELD_ERROR_OTHER is any other error
*/
- int rc = -2;
+ int rc = CRYPTO_GETFIELD_ERROR_OTHER;
+ int i;
+ char temp_field[PROPERTY_KEY_MAX];
if (persist_data == NULL) {
load_persistent_data();
@@ -3414,13 +3587,40 @@
}
}
+ // Read value from persistent entries. If the original value is split into multiple entries,
+ // stitch them back together.
if (!persist_get_key(fieldname, temp_value)) {
- /* We found it, copy it to the caller's buffer and return */
- strlcpy(value, temp_value, len);
- rc = 0;
+ // We found it, copy it to the caller's buffer and keep going until all entries are read.
+ if (strlcpy(value, temp_value, len) >= (unsigned) len) {
+ // value too small
+ rc = CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL;
+ goto out;
+ }
+ rc = CRYPTO_GETFIELD_OK;
+
+ for (i = 1; /* break explicitly */; i++) {
+ if (snprintf(temp_field, sizeof(temp_field), "%s_%d", fieldname, i) >=
+ (int) sizeof(temp_field)) {
+ // If the fieldname is very long, we stop as soon as it begins to overflow the
+ // maximum field length. At this point we have in fact fully read out the original
+ // value because cryptfs_setfield would not allow fields with longer names to be
+ // written in the first place.
+ break;
+ }
+ if (!persist_get_key(temp_field, temp_value)) {
+ if (strlcat(value, temp_value, len) >= (unsigned)len) {
+ // value too small.
+ rc = CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL;
+ goto out;
+ }
+ } else {
+ // Exhaust all entries.
+ break;
+ }
+ }
} else {
/* Sadness, it's not there. Return the error */
- rc = -1;
+ rc = CRYPTO_GETFIELD_ERROR_NO_FIELD;
}
out:
@@ -3428,12 +3628,16 @@
}
/* Set the value of the specified field. */
-int cryptfs_setfield(char *fieldname, char *value)
+int cryptfs_setfield(const char *fieldname, const char *value)
{
char encrypted_state[PROPERTY_VALUE_MAX];
- /* 0 is success, -1 is an error */
- int rc = -1;
+ /* 0 is success, negative values are error */
+ int rc = CRYPTO_SETFIELD_ERROR_OTHER;
int encrypted = 0;
+ unsigned int field_id;
+ char temp_field[PROPERTY_KEY_MAX];
+ unsigned int num_entries;
+ unsigned int max_keylen;
if (persist_data == NULL) {
load_persistent_data();
@@ -3448,10 +3652,52 @@
encrypted = 1;
}
- if (persist_set_key(fieldname, value, encrypted)) {
+ // Compute the number of entries required to store value, each entry can store up to
+ // (PROPERTY_VALUE_MAX - 1) chars
+ if (strlen(value) == 0) {
+ // Empty value also needs one entry to store.
+ num_entries = 1;
+ } else {
+ num_entries = (strlen(value) + (PROPERTY_VALUE_MAX - 1) - 1) / (PROPERTY_VALUE_MAX - 1);
+ }
+
+ max_keylen = strlen(fieldname);
+ if (num_entries > 1) {
+ // Need an extra "_%d" suffix.
+ max_keylen += 1 + log10(num_entries);
+ }
+ if (max_keylen > PROPERTY_KEY_MAX - 1) {
+ rc = CRYPTO_SETFIELD_ERROR_FIELD_TOO_LONG;
goto out;
}
+ // Make sure we have enough space to write the new value
+ if (persist_data->persist_valid_entries + num_entries - persist_count_keys(fieldname) >
+ persist_get_max_entries(encrypted)) {
+ rc = CRYPTO_SETFIELD_ERROR_VALUE_TOO_LONG;
+ goto out;
+ }
+
+ // Now that we know persist_data has enough space for value, let's delete the old field first
+ // to make up space.
+ persist_del_keys(fieldname, 0);
+
+ if (persist_set_key(fieldname, value, encrypted)) {
+ // fail to set key, should not happen as we have already checked the available space
+ SLOGE("persist_set_key() error during setfield()");
+ goto out;
+ }
+
+ for (field_id = 1; field_id < num_entries; field_id++) {
+ snprintf(temp_field, sizeof(temp_field), "%s_%d", fieldname, field_id);
+
+ if (persist_set_key(temp_field, value + field_id * (PROPERTY_VALUE_MAX - 1), encrypted)) {
+ // fail to set key, should not happen as we have already checked the available space.
+ SLOGE("persist_set_key() error during setfield()");
+ goto out;
+ }
+ }
+
/* If we are running encrypted, save the persistent data now */
if (encrypted) {
if (save_persistent_data()) {
@@ -3460,7 +3706,7 @@
}
}
- rc = 0;
+ rc = CRYPTO_SETFIELD_OK;
out:
return rc;
@@ -3523,7 +3769,7 @@
char* cryptfs_get_password()
{
struct timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
+ clock_gettime(CLOCK_BOOTTIME, &now);
if (now.tv_sec < password_expiry_time) {
return password;
} else {
diff --git a/cryptfs.h b/cryptfs.h
index 67592a5..8e38213 100644
--- a/cryptfs.h
+++ b/cryptfs.h
@@ -204,6 +204,23 @@
#define ENABLE_INPLACE_ERR_OTHER -1
#define ENABLE_INPLACE_ERR_DEV -2 /* crypto_blkdev issue */
+/* Return values for cryptfs_getfield */
+#define CRYPTO_GETFIELD_OK 0
+#define CRYPTO_GETFIELD_ERROR_NO_FIELD -1
+#define CRYPTO_GETFIELD_ERROR_OTHER -2
+#define CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL -3
+
+/* Return values for cryptfs_setfield */
+#define CRYPTO_SETFIELD_OK 0
+#define CRYPTO_SETFIELD_ERROR_OTHER -1
+#define CRYPTO_SETFIELD_ERROR_FIELD_TOO_LONG -2
+#define CRYPTO_SETFIELD_ERROR_VALUE_TOO_LONG -3
+
+/* Return values for persist_del_key */
+#define PERSIST_DEL_KEY_OK 0
+#define PERSIST_DEL_KEY_ERROR_OTHER -1
+#define PERSIST_DEL_KEY_ERROR_NO_FIELD -2
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -223,8 +240,8 @@
char *crypto_dev_path, unsigned int max_pathlen,
int *new_major, int *new_minor);
int cryptfs_revert_volume(const char *label);
- int cryptfs_getfield(char *fieldname, char *value, int len);
- int cryptfs_setfield(char *fieldname, char *value);
+ int cryptfs_getfield(const char *fieldname, char *value, int len);
+ int cryptfs_setfield(const char *fieldname, const char *value);
int cryptfs_mount_default_encrypted(void);
int cryptfs_get_password_type(void);
char* cryptfs_get_password(void);