X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=misc%2Fe4crypt.c;h=67d25d88dff3a7c33aa0c5afe04ecbdf3731e681;hb=915c3c1e0573632c057185a3153b03d9b04989a0;hp=05bd00b47a7bff20b4ef3eca3831202a8f29d87d;hpb=8beba812a961f9fdf46610ad7fb6df5ba90b5069;p=tools%2Fe2fsprogs.git diff --git a/misc/e4crypt.c b/misc/e4crypt.c index 05bd00b..67d25d8 100644 --- a/misc/e4crypt.c +++ b/misc/e4crypt.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -38,7 +39,12 @@ #include #include #include -#include +#if !defined(HAVE_ADD_KEY) || !defined(HAVE_KEYCTL) +#include +#endif +#ifdef HAVE_SYS_KEY_H +#include +#endif #include "ext2fs/ext2_fs.h" #include "ext2fs/ext2fs.h" @@ -71,6 +77,7 @@ typedef __s32 key_serial_t; int options; +#ifndef HAVE_KEYCTL static long keyctl(int cmd, ...) { va_list va; @@ -84,8 +91,19 @@ static long keyctl(int cmd, ...) va_end(va); return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5); } +#endif + +#ifndef HAVE_ADD_KEY +static key_serial_t add_key(const char *type, const char *description, + const void *payload, size_t plen, + key_serial_t keyring) +{ + return syscall(__NR_add_key, type, description, payload, + plen, keyring); +} +#endif -static const char *hexchars = "0123456789abcdef"; +static const unsigned char *hexchars = (const unsigned char *) "0123456789abcdef"; static const size_t hexchars_size = 16; #define SHA512_LENGTH 64 @@ -134,11 +152,11 @@ static void validate_paths(int argc, char *argv[], int path_start_index) exit(1); } -static int hex2byte(const char *hex, size_t hex_size, char *bytes, +static int hex2byte(const char *hex, size_t hex_size, unsigned char *bytes, size_t bytes_size) { - int x; - char *h, *l; + size_t x; + unsigned char *h, *l; if (hex_size % 2) return -EINVAL; @@ -170,11 +188,11 @@ struct salt { struct salt *salt_list; unsigned num_salt; unsigned max_salt; -char passphrase[EXT4_MAX_PASSPHRASE_SIZE]; +char in_passphrase[EXT4_MAX_PASSPHRASE_SIZE]; static struct salt *find_by_salt(unsigned char *salt, size_t salt_len) { - int i; + unsigned int i; struct salt *p; for (i = 0, p = salt_list; i < num_salt; i++, p++) @@ -208,17 +226,18 @@ static void clear_secrets(void) free(salt_list); salt_list = NULL; } - memset(passphrase, 0, sizeof(passphrase)); + memset(in_passphrase, 0, sizeof(in_passphrase)); } -static void die_signal_handler(int signum, siginfo_t *siginfo, - void *context) +static void die_signal_handler(int signum EXT2FS_ATTR((unused)), + siginfo_t *siginfo EXT2FS_ATTR((unused)), + void *context EXT2FS_ATTR((unused))) { clear_secrets(); exit(-1); } -void sigcatcher_setup(void) +static void sigcatcher_setup(void) { struct sigaction sa; @@ -255,9 +274,9 @@ void sigcatcher_setup(void) static void parse_salt(char *salt_str, int flags) { unsigned char buf[EXT4_MAX_SALT_SIZE]; - unsigned char *salt_buf, *cp = salt_str; - char tmp[80]; - int i, fd, ret, salt_len = 0; + char *cp = salt_str; + unsigned char *salt_buf; + int fd, ret, salt_len = 0; if (flags & PARSE_FLAGS_FORCE_FN) goto salt_from_filename; @@ -266,7 +285,7 @@ static void parse_salt(char *salt_str, int flags) salt_len = strlen(cp); if (salt_len >= EXT4_MAX_SALT_SIZE) goto invalid_salt; - strncpy(buf, cp, sizeof(buf)); + strncpy((char *) buf, cp, sizeof(buf)); } else if (cp[0] == '/') { salt_from_filename: fd = open(cp, O_RDONLY | O_DIRECTORY); @@ -294,7 +313,7 @@ static void parse_salt(char *salt_str, int flags) cp += 2; goto salt_from_filename; } else if (strncmp(cp, "0x", 2) == 0) { - char *h, *l; + unsigned char *h, *l; cp += 2; if (strlen(cp) & 1) @@ -302,7 +321,7 @@ static void parse_salt(char *salt_str, int flags) while (*cp) { if (salt_len >= EXT4_MAX_SALT_SIZE) goto invalid_salt; - h = memchr(hexchars, *cp++, sizeof(hexchars)); + h = memchr(hexchars, *cp++, hexchars_size); l = memchr(hexchars, *cp++, hexchars_size); if (!h || !l) goto invalid_salt; @@ -384,27 +403,28 @@ static void set_policy(struct salt *set_salt, int pad, } } -static void pbkdf2_sha512(const char *passphrase, struct salt *salt, int count, - char derived_key[EXT4_MAX_KEY_SIZE]) +static void pbkdf2_sha512(const char *passphrase, struct salt *salt, + unsigned int count, + unsigned char derived_key[EXT4_MAX_KEY_SIZE]) { size_t passphrase_size = strlen(passphrase); - char buf[SHA512_LENGTH + EXT4_MAX_PASSPHRASE_SIZE] = {0}; - char tempbuf[SHA512_LENGTH] = {0}; + unsigned char buf[SHA512_LENGTH + EXT4_MAX_PASSPHRASE_SIZE] = {0}; + unsigned char tempbuf[SHA512_LENGTH] = {0}; char final[SHA512_LENGTH] = {0}; - char saltbuf[EXT4_MAX_SALT_SIZE + EXT4_MAX_PASSPHRASE_SIZE] = {0}; + unsigned char saltbuf[EXT4_MAX_SALT_SIZE + EXT4_MAX_PASSPHRASE_SIZE] = {0}; int actual_buf_len = SHA512_LENGTH + passphrase_size; int actual_saltbuf_len = EXT4_MAX_SALT_SIZE + passphrase_size; - int x, y; + unsigned int x, y; __u32 *final_u32 = (__u32 *)final; __u32 *temp_u32 = (__u32 *)tempbuf; if (passphrase_size > EXT4_MAX_PASSPHRASE_SIZE) { - printf("Passphrase size is %d; max is %d.\n", passphrase_size, + printf("Passphrase size is %zd; max is %d.\n", passphrase_size, EXT4_MAX_PASSPHRASE_SIZE); exit(1); } if (salt->salt_len > EXT4_MAX_SALT_SIZE) { - printf("Salt size is %d; max is %d.\n", salt->salt_len, + printf("Salt size is %zd; max is %d.\n", salt->salt_len, EXT4_MAX_SALT_SIZE); exit(1); } @@ -446,7 +466,7 @@ static int disable_echo(struct termios *saved_settings) return rc; } -void get_passphrase(char *passphrase, int len) +static void get_passphrase(char *passphrase, int len) { char *p; struct termios current_settings; @@ -483,35 +503,23 @@ static const struct keyring_map keyrings[] = { static int get_keyring_id(const char *keyring) { - int x; + unsigned int x; char *end; /* * If no keyring is specified, by default use either the user - * session key ring or the session keyring. Fetching the + * session keyring or the session keyring. Fetching the * session keyring will return the user session keyring if no * session keyring has been set. - * - * We need to do this instead of simply adding the key to - * KEY_SPEC_SESSION_KEYRING since trying to add a key to a - * session keyring that does not yet exist will cause the - * kernel to create a session keyring --- which wil then get - * garbage collected as soon as e4crypt exits. - * - * The fact that the keyctl system call and the add_key system - * call treats KEY_SPEC_SESSION_KEYRING differently when a - * session keyring does not exist is very unfortunate and - * confusing, but so it goes... */ if (keyring == NULL) - return keyctl(KEYCTL_GET_KEYRING_ID, - KEY_SPEC_SESSION_KEYRING, 0); + return KEY_SPEC_SESSION_KEYRING; for (x = 0; x < (sizeof(keyrings) / sizeof(keyrings[0])); ++x) { if (strcmp(keyring, keyrings[x].name) == 0) { return keyrings[x].code; } } - x = strtol(keyring, &end, 10); + x = strtoul(keyring, &end, 10); if (*end == '\0') { if (keyctl(KEYCTL_DESCRIBE, x, NULL, 0) < 0) return 0; @@ -522,8 +530,8 @@ static int get_keyring_id(const char *keyring) static void generate_key_ref_str(struct salt *salt) { - char key_ref1[SHA512_LENGTH]; - char key_ref2[SHA512_LENGTH]; + unsigned char key_ref1[SHA512_LENGTH]; + unsigned char key_ref2[SHA512_LENGTH]; int x; ext2fs_sha512(salt->key, EXT4_MAX_KEY_SIZE, key_ref1); @@ -559,15 +567,36 @@ static void insert_key_into_keyring(const char *keyring, struct salt *salt) return; } else if ((rc == -1) && (errno != ENOKEY)) { printf("keyctl_search failed: %s\n", strerror(errno)); - if (errno == -EINVAL) + if (errno == EINVAL) printf("Keyring [%s] is not available.\n", keyring); exit(1); } key.mode = EXT4_ENCRYPTION_MODE_AES_256_XTS; memcpy(key.raw, salt->key, EXT4_MAX_KEY_SIZE); key.size = EXT4_MAX_KEY_SIZE; - rc = syscall(__NR_add_key, EXT2FS_KEY_TYPE_LOGON, key_ref_full, - (void *)&key, sizeof(key), keyring_id); + + /* + * We need to do this instead of simply adding the key to + * KEY_SPEC_SESSION_KEYRING since trying to add a key to a + * session keyring that does not yet exist will cause the + * kernel to create a session keyring --- which will then get + * garbage collected as soon as e4crypt exits. + * + * The fact that the keyctl system call and the add_key system + * call treats KEY_SPEC_SESSION_KEYRING differently when a + * session keyring does not exist is very unfortunate and + * confusing, but so it goes... + */ + if (keyring_id == KEY_SPEC_SESSION_KEYRING) { + keyring_id = keyctl(KEYCTL_GET_KEYRING_ID, keyring_id, 0); + if (keyring_id < 0) { + printf("Error getting session keyring ID: %s\n", + strerror(errno)); + exit(1); + } + } + rc = add_key(EXT2FS_KEY_TYPE_LOGON, key_ref_full, (void *)&key, + sizeof(key), keyring_id); if (rc == -1) { if (errno == EDQUOT) { printf("Error adding key to keyring; quota exceeded\n"); @@ -583,12 +612,7 @@ static void insert_key_into_keyring(const char *keyring, struct salt *salt) } } -static int is_keyring_valid(const char *keyring) -{ - return (get_keyring_id(keyring) != 0); -} - -void get_default_salts(void) +static void get_default_salts(void) { FILE *f = setmntent("/etc/mtab", "r"); struct mntent *mnt; @@ -614,11 +638,11 @@ struct cmd_desc { #define CMD_HIDDEN 0x0001 -void do_help(int argc, char **argv, const struct cmd_desc *cmd); +static void do_help(int argc, char **argv, const struct cmd_desc *cmd); #define add_key_desc "adds a key to the user's keyring" #define add_key_help \ -"e4crypt add_key -S salt [ -k keyring ] [-v] [-q] [ path ... ]\n\n" \ +"e4crypt add_key -S salt [ -k keyring ] [-v] [-q] [ -p pad ] [ path ... ]\n\n" \ "Prompts the user for a passphrase and inserts it into the specified\n" \ "keyring. If no keyring is specified, e4crypt will use the session\n" \ "keyring if it exists or the user session keyring if it does not.\n\n" \ @@ -626,11 +650,13 @@ void do_help(int argc, char **argv, const struct cmd_desc *cmd); "set the policy of those directories to use the key just entered by\n" \ "the user.\n" -void do_add_key(int argc, char **argv, const struct cmd_desc *cmd) +static void do_add_key(int argc, char **argv, const struct cmd_desc *cmd) { struct salt *salt; + bool explicit_salt = false; char *keyring = NULL; int i, opt, pad = 4; + unsigned j; while ((opt = getopt(argc, argv, "k:S:p:vq")) != -1) { switch (opt) { @@ -642,8 +668,13 @@ void do_add_key(int argc, char **argv, const struct cmd_desc *cmd) pad = atoi(optarg); break; case 'S': + if (explicit_salt) { + fputs("May only provide -S once\n", stderr); + exit(1); + } /* Salt value for passphrase. */ parse_salt(optarg, 0); + explicit_salt = true; break; case 'v': options |= OPT_VERBOSE; @@ -652,8 +683,10 @@ void do_add_key(int argc, char **argv, const struct cmd_desc *cmd) options |= OPT_QUIET; break; default: - fprintf(stderr, "Unrecognized option: %c\n", opt); case '?': + if (opt != '?') + fprintf(stderr, "Unrecognized option: %c\n", + opt); fputs("USAGE:\n ", stderr); fputs(cmd->cmd_help, stderr); exit(1); @@ -666,38 +699,38 @@ void do_add_key(int argc, char **argv, const struct cmd_desc *cmd) exit(1); } validate_paths(argc, argv, optind); - for (i = optind; i < argc; i++) - parse_salt(argv[i], PARSE_FLAGS_FORCE_FN); + if (!explicit_salt) + for (i = optind; i < argc; i++) + parse_salt(argv[i], PARSE_FLAGS_FORCE_FN); printf("Enter passphrase (echo disabled): "); - get_passphrase(passphrase, sizeof(passphrase)); - for (i = 0, salt = salt_list; i < num_salt; i++, salt++) { - pbkdf2_sha512(passphrase, salt, + get_passphrase(in_passphrase, sizeof(in_passphrase)); + for (j = 0, salt = salt_list; j < num_salt; j++, salt++) { + pbkdf2_sha512(in_passphrase, salt, EXT4_PBKDF2_ITERATIONS, salt->key); generate_key_ref_str(salt); insert_key_into_keyring(keyring, salt); } - if (optind != argc) - set_policy(NULL, pad, argc, argv, optind); + if (optind != argc) { + salt = explicit_salt ? salt_list : NULL; + set_policy(salt, pad, argc, argv, optind); + } clear_secrets(); exit(0); } #define set_policy_desc "sets a policy for directories" #define set_policy_help \ -"e4crypt set_policy policy path ... \n\n" \ +"e4crypt set_policy [ -p pad ] policy path ... \n\n" \ "Sets the policy for the directories specified on the command line.\n" \ "All directories must be empty to set the policy; if the directory\n" \ "already has a policy established, e4crypt will validate that it the\n" \ "policy matches what was specified. A policy is an encryption key\n" \ "identifier consisting of 16 hexadecimal characters.\n" -void do_set_policy(int argc, char **argv, const struct cmd_desc *cmd) +static void do_set_policy(int argc, char **argv, const struct cmd_desc *cmd) { - struct salt *salt, saltbuf; - char *key_ref_str = NULL; - char *keyring = NULL; - int add_passphrase = 0; - int i, c, opt, pad = 4; + struct salt saltbuf; + int c, pad = 4; while ((c = getopt (argc, argv, "p:")) != EOF) { switch (c) { @@ -714,10 +747,6 @@ void do_set_policy(int argc, char **argv, const struct cmd_desc *cmd) exit(1); } - printf("arg %s\n", argv[optind]); - exit(0); - - strcpy(saltbuf.key_ref_str, argv[optind]); if ((strlen(argv[optind]) != (EXT4_KEY_DESCRIPTOR_SIZE * 2)) || hex2byte(argv[optind], (EXT4_KEY_DESCRIPTOR_SIZE * 2), saltbuf.key_desc, EXT4_KEY_DESCRIPTOR_SIZE)) { @@ -728,6 +757,7 @@ void do_set_policy(int argc, char **argv, const struct cmd_desc *cmd) exit(1); } validate_paths(argc, argv, optind+1); + strcpy(saltbuf.key_ref_str, argv[optind]); set_policy(&saltbuf, pad, argc, argv, optind+1); exit(0); } @@ -737,10 +767,9 @@ void do_set_policy(int argc, char **argv, const struct cmd_desc *cmd) "e4crypt get_policy path ... \n\n" \ "Gets the policy for the directories specified on the command line.\n" -void do_get_policy(int argc, char **argv, const struct cmd_desc *cmd) +static void do_get_policy(int argc, char **argv, const struct cmd_desc *cmd) { struct ext4_encryption_policy policy; - struct stat st; int i, j, fd, rc; if (argc < 2) { @@ -751,12 +780,7 @@ void do_get_policy(int argc, char **argv, const struct cmd_desc *cmd) } for (i = 1; i < argc; i++) { - if (stat(argv[i], &st) < 0) { - perror(argv[i]); - continue; - } - fd = open(argv[i], - S_ISDIR(st.st_mode) ? O_DIRECTORY : O_RDONLY); + fd = open(argv[i], O_RDONLY); if (fd == -1) { perror(argv[i]); exit(1); @@ -777,13 +801,14 @@ void do_get_policy(int argc, char **argv, const struct cmd_desc *cmd) exit(0); } -#define new_session_desc "given the invoking process a new session keyring" +#define new_session_desc "give the invoking process a new session keyring" #define new_session_help \ -"e4crypt new_sessoin\n\n" \ +"e4crypt new_session\n\n" \ "Give the invoking process (typically a shell) a new session keyring,\n" \ "discarding its old session keyring.\n" -void do_new_session(int argc, char **argv, const struct cmd_desc *cmd) +static void do_new_session(int argc, char **argv EXT2FS_ATTR((unused)), + const struct cmd_desc *cmd) { long keyid, ret; @@ -815,10 +840,11 @@ const struct cmd_desc cmd_list[] = { CMD(get_policy), CMD(new_session), CMD(set_policy), - { NULL, NULL, NULL, NULL } + { NULL, NULL, NULL, NULL, 0 } }; -void do_help(int argc, char **argv, const struct cmd_desc *cmd) +static void do_help(int argc, char **argv, + const struct cmd_desc *cmd EXT2FS_ATTR((unused))) { const struct cmd_desc *p; @@ -842,7 +868,7 @@ void do_help(int argc, char **argv, const struct cmd_desc *cmd) continue; printf(" %-20s %s\n", p->cmd_name, p->cmd_desc); } - printf("\nTo get more information on a commnd, " + printf("\nTo get more information on a command, " "type 'e4crypt help cmd'\n"); exit(0); } @@ -854,6 +880,7 @@ int main(int argc, char *argv[]) if (argc < 2) do_help(argc, argv, cmd_list); + sigcatcher_setup(); for (cmd = cmd_list; cmd->cmd_name; cmd++) { if (strcmp(cmd->cmd_name, argv[1]) == 0) { cmd->cmd_func(argc-1, argv+1, cmd);