]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
e4crypt: change the UI to use a subcommand style
authorTheodore Ts'o <tytso@mit.edu>
Mon, 30 Mar 2015 06:11:53 +0000 (02:11 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Mon, 30 Mar 2015 06:13:09 +0000 (02:13 -0400)
Also add a new subcommand "new_session", which works much like keyctl
new_session does.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
misc/e4crypt.8.in
misc/e4crypt.c

index ed7e951b051e784f286fd3ecc95e2efcb895b582..e03f20b5faa129b9f1c872c4aaea236c145f60df 100644 (file)
@@ -1,4 +1,4 @@
-.TH E4CRYPT 8 "Mar 2015" "e4crypt version 1"
+.TH E4CRYPT 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
 .SH NAME
 e4crypt \- ext4 filesystem encryption utility
 .SH SYNOPSIS
@@ -18,40 +18,31 @@ e4crypt \- ext4 filesystem encryption utility
 .SH DESCRIPTION
 .B e4crypt
 performs encryption management for ext4 file systems.
-.SH OPTIONS
+.SH COMMANDS
 .TP
-.B \-a
-Prompts the user for a passphrase and transforms it into an ecryption
-key for use by ext4.   The encryption key will be added to the specified
-keyring, with a type "logon" (which makes the key accessible to the
-user, but which does not allow the key to be returned to userspace), and
-with the descrpiptor of the key set to "ext4:" followed the encryption
-key identifer, which is composed of 16 hexadecimal characters calculated
-by taking a cryptographic hash of the key.
+.B e4crypt add_key -S \fR[\fB -k \fIkeyring\fR ] [\fB-v\fR] [\fB-q\fR] [ \fI path\fR ... ]
+Prompts the user for a passphrase and inserts it into the specified
+keyring.  If no keyring is specified, e4crypt will use the session
+keyring if it exists or the user session keyring if it does not.
+.IP
+If one or more directory paths are specified, e4crypt will try to
+set the policy of those directories to use the key just entered by
+the user.
 .TP
-.BI \-k " keyring"
-This option specifies the keyring to which the key will be added.  See
-the keyctl man page for more details, but the only keyring which only
-makes sense is @u, @s, and @us, which specifies the user, session, and
-user session keyrings, respectively.   By default,
-.B e4crypt
-will add the key to the session keyring if it has been establishd for
-the current process, or the user session keyring if it has not.
-.TP
-.BI \-S " salt"
-The salt must be specified, and it should be unique for each
-passphrase.  The salt consists of up to 256 hexadecimal bytes.
+.B e4crypt new_session
+Give the invoking process (typically a shell) a new session keyring,
+discarding its old session keyring.
 .TP
-.B \-s
-Sets a policy for the directories specified on the command line.
+.B set_policy -s \fIpolicy path\fR ...
+Sets the policy for the directories specified on the command line.
 All directories must be empty to set the policy; if the directory
-already has a policy established,
-.B e4crypt
-will validate that the policy is what was specified.  A policy is an
-encryption key identifier of length 16 hexadecimal characters.
+already has a policy established, e4crypt will validate that it the
+policy matches what was specified.  A policy is an encryption key
+identifier consisting of 16 hexadecimal characters.
 .SH AUTHOR
-Written by Michael Halcrow <mhalcrow@google.com> and Ildar Muslukhov
-<muslukhovi@gmail.com>.
+Written by Michael Halcrow <mhalcrow@google.com>, Ildar Muslukhov
+<muslukhovi@gmail.com>, and Theodore Ts'o <tytso@mit.edu>
 .SH SEE ALSO
+.BR keyctl (1),
 .BR mke2fs (8),
 .BR mount (8).
index 1a9ce9681ae9723f3213f28ef5e308bfe0890d41..1e750799efce285920c24a941951103f848b9220 100644 (file)
 #define KEY_SPEC_GROUP_KEYRING         -6
 
 #define KEYCTL_GET_KEYRING_ID          0
+#define KEYCTL_JOIN_SESSION_KEYRING    1
 #define KEYCTL_DESCRIBE                        6
 #define KEYCTL_SEARCH                  10
+#define KEYCTL_SESSION_TO_PARENT       18
 
 typedef __s32 key_serial_t;
 
@@ -90,10 +92,6 @@ static const size_t hexchars_size = 16;
 #define EXT2FS_KEY_DESC_PREFIX "ext4:"
 #define EXT2FS_KEY_DESC_PREFIX_SIZE 5
 
-#define MSG_USAGE \
-"Usage:\te4crypt -a -S salt [ -k keyring ] [ path ...  ]\n" \
-"\te4crypt -s policy path ...\n"
-
 #define EXT4_IOC_ENCRYPTION_POLICY      _IOW('f', 19, struct ext4_encryption_policy)
 
 static void validate_paths(int argc, char *argv[], int path_start_index)
@@ -583,53 +581,46 @@ void get_default_salts(void)
        endmntent(f);
 }
 
-int main(int argc, char *argv[])
+/* Functions which implement user commands */
+
+struct cmd_desc {
+       const char *cmd_name;
+       void (*cmd_func)(int, char **, const struct cmd_desc *);
+       const char *cmd_desc;
+       const char *cmd_help;
+       int cmd_flags;
+};
+
+#define CMD_HIDDEN     0x0001
+
+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" \
+"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" \
+"If one or more directory paths are specified, e4crypt will try to\n" \
+"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)
 {
-       struct salt *salt, saltbuf;
-       char *key_ref_str = NULL;
+       struct salt *salt;
        char *keyring = NULL;
-       int add_passphrase = 0;
        int i, opt;
 
-       atexit(clear_secrets);
-       if (argc == 1)
-               goto fail;
-       while ((opt = getopt(argc, argv, "ak:s:S:t:vq")) != -1) {
+       while ((opt = getopt(argc, argv, "k:S:vq")) != -1) {
                switch (opt) {
                case 'k':
                        /* Specify a keyring. */
                        keyring = optarg;
                        break;
-               case 'a':
-                       /* Add passphrase-based key to keyring. */
-                       add_passphrase = 1;
-                       break;
-               case 's':
-                       /* Set policy on a directory. */
-                       key_ref_str = optarg;
-                       break;
                case 'S':
                        /* Salt value for passphrase. */
                        parse_salt(optarg, 0);
                        break;
-               case 't': {
-                       uuid_t  uu;
-                       char str[40];
-                       int fd;
-
-                       fd = open(optarg, O_RDONLY | O_DIRECTORY);
-                       if (fd < 0) {
-                               perror(optarg);
-                               exit(1);
-                       }
-                       if (ioctl(fd, EXT4_IOC_GET_ENCRYPTION_PWSALT, &uu) < 0) {
-                               perror("EXT4_IOC_GET_ENCRYPTION_PWSALT");
-                               exit(1);
-                       }
-                       uuid_unparse(uu, str);
-                       printf("Encryption PW Salt: %s\n", str);
-                       exit(0);
-               }
                case 'v':
                        options |= OPT_VERBOSE;
                        break;
@@ -637,65 +628,158 @@ int main(int argc, char *argv[])
                        options |= OPT_QUIET;
                        break;
                default:
-                       printf("Unrecognized option: %c\n", opt);
-                       goto fail;
-               }
-       }
-       if (key_ref_str) {
-               if (add_passphrase) {
-                       printf("-s option invalid with -a\n");
-                       goto fail;
-               }
-               if (keyring) {
-                       printf("-s option invalid with -k\n");
-                       goto fail;
-               }
-               if (num_salt) {
-                       printf("-s option invalid with -n\n");
-                       goto fail;
-               }
-               strcpy(saltbuf.key_ref_str, key_ref_str);
-               if ((strlen(key_ref_str) != (EXT4_KEY_DESCRIPTOR_SIZE * 2)) ||
-                    hex2byte(key_ref_str, (EXT4_KEY_DESCRIPTOR_SIZE * 2),
-                             saltbuf.key_desc, EXT4_KEY_DESCRIPTOR_SIZE)) {
-                       printf("Invalid key descriptor [%s]. Valid characters "
-                              "are 0-9 and a-f, lower case.  "
-                              "Length must be %d.\n",
-                              key_ref_str, (EXT4_KEY_DESCRIPTOR_SIZE * 2));
+                       fprintf(stderr, "Unrecognized option: %c\n", opt);
+               case '?':
+                       fputs("USAGE:\n  ", stderr);
+                       fputs(cmd->cmd_help, stderr);
                        exit(1);
                }
-               if (optind == argc) {
-                       printf("At least one path option must be provided.\n");
-                       exit(1);
-               }
-               validate_paths(argc, argv, optind);
-               set_policy(&saltbuf, argc, argv, optind);
-               exit(0);
        }
-       if (add_passphrase) {
-               if (num_salt == 0)
-                       get_default_salts();
-               if (num_salt == 0) {
-                       fprintf(stderr, "No salt values available\n");
+       if (num_salt == 0)
+               get_default_salts();
+       if (num_salt == 0) {
+               fprintf(stderr, "No salt values available\n");
+               exit(1);
+       }
+       validate_paths(argc, argv, optind);
+       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,
+                             EXT4_PBKDF2_ITERATIONS, salt->key);
+               generate_key_ref_str(salt);
+               insert_key_into_keyring(keyring, salt);
+       }
+       if (optind != argc)
+               set_policy(NULL, 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" \
+"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)
+{
+       struct salt *salt, saltbuf;
+       char *key_ref_str = NULL;
+       char *keyring = NULL;
+       int add_passphrase = 0;
+       int i, opt;
+
+       if (argc < 3) {
+               fprintf(stderr, "Missing required argument(s).\n\n");
+               fputs("USAGE:\n  ", stderr);
+               fputs(cmd->cmd_help, stderr);
+               exit(1);
+       }
+
+       strcpy(saltbuf.key_ref_str, argv[1]);
+       if ((strlen(argv[1]) != (EXT4_KEY_DESCRIPTOR_SIZE * 2)) ||
+           hex2byte(argv[1], (EXT4_KEY_DESCRIPTOR_SIZE * 2),
+                    saltbuf.key_desc, EXT4_KEY_DESCRIPTOR_SIZE)) {
+               printf("Invalid key descriptor [%s]. Valid characters "
+                      "are 0-9 and a-f, lower case.  "
+                      "Length must be %d.\n",
+                      argv[1], (EXT4_KEY_DESCRIPTOR_SIZE * 2));
                        exit(1);
+       }
+       validate_paths(argc, argv, 2);
+       set_policy(&saltbuf, argc, argv, 2);
+       exit(0);
+}
+
+#define new_session_desc "given the invoking process a new session keyring"
+#define new_session_help \
+"e4crypt new_sessoin\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)
+{
+       long keyid, ret;
+
+       if (argc > 1) {
+               fputs("Excess arguments\n\n", stderr);
+               fputs(cmd->cmd_help, stderr);
+               exit(1);
+       }
+       keyid = keyctl(KEYCTL_JOIN_SESSION_KEYRING, NULL);
+       if (keyid < 0) {
+               perror("KEYCTL_JOIN_SESSION_KEYRING");
+               exit(1);
+       }
+       ret = keyctl(KEYCTL_SESSION_TO_PARENT, NULL);
+       if (ret < 0) {
+               perror("KEYCTL_SESSION_TO_PARENT");
+               exit(1);
+       }
+       printf("Switched invoking process to new session keyring %ld\n", keyid);
+       exit(0);
+}
+
+#define CMD(name) { #name, do_##name, name##_desc, name##_help, 0 }
+#define _CMD(name) { #name, do_##name, NULL, NULL, CMD_HIDDEN }
+
+const struct cmd_desc cmd_list[] = {
+       _CMD(help),
+       CMD(add_key),
+       CMD(new_session),
+       CMD(set_policy),
+       { NULL, NULL, NULL, NULL }
+};
+
+void do_help(int argc, char **argv, const struct cmd_desc *cmd)
+{
+       const struct cmd_desc *p;
+
+       if (argc > 1) {
+               for (p = cmd_list; p->cmd_name; p++) {
+                       if (p->cmd_flags & CMD_HIDDEN)
+                               continue;
+                       if (strcmp(p->cmd_name, argv[1]) == 0) {
+                               putc('\n', stdout);
+                               fputs("USAGE:\n  ", stdout);
+                               fputs(p->cmd_help, stdout);
+                               exit(0);
+                       }
                }
-               validate_paths(argc, argv, optind);
-               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,
-                                     EXT4_PBKDF2_ITERATIONS, salt->key);
-                       generate_key_ref_str(salt);
-                       insert_key_into_keyring(keyring, salt);
+               printf("Unknown command: %s\n\n", argv[1]);
+       }
+
+       fputs("Available commands:\n", stdout);
+       for (p = cmd_list; p->cmd_name; p++) {
+               if (p->cmd_flags & CMD_HIDDEN)
+                       continue;
+               printf("  %-20s %s\n", p->cmd_name, p->cmd_desc);
+       }
+       printf("\nTo get more information on a commnd, "
+              "type 'e4crypt help cmd'\n");
+       exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+       const struct cmd_desc *cmd;
+
+       if (argc < 2)
+               do_help(argc, argv, cmd_list);
+
+       for (cmd = cmd_list; cmd->cmd_name; cmd++) {
+               if (strcmp(cmd->cmd_name, argv[1]) == 0) {
+                       cmd->cmd_func(argc-1, argv+1, cmd);
+                       exit(0);
                }
-               if (optind != argc)
-                       set_policy(NULL, argc, argv, optind);
-               clear_secrets();
-               exit(0);
        }
-fail:
-       printf(MSG_USAGE);
-       return 1;
+       printf("Unknown command: %s\n\n", argv[1]);
+       do_help(1, argv, cmd_list);
+       return 0;
 }