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 = OPENSSL_zalloc(sizeof(*ui_method));
566 if (ui_method != NULL) {
567 ui_method->name = OPENSSL_strdup(name);
568 if (ui_method->name == NULL) {
569 OPENSSL_free(ui_method);
570 UIerr(UI_F_UI_CREATE_METHOD, ERR_R_MALLOC_FAILURE);
578 * BIG FSCKING WARNING!!!! If you use this on a statically allocated method
579 * (that is, it hasn't been allocated using UI_create_method(), you deserve
580 * anything Murphy can throw at you and more! You have been warned.
582 void UI_destroy_method(UI_METHOD *ui_method)
584 OPENSSL_free(ui_method->name);
585 ui_method->name = NULL;
586 OPENSSL_free(ui_method);
589 int UI_method_set_opener(UI_METHOD *method, int (*opener) (UI *ui))
591 if (method != NULL) {
592 method->ui_open_session = opener;
598 int UI_method_set_writer(UI_METHOD *method,
599 int (*writer) (UI *ui, UI_STRING *uis))
601 if (method != NULL) {
602 method->ui_write_string = writer;
608 int UI_method_set_flusher(UI_METHOD *method, int (*flusher) (UI *ui))
610 if (method != NULL) {
611 method->ui_flush = flusher;
617 int UI_method_set_reader(UI_METHOD *method,
618 int (*reader) (UI *ui, UI_STRING *uis))
620 if (method != NULL) {
621 method->ui_read_string = reader;
627 int UI_method_set_closer(UI_METHOD *method, int (*closer) (UI *ui))
629 if (method != NULL) {
630 method->ui_close_session = closer;
636 int UI_method_set_prompt_constructor(UI_METHOD *method,
637 char *(*prompt_constructor) (UI *ui,
643 if (method != NULL) {
644 method->ui_construct_prompt = prompt_constructor;
650 int (*UI_method_get_opener(UI_METHOD *method)) (UI *)
653 return method->ui_open_session;
657 int (*UI_method_get_writer(UI_METHOD *method)) (UI *, UI_STRING *)
660 return method->ui_write_string;
664 int (*UI_method_get_flusher(UI_METHOD *method)) (UI *)
667 return method->ui_flush;
671 int (*UI_method_get_reader(UI_METHOD *method)) (UI *, UI_STRING *)
674 return method->ui_read_string;
678 int (*UI_method_get_closer(UI_METHOD *method)) (UI *)
681 return method->ui_close_session;
685 char *(*UI_method_get_prompt_constructor(UI_METHOD *method)) (UI *,
690 return method->ui_construct_prompt;
694 enum UI_string_types UI_get_string_type(UI_STRING *uis)
699 int UI_get_input_flags(UI_STRING *uis)
701 return uis->input_flags;
704 const char *UI_get0_output_string(UI_STRING *uis)
706 return uis->out_string;
709 const char *UI_get0_action_string(UI_STRING *uis)
714 return uis->_.boolean_data.action_desc;
724 const char *UI_get0_result_string(UI_STRING *uis)
729 return uis->result_buf;
739 const char *UI_get0_test_string(UI_STRING *uis)
743 return uis->_.string_data.test_buf;
754 int UI_get_result_minsize(UI_STRING *uis)
759 return uis->_.string_data.result_minsize;
769 int UI_get_result_maxsize(UI_STRING *uis)
774 return uis->_.string_data.result_maxsize;
784 int UI_set_result(UI *ui, UI_STRING *uis, const char *result)
786 int l = strlen(result);
788 ui->flags &= ~UI_FLAG_REDOABLE;
794 char number1[DECIMAL_SIZE(uis->_.string_data.result_minsize) + 1];
795 char number2[DECIMAL_SIZE(uis->_.string_data.result_maxsize) + 1];
797 BIO_snprintf(number1, sizeof(number1), "%d",
798 uis->_.string_data.result_minsize);
799 BIO_snprintf(number2, sizeof(number2), "%d",
800 uis->_.string_data.result_maxsize);
802 if (l < uis->_.string_data.result_minsize) {
803 ui->flags |= UI_FLAG_REDOABLE;
804 UIerr(UI_F_UI_SET_RESULT, UI_R_RESULT_TOO_SMALL);
805 ERR_add_error_data(5, "You must type in ",
806 number1, " to ", number2, " characters");
809 if (l > uis->_.string_data.result_maxsize) {
810 ui->flags |= UI_FLAG_REDOABLE;
811 UIerr(UI_F_UI_SET_RESULT, UI_R_RESULT_TOO_LARGE);
812 ERR_add_error_data(5, "You must type in ",
813 number1, " to ", number2, " characters");
818 if (uis->result_buf == NULL) {
819 UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER);
823 OPENSSL_strlcpy(uis->result_buf, result,
824 uis->_.string_data.result_maxsize + 1);
830 if (uis->result_buf == NULL) {
831 UIerr(UI_F_UI_SET_RESULT, UI_R_NO_RESULT_BUFFER);
835 uis->result_buf[0] = '\0';
836 for (p = result; *p; p++) {
837 if (strchr(uis->_.boolean_data.ok_chars, *p)) {
838 uis->result_buf[0] = uis->_.boolean_data.ok_chars[0];
841 if (strchr(uis->_.boolean_data.cancel_chars, *p)) {
842 uis->result_buf[0] = uis->_.boolean_data.cancel_chars[0];