int e4crypt_delete_user_key(const char *user_handle) { SLOGD("e4crypt_delete_user_key(\"%s\")", user_handle); auto key_path = get_key_path(DATA_MNT_POINT, user_handle); auto key = e4crypt_get_key(key_path, false); auto ext4_key = fill_key(key); auto ref = keyname(generate_key_ref(ext4_key.raw, ext4_key.size)); auto key_serial = keyctl_search(e4crypt_keyring(), "logon", ref.c_str(), 0); if (keyctl_revoke(key_serial) == 0) { SLOGD("Revoked key with serial %ld ref %s\n", key_serial, ref.c_str()); } else { SLOGE("Failed to revoke key with serial %ld ref %s: %s\n", key_serial, ref.c_str(), strerror(errno)); } int pid = fork(); if (pid < 0) { SLOGE("Unable to fork: %s", strerror(errno)); return -1; } if (pid == 0) { SLOGD("Forked for secdiscard"); execl("/system/bin/secdiscard", "/system/bin/secdiscard", key_path.c_str(), NULL); SLOGE("Unable to launch secdiscard on %s: %s\n", key_path.c_str(), strerror(errno)); exit(-1); } // ext4enc:TODO reap the zombie return 0; }
/* * Revoke a key */ static int key_invalidate(char *keystr, int keymask) { FILE *fp; char buf[BUFSIZ], *ptr; key_serial_t key; int mask; xlog_syslog(0); if ((fp = fopen(PROCKEYS, "r")) == NULL) { xlog_err("fopen(%s) failed: %m", PROCKEYS); return EXIT_FAILURE; } while(fgets(buf, BUFSIZ, fp) != NULL) { if (strstr(buf, "keyring") != NULL) continue; mask = 0; if ((ptr = strstr(buf, "uid:")) != NULL) mask = UIDKEYS; else if ((ptr = strstr(buf, "gid:")) != NULL) mask = GIDKEYS; else continue; if ((keymask & mask) == 0) continue; if (strncmp(ptr+4, keystr, strlen(keystr)) != 0) continue; if (verbose) { *(strchr(buf, '\n')) = '\0'; xlog_warn("invalidating '%s'", buf); } /* * The key is the first arugment in the string */ *(strchr(buf, ' ')) = '\0'; sscanf(buf, "%x", &key); /* older libkeyutils compatibility */ #ifndef KEYCTL_INVALIDATE #define KEYCTL_INVALIDATE 21 /* invalidate a key */ #endif if (keyctl(KEYCTL_INVALIDATE, key) < 0) { if (errno != EOPNOTSUPP) { xlog_err("keyctl_invalidate(0x%x) failed: %m", key); fclose(fp); return EXIT_FAILURE; } else { /* older kernel compatibility attempt: */ if (keyctl_revoke(key) < 0) { xlog_err("keyctl_revoke(0x%x) failed: %m", key); fclose(fp); return EXIT_FAILURE; } } } keymask &= ~mask; if (keymask == 0) { fclose(fp); return EXIT_SUCCESS; } } xlog_err("'%s' key was not found.", keystr); fclose(fp); return EXIT_FAILURE; }
int main(int argc, char *argv[]) { int ret = 1; char *secret_cmd = NULL; char *subprocess_argv[4]; struct sm_opts *opts = NULL; key_serial_t key_id; char key_payload[KEY_PAYLOAD_MAXLEN]; char session_name[SESSION_NAME_MAXLEN]; // parse_opts gives use default values if not provided opts = sm_opts_parse(argc, argv); if (opts == NULL) { ret = 1; goto exit; } if (opts->flags & OPT_HELP || opts->flags & OPT_UNRECOGNIZED) { print_usage(); ret = 0; goto exit; } if (opts->flags & OPT_VERSION) { fprintf(stderr, PACKAGE_NAME " " PACKAGE_VERSION "\n"); ret = 0; goto exit; } // We deal with only one session name for the moment sprintf(session_name, "sm-session-%u", SM_MAGIC); // Start to request a key in the current session if present key_id = request_key("user", session_name, NULL, KEY_SPEC_SESSION_KEYRING); if (opts->flags & OPT_QUIT ) { if (key_id > 0) keyctl_revoke(key_id); else fprintf(stderr, "No keyring session could be found.\n"); ret = 0; goto exit; } if (opts->flags & OPT_SHOW_KEYID) { if (key_id > 0) { printf("%d\n", key_id); ret = 0; goto exit; } else { fprintf(stderr, "No key is attached to the current session.\n"); ret = 1; goto exit; } } if (key_id <= 0) { // Ask the user to enter his secret phrase and memset(key_payload, 0, KEY_PAYLOAD_MAXLEN); sprintf(key_payload, "%s", getpass("Secret: ")); if (strlen(key_payload) == 0) { fprintf(stderr, "An empty secret phrase is not supported.\n"); ret = 1; goto exit; } key_id = add_key("user", session_name, key_payload, strlen(key_payload), KEY_SPEC_SESSION_KEYRING); if (key_id < 0) { fprintf(stderr, "FATAL: Cannot add a passphrase, is CONFIG_KEYS enabled in your kernel?\n"); ret = 1; goto exit; } // To be able to find again the passphrase in the next execution of sm, // we have to attach the current keyring session to the shell // interpreter which executed this cmd keyctl_session_to_parent(); } else { // Read the passphrase memset(key_payload, 0, KEY_PAYLOAD_MAXLEN); if (keyctl_read(key_id, key_payload, KEY_PAYLOAD_MAXLEN) < 0) { ret = 1; goto exit; } } // We should have here a valid key id, so trigger the timeout again keyctl_set_timeout(key_id, (unsigned int) opts->timeout_sec); // Replace all {} occurrences by the secret phrase secret_cmd = replace_str(opts->cmd, opts->repl_str, key_payload); // Execute the secret cmd if (secret_cmd) { // Replacing the current executable image will at least return the exit // code of the executed command subprocess_argv[0] = "sh"; subprocess_argv[1] = "-c"; subprocess_argv[2] = secret_cmd; subprocess_argv[3] = NULL; execvp("/bin/sh", subprocess_argv); assert(0); } exit: if (opts) sm_opts_free(opts); return ret; }
/* * Revoke a key */ static int key_invalidate(char *keystr, int keymask) { FILE *fp; char buf[BUFSIZ], *ptr; key_serial_t key; int mask; xlog_syslog(0); if ((fp = fopen(PROCKEYS, "r")) == NULL) { xlog_err("fopen(%s) failed: %m", PROCKEYS); return 1; } while(fgets(buf, BUFSIZ, fp) != NULL) { if (strstr(buf, "keyring") != NULL) continue; mask = 0; if ((ptr = strstr(buf, "uid:")) != NULL) mask = UIDKEYS; else if ((ptr = strstr(buf, "gid:")) != NULL) mask = GIDKEYS; else continue; if ((keymask & mask) == 0) continue; if (strncmp(ptr+4, keystr, strlen(keystr)) != 0) continue; if (verbose) { *(strchr(buf, '\n')) = '\0'; xlog_warn("invalidating '%s'", buf); } /* * The key is the first arugment in the string */ *(strchr(buf, ' ')) = '\0'; sscanf(buf, "%x", &key); #ifdef HAVE_KEYCTL_INVALIDATE #warning Using keyctl-invalidate (yay!). if (keyctl_invalidate(key) < 0) { xlog_err("keyctl_invalidate(0x%x) failed: %m", key); fclose(fp); return 1; } #else #ifdef HAVE_KEYCTL_REVOKE #warning Using keyctl-revoke because keyctl-invalidate is not available. if (keyctl_revoke(key) < 0) { xlog_err("keyctl_invalidate(0x%x) failed: %m", key); fclose(fp); return 1; } #else #error "Need keyctl_revoke or keyctl_invalidate." #endif #endif keymask &= ~mask; if (keymask == 0) { fclose(fp); return 0; } } xlog_err("'%s' key was not found.", keystr); fclose(fp); return 1; }