From 07f6db7fc29a93fae3213af18371cccb17e0276a Mon Sep 17 00:00:00 2001 From: Samuel Mendoza-Jonas Date: Wed, 20 Jun 2018 10:45:56 +1000 Subject: [PATCH] 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 --- ui/ncurses/Makefile.am | 4 +- ui/ncurses/nc-add-url.c | 63 ++++++--- ui/ncurses/nc-auth.c | 299 ++++++++++++++++++++++++++++++++++++++++ ui/ncurses/nc-auth.h | 33 +++++ ui/ncurses/nc-config.c | 64 +++++++-- ui/ncurses/nc-cui.c | 152 +++++++++++++++++++- ui/ncurses/nc-cui.h | 6 + ui/ncurses/nc-lang.c | 127 +++++++++++------ ui/ncurses/nc-plugin.c | 44 +++--- ui/ncurses/nc-plugin.h | 2 - ui/ncurses/nc-scr.h | 1 + ui/ncurses/nc-widgets.c | 12 +- ui/ncurses/nc-widgets.h | 3 + 13 files changed, 705 insertions(+), 105 deletions(-) create mode 100644 ui/ncurses/nc-auth.c create mode 100644 ui/ncurses/nc-auth.h 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 #include +#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 +#include +#include + +#include +#include +#include +#include + +#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 #include +#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 #include +#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, -- 2.39.2