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
);
74 sk_UI_STRING_pop_free(ui
->strings
, free_string
);
75 CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI
, ui
, &ui
->ex_data
);
76 CRYPTO_THREAD_lock_free(ui
->lock
);
80 static int allocate_string_stack(UI
*ui
)
82 if (ui
->strings
== NULL
) {
83 ui
->strings
= sk_UI_STRING_new_null();
84 if (ui
->strings
== NULL
) {
91 static UI_STRING
*general_allocate_prompt(UI
*ui
, const char *prompt
,
93 enum UI_string_types type
,
94 int input_flags
, char *result_buf
)
96 UI_STRING
*ret
= NULL
;
99 UIerr(UI_F_GENERAL_ALLOCATE_PROMPT
, ERR_R_PASSED_NULL_PARAMETER
);
100 } else if ((type
== UIT_PROMPT
|| type
== UIT_VERIFY
101 || type
== UIT_BOOLEAN
) && result_buf
== NULL
) {
102 UIerr(UI_F_GENERAL_ALLOCATE_PROMPT
, UI_R_NO_RESULT_BUFFER
);
103 } else if ((ret
= OPENSSL_malloc(sizeof(*ret
))) != NULL
) {
104 ret
->out_string
= prompt
;
105 ret
->flags
= prompt_freeable
? OUT_STRING_FREEABLE
: 0;
106 ret
->input_flags
= input_flags
;
108 ret
->result_buf
= result_buf
;
113 static int general_allocate_string(UI
*ui
, const char *prompt
,
115 enum UI_string_types type
, int input_flags
,
116 char *result_buf
, int minsize
, int maxsize
,
117 const char *test_buf
)
120 UI_STRING
*s
= general_allocate_prompt(ui
, prompt
, prompt_freeable
,
121 type
, input_flags
, result_buf
);
124 if (allocate_string_stack(ui
) >= 0) {
125 s
->_
.string_data
.result_minsize
= minsize
;
126 s
->_
.string_data
.result_maxsize
= maxsize
;
127 s
->_
.string_data
.test_buf
= test_buf
;
128 ret
= sk_UI_STRING_push(ui
->strings
, s
);
129 /* sk_push() returns 0 on error. Let's adapt that */
138 static int general_allocate_boolean(UI
*ui
,
140 const char *action_desc
,
141 const char *ok_chars
,
142 const char *cancel_chars
,
144 enum UI_string_types type
,
145 int input_flags
, char *result_buf
)
151 if (ok_chars
== NULL
) {
152 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN
, ERR_R_PASSED_NULL_PARAMETER
);
153 } else if (cancel_chars
== NULL
) {
154 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN
, ERR_R_PASSED_NULL_PARAMETER
);
156 for (p
= ok_chars
; *p
; p
++) {
157 if (strchr(cancel_chars
, *p
)) {
158 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN
,
159 UI_R_COMMON_OK_AND_CANCEL_CHARACTERS
);
163 s
= general_allocate_prompt(ui
, prompt
, prompt_freeable
,
164 type
, input_flags
, result_buf
);
167 if (allocate_string_stack(ui
) >= 0) {
168 s
->_
.boolean_data
.action_desc
= action_desc
;
169 s
->_
.boolean_data
.ok_chars
= ok_chars
;
170 s
->_
.boolean_data
.cancel_chars
= cancel_chars
;
171 ret
= sk_UI_STRING_push(ui
->strings
, s
);
173 * sk_push() returns 0 on error. Let's adapt that
185 * Returns the index to the place in the stack or -1 for error. Uses a
186 * direct reference to the prompt.
188 int UI_add_input_string(UI
*ui
, const char *prompt
, int flags
,
189 char *result_buf
, int minsize
, int maxsize
)
191 return general_allocate_string(ui
, prompt
, 0,
192 UIT_PROMPT
, flags
, result_buf
, minsize
,
196 /* Same as UI_add_input_string(), excepts it takes a copy of the prompt */
197 int UI_dup_input_string(UI
*ui
, const char *prompt
, int flags
,
198 char *result_buf
, int minsize
, int maxsize
)
200 char *prompt_copy
= NULL
;
203 prompt_copy
= OPENSSL_strdup(prompt
);
204 if (prompt_copy
== NULL
) {
205 UIerr(UI_F_UI_DUP_INPUT_STRING
, ERR_R_MALLOC_FAILURE
);
210 return general_allocate_string(ui
, prompt_copy
, 1,
211 UIT_PROMPT
, flags
, result_buf
, minsize
,
215 int UI_add_verify_string(UI
*ui
, const char *prompt
, int flags
,
216 char *result_buf
, int minsize
, int maxsize
,
217 const char *test_buf
)
219 return general_allocate_string(ui
, prompt
, 0,
220 UIT_VERIFY
, flags
, result_buf
, minsize
,
224 int UI_dup_verify_string(UI
*ui
, const char *prompt
, int flags
,
225 char *result_buf
, int minsize
, int maxsize
,
226 const char *test_buf
)
228 char *prompt_copy
= NULL
;
231 prompt_copy
= OPENSSL_strdup(prompt
);
232 if (prompt_copy
== NULL
) {
233 UIerr(UI_F_UI_DUP_VERIFY_STRING
, ERR_R_MALLOC_FAILURE
);
238 return general_allocate_string(ui
, prompt_copy
, 1,
239 UIT_VERIFY
, flags
, result_buf
, minsize
,
243 int UI_add_input_boolean(UI
*ui
, const char *prompt
, const char *action_desc
,
244 const char *ok_chars
, const char *cancel_chars
,
245 int flags
, char *result_buf
)
247 return general_allocate_boolean(ui
, prompt
, action_desc
,
248 ok_chars
, cancel_chars
, 0, UIT_BOOLEAN
,
252 int UI_dup_input_boolean(UI
*ui
, const char *prompt
, const char *action_desc
,
253 const char *ok_chars
, const char *cancel_chars
,
254 int flags
, char *result_buf
)
256 char *prompt_copy
= NULL
;
257 char *action_desc_copy
= NULL
;
258 char *ok_chars_copy
= NULL
;
259 char *cancel_chars_copy
= NULL
;
262 prompt_copy
= OPENSSL_strdup(prompt
);
263 if (prompt_copy
== NULL
) {
264 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN
, ERR_R_MALLOC_FAILURE
);
270 action_desc_copy
= OPENSSL_strdup(action_desc
);
271 if (action_desc_copy
== NULL
) {
272 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN
, ERR_R_MALLOC_FAILURE
);
278 ok_chars_copy
= OPENSSL_strdup(ok_chars
);
279 if (ok_chars_copy
== NULL
) {
280 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN
, ERR_R_MALLOC_FAILURE
);
286 cancel_chars_copy
= OPENSSL_strdup(cancel_chars
);
287 if (cancel_chars_copy
== NULL
) {
288 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN
, ERR_R_MALLOC_FAILURE
);
293 return general_allocate_boolean(ui
, prompt_copy
, action_desc_copy
,
294 ok_chars_copy
, cancel_chars_copy
, 1,
295 UIT_BOOLEAN
, flags
, result_buf
);
297 OPENSSL_free(prompt_copy
);
298 OPENSSL_free(action_desc_copy
);
299 OPENSSL_free(ok_chars_copy
);
300 OPENSSL_free(cancel_chars_copy
);
304 int UI_add_info_string(UI
*ui
, const char *text
)
306 return general_allocate_string(ui
, text
, 0, UIT_INFO
, 0, NULL
, 0, 0,
310 int UI_dup_info_string(UI
*ui
, const char *text
)
312 char *text_copy
= NULL
;
315 text_copy
= OPENSSL_strdup(text
);
316 if (text_copy
== NULL
) {
317 UIerr(UI_F_UI_DUP_INFO_STRING
, ERR_R_MALLOC_FAILURE
);
322 return general_allocate_string(ui
, text_copy
, 1, UIT_INFO
, 0, NULL
,
326 int UI_add_error_string(UI
*ui
, const char *text
)
328 return general_allocate_string(ui
, text
, 0, UIT_ERROR
, 0, NULL
, 0, 0,
332 int UI_dup_error_string(UI
*ui
, const char *text
)
334 char *text_copy
= NULL
;
337 text_copy
= OPENSSL_strdup(text
);
338 if (text_copy
== NULL
) {
339 UIerr(UI_F_UI_DUP_ERROR_STRING
, ERR_R_MALLOC_FAILURE
);
343 return general_allocate_string(ui
, text_copy
, 1, UIT_ERROR
, 0, NULL
,
347 char *UI_construct_prompt(UI
*ui
, const char *object_desc
,
348 const char *object_name
)
352 if (ui
->meth
->ui_construct_prompt
)
353 prompt
= ui
->meth
->ui_construct_prompt(ui
, object_desc
, object_name
);
355 char prompt1
[] = "Enter ";
356 char prompt2
[] = " for ";
357 char prompt3
[] = ":";
360 if (object_desc
== NULL
)
362 len
= sizeof(prompt1
) - 1 + strlen(object_desc
);
364 len
+= sizeof(prompt2
) - 1 + strlen(object_name
);
365 len
+= sizeof(prompt3
) - 1;
367 prompt
= OPENSSL_malloc(len
+ 1);
370 OPENSSL_strlcpy(prompt
, prompt1
, len
+ 1);
371 OPENSSL_strlcat(prompt
, object_desc
, len
+ 1);
373 OPENSSL_strlcat(prompt
, prompt2
, len
+ 1);
374 OPENSSL_strlcat(prompt
, object_name
, len
+ 1);
376 OPENSSL_strlcat(prompt
, prompt3
, len
+ 1);
381 void *UI_add_user_data(UI
*ui
, void *user_data
)
383 void *old_data
= ui
->user_data
;
384 ui
->user_data
= user_data
;
388 void *UI_get0_user_data(UI
*ui
)
390 return ui
->user_data
;
393 const char *UI_get0_result(UI
*ui
, int i
)
396 UIerr(UI_F_UI_GET0_RESULT
, UI_R_INDEX_TOO_SMALL
);
399 if (i
>= sk_UI_STRING_num(ui
->strings
)) {
400 UIerr(UI_F_UI_GET0_RESULT
, UI_R_INDEX_TOO_LARGE
);
403 return UI_get0_result_string(sk_UI_STRING_value(ui
->strings
, i
));
406 static int print_error(const char *str
, size_t len
, UI
*ui
)
410 memset(&uis
, 0, sizeof(uis
));
411 uis
.type
= UIT_ERROR
;
412 uis
.out_string
= str
;
414 if (ui
->meth
->ui_write_string
&& !ui
->meth
->ui_write_string(ui
, &uis
))
419 int UI_process(UI
*ui
)
423 if (ui
->meth
->ui_open_session
&& !ui
->meth
->ui_open_session(ui
))
426 if (ui
->flags
& UI_FLAG_PRINT_ERRORS
)
427 ERR_print_errors_cb((int (*)(const char *, size_t, void *))
428 print_error
, (void *)ui
);
430 for (i
= 0; i
< sk_UI_STRING_num(ui
->strings
); i
++) {
431 if (ui
->meth
->ui_write_string
432 && !ui
->meth
->ui_write_string(ui
,
433 sk_UI_STRING_value(ui
->strings
, i
)))
440 if (ui
->meth
->ui_flush
)
441 switch (ui
->meth
->ui_flush(ui
)) {
442 case -1: /* Interrupt/Cancel/something... */
448 default: /* Success */
453 for (i
= 0; i
< sk_UI_STRING_num(ui
->strings
); i
++) {
454 if (ui
->meth
->ui_read_string
) {
455 switch (ui
->meth
->ui_read_string(ui
,
456 sk_UI_STRING_value(ui
->strings
,
458 case -1: /* Interrupt/Cancel/something... */
464 default: /* Success */
471 if (ui
->meth
->ui_close_session
&& !ui
->meth
->ui_close_session(ui
))
476 int UI_ctrl(UI
*ui
, int cmd
, long i
, void *p
, void (*f
) (void))
479 UIerr(UI_F_UI_CTRL
, ERR_R_PASSED_NULL_PARAMETER
);
483 case UI_CTRL_PRINT_ERRORS
:
485 int save_flag
= ! !(ui
->flags
& UI_FLAG_PRINT_ERRORS
);
487 ui
->flags
|= UI_FLAG_PRINT_ERRORS
;
489 ui
->flags
&= ~UI_FLAG_PRINT_ERRORS
;
492 case UI_CTRL_IS_REDOABLE
:
493 return ! !(ui
->flags
& UI_FLAG_REDOABLE
);
497 UIerr(UI_F_UI_CTRL
, UI_R_UNKNOWN_CONTROL_COMMAND
);
501 int UI_set_ex_data(UI
*r
, int idx
, void *arg
)
503 return (CRYPTO_set_ex_data(&r
->ex_data
, idx
, arg
));
506 void *UI_get_ex_data(UI
*r
, int idx
)
508 return (CRYPTO_get_ex_data(&r
->ex_data
, idx
));
511 void UI_set_default_method(const UI_METHOD
*meth
)
513 default_UI_meth
= meth
;
516 const UI_METHOD
*UI_get_default_method(void)
518 if (default_UI_meth
== NULL
) {
519 default_UI_meth
= UI_OpenSSL();
521 return default_UI_meth
;
524 const UI_METHOD
*UI_get_method(UI
*ui
)
529 const UI_METHOD
*UI_set_method(UI
*ui
, const UI_METHOD
*meth
)
535 UI_METHOD
*UI_create_method(char *name
)
537 UI_METHOD
*ui_method
= OPENSSL_zalloc(sizeof(*ui_method
));
539 if (ui_method
!= NULL
)
540 ui_method
->name
= OPENSSL_strdup(name
);
545 * BIG FSCKING WARNING!!!! If you use this on a statically allocated method
546 * (that is, it hasn't been allocated using UI_create_method(), you deserve
547 * anything Murphy can throw at you and more! You have been warned.
549 void UI_destroy_method(UI_METHOD
*ui_method
)
551 OPENSSL_free(ui_method
->name
);
552 ui_method
->name
= NULL
;
553 OPENSSL_free(ui_method
);
556 int UI_method_set_opener(UI_METHOD
*method
, int (*opener
) (UI
*ui
))
559 method
->ui_open_session
= opener
;
565 int UI_method_set_writer(UI_METHOD
*method
,
566 int (*writer
) (UI
*ui
, UI_STRING
*uis
))
569 method
->ui_write_string
= writer
;
575 int UI_method_set_flusher(UI_METHOD
*method
, int (*flusher
) (UI
*ui
))
578 method
->ui_flush
= flusher
;
584 int UI_method_set_reader(UI_METHOD
*method
,
585 int (*reader
) (UI
*ui
, UI_STRING
*uis
))
588 method
->ui_read_string
= reader
;
594 int UI_method_set_closer(UI_METHOD
*method
, int (*closer
) (UI
*ui
))
597 method
->ui_close_session
= closer
;
603 int UI_method_set_prompt_constructor(UI_METHOD
*method
,
604 char *(*prompt_constructor
) (UI
*ui
,
611 method
->ui_construct_prompt
= prompt_constructor
;
617 int (*UI_method_get_opener(UI_METHOD
*method
)) (UI
*) {
619 return method
->ui_open_session
;
624 int (*UI_method_get_writer(UI_METHOD
*method
)) (UI
*, UI_STRING
*) {
626 return method
->ui_write_string
;
631 int (*UI_method_get_flusher(UI_METHOD
*method
)) (UI
*) {
633 return method
->ui_flush
;
638 int (*UI_method_get_reader(UI_METHOD
*method
)) (UI
*, UI_STRING
*) {
640 return method
->ui_read_string
;
645 int (*UI_method_get_closer(UI_METHOD
*method
)) (UI
*) {
647 return method
->ui_close_session
;
652 char *(*UI_method_get_prompt_constructor(UI_METHOD
*method
)) (UI
*,
656 return method
->ui_construct_prompt
;
661 enum UI_string_types
UI_get_string_type(UI_STRING
*uis
)
668 int UI_get_input_flags(UI_STRING
*uis
)
672 return uis
->input_flags
;
675 const char *UI_get0_output_string(UI_STRING
*uis
)
679 return uis
->out_string
;
682 const char *UI_get0_action_string(UI_STRING
*uis
)
689 return uis
->_
.boolean_data
.action_desc
;
695 const char *UI_get0_result_string(UI_STRING
*uis
)
702 return uis
->result_buf
;
708 const char *UI_get0_test_string(UI_STRING
*uis
)
714 return uis
->_
.string_data
.test_buf
;
720 int UI_get_result_minsize(UI_STRING
*uis
)
727 return uis
->_
.string_data
.result_minsize
;
733 int UI_get_result_maxsize(UI_STRING
*uis
)
740 return uis
->_
.string_data
.result_maxsize
;
746 int UI_set_result(UI
*ui
, UI_STRING
*uis
, const char *result
)
748 int l
= strlen(result
);
750 ui
->flags
&= ~UI_FLAG_REDOABLE
;
758 char number1
[DECIMAL_SIZE(uis
->_
.string_data
.result_minsize
) + 1];
759 char number2
[DECIMAL_SIZE(uis
->_
.string_data
.result_maxsize
) + 1];
761 BIO_snprintf(number1
, sizeof(number1
), "%d",
762 uis
->_
.string_data
.result_minsize
);
763 BIO_snprintf(number2
, sizeof(number2
), "%d",
764 uis
->_
.string_data
.result_maxsize
);
766 if (l
< uis
->_
.string_data
.result_minsize
) {
767 ui
->flags
|= UI_FLAG_REDOABLE
;
768 UIerr(UI_F_UI_SET_RESULT
, UI_R_RESULT_TOO_SMALL
);
769 ERR_add_error_data(5, "You must type in ",
770 number1
, " to ", number2
, " characters");
773 if (l
> uis
->_
.string_data
.result_maxsize
) {
774 ui
->flags
|= UI_FLAG_REDOABLE
;
775 UIerr(UI_F_UI_SET_RESULT
, UI_R_RESULT_TOO_LARGE
);
776 ERR_add_error_data(5, "You must type in ",
777 number1
, " to ", number2
, " characters");
782 if (!uis
->result_buf
) {
783 UIerr(UI_F_UI_SET_RESULT
, UI_R_NO_RESULT_BUFFER
);
787 OPENSSL_strlcpy(uis
->result_buf
, result
,
788 uis
->_
.string_data
.result_maxsize
+ 1);
794 if (!uis
->result_buf
) {
795 UIerr(UI_F_UI_SET_RESULT
, UI_R_NO_RESULT_BUFFER
);
799 uis
->result_buf
[0] = '\0';
800 for (p
= result
; *p
; p
++) {
801 if (strchr(uis
->_
.boolean_data
.ok_chars
, *p
)) {
802 uis
->result_buf
[0] = uis
->_
.boolean_data
.ok_chars
[0];
805 if (strchr(uis
->_
.boolean_data
.cancel_chars
, *p
)) {
806 uis
->result_buf
[0] = uis
->_
.boolean_data
.cancel_chars
[0];