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 */
140 static int general_allocate_boolean(UI
*ui
,
142 const char *action_desc
,
143 const char *ok_chars
,
144 const char *cancel_chars
,
146 enum UI_string_types type
,
147 int input_flags
, char *result_buf
)
153 if (ok_chars
== NULL
) {
154 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN
, ERR_R_PASSED_NULL_PARAMETER
);
155 } else if (cancel_chars
== NULL
) {
156 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN
, ERR_R_PASSED_NULL_PARAMETER
);
158 for (p
= ok_chars
; *p
; p
++) {
159 if (strchr(cancel_chars
, *p
)) {
160 UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN
,
161 UI_R_COMMON_OK_AND_CANCEL_CHARACTERS
);
165 s
= general_allocate_prompt(ui
, prompt
, prompt_freeable
,
166 type
, input_flags
, result_buf
);
169 if (allocate_string_stack(ui
) >= 0) {
170 s
->_
.boolean_data
.action_desc
= action_desc
;
171 s
->_
.boolean_data
.ok_chars
= ok_chars
;
172 s
->_
.boolean_data
.cancel_chars
= cancel_chars
;
173 ret
= sk_UI_STRING_push(ui
->strings
, s
);
175 * sk_push() returns 0 on error. Let's adapt that
189 * Returns the index to the place in the stack or -1 for error. Uses a
190 * direct reference to the prompt.
192 int UI_add_input_string(UI
*ui
, const char *prompt
, int flags
,
193 char *result_buf
, int minsize
, int maxsize
)
195 return general_allocate_string(ui
, prompt
, 0,
196 UIT_PROMPT
, flags
, result_buf
, minsize
,
200 /* Same as UI_add_input_string(), excepts it takes a copy of the prompt */
201 int UI_dup_input_string(UI
*ui
, const char *prompt
, int flags
,
202 char *result_buf
, int minsize
, int maxsize
)
204 char *prompt_copy
= NULL
;
207 prompt_copy
= OPENSSL_strdup(prompt
);
208 if (prompt_copy
== NULL
) {
209 UIerr(UI_F_UI_DUP_INPUT_STRING
, ERR_R_MALLOC_FAILURE
);
214 return general_allocate_string(ui
, prompt_copy
, 1,
215 UIT_PROMPT
, flags
, result_buf
, minsize
,
219 int UI_add_verify_string(UI
*ui
, const char *prompt
, int flags
,
220 char *result_buf
, int minsize
, int maxsize
,
221 const char *test_buf
)
223 return general_allocate_string(ui
, prompt
, 0,
224 UIT_VERIFY
, flags
, result_buf
, minsize
,
228 int UI_dup_verify_string(UI
*ui
, const char *prompt
, int flags
,
229 char *result_buf
, int minsize
, int maxsize
,
230 const char *test_buf
)
232 char *prompt_copy
= NULL
;
235 prompt_copy
= OPENSSL_strdup(prompt
);
236 if (prompt_copy
== NULL
) {
237 UIerr(UI_F_UI_DUP_VERIFY_STRING
, ERR_R_MALLOC_FAILURE
);
242 return general_allocate_string(ui
, prompt_copy
, 1,
243 UIT_VERIFY
, flags
, result_buf
, minsize
,
247 int UI_add_input_boolean(UI
*ui
, const char *prompt
, const char *action_desc
,
248 const char *ok_chars
, const char *cancel_chars
,
249 int flags
, char *result_buf
)
251 return general_allocate_boolean(ui
, prompt
, action_desc
,
252 ok_chars
, cancel_chars
, 0, UIT_BOOLEAN
,
256 int UI_dup_input_boolean(UI
*ui
, const char *prompt
, const char *action_desc
,
257 const char *ok_chars
, const char *cancel_chars
,
258 int flags
, char *result_buf
)
260 char *prompt_copy
= NULL
;
261 char *action_desc_copy
= NULL
;
262 char *ok_chars_copy
= NULL
;
263 char *cancel_chars_copy
= NULL
;
266 prompt_copy
= OPENSSL_strdup(prompt
);
267 if (prompt_copy
== NULL
) {
268 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN
, ERR_R_MALLOC_FAILURE
);
274 action_desc_copy
= OPENSSL_strdup(action_desc
);
275 if (action_desc_copy
== NULL
) {
276 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN
, ERR_R_MALLOC_FAILURE
);
282 ok_chars_copy
= OPENSSL_strdup(ok_chars
);
283 if (ok_chars_copy
== NULL
) {
284 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN
, ERR_R_MALLOC_FAILURE
);
290 cancel_chars_copy
= OPENSSL_strdup(cancel_chars
);
291 if (cancel_chars_copy
== NULL
) {
292 UIerr(UI_F_UI_DUP_INPUT_BOOLEAN
, ERR_R_MALLOC_FAILURE
);
297 return general_allocate_boolean(ui
, prompt_copy
, action_desc_copy
,
298 ok_chars_copy
, cancel_chars_copy
, 1,
299 UIT_BOOLEAN
, flags
, result_buf
);
301 OPENSSL_free(prompt_copy
);
302 OPENSSL_free(action_desc_copy
);
303 OPENSSL_free(ok_chars_copy
);
304 OPENSSL_free(cancel_chars_copy
);
308 int UI_add_info_string(UI
*ui
, const char *text
)
310 return general_allocate_string(ui
, text
, 0, UIT_INFO
, 0, NULL
, 0, 0,
314 int UI_dup_info_string(UI
*ui
, const char *text
)
316 char *text_copy
= NULL
;
319 text_copy
= OPENSSL_strdup(text
);
320 if (text_copy
== NULL
) {
321 UIerr(UI_F_UI_DUP_INFO_STRING
, ERR_R_MALLOC_FAILURE
);
326 return general_allocate_string(ui
, text_copy
, 1, UIT_INFO
, 0, NULL
,
330 int UI_add_error_string(UI
*ui
, const char *text
)
332 return general_allocate_string(ui
, text
, 0, UIT_ERROR
, 0, NULL
, 0, 0,
336 int UI_dup_error_string(UI
*ui
, const char *text
)
338 char *text_copy
= NULL
;
341 text_copy
= OPENSSL_strdup(text
);
342 if (text_copy
== NULL
) {
343 UIerr(UI_F_UI_DUP_ERROR_STRING
, ERR_R_MALLOC_FAILURE
);
347 return general_allocate_string(ui
, text_copy
, 1, UIT_ERROR
, 0, NULL
,
351 char *UI_construct_prompt(UI
*ui
, const char *object_desc
,
352 const char *object_name
)
356 if (ui
->meth
->ui_construct_prompt
)
357 prompt
= ui
->meth
->ui_construct_prompt(ui
, object_desc
, object_name
);
359 char prompt1
[] = "Enter ";
360 char prompt2
[] = " for ";
361 char prompt3
[] = ":";
364 if (object_desc
== NULL
)
366 len
= sizeof(prompt1
) - 1 + strlen(object_desc
);
368 len
+= sizeof(prompt2
) - 1 + strlen(object_name
);
369 len
+= sizeof(prompt3
) - 1;
371 prompt
= OPENSSL_malloc(len
+ 1);
374 OPENSSL_strlcpy(prompt
, prompt1
, len
+ 1);
375 OPENSSL_strlcat(prompt
, object_desc
, len
+ 1);
377 OPENSSL_strlcat(prompt
, prompt2
, len
+ 1);
378 OPENSSL_strlcat(prompt
, object_name
, len
+ 1);
380 OPENSSL_strlcat(prompt
, prompt3
, len
+ 1);
385 void *UI_add_user_data(UI
*ui
, void *user_data
)
387 void *old_data
= ui
->user_data
;
388 ui
->user_data
= user_data
;
392 void *UI_get0_user_data(UI
*ui
)
394 return ui
->user_data
;
397 const char *UI_get0_result(UI
*ui
, int i
)
400 UIerr(UI_F_UI_GET0_RESULT
, UI_R_INDEX_TOO_SMALL
);
403 if (i
>= sk_UI_STRING_num(ui
->strings
)) {
404 UIerr(UI_F_UI_GET0_RESULT
, UI_R_INDEX_TOO_LARGE
);
407 return UI_get0_result_string(sk_UI_STRING_value(ui
->strings
, i
));
410 static int print_error(const char *str
, size_t len
, UI
*ui
)
414 memset(&uis
, 0, sizeof(uis
));
415 uis
.type
= UIT_ERROR
;
416 uis
.out_string
= str
;
418 if (ui
->meth
->ui_write_string
&& !ui
->meth
->ui_write_string(ui
, &uis
))
423 int UI_process(UI
*ui
)
427 if (ui
->meth
->ui_open_session
&& !ui
->meth
->ui_open_session(ui
))
430 if (ui
->flags
& UI_FLAG_PRINT_ERRORS
)
431 ERR_print_errors_cb((int (*)(const char *, size_t, void *))
432 print_error
, (void *)ui
);
434 for (i
= 0; i
< sk_UI_STRING_num(ui
->strings
); i
++) {
435 if (ui
->meth
->ui_write_string
436 && !ui
->meth
->ui_write_string(ui
,
437 sk_UI_STRING_value(ui
->strings
, i
)))
444 if (ui
->meth
->ui_flush
)
445 switch (ui
->meth
->ui_flush(ui
)) {
446 case -1: /* Interrupt/Cancel/something... */
452 default: /* Success */
457 for (i
= 0; i
< sk_UI_STRING_num(ui
->strings
); i
++) {
458 if (ui
->meth
->ui_read_string
) {
459 switch (ui
->meth
->ui_read_string(ui
,
460 sk_UI_STRING_value(ui
->strings
,
462 case -1: /* Interrupt/Cancel/something... */
468 default: /* Success */
475 if (ui
->meth
->ui_close_session
&& !ui
->meth
->ui_close_session(ui
))
480 int UI_ctrl(UI
*ui
, int cmd
, long i
, void *p
, void (*f
) (void))
483 UIerr(UI_F_UI_CTRL
, ERR_R_PASSED_NULL_PARAMETER
);
487 case UI_CTRL_PRINT_ERRORS
:
489 int save_flag
= ! !(ui
->flags
& UI_FLAG_PRINT_ERRORS
);
491 ui
->flags
|= UI_FLAG_PRINT_ERRORS
;
493 ui
->flags
&= ~UI_FLAG_PRINT_ERRORS
;
496 case UI_CTRL_IS_REDOABLE
:
497 return ! !(ui
->flags
& UI_FLAG_REDOABLE
);
501 UIerr(UI_F_UI_CTRL
, UI_R_UNKNOWN_CONTROL_COMMAND
);
505 int UI_set_ex_data(UI
*r
, int idx
, void *arg
)
507 return (CRYPTO_set_ex_data(&r
->ex_data
, idx
, arg
));
510 void *UI_get_ex_data(UI
*r
, int idx
)
512 return (CRYPTO_get_ex_data(&r
->ex_data
, idx
));
515 void UI_set_default_method(const UI_METHOD
*meth
)
517 default_UI_meth
= meth
;
520 const UI_METHOD
*UI_get_default_method(void)
522 if (default_UI_meth
== NULL
) {
523 default_UI_meth
= UI_OpenSSL();
525 return default_UI_meth
;
528 const UI_METHOD
*UI_get_method(UI
*ui
)
533 const UI_METHOD
*UI_set_method(UI
*ui
, const UI_METHOD
*meth
)
539 UI_METHOD
*UI_create_method(const char *name
)
541 UI_METHOD
*ui_method
= OPENSSL_zalloc(sizeof(*ui_method
));
543 if (ui_method
!= NULL
) {
544 ui_method
->name
= OPENSSL_strdup(name
);
545 if (ui_method
->name
== NULL
) {
546 OPENSSL_free(ui_method
);
547 UIerr(UI_F_UI_CREATE_METHOD
, ERR_R_MALLOC_FAILURE
);
555 * BIG FSCKING WARNING!!!! If you use this on a statically allocated method
556 * (that is, it hasn't been allocated using UI_create_method(), you deserve
557 * anything Murphy can throw at you and more! You have been warned.
559 void UI_destroy_method(UI_METHOD
*ui_method
)
561 OPENSSL_free(ui_method
->name
);
562 ui_method
->name
= NULL
;
563 OPENSSL_free(ui_method
);
566 int UI_method_set_opener(UI_METHOD
*method
, int (*opener
) (UI
*ui
))
569 method
->ui_open_session
= opener
;
575 int UI_method_set_writer(UI_METHOD
*method
,
576 int (*writer
) (UI
*ui
, UI_STRING
*uis
))
579 method
->ui_write_string
= writer
;
585 int UI_method_set_flusher(UI_METHOD
*method
, int (*flusher
) (UI
*ui
))
588 method
->ui_flush
= flusher
;
594 int UI_method_set_reader(UI_METHOD
*method
,
595 int (*reader
) (UI
*ui
, UI_STRING
*uis
))
598 method
->ui_read_string
= reader
;
604 int UI_method_set_closer(UI_METHOD
*method
, int (*closer
) (UI
*ui
))
607 method
->ui_close_session
= closer
;
613 int UI_method_set_prompt_constructor(UI_METHOD
*method
,
614 char *(*prompt_constructor
) (UI
*ui
,
621 method
->ui_construct_prompt
= prompt_constructor
;
627 int (*UI_method_get_opener(UI_METHOD
*method
)) (UI
*) {
629 return method
->ui_open_session
;
634 int (*UI_method_get_writer(UI_METHOD
*method
)) (UI
*, UI_STRING
*) {
636 return method
->ui_write_string
;
641 int (*UI_method_get_flusher(UI_METHOD
*method
)) (UI
*) {
643 return method
->ui_flush
;
648 int (*UI_method_get_reader(UI_METHOD
*method
)) (UI
*, UI_STRING
*) {
650 return method
->ui_read_string
;
655 int (*UI_method_get_closer(UI_METHOD
*method
)) (UI
*) {
657 return method
->ui_close_session
;
662 char *(*UI_method_get_prompt_constructor(UI_METHOD
*method
)) (UI
*,
666 return method
->ui_construct_prompt
;
671 enum UI_string_types
UI_get_string_type(UI_STRING
*uis
)
678 int UI_get_input_flags(UI_STRING
*uis
)
682 return uis
->input_flags
;
685 const char *UI_get0_output_string(UI_STRING
*uis
)
689 return uis
->out_string
;
692 const char *UI_get0_action_string(UI_STRING
*uis
)
699 return uis
->_
.boolean_data
.action_desc
;
705 const char *UI_get0_result_string(UI_STRING
*uis
)
712 return uis
->result_buf
;
718 const char *UI_get0_test_string(UI_STRING
*uis
)
724 return uis
->_
.string_data
.test_buf
;
730 int UI_get_result_minsize(UI_STRING
*uis
)
737 return uis
->_
.string_data
.result_minsize
;
743 int UI_get_result_maxsize(UI_STRING
*uis
)
750 return uis
->_
.string_data
.result_maxsize
;
756 int UI_set_result(UI
*ui
, UI_STRING
*uis
, const char *result
)
758 int l
= strlen(result
);
760 ui
->flags
&= ~UI_FLAG_REDOABLE
;
768 char number1
[DECIMAL_SIZE(uis
->_
.string_data
.result_minsize
) + 1];
769 char number2
[DECIMAL_SIZE(uis
->_
.string_data
.result_maxsize
) + 1];
771 BIO_snprintf(number1
, sizeof(number1
), "%d",
772 uis
->_
.string_data
.result_minsize
);
773 BIO_snprintf(number2
, sizeof(number2
), "%d",
774 uis
->_
.string_data
.result_maxsize
);
776 if (l
< uis
->_
.string_data
.result_minsize
) {
777 ui
->flags
|= UI_FLAG_REDOABLE
;
778 UIerr(UI_F_UI_SET_RESULT
, UI_R_RESULT_TOO_SMALL
);
779 ERR_add_error_data(5, "You must type in ",
780 number1
, " to ", number2
, " characters");
783 if (l
> uis
->_
.string_data
.result_maxsize
) {
784 ui
->flags
|= UI_FLAG_REDOABLE
;
785 UIerr(UI_F_UI_SET_RESULT
, UI_R_RESULT_TOO_LARGE
);
786 ERR_add_error_data(5, "You must type in ",
787 number1
, " to ", number2
, " characters");
792 if (!uis
->result_buf
) {
793 UIerr(UI_F_UI_SET_RESULT
, UI_R_NO_RESULT_BUFFER
);
797 OPENSSL_strlcpy(uis
->result_buf
, result
,
798 uis
->_
.string_data
.result_maxsize
+ 1);
804 if (!uis
->result_buf
) {
805 UIerr(UI_F_UI_SET_RESULT
, UI_R_NO_RESULT_BUFFER
);
809 uis
->result_buf
[0] = '\0';
810 for (p
= result
; *p
; p
++) {
811 if (strchr(uis
->_
.boolean_data
.ok_chars
, *p
)) {
812 uis
->result_buf
[0] = uis
->_
.boolean_data
.ok_chars
[0];
815 if (strchr(uis
->_
.boolean_data
.cancel_chars
, *p
)) {
816 uis
->result_buf
[0] = uis
->_
.boolean_data
.cancel_chars
[0];