[5/5] ui/ncurses: Add prompt for LUKS device password
diff mbox series

Message ID 20190215003603.16285-6-sam@mendozajonas.com
State Accepted
Headers show
Series
  • Support for dm-crypt LUKS devices
Related show

Commit Message

Samuel Mendoza-Jonas Feb. 15, 2019, 12:36 a.m. UTC
Implement device_add() in cui_client_ops and use this interface to
recognise when the server notifies the client of an encrypted device. A
"device header" will be created for this device and added to the menu
with no associated boot options.

The nc-auth prompt is extended to ask for a disk password when the device
header for an encrypted device is selected.
Assuming the password is correct pb-discover will remove the original
device and notify the client about the newly opened device, which will
be reflected in the menu.

Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
 ui/common/discover-client.c |  25 ++++++
 ui/common/discover-client.h |   3 +
 ui/ncurses/nc-auth.c        |  30 ++++++-
 ui/ncurses/nc-auth.h        |   1 +
 ui/ncurses/nc-cui.c         | 166 +++++++++++++++++++++++++++++++++++-
 ui/ncurses/nc-cui.h         |   3 +
 6 files changed, 220 insertions(+), 8 deletions(-)

Patch
diff mbox series

diff --git a/ui/common/discover-client.c b/ui/common/discover-client.c
index e7dfb831..6dda2d32 100644
--- a/ui/common/discover-client.c
+++ b/ui/common/discover-client.c
@@ -552,3 +552,28 @@  int discover_client_send_set_password(struct discover_client *client,
 	pb_log("sending auth message..\n");
 	return pb_protocol_write_message(client->fd, message);
 }
+
+int discover_client_send_open_luks_device(struct discover_client *client,
+		char *password, char *device_id)
+{
+	struct pb_protocol_message *message;
+	struct auth_message auth_msg;
+	int len;
+
+	auth_msg.op = AUTH_MSG_DECRYPT;
+	auth_msg.decrypt_dev.password = password;
+	auth_msg.decrypt_dev.device_id = device_id;
+
+	len = pb_protocol_authenticate_len(&auth_msg);
+
+	message = pb_protocol_create_message(client,
+				PB_PROTOCOL_ACTION_AUTHENTICATE, len);
+	if (!message)
+		return -1;
+
+	pb_log("serialising auth message..\n");
+	pb_protocol_serialise_authenticate(&auth_msg, message->payload, len);
+
+	pb_log("sending auth message..\n");
+	return pb_protocol_write_message(client->fd, message);
+}
diff --git a/ui/common/discover-client.h b/ui/common/discover-client.h
index 9b56dcb7..183d1935 100644
--- a/ui/common/discover-client.h
+++ b/ui/common/discover-client.h
@@ -113,6 +113,9 @@  int discover_client_send_authenticate(struct discover_client *client,
 /* Set a new system password, authenticating with the current password */
 int discover_client_send_set_password(struct discover_client *client,
 		char *password, char *new_password);
+/* Send a password to open an encrypted device */
+int discover_client_send_open_luks_device(struct discover_client *client,
+		char *password, char *device_id);
 
 /* send a temporary autoboot override */
 int discover_client_send_temp_autoboot(struct discover_client *client,
diff --git a/ui/ncurses/nc-auth.c b/ui/ncurses/nc-auth.c
index 5bfda8b4..227c57bf 100644
--- a/ui/ncurses/nc-auth.c
+++ b/ui/ncurses/nc-auth.c
@@ -42,6 +42,7 @@  struct auth_screen {
 	void 			(*process_key)(struct nc_scr *, int);
 
 	bool			set_password;
+	const struct device	*dev;
 	void			(*callback)(struct nc_scr *);
 	int			offset_y;
 	int			label_x;
@@ -144,6 +145,9 @@  static void ok_click(void *arg)
 	if (screen->set_password) {
 		new_password = widget_textbox_get_value(screen->widgets.new_f);
 		rc = cui_send_set_password(screen->cui, password, new_password);
+	} else if (screen->dev) {
+		rc = cui_send_open_luks_device(screen->cui, password,
+				screen->dev->id);
 	} else
 		rc = cui_send_authenticate(screen->cui, password);
 
@@ -194,6 +198,7 @@  static void auth_screen_layout_widgets(struct auth_screen *screen)
 static void auth_screen_draw(struct auth_screen *screen)
 {
 	struct nc_widgetset *set;
+	char *label;
 
 	set = widgetset_create(screen, screen->scr.main_ncw,
 			screen->scr.sub_ncw);
@@ -203,10 +208,20 @@  static void auth_screen_draw(struct auth_screen *screen)
 	}
 	screen->widgetset = set;
 
-	screen->widgets.title_a_l = widget_new_label(set, 0, 0,
-			_("This action requires authorisation."));
-	screen->widgets.title_b_l = widget_new_label(set, 0, 0,
-			_("Please enter the system password."));
+	if (screen->dev) {
+		label = talloc_asprintf(screen,
+				_("Opening encrypted device %s"),
+				screen->dev->id);
+		screen->widgets.title_a_l = widget_new_label(set, 0, 0, label);
+		screen->widgets.title_b_l = widget_new_label(set, 0, 0,
+				_("Please enter the disk password."));
+		talloc_free(label);
+	} else {
+		screen->widgets.title_a_l = widget_new_label(set, 0, 0,
+				_("This action requires authorisation."));
+		screen->widgets.title_b_l = widget_new_label(set, 0, 0,
+				_("Please enter the system password."));
+	}
 
 	screen->widgets.password_f = widget_new_textbox_hidden(set, 0, 0,
 			COLS - 20 - 20, "", true);
@@ -236,6 +251,7 @@  static int auth_screen_destroy(void *arg)
 
 struct auth_screen *auth_screen_init(struct cui *cui,
 		WINDOW *parent, bool set_password,
+		const struct device *dev,
 		void (*callback)(struct nc_scr *),
 		void (*on_exit)(struct cui *))
 {
@@ -246,6 +262,11 @@  struct auth_screen *auth_screen_init(struct cui *cui,
 	if (!cui || !parent)
 		return NULL;
 
+	if (set_password && dev) {
+		pb_log_fn("Incorrect parameters (set_password and device)\n");
+		return NULL;
+	}
+
 	screen = talloc_zero(cui, struct auth_screen);
 	if (!screen)
 		return NULL;
@@ -254,6 +275,7 @@  struct auth_screen *auth_screen_init(struct cui *cui,
 	screen->cui = cui;
 	screen->return_scr = cui->current;
 	screen->set_password = set_password;
+	screen->dev = dev;
 	screen->callback = callback;
 	screen->on_exit = on_exit;
 	screen->label_x = 5;
diff --git a/ui/ncurses/nc-auth.h b/ui/ncurses/nc-auth.h
index e8e41482..0473c922 100644
--- a/ui/ncurses/nc-auth.h
+++ b/ui/ncurses/nc-auth.h
@@ -24,6 +24,7 @@  struct auth_screen;
 
 struct auth_screen *auth_screen_init(struct cui *cui,
 		WINDOW *pad, bool set_password,
+		const struct device *dev,
 		void (callback)(struct nc_scr *),
 		void (*on_exit)(struct cui *));
 
diff --git a/ui/ncurses/nc-cui.c b/ui/ncurses/nc-cui.c
index d80e2c3e..ae5e9bc6 100644
--- a/ui/ncurses/nc-cui.c
+++ b/ui/ncurses/nc-cui.c
@@ -360,7 +360,7 @@  static int menu_reinit_execute(struct pmenu_item *item)
 		return 0;
 
 	cui->auth_screen = auth_screen_init(cui, cui->current->main_ncw,
-			false, menu_reinit_cb, cui_auth_exit);
+			false, NULL, menu_reinit_cb, cui_auth_exit);
 
 	if (cui->auth_screen)
 		cui_set_current(cui, auth_screen_scr(cui->auth_screen));
@@ -407,6 +407,35 @@  static int cui_boot_check(struct pmenu_item *item)
 	return 0;
 }
 
+static void cui_luks_cb(struct nc_scr *scr)
+{
+	struct cui_opt_data *cod;
+	struct pmenu_item *item;
+	struct pmenu *menu;
+	struct cui *cui;
+
+	menu = pmenu_from_scr(scr);
+	item = pmenu_find_selected(menu);
+	cod = cod_from_item(item);
+	cui = cui_from_item(item);
+
+	cui_show_open_luks(cui, scr->main_ncw, cod->dev);
+}
+
+static int cui_open_luks_device(struct pmenu_item *item)
+{
+	struct cui_opt_data *cod = cod_from_item(item);
+	struct cui *cui = cui_from_item(item);
+
+	if (discover_client_authenticated(cui->client))
+		cui_show_open_luks(cui, item->pmenu->scr.main_ncw, cod->dev);
+	else
+		cui_show_auth(cui, item->pmenu->scr.main_ncw, false,
+				cui_luks_cb);
+
+	return 0;
+}
+
 static void cui_boot_editor_on_exit(struct cui *cui,
 		struct pmenu_item *item,
 		struct pb_boot_data *bd)
@@ -707,13 +736,28 @@  void cui_show_auth(struct cui *cui, WINDOW *parent, bool set_password,
 	if (cui->auth_screen)
 		return;
 
-	cui->auth_screen = auth_screen_init(cui, parent, set_password,
+	cui->auth_screen = auth_screen_init(cui, parent, set_password, NULL,
 			callback, cui_auth_exit);
 
 	if (cui->auth_screen)
 		cui_set_current(cui, auth_screen_scr(cui->auth_screen));
 }
 
+void cui_show_open_luks(struct cui *cui, WINDOW *parent,
+		const struct device *dev)
+{
+	if (!cui->current)
+		return;
+
+	if (cui->auth_screen)
+		return;
+
+	cui->auth_screen = auth_screen_init(cui, parent, false, dev,
+			NULL, cui_auth_exit);
+
+	if (cui->auth_screen)
+		cui_set_current(cui, auth_screen_scr(cui->auth_screen));
+}
 /**
  * cui_set_current - Set the currently active screen and redraw it.
  */
@@ -899,7 +943,7 @@  static void cui_handle_resize(struct cui *cui)
 }
 
 /**
- * cui_device_add - Client device_add callback.
+ * cui_boot_option_add - Client boot_option_add callback.
  *
  * Creates menu_items for all the device boot_options and inserts those
  * menu_items into the main menu.  Redraws the main menu if it is active.
@@ -1080,6 +1124,114 @@  static int cui_boot_option_add(struct device *dev, struct boot_option *opt,
 	return 0;
 }
 
+/**
+ * cui_device_add - Client device_add callback
+ *
+ * For ncurses this is only used to specially handle encrypted devices and
+ * create a special device header for them.
+ * Normal devices are handled as part of the cui_boot_option_add() process.
+ */
+static int cui_device_add(struct device *dev, void *arg)
+{
+	struct cui *cui = cui_from_arg(arg);
+	struct pmenu *menu = cui->main;
+	struct pmenu_item *dev_hdr;
+	unsigned int insert_pt, i;
+	struct cui_opt_data *cod;
+	struct blockdev_info *bd;
+	struct system_info *sys;
+	int result, rows, cols;
+	ITEM *selected;
+	char *name;
+
+	/* Nothing to do */
+	if (dev->type != DEVICE_TYPE_LUKS) {
+		pb_log("Ignoring dev %s with type %s\n",
+				dev->id, device_type_display_name(dev->type));
+		return 0;
+	}
+
+	pb_log("Creating header for encrypted device %s\n", dev->id);
+
+	/* Create a dev_hdr for the encrypted device */
+	/* Find block info */
+	sys = cui->sysinfo;
+	name = NULL;
+	for (i = 0; sys && i < sys->n_blockdevs; i++) {
+		bd = sys->blockdevs[i];
+		if (!strcmp(dev->id, bd->name)) {
+			name = talloc_asprintf(menu, "[%s: %s / %s]",
+				device_type_display_name(dev->type),
+				bd->name, bd->uuid);
+			break;
+		}
+	}
+	if (!name) {
+		name = talloc_asprintf(menu, "[%s: \"%s\"]",
+			device_type_display_name(dev->type),
+			dev->id);
+	}
+
+	dev_hdr = pmenu_item_create(menu, name);
+	if (!dev_hdr) {
+		pb_log_fn("Failed to create header item\n");
+		return -1;
+	}
+	talloc_free(name);
+
+	dev_hdr->on_execute = cui_open_luks_device;
+
+	cod = talloc_zero(dev_hdr, struct cui_opt_data);
+	cod->name = talloc_strdup(dev_hdr, dev->id);
+	cod->dev = dev;
+	dev_hdr->data = cod;
+
+	if (cui->current == &cui->main->scr)
+		nc_scr_unpost(cui->current);
+
+	/* This disconnects items array from menu. */
+	result = set_menu_items(menu->ncm, NULL);
+
+	if (result) {
+		pb_log_fn("set_menu_items failed: %d\n", result);
+		return -1;
+	}
+
+
+	insert_pt = pmenu_grow(menu, 1);
+	pmenu_item_insert(menu, dev_hdr, insert_pt);
+	pb_log("Added header for encrypted device %s\n", dev->id);
+
+	selected = current_item(menu->ncm);
+	menu_format(menu->ncm, &rows, &cols);
+
+	/* Re-attach the items array. */
+	result = set_menu_items(menu->ncm, menu->items);
+
+	if (result)
+		pb_log_fn("set_menu_items failed: %d\n", result);
+
+	if (!item_visible(selected)) {
+		int idx, top;
+
+		top = top_row(menu->ncm);
+		idx = item_index(selected);
+
+		/* If our index is above the current top row, align
+		 * us to the new top. Otherwise, align us to the new
+		 * bottom */
+		top = top < idx ? idx - rows + 1 : idx;
+
+		set_top_row(menu->ncm, top);
+		set_current_item(menu->ncm, selected);
+	}
+
+	if (cui->current == &menu->scr)
+		nc_scr_post(cui->current);
+
+	return 0;
+}
+
 /**
  * cui_device_remove - Client device remove callback.
  *
@@ -1482,6 +1634,12 @@  int cui_send_set_password(struct cui *cui, char *password, char *new_password)
 			new_password);
 }
 
+int cui_send_open_luks_device(struct cui *cui, char *password, char *device_id)
+{
+	return discover_client_send_open_luks_device(cui->client, password,
+			device_id);
+}
+
 void cui_send_reinit(struct cui *cui)
 {
 	discover_client_send_reinit(cui->client);
@@ -1629,7 +1787,7 @@  fail_setup:
 }
 
 static struct discover_client_ops cui_client_ops = {
-	.device_add = NULL,
+	.device_add = cui_device_add,
 	.boot_option_add = cui_boot_option_add,
 	.device_remove = cui_device_remove,
 	.plugin_option_add = cui_plugin_option_add,
diff --git a/ui/ncurses/nc-cui.h b/ui/ncurses/nc-cui.h
index 8fa27aa7..039aa922 100644
--- a/ui/ncurses/nc-cui.h
+++ b/ui/ncurses/nc-cui.h
@@ -101,11 +101,14 @@  void cui_show_plugin(struct pmenu_item *item);
 void cui_show_plugin_menu(struct cui *cui);
 void cui_show_auth(struct cui *cui, WINDOW *parent, bool set_password,
 		void (*callback)(struct nc_scr *));
+void cui_show_open_luks(struct cui *cui, WINDOW *parent,
+		const struct device *dev);
 int cui_send_config(struct cui *cui, struct config *config);
 int cui_send_url(struct cui *cui, char *url);
 int cui_send_plugin_install(struct cui *cui, char *file);
 int cui_send_authenticate(struct cui *cui, char *password);
 int cui_send_set_password(struct cui *cui, char *password, char *new_password);
+int cui_send_open_luks_device(struct cui *cui, char *password, char *device_id);
 void cui_send_reinit(struct cui *cui);
 
 /* convenience routines */