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 != '\0'; p++) {
163 if (strchr(cancel_chars, *p) != NULL) {
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;
210 if (prompt != 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;
238 if (prompt != 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;
269 if (prompt != NULL) {
270 prompt_copy = OPENSSL_strdup(prompt);
271 if (prompt_copy == NULL) {
272 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN, ERR_R_MALLOC_FAILURE);
277 if (action_desc != NULL) {
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);
285 if (ok_chars != NULL) {
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);
293 if (cancel_chars != NULL) {
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 != NULL)
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);
371 if (object_name != NULL)
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);
380 if (object_name != NULL) {
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 != NULL
423 && ui->meth->ui_write_string(ui, &uis) <= 0)
428 int UI_process(UI *ui)
431 const char *state = "processing";
433 if (ui->meth->ui_open_session != NULL
434 && ui->meth->ui_open_session(ui) <= 0) {
435 state = "opening session";
440 if (ui->flags & UI_FLAG_PRINT_ERRORS)
441 ERR_print_errors_cb((int (*)(const char *, size_t, void *))
442 print_error, (void *)ui);
444 for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) {
445 if (ui->meth->ui_write_string != NULL
446 && (ui->meth->ui_write_string(ui,
447 sk_UI_STRING_value(ui->strings, i))
450 state = "writing strings";
456 if (ui->meth->ui_flush != NULL)
457 switch (ui->meth->ui_flush(ui)) {
458 case -1: /* Interrupt/Cancel/something... */
465 default: /* Success */
470 for (i = 0; i < sk_UI_STRING_num(ui->strings); i++) {
471 if (ui->meth->ui_read_string != NULL) {
472 switch (ui->meth->ui_read_string(ui,
473 sk_UI_STRING_value(ui->strings,
475 case -1: /* Interrupt/Cancel/something... */
479 state = "reading strings";
482 default: /* Success */
489 if (ui->meth->ui_close_session != NULL
490 && ui->meth->ui_close_session(ui) <= 0) {
492 state = "closing session";
497 UIerr(UI_F_UI_PROCESS, UI_R_PROCESSING_ERROR);
498 ERR_add_error_data(2, "while ", state);
503 int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f) (void))
506 UIerr(UI_F_UI_CTRL, ERR_R_PASSED_NULL_PARAMETER);
510 case UI_CTRL_PRINT_ERRORS:
512 int save_flag = ! !(ui->flags & UI_FLAG_PRINT_ERRORS);
514 ui->flags |= UI_FLAG_PRINT_ERRORS;
516 ui->flags &= ~UI_FLAG_PRINT_ERRORS;
519 case UI_CTRL_IS_REDOABLE:
520 return ! !(ui->flags & UI_FLAG_REDOABLE);
524 UIerr(UI_F_UI_CTRL, UI_R_UNKNOWN_CONTROL_COMMAND);
528 int UI_set_ex_data(UI *r, int idx, void *arg)
530 return (CRYPTO_set_ex_data(&r->ex_data, idx, arg));
533 void *UI_get_ex_data(UI *r, int idx)
535 return (CRYPTO_get_ex_data(&r->ex_data, idx));
538 void UI_set_default_method(const UI_METHOD *meth)
540 default_UI_meth = meth;
543 const UI_METHOD *UI_get_default_method(void)
545 if (default_UI_meth == NULL) {
546 default_UI_meth = UI_OpenSSL();
548 return default_UI_meth;
551 const UI_METHOD *UI_get_method(UI *ui)
556 const UI_METHOD *UI_set_method(UI *ui, const UI_METHOD *meth)
562 UI_METHOD *UI_create_method(const char *name)
564 UI_METHOD *ui_method = NULL;
566 if ((ui_method = OPENSSL_zalloc(sizeof(*ui_method))) == NULL
567 || (ui_method->name = OPENSSL_strdup(name)) == NULL
568 || !CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI_METHOD, ui_method,
569 &ui_method->ex_data)) {
571 OPENSSL_free(ui_method->name);
572 OPENSSL_free(ui_method);
573 UIerr(UI_F_UI_CREATE_METHOD, ERR_R_MALLOC_FAILURE);
580 * BIG FSCKING WARNING!!!! If you use this on a statically allocated method
581 * (that is, it hasn't been allocated using UI_create_method(), you deserve
582 * anything Murphy can throw at you and more! You have been warned.
584 void UI_destroy_method(UI_METHOD *ui_method)
586 if (ui_method == NULL)
588 CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI_METHOD, ui_method,
589 &ui_method->ex_data);
590 OPENSSL_free(ui_method->name);
591 ui_method->name = NULL;
592 OPENSSL_free(ui_method);
595 int UI_method_set_opener(UI_METHOD *method, int (*opener) (UI *ui))
597 if (method != NULL) {
598 method->ui_open_session = opener;
604 int UI_method_set_writer(UI_METHOD *method,
605 int (*writer) (UI *ui, UI_STRING *uis))
607 if (method != NULL) {
608 method->ui_write_string = writer;
614 int UI_method_set_flusher(UI_METHOD *method, int (*flusher) (UI *ui))
616 if (method != NULL) {
617 method->ui_flush = flusher;
623 int UI_method_set_reader(UI_METHOD *method,
624 int (*reader) (UI *ui, UI_STRING *uis))
626 if (method != NULL) {
627 method->ui_read_string = reader;
633 int UI_method_set_closer(UI_METHOD *method, int (*closer) (UI *ui))
635 if (method != NULL) {
636 method->ui_close_session = closer;
642 int UI_method_set_prompt_constructor(UI_METHOD *method,
643 char *(*prompt_constructor) (UI *ui,
649 if (method != NULL) {
650 method->ui_construct_prompt = prompt_constructor;
656 int UI_method_set_ex_data(UI_METHOD *method, int idx, void *data)
658 return CRYPTO_set_ex_data(&method->ex_data, idx, data);
661 int (*UI_method_get_opener(const UI_METHOD *method)) (UI *)
664 return method->ui_open_session;
668 int (*UI_method_get_writer(const UI_METHOD *method)) (UI *, UI_STRING *)
671 return method->ui_write_string;
675 int (*UI_method_get_flusher(const UI_METHOD *method)) (UI *)
678 return method->ui_flush;
682 int (*UI_method_get_reader(const UI_METHOD *method)) (UI *, UI_STRING *)
685 return method->ui_read_string;
689 int (*UI_method_get_closer(const UI_METHOD *method)) (UI *)
692 return method->ui_close_session;
696 char *(*UI_method_get_prompt_constructor(const UI_METHOD *method))
697 (UI *, const char *, const char *)
700 return method->ui_construct_prompt;
704 const void *UI_method_get_ex_data(const UI_METHOD *method, int idx)
706 return CRYPTO_get_ex_data(&method->ex_data, idx);
709 enum UI_string_types UI_get_string_type(UI_STRING *uis)
714 int UI_get_input_flags(UI_STRING *uis)
716 return uis->input_flags;
719 const char *UI_get0_output_string(UI_STRING *uis)
721 return uis->out_string;
724 const char *UI_get0_action_string(UI_STRING *uis)
728 return uis->_.boolean_data.action_desc;
739 const char *UI_get0_result_string(UI_STRING *uis)
744 return uis->result_buf;
754 const char *UI_get0_test_string(UI_STRING *uis)
758 return uis->_.string_data.test_buf;
769 int UI_get_result_minsize(UI_STRING *uis)
774 return uis->_.string_data.result_minsize;
784 int UI_get_result_maxsize(UI_STRING *uis)
789 return uis->_.string_data.result_maxsize;
799 int UI_set_result(UI *ui, UI_STRING *uis, const char *result)
801 int l = strlen(result);
803 ui->flags &= ~UI_FLAG_REDOABLE;
809 char number1[DECIMAL_SIZE(uis->_.string_data.result_minsize) + 1];
810 char number2[DECIMAL_SIZE(uis->_.string_data.result_maxsize) + 1];
812 BIO_snprintf(number1, sizeof(number1), "%d",
813 uis->_.string_data.result_minsize);
814 BIO_snprintf(number2, sizeof(number2), "%d",
815 uis->_.string_data.result_maxsize);
817 if (l < uis->_.string_data.result_minsize) {
818 ui->flags |= UI_FLAG_REDOABLE;
819 UIerr(UI_F_UI_SET_RESULT, UI_R_RESULT_TOO_SMALL);
820 ERR_add_error_data(5, "You must type in ",
821 number1, " to ", number2, " characters");
824 if (l > uis->_.string_data.result_maxsize) {
825 ui->flags |= UI_FLAG_REDOABLE;
826 UIerr(UI_F_UI_SET_RESULT, UI_R_RESULT_TOO_LARGE);
827 ERR_add_error_data(5, "You must type in ",
828 number1, " to ", number2, " characters");
833 if (uis->result_buf == NULL) {
834 UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER);
838 OPENSSL_strlcpy(uis->result_buf, result,
839 uis->_.string_data.result_maxsize + 1);
845 if (uis->result_buf == NULL) {
846 UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER);
850 uis->result_buf[0] = '\0';
851 for (p = result; *p; p++) {
852 if (strchr(uis->_.boolean_data.ok_chars, *p)) {
853 uis->result_buf[0] = uis->_.boolean_data.ok_chars[0];
856 if (strchr(uis->_.boolean_data.cancel_chars, *p)) {
857 uis->result_buf[0] = uis->_.boolean_data.cancel_chars[0];