ui/ncurses: Add prompt for LUKS device password
authorSamuel Mendoza-Jonas <sam@mendozajonas.com>
Thu, 14 Feb 2019 23:40:56 +0000 (10:40 +1100)
committerSamuel Mendoza-Jonas <sam@mendozajonas.com>
Tue, 26 Mar 2019 05:46:38 +0000 (16:46 +1100)
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
ui/common/discover-client.h
ui/ncurses/nc-auth.c
ui/ncurses/nc-auth.h
ui/ncurses/nc-cui.c
ui/ncurses/nc-cui.h

index e7dfb831ba6b586ab311607128abb47e92890e8d..6dda2d32f55a5dcfce5d8215f3a42f8a00d32c6e 100644 (file)
@@ -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);
+}
index 9b56dcb76258433d6b38620ca0f9a59c98f9b4bc..183d1935f329a84d2192afdb2cc8b59434a70c60 100644 (file)
@@ -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,
index 5bfda8b4ec43648b4b2e24714ffc06e87e5b22ac..227c57bf8ea8c5a575f4dda40c7d4b0c8dd35724 100644 (file)
@@ -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;
index e8e41482b32b29ca9cef062991a0c7b41389db6f..0473c922b51e2a0a3b44ac334248c4e4f8bfdb9e 100644 (file)
@@ -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 *));
 
index d80e2c3e5e6f0a30e48f11b1e623ea1ec26d7ac0..bd2eb6821cc6d25ec9533c0f6b305e2eb2bb288c 100644 (file)
@@ -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,113 @@ 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 +1633,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 +1786,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,
index 8fa27aa7e7d78a37480629d0ba1c9c194c1c161c..039aa922dd6d233bc4353bf98f28006705395485 100644 (file)
@@ -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 */