summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Mendoza-Jonas <sam@mendozajonas.com>2018-06-20 10:45:56 +1000
committerSamuel Mendoza-Jonas <sam@mendozajonas.com>2018-12-03 14:48:41 +1100
commit07f6db7fc29a93fae3213af18371cccb17e0276a (patch)
treee6306f75ae6cb0e863d9c096d0a7a56140657634
parent9011b958364f2af965a33681e7375f079ba75d02 (diff)
downloadtalos-petitboot-07f6db7fc29a93fae3213af18371cccb17e0276a.zip
talos-petitboot-07f6db7fc29a93fae3213af18371cccb17e0276a.tar.gz
ui/ncurses: Add nc-auth and authenticate when required.
When the user tries to perform actions that require authentication a new subscreen 'nc-auth' is launched which accepts a password and will send an authentication request before performing the action. This also adds a button in nc-config which launches an nc-auth screen allowing the user to set or change the system password. Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
-rw-r--r--ui/ncurses/Makefile.am4
-rw-r--r--ui/ncurses/nc-add-url.c63
-rw-r--r--ui/ncurses/nc-auth.c299
-rw-r--r--ui/ncurses/nc-auth.h33
-rw-r--r--ui/ncurses/nc-config.c64
-rw-r--r--ui/ncurses/nc-cui.c152
-rw-r--r--ui/ncurses/nc-cui.h6
-rw-r--r--ui/ncurses/nc-lang.c127
-rw-r--r--ui/ncurses/nc-plugin.c44
-rw-r--r--ui/ncurses/nc-plugin.h2
-rw-r--r--ui/ncurses/nc-scr.h1
-rw-r--r--ui/ncurses/nc-widgets.c12
-rw-r--r--ui/ncurses/nc-widgets.h3
13 files changed, 705 insertions, 105 deletions
diff --git a/ui/ncurses/Makefile.am b/ui/ncurses/Makefile.am
index b791b9d..cd525df 100644
--- a/ui/ncurses/Makefile.am
+++ b/ui/ncurses/Makefile.am
@@ -57,7 +57,9 @@ ui_ncurses_libpbnc_la_SOURCES = \
ui/ncurses/nc-plugin.c \
ui/ncurses/nc-plugin.h \
ui/ncurses/nc-plugin-help.c \
- ui/ncurses/nc-plugin-menu-help.c
+ ui/ncurses/nc-plugin-menu-help.c \
+ ui/ncurses/nc-auth.c \
+ ui/ncurses/nc-auth.h
sbin_PROGRAMS += ui/ncurses/petitboot-nc
diff --git a/ui/ncurses/nc-add-url.c b/ui/ncurses/nc-add-url.c
index 4abca38..33f502d 100644
--- a/ui/ncurses/nc-add-url.c
+++ b/ui/ncurses/nc-add-url.c
@@ -28,6 +28,7 @@
#include <i18n/i18n.h>
#include <log/log.h>
+#include "ui/common/discover-client.h"
#include "nc-cui.h"
#include "nc-add-url.h"
#include "nc-widgets.h"
@@ -111,14 +112,37 @@ static void add_url_screen_process_key(struct nc_scr *scr, int key)
cui_show_help(screen->cui, _("Retrieve Config"),
&add_url_help_text);
- } else if (handled) {
+ } else if (handled && (screen->cui->current == scr)) {
pad_refresh(screen);
}
}
+static int screen_process_form(struct add_url_screen *screen)
+{
+ char *url;
+ int rc;
+
+ url = widget_textbox_get_value(screen->widgets.url_f);
+ if (!url || !strlen(url))
+ return 0;
+
+ /* Once we have all the info we need, tell the server */
+ rc = cui_send_url(screen->cui, url);
+
+ if (rc)
+ pb_log("cui_send_retreive failed!\n");
+ else
+ pb_debug("add_url url sent!\n");
+ return 0;
+}
+
static int add_url_screen_post(struct nc_scr *scr)
{
struct add_url_screen *screen = add_url_screen_from_scr(scr);
+
+ if (screen->exit)
+ screen->on_exit(screen->cui);
+
widgetset_post(screen->widgetset);
nc_scr_frame_draw(scr);
if (screen->need_redraw) {
@@ -142,34 +166,29 @@ struct nc_scr *add_url_screen_scr(struct add_url_screen *screen)
return &screen->scr;
}
-static int screen_process_form(struct add_url_screen *screen)
+static void add_url_process_cb(struct nc_scr *scr)
{
- char *url;
- int rc;
-
- url = widget_textbox_get_value(screen->widgets.url_f);
- if (!url || !strlen(url))
- return 0;
-
- /* Once we have all the info we need, tell the server */
- rc = cui_send_url(screen->cui, url);
+ struct add_url_screen *screen = add_url_screen_from_scr(scr);
- if (rc)
- pb_log("cui_send_retreive failed!\n");
- else
- pb_debug("add_url url sent!\n");
- return 0;
+ if (!screen_process_form(screen))
+ screen->exit = true;
}
static void ok_click(void *arg)
{
struct add_url_screen *screen = arg;
- if (screen_process_form(screen))
- /* errors are written to the status line, so we'll need
- * to refresh */
- wrefresh(screen->scr.main_ncw);
- else
- screen->exit = true;
+
+ if (discover_client_authenticated(screen->cui->client)) {
+ if (screen_process_form(screen))
+ /* errors are written to the status line, so we'll need
+ * to refresh */
+ wrefresh(screen->scr.main_ncw);
+ else
+ screen->exit = true;
+ } else {
+ cui_show_auth(screen->cui, screen->scr.main_ncw, false,
+ add_url_process_cb);
+ }
}
static void help_click(void *arg)
diff --git a/ui/ncurses/nc-auth.c b/ui/ncurses/nc-auth.c
new file mode 100644
index 0000000..5bfda8b
--- /dev/null
+++ b/ui/ncurses/nc-auth.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2018 IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <talloc/talloc.h>
+#include <types/types.h>
+#include <i18n/i18n.h>
+#include <log/log.h>
+
+#include "nc-cui.h"
+#include "nc-widgets.h"
+#include "nc-auth.h"
+
+#define N_FIELDS 5
+
+struct auth_screen {
+ struct nc_scr scr;
+ struct cui *cui;
+ struct nc_scr *return_scr;
+ struct nc_widgetset *widgetset;
+ void (*process_key)(struct nc_scr *, int);
+
+ bool set_password;
+ void (*callback)(struct nc_scr *);
+ int offset_y;
+ int label_x;
+ int field_x;
+
+ bool exit;
+ void (*on_exit)(struct cui *);
+
+ struct {
+ struct nc_widget_label *title_a_l;
+ struct nc_widget_label *title_b_l;
+ struct nc_widget_textbox *password_f;
+ struct nc_widget_label *new_l;
+ struct nc_widget_textbox *new_f;
+ struct nc_widget_button *ok_b;
+ struct nc_widget_button *cancel_b;
+ } widgets;
+};
+
+struct nc_scr *auth_screen_return_scr(struct auth_screen *screen)
+{
+ return screen->return_scr;
+}
+
+struct nc_scr *auth_screen_scr(struct auth_screen *screen)
+{
+ return &screen->scr;
+}
+
+static struct auth_screen *auth_screen_from_scr(struct nc_scr *scr)
+{
+ struct auth_screen *auth_screen;
+
+ assert(scr->sig == pb_auth_screen_sig);
+ auth_screen = (struct auth_screen *)
+ ((char *)scr - (size_t)&((struct auth_screen *)0)->scr);
+ assert(auth_screen->scr.sig == pb_auth_screen_sig);
+ return auth_screen;
+}
+
+static void auth_screen_process_key(struct nc_scr *scr, int key)
+{
+ struct auth_screen *screen = auth_screen_from_scr(scr);
+ bool handled;
+
+ handled = widgetset_process_key(screen->widgetset, key);
+
+ if (!handled) {
+ switch (key) {
+ case 'x':
+ case 27: /* esc */
+ screen->exit = true;
+ break;
+ }
+ }
+
+ if (screen->exit)
+ screen->on_exit(screen->cui);
+ else if (handled)
+ wrefresh(screen->scr.sub_ncw);
+}
+
+static void auth_screen_frame_draw(struct nc_scr *scr)
+{
+ int y, x;
+
+ getmaxyx(scr->sub_ncw, y, x);
+
+ mvwhline(scr->sub_ncw, 0, 0, ACS_HLINE, x);
+ mvwhline(scr->sub_ncw, y - 1, 0, ACS_HLINE, x);
+
+ mvwvline(scr->sub_ncw, 0, 0, ACS_VLINE, y);
+ mvwvline(scr->sub_ncw, 0, x - 1, ACS_VLINE, y);
+}
+
+static int auth_screen_post(struct nc_scr *scr)
+{
+ struct auth_screen *screen = auth_screen_from_scr(scr);
+ widgetset_post(screen->widgetset);
+ auth_screen_frame_draw(scr);
+ wrefresh(scr->sub_ncw);
+ return 0;
+}
+
+static int auth_screen_unpost(struct nc_scr *scr)
+{
+ struct auth_screen *screen = auth_screen_from_scr(scr);
+ widgetset_unpost(screen->widgetset);
+ return 0;
+}
+
+static void ok_click(void *arg)
+{
+ struct auth_screen *screen = arg;
+ char *password, *new_password;
+ int rc;
+
+
+ password = widget_textbox_get_value(screen->widgets.password_f);
+ 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
+ rc = cui_send_authenticate(screen->cui, password);
+
+ if (rc)
+ pb_log("Failed to send authenticate action\n");
+ else if (screen->callback)
+ screen->callback(screen->return_scr);
+
+ screen->exit = true;
+}
+
+static void cancel_click(void *arg)
+{
+ struct auth_screen *screen = arg;
+ screen->exit = true;
+}
+
+static void auth_screen_layout_widgets(struct auth_screen *screen)
+{
+ int y = 1;
+
+ widget_move(widget_label_base(screen->widgets.title_a_l),
+ y++, screen->label_x);
+ widget_move(widget_label_base(screen->widgets.title_b_l),
+ y++, screen->label_x);
+
+ y += 1;
+
+ widget_move(widget_textbox_base(screen->widgets.password_f),
+ y++, screen->field_x);
+
+ y += 1;
+
+ if (screen->set_password) {
+ widget_move(widget_label_base(screen->widgets.new_l),
+ y++, screen->label_x);
+ widget_move(widget_textbox_base(screen->widgets.new_f),
+ y++, screen->field_x);
+ y += 1;
+ }
+
+ widget_move(widget_button_base(screen->widgets.ok_b),
+ y, 10);
+ widget_move(widget_button_base(screen->widgets.cancel_b),
+ y, 30);
+}
+
+static void auth_screen_draw(struct auth_screen *screen)
+{
+ struct nc_widgetset *set;
+
+ set = widgetset_create(screen, screen->scr.main_ncw,
+ screen->scr.sub_ncw);
+ if (!set) {
+ pb_log("%s: failed to create widgetset\n", __func__);
+ return;
+ }
+ 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."));
+
+ screen->widgets.password_f = widget_new_textbox_hidden(set, 0, 0,
+ COLS - 20 - 20, "", true);
+
+ if (screen->set_password) {
+ screen->widgets.new_l = widget_new_label(set, 0, 0,
+ _("New password:"));
+ screen->widgets.new_f = widget_new_textbox_hidden(set, 0, 0,
+ COLS - 20 - 20, "", true);
+ }
+
+ screen->widgets.ok_b = widget_new_button(set, 0, 0, 10, _("OK"),
+ ok_click, screen);
+ screen->widgets.cancel_b = widget_new_button(set, 0, 0, 10, _("Cancel"),
+ cancel_click, screen);
+
+ auth_screen_layout_widgets(screen);
+}
+
+static int auth_screen_destroy(void *arg)
+{
+ struct auth_screen *screen = arg;
+ if (screen->scr.sub_ncw)
+ delwin(screen->scr.sub_ncw);
+ return 0;
+}
+
+struct auth_screen *auth_screen_init(struct cui *cui,
+ WINDOW *parent, bool set_password,
+ void (*callback)(struct nc_scr *),
+ void (*on_exit)(struct cui *))
+{
+ struct auth_screen *screen = NULL;
+ struct nc_scr *scr;
+ int y, x;
+
+ if (!cui || !parent)
+ return NULL;
+
+ screen = talloc_zero(cui, struct auth_screen);
+ if (!screen)
+ return NULL;
+ talloc_set_destructor(screen, auth_screen_destroy);
+
+ screen->cui = cui;
+ screen->return_scr = cui->current;
+ screen->set_password = set_password;
+ screen->callback = callback;
+ screen->on_exit = on_exit;
+ screen->label_x = 5;
+ screen->field_x = 10;
+
+ /*
+ * Manually init our nc_scr: we only want to create the subwin and
+ * 'inherit' the parent window.
+ */
+ scr = &screen->scr;
+ scr->sig = pb_auth_screen_sig;
+ scr->ui_ctx = cui;
+ scr->process_key = auth_screen_process_key;
+ scr->post = auth_screen_post;
+ scr->unpost = auth_screen_unpost;
+ scr->resize = NULL;
+
+
+ getbegyx(parent, y, x);
+ /* Hold on to the real offset from the top of the screen */
+ screen->offset_y = y + 5;
+ (void)x;
+
+ scr->main_ncw = parent;
+ scr->sub_ncw = derwin(parent, set_password ? 15 : 10, COLS - 20,
+ 5, 10); /* relative to parent origin */
+ if (!scr->sub_ncw) {
+ pb_log("Could not create subwin\n");
+ goto err;
+ }
+
+ auth_screen_draw(screen);
+
+ return screen;
+err:
+ pb_log("failed to create auth screen\n");
+ if (screen) {
+ if (screen->scr.sub_ncw)
+ delwin(screen->scr.sub_ncw);
+ talloc_free(screen);
+ }
+ return NULL;
+}
diff --git a/ui/ncurses/nc-auth.h b/ui/ncurses/nc-auth.h
new file mode 100644
index 0000000..e8e4148
--- /dev/null
+++ b/ui/ncurses/nc-auth.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _NC_AUTH_H
+#define _NC_AUTH_H
+
+#include "nc-cui.h"
+
+struct auth_screen;
+
+struct auth_screen *auth_screen_init(struct cui *cui,
+ WINDOW *pad, bool set_password,
+ void (callback)(struct nc_scr *),
+ void (*on_exit)(struct cui *));
+
+struct nc_scr *auth_screen_scr(struct auth_screen *screen);
+struct nc_scr *auth_screen_return_scr(struct auth_screen *screen);
+
+#endif /* define _NC_AUTH_H */
diff --git a/ui/ncurses/nc-config.c b/ui/ncurses/nc-config.c
index 5186176..4685fa5 100644
--- a/ui/ncurses/nc-config.c
+++ b/ui/ncurses/nc-config.c
@@ -29,11 +29,12 @@
#include <log/log.h>
#include <i18n/i18n.h>
+#include "ui/common/discover-client.h"
#include "nc-cui.h"
#include "nc-config.h"
#include "nc-widgets.h"
-#define N_FIELDS 48
+#define N_FIELDS 49
extern struct help_text config_help_text;
@@ -51,7 +52,6 @@ struct config_screen {
bool exit;
bool show_help;
- bool show_subset;
bool need_redraw;
bool need_update;
@@ -118,6 +118,8 @@ struct config_screen {
struct nc_widget_label *manual_console_l;
struct nc_widget_label *current_console_l;
+ struct nc_widget_button *update_password_l;
+
struct nc_widget_label *net_override_l;
struct nc_widget_label *safe_mode;
struct nc_widget_button *ok_b;
@@ -175,7 +177,7 @@ static void config_screen_process_key(struct nc_scr *scr, int key)
cui_show_help(screen->cui, _("System Configuration"),
&config_help_text);
- } else if (handled && !screen->show_subset) {
+ } else if (handled && (screen->cui->current == scr)) {
pad_refresh(screen);
}
}
@@ -370,15 +372,39 @@ static int screen_process_form(struct config_screen *screen)
return 0;
}
+static void config_screen_config_cb(struct nc_scr *scr)
+{
+ struct config_screen *screen = config_screen_from_scr(scr);
+
+ if (!screen_process_form(screen))
+ screen->exit = true;
+}
+
+#ifdef CRYPT_SUPPORT
+static void password_click(void *arg)
+{
+ struct config_screen *screen = arg;
+
+ screen->need_update = true;
+ cui_show_auth(screen->cui, screen->scr.main_ncw, true, NULL);
+}
+#endif
+
static void ok_click(void *arg)
{
struct config_screen *screen = arg;
- if (screen_process_form(screen))
- /* errors are written to the status line, so we'll need
- * to refresh */
- wrefresh(screen->scr.main_ncw);
- else
- screen->exit = true;
+
+ if (discover_client_authenticated(screen->cui->client)) {
+ if (screen_process_form(screen))
+ /* errors are written to the status line, so we'll need
+ * to refresh */
+ wrefresh(screen->scr.main_ncw);
+ else
+ screen->exit = true;
+ } else {
+ cui_show_auth(screen->cui, screen->scr.main_ncw, false,
+ config_screen_config_cb);
+ }
}
static void help_click(void *arg)
@@ -650,6 +676,12 @@ static void config_screen_layout_widgets(struct config_screen *screen)
screen->widgets.current_console_l), false);
}
+#ifdef CRYPT_SUPPORT
+ widget_move(widget_button_base(screen->widgets.update_password_l),
+ y, screen->field_x);
+ y += 2;
+#endif
+
if (screen->net_override) {
widget_move(widget_label_base(screen->widgets.net_override_l),
y, screen->label_x);
@@ -705,7 +737,6 @@ static void config_screen_add_device(void *arg)
{
struct config_screen *screen = arg;
- screen->show_subset = true;
cui_show_subset(screen->cui, _("Select a boot device to add"),
screen->widgets.boot_order_f);
}
@@ -1113,6 +1144,11 @@ static void config_screen_setup_widgets(struct config_screen *screen,
ttyname(STDIN_FILENO));
screen->widgets.current_console_l = widget_new_label(set, 0 , 0, tty);
+#ifdef CRYPT_SUPPORT
+ screen->widgets.update_password_l = widget_new_button(set, 0, 0, 30,
+ _("Update system password"), password_click, screen);
+#endif
+
screen->widgets.ok_b = widget_new_button(set, 0, 0, 10, _("OK"),
ok_click, screen);
screen->widgets.help_b = widget_new_button(set, 0, 0, 10, _("Help"),
@@ -1212,7 +1248,12 @@ void config_screen_update(struct config_screen *screen,
static int config_screen_post(struct nc_scr *scr)
{
struct config_screen *screen = config_screen_from_scr(scr);
- screen->show_subset = false;
+
+ /* We may have been posted after an auth action completed */
+ if (screen->exit) {
+ screen->on_exit(screen->cui);
+ return 0;
+ }
if (screen->need_update) {
config_screen_draw(screen, screen->cui->config,
@@ -1262,7 +1303,6 @@ struct config_screen *config_screen_init(struct cui *cui,
screen->field_x = 17;
screen->ipmi_override = false;
- screen->show_subset = false;
screen->scr.frame.ltitle = talloc_strdup(screen,
_("Petitboot System Configuration"));
diff --git a/ui/ncurses/nc-cui.c b/ui/ncurses/nc-cui.c
index 474622c..495f785 100644
--- a/ui/ncurses/nc-cui.c
+++ b/ui/ncurses/nc-cui.c
@@ -47,6 +47,7 @@
#include "nc-statuslog.h"
#include "nc-subset.h"
#include "nc-plugin.h"
+#include "nc-auth.h"
#include "console-codes.h"
extern const struct help_text main_menu_help_text;
@@ -58,6 +59,7 @@ static struct pmenu *main_menu_init(struct cui *cui);
static struct pmenu *plugin_menu_init(struct cui *cui);
static void cui_cancel_autoboot_on_exit(struct cui *cui);
+static void cui_auth_exit(struct cui *cui);
static struct {
int key;
@@ -331,10 +333,38 @@ static int menu_statuslog_execute(struct pmenu_item *item)
return 0;
}
+static void menu_reinit_cb(struct nc_scr *scr)
+{
+ struct pmenu *menu = pmenu_from_scr(scr);
+
+ cui_send_reinit(cui_from_pmenu(menu));
+}
+
static int menu_reinit_execute(struct pmenu_item *item)
{
- if (cui_from_item(item)->client)
- cui_send_reinit(cui_from_item(item));
+ struct cui *cui = cui_from_item(item);
+
+ if (!cui->client)
+ return 0;
+
+ /* If we don't need to authenticate, send the reinit immediately */
+ if (discover_client_authenticated(cui->client)) {
+ cui_send_reinit(cui);
+ return 0;
+ }
+
+ if (!cui->current)
+ return 0;
+
+ if (cui->auth_screen)
+ return 0;
+
+ cui->auth_screen = auth_screen_init(cui, cui->current->main_ncw,
+ false, menu_reinit_cb, cui_auth_exit);
+
+ if (cui->auth_screen)
+ cui_set_current(cui, auth_screen_scr(cui->auth_screen));
+
return 0;
}
@@ -352,6 +382,26 @@ static int menu_plugin_execute(struct pmenu_item *item)
return 0;
}
+static void cui_boot_cb(struct nc_scr *scr)
+{
+ struct pmenu *menu = pmenu_from_scr(scr);
+
+ if (pmenu_find_selected(menu))
+ cui_boot(pmenu_find_selected(menu));
+}
+
+static int cui_boot_check(struct pmenu_item *item)
+{
+ struct cui *cui = cui_from_item(item);
+
+ if (discover_client_authenticated(cui->client))
+ return cui_boot(item);
+
+ cui_show_auth(cui, item->pmenu->scr.main_ncw, false, cui_boot_cb);
+
+ return 0;
+}
+
static void cui_boot_editor_on_exit(struct cui *cui,
struct pmenu_item *item,
struct pb_boot_data *bd)
@@ -383,7 +433,7 @@ static void cui_boot_editor_on_exit(struct cui *cui,
}
item->on_edit = cui_item_edit;
- item->on_execute = cui_boot;
+ item->on_execute = cui_boot_check;
item->data = cod;
talloc_steal(item, cod);
@@ -442,6 +492,52 @@ void cui_item_new(struct pmenu *menu)
cui_set_current(cui, boot_editor_scr(cui->boot_editor));
}
+
+/* Call pb-plugin to install a plugin specified by plugin_file */
+static int cui_install_plugin(struct pmenu_item *item)
+{
+ struct cui *cui = cui_from_item(item);
+ struct cui_opt_data *cod = cod_from_item(item);
+ int rc;
+
+ rc = cui_send_plugin_install(cui, cod->pd->plugin_file);
+
+ if (rc) {
+ pb_log("cui_send_plugin_install failed!\n");
+ nc_scr_status_printf(cui->current,
+ _("Failed to send install request"));
+ } else {
+ nc_scr_status_printf(cui->current, _("Installing plugin %s"),
+ cod->pd->plugin_file);
+ pb_debug("cui_send_plugin_install sent!\n");
+ }
+
+ return rc;
+}
+
+static void cui_plugin_install_cb(struct nc_scr *scr)
+{
+ struct pmenu *menu = pmenu_from_scr(scr);
+
+ if (pmenu_find_selected(menu))
+ cui_install_plugin(pmenu_find_selected(menu));
+ else
+ pb_debug("%s: no current item\n", __func__);
+}
+
+static int cui_plugin_install_check(struct pmenu_item *item)
+{
+ struct cui *cui = cui_from_item(item);
+
+ if (discover_client_authenticated(cui->client))
+ return cui_install_plugin(item);
+
+ cui_show_auth(cui, item->pmenu->scr.main_ncw, false,
+ cui_plugin_install_cb);
+
+ return 0;
+}
+
static void cui_sysinfo_exit(struct cui *cui)
{
cui_set_current(cui, &cui->main->scr);
@@ -580,6 +676,39 @@ void cui_show_subset(struct cui *cui, const char *title,
cui_set_current(cui, subset_screen_scr(cui->subset_screen));
}
+static void cui_auth_exit(struct cui *cui)
+{
+ struct nc_scr *return_scr = auth_screen_return_scr(cui->auth_screen);
+
+ /*
+ * Destroy the auth screen first so that the subwindow is cleaned up
+ * before the return_scr posts. If we don't do this operations on the
+ * main_ncw can cause a blank screen at first (eg. status update).
+ */
+ nc_scr_unpost(cui->current);
+ talloc_free(cui->auth_screen);
+ cui->auth_screen = NULL;
+
+ cui->current = return_scr;
+ nc_scr_post(cui->current);
+}
+
+void cui_show_auth(struct cui *cui, WINDOW *parent, bool set_password,
+ void (*callback)(struct nc_scr *))
+{
+ if (!cui->current)
+ return;
+
+ if (cui->auth_screen)
+ return;
+
+ cui->auth_screen = auth_screen_init(cui, parent, set_password,
+ callback, 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.
*/
@@ -814,10 +943,10 @@ static int cui_boot_option_add(struct device *dev, struct boot_option *opt,
if (plugin_option) {
i->on_edit = NULL;
- i->on_execute = plugin_install_plugin;
+ i->on_execute = cui_plugin_install_check;
} else {
i->on_edit = cui_item_edit;
- i->on_execute = cui_boot;
+ i->on_execute = cui_boot_check;
}
i->data = cod = talloc(i, struct cui_opt_data);
@@ -1247,7 +1376,7 @@ static void cui_update_sysinfo(struct system_info *sysinfo, void *arg)
cui_update_mm_title(cui);
}
-static void cui_update_language(struct cui *cui, char *lang)
+void cui_update_language(struct cui *cui, const char *lang)
{
bool repost_menu;
char *cur_lang;
@@ -1311,6 +1440,17 @@ int cui_send_plugin_install(struct cui *cui, char *file)
return discover_client_send_plugin_install(cui->client, file);
}
+int cui_send_authenticate(struct cui *cui, char *password)
+{
+ return discover_client_send_authenticate(cui->client, password);
+}
+
+int cui_send_set_password(struct cui *cui, char *password, char *new_password)
+{
+ return discover_client_send_set_password(cui->client, password,
+ new_password);
+}
+
void cui_send_reinit(struct cui *cui)
{
discover_client_send_reinit(cui->client);
diff --git a/ui/ncurses/nc-cui.h b/ui/ncurses/nc-cui.h
index abe4db9..8fa27aa 100644
--- a/ui/ncurses/nc-cui.h
+++ b/ui/ncurses/nc-cui.h
@@ -73,6 +73,7 @@ struct cui {
struct help_screen *help_screen;
struct subset_screen *subset_screen;
struct statuslog_screen *statuslog_screen;
+ struct auth_screen *auth_screen;
struct pjs *pjs;
void *platform_info;
unsigned int default_item;
@@ -98,9 +99,13 @@ void cui_show_subset(struct cui *cui, const char *title,
void cui_show_add_url(struct cui *cui);
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 *));
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);
void cui_send_reinit(struct cui *cui);
/* convenience routines */
@@ -112,6 +117,7 @@ void cui_abort_on_exit(struct pmenu *menu);
void cui_on_open(struct pmenu *menu);
int cui_run_cmd(struct cui *cui, const char **cmd_argv);
int cui_run_cmd_from_item(struct pmenu_item *item);
+void cui_update_language(struct cui *cui, const char *lang);
static inline struct cui *cui_from_arg(void *arg)
{
diff --git a/ui/ncurses/nc-lang.c b/ui/ncurses/nc-lang.c
index a7c9ccc..91d86e1 100644
--- a/ui/ncurses/nc-lang.c
+++ b/ui/ncurses/nc-lang.c
@@ -29,11 +29,12 @@
#include <i18n/i18n.h>
#include <pb-config/pb-config.h>
+#include "ui/common/discover-client.h"
#include "nc-cui.h"
#include "nc-lang.h"
#include "nc-widgets.h"
-#define N_FIELDS 5
+#define N_FIELDS 7
static struct lang {
const char *name;
@@ -70,6 +71,9 @@ struct lang_screen {
struct nc_widget_select *lang_f;
struct nc_widget_label *lang_l;
+ struct nc_widget_label *save_l;
+ struct nc_widget_checkbox *save_cb;
+
struct nc_widget_label *safe_mode;
struct nc_widget_button *ok_b;
struct nc_widget_button *cancel_b;
@@ -115,12 +119,55 @@ static void lang_screen_process_key(struct nc_scr *scr, int key)
if (screen->exit) {
screen->on_exit(screen->cui);
-
- } else if (handled) {
+ } else if (handled && (screen->cui->current == scr)) {
pad_refresh(screen);
}
}
+static const char *lang_get_lang_name(struct lang_screen *screen)
+{
+ struct lang *lang;
+ int idx;
+
+ idx = widget_select_get_value(screen->widgets.lang_f);
+
+ /* Option -1 ("Unknown") can only be populated from the current
+ * language, so there's no change here */
+ if (idx == -1)
+ return NULL;
+
+ lang = &languages[idx];
+
+ return lang->name;
+}
+
+static int lang_process_form(struct lang_screen *screen)
+{
+ struct config *config;
+ const char *lang;
+ int rc;
+
+ config = config_copy(screen, screen->cui->config);
+
+ lang = lang_get_lang_name(screen);
+
+ if (!lang || (config->lang && !strcmp(lang, config->lang)))
+ return 0;
+
+ config->lang = talloc_strdup(screen, lang);
+
+ config->safe_mode = false;
+ rc = cui_send_config(screen->cui, config);
+ talloc_free(config);
+
+ if (rc)
+ pb_log("cui_send_config failed!\n");
+ else
+ pb_debug("config sent!\n");
+
+ return 0;
+}
+
static void lang_screen_resize(struct nc_scr *scr)
{
struct lang_screen *screen = lang_screen_from_scr(scr);
@@ -130,6 +177,10 @@ static void lang_screen_resize(struct nc_scr *scr)
static int lang_screen_post(struct nc_scr *scr)
{
struct lang_screen *screen = lang_screen_from_scr(scr);
+
+ if (screen->exit)
+ screen->on_exit(screen->cui);
+
widgetset_post(screen->widgetset);
nc_scr_frame_draw(scr);
wrefresh(screen->scr.main_ncw);
@@ -149,49 +200,39 @@ struct nc_scr *lang_screen_scr(struct lang_screen *screen)
return &screen->scr;
}
-static int lang_process_form(struct lang_screen *screen)
+static void lang_screen_update_cb(struct nc_scr *scr)
{
- struct config *config;
- struct lang *lang;
- int idx, rc;
-
- config = config_copy(screen, screen->cui->config);
-
- idx = widget_select_get_value(screen->widgets.lang_f);
-
- /* Option -1 ("Unknown") can only be populated from the current
- * language, so there's no change here */
- if (idx == -1)
- return 0;
-
- lang = &languages[idx];
-
- if (config->lang && !strcmp(lang->name, config->lang))
- return 0;
-
- config->lang = talloc_strdup(screen, lang->name);
-
- config->safe_mode = false;
- rc = cui_send_config(screen->cui, config);
- talloc_free(config);
-
- if (rc)
- pb_log("cui_send_config failed!\n");
- else
- pb_debug("config sent!\n");
+ struct lang_screen *screen = lang_screen_from_scr(scr);
- return 0;
+ if (!lang_process_form(screen))
+ screen->exit = true;
}
static void ok_click(void *arg)
{
struct lang_screen *screen = arg;
- if (lang_process_form(screen))
- /* errors are written to the status line, so we'll need
- * to refresh */
- wrefresh(screen->scr.main_ncw);
- else
+ const char *lang;
+
+ if (!widget_checkbox_get_value(screen->widgets.save_cb)) {
+ /* Just update the client display */
+ lang = lang_get_lang_name(screen);
+ if (lang)
+ cui_update_language(screen->cui, lang);
screen->exit = true;
+ return;
+ }
+
+ if (discover_client_authenticated(screen->cui->client)) {
+ if (lang_process_form(screen))
+ /* errors are written to the status line, so we'll need
+ * to refresh */
+ wrefresh(screen->scr.main_ncw);
+ else
+ screen->exit = true;
+ } else {
+ cui_show_auth(screen->cui, screen->scr.main_ncw, false,
+ lang_screen_update_cb);
+ }
}
static void cancel_click(void *arg)
@@ -221,6 +262,10 @@ static void lang_screen_layout_widgets(struct lang_screen *screen)
y += 1;
+ y += layout_pair(screen, y, screen->widgets.save_l,
+ widget_checkbox_base(screen->widgets.save_cb));
+ y += 1;
+
if (screen->cui->config->safe_mode) {
widget_move(widget_label_base(screen->widgets.safe_mode),
y, screen->field_x);
@@ -289,6 +334,10 @@ static void lang_screen_setup_widgets(struct lang_screen *screen,
label, true);
}
+ screen->widgets.save_l = widget_new_label(set, 0, 0,
+ _("Save changes?"));
+ screen->widgets.save_cb = widget_new_checkbox(set, 0, 0, false);
+
if (config->safe_mode)
screen->widgets.safe_mode = widget_new_label(set, 0, 0,
_("Selecting 'OK' will exit safe mode"));
@@ -325,7 +374,7 @@ static void lang_screen_draw(struct lang_screen *screen,
bool repost = false;
int height;
- height = ARRAY_SIZE(languages) + 4;
+ height = ARRAY_SIZE(languages) + N_FIELDS + 4;
if (!screen->pad || getmaxy(screen->pad) < height) {
if (screen->pad)
delwin(screen->pad);
diff --git a/ui/ncurses/nc-plugin.c b/ui/ncurses/nc-plugin.c
index ad8210f..f897cc8 100644
--- a/ui/ncurses/nc-plugin.c
+++ b/ui/ncurses/nc-plugin.c
@@ -40,6 +40,8 @@
extern const struct help_text plugin_help_text;
+static void plugin_run_command(void *arg);
+
struct plugin_screen {
struct nc_scr scr;
struct cui *cui;
@@ -48,6 +50,7 @@ struct plugin_screen {
bool exit;
bool show_help;
+ bool show_auth_run;
bool need_redraw;
void (*on_exit)(struct cui *);
@@ -160,7 +163,7 @@ static void plugin_screen_process_key(struct nc_scr *scr, int key)
cui_show_help(screen->cui, _("Petitboot Plugin"),
&plugin_help_text);
- } else if (handled) {
+ } else if (handled && (screen->cui->current == scr)) {
pad_refresh(screen);
}
}
@@ -178,6 +181,12 @@ static int plugin_screen_post(struct nc_scr *scr)
}
wrefresh(screen->scr.main_ncw);
pad_refresh(screen);
+
+ if (screen->show_auth_run) {
+ screen->show_auth_run = false;
+ plugin_run_command(screen);
+ }
+
return 0;
}
@@ -232,28 +241,21 @@ static void plugin_run_command(void *arg)
talloc_free(cmd);
}
-/* Call pb-plugin to install a plugin specified by plugin_file */
-int plugin_install_plugin(struct pmenu_item *item)
+static void plugin_run_command_check(void *arg)
{
- struct cui *cui = cui_from_item(item);
- struct cui_opt_data *cod = cod_from_item(item);
- int rc;
-
- assert(cui->current == &cui->plugin_menu->scr);
-
- nc_scr_status_printf(cui->current, _("Installing plugin %s"),
- cod->pd->plugin_file);
-
- rc = cui_send_plugin_install(cui, cod->pd->plugin_file);
+ struct plugin_screen *screen = arg;
- if (rc) {
- pb_log("cui_send_plugin_install failed!\n");
- nc_scr_status_printf(cui->current,
- _("Failed to send install request"));
- } else
- pb_debug("cui_send_plugin_install sent!\n");
+ if (discover_client_authenticated(screen->cui->client)) {
+ plugin_run_command(screen);
+ return;
+ }
- return rc;
+ /*
+ * Don't supply a callback as we want to handle running the command
+ * from the plugin screen.
+ */
+ screen->show_auth_run = true;
+ cui_show_auth(screen->cui, screen->scr.main_ncw, false, NULL);
}
static void plugin_screen_setup_widgets(struct plugin_screen *screen)
@@ -291,7 +293,7 @@ static void plugin_screen_setup_widgets(struct plugin_screen *screen)
}
screen->widgets.run_b = widget_new_button(set, 0, 0, 30,
- _("Run selected command"), plugin_run_command, screen);
+ _("Run selected command"), plugin_run_command_check, screen);
}
static int layout_pair(struct plugin_screen *screen, int y,
diff --git a/ui/ncurses/nc-plugin.h b/ui/ncurses/nc-plugin.h
index 6dfd4ae..398b7c7 100644
--- a/ui/ncurses/nc-plugin.h
+++ b/ui/ncurses/nc-plugin.h
@@ -29,6 +29,4 @@ struct plugin_screen *plugin_screen_init(struct cui *cui,
struct nc_scr *plugin_screen_scr(struct plugin_screen *screen);
void plugin_screen_update(struct plugin_screen *screen);
-int plugin_install_plugin(struct pmenu_item *item);
-
#endif /* defined _NC_PLUGIN_H */
diff --git a/ui/ncurses/nc-scr.h b/ui/ncurses/nc-scr.h
index 5671a6b..9f46f99 100644
--- a/ui/ncurses/nc-scr.h
+++ b/ui/ncurses/nc-scr.h
@@ -50,6 +50,7 @@ enum pb_nc_sig {
pb_add_url_screen_sig = 888,
pb_subset_screen_sig = 101,
pb_plugin_screen_sig = 202,
+ pb_auth_screen_sig = 303,
pb_removed_sig = -999,
};
diff --git a/ui/ncurses/nc-widgets.c b/ui/ncurses/nc-widgets.c
index 30915a9..afd56d7 100644
--- a/ui/ncurses/nc-widgets.c
+++ b/ui/ncurses/nc-widgets.c
@@ -365,8 +365,8 @@ static int textbox_destructor(void *ptr)
return 0;
}
-struct nc_widget_textbox *widget_new_textbox(struct nc_widgetset *set,
- int y, int x, int len, char *str)
+struct nc_widget_textbox *widget_new_textbox_hidden(struct nc_widgetset *set,
+ int y, int x, int len, char *str, bool hide_input)
{
struct nc_widget_textbox *textbox;
FIELD *f;
@@ -383,6 +383,8 @@ struct nc_widget_textbox *widget_new_textbox(struct nc_widgetset *set,
textbox->widget.unfocussed_attr = A_UNDERLINE;
field_opts_off(f, O_STATIC | O_WRAP | O_BLANK);
+ if (hide_input)
+ field_opts_off(f, O_PUBLIC);
set_field_buffer(f, 0, str);
set_field_back(f, textbox->widget.unfocussed_attr);
set_field_userptr(f, &textbox->widget);
@@ -393,6 +395,12 @@ struct nc_widget_textbox *widget_new_textbox(struct nc_widgetset *set,
return textbox;
}
+struct nc_widget_textbox *widget_new_textbox(struct nc_widgetset *set,
+ int y, int x, int len, char *str)
+{
+ return widget_new_textbox_hidden(set, y, x, len, str, false);
+}
+
void widget_textbox_set_fixed_size(struct nc_widget_textbox *textbox)
{
field_opts_on(textbox->widget.field, O_STATIC);
diff --git a/ui/ncurses/nc-widgets.h b/ui/ncurses/nc-widgets.h
index a946c4f..ce3b038 100644
--- a/ui/ncurses/nc-widgets.h
+++ b/ui/ncurses/nc-widgets.h
@@ -16,6 +16,7 @@
*/
#ifndef NC_WIDGETS_H
+#define NC_WIDGETS_H
struct nc_widgetset;
struct nc_widget_label;
@@ -27,6 +28,8 @@ struct nc_widget_label *widget_new_label(struct nc_widgetset *set,
int y, int x, char *str);
struct nc_widget_checkbox *widget_new_checkbox(struct nc_widgetset *set,
int y, int x, bool checked);
+struct nc_widget_textbox *widget_new_textbox_hidden(struct nc_widgetset *set,
+ int y, int x, int len, char *str, bool hide_input);
struct nc_widget_textbox *widget_new_textbox(struct nc_widgetset *set,
int y, int x, int len, char *str);
struct nc_widget_subset *widget_new_subset(struct nc_widgetset *set,
OpenPOWER on IntegriCloud