2 * Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the OpenSSL license (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
11 #include "internal/cryptlib.h"
12 #include <openssl/e_os2.h>
13 #include <openssl/buffer.h>
14 #include <openssl/ui.h>
15 #include <openssl/err.h>
18 static const UI_METHOD *default_UI_meth = NULL;
22 return (UI_new_method(NULL));
25 UI *UI_new_method(const UI_METHOD *method)
27 UI *ret = OPENSSL_zalloc(sizeof(*ret));
30 UIerr(UI_F_UI_NEW_METHOD, ERR_R_MALLOC_FAILURE);
34 ret->lock = CRYPTO_THREAD_lock_new();
35 if (ret->lock == NULL) {
36 UIerr(UI_F_UI_NEW_METHOD, ERR_R_MALLOC_FAILURE);
42 ret->meth = UI_get_default_method();
46 if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI, ret, &ret->ex_data)) {
53 static void free_string(UI_STRING *uis)
55 if (uis->flags & OUT_STRING_FREEABLE) {
56 OPENSSL_free((char *)uis->out_string);
59 OPENSSL_free((char *)uis->_.boolean_data.action_desc);
60 OPENSSL_free((char *)uis->_.boolean_data.ok_chars);
61 OPENSSL_free((char *)uis->_.boolean_data.cancel_chars);
78 sk_UI_STRING_pop_free(ui->strings, free_string);
79 CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI, ui, &ui->ex_data);
80 CRYPTO_THREAD_lock_free(ui->lock);
84 static int allocate_string_stack(UI *ui)
86 if (ui->strings == NULL) {
87 ui->strings = sk_UI_STRING_new_null();
88 if (ui->strings == NULL) {
95 static UI_STRING *general_allocate_prompt(UI *ui, const char *prompt,
97 enum UI_string_types type,
98 int input_flags, char *result_buf)
100 UI_STRING *ret = NULL;
102 if (prompt == NULL) {
103 UIerr(UI_F_GENERAL_ALLOCATE_PROMPT, ERR_R_PASSED_NULL_PARAMETER);
104 } else if ((type == UIT_PROMPT || type == UIT_VERIFY
105 || type == UIT_BOOLEAN) && result_buf == NULL) {
106 UIerr(UI_F_GENERAL_ALLOCATE_PROMPT, UI_R_NO_RESULT_BUFFER);
107 } else if ((ret = OPENSSL_malloc(sizeof(*ret))) != NULL) {
108 ret->out_string = prompt;
109 ret->flags = prompt_freeable ? OUT_STRING_FREEABLE : 0;
110 ret->input_flags = input_flags;
112 ret->result_buf = result_buf;
117 static int general_allocate_string(UI *ui, const char *prompt,
119 enum UI_string_types type, int input_flags,
120 char *result_buf, int minsize, int maxsize,
121 const char *test_buf)
124 UI_STRING *s = general_allocate_prompt(ui, prompt, prompt_freeable,
125 type, input_flags, result_buf);
128 if (allocate_string_stack(ui) >= 0) {
129 s->_.string_data.result_minsize = minsize;
130 s->_.string_data.result_maxsize = maxsize;
131 s->_.string_data.test_buf = test_buf;
132 ret = sk_UI_STRING_push(ui->strings, s);
133 /* sk_push() returns 0 on error. Let's adapt that */
144 static int general_allocate_boolean(UI *ui,
146 const char *action_desc,
147 const char *ok_chars,
148 const char *cancel_chars,
150 enum UI_string_types type,
151 int input_flags, char *result_buf)
157 if (ok_chars == NULL) {
158 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN, ERR_R_PASSED_NULL_PARAMETER);
159 } else if (cancel_chars == NULL) {
160 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN, ERR_R_PASSED_NULL_PARAMETER);
162 for (p = ok_chars; *p; p++) {
163 if (strchr(cancel_chars, *p)) {
164 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN,
165 UI_R_COMMON_OK_AND_CANCEL_CHARACTERS);
169 s = general_allocate_prompt(ui, prompt, prompt_freeable,
170 type, input_flags, result_buf);
173 if (allocate_string_stack(ui) >= 0) {
174 s->_.boolean_data.action_desc = action_desc;
175 s->_.boolean_data.ok_chars = ok_chars;
176 s->_.boolean_data.cancel_chars = cancel_chars;
177 ret = sk_UI_STRING_push(ui->strings, s);
179 * sk_push() returns 0 on error. Let's adapt that
193 * Returns the index to the place in the stack or -1 for error. Uses a
194 * direct reference to the prompt.
196 int UI_add_input_string(UI *ui, const char *prompt, int flags,
197 char *result_buf, int minsize, int maxsize)
199 return general_allocate_string(ui, prompt, 0,
200 UIT_PROMPT, flags, result_buf, minsize,
204 /* Same as UI_add_input_string(), excepts it takes a copy of the prompt */
205 int UI_dup_input_string(UI *ui, const char *prompt, int flags,
206 char *result_buf, int minsize, int maxsize)
208 char *prompt_copy = NULL;
211 prompt_copy = OPENSSL_strdup(prompt);
212 if (prompt_copy == NULL) {
213 UIerr(UI_F_UI_DUP_INPUT_STRING, ERR_R_MALLOC_FAILURE);
218 return general_allocate_string(ui, prompt_copy, 1,
219 UIT_PROMPT, flags, result_buf, minsize,
223 int UI_add_verify_string(UI *ui, const char *prompt, int flags,
224 char *result_buf, int minsize, int maxsize,
225 const char *test_buf)
227 return general_allocate_string(ui, prompt, 0,
228 UIT_VERIFY, flags, result_buf, minsize,
232 int UI_dup_verify_string(UI *ui, const char *prompt, int flags,
233 char *result_buf, int minsize, int maxsize,
234 const char *test_buf)
236 char *prompt_copy = NULL;
239 prompt_copy = OPENSSL_strdup(prompt);
240 if (prompt_copy == NULL) {
241 UIerr(UI_F_UI_DUP_VERIFY_STRING, ERR_R_MALLOC_FAILURE);
246 return general_allocate_string(ui, prompt_copy, 1,
247 UIT_VERIFY, flags, result_buf, minsize,
251 int UI_add_input_boolean(UI *ui, const char *prompt, const char *action_desc,
252 const char *ok_chars, const char *cancel_chars,
253 int flags, char *result_buf)
255 return general_allocate_boolean(ui, prompt, action_desc,
256 ok_chars, cancel_chars, 0, UIT_BOOLEAN,
260 int UI_dup_input_boolean(UI *ui, const char *prompt, const char *action_desc,
261 const char *ok_chars, const char *cancel_chars,
262 int flags, char *result_buf)
264 char *prompt_copy = NULL;
265 char *action_desc_copy = NULL;
266 char *ok_chars_copy = NULL;
267 char *cancel_chars_copy = NULL;
270 prompt_copy = OPENSSL_strdup(prompt);
271 if (prompt_copy == NULL) {
272 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
278 action_desc_copy = OPENSSL_strdup(action_desc);
279 if (action_desc_copy == NULL) {
280 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
286 ok_chars_copy = OPENSSL_strdup(ok_chars);
287 if (ok_chars_copy == NULL) {
288 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
294 cancel_chars_copy = OPENSSL_strdup(cancel_chars);
295 if (cancel_chars_copy == NULL) {
296 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
301 return general_allocate_boolean(ui, prompt_copy, action_desc_copy,
302 ok_chars_copy, cancel_chars_copy, 1,
303 UIT_BOOLEAN, flags, result_buf);
305 OPENSSL_free(prompt_copy);
306 OPENSSL_free(action_desc_copy);
307 OPENSSL_free(ok_chars_copy);
308 OPENSSL_free(cancel_chars_copy);
312 int UI_add_info_string(UI *ui, const char *text)
314 return general_allocate_string(ui, text, 0, UIT_INFO, 0, NULL, 0, 0,
318 int UI_dup_info_string(UI *ui, const char *text)
320 char *text_copy = NULL;
323 text_copy = OPENSSL_strdup(text);
324 if (text_copy == NULL) {
325 UIerr(UI_F_UI_DUP_INFO_STRING, ERR_R_MALLOC_FAILURE);
330 return general_allocate_string(ui, text_copy, 1, UIT_INFO, 0, NULL,
334 int UI_add_error_string(UI *ui, const char *text)
336 return general_allocate_string(ui, text, 0, UIT_ERROR, 0, NULL, 0, 0,
340 int UI_dup_error_string(UI *ui, const char *text)
342 char *text_copy = NULL;
345 text_copy = OPENSSL_strdup(text);
346 if (text_copy == NULL) {
347 UIerr(UI_F_UI_DUP_ERROR_STRING, ERR_R_MALLOC_FAILURE);
351 return general_allocate_string(ui, text_copy, 1, UIT_ERROR, 0, NULL,
355 char *UI_construct_prompt(UI *ui, const char *object_desc,
356 const char *object_name)
360 if (ui->meth->ui_construct_prompt)
361 prompt = ui->meth->ui_construct_prompt(ui, object_desc, object_name);
363 char prompt1[] = "Enter ";
364 char prompt2[] = " for ";
365 char prompt3[] = ":";
368 if (object_desc == NULL)
370 len = sizeof(prompt1) - 1 + strlen(object_desc);
372 len += sizeof(prompt2) - 1 + strlen(object_name);
373 len += sizeof(prompt3) - 1;
375 prompt = OPENSSL_malloc(len + 1);
378 OPENSSL_strlcpy(prompt, prompt1, len + 1);
379 OPENSSL_strlcat(prompt, object_desc, len + 1);
381 OPENSSL_strlcat(prompt, prompt2, len + 1);
382 OPENSSL_strlcat(prompt, object_name, len + 1);
384 OPENSSL_strlcat(prompt, prompt3, len + 1);
389 void *UI_add_user_data(UI *ui, void *user_data)
391 void *old_data = ui->user_data;
392 ui->user_data = user_data;
396 void *UI_get0_user_data(UI *ui)
398 return ui->user_data;
401 const char *UI_get0_result(UI *ui, int i)
404 UIerr(UI_F_UI_GET0_RESULT, UI_R_INDEX_TOO_SMALL);
407 if (i >= sk_UI_STRING_num(ui->strings)) {
408 UIerr(UI_F_UI_GET0_RESULT, UI_R_INDEX_TOO_LARGE);
411 return UI_get0_result_string(sk_UI_STRING_value(ui->strings, i));
414 static int print_error(const char *str, size_t len, UI *ui)
418 memset(&uis, 0, sizeof(uis));
419 uis.type = UIT_ERROR;
420 uis.out_string = str;
422 if (ui->meth->ui_write_string && !ui->meth->ui_write_string(ui, &uis))
427 int UI_process(UI *ui)
431 if (ui->meth->ui_open_session && !ui->meth->ui_open_session(ui))
434 if (ui->flags & UI_FLAG_PRINT_ERRORS)
435 ERR_print_errors_cb((int (*)(const char *, size_t, void *))
436 print_error, (void *)ui);
438 for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) {
439 if (ui->meth->ui_write_string
440 && !ui->meth->ui_write_string(ui,
441 sk_UI_STRING_value(ui->strings, i)))
448 if (ui->meth->ui_flush)
449 switch (ui->meth->ui_flush(ui)) {
450 case -1: /* Interrupt/Cancel/something... */
456 default: /* Success */
461 for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) {
462 if (ui->meth->ui_read_string) {
463 switch (ui->meth->ui_read_string(ui,
464 sk_UI_STRING_value(ui->strings,
466 case -1: /* Interrupt/Cancel/something... */
472 default: /* Success */
479 if (ui->meth->ui_close_session && !ui->meth->ui_close_session(ui))
484 int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f) (void))
487 UIerr(UI_F_UI_CTRL, ERR_R_PASSED_NULL_PARAMETER);
491 case UI_CTRL_PRINT_ERRORS:
493 int save_flag = ! !(ui->flags & UI_FLAG_PRINT_ERRORS);
495 ui->flags |= UI_FLAG_PRINT_ERRORS;
497 ui->flags &= ~UI_FLAG_PRINT_ERRORS;
500 case UI_CTRL_IS_REDOABLE:
501 return ! !(ui->flags & UI_FLAG_REDOABLE);
505 UIerr(UI_F_UI_CTRL, UI_R_UNKNOWN_CONTROL_COMMAND);
509 int UI_set_ex_data(UI *r, int idx, void *arg)
511 return (CRYPTO_set_ex_data(&r->ex_data, idx, arg));
514 void *UI_get_ex_data(UI *r, int idx)
516 return (CRYPTO_get_ex_data(&r->ex_data, idx));
519 void UI_set_default_method(const UI_METHOD *meth)
521 default_UI_meth = meth;
524 const UI_METHOD *UI_get_default_method(void)
526 if (default_UI_meth == NULL) {
527 default_UI_meth = UI_OpenSSL();
529 return default_UI_meth;
532 const UI_METHOD *UI_get_method(UI *ui)
537 const UI_METHOD *UI_set_method(UI *ui, const UI_METHOD *meth)
543 UI_METHOD *UI_create_method(const char *name)
545 UI_METHOD *ui_method = OPENSSL_zalloc(sizeof(*ui_method));
547 if (ui_method != NULL) {
548 ui_method->name = OPENSSL_strdup(name);
549 if (ui_method->name == NULL) {
550 OPENSSL_free(ui_method);
551 UIerr(UI_F_UI_CREATE_METHOD, ERR_R_MALLOC_FAILURE);
559 * BIG FSCKING WARNING!!!! If you use this on a statically allocated method
560 * (that is, it hasn't been allocated using UI_create_method(), you deserve
561 * anything Murphy can throw at you and more! You have been warned.
563 void UI_destroy_method(UI_METHOD *ui_method)
565 OPENSSL_free(ui_method->name);
566 ui_method->name = NULL;
567 OPENSSL_free(ui_method);
570 int UI_method_set_opener(UI_METHOD *method, int (*opener) (UI *ui))
573 method->ui_open_session = opener;
579 int UI_method_set_writer(UI_METHOD *method,
580 int (*writer) (UI *ui, UI_STRING *uis))
583 method->ui_write_string = writer;
589 int UI_method_set_flusher(UI_METHOD *method, int (*flusher) (UI *ui))
592 method->ui_flush = flusher;
598 int UI_method_set_reader(UI_METHOD *method,
599 int (*reader) (UI *ui, UI_STRING *uis))
602 method->ui_read_string = reader;
608 int UI_method_set_closer(UI_METHOD *method, int (*closer) (UI *ui))
611 method->ui_close_session = closer;
617 int UI_method_set_prompt_constructor(UI_METHOD *method,
618 char *(*prompt_constructor) (UI *ui,
625 method->ui_construct_prompt = prompt_constructor;
631 int (*UI_method_get_opener(UI_METHOD *method)) (UI *) {
633 return method->ui_open_session;
638 int (*UI_method_get_writer(UI_METHOD *method)) (UI *, UI_STRING *) {
640 return method->ui_write_string;
645 int (*UI_method_get_flusher(UI_METHOD *method)) (UI *) {
647 return method->ui_flush;
652 int (*UI_method_get_reader(UI_METHOD *method)) (UI *, UI_STRING *) {
654 return method->ui_read_string;
659 int (*UI_method_get_closer(UI_METHOD *method)) (UI *) {
661 return method->ui_close_session;
666 char *(*UI_method_get_prompt_constructor(UI_METHOD *method)) (UI *,
670 return method->ui_construct_prompt;
675 enum UI_string_types UI_get_string_type(UI_STRING *uis)
680 int UI_get_input_flags(UI_STRING *uis)
682 return uis->input_flags;
685 const char *UI_get0_output_string(UI_STRING *uis)
687 return uis->out_string;
690 const char *UI_get0_action_string(UI_STRING *uis)
695 return uis->_.boolean_data.action_desc;
705 const char *UI_get0_result_string(UI_STRING *uis)
710 return uis->result_buf;
720 const char *UI_get0_test_string(UI_STRING *uis)
724 return uis->_.string_data.test_buf;
735 int UI_get_result_minsize(UI_STRING *uis)
740 return uis->_.string_data.result_minsize;
750 int UI_get_result_maxsize(UI_STRING *uis)
755 return uis->_.string_data.result_maxsize;
765 int UI_set_result(UI *ui, UI_STRING *uis, const char *result)
767 int l = strlen(result);
769 ui->flags &= ~UI_FLAG_REDOABLE;
775 char number1[DECIMAL_SIZE(uis->_.string_data.result_minsize) + 1];
776 char number2[DECIMAL_SIZE(uis->_.string_data.result_maxsize) + 1];
778 BIO_snprintf(number1, sizeof(number1), "%d",
779 uis->_.string_data.result_minsize);
780 BIO_snprintf(number2, sizeof(number2), "%d",
781 uis->_.string_data.result_maxsize);
783 if (l < uis->_.string_data.result_minsize) {
784 ui->flags |= UI_FLAG_REDOABLE;
785 UIerr(UI_F_UI_SET_RESULT, UI_R_RESULT_TOO_SMALL);
786 ERR_add_error_data(5, "You must type in ",
787 number1, " to ", number2, " characters");
790 if (l > uis->_.string_data.result_maxsize) {
791 ui->flags |= UI_FLAG_REDOABLE;
792 UIerr(UI_F_UI_SET_RESULT, UI_R_RESULT_TOO_LARGE);
793 ERR_add_error_data(5, "You must type in ",
794 number1, " to ", number2, " characters");
799 if (uis->result_buf == NULL) {
800 UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER);
804 OPENSSL_strlcpy(uis->result_buf, result,
805 uis->_.string_data.result_maxsize + 1);
811 if (uis->result_buf == NULL) {
812 UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER);
816 uis->result_buf[0] = '\0';
817 for (p = result; *p; p++) {
818 if (strchr(uis->_.boolean_data.ok_chars, *p)) {
819 uis->result_buf[0] = uis->_.boolean_data.ok_chars[0];
822 if (strchr(uis->_.boolean_data.cancel_chars, *p)) {
823 uis->result_buf[0] = uis->_.boolean_data.cancel_chars[0];