clevis-luks-udisks2.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. /* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
  2. /*
  3. * Copyright (c) 2015 Red Hat, Inc.
  4. * Author: Nathaniel McCallum <npmccallum@redhat.com>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <udisks/udisks.h>
  20. #include <glib-unix.h>
  21. #include <luksmeta.h>
  22. #include <sys/types.h>
  23. #include <sys/socket.h>
  24. #include <sys/wait.h>
  25. #include <string.h>
  26. #include <stdbool.h>
  27. #include <stdint.h>
  28. #include <stdio.h>
  29. #include <libaudit.h>
  30. #include <getopt.h>
  31. #include <pwd.h>
  32. #include <grp.h>
  33. #define MAX_UDP 65507
  34. #define UERR ((uid_t) -1)
  35. #define GERR ((gid_t) -1)
  36. typedef struct {
  37. ssize_t used;
  38. char data[MAX_UDP];
  39. } pkt_t;
  40. enum {
  41. PIPE_RD = 0,
  42. PIPE_WR = 1
  43. };
  44. struct context {
  45. UDisksClient *clt;
  46. GMainLoop *loop;
  47. GList *lst;
  48. int sock;
  49. };
  50. static const luksmeta_uuid_t CLEVIS_LUKS_UUID = {
  51. 0xcb, 0x6e, 0x89, 0x04, 0x81, 0xff, 0x40, 0xda,
  52. 0xa8, 0x4a, 0x07, 0xab, 0x9a, 0xb5, 0x71, 0x5e
  53. };
  54. static void
  55. remove_path(GList **lst, const char *path)
  56. {
  57. GList *i = NULL;
  58. while ((i = g_list_find_custom(*lst, path, (GCompareFunc) g_strcmp0))) {
  59. *lst = g_list_remove(*lst, i->data);
  60. g_free(i->data);
  61. }
  62. }
  63. static gboolean
  64. idle(gpointer misc)
  65. {
  66. struct context *ctx = misc;
  67. GVariant *options = NULL;
  68. options = g_variant_new_parsed("@a{sv} { %s: <true> }",
  69. "auth.no_user_interaction");
  70. if (!options)
  71. goto error;
  72. g_variant_ref_sink(options);
  73. for (GList *i = ctx->lst; i; i = i->next) {
  74. UDisksEncrypted *enc = NULL;
  75. const char *path = i->data;
  76. UDisksObject *uobj = NULL;
  77. UDisksBlock *block = NULL;
  78. const char *dev = NULL;
  79. pkt_t pkt = {};
  80. uobj = udisks_client_peek_object(ctx->clt, path);
  81. if (!uobj)
  82. continue;
  83. enc = udisks_object_peek_encrypted(uobj);
  84. if (!enc)
  85. continue;
  86. block = udisks_object_peek_block(uobj);
  87. if (!block)
  88. continue;
  89. dev = udisks_block_get_device(block);
  90. if (!dev)
  91. continue;
  92. pkt.used = strlen(dev) + 1;
  93. if ((size_t) pkt.used > sizeof(pkt.data))
  94. continue;
  95. strcpy(pkt.data, dev);
  96. if (send(ctx->sock, pkt.data, pkt.used, 0) != pkt.used) {
  97. g_main_loop_quit(ctx->loop);
  98. break;
  99. }
  100. memset(&pkt, 0, sizeof(pkt));
  101. pkt.used = recv(ctx->sock, pkt.data, sizeof(pkt.data), 0);
  102. if (pkt.used == 0)
  103. continue;
  104. else if (pkt.used < 0 || (size_t) pkt.used >= sizeof(pkt.data)) {
  105. g_main_loop_quit(ctx->loop);
  106. break;
  107. }
  108. /* NOTE: pkt.data is now implicitly NULL terminated regardless of
  109. * whether or not the plaintext inside the JWE was terminated. */
  110. udisks_encrypted_call_unlock_sync(enc, pkt.data, options,
  111. NULL, NULL, NULL);
  112. memset(&pkt, 0, sizeof(pkt));
  113. }
  114. error:
  115. g_list_free_full(ctx->lst, g_free);
  116. g_variant_unref(options);
  117. ctx->lst = NULL;
  118. return FALSE;
  119. }
  120. static void
  121. oadd(GDBusObjectManager *mgr, GDBusObject *obj, gpointer misc)
  122. {
  123. struct context *ctx = misc;
  124. UDisksObject *uobj = NULL;
  125. const char *path = NULL;
  126. const char *back = NULL;
  127. UDisksBlock *ct = NULL;
  128. UDisksBlock *pt = NULL;
  129. GList *tmp = NULL;
  130. char *ptmp = NULL;
  131. path = g_dbus_object_get_object_path(obj);
  132. if (!path)
  133. return;
  134. uobj = udisks_client_peek_object(ctx->clt, path);
  135. if (!uobj)
  136. return;
  137. ct = udisks_object_peek_block(uobj);
  138. if (!ct)
  139. return;
  140. back = udisks_block_get_crypto_backing_device(ct);
  141. if (back)
  142. remove_path(&ctx->lst, back);
  143. if (!udisks_block_get_hint_auto(ct))
  144. return;
  145. if (!udisks_object_peek_encrypted(uobj))
  146. return;
  147. pt = udisks_client_get_cleartext_block(ctx->clt, ct);
  148. if (pt) {
  149. g_object_unref(pt);
  150. return;
  151. }
  152. ptmp = g_strdup(path);
  153. if (!ptmp)
  154. return;
  155. tmp = g_list_prepend(ctx->lst, ptmp);
  156. if (!tmp) {
  157. g_free(ptmp);
  158. return;
  159. }
  160. ctx->lst = tmp;
  161. g_idle_add(idle, ctx);
  162. }
  163. static void
  164. orem(GDBusObjectManager *mgr, GDBusObject *obj, gpointer misc)
  165. {
  166. struct context *ctx = misc;
  167. remove_path(&ctx->lst, g_dbus_object_get_object_path(obj));
  168. }
  169. static gboolean
  170. sockerr(gint fd, GIOCondition cond, gpointer misc)
  171. {
  172. struct context *ctx = misc;
  173. close(fd);
  174. g_main_loop_quit(ctx->loop);
  175. return FALSE;
  176. }
  177. static int
  178. child_main(int sock)
  179. {
  180. struct context ctx = { .sock = sock };
  181. int exit_status = EXIT_FAILURE;
  182. GDBusObjectManager *mgr = NULL;
  183. gulong id = 0;
  184. ctx.loop = g_main_loop_new(NULL, FALSE);
  185. if (!ctx.loop)
  186. goto error;
  187. ctx.clt = udisks_client_new_sync(NULL, NULL);
  188. if (!ctx.clt)
  189. goto error;
  190. mgr = udisks_client_get_object_manager(ctx.clt);
  191. if (!mgr)
  192. goto error;
  193. id = g_signal_connect(mgr, "object-added", G_CALLBACK(oadd), &ctx);
  194. if (id == 0)
  195. goto error;
  196. id = g_signal_connect(mgr, "object-removed", G_CALLBACK(orem), &ctx);
  197. if (id == 0)
  198. goto error;
  199. id = g_unix_fd_add(sock, G_IO_ERR, sockerr, &ctx);
  200. if (id == 0)
  201. goto error;
  202. g_main_loop_run(ctx.loop);
  203. exit_status = EXIT_SUCCESS;
  204. error:
  205. g_list_free_full(ctx.lst, g_free);
  206. g_main_loop_unref(ctx.loop);
  207. g_object_unref(ctx.clt);
  208. close(sock);
  209. return exit_status;
  210. }
  211. /*
  212. * ==========================================================================
  213. * Caution, code below this point runs with euid = 0!
  214. * ==========================================================================
  215. */
  216. static int pair[2] = { -1, -1 };
  217. pid_t pid = 0;
  218. static void
  219. safeclose(int *fd)
  220. {
  221. if (*fd >= 0)
  222. close(*fd);
  223. *fd = -1;
  224. }
  225. static void
  226. on_signal(int sig)
  227. {
  228. if (sig == SIGCHLD) {
  229. if (wait(NULL) != pid)
  230. return;
  231. pid = -1;
  232. }
  233. safeclose(&pair[0]);
  234. }
  235. static ssize_t
  236. recover_key(const pkt_t *jwe, char *out, size_t max, uid_t uid, gid_t gid)
  237. {
  238. int push[2] = { -1, -1 };
  239. int pull[2] = { -1, -1 };
  240. ssize_t bytes = 0;
  241. pid_t chld = 0;
  242. if (pipe(push) != 0)
  243. goto error;
  244. if (pipe(pull) != 0)
  245. goto error;
  246. chld = fork();
  247. if (chld < 0)
  248. goto error;
  249. if (chld == 0) {
  250. char *const env[] = { "PATH=" BINDIR, NULL };
  251. int r = 0;
  252. if (setgid(gid) != 0 || setegid(gid) != 0)
  253. return EXIT_FAILURE;
  254. if (setuid(uid) != 0 || seteuid(uid) != 0)
  255. return EXIT_FAILURE;
  256. r = dup2(push[PIPE_RD], STDIN_FILENO);
  257. if (r != STDIN_FILENO)
  258. return EXIT_FAILURE;
  259. r = dup2(pull[PIPE_WR], STDOUT_FILENO);
  260. if (r != STDOUT_FILENO)
  261. return EXIT_FAILURE;
  262. safeclose(&push[PIPE_RD]);
  263. safeclose(&push[PIPE_WR]);
  264. safeclose(&pull[PIPE_RD]);
  265. safeclose(&pull[PIPE_WR]);
  266. execle(BINDIR "/clevis", "clevis", "decrypt", NULL, env);
  267. return EXIT_FAILURE;
  268. }
  269. safeclose(&push[PIPE_RD]);
  270. safeclose(&pull[PIPE_WR]);
  271. bytes = write(push[PIPE_WR], jwe->data, jwe->used);
  272. safeclose(&push[PIPE_WR]);
  273. if (bytes < 0 || bytes != jwe->used) {
  274. errno = errno == 0 ? EIO : errno;
  275. kill(chld, SIGTERM);
  276. goto error;
  277. }
  278. bytes = 0;
  279. for (ssize_t block = 1; block > 0; bytes += block) {
  280. block = read(pull[PIPE_RD], &out[bytes], max - bytes);
  281. if (block < 0) {
  282. kill(chld, SIGTERM);
  283. goto error;
  284. }
  285. }
  286. safeclose(&pull[PIPE_RD]);
  287. return bytes;
  288. error:
  289. safeclose(&push[PIPE_RD]);
  290. safeclose(&push[PIPE_WR]);
  291. safeclose(&pull[PIPE_RD]);
  292. safeclose(&pull[PIPE_WR]);
  293. return -errno;
  294. }
  295. static bool
  296. log_attempt(int log, struct crypt_device *cd, bool success)
  297. {
  298. const char *uuid = NULL;
  299. char msg[4096] = {};
  300. char *dev = NULL;
  301. int r = 0;
  302. uuid = crypt_get_uuid(cd);
  303. if (!uuid)
  304. return false;
  305. dev = audit_encode_nv_string("device", crypt_get_device_name(cd), 0);
  306. if (!dev)
  307. return false;
  308. r = snprintf(msg, sizeof(msg),
  309. "op=recovered-key-for uuid=%s %s",
  310. uuid, dev);
  311. free(dev);
  312. if (r < 0 || r == sizeof(msg))
  313. return false;
  314. return audit_log_user_message(log, AUDIT_USER_DEVICE, msg,
  315. NULL, NULL, NULL, success) > 0;
  316. }
  317. static const char *sopts = "hu:g:";
  318. static const struct option lopts[] = {
  319. { "help", no_argument, .val = 'h' },
  320. { "user", required_argument, .val = 'u' },
  321. { "group", required_argument, .val = 'g' },
  322. {}
  323. };
  324. static uid_t
  325. usr2uid(const char *usr) {
  326. const struct passwd *tmp = getpwnam(usr);
  327. return tmp ? tmp->pw_uid : UERR;
  328. }
  329. static gid_t
  330. grp2gid(const char *grp) {
  331. const struct group *tmp = getgrnam(grp);
  332. return tmp ? tmp->gr_gid : GERR;
  333. }
  334. int
  335. main(int argc, char *const argv[])
  336. {
  337. const int slotlen = crypt_keyslot_max(CRYPT_LUKS1);
  338. gid_t recg = grp2gid(CLEVIS_GROUP); /* Recovery group */
  339. uid_t recu = usr2uid(CLEVIS_USER); /* Recovery user */
  340. gid_t unlg = getgid(); /* Unlock group */
  341. uid_t unlu = getuid(); /* Unlock user */
  342. int log = -1;
  343. if (recu == UERR) {
  344. fprintf(stderr, "Invalid user name '%s'!\n", CLEVIS_USER);
  345. return EXIT_FAILURE;
  346. }
  347. if (recg == GERR) {
  348. fprintf(stderr, "Invalid group name '%s'!\n", CLEVIS_GROUP);
  349. return EXIT_FAILURE;
  350. }
  351. if (geteuid() != 0) {
  352. fprintf(stderr, "Root privileges required!\n");
  353. return EXIT_FAILURE;
  354. }
  355. for (int c; (c = getopt_long(argc, argv, sopts, lopts, NULL)) >= 0; ) {
  356. switch (c) {
  357. case 'u':
  358. if (getuid() != 0) {
  359. fprintf(stderr, "You can only specify the user as root!\n");
  360. return EXIT_FAILURE;
  361. }
  362. unlu = usr2uid(optarg);
  363. if (unlu == 0 || unlu == UERR) {
  364. fprintf(stderr, "Invalid user name '%s'!\n", optarg);
  365. return EXIT_FAILURE;
  366. }
  367. break;
  368. case 'g':
  369. if (getuid() != 0) {
  370. fprintf(stderr, "You can only specify the group as root!\n");
  371. return EXIT_FAILURE;
  372. }
  373. unlg = grp2gid(optarg);
  374. if (unlg == 0 || unlg == GERR) {
  375. fprintf(stderr, "Invalid group name '%s'!\n", optarg);
  376. return EXIT_FAILURE;
  377. }
  378. break;
  379. default:
  380. fprintf(stderr, "Usage: clevis-luks-udisks2 [-u USER -g GROUP]\n");
  381. return EXIT_FAILURE;
  382. }
  383. }
  384. if (unlu == 0 || unlg == 0) {
  385. fprintf(stderr, "Either run as SETUID=root or use -u/-g!\n");
  386. return EXIT_FAILURE;
  387. }
  388. if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) == -1)
  389. return EXIT_FAILURE;
  390. pid = fork();
  391. if (pid < 0) {
  392. safeclose(&pair[0]);
  393. safeclose(&pair[1]);
  394. return EXIT_FAILURE;
  395. }
  396. if (pid == 0) {
  397. int status = EXIT_FAILURE;
  398. safeclose(&pair[0]);
  399. if (setgid(unlg) == 0 && setegid(unlg) == 0 &&
  400. setuid(unlu) == 0 && seteuid(unlu) == 0)
  401. status = child_main(pair[1]);
  402. safeclose(&pair[1]);
  403. return status;
  404. }
  405. safeclose(&pair[1]);
  406. signal(SIGHUP, on_signal);
  407. signal(SIGINT, on_signal);
  408. signal(SIGPIPE, on_signal);
  409. signal(SIGTERM, on_signal);
  410. signal(SIGUSR1, on_signal);
  411. signal(SIGUSR2, on_signal);
  412. signal(SIGCHLD, on_signal);
  413. if (setgid(0) == -1 || setegid(0) == -1 ||
  414. setuid(0) == -1 || seteuid(0) == -1)
  415. goto error;
  416. log = audit_open();
  417. if (log < 0)
  418. goto error;
  419. for (pkt_t req = {}, jwe = {}, key = {}; ; key = (pkt_t) {}) {
  420. struct crypt_device *cd = NULL;
  421. luksmeta_uuid_t uuid = {};
  422. int r = 0;
  423. /* Receive a request. Ensure that it is null terminated. */
  424. req.used = recv(pair[0], req.data, sizeof(req.data), 0);
  425. if (req.used < 1 || req.data[req.used - 1])
  426. break;
  427. r = crypt_init(&cd, req.data);
  428. if (r < 0)
  429. goto next;
  430. r = crypt_load(cd, CRYPT_LUKS1, NULL);
  431. if (r < 0)
  432. goto next;
  433. for (uint8_t s = 0; s < slotlen && key.used <= 0; s++) {
  434. fprintf(stderr, "%s\tSLOT\t%hhu\n", req.data, s);
  435. switch (crypt_keyslot_status(cd, s)) {
  436. case CRYPT_SLOT_ACTIVE:
  437. case CRYPT_SLOT_ACTIVE_LAST:
  438. break;
  439. default:
  440. continue;
  441. }
  442. jwe.used = luksmeta_load(cd, s, uuid, jwe.data, sizeof(jwe.data));
  443. if (jwe.used <= 0)
  444. continue;
  445. if (memcmp(uuid, CLEVIS_LUKS_UUID, sizeof(uuid)) != 0)
  446. continue;
  447. fprintf(stderr, "%s\tMETA\t%s\n", req.data,
  448. strerror(jwe.used < 0 ? -jwe.used : 0));
  449. /* Recover the key from the JWE. */
  450. key.used = recover_key(&jwe, key.data, sizeof(key.data), recu, recg);
  451. fprintf(stderr, "%s\tRCVR\t%s (%zd)\n", req.data,
  452. strerror(key.used < 0 ? -key.used : 0), key.used);
  453. }
  454. if (key.used < 0)
  455. key.used = 0;
  456. /* Don't return the key unless auditing succeeds. */
  457. if (!log_attempt(log, cd, key.used > 0))
  458. memset(&key, 0, sizeof(key));
  459. next:
  460. crypt_free(cd);
  461. /* Send the key as a reply. */
  462. if (send(pair[0], key.data, key.used, 0) != key.used)
  463. break;
  464. }
  465. error:
  466. safeclose(&log);
  467. safeclose(&pair[0]);
  468. if (pid != -1) {
  469. kill(pid, SIGTERM);
  470. waitpid(pid, NULL, 0);
  471. }
  472. return EXIT_FAILURE;
  473. }