ui/ncurses: Add nc-auth and authenticate when required.
[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         void                    (*callback)(struct nc_scr *);
46         int                     offset_y;
47         int                     label_x;
48         int                     field_x;
49
50         bool                    exit;
51         void                    (*on_exit)(struct cui *);
52
53         struct {
54                 struct nc_widget_label          *title_a_l;
55                 struct nc_widget_label          *title_b_l;
56                 struct nc_widget_textbox        *password_f;
57                 struct nc_widget_label          *new_l;
58                 struct nc_widget_textbox        *new_f;
59                 struct nc_widget_button         *ok_b;
60                 struct nc_widget_button         *cancel_b;
61         } widgets;
62 };
63
64 struct nc_scr *auth_screen_return_scr(struct auth_screen *screen)
65 {
66         return screen->return_scr;
67 }
68
69 struct nc_scr *auth_screen_scr(struct auth_screen *screen)
70 {
71         return &screen->scr;
72 }
73
74 static struct auth_screen *auth_screen_from_scr(struct nc_scr *scr)
75 {
76         struct auth_screen *auth_screen;
77
78         assert(scr->sig == pb_auth_screen_sig);
79         auth_screen = (struct auth_screen *)
80                 ((char *)scr - (size_t)&((struct auth_screen *)0)->scr);
81         assert(auth_screen->scr.sig == pb_auth_screen_sig);
82         return auth_screen;
83 }
84
85 static void auth_screen_process_key(struct nc_scr *scr, int key)
86 {
87         struct auth_screen *screen = auth_screen_from_scr(scr);
88         bool handled;
89
90         handled = widgetset_process_key(screen->widgetset, key);
91
92         if (!handled) {
93                 switch (key) {
94                 case 'x':
95                 case 27: /* esc */
96                         screen->exit = true;
97                         break;
98                 }
99         }
100
101         if (screen->exit)
102                 screen->on_exit(screen->cui);
103         else if (handled)
104                 wrefresh(screen->scr.sub_ncw);
105 }
106
107 static void auth_screen_frame_draw(struct nc_scr *scr)
108 {
109         int y, x;
110
111         getmaxyx(scr->sub_ncw, y, x);
112
113         mvwhline(scr->sub_ncw, 0, 0, ACS_HLINE, x);
114         mvwhline(scr->sub_ncw, y - 1, 0, ACS_HLINE, x);
115
116         mvwvline(scr->sub_ncw, 0, 0, ACS_VLINE, y);
117         mvwvline(scr->sub_ncw, 0, x - 1, ACS_VLINE, y);
118 }
119
120 static int auth_screen_post(struct nc_scr *scr)
121 {
122         struct auth_screen *screen = auth_screen_from_scr(scr);
123         widgetset_post(screen->widgetset);
124         auth_screen_frame_draw(scr);
125         wrefresh(scr->sub_ncw);
126         return 0;
127 }
128
129 static int auth_screen_unpost(struct nc_scr *scr)
130 {
131         struct auth_screen *screen = auth_screen_from_scr(scr);
132         widgetset_unpost(screen->widgetset);
133         return 0;
134 }
135
136 static void ok_click(void *arg)
137 {
138         struct auth_screen *screen = arg;
139         char *password, *new_password;
140         int rc;
141
142
143         password = widget_textbox_get_value(screen->widgets.password_f);
144         if (screen->set_password) {
145                 new_password = widget_textbox_get_value(screen->widgets.new_f);
146                 rc = cui_send_set_password(screen->cui, password, new_password);
147         } else
148                 rc = cui_send_authenticate(screen->cui, password);
149
150         if (rc)
151                 pb_log("Failed to send authenticate action\n");
152         else if (screen->callback)
153                 screen->callback(screen->return_scr);
154
155         screen->exit = true;
156 }
157
158 static void cancel_click(void *arg)
159 {
160         struct auth_screen *screen = arg;
161         screen->exit = true;
162 }
163
164 static void auth_screen_layout_widgets(struct auth_screen *screen)
165 {
166         int y = 1;
167
168         widget_move(widget_label_base(screen->widgets.title_a_l),
169                         y++, screen->label_x);
170         widget_move(widget_label_base(screen->widgets.title_b_l),
171                         y++, screen->label_x);
172
173         y += 1;
174
175         widget_move(widget_textbox_base(screen->widgets.password_f),
176                         y++, screen->field_x);
177
178         y += 1;
179
180         if (screen->set_password) {
181                 widget_move(widget_label_base(screen->widgets.new_l),
182                                 y++, screen->label_x);
183                 widget_move(widget_textbox_base(screen->widgets.new_f),
184                                 y++, screen->field_x);
185                 y += 1;
186         }
187
188         widget_move(widget_button_base(screen->widgets.ok_b),
189                         y, 10);
190         widget_move(widget_button_base(screen->widgets.cancel_b),
191                         y, 30);
192 }
193
194 static void auth_screen_draw(struct auth_screen *screen)
195 {
196         struct nc_widgetset *set;
197
198         set = widgetset_create(screen, screen->scr.main_ncw,
199                         screen->scr.sub_ncw);
200         if (!set) {
201                 pb_log("%s: failed to create widgetset\n", __func__);
202                 return;
203         }
204         screen->widgetset = set;
205
206         screen->widgets.title_a_l = widget_new_label(set, 0, 0,
207                         _("This action requires authorisation."));
208         screen->widgets.title_b_l = widget_new_label(set, 0, 0,
209                         _("Please enter the system password."));
210
211         screen->widgets.password_f = widget_new_textbox_hidden(set, 0, 0,
212                         COLS - 20 - 20, "", true);
213
214         if (screen->set_password) {
215                 screen->widgets.new_l = widget_new_label(set, 0, 0,
216                                 _("New password:"));
217                 screen->widgets.new_f = widget_new_textbox_hidden(set, 0, 0,
218                                 COLS - 20 - 20, "", true);
219         }
220
221         screen->widgets.ok_b = widget_new_button(set, 0, 0, 10, _("OK"),
222                         ok_click, screen);
223         screen->widgets.cancel_b = widget_new_button(set, 0, 0, 10, _("Cancel"),
224                         cancel_click, screen);
225
226         auth_screen_layout_widgets(screen);
227 }
228
229 static int auth_screen_destroy(void *arg)
230 {
231         struct auth_screen *screen = arg;
232         if (screen->scr.sub_ncw)
233                 delwin(screen->scr.sub_ncw);
234         return 0;
235 }
236
237 struct auth_screen *auth_screen_init(struct cui *cui,
238                 WINDOW *parent, bool set_password,
239                 void (*callback)(struct nc_scr *),
240                 void (*on_exit)(struct cui *))
241 {
242         struct auth_screen *screen = NULL;
243         struct nc_scr *scr;
244         int y, x;
245
246         if (!cui || !parent)
247                 return NULL;
248
249         screen = talloc_zero(cui, struct auth_screen);
250         if (!screen)
251                 return NULL;
252         talloc_set_destructor(screen, auth_screen_destroy);
253
254         screen->cui = cui;
255         screen->return_scr = cui->current;
256         screen->set_password = set_password;
257         screen->callback = callback;
258         screen->on_exit = on_exit;
259         screen->label_x = 5;
260         screen->field_x = 10;
261
262         /*
263          * Manually init our nc_scr: we only want to create the subwin and
264          * 'inherit' the parent window.
265          */
266         scr = &screen->scr;
267         scr->sig = pb_auth_screen_sig;
268         scr->ui_ctx = cui;
269         scr->process_key = auth_screen_process_key;
270         scr->post = auth_screen_post;
271         scr->unpost = auth_screen_unpost;
272         scr->resize = NULL;
273
274
275         getbegyx(parent, y, x);
276         /* Hold on to the real offset from the top of the screen */
277         screen->offset_y = y + 5;
278         (void)x;
279
280         scr->main_ncw = parent;
281         scr->sub_ncw = derwin(parent, set_password ? 15 : 10, COLS - 20,
282                         5, 10); /* relative to parent origin */
283         if (!scr->sub_ncw) {
284                 pb_log("Could not create subwin\n");
285                 goto err;
286         }
287
288         auth_screen_draw(screen);
289
290         return screen;
291 err:
292         pb_log("failed to create auth screen\n");
293         if (screen) {
294                 if (screen->scr.sub_ncw)
295                         delwin(screen->scr.sub_ncw);
296                 talloc_free(screen);
297         }
298         return NULL;
299 }