1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci#include <string.h>
11e1051a39Sopenharmony_ci#include <openssl/err.h>
12e1051a39Sopenharmony_ci#include <openssl/ui.h>
13e1051a39Sopenharmony_ci#include "apps_ui.h"
14e1051a39Sopenharmony_ci
15e1051a39Sopenharmony_cistatic UI_METHOD *ui_method = NULL;
16e1051a39Sopenharmony_cistatic const UI_METHOD *ui_base_method = NULL;
17e1051a39Sopenharmony_ci
18e1051a39Sopenharmony_cistatic int ui_open(UI *ui)
19e1051a39Sopenharmony_ci{
20e1051a39Sopenharmony_ci    int (*opener)(UI *ui) = UI_method_get_opener(ui_base_method);
21e1051a39Sopenharmony_ci
22e1051a39Sopenharmony_ci    if (opener != NULL)
23e1051a39Sopenharmony_ci        return opener(ui);
24e1051a39Sopenharmony_ci    return 1;
25e1051a39Sopenharmony_ci}
26e1051a39Sopenharmony_ci
27e1051a39Sopenharmony_cistatic int ui_read(UI *ui, UI_STRING *uis)
28e1051a39Sopenharmony_ci{
29e1051a39Sopenharmony_ci    int (*reader)(UI *ui, UI_STRING *uis) = NULL;
30e1051a39Sopenharmony_ci
31e1051a39Sopenharmony_ci    if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD
32e1051a39Sopenharmony_ci        && UI_get0_user_data(ui)) {
33e1051a39Sopenharmony_ci        switch (UI_get_string_type(uis)) {
34e1051a39Sopenharmony_ci        case UIT_PROMPT:
35e1051a39Sopenharmony_ci        case UIT_VERIFY:
36e1051a39Sopenharmony_ci            {
37e1051a39Sopenharmony_ci                const char *password =
38e1051a39Sopenharmony_ci                    ((PW_CB_DATA *)UI_get0_user_data(ui))->password;
39e1051a39Sopenharmony_ci
40e1051a39Sopenharmony_ci                if (password != NULL) {
41e1051a39Sopenharmony_ci                    UI_set_result(ui, uis, password);
42e1051a39Sopenharmony_ci                    return 1;
43e1051a39Sopenharmony_ci                }
44e1051a39Sopenharmony_ci            }
45e1051a39Sopenharmony_ci            break;
46e1051a39Sopenharmony_ci        case UIT_NONE:
47e1051a39Sopenharmony_ci        case UIT_BOOLEAN:
48e1051a39Sopenharmony_ci        case UIT_INFO:
49e1051a39Sopenharmony_ci        case UIT_ERROR:
50e1051a39Sopenharmony_ci            break;
51e1051a39Sopenharmony_ci        }
52e1051a39Sopenharmony_ci    }
53e1051a39Sopenharmony_ci
54e1051a39Sopenharmony_ci    reader = UI_method_get_reader(ui_base_method);
55e1051a39Sopenharmony_ci    if (reader != NULL)
56e1051a39Sopenharmony_ci        return reader(ui, uis);
57e1051a39Sopenharmony_ci    /* Default to the empty password if we've got nothing better */
58e1051a39Sopenharmony_ci    UI_set_result(ui, uis, "");
59e1051a39Sopenharmony_ci    return 1;
60e1051a39Sopenharmony_ci}
61e1051a39Sopenharmony_ci
62e1051a39Sopenharmony_cistatic int ui_write(UI *ui, UI_STRING *uis)
63e1051a39Sopenharmony_ci{
64e1051a39Sopenharmony_ci    int (*writer)(UI *ui, UI_STRING *uis) = NULL;
65e1051a39Sopenharmony_ci
66e1051a39Sopenharmony_ci    if (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD
67e1051a39Sopenharmony_ci        && UI_get0_user_data(ui)) {
68e1051a39Sopenharmony_ci        switch (UI_get_string_type(uis)) {
69e1051a39Sopenharmony_ci        case UIT_PROMPT:
70e1051a39Sopenharmony_ci        case UIT_VERIFY:
71e1051a39Sopenharmony_ci            {
72e1051a39Sopenharmony_ci                const char *password =
73e1051a39Sopenharmony_ci                    ((PW_CB_DATA *)UI_get0_user_data(ui))->password;
74e1051a39Sopenharmony_ci
75e1051a39Sopenharmony_ci                if (password != NULL)
76e1051a39Sopenharmony_ci                    return 1;
77e1051a39Sopenharmony_ci            }
78e1051a39Sopenharmony_ci            break;
79e1051a39Sopenharmony_ci        case UIT_NONE:
80e1051a39Sopenharmony_ci        case UIT_BOOLEAN:
81e1051a39Sopenharmony_ci        case UIT_INFO:
82e1051a39Sopenharmony_ci        case UIT_ERROR:
83e1051a39Sopenharmony_ci            break;
84e1051a39Sopenharmony_ci        }
85e1051a39Sopenharmony_ci    }
86e1051a39Sopenharmony_ci
87e1051a39Sopenharmony_ci    writer = UI_method_get_writer(ui_base_method);
88e1051a39Sopenharmony_ci    if (writer != NULL)
89e1051a39Sopenharmony_ci        return writer(ui, uis);
90e1051a39Sopenharmony_ci    return 1;
91e1051a39Sopenharmony_ci}
92e1051a39Sopenharmony_ci
93e1051a39Sopenharmony_cistatic int ui_close(UI *ui)
94e1051a39Sopenharmony_ci{
95e1051a39Sopenharmony_ci    int (*closer)(UI *ui) = UI_method_get_closer(ui_base_method);
96e1051a39Sopenharmony_ci
97e1051a39Sopenharmony_ci    if (closer != NULL)
98e1051a39Sopenharmony_ci        return closer(ui);
99e1051a39Sopenharmony_ci    return 1;
100e1051a39Sopenharmony_ci}
101e1051a39Sopenharmony_ci
102e1051a39Sopenharmony_ci/* object_name defaults to prompt_info from ui user data if present */
103e1051a39Sopenharmony_cistatic char *ui_prompt_construct(UI *ui, const char *phrase_desc,
104e1051a39Sopenharmony_ci                                 const char *object_name)
105e1051a39Sopenharmony_ci{
106e1051a39Sopenharmony_ci    PW_CB_DATA *cb_data = (PW_CB_DATA *)UI_get0_user_data(ui);
107e1051a39Sopenharmony_ci
108e1051a39Sopenharmony_ci    if (phrase_desc == NULL)
109e1051a39Sopenharmony_ci        phrase_desc = "pass phrase";
110e1051a39Sopenharmony_ci    if (object_name == NULL && cb_data != NULL)
111e1051a39Sopenharmony_ci        object_name = cb_data->prompt_info;
112e1051a39Sopenharmony_ci    return UI_construct_prompt(NULL, phrase_desc, object_name);
113e1051a39Sopenharmony_ci}
114e1051a39Sopenharmony_ci
115e1051a39Sopenharmony_ciint set_base_ui_method(const UI_METHOD *ui_meth)
116e1051a39Sopenharmony_ci{
117e1051a39Sopenharmony_ci    if (ui_meth == NULL)
118e1051a39Sopenharmony_ci        ui_meth = UI_null();
119e1051a39Sopenharmony_ci    ui_base_method = ui_meth;
120e1051a39Sopenharmony_ci    return 1;
121e1051a39Sopenharmony_ci}
122e1051a39Sopenharmony_ci
123e1051a39Sopenharmony_ciint setup_ui_method(void)
124e1051a39Sopenharmony_ci{
125e1051a39Sopenharmony_ci    ui_base_method = UI_null();
126e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_UI_CONSOLE
127e1051a39Sopenharmony_ci    ui_base_method = UI_OpenSSL();
128e1051a39Sopenharmony_ci#endif
129e1051a39Sopenharmony_ci    ui_method = UI_create_method("OpenSSL application user interface");
130e1051a39Sopenharmony_ci    return ui_method != NULL
131e1051a39Sopenharmony_ci        && 0 == UI_method_set_opener(ui_method, ui_open)
132e1051a39Sopenharmony_ci        && 0 == UI_method_set_reader(ui_method, ui_read)
133e1051a39Sopenharmony_ci        && 0 == UI_method_set_writer(ui_method, ui_write)
134e1051a39Sopenharmony_ci        && 0 == UI_method_set_closer(ui_method, ui_close)
135e1051a39Sopenharmony_ci        && 0 == UI_method_set_prompt_constructor(ui_method,
136e1051a39Sopenharmony_ci                                                 ui_prompt_construct);
137e1051a39Sopenharmony_ci}
138e1051a39Sopenharmony_ci
139e1051a39Sopenharmony_civoid destroy_ui_method(void)
140e1051a39Sopenharmony_ci{
141e1051a39Sopenharmony_ci    if (ui_method != NULL) {
142e1051a39Sopenharmony_ci        UI_destroy_method(ui_method);
143e1051a39Sopenharmony_ci        ui_method = NULL;
144e1051a39Sopenharmony_ci    }
145e1051a39Sopenharmony_ci}
146e1051a39Sopenharmony_ci
147e1051a39Sopenharmony_ciconst UI_METHOD *get_ui_method(void)
148e1051a39Sopenharmony_ci{
149e1051a39Sopenharmony_ci    return ui_method;
150e1051a39Sopenharmony_ci}
151e1051a39Sopenharmony_ci
152e1051a39Sopenharmony_cistatic void *ui_malloc(int sz, const char *what)
153e1051a39Sopenharmony_ci{
154e1051a39Sopenharmony_ci    void *vp = OPENSSL_malloc(sz);
155e1051a39Sopenharmony_ci
156e1051a39Sopenharmony_ci    if (vp == NULL) {
157e1051a39Sopenharmony_ci        BIO_printf(bio_err, "Could not allocate %d bytes for %s\n", sz, what);
158e1051a39Sopenharmony_ci        ERR_print_errors(bio_err);
159e1051a39Sopenharmony_ci        exit(1);
160e1051a39Sopenharmony_ci    }
161e1051a39Sopenharmony_ci    return vp;
162e1051a39Sopenharmony_ci}
163e1051a39Sopenharmony_ci
164e1051a39Sopenharmony_ciint password_callback(char *buf, int bufsiz, int verify, PW_CB_DATA *cb_data)
165e1051a39Sopenharmony_ci{
166e1051a39Sopenharmony_ci    int res = 0;
167e1051a39Sopenharmony_ci    UI *ui;
168e1051a39Sopenharmony_ci    int ok = 0;
169e1051a39Sopenharmony_ci    char *buff = NULL;
170e1051a39Sopenharmony_ci    int ui_flags = 0;
171e1051a39Sopenharmony_ci    const char *prompt_info = NULL;
172e1051a39Sopenharmony_ci    char *prompt;
173e1051a39Sopenharmony_ci
174e1051a39Sopenharmony_ci    if ((ui = UI_new_method(ui_method)) == NULL)
175e1051a39Sopenharmony_ci        return 0;
176e1051a39Sopenharmony_ci
177e1051a39Sopenharmony_ci    if (cb_data != NULL && cb_data->prompt_info != NULL)
178e1051a39Sopenharmony_ci        prompt_info = cb_data->prompt_info;
179e1051a39Sopenharmony_ci    prompt = UI_construct_prompt(ui, "pass phrase", prompt_info);
180e1051a39Sopenharmony_ci    if (prompt == NULL) {
181e1051a39Sopenharmony_ci        BIO_printf(bio_err, "Out of memory\n");
182e1051a39Sopenharmony_ci        UI_free(ui);
183e1051a39Sopenharmony_ci        return 0;
184e1051a39Sopenharmony_ci    }
185e1051a39Sopenharmony_ci
186e1051a39Sopenharmony_ci    ui_flags |= UI_INPUT_FLAG_DEFAULT_PWD;
187e1051a39Sopenharmony_ci    UI_ctrl(ui, UI_CTRL_PRINT_ERRORS, 1, 0, 0);
188e1051a39Sopenharmony_ci
189e1051a39Sopenharmony_ci    /* We know that there is no previous user data to return to us */
190e1051a39Sopenharmony_ci    (void)UI_add_user_data(ui, cb_data);
191e1051a39Sopenharmony_ci
192e1051a39Sopenharmony_ci    ok = UI_add_input_string(ui, prompt, ui_flags, buf,
193e1051a39Sopenharmony_ci                             PW_MIN_LENGTH, bufsiz - 1);
194e1051a39Sopenharmony_ci
195e1051a39Sopenharmony_ci    if (ok >= 0 && verify) {
196e1051a39Sopenharmony_ci        buff = ui_malloc(bufsiz, "password buffer");
197e1051a39Sopenharmony_ci        ok = UI_add_verify_string(ui, prompt, ui_flags, buff,
198e1051a39Sopenharmony_ci                                  PW_MIN_LENGTH, bufsiz - 1, buf);
199e1051a39Sopenharmony_ci    }
200e1051a39Sopenharmony_ci    if (ok >= 0)
201e1051a39Sopenharmony_ci        do {
202e1051a39Sopenharmony_ci            ok = UI_process(ui);
203e1051a39Sopenharmony_ci        } while (ok < 0 && UI_ctrl(ui, UI_CTRL_IS_REDOABLE, 0, 0, 0));
204e1051a39Sopenharmony_ci
205e1051a39Sopenharmony_ci    OPENSSL_clear_free(buff, (unsigned int)bufsiz);
206e1051a39Sopenharmony_ci
207e1051a39Sopenharmony_ci    if (ok >= 0)
208e1051a39Sopenharmony_ci        res = strlen(buf);
209e1051a39Sopenharmony_ci    if (ok == -1) {
210e1051a39Sopenharmony_ci        BIO_printf(bio_err, "User interface error\n");
211e1051a39Sopenharmony_ci        ERR_print_errors(bio_err);
212e1051a39Sopenharmony_ci        OPENSSL_cleanse(buf, (unsigned int)bufsiz);
213e1051a39Sopenharmony_ci        res = 0;
214e1051a39Sopenharmony_ci    }
215e1051a39Sopenharmony_ci    if (ok == -2) {
216e1051a39Sopenharmony_ci        BIO_printf(bio_err, "aborted!\n");
217e1051a39Sopenharmony_ci        OPENSSL_cleanse(buf, (unsigned int)bufsiz);
218e1051a39Sopenharmony_ci        res = 0;
219e1051a39Sopenharmony_ci    }
220e1051a39Sopenharmony_ci    UI_free(ui);
221e1051a39Sopenharmony_ci    OPENSSL_free(prompt);
222e1051a39Sopenharmony_ci    return res;
223e1051a39Sopenharmony_ci}
224