discover/grub2: Allow to separate the --id argument using a space char
[petitboot] / ui / ncurses / nc-auth.c
1 /*
2  *  Copyright (C) 2018 IBM Corporation
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; version 2 of the License.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17
18 #if defined(HAVE_CONFIG_H)
19 #include "config.h"
20 #endif
21
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <talloc/talloc.h>
27 #include <types/types.h>
28 #include <i18n/i18n.h>
29 #include <log/log.h>
30
31 #include "nc-cui.h"
32 #include "nc-widgets.h"
33 #include "nc-auth.h"
34
35 #define N_FIELDS        5
36
37 struct auth_screen {
38         struct nc_scr           scr;
39         struct cui              *cui;
40         struct nc_scr           *return_scr;
41         struct nc_widgetset     *widgetset;
42         void                    (*process_key)(struct nc_scr *, int);
43
44         bool                    set_password;
45         const struct device     *dev;
46         void                    (*callback)(struct nc_scr *);
47         int                     offset_y;
48         int                     label_x;
49         int                     field_x;
50
51         bool                    exit;
52         void                    (*on_exit)(struct cui *);
53
54         struct {
55                 struct nc_widget_label          *title_a_l;
56                 struct nc_widget_label          *title_b_l;
57                 struct nc_widget_textbox        *password_f;
58                 struct nc_widget_label          *new_l;
59                 struct nc_widget_textbox        *new_f;
60                 struct nc_widget_button         *ok_b;
61                 struct nc_widget_button         *cancel_b;
62         } widgets;
63 };
64
65 struct nc_scr *auth_screen_return_scr(struct auth_screen *screen)
66 {
67         return screen->return_scr;
68 }
69
70 struct nc_scr *auth_screen_scr(struct auth_screen *screen)
71 {
72         return &screen->scr;
73 }
74
75 static struct auth_screen *auth_screen_from_scr(struct nc_scr *scr)
76 {
77         struct auth_screen *auth_screen;
78
79         assert(scr->sig == pb_auth_screen_sig);
80         auth_screen = (struct auth_screen *)
81                 ((char *)scr - (size_t)&((struct auth_screen *)0)->scr);
82         assert(auth_screen->scr.sig == pb_auth_screen_sig);
83         return auth_screen;
84 }
85
86 static void auth_screen_process_key(struct nc_scr *scr, int key)
87 {
88         struct auth_screen *screen = auth_screen_from_scr(scr);
89         bool handled;
90
91         handled = widgetset_process_key(screen->widgetset, key);
92
93         if (!handled) {
94                 switch (key) {
95                 case 'x':
96                 case 27: /* esc */
97                         screen->exit = true;
98                         break;
99                 }
100         }
101
102         if (screen->exit)
103                 screen->on_exit(screen->cui);
104         else if (handled)
105                 wrefresh(screen->scr.sub_ncw);
106 }
107
108 static void auth_screen_frame_draw(struct nc_scr *scr)
109 {
110         int y, x;
111
112         getmaxyx(scr->sub_ncw, y, x);
113
114         mvwhline(scr->sub_ncw, 0, 0, ACS_HLINE, x);
115         mvwhline(scr->sub_ncw, y - 1, 0, ACS_HLINE, x);
116
117         mvwvline(scr->sub_ncw, 0, 0, ACS_VLINE, y);
118         mvwvline(scr->sub_ncw, 0, x - 1, ACS_VLINE, y);
119 }
120
121 static int auth_screen_post(struct nc_scr *scr)
122 {
123         struct auth_screen *screen = auth_screen_from_scr(scr);
124         widgetset_post(screen->widgetset);
125         auth_screen_frame_draw(scr);
126         wrefresh(scr->sub_ncw);
127         return 0;
128 }
129
130 static int auth_screen_unpost(struct nc_scr *scr)
131 {
132         struct auth_screen *screen = auth_screen_from_scr(scr);
133         widgetset_unpost(screen->widgetset);
134         return 0;
135 }
136
137 static void ok_click(void *arg)
138 {
139         struct auth_screen *screen = arg;
140         char *password, *new_password;
141         int rc;
142
143
144         password = widget_textbox_get_value(screen->widgets.password_f);
145         if (screen->set_password) {
146                 new_password = widget_textbox_get_value(screen->widgets.new_f);
147                 rc = cui_send_set_password(screen->cui, password, new_password);
148         } else if (screen->dev) {
149                 rc = cui_send_open_luks_device(screen->cui, password,
150                                 screen->dev->id);
151         } else
152                 rc = cui_send_authenticate(screen->cui, password);
153
154         if (rc)
155                 pb_log("Failed to send authenticate action\n");
156         else if (screen->callback)
157                 screen->callback(screen->return_scr);
158
159         screen->exit = true;
160 }
161
162 static void cancel_click(void *arg)
163 {
164         struct auth_screen *screen = arg;
165         screen->exit = true;
166 }
167
168 static void auth_screen_layout_widgets(struct auth_screen *screen)
169 {
170         int y = 1;
171
172         widget_move(widget_label_base(screen->widgets.title_a_l),
173                         y++, screen->label_x);
174         widget_move(widget_label_base(screen->widgets.title_b_l),
175                         y++, screen->label_x);
176
177         y += 1;
178
179         widget_move(widget_textbox_base(screen->widgets.password_f),
180                         y++, screen->field_x);
181
182         y += 1;
183
184         if (screen->set_password) {
185                 widget_move(widget_label_base(screen->widgets.new_l),
186                                 y++, screen->label_x);
187                 widget_move(widget_textbox_base(screen->widgets.new_f),
188                                 y++, screen->field_x);
189                 y += 1;
190         }
191
192         widget_move(widget_button_base(screen->widgets.ok_b),
193                         y, 10);
194         widget_move(widget_button_base(screen->widgets.cancel_b),
195                         y, 30);
196 }
197
198 static void auth_screen_draw(struct auth_screen *screen)
199 {
200         struct nc_widgetset *set;
201         char *label;
202
203         set = widgetset_create(screen, screen->scr.main_ncw,
204                         screen->scr.sub_ncw);
205         if (!set) {
206                 pb_log("%s: failed to create widgetset\n", __func__);
207                 return;
208         }
209         screen->widgetset = set;
210
211         if (screen->dev) {
212                 label = talloc_asprintf(screen,
213                                 _("Opening encrypted device %s"),
214                                 screen->dev->id);
215                 screen->widgets.title_a_l = widget_new_label(set, 0, 0, label);
216                 screen->widgets.title_b_l = widget_new_label(set, 0, 0,
217                                 _("Please enter the disk password."));
218                 talloc_free(label);
219         } else {
220                 screen->widgets.title_a_l = widget_new_label(set, 0, 0,
221                                 _("This action requires authorisation."));
222                 screen->widgets.title_b_l = widget_new_label(set, 0, 0,
223                                 _("Please enter the system password."));
224         }
225
226         screen->widgets.password_f = widget_new_textbox_hidden(set, 0, 0,
227                         COLS - 20 - 20, "", true);
228
229         if (screen->set_password) {
230                 screen->widgets.new_l = widget_new_label(set, 0, 0,
231                                 _("New password:"));
232                 screen->widgets.new_f = widget_new_textbox_hidden(set, 0, 0,
233                                 COLS - 20 - 20, "", true);
234         }
235
236         screen->widgets.ok_b = widget_new_button(set, 0, 0, 10, _("OK"),
237                         ok_click, screen);
238         screen->widgets.cancel_b = widget_new_button(set, 0, 0, 10, _("Cancel"),
239                         cancel_click, screen);
240
241         auth_screen_layout_widgets(screen);
242 }
243
244 static int auth_screen_destroy(void *arg)
245 {
246         struct auth_screen *screen = arg;
247         if (screen->scr.sub_ncw)
248                 delwin(screen->scr.sub_ncw);
249         return 0;
250 }
251
252 struct auth_screen *auth_screen_init(struct cui *cui,
253                 WINDOW *parent, bool set_password,
254                 const struct device *dev,
255                 void (*callback)(struct nc_scr *),
256                 void (*on_exit)(struct cui *))
257 {
258         struct auth_screen *screen = NULL;
259         struct nc_scr *scr;
260         int y, x;
261
262         if (!cui || !parent)
263                 return NULL;
264
265         if (set_password && dev) {
266                 pb_log_fn("Incorrect parameters (set_password and device)\n");
267                 return NULL;
268         }
269
270         screen = talloc_zero(cui, struct auth_screen);
271         if (!screen)
272                 return NULL;
273         talloc_set_destructor(screen, auth_screen_destroy);
274
275         screen->cui = cui;
276         screen->return_scr = cui->current;
277         screen->set_password = set_password;
278         screen->dev = dev;
279         screen->callback = callback;
280         screen->on_exit = on_exit;
281         screen->label_x = 5;
282         screen->field_x = 10;
283
284         /*
285          * Manually init our nc_scr: we only want to create the subwin and
286          * 'inherit' the parent window.
287          */
288         scr = &screen->scr;
289         scr->sig = pb_auth_screen_sig;
290         scr->ui_ctx = cui;
291         scr->process_key = auth_screen_process_key;
292         scr->post = auth_screen_post;
293         scr->unpost = auth_screen_unpost;
294         scr->resize = NULL;
295
296
297         getbegyx(parent, y, x);
298         /* Hold on to the real offset from the top of the screen */
299         screen->offset_y = y + 5;
300         (void)x;
301
302         scr->main_ncw = parent;
303         scr->sub_ncw = derwin(parent, set_password ? 15 : 10, COLS - 20,
304                         5, 10); /* relative to parent origin */
305         if (!scr->sub_ncw) {
306                 pb_log("Could not create subwin\n");
307                 goto err;
308         }
309
310         auth_screen_draw(screen);
311
312         return screen;
313 err:
314         pb_log("failed to create auth screen\n");
315         if (screen) {
316                 if (screen->scr.sub_ncw)
317                         delwin(screen->scr.sub_ncw);
318                 talloc_free(screen);
319         }
320         return NULL;
321 }